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