source: mainline/uspace/lib/ui/src/wdecor.c@ 570a3f3

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 570a3f3 was 06176e1, checked in by Jiri Svoboda <jiri@…>, 3 years ago

Minimizing windows

  • Property mode set to 100644
File size: 24.3 KB
Line 
1/*
2 * Copyright (c) 2022 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 Window decoration
34 */
35
36#include <assert.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 <ui/paint.h>
46#include <ui/pbutton.h>
47#include <ui/wdecor.h>
48#include "../private/resource.h"
49#include "../private/wdecor.h"
50
51static void ui_wdecor_btn_min_clicked(ui_pbutton_t *, void *);
52static errno_t ui_wdecor_btn_min_paint(ui_pbutton_t *, void *,
53 gfx_coord2_t *);
54
55static void ui_wdecor_btn_max_clicked(ui_pbutton_t *, void *);
56static errno_t ui_wdecor_btn_max_paint(ui_pbutton_t *, void *,
57 gfx_coord2_t *);
58
59static void ui_wdecor_btn_close_clicked(ui_pbutton_t *, void *);
60static errno_t ui_wdecor_btn_close_paint(ui_pbutton_t *, void *,
61 gfx_coord2_t *);
62
63static ui_pbutton_cb_t ui_wdecor_btn_min_cb = {
64 .clicked = ui_wdecor_btn_min_clicked
65};
66
67static ui_pbutton_decor_ops_t ui_wdecor_btn_min_decor_ops = {
68 .paint = ui_wdecor_btn_min_paint
69};
70
71static ui_pbutton_cb_t ui_wdecor_btn_max_cb = {
72 .clicked = ui_wdecor_btn_max_clicked
73};
74
75static ui_pbutton_decor_ops_t ui_wdecor_btn_max_decor_ops = {
76 .paint = ui_wdecor_btn_max_paint
77};
78
79static ui_pbutton_cb_t ui_wdecor_btn_close_cb = {
80 .clicked = ui_wdecor_btn_close_clicked
81};
82
83static ui_pbutton_decor_ops_t ui_wdecor_btn_close_decor_ops = {
84 .paint = ui_wdecor_btn_close_paint
85};
86
87enum {
88 /** Width of corner drag area */
89 wdecor_corner_w = 24,
90 /** Height of corner drag area */
91 wdecor_corner_h = 24,
92 /** Window resizing edge witdth */
93 wdecor_edge_w = 4,
94 /** Window resizing edge height */
95 wdecor_edge_h = 4,
96 /** Title bar height */
97 wdecor_tbar_h = 22,
98 /** Window width */
99 wdecor_frame_w = 4,
100 /** Window frame width in text mode */
101 wdecor_frame_w_text = 1,
102 /** Window caption horizontal margin */
103 wdecor_cap_hmargin = 4,
104 /** Window caption horizontal margin in text mode */
105 wdecor_cap_hmargin_text = 1,
106 /** Close button cross leg length */
107 wdecor_close_cross_n = 5,
108 /** Close button cross pen width */
109 wdecor_close_cross_w = 2,
110 /** Close button cross pen height */
111 wdecor_close_cross_h = 1,
112 /** Minimize icon width */
113 wdecor_min_w = 10,
114 /** Minimize icon height */
115 wdecor_min_h = 10,
116 /** Maximize icon width */
117 wdecor_max_w = 10,
118 /** Maximize icon height */
119 wdecor_max_h = 10,
120 /** Unmaximize icon window width */
121 wdecor_unmax_w = 8,
122 /** Unmaximize icon window height */
123 wdecor_unmax_h = 8,
124 /** Unmaximize icon window horizontal distance */
125 wdecor_unmax_dw = 4,
126 /** Unmaximize icon window vertical distance */
127 wdecor_unmax_dh = 4
128};
129
130/** Create new window decoration.
131 *
132 * @param resource UI resource
133 * @param caption Window caption
134 * @param style Style
135 * @param rwdecor Place to store pointer to new window decoration
136 * @return EOK on success, ENOMEM if out of memory
137 */
138errno_t ui_wdecor_create(ui_resource_t *resource, const char *caption,
139 ui_wdecor_style_t style, ui_wdecor_t **rwdecor)
140{
141 ui_wdecor_t *wdecor;
142 errno_t rc;
143
144 wdecor = calloc(1, sizeof(ui_wdecor_t));
145 if (wdecor == NULL)
146 return ENOMEM;
147
148 wdecor->caption = str_dup(caption);
149 if (wdecor->caption == NULL) {
150 free(wdecor);
151 return ENOMEM;
152 }
153
154 if ((style & ui_wds_minimize_btn) != 0) {
155 rc = ui_pbutton_create(resource, "_", &wdecor->btn_min);
156 if (rc != EOK) {
157 ui_wdecor_destroy(wdecor);
158 return rc;
159 }
160
161 ui_pbutton_set_cb(wdecor->btn_min, &ui_wdecor_btn_min_cb,
162 (void *)wdecor);
163
164 ui_pbutton_set_decor_ops(wdecor->btn_min,
165 &ui_wdecor_btn_min_decor_ops, (void *)wdecor);
166 }
167
168 if ((style & ui_wds_maximize_btn) != 0) {
169 rc = ui_pbutton_create(resource, "^", &wdecor->btn_max);
170 if (rc != EOK) {
171 ui_wdecor_destroy(wdecor);
172 return rc;
173 }
174
175 ui_pbutton_set_cb(wdecor->btn_max, &ui_wdecor_btn_max_cb,
176 (void *)wdecor);
177
178 ui_pbutton_set_decor_ops(wdecor->btn_max,
179 &ui_wdecor_btn_max_decor_ops, (void *)wdecor);
180 }
181
182 if ((style & ui_wds_close_btn) != 0) {
183 rc = ui_pbutton_create(resource, "X", &wdecor->btn_close);
184 if (rc != EOK) {
185 ui_wdecor_destroy(wdecor);
186 return rc;
187 }
188
189 ui_pbutton_set_cb(wdecor->btn_close, &ui_wdecor_btn_close_cb,
190 (void *)wdecor);
191
192 ui_pbutton_set_decor_ops(wdecor->btn_close,
193 &ui_wdecor_btn_close_decor_ops, (void *)wdecor);
194 }
195
196 wdecor->res = resource;
197 wdecor->active = true;
198 wdecor->style = style;
199 *rwdecor = wdecor;
200 return EOK;
201}
202
203/** Destroy window decoration.
204 *
205 * @param wdecor Window decoration or @c NULL
206 */
207void ui_wdecor_destroy(ui_wdecor_t *wdecor)
208{
209 if (wdecor == NULL)
210 return;
211
212 ui_pbutton_destroy(wdecor->btn_min);
213 ui_pbutton_destroy(wdecor->btn_max);
214 ui_pbutton_destroy(wdecor->btn_close);
215 free(wdecor->caption);
216 free(wdecor);
217}
218
219/** Set window decoration callbacks.
220 *
221 * @param wdecor Window decoration
222 * @param cb Window decoration callbacks
223 * @param arg Callback argument
224 */
225void ui_wdecor_set_cb(ui_wdecor_t *wdecor, ui_wdecor_cb_t *cb, void *arg)
226{
227 wdecor->cb = cb;
228 wdecor->arg = arg;
229}
230
231/** Set window decoration rectangle.
232 *
233 * @param wdecor Window decoration
234 * @param rect New window decoration rectangle
235 */
236void ui_wdecor_set_rect(ui_wdecor_t *wdecor, gfx_rect_t *rect)
237{
238 ui_wdecor_geom_t geom;
239
240 wdecor->rect = *rect;
241
242 ui_wdecor_get_geom(wdecor, &geom);
243
244 if (wdecor->btn_min != NULL)
245 ui_pbutton_set_rect(wdecor->btn_min, &geom.btn_min_rect);
246 if (wdecor->btn_max != NULL)
247 ui_pbutton_set_rect(wdecor->btn_max, &geom.btn_max_rect);
248 if (wdecor->btn_close != NULL)
249 ui_pbutton_set_rect(wdecor->btn_close, &geom.btn_close_rect);
250}
251
252/** Set active flag.
253 *
254 * Active window is the one receiving keyboard events.
255 *
256 * @param wdecor Window decoration
257 * @param active @c true iff window is active
258 */
259void ui_wdecor_set_active(ui_wdecor_t *wdecor, bool active)
260{
261 wdecor->active = active;
262}
263
264/** Set maximized flag.
265 *
266 * Active window is the one receiving keyboard events.
267 *
268 * @param wdecor Window decoration
269 * @param maximized @c true iff window is maximized
270 */
271void ui_wdecor_set_maximized(ui_wdecor_t *wdecor, bool maximized)
272{
273 wdecor->maximized = maximized;
274}
275
276/** Change caption.
277 *
278 * @param wdecor Window decoration
279 * @param caption New caption
280 *
281 * @return EOK on success or an error code
282 */
283errno_t ui_wdecor_set_caption(ui_wdecor_t *wdecor, const char *caption)
284{
285 char *cdup;
286
287 cdup = str_dup(caption);
288 if (cdup == NULL)
289 return ENOMEM;
290
291 free(wdecor->caption);
292 wdecor->caption = cdup;
293
294 ui_wdecor_paint(wdecor);
295 return EOK;
296}
297
298/** Paint window decoration.
299 *
300 * @param wdecor Window decoration
301 * @return EOK on success or an error code
302 */
303errno_t ui_wdecor_paint(ui_wdecor_t *wdecor)
304{
305 errno_t rc;
306 gfx_rect_t rect;
307 gfx_rect_t trect;
308 gfx_rect_t text_rect;
309 gfx_text_fmt_t fmt;
310 gfx_coord2_t pos;
311 ui_wdecor_geom_t geom;
312
313 rect = wdecor->rect;
314 ui_wdecor_get_geom(wdecor, &geom);
315
316 if ((wdecor->style & ui_wds_frame) != 0) {
317
318 if (wdecor->res->textmode != false) {
319 rc = ui_paint_text_box(wdecor->res, &rect,
320 ui_box_double, wdecor->res->wnd_face_color);
321 if (rc != EOK)
322 return rc;
323 } else {
324 rc = ui_paint_outset_frame(wdecor->res, &rect,
325 &rect);
326 if (rc != EOK)
327 return rc;
328
329 rc = ui_paint_bevel(wdecor->res->gc, &rect,
330 wdecor->res->wnd_face_color,
331 wdecor->res->wnd_face_color, 2, &rect);
332 if (rc != EOK)
333 return rc;
334 }
335 }
336
337 if ((wdecor->style & ui_wds_titlebar) != 0) {
338 trect = geom.title_bar_rect;
339
340 if (wdecor->res->textmode == false) {
341 rc = ui_paint_bevel(wdecor->res->gc, &trect,
342 wdecor->res->wnd_shadow_color,
343 wdecor->res->wnd_highlight_color, 1, &trect);
344 if (rc != EOK)
345 return rc;
346
347 rc = gfx_set_color(wdecor->res->gc, wdecor->active ?
348 wdecor->res->tbar_act_bg_color :
349 wdecor->res->tbar_inact_bg_color);
350 if (rc != EOK)
351 return rc;
352
353 rc = gfx_fill_rect(wdecor->res->gc, &trect);
354 if (rc != EOK)
355 return rc;
356 }
357
358 gfx_text_fmt_init(&fmt);
359 fmt.font = wdecor->res->font;
360 fmt.color = wdecor->active ?
361 wdecor->res->tbar_act_text_color :
362 wdecor->res->tbar_inact_text_color;
363 fmt.halign = gfx_halign_center;
364 fmt.valign = gfx_valign_center;
365 fmt.abbreviate = true;
366 fmt.width = geom.caption_rect.p1.x -
367 geom.caption_rect.p0.x;
368
369 pos.x = (geom.caption_rect.p0.x + geom.caption_rect.p1.x) / 2;
370 pos.y = (geom.caption_rect.p0.y + geom.caption_rect.p1.y) / 2;
371
372 if (wdecor->res->textmode) {
373 /* Make space around caption text */
374 gfx_text_rect(&pos, &fmt, wdecor->caption, &text_rect);
375
376 /* Only make space if caption is non-empty */
377 if (text_rect.p0.x < text_rect.p1.x) {
378 text_rect.p0.x -= 1;
379 text_rect.p1.x += 1;
380 }
381
382 rc = gfx_set_color(wdecor->res->gc, wdecor->active ?
383 wdecor->res->tbar_act_bg_color :
384 wdecor->res->tbar_inact_bg_color);
385 if (rc != EOK)
386 return rc;
387
388 rc = gfx_fill_rect(wdecor->res->gc, &text_rect);
389 if (rc != EOK)
390 return rc;
391 }
392
393 rc = gfx_puttext(&pos, &fmt, wdecor->caption);
394 if (rc != EOK)
395 return rc;
396
397 if (wdecor->btn_min != NULL) {
398 rc = ui_pbutton_paint(wdecor->btn_min);
399 if (rc != EOK)
400 return rc;
401 }
402
403 if (wdecor->btn_max != NULL) {
404 rc = ui_pbutton_paint(wdecor->btn_max);
405 if (rc != EOK)
406 return rc;
407 }
408
409 if (wdecor->btn_close != NULL) {
410 rc = ui_pbutton_paint(wdecor->btn_close);
411 if (rc != EOK)
412 return rc;
413 }
414 }
415
416 rc = gfx_update(wdecor->res->gc);
417 if (rc != EOK)
418 return rc;
419
420 return EOK;
421}
422
423/** Send decoration minimize event.
424 *
425 * @param wdecor Window decoration
426 */
427void ui_wdecor_minimize(ui_wdecor_t *wdecor)
428{
429 if (wdecor->cb != NULL && wdecor->cb->minimize != NULL)
430 wdecor->cb->minimize(wdecor, wdecor->arg);
431}
432
433/** Send decoration maximize event.
434 *
435 * @param wdecor Window decoration
436 */
437void ui_wdecor_maximize(ui_wdecor_t *wdecor)
438{
439 if (wdecor->cb != NULL && wdecor->cb->maximize != NULL)
440 wdecor->cb->maximize(wdecor, wdecor->arg);
441}
442
443/** Send decoration unmaximize event.
444 *
445 * @param wdecor Window decoration
446 */
447void ui_wdecor_unmaximize(ui_wdecor_t *wdecor)
448{
449 if (wdecor->cb != NULL && wdecor->cb->unmaximize != NULL)
450 wdecor->cb->unmaximize(wdecor, wdecor->arg);
451}
452
453/** Send decoration close event.
454 *
455 * @param wdecor Window decoration
456 */
457void ui_wdecor_close(ui_wdecor_t *wdecor)
458{
459 if (wdecor->cb != NULL && wdecor->cb->close != NULL)
460 wdecor->cb->close(wdecor, wdecor->arg);
461}
462
463/** Send decoration move event.
464 *
465 * @param wdecor Window decoration
466 * @param pos Position where the title bar was pressed
467 */
468void ui_wdecor_move(ui_wdecor_t *wdecor, gfx_coord2_t *pos)
469{
470 if (wdecor->cb != NULL && wdecor->cb->move != NULL)
471 wdecor->cb->move(wdecor, wdecor->arg, pos);
472}
473
474/** Send decoration resize event.
475 *
476 * @param wdecor Window decoration
477 * @param rsztype Resize type
478 * @param pos Position where the button was pressed
479 */
480void ui_wdecor_resize(ui_wdecor_t *wdecor, ui_wdecor_rsztype_t rsztype,
481 gfx_coord2_t *pos)
482{
483 if (wdecor->cb != NULL && wdecor->cb->resize != NULL)
484 wdecor->cb->resize(wdecor, wdecor->arg, rsztype, pos);
485}
486
487/** Send cursor change event.
488 *
489 * @param wdecor Window decoration
490 * @param cursor Cursor
491 */
492void ui_wdecor_set_cursor(ui_wdecor_t *wdecor, ui_stock_cursor_t cursor)
493{
494 if (wdecor->cb != NULL && wdecor->cb->set_cursor != NULL)
495 wdecor->cb->set_cursor(wdecor, wdecor->arg, cursor);
496}
497
498/** Get window decoration geometry.
499 *
500 * @param wdecor Window decoration
501 * @param geom Structure to fill in with computed geometry
502 */
503void ui_wdecor_get_geom(ui_wdecor_t *wdecor, ui_wdecor_geom_t *geom)
504{
505 gfx_coord_t frame_w;
506 gfx_coord_t btn_x;
507 gfx_coord_t btn_y;
508 gfx_coord_t cap_hmargin;
509
510 /* Does window have a frame? */
511 if ((wdecor->style & ui_wds_frame) != 0) {
512 frame_w = wdecor->res->textmode ?
513 wdecor_frame_w_text : wdecor_frame_w;
514
515 geom->interior_rect.p0.x = wdecor->rect.p0.x + frame_w;
516 geom->interior_rect.p0.y = wdecor->rect.p0.y + frame_w;
517 geom->interior_rect.p1.x = wdecor->rect.p1.x - frame_w;
518 geom->interior_rect.p1.y = wdecor->rect.p1.y - frame_w;
519 } else {
520 geom->interior_rect = wdecor->rect;
521 }
522
523 /* Does window have a title bar? */
524 if ((wdecor->style & ui_wds_titlebar) != 0) {
525 if (wdecor->res->textmode) {
526 geom->title_bar_rect.p0 = wdecor->rect.p0;
527 geom->title_bar_rect.p1.x = wdecor->rect.p1.x;
528 geom->title_bar_rect.p1.y = wdecor->rect.p0.y + 1;
529
530 btn_x = geom->title_bar_rect.p1.x - 1;
531 btn_y = geom->title_bar_rect.p0.y;
532 } else {
533 geom->title_bar_rect.p0 = geom->interior_rect.p0;
534 geom->title_bar_rect.p1.x = geom->interior_rect.p1.x;
535 geom->title_bar_rect.p1.y = geom->interior_rect.p0.y +
536 wdecor_tbar_h;
537
538 btn_x = geom->title_bar_rect.p1.x - 1;
539 btn_y = geom->title_bar_rect.p0.y + 1;
540 }
541
542 geom->app_area_rect.p0.x = geom->interior_rect.p0.x;
543 geom->app_area_rect.p0.y = geom->title_bar_rect.p1.y;
544 geom->app_area_rect.p1 = geom->interior_rect.p1;
545
546 } else {
547 geom->title_bar_rect.p0.x = 0;
548 geom->title_bar_rect.p0.y = 0;
549 geom->title_bar_rect.p1.x = 0;
550 geom->title_bar_rect.p1.y = 0;
551
552 geom->app_area_rect = geom->interior_rect;
553 btn_x = 0;
554 btn_y = 0;
555 }
556
557 /* Does window have a close button? */
558 if ((wdecor->style & ui_wds_close_btn) != 0) {
559 if (wdecor->res->textmode == false) {
560 geom->btn_close_rect.p0.x = btn_x - 20;
561 geom->btn_close_rect.p0.y = btn_y;
562 geom->btn_close_rect.p1.x = btn_x;
563 geom->btn_close_rect.p1.y = btn_y + 20;
564
565 btn_x -= 20;
566 } else {
567 geom->btn_close_rect.p0.x = btn_x - 3;
568 geom->btn_close_rect.p0.y = btn_y;
569 geom->btn_close_rect.p1.x = btn_x;
570 geom->btn_close_rect.p1.y = btn_y + 1;
571
572 btn_x -= 3;
573 }
574 } else {
575 geom->btn_close_rect.p0.x = 0;
576 geom->btn_close_rect.p0.y = 0;
577 geom->btn_close_rect.p1.x = 0;
578 geom->btn_close_rect.p1.y = 0;
579 }
580
581 /* Does window have a (un)maximize button? */
582 if ((wdecor->style & ui_wds_maximize_btn) != 0) {
583 if (wdecor->res->textmode == false) {
584 geom->btn_max_rect.p0.x = btn_x - 20;
585 geom->btn_max_rect.p0.y = btn_y;
586 geom->btn_max_rect.p1.x = btn_x;
587 geom->btn_max_rect.p1.y = btn_y + 20;
588
589 btn_x -= 20;
590 } else {
591 geom->btn_max_rect.p0.x = btn_x - 3;
592 geom->btn_max_rect.p0.y = btn_y;
593 geom->btn_max_rect.p1.x = btn_x;
594 geom->btn_max_rect.p1.y = btn_y + 1;
595
596 btn_x -= 3;
597 }
598 } else {
599 geom->btn_max_rect.p0.x = 0;
600 geom->btn_max_rect.p0.y = 0;
601 geom->btn_max_rect.p1.x = 0;
602 geom->btn_max_rect.p1.y = 0;
603 }
604
605 /* Does window have a minimize button? */
606 if ((wdecor->style & ui_wds_minimize_btn) != 0) {
607 if (wdecor->res->textmode == false) {
608 geom->btn_min_rect.p0.x = btn_x - 20;
609 geom->btn_min_rect.p0.y = btn_y;
610 geom->btn_min_rect.p1.x = btn_x;
611 geom->btn_min_rect.p1.y = btn_y + 20;
612
613 btn_x -= 20;
614 } else {
615 geom->btn_min_rect.p0.x = btn_x - 3;
616 geom->btn_min_rect.p0.y = btn_y;
617 geom->btn_min_rect.p1.x = btn_x;
618 geom->btn_min_rect.p1.y = btn_y + 1;
619
620 btn_x -= 3;
621 }
622 } else {
623 geom->btn_min_rect.p0.x = 0;
624 geom->btn_min_rect.p0.y = 0;
625 geom->btn_min_rect.p1.x = 0;
626 geom->btn_min_rect.p1.y = 0;
627 }
628
629 if (wdecor->res->textmode == false)
630 cap_hmargin = wdecor_cap_hmargin;
631 else
632 cap_hmargin = wdecor_cap_hmargin_text;
633
634 geom->caption_rect.p0.x = geom->title_bar_rect.p0.x +
635 cap_hmargin;
636 geom->caption_rect.p0.y = geom->title_bar_rect.p0.y;
637 geom->caption_rect.p1.x = btn_x - cap_hmargin;
638 geom->caption_rect.p1.y = geom->title_bar_rect.p1.y;
639}
640
641/** Get outer rectangle from application area rectangle.
642 *
643 * Note that this needs to work just based on a UI, without having an actual
644 * window decoration, since we need it in order to create the window
645 * and its decoration.
646 *
647 * @param style Decoration style
648 * @param app Application area rectangle
649 * @param rect Place to store (outer) window decoration rectangle
650 */
651void ui_wdecor_rect_from_app(ui_wdecor_style_t style, gfx_rect_t *app,
652 gfx_rect_t *rect)
653{
654 *rect = *app;
655
656 if ((style & ui_wds_frame) != 0) {
657 rect->p0.x -= wdecor_edge_w;
658 rect->p0.y -= wdecor_edge_h;
659 rect->p1.x += wdecor_edge_w;
660 rect->p1.y += wdecor_edge_h;
661 }
662
663 if ((style & ui_wds_titlebar) != 0)
664 rect->p0.y -= 22;
665}
666
667/** Application area rectangle from window rectangle.
668 *
669 * Note that this needs to work just based on a UI, without having an actual
670 * window decoration, since we need it in process of resizing the window,
671 * before it is actually resized.
672 *
673 * @param style Decoration style
674 * @param rect Window decoration rectangle
675 * @param app Place to store application area rectangle
676 */
677void ui_wdecor_app_from_rect(ui_wdecor_style_t style, gfx_rect_t *rect,
678 gfx_rect_t *app)
679{
680 *app = *rect;
681
682 if ((style & ui_wds_frame) != 0) {
683 app->p0.x += wdecor_edge_w;
684 app->p0.y += wdecor_edge_h;
685 app->p1.x -= wdecor_edge_w;
686 app->p1.y -= wdecor_edge_h;
687 }
688
689 if ((style & ui_wds_titlebar) != 0)
690 app->p0.y += 22;
691}
692
693/** Get resize type for pointer at the specified position.
694 *
695 * @param wdecor Window decoration
696 * @param pos Pointer position
697 * @return Resize type
698 */
699ui_wdecor_rsztype_t ui_wdecor_get_rsztype(ui_wdecor_t *wdecor,
700 gfx_coord2_t *pos)
701{
702 bool eleft, eright;
703 bool etop, ebottom;
704 bool edge;
705 bool cleft, cright;
706 bool ctop, cbottom;
707
708 /* Window not resizable? */
709 if ((wdecor->style & ui_wds_resizable) == 0)
710 return ui_wr_none;
711
712 /* Window is maximized? */
713 if (wdecor->maximized)
714 return ui_wr_none;
715
716 /* Position not inside window? */
717 if (!gfx_pix_inside_rect(pos, &wdecor->rect))
718 return ui_wr_none;
719
720 /* Position is within edge width from the outside */
721 eleft = (pos->x < wdecor->rect.p0.x + wdecor_edge_w);
722 eright = (pos->x >= wdecor->rect.p1.x - wdecor_edge_w);
723 etop = (pos->y < wdecor->rect.p0.y + wdecor_edge_h);
724 ebottom = (pos->y >= wdecor->rect.p1.y - wdecor_edge_h);
725
726 /* Position is on one of the four edges */
727 edge = eleft || eright || etop || ebottom;
728
729 /* Position is within resize-corner distance from the outside */
730 cleft = (pos->x < wdecor->rect.p0.x + wdecor_corner_w);
731 cright = (pos->x >= wdecor->rect.p1.x - wdecor_corner_w);
732 ctop = (pos->y < wdecor->rect.p0.y + wdecor_corner_h);
733 cbottom = (pos->y >= wdecor->rect.p1.y - wdecor_corner_h);
734
735 /* Top-left corner */
736 if (edge && cleft && ctop)
737 return ui_wr_top_left;
738
739 /* Top-right corner */
740 if (edge && cright && ctop)
741 return ui_wr_top_right;
742
743 /* Bottom-left corner */
744 if (edge && cleft && cbottom)
745 return ui_wr_bottom_left;
746
747 /* Bottom-right corner */
748 if (edge && cright && cbottom)
749 return ui_wr_bottom_right;
750
751 /* Left edge */
752 if (eleft)
753 return ui_wr_left;
754
755 /* Right edge */
756 if (eright)
757 return ui_wr_right;
758
759 /* Top edge */
760 if (etop)
761 return ui_wr_top;
762
763 /* Bottom edge */
764 if (ebottom)
765 return ui_wr_bottom;
766
767 return ui_wr_none;
768}
769
770/** Get stock cursor to use for the specified window resize type.
771 *
772 * The resize type must be valid, otherwise behavior is undefined.
773 *
774 * @param rsztype Resize type
775 * @return Cursor to use for this resize type
776 */
777ui_stock_cursor_t ui_wdecor_cursor_from_rsztype(ui_wdecor_rsztype_t rsztype)
778{
779 switch (rsztype) {
780 case ui_wr_none:
781 return ui_curs_arrow;
782
783 case ui_wr_top:
784 case ui_wr_bottom:
785 return ui_curs_size_ud;
786
787 case ui_wr_left:
788 case ui_wr_right:
789 return ui_curs_size_lr;
790
791 case ui_wr_top_left:
792 case ui_wr_bottom_right:
793 return ui_curs_size_uldr;
794
795 case ui_wr_top_right:
796 case ui_wr_bottom_left:
797 return ui_curs_size_urdl;
798
799 default:
800 assert(false);
801 return ui_curs_arrow;
802 }
803}
804
805/** Handle window frame position event.
806 *
807 * @param wdecor Window decoration
808 * @param pos_event Position event
809 */
810void ui_wdecor_frame_pos_event(ui_wdecor_t *wdecor, pos_event_t *event)
811{
812 gfx_coord2_t pos;
813 ui_wdecor_rsztype_t rsztype;
814 ui_stock_cursor_t cursor;
815
816 pos.x = event->hpos;
817 pos.y = event->vpos;
818
819 /* Set appropriate resizing cursor, or set arrow cursor */
820
821 rsztype = ui_wdecor_get_rsztype(wdecor, &pos);
822 cursor = ui_wdecor_cursor_from_rsztype(rsztype);
823
824 ui_wdecor_set_cursor(wdecor, cursor);
825
826 /* Press on window border? */
827 if (rsztype != ui_wr_none && event->type == POS_PRESS)
828 ui_wdecor_resize(wdecor, rsztype, &pos);
829}
830
831/** Handle window decoration position event.
832 *
833 * @param wdecor Window decoration
834 * @param pos_event Position event
835 * @return @c ui_claimed iff event was claimed
836 */
837ui_evclaim_t ui_wdecor_pos_event(ui_wdecor_t *wdecor, pos_event_t *event)
838{
839 gfx_coord2_t pos;
840 ui_wdecor_geom_t geom;
841 ui_evclaim_t claim;
842
843 pos.x = event->hpos;
844 pos.y = event->vpos;
845
846 ui_wdecor_get_geom(wdecor, &geom);
847
848 if (wdecor->btn_min != NULL) {
849 claim = ui_pbutton_pos_event(wdecor->btn_min, event);
850 if (claim == ui_claimed)
851 return ui_claimed;
852 }
853
854 if (wdecor->btn_max != NULL) {
855 claim = ui_pbutton_pos_event(wdecor->btn_max, event);
856 if (claim == ui_claimed)
857 return ui_claimed;
858 }
859
860 if (wdecor->btn_close != NULL) {
861 claim = ui_pbutton_pos_event(wdecor->btn_close, event);
862 if (claim == ui_claimed)
863 return ui_claimed;
864 }
865
866 ui_wdecor_frame_pos_event(wdecor, event);
867
868 if ((wdecor->style & ui_wds_titlebar) != 0 && !wdecor->maximized) {
869 if (event->type == POS_PRESS &&
870 gfx_pix_inside_rect(&pos, &geom.title_bar_rect)) {
871 ui_wdecor_move(wdecor, &pos);
872 return ui_claimed;
873 }
874 }
875
876 return ui_unclaimed;
877}
878
879/** Window decoration minimize button was clicked.
880 *
881 * @param pbutton Minimize button
882 * @param arg Argument (ui_wdecor_t)
883 */
884static void ui_wdecor_btn_min_clicked(ui_pbutton_t *pbutton, void *arg)
885{
886 ui_wdecor_t *wdecor = (ui_wdecor_t *) arg;
887
888 (void) pbutton;
889
890 ui_wdecor_minimize(wdecor);
891}
892
893/** Window decoration (un)maximize button was clicked.
894 *
895 * @param pbutton (Un)maximize button
896 * @param arg Argument (ui_wdecor_t)
897 */
898static void ui_wdecor_btn_max_clicked(ui_pbutton_t *pbutton, void *arg)
899{
900 ui_wdecor_t *wdecor = (ui_wdecor_t *) arg;
901
902 (void) pbutton;
903
904 if (wdecor->maximized)
905 ui_wdecor_unmaximize(wdecor);
906 else
907 ui_wdecor_maximize(wdecor);
908}
909
910/** Paint minimize button decoration.
911 *
912 * @param pbutton Push button
913 * @param arg Argument (ui_wdecor_t *)
914 * @param pos Center position
915 */
916static errno_t ui_wdecor_btn_min_paint(ui_pbutton_t *pbutton,
917 void *arg, gfx_coord2_t *pos)
918{
919 ui_wdecor_t *wdecor = (ui_wdecor_t *)arg;
920 errno_t rc;
921
922 rc = ui_paint_minicon(wdecor->res, pos, wdecor_min_w,
923 wdecor_min_h);
924
925 return rc;
926}
927
928/** Paint (un)maximize button decoration.
929 *
930 * @param pbutton Push button
931 * @param arg Argument (ui_wdecor_t *)
932 * @param pos Center position
933 */
934static errno_t ui_wdecor_btn_max_paint(ui_pbutton_t *pbutton,
935 void *arg, gfx_coord2_t *pos)
936{
937 ui_wdecor_t *wdecor = (ui_wdecor_t *)arg;
938 errno_t rc;
939
940 if (wdecor->maximized) {
941 rc = ui_paint_unmaxicon(wdecor->res, pos, wdecor_unmax_w,
942 wdecor_unmax_h, wdecor_unmax_dw, wdecor_unmax_dh);
943 } else {
944 rc = ui_paint_maxicon(wdecor->res, pos, wdecor_max_w,
945 wdecor_max_h);
946 }
947
948 return rc;
949}
950
951/** Window decoration close button was clicked.
952 *
953 * @param pbutton Close button
954 * @param arg Argument (ui_wdecor_t)
955 */
956static void ui_wdecor_btn_close_clicked(ui_pbutton_t *pbutton, void *arg)
957{
958 ui_wdecor_t *wdecor = (ui_wdecor_t *) arg;
959
960 (void) pbutton;
961 ui_wdecor_close(wdecor);
962}
963
964/** Paint close button decoration.
965 *
966 * @param pbutton Push button
967 * @param arg Argument (ui_wdecor_t *)
968 * @param pos Center position
969 */
970static errno_t ui_wdecor_btn_close_paint(ui_pbutton_t *pbutton,
971 void *arg, gfx_coord2_t *pos)
972{
973 ui_wdecor_t *wdecor = (ui_wdecor_t *)arg;
974 gfx_coord2_t p;
975 errno_t rc;
976
977 rc = gfx_set_color(wdecor->res->gc, wdecor->res->btn_text_color);
978 if (rc != EOK)
979 return rc;
980
981 p.x = pos->x - 1;
982 p.y = pos->y - 1;
983 return ui_paint_cross(wdecor->res->gc, &p, wdecor_close_cross_n,
984 wdecor_close_cross_w, wdecor_close_cross_h);
985}
986
987/** @}
988 */
Note: See TracBrowser for help on using the repository browser.