Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2020-06-24 18:50:01 +0300
committerHans Goudey <h.goudey@me.com>2020-06-24 18:50:01 +0300
commitbaff05ad1c156ca477375c440e2c5b92cad214e9 (patch)
treeb89d9d5a9e9611247d964d5e9b0ccd098bf88c2d /source/blender/editors/interface
parentec7510b458528eb8dcdf2c538a2b805813940447 (diff)
UI: Add Free Handle Types to CurveProfile Widget
Under the hood the CurveProfile widget (used for bevel custom profiles) uses a bezier curve, but right now though it only supports two of the bezier curve handle types, vector and auto. This patch adds support for free handles and adds all of the logic for editing them. This is the first step to the ability to import and export curve objects in the widget. There's some code cleanup in curveprofile.c. Movement for handles and control points is abstracted to functions there rather than happening in interface_handlers.c. An "Apply Preset" button is also added, which solves a confusing issue where you apply a preset, then change the number of samples and the preset doesn't change. The button makes it clear that the preset needs to be reapplied. Reviewed By: Severin Differential Revision: https://developer.blender.org/D6470
Diffstat (limited to 'source/blender/editors/interface')
-rw-r--r--source/blender/editors/interface/interface_draw.c113
-rw-r--r--source/blender/editors/interface/interface_handlers.c154
-rw-r--r--source/blender/editors/interface/interface_templates.c132
3 files changed, 244 insertions, 155 deletions
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 1cb8565b38d..98cb85061f2 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -25,6 +25,7 @@
#include <string.h>
#include "DNA_color_types.h"
+#include "DNA_curve_types.h"
#include "DNA_curveprofile_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_screen_types.h"
@@ -2159,7 +2160,19 @@ void ui_draw_but_CURVE(ARegion *region, uiBut *but, const uiWidgetColors *wcol,
immUnbindProgram();
}
-/** Used to draw a curve profile widget. Somewhat similar to ui_draw_but_CURVE */
+/**
+ * Helper for #ui_draw_but_CURVEPROFILE. Used to tell whether to draw a control point's handles.
+ */
+static bool point_draw_handles(CurveProfilePoint *point)
+{
+ return (point->flag & PROF_SELECT &&
+ (ELEM(point->h1, HD_FREE, HD_ALIGN) || ELEM(point->h2, HD_FREE, HD_ALIGN))) ||
+ ELEM(point->flag, PROF_H1_SELECT, PROF_H2_SELECT);
+}
+
+/**
+ * Draws the curve profile widget. Somewhat similar to ui_draw_but_CURVE.
+ */
void ui_draw_but_CURVEPROFILE(ARegion *region,
uiBut *but,
const uiWidgetColors *wcol,
@@ -2175,18 +2188,18 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
profile = (CurveProfile *)but->poin;
}
- /* Calculate offset and zoom */
+ /* Calculate offset and zoom. */
float zoomx = (BLI_rcti_size_x(rect) - 2.0f) / BLI_rctf_size_x(&profile->view_rect);
float zoomy = (BLI_rcti_size_y(rect) - 2.0f) / BLI_rctf_size_y(&profile->view_rect);
float offsx = profile->view_rect.xmin - (1.0f / zoomx);
float offsy = profile->view_rect.ymin - (1.0f / zoomy);
- /* Exit early if too narrow */
+ /* Exit early if too narrow. */
if (zoomx == 0.0f) {
return;
}
- /* Test needed because path can draw outside of boundary */
+ /* Test needed because path can draw outside of boundary. */
int scissor[4];
GPU_scissor_get_i(scissor);
rcti scissor_new = {
@@ -2208,7 +2221,7 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- /* Backdrop */
+ /* Draw the backdrop. */
float color_backdrop[4] = {0, 0, 0, 1};
if (profile->flag & PROF_USE_CLIP) {
gl_shaded_color_get_fl((uchar *)wcol->inner, -20, color_backdrop);
@@ -2227,33 +2240,33 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
}
- /* 0.25 step grid */
+ /* 0.25 step grid. */
gl_shaded_color((uchar *)wcol->inner, -16);
ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 0.25f);
- /* 1.0 step grid */
+ /* 1.0 step grid. */
gl_shaded_color((uchar *)wcol->inner, -24);
ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 1.0f);
- /* Draw the path's fill */
+ /* Draw the path's fill. */
if (profile->table == NULL) {
- BKE_curveprofile_update(profile, false);
+ BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
}
CurveProfilePoint *pts = profile->table;
- /* Also add the last points on the right and bottom edges to close off the fill polygon */
+ /* Also add the last points on the right and bottom edges to close off the fill polygon. */
bool add_left_tri = profile->view_rect.xmin < 0.0f;
bool add_bottom_tri = profile->view_rect.ymin < 0.0f;
uint tot_points = (uint)PROF_N_TABLE(profile->path_len) + 1 + add_left_tri + add_bottom_tri;
uint tot_triangles = tot_points - 2;
- /* Create array of the positions of the table's points */
+ /* Create array of the positions of the table's points. */
float(*table_coords)[2] = MEM_mallocN(sizeof(*table_coords) * tot_points, "table x coords");
for (i = 0; i < (uint)PROF_N_TABLE(profile->path_len);
- i++) { /* Only add the points from the table here */
+ i++) { /* Only add the points from the table here. */
table_coords[i][0] = pts[i].x;
table_coords[i][1] = pts[i].y;
}
if (add_left_tri && add_bottom_tri) {
- /* Add left side, bottom left corner, and bottom side points */
+ /* Add left side, bottom left corner, and bottom side points. */
table_coords[tot_points - 3][0] = profile->view_rect.xmin;
table_coords[tot_points - 3][1] = 1.0f;
table_coords[tot_points - 2][0] = profile->view_rect.xmin;
@@ -2262,30 +2275,30 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
table_coords[tot_points - 1][1] = profile->view_rect.ymin;
}
else if (add_left_tri) {
- /* Add the left side and bottom left corner points */
+ /* Add the left side and bottom left corner points. */
table_coords[tot_points - 2][0] = profile->view_rect.xmin;
table_coords[tot_points - 2][1] = 1.0f;
table_coords[tot_points - 1][0] = profile->view_rect.xmin;
table_coords[tot_points - 1][1] = 0.0f;
}
else if (add_bottom_tri) {
- /* Add the bottom side and bottom left corner points */
+ /* Add the bottom side and bottom left corner points. */
table_coords[tot_points - 2][0] = 0.0f;
table_coords[tot_points - 2][1] = profile->view_rect.ymin;
table_coords[tot_points - 1][0] = 1.0f;
table_coords[tot_points - 1][1] = profile->view_rect.ymin;
}
else {
- /* Just add the bottom corner point. Side points would be redundant anyway */
+ /* Just add the bottom corner point. Side points would be redundant anyway. */
table_coords[tot_points - 1][0] = 0.0f;
table_coords[tot_points - 1][1] = 0.0f;
}
- /* Calculate the table point indices of the triangles for the profile's fill */
+ /* Calculate the table point indices of the triangles for the profile's fill. */
uint(*tri_indices)[3] = MEM_mallocN(sizeof(*tri_indices) * tot_triangles, "return tri indices");
BLI_polyfill_calc(table_coords, tot_points, -1, tri_indices);
- /* Draw the triangles for the profile fill */
+ /* Draw the triangles for the profile fill. */
immUniformColor3ubvAlpha((const uchar *)wcol->item, 128);
GPU_blend(true);
GPU_polygon_smooth(false);
@@ -2301,7 +2314,7 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
immEnd();
MEM_freeN(tri_indices);
- /* Draw the profile's path so the edge stands out a bit */
+ /* Draw the profile's path so the edge stands out a bit. */
tot_points -= (add_left_tri + add_left_tri);
GPU_line_width(1.0f);
immUniformColor3ubvAlpha((const uchar *)wcol->item, 255);
@@ -2313,9 +2326,44 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
immVertex2f(pos, fx, fy);
}
immEnd();
- immUnbindProgram();
MEM_freeN(table_coords);
+ /* Draw the handles for the selected control points. */
+ pts = profile->path;
+ tot_points = (uint)profile->path_len;
+ int selected_free_points = 0;
+ for (i = 0; i < tot_points; i++) {
+ if (point_draw_handles(&pts[i])) {
+ selected_free_points++;
+ }
+ }
+ /* Draw the lines to the handles from the points. */
+ if (selected_free_points > 0) {
+ GPU_line_width(1.0f);
+ gl_shaded_color((uchar *)wcol->inner, -24);
+ GPU_line_smooth(true);
+ immBegin(GPU_PRIM_LINES, selected_free_points * 4);
+ float ptx, pty;
+ for (i = 0; i < tot_points; i++) {
+ if (point_draw_handles(&pts[i])) {
+ ptx = rect->xmin + zoomx * (pts[i].x - offsx);
+ pty = rect->ymin + zoomy * (pts[i].y - offsy);
+
+ fx = rect->xmin + zoomx * (pts[i].h1_loc[0] - offsx);
+ fy = rect->ymin + zoomy * (pts[i].h1_loc[1] - offsy);
+ immVertex2f(pos, ptx, pty);
+ immVertex2f(pos, fx, fy);
+
+ fx = rect->xmin + zoomx * (pts[i].h2_loc[0] - offsx);
+ fy = rect->ymin + zoomy * (pts[i].h2_loc[1] - offsy);
+ immVertex2f(pos, ptx, pty);
+ immVertex2f(pos, fx, fy);
+ }
+ }
+ immEnd();
+ }
+ immUnbindProgram();
+
/* New GPU instructions for control points and sampled points. */
format = immVertexFormat();
pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -2339,8 +2387,6 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
}
/* Draw the control points. */
- pts = profile->path;
- tot_points = (uint)profile->path_len;
GPU_line_smooth(false);
GPU_blend(false);
GPU_point_size(max_ff(3.0f, min_ff(UI_DPI_FAC / but->block->aspect * 5.0f, 5.0f)));
@@ -2353,6 +2399,28 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
}
immEnd();
+ /* Draw the handle points. */
+ if (selected_free_points > 0) {
+ GPU_line_smooth(false);
+ GPU_blend(false);
+ GPU_point_size(max_ff(2.0f, min_ff(UI_DPI_FAC / but->block->aspect * 4.0f, 4.0f)));
+ immBegin(GPU_PRIM_POINTS, selected_free_points * 2);
+ for (i = 0; i < tot_points; i++) {
+ if (point_draw_handles(&pts[i])) {
+ fx = rect->xmin + zoomx * (pts[i].h1_loc[0] - offsx);
+ fy = rect->ymin + zoomy * (pts[i].h1_loc[1] - offsy);
+ immAttr4fv(col, (pts[i].flag & PROF_H1_SELECT) ? color_vert_select : color_vert);
+ immVertex2f(pos, fx, fy);
+
+ fx = rect->xmin + zoomx * (pts[i].h2_loc[0] - offsx);
+ fy = rect->ymin + zoomy * (pts[i].h2_loc[1] - offsy);
+ immAttr4fv(col, (pts[i].flag & PROF_H2_SELECT) ? color_vert_select : color_vert);
+ immVertex2f(pos, fx, fy);
+ }
+ }
+ immEnd();
+ }
+
/* Draw the sampled points in addition to the control points if they have been created */
pts = profile->segments;
tot_points = (uint)profile->segments_len;
@@ -2367,7 +2435,6 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
}
immEnd();
}
-
immUnbindProgram();
/* restore scissortest */
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 3f3f0513184..f6bfb492c92 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -6944,7 +6944,7 @@ static bool ui_numedit_but_CURVEPROFILE(uiBlock *block,
d[0] = mx - data->dragstartx;
d[1] = my - data->dragstarty;
- if (len_squared_v2(d) < (3.0f * 3.0f)) {
+ if (len_squared_v2(d) < (9.0f * U.dpi_fac)) {
snap = false;
}
}
@@ -6953,32 +6953,38 @@ static bool ui_numedit_but_CURVEPROFILE(uiBlock *block,
fy = (my - dragy) / zoomy;
if (data->dragsel != -1) {
- CurveProfilePoint *point_last = NULL;
+ float last_x, last_y;
const float mval_factor = ui_mouse_scale_warp_factor(shift);
bool moved_point = false; /* for ctrl grid, can't use orig coords because of sorting */
fx *= mval_factor;
fy *= mval_factor;
- /* Move all the points that aren't the last or the first */
- for (a = 1; a < profile->path_len - 1; a++) {
- if (pts[a].flag & PROF_SELECT) {
- float origx = pts[a].x, origy = pts[a].y;
- pts[a].x += fx;
- pts[a].y += fy;
- if (snap) {
- pts[a].x = 0.125f * roundf(8.0f * pts[a].x);
- pts[a].y = 0.125f * roundf(8.0f * pts[a].y);
+ /* Move all selected points. */
+ float delta[2] = {fx, fy};
+ for (a = 0; a < profile->path_len; a++) {
+ /* Don't move the last and first control points. */
+ if ((pts[a].flag & PROF_SELECT) && (a != 0) && (a != profile->path_len)) {
+ moved_point |= BKE_curveprofile_move_point(profile, &pts[a], snap, delta);
+ last_x = pts[a].x;
+ last_y = pts[a].y;
+ }
+ else {
+ /* Move handles when they're selected but the control point isn't. */
+ if (ELEM(pts[a].h2, HD_FREE, HD_ALIGN) && pts[a].flag == PROF_H1_SELECT) {
+ moved_point |= BKE_curveprofile_move_handle(&pts[a], true, snap, delta);
+ last_x = pts[a].h1_loc[0];
+ last_y = pts[a].h1_loc[1];
}
- if (!moved_point && (pts[a].x != origx || pts[a].y != origy)) {
- moved_point = true;
+ if (ELEM(pts[a].h2, HD_FREE, HD_ALIGN) && pts[a].flag == PROF_H2_SELECT) {
+ moved_point |= BKE_curveprofile_move_handle(&pts[a], false, snap, delta);
+ last_x = pts[a].h2_loc[0];
+ last_y = pts[a].h2_loc[1];
}
-
- point_last = &pts[a];
}
}
- BKE_curveprofile_update(profile, false);
+ BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
if (moved_point) {
data->draglastx = evtx;
@@ -6989,10 +6995,8 @@ static bool ui_numedit_but_CURVEPROFILE(uiBlock *block,
* but in practice this isnt really an issue */
if (ui_but_is_cursor_warp(but)) {
/* OK but can go outside bounds */
- data->ungrab_mval[0] = but->rect.xmin +
- ((point_last->x - profile->view_rect.xmin) * zoomx);
- data->ungrab_mval[1] = but->rect.ymin +
- ((point_last->y - profile->view_rect.ymin) * zoomy);
+ data->ungrab_mval[0] = but->rect.xmin + ((last_x - profile->view_rect.xmin) * zoomx);
+ data->ungrab_mval[1] = but->rect.ymin + ((last_y - profile->view_rect.ymin) * zoomy);
BLI_rctf_clamp_pt_v(&but->rect, data->ungrab_mval);
}
#endif
@@ -7000,7 +7004,7 @@ static bool ui_numedit_but_CURVEPROFILE(uiBlock *block,
data->dragchange = true; /* mark for selection */
}
else {
- /* clamp for clip */
+ /* Clamp the view rect when clipping is on. */
if (profile->flag & PROF_USE_CLIP) {
if (profile->view_rect.xmin - fx < profile->clip_rect.xmin) {
fx = profile->view_rect.xmin - profile->clip_rect.xmin;
@@ -7031,16 +7035,26 @@ static bool ui_numedit_but_CURVEPROFILE(uiBlock *block,
}
/**
+ * Helper for #ui_do_but_CURVEPROFILE. Used to tell whether to select a control point's handles.
+ */
+static bool point_draw_handles(CurveProfilePoint *point)
+{
+ return (point->flag & PROF_SELECT &&
+ (ELEM(point->h1, HD_FREE, HD_ALIGN) || ELEM(point->h2, HD_FREE, HD_ALIGN))) ||
+ ELEM(point->flag, PROF_H1_SELECT, PROF_H2_SELECT);
+}
+
+/**
* Interaction for curve profile widget.
* \note Uses hardcoded keys rather than the keymap.
*/
static int ui_do_but_CURVEPROFILE(
bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
- int mx, my, i;
+ CurveProfile *profile = (CurveProfile *)but->poin;
+ int mx = event->x;
+ int my = event->y;
- mx = event->x;
- my = event->y;
ui_window_to_block(data->region, block, &mx, &my);
/* Move selected control points. */
@@ -7053,12 +7067,10 @@ static int ui_do_but_CURVEPROFILE(
return WM_UI_HANDLER_BREAK;
}
- CurveProfile *profile = (CurveProfile *)but->poin;
-
/* Delete selected control points. */
if (event->type == EVT_XKEY && event->val == KM_RELEASE) {
BKE_curveprofile_remove_by_flag(profile, PROF_SELECT);
- BKE_curveprofile_update(profile, false);
+ BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
button_activate_state(C, but, BUTTON_STATE_EXIT);
return WM_UI_HANDLER_BREAK;
}
@@ -7066,76 +7078,94 @@ static int ui_do_but_CURVEPROFILE(
/* Selecting, adding, and starting point movements. */
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
- CurveProfilePoint *pts; /* Path or table. */
const float m_xy[2] = {mx, my};
- float dist_min_sq;
- int i_selected = -1;
if (event->ctrl) {
float f_xy[2];
BLI_rctf_transform_pt_v(&profile->view_rect, &but->rect, f_xy, m_xy);
BKE_curveprofile_insert(profile, f_xy[0], f_xy[1]);
- BKE_curveprofile_update(profile, false);
+ BKE_curveprofile_update(profile, PROF_UPDATE_CLIP);
}
/* Check for selecting of a point by finding closest point in radius. */
- dist_min_sq = square_f(U.dpi_fac * 14.0f); /* 14 pixels radius for selecting points. */
- pts = profile->path;
- for (i = 0; i < profile->path_len; i++) {
+ CurveProfilePoint *pts = profile->path;
+ float dist_min_sq = square_f(U.dpi_fac * 14.0f); /* 14 pixels radius for selecting points. */
+ int i_selected = -1;
+ short selection_type = 0; /* For handle selection. */
+ for (int i = 0; i < profile->path_len; i++) {
float f_xy[2];
BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, &pts[i].x);
- const float dist_sq = len_squared_v2v2(m_xy, f_xy);
+ float dist_sq = len_squared_v2v2(m_xy, f_xy);
if (dist_sq < dist_min_sq) {
i_selected = i;
+ selection_type = PROF_SELECT;
dist_min_sq = dist_sq;
}
+
+ /* Also select handles if the point is selected and it has the right handle type. */
+ if (point_draw_handles(&pts[i])) {
+ if (ELEM(profile->path[i].h1, HD_FREE, HD_ALIGN)) {
+ BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, pts[i].h1_loc);
+ dist_sq = len_squared_v2v2(m_xy, f_xy);
+ if (dist_sq < dist_min_sq) {
+ i_selected = i;
+ selection_type = PROF_H1_SELECT;
+ dist_min_sq = dist_sq;
+ }
+ }
+ if (ELEM(profile->path[i].h2, HD_FREE, HD_ALIGN)) {
+ BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, pts[i].h2_loc);
+ dist_sq = len_squared_v2v2(m_xy, f_xy);
+ if (dist_sq < dist_min_sq) {
+ i_selected = i;
+ selection_type = PROF_H2_SELECT;
+ dist_min_sq = dist_sq;
+ }
+ }
+ }
}
- /* Add a point if the click was close to the path but not a control point. */
- if (i_selected == -1) { /* No control point selected. */
+ /* Add a point if the click was close to the path but not a control point or handle. */
+ if (i_selected == -1) {
float f_xy[2], f_xy_prev[2];
- pts = profile->table;
- BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, &pts[0].x);
+ CurveProfilePoint *table = profile->table;
+ BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, &table[0].x);
dist_min_sq = square_f(U.dpi_fac * 8.0f); /* 8 pixel radius from each table point. */
/* Loop through the path's high resolution table and find what's near the click. */
- for (i = 1; i <= PROF_N_TABLE(profile->path_len); i++) {
+ for (int i = 1; i <= PROF_N_TABLE(profile->path_len); i++) {
copy_v2_v2(f_xy_prev, f_xy);
- BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, &pts[i].x);
+ BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, &table[i].x);
if (dist_squared_to_line_segment_v2(m_xy, f_xy_prev, f_xy) < dist_min_sq) {
BLI_rctf_transform_pt_v(&profile->view_rect, &but->rect, f_xy, m_xy);
CurveProfilePoint *new_pt = BKE_curveprofile_insert(profile, f_xy[0], f_xy[1]);
- BKE_curveprofile_update(profile, false);
-
- /* reset pts back to the control points. */
- pts = profile->path;
+ BKE_curveprofile_update(profile, PROF_UPDATE_CLIP);
/* Get the index of the newly added point. */
- for (i = 0; i < profile->path_len; i++) {
- if (&pts[i] == new_pt) {
- i_selected = i;
- }
- }
+ i_selected = (int)(new_pt - profile->path);
+ BLI_assert(i_selected >= 0 && i_selected <= profile->path_len);
+ selection_type = PROF_SELECT;
break;
}
}
}
- /* Change the flag for the point(s) if one was selected. */
+ /* Change the flag for the point(s) if one was selected or added. */
if (i_selected != -1) {
/* Deselect all if this one is deselected, except if we hold shift. */
- if (!event->shift) {
- for (i = 0; i < profile->path_len; i++) {
- pts[i].flag &= ~PROF_SELECT;
- }
- pts[i_selected].flag |= PROF_SELECT;
+ if (event->shift) {
+ pts[i_selected].flag ^= selection_type;
}
else {
- pts[i_selected].flag ^= PROF_SELECT;
+ for (int i = 0; i < profile->path_len; i++) {
+ // pts[i].flag &= ~(PROF_SELECT | PROF_H1_SELECT | PROF_H2_SELECT);
+ profile->path[i].flag &= ~(PROF_SELECT | PROF_H1_SELECT | PROF_H2_SELECT);
+ }
+ profile->path[i_selected].flag |= selection_type;
}
}
else {
@@ -7166,19 +7196,13 @@ static int ui_do_but_CURVEPROFILE(
else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
/* Finish move. */
if (data->dragsel != -1) {
- CurveProfilePoint *pts = profile->path;
if (data->dragchange == false) {
/* Deselect all, select one. */
- if (!event->shift) {
- for (i = 0; i < profile->path_len; i++) {
- pts[i].flag &= ~PROF_SELECT;
- }
- pts[data->dragsel].flag |= PROF_SELECT;
- }
}
else {
- BKE_curveprofile_update(profile, true); /* Remove doubles after move. */
+ /* Remove doubles, clip after move. */
+ BKE_curveprofile_update(profile, PROF_UPDATE_REMOVE_DOUBLES | PROF_UPDATE_CLIP);
}
}
button_activate_state(C, but, BUTTON_STATE_EXIT);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 16b6b313f69..0d6717c8e12 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -4463,7 +4463,7 @@ static void CurveProfile_presets_dofunc(bContext *C, void *profile_v, int event)
profile->preset = event;
BKE_curveprofile_reset(profile);
- BKE_curveprofile_update(profile, false);
+ BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
ED_undo_push(C, "CurveProfile tools");
ED_region_tag_redraw(CTX_wm_region(C));
@@ -4579,7 +4579,7 @@ static void CurveProfile_tools_dofunc(bContext *C, void *profile_v, int event)
switch (event) {
case UIPROFILE_FUNC_RESET: /* reset */
BKE_curveprofile_reset(profile);
- BKE_curveprofile_update(profile, false);
+ BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
break;
case UIPROFILE_FUNC_RESET_VIEW: /* reset view to clipping rect */
profile->view_rect = profile->clip_rect;
@@ -4645,7 +4645,7 @@ static void CurveProfile_buttons_zoom_in(bContext *C, void *profile_v, void *UNU
CurveProfile *profile = profile_v;
float d;
- /* we allow 20 times zoom */
+ /* Allow a 20x zoom. */
if (BLI_rctf_size_x(&profile->view_rect) > 0.04f * BLI_rctf_size_x(&profile->clip_rect)) {
d = 0.1154f * BLI_rctf_size_x(&profile->view_rect);
profile->view_rect.xmin += d;
@@ -4709,7 +4709,7 @@ static void CurveProfile_clipping_toggle(bContext *C, void *cb_v, void *profile_
profile->flag ^= PROF_USE_CLIP;
- BKE_curveprofile_update(profile, false);
+ BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
rna_update_cb(C, cb_v, NULL);
}
@@ -4718,7 +4718,7 @@ static void CurveProfile_buttons_reverse(bContext *C, void *cb_v, void *profile_
CurveProfile *profile = profile_v;
BKE_curveprofile_reverse(profile);
- BKE_curveprofile_update(profile, false);
+ BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
rna_update_cb(C, cb_v, NULL);
}
@@ -4727,35 +4727,23 @@ static void CurveProfile_buttons_delete(bContext *C, void *cb_v, void *profile_v
CurveProfile *profile = profile_v;
BKE_curveprofile_remove_by_flag(profile, SELECT);
- BKE_curveprofile_update(profile, false);
-
- rna_update_cb(C, cb_v, NULL);
-}
-
-static void CurveProfile_buttons_setsharp(bContext *C, void *cb_v, void *profile_v)
-{
- CurveProfile *profile = profile_v;
-
- BKE_curveprofile_selected_handle_set(profile, HD_VECT, HD_VECT);
- BKE_curveprofile_update(profile, false);
+ BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
rna_update_cb(C, cb_v, NULL);
}
-static void CurveProfile_buttons_setcurved(bContext *C, void *cb_v, void *profile_v)
+static void CurveProfile_buttons_update(bContext *C, void *arg1_v, void *profile_v)
{
CurveProfile *profile = profile_v;
-
- BKE_curveprofile_selected_handle_set(profile, HD_AUTO, HD_AUTO);
- BKE_curveprofile_update(profile, false);
-
- rna_update_cb(C, cb_v, NULL);
+ BKE_curveprofile_update(profile, PROF_UPDATE_REMOVE_DOUBLES | PROF_UPDATE_CLIP);
+ rna_update_cb(C, arg1_v, NULL);
}
-static void CurveProfile_buttons_update(bContext *C, void *arg1_v, void *profile_v)
+static void CurveProfile_buttons_reset(bContext *C, void *arg1_v, void *profile_v)
{
CurveProfile *profile = profile_v;
- BKE_curveprofile_update(profile, true);
+ BKE_curveprofile_reset(profile);
+ BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
rna_update_cb(C, arg1_v, NULL);
}
@@ -4774,7 +4762,7 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
UI_block_emboss_set(block, UI_EMBOSS);
- uiLayoutRow(layout, false);
+ uiLayoutSetPropSep(layout, false);
/* Preset selector */
/* There is probably potential to use simpler "uiItemR" functions here, but automatic updating
@@ -4783,6 +4771,29 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
block, CurveProfile_buttons_presets, profile, "Preset", 0, 0, UI_UNIT_X, UI_UNIT_X, "");
UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
+ /* Show a "re-apply" preset button when it has been changed from the preset. */
+ if (profile->flag & PROF_DIRTY_PRESET) {
+ /* Only for dynamic presets. */
+ if (ELEM(profile->preset, PROF_PRESET_STEPS, PROF_PRESET_SUPPORTS)) {
+ bt = uiDefIconTextBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_NONE,
+ "Apply Preset",
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_X,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ "Reapply and update the preset, removing changes");
+ UI_but_funcN_set(bt, CurveProfile_buttons_reset, MEM_dupallocN(cb), profile);
+ }
+ }
+
row = uiLayoutRow(layout, false);
/* (Left aligned) */
@@ -4890,11 +4901,24 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
"");
/* Position sliders for (first) selected point */
+ float *selection_x, *selection_y;
for (i = 0; i < profile->path_len; i++) {
if (profile->path[i].flag & PROF_SELECT) {
point = &profile->path[i];
+ selection_x = &point->x;
+ selection_y = &point->y;
break;
}
+ else if (profile->path[i].flag & PROF_H1_SELECT) {
+ point = &profile->path[i];
+ selection_x = &point->h1_loc[0];
+ selection_y = &point->h1_loc[1];
+ }
+ else if (profile->path[i].flag & PROF_H2_SELECT) {
+ point = &profile->path[i];
+ selection_x = &point->h2_loc[0];
+ selection_y = &point->h2_loc[1];
+ }
}
if (i == 0 || i == profile->path_len - 1) {
point_last_or_first = true;
@@ -4910,46 +4934,19 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
bounds.xmax = bounds.ymax = 1000.0;
}
- uiLayoutRow(layout, true);
- UI_block_funcN_set(block, CurveProfile_buttons_update, MEM_dupallocN(cb), profile);
+ row = uiLayoutRow(layout, true);
- /* Sharp / Smooth */
- bt = uiDefIconBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_LINCURVE,
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_X,
- NULL,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- TIP_("Set the point's handle type to sharp"));
- if (point_last_or_first) {
- UI_but_flag_enable(bt, UI_BUT_DISABLED);
- }
- UI_but_funcN_set(bt, CurveProfile_buttons_setsharp, MEM_dupallocN(cb), profile);
- bt = uiDefIconBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_SMOOTHCURVE,
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_X,
- NULL,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- TIP_("Set the point's handle type to smooth"));
- UI_but_funcN_set(bt, CurveProfile_buttons_setcurved, MEM_dupallocN(cb), profile);
- if (point_last_or_first) {
- UI_but_flag_enable(bt, UI_BUT_DISABLED);
- }
+ PointerRNA point_ptr;
+ RNA_pointer_create(ptr->owner_id, &RNA_CurveProfilePoint, point, &point_ptr);
+ PropertyRNA *prop_handle_type = RNA_struct_find_property(&point_ptr, "handle_type_1");
+ uiItemFullR(row,
+ &point_ptr,
+ prop_handle_type,
+ RNA_NO_INDEX,
+ 0,
+ UI_ITEM_R_EXPAND | UI_ITEM_R_ICON_ONLY,
+ "",
+ ICON_NONE);
/* Position */
bt = uiDefButF(block,
@@ -4960,16 +4957,16 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
2 * UI_UNIT_Y,
UI_UNIT_X * 10,
UI_UNIT_Y,
- &point->x,
+ selection_x,
bounds.xmin,
bounds.xmax,
1,
5,
"");
+ UI_but_funcN_set(bt, CurveProfile_buttons_update, MEM_dupallocN(cb), profile);
if (point_last_or_first) {
UI_but_flag_enable(bt, UI_BUT_DISABLED);
}
-
bt = uiDefButF(block,
UI_BTYPE_NUM,
0,
@@ -4978,12 +4975,13 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
1 * UI_UNIT_Y,
UI_UNIT_X * 10,
UI_UNIT_Y,
- &point->y,
+ selection_y,
bounds.ymin,
bounds.ymax,
1,
5,
"");
+ UI_but_funcN_set(bt, CurveProfile_buttons_update, MEM_dupallocN(cb), profile);
if (point_last_or_first) {
UI_but_flag_enable(bt, UI_BUT_DISABLED);
}