/** * \brief Setup widget demo * * Allocates memory for the application context, and creates all widgets that * make up its interface. If memory allocation or widget creation fails, the * application exits immediately. * * \return Boolean true if the application was launched successfully, false if * a memory allocation occurred. */ bool app_widget_launch(void) { struct win_window *parent; struct win_area area; struct wtk_check_box *cb; struct wtk_radio_group *rg; struct wtk_radio_button *rb; struct wtk_button *btn; /* Create a new context for the GUI */ widget_ctx = membag_alloc(sizeof(struct widget_context)); if (!widget_ctx) { return false; } /* Initialize context data. */ widget_ctx->color_scheme = 0; widget_ctx->color_invert = 0; /* Set the background information for the GUI window */ widget_ctx->frame_bg.type = GFX_BITMAP_SOLID; widget_ctx->frame_bg.data.color = APP_BACKGROUND_COLOR; /* Set the area for the GUI window */ area = win_get_attributes(win_get_root())->area; win_inflate_area(&area, -20); /* Create and show the main GUI frame */ widget_ctx->frame = wtk_basic_frame_create( win_get_root(), &area, &widget_ctx->frame_bg, NULL, widget_frame_command_handler, widget_ctx); if (!widget_ctx->frame) { goto error_frame; } parent = wtk_basic_frame_as_child(widget_ctx->frame); win_show(parent); /* Update area for the slider widget */ area.pos.x = WIDGET_POS_X; area.pos.y = WIDGET_POS_Y + SLIDER_POS_Y; area.size.x = SLIDER_SIZE_X; area.size.y = SLIDER_SIZE_Y; /* Create slider inside frame */ widget_ctx->slider = wtk_slider_create(parent, &area, 100, 50, WTK_SLIDER_HORIZONTAL | WTK_SLIDER_CMD_MOVE | WTK_SLIDER_CMD_RELEASE, (win_command_t)SLIDER_ID); if (!widget_ctx->slider) { goto error_widget; } win_show(wtk_slider_as_child(widget_ctx->slider)); /* Update area for the progress bar widget */ area.pos.x += area.size.x + SLIDER_PB_SPACING_X; area.size.x = PB_SIZE_X; area.size.y = PB_SIZE_Y; /* Create progress bar to the right of the slider */ widget_ctx->pb = wtk_progress_bar_create(parent, &area, 100, 50, GFX_COLOR_BLACK, GFX_COLOR_BLACK, WTK_PROGRESS_BAR_HORIZONTAL); if (!widget_ctx->pb) { goto error_widget; } win_show(wtk_progress_bar_as_child(widget_ctx->pb)); app_widget_update_colors(widget_ctx); /* Update area for the checkbox widget */ area.pos.x = WIDGET_POS_X; area.pos.y += area.size.y + CHECK_BOX_SPACING_Y; wtk_check_box_size_hint(&area.size, checkbox_string); /* Create check box below slider and progress bar */ cb = wtk_check_box_create(parent, &area, checkbox_string, false, (win_command_t)CHECK_BOX_ID); if (!cb) { goto error_widget; } win_show(wtk_check_box_as_child(cb)); /* Create a logical group for the radio buttons */ rg = wtk_radio_group_create(); if (!rg) { goto error_widget; } /* Update area for the first radio button widget */ area.pos.y += area.size.y + RADIO_BUTTON_SPACING_Y; wtk_radio_button_size_hint(&area.size, rb1_string); /* Create first radio button widget */ rb = wtk_radio_button_create(parent, &area, rb1_string, true, rg, (win_command_t)RADIO_BUTTON_1_ID); if (!rb) { goto error_widget; } win_show(wtk_radio_button_as_child(rb)); /* Update area for the second radio button widget */ area.pos.y += area.size.y + RADIO_BUTTON_SPACING_Y; wtk_radio_button_size_hint(&area.size, rb2_string); /* Create second radio button widget */ rb = wtk_radio_button_create(parent, &area, rb2_string, false, rg, (win_command_t)RADIO_BUTTON_2_ID); if (!rb) { goto error_widget; } win_show(wtk_radio_button_as_child(rb)); /* Update area for the button widget */ area.pos.y += area.size.y + BUTTON_SPACING_Y; area.size.x = SLIDER_SIZE_X + SLIDER_PB_SPACING_X + PB_SIZE_X; area.size.y = BUTTON_SIZE_Y; /* Create button widget */ btn = wtk_button_create(parent, &area, btn_string, (win_command_t)BUTTON_ID); wtk_button_size_hint(&area.size, btn_string); if (!btn) { goto error_widget; } win_show(wtk_button_as_child(btn)); return true; /* Error handling to clean up allocations after an error */ error_widget: win_destroy(wtk_basic_frame_as_child(widget_ctx->frame)); error_frame: membag_free(widget_ctx); return false; }
int main( int argc, char* argv[] ) { if( fs_init() ) return 1; win_initialize( argc, argv ); g_RS = rsl_create(); g_RS.change_cb = runner_change_callback; g_winActCb = runner_action_callback; rsl_compile( &g_RS, g_scriptData, NULL ); X_DBG( rsl_dump( &g_RS ) ); #if 0 /////////////////////////////////////////////////// // win_set_title( "Testā rešpekt" ); // win_set_background_color( 120, 150, 180 ); // win_set_background_image( 0 ); win_ctl_resize( 2 ); g_controls[0].type = WCTL_BUTTON; g_controls[0].x1 = 100; g_controls[0].y1 = 100; g_controls[0].x2 = 300; g_controls[0].y2 = 140; byte colors[ 24 ] = { 50, 50, 50, 1, 50, 50, 50, 1, 50, 50, 50, 1, 200, 200, 200, 1, 220, 220, 220, 1, 180, 180, 180, 1, }; memcpy( g_controls[0].fgColorN, colors, 24 ); strcpy( g_controls[0].text, "Spēlēt" ); win_ctl_updated( 0, WCU_EVERYTHING ); g_controls[1].type = WCTL_BUTTON; g_controls[1].x1 = 100; g_controls[1].y1 = 200; g_controls[1].x2 = 300; g_controls[1].y2 = 240; byte colors2[ 24 ] = { 50, 30, 30, 1, 60, 40, 40, 1, 70, 50, 50, 1, 190, 190, 210, 1, 210, 210, 230, 1, 170, 170, 190, 1, }; memcpy( g_controls[1].fgColorN, colors2, 24 ); strcpy( g_controls[1].text, "Instalēt" ); win_ctl_updated( 1, WCU_EVERYTHING ); /////////////////////////////////////////////////// #endif vl_set( &g_RS.varlist, strlitlen( "_action" ), strlitlen( "init" ) ); rsl_run( &g_RS ); vl_set( &g_RS.varlist, strlitlen( "_action" ), strlitlen( "" ) ); runner_apply_changes(); while( win_process( 0 ) ); rsl_destroy( &g_RS ); fs_free(); win_destroy(); return 0; }
/** * This function is the window event handler for frame widgets. * It handles all events sent to the windows composing the widget. * * \param win Window receiving the event. * \param type The event type. * \param data Custom data, depending on event type. * * \return True if the event was recognized and accepted. */ static bool wtk_frame_handler(struct win_window *win, enum win_event_type type, void const *data) { /* Custom data for windows of a widget points back to the widget itself. */ struct wtk_frame *frame = (struct wtk_frame *)win_get_custom_data(win); switch (type) { case WIN_EVENT_DRAW: { /* For DRAW events, the data parameter points to the * clipping region. */ struct win_clip_region const *clip = (struct win_clip_region const *)data; struct win_area const *area = win_get_area(win); /* Draw frame decorations if this is the container window. */ if (win == frame->container) { /* Draw left border. */ gfx_draw_filled_rect(clip->origin.x, clip->origin.y, WTK_FRAME_LEFTBORDER, area->size.y, WTK_FRAME_BORDER_COLOR); /* Draw right border. */ gfx_draw_filled_rect(clip->origin.x + area->size.x - WTK_FRAME_RIGHTBORDER, clip->origin.y, WTK_FRAME_RIGHTBORDER, area->size.y, WTK_FRAME_BORDER_COLOR); /* Draw top border. */ gfx_draw_filled_rect(clip->origin.x + WTK_FRAME_LEFTBORDER, clip->origin.y, area->size.x - WTK_FRAME_LEFTBORDER - WTK_FRAME_RIGHTBORDER, WTK_FRAME_TOPBORDER, WTK_FRAME_BORDER_COLOR); /* Draw bottom border. */ gfx_draw_filled_rect(clip->origin.x + WTK_FRAME_LEFTBORDER, clip->origin.y + area->size.y - WTK_FRAME_BOTTOMBORDER, area->size.x - WTK_FRAME_LEFTBORDER - WTK_FRAME_RIGHTBORDER, WTK_FRAME_BOTTOMBORDER, WTK_FRAME_BORDER_COLOR); /* Draw title bar background. */ gfx_draw_filled_rect(clip->origin.x + WTK_FRAME_LEFTBORDER, clip->origin.y + WTK_FRAME_TOPBORDER, area->size.x - WTK_FRAME_LEFTBORDER - WTK_FRAME_RIGHTBORDER, WTK_FRAME_TITLEBAR_HEIGHT, WTK_FRAME_TITLEBAR_COLOR); /* Draw caption string. */ gfx_draw_string(frame->caption, clip->origin.x + WTK_FRAME_LEFTBORDER + WTK_FRAME_CAPTION_X, clip->origin.y + WTK_FRAME_TOPBORDER + WTK_FRAME_CAPTION_Y, &sysfont, GFX_COLOR_TRANSPARENT, WTK_FRAME_CAPTION_COLOR); } /* Draw resize handle if this is the resize window. */ else if (win == frame->resize) { gfx_draw_filled_circle(clip->origin.x + area->size.x - 1, clip->origin.y + area->size.y - 1, WTK_FRAME_RESIZE_RADIUS, WTK_FRAME_RESIZE_COLOR, GFX_QUADRANT1); } /* Always accept DRAW events, as the return value is * ignored anyway for that event type. */ return true; } case WIN_EVENT_POINTER: { /* For POINTER events, the data parameter points to the * pointer event information. */ struct win_pointer_event const *event = (struct win_pointer_event const *)data; /* Handle move if this is the container window. */ if (win == frame->container) { switch (event->type) { case WIN_POINTER_PRESS: wtk_handle_frame_press(frame, event); break; case WIN_POINTER_MOVE: wtk_handle_frame_move(frame, event); break; case WIN_POINTER_RELEASE: wtk_handle_frame_release(frame, event); break; default: break; } } /* Handle resize if this is the resize handle. */ else if (win == frame->resize) { switch (event->type) { case WIN_POINTER_PRESS: wtk_handle_resize_press(frame, event); break; case WIN_POINTER_MOVE: wtk_handle_resize_move(frame, event); break; case WIN_POINTER_RELEASE: wtk_handle_resize_release(frame, event); break; default: break; } } /* Accept all POINTER events so that it does not * propagate up the window tree to our parent in case * we did not click anything useful inside the frame. */ return true; } case WIN_EVENT_DESTROY: { /* When the container window is destroyed, also destroy * the rest of the non-window frame allocations. */ if (win == frame->container) { /* Memory allocated for windows will be * automatically destroyed by the window * system. We must destroy other allocations. */ membag_free(frame->caption); membag_free(frame); } /* Always accept DESTROY events, as the return value is * ignored anyway for that event type. */ return true; } case WIN_EVENT_COMMAND: { /* When commands are received either directly or * propagated from child widgets and windows, send it * to the frame handler. */ if (win == frame->container) { if (frame->frame_handler) { /* If the frame handler returns true, * it wants us to destroy the frame. * This is normally used by CLOSE * buttons. */ bool shouldDestroy = frame->frame_handler(frame, (win_command_t) data); /* It is safe to destroy it here, since * the event handling finished right * after this handler returns, and no * other references to this frame or * its contents will be done. */ if (shouldDestroy) { win_destroy(frame->container); } /* Accept the event if there was a * handler installed. */ return true; } } /* Reject the event if there was no handler, or this * was not the container window at all. */ return false; } default: /* Reject unknown event types. */ return false; } }
/** * This function creates a new frame widget. It allocates required memory and * intializes necessary windows to create the widget. If there is not enough * memory, the function returns NULL. * * To destroy the widget and all its contents, and free its memory, call * win_destroy() on the frame's child reference, given by wtk_frame_as_child(), * like this: "win_destroy(wtk_frame_as_child(my_frame_ptr));". * The frame's internal area will equal the area parameter, but the total * extents will be slightly larger, to accommodate for titlebar, borders etc. * * \param parent Parent window. * \param area Area of the internal contents. * \param caption Pointer to caption string. Will be copied into widget. * \param allow_resize True if resize handle should be included on the frame. * \param frame_handler Optional command event handler, for applications. * \param custom_data Optional custom data link, for applications. * * \return Pointer to frame, or NULL if failed. */ struct wtk_frame *wtk_frame_create(struct win_window *parent, struct win_area const *area, char const *caption, bool allow_resize, wtk_frame_handler_t frame_handler, void *custom_data) { struct win_attributes attr; struct wtk_frame *frame; Assert(area); Assert(caption); Assert(parent); /* Allocate memory for frame control data. */ frame = membag_alloc(sizeof(struct wtk_frame)); if (!frame) { goto outofmem_frame; } frame->state = WTK_FRAME_NORMAL; frame->frame_handler = frame_handler; frame->custom_data = custom_data; /* Allocate memory for caption string, and copy text. */ frame->caption = membag_alloc((strlen(caption) + 1) * sizeof(char)); if (!frame->caption) { goto outofmem_caption; } wtk_copy_string(frame->caption, caption); /* Start with valid area info, but only contents frame will keep the * original area. The other frames will be resized properly at the end. * All windows have the same event handler, and the same link back to * the widget object. */ attr.area = *area; attr.event_handler = wtk_frame_handler; attr.custom = frame; /* Prepare container frame, which will contain title bar, border, size, * handle etc. */ attr.background = NULL; attr.behavior = WIN_BEHAVIOR_RAISE_ON_PRESS; /* Create the container window, the proper size will be set later. */ frame->container = win_create(parent, &attr); if (!frame->container) { goto outofmem_container; } /* Prepare the contents frame, which will contain whatever controls * owned by the frame. Size will be equal to the given area parameter. */ attr.area.pos.x = WTK_FRAME_LEFTBORDER; attr.area.pos.y = WTK_FRAME_TOPBORDER + WTK_FRAME_TITLEBAR_HEIGHT; attr.background = &wtk_frame_background; attr.behavior = 0; frame->contents = win_create(frame->container, &attr); if (!frame->contents) { goto outofmem_contents; } /* Only create resize handle window if resize is allowed. */ if (allow_resize) { /* Prepare resize handle. Proper position will be set later. * Size is set here, though. */ attr.area.size.x = WTK_FRAME_RESIZE_WIDTH; attr.area.size.y = WTK_FRAME_RESIZE_HEIGHT; attr.background = NULL; attr.behavior = 0; frame->resize = win_create(frame->container, &attr); if (!frame->resize) { goto outofmem_resize; } win_show(frame->resize); } else { frame->resize = NULL; } /* Now, resize and rearrange according to size of contents frame, which * is equal to the given area parameter. */ wtk_resize_frame(frame, area); /* Make sure internals are visible when frame is mapped. */ win_show(frame->contents); return frame; outofmem_resize: win_destroy(frame->contents); outofmem_contents: win_destroy(frame->container); outofmem_container: membag_free(frame->caption); outofmem_caption: membag_free(frame); outofmem_frame: return NULL; }
/** * \brief Setup widget demo * * This function launches the widget demo. */ void app_widget_launch() { struct win_window *win_root; struct win_window *parent; struct win_area area; struct wtk_label *lbl; struct wtk_button *btn; /* Get pointer to root window */ win_root = win_get_root(); /* Application frame */ /* Create a background bitmap using a solid color. */ frame_background.type = GFX_BITMAP_SOLID; frame_background.data.color = APP_BACKGROUND_COLOR; /* Set the area to fill the entire screen */ area.pos.x = 0; area.pos.y = 0; area.size.x = gfx_get_width(); area.size.y = gfx_get_height(); /* * Create a basic frame with a specified background and command event * handler. Check the return value if an error occurred while creating * the widget. */ main_frame = wtk_basic_frame_create(win_root, &area, &frame_background, NULL, widget_frame_command_handler, NULL); if (!main_frame) { goto error_frame; } /* Get a pointer to the widget's window for adding sub-widgets. */ parent = wtk_basic_frame_as_child(main_frame); /* * Draw the frame by showing the frame widget's window. Any * child-widgets and windows will not be shown before the parent * widget/window is shown. */ win_show(parent); /* Application label */ area.pos.x = LABEL_POS_X; area.pos.y = LABEL_POS_Y; /* Find an optimal size for the widget. */ wtk_label_size_hint(&area.size, demo_string); /* * Create the label and check the return value if an error occurred * while creating the label. */ lbl = wtk_label_create(parent, &area, demo_string, GFX_COLOR(255, 255, 255), NULL, false); if (!lbl) { goto error_widget; } /* Draw the label by showing the label widget's window. */ win_show(wtk_label_as_child(lbl)); /* Application slider */ area.pos.x = SLIDER_POS_X; area.pos.y = SLIDER_POS_Y; area.size.x = SLIDER_SIZE_X; area.size.y = SLIDER_SIZE_Y; /* * Create the slider and check the return value if an error occurred * while creating the slider. */ slider = wtk_slider_create(parent, &area, SLIDER_MAX_VALUE, SLIDER_MAX_VALUE / 2, WTK_SLIDER_HORIZONTAL | WTK_SLIDER_CMD_RELEASE, (win_command_t)SLIDER_ID); if (!slider) { goto error_widget; } /* Draw the slider by showing the slider widget's window. */ win_show(wtk_slider_as_child(slider)); /* Application progress bar, placed right of the slider. */ area.pos.x += area.size.x + SLIDER_PB_SPACING_X; area.size.x = PB_SIZE_X; area.size.y = PB_SIZE_Y; /* * Create the progress bar and check the return value if an error * occurred while creating the progress bar. */ progress_bar = wtk_progress_bar_create(parent, &area, SLIDER_MAX_VALUE, SLIDER_MAX_VALUE / 2, GFX_COLOR(255, 255, 0), GFX_COLOR(90, 90, 90), WTK_PROGRESS_BAR_HORIZONTAL); if (!progress_bar) { goto error_widget; } /* Draw the progress bar by showing the progress bar widget's window. */ win_show(wtk_progress_bar_as_child(progress_bar)); /** \todo Add code to set up button here. */ /** \todo Add code to set up basic frame here. */ return; error_widget: /* Destroy widget and all sub-widgets. */ win_destroy(wtk_basic_frame_as_child(main_frame)); error_frame: /* Wait forever if an error occurred during setup. */ while (1) { } }