Tweak drag and selection behavior: selection is kept after dragging
selected entities, but cleared after dragging an unselected entity. Marquee selection is select-only (not toggle), and "Select All" replaces "Invert Selection". Left-click on nothing will clear the selection. Also add context menu entries for cut, copy, and paste. [git-p4: depot-paths = "//depot/solvespace/": change = 2089]
This commit is contained in:
parent
c225087ab5
commit
ee052b556a
|
@ -139,10 +139,10 @@ void GraphicsWindow::PasteClipboard(Vector trans, double theta, double scale) {
|
||||||
SS.GenerateAll(-1, -1);
|
SS.GenerateAll(-1, -1);
|
||||||
SS.MarkGroupDirty(r->group);
|
SS.MarkGroupDirty(r->group);
|
||||||
bool hasDistance;
|
bool hasDistance;
|
||||||
int pts;
|
int i, pts;
|
||||||
EntReqTable::GetRequestInfo(r->type, r->extraPoints,
|
EntReqTable::GetRequestInfo(r->type, r->extraPoints,
|
||||||
NULL, &pts, NULL, &hasDistance);
|
NULL, &pts, NULL, &hasDistance);
|
||||||
for(int i = 0; i < pts; i++) {
|
for(i = 0; i < pts; i++) {
|
||||||
Vector pt = cr->point[i];
|
Vector pt = cr->point[i];
|
||||||
// We need the reflection to occur within the workplane; it may
|
// We need the reflection to occur within the workplane; it may
|
||||||
// otherwise correspond to just a rotation as projected.
|
// otherwise correspond to just a rotation as projected.
|
||||||
|
@ -165,6 +165,9 @@ void GraphicsWindow::PasteClipboard(Vector trans, double theta, double scale) {
|
||||||
|
|
||||||
cr->newReq = hr;
|
cr->newReq = hr;
|
||||||
ToggleSelectionStateOf(hr.entity(0));
|
ToggleSelectionStateOf(hr.entity(0));
|
||||||
|
for(i = 0; i < pts; i++) {
|
||||||
|
ToggleSelectionStateOf(hr.entity(i+1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Constraint *c;
|
Constraint *c;
|
||||||
|
|
18
draw.cpp
18
draw.cpp
|
@ -93,6 +93,19 @@ void GraphicsWindow::ClearNonexistentSelectionItems(void) {
|
||||||
if(change) InvalidateGraphics();
|
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
|
// Toggle the selection state of the indicated item: if it was selected then
|
||||||
// un-select it, and if it wasn't then select it.
|
// un-select it, and if it wasn't then select it.
|
||||||
|
@ -136,7 +149,12 @@ void GraphicsWindow::ToggleSelectionStateOf(Selection *stog, bool batch) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It's too confusing to make operations that select multiple entities
|
||||||
|
// (like marquee selection) toggle. So make those select-only.
|
||||||
|
if(!batch) {
|
||||||
selection.RemoveTagged();
|
selection.RemoveTagged();
|
||||||
|
}
|
||||||
if(wasSelected) return;
|
if(wasSelected) return;
|
||||||
|
|
||||||
// So it's not selected, so we should select it.
|
// So it's not selected, so we should select it.
|
||||||
|
|
|
@ -44,7 +44,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
||||||
{ 1, "&Delete\tDel", MNU_DELETE, 127, mClip },
|
{ 1, "&Delete\tDel", MNU_DELETE, 127, mClip },
|
||||||
{ 1, NULL, 0, NULL },
|
{ 1, NULL, 0, NULL },
|
||||||
{ 1, "Select &Edge Chain\tCtrl+E", MNU_SELECT_CHAIN, 'E'|C, mEdit },
|
{ 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 },
|
{ 1, "&Unselect All\tEsc", MNU_UNSELECT_ALL, 27, mEdit },
|
||||||
|
|
||||||
{ 0, "&View", 0, NULL },
|
{ 0, "&View", 0, NULL },
|
||||||
|
@ -626,7 +626,7 @@ void GraphicsWindow::MenuEdit(int id) {
|
||||||
SS.nakedEdges.Clear();
|
SS.nakedEdges.Clear();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MNU_INVERT_SEL: {
|
case MNU_SELECT_ALL: {
|
||||||
Entity *e;
|
Entity *e;
|
||||||
for(e = SK.entity.First(); e; e = SK.entity.NextAfter(e)) {
|
for(e = SK.entity.First(); e; e = SK.entity.NextAfter(e)) {
|
||||||
if(e->group.v != SS.GW.activeGroup.v) continue;
|
if(e->group.v != SS.GW.activeGroup.v) continue;
|
||||||
|
|
64
mouse.cpp
64
mouse.cpp
|
@ -177,8 +177,21 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
||||||
pending.normal = hover.entity;
|
pending.normal = hover.entity;
|
||||||
pending.operation = DRAGGING_NORMAL;
|
pending.operation = DRAGGING_NORMAL;
|
||||||
} else {
|
} else {
|
||||||
StartDraggingBySelection();
|
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();
|
ClearSelection();
|
||||||
|
ToggleSelectionStateOf(e->h);
|
||||||
|
}
|
||||||
|
StartDraggingBySelection();
|
||||||
|
// 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();
|
hover.Clear();
|
||||||
pending.operation = DRAGGING_POINTS;
|
pending.operation = DRAGGING_POINTS;
|
||||||
}
|
}
|
||||||
|
@ -488,7 +501,11 @@ void GraphicsWindow::MouseRightUp(double x, double y) {
|
||||||
context.active = true;
|
context.active = true;
|
||||||
|
|
||||||
GroupSelection();
|
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.
|
// No reason to display a context menu.
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -574,6 +591,17 @@ void GraphicsWindow::MouseRightUp(double x, double y) {
|
||||||
CMNU_SELECT_CHAIN);
|
CMNU_SELECT_CHAIN);
|
||||||
}
|
}
|
||||||
AddContextMenuItem(NULL, CONTEXT_SEPARATOR);
|
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("Delete Selection", CMNU_DELETE_SEL);
|
||||||
AddContextMenuItem("Unselect All", CMNU_UNSELECT_ALL);
|
AddContextMenuItem("Unselect All", CMNU_UNSELECT_ALL);
|
||||||
}
|
}
|
||||||
|
@ -591,6 +619,18 @@ void GraphicsWindow::MouseRightUp(double x, double y) {
|
||||||
MenuEdit(MNU_SELECT_CHAIN);
|
MenuEdit(MNU_SELECT_CHAIN);
|
||||||
break;
|
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:
|
case CMNU_DELETE_SEL:
|
||||||
MenuClipboard(MNU_DELETE);
|
MenuClipboard(MNU_DELETE);
|
||||||
break;
|
break;
|
||||||
|
@ -679,8 +719,10 @@ void GraphicsWindow::MouseRightUp(double x, double y) {
|
||||||
default:
|
default:
|
||||||
if(ret >= CMNU_FIRST_STYLE) {
|
if(ret >= CMNU_FIRST_STYLE) {
|
||||||
Style::AssignSelectionToStyle(ret - CMNU_FIRST_STYLE);
|
Style::AssignSelectionToStyle(ret - CMNU_FIRST_STYLE);
|
||||||
}
|
} else {
|
||||||
// otherwise it was cancelled, so do nothing
|
// otherwise it was cancelled, so do nothing
|
||||||
|
contextMenuCancelTime = GetMilliseconds();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1024,7 +1066,9 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
||||||
case 0:
|
case 0:
|
||||||
default:
|
default:
|
||||||
ClearPending();
|
ClearPending();
|
||||||
|
if(hover.entity.v || hover.constraint.v) {
|
||||||
ToggleSelectionStateOf(&hover);
|
ToggleSelectionStateOf(&hover);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1050,6 +1094,20 @@ void GraphicsWindow::MouseLeftUp(double mx, double my) {
|
||||||
InvalidateGraphics();
|
InvalidateGraphics();
|
||||||
break;
|
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:
|
default:
|
||||||
break; // do nothing
|
break; // do nothing
|
||||||
}
|
}
|
||||||
|
|
27
ui.h
27
ui.h
|
@ -265,7 +265,7 @@ public:
|
||||||
MNU_PASTE_TRANSFORM,
|
MNU_PASTE_TRANSFORM,
|
||||||
MNU_DELETE,
|
MNU_DELETE,
|
||||||
MNU_SELECT_CHAIN,
|
MNU_SELECT_CHAIN,
|
||||||
MNU_INVERT_SEL,
|
MNU_SELECT_ALL,
|
||||||
MNU_SNAP_TO_GRID,
|
MNU_SNAP_TO_GRID,
|
||||||
MNU_ROTATE_90,
|
MNU_ROTATE_90,
|
||||||
MNU_UNSELECT_ALL,
|
MNU_UNSELECT_ALL,
|
||||||
|
@ -486,24 +486,29 @@ public:
|
||||||
int n;
|
int n;
|
||||||
} gs;
|
} gs;
|
||||||
void GroupSelection(void);
|
void GroupSelection(void);
|
||||||
|
bool EntityIsSelected(hEntity he);
|
||||||
void ToggleSelectionStateOf(hEntity he, bool batch=false);
|
void ToggleSelectionStateOf(hEntity he, bool batch=false);
|
||||||
void ToggleSelectionStateOf(Selection *s, bool batch=false);
|
void ToggleSelectionStateOf(Selection *s, bool batch=false);
|
||||||
void SelectByMarquee(void);
|
void SelectByMarquee(void);
|
||||||
void ClearSuper(void);
|
void ClearSuper(void);
|
||||||
|
|
||||||
static const int CMNU_UNSELECT_ALL = 0x100;
|
static const int CMNU_UNSELECT_ALL = 0x100;
|
||||||
static const int CMNU_DELETE_SEL = 0x101;
|
static const int CMNU_CUT_SEL = 0x101;
|
||||||
static const int CMNU_NEW_CUSTOM_STYLE = 0x102;
|
static const int CMNU_COPY_SEL = 0x102;
|
||||||
static const int CMNU_NO_STYLE = 0x103;
|
static const int CMNU_PASTE_SEL = 0x103;
|
||||||
static const int CMNU_GROUP_INFO = 0x104;
|
static const int CMNU_DELETE_SEL = 0x104;
|
||||||
static const int CMNU_REFERENCE_DIM = 0x105;
|
static const int CMNU_SELECT_CHAIN = 0x105;
|
||||||
static const int CMNU_OTHER_ANGLE = 0x106;
|
static const int CMNU_NEW_CUSTOM_STYLE = 0x110;
|
||||||
static const int CMNU_DEL_COINCIDENT = 0x107;
|
static const int CMNU_NO_STYLE = 0x111;
|
||||||
static const int CMNU_STYLE_INFO = 0x108;
|
static const int CMNU_GROUP_INFO = 0x120;
|
||||||
static const int CMNU_SNAP_TO_GRID = 0x109;
|
static const int CMNU_STYLE_INFO = 0x121;
|
||||||
static const int CMNU_SELECT_CHAIN = 0x10a;
|
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;
|
static const int CMNU_FIRST_STYLE = 0x40000000;
|
||||||
void ContextMenuListStyles(void);
|
void ContextMenuListStyles(void);
|
||||||
|
SDWORD contextMenuCancelTime;
|
||||||
|
|
||||||
// The toolbar, in toolbar.cpp
|
// The toolbar, in toolbar.cpp
|
||||||
bool ToolbarDrawOrHitTest(int x, int y, bool paint, int *menu);
|
bool ToolbarDrawOrHitTest(int x, int y, bool paint, int *menu);
|
||||||
|
|
|
@ -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)
|
show and modify view parameters (translate, rotate, scale)
|
||||||
context menu to hide / suppress groups by entity?
|
context menu to hide / suppress groups by entity?
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user