diff --git a/clipboard.cpp b/clipboard.cpp index ccd6cd7..9f7f9e1 100644 --- a/clipboard.cpp +++ b/clipboard.cpp @@ -139,10 +139,10 @@ void GraphicsWindow::PasteClipboard(Vector trans, double theta, double scale) { SS.GenerateAll(-1, -1); SS.MarkGroupDirty(r->group); bool hasDistance; - int pts; + int i, pts; EntReqTable::GetRequestInfo(r->type, r->extraPoints, NULL, &pts, NULL, &hasDistance); - for(int i = 0; i < pts; i++) { + for(i = 0; i < pts; i++) { Vector pt = cr->point[i]; // We need the reflection to occur within the workplane; it may // otherwise correspond to just a rotation as projected. @@ -165,6 +165,9 @@ void GraphicsWindow::PasteClipboard(Vector trans, double theta, double scale) { cr->newReq = hr; ToggleSelectionStateOf(hr.entity(0)); + for(i = 0; i < pts; i++) { + ToggleSelectionStateOf(hr.entity(i+1)); + } } Constraint *c; diff --git a/draw.cpp b/draw.cpp index 0b69870..149179a 100644 --- a/draw.cpp +++ b/draw.cpp @@ -93,6 +93,19 @@ void GraphicsWindow::ClearNonexistentSelectionItems(void) { if(change) InvalidateGraphics(); } +//----------------------------------------------------------------------------- +// Is this entity selected? +//----------------------------------------------------------------------------- +bool GraphicsWindow::EntityIsSelected(hEntity he) { + Selection *s; + for(s = selection.First(); s; s = selection.NextAfter(s)) { + if(s->entity.v == he.v) { + return true; + } + } + return false; +} + //----------------------------------------------------------------------------- // Toggle the selection state of the indicated item: if it was selected then // un-select it, and if it wasn't then select it. @@ -136,7 +149,12 @@ void GraphicsWindow::ToggleSelectionStateOf(Selection *stog, bool batch) { } } } - selection.RemoveTagged(); + + // It's too confusing to make operations that select multiple entities + // (like marquee selection) toggle. So make those select-only. + if(!batch) { + selection.RemoveTagged(); + } if(wasSelected) return; // So it's not selected, so we should select it. diff --git a/graphicswin.cpp b/graphicswin.cpp index f4af8df..08791c9 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -44,7 +44,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { { 1, "&Delete\tDel", MNU_DELETE, 127, mClip }, { 1, NULL, 0, NULL }, { 1, "Select &Edge Chain\tCtrl+E", MNU_SELECT_CHAIN, 'E'|C, mEdit }, -{ 1, "Invert &Selection\tCtrl+A", MNU_INVERT_SEL, 'A'|C, mEdit }, +{ 1, "Select &All\tCtrl+A", MNU_SELECT_ALL, 'A'|C, mEdit }, { 1, "&Unselect All\tEsc", MNU_UNSELECT_ALL, 27, mEdit }, { 0, "&View", 0, NULL }, @@ -626,7 +626,7 @@ void GraphicsWindow::MenuEdit(int id) { SS.nakedEdges.Clear(); break; - case MNU_INVERT_SEL: { + case MNU_SELECT_ALL: { Entity *e; for(e = SK.entity.First(); e; e = SK.entity.NextAfter(e)) { if(e->group.v != SS.GW.activeGroup.v) continue; diff --git a/mouse.cpp b/mouse.cpp index 117b2a1..4f6ef68 100644 --- a/mouse.cpp +++ b/mouse.cpp @@ -177,8 +177,21 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, pending.normal = hover.entity; pending.operation = DRAGGING_NORMAL; } else { + if(EntityIsSelected(e->h)) { + // The entity is selected, which means that it wasn't + // before the user clicked to start dragging, which + // means they're dragging just the hovered thing, + // not the full selection. So clear all the selection + // except that entity. + ClearSelection(); + ToggleSelectionStateOf(e->h); + } StartDraggingBySelection(); - ClearSelection(); + // If something's hovered, then the user selected it when + // they clicked to start dragging, but they probably + // didn't mean to select it. Or if it was selected, then + // they didn't mean to deselect it. So fix that. + ToggleSelectionStateOf(e->h); hover.Clear(); pending.operation = DRAGGING_POINTS; } @@ -488,7 +501,11 @@ void GraphicsWindow::MouseRightUp(double x, double y) { context.active = true; GroupSelection(); - if(hover.IsEmpty() && gs.n == 0 && gs.constraints == 0) { + if(hover.IsEmpty() && + gs.n == 0 && + gs.constraints == 0 && + (SS.clipboard.r.n == 0 || !LockedInWorkplane())) + { // No reason to display a context menu. goto done; } @@ -574,6 +591,17 @@ void GraphicsWindow::MouseRightUp(double x, double y) { CMNU_SELECT_CHAIN); } AddContextMenuItem(NULL, CONTEXT_SEPARATOR); + if(LockedInWorkplane()) { + AddContextMenuItem("Cut Selection", CMNU_CUT_SEL); + AddContextMenuItem("Copy Selection", CMNU_COPY_SEL); + } + } + + if(SS.clipboard.r.n > 0 && LockedInWorkplane()) { + AddContextMenuItem("Paste Selection", CMNU_PASTE_SEL); + } + + if(!selEmpty) { AddContextMenuItem("Delete Selection", CMNU_DELETE_SEL); AddContextMenuItem("Unselect All", CMNU_UNSELECT_ALL); } @@ -591,6 +619,18 @@ void GraphicsWindow::MouseRightUp(double x, double y) { MenuEdit(MNU_SELECT_CHAIN); break; + case CMNU_CUT_SEL: + MenuClipboard(MNU_CUT); + break; + + case CMNU_COPY_SEL: + MenuClipboard(MNU_COPY); + break; + + case CMNU_PASTE_SEL: + MenuClipboard(MNU_PASTE); + break; + case CMNU_DELETE_SEL: MenuClipboard(MNU_DELETE); break; @@ -679,8 +719,10 @@ void GraphicsWindow::MouseRightUp(double x, double y) { default: if(ret >= CMNU_FIRST_STYLE) { Style::AssignSelectionToStyle(ret - CMNU_FIRST_STYLE); + } else { + // otherwise it was cancelled, so do nothing + contextMenuCancelTime = GetMilliseconds(); } - // otherwise it was cancelled, so do nothing break; } @@ -1024,7 +1066,9 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) { case 0: default: ClearPending(); - ToggleSelectionStateOf(&hover); + if(hover.entity.v || hover.constraint.v) { + ToggleSelectionStateOf(&hover); + } break; } @@ -1050,6 +1094,20 @@ void GraphicsWindow::MouseLeftUp(double mx, double my) { InvalidateGraphics(); break; + case 0: + // We need to clear the selection here, and not in the mouse down + // event, since a mouse down without anything hovered could also + // be the start of marquee selection. But don't do that on the + // left click to cancel a context menu. The time delay is an ugly + // hack. + if(hover.IsEmpty() && + (contextMenuCancelTime == 0 || + (GetMilliseconds() - contextMenuCancelTime) > 200)) + { + ClearSelection(); + } + break; + default: break; // do nothing } diff --git a/ui.h b/ui.h index e1fe2ab..5f5a0ac 100644 --- a/ui.h +++ b/ui.h @@ -265,7 +265,7 @@ public: MNU_PASTE_TRANSFORM, MNU_DELETE, MNU_SELECT_CHAIN, - MNU_INVERT_SEL, + MNU_SELECT_ALL, MNU_SNAP_TO_GRID, MNU_ROTATE_90, MNU_UNSELECT_ALL, @@ -486,24 +486,29 @@ public: int n; } gs; void GroupSelection(void); + bool EntityIsSelected(hEntity he); void ToggleSelectionStateOf(hEntity he, bool batch=false); void ToggleSelectionStateOf(Selection *s, bool batch=false); void SelectByMarquee(void); void ClearSuper(void); static const int CMNU_UNSELECT_ALL = 0x100; - static const int CMNU_DELETE_SEL = 0x101; - static const int CMNU_NEW_CUSTOM_STYLE = 0x102; - static const int CMNU_NO_STYLE = 0x103; - static const int CMNU_GROUP_INFO = 0x104; - static const int CMNU_REFERENCE_DIM = 0x105; - static const int CMNU_OTHER_ANGLE = 0x106; - static const int CMNU_DEL_COINCIDENT = 0x107; - static const int CMNU_STYLE_INFO = 0x108; - static const int CMNU_SNAP_TO_GRID = 0x109; - static const int CMNU_SELECT_CHAIN = 0x10a; + static const int CMNU_CUT_SEL = 0x101; + static const int CMNU_COPY_SEL = 0x102; + static const int CMNU_PASTE_SEL = 0x103; + static const int CMNU_DELETE_SEL = 0x104; + static const int CMNU_SELECT_CHAIN = 0x105; + static const int CMNU_NEW_CUSTOM_STYLE = 0x110; + static const int CMNU_NO_STYLE = 0x111; + static const int CMNU_GROUP_INFO = 0x120; + static const int CMNU_STYLE_INFO = 0x121; + static const int CMNU_REFERENCE_DIM = 0x130; + static const int CMNU_OTHER_ANGLE = 0x131; + static const int CMNU_DEL_COINCIDENT = 0x132; + static const int CMNU_SNAP_TO_GRID = 0x140; static const int CMNU_FIRST_STYLE = 0x40000000; void ContextMenuListStyles(void); + SDWORD contextMenuCancelTime; // The toolbar, in toolbar.cpp bool ToolbarDrawOrHitTest(int x, int y, bool paint, int *menu); diff --git a/wishlist.txt b/wishlist.txt index 011ebd1..8202ebc 100644 --- a/wishlist.txt +++ b/wishlist.txt @@ -1,6 +1,4 @@ -de-select after left-clicking nothing, keep sel on drag? -bbox selection is select-only, not toggle? show and modify view parameters (translate, rotate, scale) context menu to hide / suppress groups by entity?