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

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

Support double-click

Needed to open Navigator entries using the mouse.

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