diff options
Diffstat (limited to 'source/blender/editors')
-rw-r--r-- | source/blender/editors/include/UI_interface.h | 3 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_draw.c | 232 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_handlers.c | 335 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_intern.h | 5 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_query.c | 3 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_templates.c | 608 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_widgets.c | 4 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_bevel.c | 263 |
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); } |