Blender  V3.3
spreadsheet_row_filter_ui.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <cstring>
4 
5 #include "BLI_listbase.h"
6 #include "BLI_string.h"
7 #include "BLI_string_ref.hh"
8 
9 #include "DNA_screen_types.h"
10 #include "DNA_space_types.h"
11 
12 #include "BKE_screen.h"
13 
14 #include "RNA_access.h"
15 #include "RNA_prototypes.h"
16 
17 #include "UI_interface.h"
18 #include "UI_resources.h"
19 
20 #include "BLT_translation.h"
21 
22 #include "WM_api.h"
23 #include "WM_types.h"
24 
25 #include "spreadsheet_column.hh"
26 #include "spreadsheet_intern.hh"
29 
30 using namespace blender;
31 using namespace blender::ed::spreadsheet;
32 
33 static void filter_panel_id_fn(void *UNUSED(row_filter_v), char *r_name)
34 {
35  /* All row filters use the same panel ID. */
36  BLI_snprintf(r_name, BKE_ST_MAXNAME, "SPREADSHEET_PT_filter");
37 }
38 
39 static std::string operation_string(const eSpreadsheetColumnValueType data_type,
40  const eSpreadsheetFilterOperation operation)
41 {
43  return "=";
44  }
45 
46  switch (operation) {
48  return "=";
50  return ">";
52  return "<";
53  }
55  return "";
56 }
57 
58 static std::string value_string(const SpreadsheetRowFilter &row_filter,
59  const eSpreadsheetColumnValueType data_type)
60 {
61  switch (data_type) {
64  return std::to_string(row_filter.value_int);
66  std::ostringstream result;
67  result.precision(3);
68  result << std::fixed << row_filter.value_float;
69  return result.str();
70  }
72  std::ostringstream result;
73  result.precision(3);
74  result << std::fixed << "(" << row_filter.value_float2[0] << ", "
75  << row_filter.value_float2[1] << ")";
76  return result.str();
77  }
79  std::ostringstream result;
80  result.precision(3);
81  result << std::fixed << "(" << row_filter.value_float3[0] << ", "
82  << row_filter.value_float3[1] << ", " << row_filter.value_float3[2] << ")";
83  return result.str();
84  }
86  return (row_filter.flag & SPREADSHEET_ROW_FILTER_BOOL_VALUE) ? IFACE_("True") :
87  IFACE_("False");
89  if (row_filter.value_string != nullptr) {
90  return row_filter.value_string;
91  }
92  return "";
95  std::ostringstream result;
96  result.precision(3);
97  result << std::fixed << "(" << row_filter.value_color[0] << ", " << row_filter.value_color[1]
98  << ", " << row_filter.value_color[2] << ", " << row_filter.value_color[3] << ")";
99  return result.str();
100  }
102  return row_filter.value_string;
104  return "";
105  }
107  return "";
108 }
109 
111  const StringRef column_name)
112 {
113  LISTBASE_FOREACH (SpreadsheetColumn *, column, &sspreadsheet.columns) {
114  if (column->display_name == column_name) {
115  return column;
116  }
117  }
118  return nullptr;
119 }
120 
122 {
123  uiLayout *layout = panel->layout;
125  PointerRNA *filter_ptr = UI_panel_custom_data_get(panel);
126  const SpreadsheetRowFilter *filter = (SpreadsheetRowFilter *)filter_ptr->data;
127  const StringRef column_name = filter->column_name;
128  const eSpreadsheetFilterOperation operation = (eSpreadsheetFilterOperation)filter->operation;
129 
130  const SpreadsheetColumn *column = lookup_visible_column_for_filter(*sspreadsheet, column_name);
131  if (!(sspreadsheet->filter_flag & SPREADSHEET_FILTER_ENABLE) ||
132  (column == nullptr && !column_name.is_empty())) {
133  uiLayoutSetActive(layout, false);
134  }
135 
136  uiLayout *row = uiLayoutRow(layout, true);
138  uiItemR(row, filter_ptr, "enabled", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
139 
140  if (column_name.is_empty()) {
141  uiItemL(row, IFACE_("Filter"), ICON_NONE);
142  }
143  else if (column == nullptr) {
144  uiItemL(row, column_name.data(), ICON_NONE);
145  }
146  else {
148  std::stringstream ss;
149  ss << column_name;
150  ss << " ";
151  ss << operation_string(data_type, operation);
152  ss << " ";
153  ss << value_string(*filter, data_type);
154  uiItemL(row, ss.str().c_str(), ICON_NONE);
155  }
156 
157  row = uiLayoutRow(layout, true);
159  const int current_index = BLI_findindex(&sspreadsheet->row_filters, filter);
160  uiItemIntO(row, "", ICON_X, "SPREADSHEET_OT_remove_row_filter_rule", "index", current_index);
161 
162  /* Some padding so the X isn't too close to the drag icon. */
163  uiItemS_ex(layout, 0.25f);
164 }
165 
166 static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel)
167 {
168  uiLayout *layout = panel->layout;
170  PointerRNA *filter_ptr = UI_panel_custom_data_get(panel);
172  const StringRef column_name = filter->column_name;
173  const eSpreadsheetFilterOperation operation = (eSpreadsheetFilterOperation)filter->operation;
174 
175  const SpreadsheetColumn *column = lookup_visible_column_for_filter(*sspreadsheet, column_name);
176  if (!(sspreadsheet->filter_flag & SPREADSHEET_FILTER_ENABLE) ||
178  (column == nullptr && !column_name.is_empty())) {
179  uiLayoutSetActive(layout, false);
180  }
181 
182  uiLayoutSetPropSep(layout, true);
183  uiLayoutSetPropDecorate(layout, false);
184 
185  uiItemR(layout, filter_ptr, "column_name", 0, IFACE_("Column"), ICON_NONE);
186 
187  /* Don't draw settings for filters with no corresponding visible column. */
188  if (column == nullptr || column_name.is_empty()) {
189  return;
190  }
191 
192  switch (static_cast<eSpreadsheetColumnValueType>(column->data_type)) {
194  uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
195  uiItemR(layout, filter_ptr, "value_int8", 0, IFACE_("Value"), ICON_NONE);
196  break;
198  uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
199  uiItemR(layout, filter_ptr, "value_int", 0, IFACE_("Value"), ICON_NONE);
200  break;
202  uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
203  uiItemR(layout, filter_ptr, "value_float", 0, IFACE_("Value"), ICON_NONE);
204  if (operation == SPREADSHEET_ROW_FILTER_EQUAL) {
205  uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
206  }
207  break;
209  uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
210  uiItemR(layout, filter_ptr, "value_float2", 0, IFACE_("Value"), ICON_NONE);
211  if (operation == SPREADSHEET_ROW_FILTER_EQUAL) {
212  uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
213  }
214  break;
216  uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
217  uiItemR(layout, filter_ptr, "value_float3", 0, IFACE_("Value"), ICON_NONE);
218  if (operation == SPREADSHEET_ROW_FILTER_EQUAL) {
219  uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
220  }
221  break;
223  uiItemR(layout, filter_ptr, "value_boolean", 0, IFACE_("Value"), ICON_NONE);
224  break;
226  uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE);
227  break;
230  uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
231  uiItemR(layout, filter_ptr, "value_color", 0, IFACE_("Value"), ICON_NONE);
232  if (operation == SPREADSHEET_ROW_FILTER_EQUAL) {
233  uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
234  }
235  break;
237  uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE);
238  break;
240  uiItemL(layout, IFACE_("Unknown column type"), ICON_ERROR);
241  break;
242  }
243 }
244 
245 static void spreadsheet_row_filters_layout(const bContext *C, Panel *panel)
246 {
247  uiLayout *layout = panel->layout;
248  ARegion *region = CTX_wm_region(C);
249  bScreen *screen = CTX_wm_screen(C);
251  ListBase *row_filters = &sspreadsheet->row_filters;
252 
253  if (!(sspreadsheet->filter_flag & SPREADSHEET_FILTER_ENABLE)) {
254  uiLayoutSetActive(layout, false);
255  }
256 
257  uiItemO(layout, nullptr, ICON_ADD, "SPREADSHEET_OT_add_row_filter_rule");
258 
259  const bool panels_match = UI_panel_list_matches_data(region, row_filters, filter_panel_id_fn);
260 
261  if (!panels_match) {
262  UI_panels_free_instanced(C, region);
263  LISTBASE_FOREACH (SpreadsheetRowFilter *, row_filter, row_filters) {
264  char panel_idname[MAX_NAME];
265  filter_panel_id_fn(row_filter, panel_idname);
266 
267  PointerRNA *filter_ptr = (PointerRNA *)MEM_mallocN(sizeof(PointerRNA), "panel customdata");
268  RNA_pointer_create(&screen->id, &RNA_SpreadsheetRowFilter, row_filter, filter_ptr);
269 
270  UI_panel_add_instanced(C, region, &region->panels, panel_idname, filter_ptr);
271  }
272  }
273  else {
274  /* Assuming there's only one group of instanced panels, update the custom data pointers. */
275  Panel *panel_iter = (Panel *)region->panels.first;
276  LISTBASE_FOREACH (SpreadsheetRowFilter *, row_filter, row_filters) {
277 
278  /* Move to the next instanced panel corresponding to the next filter. */
279  while ((panel_iter->type == nullptr) || !(panel_iter->type->flag & PANEL_TYPE_INSTANCED)) {
280  panel_iter = panel_iter->next;
281  BLI_assert(panel_iter != nullptr); /* There shouldn't be fewer panels than filters. */
282  }
283 
284  PointerRNA *filter_ptr = (PointerRNA *)MEM_mallocN(sizeof(PointerRNA), "panel customdata");
285  RNA_pointer_create(&screen->id, &RNA_SpreadsheetRowFilter, row_filter, filter_ptr);
286  UI_panel_custom_data_set(panel_iter, filter_ptr);
287 
288  panel_iter = panel_iter->next;
289  }
290  }
291 }
292 
293 static void filter_reorder(bContext *C, Panel *panel, int new_index)
294 {
296  ListBase *row_filters = &sspreadsheet->row_filters;
297  PointerRNA *filter_ptr = UI_panel_custom_data_get(panel);
299 
300  int current_index = BLI_findindex(row_filters, filter);
301  BLI_assert(current_index >= 0);
302  BLI_assert(new_index >= 0);
303 
304  BLI_listbase_link_move(row_filters, filter, new_index - current_index);
305 }
306 
307 static short get_filter_expand_flag(const bContext *UNUSED(C), Panel *panel)
308 {
309  PointerRNA *filter_ptr = UI_panel_custom_data_get(panel);
311 
313 }
314 
315 static void set_filter_expand_flag(const bContext *UNUSED(C), Panel *panel, short expand_flag)
316 {
317  PointerRNA *filter_ptr = UI_panel_custom_data_get(panel);
319 
321  expand_flag & SPREADSHEET_ROW_FILTER_UI_EXPAND,
323 }
324 
326 {
327  {
328  PanelType *panel_type = MEM_cnew<PanelType>(__func__);
329  strcpy(panel_type->idname, "SPREADSHEET_PT_row_filters");
330  strcpy(panel_type->label, N_("Filters"));
331  strcpy(panel_type->category, "Filters");
333  panel_type->flag = PANEL_TYPE_NO_HEADER;
334  panel_type->draw = spreadsheet_row_filters_layout;
335  BLI_addtail(&region_type.paneltypes, panel_type);
336  }
337 
338  {
339  PanelType *panel_type = MEM_cnew<PanelType>(__func__);
340  strcpy(panel_type->idname, "SPREADSHEET_PT_filter");
341  strcpy(panel_type->label, "");
342  strcpy(panel_type->category, "Filters");
346  panel_type->draw = spreadsheet_filter_panel_draw;
349  panel_type->reorder = filter_reorder;
350  BLI_addtail(&region_type.paneltypes, panel_type);
351  }
352 }
struct SpaceSpreadsheet * CTX_wm_space_spreadsheet(const bContext *C)
Definition: context.c:941
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:733
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
@ PANEL_TYPE_NO_HEADER
Definition: BKE_screen.h:280
@ PANEL_TYPE_INSTANCED
Definition: BKE_screen.h:285
@ PANEL_TYPE_HEADER_EXPAND
Definition: BKE_screen.h:282
#define BKE_ST_MAXNAME
Definition: BKE_screen.h:53
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void void void bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL()
Definition: listbase.c:405
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
#define UNUSED(x)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
#define IFACE_(msgid)
#define BLT_I18NCONTEXT_DEFAULT_BPYRNA
#define MAX_NAME
Definition: DNA_defs.h:48
@ SPREADSHEET_ROW_FILTER_BOOL_VALUE
@ SPREADSHEET_ROW_FILTER_UI_EXPAND
@ SPREADSHEET_ROW_FILTER_ENABLED
@ SPREADSHEET_FILTER_ENABLE
eSpreadsheetFilterOperation
@ SPREADSHEET_ROW_FILTER_GREATER
@ SPREADSHEET_ROW_FILTER_EQUAL
@ SPREADSHEET_ROW_FILTER_LESS
eSpreadsheetColumnValueType
@ SPREADSHEET_VALUE_TYPE_INT8
@ SPREADSHEET_VALUE_TYPE_FLOAT
@ SPREADSHEET_VALUE_TYPE_BYTE_COLOR
@ SPREADSHEET_VALUE_TYPE_UNKNOWN
@ SPREADSHEET_VALUE_TYPE_FLOAT3
@ SPREADSHEET_VALUE_TYPE_BOOL
@ SPREADSHEET_VALUE_TYPE_STRING
@ SPREADSHEET_VALUE_TYPE_INT32
@ SPREADSHEET_VALUE_TYPE_FLOAT2
@ SPREADSHEET_VALUE_TYPE_COLOR
@ SPREADSHEET_VALUE_TYPE_INSTANCES
#define C
Definition: RandGen.cpp:25
void uiItemS_ex(uiLayout *layout, float factor)
void uiLayoutSetActive(uiLayout *layout, bool active)
@ UI_EMBOSS_NONE
Definition: UI_interface.h:109
void uiItemIntO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
void uiItemL(uiLayout *layout, const char *name, int icon)
struct PointerRNA * UI_panel_custom_data_get(const struct Panel *panel)
void UI_panel_custom_data_set(struct Panel *panel, struct PointerRNA *custom_data)
struct Panel * UI_panel_add_instanced(const struct bContext *C, struct ARegion *region, struct ListBase *panels, const char *panel_idname, struct PointerRNA *custom_data)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void UI_panels_free_instanced(const struct bContext *C, struct ARegion *region)
bool UI_panel_list_matches_data(struct ARegion *region, struct ListBase *data, uiListPanelIDFromDataFunc panel_idname_func)
@ UI_ITEM_R_ICON_ONLY
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiLayoutSetEmboss(uiLayout *layout, eUIEmbossType emboss)
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
return(oflags[bm->toolflag_index].f &oflag) !=0
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
std::string to_string(const T &n)
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:136
void register_row_filter_panels(ARegionType &region_type)
static short get_filter_expand_flag(const bContext *UNUSED(C), Panel *panel)
static std::string operation_string(const eSpreadsheetColumnValueType data_type, const eSpreadsheetFilterOperation operation)
static void spreadsheet_filter_panel_draw_header(const bContext *C, Panel *panel)
static SpreadsheetColumn * lookup_visible_column_for_filter(const SpaceSpreadsheet &sspreadsheet, const StringRef column_name)
static void filter_panel_id_fn(void *UNUSED(row_filter_v), char *r_name)
static void spreadsheet_row_filters_layout(const bContext *C, Panel *panel)
static void filter_reorder(bContext *C, Panel *panel, int new_index)
static std::string value_string(const SpreadsheetRowFilter &row_filter, const eSpreadsheetColumnValueType data_type)
static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel)
static void set_filter_expand_flag(const bContext *UNUSED(C), Panel *panel, short expand_flag)
ListBase paneltypes
Definition: BKE_screen.h:198
ListBase panels
void * first
Definition: DNA_listBase.h:31
short(* get_list_data_expand_flag)(const struct bContext *C, struct Panel *pa)
Definition: BKE_screen.h:260
void(* draw)(const struct bContext *C, struct Panel *panel)
Definition: BKE_screen.h:248
void(* draw_header)(const struct bContext *C, struct Panel *panel)
Definition: BKE_screen.h:244
char idname[BKE_ST_MAXNAME]
Definition: BKE_screen.h:223
void(* set_list_data_expand_flag)(const struct bContext *C, struct Panel *pa, short expand_flag)
Definition: BKE_screen.h:267
void(* reorder)(struct bContext *C, struct Panel *pa, int new_index)
Definition: BKE_screen.h:253
char translation_context[BKE_ST_MAXNAME]
Definition: BKE_screen.h:226
char category[BKE_ST_MAXNAME]
Definition: BKE_screen.h:228
char label[BKE_ST_MAXNAME]
Definition: BKE_screen.h:224
struct PanelType * type
struct uiLayout * layout
struct Panel * next
void * data
Definition: RNA_types.h:38
#define N_(msgid)