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
parent
6c63d9c8cb
commit
d36c70216a
16
entity.cpp
16
entity.cpp
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
179
graphicswin.cpp
179
graphicswin.cpp
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
30
ui.h
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue