Changes in uspace/lib/gui/grid.c [e63c424f:6d5e378] in mainline


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/gui/grid.c

    re63c424f r6d5e378  
    11/*
    22 * Copyright (c) 2012 Petr Koupy
    3  * Copyright (c) 2013 Martin Decky
    43 * All rights reserved.
    54 *
     
    3938#include <malloc.h>
    4039#include <surface.h>
     40
    4141#include "window.h"
    4242#include "grid.h"
    4343
    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        
     44static void paint_internal(widget_t *w)
     45{
     46        grid_t *grid = (grid_t *) w;
     47
    5448        surface_t *surface = window_claim(grid->widget.window);
    5549        if (!surface) {
    5650                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++)
     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) {
    6355                        surface_put_pixel(surface, x, y, grid->background);
    64         }
    65        
     56                }
     57        }
     58
    6659        window_yield(grid->widget.window);
    6760}
    6861
    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))
     62static widget_t **widget_at(grid_t *grid, size_t row, size_t col)
     63{
     64        if (row < grid->rows && col < grid->cols) {
    7265                return grid->layout + (row * grid->cols + col);
    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;
     66        } else {
     67                return NULL;
     68        }
    9569}
    9670
     
    10478{
    10579        grid_t *grid = (grid_t *) widget;
    106        
     80
    10781        deinit_grid(grid);
     82
    10883        free(grid);
    10984}
     
    11186static void grid_reconfigure(widget_t *widget)
    11287{
    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         }
     88        /* no-op */
    17889}
    17990
     
    18293{
    18394        grid_t *grid = (grid_t *) widget;
    184        
     95
    18596        widget_modify(widget, hpos, vpos, width, height);
    18697        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);
     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;
    228119                                }
    229120                        }
    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);
     121                        if (found) {
     122                                break;
     123                        }
     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        }
    294152}
    295153
     
    297155{
    298156        paint_internal(widget);
    299        
    300157        list_foreach(widget->children, link) {
    301158                widget_t *child = list_get_instance(link, widget_t, link);
    302159                child->repaint(child);
    303160        }
    304        
    305161        window_damage(widget->window);
    306162}
     
    308164static void grid_handle_keyboard_event(widget_t *widget, kbd_event_t event)
    309165{
    310         /* No-op */
     166        /* no-op */
    311167}
    312168
     
    314170{
    315171        grid_t *grid = (grid_t *) widget;
    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        
     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
     189static 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
    340195        widget->parent = (widget_t *) grid;
    341        
    342196        list_append(&widget->link, &grid->widget.children);
    343197        widget->window = grid->widget.window;
    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                                 }
    359                         }
    360                 }
    361         }
    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))
     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;
     204                        }
     205                }
     206        }
     207}
     208
     209bool 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) {
    370217                return false;
    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        
     218        }
     219        memset(layout, 0, rows * cols * sizeof(widget_t *));
     220
    379221        widget_init(&grid->widget, parent);
    380        
     222
    381223        grid->widget.destroy = grid_destroy;
    382224        grid->widget.reconfigure = grid_reconfigure;
     
    385227        grid->widget.handle_keyboard_event = grid_handle_keyboard_event;
    386228        grid->widget.handle_position_event = grid_handle_position_event;
    387        
     229
    388230        grid->add = grid_add;
    389231        grid->background = background;
     232        grid->rows = rows;
    390233        grid->cols = cols;
    391         grid->rows = rows;
    392        
     234        grid->layout = layout;
     235
    393236        return true;
    394237}
    395238
    396 grid_t *create_grid(widget_t *parent, size_t cols, size_t rows, pixel_t background)
     239grid_t *create_grid(widget_t *parent, size_t rows, size_t cols, pixel_t background)
    397240{
    398241        grid_t *grid = (grid_t *) malloc(sizeof(grid_t));
    399         if (!grid)
     242        if (!grid) {
    400243                return NULL;
    401        
    402         if (init_grid(grid, parent, cols, rows, background))
     244        }
     245
     246        if (init_grid(grid, parent, rows, cols, background)) {
    403247                return grid;
    404        
    405         free(grid);
    406         return NULL;
     248        } else {
     249                free(grid);
     250                return NULL;
     251        }
    407252}
    408253
Note: See TracChangeset for help on using the changeset viewer.