void scroll_to_divnode(struct divnode *div) { s16 dx = 0,dy = 0; struct divnode *ds = div->divscroll; struct widget *w; if (!ds) return; /* If the divnode is larger or equal size to the scrolled * container, no need to scroll it in. * This fixes some confusing scroll behavior when focusing the textbox widget. */ if ( (div->r.x <= ds->calc.x && (div->r.x + div->r.w) > (ds->calc.x + ds->calc.w)) || (div->r.y <= ds->calc.y && (div->r.y + div->r.h) > (ds->calc.y + ds->calc.h)) ) return; /* Figure out how much to scroll, if any. */ if (div->r.x < ds->calc.x) dx = div->r.x - ds->calc.x; else if ( (div->r.x + div->r.w) > (ds->calc.x + ds->calc.w) ) dx = (div->r.x + div->r.w) - (ds->calc.x + ds->calc.w); if (div->r.y < ds->calc.y) dy = div->r.y - ds->calc.y; else if ( (div->r.y + div->r.h) > (ds->calc.y + ds->calc.h) ) dy = (div->r.y + div->r.h) - (ds->calc.y + ds->calc.h); /* No scrolling? */ if (!(dx || dy)) return; /* Get a pointer to the scroll bar */ if (!iserror(rdhandle((void **)&w,PG_TYPE_WIDGET,-1, ds->owner->scrollbind)) && w) { if (dx) widget_set(w,PG_WP_SCROLL_X,widget_get(w,PG_WP_SCROLL_X) + dx); if (dy) widget_set(w,PG_WP_SCROLL_Y,widget_get(w,PG_WP_SCROLL_Y) + dy); update(NULL,1); } }
void themeify_panelbar(struct widget *self,bool force) { int hz = widget_get(self,PG_WP_SIDE) & (PG_S_TOP | PG_S_BOTTOM); /* Apply the current state */ if (DATA->on) div_setstate(DATA->panelbar,hz ? PGTH_O_PANELBAR_H_ON : PGTH_O_PANELBAR_V_ON,force); else if (DATA->over) div_setstate(DATA->panelbar,hz ? PGTH_O_PANELBAR_H_HILIGHT : PGTH_O_PANELBAR_V_HILIGHT,force); else div_setstate(DATA->panelbar,hz ? PGTH_O_PANELBAR_H : PGTH_O_PANELBAR_V,force); }
glob panel_get(struct widget *self,int property) { struct widget *w; g_error e; switch (property) { case PG_WP_THOBJ: return DATA->bg->state; case PG_WP_TEXT: e = rdhandle((void **) &w, PG_TYPE_WIDGET, self->owner, DATA->hlabel); errorcheck; return widget_get(w,property); case PG_WP_IMAGE: e = rdhandle((void **) &w, PG_TYPE_WIDGET, self->owner, DATA->hlabel); errorcheck; return widget_get(w,property); case PG_WP_PANELBAR: return DATA->hbar; case PG_WP_PANELBAR_LABEL: return DATA->hlabel; case PG_WP_PANELBAR_CLOSE: return DATA->hclose; case PG_WP_PANELBAR_ROTATE: return DATA->hrotate; case PG_WP_PANELBAR_ZOOM: return DATA->hzoom; case PG_WP_MARGIN: return DATA->margin; } return widget_base_get(self,property); }
glob tabpage_get(struct widget *self,int property) { struct widget *w; /* Redirect applicable properties to the tab */ if (is_tab_property(property)) if (!iserror(rdhandle((void**)&w, PG_TYPE_WIDGET, self->owner, DATA->htab)) && w) return widget_get(w, property); /* Redirect applicable properties to the tab bar */ if (is_tab_bar_property(property)) if (!iserror(rdhandle((void**)&w, PG_TYPE_WIDGET, self->owner, DATA->htab_bar)) && w) return widget_get(w, property); switch (property) { case PG_WP_TAB: return DATA->htab; case PG_WP_TAB_BAR: return DATA->htab_bar; } return WIDGET_PARENT->get(self,property); }
int panel_rotate_callback(int event, struct widget *from, s32 param, int owner, const u8 *data) { struct widget *p; p = from->callback_owner; if (p && event==PG_WE_ACTIVATE) { switch (widget_get(p,PG_WP_SIDE)) { case PG_S_TOP: widget_set(p,PG_WP_SIDE,PG_S_RIGHT); break; case PG_S_RIGHT: widget_set(p,PG_WP_SIDE,PG_S_BOTTOM); break; case PG_S_BOTTOM: widget_set(p,PG_WP_SIDE,PG_S_LEFT); break; case PG_S_LEFT: widget_set(p,PG_WP_SIDE,PG_S_TOP); break; } update(NULL,1); } return 1; /* Absorb event */ }
void panel_resize(struct widget *self) { struct widget *bar = NULL; rdhandle((void **) &bar, PG_TYPE_WIDGET, self->owner, DATA->hbar); if (DATA->margin_override) DATA->bg->split = DATA->margin; else DATA->bg->split = theme_lookup(DATA->bg->state,PGTH_P_MARGIN); self->in->div->split = theme_lookup(DATA->bg->state,PGTH_P_BORDER_SIZE); /* The minimum setting on the panelbar needs to leave room for the margin * on both sides, and the panelbar width itself. */ if (bar) widget_set(bar, PG_WP_MINIMUM, widget_get(bar, PG_WP_SIZE) + (self->in->div->split << 1)); }
void cursor_widgetunder(struct cursor *crsr) { int x,y; struct divnode *div; struct divtree *dt; cursor_getposition(crsr, &x, &y, &dt); div = dt->head; /* If there are popups and they're all in the nontoolbar area, * we can pass toolbar's events through to the bottom layer in the dtstack */ if (popup_toolbar_passthrough()) { struct divnode *ntb = appmgr_nontoolbar_area(); if (ntb) { if (x < ntb->r.x || y < ntb->r.y || x >= ntb->r.x+ntb->r.w || y >= ntb->r.y+ntb->r.h) { /* Get a widget from the bottom layer, with the toolbars */ div = dts->root->head; } } } /* recursively determine the widget/divnode under the cursor */ crsr->ctx.div_under = NULL; crsr->ctx.deepest_div = NULL; r_cursor_widgetunder(crsr,div,x,y); /* Save the widget associated with the divnode we're under */ if (crsr->ctx.div_under) { crsr->ctx.widget_under = hlookup(crsr->ctx.div_under->owner,NULL); /* Also change the cursor theme */ cursor_set_theme(crsr, widget_get(crsr->ctx.div_under->owner,PG_WP_THOBJ)); } else { crsr->ctx.widget_under = 0; /* Default cursor theme */ cursor_set_theme(crsr, PGTH_O_DEFAULT); } }
/* Sends a trigger to all of a widget's children */ void r_send_trigger(struct widget *w, s32 type, union trigparam *param, int *stop,int forward) { struct widget *bar; if (!w || (*stop) > 0) return; send_trigger(w,type,param); /* Also traverse the panelbar if there is one */ if (!iserror(rdhandle((void**)&bar, PG_TYPE_WIDGET, w->owner, widget_get(w,PG_WP_PANELBAR))) && bar) { r_send_trigger(bar, type, param, stop,0); if ((*stop) > 0) return; } r_send_trigger(widget_traverse(w,PG_TRAVERSE_CHILDREN,0),type,param,stop,1); if (forward) r_send_trigger(widget_traverse(w,PG_TRAVERSE_FORWARD,1),type,param,stop,1); }
g_error widget_base_set(struct widget *w, int property, glob data) { char *str; struct divnode *maindiv = w->in->div ? w->in->div : w->in; switch (property) { /* Set the size, assuming initial split at w->in. * Calls resize handler if it exists, and sets the * appropriate flags. */ case PG_WP_SIDE: if (!VALID_SIDE(data)) return mkerror(PG_ERRT_BADPARAM,2); w->in->flags &= SIDEMASK; w->in->flags |= ((sidet)data) | DIVNODE_NEED_RECALC; resizewidget(w); w->dt->flags |= DIVTREE_NEED_RECALC; redraw_bg(w); if (w->auto_orientation) { /* Set orientation on all child widgets */ struct widget *p; p = widget_traverse(w, PG_TRAVERSE_CHILDREN, 0); while (p) { switch (data) { case PG_S_LEFT: case PG_S_RIGHT: if (w->auto_orientation & PG_AUTO_DIRECTION) widget_set(p, PG_WP_DIRECTION, PG_DIR_VERTICAL); if (w->auto_orientation & PG_AUTO_SIDE) switch (widget_get(p, PG_WP_SIDE)) { case PG_S_LEFT: widget_set(p, PG_WP_SIDE, PG_S_TOP); break; case PG_S_RIGHT: widget_set(p, PG_WP_SIDE, PG_S_BOTTOM); break; } break; case PG_S_TOP: case PG_S_BOTTOM: if (w->auto_orientation & PG_AUTO_DIRECTION) widget_set(p, PG_WP_DIRECTION, PG_DIR_HORIZONTAL); if (w->auto_orientation & PG_AUTO_SIDE) switch (widget_get(p, PG_WP_SIDE)) { case PG_S_TOP: widget_set(p, PG_WP_SIDE, PG_S_LEFT); break; case PG_S_BOTTOM: widget_set(p, PG_WP_SIDE, PG_S_RIGHT); break; } break; } p = widget_traverse(p, PG_TRAVERSE_FORWARD,1); } } break; case PG_WP_SIZE: if (data<0) { /* Automatic sizing */ w->in->flags |= DIVNODE_SIZE_AUTOSPLIT; w->dt->flags |= DIVTREE_NEED_RESIZE; } else { w->in->split = data; w->in->flags &= ~DIVNODE_SIZE_AUTOSPLIT; /* No auto resizing */ } w->in->flags |= DIVNODE_NEED_RECALC; w->dt->flags |= DIVTREE_NEED_RECALC; redraw_bg(w); break; case PG_WP_SIZEMODE: w->in->flags &= ~DIVNODE_SIZE_AUTOSPLIT; /* No auto resizing */ w->in->flags &= ~PG_SZMODEMASK; w->in->flags |= data & PG_SZMODEMASK; redraw_bg(w); break; case PG_WP_SCROLL_X: if (data > w->in->child.w - w->in->r.w) data = w->in->child.w - w->in->r.w; if (data < 0) data = 0; if (maindiv->translation.x != -data) { maindiv->translation.x = -data; maindiv->flags |= DIVNODE_SCROLL_ONLY | DIVNODE_NEED_RECALC; w->dt->flags |= DIVTREE_NEED_REDRAW; hotspot_free(); } maindiv->flags |= DIVNODE_DIVSCROLL | DIVNODE_EXTEND_WIDTH; break; case PG_WP_SCROLL_Y: if (data > w->in->child.h - w->in->r.h) data = w->in->child.h - w->in->r.h; if (data < 0) data = 0; if (maindiv->translation.y != -data) { maindiv->translation.y = -data; maindiv->flags |= DIVNODE_SCROLL_ONLY | DIVNODE_NEED_RECALC; w->dt->flags |= DIVTREE_NEED_REDRAW; hotspot_free(); } maindiv->flags |= DIVNODE_DIVSCROLL | DIVNODE_EXTEND_HEIGHT; break; case PG_WP_NAME: if (iserror(rdhandle((void **)&str,PG_TYPE_PGSTRING,-1,data))) return mkerror(PG_ERRT_HANDLE,18); w->name = handle_canonicalize((handle) data); break; case PG_WP_PUBLICBOX: w->publicbox = data; break; case PG_WP_BIND: w->scrollbind = data; break; case PG_WP_THOBJ: maindiv->state = data; resizewidget(w); w->in->flags |= DIVNODE_NEED_RECALC; w->dt->flags |= DIVTREE_NEED_RECALC; break; case PG_WP_TRIGGERMASK: w->trigger_mask = data; break; case PG_WP_HILIGHTED: { struct widget *p; // // Pass the message onto the other sub widgets // p = widget_traverse(w, PG_TRAVERSE_CHILDREN, 0); while (p) { widget_set(p, PG_WP_HILIGHTED, data); p = widget_traverse(p, PG_TRAVERSE_FORWARD,1); } } break; case PG_WP_AUTO_ORIENTATION: w->auto_orientation = data; break; default: return mkerror(PG_ERRT_BADPARAM,6); /* Unknown property */ } return success; }
void panelbar_trigger_solid(struct widget *self,s32 type,union trigparam *param) { bool force = 0; struct widget *boundwidget; int s; switch (type) { case PG_TRIGGER_ENTER: DATA->over = 1; break; case PG_TRIGGER_LEAVE: DATA->over=0; break; case PG_TRIGGER_DOWN: if (param->mouse.chbtn != 1) return; /* If we're bound to another widget (we should be) save its current size */ if (!iserror(rdhandle((void**)&boundwidget,PG_TYPE_WIDGET,self->owner, DATA->bindto)) && boundwidget) { DATA->oldsize = widget_get(boundwidget,PG_WP_SIZE); /* To make things easier during dragging, * get the effective split to equal the split */ widget_set(boundwidget, PG_WP_SIZEMODE, PG_SZMODE_PIXEL); widget_set(boundwidget, PG_WP_SIZE, panel_effective_split(boundwidget->in)); } DATA->on = 1; DATA->x = param->mouse.x; DATA->y = param->mouse.y; DATA->draglen = 0; break; case PG_TRIGGER_UP: case PG_TRIGGER_RELEASE: if (!DATA->on) return; if (!(param->mouse.chbtn & 1)) return; if (!iserror(rdhandle((void**)&boundwidget,PG_TYPE_WIDGET,self->owner, DATA->bindto)) && boundwidget) { if (DATA->draglen < MINDRAGLEN) { /* This was a click, not a drag */ DATA->over = 0; widget_set(boundwidget,PG_WP_SIZEMODE,PG_SZMODE_PIXEL); if (DATA->oldsize > DATA->minimum) /* Roll up the panel */ widget_set(boundwidget,PG_WP_SIZE,DATA->minimum); else /* Unroll the panel */ widget_set(boundwidget,PG_WP_SIZE,DATA->unrolled); update(NULL,1); } else { s = panel_effective_split(boundwidget->in); /* Save this as the new unrolled split, * Unless the user manually rolled up the panel */ if ((s-DATA->minimum) > MAXROLLUP) DATA->unrolled = s; else s = DATA->minimum; } } DATA->on = 0; break; case PG_TRIGGER_MOVE: case PG_TRIGGER_DRAG: if (!DATA->on) return; if (panel_throttle(self)) return; if (!iserror(rdhandle((void**)&boundwidget,PG_TYPE_WIDGET,self->owner, DATA->bindto)) && boundwidget) { s = panel_calcsplit(self,param->mouse.x,param->mouse.y, widget_get(boundwidget,PG_WP_SIDE)); DATA->draglen += abs(s); if (s) { s += boundwidget->in->split; /* FIXME: This isn't quite right, in solid dragging mode the panelbar * can get out of sync with the cursor when this s < DATA->minimum code * comes into effect. */ if (s < DATA->minimum) s = DATA->minimum; else { DATA->x = param->mouse.x; DATA->y = param->mouse.y; } widget_set(boundwidget, PG_WP_SIZE,s); update(NULL,1); } } return; } themeify_panelbar(self,force); }
void panelbar_trigger_sprite(struct widget *self,s32 type,union trigparam *param) { bool force = 0; struct widget *boundwidget; int s; switch (type) { case PG_TRIGGER_ENTER: DATA->over = 1; break; case PG_TRIGGER_LEAVE: /* If we're dragging, the mouse didn't REALLY leave */ if (DATA->on) return; DATA->over=0; break; case PG_TRIGGER_DOWN: if (param->mouse.chbtn != 1) return; /* If we're bound to another widget (we should be) save its current size */ if (!iserror(rdhandle((void**)&boundwidget,PG_TYPE_WIDGET,self->owner, DATA->bindto)) && boundwidget) { DATA->oldsize = widget_get(boundwidget,PG_WP_SIZE); /* If we're not rolled up, save this as the unrolled split */ if (DATA->oldsize > DATA->minimum) DATA->unrolled = DATA->oldsize; } DATA->on = 1; DATA->x = param->mouse.x; DATA->y = param->mouse.y; DATA->draglen = 0; /* Update the screen now, so we have an up-to-date picture of the panelbar stored in DATA->s */ themeify_panelbar(self,1); VID(sprite_hideall) (); /* This line combined with the zero flag on */ update(NULL,0); /* the next gets a clean spriteless grab */ /* In case there was no release trigger (bug in input driver) */ if (DATA->s) { free_sprite(DATA->s); DATA->s = NULL; } if (DATA->sbit) { VID(bitmap_free) (DATA->sbit); DATA->sbit = NULL; } /* Allocate the new sprite */ if(iserror(new_sprite(&DATA->s,self->dt,DATA->panelbar->r.w,DATA->panelbar->r.h))) { DATA->s = NULL; return; } if (iserror(VID(bitmap_new) (&DATA->sbit,DATA->panelbar->r.w,DATA->panelbar->r.h,vid->bpp))) { free_sprite(DATA->s); DATA->s = NULL; DATA->sbit = NULL; return; } DATA->s->bitmap = &DATA->sbit; /* Grab a bitmap of the panelbar to use as the sprite */ VID(blit) (DATA->sbit,0,0,DATA->panelbar->r.w,DATA->panelbar->r.h, self->dt->display,DATA->s->x = DATA->panelbar->r.x,DATA->s->y = DATA->panelbar->r.y, PG_LGOP_NONE); /* Clip the sprite to the travel allowed by boundwidget's parent */ if (!iserror(rdhandle((void**)&boundwidget,PG_TYPE_WIDGET,self->owner, DATA->bindto)) && boundwidget) { DATA->s->clip_to = boundwidget->in; } return; case PG_TRIGGER_UP: case PG_TRIGGER_RELEASE: if (!DATA->on) return; if (!(param->mouse.chbtn & 1)) return; if (!iserror(rdhandle((void**)&boundwidget,PG_TYPE_WIDGET,self->owner, DATA->bindto)) && boundwidget) { s = panel_calcsplit(self,param->mouse.x,param->mouse.y, widget_get(boundwidget,PG_WP_SIDE)); if (DATA->draglen < MINDRAGLEN) { /* This was a click, not a drag */ DATA->over = 0; widget_set(boundwidget,PG_WP_SIZEMODE,PG_SZMODE_PIXEL); if (DATA->oldsize > DATA->minimum) /* Roll up the panel */ widget_set(boundwidget,PG_WP_SIZE,DATA->minimum); else /* Unroll the panel */ widget_set(boundwidget,PG_WP_SIZE,DATA->unrolled); } else { s += panel_effective_split(boundwidget->in); /* Save this as the new unrolled split, * Unless the user manually rolled up the panel */ if ((s-DATA->minimum) > MAXROLLUP) DATA->unrolled = s; else s = DATA->minimum; widget_set(boundwidget,PG_WP_SIZEMODE,PG_SZMODE_PIXEL); widget_set(boundwidget,PG_WP_SIZE,s); DATA->over = 1; } } VID(bitmap_free) (DATA->sbit); free_sprite(DATA->s); DATA->s = NULL; DATA->sbit = NULL; force = 1; /* Definitely draw the new position */ DATA->on = 0; break; case PG_TRIGGER_MOVE: case PG_TRIGGER_DRAG: if (!DATA->on) return; /* Ok, button 1 is dragging through our widget... */ if (panel_throttle(self)) return; /* Race condition prevention? * Without this, sometimes segfaults because DATA->s is NULL. * Possibly events_pending() triggered another event? */ if (!DATA->s) return; /* Determine where to blit the bar to... */ switch (self->in->flags & (~SIDEMASK)) { case PG_S_TOP: case PG_S_BOTTOM: DATA->s->x = DATA->panelbar->r.x; DATA->draglen += abs(param->mouse.y - DATA->y + DATA->panelbar->r.y - DATA->s->y); DATA->s->y = param->mouse.y - DATA->y + DATA->panelbar->r.y; break; case PG_S_LEFT: case PG_S_RIGHT: DATA->s->y = DATA->panelbar->r.y; DATA->draglen += abs(param->mouse.x - DATA->x + DATA->panelbar->r.x - DATA->s->x); DATA->s->x = param->mouse.x - DATA->x + DATA->panelbar->r.x; break; } /* Reposition sprite */ VID(sprite_update) (DATA->s); return; } themeify_panelbar(self,force); }
/* Fillstyle interpreter- generates/refreshes a gropnode list */ g_error exec_fillstyle_inner(struct gropctxt *ctx,u16 state, u16 property) { g_error e; u32 fssize; /* Fillstyle size */ unsigned char *fs; /* Pointer to the actual fillstyle data */ unsigned char *p,*plimit; unsigned char op; int r,g,b; /* For color arithmetic */ struct widget *w; int stackframe = fsstkpos-4; /* Look up the fillstyle */ e = rdhandle((void**)&fs,PG_TYPE_FILLSTYLE,-1,theme_lookup(state,property)); errorcheck; if (!fs) { /* When our best just isn't good enough... */ if (property == PGTH_P_BACKDROP || property == PGTH_P_BORDER_FILL) return success; /* The default fillstyle, if no theme is loaded or no theme has defined the property*/ addgrop(ctx,PG_GROP_SETCOLOR); ctx->current->param[0] = VID(color_pgtohwr) (0x000000); switch (state) { case PGTH_O_BUTTON_ON: /* 2 borders */ addgropsz(ctx,PG_GROP_FRAME,ctx->r.x,ctx->r.y,ctx->r.w,ctx->r.h); ctx->r.x += 1; ctx->r.y += 1; ctx->r.w -= 2; ctx->r.h -= 2; default: /* 1 border */ addgropsz(ctx,PG_GROP_FRAME,ctx->r.x,ctx->r.y,ctx->r.w,ctx->r.h); ctx->r.x += 1; ctx->r.y += 1; ctx->r.w -= 2; ctx->r.h -= 2; case PGTH_O_LABEL_SCROLL: /* No border */ addgrop(ctx,PG_GROP_SETCOLOR); ctx->current->param[0] = VID(color_pgtohwr) (theme_lookup(state,PGTH_P_BGCOLOR)); addgropsz(ctx,PG_GROP_RECT,ctx->r.x,ctx->r.y,ctx->r.w,ctx->r.h); } return success; } /* Process the opcodes */ fssize = *(((u32 *)fs)++); p = fs; plimit = fs+fssize; while (p<plimit) { op = *(p++); /* These must occur in MSB to LSB order! (see constants.h) */ if (op & PGTH_OPSIMPLE_GROP) { /* 1-byte gropnode */ e = fsgrop(ctx,op & (PGTH_OPSIMPLE_GROP-1)); errorcheck; } else if (op & PGTH_OPSIMPLE_LITERAL) { /* 1-byte literal */ fsstack[fsstkpos++] = op & (PGTH_OPSIMPLE_LITERAL-1); } else if (op & PGTH_OPSIMPLE_CMDCODE) { /* Command code */ switch (op) { case PGTH_OPCMD_LONGLITERAL: if ((plimit-p)<4) return mkerror(PG_ERRT_BADPARAM,91); /* Truncated opcode */ fsstack[fsstkpos++] = NEXTLONG; p += 4; break; case PGTH_OPCMD_LONGGROP: if ((plimit-p)<2) return mkerror(PG_ERRT_BADPARAM,91); /* Truncated opcode */ e = fsgrop(ctx,NEXTSHORT); p += 2; errorcheck; break; case PGTH_OPCMD_LONGGET: if (plimit<=p) return mkerror(PG_ERRT_BADPARAM,91); /* Truncated opcode */ e = fsget(*(p++)+stackframe); errorcheck; break; case PGTH_OPCMD_LONGSET: if (plimit<=p) return mkerror(PG_ERRT_BADPARAM,91); /* Truncated opcode */ e = fsset(*(p++)+stackframe); errorcheck; break; case PGTH_OPCMD_PROPERTY: if ((plimit-p)<4) return mkerror(PG_ERRT_BADPARAM,91); /* Truncated opcode */ fsa = NEXTSHORT; p += 2; fsb = NEXTSHORT; p += 2; fsstack[fsstkpos++] = theme_lookup(fsa,fsb); #ifdef CONFIG_ANIMATION /* If it depends on time or randomness, turn on the animated flag in the divnode */ if ((fsb==PGTH_P_TICKS || fsb==PGTH_P_RANDOM) && ctx->owner) ctx->owner->flags |= DIVNODE_ANIMATED; #endif break; case PGTH_OPCMD_LOCALPROP: if ((plimit-p)<2) return mkerror(PG_ERRT_BADPARAM,91); /* Truncated opcode */ fsa = NEXTSHORT; p += 2; #ifdef DEBUG_THEME printf("Local theme lookup, property %d\n",(int)fsa); #endif fsstack[fsstkpos++] = theme_lookup(state,fsa); #ifdef CONFIG_ANIMATION /* If it depends on time or randomness, turn on the animated flag in the divnode */ if ((fsa==PGTH_P_TICKS || fsa==PGTH_P_RANDOM) && ctx->owner) ctx->owner->flags |= DIVNODE_ANIMATED; #endif break; case PGTH_OPCMD_PLUS: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa + fsb; break; case PGTH_OPCMD_MINUS: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa - fsb; break; case PGTH_OPCMD_MULTIPLY: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa * fsb; break; case PGTH_OPCMD_SHIFTL: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa << fsb; break; case PGTH_OPCMD_SHIFTR: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa >> fsb; break; case PGTH_OPCMD_OR: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa | fsb; break; case PGTH_OPCMD_AND: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa & fsb; break; case PGTH_OPCMD_EQ: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa == fsb; break; case PGTH_OPCMD_LT: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa < fsb; break; case PGTH_OPCMD_GT: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa > fsb; break; case PGTH_OPCMD_LOGICAL_OR: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa || fsb; break; case PGTH_OPCMD_LOGICAL_AND: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa && fsb; break; case PGTH_OPCMD_LOGICAL_NOT: fsstack[fsstkpos-1] = !fsstack[fsstkpos-1]; break; case PGTH_OPCMD_DIVIDE: e = fspopargs(); errorcheck; if (fsb) fsstack[fsstkpos++] = fsa / fsb; else fsstack[fsstkpos++] = 0xFFFFFFFF; /* limit of fsa/fsb as fsb approaches 0 */ break; case PGTH_OPCMD_COLORADD: e = fspopargs(); errorcheck; r = getred(fsa); g = getgreen(fsa); b = getblue(fsa); r += getred(fsb); g += getgreen(fsb); b += getblue(fsb); if (r>255) r = 255; if (g>255) g = 255; if (b>255) b = 255; fsstack[fsstkpos++] = mkcolor(r,g,b); break; case PGTH_OPCMD_COLORSUB: e = fspopargs(); errorcheck; r = getred(fsa); g = getgreen(fsa); b = getblue(fsa); r -= getred(fsb); g -= getgreen(fsb); b -= getblue(fsb); if (r<0) r = 0; if (g<0) g = 0; if (b<0) b = 0; fsstack[fsstkpos++] = mkcolor(r,g,b); break; case PGTH_OPCMD_COLORDIV: e = fspopargs(); errorcheck; r = getred(fsa); g = getgreen(fsa); b = getblue(fsa); r = getred(fsb) ? (r/getred(fsb)) : 0xFF; /* Avoid divide by zero */ g = getgreen(fsb) ? (g/getgreen(fsb)) : 0xFF; b = getred(fsb) ? (b/getblue(fsb)) : 0xFF; fsstack[fsstkpos++] = mkcolor(r,g,b); break; case PGTH_OPCMD_COLORMULT: e = fspopargs(); errorcheck; r = getred(fsa); g = getgreen(fsa); b = getblue(fsa); r *= getred(fsb); g *= getgreen(fsb); b *= getblue(fsb); if (r>255) r = 255; if (g>255) g = 255; if (b>255) b = 255; fsstack[fsstkpos++] = mkcolor(r,g,b); break; case PGTH_OPCMD_QUESTIONCOLON: if (fsstkpos<3) return mkerror(PG_ERRT_BADPARAM,88); /* Stack underflow */ fsstkpos -= 2; fsstack[fsstkpos-1] = fsstack[fsstkpos+1] ? fsstack[fsstkpos] : fsstack[fsstkpos-1]; break; case PGTH_OPCMD_WIDGET: if (ctx->owner && ctx->owner->owner) fsstack[fsstkpos++] = hlookup(ctx->owner->owner,NULL); else fsstack[fsstkpos++] = 0; break; case PGTH_OPCMD_TRAVERSEWGT: if (fsstkpos<3) return mkerror(PG_ERRT_BADPARAM,88); /* Stack underflow */ fsstkpos -= 2; e = rdhandle((void**)&w, PG_TYPE_WIDGET, -1, fsstack[fsstkpos+1]); errorcheck; if (w) fsstack[fsstkpos-1] = hlookup(widget_traverse(w,fsstack[fsstkpos],fsstack[fsstkpos-1]),NULL); else fsstack[fsstkpos-1] = 0; break; case PGTH_OPCMD_GETWIDGET: e = fspopargs(); errorcheck; e = rdhandle((void**)&w, PG_TYPE_WIDGET, -1, fsa); errorcheck; if (w) fsstack[fsstkpos++] = widget_get(w,fsb); else fsstack[fsstkpos++] = 0; break; case PGTH_OPCMD_CALL: if ((plimit-p)<4) return mkerror(PG_ERRT_BADPARAM,91); /* Truncated opcode */ fsa = NEXTSHORT; p += 2; fsb = NEXTSHORT; p += 2; e = exec_fillstyle_inner(ctx,fsa,fsb); errorcheck; break; case PGTH_OPCMD_LOCALCALL: if ((plimit-p)<2) return mkerror(PG_ERRT_BADPARAM,91); /* Truncated opcode */ fsb = NEXTSHORT; p += 2; e = exec_fillstyle_inner(ctx,state,fsb); errorcheck; break; case PGTH_OPCMD_EXTENDED: /* extended command */ op = *(p++); switch (op) { case PGTH_EXCMD_SKIP_IF: if (!fsstack[--fsstkpos]) { --fsstkpos; break; } /* else proceed to EXCMD_SKIP */ case PGTH_EXCMD_SKIP: p += (s32)fsstack[--fsstkpos]; break; } break; } } else if (op & PGTH_OPSIMPLE_GET) { /* 1-byte get */ e = fsget((op & (PGTH_OPSIMPLE_GET-1)) + stackframe); errorcheck; } else { /* 1-byte set */ e = fsset(op + stackframe); errorcheck; } #ifdef DEBUG_THEME /* trace */ printf("FILLSTYLE --- Op: 0x%02X Stk:",op); for (fsa=0;fsa<fsstkpos;fsa++) printf(" %d",(int)fsstack[fsa]); printf("\n"); #endif /* check for stack over/underflow */ if (fsstkpos<0) return mkerror(PG_ERRT_BADPARAM,88); /* Stack underflow */ if (fsstkpos>=FSSTACKSIZE) return mkerror(PG_ERRT_BADPARAM,89); /* Stack overflow */ }
/* Called when our tab button is selected or deselected */ static int tabpage_tab_callback(int event, struct widget *from, s32 param, int owner, const u8 *data) { tabpage_show_hide(from->callback_owner, widget_get(from, PG_WP_ON)); post_event(PG_WE_ACTIVATE,from->callback_owner,0,0,NULL); }
/* This is called whenever the widget is attached, after the attaching * process is complete. We use this as a hook for managing the tab and tab_bar. */ g_error tabpage_post_attach(struct widget *self, struct widget *parent, int rship) { struct widget *tab, *tab_bar, *parent_tab; g_error e; handle existing_bar = 0; /* Dereference handles */ e = rdhandle((void**)&tab, PG_TYPE_WIDGET, self->owner, DATA->htab); errorcheck; e = rdhandle((void**)&tab_bar, PG_TYPE_WIDGET, self->owner, DATA->htab_bar); errorcheck; /* Detach our tab. It will be reattached later if necessary */ e = widget_derive(&tab, &DATA->htab, tab->type, NULL, 0, 0, self->owner); errorcheck; /* If we already have a tab bar but it's empty, delete it */ if (DATA->htab_bar && !widget_traverse(tab_bar, PG_TRAVERSE_CHILDREN, 0)) { handle_free(self->owner, DATA->htab_bar); DATA->htab_bar = 0; } /* Are we being attached rather than detached? */ if (parent) { /* If we're attaching before or after another tab page, share its tab bar */ if (parent->type==PG_WIDGET_TABPAGE && (rship==PG_DERIVE_BEFORE || rship==PG_DERIVE_AFTER)) { struct widget *self = parent; existing_bar = DATA->htab_bar; } DATA->htab_bar = existing_bar; /* Otherwise, create a new tab bar */ if (!DATA->htab_bar) { tab_bar = NULL; e = widget_derive(&tab_bar, &DATA->htab_bar, PG_WIDGET_TOOLBAR, self, self->h, PG_DERIVE_BEFORE, self->owner); errorcheck; e = widget_set(tab_bar, PG_WP_THOBJ, PGTH_O_TAB_BAR); errorcheck; tab_bar->auto_orientation = PG_AUTO_SIDE; } /* If we're attaching on an existing bar, attach the tab in the same * relative order as the tab pages themselves. */ parent_tab = NULL; rdhandle((void**)&parent_tab, PG_TYPE_WIDGET, self->owner, widget_get(parent, PG_WP_TAB)); if (existing_bar && parent_tab) { e = widget_derive(&tab, &DATA->htab, tab->type, parent_tab, parent_tab->h, rship, self->owner); errorcheck; } /* Otherwise just put it in our tab bar directly */ else { e = widget_derive(&tab, &DATA->htab, tab->type, tab_bar, tab_bar->h, PG_DERIVE_INSIDE, self->owner); errorcheck; } /* If we were here first, make ourselves active */ if (!existing_bar) { e = widget_set(self, PG_WP_ON, 1); errorcheck; } } return success; }