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>
|
2018-10-17 12:01:10 +00:00
|
|
|
#include <string>
|
|
|
|
|
|
|
|
#include <boost/optional.hpp>
|
2018-10-04 09:12:55 +00:00
|
|
|
|
2018-10-18 13:13:38 +00:00
|
|
|
#include <wx/event.h>
|
2018-10-04 09:12:55 +00:00
|
|
|
#include <wx/filedlg.h>
|
2018-10-17 12:01:10 +00:00
|
|
|
#include <wx/gdicmn.h>
|
2018-10-19 13:12:38 +00:00
|
|
|
#include <wx/panel.h>
|
2018-11-28 18:26:11 +00:00
|
|
|
#include <wx/debug.h>
|
2018-10-04 09:12:55 +00:00
|
|
|
|
|
|
|
class wxCheckBox;
|
2018-10-17 12:01:10 +00:00
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
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); }
|
|
|
|
explicit operator bool() const noexcept { 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:
|
2018-10-19 13:12:38 +00:00
|
|
|
struct ExtraPanel : public wxPanel
|
|
|
|
{
|
|
|
|
wxCheckBox *cbox;
|
2018-10-19 11:38:35 +00:00
|
|
|
|
2018-10-19 13:12:38 +00:00
|
|
|
ExtraPanel(wxWindow *parent);
|
|
|
|
static wxWindow* ctor(wxWindow *parent);
|
|
|
|
};
|
|
|
|
|
|
|
|
wxString checkbox_label;
|
2018-10-04 09:12:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-10-17 12:01:10 +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);
|
|
|
|
std::string serialize();
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-10-04 09:12:55 +00:00
|
|
|
}}
|
|
|
|
|
|
|
|
#endif
|