Browse Source
Widgets demo updated to (optionally) use the new tabset.remotes/origin_old/ugfx_release_2.6
9 changed files with 991 additions and 134 deletions
@ -0,0 +1,562 @@ |
|||
/*
|
|||
* 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/gwin_frame.c |
|||
* @brief GWIN sub-system frame code. |
|||
*/ |
|||
|
|||
#include "gfx.h" |
|||
|
|||
#if GFX_USE_GWIN && GWIN_NEED_TABSET |
|||
|
|||
#include "gwin_class.h" |
|||
|
|||
// Some position values
|
|||
#define BORDER_WIDTH 2 |
|||
#define TEXT_PADDING 5 |
|||
|
|||
// Some color blending
|
|||
#define GTABSET_TAB_CNR 8 // Diagonal corner on active tab
|
|||
#define GTABSET_TOP_FADE 50 // (GTABSET_TOP_FADE/255)% fade to white for top of tab/button
|
|||
#define GTABSET_BOTTOM_FADE 25 // (GTABSET_BOTTOM_FADE/255)% fade to black for bottom of tab/button
|
|||
#define GTABSET_OUTLINE_FADE 128 // (GTABSET_OUTLINE_FADE/255)% fade to background for active tab edge
|
|||
|
|||
/* Internal state flags */ |
|||
#define GWIN_TABSET_USER_FLAGS (GWIN_TABSET_BORDER) |
|||
#if GWIN_TABSET_BORDER < GWIN_FIRST_CONTROL_FLAG |
|||
#error "GWIN Tabset: - Flag definitions don't match" |
|||
#endif |
|||
#if GWIN_TABSET_BORDER > GWIN_LAST_CONTROL_FLAG |
|||
#error "GWIN Tabset: - Flag definitions don't match" |
|||
#endif |
|||
|
|||
/********************************************************************************************************************
|
|||
* Tab-page stuff |
|||
*/ |
|||
|
|||
static void FixTabSizePos(GHandle gh); |
|||
|
|||
typedef GContainerObject GTabpageObject; |
|||
|
|||
static coord_t TabpageBorderSize(GHandle gh) { (void)gh; return 0; } |
|||
|
|||
static void gwinTabpageDraw_Std(GWidgetObject *gw, void *param) { |
|||
(void)gw; |
|||
(void)param; |
|||
|
|||
// The page is effectively transparent
|
|||
} |
|||
|
|||
static void TabpageDestroy(GHandle gh) { |
|||
_gcontainerDestroy(gh); |
|||
|
|||
FixTabSizePos(gh->parent); |
|||
} |
|||
|
|||
static const gcontainerVMT tabpageVMT = { |
|||
{ |
|||
{ |
|||
"Tabpage", // The classname
|
|||
sizeof(GTabpageObject), // The object size
|
|||
TabpageDestroy, // The destroy routine
|
|||
_gcontainerRedraw, // The redraw routine
|
|||
0, // The after-clear routine
|
|||
}, |
|||
gwinTabpageDraw_Std, // The default drawing routine
|
|||
#if GINPUT_NEED_MOUSE |
|||
{ |
|||
0, // Process mouse down event
|
|||
0, // Process mouse up events
|
|||
0, // 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 |
|||
}, |
|||
TabpageBorderSize, // The size of the left border (mandatory)
|
|||
TabpageBorderSize, // The size of the top border (mandatory)
|
|||
TabpageBorderSize, // The size of the right border (mandatory)
|
|||
TabpageBorderSize, // The size of the bottom border (mandatory)
|
|||
0, // A child has been added (optional)
|
|||
0, // A child has been deleted (optional)
|
|||
}; |
|||
|
|||
void gwinTabsetSetTitle(GHandle gh, const char *title, bool_t useAlloc) { |
|||
if (gh->vmt != (gwinVMT *)&tabpageVMT) |
|||
return; |
|||
|
|||
gwinSetText(gh, title, useAlloc); |
|||
FixTabSizePos(gh->parent); |
|||
gwinRedraw(gh->parent); |
|||
} |
|||
|
|||
/********************************************************************************************************************
|
|||
* Tab-set stuff |
|||
*/ |
|||
|
|||
static coord_t CalcTabHeight(GHandle gh) { |
|||
GHandle ph; |
|||
coord_t x, y, w; |
|||
|
|||
x = w = 0; |
|||
y = GWIN_TABSET_TABHEIGHT; |
|||
for(ph = gwinGetFirstChild(gh); ph; ph = gwinGetSibling(ph)) { |
|||
if (ph->vmt == (gwinVMT *)&tabpageVMT) { |
|||
w = gdispGetStringWidth(((GWidgetObject *)ph)->text, gh->font) + TEXT_PADDING*2; |
|||
x += w; |
|||
if (x > gh->width) { |
|||
y += GWIN_TABSET_TABHEIGHT; |
|||
x = w; |
|||
} |
|||
} |
|||
} |
|||
return y; |
|||
} |
|||
|
|||
static void FixTabSizePos(GHandle gh) { |
|||
coord_t w, h, oldth; |
|||
GHandle vis, ph; |
|||
|
|||
oldth = ((GTabsetObject *)gh)->border_top; |
|||
((GTabsetObject *)gh)->border_top = CalcTabHeight(gh); |
|||
oldth -= ((GTabsetObject *)gh)->border_top; |
|||
if (oldth == 0) |
|||
return; |
|||
|
|||
vis = 0; |
|||
w = gwinGetInnerWidth(gh); |
|||
h = gwinGetInnerHeight(gh); |
|||
for(ph = gwinGetFirstChild(gh); ph; ph = gwinGetSibling(ph)) { |
|||
if (ph->vmt == (gwinVMT *)&tabpageVMT) { |
|||
if (!vis || (ph->flags & GWIN_FLG_VISIBLE)) |
|||
vis = ph; |
|||
gwinMove(ph, 0, 0); |
|||
gwinResize(ph, w, h); |
|||
} else { |
|||
gwinMove(ph, ph->x-gh->x-((gh->flags & GWIN_TABSET_BORDER) ? BORDER_WIDTH : 0) , ph->y-oldth-gh->y); |
|||
} |
|||
} |
|||
if (vis && !(vis->flags & GWIN_FLG_VISIBLE)) { |
|||
vis->flags |= GWIN_FLG_VISIBLE; |
|||
_gwinRippleVisibility(); |
|||
} |
|||
} |
|||
|
|||
static coord_t TabSetBorderSize(GHandle gh) { return (gh->flags & GWIN_TABSET_BORDER) ? BORDER_WIDTH : 0; } |
|||
static coord_t TabSetBorderTop(GHandle gh) { return ((GTabsetObject *)gh)->border_top; } |
|||
|
|||
#if GINPUT_NEED_MOUSE |
|||
static void mouseDown(GWidgetObject *gw, coord_t mx, coord_t my) { |
|||
GHandle ph, gh; |
|||
int cnt; |
|||
|
|||
if (my < 0 || my > ((GTabsetObject *)gw)->border_top) |
|||
return; |
|||
|
|||
// Work out which tab was pressed
|
|||
{ |
|||
coord_t x, w, y; |
|||
|
|||
cnt = 0; |
|||
x = w = 0; |
|||
y = GWIN_TABSET_TABHEIGHT; |
|||
gh = 0; |
|||
for(ph = gwinGetFirstChild(&gw->g); ph; ph = gwinGetSibling(ph)) { |
|||
if (ph->vmt == (gwinVMT *)&tabpageVMT) { |
|||
w = gdispGetStringWidth(((GWidgetObject *)ph)->text, gw->g.font) + TEXT_PADDING*2; |
|||
x += w; |
|||
if (x > gw->g.width) { |
|||
y += GWIN_TABSET_TABHEIGHT; |
|||
x = w; |
|||
} |
|||
if (my < y && mx < x) { |
|||
gh = ph; |
|||
break; |
|||
} |
|||
cnt++; |
|||
} |
|||
} |
|||
if (!gh || (gh->flags & GWIN_FLG_VISIBLE)) |
|||
return; |
|||
} |
|||
|
|||
// Mark the existing tab as not visible
|
|||
for(ph = gwinGetFirstChild(&gw->g); ph; ph = gwinGetSibling(ph)) { |
|||
if (ph->vmt == (gwinVMT *)&tabpageVMT && (ph->flags & GWIN_FLG_VISIBLE)) { |
|||
// Mark this page invisible
|
|||
ph->flags &= ~GWIN_FLG_VISIBLE; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
// Mark this tab as visible
|
|||
gh->flags |= GWIN_FLG_VISIBLE; |
|||
_gwinRippleVisibility(); |
|||
|
|||
// Force a redraw of the whole tabset
|
|||
_gwinUpdate(&gw->g); |
|||
|
|||
// Send the Tabset Event
|
|||
{ |
|||
GSourceListener * psl; |
|||
GEventGWinTabset * pge; |
|||
|
|||
psl = 0; |
|||
while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) { |
|||
if (!(pge = (GEventGWinTabset *)geventGetEventBuffer(psl))) |
|||
continue; |
|||
pge->type = GEVENT_GWIN_TABSET; |
|||
pge->gwin = &gw->g; |
|||
#if GWIN_WIDGET_TAGS |
|||
pge->tag = gw->tag; |
|||
#endif |
|||
pge->ghPage = gh; |
|||
pge->nPage = cnt; |
|||
geventSendEvent(psl); |
|||
} |
|||
} |
|||
} |
|||
#endif |
|||
|
|||
static const gcontainerVMT tabsetVMT = { |
|||
{ |
|||
{ |
|||
"Tabset", // The classname
|
|||
sizeof(GTabsetObject), // The object size
|
|||
_gcontainerDestroy, // The destroy routine
|
|||
_gcontainerRedraw, // The redraw routine
|
|||
0, // The after-clear routine
|
|||
}, |
|||
gwinTabsetDraw_Std, // The default drawing routine
|
|||
#if GINPUT_NEED_MOUSE |
|||
{ |
|||
mouseDown, // Process mouse down event
|
|||
0, // Process mouse up events
|
|||
0, // 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 |
|||
}, |
|||
TabSetBorderSize, // The size of the left border (mandatory)
|
|||
TabSetBorderTop, // The size of the top border (mandatory)
|
|||
TabSetBorderSize, // The size of the right border (mandatory)
|
|||
TabSetBorderSize, // The size of the bottom border (mandatory)
|
|||
0, // A child has been added (optional)
|
|||
0, // A child has been deleted (optional)
|
|||
}; |
|||
|
|||
GHandle gwinGTabsetCreate(GDisplay *g, GTabsetObject *fo, GWidgetInit *pInit, uint32_t flags) { |
|||
if (!(fo = (GTabsetObject *)_gcontainerCreate(g, (GContainerObject *)fo, pInit, &tabsetVMT))) |
|||
return 0; |
|||
|
|||
// Set Tabset specific stuff
|
|||
fo->c.g.flags |= flags & GWIN_TABSET_USER_FLAGS; |
|||
fo->border_top = GWIN_TABSET_TABHEIGHT; |
|||
|
|||
gwinSetVisible(&fo->c.g, pInit->g.show); |
|||
|
|||
return &fo->c.g; |
|||
} |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|||
// API calls
|
|||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|||
|
|||
GHandle gwinTabsetAddTab(GHandle gh, const char *title, bool_t useAlloc) { |
|||
GWidgetInit wi; |
|||
|
|||
if (gh->vmt != (gwinVMT *)&tabsetVMT) |
|||
return 0; |
|||
|
|||
// Set up the init structure
|
|||
gwinWidgetClearInit(&wi); |
|||
wi.g.x = wi.g.y = 0; |
|||
wi.g.width = gwinGetInnerWidth(gh); |
|||
wi.g.height = gwinGetInnerHeight(gh); |
|||
wi.g.show = !gwinTabsetCountTabs(gh); |
|||
wi.g.parent = gh; |
|||
|
|||
// Create the page
|
|||
if (!(gh = _gcontainerCreate(gh->display, 0, &wi, &tabpageVMT))) |
|||
return 0; |
|||
|
|||
// Set the text and visibility
|
|||
gwinSetText(gh, title, useAlloc); |
|||
FixTabSizePos(gh->parent); |
|||
|
|||
gwinSetVisible(gh, wi.g.show); |
|||
gwinRedraw(gh->parent); |
|||
return gh; |
|||
} |
|||
|
|||
int gwinTabsetCountTabs(GHandle gh) { |
|||
int cnt; |
|||
|
|||
if (gh->vmt != (gwinVMT *)&tabsetVMT) |
|||
return 0; |
|||
|
|||
for(cnt = 0, gh = gwinGetFirstChild(gh); gh; gh = gwinGetSibling(gh)) { |
|||
if (gh->vmt == (gwinVMT *)&tabpageVMT) |
|||
cnt++; |
|||
} |
|||
return cnt; |
|||
} |
|||
|
|||
GHandle gwinTabsetGetTabByIndex(GHandle gh, int index) { |
|||
if (gh->vmt != (gwinVMT *)&tabsetVMT) |
|||
return 0; |
|||
|
|||
for(gh = gwinGetFirstChild(gh); gh; gh = gwinGetSibling(gh)) { |
|||
if (gh->vmt == (gwinVMT *)&tabpageVMT && !index--) |
|||
return gh; |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
GHandle gwinTabsetGetTabByTitle(GHandle gh, const char *title) { |
|||
if (gh->vmt != (gwinVMT *)&tabsetVMT) |
|||
return 0; |
|||
|
|||
for(gh = gwinGetFirstChild(gh); gh; gh = gwinGetSibling(gh)) { |
|||
if (gh->vmt == (gwinVMT *)&tabpageVMT && !strcmp(title, ((GWidgetObject *)gh)->text)) |
|||
return gh; |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
void gwinTabsetSetTab(GHandle gh) { |
|||
GHandle ph; |
|||
|
|||
if (gh->vmt != (gwinVMT *)&tabpageVMT || (gh->flags & GWIN_FLG_VISIBLE)) |
|||
return; |
|||
|
|||
// We alter the visibility flags here directly as we know we are going to redraw everything
|
|||
for(ph = gwinGetFirstChild(gh->parent); ph; ph = gwinGetSibling(ph)) { |
|||
if (ph->vmt == (gwinVMT *)&tabpageVMT && (ph->flags & GWIN_FLG_VISIBLE)) { |
|||
// Mark this page invisible
|
|||
ph->flags &= ~GWIN_FLG_VISIBLE; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
// Mark this tab as visible
|
|||
gh->flags |= GWIN_FLG_VISIBLE; |
|||
_gwinRippleVisibility(); |
|||
|
|||
// Force a redraw of the tabset
|
|||
gwinRedraw(gh->parent); |
|||
} |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|||
// Default render routines //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|||
|
|||
#if GWIN_FLAT_STYLING |
|||
static void fgarea(GWidgetObjset *gw, const char *text, coord_t y, coord_t x, coord_t w) { |
|||
const GColorSet * pcol; |
|||
|
|||
pcol = (gw->g.flags & GWIN_FLG_SYSENABLED) ? &gw->pstyle->pressed : &gw->pstyle->disabled; |
|||
|
|||
gdispGDrawBox(gw->g.display, gw->g.x+x, gw->g.y+y, w, GWIN_TABSET_TABHEIGHT, pcol->edge); |
|||
gdispGFillStringBox(gw->g.display, gw->g.x+x+1, gw->g.y+y+1, w-2, GWIN_TABSET_TABHEIGHT-1, text, gw->g.font, pcol->text, pcol->fill, justifyCenter); |
|||
} |
|||
static void bgarea(GWidgetObjset *gw, const char *text, coord_t y, coord_t x, coord_t w) { |
|||
const GColorSet * pcol; |
|||
|
|||
pcol = (gw->g.flags & GWIN_FLG_SYSENABLED) ? &gw->pstyle->enabled : &gw->pstyle->disabled; |
|||
|
|||
gdispGFillStringBox(gw->g.display, gw->g.x+x, gw->g.y+y, w-1, GWIN_TABSET_TABHEIGHT, text, gw->g.font, pcol->text, pcol->fill, justifyCenter); |
|||
gdispGDrawLine(gw->g.display, gw->g.x+x+w-1, gw->g.y+y, gw->g.x+x+w-1, gw->g.y+y+GWIN_TABSET_TABHEIGHT-1, pcol->edge); |
|||
gdispGDrawLine(gw->g.display, gw->g.x+x, gw->g.y+y+GWIN_TABSET_TABHEIGHT-1, gw->g.x+x+w-2, gw->g.y+y+GWIN_TABSET_TABHEIGHT-1, pcol->edge); |
|||
} |
|||
static void ntarea(GWidgetObjset *gw, coord_t y, coord_t x, coord_t w) { |
|||
const GColorSet * pcol; |
|||
|
|||
pcol = (gw->g.flags & GWIN_FLG_SYSENABLED) ? &gw->pstyle->pressed : &gw->pstyle->disabled; |
|||
|
|||
gdispGFillArea(gw->g.display, gw->g.x+x, gw->g.y, w+y, GWIN_TABSET_TABHEIGHT-1, gw->g.bgcolor); |
|||
gdispGDrawLine(gw->g.display, gw->g.x+x, gw->g.y+y+GWIN_TABSET_TABHEIGHT-1, gw->g.x+x+w-1, gw->g.y+y+GWIN_TABSET_TABHEIGHT-1, pcol->edge); |
|||
} |
|||
#else |
|||
static void fgarea(GWidgetObject *gw, const char *text, coord_t y, coord_t x, coord_t w) { |
|||
const GColorSet * pcol; |
|||
color_t tcol; |
|||
|
|||
pcol = (gw->g.flags & GWIN_FLG_SYSENABLED) ? &gw->pstyle->pressed : &gw->pstyle->disabled; |
|||
|
|||
tcol = gdispBlendColor(pcol->edge, gw->pstyle->background, GTABSET_OUTLINE_FADE); |
|||
gdispGFillStringBox(gw->g.display, gw->g.x+x, gw->g.y+y, w, GWIN_TABSET_TABHEIGHT, text, gw->g.font, pcol->text, gw->g.bgcolor, justifyCenter); |
|||
gdispGDrawLine(gw->g.display, gw->g.x+x, gw->g.y+y, gw->g.x+x+w-(GTABSET_TAB_CNR+1), gw->g.y+y, tcol); |
|||
gdispGDrawLine(gw->g.display, gw->g.x+x+w-(GTABSET_TAB_CNR+1), gw->g.y+y, gw->g.x+x+w-1, gw->g.y+y+GTABSET_TAB_CNR, tcol); |
|||
gdispGDrawLine(gw->g.display, gw->g.x+x+w-1, gw->g.y+y+GTABSET_TAB_CNR, gw->g.x+x+w-1, gw->g.y+y+GWIN_TABSET_TABHEIGHT-1, tcol); |
|||
if (!x) |
|||
gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y+y, gw->g.x, gw->g.y+y+GWIN_TABSET_TABHEIGHT-1, tcol); |
|||
} |
|||
static void bgarea(GWidgetObject *gw, const char *text, coord_t y, coord_t x, coord_t w) { |
|||
const GColorSet * pcol; |
|||
fixed alpha; |
|||
coord_t i; |
|||
color_t tcol, bcol; |
|||
|
|||
pcol = (gw->g.flags & GWIN_FLG_SYSENABLED) ? &gw->pstyle->enabled : &gw->pstyle->disabled; |
|||
|
|||
/* Fill the box blended from variants of the fill color */ |
|||
tcol = gdispBlendColor(White, pcol->fill, GTABSET_TOP_FADE); |
|||
bcol = gdispBlendColor(Black, pcol->fill, GTABSET_BOTTOM_FADE); |
|||
for(alpha = 0, i = 0; i < GWIN_TABSET_TABHEIGHT; i++, alpha += FIXED(255)/GWIN_TABSET_TABHEIGHT) |
|||
gdispGDrawLine(gw->g.display, gw->g.x+x, gw->g.y+y+i, gw->g.x+x+w-2, gw->g.y+y+i, gdispBlendColor(bcol, tcol, NONFIXED(alpha))); |
|||
gdispGDrawLine(gw->g.display, gw->g.x+x+w-1, gw->g.y+y, gw->g.x+x+w-1, gw->g.y+y+GWIN_TABSET_TABHEIGHT-1, pcol->edge); |
|||
gdispGDrawStringBox(gw->g.display, gw->g.x+x+1, gw->g.y+y+1, w-2, GWIN_TABSET_TABHEIGHT-2, text, gw->g.font, pcol->text, justifyCenter); |
|||
} |
|||
static void ntarea(GWidgetObject *gw, coord_t y, coord_t x, coord_t w) { |
|||
const GColorSet * pcol; |
|||
|
|||
pcol = (gw->g.flags & GWIN_FLG_SYSENABLED) ? &gw->pstyle->pressed : &gw->pstyle->disabled; |
|||
|
|||
gdispGFillArea(gw->g.display, gw->g.x+x, gw->g.y+y, w, GWIN_TABSET_TABHEIGHT-1, gw->g.bgcolor); |
|||
gdispGDrawLine(gw->g.display, gw->g.x+x, gw->g.y+y+GWIN_TABSET_TABHEIGHT-1, gw->g.x+x+w-1, gw->g.y+y+GWIN_TABSET_TABHEIGHT-1, pcol->edge); |
|||
} |
|||
#endif |
|||
|
|||
static coord_t drawtabs(GWidgetObject *gw) { |
|||
GHandle ph; |
|||
coord_t x, y, w; |
|||
|
|||
x = w = 0; |
|||
y = 0; |
|||
for(ph = gwinGetFirstChild(&gw->g); ph; ph = gwinGetSibling(ph)) { |
|||
if (ph->vmt == (gwinVMT *)&tabpageVMT) { |
|||
w = gdispGetStringWidth(((GWidgetObject *)ph)->text, gw->g.font) + TEXT_PADDING*2; |
|||
if (x+w > gw->g.width) { |
|||
ntarea(gw, y, x, gw->g.width - x); |
|||
y += GWIN_TABSET_TABHEIGHT; |
|||
x = 0; |
|||
} |
|||
if (ph->flags & GWIN_FLG_VISIBLE) |
|||
fgarea(gw, ((GWidgetObject *)ph)->text, y, x, w); |
|||
else |
|||
bgarea(gw, ((GWidgetObject *)ph)->text, y, x, w); |
|||
x += w; |
|||
} |
|||
} |
|||
if (x < gw->g.width) |
|||
ntarea(gw, y, x, gw->g.width - x); |
|||
return y + GWIN_TABSET_TABHEIGHT; |
|||
} |
|||
|
|||
static void drawborder(GWidgetObject *gw, coord_t y) { |
|||
if ((gw->g.flags & GWIN_CONTAINER_BORDER)) { |
|||
const GColorSet * pcol; |
|||
coord_t x, w; |
|||
|
|||
pcol = (gw->g.flags & GWIN_FLG_SYSENABLED) ? &gw->pstyle->enabled : &gw->pstyle->disabled; |
|||
x = gw->g.x+gw->g.width-1; |
|||
w = gw->g.y+gw->g.height-1; |
|||
gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y+y, gw->g.x, w-1, pcol->edge); |
|||
gdispGDrawLine(gw->g.display, gw->g.x, w, x, w, pcol->edge); |
|||
gdispGDrawLine(gw->g.display, x, gw->g.y+y, x, w-1, pcol->edge); |
|||
} |
|||
} |
|||
|
|||
void gwinTabsetDraw_Transparent(GWidgetObject *gw, void *param) { |
|||
(void) param; |
|||
|
|||
if (gw->g.vmt != (gwinVMT *)&tabsetVMT) |
|||
return; |
|||
|
|||
drawborder(gw, drawtabs(gw)); |
|||
|
|||
// Don't touch the client area
|
|||
} |
|||
|
|||
void gwinTabsetDraw_Std(GWidgetObject *gw, void *param) { |
|||
coord_t y; |
|||
(void) param; |
|||
|
|||
if (gw->g.vmt != (gwinVMT *)&tabsetVMT) |
|||
return; |
|||
|
|||
// Draw the frame
|
|||
y = drawtabs(gw); |
|||
drawborder(gw, y); |
|||
|
|||
// Draw the client area
|
|||
if ((gw->g.flags & GWIN_CONTAINER_BORDER)) |
|||
gdispGFillArea(gw->g.display, gw->g.x+1, gw->g.y+y, gw->g.width-2, gw->g.height-y-1, gw->pstyle->background); |
|||
else |
|||
gdispGFillArea(gw->g.display, gw->g.x, gw->g.y+y, gw->g.width, gw->g.height-y, gw->pstyle->background); |
|||
} |
|||
|
|||
#if GDISP_NEED_IMAGE |
|||
void gwinTabsetDraw_Image(GWidgetObject *gw, void *param) { |
|||
#define gi ((gdispImage *)param) |
|||
coord_t x, y, iw, ih, mx, my; |
|||
|
|||
if (gw->g.vmt != (gwinVMT *)&tabsetVMT) |
|||
return; |
|||
|
|||
// Draw the frame
|
|||
y = drawtabs(gw); |
|||
drawborder(gw, y); |
|||
|
|||
// Draw the client area by tiling the image
|
|||
mx = gw->g.x+gw->g.width; |
|||
my = gw->g.y+gw->g.height; |
|||
if ((gw->g.flags & GWIN_CONTAINER_BORDER)) { |
|||
mx -= 2; |
|||
my -= 1; |
|||
} |
|||
for(y = gw->g.y+y, ih = gi->height; y < my; y += ih) { |
|||
if (ih > my - y) |
|||
ih = my - y; |
|||
x = gw->g.x; |
|||
if ((gw->g.flags & GWIN_CONTAINER_BORDER)) |
|||
x++; |
|||
for(iw = gi->width; x < mx; x += iw) { |
|||
if (iw > mx - x) |
|||
iw = mx - x; |
|||
gdispGImageDraw(gw->g.display, gi, x, y, ih, iw, 0, 0); |
|||
} |
|||
} |
|||
|
|||
#undef gi |
|||
} |
|||
#endif |
|||
|
|||
#endif /* (GFX_USE_GWIN && GWIN_NEED_TABSET) || defined(__DOXYGEN__) */ |
@ -0,0 +1,206 @@ |
|||
/*
|
|||
* 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/gwin_tabset.h |
|||
* @brief GWIN Graphic window subsystem header file. |
|||
* |
|||
* @defgroup Tabset Tabset |
|||
* @ingroup Containers |
|||
* |
|||
* @details A tabset is a set of tabs that control visibility of a number of pages of widgets. |
|||
* Note: Although the tabset is implemented as a container - you don't put your controls |
|||
* directly on the tabset. Instead you create a page and put your widgets on the page. |
|||
* |
|||
* @pre GFX_USE_GWIN must be set to TRUE in your gfxconf.h |
|||
* @pre GWIN_NEED_TABSET must be set to TRUE in your gfxconf.h |
|||
* @{ |
|||
*/ |
|||
|
|||
#ifndef _GWIN_TABSET_H |
|||
#define _GWIN_TABSET_H |
|||
|
|||
/* This file is included from src/gwin/gwin_container.h */ |
|||
|
|||
/**
|
|||
* @brief The Event Type for a Tabset Event |
|||
*/ |
|||
#define GEVENT_GWIN_TABSET (GEVENT_GWIN_CTRL_FIRST+5) |
|||
|
|||
/**
|
|||
* @brief A Tabset Event |
|||
* @note There are currently no GEventGWinTabset listening flags - use 0 as the flags to @p gwinAttachListener() |
|||
*/ |
|||
typedef struct GEventGWinTabset { |
|||
GEventType type; // The type of this event (GEVENT_GWIN_TABSET)
|
|||
GHandle gwin; // The tabset window handle
|
|||
#if GWIN_NEED_WIDGET && GWIN_WIDGET_TAGS |
|||
WidgetTag tag; // The tag of the tabset
|
|||
#endif |
|||
// Above are the generic widget event elements, below the tabset specific elements
|
|||
GHandle ghPage; // The tabpage window handle that has been selected
|
|||
int nPage; // The page number (0 to n-1) that has been selected
|
|||
} GEventGWinTabset; |
|||
|
|||
/**
|
|||
* @brief Flags for gwinTabsetCreate() |
|||
* @{ |
|||
*/ |
|||
#define GWIN_TABSET_BORDER 0x00000001 // Should the tab pages have a border?
|
|||
/** @} */ |
|||
|
|||
typedef struct GTabsetObject { |
|||
GContainerObject c; |
|||
coord_t border_top; |
|||
} GTabsetObject; |
|||
|
|||
#ifdef __cplusplus |
|||
extern "C" { |
|||
#endif |
|||
|
|||
/**
|
|||
* @brief Create a tabset widget |
|||
* |
|||
* @details This widget provides a set of tabs. |
|||
* |
|||
* @param[in] g The GDisplay to display this window on |
|||
* @param[in] fo The GTabsetObject 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_TABSET_BORDER |
|||
* |
|||
* @return NULL if there is no resulting widget. A valid GHandle otherwise. |
|||
* |
|||
* @api |
|||
*/ |
|||
GHandle gwinGTabsetCreate(GDisplay *g, GTabsetObject *fo, GWidgetInit *pInit, uint32_t flags); |
|||
#define gwinTabsetCreate(fo, pInit, flags) gwinGTabsetCreate(GDISP, fo, pInit, flags); |
|||
|
|||
/**
|
|||
* @brief Add a tab-page to the tabset |
|||
* @returns The GHandle of the tab-page container. |
|||
* |
|||
* @param[in] gh The tabset handle |
|||
* @param[in] title The text to set. This must be a constant string unless useAlloc is set. |
|||
* @param[in] useAlloc If TRUE the string specified will be copied into dynamically allocated memory. |
|||
* |
|||
* @api |
|||
*/ |
|||
GHandle gwinTabsetAddTab(GHandle gh, const char *title, bool_t useAlloc); |
|||
|
|||
/**
|
|||
* @brief Delete a tab-page. |
|||
* @details Any widgets on the page will also be destroyed |
|||
* |
|||
* @param[in] gh The tab-page handle |
|||
* |
|||
* @note The index position of all tabs after this tab in the tabset are automatically renumbered. |
|||
* |
|||
* @api |
|||
*/ |
|||
#define gwinTabsetDeleteTab(gh) gwinDestroy(gh) |
|||
|
|||
/**
|
|||
* @brief Count the number of tabs in the tabset |
|||
* @returns The number of tabs or zero if none exist. |
|||
* |
|||
* @param[in] gh The tabset handle |
|||
* |
|||
* @api |
|||
*/ |
|||
int gwinTabsetCountTabs(GHandle gh); |
|||
|
|||
/**
|
|||
* @brief Get the GHandle of a tab based on its position |
|||
* @returns The GHandle of the tab-page container or NULL if that tab-page doesn't exist. |
|||
* |
|||
* @param[in] gh The tabset handle |
|||
* @param[in] index The tab-page handle to return (0 to number of pages - 1) |
|||
* |
|||
* @api |
|||
*/ |
|||
GHandle gwinTabsetGetTabByIndex(GHandle gh, int index); |
|||
|
|||
/**
|
|||
* @brief Get the GHandle of a tab based on its title |
|||
* @returns The GHandle of the tab-page container or NULL if that tab-page doesn't exist. |
|||
* |
|||
* @param[in] gh The tabset handle |
|||
* @param[in] title The title to search for |
|||
* |
|||
* @api |
|||
*/ |
|||
GHandle gwinTabsetGetTabByTitle(GHandle gh, const char *title); |
|||
|
|||
/**
|
|||
* @brief Set the title of a tab-page. |
|||
* |
|||
* @param[in] gh The tab-page handle (NB: Use the page handle NOT the tabset handle) |
|||
* @param[in] title The text to set. This must be a constant string unless useAlloc is set. |
|||
* @param[in] useAlloc If TRUE the string specified will be copied into dynamically allocated memory. |
|||
* |
|||
* @note This function should be used to change the text associated with a tab-page |
|||
* rather than @p gwinSetText(). |
|||
* |
|||
* @api |
|||
*/ |
|||
void gwinTabsetSetTitle(GHandle gh, const char *title, bool_t useAlloc); |
|||
|
|||
/**
|
|||
* @brief Get the title of a tab-page. |
|||
* @return The title of the tab. |
|||
* |
|||
* @param[in] gh The tab-page handle (NB: Use the page handle NOT the tabset handle) |
|||
* |
|||
* @api |
|||
*/ |
|||
#define gwinTabsetGetTitle(gh) gwinGetText(gh) |
|||
|
|||
/**
|
|||
* @brief Set the active tab in a tabset. |
|||
* |
|||
* @param[in] gh The tab-page handle (NB: Use the page handle NOT the tabset handle) |
|||
* |
|||
* @api |
|||
*/ |
|||
void gwinTabsetSetTab(GHandle gh); |
|||
|
|||
/**
|
|||
* @brief The custom draw routines for a frame window |
|||
* @details These function may be passed to @p gwinSetCustomDraw() to get different frame drawing styles |
|||
* |
|||
* @param[in] gw The widget object (in this case a frame) |
|||
* @param[in] param A parameter passed in from the user |
|||
* |
|||
* @note In your own custom drawing function you may optionally call these |
|||
* standard functions and then draw your extra details on top. |
|||
* |
|||
* @note gwinTabsetDraw_Std() will fill the client area with the background color.<br/> |
|||
* gwinTabsetDraw_Transparent() will not fill the client area at all.<br/> |
|||
* gwinTabsetDraw_Image() will tile the image throughout the client area.<br/> |
|||
* All these drawing functions draw the frame itself the same way. |
|||
* |
|||
* @note The standard functions below ignore the param parameter except for @p gwinTabsetDraw_Image(). |
|||
* @note The image custom draw function @p gwinTabsetDraw_Image() uses param to pass in the gdispImage pointer. |
|||
* The image must be already opened before calling @p gwinSetCustomDraw(). |
|||
* |
|||
* @api |
|||
* @{ |
|||
*/ |
|||
void gwinTabsetDraw_Std(GWidgetObject *gw, void *param); |
|||
void gwinTabsetDraw_Transparent(GWidgetObject *gw, void *param); |
|||
void gwinTabsetDraw_Image(GWidgetObject *gw, void *param); |
|||
/** @} */ |
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
|
|||
#endif /* _GWIN_TABSET_H */ |
|||
/** @} */ |
|||
|
Loading…
Reference in new issue