commit b0338320849b8d570511491a73dee2d75aff5fd9
parent d0099e84bdff7d265d14fc3ae226b0881ba98ed6
Author: lumidify <nobody@lumidify.org>
Date: Sun, 17 Jan 2021 21:25:32 +0100
Add very broken scrollbar support to box
Diffstat:
13 files changed, 156 insertions(+), 87 deletions(-)
diff --git a/.ltk/theme.ini b/.ltk/theme.ini
@@ -23,7 +23,7 @@ text_color = #FFFFFF
pad = 5
[scrollbar]
-size = 5
+size = 15
bg = #000000
bg_disabled = #555555
fg = #113355
diff --git a/box.c b/box.c
@@ -34,7 +34,7 @@
#include "scrollbar.h"
#include "box.h"
-static void ltk_box_draw(ltk_box *box);
+static void ltk_box_draw(ltk_box *box, ltk_rect clip);
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);
@@ -72,12 +72,16 @@ static int ltk_box_cmd_create(
char **errstr);
static void
-ltk_box_draw(ltk_box *box) {
+ltk_box_draw(ltk_box *box, ltk_rect clip) {
ltk_widget *ptr;
+ ltk_rect real_clip = ltk_rect_intersect(box->widget.rect, clip);
for (size_t i = 0; i < box->num_widgets; i++) {
ptr = box->widgets[i];
- ptr->draw(ptr);
+ /* FIXME: Maybe continue immediately if widget is
+ obviously outside of clipping rect */
+ ptr->draw(ptr, real_clip);
}
+ box->sc->widget.draw(box->sc, real_clip);
}
static ltk_box *
@@ -95,7 +99,7 @@ ltk_box_create(ltk_window *window, const char *id, ltk_orientation orient) {
box->widget.child_size_change = <k_box_child_size_change;
box->widget.remove_child = <k_box_remove;
- box->sc = NULL;
+ box->sc = ltk_scrollbar_create(window, orient);
box->widgets = NULL;
box->num_alloc = 0;
box->num_widgets = 0;
@@ -116,38 +120,42 @@ ltk_box_destroy(ltk_box *box, int shallow) {
free(box->widgets);
ltk_remove_widget(box->widget.window, box->widget.id);
free(box->widget.id);
+ box->sc->widget.destroy(box->sc, 0);
free(box);
}
-/* FIXME: Need some sort of "visible rect" so widgets don't draw outside */
/* FIXME: Make this function name more consistent */
+/* FIXME: The widget positions are set with the old scrollbar->cur_pos, before the
+ virtual_size is set - this can cause problems when a widget changes its size
+ (in the scrolled direction) when resized. */
static void
ltk_recalculate_box(ltk_box *box) {
ltk_widget *ptr;
+ ltk_rect *sc_rect = &box->sc->widget.rect;
int cur_pos = 0;
for (size_t i = 0; i < box->num_widgets; i++) {
ptr = box->widgets[i];
if (box->orient == LTK_HORIZONTAL) {
- ptr->rect.x = cur_pos;
+ ptr->rect.x = cur_pos - box->sc->cur_pos;
if (ptr->sticky & LTK_STICKY_TOP && ptr->sticky & LTK_STICKY_BOTTOM)
- ptr->rect.h = box->widget.rect.h;
+ ptr->rect.h = box->widget.rect.h - sc_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;
+ 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->resize)
ptr->resize(ptr);
cur_pos += ptr->rect.w;
} else {
- ptr->rect.y = cur_pos;
+ ptr->rect.y = cur_pos - box->sc->cur_pos;
if (ptr->sticky & LTK_STICKY_LEFT && ptr->sticky & LTK_STICKY_RIGHT)
- ptr->rect.w = box->widget.rect.w;
+ ptr->rect.w = box->widget.rect.w - sc_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;
+ 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->resize)
@@ -155,6 +163,14 @@ ltk_recalculate_box(ltk_box *box) {
cur_pos += ptr->rect.h;
}
}
+ ltk_scrollbar_set_virtual_size(box->sc, cur_pos);
+ if (box->orient == LTK_HORIZONTAL) {
+ sc_rect->y = box->widget.rect.y + box->widget.rect.h - sc_rect->h;
+ sc_rect->w = box->widget.rect.w;
+ } else {
+ sc_rect->x = box->widget.rect.x + box->widget.rect.w - sc_rect->w;
+ sc_rect->h = box->widget.rect.h;
+ }
}
/* FIXME: This entire resizing thing is a bit weird. For instance, if a label
@@ -179,11 +195,13 @@ ltk_box_child_size_change(ltk_box *box, ltk_widget *widget) {
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;
+ int sc_w = box->sc->widget.rect.w;
+ int sc_h = box->sc->widget.rect.h;
+ if (box->orient == LTK_HORIZONTAL && widget->ideal_h + sc_h > box->widget.ideal_h) {
+ box->widget.ideal_h = widget->ideal_h + sc_h;
size_changed = 1;
- } else if (box->orient == LTK_VERTICAL && widget->ideal_w > box->widget.ideal_h) {
- box->widget.ideal_w = widget->ideal_w;
+ } else if (box->orient == LTK_VERTICAL && widget->ideal_w + sc_w > box->widget.ideal_h) {
+ box->widget.ideal_w = widget->ideal_w + sc_w;
size_changed = 1;
}
@@ -208,11 +226,19 @@ ltk_box_add(ltk_window *window, ltk_widget *widget, ltk_box *box, unsigned short
box->widgets = new;
}
+ int sc_w = box->sc->widget.rect.w;
+ int sc_h = box->sc->widget.rect.h;
+
box->widgets[box->num_widgets++] = widget;
- if (box->orient == LTK_HORIZONTAL)
+ if (box->orient == LTK_HORIZONTAL) {
box->widget.ideal_w += widget->ideal_w;
- else
+ if (widget->ideal_h + sc_h > box->widget.ideal_h)
+ box->widget.ideal_h = widget->ideal_h + sc_h;
+ } else {
box->widget.ideal_h += widget->ideal_h;
+ if (widget->ideal_w + sc_w > box->widget.ideal_w)
+ box->widget.ideal_w = widget->ideal_w + sc_w;
+ }
widget->parent = box;
widget->sticky = sticky;
ltk_box_child_size_change(box, widget);
@@ -223,6 +249,8 @@ ltk_box_add(ltk_window *window, ltk_widget *widget, ltk_box *box, unsigned short
static int
ltk_box_remove(ltk_window *window, ltk_widget *widget, ltk_box *box, char **errstr) {
+ int sc_w = box->sc->widget.rect.w;
+ int sc_h = box->sc->widget.rect.h;
if (widget->parent != box) {
*errstr = "Widget isn't contained in given box.\n";
return 1;
@@ -237,19 +265,19 @@ ltk_box_remove(ltk_window *window, ltk_widget *widget, ltk_box *box, char **errs
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) {
+ if (box->orient == LTK_HORIZONTAL && widget->ideal_h + sc_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->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->resize)
box->widget.parent->resize(box->widget.parent);
- } else if (box->orient == LTK_VERTICAL && widget->ideal_w == box->widget.ideal_w) {
+ } 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 > box->widget.ideal_w)
- box->widget.ideal_w = box->widgets[j]->ideal_w;
+ 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->resize)
box->widget.parent->resize(box->widget.parent);
@@ -266,11 +294,16 @@ static void
ltk_box_mouse_event(ltk_box *box, XEvent event, void (*handler)(ltk_widget *, XEvent)) {
int pos, start, size;
ltk_widget *widget;
+ int old_sc_pos = box->sc->cur_pos;
- /*
- if (ltk_collide_rect(box->sc.widget.rect, event.xbutton.x, event.xbutton.y))
+ if (ltk_collide_rect(box->sc->widget.rect, event.xbutton.x, event.xbutton.y)) {
handler(box->sc, event);
- */
+ if (old_sc_pos != box->sc->cur_pos) {
+ ltk_recalculate_box(box);
+ ltk_window_invalidate_rect(box->widget.window, box->widget.rect);
+ }
+ return;
+ }
/* FIXME: When scrolling is implemented, check only the currently visible items */
for (size_t i = 0; i < box->num_widgets; i++) {
@@ -297,9 +330,6 @@ ltk_box_mouse_release(ltk_box *box, XEvent event) {
even if not actually hovered over! */
static void
ltk_box_motion_notify(ltk_box *box, XEvent event) {
- short pressed = (event.xmotion.state & Button1Mask) == Button1Mask;
- if (pressed)
- return;
ltk_box_mouse_event(box, event, <k_widget_motion_notify_event);
}
diff --git a/button.c b/button.c
@@ -36,7 +36,7 @@
#include "text.h"
#include "button.h"
-static void ltk_button_draw(ltk_button *button);
+static void ltk_button_draw(ltk_button *button, ltk_rect clip);
static void ltk_button_mouse_release(ltk_button *button, XEvent event);
static ltk_button *ltk_button_create(ltk_window *window,
const char *id, const char *text);
@@ -125,7 +125,7 @@ ltk_button_ini_handler(ltk_window *window, const char *prop, const char *value)
}
static void
-ltk_button_draw(ltk_button *button) {
+ltk_button_draw(ltk_button *button, ltk_rect clip) {
ltk_window *window = button->widget.window;
ltk_rect rect = button->widget.rect;
int bw = theme.border_width;
@@ -166,7 +166,7 @@ ltk_button_draw(ltk_button *button) {
ltk_text_line_get_size(button->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(button->tl, window->gc, text_x, text_y);
+ ltk_text_line_draw(button->tl, window->gc, text_x, text_y, clip);
}
static void
diff --git a/grid.c b/grid.c
@@ -42,7 +42,7 @@
static void ltk_grid_set_row_weight(ltk_grid *grid, int row, int weight);
static void ltk_grid_set_column_weight(ltk_grid *grid, int column, int weight);
-static void ltk_grid_draw(ltk_grid *grid);
+static void ltk_grid_draw(ltk_grid *grid, ltk_rect clip);
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);
@@ -96,13 +96,13 @@ ltk_grid_set_column_weight(ltk_grid *grid, int column, int weight) {
}
static void
-ltk_grid_draw(ltk_grid *grid) {
+ltk_grid_draw(ltk_grid *grid, ltk_rect clip) {
int i;
for (i = 0; i < grid->rows * grid->columns; i++) {
if (!grid->widget_grid[i])
continue;
ltk_widget *ptr = grid->widget_grid[i];
- ptr->draw(ptr);
+ ptr->draw(ptr, clip);
}
}
diff --git a/label.c b/label.c
@@ -36,7 +36,7 @@
#include "text.h"
#include "label.h"
-static void ltk_label_draw(ltk_label *label);
+static void ltk_label_draw(ltk_label *label, ltk_rect clip);
static ltk_label *ltk_label_create(ltk_window *window,
const char *id, const char *text);
static void ltk_label_destroy(ltk_label *label, int shallow);
@@ -66,7 +66,7 @@ ltk_label_ini_handler(ltk_window *window, const char *prop, const char *value) {
}
static void
-ltk_label_draw(ltk_label *label) {
+ltk_label_draw(ltk_label *label, ltk_rect clip) {
ltk_window *window = label->widget.window;
ltk_rect rect = label->widget.rect;
@@ -74,7 +74,7 @@ ltk_label_draw(ltk_label *label) {
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);
+ ltk_text_line_draw(label->tl, window->gc, text_x, text_y, clip);
}
static ltk_label *
diff --git a/ltk.h b/ltk.h
@@ -59,6 +59,8 @@ typedef enum {
} ltk_widget_state;
typedef enum {
+ /* for e.g. scrollbar, which can't be directly accessed by users */
+ LTK_UNKNOWN,
LTK_GRID,
LTK_BUTTON,
LTK_DRAW,
@@ -88,7 +90,7 @@ typedef struct ltk_widget {
void (*mouse_enter) (void *, XEvent);
void (*resize) (void *);
- void (*draw) (void *);
+ void (*draw) (void *, ltk_rect);
void (*change_state) (void *);
void (*destroy) (void *, int);
@@ -147,6 +149,8 @@ typedef struct ltk_window {
struct ltk_event_queue *last_event;
} ltk_window;
+ltk_rect ltk_rect_intersect(ltk_rect r1, ltk_rect r2);
+ltk_rect ltk_rect_union(ltk_rect r1, ltk_rect r2);
void ltk_window_invalidate_rect(ltk_window *window, ltk_rect rect);
void ltk_warn(const char *format, ...);
void ltk_fatal(const char *format, ...);
diff --git a/ltkd.c b/ltkd.c
@@ -1,3 +1,4 @@
+/* FIXME: PROPERLY CLEANUP ALL THEMES */
/* FIXME: error checking in tokenizer (is this necessary?) */
/* FIXME: parsing doesn't work properly with bs? */
/* FIXME: strip whitespace at end of lines in socket format */
@@ -101,7 +102,6 @@ static void ltk_redraw_window(ltk_window *window);
static void ltk_window_other_event(ltk_window *window, XEvent event);
static void ltk_handle_event(ltk_window *window, XEvent event);
static void ltk_load_theme(ltk_window *window, const char *path);
-static ltk_rect ltk_rect_union(ltk_rect r1, ltk_rect r2);
static int read_sock(struct ltk_sock_info *sock);
static int push_token(struct token_list *tl, char *token);
static int read_sock(struct ltk_sock_info *sock);
@@ -110,7 +110,6 @@ static int queue_sock_write(struct ltk_sock_info *sock, const char *str, int len
static int tokenize_command(struct ltk_sock_info *sock);
static int ltk_set_root_widget_cmd(ltk_window *window, char **tokens, int num_tokens, char **errstr);
static void process_commands(ltk_window *window, struct ltk_sock_info *sock);
-static ltk_rect ltk_rect_union(ltk_rect r1, ltk_rect r2);
static int add_client(int fd);
static int listen_sock(const char *sock_path);
static int accept_sock(int listenfd);
@@ -406,15 +405,26 @@ ltk_set_root_widget_cmd(
return 0;
}
-static ltk_rect
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+ltk_rect
+ltk_rect_intersect(ltk_rect r1, ltk_rect r2) {
+ ltk_rect i;
+ i.x = MAX(r1.x, r2.x);
+ i.y = MAX(r1.y, r2.y);
+ i.w = MIN(r1.x + r1.w, r2.x + r2.w) - i.x;
+ i.h = MIN(r1.y + r1.h, r2.y + r2.h) - i.y;
+ return i;
+}
+
+ltk_rect
ltk_rect_union(ltk_rect r1, ltk_rect r2) {
ltk_rect u;
- u.x = r1.x < r2.x ? r1.x : r2.x;
- u.y = r1.y < r2.y ? r1.y : r2.y;
- int x2 = r1.x + r1.w < r2.x + r2.w ? r2.x + r2.w : r1.x + r1.w;
- int y2 = r1.y + r1.h < r2.y + r2.h ? r2.y + r2.h : r1.y + r1.h;
- u.w = x2 - u.x;
- u.h = y2 - u.y;
+ u.x = MIN(r1.x, r2.x);
+ u.y = MIN(r1.y, r2.y);
+ u.w = MAX(r1.x + r1.w, r2.x + r2.w) - u.x;
+ u.h = MAX(r1.y + r1.h, r2.y + r2.h) - u.y;
return u;
}
@@ -530,9 +540,9 @@ ltk_redraw_window(ltk_window *window) {
window->dirty_rect.h -= window->dirty_rect.y + window->dirty_rect.h - window->rect.h;
XClearArea(window->dpy, window->xwindow, window->dirty_rect.x, window->dirty_rect.y, window->dirty_rect.w, window->dirty_rect.h, False);
if (!window->root_widget) return;
- /* FIXME: actually respect the dirty rect... */
ptr = window->root_widget;
- ptr->draw(ptr);
+ if (ptr)
+ ptr->draw(ptr, window->dirty_rect);
}
static void
@@ -675,6 +685,8 @@ ltk_ini_handler(void *window, const char *widget, const char *prop, const char *
ltk_button_ini_handler(window, prop, value);
} else if (strcmp(widget, "label") == 0) {
ltk_label_ini_handler(window, prop, value);
+ } else if (strcmp(widget, "scrollbar") == 0) {
+ ltk_scrollbar_ini_handler(window, prop, value);
} else {
return 0;
}
@@ -698,6 +710,7 @@ ltk_load_theme(ltk_window *window, const char *path) {
ltk_window_setup_theme_defaults(window);
ltk_button_setup_theme_defaults(window);
ltk_label_setup_theme_defaults(window);
+ ltk_scrollbar_setup_theme_defaults(window);
if (ini_parse(path, ltk_ini_handler, window) < 0) {
ltk_warn("Can't load theme.\n");
}
@@ -792,7 +805,7 @@ ltk_widget_mouse_press_event(ltk_widget *widget, XEvent event) {
if (!widget || widget->state == LTK_DISABLED)
return;
if (event.xbutton.button == 1) {
- /* ltk_widget *parent = widget->parent; FIXME */
+ /* ltk_widget *parent = widget->parent; FIXME: set pressed widget hierarchy */
widget->state = LTK_PRESSED;
if (widget->change_state)
widget->change_state(widget);
@@ -825,7 +838,8 @@ ltk_widget_mouse_release_event(ltk_widget *widget, XEvent event) {
void
ltk_widget_motion_notify_event(ltk_widget *widget, XEvent event) {
if (!widget) return;
- short pressed = (event.xmotion.state & Button1Mask) == Button1Mask;
+ /* FIXME: THIS WHOLE STATE HANDLING IS BROKEN */
+ int pressed = (event.xmotion.state & Button1Mask) == Button1Mask;
if ((widget->state == LTK_NORMAL) && !pressed) {
widget->state = LTK_ACTIVE;
if (widget->change_state)
diff --git a/scrollbar.c b/scrollbar.c
@@ -35,10 +35,9 @@
#include "util.h"
#include "scrollbar.h"
-static void ltk_scrollbar_draw(ltk_scrollbar *scrollbar);
+static void ltk_scrollbar_draw(ltk_scrollbar *scrollbar, ltk_rect clip);
static void ltk_scrollbar_mouse_press(ltk_scrollbar *scrollbar, XEvent event);
static void ltk_scrollbar_motion_notify(ltk_scrollbar *scrollbar, XEvent event);
-static ltk_scrollbar *ltk_scrollbar_create(ltk_window *window, ltk_orientation orient);
static void ltk_scrollbar_destroy(ltk_scrollbar *scrollbar, int shallow);
static struct {
@@ -95,8 +94,17 @@ ltk_scrollbar_ini_handler(ltk_window *window, const char *prop, const char *valu
}
}
+void
+ltk_scrollbar_set_virtual_size(ltk_scrollbar *scrollbar, int virtual_size) {
+ /* FIXME: some sort of error? */
+ if (virtual_size <= 0)
+ return;
+ scrollbar->cur_pos = (int)(((double)scrollbar->cur_pos / scrollbar->virtual_size) * virtual_size);
+ scrollbar->virtual_size = virtual_size;
+}
+
static void
-ltk_scrollbar_draw(ltk_scrollbar *scrollbar) {
+ltk_scrollbar_draw(ltk_scrollbar *scrollbar, ltk_rect clip) {
LtkColor *bg, *fg;
int handle_x, handle_y, handle_w, handle_h;
ltk_window *window = scrollbar->widget.window;
@@ -131,12 +139,18 @@ ltk_scrollbar_draw(ltk_scrollbar *scrollbar) {
handle_y = rect.y;
handle_h = rect.h;
handle_x = (int)(rect.x + (scrollbar->cur_pos / (double)scrollbar->virtual_size) * rect.w);
- handle_w = (int)((rect.w / (double)scrollbar->virtual_size) * rect.w);
+ if (scrollbar->virtual_size > rect.w)
+ handle_w = (int)((rect.w / (double)scrollbar->virtual_size) * rect.w);
+ else
+ handle_w = rect.w;
} else {
handle_x = rect.x;
handle_w = rect.w;
- handle_y = (int)(rect.x + (scrollbar->cur_pos / (double)scrollbar->virtual_size) * rect.h);
- handle_h = (int)((rect.h / (double)scrollbar->virtual_size) * rect.h);
+ handle_y = (int)(rect.y + (scrollbar->cur_pos / (double)scrollbar->virtual_size) * rect.h);
+ if (scrollbar->virtual_size > rect.h)
+ handle_h = (int)((rect.h / (double)scrollbar->virtual_size) * rect.h);
+ else
+ handle_h = rect.h;
}
if (handle_w <= 0 || handle_h <= 0)
return;
@@ -151,38 +165,43 @@ ltk_scrollbar_mouse_press(ltk_scrollbar *scrollbar, XEvent event) {
}
static void
-ltk_scrollbar_motion_notify(ltk_scrollbar *scrollbar, XEvent event) {
+ltk_scrollbar_motion_notify(ltk_scrollbar *sc, XEvent event) {
double scale;
int delta, max_pos;
- if (scrollbar->widget.state != LTK_PRESSED)
+ /* FIXME: Make this work properly with LTK_PRESSED */
+ if ((event.xmotion.state & Button1Mask) != Button1Mask)
return;
- if (scrollbar->orient == LTK_HORIZONTAL) {
- delta = event.xbutton.x - scrollbar->last_mouse_x;
- max_pos = scrollbar->virtual_size - scrollbar->widget.rect.w;
- scale = scrollbar->virtual_size / (double)scrollbar->widget.rect.w;
+ ltk_warn("adasd\n");
+ if (sc->orient == LTK_HORIZONTAL) {
+ delta = event.xbutton.x - sc->last_mouse_x;
+ max_pos = sc->virtual_size > sc->widget.rect.w ? sc->virtual_size - sc->widget.rect.w : 0;
+ scale = sc->virtual_size / (double)sc->widget.rect.w;
} else {
- delta = event.xbutton.y - scrollbar->last_mouse_y;
- max_pos = scrollbar->virtual_size - scrollbar->widget.rect.h;
- scale = scrollbar->virtual_size / (double)scrollbar->widget.rect.h;
+ delta = event.xbutton.y - sc->last_mouse_y;
+ max_pos = sc->virtual_size > sc->widget.rect.h ? sc->virtual_size - sc->widget.rect.h : 0;
+ scale = sc->virtual_size / (double)sc->widget.rect.h;
}
- scrollbar->cur_pos += (int)(scale * delta);
- if (scrollbar->cur_pos < 0)
- scrollbar->cur_pos = 0;
- else if (scrollbar->cur_pos > max_pos)
- scrollbar->cur_pos = max_pos;
- scrollbar->last_mouse_x = event.xbutton.x;
- scrollbar->last_mouse_y = event.xbutton.y;
+ sc->cur_pos += (int)(scale * delta);
+ if (sc->cur_pos < 0)
+ sc->cur_pos = 0;
+ else if (sc->cur_pos > max_pos)
+ sc->cur_pos = max_pos;
+ sc->last_mouse_x = event.xbutton.x;
+ sc->last_mouse_y = event.xbutton.y;
}
-static ltk_scrollbar *
+ltk_scrollbar *
ltk_scrollbar_create(ltk_window *window, ltk_orientation orient) {
ltk_scrollbar *sc = malloc(sizeof(ltk_scrollbar));
if (!sc)
ltk_fatal_errno("Unable to allocate memory for scrollbar.\n");
- ltk_fill_widget_default(sc, NULL, window, <k_scrollbar_draw,
- NULL, <k_scrollbar_destroy, 1);
+ ltk_fill_widget_defaults(sc, NULL, window, <k_scrollbar_draw,
+ NULL, <k_scrollbar_destroy, 1, LTK_UNKNOWN);
sc->last_mouse_x = sc->last_mouse_y = 0;
- sc->virtual_size = 0;
+ sc->widget.motion_notify = <k_scrollbar_motion_notify;
+ sc->widget.mouse_press = <k_scrollbar_mouse_press;
+ /* This cannot be 0 because that leads to divide-by-zero */
+ sc->virtual_size = 1;
sc->cur_pos = 0;
sc->orient = orient;
if (orient == LTK_HORIZONTAL)
diff --git a/scrollbar.h b/scrollbar.h
@@ -38,5 +38,6 @@ typedef struct {
void ltk_scrollbar_set_virtual_size(ltk_scrollbar *scrollbar, int virtual_size);
void ltk_scrollbar_setup_theme_defaults(ltk_window *window);
void ltk_scrollbar_ini_handler(ltk_window *window, const char *prop, const char *value);
+ltk_scrollbar *ltk_scrollbar_create(ltk_window *window, ltk_orientation orient);
#endif /* _LTK_SCROLLBAR_H_ */
diff --git a/text.h b/text.h
@@ -10,7 +10,7 @@ void ltk_init_text(const char *default_font, Display *dpy, int screen, Colormap
void ltk_cleanup_text(void);
LtkTextLine *ltk_text_line_create(Window window, uint16_t font_size, char *text, int width);
void ltk_text_line_render(LtkTextLine *tl, LtkColor *bg, LtkColor *fg);
-void ltk_text_line_draw(LtkTextLine *tl, GC gc, int x, int y);
+void ltk_text_line_draw(LtkTextLine *tl, GC gc, int x, int y, ltk_rect clip);
void ltk_text_line_set_width(LtkTextLine *tl, int width);
void ltk_text_line_get_size(LtkTextLine *tl, int *w, int *h);
void ltk_text_line_destroy(LtkTextLine *tl);
diff --git a/text_line.c b/text_line.c
@@ -35,14 +35,14 @@ void ltk_cleanup_text(void);
LtkTextLine *ltk_text_line_create(Window window, uint16_t font_size, char *text, int width);
void ltk_text_line_render(LtkTextLine *tl, LtkColor *bg, LtkColor *fg);
-void ltk_text_line_draw(LtkTextLine *tl, GC gc, int x, int y);
+void ltk_text_line_draw(LtkTextLine *tl, GC gc, int x, int y, ltk_rect clip);
void ltk_text_line_set_width(LtkTextLine *tl, int width);
void ltk_text_line_get_size(LtkTextLine *tl, int *w, int *h);
void ltk_text_line_destroy(LtkTextLine *tl);
static void ltk_text_line_create_glyphs(struct ltk_text_line *tl);
static void ltk_text_line_draw_glyph(ltk_glyph *glyph, int xoff, int yoff,
- XImage *img, XColor fg);
+ XImage *img, XColor fg, ltk_rect clip);
static XImage *ltk_create_ximage(Display *dpy, int w, int h, int depth,
XColor bg);
@@ -68,7 +68,7 @@ ltk_create_ximage(Display *dpy, int w, int h, int depth, XColor bg) {
/* based on http://codemadness.org/git/dwm-font/file/drw.c.html#l315 */
static void
-ltk_text_line_draw_glyph(ltk_glyph *glyph, int xoff, int yoff, XImage *img, XColor fg) {
+ltk_text_line_draw_glyph(ltk_glyph *glyph, int xoff, int yoff, XImage *img, XColor fg, ltk_rect clip) {
int x = glyph->x + xoff;
int y = glyph->y + yoff;
double a;
@@ -95,7 +95,8 @@ ltk_text_line_render(
GC gc,
Colormap colormap,
XColor fg,
- XColor bg)
+ XColor bg,
+ ltk_rect clip)
{
ltk_glyph *glyph;
@@ -105,7 +106,7 @@ ltk_text_line_render(
/* FIXME: pass old image; if it has same dimensions, just clear it */
XImage *img = ltk_create_ximage(dpy, tl->w, tl->h, depth, bg);
for (int i = 0; i < tl->glyph_len; i++) {
- ltk_text_line_draw_glyph(&tl->glyphs[i], -tl->x_min, -tl->y_min, img, fg);
+ ltk_text_line_draw_glyph(&tl->glyphs[i], -tl->x_min, -tl->y_min, img, fg, clip);
}
return img;
}
diff --git a/text_pango.c b/text_pango.c
@@ -98,7 +98,7 @@ ltk_text_line_render(LtkTextLine *tl, LtkColor *bg, LtkColor *fg) {
}
void
-ltk_text_line_draw(LtkTextLine *tl, GC gc, int x, int y) {
+ltk_text_line_draw(LtkTextLine *tl, GC gc, int x, int y, ltk_rect clip) {
XCopyArea(tm.dpy, tl->pixmap, tl->window, gc, 0, 0, tl->w, tl->h, x, y);
}
diff --git a/text_stb.c b/text_stb.c
@@ -534,7 +534,7 @@ ltk_text_line_render(
/* FIXME: error checking if img is rendered yet, tm initialized, etc. */
void
-ltk_text_line_draw(LtkTextLine *tl, GC gc, int x, int y) {
+ltk_text_line_draw(LtkTextLine *tl, GC gc, int x, int y, ltk_rect clip) {
XPutImage(tm.dpy, tl->window, gc, tl->img, 0, 0, x, y, tl->w, tl->h);
}