diff options
Diffstat (limited to 'source/blender/editors/space_spreadsheet/spreadsheet_draw.cc')
-rw-r--r-- | source/blender/editors/space_spreadsheet/spreadsheet_draw.cc | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc new file mode 100644 index 00000000000..d6379c740e8 --- /dev/null +++ b/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc @@ -0,0 +1,304 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "UI_interface.h" +#include "UI_resources.h" +#include "UI_view2d.h" + +#include "GPU_immediate.h" + +#include "DNA_screen_types.h" +#include "DNA_userdef_types.h" + +#include "BLI_rect.h" + +#include "spreadsheet_draw.hh" + +namespace blender::ed::spreadsheet { + +SpreadsheetDrawer::SpreadsheetDrawer() +{ + left_column_width = UI_UNIT_X * 2; + top_row_height = UI_UNIT_Y * 1.1f; + row_height = UI_UNIT_Y; +} + +SpreadsheetDrawer::~SpreadsheetDrawer() = default; + +void SpreadsheetDrawer::draw_top_row_cell(int UNUSED(column_index), + const CellDrawParams &UNUSED(params)) const +{ +} + +void SpreadsheetDrawer::draw_left_column_cell(int UNUSED(row_index), + const CellDrawParams &UNUSED(params)) const +{ +} + +void SpreadsheetDrawer::draw_content_cell(int UNUSED(row_index), + int UNUSED(column_index), + const CellDrawParams &UNUSED(params)) const +{ +} + +int SpreadsheetDrawer::column_width(int UNUSED(column_index)) const +{ + return 5 * UI_UNIT_X; +} + +static void draw_index_column_background(const uint pos, + const ARegion *region, + const SpreadsheetDrawer &drawer) +{ + immUniformThemeColorShade(TH_BACK, 11); + immRecti(pos, 0, region->winy - drawer.top_row_height, drawer.left_column_width, 0); +} + +static void draw_alternating_row_overlay(const uint pos, + const int scroll_offset_y, + const ARegion *region, + const SpreadsheetDrawer &drawer) +{ + immUniformThemeColor(TH_ROW_ALTERNATE); + GPU_blend(GPU_BLEND_ALPHA); + BLI_assert(drawer.row_height > 0); + const int row_pair_height = drawer.row_height * 2; + const int row_top_y = region->winy - drawer.top_row_height - scroll_offset_y % row_pair_height; + for (const int i : IndexRange(region->winy / row_pair_height + 1)) { + int x_left = 0; + int x_right = region->winx; + int y_top = row_top_y - i * row_pair_height - drawer.row_height; + int y_bottom = y_top - drawer.row_height; + y_top = std::min(y_top, region->winy - drawer.top_row_height); + y_bottom = std::min(y_bottom, region->winy - drawer.top_row_height); + immRecti(pos, x_left, y_top, x_right, y_bottom); + } + GPU_blend(GPU_BLEND_NONE); +} + +static void draw_top_row_background(const uint pos, + const ARegion *region, + const SpreadsheetDrawer &drawer) +{ + immUniformThemeColorShade(TH_BACK, 11); + immRecti(pos, 0, region->winy, region->winx, region->winy - drawer.top_row_height); +} + +static void draw_separator_lines(const uint pos, + const int scroll_offset_x, + const ARegion *region, + const SpreadsheetDrawer &drawer) +{ + immUniformThemeColorShade(TH_BACK, -11); + + immBeginAtMost(GPU_PRIM_LINES, drawer.tot_columns * 2 + 4); + + /* Left column line. */ + immVertex2i(pos, drawer.left_column_width, region->winy); + immVertex2i(pos, drawer.left_column_width, 0); + + /* Top row line. */ + immVertex2i(pos, 0, region->winy - drawer.top_row_height); + immVertex2i(pos, region->winx, region->winy - drawer.top_row_height); + + /* Column separator lines. */ + int line_x = drawer.left_column_width - scroll_offset_x; + for (const int column_index : IndexRange(drawer.tot_columns)) { + const int column_width = drawer.column_width(column_index); + line_x += column_width; + if (line_x >= drawer.left_column_width) { + immVertex2i(pos, line_x, region->winy); + immVertex2i(pos, line_x, 0); + } + } + immEnd(); +} + +static void get_visible_rows(const SpreadsheetDrawer &drawer, + const ARegion *region, + const int scroll_offset_y, + int *r_first_row, + int *r_max_visible_rows) +{ + *r_first_row = -scroll_offset_y / drawer.row_height; + *r_max_visible_rows = region->winy / drawer.row_height + 1; +} + +static void draw_left_column_content(const int scroll_offset_y, + const bContext *C, + ARegion *region, + const SpreadsheetDrawer &drawer) +{ + GPU_scissor_test(true); + GPU_scissor(0, 0, drawer.left_column_width, region->winy - drawer.top_row_height); + + uiBlock *left_column_block = UI_block_begin(C, region, __func__, UI_EMBOSS_NONE); + int first_row, max_visible_rows; + get_visible_rows(drawer, region, scroll_offset_y, &first_row, &max_visible_rows); + for (const int row_index : IndexRange(first_row, max_visible_rows)) { + if (row_index >= drawer.tot_rows) { + break; + } + CellDrawParams params; + params.block = left_column_block; + params.xmin = 0; + params.ymin = region->winy - drawer.top_row_height - (row_index + 1) * drawer.row_height - + scroll_offset_y; + params.width = drawer.left_column_width; + params.height = drawer.row_height; + drawer.draw_left_column_cell(row_index, params); + } + + UI_block_end(C, left_column_block); + UI_block_draw(C, left_column_block); + + GPU_scissor_test(false); +} + +static void draw_top_row_content(const bContext *C, + ARegion *region, + const SpreadsheetDrawer &drawer, + const int scroll_offset_x) +{ + GPU_scissor_test(true); + GPU_scissor(drawer.left_column_width + 1, + region->winy - drawer.top_row_height, + region->winx - drawer.left_column_width, + drawer.top_row_height); + + uiBlock *first_row_block = UI_block_begin(C, region, __func__, UI_EMBOSS_NONE); + + int left_x = drawer.left_column_width - scroll_offset_x; + for (const int column_index : IndexRange(drawer.tot_columns)) { + const int column_width = drawer.column_width(column_index); + const int right_x = left_x + column_width; + + CellDrawParams params; + params.block = first_row_block; + params.xmin = left_x; + params.ymin = region->winy - drawer.top_row_height; + params.width = column_width; + params.height = drawer.top_row_height; + drawer.draw_top_row_cell(column_index, params); + + left_x = right_x; + } + + UI_block_end(C, first_row_block); + UI_block_draw(C, first_row_block); + + GPU_scissor_test(false); +} + +static void draw_cell_contents(const bContext *C, + ARegion *region, + const SpreadsheetDrawer &drawer, + const int scroll_offset_x, + const int scroll_offset_y) +{ + GPU_scissor_test(true); + GPU_scissor(drawer.left_column_width + 1, + 0, + region->winx - drawer.left_column_width, + region->winy - drawer.top_row_height); + + uiBlock *cells_block = UI_block_begin(C, region, __func__, UI_EMBOSS_NONE); + + int first_row, max_visible_rows; + get_visible_rows(drawer, region, scroll_offset_y, &first_row, &max_visible_rows); + + int left_x = drawer.left_column_width - scroll_offset_x; + for (const int column_index : IndexRange(drawer.tot_columns)) { + const int column_width = drawer.column_width(column_index); + const int right_x = left_x + column_width; + + if (right_x >= drawer.left_column_width && left_x <= region->winx) { + for (const int row_index : IndexRange(first_row, max_visible_rows)) { + if (row_index >= drawer.tot_rows) { + break; + } + + CellDrawParams params; + params.block = cells_block; + params.xmin = left_x; + params.ymin = region->winy - drawer.top_row_height - (row_index + 1) * drawer.row_height - + scroll_offset_y; + params.width = column_width; + params.height = drawer.row_height; + drawer.draw_content_cell(row_index, column_index, params); + } + } + + left_x = right_x; + } + + UI_block_end(C, cells_block); + UI_block_draw(C, cells_block); + + GPU_scissor_test(false); +} + +static void update_view2d_tot_rect(const SpreadsheetDrawer &drawer, + ARegion *region, + const int row_amount) +{ + int column_width_sum = 0; + for (const int column_index : IndexRange(drawer.tot_columns)) { + column_width_sum += drawer.column_width(column_index); + } + + UI_view2d_totRect_set(®ion->v2d, + column_width_sum + drawer.left_column_width, + row_amount * drawer.row_height + drawer.top_row_height); +} + +void draw_spreadsheet_in_region(const bContext *C, + ARegion *region, + const SpreadsheetDrawer &drawer) +{ + update_view2d_tot_rect(drawer, region, drawer.tot_rows); + + UI_ThemeClearColor(TH_BACK); + + View2D *v2d = ®ion->v2d; + const int scroll_offset_y = v2d->cur.ymax; + const int scroll_offset_x = v2d->cur.xmin; + + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + draw_index_column_background(pos, region, drawer); + draw_alternating_row_overlay(pos, scroll_offset_y, region, drawer); + draw_top_row_background(pos, region, drawer); + draw_separator_lines(pos, scroll_offset_x, region, drawer); + + immUnbindProgram(); + + draw_left_column_content(scroll_offset_y, C, region, drawer); + draw_top_row_content(C, region, drawer, scroll_offset_x); + draw_cell_contents(C, region, drawer, scroll_offset_x, scroll_offset_y); + + rcti scroller_mask; + BLI_rcti_init(&scroller_mask, + drawer.left_column_width, + region->winx, + 0, + region->winy - drawer.top_row_height); + UI_view2d_scrollers_draw(v2d, &scroller_mask); +} + +} // namespace blender::ed::spreadsheet |