solvespace/src/platform/gui.h
whitequark f324477dd0 Implement a platform abstraction for windows.
This commit removes a large amount of code partially duplicated
between the text and the graphics windows, and opens the path to
having more than one model window on screen at any given time,
as well as simplifies platform work.

This commit also adds complete support for High-DPI device pixel
ratio. It adds support for font scale factor (a fractional factor
on top of integral device pixel ratio) on the platform side, but not
on the application side.

This commit also adds error checking to all Windows API calls
(within the abstracted code) and fixes a significant number of
misuses and non-future-proof uses of Windows API.

This commit also makes uses of Windows API idiomatic, e.g. using
the built-in vertical scroll bar, native tooltips, control
subclassing instead of hooks in the global dispatch loop, and so on.

It reinstates tooltip support and removes menu-related hacks.
2018-07-17 13:31:17 +00:00

230 lines
6.0 KiB
C++

//-----------------------------------------------------------------------------
// An abstraction for platform-dependent GUI functionality.
//
// Copyright 2018 whitequark
//-----------------------------------------------------------------------------
#ifndef SOLVESPACE_GUI_H
#define SOLVESPACE_GUI_H
namespace Platform {
//-----------------------------------------------------------------------------
// Events
//-----------------------------------------------------------------------------
// A mouse input event.
class MouseEvent {
public:
enum class Type {
MOTION,
PRESS,
DBL_PRESS,
RELEASE,
SCROLL_VERT,
LEAVE,
};
enum class Button {
NONE,
LEFT,
MIDDLE,
RIGHT,
};
Type type;
double x;
double y;
bool shiftDown;
bool controlDown;
union {
Button button; // for Type::{MOTION,PRESS,DBL_PRESS,RELEASE}
double scrollDelta; // for Type::SCROLL_VERT
};
};
// A keyboard input event.
struct KeyboardEvent {
enum class Type {
PRESS,
RELEASE,
};
enum class Key {
CHARACTER,
FUNCTION,
};
Type type;
Key key;
union {
char32_t chr; // for Key::CHARACTER
int num; // for Key::FUNCTION
};
bool shiftDown;
bool controlDown;
bool Equals(const KeyboardEvent &other) {
return type == other.type && key == other.key && num == other.num &&
shiftDown == other.shiftDown && controlDown == other.controlDown;
}
};
std::string AcceleratorDescription(const KeyboardEvent &accel);
//-----------------------------------------------------------------------------
// 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();
// A native menu item.
class MenuItem {
public:
enum class Indicator {
NONE,
CHECK_MARK,
RADIO_MARK,
};
std::function<void()> onTrigger;
virtual ~MenuItem() {}
virtual void SetAccelerator(KeyboardEvent accel) = 0;
virtual void SetIndicator(Indicator type) = 0;
virtual void SetEnabled(bool enabled) = 0;
virtual void SetActive(bool active) = 0;
};
typedef std::shared_ptr<MenuItem> MenuItemRef;
// A native menu.
class Menu {
public:
virtual ~Menu() {}
virtual std::shared_ptr<MenuItem> AddItem(
const std::string &label, std::function<void()> onTrigger = std::function<void()>()) = 0;
virtual std::shared_ptr<Menu> AddSubMenu(const std::string &label) = 0;
virtual void AddSeparator() = 0;
virtual void PopUp() = 0;
virtual void Clear() = 0;
};
typedef std::shared_ptr<Menu> MenuRef;
// A native menu bar.
class MenuBar {
public:
virtual ~MenuBar() {}
virtual std::shared_ptr<Menu> AddSubMenu(const std::string &label) = 0;
virtual void Clear() = 0;
};
typedef std::shared_ptr<MenuBar> MenuBarRef;
MenuRef CreateMenu();
MenuBarRef GetOrCreateMainMenu(bool *unique);
// A native top-level window, with an OpenGL context, and an editor overlay.
class Window {
public:
enum class Kind {
TOPLEVEL,
TOOL,
};
enum class Cursor {
POINTER,
HAND
};
std::function<void()> onClose;
std::function<void(bool)> onFullScreen;
std::function<bool(MouseEvent)> onMouseEvent;
std::function<bool(KeyboardEvent)> onKeyboardEvent;
std::function<void(std::string)> onEditingDone;
std::function<void(double)> onScrollbarAdjusted;
std::function<void()> onRender;
virtual ~Window() {}
// Returns physical display DPI.
virtual double GetPixelDensity() = 0;
// Returns raster graphics and coordinate scale (already applied on the platform side),
// i.e. size of logical pixel in physical pixels, or device pixel ratio.
virtual int GetDevicePixelRatio() = 0;
// Returns (fractional) font scale, to be applied on top of (integral) device pixel ratio.
virtual double GetDeviceFontScale() {
return GetPixelDensity() / GetDevicePixelRatio() / 96.0;
}
virtual bool IsVisible() = 0;
virtual void SetVisible(bool visible) = 0;
virtual void Focus() = 0;
virtual bool IsFullScreen() = 0;
virtual void SetFullScreen(bool fullScreen) = 0;
virtual void SetTitle(const std::string &title) = 0;
virtual bool SetTitleForFilename(const Path &filename) { return false; }
virtual void SetMenuBar(MenuBarRef menuBar) = 0;
virtual void GetContentSize(double *width, double *height) = 0;
virtual void SetMinContentSize(double width, double height) = 0;
virtual void FreezePosition(const std::string &key) = 0;
virtual void ThawPosition(const std::string &key) = 0;
virtual void SetCursor(Cursor cursor) = 0;
virtual void SetTooltip(const std::string &text) = 0;
virtual bool IsEditorVisible() = 0;
virtual void ShowEditor(double x, double y, double fontHeight, double minWidth,
bool isMonospace, const std::string &text) = 0;
virtual void HideEditor() = 0;
virtual void SetScrollbarVisible(bool visible) = 0;
virtual void ConfigureScrollbar(double min, double max, double pageSize) = 0;
virtual double GetScrollbarPosition() = 0;
virtual void SetScrollbarPosition(double pos) = 0;
virtual void Invalidate() = 0;
virtual void Redraw() = 0;
virtual void *NativePtr() = 0;
};
typedef std::shared_ptr<Window> WindowRef;
WindowRef CreateWindow(Window::Kind kind = Window::Kind::TOPLEVEL,
WindowRef parentWindow = NULL);
//-----------------------------------------------------------------------------
// Application-wide APIs
//-----------------------------------------------------------------------------
void Exit();
}
#endif