Changeset aa2b32c in mainline for uspace/lib/gui/grid.c
- Timestamp:
- 2013-04-29T12:44:05Z (12 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- a269d05
- Parents:
- 06b0211b (diff), 9e7898e (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/gui/grid.c
r06b0211b raa2b32c 1 1 /* 2 2 * Copyright (c) 2012 Petr Koupy 3 * Copyright (c) 2013 Martin Decky 3 4 * All rights reserved. 4 5 * … … 38 39 #include <malloc.h> 39 40 #include <surface.h> 40 41 41 #include "window.h" 42 42 #include "grid.h" 43 43 44 static void paint_internal(widget_t *w) 45 { 46 grid_t *grid = (grid_t *) w; 47 44 typedef struct { 45 sysarg_t min; 46 sysarg_t max; 47 sysarg_t val; 48 } constraints_t; 49 50 static void paint_internal(widget_t *widget) 51 { 52 grid_t *grid = (grid_t *) widget; 53 48 54 surface_t *surface = window_claim(grid->widget.window); 49 55 if (!surface) { 50 56 window_yield(grid->widget.window); 51 } 52 53 for (sysarg_t y = w->vpos; y < w->vpos + w->height; ++y) { 54 for (sysarg_t x = w->hpos; x < w->hpos + w->width; ++x) { 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++) 55 63 surface_put_pixel(surface, x, y, grid->background); 56 } 57 } 58 64 } 65 59 66 window_yield(grid->widget.window); 60 67 } 61 68 62 static widget_t **widget_at(grid_t *grid, size_t row, size_t col)63 { 64 if ( row < grid->rows && col < grid->cols) {69 static grid_cell_t *grid_cell_at(grid_t *grid, size_t col, size_t row) 70 { 71 if ((col < grid->cols) && (row < grid->rows)) 65 72 return grid->layout + (row * grid->cols + col); 66 } else { 67 return NULL; 68 } 73 74 return NULL; 75 } 76 77 static 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; 69 95 } 70 96 … … 78 104 { 79 105 grid_t *grid = (grid_t *) widget; 80 106 81 107 deinit_grid(grid); 82 83 108 free(grid); 84 109 } … … 86 111 static void grid_reconfigure(widget_t *widget) 87 112 { 88 /* no-op */ 113 /* No-op */ 114 } 115 116 static 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 153 static 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 } 89 178 } 90 179 … … 93 182 { 94 183 grid_t *grid = (grid_t *) widget; 95 184 96 185 widget_modify(widget, hpos, vpos, width, height); 97 186 paint_internal(widget); 98 99 sysarg_t cell_width = width / grid->cols; 100 sysarg_t cell_height = height / grid->rows; 101 102 list_foreach(widget->children, link) { 103 widget_t *child = list_get_instance(link, widget_t, link); 104 105 sysarg_t widget_hpos = 0; 106 sysarg_t widget_vpos = 0; 107 sysarg_t widget_width = 0; 108 sysarg_t widget_height = 0; 109 110 size_t r = 0; 111 size_t c = 0; 112 for (r = 0; r < grid->rows; ++r) { 113 bool found = false; 114 for (c = 0; c < grid->cols; ++c) { 115 widget_t **cell = widget_at(grid, r, c); 116 if (cell && *cell == child) { 117 found = true; 118 break; 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); 119 228 } 120 229 } 121 if (found) { 122 break; 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; 123 283 } 124 } 125 126 widget_hpos = cell_width * c + hpos; 127 widget_vpos = cell_height * r + vpos; 128 129 for (size_t _c = c; _c < grid->cols; ++_c) { 130 widget_t **cell = widget_at(grid, r, _c); 131 if (cell && *cell == child) { 132 widget_width += cell_width; 133 } else { 134 break; 135 } 136 } 137 138 for (size_t _r = r; _r < grid->rows; ++_r) { 139 widget_t **cell = widget_at(grid, _r, c); 140 if (cell && *cell == child) { 141 widget_height += cell_height; 142 } else { 143 break; 144 } 145 } 146 147 if (widget_width > 0 && widget_height > 0) { 148 child->rearrange(child, 149 widget_hpos, widget_vpos, widget_width, widget_height); 150 } 151 } 284 285 cur_vpos += heights[r].val; 286 } 287 } 288 289 if (widths) 290 free(widths); 291 292 if (heights) 293 free(heights); 152 294 } 153 295 … … 155 297 { 156 298 paint_internal(widget); 299 157 300 list_foreach(widget->children, link) { 158 301 widget_t *child = list_get_instance(link, widget_t, link); 159 302 child->repaint(child); 160 303 } 304 161 305 window_damage(widget->window); 162 306 } … … 164 308 static void grid_handle_keyboard_event(widget_t *widget, kbd_event_t event) 165 309 { 166 /* no-op */310 /* No-op */ 167 311 } 168 312 … … 170 314 { 171 315 grid_t *grid = (grid_t *) widget; 172 173 if ((widget->height / grid->rows) == 0) { 174 return; 175 } 176 if ((widget->width / grid->cols) == 0) { 177 return; 178 } 179 180 sysarg_t row = (event.vpos - widget->vpos) / (widget->height / grid->rows); 181 sysarg_t col = (event.hpos - widget->hpos) / (widget->width / grid->cols); 182 183 widget_t **cell = widget_at(grid, row, col); 184 if (cell && *cell) { 185 (*cell)->handle_position_event(*cell, event); 186 } 187 } 188 189 static void grid_add(grid_t *grid, widget_t *widget, 190 size_t row, size_t col, size_t rows, size_t cols) 191 { 192 assert(row + rows <= grid->rows); 193 assert(col + cols <= grid->cols); 194 316 317 grid_cell_t *cell = grid_coords_at(grid, event.hpos, event.vpos); 318 if ((cell) && (cell->widget)) 319 cell->widget->handle_position_event(cell->widget, event); 320 } 321 322 static bool grid_add(struct grid *grid, widget_t *widget, size_t col, 323 size_t row, size_t cols, size_t rows) 324 { 325 if ((cols == 0) || (rows == 0) || (col + cols > grid->cols) || 326 (row + rows > grid->rows)) 327 return false; 328 329 grid_cell_t *cell = grid_cell_at(grid, col, row); 330 if (!cell) 331 return false; 332 333 /* 334 * Check whether the cell is not occupied by an 335 * extension of a different cell. 336 */ 337 if ((!cell->widget) && (cell->cols > 0) && (cell->rows > 0)) 338 return false; 339 195 340 widget->parent = (widget_t *) grid; 341 196 342 list_append(&widget->link, &grid->widget.children); 197 343 widget->window = grid->widget.window; 198 199 for (size_t r = row; r < row + rows; ++r) { 200 for (size_t c = col; c < col + cols; ++c) { 201 widget_t **cell = widget_at(grid, r, c); 202 if (cell) { 203 *cell = widget; 344 345 /* Mark cells in layout */ 346 for (size_t r = row; r < row + rows; r++) { 347 for (size_t c = col; c < col + cols; c++) { 348 if ((r == row) && (c == col)) { 349 cell->widget = widget; 350 cell->cols = cols; 351 cell->rows = rows; 352 } else { 353 grid_cell_t *extension = grid_cell_at(grid, c, r); 354 if (extension) { 355 extension->widget = NULL; 356 extension->cols = 1; 357 extension->rows = 1; 358 } 204 359 } 205 360 } 206 361 } 207 } 208 209 bool init_grid(grid_t *grid, 210 widget_t *parent, size_t rows, size_t cols, pixel_t background) 211 { 212 assert(rows > 0); 213 assert(cols > 0); 214 215 widget_t **layout = (widget_t **) malloc(rows * cols * sizeof(widget_t *)); 216 if (!layout) { 362 363 return true; 364 } 365 366 bool init_grid(grid_t *grid, widget_t *parent, size_t cols, size_t rows, 367 pixel_t background) 368 { 369 if ((cols == 0) || (rows == 0)) 217 370 return false; 218 } 219 memset(layout, 0, rows * cols * sizeof(widget_t *)); 220 371 372 grid->layout = 373 (grid_cell_t *) calloc(cols * rows, sizeof(grid_cell_t)); 374 if (!grid->layout) 375 return false; 376 377 memset(grid->layout, 0, cols * rows * sizeof(grid_cell_t)); 378 221 379 widget_init(&grid->widget, parent); 222 380 223 381 grid->widget.destroy = grid_destroy; 224 382 grid->widget.reconfigure = grid_reconfigure; … … 227 385 grid->widget.handle_keyboard_event = grid_handle_keyboard_event; 228 386 grid->widget.handle_position_event = grid_handle_position_event; 229 387 230 388 grid->add = grid_add; 231 389 grid->background = background; 390 grid->cols = cols; 232 391 grid->rows = rows; 233 grid->cols = cols; 234 grid->layout = layout; 235 392 236 393 return true; 237 394 } 238 395 239 grid_t *create_grid(widget_t *parent, size_t rows, size_t cols, pixel_t background)396 grid_t *create_grid(widget_t *parent, size_t cols, size_t rows, pixel_t background) 240 397 { 241 398 grid_t *grid = (grid_t *) malloc(sizeof(grid_t)); 242 if (!grid) {399 if (!grid) 243 400 return NULL; 244 } 245 246 if (init_grid(grid, parent, rows, cols, background)) { 401 402 if (init_grid(grid, parent, cols, rows, background)) 247 403 return grid; 248 } else { 249 free(grid); 250 return NULL; 251 } 404 405 free(grid); 406 return NULL; 252 407 } 253 408
Note:
See TracChangeset
for help on using the changeset viewer.