From e158c4832aa1d5dc8603fb9c33cac3f7cc19abc9 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Wed, 21 Jun 2017 14:25:13 +0200 Subject: added the widget and the composite widget classes --- src/gui/composite_widget.c | 137 +++++++++++++++++++++++++++++++++++++++++++++ src/gui/composite_widget.h | 32 +++++++++++ src/gui/widget.c | 74 +++++++++++++++++++++--- src/gui/widget.h | 19 ++++++- 4 files changed, 253 insertions(+), 9 deletions(-) create mode 100644 src/gui/composite_widget.c create mode 100644 src/gui/composite_widget.h (limited to 'src/gui') diff --git a/src/gui/composite_widget.c b/src/gui/composite_widget.c new file mode 100644 index 0000000..e9cc166 --- /dev/null +++ b/src/gui/composite_widget.c @@ -0,0 +1,137 @@ +#include "composite_widget.h" + +#include "string.h" +#include "stddef.h" + +static composite_widget_vtable_t composite_widget_vtable = { + { + composite_widget_draw, + composite_widget_get_focus, + widget_model_to_screen, + widget_contains_coordinate, + composite_widget_on_mouse_down, + composite_widget_on_mouse_up, + composite_widget_on_mouse_move, + composite_widget_on_key_down, + composite_widget_on_key_up + }, + composite_widget_add_child +}; + +void composite_widget_init( composite_widget_t *widget, widget_t *parent, const int x, const int y, const int w, const int h ) +{ + memset( widget, 0, sizeof( composite_widget_t ) ); + + widget_init( &widget->base, parent, x, y, w, h ); + + widget->nof_children = 0; + widget->focused_child = NULL; + memset( widget->children, 0, MAX_NOF_WIDGET_CHILDREN * sizeof( widget_t * ) ); + + widget->vtable = &composite_widget_vtable; +} + +void composite_widget_draw( void *obj, graphics_context_t *context ) +{ + composite_widget_t *widget = obj; + + widget->base.vtable->draw( obj, context ); + + for( int i = widget->nof_children - 1; i >= 0; i-- ) { + widget_t *child = widget->children[i]; + child->vtable->draw( child, context ); + } +} + +void composite_widget_get_focus( void *obj, widget_t *widget ) +{ + composite_widget_t *o = obj; + + o->focused_child = widget; + + o->base.vtable->get_focus( o, widget ); +} + +void composite_widget_add_child( void *obj, widget_t *child ) +{ + composite_widget_t *widget = obj; + + if( widget->nof_children >= MAX_NOF_WIDGET_CHILDREN ) { + // TODO: kernel_panic, but in an indirect way because + // the GUI framework should not depend on the kernel. + // Maybe something like a runtime context similar to + // the graphics context? + return; + } + + widget->children[widget->nof_children++] = child; +} + +void composite_widget_on_mouse_down( void *obj, const int x, const int y ) +{ + composite_widget_t *widget = obj; + + for( int i = 0; i < widget->nof_children; i++ ) { + widget_t *child = widget->children[i]; + if( child->vtable->contains_coordinate( child, x - widget->base.x, y - widget->base.y ) ) { + child->vtable->on_mouse_down( child, x - widget->base.x, y - widget->base.y ); + break; + } + } +} + +void composite_widget_on_mouse_up( void *obj, const int x, const int y ) +{ + composite_widget_t *widget = obj; + + for( int i = 0; i < widget->nof_children; i++ ) { + widget_t *child = widget->children[i]; + if( child->vtable->contains_coordinate( child, x - widget->base.x, y - widget->base.y ) ) { + child->vtable->on_mouse_up( child, x - widget->base.x, y - widget->base.y ); + break; + } + } +} + +void composite_widget_on_mouse_move( void *obj, const int old_x, const int old_y, const int x, const int y ) +{ + composite_widget_t *widget = obj; + widget_t *moved_out_from = NULL; + + for( int i = 0; i < widget->nof_children; i++ ) { + widget_t *child = widget->children[i]; + if( child->vtable->contains_coordinate( child, old_x - widget->base.x, old_y - widget->base.y ) ) { + child->vtable->on_mouse_move( child, old_x - widget->base.x, old_y - widget->base.y, x - widget->base.x, y - widget->base.y ); + moved_out_from = child; + break; + } + } + + for( int i = 0; i < widget->nof_children; i++ ) { + widget_t *child = widget->children[i]; + if( child->vtable->contains_coordinate( child, x - widget->base.x, y - widget->base.y ) ) { + if( moved_out_from != NULL ) { + child->vtable->on_mouse_move( child, old_x - widget->base.x, old_y - widget->base.y, x - widget->base.x, y - widget->base.y ); + break; + } + } + } +} + +void composite_widget_on_key_down( void *obj, char c ) +{ + composite_widget_t *widget = obj; + + if( widget->focused_child != NULL ) { + widget->focused_child->vtable->on_key_down( widget->focused_child, c ); + } +} + +void composite_widget_on_key_up( void *obj, char c ) +{ + composite_widget_t *widget = obj; + + if( widget->focused_child != NULL ) { + widget->focused_child->vtable->on_key_up( widget->focused_child, c ); + } +} diff --git a/src/gui/composite_widget.h b/src/gui/composite_widget.h new file mode 100644 index 0000000..d3ba90a --- /dev/null +++ b/src/gui/composite_widget.h @@ -0,0 +1,32 @@ +#ifndef COMPOSITE_WIDGET_H +#define COMPOSITE_WIDGET_H + +#include "widget.h" + +#define MAX_NOF_WIDGET_CHILDREN 100 + +typedef struct { + widget_vtable_t base; + void (*add_child)( void *obj, widget_t *child ); +} composite_widget_vtable_t; + +typedef struct { + widget_t base; + composite_widget_vtable_t *vtable; + widget_t *children[MAX_NOF_WIDGET_CHILDREN]; + int nof_children; + widget_t *focused_child; +} composite_widget_t; + +void composite_widget_init( composite_widget_t *widget, widget_t *parent, const int x, const int y, const int w, const int h ); + +void composite_widget_draw( void *obj, graphics_context_t *context ); +void composite_widget_get_focus( void *obj, widget_t *widget ); +void composite_widget_on_mouse_down( void *obj, const int x, const int y ); +void composite_widget_on_mouse_up( void *obj, const int x, const int y ); +void composite_widget_on_mouse_move( void *obj, const int old_x, const int old_y, const int x, const int y ); +void composite_widget_on_key_down( void *obj, char c ); +void composite_widget_on_key_up( void *obj, char c ); +void composite_widget_add_child( void *obj, widget_t *child ); + +#endif // COMPOSITE_WIDGET_H diff --git a/src/gui/widget.c b/src/gui/widget.c index 313fd49..cd77d03 100644 --- a/src/gui/widget.c +++ b/src/gui/widget.c @@ -5,12 +5,14 @@ static widget_vtable_t widget_vtable = { widget_draw, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL + widget_get_focus, + widget_model_to_screen, + widget_contains_coordinate, + widget_on_mouse_down, + widget_on_mouse_up, + widget_on_mouse_move, + widget_on_key_down, + widget_on_key_up }; void widget_init( widget_t *widget, widget_t *parent, const int x, const int y, const int w, const int h ) @@ -29,7 +31,65 @@ void widget_init( widget_t *widget, widget_t *parent, const int x, const int y, void widget_draw( void *obj, graphics_context_t *context ) { widget_t *widget = obj; + int x = 0; + int y = 0; - vga_draw_rectangle( context, widget->x, widget->y, widget->w, widget->h, + widget->vtable->model_to_screen( widget, &x, &y ); + + vga_draw_rectangle( context, x, y, widget->w, widget->h, vga_make_RGB( 0xFF, 0xFF, 0xFF ) ); } + +void widget_get_focus( void *obj, widget_t *widget ) +{ + widget_t *o = obj; + + if( o->parent != NULL ) { + o->parent->vtable->get_focus( widget->parent, widget ); + } +} + +void widget_model_to_screen( void *obj, int *x, int *y ) +{ + widget_t *widget = obj; + + if( widget->parent != NULL ) { + widget->parent->vtable->model_to_screen( widget->parent, x, y ); + } + + *x += widget->x; + *y += widget->y; +} + +bool widget_contains_coordinate( void *obj, const int x, const int y ) +{ + widget_t *widget = obj; + + return widget->x <= x && x < widget->x + widget->w && + widget->y <= y && y < widget->y + widget->h; +} + +void widget_on_mouse_down( void *obj, const int x, const int y ) +{ + widget_t *widget = obj; + + if( widget->focusable ) { + widget->vtable->get_focus( widget, widget ); + } +} + +void widget_on_mouse_up( void *obj, const int x, const int y ) +{ +} + +void widget_on_mouse_move( void *obj, const int old_x, const int old_y, const int x, const int y ) +{ +} + +void widget_on_key_down( void *obj, char c ) +{ +} + +void widget_on_key_up( void *obj, char c ) +{ +} diff --git a/src/gui/widget.h b/src/gui/widget.h index a1e9a21..1fd23ac 100644 --- a/src/gui/widget.h +++ b/src/gui/widget.h @@ -3,14 +3,20 @@ #include "graphics_context.h" +#include + +struct widget_t; + typedef struct { void (*draw)( void *obj, graphics_context_t *context ); - void (*get_focus)( void *obj ); - void (*widget_model_to_screen)( void *obj, int *x, int *y ); + void (*get_focus)( void *obj, struct widget_t *widget ); + void (*model_to_screen)( void *obj, int *x, int *y ); + bool (*contains_coordinate)( void *obj, const int x, const int y ); void (*on_mouse_down)( void *obj, const int x, const int y ); void (*on_mouse_up)( void *obj, const int x, const int y ); void (*on_mouse_move)( void *obj, const int old_x, const int old_y, const int x, const int y ); void (*on_key_down)( void *obj, char c ); + void (*on_key_up)( void *obj, char c ); } widget_vtable_t; typedef struct widget_t { @@ -18,6 +24,7 @@ typedef struct widget_t { int y; int w; int h; + bool focusable; struct widget_t *parent; widget_vtable_t *vtable; } widget_t; @@ -25,5 +32,13 @@ typedef struct widget_t { void widget_init( widget_t *widget, widget_t *parent, const int x, const int y, const int w, const int h ); void widget_draw( void *obj, graphics_context_t *context ); +void widget_get_focus( void *obj, widget_t *widget ); +void widget_model_to_screen( void *obj, int *x, int *y ); +bool widget_contains_coordinate( void *obj, const int x, const int y ); +void widget_on_mouse_down( void *obj, const int x, const int y ); +void widget_on_mouse_up( void *obj, const int x, const int y ); +void widget_on_mouse_move( void *obj, const int old_x, const int old_y, const int x, const int y ); +void widget_on_key_down( void *obj, char c ); +void widget_on_key_up( void *obj, char c ); #endif // WIDGET_H -- cgit v1.2.3-54-g00ecf