From 0f228fc0fb8f3808afe4d0cd2d7168d012ce553f Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Fri, 2 Jan 2009 02:38:36 -0800 Subject: [PATCH] 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] --- Makefile | 6 + draw.cpp | 24 ++++ graphicswin.cpp | 9 ++ icons/perpendicular.png | Bin 26372 -> 26400 bytes png2c.pl | 35 ++++++ solvespace.cpp | 4 + solvespace.h | 5 + toolbar.cpp | 263 ++++++++++++++++++++++++++++++++++++++++ ui.h | 12 ++ win32/w32main.cpp | 41 +++++++ 10 files changed, 399 insertions(+) create mode 100644 png2c.pl create mode 100644 toolbar.cpp diff --git a/Makefile b/Makefile index 2fc80ff5..b50d96d2 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ SSOBJS = $(OBJDIR)\solvespace.obj \ $(OBJDIR)\expr.obj \ $(OBJDIR)\constraint.obj \ $(OBJDIR)\draw.obj \ + $(OBJDIR)\toolbar.obj \ $(OBJDIR)\drawconstraint.obj \ $(OBJDIR)\file.obj \ $(OBJDIR)\undoredo.obj \ @@ -67,3 +68,8 @@ $(RES): win32/$(@B).rc icon.ico rc win32/$(@B).rc mv win32/$(@B).res $(OBJDIR)/$(@B).res +toolbar.cpp: $(OBJDIR)/icons.h + +$(OBJDIR)/icons.h: icons/* png2c.pl + perl png2c.pl > $(OBJDIR)/icons.h + diff --git a/draw.cpp b/draw.cpp index 1f59ff6a..cdfc13df 100644 --- a/draw.cpp +++ b/draw.cpp @@ -25,6 +25,13 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, shiftDown = !shiftDown; } + if(SS.showToolbar) { + if(ToolbarMouseMoved((int)x, (int)y)) { + hover.Clear(); + return; + } + } + Point2d mp = { x, y }; // 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; HideTextEditControl(); + if(SS.showToolbar) { + if(ToolbarMouseDown((int)mx, (int)my)) return; + } + // Make sure the hover is up to date. MouseMoved(mx, my, false, false, false, false, false); orig.mouse.x = mx; @@ -682,6 +693,14 @@ void GraphicsWindow::MouseScroll(double x, double y, int delta) { 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) { if(entity.v != b->entity.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++) { selection[i].Draw(); } + + // And finally the toolbar. + if(SS.showToolbar) { + ToolbarDraw(); + } } diff --git a/graphicswin.cpp b/graphicswin.cpp index 49db02cc..1da1df6b 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -43,6 +43,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { { 1, "Nearest &Iso View\tF2", MNU_NEAREST_ISO, F(2), mView }, { 1, NULL, 0, NULL }, { 1, "Show Text &Window\tTab", MNU_SHOW_TEXT_WND, '\t', mView }, +{ 1, "Show &Toolbar", MNU_SHOW_TOOLBAR, 0, mView }, { 1, NULL, 0, NULL }, { 1, "Dimensions in &Inches", MNU_UNITS_INCHES, 0, mView }, { 1, "Dimensions in &Millimeters", MNU_UNITS_MM, 0, mView }, @@ -395,6 +396,12 @@ void GraphicsWindow::MenuView(int id) { SS.GW.EnsureValidActives(); break; + case MNU_SHOW_TOOLBAR: + SS.showToolbar = !SS.showToolbar; + SS.GW.EnsureValidActives(); + PaintGraphics(); + break; + case MNU_UNITS_MM: SS.viewUnits = SolveSpace::UNIT_MM; SS.later.showTW = true; @@ -475,6 +482,8 @@ void GraphicsWindow::EnsureValidActives(void) { ShowTextWindow(SS.GW.showTextWindow); CheckMenuById(MNU_SHOW_TEXT_WND, SS.GW.showTextWindow); + CheckMenuById(MNU_SHOW_TOOLBAR, SS.showToolbar); + if(change) SS.later.showTW = true; } diff --git a/icons/perpendicular.png b/icons/perpendicular.png index 8782fd539979a6dc25bf4dea5b1dbe2fbacca7e5..b93d8b399f147edfe150d449d01f454ed4724f63 100644 GIT binary patch delta 7550 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 diff --git a/png2c.pl b/png2c.pl new file mode 100644 index 00000000..fa3a3a10 --- /dev/null +++ b/png2c.pl @@ -0,0 +1,35 @@ +#!/usr/bin/perl + +use GD; + +for $file () { + + $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"; + +} diff --git a/solvespace.cpp b/solvespace.cpp index 52b73be9..656a1264 100644 --- a/solvespace.cpp +++ b/solvespace.cpp @@ -53,6 +53,8 @@ void SolveSpace::Init(char *cmdLine) { exportOffset = CnfThawFloat(0.0f, "ExportOffset"); // Draw back faces of triangles (when mesh is leaky/self-intersecting) drawBackFaces = CnfThawDWORD(1, "DrawBackFaces"); + // Show toolbar in the graphics window + showToolbar = CnfThawDWORD(1, "ShowToolbar"); // Recent files menus for(i = 0; i < MAX_RECENT; i++) { char name[100]; @@ -115,6 +117,8 @@ void SolveSpace::Exit(void) { CnfFreezeFloat(exportOffset, "ExportOffset"); // Draw back faces of triangles (when mesh is leaky/self-intersecting) CnfFreezeDWORD(drawBackFaces, "DrawBackFaces"); + // Show toolbar in the graphics window + CnfFreezeDWORD(showToolbar, "ShowToolbar"); ExitNow(); } diff --git a/solvespace.h b/solvespace.h index 468021c1..28896e98 100644 --- a/solvespace.h +++ b/solvespace.h @@ -99,8 +99,12 @@ void dbp(char *str, ...); void SetWindowTitle(char *str); void Message(char *str, ...); void Error(char *str, ...); +void SetTimerFor(int milliseconds); void ExitNow(void); +void DrawWithBitmapFont(char *str); +void GetBitmapFontExtent(char *str, int *w, int *h); + void CnfFreezeString(char *str, char *name); void CnfFreezeDWORD(DWORD v, char *name); void CnfFreezeFloat(float v, char *name); @@ -372,6 +376,7 @@ public: float exportScale; float exportOffset; int drawBackFaces; + int showToolbar; int CircleSides(double r); typedef enum { diff --git a/toolbar.cpp b/toolbar.cpp new file mode 100644 index 00000000..1ff8edbe --- /dev/null +++ b/toolbar.cpp @@ -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(); +} + diff --git a/ui.h b/ui.h index 157b94f9..c2f4cd24 100644 --- a/ui.h +++ b/ui.h @@ -187,6 +187,7 @@ public: MNU_NEAREST_ORTHO, MNU_NEAREST_ISO, MNU_SHOW_TEXT_WND, + MNU_SHOW_TOOLBAR, MNU_UNITS_INCHES, MNU_UNITS_MM, // Edit @@ -371,6 +372,16 @@ public: 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. bool showWorkplanes; bool showNormals; @@ -395,6 +406,7 @@ public: void MouseLeftDoubleClick(double x, double y); void MouseMiddleOrRightDown(double x, double y); void MouseScroll(double x, double y, int delta); + void MouseLeave(void); void EditControlDone(char *s); }; diff --git a/win32/w32main.cpp b/win32/w32main.cpp index b997bdd5..02b08520 100644 --- a/win32/w32main.cpp +++ b/win32/w32main.cpp @@ -22,6 +22,9 @@ #define EDIT_WIDTH 220 #define EDIT_HEIGHT 21 +// The list representing glyph with ASCII code zero, for bitmap fonts +#define BITMAP_GLYPH_BASE 1000 + HINSTANCE Instance; HWND TextWnd; @@ -95,6 +98,27 @@ void Message(char *str, ...) 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) { ShellExecute(GraphicsWnd, "open", url, NULL, NULL, SW_SHOWNORMAL); @@ -598,6 +622,10 @@ static void CreateGlContext(void) GraphicsHpgl = wglCreateContext(hdc); 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) @@ -702,6 +730,10 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam, break; } + case WM_MOUSELEAVE: + SS.GW.MouseLeave(); + break; + case WM_MOUSEMOVE: case WM_LBUTTONDOWN: case WM_LBUTTONUP: @@ -711,6 +743,15 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam, int x = LOWORD(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; GetClientRect(GraphicsWnd, &r); x = x - (r.right - r.left)/2;