commit f8162695f7e3ea7d517610987a5fbc614f515878
parent 0d6981b3dbd7dbfcc80fe517414fac3da70822b4
Author: lumidify <nobody@lumidify.org>
Date:   Sun,  1 Jan 2017 18:48:28 +0100
Update event system
Diffstat:
15 files changed, 218 insertions(+), 177 deletions(-)
diff --git a/README.md b/README.md
@@ -6,6 +6,6 @@ Please do not attempt to actually use any of the code.
 
 ## Licenses of Other Libraries Used
 
-[uthash](https://troydhanson.github.io/uthash/): [BSD Revised](https://troydhanson.github.io/uthash/license.html)
+[uthash](https://troydhanson.github.io/uthash/) by Troy D. Hanson: [BSD Revised](https://troydhanson.github.io/uthash/license.html)
 
-[cJSON](https://github.com/DaveGamble/cJSON): [MIT/X](https://github.com/DaveGamble/cJSON/blob/master/LICENSE)
+[cJSON](https://github.com/DaveGamble/cJSON) by Dave Gamble: [MIT/X](https://github.com/DaveGamble/cJSON/blob/master/LICENSE)
diff --git a/button.c b/button.c
@@ -154,6 +154,7 @@ void ltk_draw_button(void *widget)
     }
     XSetForeground(ltk_global->display, window->gc, fill_color.pixel);
     XFillRectangle(ltk_global->display, window->xwindow, window->gc, rect.x, rect.y, rect.w, rect.h);
+    if (border_width < 1) return;
     XSetForeground(ltk_global->display, window->gc, border_color.pixel);
     XSetLineAttributes(ltk_global->display, window->gc, border_width, LineSolid, CapButt, JoinMiter);
     XDrawRectangle(ltk_global->display, window->xwindow, window->gc, rect.x, rect.y, rect.w, rect.h);
@@ -173,11 +174,15 @@ LtkButton *ltk_create_button(LtkWindow *window, const char *text, void (*callbac
     button->widget.parent = NULL;
     button->widget.active_widget = NULL;
     button->widget.hover_widget = NULL;
-    button->widget.key_func = <k_button_key_event;
-    button->widget.mouse_func = <k_button_mouse_event;
-    button->widget.update_function = NULL;
-    button->widget.draw_function = <k_draw_button;
-    button->widget.destroy_function = <k_destroy_button;
+    button->widget.key_press = NULL;
+    button->widget.key_release = NULL;
+    button->widget.mouse_press = NULL;
+    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 */
@@ -206,52 +211,8 @@ void ltk_button_key_event(void *widget, XEvent event)
 {
 }
 
-void ltk_button_mouse_event(void *widget, XEvent event)
+
+void ltk_button_mouse_release(void *widget, XEvent event)
 {
     LtkButton *button = widget;
-    if (button->widget.state == DISABLED)
-    {
-        return;
-    }
-    if (event.type == ButtonPress && event.xbutton.button == 1)
-    {
-        LtkWidget *parent = button->widget.parent;
-        if (parent)
-        {
-            ltk_remove_active_widget(parent);
-            parent->active_widget = button;
-        }
-        button->widget.state = PRESSED;
-        ltk_draw_button(button);
-    }
-    else if (event.type == ButtonRelease)
-    {
-        if (button->widget.state == PRESSED)
-        {
-            button->widget.state = HOVERACTIVE;
-            ltk_draw_button(button);
-        }
-    }
-    else if (event.type == MotionNotify)
-    {
-        if (button->widget.state == NORMAL || button->widget.state == ACTIVE)
-        {
-            if (button->widget.state == ACTIVE)
-            {
-                button->widget.state = HOVERACTIVE;
-            }
-            else
-            {
-                button->widget.state = HOVER;
-            }
-            LtkWidget *parent = button->widget.parent;
-            LtkWidget *hover_widget;
-            if (parent)
-            {
-                ltk_remove_hover_widget(parent);
-                parent->hover_widget = button;
-            }
-            ltk_draw_button(button);
-        }
-    }
 }
diff --git a/button.h b/button.h
@@ -72,7 +72,6 @@ LtkButton *ltk_create_button(LtkWindow *window, const char *text, void (*callbac
 void ltk_button_key_event(void *widget, XEvent event);
 void ltk_button_mouse_event(void *widget, XEvent event);
 void ltk_destroy_button(void *widget);
-void ltk_button_key_event(void *widget, XEvent event);
-void ltk_button_mouse_event(void *widget, XEvent event);
+void ltk_button_mouse_release(void *widget, XEvent event);
 
 #endif
diff --git a/common.c b/common.c
@@ -56,7 +56,7 @@ void ltk_remove_active_widget(void *widget)
     {
         child = parent->active_widget;
         child->state = NORMAL;
-        child->draw_function(child);
+        child->draw(child);
         parent->active_widget = NULL;
         parent = child;
     }
@@ -73,7 +73,7 @@ void ltk_remove_hover_widget(void *widget)
     {
         child = parent->hover_widget;
         child->state = child->state == HOVERACTIVE ? ACTIVE : NORMAL;
-        child->draw_function(child);
+        child->draw(child);
         parent->hover_widget = NULL;
         parent = child;
     }
diff --git a/common.h b/common.h
@@ -24,6 +24,7 @@
 #ifndef _LTK_COMMON_H_
 #define _LTK_COMMON_H_
 
+typedef void (*LTK_VOID_FUNC)(void *);
 typedef struct LtkWidget LtkWidget;
 
 typedef enum
diff --git a/event.c b/event.c
@@ -26,17 +26,27 @@
 void ltk_handle_event(XEvent event)
 {
     LtkWindow *window;
+    LtkWidget *root_widget;
     HASH_FIND_INT(ltk_global->window_hash, &event.xany.window, window);
-    if ((event.type == KeyPress || event.type == KeyRelease) && window->key_func)
+    root_widget = window->root_widget;
+    if (!root_widget) return;
+    switch (event.type)
     {
-        window->key_func(window, event);
-    }
-    else if ((event.type == ButtonPress || event.type == ButtonRelease || event.type == MotionNotify) && window->mouse_func)
-    {
-        window->mouse_func(window, event);
-    }
-    else if (window->other_func)
-    {
-        window->other_func(window, event);
+    case KeyPress:
+        break;
+    case KeyRelease:
+        break;
+    case ButtonPress:
+        ltk_mouse_press_event(root_widget, event);
+        break;
+    case ButtonRelease:
+        ltk_mouse_release_event(root_widget, event);
+        break;
+    case MotionNotify:
+        ltk_motion_notify_event(root_widget, event);
+        break;
+    default:
+        if (window->other_event)
+            window->other_event(window, event);
     }
 }
diff --git a/event.h b/event.h
@@ -26,6 +26,6 @@
 #ifndef _LTK_EVENT_H_
 #define _LTK_EVENT_H_
 
-typedef void (*LTK_EVENT_FUNC)(void *widget, XEvent event);
+typedef void (*LTK_EVENT_FUNC)(void *, XEvent);
 
 #endif
diff --git a/grid.c b/grid.c
@@ -42,12 +42,9 @@ void ltk_draw_grid(LtkGrid *grid)
     int i;
     for (i = 0; i < grid->rows * grid->columns; i++)
     {
-        if (!grid->widget_grid[i])
-        {
-            continue;
-        }
+        if (!grid->widget_grid[i]) continue;
         LtkWidget *ptr = grid->widget_grid[i];
-        ptr->draw_function(ptr);
+        ptr->draw(ptr);
     }
 }
 
@@ -57,11 +54,15 @@ LtkGrid *ltk_create_grid(LtkWindow *window, int rows, int columns)
 
     grid->widget.window = window;
     grid->widget.parent = NULL;
-    grid->widget.key_func = <k_grid_key_event;
-    grid->widget.mouse_func = <k_grid_mouse_event;
-    grid->widget.update_function = <k_recalculate_grid;
-    grid->widget.draw_function = <k_draw_grid;
-    grid->widget.destroy_function = <k_destroy_grid;
+    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;
@@ -113,7 +114,7 @@ void ltk_destroy_grid(void *widget)
         if (grid->widget_grid[i])
         {
             ptr = grid->widget_grid[i];
-            ptr->destroy_function(ptr);
+            ptr->destroy(ptr);
         }
     }
     free(grid->widget_grid);
@@ -203,9 +204,9 @@ void ltk_recalculate_grid(void *widget)
             }
             if (orig_width != ptr->rect.w || orig_height != ptr->rect.h)
             {
-                if (ptr->update_function)
+                if (ptr->resize)
                 {
-                    ptr->update_function(ptr);
+                    ptr->resize(ptr);
                 }
             }
 
@@ -246,10 +247,12 @@ void ltk_grid_widget(void *ptr, LtkGrid *grid, int row, int column, int row_span
     widget->column = column;
     widget->row_span = row_span;
     widget->column_span = column_span;
-    if (grid->column_weights[column] == 0 && widget->rect.w > grid->column_widths[column]) {
+    if (grid->column_weights[column] == 0 && widget->rect.w > grid->column_widths[column])
+    {
         grid->column_widths[column] = widget->rect.w;
     }
-    if (grid->row_weights[row] == 0 && widget->rect.h > grid->row_heights[row]) {
+    if (grid->row_weights[row] == 0 && widget->rect.h > grid->row_heights[row])
+    {
         grid->row_heights[row] = widget->rect.h;
     }
     grid->widget_grid[widget->row * grid->columns + widget->column] = widget;
@@ -257,57 +260,71 @@ void ltk_grid_widget(void *ptr, LtkGrid *grid, int row, int column, int row_span
     ltk_recalculate_grid(grid);
 }
 
-void ltk_grid_key_event(void *widget, XEvent event)
-{
-    LtkGrid *grid = widget;
-    LtkWidget *ptr = grid->widget.active_widget;
-    if (ptr && ptr->key_func)
-    {
-        ptr->key_func(ptr, event);
-    }
-}
-
-void ltk_grid_mouse_event(void *widget, XEvent event)
+int ltk_grid_find_nearest_column(LtkGrid *grid, int x)
 {
-    LtkGrid *grid = widget;
-    LtkWidget *ptr;
     int i;
-    int x, y;
-    int row, column;
-    if (event.type == ButtonPress || event.type == ButtonRelease)
-    {
-        x = event.xbutton.x;
-        y = event.xbutton.y;
-    }
-    else if (event.type == MotionNotify)
-    {
-        x = event.xmotion.x;
-        y = event.xmotion.y;
-    }
     for (i = 0; i < grid->columns; i++)
     {
         if (grid->column_pos[i] <= x && grid->column_pos[i + 1] >= x)
         {
-            column = i;
+            return i;
         }
     }
+}
+
+int ltk_grid_find_nearest_row(LtkGrid *grid, int y)
+{
+    int i;
     for (i = 0; i < grid->rows; i++)
     {
         if (grid->row_pos[i] <= y && grid->row_pos[i + 1] >= y)
         {
-            row = i;
+            return i;
         }
     }
-    ptr = grid->widget_grid[row * grid->columns + column];
-    if (ptr && ptr->mouse_func)
+}
+
+ltk_grid_mouse_press(void *widget, XEvent event)
+{
+    LtkGrid *grid = widget;
+    int x = event.xbutton.x;
+    int y = event.xbutton.y;
+    int row = ltk_grid_find_nearest_row(grid, y);
+    int column = ltk_grid_find_nearest_column(grid, x);
+    LtkWidget *ptr = grid->widget_grid[row * grid->columns + column];
+    if (ptr && ltk_collide_rect(ptr->rect, x, y))
+    {
+        ltk_mouse_press_event(ptr, event);
+    }
+}
+
+ltk_grid_mouse_release(void *widget, XEvent event)
+{
+    LtkGrid *grid = widget;
+    int x = event.xbutton.x;
+    int y = event.xbutton.y;
+    int row = ltk_grid_find_nearest_row(grid, y);
+    int column = ltk_grid_find_nearest_column(grid, x);
+    LtkWidget *ptr = grid->widget_grid[row * grid->columns + column];
+    if (ptr && ltk_collide_rect(ptr->rect, x, y))
+    {
+        ltk_mouse_release_event(ptr, event);
+    }
+}
+
+ltk_grid_motion_notify(void *widget, XEvent event)
+{
+    LtkGrid *grid = widget;
+    int x = event.xbutton.x;
+    int y = event.xbutton.y;
+    int row = ltk_grid_find_nearest_row(grid, y);
+    int column = ltk_grid_find_nearest_column(grid, x);
+    LtkWidget *ptr = grid->widget_grid[row * grid->columns + column];
+    if (ptr)
     {
         if (ltk_collide_rect(ptr->rect, x, y))
-        {
-        ptr->mouse_func(ptr, event);
-        }
-        else if (grid->widget.hover_widget)
-        {
+            ltk_motion_notify_event(ptr, event);
+        else
             ltk_remove_hover_widget(grid);
-        }
     }
 }
diff --git a/grid.h b/grid.h
@@ -46,8 +46,9 @@ 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_key_event(void *widget, XEvent event);
-void ltk_grid_mouse_event(void *widget, XEvent event);
 void ltk_grid_widget(void *ptr, LtkGrid *grid, int row, int column, int rowspan, int columnspan, int sticky[4]);
+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);
 
 #endif
diff --git a/test1.c b/test1.c
@@ -1,21 +1,8 @@
 #include "ltk.h"
 
-void bob(void *window, XEvent event)
+void bob1(void)
 {
-    KeySym key;
-    char text[255];
-    if (XLookupString(&event.xkey, text, 255, &key, 0) == 1)
-    {
-        if (text[0] == 'q')
-        {
-            ltk_quit();
-        }
-    }
-}
-
-void bob1(void *window, XEvent event)
-{
-    printf("mouse\n");
+    printf("bob\n");
 }
 
 int main(int argc, char *argv[])
@@ -28,7 +15,7 @@ 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);
-    LtkButton *button1 = ltk_create_button(window1, "I'm a button!", NULL);
+    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);
     LtkButton *button2 = ltk_create_button(window1, "I'm a button!", NULL);
diff --git a/themes/default.ini b/themes/default.ini
@@ -0,0 +1,21 @@
+[window]
+border_width = 0
+background = #000000
+foreground = #FFFFFF
+
+[button]
+border_width = 2
+font_size = 20
+border_color = #339999
+fill_color = #113355
+pad_left = 5
+pad_right = 5
+pad_top = 5
+pad_bottom = 5
+fill_color_hover = 738194
+border_color_pressed = #FFFFFF
+fill_color_pressed = 113355
+border_color_active = #FFFFFF
+fill_color_active = #113355
+border_color_disabled = #FFFFFF
+fill_color_disabled = #292929
diff --git a/widget.c b/widget.c
@@ -21,3 +21,60 @@
  * SOFTWARE.
  */
 
+#include "ltk.h"
+
+void ltk_mouse_press_event(void *widget, XEvent event)
+{
+    LtkWidget *ptr = widget;
+    if (!ptr || ptr->state == DISABLED) return;
+    if (event.xbutton.button == 1)
+    {
+        LtkWidget *parent = ptr->parent;
+        if (parent)
+        {
+            ltk_remove_active_widget(parent);
+            parent->active_widget = ptr;
+        }
+        ptr->state = PRESSED;
+        if (ptr->redraw_state) ptr->draw(ptr);
+    }
+    if (ptr->mouse_press)
+    {
+        ptr->mouse_press(ptr, event);
+    }
+}
+
+void ltk_mouse_release_event(void *widget, XEvent event)
+{
+    LtkWidget *ptr = widget;
+    if (!ptr || ptr->state == DISABLED) return;
+    if (ptr->state == PRESSED)
+    {
+        ptr->state = HOVERACTIVE;
+        if (ptr->redraw_state) ptr->draw(ptr);
+    }
+    if (ptr->mouse_release)
+    {
+        ptr->mouse_release(ptr, event);
+    }
+}
+
+void ltk_motion_notify_event(void *widget, XEvent event)
+{
+    LtkWidget *ptr = widget;
+    if (!ptr || ptr->state == NORMAL || ptr->state == ACTIVE)
+    {
+        ptr->state = ptr->state == ACTIVE ? HOVERACTIVE : 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->motion_notify)
+    {
+        ptr->motion_notify(ptr, event);
+    }
+}
diff --git a/widget.h b/widget.h
@@ -38,18 +38,29 @@ typedef struct LtkWidget
     void *hover_widget;
     /* Parent widget */
     void *parent;
-    /* Function to be called on a KeyPress or KeyRelease event */
-    LTK_EVENT_FUNC key_func;
-    /* Function to be called on a ButtonPress, ButtonRelease, or MotionNotify event */
-    LTK_EVENT_FUNC mouse_func;
-    /* For container widgets; function to be called when the widget is resized */
-    void (*update_function)(void *);
+
+    /* Called on KeyPress events */
+    void (*key_press)(void *, XEvent event);
+    /* Called on KeyRelease events */
+    void (*key_release)(void *, XEvent event);
+    /* Called on ButtonPress events */
+    void (*mouse_press)(void *, XEvent event);
+    /* Called on ButtonRelease event */
+    void (*mouse_release)(void *, XEvent event);
+    /* Called on MotionNotify events */
+    void (*motion_notify)(void *, XEvent event);
+
+    /* Function to update the widget after its LtkRect has been modified */
+    void (*resize)(void *);
     /* Function to draw the widget */
-    void (*draw_function)(void *);
-    /* State of the widget; NORMAL, PRESSED, ACTIVE, HOVER, or DISABLED */
+    void (*draw)(void *);
+    /* Function to destroy the widget */
+    void (*destroy)(void *);
+
+    /* Specifies if the widget needs to be redrawn after a state change */
+    int redraw_state;
+    /* State of the widget */
     LtkWidgetState state;
-    /* Function to destroy the widget; used by containers to destroy child widgets */
-    void (*destroy_function)(void *);
     /* Position and size of the widget */
     LtkRect rect;
     /* Row of widget if gridded */
diff --git a/window.c b/window.c
@@ -49,7 +49,7 @@ void ltk_redraw_window(LtkWindow *window)
         return;
     }
     ptr = window->root_widget;
-    ptr->draw_function(ptr);
+    ptr->draw(ptr);
 }
 
 LtkWindow *ltk_create_window(const char *title, int x, int y, unsigned int w, unsigned int h)
@@ -65,9 +65,7 @@ LtkWindow *ltk_create_window(const char *title, int x, int y, unsigned int w, un
     XSetStandardProperties(display, window->xwindow, title, NULL, None, NULL, 0, NULL);
     window->root_widget = NULL;
 
-    window->key_func = <k_window_key_event;
-    window->mouse_func = <k_window_mouse_event;
-    window->other_func = <k_window_other_event;
+    window->other_event = <k_window_other_event;
 
     window->rect.w = 0;
     window->rect.h = 0;
@@ -88,31 +86,11 @@ void ltk_destroy_window(LtkWindow *window)
     LtkWidget *ptr = window->root_widget;
     if (ptr)
     {
-        ptr->destroy_function(ptr);
+        ptr->destroy(ptr);
     }
     free(window);
 }
 
-void ltk_window_key_event(void *widget, XEvent event)
-{
-    LtkWindow *window = widget;
-    LtkWidget *ptr = window->root_widget;
-    if (ptr && ptr->key_func)
-    {
-        ptr->key_func(ptr, event);
-    }
-}
-
-void ltk_window_mouse_event(void *widget, XEvent event)
-{
-    LtkWindow *window = widget;
-    LtkWidget *ptr = window->root_widget;
-    if (ptr && ptr->mouse_func)
-    {
-        ptr->mouse_func(ptr, event);
-    }
-}
-
 void ltk_window_other_event(void *widget, XEvent event)
 {
     LtkWindow *window = widget;
@@ -122,13 +100,13 @@ void ltk_window_other_event(void *widget, XEvent event)
         unsigned int w, h;
         w = event.xconfigure.width;
         h = event.xconfigure.height;
-        if (ptr && ptr->update_function && (window->rect.w != w || window->rect.h != h))
+        if (ptr && ptr->resize && (window->rect.w != w || window->rect.h != h))
         {
             window->rect.w = w;
             window->rect.h = h;
             ptr->rect.w = w;
             ptr->rect.h = h;
-            ptr->update_function(ptr);
+            ptr->resize(ptr);
             ltk_redraw_window(window);
         }
     }
@@ -155,7 +133,7 @@ void ltk_resize_window(Uint32 id, int w, int h)
     }
     ptr->rect.w = w;
     ptr->rect.h = h;
-    ptr->update_function(ptr);
+    ptr->resize(ptr);
 }
 
 void ltk_window_set_root_widget(LtkWindow *window, void *root_widget)
diff --git a/window.h b/window.h
@@ -32,9 +32,7 @@ typedef struct LtkWindow
     Window xwindow;
     GC gc;
     void *root_widget;
-    LTK_EVENT_FUNC key_func;           /* Called on any keyboard event */
-    LTK_EVENT_FUNC mouse_func;         /* Called on any mouse event */
-    LTK_EVENT_FUNC other_func;         /* Called on any other event */
+    void (*other_event)(void *, XEvent event);
     LtkRect rect;
     UT_hash_handle hh;
 } LtkWindow;