Bevel: Make modal keymap instead of hardcoded.

Also added keys for toggling harden normals,
and cycling through miter types.
Still to do: add some shortcuts for affecting the
spread value for arc miters.
This commit is contained in:
Howard Trickey 2019-02-10 16:08:25 -05:00
parent 09f4505712
commit 9ca6fc41ae
6 changed files with 282 additions and 130 deletions

@ -1 +1 @@
Subproject commit be0e825355c92d38d5fa55e43591a950fc517a7f
Subproject commit f999cc0908333ac0d4b2b203706f3eb640ba54c9

View File

@ -111,6 +111,7 @@ _km_hierarchy = [
('Knife Tool Modal Map', 'EMPTY', 'WINDOW', []),
('Custom Normals Modal Map', 'EMPTY', 'WINDOW', []),
('Bevel Modal Map', 'EMPTY', 'WINDOW', []),
('Paint Stroke Modal', 'EMPTY', 'WINDOW', []),
('Paint Curve', 'EMPTY', 'WINDOW', []),

View File

@ -4754,6 +4754,40 @@ def km_custom_normals_modal_map(_params):
return keymap
def km_bevel_modal_map(_params):
items = []
keymap = (
"Bevel Modal Map",
{"space_type": 'EMPTY', "region_type": 'WINDOW', "modal": True},
{"items": items},
)
items.extend([
("CANCEL", {"type": 'ESC', "value": 'PRESS', "any": True}, None),
("CANCEL", {"type": 'RIGHTMOUSE', "value": 'PRESS', "any": True}, None),
("CONFIRM", {"type": 'RET', "value": 'PRESS', "any": True}, None),
("CONFIRM", {"type": 'NUMPAD_ENTER', "value": 'PRESS', "any": True}, None),
("CONFIRM", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None),
("VALUE_OFFSET", {"type": 'A', "value": 'PRESS', "any": True}, None),
("VALUE_PROFILE", {"type": 'P', "value": 'PRESS', "any": True}, None),
("VALUE_SEGMENTS", {"type": 'S', "value": 'PRESS', "any": True}, None),
("SEGMENTS_UP", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "any": True}, None),
("SEGMENTS_UP", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "any": True}, None),
("SEGMENTS_DOWN", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "any": True}, None),
("SEGMENTS_DOWN", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "any": True}, None),
("OFFSET_MODE_CHANGE", {"type": 'M', "value": 'PRESS', "any": True}, None),
("CLAMP_OVERLAP_TOGGLE", {"type": 'C', "value": 'PRESS', "any": True}, None),
("VERTEX_ONLY_TOGGLE", {"type": 'V', "value": 'PRESS', "any": True}, None),
("HARDEN_NORMALS_TOGGLE", {"type": 'H', "value": 'PRESS', "any": True}, None),
("MARK_SEAM_TOGGLE", {"type": 'U', "value": 'PRESS', "any": True}, None),
("MARK_SHARP_TOGGLE", {"type": 'K', "value": 'PRESS', "any": True}, None),
("OUTER_MITER_CHANGE", {"type": 'O', "value": 'PRESS', "any": True}, None),
("INNER_MITER_CHANGE", {"type": 'I', "value": 'PRESS', "any": True}, None),
])
return keymap
def km_view3d_fly_modal(_params):
items = []
keymap = (
@ -5973,6 +6007,7 @@ def generate_keymaps(params=None):
km_standard_modal_map(params),
km_knife_tool_modal_map(params),
km_custom_normals_modal_map(params),
km_bevel_modal_map(params),
km_view3d_fly_modal(params),
km_view3d_walk_modal(params),
km_view3d_rotate_modal(params),

View File

@ -50,6 +50,9 @@
#include "ED_transform.h"
#include "ED_view3d.h"
#include "WM_api.h"
#include "WM_types.h"
#include "mesh_intern.h" /* own include */
@ -97,38 +100,97 @@ typedef struct {
float segments; /* Segments as float so smooth mouse pan works in small increments */
} BevelData;
enum {
BEV_MODAL_CANCEL = 1,
BEV_MODAL_CONFIRM,
BEV_MODAL_VALUE_OFFSET,
BEV_MODAL_VALUE_PROFILE,
BEV_MODAL_VALUE_SEGMENTS,
BEV_MODAL_SEGMENTS_UP,
BEV_MODAL_SEGMENTS_DOWN,
BEV_MODAL_OFFSET_MODE_CHANGE,
BEV_MODAL_CLAMP_OVERLAP_TOGGLE,
BEV_MODAL_VERTEX_ONLY_TOGGLE,
BEV_MODAL_HARDEN_NORMALS_TOGGLE,
BEV_MODAL_MARK_SEAM_TOGGLE,
BEV_MODAL_MARK_SHARP_TOGGLE,
BEV_MODAL_OUTER_MITER_CHANGE,
BEV_MODAL_INNER_MITER_CHANGE,
};
static void edbm_bevel_update_header(bContext *C, wmOperator *op)
{
const char *str = IFACE_("Confirm: (Enter/LMB), Cancel: (Esc/RMB), Mode: %s (M), Clamp Overlap: %s (C), "
"Vertex Only: %s (V), Profile Control: %s (P), Offset: %s, Segments: %d, Profile: %.3f");
char msg[UI_MAX_DRAW_STR];
ScrArea *sa = CTX_wm_area(C);
char header[UI_MAX_DRAW_STR];
char buf[UI_MAX_DRAW_STR];
char *p = buf;
int available_len = sizeof(buf);
Scene *sce = CTX_data_scene(C);
BevelData *opdata = op->customdata;
char offset_str[NUM_STR_REP_LEN];
const char *mode_str, *omiter_str, *imiter_str;
PropertyRNA *prop;
if (sa) {
BevelData *opdata = op->customdata;
char offset_str[NUM_STR_REP_LEN];
const char *type_str;
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "offset_type");
#define WM_MODALKEY(_id) \
WM_modalkeymap_operator_items_to_string_buf(op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p)
if (hasNumInput(&opdata->num_input[OFFSET_VALUE])) {
outputNumInput(&opdata->num_input[OFFSET_VALUE], offset_str, &sce->unit);
}
else {
BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "offset"));
}
RNA_property_enum_name_gettexted(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &type_str);
BLI_snprintf(msg, sizeof(msg), str, type_str,
WM_bool_as_string(RNA_boolean_get(op->ptr, "clamp_overlap")),
WM_bool_as_string(RNA_boolean_get(op->ptr, "vertex_only")),
WM_bool_as_string(opdata->value_mode == PROFILE_VALUE),
offset_str, RNA_int_get(op->ptr, "segments"), RNA_float_get(op->ptr, "profile"));
ED_area_status_text(sa, msg);
if (hasNumInput(&opdata->num_input[OFFSET_VALUE])) {
outputNumInput(&opdata->num_input[OFFSET_VALUE], offset_str, &sce->unit);
}
else {
BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "offset"));
}
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), &mode_str);
prop = RNA_struct_find_property(op->ptr, "miter_outer");
RNA_property_enum_name_gettexted(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &omiter_str);
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),
IFACE_("%s: confirm, "
"%s: cancel, "
"%s: mode (%s), "
"%s: offset (%s), "
"%s: segments (%d), "
"%s: profile (%.3f), "
"%s: clamp overlap (%s), "
"%s: vertex only (%s), "
"%s: outer miter (%s), "
"%s: inner imter (%s), "
"%s: harden normals (%s), "
"%s: mark seam (%s), "
"%s: mark sharp (%s)"
),
WM_MODALKEY(BEV_MODAL_CONFIRM),
WM_MODALKEY(BEV_MODAL_CANCEL),
WM_MODALKEY(BEV_MODAL_OFFSET_MODE_CHANGE),
mode_str,
WM_MODALKEY(BEV_MODAL_VALUE_OFFSET),
offset_str,
WM_MODALKEY(BEV_MODAL_VALUE_SEGMENTS),
RNA_int_get(op->ptr, "segments"),
WM_MODALKEY(BEV_MODAL_VALUE_PROFILE),
RNA_float_get(op->ptr, "profile"),
WM_MODALKEY(BEV_MODAL_CLAMP_OVERLAP_TOGGLE),
WM_bool_as_string(RNA_boolean_get(op->ptr, "clamp_overlap")),
WM_MODALKEY(BEV_MODAL_VERTEX_ONLY_TOGGLE),
WM_bool_as_string(RNA_boolean_get(op->ptr, "vertex_only")),
WM_MODALKEY(BEV_MODAL_OUTER_MITER_CHANGE),
omiter_str,
WM_MODALKEY(BEV_MODAL_INNER_MITER_CHANGE),
imiter_str,
WM_MODALKEY(BEV_MODAL_HARDEN_NORMALS_TOGGLE),
WM_bool_as_string(RNA_boolean_get(op->ptr, "harden_normals")),
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"))
);
#undef WM_MODALKEY
ED_workspace_status_text(C, header);
}
static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
@ -463,40 +525,96 @@ static void edbm_bevel_numinput_set_value(wmOperator *op)
}
}
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_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, "OFFSET_MODE_CHANGE", 0, "Change offset mode",
"Cycle through offset modes"},
{BEV_MODAL_CLAMP_OVERLAP_TOGGLE, "CLAMP_OVERLAP_TOGGLE", 0, "Toggle clamp overlap",
"Toggle clamp overlap flag"},
{BEV_MODAL_VERTEX_ONLY_TOGGLE, "VERTEX_ONLY_TOGGLE", 0, "Toggle vertex only",
"Toggle vertex only flag"},
{BEV_MODAL_HARDEN_NORMALS_TOGGLE, "HARDEN_NORMALS_TOGGLE", 0, "Toggle harden normals",
"Toggle harden normals flag"},
{BEV_MODAL_MARK_SEAM_TOGGLE, "MARK_SEAM_TOGGLE", 0, "Toggle mark seam",
"Toggle mark seam flag"},
{BEV_MODAL_MARK_SHARP_TOGGLE, "MARK_SHARP_TOGGLE", 0, "Toggle mark sharp",
"Toggle mark sharp flag"},
{BEV_MODAL_OUTER_MITER_CHANGE, "OUTER_MITER_CHANGE", 0, "Change outer miter",
"Cycle through outer miter kinds"},
{BEV_MODAL_INNER_MITER_CHANGE, "INNER_MITER_CHANGE", 0, "Change inner miter",
"Cycle through inner miter kinds"},
{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 */
if (keymap && keymap->modal_items)
return NULL;
keymap = WM_modalkeymap_add(keyconf, "Bevel Modal Map", modal_items);
WM_modalkeymap_assign(keymap, "MESH_OT_bevel");
return keymap;
}
static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
BevelData *opdata = op->customdata;
const bool has_numinput = hasNumInput(&opdata->num_input[opdata->value_mode]);
bool handled = false;
/* Modal numinput active, try to handle numeric inputs first... */
if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) {
if (event->type != EVT_MODAL_MAP && event->val == KM_PRESS && has_numinput && 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);
return OPERATOR_RUNNING_MODAL;
}
else {
bool handled = false;
switch (event->type) {
case ESCKEY:
case RIGHTMOUSE:
else if (event->type == MOUSEMOVE) {
if (!has_numinput) {
edbm_bevel_mouse_set_value(op, event);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
handled = true;
}
}
else if (event->type == MOUSEPAN) {
float delta = 0.02f * (event->y - event->prevy);
if (opdata->segments >= 1 && opdata->segments + delta < 1)
opdata->segments = 1;
else
opdata->segments += delta;
RNA_int_set(op->ptr, "segments", (int)opdata->segments);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
handled = true;
}
else if (event->type == EVT_MODAL_MAP){
switch (event->val) {
case BEV_MODAL_CANCEL:
edbm_bevel_cancel(C, op);
return OPERATOR_CANCELLED;
case MOUSEMOVE:
if (!has_numinput) {
edbm_bevel_mouse_set_value(op, event);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
handled = true;
}
break;
case LEFTMOUSE:
case PADENTER:
case RETKEY:
case BEV_MODAL_CONFIRM:
#if 0
if ((event->val == KM_PRESS) ||
((event->val == KM_RELEASE) && RNA_boolean_get(op->ptr, "release_confirm")))
#endif
{
edbm_bevel_calc(op);
edbm_bevel_exit(C, op);
@ -504,29 +622,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
break;
case MOUSEPAN: {
float delta = 0.02f * (event->y - event->prevy);
if (opdata->segments >= 1 && opdata->segments + delta < 1)
opdata->segments = 1;
else
opdata->segments += delta;
RNA_int_set(op->ptr, "segments", (int)opdata->segments);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
handled = true;
break;
}
/* Note this will prevent padplus and padminus to ever activate modal numinput.
* This is not really an issue though, as we only expect positive values here...
* Else we could force them to only modify segments number when shift is pressed, or so.
*/
case WHEELUPMOUSE: /* change number of segments */
case PADPLUSKEY:
if (event->val == KM_RELEASE)
break;
case BEV_MODAL_SEGMENTS_UP:
opdata->segments = opdata->segments + 1;
RNA_int_set(op->ptr, "segments", (int)opdata->segments);
edbm_bevel_calc(op);
@ -534,11 +630,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
handled = true;
break;
case WHEELDOWNMOUSE: /* change number of segments */
case PADMINUS:
if (event->val == KM_RELEASE)
break;
case BEV_MODAL_SEGMENTS_DOWN:
opdata->segments = max_ff(opdata->segments - 1, 1);
RNA_int_set(op->ptr, "segments", (int)opdata->segments);
edbm_bevel_calc(op);
@ -546,13 +638,9 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
handled = true;
break;
case MKEY:
if (event->val == KM_RELEASE)
break;
case BEV_MODAL_OFFSET_MODE_CHANGE:
{
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "offset_type");
int type = RNA_property_enum_get(op->ptr, prop);
int type = RNA_enum_get(op->ptr, "offset_type");
type++;
if (type > BEVEL_AMT_PERCENT) {
type = BEVEL_AMT_OFFSET;
@ -561,7 +649,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
opdata->value_mode = OFFSET_VALUE_PERCENT;
else if (opdata->value_mode == OFFSET_VALUE_PERCENT && type != BEVEL_AMT_PERCENT)
opdata->value_mode = OFFSET_VALUE;
RNA_property_enum_set(op->ptr, prop, type);
RNA_enum_set(op->ptr, "offset_type", type);
if (opdata->initial_length[opdata->value_mode] == -1.0f)
edbm_bevel_calc_initial_length(op, event, true);
}
@ -575,84 +663,110 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
edbm_bevel_update_header(C, op);
handled = true;
break;
case CKEY:
if (event->val == KM_RELEASE)
break;
case BEV_MODAL_CLAMP_OVERLAP_TOGGLE:
{
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "clamp_overlap");
RNA_property_boolean_set(op->ptr, prop, !RNA_property_boolean_get(op->ptr, prop));
}
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
handled = true;
break;
case PKEY:
if (event->val == KM_RELEASE)
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);
handled = true;
break;
if (opdata->value_mode == PROFILE_VALUE) {
opdata->value_mode = OFFSET_VALUE;
}
else {
opdata->value_mode = PROFILE_VALUE;
}
case BEV_MODAL_VALUE_OFFSET:
opdata->value_mode = OFFSET_VALUE;
edbm_bevel_calc_initial_length(op, event, true);
break;
case SKEY:
if (event->val == KM_RELEASE)
break;
if (opdata->value_mode == SEGMENTS_VALUE) {
opdata->value_mode = OFFSET_VALUE;
}
else {
opdata->value_mode = SEGMENTS_VALUE;
}
case BEV_MODAL_VALUE_PROFILE:
opdata->value_mode = PROFILE_VALUE;
edbm_bevel_calc_initial_length(op, event, true);
break;
case VKEY:
if (event->val == KM_RELEASE)
break;
{
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "vertex_only");
RNA_property_boolean_set(op->ptr, prop, !RNA_property_boolean_get(op->ptr, prop));
}
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
handled = true;
case BEV_MODAL_VALUE_SEGMENTS:
opdata->value_mode = SEGMENTS_VALUE;
edbm_bevel_calc_initial_length(op, event, true);
break;
case UKEY:
if (event->val == KM_RELEASE)
case BEV_MODAL_VERTEX_ONLY_TOGGLE:
{
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);
handled = true;
break;
else {
}
case BEV_MODAL_MARK_SEAM_TOGGLE:
{
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);
handled = true;
break;
}
case KKEY:
if (event->val == KM_RELEASE)
break;
else {
case BEV_MODAL_MARK_SHARP_TOGGLE:
{
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);
handled = true;
break;
}
}
case BEV_MODAL_INNER_MITER_CHANGE:
{
int miter_inner = RNA_enum_get(op->ptr, "miter_inner");
miter_inner++;
if (miter_inner == BEVEL_MITER_PATCH)
miter_inner++; /* no patch option for inner miter */
if (miter_inner > BEVEL_MITER_ARC)
miter_inner = BEVEL_MITER_SHARP;
RNA_enum_set(op->ptr, "miter_inner", miter_inner);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
handled = true;
break;
}
/* Modal numinput inactive, try to handle numeric inputs last... */
if (!handled && event->val == KM_PRESS && 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);
return OPERATOR_RUNNING_MODAL;
case BEV_MODAL_OUTER_MITER_CHANGE:
{
int miter_outer = RNA_enum_get(op->ptr, "miter_outer");
miter_outer++;
if (miter_outer > BEVEL_MITER_ARC)
miter_outer = BEVEL_MITER_SHARP;
RNA_enum_set(op->ptr, "miter_outer", miter_outer);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
handled = true;
break;
}
case BEV_MODAL_HARDEN_NORMALS_TOGGLE:
{
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);
handled = true;
break;
}
}
}
/* Modal numinput inactive, try to handle numeric inputs last... */
if (!handled && event->val == KM_PRESS && 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);
return OPERATOR_RUNNING_MODAL;
}
return OPERATOR_RUNNING_MODAL;
}

View File

@ -88,6 +88,7 @@ void MESH_OT_primitive_cube_add_gizmo(struct wmOperatorType *ot);
/* *** editmesh_bevel.c *** */
void MESH_OT_bevel(struct wmOperatorType *ot);
struct wmKeyMap *bevel_modal_keymap(struct wmKeyConfig *keyconf);
/* *** editmesh_bisect.c *** */
void MESH_OT_bisect(struct wmOperatorType *ot);

View File

@ -320,4 +320,5 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
knifetool_modal_keymap(keyconf);
point_normals_modal_keymap(keyconf);
bevel_modal_keymap(keyconf);
}