#include "composite_widget.h" #include "string.h" #include static composite_widget_vtable_t const 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, const vga_color_t background_color ) { memset( widget, 0, sizeof( composite_widget_t ) ); widget_init( &widget->base, parent, x, y, w, h, background_color ); widget->nof_children = 0; widget->focused_child = NULL; memset( widget->children, 0, MAX_NOF_WIDGET_CHILDREN * sizeof( widget_t * ) ); ((widget_t *)widget)->vtable = (widget_vtable_t *)&composite_widget_vtable; } void composite_widget_draw( void *obj, graphics_context_t *context ) { composite_widget_t *widget = obj; widget_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; widget_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; // TODO: have a mouse leave and mouse enter event instead 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 ); } }