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
#define _GWIN_BUTTON_H
#if GWIN_NEED_BUTTON || defined(__DOXYGEN__)
/* This file is included within "gwin/gwidget.h" */
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define GW_BUTTON 0x0002
/**
* @brief The Event Type for a Button Event
*/
#define GEVENT_GWIN_BUTTON (GEVENT_GWIN_FIRST+0)
/*===========================================================================*/
/* Type definitions */
/*===========================================================================*/
typedef struct GEventGWinButton_t {
/**
* @brief A Button Event
* @note There are currently no GEventGWinButton listening flags - use 0 as the flags to @p gwinAttachListener()
*/
typedef struct GEventGWinButton {
GEventType type; // The type of this event (GEVENT_GWIN_BUTTON)
GHandle button; // The button that has been depressed (actually triggered on release)
} GEventGWinButton;
// There are currently no GEventGWinButton listening flags - use 0
typedef enum GButtonShape_e {
GBTN_3D, GBTN_SQUARE, GBTN_ROUNDED, GBTN_ELLIPSE, GBTN_CUSTOM,
GBTN_ARROW_UP, GBTN_ARROW_DOWN, GBTN_ARROW_LEFT, GBTN_ARROW_RIGHT,
} GButtonShape;
typedef struct GButtonDrawStyle_t {
/**
* @brief Button colors
*/
typedef struct GButtonColors {
color_t color_edge;
color_t color_fill;
color_t color_txt;
} GButtonDrawStyle;
} GButtonColors;
typedef enum GButtonType_e {
GBTN_NORMAL, GBTN_TOGGLE
} GButtonType;
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
/**
* @brief The button widget structure
* @note Do not use the members directly - treat it as a black-box.
*/
typedef struct GButtonObject_t {
GWindowObject gwin;
GButtonDrawStyle up;
GButtonDrawStyle dn;
GButtonState state;
GButtonType type;
const char *txt;
GButtonDrawFunction fn;
void *param;
GListener listener;
GWidgetObject w;
GButtonColors c_up;
GButtonColors c_dn;
GButtonColors c_dis;
} GButtonObject;
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Create a button window.
* @brief Create a button widget.
* @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] 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] 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 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 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
*/
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.
* @details The button style is defined by its shape and colours.
* @brief Set the colors of a button.
*
* @param[in] gh The window handle (must be a button window)
* @param[in] shape The shape of the button.
* @param[in] pUp The styling for the button when in the up state.
* @param[in] pDown The styling for the button when in the down state.
* @param[in] gh The window handle (must be a button widget)
* @param[in] pUp The colors for the button when in the up state.
* @param[in] pDown The colors 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 style is copied into the internal button structure - there is no need to
* maintain a static style structures.
* @note The pUp and pDown parameters can be NULL. If they are then the existing color styles
* maintain static style structures (they can be temporary structures on the stack).
* @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.
* @note Some custom drawn buttons will ignore he specified colors
*
* @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] 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.
* @param[in] gh The window handle (must be a button widget)
*
* @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)
*
* @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] gw The widget object (in this case a button)
* @param[in] param A parameter passed in from the user
*
* @note In your custom button drawing function you may optionally call these
* standard functions and then draw your extra details on top.
* @note The standard functions below ignore the param parameter. It is there
* only to ensure the functions match the GButtonDrawFunction type.
* @note When called by a button press/release the framework ensure that it is
* a button object and sets up clipping to the button object window. These
* drawing routines then don't have to worry about explicitly doing that.
* @note The standard functions below ignore the param parameter except for @p gwinButtonDraw_Image().
* @note The image custom draw function @p gwinButtonDraw_Image() uses param to pass in the gdispImage pointer.
* The image must be already opened before calling @p gwinSetCustomDraw(). The image should be 3
* times the height of the button. The button image is repeated 3 times vertically, the first (top) for
* 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
* @{
*/
void gwinButtonDraw_3D(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param);
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); // @< A standard 3D button
void gwinButtonDraw_Box(GWidgetObject *gw, void *param); // @< A very simple box style button
#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
#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
#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_ArrowDown(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param);
void gwinButtonDraw_ArrowLeft(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param);
void gwinButtonDraw_ArrowRight(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(GWidgetObject *gw, void *param); // @< A down arrow button
void gwinButtonDraw_ArrowLeft(GWidgetObject *gw, void *param); // @< A left arrow button
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
/** @} */
@ -265,8 +157,6 @@ void gwinButtonDraw_Square(GHandle gh, bool_t enabled, bool_t isdown, const char
}
#endif
#endif /* GWIN_NEED_BUTTON */
#endif /* _GWIN_BUTTON_H */
/** @} */

View File

@ -12,7 +12,7 @@
* @defgroup Checkbox Checkbox
* @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 GWIN_NEED_CHECKBOX must be set to TRUE in your gfxconf.h
@ -22,13 +22,12 @@
#ifndef _GWIN_CHECKBOX_H
#define _GWIN_CHECKBOX_H
#if GWIN_NEED_CHECKBOX || defined(__DOXYGEN__)
/* This file is included within "gwin/gwidget.h" */
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define GW_CHECKBOX 0x0005
#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?
} GEventGWinCheckbox;
typedef enum GCheckboxState_e {
GCHBX_UNCHECKED, GCHBX_CHECKED
} GCheckboxState;
typedef struct GCheckboxColor_t {
color_t border;
color_t checked;
color_t bg;
} GCheckboxColor;
/* custom rendering interface */
typedef void (*GCheckboxDrawFunction)(GHandle gh, bool_t enabled, bool_t state, void* param);
typedef struct GCheckboxColors {
color_t color_border;
color_t color_checked;
color_t color_bg;
color_t color_txt;
} GCheckboxColors;
/* A Checkbox window */
typedef struct GCheckboxObject_t {
GWindowObject gwin;
GListener listener;
GCheckboxDrawFunction fn;
GCheckboxColor *colors;
bool_t isChecked;
void *param;
GWidgetObject w;
GCheckboxColors c;
} 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] 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] height The height of the window
*
* @note The checkbox is not automatically drawn. Call gwinCheckboxDraw() after changing the checkbox style.
*
* @return NULL if there is no resultant drawing area, otherwise a window handle.
* @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 checkbox is not automatically drawn. Call gwinDraw() to draw it.
*
* @api
*/
GHandle gwinCheckboxCreate(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)
GHandle gwinCreateCheckbox(GCheckboxObject *gb, coord_t x, coord_t y, coord_t width, coord_t height);
/**
* @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)
*
* @return The state of the checkbox (GCHBX_CHECKED or GCHBX_UNCHECKED)
*
* @api
*/
#define gwinCheckboxGetState(gh) (((GCheckboxObject *)(gh))->isChecked)
bool_t gwinIsCheckboxChecked(GHandle gh);
/**
* @brief Get the source handle of a checkbox
* @details Get the source handle of a checkbox so the application can listen for events
* @brief Set the colors used to draw the checkbox
*
* @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
*/
#define gwinCheckboxGetSource(gh) ((GSourceHandle)(gh))
void gwinCheckboxSetColors(GHandle gh, GCheckboxColors *pColors);
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
/**
* @brief Attach a mouse to a checkbox
*
* @param[in] gh The checkbox handle
* @param[in] instance The mouse instance
*
* @api
*/
bool_t gwinCheckboxAttachMouse(GHandle gh, uint16_t instance);
#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */
#endif /* _GWIN_NEED_CHECKBOX */
/**
* @brief Some custom checkbox drawing routines
* @details These function may be passed to @p gwinSetCustomDraw() to get different checkbox drawing styles
*
* @param[in] gw The widget (which must be a checkbox)
* @param[in] param A parameter passed in from the user
*
* @note In your custom checkbox drawing function you may optionally call this
* standard functions and then draw your extra details on top.
* @note The standard functions below ignore the param parameter.
* @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
* @{
*/
void gwinCheckboxDraw_CheckOnLeft(GWidgetObject *gw, void *param);
void gwinCheckboxDraw_CheckOnRight(GWidgetObject *gw, void *param);
/* @} */
#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
#define _GWIN_CONSOLE_H
#if GWIN_NEED_CONSOLE || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define GW_CONSOLE 0x0001
/*===========================================================================*/
/* Type definitions */
/*===========================================================================*/
/* This file is included within "gwin/gwin.h" */
// A console window. Supports wrapped text writing and a cursor.
typedef struct GConsoleObject_t {
GWindowObject gwin;
GWindowObject g;
coord_t cx, cy; // Cursor position
#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
struct GConsoleWindowStream_t {
const struct GConsoleWindowVMT_t *vmt;
@ -47,15 +38,8 @@ typedef struct GConsoleObject_t {
} stream;
#endif
coord_t cx,cy; // Cursor position
uint8_t fy; // Current font height
uint8_t fp; // Current font inter-character spacing
} GConsoleObject;
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
@ -67,18 +51,19 @@ extern "C" {
* @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] 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] 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 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 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.
*
* @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
/**
@ -157,7 +142,5 @@ void gwinPrintf(GHandle gh, const char *fmt, ...);
}
#endif
#endif /* GWIN_NEED_CONSOLE */
#endif /* _GWIN_CONSOLE_H */
/** @} */

View File

@ -22,20 +22,7 @@
#ifndef _GWIN_GRAPH_H
#define _GWIN_GRAPH_H
#if GWIN_NEED_GRAPH || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define GW_GRAPH 0x0003
/*===========================================================================*/
/* Type definitions */
/*===========================================================================*/
// GDISP now has its own point structure
#define GGraphPoint point
/* This file is included within "gwin/gwin.h" */
typedef enum GGraphPointType_e {
GGRAPH_POINT_NONE, GGRAPH_POINT_DOT, GGRAPH_POINT_SQUARE, GGRAPH_POINT_CIRCLE
@ -85,7 +72,7 @@ typedef struct GGraphStyle_t {
// A graph window
typedef struct GGraphObject_t {
GWindowObject gwin;
GWindowObject g;
GGraphStyle style;
coord_t xorigin, yorigin;
coord_t lastx, lasty;
@ -104,10 +91,12 @@ extern "C" {
* @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] 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] 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 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
* 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.
@ -187,8 +176,6 @@ void gwinGraphDrawPoints(GHandle gh, const point *points, unsigned count);
}
#endif
#endif /* GWIN_NEED_GRAPH */
#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
* @ingroup GWIN
*
* @details GWIN provides a basic window manager which allows it to easily
* create and destroy different windows on runtime. Each window
* will have it's own properties such as colors, brushes as well as
* it's own drawing origin.
* Moving the windows around is not supported yet.
* @details GWIN provides a basic window manager which allows it to easily
* create and destroy different windows at runtime. Each window
* will have it's own properties such as colors as well as
* it's own drawing origin.
*
* @pre GFX_USE_GWIN must be set to TRUE in your gfxconf.h
*
* @{
*/
@ -30,30 +28,23 @@
#if GFX_USE_GWIN || defined(__DOXYGEN__)
/*===========================================================================*/
/* Type definitions */
/*===========================================================================*/
typedef uint16_t GWindowType;
#define GW_WINDOW 0x0000
#define GW_FIRST_USER_WINDOW 0x8000
// A basic window
typedef struct GWindowObject_t {
GWindowType type; // What type of window is this
uint16_t flags; // Internal flags
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
/**
* @brief A window object structure
* @note Do you access the members directly. Treat it as a black-box and use the method functions.
*
* @{
*/
typedef struct GWindowObject {
const struct gwinVMT *vmt; // @< The VMT for this GWIN
coord_t x, y; // @< Screen relative position
coord_t width, height; // @< Dimensions of this window
color_t color, bgcolor; // @< Current drawing colors
uint16_t flags; // @< Window flags (the meaning is private to the GWIN class)
#if GDISP_NEED_TEXT
font_t font; // Current font
font_t font; // @< Current font
#endif
} GWindowObject, * GHandle;
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
/* @} */
#ifdef __cplusplus
extern "C" {
@ -65,18 +56,20 @@ extern "C" {
* @brief Create a basic window.
* @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] x,y The screen coordinates for the bottom left corner of the window
* @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 top left corner of the window
* @param[in] width The width 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 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 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
*/
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.
@ -85,17 +78,22 @@ GHandle gwinCreateWindow(GWindowObject *gw, coord_t x, coord_t y, coord_t width,
*
* @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] enabled Enable or disable the widget
*
* @api
* @param[in] gh The window
*/
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
@ -148,23 +146,16 @@ void gwinSetEnabled(GHandle gh, bool_t enabled);
*/
#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 */
#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.
*
@ -178,16 +169,6 @@ void gwinSetEnabled(GHandle gh, bool_t enabled);
/* 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
* @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
/* Include widgets */
#include "gwin/gwidget.h"
/* Include extra window types */
#include "gwin/console.h" /* 0x0001 */
#include "gwin/button.h" /* 0x0002 */
#include "gwin/graph.h" /* 0x0003 */
#include "gwin/slider.h" /* 0x0004 */
#include "gwin/checkbox.h" /* 0x0005 */
#if GWIN_NEED_CONSOLE || defined(__DOXYGEN__)
#include "gwin/console.h"
#endif
#if GWIN_NEED_GRAPH || defined(__DOXYGEN__)
#include "gwin/graph.h"
#endif
#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
#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)
/*===========================================================================*/
/* Type definitions */
/*===========================================================================*/
typedef struct GEventGWinSlider_t {
GEventType type; // The type of this event (GEVENT_GWIN_BUTTON)
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
typedef struct GSliderDrawStyle_t {
typedef struct GSliderColors {
color_t color_edge;
color_t color_thumb;
color_t color_active;
color_t color_inactive;
} GSliderDrawStyle;
typedef void (*GSliderDrawFunction)(GHandle gh, bool_t isVertical, coord_t thumbpos, const GSliderDrawStyle *pstyle, void *param);
color_t color_txt;
} GSliderColors;
// A slider window
typedef struct GSliderObject_t {
GWindowObject gwin;
GSliderDrawStyle style;
bool_t tracking;
GWidgetObject w;
GSliderColors c;
coord_t dpos;
int min;
int max;
int pos;
GSliderDrawFunction fn;
void *param;
GListener listener;
} GSliderObject;
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
@ -79,12 +61,14 @@ extern "C" {
* @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] 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] height The height of the window
*
* @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 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
*
* @api
@ -130,51 +114,7 @@ void gwinSetSliderPosition(GHandle gh, int pos);
*
* @api
*/
void gwinSetSliderStyle(GHandle gh, const GSliderDrawStyle *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)
void gwinSetSliderColors(GHandle gh, const GSliderColors *pStyle);
/**
* @brief Get the current slider position.
@ -190,69 +130,35 @@ void gwinSetSliderCustom(GHandle gh, GSliderDrawFunction fn, void *param);
#define gwinGetSliderPosition(gh) (((GSliderObject *)(gh))->pos)
/**
* @brief Get the source handle of a slider
* @details Get the source handle of a slider so the application can listen for events
* @brief Some custom slider drawing routines
* @details These function may be passed to @p gwinSetCustomDraw() to get different slider drawing styles
*
* @param[in] gh The window handle
*
* @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] gw The widget (which must be a slider)
* @param[in] param A parameter passed in from the user
*
* @note In your custom slider drawing function you may optionally call this
* standard functions and then draw your extra details on top.
* @note The standard functions below ignore the param parameter. It is there
* only to ensure the functions match the GSliderDrawFunction type.
* @note When called by a slider the framework ensure that it is
* a slider object and sets up clipping to the slider object window. These
* drawing routines then don't have to worry about explicitly doing that.
* @note The standard functions below ignore the param parameter except for @p gwinSliderDraw_Image().
* @note The image custom draw function @p gwinSliderDraw_Image() uses param to pass in the gdispImage pointer.
* The image must be already opened before calling @p gwinSetCustomDraw(). The image is tiled to fill
* the active area of the slider. The normal colors apply to the border and inactive area and the dividing line
* 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
* @{
*/
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
}
#endif
#endif /* GWIN_NEED_SLIDER */
#endif /* _GWIN_SLIDER_H */
/** @} */

View File

@ -19,392 +19,313 @@
#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 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
#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(0xE0E0E0), // color_up_fill;
HTML2COLOR(0x000000), // color_up_txt;
};
static const GButtonDrawStyle GButtonDefaultStyleDown = {
static const GButtonColors GButtonDefaultColorsDown = {
HTML2COLOR(0x404040), // color_dn_edge;
HTML2COLOR(0x808080), // color_dn_fill;
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
static void gwinButtonCallback(void *param, GEvent *pe) {
GSourceListener *psl;
#define gh ((GHandle)param)
#define gbw ((GButtonObject *)param)
#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;
}
// Send the button event
static void SendButtonEvent(GWidgetObject *gw) {
GSourceListener * psl;
GEvent * pe;
#define pbe ((GEventGWinButton *)pe)
// Trigger a GWIN Button Event
psl = 0;
while ((psl = geventGetSourceListener(gsh, psl))) {
while ((psl = geventGetSourceListener((GSourceHandle)gw, psl))) {
if (!(pe = geventGetEventBuffer(psl)))
continue;
pbe->type = GEVENT_GWIN_BUTTON;
pbe->button = gh;
pbe->button = (GHandle)gw;
geventSendEvent(psl);
}
#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) {
if (!(gb = (GButtonObject *)_gwinInit((GWindowObject *)gb, x, y, width, height, sizeof(GButtonObject))))
return 0;
gb->gwin.type = GW_BUTTON;
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;
// A mouse down has occurred over the button
static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) {
(void) x; (void) y;
gw->g.flags |= GBUTTON_FLG_PRESSED;
gwinDraw((GHandle)gw);
}
void gwinSetButtonStyle(GHandle gh, GButtonShape shape, const GButtonDrawStyle *pUp, const GButtonDrawStyle *pDown) {
#define gbw ((GButtonObject *)gh)
if (gh->type != GW_BUTTON)
return;
// A mouse up has occurred (it may or may not be over the button)
static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y) {
(void) x; (void) y;
gw->g.flags &= ~GBUTTON_FLG_PRESSED;
gwinDraw((GHandle)gw);
switch(shape) {
case GBTN_SQUARE: gbw->fn = gwinButtonDraw_Square; break;
#if GDISP_NEED_ARC
case GBTN_ROUNDED: gbw->fn = gwinButtonDraw_Rounded; break;
#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);
#if !GWIN_BUTTON_LAZY_RELEASE
// If the mouse up was not over the button then cancel the event
if (x < 0 || y < 0 || x >= gw->g.width || y >= gw->g.height)
return;
#endif
gbw->fn(gh,
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
SendButtonEvent(gw);
}
void gwinSetButtonCustom(GHandle gh, GButtonDrawFunction fn, void *param) {
#define gbw ((GButtonObject *)gh)
// A toggle off has occurred
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;
gbw->fn = fn ? fn : gwinButtonDraw_3D;
gbw->param = param;
#undef gbw
if (pUp) ((GButtonObject *)gh)->c_up = *pUp;
if (pDown) ((GButtonObject *)gh)->c_dn = *pDown;
if (pDisabled) ((GButtonObject *)gh)->c_dis = *pDisabled;
}
void gwinButtonSetEnabled(GHandle gh, bool_t enabled) {
if (gh->type != GW_BUTTON)
return;
bool_t gwinIsButtonPressed(GHandle gh) {
if (gh->vmt != (gwinVMT *)&buttonVMT)
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;
(void) isdown;
(void) param;
/*----------------------------------------------------------
* Custom Draw Routines
*----------------------------------------------------------*/
gdispFillStringBox(gh->x, gh->y, gh->width-1, gh->height-1, txt, gh->font, pstyle->color_txt, pstyle->color_fill, justifyCenter);
gdispDrawLine(gh->x+gh->width-1, gh->y, gh->x+gh->width-1, gh->y+gh->height-1, pstyle->color_edge);
gdispDrawLine(gh->x, gh->y+gh->height-1, gh->x+gh->width-2, gh->y+gh->height-1, pstyle->color_edge);
static GButtonColors *getDrawColors(GWidgetObject *gw) {
if (!(gw->g.flags & GWIN_FLG_ENABLED)) return &((GButtonObject *)gw)->c_dis;
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) enabled;
(void) isdown;
(void) param;
void gwinButtonDraw_3D(GWidgetObject *gw, void *param) {
(void) param;
GButtonColors * pcol;
gdispFillStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, pstyle->color_fill, justifyCenter);
gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge);
if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
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
void gwinButtonDraw_Rounded(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) {
(void) enabled;
(void) isdown;
(void) param;
void gwinButtonDraw_Rounded(GWidgetObject *gw, void *param) {
(void) param;
GButtonColors * pcol;
if (gh->width >= 2*RND_CNR_SIZE+10) {
gdispFillRoundedBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, RND_CNR_SIZE-1, pstyle->color_fill);
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.vmt != (gwinVMT *)&buttonVMT) return;
pcol = getDrawColors(gw);
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 {
gdispFillStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, pstyle->color_fill, justifyCenter);
gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge);
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);
}
}
#endif
#if GDISP_NEED_ELLIPSE
void gwinButtonDraw_Ellipse(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) {
(void) enabled;
(void) isdown;
(void) param;
void gwinButtonDraw_Ellipse(GWidgetObject *gw, void *param) {
(void) param;
GButtonColors * pcol;
gdispFillEllipse(gh->x+1, gh->y+1, gh->width/2-1, gh->height/2-1, pstyle->color_fill);
gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter);
gdispDrawEllipse(gh->x, gh->y, gh->width/2, gh->height/2, pstyle->color_edge);
if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
pcol = getDrawColors(gw);
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
#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) enabled;
(void) isdown;
(void) param;
point arw[7];
void gwinButtonDraw_ArrowUp(GWidgetObject *gw, void *param) {
(void) param;
GButtonColors * pcol;
point arw[7];
arw[0].x = gh->width/2; arw[0].y = 0;
arw[1].x = gh->width-1; arw[1].y = gh->height/ARROWHEAD_DIVIDER;
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;
if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
pcol = getDrawColors(gw);
gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill);
gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge);
gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter);
arw[0].x = gw->g.width/2; arw[0].y = 0;
arw[1].x = gw->g.width-1; arw[1].y = gw->g.height/ARROWHEAD_DIVIDER;
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) enabled;
(void) isdown;
(void) param;
point arw[7];
void gwinButtonDraw_ArrowDown(GWidgetObject *gw, void *param) {
(void) param;
GButtonColors * pcol;
point arw[7];
arw[0].x = gh->width/2; arw[0].y = gh->height-1;
arw[1].x = gh->width-1; arw[1].y = gh->height-1-gh->height/ARROWHEAD_DIVIDER;
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;
if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
pcol = getDrawColors(gw);
gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill);
gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge);
gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter);
arw[0].x = gw->g.width/2; arw[0].y = gw->g.height-1;
arw[1].x = gw->g.width-1; arw[1].y = gw->g.height-1-gw->g.height/ARROWHEAD_DIVIDER;
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) enabled;
(void) isdown;
(void) param;
point arw[7];
void gwinButtonDraw_ArrowLeft(GWidgetObject *gw, void *param) {
(void) param;
GButtonColors * pcol;
point arw[7];
arw[0].x = 0; arw[0].y = gh->height/2;
arw[1].x = gh->width/ARROWHEAD_DIVIDER; arw[1].y = 0;
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;
if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
pcol = getDrawColors(gw);
gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill);
gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge);
gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter);
arw[0].x = 0; arw[0].y = gw->g.height/2;
arw[1].x = gw->g.width/ARROWHEAD_DIVIDER; arw[1].y = 0;
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) enabled;
(void) isdown;
(void) param;
point arw[7];
void gwinButtonDraw_ArrowRight(GWidgetObject *gw, void *param) {
(void) param;
GButtonColors * pcol;
point arw[7];
arw[0].x = gh->width-1; arw[0].y = gh->height/2;
arw[1].x = gh->width-1-gh->width/ARROWHEAD_DIVIDER; arw[1].y = 0;
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;
if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
pcol = getDrawColors(gw);
gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill);
gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge);
gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter);
arw[0].x = gw->g.width-1; arw[0].y = gw->g.height/2;
arw[1].x = gw->g.width-1-gw->g.width/ARROWHEAD_DIVIDER; arw[1].y = 0;
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
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
bool_t gwinAttachButtonMouse(GHandle gh, uint16_t instance) {
GSourceHandle gsh;
#if GDISP_NEED_IMAGE || defined(__DOXYGEN__)
void gwinButtonDraw_Image(GWidgetObject *gw, void *param) {
GButtonColors * pcol;
coord_t sy;
if (gh->type != GW_BUTTON || !(gsh = ginputGetMouse(instance)))
return FALSE;
if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA);
}
#endif
if (!(gw->g.flags & GWIN_FLG_ENABLED)) {
pcol = &((GButtonObject *)gw)->c_dis;
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
bool_t gwinAttachButtonToggle(GHandle gh, uint16_t instance) {
GSourceHandle gsh;
if (gh->type != GW_BUTTON || !(gsh = ginputGetToggle(instance)))
return FALSE;
return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_TOGGLE_OFF|GLISTEN_TOGGLE_ON);
gdispImageDraw((gdispImage *)param, gw->g.x, gw->g.y, gw->g.width, gw->g.height, 0, sy);
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

View File

@ -7,7 +7,7 @@
/**
* @file src/gwin/checkbox.c
* @brief GWIN sub-system checkbox code.
* @brief GWIN sub-system button code.
*
* @defgroup Checkbox Checkbox
* @ingroup GWIN
@ -19,168 +19,137 @@
#if (GFX_USE_GWIN && GWIN_NEED_CHECKBOX) || defined(__DOXYGEN__)
static const GCheckboxColor defaultColors = {
Grey, // border
Grey, // selected
Black // background
#include "gwin/class_gwin.h"
// Our checked state
#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 void gwinCheckboxDrawDefaultStyle(GHandle gh, bool_t enabled, bool_t isChecked, void* param) {
#define gcw ((GCheckboxObject *)gh)
static const GCheckboxColors defaultColors = {
Black, // border
Grey, // selected
White, // background
Black, // text
};
(void) enabled;
(void) param;
// Send the checkbox event
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);
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
// Trigger a GWIN Checkbox Event
psl = 0;
while ((psl = geventGetSourceListener(gsh, psl))) {
while ((psl = geventGetSourceListener((GSourceHandle)gw, psl))) {
if (!(pe = geventGetEventBuffer(psl)))
continue;
pbe->type = GEVENT_GWIN_CHECKBOX;
pbe->checkbox = gh;
pbe->isChecked = gbw->isChecked;
pce->type = GEVENT_GWIN_CHECKBOX;
pce->checkbox = &gw->g;
pce->isChecked = (gw->g.flags & GCHECKBOX_FLG_CHECKED) ? TRUE : FALSE;
geventSendEvent(psl);
}
}
#undef gh
#undef pbe
#undef pme
#undef pte
#undef pxe
#undef gsh
#undef gbw
#undef pce
}
GHandle gwinCheckboxCreate(GCheckboxObject *gb, coord_t x, coord_t y, coord_t width, coord_t height) {
if (!(gb = (GCheckboxObject *)_gwinInit((GWindowObject *)gb, x, y, width, height, sizeof(GCheckboxObject))))
// A mouse down has occurred over the checkbox
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;
gb->gwin.type = GW_CHECKBOX; // create a window of the type checkbox
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;
gb->c = defaultColors; // assign the default colors
return (GHandle)gb;
}
void gwinCheckboxSetCustom(GHandle gh, GCheckboxDrawFunction fn, void *param) {
#define gcw ((GCheckboxObject *)gh)
bool_t gwinIsCheckboxChecked(GHandle gh) {
if (gh->vmt != (gwinVMT *)&checkboxVMT)
return FALSE;
if (gh->type != GW_CHECKBOX)
return;
gcw->fn = fn;
gcw->param = param;
#undef gcw
return (gh->flags & GCHECKBOX_FLG_CHECKED) ? TRUE : FALSE;
}
void gwinCheckboxSetEnabled(GHandle gh, bool_t enabled) {
if (gh->type != GW_CHECKBOX)
void gwinCheckboxSetColors(GHandle gh, GCheckboxColors *pColors) {
if (gh->vmt != (gwinVMT *)&checkboxVMT)
return;
gh->enabled = enabled;
((GCheckboxObject *)gh)->c = *pColors;
}
void gwinCheckboxDraw(GHandle gh) {
#define gcw ((GCheckboxObject *)gh)
void gwinCheckboxDraw_CheckOnLeft(GWidgetObject *gw, void *param) {
#define gcw ((GCheckboxObject *)gw)
coord_t ld, df;
(void) param;
if (gh->type != GW_CHECKBOX)
if (gw->g.vmt != (gwinVMT *)&checkboxVMT)
return;
#if GDISP_NEED_CLIP
//gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
ld = gw->g.width < gw->g.height ? gw->g.width : gw->g.height;
gdispFillArea(gw->g.x+1, gw->g.y+1, ld, ld-2, gcw->c.color_bg);
gdispDrawBox(gw->g.x, gw->g.y, ld, ld, gcw->c.color_border);
gcw->fn(gh,
gcw->gwin.enabled,
gcw->isChecked,
gcw->param);
df = ld < 4 ? 1 : 2;
if (gw->g.flags & GCHECKBOX_FLG_CHECKED)
gdispFillArea(gw->g.x+df, gw->g.y+df, ld-2*df, ld-2*df, gcw->c.color_checked);
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
}
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
bool_t gwinCheckboxAttachMouse(GHandle gh, uint16_t instance) {
GSourceHandle gsh;
void gwinCheckboxDraw_CheckOnRight(GWidgetObject *gw, void *param) {
#define gcw ((GCheckboxObject *)gw)
coord_t ep, ld, df;
(void) param;
if (gh->type != GW_CHECKBOX || !(gsh = ginputGetMouse(instance)))
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)
if (gw->g.vmt != (gwinVMT *)&checkboxVMT)
return;
gcw->colors->border = border;
gcw->colors->checked = checked,
gcw->colors->bg = bg;
ld = gw->g.width < gw->g.height ? gw->g.width : gw->g.height;
ep = gw->g.width-ld-1;
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
}

View File

@ -8,20 +8,15 @@
/**
* @file src/gwin/console.c
* @brief GWIN sub-system console code.
*
* @defgroup Console Console
* @ingroup GWIN
*
* @{
*/
#include "gfx.h"
#if (GFX_USE_GWIN && GWIN_NEED_CONSOLE) || defined(__DOXYGEN__)
#if GFX_USE_GWIN && GWIN_NEED_CONSOLE
#include <string.h>
#include "gwin/internal.h"
#include "gwin/class_gwin.h"
#define GWIN_CONSOLE_USE_CLEAR_LINES TRUE
#define GWIN_CONSOLE_USE_FILLED_CHARS FALSE
@ -58,11 +53,20 @@
};
#endif
GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t width, coord_t height, font_t font) {
if (!(gc = (GConsoleObject *)_gwinInit((GWindowObject *)gc, x, y, width, height, sizeof(GConsoleObject))))
static void AfterClear(GWindowObject *gh) {
((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;
gc->gwin.type = GW_CONSOLE;
gwinSetFont(&gc->gwin, font);
#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
gc->stream.vmt = &GWindowConsoleVMT;
#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
BaseSequentialStream *gwinGetConsoleStream(GHandle gh) {
if (gh->type != GW_CONSOLE)
if (gh->vmt != &consoleVMT)
return 0;
return (BaseSequentialStream *)&(((GConsoleObject *)(gh))->stream);
}
#endif
void gwinPutChar(GHandle gh, char c) {
uint8_t width;
#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
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
@ -91,24 +99,24 @@ void gwinPutChar(GHandle gh, char c) {
if (c == '\n') {
gcw->cx = 0;
gcw->cy += gcw->fy;
gcw->cy += fy;
// We use lazy scrolling here and only scroll when the next char arrives
} else if (c == '\r') {
// gcw->cx = 0;
} else {
width = gdispGetCharWidth(c, gh->font) + gcw->fp;
width = gdispGetCharWidth(c, gh->font) + fp;
if (gcw->cx + width >= gh->width) {
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
/* 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 */
gcw->cx = 0;
gcw->cy = (((coord_t)(gh->height/gcw->fy))-1)*gcw->fy;
gcw->cy = (((coord_t)(gh->height/fy))-1)*fy;
#else
/* clear the console */
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
/* clear to the end of the line */
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
#if GWIN_CONSOLE_USE_FILLED_CHARS
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];
#endif
if (gh->type != GW_CONSOLE || !gh->font) return;
if (gh->vmt != &consoleVMT || !gh->font)
return;
va_start(ap, fmt);
while (TRUE) {
@ -343,5 +352,5 @@ void gwinPrintf(GHandle gh, const char *fmt, ...) {
}
#endif /* GFX_USE_GWIN && GWIN_NEED_CONSOLE */
/** @} */

View File

@ -8,18 +8,13 @@
/**
* @file src/gwin/graph.c
* @brief GWIN sub-system button code.
*
* @defgroup Graph Graph
* @ingroup GWIN
*
* @{
*/
#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_ARROW_SIZE 5
@ -34,13 +29,19 @@ static const GGraphStyle GGraphDefaultStyle = {
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) {
if (style->type == GGRAPH_POINT_NONE)
return;
// Convert to device space. Note the y-axis is inverted.
x += gg->gwin.x + gg->xorigin;
y = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y;
x += gg->g.x + gg->xorigin;
y = gg->g.y + gg->g.height - 1 - gg->yorigin - y;
if (style->size <= 1) {
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;
// Convert to device space. Note the y-axis is inverted.
x0 += gg->gwin.x + gg->xorigin;
y0 = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y0;
x1 += gg->gwin.x + gg->xorigin;
y1 = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y1;
x0 += gg->g.x + gg->xorigin;
y0 = gg->g.y + gg->g.height - 1 - gg->yorigin - y0;
x1 += gg->g.x + gg->xorigin;
y1 = gg->g.y + gg->g.height - 1 - gg->yorigin - y1;
if (style->size <= 0) {
// 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) {
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;
gg->gwin.type = GW_GRAPH;
gg->xorigin = gg->yorigin = 0;
gg->lastx = gg->lasty = 0;
gwinGraphSetStyle(&gg->gwin, &GGraphDefaultStyle);
gwinGraphSetStyle((GHandle)gg, &GGraphDefaultStyle);
return (GHandle)gg;
}
void gwinGraphSetStyle(GHandle gh, const GGraphStyle *pstyle) {
#define gg ((GGraphObject *)gh)
if (gh->type != GW_GRAPH)
if (gh->vmt != &graphVMT)
return;
gg->style.point.type = pstyle->point.type;
gg->style.point.size = pstyle->point.size;
gg->style.point.color = pstyle->point.color;
gg->style.line.type = pstyle->line.type;
gg->style.line.size = pstyle->line.size;
gg->style.line.color = pstyle->line.color;
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.point = pstyle->point;
gg->style.line = pstyle->line;
gg->style.xaxis = pstyle->xaxis;
gg->style.yaxis = pstyle->yaxis;
gg->style.xgrid = pstyle->xgrid;
gg->style.ygrid = pstyle->ygrid;
gg->style.flags = pstyle->flags;
#undef gg
@ -206,7 +192,7 @@ void gwinGraphSetStyle(GHandle gh, const GGraphStyle *pstyle) {
void gwinGraphSetOrigin(GHandle gh, coord_t x, coord_t y) {
#define gg ((GGraphObject *)gh)
if (gh->type != GW_GRAPH)
if (gh->vmt != &graphVMT)
return;
gg->xorigin = x;
@ -219,7 +205,7 @@ void gwinGraphDrawAxis(GHandle gh) {
#define gg ((GGraphObject *)gh)
coord_t i, xmin, ymin, xmax, ymax;
if (gh->type != GW_GRAPH)
if (gh->vmt != &graphVMT)
return;
xmin = -gg->xorigin;
@ -277,7 +263,7 @@ void gwinGraphDrawAxis(GHandle gh) {
}
void gwinGraphStartSet(GHandle gh) {
if (gh->type != GW_GRAPH)
if (gh->vmt != &graphVMT)
return;
gh->flags &= ~GGRAPH_FLG_CONNECTPOINTS;
@ -286,7 +272,7 @@ void gwinGraphStartSet(GHandle gh) {
void gwinGraphDrawPoint(GHandle gh, coord_t x, coord_t y) {
#define gg ((GGraphObject *)gh)
if (gh->type != GW_GRAPH)
if (gh->vmt != &graphVMT)
return;
if ((gh->flags & GGRAPH_FLG_CONNECTPOINTS)) {
@ -314,7 +300,7 @@ void gwinGraphDrawPoints(GHandle gh, const point *points, unsigned count) {
unsigned i;
const point *p;
if (gh->type != GW_GRAPH)
if (gh->vmt != &graphVMT)
return;
// Draw the connecting lines
@ -344,5 +330,3 @@ void gwinGraphDrawPoints(GHandle gh, const point *points, unsigned count) {
}
#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
#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
// 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;
// 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;
// Allocate the structure if necessary
if (!gw) {
if (!(gw = (GWindowObject *)gfxAlloc(size)))
if (!pgw) {
if (!(pgw = (GWindowObject *)gfxAlloc(size)))
return 0;
gw->flags = GWIN_FLG_DYNAMIC;
pgw->flags = GWIN_FLG_DYNAMIC;
} else
gw->flags = 0;
pgw->flags = 0;
// Initialise all basic fields (except the type)
gw->x = x;
gw->y = y;
gw->width = width;
gw->height = height;
gw->color = White;
gw->bgcolor = Black;
// Initialise all basic fields
pgw->vmt = vmt;
pgw->x = x;
pgw->y = y;
pgw->width = width;
pgw->height = height;
pgw->color = White;
pgw->bgcolor = Black;
#if GDISP_NEED_TEXT
gw->font = 0;
pgw->font = defaultFont;
#endif
return (GHandle)gw;
return (GHandle)pgw;
}
GHandle gwinCreateWindow(GWindowObject *gw, 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 0;
gw->type = GW_WINDOW;
return (GHandle)gw;
GHandle gwinCreateWindow(GWindowObject *pgw, coord_t x, coord_t y, coord_t width, coord_t height) {
return _gwinInit(pgw, x, y, width, height, sizeof(GWindowObject), &basegwinVMT);
}
void gwinSetEnabled(GHandle gh, bool_t enabled) {
(void)gh;
(void)enabled;
}
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;
}
void gwinDestroy(GHandle gh) {
if (gh->vmt->Destroy)
gh->vmt->Destroy(gh);
// Clean up the structure
if (gh->flags & GWIN_FLG_DYNAMIC) {
@ -88,30 +70,17 @@ void gwinDestroyWindow(GHandle gh) {
}
}
void gwinDraw(GHandle gh) {
switch(gh->type) {
#if GWIN_NEED_BUTTON
case GW_BUTTON:
gwinButtonDraw(gh);
break;
#endif
#if GWIN_NEED_SLIDER
case GW_SLIDER:
gwinSliderDraw(gh);
break;
#endif
}
const char *gwinGetClassName(GHandle gh) {
return gh->vmt->classname;
}
#if GDISP_NEED_TEXT
void gwinSetDefaultFont(font_t font) {
defaultFont = font;
}
void gwinSetFont(GHandle gh, font_t 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
@ -120,13 +89,8 @@ void gwinClear(GHandle gh) {
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
#if GWIN_NEED_CONSOLE
if (gh->type == GW_CONSOLE) {
((GConsoleObject *)gh)->cx = 0;
((GConsoleObject *)gh)->cy = 0;
}
#endif
if (gh->vmt->AfterClear)
gh->vmt->AfterClear(gh);
}
void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) {

View File

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

View File

@ -19,140 +19,168 @@
#if (GFX_USE_GWIN && GWIN_NEED_SLIDER) || defined(__DOXYGEN__)
#include "gwin/internal.h"
#include "gwin/class_gwin.h"
#ifndef GWIN_SLIDER_DEAD_BAND
#define GWIN_SLIDER_DEAD_BAND 5
#endif
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
static void trackSliderDraw(GHandle gh, coord_t x, coord_t y);
#endif
// Prototypes for slider VMT functions
static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y);
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 = {
HTML2COLOR(0x404040), // color_edge;
HTML2COLOR(0x000000), // color_thumb;
HTML2COLOR(0x00E000), // color_active;
HTML2COLOR(0xE0E0E0), // color_inactive;
// The button VMT table
static const gwidgetVMT sliderVMT = {
{
"Slider", // The classname
_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 void gwinSliderCallback(void *param, GEvent *pe) {
GSourceListener *psl;
#define gh ((GHandle)param)
#define gsw ((GSliderObject *)param)
#define gsh ((GSourceHandle)param)
#define pme ((GEventMouse *)pe)
#define pde ((GEventDial *)pe)
#define pse ((GEventGWinSlider *)pe)
static const GSliderColors GSliderDefaultColors = {
HTML2COLOR(0x404040), // color_edge
HTML2COLOR(0x000000), // color_thumb
HTML2COLOR(0x00E000), // color_active
HTML2COLOR(0xE0E0E0), // color_inactive
HTML2COLOR(0xFFFFFF), // color_txt
};
switch (pe->type) {
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
case GEVENT_MOUSE:
case GEVENT_TOUCH:
// If not tracking we only only interested in a mouse down over the slider
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;
}
// Send the slider event
static void SendSliderEvent(GWidgetObject *gw) {
GSourceListener * psl;
GEvent * pe;
#define pse ((GEventGWinSlider *)pe)
// We are tracking the mouse
// 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
// Trigger a GWIN Button Event
psl = 0;
while ((psl = geventGetSourceListener(gsh, psl))) {
while ((psl = geventGetSourceListener((GSourceHandle)gw, psl))) {
if (!(pe = geventGetEventBuffer(psl)))
continue;
pse->type = GEVENT_GWIN_SLIDER;
pse->slider = gh;
pse->position = gsw->pos;
pse->slider = (GHandle)gw;
pse->position = ((GSliderObject *)gw)->pos;
geventSendEvent(psl);
}
#undef pse
#undef pme
#undef pxe
#undef gsh
#undef gsw
#undef pbe
}
// Reset the display position back to the value predicted by the saved slider position
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 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) {
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;
gs->gwin.type = GW_SLIDER;
gs->fn = gwinSliderDraw_Std;
gs->param = 0;
gwinSetSliderStyle(&gs->gwin, &GSliderDefaultStyle);
gs->c = GSliderDefaultColors;
gs->min = 0;
gs->max = 100;
gs->pos = 0;
gs->tracking = FALSE;
geventListenerInit(&gs->listener);
geventRegisterCallback(&gs->listener, gwinSliderCallback, gs);
ResetDisplayPos(gs);
return (GHandle)gs;
}
void gwinSetSliderRange(GHandle gh, int min, int max) {
#define gsw ((GSliderObject *)gh)
if (gh->type != GW_SLIDER)
if (gh->vmt != (gwinVMT *)&sliderVMT)
return;
if (min == max) // prevent divide by 0 errors.
@ -160,13 +188,14 @@ void gwinSetSliderRange(GHandle gh, int min, int max) {
gsw->min = min;
gsw->max = max;
gsw->pos = min;
ResetDisplayPos(gsw);
#undef gsw
}
void gwinSetSliderPosition(GHandle gh, int pos) {
#define gsw ((GSliderObject *)gh)
if (gh->type != GW_SLIDER)
if (gh->vmt != (gwinVMT *)&sliderVMT)
return;
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 gsw->pos = pos;
}
ResetDisplayPos(gsw);
#undef gsw
}
void gwinSetSliderStyle(GHandle gh, const GSliderDrawStyle *pStyle) {
#define gsw ((GSliderObject *)gh)
if (gh->type != GW_SLIDER)
void gwinSetSliderColors(GHandle gh, const GSliderColors *pColors) {
if (gh->vmt != (gwinVMT *)&sliderVMT)
return;
gsw->style.color_edge = pStyle->color_edge;
gsw->style.color_thumb = pStyle->color_thumb;
gsw->style.color_active = pStyle->color_active;
gsw->style.color_inactive = pStyle->color_inactive;
#undef gsw
((GSliderObject *)gh)->c = *pColors;
}
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
static void trackSliderDraw(GHandle gh, coord_t x, coord_t y) {
#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 gwinSliderDraw_Std(GWidgetObject *gw, void *param) {
#define gsw ((GSliderObject *)gw)
(void) param;
if (isVertical) {
if (thumbpos != gh->height-1)
gdispFillArea(gh->x, gh->y+thumbpos, gh->width, gh->height - thumbpos, pstyle->color_active);
if (thumbpos != 0)
gdispFillArea(gh->x, gh->y, gh->width, thumbpos, pstyle->color_inactive);
gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge);
gdispDrawLine(gh->x, gh->y+thumbpos, gh->x+gh->width-1, gh->y+thumbpos, pstyle->color_thumb);
if (thumbpos >= 2)
gdispDrawLine(gh->x, gh->y+thumbpos-2, gh->x+gh->width-1, gh->y+thumbpos-2, pstyle->color_thumb);
if (thumbpos <= gh->height-2)
gdispDrawLine(gh->x, gh->y+thumbpos+2, gh->x+gh->width-1, gh->y+thumbpos+2, pstyle->color_thumb);
if (gw->g.vmt != (gwinVMT *)&sliderVMT)
return;
if (gw->g.width < gw->g.height) { // Vertical slider
if (gsw->dpos != gw->g.height-1)
gdispFillArea(gw->g.x, gw->g.y+gsw->dpos, gw->g.width, gw->g.height - gsw->dpos, gsw->c.color_active);
if (gsw->dpos != 0)
gdispFillArea(gw->g.x, gw->g.y, gw->g.width, gsw->dpos, gsw->c.color_inactive);
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);
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 {
if (thumbpos != gh->width-1)
gdispFillArea(gh->x+thumbpos, gh->y, gh->width-thumbpos, gh->height, pstyle->color_inactive);
if (thumbpos != 0)
gdispFillArea(gh->x, gh->y, thumbpos, gh->height, pstyle->color_active);
gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge);
gdispDrawLine(gh->x+thumbpos, gh->y, gh->x+thumbpos, gh->y+gh->height-1, pstyle->color_thumb);
if (thumbpos >= 2)
gdispDrawLine(gh->x+thumbpos-2, gh->y, gh->x+thumbpos-2, gh->y+gh->height-1, pstyle->color_thumb);
if (thumbpos <= gh->width-2)
gdispDrawLine(gh->x+thumbpos+2, gh->y, gh->x+thumbpos+2, gh->y+gh->height-1, pstyle->color_thumb);
if (gsw->dpos != gw->g.width-1)
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)
gdispFillArea(gw->g.x, gw->g.y, gsw->dpos, gw->g.height, gsw->c.color_active);
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);
if (gsw->dpos >= 2)
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 (gsw->dpos <= gw->g.width-2)
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
bool_t gwinAttachSliderMouse(GHandle gh, uint16_t instance) {
GSourceHandle gsh;
void gwinSliderDraw_Image(GWidgetObject *gw, void *param) {
#define gsw ((GSliderObject *)gw)
#define gi ((gdispImage *)param)
coord_t z, v;
if (gh->type != GW_SLIDER || !(gsh = ginputGetMouse(instance)))
return FALSE;
if (gw->g.vmt != (gwinVMT *)&sliderVMT)
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
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
#undef gsw
}
#endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */
/** @} */