diff options
37 files changed, 1787 insertions, 537 deletions
diff --git a/demos/modules/gwin/frame/demo.mk b/demos/modules/gwin/frame/demo.mk new file mode 100644 index 00000000..b10701c9 --- /dev/null +++ b/demos/modules/gwin/frame/demo.mk @@ -0,0 +1,3 @@ +DEMODIR = $(GFXLIB)/demos/modules/gwin/frame +GFXINC += $(DEMODIR) +GFXSRC += $(DEMODIR)/main.c diff --git a/demos/modules/gwin/frame/gfxconf.h b/demos/modules/gwin/frame/gfxconf.h new file mode 100644 index 00000000..6809013d --- /dev/null +++ b/demos/modules/gwin/frame/gfxconf.h @@ -0,0 +1,107 @@ +/** + * This file has a different license to the rest of the uGFX 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. + */ + +/** + * Copy this file into your project directory and rename it as gfxconf.h + * Edit your copy to turn on the uGFX features you want to use. + * The values below are the defaults. You should delete anything + * you are leaving as default. + * + * Please use spaces instead of tabs in this file. + */ + +#ifndef _GFXCONF_H +#define _GFXCONF_H + +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS TRUE +//#define GFX_USE_OS_WIN32 TRUE +//#define GFX_USE_OS_LINUX TRUE +//#define GFX_USE_OS_OSX TRUE + + +/////////////////////////////////////////////////////////////////////////// +// GDISP // +/////////////////////////////////////////////////////////////////////////// +#define GFX_USE_GDISP TRUE + +#define GDISP_NEED_AUTOFLUSH FALSE +#define GDISP_NEED_TIMERFLUSH FALSE +#define GDISP_NEED_VALIDATION TRUE +#define GDISP_NEED_CLIP TRUE +#define GDISP_NEED_TEXT TRUE + #define GDISP_INCLUDE_FONT_UI2 TRUE +#define GDISP_NEED_CIRCLE TRUE +#define GDISP_NEED_CONVEX_POLYGON TRUE +#define GDISP_NEED_MULTITHREAD TRUE + +#define GDISP_DEFAULT_ORIENTATION GDISP_ROTATE_LANDSCAPE + +/////////////////////////////////////////////////////////////////////////// +// GWIN // +/////////////////////////////////////////////////////////////////////////// +#define GFX_USE_GWIN TRUE + +#define GWIN_NEED_WINDOWMANAGER TRUE + +#define GWIN_NEED_CONSOLE TRUE + #define GWIN_CONSOLE_USE_HISTORY TRUE + #define GWIN_CONSOLE_HISTORY_AVERAGING TRUE + #define GWIN_CONSOLE_HISTORY_ATCREATE TRUE + #define GWIN_CONSOLE_ESCSEQ TRUE + #define GWIN_CONSOLE_USE_BASESTREAM TRUE +#define GWIN_NEED_GRAPH TRUE + +#define GWIN_NEED_WIDGET TRUE + #define GWIN_NEED_LABEL TRUE + #define GWIN_LABEL_ATTRIBUTE TRUE + #define GWIN_NEED_BUTTON TRUE + #define GWIN_BUTTON_LAZY_RELEASE TRUE + #define GWIN_NEED_SLIDER TRUE + #define GWIN_NEED_CHECKBOX TRUE + #define GWIN_NEED_IMAGE FALSE + #define GWIN_NEED_IMAGE_ANIMATION TRUE + #define GWIN_NEED_RADIO TRUE + #define GWIN_NEED_LIST TRUE + #define GWIN_NEED_LIST_IMAGES FALSE + #define GWIN_NEED_PROGRESSBAR TRUE + #define GWIN_PROGRESSBAR_AUTO TRUE + #define GWIN_FLAT_STYLING TRUE +#define GWIN_NEED_CONTAINERS TRUE + #define GWIN_NEED_CONTAINER TRUE + #define GWIN_NEED_FRAME TRUE + + +/////////////////////////////////////////////////////////////////////////// +// GEVENT // +/////////////////////////////////////////////////////////////////////////// +#define GFX_USE_GEVENT TRUE + +/////////////////////////////////////////////////////////////////////////// +// GTIMER // +/////////////////////////////////////////////////////////////////////////// +#define GFX_USE_GTIMER TRUE + +/////////////////////////////////////////////////////////////////////////// +// GQUEUE // +/////////////////////////////////////////////////////////////////////////// +#define GFX_USE_GQUEUE TRUE + +#define GQUEUE_NEED_ASYNC TRUE +#define GQUEUE_NEED_GSYNC TRUE +#define GQUEUE_NEED_FSYNC FALSE +#define GQUEUE_NEED_BUFFERS FALSE + +/////////////////////////////////////////////////////////////////////////// +// GINPUT // +/////////////////////////////////////////////////////////////////////////// +#define GFX_USE_GINPUT TRUE + +#define GINPUT_NEED_MOUSE TRUE + +#endif /* _GFXCONF_H */ diff --git a/demos/modules/gwin/frame/main.c b/demos/modules/gwin/frame/main.c new file mode 100644 index 00000000..ebfeaa6e --- /dev/null +++ b/demos/modules/gwin/frame/main.c @@ -0,0 +1,47 @@ +#include "gfx.h" + +static GListener gl; +static GHandle ghFrame1; + +static void createWidgets(void) { + GWidgetInit wi; + + // Apply some default values for GWIN + gwinWidgetClearInit(&wi); + wi.g.show = TRUE; + + // Apply the frame parameters + wi.g.width = 400; + wi.g.height = 300; + wi.g.y = 10; + wi.g.x = 10; + wi.text = "Frame 1"; + + ghFrame1 = gwinFrameCreate(0, &wi, GWIN_FRAME_BORDER | GWIN_FRAME_CLOSE_BTN | GWIN_FRAME_MINMAX_BTN); +} + +int main(void) { + // Initialize the display + gfxInit(); + + // Attach the mouse input + gwinAttachMouse(0); + + // Set the widget defaults + gwinSetDefaultFont(gdispOpenFont("*")); + gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); + gdispClear(White); + + // create the widget + createWidgets(); + + // We want to listen for widget events + geventListenerInit(&gl); + gwinAttachListener(&gl); + + while(1) { + gfxSleepMilliseconds(1000); + } + + return 0; +} diff --git a/demos/modules/gwin/imagebox/main.c b/demos/modules/gwin/imagebox/main.c index c15f5fb3..d8ebbe73 100644 --- a/demos/modules/gwin/imagebox/main.c +++ b/demos/modules/gwin/imagebox/main.c @@ -41,7 +41,7 @@ static void createWidgets(void) { // create the first image widget wi.g.x = 10; wi.g.y = 10; wi.g.width = 200; wi.g.height = 100; - ghImage1 = gwinImageCreate(NULL, &wi.g); + ghImage1 = gwinImageCreate(0, &wi.g); gwinImageOpenFile(ghImage1, "ugfx_logo_banner.bmp"); } diff --git a/demos/modules/gwin/label/main.c b/demos/modules/gwin/label/main.c index 175c0d6e..918f2787 100644 --- a/demos/modules/gwin/label/main.c +++ b/demos/modules/gwin/label/main.c @@ -44,13 +44,13 @@ static void createWidgets(void) { // Create the IP label wi.g.width = 200; wi.g.height = 20; wi.g.x = 10, wi.g.y = 80; wi.text = "192.168.1.42"; - ghLabel1 = gwinLabelCreate(NULL, &wi); + ghLabel1 = gwinLabelCreate(0, &wi); gwinLabelSetAttribute(ghLabel1, 100, "Current IP:"); // Create the DHCP label wi.g.width = 200; wi.g.height = 20; wi.g.x = 10, wi.g.y = 100; wi.text = "Off"; - ghLabel2 = gwinLabelCreate(NULL, &wi); + ghLabel2 = gwinLabelCreate(0, &wi); gwinLabelSetAttribute(ghLabel2, 100, "DHCP:"); } diff --git a/demos/modules/gwin/list/main.c b/demos/modules/gwin/list/main.c index 6d469626..ed5b6905 100644 --- a/demos/modules/gwin/list/main.c +++ b/demos/modules/gwin/list/main.c @@ -43,12 +43,12 @@ static void createWidgets(void) { // Create the label for the first list wi.g.width = 150; wi.g.height = 20; wi.g.x = 10, wi.g.y = 80; wi.text = "List 1: Default"; - ghLabel1 = gwinLabelCreate(NULL, &wi); + ghLabel1 = gwinLabelCreate(0, &wi); // Create the label for the second list wi.g.width = 150; wi.g.height = 20; wi.g.x = 165, wi.g.y = 80; wi.text = "List 2: Smooth scrolling"; - ghLabel1 = gwinLabelCreate(NULL, &wi); + ghLabel1 = gwinLabelCreate(0, &wi); // The first list widget wi.g.width = 150; diff --git a/demos/modules/gwin/progressbar/main.c b/demos/modules/gwin/progressbar/main.c index 6fb53c2e..8e9e8352 100644 --- a/demos/modules/gwin/progressbar/main.c +++ b/demos/modules/gwin/progressbar/main.c @@ -9,7 +9,7 @@ static void _createWidget(void) { wi.g.show = TRUE; wi.g.y = 10; wi.g.x = 10; wi.g.width = 200; wi.g.height = 20; wi.text = "Progress 1"; - ghProgressbar = gwinProgressbarCreate(NULL, &wi); + ghProgressbar = gwinProgressbarCreate(0, &wi); } int main(void) { diff --git a/demos/modules/gwin/widgets/gfxconf.h b/demos/modules/gwin/widgets/gfxconf.h index 25065b27..9f8601b8 100644 --- a/demos/modules/gwin/widgets/gfxconf.h +++ b/demos/modules/gwin/widgets/gfxconf.h @@ -43,6 +43,7 @@ #define GDISP_NEED_IMAGE_GIF TRUE #define GDISP_DEFAULT_ORIENTATION GDISP_ROTATE_LANDSCAPE +#define GDISP_NEED_MULTITHREAD TRUE /////////////////////////////////////////////////////////////////////////// // GWIN // @@ -52,10 +53,14 @@ #define GWIN_NEED_WINDOWMANAGER TRUE #define GWIN_NEED_CONSOLE TRUE + #define GWIN_CONSOLE_USE_HISTORY TRUE + #define GWIN_CONSOLE_HISTORY_AVERAGING TRUE + #define GWIN_CONSOLE_HISTORY_ATCREATE TRUE #define GWIN_NEED_GRAPH TRUE #define GWIN_NEED_WIDGET TRUE #define GWIN_NEED_LABEL TRUE + #define GWIN_LABEL_ATTRIBUTE TRUE #define GWIN_NEED_BUTTON TRUE // #define GWIN_BUTTON_LAZY_RELEASE TRUE #define GWIN_NEED_SLIDER TRUE @@ -67,6 +72,9 @@ #define GWIN_NEED_PROGRESSBAR TRUE #define GWIN_PROGRESSBAR_AUTO TRUE +#define GWIN_NEED_CONTAINERS TRUE + #define GWIN_NEED_CONTAINER TRUE + /////////////////////////////////////////////////////////////////////////// // GEVENT // /////////////////////////////////////////////////////////////////////////// diff --git a/demos/modules/gwin/widgets/main.c b/demos/modules/gwin/widgets/main.c index 9742a027..69f90285 100644 --- a/demos/modules/gwin/widgets/main.c +++ b/demos/modules/gwin/widgets/main.c @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - +#include <stdio.h> #include "gfx.h" /** @@ -71,13 +71,15 @@ static const GWidgetStyle YellowWidgetStyle = { }; /* The variables we need */ +static font_t font; static GListener gl; static GHandle ghConsole; static GHandle ghTabButtons, ghTabSliders, ghTabCheckboxes, ghTabLabels, ghTabRadios, ghTabLists, ghTabImages, ghTabProgressbar; +static GHandle ghPgButtons, ghPgSliders, ghPgCheckboxes, ghPgLabels, ghPgRadios, ghPgLists, ghPgImages, ghPgProgressbars; static GHandle ghButton1, ghButton2, ghButton3, ghButton4; static GHandle ghSlider1, ghSlider2, ghSlider3, ghSlider4; static GHandle ghCheckbox1, ghCheckbox2, ghCheckDisableAll; -static GHandle ghLabel1; +static GHandle ghLabelSlider1, ghLabelSlider2, ghLabelSlider3, ghLabelSlider4, ghLabelRadio1; static GHandle ghRadio1, ghRadio2; static GHandle ghRadioBlack, ghRadioWhite, ghRadioYellow; static GHandle ghList1, ghList2, ghList3, ghList4; @@ -89,11 +91,12 @@ static gdispImage imgYesNo; #define ScrWidth gdispGetWidth() #define ScrHeight gdispGetHeight() +#define BUTTON_PADDING 20 #define TAB_HEIGHT 30 -#define LABEL_HEIGHT 40 +#define LABEL_HEIGHT 15 #define BUTTON_WIDTH 50 #define BUTTON_HEIGHT 30 -#define LIST_WIDTH 100 +#define LIST_WIDTH 75 #define LIST_HEIGHT 80 #define SLIDER_WIDTH 20 #define CHECKBOX_WIDTH 80 @@ -106,6 +109,20 @@ static gdispImage imgYesNo; #define GROUP_YESNO 1 #define GROUP_COLORS 2 +// Wrap tabs onto the next line if they don't fit. +static void setbtntext(GWidgetInit *pwi, coord_t maxwidth, char *txt) { + if (pwi->g.x >= maxwidth) { + pwi->g.x = 0; + pwi->g.y += pwi->g.height; + } + pwi->text = txt; + pwi->g.width = gdispGetStringWidth(pwi->text, font) + BUTTON_PADDING; + if (pwi->g.x + pwi->g.width > maxwidth) { + pwi->g.x = 0; + pwi->g.y += pwi->g.height; + } +} + /** * Create all the widgets. * With the exception of the Tabs they are all created invisible. @@ -117,86 +134,132 @@ static void createWidgets(void) { // Create the Tabs wi.g.show = TRUE; wi.customDraw = gwinRadioDraw_Tab; - wi.g.width = ScrWidth/7; wi.g.height = TAB_HEIGHT; wi.g.y = 0; - wi.g.x = 0*wi.g.width; wi.text = "Buttons"; + wi.g.height = TAB_HEIGHT; wi.g.y = 0; + wi.g.x = 0; setbtntext(&wi, ScrWidth, "Buttons"); ghTabButtons = gwinRadioCreate(0, &wi, GROUP_TABS); - wi.g.x = 1*wi.g.width; wi.text = "Sliders"; + wi.g.x += wi.g.width; setbtntext(&wi, ScrWidth, "Sliders"); ghTabSliders = gwinRadioCreate(0, &wi, GROUP_TABS); - wi.g.x = 2*wi.g.width; wi.text = "Checkbox"; + wi.g.x += wi.g.width; setbtntext(&wi, ScrWidth, "Checkbox"); ghTabCheckboxes = gwinRadioCreate(0, &wi, GROUP_TABS); - wi.g.x = 3*wi.g.width; wi.text = "Radios"; + wi.g.x += wi.g.width; setbtntext(&wi, ScrWidth, "Radios"); ghTabRadios = gwinRadioCreate(0, &wi, GROUP_TABS); - wi.g.x = 4*wi.g.width; wi.text = "Lists"; + wi.g.x += wi.g.width; setbtntext(&wi, ScrWidth, "Lists"); ghTabLists = gwinRadioCreate(0, &wi, GROUP_TABS); - wi.g.x = 5*wi.g.width; wi.text = "Labels"; + wi.g.x += wi.g.width; setbtntext(&wi, ScrWidth, "Labels"); ghTabLabels = gwinRadioCreate(0, &wi, GROUP_TABS); - wi.g.x = 6*wi.g.width; wi.text = "Images"; + wi.g.x += wi.g.width; setbtntext(&wi, ScrWidth, "Images"); ghTabImages = gwinRadioCreate(0, &wi, GROUP_TABS); - wi.g.y = TAB_HEIGHT; - wi.g.x = 0*wi.g.width; wi.text = "Progressbar"; + wi.g.x += wi.g.width; setbtntext(&wi, ScrWidth, "Progressbar"); ghTabProgressbar = gwinRadioCreate(0, &wi, GROUP_TABS); + wi.g.y += wi.g.height; + wi.customDraw = 0; + + // Create the Pages + wi.g.show = FALSE; + wi.g.x = 5; wi.g.y += 5; + wi.g.width = ScrWidth/2 - 10; wi.g.height = ScrHeight-wi.g.y-5; + ghPgButtons = gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER); + ghPgSliders = gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER); + ghPgCheckboxes = gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER); + ghPgRadios = gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER); + ghPgLists = gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER); + ghPgLabels = gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER); + ghPgImages = gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER); + ghPgProgressbars = gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER); + wi.g.show = TRUE; + + // Console - we apply some special colors before making it visible + wi.g.x = ScrWidth/2+1; + wi.g.width = ScrWidth/2 - 5; + ghConsole = gwinConsoleCreate(0, &wi.g); + gwinSetColor(ghConsole, Yellow); + gwinSetBgColor(ghConsole, Black); - // Buttons - wi.g.show = FALSE; wi.customDraw = 0; - wi.g.width = BUTTON_WIDTH; wi.g.height = BUTTON_HEIGHT; wi.g.y = 2*TAB_HEIGHT+10; - wi.g.x = 0+0*(BUTTON_WIDTH+1); wi.text = "B1"; + // Buttons + wi.g.parent = ghPgButtons; + wi.g.width = BUTTON_WIDTH; wi.g.height = BUTTON_HEIGHT; wi.g.y = 5; + wi.g.x = 5; setbtntext(&wi, gwinGetInnerWidth(ghPgButtons), "Button 1"); ghButton1 = gwinButtonCreate(0, &wi); - wi.g.x = 0+1*(BUTTON_WIDTH+1); wi.text = "B2"; + wi.g.x += wi.g.width+3; setbtntext(&wi, gwinGetInnerWidth(ghPgButtons), "Button 2"); ghButton2 = gwinButtonCreate(0, &wi); - wi.g.x = 0+2*(BUTTON_WIDTH+1); wi.text = "B3"; + wi.g.x += wi.g.width+3; setbtntext(&wi, gwinGetInnerWidth(ghPgButtons), "Button 3"); ghButton3 = gwinButtonCreate(0, &wi); - wi.g.x = 0+3*(BUTTON_WIDTH+1); wi.text = "B4"; + wi.g.x += wi.g.width+3; setbtntext(&wi, gwinGetInnerWidth(ghPgButtons), "Button 4"); ghButton4 = gwinButtonCreate(0, &wi); // Horizontal Sliders - wi.g.width = ScrWidth/2-2; wi.g.height = SLIDER_WIDTH; wi.g.x = ScrWidth/2+1; - wi.g.y = ScrHeight/2-2*(SLIDER_WIDTH+1); wi.text = "S1"; + wi.g.parent = ghPgSliders; + wi.g.width = gwinGetInnerWidth(ghPgSliders) - 10; wi.g.height = SLIDER_WIDTH; + wi.g.x = 5; wi.g.y = 5; wi.text = "S1"; ghSlider1 = gwinSliderCreate(0, &wi); - wi.g.y = ScrHeight/2-1*(SLIDER_WIDTH+1); wi.text = "S2"; + gwinSliderSetPosition(ghSlider1, 33); + wi.g.y += wi.g.height + 1; wi.text = "S2"; ghSlider2 = gwinSliderCreate(0, &wi); + gwinSliderSetPosition(ghSlider2, 86); // Vertical Sliders - wi.g.width = SLIDER_WIDTH; wi.g.height = ScrHeight/2-2; wi.g.y = ScrHeight/2+1; - wi.g.x = 0+0*(SLIDER_WIDTH+1); wi.text = "S3"; + wi.g.y += wi.g.height + 5; + wi.g.width = SLIDER_WIDTH; wi.g.height = gwinGetInnerHeight(ghPgSliders) - 5 - wi.g.y; + wi.g.x = 5; wi.text = "S3"; ghSlider3 = gwinSliderCreate(0, &wi); - wi.g.x = 0+1*(SLIDER_WIDTH+1); wi.text = "S4"; + gwinSliderSetPosition(ghSlider3, 13); + wi.g.x += wi.g.width+1; wi.text = "S4"; ghSlider4 = gwinSliderCreate(0, &wi); + gwinSliderSetPosition(ghSlider4, 76); // Checkboxes - for the 2nd checkbox we apply special drawing before making it visible - wi.g.width = CHECKBOX_WIDTH; wi.g.height = CHECKBOX_HEIGHT; wi.g.x = 0; - wi.g.y = 2*TAB_HEIGHT+10+0*(CHECKBOX_HEIGHT+1); wi.text = "C1"; + wi.g.parent = ghPgCheckboxes; + wi.g.width = CHECKBOX_WIDTH; wi.g.height = CHECKBOX_HEIGHT; wi.g.x = 5; + wi.g.y = 5; wi.text = "C1"; ghCheckbox1 = gwinCheckboxCreate(0, &wi); wi.customDraw = gwinCheckboxDraw_CheckOnRight; - wi.g.y = 2*TAB_HEIGHT+10+1*(CHECKBOX_HEIGHT+1); wi.text = "C2"; + wi.g.y += wi.g.height+1; wi.text = "C2"; ghCheckbox2 = gwinCheckboxCreate(0, &wi); wi.customDraw = 0; wi.g.width = DISABLEALL_WIDTH; - wi.g.y = 2*TAB_HEIGHT+10+2*(CHECKBOX_HEIGHT+1); wi.text = "Disable All"; + wi.g.y += wi.g.height+1; wi.text = "Disable All"; ghCheckDisableAll = gwinCheckboxCreate(0, &wi); // Labels - wi.g.width = 0; wi.g.height = LABEL_HEIGHT; // dynamic width, fixed height - wi.g.y = 2*TAB_HEIGHT+10+2*(CHECKBOX_HEIGHT+1); wi.text = "Label"; - ghLabel1 = gwinLabelCreate(0, &wi); + wi.g.parent = ghPgLabels; + wi.g.width = 200; wi.g.height = LABEL_HEIGHT; + wi.g.x = wi.g.y = 5;wi.text = "N/A"; + ghLabelSlider1 = gwinLabelCreate(0, &wi); + gwinLabelSetAttribute(ghLabelSlider1, 100, "Slider 1:"); + wi.g.y += LABEL_HEIGHT + 2; + ghLabelSlider2 = gwinLabelCreate(0, &wi); + gwinLabelSetAttribute(ghLabelSlider2, 100, "Slider 2:"); + wi.g.y += LABEL_HEIGHT + 2; + ghLabelSlider3 = gwinLabelCreate(0, &wi); + gwinLabelSetAttribute(ghLabelSlider3, 100, "Slider 3:"); + wi.g.y += LABEL_HEIGHT + 2; + ghLabelSlider4 = gwinLabelCreate(0, &wi); + gwinLabelSetAttribute(ghLabelSlider4, 100, "Slider 4:"); + wi.g.y += LABEL_HEIGHT + 2; + ghLabelRadio1 = gwinLabelCreate(0, &wi); + gwinLabelSetAttribute(ghLabelRadio1, 100, "RadioButton 1:"); + // Radio Buttons - wi.g.width = RADIO_WIDTH; wi.g.height = RADIO_HEIGHT; wi.g.y = 2*TAB_HEIGHT+10; - wi.g.x = 0*wi.g.width; wi.text = "Yes"; + wi.g.parent = ghPgRadios; + wi.g.width = RADIO_WIDTH; wi.g.height = RADIO_HEIGHT; wi.g.y = 5; + wi.g.x = 5; wi.text = "Yes"; ghRadio1 = gwinRadioCreate(0, &wi, GROUP_YESNO); - wi.g.x = 1*wi.g.width; wi.text = "No"; + wi.g.x += wi.g.width; wi.text = "No"; if (wi.g.x + wi.g.width > gwinGetInnerWidth(ghPgRadios)) { wi.g.x = 0; wi.g.y += RADIO_HEIGHT; } ghRadio2 = gwinRadioCreate(0, &wi, GROUP_YESNO); + gwinRadioPress(ghRadio1); wi.g.width = COLOR_WIDTH; wi.g.y += RADIO_HEIGHT+5; - wi.g.x = 0*wi.g.width; wi.text = "Black"; + wi.g.x = 5; wi.text = "Black"; ghRadioBlack = gwinRadioCreate(0, &wi, GROUP_COLORS); - wi.g.x = 1*wi.g.width; wi.text = "White"; + wi.g.x += wi.g.width; wi.text = "White"; if (wi.g.x + wi.g.width > gwinGetInnerWidth(ghPgRadios)) { wi.g.x = 0; wi.g.y += RADIO_HEIGHT; } ghRadioWhite = gwinRadioCreate(0, &wi, GROUP_COLORS); - wi.g.x = 2*wi.g.width; wi.text = "Yellow"; + wi.g.x += wi.g.width; wi.text = "Yellow"; if (wi.g.x + wi.g.width > gwinGetInnerWidth(ghPgRadios)) { wi.g.x = 0; wi.g.y += RADIO_HEIGHT; } ghRadioYellow = gwinRadioCreate(0, &wi, GROUP_COLORS); gwinRadioPress(ghRadioWhite); // Lists - wi.g.show = FALSE; wi.customDraw = 0; - wi.g.width = LIST_WIDTH; wi.g.height = LIST_HEIGHT; wi.g.y = 2*TAB_HEIGHT+10; - wi.g.x = 0+0*(LIST_WIDTH+5); wi.text = "L1"; + wi.g.parent = ghPgLists; + wi.g.width = LIST_WIDTH; wi.g.height = LIST_HEIGHT; wi.g.y = 5; + wi.g.x = 5; wi.text = "L1"; ghList1 = gwinListCreate(0, &wi, FALSE); gwinListAddItem(ghList1, "Item 0", FALSE); gwinListAddItem(ghList1, "Item 1", FALSE); @@ -212,7 +275,7 @@ static void createWidgets(void) { gwinListAddItem(ghList1, "Item 11", FALSE); gwinListAddItem(ghList1, "Item 12", FALSE); gwinListAddItem(ghList1, "Item 13", FALSE); - wi.g.x = 0+1*(LIST_WIDTH+5); wi.text = "L2"; + wi.text = "L2"; wi.g.x += LIST_WIDTH+1; if (wi.g.x + LIST_WIDTH > gwinGetInnerWidth(ghPgLists)) { wi.g.x = 0; wi.g.y += LIST_HEIGHT+1; } ghList2 = gwinListCreate(0, &wi, TRUE); gwinListAddItem(ghList2, "Item 0", FALSE); gwinListAddItem(ghList2, "Item 1", FALSE); @@ -228,7 +291,7 @@ static void createWidgets(void) { gwinListAddItem(ghList2, "Item 11", FALSE); gwinListAddItem(ghList2, "Item 12", FALSE); gwinListAddItem(ghList2, "Item 13", FALSE); - wi.g.x = 0+2*(LIST_WIDTH+5); wi.text = "L3"; + wi.text = "L3"; wi.g.x += LIST_WIDTH+1; if (wi.g.x + LIST_WIDTH > gwinGetInnerWidth(ghPgLists)) { wi.g.x = 0; wi.g.y += LIST_HEIGHT+1; } ghList3 = gwinListCreate(0, &wi, TRUE); gwinListAddItem(ghList3, "Item 0", FALSE); gwinListAddItem(ghList3, "Item 1", FALSE); @@ -237,7 +300,7 @@ static void createWidgets(void) { gdispImageOpenFile(&imgYesNo, "image_yesno.gif"); gwinListItemSetImage(ghList3, 1, &imgYesNo); gwinListItemSetImage(ghList3, 3, &imgYesNo); - wi.g.x = 0+3*(LIST_WIDTH+5); wi.text = "L4"; + wi.text = "L4"; wi.g.x += LIST_WIDTH+1; if (wi.g.x + LIST_WIDTH > gwinGetInnerWidth(ghPgLists)) { wi.g.x = 0; wi.g.y += LIST_HEIGHT+1; } ghList4 = gwinListCreate(0, &wi, TRUE); gwinListAddItem(ghList4, "Item 0", FALSE); gwinListAddItem(ghList4, "Item 1", FALSE); @@ -256,23 +319,17 @@ static void createWidgets(void) { gwinListSetScroll(ghList4, scrollSmooth); // Image - wi.g.x = 20; wi.g.y = 2*TAB_HEIGHT+20; wi.g.width = 200; wi.g.height = 100; + wi.g.parent = ghPgImages; + wi.g.x = wi.g.y = 0; wi.g.width = gwinGetInnerWidth(ghPgImages); wi.g.height = gwinGetInnerHeight(ghPgImages); ghImage1 = gwinImageCreate(0, &wi.g); gwinImageOpenFile(ghImage1, "romfs_img_ugfx.gif"); // Progressbar - wi.g.show = FALSE; wi.customDraw = 0; - wi.g.width = 200; wi.g.height = 20; wi.g.y = 2*TAB_HEIGHT+10; - wi.g.x = 20; wi.text = "Progressbar 1"; + wi.g.parent = ghPgProgressbars; + wi.g.width = gwinGetInnerWidth(ghPgImages)-5; wi.g.height = SLIDER_WIDTH; wi.g.y = 5; + wi.g.x = 5; wi.text = "Progressbar 1"; ghProgressbar1 = gwinProgressbarCreate(0, &wi); gwinProgressbarSetResolution(ghProgressbar1, 10); - - // Console - we apply some special colors before making it visible - wi.g.width = ScrWidth/2-1; wi.g.height = ScrHeight/2-1; - wi.g.x = ScrWidth/2+1; wi.g.y = ScrHeight/2+1; - ghConsole = gwinConsoleCreate(0, &wi.g); - gwinSetColor(ghConsole, Yellow); - gwinSetBgColor(ghConsole, Black); } /** @@ -280,29 +337,14 @@ static void createWidgets(void) { */ static void setTab(GHandle tab) { /* Make sure everything is invisible first */ - gwinSetVisible(ghButton1, FALSE); - gwinSetVisible(ghButton2, FALSE); - gwinSetVisible(ghButton3, FALSE); - gwinSetVisible(ghButton4, FALSE); - gwinSetVisible(ghSlider1, FALSE); - gwinSetVisible(ghSlider2, FALSE); - gwinSetVisible(ghSlider3, FALSE); - gwinSetVisible(ghSlider4, FALSE); - gwinSetVisible(ghCheckbox1, FALSE); - gwinSetVisible(ghCheckbox2, FALSE); - gwinSetVisible(ghCheckDisableAll, FALSE); - gwinSetVisible(ghLabel1, FALSE); - gwinSetVisible(ghRadio1, FALSE); - gwinSetVisible(ghRadio2, FALSE); - gwinSetVisible(ghRadioWhite, FALSE); - gwinSetVisible(ghRadioBlack, FALSE); - gwinSetVisible(ghRadioYellow, FALSE); - gwinSetVisible(ghList1, FALSE); - gwinSetVisible(ghList2, FALSE); - gwinSetVisible(ghList3, FALSE); - gwinSetVisible(ghList4, FALSE); - gwinSetVisible(ghImage1, FALSE); - gwinSetVisible(ghProgressbar1, FALSE); + gwinHide(ghPgButtons); + gwinHide(ghPgSliders); + gwinHide(ghPgCheckboxes); + gwinHide(ghPgLabels); + gwinHide(ghPgRadios); + gwinHide(ghPgLists); + gwinHide(ghPgImages); + gwinHide(ghPgProgressbars); // Stop the progress bar gwinProgressbarStop(ghProgressbar1); @@ -310,36 +352,21 @@ static void setTab(GHandle tab) { /* Turn on widgets depending on the tab selected */ if (tab == ghTabButtons) { - gwinSetVisible(ghButton1, TRUE); - gwinSetVisible(ghButton2, TRUE); - gwinSetVisible(ghButton3, TRUE); - gwinSetVisible(ghButton4, TRUE); + gwinShow(ghPgButtons); } else if (tab == ghTabSliders) { - gwinSetVisible(ghSlider1, TRUE); - gwinSetVisible(ghSlider2, TRUE); - gwinSetVisible(ghSlider3, TRUE); - gwinSetVisible(ghSlider4, TRUE); + gwinShow(ghPgSliders); } else if (tab == ghTabCheckboxes) { - gwinSetVisible(ghCheckbox1, TRUE); - gwinSetVisible(ghCheckbox2, TRUE); - gwinSetVisible(ghCheckDisableAll, TRUE); + gwinShow(ghPgCheckboxes); } else if (tab == ghTabLabels) { - gwinSetVisible(ghLabel1, TRUE); + gwinShow(ghPgLabels); } else if (tab == ghTabRadios) { - gwinSetVisible(ghRadio1, TRUE); - gwinSetVisible(ghRadio2, TRUE); - gwinSetVisible(ghRadioWhite, TRUE); - gwinSetVisible(ghRadioBlack, TRUE); - gwinSetVisible(ghRadioYellow, TRUE); + gwinShow(ghPgRadios); } else if (tab == ghTabLists) { - gwinSetVisible(ghList1, TRUE); - gwinSetVisible(ghList2, TRUE); - gwinSetVisible(ghList3, TRUE); - gwinSetVisible(ghList4, TRUE); + gwinShow(ghPgLists); } else if (tab == ghTabImages) { - gwinSetVisible(ghImage1, TRUE); + gwinShow(ghPgImages); } else if (tab == ghTabProgressbar) { - gwinSetVisible(ghProgressbar1, TRUE); + gwinShow(ghPgProgressbars); // Start the progress bar gwinProgressbarStart(ghProgressbar1, 500); @@ -350,29 +377,17 @@ static void setTab(GHandle tab) { * Set the enabled state of every widget (except the tabs etc) */ static void setEnabled(bool_t ena) { - gwinSetEnabled(ghButton1, ena); - gwinSetEnabled(ghButton2, ena); - gwinSetEnabled(ghButton3, ena); - gwinSetEnabled(ghButton4, ena); - gwinSetEnabled(ghSlider1, ena); - gwinSetEnabled(ghSlider2, ena); - gwinSetEnabled(ghSlider3, ena); - gwinSetEnabled(ghSlider4, ena); + gwinSetEnabled(ghPgButtons, ena); + gwinSetEnabled(ghPgSliders, ena); + gwinSetEnabled(ghPgLabels, ena); + gwinSetEnabled(ghPgRadios, ena); + gwinSetEnabled(ghPgLists, ena); + gwinSetEnabled(ghPgImages, ena); + gwinSetEnabled(ghPgProgressbars, ena); + // Checkboxes we need to do individually so we don't disable the checkbox to re-enable everything gwinSetEnabled(ghCheckbox1, ena); gwinSetEnabled(ghCheckbox2, ena); //gwinSetEnabled(ghCheckDisableAll, TRUE); - gwinSetEnabled(ghLabel1, ena); - gwinSetEnabled(ghRadio1, ena); - gwinSetEnabled(ghRadio2, ena); - gwinSetEnabled(ghList1, ena); - gwinSetEnabled(ghList2, ena); - gwinSetEnabled(ghList3, ena); - gwinSetEnabled(ghList4, ena); - gwinSetEnabled(ghRadioWhite, ena); - gwinSetEnabled(ghRadioBlack, ena); - gwinSetEnabled(ghRadioYellow, ena); - gwinSetEnabled(ghImage1, ena); - gwinSetEnabled(ghProgressbar1, ena); } int main(void) { @@ -387,7 +402,8 @@ int main(void) { #endif // Set the widget defaults - gwinSetDefaultFont(gdispOpenFont("*")); + font = gdispOpenFont("*"); // Get the first defined font. + gwinSetDefaultFont(font); gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); gdispClear(White); @@ -405,7 +421,7 @@ int main(void) { #endif // Make the console visible - gwinSetVisible(ghConsole, TRUE); + gwinShow(ghConsole); gwinClear(ghConsole); // We want to listen for widget events @@ -452,14 +468,26 @@ int main(void) { // Set control visibility depending on the tab selected setTab(((GEventGWinRadio *)pe)->radio); - // Do some special animation for Label1 to demonstrate auto width sizing + // We show the state of some of the GUI elements here if (((GEventGWinRadio *)pe)->radio == ghTabLabels) { - gwinPrintf(ghConsole, "Change Label Text\n"); - gfxSleepMilliseconds(1000); - gwinSetText(ghLabel1, "Very Big Label", FALSE); - - gfxSleepMilliseconds(1000); - gwinSetText(ghLabel1, "Label", FALSE); + char tmp[20]; + + // The sliders + snprintf(tmp, sizeof(tmp), "%d%%", gwinSliderGetPosition(ghSlider1)); + gwinSetText(ghLabelSlider1, tmp, TRUE); + snprintf(tmp, sizeof(tmp), "%d%%", gwinSliderGetPosition(ghSlider2)); + gwinSetText(ghLabelSlider2, tmp, TRUE); + snprintf(tmp, sizeof(tmp), "%d%%", gwinSliderGetPosition(ghSlider3)); + gwinSetText(ghLabelSlider3, tmp, TRUE); + snprintf(tmp, sizeof(tmp), "%d%%", gwinSliderGetPosition(ghSlider4)); + gwinSetText(ghLabelSlider4, tmp, TRUE); + + // The radio buttons + if (gwinRadioIsPressed(ghRadio1)) { + gwinSetText(ghLabelRadio1, "Yes", TRUE); + } else if (gwinRadioIsPressed(ghRadio2)) { + gwinSetText(ghLabelRadio1, "No", TRUE); + } } break; @@ -480,11 +508,13 @@ int main(void) { #if GDISP_NEED_CLIP gdispUnsetClip(); #endif - gdispFillArea(0, 0, ScrWidth, ScrHeight/2, pstyle->background); - gdispFillArea(0, ScrHeight/2, ScrWidth/2, ScrHeight/2, pstyle->background); + gdispClear(pstyle->background); // Update the style on all controls gwinSetDefaultStyle(pstyle, TRUE); + + // Redraw the console too + //gwinRedraw(ghConsole); } break; } diff --git a/docs/releases.txt b/docs/releases.txt index b08f970e..b7c019aa 100644 --- a/docs/releases.txt +++ b/docs/releases.txt @@ -2,7 +2,7 @@ *** Releases *** ***************************************************************************** -current release: 2.0 +*** Changes After 2.0 *** FIX: Significant improvements to the way the MCU touch driver works. FEATURE: Add support for edge to edge touch calibration. FEATURE: Added progressbar widget @@ -36,9 +36,12 @@ FEATURE: Added many GWIN simple demo's and updated the combined widget demo FEATURE: Added gwinEnable() and gwinDisable() FIX: Progressbar widget bug fix that could gwinProgressbarStop() to crash FIX: Imagebox widget bug fix that could cause gwinImageOpenFile() to crash +FEATURE: GWIN containers such as "container" and "frame" which provides parent/children widget management +FEATURE: Added gdispContrastColor() +FEATURE: Added gwinShow() and gwinHide() -*** changes after 1.9 *** +*** Release 2.0 *** FEATURE: GDISP Streaming API and demos. DEPRECATE: GDISP_NEED_ASYNC is now deprecated. DEPRECATE: 3rd party boing demo is now deprecated (replaced by GDISP Streaming demo) @@ -66,7 +69,7 @@ FEATURE: Board definitions, example projects and makefiles for the Marlin board. FEATURE: New invsqrt() routine added to GMISC -*** changes after 1.8 *** +*** Release 1.9 *** FEATURE: GWIN list boxes. FIX: POSIX port removed, now dedicated OS-X and Linux ports FIX: Several bugfixes @@ -80,7 +83,7 @@ FEATURE: Added gwinListSetScroll() FEATURE: Added gwinLabelSetBorder() -*** changes after 1.7 *** +*** Release 1.8 *** FEATURE: Rename of the project from ChibiOS/GFX to uGFX FEATURE: Moved from github.com to bitbucket.org FEATURE: New website with a lot more of documentation @@ -92,13 +95,13 @@ FIX: gfxHalt() fix for the Win32 port FIX: Cleaned up board file mess -*** changes after 1.6 *** +*** Release 1.7 *** FEATURE: Added RA8875 GDISP driver FEATURE: Added FT5x06 GINPUT/touch driver FIX: Several bugfixes -*** changes after 1.5 *** +*** Release 1.6 *** FEATURE: Added ILI9325 driver - Thanks to Chris van Dongen aka _Sjaak FEATURE: Added TDISP module FIX: tdispGotoXY() renamed to tdispSetCursor() @@ -130,7 +133,7 @@ FEATURE: Added GOS module (including sub modules such as GQUEUE) FEATURE: Added some functionalities to the TDISP module by user 'Frysk' -*** changes after 1.4 *** +*** Release 1.5 *** FEATURE: GEVENT - for passing event structures from Sources to Listeners FEATURE: GTIMER - thread context based once-off and periodic timers. FEATURE: GINPUT - extensible, multiple device-type, input sub-system. @@ -150,7 +153,7 @@ FEATURE: Added a number of module demo and test programs DEPRECATE: Remove of XPT2046 since full compatibility with ADS7843 -*** changes after 1.3 *** +*** Release 1.4 *** FIX: Nokia 6610 fix FEATURE: New driver: Win32 FEATURE: implementation of gdispFillArc() @@ -162,7 +165,7 @@ FEATURE: GWIN infrastructure FEATURE: now we fully support doxygen -*** changes after 1.2 *** +*** Release 1.3 *** FEATURE: added FSMC for SSD1289 / F4 FEATURE: added calibration storage interface FIX: bugfix in filling functions for SSD1289 @@ -170,7 +173,7 @@ FEATURE: added point_t struct in gdisp.h FEATURE: added graph module -*** changer after 1.1 *** +*** Release 1.2 *** FIX: orientation macros changed FIX: huge internal bugfix in orientation stuff (big thanks to Abhishek) FEATURE: added TOUCHPAD_XY_INVERTED macro @@ -182,7 +185,7 @@ FIX: lcdConsoleXXX() functions have been renamed to gfxConsoleXXX() FEATURE: FSMC for SSD1289 F2/F4 -*** changes after 1.0 *** +*** Release 1.1 *** FIX: removed gdisp and touchpad prefix of driver directories UPDATE: added SSD1963 driver FIX: fixed Validation, VMT driver, console and BitBlit diff --git a/gfxconf.example.h b/gfxconf.example.h index 6b545307..652b6a1b 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -9,8 +9,12 @@ /** * Copy this file into your project directory and rename it as gfxconf.h * Edit your copy to turn on the uGFX features you want to use. - * The values below are the defaults. You should delete anything - * you are leaving as default. + * The values below are the defaults. + * + * Only remove the comments from lines where you want to change the + * default value. This allows definitions to be included from + * driver makefiles when required and provides the best future + * compatibility for your project. * * Please use spaces instead of tabs in this file. */ @@ -24,7 +28,7 @@ /////////////////////////////////////////////////////////////////////////// //#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_FREERTOS FALSE - #define GFX_FREERTOS_USE_TRACE FALSE +// #define GFX_FREERTOS_USE_TRACE FALSE //#define GFX_USE_OS_WIN32 FALSE //#define GFX_USE_OS_LINUX FALSE //#define GFX_USE_OS_OSX FALSE @@ -33,217 +37,221 @@ /////////////////////////////////////////////////////////////////////////// // GDISP // /////////////////////////////////////////////////////////////////////////// -#define GFX_USE_GDISP FALSE - -#define GDISP_NEED_AUTOFLUSH FALSE -#define GDISP_NEED_TIMERFLUSH FALSE -#define GDISP_NEED_VALIDATION TRUE -#define GDISP_NEED_CLIP TRUE -#define GDISP_NEED_CIRCLE FALSE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_CONVEX_POLYGON FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_QUERY FALSE -#define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_STREAMING FALSE -#define GDISP_NEED_TEXT FALSE - #define GDISP_NEED_ANTIALIAS FALSE - #define GDISP_NEED_UTF8 FALSE - #define GDISP_NEED_TEXT_KERNING FALSE - #define GDISP_INCLUDE_FONT_UI1 FALSE - #define GDISP_INCLUDE_FONT_UI2 FALSE - #define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE - #define GDISP_INCLUDE_FONT_DEJAVUSANS10 FALSE - #define GDISP_INCLUDE_FONT_DEJAVUSANS12 FALSE - #define GDISP_INCLUDE_FONT_DEJAVUSANS16 FALSE - #define GDISP_INCLUDE_FONT_DEJAVUSANS24 FALSE - #define GDISP_INCLUDE_FONT_DEJAVUSANS32 FALSE - #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12 FALSE - #define GDISP_INCLUDE_FONT_FIXED_10X20 FALSE - #define GDISP_INCLUDE_FONT_FIXED_7X14 FALSE - #define GDISP_INCLUDE_FONT_FIXED_5X8 FALSE - #define GDISP_INCLUDE_FONT_DEJAVUSANS12_AA FALSE - #define GDISP_INCLUDE_FONT_DEJAVUSANS16_AA FALSE - #define GDISP_INCLUDE_FONT_DEJAVUSANS24_AA FALSE - #define GDISP_INCLUDE_FONT_DEJAVUSANS32_AA FALSE - #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12_AA FALSE - #define GDISP_INCLUDE_USER_FONTS FALSE - -#define GDISP_NEED_IMAGE FALSE - #define GDISP_NEED_IMAGE_NATIVE FALSE - #define GDISP_NEED_IMAGE_GIF FALSE - #define GDISP_NEED_IMAGE_BMP FALSE - #define GDISP_NEED_IMAGE_BMP_1 FALSE - #define GDISP_NEED_IMAGE_BMP_4 FALSE - #define GDISP_NEED_IMAGE_BMP_4_RLE FALSE - #define GDISP_NEED_IMAGE_BMP_8 FALSE - #define GDISP_NEED_IMAGE_BMP_8_RLE FALSE - #define GDISP_NEED_IMAGE_BMP_16 FALSE - #define GDISP_NEED_IMAGE_BMP_24 FALSE - #define GDISP_NEED_IMAGE_BMP_32 FALSE - #define GDISP_NEED_IMAGE_JPG FALSE - #define GDISP_NEED_IMAGE_PNG FALSE - #define GDISP_NEED_IMAGE_ACCOUNTING FALSE - -#define GDISP_NEED_STARTUP_LOGO TRUE - -#define GDISP_DEFAULT_ORIENTATION GDISP_ROTATE_LANDSCAPE -#define GDISP_LINEBUF_SIZE 128 - -#define GDISP_TOTAL_DISPLAYS 1 - #if GDISP_TOTAL_DISPLAYS > 1 - #define GDISP_HARDWARE_STREAM_WRITE FALSE - #define GDISP_HARDWARE_STREAM_READ FALSE - #define GDISP_HARDWARE_STREAM_POS FALSE - #define GDISP_HARDWARE_DRAWPIXEL FALSE - #define GDISP_HARDWARE_CLEARS FALSE - #define GDISP_HARDWARE_FILLS FALSE - #define GDISP_HARDWARE_BITFILLS FALSE - #define GDISP_HARDWARE_SCROLL FALSE - #define GDISP_HARDWARE_PIXELREAD FALSE - #define GDISP_HARDWARE_CONTROL FALSE - #define GDISP_HARDWARE_QUERY FALSE - #define GDISP_HARDWARE_CLIP FALSE - #endif - -#define GDISP_TOTAL_CONTROLLERS 1 - #if GDISP_TOTAL_CONTROLLERS > 1 - #define GDISP_CONTROLLER_LIST GDISPVMT_Win32, GDISPVMT_Win32 - #define GDISP_CONTROLLER_DISPLAYS 1, 1 - #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 - #endif - -#define GDISP_USE_GFXNET FALSE - #define GDISP_GFXNET_PORT 13001 - #define GDISP_GFXNET_CUSTOM_LWIP_STARTUP FALSE - #define GDISP_DONT_WAIT_FOR_NET_DISPLAY FALSE - #define GDISP_GFXNET_UNSAFE_SOCKETS FALSE +//#define GFX_USE_GDISP FALSE + +//#define GDISP_NEED_AUTOFLUSH FALSE +//#define GDISP_NEED_TIMERFLUSH FALSE +//#define GDISP_NEED_VALIDATION TRUE +//#define GDISP_NEED_CLIP TRUE +//#define GDISP_NEED_CIRCLE FALSE +//#define GDISP_NEED_ELLIPSE FALSE +//#define GDISP_NEED_ARC FALSE +//#define GDISP_NEED_CONVEX_POLYGON FALSE +//#define GDISP_NEED_SCROLL FALSE +//#define GDISP_NEED_PIXELREAD FALSE +//#define GDISP_NEED_CONTROL FALSE +//#define GDISP_NEED_QUERY FALSE +//#define GDISP_NEED_MULTITHREAD FALSE +//#define GDISP_NEED_STREAMING FALSE +//#define GDISP_NEED_TEXT FALSE +// #define GDISP_NEED_ANTIALIAS FALSE +// #define GDISP_NEED_UTF8 FALSE +// #define GDISP_NEED_TEXT_KERNING FALSE +// #define GDISP_INCLUDE_FONT_UI1 FALSE +// #define GDISP_INCLUDE_FONT_UI2 FALSE // The smallest preferred font. +// #define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS10 FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS12 FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS16 FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS24 FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS32 FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12 FALSE +// #define GDISP_INCLUDE_FONT_FIXED_10X20 FALSE +// #define GDISP_INCLUDE_FONT_FIXED_7X14 FALSE +// #define GDISP_INCLUDE_FONT_FIXED_5X8 FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS12_AA FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS16_AA FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS24_AA FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS32_AA FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12_AA FALSE +// #define GDISP_INCLUDE_USER_FONTS FALSE + +//#define GDISP_NEED_IMAGE FALSE +// #define GDISP_NEED_IMAGE_NATIVE FALSE +// #define GDISP_NEED_IMAGE_GIF FALSE +// #define GDISP_NEED_IMAGE_BMP FALSE +// #define GDISP_NEED_IMAGE_BMP_1 FALSE +// #define GDISP_NEED_IMAGE_BMP_4 FALSE +// #define GDISP_NEED_IMAGE_BMP_4_RLE FALSE +// #define GDISP_NEED_IMAGE_BMP_8 FALSE +// #define GDISP_NEED_IMAGE_BMP_8_RLE FALSE +// #define GDISP_NEED_IMAGE_BMP_16 FALSE +// #define GDISP_NEED_IMAGE_BMP_24 FALSE +// #define GDISP_NEED_IMAGE_BMP_32 FALSE +// #define GDISP_NEED_IMAGE_JPG FALSE +// #define GDISP_NEED_IMAGE_PNG FALSE +// #define GDISP_NEED_IMAGE_ACCOUNTING FALSE + +//#define GDISP_NEED_STARTUP_LOGO TRUE + +//#define GDISP_DEFAULT_ORIENTATION GDISP_ROTATE_LANDSCAPE // If not defined the native hardware orientation is used. +//#define GDISP_LINEBUF_SIZE 128 + +//#define GDISP_TOTAL_DISPLAYS 1 +// #if GDISP_TOTAL_DISPLAYS > 1 +// // For code and speed optimization define as TRUE or FALSE if all displays have the same capability +// #define GDISP_HARDWARE_STREAM_WRITE FALSE +// #define GDISP_HARDWARE_STREAM_READ FALSE +// #define GDISP_HARDWARE_STREAM_POS FALSE +// #define GDISP_HARDWARE_DRAWPIXEL FALSE +// #define GDISP_HARDWARE_CLEARS FALSE +// #define GDISP_HARDWARE_FILLS FALSE +// #define GDISP_HARDWARE_BITFILLS FALSE +// #define GDISP_HARDWARE_SCROLL FALSE +// #define GDISP_HARDWARE_PIXELREAD FALSE +// #define GDISP_HARDWARE_CONTROL FALSE +// #define GDISP_HARDWARE_QUERY FALSE +// #define GDISP_HARDWARE_CLIP FALSE +// #endif + +//#define GDISP_TOTAL_CONTROLLERS 1 +// #if GDISP_TOTAL_CONTROLLERS > 1 +// #define GDISP_CONTROLLER_LIST GDISPVMT_Win32, GDISPVMT_Win32 +// #define GDISP_CONTROLLER_DISPLAYS 1, 1 +// #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 +// #endif + +//#define GDISP_USE_GFXNET FALSE +// #define GDISP_GFXNET_PORT 13001 +// #define GDISP_GFXNET_CUSTOM_LWIP_STARTUP FALSE +// #define GDISP_DONT_WAIT_FOR_NET_DISPLAY FALSE +// #define GDISP_GFXNET_UNSAFE_SOCKETS FALSE /////////////////////////////////////////////////////////////////////////// // GWIN // /////////////////////////////////////////////////////////////////////////// -#define GFX_USE_GWIN FALSE - -#define GWIN_NEED_WINDOWMANAGER FALSE - -#define GWIN_NEED_CONSOLE FALSE - #define GWIN_CONSOLE_USE_HISTORY FALSE - #define GWIN_CONSOLE_HISTORY_AVERAGING FALSE - #define GWIN_CONSOLE_HISTORY_ATCREATE FALSE - #define GWIN_CONSOLE_ESCSEQ FALSE - #define GWIN_CONSOLE_USE_BASESTREAM FALSE - #define GWIN_CONSOLE_USE_FLOAT FALSE -#define GWIN_NEED_GRAPH FALSE - -#define GWIN_NEED_WIDGET FALSE - #define GWIN_NEED_LABEL FALSE - #define GWIN_LABEL_ATTRIBUTE FALSE - #define GWIN_NEED_BUTTON FALSE - #define GWIN_BUTTON_LAZY_RELEASE FALSE - #define GWIN_NEED_SLIDER FALSE - #define GWIN_NEED_CHECKBOX FALSE - #define GWIN_NEED_IMAGE FALSE - #define GWIN_NEED_IMAGE_ANIMATION FALSE - #define GWIN_NEED_RADIO FALSE - #define GWIN_NEED_LIST FALSE - #define GWIN_NEED_LIST_IMAGES FALSE - #define GWIN_NEED_PROGRESSBAR FALSE - #define GWIN_PROGRESSBAR_AUTO FALSE - #define GWIN_FLAT_STYLING FALSE +//#define GFX_USE_GWIN FALSE + +//#define GWIN_NEED_WINDOWMANAGER FALSE + +//#define GWIN_NEED_CONSOLE FALSE +// #define GWIN_CONSOLE_USE_HISTORY FALSE +// #define GWIN_CONSOLE_HISTORY_AVERAGING FALSE +// #define GWIN_CONSOLE_HISTORY_ATCREATE FALSE +// #define GWIN_CONSOLE_ESCSEQ FALSE +// #define GWIN_CONSOLE_USE_BASESTREAM FALSE +// #define GWIN_CONSOLE_USE_FLOAT FALSE +//#define GWIN_NEED_GRAPH FALSE + +//#define GWIN_NEED_WIDGET FALSE +// #define GWIN_NEED_LABEL FALSE +// #define GWIN_LABEL_ATTRIBUTE FALSE +// #define GWIN_NEED_BUTTON FALSE +// #define GWIN_BUTTON_LAZY_RELEASE FALSE +// #define GWIN_NEED_SLIDER FALSE +// #define GWIN_NEED_CHECKBOX FALSE +// #define GWIN_NEED_IMAGE FALSE +// #define GWIN_NEED_IMAGE_ANIMATION FALSE +// #define GWIN_NEED_RADIO FALSE +// #define GWIN_NEED_LIST FALSE +// #define GWIN_NEED_LIST_IMAGES FALSE +// #define GWIN_NEED_PROGRESSBAR FALSE +// #define GWIN_PROGRESSBAR_AUTO FALSE +// #define GWIN_FLAT_STYLING FALSE + +//#define GWIN_NEED_CONTAINERS FALSE +// #define GWIN_NEED_CONTAINER FALSE +// #define GWIN_NEED_FRAME FALSE /////////////////////////////////////////////////////////////////////////// // GEVENT // /////////////////////////////////////////////////////////////////////////// -#define GFX_USE_GEVENT FALSE +//#define GFX_USE_GEVENT FALSE -#define GEVENT_ASSERT_NO_RESOURCE FALSE -#define GEVENT_MAXIMUM_SIZE 32 -#define GEVENT_MAX_SOURCE_LISTENERS 32 +//#define GEVENT_ASSERT_NO_RESOURCE FALSE +//#define GEVENT_MAXIMUM_SIZE 32 +//#define GEVENT_MAX_SOURCE_LISTENERS 32 /////////////////////////////////////////////////////////////////////////// // GTIMER // /////////////////////////////////////////////////////////////////////////// -#define GFX_USE_GTIMER FALSE +//#define GFX_USE_GTIMER FALSE -#define GTIMER_THREAD_PRIORITY HIGH_PRIORITY -#define GTIMER_THREAD_WORKAREA_SIZE 2048 +//#define GTIMER_THREAD_PRIORITY HIGH_PRIORITY +//#define GTIMER_THREAD_WORKAREA_SIZE 2048 /////////////////////////////////////////////////////////////////////////// // GQUEUE // /////////////////////////////////////////////////////////////////////////// -#define GFX_USE_GQUEUE FALSE +//#define GFX_USE_GQUEUE FALSE -#define GQUEUE_NEED_ASYNC FALSE -#define GQUEUE_NEED_GSYNC FALSE -#define GQUEUE_NEED_FSYNC FALSE -#define GQUEUE_NEED_BUFFERS FALSE +//#define GQUEUE_NEED_ASYNC FALSE +//#define GQUEUE_NEED_GSYNC FALSE +//#define GQUEUE_NEED_FSYNC FALSE +//#define GQUEUE_NEED_BUFFERS FALSE /////////////////////////////////////////////////////////////////////////// // GINPUT // /////////////////////////////////////////////////////////////////////////// -#define GFX_USE_GINPUT FALSE +//#define GFX_USE_GINPUT FALSE -#define GINPUT_NEED_MOUSE FALSE -#define GINPUT_NEED_KEYBOARD FALSE -#define GINPUT_NEED_TOGGLE FALSE -#define GINPUT_NEED_DIAL FALSE +//#define GINPUT_NEED_MOUSE FALSE +//#define GINPUT_NEED_KEYBOARD FALSE +//#define GINPUT_NEED_TOGGLE FALSE +//#define GINPUT_NEED_DIAL FALSE /////////////////////////////////////////////////////////////////////////// // GFILE // /////////////////////////////////////////////////////////////////////////// -#define GFX_USE_GFILE FALSE +//#define GFX_USE_GFILE FALSE -#define GFILE_NEED_PRINTG FALSE -#define GFILE_NEED_SCANG FALSE -#define GFILE_NEED_STRINGS FALSE -#define GFILE_NEED_STDIO FALSE - #define GFILE_ALLOW_FLOATS FALSE - #define GFILE_ALLOW_DEVICESPECIFIC FALSE - #define GFILE_MAX_GFILES 3 +//#define GFILE_NEED_PRINTG FALSE +//#define GFILE_NEED_SCANG FALSE +//#define GFILE_NEED_STRINGS FALSE +//#define GFILE_NEED_STDIO FALSE +// #define GFILE_ALLOW_FLOATS FALSE +// #define GFILE_ALLOW_DEVICESPECIFIC FALSE +// #define GFILE_MAX_GFILES 3 -#define GFILE_NEED_MEMFS FALSE -#define GFILE_NEED_ROMFS FALSE -#define GFILE_NEED_RAMFS FALSE -#define GFILE_NEED_FATFS FALSE -#define GFILE_NEED_NATIVEFS FALSE -#define GFILE_NEED_CHBIOSFS FALSE +//#define GFILE_NEED_MEMFS FALSE +//#define GFILE_NEED_ROMFS FALSE +//#define GFILE_NEED_RAMFS FALSE +//#define GFILE_NEED_FATFS FALSE +//#define GFILE_NEED_NATIVEFS FALSE +//#define GFILE_NEED_CHBIOSFS FALSE /////////////////////////////////////////////////////////////////////////// // GADC // /////////////////////////////////////////////////////////////////////////// -#define GFX_USE_GADC FALSE +//#define GFX_USE_GADC FALSE -#define GADC_MAX_LOWSPEED_DEVICES 4 +//#define GADC_MAX_LOWSPEED_DEVICES 4 /////////////////////////////////////////////////////////////////////////// // GAUDIO // /////////////////////////////////////////////////////////////////////////// -#define GFX_USE_GAUDIO FALSE - #define GAUDIO_NEED_PLAY FALSE - #define GAUDIO_NEED_RECORD FALSE +//#define GFX_USE_GAUDIO FALSE +// #define GAUDIO_NEED_PLAY FALSE +// #define GAUDIO_NEED_RECORD FALSE /////////////////////////////////////////////////////////////////////////// // GMISC // /////////////////////////////////////////////////////////////////////////// -#define GFX_USE_GMISC FALSE - -#define GMISC_NEED_ARRAYOPS FALSE -#define GMISC_NEED_FASTTRIG FALSE -#define GMISC_NEED_FIXEDTRIG FALSE -#define GMISC_NEED_INVSQRT FALSE - #define GMISC_INVSQRT_MIXED_ENDIAN FALSE - #define GMISC_INVSQRT_REAL_SLOW FALSE - +//#define GFX_USE_GMISC FALSE + +//#define GMISC_NEED_ARRAYOPS FALSE +//#define GMISC_NEED_FASTTRIG FALSE +//#define GMISC_NEED_FIXEDTRIG FALSE +//#define GMISC_NEED_INVSQRT FALSE +// #define GMISC_INVSQRT_MIXED_ENDIAN FALSE +// #define GMISC_INVSQRT_REAL_SLOW FALSE #endif /* _GFXCONF_H */ diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 9f3ff11b..e9ede8ab 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -3020,13 +3020,23 @@ color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha) g += GREEN_OF(bg) * bg_ratio; b += BLUE_OF(bg) * bg_ratio; - r /= 256; - g /= 256; - b /= 256; + r >>= 8; + g >>= 8; + b >>= 8; return RGB2COLOR(r, g, b); } +color_t gdispContrastColor(color_t color) { + uint16_t r, g, b; + + r = RED_OF(color) > 128 ? 0 : 255; + g = GREEN_OF(color) > 128 ? 0 : 255; + b = BLUE_OF(color) > 128 ? 0 : 255; + + return RGB2COLOR(r, g, b); +} + #if (!defined(gdispPackPixels) && !defined(GDISP_PIXELFORMAT_CUSTOM)) void gdispPackPixels(pixel_t *buf, coord_t cx, coord_t x, coord_t y, color_t color) { /* No mutex required as we only read static data */ diff --git a/src/gdisp/sys_defs.h b/src/gdisp/sys_defs.h index a40d6e80..72fdc621 100644 --- a/src/gdisp/sys_defs.h +++ b/src/gdisp/sys_defs.h @@ -211,6 +211,16 @@ extern "C" { color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha); /** + * @brief Find a contrasting color + * @return The contrasting color + * + * @param[in] color The color to contrast + * + * @api + */ +color_t gdispContrastColor(color_t color); + +/** * @brief Get the specified display * @return The pointer to the display or NULL if the display doesn't exist * @note The GDISP variable contains the display used by the gdispXxxx routines diff --git a/src/gdisp/sys_options.h b/src/gdisp/sys_options.h index a38e4c6f..466bbb98 100644 --- a/src/gdisp/sys_options.h +++ b/src/gdisp/sys_options.h @@ -26,7 +26,7 @@ * @details Defaults to TRUE */ #ifndef GDISP_NEED_STARTUP_LOGO - #define GDISP_NEED_STARTUP_LOGO TRUE + #define GDISP_NEED_STARTUP_LOGO TRUE #endif /** * @brief Should drawing operations be automatically flushed. diff --git a/src/gfile/gfile.c b/src/gfile/gfile.c index 8a3abf9c..c711cfef 100644 --- a/src/gfile/gfile.c +++ b/src/gfile/gfile.c @@ -595,7 +595,7 @@ bool_t gfileEOF(GFILE *f) { if (c >= '0' && c <= '9') c -= '0'; else if (c == '*') - c = va_arg(ap, int); + c = va_arg(arg, int); else break; width = width * 10 + c; @@ -606,7 +606,7 @@ bool_t gfileEOF(GFILE *f) { if (c >= '0' && c <= '9') c -= '0'; else if (c == '*') - c = va_arg(ap, int); + c = va_arg(arg, int); else break; precision = precision * 10 + c; @@ -627,11 +627,11 @@ bool_t gfileEOF(GFILE *f) { return ret; case 'c': filler = ' '; - *p++ = va_arg(ap, int); + *p++ = va_arg(arg, int); break; case 's': filler = ' '; - if ((s = va_arg(ap, char *)) == 0) + if ((s = va_arg(arg, char *)) == 0) s = "(null)"; if (precision == 0) precision = 32767; @@ -640,9 +640,9 @@ bool_t gfileEOF(GFILE *f) { case 'D': case 'd': if (is_long) - l = va_arg(ap, long); + l = va_arg(arg, long); else - l = va_arg(ap, int); + l = va_arg(arg, int); if (l < 0) { *p++ = '-'; l = -l; @@ -651,7 +651,7 @@ bool_t gfileEOF(GFILE *f) { break; #if GFILE_ALLOW_FLOATS case 'f': - f = (float) va_arg(ap, double); + f = (float) va_arg(arg, double); if (f < 0) { *p++ = '-'; f = -f; @@ -676,9 +676,9 @@ bool_t gfileEOF(GFILE *f) { c = 8; unsigned_common: if (is_long) - l = va_arg(ap, long); + l = va_arg(arg, long); else - l = va_arg(ap, int); + l = va_arg(arg, int); p = ltoa_wd(p, l, c, 0); break; default: diff --git a/src/gfile/sys_options.h b/src/gfile/sys_options.h index 6e36e6b7..564cc2d7 100644 --- a/src/gfile/sys_options.h +++ b/src/gfile/sys_options.h @@ -133,7 +133,7 @@ * @brief Add floating point support to printg/scang etc. */ #ifndef GFILE_ALLOW_FLOATS - #define GFILE_ALLOW_FLOATS + #define GFILE_ALLOW_FLOATS FALSE #endif /** * @brief Can the device be specified as part of the file name. diff --git a/src/gwin/button.c b/src/gwin/button.c index f34e4ba3..da68d267 100644 --- a/src/gwin/button.c +++ b/src/gwin/button.c @@ -55,14 +55,14 @@ static void SendButtonEvent(GWidgetObject *gw) { static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) { (void) x; (void) y; gw->g.flags |= GBUTTON_FLG_PRESSED; - _gwidgetRedraw((GHandle)gw); + _gwidgetUpdate((GHandle)gw); } // 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; - _gwidgetRedraw((GHandle)gw); + _gwidgetUpdate((GHandle)gw); #if !GWIN_BUTTON_LAZY_RELEASE // If the mouse up was not over the button then cancel the event @@ -79,14 +79,14 @@ static void SendButtonEvent(GWidgetObject *gw) { static void ToggleOff(GWidgetObject *gw, uint16_t role) { (void) role; gw->g.flags &= ~GBUTTON_FLG_PRESSED; - _gwidgetRedraw((GHandle)gw); + _gwidgetUpdate((GHandle)gw); } // A toggle on has occurred static void ToggleOn(GWidgetObject *gw, uint16_t role) { (void) role; gw->g.flags |= GBUTTON_FLG_PRESSED; - _gwidgetRedraw((GHandle)gw); + _gwidgetUpdate((GHandle)gw); // Trigger the event on button down (different than for mouse/touch) SendButtonEvent(gw); } @@ -161,7 +161,7 @@ bool_t gwinButtonIsPressed(GHandle gh) { *----------------------------------------------------------*/ static const GColorSet *getDrawColors(GWidgetObject *gw) { - if (!(gw->g.flags & GWIN_FLG_ENABLED)) return &gw->pstyle->disabled; + 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; } @@ -336,7 +336,7 @@ static const GColorSet *getDrawColors(GWidgetObject *gw) { if (gw->g.vmt != (gwinVMT *)&buttonVMT) return; pcol = getDrawColors(gw); - if (!(gw->g.flags & GWIN_FLG_ENABLED)) { + if (!(gw->g.flags & GWIN_FLG_SYSENABLED)) { sy = 2 * gw->g.height; } else if ((gw->g.flags & GBUTTON_FLG_PRESSED)) { sy = gw->g.height; diff --git a/src/gwin/checkbox.c b/src/gwin/checkbox.c index 8cdd51d9..11d76cb2 100644 --- a/src/gwin/checkbox.c +++ b/src/gwin/checkbox.c @@ -48,7 +48,7 @@ static void SendCheckboxEvent(GWidgetObject *gw) { static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) { (void) x; (void) y; gw->g.flags ^= GCHECKBOX_FLG_CHECKED; - _gwidgetRedraw((GHandle)gw); + _gwidgetUpdate((GHandle)gw); SendCheckboxEvent(gw); } #endif @@ -57,7 +57,7 @@ static void SendCheckboxEvent(GWidgetObject *gw) { static void ToggleOn(GWidgetObject *gw, uint16_t role) { (void) role; gw->g.flags ^= GCHECKBOX_FLG_CHECKED; - _gwidgetRedraw((GHandle)gw); + _gwidgetUpdate((GHandle)gw); SendCheckboxEvent(gw); } @@ -130,7 +130,7 @@ void gwinCheckboxCheck(GHandle gh, bool_t isChecked) { if (!(gh->flags & GCHECKBOX_FLG_CHECKED)) return; gh->flags &= ~GCHECKBOX_FLG_CHECKED; } - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); SendCheckboxEvent((GWidgetObject *)gh); } @@ -146,7 +146,7 @@ bool_t gwinCheckboxIsChecked(GHandle gh) { *----------------------------------------------------------*/ static const GColorSet *getDrawColors(GWidgetObject *gw) { - if (!(gw->g.flags & GWIN_FLG_ENABLED)) return &gw->pstyle->disabled; + if (!(gw->g.flags & GWIN_FLG_SYSENABLED)) return &gw->pstyle->disabled; if ((gw->g.flags & GCHECKBOX_FLG_CHECKED)) return &gw->pstyle->pressed; return &gw->pstyle->enabled; } diff --git a/src/gwin/class_gwin.h b/src/gwin/class_gwin.h index 50dd480e..2c9b6a68 100644 --- a/src/gwin/class_gwin.h +++ b/src/gwin/class_gwin.h @@ -27,16 +27,20 @@ * @brief The predefined flags for a Window * @{ */ -#define GWIN_FLG_DYNAMIC 0x0001 // @< The GWIN structure is allocated -#define GWIN_FLG_VISIBLE 0x0002 // @< The window is visible -#define GWIN_FLG_MINIMIZED 0x0004 // @< The window is minimized -#define GWIN_FLG_MAXIMIZED 0x0008 // @< The window is maximized -#define GWIN_FLG_ENABLED 0x0010 // @< The window is enabled -#define GWIN_FLG_WIDGET 0x0020 // @< This is a widget -#define GWIN_FLG_ALLOCTXT 0x0040 // @< The widget text is allocated -#define GWIN_FLG_MOUSECAPTURE 0x0080 // @< The widget has captured the mouse -#define GWIN_FIRST_WM_FLAG 0x0100 // @< 4 bits free for the window manager to use -#define GWIN_FIRST_CONTROL_FLAG 0x1000 // @< 4 bits free for Windows and Widgets to use +#define GWIN_FIRST_CONTROL_FLAG 0x00000001 // @< 8 bits free for the control to use +#define GWIN_FLG_VISIBLE 0x00000100 // @< The window is "visible" +#define GWIN_FLG_SYSVISIBLE 0x00000200 // @< The window is visible after parents are tested +#define GWIN_FLG_ENABLED 0x00000400 // @< The window is "enabled" +#define GWIN_FLG_SYSENABLED 0x00000800 // @< The window is enabled after parents are tested +#define GWIN_FLG_DYNAMIC 0x00001000 // @< The GWIN structure is allocated +#define GWIN_FLG_ALLOCTXT 0x00002000 // @< The text/label is allocated +#define GWIN_FLG_MOUSECAPTURE 0x00004000 // @< The window has captured the mouse +#define GWIN_FLG_SUPERMASK 0x000F0000 // @< The bit mask to leave just the window superclass type +#define GWIN_FLG_WIDGET 0x00010000 // @< This is a widget +#define GWIN_FLG_CONTAINER 0x00020000 // @< This is a container +#define GWIN_FLG_MINIMIZED 0x00100000 // @< The window is minimized +#define GWIN_FLG_MAXIMIZED 0x00200000 // @< The window is maximized +#define GWIN_FIRST_WM_FLAG 0x01000000 // @< 8 bits free for the window manager to use /* @} */ /** @@ -104,6 +108,29 @@ typedef struct gwinVMT { /* @} */ #endif +#if GWIN_NEED_CONTAINERS || defined(__DOXYGEN__) + + /** + * @brief The Virtual Method Table for a container + * @note A container must have a destroy function. Either use @p _gcontainerDestroy() or use your own function + * which internally calls @p _gcontainerDestroy(). + * @note A container must have a gwin redraw function. Use @p _containerRedraw(). + * @note If toggleroles != 0, ToggleAssign(), ToggleGet() and one or both of ToggleOff() and ToggleOn() must be specified. + * @note If dialroles != 0, DialAssign(), DialGet() and DialMove() must be specified. + * @{ + */ + typedef struct gcontainerVMT { + gwidgetVMT gw; + coord_t (*LeftBorder) (GHandle gh); // @< The size of the left border (mandatory) + coord_t (*TopBorder) (GHandle gh); // @< The size of the top border (mandatory) + coord_t (*RightBorder) (GHandle gh); // @< The size of the right border (mandatory) + coord_t (*BottomBorder) (GHandle gh); // @< The size of the bottom border (mandatory) + void (*NotifyAdd) (GHandle gh, GHandle ghChild); // @< Notification that a child has been added (optional) + void (*NotifyDelete) (GHandle gh, GHandle ghChild); // @< Notification that a child has been deleted (optional) + } gcontainerVMT; + /* @} */ +#endif + // These flags are needed whether or not we are running a window manager. /** * @brief Flags for redrawing after a visibility change @@ -111,16 +138,11 @@ typedef struct gwinVMT { */ #define GWIN_WMFLG_PRESERVE 0x0001 // @< Preserve whatever existing contents possible if a window can't redraw #define GWIN_WMFLG_NOBGCLEAR 0x0002 // @< Don't clear the area if the window is not visible -#define GWIN_WMFLG_NOZORDER 0x0004 // @< Don't redraw higher z-order windows that overlap +#define GWIN_WMFLG_KEEPCLIP 0x0004 // @< Don't modify the preset clipping area +#define GWIN_WMFLG_NOZORDER 0x0008 // @< Don't redraw higher z-order windows that overlap /* @} */ #if GWIN_NEED_WINDOWMANAGER || defined(__DOXYGEN__) - #if 1 // When we know that wmq is the first element of the GWindowObject structure - #define QItem2GWindow(qi) ((GHandle)qi) - #else - #define QItem2GWindow(qi) ((GHandle)(((char *)(qi)) - (size_t)(&(((GWindowObject *)0)->wmq)))) - #endif - // @note There is only ever one instance of each GWindowManager type typedef struct GWindowManager { const struct gwmVMT *vmt; @@ -136,18 +158,14 @@ typedef struct gwinVMT { bool_t (*Add) (GHandle gh, const GWindowInit *pInit); // @< A window has been added void (*Delete) (GHandle gh); // @< A window has been deleted void (*Redraw) (GHandle gh, int visflags); // @< A window needs to be redraw (or undrawn) - void (*Redim) (GHandle gh, coord_t x, coord_t y, coord_t w, coord_t h); // @< A window wants to be moved or resized + void (*Size) (GHandle gh, coord_t w, coord_t h); // @< A window wants to be resized + void (*Move) (GHandle gh, coord_t x, coord_t y); // @< A window wants to be moved void (*Raise) (GHandle gh); // @< A window wants to be on top void (*MinMax) (GHandle gh, GWindowMinMax minmax); // @< A window wants to be minimized/maximised } gwmVMT; /* @} */ /** - * @brief The list of all windows in the system - */ - extern gfxQueueASync _GWINList; - - /** * @brief The current window manager */ extern GWindowManager * _GWINwm; @@ -197,13 +215,93 @@ GHandle _gwindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit void _gwidgetDestroy(GHandle gh); /** - * @brief Redraw the Widget object + * @brief Redraw the Widget object (VMT method only) * * @param[in] gh The widget to redraw * + * @note Do not use this routine to update a widget after a status change. + * Use @p _gwidgetUpdate() instead. The difference is that this routine + * does not set the clip region. This routine should only be used in the + * VMT. + * * @notapi */ void _gwidgetRedraw(GHandle gh); + + /** + * @brief Redraw the Widget object after a widget status change. + * + * @param[in] gh The widget to redraw + * + * @note Use this routine to update a widget after a status change. + * + * @notapi + */ + void _gwidgetUpdate(GHandle gh); +#endif + +#if GWIN_NEED_CONTAINERS || defined(__DOXYGEN__) + /** + * @brief Initialise (and allocate if necessary) the base Container object + * + * @param[in] g The GDisplay to display this window on + * @param[in] pgw The GContainerObject structure. If NULL one is allocated from the heap + * @param[in] pInit The user initialization parameters + * @param[in] vmt The virtual method table for the Container object + * + * @return The GHandle of the created widget + * + * @notapi + */ + GHandle _gcontainerCreate(GDisplay *g, GContainerObject *pgw, const GWidgetInit *pInit, const gcontainerVMT *vmt); + + /** + * @brief Destroy the Container object + * + * @param[in] gh The container to destroy + * + * @notapi + */ + void _gcontainerDestroy(GHandle gh); + + /** + * @brief Redraw the Container object (VMT method only) + * + * @param[in] gh The container to redraw + * + * @note Do not use this routine to update a container after a status change. + * Use @p _gcontainerUpdate() instead. The difference is that this routine + * does not set the clip region. This routine should only be used in the + * VMT. + * + * @notapi + */ + void _gcontainerRedraw(GHandle gh); + + /** + * @brief Redraw the Container object after a container status change. + * + * @param[in] gh The container to redraw + * + * @note Use this routine to update a container after a status change. + * + * @notapi + */ + void _gcontainerUpdate(GHandle gh); + + /** + * @brief Apply the specified action to a window and its children. + * @note The action is applied to the parent first and then its children. + * @note This routine is built to keep stack usage from recursing to a minimum. + * + * @param[in] gh The window to recurse through + * @param[in] fn The function to apply. If it returns TRUE any children it has should also have the function applied + * + * @notapi + */ + void _gwinRecurse(GHandle gh, bool_t (*fn)(GHandle gh)); +#else + #define _gwinRecurse(gh, fn) fn(gh) #endif #ifdef __cplusplus diff --git a/src/gwin/frame.c b/src/gwin/frame.c new file mode 100644 index 00000000..dad807ca --- /dev/null +++ b/src/gwin/frame.c @@ -0,0 +1,233 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file src/gwin/frame.c + * @brief GWIN sub-system frame code. + * + * @defgroup Frame Frame + * @ingroup GWIN + * + * @{ + */ + +#include "gfx.h" + +#if GFX_USE_GWIN && GWIN_NEED_FRAME + +#include "src/gwin/class_gwin.h" + +#if GWIN_FRAME_BORDER != GWIN_FIRST_CONTROL_FLAG + #error "GWIN Frame: - Flag definitions don't match" +#endif + +/* Some values for the default render */ +#define BORDER_X 5 +#define BORDER_Y 30 +#define BUTTON_X 20 +#define BUTTON_Y 20 + +/* Some useful macros for data type conversions */ +#define gh2obj ((GFrameObject *)gh) + +/* Forware declarations */ +static void gwinFrameDraw_Std(GWidgetObject *gw, void *param); +static void _callbackBtn(void *param, GEvent *pe); + +static coord_t BorderSizeLRB(GHandle gh) { return (gh->flags & GWIN_FRAME_BORDER) ? BORDER_X : 0; } +static coord_t BorderSizeT(GHandle gh) { return (gh->flags & GWIN_FRAME_BORDER) ? BORDER_Y : 0; } + +static void _frameDestroy(GHandle gh) { + /* Deregister the button callback */ + geventRegisterCallback(&gh2obj->gl, NULL, NULL); + geventDetachSource(&gh2obj->gl, NULL); + + /* call the gcontainer standard destroy routine */ + _gcontainerDestroy(gh); +} + +#if 0 && GINPUT_NEED_MOUSE + static void _mouseDown(GWidgetObject *gw, coord_t x, coord_t y) { + + } + + static void _mouseUp(GWidgetObject *gw, coord_t x, coord_t y) { + + } + + static void _mouseMove(GWidgetObject *gw, coord_t x, coord_t y) { + + } +#endif + +static const gcontainerVMT frameVMT = { + { + { + "Frame", // The classname + sizeof(GFrameObject), // The object size + _frameDestroy, // The destroy routie + _gcontainerRedraw, // The redraw routine + 0, // The after-clear routine + }, + gwinFrameDraw_Std, // The default drawing routine + #if GINPUT_NEED_MOUSE + { + 0,//_mouseDown, // Process mouse down event + 0,//_mouseUp, // Process mouse up events + 0,//_mouseMove, // Process mouse move events + }, + #endif + #if GINPUT_NEED_TOGGLE + { + 0, // 1 toggle role + 0, // Assign Toggles + 0, // Get Toggles + 0, // Process toggle off events + 0, // Process toggle on events + }, + #endif + #if GINPUT_NEED_DIAL + { + 0, // 1 dial roles + 0, // Assign Dials + 0, // Get Dials + 0, // Process dial move events + }, + #endif + }, + BorderSizeLRB, // The size of the left border (mandatory) + BorderSizeT, // The size of the top border (mandatory) + BorderSizeLRB, // The size of the right border (mandatory) + BorderSizeLRB, // The size of the bottom border (mandatory) + 0, // A child has been added (optional) + 0, // A child has been deleted (optional) +}; + +GHandle gwinGFrameCreate(GDisplay *g, GFrameObject *fo, GWidgetInit *pInit, uint32_t flags) { + if (!(fo = (GFrameObject *)_gcontainerCreate(g, &fo->gc, pInit, &frameVMT))) + return 0; + + fo->btnClose = 0; + fo->btnMin = 0; + fo->btnMax = 0; + + /* Buttons require a border */ + if ((flags & (GWIN_FRAME_CLOSE_BTN|GWIN_FRAME_MINMAX_BTN))) + flags |= GWIN_FRAME_BORDER; + + /* create and initialize the listener if any button is present. */ + if ((flags & (GWIN_FRAME_CLOSE_BTN|GWIN_FRAME_MINMAX_BTN))) { + geventListenerInit(&fo->gl); + gwinAttachListener(&fo->gl); + geventRegisterCallback(&fo->gl, _callbackBtn, (GHandle)fo); + } + + /* create close button if necessary */ + if ((flags & GWIN_FRAME_CLOSE_BTN)) { + GWidgetInit wi; + + gwinWidgetClearInit(&wi); + wi.g.show = TRUE; + wi.g.parent = &fo->gc.g; + + wi.g.x = fo->gc.g.width - BORDER_X - BUTTON_X; + wi.g.y = (BORDER_Y - BUTTON_Y) / 2; + wi.g.width = BUTTON_X; + wi.g.height = BUTTON_Y; + wi.text = "X"; + fo->btnClose = gwinGButtonCreate(g, 0, &wi); + } + + /* create minimize and maximize buttons if necessary */ + if ((flags & GWIN_FRAME_MINMAX_BTN)) { + GWidgetInit wi; + + gwinWidgetClearInit(&wi); + wi.g.show = TRUE; + wi.g.parent = &fo->gc.g; + + wi.g.x = (flags & GWIN_FRAME_CLOSE_BTN) ? fo->gc.g.width - 2*BORDER_X - 2*BUTTON_X : fo->gc.g.width - BORDER_X - BUTTON_X; + wi.g.y = (BORDER_Y - BUTTON_Y) / 2; + wi.g.width = BUTTON_X; + wi.g.height = BUTTON_Y; + wi.text = "O"; + fo->btnMin = gwinGButtonCreate(g, 0, &wi); + + wi.g.x = (flags & GWIN_FRAME_CLOSE_BTN) ? fo->gc.g.width - 3*BORDER_X - 3*BUTTON_X : fo->gc.g.width - BORDER_X - BUTTON_X; + wi.g.y = (BORDER_Y - BUTTON_Y) / 2; + wi.g.width = BUTTON_X; + wi.g.height = BUTTON_Y; + wi.text = "_"; + fo->btnMax = gwinGButtonCreate(g, 0, &wi); + } + + /* Apply flags. We apply these here so the controls above are outside the child area */ + fo->gc.g.flags |= flags; + + gwinSetVisible(&fo->gc.g, pInit->g.show); + + return &fo->gc.g; +} + +/* Process a button event */ +static void _callbackBtn(void *param, GEvent *pe) { + switch (pe->type) { + case GEVENT_GWIN_BUTTON: + if (((GEventGWinButton *)pe)->button == ((GFrameObject*)(GHandle)param)->btnClose) + gwinDestroy((GHandle)param); + + else if (((GEventGWinButton *)pe)->button == ((GFrameObject*)(GHandle)param)->btnMin) { + ;/* ToDo */ + + } else if (((GEventGWinButton *)pe)->button == ((GFrameObject*)(GHandle)param)->btnMax) { + ;/* ToDo */ + } + + break; + + default: + break; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Default render 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; +} + +static void gwinFrameDraw_Std(GWidgetObject *gw, void *param) { + const GColorSet *pcol; + (void)param; + + if (gw->g.vmt != (gwinVMT *)&frameVMT) + return; + + pcol = _getDrawColors(gw); + + // Render the actual frame (with border, if any) + if (gw->g.flags & GWIN_FRAME_BORDER) { + gdispGFillArea(gw->g.display, gw->g.x + BORDER_X, gw->g.y + BORDER_Y, gw->g.width - 2*BORDER_X, gw->g.height - BORDER_Y - BORDER_X, gw->pstyle->background); + gdispGFillStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, BORDER_Y, gw->text, gw->g.font, gdispContrastColor(pcol->edge), pcol->edge, justifyCenter); + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y+BORDER_Y, BORDER_X, gw->g.height-(BORDER_Y+BORDER_X), pcol->edge); + gdispGFillArea(gw->g.display, gw->g.x+gw->g.width-BORDER_X, gw->g.y+BORDER_Y, BORDER_X, gw->g.height-(BORDER_Y+BORDER_X), pcol->edge); + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y+gw->g.height-BORDER_X, gw->g.width, BORDER_X, pcol->edge); + } else { + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); + } +} + +#endif /* (GFX_USE_GWIN && GWIN_NEED_FRAME) || defined(__DOXYGEN__) */ +/** @} */ + diff --git a/src/gwin/frame.h b/src/gwin/frame.h new file mode 100644 index 00000000..8116b1de --- /dev/null +++ b/src/gwin/frame.h @@ -0,0 +1,70 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file src/gwin/frame.h + * @brief GWIN Graphic window subsystem header file. + * + * @defgroup Frame Frame + * @ingroup GWIN + * + * @details A frame is a rectangular window that can have optional border as well as buttons to + * close, maximize and minimize it. The main purpose of this widget is to contain children. + * + * @pre GFX_USE_GWIN must be set to TRUE in your gfxconf.h + * @pre GWIN_NEED_FRAME must be set to TRUE in your gfxconf.h + * @{ + */ + +#ifndef _GWIN_FRAME_H +#define _GWIN_FRAME_H + +/** + * @brief Flags for gwinFrameCreate() + * @{ + */ +#define GWIN_FRAME_BORDER 0x00000001 +#define GWIN_FRAME_CLOSE_BTN 0x00000002 +#define GWIN_FRAME_MINMAX_BTN 0x00000004 +/* @} */ + +typedef struct GFrameObject { + GContainerObject gc; + + GListener gl; // internal listener for the buttons + // These could probably be removed... I have to think harder later + GHandle btnClose; + GHandle btnMin; + GHandle btnMax; +} GFrameObject; + +/** + * @brief Create a frame widget + * + * @details This widget provides a window like we know it from desktop systems. You usually use this together with + * gwinAddChild(). + * + * @param[in] g The GDisplay to display this window on + * @param[in] fo The GFrameObject structure to initialize. If this is NULL the structure is dynamically allocated. + * @param[in] pInit The initialization parameters + * @param[in] flags Some flags, see notes. + * + * @note Possible flags are: GWIN_FRAME_BORDER, GWIN_FRAME_CLOSE_BTN, GWIN_FRAME_MINMAX_BTN. + * Whether the close or the minimize maximize buttons are used, the boarder is automatically invoked. + * @note These frame buttons are processed internally. The close button will invoke a gwinDestroy() which will + * destroy the window itself and EVERY child it contains (also children of children). + * + * @return NULL if there is no resulting widget. A valid GHandle otherwise. + * + * @api + */ +GHandle gwinGFrameCreate(GDisplay *g, GFrameObject *fo, GWidgetInit *pInit, uint32_t flags); +#define gwinFrameCreate(fo, pInit, flags) gwinGFrameCreate(GDISP, fo, pInit, flags); + +#endif /* _GWIN_FRAME_H */ +/** @} */ + diff --git a/src/gwin/gcontainer.c b/src/gwin/gcontainer.c new file mode 100644 index 00000000..3f6bfb56 --- /dev/null +++ b/src/gwin/gcontainer.c @@ -0,0 +1,193 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file src/gwin/gcontainer.c + * @brief GWIN sub-system container code. + * + * @defgroup Containers Containers + * @ingroup GWIN + * + * @{ + */ + +#include "gfx.h" + +#if GFX_USE_GWIN && GWIN_NEED_CONTAINERS + +#include "src/gwin/class_gwin.h" + +void _gcontainerInit(void) +{ +} + +void _gcontainerDeinit(void) +{ +} + +GHandle _gcontainerCreate(GDisplay *g, GContainerObject *pgc, const GWidgetInit *pInit, const gcontainerVMT *vmt) { + if (!(pgc = (GContainerObject *)_gwidgetCreate(g, (GWidgetObject *)pgc, pInit, &vmt->gw))) + return 0; + + pgc->g.flags |= GWIN_FLG_CONTAINER; + + return &pgc->g; +} + +void _gcontainerDestroy(GHandle gh) { + GHandle child; + + while((child = gwinGetFirstChild(gh))) + gwinDestroy(child); + _gwidgetDestroy(gh); +} + +void _gcontainerRedraw(GHandle gh) { + GHandle child; + + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) + return; + + ((GWidgetObject *)gh)->fnDraw((GWidgetObject *)gh, ((GWidgetObject *)gh)->fnParam); + + for(child = gwinGetFirstChild(gh); child; child = gwinGetSibling(child)) + gwinRedraw(child); +} + +void _gcontainerUpdate(GHandle gh) { + GHandle child; + + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) + return; + + #if GDISP_NEED_CLIP + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + #endif + ((GWidgetObject *)gh)->fnDraw((GWidgetObject *)gh, ((GWidgetObject *)gh)->fnParam); + + for(child = gwinGetFirstChild(gh); child; child = gwinGetSibling(child)) + gwinRedraw(child); +} + +void _gwinRecurse(GHandle gh, bool_t (*fn)(GHandle gh)) { + if (fn(gh) && (gh->flags & GWIN_FLG_CONTAINER)) { + // Apply to this windows children + for(gh = gwinGetFirstChild(gh); gh; gh = gwinGetSibling(gh)) { + // Only recurse when we have to. Otherwise apply it directly + if ((gh->flags & GWIN_FLG_CONTAINER)) + _gwinRecurse(gh, fn); + else + fn(gh); + } + } +} + +GHandle gwinGetFirstChild(GHandle gh) { + GHandle child; + + for(child = gwinGetNextWindow(0); child; child = gwinGetNextWindow(child)) + if (child->parent == gh) + return child; + return 0; +} + +GHandle gwinGetSibling(GHandle gh) { + GHandle child; + + for(child = gwinGetNextWindow(gh), gh = gh->parent; child; child = gwinGetNextWindow(child)) + if (child->parent == gh) + return child; + return 0; +} + +coord_t gwinGetInnerWidth(GHandle gh) { + if (!(gh->flags & GWIN_FLG_CONTAINER)) + return 0; + return gh->width - ((const gcontainerVMT *)gh->vmt)->LeftBorder(gh) - ((const gcontainerVMT *)gh->vmt)->RightBorder(gh); +} + +coord_t gwinGetInnerHeight(GHandle gh) { + if (!(gh->flags & GWIN_FLG_CONTAINER)) + return 0; + return gh->height - ((const gcontainerVMT *)gh->vmt)->TopBorder(gh) - ((const gcontainerVMT *)gh->vmt)->BottomBorder(gh); +} + +#endif /* GFX_USE_GWIN && GWIN_NEED_CONTAINERS */ +/** @} */ + +/*----------------------------------------------- + * The simplest container type - a container + *----------------------------------------------- + * + * @defgroup Containers Containers + * @ingroup GWIN + * + * @{ + */ + +#if GFX_USE_GWIN && GWIN_NEED_CONTAINER + +#if GWIN_CONTAINER_BORDER != GWIN_FIRST_CONTROL_FLAG + #error "GWIN Container: - Flag definitions don't match" +#endif + +static coord_t BorderSize(GHandle gh) { return (gh->flags & GWIN_CONTAINER_BORDER) ? 2 : 0; } + +static void DrawSimpleContainer(GWidgetObject *gw, void *param) { + (void) param; + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); + if ((gw->g.flags & GWIN_CONTAINER_BORDER)) + gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge); +} + +// The container VMT table +static const gcontainerVMT containerVMT = { + { + { + "Container", // The classname + sizeof(GContainerObject), // The object size + _gcontainerDestroy, // The destroy routine + _gcontainerRedraw, // The redraw routine + 0, // The after-clear routine + }, + DrawSimpleContainer, // The default drawing routine + #if GINPUT_NEED_MOUSE + { + 0, 0, 0, // No mouse + }, + #endif + #if GINPUT_NEED_TOGGLE + { + 0, 0, 0, 0, 0, // No toggles + }, + #endif + #if GINPUT_NEED_DIAL + { + 0, 0, 0, 0, // No dials + }, + #endif + }, + BorderSize, // The size of the left border (mandatory) + BorderSize, // The size of the top border (mandatory) + BorderSize, // The size of the right border (mandatory) + BorderSize, // The size of the bottom border (mandatory) + 0, // A child has been added (optional) + 0, // A child has been deleted (optional) +}; + +GHandle gwinGContainerCreate(GDisplay *g, GContainerObject *gc, const GWidgetInit *pInit, uint32_t flags) { + if (!(gc = (GContainerObject *)_gcontainerCreate(g, gc, pInit, &containerVMT))) + return 0; + + gc->g.flags |= flags; + + gwinSetVisible((GHandle)gc, pInit->g.show); + return (GHandle)gc; +} + +#endif +/** @} */ diff --git a/src/gwin/gcontainer.h b/src/gwin/gcontainer.h new file mode 100644 index 00000000..4a7b5632 --- /dev/null +++ b/src/gwin/gcontainer.h @@ -0,0 +1,136 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file src/gwin/gcontainer.h + * @brief GWIN Containers header file. + */ + +#ifndef _GCONTAINER_H +#define _GCONTAINER_H + +/* This file is included within "gwin/gwin.h" */ + +/** + * @defgroup Containers Containers + * @ingroup GWIN + * + * @details A Container is a GWindow that supports child windows. It is also + * a widget in its own right and therefore can accept user input directly. + * + * @pre GFX_USE_GWIN and GWIN_NEED_CONTAINERS must be set to TRUE in your gfxconf.h + * @{ + */ + +// Forward definition +struct GContainerObject; + +/** + * @brief The GWIN Container structure + * @note A container is a GWIN widget that can have children. + * @note Do not access the members directly. Treat it as a black-box and use the method functions. + * + * @{ + */ +typedef GWidgetObject GContainerObject; +/* @} */ + +/** + * A comment/rant on the above structure: + * We would really like the GWidgetObject 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 Get the first child window + * + * @return The first child or NULL if are no children windows + * + * @param[in] gh The parent container or NULL to get the first top level window + * + * @api + */ + GHandle gwinGetFirstChild(GHandle gh); + + /** + * @brief Get the next child window in the z-order + * + * @return The next window or NULL if no more children + * + * @param[in] gh The window to obtain the next sibling of. + * + * @note This returns the next window under the current parent window. + * Unlike @p gwinGetNextWindow() it will only return windows that + * have the same parent as the supplied window. + * + * @api + */ + GHandle gwinGetSibling(GHandle gh); + + /** + * @brief Get the inner width of a container window + * + * @return The inner width of a container window or zero if this is not a container + * + * @param[in] gh The window + * + * @api + */ + coord_t gwinGetInnerWidth(GHandle gh); + + /** + * @brief Get the inner height of a container window + * + * @return The inner height of a container window or zero if this is not a container + * + * @param[in] gh The window + * + * @api + */ + coord_t gwinGetInnerHeight(GHandle gh); + + + /** + * @brief Flags for gwinContainerCreate() + * @{ + */ + #define GWIN_CONTAINER_BORDER 0x00000001 + /* @} */ + + /** + * @brief Create a simple container. + * @return NULL if there is no resultant drawing area, otherwise a window handle. + * + * @param[in] g The GDisplay to display this window on + * @param[in] gb The GContainerObject structure to initialise. If this is NULL the structure is dynamically allocated. + * @param[in] pInit The initialisation parameters + * + * @api + */ + GHandle gwinGContainerCreate(GDisplay *g, GContainerObject *gw, const GWidgetInit *pInit, uint32_t flags); + #define gwinContainerCreate(gc, pInit, flags) gwinGContainerCreate(GDISP, gc, pInit, flags) + +#ifdef __cplusplus +} +#endif + +/* Include extra container types */ +#if GWIN_NEED_FRAME || defined(__DOXYGEN__) + #include "src/gwin/frame.h" +#endif + +#endif /* _GCONTAINER_H */ +/** @} */ diff --git a/src/gwin/gimage.c b/src/gwin/gimage.c index 9d6363ba..baf14ad1 100644 --- a/src/gwin/gimage.c +++ b/src/gwin/gimage.c @@ -30,7 +30,7 @@ static void _destroy(GWindowObject *gh) { #define gh ((GHandle)param) // We need to re-test the visibility in case it has been made invisible since the last frame. - if ((gh->flags & GWIN_FLG_VISIBLE)) { + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { // Setting the clip here shouldn't be necessary if the redraw doesn't overdraw // but we put it in for safety anyway #if GDISP_NEED_CLIP @@ -160,7 +160,7 @@ bool_t gwinImageOpenGFile(GHandle gh, GFILE *f) { if ((gdispImageOpenGFile(&widget(gh)->image, f) & GDISP_IMAGE_ERR_UNRECOVERABLE)) return FALSE; - if ((gh->flags & GWIN_FLG_VISIBLE)) { + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { // Setting the clip here shouldn't be necessary if the redraw doesn't overdraw // but we put it in for safety anyway #if GDISP_NEED_CLIP diff --git a/src/gwin/gwidget.c b/src/gwin/gwidget.c index c46520ea..ccfbd26e 100644 --- a/src/gwin/gwidget.c +++ b/src/gwin/gwidget.c @@ -82,16 +82,15 @@ static const GWidgetStyle * defaultStyle = &BlackWidgetStyle; /* Process an event */ static void gwidgetEvent(void *param, GEvent *pe) { - #define gh QItem2GWindow(qi) #define pme ((GEventMouse *)pe) #define pte ((GEventToggle *)pe) #define pde ((GEventDial *)pe) - const gfxQueueASyncItem * qi; + GHandle gh; #if GFX_USE_GINPUT && (GINPUT_NEED_TOGGLE || GINPUT_NEED_DIAL) - uint16_t role; + uint16_t role; #endif - (void) param; + (void) param; // Process various events switch (pe->type) { @@ -100,14 +99,14 @@ static void gwidgetEvent(void *param, GEvent *pe) { case GEVENT_MOUSE: case GEVENT_TOUCH: // Cycle through all windows - for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { // check if the widget matches this display if (gh->display != pme->display) continue; - // check if it a widget that is enabled and visible - if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) + // check if it is a widget that is enabled and visible + if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE)) continue; // Are we captured? @@ -134,10 +133,10 @@ static void gwidgetEvent(void *param, GEvent *pe) { #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE case GEVENT_TOGGLE: // Cycle through all windows - for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { // check if it a widget that is enabled and visible - if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) + if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE)) continue; for(role = 0; role < wvmt->toggleroles; role++) { @@ -158,10 +157,10 @@ static void gwidgetEvent(void *param, GEvent *pe) { #if GFX_USE_GINPUT && GINPUT_NEED_DIAL case GEVENT_DIAL: // Cycle through all windows - for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { // check if it a widget that is enabled and visible - if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) + if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE)) continue; for(role = 0; role < wvmt->dialroles; role++) { @@ -178,7 +177,6 @@ static void gwidgetEvent(void *param, GEvent *pe) { break; } - #undef gh #undef pme #undef pte #undef pde @@ -186,11 +184,10 @@ static void gwidgetEvent(void *param, GEvent *pe) { #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE static GHandle FindToggleUser(uint16_t instance) { - #define gh QItem2GWindow(qi) - const gfxQueueASyncItem * qi; - uint16_t role; + GHandle gh; + uint16_t role; - for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { if (!(gh->flags & GWIN_FLG_WIDGET)) // check if it a widget continue; @@ -200,17 +197,15 @@ static void gwidgetEvent(void *param, GEvent *pe) { } } return 0; - #undef gh } #endif #if GFX_USE_GINPUT && GINPUT_NEED_DIAL static GHandle FindDialUser(uint16_t instance) { - #define gh QItem2GWindow(qi) - const gfxQueueASyncItem * qi; - uint16_t role; + GHandle gh; + uint16_t role; - for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { if (!(gh->flags & GWIN_FLG_WIDGET)) // check if it a widget continue; @@ -220,7 +215,6 @@ static void gwidgetEvent(void *param, GEvent *pe) { } } return 0; - #undef gh } #endif @@ -236,9 +230,14 @@ void _gwidgetDeinit(void) } GHandle _gwidgetCreate(GDisplay *g, GWidgetObject *pgw, const GWidgetInit *pInit, const gwidgetVMT *vmt) { - if (!(pgw = (GWidgetObject *)_gwindowCreate(g, &pgw->g, &pInit->g, &vmt->g, GWIN_FLG_WIDGET|GWIN_FLG_ENABLED))) + if (!(pgw = (GWidgetObject *)_gwindowCreate(g, &pgw->g, &pInit->g, &vmt->g, GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED))) return 0; + #if GWIN_NEED_COLLECTIONS + // This window can't be system enabled if the parent is not enabled + if (pgw->parent && !(pgw->parent->flags & GWIN_FLG_SYSENABLED)) + pgw->g.flags &= ~GWIN_FLG_SYSENABLED; + #endif pgw->text = pInit->text ? pInit->text : ""; pgw->fnDraw = pInit->customDraw ? pInit->customDraw : vmt->DefaultDraw; pgw->fnParam = pInit->customParam; @@ -287,13 +286,19 @@ void _gwidgetDestroy(GHandle gh) { } void _gwidgetRedraw(GHandle gh) { - if (!(gh->flags & GWIN_FLG_VISIBLE)) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) + return; + + gw->fnDraw(gw, gw->fnParam); +} + +void _gwidgetUpdate(GHandle gh) { + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gw->fnDraw(gw, gw->fnParam); } @@ -310,13 +315,13 @@ void gwinSetDefaultStyle(const GWidgetStyle *pstyle, bool_t updateAll) { pstyle = &BlackWidgetStyle; if (updateAll) { - const gfxQueueASyncItem * qi; GHandle gh; - for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { - gh = QItem2GWindow(qi); + for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { if ((gh->flags & GWIN_FLG_WIDGET) && ((GWidgetObject *)gh)->pstyle == defaultStyle) gwinSetStyle(gh, pstyle); + else + gwinRedraw(gh); } } gwinSetDefaultBgColor(pstyle->background); @@ -359,7 +364,7 @@ void gwinSetText(GHandle gh, const char *text, bool_t useAlloc) { gw->text = (const char *)str; } else gw->text = text; - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); } const char *gwinGetText(GHandle gh) { @@ -375,7 +380,7 @@ void gwinSetStyle(GHandle gh, const GWidgetStyle *pstyle) { gw->pstyle = pstyle ? pstyle : defaultStyle; gh->bgcolor = pstyle->background; gh->color = pstyle->enabled.text; - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); } const GWidgetStyle *gwinGetStyle(GHandle gh) { @@ -391,7 +396,7 @@ void gwinSetCustomDraw(GHandle gh, CustomWidgetDrawFunction fn, void *param) { gw->fnDraw = fn ? fn : wvmt->DefaultDraw; gw->fnParam = param; - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); } bool_t gwinAttachListener(GListener *pl) { diff --git a/src/gwin/gwin.c b/src/gwin/gwin.c index 84443f9f..2e4144a7 100644 --- a/src/gwin/gwin.c +++ b/src/gwin/gwin.c @@ -39,10 +39,11 @@ static color_t defaultBgColor = Black; #if GWIN_NEED_WINDOWMANAGER #define _gwm_redraw(gh, flags) _GWINwm->vmt->Redraw(gh, flags) - #define _gwm_redim(gh,x,y,w,h) _GWINwm->vmt->Redim(gh,x,y,w,h); + #define _gwm_move(gh,x,y) _GWINwm->vmt->Move(gh,x,y); + #define _gwm_resize(gh,w,h) _GWINwm->vmt->Size(gh,w,h); #else static void _gwm_redraw(GHandle gh, int flags) { - if ((gh->flags & GWIN_FLG_VISIBLE)) { + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { if (gh->vmt->Redraw) { #if GDISP_NEED_CLIP gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); @@ -63,19 +64,22 @@ static color_t defaultBgColor = Black; gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, defaultBgColor); } } - static void _gwm_redim(GHandle gh, coord_t x, coord_t y, coord_t width, coord_t height) { - gh->x = x; gh->y = y; + static void _gwm_resize(GHandle gh, coord_t width, coord_t height) { gh->width = width; gh->height = height; - if (gh->x < 0) { gh->width += gh->x; gh->x = 0; } - if (gh->y < 0) { gh->height += gh->y; gh->y = 0; } - if (gh->x > gdispGetWidth()-MIN_WIN_WIDTH) gh->x = gdispGetWidth()-MIN_WIN_WIDTH; - if (gh->y > gdispGetHeight()-MIN_WIN_HEIGHT) gh->y = gdispGetHeight()-MIN_WIN_HEIGHT; if (gh->width < MIN_WIN_WIDTH) { gh->width = MIN_WIN_WIDTH; } if (gh->height < MIN_WIN_HEIGHT) { gh->height = MIN_WIN_HEIGHT; } if (gh->x+gh->width > gdispGetWidth()) gh->width = gdispGetWidth() - gh->x; if (gh->y+gh->height > gdispGetHeight()) gh->height = gdispGetHeight() - gh->y; - - // Redraw the window + _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); + } + static void _gwm_move(GHandle gh, coord_t x, coord_t y) { + gh->x = x; gh->y = y; + if (gh->x < 0) gh->x = 0; + if (gh->y < 0) gh->y = 0; + if (gh->x > gdispGetWidth()-MIN_WIN_WIDTH) gh->x = gdispGetWidth()-MIN_WIN_WIDTH; + if (gh->y > gdispGetHeight()-MIN_WIN_HEIGHT) gh->y = gdispGetHeight()-MIN_WIN_HEIGHT; + if (gh->x+gh->width > gdispGetWidth()) gh->width = gdispGetWidth() - gh->x; + if (gh->y+gh->height > gdispGetHeight()) gh->height = gdispGetHeight() - gh->y; _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); } #endif @@ -86,20 +90,30 @@ static color_t defaultBgColor = Black; void _gwinInit(void) { + #if GWIN_NEED_WINDOWMANAGER + extern void _gwmInit(void); + + _gwmInit(); + #endif #if GWIN_NEED_WIDGET extern void _gwidgetInit(void); _gwidgetInit(); #endif - #if GWIN_NEED_WINDOWMANAGER - extern void _gwmInit(void); + #if GWIN_NEED_CONTAINERS + extern void _gcontainerInit(void); - _gwmInit(); + _gcontainerInit(); #endif } void _gwinDeinit(void) { + #if GWIN_NEED_CONTAINERS + extern void _gcontainerDeinit(void); + + _gcontainerDeinit(); + #endif #if GWIN_NEED_WIDGET extern void _gwidgetDeinit(void); @@ -132,6 +146,18 @@ GHandle _gwindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit pgw->font = defaultFont; #endif + #if GWIN_NEED_CONTAINERS + if (pInit->parent) { + if (!(pInit->parent->flags & GWIN_FLG_CONTAINER) || pgw->display != pInit->parent->display) { + if ((pgw->flags & GWIN_FLG_DYNAMIC)) + gfxFree(pgw); + return 0; + } + pgw->parent = pInit->parent; + } else + pgw->parent = 0; + #endif + #if GWIN_NEED_WINDOWMANAGER if (!_GWINwm->vmt->Add(pgw, pInit)) { if ((pgw->flags & GWIN_FLG_DYNAMIC)) @@ -139,7 +165,15 @@ GHandle _gwindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit return 0; } #else - _gwm_redim(pgw, pInit->x, pInit->y, pInit->width, pInit->height); + pgw->x = pgw->y = pgw->width = pgw->height = 0; + _gwm_move(pgw, pInit->x, pInit->y); + _gwm_resize(pgw, pInit->width, pInit->height); + #endif + + #if GWIN_NEED_CONTAINERS + // Notify the parent it has been added + if (pgw->parent && ((gcontainerVMT *)pgw->parent->vmt)->NotifyAdd) + ((gcontainerVMT *)pgw->parent->vmt)->NotifyAdd(pgw->parent, pgw); #endif return (GHandle)pgw; @@ -203,6 +237,12 @@ void gwinDestroy(GHandle gh) { // Make the window invisible gwinSetVisible(gh, FALSE); + #if GWIN_NEED_CONTAINERS + // Notify the parent it is about to be deleted + if (gh->parent && ((gcontainerVMT *)gh->parent->vmt)->NotifyDelete) + ((gcontainerVMT *)gh->parent->vmt)->NotifyDelete(gh->parent, gh); + #endif + // Remove from the window manager #if GWIN_NEED_WINDOWMANAGER _GWINwm->vmt->Delete(gh); @@ -224,48 +264,120 @@ const char *gwinGetClassName(GHandle gh) { return gh->vmt->classname; } -void gwinSetVisible(GHandle gh, bool_t visible) { - if (visible) { - if (!(gh->flags & GWIN_FLG_VISIBLE)) { - gh->flags |= GWIN_FLG_VISIBLE; - _gwm_redraw(gh, 0); +#if GWIN_NEED_CONTAINERS + // These two sub-functions set/clear system visibility recursively. + static bool_t setSysVisFlag(GHandle gh) { + // If we are now visible and our parent is visible + if ((gh->flags & GWIN_FLG_VISIBLE) && (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSVISIBLE))) { + gh->flags |= GWIN_FLG_SYSVISIBLE; + return TRUE; } - } else { - if ((gh->flags & GWIN_FLG_VISIBLE)) { - gh->flags &= ~GWIN_FLG_VISIBLE; - _gwm_redraw(gh, 0); + return FALSE; + } + static bool_t clrSysVisFlag(GHandle gh) { + // If we are now not visible but our parent is visible + if (!(gh->flags & GWIN_FLG_VISIBLE) || (gh->parent && !(gh->parent->flags & GWIN_FLG_SYSVISIBLE))) { + gh->flags &= ~GWIN_FLG_SYSVISIBLE; + return TRUE; } + return FALSE; } -} + void gwinSetVisible(GHandle gh, bool_t visible) { + if (visible) { + if (!(gh->flags & GWIN_FLG_VISIBLE)) { + gh->flags |= GWIN_FLG_VISIBLE; + _gwinRecurse(gh, setSysVisFlag); + _gwm_redraw(gh, 0); + } + } else { + if ((gh->flags & GWIN_FLG_VISIBLE)) { + gh->flags &= ~GWIN_FLG_VISIBLE; + _gwinRecurse(gh, clrSysVisFlag); + _gwm_redraw(gh, 0); + } + } + } +#else + void gwinSetVisible(GHandle gh, bool_t visible) { + if (visible) { + if (!(gh->flags & GWIN_FLG_VISIBLE)) { + gh->flags |= (GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE); + _gwm_redraw(gh, 0); + } + } else { + if ((gh->flags & GWIN_FLG_VISIBLE)) { + gh->flags &= ~(GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE); + _gwm_redraw(gh, 0); + } + } + } +#endif bool_t gwinGetVisible(GHandle gh) { - return (gh->flags & GWIN_FLG_VISIBLE) ? TRUE : FALSE; + return (gh->flags & GWIN_FLG_SYSVISIBLE) ? TRUE : FALSE; } -void gwinSetEnabled(GHandle gh, bool_t enabled) { - if (enabled) { - if (!(gh->flags & GWIN_FLG_ENABLED)) { - gh->flags |= GWIN_FLG_ENABLED; - _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); +#if GWIN_NEED_CONTAINERS + // These two sub-functions set/clear system enable recursively. + static bool_t setSysEnaFlag(GHandle gh) { + // If we are now enabled and our parent is enabled + if ((gh->flags & GWIN_FLG_ENABLED) && (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSENABLED))) { + gh->flags |= GWIN_FLG_SYSENABLED; + return TRUE; } - } else { - if ((gh->flags & GWIN_FLG_ENABLED)) { - gh->flags &= ~GWIN_FLG_ENABLED; - _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); + return FALSE; + } + static bool_t clrSysEnaFlag(GHandle gh) { + // If we are now not enabled but our parent is enabled + if (!(gh->flags & GWIN_FLG_ENABLED) || (gh->parent && !(gh->parent->flags & GWIN_FLG_SYSENABLED))) { + gh->flags &= ~GWIN_FLG_SYSENABLED; + return TRUE; } + return FALSE; } -} + void gwinSetEnabled(GHandle gh, bool_t enabled) { + if (enabled) { + if (!(gh->flags & GWIN_FLG_ENABLED)) { + gh->flags |= GWIN_FLG_ENABLED; + _gwinRecurse(gh, setSysEnaFlag); + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) + _gwm_redraw(gh, GWIN_WMFLG_PRESERVE); + } + } else { + if ((gh->flags & GWIN_FLG_ENABLED)) { + gh->flags &= ~GWIN_FLG_ENABLED; + _gwinRecurse(gh, clrSysEnaFlag); + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) + _gwm_redraw(gh, GWIN_WMFLG_PRESERVE); + } + } + } +#else + void gwinSetEnabled(GHandle gh, bool_t enabled) { + if (enabled) { + if (!(gh->flags & GWIN_FLG_ENABLED)) { + gh->flags |= (GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED); + _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); + } + } else { + if ((gh->flags & GWIN_FLG_ENABLED)) { + gh->flags &= ~(GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED); + _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); + } + } + } +#endif bool_t gwinGetEnabled(GHandle gh) { - return (gh->flags & GWIN_FLG_ENABLED) ? TRUE : FALSE; + return (gh->flags & GWIN_FLG_SYSENABLED) ? TRUE : FALSE; } void gwinMove(GHandle gh, coord_t x, coord_t y) { - _gwm_redim(gh, x, y, gh->width, gh->height); + _gwm_move(gh, x, y); } void gwinResize(GHandle gh, coord_t width, coord_t height) { - _gwm_redim(gh, gh->x, gh->y, width, height); + _gwm_resize(gh, width, height); } void gwinRedraw(GHandle gh) { @@ -284,23 +396,28 @@ void gwinClear(GHandle gh) { * still call the AfterClear() routine as some widgets will * need this to clear internal buffers or similar */ - if (!((gh->flags & GWIN_FLG_VISIBLE))) { + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) { if (gh->vmt->AfterClear) gh->vmt->AfterClear(gh); } else { - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + #if GDISP_NEED_CLIP + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + #endif - gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor); - if (gh->vmt->AfterClear) - gh->vmt->AfterClear(gh); + gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor); + if (gh->vmt->AfterClear) + gh->vmt->AfterClear(gh); } + + #if GWIN_NEED_CONTAINERS + for (gh = gwinGetFirstChild(gh); gh; gh = gwinGetSibling(gh)) + gwinRedraw(gh); + #endif } void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -310,7 +427,7 @@ void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) { } void gwinDrawLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -320,7 +437,7 @@ void gwinDrawLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1) { } void gwinDrawBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -330,7 +447,7 @@ void gwinDrawBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) { } void gwinFillArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -340,7 +457,7 @@ void gwinFillArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) { } void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -351,7 +468,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor #if GDISP_NEED_CIRCLE void gwinDrawCircle(GHandle gh, coord_t x, coord_t y, coord_t radius) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -361,7 +478,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinFillCircle(GHandle gh, coord_t x, coord_t y, coord_t radius) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -373,7 +490,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor #if GDISP_NEED_ELLIPSE void gwinDrawEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -383,7 +500,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinFillEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -395,7 +512,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor #if GDISP_NEED_ARC void gwinDrawArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -405,7 +522,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinFillArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -417,7 +534,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor #if GDISP_NEED_PIXELREAD color_t gwinGetPixelColor(GHandle gh, coord_t x, coord_t y) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return defaultBgColor; #if GDISP_NEED_CLIP @@ -429,7 +546,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor #if GDISP_NEED_TEXT void gwinDrawChar(GHandle gh, coord_t x, coord_t y, char c) { - if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) return; #if GDISP_NEED_CLIP @@ -439,7 +556,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinFillChar(GHandle gh, coord_t x, coord_t y, char c) { - if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) return; #if GDISP_NEED_CLIP @@ -449,7 +566,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinDrawString(GHandle gh, coord_t x, coord_t y, const char *str) { - if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) return; #if GDISP_NEED_CLIP @@ -459,7 +576,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinFillString(GHandle gh, coord_t x, coord_t y, const char *str) { - if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) return; #if GDISP_NEED_CLIP @@ -469,7 +586,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinDrawStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify) { - if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) return; #if GDISP_NEED_CLIP @@ -479,7 +596,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinFillStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify) { - if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) return; #if GDISP_NEED_CLIP @@ -491,7 +608,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor #if GDISP_NEED_CONVEX_POLYGON void gwinDrawPoly(GHandle gh, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -501,7 +618,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinFillConvexPoly(GHandle gh, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -513,7 +630,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor #if GDISP_NEED_IMAGE gdispImageError gwinDrawImage(GHandle gh, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return GDISP_IMAGE_ERR_OK; #if GDISP_NEED_CLIP diff --git a/src/gwin/gwm.c b/src/gwin/gwm.c index 3140b03f..1c96d1c9 100644 --- a/src/gwin/gwm.c +++ b/src/gwin/gwm.c @@ -28,7 +28,8 @@ static void WM_DeInit(void); static bool_t WM_Add(GHandle gh, const GWindowInit *pInit); static void WM_Delete(GHandle gh); static void WM_Redraw(GHandle gh, int flags); -static void WM_Redim(GHandle gh, coord_t x, coord_t y, coord_t w, coord_t h); +static void WM_Size(GHandle gh, coord_t w, coord_t h); +static void WM_Move(GHandle gh, coord_t x, coord_t y); static void WM_Raise(GHandle gh); static void WM_MinMax(GHandle gh, GWindowMinMax minmax); @@ -38,7 +39,8 @@ static const gwmVMT GNullWindowManagerVMT = { WM_Add, WM_Delete, WM_Redraw, - WM_Redim, + WM_Size, + WM_Move, WM_Raise, WM_MinMax, }; @@ -47,7 +49,7 @@ static const GWindowManager GNullWindowManager = { &GNullWindowManagerVMT, }; -gfxQueueASync _GWINList; +static gfxQueueASync _GWINList; GWindowManager * _GWINwm; #if GFX_USE_GTIMER static GTimer RedrawTimer; @@ -114,11 +116,9 @@ void gwinRedrawDisplay(GDisplay *g, bool_t preserve) { (void) param; #endif - const gfxQueueASyncItem * qi; GHandle gh; - for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { - gh = QItem2GWindow(qi); + for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { if (!g || gh->display == g) _GWINwm->vmt->Redraw(gh, preserve ? (GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR|GWIN_WMFLG_NOZORDER) @@ -150,8 +150,11 @@ static bool_t WM_Add(GHandle gh, const GWindowInit *pInit) { // Put it on the end of the queue gfxQueueASyncPut(&_GWINList, &gh->wmq); - // Make sure the size is valid - WM_Redim(gh, pInit->x, pInit->y, pInit->width, pInit->height); + // Make sure the size/position is valid - prefer position over size. + gh->width = MIN_WIN_WIDTH; gh->height = MIN_WIN_HEIGHT; + gh->x = gh->y = 0; + WM_Move(gh, pInit->x, pInit->y); + WM_Size(gh, pInit->width, pInit->height); return TRUE; } @@ -161,15 +164,20 @@ static void WM_Delete(GHandle gh) { } static void WM_Redraw(GHandle gh, int flags) { - if ((gh->flags & GWIN_FLG_VISIBLE)) { + #if GWIN_NEED_CONTAINERS + redo_redraw: + #endif + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { if (gh->vmt->Redraw) { #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + if (!(flags & GWIN_WMFLG_KEEPCLIP)) + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif gh->vmt->Redraw(gh); } else if (!(flags & GWIN_WMFLG_PRESERVE)) { #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + if (!(flags & GWIN_WMFLG_KEEPCLIP)) + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor); if (gh->vmt->AfterClear) @@ -184,42 +192,101 @@ static void WM_Redraw(GHandle gh, int flags) { } else if (!(flags & GWIN_WMFLG_NOBGCLEAR)) { #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + if (!(flags & GWIN_WMFLG_KEEPCLIP)) + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + #endif + #if GWIN_NEED_CONTAINERS + if (gh->parent) { + // Get the parent to redraw the area + gh = gh->parent; + flags |= GWIN_WMFLG_KEEPCLIP; + goto redo_redraw; + } #endif gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); } } -static void WM_Redim(GHandle gh, coord_t x, coord_t y, coord_t w, coord_t h) { - // This is the simplest way of doing it - just clip the the screen - // If it won't fit on the screen move it around until it does. - if (x < 0) { w += x; x = 0; } - if (y < 0) { h += y; y = 0; } - if (x > gdispGGetWidth(gh->display)-MIN_WIN_WIDTH) x = gdispGGetWidth(gh->display)-MIN_WIN_WIDTH; - if (y > gdispGGetHeight(gh->display)-MIN_WIN_HEIGHT) y = gdispGGetHeight(gh->display)-MIN_WIN_HEIGHT; - if (w < MIN_WIN_WIDTH) { w = MIN_WIN_WIDTH; } - if (h < MIN_WIN_HEIGHT) { h = MIN_WIN_HEIGHT; } - if (x+w > gdispGGetWidth(gh->display)) w = gdispGGetWidth(gh->display) - x; - if (y+h > gdispGGetHeight(gh->display)) h = gdispGGetHeight(gh->display) - y; +static void WM_Size(GHandle gh, coord_t w, coord_t h) { + coord_t v; + + #if GWIN_NEED_CONTAINERS + if (gh->parent) { + // Clip to the container + v = gh->parent->x + gh->parent->width - ((const gcontainerVMT *)gh->parent->vmt)->RightBorder(gh->parent); + if (gh->x+w > v) w = v - gh->x; + v = gh->parent->y + gh->parent->height - ((const gcontainerVMT *)gh->parent->vmt)->BottomBorder(gh->parent); + if (gh->y+h > v) h = v - gh->y; + } + #endif + + // Clip to the screen + v = gdispGGetWidth(gh->display); + if (gh->x+w > v) w = v - gh->x; + v = gdispGGetHeight(gh->display); + if (gh->y+h > v) h = v - gh->y; + + // Give it a minimum size + if (w < MIN_WIN_WIDTH) w = MIN_WIN_WIDTH; + if (h < MIN_WIN_HEIGHT) h = MIN_WIN_HEIGHT; // If there has been no resize just exit - if (gh->x == x && gh->y == y && gh->width == w && gh->height == h) + if (gh->width == w && gh->height == h) return; - // Clear the old area - if ((gh->flags & GWIN_FLG_VISIBLE)) { - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif - gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); + // Clear the old area and then redraw + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { + gh->flags &= ~GWIN_FLG_SYSVISIBLE; + WM_Redraw(gh, 0); + gh->width = w; gh->height = h; + gh->flags |= GWIN_FLG_SYSVISIBLE; + WM_Redraw(gh, 0); + } else { + gh->width = w; gh->height = h; } +} + +static void WM_Move(GHandle gh, coord_t x, coord_t y) { + coord_t v; + + #if GWIN_NEED_CONTAINERS + if (gh->parent) { + // Clip to the parent size + v = gh->parent->width - ((const gcontainerVMT *)gh->parent->vmt)->LeftBorder(gh->parent) - ((const gcontainerVMT *)gh->parent->vmt)->RightBorder(gh->parent); + if (x+gh->width > v) x = v-gh->width; + v = gh->parent->height - ((const gcontainerVMT *)gh->parent->vmt)->TopBorder(gh->parent) - ((const gcontainerVMT *)gh->parent->vmt)->BottomBorder(gh->parent); + if (y+gh->height > v) y = v-gh->height; + if (x < 0) x = 0; + if (y < 0) y = 0; + + // Convert to absolute position + x += gh->parent->x + ((const gcontainerVMT *)gh->parent->vmt)->LeftBorder(gh->parent); + y += gh->parent->y + ((const gcontainerVMT *)gh->parent->vmt)->TopBorder(gh->parent); + } + #endif - // Set the new size - gh->x = x; gh->y = y; - gh->width = w; gh->height = h; + // Clip to the screen + v = gdispGGetWidth(gh->display); + if (x+gh->width > v) x = v-gh->width; + v = gdispGGetHeight(gh->display); + if (y+gh->height > v) y = v-gh->height; + if (x < 0) x = 0; + if (y < 0) y = 0; - // Redraw the window (if possible) - WM_Redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); + // If there has been no move just exit + if (gh->x == x && gh->y == y) + return; + + // Clear the old area and then redraw + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { + gh->flags &= ~GWIN_FLG_SYSVISIBLE; + WM_Redraw(gh, 0); + gh->x = x; gh->y = y; + gh->flags |= GWIN_FLG_SYSVISIBLE; + WM_Redraw(gh, 0); + } else { + gh->x = x; gh->y = y; + } } static void WM_MinMax(GHandle gh, GWindowMinMax minmax) { @@ -230,6 +297,7 @@ static void WM_MinMax(GHandle gh, GWindowMinMax minmax) { static void WM_Raise(GHandle gh) { // Take it off the list and then put it back on top // The order of the list then reflects the z-order. + gfxQueueASyncRemove(&_GWINList, &gh->wmq); gfxQueueASyncPut(&_GWINList, &gh->wmq); @@ -237,5 +305,9 @@ static void WM_Raise(GHandle gh) { WM_Redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); } +GHandle gwinGetNextWindow(GHandle gh) { + return gh ? (GHandle)gfxQueueASyncNext(&gh->wmq) : (GHandle)gfxQueueASyncPeek(&_GWINList); +} + #endif /* GFX_USE_GWIN && GWIN_NEED_WINDOWMANAGER */ /** @} */ diff --git a/src/gwin/label.c b/src/gwin/label.c index 2aa0c860..ffb9fa3d 100644 --- a/src/gwin/label.c +++ b/src/gwin/label.c @@ -147,7 +147,7 @@ static void gwinLabelDefaultDraw(GWidgetObject *gw, void *param) { w = (gw->g.flags & GLABEL_FLG_WAUTO) ? getwidth(gw->text, gw->g.font, gdispGGetWidth(gw->g.display) - gw->g.x) : gw->g.width; h = (gw->g.flags & GLABEL_FLG_HAUTO) ? getheight(gw->text, gw->g.font, gdispGGetWidth(gw->g.display) - gw->g.x) : gw->g.height; - c = (gw->g.flags & GWIN_FLG_ENABLED) ? gw->pstyle->enabled.text : gw->pstyle->disabled.text; + c = (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.text : gw->pstyle->disabled.text; if (gw->g.width != w || gw->g.height != h) { gwinResize(&gw->g, w, h); @@ -167,7 +167,7 @@ static void gwinLabelDefaultDraw(GWidgetObject *gw, void *param) { // render the border (if any) if (gw->g.flags & GLABEL_FLG_BORDER) - gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, w, h, (gw->g.flags & GWIN_FLG_ENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge); + gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, w, h, (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge); } #endif // GFX_USE_GWIN && GFX_NEED_LABEL diff --git a/src/gwin/list.c b/src/gwin/list.c index 788e8828..a960e3ed 100644 --- a/src/gwin/list.c +++ b/src/gwin/list.c @@ -107,7 +107,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); } } - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); sendListEvent(gw, item); } @@ -136,14 +136,14 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); gw2obj->top -= iheight; if (gw2obj->top < 0) gw2obj->top = 0; - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); } } else if (y >= gw->g.height - 2*ARROW) { if (gw2obj->top < gw2obj->cnt * iheight - pgsz) { gw2obj->top += iheight; if (gw2obj->top > gw2obj->cnt * iheight - pgsz) gw2obj->top = gw2obj->cnt * iheight - pgsz; - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); } } else if (y < gw->g.height/2) { if (gw2obj->top > 0) { @@ -151,7 +151,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); gw2obj->top -= pgsz; else gw2obj->top = 0; - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); } } else { if (gw2obj->top < gw2obj->cnt * iheight - pgsz) { @@ -159,7 +159,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); gw2obj->top += pgsz; else gw2obj->top = gw2obj->cnt * iheight - pgsz; - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); } } return; @@ -197,7 +197,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); gw2obj->top = 0; gw2obj->last_mouse_y = y; if (oldtop != gw2obj->top) - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); } } #endif @@ -218,7 +218,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); if (qix) { qi2li->flags &=~ GLIST_FLG_SELECTED; qix2li->flags |= GLIST_FLG_SELECTED; - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); } break; } @@ -235,7 +235,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); if (qix) { qi2li->flags &=~ GLIST_FLG_SELECTED; qix2li->flags |= GLIST_FLG_SELECTED; - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); } break; } @@ -388,7 +388,7 @@ int gwinListAddItem(GHandle gh, const char* item_name, bool_t useAlloc) { // increment the total amount of entries in the list widget gh2obj->cnt++; - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); // return the position in the list (-1 because we start with index 0) return gh2obj->cnt-1; @@ -486,7 +486,7 @@ void gwinListDeleteAll(GHandle gh) { gh->flags &= ~GLIST_FLG_HASIMAGES; gh2obj->cnt = 0; gh2obj->top = 0; - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); } void gwinListItemDelete(GHandle gh, int item) { @@ -507,7 +507,7 @@ void gwinListItemDelete(GHandle gh, int item) { gfxFree((void *)qi); if (gh2obj->top >= item && gh2obj->top) gh2obj->top--; - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); break; } } @@ -620,7 +620,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) { if (!(gw->g.flags & GLIST_FLG_ENABLERENDER)) return; - ps = (gw->g.flags & GWIN_FLG_ENABLED) ? &gw->pstyle->enabled : &gw->pstyle->disabled; + ps = (gw->g.flags & GWIN_FLG_SYSENABLED) ? &gw->pstyle->enabled : &gw->pstyle->disabled; iheight = gdispGetFontMetric(gw->g.font, fontHeight) + VERTICAL_PADDING; x = 1; @@ -643,7 +643,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) { gdispGFillConvexPoly(gw->g.display, gw->g.x+iwidth+((SCROLLWIDTH-ARROW)/2+2), gw->g.y+(ARROW/2+1), upArrow, 3, ps->fill); gdispGFillConvexPoly(gw->g.display, gw->g.x+iwidth+((SCROLLWIDTH-ARROW)/2+2), gw->g.y+gw->g.height-(ARROW+ARROW/2+1), downArrow, 3, ps->fill); #else - #warning "GWIN: Lists display better when GDISP_NEED_CONVEX_POLGON is turned on" + #warning "GWIN: Lists display better when GDISP_NEED_CONVEX_POLYGON is turned on" gdispGFillArea(gw->g.display, gw->g.x+iwidth+((SCROLLWIDTH-ARROW)/2+2), gw->g.y+(ARROW/2+1), ARROW, ARROW, ps->fill); gdispGFillArea(gw->g.display, gw->g.x+iwidth+((SCROLLWIDTH-ARROW)/2+2), gw->g.y+gw->g.height-(ARROW+ARROW/2+1), ARROW, ARROW, ps->fill); #endif @@ -677,7 +677,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) { if (qi2li->pimg && gdispImageIsOpen(qi2li->pimg)) { // Calculate which image sy = (qi2li->flags & GLIST_FLG_SELECTED) ? 0 : (iheight-VERTICAL_PADDING); - if (!(gw->g.flags & GWIN_FLG_ENABLED)) + if (!(gw->g.flags & GWIN_FLG_SYSENABLED)) sy += 2*(iheight-VERTICAL_PADDING); while (sy > qi2li->pimg->height) sy -= iheight-VERTICAL_PADDING; diff --git a/src/gwin/progressbar.c b/src/gwin/progressbar.c index 524a5346..ca267f0c 100644 --- a/src/gwin/progressbar.c +++ b/src/gwin/progressbar.c @@ -128,7 +128,7 @@ void gwinProgressbarSetPosition(GHandle gh, int pos) { } ResetDisplayPos(gsw); - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); #undef gsw } @@ -159,7 +159,7 @@ void gwinProgressbarIncrement(GHandle gh) { gsw->pos = gsw->max; ResetDisplayPos(gsw); - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); #undef gsw } @@ -178,7 +178,7 @@ void gwinProgressbarDecrement(GHandle gh) { gsw->pos -= gsw->res; ResetDisplayPos(gsw); - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); #undef gsw } @@ -239,7 +239,7 @@ void gwinProgressbarDraw_Std(GWidgetObject *gw, void *param) { return; // get the colors right - if ((gw->g.flags & GWIN_FLG_ENABLED)) + if ((gw->g.flags & GWIN_FLG_SYSENABLED)) pcol = &gw->pstyle->pressed; else pcol = &gw->pstyle->disabled; @@ -277,7 +277,7 @@ void gwinProgressbarDraw_Image(GWidgetObject *gw, void *param) { if (gw->g.vmt != (gwinVMT *)&progressbarVMT) return; - if ((gw->g.flags & GWIN_FLG_ENABLED)) + if ((gw->g.flags & GWIN_FLG_SYSENABLED)) pcol = &gw->pstyle->pressed; else pcol = &gw->pstyle->disabled; diff --git a/src/gwin/radio.c b/src/gwin/radio.c index 0ae5546a..da6aa5ea 100644 --- a/src/gwin/radio.c +++ b/src/gwin/radio.c @@ -133,10 +133,10 @@ void gwinRadioPress(GHandle gh) { if ((gx = gwinRadioGetActive(((GRadioObject *)gh)->group))) { gx->flags &= ~GRADIO_FLG_PRESSED; - _gwidgetRedraw(gx); + _gwidgetUpdate(gx); } gh->flags |= GRADIO_FLG_PRESSED; - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); SendRadioEvent((GWidgetObject *)gh); } @@ -148,11 +148,9 @@ bool_t gwinRadioIsPressed(GHandle gh) { } GHandle gwinRadioGetActive(uint16_t group) { - const gfxQueueASyncItem * qi; - GHandle gh; + GHandle gh; - for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { - gh = QItem2GWindow(qi); + for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { if (gh->vmt == (gwinVMT *)&radioVMT && ((GRadioObject *)gh)->group == group && (gh->flags & GRADIO_FLG_PRESSED)) return gh; } @@ -164,7 +162,7 @@ GHandle gwinRadioGetActive(uint16_t group) { *----------------------------------------------------------*/ static const GColorSet *getDrawColors(GWidgetObject *gw) { - if (!(gw->g.flags & GWIN_FLG_ENABLED)) return &gw->pstyle->disabled; + if (!(gw->g.flags & GWIN_FLG_SYSENABLED)) return &gw->pstyle->disabled; if ((gw->g.flags & GRADIO_FLG_PRESSED)) return &gw->pstyle->pressed; return &gw->pstyle->enabled; } diff --git a/src/gwin/slider.c b/src/gwin/slider.c index 4c91ede6..3266e20a 100644 --- a/src/gwin/slider.c +++ b/src/gwin/slider.c @@ -74,7 +74,7 @@ static void ResetDisplayPos(GSliderObject *gsw) { if (x < 0 || x >= gh->width || y < 0 || y >= gh->height) { // No - restore the slider ResetDisplayPos(gsw); - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); return; } #endif @@ -97,7 +97,7 @@ static void ResetDisplayPos(GSliderObject *gsw) { } ResetDisplayPos(gsw); - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); // Generate the event SendSliderEvent(gw); @@ -127,7 +127,7 @@ static void ResetDisplayPos(GSliderObject *gsw) { } // Update the display - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); #undef gsw } #endif @@ -169,7 +169,7 @@ static void ResetDisplayPos(GSliderObject *gsw) { gsw->pos = (uint16_t)((uint32_t)value*(gsw->max-gsw->min)/max + gsw->min); ResetDisplayPos(gsw); - _gwidgetRedraw((GHandle)gw); + _gwidgetUpdate((GHandle)gw); // Generate the event SendSliderEvent(gw); @@ -272,7 +272,7 @@ void gwinSliderSetPosition(GHandle gh, int pos) { else gsw->pos = pos; } ResetDisplayPos(gsw); - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); #undef gsw } @@ -289,7 +289,7 @@ void gwinSliderDraw_Std(GWidgetObject *gw, void *param) { if (gw->g.vmt != (gwinVMT *)&sliderVMT) return; - if ((gw->g.flags & GWIN_FLG_ENABLED)) + if ((gw->g.flags & GWIN_FLG_SYSENABLED)) pcol = &gw->pstyle->pressed; else pcol = &gw->pstyle->disabled; @@ -334,7 +334,7 @@ void gwinSliderDraw_Image(GWidgetObject *gw, void *param) { if (gw->g.vmt != (gwinVMT *)&sliderVMT) return; - if ((gw->g.flags & GWIN_FLG_ENABLED)) + if ((gw->g.flags & GWIN_FLG_SYSENABLED)) pcol = &gw->pstyle->pressed; else pcol = &gw->pstyle->disabled; diff --git a/src/gwin/sys_defs.h b/src/gwin/sys_defs.h index c632b069..426b2c02 100644 --- a/src/gwin/sys_defs.h +++ b/src/gwin/sys_defs.h @@ -27,6 +27,9 @@ #if GFX_USE_GWIN || defined(__DOXYGEN__) +/* Forward declaration */ +typedef struct GWindowObject *GHandle; + /** * @brief A window object structure * @note Do not access the members directly. Treat it as a black-box and use the method functions. @@ -46,6 +49,9 @@ typedef struct GWindowObject { #if GDISP_NEED_TEXT font_t font; // @< The current font #endif + #if GWIN_NEED_CONTAINERS + GHandle parent; // @< The parent window + #endif } GWindowObject, * GHandle; /* @} */ @@ -62,9 +68,12 @@ typedef struct GWindowObject { * @{ */ typedef struct GWindowInit { - coord_t x, y; // @< The initial screen position + coord_t x, y; // @< The initial position relative to its parent coord_t width, height; // @< The initial dimension bool_t show; // @< Should the window be visible initially + #if GWIN_NEED_CONTAINERS + GHandle parent; // @< The parent - must be a container or NULL + #endif } GWindowInit; /* @} */ @@ -324,15 +333,39 @@ extern "C" { * as not visible, nothing is done to remove the window from the screen. * When there is a window manager, it is up to the window manager to * handle what happens. + * @note Even when you mark a window as visible, it may still not be displayed + * if it's parent is invisible. When the parent becomes visible this child + * will automatically be shown because it is already marked as visible. * * @api */ void gwinSetVisible(GHandle gh, bool_t visible); /** + * @brief Makes a widget become visible + * + * @param[in] gh The window handle + * + * @api + */ + #define gwinShow(gh) gwinSetVisible(gh, TRUE); + + /** + * @brief Makes a widget become invisible + * + * @param[in] gh The window handle + * + * @api + */ + #define gwinHide(gh) gwinSetVisible(gh, FALSE); + + /** * @brief Gets the visibility of a window * @return TRUE if visible * + * @note It is possible for a child to be marked as visible by @p gwinSetVisible() + * but for this call to return FALSE if one of its parents are not visible. + * * @param[in] gh The window * * @api @@ -345,8 +378,10 @@ extern "C" { * @param[in] gh The window handle * @param[in] enabled Enable or disable the window * - * @note The window is automatically redrawn if it - * supports self-redrawing. + * @note The window is automatically redrawn if it supports self-redrawing. + * @note Even when you mark a window as enabled, it may still remain disabled + * if it's parent is disabled. When the parent becomes enabled this child + * will automatically be enabled because it is already marked as enabled. * * @api */ @@ -374,6 +409,9 @@ extern "C" { * @brief Gets the enabled state of a window * @return TRUE if enabled * + * @note It is possible for a child to be marked as enabled by @p gwinSetEnabled() + * but for this call to return FALSE if one of its parents are not enabled. + * * @param[in] gh The window * * @api @@ -491,6 +529,24 @@ extern "C" { * @api */ void gwinRaise(GHandle gh); + + /** + * @brief Get the next window in the z-order + * @return The next window or NULL if no more windows + * + * @param[in] gh The previous window or NULL to get the first window + * + * @note This returns the next window in the system from top to bottom. + * @note Where there are parent child relationships, this ignores them + * and will list all windows in the system. There is no defined + * order between children of siblings and they can in fact be mixed + * in order. The only relationship honored is that parents will be + * listed before their children. + * + * @api + */ + GHandle gwinGetNextWindow(GHandle gh); + #endif #if GDISP_NEED_TEXT || defined(__DOXYGEN__) @@ -880,7 +936,12 @@ extern "C" { #include "src/gwin/gwidget.h" #endif - /* Include extra window types */ + /* Include containers */ + #if GWIN_NEED_CONTAINERS || defined(__DOXYGEN__) + #include "src/gwin/gcontainer.h" + #endif + + /* Include vanilla window objects */ #if GWIN_NEED_CONSOLE || defined(__DOXYGEN__) #include "src/gwin/console.h" #endif diff --git a/src/gwin/sys_make.mk b/src/gwin/sys_make.mk index 4c670ea2..95a2ba84 100644 --- a/src/gwin/sys_make.mk +++ b/src/gwin/sys_make.mk @@ -11,4 +11,6 @@ GFXSRC += $(GFXLIB)/src/gwin/gwin.c \ $(GFXLIB)/src/gwin/radio.c \ $(GFXLIB)/src/gwin/list.c \ $(GFXLIB)/src/gwin/progressbar.c \ + $(GFXLIB)/src/gwin/gcontainer.c \ + $(GFXLIB)/src/gwin/frame.c \ diff --git a/src/gwin/sys_options.h b/src/gwin/sys_options.h index 41bc551f..39630de0 100644 --- a/src/gwin/sys_options.h +++ b/src/gwin/sys_options.h @@ -30,6 +30,13 @@ #define GWIN_NEED_WIDGET FALSE #endif /** + * @brief Should the widget hierarchy be included. This provides parent-child features. + * @details Defaults to FALSE + */ + #ifndef GWIN_NEED_CONTAINERS + #define GWIN_NEED_CONTAINERS FALSE + #endif + /** * @brief Should widget functions be included. Needed for any widget (eg Buttons, Sliders etc) * @details Defaults to FALSE */ @@ -37,6 +44,20 @@ #define GWIN_NEED_WIDGET FALSE #endif /** + * @brief Should the simple container be included. + * @details Defaults to FALSE + */ + #ifndef GWIN_NEED_CONTAINER + #define GWIN_NEED_CONTAINER FALSE + #endif + /** + * @brief Should the frame widget be included. + * @details Defaults to FALSE + */ + #ifndef GWIN_NEED_FRAME + #define GWIN_NEED_FRAME FALSE + #endif + /** * @brief Should console functions be included. * @details Defaults to FALSE */ diff --git a/src/gwin/sys_rules.h b/src/gwin/sys_rules.h index f9f00a48..ddfea3aa 100644 --- a/src/gwin/sys_rules.h +++ b/src/gwin/sys_rules.h @@ -28,6 +28,15 @@ #endif // Objects require their super-class + #if GWIN_NEED_FRAME || GWIN_NEED_CONTAINER + #if !GWIN_NEED_CONTAINERS + #if GFX_DISPLAY_RULE_WARNINGS + #warning "GWIN: GWIN_NEED_CONTAINERS is required when a container is enabled. It has been turned on for you." + #endif + #undef GWIN_NEED_CONTAINERS + #define GWIN_NEED_CONTAINERS TRUE + #endif + #endif #if GWIN_NEED_BUTTON || GWIN_NEED_SLIDER || GWIN_NEED_CHECKBOX || GWIN_NEED_LABEL || GWIN_NEED_RADIO || GWIN_NEED_LIST || \ GWIN_NEED_IMAGE || GWIN_NEED_CHECKBOX || GWIN_NEED_PROGRESSBAR #if !GWIN_NEED_WIDGET @@ -40,6 +49,15 @@ #endif // Rules for the super-classes + #if GWIN_NEED_CONTAINERS + #if !GWIN_NEED_WIDGET + #if GFX_DISPLAY_RULE_WARNINGS + #warning "GWIN: GWIN_NEED_WIDGET is required when GWIN_NEED_CONTAINERS is enabled. It has been turned on for you." + #endif + #undef GWIN_NEED_WIDGET + #define GWIN_NEED_WIDGET TRUE + #endif + #endif #if GWIN_NEED_WIDGET #if !GDISP_NEED_TEXT #error "GWIN: GDISP_NEED_TEXT is required if GWIN_NEED_WIDGET is TRUE." diff --git a/tools/file2c/src/file2c.c b/tools/file2c/src/file2c.c index 87ea88e9..079b1a59 100644 --- a/tools/file2c/src/file2c.c +++ b/tools/file2c/src/file2c.c @@ -168,7 +168,7 @@ size_t i; if (opt_inputfile) opt_arrayname = basenameof(strcpy(tname, opt_inputfile)); if (!opt_arrayname || !opt_arrayname[0]) { - srand(time(NULL)); + srand(time(0)); sprintf(tname, "filearray%u", rand()); opt_arrayname = tname; } |