mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-09 20:47:00 -04:00
ddfb1a5089
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@2 0fc631ac-6414-0410-93d0-97cfa31319b6
530 lines
18 KiB
C++
530 lines
18 KiB
C++
//+----------------------------------------------------------------------------+
|
|
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
|
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
|
|
//| License: GNU General Public License 2 or later (see file COPYING) |
|
|
//+----------------------------------------------------------------------------+
|
|
|
|
// ----------------------------------------------------------------------------- : Includes
|
|
|
|
#include <gui/symbol/point_editor.hpp>
|
|
#include <gui/symbol/window.hpp>
|
|
#include <gfx/bezier.hpp>
|
|
#include <data/action/symbol_part.hpp>
|
|
#include <util/window_id.hpp>
|
|
#include <util/error.hpp>
|
|
|
|
// ----------------------------------------------------------------------------- : SymbolPointEditor
|
|
|
|
SymbolPointEditor::SymbolPointEditor(SymbolControl* control, const SymbolPartP& part)
|
|
: SymbolEditorBase(control)
|
|
, part(part)
|
|
, selection(SELECTED_NONE)
|
|
, hovering(SELECTED_NONE)
|
|
// Load gui stock
|
|
, pointSelect(_("CUR_POINT"), wxBITMAP_TYPE_CUR_RESOURCE)
|
|
, pointAdd (_("CUR_POINT_ADD"), wxBITMAP_TYPE_CUR_RESOURCE)
|
|
, pointCurve (_("CUR_POINT_CURVE"),wxBITMAP_TYPE_CUR_RESOURCE)
|
|
, pointMove (_("CUR_POINT_MOVE"), wxBITMAP_TYPE_CUR_RESOURCE)
|
|
{
|
|
resetActions();
|
|
// // fix pen joins
|
|
// penHandleHover.join = wxJOIN_MITER;
|
|
// penMainHover.join = wxJOIN_MITER;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------- : Drawing
|
|
|
|
void SymbolPointEditor::draw(DC& dc) {
|
|
// highlight the part
|
|
control.highlightPart(dc, *part, HIGHLIGHT_BORDER);
|
|
// handles etc.
|
|
if (hovering == SELECTED_LINE) {
|
|
drawHoveredLine(dc);
|
|
}
|
|
drawHandles(dc);
|
|
if (hovering == SELECTED_NEW_POINT) {
|
|
drawNewPoint(dc);
|
|
}
|
|
}
|
|
|
|
void SymbolPointEditor::drawHoveredLine(DC& dc) {
|
|
BezierCurve c(*hoverLine1, *hoverLine2);
|
|
wxPoint prevPoint = control.rotation.tr(hoverLine1->pos);
|
|
for(int i = 1 ; i <= 100 ; ++i) {
|
|
// Draw 100 segments of the curve
|
|
double t = double(i)/100.0f;
|
|
wxPoint curPoint = control.rotation.tr(c.pointAt(t));
|
|
double selectPercent = 1.0 - 1.2 * sqrt(fabs(hoverLineT-t)); // amount to color
|
|
if (selectPercent > 0) {
|
|
// gradient color
|
|
Color color(
|
|
col(300 - 300 * selectPercent),
|
|
col(300 * selectPercent),
|
|
col(0)
|
|
);
|
|
dc.SetPen(wxPen(color, 3));
|
|
dc.DrawLine(prevPoint, curPoint);
|
|
}
|
|
prevPoint = curPoint;
|
|
}
|
|
}
|
|
|
|
void SymbolPointEditor::drawHandles(DC& dc) {
|
|
dc.SetPen(Color(0,0,128));
|
|
dc.SetBrush(Color(128,128,255));
|
|
for (int i = 0 ; (size_t)i < part->points.size() ; ++i) {
|
|
// determine which handles to draw
|
|
bool selected = pointSelected(*part->getPoint(i));
|
|
bool selBefore = selected || pointSelected(*part->getPoint(i-1));
|
|
bool selAfter = selected || pointSelected(*part->getPoint(i+1));
|
|
// and draw them
|
|
drawControlPoint(dc, *part->getPoint(i), selBefore, selAfter);
|
|
}
|
|
}
|
|
|
|
void SymbolPointEditor::drawNewPoint(DC& dc) {
|
|
dc.SetPen(*wxGREEN_PEN);
|
|
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
|
wxPoint p = control.rotation.tr(newPoint);
|
|
drawHandleBox(dc, p.x, p.y, true);
|
|
}
|
|
|
|
void SymbolPointEditor::drawControlPoint(DC& dc, const ControlPoint& p, bool drawHandleBefore, bool drawHandleAfter) {
|
|
// Position
|
|
wxPoint p0 = control.rotation.tr(p.pos);
|
|
// Sub handles
|
|
if (drawHandleBefore || drawHandleAfter) {
|
|
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
|
// Before handle
|
|
if (drawHandleBefore && p.segmentBefore == SEGMENT_CURVE) {
|
|
wxPoint p1 = control.rotation.tr(p.pos + p.deltaBefore);
|
|
dc.SetPen(handlePen(PEN_LINE, p.lock));
|
|
dc.DrawLine(p0.x, p0.y, p1.x, p1.y);
|
|
dc.SetPen(handlePen(handleHovered(p, HANDLE_BEFORE) ? PEN_HOVER : PEN_NORMAL, p.lock));
|
|
drawHandleCircle(dc, p1.x, p1.y);
|
|
}
|
|
// After handle
|
|
if (drawHandleAfter && p.segmentAfter == SEGMENT_CURVE) {
|
|
wxPoint p1 = control.rotation.tr(p.pos + p.deltaAfter);
|
|
dc.SetPen(handlePen(PEN_LINE, p.lock));
|
|
dc.DrawLine(p0.x, p0.y, p1.x, p1.y);
|
|
dc.SetPen(handlePen(handleHovered(p, HANDLE_AFTER) ? PEN_HOVER : PEN_NORMAL, p.lock));
|
|
drawHandleCircle(dc, p1.x, p1.y);
|
|
}
|
|
}
|
|
// Main handle
|
|
// last, so it draws over lines to handles
|
|
bool selected = pointSelected(p);
|
|
wxPen hp(*wxBLACK, pointHovered(p) ? 2 : 1);
|
|
hp.SetJoin(wxJOIN_MITER);
|
|
dc.SetPen(hp);
|
|
dc.SetBrush(selected ? *wxGREEN_BRUSH : *wxTRANSPARENT_BRUSH);
|
|
drawHandleBox(dc, p0.x, p0.y, selected);
|
|
}
|
|
|
|
void SymbolPointEditor::drawHandleBox(DC& dc, UInt px, UInt py, bool active) {
|
|
dc.DrawRectangle(px - 3, py - 3, 7, 7);
|
|
if (!active) {
|
|
dc.SetPen(*wxWHITE_PEN);
|
|
dc.DrawRectangle(px - 2, py - 2, 5, 5);
|
|
}
|
|
}
|
|
void SymbolPointEditor::drawHandleCircle(DC& dc, UInt px, UInt py) {
|
|
dc.DrawCircle(px, py, 4);
|
|
}
|
|
|
|
wxPen SymbolPointEditor::handlePen(WhichPen p, LockMode lock) {
|
|
Color col;
|
|
if (lock == LOCK_FREE) col = Color(100, 100, 255);
|
|
if (lock == LOCK_DIR) col = Color(153, 0, 204);
|
|
if (lock == LOCK_SIZE) col = Color(204, 50, 50);
|
|
switch(p) {
|
|
case PEN_NORMAL: return wxPen(col);
|
|
case PEN_HOVER: return wxPen(col, 2);
|
|
case PEN_LINE: return wxPen(col, 1, wxDOT);
|
|
default: throw InternalError(_("SymbolPointEditor::handlePen"));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------- : UI
|
|
|
|
void SymbolPointEditor::initUI(wxToolBar* tb, wxMenuBar* mb) {
|
|
// Initialize toolbar
|
|
tb->AddSeparator();
|
|
tb->AddTool(ID_SEGMENT_LINE, _("Line"), Bitmap(_("TOOL_LINE")), wxNullBitmap, wxITEM_CHECK, _("To straigt line"), _("Makes the selected line straight"));
|
|
tb->AddTool(ID_SEGMENT_CURVE, _("Curve"), Bitmap(_("TOOL_CURVE")), wxNullBitmap, wxITEM_CHECK, _("To curve"), _("Makes the selected line curved"));
|
|
tb->AddSeparator();
|
|
tb->AddTool(ID_LOCK_FREE, _("Free"), Bitmap(_("TOOL_LOCK_FREE")), wxNullBitmap, wxITEM_CHECK, _("Unlock node"), _("Allows the two control points on the node to be moved freely"));
|
|
tb->AddTool(ID_LOCK_DIR, _("Smooth"), Bitmap(_("TOOL_LOCK_DIR")), wxNullBitmap, wxITEM_CHECK, _("Make node smooth"), _("Makes the selected node smooth by placing the two control points opposite each other"));
|
|
tb->AddTool(ID_LOCK_SIZE, _("Symmetric"), Bitmap(_("TOOL_LOCK_SIZE")), wxNullBitmap, wxITEM_CHECK, _("Make node symmetric"), _("Makes the selected node symetric"));
|
|
tb->Realize();
|
|
// TODO : menu bar
|
|
//mb->Insert(2, curveMenu, _("&Curve"))
|
|
}
|
|
|
|
void SymbolPointEditor::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
|
|
tb->DeleteTool(ID_SEGMENT_LINE);
|
|
tb->DeleteTool(ID_SEGMENT_CURVE);
|
|
tb->DeleteTool(ID_LOCK_FREE);
|
|
tb->DeleteTool(ID_LOCK_DIR);
|
|
tb->DeleteTool(ID_LOCK_SIZE);
|
|
// HACK: hardcoded size of rest of toolbar
|
|
tb->DeleteToolByPos(4); // delete separator
|
|
tb->DeleteToolByPos(4); // delete separator
|
|
// TODO : menu bar
|
|
//mb->Remove(2)
|
|
}
|
|
|
|
void SymbolPointEditor::onUpdateUI(wxUpdateUIEvent& ev) {
|
|
// enable
|
|
bool enabled = false, checked = false;
|
|
switch (ev.GetId()) {
|
|
case ID_SEGMENT_LINE: case ID_SEGMENT_CURVE:
|
|
enabled = selection == SELECTED_LINE;
|
|
break;
|
|
case ID_LOCK_FREE: case ID_LOCK_DIR: case ID_LOCK_SIZE:
|
|
enabled = selection == SELECTED_POINTS &&
|
|
selectedPoints.size() == 1 &&
|
|
(*selectedPoints.begin())->segmentBefore == SEGMENT_CURVE &&
|
|
(*selectedPoints.begin())->segmentAfter == SEGMENT_CURVE;
|
|
break;
|
|
default:
|
|
ev.Enable(false); // we don't know this item
|
|
return;
|
|
}
|
|
// check
|
|
if (enabled) {
|
|
switch (ev.GetId()) {
|
|
case ID_SEGMENT_LINE: case ID_SEGMENT_CURVE:
|
|
checked = selectedLine1->segmentAfter == ev.GetId() - ID_SEGMENT;
|
|
break;
|
|
case ID_LOCK_FREE: case ID_LOCK_DIR: case ID_LOCK_SIZE:
|
|
checked = (*selectedPoints.begin())->lock == ev.GetId() - ID_LOCK;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ev.Enable(enabled);
|
|
ev.Check(checked);
|
|
}
|
|
|
|
void SymbolPointEditor::onCommand(int id) {
|
|
switch (id) {
|
|
case ID_SEGMENT_LINE: case ID_SEGMENT_CURVE:
|
|
onChangeSegment( static_cast<SegmentMode>(id - ID_SEGMENT) );
|
|
case ID_LOCK_FREE: case ID_LOCK_DIR: case ID_LOCK_SIZE:
|
|
onChangeLock( static_cast<LockMode>(id - ID_LOCK) );
|
|
}
|
|
}
|
|
|
|
|
|
int SymbolPointEditor::modeToolId() { return ID_MODE_POINTS; }
|
|
|
|
// ----------------------------------------------------------------------------- : Mouse events
|
|
|
|
void SymbolPointEditor::onLeftDown(const Vector2D& pos, wxMouseEvent& ev) {
|
|
SelectedHandle handle = findHandle(pos);
|
|
if (handle.handle) {
|
|
selectHandle(handle, ev);
|
|
} else if (hovering == SELECTED_LINE) {
|
|
selectLine(ev);
|
|
} else if (hovering == SELECTED_NEW_POINT) {
|
|
selectLine(ev);
|
|
} else {
|
|
selectNothing();
|
|
}
|
|
// update window
|
|
control.Refresh(false);
|
|
}
|
|
|
|
void SymbolPointEditor::onLeftUp(const Vector2D& pos, wxMouseEvent& ev) {
|
|
// Left up => finalize all actions, new events start new actions
|
|
resetActions();
|
|
}
|
|
|
|
void SymbolPointEditor::onLeftDClick(const Vector2D& pos, wxMouseEvent& ev) {
|
|
findHoveredItem(pos, false);
|
|
if (hovering == SELECTED_NEW_POINT) {
|
|
// Add point
|
|
ControlPointAddAction* act = new ControlPointAddAction(part, hoverLine1Idx, hoverLineT);
|
|
getSymbol()->actions.add(act);
|
|
// select the new point
|
|
selectPoint(act->getNewPoint(), false);
|
|
selection = SELECTED_POINTS;
|
|
} else if (hovering == SELECTED_HANDLE && hoverHandle.handle == HANDLE_MAIN) { //%%%%%%% ||/&&
|
|
// Delete point
|
|
selectedPoints.clear();
|
|
selectPoint(hoverHandle.point, false);
|
|
getSymbol()->actions.add(controlPointRemoveAction(part, selectedPoints));
|
|
selectedPoints.clear();
|
|
selection = SELECTED_NONE;
|
|
}
|
|
// refresh
|
|
findHoveredItem(pos, false);
|
|
control.Refresh(false);
|
|
}
|
|
|
|
void SymbolPointEditor::onMouseMove(const Vector2D& from, const Vector2D& to, wxMouseEvent& ev) {
|
|
// Moving the mouse without dragging => select a point/handle
|
|
findHoveredItem(to, ev.AltDown());
|
|
control.Refresh(false);
|
|
}
|
|
|
|
void SymbolPointEditor::onMouseDrag(const Vector2D& from, const Vector2D& to, wxMouseEvent& ev) {
|
|
Vector2D delta = to - from;
|
|
if (selection == SELECTED_LINE && ev.AltDown()) {
|
|
// Drag the curve
|
|
if (controlPointMoveAction) controlPointMoveAction = 0;
|
|
if (!curveDragAction) {
|
|
curveDragAction = new CurveDragAction(selectedLine1, selectedLine2);
|
|
getSymbol()->actions.add(curveDragAction);
|
|
}
|
|
curveDragAction->move(delta, selectedLineT);
|
|
control.Refresh(false);
|
|
} else if (selection == SELECTED_POINTS || selection == SELECTED_LINE) {
|
|
// Move all selected points
|
|
if (curveDragAction) curveDragAction = 0;
|
|
if (!controlPointMoveAction) {
|
|
// create action we can add this movement to
|
|
controlPointMoveAction = new ControlPointMoveAction(selectedPoints);
|
|
getSymbol()->actions.add(controlPointMoveAction);
|
|
}
|
|
controlPointMoveAction->constrain = ev.ControlDown(); // ctrl constrains
|
|
controlPointMoveAction->move(delta);
|
|
newPoint += delta;
|
|
control.Refresh(false);
|
|
} else if (selection == SELECTED_HANDLE) {
|
|
// Move the selected handle
|
|
if (!handleMoveAction) {
|
|
handleMoveAction = new HandleMoveAction(selectedHandle);
|
|
getSymbol()->actions.add(handleMoveAction);
|
|
}
|
|
handleMoveAction->constrain = ev.ControlDown(); // ctrl constrains
|
|
handleMoveAction->move(delta);
|
|
control.Refresh(false);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------- : Other events
|
|
|
|
|
|
void SymbolPointEditor::onKeyChange(wxKeyEvent& ev) {
|
|
if (ev.GetKeyCode() == WXK_ALT && (hovering == SELECTED_LINE || hovering == SELECTED_NEW_POINT)) {
|
|
if (ev.AltDown()) {
|
|
hovering = SELECTED_LINE;
|
|
control.SetCursor(pointCurve);
|
|
SetStatusText(_("Drag to move curve"));
|
|
} else {
|
|
hovering = SELECTED_NEW_POINT;
|
|
control.SetCursor(pointAdd);
|
|
SetStatusText(_("Alt + drag to move curve; double click to add control point on this line"));
|
|
}
|
|
control.Refresh(false);
|
|
} else if (ev.GetKeyCode() == WXK_CONTROL) {
|
|
// constrain changed
|
|
if (controlPointMoveAction) {
|
|
controlPointMoveAction->constrain = ev.ControlDown();
|
|
controlPointMoveAction->move(Vector2D()); //refresh action
|
|
control.Refresh(false);
|
|
} else if (handleMoveAction) {
|
|
handleMoveAction->constrain = ev.ControlDown();
|
|
handleMoveAction->move(Vector2D()); //refresh action
|
|
control.Refresh(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SymbolPointEditor::onChar(wxKeyEvent& ev) {
|
|
if (ev.GetKeyCode() == WXK_DELETE) {
|
|
deleteSelection();
|
|
} else {
|
|
ev.Skip();
|
|
}
|
|
}
|
|
|
|
bool SymbolPointEditor::isEditing() {
|
|
return handleMoveAction || controlPointMoveAction || curveDragAction;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------- : Selection
|
|
|
|
void SymbolPointEditor::selectNothing() {
|
|
selection = SELECTED_NONE;
|
|
selectedPoints.clear();
|
|
}
|
|
|
|
void SymbolPointEditor::selectPoint(const ControlPointP& point, bool toggle) {
|
|
set<ControlPointP>::iterator inSet = selectedPoints.find(point);
|
|
if (toggle) {
|
|
if (inSet == selectedPoints.end()) {
|
|
selectedPoints.insert(point);
|
|
} else {
|
|
selectedPoints.erase(inSet);
|
|
}
|
|
} else {
|
|
if (inSet == selectedPoints.end()) {
|
|
selectedPoints.clear();
|
|
selectedPoints.insert(point);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SymbolPointEditor::selectHandle(const SelectedHandle& h, const wxMouseEvent& keystate) {
|
|
if (h.handle == HANDLE_MAIN) {
|
|
selection = SELECTED_POINTS;
|
|
selectPoint(h.point, keystate.ShiftDown());
|
|
} else {
|
|
selection = SELECTED_HANDLE;
|
|
selectedHandle = h;
|
|
}
|
|
}
|
|
|
|
void SymbolPointEditor::selectLine(const wxMouseEvent& keystate) {
|
|
selection = SELECTED_LINE;
|
|
selectedLine1 = hoverLine1;
|
|
selectedLine2 = hoverLine2;
|
|
selectedLineT = hoverLineT;
|
|
if (!keystate.ShiftDown()) selectedPoints.clear();
|
|
selectPoint(selectedLine1, true);
|
|
selectPoint(selectedLine2, true);
|
|
}
|
|
|
|
|
|
bool SymbolPointEditor::pointSelected(const ControlPointP& pnt) {
|
|
return selectedPoints.find(pnt) != selectedPoints.end();
|
|
}
|
|
bool SymbolPointEditor::pointSelected(const ControlPoint& pnt) {
|
|
FOR_EACH(s, selectedPoints) {
|
|
if (s.get() == &pnt) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SymbolPointEditor::pointHovered(const ControlPointP& pnt) {
|
|
return handleHovered(pnt, HANDLE_MAIN);
|
|
}
|
|
bool SymbolPointEditor::pointHovered(const ControlPoint& pnt) {
|
|
return handleHovered(pnt, HANDLE_MAIN);
|
|
}
|
|
|
|
bool SymbolPointEditor::handleHovered(const ControlPointP& pnt, WhichHandle wh) {
|
|
return hovering == SELECTED_HANDLE && hoverHandle.point == pnt && hoverHandle.handle == wh;
|
|
}
|
|
bool SymbolPointEditor::handleHovered(const ControlPoint& pnt, WhichHandle wh) {
|
|
return hovering == SELECTED_HANDLE && hoverHandle.point && hoverHandle.point.get() == &pnt && hoverHandle.handle == wh;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------- : Actions
|
|
|
|
void SymbolPointEditor::resetActions() {
|
|
handleMoveAction = nullptr;
|
|
controlPointMoveAction = nullptr;
|
|
curveDragAction = nullptr;
|
|
}
|
|
|
|
void SymbolPointEditor::deleteSelection() {
|
|
if (!selectedPoints.empty()) {
|
|
getSymbol()->actions.add(controlPointRemoveAction(part, selectedPoints));
|
|
selectedPoints.clear();
|
|
resetActions();
|
|
control.Refresh(false);
|
|
}
|
|
}
|
|
|
|
void SymbolPointEditor::onChangeSegment(SegmentMode mode) {
|
|
assert(selectedLine1);
|
|
assert(selectedLine2);
|
|
if (selectedLine1->segmentAfter == mode) return;
|
|
getSymbol()->actions.add(new SegmentModeAction(selectedLine1, selectedLine2, mode));
|
|
control.Refresh(false);
|
|
}
|
|
|
|
void SymbolPointEditor::onChangeLock(LockMode mode) {
|
|
getSymbol()->actions.add(new LockModeAction(*selectedPoints.begin(), mode));
|
|
control.Refresh(false);
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------- : Finding items
|
|
|
|
void SymbolPointEditor::findHoveredItem(const Vector2D& pos, bool altDown) {
|
|
// is there a point currently under the cursor?
|
|
hoverHandle = findHandle(pos);
|
|
// change cursor and statusbar if point is under it
|
|
if (hoverHandle.handle) {
|
|
hovering = SELECTED_HANDLE;
|
|
control.SetCursor(pointMove);
|
|
SetStatusText(_("Click and drag to move control point"));
|
|
} else {
|
|
// Not on a point or handle, maybe the cursor is on a curve
|
|
if (checkPosOnCurve(pos)) {
|
|
if (altDown) {
|
|
hovering = SELECTED_LINE;
|
|
control.SetCursor(pointCurve);
|
|
SetStatusText(_("Drag to move curve"));
|
|
} else {
|
|
hovering = SELECTED_NEW_POINT;
|
|
control.SetCursor(pointAdd);
|
|
SetStatusText(_("Alt + drag to move curve; double click to add control point on this line"));
|
|
}
|
|
} else {
|
|
hovering = SELECTED_NONE;
|
|
control.SetCursor(*wxSTANDARD_CURSOR);
|
|
SetStatusText(_(""));
|
|
}
|
|
}
|
|
}
|
|
|
|
bool SymbolPointEditor::checkPosOnCurve(const Vector2D& pos) {
|
|
double range = control.rotation.trInvS(3); // less then 3 pixels away is still a hit
|
|
size_t size = part->points.size();
|
|
for(int i = 0 ; (size_t)i < size ; ++i) {
|
|
// Curve between these lines
|
|
hoverLine1 = part->getPoint(i);
|
|
hoverLine2 = part->getPoint(i + 1);
|
|
if (posOnSegment(pos, range, *hoverLine1, *hoverLine2, newPoint, hoverLineT)) {
|
|
// mouse is on this line
|
|
hoverLine1Idx = i;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
SelectedHandle SymbolPointEditor::findHandle(const Vector2D& pos) {
|
|
double range = control.rotation.trInvS(3); // less then 3 pixels away is still a hit
|
|
// Is there a main handle there?
|
|
FOR_EACH(p, part->points) {
|
|
if (inRange(p->pos, pos, range)) {
|
|
// point is at pos
|
|
return SelectedHandle(p, HANDLE_MAIN);
|
|
}
|
|
}
|
|
// Is there a sub handle there?
|
|
// only check visible handles
|
|
for (int i = 0 ; (size_t)i < part->points.size() ; ++i) {
|
|
ControlPointP p = part->getPoint(i);
|
|
bool sel = pointSelected(p);
|
|
bool before = sel || pointSelected(part->getPoint(i-1)); // are the handles visible?
|
|
bool after = sel || pointSelected(part->getPoint(i+1));
|
|
if (before && p->segmentBefore == SEGMENT_CURVE) {
|
|
if (inRange(p->pos + p->deltaBefore, pos, range)) {
|
|
return SelectedHandle(p, HANDLE_BEFORE);
|
|
}
|
|
}
|
|
if (after && p->segmentAfter == SEGMENT_CURVE) {
|
|
if (inRange(p->pos + p->deltaAfter, pos, range)) {
|
|
return SelectedHandle(p, HANDLE_AFTER);
|
|
}
|
|
}
|
|
}
|
|
// Nothing found
|
|
return HANDLE_NONE;
|
|
}
|
|
|
|
bool SymbolPointEditor::inRange(const Vector2D& a, const Vector2D& b, double range) {
|
|
return abs(a.x - b.x) <= range &&
|
|
abs(a.y - b.y) <= range;
|
|
}
|