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;
Vector p;
double a, b, c, d;
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);
Vector v = Vector::RotationV(a, b, c, d);
double q[4];
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;
@ -77,3 +76,4 @@ void Entity::DrawOrGetDistance(void) {
oops();
}
}

View File

@ -2,36 +2,43 @@
#include "solvespace.h"
#define mView (&GraphicsWindow::MenuView)
#define mEdit (&GraphicsWindow::MenuEdit)
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 },
{ 0, "&View", 0, NULL },
{ 1, "Zoom &In\t+", 0, NULL },
{ 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, "&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, "&Sketch", 0, NULL },
{ 1, NULL, 0, NULL },
{ 1, "To&ggle Construction\tG", 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/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 },
{ 1, "S&ymmetric\tY", 0, NULL },
{ 0, "&Sketch", 0, NULL },
{ 1, NULL, 0, NULL },
{ 1, "To&ggle Construction\tG", 0, NULL },
{ 0, "&Help", 0, NULL },
{ 1, "&About\t", 0, NULL },
{ -1 },
{ 0, "&Constrain", 0, NULL },
{ 1, "S&ymmetric\tY", 0, NULL },
{ 0, "&Help", 0, NULL },
{ 1, "&About\t", 0, NULL },
{ -1 },
};
void GraphicsWindow::Init(void) {
@ -40,7 +47,7 @@ void GraphicsWindow::Init(void) {
offset.x = offset.y = offset.z = 0;
scale = 1;
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;
showAxes = true;
@ -50,10 +57,10 @@ void GraphicsWindow::Init(void) {
}
void GraphicsWindow::NormalizeProjectionVectors(void) {
Vector norm = projRight.Cross(projDown);
projDown = norm.Cross(projRight);
Vector norm = projRight.Cross(projUp);
projUp = norm.Cross(projRight);
projDown = projDown.ScaledBy(1/projDown.Magnitude());
projUp = projUp.ScaledBy(1/projUp.Magnitude());
projRight = projRight.ScaledBy(1/projRight.Magnitude());
}
@ -62,10 +69,56 @@ Point2d GraphicsWindow::ProjectPoint(Vector p) {
Point2d r;
r.x = p.Dot(projRight) * scale;
r.y = p.Dot(projDown) * scale;
r.y = p.Dot(projUp) * scale;
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,
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;
if(shiftDown) {
offset.x = orig.offset.x + dx*projRight.x + dy*projDown.x;
offset.y = orig.offset.y + dx*projRight.y + dy*projDown.y;
offset.z = orig.offset.z + dx*projRight.z + dy*projDown.z;
offset.x = orig.offset.x + dx*projRight.x + dy*projUp.x;
offset.y = orig.offset.y + dx*projRight.y + dy*projUp.y;
offset.z = orig.offset.z + dx*projRight.z + dy*projUp.z;
} else if(ctrlDown) {
double theta = atan2(orig.mouse.y, orig.mouse.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);
projDown = orig.projDown.RotatedAbout(normal, theta);
projUp = orig.projUp.RotatedAbout(normal, theta);
NormalizeProjectionVectors();
} else {
double s = 0.3*(PI/180); // degrees per pixel
projRight = orig.projRight.RotatedAbout(orig.projDown, -s*dx);
projDown = orig.projDown.RotatedAbout(orig.projRight, s*dy);
projRight = orig.projRight.RotatedAbout(orig.projUp, -s*dx);
projUp = orig.projUp.RotatedAbout(orig.projRight, s*dy);
NormalizeProjectionVectors();
}
orig.projRight = projRight;
orig.projDown = projDown;
orig.projUp = projUp;
orig.offset = offset;
orig.mouse.x = x;
orig.mouse.y = y;
@ -142,6 +195,7 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp, Selection *dest) {
dest->point.v = 0;
dest->entity.v = 0;
// Do the points
for(i = 0; i < SS.entity.elems; i++) {
d = SS.entity.elem[i].t.GetDistance(mp);
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++) {
d = SS.point.elem[i].t.GetDistance(mp);
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) {
orig.offset = offset;
orig.projDown = projDown;
orig.projUp = projUp;
orig.projRight = projRight;
orig.mouse.x = x;
orig.mouse.y = y;
@ -193,22 +278,22 @@ done:
void GraphicsWindow::MouseScroll(double x, double y, int delta) {
double offsetRight = offset.Dot(projRight);
double offsetDown = offset.Dot(projDown);
double offsetUp = offset.Dot(projUp);
double righti = x/scale - offsetRight;
double downi = y/scale - offsetDown;
double upi = y/scale - offsetUp;
if(delta > 0) {
scale *= 1.3;
scale *= 1.2;
} else {
scale /= 1.3;
scale /= 1.2;
}
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(projDown.ScaledBy(downf - downi));
offset = offset.Plus(projUp.ScaledBy(upf - upi));
InvalidateGraphics();
}
@ -245,10 +330,10 @@ void GraphicsWindow::Paint(int w, int h) {
glScaled(scale*2.0/w, scale*2.0/h, 0);
double tx = projRight.Dot(offset);
double ty = projDown.Dot(offset);
double ty = projUp.Dot(offset);
double mat[16];
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, 1);
glMultMatrixd(mat);

View File

@ -126,7 +126,7 @@ void Point::Draw(void) {
double s = 4;
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);
glxVertex3v(v.Plus (r).Plus (d));

View File

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

30
ui.h
View File

@ -69,17 +69,27 @@ public:
class GraphicsWindow {
public:
void Init(void);
// 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 {
int level; // 0 == on menu bar, 1 == one level down
char *label; // or NULL for a separator
int id; // unique ID
int accel; // keyboard accelerator
MenuHandler *fn;
} MenuEntry;
static const MenuEntry menu[];
void Init(void);
static void MenuView(MenuId id);
static void MenuEdit(MenuId id);
// The width and height (in pixels) of the window.
double width, height;
@ -88,12 +98,12 @@ public:
// projection.
Vector offset;
Vector projRight;
Vector projDown;
Vector projUp;
double scale;
struct {
Vector offset;
Vector projRight;
Vector projDown;
Vector projUp;
Point2d mouse;
} orig;
@ -116,6 +126,16 @@ public:
static const int MAX_SELECTED = 32;
Selection selection[MAX_SELECTED];
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.
bool show2dCsyss;

View File

@ -42,6 +42,17 @@ void dbp(char *str, ...)
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)
{
RECT rect;
@ -241,6 +252,37 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
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)
{
PIXELFORMATDESCRIPTOR pfd;
@ -347,6 +389,16 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
SS.GW.MouseScroll(LastMousePos.x, LastMousePos.y, delta);
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_DESTROY:
@ -485,6 +537,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
MSG msg;
DWORD ret;
while(ret = GetMessage(&msg, NULL, 0, 0)) {
if(msg.message == WM_KEYDOWN) {
if(ProcessKeyDown(msg.wParam)) continue;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}