ltkx

GUI toolkit for X11 (WIP)
git clone git://lumidify.org/ltkx.git
Log | Files | Refs | README | LICENSE

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:
Mbutton.c | 56+++++++++++++++++++++++++++++---------------------------
Mbutton.h | 2+-
Mcommon.c | 8++++----
Mcommon.h | 12++++++------
Mgrid.c | 34++++++++++++----------------------
Mgrid.h | 2+-
Mtest1.c | 21++++++++++++++++-----
Mwidget.c | 55+++++++++++++++++++++++++++++++++++++++++++++----------
Mwidget.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, &ltk_draw_button, &ltk_destroy_button, 1); button->widget.mouse_release = &ltk_button_mouse_release; - button->widget.motion_notify = NULL; - button->widget.resize = NULL; - button->widget.draw = &ltk_draw_button; - button->widget.destroy = &ltk_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, &ltk_draw_grid, &ltk_destroy_grid, 0); grid->widget.mouse_press = &ltk_grid_mouse_press; grid->widget.mouse_release = &ltk_grid_mouse_release; grid->widget.motion_notify = &ltk_grid_motion_notify; - grid->widget.key_press = NULL; - grid->widget.key_release = NULL; grid->widget.resize = &ltk_recalculate_grid; - grid->widget.draw = &ltk_draw_grid; - grid->widget.destroy = &ltk_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