source: mainline/uspace/lib/ui/src/checkbox.c@ e229148

Last change on this file since e229148 was 806d761, checked in by Jiri Svoboda <jiri@…>, 17 months ago

Start menu should have 'open in terminal' functionality

Makes it easier for the user and if we are running in console mode,
we correctly start the application, instead of failing to start a
terminal.

  • Property mode set to 100644
File size: 10.2 KB
Line 
1/*
2 * Copyright (c) 2024 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 Check box
34 */
35
36#include <errno.h>
37#include <gfx/color.h>
38#include <gfx/context.h>
39#include <gfx/render.h>
40#include <gfx/text.h>
41#include <io/pos_event.h>
42#include <stdlib.h>
43#include <str.h>
44#include <ui/control.h>
45#include <ui/paint.h>
46#include <ui/checkbox.h>
47#include "../private/checkbox.h"
48#include "../private/resource.h"
49
50enum {
51 checkbox_box_w = 16,
52 checkbox_box_h = 16,
53 checkbox_label_margin = 8,
54 checkbox_cross_n = 5,
55 checkbox_cross_w = 2,
56 checkbox_cross_h = 2
57};
58
59static void ui_checkbox_ctl_destroy(void *);
60static errno_t ui_checkbox_ctl_paint(void *);
61static ui_evclaim_t ui_checkbox_ctl_pos_event(void *, pos_event_t *);
62
63/** Check box control ops */
64ui_control_ops_t ui_checkbox_ops = {
65 .destroy = ui_checkbox_ctl_destroy,
66 .paint = ui_checkbox_ctl_paint,
67 .pos_event = ui_checkbox_ctl_pos_event
68};
69
70/** Create new check box.
71 *
72 * @param resource UI resource
73 * @param caption Caption
74 * @param rcheckbox Place to store pointer to new check box
75 * @return EOK on success, ENOMEM if out of memory
76 */
77errno_t ui_checkbox_create(ui_resource_t *resource, const char *caption,
78 ui_checkbox_t **rcheckbox)
79{
80 ui_checkbox_t *checkbox;
81 errno_t rc;
82
83 checkbox = calloc(1, sizeof(ui_checkbox_t));
84 if (checkbox == NULL)
85 return ENOMEM;
86
87 rc = ui_control_new(&ui_checkbox_ops, (void *) checkbox,
88 &checkbox->control);
89 if (rc != EOK) {
90 free(checkbox);
91 return rc;
92 }
93
94 checkbox->caption = str_dup(caption);
95 if (checkbox->caption == NULL) {
96 ui_control_delete(checkbox->control);
97 free(checkbox);
98 return ENOMEM;
99 }
100
101 checkbox->res = resource;
102 *rcheckbox = checkbox;
103 return EOK;
104}
105
106/** Destroy check box.
107 *
108 * @param checkbox Check box or @c NULL
109 */
110void ui_checkbox_destroy(ui_checkbox_t *checkbox)
111{
112 if (checkbox == NULL)
113 return;
114
115 ui_control_delete(checkbox->control);
116 free(checkbox);
117}
118
119/** Get base control from check box.
120 *
121 * @param checkbox Check box
122 * @return Control
123 */
124ui_control_t *ui_checkbox_ctl(ui_checkbox_t *checkbox)
125{
126 return checkbox->control;
127}
128
129/** Set check box callbacks.
130 *
131 * @param checkbox Check box
132 * @param cb Check box callbacks
133 * @param arg Callback argument
134 */
135void ui_checkbox_set_cb(ui_checkbox_t *checkbox, ui_checkbox_cb_t *cb, void *arg)
136{
137 checkbox->cb = cb;
138 checkbox->arg = arg;
139}
140
141/** Set check box rectangle.
142 *
143 * @param checkbox Check box
144 * @param rect New check box rectangle
145 */
146void ui_checkbox_set_rect(ui_checkbox_t *checkbox, gfx_rect_t *rect)
147{
148 checkbox->rect = *rect;
149}
150
151/** Return if check box is checked.
152 *
153 * @param checkbox Check box
154 * @return @c true iff check box is checked
155 */
156bool ui_checkbox_get_checked(ui_checkbox_t *checkbox)
157{
158 return checkbox->checked;
159}
160
161/** Set check box checked state.
162 *
163 * @param checkbox Check box
164 * @param checked @c true iff checkbox should be checked
165 */
166void ui_checkbox_set_checked(ui_checkbox_t *checkbox, bool checked)
167{
168 checkbox->checked = checked;
169}
170
171/** Paint check box in graphics mode.
172 *
173 * @param checkbox Check box
174 * @return EOK on success or an error code
175 */
176errno_t ui_checkbox_paint_gfx(ui_checkbox_t *checkbox)
177{
178 gfx_coord2_t pos;
179 gfx_text_fmt_t fmt;
180 gfx_rect_t box_rect;
181 gfx_rect_t box_inside;
182 gfx_coord2_t box_center;
183 bool depressed;
184 errno_t rc;
185
186 box_rect.p0 = checkbox->rect.p0;
187 box_rect.p1.x = box_rect.p0.x + checkbox_box_w;
188 box_rect.p1.y = box_rect.p0.y + checkbox_box_h;
189
190 /* Paint checkbox frame */
191
192 rc = ui_paint_inset_frame(checkbox->res, &box_rect, &box_inside);
193 if (rc != EOK)
194 goto error;
195
196 /* Paint checkbox interior */
197
198 depressed = checkbox->held && checkbox->inside;
199
200 rc = gfx_set_color(checkbox->res->gc, depressed ?
201 checkbox->res->entry_act_bg_color :
202 checkbox->res->entry_bg_color);
203 if (rc != EOK)
204 goto error;
205
206 rc = gfx_fill_rect(checkbox->res->gc, &box_inside);
207 if (rc != EOK)
208 goto error;
209
210 /* Paint cross mark */
211
212 if (checkbox->checked) {
213 rc = gfx_set_color(checkbox->res->gc,
214 checkbox->res->entry_fg_color);
215 if (rc != EOK)
216 goto error;
217
218 box_center.x = (box_inside.p0.x + box_inside.p1.x) / 2 - 1;
219 box_center.y = (box_inside.p0.y + box_inside.p1.y) / 2 - 1;
220
221 rc = ui_paint_cross(checkbox->res->gc, &box_center,
222 checkbox_cross_n, checkbox_cross_w, checkbox_cross_h);
223 if (rc != EOK)
224 goto error;
225 }
226
227 /* Paint checkbox label */
228
229 pos.x = box_rect.p1.x + checkbox_label_margin;
230 pos.y = (box_rect.p0.y + box_rect.p1.y) / 2;
231
232 gfx_text_fmt_init(&fmt);
233 fmt.font = checkbox->res->font;
234 fmt.color = checkbox->res->wnd_text_color;
235 fmt.halign = gfx_halign_left;
236 fmt.valign = gfx_valign_center;
237
238 rc = gfx_puttext(&pos, &fmt, checkbox->caption);
239 if (rc != EOK)
240 goto error;
241
242 rc = gfx_update(checkbox->res->gc);
243 if (rc != EOK)
244 goto error;
245
246 return EOK;
247error:
248 return rc;
249}
250
251/** Paint check box in text mode.
252 *
253 * @param checkbox Check box
254 * @return EOK on success or an error code
255 */
256errno_t ui_checkbox_paint_text(ui_checkbox_t *checkbox)
257{
258 gfx_coord2_t pos;
259 gfx_text_fmt_t fmt;
260 bool depressed;
261 errno_t rc;
262
263 /* Paint checkbox */
264
265 depressed = checkbox->held && checkbox->inside;
266
267 pos.x = checkbox->rect.p0.x;
268 pos.y = checkbox->rect.p0.y;
269
270 gfx_text_fmt_init(&fmt);
271 fmt.font = checkbox->res->font;
272 fmt.color = depressed ? checkbox->res->entry_act_bg_color :
273 checkbox->res->wnd_text_color;
274 fmt.halign = gfx_halign_left;
275 fmt.valign = gfx_valign_top;
276
277 rc = gfx_puttext(&pos, &fmt, checkbox->checked ? "[X]" : "[ ]");
278 if (rc != EOK)
279 goto error;
280
281 /* Paint checkbox label */
282
283 pos.x += 4;
284 fmt.color = checkbox->res->wnd_text_color;
285
286 rc = gfx_puttext(&pos, &fmt, checkbox->caption);
287 if (rc != EOK)
288 goto error;
289
290 rc = gfx_update(checkbox->res->gc);
291 if (rc != EOK)
292 goto error;
293
294 return EOK;
295error:
296 return rc;
297}
298
299/** Paint check box.
300 *
301 * @param checkbox Check box
302 * @return EOK on success or an error code
303 */
304errno_t ui_checkbox_paint(ui_checkbox_t *checkbox)
305{
306 if (checkbox->res->textmode)
307 return ui_checkbox_paint_text(checkbox);
308 else
309 return ui_checkbox_paint_gfx(checkbox);
310}
311
312/** Press down button.
313 *
314 * @param checkbox Check box
315 */
316void ui_checkbox_press(ui_checkbox_t *checkbox)
317{
318 if (checkbox->held)
319 return;
320
321 checkbox->inside = true;
322 checkbox->held = true;
323 (void) ui_checkbox_paint(checkbox);
324}
325
326/** Release button.
327 *
328 * @param checkbox Check box
329 */
330void ui_checkbox_release(ui_checkbox_t *checkbox)
331{
332 if (!checkbox->held)
333 return;
334
335 checkbox->held = false;
336
337 if (checkbox->inside) {
338 /* Toggle check box state */
339 checkbox->checked = !checkbox->checked;
340
341 /* Repaint and notify */
342 (void) ui_checkbox_paint(checkbox);
343 ui_checkbox_switched(checkbox);
344 }
345}
346
347/** Pointer entered button.
348 *
349 * @param checkbox Check box
350 */
351void ui_checkbox_enter(ui_checkbox_t *checkbox)
352{
353 if (checkbox->inside)
354 return;
355
356 checkbox->inside = true;
357 if (checkbox->held)
358 (void) ui_checkbox_paint(checkbox);
359}
360
361/** Pointer left button.
362 *
363 * @param checkbox Check box
364 */
365void ui_checkbox_leave(ui_checkbox_t *checkbox)
366{
367 if (!checkbox->inside)
368 return;
369
370 checkbox->inside = false;
371 if (checkbox->held)
372 (void) ui_checkbox_paint(checkbox);
373}
374
375/** Button was switched.
376 *
377 * @param checkbox Check box
378 */
379void ui_checkbox_switched(ui_checkbox_t *checkbox)
380{
381 if (checkbox->cb != NULL && checkbox->cb->switched != NULL) {
382 checkbox->cb->switched(checkbox, checkbox->arg,
383 checkbox->checked);
384 }
385}
386
387/** Handle check box position event.
388 *
389 * @param checkbox Check box
390 * @param pos_event Position event
391 * @return @c ui_claimed iff the event is claimed
392 */
393ui_evclaim_t ui_checkbox_pos_event(ui_checkbox_t *checkbox, pos_event_t *event)
394{
395 gfx_coord2_t pos;
396 bool inside;
397
398 pos.x = event->hpos;
399 pos.y = event->vpos;
400
401 inside = gfx_pix_inside_rect(&pos, &checkbox->rect);
402
403 switch (event->type) {
404 case POS_PRESS:
405 if (inside) {
406 ui_checkbox_press(checkbox);
407 return ui_claimed;
408 }
409 break;
410 case POS_RELEASE:
411 if (checkbox->held) {
412 ui_checkbox_release(checkbox);
413 return ui_claimed;
414 }
415 break;
416 case POS_UPDATE:
417 if (inside && !checkbox->inside) {
418 ui_checkbox_enter(checkbox);
419 return ui_claimed;
420 } else if (!inside && checkbox->inside) {
421 ui_checkbox_leave(checkbox);
422 }
423 break;
424 case POS_DCLICK:
425 break;
426 }
427
428 return ui_unclaimed;
429}
430
431/** Destroy check box control.
432 *
433 * @param arg Argument (ui_checkbox_t *)
434 */
435void ui_checkbox_ctl_destroy(void *arg)
436{
437 ui_checkbox_t *checkbox = (ui_checkbox_t *) arg;
438
439 ui_checkbox_destroy(checkbox);
440}
441
442/** Paint check box control.
443 *
444 * @param arg Argument (ui_checkbox_t *)
445 * @return EOK on success or an error code
446 */
447errno_t ui_checkbox_ctl_paint(void *arg)
448{
449 ui_checkbox_t *checkbox = (ui_checkbox_t *) arg;
450
451 return ui_checkbox_paint(checkbox);
452}
453
454/** Handle check box control position event.
455 *
456 * @param arg Argument (ui_checkbox_t *)
457 * @param pos_event Position event
458 * @return @c ui_claimed iff the event is claimed
459 */
460ui_evclaim_t ui_checkbox_ctl_pos_event(void *arg, pos_event_t *event)
461{
462 ui_checkbox_t *checkbox = (ui_checkbox_t *) arg;
463
464 return ui_checkbox_pos_event(checkbox, event);
465}
466
467/** @}
468 */
Note: See TracBrowser for help on using the repository browser.