source: mainline/uspace/lib/ui/src/wdecor.c@ 95658c9

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

Add pos_id information to move request, too

This will become useful momentarily.

  • Property mode set to 100644
File size: 24.6 KB
Line 
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 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 * @param pos_id Positioning device ID
468 */
469void ui_wdecor_move(ui_wdecor_t *wdecor, gfx_coord2_t *pos, sysarg_t pos_id)
470{
471 if (wdecor->cb != NULL && wdecor->cb->move != NULL)
472 wdecor->cb->move(wdecor, wdecor->arg, pos, pos_id);
473}
474
475/** Send decoration resize event.
476 *
477 * @param wdecor Window decoration
478 * @param rsztype Resize type
479 * @param pos Position where the button was pressed
480 * @param pos_id Positioning device ID
481 */
482void ui_wdecor_resize(ui_wdecor_t *wdecor, ui_wdecor_rsztype_t rsztype,
483 gfx_coord2_t *pos, sysarg_t pos_id)
484{
485 if (wdecor->cb != NULL && wdecor->cb->resize != NULL)
486 wdecor->cb->resize(wdecor, wdecor->arg, rsztype, pos, pos_id);
487}
488
489/** Send cursor change event.
490 *
491 * @param wdecor Window decoration
492 * @param cursor Cursor
493 */
494void ui_wdecor_set_cursor(ui_wdecor_t *wdecor, ui_stock_cursor_t cursor)
495{
496 if (wdecor->cb != NULL && wdecor->cb->set_cursor != NULL)
497 wdecor->cb->set_cursor(wdecor, wdecor->arg, cursor);
498}
499
500/** Get window decoration geometry.
501 *
502 * @param wdecor Window decoration
503 * @param geom Structure to fill in with computed geometry
504 */
505void ui_wdecor_get_geom(ui_wdecor_t *wdecor, ui_wdecor_geom_t *geom)
506{
507 gfx_coord_t frame_w;
508 gfx_coord_t btn_x;
509 gfx_coord_t btn_y;
510 gfx_coord_t cap_hmargin;
511
512 /* Does window have a frame? */
513 if ((wdecor->style & ui_wds_frame) != 0) {
514 frame_w = wdecor->res->textmode ?
515 wdecor_frame_w_text : wdecor_frame_w;
516
517 geom->interior_rect.p0.x = wdecor->rect.p0.x + frame_w;
518 geom->interior_rect.p0.y = wdecor->rect.p0.y + frame_w;
519 geom->interior_rect.p1.x = wdecor->rect.p1.x - frame_w;
520 geom->interior_rect.p1.y = wdecor->rect.p1.y - frame_w;
521 } else {
522 geom->interior_rect = wdecor->rect;
523 }
524
525 /* Does window have a title bar? */
526 if ((wdecor->style & ui_wds_titlebar) != 0) {
527 if (wdecor->res->textmode) {
528 geom->title_bar_rect.p0 = wdecor->rect.p0;
529 geom->title_bar_rect.p1.x = wdecor->rect.p1.x;
530 geom->title_bar_rect.p1.y = wdecor->rect.p0.y + 1;
531
532 btn_x = geom->title_bar_rect.p1.x - 1;
533 btn_y = geom->title_bar_rect.p0.y;
534 } else {
535 geom->title_bar_rect.p0 = geom->interior_rect.p0;
536 geom->title_bar_rect.p1.x = geom->interior_rect.p1.x;
537 geom->title_bar_rect.p1.y = geom->interior_rect.p0.y +
538 wdecor_tbar_h;
539
540 btn_x = geom->title_bar_rect.p1.x - 1;
541 btn_y = geom->title_bar_rect.p0.y + 1;
542 }
543
544 geom->app_area_rect.p0.x = geom->interior_rect.p0.x;
545 geom->app_area_rect.p0.y = geom->title_bar_rect.p1.y;
546 geom->app_area_rect.p1 = geom->interior_rect.p1;
547
548 } else {
549 geom->title_bar_rect.p0.x = 0;
550 geom->title_bar_rect.p0.y = 0;
551 geom->title_bar_rect.p1.x = 0;
552 geom->title_bar_rect.p1.y = 0;
553
554 geom->app_area_rect = geom->interior_rect;
555 btn_x = 0;
556 btn_y = 0;
557 }
558
559 /* Does window have a close button? */
560 if ((wdecor->style & ui_wds_close_btn) != 0) {
561 if (wdecor->res->textmode == false) {
562 geom->btn_close_rect.p0.x = btn_x - 20;
563 geom->btn_close_rect.p0.y = btn_y;
564 geom->btn_close_rect.p1.x = btn_x;
565 geom->btn_close_rect.p1.y = btn_y + 20;
566
567 btn_x -= 20;
568 } else {
569 geom->btn_close_rect.p0.x = btn_x - 3;
570 geom->btn_close_rect.p0.y = btn_y;
571 geom->btn_close_rect.p1.x = btn_x;
572 geom->btn_close_rect.p1.y = btn_y + 1;
573
574 btn_x -= 3;
575 }
576 } else {
577 geom->btn_close_rect.p0.x = 0;
578 geom->btn_close_rect.p0.y = 0;
579 geom->btn_close_rect.p1.x = 0;
580 geom->btn_close_rect.p1.y = 0;
581 }
582
583 /* Does window have a (un)maximize button? */
584 if ((wdecor->style & ui_wds_maximize_btn) != 0) {
585 if (wdecor->res->textmode == false) {
586 geom->btn_max_rect.p0.x = btn_x - 20;
587 geom->btn_max_rect.p0.y = btn_y;
588 geom->btn_max_rect.p1.x = btn_x;
589 geom->btn_max_rect.p1.y = btn_y + 20;
590
591 btn_x -= 20;
592 } else {
593 geom->btn_max_rect.p0.x = btn_x - 3;
594 geom->btn_max_rect.p0.y = btn_y;
595 geom->btn_max_rect.p1.x = btn_x;
596 geom->btn_max_rect.p1.y = btn_y + 1;
597
598 btn_x -= 3;
599 }
600 } else {
601 geom->btn_max_rect.p0.x = 0;
602 geom->btn_max_rect.p0.y = 0;
603 geom->btn_max_rect.p1.x = 0;
604 geom->btn_max_rect.p1.y = 0;
605 }
606
607 /* Does window have a minimize button? */
608 if ((wdecor->style & ui_wds_minimize_btn) != 0) {
609 if (wdecor->res->textmode == false) {
610 geom->btn_min_rect.p0.x = btn_x - 20;
611 geom->btn_min_rect.p0.y = btn_y;
612 geom->btn_min_rect.p1.x = btn_x;
613 geom->btn_min_rect.p1.y = btn_y + 20;
614
615 btn_x -= 20;
616 } else {
617 geom->btn_min_rect.p0.x = btn_x - 3;
618 geom->btn_min_rect.p0.y = btn_y;
619 geom->btn_min_rect.p1.x = btn_x;
620 geom->btn_min_rect.p1.y = btn_y + 1;
621
622 btn_x -= 3;
623 }
624 } else {
625 geom->btn_min_rect.p0.x = 0;
626 geom->btn_min_rect.p0.y = 0;
627 geom->btn_min_rect.p1.x = 0;
628 geom->btn_min_rect.p1.y = 0;
629 }
630
631 if (wdecor->res->textmode == false)
632 cap_hmargin = wdecor_cap_hmargin;
633 else
634 cap_hmargin = wdecor_cap_hmargin_text;
635
636 geom->caption_rect.p0.x = geom->title_bar_rect.p0.x +
637 cap_hmargin;
638 geom->caption_rect.p0.y = geom->title_bar_rect.p0.y;
639 geom->caption_rect.p1.x = btn_x - cap_hmargin;
640 geom->caption_rect.p1.y = geom->title_bar_rect.p1.y;
641}
642
643/** Get outer rectangle from application area rectangle.
644 *
645 * Note that this needs to work just based on a UI, without having an actual
646 * window decoration, since we need it in order to create the window
647 * and its decoration.
648 *
649 * @param style Decoration style
650 * @param app Application area rectangle
651 * @param rect Place to store (outer) window decoration rectangle
652 */
653void ui_wdecor_rect_from_app(ui_wdecor_style_t style, gfx_rect_t *app,
654 gfx_rect_t *rect)
655{
656 *rect = *app;
657
658 if ((style & ui_wds_frame) != 0) {
659 rect->p0.x -= wdecor_edge_w;
660 rect->p0.y -= wdecor_edge_h;
661 rect->p1.x += wdecor_edge_w;
662 rect->p1.y += wdecor_edge_h;
663 }
664
665 if ((style & ui_wds_titlebar) != 0)
666 rect->p0.y -= 22;
667}
668
669/** Application area rectangle from window rectangle.
670 *
671 * Note that this needs to work just based on a UI, without having an actual
672 * window decoration, since we need it in process of resizing the window,
673 * before it is actually resized.
674 *
675 * @param style Decoration style
676 * @param rect Window decoration rectangle
677 * @param app Place to store application area rectangle
678 */
679void ui_wdecor_app_from_rect(ui_wdecor_style_t style, gfx_rect_t *rect,
680 gfx_rect_t *app)
681{
682 *app = *rect;
683
684 if ((style & ui_wds_frame) != 0) {
685 app->p0.x += wdecor_edge_w;
686 app->p0.y += wdecor_edge_h;
687 app->p1.x -= wdecor_edge_w;
688 app->p1.y -= wdecor_edge_h;
689 }
690
691 if ((style & ui_wds_titlebar) != 0)
692 app->p0.y += 22;
693}
694
695/** Get resize type for pointer at the specified position.
696 *
697 * @param wdecor Window decoration
698 * @param pos Pointer position
699 * @return Resize type
700 */
701ui_wdecor_rsztype_t ui_wdecor_get_rsztype(ui_wdecor_t *wdecor,
702 gfx_coord2_t *pos)
703{
704 bool eleft, eright;
705 bool etop, ebottom;
706 bool edge;
707 bool cleft, cright;
708 bool ctop, cbottom;
709
710 /* Window not resizable? */
711 if ((wdecor->style & ui_wds_resizable) == 0)
712 return ui_wr_none;
713
714 /* Window is maximized? */
715 if (wdecor->maximized)
716 return ui_wr_none;
717
718 /* Position not inside window? */
719 if (!gfx_pix_inside_rect(pos, &wdecor->rect))
720 return ui_wr_none;
721
722 /* Position is within edge width from the outside */
723 eleft = (pos->x < wdecor->rect.p0.x + wdecor_edge_w);
724 eright = (pos->x >= wdecor->rect.p1.x - wdecor_edge_w);
725 etop = (pos->y < wdecor->rect.p0.y + wdecor_edge_h);
726 ebottom = (pos->y >= wdecor->rect.p1.y - wdecor_edge_h);
727
728 /* Position is on one of the four edges */
729 edge = eleft || eright || etop || ebottom;
730
731 /* Position is within resize-corner distance from the outside */
732 cleft = (pos->x < wdecor->rect.p0.x + wdecor_corner_w);
733 cright = (pos->x >= wdecor->rect.p1.x - wdecor_corner_w);
734 ctop = (pos->y < wdecor->rect.p0.y + wdecor_corner_h);
735 cbottom = (pos->y >= wdecor->rect.p1.y - wdecor_corner_h);
736
737 /* Top-left corner */
738 if (edge && cleft && ctop)
739 return ui_wr_top_left;
740
741 /* Top-right corner */
742 if (edge && cright && ctop)
743 return ui_wr_top_right;
744
745 /* Bottom-left corner */
746 if (edge && cleft && cbottom)
747 return ui_wr_bottom_left;
748
749 /* Bottom-right corner */
750 if (edge && cright && cbottom)
751 return ui_wr_bottom_right;
752
753 /* Left edge */
754 if (eleft)
755 return ui_wr_left;
756
757 /* Right edge */
758 if (eright)
759 return ui_wr_right;
760
761 /* Top edge */
762 if (etop)
763 return ui_wr_top;
764
765 /* Bottom edge */
766 if (ebottom)
767 return ui_wr_bottom;
768
769 return ui_wr_none;
770}
771
772/** Get stock cursor to use for the specified window resize type.
773 *
774 * The resize type must be valid, otherwise behavior is undefined.
775 *
776 * @param rsztype Resize type
777 * @return Cursor to use for this resize type
778 */
779ui_stock_cursor_t ui_wdecor_cursor_from_rsztype(ui_wdecor_rsztype_t rsztype)
780{
781 switch (rsztype) {
782 case ui_wr_none:
783 return ui_curs_arrow;
784
785 case ui_wr_top:
786 case ui_wr_bottom:
787 return ui_curs_size_ud;
788
789 case ui_wr_left:
790 case ui_wr_right:
791 return ui_curs_size_lr;
792
793 case ui_wr_top_left:
794 case ui_wr_bottom_right:
795 return ui_curs_size_uldr;
796
797 case ui_wr_top_right:
798 case ui_wr_bottom_left:
799 return ui_curs_size_urdl;
800
801 default:
802 assert(false);
803 return ui_curs_arrow;
804 }
805}
806
807/** Handle window frame position event.
808 *
809 * @param wdecor Window decoration
810 * @param pos_event Position event
811 */
812void ui_wdecor_frame_pos_event(ui_wdecor_t *wdecor, pos_event_t *event)
813{
814 gfx_coord2_t pos;
815 sysarg_t pos_id;
816 ui_wdecor_rsztype_t rsztype;
817 ui_stock_cursor_t cursor;
818
819 pos.x = event->hpos;
820 pos.y = event->vpos;
821 pos_id = event->pos_id;
822
823 /* Set appropriate resizing cursor, or set arrow cursor */
824
825 rsztype = ui_wdecor_get_rsztype(wdecor, &pos);
826 cursor = ui_wdecor_cursor_from_rsztype(rsztype);
827
828 ui_wdecor_set_cursor(wdecor, cursor);
829
830 /* Press on window border? */
831 if (rsztype != ui_wr_none && event->type == POS_PRESS)
832 ui_wdecor_resize(wdecor, rsztype, &pos, pos_id);
833}
834
835/** Handle window decoration position event.
836 *
837 * @param wdecor Window decoration
838 * @param pos_event Position event
839 * @return @c ui_claimed iff event was claimed
840 */
841ui_evclaim_t ui_wdecor_pos_event(ui_wdecor_t *wdecor, pos_event_t *event)
842{
843 gfx_coord2_t pos;
844 sysarg_t pos_id;
845 ui_wdecor_geom_t geom;
846 ui_evclaim_t claim;
847
848 pos.x = event->hpos;
849 pos.y = event->vpos;
850 pos_id = event->pos_id;
851
852 ui_wdecor_get_geom(wdecor, &geom);
853
854 if (wdecor->btn_min != NULL) {
855 claim = ui_pbutton_pos_event(wdecor->btn_min, event);
856 if (claim == ui_claimed)
857 return ui_claimed;
858 }
859
860 if (wdecor->btn_max != NULL) {
861 claim = ui_pbutton_pos_event(wdecor->btn_max, event);
862 if (claim == ui_claimed)
863 return ui_claimed;
864 }
865
866 if (wdecor->btn_close != NULL) {
867 claim = ui_pbutton_pos_event(wdecor->btn_close, event);
868 if (claim == ui_claimed)
869 return ui_claimed;
870 }
871
872 ui_wdecor_frame_pos_event(wdecor, event);
873
874 if ((wdecor->style & ui_wds_titlebar) != 0 && !wdecor->maximized) {
875 if (event->type == POS_PRESS &&
876 gfx_pix_inside_rect(&pos, &geom.title_bar_rect)) {
877 ui_wdecor_move(wdecor, &pos, pos_id);
878 return ui_claimed;
879 }
880 }
881
882 return ui_unclaimed;
883}
884
885/** Window decoration minimize button was clicked.
886 *
887 * @param pbutton Minimize button
888 * @param arg Argument (ui_wdecor_t)
889 */
890static void ui_wdecor_btn_min_clicked(ui_pbutton_t *pbutton, void *arg)
891{
892 ui_wdecor_t *wdecor = (ui_wdecor_t *) arg;
893
894 (void) pbutton;
895
896 ui_wdecor_minimize(wdecor);
897}
898
899/** Window decoration (un)maximize button was clicked.
900 *
901 * @param pbutton (Un)maximize button
902 * @param arg Argument (ui_wdecor_t)
903 */
904static void ui_wdecor_btn_max_clicked(ui_pbutton_t *pbutton, void *arg)
905{
906 ui_wdecor_t *wdecor = (ui_wdecor_t *) arg;
907
908 (void) pbutton;
909
910 if (wdecor->maximized)
911 ui_wdecor_unmaximize(wdecor);
912 else
913 ui_wdecor_maximize(wdecor);
914}
915
916/** Paint minimize button decoration.
917 *
918 * @param pbutton Push button
919 * @param arg Argument (ui_wdecor_t *)
920 * @param pos Center position
921 */
922static errno_t ui_wdecor_btn_min_paint(ui_pbutton_t *pbutton,
923 void *arg, gfx_coord2_t *pos)
924{
925 ui_wdecor_t *wdecor = (ui_wdecor_t *)arg;
926 errno_t rc;
927
928 rc = ui_paint_minicon(wdecor->res, pos, wdecor_min_w,
929 wdecor_min_h);
930
931 return rc;
932}
933
934/** Paint (un)maximize button decoration.
935 *
936 * @param pbutton Push button
937 * @param arg Argument (ui_wdecor_t *)
938 * @param pos Center position
939 */
940static errno_t ui_wdecor_btn_max_paint(ui_pbutton_t *pbutton,
941 void *arg, gfx_coord2_t *pos)
942{
943 ui_wdecor_t *wdecor = (ui_wdecor_t *)arg;
944 errno_t rc;
945
946 if (wdecor->maximized) {
947 rc = ui_paint_unmaxicon(wdecor->res, pos, wdecor_unmax_w,
948 wdecor_unmax_h, wdecor_unmax_dw, wdecor_unmax_dh);
949 } else {
950 rc = ui_paint_maxicon(wdecor->res, pos, wdecor_max_w,
951 wdecor_max_h);
952 }
953
954 return rc;
955}
956
957/** Window decoration close button was clicked.
958 *
959 * @param pbutton Close button
960 * @param arg Argument (ui_wdecor_t)
961 */
962static void ui_wdecor_btn_close_clicked(ui_pbutton_t *pbutton, void *arg)
963{
964 ui_wdecor_t *wdecor = (ui_wdecor_t *) arg;
965
966 (void) pbutton;
967 ui_wdecor_close(wdecor);
968}
969
970/** Paint close button decoration.
971 *
972 * @param pbutton Push button
973 * @param arg Argument (ui_wdecor_t *)
974 * @param pos Center position
975 */
976static errno_t ui_wdecor_btn_close_paint(ui_pbutton_t *pbutton,
977 void *arg, gfx_coord2_t *pos)
978{
979 ui_wdecor_t *wdecor = (ui_wdecor_t *)arg;
980 gfx_coord2_t p;
981 errno_t rc;
982
983 rc = gfx_set_color(wdecor->res->gc, wdecor->res->btn_text_color);
984 if (rc != EOK)
985 return rc;
986
987 p.x = pos->x - 1;
988 p.y = pos->y - 1;
989 return ui_paint_cross(wdecor->res->gc, &p, wdecor_close_cross_n,
990 wdecor_close_cross_w, wdecor_close_cross_h);
991}
992
993/** @}
994 */
Note: See TracBrowser for help on using the repository browser.