#include <string.h>
#include "imago2.h"
#include "rtk_impl.h"
+#include "app.h"
static rtk_draw_ops gfx;
static void draw_checkbox(rtk_widget *w);
static void draw_separator(rtk_widget *w);
+static void invalfb(rtk_widget *w);
+
static rtk_widget *hover, *focused, *pressed;
{
w->any.x = x;
w->any.y = y;
- w->any.flags |= GEOMCHG;
+ w->any.flags |= GEOMCHG | DIRTY;
}
void rtk_pos(rtk_widget *w, int *xptr, int *yptr)
{
w->any.width = xsz;
w->any.height = ysz;
- w->any.flags |= GEOMCHG;
+ w->any.flags |= GEOMCHG | DIRTY;
}
void rtk_size(rtk_widget *w, int *xptr, int *yptr)
*yptr = w->any.height;
}
+void rtk_get_rect(rtk_widget *w, rtk_rect *r)
+{
+ r->x = w->any.x;
+ r->y = w->any.y;
+ r->width = w->any.width;
+ r->height = w->any.height;
+}
+
int rtk_set_text(rtk_widget *w, const char *str)
{
rtk_rect rect;
calc_widget_rect(w, &rect);
rtk_resize(w, rect.width, rect.height);
+ rtk_invalidate(w);
return 0;
}
void rtk_set_value(rtk_widget *w, int val)
{
w->any.value = val;
+ rtk_invalidate(w);
}
int rtk_get_value(rtk_widget *w)
w->any.cbcls = cls;
}
+void rtk_show(rtk_widget *w)
+{
+ w->any.flags |= VISIBLE;
+ rtk_invalidate(w);
+}
+
+void rtk_hide(rtk_widget *w)
+{
+ w->any.flags &= ~VISIBLE;
+ invalfb(w);
+}
+
+int rtk_visible(const rtk_widget *w)
+{
+ return w->any.flags & VISIBLE;
+}
+
+void rtk_invalidate(rtk_widget *w)
+{
+ w->any.flags |= DIRTY;
+}
+
+void rtk_validate(rtk_widget *w)
+{
+ w->any.flags &= ~DIRTY;
+}
+
void rtk_win_layout(rtk_widget *w, int layout)
{
w->win.layout = layout;
}
w->win.clist = w->win.ctail = 0;
+ rtk_invalidate(w);
}
void rtk_win_add(rtk_widget *par, rtk_widget *child)
child->any.next = 0;
child->any.par = par;
+ rtk_invalidate(par);
}
void rtk_win_rm(rtk_widget *par, rtk_widget *child)
prev = prev->any.next;
}
par->win.clist = dummy.any.next;
+ rtk_invalidate(par);
}
int rtk_win_has(rtk_widget *par, rtk_widget *child)
}
/* --- button functions --- */
+void rtk_bn_mode(rtk_widget *w, int mode)
+{
+ RTK_ASSERT_TYPE(w, RTK_BUTTON);
+ w->bn.mode = mode;
+ rtk_invalidate(w);
+}
void rtk_bn_set_icon(rtk_widget *w, rtk_icon *icon)
{
calc_widget_rect(w, &rect);
rtk_resize(w, rect.width, rect.height);
+ rtk_invalidate(w);
}
rtk_icon *rtk_bn_get_icon(rtk_widget *w)
/* --- constructors --- */
-rtk_widget *rtk_create_window(rtk_widget *par, const char *title, int x, int y, int width, int height)
+rtk_widget *rtk_create_window(rtk_widget *par, const char *title, int x, int y,
+ int width, int height, unsigned int flags)
{
rtk_widget *w;
rtk_set_text(w, title);
rtk_move(w, x, y);
rtk_resize(w, width, height);
+
+ w->any.flags |= flags << 16;
return w;
}
w->any.width = rect.width;
w->any.height = rect.height;
- w->any.flags = (w->any.flags & ~GEOMCHG) | DIRTY;
+ w->any.flags &= ~GEOMCHG;
+ rtk_invalidate(w);
}
void rtk_draw_widget(rtk_widget *w)
{
+ int dirty;
+
+ if(!(w->any.flags & VISIBLE)) {
+ return;
+ }
+
if(need_relayout(w)) {
calc_layout(w);
}
+ dirty = w->any.flags & DIRTY;
+ if(!dirty && w->any.type != RTK_WIN) {
+ return;
+ }
+
switch(w->any.type) {
case RTK_WIN:
draw_window(w);
break;
}
- w->any.flags &= ~DIRTY;
+ if(dirty) {
+ rtk_validate(w);
+ invalfb(w);
+ }
}
static void widget_rect(rtk_widget *w, rtk_rect *rect)
#define COL_LBEV 0xffaaaaaa
#define COL_SBEV 0xff222222
#define COL_TEXT 0xff000000
+#define COL_WINFRM 0xff2244aa
+#define COL_WINFRM_LIT 0xff4466ff
+#define COL_WINFRM_SHAD 0xff051166
static void hline(int x, int y, int sz, uint32_t col)
{
enum {FRM_SOLID, FRM_OUTSET, FRM_INSET};
+enum {UICOL_BG, UICOL_LBEV, UICOL_SBEV};
+static uint32_t uicol[3];
+
+static void uicolor(uint32_t col, uint32_t lcol, uint32_t scol)
+{
+ uicol[UICOL_BG] = col;
+ uicol[UICOL_LBEV] = lcol;
+ uicol[UICOL_SBEV] = scol;
+}
+
static void draw_frame(rtk_rect *rect, int type)
{
int tlcol, brcol;
tlcol = brcol = 0xff000000;
break;
case FRM_OUTSET:
- tlcol = COL_LBEV;
- brcol = COL_SBEV;
+ tlcol = uicol[UICOL_LBEV];
+ brcol = uicol[UICOL_SBEV];
break;
case FRM_INSET:
- tlcol = COL_SBEV;
- brcol = COL_LBEV;
+ tlcol = uicol[UICOL_SBEV];
+ brcol = uicol[UICOL_LBEV];
break;
default:
break;
vline(rect->x + rect->width - 1, rect->y + 1, rect->height - 2, brcol);
}
+#define WINFRM_SZ 2
+#define WINFRM_TBAR 16
+
static void draw_window(rtk_widget *w)
{
- rtk_rect rect;
+ rtk_rect rect, frmrect, tbrect;
rtk_widget *c;
+ int win_dirty = w->any.flags & DIRTY;
+
+ if(win_dirty) {
+ widget_rect(w, &rect);
+
+ if(w->any.flags & FRAME) {
+ uicolor(COL_WINFRM, COL_WINFRM_LIT, COL_WINFRM_SHAD);
+
+ frmrect = rect;
+ frmrect.width += WINFRM_SZ * 2;
+ frmrect.height += WINFRM_SZ * 2 + WINFRM_TBAR;
+ frmrect.x -= WINFRM_SZ;
+ frmrect.y -= WINFRM_SZ + WINFRM_TBAR;
+
+ tbrect.x = rect.x;
+ tbrect.y = rect.y - WINFRM_TBAR;
+ tbrect.width = rect.width;
+ tbrect.height = WINFRM_TBAR;
+
+ draw_frame(&frmrect, FRM_OUTSET);
+ frmrect.x++;
+ frmrect.y++;
+ frmrect.width -= 2;
+ frmrect.height -= 2;
+ draw_frame(&frmrect, FRM_INSET);
+
+ draw_frame(&tbrect, FRM_OUTSET);
+ tbrect.x++;
+ tbrect.y++;
+ tbrect.width -= 2;
+ tbrect.height -= 2;
+ gfx.fill(&tbrect, COL_WINFRM);
+ }
- widget_rect(w, &rect);
- gfx.fill(&rect, COL_BG);
+ gfx.fill(&rect, COL_BG);
+ }
c = w->win.clist;
while(c) {
+ if(win_dirty) {
+ rtk_invalidate(c);
+ }
rtk_draw_widget(c);
c = c->any.next;
}
static void draw_button(rtk_widget *w)
{
+ int pressed;
rtk_rect rect;
widget_rect(w, &rect);
abs_pos(w, &rect.x, &rect.y);
+ if(w->bn.mode == RTK_TOGGLEBN) {
+ pressed = w->any.value;
+ } else {
+ pressed = w->any.flags & PRESS;
+ }
+
+ uicolor(COL_BG, COL_LBEV, COL_SBEV);
+
if(rect.width > 2 && rect.height > 2) {
- draw_frame(&rect, w->any.flags & PRESS ? FRM_INSET : FRM_OUTSET);
+ draw_frame(&rect, pressed ? FRM_INSET : FRM_OUTSET);
rect.x++;
rect.y++;
if(!win) return;
+ uicolor(COL_BG, COL_LBEV, COL_SBEV);
+
widget_rect(w, &rect);
abs_pos(w, &rect.x, &rect.y);
if(hover) {
hover->any.flags &= ~HOVER;
+
+ if(hover->type != RTK_WIN) {
+ rtk_invalidate(hover);
+ invalfb(hover);
+ }
}
hover = w;
if(w) {
w->any.flags |= HOVER;
+
+ if(w->type != RTK_WIN) {
+ rtk_invalidate(w);
+ invalfb(w);
+ }
}
}
if(pressed) {
pressed->any.flags &= ~PRESS;
+ rtk_invalidate(pressed);
+ invalfb(pressed);
}
pressed = w;
if(w) {
w->any.flags |= PRESS;
+ rtk_invalidate(w);
+ invalfb(w);
}
}
static void click(rtk_widget *w, int x, int y)
{
switch(w->type) {
- case RTK_CHECKBOX:
- w->any.value ^= 1;
case RTK_BUTTON:
+ if(w->bn.mode == RTK_TOGGLEBN) {
+ case RTK_CHECKBOX:
+ w->any.value ^= 1;
+ }
if(w->any.cbfunc) {
w->any.cbfunc(w, w->any.cbcls);
}
+ rtk_invalidate(w);
+ invalfb(w);
break;
default:
return res;
}
- sethover(w);
-
if(w->type == RTK_WIN) {
c = w->win.clist;
while(c) {
}
}
- return 1;
+ if(hover != w) {
+ sethover(w);
+ return 1;
+ }
+ return 0;
+}
+
+void rtk_fix_rect(rtk_rect *rect)
+{
+ int x, y, w, h;
+
+ x = rect->x;
+ y = rect->y;
+
+ if(rect->width < 0) {
+ w = -rect->width;
+ x += rect->width;
+ } else {
+ w = rect->width;
+ }
+ if(rect->height < 0) {
+ h = -rect->height;
+ y += rect->height;
+ } else {
+ h = rect->height;
+ }
+
+ rect->x = x;
+ rect->y = y;
+ rect->width = w;
+ rect->height = h;
+}
+
+void rtk_rect_union(rtk_rect *a, const rtk_rect *b)
+{
+ int x0, y0, x1, y1;
+
+ x0 = a->x;
+ y0 = a->y;
+ x1 = a->x + a->width;
+ y1 = a->y + a->height;
+
+ if(b->x < x0) x0 = b->x;
+ if(b->y < y0) y0 = b->y;
+ if(b->x + b->width > x1) x1 = b->x + b->width;
+ if(b->y + b->height > y1) y1 = b->y + b->height;
+
+ a->x = x0;
+ a->y = y0;
+ a->width = x1 - x0;
+ a->height = y1 - y0;
+}
+
+static void invalfb(rtk_widget *w)
+{
+ app_redisplay(w->any.x, w->any.y, w->any.width, w->any.height);
}