source: mainline/uspace/lib/ui/src/pbutton.c@ c9a7adc

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

3D button frame

  • Property mode set to 100644
File size: 9.1 KB
Line 
1/*
2 * Copyright (c) 2020 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 Push button
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 <stdlib.h>
42#include <str.h>
43#include <ui/pbutton.h>
44#include "../private/pbutton.h"
45#include "../private/resource.h"
46
47/** Caption movement when button is pressed down */
48enum {
49 ui_pb_press_dx = 1,
50 ui_pb_press_dy = 1
51};
52
53/** Create new push button.
54 *
55 * @param resource UI resource
56 * @param caption Caption
57 * @param rpbutton Place to store pointer to new push button
58 * @return EOK on success, ENOMEM if out of memory
59 */
60errno_t ui_pbutton_create(ui_resource_t *resource, const char *caption,
61 ui_pbutton_t **rpbutton)
62{
63 ui_pbutton_t *pbutton;
64
65 pbutton = calloc(1, sizeof(ui_pbutton_t));
66 if (pbutton == NULL)
67 return ENOMEM;
68
69 pbutton->caption = str_dup(caption);
70 if (pbutton->caption == NULL) {
71 free(pbutton);
72 return ENOMEM;
73 }
74
75 pbutton->res = resource;
76 *rpbutton = pbutton;
77 return EOK;
78}
79
80/** Destroy push button.
81 *
82 * @param pbutton Push button or @c NULL
83 */
84void ui_pbutton_destroy(ui_pbutton_t *pbutton)
85{
86 if (pbutton == NULL)
87 return;
88
89 free(pbutton);
90}
91
92/** Set button rectangle.
93 *
94 * @param pbutton Button
95 * @param rect New button rectanle
96 */
97void ui_pbutton_set_rect(ui_pbutton_t *pbutton, gfx_rect_t *rect)
98{
99 pbutton->rect = *rect;
100}
101
102/** Set default flag.
103 *
104 * Default button is the one activated by Enter key, it is marked
105 * by thicker frame.
106 *
107 * @param pbutton Button
108 * @param isdefault @c true iff button is default
109 */
110void ui_pbutton_set_default(ui_pbutton_t *pbutton, bool isdefault)
111{
112 pbutton->isdefault = isdefault;
113}
114
115/** Paint outer button frame.
116 *
117 * @param pbutton Push button
118 * @return EOK on success or an error code
119 */
120static errno_t ui_pbutton_paint_frame(ui_pbutton_t *pbutton)
121{
122 gfx_color_t *color = NULL;
123 gfx_rect_t rect;
124 gfx_coord_t thickness;
125 errno_t rc;
126
127 thickness = pbutton->isdefault ? 2 : 1;
128
129 rc = gfx_color_new_rgb_i16(0, 0, 0, &color);
130 if (rc != EOK)
131 goto error;
132
133 rc = gfx_set_color(pbutton->res->gc, color);
134 if (rc != EOK)
135 goto error;
136
137 rect.p0.x = pbutton->rect.p0.x + 1;
138 rect.p0.y = pbutton->rect.p0.y;
139 rect.p1.x = pbutton->rect.p1.x - 1;
140 rect.p1.y = pbutton->rect.p0.y + thickness;
141 rc = gfx_fill_rect(pbutton->res->gc, &rect);
142 if (rc != EOK)
143 goto error;
144
145 rect.p0.x = pbutton->rect.p0.x + 1;
146 rect.p0.y = pbutton->rect.p1.y - thickness;
147 rect.p1.x = pbutton->rect.p1.x - 1;
148 rect.p1.y = pbutton->rect.p1.y;
149 rc = gfx_fill_rect(pbutton->res->gc, &rect);
150 if (rc != EOK)
151 goto error;
152
153 rect.p0.x = pbutton->rect.p0.x;
154 rect.p0.y = pbutton->rect.p0.y + 1;
155 rect.p1.x = pbutton->rect.p0.x + thickness;
156 rect.p1.y = pbutton->rect.p1.y - 1;
157 rc = gfx_fill_rect(pbutton->res->gc, &rect);
158 if (rc != EOK)
159 goto error;
160
161 rect.p0.x = pbutton->rect.p1.x - thickness;
162 rect.p0.y = pbutton->rect.p0.y + 1;
163 rect.p1.x = pbutton->rect.p1.x;
164 rect.p1.y = pbutton->rect.p1.y - 1;
165 rc = gfx_fill_rect(pbutton->res->gc, &rect);
166 if (rc != EOK)
167 goto error;
168
169 gfx_color_delete(color);
170 return EOK;
171error:
172 if (color != NULL)
173 gfx_color_delete(color);
174 return rc;
175}
176
177/** Paint outset button bevel.
178 *
179 * @param pbutton Push button
180 * @return EOK on success or an error code
181 */
182static errno_t ui_pbutton_paint_outset(ui_pbutton_t *pbutton,
183 gfx_rect_t *rect)
184{
185 gfx_color_t *color = NULL;
186 gfx_rect_t frect;
187 gfx_coord_t i;
188 errno_t rc;
189
190 /* Highlight */
191
192 rc = gfx_color_new_rgb_i16(0xffff, 0xffff, 0xffff, &color);
193 if (rc != EOK)
194 goto error;
195
196 rc = gfx_set_color(pbutton->res->gc, color);
197 if (rc != EOK)
198 goto error;
199
200 for (i = 0; i < 2; i++) {
201 frect.p0.x = rect->p0.x + i;
202 frect.p0.y = rect->p0.y + i;
203 frect.p1.x = rect->p1.x - i - 1;
204 frect.p1.y = rect->p0.y + i + 1;
205 rc = gfx_fill_rect(pbutton->res->gc, &frect);
206 if (rc != EOK)
207 goto error;
208
209 frect.p0.x = rect->p0.x + i;
210 frect.p0.y = rect->p0.y + i + 1;
211 frect.p1.x = rect->p0.x + i + 1;
212 frect.p1.y = rect->p1.y - i - 1;
213 rc = gfx_fill_rect(pbutton->res->gc, &frect);
214 if (rc != EOK)
215 goto error;
216 }
217
218 gfx_color_delete(color);
219 color = NULL;
220
221 /* Shadow */
222
223 rc = gfx_color_new_rgb_i16(0x8888, 0x8888, 0x8888, &color);
224 if (rc != EOK)
225 goto error;
226
227 rc = gfx_set_color(pbutton->res->gc, color);
228 if (rc != EOK)
229 goto error;
230
231 for (i = 0; i < 2; i++) {
232 frect.p0.x = rect->p0.x + i;
233 frect.p0.y = rect->p1.y - i - 1;
234 frect.p1.x = rect->p1.x - i - 1;
235 frect.p1.y = rect->p1.y - i;
236 rc = gfx_fill_rect(pbutton->res->gc, &frect);
237 if (rc != EOK)
238 goto error;
239
240 frect.p0.x = rect->p1.x - i - 1;
241 frect.p0.y = rect->p0.y + i;
242 frect.p1.x = rect->p1.x - i;
243 frect.p1.y = rect->p1.y - i;
244 rc = gfx_fill_rect(pbutton->res->gc, &frect);
245 if (rc != EOK)
246 goto error;
247 }
248
249 gfx_color_delete(color);
250
251 return EOK;
252error:
253 if (color != NULL)
254 gfx_color_delete(color);
255 return rc;
256}
257
258/** Paint inset button bevel.
259 *
260 * @param pbutton Push button
261 * @return EOK on success or an error code
262 */
263static errno_t ui_pbutton_paint_inset(ui_pbutton_t *pbutton,
264 gfx_rect_t *rect)
265{
266 gfx_color_t *color = NULL;
267 gfx_rect_t frect;
268 errno_t rc;
269
270 rc = gfx_color_new_rgb_i16(0x8888, 0x8888, 0x8888, &color);
271 if (rc != EOK)
272 goto error;
273
274 rc = gfx_set_color(pbutton->res->gc, color);
275 if (rc != EOK)
276 goto error;
277
278 frect.p0.x = rect->p0.x;
279 frect.p0.y = rect->p0.y;
280 frect.p1.x = rect->p1.x;
281 frect.p1.y = rect->p0.y + 2;
282 rc = gfx_fill_rect(pbutton->res->gc, &frect);
283 if (rc != EOK)
284 goto error;
285
286 frect.p0.x = rect->p0.x;
287 frect.p0.y = rect->p0.y + 2;
288 frect.p1.x = rect->p0.x + 2;
289 frect.p1.y = rect->p1.y;
290 rc = gfx_fill_rect(pbutton->res->gc, &frect);
291 if (rc != EOK)
292 goto error;
293
294 gfx_color_delete(color);
295
296 return EOK;
297error:
298 if (color != NULL)
299 gfx_color_delete(color);
300 return rc;
301}
302
303/** Paint push button.
304 *
305 * @param pbutton Push button
306 * @return EOK on success or an error code
307 */
308errno_t ui_pbutton_paint(ui_pbutton_t *pbutton)
309{
310 gfx_color_t *color = NULL;
311 gfx_coord2_t pos;
312 gfx_text_fmt_t fmt;
313 gfx_rect_t rect;
314 gfx_coord_t thickness;
315 errno_t rc;
316
317 thickness = pbutton->isdefault ? 2 : 1;
318
319 rect.p0.x = pbutton->rect.p0.x + thickness;
320 rect.p0.y = pbutton->rect.p0.y + thickness;
321 rect.p1.x = pbutton->rect.p1.x - thickness;
322 rect.p1.y = pbutton->rect.p1.y - thickness;
323
324 rc = gfx_color_new_rgb_i16(0xc8c8, 0xc8c8, 0xc8c8, &color);
325 if (rc != EOK)
326 goto error;
327
328 rc = gfx_set_color(pbutton->res->gc, color);
329 if (rc != EOK)
330 goto error;
331
332 rc = gfx_fill_rect(pbutton->res->gc, &rect);
333 if (rc != EOK)
334 goto error;
335
336 gfx_color_delete(color);
337 color = NULL;
338
339 rc = gfx_color_new_rgb_i16(0, 0, 0, &color);
340 if (rc != EOK)
341 goto error;
342
343 rc = gfx_set_color(pbutton->res->gc, color);
344 if (rc != EOK)
345 goto error;
346
347 /* Center of button rectangle */
348 pos.x = (rect.p0.x + rect.p1.x) / 2;
349 pos.y = (rect.p0.y + rect.p1.y) / 2;
350
351 if (pbutton->held) {
352 pos.x += ui_pb_press_dx;
353 pos.y += ui_pb_press_dy;
354 }
355
356 gfx_text_fmt_init(&fmt);
357 fmt.halign = gfx_halign_center;
358 fmt.valign = gfx_valign_center;
359
360 rc = gfx_puttext(pbutton->res->font, &pos, &fmt, pbutton->caption);
361 if (rc != EOK)
362 goto error;
363
364 gfx_color_delete(color);
365 color = NULL;
366
367 rc = ui_pbutton_paint_frame(pbutton);
368 if (rc != EOK)
369 goto error;
370
371 if (pbutton->held) {
372 rc = ui_pbutton_paint_inset(pbutton, &rect);
373 if (rc != EOK)
374 goto error;
375 } else {
376 rc = ui_pbutton_paint_outset(pbutton, &rect);
377 if (rc != EOK)
378 goto error;
379 }
380
381 return EOK;
382error:
383 if (color != NULL)
384 gfx_color_delete(color);
385 return rc;
386}
387
388/** Press down button.
389 *
390 * This does not automatically repaint the button.
391 *
392 * @param pbutton Push button
393 */
394void ui_pbutton_press(ui_pbutton_t *pbutton)
395{
396 pbutton->held = true;
397}
398
399/** Release button.
400 *
401 * This does not automatically repaint the button.
402 *
403 * @param pbutton Push button
404 */
405void ui_pbutton_release(ui_pbutton_t *pbutton)
406{
407 pbutton->held = false;
408}
409
410/** @}
411 */
Note: See TracBrowser for help on using the repository browser.