Implement a platform abstraction for timers.
This commit temporarily disables tooltip functionality; it will be handled natively in a platform abstraction for windows using much simpler code.
This commit is contained in:
parent
28f94dcd0a
commit
7ab87caa88
@ -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
|
||||
|
@ -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"));
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
32
src/platform/gui.h
Normal file
32
src/platform/gui.h
Normal file
@ -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<void()> onTimeout;
|
||||
|
||||
virtual ~Timer() {}
|
||||
|
||||
virtual void WindUp(unsigned milliseconds) = 0;
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<Timer> TimerRef;
|
||||
|
||||
TimerRef CreateTimer();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
40
src/platform/guigtk.cpp
Normal file
40
src/platform/guigtk.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// The GTK-based implementation of platform-dependent GUI functionality.
|
||||
//
|
||||
// Copyright 2018 whitequark
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <glibmm/main.h>
|
||||
#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<TimerImplGtk>(new TimerImplGtk);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
74
src/platform/guimac.mm
Normal file
74
src/platform/guimac.mm
Normal file
@ -0,0 +1,74 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// The Cocoa-based implementation of platform-dependent GUI functionality.
|
||||
//
|
||||
// Copyright 2018 whitequark
|
||||
//-----------------------------------------------------------------------------
|
||||
#import <AppKit/AppKit.h>
|
||||
#include "solvespace.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Objective-C bridging
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@interface SSFunction : NSObject
|
||||
- (SSFunction *)initWithFunction:(std::function<void ()> *)aFunc;
|
||||
- (void)run;
|
||||
@end
|
||||
|
||||
@implementation SSFunction
|
||||
{
|
||||
std::function<void ()> *func;
|
||||
}
|
||||
|
||||
- (SSFunction *)initWithFunction:(std::function<void ()> *)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<TimerImplCocoa>(new TimerImplCocoa);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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<Timer>(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
|
||||
//-----------------------------------------------------------------------------
|
80
src/platform/guiwin.cpp
Normal file
80
src/platform/guiwin.cpp
Normal file
@ -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 <windows.h>
|
||||
|
||||
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<TimerImplWin32>(new TimerImplWin32);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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<ViewportCanvas> CreateRenderer();
|
||||
|
||||
#endif
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
9
src/ui.h
9
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<Pixmap> 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;
|
||||
|
Loading…
Reference in New Issue
Block a user