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:
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/include/UI_interface.h3
-rw-r--r--source/blender/editors/interface/interface_draw.c232
-rw-r--r--source/blender/editors/interface/interface_handlers.c335
-rw-r--r--source/blender/editors/interface/interface_intern.h5
-rw-r--r--source/blender/editors/interface/interface_query.c3
-rw-r--r--source/blender/editors/interface/interface_templates.c608
-rw-r--r--source/blender/editors/interface/interface_widgets.c4
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c263
8 files changed, 1398 insertions, 55 deletions
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 8f205173011..69229f25917 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -346,6 +346,8 @@ typedef enum {
/** sphere widget (used to input a unit-vector, aka normal) */
UI_BTYPE_UNITVEC = 31 << 9,
UI_BTYPE_CURVE = 32 << 9,
+ /** Profile editing widget */
+ UI_BTYPE_CURVEPROFILE = 33 << 9,
UI_BTYPE_LISTBOX = 36 << 9,
UI_BTYPE_LISTROW = 37 << 9,
UI_BTYPE_HSVCIRCLE = 38 << 9,
@@ -1973,6 +1975,7 @@ void uiTemplateCurveMapping(uiLayout *layout,
bool brush,
bool neg_slope,
bool tone);
+void uiTemplateCurveProfile(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
void uiTemplateColorPicker(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 72c31c7b39e..499842a570b 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -27,16 +27,21 @@
#include "DNA_color_types.h"
#include "DNA_screen_types.h"
#include "DNA_movieclip_types.h"
+#include "DNA_curveprofile_types.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BLI_polyfill_2d.h"
+
+#include "MEM_guardedalloc.h"
#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_node.h"
#include "BKE_tracking.h"
+#include "BKE_curveprofile.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -1814,6 +1819,8 @@ static void ui_draw_but_curve_grid(
immVertex2f(pos, rect->xmax, fy);
fy += dy;
}
+ /* Note: Assertion fails with here when the view is moved farther below the center.
+ * Missing two points from the number given with immBegin. */
immEnd();
}
@@ -2113,6 +2120,231 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, const uiWidgetColors *wcol, cons
immUnbindProgram();
}
+/** Used to draw a curve profile widget. Somewhat similar to ui_draw_but_CURVE */
+void ui_draw_but_CURVEPROFILE(ARegion *ar,
+ uiBut *but,
+ const uiWidgetColors *wcol,
+ const rcti *rect)
+{
+ uint i;
+ float fx, fy;
+ CurveProfile *profile;
+ if (but->editprofile) {
+ profile = but->editprofile;
+ }
+ else {
+ profile = (CurveProfile *)but->poin;
+ }
+
+ /* 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 */
+ if (zoomx == 0.0f) {
+ return;
+ }
+
+ /* Test needed because path can draw outside of boundary */
+ int scissor[4];
+ GPU_scissor_get_i(scissor);
+ rcti scissor_new = {
+ .xmin = rect->xmin,
+ .ymin = rect->ymin,
+ .xmax = rect->xmax,
+ .ymax = rect->ymax,
+ };
+ rcti scissor_region = {0, ar->winx, 0, ar->winy};
+ BLI_rcti_isect(&scissor_new, &scissor_region, &scissor_new);
+ GPU_scissor(scissor_new.xmin,
+ scissor_new.ymin,
+ BLI_rcti_size_x(&scissor_new),
+ BLI_rcti_size_y(&scissor_new));
+
+ GPU_line_width(1.0f);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ /* 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);
+ immUniformColor3fv(color_backdrop);
+ immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ immUniformColor3ubv((uchar *)wcol->inner);
+ immRectf(pos,
+ rect->xmin + zoomx * (profile->clip_rect.xmin - offsx),
+ rect->ymin + zoomy * (profile->clip_rect.ymin - offsy),
+ rect->xmin + zoomx * (profile->clip_rect.xmax - offsx),
+ rect->ymin + zoomy * (profile->clip_rect.ymax - offsy));
+ }
+ else {
+ rgb_uchar_to_float(color_backdrop, (uchar *)wcol->inner);
+ immUniformColor3fv(color_backdrop);
+ immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ }
+
+ /* 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 */
+ 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 */
+ if (profile->table == NULL) {
+ BKE_curveprofile_update(profile, false);
+ }
+ CurveProfilePoint *pts = profile->table;
+ /* 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 */
+ 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 */
+ 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 */
+ 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;
+ 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 if (add_left_tri) {
+ /* 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 */
+ 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 */
+ 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 */
+ 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 */
+ immUniformColor3ubvAlpha((const uchar *)wcol->item, 128);
+ GPU_blend(true);
+ GPU_polygon_smooth(false);
+ immBegin(GPU_PRIM_TRIS, 3 * tot_triangles);
+ for (i = 0; i < tot_triangles; i++) {
+ for (uint j = 0; j < 3; j++) {
+ uint *tri = tri_indices[i];
+ fx = rect->xmin + zoomx * (table_coords[tri[j]][0] - offsx);
+ fy = rect->ymin + zoomy * (table_coords[tri[j]][1] - offsy);
+ immVertex2f(pos, fx, fy);
+ }
+ }
+ immEnd();
+ MEM_freeN(tri_indices);
+
+ /* 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);
+ GPU_line_smooth(true);
+ immBegin(GPU_PRIM_LINE_STRIP, tot_points - 1);
+ for (i = 0; i < tot_points - 1; i++) {
+ fx = rect->xmin + zoomx * (table_coords[i][0] - offsx);
+ fy = rect->ymin + zoomy * (table_coords[i][1] - offsy);
+ immVertex2f(pos, fx, fy);
+ }
+ immEnd();
+ immUnbindProgram();
+ MEM_freeN(table_coords);
+
+ /* 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);
+ uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+
+ /* Calculate vertex colors based on text theme. */
+ float color_vert[4], color_vert_select[4], color_sample[4];
+ UI_GetThemeColor4fv(TH_TEXT_HI, color_vert);
+ UI_GetThemeColor4fv(TH_TEXT, color_vert_select);
+ color_sample[0] = (float)wcol->item[0] / 255.0f;
+ color_sample[1] = (float)wcol->item[1] / 255.0f;
+ color_sample[2] = (float)wcol->item[2] / 255.0f;
+ color_sample[3] = (float)wcol->item[3] / 255.0f;
+ if (len_squared_v3v3(color_vert, color_vert_select) < 0.1f) {
+ interp_v3_v3v3(color_vert, color_vert_select, color_backdrop, 0.75f);
+ }
+ if (len_squared_v3(color_vert) > len_squared_v3(color_vert_select)) {
+ /* Ensure brightest text color is used for selection. */
+ swap_v3_v3(color_vert, color_vert_select);
+ }
+
+ /* 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)));
+ immBegin(GPU_PRIM_POINTS, tot_points);
+ for (i = 0; i < tot_points; i++) {
+ fx = rect->xmin + zoomx * (pts[i].x - offsx);
+ fy = rect->ymin + zoomy * (pts[i].y - offsy);
+ immAttr4fv(col, (pts[i].flag & PROF_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;
+ if (tot_points > 0 && pts) {
+ GPU_point_size(max_ff(2.0f, min_ff(UI_DPI_FAC / but->block->aspect * 3.0f, 3.0f)));
+ immBegin(GPU_PRIM_POINTS, tot_points);
+ for (i = 0; i < tot_points; i++) {
+ fx = rect->xmin + zoomx * (pts[i].x - offsx);
+ fy = rect->ymin + zoomy * (pts[i].y - offsy);
+ immAttr4fv(col, color_sample);
+ immVertex2f(pos, fx, fy);
+ }
+ immEnd();
+ }
+
+ immUnbindProgram();
+
+ /* restore scissortest */
+ GPU_scissor(scissor[0], scissor[1], scissor[2], scissor[3]);
+
+ /* Outline */
+ format = immVertexFormat();
+ pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3ubv((const uchar *)wcol->outline);
+ imm_draw_box_wire_2d(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+
+ immUnbindProgram();
+}
+
void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(ar),
uiBut *but,
const uiWidgetColors *UNUSED(wcol),
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 806b5789df1..673e4c1a8da 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -32,7 +32,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_brush_types.h"
-
+#include "DNA_curveprofile_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -57,6 +57,7 @@
#include "BKE_tracking.h"
#include "BKE_unit.h"
#include "BKE_paint.h"
+#include "BKE_curveprofile.h"
#include "IMB_colormanagement.h"
@@ -442,6 +443,8 @@ static uiButMultiState *ui_multibut_lookup(uiHandleButtonData *data, const uiBut
static ColorBand but_copypaste_coba = {0};
static CurveMapping but_copypaste_curve = {0};
static bool but_copypaste_curve_alive = false;
+static CurveProfile but_copypaste_profile = {0};
+static bool but_copypaste_profile_alive = false;
/** \} */
@@ -1080,6 +1083,13 @@ static void ui_apply_but_CURVE(bContext *C, uiBut *but, uiHandleButtonData *data
data->applied = true;
}
+static void ui_apply_but_CURVEPROFILE(bContext *C, uiBut *but, uiHandleButtonData *data)
+{
+ ui_apply_but_func(C, but);
+ data->retval = but->retval;
+ data->applied = true;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1979,6 +1989,7 @@ static void ui_apply_but(
float *editvec;
ColorBand *editcoba;
CurveMapping *editcumap;
+ CurveProfile *editprofile;
data->retval = 0;
@@ -2036,11 +2047,13 @@ static void ui_apply_but(
editvec = but->editvec;
editcoba = but->editcoba;
editcumap = but->editcumap;
+ editprofile = but->editprofile;
but->editstr = NULL;
but->editval = NULL;
but->editvec = NULL;
but->editcoba = NULL;
but->editcumap = NULL;
+ but->editprofile = NULL;
/* handle different types */
switch (but->type) {
@@ -2100,6 +2113,9 @@ static void ui_apply_but(
case UI_BTYPE_CURVE:
ui_apply_but_CURVE(C, but, data);
break;
+ case UI_BTYPE_CURVEPROFILE:
+ ui_apply_but_CURVEPROFILE(C, but, data);
+ break;
case UI_BTYPE_KEY_EVENT:
case UI_BTYPE_HOTKEY_EVENT:
ui_apply_but_BUT(C, but, data);
@@ -2147,6 +2163,7 @@ static void ui_apply_but(
but->editvec = editvec;
but->editcoba = editcoba;
but->editcumap = editcumap;
+ but->editprofile = editprofile;
}
/** \} */
@@ -2446,6 +2463,29 @@ static void ui_but_paste_curvemapping(bContext *C, uiBut *but)
}
}
+static void ui_but_copy_CurveProfile(uiBut *but)
+{
+ if (but->poin != NULL) {
+ but_copypaste_profile_alive = true;
+ BKE_curveprofile_free_data(&but_copypaste_profile);
+ BKE_curveprofile_copy_data(&but_copypaste_profile, (CurveProfile *)but->poin);
+ }
+}
+
+static void ui_but_paste_CurveProfile(bContext *C, uiBut *but)
+{
+ if (but_copypaste_profile_alive) {
+ if (!but->poin) {
+ but->poin = MEM_callocN(sizeof(CurveProfile), "CurveProfile");
+ }
+
+ button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
+ BKE_curveprofile_free_data((CurveProfile *)but->poin);
+ BKE_curveprofile_copy_data((CurveProfile *)but->poin, &but_copypaste_profile);
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ }
+}
+
static void ui_but_copy_operator(bContext *C, uiBut *but, char *output, int output_len_max)
{
PointerRNA *opptr;
@@ -2540,6 +2580,10 @@ static void ui_but_copy(bContext *C, uiBut *but, const bool copy_array)
ui_but_copy_curvemapping(but);
break;
+ case UI_BTYPE_CURVEPROFILE:
+ ui_but_copy_CurveProfile(but);
+ break;
+
case UI_BTYPE_BUT:
if (!but->optype) {
break;
@@ -2623,6 +2667,10 @@ static void ui_but_paste(bContext *C, uiBut *but, uiHandleButtonData *data, cons
ui_but_paste_curvemapping(C, but);
break;
+ case UI_BTYPE_CURVEPROFILE:
+ ui_but_paste_CurveProfile(C, but);
+ break;
+
default:
break;
}
@@ -2633,6 +2681,7 @@ static void ui_but_paste(bContext *C, uiBut *but, uiHandleButtonData *data, cons
void ui_but_clipboard_free(void)
{
BKE_curvemapping_free_data(&but_copypaste_curve);
+ BKE_curveprofile_free_data(&but_copypaste_profile);
}
/** \} */
@@ -3757,6 +3806,9 @@ static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data)
if (but->type == UI_BTYPE_CURVE) {
but->editcumap = (CurveMapping *)but->poin;
}
+ if (but->type == UI_BTYPE_CURVEPROFILE) {
+ but->editprofile = (CurveProfile *)but->poin;
+ }
else if (but->type == UI_BTYPE_COLORBAND) {
data->coba = (ColorBand *)but->poin;
but->editcoba = data->coba;
@@ -3847,6 +3899,7 @@ static void ui_numedit_end(uiBut *but, uiHandleButtonData *data)
but->editvec = NULL;
but->editcoba = NULL;
but->editcumap = NULL;
+ but->editprofile = NULL;
data->dragstartx = 0;
data->draglastx = 0;
@@ -6803,6 +6856,281 @@ static int ui_do_but_CURVE(
return WM_UI_HANDLER_CONTINUE;
}
+/* Same as ui_numedit_but_CURVE with some smaller changes. */
+static bool ui_numedit_but_CURVEPROFILE(uiBlock *block,
+ uiBut *but,
+ uiHandleButtonData *data,
+ int evtx,
+ int evty,
+ bool snap,
+ const bool shift)
+{
+ CurveProfile *profile = (CurveProfile *)but->poin;
+ CurveProfilePoint *pts = profile->path;
+ float fx, fy, zoomx, zoomy;
+ int mx, my, dragx, dragy;
+ int a;
+ bool changed = false;
+
+ /* evtx evty and drag coords are absolute mousecoords,
+ * prevents errors when editing when layout changes */
+ mx = evtx;
+ my = evty;
+ ui_window_to_block(data->region, block, &mx, &my);
+ dragx = data->draglastx;
+ dragy = data->draglasty;
+ ui_window_to_block(data->region, block, &dragx, &dragy);
+
+ zoomx = BLI_rctf_size_x(&but->rect) / BLI_rctf_size_x(&profile->view_rect);
+ zoomy = BLI_rctf_size_y(&but->rect) / BLI_rctf_size_y(&profile->view_rect);
+
+ if (snap) {
+ float d[2];
+
+ d[0] = mx - data->dragstartx;
+ d[1] = my - data->dragstarty;
+
+ if (len_squared_v2(d) < (3.0f * 3.0f)) {
+ snap = false;
+ }
+ }
+
+ fx = (mx - dragx) / zoomx;
+ fy = (my - dragy) / zoomy;
+
+ if (data->dragsel != -1) {
+ CurveProfilePoint *point_last = NULL;
+ 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);
+ }
+ if (!moved_point && (pts[a].x != origx || pts[a].y != origy)) {
+ moved_point = true;
+ }
+
+ point_last = &pts[a];
+ }
+ }
+
+ BKE_curveprofile_update(profile, false);
+
+ if (moved_point) {
+ data->draglastx = evtx;
+ data->draglasty = evty;
+ changed = true;
+#ifdef USE_CONT_MOUSE_CORRECT
+ /* note: using 'cmp_last' is weak since there may be multiple points selected,
+ * 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);
+ BLI_rctf_clamp_pt_v(&but->rect, data->ungrab_mval);
+ }
+#endif
+ }
+ data->dragchange = true; /* mark for selection */
+ }
+ else {
+ /* clamp for clip */
+ 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;
+ }
+ else if (profile->view_rect.xmax - fx > profile->clip_rect.xmax) {
+ fx = profile->view_rect.xmax - profile->clip_rect.xmax;
+ }
+ if (profile->view_rect.ymin - fy < profile->clip_rect.ymin) {
+ fy = profile->view_rect.ymin - profile->clip_rect.ymin;
+ }
+ else if (profile->view_rect.ymax - fy > profile->clip_rect.ymax) {
+ fy = profile->view_rect.ymax - profile->clip_rect.ymax;
+ }
+ }
+
+ profile->view_rect.xmin -= fx;
+ profile->view_rect.ymin -= fy;
+ profile->view_rect.xmax -= fx;
+ profile->view_rect.ymax -= fy;
+
+ data->draglastx = evtx;
+ data->draglasty = evty;
+
+ changed = true;
+ }
+
+ return changed;
+}
+
+/** 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;
+
+ mx = event->x;
+ my = event->y;
+ ui_window_to_block(data->region, block, &mx, &my);
+
+ /* Move selected control points. */
+ if (event->type == GKEY && event->val == KM_RELEASE) {
+ data->dragstartx = mx;
+ data->dragstarty = my;
+ data->draglastx = mx;
+ data->draglasty = my;
+ button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
+ return WM_UI_HANDLER_BREAK;
+ }
+
+ CurveProfile *profile = (CurveProfile *)but->poin;
+
+ /* Delete selected control points. */
+ if (event->type == XKEY && event->val == KM_RELEASE) {
+ BKE_curveprofile_remove_by_flag(profile, PROF_SELECT);
+ BKE_curveprofile_update(profile, false);
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ return WM_UI_HANDLER_BREAK;
+ }
+
+ /* 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);
+ }
+
+ /* Check for selecting of a point by finding closest point in radius. */
+ dist_min_sq = SQUARE(U.dpi_fac * 14.0f); /* 14 pixels radius for selecting points. */
+ pts = profile->path;
+ for (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);
+ if (dist_sq < dist_min_sq) {
+ i_selected = i;
+ 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. */
+ 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);
+
+ dist_min_sq = SQUARE(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++) {
+ copy_v2_v2(f_xy_prev, f_xy);
+ BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, &pts[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;
+
+ /* Get the index of the newly added point. */
+ for (i = 0; i < profile->path_len; i++) {
+ if (&pts[i] == new_pt) {
+ i_selected = i;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ /* Change the flag for the point(s) if one was selected. */
+ 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;
+ }
+ else {
+ pts[i_selected].flag ^= PROF_SELECT;
+ }
+ }
+ else {
+ /* Move the view. */
+ data->cancel = true;
+ }
+
+ data->dragsel = i_selected;
+
+ data->dragstartx = mx;
+ data->dragstarty = my;
+ data->draglastx = mx;
+ data->draglasty = my;
+
+ button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
+ return WM_UI_HANDLER_BREAK;
+ }
+ }
+ else if (data->state == BUTTON_STATE_NUM_EDITING) { /* Do control point movement. */
+ if (event->type == MOUSEMOVE) {
+ if (mx != data->draglastx || my != data->draglasty) {
+ if (ui_numedit_but_CURVEPROFILE(
+ block, but, data, mx, my, event->ctrl != 0, event->shift != 0)) {
+ ui_numedit_apply(C, block, but, data);
+ }
+ }
+ }
+ 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. */
+ }
+ }
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ }
+ return WM_UI_HANDLER_BREAK;
+ }
+
+ return WM_UI_HANDLER_CONTINUE;
+}
+
static bool ui_numedit_but_HISTOGRAM(uiBut *but, uiHandleButtonData *data, int mx, int my)
{
Histogram *hist = (Histogram *)but->poin;
@@ -7208,6 +7536,9 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
case UI_BTYPE_CURVE:
retval = ui_do_but_CURVE(C, block, but, data, event);
break;
+ case UI_BTYPE_CURVEPROFILE:
+ retval = ui_do_but_CURVEPROFILE(C, block, but, data, event);
+ break;
case UI_BTYPE_HSVCUBE:
retval = ui_do_but_HSVCUBE(C, block, but, data, event);
break;
@@ -7599,7 +7930,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
copy_v2_fl(data->ungrab_mval, FLT_MAX);
#endif
- if (ELEM(but->type, UI_BTYPE_CURVE, UI_BTYPE_SEARCH_MENU)) {
+ if (ELEM(but->type, UI_BTYPE_CURVE, UI_BTYPE_CURVEPROFILE, UI_BTYPE_SEARCH_MENU)) {
/* XXX curve is temp */
}
else {
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 81979b1fc8f..3fe2750e070 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -274,6 +274,7 @@ struct uiBut {
float *editvec;
void *editcoba;
void *editcumap;
+ void *editprofile;
uiButPushedStateFunc pushed_state_func;
void *pushed_state_arg;
@@ -740,6 +741,10 @@ void ui_draw_but_CURVE(ARegion *ar,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
+void ui_draw_but_CURVEPROFILE(ARegion *ar,
+ uiBut *but,
+ const struct uiWidgetColors *wcol,
+ const rcti *rect);
void ui_draw_but_IMAGE(ARegion *ar,
uiBut *but,
const struct uiWidgetColors *wcol,
diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c
index 34b1070f8b4..ab20b5ac520 100644
--- a/source/blender/editors/interface/interface_query.c
+++ b/source/blender/editors/interface/interface_query.c
@@ -422,7 +422,8 @@ bool ui_but_is_cursor_warp(const uiBut *but)
UI_BTYPE_HSVCIRCLE,
UI_BTYPE_TRACK_PREVIEW,
UI_BTYPE_HSVCUBE,
- UI_BTYPE_CURVE)) {
+ UI_BTYPE_CURVE,
+ UI_BTYPE_CURVEPROFILE)) {
return true;
}
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 021d7733fae..b205572ba06 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -35,6 +35,7 @@
#include "DNA_texture_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_shader_fx_types.h"
+#include "DNA_curveprofile_types.h"
#include "BLI_utildefines.h"
#include "BLI_alloca.h"
@@ -69,6 +70,7 @@
#include "BKE_packedFile.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
+#include "BKE_curveprofile.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "BKE_shader_fx.h"
@@ -4505,6 +4507,612 @@ void uiTemplateCurveMapping(uiLayout *layout,
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Curve Profile Template
+ * \{ */
+
+static void CurveProfile_presets_dofunc(bContext *C, void *profile_v, int event)
+{
+ CurveProfile *profile = profile_v;
+
+ profile->preset = event;
+ BKE_curveprofile_reset(profile);
+ BKE_curveprofile_update(profile, false);
+
+ ED_undo_push(C, "CurveProfile tools");
+ ED_region_tag_redraw(CTX_wm_region(C));
+}
+
+static uiBlock *CurveProfile_presets_func(bContext *C, ARegion *ar, CurveProfile *profile)
+{
+ uiBlock *block;
+ short yco = 0;
+ short menuwidth = 12 * UI_UNIT_X;
+ menuwidth = 0;
+
+ block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
+ UI_block_func_butmenu_set(block, CurveProfile_presets_dofunc, profile);
+
+ uiDefIconTextBut(block,
+ UI_BTYPE_BUT_MENU,
+ 1,
+ ICON_BLANK1,
+ IFACE_("Default"),
+ 0,
+ yco -= UI_UNIT_Y,
+ menuwidth,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0,
+ PROF_PRESET_LINE,
+ "");
+ uiDefIconTextBut(block,
+ UI_BTYPE_BUT_MENU,
+ 1,
+ ICON_BLANK1,
+ IFACE_("Support Loops"),
+ 0,
+ yco -= UI_UNIT_Y,
+ menuwidth,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0,
+ PROF_PRESET_SUPPORTS,
+ "");
+ uiDefIconTextBut(block,
+ UI_BTYPE_BUT_MENU,
+ 1,
+ ICON_BLANK1,
+ IFACE_("Cornice Moulding"),
+ 0,
+ yco -= UI_UNIT_Y,
+ menuwidth,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0,
+ PROF_PRESET_CORNICE,
+ "");
+ uiDefIconTextBut(block,
+ UI_BTYPE_BUT_MENU,
+ 1,
+ ICON_BLANK1,
+ IFACE_("Crown Moulding"),
+ 0,
+ yco -= UI_UNIT_Y,
+ menuwidth,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0,
+ PROF_PRESET_CROWN,
+ "");
+ uiDefIconTextBut(block,
+ UI_BTYPE_BUT_MENU,
+ 1,
+ ICON_BLANK1,
+ IFACE_("Steps"),
+ 0,
+ yco -= UI_UNIT_Y,
+ menuwidth,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0,
+ PROF_PRESET_STEPS,
+ "");
+
+ UI_block_direction_set(block, UI_DIR_DOWN);
+ UI_block_bounds_set_text(block, (int)(3.0f * UI_UNIT_X));
+
+ return block;
+}
+
+static uiBlock *CurveProfile_buttons_presets(bContext *C, ARegion *ar, void *profile_v)
+{
+ return CurveProfile_presets_func(C, ar, (CurveProfile *)profile_v);
+}
+
+/* Only for CurveProfile tools block */
+enum {
+ UIPROFILE_FUNC_RESET,
+ UIPROFILE_FUNC_RESET_VIEW,
+};
+
+static void CurveProfile_tools_dofunc(bContext *C, void *profile_v, int event)
+{
+ CurveProfile *profile = profile_v;
+
+ switch (event) {
+ case UIPROFILE_FUNC_RESET: /* reset */
+ BKE_curveprofile_reset(profile);
+ BKE_curveprofile_update(profile, false);
+ break;
+ case UIPROFILE_FUNC_RESET_VIEW: /* reset view to clipping rect */
+ profile->view_rect = profile->clip_rect;
+ break;
+ }
+ ED_undo_push(C, "CurveProfile tools");
+ ED_region_tag_redraw(CTX_wm_region(C));
+}
+
+static uiBlock *CurveProfile_tools_func(bContext *C, ARegion *ar, CurveProfile *profile)
+{
+ uiBlock *block;
+ short yco = 0;
+ short menuwidth = 10 * UI_UNIT_X;
+
+ block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
+ UI_block_func_butmenu_set(block, CurveProfile_tools_dofunc, profile);
+
+ uiDefIconTextBut(block,
+ UI_BTYPE_BUT_MENU,
+ 1,
+ ICON_BLANK1,
+ IFACE_("Reset View"),
+ 0,
+ yco -= UI_UNIT_Y,
+ menuwidth,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0,
+ UIPROFILE_FUNC_RESET_VIEW,
+ "");
+ uiDefIconTextBut(block,
+ UI_BTYPE_BUT_MENU,
+ 1,
+ ICON_BLANK1,
+ IFACE_("Reset Curve"),
+ 0,
+ yco -= UI_UNIT_Y,
+ menuwidth,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0,
+ UIPROFILE_FUNC_RESET,
+ "");
+
+ UI_block_direction_set(block, UI_DIR_DOWN);
+ UI_block_bounds_set_text(block, (int)(3.0f * UI_UNIT_X));
+
+ return block;
+}
+
+static uiBlock *CurveProfile_buttons_tools(bContext *C, ARegion *ar, void *profile_v)
+{
+ return CurveProfile_tools_func(C, ar, (CurveProfile *)profile_v);
+}
+
+static void CurveProfile_buttons_zoom_in(bContext *C, void *profile_v, void *UNUSED(arg))
+{
+ CurveProfile *profile = profile_v;
+ float d;
+
+ /* we allow 20 times 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;
+ profile->view_rect.xmax -= d;
+ d = 0.1154f * BLI_rctf_size_y(&profile->view_rect);
+ profile->view_rect.ymin += d;
+ profile->view_rect.ymax -= d;
+ }
+
+ ED_region_tag_redraw(CTX_wm_region(C));
+}
+
+static void CurveProfile_buttons_zoom_out(bContext *C, void *profile_v, void *UNUSED(arg))
+{
+ CurveProfile *profile = profile_v;
+ float d, d1;
+
+ /* Allow 20 times zoom, but don't view outside clip */
+ if (BLI_rctf_size_x(&profile->view_rect) < 20.0f * BLI_rctf_size_x(&profile->clip_rect)) {
+ d = d1 = 0.15f * BLI_rctf_size_x(&profile->view_rect);
+
+ if (profile->flag & PROF_USE_CLIP) {
+ if (profile->view_rect.xmin - d < profile->clip_rect.xmin) {
+ d1 = profile->view_rect.xmin - profile->clip_rect.xmin;
+ }
+ }
+ profile->view_rect.xmin -= d1;
+
+ d1 = d;
+ if (profile->flag & PROF_USE_CLIP) {
+ if (profile->view_rect.xmax + d > profile->clip_rect.xmax) {
+ d1 = -profile->view_rect.xmax + profile->clip_rect.xmax;
+ }
+ }
+ profile->view_rect.xmax += d1;
+
+ d = d1 = 0.15f * BLI_rctf_size_y(&profile->view_rect);
+
+ if (profile->flag & PROF_USE_CLIP) {
+ if (profile->view_rect.ymin - d < profile->clip_rect.ymin) {
+ d1 = profile->view_rect.ymin - profile->clip_rect.ymin;
+ }
+ }
+ profile->view_rect.ymin -= d1;
+
+ d1 = d;
+ if (profile->flag & PROF_USE_CLIP) {
+ if (profile->view_rect.ymax + d > profile->clip_rect.ymax) {
+ d1 = -profile->view_rect.ymax + profile->clip_rect.ymax;
+ }
+ }
+ profile->view_rect.ymax += d1;
+ }
+
+ ED_region_tag_redraw(CTX_wm_region(C));
+}
+
+static void CurveProfile_clipping_toggle(bContext *C, void *cb_v, void *profile_v)
+{
+ CurveProfile *profile = profile_v;
+
+ profile->flag ^= PROF_USE_CLIP;
+
+ BKE_curveprofile_update(profile, false);
+ rna_update_cb(C, cb_v, NULL);
+}
+
+static void CurveProfile_buttons_reverse(bContext *C, void *cb_v, void *profile_v)
+{
+ CurveProfile *profile = profile_v;
+
+ BKE_curveprofile_reverse(profile);
+ BKE_curveprofile_update(profile, false);
+ rna_update_cb(C, cb_v, NULL);
+}
+
+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);
+
+ rna_update_cb(C, cb_v, NULL);
+}
+
+static void CurveProfile_buttons_setcurved(bContext *C, void *cb_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);
+}
+
+static void CurveProfile_buttons_update(bContext *C, void *arg1_v, void *profile_v)
+{
+ CurveProfile *profile = profile_v;
+ BKE_curveprofile_update(profile, true);
+ rna_update_cb(C, arg1_v, NULL);
+}
+
+static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUpdateCb *cb)
+{
+ CurveProfile *profile = ptr->data;
+ CurveProfilePoint *point = NULL;
+ uiLayout *row, *sub;
+ uiBlock *block;
+ uiBut *bt;
+ int i, icon, path_width, path_height;
+ bool point_last_or_first = false;
+ rctf bounds;
+
+ block = uiLayoutGetBlock(layout);
+
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ uiLayoutRow(layout, false);
+
+ /* Preset selector */
+ /* There is probably potential to use simpler "uiItemR" functions here, but automatic updating
+ * after a preset is selected would be more complicated. */
+ bt = uiDefBlockBut(
+ 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);
+
+ row = uiLayoutRow(layout, false);
+
+ /* (Left aligned) */
+ sub = uiLayoutRow(row, true);
+ uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
+
+ /* Zoom in */
+ bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_ZOOM_IN,
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_X,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Zoom in"));
+ UI_but_func_set(bt, CurveProfile_buttons_zoom_in, profile, NULL);
+
+ /* Zoom out */
+ bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_ZOOM_OUT,
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_X,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Zoom out"));
+ UI_but_func_set(bt, CurveProfile_buttons_zoom_out, profile, NULL);
+
+ /* (Right aligned) */
+ sub = uiLayoutRow(row, true);
+ uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
+
+ /* Reset view, reset curve */
+ bt = uiDefIconBlockBut(
+ block, CurveProfile_buttons_tools, profile, 0, 0, 0, 0, UI_UNIT_X, UI_UNIT_X, TIP_("Tools"));
+ UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
+
+ /* Flip path */
+ bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_ARROW_LEFTRIGHT,
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_X,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Reverse Path"));
+ UI_but_funcN_set(bt, CurveProfile_buttons_reverse, MEM_dupallocN(cb), profile);
+
+ /* Clipping toggle */
+ icon = (profile->flag & PROF_USE_CLIP) ? ICON_CLIPUV_HLT : ICON_CLIPUV_DEHLT;
+ bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ icon,
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_X,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Toggle Profile Clipping"));
+ UI_but_funcN_set(bt, CurveProfile_clipping_toggle, MEM_dupallocN(cb), profile);
+
+ UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL);
+
+ /* The path itself */
+ path_width = max_ii(uiLayoutGetWidth(layout), UI_UNIT_X);
+ path_width = min_ii(path_width, (int)(16.0f * UI_UNIT_X));
+ path_height = path_width;
+ uiLayoutRow(layout, false);
+ uiDefBut(block,
+ UI_BTYPE_CURVEPROFILE,
+ 0,
+ "",
+ 0,
+ 0,
+ (short)path_width,
+ (short)path_height,
+ profile,
+ 0.0f,
+ 1.0f,
+ -1,
+ 0,
+ "");
+
+ /* Position sliders for (first) selected point */
+ for (i = 0; i < profile->path_len; i++) {
+ if (profile->path[i].flag & PROF_SELECT) {
+ point = &profile->path[i];
+ break;
+ }
+ }
+ if (i == 0 || i == profile->path_len - 1) {
+ point_last_or_first = true;
+ }
+
+ /* Selected point data */
+ if (point) {
+ if (profile->flag & PROF_USE_CLIP) {
+ bounds = profile->clip_rect;
+ }
+ else {
+ bounds.xmin = bounds.ymin = -1000.0;
+ bounds.xmax = bounds.ymax = 1000.0;
+ }
+
+ uiLayoutRow(layout, true);
+ UI_block_funcN_set(block, CurveProfile_buttons_update, MEM_dupallocN(cb), profile);
+
+ /* 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 sharp."));
+ 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);
+ }
+
+ /* Position */
+ bt = uiDefButF(block,
+ UI_BTYPE_NUM,
+ 0,
+ "X:",
+ 0,
+ 2 * UI_UNIT_Y,
+ UI_UNIT_X * 10,
+ UI_UNIT_Y,
+ &point->x,
+ bounds.xmin,
+ bounds.xmax,
+ 1,
+ 5,
+ "");
+ if (point_last_or_first) {
+ UI_but_flag_enable(bt, UI_BUT_DISABLED);
+ }
+
+ bt = uiDefButF(block,
+ UI_BTYPE_NUM,
+ 0,
+ "Y:",
+ 0,
+ 1 * UI_UNIT_Y,
+ UI_UNIT_X * 10,
+ UI_UNIT_Y,
+ &point->y,
+ bounds.ymin,
+ bounds.ymax,
+ 1,
+ 5,
+ "");
+ if (point_last_or_first) {
+ UI_but_flag_enable(bt, UI_BUT_DISABLED);
+ }
+
+ /* Delete points */
+ bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_X,
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_X,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Delete points"));
+ UI_but_funcN_set(bt, CurveProfile_buttons_delete, MEM_dupallocN(cb), profile);
+ if (point_last_or_first) {
+ UI_but_flag_enable(bt, UI_BUT_DISABLED);
+ }
+ }
+
+ uiItemR(layout, ptr, "use_sample_straight_edges", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_sample_even_lengths", 0, NULL, ICON_NONE);
+
+ UI_block_funcN_set(block, NULL, NULL, NULL);
+}
+
+/** Template for a path creation widget intended for custom bevel profiles.
+ * This section is quite similar to uiTemplateCurveMapping, but with reduced complexity */
+void uiTemplateCurveProfile(uiLayout *layout, PointerRNA *ptr, const char *propname)
+{
+ RNAUpdateCb *cb;
+ PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
+ PointerRNA cptr;
+ ID *id;
+ uiBlock *block = uiLayoutGetBlock(layout);
+
+ if (!prop) {
+ RNA_warning(
+ "Curve Profile property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+
+ if (RNA_property_type(prop) != PROP_POINTER) {
+ RNA_warning(
+ "Curve Profile is not a pointer: %s.%s", RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+
+ cptr = RNA_property_pointer_get(ptr, prop);
+ if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_CurveProfile)) {
+ return;
+ }
+
+ /* Share update functionality with the CurveMapping widget template. */
+ cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
+ cb->ptr = *ptr;
+ cb->prop = prop;
+
+ id = cptr.owner_id;
+ UI_block_lock_set(block, (id && ID_IS_LINKED(id)), ERROR_LIBDATA_MESSAGE);
+
+ CurveProfile_buttons_layout(layout, &cptr, cb);
+
+ UI_block_lock_clear(block);
+
+ MEM_freeN(cb);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name ColorPicker Template
* \{ */
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 4cef9ace66e..7f7352517c8 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -4774,6 +4774,10 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
ui_draw_but_CURVE(ar, but, &tui->wcol_regular, rect);
break;
+ case UI_BTYPE_CURVEPROFILE:
+ ui_draw_but_CURVEPROFILE(ar, but, &tui->wcol_regular, rect);
+ break;
+
case UI_BTYPE_PROGRESS_BAR:
wt = widget_type(UI_WTYPE_PROGRESSBAR);
fstyle = &style->widgetlabel;
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 7afd72f33c9..acdf667b410 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -33,8 +33,10 @@
#include "BKE_unit.h"
#include "BKE_layer.h"
#include "BKE_mesh.h"
+#include "BKE_curveprofile.h"
#include "DNA_mesh_types.h"
+#include "DNA_curveprofile_types.h"
#include "RNA_define.h"
#include "RNA_access.h"
@@ -43,6 +45,7 @@
#include "WM_types.h"
#include "UI_interface.h"
+#include "UI_resources.h"
#include "ED_mesh.h"
#include "ED_numinput.h"
@@ -96,6 +99,8 @@ typedef struct {
short gizmo_flag;
short value_mode; /* Which value does mouse movement and numeric input affect? */
float segments; /* Segments as float so smooth mouse pan works in small increments */
+
+ CurveProfile *custom_profile;
} BevelData;
enum {
@@ -114,6 +119,8 @@ enum {
BEV_MODAL_MARK_SHARP_TOGGLE,
BEV_MODAL_OUTER_MITER_CHANGE,
BEV_MODAL_INNER_MITER_CHANGE,
+ BEV_MODAL_CUSTOM_PROFILE_TOGGLE,
+ BEV_MODAL_VERTEX_MESH_CHANGE,
};
static float get_bevel_offset(wmOperator *op)
@@ -129,15 +136,15 @@ static float get_bevel_offset(wmOperator *op)
return val;
}
-static void edbm_bevel_update_header(bContext *C, wmOperator *op)
+static void edbm_bevel_update_status_text(bContext *C, wmOperator *op)
{
- char header[UI_MAX_DRAW_STR];
+ char status_text[UI_MAX_DRAW_STR];
char buf[UI_MAX_DRAW_STR];
char *p = buf;
int available_len = sizeof(buf);
Scene *sce = CTX_data_scene(C);
char offset_str[NUM_STR_REP_LEN];
- const char *mode_str, *omiter_str, *imiter_str;
+ const char *mode_str, *omiter_str, *imiter_str, *vmesh_str;
PropertyRNA *prop;
#define WM_MODALKEY(_id) \
@@ -167,22 +174,27 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
prop = RNA_struct_find_property(op->ptr, "miter_inner");
RNA_property_enum_name_gettexted(
C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &imiter_str);
-
- BLI_snprintf(header,
- sizeof(header),
- TIP_("%s: confirm, "
- "%s: cancel, "
- "%s: mode (%s), "
- "%s: width (%s), "
- "%s: segments (%d), "
- "%s: profile (%.3f), "
- "%s: clamp overlap (%s), "
- "%s: vertex only (%s), "
- "%s: outer miter (%s), "
- "%s: inner miter (%s), "
- "%s: harden normals (%s), "
- "%s: mark seam (%s), "
- "%s: mark sharp (%s)"),
+ prop = RNA_struct_find_property(op->ptr, "vmesh_method");
+ RNA_property_enum_name_gettexted(
+ C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &vmesh_str);
+
+ BLI_snprintf(status_text,
+ sizeof(status_text),
+ TIP_("%s: Confirm, "
+ "%s: Cancel, "
+ "%s: Mode (%s), "
+ "%s: Width (%s), "
+ "%s: Segments (%d), "
+ "%s: Profile (%.3f), "
+ "%s: Clamp Overlap (%s), "
+ "%s: Vertex Only (%s), "
+ "%s: Outer Miter (%s), "
+ "%s: Inner Miter (%s), "
+ "%s: Harden Normals (%s), "
+ "%s: Mark Seam (%s), "
+ "%s: Mark Sharp (%s), "
+ "%s: Custom Profile (%s), "
+ "%s: Intersection (%s)"),
WM_MODALKEY(BEV_MODAL_CONFIRM),
WM_MODALKEY(BEV_MODAL_CANCEL),
WM_MODALKEY(BEV_MODAL_OFFSET_MODE_CHANGE),
@@ -206,16 +218,21 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
WM_MODALKEY(BEV_MODAL_MARK_SEAM_TOGGLE),
WM_bool_as_string(RNA_boolean_get(op->ptr, "mark_seam")),
WM_MODALKEY(BEV_MODAL_MARK_SHARP_TOGGLE),
- WM_bool_as_string(RNA_boolean_get(op->ptr, "mark_sharp")));
+ WM_bool_as_string(RNA_boolean_get(op->ptr, "mark_sharp")),
+ WM_MODALKEY(BEV_MODAL_CUSTOM_PROFILE_TOGGLE),
+ WM_bool_as_string(RNA_boolean_get(op->ptr, "use_custom_profile")),
+ WM_MODALKEY(BEV_MODAL_VERTEX_MESH_CHANGE),
+ vmesh_str);
#undef WM_MODALKEY
- ED_workspace_status_text(C, header);
+ ED_workspace_status_text(C, status_text);
}
static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
{
Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
BevelData *opdata;
ViewLayer *view_layer = CTX_data_view_layer(C);
float pixels_per_inch;
@@ -230,6 +247,9 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
uint objects_used_len = 0;
opdata->max_obj_scale = FLT_MIN;
+ /* Put the Curve Profile from the toolsettings into the opdata struct */
+ opdata->custom_profile = ts->custom_bevel_profile_preset;
+
{
uint ob_store_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
@@ -318,6 +338,8 @@ static bool edbm_bevel_calc(wmOperator *op)
const int miter_outer = RNA_enum_get(op->ptr, "miter_outer");
const int miter_inner = RNA_enum_get(op->ptr, "miter_inner");
const float spread = RNA_float_get(op->ptr, "spread");
+ const bool use_custom_profile = RNA_boolean_get(op->ptr, "use_custom_profile");
+ const int vmesh_method = RNA_enum_get(op->ptr, "vmesh_method");
for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
em = opdata->ob_store[ob_index].em;
@@ -344,7 +366,8 @@ static bool edbm_bevel_calc(wmOperator *op)
"bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f "
"clamp_overlap=%b material=%i loop_slide=%b mark_seam=%b mark_sharp=%b "
"harden_normals=%b face_strength_mode=%i "
- "miter_outer=%i miter_inner=%i spread=%f smoothresh=%f",
+ "miter_outer=%i miter_inner=%i spread=%f smoothresh=%f use_custom_profile=%b "
+ "custom_profile=%p vmesh_method=%i",
BM_ELEM_SELECT,
offset,
segments,
@@ -361,7 +384,10 @@ static bool edbm_bevel_calc(wmOperator *op)
miter_outer,
miter_inner,
spread,
- me->smoothresh);
+ me->smoothresh,
+ use_custom_profile,
+ opdata->custom_profile,
+ vmesh_method);
BMO_op_exec(em->bm, &bmop);
@@ -389,7 +415,6 @@ static bool edbm_bevel_calc(wmOperator *op)
static void edbm_bevel_exit(bContext *C, wmOperator *op)
{
BevelData *opdata = op->customdata;
-
ScrArea *sa = CTX_wm_area(C);
if (sa) {
@@ -430,7 +455,7 @@ static void edbm_bevel_cancel(bContext *C, wmOperator *op)
ED_region_tag_redraw(CTX_wm_region(C));
}
-/* bevel! yay!!*/
+/* bevel! yay!! */
static int edbm_bevel_exec(bContext *C, wmOperator *op)
{
if (!edbm_bevel_init(C, op, false)) {
@@ -500,7 +525,7 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
edbm_bevel_calc_initial_length(op, event, false);
- edbm_bevel_update_header(C, op);
+ edbm_bevel_update_status_text(C, op);
if (!edbm_bevel_calc(op)) {
edbm_bevel_cancel(C, op);
@@ -598,13 +623,9 @@ wmKeyMap *bevel_modal_keymap(wmKeyConfig *keyconf)
static const EnumPropertyItem modal_items[] = {
{BEV_MODAL_CANCEL, "CANCEL", 0, "Cancel", "Cancel bevel"},
{BEV_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", "Confirm bevel"},
- {BEV_MODAL_VALUE_OFFSET, "VALUE_OFFSET", 0, "Value is offset", "Value changes offset"},
- {BEV_MODAL_VALUE_PROFILE, "VALUE_PROFILE", 0, "Value is profile", "Value changes profile"},
- {BEV_MODAL_VALUE_SEGMENTS,
- "VALUE_SEGMENTS",
- 0,
- "Value is segments",
- "Value changes segments"},
+ {BEV_MODAL_VALUE_OFFSET, "VALUE_OFFSET", 0, "Change offset", "Value changes offset"},
+ {BEV_MODAL_VALUE_PROFILE, "VALUE_PROFILE", 0, "Change profile", "Value changes profile"},
+ {BEV_MODAL_VALUE_SEGMENTS, "VALUE_SEGMENTS", 0, "Change segments", "Value changes segments"},
{BEV_MODAL_SEGMENTS_UP, "SEGMENTS_UP", 0, "Increase segments", "Increase segments"},
{BEV_MODAL_SEGMENTS_DOWN, "SEGMENTS_DOWN", 0, "Decrease segments", "Decrease segments"},
{BEV_MODAL_OFFSET_MODE_CHANGE,
@@ -647,12 +668,18 @@ wmKeyMap *bevel_modal_keymap(wmKeyConfig *keyconf)
0,
"Change inner miter",
"Cycle through inner miter kinds"},
+ {BEV_MODAL_CUSTOM_PROFILE_TOGGLE, "CUSTOM_PROFILE_TOGGLE", 0, "Toggle custom profile", ""},
+ {BEV_MODAL_VERTEX_MESH_CHANGE,
+ "VERTEX_MESH_CHANGE",
+ 0,
+ "Change intersection method",
+ "Cycle through intersection methods"},
{0, NULL, 0, NULL, NULL},
};
wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Bevel Modal Map");
- /* this function is called for each spacetype, only needs to add map once */
+ /* This function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return NULL;
}
@@ -682,14 +709,14 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) {
edbm_bevel_numinput_set_value(op);
edbm_bevel_calc(op);
- edbm_bevel_update_header(C, op);
+ edbm_bevel_update_status_text(C, op);
return OPERATOR_RUNNING_MODAL;
}
else if (etype == MOUSEMOVE) {
if (!has_numinput) {
edbm_bevel_mouse_set_value(op, event);
edbm_bevel_calc(op);
- edbm_bevel_update_header(C, op);
+ edbm_bevel_update_status_text(C, op);
handled = true;
}
}
@@ -703,7 +730,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
RNA_int_set(op->ptr, "segments", (int)opdata->segments);
edbm_bevel_calc(op);
- edbm_bevel_update_header(C, op);
+ edbm_bevel_update_status_text(C, op);
handled = true;
}
else if (etype == EVT_MODAL_MAP) {
@@ -723,7 +750,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
opdata->segments = opdata->segments + 1;
RNA_int_set(op->ptr, "segments", (int)opdata->segments);
edbm_bevel_calc(op);
- edbm_bevel_update_header(C, op);
+ edbm_bevel_update_status_text(C, op);
handled = true;
break;
@@ -731,7 +758,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
opdata->segments = max_ff(opdata->segments - 1, 1);
RNA_int_set(op->ptr, "segments", (int)opdata->segments);
edbm_bevel_calc(op);
- edbm_bevel_update_header(C, op);
+ edbm_bevel_update_status_text(C, op);
handled = true;
break;
@@ -758,7 +785,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
edbm_bevel_mouse_set_value(op, event);
}
edbm_bevel_calc(op);
- edbm_bevel_update_header(C, op);
+ edbm_bevel_update_status_text(C, op);
handled = true;
break;
@@ -766,7 +793,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool clamp_overlap = RNA_boolean_get(op->ptr, "clamp_overlap");
RNA_boolean_set(op->ptr, "clamp_overlap", !clamp_overlap);
edbm_bevel_calc(op);
- edbm_bevel_update_header(C, op);
+ edbm_bevel_update_status_text(C, op);
handled = true;
break;
}
@@ -790,7 +817,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only");
RNA_boolean_set(op->ptr, "vertex_only", !vertex_only);
edbm_bevel_calc(op);
- edbm_bevel_update_header(C, op);
+ edbm_bevel_update_status_text(C, op);
handled = true;
break;
}
@@ -799,7 +826,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam");
RNA_boolean_set(op->ptr, "mark_seam", !mark_seam);
edbm_bevel_calc(op);
- edbm_bevel_update_header(C, op);
+ edbm_bevel_update_status_text(C, op);
handled = true;
break;
}
@@ -808,7 +835,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
RNA_boolean_set(op->ptr, "mark_sharp", !mark_sharp);
edbm_bevel_calc(op);
- edbm_bevel_update_header(C, op);
+ edbm_bevel_update_status_text(C, op);
handled = true;
break;
}
@@ -824,7 +851,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
RNA_enum_set(op->ptr, "miter_inner", miter_inner);
edbm_bevel_calc(op);
- edbm_bevel_update_header(C, op);
+ edbm_bevel_update_status_text(C, op);
handled = true;
break;
}
@@ -837,7 +864,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
RNA_enum_set(op->ptr, "miter_outer", miter_outer);
edbm_bevel_calc(op);
- edbm_bevel_update_header(C, op);
+ edbm_bevel_update_status_text(C, op);
handled = true;
break;
}
@@ -846,7 +873,29 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool harden_normals = RNA_boolean_get(op->ptr, "harden_normals");
RNA_boolean_set(op->ptr, "harden_normals", !harden_normals);
edbm_bevel_calc(op);
- edbm_bevel_update_header(C, op);
+ edbm_bevel_update_status_text(C, op);
+ handled = true;
+ break;
+ }
+
+ case BEV_MODAL_CUSTOM_PROFILE_TOGGLE: {
+ bool use_custom_profile = RNA_boolean_get(op->ptr, "use_custom_profile");
+ RNA_boolean_set(op->ptr, "use_custom_profile", !use_custom_profile);
+ edbm_bevel_calc(op);
+ edbm_bevel_update_status_text(C, op);
+ handled = true;
+ break;
+ }
+
+ case BEV_MODAL_VERTEX_MESH_CHANGE: {
+ int vmesh_method = RNA_enum_get(op->ptr, "vmesh_method");
+ vmesh_method++;
+ if (vmesh_method > BEVEL_VMESH_CUTOFF) {
+ vmesh_method = BEVEL_VMESH_ADJ;
+ }
+ RNA_enum_set(op->ptr, "vmesh_method", vmesh_method);
+ edbm_bevel_calc(op);
+ edbm_bevel_update_status_text(C, op);
handled = true;
break;
}
@@ -858,13 +907,84 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) {
edbm_bevel_numinput_set_value(op);
edbm_bevel_calc(op);
- edbm_bevel_update_header(C, op);
+ edbm_bevel_update_status_text(C, op);
return OPERATOR_RUNNING_MODAL;
}
return OPERATOR_RUNNING_MODAL;
}
+static void edbm_bevel_ui(bContext *C, wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ uiLayout *row, *col, *split;
+ PointerRNA ptr, toolsettings_ptr;
+ PropertyRNA *prop;
+ const char *offset_name;
+
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+
+ if (RNA_enum_get(&ptr, "offset_type") == BEVEL_AMT_PERCENT) {
+ uiItemR(layout, &ptr, "offset_pct", 0, NULL, ICON_NONE);
+ }
+ else {
+ switch (RNA_enum_get(&ptr, "offset_type")) {
+ case BEVEL_AMT_DEPTH:
+ offset_name = "Depth";
+ break;
+ case BEVEL_AMT_WIDTH:
+ offset_name = "Width";
+ break;
+ case BEVEL_AMT_OFFSET:
+ offset_name = "Offset";
+ break;
+ }
+ prop = RNA_struct_find_property(op->ptr, "offset_type");
+ RNA_property_enum_name_gettexted(
+ C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &offset_name);
+ uiItemR(layout, &ptr, "offset", 0, offset_name, ICON_NONE);
+ }
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, &ptr, "offset_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+
+ split = uiLayoutSplit(layout, 0.5f, true);
+ col = uiLayoutColumn(split, true);
+ uiItemR(col, &ptr, "vertex_only", 0, NULL, ICON_NONE);
+ uiItemR(col, &ptr, "clamp_overlap", 0, NULL, ICON_NONE);
+ uiItemR(col, &ptr, "loop_slide", 0, NULL, ICON_NONE);
+ col = uiLayoutColumn(split, true);
+ uiItemR(col, &ptr, "mark_seam", 0, NULL, ICON_NONE);
+ uiItemR(col, &ptr, "mark_sharp", 0, NULL, ICON_NONE);
+ uiItemR(col, &ptr, "harden_normals", 0, NULL, ICON_NONE);
+
+ uiItemR(layout, &ptr, "segments", 0, NULL, ICON_NONE);
+ uiItemR(layout, &ptr, "profile", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, &ptr, "material", 0, NULL, ICON_NONE);
+
+ uiItemL(layout, "Miter Type:", ICON_NONE);
+ uiItemR(layout, &ptr, "miter_outer", 0, "Outer", ICON_NONE);
+ uiItemR(layout, &ptr, "miter_inner", 0, "Inner", ICON_NONE);
+ if (RNA_enum_get(&ptr, "miter_inner") == BEVEL_MITER_ARC) {
+ uiItemR(layout, &ptr, "spread", 0, NULL, ICON_NONE);
+ }
+
+ uiItemL(layout, "Face Strength Mode:", ICON_NONE);
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, &ptr, "face_strength_mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+
+ uiItemL(layout, "Intersection Type:", ICON_NONE);
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, &ptr, "vmesh_method", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+
+ uiItemR(layout, &ptr, "use_custom_profile", 0, NULL, ICON_NONE);
+ if (RNA_boolean_get(&ptr, "use_custom_profile")) {
+ /* Get an RNA pointer to ToolSettings to give to the curve profile template code */
+ Scene *scene = CTX_data_scene(C);
+ RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr);
+ uiTemplateCurveProfile(layout, &toolsettings_ptr, "custom_bevel_profile_preset");
+ }
+}
+
void MESH_OT_bevel(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -906,10 +1026,19 @@ void MESH_OT_bevel(wmOperatorType *ot)
{0, NULL, 0, NULL, NULL},
};
+ static EnumPropertyItem vmesh_method_items[] = {
+ {BEVEL_VMESH_ADJ, "ADJ", 0, "Grid Fill", "Default patterned fill"},
+ {BEVEL_VMESH_CUTOFF,
+ "CUTOFF",
+ 0,
+ "Cutoff",
+ "A cut-off at each profile's end before the intersection"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
/* identifiers */
ot->name = "Bevel";
- ot->description =
- "Cut into selected items at an angle to create flat or rounded bevel or chamfer";
+ ot->description = "Cut into selected items at an angle to create bevel or chamfer";
ot->idname = "MESH_OT_bevel";
/* api callbacks */
@@ -919,19 +1048,23 @@ void MESH_OT_bevel(wmOperatorType *ot)
ot->cancel = edbm_bevel_cancel;
ot->poll = ED_operator_editmesh;
ot->poll_property = edbm_bevel_poll_property;
+ ot->ui = edbm_bevel_ui;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR_XY | OPTYPE_BLOCKING;
+ /* properties */
RNA_def_enum(
ot->srna, "offset_type", offset_type_items, 0, "Width Type", "What distance Width measures");
prop = RNA_def_property(ot->srna, "offset", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_range(prop, 0.0, 1e6);
- RNA_def_property_ui_range(prop, 0.0f, 100.0, 1, 3);
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 1, 3);
RNA_def_property_ui_text(prop, "Width", "Bevel amount");
+
prop = RNA_def_property(ot->srna, "offset_pct", PROP_FLOAT, PROP_PERCENTAGE);
RNA_def_property_range(prop, 0.0, 100);
RNA_def_property_ui_text(prop, "Width Percent", "Bevel amount for percentage method");
+
RNA_def_int(ot->srna,
"segments",
1,
@@ -941,6 +1074,7 @@ void MESH_OT_bevel(wmOperatorType *ot)
"Segments for curved edge",
1,
100);
+
RNA_def_float(ot->srna,
"profile",
0.5f,
@@ -950,16 +1084,22 @@ void MESH_OT_bevel(wmOperatorType *ot)
"Controls profile shape (0.5 = round)",
PROFILE_HARD_MIN,
1.0f);
+
RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex Only", "Bevel only vertices");
+
RNA_def_boolean(ot->srna,
"clamp_overlap",
false,
"Clamp Overlap",
"Do not allow beveled edges/vertices to overlap each other");
+
RNA_def_boolean(
- ot->srna, "loop_slide", true, "Loop Slide", "Prefer slide along edge to even widths");
+ ot->srna, "loop_slide", true, "Loop Slide", "Prefer sliding along edges to even widths");
+
RNA_def_boolean(ot->srna, "mark_seam", false, "Mark Seams", "Mark Seams along beveled edges");
+
RNA_def_boolean(ot->srna, "mark_sharp", false, "Mark Sharp", "Mark beveled edges as sharp");
+
RNA_def_int(ot->srna,
"material",
-1,
@@ -969,29 +1109,34 @@ void MESH_OT_bevel(wmOperatorType *ot)
"Material for bevel faces (-1 means use adjacent faces)",
-1,
100);
+
RNA_def_boolean(ot->srna,
"harden_normals",
false,
"Harden Normals",
"Match normals of new faces to adjacent faces");
+
RNA_def_enum(ot->srna,
"face_strength_mode",
face_strength_mode_items,
BEVEL_FACE_STRENGTH_NONE,
"Face Strength Mode",
"Whether to set face strength, and which faces to set face strength on");
+
RNA_def_enum(ot->srna,
"miter_outer",
miter_outer_items,
BEVEL_MITER_SHARP,
"Outer Miter",
"Pattern to use for outside of miters");
+
RNA_def_enum(ot->srna,
"miter_inner",
miter_inner_items,
BEVEL_MITER_SHARP,
"Inner Miter",
"Pattern to use for inside of miters");
+
RNA_def_float(ot->srna,
"spread",
0.1f,
@@ -1001,6 +1146,20 @@ void MESH_OT_bevel(wmOperatorType *ot)
"Amount to spread arcs for arc inner miters",
0.0f,
100.0f);
+
+ RNA_def_boolean(ot->srna,
+ "use_custom_profile",
+ false,
+ "Custom Profile",
+ "Use a custom profile for the bevel");
+
+ RNA_def_enum(ot->srna,
+ "vmesh_method",
+ vmesh_method_items,
+ BEVEL_VMESH_ADJ,
+ "Vertex Mesh Method",
+ "The method to use to create meshes at intersections");
+
prop = RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}