HelenOS sources
This source file includes following definitions.
- ui_tab_create
- ui_tab_destroy
- ui_tab_first
- ui_tab_next
- ui_tab_last
- ui_tab_prev
- ui_tab_is_selected
- ui_tab_add
- ui_tab_remove
- ui_tab_handle_width
- ui_tab_handle_height
- ui_tab_get_geom
- ui_tab_get_res
- ui_tab_paint_handle_frame
- ui_tab_paint_body_frame
- ui_tab_paint_frame
- ui_tab_paint
- ui_tab_pos_event
- ui_tab_kbd_event
#include <adt/list.h>
#include <errno.h>
#include <gfx/color.h>
#include <gfx/context.h>
#include <gfx/render.h>
#include <gfx/text.h>
#include <io/pos_event.h>
#include <stdlib.h>
#include <str.h>
#include <uchar.h>
#include <ui/control.h>
#include <ui/paint.h>
#include <ui/popup.h>
#include <ui/tab.h>
#include <ui/tabset.h>
#include <ui/resource.h>
#include <ui/window.h>
#include "../private/control.h"
#include "../private/tab.h"
#include "../private/tabset.h"
#include "../private/resource.h"
enum {
tab_start_hmargin = 6,
tab_start_hmargin_text = 1,
tab_handle_hpad = 6,
tab_handle_top_pad = 5,
tab_handle_bottom_pad = 5,
tab_handle_hpad_text = 1,
tab_handle_top_pad_text = 0,
tab_handle_bottom_pad_text = 1,
tab_handle_chamfer = 3,
tab_handle_pullup = 2,
tab_frame_w = 2,
tab_frame_h = 2,
tab_frame_w_text = 1,
tab_frame_h_text = 1
};
static ui_box_chars_t sel_tab_box_chars = {
{
{ "\u250c", "\u2500", "\u2510" },
{ "\u2502", " ", "\u2502" },
{ "\u2518", " ", "\u2514" }
}
};
static ui_box_chars_t unsel_tab_box_chars = {
{
{ "\u250c", "\u2500", "\u2510" },
{ "\u2502", " ", "\u2502" },
{ "\u2534", "\u2500", "\u2534" }
}
};
errno_t ui_tab_create(ui_tab_set_t *tabset, const char *caption,
ui_tab_t **rtab)
{
ui_tab_t *tab;
ui_tab_t *prev;
tab = calloc(1, sizeof(ui_tab_t));
if (tab == NULL)
return ENOMEM;
tab->caption = str_dup(caption);
if (tab->caption == NULL) {
free(tab);
return ENOMEM;
}
prev = ui_tab_last(tabset);
if (prev != NULL)
tab->xoff = prev->xoff + ui_tab_handle_width(prev);
else
tab->xoff = tabset->res->textmode ?
tab_start_hmargin_text : tab_start_hmargin;
tab->tabset = tabset;
list_append(&tab->ltabs, &tabset->tabs);
if (tabset->selected == NULL)
tabset->selected = tab;
*rtab = tab;
return EOK;
}
void ui_tab_destroy(ui_tab_t *tab)
{
if (tab == NULL)
return;
ui_control_destroy(tab->content);
list_remove(&tab->ltabs);
free(tab->caption);
free(tab);
}
ui_tab_t *ui_tab_first(ui_tab_set_t *tabset)
{
link_t *link;
link = list_first(&tabset->tabs);
if (link == NULL)
return NULL;
return list_get_instance(link, ui_tab_t, ltabs);
}
ui_tab_t *ui_tab_next(ui_tab_t *cur)
{
link_t *link;
link = list_next(&cur->ltabs, &cur->tabset->tabs);
if (link == NULL)
return NULL;
return list_get_instance(link, ui_tab_t, ltabs);
}
ui_tab_t *ui_tab_last(ui_tab_set_t *tabset)
{
link_t *link;
link = list_last(&tabset->tabs);
if (link == NULL)
return NULL;
return list_get_instance(link, ui_tab_t, ltabs);
}
ui_tab_t *ui_tab_prev(ui_tab_t *cur)
{
link_t *link;
link = list_prev(&cur->ltabs, &cur->tabset->tabs);
if (link == NULL)
return NULL;
return list_get_instance(link, ui_tab_t, ltabs);
}
bool ui_tab_is_selected(ui_tab_t *tab)
{
return tab->tabset->selected == tab;
}
void ui_tab_add(ui_tab_t *tab, ui_control_t *control)
{
assert(tab->content == NULL);
tab->content = control;
control->elemp = (void *) tab;
}
void ui_tab_remove(ui_tab_t *tab, ui_control_t *control)
{
assert(tab->content == control);
assert((ui_tab_t *) control->elemp == tab);
tab->content = NULL;
control->elemp = NULL;
}
gfx_coord_t ui_tab_handle_width(ui_tab_t *tab)
{
ui_resource_t *res;
gfx_coord_t frame_w;
gfx_coord_t handle_hpad;
gfx_coord_t text_w;
res = tab->tabset->res;
if (!res->textmode) {
frame_w = tab_frame_w;
handle_hpad = tab_handle_hpad;
} else {
frame_w = tab_frame_w_text;
handle_hpad = tab_handle_hpad_text;
}
text_w = ui_text_width(tab->tabset->res->font, tab->caption);
return 2 * frame_w + 2 * handle_hpad + text_w;
}
gfx_coord_t ui_tab_handle_height(ui_tab_t *tab)
{
gfx_coord_t frame_h;
gfx_coord_t handle_top_pad;
gfx_coord_t handle_bottom_pad;
gfx_font_metrics_t metrics;
ui_resource_t *res;
res = tab->tabset->res;
gfx_font_get_metrics(tab->tabset->res->font, &metrics);
if (!res->textmode) {
frame_h = tab_frame_h;
handle_top_pad = tab_handle_top_pad;
handle_bottom_pad = tab_handle_bottom_pad;
} else {
frame_h = tab_frame_h_text;
handle_top_pad = tab_handle_top_pad_text;
handle_bottom_pad = tab_handle_bottom_pad_text;
}
return frame_h + handle_top_pad + metrics.ascent +
metrics.descent + 1 + handle_bottom_pad;
}
void ui_tab_get_geom(ui_tab_t *tab, ui_tab_geom_t *geom)
{
gfx_coord_t handle_w;
gfx_coord_t handle_h;
gfx_coord_t pullup;
gfx_coord_t frame_w;
gfx_coord_t frame_h;
gfx_coord_t handle_hpad;
gfx_coord_t handle_top_pad;
ui_resource_t *res;
res = tab->tabset->res;
handle_w = ui_tab_handle_width(tab);
handle_h = ui_tab_handle_height(tab);
pullup = res->textmode ? 0 : tab_handle_pullup;
if (!res->textmode) {
frame_w = tab_frame_w;
frame_h = tab_frame_h;
handle_hpad = tab_handle_hpad;
handle_top_pad = tab_handle_top_pad;
} else {
frame_w = tab_frame_w_text;
frame_h = tab_frame_h_text;
handle_hpad = tab_handle_hpad_text;
handle_top_pad = tab_handle_top_pad_text;
}
geom->handle_area.p0.x = tab->tabset->rect.p0.x + tab->xoff;
geom->handle_area.p0.y = tab->tabset->rect.p0.y;
geom->handle_area.p1.x = geom->handle_area.p0.x + handle_w;
geom->handle_area.p1.y = geom->handle_area.p0.y + handle_h + pullup;
geom->handle = geom->handle_area;
if (!ui_tab_is_selected(tab)) {
geom->handle.p0.y += pullup;
geom->handle_area.p1.y -= pullup;
}
geom->text_pos.x = geom->handle.p0.x + frame_w + handle_hpad;
geom->text_pos.y = geom->handle.p0.y + frame_h + handle_top_pad;
geom->body.p0.x = tab->tabset->rect.p0.x;
geom->body.p0.y = tab->tabset->rect.p0.y + handle_h - frame_h +
pullup;
geom->body.p1 = tab->tabset->rect.p1;
}
ui_resource_t *ui_tab_get_res(ui_tab_t *tab)
{
return tab->tabset->res;
}
errno_t ui_tab_paint_handle_frame(gfx_context_t *gc, gfx_rect_t *rect,
gfx_coord_t chamfer, gfx_color_t *hi_color, gfx_color_t *sh_color,
bool selected, gfx_rect_t *irect)
{
gfx_rect_t r;
gfx_coord_t i;
errno_t rc;
rc = gfx_set_color(gc, hi_color);
if (rc != EOK)
goto error;
r.p0.x = rect->p0.x;
r.p0.y = rect->p0.y + chamfer;
r.p1.x = rect->p0.x + 1;
r.p1.y = rect->p1.y - 2;
rc = gfx_fill_rect(gc, &r);
if (rc != EOK)
goto error;
for (i = 1; i < chamfer; i++) {
r.p0.x = rect->p0.x + i;
r.p0.y = rect->p0.y + chamfer - i;
r.p1.x = r.p0.x + 1;
r.p1.y = r.p0.y + 1;
rc = gfx_fill_rect(gc, &r);
if (rc != EOK)
goto error;
}
r.p0.x = rect->p0.x + chamfer;
r.p0.y = rect->p0.y;
r.p1.x = rect->p1.x - chamfer;
r.p1.y = rect->p0.y + 1;
rc = gfx_fill_rect(gc, &r);
if (rc != EOK)
goto error;
rc = gfx_set_color(gc, sh_color);
if (rc != EOK)
goto error;
for (i = 1; i < chamfer; i++) {
r.p0.x = rect->p1.x - 1 - i;
r.p0.y = rect->p0.y + chamfer - i;
r.p1.x = r.p0.x + 1;
r.p1.y = r.p0.y + 1;
rc = gfx_fill_rect(gc, &r);
if (rc != EOK)
goto error;
}
r.p0.x = rect->p1.x - 1;
r.p0.y = rect->p0.y + chamfer;
r.p1.x = rect->p1.x;
r.p1.y = rect->p1.y - 2;
rc = gfx_fill_rect(gc, &r);
if (rc != EOK)
goto error;
irect->p0.x = rect->p0.x + 1;
irect->p0.y = rect->p0.y + 1;
irect->p1.x = rect->p1.x - 1;
irect->p1.y = rect->p1.y;
return EOK;
error:
return rc;
}
errno_t ui_tab_paint_body_frame(ui_tab_t *tab)
{
gfx_rect_t bg_rect;
ui_tab_geom_t geom;
ui_resource_t *res;
errno_t rc;
res = ui_tab_get_res(tab);
ui_tab_get_geom(tab, &geom);
if (!res->textmode) {
rc = ui_paint_outset_frame(res, &geom.body, &bg_rect);
if (rc != EOK)
goto error;
} else {
rc = ui_paint_text_box(res, &geom.body, ui_box_single,
res->wnd_face_color);
if (rc != EOK)
goto error;
bg_rect.p0.x = geom.body.p0.x + 1;
bg_rect.p0.y = geom.body.p0.y + 1;
bg_rect.p1.x = geom.body.p1.x - 1;
bg_rect.p1.y = geom.body.p1.y - 1;
}
rc = gfx_set_color(res->gc, res->wnd_face_color);
if (rc != EOK)
goto error;
rc = gfx_fill_rect(res->gc, &bg_rect);
if (rc != EOK)
goto error;
return EOK;
error:
return rc;
}
errno_t ui_tab_paint_frame(ui_tab_t *tab)
{
gfx_rect_t r0;
ui_tab_geom_t geom;
ui_resource_t *res;
errno_t rc;
res = ui_tab_get_res(tab);
ui_tab_get_geom(tab, &geom);
rc = gfx_set_color(res->gc, res->wnd_face_color);
if (rc != EOK)
goto error;
rc = gfx_fill_rect(res->gc, &geom.handle_area);
if (rc != EOK)
goto error;
if (!res->textmode) {
rc = ui_tab_paint_handle_frame(res->gc, &geom.handle,
tab_handle_chamfer, res->wnd_frame_hi_color, res->wnd_frame_sh_color,
ui_tab_is_selected(tab), &r0);
if (rc != EOK)
goto error;
rc = ui_tab_paint_handle_frame(res->gc, &r0, tab_handle_chamfer - 1,
res->wnd_highlight_color, res->wnd_shadow_color,
ui_tab_is_selected(tab), &r0);
if (rc != EOK)
goto error;
} else {
rc = ui_paint_text_box_custom(res, &geom.handle,
ui_tab_is_selected(tab) ? &sel_tab_box_chars :
&unsel_tab_box_chars, res->wnd_face_color);
if (rc != EOK)
goto error;
}
return EOK;
error:
return rc;
}
errno_t ui_tab_paint(ui_tab_t *tab)
{
gfx_text_fmt_t fmt;
ui_tab_geom_t geom;
ui_resource_t *res;
errno_t rc;
res = ui_tab_get_res(tab);
ui_tab_get_geom(tab, &geom);
rc = ui_tab_paint_frame(tab);
if (rc != EOK)
goto error;
gfx_text_fmt_init(&fmt);
fmt.font = res->font;
fmt.halign = gfx_halign_left;
fmt.valign = gfx_valign_top;
fmt.color = res->wnd_text_color;
rc = gfx_puttext(&geom.text_pos, &fmt, tab->caption);
if (rc != EOK)
goto error;
if (tab->content != NULL && ui_tab_is_selected(tab)) {
rc = ui_control_paint(tab->content);
if (rc != EOK)
goto error;
}
rc = gfx_update(res->gc);
if (rc != EOK)
goto error;
return EOK;
error:
return rc;
}
ui_evclaim_t ui_tab_pos_event(ui_tab_t *tab, pos_event_t *event)
{
ui_tab_geom_t geom;
gfx_coord2_t epos;
ui_tab_get_geom(tab, &geom);
epos.x = event->hpos;
epos.y = event->vpos;
if (gfx_pix_inside_rect(&epos, &geom.handle)) {
if (event->type == POS_PRESS && event->btn_num == 1 &&
!ui_tab_is_selected(tab))
ui_tab_set_select(tab->tabset, tab);
return ui_claimed;
}
if (ui_tab_is_selected(tab) && tab->content != NULL)
return ui_control_pos_event(tab->content, event);
return ui_unclaimed;
}
ui_evclaim_t ui_tab_kbd_event(ui_tab_t *tab, kbd_event_t *event)
{
if (ui_tab_is_selected(tab) && tab->content != NULL)
return ui_control_kbd_event(tab->content, event);
return ui_unclaimed;
}
HelenOS homepage, sources at GitHub