source: mainline/uspace/lib/gui/grid.c@ 09553a0

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 09553a0 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
RevLine 
[6d5e378]1/*
2 * Copyright (c) 2012 Petr Koupy
[e63c424f]3 * Copyright (c) 2013 Martin Decky
[6d5e378]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>
[38d150e]39#include <stdlib.h>
[6d5e378]40#include <surface.h>
41#include "window.h"
42#include "grid.h"
43
[e63c424f]44typedef struct {
45 sysarg_t min;
46 sysarg_t max;
47 sysarg_t val;
48} constraints_t;
[6d5e378]49
[e63c424f]50static void paint_internal(widget_t *widget)
51{
52 grid_t *grid = (grid_t *) widget;
[a35b458]53
[6d5e378]54 surface_t *surface = window_claim(grid->widget.window);
55 if (!surface) {
56 window_yield(grid->widget.window);
[e63c424f]57 return;
[6d5e378]58 }
[a35b458]59
[e63c424f]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++)
[6d5e378]63 surface_put_pixel(surface, x, y, grid->background);
64 }
[a35b458]65
[6d5e378]66 window_yield(grid->widget.window);
67}
68
[e63c424f]69static grid_cell_t *grid_cell_at(grid_t *grid, size_t col, size_t row)
[6d5e378]70{
[e63c424f]71 if ((col < grid->cols) && (row < grid->rows))
[6d5e378]72 return grid->layout + (row * grid->cols + col);
[a35b458]73
[e63c424f]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;
[a35b458]84
[e63c424f]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 }
[6d5e378]92 }
[a35b458]93
[e63c424f]94 return NULL;
[6d5e378]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;
[a35b458]106
[6d5e378]107 deinit_grid(grid);
108 free(grid);
109}
110
111static void grid_reconfigure(widget_t *widget)
112{
[e63c424f]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);
[a35b458]120
[e63c424f]121 sysarg_t dim_min_part = dim_min / run;
122 sysarg_t dim_min_rem = dim_min % run;
[a35b458]123
[e63c424f]124 sysarg_t dim_max_part = dim_max / run;
125 sysarg_t dim_max_rem = dim_max % run;
[a35b458]126
[e63c424f]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;
[a35b458]130
[e63c424f]131 if (i == run - 1) {
132 dim_min_cur += dim_min_rem;
133 dim_max_cur += dim_max_rem;
134 }
[a35b458]135
[e63c424f]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;
[a35b458]142
[e63c424f]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;
[a35b458]157
[e63c424f]158 for (size_t i = 0; i < run; i++) {
159 cons[i].val = cons[i].min;
160 cur_sum += cons[i].val;
161 }
[a35b458]162
[e63c424f]163 /* Iterative improvement */
164 while (cur_sum < sum) {
165 sysarg_t delta = (sum - cur_sum) / run;
166 if (delta == 0)
167 break;
[a35b458]168
[e63c424f]169 cur_sum = 0;
[a35b458]170
[e63c424f]171 for (size_t i = 0; i < run; i++) {
172 if (cons[i].val + delta < cons[i].max)
173 cons[i].val += delta;
[a35b458]174
[e63c424f]175 cur_sum += cons[i].val;
176 }
177 }
[6d5e378]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;
[a35b458]184
[6d5e378]185 widget_modify(widget, hpos, vpos, width, height);
186 paint_internal(widget);
[a35b458]187
[e63c424f]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;
[a35b458]195
[e63c424f]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;
[a35b458]200
[e63c424f]201 widget_t *widget = cell->widget;
202 if (widget)
203 adjust_constraints(&widths[c], cell->cols,
204 widget->width_min, widget->width_max);
[6d5e378]205 }
206 }
[a35b458]207
[e63c424f]208 solve_constraints(widths, grid->cols, width);
209 }
[a35b458]210
[e63c424f]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;
[a35b458]218
[e63c424f]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;
[a35b458]223
[e63c424f]224 widget_t *widget = cell->widget;
225 if (widget) {
226 adjust_constraints(&heights[r], cell->rows,
227 widget->height_min, widget->height_max);
228 }
[6d5e378]229 }
230 }
[a35b458]231
[e63c424f]232 solve_constraints(heights, grid->rows, height);
233 }
[a35b458]234
[e63c424f]235 /* Rearrange widgets */
236 if ((widths) && (heights)) {
237 sysarg_t cur_vpos = vpos;
[a35b458]238
[e63c424f]239 for (size_t r = 0; r < grid->rows; r++) {
240 sysarg_t cur_hpos = hpos;
[a35b458]241
[e63c424f]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;
[a35b458]246
[e63c424f]247 widget_t *widget = cell->widget;
248 if (widget) {
249 sysarg_t cur_width = 0;
250 sysarg_t cur_height = 0;
[a35b458]251
[e63c424f]252 for (size_t cd = 0; cd < cell->cols; cd++)
253 cur_width += widths[c + cd].val;
[a35b458]254
[e63c424f]255 for (size_t rd = 0; rd < cell->rows; rd++)
256 cur_height += heights[r + rd].val;
[a35b458]257
[e63c424f]258 if ((cur_width > 0) && (cur_height > 0)) {
259 sysarg_t wwidth = cur_width;
260 sysarg_t wheight = cur_height;
[a35b458]261
[e63c424f]262 /*
263 * Make sure the widget is respects its
264 * maximal constrains.
265 */
[a35b458]266
[e63c424f]267 if ((widget->width_max > 0) &&
268 (wwidth > widget->width_max))
269 wwidth = widget->width_max;
[a35b458]270
[e63c424f]271 if ((widget->height_max > 0) &&
272 (wheight > widget->height_max))
273 wheight = widget->height_max;
[a35b458]274
[e63c424f]275 widget->rearrange(widget, cur_hpos, cur_vpos,
276 wwidth, wheight);
277 }
[a35b458]278
279
[e63c424f]280 }
[a35b458]281
[e63c424f]282 cur_hpos += widths[c].val;
[6d5e378]283 }
[a35b458]284
[e63c424f]285 cur_vpos += heights[r].val;
[6d5e378]286 }
287 }
[a35b458]288
[e63c424f]289 if (widths)
290 free(widths);
[a35b458]291
[e63c424f]292 if (heights)
293 free(heights);
[6d5e378]294}
295
296static void grid_repaint(widget_t *widget)
297{
298 paint_internal(widget);
[a35b458]299
[feeac0d]300 list_foreach(widget->children, link, widget_t, child) {
[6d5e378]301 child->repaint(child);
302 }
[a35b458]303
[6d5e378]304 window_damage(widget->window);
305}
306
307static void grid_handle_keyboard_event(widget_t *widget, kbd_event_t event)
308{
[e63c424f]309 /* No-op */
[6d5e378]310}
311
312static void grid_handle_position_event(widget_t *widget, pos_event_t event)
313{
314 grid_t *grid = (grid_t *) widget;
[a35b458]315
[e63c424f]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);
[6d5e378]319}
320
[e63c424f]321static bool grid_add(struct grid *grid, widget_t *widget, size_t col,
322 size_t row, size_t cols, size_t rows)
[6d5e378]323{
[e63c424f]324 if ((cols == 0) || (rows == 0) || (col + cols > grid->cols) ||
325 (row + rows > grid->rows))
326 return false;
[a35b458]327
[e63c424f]328 grid_cell_t *cell = grid_cell_at(grid, col, row);
329 if (!cell)
330 return false;
[a35b458]331
[e63c424f]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;
[a35b458]338
[6d5e378]339 widget->parent = (widget_t *) grid;
[a35b458]340
[6d5e378]341 list_append(&widget->link, &grid->widget.children);
342 widget->window = grid->widget.window;
[a35b458]343
[e63c424f]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 }
[6d5e378]358 }
359 }
360 }
[a35b458]361
[e63c424f]362 return true;
[6d5e378]363}
364
[10cb47e]365bool init_grid(grid_t *grid, widget_t *parent, const void *data, size_t cols,
366 size_t rows, pixel_t background)
[6d5e378]367{
[e63c424f]368 if ((cols == 0) || (rows == 0))
[6d5e378]369 return false;
[a35b458]370
[e63c424f]371 grid->layout =
372 (grid_cell_t *) calloc(cols * rows, sizeof(grid_cell_t));
373 if (!grid->layout)
374 return false;
[a35b458]375
[e63c424f]376 memset(grid->layout, 0, cols * rows * sizeof(grid_cell_t));
[a35b458]377
[10cb47e]378 widget_init(&grid->widget, parent, data);
[a35b458]379
[6d5e378]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;
[a35b458]386
[6d5e378]387 grid->add = grid_add;
388 grid->background = background;
389 grid->cols = cols;
[e63c424f]390 grid->rows = rows;
[a35b458]391
[6d5e378]392 return true;
393}
394
[10cb47e]395grid_t *create_grid(widget_t *parent, const void *data, size_t cols,
396 size_t rows, pixel_t background)
[6d5e378]397{
398 grid_t *grid = (grid_t *) malloc(sizeof(grid_t));
[e63c424f]399 if (!grid)
[6d5e378]400 return NULL;
[a35b458]401
[10cb47e]402 if (init_grid(grid, parent, data, cols, rows, background))
[6d5e378]403 return grid;
[a35b458]404
[e63c424f]405 free(grid);
406 return NULL;
[6d5e378]407}
408
409/** @}
410 */
Note: See TracBrowser for help on using the repository browser.