commit 791c8bda54d3acfcffabba04ff1be38852c38435
parent 829de8bbcb77ea2607f1ec22113222ac755256b8
Author: lumidify <nobody@lumidify.org>
Date: Sat, 16 Jan 2021 21:37:25 +0100
Improve resizing; misc. changes
Diffstat:
M | box.c | | | 119 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------- |
M | button.c | | | 4 | ++-- |
M | grid.c | | | 74 | ++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ |
M | label.c | | | 4 | ++-- |
M | ltk.h | | | 8 | ++++++-- |
M | ltkd.c | | | 15 | +++++++++------ |
M | testbox.gui | | | 2 | ++ |
7 files changed, 161 insertions(+), 65 deletions(-)
diff --git a/box.c b/box.c
@@ -38,6 +38,7 @@ static void ltk_box_draw(ltk_box *box);
static ltk_box *ltk_box_create(ltk_window *window, const char *id, ltk_orientation orient);
static void ltk_box_destroy(ltk_box *box, int shallow);
static void ltk_recalculate_box(ltk_box *box);
+static void ltk_box_child_size_change(ltk_box *box, ltk_widget *widget);
/* FIXME: Why is sticky unsigned short? */
static int ltk_box_add(ltk_window *window, ltk_widget *widget, ltk_box *box, unsigned short sticky, char **errstr);
static int ltk_box_remove(ltk_window *window, ltk_widget *widget, ltk_box *box, char **errstr);
@@ -91,6 +92,7 @@ ltk_box_create(ltk_window *window, const char *id, ltk_orientation orient) {
box->widget.mouse_release = <k_box_mouse_release;
box->widget.motion_notify = <k_box_motion_notify;
box->widget.resize = <k_recalculate_box;
+ box->widget.child_size_change = <k_box_child_size_change;
box->widget.remove_child = <k_box_remove;
box->sc = NULL;
@@ -117,7 +119,6 @@ ltk_box_destroy(ltk_box *box, int shallow) {
free(box);
}
-/* FIXME: Allow no sticky value to be centered in middle */
/* FIXME: Need some sort of "visible rect" so widgets don't draw outside */
/* FIXME: Make this function name more consistent */
static void
@@ -128,26 +129,70 @@ ltk_recalculate_box(ltk_box *box) {
ptr = box->widgets[i];
if (box->orient == LTK_HORIZONTAL) {
ptr->rect.x = cur_pos;
- cur_pos += ptr->rect.w;
if (ptr->sticky & LTK_STICKY_TOP && ptr->sticky & LTK_STICKY_BOTTOM)
ptr->rect.h = box->widget.rect.h;
if (ptr->sticky & LTK_STICKY_TOP)
ptr->rect.y = box->widget.rect.y;
else if (ptr->sticky & LTK_STICKY_BOTTOM)
ptr->rect.y = box->widget.rect.y + box->widget.rect.h - ptr->rect.h;
+ else
+ ptr->rect.y = box->widget.rect.y + (box->widget.rect.h - ptr->rect.h) / 2;
+ if (ptr->resize)
+ ptr->resize(ptr);
+ cur_pos += ptr->rect.w;
} else {
ptr->rect.y = cur_pos;
- cur_pos += ptr->rect.h;
if (ptr->sticky & LTK_STICKY_LEFT && ptr->sticky & LTK_STICKY_RIGHT)
ptr->rect.w = box->widget.rect.w;
if (ptr->sticky & LTK_STICKY_LEFT)
ptr->rect.x = box->widget.rect.x;
else if (ptr->sticky & LTK_STICKY_RIGHT)
ptr->rect.x = box->widget.rect.x + box->widget.rect.w - ptr->rect.w;
+ else
+ ptr->rect.x = box->widget.rect.x + (box->widget.rect.w - ptr->rect.w) / 2;
+ if (ptr->resize)
+ ptr->resize(ptr);
+ cur_pos += ptr->rect.h;
}
}
}
+/* FIXME: This entire resizing thing is a bit weird. For instance, if a label
+ in a vertical box increases its height because its width has been decreased
+ and it is forced to wrap, should that just change the rect or also the
+ ideal size? Ideal size wouldn't really make sense here, but then the box
+ might be forced to add a scrollbar even though the parent widget would
+ actually give it more space if it knew that it needed it. */
+
+static void
+ltk_box_child_size_change(ltk_box *box, ltk_widget *widget) {
+ short size_changed = 0;
+ /* This is always reset here - if it needs to be changed,
+ the resize function called by the last child_size_change
+ function will fix it */
+ /* Note: This seems a bit weird, but if each widget set its rect itself,
+ that would also lead to weird things. For instance, if a butten is
+ added to after a box after being ungridded, and its rect was changed
+ by the grid (e.g. because of a column weight), who should reset the
+ rect if it doesn't have sticky set? Of course, the resize function
+ could also set all widgets even if they don't have any sticky
+ settings, but there'd probably be some catch as well. */
+ widget->rect.w = widget->ideal_w;
+ widget->rect.h = widget->ideal_h;
+ if (box->orient == LTK_HORIZONTAL && widget->ideal_h > box->widget.ideal_h) {
+ box->widget.ideal_h = widget->ideal_h;
+ size_changed = 1;
+ } else if (box->orient == LTK_VERTICAL && widget->ideal_w > box->widget.ideal_h) {
+ box->widget.ideal_w = widget->ideal_w;
+ size_changed = 1;
+ }
+
+ if (size_changed && box->widget.parent && box->widget.parent->child_size_change)
+ box->widget.parent->child_size_change(box->widget.parent, box);
+ else
+ ltk_recalculate_box(box);
+}
+
static int
ltk_box_add(ltk_window *window, ltk_widget *widget, ltk_box *box, unsigned short sticky, char **errstr) {
if (widget->parent) {
@@ -164,9 +209,13 @@ ltk_box_add(ltk_window *window, ltk_widget *widget, ltk_box *box, unsigned short
}
box->widgets[box->num_widgets++] = widget;
+ if (box->orient == LTK_HORIZONTAL)
+ box->widget.ideal_w += widget->ideal_w;
+ else
+ box->widget.ideal_h += widget->ideal_h;
widget->parent = box;
widget->sticky = sticky;
- ltk_recalculate_box(box);
+ ltk_box_child_size_change(box, widget);
ltk_window_invalidate_rect(window, box->widget.rect);
return 0;
@@ -186,6 +235,25 @@ ltk_box_remove(ltk_window *window, ltk_widget *widget, ltk_box *box, char **errs
(box->num_widgets - i - 1) * sizeof(ltk_widget *));
box->num_widgets--;
ltk_window_invalidate_rect(window, box->widget.rect);
+ /* search for new ideal width/height */
+ /* FIXME: make this all a bit nicer and break the lines better */
+ if (box->orient == LTK_HORIZONTAL && widget->ideal_h == box->widget.ideal_h) {
+ box->widget.ideal_h = 0;
+ for (size_t j = 0; j < box->num_widgets; j++) {
+ if (box->widgets[j]->ideal_h > box->widget.ideal_h)
+ box->widget.ideal_h = box->widgets[j]->ideal_h;
+ }
+ if (box->widget.parent && box->widget.parent->resize)
+ box->widget.parent->resize(box->widget.parent);
+ } else if (box->orient == LTK_VERTICAL && widget->ideal_w == box->widget.ideal_w) {
+ box->widget.ideal_w = 0;
+ for (size_t j = 0; j < box->num_widgets; j++) {
+ if (box->widgets[j]->ideal_w > box->widget.ideal_w)
+ box->widget.ideal_w = box->widgets[j]->ideal_w;
+ }
+ if (box->widget.parent && box->widget.parent->resize)
+ box->widget.parent->resize(box->widget.parent);
+ }
return 0;
}
}
@@ -204,18 +272,10 @@ ltk_box_mouse_event(ltk_box *box, XEvent event, void (*handler)(ltk_widget *, XE
handler(box->sc, event);
*/
+ /* FIXME: When scrolling is implemented, check only the currently visible items */
for (size_t i = 0; i < box->num_widgets; i++) {
widget = box->widgets[i];
- if (box->orient == LTK_HORIZONTAL) {
- pos = event.xbutton.x;
- start = widget->rect.x;
- size = widget->rect.w;
- } else {
- pos = event.xbutton.y;
- start = widget->rect.y;
- size = widget->rect.h;
- }
- if (pos >= start && pos <= start + size) {
+ if (ltk_collide_rect(widget->rect, event.xbutton.x, event.xbutton.y)) {
handler(widget, event);
return;
}
@@ -243,7 +303,7 @@ ltk_box_motion_notify(ltk_box *box, XEvent event) {
ltk_box_mouse_event(box, event, <k_widget_motion_notify_event);
}
-/* box <box id> add <widget id> <sticky> */
+/* box <box id> add <widget id> [sticky] */
static int
ltk_box_cmd_add(
ltk_window *window,
@@ -255,7 +315,7 @@ ltk_box_cmd_add(
ltk_widget *widget;
int sticky = 0;
- if (num_tokens != 5) {
+ if (num_tokens != 4 && num_tokens != 5) {
*errstr = "Invalid number of arguments.\n";
return 1;
}
@@ -266,19 +326,20 @@ ltk_box_cmd_add(
return 1;
}
- /* FIXME: Allow default value (just no sticky at all) */
- for (c = tokens[4]; *c != '\0'; c++) {
- if (*c == 'n') {
- sticky |= LTK_STICKY_TOP;
- } else if (*c == 's') {
- sticky |= LTK_STICKY_BOTTOM;
- } else if (*c == 'e') {
- sticky |= LTK_STICKY_RIGHT;
- } else if (*c == 'w') {
- sticky |= LTK_STICKY_LEFT;
- } else if (*c != 'u') {
- *errstr = "Invalid sticky specification.\n";
- return 1;
+ if (num_tokens == 5) {
+ for (c = tokens[4]; *c != '\0'; c++) {
+ if (*c == 'n') {
+ sticky |= LTK_STICKY_TOP;
+ } else if (*c == 's') {
+ sticky |= LTK_STICKY_BOTTOM;
+ } else if (*c == 'e') {
+ sticky |= LTK_STICKY_RIGHT;
+ } else if (*c == 'w') {
+ sticky |= LTK_STICKY_LEFT;
+ } else {
+ *errstr = "Invalid sticky specification.\n";
+ return 1;
+ }
}
}
diff --git a/button.c b/button.c
@@ -213,8 +213,8 @@ ltk_button_create(ltk_window *window, const char *id, const char *text) {
button->tl = ltk_text_line_create(window->xwindow, font_size, text_copy, -1);
int text_w, text_h;
ltk_text_line_get_size(button->tl, &text_w, &text_h);
- button->widget.rect.w = text_w + theme.border_width * 2 + theme.pad * 2;
- button->widget.rect.h = text_h + theme.border_width * 2 + theme.pad * 2;
+ button->widget.ideal_w = text_w + theme.border_width * 2 + theme.pad * 2;
+ button->widget.ideal_h = text_h + theme.border_width * 2 + theme.pad * 2;
/* render text */
ltk_button_change_state(button);
diff --git a/grid.c b/grid.c
@@ -21,8 +21,12 @@
* SOFTWARE.
*/
-/* TODO: remove_widget function that also adjusts static width */
-/* TODO: widget size request */
+/* TODO: make ungrid function also adjust static row/column width/height
+ -> also, how should the grid deal with a widget spanning over multiple
+ rows/columns with static size - if all are static, it could just
+ divide the widget size (it would complicate things, though), but
+ what should happen if some rows/columns under the span do have a
+ positive weight? */
#include <stdio.h>
#include <stdlib.h>
@@ -43,6 +47,7 @@ static ltk_grid *ltk_grid_create(ltk_window *window, const char *id,
int rows, int columns);
static void ltk_grid_destroy(ltk_grid *grid, int shallow);
static void ltk_recalculate_grid(ltk_grid *grid);
+static void ltk_grid_child_size_change(ltk_grid *grid, ltk_widget *widget);
static int ltk_grid_add(ltk_window *window, ltk_widget *widget, ltk_grid *grid,
int row, int column, int row_span, int column_span, unsigned short sticky, char **errstr);
static int ltk_grid_ungrid(ltk_window *window, ltk_widget *widget, ltk_grid *grid, char **errstr);
@@ -113,6 +118,7 @@ ltk_grid_create(ltk_window *window, const char *id, int rows, int columns) {
grid->widget.mouse_release = <k_grid_mouse_release;
grid->widget.motion_notify = <k_grid_motion_notify;
grid->widget.resize = <k_recalculate_grid;
+ grid->widget.child_size_change = <k_grid_child_size_change;
grid->widget.remove_child = <k_grid_ungrid;
grid->rows = rows;
@@ -239,7 +245,7 @@ ltk_recalculate_grid(ltk_grid *grid) {
}
if (orig_width != ptr->rect.w || orig_height != ptr->rect.h) {
if (ptr->resize) {
- ptr->resize(ptr, orig_width, orig_height);
+ ptr->resize(ptr);
}
}
@@ -262,6 +268,30 @@ ltk_recalculate_grid(ltk_grid *grid) {
}
}
+/* FIXME: Maybe add debug stuff to check that grid is actually parent of widget */
+static void
+ltk_grid_child_size_change(ltk_grid *grid, ltk_widget *widget) {
+ short size_changed = 0;
+ widget->rect.w = widget->ideal_w;
+ widget->rect.h = widget->ideal_h;
+ if (grid->column_weights[widget->column] == 0 &&
+ widget->rect.w > grid->column_widths[widget->column]) {
+ grid->widget.ideal_w += widget->rect.w - grid->column_widths[widget->column];
+ grid->column_widths[widget->column] = widget->rect.w;
+ size_changed = 1;
+ }
+ if (grid->row_weights[widget->row] == 0 &&
+ widget->rect.h > grid->row_heights[widget->row]) {
+ grid->widget.ideal_h += widget->rect.h - grid->row_heights[widget->row];
+ grid->row_heights[widget->row] = widget->rect.h;
+ size_changed = 1;
+ }
+ if (size_changed && grid->widget.parent && grid->widget.parent->child_size_change)
+ grid->widget.parent->child_size_change(grid->widget.parent, grid);
+ else
+ ltk_recalculate_grid(grid);
+}
+
/* FIXME: Check if widget already exists at position */
static int
ltk_grid_add(ltk_window *window, ltk_widget *widget, ltk_grid *grid,
@@ -275,19 +305,13 @@ ltk_grid_add(ltk_window *window, ltk_widget *widget, ltk_grid *grid,
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]) {
- grid->column_widths[column] = widget->rect.w;
- }
- if (grid->row_weights[row] == 0 && widget->rect.h > grid->row_heights[row]) {
- grid->row_heights[row] = widget->rect.h;
- }
for (int i = row; i < row + row_span; i++) {
for (int j = column; j < column + column_span; j++) {
grid->widget_grid[i * grid->columns + j] = widget;
}
}
widget->parent = grid;
- ltk_recalculate_grid(grid);
+ ltk_grid_child_size_change(grid, widget);
ltk_window_invalidate_rect(window, grid->widget.rect);
return 0;
@@ -374,7 +398,7 @@ ltk_grid_motion_notify(ltk_grid *grid, XEvent event) {
ltk_widget_motion_notify_event(ptr, event);
}
-/* grid <grid id> add <widget id> <row> <column> <row_span> <column_span> <sticky> */
+/* grid <grid id> add <widget id> <row> <column> <row_span> <column_span> [sticky] */
static int
ltk_grid_cmd_add(
ltk_window *window,
@@ -387,7 +411,7 @@ ltk_grid_cmd_add(
const char *errstr_num;
int row, column, row_span, column_span, sticky = 0;
- if (num_tokens != 9) {
+ if (num_tokens != 8 && num_tokens != 9) {
*errstr = "Invalid number of arguments.\n";
return 1;
}
@@ -418,18 +442,20 @@ ltk_grid_cmd_add(
return 1;
}
- for (c = tokens[8]; *c != '\0'; c++) {
- if (*c == 'n') {
- sticky |= LTK_STICKY_TOP;
- } else if (*c == 's') {
- sticky |= LTK_STICKY_BOTTOM;
- } else if (*c == 'e') {
- sticky |= LTK_STICKY_RIGHT;
- } else if (*c == 'w') {
- sticky |= LTK_STICKY_LEFT;
- } else if (*c != 'u') {
- *errstr = "Invalid sticky specification.\n";
- return 1;
+ if (num_tokens == 9) {
+ for (c = tokens[8]; *c != '\0'; c++) {
+ if (*c == 'n') {
+ sticky |= LTK_STICKY_TOP;
+ } else if (*c == 's') {
+ sticky |= LTK_STICKY_BOTTOM;
+ } else if (*c == 'e') {
+ sticky |= LTK_STICKY_RIGHT;
+ } else if (*c == 'w') {
+ sticky |= LTK_STICKY_LEFT;
+ } else {
+ *errstr = "Invalid sticky specification.\n";
+ return 1;
+ }
}
}
diff --git a/label.c b/label.c
@@ -92,8 +92,8 @@ ltk_label_create(ltk_window *window, const char *id, const char *text) {
label->tl = ltk_text_line_create(window->xwindow, font_size, text_copy, -1);
int text_w, text_h;
ltk_text_line_get_size(label->tl, &text_w, &text_h);
- label->widget.rect.w = text_w + theme.pad * 2;
- label->widget.rect.h = text_h + theme.pad * 2;
+ label->widget.ideal_w = text_w + theme.pad * 2;
+ label->widget.ideal_h = text_h + theme.pad * 2;
ltk_text_line_render(label->tl, &window->theme.bg, &theme.text_color);
return label;
diff --git a/ltk.h b/ltk.h
@@ -70,12 +70,15 @@ typedef enum {
typedef struct ltk_window ltk_window;
typedef struct ltk_widget {
- ltk_rect rect;
ltk_window *window;
struct ltk_widget *active_widget;
struct ltk_widget *parent;
char *id;
+ ltk_rect rect;
+ unsigned int ideal_w;
+ unsigned int ideal_h;
+
void (*key_press) (void *, XEvent);
void (*key_release) (void *, XEvent);
void (*mouse_press) (void *, XEvent);
@@ -84,11 +87,12 @@ typedef struct ltk_widget {
void (*mouse_leave) (void *, XEvent);
void (*mouse_enter) (void *, XEvent);
- void (*resize) (void *, int, int);
+ void (*resize) (void *);
void (*draw) (void *);
void (*change_state) (void *);
void (*destroy) (void *, int);
+ void (*child_size_change) (struct ltk_widget *, struct ltk_widget *);
int (*remove_child) (ltk_window *, void *, void *, char **);
ltk_widget_type type;
diff --git a/ltkd.c b/ltkd.c
@@ -397,12 +397,11 @@ ltk_set_root_widget_cmd(
widget = ltk_get_widget(tokens[1], LTK_WIDGET, errstr);
if (!widget) return 1;
window->root_widget = widget;
- int w = widget->rect.w;
- int h = widget->rect.h;
+ ltk_window_invalidate_rect(window, widget->rect);
widget->rect.w = window->rect.w;
widget->rect.h = window->rect.h;
if (widget->resize)
- widget->resize(widget, w, h);
+ widget->resize(widget);
return 0;
}
@@ -548,10 +547,11 @@ ltk_window_other_event(ltk_window *window, XEvent event) {
if (orig_w != w || orig_h != h) {
window->rect.w = w;
window->rect.h = h;
+ ltk_window_invalidate_rect(window, window->rect);
if (ptr && ptr->resize) {
ptr->rect.w = w;
ptr->rect.h = h;
- ptr->resize(ptr, orig_w, orig_h);
+ ptr->resize(ptr);
}
}
} else if (event.type == Expose && event.xexpose.count == 0) {
@@ -767,6 +767,7 @@ ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window *window,
widget->draw = draw;
widget->change_state = change_state;
widget->destroy = destroy;
+ widget->child_size_change = NULL;
widget->remove_child = NULL;
widget->needs_redraw = needs_redraw;
@@ -774,8 +775,10 @@ ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window *window,
widget->row = 0;
widget->rect.x = 0;
widget->rect.y = 0;
- widget->rect.w = 100;
- widget->rect.h = 100;
+ widget->rect.w = 0;
+ widget->rect.h = 0;
+ widget->ideal_w = 0;
+ widget->ideal_h = 0;
widget->row = 0;
widget->column = 0;
diff --git a/testbox.gui b/testbox.gui
@@ -2,5 +2,7 @@ box box1 create vertical
set-root-widget box1
button btn1 create "I'm a button!"
button btn2 create "I'm also a button!"
+button btn3 create "I'm another boring button."
box box1 add btn1 ew
box box1 add btn2 e
+box box1 add btn3