diff --git a/demos/modules/gwin/slider/gfxconf.h b/demos/modules/gwin/slider/gfxconf.h index fc8d356e..cb9fc1db 100644 --- a/demos/modules/gwin/slider/gfxconf.h +++ b/demos/modules/gwin/slider/gfxconf.h @@ -56,6 +56,7 @@ #define GWIN_NEED_WINDOWMANAGER TRUE #define GWIN_NEED_WIDGET TRUE #define GWIN_NEED_SLIDER TRUE +#define GWIN_NEED_CONSOLE TRUE /* Features for the GINPUT subsystem. */ #define GINPUT_NEED_MOUSE TRUE diff --git a/demos/modules/gwin/slider/main.c b/demos/modules/gwin/slider/main.c index bf0aacfc..781447b6 100644 --- a/demos/modules/gwin/slider/main.c +++ b/demos/modules/gwin/slider/main.c @@ -30,7 +30,7 @@ #include "gfx.h" static GListener gl; -static GHandle ghSlider1, ghSlider2; +static GHandle ghSlider1, ghSlider2, ghConsole; static void createWidgets(void) { GWidgetInit wi; @@ -40,16 +40,24 @@ static void createWidgets(void) { wi.g.show = TRUE; // create Slider1 - wi.g.y = 10; wi.g.x = 10; wi.g.width = 200; wi.g.height = 20; wi.text = "S1"; + wi.g.y = 10; wi.g.x = 10; wi.g.width = gdispGetWidth()-20; wi.g.height = 20; wi.text = "S1"; ghSlider1 = gwinSliderCreate(0, &wi); // create Slider2 - wi.g.y = 40; wi.g.x = 10; wi.g.width = 20; wi.g.height = 200; wi.text = "S2"; + wi.g.y = 40; wi.g.x = 10; wi.g.width = 20; wi.g.height = gdispGetHeight() - 50; wi.text = "S2"; ghSlider2 = gwinSliderCreate(0, &wi); + + // Set slider 2 to return extended events + gwinSliderSendExtendedEvents(ghSlider2, TRUE); + + // Console to display slider events + wi.g.y = 40; wi.g.x = 40; wi.g.width = gdispGetWidth()-50; wi.g.height = gdispGetHeight()-50; + ghConsole = gwinConsoleCreate(0, &wi.g); } int main(void) { - GEvent* pe; + GEventGWinSlider * pe; + const char * sAction; // Initialize the display gfxInit(); @@ -61,21 +69,32 @@ int main(void) { // create the widget createWidgets(); + gwinSetColor(ghConsole, Green); + gwinSetBgColor(ghConsole, White); + gwinClear(ghConsole); // We want to listen for widget events geventListenerInit(&gl); gwinAttachListener(&gl); while(1) { - // Get an Event - pe = geventEventWait(&gl, TIME_INFINITE); + // Get an Event (assume it is a slider event) + pe = (GEventGWinSlider *)geventEventWait(&gl, TIME_INFINITE); switch(pe->type) { case GEVENT_GWIN_SLIDER: - //printf("Slider %s = %d\n", gwinGetText(((GEventGWinSlider *)pe)->gwin), ((GEventGWinSlider *)pe)->position); + switch(pe->action) { + case GSLIDER_EVENT_SET: sAction = "SET"; break; + case GSLIDER_EVENT_CANCEL: sAction = "CANCEL"; break; + case GSLIDER_EVENT_MOVE: sAction = "MOVE"; break; + case GSLIDER_EVENT_START: sAction = "START"; break; + default: sAction = "????"; break; + } + gwinPrintf(ghConsole, "Slider %s = %d%% %s\n", gwinGetText(pe->gwin), pe->position, sAction); break; default: + // Oops - not a slider event. break; } } diff --git a/src/gwin/gwin_slider.c b/src/gwin/gwin_slider.c index f1230d5a..9652e6df 100644 --- a/src/gwin/gwin_slider.c +++ b/src/gwin/gwin_slider.c @@ -16,6 +16,8 @@ #include "gwin_class.h" +#define GSLIDER_FLG_EXTENDED_EVENTS (GWIN_FIRST_CONTROL_FLAG<<0) + #ifndef GWIN_SLIDER_DEAD_BAND #define GWIN_SLIDER_DEAD_BAND 5 #endif @@ -24,23 +26,58 @@ #define GWIN_SLIDER_TOGGLE_INC 20 // How many toggles to go from minimum to maximum #endif +// Calculate the slider position from the display position +static int CalculatePosFromDPos(GSliderObject *gsw) { + // Set the new position + if (gsw->w.g.width < gsw->w.g.height) { + if (gsw->dpos > gsw->w.g.height-GWIN_SLIDER_DEAD_BAND) + return gsw->min; + if (gsw->dpos < GWIN_SLIDER_DEAD_BAND) + return gsw->max; + return ((int)(gsw->w.g.height-1-gsw->dpos-GWIN_SLIDER_DEAD_BAND))*(gsw->max-gsw->min)/(gsw->w.g.height-2*GWIN_SLIDER_DEAD_BAND) + gsw->min; + } + if (gsw->dpos > gsw->w.g.width-GWIN_SLIDER_DEAD_BAND) + return gsw->max; + if (gsw->dpos < GWIN_SLIDER_DEAD_BAND) + return gsw->min; + return ((int)(gsw->dpos-GWIN_SLIDER_DEAD_BAND))*(gsw->max-gsw->min)/(gsw->w.g.width-2*GWIN_SLIDER_DEAD_BAND) + gsw->min; +} + // Send the slider event -static void SendSliderEvent(GWidgetObject *gw) { +static void SendSliderEvent(GSliderObject *gsw, uint8_t action) { GSourceListener * psl; GEvent * pe; #define pse ((GEventGWinSlider *)pe) - // Trigger a GWIN Button Event + // Does this slider want more than just SET events? + if (action != GSLIDER_EVENT_SET && !(gsw->w.g.flags & GSLIDER_FLG_EXTENDED_EVENTS)) + return; + psl = 0; while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) { + // Work out which action to send. + // This precedence order helps provide some protection against missed events. + // Saving it into srcflags works regardless of if a buffer is available. + if (psl->srcflags < action) + psl->srcflags = action; + + // Skip sending if no buffer is available if (!(pe = geventGetEventBuffer(psl))) continue; + + // Fill in the event pse->type = GEVENT_GWIN_SLIDER; - pse->gwin = (GHandle)gw; - pse->position = ((GSliderObject *)gw)->pos; + pse->gwin = (GHandle)gsw; + pse->action = psl->srcflags; #if GWIN_WIDGET_TAGS - pse->tag = gw->tag; + pse->tag = gsw->w.tag; #endif + + // If it is a cancel or set use the defined position else use the calculated position. + pse->position = pse->action >= GSLIDER_EVENT_CANCEL ? gsw->pos : CalculatePosFromDPos(gsw); + + // Cleanup and send. + psl->srcflags = 0; geventSendEvent(psl); } @@ -56,76 +93,72 @@ static void ResetDisplayPos(GSliderObject *gsw) { } #if GINPUT_NEED_MOUSE + // Set the display position from the mouse position + static void SetDisplayPosFromMouse(GSliderObject *gsw, coord_t x, coord_t y) { + if (gsw->w.g.width < gsw->w.g.height) + gsw->dpos = y < 0 ? 0 : (y >= gsw->w.g.height ? gsw->w.g.height-1 : y); + else + gsw->dpos = x < 0 ? 0 : (x >= gsw->w.g.width ? gsw->w.g.width-1 : x); + } + // 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 + #if !GWIN_BUTTON_LAZY_RELEASE // Are we over the slider? - if (x < 0 || x >= gh->width || y < 0 || y >= gh->height) { + if (x < 0 || x >= gsw->w.g.width || y < 0 || y >= gsw->w.g.height) { // No - restore the slider ResetDisplayPos(gsw); - _gwinUpdate(gh); + _gwinUpdate(&gsw->w.g); + SendSliderEvent(gsw, GSLIDER_EVENT_CANCEL); return; } #endif // Set the new position - if (gh->width < gh->height) { - if (y > gh->height-GWIN_SLIDER_DEAD_BAND) - gsw->pos = gsw->min; - else if (y < GWIN_SLIDER_DEAD_BAND) - gsw->pos = gsw->max; - else - gsw->pos = (uint16_t)((int32_t)(gh->height-1-y-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->height-2*GWIN_SLIDER_DEAD_BAND) + gsw->min); - } else { - if (x > gh->width-GWIN_SLIDER_DEAD_BAND) - gsw->pos = gsw->max; - else if (x < GWIN_SLIDER_DEAD_BAND) - gsw->pos = gsw->min; - else - gsw->pos = (uint16_t)((int32_t)(x-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->width-2*GWIN_SLIDER_DEAD_BAND) + gsw->min); - } + SetDisplayPosFromMouse(gsw, x, y); + gsw->pos = CalculatePosFromDPos(gsw); + // Update the display ResetDisplayPos(gsw); - _gwinUpdate(gh); + _gwinUpdate(&gsw->w.g); // Generate the event - SendSliderEvent(gw); - #undef gh + SendSliderEvent(gsw, GSLIDER_EVENT_SET); + #undef gsw } - // A mouse move (or mouse down) event + // A mouse down event + static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) { + #define gsw ((GSliderObject *)gw) + + // Determine the display position + SetDisplayPosFromMouse(gsw, x, y); + + // Update the display + _gwinUpdate(&gsw->w.g); + + // Send the event + SendSliderEvent(gsw, GSLIDER_EVENT_START); + + #undef gsw + } + + // A mouse move 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; - } + // Determine the display position + SetDisplayPosFromMouse(gsw, x, y); // Update the display - _gwinUpdate(&gw->g); + _gwinUpdate(&gsw->w.g); + + // Send the event + SendSliderEvent(gsw, GSLIDER_EVENT_MOVE); + #undef gsw } #endif @@ -136,11 +169,11 @@ static void ResetDisplayPos(GSliderObject *gsw) { #define gsw ((GSliderObject *)gw) if (role) { - gwinSliderSetPosition((GHandle)gw, gsw->pos+(gsw->max-gsw->min)/GWIN_SLIDER_TOGGLE_INC); - SendSliderEvent(gw); + gwinSliderSetPosition(&gsw->w.g, gsw->pos+(gsw->max-gsw->min)/GWIN_SLIDER_TOGGLE_INC); + SendSliderEvent(gsw, GSLIDER_EVENT_SET); } else { - gwinSliderSetPosition((GHandle)gw, gsw->pos-(gsw->max-gsw->min)/GWIN_SLIDER_TOGGLE_INC); - SendSliderEvent(gw); + gwinSliderSetPosition(&gsw->w.g, gsw->pos-(gsw->max-gsw->min)/GWIN_SLIDER_TOGGLE_INC); + SendSliderEvent(gsw, GSLIDER_EVENT_SET); } #undef gsw } @@ -167,10 +200,10 @@ static void ResetDisplayPos(GSliderObject *gsw) { gsw->pos = (uint16_t)((uint32_t)value*(gsw->max-gsw->min)/max + gsw->min); ResetDisplayPos(gsw); - _gwinUpdate((GHandle)gw); + _gwinUpdate(&gsw->w.g); // Generate the event - SendSliderEvent(gw); + SendSliderEvent(gsw, GSLIDER_EVENT_SET); #undef gsw } @@ -197,7 +230,7 @@ static const gwidgetVMT sliderVMT = { gwinSliderDraw_Std, // The default drawing routine #if GINPUT_NEED_MOUSE { - 0, // Process mouse down events (NOT USED) + MouseDown, // Process mouse down events MouseUp, // Process mouse up events MouseMove, // Process mouse move events }, @@ -275,6 +308,16 @@ void gwinSliderSetPosition(GHandle gh, int pos) { #undef gsw } +void gwinSliderSendExtendedEvents(GHandle gh, bool_t enabled) { + if (gh->vmt != (gwinVMT *)&sliderVMT) + return; + + if (enabled) + gh->flags |= GSLIDER_FLG_EXTENDED_EVENTS; + else + gh->flags &= ~GSLIDER_FLG_EXTENDED_EVENTS; +} + /*---------------------------------------------------------- * Custom Draw Routines *----------------------------------------------------------*/ diff --git a/src/gwin/gwin_slider.h b/src/gwin/gwin_slider.h index b88d6dfd..91a381a5 100644 --- a/src/gwin/gwin_slider.h +++ b/src/gwin/gwin_slider.h @@ -27,12 +27,18 @@ #define GEVENT_GWIN_SLIDER (GEVENT_GWIN_CTRL_FIRST+1) typedef struct GEventGWinSlider { - GEventType type; // The type of this event (GEVENT_GWIN_BUTTON) + GEventType type; // The type of this event (GEVENT_GWIN_SLIDER) GHandle gwin; // The slider that is returning results #if GWIN_WIDGET_TAGS WidgetTag tag; // The slider tag #endif int position; + + uint8_t action; + #define GSLIDER_EVENT_SET 4 /* Slider position is set. This is the only event returned by default */ + #define GSLIDER_EVENT_CANCEL 3 /* Slider position changing has been cancelled */ + #define GSLIDER_EVENT_START 2 /* Slider position has started changing */ + #define GSLIDER_EVENT_MOVE 1 /* Slider position has been moved */ } GEventGWinSlider; // There are currently no GEventGWinSlider listening flags - use 0 @@ -123,6 +129,19 @@ void gwinSliderSetPosition(GHandle gh, int pos); */ #define gwinSliderGetPosition(gh) (((GSliderObject *)(gh))->pos) +/** + * @brief Should the slider send extended events. + * + * @param[in] gh The window handle (must be a slider window) + * @param[in] enabled TRUE to enable extended events, FALSE to disable them + * + * @note The slider by default will only send slider events with an action of GSLIDER_EVENT_SET. + * This call can be used to enable other slider action's to be sent as events + * + * @api + */ +void gwinSliderSendExtendedEvents(GHandle gh, bool_t enabled); + /** * @brief Some custom slider drawing routines * @details These function may be passed to @p gwinSetCustomDraw() to get different slider drawing styles