source: mainline/uspace/lib/ui/src/paint.c@ b0858150

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

Radio button

Please don't ask me how I derived the formulae for circle midpoint
algorithm, it's been 8 years and I just don't remember.

  • Property mode set to 100644
File size: 6.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 Painting routines
34 */
35
36#include <errno.h>
37#include <gfx/color.h>
38#include <gfx/context.h>
39#include <gfx/render.h>
40#include <ui/paint.h>
41#include "../private/resource.h"
42
43/** Paint bevel.
44 *
45 * @param gc Graphic context
46 * @param rect Rectangle to paint into
47 * @param tlcolor Top-left color
48 * @param brcolor Bottom-right color
49 * @param thickness Bevel thickness in pixels
50 * @param inside Place to store rectangle of the interior or @c NULL
51 * @reutrn EOK on success or an error code
52 */
53errno_t ui_paint_bevel(gfx_context_t *gc, gfx_rect_t *rect,
54 gfx_color_t *tlcolor, gfx_color_t *brcolor, gfx_coord_t thickness,
55 gfx_rect_t *inside)
56{
57 gfx_rect_t frect;
58 gfx_coord_t i;
59 errno_t rc;
60
61 /* Top left */
62
63 rc = gfx_set_color(gc, tlcolor);
64 if (rc != EOK)
65 goto error;
66
67 for (i = 0; i < thickness; i++) {
68 frect.p0.x = rect->p0.x + i;
69 frect.p0.y = rect->p0.y + i;
70 frect.p1.x = rect->p1.x - i - 1;
71 frect.p1.y = rect->p0.y + i + 1;
72 rc = gfx_fill_rect(gc, &frect);
73 if (rc != EOK)
74 goto error;
75
76 frect.p0.x = rect->p0.x + i;
77 frect.p0.y = rect->p0.y + i + 1;
78 frect.p1.x = rect->p0.x + i + 1;
79 frect.p1.y = rect->p1.y - i - 1;
80 rc = gfx_fill_rect(gc, &frect);
81 if (rc != EOK)
82 goto error;
83 }
84
85 /* Bottom right */
86
87 rc = gfx_set_color(gc, brcolor);
88 if (rc != EOK)
89 goto error;
90
91 for (i = 0; i < thickness; i++) {
92 frect.p0.x = rect->p0.x + i;
93 frect.p0.y = rect->p1.y - i - 1;
94 frect.p1.x = rect->p1.x - i - 1;
95 frect.p1.y = rect->p1.y - i;
96 rc = gfx_fill_rect(gc, &frect);
97 if (rc != EOK)
98 goto error;
99
100 frect.p0.x = rect->p1.x - i - 1;
101 frect.p0.y = rect->p0.y + i;
102 frect.p1.x = rect->p1.x - i;
103 frect.p1.y = rect->p1.y - i;
104 rc = gfx_fill_rect(gc, &frect);
105 if (rc != EOK)
106 goto error;
107 }
108
109 if (inside != NULL) {
110 inside->p0.x = rect->p0.x + thickness;
111 inside->p0.y = rect->p0.y + thickness;
112 inside->p1.x = rect->p1.x - thickness;
113 inside->p1.y = rect->p1.y - thickness;
114 }
115
116 return EOK;
117error:
118 return rc;
119}
120
121/** Paint inset frame.
122 *
123 * @param resource UI resource
124 * @param rect Rectangle to paint onto
125 * @param inside Place to store inside rectangle or @c NULL
126 * @return EOK on success or an error code
127 */
128errno_t ui_paint_inset_frame(ui_resource_t *resource, gfx_rect_t *rect,
129 gfx_rect_t *inside)
130{
131 gfx_rect_t frame;
132 errno_t rc;
133
134 rc = ui_paint_bevel(resource->gc, rect,
135 resource->wnd_shadow_color, resource->wnd_highlight_color,
136 1, &frame);
137 if (rc != EOK)
138 goto error;
139
140 rc = ui_paint_bevel(resource->gc, &frame,
141 resource->wnd_frame_sh_color, resource->wnd_frame_hi_color,
142 1, inside);
143 if (rc != EOK)
144 goto error;
145
146 return EOK;
147error:
148 return rc;
149}
150
151/** Paint filled circle vertical scanline.
152 *
153 * @param gc Graphic context
154 * @param center Coordinates of the center of the circle
155 * @param x X-coordinate of the scanline
156 * @param y0 Lowest Y coordinate of the scanline (inclusive)
157 * @param y1 Highest Y coordinate of the scanline (inclusive)
158 * @param part Which part(s) of cicle to paint
159 * @return EOK on success or an error code
160 */
161static errno_t ui_paint_fcircle_line(gfx_context_t *gc, gfx_coord2_t *center,
162 gfx_coord_t x, gfx_coord_t y0, gfx_coord_t y1, ui_fcircle_part_t part)
163{
164 gfx_rect_t rect;
165 gfx_rect_t trect;
166
167 rect.p0.x = x;
168 rect.p0.y = y0;
169 rect.p1.x = x + 1;
170 rect.p1.y = y1;
171
172 /* Clip to upper-left/lower-right half of circle, if required */
173
174 if ((part & ui_fcircle_upleft) == 0) {
175 if (rect.p0.y < -rect.p1.x)
176 rect.p0.y = -rect.p1.x;
177 }
178
179 if ((part & ui_fcircle_lowright) == 0) {
180 if (rect.p1.y > -rect.p1.x)
181 rect.p1.y = -rect.p1.x;
182 }
183
184 /* If coordinates are reversed, there is nothing to do */
185 if (rect.p1.y <= rect.p0.y)
186 return EOK;
187
188 gfx_rect_translate(center, &rect, &trect);
189
190 return gfx_fill_rect(gc, &trect);
191}
192
193/** Paint filled circle scanlines corresponding to octant point.
194 *
195 * Fills the four vertical scanlines lying between the eight reflections
196 * of a circle point.
197 *
198 * @param gc Graphic context
199 * @param center Coordinates of the center
200 * @param r Radius in pixels
201 * @param part Which part(s) of cicle to paint
202 * @return EOK on success or an error code
203 */
204static int ui_paint_fcircle_point(gfx_context_t *gc, gfx_coord2_t *center,
205 gfx_coord2_t *p, ui_fcircle_part_t part)
206{
207 errno_t rc;
208
209 rc = ui_paint_fcircle_line(gc, center, +p->x, -p->y, p->y + 1, part);
210 if (rc != EOK)
211 return rc;
212 rc = ui_paint_fcircle_line(gc, center, -p->x, -p->y, p->y + 1, part);
213 if (rc != EOK)
214 return rc;
215 rc = ui_paint_fcircle_line(gc, center, +p->y, -p->x, p->x + 1, part);
216 if (rc != EOK)
217 return rc;
218 rc = ui_paint_fcircle_line(gc, center, -p->y, -p->x, p->x + 1, part);
219 if (rc != EOK)
220 return rc;
221
222 return EOK;
223}
224
225/** Paint a filled circle.
226 *
227 * @param gc Graphic context
228 * @param center Coordinates of the center
229 * @param r Radius in pixels
230 * @param part Which part(s) of cicle to paint
231 * @return EOK on success or an error code
232 */
233errno_t ui_paint_filled_circle(gfx_context_t *gc, gfx_coord2_t *center,
234 gfx_coord_t r, ui_fcircle_part_t part)
235{
236 gfx_coord2_t p;
237 gfx_coord_t f;
238 errno_t rc;
239
240 /* Run through one octant using circle midpoint algorithm */
241
242 p.x = r;
243 p.y = 0;
244 f = 1 - r;
245
246 rc = ui_paint_fcircle_point(gc, center, &p, part);
247 if (rc != EOK)
248 return rc;
249
250 while (p.x > p.y) {
251 if (f < 0) {
252 f = f + 2 * p.y + 3;
253 } else {
254 f = f + 2 * (p.y - p.x) + 5;
255 --p.x;
256 }
257 ++p.y;
258
259 rc = ui_paint_fcircle_point(gc, center, &p, part);
260 if (rc != EOK)
261 return rc;
262 }
263
264 return EOK;
265}
266
267/** @}
268 */
Note: See TracBrowser for help on using the repository browser.