Blender V4.3
spreadsheet_draw.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "UI_interface.hh"
6#include "UI_resources.hh"
7#include "UI_view2d.hh"
8
9#include "GPU_immediate.hh"
10
11#include "DNA_screen_types.h"
12#include "DNA_userdef_types.h"
13
14#include "BLI_rect.h"
15
16#include "spreadsheet_draw.hh"
17
18#define CELL_RIGHT_PADDING (2.0f * UI_SCALE_FAC)
19
21
28
30
31void SpreadsheetDrawer::draw_top_row_cell(int /*column_index*/,
32 const CellDrawParams & /*params*/) const
33{
34}
35
37 const CellDrawParams & /*params*/) const
38{
39}
40
42 int /*column_index*/,
43 const CellDrawParams & /*params*/) const
44{
45}
46
47int SpreadsheetDrawer::column_width(int /*column_index*/) const
48{
49 return 5 * UI_UNIT_X;
50}
51
53 const ARegion *region,
54 const SpreadsheetDrawer &drawer)
55{
57 immRecti(pos, 0, region->winy - drawer.top_row_height, drawer.left_column_width, 0);
58}
59
61 const int scroll_offset_y,
62 const ARegion *region,
63 const SpreadsheetDrawer &drawer)
64{
67 BLI_assert(drawer.row_height > 0);
68 const int row_pair_height = drawer.row_height * 2;
69 const int row_top_y = region->winy - drawer.top_row_height - scroll_offset_y % row_pair_height;
70 for (const int i : IndexRange(region->winy / row_pair_height + 1)) {
71 int x_left = 0;
72 int x_right = region->winx;
73 int y_top = row_top_y - i * row_pair_height - drawer.row_height;
74 int y_bottom = y_top - drawer.row_height;
75 y_top = std::min(y_top, region->winy - drawer.top_row_height);
76 y_bottom = std::min(y_bottom, region->winy - drawer.top_row_height);
77 immRecti(pos, x_left, y_top, x_right, y_bottom);
78 }
80}
81
83 const ARegion *region,
84 const SpreadsheetDrawer &drawer)
85{
87 immRecti(pos, 0, region->winy, region->winx, region->winy - drawer.top_row_height);
88}
89
90static void draw_separator_lines(const uint pos,
91 const int scroll_offset_x,
92 const ARegion *region,
93 const SpreadsheetDrawer &drawer)
94{
96
98
99 /* Left column line. */
100 immVertex2i(pos, drawer.left_column_width, region->winy);
102
103 /* Top row line. */
104 immVertex2i(pos, 0, region->winy - drawer.top_row_height);
105 immVertex2i(pos, region->winx, region->winy - drawer.top_row_height);
106
107 /* Column separator lines. */
108 int line_x = drawer.left_column_width - scroll_offset_x;
109 for (const int column_index : IndexRange(drawer.tot_columns)) {
110 const int column_width = drawer.column_width(column_index);
111 line_x += column_width;
112 if (line_x >= drawer.left_column_width) {
113 immVertex2i(pos, line_x, region->winy);
114 immVertex2i(pos, line_x, 0);
115 }
116 }
117 immEnd();
118}
119
120static void get_visible_rows(const SpreadsheetDrawer &drawer,
121 const ARegion *region,
122 const int scroll_offset_y,
123 int *r_first_row,
124 int *r_max_visible_rows)
125{
126 *r_first_row = -scroll_offset_y / drawer.row_height;
127 *r_max_visible_rows = region->winy / drawer.row_height + 1;
128}
129
130static void draw_left_column_content(const int scroll_offset_y,
131 const bContext *C,
132 ARegion *region,
133 const SpreadsheetDrawer &drawer)
134{
135 int old_scissor[4];
136 GPU_scissor_get(old_scissor);
137
138 GPU_scissor(0, 0, drawer.left_column_width, region->winy - drawer.top_row_height);
139
140 uiBlock *left_column_block = UI_block_begin(C, region, __func__, UI_EMBOSS_NONE);
141 int first_row, max_visible_rows;
142 get_visible_rows(drawer, region, scroll_offset_y, &first_row, &max_visible_rows);
143 for (const int row_index : IndexRange(first_row, max_visible_rows)) {
144 if (row_index >= drawer.tot_rows) {
145 break;
146 }
148 params.block = left_column_block;
149 params.xmin = 0;
150 params.ymin = region->winy - drawer.top_row_height - (row_index + 1) * drawer.row_height -
151 scroll_offset_y;
153 params.height = drawer.row_height;
154 drawer.draw_left_column_cell(row_index, params);
155 }
156
157 UI_block_end(C, left_column_block);
158 UI_block_draw(C, left_column_block);
159
160 GPU_scissor(UNPACK4(old_scissor));
161}
162
163static void draw_top_row_content(const bContext *C,
164 ARegion *region,
165 const SpreadsheetDrawer &drawer,
166 const int scroll_offset_x)
167{
168 int old_scissor[4];
169 GPU_scissor_get(old_scissor);
170
172 region->winy - drawer.top_row_height,
173 region->winx - drawer.left_column_width,
174 drawer.top_row_height);
175
176 uiBlock *first_row_block = UI_block_begin(C, region, __func__, UI_EMBOSS_NONE);
177
178 int left_x = drawer.left_column_width - scroll_offset_x;
179 for (const int column_index : IndexRange(drawer.tot_columns)) {
180 const int column_width = drawer.column_width(column_index);
181 const int right_x = left_x + column_width;
182
184 params.block = first_row_block;
185 params.xmin = left_x;
186 params.ymin = region->winy - drawer.top_row_height;
187 params.width = column_width - CELL_RIGHT_PADDING;
188 params.height = drawer.top_row_height;
189 drawer.draw_top_row_cell(column_index, params);
190
191 left_x = right_x;
192 }
193
194 UI_block_end(C, first_row_block);
195 UI_block_draw(C, first_row_block);
196
197 GPU_scissor(UNPACK4(old_scissor));
198}
199
200static void draw_cell_contents(const bContext *C,
201 ARegion *region,
202 const SpreadsheetDrawer &drawer,
203 const int scroll_offset_x,
204 const int scroll_offset_y)
205{
206 int old_scissor[4];
207 GPU_scissor_get(old_scissor);
208
210 0,
211 region->winx - drawer.left_column_width,
212 region->winy - drawer.top_row_height);
213
214 uiBlock *cells_block = UI_block_begin(C, region, __func__, UI_EMBOSS_NONE);
215
216 int first_row, max_visible_rows;
217 get_visible_rows(drawer, region, scroll_offset_y, &first_row, &max_visible_rows);
218
219 int left_x = drawer.left_column_width - scroll_offset_x;
220 for (const int column_index : IndexRange(drawer.tot_columns)) {
221 const int column_width = drawer.column_width(column_index);
222 const int right_x = left_x + column_width;
223
224 if (right_x >= drawer.left_column_width && left_x <= region->winx) {
225 for (const int row_index : IndexRange(first_row, max_visible_rows)) {
226 if (row_index >= drawer.tot_rows) {
227 break;
228 }
229
231 params.block = cells_block;
232 params.xmin = left_x;
233 params.ymin = region->winy - drawer.top_row_height - (row_index + 1) * drawer.row_height -
234 scroll_offset_y;
235 params.width = column_width - CELL_RIGHT_PADDING;
236 params.height = drawer.row_height;
237 drawer.draw_content_cell(row_index, column_index, params);
238 }
239 }
240
241 left_x = right_x;
242 }
243
244 UI_block_end(C, cells_block);
245 UI_block_draw(C, cells_block);
246
247 GPU_scissor(UNPACK4(old_scissor));
248}
249
251 ARegion *region,
252 const int row_amount)
253{
254 int column_width_sum = 0;
255 for (const int column_index : IndexRange(drawer.tot_columns)) {
256 column_width_sum += drawer.column_width(column_index);
257 }
258
259 UI_view2d_totRect_set(&region->v2d,
260 column_width_sum + drawer.left_column_width,
261 row_amount * drawer.row_height + drawer.top_row_height);
262}
263
265 ARegion *region,
266 const SpreadsheetDrawer &drawer)
267{
268 update_view2d_tot_rect(drawer, region, drawer.tot_rows);
269
271
272 View2D *v2d = &region->v2d;
273 const int scroll_offset_y = v2d->cur.ymax;
274 const int scroll_offset_x = v2d->cur.xmin;
275
279
280 draw_index_column_background(pos, region, drawer);
281 draw_alternating_row_overlay(pos, scroll_offset_y, region, drawer);
282 draw_top_row_background(pos, region, drawer);
283 draw_separator_lines(pos, scroll_offset_x, region, drawer);
284
286
287 draw_left_column_content(scroll_offset_y, C, region, drawer);
288 draw_top_row_content(C, region, drawer, scroll_offset_x);
289 draw_cell_contents(C, region, drawer, scroll_offset_x, scroll_offset_y);
290
291 rcti scroller_mask;
292 BLI_rcti_init(&scroller_mask,
293 drawer.left_column_width,
294 region->winx,
295 0,
296 region->winy - drawer.top_row_height);
297 UI_view2d_scrollers_draw(v2d, &scroller_mask);
298}
299
300} // namespace blender::ed::spreadsheet
#define BLI_assert(a)
Definition BLI_assert.h:50
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.c:418
unsigned int uint
#define UNPACK4(a)
void immEnd()
void immUnbindProgram()
void immUniformThemeColor(int color_id)
void immUniformThemeColorShade(int color_id, int offset)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immBeginAtMost(GPUPrimType, uint max_vertex_len)
void immVertex2i(uint attr_id, int x, int y)
GPUVertFormat * immVertexFormat()
void immRecti(uint pos, int x1, int y1, int x2, int y2)
@ GPU_PRIM_LINES
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(eGPUBlend blend)
Definition gpu_state.cc:42
void GPU_scissor(int x, int y, int width, int height)
Definition gpu_state.cc:188
void GPU_scissor_get(int coords[4])
Definition gpu_state.cc:257
@ GPU_FETCH_INT_TO_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_I32
#define UI_UNIT_Y
@ UI_EMBOSS_NONE
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, eUIEmbossType emboss)
void UI_block_draw(const bContext *C, uiBlock *block)
#define UI_UNIT_X
void UI_block_end(const bContext *C, uiBlock *block)
@ TH_ROW_ALTERNATE
@ TH_BACK
void UI_ThemeClearColor(int colorid)
void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
Definition view2d.cc:1605
void UI_view2d_totRect_set(View2D *v2d, int width, int height)
Definition view2d.cc:1032
virtual void draw_top_row_cell(int column_index, const CellDrawParams &params) const
virtual int column_width(int column_index) const
virtual void draw_left_column_cell(int row_index, const CellDrawParams &params) const
virtual void draw_content_cell(int row_index, int column_index, const CellDrawParams &params) const
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
format
static void draw_index_column_background(const uint pos, const ARegion *region, const SpreadsheetDrawer &drawer)
static void draw_left_column_content(const int scroll_offset_y, const bContext *C, ARegion *region, const SpreadsheetDrawer &drawer)
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)
void draw_spreadsheet_in_region(const bContext *C, ARegion *region, const SpreadsheetDrawer &drawer)
static void update_view2d_tot_rect(const SpreadsheetDrawer &drawer, ARegion *region, const int row_amount)
static void draw_top_row_content(const bContext *C, ARegion *region, const SpreadsheetDrawer &drawer, const int scroll_offset_x)
static void draw_alternating_row_overlay(const uint pos, const int scroll_offset_y, const ARegion *region, const SpreadsheetDrawer &drawer)
static void draw_cell_contents(const bContext *C, ARegion *region, const SpreadsheetDrawer &drawer, const int scroll_offset_x, const int scroll_offset_y)
static void draw_separator_lines(const uint pos, const int scroll_offset_x, const ARegion *region, const SpreadsheetDrawer &drawer)
static void draw_top_row_background(const uint pos, const ARegion *region, const SpreadsheetDrawer &drawer)
#define CELL_RIGHT_PADDING
float xmin
float ymax