Add the keyboard accelerator mechanism for menu items. Use that to

implement zoom in/out, and orient onto a csys.

[git-p4: depot-paths = "//depot/solvespace/": change = 1663]
solver
Jonathan Westhues 2008-04-12 07:17:58 -08:00
parent 6c63d9c8cb
commit d36c70216a
6 changed files with 222 additions and 61 deletions

View File

@ -36,16 +36,15 @@ void Entity::DrawOrGetDistance(void) {
if(!SS.GW.show2dCsyss) break; if(!SS.GW.show2dCsyss) break;
Vector p; Vector p;
double a, b, c, d;
p = SS.point.FindById(point(16))->GetCoords(); p = SS.point.FindById(point(16))->GetCoords();
a = SS.param.FindById(param(0))->val;
b = SS.param.FindById(param(1))->val;
c = SS.param.FindById(param(2))->val;
d = SS.param.FindById(param(3))->val;
Vector u = Vector::RotationU(a, b, c, d); double q[4];
Vector v = Vector::RotationV(a, b, c, d); for(int i = 0; i < 4; i++) {
q[i] = SS.param.FindById(param(i))->val;
}
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;
@ -77,3 +76,4 @@ void Entity::DrawOrGetDistance(void) {
oops(); oops();
} }
} }

View File

@ -2,36 +2,43 @@
#include "solvespace.h" #include "solvespace.h"
#define mView (&GraphicsWindow::MenuView)
#define mEdit (&GraphicsWindow::MenuEdit)
const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 0, "&File", 0, NULL }, { 0, "&File", 0, NULL },
{ 1, "&New\tCtrl+N", 0, NULL }, { 1, "&New\tCtrl+N", 0, NULL },
{ 1, "&Open...\tCtrl+O", 0, NULL }, { 1, "&Open...\tCtrl+O", 0, NULL },
{ 1, "&Save\tCtrl+S", 0, NULL }, { 1, "&Save\tCtrl+S", 0, NULL },
{ 1, "Save &As...", 0, NULL }, { 1, "Save &As...", 0, NULL },
{ 1, NULL, 0, NULL }, { 1, NULL, 0, NULL },
{ 1, "E&xit", 0, NULL }, { 1, "E&xit", 0, NULL },
{ 0, "&Edit", 0, NULL }, { 0, "&Edit", 0, NULL },
{ 1, "&Undo\tCtrl+Z", 0, NULL }, { 1, "&Undo\tCtrl+Z", 0, NULL },
{ 1, "&Redo\tCtrl+Y", 0, NULL }, { 1, "&Redo\tCtrl+Y", 0, NULL },
{ 0, "&View", 0, NULL }, { 1, NULL, 0, NULL },
{ 1, "Zoom &In\t+", 0, NULL }, { 1, "&Unselect All\tEsc", MNU_UNSELECT_ALL, 27, mEdit },
{ 1, "Zoom &Out\t-", 0, NULL },
{ 1, "Zoom To &Fit\tF", 0, NULL },
{ 1, NULL, 0, NULL },
{ 1, "Dimensions in &Inches", 0, NULL },
{ 1, "Dimensions in &Millimeters", 0, NULL },
{ 0, "&Sketch", 0, NULL }, { 0, "&View", 0, NULL },
{ 1, NULL, 0, NULL }, { 1, "Zoom &In\t+", MNU_ZOOM_IN, '+', mView },
{ 1, "To&ggle Construction\tG", 0, NULL }, { 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, "&Constrain", 0, NULL }, { 0, "&Sketch", 0, NULL },
{ 1, "S&ymmetric\tY", 0, NULL }, { 1, NULL, 0, NULL },
{ 1, "To&ggle Construction\tG", 0, NULL },
{ 0, "&Help", 0, NULL }, { 0, "&Constrain", 0, NULL },
{ 1, "&About\t", 0, NULL }, { 1, "S&ymmetric\tY", 0, NULL },
{ -1 },
{ 0, "&Help", 0, NULL },
{ 1, "&About\t", 0, NULL },
{ -1 },
}; };
void GraphicsWindow::Init(void) { void GraphicsWindow::Init(void) {
@ -40,7 +47,7 @@ void GraphicsWindow::Init(void) {
offset.x = offset.y = offset.z = 0; offset.x = offset.y = offset.z = 0;
scale = 1; scale = 1;
projRight.x = 1; projRight.y = projRight.z = 0; projRight.x = 1; projRight.y = projRight.z = 0;
projDown.y = 1; projDown.z = projDown.x = 0; projUp.y = 1; projUp.z = projUp.x = 0;
show2dCsyss = true; show2dCsyss = true;
showAxes = true; showAxes = true;
@ -50,10 +57,10 @@ void GraphicsWindow::Init(void) {
} }
void GraphicsWindow::NormalizeProjectionVectors(void) { void GraphicsWindow::NormalizeProjectionVectors(void) {
Vector norm = projRight.Cross(projDown); Vector norm = projRight.Cross(projUp);
projDown = norm.Cross(projRight); projUp = norm.Cross(projRight);
projDown = projDown.ScaledBy(1/projDown.Magnitude()); projUp = projUp.ScaledBy(1/projUp.Magnitude());
projRight = projRight.ScaledBy(1/projRight.Magnitude()); projRight = projRight.ScaledBy(1/projRight.Magnitude());
} }
@ -62,10 +69,56 @@ Point2d GraphicsWindow::ProjectPoint(Vector p) {
Point2d r; Point2d r;
r.x = p.Dot(projRight) * scale; r.x = p.Dot(projRight) * scale;
r.y = p.Dot(projDown) * scale; r.y = p.Dot(projUp) * scale;
return r; return r;
} }
void GraphicsWindow::MenuView(MenuId id) {
switch(id) {
case MNU_ZOOM_IN:
SS.GW.scale *= 1.2;
break;
case MNU_ZOOM_OUT:
SS.GW.scale /= 1.2;
break;
case MNU_ZOOM_TO_FIT:
break;
case MNU_ORIENT_ONTO:
SS.GW.GroupSelection();
if(SS.GW.gs.n == 1 && SS.GW.gs.csyss == 1) {
Entity *e = SS.entity.FindById(SS.GW.gs.entity[0]);
double q[4];
for(int i = 0; i < 4; i++) {
q[i] = SS.param.FindById(e->param(i))->val;
}
SS.GW.projRight = Vector::RotationU(q[0], q[1], q[2], q[3]);
SS.GW.projUp = Vector::RotationV(q[0], q[1], q[2], q[3]);
SS.GW.offset = SS.point.FindById(e->point(16))->GetCoords();
SS.GW.ClearSelection();
InvalidateGraphics();
} else {
Error("Select plane or coordinate system before orienting.");
}
break;
default: oops();
}
InvalidateGraphics();
}
void GraphicsWindow::MenuEdit(MenuId id) {
switch(id) {
case MNU_UNSELECT_ALL:
SS.GW.ClearSelection();
break;
default: oops();
}
}
void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, 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)
{ {
@ -78,28 +131,28 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
double dy = (y - orig.mouse.y) / scale; double dy = (y - orig.mouse.y) / scale;
if(shiftDown) { if(shiftDown) {
offset.x = orig.offset.x + dx*projRight.x + dy*projDown.x; offset.x = orig.offset.x + dx*projRight.x + dy*projUp.x;
offset.y = orig.offset.y + dx*projRight.y + dy*projDown.y; offset.y = orig.offset.y + dx*projRight.y + dy*projUp.y;
offset.z = orig.offset.z + dx*projRight.z + dy*projDown.z; offset.z = orig.offset.z + dx*projRight.z + dy*projUp.z;
} else if(ctrlDown) { } else if(ctrlDown) {
double theta = atan2(orig.mouse.y, orig.mouse.x); double theta = atan2(orig.mouse.y, orig.mouse.x);
theta -= atan2(y, x); theta -= atan2(y, x);
Vector normal = orig.projRight.Cross(orig.projDown); Vector normal = orig.projRight.Cross(orig.projUp);
projRight = orig.projRight.RotatedAbout(normal, theta); projRight = orig.projRight.RotatedAbout(normal, theta);
projDown = orig.projDown.RotatedAbout(normal, theta); projUp = orig.projUp.RotatedAbout(normal, theta);
NormalizeProjectionVectors(); NormalizeProjectionVectors();
} else { } else {
double s = 0.3*(PI/180); // degrees per pixel double s = 0.3*(PI/180); // degrees per pixel
projRight = orig.projRight.RotatedAbout(orig.projDown, -s*dx); projRight = orig.projRight.RotatedAbout(orig.projUp, -s*dx);
projDown = orig.projDown.RotatedAbout(orig.projRight, s*dy); projUp = orig.projUp.RotatedAbout(orig.projRight, s*dy);
NormalizeProjectionVectors(); NormalizeProjectionVectors();
} }
orig.projRight = projRight; orig.projRight = projRight;
orig.projDown = projDown; orig.projUp = projUp;
orig.offset = offset; orig.offset = offset;
orig.mouse.x = x; orig.mouse.x = x;
orig.mouse.y = y; orig.mouse.y = y;
@ -142,6 +195,7 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp, Selection *dest) {
dest->point.v = 0; dest->point.v = 0;
dest->entity.v = 0; dest->entity.v = 0;
// Do the points
for(i = 0; i < SS.entity.elems; i++) { for(i = 0; i < SS.entity.elems; i++) {
d = SS.entity.elem[i].t.GetDistance(mp); d = SS.entity.elem[i].t.GetDistance(mp);
if(d < 10 && d < dmin) { if(d < 10 && d < dmin) {
@ -150,6 +204,7 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp, Selection *dest) {
} }
} }
// Entities
for(i = 0; i < SS.point.elems; i++) { for(i = 0; i < SS.point.elems; i++) {
d = SS.point.elem[i].t.GetDistance(mp); d = SS.point.elem[i].t.GetDistance(mp);
if(d < 10 && d < dmin) { if(d < 10 && d < dmin) {
@ -159,9 +214,39 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp, Selection *dest) {
} }
} }
void GraphicsWindow::ClearSelection(void) {
for(int i = 0; i < MAX_SELECTED; i++) {
selection[i].Clear();
}
InvalidateGraphics();
}
void GraphicsWindow::GroupSelection(void) {
gs.points = gs.entities = 0;
gs.csyss = 0;
gs.n = 0;
int i;
for(i = 0; i < MAX_SELECTED; i++) {
Selection *s = &(selection[i]);
if(s->point.v) {
gs.point[(gs.points)++] = s->point;
(gs.n)++;
}
if(s->entity.v) {
gs.entity[(gs.entities)++] = s->entity;
(gs.n)++;
Entity *e = SS.entity.FindById(s->entity);
if(e->type == Entity::CSYS_2D) {
(gs.csyss)++;
}
}
}
}
void GraphicsWindow::MouseMiddleDown(double x, double y) { void GraphicsWindow::MouseMiddleDown(double x, double y) {
orig.offset = offset; orig.offset = offset;
orig.projDown = projDown; 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;
@ -193,22 +278,22 @@ done:
void GraphicsWindow::MouseScroll(double x, double y, int delta) { void GraphicsWindow::MouseScroll(double x, double y, int delta) {
double offsetRight = offset.Dot(projRight); double offsetRight = offset.Dot(projRight);
double offsetDown = offset.Dot(projDown); double offsetUp = offset.Dot(projUp);
double righti = x/scale - offsetRight; double righti = x/scale - offsetRight;
double downi = y/scale - offsetDown; double upi = y/scale - offsetUp;
if(delta > 0) { if(delta > 0) {
scale *= 1.3; scale *= 1.2;
} else { } else {
scale /= 1.3; scale /= 1.2;
} }
double rightf = x/scale - offsetRight; double rightf = x/scale - offsetRight;
double downf = y/scale - offsetDown; double upf = y/scale - offsetUp;
offset = offset.Plus(projRight.ScaledBy(rightf - righti)); offset = offset.Plus(projRight.ScaledBy(rightf - righti));
offset = offset.Plus(projDown.ScaledBy(downf - downi)); offset = offset.Plus(projUp.ScaledBy(upf - upi));
InvalidateGraphics(); InvalidateGraphics();
} }
@ -245,10 +330,10 @@ void GraphicsWindow::Paint(int w, int h) {
glScaled(scale*2.0/w, scale*2.0/h, 0); glScaled(scale*2.0/w, scale*2.0/h, 0);
double tx = projRight.Dot(offset); double tx = projRight.Dot(offset);
double ty = projDown.Dot(offset); double ty = projUp.Dot(offset);
double mat[16]; double mat[16];
MakeMatrix(mat, projRight.x, projRight.y, projRight.z, tx, MakeMatrix(mat, projRight.x, projRight.y, projRight.z, tx,
projDown.x, projDown.y, projDown.z, ty, projUp.x, projUp.y, projUp.z, ty,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1); 0, 0, 0, 1);
glMultMatrixd(mat); glMultMatrixd(mat);

View File

@ -126,7 +126,7 @@ void Point::Draw(void) {
double s = 4; double s = 4;
Vector r = SS.GW.projRight.ScaledBy(4/SS.GW.scale); Vector r = SS.GW.projRight.ScaledBy(4/SS.GW.scale);
Vector d = SS.GW.projDown.ScaledBy(4/SS.GW.scale); Vector d = SS.GW.projUp.ScaledBy(4/SS.GW.scale);
glBegin(GL_QUADS); glBegin(GL_QUADS);
glxVertex3v(v.Plus (r).Plus (d)); glxVertex3v(v.Plus (r).Plus (d));

View File

@ -13,6 +13,7 @@
#endif #endif
void dbp(char *str, ...); void dbp(char *str, ...);
void Error(char *str, ...);
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>

30
ui.h
View File

@ -69,17 +69,27 @@ public:
class GraphicsWindow { class GraphicsWindow {
public: public:
void Init(void);
// This table describes the top-level menus in the graphics winodw. // This table describes the top-level menus in the graphics winodw.
typedef void MenuHandler(int id); typedef enum {
MNU_ZOOM_IN = 100,
MNU_ZOOM_OUT,
MNU_ZOOM_TO_FIT,
MNU_ORIENT_ONTO,
MNU_UNSELECT_ALL,
} MenuId;
typedef void MenuHandler(MenuId id);
typedef struct { typedef struct {
int level; // 0 == on menu bar, 1 == one level down int level; // 0 == on menu bar, 1 == one level down
char *label; // or NULL for a separator char *label; // or NULL for a separator
int id; // unique ID int id; // unique ID
int accel; // keyboard accelerator
MenuHandler *fn; MenuHandler *fn;
} MenuEntry; } MenuEntry;
static const MenuEntry menu[]; static const MenuEntry menu[];
static void MenuView(MenuId id);
void Init(void); static void MenuEdit(MenuId id);
// The width and height (in pixels) of the window. // The width and height (in pixels) of the window.
double width, height; double width, height;
@ -88,12 +98,12 @@ public:
// projection. // projection.
Vector offset; Vector offset;
Vector projRight; Vector projRight;
Vector projDown; Vector projUp;
double scale; double scale;
struct { struct {
Vector offset; Vector offset;
Vector projRight; Vector projRight;
Vector projDown; Vector projUp;
Point2d mouse; Point2d mouse;
} orig; } orig;
@ -116,6 +126,16 @@ public:
static const int MAX_SELECTED = 32; static const int MAX_SELECTED = 32;
Selection selection[MAX_SELECTED]; Selection selection[MAX_SELECTED];
void HitTestMakeSelection(Point2d mp, Selection *dest); void HitTestMakeSelection(Point2d mp, Selection *dest);
void ClearSelection(void);
struct {
hPoint point[MAX_SELECTED];
hEntity entity[MAX_SELECTED];
int points;
int entities;
int csyss;
int n;
} gs;
void GroupSelection(void);
// This sets what gets displayed. // This sets what gets displayed.
bool show2dCsyss; bool show2dCsyss;

View File

@ -42,6 +42,17 @@ void dbp(char *str, ...)
OutputDebugString("\n"); OutputDebugString("\n");
} }
void Error(char *str, ...)
{
va_list f;
char buf[1024];
va_start(f, str);
vsprintf(buf, str, f);
HWND h = GetForegroundWindow();
MessageBox(h, buf, "SolveSpace Error", MB_OK | MB_ICONERROR);
}
static void PaintTextWnd(HDC hdc) static void PaintTextWnd(HDC hdc)
{ {
RECT rect; RECT rect;
@ -241,6 +252,37 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
return 1; return 1;
} }
static BOOL ProcessKeyDown(WPARAM wParam)
{
int c;
switch(wParam) {
case VK_OEM_PLUS: c = '+'; break;
case VK_OEM_MINUS: c = '-'; break;
case VK_ESCAPE: c = 27; break;
case VK_OEM_4: c = '['; break;
case VK_OEM_6: c = ']'; break;
case VK_OEM_5: c = '\\'; break;
case VK_SPACE: c = ' '; break;
case VK_DELETE: c = 127; break;
default:
c = wParam;
break;
}
if(GetAsyncKeyState(VK_CONTROL) & 0x8000) c |= 0x100;
if(GetAsyncKeyState(VK_SHIFT) & 0x8000) c |= 0x200;
for(int i = 0; SS.GW.menu[i].level >= 0; i++) {
if(c == SS.GW.menu[i].accel) {
(SS.GW.menu[i].fn)((GraphicsWindow::MenuId)SS.GW.menu[i].id);
break;
}
}
// No accelerator; process the key as normal.
return FALSE;
}
static HGLRC CreateGlContext(HDC hdc) static HGLRC CreateGlContext(HDC hdc)
{ {
PIXELFORMATDESCRIPTOR pfd; PIXELFORMATDESCRIPTOR pfd;
@ -347,6 +389,16 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
SS.GW.MouseScroll(LastMousePos.x, LastMousePos.y, delta); SS.GW.MouseScroll(LastMousePos.x, LastMousePos.y, delta);
break; break;
} }
case WM_COMMAND: {
int id = LOWORD(wParam);
for(int i = 0; SS.GW.menu[i].level >= 0; i++) {
if(id == SS.GW.menu[i].id) {
(SS.GW.menu[i].fn)((GraphicsWindow::MenuId)id);
break;
}
}
break;
}
case WM_CLOSE: case WM_CLOSE:
case WM_DESTROY: case WM_DESTROY:
@ -485,6 +537,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
MSG msg; MSG msg;
DWORD ret; DWORD ret;
while(ret = GetMessage(&msg, NULL, 0, 0)) { while(ret = GetMessage(&msg, NULL, 0, 0)) {
if(msg.message == WM_KEYDOWN) {
if(ProcessKeyDown(msg.wParam)) continue;
}
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
} }