739 lines
18 KiB
C
739 lines
18 KiB
C
/*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
/** \file blender/editors/sculpt_paint/paint_curve.c
|
|
* \ingroup edsculpt
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "DNA_brush_types.h"
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_screen_types.h"
|
|
#include "DNA_space_types.h"
|
|
#include "DNA_view3d_types.h"
|
|
|
|
#include "BLI_math_vector.h"
|
|
|
|
#include "BKE_context.h"
|
|
#include "BKE_main.h"
|
|
#include "BKE_paint.h"
|
|
|
|
#include "DEG_depsgraph.h"
|
|
|
|
#include "ED_view3d.h"
|
|
#include "ED_paint.h"
|
|
|
|
#include "WM_api.h"
|
|
#include "WM_types.h"
|
|
|
|
#include "RNA_access.h"
|
|
#include "RNA_define.h"
|
|
|
|
#include "UI_view2d.h"
|
|
|
|
#include "paint_intern.h"
|
|
|
|
#define PAINT_CURVE_SELECT_THRESHOLD 40.0f
|
|
#define PAINT_CURVE_POINT_SELECT(pcp, i) (*(&pcp->bez.f1 + i) = SELECT)
|
|
|
|
bool paint_curve_poll(bContext *C)
|
|
{
|
|
Object *ob = CTX_data_active_object(C);
|
|
Paint *p;
|
|
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
|
SpaceImage *sima;
|
|
|
|
if (rv3d && !(ob && ((ob->mode & OB_MODE_ALL_PAINT) != 0)))
|
|
return false;
|
|
|
|
sima = CTX_wm_space_image(C);
|
|
|
|
if (sima && sima->mode != SI_MODE_PAINT)
|
|
return false;
|
|
|
|
p = BKE_paint_get_active_from_context(C);
|
|
|
|
if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#define SEL_F1 (1 << 0)
|
|
#define SEL_F2 (1 << 1)
|
|
#define SEL_F3 (1 << 2)
|
|
|
|
/* returns 0, 1, or 2 in point according to handle 1, pivot or handle 2 */
|
|
static PaintCurvePoint *paintcurve_point_get_closest(PaintCurve *pc, const float pos[2], bool ignore_pivot, const float threshold, char *point)
|
|
{
|
|
PaintCurvePoint *pcp, *closest = NULL;
|
|
int i;
|
|
float dist, closest_dist = FLT_MAX;
|
|
|
|
for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
|
|
dist = len_manhattan_v2v2(pos, pcp->bez.vec[0]);
|
|
if (dist < threshold) {
|
|
if (dist < closest_dist) {
|
|
closest = pcp;
|
|
closest_dist = dist;
|
|
if (point)
|
|
*point = SEL_F1;
|
|
}
|
|
}
|
|
if (!ignore_pivot) {
|
|
dist = len_manhattan_v2v2(pos, pcp->bez.vec[1]);
|
|
if (dist < threshold) {
|
|
if (dist < closest_dist) {
|
|
closest = pcp;
|
|
closest_dist = dist;
|
|
if (point)
|
|
*point = SEL_F2;
|
|
}
|
|
}
|
|
}
|
|
dist = len_manhattan_v2v2(pos, pcp->bez.vec[2]);
|
|
if (dist < threshold) {
|
|
if (dist < closest_dist) {
|
|
closest = pcp;
|
|
closest_dist = dist;
|
|
if (point)
|
|
*point = SEL_F3;
|
|
}
|
|
}
|
|
}
|
|
|
|
return closest;
|
|
}
|
|
|
|
static int paintcurve_point_co_index(char sel)
|
|
{
|
|
char i = 0;
|
|
while (sel != 1) {
|
|
sel >>= 1;
|
|
i++;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
static char paintcurve_point_side_index(const BezTriple *bezt, const bool is_first, const char fallback)
|
|
{
|
|
/* when matching, guess based on endpoint side */
|
|
if (BEZT_ISSEL_ANY(bezt)) {
|
|
if ((bezt->f1 & SELECT) == (bezt->f3 & SELECT)) {
|
|
return is_first ? SEL_F1 : SEL_F3;
|
|
}
|
|
else if (bezt->f1 & SELECT) {
|
|
return SEL_F1;
|
|
}
|
|
else if (bezt->f3 & SELECT) {
|
|
return SEL_F3;
|
|
}
|
|
else {
|
|
return fallback;
|
|
}
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/******************* Operators *********************************/
|
|
|
|
static int paintcurve_new_exec(bContext *C, wmOperator *UNUSED(op))
|
|
{
|
|
Paint *p = BKE_paint_get_active_from_context(C);
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
if (p && p->brush) {
|
|
p->brush->paint_curve = BKE_paint_curve_add(bmain, "PaintCurve");
|
|
}
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void PAINTCURVE_OT_new(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name = "Add New Paint Curve";
|
|
ot->description = "Add new paint curve";
|
|
ot->idname = "PAINTCURVE_OT_new";
|
|
|
|
/* api callbacks */
|
|
ot->exec = paintcurve_new_exec;
|
|
ot->poll = paint_curve_poll;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
}
|
|
|
|
static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2])
|
|
{
|
|
Paint *p = BKE_paint_get_active_from_context(C);
|
|
Brush *br = p->brush;
|
|
Main *bmain = CTX_data_main(C);
|
|
PaintCurve *pc;
|
|
PaintCurvePoint *pcp;
|
|
wmWindow *window = CTX_wm_window(C);
|
|
ARegion *ar = CTX_wm_region(C);
|
|
float vec[3] = {loc[0], loc[1], 0.0};
|
|
int add_index;
|
|
int i;
|
|
|
|
pc = br->paint_curve;
|
|
if (!pc) {
|
|
br->paint_curve = pc = BKE_paint_curve_add(bmain, "PaintCurve");
|
|
}
|
|
|
|
ED_paintcurve_undo_push_begin(op->type->name);
|
|
|
|
pcp = MEM_mallocN((pc->tot_points + 1) * sizeof(PaintCurvePoint), "PaintCurvePoint");
|
|
add_index = pc->add_index;
|
|
|
|
if (pc->points) {
|
|
if (add_index > 0)
|
|
memcpy(pcp, pc->points, add_index * sizeof(PaintCurvePoint));
|
|
if (add_index < pc->tot_points)
|
|
memcpy(pcp + add_index + 1, pc->points + add_index, (pc->tot_points - add_index) * sizeof(PaintCurvePoint));
|
|
|
|
MEM_freeN(pc->points);
|
|
}
|
|
pc->points = pcp;
|
|
pc->tot_points++;
|
|
|
|
/* initialize new point */
|
|
memset(&pcp[add_index], 0, sizeof(PaintCurvePoint));
|
|
copy_v3_v3(pcp[add_index].bez.vec[0], vec);
|
|
copy_v3_v3(pcp[add_index].bez.vec[1], vec);
|
|
copy_v3_v3(pcp[add_index].bez.vec[2], vec);
|
|
|
|
/* last step, clear selection from all bezier handles expect the next */
|
|
for (i = 0; i < pc->tot_points; i++) {
|
|
pcp[i].bez.f1 = pcp[i].bez.f2 = pcp[i].bez.f3 = 0;
|
|
}
|
|
|
|
BKE_paint_curve_clamp_endpoint_add_index(pc, add_index);
|
|
|
|
if (pc->add_index != 0) {
|
|
pcp[add_index].bez.f3 = SELECT;
|
|
pcp[add_index].bez.h2 = HD_ALIGN;
|
|
}
|
|
else {
|
|
pcp[add_index].bez.f1 = SELECT;
|
|
pcp[add_index].bez.h1 = HD_ALIGN;
|
|
}
|
|
|
|
ED_paintcurve_undo_push_end();
|
|
|
|
WM_paint_cursor_tag_redraw(window, ar);
|
|
}
|
|
|
|
|
|
static int paintcurve_add_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
{
|
|
int loc[2] = {event->mval[0], event->mval[1]};
|
|
paintcurve_point_add(C, op, loc);
|
|
RNA_int_set_array(op->ptr, "location", loc);
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
static int paintcurve_add_point_exec(bContext *C, wmOperator *op)
|
|
{
|
|
int loc[2];
|
|
|
|
if (RNA_struct_property_is_set(op->ptr, "location")) {
|
|
RNA_int_get_array(op->ptr, "location", loc);
|
|
paintcurve_point_add(C, op, loc);
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
void PAINTCURVE_OT_add_point(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name = "Add New Paint Curve Point";
|
|
ot->description = ot->name;
|
|
ot->idname = "PAINTCURVE_OT_add_point";
|
|
|
|
/* api callbacks */
|
|
ot->invoke = paintcurve_add_point_invoke;
|
|
ot->exec = paintcurve_add_point_exec;
|
|
ot->poll = paint_curve_poll;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
|
|
|
|
/* properties */
|
|
RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, SHRT_MAX,
|
|
"Location", "Location of vertex in area space", 0, SHRT_MAX);
|
|
}
|
|
|
|
static int paintcurve_delete_point_exec(bContext *C, wmOperator *op)
|
|
{
|
|
Paint *p = BKE_paint_get_active_from_context(C);
|
|
Brush *br = p->brush;
|
|
PaintCurve *pc;
|
|
PaintCurvePoint *pcp;
|
|
wmWindow *window = CTX_wm_window(C);
|
|
ARegion *ar = CTX_wm_region(C);
|
|
int i;
|
|
int tot_del = 0;
|
|
pc = br->paint_curve;
|
|
|
|
if (!pc || pc->tot_points == 0) {
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
ED_paintcurve_undo_push_begin(op->type->name);
|
|
|
|
#define DELETE_TAG 2
|
|
|
|
for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
|
|
if (BEZT_ISSEL_ANY(&pcp->bez)) {
|
|
pcp->bez.f2 |= DELETE_TAG;
|
|
tot_del++;
|
|
}
|
|
}
|
|
|
|
if (tot_del > 0) {
|
|
int j = 0;
|
|
int new_tot = pc->tot_points - tot_del;
|
|
PaintCurvePoint *points_new = NULL;
|
|
if (new_tot > 0)
|
|
points_new = MEM_mallocN(new_tot * sizeof(PaintCurvePoint), "PaintCurvePoint");
|
|
|
|
for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
|
|
if (!(pcp->bez.f2 & DELETE_TAG)) {
|
|
points_new[j] = pc->points[i];
|
|
|
|
if ((i + 1) == pc->add_index) {
|
|
BKE_paint_curve_clamp_endpoint_add_index(pc, j);
|
|
}
|
|
j++;
|
|
}
|
|
else if ((i + 1) == pc->add_index) {
|
|
/* prefer previous point */
|
|
pc->add_index = j;
|
|
}
|
|
}
|
|
MEM_freeN(pc->points);
|
|
|
|
pc->points = points_new;
|
|
pc->tot_points = new_tot;
|
|
}
|
|
|
|
#undef DELETE_TAG
|
|
|
|
ED_paintcurve_undo_push_end();
|
|
|
|
WM_paint_cursor_tag_redraw(window, ar);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
|
|
void PAINTCURVE_OT_delete_point(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name = "Remove Paint Curve Point";
|
|
ot->description = ot->name;
|
|
ot->idname = "PAINTCURVE_OT_delete_point";
|
|
|
|
/* api callbacks */
|
|
ot->exec = paintcurve_delete_point_exec;
|
|
ot->poll = paint_curve_poll;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_UNDO;
|
|
}
|
|
|
|
|
|
static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2], bool toggle, bool extend)
|
|
{
|
|
wmWindow *window = CTX_wm_window(C);
|
|
ARegion *ar = CTX_wm_region(C);
|
|
Paint *p = BKE_paint_get_active_from_context(C);
|
|
Brush *br = p->brush;
|
|
PaintCurve *pc;
|
|
int i;
|
|
const float loc_fl[2] = {UNPACK2(loc)};
|
|
|
|
pc = br->paint_curve;
|
|
|
|
if (!pc)
|
|
return false;
|
|
|
|
ED_paintcurve_undo_push_begin(op->type->name);
|
|
|
|
if (toggle) {
|
|
PaintCurvePoint *pcp;
|
|
char select = 0;
|
|
bool selected = false;
|
|
|
|
pcp = pc->points;
|
|
|
|
for (i = 0; i < pc->tot_points; i++) {
|
|
if (pcp[i].bez.f1 || pcp[i].bez.f2 || pcp[i].bez.f3) {
|
|
selected = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!selected) {
|
|
select = SELECT;
|
|
}
|
|
|
|
for (i = 0; i < pc->tot_points; i++) {
|
|
pc->points[i].bez.f1 = pc->points[i].bez.f2 = pc->points[i].bez.f3 = select;
|
|
}
|
|
}
|
|
else {
|
|
PaintCurvePoint *pcp;
|
|
char selflag;
|
|
|
|
pcp = paintcurve_point_get_closest(pc, loc_fl, false, PAINT_CURVE_SELECT_THRESHOLD, &selflag);
|
|
|
|
if (pcp) {
|
|
BKE_paint_curve_clamp_endpoint_add_index(pc, pcp - pc->points);
|
|
|
|
if (selflag == SEL_F2) {
|
|
if (extend)
|
|
pcp->bez.f2 ^= SELECT;
|
|
else
|
|
pcp->bez.f2 |= SELECT;
|
|
}
|
|
else if (selflag == SEL_F1) {
|
|
if (extend)
|
|
pcp->bez.f1 ^= SELECT;
|
|
else
|
|
pcp->bez.f1 |= SELECT;
|
|
}
|
|
else if (selflag == SEL_F3) {
|
|
if (extend)
|
|
pcp->bez.f3 ^= SELECT;
|
|
else
|
|
pcp->bez.f3 |= SELECT;
|
|
}
|
|
}
|
|
|
|
/* clear selection for unselected points if not extending and if a point has been selected */
|
|
if (!extend && pcp) {
|
|
for (i = 0; i < pc->tot_points; i++) {
|
|
pc->points[i].bez.f1 = pc->points[i].bez.f2 = pc->points[i].bez.f3 = 0;
|
|
|
|
if ((pc->points + i) == pcp) {
|
|
char index = paintcurve_point_co_index(selflag);
|
|
PAINT_CURVE_POINT_SELECT(pcp, index);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!pcp) {
|
|
ED_paintcurve_undo_push_end();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
ED_paintcurve_undo_push_end();
|
|
|
|
WM_paint_cursor_tag_redraw(window, ar);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
static int paintcurve_select_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
{
|
|
int loc[2] = {UNPACK2(event->mval)};
|
|
bool toggle = RNA_boolean_get(op->ptr, "toggle");
|
|
bool extend = RNA_boolean_get(op->ptr, "extend");
|
|
if (paintcurve_point_select(C, op, loc, toggle, extend)) {
|
|
RNA_int_set_array(op->ptr, "location", loc);
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
else {
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
}
|
|
|
|
static int paintcurve_select_point_exec(bContext *C, wmOperator *op)
|
|
{
|
|
int loc[2];
|
|
|
|
if (RNA_struct_property_is_set(op->ptr, "location")) {
|
|
bool toggle = RNA_boolean_get(op->ptr, "toggle");
|
|
bool extend = RNA_boolean_get(op->ptr, "extend");
|
|
RNA_int_get_array(op->ptr, "location", loc);
|
|
if (paintcurve_point_select(C, op, loc, toggle, extend))
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
void PAINTCURVE_OT_select(wmOperatorType *ot)
|
|
{
|
|
PropertyRNA *prop;
|
|
|
|
/* identifiers */
|
|
ot->name = "Select Paint Curve Point";
|
|
ot->description = "Select a paint curve point";
|
|
ot->idname = "PAINTCURVE_OT_select";
|
|
|
|
/* api callbacks */
|
|
ot->invoke = paintcurve_select_point_invoke;
|
|
ot->exec = paintcurve_select_point_exec;
|
|
ot->poll = paint_curve_poll;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
|
|
|
|
/* properties */
|
|
RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, SHRT_MAX,
|
|
"Location", "Location of vertex in area space", 0, SHRT_MAX);
|
|
prop = RNA_def_boolean(ot->srna, "toggle", false, "Toggle", "(De)select all");
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection");
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
}
|
|
|
|
typedef struct PointSlideData {
|
|
PaintCurvePoint *pcp;
|
|
char select;
|
|
int initial_loc[2];
|
|
float point_initial_loc[3][2];
|
|
int event;
|
|
bool align;
|
|
} PointSlideData;
|
|
|
|
static int paintcurve_slide_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
{
|
|
Paint *p = BKE_paint_get_active_from_context(C);
|
|
const float loc_fl[2] = {UNPACK2(event->mval)};
|
|
char select;
|
|
int i;
|
|
bool do_select = RNA_boolean_get(op->ptr, "select");
|
|
bool align = RNA_boolean_get(op->ptr, "align");
|
|
Brush *br = p->brush;
|
|
PaintCurve *pc = br->paint_curve;
|
|
PaintCurvePoint *pcp;
|
|
|
|
if (!pc)
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
if (do_select) {
|
|
pcp = paintcurve_point_get_closest(pc, loc_fl, align, PAINT_CURVE_SELECT_THRESHOLD, &select);
|
|
}
|
|
else {
|
|
pcp = NULL;
|
|
/* just find first selected point */
|
|
for (i = 0; i < pc->tot_points; i++) {
|
|
if ((select = paintcurve_point_side_index(&pc->points[i].bez, i == 0, SEL_F3))) {
|
|
pcp = &pc->points[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (pcp) {
|
|
ARegion *ar = CTX_wm_region(C);
|
|
wmWindow *window = CTX_wm_window(C);
|
|
PointSlideData *psd = MEM_mallocN(sizeof(PointSlideData), "PointSlideData");
|
|
copy_v2_v2_int(psd->initial_loc, event->mval);
|
|
psd->event = event->type;
|
|
psd->pcp = pcp;
|
|
psd->select = paintcurve_point_co_index(select);
|
|
for (i = 0; i < 3; i++) {
|
|
copy_v2_v2(psd->point_initial_loc[i], pcp->bez.vec[i]);
|
|
}
|
|
psd->align = align;
|
|
op->customdata = psd;
|
|
|
|
/* first, clear all selection from points */
|
|
for (i = 0; i < pc->tot_points; i++)
|
|
pc->points[i].bez.f1 = pc->points[i].bez.f3 = pc->points[i].bez.f2 = 0;
|
|
|
|
/* only select the active point */
|
|
PAINT_CURVE_POINT_SELECT(pcp, psd->select);
|
|
BKE_paint_curve_clamp_endpoint_add_index(pc, pcp - pc->points);
|
|
|
|
WM_event_add_modal_handler(C, op);
|
|
WM_paint_cursor_tag_redraw(window, ar);
|
|
return OPERATOR_RUNNING_MODAL;
|
|
}
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
}
|
|
|
|
static int paintcurve_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
|
{
|
|
PointSlideData *psd = op->customdata;
|
|
|
|
if (event->type == psd->event && event->val == KM_RELEASE) {
|
|
MEM_freeN(psd);
|
|
ED_paintcurve_undo_push_begin(op->type->name);
|
|
ED_paintcurve_undo_push_end();
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
switch (event->type) {
|
|
case MOUSEMOVE:
|
|
{
|
|
ARegion *ar = CTX_wm_region(C);
|
|
wmWindow *window = CTX_wm_window(C);
|
|
float diff[2] = {
|
|
event->mval[0] - psd->initial_loc[0],
|
|
event->mval[1] - psd->initial_loc[1]};
|
|
if (psd->select == 1) {
|
|
int i;
|
|
for (i = 0; i < 3; i++)
|
|
add_v2_v2v2(psd->pcp->bez.vec[i], diff, psd->point_initial_loc[i]);
|
|
}
|
|
else {
|
|
add_v2_v2(diff, psd->point_initial_loc[psd->select]);
|
|
copy_v2_v2(psd->pcp->bez.vec[psd->select], diff);
|
|
|
|
if (psd->align) {
|
|
char opposite = (psd->select == 0) ? 2 : 0;
|
|
sub_v2_v2v2(diff, psd->pcp->bez.vec[1], psd->pcp->bez.vec[psd->select]);
|
|
add_v2_v2v2(psd->pcp->bez.vec[opposite], psd->pcp->bez.vec[1], diff);
|
|
}
|
|
}
|
|
WM_paint_cursor_tag_redraw(window, ar);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
}
|
|
|
|
|
|
void PAINTCURVE_OT_slide(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name = "Slide Paint Curve Point";
|
|
ot->description = "Select and slide paint curve point";
|
|
ot->idname = "PAINTCURVE_OT_slide";
|
|
|
|
/* api callbacks */
|
|
ot->invoke = paintcurve_slide_invoke;
|
|
ot->modal = paintcurve_slide_modal;
|
|
ot->poll = paint_curve_poll;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_UNDO;
|
|
|
|
/* properties */
|
|
RNA_def_boolean(ot->srna, "align", false, "Align Handles", "Aligns opposite point handle during transform");
|
|
RNA_def_boolean(ot->srna, "select", true, "Select", "Attempt to select a point handle before transform");
|
|
}
|
|
|
|
static int paintcurve_draw_exec(bContext *C, wmOperator *UNUSED(op))
|
|
{
|
|
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
|
|
const char *name;
|
|
|
|
switch (mode) {
|
|
case PAINT_MODE_TEXTURE_2D:
|
|
case PAINT_MODE_TEXTURE_3D:
|
|
name = "PAINT_OT_image_paint";
|
|
break;
|
|
case PAINT_MODE_WEIGHT:
|
|
name = "PAINT_OT_weight_paint";
|
|
break;
|
|
case PAINT_MODE_VERTEX:
|
|
name = "PAINT_OT_vertex_paint";
|
|
break;
|
|
case PAINT_MODE_SCULPT:
|
|
name = "SCULPT_OT_brush_stroke";
|
|
break;
|
|
default:
|
|
return OPERATOR_PASS_THROUGH;
|
|
}
|
|
|
|
return WM_operator_name_call(C, name, WM_OP_INVOKE_DEFAULT, NULL);
|
|
}
|
|
|
|
void PAINTCURVE_OT_draw(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name = "Draw Curve";
|
|
ot->description = "Draw curve";
|
|
ot->idname = "PAINTCURVE_OT_draw";
|
|
|
|
/* api callbacks */
|
|
ot->exec = paintcurve_draw_exec;
|
|
ot->poll = paint_curve_poll;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_UNDO;
|
|
}
|
|
|
|
static int paintcurve_cursor_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
|
|
{
|
|
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
|
|
|
|
switch (mode) {
|
|
case PAINT_MODE_TEXTURE_2D:
|
|
{
|
|
ARegion *ar = CTX_wm_region(C);
|
|
SpaceImage *sima = CTX_wm_space_image(C);
|
|
float location[2];
|
|
|
|
if (!sima)
|
|
return OPERATOR_CANCELLED;
|
|
|
|
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
|
|
copy_v2_v2(sima->cursor, location);
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
|
|
break;
|
|
}
|
|
default:
|
|
ED_view3d_cursor3d_update(C, event->mval, true, V3D_CURSOR_ORIENT_VIEW);
|
|
break;
|
|
}
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void PAINTCURVE_OT_cursor(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name = "Place Cursor";
|
|
ot->description = "Place cursor";
|
|
ot->idname = "PAINTCURVE_OT_cursor";
|
|
|
|
/* api callbacks */
|
|
ot->invoke = paintcurve_cursor_invoke;
|
|
ot->poll = paint_curve_poll;
|
|
|
|
/* flags */
|
|
ot->flag = 0;
|
|
}
|