Add a toolbar. This requires a tool to convert my PNG icons to

tables in the code, which I have written in perl and am checking
in.

Also get WM_MOUSELEAVE events from win32, so that I can de-hover
everything when the mouse leaves the graphics window. And fix one
of the icons, which was 23x24 instead of 24x24.

[git-p4: depot-paths = "//depot/solvespace/": change = 1883]
solver
Jonathan Westhues 2009-01-02 02:38:36 -08:00
parent 3ae0ca8c19
commit 0f228fc0fb
10 changed files with 399 additions and 0 deletions

View File

@ -25,6 +25,7 @@ SSOBJS = $(OBJDIR)\solvespace.obj \
$(OBJDIR)\expr.obj \ $(OBJDIR)\expr.obj \
$(OBJDIR)\constraint.obj \ $(OBJDIR)\constraint.obj \
$(OBJDIR)\draw.obj \ $(OBJDIR)\draw.obj \
$(OBJDIR)\toolbar.obj \
$(OBJDIR)\drawconstraint.obj \ $(OBJDIR)\drawconstraint.obj \
$(OBJDIR)\file.obj \ $(OBJDIR)\file.obj \
$(OBJDIR)\undoredo.obj \ $(OBJDIR)\undoredo.obj \
@ -67,3 +68,8 @@ $(RES): win32/$(@B).rc icon.ico
rc win32/$(@B).rc rc win32/$(@B).rc
mv win32/$(@B).res $(OBJDIR)/$(@B).res mv win32/$(@B).res $(OBJDIR)/$(@B).res
toolbar.cpp: $(OBJDIR)/icons.h
$(OBJDIR)/icons.h: icons/* png2c.pl
perl png2c.pl > $(OBJDIR)/icons.h

View File

@ -25,6 +25,13 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
shiftDown = !shiftDown; shiftDown = !shiftDown;
} }
if(SS.showToolbar) {
if(ToolbarMouseMoved((int)x, (int)y)) {
hover.Clear();
return;
}
}
Point2d mp = { x, y }; Point2d mp = { x, y };
// 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
@ -337,6 +344,10 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
if(GraphicsEditControlIsVisible()) return; if(GraphicsEditControlIsVisible()) return;
HideTextEditControl(); HideTextEditControl();
if(SS.showToolbar) {
if(ToolbarMouseDown((int)mx, (int)my)) return;
}
// Make sure the hover is up to date. // Make sure the hover is up to date.
MouseMoved(mx, my, false, false, false, false, false); MouseMoved(mx, my, false, false, false, false, false);
orig.mouse.x = mx; orig.mouse.x = mx;
@ -682,6 +693,14 @@ void GraphicsWindow::MouseScroll(double x, double y, int delta) {
InvalidateGraphics(); InvalidateGraphics();
} }
void GraphicsWindow::MouseLeave(void) {
// Un-hover everything when the mouse leaves our window.
hover.Clear();
toolbarTooltipped = 0;
toolbarHovered = 0;
PaintGraphics();
}
bool GraphicsWindow::Selection::Equals(Selection *b) { bool GraphicsWindow::Selection::Equals(Selection *b) {
if(entity.v != b->entity.v) return false; if(entity.v != b->entity.v) return false;
if(constraint.v != b->constraint.v) return false; if(constraint.v != b->constraint.v) return false;
@ -1006,5 +1025,10 @@ void GraphicsWindow::Paint(int w, int h) {
for(i = 0; i < MAX_SELECTED; i++) { for(i = 0; i < MAX_SELECTED; i++) {
selection[i].Draw(); selection[i].Draw();
} }
// And finally the toolbar.
if(SS.showToolbar) {
ToolbarDraw();
}
} }

View File

@ -43,6 +43,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "Nearest &Iso View\tF2", MNU_NEAREST_ISO, F(2), mView }, { 1, "Nearest &Iso View\tF2", MNU_NEAREST_ISO, F(2), mView },
{ 1, NULL, 0, NULL }, { 1, NULL, 0, NULL },
{ 1, "Show Text &Window\tTab", MNU_SHOW_TEXT_WND, '\t', mView }, { 1, "Show Text &Window\tTab", MNU_SHOW_TEXT_WND, '\t', mView },
{ 1, "Show &Toolbar", MNU_SHOW_TOOLBAR, 0, mView },
{ 1, NULL, 0, NULL }, { 1, NULL, 0, NULL },
{ 1, "Dimensions in &Inches", MNU_UNITS_INCHES, 0, mView }, { 1, "Dimensions in &Inches", MNU_UNITS_INCHES, 0, mView },
{ 1, "Dimensions in &Millimeters", MNU_UNITS_MM, 0, mView }, { 1, "Dimensions in &Millimeters", MNU_UNITS_MM, 0, mView },
@ -395,6 +396,12 @@ void GraphicsWindow::MenuView(int id) {
SS.GW.EnsureValidActives(); SS.GW.EnsureValidActives();
break; break;
case MNU_SHOW_TOOLBAR:
SS.showToolbar = !SS.showToolbar;
SS.GW.EnsureValidActives();
PaintGraphics();
break;
case MNU_UNITS_MM: case MNU_UNITS_MM:
SS.viewUnits = SolveSpace::UNIT_MM; SS.viewUnits = SolveSpace::UNIT_MM;
SS.later.showTW = true; SS.later.showTW = true;
@ -475,6 +482,8 @@ void GraphicsWindow::EnsureValidActives(void) {
ShowTextWindow(SS.GW.showTextWindow); ShowTextWindow(SS.GW.showTextWindow);
CheckMenuById(MNU_SHOW_TEXT_WND, SS.GW.showTextWindow); CheckMenuById(MNU_SHOW_TEXT_WND, SS.GW.showTextWindow);
CheckMenuById(MNU_SHOW_TOOLBAR, SS.showToolbar);
if(change) SS.later.showTW = true; if(change) SS.later.showTW = true;
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

35
png2c.pl Normal file
View File

@ -0,0 +1,35 @@
#!/usr/bin/perl
use GD;
for $file (<icons/*.png>) {
$file =~ m#.*/(.*)\.png#;
$base = "Icon_$1";
$base =~ y/-/_/;
open(PNG, $file) or die "$file: $!\n";
$img = newFromPng GD::Image(\*PNG) or die;
$img->trueColor(1);
close PNG;
($width, $height) = $img->getBounds();
die "$file: $width, $height" if ($width != 24) or ($height != 24);
print "unsigned char $base\[24*24*3] = {\n";
for($y = 0; $y < 24; $y++) {
for($x = 0; $x < 24; $x++) {
$index = $img->getPixel($x, 23-$y);
($r, $g, $b) = $img->rgb($index);
if($r + $g + $b < 11) {
($r, $g, $b) = (30, 30, 30);
}
printf " 0x%02x, 0x%02x, 0x%02x,\n", $r, $g, $b;
}
}
print "};\n\n";
}

View File

@ -53,6 +53,8 @@ void SolveSpace::Init(char *cmdLine) {
exportOffset = CnfThawFloat(0.0f, "ExportOffset"); exportOffset = CnfThawFloat(0.0f, "ExportOffset");
// Draw back faces of triangles (when mesh is leaky/self-intersecting) // Draw back faces of triangles (when mesh is leaky/self-intersecting)
drawBackFaces = CnfThawDWORD(1, "DrawBackFaces"); drawBackFaces = CnfThawDWORD(1, "DrawBackFaces");
// Show toolbar in the graphics window
showToolbar = CnfThawDWORD(1, "ShowToolbar");
// Recent files menus // Recent files menus
for(i = 0; i < MAX_RECENT; i++) { for(i = 0; i < MAX_RECENT; i++) {
char name[100]; char name[100];
@ -115,6 +117,8 @@ void SolveSpace::Exit(void) {
CnfFreezeFloat(exportOffset, "ExportOffset"); CnfFreezeFloat(exportOffset, "ExportOffset");
// Draw back faces of triangles (when mesh is leaky/self-intersecting) // Draw back faces of triangles (when mesh is leaky/self-intersecting)
CnfFreezeDWORD(drawBackFaces, "DrawBackFaces"); CnfFreezeDWORD(drawBackFaces, "DrawBackFaces");
// Show toolbar in the graphics window
CnfFreezeDWORD(showToolbar, "ShowToolbar");
ExitNow(); ExitNow();
} }

View File

@ -99,8 +99,12 @@ void dbp(char *str, ...);
void SetWindowTitle(char *str); void SetWindowTitle(char *str);
void Message(char *str, ...); void Message(char *str, ...);
void Error(char *str, ...); void Error(char *str, ...);
void SetTimerFor(int milliseconds);
void ExitNow(void); void ExitNow(void);
void DrawWithBitmapFont(char *str);
void GetBitmapFontExtent(char *str, int *w, int *h);
void CnfFreezeString(char *str, char *name); void CnfFreezeString(char *str, char *name);
void CnfFreezeDWORD(DWORD v, char *name); void CnfFreezeDWORD(DWORD v, char *name);
void CnfFreezeFloat(float v, char *name); void CnfFreezeFloat(float v, char *name);
@ -372,6 +376,7 @@ public:
float exportScale; float exportScale;
float exportOffset; float exportOffset;
int drawBackFaces; int drawBackFaces;
int showToolbar;
int CircleSides(double r); int CircleSides(double r);
typedef enum { typedef enum {

263
toolbar.cpp Normal file
View File

@ -0,0 +1,263 @@
#include "solvespace.h"
#include "obj/icons.h"
BYTE SPACER[1];
static const struct {
BYTE *image;
int menu;
char *tip;
} Toolbar[] = {
{ Icon_line, GraphicsWindow::MNU_LINE_SEGMENT, "Sketch line segment" },
{ Icon_rectangle, GraphicsWindow::MNU_RECTANGLE, "Sketch rectangle" },
{ Icon_circle, GraphicsWindow::MNU_CIRCLE, "Sketch circle" },
{ Icon_arc, GraphicsWindow::MNU_ARC, "Sketch arc, or tangent arc at selected point" },
{ Icon_bezier, GraphicsWindow::MNU_CUBIC, "Sketch cubic Bezier section" },
{ Icon_point, GraphicsWindow::MNU_DATUM_POINT, "Sketch datum point" },
{ Icon_construction, GraphicsWindow::MNU_CONSTRUCTION, "Toggle construction" },
{ Icon_trim, GraphicsWindow::MNU_CONSTRUCTION, "Split lines / curves where they intersect" },
{ SPACER },
{ Icon_length, GraphicsWindow::MNU_DISTANCE_DIA, "Constrain distance / diameter / length" },
{ Icon_angle, GraphicsWindow::MNU_ANGLE, "Constrain angle" },
{ Icon_horiz, GraphicsWindow::MNU_HORIZONTAL, "Constrain to be horizontal" },
{ Icon_vert, GraphicsWindow::MNU_VERTICAL, "Constrain to be vertical" },
{ Icon_parallel, GraphicsWindow::MNU_PARALLEL, "Constrain to be parallel or tangent" },
{ Icon_perpendicular, GraphicsWindow::MNU_PERPENDICULAR, "Constrain to be perpendicular" },
{ Icon_pointonx, GraphicsWindow::MNU_ON_ENTITY, "Constrain point on line / curve / plane / face" },
{ Icon_symmetric, GraphicsWindow::MNU_SYMMETRIC, "Constrain symmetric" },
{ Icon_ref, GraphicsWindow::MNU_REFERENCE, "Toggle reference dimension" },
{ SPACER },
{ Icon_extrude, GraphicsWindow::MNU_GROUP_EXTRUDE, "New group extruding active sketch" },
{ Icon_sketch_in_plane, GraphicsWindow::MNU_GROUP_WRKPL, "New group in new workplane (thru given entities)" },
{ Icon_sketch_in_3d, GraphicsWindow::MNU_GROUP_3D, "New group in 3d" },
{ Icon_assemble, GraphicsWindow::MNU_GROUP_IMPORT, "New group importing / assembling file" },
{ SPACER },
{ Icon_in3d, GraphicsWindow::MNU_FREE_IN_3D, "Sketch / constrain in 3d" },
{ Icon_ontoworkplane, GraphicsWindow::MNU_SEL_WORKPLANE, "Sketch / constrain in workplane" },
{ NULL },
};
void GraphicsWindow::ToolbarDraw(void) {
ToolbarDrawOrHitTest(0, 0, true, NULL);
}
bool GraphicsWindow::ToolbarMouseMoved(int x, int y) {
x += ((int)width/2);
y += ((int)height/2);
int nh;
bool withinToolbar = ToolbarDrawOrHitTest(x, y, false, &nh);
if(!withinToolbar) nh = 0;
if(nh != toolbarTooltipped) {
// Don't let the tool tip move around if the mouse moves within the
// same item.
toolbarMouseX = x;
toolbarMouseY = y;
toolbarTooltipped = 0;
}
if(nh != toolbarHovered) {
toolbarHovered = nh;
SetTimerFor(1000);
PaintGraphics();
}
// So if we moved off the toolbar, then toolbarHovered is now equal to
// zero, so it doesn't matter if the tool tip timer expires. And if
// we moved from one item to another, we reset the timer, so also okay.
return withinToolbar;
}
bool GraphicsWindow::ToolbarMouseDown(int x, int y) {
x += ((int)width/2);
y += ((int)height/2);
int nh;
bool withinToolbar = ToolbarDrawOrHitTest(x, y, false, &nh);
if(withinToolbar) {
for(int i = 0; SS.GW.menu[i].level >= 0; i++) {
if(nh == SS.GW.menu[i].id) {
(SS.GW.menu[i].fn)((GraphicsWindow::MenuId)SS.GW.menu[i].id);
break;
}
}
}
return withinToolbar;
}
bool GraphicsWindow::ToolbarDrawOrHitTest(int mx, int my,
bool paint, int *menu)
{
int i;
int x = 17, y = (int)(height - 52);
int fudge = 8;
int h = 32*12 + 3*16 + fudge;
int aleft = 0, aright = 66, atop = y+16+fudge/2, abot = y+16-h;
bool withinToolbar =
(mx >= aleft && mx <= aright && my <= atop && my >= abot);
if(!paint && !withinToolbar) {
// This gets called every MouseMove event, so return quickly.
return false;
}
if(paint) {
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glTranslated(-1, -1, 0);
glScaled(2.0/width, 2.0/height, 0);
glDisable(GL_LIGHTING);
double c = 30.0/255;
glColor4d(c, c, c, 1.0);
glBegin(GL_QUADS);
glVertex2d(aleft, atop);
glVertex2d(aleft, abot);
glVertex2d(aright, abot);
glVertex2d(aright, atop);
glEnd();
}
struct {
bool show;
char *str;
} toolTip = { false, NULL };
bool leftpos = true;
for(i = 0; Toolbar[i].image; i++) {
if(Toolbar[i].image == SPACER) {
if(!leftpos) {
leftpos = true;
y -= 32;
x -= 32;
}
y -= 16;
if(paint) {
// Draw a separator bar in a slightly different color.
int divw = 30, divh = 2;
glColor4d(0.17, 0.17, 0.17, 1);
x += 16;
y += 24;
glBegin(GL_QUADS);
glVertex2d(x+divw, y+divh);
glVertex2d(x+divw, y-divh);
glVertex2d(x-divw, y-divh);
glVertex2d(x-divw, y+divh);
glEnd();
x -= 16;
y -= 24;
}
continue;
}
if(paint) {
glRasterPos2i(x - 12, y - 12);
glDrawPixels(24, 24, GL_RGB, GL_UNSIGNED_BYTE, Toolbar[i].image);
if(toolbarHovered == Toolbar[i].menu) {
// Highlight the hovered or pending item.
glColor4d(1, 1, 0, 0.3);
int boxhw = 15;
glBegin(GL_QUADS);
glVertex2d(x+boxhw, y+boxhw);
glVertex2d(x+boxhw, y-boxhw);
glVertex2d(x-boxhw, y-boxhw);
glVertex2d(x-boxhw, y+boxhw);
glEnd();
}
if(toolbarTooltipped == Toolbar[i].menu) {
// Display the tool tip for this item; postpone till later
// so that no one draws over us. Don't need position since
// that's just wherever the mouse is.
toolTip.show = true;
toolTip.str = Toolbar[i].tip;
}
} else {
int boxhw = 16;
if(mx < (x+boxhw) && mx > (x - boxhw) &&
my < (y+boxhw) && my > (y - boxhw))
{
if(menu) *menu = Toolbar[i].menu;
}
}
if(leftpos) {
x += 32;
leftpos = false;
} else {
x -= 32;
y -= 32;
leftpos = true;
}
}
if(paint) {
// Do this last so that nothing can draw over it.
if(toolTip.show) {
char str[1024];
if(strlen(toolTip.str) >= 200) oops();
strcpy(str, toolTip.str);
for(i = 0; SS.GW.menu[i].level >= 0; i++) {
if(toolbarTooltipped == SS.GW.menu[i].id) {
int accel = SS.GW.menu[i].accel;
int ac = accel & 0xff;
if(isalnum(ac) || ac == '[') {
char *s = str+strlen(str);
if(accel & 0x100) {
sprintf(s, " (Shift+%c)", ac);
} else if((accel & ~0xff) == 0) {
sprintf(s, " (%c)", ac);
}
}
break;
}
}
int tw, th;
GetBitmapFontExtent(str, &tw, &th);
tw += 10;
th += 2;
double ox = toolbarMouseX + 3, oy = toolbarMouseY + 3;
glColor4d(1.0, 1.0, 0.6, 1.0);
glBegin(GL_QUADS);
glVertex2d(ox, oy);
glVertex2d(ox+tw, oy);
glVertex2d(ox+tw, oy+th);
glVertex2d(ox, oy+th);
glEnd();
glColor4d(0.0, 0.0, 0.0, 1.0);
glBegin(GL_LINE_LOOP);
glVertex2d(ox, oy);
glVertex2d(ox+tw, oy);
glVertex2d(ox+tw, oy+th);
glVertex2d(ox, oy+th);
glEnd();
glColor4d(0, 0, 0, 1);
glPushMatrix();
glRasterPos2d(ox+6, oy+6);
DrawWithBitmapFont(str);
glPopMatrix();
}
glxDepthRangeLockToFront(false);
}
return withinToolbar;
}
void GraphicsWindow::TimerCallback(void) {
SS.GW.toolbarTooltipped = SS.GW.toolbarHovered;
PaintGraphics();
}

12
ui.h
View File

@ -187,6 +187,7 @@ public:
MNU_NEAREST_ORTHO, MNU_NEAREST_ORTHO,
MNU_NEAREST_ISO, MNU_NEAREST_ISO,
MNU_SHOW_TEXT_WND, MNU_SHOW_TEXT_WND,
MNU_SHOW_TOOLBAR,
MNU_UNITS_INCHES, MNU_UNITS_INCHES,
MNU_UNITS_MM, MNU_UNITS_MM,
// Edit // Edit
@ -371,6 +372,16 @@ public:
void ClearSuper(void); void ClearSuper(void);
// The toolbar, in toolbar.cpp
bool ToolbarDrawOrHitTest(int x, int y, bool paint, int *menu);
void ToolbarDraw(void);
bool ToolbarMouseMoved(int x, int y);
bool ToolbarMouseDown(int x, int y);
static void TimerCallback(void);
int toolbarHovered;
int toolbarTooltipped;
int toolbarMouseX, toolbarMouseY;
// This sets what gets displayed. // This sets what gets displayed.
bool showWorkplanes; bool showWorkplanes;
bool showNormals; bool showNormals;
@ -395,6 +406,7 @@ public:
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 MouseScroll(double x, double y, int delta); void MouseScroll(double x, double y, int delta);
void MouseLeave(void);
void EditControlDone(char *s); void EditControlDone(char *s);
}; };

View File

@ -22,6 +22,9 @@
#define EDIT_WIDTH 220 #define EDIT_WIDTH 220
#define EDIT_HEIGHT 21 #define EDIT_HEIGHT 21
// The list representing glyph with ASCII code zero, for bitmap fonts
#define BITMAP_GLYPH_BASE 1000
HINSTANCE Instance; HINSTANCE Instance;
HWND TextWnd; HWND TextWnd;
@ -95,6 +98,27 @@ void Message(char *str, ...)
va_end(f); va_end(f);
} }
void CALLBACK TimerCallback(HWND hwnd, UINT msg, UINT_PTR id, DWORD time)
{
SS.GW.TimerCallback();
}
void SetTimerFor(int milliseconds)
{
SetTimer(GraphicsWnd, 1, milliseconds, TimerCallback);
}
void DrawWithBitmapFont(char *str)
{
// These lists were created in CreateGlContext
glListBase(BITMAP_GLYPH_BASE);
glCallLists(strlen(str), GL_UNSIGNED_BYTE, str);
}
void GetBitmapFontExtent(char *str, int *w, int *h)
{
// Easy since that's a fixed-width font for now.
*h = TEXT_HEIGHT;
*w = TEXT_WIDTH*strlen(str);
}
void OpenWebsite(char *url) { void OpenWebsite(char *url) {
ShellExecute(GraphicsWnd, "open", url, NULL, NULL, SW_SHOWNORMAL); ShellExecute(GraphicsWnd, "open", url, NULL, NULL, SW_SHOWNORMAL);
@ -598,6 +622,10 @@ static void CreateGlContext(void)
GraphicsHpgl = wglCreateContext(hdc); GraphicsHpgl = wglCreateContext(hdc);
wglMakeCurrent(hdc, GraphicsHpgl); wglMakeCurrent(hdc, GraphicsHpgl);
// Create a bitmap font in a display list, for DrawWithBitmapFont().
SelectObject(hdc, FixedFont);
wglUseFontBitmaps(hdc, 0, 255, BITMAP_GLYPH_BASE);
} }
void InvalidateGraphics(void) void InvalidateGraphics(void)
@ -702,6 +730,10 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
break; break;
} }
case WM_MOUSELEAVE:
SS.GW.MouseLeave();
break;
case WM_MOUSEMOVE: case WM_MOUSEMOVE:
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
case WM_LBUTTONUP: case WM_LBUTTONUP:
@ -711,6 +743,15 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
int x = LOWORD(lParam); int x = LOWORD(lParam);
int y = HIWORD(lParam); int y = HIWORD(lParam);
// We need this in order to get the WM_MOUSELEAVE
TRACKMOUSEEVENT tme;
ZERO(&tme);
tme.cbSize = sizeof(tme);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = GraphicsWnd;
TrackMouseEvent(&tme);
// Convert to xy (vs. ij) style coordinates, with (0, 0) at center
RECT r; RECT r;
GetClientRect(GraphicsWnd, &r); GetClientRect(GraphicsWnd, &r);
x = x - (r.right - r.left)/2; x = x - (r.right - r.left)/2;