commit 657c2bb9354fc1f5d1e224c5db412ce0c4da447f
parent 997414b6693f3a4bc08c43347baa4e829d8e6cca
Author: lumidify <nobody@lumidify.org>
Date: Sat, 27 Feb 2021 21:26:15 +0100
Add graphics helper functions
These aren't used everywhere yet, and everything is still a bit buggy,
but that will hopefully change eventually.
Diffstat:
15 files changed, 219 insertions(+), 99 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,5 +1,2 @@
-ltkd
-ltkc
-ltk.sock
*.o
*.core
diff --git a/LICENSE b/LICENSE
@@ -1,4 +1,5 @@
-See khash.h, ini.*, stb_truetype.*, and strtonum.c for third-party licenses.
+See src/khash.h, src/ini.*, src/stb_truetype.*, and src/strtonum.c
+for third-party licenses.
ISC License
diff --git a/Makefile b/Makefile
@@ -47,6 +47,7 @@ OBJ = \
src/button.o \
src/label.o \
src/draw.o \
+ src/graphics.o \
$(EXTRA_OBJ)
# Note: This could be improved so a change in a header only causes the .c files
@@ -68,7 +69,8 @@ HDR = \
src/scrollbar.h \
src/stb_truetype.h \
src/text.h \
- src/util.h
+ src/util.h \
+ src/graphics.h
CFLAGS += $(EXTRA_CFLAGS)
LDFLAGS += $(EXTRA_LDFLAGS)
diff --git a/src/.gitignore b/src/.gitignore
@@ -0,0 +1,4 @@
+ltkd
+ltkc
+*.o
+*.core
diff --git a/src/box.c b/src/box.c
@@ -55,7 +55,10 @@ static struct ltk_widget_vtable vtable = {
.remove_child = <k_box_remove,
.mouse_press = <k_box_mouse_press,
.mouse_release = <k_box_mouse_release,
- .motion_notify = <k_box_motion_notify
+ .motion_notify = <k_box_motion_notify,
+ .needs_redraw = 0,
+ .needs_pixmap = 0,
+ .type = LTK_BOX
};
static int ltk_box_cmd_add(
@@ -99,7 +102,7 @@ static ltk_box *
ltk_box_create(ltk_window *window, const char *id, ltk_orientation orient) {
ltk_box *box = ltk_malloc(sizeof(ltk_box));
- ltk_fill_widget_defaults(&box->widget, id, window, &vtable, 0, LTK_BOX);
+ ltk_fill_widget_defaults(&box->widget, id, window, &vtable, 0, 0);
box->sc = ltk_scrollbar_create(window, orient, <k_box_scroll, box);
box->widgets = NULL;
@@ -150,8 +153,7 @@ ltk_recalculate_box(ltk_widget *self) {
ptr->rect.y = box->widget.rect.y + box->widget.rect.h - ptr->rect.h - sc_rect->h;
else
ptr->rect.y = box->widget.rect.y + (box->widget.rect.h - ptr->rect.h) / 2;
- if (ptr->vtable->resize)
- ptr->vtable->resize(ptr);
+ ltk_widget_resize(ptr);
cur_pos += ptr->rect.w;
} else {
ptr->rect.y = cur_pos - box->sc->cur_pos;
@@ -163,8 +165,7 @@ ltk_recalculate_box(ltk_widget *self) {
ptr->rect.x = box->widget.rect.x + box->widget.rect.w - ptr->rect.w - sc_rect->w;
else
ptr->rect.x = box->widget.rect.x + (box->widget.rect.w - ptr->rect.w) / 2;
- if (ptr->vtable->resize)
- ptr->vtable->resize(ptr);
+ ltk_widget_resize(ptr);
cur_pos += ptr->rect.h;
}
}
@@ -278,16 +279,16 @@ ltk_box_remove(ltk_window *window, ltk_widget *widget, ltk_widget *self, char **
if (box->widgets[j]->ideal_h + sc_h > box->widget.ideal_h)
box->widget.ideal_h = box->widgets[j]->ideal_h + sc_h;
}
- if (box->widget.parent && box->widget.parent->vtable->resize)
- box->widget.parent->vtable->resize(box->widget.parent);
+ if (box->widget.parent)
+ ltk_widget_resize(box->widget.parent);
} else if (box->orient == LTK_VERTICAL && widget->ideal_w + sc_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 + sc_w > box->widget.ideal_w)
box->widget.ideal_w = box->widgets[j]->ideal_w + sc_w;
}
- if (box->widget.parent && box->widget.parent->vtable->resize)
- box->widget.parent->vtable->resize(box->widget.parent);
+ if (box->widget.parent)
+ ltk_widget_resize(box->widget.parent);
}
return 0;
}
diff --git a/src/button.c b/src/button.c
@@ -31,6 +31,7 @@
#include "util.h"
#include "text.h"
#include "button.h"
+#include "graphics.h"
static void ltk_button_draw(ltk_widget *self, ltk_rect clip);
static int ltk_button_mouse_release(ltk_widget *self, XEvent event);
@@ -38,14 +39,16 @@ static ltk_button *ltk_button_create(ltk_window *window,
const char *id, const char *text);
static void ltk_button_destroy(ltk_widget *self, int shallow);
static void ltk_button_change_state(ltk_widget *self);
-static void ltk_button_resize(ltk_widget *self);
+static void ltk_button_redraw_pixmap(ltk_button *button);
static struct ltk_widget_vtable vtable = {
.mouse_release = <k_button_mouse_release,
.change_state = <k_button_change_state,
.draw = <k_button_draw,
.destroy = <k_button_destroy,
- .resize = <k_button_resize
+ .type = LTK_BUTTON,
+ .needs_redraw = 1,
+ .needs_pixmap = 1
};
static struct {
@@ -136,12 +139,12 @@ ltk_button_draw(ltk_widget *self, ltk_rect clip) {
ltk_window *window = button->widget.window;
ltk_rect rect = button->widget.rect;
ltk_rect clip_final = ltk_rect_intersect(clip, rect);
+ if (self->dirty)
+ ltk_button_redraw_pixmap(button);
/* no idea why it would be less than 0, but whatever */
if (clip_final.w <= 0 || clip_final.h <= 0)
return;
- XCopyArea(window->dpy, button->pixmap, window->xwindow, window->gc,
- clip_final.x - rect.x, clip_final.y - rect.y,
- clip_final.w, clip_final.h, clip_final.x, clip_final.y);
+ ltk_copy_clipped(self, clip_final);
}
static void
@@ -171,15 +174,10 @@ ltk_button_redraw_pixmap(ltk_button *button) {
default:
ltk_fatal("No style found for button!\n");
}
- XSetForeground(window->dpy, window->gc, fill->xcolor.pixel);
- XFillRectangle(window->dpy, button->pixmap, window->gc, 0, 0, rect.w, rect.h);
- /* FIXME: Why did I do this? */
- if (bw < 1) return;
- XSetForeground(window->dpy, window->gc, border->xcolor.pixel);
- XSetLineAttributes(window->dpy, window->gc, bw, LineSolid,
- CapButt, JoinMiter);
- XDrawRectangle(window->dpy, button->pixmap, window->gc,
- bw / 2, bw / 2, rect.w - bw, rect.h - bw);
+ rect.x = 0;
+ rect.y = 0;
+ ltk_fill_widget_rect(&button->widget, fill, rect);
+ ltk_draw_widget_rect(&button->widget, border, rect, bw);
int text_w, text_h;
ltk_text_line_get_size(button->tl, &text_w, &text_h);
@@ -187,29 +185,8 @@ ltk_button_redraw_pixmap(ltk_button *button) {
int text_y = (rect.h - text_h) / 2;
/* FIXME: Remove clipping rect from text line - this is just used here as a dummy
because it is completely ignored */
- ltk_text_line_draw(button->tl, button->pixmap, window->gc, text_x, text_y, rect);
-}
-
-/* FIXME: Make this amortised constant; make it generic for all widgets */
-static void
-ltk_button_resize(ltk_widget *self) {
- ltk_button *button = (ltk_button *)self;
- Window win;
- int x, y;
- unsigned int w, h, bw, d;
- unsigned int new_w, new_h;
- ltk_window *window = button->widget.window;
- ltk_rect rect = button->widget.rect;
- XGetGeometry(window->dpy, button->pixmap, &win, &x, &y, &w, &h, &bw, &d);
-
- new_w = (int)w < rect.w ? rect.w : (int)w;
- new_h = (int)h < rect.h ? rect.h : (int)h;
- if (new_w < w && new_h < h)
- return;
- XFreePixmap(window->dpy, button->pixmap);
- button->pixmap = XCreatePixmap(window->dpy, window->xwindow,
- new_w, new_h, window->depth);
- ltk_button_redraw_pixmap(button);
+ ltk_text_line_draw(button->tl, button->widget.pixmap, window->gc, text_x, text_y, rect);
+ button->widget.dirty = 0;
}
static void
@@ -233,7 +210,7 @@ ltk_button_change_state(ltk_widget *self) {
ltk_fatal("No style found for button!\n");
}
ltk_text_line_render(button->tl, fill, &theme.text_color);
- ltk_button_redraw_pixmap(button);
+ self->dirty = 1;
}
static int
@@ -249,7 +226,6 @@ ltk_button_create(ltk_window *window, const char *id, const char *text) {
char *text_copy;
ltk_button *button = ltk_malloc(sizeof(ltk_button));
- ltk_fill_widget_defaults(&button->widget, id, window, &vtable, 1, LTK_BUTTON);
uint16_t font_size = window->theme.font_size;
text_copy = ltk_strdup(text);
button->tl = ltk_text_line_create(window->xwindow, font_size, text_copy, -1);
@@ -257,8 +233,7 @@ ltk_button_create(ltk_window *window, const char *id, const char *text) {
ltk_text_line_get_size(button->tl, &text_w, &text_h);
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;
- button->pixmap = XCreatePixmap(window->dpy, window->xwindow,
- button->widget.ideal_w, button->widget.ideal_h, window->depth);
+ ltk_fill_widget_defaults(&button->widget, id, window, &vtable, button->widget.ideal_w, button->widget.ideal_h);
/* render text */
ltk_button_change_state((ltk_widget *)button);
diff --git a/src/draw.c b/src/draw.c
@@ -45,6 +45,11 @@ static struct ltk_widget_vtable vtable = {
.draw = <k_draw_draw,
.resize = <k_draw_resize,
.destroy = <k_draw_destroy,
+ .type = LTK_DRAW,
+ .needs_redraw = 1,
+ /* FIXME: use the widget pixmap here and store the drawn stuff
+ logically as paths, not just on the pixmap */
+ .needs_pixmap = 0
};
static int ltk_draw_cmd_clear(
@@ -87,7 +92,7 @@ static ltk_draw *
ltk_draw_create(ltk_window *window, const char *id, int w, int h, const char *color) {
ltk_draw *draw = ltk_malloc(sizeof(ltk_draw));
- ltk_fill_widget_defaults(&draw->widget, id, window, &vtable, 1, LTK_DRAW);
+ ltk_fill_widget_defaults(&draw->widget, id, window, &vtable, w, h);
draw->widget.rect.w = w;
draw->widget.rect.h = h;
draw->pix = XCreatePixmap(window->dpy, window->xwindow, w, h, window->depth);
diff --git a/src/graphics.c b/src/graphics.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021 lumidify <nobody@lumidify.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include "color.h"
+#include "rect.h"
+#include "widget.h"
+#include "ltk.h"
+
+void
+ltk_fill_widget_rect(ltk_widget *widget, ltk_color *color, ltk_rect rect) {
+ ltk_window *win = widget->window;
+ XSetForeground(win->dpy, win->gc, color->xcolor.pixel);
+ XFillRectangle(win->dpy, widget->pixmap, win->gc, rect.x, rect.y, rect.w, rect.h);
+}
+
+void
+ltk_draw_widget_rect(ltk_widget *widget, ltk_color *color, ltk_rect rect, int border_width) {
+ ltk_window *win = widget->window;
+ if (border_width <= 0)
+ return;
+ XSetForeground(win->dpy, win->gc, color->xcolor.pixel);
+ XSetLineAttributes(win->dpy, win->gc, border_width, LineSolid, CapButt, JoinMiter);
+ XDrawRectangle(
+ win->dpy, widget->pixmap, win->gc,
+ border_width / 2, border_width / 2,
+ rect.w - border_width, rect.h - border_width
+ );
+}
+
+void
+ltk_copy_clipped(ltk_widget *widget, ltk_rect clip) {
+ ltk_window *win = widget->window;
+ ltk_rect clip_final = ltk_rect_intersect(clip, widget->rect);
+ if (clip_final.w <= 0 || clip_final.h <= 0)
+ return;
+ XCopyArea(
+ win->dpy, widget->pixmap, win->xwindow, win->gc,
+ clip_final.x - widget->rect.x, clip_final.y - widget->rect.y,
+ clip_final.w, clip_final.h, clip_final.x, clip_final.y
+ );
+}
diff --git a/src/graphics.h b/src/graphics.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2021 lumidify <nobody@lumidify.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LTK_GRAPHICS_H_
+#define _LTK_GRAPHICS_H_
+
+/* Requires: "color.h", "rect.h", "widget.h" */
+
+/* FIXME: Is it faster to take ltk_color* or ltk_color? */
+
+/* Fill `rect` with `color` on `widget`'s pixmap.
+ * `rect` is relative to `widget`'s rect. */
+void ltk_fill_widget_rect(ltk_widget *widget, ltk_color *color, ltk_rect rect);
+
+/* Draw `rect` with `color` and `border_width` on `widget`'s pixmap.
+ * `rect` is relative to `widget`'s rect. */
+void ltk_draw_widget_rect(ltk_widget *widget, ltk_color *color, ltk_rect rect, int border_width);
+
+/* Copy the part of `widget`'s pixmap covered by the intersection of `clip`
+ * and `widget`'s rect to the window `widget` is contained within.
+ * `clip` is absolute, i.e. relative to the coordinates of the window,
+ * not of `widget`. */
+void ltk_copy_clipped(ltk_widget *widget, ltk_rect clip);
+
+#endif /* _LTK_GRAPHICS_H_ */
diff --git a/src/grid.c b/src/grid.c
@@ -63,7 +63,10 @@ static struct ltk_widget_vtable vtable = {
.remove_child = <k_grid_ungrid,
.mouse_press = <k_grid_mouse_press,
.mouse_release = <k_grid_mouse_release,
- .motion_notify = <k_grid_motion_notify
+ .motion_notify = <k_grid_motion_notify,
+ .type = LTK_GRID,
+ .needs_redraw = 0,
+ .needs_pixmap = 0
};
static int ltk_grid_cmd_add(
@@ -120,7 +123,7 @@ static ltk_grid *
ltk_grid_create(ltk_window *window, const char *id, int rows, int columns) {
ltk_grid *grid = ltk_malloc(sizeof(ltk_grid));
- ltk_fill_widget_defaults(&grid->widget, id, window, &vtable, 0, LTK_GRID);
+ ltk_fill_widget_defaults(&grid->widget, id, window, &vtable, 0, 0);
grid->rows = rows;
grid->columns = columns;
@@ -246,11 +249,8 @@ ltk_recalculate_grid(ltk_widget *self) {
if (ptr->sticky & LTK_STICKY_TOP && ptr->sticky & LTK_STICKY_BOTTOM) {
ptr->rect.h = grid->row_pos[end_row] - grid->row_pos[i];
}
- if (orig_width != ptr->rect.w || orig_height != ptr->rect.h) {
- if (ptr->vtable->resize) {
- ptr->vtable->resize(ptr);
- }
- }
+ if (orig_width != ptr->rect.w || orig_height != ptr->rect.h)
+ ltk_widget_resize(ptr);
if (ptr->sticky & LTK_STICKY_RIGHT) {
ptr->rect.x = grid->column_pos[end_column] - ptr->rect.w;
diff --git a/src/label.c b/src/label.c
@@ -31,15 +31,20 @@
#include "util.h"
#include "text.h"
#include "label.h"
+#include "graphics.h"
static void ltk_label_draw(ltk_widget *self, ltk_rect clip);
static ltk_label *ltk_label_create(ltk_window *window,
const char *id, const char *text);
static void ltk_label_destroy(ltk_widget *self, int shallow);
+static void ltk_label_redraw_pixmap(ltk_label *label);
static struct ltk_widget_vtable vtable = {
.draw = <k_label_draw,
- .destroy = <k_label_destroy
+ .destroy = <k_label_destroy,
+ .type = LTK_LABEL,
+ .needs_redraw = 1,
+ .needs_pixmap = 1
};
static struct {
@@ -78,19 +83,26 @@ ltk_label_draw(ltk_widget *self, ltk_rect clip) {
ltk_window *window = label->widget.window;
ltk_rect rect = label->widget.rect;
ltk_rect clip_final = ltk_rect_intersect(clip, rect);
+ if (self->dirty)
+ ltk_label_redraw_pixmap(label);
/* no idea why it would be less than 0, but whatever */
if (clip_final.w <= 0 || clip_final.h <= 0)
return;
- XCopyArea(window->dpy, label->text_pixmap, window->xwindow, window->gc,
- clip_final.x - rect.x, clip_final.y - rect.y,
- clip_final.w, clip_final.h, clip_final.x, clip_final.y);
- /*
+ ltk_copy_clipped(self, clip_final);
+}
+
+static void
+ltk_label_redraw_pixmap(ltk_label *label) {
+ ltk_rect r = label->widget.rect;
+ r.x = 0;
+ r.y = 0;
+ ltk_fill_widget_rect(&label->widget, &theme.bg_color, r);
+
int text_w, text_h;
ltk_text_line_get_size(label->tl, &text_w, &text_h);
- int text_x = rect.x + (rect.w - text_w) / 2;
- int text_y = rect.y + (rect.h - text_h) / 2;
- ltk_text_line_draw(label->tl, window->gc, text_x, text_y, clip);
- */
+ int text_x = (r.w - text_w) / 2;
+ int text_y = (r.h - text_h) / 2;
+ ltk_text_line_draw(label->tl, label->widget.pixmap, label->widget.window->gc, text_x, text_y, r);
}
static ltk_label *
@@ -98,7 +110,6 @@ ltk_label_create(ltk_window *window, const char *id, const char *text) {
char *text_copy;
ltk_label *label = ltk_malloc(sizeof(ltk_label));
- ltk_fill_widget_defaults(&label->widget, id, window, &vtable, 1, LTK_LABEL);
uint16_t font_size = window->theme.font_size;
text_copy = ltk_strdup(text);
label->tl = ltk_text_line_create(window->xwindow, font_size, text_copy, -1);
@@ -107,11 +118,7 @@ ltk_label_create(ltk_window *window, const char *id, const char *text) {
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);
- label->text_pixmap = XCreatePixmap(window->dpy, window->xwindow,
- label->widget.ideal_w, label->widget.ideal_h, window->depth);
- XSetForeground(window->dpy, window->gc, theme.bg_color.xcolor.pixel);
- XFillRectangle(window->dpy, label->text_pixmap, window->gc, 0, 0, label->widget.ideal_w, label->widget.ideal_h);
- ltk_text_line_draw(label->tl, label->text_pixmap, window->gc, theme.pad, theme.pad, label->widget.rect);
+ ltk_fill_widget_defaults(&label->widget, id, window, &vtable, label->widget.ideal_w, label->widget.ideal_h);
return label;
}
diff --git a/src/ltkd.c b/src/ltkd.c
@@ -420,8 +420,7 @@ ltk_set_root_widget_cmd(
ltk_window_invalidate_rect(window, widget->rect);
widget->rect.w = window->rect.w;
widget->rect.h = window->rect.h;
- if (widget->vtable->resize)
- widget->vtable->resize(widget);
+ ltk_widget_resize(widget);
return 0;
}
@@ -494,10 +493,10 @@ ltk_window_other_event(ltk_window *window, XEvent event) {
window->rect.w = w;
window->rect.h = h;
ltk_window_invalidate_rect(window, window->rect);
- if (ptr && ptr->vtable->resize) {
+ if (ptr) {
ptr->rect.w = w;
ptr->rect.h = h;
- ptr->vtable->resize(ptr);
+ ltk_widget_resize(ptr);
}
}
} else if (event.type == Expose && event.xexpose.count == 0) {
diff --git a/src/scrollbar.c b/src/scrollbar.c
@@ -40,7 +40,10 @@ static struct ltk_widget_vtable vtable = {
.draw = <k_scrollbar_draw,
.mouse_press = <k_scrollbar_mouse_press,
.motion_notify = <k_scrollbar_motion_notify,
- .destroy = <k_scrollbar_destroy
+ .destroy = <k_scrollbar_destroy,
+ .type = LTK_UNKNOWN, /* FIXME */
+ .needs_redraw = 1,
+ .needs_pixmap = 1
};
static struct {
@@ -230,7 +233,7 @@ ltk_scrollbar_motion_notify(ltk_widget *self, XEvent event) {
ltk_scrollbar *
ltk_scrollbar_create(ltk_window *window, ltk_orientation orient, void (*callback)(ltk_widget *), void *data) {
ltk_scrollbar *sc = ltk_malloc(sizeof(ltk_scrollbar));
- ltk_fill_widget_defaults((ltk_widget *)sc, NULL, window, &vtable, 1, LTK_UNKNOWN);
+ ltk_fill_widget_defaults((ltk_widget *)sc, NULL, window, &vtable, 1, 1); /* FIXME: proper size */
sc->last_mouse_x = sc->last_mouse_y = 0;
/* This cannot be 0 because that leads to divide-by-zero */
sc->virtual_size = 1;
diff --git a/src/widget.c b/src/widget.c
@@ -59,41 +59,66 @@ ltk_widgets_cleanup() {
void
ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window *window,
- struct ltk_widget_vtable *vtable, unsigned int needs_redraw, ltk_widget_type type) {
+ struct ltk_widget_vtable *vtable, int w, int h) {
if (id)
widget->id = ltk_strdup(id);
else
widget->id = NULL;
widget->window = window;
- widget->active_widget = NULL;
widget->parent = NULL;
- widget->type = type;
+
+ widget->pix_w = w;
+ widget->pix_h = h;
+ if (vtable->needs_pixmap)
+ widget->pixmap = XCreatePixmap(window->dpy, window->xwindow, w, h, window->depth);
/* FIXME: possibly check that draw and destroy aren't NULL */
widget->vtable = vtable;
- widget->needs_redraw = needs_redraw;
widget->state = LTK_NORMAL;
widget->row = 0;
widget->rect.x = 0;
widget->rect.y = 0;
- widget->rect.w = 0;
- widget->rect.h = 0;
- widget->ideal_w = 0;
- widget->ideal_h = 0;
+ widget->rect.w = w;
+ widget->rect.h = h;
widget->row = 0;
widget->column = 0;
widget->row_span = 0;
widget->column_span = 0;
widget->sticky = 0;
+ widget->dirty = 1;
+}
+
+/* FIXME: Make this properly amortised constant */
+/* FIXME: Maybe pass the new width as arg here?
+ That would make a bit more sense */
+void
+ltk_widget_resize(ltk_widget *widget) {
+ if (widget->vtable->resize)
+ widget->vtable->resize(widget);
+ if (!widget->vtable->needs_pixmap)
+ return;
+ int new_w, new_h;
+ ltk_window *w = widget->window;
+ ltk_rect r = widget->rect;
+ int pw = widget->pix_w;
+ int ph = widget->pix_h;
+
+ new_w = pw < r.w ? r.w : pw;
+ new_h = ph < r.h ? r.h : ph;
+ if (new_w == pw && new_h == ph)
+ return;
+ XFreePixmap(w->dpy, widget->pixmap);
+ widget->pixmap = XCreatePixmap(w->dpy, w->xwindow, new_w, new_h, w->depth);
+ widget->dirty = 1;
}
void
ltk_widget_change_state(ltk_widget *widget) {
if (widget->vtable->change_state)
widget->vtable->change_state(widget);
- if (widget->needs_redraw)
+ if (widget->vtable->needs_redraw)
ltk_window_invalidate_rect(widget->window, widget->rect);
}
@@ -170,7 +195,7 @@ ltk_get_widget(const char *id, ltk_widget_type type, char **errstr) {
return NULL;
}
widget = kh_value(widget_hash, k);
- if (type != LTK_WIDGET && widget->type != type) {
+ if (type != LTK_WIDGET && widget->vtable->type != type) {
*errstr = "Widget with given ID has wrong type.\n";
return NULL;
}
diff --git a/src/widget.h b/src/widget.h
@@ -55,24 +55,25 @@ struct ltk_widget_vtable;
typedef struct ltk_widget {
struct ltk_window *window;
- struct ltk_widget *active_widget;
struct ltk_widget *parent;
char *id;
struct ltk_widget_vtable *vtable;
+ Pixmap pixmap;
+ int pix_w;
+ int pix_h;
ltk_rect rect;
unsigned int ideal_w;
unsigned int ideal_h;
- ltk_widget_type type;
ltk_widget_state state;
unsigned int sticky;
unsigned short row;
unsigned short column;
unsigned short row_span;
unsigned short column_span;
- unsigned char needs_redraw;
+ char dirty;
} ltk_widget;
struct ltk_widget_vtable {
@@ -92,11 +93,15 @@ struct ltk_widget_vtable {
void (*child_size_change) (struct ltk_widget *, struct ltk_widget *);
int (*remove_child) (struct ltk_window *, struct ltk_widget *, struct ltk_widget *, char **);
+
+ ltk_widget_type type;
+ char needs_redraw;
+ char needs_pixmap;
};
int ltk_widget_destroy(struct ltk_window *window, char **tokens, size_t num_tokens, char **errstr);
void ltk_fill_widget_defaults(ltk_widget *widget, const char *id, struct ltk_window *window,
- struct ltk_widget_vtable *vtable, unsigned int needs_redraw, ltk_widget_type type);
+ struct ltk_widget_vtable *vtable, int w, int h);
void ltk_widget_change_state(ltk_widget *widget);
void ltk_widget_mouse_press_event(ltk_widget *widget, XEvent event);
void ltk_widget_mouse_release_event(ltk_widget *widget, XEvent event);
@@ -107,5 +112,6 @@ void ltk_set_widget(ltk_widget *widget, const char *id);
void ltk_remove_widget(const char *id);
void ltk_widgets_cleanup();
void ltk_widgets_init();
+void ltk_widget_resize(ltk_widget *widget);
#endif /* _LTK_WIDGET_H_ */