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

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

Implement text abbreviation

When rendering text, gfx_puttext can now abbreviate it with …
to fit within the specified width. Use on window captions.
Now Barber Pole can have a proper caption.

Note that now the caption is centered on the space between the left
edge and the buttons, instead on the entire title bar, so it
may look a little lopsided. It will look better once we put
something to the left side of the title bar.

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