New simplified gwin using a pseudo class structure.

ugfx_release_2.6
inmarket 2013-06-06 14:33:32 +10:00
parent eebecad9f7
commit 7baf5c5d44
20 changed files with 1651 additions and 1319 deletions

View File

@ -0,0 +1,65 @@
/*
* This file has a different license to the rest of the GFX system.
* You can copy, modify and distribute this file as you see fit.
* You do not need to publish your source modifications to this file.
* The only thing you are not permitted to do is to relicense it
* under a different license.
*/
#ifndef _GFXCONF_H
#define _GFXCONF_H
#define GFX_USE_OS_CHIBIOS TRUE
//#define GFX_USE_OS_WIN32 TRUE
//#define GFX_USE_OS_POSIX TRUE
/* GFX sub-systems to turn on */
#define GFX_USE_GDISP TRUE
#define GFX_USE_GWIN TRUE
#define GFX_USE_GEVENT TRUE
#define GFX_USE_GTIMER TRUE
#define GFX_USE_GINPUT TRUE
/* Features for the GDISP sub-system. */
#define GDISP_NEED_VALIDATION TRUE
#define GDISP_NEED_CLIP TRUE
#define GDISP_NEED_TEXT TRUE
#define GDISP_NEED_CIRCLE TRUE
#define GDISP_NEED_ELLIPSE TRUE
#define GDISP_NEED_ARC TRUE
#define GDISP_NEED_CONVEX_POLYGON TRUE
#define GDISP_NEED_SCROLL FALSE
#define GDISP_NEED_PIXELREAD FALSE
#define GDISP_NEED_CONTROL FALSE
#define GDISP_NEED_IMAGE TRUE
#define GDISP_NEED_MULTITHREAD TRUE
#define GDISP_NEED_ASYNC FALSE
#define GDISP_NEED_MSGAPI FALSE
/* Builtin Fonts */
#define GDISP_INCLUDE_FONT_SMALL FALSE
#define GDISP_INCLUDE_FONT_LARGER FALSE
#define GDISP_INCLUDE_FONT_UI1 FALSE
#define GDISP_INCLUDE_FONT_UI2 TRUE
#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE
/* GDISP image decoders */
#define GDISP_NEED_IMAGE_NATIVE FALSE
#define GDISP_NEED_IMAGE_GIF TRUE
#define GDISP_NEED_IMAGE_BMP FALSE
#define GDISP_NEED_IMAGE_JPG FALSE
#define GDISP_NEED_IMAGE_PNG FALSE
/* Features for the GWIN sub-system. */
#define GWIN_NEED_CONSOLE TRUE
#define GWIN_NEED_GRAPH FALSE
#define GWIN_NEED_BUTTON TRUE
#define GWIN_NEED_SLIDER TRUE
#define GWIN_NEED_CHECKBOX TRUE
/* Features for the GINPUT sub-system. */
#define GINPUT_NEED_MOUSE TRUE
#define GINPUT_NEED_TOGGLE FALSE
#define GINPUT_NEED_DIAL FALSE
#endif /* _GFXCONF_H */

View File

@ -0,0 +1,141 @@
/*
ChibiOS/GFX - Copyright (C) 2012, 2013
Joel Bodenmann aka Tectu <joel@unormal.org>
This file is part of ChibiOS/GFX.
ChibiOS/GFX is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/GFX is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "gfx.h"
static GListener gl;
static GHandle ghConsole;
static GHandle ghButton1, ghButton2, ghButton3, ghButton4;
static GHandle ghSlider1, ghSlider2, ghSlider3, ghSlider4;
static GHandle ghCheckbox1, ghCheckbox2;
#define ScrWidth gdispGetWidth()
#define ScrHeight gdispGetHeight()
#define BUTTON_WIDTH 50
#define BUTTON_HEIGHT 30
#define SLIDER_WIDTH 10
#define CHECKBOX_WIDTH 80
#define CHECKBOX_HEIGHT 20
int main(void) {
GEvent * pe;
// Initialize the display
gfxInit();
gdispClear(White);
// Set the font
gwinSetDefaultFont(gdispOpenFont("UI2"));
// Create out gwin windows/widgets
ghButton1 = gwinCreateButton(NULL, 0+0*(BUTTON_WIDTH+1), 0, BUTTON_WIDTH, BUTTON_HEIGHT);
ghButton2 = gwinCreateButton(NULL, 0+1*(BUTTON_WIDTH+1), 0, BUTTON_WIDTH, BUTTON_HEIGHT);
ghButton3 = gwinCreateButton(NULL, 0+2*(BUTTON_WIDTH+1), 0, BUTTON_WIDTH, BUTTON_HEIGHT);
ghButton4 = gwinCreateButton(NULL, 0+3*(BUTTON_WIDTH+1), 0, BUTTON_WIDTH, BUTTON_HEIGHT);
ghConsole = gwinCreateConsole(NULL, ScrWidth/2+1, ScrHeight/2+1, ScrWidth/2-1, ScrHeight/2-1);
ghSlider1 = gwinCreateSlider(NULL, ScrWidth/2+1, ScrHeight/2-2*(SLIDER_WIDTH+1), ScrWidth/2-2, SLIDER_WIDTH);
ghSlider2 = gwinCreateSlider(NULL, ScrWidth/2+1, ScrHeight/2-1*(SLIDER_WIDTH+1), ScrWidth/2-2, SLIDER_WIDTH);
ghSlider3 = gwinCreateSlider(NULL, 0+1*(SLIDER_WIDTH+1), ScrHeight/2+1, SLIDER_WIDTH, ScrHeight/2-2);
ghSlider4 = gwinCreateSlider(NULL, 0+1*(SLIDER_WIDTH+1), ScrHeight/2+1, SLIDER_WIDTH, ScrHeight/2-2);
ghCheckbox1 = gwinCreateCheckbox(NULL, 0, BUTTON_HEIGHT+1, CHECKBOX_WIDTH, CHECKBOX_HEIGHT);
ghCheckbox2 = gwinCreateCheckbox(NULL, 0, BUTTON_HEIGHT+1+1*(CHECKBOX_HEIGHT+1), CHECKBOX_WIDTH, CHECKBOX_HEIGHT);
// Color everything
gwinSetColor(ghConsole, Yellow);
gwinSetBgColor(ghConsole, Black);
// Set the text on all the controls
gwinSetText(ghButton1, "B1", FALSE);
gwinSetText(ghButton2, "B2", FALSE);
gwinSetText(ghButton3, "B3", FALSE);
gwinSetText(ghButton4, "B4", FALSE);
gwinSetText(ghSlider1, "S1", FALSE);
gwinSetText(ghSlider2, "S2", FALSE);
gwinSetText(ghSlider3, "S3", FALSE);
gwinSetText(ghSlider4, "S4", FALSE);
gwinSetText(ghCheckbox1, "C1", FALSE);
gwinSetText(ghCheckbox2, "C2", FALSE);
// Assign the mouse and dials to the buttons & sliders etc.
#if GINPUT_NEED_MOUSE
gwinAttachMouse(ghSlider1, 0);
gwinAttachMouse(ghSlider2, 0);
gwinAttachMouse(ghSlider3, 0);
gwinAttachMouse(ghSlider4, 0);
gwinAttachMouse(ghButton1, 0);
gwinAttachMouse(ghButton2, 0);
gwinAttachMouse(ghButton3, 0);
gwinAttachMouse(ghButton4, 0);
gwinAttachMouse(ghCheckbox1, 0);
gwinAttachMouse(ghCheckbox2, 0);
#endif
#if GINPUT_NEED_DIAL
gwinAttachSliderDial(ghSlider1, 0);
gwinAttachSliderDial(ghSlider3, 1);
#endif
// We want to listen for widget events
geventListenerInit(&gl);
gwinAttachListener(ghSlider1, &gl, 0);
gwinAttachListener(ghSlider2, &gl, 0);
gwinAttachListener(ghSlider3, &gl, 0);
gwinAttachListener(ghSlider4, &gl, 0);
gwinAttachListener(ghButton1, &gl, 0);
gwinAttachListener(ghButton2, &gl, 0);
gwinAttachListener(ghButton3, &gl, 0);
gwinAttachListener(ghButton4, &gl, 0);
gwinAttachListener(ghCheckbox1, &gl, 0);
gwinAttachListener(ghCheckbox2, &gl, 0);
// Draw everything on the screen
gwinClear(ghConsole);
gwinDraw(ghSlider1);
gwinDraw(ghSlider2);
gwinDraw(ghSlider3);
gwinDraw(ghSlider4);
gwinDraw(ghButton1);
gwinDraw(ghButton2);
gwinDraw(ghButton3);
gwinDraw(ghButton4);
gwinDraw(ghCheckbox1);
gwinDraw(ghCheckbox2);
while(1) {
// Get an Event
pe = geventEventWait(&gl, TIME_INFINITE);
switch(pe->type) {
case GEVENT_GWIN_BUTTON:
gwinPrintf(ghConsole, "Button %s\n", gwinGetText(((GEventGWinButton *)pe)->button));
break;
case GEVENT_GWIN_SLIDER:
gwinPrintf(ghConsole, "Slider %s=%d\n", gwinGetText(((GEventGWinSlider *)pe)->slider), ((GEventGWinSlider *)pe)->position);
break;
case GEVENT_GWIN_CHECKBOX:
gwinPrintf(ghConsole, "Checkbox %s=%s\n", gwinGetText(((GEventGWinCheckbox *)pe)->checkbox), ((GEventGWinCheckbox *)pe)->isChecked ? "Checked" : "UnChecked");
break;
default:
gwinPrintf(ghConsole, "Unknown %d\n", pe->type);
break;
}
}
return 0;
}

View File

@ -0,0 +1,6 @@
This demo supports input from both a mouse/touch and/or a dial input.
If your platform does not support one or the other, turn it off in
gfxconf.h
Note that you will need to include the drivers into your project
makefile for whichever inputs you decide to use.

View File

@ -24,240 +24,132 @@
#ifndef _GWIN_BUTTON_H #ifndef _GWIN_BUTTON_H
#define _GWIN_BUTTON_H #define _GWIN_BUTTON_H
#if GWIN_NEED_BUTTON || defined(__DOXYGEN__) /* This file is included within "gwin/gwidget.h" */
/*===========================================================================*/ /**
/* Driver constants. */ * @brief The Event Type for a Button Event
/*===========================================================================*/ */
#define GW_BUTTON 0x0002
#define GEVENT_GWIN_BUTTON (GEVENT_GWIN_FIRST+0) #define GEVENT_GWIN_BUTTON (GEVENT_GWIN_FIRST+0)
/*===========================================================================*/ /**
/* Type definitions */ * @brief A Button Event
/*===========================================================================*/ * @note There are currently no GEventGWinButton listening flags - use 0 as the flags to @p gwinAttachListener()
*/
typedef struct GEventGWinButton_t { typedef struct GEventGWinButton {
GEventType type; // The type of this event (GEVENT_GWIN_BUTTON) GEventType type; // The type of this event (GEVENT_GWIN_BUTTON)
GHandle button; // The button that has been depressed (actually triggered on release) GHandle button; // The button that has been depressed (actually triggered on release)
} GEventGWinButton; } GEventGWinButton;
// There are currently no GEventGWinButton listening flags - use 0 /**
* @brief Button colors
typedef enum GButtonShape_e { */
GBTN_3D, GBTN_SQUARE, GBTN_ROUNDED, GBTN_ELLIPSE, GBTN_CUSTOM, typedef struct GButtonColors {
GBTN_ARROW_UP, GBTN_ARROW_DOWN, GBTN_ARROW_LEFT, GBTN_ARROW_RIGHT,
} GButtonShape;
typedef struct GButtonDrawStyle_t {
color_t color_edge; color_t color_edge;
color_t color_fill; color_t color_fill;
color_t color_txt; color_t color_txt;
} GButtonDrawStyle; } GButtonColors;
typedef enum GButtonType_e { /**
GBTN_NORMAL, GBTN_TOGGLE * @brief The button widget structure
} GButtonType; * @note Do not use the members directly - treat it as a black-box.
*/
typedef enum GButtonState_e {
GBTN_UP, GBTN_DOWN
} GButtonState;
typedef void (*GButtonDrawFunction)(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param);
// A button window
typedef struct GButtonObject_t { typedef struct GButtonObject_t {
GWindowObject gwin; GWidgetObject w;
GButtonColors c_up;
GButtonDrawStyle up; GButtonColors c_dn;
GButtonDrawStyle dn; GButtonColors c_dis;
GButtonState state;
GButtonType type;
const char *txt;
GButtonDrawFunction fn;
void *param;
GListener listener;
} GButtonObject; } GButtonObject;
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/** /**
* @brief Create a button window. * @brief Create a button widget.
* @return NULL if there is no resultant drawing area, otherwise a window handle. * @return NULL if there is no resultant drawing area, otherwise a window handle.
* *
* @param[in] gb The GButtonObject structure to initialise. If this is NULL the structure is dynamically allocated. * @param[in] gb The GButtonObject structure to initialise. If this is NULL the structure is dynamically allocated.
* @param[in] x,y The screen co-ordinates for the bottom left corner of the window * @param[in] x,y The screen co-ordinates for the top left corner of the window
* @param[in] width The width of the window * @param[in] width The width of the window
* @param[in] height The height of the window * @param[in] height The height of the window
* @param[in] font The font to use *
* @param[in] type The type of button
* @note The drawing color gets set to White and the background drawing color to Black. * @note The drawing color gets set to White and the background drawing color to Black.
* @note Don't forget to set the font using @p gwinSetFont() or @p gwinSetDefaultFont()
* @note The dimensions and position may be changed to fit on the real screen. * @note The dimensions and position may be changed to fit on the real screen.
* @note The button is not automatically drawn. Call gwinButtonDraw() after changing the button style or setting the text. * @note The button is not automatically drawn. Call gwinDraw() to draw it.
* *
* @api * @api
*/ */
GHandle gwinCreateButton(GButtonObject *gb, coord_t x, coord_t y, coord_t width, coord_t height, font_t font, GButtonType type); GHandle gwinCreateButton(GButtonObject *gb, coord_t x, coord_t y, coord_t width, coord_t height);
/** /**
* @brief Set the style of a button. * @brief Set the colors of a button.
* @details The button style is defined by its shape and colours.
* *
* @param[in] gh The window handle (must be a button window) * @param[in] gh The window handle (must be a button widget)
* @param[in] shape The shape of the button. * @param[in] pUp The colors for the button when in the up state.
* @param[in] pUp The styling for the button when in the up state. * @param[in] pDown The colors for the button when in the down state.
* @param[in] pDown The styling for the button when in the down state. * @param[in] pDisabled The colors for the button when it is disabled.
* *
* @note The button is not automatically redrawn. Call gwinButtonDraw() after changing the button style * @note The button is not automatically redrawn. Call gwinButtonDraw() after changing the button style
* @note The button style is copied into the internal button structure - there is no need to * @note The button style is copied into the internal button structure - there is no need to
* maintain a static style structures. * maintain static style structures (they can be temporary structures on the stack).
* @note The pUp and pDown parameters can be NULL. If they are then the existing color styles * @note The pUp, pDown and pDisabled parameters can be NULL. If they are then the existing color styles
* are not changed for that button state. * are not changed for that button state.
* @note Some custom drawn buttons will ignore he specified colors
* *
* @api * @api
*/ */
void gwinSetButtonStyle(GHandle gh, GButtonShape shape, const GButtonDrawStyle *pUp, const GButtonDrawStyle *pDown); void gwinSetButtonColors(GHandle gh, const GButtonColors *pUp, const GButtonColors *pDown, const GButtonColors *pDisabled);
/** /**
* @brief Set the text of a button. * @brief Is the button current pressed
* @return TRUE if the button is depressed
* *
* @param[in] gh The window handle (must be a button window) * @param[in] gh The window handle (must be a button widget)
* @param[in] txt The button text to set. This must be a constant string unless useAlloc is set.
* @param[in] useAlloc If TRUE the string specified will be copied into dynamically allocated memory.
* @note The button is not automatically redrawn. Call gwinButtonDraw() after changing the button text.
* *
* @api * @api
*/ */
void gwinSetButtonText(GHandle gh, const char *txt, bool_t useAlloc); bool_t gwinIsButtonPressed(GHandle gh);
/** /**
* @brief Redraw the button. * @brief Some custom button drawing routines
* @details These function may be passed to @p gwinSetCustomDraw() to get different button drawing styles
* *
* @param[in] gh The window handle (must be a button window) * @param[in] gw The widget object (in this case a button)
*
* @api
*/
void gwinButtonDraw(GHandle gh);
/**
* @brief Enable or disable a button
*
* @param[in] gh The window handle (must be a button window)
* @param[in] enabled Enable or disable the button
*
* @api
*/
void gwinButtonSetEnabled(GHandle gh, bool_t enabled);
/**
* @brief Set the callback routine to perform a custom button drawing.
*
* @param[in] gh The window handle (must be a button window)
* @param[in] fn The function to use to draw the button
* @param[in] param A parameter to pass to the button drawing function
*
* @api
*/
void gwinSetButtonCustom(GHandle gh, GButtonDrawFunction fn, void *param);
/**
* @brief Enable a button
*
* @api
*/
#define gwinEnableButton(gh) gwinButtonSetEnabled( ((GButtonObject *)(gh)), TRUE)
/**
* @brief Disable a button
*
* @api
*/
#define gwinDisableButton(gh) gwinButtonSetEnabled( ((GButtonObject *)(gh)), FALSE)
/**
* @brief Get the state of a button
*
* @param[in] gh The window handle (must be a button window)
*
* @api
*/
#define gwinGetButtonState(gh) (((GButtonObject *)(gh))->state)
/**
* @brief Get the source handle of a button
* @details Get the source handle of a button so the application can listen for events
*
* @param[in] gh The window handle
*
* @api
*/
#define gwinGetButtonSource(gh) ((GSourceHandle)(gh))
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
/**
* @brief Attach a mouse to a button
*
* @param[in] gh The button handle
* @param[in] instance The mouse instance
*
* @api
*/
bool_t gwinAttachButtonMouse(GHandle gh, uint16_t instance);
#endif
#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
/**
* @brief Attach a toggle to a button
*
* @param[in] gh The button handle
* @param[in] instance The toggle instance
*
* @api
*/
bool_t gwinAttachButtonToggle(GHandle gh, uint16_t instance);
#endif
/**
* @brief Standard button drawing routines
* @details These routines are called to draw the standard button styles.
*
* @param[in] gh The button handle
* @param[in] enabled Is the button currently enabled or disabled
* @param[in] isdown Is the button currently down (depressed)
* @param[in] txt The text to be display inside the button
* @param[in] pstyle The current drawing style for the state we are in
* @param[in] param A parameter passed in from the user * @param[in] param A parameter passed in from the user
* *
* @note In your custom button drawing function you may optionally call these * @note In your custom button drawing function you may optionally call these
* standard functions and then draw your extra details on top. * standard functions and then draw your extra details on top.
* @note The standard functions below ignore the param parameter. It is there * @note The standard functions below ignore the param parameter except for @p gwinButtonDraw_Image().
* only to ensure the functions match the GButtonDrawFunction type. * @note The image custom draw function @p gwinButtonDraw_Image() uses param to pass in the gdispImage pointer.
* @note When called by a button press/release the framework ensure that it is * The image must be already opened before calling @p gwinSetCustomDraw(). The image should be 3
* a button object and sets up clipping to the button object window. These * times the height of the button. The button image is repeated 3 times vertically, the first (top) for
* drawing routines then don't have to worry about explicitly doing that. * the "up" image, the 2nd for the "down" image, and the third (bottom) image for the disabled state. If
* the disabled state is never going to be used then the image can be just 2 times the button height.
* No checking is done to compare the size of the button to the size of the image.
* Note text is drawn on top of the image.
* @note These custom drawing routines don't have to worry about setting clipping as the framework
* sets clipping to the object window prior to calling these routines.
* *
* @api * @api
* @{ * @{
*/ */
void gwinButtonDraw_3D(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param); void gwinButtonDraw_3D(GWidgetObject *gw, void *param); // @< A standard 3D button
void gwinButtonDraw_Square(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param); void gwinButtonDraw_Box(GWidgetObject *gw, void *param); // @< A very simple box style button
#if GDISP_NEED_ARC || defined(__DOXYGEN__) #if GDISP_NEED_ARC || defined(__DOXYGEN__)
void gwinButtonDraw_Rounded(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param); void gwinButtonDraw_Rounded(GWidgetObject *gw, void *param); // @< A rounded rectangle button
#endif #endif
#if GDISP_NEED_ELLIPSE || defined(__DOXYGEN__) #if GDISP_NEED_ELLIPSE || defined(__DOXYGEN__)
void gwinButtonDraw_Ellipse(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param); void gwinButtonDraw_Ellipse(GWidgetObject *gw, void *param); // @< A circular button
#endif #endif
#if GDISP_NEED_CONVEX_POLYGON || defined(__DOXYGEN__) #if GDISP_NEED_CONVEX_POLYGON || defined(__DOXYGEN__)
void gwinButtonDraw_ArrowUp(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param); void gwinButtonDraw_ArrowUp(GWidgetObject *gw, void *param); // @< An up arrow button
void gwinButtonDraw_ArrowDown(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param); void gwinButtonDraw_ArrowDown(GWidgetObject *gw, void *param); // @< A down arrow button
void gwinButtonDraw_ArrowLeft(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param); void gwinButtonDraw_ArrowLeft(GWidgetObject *gw, void *param); // @< A left arrow button
void gwinButtonDraw_ArrowRight(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param); void gwinButtonDraw_ArrowRight(GWidgetObject *gw, void *param); // @< A right arrow button
#endif
#if GDISP_NEED_IMAGE || defined(__DOXYGEN__)
void gwinButtonDraw_Image(GWidgetObject *gw, void *param); // @< An image button - see the notes above on the param.
#endif #endif
/** @} */ /** @} */
@ -265,8 +157,6 @@ void gwinButtonDraw_Square(GHandle gh, bool_t enabled, bool_t isdown, const char
} }
#endif #endif
#endif /* GWIN_NEED_BUTTON */
#endif /* _GWIN_BUTTON_H */ #endif /* _GWIN_BUTTON_H */
/** @} */ /** @} */

View File

@ -12,7 +12,7 @@
* @defgroup Checkbox Checkbox * @defgroup Checkbox Checkbox
* @ingroup GWIN * @ingroup GWIN
* *
* @details GWIN allows it to easily create checkboxes. * @details GWIN allows it to easily create a group of checkbox buttons.
* *
* @pre GFX_USE_GWIN must be set to TRUE in your gfxconf.h * @pre GFX_USE_GWIN must be set to TRUE in your gfxconf.h
* @pre GWIN_NEED_CHECKBOX must be set to TRUE in your gfxconf.h * @pre GWIN_NEED_CHECKBOX must be set to TRUE in your gfxconf.h
@ -22,13 +22,12 @@
#ifndef _GWIN_CHECKBOX_H #ifndef _GWIN_CHECKBOX_H
#define _GWIN_CHECKBOX_H #define _GWIN_CHECKBOX_H
#if GWIN_NEED_CHECKBOX || defined(__DOXYGEN__) /* This file is included within "gwin/gwidget.h" */
/*===========================================================================*/ /*===========================================================================*/
/* Driver constants. */ /* Driver constants. */
/*===========================================================================*/ /*===========================================================================*/
#define GW_CHECKBOX 0x0005
#define GEVENT_GWIN_CHECKBOX (GEVENT_GWIN_FIRST+2) #define GEVENT_GWIN_CHECKBOX (GEVENT_GWIN_FIRST+2)
/*===========================================================================*/ /*===========================================================================*/
@ -41,124 +40,76 @@ typedef struct GEventGWinCheckbox_t {
bool_t isChecked; // Is the checkbox currently checked or unchecked? bool_t isChecked; // Is the checkbox currently checked or unchecked?
} GEventGWinCheckbox; } GEventGWinCheckbox;
typedef enum GCheckboxState_e { typedef struct GCheckboxColors {
GCHBX_UNCHECKED, GCHBX_CHECKED color_t color_border;
} GCheckboxState; color_t color_checked;
color_t color_bg;
typedef struct GCheckboxColor_t { color_t color_txt;
color_t border; } GCheckboxColors;
color_t checked;
color_t bg;
} GCheckboxColor;
/* custom rendering interface */
typedef void (*GCheckboxDrawFunction)(GHandle gh, bool_t enabled, bool_t state, void* param);
/* A Checkbox window */ /* A Checkbox window */
typedef struct GCheckboxObject_t { typedef struct GCheckboxObject_t {
GWindowObject gwin; GWidgetObject w;
GListener listener; GCheckboxColors c;
GCheckboxDrawFunction fn;
GCheckboxColor *colors;
bool_t isChecked;
void *param;
} GCheckboxObject; } GCheckboxObject;
/** /**
* @brief Create a checkbox window. * @brief Create a checkbox window.
* @return NULL if there is no resultant drawing area, otherwise a window handle.
* *
* @param[in] gb The GCheckboxObject structure to initialise. If this is NULL, the structure is dynamically allocated. * @param[in] gb The GCheckboxObject structure to initialise. If this is NULL, the structure is dynamically allocated.
* @param[in] x,y The screen co-ordinates for the bottom left corner of the window * @param[in] x,y The screen co-ordinates for the top left corner of the window
* @param[in] width The width of the window * @param[in] width The width of the window
* @param[in] height The height of the window * @param[in] height The height of the window
* *
* @note The checkbox is not automatically drawn. Call gwinCheckboxDraw() after changing the checkbox style. * @note The drawing color gets set to White and the background drawing color to Black.
* * @note Don't forget to set the font using @p gwinSetFont() or @p gwinSetDefaultFont()
* @return NULL if there is no resultant drawing area, otherwise a window handle. * @note The dimensions and position may be changed to fit on the real screen.
* @note The checkbox is not automatically drawn. Call gwinDraw() to draw it.
* *
* @api * @api
*/ */
GHandle gwinCheckboxCreate(GCheckboxObject *gb, coord_t x, coord_t y, coord_t width, coord_t height); GHandle gwinCreateCheckbox(GCheckboxObject *gb, coord_t x, coord_t y, coord_t width, coord_t height);
/**
* @brief Redraw a checkbox
*
* @param[in] gh The window handle (must be a checkbox window)
*
* @api
*/
void gwinCheckboxDraw(GHandle gh);
/**
* @brief Enable or disable a button
*
* @param[in] gh The window handle (must be a checkbox window)
* @param[in] enabled Enable or disable the button
*
* @api
*/
void gwinCheckboxSetEnabled(GHandle gh, bool_t enabled);
/**
* @brief Set the callback routine to perform a custom drawing.
*
* @param[in] gh The window handle (must be a checkbox window)
* @param[in] fn The function to use to draw the checkbox
* @param[in] param A parameter to pass to the checkbox drawing function
*
* @api
*/
void gwinCheckboxSetCustom(GHandle gh, GCheckboxDrawFunction fn, void *param);
/**
* @brief Enable a checkbox
*
* @api
*/
#define gwinCheckboxEnable(gh) gwinCheckboxSetEnabled( ((GCheckboxObject *)(gh)), TRUE)
/**
* @brief Disable a checkbox
*
* @api
*/
#define gwinCheckboxDisable(gh) gwinCheckboxSetEnabled( ((GCheckboxObject *)(gh)), FALSE)
/** /**
* @brief Get the state of a checkbox * @brief Get the state of a checkbox
* @return TRUE if the checkbox is currently checked
* *
* @param[in] gh The window handle (must be a checkbox window) * @param[in] gh The window handle (must be a checkbox window)
* *
* @return The state of the checkbox (GCHBX_CHECKED or GCHBX_UNCHECKED)
*
* @api * @api
*/ */
#define gwinCheckboxGetState(gh) (((GCheckboxObject *)(gh))->isChecked) bool_t gwinIsCheckboxChecked(GHandle gh);
/** /**
* @brief Get the source handle of a checkbox * @brief Set the colors used to draw the checkbox
* @details Get the source handle of a checkbox so the application can listen for events
* *
* @param[in] gh The window handle (must be a checkbox window) * @param[in] gh The window handle (must be a checkbox window)
* @param[in] pColors The colors to use
* *
* @api * @api
*/ */
#define gwinCheckboxGetSource(gh) ((GSourceHandle)(gh)) void gwinCheckboxSetColors(GHandle gh, GCheckboxColors *pColors);
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE /**
/** * @brief Some custom checkbox drawing routines
* @brief Attach a mouse to a checkbox * @details These function may be passed to @p gwinSetCustomDraw() to get different checkbox drawing styles
* *
* @param[in] gh The checkbox handle * @param[in] gw The widget (which must be a checkbox)
* @param[in] instance The mouse instance * @param[in] param A parameter passed in from the user
* *
* @api * @note In your custom checkbox drawing function you may optionally call this
*/ * standard functions and then draw your extra details on top.
bool_t gwinCheckboxAttachMouse(GHandle gh, uint16_t instance); * @note The standard functions below ignore the param parameter.
#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */ * @note These custom drawing routines don't have to worry about setting clipping as the framework
* sets clipping to the object window prior to calling these routines.
#endif /* _GWIN_NEED_CHECKBOX */ *
* @api
* @{
*/
void gwinCheckboxDraw_CheckOnLeft(GWidgetObject *gw, void *param);
void gwinCheckboxDraw_CheckOnRight(GWidgetObject *gw, void *param);
/* @} */
#endif /* _GWIN_CHECKBOX_H */ #endif /* _GWIN_CHECKBOX_H */
/** @} */ /** @} */

View File

@ -0,0 +1,123 @@
/*
* This file is subject to the terms of the GFX License, v1.0. If a copy of
* the license was not distributed with this file, you can obtain one at:
*
* http://chibios-gfx.com/license.html
*/
/**
* @file include/gwin/class_gwin.h
* @brief GWIN Graphic window subsystem header file.
*
* @defgroup Internal Internal
* @ingroup GWIN
*
* @note These definitions are normally not used by an application program. They are useful
* only if you want to create your own custom GWIN window or widget.
* @note To access these definitions you must include "gwin/class_gwin.h" in your source file.
*
* @{
*/
#ifndef _CLASS_GWIN_H
#define _CLASS_GWIN_H
#if GFX_USE_GWIN || defined(__DOXYGEN__)
/**
* @brief The Virtual Method Table for a GWIN window
* @{
*/
typedef struct gwinVMT {
const char *classname; // @< The GWIN classname
void (*Destroy)(GWindowObject *gh); // @< The GWIN Destroy function (optional)
void (*AfterClear)(GWindowObject *gh); // @< The GWIN After-Clear function (optional)
} gwinVMT;
/* @} */
/**
* @brief The Virtual Method Table for a widget
* @note A widget must have a destroy function. Either use @p _gwidgetDestroy() or use your own function
* which internally calls @p _gwidgetDestroy().
* @note If no MouseDown(), MouseUp() or MouseMove() function is provided, the widget will not accept being attached to a mouse input source.
* @note If no ToggleOn() or ToggleOff() function is provided, the widget will not accept being attached to a toggle input source.
* @note If no DialMove() function is provided, the widget will not accept being attached to a dial input source.
* @note AssignToggle() and AssignDial() enable a widget to handle more than one toggle/dial device attached to the widget.
* For example, a slider might accept two toggles, one for slider-down and one for slider-up.
* The function enables the widget to record that a particular device instance performs each particular role.
* (eg toggle0 = slider-down, toggle1 = slider-up).
* @{
*/
typedef struct gwidgetVMT {
struct gwinVMT g; // @< This is still a GWIN
void (*DefaultDraw) (GWidgetObject *gw, void *param); // @< The default drawing routine (mandatory)
void (*MouseDown) (GWidgetObject *gw, coord_t x, coord_t y); // @< Process mouse down events (optional)
void (*MouseUp) (GWidgetObject *gw, coord_t x, coord_t y); // @< Process mouse up events (optional)
void (*MouseMove) (GWidgetObject *gw, coord_t x, coord_t y); // @< Process mouse move events (optional)
void (*ToggleOff) (GWidgetObject *gw, uint16_t instance); // @< Process toggle off events (optional)
void (*ToggleOn) (GWidgetObject *gw, uint16_t instance); // @< Process toggle on events (optional)
void (*DialMove) (GWidgetObject *gw, uint16_t instance, uint16_t value); // @< Process dial move events (optional)
void (*AllEvents) (GWidgetObject *gw, GEvent *pe); // @< Process all events (optional)
bool_t (*AssignToggle) (GWidgetObject *gw, uint16_t role, uint16_t instance); // @< Test the role and save the toggle instance handle (optional)
bool_t (*AssignDial) (GWidgetObject *gw, uint16_t role, uint16_t instance); // @< Test the role and save the dial instance handle (optional)
} gwidgetVMT;
/* @} */
/**
* @brief The predefined flags for a GWIN and a Widget
* @{
*/
#define GWIN_FLG_DYNAMIC 0x0001 // @< The GWIN structure is allocated
#define GWIN_FLG_WIDGET 0x0002 // @< This is a widget
#define GWIN_FLG_ENABLED 0x0002 // @< The widget is enabled
#define GWIN_FLG_ALLOCTXT 0x0008 // @< The widget text is allocated
#define GWIN_FLG_MOUSECAPTURE 0x0010 // @< The widget has captured the mouse
#define GWIN_FIRST_CONTROL_FLAG 0x0100 // @< Free for GWINs and Widgets to use
/* @} */
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialise (and allocate if necessary) the base GWIN object
*
* @param[in] pgw The GWindowObject structure. If NULL one is allocated from the heap
* @param[in] x, y The top left corner of the GWIN relative to the screen
* @param[in] w, h The width and height of the GWIN window
* @param[in] size The size of the GWIN object to allocate
* @param[in] vmt The virtual method table for the GWIN object
*
* @notapi
*/
GHandle _gwinInit(GWindowObject *pgw, coord_t x, coord_t y, coord_t w, coord_t h, size_t size, const gwinVMT *vmt);
/**
* @brief Initialise (and allocate if necessary) the base Widget object
*
* @param[in] pgw The GWidgetObject structure. If NULL one is allocated from the heap
* @param[in] x, y The top left corner of the Widget relative to the screen
* @param[in] w, h The width and height of the Widget window
* @param[in] size The size of the Widget object to allocate
* @param[in] vmt The virtual method table for the Widget object
*
* @notapi
*/
GHandle _gwidgetInit(GWidgetObject *pgw, coord_t x, coord_t y, coord_t w, coord_t h, size_t size, const gwidgetVMT *vmt);
/**
* @brief Destroy the Widget object
*
* @param[in] gw The widget to destroy
*
* @notapi
*/
void _gwidgetDestroy(GHandle gh);
#ifdef __cplusplus
}
#endif
#endif /* GFX_USE_GWIN */
#endif /* _CLASS_GWIN_H */
/** @} */

View File

@ -24,22 +24,13 @@
#ifndef _GWIN_CONSOLE_H #ifndef _GWIN_CONSOLE_H
#define _GWIN_CONSOLE_H #define _GWIN_CONSOLE_H
#if GWIN_NEED_CONSOLE || defined(__DOXYGEN__) /* This file is included within "gwin/gwin.h" */
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define GW_CONSOLE 0x0001
/*===========================================================================*/
/* Type definitions */
/*===========================================================================*/
// A console window. Supports wrapped text writing and a cursor. // A console window. Supports wrapped text writing and a cursor.
typedef struct GConsoleObject_t { typedef struct GConsoleObject_t {
GWindowObject gwin; GWindowObject g;
coord_t cx, cy; // Cursor position
#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM #if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
struct GConsoleWindowStream_t { struct GConsoleWindowStream_t {
const struct GConsoleWindowVMT_t *vmt; const struct GConsoleWindowVMT_t *vmt;
@ -47,15 +38,8 @@ typedef struct GConsoleObject_t {
} stream; } stream;
#endif #endif
coord_t cx,cy; // Cursor position
uint8_t fy; // Current font height
uint8_t fp; // Current font inter-character spacing
} GConsoleObject; } GConsoleObject;
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -67,18 +51,19 @@ extern "C" {
* @return NULL if there is no resultant drawing area, otherwise a window handle. * @return NULL if there is no resultant drawing area, otherwise a window handle.
* *
* @param[in] gc The GConsoleObject structure to initialise. If this is NULL the structure is dynamically allocated. * @param[in] gc The GConsoleObject structure to initialise. If this is NULL the structure is dynamically allocated.
* @param[in] x,y The screen co-ordinates for the bottom left corner of the window * @param[in] x,y The screen co-ordinates for the top left corner of the window
* @param[in] width The width of the window * @param[in] width The width of the window
* @param[in] height The height of the window * @param[in] height The height of the window
* @param[in] font The font to use *
* @note The console is not automatically cleared on creation. You must do that by calling gwinClear() (possibly after changing your background color) * @note The console is not automatically cleared on creation. You must do that by calling gwinClear() (possibly after changing your background color)
* @note Don't forget to set the font using @p gwinSetFont() or @p gwinSetDefaultFont()
* @note If the dispay does not support scrolling, the window will be cleared when the bottom line is reached. * @note If the dispay does not support scrolling, the window will be cleared when the bottom line is reached.
* @note The default drawing color gets set to White and the background drawing color to Black. * @note The default drawing color gets set to White and the background drawing color to Black.
* @note The dimensions and position may be changed to fit on the real screen. * @note The dimensions and position may be changed to fit on the real screen.
* *
* @api * @api
*/ */
GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t width, coord_t height, font_t font); GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t width, coord_t height);
#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM #if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
/** /**
@ -157,7 +142,5 @@ void gwinPrintf(GHandle gh, const char *fmt, ...);
} }
#endif #endif
#endif /* GWIN_NEED_CONSOLE */
#endif /* _GWIN_CONSOLE_H */ #endif /* _GWIN_CONSOLE_H */
/** @} */ /** @} */

View File

@ -22,20 +22,7 @@
#ifndef _GWIN_GRAPH_H #ifndef _GWIN_GRAPH_H
#define _GWIN_GRAPH_H #define _GWIN_GRAPH_H
#if GWIN_NEED_GRAPH || defined(__DOXYGEN__) /* This file is included within "gwin/gwin.h" */
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define GW_GRAPH 0x0003
/*===========================================================================*/
/* Type definitions */
/*===========================================================================*/
// GDISP now has its own point structure
#define GGraphPoint point
typedef enum GGraphPointType_e { typedef enum GGraphPointType_e {
GGRAPH_POINT_NONE, GGRAPH_POINT_DOT, GGRAPH_POINT_SQUARE, GGRAPH_POINT_CIRCLE GGRAPH_POINT_NONE, GGRAPH_POINT_DOT, GGRAPH_POINT_SQUARE, GGRAPH_POINT_CIRCLE
@ -85,7 +72,7 @@ typedef struct GGraphStyle_t {
// A graph window // A graph window
typedef struct GGraphObject_t { typedef struct GGraphObject_t {
GWindowObject gwin; GWindowObject g;
GGraphStyle style; GGraphStyle style;
coord_t xorigin, yorigin; coord_t xorigin, yorigin;
coord_t lastx, lasty; coord_t lastx, lasty;
@ -104,10 +91,12 @@ extern "C" {
* @return NULL if there is no resultant drawing area, otherwise a window handle. * @return NULL if there is no resultant drawing area, otherwise a window handle.
* *
* @param[in] gg The GGraphObject structure to initialise. If this is NULL the structure is dynamically allocated. * @param[in] gg The GGraphObject structure to initialise. If this is NULL the structure is dynamically allocated.
* @param[in] x,y The screen co-ordinates for the bottom left corner of the window * @param[in] x,y The screen co-ordinates for the top left corner of the window
* @param[in] width The width of the window * @param[in] width The width of the window
* @param[in] height The height of the window * @param[in] height The height of the window
*
* @note The console is not automatically cleared on creation. You must do that by calling gwinClear() (possibly after changing your background color) * @note The console is not automatically cleared on creation. You must do that by calling gwinClear() (possibly after changing your background color)
* @note Don't forget to set the font using @p gwinSetFont() or @p gwinSetDefaultFont()
* @note The coordinate system within the window for graphing operations (but not for any other drawing * @note The coordinate system within the window for graphing operations (but not for any other drawing
* operation) is relative to the bottom left corner and then shifted right and up by the specified * operation) is relative to the bottom left corner and then shifted right and up by the specified
* graphing x and y origin. Note that this system is inverted in the y direction relative to the display. * graphing x and y origin. Note that this system is inverted in the y direction relative to the display.
@ -187,8 +176,6 @@ void gwinGraphDrawPoints(GHandle gh, const point *points, unsigned count);
} }
#endif #endif
#endif /* GWIN_NEED_GRAPH */
#endif /* _GWIN_GRAPH_H */ #endif /* _GWIN_GRAPH_H */
/** @} */ /** @} */

View File

@ -0,0 +1,234 @@
/*
* This file is subject to the terms of the GFX License, v1.0. If a copy of
* the license was not distributed with this file, you can obtain one at:
*
* http://chibios-gfx.com/license.html
*/
/**
* @file include/gwin/gwidget.h
* @brief GWIN Widgets header file.
*/
#ifndef _GWIDGET_H
#define _GWIDGET_H
/* This file is included within "gwin/gwin.h" */
/**
* @defgroup Widget Widget
* @ingroup GWIN
*
* @details A Widget is a GWindow that supports interacting with the user
* via an input device such as a mouse or toggle buttons. It is the
* base class for widgets such as buttons and sliders.
*
* @pre GFX_USE_GWIN must be set to TRUE in your gfxconf.h
* @{
*/
// Forward definition
struct GWidgetObject;
/**
* @brief Defines a custom drawing function for a widget
*/
typedef void (*CustomWidgetDrawFunction)(struct GWidgetObject *gw, void *param);
/**
* @brief The GWIN Widget structure
* @note A widget is a GWIN window that accepts user input.
* It also has a number of other properties such as its ability
* to redraw itself (a widget maintains drawing state).
* @note Do you access the members directly. Treat it as a black-box and use the method functions.
*
* @{
*/
typedef struct GWidgetObject {
GWindowObject g; // @< This is still a GWIN
GListener listener; // @< The widget listener
const char * txt; // @< The widget text
CustomWidgetDrawFunction fnDraw; // @< The current draw function
void * fnParam; // @< A parameter for the current draw function
} GWidgetObject;
/* @} */
/**
* A comment/rant on the above structure:
* We would really like the GWindowObject member to be anonymous. While this is
* allowed under the C11, C99, GNU and various other standards which have been
* around forever - compiler support often requires special flags e.g
* gcc requires the -fms-extensions flag (no wonder the language and compilers have
* not really progressed in 30 years). As portability is a key requirement
* we unfortunately won't use this useful feature in case we get a compiler that
* won't support it even with special flags.
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Enable or disable a widget
*
* @param[in] gh The widget handle
* @param[in] enabled Enable or disable the widget
*
* @note The widget is not automatically redrawn. Call @p gwinDraw() to redraw the widget.
* @note Non-widgets will ignore this call.
*
* @api
*/
void gwinSetEnabled(GHandle gh, bool_t enabled);
/**
* @brief Enable a widget
*
* @param[in] gh The widget handle
*
* @note The widget is not automatically redrawn. Call @p gwinDraw() to redraw the widget.
* @note Non-widgets will ignore this call.
*
* @api
*/
#define gwinEnable(gh) gwinSetEnabled(gh, TRUE)
/**
* @brief Disable a widget
*
* @param[in] gh The widget handle
*
* @note The widget is not automatically redrawn. Call @p gwinDraw() to redraw the widget.
* @note Non-widgets will ignore this call.
*
* @api
*/
#define gwinDisable(gh) gwinSetEnabled(gh, FALSE)
/**
* @brief Redraw the widget
*
* @param[in] gh The widget handle
*
* @note Non-widgets will ignore this call.
*
* @api
*/
void gwinDraw(GHandle gh);
/**
* @brief Set the text of a widget.
*
* @param[in] gh The widget handle
* @param[in] txt The text to set. This must be a constant string unless useAlloc is set.
* @param[in] useAlloc If TRUE the string specified will be copied into dynamically allocated memory.
*
* @note The widget is not automatically redrawn. Call @p gwinDraw() to redraw the widget.
* @note Non-widgets will ignore this call.
*
* @api
*/
void gwinSetText(GHandle gh, const char *txt, bool_t useAlloc);
/**
* @brief Get the text of a widget.
* @return The widget text or NULL if it isn't a widget
*
* @param[in] gh The widget handle
*
* @api
*/
const char *gwinGetText(GHandle gh);
/**
* @brief Set the routine to perform a custom widget drawing.
*
* @param[in] gh The widget handle
* @param[in] fn The function to use to draw the widget
* @param[in] param A parameter to pass to the widget drawing function
*
* @note The widget is not automatically redrawn. Call @p gwinDraw() to redraw the widget.
* @note Non-widgets will ignore this call.
*
* @api
*/
void gwinSetCustomDraw(GHandle gh, CustomWidgetDrawFunction fn, void *param);
/**
* @brief Attach a Listener to this widget
* @return TRUE on success
*
* @param[in] gh The widget handle
* @param[in] pl The listener
* @param[in] flags Flags to use for listening. For most widgets this should be 0.
*
* @api
*/
bool_t gwinAttachListener(GHandle gh, GListener *pl, unsigned flags);
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
/**
* @brief Attach a mouse to a widget
* @return TRUE on success
*
* @param[in] gh The widget handle
* @param[in] instance The mouse instance
*
* @api
*/
bool_t gwinAttachMouse(GHandle gh, uint16_t instance);
#endif
#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
/**
* @brief Attach a toggle to a widget
* @return TRUE on success
*
* @param[in] gh The widget handle
* @param[in] role The function the toggle will perform for the widget
* @param[in] instance The toggle instance
*
* @note See the documentation on the specific widget to see the possible
* values for the role parameter. If it is out of range, this function
* will return FALSE
*
* @api
*/
bool_t gwinAttachToggle(GHandle gh, uint16_t role, uint16_t instance);
#endif
#if GFX_USE_GINPUT && GINPUT_NEED_DIAL
/**
* @brief Attach a toggle to a widget
* @return TRUE on success
*
* @param[in] gh The widget handle
* @param[in] role The function the dial will perform for the widget
* @param[in] instance The dial instance
*
* @note See the documentation on the specific widget to see the possible
* values for the role parameter. If it is out of range, this function
* will return FALSE
*
* @api
*/
bool_t gwinAttachDial(GHandle gh, uint16_t role, uint16_t instance);
#endif
#ifdef __cplusplus
}
#endif
/* Include extra widget types */
#if GWIN_NEED_BUTTON || defined(__DOXYGEN__)
#include "gwin/button.h"
#endif
#if GWIN_NEED_SLIDER || defined(__DOXYGEN__)
#include "gwin/slider.h"
#endif
#if GWIN_NEED_CHECKBOX || defined(__DOXYGEN__)
#include "gwin/checkbox.h"
#endif
#endif /* _GWIDGET_H */
/** @} */

View File

@ -12,14 +12,12 @@
* @defgroup Window Window * @defgroup Window Window
* @ingroup GWIN * @ingroup GWIN
* *
* @details GWIN provides a basic window manager which allows it to easily * @details GWIN provides a basic window manager which allows it to easily
* create and destroy different windows on runtime. Each window * create and destroy different windows at runtime. Each window
* will have it's own properties such as colors, brushes as well as * will have it's own properties such as colors as well as
* it's own drawing origin. * it's own drawing origin.
* Moving the windows around is not supported yet.
* *
* @pre GFX_USE_GWIN must be set to TRUE in your gfxconf.h * @pre GFX_USE_GWIN must be set to TRUE in your gfxconf.h
*
* @{ * @{
*/ */
@ -30,30 +28,23 @@
#if GFX_USE_GWIN || defined(__DOXYGEN__) #if GFX_USE_GWIN || defined(__DOXYGEN__)
/*===========================================================================*/ /**
/* Type definitions */ * @brief A window object structure
/*===========================================================================*/ * @note Do you access the members directly. Treat it as a black-box and use the method functions.
*
typedef uint16_t GWindowType; * @{
#define GW_WINDOW 0x0000 */
#define GW_FIRST_USER_WINDOW 0x8000 typedef struct GWindowObject {
const struct gwinVMT *vmt; // @< The VMT for this GWIN
// A basic window coord_t x, y; // @< Screen relative position
typedef struct GWindowObject_t { coord_t width, height; // @< Dimensions of this window
GWindowType type; // What type of window is this color_t color, bgcolor; // @< Current drawing colors
uint16_t flags; // Internal flags uint16_t flags; // @< Window flags (the meaning is private to the GWIN class)
coord_t x, y; // Screen relative position
coord_t width, height; // Dimensions of this window
color_t color, bgcolor; // Current drawing colors
bool_t enabled; // Enabled/Disabled state
#if GDISP_NEED_TEXT #if GDISP_NEED_TEXT
font_t font; // Current font font_t font; // @< Current font
#endif #endif
} GWindowObject, * GHandle; } GWindowObject, * GHandle;
/* @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -65,18 +56,20 @@ extern "C" {
* @brief Create a basic window. * @brief Create a basic window.
* @return NULL if there is no resultant drawing area, otherwise a window handle. * @return NULL if there is no resultant drawing area, otherwise a window handle.
* *
* @param[in] gw The window structure to initialize. If this is NULL the structure is dynamically allocated. * @param[in] pgw The window structure to initialize. If this is NULL the structure is dynamically allocated.
* @param[in] x,y The screen coordinates for the bottom left corner of the window * @param[in] x,y The screen coordinates for the top left corner of the window
* @param[in] width The width of the window * @param[in] width The width of the window
* @param[in] height The height of the window * @param[in] height The height of the window
*
* @note The default drawing color gets set to White and the background drawing color to Black. * @note The default drawing color gets set to White and the background drawing color to Black.
* @note No default font is set so make sure to set one before drawing any text. * @note No default font is set so make sure to set one before drawing any text.
* @note The dimensions and position may be changed to fit on the real screen. * @note The dimensions and position may be changed to fit on the real screen.
* @note The window is not automatically cleared on creation. You must do that by calling gwinClear() (possibly after changing your background color) * @note The window is not automatically cleared on creation. You must do that by calling @p gwinClear()
* (possibly after changing your background color)
* *
* @api * @api
*/ */
GHandle gwinCreateWindow(GWindowObject *gw, coord_t x, coord_t y, coord_t width, coord_t height); GHandle gwinCreateWindow(GWindowObject *pgw, coord_t x, coord_t y, coord_t width, coord_t height);
/** /**
* @brief Destroy a window (of any type). Releases any dynamically allocated memory. * @brief Destroy a window (of any type). Releases any dynamically allocated memory.
@ -85,17 +78,22 @@ GHandle gwinCreateWindow(GWindowObject *gw, coord_t x, coord_t y, coord_t width,
* *
* @api * @api
*/ */
void gwinDestroyWindow(GHandle gh); void gwinDestroy(GHandle gh);
/** /**
* @brief Enable or disable a widget (of any type). * @brief Get the real class name of the GHandle
* @details Returns a string describing the object class.
* *
* @param[in] gh The window handle * @param[in] gh The window
* @param[in] enabled Enable or disable the widget
*
* @api
*/ */
void gwinSetEnabled(GHandle gh, bool_t enabled); const char *gwinGetClassName(GHandle gh);
/**
* @brief Get an ID that uniquely describes the class of the GHandle
*
* @param[in] gh The window
*/
#define gwinGetClassID(gh) ((void *)((gh)->vmt))
/** /**
* @brief Get the X coordinate of the window * @brief Get the X coordinate of the window
@ -148,23 +146,16 @@ void gwinSetEnabled(GHandle gh, bool_t enabled);
*/ */
#define gwinSetBgColor(gh, bgclr) (gh)->bgcolor = (bgclr) #define gwinSetBgColor(gh, bgclr) (gh)->bgcolor = (bgclr)
/**
* @brief Enable a window of any type
*
* @param[in] gh The window handle
*/
#define gwinEnable(gh) gwinSetEnabled(gh, TRUE)
/**
* @brief Disable a window of any type
*
* @param[in] gh The window handle
*/
#define gwinDisable(gh) gwinSetEnabled(gh, FALSE)
/* Set up for text */ /* Set up for text */
#if GDISP_NEED_TEXT || defined(__DOXYGEN__) #if GDISP_NEED_TEXT || defined(__DOXYGEN__)
/**
* @brief Set the default font for all new GWIN windows
*
* @param[in] gh The window
*/
void gwinSetDefaultFont(font_t font);
/** /**
* @brief Set the current font for this window. * @brief Set the current font for this window.
* *
@ -178,16 +169,6 @@ void gwinSetEnabled(GHandle gh, bool_t enabled);
/* Drawing Functions */ /* Drawing Functions */
/**
* @brief Draw the window
* @note Redraws the Window if the GWIN object has a draw routine
*
* @param[in] gh The window handle
*
* @api
*/
void gwinDraw(GHandle gh);
/** /**
* @brief Clear the window * @brief Clear the window
* @note Uses the current background color to clear the window * @note Uses the current background color to clear the window
@ -538,12 +519,16 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
} }
#endif #endif
/* Include widgets */
#include "gwin/gwidget.h"
/* Include extra window types */ /* Include extra window types */
#include "gwin/console.h" /* 0x0001 */ #if GWIN_NEED_CONSOLE || defined(__DOXYGEN__)
#include "gwin/button.h" /* 0x0002 */ #include "gwin/console.h"
#include "gwin/graph.h" /* 0x0003 */ #endif
#include "gwin/slider.h" /* 0x0004 */ #if GWIN_NEED_GRAPH || defined(__DOXYGEN__)
#include "gwin/checkbox.h" /* 0x0005 */ #include "gwin/graph.h"
#endif
#endif /* GFX_USE_GWIN */ #endif /* GFX_USE_GWIN */

View File

@ -1,41 +0,0 @@
/*
* This file is subject to the terms of the GFX License, v1.0. If a copy of
* the license was not distributed with this file, you can obtain one at:
*
* http://chibios-gfx.com/license.html
*/
/**
* @file include/gwin/internal.h
* @brief GWIN Graphic window subsystem header file.
*
* @addtogroup GWIN
* @{
*/
#ifndef _GWIN_INTERNAL_H
#define _GWIN_INTERNAL_H
#if GFX_USE_GWIN || defined(__DOXYGEN__)
/*===========================================================================*/
/* Sub-system constants. */
/*===========================================================================*/
#define GWIN_FLG_DYNAMIC 0x0001
#define GBTN_FLG_ALLOCTXT 0x0002
#define GWIN_FIRST_CONTROL_FLAG 0x0004
#ifdef __cplusplus
extern "C" {
#endif
GHandle _gwinInit(GWindowObject *gw, coord_t x, coord_t y, coord_t width, coord_t height, size_t size);
#ifdef __cplusplus
}
#endif
#endif /* GFX_USE_GWIN */
#endif /* _GWIN_INTERNAL_H */
/** @} */

View File

@ -22,19 +22,10 @@
#ifndef _GWIN_SLIDER_H #ifndef _GWIN_SLIDER_H
#define _GWIN_SLIDER_H #define _GWIN_SLIDER_H
#if GWIN_NEED_SLIDER || defined(__DOXYGEN__) /* This file is included within "gwin/gwidget.h" */
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define GW_SLIDER 0x0004
#define GEVENT_GWIN_SLIDER (GEVENT_GWIN_FIRST+1) #define GEVENT_GWIN_SLIDER (GEVENT_GWIN_FIRST+1)
/*===========================================================================*/
/* Type definitions */
/*===========================================================================*/
typedef struct GEventGWinSlider_t { typedef struct GEventGWinSlider_t {
GEventType type; // The type of this event (GEVENT_GWIN_BUTTON) GEventType type; // The type of this event (GEVENT_GWIN_BUTTON)
GHandle slider; // The slider that is returning results GHandle slider; // The slider that is returning results
@ -43,33 +34,24 @@ typedef struct GEventGWinSlider_t {
// There are currently no GEventGWinSlider listening flags - use 0 // There are currently no GEventGWinSlider listening flags - use 0
typedef struct GSliderDrawStyle_t { typedef struct GSliderColors {
color_t color_edge; color_t color_edge;
color_t color_thumb; color_t color_thumb;
color_t color_active; color_t color_active;
color_t color_inactive; color_t color_inactive;
} GSliderDrawStyle; color_t color_txt;
} GSliderColors;
typedef void (*GSliderDrawFunction)(GHandle gh, bool_t isVertical, coord_t thumbpos, const GSliderDrawStyle *pstyle, void *param);
// A slider window // A slider window
typedef struct GSliderObject_t { typedef struct GSliderObject_t {
GWindowObject gwin; GWidgetObject w;
GSliderColors c;
GSliderDrawStyle style; coord_t dpos;
bool_t tracking;
int min; int min;
int max; int max;
int pos; int pos;
GSliderDrawFunction fn;
void *param;
GListener listener;
} GSliderObject; } GSliderObject;
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -79,12 +61,14 @@ extern "C" {
* @return NULL if there is no resultant drawing area, otherwise a window handle. * @return NULL if there is no resultant drawing area, otherwise a window handle.
* *
* @param[in] gb The GSliderObject structure to initialise. If this is NULL the structure is dynamically allocated. * @param[in] gb The GSliderObject structure to initialise. If this is NULL the structure is dynamically allocated.
* @param[in] x,y The screen co-ordinates for the bottom left corner of the window * @param[in] x,y The screen co-ordinates for the top left corner of the window
* @param[in] width The width of the window * @param[in] width The width of the window
* @param[in] height The height of the window * @param[in] height The height of the window
*
* @note The drawing color gets set to White and the background drawing color to Black. * @note The drawing color gets set to White and the background drawing color to Black.
* @note Don't forget to set the font using @p gwinSetFont() or @p gwinSetDefaultFont()
* @note The dimensions and position may be changed to fit on the real screen. * @note The dimensions and position may be changed to fit on the real screen.
* @note The slider is not automatically drawn. Call gwinSliderDraw() after changing the slider style. * @note The slider is not automatically drawn. Call gwinDraw() to draw it.
* @note Sets the slider range from 0 to 100 with an initial position of 0 * @note Sets the slider range from 0 to 100 with an initial position of 0
* *
* @api * @api
@ -130,51 +114,7 @@ void gwinSetSliderPosition(GHandle gh, int pos);
* *
* @api * @api
*/ */
void gwinSetSliderStyle(GHandle gh, const GSliderDrawStyle *pStyle); void gwinSetSliderColors(GHandle gh, const GSliderColors *pStyle);
/**
* @brief Redraw the slider.
*
* @param[in] gh The window handle (must be a slider window)
*
* @api
*/
void gwinSliderDraw(GHandle gh);
/**
* @brief Enable or disable a button
*
* @param[in] gh The window handle (must be a slider window)
* @param[in] enabled Enable or disable the slider
*
* @api
*/
void gwinSliderSetEnabled(GHandle gh, bool_t enabled);
/**
* @brief Set the callback routine to perform a custom slider drawing.
*
* @param[in] gh The window handle (must be a slider window)
* @param[in] fn The function to use to draw the slider
* @param[in] param A parameter to pass to the slider drawing function
*
* @api
*/
void gwinSetSliderCustom(GHandle gh, GSliderDrawFunction fn, void *param);
/**
* @brief Enable a slider
*
* @api
*/
#define gwinEnableSlider(gh) gwinSliderSetEnabled( ((GSliderObject *)(gh)), TRUE)
/**
* @brief Disable a slider
*
* @api
*/
#define gwinDisableSlider(gh) gwinSliderSetEnabled( ((GSliderObject *)(gh)), FALSE)
/** /**
* @brief Get the current slider position. * @brief Get the current slider position.
@ -190,69 +130,35 @@ void gwinSetSliderCustom(GHandle gh, GSliderDrawFunction fn, void *param);
#define gwinGetSliderPosition(gh) (((GSliderObject *)(gh))->pos) #define gwinGetSliderPosition(gh) (((GSliderObject *)(gh))->pos)
/** /**
* @brief Get the source handle of a slider * @brief Some custom slider drawing routines
* @details Get the source handle of a slider so the application can listen for events * @details These function may be passed to @p gwinSetCustomDraw() to get different slider drawing styles
* *
* @param[in] gh The window handle * @param[in] gw The widget (which must be a slider)
*
* @api
*/
#define gwinGetSliderSource(gh) ((GSourceHandle)(gh))
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
/**
* @brief Attach a mouse source
* @details Attach a mouse to a slider
*
* @param[in] gh The slider handle
* @param[in] instance The mouse instance
*
* @api
*/
bool_t gwinAttachSliderMouse(GHandle gh, uint16_t instance);
#endif
#if GFX_USE_GINPUT && GINPUT_NEED_DIAL
/**
* @brief Attach a dial source
* @details Attach a dial to a slider
*
* @param[in] gh The dial handle
* @param[in] instance The dial instance
*
* @api
*/
bool_t gwinAttachSliderDial(GHandle gh, uint16_t instance);
#endif
/**
* @brief Standard slider drawing routines
* @details This routine is called to draw the standard slider.
*
* @param[in] gh The slider handle
* @param[in] isVertical The slider is vertically oriented instead of horizontal
* @param[in] thumbpos The position of the slider (0..cx-1 or cy-1..0)
* @param[in] pstyle The current drawing style
* @param[in] param A parameter passed in from the user * @param[in] param A parameter passed in from the user
* *
* @note In your custom slider drawing function you may optionally call this * @note In your custom slider drawing function you may optionally call this
* standard functions and then draw your extra details on top. * standard functions and then draw your extra details on top.
* @note The standard functions below ignore the param parameter. It is there * @note The standard functions below ignore the param parameter except for @p gwinSliderDraw_Image().
* only to ensure the functions match the GSliderDrawFunction type. * @note The image custom draw function @p gwinSliderDraw_Image() uses param to pass in the gdispImage pointer.
* @note When called by a slider the framework ensure that it is * The image must be already opened before calling @p gwinSetCustomDraw(). The image is tiled to fill
* a slider object and sets up clipping to the slider object window. These * the active area of the slider. The normal colors apply to the border and inactive area and the dividing line
* drawing routines then don't have to worry about explicitly doing that. * between the active and inactive areas.
* No checking is done to compare the dimensions of the slider to the size of the image.
* Note text is drawn on top of the image.
* @note These custom drawing routines don't have to worry about setting clipping as the framework
* sets clipping to the object window prior to calling these routines.
* *
* @api * @api
* @{
*/ */
void gwinSliderDraw_Std(GHandle gh, bool_t isVertical, coord_t thumbpos, const GSliderDrawStyle *pstyle, void *param); void gwinSliderDraw_Std(GWidgetObject *gw, void *param);
void gwinSliderDraw_Image(GWidgetObject *gw, void *param);
/* @} */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* GWIN_NEED_SLIDER */
#endif /* _GWIN_SLIDER_H */ #endif /* _GWIN_SLIDER_H */
/** @} */ /** @} */

View File

@ -19,392 +19,313 @@
#if (GFX_USE_GWIN && GWIN_NEED_BUTTON) || defined(__DOXYGEN__) #if (GFX_USE_GWIN && GWIN_NEED_BUTTON) || defined(__DOXYGEN__)
/* Parameters for various shapes */ #include "gwin/class_gwin.h"
// Parameters for various shapes
#define RND_CNR_SIZE 5 // Rounded corner size for rounded buttons #define RND_CNR_SIZE 5 // Rounded corner size for rounded buttons
#define ARROWHEAD_DIVIDER 4 // A quarter of the height for the arrow head #define ARROWHEAD_DIVIDER 4 // A quarter of the height for the arrow head
#define ARROWBODY_DIVIDER 4 // A quarter of the width for the arrow body #define ARROWBODY_DIVIDER 4 // A quarter of the width for the arrow body
#include <string.h> // Our pressed state
#define GBUTTON_FLG_PRESSED (GWIN_FIRST_CONTROL_FLAG<<0)
#include "gwin/internal.h" // Prototypes for button VMT functions
static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y);
static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y);
static void ToggleOff(GWidgetObject *gw, uint16_t instance);
static void ToggleOn(GWidgetObject *gw, uint16_t instance);
#define GWIN_BUTTON_DEFAULT_SHAPE GBTN_3D // The button VMT table
static const gwidgetVMT buttonVMT = {
{
"Button", // The classname
_gwidgetDestroy, // The destroy routine
0, // The after-clear routine
},
gwinButtonDraw_3D, // The default drawing routine
MouseDown, // Process mouse down events
MouseUp, // Process mouse up events
0, // Process mouse move events (NOT USED)
ToggleOff, // Process toggle off events
ToggleOn, // Process toggle on events
0, // Process dial move events (NOT USED)
0, // Process all events (NOT USED)
0, // AssignToggle (NOT USED)
0, // AssignDial (NOT USED)
};
static const GButtonDrawStyle GButtonDefaultStyleUp = { // Default color scheme
static const GButtonColors GButtonDefaultColorsUp = {
HTML2COLOR(0x404040), // color_up_edge; HTML2COLOR(0x404040), // color_up_edge;
HTML2COLOR(0xE0E0E0), // color_up_fill; HTML2COLOR(0xE0E0E0), // color_up_fill;
HTML2COLOR(0x000000), // color_up_txt; HTML2COLOR(0x000000), // color_up_txt;
}; };
static const GButtonColors GButtonDefaultColorsDown = {
static const GButtonDrawStyle GButtonDefaultStyleDown = {
HTML2COLOR(0x404040), // color_dn_edge; HTML2COLOR(0x404040), // color_dn_edge;
HTML2COLOR(0x808080), // color_dn_fill; HTML2COLOR(0x808080), // color_dn_fill;
HTML2COLOR(0x404040), // color_dn_txt; HTML2COLOR(0x404040), // color_dn_txt;
}; };
static const GButtonColors GButtonDefaultColorsDisabled = {
HTML2COLOR(0x808080), // color_dis_edge;
HTML2COLOR(0xE0E0E0), // color_dis_fill;
HTML2COLOR(0xC0C0C0), // color_dis_txt;
};
// Process an event callback // Send the button event
static void gwinButtonCallback(void *param, GEvent *pe) { static void SendButtonEvent(GWidgetObject *gw) {
GSourceListener *psl; GSourceListener * psl;
#define gh ((GHandle)param) GEvent * pe;
#define gbw ((GButtonObject *)param) #define pbe ((GEventGWinButton *)pe)
#define gsh ((GSourceHandle)param)
#define pme ((GEventMouse *)pe)
#define pte ((GEventTouch *)pe)
#define pxe ((GEventToggle *)pe)
#define pbe ((GEventGWinButton *)pe)
// check if button is disabled
if (!gh->enabled)
return;
switch (pe->type) {
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
case GEVENT_MOUSE:
case GEVENT_TOUCH:
// Ignore anything other than the primary mouse button going up or down
if (!((pme->current_buttons ^ pme->last_buttons) & GINPUT_MOUSE_BTN_LEFT))
return;
if (gbw->state == GBTN_UP) {
// Our button is UP: Test for button down over the button
if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)
&& pme->x >= gbw->gwin.x && pme->x < gbw->gwin.x + gbw->gwin.width
&& pme->y >= gbw->gwin.y && pme->y < gbw->gwin.y + gbw->gwin.height) {
gbw->state = GBTN_DOWN;
gwinButtonDraw((GHandle)param);
}
return;
}
// Our button is DOWN
// Skip more mouse downs
if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT))
return;
// This must be a mouse up - set the button as UP
gbw->state = GBTN_UP;
gwinButtonDraw((GHandle)param);
#if GWIN_BUTTON_LAZY_RELEASE
break;
#else
// If the mouse up was over the button then create the event
if (pme->x >= gbw->gwin.x && pme->x < gbw->gwin.x + gbw->gwin.width
&& pme->y >= gbw->gwin.y && pme->y < gbw->gwin.y + gbw->gwin.height)
break;
return;
#endif
#endif
#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
case GEVENT_TOGGLE:
// State has changed - update the button
gbw->state = pxe->on ? GBTN_DOWN : GBTN_UP;
gwinButtonDraw((GHandle)param);
// Trigger the event on button down (different than for mouse/touch)
if (gbw->state == GBTN_DOWN)
break;
return;
#endif
default:
return;
}
// Trigger a GWIN Button Event // Trigger a GWIN Button Event
psl = 0; psl = 0;
while ((psl = geventGetSourceListener(gsh, psl))) { while ((psl = geventGetSourceListener((GSourceHandle)gw, psl))) {
if (!(pe = geventGetEventBuffer(psl))) if (!(pe = geventGetEventBuffer(psl)))
continue; continue;
pbe->type = GEVENT_GWIN_BUTTON; pbe->type = GEVENT_GWIN_BUTTON;
pbe->button = gh; pbe->button = (GHandle)gw;
geventSendEvent(psl); geventSendEvent(psl);
} }
#undef pbe #undef pbe
#undef pme
#undef pte
#undef pxe
#undef gsh
#undef gbw
#undef gh
} }
GHandle gwinCreateButton(GButtonObject *gb, coord_t x, coord_t y, coord_t width, coord_t height, font_t font, GButtonType type) { // A mouse down has occurred over the button
if (!(gb = (GButtonObject *)_gwinInit((GWindowObject *)gb, x, y, width, height, sizeof(GButtonObject)))) static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) {
return 0; (void) x; (void) y;
gw->g.flags |= GBUTTON_FLG_PRESSED;
gb->gwin.type = GW_BUTTON; gwinDraw((GHandle)gw);
gb->fn = 0;
gb->param = 0;
gwinSetFont(&gb->gwin, font);
gwinSetButtonStyle(&gb->gwin, GWIN_BUTTON_DEFAULT_SHAPE, &GButtonDefaultStyleUp, &GButtonDefaultStyleDown);
gb->type = type;
gb->state = GBTN_UP;
gb->txt = "";
geventListenerInit(&gb->listener);
geventRegisterCallback(&gb->listener, gwinButtonCallback, gb);
// buttons are enabled by default
gb->gwin.enabled = TRUE;
return (GHandle)gb;
} }
void gwinSetButtonStyle(GHandle gh, GButtonShape shape, const GButtonDrawStyle *pUp, const GButtonDrawStyle *pDown) { // A mouse up has occurred (it may or may not be over the button)
#define gbw ((GButtonObject *)gh) static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y) {
if (gh->type != GW_BUTTON) (void) x; (void) y;
return; gw->g.flags &= ~GBUTTON_FLG_PRESSED;
gwinDraw((GHandle)gw);
switch(shape) { #if !GWIN_BUTTON_LAZY_RELEASE
case GBTN_SQUARE: gbw->fn = gwinButtonDraw_Square; break; // If the mouse up was not over the button then cancel the event
#if GDISP_NEED_ARC if (x < 0 || y < 0 || x >= gw->g.width || y >= gw->g.height)
case GBTN_ROUNDED: gbw->fn = gwinButtonDraw_Rounded; break; return;
#endif
#if GDISP_NEED_ELLIPSE
case GBTN_ELLIPSE: gbw->fn = gwinButtonDraw_Ellipse; break;
#endif
#if GDISP_NEED_CONVEX_POLYGON
case GBTN_ARROW_UP: gbw->fn = gwinButtonDraw_ArrowUp; break;
case GBTN_ARROW_DOWN: gbw->fn = gwinButtonDraw_ArrowDown; break;
case GBTN_ARROW_LEFT: gbw->fn = gwinButtonDraw_ArrowLeft; break;
case GBTN_ARROW_RIGHT: gbw->fn = gwinButtonDraw_ArrowRight; break;
#endif
case GBTN_CUSTOM: if (gbw->fn) break; /* Fall Through */
case GBTN_3D: /* Fall through */
default: gbw->fn = gwinButtonDraw_3D; break;
}
if (pUp) {
gbw->up.color_edge = pUp->color_edge;
gbw->up.color_fill = pUp->color_fill;
gbw->up.color_txt = pUp->color_txt;
}
if (pDown) {
gbw->dn.color_edge = pDown->color_edge;
gbw->dn.color_fill = pDown->color_fill;
gbw->dn.color_txt = pDown->color_txt;
}
#undef gbw
}
void gwinSetButtonText(GHandle gh, const char *txt, bool_t useAlloc) {
#define gbw ((GButtonObject *)gh)
if (gh->type != GW_BUTTON)
return;
// Dispose of the old string
if ((gh->flags & GBTN_FLG_ALLOCTXT)) {
gh->flags &= ~GBTN_FLG_ALLOCTXT;
if (gbw->txt) {
gfxFree((void *)gbw->txt);
gbw->txt = "";
}
}
// Alloc the new text if required
if (txt && useAlloc) {
char *str;
if ((str = (char *)gfxAlloc(strlen(txt)+1))) {
gh->flags |= GBTN_FLG_ALLOCTXT;
strcpy(str, txt);
}
txt = (const char *)str;
}
gbw->txt = txt ? txt : "";
#undef gbw
}
void gwinButtonDraw(GHandle gh) {
#define gbw ((GButtonObject *)gh)
if (gh->type != GW_BUTTON)
return;
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif #endif
gbw->fn(gh, SendButtonEvent(gw);
gbw->gwin.enabled,
gbw->state == GBTN_DOWN,
gh->font && gbw->txt ? gbw->txt : "",
gbw->state == GBTN_DOWN ? &gbw->dn : &gbw->up,
gbw->param);
#undef gbw
} }
void gwinSetButtonCustom(GHandle gh, GButtonDrawFunction fn, void *param) { // A toggle off has occurred
#define gbw ((GButtonObject *)gh) static void ToggleOff(GWidgetObject *gw, uint16_t instance) {
(void) instance;
gw->g.flags &= ~GBUTTON_FLG_PRESSED;
gwinDraw((GHandle)gw);
}
if (gh->type != GW_BUTTON) // A toggle on has occurred
static void ToggleOn(GWidgetObject *gw, uint16_t instance) {
(void) instance;
gw->g.flags |= GBUTTON_FLG_PRESSED;
gwinDraw((GHandle)gw);
// Trigger the event on button down (different than for mouse/touch)
SendButtonEvent(gw);
}
GHandle gwinCreateButton(GButtonObject *gw, coord_t x, coord_t y, coord_t width, coord_t height) {
if (!(gw = (GButtonObject *)_gwidgetInit((GWidgetObject *)gw, x, y, width, height, sizeof(GButtonObject), &buttonVMT)))
return 0;
gw->c_up = GButtonDefaultColorsUp;
gw->c_dn = GButtonDefaultColorsDown;
gw->c_dis = GButtonDefaultColorsDisabled;
return (GHandle)gw;
}
void gwinSetButtonColors(GHandle gh, const GButtonColors *pUp, const GButtonColors *pDown, const GButtonColors *pDisabled) {
if (gh->vmt != (gwinVMT *)&buttonVMT)
return; return;
gbw->fn = fn ? fn : gwinButtonDraw_3D; if (pUp) ((GButtonObject *)gh)->c_up = *pUp;
gbw->param = param; if (pDown) ((GButtonObject *)gh)->c_dn = *pDown;
if (pDisabled) ((GButtonObject *)gh)->c_dis = *pDisabled;
#undef gbw
} }
void gwinButtonSetEnabled(GHandle gh, bool_t enabled) { bool_t gwinIsButtonPressed(GHandle gh) {
if (gh->type != GW_BUTTON) if (gh->vmt != (gwinVMT *)&buttonVMT)
return; return FALSE;
gh->enabled = enabled; return (gh->flags & GBUTTON_FLG_PRESSED) ? TRUE : FALSE;
} }
void gwinButtonDraw_3D(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { /*----------------------------------------------------------
(void) enabled; * Custom Draw Routines
(void) isdown; *----------------------------------------------------------*/
(void) param;
gdispFillStringBox(gh->x, gh->y, gh->width-1, gh->height-1, txt, gh->font, pstyle->color_txt, pstyle->color_fill, justifyCenter); static GButtonColors *getDrawColors(GWidgetObject *gw) {
gdispDrawLine(gh->x+gh->width-1, gh->y, gh->x+gh->width-1, gh->y+gh->height-1, pstyle->color_edge); if (!(gw->g.flags & GWIN_FLG_ENABLED)) return &((GButtonObject *)gw)->c_dis;
gdispDrawLine(gh->x, gh->y+gh->height-1, gh->x+gh->width-2, gh->y+gh->height-1, pstyle->color_edge); if ((gw->g.flags & GBUTTON_FLG_PRESSED)) return &((GButtonObject *)gw)->c_dn;
return &((GButtonObject *)gw)->c_up;
} }
void gwinButtonDraw_Square(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { void gwinButtonDraw_3D(GWidgetObject *gw, void *param) {
(void) enabled; (void) param;
(void) isdown; GButtonColors * pcol;
(void) param;
gdispFillStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, pstyle->color_fill, justifyCenter); if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge); pcol = getDrawColors(gw);
gdispFillStringBox(gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->txt, gw->g.font, pcol->color_txt, pcol->color_fill, justifyCenter);
gdispDrawLine(gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->color_edge);
gdispDrawLine(gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->color_edge);
}
void gwinButtonDraw_Box(GWidgetObject *gw, void *param) {
(void) param;
GButtonColors * pcol;
if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
pcol = getDrawColors(gw);
gdispFillStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, pcol->color_fill, justifyCenter);
gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->color_edge);
} }
#if GDISP_NEED_ARC #if GDISP_NEED_ARC
void gwinButtonDraw_Rounded(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { void gwinButtonDraw_Rounded(GWidgetObject *gw, void *param) {
(void) enabled; (void) param;
(void) isdown; GButtonColors * pcol;
(void) param;
if (gh->width >= 2*RND_CNR_SIZE+10) { if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
gdispFillRoundedBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, RND_CNR_SIZE-1, pstyle->color_fill); pcol = getDrawColors(gw);
gdispDrawStringBox(gh->x+1, gh->y+RND_CNR_SIZE, gh->width-2, gh->height-(2*RND_CNR_SIZE), txt, gh->font, pstyle->color_txt, justifyCenter);
gdispDrawRoundedBox(gh->x, gh->y, gh->width, gh->height, RND_CNR_SIZE, pstyle->color_edge); if (gw->g.width >= 2*RND_CNR_SIZE+10) {
gdispFillRoundedBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, RND_CNR_SIZE-1, pcol->color_fill);
gdispDrawStringBox(gw->g.x+1, gw->g.y+RND_CNR_SIZE, gw->g.width-2, gw->g.height-(2*RND_CNR_SIZE), gw->txt, gw->g.font, pcol->color_txt, justifyCenter);
gdispDrawRoundedBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, RND_CNR_SIZE, pcol->color_edge);
} else { } else {
gdispFillStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, pstyle->color_fill, justifyCenter); gdispFillStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, pcol->color_fill, justifyCenter);
gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge); gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->color_edge);
} }
} }
#endif #endif
#if GDISP_NEED_ELLIPSE #if GDISP_NEED_ELLIPSE
void gwinButtonDraw_Ellipse(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { void gwinButtonDraw_Ellipse(GWidgetObject *gw, void *param) {
(void) enabled; (void) param;
(void) isdown; GButtonColors * pcol;
(void) param;
gdispFillEllipse(gh->x+1, gh->y+1, gh->width/2-1, gh->height/2-1, pstyle->color_fill); if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter); pcol = getDrawColors(gw);
gdispDrawEllipse(gh->x, gh->y, gh->width/2, gh->height/2, pstyle->color_edge);
gdispFillEllipse(gw->g.x+1, gw->g.y+1, gw->g.width/2-1, gw->g.height/2-1, pcol->color_fill);
gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, justifyCenter);
gdispDrawEllipse(gw->g.x, gw->g.y, gw->g.width/2, gw->g.height/2, pcol->color_edge);
} }
#endif #endif
#if GDISP_NEED_CONVEX_POLYGON #if GDISP_NEED_CONVEX_POLYGON
void gwinButtonDraw_ArrowUp(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { void gwinButtonDraw_ArrowUp(GWidgetObject *gw, void *param) {
(void) enabled; (void) param;
(void) isdown; GButtonColors * pcol;
(void) param; point arw[7];
point arw[7];
arw[0].x = gh->width/2; arw[0].y = 0; if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
arw[1].x = gh->width-1; arw[1].y = gh->height/ARROWHEAD_DIVIDER; pcol = getDrawColors(gw);
arw[2].x = (gh->width + gh->width/ARROWBODY_DIVIDER)/2; arw[2].y = gh->height/ARROWHEAD_DIVIDER;
arw[3].x = (gh->width + gh->width/ARROWBODY_DIVIDER)/2; arw[3].y = gh->height-1;
arw[4].x = (gh->width - gh->width/ARROWBODY_DIVIDER)/2; arw[4].y = gh->height-1;
arw[5].x = (gh->width - gh->width/ARROWBODY_DIVIDER)/2; arw[5].y = gh->height/ARROWHEAD_DIVIDER;
arw[6].x = 0; arw[6].y = gh->height/ARROWHEAD_DIVIDER;
gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill); arw[0].x = gw->g.width/2; arw[0].y = 0;
gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge); arw[1].x = gw->g.width-1; arw[1].y = gw->g.height/ARROWHEAD_DIVIDER;
gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter); arw[2].x = (gw->g.width + gw->g.width/ARROWBODY_DIVIDER)/2; arw[2].y = gw->g.height/ARROWHEAD_DIVIDER;
arw[3].x = (gw->g.width + gw->g.width/ARROWBODY_DIVIDER)/2; arw[3].y = gw->g.height-1;
arw[4].x = (gw->g.width - gw->g.width/ARROWBODY_DIVIDER)/2; arw[4].y = gw->g.height-1;
arw[5].x = (gw->g.width - gw->g.width/ARROWBODY_DIVIDER)/2; arw[5].y = gw->g.height/ARROWHEAD_DIVIDER;
arw[6].x = 0; arw[6].y = gw->g.height/ARROWHEAD_DIVIDER;
gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_fill);
gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_edge);
gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, justifyCenter);
} }
void gwinButtonDraw_ArrowDown(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { void gwinButtonDraw_ArrowDown(GWidgetObject *gw, void *param) {
(void) enabled; (void) param;
(void) isdown; GButtonColors * pcol;
(void) param; point arw[7];
point arw[7];
arw[0].x = gh->width/2; arw[0].y = gh->height-1; if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
arw[1].x = gh->width-1; arw[1].y = gh->height-1-gh->height/ARROWHEAD_DIVIDER; pcol = getDrawColors(gw);
arw[2].x = (gh->width + gh->width/ARROWBODY_DIVIDER)/2; arw[2].y = gh->height-1-gh->height/ARROWHEAD_DIVIDER;
arw[3].x = (gh->width + gh->width/ARROWBODY_DIVIDER)/2; arw[3].y = 0;
arw[4].x = (gh->width - gh->width/ARROWBODY_DIVIDER)/2; arw[4].y = 0;
arw[5].x = (gh->width - gh->width/ARROWBODY_DIVIDER)/2; arw[5].y = gh->height-1-gh->height/ARROWHEAD_DIVIDER;
arw[6].x = 0; arw[6].y = gh->height-1-gh->height/ARROWHEAD_DIVIDER;
gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill); arw[0].x = gw->g.width/2; arw[0].y = gw->g.height-1;
gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge); arw[1].x = gw->g.width-1; arw[1].y = gw->g.height-1-gw->g.height/ARROWHEAD_DIVIDER;
gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter); arw[2].x = (gw->g.width + gw->g.width/ARROWBODY_DIVIDER)/2; arw[2].y = gw->g.height-1-gw->g.height/ARROWHEAD_DIVIDER;
arw[3].x = (gw->g.width + gw->g.width/ARROWBODY_DIVIDER)/2; arw[3].y = 0;
arw[4].x = (gw->g.width - gw->g.width/ARROWBODY_DIVIDER)/2; arw[4].y = 0;
arw[5].x = (gw->g.width - gw->g.width/ARROWBODY_DIVIDER)/2; arw[5].y = gw->g.height-1-gw->g.height/ARROWHEAD_DIVIDER;
arw[6].x = 0; arw[6].y = gw->g.height-1-gw->g.height/ARROWHEAD_DIVIDER;
gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_fill);
gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_edge);
gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, justifyCenter);
} }
void gwinButtonDraw_ArrowLeft(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { void gwinButtonDraw_ArrowLeft(GWidgetObject *gw, void *param) {
(void) enabled; (void) param;
(void) isdown; GButtonColors * pcol;
(void) param; point arw[7];
point arw[7];
arw[0].x = 0; arw[0].y = gh->height/2; if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
arw[1].x = gh->width/ARROWHEAD_DIVIDER; arw[1].y = 0; pcol = getDrawColors(gw);
arw[2].x = gh->width/ARROWHEAD_DIVIDER; arw[2].y = (gh->height - gh->height/ARROWBODY_DIVIDER)/2;
arw[3].x = gh->width-1; arw[3].y = (gh->height - gh->height/ARROWBODY_DIVIDER)/2;
arw[4].x = gh->width-1; arw[4].y = (gh->height + gh->height/ARROWBODY_DIVIDER)/2;
arw[5].x = gh->width/ARROWHEAD_DIVIDER; arw[5].y = (gh->height + gh->height/ARROWBODY_DIVIDER)/2;
arw[6].x = gh->width/ARROWHEAD_DIVIDER; arw[6].y = gh->height-1;
gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill); arw[0].x = 0; arw[0].y = gw->g.height/2;
gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge); arw[1].x = gw->g.width/ARROWHEAD_DIVIDER; arw[1].y = 0;
gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter); arw[2].x = gw->g.width/ARROWHEAD_DIVIDER; arw[2].y = (gw->g.height - gw->g.height/ARROWBODY_DIVIDER)/2;
arw[3].x = gw->g.width-1; arw[3].y = (gw->g.height - gw->g.height/ARROWBODY_DIVIDER)/2;
arw[4].x = gw->g.width-1; arw[4].y = (gw->g.height + gw->g.height/ARROWBODY_DIVIDER)/2;
arw[5].x = gw->g.width/ARROWHEAD_DIVIDER; arw[5].y = (gw->g.height + gw->g.height/ARROWBODY_DIVIDER)/2;
arw[6].x = gw->g.width/ARROWHEAD_DIVIDER; arw[6].y = gw->g.height-1;
gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_fill);
gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_edge);
gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, justifyCenter);
} }
void gwinButtonDraw_ArrowRight(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { void gwinButtonDraw_ArrowRight(GWidgetObject *gw, void *param) {
(void) enabled; (void) param;
(void) isdown; GButtonColors * pcol;
(void) param; point arw[7];
point arw[7];
arw[0].x = gh->width-1; arw[0].y = gh->height/2; if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
arw[1].x = gh->width-1-gh->width/ARROWHEAD_DIVIDER; arw[1].y = 0; pcol = getDrawColors(gw);
arw[2].x = gh->width-1-gh->width/ARROWHEAD_DIVIDER; arw[2].y = (gh->height - gh->height/ARROWBODY_DIVIDER)/2;
arw[3].x = 0; arw[3].y = (gh->height - gh->height/ARROWBODY_DIVIDER)/2;
arw[4].x = 0; arw[4].y = (gh->height + gh->height/ARROWBODY_DIVIDER)/2;
arw[5].x = gh->width-1-gh->width/ARROWHEAD_DIVIDER; arw[5].y = (gh->height + gh->height/ARROWBODY_DIVIDER)/2;
arw[6].x = gh->width-1-gh->width/ARROWHEAD_DIVIDER; arw[6].y = gh->height-1;
gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill); arw[0].x = gw->g.width-1; arw[0].y = gw->g.height/2;
gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge); arw[1].x = gw->g.width-1-gw->g.width/ARROWHEAD_DIVIDER; arw[1].y = 0;
gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter); arw[2].x = gw->g.width-1-gw->g.width/ARROWHEAD_DIVIDER; arw[2].y = (gw->g.height - gw->g.height/ARROWBODY_DIVIDER)/2;
arw[3].x = 0; arw[3].y = (gw->g.height - gw->g.height/ARROWBODY_DIVIDER)/2;
arw[4].x = 0; arw[4].y = (gw->g.height + gw->g.height/ARROWBODY_DIVIDER)/2;
arw[5].x = gw->g.width-1-gw->g.width/ARROWHEAD_DIVIDER; arw[5].y = (gw->g.height + gw->g.height/ARROWBODY_DIVIDER)/2;
arw[6].x = gw->g.width-1-gw->g.width/ARROWHEAD_DIVIDER; arw[6].y = gw->g.height-1;
gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_fill);
gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_edge);
gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, justifyCenter);
} }
#endif #endif
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE #if GDISP_NEED_IMAGE || defined(__DOXYGEN__)
bool_t gwinAttachButtonMouse(GHandle gh, uint16_t instance) { void gwinButtonDraw_Image(GWidgetObject *gw, void *param) {
GSourceHandle gsh; GButtonColors * pcol;
coord_t sy;
if (gh->type != GW_BUTTON || !(gsh = ginputGetMouse(instance))) if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
return FALSE;
return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA); if (!(gw->g.flags & GWIN_FLG_ENABLED)) {
} pcol = &((GButtonObject *)gw)->c_dis;
#endif sy = 2 * gw->g.height;
} else if ((gw->g.flags & GBUTTON_FLG_PRESSED)) {
pcol = &((GButtonObject *)gw)->c_dn;
sy = gw->g.height;
} else {
pcol = &((GButtonObject *)gw)->c_up;
sy = 0;
}
#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE gdispImageDraw((gdispImage *)param, gw->g.x, gw->g.y, gw->g.width, gw->g.height, 0, sy);
bool_t gwinAttachButtonToggle(GHandle gh, uint16_t instance) { gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, justifyCenter);
GSourceHandle gsh;
if (gh->type != GW_BUTTON || !(gsh = ginputGetToggle(instance)))
return FALSE;
return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_TOGGLE_OFF|GLISTEN_TOGGLE_ON);
} }
#endif #endif

View File

@ -7,7 +7,7 @@
/** /**
* @file src/gwin/checkbox.c * @file src/gwin/checkbox.c
* @brief GWIN sub-system checkbox code. * @brief GWIN sub-system button code.
* *
* @defgroup Checkbox Checkbox * @defgroup Checkbox Checkbox
* @ingroup GWIN * @ingroup GWIN
@ -19,168 +19,137 @@
#if (GFX_USE_GWIN && GWIN_NEED_CHECKBOX) || defined(__DOXYGEN__) #if (GFX_USE_GWIN && GWIN_NEED_CHECKBOX) || defined(__DOXYGEN__)
static const GCheckboxColor defaultColors = { #include "gwin/class_gwin.h"
Grey, // border
Grey, // selected // Our checked state
Black // background #define GCHECKBOX_FLG_CHECKED (GWIN_FIRST_CONTROL_FLAG<<0)
// Prototypes for button VMT functions
static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y);
static void ToggleOn(GWidgetObject *gw, uint16_t instance);
// The button VMT table
static const gwidgetVMT checkboxVMT = {
{
"Checkbox", // The classname
_gwidgetDestroy, // The destroy routine
0, // The after-clear routine
},
gwinCheckboxDraw_CheckOnLeft, // The default drawing routine
MouseDown, // Process mouse down events
0, // Process mouse up events (NOT USED)
0, // Process mouse move events (NOT USED)
0, // Process toggle off events (NOT USED)
ToggleOn, // Process toggle on events
0, // Process dial move events (NOT USED)
0, // Process all events (NOT USED)
0, // AssignToggle (NOT USED)
0, // AssignDial (NOT USED)
}; };
/* default style drawing routine */ static const GCheckboxColors defaultColors = {
static void gwinCheckboxDrawDefaultStyle(GHandle gh, bool_t enabled, bool_t isChecked, void* param) { Black, // border
#define gcw ((GCheckboxObject *)gh) Grey, // selected
White, // background
Black, // text
};
(void) enabled; // Send the checkbox event
(void) param; static void SendCheckboxEvent(GWidgetObject *gw) {
GSourceListener * psl;
GEvent * pe;
#define pce ((GEventGWinCheckbox *)pe)
gdispDrawBox(gh->x, gh->y, gh->width, gh->height, gcw->colors->border); // Trigger a GWIN Checkbox Event
if (isChecked)
gdispFillArea(gh->x+2, gh->y+2, gh->width-4, gh->height-4, gcw->colors->checked);
else
gdispFillArea(gh->x+2, gh->y+2, gh->width-4, gh->height-4, gcw->colors->bg);
#undef gcw
}
/* process an event callback */
static void gwinCheckboxCallback(void *param, GEvent *pe) {
GSourceListener *psl;
#define gh ((GHandle)param)
#define gbw ((GCheckboxObject *)param)
#define gsh ((GSourceHandle)param)
#define pme ((GEventMouse *)pe)
#define pte ((GEventTouch *)pe)
#define pxe ((GEventToggle *)pe)
#define pbe ((GEventGWinCheckbox *)pe)
/* check if checkbox is disabled */
if (!gh->enabled)
return;
switch (pe->type) {
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
case GEVENT_MOUSE:
case GEVENT_TOUCH:
// Ignore anything other than the primary mouse button going up or down
if (!((pme->current_buttons ^ pme->last_buttons) & GINPUT_MOUSE_BTN_LEFT))
return;
if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)
&& pme->x >= gbw->gwin.x && pme->x < gbw->gwin.x + gbw->gwin.width
&& pme->y >= gbw->gwin.y && pme->y < gbw->gwin.y + gbw->gwin.height) {
gbw->isChecked = !gbw->isChecked;
gwinCheckboxDraw((GHandle)param);
break;
}
return;
#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */
default:
return;
}
// Trigger a GWIN checkbox event
psl = 0; psl = 0;
while ((psl = geventGetSourceListener(gsh, psl))) { while ((psl = geventGetSourceListener((GSourceHandle)gw, psl))) {
if (!(pe = geventGetEventBuffer(psl))) if (!(pe = geventGetEventBuffer(psl)))
continue; continue;
pbe->type = GEVENT_GWIN_CHECKBOX; pce->type = GEVENT_GWIN_CHECKBOX;
pbe->checkbox = gh; pce->checkbox = &gw->g;
pbe->isChecked = gbw->isChecked; pce->isChecked = (gw->g.flags & GCHECKBOX_FLG_CHECKED) ? TRUE : FALSE;
geventSendEvent(psl); geventSendEvent(psl);
} }
#undef gh #undef pce
#undef pbe
#undef pme
#undef pte
#undef pxe
#undef gsh
#undef gbw
} }
GHandle gwinCheckboxCreate(GCheckboxObject *gb, coord_t x, coord_t y, coord_t width, coord_t height) { // A mouse down has occurred over the checkbox
if (!(gb = (GCheckboxObject *)_gwinInit((GWindowObject *)gb, x, y, width, height, sizeof(GCheckboxObject)))) static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) {
(void) x; (void) y;
gw->g.flags ^= GCHECKBOX_FLG_CHECKED;
gwinDraw((GHandle)gw);
SendCheckboxEvent(gw);
}
// A toggle on has occurred
static void ToggleOn(GWidgetObject *gw, uint16_t instance) {
(void) instance;
gw->g.flags ^= GCHECKBOX_FLG_CHECKED;
gwinDraw((GHandle)gw);
SendCheckboxEvent(gw);
}
GHandle gwinCreateCheckbox(GCheckboxObject *gb, coord_t x, coord_t y, coord_t width, coord_t height) {
if (!(gb = (GCheckboxObject *)_gwidgetInit((GWidgetObject *)gb, x, y, width, height, sizeof(GCheckboxObject), &checkboxVMT)))
return 0; return 0;
gb->gwin.type = GW_CHECKBOX; // create a window of the type checkbox gb->c = defaultColors; // assign the default colors
gb->fn = gwinCheckboxDrawDefaultStyle; // set the default style drawing routine
gb->colors = &defaultColors; // asign the default colors
gb->param = 0; // some safe value here
gb->isChecked = GCHBX_UNCHECKED; // checkbox is currently unchecked
gb->gwin.enabled = TRUE; // checkboxes are enabled by default
geventListenerInit(&gb->listener);
geventRegisterCallback(&gb->listener, gwinCheckboxCallback, gb);
// checkboxes are enabled by default
gb->gwin.enabled = TRUE;
return (GHandle)gb; return (GHandle)gb;
} }
void gwinCheckboxSetCustom(GHandle gh, GCheckboxDrawFunction fn, void *param) { bool_t gwinIsCheckboxChecked(GHandle gh) {
#define gcw ((GCheckboxObject *)gh) if (gh->vmt != (gwinVMT *)&checkboxVMT)
return FALSE;
if (gh->type != GW_CHECKBOX) return (gh->flags & GCHECKBOX_FLG_CHECKED) ? TRUE : FALSE;
return;
gcw->fn = fn;
gcw->param = param;
#undef gcw
} }
void gwinCheckboxSetColors(GHandle gh, GCheckboxColors *pColors) {
void gwinCheckboxSetEnabled(GHandle gh, bool_t enabled) { if (gh->vmt != (gwinVMT *)&checkboxVMT)
if (gh->type != GW_CHECKBOX)
return; return;
gh->enabled = enabled; ((GCheckboxObject *)gh)->c = *pColors;
} }
void gwinCheckboxDraw(GHandle gh) { void gwinCheckboxDraw_CheckOnLeft(GWidgetObject *gw, void *param) {
#define gcw ((GCheckboxObject *)gh) #define gcw ((GCheckboxObject *)gw)
coord_t ld, df;
(void) param;
if (gh->type != GW_CHECKBOX) if (gw->g.vmt != (gwinVMT *)&checkboxVMT)
return; return;
#if GDISP_NEED_CLIP ld = gw->g.width < gw->g.height ? gw->g.width : gw->g.height;
//gdispSetClip(gh->x, gh->y, gh->width, gh->height); gdispFillArea(gw->g.x+1, gw->g.y+1, ld, ld-2, gcw->c.color_bg);
#endif gdispDrawBox(gw->g.x, gw->g.y, ld, ld, gcw->c.color_border);
gcw->fn(gh, df = ld < 4 ? 1 : 2;
gcw->gwin.enabled, if (gw->g.flags & GCHECKBOX_FLG_CHECKED)
gcw->isChecked, gdispFillArea(gw->g.x+df, gw->g.y+df, ld-2*df, ld-2*df, gcw->c.color_checked);
gcw->param);
gdispFillStringBox(gw->g.x+ld+1, gw->g.y, gw->g.width-ld-1, gw->g.height, gw->txt, gw->g.font, gcw->c.color_txt, gcw->c.color_bg, justifyLeft);
#undef gcw #undef gcw
} }
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE void gwinCheckboxDraw_CheckOnRight(GWidgetObject *gw, void *param) {
bool_t gwinCheckboxAttachMouse(GHandle gh, uint16_t instance) { #define gcw ((GCheckboxObject *)gw)
GSourceHandle gsh; coord_t ep, ld, df;
(void) param;
if (gh->type != GW_CHECKBOX || !(gsh = ginputGetMouse(instance))) if (gw->g.vmt != (gwinVMT *)&checkboxVMT)
return FALSE;
return geventAttachSource(&((GCheckboxObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA);
}
#endif
void gwinCheckboxSetColors(GHandle gh, color_t border, color_t checked, color_t bg) {
#define gcw ((GCheckboxObject *)gh)
if (gh->type != GW_CHECKBOX)
return; return;
gcw->colors->border = border; ld = gw->g.width < gw->g.height ? gw->g.width : gw->g.height;
gcw->colors->checked = checked, ep = gw->g.width-ld-1;
gcw->colors->bg = bg; gdispFillArea(gw->g.x+ep-1, gw->g.y+1, ld, ld-2, gcw->c.color_bg);
gdispDrawBox(gw->g.x+ep, gw->g.y, ld, ld, gcw->c.color_border);
df = ld < 4 ? 1 : 2;
if (gw->g.flags & GCHECKBOX_FLG_CHECKED)
gdispFillArea(gw->g.x+ep+df, gw->g.y+df, ld-2*df, ld-2*df, gcw->c.color_checked);
gdispFillStringBox(gw->g.x, gw->g.y, ep, gw->g.height, gw->txt, gw->g.font, gcw->c.color_txt, gcw->c.color_bg, justifyRight);
#undef gcw #undef gcw
} }

View File

@ -8,20 +8,15 @@
/** /**
* @file src/gwin/console.c * @file src/gwin/console.c
* @brief GWIN sub-system console code. * @brief GWIN sub-system console code.
*
* @defgroup Console Console
* @ingroup GWIN
*
* @{
*/ */
#include "gfx.h" #include "gfx.h"
#if (GFX_USE_GWIN && GWIN_NEED_CONSOLE) || defined(__DOXYGEN__) #if GFX_USE_GWIN && GWIN_NEED_CONSOLE
#include <string.h> #include <string.h>
#include "gwin/internal.h" #include "gwin/class_gwin.h"
#define GWIN_CONSOLE_USE_CLEAR_LINES TRUE #define GWIN_CONSOLE_USE_CLEAR_LINES TRUE
#define GWIN_CONSOLE_USE_FILLED_CHARS FALSE #define GWIN_CONSOLE_USE_FILLED_CHARS FALSE
@ -58,11 +53,20 @@
}; };
#endif #endif
GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t width, coord_t height, font_t font) { static void AfterClear(GWindowObject *gh) {
if (!(gc = (GConsoleObject *)_gwinInit((GWindowObject *)gc, x, y, width, height, sizeof(GConsoleObject)))) ((GConsoleObject *)gh)->cx = 0;
((GConsoleObject *)gh)->cy = 0;
}
static const gwinVMT consoleVMT = {
"Console", // The classname
0, // The destroy routine
AfterClear, // The after-clear routine
};
GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t width, coord_t height) {
if (!(gc = (GConsoleObject *)_gwinInit((GWindowObject *)gc, x, y, width, height, sizeof(GConsoleObject), &consoleVMT)))
return 0; return 0;
gc->gwin.type = GW_CONSOLE;
gwinSetFont(&gc->gwin, font);
#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM #if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
gc->stream.vmt = &GWindowConsoleVMT; gc->stream.vmt = &GWindowConsoleVMT;
#endif #endif
@ -73,17 +77,21 @@ GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t widt
#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM #if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
BaseSequentialStream *gwinGetConsoleStream(GHandle gh) { BaseSequentialStream *gwinGetConsoleStream(GHandle gh) {
if (gh->type != GW_CONSOLE) if (gh->vmt != &consoleVMT)
return 0; return 0;
return (BaseSequentialStream *)&(((GConsoleObject *)(gh))->stream); return (BaseSequentialStream *)&(((GConsoleObject *)(gh))->stream);
} }
#endif #endif
void gwinPutChar(GHandle gh, char c) { void gwinPutChar(GHandle gh, char c) {
uint8_t width;
#define gcw ((GConsoleObject *)gh) #define gcw ((GConsoleObject *)gh)
uint8_t width, fy, fp;
if (gh->type != GW_CONSOLE || !gh->font) return; if (gh->vmt != &consoleVMT || !gh->font)
return;
fy = gdispGetFontMetric(gh->font, fontHeight);
fp = gdispGetFontMetric(gh->font, fontCharPadding);
#if GDISP_NEED_CLIP #if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height); gdispSetClip(gh->x, gh->y, gh->width, gh->height);
@ -91,24 +99,24 @@ void gwinPutChar(GHandle gh, char c) {
if (c == '\n') { if (c == '\n') {
gcw->cx = 0; gcw->cx = 0;
gcw->cy += gcw->fy; gcw->cy += fy;
// We use lazy scrolling here and only scroll when the next char arrives // We use lazy scrolling here and only scroll when the next char arrives
} else if (c == '\r') { } else if (c == '\r') {
// gcw->cx = 0; // gcw->cx = 0;
} else { } else {
width = gdispGetCharWidth(c, gh->font) + gcw->fp; width = gdispGetCharWidth(c, gh->font) + fp;
if (gcw->cx + width >= gh->width) { if (gcw->cx + width >= gh->width) {
gcw->cx = 0; gcw->cx = 0;
gcw->cy += gcw->fy; gcw->cy += fy;
} }
if (gcw->cy + gcw->fy > gh->height) { if (gcw->cy + fy > gh->height) {
#if GDISP_NEED_SCROLL #if GDISP_NEED_SCROLL
/* scroll the console */ /* scroll the console */
gdispVerticalScroll(gh->x, gh->y, gh->width, gh->height, gcw->fy, gh->bgcolor); gdispVerticalScroll(gh->x, gh->y, gh->width, gh->height, fy, gh->bgcolor);
/* reset the cursor to the start of the last line */ /* reset the cursor to the start of the last line */
gcw->cx = 0; gcw->cx = 0;
gcw->cy = (((coord_t)(gh->height/gcw->fy))-1)*gcw->fy; gcw->cy = (((coord_t)(gh->height/fy))-1)*fy;
#else #else
/* clear the console */ /* clear the console */
gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor); gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
@ -121,7 +129,7 @@ void gwinPutChar(GHandle gh, char c) {
#if GWIN_CONSOLE_USE_CLEAR_LINES #if GWIN_CONSOLE_USE_CLEAR_LINES
/* clear to the end of the line */ /* clear to the end of the line */
if (gcw->cx == 0) if (gcw->cx == 0)
gdispFillArea(gh->x, gh->y + gcw->cy, gh->width, gcw->fy, gh->bgcolor); gdispFillArea(gh->x, gh->y + gcw->cy, gh->width, fy, gh->bgcolor);
#endif #endif
#if GWIN_CONSOLE_USE_FILLED_CHARS #if GWIN_CONSOLE_USE_FILLED_CHARS
gdispFillChar(gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, gh->color, gh->bgcolor); gdispFillChar(gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, gh->color, gh->bgcolor);
@ -200,7 +208,8 @@ void gwinPrintf(GHandle gh, const char *fmt, ...) {
char tmpbuf[MAX_FILLER + 1]; char tmpbuf[MAX_FILLER + 1];
#endif #endif
if (gh->type != GW_CONSOLE || !gh->font) return; if (gh->vmt != &consoleVMT || !gh->font)
return;
va_start(ap, fmt); va_start(ap, fmt);
while (TRUE) { while (TRUE) {
@ -343,5 +352,5 @@ void gwinPrintf(GHandle gh, const char *fmt, ...) {
} }
#endif /* GFX_USE_GWIN && GWIN_NEED_CONSOLE */ #endif /* GFX_USE_GWIN && GWIN_NEED_CONSOLE */
/** @} */

View File

@ -8,18 +8,13 @@
/** /**
* @file src/gwin/graph.c * @file src/gwin/graph.c
* @brief GWIN sub-system button code. * @brief GWIN sub-system button code.
*
* @defgroup Graph Graph
* @ingroup GWIN
*
* @{
*/ */
#include "gfx.h" #include "gfx.h"
#if (GFX_USE_GWIN && GWIN_NEED_GRAPH) || defined(__DOXYGEN__) #if GFX_USE_GWIN && GWIN_NEED_GRAPH
#include "gwin/internal.h" #include "gwin/class_gwin.h"
#define GGRAPH_FLG_CONNECTPOINTS (GWIN_FIRST_CONTROL_FLAG<<0) #define GGRAPH_FLG_CONNECTPOINTS (GWIN_FIRST_CONTROL_FLAG<<0)
#define GGRAPH_ARROW_SIZE 5 #define GGRAPH_ARROW_SIZE 5
@ -34,13 +29,19 @@ static const GGraphStyle GGraphDefaultStyle = {
GWIN_GRAPH_STYLE_XAXIS_ARROWS|GWIN_GRAPH_STYLE_YAXIS_ARROWS // flags GWIN_GRAPH_STYLE_XAXIS_ARROWS|GWIN_GRAPH_STYLE_YAXIS_ARROWS // flags
}; };
static const gwinVMT graphVMT = {
"Graph", // The classname
0, // The destroy routine
0, // The after-clear routine
};
static void pointto(GGraphObject *gg, coord_t x, coord_t y, const GGraphPointStyle *style) { static void pointto(GGraphObject *gg, coord_t x, coord_t y, const GGraphPointStyle *style) {
if (style->type == GGRAPH_POINT_NONE) if (style->type == GGRAPH_POINT_NONE)
return; return;
// Convert to device space. Note the y-axis is inverted. // Convert to device space. Note the y-axis is inverted.
x += gg->gwin.x + gg->xorigin; x += gg->g.x + gg->xorigin;
y = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y; y = gg->g.y + gg->g.height - 1 - gg->yorigin - y;
if (style->size <= 1) { if (style->size <= 1) {
gdispDrawPixel(x, y, style->color); gdispDrawPixel(x, y, style->color);
@ -73,10 +74,10 @@ static void lineto(GGraphObject *gg, coord_t x0, coord_t y0, coord_t x1, coord_t
return; return;
// Convert to device space. Note the y-axis is inverted. // Convert to device space. Note the y-axis is inverted.
x0 += gg->gwin.x + gg->xorigin; x0 += gg->g.x + gg->xorigin;
y0 = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y0; y0 = gg->g.y + gg->g.height - 1 - gg->yorigin - y0;
x1 += gg->gwin.x + gg->xorigin; x1 += gg->g.x + gg->xorigin;
y1 = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y1; y1 = gg->g.y + gg->g.height - 1 - gg->yorigin - y1;
if (style->size <= 0) { if (style->size <= 0) {
// Use the driver to draw a solid line // Use the driver to draw a solid line
@ -163,41 +164,26 @@ static void lineto(GGraphObject *gg, coord_t x0, coord_t y0, coord_t x1, coord_t
} }
GHandle gwinCreateGraph(GGraphObject *gg, coord_t x, coord_t y, coord_t width, coord_t height) { GHandle gwinCreateGraph(GGraphObject *gg, coord_t x, coord_t y, coord_t width, coord_t height) {
if (!(gg = (GGraphObject *)_gwinInit((GWindowObject *)gg, x, y, width, height, sizeof(GGraphObject)))) if (!(gg = (GGraphObject *)_gwinInit((GWindowObject *)gg, x, y, width, height, sizeof(GGraphObject), &graphVMT)))
return 0; return 0;
gg->gwin.type = GW_GRAPH;
gg->xorigin = gg->yorigin = 0; gg->xorigin = gg->yorigin = 0;
gg->lastx = gg->lasty = 0; gg->lastx = gg->lasty = 0;
gwinGraphSetStyle(&gg->gwin, &GGraphDefaultStyle); gwinGraphSetStyle((GHandle)gg, &GGraphDefaultStyle);
return (GHandle)gg; return (GHandle)gg;
} }
void gwinGraphSetStyle(GHandle gh, const GGraphStyle *pstyle) { void gwinGraphSetStyle(GHandle gh, const GGraphStyle *pstyle) {
#define gg ((GGraphObject *)gh) #define gg ((GGraphObject *)gh)
if (gh->type != GW_GRAPH) if (gh->vmt != &graphVMT)
return; return;
gg->style.point.type = pstyle->point.type; gg->style.point = pstyle->point;
gg->style.point.size = pstyle->point.size; gg->style.line = pstyle->line;
gg->style.point.color = pstyle->point.color; gg->style.xaxis = pstyle->xaxis;
gg->style.line.type = pstyle->line.type; gg->style.yaxis = pstyle->yaxis;
gg->style.line.size = pstyle->line.size; gg->style.xgrid = pstyle->xgrid;
gg->style.line.color = pstyle->line.color; gg->style.ygrid = pstyle->ygrid;
gg->style.xaxis.type = pstyle->xaxis.type;
gg->style.xaxis.size = pstyle->xaxis.size;
gg->style.xaxis.color = pstyle->xaxis.color;
gg->style.yaxis.type = pstyle->yaxis.type;
gg->style.yaxis.size = pstyle->yaxis.size;
gg->style.yaxis.color = pstyle->yaxis.color;
gg->style.xgrid.type = pstyle->xgrid.type;
gg->style.xgrid.size = pstyle->xgrid.size;
gg->style.xgrid.color = pstyle->xgrid.color;
gg->style.xgrid.spacing = pstyle->xgrid.spacing;
gg->style.ygrid.type = pstyle->ygrid.type;
gg->style.ygrid.size = pstyle->ygrid.size;
gg->style.ygrid.color = pstyle->ygrid.color;
gg->style.ygrid.spacing = pstyle->ygrid.spacing;
gg->style.flags = pstyle->flags; gg->style.flags = pstyle->flags;
#undef gg #undef gg
@ -206,7 +192,7 @@ void gwinGraphSetStyle(GHandle gh, const GGraphStyle *pstyle) {
void gwinGraphSetOrigin(GHandle gh, coord_t x, coord_t y) { void gwinGraphSetOrigin(GHandle gh, coord_t x, coord_t y) {
#define gg ((GGraphObject *)gh) #define gg ((GGraphObject *)gh)
if (gh->type != GW_GRAPH) if (gh->vmt != &graphVMT)
return; return;
gg->xorigin = x; gg->xorigin = x;
@ -219,7 +205,7 @@ void gwinGraphDrawAxis(GHandle gh) {
#define gg ((GGraphObject *)gh) #define gg ((GGraphObject *)gh)
coord_t i, xmin, ymin, xmax, ymax; coord_t i, xmin, ymin, xmax, ymax;
if (gh->type != GW_GRAPH) if (gh->vmt != &graphVMT)
return; return;
xmin = -gg->xorigin; xmin = -gg->xorigin;
@ -277,7 +263,7 @@ void gwinGraphDrawAxis(GHandle gh) {
} }
void gwinGraphStartSet(GHandle gh) { void gwinGraphStartSet(GHandle gh) {
if (gh->type != GW_GRAPH) if (gh->vmt != &graphVMT)
return; return;
gh->flags &= ~GGRAPH_FLG_CONNECTPOINTS; gh->flags &= ~GGRAPH_FLG_CONNECTPOINTS;
@ -286,7 +272,7 @@ void gwinGraphStartSet(GHandle gh) {
void gwinGraphDrawPoint(GHandle gh, coord_t x, coord_t y) { void gwinGraphDrawPoint(GHandle gh, coord_t x, coord_t y) {
#define gg ((GGraphObject *)gh) #define gg ((GGraphObject *)gh)
if (gh->type != GW_GRAPH) if (gh->vmt != &graphVMT)
return; return;
if ((gh->flags & GGRAPH_FLG_CONNECTPOINTS)) { if ((gh->flags & GGRAPH_FLG_CONNECTPOINTS)) {
@ -314,7 +300,7 @@ void gwinGraphDrawPoints(GHandle gh, const point *points, unsigned count) {
unsigned i; unsigned i;
const point *p; const point *p;
if (gh->type != GW_GRAPH) if (gh->vmt != &graphVMT)
return; return;
// Draw the connecting lines // Draw the connecting lines
@ -344,5 +330,3 @@ void gwinGraphDrawPoints(GHandle gh, const point *points, unsigned count) {
} }
#endif /* GFX_USE_GWIN && GWIN_NEED_GRAPH */ #endif /* GFX_USE_GWIN && GWIN_NEED_GRAPH */
/** @} */

254
src/gwin/gwidget.c 100644
View File

@ -0,0 +1,254 @@
/*
* This file is subject to the terms of the GFX License, v1.0. If a copy of
* the license was not distributed with this file, you can obtain one at:
*
* http://chibios-gfx.com/license.html
*/
#include "gfx.h"
#if GFX_USE_GWIN
#include <string.h>
#include "gwin/class_gwin.h"
/* We use these everywhere in this file */
#define gw ((GWidgetObject *)gh)
#define wvmt ((gwidgetVMT *)gh->vmt)
static void gwidgetCallback(void *param, GEvent *pe) {
#define gh ((GWindowObject *)param)
#define pme ((GEventMouse *)pe)
#define pte ((GEventToggle *)pe)
#define pde ((GEventDial *)pe)
// check if widget is disabled
if (!(gw->g.flags & GWIN_FLG_ENABLED))
return;
// Process via AllEvents() if it is defined
if (wvmt->AllEvents)
wvmt->AllEvents(gw, pe);
// Process various events
switch (pe->type) {
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
case GEVENT_MOUSE:
case GEVENT_TOUCH:
// Are we captured?
if ((gw->g.flags & GWIN_FLG_MOUSECAPTURE)) {
if (pme->meta == GMETA_MOUSE_UP) {
gw->g.flags &= ~GWIN_FLG_MOUSECAPTURE;
if (wvmt->MouseUp)
wvmt->MouseUp(gw, pme->x - gw->g.x, pme->y - gw->g.y);
return;
} else if (wvmt->MouseMove)
wvmt->MouseMove(gw, pme->x - gw->g.x, pme->y - gw->g.y);
// We are not captured - look for mouse downs over the widget
} else if (pme->meta == GMETA_MOUSE_DOWN
&& pme->x >= gw->g.x && pme->x < gw->g.x + gw->g.width
&& pme->y >= gw->g.y && pme->y < gw->g.y + gw->g.height) {
gw->g.flags |= GWIN_FLG_MOUSECAPTURE;
if (wvmt->MouseDown)
wvmt->MouseDown(gw, pme->x - gw->g.x, pme->y - gw->g.y);
}
break;
#endif
#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
case GEVENT_TOGGLE:
if (pte->on) {
if (wvmt->ToggleOn)
wvmt->ToggleOn(gw, pte->instance);
} else {
if (wvmt->ToggleOff)
wvmt->ToggleOff(gw, pte->instance);
}
break;
#endif
#if GFX_USE_GINPUT && GINPUT_NEED_DIAL
case GEVENT_DIAL:
if (wvmt->DialMove)
wvmt->DialMove(gw, pde->instance, pde->value);
break;
#endif
default:
break;
}
#undef gh
#undef pme
#undef pte
#undef pde
}
GHandle _gwidgetInit(GWidgetObject *pgw, coord_t x, coord_t y, coord_t width, coord_t height, size_t size, const gwidgetVMT *vmt) {
if (!(pgw = (GWidgetObject *)_gwinInit((GWindowObject *)pgw, x, y, width, height, size, (const gwinVMT *)vmt)))
return 0;
pgw->g.flags |= (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED);
pgw->txt = "";
pgw->fnDraw = vmt->DefaultDraw;
pgw->fnParam = 0;
geventListenerInit(&pgw->listener);
geventRegisterCallback(&pgw->listener, gwidgetCallback, pgw);
return (GHandle)pgw;
}
void _gwidgetDestroy(GHandle gh) {
if (!(gh->flags & GWIN_FLG_WIDGET))
return;
// Deallocate the text (if necessary)
if ((gh->flags & GWIN_FLG_ALLOCTXT)) {
gh->flags &= ~GWIN_FLG_ALLOCTXT;
gfxFree((void *)gw->txt);
}
// Untangle the listeners (both on us and to us).
geventDetachSource(&gw->listener, 0);
geventDetachSourceListeners((GSourceHandle)gh);
gh->flags &= ~GWIN_FLG_WIDGET;
}
void gwinSetEnabled(GHandle gh, bool_t enabled) {
if (!(gh->flags & GWIN_FLG_WIDGET))
return;
if (enabled)
gh->flags |= GWIN_FLG_ENABLED;
else
gh->flags &= ~GWIN_FLG_ENABLED;
}
void gwinDraw(GHandle gh) {
if (!(gh->flags & GWIN_FLG_WIDGET))
return;
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
gw->fnDraw(gw, gw->fnParam);
}
void gwinSetText(GHandle gh, const char *txt, bool_t useAlloc) {
if (!(gh->flags & GWIN_FLG_WIDGET))
return;
// Dispose of the old string
if ((gh->flags & GWIN_FLG_ALLOCTXT)) {
gh->flags &= ~GWIN_FLG_ALLOCTXT;
if (gw->txt) {
gfxFree((void *)gw->txt);
gw->txt = "";
}
}
// Alloc the new text if required
if (txt && !*txt) txt = 0;
if (txt && useAlloc) {
char *str;
if ((str = (char *)gfxAlloc(strlen(txt)+1))) {
gh->flags |= GWIN_FLG_ALLOCTXT;
strcpy(str, txt);
}
txt = (const char *)str;
}
gw->txt = txt ? txt : "";
}
const char *gwinGetText(GHandle gh) {
if (!(gh->flags & GWIN_FLG_WIDGET))
return 0;
return gw->txt;
}
void gwinSetCustomDraw(GHandle gh, CustomWidgetDrawFunction fn, void *param) {
if (!(gh->flags & GWIN_FLG_WIDGET))
return;
gw->fnDraw = fn ? fn : wvmt->DefaultDraw;
gw->fnParam = param;
}
bool_t gwinAttachListener(GHandle gh, GListener *pl, unsigned flags) {
if (!(gh->flags & GWIN_FLG_WIDGET))
return FALSE;
return geventAttachSource(pl, (GSourceHandle)gh, flags);
}
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
bool_t gwinAttachMouse(GHandle gh, uint16_t instance) {
GSourceHandle gsh;
unsigned flags;
if (!(gh->flags & GWIN_FLG_WIDGET))
return FALSE;
if (!wvmt->MouseDown && !wvmt->MouseMove && !wvmt->MouseUp)
return FALSE;
if (!(gsh = ginputGetMouse(instance)))
return FALSE;
flags = wvmt->MouseMove ? (GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES) : GLISTEN_MOUSEMETA;
return geventAttachSource(&gw->listener, gsh, flags);
}
#endif
#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
bool_t gwinAttachToggle(GHandle gh, uint16_t role, uint16_t instance) {
GSourceHandle gsh;
unsigned flags;
if (!(gh->flags & GWIN_FLG_WIDGET))
return FALSE;
flags = 0;
if (wvmt->ToggleOff) flags |= GLISTEN_TOGGLE_OFF;
if (wvmt->ToggleOn) flags |= GLISTEN_TOGGLE_ON;
if (!flags)
return FALSE;
if (!(gsh = ginputGetToggle(instance)))
return FALSE;
if (wvmt->AssignToggle && !wvmt->AssignToggle(gw, role, instance))
return FALSE;
return geventAttachSource(&gw->listener, gsh, flags);
}
#endif
#if GFX_USE_GINPUT && GINPUT_NEED_DIAL
bool_t gwinAttachDial(GHandle gh, uint16_t role, uint16_t instance) {
GSourceHandle gsh;
if (!(gh->flags & GWIN_FLG_WIDGET))
return FALSE;
if (!wvmt->DialMove)
return FALSE;
if (!(gsh = ginputGetDial(instance)))
return FALSE;
if (wvmt->AssignDial && !wvmt->AssignDial(gw, role, instance))
return FALSE;
return geventAttachSource(&gw->listener, gsh, 0);
}
#endif
#endif /* GFX_USE_GWIN */
/** @} */

View File

@ -9,11 +9,19 @@
#if GFX_USE_GWIN #if GFX_USE_GWIN
#include "gwin/internal.h" #include "gwin/class_gwin.h"
static const gwinVMT basegwinVMT = {
"GWIN", // The classname
0, // The destroy routine
0, // The after-clear routine
};
static font_t defaultFont;
// Internal routine for use by GWIN components only // Internal routine for use by GWIN components only
// Initialise a window creating it dynamicly if required. // Initialise a window creating it dynamicly if required.
GHandle _gwinInit(GWindowObject *gw, coord_t x, coord_t y, coord_t width, coord_t height, size_t size) { GHandle _gwinInit(GWindowObject *pgw, coord_t x, coord_t y, coord_t width, coord_t height, size_t size, const gwinVMT *vmt) {
coord_t w, h; coord_t w, h;
// Check the window size against the screen size // Check the window size against the screen size
@ -26,60 +34,34 @@ GHandle _gwinInit(GWindowObject *gw, coord_t x, coord_t y, coord_t width, coord_
if (y+height > h) height = h - y; if (y+height > h) height = h - y;
// Allocate the structure if necessary // Allocate the structure if necessary
if (!gw) { if (!pgw) {
if (!(gw = (GWindowObject *)gfxAlloc(size))) if (!(pgw = (GWindowObject *)gfxAlloc(size)))
return 0; return 0;
gw->flags = GWIN_FLG_DYNAMIC; pgw->flags = GWIN_FLG_DYNAMIC;
} else } else
gw->flags = 0; pgw->flags = 0;
// Initialise all basic fields (except the type) // Initialise all basic fields
gw->x = x; pgw->vmt = vmt;
gw->y = y; pgw->x = x;
gw->width = width; pgw->y = y;
gw->height = height; pgw->width = width;
gw->color = White; pgw->height = height;
gw->bgcolor = Black; pgw->color = White;
pgw->bgcolor = Black;
#if GDISP_NEED_TEXT #if GDISP_NEED_TEXT
gw->font = 0; pgw->font = defaultFont;
#endif #endif
return (GHandle)gw; return (GHandle)pgw;
} }
GHandle gwinCreateWindow(GWindowObject *gw, coord_t x, coord_t y, coord_t width, coord_t height) { GHandle gwinCreateWindow(GWindowObject *pgw, coord_t x, coord_t y, coord_t width, coord_t height) {
if (!(gw = (GWindowObject *)_gwinInit((GWindowObject *)gw, x, y, width, height, sizeof(GWindowObject)))) return _gwinInit(pgw, x, y, width, height, sizeof(GWindowObject), &basegwinVMT);
return 0;
gw->type = GW_WINDOW;
return (GHandle)gw;
} }
void gwinSetEnabled(GHandle gh, bool_t enabled) { void gwinDestroy(GHandle gh) {
(void)gh; if (gh->vmt->Destroy)
(void)enabled; gh->vmt->Destroy(gh);
}
void gwinDestroyWindow(GHandle gh) {
// Clean up any type specific dynamic memory allocations
switch(gh->type) {
#if GWIN_NEED_BUTTON
case GW_BUTTON:
if ((gh->flags & GBTN_FLG_ALLOCTXT)) {
gh->flags &= ~GBTN_FLG_ALLOCTXT; // To be sure, to be sure
gfxFree((void *)((GButtonObject *)gh)->txt);
}
geventDetachSource(&((GButtonObject *)gh)->listener, 0);
geventDetachSourceListeners((GSourceHandle)gh);
break;
#endif
#if GWIN_NEED_SLIDER
case GW_SLIDER:
geventDetachSource(&((GSliderObject *)gh)->listener, 0);
geventDetachSourceListeners((GSourceHandle)gh);
break;
#endif
default:
break;
}
// Clean up the structure // Clean up the structure
if (gh->flags & GWIN_FLG_DYNAMIC) { if (gh->flags & GWIN_FLG_DYNAMIC) {
@ -88,30 +70,17 @@ void gwinDestroyWindow(GHandle gh) {
} }
} }
void gwinDraw(GHandle gh) { const char *gwinGetClassName(GHandle gh) {
switch(gh->type) { return gh->vmt->classname;
#if GWIN_NEED_BUTTON
case GW_BUTTON:
gwinButtonDraw(gh);
break;
#endif
#if GWIN_NEED_SLIDER
case GW_SLIDER:
gwinSliderDraw(gh);
break;
#endif
}
} }
#if GDISP_NEED_TEXT #if GDISP_NEED_TEXT
void gwinSetDefaultFont(font_t font) {
defaultFont = font;
}
void gwinSetFont(GHandle gh, font_t font) { void gwinSetFont(GHandle gh, font_t font) {
gh->font = font; gh->font = font;
#if GWIN_NEED_CONSOLE
if (font && gh->type == GW_CONSOLE) {
((GConsoleObject *)gh)->fy = gdispGetFontMetric(font, fontHeight);
((GConsoleObject *)gh)->fp = gdispGetFontMetric(font, fontCharPadding);
}
#endif
} }
#endif #endif
@ -120,13 +89,8 @@ void gwinClear(GHandle gh) {
gdispSetClip(gh->x, gh->y, gh->width, gh->height); gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif #endif
gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor); gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
if (gh->vmt->AfterClear)
#if GWIN_NEED_CONSOLE gh->vmt->AfterClear(gh);
if (gh->type == GW_CONSOLE) {
((GConsoleObject *)gh)->cx = 0;
((GConsoleObject *)gh)->cy = 0;
}
#endif
} }
void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) { void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) {

View File

@ -1,7 +1,8 @@
GFXSRC += $(GFXLIB)/src/gwin/gwin.c \ GFXSRC += $(GFXLIB)/src/gwin/gwin.c \
$(GFXLIB)/src/gwin/gwidget.c \
$(GFXLIB)/src/gwin/console.c \ $(GFXLIB)/src/gwin/console.c \
$(GFXLIB)/src/gwin/graph.c \
$(GFXLIB)/src/gwin/button.c \ $(GFXLIB)/src/gwin/button.c \
$(GFXLIB)/src/gwin/slider.c \ $(GFXLIB)/src/gwin/slider.c \
$(GFXLIB)/src/gwin/graph.c \
$(GFXLIB)/src/gwin/checkbox.c \ $(GFXLIB)/src/gwin/checkbox.c \

View File

@ -19,140 +19,168 @@
#if (GFX_USE_GWIN && GWIN_NEED_SLIDER) || defined(__DOXYGEN__) #if (GFX_USE_GWIN && GWIN_NEED_SLIDER) || defined(__DOXYGEN__)
#include "gwin/internal.h" #include "gwin/class_gwin.h"
#ifndef GWIN_SLIDER_DEAD_BAND #ifndef GWIN_SLIDER_DEAD_BAND
#define GWIN_SLIDER_DEAD_BAND 5 #define GWIN_SLIDER_DEAD_BAND 5
#endif #endif
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE // Prototypes for slider VMT functions
static void trackSliderDraw(GHandle gh, coord_t x, coord_t y); static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y);
#endif static void MouseMove(GWidgetObject *gw, coord_t x, coord_t y);
static void DialMove(GWidgetObject *gw, uint16_t instance, uint16_t value);
static const GSliderDrawStyle GSliderDefaultStyle = { // The button VMT table
HTML2COLOR(0x404040), // color_edge; static const gwidgetVMT sliderVMT = {
HTML2COLOR(0x000000), // color_thumb; {
HTML2COLOR(0x00E000), // color_active; "Slider", // The classname
HTML2COLOR(0xE0E0E0), // color_inactive; _gwidgetDestroy, // The destroy routine
0, // The after-clear routine
},
gwinSliderDraw_Std, // The default drawing routine
MouseMove, // Process mouse down events (AS MOUSEMOVE)
MouseUp, // Process mouse up events
MouseMove, // Process mouse move events
0, // Process toggle off events (NOT USED)
0, // Process toggle on events (NOT USED)
DialMove, // Process dial move events
0, // Process all events (NOT USED)
0, // AssignToggle (NOT USED)
0, // AssignDial (NOT USED)
}; };
// Process an event callback static const GSliderColors GSliderDefaultColors = {
static void gwinSliderCallback(void *param, GEvent *pe) { HTML2COLOR(0x404040), // color_edge
GSourceListener *psl; HTML2COLOR(0x000000), // color_thumb
#define gh ((GHandle)param) HTML2COLOR(0x00E000), // color_active
#define gsw ((GSliderObject *)param) HTML2COLOR(0xE0E0E0), // color_inactive
#define gsh ((GSourceHandle)param) HTML2COLOR(0xFFFFFF), // color_txt
#define pme ((GEventMouse *)pe) };
#define pde ((GEventDial *)pe)
#define pse ((GEventGWinSlider *)pe)
switch (pe->type) { // Send the slider event
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE static void SendSliderEvent(GWidgetObject *gw) {
case GEVENT_MOUSE: GSourceListener * psl;
case GEVENT_TOUCH: GEvent * pe;
// If not tracking we only only interested in a mouse down over the slider #define pse ((GEventGWinSlider *)pe)
if (!gsw->tracking) {
if ((pme->meta & GMETA_MOUSE_DOWN)
&& pme->x >= gh->x && pme->x < gh->x + gh->width
&& pme->y >= gh->y && pme->y < gh->y + gh->height) {
gsw->tracking = TRUE;
trackSliderDraw(gh, pme->x-gh->x, pme->y-gh->y);
}
return;
}
// We are tracking the mouse // Trigger a GWIN Button Event
// Test for button up
if ((pme->meta & GMETA_MOUSE_UP)) {
gsw->tracking = FALSE;
#if !GWIN_BUTTON_LAZY_RELEASE
// Are we over the slider?
if (pme->x < gh->x || pme->x >= gh->x + gh->width
|| pme->y < gh->y || pme->y >= gh->y + gh->height) {
// No - restore the slider
gwinSliderDraw(gh);
return;
}
#endif
// Set the new position
if (gh->width < gh->height)
gwinSetSliderPosition(gh,
(uint16_t)((uint32_t)(gh->height-1-pme->y+gh->y-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->height-2*GWIN_SLIDER_DEAD_BAND) + gsw->min));
else
gwinSetSliderPosition(gh,
(uint16_t)((uint32_t)(pme->x-gh->x-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->width-2*GWIN_SLIDER_DEAD_BAND) + gsw->min));
// Update the display
gwinSliderDraw(gh);
// Generate the event
break;
}
// If mouse down - track movement
if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT))
trackSliderDraw(gh, pme->x-gh->x, pme->y-gh->y);
return;
#endif
#if GFX_USE_GINPUT && GINPUT_NEED_DIAL
case GEVENT_DIAL:
// Set the new position
gwinSetSliderPosition(gh, (uint16_t)((uint32_t)pde->value*(gsw->max-gsw->min)/ginputGetDialRange(pde->instance) + gsw->min));
// Update the display
gwinSliderDraw(gh);
// Generate the event
break;
#endif
default:
return;
}
// Trigger a GWIN Slider Event
psl = 0; psl = 0;
while ((psl = geventGetSourceListener(gsh, psl))) { while ((psl = geventGetSourceListener((GSourceHandle)gw, psl))) {
if (!(pe = geventGetEventBuffer(psl))) if (!(pe = geventGetEventBuffer(psl)))
continue; continue;
pse->type = GEVENT_GWIN_SLIDER; pse->type = GEVENT_GWIN_SLIDER;
pse->slider = gh; pse->slider = (GHandle)gw;
pse->position = gsw->pos; pse->position = ((GSliderObject *)gw)->pos;
geventSendEvent(psl); geventSendEvent(psl);
} }
#undef pse #undef pbe
#undef pme }
#undef pxe
#undef gsh // Reset the display position back to the value predicted by the saved slider position
#undef gsw static void ResetDisplayPos(GSliderObject *gsw) {
if (gsw->w.g.width < gsw->w.g.height)
gsw->dpos = gsw->w.g.height-1-((gsw->w.g.height-1)*(gsw->pos-gsw->min))/(gsw->max-gsw->min);
else
gsw->dpos = ((gsw->w.g.width-1)*(gsw->pos-gsw->min))/(gsw->max-gsw->min);
}
// A mouse up event
static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y) {
#define gsw ((GSliderObject *)gw)
#define gh ((GHandle)gw)
#if GWIN_BUTTON_LAZY_RELEASE
// Clip to the slider
if (x < 0) x = 0;
else if (x >= gh->width) x = gh->width-1;
if (y < 0) y = 0;
else if (y >= gh->height) x = gh->height-1;
#else
// Are we over the slider?
if (x < 0 || x >= gh->width || y < 0 || y >= gh->height) {
// No - restore the slider
ResetDisplayPos(gsw);
gwinDraw(gh);
return;
}
#endif
// Set the new position
if (gh->width < gh->height)
gsw->pos = (uint16_t)((uint32_t)(gh->height-1-y-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->height-2*GWIN_SLIDER_DEAD_BAND) + gsw->min);
else
gsw->pos = (uint16_t)((uint32_t)(x-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->width-2*GWIN_SLIDER_DEAD_BAND) + gsw->min);
ResetDisplayPos(gsw);
gwinDraw(gh);
// Generate the event
SendSliderEvent(gw);
#undef gh #undef gh
#undef gsw
}
// A mouse move (or mouse down) event
static void MouseMove(GWidgetObject *gw, coord_t x, coord_t y) {
#define gsw ((GSliderObject *)gw)
// Determine the temporary display position (with range checking)
if (gw->g.width < gw->g.height) {
if (y < 0)
gsw->dpos = 0;
else if (y >= gw->g.height)
gsw->dpos = gw->g.height-1;
else
gsw->dpos = y;
} else {
if (x < 0)
gsw->dpos = 0;
else if (x >= gw->g.width)
gsw->dpos = gw->g.width-1;
else
gsw->dpos = x;
}
// Update the display
gwinDraw(&gw->g);
#undef gsw
}
// A dial move event
static void DialMove(GWidgetObject *gw, uint16_t instance, uint16_t value) {
#if GFX_USE_GINPUT && GINPUT_NEED_DIAL
#define gsw ((GSliderObject *)gw)
// Set the new position
gsw->pos = (uint16_t)((uint32_t)value*(gsw->max-gsw->min)/ginputGetDialRange(instance) + gsw->min);
ResetDisplayPos(gsw);
gwinDraw(&gw->g);
// Generate the event
SendSliderEvent(gw);
#undef gsw
#else
(void)gw; (void)instance; (void)value;
#endif
} }
GHandle gwinCreateSlider(GSliderObject *gs, coord_t x, coord_t y, coord_t width, coord_t height) { GHandle gwinCreateSlider(GSliderObject *gs, coord_t x, coord_t y, coord_t width, coord_t height) {
if (!(gs = (GSliderObject *)_gwinInit((GWindowObject *)gs, x, y, width, height, sizeof(GSliderObject)))) if (!(gs = (GSliderObject *)_gwidgetInit((GWidgetObject *)gs, x, y, width, height, sizeof(GSliderObject), &sliderVMT)))
return 0; return 0;
gs->gwin.type = GW_SLIDER; gs->c = GSliderDefaultColors;
gs->fn = gwinSliderDraw_Std;
gs->param = 0;
gwinSetSliderStyle(&gs->gwin, &GSliderDefaultStyle);
gs->min = 0; gs->min = 0;
gs->max = 100; gs->max = 100;
gs->pos = 0; gs->pos = 0;
gs->tracking = FALSE; ResetDisplayPos(gs);
geventListenerInit(&gs->listener);
geventRegisterCallback(&gs->listener, gwinSliderCallback, gs);
return (GHandle)gs; return (GHandle)gs;
} }
void gwinSetSliderRange(GHandle gh, int min, int max) { void gwinSetSliderRange(GHandle gh, int min, int max) {
#define gsw ((GSliderObject *)gh) #define gsw ((GSliderObject *)gh)
if (gh->type != GW_SLIDER) if (gh->vmt != (gwinVMT *)&sliderVMT)
return; return;
if (min == max) // prevent divide by 0 errors. if (min == max) // prevent divide by 0 errors.
@ -160,13 +188,14 @@ void gwinSetSliderRange(GHandle gh, int min, int max) {
gsw->min = min; gsw->min = min;
gsw->max = max; gsw->max = max;
gsw->pos = min; gsw->pos = min;
ResetDisplayPos(gsw);
#undef gsw #undef gsw
} }
void gwinSetSliderPosition(GHandle gh, int pos) { void gwinSetSliderPosition(GHandle gh, int pos) {
#define gsw ((GSliderObject *)gh) #define gsw ((GSliderObject *)gh)
if (gh->type != GW_SLIDER) if (gh->vmt != (gwinVMT *)&sliderVMT)
return; return;
if (gsw->min <= gsw->max) { if (gsw->min <= gsw->max) {
@ -178,125 +207,96 @@ void gwinSetSliderPosition(GHandle gh, int pos) {
else if (pos < gsw->max) gsw->pos = gsw->max; else if (pos < gsw->max) gsw->pos = gsw->max;
else gsw->pos = pos; else gsw->pos = pos;
} }
ResetDisplayPos(gsw);
#undef gsw #undef gsw
} }
void gwinSetSliderStyle(GHandle gh, const GSliderDrawStyle *pStyle) { void gwinSetSliderColors(GHandle gh, const GSliderColors *pColors) {
#define gsw ((GSliderObject *)gh) if (gh->vmt != (gwinVMT *)&sliderVMT)
if (gh->type != GW_SLIDER)
return; return;
gsw->style.color_edge = pStyle->color_edge; ((GSliderObject *)gh)->c = *pColors;
gsw->style.color_thumb = pStyle->color_thumb;
gsw->style.color_active = pStyle->color_active;
gsw->style.color_inactive = pStyle->color_inactive;
#undef gsw
} }
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE void gwinSliderDraw_Std(GWidgetObject *gw, void *param) {
static void trackSliderDraw(GHandle gh, coord_t x, coord_t y) { #define gsw ((GSliderObject *)gw)
#define gsw ((GSliderObject *)gh)
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
if (gh->height <= gh->width)
gsw->fn(gh, FALSE, x, &gsw->style, gsw->param);
else
gsw->fn(gh, TRUE, y, &gsw->style, gsw->param);
#undef gbw
}
#endif
void gwinSliderDraw(GHandle gh) {
#define gsw ((GSliderObject *)gh)
if (gh->type != GW_SLIDER)
return;
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
if (gh->height <= gh->width)
gsw->fn(gh, FALSE, ((gh->width-1)*(gsw->pos-gsw->min))/(gsw->max-gsw->min), &gsw->style, gsw->param);
else
gsw->fn(gh, TRUE, gh->height-1-((gh->height-1)*(gsw->pos-gsw->min))/(gsw->max-gsw->min), &gsw->style, gsw->param);
#undef gbw
}
void gwinSetSliderCustom(GHandle gh, GSliderDrawFunction fn, void *param) {
#define gsw ((GSliderObject *)gh)
if (gh->type != GW_SLIDER)
return;
gsw->fn = fn ? fn : gwinSliderDraw_Std;
gsw->param = param;
#undef gsw
}
void gwinSliderSetEnabled(GHandle gh, bool_t enabled) {
if (gh->type != GW_SLIDER)
return;
gh->enabled = enabled;
}
void gwinSliderDraw_Std(GHandle gh, bool_t isVertical, coord_t thumbpos, const GSliderDrawStyle *pstyle, void *param) {
(void) param; (void) param;
if (isVertical) { if (gw->g.vmt != (gwinVMT *)&sliderVMT)
if (thumbpos != gh->height-1) return;
gdispFillArea(gh->x, gh->y+thumbpos, gh->width, gh->height - thumbpos, pstyle->color_active);
if (thumbpos != 0) if (gw->g.width < gw->g.height) { // Vertical slider
gdispFillArea(gh->x, gh->y, gh->width, thumbpos, pstyle->color_inactive); if (gsw->dpos != gw->g.height-1)
gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge); gdispFillArea(gw->g.x, gw->g.y+gsw->dpos, gw->g.width, gw->g.height - gsw->dpos, gsw->c.color_active);
gdispDrawLine(gh->x, gh->y+thumbpos, gh->x+gh->width-1, gh->y+thumbpos, pstyle->color_thumb); if (gsw->dpos != 0)
if (thumbpos >= 2) gdispFillArea(gw->g.x, gw->g.y, gw->g.width, gsw->dpos, gsw->c.color_inactive);
gdispDrawLine(gh->x, gh->y+thumbpos-2, gh->x+gh->width-1, gh->y+thumbpos-2, pstyle->color_thumb); gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gsw->c.color_edge);
if (thumbpos <= gh->height-2) gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos, gsw->c.color_thumb);
gdispDrawLine(gh->x, gh->y+thumbpos+2, gh->x+gh->width-1, gh->y+thumbpos+2, pstyle->color_thumb); if (gsw->dpos >= 2)
gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos-2, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos-2, gsw->c.color_thumb);
if (gsw->dpos <= gw->g.height-2)
gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos+2, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos+2, gsw->c.color_thumb);
// Horizontal slider
} else { } else {
if (thumbpos != gh->width-1) if (gsw->dpos != gw->g.width-1)
gdispFillArea(gh->x+thumbpos, gh->y, gh->width-thumbpos, gh->height, pstyle->color_inactive); gdispFillArea(gw->g.x+gsw->dpos, gw->g.y, gw->g.width-gsw->dpos, gw->g.height, gsw->c.color_inactive);
if (thumbpos != 0) if (gsw->dpos != 0)
gdispFillArea(gh->x, gh->y, thumbpos, gh->height, pstyle->color_active); gdispFillArea(gw->g.x, gw->g.y, gsw->dpos, gw->g.height, gsw->c.color_active);
gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge); gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gsw->c.color_edge);
gdispDrawLine(gh->x+thumbpos, gh->y, gh->x+thumbpos, gh->y+gh->height-1, pstyle->color_thumb); gdispDrawLine(gw->g.x+gsw->dpos, gw->g.y, gw->g.x+gsw->dpos, gw->g.y+gw->g.height-1, gsw->c.color_thumb);
if (thumbpos >= 2) if (gsw->dpos >= 2)
gdispDrawLine(gh->x+thumbpos-2, gh->y, gh->x+thumbpos-2, gh->y+gh->height-1, pstyle->color_thumb); gdispDrawLine(gw->g.x+gsw->dpos-2, gw->g.y, gw->g.x+gsw->dpos-2, gw->g.y+gw->g.height-1, gsw->c.color_thumb);
if (thumbpos <= gh->width-2) if (gsw->dpos <= gw->g.width-2)
gdispDrawLine(gh->x+thumbpos+2, gh->y, gh->x+thumbpos+2, gh->y+gh->height-1, pstyle->color_thumb); gdispDrawLine(gw->g.x+gsw->dpos+2, gw->g.y, gw->g.x+gsw->dpos+2, gw->g.y+gw->g.height-1, gsw->c.color_thumb);
} }
gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, gsw->c.color_txt, justifyCenter);
#undef gsw
} }
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE void gwinSliderDraw_Image(GWidgetObject *gw, void *param) {
bool_t gwinAttachSliderMouse(GHandle gh, uint16_t instance) { #define gsw ((GSliderObject *)gw)
GSourceHandle gsh; #define gi ((gdispImage *)param)
coord_t z, v;
if (gh->type != GW_SLIDER || !(gsh = ginputGetMouse(instance))) if (gw->g.vmt != (gwinVMT *)&sliderVMT)
return FALSE; return;
return geventAttachSource(&((GSliderObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES); if (gw->g.width < gw->g.height) { // Vertical slider
if (gsw->dpos != 0) // The unfilled area
gdispFillArea(gw->g.x, gw->g.y, gw->g.width, gsw->dpos, gsw->c.color_inactive);
if (gsw->dpos != gw->g.height-1) { // The filled area
for(z=gw->g.height, v=gi->height; z > gsw->dpos;) {
z -= v;
if (z < gsw->dpos) {
v -= gsw->dpos - z;
z = gsw->dpos;
}
gdispImageDraw(gi, gw->g.x, gw->g.y+z, gw->g.width, v, 0, gi->height-v);
}
}
gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gsw->c.color_edge);
gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos, gsw->c.color_thumb);
// Horizontal slider
} else {
if (gsw->dpos != gw->g.width-1) // The unfilled area
gdispFillArea(gw->g.x+gsw->dpos, gw->g.y, gw->g.width-gsw->dpos, gw->g.height, gsw->c.color_inactive);
if (gsw->dpos != 0) { // The filled area
for(z=0, v=gi->width; z < gsw->dpos; z += v) {
if (z+v > gsw->dpos)
v -= z+v - gsw->dpos;
gdispImageDraw(gi, gw->g.x+z, gw->g.y, v, gw->g.height, 0, 0);
}
}
gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gsw->c.color_edge);
gdispDrawLine(gw->g.x+gsw->dpos, gw->g.y, gw->g.x+gsw->dpos, gw->g.y+gw->g.height-1, gsw->c.color_thumb);
} }
#endif gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, gsw->c.color_txt, justifyCenter);
#if GFX_USE_GINPUT && GINPUT_NEED_DIAL #undef gsw
bool_t gwinAttachSliderDial(GHandle gh, uint16_t instance) { }
GSourceHandle gsh;
if (gh->type != GW_SLIDER || !(gsh = ginputGetDial(instance)))
return FALSE;
return geventAttachSource(&((GSliderObject *)gh)->listener, gsh, 0);
}
#endif
#endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */ #endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */
/** @} */ /** @} */