diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f8f5d74..d9eaa37 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -105,6 +105,7 @@ endif() if(WIN32) set(platform_SOURCES platform/w32main.cpp + platform/guiwin.cpp ${gl_SOURCES}) set(platform_LIBRARIES @@ -116,12 +117,13 @@ elseif(APPLE) set(platform_SOURCES platform/cocoamain.mm + platform/guimac.mm render/rendergl.cpp ${gl_SOURCES}) else() set(platform_SOURCES platform/gtkmain.cpp - render/rendergl.cpp + platform/guigtk.cpp ${gl_SOURCES}) set(platform_LIBRARIES @@ -333,7 +335,7 @@ endif() # solvespace headless library set(headless_SOURCES - platform/headless.cpp + platform/guinone.cpp render/rendercairo.cpp) add_library(solvespace-headless STATIC EXCLUDE_FROM_ALL diff --git a/src/confscreen.cpp b/src/confscreen.cpp index 698aa85..f3aefbf 100644 --- a/src/confscreen.cpp +++ b/src/confscreen.cpp @@ -459,7 +459,7 @@ bool TextWindow::EditControlDoneForConfiguration(const char *s) { if(sscanf(s, "%d", &interval)==1) { if(interval >= 1) { SS.autosaveInterval = interval; - SetAutosaveTimerFor(interval); + SS.ScheduleAutosave(); } else { Error(_("Bad value: autosave interval should be positive")); } diff --git a/src/mouse.cpp b/src/mouse.cpp index d3dd7c9..3121b98 100644 --- a/src/mouse.cpp +++ b/src/mouse.cpp @@ -468,11 +468,13 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, } } -void GraphicsWindow::ClearPending() { +void GraphicsWindow::ClearPending(bool scheduleShowTW) { pending.points.Clear(); pending.requests.Clear(); pending = {}; - SS.ScheduleShowTW(); + if(scheduleShowTW) { + SS.ScheduleShowTW(); + } } bool GraphicsWindow::IsFromPending(hRequest r) { @@ -1536,7 +1538,6 @@ void GraphicsWindow::MouseLeave() { // currently a context menu shown. if(!context.active) { hover.Clear(); - toolbarTooltipped = Command::NONE; toolbarHovered = Command::NONE; PaintGraphics(); } diff --git a/src/platform/cocoamain.mm b/src/platform/cocoamain.mm index 262d504..e67dc86 100644 --- a/src/platform/cocoamain.mm +++ b/src/platform/cocoamain.mm @@ -62,52 +62,6 @@ std::string CnfThawString(const std::string &val, const std::string &key) { } }; -/* Timer */ - -@interface DeferredHandler : NSObject -+ (void) runLater:(id)dummy; -+ (void) runCallback; -+ (void) doAutosave; -@end - -@implementation DeferredHandler -+ (void) runLater:(id)dummy { - SolveSpace::SS.DoLater(); -} -+ (void) runCallback { - SolveSpace::SS.GW.TimerCallback(); - SolveSpace::SS.TW.TimerCallback(); -} -+ (void) doAutosave { - SolveSpace::SS.Autosave(); -} -@end - -static void Schedule(SEL selector, double interval) { - NSMethodSignature *signature = [[DeferredHandler class] - methodSignatureForSelector:selector]; - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; - [invocation setSelector:selector]; - [invocation setTarget:[DeferredHandler class]]; - [NSTimer scheduledTimerWithTimeInterval:interval - invocation:invocation repeats:NO]; -} - -void SolveSpace::SetTimerFor(int milliseconds) { - Schedule(@selector(runCallback), milliseconds / 1000.0); -} - -void SolveSpace::SetAutosaveTimerFor(int minutes) { - Schedule(@selector(doAutosave), minutes * 60.0); -} - -void SolveSpace::ScheduleLater() { - [[NSRunLoop currentRunLoop] - performSelector:@selector(runLater:) - target:[DeferredHandler class] argument:nil - order:0 modes:@[NSDefaultRunLoopMode]]; -} - /* OpenGL view */ @interface GLViewWithEditor : NSView diff --git a/src/platform/gtkmain.cpp b/src/platform/gtkmain.cpp index a4dbfbf..91d2f98 100644 --- a/src/platform/gtkmain.cpp +++ b/src/platform/gtkmain.cpp @@ -187,36 +187,6 @@ static void CnfThawWindowPos(Gtk::Window *win, const std::string &key) { win->resize(w, h); } -/* Timers */ - -static bool TimerCallback() { - SS.GW.TimerCallback(); - SS.TW.TimerCallback(); - return false; -} - -void SetTimerFor(int milliseconds) { - Glib::signal_timeout().connect(&TimerCallback, milliseconds); -} - -static bool AutosaveTimerCallback() { - SS.Autosave(); - return false; -} - -void SetAutosaveTimerFor(int minutes) { - Glib::signal_timeout().connect(&AutosaveTimerCallback, minutes * 60 * 1000); -} - -static bool LaterCallback() { - SS.DoLater(); - return false; -} - -void ScheduleLater() { - Glib::signal_timeout().connect(&LaterCallback, 0); -} - /* Editor overlay */ class EditorOverlay : public Gtk::Fixed { diff --git a/src/platform/gui.h b/src/platform/gui.h new file mode 100644 index 0000000..ed93637 --- /dev/null +++ b/src/platform/gui.h @@ -0,0 +1,32 @@ +//----------------------------------------------------------------------------- +// An abstraction for platform-dependent GUI functionality. +// +// Copyright 2018 whitequark +//----------------------------------------------------------------------------- + +#ifndef SOLVESPACE_GUI_H +#define SOLVESPACE_GUI_H + +namespace Platform { + +//----------------------------------------------------------------------------- +// Interfaces +//----------------------------------------------------------------------------- + +// A native single-shot timer. +class Timer { +public: + std::function onTimeout; + + virtual ~Timer() {} + + virtual void WindUp(unsigned milliseconds) = 0; +}; + +typedef std::unique_ptr TimerRef; + +TimerRef CreateTimer(); + +} + +#endif diff --git a/src/platform/guigtk.cpp b/src/platform/guigtk.cpp new file mode 100644 index 0000000..1df7f6d --- /dev/null +++ b/src/platform/guigtk.cpp @@ -0,0 +1,40 @@ +//----------------------------------------------------------------------------- +// The GTK-based implementation of platform-dependent GUI functionality. +// +// Copyright 2018 whitequark +//----------------------------------------------------------------------------- +#include +#include "solvespace.h" + +namespace SolveSpace { +namespace Platform { + +//----------------------------------------------------------------------------- +// Timers +//----------------------------------------------------------------------------- + +class TimerImplGtk : public Timer { +public: + sigc::connection _connection; + + void WindUp(unsigned milliseconds) override { + if(!_connection.empty()) { + _connection.disconnect(); + } + + auto handler = [this]() { + if(this->onTimeout) { + this->onTimeout(); + } + return false; + }; + _connection = Glib::signal_timeout().connect(handler, milliseconds); + } +}; + +TimerRef CreateTimer() { + return std::unique_ptr(new TimerImplGtk); +} + +} +} diff --git a/src/platform/guimac.mm b/src/platform/guimac.mm new file mode 100644 index 0000000..c0ecbd8 --- /dev/null +++ b/src/platform/guimac.mm @@ -0,0 +1,74 @@ +//----------------------------------------------------------------------------- +// The Cocoa-based implementation of platform-dependent GUI functionality. +// +// Copyright 2018 whitequark +//----------------------------------------------------------------------------- +#import +#include "solvespace.h" + +//----------------------------------------------------------------------------- +// Objective-C bridging +//----------------------------------------------------------------------------- + +@interface SSFunction : NSObject +- (SSFunction *)initWithFunction:(std::function *)aFunc; +- (void)run; +@end + +@implementation SSFunction +{ + std::function *func; +} + +- (SSFunction *)initWithFunction:(std::function *)aFunc { + if(self = [super init]) { + func = aFunc; + } + return self; +} + +- (void)run { + if(*func) (*func)(); +} +@end + +namespace SolveSpace { +namespace Platform { + +//----------------------------------------------------------------------------- +// Timers +//----------------------------------------------------------------------------- + +class TimerImplCocoa : public Timer { +public: + NSTimer *timer; + + TimerImplCocoa() : timer(NULL) {} + + void WindUp(unsigned milliseconds) override { + SSFunction *callback = [[SSFunction alloc] init:&this->onTimeout]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: + [callback methodSignatureForSelector:@selector(run)]]; + [invocation setTarget:callback]; + [invocation setSelector:@selector(run)]; + + if(timer != NULL) { + [timer invalidate]; + } + timer = [NSTimer scheduledTimerWithTimeInterval:(milliseconds / 1000.0) + invocation:invocation repeats:NO]; + } + + ~TimerImplCocoa() { + if(timer != NULL) { + [timer invalidate]; + } + } +}; + +TimerRef CreateTimer() { + return std::unique_ptr(new TimerImplCocoa); +} + +} +} diff --git a/src/platform/headless.cpp b/src/platform/guinone.cpp similarity index 97% rename from src/platform/headless.cpp rename to src/platform/guinone.cpp index f37edf5..95e7fa1 100644 --- a/src/platform/headless.cpp +++ b/src/platform/guinone.cpp @@ -8,6 +8,23 @@ namespace SolveSpace { +namespace Platform { + +//----------------------------------------------------------------------------- +// Timers +//----------------------------------------------------------------------------- + +class TimerImplDummy : public Timer { +public: + void WindUp(unsigned milliseconds) override {} +}; + +TimerRef CreateTimer() { + return std::unique_ptr(new TimerImplDummy); +} + +} + //----------------------------------------------------------------------------- // Settings //----------------------------------------------------------------------------- @@ -78,17 +95,6 @@ std::string CnfThawString(const std::string &val, const std::string &key) { return ret; } -//----------------------------------------------------------------------------- -// Timers -//----------------------------------------------------------------------------- - -void SetTimerFor(int milliseconds) { -} -void SetAutosaveTimerFor(int minutes) { -} -void ScheduleLater() { -} - //----------------------------------------------------------------------------- // Rendering //----------------------------------------------------------------------------- diff --git a/src/platform/guiwin.cpp b/src/platform/guiwin.cpp new file mode 100644 index 0000000..f23bfd8 --- /dev/null +++ b/src/platform/guiwin.cpp @@ -0,0 +1,80 @@ +//----------------------------------------------------------------------------- +// The Win32-based implementation of platform-dependent GUI functionality. +// +// Copyright 2018 whitequark +//----------------------------------------------------------------------------- +#include "solvespace.h" +// Include after solvespace.h to avoid identifier clashes. +#include + +namespace SolveSpace { +namespace Platform { + +//----------------------------------------------------------------------------- +// Windows API bridging +//----------------------------------------------------------------------------- + +#define sscheck(expr) do { \ + SetLastError(0); \ + if(!(expr)) \ + CheckLastError(__FILE__, __LINE__, __func__, #expr); \ + } while(0) + +void CheckLastError(const char *file, int line, const char *function, const char *expr) { + if(GetLastError() != S_OK) { + LPWSTR messageW; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, + NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR)&messageW, 0, NULL); + + std::string message; + message += ssprintf("File %s, line %u, function %s:\n", file, line, function); + message += ssprintf("Win32 API call failed: %s.\n", expr); + message += ssprintf("Error: %s", Narrow(messageW).c_str()); + FatalError(message); + } +} + +//----------------------------------------------------------------------------- +// Timers +//----------------------------------------------------------------------------- + +class TimerImplWin32 : public Timer { +public: + static HWND WindowHandle() { + static HWND hTimerWnd; + if(hTimerWnd == NULL) { + sscheck(hTimerWnd = CreateWindowExW(0, L"Message", NULL, 0, 0, 0, 0, 0, + HWND_MESSAGE, NULL, NULL, NULL)); + } + return hTimerWnd; + } + + static void CALLBACK TimerFunc(HWND hwnd, UINT msg, UINT_PTR event, DWORD time) { + sscheck(KillTimer(WindowHandle(), event)); + + TimerImplWin32 *timer = (TimerImplWin32*)event; + if(timer->onTimeout) { + timer->onTimeout(); + } + } + + void WindUp(unsigned milliseconds) override { + // FIXME(platform/gui): use SetCoalescableTimer when it's available (8+) + sscheck(SetTimer(WindowHandle(), (UINT_PTR)this, + milliseconds, &TimerImplWin32::TimerFunc)); + } + + ~TimerImplWin32() { + // FIXME(platform/gui): there's a race condition here--WM_TIMER messages already + // posted to the queue are not removed, so this destructor is at most "best effort". + KillTimer(WindowHandle(), (UINT_PTR)this); + } +}; + +TimerRef CreateTimer() { + return std::unique_ptr(new TimerImplWin32); +} + +} +} diff --git a/src/platform/w32main.cpp b/src/platform/w32main.cpp index c145b67..7478026 100644 --- a/src/platform/w32main.cpp +++ b/src/platform/w32main.cpp @@ -250,33 +250,6 @@ ContextCommand SolveSpace::ShowContextMenu() return (ContextCommand)r; } -void CALLBACK TimerCallback(HWND hwnd, UINT msg, UINT_PTR id, DWORD time) -{ - // The timer is periodic, so needs to be killed explicitly. - KillTimer(GraphicsWnd, 1); - SS.GW.TimerCallback(); - SS.TW.TimerCallback(); -} -void SolveSpace::SetTimerFor(int milliseconds) -{ - SetTimer(GraphicsWnd, 1, milliseconds, TimerCallback); -} - -void SolveSpace::ScheduleLater() -{ -} - -static void CALLBACK AutosaveCallback(HWND hwnd, UINT msg, UINT_PTR id, DWORD time) -{ - KillTimer(GraphicsWnd, 1); - SS.Autosave(); -} - -void SolveSpace::SetAutosaveTimerFor(int minutes) -{ - SetTimer(GraphicsWnd, 2, minutes * 60 * 1000, AutosaveCallback); -} - static void GetWindowSize(HWND hwnd, int *w, int *h) { RECT r; @@ -1561,13 +1534,13 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, while((ret = GetMessage(&msg, NULL, 0, 0)) != 0) { #ifdef HAVE_SPACEWARE // Is it a message from the six degree of freedom input device? - if(ProcessSpaceNavigatorMsg(&msg)) goto done; + if(ProcessSpaceNavigatorMsg(&msg)) continue; #endif // A message from the keyboard, which should be processed as a keyboard // accelerator? if(msg.message == WM_KEYDOWN) { - if(ProcessKeyDown(msg.wParam)) goto done; + if(ProcessKeyDown(msg.wParam)) continue; } if(msg.message == WM_SYSKEYDOWN && msg.hwnd == TextWnd) { // If the user presses the Alt key when the text window has focus, @@ -1578,8 +1551,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, // None of the above; so just a normal message to process. TranslateMessage(&msg); DispatchMessage(&msg); -done: - SS.DoLater(); } #ifdef HAVE_SPACEWARE diff --git a/src/render/render.h b/src/render/render.h index ca838c4..ac07284 100644 --- a/src/render/render.h +++ b/src/render/render.h @@ -8,7 +8,7 @@ #define SOLVESPACE_RENDER_H //----------------------------------------------------------------------------- -// Interfaces and utilities common for all renderers. +// Interfaces common for all renderers //----------------------------------------------------------------------------- enum class StipplePattern : uint32_t; @@ -313,7 +313,7 @@ public: }; //----------------------------------------------------------------------------- -// 2d renderers. +// 2d renderers //----------------------------------------------------------------------------- class CairoRenderer : public SurfaceRenderer { @@ -340,7 +340,7 @@ public: }; //----------------------------------------------------------------------------- -// 3d renderers. +// 3d renderers //----------------------------------------------------------------------------- // An offscreen renderer based on OpenGL framebuffers. @@ -355,6 +355,10 @@ public: void Clear(); }; +//----------------------------------------------------------------------------- +// Factories +//----------------------------------------------------------------------------- + std::shared_ptr CreateRenderer(); #endif diff --git a/src/solvespace.cpp b/src/solvespace.cpp index 1c98d50..f1e32ac 100644 --- a/src/solvespace.cpp +++ b/src/solvespace.cpp @@ -110,11 +110,21 @@ void SolveSpaceUI::Init() { SetLocale(locale); } + timerGenerateAll = Platform::CreateTimer(); + timerGenerateAll->onTimeout = std::bind(&SolveSpaceUI::GenerateAll, &SS, Generate::DIRTY, + /*andFindFree=*/false, /*genForBBox=*/false); + + timerShowTW = Platform::CreateTimer(); + timerShowTW->onTimeout = std::bind(&TextWindow::Show, &TW); + + timerAutosave = Platform::CreateTimer(); + timerAutosave->onTimeout = std::bind(&SolveSpaceUI::Autosave, &SS); + // The default styles (colors, line widths, etc.) are also stored in the // configuration file, but we will automatically load those as we need // them. - SetAutosaveTimerFor(autosaveInterval); + ScheduleAutosave(); NewFile(); AfterNewFile(); @@ -232,21 +242,15 @@ void SolveSpaceUI::Exit() { } void SolveSpaceUI::ScheduleGenerateAll() { - if(!later.scheduled) ScheduleLater(); - later.scheduled = true; - later.generateAll = true; + timerGenerateAll->WindUp(0); } void SolveSpaceUI::ScheduleShowTW() { - if(!later.scheduled) ScheduleLater(); - later.scheduled = true; - later.showTW = true; + timerShowTW->WindUp(0); } -void SolveSpaceUI::DoLater() { - if(later.generateAll) GenerateAll(); - if(later.showTW) TW.Show(); - later = {}; +void SolveSpaceUI::ScheduleAutosave() { + timerAutosave->WindUp(autosaveInterval * 60 * 1000); } double SolveSpaceUI::MmPerUnit() { @@ -389,14 +393,13 @@ bool SolveSpaceUI::GetFilenameAndSave(bool saveAs) { } } -bool SolveSpaceUI::Autosave() +void SolveSpaceUI::Autosave() { - SetAutosaveTimerFor(autosaveInterval); + ScheduleAutosave(); - if(!saveFile.IsEmpty() && unsaved) - return SaveToFile(saveFile.WithExtension(AUTOSAVE_EXT)); - - return false; + if(!saveFile.IsEmpty() && unsaved) { + SaveToFile(saveFile.WithExtension(AUTOSAVE_EXT)); + } } void SolveSpaceUI::RemoveAutosave() diff --git a/src/solvespace.h b/src/solvespace.h index 690b0d5..21d4fc9 100644 --- a/src/solvespace.h +++ b/src/solvespace.h @@ -135,6 +135,7 @@ enum class ContextCommand : uint32_t; // From the platform-specific code. #include "platform/platform.h" +#include "platform/gui.h" const size_t MAX_RECENT = 8; extern Platform::Path RecentFile[MAX_RECENT]; @@ -202,9 +203,6 @@ void dbp(const char *str, ...); void SetCurrentFilename(const Platform::Path &filename); void SetMousePointerToHand(bool yes); void DoMessageBox(const char *str, int rows, int cols, bool error); -void SetTimerFor(int milliseconds); -void SetAutosaveTimerFor(int minutes); -void ScheduleLater(); void ExitNow(); void CnfFreezeInt(uint32_t val, const std::string &name); @@ -736,7 +734,7 @@ public: Style s; } sv; static void MenuFile(Command id); - bool Autosave(); + void Autosave(); void RemoveAutosave(); bool GetFilenameAndSave(bool saveAs); bool OkayToStartNewFile(); @@ -853,14 +851,12 @@ public: // the sketch! bool allConsistent; - struct { - bool scheduled; - bool showTW; - bool generateAll; - } later; + Platform::TimerRef timerShowTW; + Platform::TimerRef timerGenerateAll; + Platform::TimerRef timerAutosave; void ScheduleShowTW(); void ScheduleGenerateAll(); - void DoLater(); + void ScheduleAutosave(); static void MenuHelp(Command id); diff --git a/src/textwin.cpp b/src/textwin.cpp index 785b424..8524be3 100644 --- a/src/textwin.cpp +++ b/src/textwin.cpp @@ -463,7 +463,9 @@ done: } void TextWindow::Show() { - if(SS.GW.pending.operation == GraphicsWindow::Pending::NONE) SS.GW.ClearPending(); + if(SS.GW.pending.operation == GraphicsWindow::Pending::NONE) { + SS.GW.ClearPending(/*scheduleShowTW=*/false); + } SS.GW.GroupSelection(); auto const &gs = SS.GW.gs; @@ -519,12 +521,6 @@ void TextWindow::Show() { InvalidateText(); } -void TextWindow::TimerCallback() -{ - tooltippedButton = hoveredButton; - InvalidateText(); -} - void TextWindow::DrawOrHitTestIcons(UiCanvas *uiCanvas, TextWindow::DrawOrHitHow how, double mx, double my) { @@ -550,13 +546,8 @@ void TextWindow::DrawOrHitTestIcons(UiCanvas *uiCanvas, TextWindow::DrawOrHitHow button->Draw(uiCanvas, x, y, (button == hoveredButton)); } else if(mx > x - 2 && mx < x + 26 && my < y + 2 && my > y - 26) { - // The mouse is hovered over this icon, so do the tooltip - // stuff. - if(button != tooltippedButton) { - oldMousePos = Point2d::From(mx, my); - } - if(button != oldHovered || how == CLICK) { - SetTimerFor(1000); + if(button != oldHovered) { + // FIXME(platorm/gui): implement native tooltips here } hoveredButton = button; if(how == CLICK) { @@ -570,33 +561,6 @@ void TextWindow::DrawOrHitTestIcons(UiCanvas *uiCanvas, TextWindow::DrawOrHitHow if(how != PAINT && hoveredButton != oldHovered) { InvalidateText(); } - - if(tooltippedButton && !tooltippedButton->Tooltip().empty()) { - if(how == PAINT) { - std::string tooltip = tooltippedButton->Tooltip(); - - int ox = (int)oldMousePos.x, oy = (int)oldMousePos.y - LINE_HEIGHT; - ox += 3; - oy -= 3; - int tw = (tooltip.length() + 1) * (CHAR_WIDTH_ - 1); - ox = min(ox, (width - 25) - tw); - oy = max(oy, 5); - - uiCanvas->DrawRect(ox, ox+tw, oy, oy+LINE_HEIGHT, - /*fillColor=*/{ 255, 255, 150, 255 }, - /*outlineColor=*/{ 0, 0, 0, 255 }, - /*zIndex=*/1); - uiCanvas->DrawBitmapText(tooltip, ox+5, oy-3+LINE_HEIGHT, { 0, 0, 0, 255 }, - /*zIndex=*/1); - } else { - if(!hoveredButton || (hoveredButton != tooltippedButton)) { - tooltippedButton = NULL; - InvalidateGraphics(); - } - // And if we're hovered, then we've set a timer that will cause - // us to show the tool tip later. - } - } } //---------------------------------------------------------------------------- @@ -1077,7 +1041,6 @@ void TextWindow::MouseEvent(bool leftClick, bool leftDown, double x, double y) { } void TextWindow::MouseLeave() { - tooltippedButton = NULL; hoveredButton = NULL; hoveredRow = 0; hoveredCol = 0; diff --git a/src/toolbar.cpp b/src/toolbar.cpp index 64fef09..5a2dfa4 100644 --- a/src/toolbar.cpp +++ b/src/toolbar.cpp @@ -98,22 +98,11 @@ bool GraphicsWindow::ToolbarMouseMoved(int x, int y) { bool withinToolbar = ToolbarDrawOrHitTest(x, y, NULL, &nh); if(!withinToolbar) nh = Command::NONE; - if(nh != toolbarTooltipped) { - // Don't let the tool tip move around if the mouse moves within the - // same item. - toolbarMouseX = x; - toolbarMouseY = y; - toolbarTooltipped = Command::NONE; - } - if(nh != toolbarHovered) { toolbarHovered = nh; - SetTimerFor(1000); + // FIXME(platorm/gui): implement native tooltips here 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; } @@ -138,7 +127,6 @@ bool GraphicsWindow::ToolbarMouseDown(int x, int y) { bool GraphicsWindow::ToolbarDrawOrHitTest(int mx, int my, UiCanvas *canvas, Command *menuHit) { - int i; int x = 17, y = (int)(height - 52); int fudge = 8; @@ -159,9 +147,6 @@ bool GraphicsWindow::ToolbarDrawOrHitTest(int mx, int my, /*outlineColor=*/{}); } - bool showTooltip = false; - std::string tooltip; - bool leftpos = true; for(ToolIcon &icon : Toolbar) { if(icon.name == "") { // spacer @@ -201,14 +186,6 @@ bool GraphicsWindow::ToolbarDrawOrHitTest(int mx, int my, /*fillColor=*/{ 255, 255, 0, 75 }, /*outlineColor=*/{}); } - - if(toolbarTooltipped == icon.command) { - // 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. - showTooltip = true; - tooltip = Translate(icon.tooltip); - } } else { int boxhw = 16; if(mx < (x+boxhw) && mx > (x - boxhw) && @@ -228,35 +205,5 @@ bool GraphicsWindow::ToolbarDrawOrHitTest(int mx, int my, } } - if(canvas) { - // Do this last so that nothing can draw over it. - if(showTooltip) { - for(i = 0; SS.GW.menu[i].level >= 0; i++) { - if(toolbarTooltipped == SS.GW.menu[i].id) { - std::string accel = MakeAcceleratorLabel(SS.GW.menu[i].accel); - if(!accel.empty()) { - tooltip += ssprintf(" (%s)", accel.c_str()); - } - break; - } - } - - int tw = (int)canvas->canvas->GetBitmapFont()->GetWidth(tooltip) * 8 + 10, - th = SS.TW.LINE_HEIGHT + 2; - - int ox = toolbarMouseX + 3, oy = toolbarMouseY + 3; - canvas->DrawRect(ox, ox+tw, oy, oy+th, - /*fillColor=*/{ 255, 255, 150, 255 }, - /*outlineColor=*/{ 0, 0, 0, 255 }); - canvas->DrawBitmapText(tooltip, ox+5, oy+4, { 0, 0, 0, 255 }); - } - } - return withinToolbar; } - -void GraphicsWindow::TimerCallback() { - SS.GW.toolbarTooltipped = SS.GW.toolbarHovered; - PaintGraphics(); -} - diff --git a/src/ui.h b/src/ui.h index 0a86be6..70c6175 100644 --- a/src/ui.h +++ b/src/ui.h @@ -326,9 +326,7 @@ public: }; void DrawOrHitTestIcons(UiCanvas *canvas, DrawOrHitHow how, double mx, double my); - void TimerCallback(); - Point2d oldMousePos; - Button *hoveredButton, *tooltippedButton; + Button *hoveredButton; Vector HsvToRgb(Vector hsv); std::shared_ptr HsvPattern2d(int w, int h); @@ -717,7 +715,7 @@ public: bool hasSuggestion; Constraint::Type suggestion; } pending; - void ClearPending(); + void ClearPending(bool scheduleShowTW = true); bool IsFromPending(hRequest r); void AddToPending(hRequest r); void ReplacePending(hRequest before, hRequest after); @@ -839,10 +837,7 @@ public: void ToolbarDraw(UiCanvas *canvas); bool ToolbarMouseMoved(int x, int y); bool ToolbarMouseDown(int x, int y); - static void TimerCallback(); Command toolbarHovered; - Command toolbarTooltipped; - int toolbarMouseX, toolbarMouseY; // This sets what gets displayed. bool showWorkplanes;