[Bf-blender-cvs] [60d1d130464] temp-pose-slide-D9054: Pose Sliding tools improvements

Christoph Lendenfeld noreply at git.blender.org
Thu Apr 15 11:27:38 CEST 2021


Commit: 60d1d130464572c518fef89a252bc7d302506e64
Author: Christoph Lendenfeld
Date:   Thu Apr 15 10:59:52 2021 +0200
Branches: temp-pose-slide-D9054
https://developer.blender.org/rB60d1d130464572c518fef89a252bc7d302506e64

Pose Sliding tools improvements

### Executive Summary

This patch improves pose sliding tools: Breakdowner, Push, and Relax.

The problems with the old tools:
- **No UI**. Even though it's clear how the tool works when you move the mouse, there is no visual indication as to the actual scale of the movement required.
- **No mouse wrapping**. This means that you have to carefully plan the initial position of the mouse when using the tools, because that impacts which values are available. This makes it hard to use it from the menu, as that forces the mouse to be in a certain position.
- **No precision mode** by pressing shift.
- **No overshoot protection**, so it's very easy to go below 0% or above 100%.

These problems are **all solved in this patch**.

##### Demo video

Here {key Shift E} is used to start the Pose Breakdowner.

{F9929705}

### Original description

**Problem**
The existing Push, Relax and Breakdowner tools are great, but the fact that they use the whole area range is less than ideal.
In theory, the tools support going beyond 0% and 100% to create an overshoot, but since they use the whole are, you might be blocked by the edges of the screen.

**Solution**
Set a pixel value as defined distance from 0% to 100% (scales with gui)
To indicate that, draw a UI under the cursor.
The percentage is now calculated accumulative to enable precision support when holding SHIFT

Info about new modifier keys is printed to the workspace status
{F9891261}

Update 2020_10_12: All lines have outlines now and handle is orange for better readability on white.
Update 2021_01_18: Static indicators moved to bottom. tick spacing now every 10%
Update 2021_03_14: Remove the slider and replace with a simple percentage indicator. (Cursor not visible in screenshot)
Update 2021_04_11: Brought the slider back. Spawns centered at the bottom of the screen
{F9929709}

By default the percentage is clamped to 0-1. But by pressing E you can enable overshoot.
Update 2020_10_12: slider range in overshoot mode is now 150% to better indicate that it can go further
Update 2021_03_14: Since the slider was removed, the percentage amount is simply displayed under the cursor
Update 2021_04_11: Overshoot now scrolls in place
{F9929712}

**Limitations and future improvements**
As mentioned in the comments below it would be a good idea to write a more general version of the slider to be used in various areas of Blender.

**Build**
[[ https://blender.community/c/graphicall/dqbbbc/ | Windows build on graphicall ]]

**Edit**
Split off the operator into it's own patch D9137

Reviewed By: zeddb, brecht, Severin, looch

Maniphest Tasks: T81836

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

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

M	source/blender/editors/armature/CMakeLists.txt
M	source/blender/editors/armature/pose_slide.c

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

diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt
index 98c050950be..7266b1b88d7 100644
--- a/source/blender/editors/armature/CMakeLists.txt
+++ b/source/blender/editors/armature/CMakeLists.txt
@@ -19,6 +19,7 @@ set(INC
   ../include
   ../../blenkernel
   ../../blenlib
+  ../../blenfont
   ../../blentranslation
   ../../depsgraph
   ../../gpu
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 93d36abe792..9b285f06d14 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -33,6 +33,7 @@
 #include "DNA_armature_types.h"
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
+#include "DNA_vec_types.h"
 
 #include "BKE_fcurve.h"
 #include "BKE_nla.h"
@@ -50,15 +51,27 @@
 #include "WM_types.h"
 
 #include "UI_interface.h"
+#include "UI_resources.h"
 
 #include "ED_armature.h"
 #include "ED_keyframes_draw.h"
 #include "ED_markers.h"
 #include "ED_numinput.h"
 #include "ED_screen.h"
+#include "ED_space_api.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
 
 #include "armature_intern.h"
 
+#include "BLF_api.h"
+
+/* Pixel distance from 0% to 100%. */
+#define SLIDE_PIXEL_DISTANCE (300 * U.dpi_fac)
+
 /* **************************************************** */
 /* == POSE 'SLIDING' TOOLS ==
  *
@@ -110,15 +123,43 @@ typedef struct tPoseSlideOp {
   /** unused for now, but can later get used for storing runtime settings.... */
   short flag;
 
+  /* Store overlay settings when invoking the operator. Bones will be temporarily hidden. */
+  int overlay_flag;
+
   /** which transforms/channels are affected (ePoseSlide_Channels) */
   short channels;
   /** axis-limits for transforms (ePoseSlide_AxisLock) */
   short axislock;
 
-  /** 0-1 value for determining the influence of whatever is relevant */
+  /* Allow overshoot or clamp between 0% and 100%. */
+  bool overshoot;
+
+  /* Reduces percentage delta from mouse movement. */
+  bool precision;
+
+  /* Move percentage in 10% steps. */
+  bool increments;
+
+  /* Pixel value in area space where the slider starts. */
+  int slider_start[2];
+
+  /* Draw callback handler. */
+  void *draw_handle;
+
+  /* Accumulative, unclamped and unrounded percentage. */
+  float raw_percentage;
+
+  /* 0-1 value for determining the influence of whatever is relevant. */
   float percentage;
 
-  /** numeric input */
+  /* Cursor position in region space. */
+  int cursor_region_x;
+  int cursor_region_y;
+
+  /* Last cursor position in screen space used for mouse movement delta calculation. */
+  int last_cursor_x;
+
+  /* Numeric input. */
   NumInput num;
 
   struct tPoseSlideObject *ob_data_array;
@@ -187,6 +228,135 @@ static const EnumPropertyItem prop_axis_lock_types[] = {
 
 /* ------------------------------------ */
 
+/* Draw a given string centered at the given coordinates. */
+static void draw_centered_string_with_background(
+    const char *string, const float x, const float y, const uchar color_bg[4], const int fontid)
+{
+  const int bg_margin = 5 * U.dpi_fac;
+  float string_pixel_size[2];
+  /* Get width and height of printed string to center above ticks. */
+  BLF_width_and_height(
+      fontid, string, sizeof(string), &string_pixel_size[0], &string_pixel_size[1]);
+  const unsigned char col[3] = {color_bg[0], color_bg[1], color_bg[2]};
+  const rctf background_rect = {.xmin = x - string_pixel_size[0] / 2 - bg_margin,
+                                .xmax = x + string_pixel_size[0] / 2 + bg_margin,
+                                .ymin = y - string_pixel_size[1] / 2 - bg_margin,
+                                .ymax = y + string_pixel_size[1] / 2 + bg_margin};
+  UI_draw_roundbox_3ub_alpha(&background_rect, true, 4.0f, col, color_bg[3]);
+  BLF_position(fontid, x - string_pixel_size[0] / 2, y - string_pixel_size[1] / 2, 0.0f);
+  BLF_draw(fontid, string, sizeof(string));
+}
+
+/* Draw an on screen Slider for a Pose Slide Operator. */
+static void pose_slide_draw_2d_slider(const struct bContext *UNUSED(C), ARegion *region, void *arg)
+{
+  tPoseSlideOp *pso = arg;
+
+  /* Only draw in region from which the Operator was started. */
+  if (region != pso->region) {
+    return;
+  }
+
+  uchar color_text[4];
+  uchar color_line[4];
+  uchar color_handle[4];
+  uchar color_bg[4];
+
+  char percentage_string[256];
+
+  immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+  /* Get theme colors. Text gets a different color when the value is clamped.*/
+  UI_GetThemeColor4ubv(TH_TEXT, color_text);
+  UI_GetThemeColor4ubv(TH_TEXT, color_line);
+  UI_GetThemeColor4ubv(TH_ACTIVE, color_handle);
+  UI_GetThemeColor4ubv(TH_HEADER, color_bg);
+  color_bg[3] = 160;
+
+  /* Get the default font. */
+  const uiStyle *style = UI_style_get();
+  const uiFontStyle *fstyle = &style->widget;
+  const int fontid = fstyle->uifont_id;
+  BLF_color3ubv(fontid, color_text);
+  BLF_rotation(fontid, 0.0f);
+
+  const float line_width = 4 * U.dpi_fac;
+  const float base_tick_height = 16.0 * U.dpi_fac;
+  const float text_offset = 24.0 * U.dpi_fac;
+  const float overshoot_range_delta = 0.2;
+  int initial_tick_percentage;
+  int handle_pos_x;
+  float overshoot_length_delta;
+
+  if (pso->overshoot) {
+    initial_tick_percentage = (int)((pso->percentage - 0.5f - overshoot_range_delta) * 100);
+    handle_pos_x = pso->slider_start[0] + (SLIDE_PIXEL_DISTANCE / 2);
+    overshoot_length_delta = SLIDE_PIXEL_DISTANCE * overshoot_range_delta;
+  }
+  else {
+    initial_tick_percentage = 0;
+    handle_pos_x = pso->slider_start[0] + SLIDE_PIXEL_DISTANCE * pso->percentage;
+    overshoot_length_delta = 0;
+  }
+
+  /* Draw main line. */
+  const struct rctf main_line_rect = {.xmin = pso->slider_start[0] - overshoot_length_delta,
+                                      .xmax = pso->slider_start[0] + SLIDE_PIXEL_DISTANCE +
+                                              overshoot_length_delta,
+                                      .ymin = pso->slider_start[1] - line_width / 2,
+                                      .ymax = pso->slider_start[1] + line_width / 2};
+  UI_draw_roundbox_3ub_alpha(&main_line_rect, true, 0, color_line, 255);
+  UI_draw_roundbox_3ub_alpha(&main_line_rect, false, 0, color_bg, 255);
+
+  /* Draw percentage ticks. */
+  const int tick_increment = 10;
+  const int percentage_range = pso->overshoot ? 100 + 100 * overshoot_range_delta * 2 : 100;
+
+  /* Round initial_tick_percentage up to the next tick_increment. */
+  int tick_percentage = ceil((float)initial_tick_percentage / tick_increment) * tick_increment;
+
+  for (; tick_percentage <= initial_tick_percentage + percentage_range;
+       tick_percentage += tick_increment) {
+    const float x = handle_pos_x +
+                    SLIDE_PIXEL_DISTANCE * (((float)tick_percentage / 100) - pso->percentage);
+    /* 0.5 steps are considered main ticks and are drawn thicker with
+     * percentage indicator string below. */
+    const bool is_main_tick = tick_percentage % 50 == 0;
+    const float tick_height = is_main_tick ? base_tick_height : base_tick_height / 2;
+
+    const struct rctf tick_rect = {.xmin = x - (line_width / 2),
+                                   .xmax = x + (line_width / 2),
+                                   .ymin = pso->slider_start[1] - (tick_height / 2),
+                                   .ymax = pso->slider_start[1] + (tick_height / 2)};
+
+    UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_line, 255);
+    UI_draw_roundbox_3ub_alpha(&tick_rect, false, 1, color_bg, 255);
+
+    /* Draw percentage on main ticks. */
+    if (is_main_tick) {
+      BLI_snprintf(percentage_string, sizeof(percentage_string), "%d%%", tick_percentage);
+      draw_centered_string_with_background(
+          percentage_string, x, pso->slider_start[1] - text_offset, color_bg, fontid);
+    }
+  }
+
+  /* Draw handle indicating current percentage. */
+  const struct rctf handle_rect = {.xmin = handle_pos_x - (line_width),
+                                   .xmax = handle_pos_x + (line_width),
+                                   .ymin = pso->slider_start[1] - (base_tick_height / 2),
+                                   .ymax = pso->slider_start[1] + (base_tick_height / 2)};
+
+  UI_draw_roundbox_3ub_alpha(&handle_rect, true, 1, color_handle, 255);
+  UI_draw_roundbox_3ub_alpha(&handle_rect, false, 1, color_bg, 255);
+
+  BLI_snprintf(percentage_string, sizeof(percentage_string), "%.0f%%", pso->percentage * 100);
+  draw_centered_string_with_background(
+      percentage_string, handle_pos_x, pso->slider_start[1] + text_offset, color_bg, fontid);
+
+  GPU_blend(GPU_BLEND_NONE);
+  immUnbindProgram();
+}
+
 /* operator init */
 static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
 {
@@ -205,6 +375,7 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
 
   /* set range info from property values - these may get overridden for the invoke() */
   pso->percentage = RNA_float_get(op->ptr, "percentage");
+  pso->raw_percentage = pso->percentage;
   pso->prevFrame = RNA_int_get(op->ptr, "prev_frame");
   pso->nextFrame = RNA_int_get(op->ptr, "next_frame");
 
@@ -257,6 +428,10 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
   pso->num.val_flag[0] |= NUM_NO_NEGATIVE;
   pso->num.unit_type[0] = B_UNIT_NONE; /* percentages don't have any units... */
 
+  /* Register UI drawing callback. */
+  pso->draw_handle = ED_region_draw_cb_activate(
+      pso->region->type, pose_slide_draw_2d_slider, pso, REGION_DRAW_POST_PIXEL);
+
   /* return status is whether we've got all the data we were requested to get */
   return 1;
 }
@@ -266,6 +441,13 @@ static void pose_slide_exit(wmOperator *op)
 {
   tPoseSlideOp *pso = op->customdata;
 
+  /* Hide Bone Overlay. */
+  View3D *v3d = pso->area->spacedata.first;
+  v3d->overlay.flag = pso->overlay_flag;
+
+  /* Remove UI drawing callback. */
+  ED_region_draw_cb_exit(pso->region->type, pso->draw_handle);
+
   /* if data exists, clear its data and exit */
   if (pso) {
     /* free the temp pchan links and

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list