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 | */
|
---|