From 246e6bdd5d9dc50ebcc4ea288a4458caa9853a48 Mon Sep 17 00:00:00 2001 From: Matthew Allum Date: Fri, 29 Apr 2005 16:44:17 +0000 Subject: [PATCH] hack buttons some more --- ChangeLog | 24 ++++++ clutter/cltr-button.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++--- clutter/cltr-button.h | 16 ++++ clutter/cltr-label.c | 19 +++-- clutter/cltr-private.h | 11 ++- clutter/cltr-video.c | 2 +- clutter/cltr-widget.c | 114 +++++++++++++++++++++++++++- clutter/cltr-widget.h | 31 ++++++++ clutter/cltr-window.c | 8 +- clutter/cltr.h | 1 + clutter/fonts.c | 18 ++++- examples/scratch.c | 18 ++++- 12 files changed, 426 insertions(+), 32 deletions(-) diff --git a/ChangeLog b/ChangeLog index 191a679..d868a7e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2005-04-29 mallum,,, + + * clutter/cltr-button.c: (cltr_button_new), + (cltr_button_on_activate), (cltr_button_new_with_label), + (cltr_button_show): + * clutter/cltr-button.h: + * clutter/cltr-label.c: (cltr_label_new), (cltr_label_paint): + * clutter/cltr-private.h: + * clutter/cltr-video.c: (cltr_video_play): + * clutter/cltr-widget.c: (cltr_widget_new), (cltr_widget_abs_x), + (cltr_widget_abs_y), (cltr_widget_abs_x2), (cltr_widget_abs_y2), + (cltr_widget_width), (cltr_widget_height), (cltr_widget_show), + (cltr_widget_focus), (cltr_widget_unfocus), + (cltr_widget_set_focus_next), (cltr_widget_get_focus_next), + (cltr_widget_show_all): + * clutter/cltr-widget.h: + * clutter/cltr-window.c: (cltr_window_new), + (cltr_window_focus_widget): + * clutter/cltr.h: + * clutter/fonts.c: (draw_layout_on_pixbuf), (font_get_pixel_size): + * examples/scratch.c: (main): + Hack buttons some more + + 2005-04-27 mallum,,, * clutter/Makefile.am: diff --git a/clutter/cltr-button.c b/clutter/cltr-button.c index 4bf39ee..be8ea02 100644 --- a/clutter/cltr-button.c +++ b/clutter/cltr-button.c @@ -3,12 +3,18 @@ struct CltrButton { - CltrWidget widget; - char *label; - Pixbuf *pixb; - + CltrWidget widget; + CltrLabel *label; + + CltrButtonActivate activate_cb; + void *activate_cb_data; + + CltrButtonState state; /* may be better in widget ? */ }; +#define BUTTON_BORDER 1 +#define BUTTON_PAD 5 + static void cltr_button_show(CltrWidget *widget); @@ -18,6 +24,12 @@ cltr_button_handle_xevent (CltrWidget *widget, XEvent *xev); static void cltr_button_paint(CltrWidget *widget); +static void +cltr_button_focus(CltrWidget *widget); + +static void +cltr_button_unfocus(CltrWidget *widget); + CltrWidget* cltr_button_new(int width, int height) @@ -31,25 +43,44 @@ cltr_button_new(int width, int height) button->widget.show = cltr_button_show; button->widget.paint = cltr_button_paint; - + button->widget.focus_in = cltr_button_focus; + button->widget.focus_out = cltr_button_unfocus; button->widget.xevent_handler = cltr_button_handle_xevent; return CLTR_WIDGET(button); } +void +cltr_button_on_activate(CltrButton *button, + CltrButtonActivate callback, + void *userdata) +{ + button->activate_cb = callback; + button->activate_cb_data = userdata; +} + CltrWidget* cltr_button_new_with_label(const char *label, CltrFont *font, PixbufPixel *col) { CltrButton *button = NULL; - int label_width, label_height; - if (font == NULL) - { - /* XXXX grab default font */ - } + button = CLTR_BUTTON(cltr_button_new(-1, -1)); + + button->label = CLTR_LABEL(cltr_label_new(label, font, col)); + button->widget.width = cltr_widget_width((CltrWidget*)button->label) + (2 * ( BUTTON_BORDER + BUTTON_PAD)); + button->widget.height = cltr_widget_height((CltrWidget*)button->label) + ( 2 * ( BUTTON_BORDER + BUTTON_PAD)); + + CLTR_DBG("width: %i, height %i", + cltr_widget_width((CltrWidget*)button->label), + cltr_widget_height((CltrWidget*)button->label)); + + cltr_widget_add_child(CLTR_WIDGET(button), + CLTR_WIDGET(button->label), + ( BUTTON_BORDER + BUTTON_PAD), + ( BUTTON_BORDER + BUTTON_PAD)); return CLTR_WIDGET(button); } @@ -60,15 +91,160 @@ cltr_button_show(CltrWidget *widget) } +static void +cltr_button_focus(CltrWidget *widget) +{ + CltrButton *button = CLTR_BUTTON(widget); + + if (button->state != CltrButtonStateFocused) + { + button->state = CltrButtonStateFocused; + cltr_widget_queue_paint(widget); + } +} + +static void +cltr_button_unfocus(CltrWidget *widget) +{ + CltrButton *button = CLTR_BUTTON(widget); + + if (button->state != CltrButtonStateInactive) + { + button->state = CltrButtonStateInactive; + + cltr_widget_queue_paint(CLTR_WIDGET(button)); + } +} + +static void +cltr_button_handle_xkeyevent(CltrButton *button, XKeyEvent *xkeyev) +{ + KeySym kc; + CltrButtonState old_state; + CltrWidget *next_focus = NULL; + + old_state = button->state; + + kc = XKeycodeToKeysym(xkeyev->display, xkeyev->keycode, 0); + + switch (kc) + { + case XK_Left: + case XK_KP_Left: + if (xkeyev->type != KeyPress) + break; + next_focus = cltr_widget_get_focus_next(CLTR_WIDGET(button), CLTR_WEST); + break; + case XK_Up: + case XK_KP_Up: + if (xkeyev->type != KeyPress) + break; + + next_focus = cltr_widget_get_focus_next(CLTR_WIDGET(button), CLTR_NORTH); + break; + case XK_Right: + case XK_KP_Right: + if (xkeyev->type != KeyPress) + break; + + next_focus = cltr_widget_get_focus_next(CLTR_WIDGET(button), CLTR_EAST); + break; + case XK_Down: + case XK_KP_Down: + if (xkeyev->type != KeyPress) + break; + + next_focus = cltr_widget_get_focus_next(CLTR_WIDGET(button), CLTR_SOUTH); + break; + case XK_Return: + if (xkeyev->type == KeyPress) + { + if (button->state != CltrButtonStateActive) + button->state = CltrButtonStateActive; + CLTR_DBG("press"); + + if (button->activate_cb) + button->activate_cb(CLTR_WIDGET(button), button->activate_cb_data); + + } + else /* KeyRelease */ + { + CLTR_DBG("release"); + if (button->state != CltrButtonStateFocused) + button->state = CltrButtonStateFocused; + + /* What to do about key repeats ? */ + + } + break; + default: + /* ??? */ + } + + if (button->state != old_state) + { + CLTR_DBG("queueing paint"); + cltr_widget_queue_paint(CLTR_WIDGET(button)); + } + + if (next_focus) + { + /* Evil - need to centralise focus management */ + ClutterMainContext *ctx = CLTR_CONTEXT(); + cltr_window_focus_widget(ctx->window, next_focus); + } +} + + static gboolean cltr_button_handle_xevent (CltrWidget *widget, XEvent *xev) { + CltrButton *button = CLTR_BUTTON(widget); + switch (xev->type) + { + case KeyPress: + case KeyRelease: + CLTR_DBG("KeyPress"); + cltr_button_handle_xkeyevent(button, &xev->xkey); + break; + } } + static void cltr_button_paint(CltrWidget *widget) { + CltrButton *button = CLTR_BUTTON(widget); + + CLTR_MARK(); + + glPushMatrix(); + glEnable(GL_BLEND); + switch (button->state) + { + case CltrButtonStateFocused: + glColor4f(1.0, 1.0, 0.0, 1.0); + break; + case CltrButtonStateActive: + glColor4f(1.0, 0.0, 0.0, 1.0); + break; + default: + glColor4f(1.0, 1.0, 1.0, 1.0); + } + + cltr_glu_rounded_rect(widget->x, + widget->y, + widget->x + widget->width, + widget->y + widget->height, + widget->width/30, + NULL); + + glDisable(GL_BLEND); + + glPopMatrix(); } + + diff --git a/clutter/cltr-button.h b/clutter/cltr-button.h index 8e4966f..9b0f0b7 100644 --- a/clutter/cltr-button.h +++ b/clutter/cltr-button.h @@ -5,10 +5,26 @@ typedef struct CltrButton CltrButton; +typedef enum CltrButtonState +{ + CltrButtonStateDisabled, + CltrButtonStateInactive, + CltrButtonStateFocused, + CltrButtonStateActive, + } +CltrButtonState; + +typedef void (*CltrButtonActivate) (CltrWidget *widget, void *userdata) ; + #define CLTR_BUTTON(w) ((CltrButton*)(w)) CltrWidget* cltr_button_new(int width, int height); +void +cltr_button_on_activate(CltrButton *button, + CltrButtonActivate callback, + void* userdata); + #endif diff --git a/clutter/cltr-label.c b/clutter/cltr-label.c index f4bcf71..b9550c7 100644 --- a/clutter/cltr-label.c +++ b/clutter/cltr-label.c @@ -36,21 +36,20 @@ cltr_label_new(const char *text, if (width && height) { - PixbufPixel bg = { 0xff, 0x0, 0x0, 0xff }; + PixbufPixel bg = { 0xff, 0xff, 0xff, 0x00 }; label->text = strdup(text); label->pixb = pixbuf_new(width, height); pixbuf_fill_rect(label->pixb, 0, 0, -1, -1, &bg); - /* font_draw(font, label->pixb, label->text, 0, 0, col); - */ + label->texture = cltr_texture_new(label->pixb); } @@ -106,6 +105,8 @@ cltr_label_paint(CltrWidget *widget) { CltrLabel *label = CLTR_LABEL(widget); + CLTR_MARK(); + if (label->text) { glPushMatrix(); @@ -115,15 +116,13 @@ cltr_label_paint(CltrWidget *widget) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND); - - /* glColor4ub(100, 200, 50, 100); */ + /* glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND); */ cltr_texture_render_to_gl_quad(label->texture, - widget->x, - widget->y, - widget->x + widget->width , - widget->y + widget->height); + cltr_widget_abs_x(widget), + cltr_widget_abs_y(widget), + cltr_widget_abs_x2(widget), + cltr_widget_abs_y2(widget)); glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); diff --git a/clutter/cltr-private.h b/clutter/cltr-private.h index a8ffec2..0fb8894 100644 --- a/clutter/cltr-private.h +++ b/clutter/cltr-private.h @@ -32,11 +32,13 @@ typedef void (*WidgetPaintMethod) (CltrWidget *widget ) ; typedef void (*WidgetShowMethod) (CltrWidget *widget ) ; typedef void (*WidgetDestroyMethod) (CltrWidget *widget) ; - +typedef void (*WidgetFocusMethod) (CltrWidget *widget) ; +typedef void (*WidgetUnfocusMethod) (CltrWidget *widget) ; typedef gboolean (*WidgetXEventHandler) (CltrWidget *widget, XEvent *xev) ; struct CltrWidget { + int type; int x,y,width,height; CltrWidget *parent; @@ -44,11 +46,18 @@ struct CltrWidget GList *children; + /* focus */ + + CltrWidget *focus_next_north, *focus_next_south, + *focus_next_west, *focus_next_east; + /* methods */ WidgetPaintMethod paint; WidgetShowMethod show; WidgetDestroyMethod destroy; + WidgetFocusMethod focus_in; + WidgetUnfocusMethod focus_out; WidgetXEventHandler xevent_handler; }; diff --git a/clutter/cltr-video.c b/clutter/cltr-video.c index 0f6c15c..33565ac 100644 --- a/clutter/cltr-video.c +++ b/clutter/cltr-video.c @@ -442,7 +442,7 @@ cltr_video_play(CltrVideo *video) GST_STATE_PLAYING) == GST_STATE_FAILURE) g_error ("Could not set state to PLAYING"); - g_timeout_add(FPS_TO_TIMEOUT(20), (GSourceFunc) cltr_video_idler, video); + g_timeout_add(FPS_TO_TIMEOUT(30), (GSourceFunc) cltr_video_idler, video); } void diff --git a/clutter/cltr-widget.c b/clutter/cltr-widget.c index e21c243..fb1349e 100644 --- a/clutter/cltr-widget.c +++ b/clutter/cltr-widget.c @@ -12,6 +12,46 @@ cltr_widget_new(void) } int +cltr_widget_abs_x(CltrWidget *widget) +{ + int x = widget->x; + + /* XXX we really need to identify top level window + * this assummes its positioned at 0,0 - but really + * it could be anywhere and need to account for this. + */ + + while ((widget = widget->parent) != NULL) + x += widget->x; + + return x; +} + +int +cltr_widget_abs_y(CltrWidget *widget) +{ + int y = widget->y; + + while ((widget = widget->parent) != NULL) + y += widget->y; + + return y; +} + +int +cltr_widget_abs_x2(CltrWidget *widget) +{ + return cltr_widget_abs_x(widget) + cltr_widget_width(widget); +} + +int +cltr_widget_abs_y2(CltrWidget *widget) +{ + return cltr_widget_abs_y(widget) + cltr_widget_height(widget); +} + + +int cltr_widget_width(CltrWidget *widget) { return widget->width; @@ -20,9 +60,10 @@ cltr_widget_width(CltrWidget *widget) int cltr_widget_height(CltrWidget *widget) { - return widget->width; + return widget->height; } + void cltr_widget_show(CltrWidget *widget) { @@ -34,6 +75,73 @@ cltr_widget_show(CltrWidget *widget) } } + +/* XXX Focus hacks; + * + * Should not call directly but via cltr_window_focus_widget() + * + * need to sort this out. +*/ +void +cltr_widget_focus(CltrWidget *widget) +{ + if (widget->focus_in) + { + widget->focus_in(widget); + } +} + +void +cltr_widget_unfocus(CltrWidget *widget) +{ + if (widget->focus_out) + { + widget->focus_out(widget); + } +} + +void +cltr_widget_set_focus_next(CltrWidget *widget, + CltrWidget *widget_to_focus, + CltrDirection direction) +{ + switch (direction) + { + case CLTR_NORTH: + widget->focus_next_north = widget_to_focus; + break; + case CLTR_SOUTH: + widget->focus_next_south = widget_to_focus; + break; + case CLTR_EAST: + widget->focus_next_east = widget_to_focus; + break; + case CLTR_WEST: + widget->focus_next_west = widget_to_focus; + break; + } +} + +CltrWidget* +cltr_widget_get_focus_next(CltrWidget *widget, + CltrDirection direction) +{ + switch (direction) + { + case CLTR_NORTH: + return widget->focus_next_north; + case CLTR_SOUTH: + return widget->focus_next_south; + case CLTR_EAST: + return widget->focus_next_east; + case CLTR_WEST: + return widget->focus_next_west; + } + + return NULL; +} + + void cltr_widget_show_all(CltrWidget *widget) { @@ -46,6 +154,8 @@ cltr_widget_show_all(CltrWidget *widget) CltrWidget *child = CLTR_WIDGET(widget_item->data); cltr_widget_show(child); + + cltr_widget_show_all(child); } while ((widget_item = g_list_next(widget_item)) != NULL); } @@ -56,11 +166,13 @@ cltr_widget_show_all(CltrWidget *widget) void cltr_widget_add_child(CltrWidget *widget, CltrWidget *child, int x, int y) { + widget->children = g_list_append(widget->children, child); child->parent = widget; child->x = x; child->y = y; + } diff --git a/clutter/cltr-widget.h b/clutter/cltr-widget.h index 8686587..87e7856 100644 --- a/clutter/cltr-widget.h +++ b/clutter/cltr-widget.h @@ -16,6 +16,37 @@ cltr_widget_width(CltrWidget *widget); int cltr_widget_height(CltrWidget *widget); +int +cltr_widget_abs_x(CltrWidget *widget); + +int +cltr_widget_abs_y(CltrWidget *widget); + +int +cltr_widget_abs_x2(CltrWidget *widget); + +int +cltr_widget_abs_y2(CltrWidget *widget); + + +/* These are hacky see notes in .c */ +void +cltr_widget_focus(CltrWidget *widget); + +void +cltr_widget_unfocus(CltrWidget *widget); + +/* ******************************* */ + +void +cltr_widget_set_focus_next(CltrWidget *widget, + CltrWidget *widget_to_focus, + CltrDirection direction); + +CltrWidget* +cltr_widget_get_focus_next(CltrWidget *widget, + CltrDirection direction); + void cltr_widget_show(CltrWidget *widget); diff --git a/clutter/cltr-window.c b/clutter/cltr-window.c index a7c8418..27036cf 100644 --- a/clutter/cltr-window.c +++ b/clutter/cltr-window.c @@ -53,7 +53,7 @@ cltr_window_new(int width, int height) XSelectInput(CltrCntx.xdpy, win->xwin, StructureNotifyMask|ExposureMask| - KeyPressMask|PropertyChangeMask); + KeyPressMask|KeyReleaseMask|PropertyChangeMask); glXMakeCurrent(CltrCntx.xdpy, win->xwin, CltrCntx.gl_context); @@ -164,8 +164,12 @@ cltr_window_focus_widget(CltrWindow *win, CltrWidget *widget) ClutterMainContext *ctx = CLTR_CONTEXT(); - win->focused_child = widget; + if (win->focused_child) + cltr_widget_unfocus(win->focused_child); + cltr_widget_focus(widget); + + win->focused_child = widget; } diff --git a/clutter/cltr.h b/clutter/cltr.h index a32af31..bc872a7 100644 --- a/clutter/cltr.h +++ b/clutter/cltr.h @@ -21,6 +21,7 @@ #include "pixbuf.h" #include "fonts.h" + typedef enum CltrDirection { CLTR_NORTH, diff --git a/clutter/fonts.c b/clutter/fonts.c index 43aae82..8806955 100644 --- a/clutter/fonts.c +++ b/clutter/fonts.c @@ -118,10 +118,16 @@ draw_layout_on_pixbuf (PangoLayout *layout, int tr1, tg1, tb1, tr2, tg2, tb2; int a = (*b * color->a + 0x80) >> 8; - /* + /* + this is wrong for when the backing has an + alpha of zero. we need a different algorythm + to handle that - so we can overlay just a font + text texture with no bg + + */ + if (!a) { b++; continue; } - */ pixbuf_get_pixel (pixb, i, j, &pixel); @@ -134,8 +140,10 @@ draw_layout_on_pixbuf (PangoLayout *layout, tb1 = (255 - a) * pixel.b + 0x80; tb2 = a * color->b + 0x80; pixel.b = ((tb1 + (tb1 >> 8)) >> 8) + ((tb2 + (tb2 >> 8)) >> 8); - - + tb1 = (255 - a) * pixel.a + 0x80; + tb2 = a * color->a + 0x80; + pixel.a = ((tb1 + (tb1 >> 8)) >> 8) + ((tb2 + (tb2 >> 8)) >> 8); + pixbuf_set_pixel (pixb, i, j, &pixel); b++; } @@ -194,6 +202,8 @@ font_get_pixel_size (ClutterFont *font, pango_layout_get_pixel_size (layout, width, height); + printf("gave width:%i, height %i\n", *width, *height); + g_object_unref(G_OBJECT(layout)); } diff --git a/examples/scratch.c b/examples/scratch.c index a8eafd0..d89111d 100644 --- a/examples/scratch.c +++ b/examples/scratch.c @@ -12,6 +12,8 @@ main(int argc, char **argv) { int i; CltrWidget *win = NULL, *grid = NULL, *test = NULL, *test2 = NULL; + CltrFont *font = NULL; + PixbufPixel col = { 0xff, 0, 0, 0xff }; gchar *img_path = NULL; gboolean want_fullscreen = FALSE; @@ -51,12 +53,22 @@ main(int argc, char **argv) if (want_fullscreen) cltr_window_set_fullscreen(CLTR_WINDOW(win)); + font = font_new("Sans 20"); - grid = cltr_photo_grid_new(800, 600, cols, cols, img_path); + test = cltr_button_new_with_label("ButtonBoooo\ndsfdsfdsf sss\nsjhsjhsjhs", font, &col); - cltr_window_focus_widget(CLTR_WINDOW(win), grid); + test2 = cltr_button_new_with_label("Button", font, &col); - cltr_widget_add_child(win, grid, 0, 0); + cltr_widget_add_child(win, test, 300, 100); + + cltr_widget_add_child(win, test2, 100, 100); + + cltr_window_focus_widget(CLTR_WINDOW(win), test); + + cltr_widget_set_focus_next(test, test2, CLTR_EAST); + cltr_widget_set_focus_next(test, test2, CLTR_WEST); + cltr_widget_set_focus_next(test2, test, CLTR_EAST); + cltr_widget_set_focus_next(test2, test, CLTR_WEST); /* -- 2.7.4