source: mainline/uspace/lib/gui/grid.c@ aeba767

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

Curb the proliferation of libdraw headers

libdraw provides a lot of ambiguously named headers, which makes it
confusing. This change merges the subdirectories into single headers,
and moves all headers into draw subdirectory, so that it's obvious
at a glance what library the header belongs to.

Compare:

#include <path.h>
#include <source.h>
#include <font/bitmap_backend.h>
#include <font/pcf.h>

vs.

#include <draw/path.h>
#include <draw/source.h>
#include <draw/font.h>

  • 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>
[2bb6d04]40#include <draw/surface.h>
[6d5e378]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
[e63c424f]279 }
[a35b458]280
[e63c424f]281 cur_hpos += widths[c].val;
[6d5e378]282 }
[a35b458]283
[e63c424f]284 cur_vpos += heights[r].val;
[6d5e378]285 }
286 }
[a35b458]287
[e63c424f]288 if (widths)
289 free(widths);
[a35b458]290
[e63c424f]291 if (heights)
292 free(heights);
[6d5e378]293}
294
295static void grid_repaint(widget_t *widget)
296{
297 paint_internal(widget);
[a35b458]298
[feeac0d]299 list_foreach(widget->children, link, widget_t, child) {
[6d5e378]300 child->repaint(child);
301 }
[a35b458]302
[6d5e378]303 window_damage(widget->window);
304}
305
306static void grid_handle_keyboard_event(widget_t *widget, kbd_event_t event)
307{
[e63c424f]308 /* No-op */
[6d5e378]309}
310
311static void grid_handle_position_event(widget_t *widget, pos_event_t event)
312{
313 grid_t *grid = (grid_t *) widget;
[a35b458]314
[e63c424f]315 grid_cell_t *cell = grid_coords_at(grid, event.hpos, event.vpos);
316 if ((cell) && (cell->widget))
317 cell->widget->handle_position_event(cell->widget, event);
[6d5e378]318}
319
[e63c424f]320static bool grid_add(struct grid *grid, widget_t *widget, size_t col,
321 size_t row, size_t cols, size_t rows)
[6d5e378]322{
[e63c424f]323 if ((cols == 0) || (rows == 0) || (col + cols > grid->cols) ||
324 (row + rows > grid->rows))
325 return false;
[a35b458]326
[e63c424f]327 grid_cell_t *cell = grid_cell_at(grid, col, row);
328 if (!cell)
329 return false;
[a35b458]330
[e63c424f]331 /*
332 * Check whether the cell is not occupied by an
333 * extension of a different cell.
334 */
335 if ((!cell->widget) && (cell->cols > 0) && (cell->rows > 0))
336 return false;
[a35b458]337
[6d5e378]338 widget->parent = (widget_t *) grid;
[a35b458]339
[6d5e378]340 list_append(&widget->link, &grid->widget.children);
341 widget->window = grid->widget.window;
[a35b458]342
[e63c424f]343 /* Mark cells in layout */
344 for (size_t r = row; r < row + rows; r++) {
345 for (size_t c = col; c < col + cols; c++) {
346 if ((r == row) && (c == col)) {
347 cell->widget = widget;
348 cell->cols = cols;
349 cell->rows = rows;
350 } else {
351 grid_cell_t *extension = grid_cell_at(grid, c, r);
352 if (extension) {
353 extension->widget = NULL;
354 extension->cols = 1;
355 extension->rows = 1;
356 }
[6d5e378]357 }
358 }
359 }
[a35b458]360
[e63c424f]361 return true;
[6d5e378]362}
363
[10cb47e]364bool init_grid(grid_t *grid, widget_t *parent, const void *data, size_t cols,
365 size_t rows, pixel_t background)
[6d5e378]366{
[e63c424f]367 if ((cols == 0) || (rows == 0))
[6d5e378]368 return false;
[a35b458]369
[e63c424f]370 grid->layout =
371 (grid_cell_t *) calloc(cols * rows, sizeof(grid_cell_t));
372 if (!grid->layout)
373 return false;
[a35b458]374
[e63c424f]375 memset(grid->layout, 0, cols * rows * sizeof(grid_cell_t));
[a35b458]376
[10cb47e]377 widget_init(&grid->widget, parent, data);
[a35b458]378
[6d5e378]379 grid->widget.destroy = grid_destroy;
380 grid->widget.reconfigure = grid_reconfigure;
381 grid->widget.rearrange = grid_rearrange;
382 grid->widget.repaint = grid_repaint;
383 grid->widget.handle_keyboard_event = grid_handle_keyboard_event;
384 grid->widget.handle_position_event = grid_handle_position_event;
[a35b458]385
[6d5e378]386 grid->add = grid_add;
387 grid->background = background;
388 grid->cols = cols;
[e63c424f]389 grid->rows = rows;
[a35b458]390
[6d5e378]391 return true;
392}
393
[10cb47e]394grid_t *create_grid(widget_t *parent, const void *data, size_t cols,
395 size_t rows, pixel_t background)
[6d5e378]396{
397 grid_t *grid = (grid_t *) malloc(sizeof(grid_t));
[e63c424f]398 if (!grid)
[6d5e378]399 return NULL;
[a35b458]400
[10cb47e]401 if (init_grid(grid, parent, data, cols, rows, background))
[6d5e378]402 return grid;
[a35b458]403
[e63c424f]404 free(grid);
405 return NULL;
[6d5e378]406}
407
408/** @}
409 */
Note: See TracBrowser for help on using the repository browser.