source: mainline/uspace/lib/gui/grid.c@ 516e780

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 516e780 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 9.6 KB
Line 
1/*
2 * Copyright (c) 2012 Petr Koupy
3 * Copyright (c) 2013 Martin Decky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup gui
31 * @{
32 */
33/**
34 * @file
35 */
36
37#include <assert.h>
38#include <mem.h>
39#include <stdlib.h>
40#include <surface.h>
41#include "window.h"
42#include "grid.h"
43
44typedef struct {
45 sysarg_t min;
46 sysarg_t max;
47 sysarg_t val;
48} constraints_t;
49
50static void paint_internal(widget_t *widget)
51{
52 grid_t *grid = (grid_t *) widget;
53
54 surface_t *surface = window_claim(grid->widget.window);
55 if (!surface) {
56 window_yield(grid->widget.window);
57 return;
58 }
59
60 // FIXME: Replace with (accelerated) rectangle fill
61 for (sysarg_t y = widget->vpos; y < widget->vpos + widget->height; y++) {
62 for (sysarg_t x = widget->hpos; x < widget->hpos + widget->width; x++)
63 surface_put_pixel(surface, x, y, grid->background);
64 }
65
66 window_yield(grid->widget.window);
67}
68
69static grid_cell_t *grid_cell_at(grid_t *grid, size_t col, size_t row)
70{
71 if ((col < grid->cols) && (row < grid->rows))
72 return grid->layout + (row * grid->cols + col);
73
74 return NULL;
75}
76
77static grid_cell_t *grid_coords_at(grid_t *grid, sysarg_t hpos, sysarg_t vpos)
78{
79 for (size_t c = 0; c < grid->cols; c++) {
80 for (size_t r = 0; r < grid->rows; r++) {
81 grid_cell_t *cell = grid_cell_at(grid, c, r);
82 if (cell) {
83 widget_t *widget = cell->widget;
84
85 if ((widget) && (hpos >= widget->hpos) &&
86 (vpos >= widget->vpos) &&
87 (hpos < widget->hpos + widget->width) &&
88 (vpos < widget->vpos + widget->height))
89 return cell;
90 }
91 }
92 }
93
94 return NULL;
95}
96
97void deinit_grid(grid_t *grid)
98{
99 widget_deinit(&grid->widget);
100 free(grid->layout);
101}
102
103static void grid_destroy(widget_t *widget)
104{
105 grid_t *grid = (grid_t *) widget;
106
107 deinit_grid(grid);
108 free(grid);
109}
110
111static void grid_reconfigure(widget_t *widget)
112{
113 /* No-op */
114}
115
116static void adjust_constraints(constraints_t *cons, size_t run,
117 sysarg_t dim_min, sysarg_t dim_max)
118{
119 assert(run > 0);
120
121 sysarg_t dim_min_part = dim_min / run;
122 sysarg_t dim_min_rem = dim_min % run;
123
124 sysarg_t dim_max_part = dim_max / run;
125 sysarg_t dim_max_rem = dim_max % run;
126
127 for (size_t i = 0; i < run; i++) {
128 sysarg_t dim_min_cur = dim_min_part;
129 sysarg_t dim_max_cur = dim_max_part;
130
131 if (i == run - 1) {
132 dim_min_cur += dim_min_rem;
133 dim_max_cur += dim_max_rem;
134 }
135
136 /*
137 * We want the strongest constraint
138 * for the minimum.
139 */
140 if (cons[i].min < dim_min_cur)
141 cons[i].min = dim_min_cur;
142
143 /*
144 * The comparison is correct, we want
145 * the weakest constraint for the
146 * maximum.
147 */
148 if (cons[i].max < dim_max_cur)
149 cons[i].max = dim_max_cur;
150 }
151}
152
153static void solve_constraints(constraints_t *cons, size_t run, sysarg_t sum)
154{
155 /* Initial solution */
156 sysarg_t cur_sum = 0;
157
158 for (size_t i = 0; i < run; i++) {
159 cons[i].val = cons[i].min;
160 cur_sum += cons[i].val;
161 }
162
163 /* Iterative improvement */
164 while (cur_sum < sum) {
165 sysarg_t delta = (sum - cur_sum) / run;
166 if (delta == 0)
167 break;
168
169 cur_sum = 0;
170
171 for (size_t i = 0; i < run; i++) {
172 if (cons[i].val + delta < cons[i].max)
173 cons[i].val += delta;
174
175 cur_sum += cons[i].val;
176 }
177 }
178}
179
180static void grid_rearrange(widget_t *widget, sysarg_t hpos, sysarg_t vpos,
181 sysarg_t width, sysarg_t height)
182{
183 grid_t *grid = (grid_t *) widget;
184
185 widget_modify(widget, hpos, vpos, width, height);
186 paint_internal(widget);
187
188 /* Compute column widths */
189 constraints_t *widths =
190 (constraints_t *) calloc(grid->cols, sizeof(constraints_t));
191 if (widths) {
192 /* Constrain widths */
193 for (size_t c = 0; c < grid->cols; c++) {
194 widths[c].min = 0;
195
196 for (size_t r = 0; r < grid->rows; r++) {
197 grid_cell_t *cell = grid_cell_at(grid, c, r);
198 if (!cell)
199 continue;
200
201 widget_t *widget = cell->widget;
202 if (widget)
203 adjust_constraints(&widths[c], cell->cols,
204 widget->width_min, widget->width_max);
205 }
206 }
207
208 solve_constraints(widths, grid->cols, width);
209 }
210
211 /* Compute row heights */
212 constraints_t *heights =
213 (constraints_t *) calloc(grid->rows, sizeof(constraints_t));
214 if (heights) {
215 /* Constrain heights */
216 for (size_t r = 0; r < grid->rows; r++) {
217 heights[r].min = 0;
218
219 for (size_t c = 0; c < grid->cols; c++) {
220 grid_cell_t *cell = grid_cell_at(grid, c, r);
221 if (!cell)
222 continue;
223
224 widget_t *widget = cell->widget;
225 if (widget) {
226 adjust_constraints(&heights[r], cell->rows,
227 widget->height_min, widget->height_max);
228 }
229 }
230 }
231
232 solve_constraints(heights, grid->rows, height);
233 }
234
235 /* Rearrange widgets */
236 if ((widths) && (heights)) {
237 sysarg_t cur_vpos = vpos;
238
239 for (size_t r = 0; r < grid->rows; r++) {
240 sysarg_t cur_hpos = hpos;
241
242 for (size_t c = 0; c < grid->cols; c++) {
243 grid_cell_t *cell = grid_cell_at(grid, c, r);
244 if (!cell)
245 continue;
246
247 widget_t *widget = cell->widget;
248 if (widget) {
249 sysarg_t cur_width = 0;
250 sysarg_t cur_height = 0;
251
252 for (size_t cd = 0; cd < cell->cols; cd++)
253 cur_width += widths[c + cd].val;
254
255 for (size_t rd = 0; rd < cell->rows; rd++)
256 cur_height += heights[r + rd].val;
257
258 if ((cur_width > 0) && (cur_height > 0)) {
259 sysarg_t wwidth = cur_width;
260 sysarg_t wheight = cur_height;
261
262 /*
263 * Make sure the widget is respects its
264 * maximal constrains.
265 */
266
267 if ((widget->width_max > 0) &&
268 (wwidth > widget->width_max))
269 wwidth = widget->width_max;
270
271 if ((widget->height_max > 0) &&
272 (wheight > widget->height_max))
273 wheight = widget->height_max;
274
275 widget->rearrange(widget, cur_hpos, cur_vpos,
276 wwidth, wheight);
277 }
278
279
280 }
281
282 cur_hpos += widths[c].val;
283 }
284
285 cur_vpos += heights[r].val;
286 }
287 }
288
289 if (widths)
290 free(widths);
291
292 if (heights)
293 free(heights);
294}
295
296static void grid_repaint(widget_t *widget)
297{
298 paint_internal(widget);
299
300 list_foreach(widget->children, link, widget_t, child) {
301 child->repaint(child);
302 }
303
304 window_damage(widget->window);
305}
306
307static void grid_handle_keyboard_event(widget_t *widget, kbd_event_t event)
308{
309 /* No-op */
310}
311
312static void grid_handle_position_event(widget_t *widget, pos_event_t event)
313{
314 grid_t *grid = (grid_t *) widget;
315
316 grid_cell_t *cell = grid_coords_at(grid, event.hpos, event.vpos);
317 if ((cell) && (cell->widget))
318 cell->widget->handle_position_event(cell->widget, event);
319}
320
321static bool grid_add(struct grid *grid, widget_t *widget, size_t col,
322 size_t row, size_t cols, size_t rows)
323{
324 if ((cols == 0) || (rows == 0) || (col + cols > grid->cols) ||
325 (row + rows > grid->rows))
326 return false;
327
328 grid_cell_t *cell = grid_cell_at(grid, col, row);
329 if (!cell)
330 return false;
331
332 /*
333 * Check whether the cell is not occupied by an
334 * extension of a different cell.
335 */
336 if ((!cell->widget) && (cell->cols > 0) && (cell->rows > 0))
337 return false;
338
339 widget->parent = (widget_t *) grid;
340
341 list_append(&widget->link, &grid->widget.children);
342 widget->window = grid->widget.window;
343
344 /* Mark cells in layout */
345 for (size_t r = row; r < row + rows; r++) {
346 for (size_t c = col; c < col + cols; c++) {
347 if ((r == row) && (c == col)) {
348 cell->widget = widget;
349 cell->cols = cols;
350 cell->rows = rows;
351 } else {
352 grid_cell_t *extension = grid_cell_at(grid, c, r);
353 if (extension) {
354 extension->widget = NULL;
355 extension->cols = 1;
356 extension->rows = 1;
357 }
358 }
359 }
360 }
361
362 return true;
363}
364
365bool init_grid(grid_t *grid, widget_t *parent, const void *data, size_t cols,
366 size_t rows, pixel_t background)
367{
368 if ((cols == 0) || (rows == 0))
369 return false;
370
371 grid->layout =
372 (grid_cell_t *) calloc(cols * rows, sizeof(grid_cell_t));
373 if (!grid->layout)
374 return false;
375
376 memset(grid->layout, 0, cols * rows * sizeof(grid_cell_t));
377
378 widget_init(&grid->widget, parent, data);
379
380 grid->widget.destroy = grid_destroy;
381 grid->widget.reconfigure = grid_reconfigure;
382 grid->widget.rearrange = grid_rearrange;
383 grid->widget.repaint = grid_repaint;
384 grid->widget.handle_keyboard_event = grid_handle_keyboard_event;
385 grid->widget.handle_position_event = grid_handle_position_event;
386
387 grid->add = grid_add;
388 grid->background = background;
389 grid->cols = cols;
390 grid->rows = rows;
391
392 return true;
393}
394
395grid_t *create_grid(widget_t *parent, const void *data, size_t cols,
396 size_t rows, pixel_t background)
397{
398 grid_t *grid = (grid_t *) malloc(sizeof(grid_t));
399 if (!grid)
400 return NULL;
401
402 if (init_grid(grid, parent, data, cols, rows, background))
403 return grid;
404
405 free(grid);
406 return NULL;
407}
408
409/** @}
410 */
Note: See TracBrowser for help on using the repository browser.