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

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

Change the correct pointer's shape when resizing window

The request to resize a window originates from the client. The display
server forces the cursor to a double-arrow shape regardless of whether
it is over the window or not, until the resize is done. This is to
make sure the cursor keeps that shape even if it moves outside of
the current boundaries of the window. With multiple pointers we need
to know which one to change. This is done by passing the pos_id from
button press event that starts the resize all the way to
ds_window_start_resize(). Then it needs to be stored in the window
structure for use when it is time to restore the cursor.

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