Changes in uspace/lib/gui/grid.c [6d5e378:feeac0d] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/gui/grid.c
r6d5e378 rfeeac0d 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); 157 list_foreach(widget->children, link) {158 widget_t *child = list_get_instance(link, widget_t, link);299 300 list_foreach(widget->children, link, widget_t, child) { 159 301 child->repaint(child); 160 302 } 303 161 304 window_damage(widget->window); 162 305 } … … 164 307 static void grid_handle_keyboard_event(widget_t *widget, kbd_event_t event) 165 308 { 166 /* no-op */309 /* No-op */ 167 310 } 168 311 … … 170 313 { 171 314 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 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 321 static 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 195 339 widget->parent = (widget_t *) grid; 340 196 341 list_append(&widget->link, &grid->widget.children); 197 342 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; 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 } 204 358 } 205 359 } 206 360 } 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) { 361 362 return true; 363 } 364 365 bool init_grid(grid_t *grid, widget_t *parent, size_t cols, size_t rows, 366 pixel_t background) 367 { 368 if ((cols == 0) || (rows == 0)) 217 369 return false; 218 } 219 memset(layout, 0, rows * cols * sizeof(widget_t *)); 220 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 221 378 widget_init(&grid->widget, parent); 222 379 223 380 grid->widget.destroy = grid_destroy; 224 381 grid->widget.reconfigure = grid_reconfigure; … … 227 384 grid->widget.handle_keyboard_event = grid_handle_keyboard_event; 228 385 grid->widget.handle_position_event = grid_handle_position_event; 229 386 230 387 grid->add = grid_add; 231 388 grid->background = background; 389 grid->cols = cols; 232 390 grid->rows = rows; 233 grid->cols = cols; 234 grid->layout = layout; 235 391 236 392 return true; 237 393 } 238 394 239 grid_t *create_grid(widget_t *parent, size_t rows, size_t cols, pixel_t background)395 grid_t *create_grid(widget_t *parent, size_t cols, size_t rows, pixel_t background) 240 396 { 241 397 grid_t *grid = (grid_t *) malloc(sizeof(grid_t)); 242 if (!grid) {398 if (!grid) 243 399 return NULL; 244 } 245 246 if (init_grid(grid, parent, rows, cols, background)) { 400 401 if (init_grid(grid, parent, cols, rows, background)) 247 402 return grid; 248 } else { 249 free(grid); 250 return NULL; 251 } 403 404 free(grid); 405 return NULL; 252 406 } 253 407
Note:
See TracChangeset
for help on using the changeset viewer.