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:
Jonathan Westhues 2009-12-21 08:44:00 -08:00
parent c225087ab5
commit ee052b556a
6 changed files with 104 additions and 22 deletions

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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
}

27
ui.h
View File

@ -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);

View File

@ -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?