1128277c9SStephan Aßmus /* 2*7c4b3726SStephan Aßmus * Copyright 2006-2007, 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" 29*7c4b3726SStephan Aßmus #include "FlipPointsCommand.h" 30128277c9SStephan Aßmus //#include "NewPathCommand.h" 310e1ba39fSStephan Aßmus #include "NudgePointsCommand.h" 32128277c9SStephan Aßmus //#include "RemovePathCommand.h" 33128277c9SStephan Aßmus #include "RemovePointsCommand.h" 34128277c9SStephan Aßmus //#include "ReversePathCommand.h" 35128277c9SStephan Aßmus //#include "SelectPathCommand.h" 36128277c9SStephan Aßmus //#include "SelectPointsCommand.h" 37f4bd80a2SStephan Aßmus #include "SplitPointsCommand.h" 380e1ba39fSStephan Aßmus #include "TransformPointsBox.h" 39128277c9SStephan Aßmus 40128277c9SStephan Aßmus #define POINT_EXTEND 3.0 41128277c9SStephan Aßmus #define CONTROL_POINT_EXTEND 2.0 42128277c9SStephan Aßmus #define INSERT_DIST_THRESHOLD 7.0 43128277c9SStephan Aßmus #define MOVE_THRESHOLD 9.0 44128277c9SStephan Aßmus 45128277c9SStephan Aßmus enum { 46128277c9SStephan Aßmus UNDEFINED, 47128277c9SStephan Aßmus 48128277c9SStephan Aßmus NEW_PATH, 49128277c9SStephan Aßmus 50128277c9SStephan Aßmus ADD_POINT, 51128277c9SStephan Aßmus INSERT_POINT, 52128277c9SStephan Aßmus MOVE_POINT, 53128277c9SStephan Aßmus MOVE_POINT_IN, 54128277c9SStephan Aßmus MOVE_POINT_OUT, 55128277c9SStephan Aßmus CLOSE_PATH, 56128277c9SStephan Aßmus 57128277c9SStephan Aßmus TOGGLE_SHARP, 58128277c9SStephan Aßmus TOGGLE_SHARP_IN, 59128277c9SStephan Aßmus TOGGLE_SHARP_OUT, 60128277c9SStephan Aßmus 61128277c9SStephan Aßmus REMOVE_POINT, 62128277c9SStephan Aßmus REMOVE_POINT_IN, 63128277c9SStephan Aßmus REMOVE_POINT_OUT, 64128277c9SStephan Aßmus 65128277c9SStephan Aßmus SELECT_POINTS, 66128277c9SStephan Aßmus TRANSFORM_POINTS, 67128277c9SStephan Aßmus TRANSLATE_POINTS, 68128277c9SStephan Aßmus 69128277c9SStephan Aßmus SELECT_SUB_PATH, 70128277c9SStephan Aßmus }; 71128277c9SStephan Aßmus 72f4bd80a2SStephan Aßmus enum { 73f4bd80a2SStephan Aßmus MSG_TRANSFORM = 'strn', 74f4bd80a2SStephan Aßmus MSG_REMOVE_POINTS = 'srmp', 75f4bd80a2SStephan Aßmus MSG_UPDATE_SHAPE_UI = 'udsi', 76f4bd80a2SStephan Aßmus 77f4bd80a2SStephan Aßmus MSG_SPLIT_POINTS = 'splt', 78*7c4b3726SStephan Aßmus MSG_FLIP_POINTS = 'flip', 79f4bd80a2SStephan Aßmus }; 80f4bd80a2SStephan Aßmus 81128277c9SStephan Aßmus inline const char* 82128277c9SStephan Aßmus string_for_mode(uint32 mode) 83128277c9SStephan Aßmus { 84128277c9SStephan Aßmus switch (mode) { 85128277c9SStephan Aßmus case UNDEFINED: 86128277c9SStephan Aßmus return "UNDEFINED"; 87128277c9SStephan Aßmus case NEW_PATH: 88128277c9SStephan Aßmus return "NEW_PATH"; 89128277c9SStephan Aßmus case ADD_POINT: 90128277c9SStephan Aßmus return "ADD_POINT"; 91128277c9SStephan Aßmus case INSERT_POINT: 92128277c9SStephan Aßmus return "INSERT_POINT"; 93128277c9SStephan Aßmus case MOVE_POINT: 94128277c9SStephan Aßmus return "MOVE_POINT"; 95128277c9SStephan Aßmus case MOVE_POINT_IN: 96128277c9SStephan Aßmus return "MOVE_POINT_IN"; 97128277c9SStephan Aßmus case MOVE_POINT_OUT: 98128277c9SStephan Aßmus return "MOVE_POINT_OUT"; 99128277c9SStephan Aßmus case CLOSE_PATH: 100128277c9SStephan Aßmus return "CLOSE_PATH"; 101128277c9SStephan Aßmus case TOGGLE_SHARP: 102128277c9SStephan Aßmus return "TOGGLE_SHARP"; 103128277c9SStephan Aßmus case TOGGLE_SHARP_IN: 104128277c9SStephan Aßmus return "TOGGLE_SHARP_IN"; 105128277c9SStephan Aßmus case TOGGLE_SHARP_OUT: 106128277c9SStephan Aßmus return "TOGGLE_SHARP_OUT"; 107128277c9SStephan Aßmus case REMOVE_POINT: 108128277c9SStephan Aßmus return "REMOVE_POINT"; 109128277c9SStephan Aßmus case REMOVE_POINT_IN: 110128277c9SStephan Aßmus return "REMOVE_POINT_IN"; 111128277c9SStephan Aßmus case REMOVE_POINT_OUT: 112128277c9SStephan Aßmus return "REMOVE_POINT_OUT"; 113128277c9SStephan Aßmus case SELECT_POINTS: 114128277c9SStephan Aßmus return "SELECT_POINTS"; 115128277c9SStephan Aßmus case TRANSFORM_POINTS: 116128277c9SStephan Aßmus return "TRANSFORM_POINTS"; 117128277c9SStephan Aßmus case TRANSLATE_POINTS: 118128277c9SStephan Aßmus return "TRANSLATE_POINTS"; 119128277c9SStephan Aßmus case SELECT_SUB_PATH: 120128277c9SStephan Aßmus return "SELECT_SUB_PATH"; 121128277c9SStephan Aßmus } 122128277c9SStephan Aßmus return "<unknown mode>"; 123128277c9SStephan Aßmus } 124128277c9SStephan Aßmus 125ce181bb0SStephan Aßmus class PathManipulator::Selection : protected BList 126128277c9SStephan Aßmus { 127128277c9SStephan Aßmus public: 128128277c9SStephan Aßmus inline Selection(int32 count = 20) 129128277c9SStephan Aßmus : BList(count) {} 130128277c9SStephan Aßmus inline ~Selection() {} 131128277c9SStephan Aßmus 132128277c9SStephan Aßmus inline void Add(int32 value) 133128277c9SStephan Aßmus { 134128277c9SStephan Aßmus if (value >= 0) { 135128277c9SStephan Aßmus // keep the list sorted 136128277c9SStephan Aßmus int32 count = CountItems(); 137128277c9SStephan Aßmus int32 index = 0; 138128277c9SStephan Aßmus for (; index < count; index++) { 139128277c9SStephan Aßmus if (IndexAt(index) > value) { 140128277c9SStephan Aßmus break; 141128277c9SStephan Aßmus } 142128277c9SStephan Aßmus } 143128277c9SStephan Aßmus BList::AddItem((void*)value, index); 144128277c9SStephan Aßmus } 145128277c9SStephan Aßmus } 146128277c9SStephan Aßmus 147128277c9SStephan Aßmus inline bool Remove(int32 value) 148128277c9SStephan Aßmus { return BList::RemoveItem((void*)value); } 149128277c9SStephan Aßmus 150128277c9SStephan Aßmus inline bool Contains(int32 value) const 151128277c9SStephan Aßmus { return BList::HasItem((void*)value); } 152128277c9SStephan Aßmus 153128277c9SStephan Aßmus inline bool IsEmpty() const 154128277c9SStephan Aßmus { return BList::IsEmpty(); } 155128277c9SStephan Aßmus 156128277c9SStephan Aßmus inline int32 IndexAt(int32 index) const 157128277c9SStephan Aßmus { return (int32)BList::ItemAt(index); } 158128277c9SStephan Aßmus 159128277c9SStephan Aßmus inline void MakeEmpty() 160128277c9SStephan Aßmus { BList::MakeEmpty(); } 161128277c9SStephan Aßmus 162128277c9SStephan Aßmus inline int32* Items() const 163128277c9SStephan Aßmus { return (int32*)BList::Items(); } 164128277c9SStephan Aßmus 165128277c9SStephan Aßmus inline const int32 CountItems() const 166128277c9SStephan Aßmus { return BList::CountItems(); } 167128277c9SStephan Aßmus 168128277c9SStephan Aßmus inline Selection& operator =(const Selection& other) 169128277c9SStephan Aßmus { 170128277c9SStephan Aßmus MakeEmpty(); 171128277c9SStephan Aßmus int32 count = other.CountItems(); 172128277c9SStephan Aßmus int32* items = other.Items(); 173128277c9SStephan Aßmus for (int32 i = 0; i < count; i++) { 174128277c9SStephan Aßmus Add(items[i]); 175128277c9SStephan Aßmus } 176128277c9SStephan Aßmus return *this; 177128277c9SStephan Aßmus } 178128277c9SStephan Aßmus 179128277c9SStephan Aßmus inline bool operator ==(const Selection& other) 180128277c9SStephan Aßmus { 181128277c9SStephan Aßmus if (other.CountItems() == CountItems()) { 182128277c9SStephan Aßmus int32* items = Items(); 183128277c9SStephan Aßmus int32* otherItems = other.Items(); 184128277c9SStephan Aßmus for (int32 i = 0; i < CountItems(); i++) { 185128277c9SStephan Aßmus if (items[i] != otherItems[i]) 186128277c9SStephan Aßmus return false; 187128277c9SStephan Aßmus items++; 188128277c9SStephan Aßmus otherItems++; 189128277c9SStephan Aßmus } 190128277c9SStephan Aßmus return true; 191128277c9SStephan Aßmus } else 192128277c9SStephan Aßmus return false; 193128277c9SStephan Aßmus } 194128277c9SStephan Aßmus 195128277c9SStephan Aßmus inline bool operator !=(const Selection& other) 196128277c9SStephan Aßmus { 197128277c9SStephan Aßmus return !(*this == other); 198128277c9SStephan Aßmus } 199128277c9SStephan Aßmus }; 200128277c9SStephan Aßmus 201128277c9SStephan Aßmus 202128277c9SStephan Aßmus // constructor 203128277c9SStephan Aßmus PathManipulator::PathManipulator(VectorPath* path) 2040e1ba39fSStephan Aßmus : Manipulator(NULL), 205128277c9SStephan Aßmus fCanvasView(NULL), 206128277c9SStephan Aßmus 207128277c9SStephan Aßmus fCommandDown(false), 208128277c9SStephan Aßmus fOptionDown(false), 209128277c9SStephan Aßmus fShiftDown(false), 210128277c9SStephan Aßmus fAltDown(false), 211128277c9SStephan Aßmus 212128277c9SStephan Aßmus fClickToClose(false), 213128277c9SStephan Aßmus 214128277c9SStephan Aßmus fMode(NEW_PATH), 215128277c9SStephan Aßmus fFallBackMode(SELECT_POINTS), 216128277c9SStephan Aßmus 217128277c9SStephan Aßmus fMouseDown(false), 218128277c9SStephan Aßmus 219128277c9SStephan Aßmus fPath(path), 220128277c9SStephan Aßmus fCurrentPathPoint(-1), 221128277c9SStephan Aßmus 222128277c9SStephan Aßmus fChangePointCommand(NULL), 223128277c9SStephan Aßmus fInsertPointCommand(NULL), 224128277c9SStephan Aßmus fAddPointCommand(NULL), 225128277c9SStephan Aßmus 226128277c9SStephan Aßmus fSelection(new Selection()), 227128277c9SStephan Aßmus fOldSelection(new Selection()), 2280e1ba39fSStephan Aßmus fTransformBox(NULL), 229128277c9SStephan Aßmus 230128277c9SStephan Aßmus fNudgeOffset(0.0, 0.0), 2310e1ba39fSStephan Aßmus fLastNudgeTime(system_time()), 2320e1ba39fSStephan Aßmus fNudgeCommand(NULL) 233128277c9SStephan Aßmus { 2340e1ba39fSStephan Aßmus fPath->Acquire(); 23505fd3818SStephan Aßmus fPath->AddListener(this); 2360e1ba39fSStephan Aßmus fPath->AddObserver(this); 237128277c9SStephan Aßmus } 238128277c9SStephan Aßmus 239128277c9SStephan Aßmus // destructor 240128277c9SStephan Aßmus PathManipulator::~PathManipulator() 241128277c9SStephan Aßmus { 242128277c9SStephan Aßmus delete fChangePointCommand; 243128277c9SStephan Aßmus delete fInsertPointCommand; 244128277c9SStephan Aßmus delete fAddPointCommand; 245128277c9SStephan Aßmus 246128277c9SStephan Aßmus delete fSelection; 247128277c9SStephan Aßmus delete fOldSelection; 2480e1ba39fSStephan Aßmus delete fTransformBox; 249128277c9SStephan Aßmus 2500e1ba39fSStephan Aßmus delete fNudgeCommand; 2510e1ba39fSStephan Aßmus 2520e1ba39fSStephan Aßmus fPath->RemoveObserver(this); 2530e1ba39fSStephan Aßmus fPath->RemoveListener(this); 2540e1ba39fSStephan Aßmus fPath->Release(); 255128277c9SStephan Aßmus } 256128277c9SStephan Aßmus 257128277c9SStephan Aßmus 258128277c9SStephan Aßmus // #pragma mark - 259128277c9SStephan Aßmus 260128277c9SStephan Aßmus class StrokePathIterator : public VectorPath::Iterator { 261128277c9SStephan Aßmus public: 262f67876a0SStephan Aßmus StrokePathIterator(CanvasView* canvasView, 263f67876a0SStephan Aßmus BView* drawingView) 264f67876a0SStephan Aßmus : fCanvasView(canvasView), 265f67876a0SStephan Aßmus fDrawingView(drawingView) 266128277c9SStephan Aßmus { 267128277c9SStephan Aßmus fDrawingView->SetHighColor(0, 0, 0, 255); 268128277c9SStephan Aßmus fDrawingView->SetDrawingMode(B_OP_OVER); 269128277c9SStephan Aßmus } 270128277c9SStephan Aßmus virtual ~StrokePathIterator() 271128277c9SStephan Aßmus {} 272128277c9SStephan Aßmus 273128277c9SStephan Aßmus virtual void MoveTo(BPoint point) 274128277c9SStephan Aßmus { 275128277c9SStephan Aßmus fBlack = true; 276f67876a0SStephan Aßmus fSkip = false; 277128277c9SStephan Aßmus fDrawingView->SetHighColor(0, 0, 0, 255); 278128277c9SStephan Aßmus 279f67876a0SStephan Aßmus fCanvasView->ConvertFromCanvas(&point); 280128277c9SStephan Aßmus fDrawingView->MovePenTo(point); 281128277c9SStephan Aßmus } 282128277c9SStephan Aßmus virtual void LineTo(BPoint point) 283128277c9SStephan Aßmus { 284f67876a0SStephan Aßmus fCanvasView->ConvertFromCanvas(&point); 285f67876a0SStephan Aßmus if (!fSkip) { 286128277c9SStephan Aßmus if (fBlack) 287128277c9SStephan Aßmus fDrawingView->SetHighColor(255, 255, 255, 255); 288128277c9SStephan Aßmus else 289128277c9SStephan Aßmus fDrawingView->SetHighColor(0, 0, 0, 255); 290128277c9SStephan Aßmus fBlack = !fBlack; 291128277c9SStephan Aßmus 292128277c9SStephan Aßmus fDrawingView->StrokeLine(point); 293f67876a0SStephan Aßmus } else { 294f67876a0SStephan Aßmus fDrawingView->MovePenTo(point); 295f67876a0SStephan Aßmus } 296f67876a0SStephan Aßmus fSkip = !fSkip; 297128277c9SStephan Aßmus } 298128277c9SStephan Aßmus 299128277c9SStephan Aßmus private: 300f67876a0SStephan Aßmus CanvasView* fCanvasView; 301128277c9SStephan Aßmus BView* fDrawingView; 302128277c9SStephan Aßmus bool fBlack; 303f67876a0SStephan Aßmus bool fSkip; 304128277c9SStephan Aßmus }; 305128277c9SStephan Aßmus 306128277c9SStephan Aßmus // Draw 307128277c9SStephan Aßmus void 308128277c9SStephan Aßmus PathManipulator::Draw(BView* into, BRect updateRect) 309128277c9SStephan Aßmus { 31064dd737cSStephan Aßmus // draw the Bezier curve, but only if not "editing", 31164dd737cSStephan Aßmus // the path is actually on top all other modifiers 312128277c9SStephan Aßmus // TODO: make this customizable in the GUI 31364dd737cSStephan Aßmus 31464dd737cSStephan Aßmus #if __HAIKU__ 31564dd737cSStephan Aßmus uint32 flags = into->Flags(); 31664dd737cSStephan Aßmus into->SetFlags(flags | B_SUBPIXEL_PRECISE); 31764dd737cSStephan Aßmus #endif // __HAIKU__ 31864dd737cSStephan Aßmus 319f67876a0SStephan Aßmus StrokePathIterator iterator(fCanvasView, into); 320f67876a0SStephan Aßmus fPath->Iterate(&iterator, fCanvasView->ZoomLevel()); 321128277c9SStephan Aßmus 32264dd737cSStephan Aßmus #if __HAIKU__ 32364dd737cSStephan Aßmus into->SetFlags(flags); 32464dd737cSStephan Aßmus #endif // __HAIKU__ 32564dd737cSStephan Aßmus 326128277c9SStephan Aßmus into->SetLowColor(0, 0, 0, 255); 327128277c9SStephan Aßmus BPoint point; 328128277c9SStephan Aßmus BPoint pointIn; 329128277c9SStephan Aßmus BPoint pointOut; 330128277c9SStephan Aßmus rgb_color focusColor = (rgb_color){ 255, 0, 0, 255 }; 331128277c9SStephan Aßmus rgb_color highlightColor = (rgb_color){ 60, 60, 255, 255 }; 332128277c9SStephan Aßmus for (int32 i = 0; fPath->GetPointsAt(i, point, pointIn, pointOut); i++) { 333128277c9SStephan Aßmus bool highlight = fCurrentPathPoint == i; 334128277c9SStephan Aßmus bool selected = fSelection->Contains(i); 335128277c9SStephan Aßmus rgb_color normal = selected ? focusColor : (rgb_color){ 0, 0, 0, 255 }; 336128277c9SStephan Aßmus into->SetLowColor(normal); 337128277c9SStephan Aßmus into->SetHighColor(255, 255, 255, 255); 338128277c9SStephan Aßmus // convert to view coordinate space 339f67876a0SStephan Aßmus fCanvasView->ConvertFromCanvas(&point); 340f67876a0SStephan Aßmus fCanvasView->ConvertFromCanvas(&pointIn); 341f67876a0SStephan Aßmus fCanvasView->ConvertFromCanvas(&pointOut); 342128277c9SStephan Aßmus // connect the points belonging to one control point 343128277c9SStephan Aßmus into->SetDrawingMode(B_OP_INVERT); 344128277c9SStephan Aßmus into->StrokeLine(point, pointIn); 345128277c9SStephan Aßmus into->StrokeLine(point, pointOut); 346128277c9SStephan Aßmus // draw main control point 347128277c9SStephan Aßmus if (highlight && (fMode == MOVE_POINT || 348128277c9SStephan Aßmus fMode == TOGGLE_SHARP || 349128277c9SStephan Aßmus fMode == REMOVE_POINT || 350128277c9SStephan Aßmus fMode == SELECT_POINTS || 351128277c9SStephan Aßmus fMode == CLOSE_PATH)) { 352128277c9SStephan Aßmus 353128277c9SStephan Aßmus into->SetLowColor(highlightColor); 354128277c9SStephan Aßmus } 355128277c9SStephan Aßmus 356128277c9SStephan Aßmus into->SetDrawingMode(B_OP_COPY); 357128277c9SStephan Aßmus BRect r(point, point); 358128277c9SStephan Aßmus r.InsetBy(-POINT_EXTEND, -POINT_EXTEND); 359128277c9SStephan Aßmus into->StrokeRect(r, B_SOLID_LOW); 360128277c9SStephan Aßmus r.InsetBy(1.0, 1.0); 361128277c9SStephan Aßmus into->FillRect(r, B_SOLID_HIGH); 362128277c9SStephan Aßmus // draw in control point 363128277c9SStephan Aßmus if (highlight && (fMode == MOVE_POINT_IN || 364128277c9SStephan Aßmus fMode == TOGGLE_SHARP_IN || 365128277c9SStephan Aßmus fMode == REMOVE_POINT_IN || 366128277c9SStephan Aßmus fMode == SELECT_POINTS)) 367128277c9SStephan Aßmus into->SetLowColor(highlightColor); 368128277c9SStephan Aßmus else 369128277c9SStephan Aßmus into->SetLowColor(normal); 370128277c9SStephan Aßmus if (selected) { 371128277c9SStephan Aßmus into->SetHighColor(220, 220, 220, 255); 372128277c9SStephan Aßmus } else { 373128277c9SStephan Aßmus into->SetHighColor(170, 170, 170, 255); 374128277c9SStephan Aßmus } 375128277c9SStephan Aßmus if (pointIn != point) { 376128277c9SStephan Aßmus r.Set(pointIn.x - CONTROL_POINT_EXTEND, pointIn.y - CONTROL_POINT_EXTEND, 377128277c9SStephan Aßmus pointIn.x + CONTROL_POINT_EXTEND, pointIn.y + CONTROL_POINT_EXTEND); 378128277c9SStephan Aßmus into->StrokeRect(r, B_SOLID_LOW); 379128277c9SStephan Aßmus r.InsetBy(1.0, 1.0); 380128277c9SStephan Aßmus into->FillRect(r, B_SOLID_HIGH); 381128277c9SStephan Aßmus } 382128277c9SStephan Aßmus // draw out control point 383128277c9SStephan Aßmus if (highlight && (fMode == MOVE_POINT_OUT || 384128277c9SStephan Aßmus fMode == TOGGLE_SHARP_OUT || 385128277c9SStephan Aßmus fMode == REMOVE_POINT_OUT || 386128277c9SStephan Aßmus fMode == SELECT_POINTS)) 387128277c9SStephan Aßmus into->SetLowColor(highlightColor); 388128277c9SStephan Aßmus else 389128277c9SStephan Aßmus into->SetLowColor(normal); 390128277c9SStephan Aßmus if (pointOut != point) { 391128277c9SStephan Aßmus r.Set(pointOut.x - CONTROL_POINT_EXTEND, pointOut.y - CONTROL_POINT_EXTEND, 392128277c9SStephan Aßmus pointOut.x + CONTROL_POINT_EXTEND, pointOut.y + CONTROL_POINT_EXTEND); 393128277c9SStephan Aßmus into->StrokeRect(r, B_SOLID_LOW); 394128277c9SStephan Aßmus r.InsetBy(1.0, 1.0); 395128277c9SStephan Aßmus into->FillRect(r, B_SOLID_HIGH); 396128277c9SStephan Aßmus } 397128277c9SStephan Aßmus } 3980e1ba39fSStephan Aßmus 3990e1ba39fSStephan Aßmus if (fTransformBox) { 4000e1ba39fSStephan Aßmus fTransformBox->Draw(into, updateRect); 4010e1ba39fSStephan Aßmus } 402128277c9SStephan Aßmus } 403128277c9SStephan Aßmus 404128277c9SStephan Aßmus // #pragma mark - 405128277c9SStephan Aßmus 406128277c9SStephan Aßmus // MouseDown 407128277c9SStephan Aßmus bool 408128277c9SStephan Aßmus PathManipulator::MouseDown(BPoint where) 409128277c9SStephan Aßmus { 410128277c9SStephan Aßmus fMouseDown = true; 411128277c9SStephan Aßmus 4120e1ba39fSStephan Aßmus if (fMode == TRANSFORM_POINTS) { 4130e1ba39fSStephan Aßmus if (fTransformBox) { 4140e1ba39fSStephan Aßmus fTransformBox->MouseDown(where); 4150e1ba39fSStephan Aßmus 4160e1ba39fSStephan Aßmus // if (!fTransformBox->IsRotating()) 4170e1ba39fSStephan Aßmus // fCanvasView->SetAutoScrolling(true); 4180e1ba39fSStephan Aßmus } 4190e1ba39fSStephan Aßmus return true; 4200e1ba39fSStephan Aßmus } 4210e1ba39fSStephan Aßmus 422128277c9SStephan Aßmus if (fMode == MOVE_POINT && 423128277c9SStephan Aßmus fSelection->CountItems() > 1 && 424128277c9SStephan Aßmus fSelection->Contains(fCurrentPathPoint)) { 425128277c9SStephan Aßmus fMode = TRANSLATE_POINTS; 426128277c9SStephan Aßmus } 427128277c9SStephan Aßmus 4284fac07a0SStephan Aßmus // apply the canvas view mouse filter depending on current mode 4294fac07a0SStephan Aßmus if (fMode == ADD_POINT || fMode == TRANSLATE_POINTS) 4304fac07a0SStephan Aßmus fCanvasView->FilterMouse(&where); 4314fac07a0SStephan Aßmus 432128277c9SStephan Aßmus BPoint canvasWhere = where; 433f67876a0SStephan Aßmus fCanvasView->ConvertToCanvas(&canvasWhere); 434128277c9SStephan Aßmus 435128277c9SStephan Aßmus // maybe we're changing some point, so we construct the 436128277c9SStephan Aßmus // "ChangePointCommand" here so that the point is remembered 437128277c9SStephan Aßmus // in its current state 4384fac07a0SStephan Aßmus // apply the canvas view mouse filter depending on current mode 439128277c9SStephan Aßmus delete fChangePointCommand; 440128277c9SStephan Aßmus fChangePointCommand = NULL; 441128277c9SStephan Aßmus switch (fMode) { 442128277c9SStephan Aßmus case TOGGLE_SHARP: 443128277c9SStephan Aßmus case TOGGLE_SHARP_IN: 444128277c9SStephan Aßmus case TOGGLE_SHARP_OUT: 445128277c9SStephan Aßmus case MOVE_POINT: 446128277c9SStephan Aßmus case MOVE_POINT_IN: 447128277c9SStephan Aßmus case MOVE_POINT_OUT: 448128277c9SStephan Aßmus case REMOVE_POINT_IN: 449128277c9SStephan Aßmus case REMOVE_POINT_OUT: 450128277c9SStephan Aßmus fChangePointCommand = new ChangePointCommand(fPath, 451128277c9SStephan Aßmus fCurrentPathPoint, 452128277c9SStephan Aßmus fSelection->Items(), 453128277c9SStephan Aßmus fSelection->CountItems()); 454128277c9SStephan Aßmus _Select(fCurrentPathPoint, fShiftDown); 455128277c9SStephan Aßmus break; 456128277c9SStephan Aßmus } 457128277c9SStephan Aßmus 458128277c9SStephan Aßmus // at this point we init doing something 459128277c9SStephan Aßmus switch (fMode) { 460128277c9SStephan Aßmus case ADD_POINT: 461128277c9SStephan Aßmus _AddPoint(canvasWhere); 462128277c9SStephan Aßmus break; 463128277c9SStephan Aßmus case INSERT_POINT: 464128277c9SStephan Aßmus _InsertPoint(canvasWhere, fCurrentPathPoint); 465128277c9SStephan Aßmus break; 466128277c9SStephan Aßmus 467128277c9SStephan Aßmus case TOGGLE_SHARP: 468128277c9SStephan Aßmus _SetSharp(fCurrentPathPoint); 469128277c9SStephan Aßmus // continue by dragging out the _connected_ in/out points 470128277c9SStephan Aßmus break; 471128277c9SStephan Aßmus case TOGGLE_SHARP_IN: 472128277c9SStephan Aßmus _SetInOutConnected(fCurrentPathPoint, false); 473128277c9SStephan Aßmus // continue by moving the "in" point 474128277c9SStephan Aßmus _SetMode(MOVE_POINT_IN); 475128277c9SStephan Aßmus break; 476128277c9SStephan Aßmus case TOGGLE_SHARP_OUT: 477128277c9SStephan Aßmus _SetInOutConnected(fCurrentPathPoint, false); 478128277c9SStephan Aßmus // continue by moving the "out" point 479128277c9SStephan Aßmus _SetMode(MOVE_POINT_OUT); 480128277c9SStephan Aßmus break; 481128277c9SStephan Aßmus 482128277c9SStephan Aßmus case MOVE_POINT: 483128277c9SStephan Aßmus case MOVE_POINT_IN: 484128277c9SStephan Aßmus case MOVE_POINT_OUT: 485128277c9SStephan Aßmus // the right thing happens since "fCurrentPathPoint" 486128277c9SStephan Aßmus // points to the correct index 487128277c9SStephan Aßmus break; 488128277c9SStephan Aßmus 489128277c9SStephan Aßmus case CLOSE_PATH: 490128277c9SStephan Aßmus // SetClosed(true, true); 491128277c9SStephan Aßmus break; 492128277c9SStephan Aßmus 493128277c9SStephan Aßmus case REMOVE_POINT: 494128277c9SStephan Aßmus if (fPath->CountPoints() == 1) { 495128277c9SStephan Aßmus // fCanvasView->Perform(new RemovePathCommand(this, fPath)); 496128277c9SStephan Aßmus } else { 497128277c9SStephan Aßmus fCanvasView->Perform(new RemovePointsCommand(fPath, 498128277c9SStephan Aßmus fCurrentPathPoint, 499128277c9SStephan Aßmus fSelection->Items(), 500128277c9SStephan Aßmus fSelection->CountItems())); 501128277c9SStephan Aßmus _RemovePoint(fCurrentPathPoint); 502128277c9SStephan Aßmus } 503128277c9SStephan Aßmus break; 504128277c9SStephan Aßmus case REMOVE_POINT_IN: 505128277c9SStephan Aßmus _RemovePointIn(fCurrentPathPoint); 506128277c9SStephan Aßmus break; 507128277c9SStephan Aßmus case REMOVE_POINT_OUT: 508128277c9SStephan Aßmus _RemovePointOut(fCurrentPathPoint); 509128277c9SStephan Aßmus break; 510128277c9SStephan Aßmus 511f4bd80a2SStephan Aßmus case SELECT_POINTS: { 512f4bd80a2SStephan Aßmus // TODO: this works so that you can deselect all points 513f4bd80a2SStephan Aßmus // when clicking outside the path even if pressing shift 514f4bd80a2SStephan Aßmus // in case the path is open... a better way would be 515f4bd80a2SStephan Aßmus // to deselect all on mouse up, if the mouse has not moved 516f4bd80a2SStephan Aßmus bool appendSelection; 517f4bd80a2SStephan Aßmus if (fPath->IsClosed()) 518f4bd80a2SStephan Aßmus appendSelection = fShiftDown; 519f4bd80a2SStephan Aßmus else 520f4bd80a2SStephan Aßmus appendSelection = fShiftDown && fCurrentPathPoint >= 0; 521f4bd80a2SStephan Aßmus 522f4bd80a2SStephan Aßmus if (!appendSelection) { 523128277c9SStephan Aßmus fSelection->MakeEmpty(); 524128277c9SStephan Aßmus _UpdateSelection(); 525128277c9SStephan Aßmus } 526128277c9SStephan Aßmus *fOldSelection = *fSelection; 527128277c9SStephan Aßmus if (fCurrentPathPoint >= 0) { 528f4bd80a2SStephan Aßmus _Select(fCurrentPathPoint, appendSelection); 529128277c9SStephan Aßmus } 530128277c9SStephan Aßmus fCanvasView->BeginRectTracking(BRect(where, where), 531128277c9SStephan Aßmus B_TRACK_RECT_CORNER); 532128277c9SStephan Aßmus break; 533128277c9SStephan Aßmus } 534f4bd80a2SStephan Aßmus } 535128277c9SStephan Aßmus 536128277c9SStephan Aßmus fTrackingStart = canvasWhere; 537128277c9SStephan Aßmus // remember the subpixel position 538128277c9SStephan Aßmus // so that MouseMoved() will work even before 539128277c9SStephan Aßmus // the integer position becomes different 540128277c9SStephan Aßmus fLastCanvasPos = where; 541f67876a0SStephan Aßmus fCanvasView->ConvertToCanvas(&fLastCanvasPos); 542128277c9SStephan Aßmus 543128277c9SStephan Aßmus // the reason to exclude the select mode 544128277c9SStephan Aßmus // is that the BView rect tracking does not 545128277c9SStephan Aßmus // scroll the rect starting point along with us 546128277c9SStephan Aßmus // (since we're doing no real scrolling) 547128277c9SStephan Aßmus // if (fMode != SELECT_POINTS) 548128277c9SStephan Aßmus // fCanvasView->SetAutoScrolling(true); 549128277c9SStephan Aßmus 550128277c9SStephan Aßmus UpdateCursor(); 551128277c9SStephan Aßmus 552128277c9SStephan Aßmus return true; 553128277c9SStephan Aßmus } 554128277c9SStephan Aßmus 555128277c9SStephan Aßmus // MouseMoved 556128277c9SStephan Aßmus void 557128277c9SStephan Aßmus PathManipulator::MouseMoved(BPoint where) 558128277c9SStephan Aßmus { 5594fac07a0SStephan Aßmus fCanvasView->FilterMouse(&where); 5604fac07a0SStephan Aßmus // NOTE: only filter mouse coords in mouse moved, no other 5614fac07a0SStephan Aßmus // mouse function 562128277c9SStephan Aßmus BPoint canvasWhere = where; 563f67876a0SStephan Aßmus fCanvasView->ConvertToCanvas(&canvasWhere); 564128277c9SStephan Aßmus 565128277c9SStephan Aßmus // since the tablet is generating mouse moved messages 566128277c9SStephan Aßmus // even if only the pressure changes (and not the actual mouse position) 567128277c9SStephan Aßmus // we insert this additional check to prevent too much calculation 568128277c9SStephan Aßmus if (fLastCanvasPos == canvasWhere) 569128277c9SStephan Aßmus return; 570128277c9SStephan Aßmus 571128277c9SStephan Aßmus fLastCanvasPos = canvasWhere; 572128277c9SStephan Aßmus 5730e1ba39fSStephan Aßmus if (fMode == TRANSFORM_POINTS) { 5740e1ba39fSStephan Aßmus if (fTransformBox) { 5750e1ba39fSStephan Aßmus fTransformBox->MouseMoved(where); 5760e1ba39fSStephan Aßmus } 5770e1ba39fSStephan Aßmus return; 5780e1ba39fSStephan Aßmus } 5790e1ba39fSStephan Aßmus 580128277c9SStephan Aßmus if (fMode == CLOSE_PATH) { 581128277c9SStephan Aßmus // continue by moving the point 582128277c9SStephan Aßmus _SetMode(MOVE_POINT); 583128277c9SStephan Aßmus delete fChangePointCommand; 584128277c9SStephan Aßmus fChangePointCommand = new ChangePointCommand(fPath, 585128277c9SStephan Aßmus fCurrentPathPoint, 586128277c9SStephan Aßmus fSelection->Items(), 587128277c9SStephan Aßmus fSelection->CountItems()); 588128277c9SStephan Aßmus } 589128277c9SStephan Aßmus 590128277c9SStephan Aßmus // if (!fPrecise) { 591128277c9SStephan Aßmus // float offset = fmod(fOutlineWidth, 2.0) / 2.0; 592128277c9SStephan Aßmus // canvasWhere.point += BPoint(offset, offset); 593128277c9SStephan Aßmus // } 594128277c9SStephan Aßmus 595128277c9SStephan Aßmus switch (fMode) { 596128277c9SStephan Aßmus case ADD_POINT: 597128277c9SStephan Aßmus case INSERT_POINT: 598128277c9SStephan Aßmus case TOGGLE_SHARP: 599128277c9SStephan Aßmus // drag the "out" control point, mirror the "in" control point 600128277c9SStephan Aßmus fPath->SetPointOut(fCurrentPathPoint, canvasWhere, true); 601128277c9SStephan Aßmus break; 602128277c9SStephan Aßmus case MOVE_POINT: 603128277c9SStephan Aßmus // drag all three control points at once 604128277c9SStephan Aßmus fPath->SetPoint(fCurrentPathPoint, canvasWhere); 605128277c9SStephan Aßmus break; 606128277c9SStephan Aßmus case MOVE_POINT_IN: 607128277c9SStephan Aßmus // drag in control point 608128277c9SStephan Aßmus fPath->SetPointIn(fCurrentPathPoint, canvasWhere); 609128277c9SStephan Aßmus break; 610128277c9SStephan Aßmus case MOVE_POINT_OUT: 611128277c9SStephan Aßmus // drag out control point 612128277c9SStephan Aßmus fPath->SetPointOut(fCurrentPathPoint, canvasWhere); 613128277c9SStephan Aßmus break; 614128277c9SStephan Aßmus 615128277c9SStephan Aßmus case SELECT_POINTS: { 616128277c9SStephan Aßmus // change the selection 617128277c9SStephan Aßmus BRect r; 618128277c9SStephan Aßmus r.left = min_c(fTrackingStart.x, canvasWhere.x); 619128277c9SStephan Aßmus r.top = min_c(fTrackingStart.y, canvasWhere.y); 620128277c9SStephan Aßmus r.right = max_c(fTrackingStart.x, canvasWhere.x); 621128277c9SStephan Aßmus r.bottom = max_c(fTrackingStart.y, canvasWhere.y); 622128277c9SStephan Aßmus _Select(r); 623128277c9SStephan Aßmus break; 624128277c9SStephan Aßmus } 625128277c9SStephan Aßmus 626128277c9SStephan Aßmus case TRANSLATE_POINTS: { 627128277c9SStephan Aßmus BPoint offset = canvasWhere - fTrackingStart; 628128277c9SStephan Aßmus _Nudge(offset); 629128277c9SStephan Aßmus fTrackingStart = canvasWhere; 630128277c9SStephan Aßmus break; 631128277c9SStephan Aßmus } 632128277c9SStephan Aßmus } 633128277c9SStephan Aßmus } 634128277c9SStephan Aßmus 635128277c9SStephan Aßmus // MouseUp 636128277c9SStephan Aßmus Command* 637128277c9SStephan Aßmus PathManipulator::MouseUp() 638128277c9SStephan Aßmus { 639128277c9SStephan Aßmus // prevent carrying out actions more than once by only 640128277c9SStephan Aßmus // doing it if "fMouseDown" is true at the point of 641128277c9SStephan Aßmus // entering this function 642128277c9SStephan Aßmus if (!fMouseDown) 643128277c9SStephan Aßmus return NULL; 644128277c9SStephan Aßmus fMouseDown = false; 645128277c9SStephan Aßmus 6460e1ba39fSStephan Aßmus if (fMode == TRANSFORM_POINTS) { 6470e1ba39fSStephan Aßmus if (fTransformBox) { 6480e1ba39fSStephan Aßmus return fTransformBox->MouseUp(); 6490e1ba39fSStephan Aßmus } 6500e1ba39fSStephan Aßmus return NULL; 6510e1ba39fSStephan Aßmus } 6520e1ba39fSStephan Aßmus 653128277c9SStephan Aßmus Command* command = NULL; 654128277c9SStephan Aßmus 655128277c9SStephan Aßmus switch (fMode) { 656128277c9SStephan Aßmus 657128277c9SStephan Aßmus case ADD_POINT: 658128277c9SStephan Aßmus command = fAddPointCommand; 659128277c9SStephan Aßmus fAddPointCommand = NULL; 660128277c9SStephan Aßmus _SetMode(MOVE_POINT_OUT); 661128277c9SStephan Aßmus break; 662128277c9SStephan Aßmus 663128277c9SStephan Aßmus case INSERT_POINT: 664128277c9SStephan Aßmus command = fInsertPointCommand; 665128277c9SStephan Aßmus fInsertPointCommand = NULL; 666128277c9SStephan Aßmus break; 667128277c9SStephan Aßmus 668128277c9SStephan Aßmus case SELECT_POINTS: 669128277c9SStephan Aßmus if (*fSelection != *fOldSelection) { 670128277c9SStephan Aßmus // command = new SelectPointsCommand(this, fPath, 671128277c9SStephan Aßmus // fOldSelection->Items(), 672128277c9SStephan Aßmus // fOldSelection->CountItems(), 673128277c9SStephan Aßmus // fSelection->Items(), 674128277c9SStephan Aßmus // fSelection->CountItems())); 675128277c9SStephan Aßmus } 676128277c9SStephan Aßmus fCanvasView->EndRectTracking(); 677128277c9SStephan Aßmus break; 678128277c9SStephan Aßmus 679128277c9SStephan Aßmus case TOGGLE_SHARP: 680128277c9SStephan Aßmus case TOGGLE_SHARP_IN: 681128277c9SStephan Aßmus case TOGGLE_SHARP_OUT: 682128277c9SStephan Aßmus case MOVE_POINT: 683128277c9SStephan Aßmus case MOVE_POINT_IN: 684128277c9SStephan Aßmus case MOVE_POINT_OUT: 685128277c9SStephan Aßmus case REMOVE_POINT_IN: 686128277c9SStephan Aßmus case REMOVE_POINT_OUT: 687128277c9SStephan Aßmus command = fChangePointCommand; 688128277c9SStephan Aßmus fChangePointCommand = NULL; 689128277c9SStephan Aßmus break; 690128277c9SStephan Aßmus 691128277c9SStephan Aßmus case TRANSLATE_POINTS: 6920e1ba39fSStephan Aßmus if (!fNudgeCommand) { 693128277c9SStephan Aßmus // select just the point that was clicked 694128277c9SStephan Aßmus *fOldSelection = *fSelection; 695128277c9SStephan Aßmus if (fCurrentPathPoint >= 0) { 696128277c9SStephan Aßmus _Select(fCurrentPathPoint, fShiftDown); 697128277c9SStephan Aßmus } 698128277c9SStephan Aßmus if (*fSelection != *fOldSelection) { 699128277c9SStephan Aßmus // command = new SelectPointsCommand(this, fPath, 700128277c9SStephan Aßmus // fOldSelection->Items(), 701128277c9SStephan Aßmus // fOldSelection->CountItems(), 702128277c9SStephan Aßmus // fSelection->Items(), 703128277c9SStephan Aßmus // fSelection->CountItems())); 704128277c9SStephan Aßmus } 7050e1ba39fSStephan Aßmus } else { 7060e1ba39fSStephan Aßmus command = _FinishNudging(); 7070e1ba39fSStephan Aßmus } 708128277c9SStephan Aßmus break; 709128277c9SStephan Aßmus } 710128277c9SStephan Aßmus 711128277c9SStephan Aßmus return command; 712128277c9SStephan Aßmus } 713128277c9SStephan Aßmus 714128277c9SStephan Aßmus // MouseOver 715128277c9SStephan Aßmus bool 716128277c9SStephan Aßmus PathManipulator::MouseOver(BPoint where) 717128277c9SStephan Aßmus { 7180e1ba39fSStephan Aßmus if (fMode == TRANSFORM_POINTS) { 7190e1ba39fSStephan Aßmus if (fTransformBox) { 7200e1ba39fSStephan Aßmus return fTransformBox->MouseOver(where); 7210e1ba39fSStephan Aßmus } 7220e1ba39fSStephan Aßmus return false; 7230e1ba39fSStephan Aßmus } 7240e1ba39fSStephan Aßmus 725128277c9SStephan Aßmus BPoint canvasWhere = where; 726f67876a0SStephan Aßmus fCanvasView->ConvertToCanvas(&canvasWhere); 727128277c9SStephan Aßmus 728128277c9SStephan Aßmus // since the tablet is generating mouse moved messages 729128277c9SStephan Aßmus // even if only the pressure changes (and not the actual mouse position) 730128277c9SStephan Aßmus // we insert this additional check to prevent too much calculation 731128277c9SStephan Aßmus if (fMouseDown && fLastCanvasPos == canvasWhere) 732128277c9SStephan Aßmus return false; 733128277c9SStephan Aßmus 734128277c9SStephan Aßmus fLastCanvasPos = canvasWhere; 735128277c9SStephan Aßmus 736128277c9SStephan Aßmus // hit testing 737128277c9SStephan Aßmus // (use a subpixel mouse pos) 738f67876a0SStephan Aßmus fCanvasView->ConvertToCanvas(&where); 739128277c9SStephan Aßmus _SetModeForMousePos(where); 740128277c9SStephan Aßmus 741128277c9SStephan Aßmus // TODO: always true? 742128277c9SStephan Aßmus return true; 743128277c9SStephan Aßmus } 744128277c9SStephan Aßmus 745128277c9SStephan Aßmus // DoubleClicked 746128277c9SStephan Aßmus bool 747128277c9SStephan Aßmus PathManipulator::DoubleClicked(BPoint where) 748128277c9SStephan Aßmus { 749128277c9SStephan Aßmus return false; 750128277c9SStephan Aßmus } 751128277c9SStephan Aßmus 752f4bd80a2SStephan Aßmus // ShowContextMenu 753f4bd80a2SStephan Aßmus bool 754f4bd80a2SStephan Aßmus PathManipulator::ShowContextMenu(BPoint where) 755f4bd80a2SStephan Aßmus { 756f4bd80a2SStephan Aßmus BPopUpMenu* menu = new BPopUpMenu("context menu", false, false); 757f4bd80a2SStephan Aßmus BMessage* message; 758f4bd80a2SStephan Aßmus BMenuItem* item; 759f4bd80a2SStephan Aßmus 760f4bd80a2SStephan Aßmus bool hasSelection = fSelection->CountItems() > 0; 761f4bd80a2SStephan Aßmus 762f4bd80a2SStephan Aßmus message = new BMessage(B_SELECT_ALL); 763f4bd80a2SStephan Aßmus item = new BMenuItem("Select All", message, 'A'); 764f4bd80a2SStephan Aßmus menu->AddItem(item); 765f4bd80a2SStephan Aßmus 766f4bd80a2SStephan Aßmus menu->AddSeparatorItem(); 767f4bd80a2SStephan Aßmus 768f4bd80a2SStephan Aßmus message = new BMessage(MSG_TRANSFORM); 769f4bd80a2SStephan Aßmus item = new BMenuItem("Transform", message); 770f4bd80a2SStephan Aßmus item->SetEnabled(hasSelection); 771f4bd80a2SStephan Aßmus menu->AddItem(item); 772f4bd80a2SStephan Aßmus 773f4bd80a2SStephan Aßmus message = new BMessage(MSG_SPLIT_POINTS); 774f4bd80a2SStephan Aßmus item = new BMenuItem("Split", message); 775f4bd80a2SStephan Aßmus item->SetEnabled(hasSelection); 776f4bd80a2SStephan Aßmus menu->AddItem(item); 777f4bd80a2SStephan Aßmus 778*7c4b3726SStephan Aßmus message = new BMessage(MSG_FLIP_POINTS); 779*7c4b3726SStephan Aßmus item = new BMenuItem("Flip", message); 780*7c4b3726SStephan Aßmus item->SetEnabled(hasSelection); 781*7c4b3726SStephan Aßmus menu->AddItem(item); 782*7c4b3726SStephan Aßmus 783f4bd80a2SStephan Aßmus message = new BMessage(MSG_REMOVE_POINTS); 784f4bd80a2SStephan Aßmus item = new BMenuItem("Remove", message, 'A'); 785f4bd80a2SStephan Aßmus item->SetEnabled(hasSelection); 786f4bd80a2SStephan Aßmus menu->AddItem(item); 787f4bd80a2SStephan Aßmus 788f4bd80a2SStephan Aßmus // go 789f4bd80a2SStephan Aßmus menu->SetTargetForItems(fCanvasView); 790f4bd80a2SStephan Aßmus menu->SetAsyncAutoDestruct(true); 791f4bd80a2SStephan Aßmus menu->SetFont(be_plain_font); 792f4bd80a2SStephan Aßmus where = fCanvasView->ConvertToScreen(where); 793f4bd80a2SStephan Aßmus BRect mouseRect(where, where); 794f4bd80a2SStephan Aßmus mouseRect.InsetBy(-10.0, -10.0); 795f4bd80a2SStephan Aßmus where += BPoint(5.0, 5.0); 796f4bd80a2SStephan Aßmus menu->Go(where, true, false, mouseRect, true); 797f4bd80a2SStephan Aßmus 798f4bd80a2SStephan Aßmus return true; 799f4bd80a2SStephan Aßmus } 800f4bd80a2SStephan Aßmus 801f4bd80a2SStephan Aßmus // #pragma mark - 802f4bd80a2SStephan Aßmus 803128277c9SStephan Aßmus // Bounds 804128277c9SStephan Aßmus BRect 805128277c9SStephan Aßmus PathManipulator::Bounds() 806128277c9SStephan Aßmus { 807f67876a0SStephan Aßmus BRect r = _ControlPointRect(); 808f67876a0SStephan Aßmus fCanvasView->ConvertFromCanvas(&r); 809f67876a0SStephan Aßmus return r; 810128277c9SStephan Aßmus } 811128277c9SStephan Aßmus 812128277c9SStephan Aßmus // TrackingBounds 813128277c9SStephan Aßmus BRect 814128277c9SStephan Aßmus PathManipulator::TrackingBounds(BView* withinView) 815128277c9SStephan Aßmus { 816128277c9SStephan Aßmus return withinView->Bounds(); 817128277c9SStephan Aßmus } 818128277c9SStephan Aßmus 819128277c9SStephan Aßmus // #pragma mark - 820128277c9SStephan Aßmus 821128277c9SStephan Aßmus // MessageReceived 822128277c9SStephan Aßmus bool 823128277c9SStephan Aßmus PathManipulator::MessageReceived(BMessage* message, Command** _command) 824128277c9SStephan Aßmus { 825128277c9SStephan Aßmus bool result = true; 826128277c9SStephan Aßmus switch (message->what) { 827f4bd80a2SStephan Aßmus case MSG_TRANSFORM: 828128277c9SStephan Aßmus if (!fSelection->IsEmpty()) 829128277c9SStephan Aßmus _SetMode(TRANSFORM_POINTS); 830128277c9SStephan Aßmus break; 831f4bd80a2SStephan Aßmus case MSG_REMOVE_POINTS: 832128277c9SStephan Aßmus *_command = _Delete(); 833128277c9SStephan Aßmus break; 834f4bd80a2SStephan Aßmus case MSG_SPLIT_POINTS: 835f4bd80a2SStephan Aßmus *_command = new SplitPointsCommand(fPath, 836f4bd80a2SStephan Aßmus fSelection->Items(), 837f4bd80a2SStephan Aßmus fSelection->CountItems()); 838f4bd80a2SStephan Aßmus break; 839*7c4b3726SStephan Aßmus case MSG_FLIP_POINTS: 840*7c4b3726SStephan Aßmus *_command = new FlipPointsCommand(fPath, 841*7c4b3726SStephan Aßmus fSelection->Items(), 842*7c4b3726SStephan Aßmus fSelection->CountItems()); 843*7c4b3726SStephan Aßmus break; 844128277c9SStephan Aßmus case B_SELECT_ALL: { 845128277c9SStephan Aßmus *fOldSelection = *fSelection; 846128277c9SStephan Aßmus fSelection->MakeEmpty(); 847128277c9SStephan Aßmus int32 count = fPath->CountPoints(); 848128277c9SStephan Aßmus for (int32 i = 0; i < count; i++) 849128277c9SStephan Aßmus fSelection->Add(i); 850128277c9SStephan Aßmus if (*fOldSelection != *fSelection) { 851128277c9SStephan Aßmus // *_command = new SelectPointsCommand(this, fPath, 852128277c9SStephan Aßmus // fOldSelection->Items(), 853128277c9SStephan Aßmus // fOldSelection->CountItems(), 854128277c9SStephan Aßmus // fSelection->Items(), 855128277c9SStephan Aßmus // fSelection->CountItems())); 856128277c9SStephan Aßmus count = fSelection->CountItems(); 857128277c9SStephan Aßmus int32 indices[count]; 858128277c9SStephan Aßmus memcpy(indices, fSelection->Items(), count * sizeof(int32)); 859128277c9SStephan Aßmus _Select(indices, count); 860128277c9SStephan Aßmus } 861128277c9SStephan Aßmus break; 862128277c9SStephan Aßmus } 863128277c9SStephan Aßmus default: 864128277c9SStephan Aßmus result = false; 865128277c9SStephan Aßmus break; 866128277c9SStephan Aßmus } 867128277c9SStephan Aßmus return result; 868128277c9SStephan Aßmus } 869128277c9SStephan Aßmus 870128277c9SStephan Aßmus 871128277c9SStephan Aßmus // ModifiersChanged 872128277c9SStephan Aßmus void 873128277c9SStephan Aßmus PathManipulator::ModifiersChanged(uint32 modifiers) 874128277c9SStephan Aßmus { 875128277c9SStephan Aßmus fCommandDown = modifiers & B_COMMAND_KEY; 876128277c9SStephan Aßmus fOptionDown = modifiers & B_CONTROL_KEY; 877128277c9SStephan Aßmus fShiftDown = modifiers & B_SHIFT_KEY; 878128277c9SStephan Aßmus fAltDown = modifiers & B_OPTION_KEY; 879128277c9SStephan Aßmus 8800e1ba39fSStephan Aßmus if (fTransformBox) { 8810e1ba39fSStephan Aßmus fTransformBox->ModifiersChanged(modifiers); 8820e1ba39fSStephan Aßmus return; 8830e1ba39fSStephan Aßmus } 884128277c9SStephan Aßmus // reevaluate mode 885128277c9SStephan Aßmus if (!fMouseDown) 886128277c9SStephan Aßmus _SetModeForMousePos(fLastCanvasPos); 887128277c9SStephan Aßmus } 888128277c9SStephan Aßmus 889128277c9SStephan Aßmus // HandleKeyDown 890128277c9SStephan Aßmus bool 891128277c9SStephan Aßmus PathManipulator::HandleKeyDown(uint32 key, uint32 modifiers, Command** _command) 892128277c9SStephan Aßmus { 893128277c9SStephan Aßmus bool result = true; 894128277c9SStephan Aßmus 895128277c9SStephan Aßmus float nudgeDist = 1.0; 896f67876a0SStephan Aßmus if (modifiers & B_SHIFT_KEY) 897f67876a0SStephan Aßmus nudgeDist /= fCanvasView->ZoomLevel(); 898128277c9SStephan Aßmus 899128277c9SStephan Aßmus switch (key) { 900128277c9SStephan Aßmus // commit 901128277c9SStephan Aßmus case B_RETURN: 9020e1ba39fSStephan Aßmus if (fTransformBox) { 9034fac07a0SStephan Aßmus _SetTransformBox(NULL); 9044fac07a0SStephan Aßmus }// else 905128277c9SStephan Aßmus // _Perform(); 906128277c9SStephan Aßmus break; 907128277c9SStephan Aßmus // cancel 908128277c9SStephan Aßmus case B_ESCAPE: 9090e1ba39fSStephan Aßmus if (fTransformBox) { 9100e1ba39fSStephan Aßmus fTransformBox->Cancel(); 9114fac07a0SStephan Aßmus _SetTransformBox(NULL); 9120e1ba39fSStephan Aßmus } else if (fFallBackMode == NEW_PATH) { 913128277c9SStephan Aßmus fFallBackMode = SELECT_POINTS; 9144fac07a0SStephan Aßmus _SetTransformBox(NULL); 9154fac07a0SStephan Aßmus }// else 916128277c9SStephan Aßmus // _Cancel(); 917128277c9SStephan Aßmus break; 918128277c9SStephan Aßmus case 't': 919128277c9SStephan Aßmus case 'T': 920128277c9SStephan Aßmus if (!fSelection->IsEmpty()) 921128277c9SStephan Aßmus _SetMode(TRANSFORM_POINTS); 922128277c9SStephan Aßmus else 923128277c9SStephan Aßmus result = false; 924128277c9SStephan Aßmus break; 925128277c9SStephan Aßmus // nudging 926128277c9SStephan Aßmus case B_UP_ARROW: 927128277c9SStephan Aßmus _Nudge(BPoint(0.0, -nudgeDist)); 928128277c9SStephan Aßmus break; 929128277c9SStephan Aßmus case B_DOWN_ARROW: 930128277c9SStephan Aßmus _Nudge(BPoint(0.0, nudgeDist)); 931128277c9SStephan Aßmus break; 932128277c9SStephan Aßmus case B_LEFT_ARROW: 933128277c9SStephan Aßmus _Nudge(BPoint(-nudgeDist, 0.0)); 934128277c9SStephan Aßmus break; 935128277c9SStephan Aßmus case B_RIGHT_ARROW: 936128277c9SStephan Aßmus _Nudge(BPoint(nudgeDist, 0.0)); 937128277c9SStephan Aßmus break; 938128277c9SStephan Aßmus 939128277c9SStephan Aßmus case B_DELETE: 940128277c9SStephan Aßmus if (!fSelection->IsEmpty()) 941128277c9SStephan Aßmus *_command = _Delete(); 942128277c9SStephan Aßmus else 943128277c9SStephan Aßmus result = false; 944128277c9SStephan Aßmus break; 945128277c9SStephan Aßmus 946128277c9SStephan Aßmus default: 947128277c9SStephan Aßmus result = false; 948128277c9SStephan Aßmus } 949128277c9SStephan Aßmus return result; 950128277c9SStephan Aßmus } 951128277c9SStephan Aßmus 952128277c9SStephan Aßmus // HandleKeyUp 953128277c9SStephan Aßmus bool 954128277c9SStephan Aßmus PathManipulator::HandleKeyUp(uint32 key, uint32 modifiers, Command** _command) 955128277c9SStephan Aßmus { 956128277c9SStephan Aßmus bool handled = true; 957128277c9SStephan Aßmus switch (key) { 958128277c9SStephan Aßmus // nudging 959128277c9SStephan Aßmus case B_UP_ARROW: 960128277c9SStephan Aßmus case B_DOWN_ARROW: 961128277c9SStephan Aßmus case B_LEFT_ARROW: 962128277c9SStephan Aßmus case B_RIGHT_ARROW: 9630e1ba39fSStephan Aßmus *_command = _FinishNudging(); 964128277c9SStephan Aßmus break; 965128277c9SStephan Aßmus default: 966128277c9SStephan Aßmus handled = false; 967128277c9SStephan Aßmus break; 968128277c9SStephan Aßmus } 969128277c9SStephan Aßmus return handled; 970128277c9SStephan Aßmus } 971128277c9SStephan Aßmus 972128277c9SStephan Aßmus // UpdateCursor 973*7c4b3726SStephan Aßmus bool 974128277c9SStephan Aßmus PathManipulator::UpdateCursor() 975128277c9SStephan Aßmus { 976*7c4b3726SStephan Aßmus if (fTransformBox) 977*7c4b3726SStephan Aßmus return fTransformBox->UpdateCursor(); 978*7c4b3726SStephan Aßmus 979128277c9SStephan Aßmus const uchar* cursorData; 980128277c9SStephan Aßmus switch (fMode) { 981128277c9SStephan Aßmus case ADD_POINT: 982128277c9SStephan Aßmus cursorData = kPathAddCursor; 983128277c9SStephan Aßmus break; 984128277c9SStephan Aßmus case INSERT_POINT: 985128277c9SStephan Aßmus cursorData = kPathInsertCursor; 986128277c9SStephan Aßmus break; 987128277c9SStephan Aßmus case MOVE_POINT: 988128277c9SStephan Aßmus case MOVE_POINT_IN: 989128277c9SStephan Aßmus case MOVE_POINT_OUT: 990128277c9SStephan Aßmus case TRANSLATE_POINTS: 991128277c9SStephan Aßmus cursorData = kPathMoveCursor; 992128277c9SStephan Aßmus break; 993128277c9SStephan Aßmus case CLOSE_PATH: 994128277c9SStephan Aßmus cursorData = kPathCloseCursor; 995128277c9SStephan Aßmus break; 996128277c9SStephan Aßmus case TOGGLE_SHARP: 997128277c9SStephan Aßmus case TOGGLE_SHARP_IN: 998128277c9SStephan Aßmus case TOGGLE_SHARP_OUT: 999128277c9SStephan Aßmus cursorData = kPathSharpCursor; 1000128277c9SStephan Aßmus break; 1001128277c9SStephan Aßmus case REMOVE_POINT: 1002128277c9SStephan Aßmus case REMOVE_POINT_IN: 1003128277c9SStephan Aßmus case REMOVE_POINT_OUT: 1004128277c9SStephan Aßmus cursorData = kPathRemoveCursor; 1005128277c9SStephan Aßmus break; 1006128277c9SStephan Aßmus case SELECT_POINTS: 1007128277c9SStephan Aßmus cursorData = kPathSelectCursor; 1008128277c9SStephan Aßmus break; 1009128277c9SStephan Aßmus 1010128277c9SStephan Aßmus case SELECT_SUB_PATH: 1011128277c9SStephan Aßmus cursorData = B_HAND_CURSOR; 1012128277c9SStephan Aßmus break; 1013128277c9SStephan Aßmus 1014128277c9SStephan Aßmus case UNDEFINED: 1015128277c9SStephan Aßmus default: 1016128277c9SStephan Aßmus cursorData = kStopCursor; 1017128277c9SStephan Aßmus break; 1018128277c9SStephan Aßmus } 1019128277c9SStephan Aßmus BCursor cursor(cursorData); 1020128277c9SStephan Aßmus fCanvasView->SetViewCursor(&cursor, true); 1021128277c9SStephan Aßmus fCanvasView->Sync(); 1022*7c4b3726SStephan Aßmus 1023*7c4b3726SStephan Aßmus return true; 1024128277c9SStephan Aßmus } 1025128277c9SStephan Aßmus 1026128277c9SStephan Aßmus // AttachedToView 1027128277c9SStephan Aßmus void 1028128277c9SStephan Aßmus PathManipulator::AttachedToView(BView* view) 1029128277c9SStephan Aßmus { 1030f67876a0SStephan Aßmus fCanvasView = dynamic_cast<CanvasView*>(view); 1031128277c9SStephan Aßmus } 1032128277c9SStephan Aßmus 1033128277c9SStephan Aßmus // DetachedFromView 1034128277c9SStephan Aßmus void 1035128277c9SStephan Aßmus PathManipulator::DetachedFromView(BView* view) 1036128277c9SStephan Aßmus { 1037128277c9SStephan Aßmus fCanvasView = NULL; 1038128277c9SStephan Aßmus } 1039128277c9SStephan Aßmus 1040128277c9SStephan Aßmus // #pragma mark - 1041128277c9SStephan Aßmus 1042128277c9SStephan Aßmus // ObjectChanged 1043128277c9SStephan Aßmus void 1044128277c9SStephan Aßmus PathManipulator::ObjectChanged(const Observable* object) 1045128277c9SStephan Aßmus { 1046128277c9SStephan Aßmus // TODO: refine VectorPath listener interface and 1047128277c9SStephan Aßmus // implement more efficiently 1048128277c9SStephan Aßmus BRect currentBounds = _ControlPointRect(); 1049128277c9SStephan Aßmus _InvalidateCanvas(currentBounds | fPreviousBounds); 1050128277c9SStephan Aßmus fPreviousBounds = currentBounds; 1051128277c9SStephan Aßmus 1052128277c9SStephan Aßmus // reevaluate mode 10530e1ba39fSStephan Aßmus if (!fMouseDown && !fTransformBox) 1054128277c9SStephan Aßmus _SetModeForMousePos(fLastCanvasPos); 1055128277c9SStephan Aßmus } 1056128277c9SStephan Aßmus 1057128277c9SStephan Aßmus // #pragma mark - 1058128277c9SStephan Aßmus 105905fd3818SStephan Aßmus // PointAdded 106005fd3818SStephan Aßmus void 106105fd3818SStephan Aßmus PathManipulator::PointAdded(int32 index) 106205fd3818SStephan Aßmus { 106305fd3818SStephan Aßmus ObjectChanged(fPath); 106405fd3818SStephan Aßmus } 106505fd3818SStephan Aßmus 106605fd3818SStephan Aßmus // PointRemoved 106705fd3818SStephan Aßmus void 106805fd3818SStephan Aßmus PathManipulator::PointRemoved(int32 index) 106905fd3818SStephan Aßmus { 10700e1ba39fSStephan Aßmus fSelection->Remove(index); 107105fd3818SStephan Aßmus ObjectChanged(fPath); 107205fd3818SStephan Aßmus } 107305fd3818SStephan Aßmus 107405fd3818SStephan Aßmus // PointChanged 107505fd3818SStephan Aßmus void 107605fd3818SStephan Aßmus PathManipulator::PointChanged(int32 index) 107705fd3818SStephan Aßmus { 107805fd3818SStephan Aßmus ObjectChanged(fPath); 107905fd3818SStephan Aßmus } 108005fd3818SStephan Aßmus 108105fd3818SStephan Aßmus // PathChanged 108205fd3818SStephan Aßmus void 108305fd3818SStephan Aßmus PathManipulator::PathChanged() 108405fd3818SStephan Aßmus { 108505fd3818SStephan Aßmus ObjectChanged(fPath); 108605fd3818SStephan Aßmus } 108705fd3818SStephan Aßmus 108805fd3818SStephan Aßmus // PathClosedChanged 108905fd3818SStephan Aßmus void 109005fd3818SStephan Aßmus PathManipulator::PathClosedChanged() 109105fd3818SStephan Aßmus { 109205fd3818SStephan Aßmus ObjectChanged(fPath); 109305fd3818SStephan Aßmus } 109405fd3818SStephan Aßmus 109505fd3818SStephan Aßmus // PathReversed 109605fd3818SStephan Aßmus void 109705fd3818SStephan Aßmus PathManipulator::PathReversed() 109805fd3818SStephan Aßmus { 10990e1ba39fSStephan Aßmus // reverse selection along with path 11000e1ba39fSStephan Aßmus int32 count = fSelection->CountItems(); 11010e1ba39fSStephan Aßmus int32 pointCount = fPath->CountPoints(); 11020e1ba39fSStephan Aßmus if (count > 0) { 11030e1ba39fSStephan Aßmus Selection temp; 11040e1ba39fSStephan Aßmus for (int32 i = 0; i < count; i++) { 11050e1ba39fSStephan Aßmus temp.Add((pointCount - 1) - fSelection->IndexAt(i)); 11060e1ba39fSStephan Aßmus } 11070e1ba39fSStephan Aßmus *fSelection = temp; 11080e1ba39fSStephan Aßmus } 11090e1ba39fSStephan Aßmus 111005fd3818SStephan Aßmus ObjectChanged(fPath); 111105fd3818SStephan Aßmus } 111205fd3818SStephan Aßmus 111305fd3818SStephan Aßmus // #pragma mark - 111405fd3818SStephan Aßmus 1115128277c9SStephan Aßmus // ControlFlags 1116128277c9SStephan Aßmus uint32 1117128277c9SStephan Aßmus PathManipulator::ControlFlags() const 1118128277c9SStephan Aßmus { 1119128277c9SStephan Aßmus uint32 flags = 0; 1120128277c9SStephan Aßmus 1121128277c9SStephan Aßmus // flags |= SHAPE_UI_FLAGS_CAN_REVERSE_PATH; 1122128277c9SStephan Aßmus // 1123128277c9SStephan Aßmus // if (!fSelection->IsEmpty()) 1124128277c9SStephan Aßmus // flags |= SHAPE_UI_FLAGS_HAS_SELECTION; 1125128277c9SStephan Aßmus // if (fPath->CountPoints() > 1) 1126128277c9SStephan Aßmus // flags |= SHAPE_UI_FLAGS_CAN_CLOSE_PATH; 1127128277c9SStephan Aßmus // if (fPath->IsClosed()) 1128128277c9SStephan Aßmus // flags |= SHAPE_UI_FLAGS_PATH_IS_CLOSED; 11290e1ba39fSStephan Aßmus // if (fTransformBox) 11300e1ba39fSStephan Aßmus // flags |= SHAPE_UI_FLAGS_IS_TRANSFORMING; 1131128277c9SStephan Aßmus 1132128277c9SStephan Aßmus return flags; 1133128277c9SStephan Aßmus } 1134128277c9SStephan Aßmus 1135128277c9SStephan Aßmus // ReversePath 1136128277c9SStephan Aßmus void 1137128277c9SStephan Aßmus PathManipulator::ReversePath() 1138128277c9SStephan Aßmus { 1139128277c9SStephan Aßmus int32 count = fSelection->CountItems(); 1140128277c9SStephan Aßmus int32 pointCount = fPath->CountPoints(); 1141128277c9SStephan Aßmus if (count > 0) { 1142128277c9SStephan Aßmus Selection temp; 1143128277c9SStephan Aßmus for (int32 i = 0; i < count; i++) { 1144128277c9SStephan Aßmus temp.Add((pointCount - 1) - fSelection->IndexAt(i)); 1145128277c9SStephan Aßmus } 1146128277c9SStephan Aßmus *fSelection = temp; 1147128277c9SStephan Aßmus } 1148128277c9SStephan Aßmus fPath->Reverse(); 1149128277c9SStephan Aßmus } 1150128277c9SStephan Aßmus 1151128277c9SStephan Aßmus // #pragma mark - 1152128277c9SStephan Aßmus 1153128277c9SStephan Aßmus // _SetMode 1154128277c9SStephan Aßmus void 1155128277c9SStephan Aßmus PathManipulator::_SetMode(uint32 mode) 1156128277c9SStephan Aßmus { 1157128277c9SStephan Aßmus if (fMode != mode) { 1158128277c9SStephan Aßmus //printf("switching mode: %s -> %s\n", string_for_mode(fMode), string_for_mode(mode)); 1159128277c9SStephan Aßmus fMode = mode; 1160128277c9SStephan Aßmus 11610e1ba39fSStephan Aßmus if (fMode == TRANSFORM_POINTS) { 11620e1ba39fSStephan Aßmus _SetTransformBox(new TransformPointsBox(fCanvasView, 11630e1ba39fSStephan Aßmus this, 11640e1ba39fSStephan Aßmus fPath, 11650e1ba39fSStephan Aßmus fSelection->Items(), 11660e1ba39fSStephan Aßmus fSelection->CountItems())); 11670e1ba39fSStephan Aßmus // fCanvasView->Perform(new EnterTransformPointsCommand(this, 11680e1ba39fSStephan Aßmus // fSelection->Items(), 11690e1ba39fSStephan Aßmus // fSelection->CountItems())); 11700e1ba39fSStephan Aßmus } else { 11710e1ba39fSStephan Aßmus if (fTransformBox) 11720e1ba39fSStephan Aßmus _SetTransformBox(NULL); 11730e1ba39fSStephan Aßmus } 11740e1ba39fSStephan Aßmus 1175128277c9SStephan Aßmus if (BWindow* window = fCanvasView->Window()) { 1176128277c9SStephan Aßmus window->PostMessage(MSG_UPDATE_SHAPE_UI); 1177128277c9SStephan Aßmus } 1178128277c9SStephan Aßmus UpdateCursor(); 1179128277c9SStephan Aßmus } 1180128277c9SStephan Aßmus } 1181128277c9SStephan Aßmus 11820e1ba39fSStephan Aßmus 11830e1ba39fSStephan Aßmus // _SetTransformBox 11840e1ba39fSStephan Aßmus void 11850e1ba39fSStephan Aßmus PathManipulator::_SetTransformBox(TransformPointsBox* transformBox) 11860e1ba39fSStephan Aßmus { 11870e1ba39fSStephan Aßmus if (fTransformBox == transformBox) 11880e1ba39fSStephan Aßmus return; 11890e1ba39fSStephan Aßmus 11900e1ba39fSStephan Aßmus BRect dirty(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN); 11910e1ba39fSStephan Aßmus if (fTransformBox) { 11920e1ba39fSStephan Aßmus // get rid of transform box display 11930e1ba39fSStephan Aßmus dirty = fTransformBox->Bounds(); 11940e1ba39fSStephan Aßmus delete fTransformBox; 11950e1ba39fSStephan Aßmus } 11960e1ba39fSStephan Aßmus 11970e1ba39fSStephan Aßmus fTransformBox = transformBox; 11980e1ba39fSStephan Aßmus 11994fac07a0SStephan Aßmus // TODO: this is weird, fMode should only be set in _SetMode, not 12004fac07a0SStephan Aßmus // here as well, also this method could be called this way 12014fac07a0SStephan Aßmus // _SetModeForMousePos -> _SetMode -> _SetTransformBox 12024fac07a0SStephan Aßmus // and then below it does _SetModeForMousePos again... 12030e1ba39fSStephan Aßmus if (fTransformBox) { 12040e1ba39fSStephan Aßmus fTransformBox->MouseMoved(fLastCanvasPos); 12050e1ba39fSStephan Aßmus if (fMode != TRANSFORM_POINTS) { 12060e1ba39fSStephan Aßmus fMode = TRANSFORM_POINTS; 12070e1ba39fSStephan Aßmus } 12080e1ba39fSStephan Aßmus dirty = dirty | fTransformBox->Bounds(); 12090e1ba39fSStephan Aßmus } else { 12100e1ba39fSStephan Aßmus if (fMode == TRANSFORM_POINTS) { 12110e1ba39fSStephan Aßmus _SetModeForMousePos(fLastCanvasPos); 12120e1ba39fSStephan Aßmus } 12130e1ba39fSStephan Aßmus } 12140e1ba39fSStephan Aßmus 12150e1ba39fSStephan Aßmus if (dirty.IsValid()) { 12160e1ba39fSStephan Aßmus dirty.InsetBy(-8, -8); 12170e1ba39fSStephan Aßmus fCanvasView->Invalidate(dirty); 12180e1ba39fSStephan Aßmus } 12190e1ba39fSStephan Aßmus } 12200e1ba39fSStephan Aßmus 1221128277c9SStephan Aßmus // _AddPoint 1222128277c9SStephan Aßmus void 1223128277c9SStephan Aßmus PathManipulator::_AddPoint(BPoint where) 1224128277c9SStephan Aßmus { 1225128277c9SStephan Aßmus if (fPath->AddPoint(where)) { 1226128277c9SStephan Aßmus fCurrentPathPoint = fPath->CountPoints() - 1; 1227128277c9SStephan Aßmus 1228128277c9SStephan Aßmus delete fAddPointCommand; 1229128277c9SStephan Aßmus fAddPointCommand = new AddPointCommand(fPath, fCurrentPathPoint, 1230128277c9SStephan Aßmus fSelection->Items(), 1231128277c9SStephan Aßmus fSelection->CountItems()); 1232128277c9SStephan Aßmus 1233128277c9SStephan Aßmus _Select(fCurrentPathPoint, fShiftDown); 1234128277c9SStephan Aßmus } 1235128277c9SStephan Aßmus } 1236128277c9SStephan Aßmus 1237128277c9SStephan Aßmus // scale_point 1238128277c9SStephan Aßmus BPoint 1239128277c9SStephan Aßmus scale_point(BPoint a, BPoint b, float scale) 1240128277c9SStephan Aßmus { 1241128277c9SStephan Aßmus return BPoint(a.x + (b.x - a.x) * scale, 1242128277c9SStephan Aßmus a.y + (b.y - a.y) * scale); 1243128277c9SStephan Aßmus } 1244128277c9SStephan Aßmus 1245128277c9SStephan Aßmus // _InsertPoint 1246128277c9SStephan Aßmus void 1247128277c9SStephan Aßmus PathManipulator::_InsertPoint(BPoint where, int32 index) 1248128277c9SStephan Aßmus { 1249128277c9SStephan Aßmus double scale; 1250128277c9SStephan Aßmus 1251128277c9SStephan Aßmus BPoint point; 1252128277c9SStephan Aßmus BPoint pointIn; 1253128277c9SStephan Aßmus BPoint pointOut; 1254128277c9SStephan Aßmus 1255128277c9SStephan Aßmus BPoint previous; 1256128277c9SStephan Aßmus BPoint previousOut; 1257128277c9SStephan Aßmus BPoint next; 1258128277c9SStephan Aßmus BPoint nextIn; 1259128277c9SStephan Aßmus 1260128277c9SStephan Aßmus if (fPath->FindBezierScale(index - 1, where, &scale) 1261128277c9SStephan Aßmus && scale >= 0.0 && scale <= 1.0 1262128277c9SStephan Aßmus && fPath->GetPoint(index - 1, scale, point)) { 1263128277c9SStephan Aßmus 1264128277c9SStephan Aßmus fPath->GetPointAt(index - 1, previous); 1265128277c9SStephan Aßmus fPath->GetPointOutAt(index - 1, previousOut); 1266128277c9SStephan Aßmus fPath->GetPointAt(index, next); 1267128277c9SStephan Aßmus fPath->GetPointInAt(index, nextIn); 1268128277c9SStephan Aßmus 1269128277c9SStephan Aßmus where = scale_point(previousOut, nextIn, scale); 1270128277c9SStephan Aßmus 1271128277c9SStephan Aßmus previousOut = scale_point(previous, previousOut, scale); 1272128277c9SStephan Aßmus nextIn = scale_point(next, nextIn, 1 - scale); 1273128277c9SStephan Aßmus pointIn = scale_point(previousOut, where, scale); 1274128277c9SStephan Aßmus pointOut = scale_point(nextIn, where, 1 - scale); 1275128277c9SStephan Aßmus 1276128277c9SStephan Aßmus if (fPath->AddPoint(point, index)) { 1277128277c9SStephan Aßmus 1278128277c9SStephan Aßmus fPath->SetPointIn(index, pointIn); 1279128277c9SStephan Aßmus fPath->SetPointOut(index, pointOut); 1280128277c9SStephan Aßmus 1281128277c9SStephan Aßmus delete fInsertPointCommand; 1282128277c9SStephan Aßmus fInsertPointCommand = new InsertPointCommand(fPath, index, 1283128277c9SStephan Aßmus fSelection->Items(), 1284128277c9SStephan Aßmus fSelection->CountItems()); 1285128277c9SStephan Aßmus 1286128277c9SStephan Aßmus fPath->SetPointOut(index - 1, previousOut); 1287128277c9SStephan Aßmus fPath->SetPointIn(index + 1, nextIn); 1288128277c9SStephan Aßmus 1289128277c9SStephan Aßmus fCurrentPathPoint = index; 1290128277c9SStephan Aßmus _ShiftSelection(fCurrentPathPoint, 1); 1291128277c9SStephan Aßmus _Select(fCurrentPathPoint, fShiftDown); 1292128277c9SStephan Aßmus } 1293128277c9SStephan Aßmus } 1294128277c9SStephan Aßmus } 1295128277c9SStephan Aßmus 1296128277c9SStephan Aßmus // _SetInOutConnected 1297128277c9SStephan Aßmus void 1298128277c9SStephan Aßmus PathManipulator::_SetInOutConnected(int32 index, bool connected) 1299128277c9SStephan Aßmus { 1300128277c9SStephan Aßmus fPath->SetInOutConnected(index, connected); 1301128277c9SStephan Aßmus } 1302128277c9SStephan Aßmus 1303128277c9SStephan Aßmus // _SetSharp 1304128277c9SStephan Aßmus void 1305128277c9SStephan Aßmus PathManipulator::_SetSharp(int32 index) 1306128277c9SStephan Aßmus { 1307128277c9SStephan Aßmus BPoint p; 1308128277c9SStephan Aßmus fPath->GetPointAt(index, p); 1309128277c9SStephan Aßmus fPath->SetPoint(index, p, p, p, true); 1310128277c9SStephan Aßmus } 1311128277c9SStephan Aßmus 1312128277c9SStephan Aßmus // _RemoveSelection 1313128277c9SStephan Aßmus void 1314128277c9SStephan Aßmus PathManipulator::_RemoveSelection() 1315128277c9SStephan Aßmus { 13160e1ba39fSStephan Aßmus // NOTE: copy selection since removing points will 13170e1ba39fSStephan Aßmus // trigger notifications, and that will influence the 13180e1ba39fSStephan Aßmus // selection 13190e1ba39fSStephan Aßmus Selection selection = *fSelection; 13200e1ba39fSStephan Aßmus int32 count = selection.CountItems(); 1321128277c9SStephan Aßmus for (int32 i = 0; i < count; i++) { 13220e1ba39fSStephan Aßmus if (!fPath->RemovePoint(selection.IndexAt(i) - i)) 1323128277c9SStephan Aßmus break; 1324128277c9SStephan Aßmus } 1325128277c9SStephan Aßmus 13260e1ba39fSStephan Aßmus fPath->SetClosed(fPath->IsClosed() && fPath->CountPoints() > 1); 1327128277c9SStephan Aßmus 1328128277c9SStephan Aßmus fSelection->MakeEmpty(); 1329128277c9SStephan Aßmus } 1330128277c9SStephan Aßmus 1331128277c9SStephan Aßmus 1332128277c9SStephan Aßmus // _RemovePoint 1333128277c9SStephan Aßmus void 1334128277c9SStephan Aßmus PathManipulator::_RemovePoint(int32 index) 1335128277c9SStephan Aßmus { 1336128277c9SStephan Aßmus if (fPath->RemovePoint(index)) { 1337128277c9SStephan Aßmus _Deselect(index); 1338128277c9SStephan Aßmus _ShiftSelection(index + 1, -1); 1339128277c9SStephan Aßmus } 1340128277c9SStephan Aßmus } 1341128277c9SStephan Aßmus 1342128277c9SStephan Aßmus // _RemovePointIn 1343128277c9SStephan Aßmus void 1344128277c9SStephan Aßmus PathManipulator::_RemovePointIn(int32 index) 1345128277c9SStephan Aßmus { 1346128277c9SStephan Aßmus BPoint p; 1347128277c9SStephan Aßmus if (fPath->GetPointAt(index, p)) { 1348128277c9SStephan Aßmus fPath->SetPointIn(index, p); 1349128277c9SStephan Aßmus fPath->SetInOutConnected(index, false); 1350128277c9SStephan Aßmus } 1351128277c9SStephan Aßmus } 1352128277c9SStephan Aßmus 1353128277c9SStephan Aßmus // _RemovePointOut 1354128277c9SStephan Aßmus void 1355128277c9SStephan Aßmus PathManipulator::_RemovePointOut(int32 index) 1356128277c9SStephan Aßmus { 1357128277c9SStephan Aßmus BPoint p; 1358128277c9SStephan Aßmus if (fPath->GetPointAt(index, p)) { 1359128277c9SStephan Aßmus fPath->SetPointOut(index, p); 1360128277c9SStephan Aßmus fPath->SetInOutConnected(index, false); 1361128277c9SStephan Aßmus } 1362128277c9SStephan Aßmus } 1363128277c9SStephan Aßmus 1364128277c9SStephan Aßmus // _Delete 1365128277c9SStephan Aßmus Command* 1366128277c9SStephan Aßmus PathManipulator::_Delete() 1367128277c9SStephan Aßmus { 1368128277c9SStephan Aßmus Command* command = NULL; 1369128277c9SStephan Aßmus if (!fMouseDown) { 13700e1ba39fSStephan Aßmus // make sure we apply an on-going transformation before we proceed 13710e1ba39fSStephan Aßmus if (fTransformBox) { 13720e1ba39fSStephan Aßmus _SetTransformBox(NULL); 13730e1ba39fSStephan Aßmus } 13740e1ba39fSStephan Aßmus 1375128277c9SStephan Aßmus if (fSelection->CountItems() == fPath->CountPoints()) { 1376128277c9SStephan Aßmus // command = new RemovePathCommand(fPath); 1377128277c9SStephan Aßmus } else { 1378128277c9SStephan Aßmus command = new RemovePointsCommand(fPath, 1379128277c9SStephan Aßmus fSelection->Items(), 1380128277c9SStephan Aßmus fSelection->CountItems()); 1381128277c9SStephan Aßmus _RemoveSelection(); 1382128277c9SStephan Aßmus } 1383128277c9SStephan Aßmus 1384128277c9SStephan Aßmus _SetModeForMousePos(fLastCanvasPos); 1385128277c9SStephan Aßmus } 1386128277c9SStephan Aßmus 1387128277c9SStephan Aßmus return command; 1388128277c9SStephan Aßmus } 1389128277c9SStephan Aßmus 1390128277c9SStephan Aßmus // #pragma mark - 1391128277c9SStephan Aßmus 1392128277c9SStephan Aßmus // _Select 1393128277c9SStephan Aßmus void 1394128277c9SStephan Aßmus PathManipulator::_Select(BRect r) 1395128277c9SStephan Aßmus { 1396128277c9SStephan Aßmus BPoint p; 1397f4bd80a2SStephan Aßmus BPoint pIn; 1398f4bd80a2SStephan Aßmus BPoint pOut; 1399128277c9SStephan Aßmus int32 count = fPath->CountPoints(); 1400128277c9SStephan Aßmus Selection temp; 1401f4bd80a2SStephan Aßmus for (int32 i = 0; i < count && fPath->GetPointsAt(i, p, pIn, pOut); i++) { 1402f4bd80a2SStephan Aßmus if (r.Contains(p) || r.Contains(pIn) || r.Contains(pOut)) { 1403128277c9SStephan Aßmus temp.Add(i); 1404128277c9SStephan Aßmus } 1405128277c9SStephan Aßmus } 1406128277c9SStephan Aßmus // merge old and new selection 1407128277c9SStephan Aßmus count = fOldSelection->CountItems(); 1408128277c9SStephan Aßmus for (int32 i = 0; i < count; i++) { 1409128277c9SStephan Aßmus int32 index = fOldSelection->IndexAt(i); 1410128277c9SStephan Aßmus if (temp.Contains(index)) 1411128277c9SStephan Aßmus temp.Remove(index); 1412128277c9SStephan Aßmus else 1413128277c9SStephan Aßmus temp.Add(index); 1414128277c9SStephan Aßmus } 1415128277c9SStephan Aßmus if (temp != *fSelection) { 1416128277c9SStephan Aßmus *fSelection = temp; 1417128277c9SStephan Aßmus _UpdateSelection(); 1418128277c9SStephan Aßmus } 1419128277c9SStephan Aßmus } 1420128277c9SStephan Aßmus 1421128277c9SStephan Aßmus // _Select 1422128277c9SStephan Aßmus void 1423128277c9SStephan Aßmus PathManipulator::_Select(int32 index, bool extend) 1424128277c9SStephan Aßmus { 1425128277c9SStephan Aßmus if (!extend) 1426128277c9SStephan Aßmus fSelection->MakeEmpty(); 1427128277c9SStephan Aßmus if (fSelection->Contains(index)) 1428128277c9SStephan Aßmus fSelection->Remove(index); 1429128277c9SStephan Aßmus else 1430128277c9SStephan Aßmus fSelection->Add(index); 1431128277c9SStephan Aßmus // TODO: this can lead to unnecessary invalidation (maybe need to investigate) 1432128277c9SStephan Aßmus _UpdateSelection(); 1433128277c9SStephan Aßmus } 1434128277c9SStephan Aßmus 1435128277c9SStephan Aßmus // _Select 1436128277c9SStephan Aßmus void 1437128277c9SStephan Aßmus PathManipulator::_Select(const int32* indices, int32 count, bool extend) 1438128277c9SStephan Aßmus { 1439128277c9SStephan Aßmus if (extend) { 1440128277c9SStephan Aßmus for (int32 i = 0; i < count; i++) { 1441128277c9SStephan Aßmus if (!fSelection->Contains(indices[i])) 1442128277c9SStephan Aßmus fSelection->Add(indices[i]); 1443128277c9SStephan Aßmus } 1444128277c9SStephan Aßmus } else { 1445128277c9SStephan Aßmus fSelection->MakeEmpty(); 1446128277c9SStephan Aßmus for (int32 i = 0; i < count; i++) { 1447128277c9SStephan Aßmus fSelection->Add(indices[i]); 1448128277c9SStephan Aßmus } 1449128277c9SStephan Aßmus } 1450128277c9SStephan Aßmus _UpdateSelection(); 1451128277c9SStephan Aßmus } 1452128277c9SStephan Aßmus 1453128277c9SStephan Aßmus // _Deselect 1454128277c9SStephan Aßmus void 1455128277c9SStephan Aßmus PathManipulator::_Deselect(int32 index) 1456128277c9SStephan Aßmus { 1457128277c9SStephan Aßmus if (fSelection->Contains(index)) { 1458128277c9SStephan Aßmus fSelection->Remove(index); 1459128277c9SStephan Aßmus _UpdateSelection(); 1460128277c9SStephan Aßmus } 1461128277c9SStephan Aßmus } 1462128277c9SStephan Aßmus 1463128277c9SStephan Aßmus // _ShiftSelection 1464128277c9SStephan Aßmus void 1465128277c9SStephan Aßmus PathManipulator::_ShiftSelection(int32 startIndex, int32 direction) 1466128277c9SStephan Aßmus { 1467128277c9SStephan Aßmus int32 count = fSelection->CountItems(); 1468128277c9SStephan Aßmus if (count > 0) { 1469128277c9SStephan Aßmus int32* selection = fSelection->Items(); 1470128277c9SStephan Aßmus for (int32 i = 0; i < count; i++) { 1471128277c9SStephan Aßmus if (selection[i] >= startIndex) { 1472128277c9SStephan Aßmus selection[i] += direction; 1473128277c9SStephan Aßmus } 1474128277c9SStephan Aßmus } 1475128277c9SStephan Aßmus } 1476128277c9SStephan Aßmus _UpdateSelection(); 1477128277c9SStephan Aßmus } 1478128277c9SStephan Aßmus 1479128277c9SStephan Aßmus // _IsSelected 1480128277c9SStephan Aßmus bool 1481128277c9SStephan Aßmus PathManipulator::_IsSelected(int32 index) const 1482128277c9SStephan Aßmus { 1483128277c9SStephan Aßmus return fSelection->Contains(index); 1484128277c9SStephan Aßmus } 1485128277c9SStephan Aßmus 1486128277c9SStephan Aßmus // #pragma mark - 1487128277c9SStephan Aßmus 1488128277c9SStephan Aßmus // _InvalidateCanvas 1489128277c9SStephan Aßmus void 1490128277c9SStephan Aßmus PathManipulator::_InvalidateCanvas(BRect rect) const 1491128277c9SStephan Aßmus { 1492f67876a0SStephan Aßmus // convert from canvas to view space 1493f67876a0SStephan Aßmus fCanvasView->ConvertFromCanvas(&rect); 1494128277c9SStephan Aßmus fCanvasView->Invalidate(rect); 1495128277c9SStephan Aßmus } 1496128277c9SStephan Aßmus 1497128277c9SStephan Aßmus // _InvalidateHighlightPoints 1498128277c9SStephan Aßmus void 1499128277c9SStephan Aßmus PathManipulator::_InvalidateHighlightPoints(int32 newIndex, uint32 newMode) 1500128277c9SStephan Aßmus { 1501128277c9SStephan Aßmus BRect oldRect = _ControlPointRect(fCurrentPathPoint, fMode); 1502128277c9SStephan Aßmus BRect newRect = _ControlPointRect(newIndex, newMode); 1503128277c9SStephan Aßmus if (oldRect.IsValid()) 1504128277c9SStephan Aßmus _InvalidateCanvas(oldRect); 1505128277c9SStephan Aßmus if (newRect.IsValid()) 1506128277c9SStephan Aßmus _InvalidateCanvas(newRect); 1507128277c9SStephan Aßmus } 1508128277c9SStephan Aßmus 1509128277c9SStephan Aßmus // _UpdateSelection 1510128277c9SStephan Aßmus void 1511128277c9SStephan Aßmus PathManipulator::_UpdateSelection() const 1512128277c9SStephan Aßmus { 1513128277c9SStephan Aßmus _InvalidateCanvas(_ControlPointRect()); 1514128277c9SStephan Aßmus if (BWindow* window = fCanvasView->Window()) { 1515128277c9SStephan Aßmus window->PostMessage(MSG_UPDATE_SHAPE_UI); 1516128277c9SStephan Aßmus } 1517128277c9SStephan Aßmus } 1518128277c9SStephan Aßmus 1519128277c9SStephan Aßmus // _ControlPointRect 1520128277c9SStephan Aßmus BRect 1521128277c9SStephan Aßmus PathManipulator::_ControlPointRect() const 1522128277c9SStephan Aßmus { 1523128277c9SStephan Aßmus BRect r = fPath->ControlPointBounds(); 1524128277c9SStephan Aßmus r.InsetBy(-POINT_EXTEND, -POINT_EXTEND); 1525128277c9SStephan Aßmus return r; 1526128277c9SStephan Aßmus } 1527128277c9SStephan Aßmus 1528128277c9SStephan Aßmus // _ControlPointRect 1529128277c9SStephan Aßmus BRect 1530128277c9SStephan Aßmus PathManipulator::_ControlPointRect(int32 index, uint32 mode) const 1531128277c9SStephan Aßmus { 1532128277c9SStephan Aßmus BRect rect(0.0, 0.0, -1.0, -1.0); 1533128277c9SStephan Aßmus if (index >= 0) { 1534128277c9SStephan Aßmus BPoint p, pIn, pOut; 1535128277c9SStephan Aßmus fPath->GetPointsAt(index, p, pIn, pOut); 1536128277c9SStephan Aßmus switch (mode) { 1537128277c9SStephan Aßmus case MOVE_POINT: 1538128277c9SStephan Aßmus case TOGGLE_SHARP: 1539128277c9SStephan Aßmus case REMOVE_POINT: 1540128277c9SStephan Aßmus case CLOSE_PATH: 1541128277c9SStephan Aßmus rect.Set(p.x, p.y, p.x, p.y); 1542128277c9SStephan Aßmus rect.InsetBy(-POINT_EXTEND, -POINT_EXTEND); 1543128277c9SStephan Aßmus break; 1544128277c9SStephan Aßmus case MOVE_POINT_IN: 1545128277c9SStephan Aßmus case TOGGLE_SHARP_IN: 1546128277c9SStephan Aßmus case REMOVE_POINT_IN: 1547128277c9SStephan Aßmus rect.Set(pIn.x, pIn.y, pIn.x, pIn.y); 1548128277c9SStephan Aßmus rect.InsetBy(-CONTROL_POINT_EXTEND, -CONTROL_POINT_EXTEND); 1549128277c9SStephan Aßmus break; 1550128277c9SStephan Aßmus case MOVE_POINT_OUT: 1551128277c9SStephan Aßmus case TOGGLE_SHARP_OUT: 1552128277c9SStephan Aßmus case REMOVE_POINT_OUT: 1553128277c9SStephan Aßmus rect.Set(pOut.x, pOut.y, pOut.x, pOut.y); 1554128277c9SStephan Aßmus rect.InsetBy(-CONTROL_POINT_EXTEND, -CONTROL_POINT_EXTEND); 1555128277c9SStephan Aßmus break; 1556128277c9SStephan Aßmus case SELECT_POINTS: 1557128277c9SStephan Aßmus rect.Set(min4(p.x, pIn.x, pOut.x, pOut.x), 1558128277c9SStephan Aßmus min4(p.y, pIn.y, pOut.y, pOut.y), 1559128277c9SStephan Aßmus max4(p.x, pIn.x, pOut.x, pOut.x), 1560128277c9SStephan Aßmus max4(p.y, pIn.y, pOut.y, pOut.y)); 1561128277c9SStephan Aßmus rect.InsetBy(-POINT_EXTEND, -POINT_EXTEND); 1562128277c9SStephan Aßmus break; 1563128277c9SStephan Aßmus } 1564128277c9SStephan Aßmus } 1565128277c9SStephan Aßmus return rect; 1566128277c9SStephan Aßmus } 1567128277c9SStephan Aßmus 1568128277c9SStephan Aßmus // #pragma mark - 1569128277c9SStephan Aßmus 1570128277c9SStephan Aßmus // _SetModeForMousePos 1571128277c9SStephan Aßmus void 1572128277c9SStephan Aßmus PathManipulator::_SetModeForMousePos(BPoint where) 1573128277c9SStephan Aßmus { 1574128277c9SStephan Aßmus uint32 mode = UNDEFINED; 1575128277c9SStephan Aßmus int32 index = -1; 1576128277c9SStephan Aßmus 1577f67876a0SStephan Aßmus float zoomLevel = fCanvasView->ZoomLevel(); 1578128277c9SStephan Aßmus 1579128277c9SStephan Aßmus // see if we're close enough at a control point 1580128277c9SStephan Aßmus BPoint point; 1581128277c9SStephan Aßmus BPoint pointIn; 1582128277c9SStephan Aßmus BPoint pointOut; 1583128277c9SStephan Aßmus for (int32 i = 0; fPath->GetPointsAt(i, point, pointIn, pointOut) 1584128277c9SStephan Aßmus && mode == UNDEFINED; i++) { 1585128277c9SStephan Aßmus 1586128277c9SStephan Aßmus float distM = point_point_distance(point, where) * zoomLevel; 1587128277c9SStephan Aßmus float distIn = point_point_distance(pointIn, where) * zoomLevel; 1588128277c9SStephan Aßmus float distOut = point_point_distance(pointOut, where) * zoomLevel; 1589128277c9SStephan Aßmus 1590128277c9SStephan Aßmus if (distM < MOVE_THRESHOLD) { 1591128277c9SStephan Aßmus if (i == 0 && fClickToClose 1592128277c9SStephan Aßmus && !fPath->IsClosed() && fPath->CountPoints() > 1) { 1593128277c9SStephan Aßmus mode = fCommandDown ? TOGGLE_SHARP : 1594128277c9SStephan Aßmus (fOptionDown ? REMOVE_POINT : CLOSE_PATH); 1595128277c9SStephan Aßmus index = i; 1596128277c9SStephan Aßmus } else { 1597128277c9SStephan Aßmus mode = fCommandDown ? TOGGLE_SHARP : 1598128277c9SStephan Aßmus (fOptionDown ? REMOVE_POINT : MOVE_POINT); 1599128277c9SStephan Aßmus index = i; 1600128277c9SStephan Aßmus } 1601128277c9SStephan Aßmus } 16020e1ba39fSStephan Aßmus if (distM - distIn > 0.00001 16030e1ba39fSStephan Aßmus && distIn < MOVE_THRESHOLD) { 1604128277c9SStephan Aßmus mode = fCommandDown ? TOGGLE_SHARP_IN : 1605128277c9SStephan Aßmus (fOptionDown ? REMOVE_POINT_IN : MOVE_POINT_IN); 1606128277c9SStephan Aßmus index = i; 1607128277c9SStephan Aßmus } 16080e1ba39fSStephan Aßmus if (distIn - distOut > 0.00001 16090e1ba39fSStephan Aßmus && distOut < distM && distOut < MOVE_THRESHOLD) { 1610128277c9SStephan Aßmus mode = fCommandDown ? TOGGLE_SHARP_OUT : 1611128277c9SStephan Aßmus (fOptionDown ? REMOVE_POINT_OUT : MOVE_POINT_OUT); 1612128277c9SStephan Aßmus index = i; 1613128277c9SStephan Aßmus } 1614128277c9SStephan Aßmus } 1615128277c9SStephan Aßmus // selection mode overrides any other mode, 1616128277c9SStephan Aßmus // but we need to check for it after we know 1617128277c9SStephan Aßmus // the index of the point under the mouse (code above) 1618128277c9SStephan Aßmus int32 pointCount = fPath->CountPoints(); 1619128277c9SStephan Aßmus if (fShiftDown && pointCount > 0) { 1620128277c9SStephan Aßmus mode = SELECT_POINTS; 1621128277c9SStephan Aßmus } 1622128277c9SStephan Aßmus 1623128277c9SStephan Aßmus // see if user wants to start new sub path 1624128277c9SStephan Aßmus if (fAltDown) { 1625128277c9SStephan Aßmus mode = NEW_PATH; 1626128277c9SStephan Aßmus index = -1; 1627128277c9SStephan Aßmus } 1628128277c9SStephan Aßmus 1629128277c9SStephan Aßmus // see if we're close enough at a line 1630128277c9SStephan Aßmus if (mode == UNDEFINED) { 1631128277c9SStephan Aßmus float distance; 1632128277c9SStephan Aßmus if (fPath->GetDistance(where, &distance, &index)) { 1633128277c9SStephan Aßmus if (distance < (INSERT_DIST_THRESHOLD / zoomLevel)) { 1634128277c9SStephan Aßmus mode = INSERT_POINT; 1635128277c9SStephan Aßmus } 1636128277c9SStephan Aßmus } else { 1637128277c9SStephan Aßmus // restore index, since it was changed by call above 1638128277c9SStephan Aßmus index = fCurrentPathPoint; 1639128277c9SStephan Aßmus } 1640128277c9SStephan Aßmus } 1641128277c9SStephan Aßmus 1642128277c9SStephan Aßmus // nope, still undefined mode, last fall back 1643128277c9SStephan Aßmus if (mode == UNDEFINED) { 1644128277c9SStephan Aßmus if (fFallBackMode == SELECT_POINTS) { 1645128277c9SStephan Aßmus if (fPath->IsClosed() && pointCount > 0) { 1646128277c9SStephan Aßmus mode = SELECT_POINTS; 1647128277c9SStephan Aßmus index = -1; 1648128277c9SStephan Aßmus } else { 1649128277c9SStephan Aßmus mode = ADD_POINT; 1650128277c9SStephan Aßmus index = pointCount - 1; 1651128277c9SStephan Aßmus } 1652128277c9SStephan Aßmus } else { 1653128277c9SStephan Aßmus // user had clicked "New Path" icon 1654128277c9SStephan Aßmus mode = fFallBackMode; 1655128277c9SStephan Aßmus } 1656128277c9SStephan Aßmus } 1657128277c9SStephan Aßmus // switch mode if necessary 1658128277c9SStephan Aßmus if (mode != fMode || index != fCurrentPathPoint) { 1659128277c9SStephan Aßmus // invalidate path display (to highlight the respective point) 1660128277c9SStephan Aßmus _InvalidateHighlightPoints(index, mode); 1661128277c9SStephan Aßmus _SetMode(mode); 1662128277c9SStephan Aßmus fCurrentPathPoint = index; 1663128277c9SStephan Aßmus } 1664128277c9SStephan Aßmus } 1665128277c9SStephan Aßmus 1666128277c9SStephan Aßmus // #pragma mark - 1667128277c9SStephan Aßmus 1668128277c9SStephan Aßmus // _Nudge 1669128277c9SStephan Aßmus void 1670128277c9SStephan Aßmus PathManipulator::_Nudge(BPoint direction) 1671128277c9SStephan Aßmus { 1672128277c9SStephan Aßmus bigtime_t now = system_time(); 1673128277c9SStephan Aßmus if (now - fLastNudgeTime > 500000) { 16740e1ba39fSStephan Aßmus fCanvasView->Perform(_FinishNudging()); 1675128277c9SStephan Aßmus } 1676128277c9SStephan Aßmus fLastNudgeTime = now; 1677128277c9SStephan Aßmus fNudgeOffset += direction; 1678128277c9SStephan Aßmus 16790e1ba39fSStephan Aßmus if (fTransformBox) { 16800e1ba39fSStephan Aßmus fTransformBox->NudgeBy(direction); 16810e1ba39fSStephan Aßmus return; 16820e1ba39fSStephan Aßmus } 16830e1ba39fSStephan Aßmus 16840e1ba39fSStephan Aßmus if (!fNudgeCommand) { 16850e1ba39fSStephan Aßmus 16860e1ba39fSStephan Aßmus bool fromSelection = !fSelection->IsEmpty(); 16870e1ba39fSStephan Aßmus 16880e1ba39fSStephan Aßmus int32 count = fromSelection ? fSelection->CountItems() 16890e1ba39fSStephan Aßmus : fPath->CountPoints(); 16900e1ba39fSStephan Aßmus int32 indices[count]; 16910e1ba39fSStephan Aßmus control_point points[count]; 16920e1ba39fSStephan Aßmus 16930e1ba39fSStephan Aßmus // init indices and points 16940e1ba39fSStephan Aßmus for (int32 i = 0; i < count; i++) { 16950e1ba39fSStephan Aßmus indices[i] = fromSelection ? fSelection->IndexAt(i) : i; 16960e1ba39fSStephan Aßmus fPath->GetPointsAt(indices[i], 16970e1ba39fSStephan Aßmus points[i].point, 16980e1ba39fSStephan Aßmus points[i].point_in, 16990e1ba39fSStephan Aßmus points[i].point_out, 17000e1ba39fSStephan Aßmus &points[i].connected); 17010e1ba39fSStephan Aßmus } 17020e1ba39fSStephan Aßmus 17030e1ba39fSStephan Aßmus fNudgeCommand = new NudgePointsCommand(fPath, indices, points, count); 17040e1ba39fSStephan Aßmus 17050e1ba39fSStephan Aßmus fNudgeCommand->SetNewTranslation(fNudgeOffset); 17060e1ba39fSStephan Aßmus fNudgeCommand->Redo(); 17070e1ba39fSStephan Aßmus 17080e1ba39fSStephan Aßmus } else { 17090e1ba39fSStephan Aßmus fNudgeCommand->SetNewTranslation(fNudgeOffset); 17100e1ba39fSStephan Aßmus fNudgeCommand->Redo(); 17110e1ba39fSStephan Aßmus } 1712128277c9SStephan Aßmus 1713128277c9SStephan Aßmus if (!fMouseDown) 1714128277c9SStephan Aßmus _SetModeForMousePos(fLastCanvasPos); 1715128277c9SStephan Aßmus } 1716128277c9SStephan Aßmus 1717128277c9SStephan Aßmus // _FinishNudging 17180e1ba39fSStephan Aßmus Command* 1719128277c9SStephan Aßmus PathManipulator::_FinishNudging() 1720128277c9SStephan Aßmus { 1721128277c9SStephan Aßmus fNudgeOffset = BPoint(0.0, 0.0); 1722128277c9SStephan Aßmus 17230e1ba39fSStephan Aßmus Command* command; 17240e1ba39fSStephan Aßmus 17250e1ba39fSStephan Aßmus if (fTransformBox) { 17260e1ba39fSStephan Aßmus command = fTransformBox->FinishNudging(); 17270e1ba39fSStephan Aßmus } else { 17280e1ba39fSStephan Aßmus command = fNudgeCommand; 17290e1ba39fSStephan Aßmus fNudgeCommand = NULL; 17300e1ba39fSStephan Aßmus } 17310e1ba39fSStephan Aßmus 17320e1ba39fSStephan Aßmus return command; 1733128277c9SStephan Aßmus } 1734128277c9SStephan Aßmus 1735128277c9SStephan Aßmus 1736