1128277c9SStephan Aßmus /* 2128277c9SStephan Aßmus * Copyright 2006, Haiku. 3128277c9SStephan Aßmus * Distributed under the terms of the MIT License. 4128277c9SStephan Aßmus * 5128277c9SStephan Aßmus * Authors: 6128277c9SStephan Aßmus * Stephan Aßmus <superstippi@gmx.de> 7128277c9SStephan Aßmus */ 8128277c9SStephan Aßmus 9128277c9SStephan Aßmus #include "PathManipulator.h" 10128277c9SStephan Aßmus 11128277c9SStephan Aßmus #include <float.h> 12128277c9SStephan Aßmus #include <stdio.h> 13128277c9SStephan Aßmus 14128277c9SStephan Aßmus #include <Cursor.h> 15128277c9SStephan Aßmus #include <Message.h> 16f4bd80a2SStephan Aßmus #include <MenuItem.h> 17f4bd80a2SStephan Aßmus #include <PopUpMenu.h> 18128277c9SStephan Aßmus #include <Window.h> 19128277c9SStephan Aßmus 20128277c9SStephan Aßmus #include "cursors.h" 21128277c9SStephan Aßmus #include "support.h" 22128277c9SStephan Aßmus 23f67876a0SStephan Aßmus #include "CanvasView.h" 24128277c9SStephan Aßmus 25128277c9SStephan Aßmus #include "AddPointCommand.h" 26128277c9SStephan Aßmus #include "ChangePointCommand.h" 27128277c9SStephan Aßmus //#include "CloseCommand.h" 28128277c9SStephan Aßmus #include "InsertPointCommand.h" 29128277c9SStephan Aßmus //#include "NewPathCommand.h" 300e1ba39fSStephan Aßmus #include "NudgePointsCommand.h" 31128277c9SStephan Aßmus //#include "RemovePathCommand.h" 32128277c9SStephan Aßmus #include "RemovePointsCommand.h" 33128277c9SStephan Aßmus //#include "ReversePathCommand.h" 34128277c9SStephan Aßmus //#include "SelectPathCommand.h" 35128277c9SStephan Aßmus //#include "SelectPointsCommand.h" 36f4bd80a2SStephan Aßmus #include "SplitPointsCommand.h" 370e1ba39fSStephan Aßmus #include "TransformPointsBox.h" 38128277c9SStephan Aßmus 39128277c9SStephan Aßmus #define POINT_EXTEND 3.0 40128277c9SStephan Aßmus #define CONTROL_POINT_EXTEND 2.0 41128277c9SStephan Aßmus #define INSERT_DIST_THRESHOLD 7.0 42128277c9SStephan Aßmus #define MOVE_THRESHOLD 9.0 43128277c9SStephan Aßmus 44128277c9SStephan Aßmus enum { 45128277c9SStephan Aßmus UNDEFINED, 46128277c9SStephan Aßmus 47128277c9SStephan Aßmus NEW_PATH, 48128277c9SStephan Aßmus 49128277c9SStephan Aßmus ADD_POINT, 50128277c9SStephan Aßmus INSERT_POINT, 51128277c9SStephan Aßmus MOVE_POINT, 52128277c9SStephan Aßmus MOVE_POINT_IN, 53128277c9SStephan Aßmus MOVE_POINT_OUT, 54128277c9SStephan Aßmus CLOSE_PATH, 55128277c9SStephan Aßmus 56128277c9SStephan Aßmus TOGGLE_SHARP, 57128277c9SStephan Aßmus TOGGLE_SHARP_IN, 58128277c9SStephan Aßmus TOGGLE_SHARP_OUT, 59128277c9SStephan Aßmus 60128277c9SStephan Aßmus REMOVE_POINT, 61128277c9SStephan Aßmus REMOVE_POINT_IN, 62128277c9SStephan Aßmus REMOVE_POINT_OUT, 63128277c9SStephan Aßmus 64128277c9SStephan Aßmus SELECT_POINTS, 65128277c9SStephan Aßmus TRANSFORM_POINTS, 66128277c9SStephan Aßmus TRANSLATE_POINTS, 67128277c9SStephan Aßmus 68128277c9SStephan Aßmus SELECT_SUB_PATH, 69128277c9SStephan Aßmus }; 70128277c9SStephan Aßmus 71f4bd80a2SStephan Aßmus enum { 72f4bd80a2SStephan Aßmus MSG_TRANSFORM = 'strn', 73f4bd80a2SStephan Aßmus MSG_REMOVE_POINTS = 'srmp', 74f4bd80a2SStephan Aßmus MSG_UPDATE_SHAPE_UI = 'udsi', 75f4bd80a2SStephan Aßmus 76f4bd80a2SStephan Aßmus MSG_SPLIT_POINTS = 'splt', 77f4bd80a2SStephan Aßmus }; 78f4bd80a2SStephan Aßmus 79128277c9SStephan Aßmus inline const char* 80128277c9SStephan Aßmus string_for_mode(uint32 mode) 81128277c9SStephan Aßmus { 82128277c9SStephan Aßmus switch (mode) { 83128277c9SStephan Aßmus case UNDEFINED: 84128277c9SStephan Aßmus return "UNDEFINED"; 85128277c9SStephan Aßmus case NEW_PATH: 86128277c9SStephan Aßmus return "NEW_PATH"; 87128277c9SStephan Aßmus case ADD_POINT: 88128277c9SStephan Aßmus return "ADD_POINT"; 89128277c9SStephan Aßmus case INSERT_POINT: 90128277c9SStephan Aßmus return "INSERT_POINT"; 91128277c9SStephan Aßmus case MOVE_POINT: 92128277c9SStephan Aßmus return "MOVE_POINT"; 93128277c9SStephan Aßmus case MOVE_POINT_IN: 94128277c9SStephan Aßmus return "MOVE_POINT_IN"; 95128277c9SStephan Aßmus case MOVE_POINT_OUT: 96128277c9SStephan Aßmus return "MOVE_POINT_OUT"; 97128277c9SStephan Aßmus case CLOSE_PATH: 98128277c9SStephan Aßmus return "CLOSE_PATH"; 99128277c9SStephan Aßmus case TOGGLE_SHARP: 100128277c9SStephan Aßmus return "TOGGLE_SHARP"; 101128277c9SStephan Aßmus case TOGGLE_SHARP_IN: 102128277c9SStephan Aßmus return "TOGGLE_SHARP_IN"; 103128277c9SStephan Aßmus case TOGGLE_SHARP_OUT: 104128277c9SStephan Aßmus return "TOGGLE_SHARP_OUT"; 105128277c9SStephan Aßmus case REMOVE_POINT: 106128277c9SStephan Aßmus return "REMOVE_POINT"; 107128277c9SStephan Aßmus case REMOVE_POINT_IN: 108128277c9SStephan Aßmus return "REMOVE_POINT_IN"; 109128277c9SStephan Aßmus case REMOVE_POINT_OUT: 110128277c9SStephan Aßmus return "REMOVE_POINT_OUT"; 111128277c9SStephan Aßmus case SELECT_POINTS: 112128277c9SStephan Aßmus return "SELECT_POINTS"; 113128277c9SStephan Aßmus case TRANSFORM_POINTS: 114128277c9SStephan Aßmus return "TRANSFORM_POINTS"; 115128277c9SStephan Aßmus case TRANSLATE_POINTS: 116128277c9SStephan Aßmus return "TRANSLATE_POINTS"; 117128277c9SStephan Aßmus case SELECT_SUB_PATH: 118128277c9SStephan Aßmus return "SELECT_SUB_PATH"; 119128277c9SStephan Aßmus } 120128277c9SStephan Aßmus return "<unknown mode>"; 121128277c9SStephan Aßmus } 122128277c9SStephan Aßmus 123ce181bb0SStephan Aßmus class PathManipulator::Selection : protected BList 124128277c9SStephan Aßmus { 125128277c9SStephan Aßmus public: 126128277c9SStephan Aßmus inline Selection(int32 count = 20) 127128277c9SStephan Aßmus : BList(count) {} 128128277c9SStephan Aßmus inline ~Selection() {} 129128277c9SStephan Aßmus 130128277c9SStephan Aßmus inline void Add(int32 value) 131128277c9SStephan Aßmus { 132128277c9SStephan Aßmus if (value >= 0) { 133128277c9SStephan Aßmus // keep the list sorted 134128277c9SStephan Aßmus int32 count = CountItems(); 135128277c9SStephan Aßmus int32 index = 0; 136128277c9SStephan Aßmus for (; index < count; index++) { 137128277c9SStephan Aßmus if (IndexAt(index) > value) { 138128277c9SStephan Aßmus break; 139128277c9SStephan Aßmus } 140128277c9SStephan Aßmus } 141128277c9SStephan Aßmus BList::AddItem((void*)value, index); 142128277c9SStephan Aßmus } 143128277c9SStephan Aßmus } 144128277c9SStephan Aßmus 145128277c9SStephan Aßmus inline bool Remove(int32 value) 146128277c9SStephan Aßmus { return BList::RemoveItem((void*)value); } 147128277c9SStephan Aßmus 148128277c9SStephan Aßmus inline bool Contains(int32 value) const 149128277c9SStephan Aßmus { return BList::HasItem((void*)value); } 150128277c9SStephan Aßmus 151128277c9SStephan Aßmus inline bool IsEmpty() const 152128277c9SStephan Aßmus { return BList::IsEmpty(); } 153128277c9SStephan Aßmus 154128277c9SStephan Aßmus inline int32 IndexAt(int32 index) const 155128277c9SStephan Aßmus { return (int32)BList::ItemAt(index); } 156128277c9SStephan Aßmus 157128277c9SStephan Aßmus inline void MakeEmpty() 158128277c9SStephan Aßmus { BList::MakeEmpty(); } 159128277c9SStephan Aßmus 160128277c9SStephan Aßmus inline int32* Items() const 161128277c9SStephan Aßmus { return (int32*)BList::Items(); } 162128277c9SStephan Aßmus 163128277c9SStephan Aßmus inline const int32 CountItems() const 164128277c9SStephan Aßmus { return BList::CountItems(); } 165128277c9SStephan Aßmus 166128277c9SStephan Aßmus inline Selection& operator =(const Selection& other) 167128277c9SStephan Aßmus { 168128277c9SStephan Aßmus MakeEmpty(); 169128277c9SStephan Aßmus int32 count = other.CountItems(); 170128277c9SStephan Aßmus int32* items = other.Items(); 171128277c9SStephan Aßmus for (int32 i = 0; i < count; i++) { 172128277c9SStephan Aßmus Add(items[i]); 173128277c9SStephan Aßmus } 174128277c9SStephan Aßmus return *this; 175128277c9SStephan Aßmus } 176128277c9SStephan Aßmus 177128277c9SStephan Aßmus inline bool operator ==(const Selection& other) 178128277c9SStephan Aßmus { 179128277c9SStephan Aßmus if (other.CountItems() == CountItems()) { 180128277c9SStephan Aßmus int32* items = Items(); 181128277c9SStephan Aßmus int32* otherItems = other.Items(); 182128277c9SStephan Aßmus for (int32 i = 0; i < CountItems(); i++) { 183128277c9SStephan Aßmus if (items[i] != otherItems[i]) 184128277c9SStephan Aßmus return false; 185128277c9SStephan Aßmus items++; 186128277c9SStephan Aßmus otherItems++; 187128277c9SStephan Aßmus } 188128277c9SStephan Aßmus return true; 189128277c9SStephan Aßmus } else 190128277c9SStephan Aßmus return false; 191128277c9SStephan Aßmus } 192128277c9SStephan Aßmus 193128277c9SStephan Aßmus inline bool operator !=(const Selection& other) 194128277c9SStephan Aßmus { 195128277c9SStephan Aßmus return !(*this == other); 196128277c9SStephan Aßmus } 197128277c9SStephan Aßmus }; 198128277c9SStephan Aßmus 199128277c9SStephan Aßmus 200128277c9SStephan Aßmus // constructor 201128277c9SStephan Aßmus PathManipulator::PathManipulator(VectorPath* path) 2020e1ba39fSStephan Aßmus : Manipulator(NULL), 203128277c9SStephan Aßmus fCanvasView(NULL), 204128277c9SStephan Aßmus 205128277c9SStephan Aßmus fCommandDown(false), 206128277c9SStephan Aßmus fOptionDown(false), 207128277c9SStephan Aßmus fShiftDown(false), 208128277c9SStephan Aßmus fAltDown(false), 209128277c9SStephan Aßmus 210128277c9SStephan Aßmus fClickToClose(false), 211128277c9SStephan Aßmus 212128277c9SStephan Aßmus fMode(NEW_PATH), 213128277c9SStephan Aßmus fFallBackMode(SELECT_POINTS), 214128277c9SStephan Aßmus 215128277c9SStephan Aßmus fMouseDown(false), 216128277c9SStephan Aßmus 217128277c9SStephan Aßmus fPath(path), 218128277c9SStephan Aßmus fCurrentPathPoint(-1), 219128277c9SStephan Aßmus 220128277c9SStephan Aßmus fChangePointCommand(NULL), 221128277c9SStephan Aßmus fInsertPointCommand(NULL), 222128277c9SStephan Aßmus fAddPointCommand(NULL), 223128277c9SStephan Aßmus 224128277c9SStephan Aßmus fSelection(new Selection()), 225128277c9SStephan Aßmus fOldSelection(new Selection()), 2260e1ba39fSStephan Aßmus fTransformBox(NULL), 227128277c9SStephan Aßmus 228128277c9SStephan Aßmus fNudgeOffset(0.0, 0.0), 2290e1ba39fSStephan Aßmus fLastNudgeTime(system_time()), 2300e1ba39fSStephan Aßmus fNudgeCommand(NULL) 231128277c9SStephan Aßmus { 2320e1ba39fSStephan Aßmus fPath->Acquire(); 23305fd3818SStephan Aßmus fPath->AddListener(this); 2340e1ba39fSStephan Aßmus fPath->AddObserver(this); 235128277c9SStephan Aßmus } 236128277c9SStephan Aßmus 237128277c9SStephan Aßmus // destructor 238128277c9SStephan Aßmus PathManipulator::~PathManipulator() 239128277c9SStephan Aßmus { 240128277c9SStephan Aßmus delete fChangePointCommand; 241128277c9SStephan Aßmus delete fInsertPointCommand; 242128277c9SStephan Aßmus delete fAddPointCommand; 243128277c9SStephan Aßmus 244128277c9SStephan Aßmus delete fSelection; 245128277c9SStephan Aßmus delete fOldSelection; 2460e1ba39fSStephan Aßmus delete fTransformBox; 247128277c9SStephan Aßmus 2480e1ba39fSStephan Aßmus delete fNudgeCommand; 2490e1ba39fSStephan Aßmus 2500e1ba39fSStephan Aßmus fPath->RemoveObserver(this); 2510e1ba39fSStephan Aßmus fPath->RemoveListener(this); 2520e1ba39fSStephan Aßmus fPath->Release(); 253128277c9SStephan Aßmus } 254128277c9SStephan Aßmus 255128277c9SStephan Aßmus 256128277c9SStephan Aßmus // #pragma mark - 257128277c9SStephan Aßmus 258128277c9SStephan Aßmus class StrokePathIterator : public VectorPath::Iterator { 259128277c9SStephan Aßmus public: 260f67876a0SStephan Aßmus StrokePathIterator(CanvasView* canvasView, 261f67876a0SStephan Aßmus BView* drawingView) 262f67876a0SStephan Aßmus : fCanvasView(canvasView), 263f67876a0SStephan Aßmus fDrawingView(drawingView) 264128277c9SStephan Aßmus { 265128277c9SStephan Aßmus fDrawingView->SetHighColor(0, 0, 0, 255); 266128277c9SStephan Aßmus fDrawingView->SetDrawingMode(B_OP_OVER); 267128277c9SStephan Aßmus } 268128277c9SStephan Aßmus virtual ~StrokePathIterator() 269128277c9SStephan Aßmus {} 270128277c9SStephan Aßmus 271128277c9SStephan Aßmus virtual void MoveTo(BPoint point) 272128277c9SStephan Aßmus { 273128277c9SStephan Aßmus fBlack = true; 274f67876a0SStephan Aßmus fSkip = false; 275128277c9SStephan Aßmus fDrawingView->SetHighColor(0, 0, 0, 255); 276128277c9SStephan Aßmus 277f67876a0SStephan Aßmus fCanvasView->ConvertFromCanvas(&point); 278128277c9SStephan Aßmus fDrawingView->MovePenTo(point); 279128277c9SStephan Aßmus } 280128277c9SStephan Aßmus virtual void LineTo(BPoint point) 281128277c9SStephan Aßmus { 282f67876a0SStephan Aßmus fCanvasView->ConvertFromCanvas(&point); 283f67876a0SStephan Aßmus if (!fSkip) { 284128277c9SStephan Aßmus if (fBlack) 285128277c9SStephan Aßmus fDrawingView->SetHighColor(255, 255, 255, 255); 286128277c9SStephan Aßmus else 287128277c9SStephan Aßmus fDrawingView->SetHighColor(0, 0, 0, 255); 288128277c9SStephan Aßmus fBlack = !fBlack; 289128277c9SStephan Aßmus 290128277c9SStephan Aßmus fDrawingView->StrokeLine(point); 291f67876a0SStephan Aßmus } else { 292f67876a0SStephan Aßmus fDrawingView->MovePenTo(point); 293f67876a0SStephan Aßmus } 294f67876a0SStephan Aßmus fSkip = !fSkip; 295128277c9SStephan Aßmus } 296128277c9SStephan Aßmus 297128277c9SStephan Aßmus private: 298f67876a0SStephan Aßmus CanvasView* fCanvasView; 299128277c9SStephan Aßmus BView* fDrawingView; 300128277c9SStephan Aßmus bool fBlack; 301f67876a0SStephan Aßmus bool fSkip; 302128277c9SStephan Aßmus }; 303128277c9SStephan Aßmus 304128277c9SStephan Aßmus // Draw 305128277c9SStephan Aßmus void 306128277c9SStephan Aßmus PathManipulator::Draw(BView* into, BRect updateRect) 307128277c9SStephan Aßmus { 308128277c9SStephan Aßmus // draw the Bezier curve, but only if editing 309128277c9SStephan Aßmus // if not "editing", the path is actually on top all other modifiers 310128277c9SStephan Aßmus // TODO: make this customizable in the GUI 311f67876a0SStephan Aßmus StrokePathIterator iterator(fCanvasView, into); 312f67876a0SStephan Aßmus fPath->Iterate(&iterator, fCanvasView->ZoomLevel()); 313128277c9SStephan Aßmus 314128277c9SStephan Aßmus into->SetLowColor(0, 0, 0, 255); 315128277c9SStephan Aßmus BPoint point; 316128277c9SStephan Aßmus BPoint pointIn; 317128277c9SStephan Aßmus BPoint pointOut; 318128277c9SStephan Aßmus rgb_color focusColor = (rgb_color){ 255, 0, 0, 255 }; 319128277c9SStephan Aßmus rgb_color highlightColor = (rgb_color){ 60, 60, 255, 255 }; 320128277c9SStephan Aßmus for (int32 i = 0; fPath->GetPointsAt(i, point, pointIn, pointOut); i++) { 321128277c9SStephan Aßmus bool highlight = fCurrentPathPoint == i; 322128277c9SStephan Aßmus bool selected = fSelection->Contains(i); 323128277c9SStephan Aßmus rgb_color normal = selected ? focusColor : (rgb_color){ 0, 0, 0, 255 }; 324128277c9SStephan Aßmus into->SetLowColor(normal); 325128277c9SStephan Aßmus into->SetHighColor(255, 255, 255, 255); 326128277c9SStephan Aßmus // convert to view coordinate space 327f67876a0SStephan Aßmus fCanvasView->ConvertFromCanvas(&point); 328f67876a0SStephan Aßmus fCanvasView->ConvertFromCanvas(&pointIn); 329f67876a0SStephan Aßmus fCanvasView->ConvertFromCanvas(&pointOut); 330128277c9SStephan Aßmus // connect the points belonging to one control point 331128277c9SStephan Aßmus into->SetDrawingMode(B_OP_INVERT); 332128277c9SStephan Aßmus into->StrokeLine(point, pointIn); 333128277c9SStephan Aßmus into->StrokeLine(point, pointOut); 334128277c9SStephan Aßmus // draw main control point 335128277c9SStephan Aßmus if (highlight && (fMode == MOVE_POINT || 336128277c9SStephan Aßmus fMode == TOGGLE_SHARP || 337128277c9SStephan Aßmus fMode == REMOVE_POINT || 338128277c9SStephan Aßmus fMode == SELECT_POINTS || 339128277c9SStephan Aßmus fMode == CLOSE_PATH)) { 340128277c9SStephan Aßmus 341128277c9SStephan Aßmus into->SetLowColor(highlightColor); 342128277c9SStephan Aßmus } 343128277c9SStephan Aßmus 344128277c9SStephan Aßmus into->SetDrawingMode(B_OP_COPY); 345128277c9SStephan Aßmus BRect r(point, point); 346128277c9SStephan Aßmus r.InsetBy(-POINT_EXTEND, -POINT_EXTEND); 347128277c9SStephan Aßmus into->StrokeRect(r, B_SOLID_LOW); 348128277c9SStephan Aßmus r.InsetBy(1.0, 1.0); 349128277c9SStephan Aßmus into->FillRect(r, B_SOLID_HIGH); 350128277c9SStephan Aßmus // draw in control point 351128277c9SStephan Aßmus if (highlight && (fMode == MOVE_POINT_IN || 352128277c9SStephan Aßmus fMode == TOGGLE_SHARP_IN || 353128277c9SStephan Aßmus fMode == REMOVE_POINT_IN || 354128277c9SStephan Aßmus fMode == SELECT_POINTS)) 355128277c9SStephan Aßmus into->SetLowColor(highlightColor); 356128277c9SStephan Aßmus else 357128277c9SStephan Aßmus into->SetLowColor(normal); 358128277c9SStephan Aßmus if (selected) { 359128277c9SStephan Aßmus into->SetHighColor(220, 220, 220, 255); 360128277c9SStephan Aßmus } else { 361128277c9SStephan Aßmus into->SetHighColor(170, 170, 170, 255); 362128277c9SStephan Aßmus } 363128277c9SStephan Aßmus if (pointIn != point) { 364128277c9SStephan Aßmus r.Set(pointIn.x - CONTROL_POINT_EXTEND, pointIn.y - CONTROL_POINT_EXTEND, 365128277c9SStephan Aßmus pointIn.x + CONTROL_POINT_EXTEND, pointIn.y + CONTROL_POINT_EXTEND); 366128277c9SStephan Aßmus into->StrokeRect(r, B_SOLID_LOW); 367128277c9SStephan Aßmus r.InsetBy(1.0, 1.0); 368128277c9SStephan Aßmus into->FillRect(r, B_SOLID_HIGH); 369128277c9SStephan Aßmus } 370128277c9SStephan Aßmus // draw out control point 371128277c9SStephan Aßmus if (highlight && (fMode == MOVE_POINT_OUT || 372128277c9SStephan Aßmus fMode == TOGGLE_SHARP_OUT || 373128277c9SStephan Aßmus fMode == REMOVE_POINT_OUT || 374128277c9SStephan Aßmus fMode == SELECT_POINTS)) 375128277c9SStephan Aßmus into->SetLowColor(highlightColor); 376128277c9SStephan Aßmus else 377128277c9SStephan Aßmus into->SetLowColor(normal); 378128277c9SStephan Aßmus if (pointOut != point) { 379128277c9SStephan Aßmus r.Set(pointOut.x - CONTROL_POINT_EXTEND, pointOut.y - CONTROL_POINT_EXTEND, 380128277c9SStephan Aßmus pointOut.x + CONTROL_POINT_EXTEND, pointOut.y + CONTROL_POINT_EXTEND); 381128277c9SStephan Aßmus into->StrokeRect(r, B_SOLID_LOW); 382128277c9SStephan Aßmus r.InsetBy(1.0, 1.0); 383128277c9SStephan Aßmus into->FillRect(r, B_SOLID_HIGH); 384128277c9SStephan Aßmus } 385128277c9SStephan Aßmus } 3860e1ba39fSStephan Aßmus 3870e1ba39fSStephan Aßmus if (fTransformBox) { 3880e1ba39fSStephan Aßmus fTransformBox->Draw(into, updateRect); 3890e1ba39fSStephan Aßmus } 390128277c9SStephan Aßmus } 391128277c9SStephan Aßmus 392128277c9SStephan Aßmus // #pragma mark - 393128277c9SStephan Aßmus 394128277c9SStephan Aßmus // MouseDown 395128277c9SStephan Aßmus bool 396128277c9SStephan Aßmus PathManipulator::MouseDown(BPoint where) 397128277c9SStephan Aßmus { 398128277c9SStephan Aßmus fMouseDown = true; 399128277c9SStephan Aßmus 4000e1ba39fSStephan Aßmus if (fMode == TRANSFORM_POINTS) { 4010e1ba39fSStephan Aßmus if (fTransformBox) { 4020e1ba39fSStephan Aßmus fTransformBox->MouseDown(where); 4030e1ba39fSStephan Aßmus 4040e1ba39fSStephan Aßmus // if (!fTransformBox->IsRotating()) 4050e1ba39fSStephan Aßmus // fCanvasView->SetAutoScrolling(true); 4060e1ba39fSStephan Aßmus } 4070e1ba39fSStephan Aßmus return true; 4080e1ba39fSStephan Aßmus } 4090e1ba39fSStephan Aßmus 410128277c9SStephan Aßmus if (fMode == MOVE_POINT && 411128277c9SStephan Aßmus fSelection->CountItems() > 1 && 412128277c9SStephan Aßmus fSelection->Contains(fCurrentPathPoint)) { 413128277c9SStephan Aßmus fMode = TRANSLATE_POINTS; 414128277c9SStephan Aßmus } 415128277c9SStephan Aßmus 416*4fac07a0SStephan Aßmus // apply the canvas view mouse filter depending on current mode 417*4fac07a0SStephan Aßmus if (fMode == ADD_POINT || fMode == TRANSLATE_POINTS) 418*4fac07a0SStephan Aßmus fCanvasView->FilterMouse(&where); 419*4fac07a0SStephan Aßmus 420128277c9SStephan Aßmus BPoint canvasWhere = where; 421f67876a0SStephan Aßmus fCanvasView->ConvertToCanvas(&canvasWhere); 422128277c9SStephan Aßmus 423128277c9SStephan Aßmus // maybe we're changing some point, so we construct the 424128277c9SStephan Aßmus // "ChangePointCommand" here so that the point is remembered 425128277c9SStephan Aßmus // in its current state 426*4fac07a0SStephan Aßmus // apply the canvas view mouse filter depending on current mode 427128277c9SStephan Aßmus delete fChangePointCommand; 428128277c9SStephan Aßmus fChangePointCommand = NULL; 429128277c9SStephan Aßmus switch (fMode) { 430128277c9SStephan Aßmus case TOGGLE_SHARP: 431128277c9SStephan Aßmus case TOGGLE_SHARP_IN: 432128277c9SStephan Aßmus case TOGGLE_SHARP_OUT: 433128277c9SStephan Aßmus case MOVE_POINT: 434128277c9SStephan Aßmus case MOVE_POINT_IN: 435128277c9SStephan Aßmus case MOVE_POINT_OUT: 436128277c9SStephan Aßmus case REMOVE_POINT_IN: 437128277c9SStephan Aßmus case REMOVE_POINT_OUT: 438128277c9SStephan Aßmus fChangePointCommand = new ChangePointCommand(fPath, 439128277c9SStephan Aßmus fCurrentPathPoint, 440128277c9SStephan Aßmus fSelection->Items(), 441128277c9SStephan Aßmus fSelection->CountItems()); 442128277c9SStephan Aßmus _Select(fCurrentPathPoint, fShiftDown); 443128277c9SStephan Aßmus break; 444128277c9SStephan Aßmus } 445128277c9SStephan Aßmus 446128277c9SStephan Aßmus // at this point we init doing something 447128277c9SStephan Aßmus switch (fMode) { 448128277c9SStephan Aßmus case ADD_POINT: 449128277c9SStephan Aßmus _AddPoint(canvasWhere); 450128277c9SStephan Aßmus break; 451128277c9SStephan Aßmus case INSERT_POINT: 452128277c9SStephan Aßmus _InsertPoint(canvasWhere, fCurrentPathPoint); 453128277c9SStephan Aßmus break; 454128277c9SStephan Aßmus 455128277c9SStephan Aßmus case TOGGLE_SHARP: 456128277c9SStephan Aßmus _SetSharp(fCurrentPathPoint); 457128277c9SStephan Aßmus // continue by dragging out the _connected_ in/out points 458128277c9SStephan Aßmus break; 459128277c9SStephan Aßmus case TOGGLE_SHARP_IN: 460128277c9SStephan Aßmus _SetInOutConnected(fCurrentPathPoint, false); 461128277c9SStephan Aßmus // continue by moving the "in" point 462128277c9SStephan Aßmus _SetMode(MOVE_POINT_IN); 463128277c9SStephan Aßmus break; 464128277c9SStephan Aßmus case TOGGLE_SHARP_OUT: 465128277c9SStephan Aßmus _SetInOutConnected(fCurrentPathPoint, false); 466128277c9SStephan Aßmus // continue by moving the "out" point 467128277c9SStephan Aßmus _SetMode(MOVE_POINT_OUT); 468128277c9SStephan Aßmus break; 469128277c9SStephan Aßmus 470128277c9SStephan Aßmus case MOVE_POINT: 471128277c9SStephan Aßmus case MOVE_POINT_IN: 472128277c9SStephan Aßmus case MOVE_POINT_OUT: 473128277c9SStephan Aßmus // the right thing happens since "fCurrentPathPoint" 474128277c9SStephan Aßmus // points to the correct index 475128277c9SStephan Aßmus break; 476128277c9SStephan Aßmus 477128277c9SStephan Aßmus case CLOSE_PATH: 478128277c9SStephan Aßmus // SetClosed(true, true); 479128277c9SStephan Aßmus break; 480128277c9SStephan Aßmus 481128277c9SStephan Aßmus case REMOVE_POINT: 482128277c9SStephan Aßmus if (fPath->CountPoints() == 1) { 483128277c9SStephan Aßmus // fCanvasView->Perform(new RemovePathCommand(this, fPath)); 484128277c9SStephan Aßmus } else { 485128277c9SStephan Aßmus fCanvasView->Perform(new RemovePointsCommand(fPath, 486128277c9SStephan Aßmus fCurrentPathPoint, 487128277c9SStephan Aßmus fSelection->Items(), 488128277c9SStephan Aßmus fSelection->CountItems())); 489128277c9SStephan Aßmus _RemovePoint(fCurrentPathPoint); 490128277c9SStephan Aßmus } 491128277c9SStephan Aßmus break; 492128277c9SStephan Aßmus case REMOVE_POINT_IN: 493128277c9SStephan Aßmus _RemovePointIn(fCurrentPathPoint); 494128277c9SStephan Aßmus break; 495128277c9SStephan Aßmus case REMOVE_POINT_OUT: 496128277c9SStephan Aßmus _RemovePointOut(fCurrentPathPoint); 497128277c9SStephan Aßmus break; 498128277c9SStephan Aßmus 499f4bd80a2SStephan Aßmus case SELECT_POINTS: { 500f4bd80a2SStephan Aßmus // TODO: this works so that you can deselect all points 501f4bd80a2SStephan Aßmus // when clicking outside the path even if pressing shift 502f4bd80a2SStephan Aßmus // in case the path is open... a better way would be 503f4bd80a2SStephan Aßmus // to deselect all on mouse up, if the mouse has not moved 504f4bd80a2SStephan Aßmus bool appendSelection; 505f4bd80a2SStephan Aßmus if (fPath->IsClosed()) 506f4bd80a2SStephan Aßmus appendSelection = fShiftDown; 507f4bd80a2SStephan Aßmus else 508f4bd80a2SStephan Aßmus appendSelection = fShiftDown && fCurrentPathPoint >= 0; 509f4bd80a2SStephan Aßmus 510f4bd80a2SStephan Aßmus if (!appendSelection) { 511128277c9SStephan Aßmus fSelection->MakeEmpty(); 512128277c9SStephan Aßmus _UpdateSelection(); 513128277c9SStephan Aßmus } 514128277c9SStephan Aßmus *fOldSelection = *fSelection; 515128277c9SStephan Aßmus if (fCurrentPathPoint >= 0) { 516f4bd80a2SStephan Aßmus _Select(fCurrentPathPoint, appendSelection); 517128277c9SStephan Aßmus } 518128277c9SStephan Aßmus fCanvasView->BeginRectTracking(BRect(where, where), 519128277c9SStephan Aßmus B_TRACK_RECT_CORNER); 520128277c9SStephan Aßmus break; 521128277c9SStephan Aßmus } 522f4bd80a2SStephan Aßmus } 523128277c9SStephan Aßmus 524128277c9SStephan Aßmus fTrackingStart = canvasWhere; 525128277c9SStephan Aßmus // remember the subpixel position 526128277c9SStephan Aßmus // so that MouseMoved() will work even before 527128277c9SStephan Aßmus // the integer position becomes different 528128277c9SStephan Aßmus fLastCanvasPos = where; 529f67876a0SStephan Aßmus fCanvasView->ConvertToCanvas(&fLastCanvasPos); 530128277c9SStephan Aßmus 531128277c9SStephan Aßmus // the reason to exclude the select mode 532128277c9SStephan Aßmus // is that the BView rect tracking does not 533128277c9SStephan Aßmus // scroll the rect starting point along with us 534128277c9SStephan Aßmus // (since we're doing no real scrolling) 535128277c9SStephan Aßmus // if (fMode != SELECT_POINTS) 536128277c9SStephan Aßmus // fCanvasView->SetAutoScrolling(true); 537128277c9SStephan Aßmus 538128277c9SStephan Aßmus UpdateCursor(); 539128277c9SStephan Aßmus 540128277c9SStephan Aßmus return true; 541128277c9SStephan Aßmus } 542128277c9SStephan Aßmus 543128277c9SStephan Aßmus // MouseMoved 544128277c9SStephan Aßmus void 545128277c9SStephan Aßmus PathManipulator::MouseMoved(BPoint where) 546128277c9SStephan Aßmus { 547*4fac07a0SStephan Aßmus fCanvasView->FilterMouse(&where); 548*4fac07a0SStephan Aßmus // NOTE: only filter mouse coords in mouse moved, no other 549*4fac07a0SStephan Aßmus // mouse function 550128277c9SStephan Aßmus BPoint canvasWhere = where; 551f67876a0SStephan Aßmus fCanvasView->ConvertToCanvas(&canvasWhere); 552128277c9SStephan Aßmus 553128277c9SStephan Aßmus // since the tablet is generating mouse moved messages 554128277c9SStephan Aßmus // even if only the pressure changes (and not the actual mouse position) 555128277c9SStephan Aßmus // we insert this additional check to prevent too much calculation 556128277c9SStephan Aßmus if (fLastCanvasPos == canvasWhere) 557128277c9SStephan Aßmus return; 558128277c9SStephan Aßmus 559128277c9SStephan Aßmus fLastCanvasPos = canvasWhere; 560128277c9SStephan Aßmus 5610e1ba39fSStephan Aßmus if (fMode == TRANSFORM_POINTS) { 5620e1ba39fSStephan Aßmus if (fTransformBox) { 5630e1ba39fSStephan Aßmus fTransformBox->MouseMoved(where); 5640e1ba39fSStephan Aßmus } 5650e1ba39fSStephan Aßmus return; 5660e1ba39fSStephan Aßmus } 5670e1ba39fSStephan Aßmus 568128277c9SStephan Aßmus if (fMode == CLOSE_PATH) { 569128277c9SStephan Aßmus // continue by moving the point 570128277c9SStephan Aßmus _SetMode(MOVE_POINT); 571128277c9SStephan Aßmus delete fChangePointCommand; 572128277c9SStephan Aßmus fChangePointCommand = new ChangePointCommand(fPath, 573128277c9SStephan Aßmus fCurrentPathPoint, 574128277c9SStephan Aßmus fSelection->Items(), 575128277c9SStephan Aßmus fSelection->CountItems()); 576128277c9SStephan Aßmus } 577128277c9SStephan Aßmus 578128277c9SStephan Aßmus // if (!fPrecise) { 579128277c9SStephan Aßmus // float offset = fmod(fOutlineWidth, 2.0) / 2.0; 580128277c9SStephan Aßmus // canvasWhere.point += BPoint(offset, offset); 581128277c9SStephan Aßmus // } 582128277c9SStephan Aßmus 583128277c9SStephan Aßmus switch (fMode) { 584128277c9SStephan Aßmus case ADD_POINT: 585128277c9SStephan Aßmus case INSERT_POINT: 586128277c9SStephan Aßmus case TOGGLE_SHARP: 587128277c9SStephan Aßmus // drag the "out" control point, mirror the "in" control point 588128277c9SStephan Aßmus fPath->SetPointOut(fCurrentPathPoint, canvasWhere, true); 589128277c9SStephan Aßmus break; 590128277c9SStephan Aßmus case MOVE_POINT: 591128277c9SStephan Aßmus // drag all three control points at once 592128277c9SStephan Aßmus fPath->SetPoint(fCurrentPathPoint, canvasWhere); 593128277c9SStephan Aßmus break; 594128277c9SStephan Aßmus case MOVE_POINT_IN: 595128277c9SStephan Aßmus // drag in control point 596128277c9SStephan Aßmus fPath->SetPointIn(fCurrentPathPoint, canvasWhere); 597128277c9SStephan Aßmus break; 598128277c9SStephan Aßmus case MOVE_POINT_OUT: 599128277c9SStephan Aßmus // drag out control point 600128277c9SStephan Aßmus fPath->SetPointOut(fCurrentPathPoint, canvasWhere); 601128277c9SStephan Aßmus break; 602128277c9SStephan Aßmus 603128277c9SStephan Aßmus case SELECT_POINTS: { 604128277c9SStephan Aßmus // change the selection 605128277c9SStephan Aßmus BRect r; 606128277c9SStephan Aßmus r.left = min_c(fTrackingStart.x, canvasWhere.x); 607128277c9SStephan Aßmus r.top = min_c(fTrackingStart.y, canvasWhere.y); 608128277c9SStephan Aßmus r.right = max_c(fTrackingStart.x, canvasWhere.x); 609128277c9SStephan Aßmus r.bottom = max_c(fTrackingStart.y, canvasWhere.y); 610128277c9SStephan Aßmus _Select(r); 611128277c9SStephan Aßmus break; 612128277c9SStephan Aßmus } 613128277c9SStephan Aßmus 614128277c9SStephan Aßmus case TRANSLATE_POINTS: { 615128277c9SStephan Aßmus BPoint offset = canvasWhere - fTrackingStart; 616128277c9SStephan Aßmus _Nudge(offset); 617128277c9SStephan Aßmus fTrackingStart = canvasWhere; 618128277c9SStephan Aßmus break; 619128277c9SStephan Aßmus } 620128277c9SStephan Aßmus } 621128277c9SStephan Aßmus } 622128277c9SStephan Aßmus 623128277c9SStephan Aßmus // MouseUp 624128277c9SStephan Aßmus Command* 625128277c9SStephan Aßmus PathManipulator::MouseUp() 626128277c9SStephan Aßmus { 627128277c9SStephan Aßmus // prevent carrying out actions more than once by only 628128277c9SStephan Aßmus // doing it if "fMouseDown" is true at the point of 629128277c9SStephan Aßmus // entering this function 630128277c9SStephan Aßmus if (!fMouseDown) 631128277c9SStephan Aßmus return NULL; 632128277c9SStephan Aßmus fMouseDown = false; 633128277c9SStephan Aßmus 6340e1ba39fSStephan Aßmus if (fMode == TRANSFORM_POINTS) { 6350e1ba39fSStephan Aßmus if (fTransformBox) { 6360e1ba39fSStephan Aßmus return fTransformBox->MouseUp(); 6370e1ba39fSStephan Aßmus } 6380e1ba39fSStephan Aßmus return NULL; 6390e1ba39fSStephan Aßmus } 6400e1ba39fSStephan Aßmus 641128277c9SStephan Aßmus Command* command = NULL; 642128277c9SStephan Aßmus 643128277c9SStephan Aßmus switch (fMode) { 644128277c9SStephan Aßmus 645128277c9SStephan Aßmus case ADD_POINT: 646128277c9SStephan Aßmus command = fAddPointCommand; 647128277c9SStephan Aßmus fAddPointCommand = NULL; 648128277c9SStephan Aßmus _SetMode(MOVE_POINT_OUT); 649128277c9SStephan Aßmus break; 650128277c9SStephan Aßmus 651128277c9SStephan Aßmus case INSERT_POINT: 652128277c9SStephan Aßmus command = fInsertPointCommand; 653128277c9SStephan Aßmus fInsertPointCommand = NULL; 654128277c9SStephan Aßmus break; 655128277c9SStephan Aßmus 656128277c9SStephan Aßmus case SELECT_POINTS: 657128277c9SStephan Aßmus if (*fSelection != *fOldSelection) { 658128277c9SStephan Aßmus // command = new SelectPointsCommand(this, fPath, 659128277c9SStephan Aßmus // fOldSelection->Items(), 660128277c9SStephan Aßmus // fOldSelection->CountItems(), 661128277c9SStephan Aßmus // fSelection->Items(), 662128277c9SStephan Aßmus // fSelection->CountItems())); 663128277c9SStephan Aßmus } 664128277c9SStephan Aßmus fCanvasView->EndRectTracking(); 665128277c9SStephan Aßmus break; 666128277c9SStephan Aßmus 667128277c9SStephan Aßmus case TOGGLE_SHARP: 668128277c9SStephan Aßmus case TOGGLE_SHARP_IN: 669128277c9SStephan Aßmus case TOGGLE_SHARP_OUT: 670128277c9SStephan Aßmus case MOVE_POINT: 671128277c9SStephan Aßmus case MOVE_POINT_IN: 672128277c9SStephan Aßmus case MOVE_POINT_OUT: 673128277c9SStephan Aßmus case REMOVE_POINT_IN: 674128277c9SStephan Aßmus case REMOVE_POINT_OUT: 675128277c9SStephan Aßmus command = fChangePointCommand; 676128277c9SStephan Aßmus fChangePointCommand = NULL; 677128277c9SStephan Aßmus break; 678128277c9SStephan Aßmus 679128277c9SStephan Aßmus case TRANSLATE_POINTS: 6800e1ba39fSStephan Aßmus if (!fNudgeCommand) { 681128277c9SStephan Aßmus // select just the point that was clicked 682128277c9SStephan Aßmus *fOldSelection = *fSelection; 683128277c9SStephan Aßmus if (fCurrentPathPoint >= 0) { 684128277c9SStephan Aßmus _Select(fCurrentPathPoint, fShiftDown); 685128277c9SStephan Aßmus } 686128277c9SStephan Aßmus if (*fSelection != *fOldSelection) { 687128277c9SStephan Aßmus // command = new SelectPointsCommand(this, fPath, 688128277c9SStephan Aßmus // fOldSelection->Items(), 689128277c9SStephan Aßmus // fOldSelection->CountItems(), 690128277c9SStephan Aßmus // fSelection->Items(), 691128277c9SStephan Aßmus // fSelection->CountItems())); 692128277c9SStephan Aßmus } 6930e1ba39fSStephan Aßmus } else { 6940e1ba39fSStephan Aßmus command = _FinishNudging(); 6950e1ba39fSStephan Aßmus } 696128277c9SStephan Aßmus break; 697128277c9SStephan Aßmus } 698128277c9SStephan Aßmus 699128277c9SStephan Aßmus return command; 700128277c9SStephan Aßmus } 701128277c9SStephan Aßmus 702128277c9SStephan Aßmus // MouseOver 703128277c9SStephan Aßmus bool 704128277c9SStephan Aßmus PathManipulator::MouseOver(BPoint where) 705128277c9SStephan Aßmus { 7060e1ba39fSStephan Aßmus if (fMode == TRANSFORM_POINTS) { 7070e1ba39fSStephan Aßmus if (fTransformBox) { 7080e1ba39fSStephan Aßmus return fTransformBox->MouseOver(where); 7090e1ba39fSStephan Aßmus } 7100e1ba39fSStephan Aßmus return false; 7110e1ba39fSStephan Aßmus } 7120e1ba39fSStephan Aßmus 713128277c9SStephan Aßmus BPoint canvasWhere = where; 714f67876a0SStephan Aßmus fCanvasView->ConvertToCanvas(&canvasWhere); 715128277c9SStephan Aßmus 716128277c9SStephan Aßmus // since the tablet is generating mouse moved messages 717128277c9SStephan Aßmus // even if only the pressure changes (and not the actual mouse position) 718128277c9SStephan Aßmus // we insert this additional check to prevent too much calculation 719128277c9SStephan Aßmus if (fMouseDown && fLastCanvasPos == canvasWhere) 720128277c9SStephan Aßmus return false; 721128277c9SStephan Aßmus 722128277c9SStephan Aßmus fLastCanvasPos = canvasWhere; 723128277c9SStephan Aßmus 724128277c9SStephan Aßmus // hit testing 725128277c9SStephan Aßmus // (use a subpixel mouse pos) 726f67876a0SStephan Aßmus fCanvasView->ConvertToCanvas(&where); 727128277c9SStephan Aßmus _SetModeForMousePos(where); 728128277c9SStephan Aßmus 729128277c9SStephan Aßmus // TODO: always true? 730128277c9SStephan Aßmus return true; 731128277c9SStephan Aßmus } 732128277c9SStephan Aßmus 733128277c9SStephan Aßmus // DoubleClicked 734128277c9SStephan Aßmus bool 735128277c9SStephan Aßmus PathManipulator::DoubleClicked(BPoint where) 736128277c9SStephan Aßmus { 737128277c9SStephan Aßmus return false; 738128277c9SStephan Aßmus } 739128277c9SStephan Aßmus 740f4bd80a2SStephan Aßmus // ShowContextMenu 741f4bd80a2SStephan Aßmus bool 742f4bd80a2SStephan Aßmus PathManipulator::ShowContextMenu(BPoint where) 743f4bd80a2SStephan Aßmus { 744f4bd80a2SStephan Aßmus BPopUpMenu* menu = new BPopUpMenu("context menu", false, false); 745f4bd80a2SStephan Aßmus BMessage* message; 746f4bd80a2SStephan Aßmus BMenuItem* item; 747f4bd80a2SStephan Aßmus 748f4bd80a2SStephan Aßmus bool hasSelection = fSelection->CountItems() > 0; 749f4bd80a2SStephan Aßmus 750f4bd80a2SStephan Aßmus message = new BMessage(B_SELECT_ALL); 751f4bd80a2SStephan Aßmus item = new BMenuItem("Select All", message, 'A'); 752f4bd80a2SStephan Aßmus menu->AddItem(item); 753f4bd80a2SStephan Aßmus 754f4bd80a2SStephan Aßmus menu->AddSeparatorItem(); 755f4bd80a2SStephan Aßmus 756f4bd80a2SStephan Aßmus message = new BMessage(MSG_TRANSFORM); 757f4bd80a2SStephan Aßmus item = new BMenuItem("Transform", message); 758f4bd80a2SStephan Aßmus item->SetEnabled(hasSelection); 759f4bd80a2SStephan Aßmus menu->AddItem(item); 760f4bd80a2SStephan Aßmus 761f4bd80a2SStephan Aßmus message = new BMessage(MSG_SPLIT_POINTS); 762f4bd80a2SStephan Aßmus item = new BMenuItem("Split", message); 763f4bd80a2SStephan Aßmus item->SetEnabled(hasSelection); 764f4bd80a2SStephan Aßmus menu->AddItem(item); 765f4bd80a2SStephan Aßmus 766f4bd80a2SStephan Aßmus message = new BMessage(MSG_REMOVE_POINTS); 767f4bd80a2SStephan Aßmus item = new BMenuItem("Remove", message, 'A'); 768f4bd80a2SStephan Aßmus item->SetEnabled(hasSelection); 769f4bd80a2SStephan Aßmus menu->AddItem(item); 770f4bd80a2SStephan Aßmus 771f4bd80a2SStephan Aßmus // go 772f4bd80a2SStephan Aßmus menu->SetTargetForItems(fCanvasView); 773f4bd80a2SStephan Aßmus menu->SetAsyncAutoDestruct(true); 774f4bd80a2SStephan Aßmus menu->SetFont(be_plain_font); 775f4bd80a2SStephan Aßmus where = fCanvasView->ConvertToScreen(where); 776f4bd80a2SStephan Aßmus BRect mouseRect(where, where); 777f4bd80a2SStephan Aßmus mouseRect.InsetBy(-10.0, -10.0); 778f4bd80a2SStephan Aßmus where += BPoint(5.0, 5.0); 779f4bd80a2SStephan Aßmus menu->Go(where, true, false, mouseRect, true); 780f4bd80a2SStephan Aßmus 781f4bd80a2SStephan Aßmus return true; 782f4bd80a2SStephan Aßmus } 783f4bd80a2SStephan Aßmus 784f4bd80a2SStephan Aßmus // #pragma mark - 785f4bd80a2SStephan Aßmus 786128277c9SStephan Aßmus // Bounds 787128277c9SStephan Aßmus BRect 788128277c9SStephan Aßmus PathManipulator::Bounds() 789128277c9SStephan Aßmus { 790f67876a0SStephan Aßmus BRect r = _ControlPointRect(); 791f67876a0SStephan Aßmus fCanvasView->ConvertFromCanvas(&r); 792f67876a0SStephan Aßmus return r; 793128277c9SStephan Aßmus } 794128277c9SStephan Aßmus 795128277c9SStephan Aßmus // TrackingBounds 796128277c9SStephan Aßmus BRect 797128277c9SStephan Aßmus PathManipulator::TrackingBounds(BView* withinView) 798128277c9SStephan Aßmus { 799128277c9SStephan Aßmus return withinView->Bounds(); 800128277c9SStephan Aßmus } 801128277c9SStephan Aßmus 802128277c9SStephan Aßmus // #pragma mark - 803128277c9SStephan Aßmus 804128277c9SStephan Aßmus // MessageReceived 805128277c9SStephan Aßmus bool 806128277c9SStephan Aßmus PathManipulator::MessageReceived(BMessage* message, Command** _command) 807128277c9SStephan Aßmus { 808128277c9SStephan Aßmus bool result = true; 809128277c9SStephan Aßmus switch (message->what) { 810f4bd80a2SStephan Aßmus case MSG_TRANSFORM: 811128277c9SStephan Aßmus if (!fSelection->IsEmpty()) 812128277c9SStephan Aßmus _SetMode(TRANSFORM_POINTS); 813128277c9SStephan Aßmus break; 814f4bd80a2SStephan Aßmus case MSG_REMOVE_POINTS: 815128277c9SStephan Aßmus *_command = _Delete(); 816128277c9SStephan Aßmus break; 817f4bd80a2SStephan Aßmus case MSG_SPLIT_POINTS: 818f4bd80a2SStephan Aßmus *_command = new SplitPointsCommand(fPath, 819f4bd80a2SStephan Aßmus fSelection->Items(), 820f4bd80a2SStephan Aßmus fSelection->CountItems()); 821f4bd80a2SStephan Aßmus break; 822128277c9SStephan Aßmus case B_SELECT_ALL: { 823128277c9SStephan Aßmus *fOldSelection = *fSelection; 824128277c9SStephan Aßmus fSelection->MakeEmpty(); 825128277c9SStephan Aßmus int32 count = fPath->CountPoints(); 826128277c9SStephan Aßmus for (int32 i = 0; i < count; i++) 827128277c9SStephan Aßmus fSelection->Add(i); 828128277c9SStephan Aßmus if (*fOldSelection != *fSelection) { 829128277c9SStephan Aßmus // *_command = new SelectPointsCommand(this, fPath, 830128277c9SStephan Aßmus // fOldSelection->Items(), 831128277c9SStephan Aßmus // fOldSelection->CountItems(), 832128277c9SStephan Aßmus // fSelection->Items(), 833128277c9SStephan Aßmus // fSelection->CountItems())); 834128277c9SStephan Aßmus count = fSelection->CountItems(); 835128277c9SStephan Aßmus int32 indices[count]; 836128277c9SStephan Aßmus memcpy(indices, fSelection->Items(), count * sizeof(int32)); 837128277c9SStephan Aßmus _Select(indices, count); 838128277c9SStephan Aßmus } 839128277c9SStephan Aßmus break; 840128277c9SStephan Aßmus } 841128277c9SStephan Aßmus default: 842128277c9SStephan Aßmus result = false; 843128277c9SStephan Aßmus break; 844128277c9SStephan Aßmus } 845128277c9SStephan Aßmus return result; 846128277c9SStephan Aßmus } 847128277c9SStephan Aßmus 848128277c9SStephan Aßmus 849128277c9SStephan Aßmus // ModifiersChanged 850128277c9SStephan Aßmus void 851128277c9SStephan Aßmus PathManipulator::ModifiersChanged(uint32 modifiers) 852128277c9SStephan Aßmus { 853128277c9SStephan Aßmus fCommandDown = modifiers & B_COMMAND_KEY; 854128277c9SStephan Aßmus fOptionDown = modifiers & B_CONTROL_KEY; 855128277c9SStephan Aßmus fShiftDown = modifiers & B_SHIFT_KEY; 856128277c9SStephan Aßmus fAltDown = modifiers & B_OPTION_KEY; 857128277c9SStephan Aßmus 8580e1ba39fSStephan Aßmus if (fTransformBox) { 8590e1ba39fSStephan Aßmus fTransformBox->ModifiersChanged(modifiers); 8600e1ba39fSStephan Aßmus return; 8610e1ba39fSStephan Aßmus } 862128277c9SStephan Aßmus // reevaluate mode 863128277c9SStephan Aßmus if (!fMouseDown) 864128277c9SStephan Aßmus _SetModeForMousePos(fLastCanvasPos); 865128277c9SStephan Aßmus } 866128277c9SStephan Aßmus 867128277c9SStephan Aßmus // HandleKeyDown 868128277c9SStephan Aßmus bool 869128277c9SStephan Aßmus PathManipulator::HandleKeyDown(uint32 key, uint32 modifiers, Command** _command) 870128277c9SStephan Aßmus { 871128277c9SStephan Aßmus bool result = true; 872128277c9SStephan Aßmus 873128277c9SStephan Aßmus float nudgeDist = 1.0; 874f67876a0SStephan Aßmus if (modifiers & B_SHIFT_KEY) 875f67876a0SStephan Aßmus nudgeDist /= fCanvasView->ZoomLevel(); 876128277c9SStephan Aßmus 877128277c9SStephan Aßmus switch (key) { 878128277c9SStephan Aßmus // commit 879128277c9SStephan Aßmus case B_RETURN: 8800e1ba39fSStephan Aßmus if (fTransformBox) { 881*4fac07a0SStephan Aßmus _SetTransformBox(NULL); 882*4fac07a0SStephan Aßmus }// else 883128277c9SStephan Aßmus // _Perform(); 884128277c9SStephan Aßmus break; 885128277c9SStephan Aßmus // cancel 886128277c9SStephan Aßmus case B_ESCAPE: 8870e1ba39fSStephan Aßmus if (fTransformBox) { 8880e1ba39fSStephan Aßmus fTransformBox->Cancel(); 889*4fac07a0SStephan Aßmus _SetTransformBox(NULL); 8900e1ba39fSStephan Aßmus } else if (fFallBackMode == NEW_PATH) { 891128277c9SStephan Aßmus fFallBackMode = SELECT_POINTS; 892*4fac07a0SStephan Aßmus _SetTransformBox(NULL); 893*4fac07a0SStephan Aßmus }// else 894128277c9SStephan Aßmus // _Cancel(); 895128277c9SStephan Aßmus break; 896128277c9SStephan Aßmus case 't': 897128277c9SStephan Aßmus case 'T': 898128277c9SStephan Aßmus if (!fSelection->IsEmpty()) 899128277c9SStephan Aßmus _SetMode(TRANSFORM_POINTS); 900128277c9SStephan Aßmus else 901128277c9SStephan Aßmus result = false; 902128277c9SStephan Aßmus break; 903128277c9SStephan Aßmus // nudging 904128277c9SStephan Aßmus case B_UP_ARROW: 905128277c9SStephan Aßmus _Nudge(BPoint(0.0, -nudgeDist)); 906128277c9SStephan Aßmus break; 907128277c9SStephan Aßmus case B_DOWN_ARROW: 908128277c9SStephan Aßmus _Nudge(BPoint(0.0, nudgeDist)); 909128277c9SStephan Aßmus break; 910128277c9SStephan Aßmus case B_LEFT_ARROW: 911128277c9SStephan Aßmus _Nudge(BPoint(-nudgeDist, 0.0)); 912128277c9SStephan Aßmus break; 913128277c9SStephan Aßmus case B_RIGHT_ARROW: 914128277c9SStephan Aßmus _Nudge(BPoint(nudgeDist, 0.0)); 915128277c9SStephan Aßmus break; 916128277c9SStephan Aßmus 917128277c9SStephan Aßmus case B_DELETE: 918128277c9SStephan Aßmus if (!fSelection->IsEmpty()) 919128277c9SStephan Aßmus *_command = _Delete(); 920128277c9SStephan Aßmus else 921128277c9SStephan Aßmus result = false; 922128277c9SStephan Aßmus break; 923128277c9SStephan Aßmus 924128277c9SStephan Aßmus default: 925128277c9SStephan Aßmus result = false; 926128277c9SStephan Aßmus } 927128277c9SStephan Aßmus return result; 928128277c9SStephan Aßmus } 929128277c9SStephan Aßmus 930128277c9SStephan Aßmus // HandleKeyUp 931128277c9SStephan Aßmus bool 932128277c9SStephan Aßmus PathManipulator::HandleKeyUp(uint32 key, uint32 modifiers, Command** _command) 933128277c9SStephan Aßmus { 934128277c9SStephan Aßmus bool handled = true; 935128277c9SStephan Aßmus switch (key) { 936128277c9SStephan Aßmus // nudging 937128277c9SStephan Aßmus case B_UP_ARROW: 938128277c9SStephan Aßmus case B_DOWN_ARROW: 939128277c9SStephan Aßmus case B_LEFT_ARROW: 940128277c9SStephan Aßmus case B_RIGHT_ARROW: 9410e1ba39fSStephan Aßmus *_command = _FinishNudging(); 942128277c9SStephan Aßmus break; 943128277c9SStephan Aßmus default: 944128277c9SStephan Aßmus handled = false; 945128277c9SStephan Aßmus break; 946128277c9SStephan Aßmus } 947128277c9SStephan Aßmus return handled; 948128277c9SStephan Aßmus } 949128277c9SStephan Aßmus 950128277c9SStephan Aßmus // UpdateCursor 951128277c9SStephan Aßmus void 952128277c9SStephan Aßmus PathManipulator::UpdateCursor() 953128277c9SStephan Aßmus { 9540e1ba39fSStephan Aßmus if (fTransformBox) { 9550e1ba39fSStephan Aßmus fTransformBox->UpdateCursor(); 9560e1ba39fSStephan Aßmus return; 9570e1ba39fSStephan Aßmus } 958128277c9SStephan Aßmus const uchar* cursorData; 959128277c9SStephan Aßmus switch (fMode) { 960128277c9SStephan Aßmus case ADD_POINT: 961128277c9SStephan Aßmus cursorData = kPathAddCursor; 962128277c9SStephan Aßmus break; 963128277c9SStephan Aßmus case INSERT_POINT: 964128277c9SStephan Aßmus cursorData = kPathInsertCursor; 965128277c9SStephan Aßmus break; 966128277c9SStephan Aßmus case MOVE_POINT: 967128277c9SStephan Aßmus case MOVE_POINT_IN: 968128277c9SStephan Aßmus case MOVE_POINT_OUT: 969128277c9SStephan Aßmus case TRANSLATE_POINTS: 970128277c9SStephan Aßmus cursorData = kPathMoveCursor; 971128277c9SStephan Aßmus break; 972128277c9SStephan Aßmus case CLOSE_PATH: 973128277c9SStephan Aßmus cursorData = kPathCloseCursor; 974128277c9SStephan Aßmus break; 975128277c9SStephan Aßmus case TOGGLE_SHARP: 976128277c9SStephan Aßmus case TOGGLE_SHARP_IN: 977128277c9SStephan Aßmus case TOGGLE_SHARP_OUT: 978128277c9SStephan Aßmus cursorData = kPathSharpCursor; 979128277c9SStephan Aßmus break; 980128277c9SStephan Aßmus case REMOVE_POINT: 981128277c9SStephan Aßmus case REMOVE_POINT_IN: 982128277c9SStephan Aßmus case REMOVE_POINT_OUT: 983128277c9SStephan Aßmus cursorData = kPathRemoveCursor; 984128277c9SStephan Aßmus break; 985128277c9SStephan Aßmus case SELECT_POINTS: 986128277c9SStephan Aßmus cursorData = kPathSelectCursor; 987128277c9SStephan Aßmus break; 988128277c9SStephan Aßmus 989128277c9SStephan Aßmus case SELECT_SUB_PATH: 990128277c9SStephan Aßmus cursorData = B_HAND_CURSOR; 991128277c9SStephan Aßmus break; 992128277c9SStephan Aßmus 993128277c9SStephan Aßmus case UNDEFINED: 994128277c9SStephan Aßmus default: 995128277c9SStephan Aßmus cursorData = kStopCursor; 996128277c9SStephan Aßmus break; 997128277c9SStephan Aßmus } 998128277c9SStephan Aßmus BCursor cursor(cursorData); 999128277c9SStephan Aßmus fCanvasView->SetViewCursor(&cursor, true); 1000128277c9SStephan Aßmus fCanvasView->Sync(); 1001128277c9SStephan Aßmus } 1002128277c9SStephan Aßmus 1003128277c9SStephan Aßmus // AttachedToView 1004128277c9SStephan Aßmus void 1005128277c9SStephan Aßmus PathManipulator::AttachedToView(BView* view) 1006128277c9SStephan Aßmus { 1007f67876a0SStephan Aßmus fCanvasView = dynamic_cast<CanvasView*>(view); 1008128277c9SStephan Aßmus } 1009128277c9SStephan Aßmus 1010128277c9SStephan Aßmus // DetachedFromView 1011128277c9SStephan Aßmus void 1012128277c9SStephan Aßmus PathManipulator::DetachedFromView(BView* view) 1013128277c9SStephan Aßmus { 1014128277c9SStephan Aßmus fCanvasView = NULL; 1015128277c9SStephan Aßmus } 1016128277c9SStephan Aßmus 1017128277c9SStephan Aßmus // #pragma mark - 1018128277c9SStephan Aßmus 1019128277c9SStephan Aßmus // ObjectChanged 1020128277c9SStephan Aßmus void 1021128277c9SStephan Aßmus PathManipulator::ObjectChanged(const Observable* object) 1022128277c9SStephan Aßmus { 1023128277c9SStephan Aßmus // TODO: refine VectorPath listener interface and 1024128277c9SStephan Aßmus // implement more efficiently 1025128277c9SStephan Aßmus BRect currentBounds = _ControlPointRect(); 1026128277c9SStephan Aßmus _InvalidateCanvas(currentBounds | fPreviousBounds); 1027128277c9SStephan Aßmus fPreviousBounds = currentBounds; 1028128277c9SStephan Aßmus 1029128277c9SStephan Aßmus // reevaluate mode 10300e1ba39fSStephan Aßmus if (!fMouseDown && !fTransformBox) 1031128277c9SStephan Aßmus _SetModeForMousePos(fLastCanvasPos); 1032128277c9SStephan Aßmus } 1033128277c9SStephan Aßmus 1034128277c9SStephan Aßmus // #pragma mark - 1035128277c9SStephan Aßmus 103605fd3818SStephan Aßmus // PointAdded 103705fd3818SStephan Aßmus void 103805fd3818SStephan Aßmus PathManipulator::PointAdded(int32 index) 103905fd3818SStephan Aßmus { 104005fd3818SStephan Aßmus ObjectChanged(fPath); 104105fd3818SStephan Aßmus } 104205fd3818SStephan Aßmus 104305fd3818SStephan Aßmus // PointRemoved 104405fd3818SStephan Aßmus void 104505fd3818SStephan Aßmus PathManipulator::PointRemoved(int32 index) 104605fd3818SStephan Aßmus { 10470e1ba39fSStephan Aßmus fSelection->Remove(index); 104805fd3818SStephan Aßmus ObjectChanged(fPath); 104905fd3818SStephan Aßmus } 105005fd3818SStephan Aßmus 105105fd3818SStephan Aßmus // PointChanged 105205fd3818SStephan Aßmus void 105305fd3818SStephan Aßmus PathManipulator::PointChanged(int32 index) 105405fd3818SStephan Aßmus { 105505fd3818SStephan Aßmus ObjectChanged(fPath); 105605fd3818SStephan Aßmus } 105705fd3818SStephan Aßmus 105805fd3818SStephan Aßmus // PathChanged 105905fd3818SStephan Aßmus void 106005fd3818SStephan Aßmus PathManipulator::PathChanged() 106105fd3818SStephan Aßmus { 106205fd3818SStephan Aßmus ObjectChanged(fPath); 106305fd3818SStephan Aßmus } 106405fd3818SStephan Aßmus 106505fd3818SStephan Aßmus // PathClosedChanged 106605fd3818SStephan Aßmus void 106705fd3818SStephan Aßmus PathManipulator::PathClosedChanged() 106805fd3818SStephan Aßmus { 106905fd3818SStephan Aßmus ObjectChanged(fPath); 107005fd3818SStephan Aßmus } 107105fd3818SStephan Aßmus 107205fd3818SStephan Aßmus // PathReversed 107305fd3818SStephan Aßmus void 107405fd3818SStephan Aßmus PathManipulator::PathReversed() 107505fd3818SStephan Aßmus { 10760e1ba39fSStephan Aßmus // reverse selection along with path 10770e1ba39fSStephan Aßmus int32 count = fSelection->CountItems(); 10780e1ba39fSStephan Aßmus int32 pointCount = fPath->CountPoints(); 10790e1ba39fSStephan Aßmus if (count > 0) { 10800e1ba39fSStephan Aßmus Selection temp; 10810e1ba39fSStephan Aßmus for (int32 i = 0; i < count; i++) { 10820e1ba39fSStephan Aßmus temp.Add((pointCount - 1) - fSelection->IndexAt(i)); 10830e1ba39fSStephan Aßmus } 10840e1ba39fSStephan Aßmus *fSelection = temp; 10850e1ba39fSStephan Aßmus } 10860e1ba39fSStephan Aßmus 108705fd3818SStephan Aßmus ObjectChanged(fPath); 108805fd3818SStephan Aßmus } 108905fd3818SStephan Aßmus 109005fd3818SStephan Aßmus // #pragma mark - 109105fd3818SStephan Aßmus 1092128277c9SStephan Aßmus // ControlFlags 1093128277c9SStephan Aßmus uint32 1094128277c9SStephan Aßmus PathManipulator::ControlFlags() const 1095128277c9SStephan Aßmus { 1096128277c9SStephan Aßmus uint32 flags = 0; 1097128277c9SStephan Aßmus 1098128277c9SStephan Aßmus // flags |= SHAPE_UI_FLAGS_CAN_REVERSE_PATH; 1099128277c9SStephan Aßmus // 1100128277c9SStephan Aßmus // if (!fSelection->IsEmpty()) 1101128277c9SStephan Aßmus // flags |= SHAPE_UI_FLAGS_HAS_SELECTION; 1102128277c9SStephan Aßmus // if (fPath->CountPoints() > 1) 1103128277c9SStephan Aßmus // flags |= SHAPE_UI_FLAGS_CAN_CLOSE_PATH; 1104128277c9SStephan Aßmus // if (fPath->IsClosed()) 1105128277c9SStephan Aßmus // flags |= SHAPE_UI_FLAGS_PATH_IS_CLOSED; 11060e1ba39fSStephan Aßmus // if (fTransformBox) 11070e1ba39fSStephan Aßmus // flags |= SHAPE_UI_FLAGS_IS_TRANSFORMING; 1108128277c9SStephan Aßmus 1109128277c9SStephan Aßmus return flags; 1110128277c9SStephan Aßmus } 1111128277c9SStephan Aßmus 1112128277c9SStephan Aßmus // ReversePath 1113128277c9SStephan Aßmus void 1114128277c9SStephan Aßmus PathManipulator::ReversePath() 1115128277c9SStephan Aßmus { 1116128277c9SStephan Aßmus int32 count = fSelection->CountItems(); 1117128277c9SStephan Aßmus int32 pointCount = fPath->CountPoints(); 1118128277c9SStephan Aßmus if (count > 0) { 1119128277c9SStephan Aßmus Selection temp; 1120128277c9SStephan Aßmus for (int32 i = 0; i < count; i++) { 1121128277c9SStephan Aßmus temp.Add((pointCount - 1) - fSelection->IndexAt(i)); 1122128277c9SStephan Aßmus } 1123128277c9SStephan Aßmus *fSelection = temp; 1124128277c9SStephan Aßmus } 1125128277c9SStephan Aßmus fPath->Reverse(); 1126128277c9SStephan Aßmus } 1127128277c9SStephan Aßmus 1128128277c9SStephan Aßmus // #pragma mark - 1129128277c9SStephan Aßmus 1130128277c9SStephan Aßmus // _SetMode 1131128277c9SStephan Aßmus void 1132128277c9SStephan Aßmus PathManipulator::_SetMode(uint32 mode) 1133128277c9SStephan Aßmus { 1134128277c9SStephan Aßmus if (fMode != mode) { 1135128277c9SStephan Aßmus //printf("switching mode: %s -> %s\n", string_for_mode(fMode), string_for_mode(mode)); 1136128277c9SStephan Aßmus fMode = mode; 1137128277c9SStephan Aßmus 11380e1ba39fSStephan Aßmus if (fMode == TRANSFORM_POINTS) { 11390e1ba39fSStephan Aßmus _SetTransformBox(new TransformPointsBox(fCanvasView, 11400e1ba39fSStephan Aßmus this, 11410e1ba39fSStephan Aßmus fPath, 11420e1ba39fSStephan Aßmus fSelection->Items(), 11430e1ba39fSStephan Aßmus fSelection->CountItems())); 11440e1ba39fSStephan Aßmus // fCanvasView->Perform(new EnterTransformPointsCommand(this, 11450e1ba39fSStephan Aßmus // fSelection->Items(), 11460e1ba39fSStephan Aßmus // fSelection->CountItems())); 11470e1ba39fSStephan Aßmus } else { 11480e1ba39fSStephan Aßmus if (fTransformBox) 11490e1ba39fSStephan Aßmus _SetTransformBox(NULL); 11500e1ba39fSStephan Aßmus } 11510e1ba39fSStephan Aßmus 1152128277c9SStephan Aßmus if (BWindow* window = fCanvasView->Window()) { 1153128277c9SStephan Aßmus window->PostMessage(MSG_UPDATE_SHAPE_UI); 1154128277c9SStephan Aßmus } 1155128277c9SStephan Aßmus UpdateCursor(); 1156128277c9SStephan Aßmus } 1157128277c9SStephan Aßmus } 1158128277c9SStephan Aßmus 11590e1ba39fSStephan Aßmus 11600e1ba39fSStephan Aßmus // _SetTransformBox 11610e1ba39fSStephan Aßmus void 11620e1ba39fSStephan Aßmus PathManipulator::_SetTransformBox(TransformPointsBox* transformBox) 11630e1ba39fSStephan Aßmus { 11640e1ba39fSStephan Aßmus if (fTransformBox == transformBox) 11650e1ba39fSStephan Aßmus return; 11660e1ba39fSStephan Aßmus 11670e1ba39fSStephan Aßmus BRect dirty(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN); 11680e1ba39fSStephan Aßmus if (fTransformBox) { 11690e1ba39fSStephan Aßmus // get rid of transform box display 11700e1ba39fSStephan Aßmus dirty = fTransformBox->Bounds(); 11710e1ba39fSStephan Aßmus delete fTransformBox; 11720e1ba39fSStephan Aßmus } 11730e1ba39fSStephan Aßmus 11740e1ba39fSStephan Aßmus fTransformBox = transformBox; 11750e1ba39fSStephan Aßmus 1176*4fac07a0SStephan Aßmus // TODO: this is weird, fMode should only be set in _SetMode, not 1177*4fac07a0SStephan Aßmus // here as well, also this method could be called this way 1178*4fac07a0SStephan Aßmus // _SetModeForMousePos -> _SetMode -> _SetTransformBox 1179*4fac07a0SStephan Aßmus // and then below it does _SetModeForMousePos again... 11800e1ba39fSStephan Aßmus if (fTransformBox) { 11810e1ba39fSStephan Aßmus fTransformBox->MouseMoved(fLastCanvasPos); 11820e1ba39fSStephan Aßmus if (fMode != TRANSFORM_POINTS) { 11830e1ba39fSStephan Aßmus fMode = TRANSFORM_POINTS; 11840e1ba39fSStephan Aßmus } 11850e1ba39fSStephan Aßmus dirty = dirty | fTransformBox->Bounds(); 11860e1ba39fSStephan Aßmus } else { 11870e1ba39fSStephan Aßmus if (fMode == TRANSFORM_POINTS) { 11880e1ba39fSStephan Aßmus _SetModeForMousePos(fLastCanvasPos); 11890e1ba39fSStephan Aßmus } 11900e1ba39fSStephan Aßmus } 11910e1ba39fSStephan Aßmus 11920e1ba39fSStephan Aßmus if (dirty.IsValid()) { 11930e1ba39fSStephan Aßmus dirty.InsetBy(-8, -8); 11940e1ba39fSStephan Aßmus fCanvasView->Invalidate(dirty); 11950e1ba39fSStephan Aßmus } 11960e1ba39fSStephan Aßmus } 11970e1ba39fSStephan Aßmus 1198128277c9SStephan Aßmus // _AddPoint 1199128277c9SStephan Aßmus void 1200128277c9SStephan Aßmus PathManipulator::_AddPoint(BPoint where) 1201128277c9SStephan Aßmus { 1202128277c9SStephan Aßmus if (fPath->AddPoint(where)) { 1203128277c9SStephan Aßmus fCurrentPathPoint = fPath->CountPoints() - 1; 1204128277c9SStephan Aßmus 1205128277c9SStephan Aßmus delete fAddPointCommand; 1206128277c9SStephan Aßmus fAddPointCommand = new AddPointCommand(fPath, fCurrentPathPoint, 1207128277c9SStephan Aßmus fSelection->Items(), 1208128277c9SStephan Aßmus fSelection->CountItems()); 1209128277c9SStephan Aßmus 1210128277c9SStephan Aßmus _Select(fCurrentPathPoint, fShiftDown); 1211128277c9SStephan Aßmus } 1212128277c9SStephan Aßmus } 1213128277c9SStephan Aßmus 1214128277c9SStephan Aßmus // scale_point 1215128277c9SStephan Aßmus BPoint 1216128277c9SStephan Aßmus scale_point(BPoint a, BPoint b, float scale) 1217128277c9SStephan Aßmus { 1218128277c9SStephan Aßmus return BPoint(a.x + (b.x - a.x) * scale, 1219128277c9SStephan Aßmus a.y + (b.y - a.y) * scale); 1220128277c9SStephan Aßmus } 1221128277c9SStephan Aßmus 1222128277c9SStephan Aßmus // _InsertPoint 1223128277c9SStephan Aßmus void 1224128277c9SStephan Aßmus PathManipulator::_InsertPoint(BPoint where, int32 index) 1225128277c9SStephan Aßmus { 1226128277c9SStephan Aßmus double scale; 1227128277c9SStephan Aßmus 1228128277c9SStephan Aßmus BPoint point; 1229128277c9SStephan Aßmus BPoint pointIn; 1230128277c9SStephan Aßmus BPoint pointOut; 1231128277c9SStephan Aßmus 1232128277c9SStephan Aßmus BPoint previous; 1233128277c9SStephan Aßmus BPoint previousOut; 1234128277c9SStephan Aßmus BPoint next; 1235128277c9SStephan Aßmus BPoint nextIn; 1236128277c9SStephan Aßmus 1237128277c9SStephan Aßmus if (fPath->FindBezierScale(index - 1, where, &scale) 1238128277c9SStephan Aßmus && scale >= 0.0 && scale <= 1.0 1239128277c9SStephan Aßmus && fPath->GetPoint(index - 1, scale, point)) { 1240128277c9SStephan Aßmus 1241128277c9SStephan Aßmus fPath->GetPointAt(index - 1, previous); 1242128277c9SStephan Aßmus fPath->GetPointOutAt(index - 1, previousOut); 1243128277c9SStephan Aßmus fPath->GetPointAt(index, next); 1244128277c9SStephan Aßmus fPath->GetPointInAt(index, nextIn); 1245128277c9SStephan Aßmus 1246128277c9SStephan Aßmus where = scale_point(previousOut, nextIn, scale); 1247128277c9SStephan Aßmus 1248128277c9SStephan Aßmus previousOut = scale_point(previous, previousOut, scale); 1249128277c9SStephan Aßmus nextIn = scale_point(next, nextIn, 1 - scale); 1250128277c9SStephan Aßmus pointIn = scale_point(previousOut, where, scale); 1251128277c9SStephan Aßmus pointOut = scale_point(nextIn, where, 1 - scale); 1252128277c9SStephan Aßmus 1253128277c9SStephan Aßmus if (fPath->AddPoint(point, index)) { 1254128277c9SStephan Aßmus 1255128277c9SStephan Aßmus fPath->SetPointIn(index, pointIn); 1256128277c9SStephan Aßmus fPath->SetPointOut(index, pointOut); 1257128277c9SStephan Aßmus 1258128277c9SStephan Aßmus delete fInsertPointCommand; 1259128277c9SStephan Aßmus fInsertPointCommand = new InsertPointCommand(fPath, index, 1260128277c9SStephan Aßmus fSelection->Items(), 1261128277c9SStephan Aßmus fSelection->CountItems()); 1262128277c9SStephan Aßmus 1263128277c9SStephan Aßmus fPath->SetPointOut(index - 1, previousOut); 1264128277c9SStephan Aßmus fPath->SetPointIn(index + 1, nextIn); 1265128277c9SStephan Aßmus 1266128277c9SStephan Aßmus fCurrentPathPoint = index; 1267128277c9SStephan Aßmus _ShiftSelection(fCurrentPathPoint, 1); 1268128277c9SStephan Aßmus _Select(fCurrentPathPoint, fShiftDown); 1269128277c9SStephan Aßmus } 1270128277c9SStephan Aßmus } 1271128277c9SStephan Aßmus } 1272128277c9SStephan Aßmus 1273128277c9SStephan Aßmus // _SetInOutConnected 1274128277c9SStephan Aßmus void 1275128277c9SStephan Aßmus PathManipulator::_SetInOutConnected(int32 index, bool connected) 1276128277c9SStephan Aßmus { 1277128277c9SStephan Aßmus fPath->SetInOutConnected(index, connected); 1278128277c9SStephan Aßmus } 1279128277c9SStephan Aßmus 1280128277c9SStephan Aßmus // _SetSharp 1281128277c9SStephan Aßmus void 1282128277c9SStephan Aßmus PathManipulator::_SetSharp(int32 index) 1283128277c9SStephan Aßmus { 1284128277c9SStephan Aßmus BPoint p; 1285128277c9SStephan Aßmus fPath->GetPointAt(index, p); 1286128277c9SStephan Aßmus fPath->SetPoint(index, p, p, p, true); 1287128277c9SStephan Aßmus } 1288128277c9SStephan Aßmus 1289128277c9SStephan Aßmus // _RemoveSelection 1290128277c9SStephan Aßmus void 1291128277c9SStephan Aßmus PathManipulator::_RemoveSelection() 1292128277c9SStephan Aßmus { 12930e1ba39fSStephan Aßmus // NOTE: copy selection since removing points will 12940e1ba39fSStephan Aßmus // trigger notifications, and that will influence the 12950e1ba39fSStephan Aßmus // selection 12960e1ba39fSStephan Aßmus Selection selection = *fSelection; 12970e1ba39fSStephan Aßmus int32 count = selection.CountItems(); 1298128277c9SStephan Aßmus for (int32 i = 0; i < count; i++) { 12990e1ba39fSStephan Aßmus if (!fPath->RemovePoint(selection.IndexAt(i) - i)) 1300128277c9SStephan Aßmus break; 1301128277c9SStephan Aßmus } 1302128277c9SStephan Aßmus 13030e1ba39fSStephan Aßmus fPath->SetClosed(fPath->IsClosed() && fPath->CountPoints() > 1); 1304128277c9SStephan Aßmus 1305128277c9SStephan Aßmus fSelection->MakeEmpty(); 1306128277c9SStephan Aßmus } 1307128277c9SStephan Aßmus 1308128277c9SStephan Aßmus 1309128277c9SStephan Aßmus // _RemovePoint 1310128277c9SStephan Aßmus void 1311128277c9SStephan Aßmus PathManipulator::_RemovePoint(int32 index) 1312128277c9SStephan Aßmus { 1313128277c9SStephan Aßmus if (fPath->RemovePoint(index)) { 1314128277c9SStephan Aßmus _Deselect(index); 1315128277c9SStephan Aßmus _ShiftSelection(index + 1, -1); 1316128277c9SStephan Aßmus } 1317128277c9SStephan Aßmus } 1318128277c9SStephan Aßmus 1319128277c9SStephan Aßmus // _RemovePointIn 1320128277c9SStephan Aßmus void 1321128277c9SStephan Aßmus PathManipulator::_RemovePointIn(int32 index) 1322128277c9SStephan Aßmus { 1323128277c9SStephan Aßmus BPoint p; 1324128277c9SStephan Aßmus if (fPath->GetPointAt(index, p)) { 1325128277c9SStephan Aßmus fPath->SetPointIn(index, p); 1326128277c9SStephan Aßmus fPath->SetInOutConnected(index, false); 1327128277c9SStephan Aßmus } 1328128277c9SStephan Aßmus } 1329128277c9SStephan Aßmus 1330128277c9SStephan Aßmus // _RemovePointOut 1331128277c9SStephan Aßmus void 1332128277c9SStephan Aßmus PathManipulator::_RemovePointOut(int32 index) 1333128277c9SStephan Aßmus { 1334128277c9SStephan Aßmus BPoint p; 1335128277c9SStephan Aßmus if (fPath->GetPointAt(index, p)) { 1336128277c9SStephan Aßmus fPath->SetPointOut(index, p); 1337128277c9SStephan Aßmus fPath->SetInOutConnected(index, false); 1338128277c9SStephan Aßmus } 1339128277c9SStephan Aßmus } 1340128277c9SStephan Aßmus 1341128277c9SStephan Aßmus // _Delete 1342128277c9SStephan Aßmus Command* 1343128277c9SStephan Aßmus PathManipulator::_Delete() 1344128277c9SStephan Aßmus { 1345128277c9SStephan Aßmus Command* command = NULL; 1346128277c9SStephan Aßmus if (!fMouseDown) { 13470e1ba39fSStephan Aßmus // make sure we apply an on-going transformation before we proceed 13480e1ba39fSStephan Aßmus if (fTransformBox) { 13490e1ba39fSStephan Aßmus _SetTransformBox(NULL); 13500e1ba39fSStephan Aßmus } 13510e1ba39fSStephan Aßmus 1352128277c9SStephan Aßmus if (fSelection->CountItems() == fPath->CountPoints()) { 1353128277c9SStephan Aßmus // command = new RemovePathCommand(fPath); 1354128277c9SStephan Aßmus } else { 1355128277c9SStephan Aßmus command = new RemovePointsCommand(fPath, 1356128277c9SStephan Aßmus fSelection->Items(), 1357128277c9SStephan Aßmus fSelection->CountItems()); 1358128277c9SStephan Aßmus _RemoveSelection(); 1359128277c9SStephan Aßmus } 1360128277c9SStephan Aßmus 1361128277c9SStephan Aßmus _SetModeForMousePos(fLastCanvasPos); 1362128277c9SStephan Aßmus } 1363128277c9SStephan Aßmus 1364128277c9SStephan Aßmus return command; 1365128277c9SStephan Aßmus } 1366128277c9SStephan Aßmus 1367128277c9SStephan Aßmus // #pragma mark - 1368128277c9SStephan Aßmus 1369128277c9SStephan Aßmus // _Select 1370128277c9SStephan Aßmus void 1371128277c9SStephan Aßmus PathManipulator::_Select(BRect r) 1372128277c9SStephan Aßmus { 1373128277c9SStephan Aßmus BPoint p; 1374f4bd80a2SStephan Aßmus BPoint pIn; 1375f4bd80a2SStephan Aßmus BPoint pOut; 1376128277c9SStephan Aßmus int32 count = fPath->CountPoints(); 1377128277c9SStephan Aßmus Selection temp; 1378f4bd80a2SStephan Aßmus for (int32 i = 0; i < count && fPath->GetPointsAt(i, p, pIn, pOut); i++) { 1379f4bd80a2SStephan Aßmus if (r.Contains(p) || r.Contains(pIn) || r.Contains(pOut)) { 1380128277c9SStephan Aßmus temp.Add(i); 1381128277c9SStephan Aßmus } 1382128277c9SStephan Aßmus } 1383128277c9SStephan Aßmus // merge old and new selection 1384128277c9SStephan Aßmus count = fOldSelection->CountItems(); 1385128277c9SStephan Aßmus for (int32 i = 0; i < count; i++) { 1386128277c9SStephan Aßmus int32 index = fOldSelection->IndexAt(i); 1387128277c9SStephan Aßmus if (temp.Contains(index)) 1388128277c9SStephan Aßmus temp.Remove(index); 1389128277c9SStephan Aßmus else 1390128277c9SStephan Aßmus temp.Add(index); 1391128277c9SStephan Aßmus } 1392128277c9SStephan Aßmus if (temp != *fSelection) { 1393128277c9SStephan Aßmus *fSelection = temp; 1394128277c9SStephan Aßmus _UpdateSelection(); 1395128277c9SStephan Aßmus } 1396128277c9SStephan Aßmus } 1397128277c9SStephan Aßmus 1398128277c9SStephan Aßmus // _Select 1399128277c9SStephan Aßmus void 1400128277c9SStephan Aßmus PathManipulator::_Select(int32 index, bool extend) 1401128277c9SStephan Aßmus { 1402128277c9SStephan Aßmus if (!extend) 1403128277c9SStephan Aßmus fSelection->MakeEmpty(); 1404128277c9SStephan Aßmus if (fSelection->Contains(index)) 1405128277c9SStephan Aßmus fSelection->Remove(index); 1406128277c9SStephan Aßmus else 1407128277c9SStephan Aßmus fSelection->Add(index); 1408128277c9SStephan Aßmus // TODO: this can lead to unnecessary invalidation (maybe need to investigate) 1409128277c9SStephan Aßmus _UpdateSelection(); 1410128277c9SStephan Aßmus } 1411128277c9SStephan Aßmus 1412128277c9SStephan Aßmus // _Select 1413128277c9SStephan Aßmus void 1414128277c9SStephan Aßmus PathManipulator::_Select(const int32* indices, int32 count, bool extend) 1415128277c9SStephan Aßmus { 1416128277c9SStephan Aßmus if (extend) { 1417128277c9SStephan Aßmus for (int32 i = 0; i < count; i++) { 1418128277c9SStephan Aßmus if (!fSelection->Contains(indices[i])) 1419128277c9SStephan Aßmus fSelection->Add(indices[i]); 1420128277c9SStephan Aßmus } 1421128277c9SStephan Aßmus } else { 1422128277c9SStephan Aßmus fSelection->MakeEmpty(); 1423128277c9SStephan Aßmus for (int32 i = 0; i < count; i++) { 1424128277c9SStephan Aßmus fSelection->Add(indices[i]); 1425128277c9SStephan Aßmus } 1426128277c9SStephan Aßmus } 1427128277c9SStephan Aßmus _UpdateSelection(); 1428128277c9SStephan Aßmus } 1429128277c9SStephan Aßmus 1430128277c9SStephan Aßmus // _Deselect 1431128277c9SStephan Aßmus void 1432128277c9SStephan Aßmus PathManipulator::_Deselect(int32 index) 1433128277c9SStephan Aßmus { 1434128277c9SStephan Aßmus if (fSelection->Contains(index)) { 1435128277c9SStephan Aßmus fSelection->Remove(index); 1436128277c9SStephan Aßmus _UpdateSelection(); 1437128277c9SStephan Aßmus } 1438128277c9SStephan Aßmus } 1439128277c9SStephan Aßmus 1440128277c9SStephan Aßmus // _ShiftSelection 1441128277c9SStephan Aßmus void 1442128277c9SStephan Aßmus PathManipulator::_ShiftSelection(int32 startIndex, int32 direction) 1443128277c9SStephan Aßmus { 1444128277c9SStephan Aßmus int32 count = fSelection->CountItems(); 1445128277c9SStephan Aßmus if (count > 0) { 1446128277c9SStephan Aßmus int32* selection = fSelection->Items(); 1447128277c9SStephan Aßmus for (int32 i = 0; i < count; i++) { 1448128277c9SStephan Aßmus if (selection[i] >= startIndex) { 1449128277c9SStephan Aßmus selection[i] += direction; 1450128277c9SStephan Aßmus } 1451128277c9SStephan Aßmus } 1452128277c9SStephan Aßmus } 1453128277c9SStephan Aßmus _UpdateSelection(); 1454128277c9SStephan Aßmus } 1455128277c9SStephan Aßmus 1456128277c9SStephan Aßmus // _IsSelected 1457128277c9SStephan Aßmus bool 1458128277c9SStephan Aßmus PathManipulator::_IsSelected(int32 index) const 1459128277c9SStephan Aßmus { 1460128277c9SStephan Aßmus return fSelection->Contains(index); 1461128277c9SStephan Aßmus } 1462128277c9SStephan Aßmus 1463128277c9SStephan Aßmus // #pragma mark - 1464128277c9SStephan Aßmus 1465128277c9SStephan Aßmus // _InvalidateCanvas 1466128277c9SStephan Aßmus void 1467128277c9SStephan Aßmus PathManipulator::_InvalidateCanvas(BRect rect) const 1468128277c9SStephan Aßmus { 1469f67876a0SStephan Aßmus // convert from canvas to view space 1470f67876a0SStephan Aßmus fCanvasView->ConvertFromCanvas(&rect); 1471128277c9SStephan Aßmus fCanvasView->Invalidate(rect); 1472128277c9SStephan Aßmus } 1473128277c9SStephan Aßmus 1474128277c9SStephan Aßmus // _InvalidateHighlightPoints 1475128277c9SStephan Aßmus void 1476128277c9SStephan Aßmus PathManipulator::_InvalidateHighlightPoints(int32 newIndex, uint32 newMode) 1477128277c9SStephan Aßmus { 1478128277c9SStephan Aßmus BRect oldRect = _ControlPointRect(fCurrentPathPoint, fMode); 1479128277c9SStephan Aßmus BRect newRect = _ControlPointRect(newIndex, newMode); 1480128277c9SStephan Aßmus if (oldRect.IsValid()) 1481128277c9SStephan Aßmus _InvalidateCanvas(oldRect); 1482128277c9SStephan Aßmus if (newRect.IsValid()) 1483128277c9SStephan Aßmus _InvalidateCanvas(newRect); 1484128277c9SStephan Aßmus } 1485128277c9SStephan Aßmus 1486128277c9SStephan Aßmus // _UpdateSelection 1487128277c9SStephan Aßmus void 1488128277c9SStephan Aßmus PathManipulator::_UpdateSelection() const 1489128277c9SStephan Aßmus { 1490128277c9SStephan Aßmus _InvalidateCanvas(_ControlPointRect()); 1491128277c9SStephan Aßmus if (BWindow* window = fCanvasView->Window()) { 1492128277c9SStephan Aßmus window->PostMessage(MSG_UPDATE_SHAPE_UI); 1493128277c9SStephan Aßmus } 1494128277c9SStephan Aßmus } 1495128277c9SStephan Aßmus 1496128277c9SStephan Aßmus // _ControlPointRect 1497128277c9SStephan Aßmus BRect 1498128277c9SStephan Aßmus PathManipulator::_ControlPointRect() const 1499128277c9SStephan Aßmus { 1500128277c9SStephan Aßmus BRect r = fPath->ControlPointBounds(); 1501128277c9SStephan Aßmus r.InsetBy(-POINT_EXTEND, -POINT_EXTEND); 1502128277c9SStephan Aßmus return r; 1503128277c9SStephan Aßmus } 1504128277c9SStephan Aßmus 1505128277c9SStephan Aßmus // _ControlPointRect 1506128277c9SStephan Aßmus BRect 1507128277c9SStephan Aßmus PathManipulator::_ControlPointRect(int32 index, uint32 mode) const 1508128277c9SStephan Aßmus { 1509128277c9SStephan Aßmus BRect rect(0.0, 0.0, -1.0, -1.0); 1510128277c9SStephan Aßmus if (index >= 0) { 1511128277c9SStephan Aßmus BPoint p, pIn, pOut; 1512128277c9SStephan Aßmus fPath->GetPointsAt(index, p, pIn, pOut); 1513128277c9SStephan Aßmus switch (mode) { 1514128277c9SStephan Aßmus case MOVE_POINT: 1515128277c9SStephan Aßmus case TOGGLE_SHARP: 1516128277c9SStephan Aßmus case REMOVE_POINT: 1517128277c9SStephan Aßmus case CLOSE_PATH: 1518128277c9SStephan Aßmus rect.Set(p.x, p.y, p.x, p.y); 1519128277c9SStephan Aßmus rect.InsetBy(-POINT_EXTEND, -POINT_EXTEND); 1520128277c9SStephan Aßmus break; 1521128277c9SStephan Aßmus case MOVE_POINT_IN: 1522128277c9SStephan Aßmus case TOGGLE_SHARP_IN: 1523128277c9SStephan Aßmus case REMOVE_POINT_IN: 1524128277c9SStephan Aßmus rect.Set(pIn.x, pIn.y, pIn.x, pIn.y); 1525128277c9SStephan Aßmus rect.InsetBy(-CONTROL_POINT_EXTEND, -CONTROL_POINT_EXTEND); 1526128277c9SStephan Aßmus break; 1527128277c9SStephan Aßmus case MOVE_POINT_OUT: 1528128277c9SStephan Aßmus case TOGGLE_SHARP_OUT: 1529128277c9SStephan Aßmus case REMOVE_POINT_OUT: 1530128277c9SStephan Aßmus rect.Set(pOut.x, pOut.y, pOut.x, pOut.y); 1531128277c9SStephan Aßmus rect.InsetBy(-CONTROL_POINT_EXTEND, -CONTROL_POINT_EXTEND); 1532128277c9SStephan Aßmus break; 1533128277c9SStephan Aßmus case SELECT_POINTS: 1534128277c9SStephan Aßmus rect.Set(min4(p.x, pIn.x, pOut.x, pOut.x), 1535128277c9SStephan Aßmus min4(p.y, pIn.y, pOut.y, pOut.y), 1536128277c9SStephan Aßmus max4(p.x, pIn.x, pOut.x, pOut.x), 1537128277c9SStephan Aßmus max4(p.y, pIn.y, pOut.y, pOut.y)); 1538128277c9SStephan Aßmus rect.InsetBy(-POINT_EXTEND, -POINT_EXTEND); 1539128277c9SStephan Aßmus break; 1540128277c9SStephan Aßmus } 1541128277c9SStephan Aßmus } 1542128277c9SStephan Aßmus return rect; 1543128277c9SStephan Aßmus } 1544128277c9SStephan Aßmus 1545128277c9SStephan Aßmus // #pragma mark - 1546128277c9SStephan Aßmus 1547128277c9SStephan Aßmus // _SetModeForMousePos 1548128277c9SStephan Aßmus void 1549128277c9SStephan Aßmus PathManipulator::_SetModeForMousePos(BPoint where) 1550128277c9SStephan Aßmus { 1551128277c9SStephan Aßmus uint32 mode = UNDEFINED; 1552128277c9SStephan Aßmus int32 index = -1; 1553128277c9SStephan Aßmus 1554f67876a0SStephan Aßmus float zoomLevel = fCanvasView->ZoomLevel(); 1555128277c9SStephan Aßmus 1556128277c9SStephan Aßmus // see if we're close enough at a control point 1557128277c9SStephan Aßmus BPoint point; 1558128277c9SStephan Aßmus BPoint pointIn; 1559128277c9SStephan Aßmus BPoint pointOut; 1560128277c9SStephan Aßmus for (int32 i = 0; fPath->GetPointsAt(i, point, pointIn, pointOut) 1561128277c9SStephan Aßmus && mode == UNDEFINED; i++) { 1562128277c9SStephan Aßmus 1563128277c9SStephan Aßmus float distM = point_point_distance(point, where) * zoomLevel; 1564128277c9SStephan Aßmus float distIn = point_point_distance(pointIn, where) * zoomLevel; 1565128277c9SStephan Aßmus float distOut = point_point_distance(pointOut, where) * zoomLevel; 1566128277c9SStephan Aßmus 1567128277c9SStephan Aßmus if (distM < MOVE_THRESHOLD) { 1568128277c9SStephan Aßmus if (i == 0 && fClickToClose 1569128277c9SStephan Aßmus && !fPath->IsClosed() && fPath->CountPoints() > 1) { 1570128277c9SStephan Aßmus mode = fCommandDown ? TOGGLE_SHARP : 1571128277c9SStephan Aßmus (fOptionDown ? REMOVE_POINT : CLOSE_PATH); 1572128277c9SStephan Aßmus index = i; 1573128277c9SStephan Aßmus } else { 1574128277c9SStephan Aßmus mode = fCommandDown ? TOGGLE_SHARP : 1575128277c9SStephan Aßmus (fOptionDown ? REMOVE_POINT : MOVE_POINT); 1576128277c9SStephan Aßmus index = i; 1577128277c9SStephan Aßmus } 1578128277c9SStephan Aßmus } 15790e1ba39fSStephan Aßmus if (distM - distIn > 0.00001 15800e1ba39fSStephan Aßmus && distIn < MOVE_THRESHOLD) { 1581128277c9SStephan Aßmus mode = fCommandDown ? TOGGLE_SHARP_IN : 1582128277c9SStephan Aßmus (fOptionDown ? REMOVE_POINT_IN : MOVE_POINT_IN); 1583128277c9SStephan Aßmus index = i; 1584128277c9SStephan Aßmus } 15850e1ba39fSStephan Aßmus if (distIn - distOut > 0.00001 15860e1ba39fSStephan Aßmus && distOut < distM && distOut < MOVE_THRESHOLD) { 1587128277c9SStephan Aßmus mode = fCommandDown ? TOGGLE_SHARP_OUT : 1588128277c9SStephan Aßmus (fOptionDown ? REMOVE_POINT_OUT : MOVE_POINT_OUT); 1589128277c9SStephan Aßmus index = i; 1590128277c9SStephan Aßmus } 1591128277c9SStephan Aßmus } 1592128277c9SStephan Aßmus // selection mode overrides any other mode, 1593128277c9SStephan Aßmus // but we need to check for it after we know 1594128277c9SStephan Aßmus // the index of the point under the mouse (code above) 1595128277c9SStephan Aßmus int32 pointCount = fPath->CountPoints(); 1596128277c9SStephan Aßmus if (fShiftDown && pointCount > 0) { 1597128277c9SStephan Aßmus mode = SELECT_POINTS; 1598128277c9SStephan Aßmus } 1599128277c9SStephan Aßmus 1600128277c9SStephan Aßmus // see if user wants to start new sub path 1601128277c9SStephan Aßmus if (fAltDown) { 1602128277c9SStephan Aßmus mode = NEW_PATH; 1603128277c9SStephan Aßmus index = -1; 1604128277c9SStephan Aßmus } 1605128277c9SStephan Aßmus 1606128277c9SStephan Aßmus // see if we're close enough at a line 1607128277c9SStephan Aßmus if (mode == UNDEFINED) { 1608128277c9SStephan Aßmus float distance; 1609128277c9SStephan Aßmus if (fPath->GetDistance(where, &distance, &index)) { 1610128277c9SStephan Aßmus if (distance < (INSERT_DIST_THRESHOLD / zoomLevel)) { 1611128277c9SStephan Aßmus mode = INSERT_POINT; 1612128277c9SStephan Aßmus } 1613128277c9SStephan Aßmus } else { 1614128277c9SStephan Aßmus // restore index, since it was changed by call above 1615128277c9SStephan Aßmus index = fCurrentPathPoint; 1616128277c9SStephan Aßmus } 1617128277c9SStephan Aßmus } 1618128277c9SStephan Aßmus 1619128277c9SStephan Aßmus // nope, still undefined mode, last fall back 1620128277c9SStephan Aßmus if (mode == UNDEFINED) { 1621128277c9SStephan Aßmus if (fFallBackMode == SELECT_POINTS) { 1622128277c9SStephan Aßmus if (fPath->IsClosed() && pointCount > 0) { 1623128277c9SStephan Aßmus mode = SELECT_POINTS; 1624128277c9SStephan Aßmus index = -1; 1625128277c9SStephan Aßmus } else { 1626128277c9SStephan Aßmus mode = ADD_POINT; 1627128277c9SStephan Aßmus index = pointCount - 1; 1628128277c9SStephan Aßmus } 1629128277c9SStephan Aßmus } else { 1630128277c9SStephan Aßmus // user had clicked "New Path" icon 1631128277c9SStephan Aßmus mode = fFallBackMode; 1632128277c9SStephan Aßmus } 1633128277c9SStephan Aßmus } 1634128277c9SStephan Aßmus // switch mode if necessary 1635128277c9SStephan Aßmus if (mode != fMode || index != fCurrentPathPoint) { 1636128277c9SStephan Aßmus // invalidate path display (to highlight the respective point) 1637128277c9SStephan Aßmus _InvalidateHighlightPoints(index, mode); 1638128277c9SStephan Aßmus _SetMode(mode); 1639128277c9SStephan Aßmus fCurrentPathPoint = index; 1640128277c9SStephan Aßmus } 1641128277c9SStephan Aßmus } 1642128277c9SStephan Aßmus 1643128277c9SStephan Aßmus // #pragma mark - 1644128277c9SStephan Aßmus 1645128277c9SStephan Aßmus // _Nudge 1646128277c9SStephan Aßmus void 1647128277c9SStephan Aßmus PathManipulator::_Nudge(BPoint direction) 1648128277c9SStephan Aßmus { 1649128277c9SStephan Aßmus bigtime_t now = system_time(); 1650128277c9SStephan Aßmus if (now - fLastNudgeTime > 500000) { 16510e1ba39fSStephan Aßmus fCanvasView->Perform(_FinishNudging()); 1652128277c9SStephan Aßmus } 1653128277c9SStephan Aßmus fLastNudgeTime = now; 1654128277c9SStephan Aßmus fNudgeOffset += direction; 1655128277c9SStephan Aßmus 16560e1ba39fSStephan Aßmus if (fTransformBox) { 16570e1ba39fSStephan Aßmus fTransformBox->NudgeBy(direction); 16580e1ba39fSStephan Aßmus return; 16590e1ba39fSStephan Aßmus } 16600e1ba39fSStephan Aßmus 16610e1ba39fSStephan Aßmus if (!fNudgeCommand) { 16620e1ba39fSStephan Aßmus 16630e1ba39fSStephan Aßmus bool fromSelection = !fSelection->IsEmpty(); 16640e1ba39fSStephan Aßmus 16650e1ba39fSStephan Aßmus int32 count = fromSelection ? fSelection->CountItems() 16660e1ba39fSStephan Aßmus : fPath->CountPoints(); 16670e1ba39fSStephan Aßmus int32 indices[count]; 16680e1ba39fSStephan Aßmus control_point points[count]; 16690e1ba39fSStephan Aßmus 16700e1ba39fSStephan Aßmus // init indices and points 16710e1ba39fSStephan Aßmus for (int32 i = 0; i < count; i++) { 16720e1ba39fSStephan Aßmus indices[i] = fromSelection ? fSelection->IndexAt(i) : i; 16730e1ba39fSStephan Aßmus fPath->GetPointsAt(indices[i], 16740e1ba39fSStephan Aßmus points[i].point, 16750e1ba39fSStephan Aßmus points[i].point_in, 16760e1ba39fSStephan Aßmus points[i].point_out, 16770e1ba39fSStephan Aßmus &points[i].connected); 16780e1ba39fSStephan Aßmus } 16790e1ba39fSStephan Aßmus 16800e1ba39fSStephan Aßmus fNudgeCommand = new NudgePointsCommand(fPath, indices, points, count); 16810e1ba39fSStephan Aßmus 16820e1ba39fSStephan Aßmus fNudgeCommand->SetNewTranslation(fNudgeOffset); 16830e1ba39fSStephan Aßmus fNudgeCommand->Redo(); 16840e1ba39fSStephan Aßmus 16850e1ba39fSStephan Aßmus } else { 16860e1ba39fSStephan Aßmus fNudgeCommand->SetNewTranslation(fNudgeOffset); 16870e1ba39fSStephan Aßmus fNudgeCommand->Redo(); 16880e1ba39fSStephan Aßmus } 1689128277c9SStephan Aßmus 1690128277c9SStephan Aßmus if (!fMouseDown) 1691128277c9SStephan Aßmus _SetModeForMousePos(fLastCanvasPos); 1692128277c9SStephan Aßmus } 1693128277c9SStephan Aßmus 1694128277c9SStephan Aßmus // _FinishNudging 16950e1ba39fSStephan Aßmus Command* 1696128277c9SStephan Aßmus PathManipulator::_FinishNudging() 1697128277c9SStephan Aßmus { 1698128277c9SStephan Aßmus fNudgeOffset = BPoint(0.0, 0.0); 1699128277c9SStephan Aßmus 17000e1ba39fSStephan Aßmus Command* command; 17010e1ba39fSStephan Aßmus 17020e1ba39fSStephan Aßmus if (fTransformBox) { 17030e1ba39fSStephan Aßmus command = fTransformBox->FinishNudging(); 17040e1ba39fSStephan Aßmus } else { 17050e1ba39fSStephan Aßmus command = fNudgeCommand; 17060e1ba39fSStephan Aßmus fNudgeCommand = NULL; 17070e1ba39fSStephan Aßmus } 17080e1ba39fSStephan Aßmus 17090e1ba39fSStephan Aßmus return command; 1710128277c9SStephan Aßmus } 1711128277c9SStephan Aßmus 1712128277c9SStephan Aßmus 1713