PrusaSlicer-NonPlainar/src/slic3r/GUI/GUI_Utils.hpp

245 lines
6.4 KiB
C++
Raw Normal View History

2018-10-04 09:12:55 +00:00
#ifndef slic3r_GUI_Utils_hpp_
#define slic3r_GUI_Utils_hpp_
2018-11-28 18:26:11 +00:00
#include <memory>
#include <string>
2019-01-11 17:09:21 +00:00
#include <ostream>
2019-02-07 14:55:47 +00:00
#include <functional>
#include <boost/optional.hpp>
2018-10-04 09:12:55 +00:00
#include <wx/frame.h>
#include <wx/dialog.h>
2018-10-18 13:13:38 +00:00
#include <wx/event.h>
2018-10-04 09:12:55 +00:00
#include <wx/filedlg.h>
#include <wx/gdicmn.h>
#include <wx/panel.h>
#include <wx/dcclient.h>
2018-11-28 18:26:11 +00:00
#include <wx/debug.h>
2018-10-04 09:12:55 +00:00
class wxCheckBox;
class wxTopLevelWindow;
class wxRect;
2018-10-04 09:12:55 +00:00
namespace Slic3r {
namespace GUI {
2018-10-18 13:13:38 +00:00
wxTopLevelWindow* find_toplevel_parent(wxWindow *window);
2019-02-07 14:55:47 +00:00
void on_window_geometry(wxTopLevelWindow *tlw, std::function<void()> callback);
enum { DPI_DEFAULT = 96 };
int get_dpi_for_window(wxWindow *window);
struct DpiChangedEvent : public wxEvent {
int dpi;
wxRect rect;
DpiChangedEvent(wxEventType eventType, int dpi, wxRect rect)
: wxEvent(0, eventType), dpi(dpi), rect(rect)
{}
virtual wxEvent *Clone() const
{
return new DpiChangedEvent(*this);
}
};
wxDECLARE_EVENT(EVT_DPI_CHANGED, DpiChangedEvent);
template<class P> class DPIAware : public P
{
public:
DPIAware(wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &pos=wxDefaultPosition,
const wxSize &size=wxDefaultSize, long style=wxDEFAULT_FRAME_STYLE, const wxString &name=wxFrameNameStr)
: P(parent, id, title, pos, size, style, name)
{
m_scale_factor = (float)get_dpi_for_window(this) / (float)DPI_DEFAULT;
2019-04-10 07:56:32 +00:00
// ->-
m_prev_scale_factor = -1;
// -<-
recalc_font();
this->Bind(EVT_DPI_CHANGED, [this](const DpiChangedEvent &evt) {
2019-04-10 07:56:32 +00:00
// ->-
m_prev_scale_factor = m_scale_factor;
// -<-
m_scale_factor = (float)evt.dpi / (float)DPI_DEFAULT;
on_dpi_changed(evt.rect);
});
}
virtual ~DPIAware() {}
float scale_factor() const { return m_scale_factor; }
2019-04-10 07:56:32 +00:00
float prev_scale_factor() const { return m_prev_scale_factor; }
int em_unit() const { return m_em_unit; }
int font_size() const { return m_font_size; }
2019-04-10 07:56:32 +00:00
protected:
virtual void on_dpi_changed(const wxRect &suggested_rect) = 0;
2019-04-10 07:56:32 +00:00
// ->-
// virtual void scale(wxWindow *window, const float& scale) = 0;
// -<-
private:
2019-04-10 07:56:32 +00:00
float m_scale_factor;
float m_prev_scale_factor;
int m_em_unit;
int m_font_size;
void recalc_font()
{
wxClientDC dc(this);
const auto metrics = dc.GetFontMetrics();
m_font_size = metrics.height;
m_em_unit = metrics.averageWidth;
}
};
typedef DPIAware<wxFrame> DPIFrame;
typedef DPIAware<wxDialog> DPIDialog;
2018-10-18 13:13:38 +00:00
class EventGuard
{
2018-11-28 18:26:11 +00:00
// This is a RAII-style smart-ptr-like guard that will bind any event to any event handler
// and unbind it as soon as it goes out of scope or unbind() is called.
// This can be used to solve the annoying problem of wx events being delivered to freed objects.
2018-10-18 13:13:38 +00:00
2018-11-28 18:26:11 +00:00
private:
// This is a way to type-erase both the event type as well as the handler:
struct EventStorageBase {
virtual ~EventStorageBase() {}
};
template<class EvTag, class Fun>
struct EventStorageFun : EventStorageBase {
wxEvtHandler *emitter;
EvTag tag;
Fun fun;
EventStorageFun(wxEvtHandler *emitter, const EvTag &tag, Fun fun)
: emitter(emitter)
, tag(tag)
, fun(std::move(fun))
{
emitter->Bind(this->tag, this->fun);
2018-10-18 13:13:38 +00:00
}
2018-11-28 18:26:11 +00:00
virtual ~EventStorageFun() { emitter->Unbind(tag, fun); }
};
template<typename EvTag, typename Class, typename EvArg, typename EvHandler>
struct EventStorageMethod : EventStorageBase {
typedef void(Class::* MethodPtr)(EvArg &);
wxEvtHandler *emitter;
EvTag tag;
MethodPtr method;
EvHandler *handler;
EventStorageMethod(wxEvtHandler *emitter, const EvTag &tag, MethodPtr method, EvHandler *handler)
: emitter(emitter)
, tag(tag)
, method(method)
, handler(handler)
{
emitter->Bind(tag, method, handler);
}
2018-10-18 13:13:38 +00:00
2018-11-28 18:26:11 +00:00
virtual ~EventStorageMethod() { emitter->Unbind(tag, method, handler); }
};
2018-10-18 13:13:38 +00:00
2018-11-28 18:26:11 +00:00
std::unique_ptr<EventStorageBase> event_storage;
public:
EventGuard() {}
EventGuard(const EventGuard&) = delete;
EventGuard(EventGuard &&other) : event_storage(std::move(other.event_storage)) {}
template<class EvTag, class Fun>
EventGuard(wxEvtHandler *emitter, const EvTag &tag, Fun fun)
:event_storage(new EventStorageFun<EvTag, Fun>(emitter, tag, std::move(fun)))
{}
template<typename EvTag, typename Class, typename EvArg, typename EvHandler>
EventGuard(wxEvtHandler *emitter, const EvTag &tag, void(Class::* method)(EvArg &), EvHandler *handler)
:event_storage(new EventStorageMethod<EvTag, Class, EvArg, EvHandler>(emitter, tag, method, handler))
{}
2018-10-18 13:13:38 +00:00
EventGuard& operator=(const EventGuard&) = delete;
EventGuard& operator=(EventGuard &&other)
{
2018-11-28 18:26:11 +00:00
event_storage = std::move(other.event_storage);
2018-10-18 13:13:38 +00:00
return *this;
}
2018-11-28 18:26:11 +00:00
void unbind() { event_storage.reset(nullptr); }
2019-03-27 11:14:34 +00:00
explicit operator bool() const { return !!event_storage; }
2018-10-18 13:13:38 +00:00
};
2018-10-04 09:12:55 +00:00
class CheckboxFileDialog : public wxFileDialog
{
public:
CheckboxFileDialog(wxWindow *parent,
const wxString &checkbox_label,
bool checkbox_value,
const wxString &message = wxFileSelectorPromptStr,
const wxString &default_dir = wxEmptyString,
const wxString &default_file = wxEmptyString,
const wxString &wildcard = wxFileSelectorDefaultWildcardStr,
long style = wxFD_DEFAULT_STYLE,
const wxPoint &pos = wxDefaultPosition,
const wxSize &size = wxDefaultSize,
const wxString &name = wxFileDialogNameStr
);
bool get_checkbox_value() const;
private:
struct ExtraPanel : public wxPanel
{
wxCheckBox *cbox;
2018-10-19 11:38:35 +00:00
ExtraPanel(wxWindow *parent);
static wxWindow* ctor(wxWindow *parent);
};
wxString checkbox_label;
2018-10-04 09:12:55 +00:00
};
class WindowMetrics
{
private:
wxRect rect;
bool maximized;
WindowMetrics() : maximized(false) {}
public:
static WindowMetrics from_window(wxTopLevelWindow *window);
static boost::optional<WindowMetrics> deserialize(const std::string &str);
wxRect get_rect() const { return rect; }
bool get_maximized() const { return maximized; }
void sanitize_for_display(const wxRect &screen_rect);
2019-01-11 17:09:21 +00:00
std::string serialize() const;
};
2019-01-11 17:09:21 +00:00
std::ostream& operator<<(std::ostream &os, const WindowMetrics& metrics);
2018-10-04 09:12:55 +00:00
}}
#endif