Add a context menu, with a grab bag of options. That will need some
refinement later, but it does not affect file formats so it's not very critical. [git-p4: depot-paths = "//depot/solvespace/": change = 2032]
This commit is contained in:
parent
274005c02c
commit
9416faca88
274
draw.cpp
274
draw.cpp
|
@ -20,6 +20,8 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
||||||
bool middleDown, bool rightDown, bool shiftDown, bool ctrlDown)
|
bool middleDown, bool rightDown, bool shiftDown, bool ctrlDown)
|
||||||
{
|
{
|
||||||
if(GraphicsEditControlIsVisible()) return;
|
if(GraphicsEditControlIsVisible()) return;
|
||||||
|
if(context.active) return;
|
||||||
|
|
||||||
if(rightDown) {
|
if(rightDown) {
|
||||||
middleDown = true;
|
middleDown = true;
|
||||||
shiftDown = !shiftDown;
|
shiftDown = !shiftDown;
|
||||||
|
@ -34,6 +36,13 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
||||||
|
|
||||||
Point2d mp = { x, y };
|
Point2d mp = { x, y };
|
||||||
|
|
||||||
|
if(rightDown && orig.mouse.DistanceTo(mp) < 5 && !orig.startedMoving) {
|
||||||
|
// Avoid accidentally panning (or rotating if shift is down) if the
|
||||||
|
// user wants a context menu.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
orig.startedMoving = true;
|
||||||
|
|
||||||
// If the middle button is down, then mouse movement is used to pan and
|
// If the middle button is down, then mouse movement is used to pan and
|
||||||
// rotate our view. This wins over everything else.
|
// rotate our view. This wins over everything else.
|
||||||
if(middleDown) {
|
if(middleDown) {
|
||||||
|
@ -347,18 +356,174 @@ void GraphicsWindow::ClearPending(void) {
|
||||||
void GraphicsWindow::MouseMiddleOrRightDown(double x, double y) {
|
void GraphicsWindow::MouseMiddleOrRightDown(double x, double y) {
|
||||||
if(GraphicsEditControlIsVisible()) return;
|
if(GraphicsEditControlIsVisible()) return;
|
||||||
|
|
||||||
if(pending.operation == DRAGGING_NEW_LINE_POINT) {
|
|
||||||
// Special case; use a middle or right click to stop drawing lines,
|
|
||||||
// since a left click would draw another one. This is quicker and
|
|
||||||
// more intuitive than hitting escape.
|
|
||||||
ClearPending();
|
|
||||||
}
|
|
||||||
|
|
||||||
orig.offset = offset;
|
orig.offset = offset;
|
||||||
orig.projUp = projUp;
|
orig.projUp = projUp;
|
||||||
orig.projRight = projRight;
|
orig.projRight = projRight;
|
||||||
orig.mouse.x = x;
|
orig.mouse.x = x;
|
||||||
orig.mouse.y = y;
|
orig.mouse.y = y;
|
||||||
|
orig.startedMoving = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphicsWindow::ContextMenuListStyles(void) {
|
||||||
|
CreateContextSubmenu();
|
||||||
|
Style *s;
|
||||||
|
bool empty = true;
|
||||||
|
for(s = SK.style.First(); s; s = SK.style.NextAfter(s)) {
|
||||||
|
if(s->h.v < Style::FIRST_CUSTOM) continue;
|
||||||
|
|
||||||
|
AddContextMenuItem(s->DescriptionString(), CMNU_FIRST_STYLE + s->h.v);
|
||||||
|
empty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!empty) AddContextMenuItem(NULL, CONTEXT_SEPARATOR);
|
||||||
|
|
||||||
|
AddContextMenuItem("No Style", CMNU_NO_STYLE);
|
||||||
|
AddContextMenuItem("Newly Created Custom Style...", CMNU_NEW_CUSTOM_STYLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphicsWindow::MouseRightUp(double x, double y) {
|
||||||
|
// Don't show a context menu if the user is right-clicking the toolbar,
|
||||||
|
// or if they are finishing a pan.
|
||||||
|
if(ToolbarMouseMoved((int)x, (int)y)) return;
|
||||||
|
if(orig.startedMoving) return;
|
||||||
|
|
||||||
|
if(context.active) return;
|
||||||
|
context.active = true;
|
||||||
|
|
||||||
|
if(pending.operation == DRAGGING_NEW_LINE_POINT) {
|
||||||
|
// Special case; use a right click to stop drawing lines, since
|
||||||
|
// a left click would draw another one. This is quicker and more
|
||||||
|
// intuitive than hitting escape.
|
||||||
|
ClearPending();
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupSelection();
|
||||||
|
if(hover.IsEmpty() && gs.n == 0 && gs.constraints == 0) {
|
||||||
|
// No reason to display a context menu.
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can either work on the selection (like the functions are designed to)
|
||||||
|
// or on the hovered item. In the latter case we can fudge things by just
|
||||||
|
// selecting the hovered item, and then applying our operation to the
|
||||||
|
// selection.
|
||||||
|
bool toggleForStyles = false,
|
||||||
|
toggleForGroupInfo = false,
|
||||||
|
toggleForDelete = false;
|
||||||
|
|
||||||
|
if(!hover.IsEmpty()) {
|
||||||
|
AddContextMenuItem("Toggle Hovered Item Selection",
|
||||||
|
CMNU_TOGGLE_SELECTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(gs.entities > 0) {
|
||||||
|
ContextMenuListStyles();
|
||||||
|
AddContextMenuItem("Assign Selection to Style", CONTEXT_SUBMENU);
|
||||||
|
} else if(hover.entity.v && gs.n == 0 && gs.constraints == 0) {
|
||||||
|
ContextMenuListStyles();
|
||||||
|
AddContextMenuItem("Assign Hovered Item to Style", CONTEXT_SUBMENU);
|
||||||
|
toggleForStyles = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(gs.n + gs.constraints == 1) {
|
||||||
|
AddContextMenuItem("Group Info for Selected Item", CMNU_GROUP_INFO);
|
||||||
|
} else if(!hover.IsEmpty() && gs.n == 0 && gs.constraints == 0) {
|
||||||
|
AddContextMenuItem("Group Info for Hovered Item", CMNU_GROUP_INFO);
|
||||||
|
toggleForGroupInfo = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hover.constraint.v && gs.n == 0 && gs.constraints == 0) {
|
||||||
|
Constraint *c = SK.GetConstraint(hover.constraint);
|
||||||
|
if(c->HasLabel()) {
|
||||||
|
AddContextMenuItem("Toggle Reference Dimension",
|
||||||
|
CMNU_REFERENCE_DIM);
|
||||||
|
}
|
||||||
|
if(c->type == Constraint::ANGLE ||
|
||||||
|
c->type == Constraint::EQUAL_ANGLE)
|
||||||
|
{
|
||||||
|
AddContextMenuItem("Other Supplementary Angle",
|
||||||
|
CMNU_OTHER_ANGLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(gs.n > 0 || gs.constraints > 0) {
|
||||||
|
AddContextMenuItem(NULL, CONTEXT_SEPARATOR);
|
||||||
|
AddContextMenuItem("Delete Selection", CMNU_DELETE_SEL);
|
||||||
|
AddContextMenuItem("Unselect All", CMNU_UNSELECT_ALL);
|
||||||
|
} else if(!hover.IsEmpty()) {
|
||||||
|
AddContextMenuItem(NULL, CONTEXT_SEPARATOR);
|
||||||
|
AddContextMenuItem("Delete Hovered Item", CMNU_DELETE_SEL);
|
||||||
|
toggleForDelete = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = ShowContextMenu();
|
||||||
|
switch(ret) {
|
||||||
|
case CMNU_TOGGLE_SELECTION:
|
||||||
|
ToggleSelectionStateOfHovered();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMNU_UNSELECT_ALL:
|
||||||
|
MenuEdit(MNU_UNSELECT_ALL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMNU_DELETE_SEL:
|
||||||
|
if(toggleForDelete) ToggleSelectionStateOfHovered();
|
||||||
|
MenuEdit(MNU_DELETE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMNU_REFERENCE_DIM:
|
||||||
|
ToggleSelectionStateOfHovered();
|
||||||
|
Constraint::MenuConstrain(MNU_REFERENCE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMNU_OTHER_ANGLE:
|
||||||
|
ToggleSelectionStateOfHovered();
|
||||||
|
Constraint::MenuConstrain(MNU_OTHER_ANGLE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMNU_GROUP_INFO: {
|
||||||
|
if(toggleForGroupInfo) ToggleSelectionStateOfHovered();
|
||||||
|
GroupSelection();
|
||||||
|
hGroup hg;
|
||||||
|
if(gs.entities == 1) {
|
||||||
|
hg = SK.GetEntity(gs.entity[0])->group;
|
||||||
|
} else if(gs.points == 1) {
|
||||||
|
hg = SK.GetEntity(gs.point[0])->group;
|
||||||
|
} else if(gs.constraints == 1) {
|
||||||
|
hg = SK.GetConstraint(gs.constraint[0])->group;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ClearSelection();
|
||||||
|
SS.TW.GoToScreen(TextWindow::SCREEN_GROUP_INFO);
|
||||||
|
SS.TW.shown.group = hg;
|
||||||
|
SS.later.showTW = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CMNU_NEW_CUSTOM_STYLE: {
|
||||||
|
if(toggleForStyles) ToggleSelectionStateOfHovered();
|
||||||
|
DWORD v = Style::CreateCustomStyle();
|
||||||
|
Style::AssignSelectionToStyle(v);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CMNU_NO_STYLE:
|
||||||
|
if(toggleForStyles) ToggleSelectionStateOfHovered();
|
||||||
|
Style::AssignSelectionToStyle(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if(ret >= CMNU_FIRST_STYLE) {
|
||||||
|
if(toggleForStyles) ToggleSelectionStateOfHovered();
|
||||||
|
Style::AssignSelectionToStyle(ret - CMNU_FIRST_STYLE);
|
||||||
|
}
|
||||||
|
// otherwise it was probably cancelled, so do nothing
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
context.active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
hRequest GraphicsWindow::AddRequest(int type) {
|
hRequest GraphicsWindow::AddRequest(int type) {
|
||||||
|
@ -607,43 +772,10 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
default: {
|
default:
|
||||||
ClearPending();
|
ClearPending();
|
||||||
|
ToggleSelectionStateOfHovered();
|
||||||
if(hover.IsEmpty()) break;
|
|
||||||
|
|
||||||
// If an item is hovered, then by clicking on it, we toggle its
|
|
||||||
// selection state.
|
|
||||||
int i;
|
|
||||||
for(i = 0; i < MAX_SELECTED; i++) {
|
|
||||||
if(selection[i].Equals(&hover)) {
|
|
||||||
selection[i].Clear();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(i != MAX_SELECTED) break;
|
|
||||||
|
|
||||||
if(hover.entity.v != 0 && SK.GetEntity(hover.entity)->IsFace()) {
|
|
||||||
// In the interest of speed for the triangle drawing code,
|
|
||||||
// only two faces may be selected at a time.
|
|
||||||
int c = 0;
|
|
||||||
for(i = 0; i < MAX_SELECTED; i++) {
|
|
||||||
hEntity he = selection[i].entity;
|
|
||||||
if(he.v != 0 && SK.GetEntity(he)->IsFace()) {
|
|
||||||
c++;
|
|
||||||
if(c >= 2) selection[i].Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0; i < MAX_SELECTED; i++) {
|
|
||||||
if(selection[i].IsEmpty()) {
|
|
||||||
selection[i] = hover;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SS.later.showTW = true;
|
SS.later.showTW = true;
|
||||||
|
@ -771,11 +903,14 @@ void GraphicsWindow::MouseScroll(double x, double y, int delta) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsWindow::MouseLeave(void) {
|
void GraphicsWindow::MouseLeave(void) {
|
||||||
// Un-hover everything when the mouse leaves our window.
|
// Un-hover everything when the mouse leaves our window, unless there's
|
||||||
hover.Clear();
|
// currently a context menu shown.
|
||||||
toolbarTooltipped = 0;
|
if(!context.active) {
|
||||||
toolbarHovered = 0;
|
hover.Clear();
|
||||||
PaintGraphics();
|
toolbarTooltipped = 0;
|
||||||
|
toolbarHovered = 0;
|
||||||
|
PaintGraphics();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GraphicsWindow::Selection::Equals(Selection *b) {
|
bool GraphicsWindow::Selection::Equals(Selection *b) {
|
||||||
|
@ -851,6 +986,51 @@ void GraphicsWindow::ClearNonexistentSelectionItems(void) {
|
||||||
if(change) InvalidateGraphics();
|
if(change) InvalidateGraphics();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Toggle the selection state of the hovered item: if it was selected then
|
||||||
|
// un-select it, and if it wasn't then select it.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void GraphicsWindow::ToggleSelectionStateOfHovered(void) {
|
||||||
|
if(hover.IsEmpty()) return;
|
||||||
|
|
||||||
|
// If an item was selected, then we just un-select it.
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < MAX_SELECTED; i++) {
|
||||||
|
if(selection[i].Equals(&hover)) {
|
||||||
|
selection[i].Clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(i != MAX_SELECTED) return;
|
||||||
|
|
||||||
|
// So it's not selected, so we should select it.
|
||||||
|
|
||||||
|
if(hover.entity.v != 0 && SK.GetEntity(hover.entity)->IsFace()) {
|
||||||
|
// In the interest of speed for the triangle drawing code,
|
||||||
|
// only two faces may be selected at a time.
|
||||||
|
int c = 0;
|
||||||
|
for(i = 0; i < MAX_SELECTED; i++) {
|
||||||
|
hEntity he = selection[i].entity;
|
||||||
|
if(he.v != 0 && SK.GetEntity(he)->IsFace()) {
|
||||||
|
c++;
|
||||||
|
if(c >= 2) selection[i].Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < MAX_SELECTED; i++) {
|
||||||
|
if(selection[i].IsEmpty()) {
|
||||||
|
selection[i] = hover;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Sort the selection according to various critieria: the entities and
|
||||||
|
// constraints separately, counts of certain types of entities (circles,
|
||||||
|
// lines, etc.), and so on.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
void GraphicsWindow::GroupSelection(void) {
|
void GraphicsWindow::GroupSelection(void) {
|
||||||
memset(&gs, 0, sizeof(gs));
|
memset(&gs, 0, sizeof(gs));
|
||||||
int i;
|
int i;
|
||||||
|
|
|
@ -154,6 +154,8 @@ void GraphicsWindow::Init(void) {
|
||||||
showTextWindow = true;
|
showTextWindow = true;
|
||||||
ShowTextWindow(showTextWindow);
|
ShowTextWindow(showTextWindow);
|
||||||
|
|
||||||
|
context.active = false;
|
||||||
|
|
||||||
// Do this last, so that all the menus get updated correctly.
|
// Do this last, so that all the menus get updated correctly.
|
||||||
EnsureValidActives();
|
EnsureValidActives();
|
||||||
}
|
}
|
||||||
|
|
18
group.cpp
18
group.cpp
|
@ -777,21 +777,3 @@ void Group::CopyEntity(IdList<Entity,hEntity> *el,
|
||||||
el->Add(&en);
|
el->Add(&en);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Group::TagEdgesFromLineSegments(SEdgeList *el) {
|
|
||||||
int i, j;
|
|
||||||
for(i = 0; i < SK.entity.n; i++) {
|
|
||||||
Entity *e = &(SK.entity.elem[i]);
|
|
||||||
if(e->group.v != opA.v) continue;
|
|
||||||
if(e->type != Entity::LINE_SEGMENT) continue;
|
|
||||||
|
|
||||||
Vector p0 = SK.GetEntity(e->point[0])->PointGetNum();
|
|
||||||
Vector p1 = SK.GetEntity(e->point[1])->PointGetNum();
|
|
||||||
|
|
||||||
for(j = 0; j < el->l.n; j++) {
|
|
||||||
SEdge *se = &(el->l.elem[j]);
|
|
||||||
if((p0.Equals(se->a) && p1.Equals(se->b))) se->tag = e->h.v;
|
|
||||||
if((p0.Equals(se->b) && p1.Equals(se->a))) se->tag = e->h.v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
4
sketch.h
4
sketch.h
|
@ -201,7 +201,6 @@ public:
|
||||||
hEntity Remap(hEntity in, int copyNumber);
|
hEntity Remap(hEntity in, int copyNumber);
|
||||||
void MakeExtrusionLines(EntityList *el, hEntity in);
|
void MakeExtrusionLines(EntityList *el, hEntity in);
|
||||||
void MakeExtrusionTopBottomFaces(EntityList *el, hEntity pt);
|
void MakeExtrusionTopBottomFaces(EntityList *el, hEntity pt);
|
||||||
void TagEdgesFromLineSegments(SEdgeList *sle);
|
|
||||||
void CopyEntity(EntityList *el,
|
void CopyEntity(EntityList *el,
|
||||||
Entity *ep, int timesApplied, int remap,
|
Entity *ep, int timesApplied, int remap,
|
||||||
hParam dx, hParam dy, hParam dz,
|
hParam dx, hParam dy, hParam dz,
|
||||||
|
@ -654,6 +653,9 @@ public:
|
||||||
static void FreezeDefaultStyles(void);
|
static void FreezeDefaultStyles(void);
|
||||||
static void LoadFactoryDefaults(void);
|
static void LoadFactoryDefaults(void);
|
||||||
|
|
||||||
|
static void AssignSelectionToStyle(DWORD v);
|
||||||
|
static DWORD CreateCustomStyle(void);
|
||||||
|
|
||||||
static Style *Get(hStyle hs);
|
static Style *Get(hStyle hs);
|
||||||
static DWORD Color(hStyle hs, bool forExport=false);
|
static DWORD Color(hStyle hs, bool forExport=false);
|
||||||
static float Width(hStyle hs);
|
static float Width(hStyle hs);
|
||||||
|
|
|
@ -27,7 +27,7 @@ void SolveSpace::CheckLicenseFromRegistry(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const int SECONDS_IN_DAY = 60*60*24;
|
const int SECONDS_IN_DAY = 60*60*24;
|
||||||
license.trialDaysRemaining = 90 -
|
license.trialDaysRemaining = 30 -
|
||||||
(int)(((now - license.firstUse))/SECONDS_IN_DAY);
|
(int)(((now - license.firstUse))/SECONDS_IN_DAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,12 @@ void ShowTextEditControl(int hr, int c, char *s);
|
||||||
void HideTextEditControl(void);
|
void HideTextEditControl(void);
|
||||||
BOOL TextEditControlIsVisible(void);
|
BOOL TextEditControlIsVisible(void);
|
||||||
|
|
||||||
|
#define CONTEXT_SUBMENU (-1)
|
||||||
|
#define CONTEXT_SEPARATOR (-2)
|
||||||
|
void AddContextMenuItem(char *legend, int id);
|
||||||
|
void CreateContextSubmenu(void);
|
||||||
|
int ShowContextMenu(void);
|
||||||
|
|
||||||
void ShowTextWindow(BOOL visible);
|
void ShowTextWindow(BOOL visible);
|
||||||
void InvalidateText(void);
|
void InvalidateText(void);
|
||||||
void InvalidateGraphics(void);
|
void InvalidateGraphics(void);
|
||||||
|
|
74
style.cpp
74
style.cpp
|
@ -33,8 +33,8 @@ char *Style::CnfWidth(char *prefix) {
|
||||||
char *Style::CnfPrefixToName(char *prefix) {
|
char *Style::CnfPrefixToName(char *prefix) {
|
||||||
static char name[100];
|
static char name[100];
|
||||||
int i = 0, j;
|
int i = 0, j;
|
||||||
strcpy(name, "def-");
|
strcpy(name, "#def-");
|
||||||
j = 4;
|
j = 5;
|
||||||
while(prefix[i] && j < 90) {
|
while(prefix[i] && j < 90) {
|
||||||
if(isupper(prefix[i]) && i != 0) {
|
if(isupper(prefix[i]) && i != 0) {
|
||||||
name[j++] = '-';
|
name[j++] = '-';
|
||||||
|
@ -106,6 +106,46 @@ void Style::FreezeDefaultStyles(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DWORD Style::CreateCustomStyle(void) {
|
||||||
|
SS.UndoRemember();
|
||||||
|
DWORD vs = max(Style::FIRST_CUSTOM, SK.style.MaximumId() + 1);
|
||||||
|
hStyle hs = { vs };
|
||||||
|
(void)Style::Get(hs);
|
||||||
|
return hs.v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Style::AssignSelectionToStyle(DWORD v) {
|
||||||
|
bool showError = false;
|
||||||
|
SS.GW.GroupSelection();
|
||||||
|
|
||||||
|
SS.UndoRemember();
|
||||||
|
for(int i = 0; i < SS.GW.gs.entities; i++) {
|
||||||
|
hEntity he = SS.GW.gs.entity[i];
|
||||||
|
if(!he.isFromRequest()) {
|
||||||
|
showError = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
hRequest hr = he.request();
|
||||||
|
Request *r = SK.GetRequest(hr);
|
||||||
|
r->style.v = v;
|
||||||
|
SS.later.generateAll = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(showError) {
|
||||||
|
Error("Can't assign style to an entity that's derived from another "
|
||||||
|
"entity; try assigning a style to this entity's parent.");
|
||||||
|
}
|
||||||
|
|
||||||
|
SS.GW.ClearSelection();
|
||||||
|
InvalidateGraphics();
|
||||||
|
|
||||||
|
// And show that style's info screen in the text window.
|
||||||
|
SS.TW.GoToScreen(TextWindow::SCREEN_STYLE_INFO);
|
||||||
|
SS.TW.shown.style.v = v;
|
||||||
|
SS.later.showTW = true;
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Look up a style by its handle. If that style does not exist, then create
|
// Look up a style by its handle. If that style does not exist, then create
|
||||||
// the style, according to our table of default styles.
|
// the style, according to our table of default styles.
|
||||||
|
@ -241,10 +281,7 @@ void TextWindow::ScreenLoadFactoryDefaultStyles(int link, DWORD v) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextWindow::ScreenCreateCustomStyle(int link, DWORD v) {
|
void TextWindow::ScreenCreateCustomStyle(int link, DWORD v) {
|
||||||
SS.UndoRemember();
|
Style::CreateCustomStyle();
|
||||||
DWORD vs = max(Style::FIRST_CUSTOM, SK.style.MaximumId() + 1);
|
|
||||||
hStyle hs = { vs };
|
|
||||||
(void)Style::Get(hs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextWindow::ScreenChangeBackgroundColor(int link, DWORD v) {
|
void TextWindow::ScreenChangeBackgroundColor(int link, DWORD v) {
|
||||||
|
@ -475,29 +512,6 @@ void TextWindow::ShowStyleInfo(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextWindow::ScreenAssignSelectionToStyle(int link, DWORD v) {
|
void TextWindow::ScreenAssignSelectionToStyle(int link, DWORD v) {
|
||||||
bool showError = false;
|
Style::AssignSelectionToStyle(v);
|
||||||
SS.GW.GroupSelection();
|
|
||||||
|
|
||||||
SS.UndoRemember();
|
|
||||||
for(int i = 0; i < SS.GW.gs.entities; i++) {
|
|
||||||
hEntity he = SS.GW.gs.entity[i];
|
|
||||||
if(!he.isFromRequest()) {
|
|
||||||
showError = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
hRequest hr = he.request();
|
|
||||||
Request *r = SK.GetRequest(hr);
|
|
||||||
r->style.v = v;
|
|
||||||
SS.later.generateAll = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(showError) {
|
|
||||||
Error("Can't assign style to an entity that's derived from another "
|
|
||||||
"entity; try assigning a style to this entity's parent.");
|
|
||||||
}
|
|
||||||
|
|
||||||
SS.GW.ClearSelection();
|
|
||||||
InvalidateGraphics();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
20
ui.h
20
ui.h
|
@ -313,6 +313,7 @@ public:
|
||||||
Vector projRight;
|
Vector projRight;
|
||||||
Vector projUp;
|
Vector projUp;
|
||||||
Point2d mouse;
|
Point2d mouse;
|
||||||
|
bool startedMoving;
|
||||||
} orig;
|
} orig;
|
||||||
|
|
||||||
// When the user is dragging a point, don't solve multiple times without
|
// When the user is dragging a point, don't solve multiple times without
|
||||||
|
@ -320,6 +321,11 @@ public:
|
||||||
// not displayed.
|
// not displayed.
|
||||||
bool havePainted;
|
bool havePainted;
|
||||||
|
|
||||||
|
// Some state for the context menu.
|
||||||
|
struct {
|
||||||
|
bool active;
|
||||||
|
} context;
|
||||||
|
|
||||||
void NormalizeProjectionVectors(void);
|
void NormalizeProjectionVectors(void);
|
||||||
Point2d ProjectPoint(Vector p);
|
Point2d ProjectPoint(Vector p);
|
||||||
Vector ProjectPoint3(Vector p);
|
Vector ProjectPoint3(Vector p);
|
||||||
|
@ -422,9 +428,20 @@ public:
|
||||||
int n;
|
int n;
|
||||||
} gs;
|
} gs;
|
||||||
void GroupSelection(void);
|
void GroupSelection(void);
|
||||||
|
void ToggleSelectionStateOfHovered(void);
|
||||||
void ClearSuper(void);
|
void ClearSuper(void);
|
||||||
|
|
||||||
|
static const int CMNU_TOGGLE_SELECTION = 0x100;
|
||||||
|
static const int CMNU_UNSELECT_ALL = 0x101;
|
||||||
|
static const int CMNU_DELETE_SEL = 0x102;
|
||||||
|
static const int CMNU_NEW_CUSTOM_STYLE = 0x103;
|
||||||
|
static const int CMNU_NO_STYLE = 0x104;
|
||||||
|
static const int CMNU_GROUP_INFO = 0x105;
|
||||||
|
static const int CMNU_REFERENCE_DIM = 0x106;
|
||||||
|
static const int CMNU_OTHER_ANGLE = 0x107;
|
||||||
|
static const int CMNU_FIRST_STYLE = 0x40000000;
|
||||||
|
void ContextMenuListStyles(void);
|
||||||
|
|
||||||
// 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);
|
||||||
void ToolbarDraw(void);
|
void ToolbarDraw(void);
|
||||||
|
@ -459,6 +476,7 @@ public:
|
||||||
void MouseLeftUp(double x, double y);
|
void MouseLeftUp(double x, double y);
|
||||||
void MouseLeftDoubleClick(double x, double y);
|
void MouseLeftDoubleClick(double x, double y);
|
||||||
void MouseMiddleOrRightDown(double x, double y);
|
void MouseMiddleOrRightDown(double x, double y);
|
||||||
|
void MouseRightUp(double x, double y);
|
||||||
void MouseScroll(double x, double y, int delta);
|
void MouseScroll(double x, double y, int delta);
|
||||||
void MouseLeave(void);
|
void MouseLeave(void);
|
||||||
void EditControlDone(char *s);
|
void EditControlDone(char *s);
|
||||||
|
|
|
@ -49,6 +49,8 @@ char RecentFile[MAX_RECENT][MAX_PATH];
|
||||||
HMENU SubMenus[100];
|
HMENU SubMenus[100];
|
||||||
HMENU RecentOpenMenu, RecentImportMenu;
|
HMENU RecentOpenMenu, RecentImportMenu;
|
||||||
|
|
||||||
|
HMENU ContextMenu, ContextSubmenu;
|
||||||
|
|
||||||
int ClientIsSmallerBy;
|
int ClientIsSmallerBy;
|
||||||
|
|
||||||
HFONT FixedFont, LinkFont;
|
HFONT FixedFont, LinkFont;
|
||||||
|
@ -94,6 +96,42 @@ void Message(char *str, ...)
|
||||||
va_end(f);
|
va_end(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddContextMenuItem(char *label, int id)
|
||||||
|
{
|
||||||
|
if(!ContextMenu) ContextMenu = CreatePopupMenu();
|
||||||
|
|
||||||
|
if(id == CONTEXT_SUBMENU) {
|
||||||
|
AppendMenu(ContextMenu, MF_STRING | MF_POPUP,
|
||||||
|
(UINT_PTR)ContextSubmenu, label);
|
||||||
|
ContextSubmenu = NULL;
|
||||||
|
} else {
|
||||||
|
HMENU m = ContextSubmenu ? ContextSubmenu : ContextMenu;
|
||||||
|
if(id == CONTEXT_SEPARATOR) {
|
||||||
|
AppendMenu(m, MF_SEPARATOR, 0, "");
|
||||||
|
} else {
|
||||||
|
AppendMenu(m, MF_STRING, id, label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateContextSubmenu(void)
|
||||||
|
{
|
||||||
|
ContextSubmenu = CreatePopupMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ShowContextMenu(void)
|
||||||
|
{
|
||||||
|
POINT p;
|
||||||
|
GetCursorPos(&p);
|
||||||
|
int r = TrackPopupMenu(ContextMenu,
|
||||||
|
TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_TOPALIGN,
|
||||||
|
p.x, p.y, 0, GraphicsWnd, NULL);
|
||||||
|
|
||||||
|
DestroyMenu(ContextMenu);
|
||||||
|
ContextMenu = NULL;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
void CALLBACK TimerCallback(HWND hwnd, UINT msg, UINT_PTR id, DWORD time)
|
void CALLBACK TimerCallback(HWND hwnd, UINT msg, UINT_PTR id, DWORD time)
|
||||||
{
|
{
|
||||||
// The timer is periodic, so needs to be killed explicitly.
|
// The timer is periodic, so needs to be killed explicitly.
|
||||||
|
@ -709,6 +747,7 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
||||||
case WM_LBUTTONUP:
|
case WM_LBUTTONUP:
|
||||||
case WM_LBUTTONDBLCLK:
|
case WM_LBUTTONDBLCLK:
|
||||||
case WM_RBUTTONDOWN:
|
case WM_RBUTTONDOWN:
|
||||||
|
case WM_RBUTTONUP:
|
||||||
case WM_MBUTTONDOWN: {
|
case WM_MBUTTONDOWN: {
|
||||||
int x = LOWORD(lParam);
|
int x = LOWORD(lParam);
|
||||||
int y = HIWORD(lParam);
|
int y = HIWORD(lParam);
|
||||||
|
@ -738,6 +777,8 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
||||||
SS.GW.MouseLeftDoubleClick(x, y);
|
SS.GW.MouseLeftDoubleClick(x, y);
|
||||||
} else if(msg == WM_MBUTTONDOWN || msg == WM_RBUTTONDOWN) {
|
} else if(msg == WM_MBUTTONDOWN || msg == WM_RBUTTONDOWN) {
|
||||||
SS.GW.MouseMiddleOrRightDown(x, y);
|
SS.GW.MouseMiddleOrRightDown(x, y);
|
||||||
|
} else if(msg == WM_RBUTTONUP) {
|
||||||
|
SS.GW.MouseRightUp(x, y);
|
||||||
} else if(msg == WM_MOUSEMOVE) {
|
} else if(msg == WM_MOUSEMOVE) {
|
||||||
SS.GW.MouseMoved(x, y,
|
SS.GW.MouseMoved(x, y,
|
||||||
!!(wParam & MK_LBUTTON),
|
!!(wParam & MK_LBUTTON),
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
grid
|
grid
|
||||||
better text
|
better text
|
||||||
right-click menu
|
right-click menu
|
||||||
faster triangulation
|
wireframe export
|
||||||
interpolating splines
|
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
faster triangulation
|
||||||
|
interpolating splines
|
||||||
copy and paste
|
copy and paste
|
||||||
loop detection
|
loop detection
|
||||||
IGES export
|
IGES export
|
||||||
|
|
Loading…
Reference in New Issue
Block a user