Tweak the handles to make more space in the request ID, so that I

can use the high bits as an "import ID" for imported parts, for
hierarchy (that retains parametric capabilities).

Implement enought that I can draw a datum point or a line segment,
and drag points around in three-space. Still so much to do.

[git-p4: depot-paths = "//depot/solvespace/": change = 1665]
solver
Jonathan Westhues 2008-04-13 02:57:41 -08:00
parent d76e708c17
commit a0e78e0da2
9 changed files with 352 additions and 123 deletions

View File

@ -143,18 +143,28 @@ done:
}
void TextWindow::Show(void) {
ShowHeader();
switch(shown->screen) {
default:
shown->screen = SCREEN_GROUP_LIST;
// fall through
case SCREEN_GROUP_LIST:
ShowGroupList();
break;
if(!(SS.GW.pendingOperation)) SS.GW.pendingDescription = NULL;
case SCREEN_REQUEST_LIST:
ShowRequestList();
break;
ShowHeader();
if(SS.GW.pendingDescription) {
// A pending operation (that must be completed with the mouse in
// the graphics window) will preempt our usual display.
Printf("");
Printf("%s", SS.GW.pendingDescription);
} else {
switch(shown->screen) {
default:
shown->screen = SCREEN_GROUP_LIST;
// fall through
case SCREEN_GROUP_LIST:
ShowGroupList();
break;
case SCREEN_REQUEST_LIST:
ShowRequestList();
break;
}
}
InvalidateText();
}
@ -192,9 +202,17 @@ void TextWindow::ScreenNavigaton(int link, DWORD v) {
void TextWindow::ShowHeader(void) {
ClearScreen();
Printf(" %Lb%f<<%E %Lh%fhome%E",
(DWORD)(&TextWindow::ScreenNavigaton),
(DWORD)(&TextWindow::ScreenNavigaton));
SS.GW.EnsureValidActiveGroup();
if(SS.GW.pendingDescription) {
Printf("");
} else {
// Navigation buttons
Printf(" %Lb%f<<%E %Lh%fhome%E group:%s",
(DWORD)(&TextWindow::ScreenNavigaton),
(DWORD)(&TextWindow::ScreenNavigaton),
SS.group.FindById(SS.GW.activeGroup)->DescriptionString());
}
int datumColor;
if(SS.GW.show2dCsyss && SS.GW.showAxes && SS.GW.showPoints) {

18
dsc.h
View File

@ -78,14 +78,22 @@ public:
}
T *FindById(H h) {
T *t = FindByIdNoOops(h);
if(!t) {
dbp("failed to look up item %16lx, searched %d items", h.v, elems);
oops();
}
return t;
}
T *FindByIdNoOops(H h) {
int i;
for(i = 0; i < elems; i++) {
if(elem[i].t.h.v == h.v) {
return &(elem[i].t);
}
}
dbp("failed to look up item %16lx, searched %d items", h.v, elems);
oops();
return NULL;
}
void ClearTags(void) {
@ -112,6 +120,12 @@ public:
// and elemsAllocated is untouched, because we didn't resize
}
void MoveSelfInto(IdList<T,H> *l) {
memcpy(l, this, sizeof(*this));
elemsAllocated = elems = 0;
elem = NULL;
}
void Clear(void) {
elemsAllocated = elems = 0;
if(elem) free(elem);

View File

@ -31,7 +31,6 @@ double Entity::GetDistance(Point2d mp) {
}
void Entity::DrawOrGetDistance(void) {
if(!visible) return;
switch(type) {
case CSYS_2D: {
Vector p;
@ -45,16 +44,15 @@ void Entity::DrawOrGetDistance(void) {
Vector u = Vector::RotationU(q[0], q[1], q[2], q[3]);
Vector v = Vector::RotationV(q[0], q[1], q[2], q[3]);
double s = (min(SS.GW.width, SS.GW.height))*0.4;
double s = (min(SS.GW.width, SS.GW.height))*0.4/SS.GW.scale;
Vector pp = p.Plus (u).Plus (v);
Vector pm = p.Plus (u).Minus(v);
Vector mm = p.Minus(u).Minus(v);
Vector mp = p.Minus(u).Plus (v);
pp = pp.ScaledBy(s);
pm = pm.ScaledBy(s);
mm = mm.ScaledBy(s);
mp = mp.ScaledBy(s);
Vector us = u.ScaledBy(s);
Vector vs = v.ScaledBy(s);
Vector pp = p.Plus (us).Plus (vs);
Vector pm = p.Plus (us).Minus(vs);
Vector mm = p.Minus(us).Minus(vs);
Vector mp = p.Minus(us).Plus (vs);
LineDrawOrGetDistance(pp, pm);
LineDrawOrGetDistance(pm, mm);
@ -71,6 +69,17 @@ void Entity::DrawOrGetDistance(void) {
}
break;
}
case DATUM_POINT:
// All display is handled by the generated point.
break;
case LINE_SEGMENT: {
Vector a = SS.point.FindById(point(16))->GetCoords();
Vector b = SS.point.FindById(point(16+3))->GetCoords();
LineDrawOrGetDistance(a, b);
break;
}
default:
oops();
}

View File

@ -4,40 +4,73 @@
#define mView (&GraphicsWindow::MenuView)
#define mEdit (&GraphicsWindow::MenuEdit)
#define mReq (&GraphicsWindow::MenuRequest)
#define S 0x100
const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 0, "&File", 0, NULL },
{ 1, "&New\tCtrl+N", 0, NULL },
{ 1, "&Open...\tCtrl+O", 0, NULL },
{ 1, "&Save\tCtrl+S", 0, NULL },
{ 1, "Save &As...", 0, NULL },
{ 1, NULL, 0, NULL },
{ 1, "E&xit", 0, NULL },
{ 0, "&File", 0, NULL },
{ 1, "&New\tCtrl+N", 0, NULL },
{ 1, "&Open...\tCtrl+O", 0, NULL },
{ 1, "&Save\tCtrl+S", 0, NULL },
{ 1, "Save &As...", 0, NULL },
{ 1, NULL, 0, NULL },
{ 1, "E&xit", 0, NULL },
{ 0, "&Edit", 0, NULL },
{ 1, "&Undo\tCtrl+Z", 0, NULL },
{ 1, "&Redo\tCtrl+Y", 0, NULL },
{ 1, NULL, 0, NULL },
{ 1, "&Unselect All\tEsc", MNU_UNSELECT_ALL, 27, mEdit },
{ 0, "&Edit", 0, NULL },
{ 1, "&Undo\tCtrl+Z", 0, NULL },
{ 1, "&Redo\tCtrl+Y", 0, NULL },
{ 1, NULL, 0, NULL },
{ 1, "&Unselect All\tEsc", MNU_UNSELECT_ALL, 27, mEdit },
{ 0, "&View", 0, NULL },
{ 1, "Zoom &In\t+", MNU_ZOOM_IN, '+', mView },
{ 1, "Zoom &Out\t-", MNU_ZOOM_OUT, '-', mView },
{ 1, "Zoom To &Fit\tF", MNU_ZOOM_TO_FIT, 'F', mView },
{ 1, NULL, 0, NULL },
{ 1, "Onto Plane/Csys\tO", MNU_ORIENT_ONTO, 'O', mView },
{ 1, NULL, 0, NULL },
{ 1, "Dimensions in &Inches", 0, NULL },
{ 1, "Dimensions in &Millimeters", 0, NULL },
{ 0, "&View", 0, NULL },
{ 1, "Zoom &In\t+", MNU_ZOOM_IN, '+', mView },
{ 1, "Zoom &Out\t-", MNU_ZOOM_OUT, '-', mView },
{ 1, "Zoom To &Fit\tF", MNU_ZOOM_TO_FIT, 'F', mView },
{ 1, NULL, 0, NULL },
{ 1, "&Onto Plane / Coordinate System\tO", MNU_ORIENT_ONTO, 'O', mView },
{ 1, "&Lock Orientation\tL", 0, 'L', mView },
{ 1, NULL, 0, NULL },
{ 1, "Dimensions in &Inches", 0, NULL },
{ 1, "Dimensions in &Millimeters", 0, NULL },
{ 0, "&Sketch", 0, NULL },
{ 1, NULL, 0, NULL },
{ 1, "To&ggle Construction\tG", 0, NULL },
{ 0, "&Request", 0, NULL },
{ 1, "Datum &Point\tP", MNU_DATUM_POINT, 'P', mReq },
{ 1, "Datum A&xis\tX", 0, 'X', mReq },
{ 1, "Datum Pla&ne\tN", 0, 'N', mReq },
{ 1, "2d Coordinate S&ystem\tY", 0, 'Y', mReq },
{ 1, NULL, 0, NULL },
{ 1, "Line &Segment\tS", MNU_LINE_SEGMENT, 'S', mReq },
{ 1, "&Circle\tC", 0, 'C', mReq },
{ 1, "&Arc of a Circle\tA", 0, 'A', mReq },
{ 1, "&Cubic Segment\t3", 0, '3', mReq },
{ 1, NULL, 0, NULL },
{ 1, "Boolean &Union\tU", 0, 'U', mReq },
{ 1, "Boolean &Difference\tD", 0, 'D', mReq },
{ 1, "Step and Repeat &Translate\tT", 0, 'T', mReq },
{ 1, "Step and Repeat &Rotate\tR", 0, 'R', mReq },
{ 1, NULL, 0, NULL },
{ 1, "Sym&bolic Variable\tB", 0, 'B', mReq },
{ 1, "&Import From File...\tI", 0, 'I', mReq },
{ 1, NULL, 0, NULL },
{ 1, "To&ggle Construction\tG", 0, 'G', NULL },
{ 0, "&Constrain", 0, NULL },
{ 1, "S&ymmetric\tY", 0, NULL },
{ 0, "&Constrain", 0, NULL },
{ 1, "&Distance / Diameter\tShift+D", 0, 'D'|S, NULL },
{ 1, "A&ngle\tShift+N", 0, 'N'|S, NULL },
{ 1, "Other S&upplementary Angle\tShift+U", 0, 'U'|S, NULL },
{ 1, NULL, 0, NULL },
{ 1, "&Horizontal\tShift+H", 0, 'H'|S, NULL },
{ 1, "&Vertical\tShift+V", 0, 'V'|S, NULL },
{ 1, NULL, 0, NULL },
{ 1, "Coincident / &On Curve\tShift+O", 0, 'O'|S, NULL },
{ 1, "E&qual Length / Radius\tShift+Q", 0, 'Q'|S, NULL },
{ 1, "At &Midpoint\tShift+M", 0, 'M'|S, NULL },
{ 1, "S&ymmetric\tShift+Y", 0, 'Y'|S, NULL },
{ 1, NULL, 0, NULL },
{ 1, "Sym&bolic Equation\tShift+B", 0, 'B'|S, NULL },
{ 0, "&Help", 0, NULL },
{ 1, "&About\t", 0, NULL },
{ 0, "&Help", 0, NULL },
{ 1, "&About\t", 0, NULL },
{ -1 },
};
@ -49,6 +82,8 @@ void GraphicsWindow::Init(void) {
projRight.x = 1; projRight.y = projRight.z = 0;
projUp.y = 1; projUp.z = projUp.x = 0;
EnsureValidActiveGroup();
show2dCsyss = true;
showAxes = true;
showPoints = true;
@ -109,16 +144,62 @@ void GraphicsWindow::MenuView(MenuId id) {
InvalidateGraphics();
}
void GraphicsWindow::EnsureValidActiveGroup(void) {
Group *g = SS.group.FindByIdNoOops(activeGroup);
if(g && g->h.v != Group::HGROUP_REFERENCES.v) {
return;
}
int i;
for(i = 0; i < SS.group.elems; i++) {
if(SS.group.elem[i].t.h.v != Group::HGROUP_REFERENCES.v) {
break;
}
}
if(i >= SS.group.elems) oops();
activeGroup = SS.group.elem[i].t.h;
}
void GraphicsWindow::MenuEdit(MenuId id) {
switch(id) {
case MNU_UNSELECT_ALL:
SS.GW.ClearSelection();
SS.GW.pendingOperation = 0;
SS.GW.pendingDescription = NULL;
SS.TW.Show();
break;
default: oops();
}
}
void GraphicsWindow::MenuRequest(MenuId id) {
char *s;
switch(id) {
case MNU_DATUM_POINT: s = "click to place datum point"; goto c;
case MNU_LINE_SEGMENT: s = "click first point of line segment"; goto c;
c:
SS.GW.pendingOperation = id;
SS.GW.pendingDescription = s;
SS.TW.Show();
break;
default: oops();
}
}
void GraphicsWindow::UpdateDraggedPoint(hPoint hp, double mx, double my) {
Point *p = SS.point.FindById(hp);
Vector pos = p->GetCoords();
pos = pos.Plus(projRight.ScaledBy((mx - orig.mouse.x)/scale));
pos = pos.Plus(projUp.ScaledBy((my - orig.mouse.y)/scale));
p->ForceTo(pos);
orig.mouse.x = mx;
orig.mouse.y = my;
InvalidateGraphics();
}
void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
bool middleDown, bool rightDown, bool shiftDown, bool ctrlDown)
{
@ -158,14 +239,23 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
orig.mouse.y = y;
InvalidateGraphics();
} else if(leftDown) {
// We are left-dragging. This is often used to drag points.
if(hover.point.v && !hover.point.isFromReferences()) {
ClearSelection();
UpdateDraggedPoint(hover.point, x, y);
}
} else {
// No mouse buttons are pressed. We just need to do our usual hit
// testing, to see if anything ought to be hovered.
Selection s;
HitTestMakeSelection(mp, &s);
if(!s.Equals(&hover)) {
hover = s;
InvalidateGraphics();
if(pendingOperation == PENDING_OPERATION_DRAGGING_POINT) {
UpdateDraggedPoint(pendingPoint, x, y);
} else {
// Do our usual hit testing, for the selection.
Selection s;
HitTestMakeSelection(mp, &s);
if(!s.Equals(&hover)) {
hover = s;
InvalidateGraphics();
}
}
}
}
@ -252,28 +342,76 @@ void GraphicsWindow::MouseMiddleDown(double x, double y) {
orig.mouse.y = y;
}
void GraphicsWindow::MouseLeftDown(double x, double y) {
// Make sure the hover is up to date.
MouseMoved(x, y, false, false, false, false, false);
hRequest GraphicsWindow::AddRequest(int type) {
Request r;
memset(&r, 0, sizeof(r));
r.group = activeGroup;
r.type = type;
SS.request.AddAndAssignId(&r);
SS.GenerateAll();
return r.h;
}
if(!hover.IsEmpty()) {
int i;
for(i = 0; i < MAX_SELECTED; i++) {
if(selection[i].Equals(&hover)) {
selection[i].Clear();
goto done;
void GraphicsWindow::MouseLeftDown(double mx, double my) {
// Make sure the hover is up to date.
MouseMoved(mx, my, false, false, false, false, false);
orig.mouse.x = mx;
orig.mouse.y = my;
// The current mouse location
Vector v = offset.ScaledBy(-1);
v = v.Plus(projRight.ScaledBy(mx/scale));
v = v.Plus(projUp.ScaledBy(my/scale));
hRequest hr;
switch(pendingOperation) {
case MNU_DATUM_POINT:
hr = AddRequest(Request::DATUM_POINT);
SS.point.FindById(hr.entity(0).point(16))->ForceTo(v);
pendingOperation = 0;
break;
case MNU_LINE_SEGMENT:
hr = AddRequest(Request::LINE_SEGMENT);
SS.point.FindById(hr.entity(0).point(16))->ForceTo(v);
pendingOperation = PENDING_OPERATION_DRAGGING_POINT;
pendingPoint = hr.entity(0).point(16+3);
SS.point.FindById(pendingPoint)->ForceTo(v);
break;
case PENDING_OPERATION_DRAGGING_POINT:
pendingOperation = 0;
break;
case 0:
default: {
pendingOperation = 0;
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;
}
}
}
for(i = 0; i < MAX_SELECTED; i++) {
if(selection[i].IsEmpty()) {
selection[i] = hover;
goto done;
if(i != MAX_SELECTED) break;
for(i = 0; i < MAX_SELECTED; i++) {
if(selection[i].IsEmpty()) {
selection[i] = hover;
break;
}
}
break;
}
// I guess we ran out of slots, oh well.
done:
InvalidateGraphics();
}
SS.TW.Show();
InvalidateGraphics();
}
void GraphicsWindow::MouseScroll(double x, double y, int delta) {
@ -302,7 +440,7 @@ void GraphicsWindow::ToggleBool(int link, DWORD v) {
bool *vb = (bool *)v;
*vb = !*vb;
SS.GenerateForUserInterface();
SS.GenerateAll();
InvalidateGraphics();
SS.TW.Show();
}
@ -313,7 +451,7 @@ void GraphicsWindow::ToggleAnyDatumShown(int link, DWORD v) {
SS.GW.showAxes = t;
SS.GW.showPoints = t;
SS.GenerateForUserInterface();
SS.GenerateAll();
InvalidateGraphics();
SS.TW.Show();
}

View File

@ -10,9 +10,9 @@ const hRequest Request::HREQUEST_REFERENCE_ZX = { 3 };
char *Group::DescriptionString(void) {
static char ret[100];
if(name.str[0]) {
sprintf(ret, "g%03x-%s", h.v, name.str);
sprintf(ret, "g%04x-%s", h.v, name.str);
} else {
sprintf(ret, "g%03x-(unnamed)", h.v);
sprintf(ret, "g%04x-(unnamed)", h.v);
}
return ret;
}
@ -30,7 +30,7 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
{
int points = 0;
int params = 0;
int type = 0;
int et = 0;
int i;
Group *g = SS.group.FindById(group);
@ -42,11 +42,13 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
bool shown = true;
switch(type) {
case Request::CSYS_2D:
type = Entity::CSYS_2D; points = 1; params = 4;
if(!SS.GW.show2dCsyss) shown = false;
goto c;
et = Entity::CSYS_2D; points = 1; params = 4; goto c;
case Request::DATUM_POINT:
et = Entity::DATUM_POINT; points = 1; params = 0; goto c;
case Request::LINE_SEGMENT:
type = Entity::LINE_SEGMENT; points = 2; params = 0; goto c;
et = Entity::LINE_SEGMENT; points = 2; params = 0; goto c;
c: {
// Common routines, for all the requests that generate a single
// entity that's defined by a simple combination of pts and params.
@ -70,12 +72,10 @@ c: {
AddParam(param, &e, 16 + 3*i + 0);
AddParam(param, &e, 16 + 3*i + 1);
}
pt.visible = shown;
point->Add(&pt);
}
e.type = type;
e.visible = shown;
e.type = et;
entity->Add(&e);
break;
}
@ -130,8 +130,6 @@ Vector Point::GetCoords(void) {
}
void Point::Draw(void) {
if(!visible) return;
Vector v = GetCoords();
double s = 4;
@ -147,8 +145,6 @@ void Point::Draw(void) {
}
double Point::GetDistance(Point2d mp) {
if(!visible) return 1e12;
Vector v = GetCoords();
Point2d pp = SS.GW.ProjectPoint(v);

View File

@ -21,28 +21,36 @@ public:
};
class hRequest {
public:
// bits 10: 0 -- request index
// bits 14: 0 -- request index (the high bits may be used as an import ID)
DWORD v;
inline hEntity entity(int i);
};
class hEntity {
public:
// bits 10: 0 -- entity index
// 21:11 -- request index
// bits 9: 0 -- entity index
// 24:10 -- request index
DWORD v;
inline hRequest request(void);
inline hParam param(int i);
inline hPoint point(int i);
};
class hParam {
public:
// bits 7: 0 -- param index
// 18: 8 -- entity index
// 29:19 -- request index
// bits 6: 0 -- param index
// 16: 7 -- entity index
// 31:17 -- request index
DWORD v;
};
class hPoint {
// bits 7: 0 -- point index
// 18: 8 -- entity index
// 29:19 -- request index
// bits 6: 0 -- point index
// 16: 7 -- entity index
// 31:17 -- request index
public:
DWORD v;
inline bool isFromReferences(void);
};
// A set of requests. Every request must have an associated group. A group
@ -71,8 +79,9 @@ public:
static const hRequest HREQUEST_REFERENCE_ZX;
// Types of requests
static const int CSYS_2D = 0;
static const int LINE_SEGMENT = 1;
static const int CSYS_2D = 0;
static const int DATUM_POINT = 1;
static const int LINE_SEGMENT = 10;
int type;
@ -83,7 +92,7 @@ public:
NameStr name;
inline hEntity entity(int i)
{ hEntity r; r.v = ((this->h.v) << 11) | i; return r; }
{ hEntity r; r.v = ((this->h.v) << 10) | i; return r; }
void AddParam(IdList<Param,hParam> *param, Entity *e, int index);
void Generate(IdList<Entity,hEntity> *entity,
@ -97,22 +106,21 @@ class Entity {
public:
static const hEntity NO_CSYS;
static const int CSYS_2D = 100;
static const int LINE_SEGMENT = 101;
static const int CSYS_2D = 1000;
static const int DATUM_POINT = 1001;
static const int LINE_SEGMENT = 1010;
int type;
hEntity h;
bool visible;
Expr *expr[16];
inline hRequest request(void)
{ hRequest r; r.v = (this->h.v >> 11); return r; }
{ hRequest r; r.v = (this->h.v >> 10); return r; }
inline hParam param(int i)
{ hParam r; r.v = ((this->h.v) << 8) | i; return r; }
{ hParam r; r.v = ((this->h.v) << 7) | i; return r; }
inline hPoint point(int i)
{ hPoint r; r.v = ((this->h.v) << 8) | i; return r; }
{ hPoint r; r.v = ((this->h.v) << 7) | i; return r; }
struct {
bool drawing;
@ -145,10 +153,9 @@ public:
static const int BY_EXPR = 2; // three Expr *, could be anything
hEntity csys;
bool visible;
inline hEntity entity(void)
{ hEntity r; r.v = (h.v >> 8); return r; }
{ hEntity r; r.v = (h.v >> 7); return r; }
inline hParam param(int i)
{ hParam r; r.v = h.v + i; return r; }
@ -164,4 +171,23 @@ public:
double GetDistance(Point2d mp);
};
inline hEntity hRequest::entity(int i)
{ hEntity r; r.v = (v << 10) | i; return r; }
inline hRequest hEntity::request(void)
{ hRequest r; r.v = (v >> 10); return r; }
inline hParam hEntity::param(int i)
{ hParam r; r.v = (v << 7) | i; return r; }
inline hPoint hEntity::point(int i)
{ hPoint r; r.v = (v << 7) | i; return r; }
inline bool hPoint::isFromReferences(void) {
DWORD d = v >> 17;
if(d == Request::HREQUEST_REFERENCE_XY.v) return true;
if(d == Request::HREQUEST_REFERENCE_YZ.v) return true;
if(d == Request::HREQUEST_REFERENCE_ZX.v) return true;
return false;
}
#endif

View File

@ -7,9 +7,6 @@ template IdList<Point,hPoint>;
SolveSpace SS;
void SolveSpace::Init(void) {
TW.Init();
GW.Init();
request.Clear();
entity.Clear();
point.Clear();
@ -48,20 +45,32 @@ void SolveSpace::Init(void) {
r.h = Request::HREQUEST_REFERENCE_ZX;
request.Add(&r);
TW.Init();
GW.Init();
TW.Show();
GenerateForUserInterface();
GenerateAll();
}
void SolveSpace::GenerateForUserInterface(void) {
void SolveSpace::GenerateAll(void) {
int i;
IdList<Param,hParam> prev;
param.MoveSelfInto(&prev);
entity.Clear();
param.Clear();
point.Clear();
for(i = 0; i < request.elems; i++) {
request.elem[i].t.Generate(&entity, &point, &param);
}
for(i = 0; i < param.elems; i++) {
Param *p = prev.FindByIdNoOops(param.elem[i].t.h);
if(p) {
param.elem[i].t.val = p->val;
}
}
ForceReferences();
}

View File

@ -60,7 +60,7 @@ public:
hGroup activeGroup;
void GenerateForUserInterface(void);
void GenerateAll(void);
void ForceReferences(void);
void Init(void);

21
ui.h
View File

@ -41,7 +41,7 @@ public:
void Init(void);
void Printf(char *fmt, ...);
void ClearScreen(void);
void Show(void);
// State for the screen that we are showing in the text window.
@ -73,11 +73,15 @@ public:
// This table describes the top-level menus in the graphics winodw.
typedef enum {
// View
MNU_ZOOM_IN = 100,
MNU_ZOOM_OUT,
MNU_ZOOM_TO_FIT,
MNU_ORIENT_ONTO,
MNU_UNSELECT_ALL,
// Request
MNU_DATUM_POINT,
MNU_LINE_SEGMENT,
} MenuId;
typedef void MenuHandler(MenuId id);
typedef struct {
@ -90,6 +94,7 @@ public:
static const MenuEntry menu[];
static void MenuView(MenuId id);
static void MenuEdit(MenuId id);
static void MenuRequest(MenuId id);
// The width and height (in pixels) of the window.
double width, height;
@ -109,6 +114,18 @@ public:
void NormalizeProjectionVectors(void);
Point2d ProjectPoint(Vector p);
hGroup activeGroup;
void EnsureValidActiveGroup();
// Operations that must be completed by doing something with the mouse
// are noted here.
static const int PENDING_OPERATION_DRAGGING_POINT = 0x0f000000;
hPoint pendingPoint;
int pendingOperation;
char *pendingDescription;
hRequest AddRequest(int type);
// The current selection.
class Selection {
@ -146,6 +163,8 @@ public:
static void ToggleBool(int link, DWORD v);
static void ToggleAnyDatumShown(int link, DWORD v);
void UpdateDraggedPoint(hPoint hp, double mx, double my);
// These are called by the platform-specific code.
void Paint(int w, int h);
void MouseMoved(double x, double y, bool leftDown, bool middleDown,