source: mainline/uspace/lib/ui/src/menubar.c@ 98735eb

serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 98735eb was d7f82635, checked in by jxsvoboda <5887334+jxsvoboda@…>, 4 years ago

Deliver close event to popup window when appropriate

That is, when focus changes or when user clicks outside of the
popup window.

  • Property mode set to 100644
File size: 7.8 KB
Line 
1/*
2 * Copyright (c) 2021 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 Menu bar
34 */
35
36#include <adt/list.h>
37#include <errno.h>
38#include <gfx/color.h>
39#include <gfx/context.h>
40#include <gfx/render.h>
41#include <gfx/text.h>
42#include <io/pos_event.h>
43#include <stdlib.h>
44#include <str.h>
45#include <ui/control.h>
46#include <ui/paint.h>
47#include <ui/menu.h>
48#include <ui/menubar.h>
49#include <ui/window.h>
50#include "../private/menubar.h"
51#include "../private/resource.h"
52
53enum {
54 menubar_hpad = 4,
55 menubar_vpad = 4,
56 menubar_hpad_text = 1,
57 menubar_vpad_text = 0
58};
59
60static void ui_menu_bar_ctl_destroy(void *);
61static errno_t ui_menu_bar_ctl_paint(void *);
62static ui_evclaim_t ui_menu_bar_ctl_pos_event(void *, pos_event_t *);
63
64/** Menu bar control ops */
65ui_control_ops_t ui_menu_bar_ops = {
66 .destroy = ui_menu_bar_ctl_destroy,
67 .paint = ui_menu_bar_ctl_paint,
68 .pos_event = ui_menu_bar_ctl_pos_event,
69};
70
71/** Create new menu bar.
72 *
73 * @param ui UI
74 * @param window Window that will contain the menu bar
75 * @param rmbar Place to store pointer to new menu bar
76 * @return EOK on success, ENOMEM if out of memory
77 */
78errno_t ui_menu_bar_create(ui_t *ui, ui_window_t *window, ui_menu_bar_t **rmbar)
79{
80 ui_menu_bar_t *mbar;
81 errno_t rc;
82
83 mbar = calloc(1, sizeof(ui_menu_bar_t));
84 if (mbar == NULL)
85 return ENOMEM;
86
87 rc = ui_control_new(&ui_menu_bar_ops, (void *) mbar, &mbar->control);
88 if (rc != EOK) {
89 free(mbar);
90 return rc;
91 }
92
93 mbar->ui = ui;
94 mbar->window = window;
95 list_initialize(&mbar->menus);
96 *rmbar = mbar;
97 return EOK;
98}
99
100/** Destroy menu bar
101 *
102 * @param mbar Menu bar or @c NULL
103 */
104void ui_menu_bar_destroy(ui_menu_bar_t *mbar)
105{
106 ui_menu_t *menu;
107
108 if (mbar == NULL)
109 return;
110
111 /* Destroy menus */
112 menu = ui_menu_first(mbar);
113 while (menu != NULL) {
114 ui_menu_destroy(menu);
115 menu = ui_menu_first(mbar);
116 }
117
118 ui_control_delete(mbar->control);
119 free(mbar);
120}
121
122/** Get base control from menu bar.
123 *
124 * @param mbar Menu bar
125 * @return Control
126 */
127ui_control_t *ui_menu_bar_ctl(ui_menu_bar_t *mbar)
128{
129 return mbar->control;
130}
131
132/** Set menu bar rectangle.
133 *
134 * @param mbar Menu bar
135 * @param rect New menu bar rectangle
136 */
137void ui_menu_bar_set_rect(ui_menu_bar_t *mbar, gfx_rect_t *rect)
138{
139 mbar->rect = *rect;
140}
141
142/** Paint menu bar.
143 *
144 * @param mbar Menu bar
145 * @return EOK on success or an error code
146 */
147errno_t ui_menu_bar_paint(ui_menu_bar_t *mbar)
148{
149 ui_resource_t *res;
150 gfx_text_fmt_t fmt;
151 gfx_coord2_t pos;
152 gfx_coord2_t tpos;
153 gfx_rect_t rect;
154 gfx_color_t *bg_color;
155 ui_menu_t *menu;
156 const char *caption;
157 gfx_coord_t width;
158 gfx_coord_t hpad;
159 gfx_coord_t vpad;
160 errno_t rc;
161
162 res = ui_window_get_res(mbar->window);
163
164 /* Paint menu bar background */
165
166 rc = gfx_set_color(res->gc, res->wnd_face_color);
167 if (rc != EOK)
168 goto error;
169
170 rc = gfx_fill_rect(res->gc, &mbar->rect);
171 if (rc != EOK)
172 goto error;
173
174 if (res->textmode) {
175 hpad = menubar_hpad_text;
176 vpad = menubar_vpad_text;
177 } else {
178 hpad = menubar_hpad;
179 vpad = menubar_vpad;
180 }
181
182 pos = mbar->rect.p0;
183
184 gfx_text_fmt_init(&fmt);
185 fmt.halign = gfx_halign_left;
186 fmt.valign = gfx_valign_top;
187
188 menu = ui_menu_first(mbar);
189 while (menu != NULL) {
190 caption = ui_menu_caption(menu);
191 width = gfx_text_width(res->font, caption) + 2 * hpad;
192 tpos.x = pos.x + hpad;
193 tpos.y = pos.y + vpad;
194
195 rect.p0 = pos;
196 rect.p1.x = rect.p0.x + width;
197 rect.p1.y = mbar->rect.p1.y;
198
199 if (menu == mbar->selected) {
200 fmt.color = res->wnd_sel_text_color;
201 bg_color = res->wnd_sel_text_bg_color;
202 } else {
203 fmt.color = res->wnd_text_color;
204 bg_color = res->wnd_face_color;
205 }
206
207 rc = gfx_set_color(res->gc, bg_color);
208 if (rc != EOK)
209 goto error;
210
211 rc = gfx_fill_rect(res->gc, &rect);
212 if (rc != EOK)
213 goto error;
214
215 rc = gfx_puttext(res->font, &tpos, &fmt, caption);
216 if (rc != EOK)
217 goto error;
218
219 pos.x += width;
220 menu = ui_menu_next(menu);
221 }
222
223 rc = gfx_update(res->gc);
224 if (rc != EOK)
225 goto error;
226
227 return EOK;
228error:
229 return rc;
230}
231
232/** Select or deselect menu from menu bar.
233 *
234 * Select @a menu. If @a menu is @c NULL or it is already selected,
235 * then select none.
236 *
237 * @param mbar Menu bar
238 * @param rect Menu bar entry rectangle
239 * @param menu Menu to select (or deselect if selected) or @c NULL
240 */
241void ui_menu_bar_select(ui_menu_bar_t *mbar, gfx_rect_t *rect,
242 ui_menu_t *menu)
243{
244 ui_menu_t *old_menu;
245
246 old_menu = mbar->selected;
247
248 if (mbar->selected != menu)
249 mbar->selected = menu;
250 else
251 mbar->selected = NULL;
252
253 /* Close previously open menu */
254 if (old_menu != NULL)
255 (void) ui_menu_close(old_menu);
256
257 (void) ui_menu_bar_paint(mbar);
258
259 if (mbar->selected != NULL) {
260 (void) ui_menu_open(mbar->selected, rect);
261 }
262}
263
264/** Handle menu bar position event.
265 *
266 * @param mbar Menu bar
267 * @param pos_event Position event
268 * @return @c ui_claimed iff the event is claimed
269 */
270ui_evclaim_t ui_menu_bar_pos_event(ui_menu_bar_t *mbar, pos_event_t *event)
271{
272 ui_resource_t *res;
273 gfx_coord2_t pos;
274 gfx_rect_t rect;
275 ui_menu_t *menu;
276 const char *caption;
277 gfx_coord_t width;
278 gfx_coord_t hpad;
279 gfx_coord2_t ppos;
280
281 res = ui_window_get_res(mbar->window);
282
283 ppos.x = event->hpos;
284 ppos.y = event->vpos;
285
286 if (res->textmode) {
287 hpad = menubar_hpad_text;
288 } else {
289 hpad = menubar_hpad;
290 }
291
292 pos = mbar->rect.p0;
293
294 menu = ui_menu_first(mbar);
295 while (menu != NULL) {
296 caption = ui_menu_caption(menu);
297 width = gfx_text_width(res->font, caption) + 2 * hpad;
298
299 rect.p0 = pos;
300 rect.p1.x = rect.p0.x + width;
301 rect.p1.y = mbar->rect.p1.y;
302
303 /* Check if press is inside menu bar entry */
304 if (event->type == POS_PRESS &&
305 gfx_pix_inside_rect(&ppos, &rect)) {
306 ui_menu_bar_select(mbar, &rect, menu);
307 return ui_claimed;
308 }
309
310 pos.x += width;
311 menu = ui_menu_next(menu);
312 }
313
314 return ui_unclaimed;
315}
316
317/** Destroy menu bar control.
318 *
319 * @param arg Argument (ui_menu_bar_t *)
320 */
321void ui_menu_bar_ctl_destroy(void *arg)
322{
323 ui_menu_bar_t *mbar = (ui_menu_bar_t *) arg;
324
325 ui_menu_bar_destroy(mbar);
326}
327
328/** Paint menu bar control.
329 *
330 * @param arg Argument (ui_menu_bar_t *)
331 * @return EOK on success or an error code
332 */
333errno_t ui_menu_bar_ctl_paint(void *arg)
334{
335 ui_menu_bar_t *mbar = (ui_menu_bar_t *) arg;
336
337 return ui_menu_bar_paint(mbar);
338}
339
340/** Handle menu bar control position event.
341 *
342 * @param arg Argument (ui_menu_bar_t *)
343 * @param pos_event Position event
344 * @return @c ui_claimed iff the event is claimed
345 */
346ui_evclaim_t ui_menu_bar_ctl_pos_event(void *arg, pos_event_t *event)
347{
348 ui_menu_bar_t *mbar = (ui_menu_bar_t *) arg;
349
350 return ui_menu_bar_pos_event(mbar, event);
351}
352
353/** @}
354 */
Note: See TracBrowser for help on using the repository browser.