source: mainline/uspace/lib/ui/src/menubar.c@ 3c8c580

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

Open menu in separate popup window (WIP)

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