Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/object/object_constraint.c
| Show First 20 Lines • Show All 696 Lines • ▼ Show 20 Lines | static void edit_constraint_properties(wmOperatorType *ot) | ||||
| prop = RNA_def_string( | prop = RNA_def_string( | ||||
| ot->srna, "constraint", NULL, MAX_NAME, "Constraint", "Name of the constraint to edit"); | ot->srna, "constraint", NULL, MAX_NAME, "Constraint", "Name of the constraint to edit"); | ||||
| RNA_def_property_flag(prop, PROP_HIDDEN); | RNA_def_property_flag(prop, PROP_HIDDEN); | ||||
| prop = RNA_def_enum( | prop = RNA_def_enum( | ||||
| ot->srna, "owner", constraint_owner_items, 0, "Owner", "The owner of this constraint"); | ot->srna, "owner", constraint_owner_items, 0, "Owner", "The owner of this constraint"); | ||||
| RNA_def_property_flag(prop, PROP_HIDDEN); | RNA_def_property_flag(prop, PROP_HIDDEN); | ||||
| } | } | ||||
| static bool edit_constraint_invoke_properties(bContext *C, wmOperator *op) | static void edit_constraint_report_property(wmOperatorType *ot) | ||||
| { | |||||
| PropertyRNA *prop = RNA_def_boolean( | |||||
| ot->srna, "report", false, "Report", "Create a notification after the operation"); | |||||
| RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); | |||||
| } | |||||
| static bool edit_constraint_invoke_properties(bContext *C, | |||||
| wmOperator *op, | |||||
| const wmEvent *event, | |||||
| int *r_retval) | |||||
| { | { | ||||
| PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint); | PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint); | ||||
| Object *ob = (ptr.owner_id) ? (Object *)ptr.owner_id : ED_object_active_context(C); | Object *ob = (ptr.owner_id) ? (Object *)ptr.owner_id : ED_object_active_context(C); | ||||
| bConstraint *con; | bConstraint *con; | ||||
| ListBase *list; | ListBase *list; | ||||
| if (RNA_struct_property_is_set(op->ptr, "constraint") && | if (RNA_struct_property_is_set(op->ptr, "constraint") && | ||||
| RNA_struct_property_is_set(op->ptr, "owner")) { | RNA_struct_property_is_set(op->ptr, "owner")) { | ||||
| Show All 11 Lines | if (ptr.data) { | ||||
| } | } | ||||
| else { | else { | ||||
| RNA_enum_set(op->ptr, "owner", EDIT_CONSTRAINT_OWNER_BONE); | RNA_enum_set(op->ptr, "owner", EDIT_CONSTRAINT_OWNER_BONE); | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* Check the custom data of panels under the mouse for a modifier. */ | |||||
| if (event != NULL) { | |||||
| PointerRNA *panel_ptr = UI_region_panel_custom_data_under_cursor(C, event); | |||||
| if (!(panel_ptr == NULL || RNA_pointer_is_null(panel_ptr))) { | |||||
| if (RNA_struct_is_a(panel_ptr->type, &RNA_Constraint)) { | |||||
| con = panel_ptr->data; | |||||
| RNA_string_set(op->ptr, "constraint", con->name); | |||||
| list = ED_object_constraint_list_from_constraint(ob, con, NULL); | |||||
| RNA_enum_set(op->ptr, | |||||
| "owner", | |||||
| (&ob->constraints == list) ? EDIT_CONSTRAINT_OWNER_OBJECT : | |||||
| EDIT_CONSTRAINT_OWNER_BONE); | |||||
| return true; | |||||
| } | |||||
| BLI_assert(r_retval != NULL); /* We need the return value in this case. */ | |||||
| if (r_retval != NULL) { | |||||
| *r_retval = (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); | |||||
| } | |||||
| return false; | |||||
| } | |||||
| } | |||||
| return false; | return false; | ||||
| } | } | ||||
| static bConstraint *edit_constraint_property_get(wmOperator *op, Object *ob, int type) | static bConstraint *edit_constraint_property_get(wmOperator *op, Object *ob, int type) | ||||
| { | { | ||||
| char constraint_name[MAX_NAME]; | char constraint_name[MAX_NAME]; | ||||
| int owner = RNA_enum_get(op->ptr, "owner"); | int owner = RNA_enum_get(op->ptr, "owner"); | ||||
| bConstraint *con; | bConstraint *con; | ||||
| ▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | static int stretchto_reset_exec(bContext *C, wmOperator *op) | ||||
| ED_object_constraint_update(bmain, ob); | ED_object_constraint_update(bmain, ob); | ||||
| WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, NULL); | WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static int stretchto_reset_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) | static int stretchto_reset_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) | ||||
| { | { | ||||
| if (edit_constraint_invoke_properties(C, op)) { | if (edit_constraint_invoke_properties(C, op, NULL, NULL)) { | ||||
| return stretchto_reset_exec(C, op); | return stretchto_reset_exec(C, op); | ||||
| } | } | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| void CONSTRAINT_OT_stretchto_reset(wmOperatorType *ot) | void CONSTRAINT_OT_stretchto_reset(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| Show All 38 Lines | static int limitdistance_reset_exec(bContext *C, wmOperator *op) | ||||
| ED_object_constraint_update(bmain, ob); | ED_object_constraint_update(bmain, ob); | ||||
| WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, NULL); | WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static int limitdistance_reset_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) | static int limitdistance_reset_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) | ||||
| { | { | ||||
| if (edit_constraint_invoke_properties(C, op)) { | if (edit_constraint_invoke_properties(C, op, NULL, NULL)) { | ||||
| return limitdistance_reset_exec(C, op); | return limitdistance_reset_exec(C, op); | ||||
| } | } | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| void CONSTRAINT_OT_limitdistance_reset(wmOperatorType *ot) | void CONSTRAINT_OT_limitdistance_reset(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | static int childof_set_inverse_exec(bContext *C, wmOperator *op) | ||||
| ED_object_constraint_update(bmain, ob); | ED_object_constraint_update(bmain, ob); | ||||
| WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); | WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static int childof_set_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) | static int childof_set_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) | ||||
| { | { | ||||
| if (edit_constraint_invoke_properties(C, op)) { | if (edit_constraint_invoke_properties(C, op, NULL, NULL)) { | ||||
| return childof_set_inverse_exec(C, op); | return childof_set_inverse_exec(C, op); | ||||
| } | } | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| void CONSTRAINT_OT_childof_set_inverse(wmOperatorType *ot) | void CONSTRAINT_OT_childof_set_inverse(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| Show All 32 Lines | static int childof_clear_inverse_exec(bContext *C, wmOperator *op) | ||||
| ED_object_constraint_update(bmain, ob); | ED_object_constraint_update(bmain, ob); | ||||
| WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); | WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static int childof_clear_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) | static int childof_clear_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) | ||||
| { | { | ||||
| if (edit_constraint_invoke_properties(C, op)) { | if (edit_constraint_invoke_properties(C, op, NULL, NULL)) { | ||||
| return childof_clear_inverse_exec(C, op); | return childof_clear_inverse_exec(C, op); | ||||
| } | } | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| void CONSTRAINT_OT_childof_clear_inverse(wmOperatorType *ot) | void CONSTRAINT_OT_childof_clear_inverse(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | static int followpath_path_animate_exec(bContext *C, wmOperator *op) | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static int followpath_path_animate_invoke(bContext *C, | static int followpath_path_animate_invoke(bContext *C, | ||||
| wmOperator *op, | wmOperator *op, | ||||
| const wmEvent *UNUSED(event)) | const wmEvent *UNUSED(event)) | ||||
| { | { | ||||
| /* hook up invoke properties for figuring out which constraint we're dealing with */ | /* hook up invoke properties for figuring out which constraint we're dealing with */ | ||||
| if (edit_constraint_invoke_properties(C, op)) { | if (edit_constraint_invoke_properties(C, op, NULL, NULL)) { | ||||
| return followpath_path_animate_exec(C, op); | return followpath_path_animate_exec(C, op); | ||||
| } | } | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| void CONSTRAINT_OT_followpath_path_animate(wmOperatorType *ot) | void CONSTRAINT_OT_followpath_path_animate(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op) | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static int objectsolver_set_inverse_invoke(bContext *C, | static int objectsolver_set_inverse_invoke(bContext *C, | ||||
| wmOperator *op, | wmOperator *op, | ||||
| const wmEvent *UNUSED(event)) | const wmEvent *UNUSED(event)) | ||||
| { | { | ||||
| if (edit_constraint_invoke_properties(C, op)) { | if (edit_constraint_invoke_properties(C, op, NULL, NULL)) { | ||||
| return objectsolver_set_inverse_exec(C, op); | return objectsolver_set_inverse_exec(C, op); | ||||
| } | } | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| void CONSTRAINT_OT_objectsolver_set_inverse(wmOperatorType *ot) | void CONSTRAINT_OT_objectsolver_set_inverse(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| Show All 39 Lines | static int objectsolver_clear_inverse_exec(bContext *C, wmOperator *op) | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static int objectsolver_clear_inverse_invoke(bContext *C, | static int objectsolver_clear_inverse_invoke(bContext *C, | ||||
| wmOperator *op, | wmOperator *op, | ||||
| const wmEvent *UNUSED(event)) | const wmEvent *UNUSED(event)) | ||||
| { | { | ||||
| if (edit_constraint_invoke_properties(C, op)) { | if (edit_constraint_invoke_properties(C, op, NULL, NULL)) { | ||||
| return objectsolver_clear_inverse_exec(C, op); | return objectsolver_clear_inverse_exec(C, op); | ||||
| } | } | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| void CONSTRAINT_OT_objectsolver_clear_inverse(wmOperatorType *ot) | void CONSTRAINT_OT_objectsolver_clear_inverse(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | void ED_object_constraint_dependency_tag_update(Main *bmain, Object *ob, bConstraint *con) | ||||
| ED_object_constraint_tag_update(bmain, ob, con); | ED_object_constraint_tag_update(bmain, ob, con); | ||||
| if (ob->pose) { | if (ob->pose) { | ||||
| object_pose_tag_update(bmain, ob); | object_pose_tag_update(bmain, ob); | ||||
| } | } | ||||
| DEG_relations_tag_update(bmain); | DEG_relations_tag_update(bmain); | ||||
| } | } | ||||
| static bool constraint_poll(bContext *C) | |||||
| { | |||||
| PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint); | |||||
| return (ptr.owner_id && ptr.data); | |||||
| } | |||||
| /** \} */ | /** \} */ | ||||
| /* ------------------------------------------------------------------- */ | /* ------------------------------------------------------------------- */ | ||||
| /** \name Delete Constraint Operator | /** \name Delete Constraint Operator | ||||
| * \{ */ | * \{ */ | ||||
| static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op)) | static int constraint_delete_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| Main *bmain = CTX_data_main(C); | Main *bmain = CTX_data_main(C); | ||||
| PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint); | Object *ob = ED_object_active_context(C); | ||||
| Object *ob = (Object *)ptr.owner_id; | bConstraint *con = edit_constraint_property_get(op, ob, 0); | ||||
| bConstraint *con = ptr.data; | |||||
| ListBase *lb = ED_object_constraint_list_from_constraint(ob, con, NULL); | ListBase *lb = ED_object_constraint_list_from_constraint(ob, con, NULL); | ||||
| /* Store name temporarily for report. */ | |||||
| char name[MAX_NAME]; | |||||
| strcpy(name, con->name); | |||||
| /* free the constraint */ | /* free the constraint */ | ||||
| if (BKE_constraint_remove_ex(lb, ob, con, true)) { | if (BKE_constraint_remove_ex(lb, ob, con, true)) { | ||||
| /* there's no active constraint now, so make sure this is the case */ | /* there's no active constraint now, so make sure this is the case */ | ||||
| BKE_constraints_active_set(&ob->constraints, NULL); | BKE_constraints_active_set(&ob->constraints, NULL); | ||||
| /* needed to set the flags on posebones correctly */ | /* needed to set the flags on posebones correctly */ | ||||
| ED_object_constraint_update(bmain, ob); | ED_object_constraint_update(bmain, ob); | ||||
| /* relations */ | /* relations */ | ||||
| DEG_relations_tag_update(CTX_data_main(C)); | DEG_relations_tag_update(CTX_data_main(C)); | ||||
| /* notifiers */ | /* notifiers */ | ||||
| WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); | WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); | ||||
| if (RNA_boolean_get(op->ptr, "report")) { | |||||
| BKE_reportf(op->reports, RPT_INFO, "Removed constraint: %s", name); | |||||
| } | |||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| /* couldn't remove due to some invalid data */ | /* couldn't remove due to some invalid data */ | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| static int constraint_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event) | |||||
| { | |||||
| int retval; | |||||
| if (edit_constraint_invoke_properties(C, op, event, &retval)) { | |||||
| return constraint_delete_exec(C, op); | |||||
| } | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| void CONSTRAINT_OT_delete(wmOperatorType *ot) | void CONSTRAINT_OT_delete(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Delete Constraint"; | ot->name = "Delete Constraint"; | ||||
| ot->idname = "CONSTRAINT_OT_delete"; | ot->idname = "CONSTRAINT_OT_delete"; | ||||
| ot->description = "Remove constraint from constraint stack"; | ot->description = "Remove constraint from constraint stack"; | ||||
| /* callbacks */ | /* callbacks */ | ||||
| ot->invoke = constraint_delete_invoke; | |||||
| ot->exec = constraint_delete_exec; | ot->exec = constraint_delete_exec; | ||||
| ot->poll = constraint_poll; | ot->poll = edit_constraint_poll; | ||||
HooglyBoogly: This is the only thing: I had to add invoke and change the poll function for the delete… | |||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| edit_constraint_properties(ot); | |||||
| edit_constraint_report_property(ot); | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* ------------------------------------------------------------------- */ | /* ------------------------------------------------------------------- */ | ||||
| /** \name Move Down Constraint Operator | /** \name Move Down Constraint Operator | ||||
| * \{ */ | * \{ */ | ||||
| Show All 13 Lines | if (con && con->next) { | ||||
| WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); | WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| static int constraint_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) | static int constraint_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| if (edit_constraint_invoke_properties(C, op)) { | int retval; | ||||
| if (edit_constraint_invoke_properties(C, op, event, &retval)) { | |||||
| return constraint_move_down_exec(C, op); | return constraint_move_down_exec(C, op); | ||||
| } | } | ||||
| return OPERATOR_CANCELLED; | return retval; | ||||
| } | } | ||||
| void CONSTRAINT_OT_move_down(wmOperatorType *ot) | void CONSTRAINT_OT_move_down(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Move Constraint Down"; | ot->name = "Move Constraint Down"; | ||||
| ot->idname = "CONSTRAINT_OT_move_down"; | ot->idname = "CONSTRAINT_OT_move_down"; | ||||
| ot->description = "Move constraint down in constraint stack"; | ot->description = "Move constraint down in constraint stack"; | ||||
| Show All 32 Lines | if (con && con->prev) { | ||||
| WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); | WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| static int constraint_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) | static int constraint_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| if (edit_constraint_invoke_properties(C, op)) { | int retval; | ||||
| if (edit_constraint_invoke_properties(C, op, event, &retval)) { | |||||
| return constraint_move_up_exec(C, op); | return constraint_move_up_exec(C, op); | ||||
| } | } | ||||
| return OPERATOR_CANCELLED; | return retval; | ||||
| } | } | ||||
| void CONSTRAINT_OT_move_up(wmOperatorType *ot) | void CONSTRAINT_OT_move_up(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Move Constraint Up"; | ot->name = "Move Constraint Up"; | ||||
| ot->idname = "CONSTRAINT_OT_move_up"; | ot->idname = "CONSTRAINT_OT_move_up"; | ||||
| ot->description = "Move constraint up in constraint stack"; | ot->description = "Move constraint up in constraint stack"; | ||||
| Show All 34 Lines | if (con) { | ||||
| WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); | WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| static int constraint_move_to_index_invoke(bContext *C, | static int constraint_move_to_index_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| wmOperator *op, | |||||
| const wmEvent *UNUSED(event)) | |||||
| { | { | ||||
| if (edit_constraint_invoke_properties(C, op)) { | int retval; | ||||
| if (edit_constraint_invoke_properties(C, op, event, &retval)) { | |||||
| return constraint_move_to_index_exec(C, op); | return constraint_move_to_index_exec(C, op); | ||||
| } | } | ||||
| return OPERATOR_CANCELLED; | return retval; | ||||
| } | } | ||||
| void CONSTRAINT_OT_move_to_index(wmOperatorType *ot) | void CONSTRAINT_OT_move_to_index(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Move Constraint To Index"; | ot->name = "Move Constraint To Index"; | ||||
| ot->idname = "CONSTRAINT_OT_move_to_index"; | ot->idname = "CONSTRAINT_OT_move_to_index"; | ||||
| ot->description = | ot->description = | ||||
| ▲ Show 20 Lines • Show All 809 Lines • Show Last 20 Lines | |||||
This is the only thing: I had to add invoke and change the poll function for the delete operator. It's now more consistent with the other stack "remove" operators.