diff --git a/source/include/gfx/default/wtk.h b/source/include/gfx/default/wtk.h index 66640b1..0fbb231 100644 --- a/source/include/gfx/default/wtk.h +++ b/source/include/gfx/default/wtk.h @@ -365,6 +365,78 @@ typedef uint8_t wtk_radio_group_size_t; //! @} +/** + * \ingroud gfx_wtk_dialogue_box + * @{ + */ + +#ifndef DIALOGUE_FRAME_POS_X +//! Dialogue box frame X position inside parent frame. +#define DIALOGUE_FRAME_POS_X 40 +#endif + +#ifndef DIALOGUE_FRAME_POS_Y +//! Dialogue box frame Y position inside parent frame. +#define DIALOGUE_FRAME_POS_Y 50 +#endif + +#ifndef DIALOGUE_FRAME_SIZE_X +//! Dialogue box horisontal size X. +#define DIALOGUE_FRAME_SIZE_X 240 +#endif + +#ifndef DIALOGUE_FRAME_SIZE_Y +//! Dialogue box vertical size Y. +#define DIALOGUE_FRAME_SIZE_Y 120 +#endif + +#ifndef BUTTON_POS_Y +//! Buttons Y position inside dialogue box frame. +#define BUTTON_POS_Y 60 +#endif + +#ifndef BUTTON_SIZE_X +//! Buttons horisontal size X. +#define BUTTON_SIZE_X 90 +#endif + +#ifndef BUTTON_SIZE_Y +//! Buttons vertical size Y. +#define BUTTON_SIZE_Y 40 +#endif + +#ifndef BUTTON_SPACING +//! Horisontal spacing between buttons on X axis. +#define BUTTON_SPACING 20 +#endif + +#ifndef DIALOGUE_BOX_BACKGROUND +//! Background color of dialogue box frame. +#define DIALOGUE_BOX_BACKGROUND GFX_COLOR(100, 100, 100) +#endif + +#ifndef DIALOGUE_FRAME_LINE_COLOR +//! Line color of the dialogue gox frame. +#define DIALOGUE_FRAME_LINE_COLOR GFX_COLOR(0, 0, 0) +#endif + +#ifndef CAPTION_POS_X +//! Caption position centered on top of dialogue box by dividing size in half. +#define CAPTION_POS_X DIALOGUE_FRAME_SIZE_X / 2 +#endif + +#ifndef CAPTION_POS_Y +//! Caption distance down from top of dialogue box. +#define CAPTION_POS_Y 10 +#endif + +//! Second caption position centered on top of dialogue box. +#define SECOND_CAPTION_POS_X CAPTION_POS_X +//! Second caption distance down from top of dialogue box. +#define SECOND_CAPTION_POS_Y 40 + +//! @} + //! @} #endif /* DEFAULT_WTK_H_INCLUDED */ diff --git a/source/include/gfx/wtk.h b/source/include/gfx/wtk.h index 85493ea..e30ea33 100644 --- a/source/include/gfx/wtk.h +++ b/source/include/gfx/wtk.h @@ -58,6 +58,7 @@ * - \ref gfx_wtk_radio_button * - \ref gfx_wtk_slider * - \ref gfx_wtk_label + * - \ref gfx_wtk_dialogue_box * @{ */ @@ -343,6 +344,29 @@ bool wtk_progress_bar_set_value(struct wtk_progress_bar *bar, uint8_t value); void wtk_progress_bar_set_colors(struct wtk_progress_bar *bar, gfx_color_t color1, gfx_color_t color2); + +struct win_window *wtk_dialogue_box_create(struct win_window *parent, + char *caption, char *second_caption, win_command_t command_data); + + +/** +* \defgroup gfx_wtk_dialogue_box Dialogue box widget +* +* Dialogue box widget provides storage structs for dialogue +* captions and command data. +* +* @{ +*/ +struct wtk_dialogue_box; + +struct win_window *wtk_dialogue_box_create(struct win_window *parent, +char *caption, char *second_caption, win_command_t command_data); + +struct win_window *wtk_dialogue_box_as_child( + struct wtk_dialogue_box *dialogue_box); +void *wtk_dialogue_box_get_custom_data( + const struct wtk_dialogue_box *dialogue_box); + //! @} diff --git a/source/util/gfx/subdir.mk b/source/util/gfx/subdir.mk index d23be97..61414de 100644 --- a/source/util/gfx/subdir.mk +++ b/source/util/gfx/subdir.mk @@ -16,5 +16,6 @@ src-$(CONFIG_GFX_WTK) += util/gfx/wtk_label.c src-$(CONFIG_GFX_WTK) += util/gfx/wtk_progress_bar.c src-$(CONFIG_GFX_WTK) += util/gfx/wtk_radio_button.c src-$(CONFIG_GFX_WTK) += util/gfx/wtk_slider.c +src-$(CONFIG_GFX_WTK) += util/gfx/wtk_dialogue_box.c mkfiles += $(src)/util/gfx/subdir.mk diff --git a/source/util/gfx/wtk_dialogue_box.c b/source/util/gfx/wtk_dialogue_box.c new file mode 100644 index 0000000..a5973be --- /dev/null +++ b/source/util/gfx/wtk_dialogue_box.c @@ -0,0 +1,438 @@ +/** + * \file + * + * \brief Dialogue box widget implementation + * + * Copyright (C) 2010 Atmel Corporation. All rights reserved. + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel AVR product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ +#include +#include +#include +#include +#include +#include + +/** + * \ingroup gfx_wtk_dialogue_box + * @{ + */ + +/** + * \brief Event command ID for the component widgets. + * + * \note The command IDs cannot be 0, since this value is reserved for no + * command event callback for certain widgets. + * + * \param BUTTON_OK_ID defines command ID for events regarding accepting dialogue + * \param BUTTON_CANCEL_ID defines command ID for events regarding aborting dialogue + */ +enum app_widget_ids { + //! Event command ID for the OK button. + BUTTON_OK_ID = 1, + //! Event command ID for the Cancel button. + BUTTON_CANCEL_ID = 2, +}; + + +/** + * \brief Dialogue box control struct + * + * This is the dialogue box control struct. It contains references to the window + * composing the dialogue box, as well as non-window information required. + * + * \internal + * \note Structure fields are only internally accessible, only pointers to + * structure is needed externally + * + * \param caption stores top string in dialogue box frame. + * \param second_caption stores bottom string in dialogue box frame. + * \param command_data command data is aquired from the function call + * creating the dialogue command data for queuing when + * the OK command is initiated when queued, the parent + * command handler will execute the functions. + * + */ +struct wtk_dialogue_box { + //! Copy of top caption string. + char *caption; + //! Copy of bottom caption string. + char *second_caption; + + //! Stores custom command data, used when "OK" is clicked. + win_command_t command_data; +}; + + +/** + * \brief Dialogue box command events handler + * + * This function handles the command events generated by the widgets. + * + * \see wtk_basic_frame_command_handler_t + * + * \param *frame Pointer to dialogue box frame. + * \param command_data Command data for dialogue box. + */ +static bool dialogue_box_command_handler(struct wtk_basic_frame *frame, + win_command_t command_data) +{ + char command = (char)(uintptr_t)command_data; + + struct wtk_dialogue_box *dialogue_box; + dialogue_box = (struct wtk_dialogue_box*) + wtk_basic_frame_get_custom_data(frame); + + struct win_window *dialogue_win = + win_get_parent(wtk_basic_frame_as_child(frame)); + + struct win_window *dialogue_parent = + win_get_parent(dialogue_win); + + struct win_command_event send_command; + + switch (command) { + + case BUTTON_OK_ID: + + /* Send the supplied command event to the frame from + * which the dialogue box originated + */ + + send_command.sender = dialogue_parent; + send_command.recipient = dialogue_parent; + send_command.data = dialogue_box->command_data; + + // Queues the command + win_queue_command_event(&send_command); + + // free memory of captions, buttons, frame, and box. + win_destroy(dialogue_win); + + break; + + case BUTTON_CANCEL_ID: + + // free memory of captions, buttons, frame, and box. + win_destroy(dialogue_win); + + break; + } + + return false; +} + +/** + * \brief Dialogue box frame draw event handler + * + * This function will draw the border of the dialogue box. + * + * \see wtk_basic_frame_draw_handler_t + */ +static void dialogue_box_draw_handler(struct win_window *win, + struct win_clip_region const *clip) +{ + // Draw the border rectangle for the dialogue box frame + gfx_draw_rect(DIALOGUE_FRAME_POS_X, DIALOGUE_FRAME_POS_Y, + + DIALOGUE_FRAME_SIZE_X, DIALOGUE_FRAME_SIZE_Y, + DIALOGUE_FRAME_LINE_COLOR); + +} + + +/** + * \brief Dialogue box event handler + * + * This function is the window event handler for dialogue box 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. False if event failed. + */ +static bool wtk_dialogue_box_event_handler(struct win_window *win, + enum win_event_type type, const void *data) +{ + // Custom data for windows of a widget points back to the widget itself. + struct wtk_dialogue_box *dialogue_box; + + dialogue_box = win_get_custom_data(win); + + switch (type) { + case WIN_EVENT_DRAW: + /* For DRAW events, the data parameter points to the + * clipping region. + */ + + /* Always accept DRAW events, as the return value is + * ignored anyway for that event type. + */ + return true; + + case WIN_EVENT_POINTER: + /* 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 frame window is destroyed, also destroy + * the rest of the non-window frame allocations. + */ + membag_free(dialogue_box); + + + /* Always accept DESTROY events, as the return value is + * ignored anyway for that event type. + */ + return true; + + default: + // Reject unknown event types. + return false; + + } +} + + + +/** + * \brief Create dialogue box widget + * + * This function creates a new dialogue box 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 basic frame's child reference, given by + * wtk_basic_frame_as_child(), like this: + * "win_destroy(wtk_basic_frame_as_child(my_frame_ptr));". + * + * \param *parent Parent window. + * \param *caption Text for upper label. + * \param *second_caption Text for below label. + * \param *command_data Pointer to command aquired from create dialogue function + * External command is executed when "OK" button is clicked. + * \param attr Aquires and contains all variables for managing the window. + * \param dialogue_background Pointer to background bitmap for frame. NULL for + * transparent background. When background is transparent + * the parent window will automatically be redrawn + * when the basic frame is drawn. + * + * \param *dialogue_window Is the window for the dialogue box. + * \param *dialogue_frame Basic frame container for dialogue box inside dialogue_window + * \param *dialogue_struct Stores the unique captions and command data + * \param *button_ok Pointer to button widget for the "OK" button. + * \param *button_cancel Pointer to button widget for the "Cancel" button. + * \param area Holds variables used in sizeing the widgets. + * + * \param dialogue_box_draw_handler Handler for drawing part of the dialogue box + * \param dialogue_box_command_handler Handler for commands used by the dialogue box. + * + * \return Pointer to dialogue box frame, or NULL if it failed. + */ +struct win_window *wtk_dialogue_box_create(struct win_window *parent, + char *caption, char *second_caption, win_command_t command_data) +{ + struct win_attributes attr; + struct gfx_bitmap dialogue_background; + struct win_window *dialogue_window; + struct wtk_basic_frame *dialogue_frame; + struct wtk_dialogue_box *dialogue_struct; + struct wtk_button *button_ok, *button_cancel; + struct wtk_label *label; + struct wtk_label *second_label; + struct win_area area; + + assert(area); + assert(parent); + + + // Allocate memory for dialogue box data. + dialogue_struct = membag_alloc(sizeof(struct wtk_dialogue_box)); + if (!dialogue_struct) { + goto outofmem_dialogue_struct; + } + + /** + * Sets up the container window, making it as large as the screen to + * absorb pointer events. + */ + area.pos.x = 0; + area.pos.y = 0; + area.size.x = gfx_get_width(); + area.size.y = gfx_get_height(); + + attr.area = area; + attr.event_handler = wtk_dialogue_box_event_handler; + attr.custom = dialogue_struct; + attr.background = NULL; + attr.behavior = 0; + + // Creates the dialogue box window. + dialogue_window = win_create(parent, &attr); + if (!dialogue_window) { + goto outofmem_win; + } + + // Stores the custom captions and command data to the dialogue struct. + dialogue_struct->command_data = command_data; + dialogue_struct->caption = caption; + dialogue_struct->second_caption = second_caption; + + /** + * Sets up the size of the dialogue box frame. + */ + area.pos.x = DIALOGUE_FRAME_POS_X; + area.pos.y = DIALOGUE_FRAME_POS_Y; + area.size.x = DIALOGUE_FRAME_SIZE_X; + area.size.y = DIALOGUE_FRAME_SIZE_Y; + + // Gives the frame background its background color. + dialogue_background.type = BITMAP_SOLID; + dialogue_background.data.color = DIALOGUE_BOX_BACKGROUND; + + + // Creates the basic frame that forms the dialogue box frontend. + dialogue_frame = wtk_basic_frame_create(dialogue_window, &area, + &dialogue_background, dialogue_box_draw_handler, + dialogue_box_command_handler, dialogue_struct); + if (!dialogue_frame) { + goto error_widget; + } + + /** + * Creating labels. + */ + + // Find an optimal size for the widget from caption string size. + wtk_label_size_hint(&area.size, caption); + + // Centers the caption string inside dialogue box frame. + area.pos.x = CAPTION_POS_X - area.size.x / 2; + // Height of caption string inside dialogue box frame. + area.pos.y = CAPTION_POS_Y; + + /* + * Create the upper label and check the return value if an error occured + * while creating the label. + */ + label = wtk_label_create(wtk_basic_frame_as_child(dialogue_frame), + &area, dialogue_struct->caption, false); + if (!label) { + goto error_widget; + } + + //! Find an optimal size for the widget from second caption string size. + wtk_label_size_hint(&area.size, second_caption); + + // Centers the caption string inside dialogue box frame. + area.pos.x = SECOND_CAPTION_POS_X - area.size.x / 2; + // Height of caption string inside dialogue box frame. + area.pos.y = SECOND_CAPTION_POS_Y; + + + /* + * Create the lower label and check the return value if an error occured + * while creating the label. + */ + second_label = wtk_label_create(wtk_basic_frame_as_child(dialogue_frame), + &area, dialogue_struct->second_caption, false); + if (!label) { + goto error_widget; + } + + + /* + * Centers the buttons in the dialogue box frame and spaces them apart + * from each other. + * + */ + + area.pos.x = DIALOGUE_FRAME_SIZE_X / 2 - BUTTON_SIZE_X - BUTTON_SPACING / 2; + area.pos.y = BUTTON_POS_Y; + area.size.x = BUTTON_SIZE_X; + area.size.y = BUTTON_SIZE_Y; + + // Creates the OK button with the OK command ID. + button_ok = wtk_button_create(wtk_basic_frame_as_child(dialogue_frame), + &area, "OK", (win_command_t)BUTTON_OK_ID); + if (!button_ok) { + goto error_widget; + } + + + /* Centers the buttons in the dialogue box frame and spaces them apart + * from each other. + */ + + area.pos.x = DIALOGUE_FRAME_SIZE_X / 2 + BUTTON_SPACING / 2; + area.pos.y = BUTTON_POS_Y; + + // Creates the Cancel button with the Cancel command ID. + button_cancel = wtk_button_create(wtk_basic_frame_as_child(dialogue_frame), + &area, "Cancel", (win_command_t)BUTTON_CANCEL_ID); + if (!button_ok) { + goto error_widget; + } + + // Draw the basic frame. + win_show(wtk_basic_frame_as_child(dialogue_frame)); + + // Draw the labels by showing the label widget's window. + win_show(wtk_label_as_child(label)); + win_show(wtk_label_as_child(second_label)); + + // Draw the labels by showing the label widget's window. + win_show(wtk_button_as_child(button_ok)); + win_show(wtk_button_as_child(button_cancel)); + + // Draw the window, showing the dialogue box. + win_show(dialogue_window); + + // Returns the dialogue box window to the function call. + return dialogue_window; + + +error_widget: + win_destroy(dialogue_window); +outofmem_win: + membag_free(dialogue_struct); +outofmem_dialogue_struct: + return NULL; +} + +//! @}