commit bfc883141ea28d04d8da91fa69dcd0dfeb01b6a0
parent eda322494fb1c420add7e80bf9ec112c8574f3b4
Author: lumidify <nobody@lumidify.org>
Date:   Mon,  2 Jan 2017 12:07:15 +0100
Update various stuff
Change 'sticky' to a bitmask.
Add 'ltk_create_widget' function to simplify widget creation.
Start adding documentation.
Diffstat:
| M | button.c |  |  | 56 | +++++++++++++++++++++++++++++--------------------------- | 
| M | button.h |  |  | 2 | +- | 
| M | common.c |  |  | 8 | ++++---- | 
| M | common.h |  |  | 12 | ++++++------ | 
| M | grid.c |  |  | 34 | ++++++++++++---------------------- | 
| M | grid.h |  |  | 2 | +- | 
| M | test1.c |  |  | 21 | ++++++++++++++++----- | 
| M | widget.c |  |  | 55 | +++++++++++++++++++++++++++++++++++++++++++++---------- | 
| M | widget.h |  |  | 20 | ++++++++++++++------ | 
9 files changed, 128 insertions(+), 82 deletions(-)
diff --git a/button.c b/button.c
@@ -23,6 +23,12 @@
 
 #include "ltk.h"
 
+/*
+ * Purpose: Extract style information for buttons.
+ * Parameters:
+ * button_json: A cJSON struct containing the JSON for the button style.
+ * Returns: An LtkButtonTheme struct containing the style for a button.
+ */
 LtkButtonTheme *ltk_parse_button_theme(cJSON *button_json)
 {
     LtkButtonTheme *button_theme = malloc(sizeof(LtkButtonTheme));
@@ -112,9 +118,13 @@ LtkButtonTheme *ltk_parse_button_theme(cJSON *button_json)
     return button_theme;
 }
 
-void ltk_draw_button(void *widget)
+/*
+ * Purpose: Draw a button in its current state.
+ * Parameters:
+ * button: Pointer to the button to draw.
+ */
+void ltk_draw_button(LtkButton *button)
 {
-    LtkButton *button = widget;
     LtkButtonTheme *theme = ltk_global->theme->button;
     LtkWindow *window = button->widget.window;
     LtkRect rect = button->widget.rect;
@@ -123,28 +133,28 @@ void ltk_draw_button(void *widget)
     int border_width;
     switch (button->widget.state)
     {
-    case NORMAL:
+    case LTK_NORMAL:
         border_color = theme->border_color;
         fill_color = theme->fill_color;
         border_width = theme->border_width;
         break;
-    case HOVERACTIVE:
-    case HOVER:
+    case LTK_HOVERACTIVE:
+    case LTK_HOVER:
         border_color = theme->border_color_hover;
         fill_color = theme->fill_color_hover;
         border_width = theme->border_width_hover;
         break;
-    case PRESSED:
+    case LTK_PRESSED:
         border_color = theme->border_color_pressed;
         fill_color = theme->fill_color_pressed;
         border_width = theme->border_width_pressed;
         break;
-    case ACTIVE:
+    case LTK_ACTIVE:
         border_color = theme->border_color_active;
         fill_color = theme->fill_color_active;
         border_width = theme->border_width_active;
         break;
-    case DISABLED:
+    case LTK_DISABLED:
         border_color = theme->border_color_disabled;
         fill_color = theme->fill_color_disabled;
         border_width = theme->border_width_disabled;
@@ -160,6 +170,15 @@ void ltk_draw_button(void *widget)
     XDrawRectangle(ltk_global->display, window->xwindow, window->gc, rect.x, rect.y, rect.w, rect.h);
 }
 
+/*
+ * Purpose:    Create a button widget.
+ * Parameters:
+ * window:     The window the button will be shown on.
+ * text:       The text to be shown on the button.
+ * callback:   A function with no parameters or return
+ *             type to be called when the button is clicked.
+ * Returns:    A pointer to the newly created button.
+ */
 LtkButton *ltk_create_button(LtkWindow *window, const char *text, void (*callback)(void))
 {
     LtkButton *button = malloc(sizeof(LtkButton));
@@ -170,25 +189,8 @@ LtkButton *ltk_create_button(LtkWindow *window, const char *text, void (*callbac
             exit(1);
     }
 
-    button->widget.window = window;
-    button->widget.parent = NULL;
-    button->widget.active_widget = NULL;
-    button->widget.hover_widget = NULL;
-    button->widget.key_press = NULL;
-    button->widget.key_release = NULL;
-    button->widget.mouse_press = NULL;
+    button->widget = ltk_create_widget(window, <k_draw_button, <k_destroy_button, 1);
     button->widget.mouse_release = <k_button_mouse_release;
-    button->widget.motion_notify = NULL;
-    button->widget.resize = NULL;
-    button->widget.draw = <k_draw_button;
-    button->widget.destroy = <k_destroy_button;
-    button->widget.redraw_state = 1;
-    button->widget.rect.x = 0;
-    button->widget.rect.y = 0;
-    /* For testing, will default to size of text once text is implemented */
-    button->widget.rect.w = 100;
-    button->widget.rect.h = 100;
-    button->widget.state = NORMAL;
 
     button->callback = callback;
     button->text = strdup(text);
@@ -210,7 +212,7 @@ void ltk_destroy_button(void *widget)
 void ltk_button_mouse_release(void *widget, XEvent event)
 {
     LtkButton *button = widget;
-    if (button->widget.state == HOVERACTIVE && button->callback)
+    if (button->widget.state == LTK_HOVERACTIVE && button->callback)
     {
         button->callback();
     }
diff --git a/button.h b/button.h
@@ -67,7 +67,7 @@ typedef struct LtkButtonTheme
 } LtkButtonTheme;
 
 LtkButtonTheme *ltk_parse_button_theme(cJSON *button_json);
-void ltk_draw_button(void *widget);
+void ltk_draw_button(LtkButton *button);
 LtkButton *ltk_create_button(LtkWindow *window, const char *text, void (*callback)(void));
 void ltk_button_key_event(void *widget, XEvent event);
 void ltk_button_mouse_event(void *widget, XEvent event);
diff --git a/common.c b/common.c
@@ -45,7 +45,7 @@ int ltk_collide_rect(LtkRect rect, int x, int y)
     return (rect.x <= x && (rect.x + rect.w) >= x && rect.y <= y && (rect.y + rect.h) >= y);
 }
 
-/* Recursively set all active_widget states to NORMAL, redraw them,
+/* Recursively set all active_widget states to LTK_NORMAL, redraw them,
  * and remove the references to them in their parent functions */
 void ltk_remove_active_widget(void *widget)
 {
@@ -55,7 +55,7 @@ void ltk_remove_active_widget(void *widget)
     while (parent->active_widget)
     {
         child = parent->active_widget;
-        child->state = NORMAL;
+        child->state = LTK_NORMAL;
         child->draw(child);
         parent->active_widget = NULL;
         parent = child;
@@ -74,7 +74,7 @@ void ltk_change_active_widget_state(void *widget, LtkWidgetState state)
     }
 }
 
-/* Recursively set all hover_widget states to NORMAL, redraw them,
+/* Recursively set all hover_widget states to LTK_NORMAL, redraw them,
  * and remove the references to them in their parent functions */
 void ltk_remove_hover_widget(void *widget)
 {
@@ -84,7 +84,7 @@ void ltk_remove_hover_widget(void *widget)
     while (parent->hover_widget)
     {
         child = parent->hover_widget;
-        child->state = child->state == HOVERACTIVE ? ACTIVE : NORMAL;
+        child->state = child->state == LTK_HOVERACTIVE ? LTK_ACTIVE : LTK_NORMAL;
         child->draw(child);
         parent->hover_widget = NULL;
         parent = child;
diff --git a/common.h b/common.h
@@ -29,12 +29,12 @@ typedef struct LtkWidget LtkWidget;
 
 typedef enum
 {
-    NORMAL,
-    HOVER,
-    PRESSED,
-    ACTIVE,
-    HOVERACTIVE,
-    DISABLED
+    LTK_NORMAL,
+    LTK_HOVER,
+    LTK_PRESSED,
+    LTK_ACTIVE,
+    LTK_HOVERACTIVE,
+    LTK_DISABLED
 } LtkWidgetState;
 
 typedef struct
diff --git a/grid.c b/grid.c
@@ -52,23 +52,11 @@ LtkGrid *ltk_create_grid(LtkWindow *window, int rows, int columns)
 {
     LtkGrid *grid = malloc(sizeof(LtkGrid));
 
-    grid->widget.window = window;
-    grid->widget.parent = NULL;
+    grid->widget = ltk_create_widget(window, <k_draw_grid, <k_destroy_grid, 0);
     grid->widget.mouse_press = <k_grid_mouse_press;
     grid->widget.mouse_release = <k_grid_mouse_release;
     grid->widget.motion_notify = <k_grid_motion_notify;
-    grid->widget.key_press = NULL;
-    grid->widget.key_release = NULL;
     grid->widget.resize = <k_recalculate_grid;
-    grid->widget.draw = <k_draw_grid;
-    grid->widget.destroy = <k_destroy_grid;
-    grid->widget.redraw_state = 0;
-    grid->widget.rect.x = 0;
-    grid->widget.rect.y = 0;
-    grid->widget.rect.w = 0;
-    grid->widget.rect.h = 0;
-    grid->widget.active_widget = NULL;
-    grid->widget.state = NORMAL;
 
     grid->rows = rows;
     grid->columns = columns;
@@ -194,11 +182,13 @@ void ltk_recalculate_grid(void *widget)
             orig_height = ptr->rect.h;
             end_row = i + ptr->row_span;
             end_column = j + ptr->column_span;
-            if (ptr->sticky[1] == 1 && ptr->sticky[3] == 1)
+            if ((ptr->sticky & (LTK_STICKY_LEFT | LTK_STICKY_RIGHT)) ==
+                (LTK_STICKY_LEFT | LTK_STICKY_RIGHT))
             {
                 ptr->rect.w = grid->column_pos[end_column] - grid->column_pos[j];
             }
-            if (ptr->sticky[0] == 1 && ptr->sticky[2] == 1)
+            if ((ptr->sticky & (LTK_STICKY_TOP | LTK_STICKY_BOTTOM)) ==
+                (LTK_STICKY_TOP | LTK_STICKY_BOTTOM))
             {
                 ptr->rect.h = grid->row_pos[end_row] - grid->row_pos[i];
             }
@@ -210,11 +200,11 @@ void ltk_recalculate_grid(void *widget)
                 }
             }
 
-            if (ptr->sticky[1] == 1)
+            if ((ptr->sticky & LTK_STICKY_RIGHT) == LTK_STICKY_RIGHT)
             {
                 ptr->rect.x = grid->column_pos[end_column] - ptr->rect.w;
             }
-            else if (ptr->sticky[3] == 1)
+            else if ((ptr->sticky & LTK_STICKY_LEFT) == LTK_STICKY_LEFT)
             {
                 ptr->rect.x = grid->column_pos[j];
             }
@@ -223,11 +213,11 @@ void ltk_recalculate_grid(void *widget)
                 ptr->rect.x = grid->column_pos[j] + ((grid->column_pos[end_column] - grid->column_pos[j]) / 2 - ptr->rect.w / 2);
             }
 
-            if (ptr->sticky[2] == 1)
+            if ((ptr->sticky & LTK_STICKY_BOTTOM) == LTK_STICKY_BOTTOM)
             {
                 ptr->rect.y = grid->row_pos[end_row] - ptr->rect.h;
             }
-            else if (ptr->sticky[0] == 1)
+            else if ((ptr->sticky & LTK_STICKY_TOP) == LTK_STICKY_TOP)
             {
                 ptr->rect.y = grid->row_pos[i];
             }
@@ -239,10 +229,10 @@ void ltk_recalculate_grid(void *widget)
     }
 }
 
-void ltk_grid_widget(void *ptr, LtkGrid *grid, int row, int column, int row_span, int column_span, int sticky[4])
+void ltk_grid_widget(void *ptr, LtkGrid *grid, int row, int column, int row_span, int column_span, unsigned short sticky)
 {
     LtkWidget *widget = ptr;
-    memcpy(widget->sticky, sticky, 4 * sizeof(int));
+    widget->sticky = sticky;
     widget->row = row;
     widget->column = column;
     widget->row_span = row_span;
@@ -315,7 +305,7 @@ ltk_grid_mouse_release(void *widget, XEvent event)
         else
         {
             ltk_remove_hover_widget(grid);
-            ltk_change_active_widget_state(grid, ACTIVE);
+            ltk_change_active_widget_state(grid, LTK_ACTIVE);
         }
     }
 }
diff --git a/grid.h b/grid.h
@@ -46,7 +46,7 @@ void ltk_draw_grid(LtkGrid *grid);
 LtkGrid *ltk_create_grid(LtkWindow *window, int rows, int columns);
 void ltk_destroy_grid(void *widget);
 void ltk_recalculate_grid(void *widget);
-void ltk_grid_widget(void *ptr, LtkGrid *grid, int row, int column, int rowspan, int columnspan, int sticky[4]);
+void ltk_grid_widget(void *ptr, LtkGrid *grid, int row, int column, int rowspan, int columnspan, unsigned short sticky);
 void ltk_grid_mouse_press(void *widget, XEvent event);
 void ltk_grid_mouse_release(void *widget, XEvent event);
 void ltk_grid_motion_notify(void *widget, XEvent event);
diff --git a/test1.c b/test1.c
@@ -5,6 +5,15 @@ void bob1(void)
     printf("bob\n");
 }
 
+void bob2(void *widget, XEvent event)
+{
+    LtkButton *button = widget;
+    if (button->widget.state == LTK_HOVERACTIVE)
+    {
+        ltk_quit();
+    }
+}
+
 int main(int argc, char *argv[])
 {
     ltk_init("themes/default.json");
@@ -15,14 +24,16 @@ int main(int argc, char *argv[])
     ltk_set_row_weight(grid1, 1, 1);
     ltk_set_column_weight(grid1, 0, 1);
     ltk_set_column_weight(grid1, 1, 1);
+    /* Test callback functions */
     LtkButton *button1 = ltk_create_button(window1, "I'm a button!", &bob1);
-    int sticky1[4] = {0, 1, 0, 1};
-    ltk_grid_widget(button1, grid1, 0, 0, 1, 1, sticky1);
+    ltk_grid_widget(button1, grid1, 0, 0, 1, 1, LTK_STICKY_LEFT | LTK_STICKY_RIGHT);
+    /* Test manual callback functions */
     LtkButton *button2 = ltk_create_button(window1, "I'm a button!", NULL);
-    ltk_grid_widget(button2, grid1, 0, 1, 1, 1, sticky1);
+    button2->widget.mouse_release = &bob2;
+    ltk_grid_widget(button2, grid1, 0, 1, 1, 1, LTK_STICKY_TOP | LTK_STICKY_BOTTOM);
     LtkButton *button3 = ltk_create_button(window1, "I'm a button!", NULL);
-    ltk_grid_widget(button3, grid1, 1, 0, 1, 1, sticky1);
+    ltk_grid_widget(button3, grid1, 1, 0, 1, 1, LTK_STICKY_TOP | LTK_STICKY_BOTTOM | LTK_STICKY_RIGHT);
     LtkButton *button4 = ltk_create_button(window1, "I'm a button!", NULL);
-    ltk_grid_widget(button4, grid1, 1, 1, 1, 1, sticky1);
+    ltk_grid_widget(button4, grid1, 1, 1, 1, 1, LTK_STICKY_LEFT | LTK_STICKY_BOTTOM);
     ltk_mainloop();
 }
diff --git a/widget.c b/widget.c
@@ -23,10 +23,45 @@
 
 #include "ltk.h"
 
+LtkWidget ltk_create_widget(LtkWindow *window, void (*draw)(void *), void (*destroy)(void *), int needs_redraw)
+{
+    LtkWidget widget;
+    widget.window = window;
+    widget.active_widget = NULL;
+    widget.hover_widget = NULL;
+    widget.parent = NULL;
+
+    widget.key_press = NULL;
+    widget.key_release = NULL;
+    widget.mouse_press = NULL;
+    widget.mouse_release = NULL;
+    widget.motion_notify = NULL;
+
+    widget.resize = NULL;
+    widget.draw = draw;
+    widget.destroy = destroy;
+
+    widget.needs_redraw = needs_redraw;
+    widget.state = LTK_NORMAL;
+    widget.row = 0;
+    widget.rect.x = 0;
+    widget.rect.y = 0;
+    widget.rect.w = 100;
+    widget.rect.h = 100;
+
+    widget.row = NULL;
+    widget.column = NULL;
+    widget.row_span = NULL;
+    widget.column_span = NULL;
+    widget.sticky = NULL;
+
+    return widget;
+}
+
 void ltk_mouse_press_event(void *widget, XEvent event)
 {
     LtkWidget *ptr = widget;
-    if (!ptr || ptr->state == DISABLED) return;
+    if (!ptr || ptr->state == LTK_DISABLED) return;
     if (event.xbutton.button == 1)
     {
         LtkWidget *parent = ptr->parent;
@@ -35,8 +70,8 @@ void ltk_mouse_press_event(void *widget, XEvent event)
             ltk_remove_active_widget(parent);
             parent->active_widget = ptr;
         }
-        ptr->state = PRESSED;
-        if (ptr->redraw_state) ptr->draw(ptr);
+        ptr->state = LTK_PRESSED;
+        if (ptr->needs_redraw) ptr->draw(ptr);
     }
     if (ptr->mouse_press)
     {
@@ -47,11 +82,11 @@ void ltk_mouse_press_event(void *widget, XEvent event)
 void ltk_mouse_release_event(void *widget, XEvent event)
 {
     LtkWidget *ptr = widget;
-    if (!ptr || ptr->state == DISABLED) return;
-    if (ptr->state == PRESSED)
+    if (!ptr || ptr->state == LTK_DISABLED) return;
+    if (ptr->state == LTK_PRESSED)
     {
-        ptr->state = HOVERACTIVE;
-        if (ptr->redraw_state) ptr->draw(ptr);
+        ptr->state = LTK_HOVERACTIVE;
+        if (ptr->needs_redraw) ptr->draw(ptr);
     }
     if (ptr->mouse_release)
     {
@@ -62,17 +97,17 @@ void ltk_mouse_release_event(void *widget, XEvent event)
 void ltk_motion_notify_event(void *widget, XEvent event)
 {
     LtkWidget *ptr = widget;
-    if (ptr && (ptr->state == NORMAL || ptr->state == ACTIVE) &&
+    if (ptr && (ptr->state == LTK_NORMAL || ptr->state == LTK_ACTIVE) &&
         (event.xmotion.state & Button1Mask) != Button1Mask)
     {
-        ptr->state = ptr->state == ACTIVE ? HOVERACTIVE : HOVER;
+        ptr->state = ptr->state == LTK_ACTIVE ? LTK_HOVERACTIVE : LTK_HOVER;
         LtkWidget *parent = ptr->parent;
         if (parent)
         {
             ltk_remove_hover_widget(parent);
             parent->hover_widget = ptr;
         }
-        if (ptr->redraw_state) ptr->draw(ptr);
+        if (ptr->needs_redraw) ptr->draw(ptr);
     }
     if (ptr->motion_notify)
     {
diff --git a/widget.h b/widget.h
@@ -26,6 +26,13 @@
 
 #include "event.h"
 
+typedef enum {
+    LTK_STICKY_LEFT = 1 << 0,
+    LTK_STICKY_RIGHT = 1 << 1,
+    LTK_STICKY_TOP = 1 << 2,
+    LTK_STICKY_BOTTOM = 1 << 3
+} LtkStickyMask;
+
 typedef struct LtkWindow LtkWindow;
 
 typedef struct LtkWidget
@@ -33,11 +40,11 @@ typedef struct LtkWidget
     /* The window the widget will be displayed on */
     LtkWindow *window;
     /* For container widgets; the widget that is currently active */
-    void *active_widget;
+    struct LtkWidget *active_widget;
     /* For container widgets; the widget that is currently highlighted */
-    void *hover_widget;
+    struct LtkWidget *hover_widget;
     /* Parent widget */
-    void *parent;
+    struct LtkWidget *parent;
 
     /* Called on KeyPress events */
     void (*key_press)(void *, XEvent event);
@@ -58,7 +65,7 @@ typedef struct LtkWidget
     void (*destroy)(void *);
 
     /* Specifies if the widget needs to be redrawn after a state change */
-    int redraw_state;
+    int needs_redraw;
     /* State of the widget */
     LtkWidgetState state;
     /* Position and size of the widget */
@@ -72,8 +79,9 @@ typedef struct LtkWidget
     /* Column span of widget if gridded */
     unsigned int column_span;
     /* Similar to sticky in tk */
-    /* -y, +x, +y, -x */
-    int sticky[4];
+    unsigned short sticky;
 } LtkWidget;
 
+LtkWidget ltk_create_widget(LtkWindow *window, void (*draw)(void *), void (*destroy)(void *), int needs_redraw);
+
 #endif