[1eaead4] | 1 | /*
|
---|
| 2 | * Copyright (c) 2023 Jiri Svoboda
|
---|
| 3 | * All rights reserved.
|
---|
| 4 | *
|
---|
| 5 | * Redistribution and use in source and binary forms, with or without
|
---|
| 6 | * modification, are permitted provided that the following conditions
|
---|
| 7 | * are met:
|
---|
| 8 | *
|
---|
| 9 | * - Redistributions of source code must retain the above copyright
|
---|
| 10 | * notice, this list of conditions and the following disclaimer.
|
---|
| 11 | * - Redistributions in binary form must reproduce the above copyright
|
---|
| 12 | * notice, this list of conditions and the following disclaimer in the
|
---|
| 13 | * documentation and/or other materials provided with the distribution.
|
---|
| 14 | * - The name of the author may not be used to endorse or promote products
|
---|
| 15 | * derived from this software without specific prior written permission.
|
---|
| 16 | *
|
---|
| 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
---|
| 18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
---|
| 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
---|
| 20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
---|
| 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
---|
| 22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
---|
| 23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
---|
| 24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
---|
| 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
---|
| 26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
| 27 | */
|
---|
| 28 |
|
---|
| 29 | /** @addtogroup libui
|
---|
| 30 | * @{
|
---|
| 31 | */
|
---|
| 32 | /**
|
---|
| 33 | * @file Tab
|
---|
| 34 | */
|
---|
| 35 |
|
---|
| 36 | #include <adt/list.h>
|
---|
| 37 | #include <errno.h>
|
---|
| 38 | #include <gfx/color.h>
|
---|
| 39 | #include <gfx/context.h>
|
---|
| 40 | #include <gfx/render.h>
|
---|
| 41 | #include <gfx/text.h>
|
---|
| 42 | #include <io/pos_event.h>
|
---|
| 43 | #include <stdlib.h>
|
---|
| 44 | #include <str.h>
|
---|
| 45 | #include <uchar.h>
|
---|
| 46 | #include <ui/control.h>
|
---|
| 47 | #include <ui/paint.h>
|
---|
| 48 | #include <ui/popup.h>
|
---|
| 49 | #include <ui/tab.h>
|
---|
| 50 | #include <ui/tabset.h>
|
---|
| 51 | #include <ui/resource.h>
|
---|
| 52 | #include <ui/window.h>
|
---|
| 53 | #include "../private/control.h"
|
---|
| 54 | #include "../private/tab.h"
|
---|
| 55 | #include "../private/tabset.h"
|
---|
| 56 | #include "../private/resource.h"
|
---|
| 57 |
|
---|
| 58 | enum {
|
---|
| 59 | /** Horizontal margin before first tab handle */
|
---|
| 60 | tab_start_hmargin = 6,
|
---|
| 61 | /** Horizontal margin before first tab handle in text mode */
|
---|
| 62 | tab_start_hmargin_text = 1,
|
---|
| 63 | /** Tab handle horizontal internal padding */
|
---|
| 64 | tab_handle_hpad = 6,
|
---|
| 65 | /** Tab handle top internal padding */
|
---|
| 66 | tab_handle_top_pad = 5,
|
---|
| 67 | /** Tab handle bottom internal padding */
|
---|
| 68 | tab_handle_bottom_pad = 5,
|
---|
| 69 | /** Tab handle horizontal internal padding in text mode */
|
---|
| 70 | tab_handle_hpad_text = 1,
|
---|
| 71 | /** Tab handle top internal padding in text mode */
|
---|
| 72 | tab_handle_top_pad_text = 0,
|
---|
| 73 | /** Tab handle bototm internal padding in text mode */
|
---|
| 74 | tab_handle_bottom_pad_text = 1,
|
---|
| 75 | /** Tab handle chamfer */
|
---|
| 76 | tab_handle_chamfer = 3,
|
---|
| 77 | /** Number of pixels to pull active handle up by */
|
---|
| 78 | tab_handle_pullup = 2,
|
---|
| 79 | /** Tab frame horizontal thickness */
|
---|
| 80 | tab_frame_w = 2,
|
---|
| 81 | /** Tab frame vertical thickness */
|
---|
| 82 | tab_frame_h = 2,
|
---|
| 83 | /** Tab frame horizontal thickness in text mode */
|
---|
| 84 | tab_frame_w_text = 1,
|
---|
| 85 | /** Tab frame horizontal thickness in text mode */
|
---|
| 86 | tab_frame_h_text = 1
|
---|
| 87 | };
|
---|
| 88 |
|
---|
| 89 | /** Selected tab handle box characters */
|
---|
| 90 | static ui_box_chars_t sel_tab_box_chars = {
|
---|
| 91 | {
|
---|
| 92 | { "\u250c", "\u2500", "\u2510" },
|
---|
| 93 | { "\u2502", " ", "\u2502" },
|
---|
| 94 | { "\u2518", " ", "\u2514" }
|
---|
| 95 | }
|
---|
| 96 | };
|
---|
| 97 |
|
---|
| 98 | /** Not selected tab handle box characters */
|
---|
| 99 | static ui_box_chars_t unsel_tab_box_chars = {
|
---|
| 100 | {
|
---|
| 101 | { "\u250c", "\u2500", "\u2510" },
|
---|
| 102 | { "\u2502", " ", "\u2502" },
|
---|
| 103 | { "\u2534", "\u2500", "\u2534" }
|
---|
| 104 | }
|
---|
| 105 | };
|
---|
| 106 |
|
---|
| 107 | /** Create new tab.
|
---|
| 108 | *
|
---|
| 109 | * @param tabset Tab set
|
---|
| 110 | * @param caption Caption
|
---|
| 111 | * @param rtab Place to store pointer to new tab
|
---|
| 112 | * @return EOK on success, ENOMEM if out of memory
|
---|
| 113 | */
|
---|
| 114 | errno_t ui_tab_create(ui_tab_set_t *tabset, const char *caption,
|
---|
| 115 | ui_tab_t **rtab)
|
---|
| 116 | {
|
---|
| 117 | ui_tab_t *tab;
|
---|
| 118 | ui_tab_t *prev;
|
---|
| 119 |
|
---|
| 120 | tab = calloc(1, sizeof(ui_tab_t));
|
---|
| 121 | if (tab == NULL)
|
---|
| 122 | return ENOMEM;
|
---|
| 123 |
|
---|
| 124 | tab->caption = str_dup(caption);
|
---|
| 125 | if (tab->caption == NULL) {
|
---|
| 126 | free(tab);
|
---|
| 127 | return ENOMEM;
|
---|
| 128 | }
|
---|
| 129 |
|
---|
| 130 | prev = ui_tab_last(tabset);
|
---|
| 131 | if (prev != NULL)
|
---|
| 132 | tab->xoff = prev->xoff + ui_tab_handle_width(prev);
|
---|
| 133 | else
|
---|
| 134 | tab->xoff = tabset->res->textmode ?
|
---|
| 135 | tab_start_hmargin_text : tab_start_hmargin;
|
---|
| 136 |
|
---|
| 137 | tab->tabset = tabset;
|
---|
| 138 | list_append(&tab->ltabs, &tabset->tabs);
|
---|
| 139 |
|
---|
| 140 | /* This is the first tab. Select it. */
|
---|
| 141 | if (tabset->selected == NULL)
|
---|
| 142 | tabset->selected = tab;
|
---|
| 143 |
|
---|
| 144 | *rtab = tab;
|
---|
| 145 | return EOK;
|
---|
| 146 | }
|
---|
| 147 |
|
---|
| 148 | /** Destroy tab.
|
---|
| 149 | *
|
---|
| 150 | * @param tab Tab or @c NULL
|
---|
| 151 | */
|
---|
| 152 | void ui_tab_destroy(ui_tab_t *tab)
|
---|
| 153 | {
|
---|
| 154 | if (tab == NULL)
|
---|
| 155 | return;
|
---|
| 156 |
|
---|
| 157 | /* Destroy content */
|
---|
| 158 | ui_control_destroy(tab->content);
|
---|
| 159 |
|
---|
| 160 | list_remove(&tab->ltabs);
|
---|
| 161 | free(tab->caption);
|
---|
| 162 | free(tab);
|
---|
| 163 | }
|
---|
| 164 |
|
---|
| 165 | /** Get first tab in tab bar.
|
---|
| 166 | *
|
---|
| 167 | * @param tabset Tab set
|
---|
| 168 | * @return First tab or @c NULL if there is none
|
---|
| 169 | */
|
---|
| 170 | ui_tab_t *ui_tab_first(ui_tab_set_t *tabset)
|
---|
| 171 | {
|
---|
| 172 | link_t *link;
|
---|
| 173 |
|
---|
| 174 | link = list_first(&tabset->tabs);
|
---|
| 175 | if (link == NULL)
|
---|
| 176 | return NULL;
|
---|
| 177 |
|
---|
| 178 | return list_get_instance(link, ui_tab_t, ltabs);
|
---|
| 179 | }
|
---|
| 180 |
|
---|
| 181 | /** Get next tab in tab bar.
|
---|
| 182 | *
|
---|
| 183 | * @param cur Current tab
|
---|
| 184 | * @return Next tab or @c NULL if @a cur is the last one
|
---|
| 185 | */
|
---|
| 186 | ui_tab_t *ui_tab_next(ui_tab_t *cur)
|
---|
| 187 | {
|
---|
| 188 | link_t *link;
|
---|
| 189 |
|
---|
| 190 | link = list_next(&cur->ltabs, &cur->tabset->tabs);
|
---|
| 191 | if (link == NULL)
|
---|
| 192 | return NULL;
|
---|
| 193 |
|
---|
| 194 | return list_get_instance(link, ui_tab_t, ltabs);
|
---|
| 195 | }
|
---|
| 196 |
|
---|
| 197 | /** Get last tab in tab bar.
|
---|
| 198 | *
|
---|
| 199 | * @param tabset Tab set
|
---|
| 200 | * @return Last tab or @c NULL if there is none
|
---|
| 201 | */
|
---|
| 202 | ui_tab_t *ui_tab_last(ui_tab_set_t *tabset)
|
---|
| 203 | {
|
---|
| 204 | link_t *link;
|
---|
| 205 |
|
---|
| 206 | link = list_last(&tabset->tabs);
|
---|
| 207 | if (link == NULL)
|
---|
| 208 | return NULL;
|
---|
| 209 |
|
---|
| 210 | return list_get_instance(link, ui_tab_t, ltabs);
|
---|
| 211 | }
|
---|
| 212 |
|
---|
| 213 | /** Get previous tab in tab bar.
|
---|
| 214 | *
|
---|
| 215 | * @param cur Current tab
|
---|
| 216 | * @return Previous tab or @c NULL if @a cur is the fist one
|
---|
| 217 | */
|
---|
| 218 | ui_tab_t *ui_tab_prev(ui_tab_t *cur)
|
---|
| 219 | {
|
---|
| 220 | link_t *link;
|
---|
| 221 |
|
---|
| 222 | link = list_prev(&cur->ltabs, &cur->tabset->tabs);
|
---|
| 223 | if (link == NULL)
|
---|
| 224 | return NULL;
|
---|
| 225 |
|
---|
| 226 | return list_get_instance(link, ui_tab_t, ltabs);
|
---|
| 227 | }
|
---|
| 228 |
|
---|
| 229 | /** Determine if tab is selected.
|
---|
| 230 | *
|
---|
| 231 | * @param tab Tab
|
---|
| 232 | * @return @c true iff tab is selected
|
---|
| 233 | */
|
---|
| 234 | bool ui_tab_is_selected(ui_tab_t *tab)
|
---|
| 235 | {
|
---|
| 236 | return tab->tabset->selected == tab;
|
---|
| 237 | }
|
---|
| 238 |
|
---|
| 239 | /** Add control to tab.
|
---|
| 240 | *
|
---|
| 241 | * Only one control can be added to a window. If more than one control
|
---|
| 242 | * is added, the results are undefined.
|
---|
| 243 | *
|
---|
| 244 | * @param tab Tab
|
---|
| 245 | * @param control Control
|
---|
| 246 | */
|
---|
| 247 | void ui_tab_add(ui_tab_t *tab, ui_control_t *control)
|
---|
| 248 | {
|
---|
| 249 | assert(tab->content == NULL);
|
---|
| 250 |
|
---|
| 251 | tab->content = control;
|
---|
| 252 | control->elemp = (void *) tab;
|
---|
| 253 | }
|
---|
| 254 |
|
---|
| 255 | /** Remove control from tab.
|
---|
| 256 | *
|
---|
| 257 | * @param tab Tab
|
---|
| 258 | * @param control Control
|
---|
| 259 | */
|
---|
| 260 | void ui_tab_remove(ui_tab_t *tab, ui_control_t *control)
|
---|
| 261 | {
|
---|
| 262 | assert(tab->content == control);
|
---|
| 263 | assert((ui_tab_t *) control->elemp == tab);
|
---|
| 264 |
|
---|
| 265 | tab->content = NULL;
|
---|
| 266 | control->elemp = NULL;
|
---|
| 267 | }
|
---|
| 268 |
|
---|
| 269 | /** Get tab handle width.
|
---|
| 270 | *
|
---|
| 271 | * @param tab Tab
|
---|
| 272 | * @return Handle width in pixels
|
---|
| 273 | */
|
---|
| 274 | gfx_coord_t ui_tab_handle_width(ui_tab_t *tab)
|
---|
| 275 | {
|
---|
| 276 | ui_resource_t *res;
|
---|
| 277 | gfx_coord_t frame_w;
|
---|
| 278 | gfx_coord_t handle_hpad;
|
---|
| 279 | gfx_coord_t text_w;
|
---|
| 280 |
|
---|
| 281 | res = tab->tabset->res;
|
---|
| 282 | if (!res->textmode) {
|
---|
| 283 | frame_w = tab_frame_w;
|
---|
| 284 | handle_hpad = tab_handle_hpad;
|
---|
| 285 | } else {
|
---|
| 286 | frame_w = tab_frame_w_text;
|
---|
| 287 | handle_hpad = tab_handle_hpad_text;
|
---|
| 288 | }
|
---|
| 289 |
|
---|
| 290 | text_w = ui_text_width(tab->tabset->res->font, tab->caption);
|
---|
| 291 | return 2 * frame_w + 2 * handle_hpad + text_w;
|
---|
| 292 | }
|
---|
| 293 |
|
---|
| 294 | /** Get tab handle height.
|
---|
| 295 | *
|
---|
| 296 | * @param tab Tab
|
---|
| 297 | * @return Handle height in pixels
|
---|
| 298 | */
|
---|
| 299 | gfx_coord_t ui_tab_handle_height(ui_tab_t *tab)
|
---|
| 300 | {
|
---|
| 301 | gfx_coord_t frame_h;
|
---|
| 302 | gfx_coord_t handle_top_pad;
|
---|
| 303 | gfx_coord_t handle_bottom_pad;
|
---|
| 304 | gfx_font_metrics_t metrics;
|
---|
| 305 | ui_resource_t *res;
|
---|
| 306 |
|
---|
| 307 | res = tab->tabset->res;
|
---|
| 308 | gfx_font_get_metrics(tab->tabset->res->font, &metrics);
|
---|
| 309 |
|
---|
| 310 | if (!res->textmode) {
|
---|
| 311 | frame_h = tab_frame_h;
|
---|
| 312 | handle_top_pad = tab_handle_top_pad;
|
---|
| 313 | handle_bottom_pad = tab_handle_bottom_pad;
|
---|
| 314 | } else {
|
---|
| 315 | frame_h = tab_frame_h_text;
|
---|
| 316 | handle_top_pad = tab_handle_top_pad_text;
|
---|
| 317 | handle_bottom_pad = tab_handle_bottom_pad_text;
|
---|
| 318 | }
|
---|
| 319 |
|
---|
| 320 | return frame_h + handle_top_pad + metrics.ascent +
|
---|
| 321 | metrics.descent + 1 + handle_bottom_pad;
|
---|
| 322 | }
|
---|
| 323 |
|
---|
| 324 | /** Get tab geometry.
|
---|
| 325 | *
|
---|
| 326 | * @param tab Tab
|
---|
| 327 | * @param geom Structure to fill in with computed geometry
|
---|
| 328 | */
|
---|
| 329 | void ui_tab_get_geom(ui_tab_t *tab, ui_tab_geom_t *geom)
|
---|
| 330 | {
|
---|
| 331 | gfx_coord_t handle_w;
|
---|
| 332 | gfx_coord_t handle_h;
|
---|
| 333 | gfx_coord_t pullup;
|
---|
| 334 | gfx_coord_t frame_w;
|
---|
| 335 | gfx_coord_t frame_h;
|
---|
| 336 | gfx_coord_t handle_hpad;
|
---|
| 337 | gfx_coord_t handle_top_pad;
|
---|
| 338 | ui_resource_t *res;
|
---|
| 339 |
|
---|
| 340 | res = tab->tabset->res;
|
---|
| 341 |
|
---|
| 342 | handle_w = ui_tab_handle_width(tab);
|
---|
| 343 | handle_h = ui_tab_handle_height(tab);
|
---|
| 344 | pullup = res->textmode ? 0 : tab_handle_pullup;
|
---|
| 345 |
|
---|
| 346 | if (!res->textmode) {
|
---|
| 347 | frame_w = tab_frame_w;
|
---|
| 348 | frame_h = tab_frame_h;
|
---|
| 349 | handle_hpad = tab_handle_hpad;
|
---|
| 350 | handle_top_pad = tab_handle_top_pad;
|
---|
| 351 | } else {
|
---|
| 352 | frame_w = tab_frame_w_text;
|
---|
| 353 | frame_h = tab_frame_h_text;
|
---|
| 354 | handle_hpad = tab_handle_hpad_text;
|
---|
| 355 | handle_top_pad = tab_handle_top_pad_text;
|
---|
| 356 | }
|
---|
| 357 |
|
---|
| 358 | /* Entire handle area */
|
---|
| 359 | geom->handle_area.p0.x = tab->tabset->rect.p0.x + tab->xoff;
|
---|
| 360 | geom->handle_area.p0.y = tab->tabset->rect.p0.y;
|
---|
| 361 | geom->handle_area.p1.x = geom->handle_area.p0.x + handle_w;
|
---|
| 362 | geom->handle_area.p1.y = geom->handle_area.p0.y + handle_h + pullup;
|
---|
| 363 |
|
---|
| 364 | geom->handle = geom->handle_area;
|
---|
| 365 |
|
---|
| 366 | /* If handle is selected */
|
---|
| 367 | if (!ui_tab_is_selected(tab)) {
|
---|
| 368 | /* Push top of handle down a bit */
|
---|
| 369 | geom->handle.p0.y += pullup;
|
---|
| 370 | /* Do not paint background over tab body frame */
|
---|
| 371 | geom->handle_area.p1.y -= pullup;
|
---|
| 372 | }
|
---|
| 373 |
|
---|
| 374 | /* Caption text position */
|
---|
| 375 | geom->text_pos.x = geom->handle.p0.x + frame_w + handle_hpad;
|
---|
| 376 | geom->text_pos.y = geom->handle.p0.y + frame_h + handle_top_pad;
|
---|
| 377 |
|
---|
| 378 | /* Tab body */
|
---|
| 379 | geom->body.p0.x = tab->tabset->rect.p0.x;
|
---|
| 380 | geom->body.p0.y = tab->tabset->rect.p0.y + handle_h - frame_h +
|
---|
| 381 | pullup;
|
---|
| 382 | geom->body.p1 = tab->tabset->rect.p1;
|
---|
| 383 | }
|
---|
| 384 |
|
---|
| 385 | /** Get UI resource from tab.
|
---|
| 386 | *
|
---|
| 387 | * @param tab Tab
|
---|
| 388 | * @return UI resource
|
---|
| 389 | */
|
---|
| 390 | ui_resource_t *ui_tab_get_res(ui_tab_t *tab)
|
---|
| 391 | {
|
---|
| 392 | return tab->tabset->res;
|
---|
| 393 | }
|
---|
| 394 |
|
---|
| 395 | /** Paint tab handle frame.
|
---|
| 396 | *
|
---|
| 397 | * @param gc Graphic context
|
---|
| 398 | * @param rect Rectangle
|
---|
| 399 | * @param chamfer Chamfer
|
---|
| 400 | * @param hi_color Highlight color
|
---|
| 401 | * @param sh_color Shadow color
|
---|
| 402 | * @param selected Tab is selected
|
---|
| 403 | * @param irect Place to store interior rectangle
|
---|
| 404 | * @return EOK on success or an error code
|
---|
| 405 | */
|
---|
| 406 | errno_t ui_tab_paint_handle_frame(gfx_context_t *gc, gfx_rect_t *rect,
|
---|
| 407 | gfx_coord_t chamfer, gfx_color_t *hi_color, gfx_color_t *sh_color,
|
---|
| 408 | bool selected, gfx_rect_t *irect)
|
---|
| 409 | {
|
---|
| 410 | gfx_rect_t r;
|
---|
| 411 | gfx_coord_t i;
|
---|
| 412 | errno_t rc;
|
---|
| 413 |
|
---|
| 414 | rc = gfx_set_color(gc, hi_color);
|
---|
| 415 | if (rc != EOK)
|
---|
| 416 | goto error;
|
---|
| 417 |
|
---|
| 418 | /* Left side */
|
---|
| 419 | r.p0.x = rect->p0.x;
|
---|
| 420 | r.p0.y = rect->p0.y + chamfer;
|
---|
| 421 | r.p1.x = rect->p0.x + 1;
|
---|
| 422 | r.p1.y = rect->p1.y - 2;
|
---|
| 423 | rc = gfx_fill_rect(gc, &r);
|
---|
| 424 | if (rc != EOK)
|
---|
| 425 | goto error;
|
---|
| 426 |
|
---|
| 427 | /* Top-left chamfer */
|
---|
| 428 | for (i = 1; i < chamfer; i++) {
|
---|
| 429 | r.p0.x = rect->p0.x + i;
|
---|
| 430 | r.p0.y = rect->p0.y + chamfer - i;
|
---|
| 431 | r.p1.x = r.p0.x + 1;
|
---|
| 432 | r.p1.y = r.p0.y + 1;
|
---|
| 433 | rc = gfx_fill_rect(gc, &r);
|
---|
| 434 | if (rc != EOK)
|
---|
| 435 | goto error;
|
---|
| 436 | }
|
---|
| 437 |
|
---|
| 438 | /* Top side */
|
---|
| 439 | r.p0.x = rect->p0.x + chamfer;
|
---|
| 440 | r.p0.y = rect->p0.y;
|
---|
| 441 | r.p1.x = rect->p1.x - chamfer;
|
---|
| 442 | r.p1.y = rect->p0.y + 1;
|
---|
| 443 | rc = gfx_fill_rect(gc, &r);
|
---|
| 444 | if (rc != EOK)
|
---|
| 445 | goto error;
|
---|
| 446 |
|
---|
| 447 | rc = gfx_set_color(gc, sh_color);
|
---|
| 448 | if (rc != EOK)
|
---|
| 449 | goto error;
|
---|
| 450 |
|
---|
| 451 | /* Top-right chamfer */
|
---|
| 452 | for (i = 1; i < chamfer; i++) {
|
---|
| 453 | r.p0.x = rect->p1.x - 1 - i;
|
---|
| 454 | r.p0.y = rect->p0.y + chamfer - i;
|
---|
| 455 | r.p1.x = r.p0.x + 1;
|
---|
| 456 | r.p1.y = r.p0.y + 1;
|
---|
| 457 | rc = gfx_fill_rect(gc, &r);
|
---|
| 458 | if (rc != EOK)
|
---|
| 459 | goto error;
|
---|
| 460 | }
|
---|
| 461 |
|
---|
| 462 | /* Right side */
|
---|
| 463 | r.p0.x = rect->p1.x - 1;
|
---|
| 464 | r.p0.y = rect->p0.y + chamfer;
|
---|
| 465 | r.p1.x = rect->p1.x;
|
---|
| 466 | r.p1.y = rect->p1.y - 2;
|
---|
| 467 | rc = gfx_fill_rect(gc, &r);
|
---|
| 468 | if (rc != EOK)
|
---|
| 469 | goto error;
|
---|
| 470 |
|
---|
| 471 | irect->p0.x = rect->p0.x + 1;
|
---|
| 472 | irect->p0.y = rect->p0.y + 1;
|
---|
| 473 | irect->p1.x = rect->p1.x - 1;
|
---|
| 474 | irect->p1.y = rect->p1.y;
|
---|
| 475 | return EOK;
|
---|
| 476 | error:
|
---|
| 477 | return rc;
|
---|
| 478 | }
|
---|
| 479 |
|
---|
| 480 | /** Paint tab body frame.
|
---|
| 481 | *
|
---|
| 482 | * @param tab Tab
|
---|
| 483 | * @return EOK on success or an error code
|
---|
| 484 | */
|
---|
| 485 | errno_t ui_tab_paint_body_frame(ui_tab_t *tab)
|
---|
| 486 | {
|
---|
| 487 | gfx_rect_t bg_rect;
|
---|
| 488 | ui_tab_geom_t geom;
|
---|
| 489 | ui_resource_t *res;
|
---|
| 490 | errno_t rc;
|
---|
| 491 |
|
---|
| 492 | res = ui_tab_get_res(tab);
|
---|
| 493 | ui_tab_get_geom(tab, &geom);
|
---|
| 494 |
|
---|
| 495 | if (!res->textmode) {
|
---|
| 496 | rc = ui_paint_outset_frame(res, &geom.body, &bg_rect);
|
---|
| 497 | if (rc != EOK)
|
---|
| 498 | goto error;
|
---|
| 499 | } else {
|
---|
| 500 | rc = ui_paint_text_box(res, &geom.body, ui_box_single,
|
---|
| 501 | res->wnd_face_color);
|
---|
| 502 | if (rc != EOK)
|
---|
| 503 | goto error;
|
---|
| 504 |
|
---|
| 505 | bg_rect.p0.x = geom.body.p0.x + 1;
|
---|
| 506 | bg_rect.p0.y = geom.body.p0.y + 1;
|
---|
| 507 | bg_rect.p1.x = geom.body.p1.x - 1;
|
---|
| 508 | bg_rect.p1.y = geom.body.p1.y - 1;
|
---|
| 509 | }
|
---|
| 510 |
|
---|
| 511 | rc = gfx_set_color(res->gc, res->wnd_face_color);
|
---|
| 512 | if (rc != EOK)
|
---|
| 513 | goto error;
|
---|
| 514 |
|
---|
| 515 | rc = gfx_fill_rect(res->gc, &bg_rect);
|
---|
| 516 | if (rc != EOK)
|
---|
| 517 | goto error;
|
---|
| 518 |
|
---|
| 519 | return EOK;
|
---|
| 520 | error:
|
---|
| 521 | return rc;
|
---|
| 522 | }
|
---|
| 523 |
|
---|
| 524 | /** Paint tab frame.
|
---|
| 525 | *
|
---|
| 526 | * @param tab Tab
|
---|
| 527 | * @return EOK on success or an error code
|
---|
| 528 | */
|
---|
| 529 | errno_t ui_tab_paint_frame(ui_tab_t *tab)
|
---|
| 530 | {
|
---|
| 531 | gfx_rect_t r0;
|
---|
| 532 | ui_tab_geom_t geom;
|
---|
| 533 | ui_resource_t *res;
|
---|
| 534 | errno_t rc;
|
---|
| 535 |
|
---|
| 536 | res = ui_tab_get_res(tab);
|
---|
| 537 | ui_tab_get_geom(tab, &geom);
|
---|
| 538 |
|
---|
| 539 | /* Paint handle background */
|
---|
| 540 |
|
---|
| 541 | rc = gfx_set_color(res->gc, res->wnd_face_color);
|
---|
| 542 | if (rc != EOK)
|
---|
| 543 | goto error;
|
---|
| 544 |
|
---|
| 545 | rc = gfx_fill_rect(res->gc, &geom.handle_area);
|
---|
| 546 | if (rc != EOK)
|
---|
| 547 | goto error;
|
---|
| 548 |
|
---|
| 549 | /* Paint handle frame */
|
---|
| 550 | if (!res->textmode) {
|
---|
| 551 | rc = ui_tab_paint_handle_frame(res->gc, &geom.handle,
|
---|
| 552 | tab_handle_chamfer, res->wnd_frame_hi_color, res->wnd_frame_sh_color,
|
---|
| 553 | ui_tab_is_selected(tab), &r0);
|
---|
| 554 | if (rc != EOK)
|
---|
| 555 | goto error;
|
---|
| 556 |
|
---|
| 557 | rc = ui_tab_paint_handle_frame(res->gc, &r0, tab_handle_chamfer - 1,
|
---|
| 558 | res->wnd_highlight_color, res->wnd_shadow_color,
|
---|
| 559 | ui_tab_is_selected(tab), &r0);
|
---|
| 560 | if (rc != EOK)
|
---|
| 561 | goto error;
|
---|
| 562 | } else {
|
---|
| 563 | rc = ui_paint_text_box_custom(res, &geom.handle,
|
---|
| 564 | ui_tab_is_selected(tab) ? &sel_tab_box_chars :
|
---|
| 565 | &unsel_tab_box_chars, res->wnd_face_color);
|
---|
| 566 | if (rc != EOK)
|
---|
| 567 | goto error;
|
---|
| 568 | }
|
---|
| 569 |
|
---|
| 570 | return EOK;
|
---|
| 571 | error:
|
---|
| 572 | return rc;
|
---|
| 573 | }
|
---|
| 574 |
|
---|
| 575 | /** Paint tab.
|
---|
| 576 | *
|
---|
| 577 | * @param tab Tab
|
---|
| 578 | * @return EOK on success or an error code
|
---|
| 579 | */
|
---|
| 580 | errno_t ui_tab_paint(ui_tab_t *tab)
|
---|
| 581 | {
|
---|
| 582 | gfx_text_fmt_t fmt;
|
---|
| 583 | ui_tab_geom_t geom;
|
---|
| 584 | ui_resource_t *res;
|
---|
| 585 | errno_t rc;
|
---|
| 586 |
|
---|
| 587 | res = ui_tab_get_res(tab);
|
---|
| 588 | ui_tab_get_geom(tab, &geom);
|
---|
| 589 |
|
---|
| 590 | rc = ui_tab_paint_frame(tab);
|
---|
| 591 | if (rc != EOK)
|
---|
| 592 | goto error;
|
---|
| 593 |
|
---|
| 594 | /* Paint caption */
|
---|
| 595 |
|
---|
| 596 | gfx_text_fmt_init(&fmt);
|
---|
| 597 | fmt.font = res->font;
|
---|
| 598 | fmt.halign = gfx_halign_left;
|
---|
| 599 | fmt.valign = gfx_valign_top;
|
---|
| 600 | fmt.color = res->wnd_text_color;
|
---|
| 601 |
|
---|
| 602 | rc = gfx_puttext(&geom.text_pos, &fmt, tab->caption);
|
---|
| 603 | if (rc != EOK)
|
---|
| 604 | goto error;
|
---|
| 605 |
|
---|
| 606 | if (tab->content != NULL && ui_tab_is_selected(tab)) {
|
---|
| 607 | /* Paint content */
|
---|
| 608 | rc = ui_control_paint(tab->content);
|
---|
| 609 | if (rc != EOK)
|
---|
| 610 | goto error;
|
---|
| 611 | }
|
---|
| 612 |
|
---|
| 613 | rc = gfx_update(res->gc);
|
---|
| 614 | if (rc != EOK)
|
---|
| 615 | goto error;
|
---|
| 616 |
|
---|
| 617 | return EOK;
|
---|
| 618 | error:
|
---|
| 619 | return rc;
|
---|
| 620 | }
|
---|
| 621 |
|
---|
| 622 | /** Handle position event in tab.
|
---|
| 623 | *
|
---|
| 624 | * @param tab Tab
|
---|
| 625 | * @param event Position event
|
---|
| 626 | * @return ui_claimed iff the event was claimed
|
---|
| 627 | */
|
---|
| 628 | ui_evclaim_t ui_tab_pos_event(ui_tab_t *tab, pos_event_t *event)
|
---|
| 629 | {
|
---|
| 630 | ui_tab_geom_t geom;
|
---|
| 631 | gfx_coord2_t epos;
|
---|
| 632 |
|
---|
| 633 | ui_tab_get_geom(tab, &geom);
|
---|
| 634 | epos.x = event->hpos;
|
---|
| 635 | epos.y = event->vpos;
|
---|
| 636 |
|
---|
| 637 | /* Event inside tab handle? */
|
---|
| 638 | if (gfx_pix_inside_rect(&epos, &geom.handle)) {
|
---|
| 639 | /* Select tab? */
|
---|
| 640 | if (event->type == POS_PRESS && event->btn_num == 1 &&
|
---|
| 641 | !ui_tab_is_selected(tab))
|
---|
| 642 | ui_tab_set_select(tab->tabset, tab);
|
---|
| 643 |
|
---|
| 644 | /* Claim event */
|
---|
| 645 | return ui_claimed;
|
---|
| 646 | }
|
---|
| 647 |
|
---|
| 648 | /* Deliver event to content control, if any */
|
---|
| 649 | if (ui_tab_is_selected(tab) && tab->content != NULL)
|
---|
| 650 | return ui_control_pos_event(tab->content, event);
|
---|
| 651 |
|
---|
| 652 | return ui_unclaimed;
|
---|
| 653 | }
|
---|
| 654 |
|
---|
| 655 | /** Handle keyboard event in tab.
|
---|
| 656 | *
|
---|
| 657 | * @param tab Tab
|
---|
| 658 | * @param event Keyboard event
|
---|
| 659 | * @return ui_claimed iff the event was claimed
|
---|
| 660 | */
|
---|
| 661 | ui_evclaim_t ui_tab_kbd_event(ui_tab_t *tab, kbd_event_t *event)
|
---|
| 662 | {
|
---|
| 663 | /* Deliver event to content control, if any */
|
---|
| 664 | if (ui_tab_is_selected(tab) && tab->content != NULL)
|
---|
| 665 | return ui_control_kbd_event(tab->content, event);
|
---|
| 666 |
|
---|
| 667 | return ui_unclaimed;
|
---|
| 668 | }
|
---|
| 669 |
|
---|
| 670 | /** @}
|
---|
| 671 | */
|
---|