crteensy Posted April 17, 2015 Report Posted April 17, 2015 Nothing earth-shattering, but I thought I might share my draggable button code. It might be interesting for others who want to implement their own custom widgets.It's based on uGFX's button and can be dragged around while the mouse is pressed over the button. It uses styles just like the original button. I have not tested the fancier dawing functions (arc, ellipse, polygons).There are two MouseMove functions in the .c file, the first (commented out) one doesn't add a dragging threshold. This is fine when used with a mouse. The second one (not commented out) adds a 5 pixel threshold before the button actually starts moving. This is a bit more convenient when used with flaky touch input.draggableButton.h:#include "gfx.h"#ifdef __cplusplusextern "C" {#endiftypedef struct GDraggableButtonObject { GWidgetObject w; #if GINPUT_NEED_TOGGLE uint16_t toggle; #endif coord_t hotspot_x; coord_t hotspot_y;} GDraggableButtonObject;GHandle gwinGDraggableButtonCreate(GDisplay *g, GDraggableButtonObject *gb, const GWidgetInit *pInit);#define gwinDraggableButtonCreate(gb, pInit) gwinGDraggableButtonCreate(GDISP, gb, pInit)void gwinDraggableButtonDraw_Normal(GWidgetObject *gw, void *param); // @< A standard button#if GDISP_NEED_ARC || defined(__DOXYGEN__) void gwinDraggableButtonDraw_Rounded(GWidgetObject *gw, void *param); // @< A rounded rectangle button#endif#if GDISP_NEED_ELLIPSE || defined(__DOXYGEN__) void gwinDraggableButtonDraw_Ellipse(GWidgetObject *gw, void *param); // @< A circular button#endif#if GDISP_NEED_CONVEX_POLYGON || defined(__DOXYGEN__) void gwinDraggableButtonDraw_ArrowUp(GWidgetObject *gw, void *param); // @< An up arrow button void gwinDraggableButtonDraw_ArrowDown(GWidgetObject *gw, void *param); // @< A down arrow button void gwinDraggableButtonDraw_ArrowLeft(GWidgetObject *gw, void *param); // @< A left arrow button void gwinDraggableButtonDraw_ArrowRight(GWidgetObject *gw, void *param); // @< A right arrow button#endif#if GDISP_NEED_IMAGE || defined(__DOXYGEN__) void gwinDraggableButtonDraw_Image(GWidgetObject *gw, void *param); // @< An image button - see the notes above on the param.#endif#ifdef __cplusplus}#endifdraggableButton.c:#include "draggableButton.h"#include #include "src/gwin/gwin_class.h"// Our pressed state#define GBUTTON_FLG_PRESSED (GWIN_FIRST_CONTROL_FLAG<<0)#define GBUTTON_FLG_MOVED (GWIN_FIRST_CONTROL_FLAG<<1)#if GINPUT_NEED_MOUSE // A mouse down has occurred over the button static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) { GDraggableButtonObject* p = (GDraggableButtonObject*)gw; gw->g.flags |= GBUTTON_FLG_PRESSED; p->hotspot_x = x; p->hotspot_y = y; _gwinUpdate((GHandle)gw); } // A mouse up has occurred (it is over the button, because the button can be dragged) static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y) { (void) x; (void) y; gw->g.flags &= ~GBUTTON_FLG_PRESSED; _gwinUpdate((GHandle)gw); if(!(gw->g.flags & GBUTTON_FLG_MOVED)) { _gwinSendEvent(&gw->g, GEVENT_GWIN_BUTTON); } else // dropped { gw->g.flags &= ~GBUTTON_FLG_MOVED; gwinRedrawDisplay(GDISP, FALSE); } }// // A mouse move has occurred// static void MouseMove(GWidgetObject *gw, coord_t x, coord_t y) {// GDraggableButtonObject* p = (GDraggableButtonObject*)gw;// coord_t winx = gwinGetScreenX((GWindowObject*)gw);// coord_t winy = gwinGetScreenY((GWindowObject*)gw);// gw->g.flags |= GBUTTON_FLG_MOVED;// #if(GWIN_NEED_CONTAINERS)// if (gw->g.parent)// {// GWindowObject* parent = gw->g.parent;// winx -= parent->x;// winy -= parent->y;// }// #endif//// gwinMove((GWindowObject *)gw, winx+x-p->hotspot_x, winy+y-p->hotspot_y);// } // A mouse move has occurred static void MouseMove(GWidgetObject *gw, coord_t x, coord_t y) { GDraggableButtonObject* p = (GDraggableButtonObject*)gw; coord_t winx = gwinGetScreenX((GWindowObject*)gw); coord_t winy = gwinGetScreenY((GWindowObject*)gw); // not moving yet? calculate displacement if (!(gw->g.flags & GBUTTON_FLG_MOVED)) { coord_t dx = abs(x - p->hotspot_x); coord_t dy = abs(y - p->hotspot_y); // displacement > 5 pixels in any direction: start moving if((dx > 5) || (dy > 5)) { gw->g.flags |= GBUTTON_FLG_MOVED; } } #if(GWIN_NEED_CONTAINERS) if (gw->g.parent) { GWindowObject* parent = gw->g.parent; winx -= parent->x; winy -= parent->y; } #endif if(gw->g.flags & GBUTTON_FLG_MOVED) { gwinMove((GWindowObject *)gw, winx+x-p->hotspot_x, winy+y-p->hotspot_y); } }#endif#if GINPUT_NEED_TOGGLE // A toggle off has occurred static void ToggleOff(GWidgetObject *gw, uint16_t role) { (void) role; gw->g.flags &= ~GBUTTON_FLG_PRESSED; _gwinUpdate((GHandle)gw); } // A toggle on has occurred static void ToggleOn(GWidgetObject *gw, uint16_t role) { (void) role; gw->g.flags |= GBUTTON_FLG_PRESSED; _gwinUpdate((GHandle)gw); // Trigger the event on button down (different than for mouse/touch) _gwinSendEvent(&gw->g, GEVENT_GWIN_BUTTON); } static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) { (void) role; ((GButtonObject *)gw)->toggle = instance; } static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) { (void) role; return ((GButtonObject *)gw)->toggle; }#endif// The button VMT tablestatic const gwidgetVMT draggableButtonVMT = { { "Draggable Button", // The classname sizeof(GButtonObject), // The object size _gwidgetDestroy, // The destroy routine _gwidgetRedraw, // The redraw routine 0, // The after-clear routine }, gwinDraggableButtonDraw_Normal, // The default drawing routine #if GINPUT_NEED_MOUSE { MouseDown, // Process mouse down events MouseUp, // Process mouse up events MouseMove, // Process mouse move events }, #endif #if GINPUT_NEED_TOGGLE { 1, // 1 toggle role ToggleAssign, // Assign Toggles ToggleGet, // Get Toggles ToggleOff, // Process toggle off events ToggleOn, // Process toggle on events }, #endif #if GINPUT_NEED_DIAL { 0, // No dial roles 0, // Assign Dials (NOT USED) 0, // Get Dials (NOT USED) 0, // Process dial move events (NOT USED) }, #endif};GHandle gwinGDraggableButtonCreate(GDisplay *g, GDraggableButtonObject *gw, const GWidgetInit *pInit) { if (!(gw = (GDraggableButtonObject *)_gwidgetCreate(g, &gw->w, pInit, &draggableButtonVMT))) return 0; #if GINPUT_NEED_TOGGLE gw->toggle = GWIDGET_NO_INSTANCE; #endif gwinSetVisible((GHandle)gw, pInit->g.show); return (GHandle)gw;}/*---------------------------------------------------------- * Custom Draw Routines *----------------------------------------------------------*/static const GColorSet *getDrawColors(GWidgetObject *gw) { if (!(gw->g.flags & GWIN_FLG_SYSENABLED)) return &gw->pstyle->disabled; if ((gw->g.flags & GBUTTON_FLG_PRESSED)) return &gw->pstyle->pressed; return &gw->pstyle->enabled;}#if GWIN_FLAT_STYLING void gwinDraggableButtonDraw_Normal(GWidgetObject *gw, void *param) { const GColorSet * pcol; (void) param; if (gw->g.vmt != (gwinVMT *)&draggableButtonVMT) return; pcol = getDrawColors(gw); gdispGFillStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); gdispGDrawLine(gw->g.display, 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->edge); gdispGDrawLine(gw->g.display, 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->edge); }#else void gwinDraggableButtonDraw_Normal(GWidgetObject *gw, void *param) { const GColorSet * pcol; fixed alpha; fixed dalpha; coord_t i; color_t tcol, bcol; (void) param; if (gw->g.vmt != (gwinVMT *)&draggableButtonVMT) return; pcol = getDrawColors(gw); /* Fill the box blended from variants of the fill color */ tcol = gdispBlendColor(White, pcol->fill, TOP_FADE); bcol = gdispBlendColor(Black, pcol->fill, BOTTOM_FADE); dalpha = FIXED(255)/gw->g.height; for(alpha = 0, i = 0; i < gw->g.height; i++, alpha += dalpha) gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y+i, gw->g.x+gw->g.width-2, gw->g.y+i, gdispBlendColor(bcol, tcol, NONFIXED(alpha))); gdispGDrawStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, justifyCenter); gdispGDrawLine(gw->g.display, 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->edge); gdispGDrawLine(gw->g.display, 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->edge); }#endif#if GDISP_NEED_ARC void gwinDraggableButtonDraw_Rounded(GWidgetObject *gw, void *param) { const GColorSet * pcol; (void) param; if (gw->g.vmt != (gwinVMT *)&draggableButtonVMT) return; pcol = getDrawColors(gw); gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); if (gw->g.width >= 2*RND_CNR_SIZE+10) { gdispGFillRoundedBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, RND_CNR_SIZE-1, pcol->fill); gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+RND_CNR_SIZE, gw->g.width-2, gw->g.height-(2*RND_CNR_SIZE), gw->text, gw->g.font, pcol->text, justifyCenter); gdispGDrawRoundedBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, RND_CNR_SIZE, pcol->edge); } else { gdispGFillStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); } }#endif#if GDISP_NEED_ELLIPSE void gwinDraggableButtonDraw_Ellipse(GWidgetObject *gw, void *param) { const GColorSet * pcol; (void) param; if (gw->g.vmt != (gwinVMT *)&draggableButtonVMT) return; pcol = getDrawColors(gw); gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); gdispGFillEllipse(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width/2-1, gw->g.height/2-1, pcol->fill); gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); gdispGDrawEllipse(gw->g.display, gw->g.x, gw->g.y, gw->g.width/2, gw->g.height/2, pcol->edge); }#endif#if GDISP_NEED_CONVEX_POLYGON void gwinDraggableButtonDraw_ArrowUp(GWidgetObject *gw, void *param) { const GColorSet * pcol; (void) param; point arw[7]; if (gw->g.vmt != (gwinVMT *)&draggableButtonVMT) return; pcol = getDrawColors(gw); 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; gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); gdispGFillConvexPoly(gw->g.display, gw->g.x, gw->g.y, arw, 7, pcol->fill); gdispGDrawPoly(gw->g.display, gw->g.x, gw->g.y, arw, 7, pcol->edge); gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); } void gwinDraggableButtonDraw_ArrowDown(GWidgetObject *gw, void *param) { const GColorSet * pcol; (void) param; point arw[7]; if (gw->g.vmt != (gwinVMT *)&draggableButtonVMT) return; pcol = getDrawColors(gw); 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; gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); gdispGFillConvexPoly(gw->g.display, gw->g.x, gw->g.y, arw, 7, pcol->fill); gdispGDrawPoly(gw->g.display, gw->g.x, gw->g.y, arw, 7, pcol->edge); gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); } void gwinDraggableButtonDraw_ArrowLeft(GWidgetObject *gw, void *param) { const GColorSet * pcol; (void) param; point arw[7]; if (gw->g.vmt != (gwinVMT *)&draggableButtonVMT) return; pcol = getDrawColors(gw); 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; gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); gdispGFillConvexPoly(gw->g.display, gw->g.x, gw->g.y, arw, 7, pcol->fill); gdispGDrawPoly(gw->g.display, gw->g.x, gw->g.y, arw, 7, pcol->edge); gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); } void gwinDraggableButtonDraw_ArrowRight(GWidgetObject *gw, void *param) { const GColorSet * pcol; (void) param; point arw[7]; if (gw->g.vmt != (gwinVMT *)&draggableButtonVMT) return; pcol = getDrawColors(gw); 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; gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); gdispGFillConvexPoly(gw->g.display, gw->g.x, gw->g.y, arw, 7, pcol->fill); gdispGDrawPoly(gw->g.display, gw->g.x, gw->g.y, arw, 7, pcol->edge); gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); }#endif#if GDISP_NEED_IMAGE || defined(__DOXYGEN__) void gwinDraggableButtonDraw_Image(GWidgetObject *gw, void *param) { const GColorSet * pcol; coord_t sy; if (gw->g.vmt != (gwinVMT *)&draggableButtonVMT) return; pcol = getDrawColors(gw); if (!(gw->g.flags & GWIN_FLG_SYSENABLED)) { sy = 2 * gw->g.height; } else if ((gw->g.flags & GBUTTON_FLG_PRESSED)) { sy = gw->g.height; } else { sy = 0; } gdispGImageDraw(gw->g.display, (gdispImage *)param, gw->g.x, gw->g.y, gw->g.width, gw->g.height, 0, sy); gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); }#endif
inmarket Posted April 17, 2015 Report Posted April 17, 2015 Very nice project and a great demo of a custom widget.Well done!
Joel Bodenmann Posted April 17, 2015 Report Posted April 17, 2015 Very nice! Keep up the good work!~ Tectu
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now