[Bf-blender-cvs] [5171d86806a] master: UI: List Panel System

Hans Goudey noreply at git.blender.org
Tue May 26 21:40:05 CEST 2020


Commit: 5171d86806a338aa885cdddf3ad83dfcf15c40aa
Author: Hans Goudey
Date:   Tue May 26 15:39:49 2020 -0400
Branches: master
https://developer.blender.org/rB5171d86806a338aa885cdddf3ad83dfcf15c40aa

UI: List Panel System

This implements a general system to implement drag and drop, subpanels,
and UI animation for the stack UIs in Blender. There are NO functional
changes in this patch, but it makes it relatively trivial to implement
these features for stacks.

The biggest complication to using panels to implement the UI for lists
is that there can be multiple modifiers of the same type. Currently there
is an assumed 1 to 1 relationship between every panel and its type, but
there can be multiple list items of the same type, so we have to break
this relationship. The mapping between panels and their data is stored
with an index in the panel's runtime struct.

To make use the system for a list like modifiers, four components
must be added:
1. A panel type defined and registered for each list data type, with a
    known mapping between list data types and panel idnames.
1. A function called by interface code to build the add the panel
    layouts with the provided helper functions.
    - UI_panel_list_matches_data will check if the panel list needs to
      be rebuilt.
    - UI_panels_free_instanced will remove the existing list panels
    - UI_panel_add_instanced adds a list panel of a given type.
3. An expand flag for the list data and implementations of
    get_list_data_expand_flag and set_list_data_expand_flag.
4. For reordering, the panel type's reorder callback. This is called
   when the instanced panels are drag-dropped. This requires
   implementing a "move to index" operator for the list data.

Reviewed By: Severin, brecht

Differential Revision: https://developer.blender.org/D7490

===================================================================

M	source/blender/blenkernel/BKE_screen.h
M	source/blender/editors/include/UI_interface.h
M	source/blender/editors/interface/interface_align.c
M	source/blender/editors/interface/interface_intern.h
M	source/blender/editors/interface/interface_panel.c
M	source/blender/editors/interface/interface_widgets.c
M	source/blender/editors/screen/area.c
M	source/blender/makesdna/DNA_screen_types.h
M	source/blender/makesrna/intern/rna_ui.c

===================================================================

diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 0d8f5ed550c..8794558b81f 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -229,6 +229,25 @@ typedef struct PanelType {
   /* draw entirely, view changes should be handled here */
   void (*draw)(const struct bContext *C, struct Panel *panel);
 
+  /* For instanced panels corresponding to a list: */
+
+  /** Reorder function, called when drag and drop finishes. */
+  void (*reorder)(struct bContext *C, struct Panel *pa, int new_index);
+  /**
+   * Get the panel and subpanel's expansion state from the expansion flag in the corresponding data
+   * item. Called on draw updates.
+   * \note Subpanels are indexed in depth first order, the visualorder you would see if all panels
+   * were expanded.
+   */
+  short (*get_list_data_expand_flag)(const struct bContext *C, struct Panel *pa);
+  /**
+   * Set the expansion bitfield from the closed / open state of this panel and its subpanels.
+   * Called when the expansion state of the panel changes with user input.
+   * \note Subpanels are indexed in depth first order, the visual order you would see if all panels
+   * were expanded.
+   */
+  void (*set_list_data_expand_flag)(const struct bContext *C, struct Panel *pa, short expand_flag);
+
   /* sub panels */
   struct PanelType *parent;
   ListBase children;
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 3ad1608b47b..c95f517b155 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -239,6 +239,8 @@ enum {
 
 #define UI_PANEL_CATEGORY_MARGIN_WIDTH (U.widget_unit * 1.0f)
 
+#define UI_PANEL_BOX_STYLE_MARGIN (U.widget_unit * 0.2f)
+
 /* but->drawflag - these flags should only affect how the button is drawn. */
 /* Note: currently, these flags _are not passed_ to the widget's state() or draw() functions
  *       (except for the 'align' ones)!
@@ -1679,6 +1681,7 @@ void UI_panel_end(const struct ScrArea *area,
                   int width,
                   int height,
                   bool open);
+
 void UI_panels_scale(struct ARegion *region, float new_width);
 void UI_panel_label_offset(struct uiBlock *block, int *r_x, int *r_y);
 int UI_panel_size_y(const struct Panel *panel);
@@ -1702,6 +1705,24 @@ void UI_panel_category_draw_all(struct ARegion *region, const char *category_id_
 
 struct PanelType *UI_paneltype_find(int space_id, int region_id, const char *idname);
 
+/* Polyinstantiated panels for representing a list of data. */
+struct Panel *UI_panel_add_instanced(struct ScrArea *area,
+                                     struct ARegion *region,
+                                     struct ListBase *panels,
+                                     char *panel_idname,
+                                     int list_index);
+void UI_panels_free_instanced(struct bContext *C, struct ARegion *region);
+
+#define LIST_PANEL_UNIQUE_STR_LEN 4
+void UI_list_panel_unique_str(struct Panel *panel, char *r_name);
+
+void UI_panel_set_expand_from_list_data(const struct bContext *C, struct Panel *panel);
+
+typedef void (*uiListPanelIDFromDataFunc)(void *data_link, char *r_idname);
+bool UI_panel_list_matches_data(struct ARegion *region,
+                                struct ListBase *data,
+                                uiListPanelIDFromDataFunc panel_idname_func);
+
 /* Handlers
  *
  * Handlers that can be registered in regions, areas and windows for
diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c
index acbdf564054..32cae609395 100644
--- a/source/blender/editors/interface/interface_align.c
+++ b/source/blender/editors/interface/interface_align.c
@@ -506,7 +506,7 @@ void ui_block_align_calc(uiBlock *block, const ARegion *region)
 
         butal->but->drawflag |= align;
         butal_other->but->drawflag |= align_opp;
-        if (butal->dists[side]) {
+        if (!IS_EQF(butal->dists[side], 0.0f)) {
           float *delta = &butal->dists[side];
 
           if (*butal->borders[side] < *butal_other->borders[side_opp]) {
@@ -517,7 +517,7 @@ void ui_block_align_calc(uiBlock *block, const ARegion *region)
           }
           co = (*butal->borders[side] += *delta);
 
-          if (butal_other->dists[side_opp]) {
+          if (!IS_EQF(butal_other->dists[side_opp], 0.0f)) {
             BLI_assert(butal_other->dists[side_opp] * 0.5f == fabsf(*delta));
             *butal_other->borders[side_opp] = co;
             butal_other->dists[side_opp] = 0.0f;
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 5b68ccf9e7c..6cd990ec2b0 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -867,6 +867,7 @@ struct GPUBatch *ui_batch_roundbox_shadow_get(void);
 
 void ui_draw_anti_tria_rect(const rctf *rect, char dir, const float color[4]);
 void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect);
+void ui_draw_box_opaque(rcti *rect, int roundboxalign);
 void ui_draw_popover_back(struct ARegion *region,
                           struct uiStyle *style,
                           uiBlock *block,
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index c5f67e63bd3..f6838002ea5 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -39,6 +39,7 @@
 
 #include "BLT_translation.h"
 
+#include "DNA_screen_types.h"
 #include "DNA_userdef_types.h"
 
 #include "BKE_context.h"
@@ -108,8 +109,14 @@ typedef struct uiHandlePanelData {
   int startsizex, startsizey;
 } uiHandlePanelData;
 
+typedef struct PanelSort {
+  Panel *panel, *orig;
+} PanelSort;
+
 static int get_panel_real_size_y(const Panel *panel);
 static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state);
+static int compare_panel(const void *a1, const void *a2);
+static bool panel_type_context_poll(PanelType *panel_type, const char *context);
 
 static void panel_title_color_get(bool show_background, uchar color[4])
 {
@@ -235,9 +242,335 @@ static bool panels_need_realign(ScrArea *area, ARegion *region, Panel **r_panel_
   return false;
 }
 
+/********* Functions for instanced panels. ***********/
+
+static Panel *UI_panel_add_instanced_ex(
+    ScrArea *area, ARegion *region, ListBase *panels, PanelType *panel_type, int list_index)
+{
+  Panel *panel = MEM_callocN(sizeof(Panel), "instanced panel");
+  panel->type = panel_type;
+  BLI_strncpy(panel->panelname, panel_type->idname, sizeof(panel->panelname));
+
+  panel->runtime.list_index = list_index;
+
+  /* Add the panel's children too. Although they aren't instanced panels, we can still use this
+   * function to create them, as UI_panel_begin does other things we don't need to do. */
+  LISTBASE_FOREACH (LinkData *, child, &panel_type->children) {
+    PanelType *child_type = child->data;
+    UI_panel_add_instanced_ex(area, region, &panel->children, child_type, list_index);
+  }
+
+  /* Make sure the panel is added to the end of the display-order as well. This is needed for
+   * loading existing files.
+   *
+   * Note: We could use special behavior to place it after the panel that starts the list of
+   * instanced panels, but that would add complexity that isn't needed for now. */
+  int max_sortorder = 0;
+  LISTBASE_FOREACH (Panel *, existing_panel, panels) {
+    if (existing_panel->sortorder > max_sortorder) {
+      max_sortorder = existing_panel->sortorder;
+    }
+  }
+  panel->sortorder = max_sortorder + 1;
+
+  BLI_addtail(panels, panel);
+
+  return panel;
+}
+
+/**
+ * Called in situations where panels need to be added dynamically rather than having only one panel
+ * corresponding to each PanelType.
+ */
+Panel *UI_panel_add_instanced(
+    ScrArea *area, ARegion *region, ListBase *panels, char *panel_idname, int list_index)
+{
+  ARegionType *region_type = region->type;
+
+  PanelType *panel_type = BLI_findstring(
+      &region_type->paneltypes, panel_idname, offsetof(PanelType, idname));
+
+  if (panel_type == NULL) {
+    printf("Panel type '%s' not found.\n", panel_idname);
+    return NULL;
+  }
+
+  return UI_panel_add_instanced_ex(area, region, panels, panel_type, list_index);
+}
+
+/**
+ * Find a unique key to append to the idname for the lookup to the panel's #uiBlock. Needed for
+ * instanced panels, where there can be multiple with the same type and idname.
+ */
+void UI_list_panel_unique_str(Panel *panel, char *r_name)
+{
+  snprintf(r_name, LIST_PANEL_UNIQUE_STR_LEN, "%d", panel->runtime.list_index);
+}
+
+/**
+ * Remove the #uiBlock corresponding to a panel. The lookup is needed because panels don't store
+ * a reference to their corresponding #uiBlock.
+ */
+static void panel_free_block(ARegion *region, Panel *panel)
+{
+  BLI_assert(panel->type);
+
+  char block_name[BKE_ST_MAXNAME + LIST_PANEL_UNIQUE_STR_LEN];
+  strncpy(block_name, panel->type->idname, BKE_ST_MAXNAME);
+  char unique_panel_str[LIST_PANEL_UNIQUE_STR_LEN];
+  UI_list_panel_unique_str(panel, unique_panel_str);
+  strncat(block_name, unique_panel_str, LIST_PANEL_UNIQUE_STR_LEN);
+
+  LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
+    if (STREQ(block->name, block_name)) {
+      BLI_remlink(&region->uiblocks, block);
+      UI_block_free(NULL, block);
+      break; /* Only delete one block for this panel. */
+    }
+  }
+}
+
+/**
+ * Free a panel and it's children.
+ *
+ * \note The only panels that should need to be deleted at runtime are panels with the
+ * #PNL_INSTANCED flag set.
+ */
+static void panel_delete(ARegion *region, ListBase *panels, Panel *panel)
+{
+  /* Recursively delete children. */
+  LISTBASE_FOREACH_MUTABLE (Panel *, child, &panel->children) {
+    panel_delete(region, &panel->children, child);
+  }
+  BLI_freelistN(&panel->children);
+
+  panel_free_block(region, panel);
+
+  BLI_remlink(panels, panel);
+  if (panel->activedata) {
+    MEM_freeN(panel->activedata);

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list