mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-16 13:45:52 +08:00
Added some widgets from BambuStudio(http://github.com/bambulab) from the state of 96707fc4b4
Thanks https://github.com/bambu123, https://github.com/lanewei120 and https://github.com/walterwongbbl for implementation.
This commit is contained in:
parent
6e206d8c9e
commit
aff3864200
303
src/slic3r/GUI/Widgets/Button.cpp
Normal file
303
src/slic3r/GUI/Widgets/Button.cpp
Normal file
@ -0,0 +1,303 @@
|
||||
#include "Button.hpp"
|
||||
#include "Label.hpp"
|
||||
|
||||
#include <wx/dcgraph.h>
|
||||
|
||||
BEGIN_EVENT_TABLE(Button, StaticBox)
|
||||
|
||||
EVT_LEFT_DOWN(Button::mouseDown)
|
||||
EVT_LEFT_UP(Button::mouseReleased)
|
||||
EVT_MOUSE_CAPTURE_LOST(Button::mouseCaptureLost)
|
||||
EVT_KEY_DOWN(Button::keyDownUp)
|
||||
EVT_KEY_UP(Button::keyDownUp)
|
||||
|
||||
// catch paint events
|
||||
EVT_PAINT(Button::paintEvent)
|
||||
|
||||
END_EVENT_TABLE()
|
||||
|
||||
/*
|
||||
* Called by the system of by wxWidgets when the panel needs
|
||||
* to be redrawn. You can also trigger this call by
|
||||
* calling Refresh()/Update().
|
||||
*/
|
||||
|
||||
Button::Button()
|
||||
: paddingSize(10, 8)
|
||||
{
|
||||
background_color = StateColor(
|
||||
std::make_pair(0xF0F0F0, (int) StateColor::Disabled),
|
||||
std::make_pair(0x37EE7C, (int) StateColor::Hovered | StateColor::Checked),
|
||||
std::make_pair(0x00AE42, (int) StateColor::Checked),
|
||||
std::make_pair(*wxLIGHT_GREY, (int) StateColor::Hovered),
|
||||
std::make_pair(*wxWHITE, (int) StateColor::Normal));
|
||||
text_color = StateColor(
|
||||
std::make_pair(*wxLIGHT_GREY, (int) StateColor::Disabled),
|
||||
std::make_pair(*wxBLACK, (int) StateColor::Normal));
|
||||
}
|
||||
|
||||
Button::Button(wxWindow* parent, wxString text, wxString icon, long style, int iconSize)
|
||||
: Button()
|
||||
{
|
||||
Create(parent, text, icon, style, iconSize);
|
||||
}
|
||||
|
||||
bool Button::Create(wxWindow* parent, wxString text, wxString icon, long style, int iconSize)
|
||||
{
|
||||
StaticBox::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style);
|
||||
state_handler.attach({&text_color});
|
||||
state_handler.update_binds();
|
||||
//BBS set default font
|
||||
SetFont(Label::Body_14);
|
||||
wxWindow::SetLabel(text);
|
||||
if (!icon.IsEmpty()) {
|
||||
//BBS set button icon default size to 20
|
||||
this->active_icon = ScalableBitmap(this, icon.ToStdString(), iconSize > 0 ? iconSize : 20);
|
||||
}
|
||||
messureSize();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Button::SetLabel(const wxString& label)
|
||||
{
|
||||
wxWindow::SetLabel(label);
|
||||
messureSize();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void Button::SetIcon(const wxString& icon)
|
||||
{
|
||||
if (!icon.IsEmpty()) {
|
||||
//BBS set button icon default size to 20
|
||||
this->active_icon = ScalableBitmap(this, icon.ToStdString(), this->active_icon.px_cnt());
|
||||
}
|
||||
else
|
||||
{
|
||||
this->active_icon = ScalableBitmap();
|
||||
}
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void Button::SetInactiveIcon(const wxString &icon)
|
||||
{
|
||||
if (!icon.IsEmpty()) {
|
||||
// BBS set button icon default size to 20
|
||||
this->inactive_icon = ScalableBitmap(this, icon.ToStdString(), this->active_icon.px_cnt());
|
||||
} else {
|
||||
this->inactive_icon = ScalableBitmap();
|
||||
}
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void Button::SetMinSize(const wxSize& size)
|
||||
{
|
||||
minSize = size;
|
||||
messureSize();
|
||||
}
|
||||
|
||||
void Button::SetPaddingSize(const wxSize& size)
|
||||
{
|
||||
paddingSize = size;
|
||||
messureSize();
|
||||
}
|
||||
|
||||
void Button::SetTextColor(StateColor const& color)
|
||||
{
|
||||
text_color = color;
|
||||
state_handler.update_binds();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void Button::SetTextColorNormal(wxColor const &color)
|
||||
{
|
||||
text_color.setColorForStates(color, 0);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
bool Button::Enable(bool enable)
|
||||
{
|
||||
bool result = wxWindow::Enable(enable);
|
||||
if (result) {
|
||||
wxCommandEvent e(EVT_ENABLE_CHANGED);
|
||||
e.SetEventObject(this);
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Button::SetCanFocus(bool canFocus) { this->canFocus = canFocus; }
|
||||
|
||||
void Button::Rescale()
|
||||
{
|
||||
if (this->active_icon.bmp().IsOk())
|
||||
this->active_icon.msw_rescale();
|
||||
|
||||
if (this->inactive_icon.bmp().IsOk())
|
||||
this->inactive_icon.msw_rescale();
|
||||
|
||||
messureSize();
|
||||
}
|
||||
|
||||
void Button::paintEvent(wxPaintEvent& evt)
|
||||
{
|
||||
// depending on your system you may need to look at double-buffered dcs
|
||||
wxPaintDC dc(this);
|
||||
render(dc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we do the actual rendering. I put it in a separate
|
||||
* method so that it can work no matter what type of DC
|
||||
* (e.g. wxPaintDC or wxClientDC) is used.
|
||||
*/
|
||||
void Button::render(wxDC& dc)
|
||||
{
|
||||
StaticBox::render(dc);
|
||||
int states = state_handler.states();
|
||||
wxSize size = GetSize();
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
// calc content size
|
||||
wxSize szIcon;
|
||||
wxSize szContent = textSize;
|
||||
|
||||
ScalableBitmap icon;
|
||||
if (m_selected || ((states & (int)StateColor::State::Hovered) != 0))
|
||||
icon = active_icon;
|
||||
else
|
||||
icon = inactive_icon;
|
||||
int padding = 5;
|
||||
if (icon.bmp().IsOk()) {
|
||||
if (szContent.y > 0) {
|
||||
//BBS norrow size between text and icon
|
||||
szContent.x += padding;
|
||||
}
|
||||
szIcon = icon.GetBmpSize();
|
||||
szContent.x += szIcon.x;
|
||||
if (szIcon.y > szContent.y)
|
||||
szContent.y = szIcon.y;
|
||||
if (szContent.x > size.x) {
|
||||
int d = std::min(padding, szContent.x - size.x);
|
||||
padding -= d;
|
||||
szContent.x -= d;
|
||||
}
|
||||
}
|
||||
// move to center
|
||||
wxRect rcContent = { {0, 0}, size };
|
||||
wxSize offset = (size - szContent) / 2;
|
||||
if (offset.x < 0) offset.x = 0;
|
||||
rcContent.Deflate(offset.x, offset.y);
|
||||
// start draw
|
||||
wxPoint pt = rcContent.GetLeftTop();
|
||||
if (icon.bmp().IsOk()) {
|
||||
pt.y += (rcContent.height - szIcon.y) / 2;
|
||||
dc.DrawBitmap(icon.bmp(), pt);
|
||||
//BBS norrow size between text and icon
|
||||
pt.x += szIcon.x + padding;
|
||||
pt.y = rcContent.y;
|
||||
}
|
||||
auto text = GetLabel();
|
||||
if (!text.IsEmpty()) {
|
||||
if (pt.x + textSize.x > size.x)
|
||||
text = wxControl::Ellipsize(text, dc, wxELLIPSIZE_END, size.x - pt.x);
|
||||
pt.y += (rcContent.height - textSize.y) / 2;
|
||||
dc.SetFont(GetFont());
|
||||
dc.SetTextForeground(text_color.colorForStates(states));
|
||||
dc.DrawText(text, pt);
|
||||
}
|
||||
}
|
||||
|
||||
void Button::messureSize()
|
||||
{
|
||||
wxClientDC dc(this);
|
||||
textSize = dc.GetTextExtent(GetLabel());
|
||||
if (minSize.GetWidth() > 0) {
|
||||
wxWindow::SetMinSize(minSize);
|
||||
return;
|
||||
}
|
||||
wxSize szContent = textSize;
|
||||
if (this->active_icon.bmp().IsOk()) {
|
||||
if (szContent.y > 0) {
|
||||
//BBS norrow size between text and icon
|
||||
szContent.x += 5;
|
||||
}
|
||||
wxSize szIcon = this->active_icon.GetBmpSize();
|
||||
szContent.x += szIcon.x;
|
||||
if (szIcon.y > szContent.y)
|
||||
szContent.y = szIcon.y;
|
||||
}
|
||||
wxSize size = szContent + paddingSize * 2;
|
||||
if (minSize.GetHeight() > 0)
|
||||
size.SetHeight(minSize.GetHeight());
|
||||
wxWindow::SetMinSize(size);
|
||||
}
|
||||
|
||||
void Button::mouseDown(wxMouseEvent& event)
|
||||
{
|
||||
event.Skip();
|
||||
pressedDown = true;
|
||||
if (canFocus)
|
||||
SetFocus();
|
||||
CaptureMouse();
|
||||
}
|
||||
|
||||
void Button::mouseReleased(wxMouseEvent& event)
|
||||
{
|
||||
event.Skip();
|
||||
if (pressedDown) {
|
||||
pressedDown = false;
|
||||
if (HasCapture())
|
||||
ReleaseMouse();
|
||||
if (wxRect({0, 0}, GetSize()).Contains(event.GetPosition()))
|
||||
sendButtonEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void Button::mouseCaptureLost(wxMouseCaptureLostEvent &event)
|
||||
{
|
||||
wxMouseEvent evt;
|
||||
mouseReleased(evt);
|
||||
}
|
||||
|
||||
void Button::keyDownUp(wxKeyEvent &event)
|
||||
{
|
||||
if (event.GetKeyCode() == WXK_SPACE || event.GetKeyCode() == WXK_RETURN) {
|
||||
wxMouseEvent evt(event.GetEventType() == wxEVT_KEY_UP ? wxEVT_LEFT_UP : wxEVT_LEFT_DOWN);
|
||||
event.SetEventObject(this);
|
||||
GetEventHandler()->ProcessEvent(evt);
|
||||
return;
|
||||
}
|
||||
if (event.GetEventType() == wxEVT_KEY_DOWN &&
|
||||
(event.GetKeyCode() == WXK_TAB || event.GetKeyCode() == WXK_LEFT || event.GetKeyCode() == WXK_RIGHT
|
||||
|| event.GetKeyCode() == WXK_UP || event.GetKeyCode() == WXK_DOWN))
|
||||
HandleAsNavigationKey(event);
|
||||
else
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void Button::sendButtonEvent()
|
||||
{
|
||||
wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
|
||||
event.SetEventObject(this);
|
||||
GetEventHandler()->ProcessEvent(event);
|
||||
}
|
||||
|
||||
#ifdef __WIN32__
|
||||
|
||||
WXLRESULT Button::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
|
||||
{
|
||||
if (nMsg == WM_GETDLGCODE) { return DLGC_WANTMESSAGE; }
|
||||
if (nMsg == WM_KEYDOWN) {
|
||||
wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, wParam, lParam));
|
||||
switch (wParam) {
|
||||
case WXK_RETURN: { // WXK_RETURN key is handled by default button
|
||||
GetEventHandler()->ProcessEvent(event);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return wxWindow::MSWWindowProc(nMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool Button::AcceptsFocus() const { return canFocus; }
|
78
src/slic3r/GUI/Widgets/Button.hpp
Normal file
78
src/slic3r/GUI/Widgets/Button.hpp
Normal file
@ -0,0 +1,78 @@
|
||||
#ifndef slic3r_GUI_Button_hpp_
|
||||
#define slic3r_GUI_Button_hpp_
|
||||
|
||||
#include "../wxExtensions.hpp"
|
||||
#include "StaticBox.hpp"
|
||||
|
||||
class Button : public StaticBox
|
||||
{
|
||||
wxSize textSize;
|
||||
wxSize minSize; // set by outer
|
||||
wxSize paddingSize;
|
||||
ScalableBitmap active_icon;
|
||||
ScalableBitmap inactive_icon;
|
||||
|
||||
StateColor text_color;
|
||||
|
||||
bool pressedDown = false;
|
||||
bool m_selected = true;
|
||||
bool canFocus = true;
|
||||
|
||||
static const int buttonWidth = 200;
|
||||
static const int buttonHeight = 50;
|
||||
|
||||
public:
|
||||
Button();
|
||||
|
||||
Button(wxWindow* parent, wxString text, wxString icon = "", long style = 0, int iconSize = 0);
|
||||
|
||||
bool Create(wxWindow* parent, wxString text, wxString icon = "", long style = 0, int iconSize = 0);
|
||||
|
||||
void SetLabel(const wxString& label) override;
|
||||
|
||||
void SetIcon(const wxString& icon);
|
||||
|
||||
void SetInactiveIcon(const wxString& icon);
|
||||
|
||||
void SetMinSize(const wxSize& size) override;
|
||||
|
||||
void SetPaddingSize(const wxSize& size);
|
||||
|
||||
void SetTextColor(StateColor const &color);
|
||||
|
||||
void SetTextColorNormal(wxColor const &color);
|
||||
|
||||
void SetSelected(bool selected = true) { m_selected = selected; }
|
||||
|
||||
bool Enable(bool enable = true) override;
|
||||
|
||||
void SetCanFocus(bool canFocus) override;
|
||||
|
||||
void Rescale();
|
||||
|
||||
protected:
|
||||
#ifdef __WIN32__
|
||||
WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) override;
|
||||
#endif
|
||||
|
||||
bool AcceptsFocus() const override;
|
||||
|
||||
private:
|
||||
void paintEvent(wxPaintEvent& evt);
|
||||
|
||||
void render(wxDC& dc);
|
||||
|
||||
void messureSize();
|
||||
|
||||
// some useful events
|
||||
void mouseDown(wxMouseEvent& event);
|
||||
void mouseReleased(wxMouseEvent& event);
|
||||
void mouseCaptureLost(wxMouseCaptureLostEvent &event);
|
||||
void keyDownUp(wxKeyEvent &event);
|
||||
|
||||
void sendButtonEvent();
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_Button_hpp_
|
125
src/slic3r/GUI/Widgets/CheckBox.cpp
Normal file
125
src/slic3r/GUI/Widgets/CheckBox.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
#include "CheckBox.hpp"
|
||||
|
||||
#include "../wxExtensions.hpp"
|
||||
|
||||
CheckBox::CheckBox(wxWindow* parent)
|
||||
: wxBitmapToggleButton(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE)
|
||||
, m_on(this, "check_on", 18)
|
||||
, m_half(this, "check_half", 18)
|
||||
, m_off(this, "check_off", 18)
|
||||
, m_on_disabled(this, "check_on_disabled", 18)
|
||||
, m_half_disabled(this, "check_half_disabled", 18)
|
||||
, m_off_disabled(this, "check_off_disabled", 18)
|
||||
, m_on_focused(this, "check_on_focused", 18)
|
||||
, m_half_focused(this, "check_half_focused", 18)
|
||||
, m_off_focused(this, "check_off_focused", 18)
|
||||
{
|
||||
//SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
|
||||
if (parent)
|
||||
SetBackgroundColour(parent->GetBackgroundColour());
|
||||
Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { m_half_checked = false; update(); e.Skip(); });
|
||||
#ifdef __WXOSX__ // State not fully implement on MacOS
|
||||
Bind(wxEVT_SET_FOCUS, &CheckBox::updateBitmap, this);
|
||||
Bind(wxEVT_KILL_FOCUS, &CheckBox::updateBitmap, this);
|
||||
Bind(wxEVT_ENTER_WINDOW, &CheckBox::updateBitmap, this);
|
||||
Bind(wxEVT_LEAVE_WINDOW, &CheckBox::updateBitmap, this);
|
||||
#endif
|
||||
SetSize(m_on.GetBmpSize());
|
||||
SetMinSize(m_on.GetBmpSize());
|
||||
update();
|
||||
}
|
||||
|
||||
void CheckBox::SetValue(bool value)
|
||||
{
|
||||
wxBitmapToggleButton::SetValue(value);
|
||||
update();
|
||||
}
|
||||
|
||||
void CheckBox::SetHalfChecked(bool value)
|
||||
{
|
||||
m_half_checked = value;
|
||||
update();
|
||||
}
|
||||
|
||||
void CheckBox::Rescale()
|
||||
{
|
||||
m_on.msw_rescale();
|
||||
m_half.msw_rescale();
|
||||
m_off.msw_rescale();
|
||||
m_on_disabled.msw_rescale();
|
||||
m_half_disabled.msw_rescale();
|
||||
m_off_disabled.msw_rescale();
|
||||
m_on_focused.msw_rescale();
|
||||
m_half_focused.msw_rescale();
|
||||
m_off_focused.msw_rescale();
|
||||
SetSize(m_on.GetBmpSize());
|
||||
update();
|
||||
}
|
||||
|
||||
void CheckBox::update()
|
||||
{
|
||||
SetBitmapLabel((m_half_checked ? m_half : GetValue() ? m_on : m_off).bmp());
|
||||
SetBitmapDisabled((m_half_checked ? m_half_disabled : GetValue() ? m_on_disabled : m_off_disabled).bmp());
|
||||
#ifdef __WXMSW__
|
||||
SetBitmapFocus((m_half_checked ? m_half_focused : GetValue() ? m_on_focused : m_off_focused).bmp());
|
||||
#endif
|
||||
SetBitmapCurrent((m_half_checked ? m_half_focused : GetValue() ? m_on_focused : m_off_focused).bmp());
|
||||
#ifdef __WXOSX__
|
||||
wxCommandEvent e(wxEVT_UPDATE_UI);
|
||||
updateBitmap(e);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __WXMSW__
|
||||
|
||||
CheckBox::State CheckBox::GetNormalState() const { return State_Normal; }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __WXOSX__
|
||||
|
||||
bool CheckBox::Enable(bool enable)
|
||||
{
|
||||
bool result = wxBitmapToggleButton::Enable(enable);
|
||||
if (result) {
|
||||
m_disable = !enable;
|
||||
wxCommandEvent e(wxEVT_ACTIVATE);
|
||||
updateBitmap(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
wxBitmap CheckBox::DoGetBitmap(State which) const
|
||||
{
|
||||
if (m_disable) {
|
||||
return wxBitmapToggleButton::DoGetBitmap(State_Disabled);
|
||||
}
|
||||
if (m_focus) {
|
||||
return wxBitmapToggleButton::DoGetBitmap(State_Current);
|
||||
}
|
||||
return wxBitmapToggleButton::DoGetBitmap(which);
|
||||
}
|
||||
|
||||
void CheckBox::updateBitmap(wxEvent & evt)
|
||||
{
|
||||
evt.Skip();
|
||||
if (evt.GetEventType() == wxEVT_ENTER_WINDOW) {
|
||||
m_hover = true;
|
||||
} else if (evt.GetEventType() == wxEVT_LEAVE_WINDOW) {
|
||||
m_hover = false;
|
||||
} else {
|
||||
if (evt.GetEventType() == wxEVT_SET_FOCUS) {
|
||||
m_focus = true;
|
||||
} else if (evt.GetEventType() == wxEVT_KILL_FOCUS) {
|
||||
m_focus = false;
|
||||
}
|
||||
wxMouseEvent e;
|
||||
if (m_hover)
|
||||
OnEnterWindow(e);
|
||||
else
|
||||
OnLeaveWindow(e);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
55
src/slic3r/GUI/Widgets/CheckBox.hpp
Normal file
55
src/slic3r/GUI/Widgets/CheckBox.hpp
Normal file
@ -0,0 +1,55 @@
|
||||
#ifndef slic3r_GUI_CheckBox_hpp_
|
||||
#define slic3r_GUI_CheckBox_hpp_
|
||||
|
||||
#include "../wxExtensions.hpp"
|
||||
|
||||
#include <wx/tglbtn.h>
|
||||
|
||||
class CheckBox : public wxBitmapToggleButton
|
||||
{
|
||||
public:
|
||||
CheckBox(wxWindow * parent = NULL);
|
||||
|
||||
public:
|
||||
void SetValue(bool value) override;
|
||||
|
||||
void SetHalfChecked(bool value = true);
|
||||
|
||||
void Rescale();
|
||||
|
||||
#ifdef __WXOSX__
|
||||
virtual bool Enable(bool enable = true) wxOVERRIDE;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
#ifdef __WXMSW__
|
||||
virtual State GetNormalState() const wxOVERRIDE;
|
||||
#endif
|
||||
|
||||
#ifdef __WXOSX__
|
||||
virtual wxBitmap DoGetBitmap(State which) const wxOVERRIDE;
|
||||
|
||||
void updateBitmap(wxEvent & evt);
|
||||
|
||||
bool m_disable = false;
|
||||
bool m_hover = false;
|
||||
bool m_focus = false;
|
||||
#endif
|
||||
|
||||
private:
|
||||
void update();
|
||||
|
||||
private:
|
||||
ScalableBitmap m_on;
|
||||
ScalableBitmap m_half;
|
||||
ScalableBitmap m_off;
|
||||
ScalableBitmap m_on_disabled;
|
||||
ScalableBitmap m_half_disabled;
|
||||
ScalableBitmap m_off_disabled;
|
||||
ScalableBitmap m_on_focused;
|
||||
ScalableBitmap m_half_focused;
|
||||
ScalableBitmap m_off_focused;
|
||||
bool m_half_checked = false;
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_CheckBox_hpp_
|
301
src/slic3r/GUI/Widgets/ComboBox.cpp
Normal file
301
src/slic3r/GUI/Widgets/ComboBox.cpp
Normal file
@ -0,0 +1,301 @@
|
||||
#include "ComboBox.hpp"
|
||||
#include "Label.hpp"
|
||||
|
||||
#include <wx/dcgraph.h>
|
||||
|
||||
BEGIN_EVENT_TABLE(ComboBox, TextInput)
|
||||
|
||||
EVT_LEFT_DOWN(ComboBox::mouseDown)
|
||||
//EVT_MOUSEWHEEL(ComboBox::mouseWheelMoved)
|
||||
EVT_KEY_DOWN(ComboBox::keyDown)
|
||||
|
||||
// catch paint events
|
||||
END_EVENT_TABLE()
|
||||
|
||||
/*
|
||||
* Called by the system of by wxWidgets when the panel needs
|
||||
* to be redrawn. You can also trigger this call by
|
||||
* calling Refresh()/Update().
|
||||
*/
|
||||
|
||||
ComboBox::ComboBox(wxWindow * parent,
|
||||
wxWindowID id,
|
||||
const wxString &value,
|
||||
const wxPoint & pos,
|
||||
const wxSize & size,
|
||||
int n,
|
||||
const wxString choices[],
|
||||
long style)
|
||||
: drop(texts, icons)
|
||||
{
|
||||
if (style & wxCB_READONLY)
|
||||
style |= wxRIGHT;
|
||||
text_off = style & CB_NO_TEXT;
|
||||
TextInput::Create(parent, "", value, (style & CB_NO_DROP_ICON) ? "" : "drop_down", pos, size,
|
||||
style | wxTE_PROCESS_ENTER);
|
||||
drop.Create(this, style & DD_STYLE_MASK);
|
||||
|
||||
if (style & wxCB_READONLY) {
|
||||
GetTextCtrl()->Hide();
|
||||
TextInput::SetFont(Label::Body_14);
|
||||
TextInput::SetBorderColor(StateColor(std::make_pair(0xDBDBDB, (int) StateColor::Disabled),
|
||||
std::make_pair(0x00AE42, (int) StateColor::Hovered),
|
||||
std::make_pair(0xDBDBDB, (int) StateColor::Normal)));
|
||||
TextInput::SetBackgroundColor(StateColor(std::make_pair(0xF0F0F0, (int) StateColor::Disabled),
|
||||
std::make_pair(0xEDFAF2, (int) StateColor::Focused),
|
||||
std::make_pair(*wxWHITE, (int) StateColor::Normal)));
|
||||
TextInput::SetLabelColor(StateColor(std::make_pair(0x909090, (int) StateColor::Disabled),
|
||||
std::make_pair(0x262E30, (int) StateColor::Normal)));
|
||||
} else {
|
||||
GetTextCtrl()->Bind(wxEVT_KEY_DOWN, &ComboBox::keyDown, this);
|
||||
}
|
||||
drop.Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &e) {
|
||||
SetSelection(e.GetInt());
|
||||
e.SetEventObject(this);
|
||||
e.SetId(GetId());
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
});
|
||||
drop.Bind(EVT_DISMISS, [this](auto &) {
|
||||
drop_down = false;
|
||||
wxCommandEvent e(wxEVT_COMBOBOX_CLOSEUP);
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
});
|
||||
for (int i = 0; i < n; ++i) Append(choices[i]);
|
||||
}
|
||||
|
||||
int ComboBox::GetSelection() const { return drop.GetSelection(); }
|
||||
|
||||
void ComboBox::SetSelection(int n)
|
||||
{
|
||||
drop.SetSelection(n);
|
||||
SetLabel(drop.GetValue());
|
||||
if (drop.selection >= 0)
|
||||
SetIcon(icons[drop.selection]);
|
||||
}
|
||||
|
||||
void ComboBox::Rescale()
|
||||
{
|
||||
TextInput::Rescale();
|
||||
drop.Rescale();
|
||||
}
|
||||
|
||||
wxString ComboBox::GetValue() const
|
||||
{
|
||||
return drop.GetSelection() >= 0 ? drop.GetValue() : GetLabel();
|
||||
}
|
||||
|
||||
void ComboBox::SetValue(const wxString &value)
|
||||
{
|
||||
drop.SetValue(value);
|
||||
SetLabel(value);
|
||||
if (drop.selection >= 0)
|
||||
SetIcon(icons[drop.selection]);
|
||||
}
|
||||
|
||||
void ComboBox::SetLabel(const wxString &value)
|
||||
{
|
||||
if (GetTextCtrl()->IsShown() || text_off)
|
||||
GetTextCtrl()->SetValue(value);
|
||||
else
|
||||
TextInput::SetLabel(value);
|
||||
}
|
||||
|
||||
wxString ComboBox::GetLabel() const
|
||||
{
|
||||
if (GetTextCtrl()->IsShown() || text_off)
|
||||
return GetTextCtrl()->GetValue();
|
||||
else
|
||||
return TextInput::GetLabel();
|
||||
}
|
||||
|
||||
void ComboBox::SetTextLabel(const wxString& label)
|
||||
{
|
||||
TextInput::SetLabel(label);
|
||||
}
|
||||
|
||||
wxString ComboBox::GetTextLabel() const
|
||||
{
|
||||
return TextInput::GetLabel();
|
||||
}
|
||||
|
||||
bool ComboBox::SetFont(wxFont const& font)
|
||||
{
|
||||
if (GetTextCtrl() && GetTextCtrl()->IsShown())
|
||||
return GetTextCtrl()->SetFont(font);
|
||||
else
|
||||
return TextInput::SetFont(font);
|
||||
}
|
||||
|
||||
int ComboBox::Append(const wxString &item, const wxBitmap &bitmap)
|
||||
{
|
||||
return Append(item, bitmap, nullptr);
|
||||
}
|
||||
|
||||
int ComboBox::Append(const wxString &item,
|
||||
const wxBitmap &bitmap,
|
||||
void * clientData)
|
||||
{
|
||||
texts.push_back(item);
|
||||
icons.push_back(bitmap);
|
||||
datas.push_back(clientData);
|
||||
types.push_back(wxClientData_None);
|
||||
drop.Invalidate();
|
||||
return texts.size() - 1;
|
||||
}
|
||||
|
||||
void ComboBox::DoClear()
|
||||
{
|
||||
texts.clear();
|
||||
icons.clear();
|
||||
datas.clear();
|
||||
types.clear();
|
||||
drop.Invalidate(true);
|
||||
}
|
||||
|
||||
void ComboBox::DoDeleteOneItem(unsigned int pos)
|
||||
{
|
||||
if (pos >= texts.size()) return;
|
||||
texts.erase(texts.begin() + pos);
|
||||
icons.erase(icons.begin() + pos);
|
||||
datas.erase(datas.begin() + pos);
|
||||
types.erase(types.begin() + pos);
|
||||
drop.Invalidate(true);
|
||||
}
|
||||
|
||||
unsigned int ComboBox::GetCount() const { return texts.size(); }
|
||||
|
||||
wxString ComboBox::GetString(unsigned int n) const
|
||||
{
|
||||
return n < texts.size() ? texts[n] : wxString{};
|
||||
}
|
||||
|
||||
void ComboBox::SetString(unsigned int n, wxString const &value)
|
||||
{
|
||||
if (n >= texts.size()) return;
|
||||
texts[n] = value;
|
||||
drop.Invalidate();
|
||||
if (n == drop.GetSelection()) SetLabel(value);
|
||||
}
|
||||
|
||||
wxBitmap ComboBox::GetItemBitmap(unsigned int n) { return icons[n]; }
|
||||
|
||||
int ComboBox::DoInsertItems(const wxArrayStringsAdapter &items,
|
||||
unsigned int pos,
|
||||
void ** clientData,
|
||||
wxClientDataType type)
|
||||
{
|
||||
if (pos > texts.size()) return -1;
|
||||
for (int i = 0; i < items.GetCount(); ++i) {
|
||||
texts.insert(texts.begin() + pos, items[i]);
|
||||
icons.insert(icons.begin() + pos, wxNullBitmap);
|
||||
datas.insert(datas.begin() + pos, clientData ? clientData[i] : NULL);
|
||||
types.insert(types.begin() + pos, type);
|
||||
++pos;
|
||||
}
|
||||
drop.Invalidate(true);
|
||||
return pos - 1;
|
||||
}
|
||||
|
||||
void *ComboBox::DoGetItemClientData(unsigned int n) const { return n < texts.size() ? datas[n] : NULL; }
|
||||
|
||||
void ComboBox::DoSetItemClientData(unsigned int n, void *data)
|
||||
{
|
||||
if (n < texts.size())
|
||||
datas[n] = data;
|
||||
}
|
||||
|
||||
void ComboBox::mouseDown(wxMouseEvent &event)
|
||||
{
|
||||
SetFocus();
|
||||
if (drop_down) {
|
||||
drop.Hide();
|
||||
} else if (drop.HasDismissLongTime()) {
|
||||
drop.autoPosition();
|
||||
drop_down = true;
|
||||
drop.Popup();
|
||||
wxCommandEvent e(wxEVT_COMBOBOX_DROPDOWN);
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void ComboBox::mouseWheelMoved(wxMouseEvent &event)
|
||||
{
|
||||
event.Skip();
|
||||
if (drop_down) return;
|
||||
auto delta = (event.GetWheelRotation() < 0 == event.IsWheelInverted()) ? -1 : 1;
|
||||
unsigned int n = GetSelection() + delta;
|
||||
if (n < GetCount()) {
|
||||
SetSelection((int) n);
|
||||
sendComboBoxEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void ComboBox::keyDown(wxKeyEvent& event)
|
||||
{
|
||||
switch (event.GetKeyCode()) {
|
||||
case WXK_RETURN:
|
||||
case WXK_SPACE:
|
||||
if (drop_down) {
|
||||
drop.DismissAndNotify();
|
||||
} else if (drop.HasDismissLongTime()) {
|
||||
drop.autoPosition();
|
||||
drop_down = true;
|
||||
drop.Popup();
|
||||
wxCommandEvent e(wxEVT_COMBOBOX_DROPDOWN);
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
}
|
||||
break;
|
||||
case WXK_UP:
|
||||
case WXK_DOWN:
|
||||
case WXK_LEFT:
|
||||
case WXK_RIGHT:
|
||||
if ((event.GetKeyCode() == WXK_UP || event.GetKeyCode() == WXK_LEFT) && GetSelection() > 0) {
|
||||
SetSelection(GetSelection() - 1);
|
||||
} else if ((event.GetKeyCode() == WXK_DOWN || event.GetKeyCode() == WXK_RIGHT) && GetSelection() + 1 < texts.size()) {
|
||||
SetSelection(GetSelection() + 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
{
|
||||
wxCommandEvent e(wxEVT_COMBOBOX);
|
||||
e.SetEventObject(this);
|
||||
e.SetId(GetId());
|
||||
e.SetInt(GetSelection());
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
}
|
||||
break;
|
||||
case WXK_TAB:
|
||||
HandleAsNavigationKey(event);
|
||||
break;
|
||||
default:
|
||||
event.Skip();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ComboBox::OnEdit()
|
||||
{
|
||||
auto value = GetTextCtrl()->GetValue();
|
||||
SetValue(value);
|
||||
}
|
||||
|
||||
#ifdef __WIN32__
|
||||
|
||||
WXLRESULT ComboBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
|
||||
{
|
||||
if (nMsg == WM_GETDLGCODE) {
|
||||
return DLGC_WANTALLKEYS;
|
||||
}
|
||||
return TextInput::MSWWindowProc(nMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void ComboBox::sendComboBoxEvent()
|
||||
{
|
||||
wxCommandEvent event(wxEVT_COMBOBOX, GetId());
|
||||
event.SetEventObject(this);
|
||||
event.SetInt(drop.GetSelection());
|
||||
event.SetString(drop.GetValue());
|
||||
GetEventHandler()->ProcessEvent(event);
|
||||
}
|
92
src/slic3r/GUI/Widgets/ComboBox.hpp
Normal file
92
src/slic3r/GUI/Widgets/ComboBox.hpp
Normal file
@ -0,0 +1,92 @@
|
||||
#ifndef slic3r_GUI_ComboBox_hpp_
|
||||
#define slic3r_GUI_ComboBox_hpp_
|
||||
|
||||
#include "TextInput.hpp"
|
||||
#include "DropDown.hpp"
|
||||
|
||||
#define CB_NO_DROP_ICON DD_NO_CHECK_ICON
|
||||
#define CB_NO_TEXT DD_NO_TEXT
|
||||
|
||||
class ComboBox : public wxWindowWithItems<TextInput, wxItemContainer>
|
||||
{
|
||||
std::vector<wxString> texts;
|
||||
std::vector<wxBitmap> icons;
|
||||
std::vector<void *> datas;
|
||||
std::vector<wxClientDataType> types;
|
||||
|
||||
DropDown drop;
|
||||
bool drop_down = false;
|
||||
bool text_off = false;
|
||||
|
||||
public:
|
||||
ComboBox(wxWindow * parent,
|
||||
wxWindowID id,
|
||||
const wxString &value = wxEmptyString,
|
||||
const wxPoint & pos = wxDefaultPosition,
|
||||
const wxSize & size = wxDefaultSize,
|
||||
int n = 0,
|
||||
const wxString choices[] = NULL,
|
||||
long style = 0);
|
||||
|
||||
DropDown & GetDropDown() { return drop; }
|
||||
|
||||
virtual bool SetFont(wxFont const & font) override;
|
||||
|
||||
public:
|
||||
int Append(const wxString &item, const wxBitmap &bitmap = wxNullBitmap);
|
||||
|
||||
int Append(const wxString &item, const wxBitmap &bitmap, void *clientData);
|
||||
|
||||
unsigned int GetCount() const override;
|
||||
|
||||
int GetSelection() const override;
|
||||
|
||||
void SetSelection(int n) override;
|
||||
|
||||
virtual void Rescale() override;
|
||||
|
||||
wxString GetValue() const;
|
||||
void SetValue(const wxString &value);
|
||||
|
||||
void SetLabel(const wxString &label) override;
|
||||
wxString GetLabel() const override;
|
||||
|
||||
void SetTextLabel(const wxString &label);
|
||||
wxString GetTextLabel() const;
|
||||
|
||||
wxString GetString(unsigned int n) const override;
|
||||
void SetString(unsigned int n, wxString const &value) override;
|
||||
|
||||
wxBitmap GetItemBitmap(unsigned int n);
|
||||
|
||||
protected:
|
||||
virtual int DoInsertItems(const wxArrayStringsAdapter &items,
|
||||
unsigned int pos,
|
||||
void ** clientData,
|
||||
wxClientDataType type) override;
|
||||
virtual void DoClear() override;
|
||||
|
||||
void DoDeleteOneItem(unsigned int pos) override;
|
||||
|
||||
void *DoGetItemClientData(unsigned int n) const override;
|
||||
void DoSetItemClientData(unsigned int n, void *data) override;
|
||||
|
||||
void OnEdit() override;
|
||||
|
||||
#ifdef __WIN32__
|
||||
WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
// some useful events
|
||||
void mouseDown(wxMouseEvent &event);
|
||||
void mouseWheelMoved(wxMouseEvent &event);
|
||||
void keyDown(wxKeyEvent &event);
|
||||
|
||||
void sendComboBoxEvent();
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_ComboBox_hpp_
|
472
src/slic3r/GUI/Widgets/DropDown.cpp
Normal file
472
src/slic3r/GUI/Widgets/DropDown.cpp
Normal file
@ -0,0 +1,472 @@
|
||||
#include "DropDown.hpp"
|
||||
#include "Label.hpp"
|
||||
|
||||
#include <wx/dcgraph.h>
|
||||
|
||||
wxDEFINE_EVENT(EVT_DISMISS, wxCommandEvent);
|
||||
|
||||
BEGIN_EVENT_TABLE(DropDown, wxPopupTransientWindow)
|
||||
|
||||
EVT_LEFT_DOWN(DropDown::mouseDown)
|
||||
EVT_LEFT_UP(DropDown::mouseReleased)
|
||||
EVT_MOUSE_CAPTURE_LOST(DropDown::mouseCaptureLost)
|
||||
EVT_MOTION(DropDown::mouseMove)
|
||||
EVT_MOUSEWHEEL(DropDown::mouseWheelMoved)
|
||||
|
||||
// catch paint events
|
||||
EVT_PAINT(DropDown::paintEvent)
|
||||
|
||||
END_EVENT_TABLE()
|
||||
|
||||
/*
|
||||
* Called by the system of by wxWidgets when the panel needs
|
||||
* to be redrawn. You can also trigger this call by
|
||||
* calling Refresh()/Update().
|
||||
*/
|
||||
|
||||
DropDown::DropDown(std::vector<wxString> &texts,
|
||||
std::vector<wxBitmap> &icons)
|
||||
: texts(texts)
|
||||
, icons(icons)
|
||||
, state_handler(this)
|
||||
, border_color(0xDBDBDB)
|
||||
, text_color(0x363636)
|
||||
, selector_border_color(std::make_pair(0x00AE42, (int) StateColor::Hovered),
|
||||
std::make_pair(*wxWHITE, (int) StateColor::Normal))
|
||||
, selector_background_color(std::make_pair(0xEDFAF2, (int) StateColor::Checked),
|
||||
std::make_pair(*wxWHITE, (int) StateColor::Normal))
|
||||
{
|
||||
}
|
||||
|
||||
DropDown::DropDown(wxWindow * parent,
|
||||
std::vector<wxString> &texts,
|
||||
std::vector<wxBitmap> &icons,
|
||||
long style)
|
||||
: DropDown(texts, icons)
|
||||
{
|
||||
Create(parent, style);
|
||||
}
|
||||
|
||||
void DropDown::Create(wxWindow * parent,
|
||||
long style)
|
||||
{
|
||||
wxPopupTransientWindow::Create(parent);
|
||||
SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
SetBackgroundColour(*wxWHITE);
|
||||
state_handler.attach({&border_color, &text_color, &selector_border_color, &selector_background_color});
|
||||
state_handler.update_binds();
|
||||
if ((style & DD_NO_CHECK_ICON) == 0)
|
||||
check_bitmap = ScalableBitmap(this, "checked", 16);
|
||||
text_off = style & DD_NO_TEXT;
|
||||
|
||||
// BBS set default font
|
||||
SetFont(Label::Body_14);
|
||||
#ifdef __WXOSX__
|
||||
// wxPopupTransientWindow releases mouse on idle, which may cause various problems,
|
||||
// such as losting mouse move, and dismissing soon on first LEFT_DOWN event.
|
||||
Bind(wxEVT_IDLE, [] (wxIdleEvent & evt) {});
|
||||
#endif
|
||||
}
|
||||
|
||||
void DropDown::Invalidate(bool clear)
|
||||
{
|
||||
if (clear) {
|
||||
selection = hover_item = -1;
|
||||
offset = wxPoint();
|
||||
}
|
||||
assert(selection < (int) texts.size());
|
||||
need_sync = true;
|
||||
}
|
||||
|
||||
void DropDown::SetSelection(int n)
|
||||
{
|
||||
assert(n < (int) texts.size());
|
||||
if (n >= (int) texts.size())
|
||||
n = -1;
|
||||
if (selection == n) return;
|
||||
selection = n;
|
||||
paintNow();
|
||||
}
|
||||
|
||||
wxString DropDown::GetValue() const
|
||||
{
|
||||
return selection >= 0 ? texts[selection] : wxString();
|
||||
}
|
||||
|
||||
void DropDown::SetValue(const wxString &value)
|
||||
{
|
||||
auto i = std::find(texts.begin(), texts.end(), value);
|
||||
selection = i == texts.end() ? -1 : std::distance(texts.begin(), i);
|
||||
}
|
||||
|
||||
void DropDown::SetCornerRadius(double radius)
|
||||
{
|
||||
this->radius = radius;
|
||||
paintNow();
|
||||
}
|
||||
|
||||
void DropDown::SetBorderColor(StateColor const &color)
|
||||
{
|
||||
border_color = color;
|
||||
state_handler.update_binds();
|
||||
paintNow();
|
||||
}
|
||||
|
||||
void DropDown::SetSelectorBorderColor(StateColor const &color)
|
||||
{
|
||||
selector_border_color = color;
|
||||
state_handler.update_binds();
|
||||
paintNow();
|
||||
}
|
||||
|
||||
void DropDown::SetTextColor(StateColor const &color)
|
||||
{
|
||||
text_color = color;
|
||||
state_handler.update_binds();
|
||||
paintNow();
|
||||
}
|
||||
|
||||
void DropDown::SetSelectorBackgroundColor(StateColor const &color)
|
||||
{
|
||||
selector_background_color = color;
|
||||
state_handler.update_binds();
|
||||
paintNow();
|
||||
}
|
||||
|
||||
void DropDown::SetUseContentWidth(bool use)
|
||||
{
|
||||
if (use_content_width == use)
|
||||
return;
|
||||
use_content_width = use;
|
||||
need_sync = true;
|
||||
messureSize();
|
||||
}
|
||||
|
||||
void DropDown::SetAlignIcon(bool align) { align_icon = align; }
|
||||
|
||||
void DropDown::Rescale()
|
||||
{
|
||||
need_sync = true;
|
||||
}
|
||||
|
||||
bool DropDown::HasDismissLongTime()
|
||||
{
|
||||
auto now = boost::posix_time::microsec_clock::universal_time();
|
||||
return !IsShown() &&
|
||||
(now - dismissTime).total_milliseconds() >= 200;
|
||||
}
|
||||
|
||||
void DropDown::paintEvent(wxPaintEvent& evt)
|
||||
{
|
||||
// depending on your system you may need to look at double-buffered dcs
|
||||
wxBufferedPaintDC dc(this);
|
||||
render(dc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Alternatively, you can use a clientDC to paint on the panel
|
||||
* at any time. Using this generally does not free you from
|
||||
* catching paint events, since it is possible that e.g. the window
|
||||
* manager throws away your drawing when the window comes to the
|
||||
* background, and expects you will redraw it when the window comes
|
||||
* back (by sending a paint event).
|
||||
*/
|
||||
void DropDown::paintNow()
|
||||
{
|
||||
// depending on your system you may need to look at double-buffered dcs
|
||||
//wxClientDC dc(this);
|
||||
//render(dc);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we do the actual rendering. I put it in a separate
|
||||
* method so that it can work no matter what type of DC
|
||||
* (e.g. wxPaintDC or wxClientDC) is used.
|
||||
*/
|
||||
void DropDown::render(wxDC &dc)
|
||||
{
|
||||
if (texts.size() == 0) return;
|
||||
int states = state_handler.states();
|
||||
dc.SetPen(wxPen(border_color.colorForStates(states)));
|
||||
dc.SetBrush(wxBrush(GetBackgroundColour()));
|
||||
// if (GetWindowStyle() & wxBORDER_NONE)
|
||||
// dc.SetPen(wxNullPen);
|
||||
|
||||
// draw background
|
||||
wxSize size = GetSize();
|
||||
if (radius == 0)
|
||||
dc.DrawRectangle(0, 0, size.x, size.y);
|
||||
else
|
||||
dc.DrawRoundedRectangle(0, 0, size.x, size.y, radius);
|
||||
|
||||
// draw hover rectangle
|
||||
wxRect rcContent = {{0, offset.y}, rowSize};
|
||||
if (hover_item >= 0 && (states & StateColor::Hovered)) {
|
||||
rcContent.y += rowSize.y * hover_item;
|
||||
if (rcContent.GetBottom() > 0 && rcContent.y < size.y) {
|
||||
if (selection == hover_item)
|
||||
dc.SetBrush(wxBrush(selector_background_color.colorForStates(states | StateColor::Checked)));
|
||||
dc.SetPen(wxPen(selector_border_color.colorForStates(states)));
|
||||
rcContent.Deflate(4, 1);
|
||||
dc.DrawRectangle(rcContent);
|
||||
rcContent.Inflate(4, 1);
|
||||
}
|
||||
rcContent.y = offset.y;
|
||||
}
|
||||
// draw checked rectangle
|
||||
if (selection >= 0 && (selection != hover_item || (states & StateColor::Hovered) == 0)) {
|
||||
rcContent.y += rowSize.y * selection;
|
||||
if (rcContent.GetBottom() > 0 && rcContent.y < size.y) {
|
||||
dc.SetBrush(wxBrush(selector_background_color.colorForStates(states | StateColor::Checked)));
|
||||
dc.SetPen(wxPen(selector_background_color.colorForStates(states)));
|
||||
rcContent.Deflate(4, 1);
|
||||
dc.DrawRectangle(rcContent);
|
||||
rcContent.Inflate(4, 1);
|
||||
}
|
||||
rcContent.y = offset.y;
|
||||
}
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
{
|
||||
wxSize offset = (rowSize - textSize) / 2;
|
||||
rcContent.Deflate(0, offset.y);
|
||||
}
|
||||
|
||||
// draw position bar
|
||||
if (rowSize.y * texts.size() > size.y) {
|
||||
int height = rowSize.y * texts.size();
|
||||
wxRect rect = {size.x - 6, -offset.y * size.y / height, 4,
|
||||
size.y * size.y / height};
|
||||
dc.SetPen(wxPen(border_color.defaultColor()));
|
||||
dc.SetBrush(wxBrush(*wxLIGHT_GREY));
|
||||
dc.DrawRoundedRectangle(rect, 2);
|
||||
rcContent.width -= 6;
|
||||
}
|
||||
|
||||
// draw check icon
|
||||
rcContent.x += 5;
|
||||
rcContent.width -= 5;
|
||||
if (check_bitmap.bmp().IsOk()) {
|
||||
auto szBmp = check_bitmap.GetBmpSize();
|
||||
if (selection >= 0) {
|
||||
wxPoint pt = rcContent.GetLeftTop();
|
||||
pt.y += (rcContent.height - szBmp.y) / 2;
|
||||
pt.y += rowSize.y * selection;
|
||||
if (pt.y + szBmp.y > 0 && pt.y < size.y)
|
||||
dc.DrawBitmap(check_bitmap.bmp(), pt);
|
||||
}
|
||||
rcContent.x += szBmp.x + 5;
|
||||
rcContent.width -= szBmp.x + 5;
|
||||
}
|
||||
// draw texts & icons
|
||||
dc.SetTextForeground(text_color.colorForStates(states));
|
||||
for (int i = 0; i < texts.size(); ++i) {
|
||||
if (rcContent.GetBottom() < 0) {
|
||||
rcContent.y += rowSize.y;
|
||||
continue;
|
||||
}
|
||||
if (rcContent.y > size.y) break;
|
||||
wxPoint pt = rcContent.GetLeftTop();
|
||||
auto & icon = icons[i];
|
||||
if (iconSize.x > 0) {
|
||||
if (icon.IsOk()) {
|
||||
pt.y += (rcContent.height - icon.GetSize().y) / 2;
|
||||
dc.DrawBitmap(icon, pt);
|
||||
}
|
||||
pt.x += iconSize.x + 5;
|
||||
pt.y = rcContent.y;
|
||||
} else if (icon.IsOk()) {
|
||||
pt.y += (rcContent.height - icon.GetSize().y) / 2;
|
||||
dc.DrawBitmap(icon, pt);
|
||||
pt.x += icon.GetWidth() + 5;
|
||||
pt.y = rcContent.y;
|
||||
}
|
||||
auto text = texts[i];
|
||||
if (!text_off && !text.IsEmpty()) {
|
||||
wxSize tSize = dc.GetMultiLineTextExtent(text);
|
||||
if (pt.x + tSize.x > rcContent.GetRight()) {
|
||||
text = wxControl::Ellipsize(text, dc, wxELLIPSIZE_END,
|
||||
rcContent.GetRight() - pt.x);
|
||||
}
|
||||
pt.y += (rcContent.height - textSize.y) / 2;
|
||||
dc.SetFont(GetFont());
|
||||
dc.DrawText(text, pt);
|
||||
}
|
||||
rcContent.y += rowSize.y;
|
||||
}
|
||||
}
|
||||
|
||||
void DropDown::messureSize()
|
||||
{
|
||||
if (!need_sync) return;
|
||||
textSize = wxSize();
|
||||
iconSize = wxSize();
|
||||
wxClientDC dc(GetParent() ? GetParent() : this);
|
||||
for (size_t i = 0; i < texts.size(); ++i) {
|
||||
wxSize size1 = text_off ? wxSize() : dc.GetMultiLineTextExtent(texts[i]);
|
||||
if (icons[i].IsOk()) {
|
||||
wxSize size2 = icons[i].GetSize();
|
||||
if (size2.x > iconSize.x) iconSize = size2;
|
||||
if (!align_icon) {
|
||||
size1.x += size2.x + (text_off ? 0 : 5);
|
||||
}
|
||||
}
|
||||
if (size1.x > textSize.x) textSize = size1;
|
||||
}
|
||||
if (!align_icon) iconSize.x = 0;
|
||||
wxSize szContent = textSize;
|
||||
szContent.x += 10;
|
||||
if (check_bitmap.bmp().IsOk()) {
|
||||
auto szBmp = check_bitmap.bmp().GetSize();
|
||||
szContent.x += szBmp.x + 5;
|
||||
}
|
||||
if (iconSize.x > 0) szContent.x += iconSize.x + (text_off ? 0 : 5);
|
||||
if (iconSize.y > szContent.y) szContent.y = iconSize.y;
|
||||
szContent.y += 10;
|
||||
if (texts.size() > 15) szContent.x += 6;
|
||||
if (GetParent()) {
|
||||
auto x = GetParent()->GetSize().x;
|
||||
if (!use_content_width || x > szContent.x)
|
||||
szContent.x = x;
|
||||
}
|
||||
rowSize = szContent;
|
||||
szContent.y *= std::min((size_t)15, texts.size());
|
||||
szContent.y += texts.size() > 15 ? rowSize.y / 2 : 0;
|
||||
wxWindow::SetSize(szContent);
|
||||
need_sync = false;
|
||||
}
|
||||
|
||||
void DropDown::autoPosition()
|
||||
{
|
||||
messureSize();
|
||||
wxPoint pos = GetParent()->ClientToScreen(wxPoint(0, -6));
|
||||
wxPoint old = GetPosition();
|
||||
wxSize size = GetSize();
|
||||
Position(pos, {0, GetParent()->GetSize().y + 12});
|
||||
if (old != GetPosition()) {
|
||||
size = rowSize;
|
||||
size.y *= std::min((size_t)15, texts.size());
|
||||
size.y += texts.size() > 15 ? rowSize.y / 2 : 0;
|
||||
if (size != GetSize()) {
|
||||
wxWindow::SetSize(size);
|
||||
offset = wxPoint();
|
||||
Position(pos, {0, GetParent()->GetSize().y + 12});
|
||||
}
|
||||
}
|
||||
if (GetPosition().y > pos.y) {
|
||||
// may exceed
|
||||
auto drect = wxDisplay(GetParent()).GetGeometry();
|
||||
if (GetPosition().y + size.y + 10 > drect.GetBottom()) {
|
||||
if (use_content_width && texts.size() <= 15) size.x += 6;
|
||||
size.y = drect.GetBottom() - GetPosition().y - 10;
|
||||
wxWindow::SetSize(size);
|
||||
if (selection >= 0) {
|
||||
if (offset.y + rowSize.y * (selection + 1) > size.y)
|
||||
offset.y = size.y - rowSize.y * (selection + 1);
|
||||
else if (offset.y + rowSize.y * selection < 0)
|
||||
offset.y = -rowSize.y * selection;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DropDown::mouseDown(wxMouseEvent& event)
|
||||
{
|
||||
// Receivce unexcepted LEFT_DOWN on Mac after OnDismiss
|
||||
if (!IsShown())
|
||||
return;
|
||||
// force calc hover item again
|
||||
mouseMove(event);
|
||||
pressedDown = true;
|
||||
CaptureMouse();
|
||||
dragStart = event.GetPosition();
|
||||
}
|
||||
|
||||
void DropDown::mouseReleased(wxMouseEvent& event)
|
||||
{
|
||||
if (pressedDown) {
|
||||
dragStart = wxPoint();
|
||||
pressedDown = false;
|
||||
if (HasCapture())
|
||||
ReleaseMouse();
|
||||
if (hover_item >= 0) { // not moved
|
||||
sendDropDownEvent();
|
||||
DismissAndNotify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DropDown::mouseCaptureLost(wxMouseCaptureLostEvent &event)
|
||||
{
|
||||
wxMouseEvent evt;
|
||||
mouseReleased(evt);
|
||||
}
|
||||
|
||||
void DropDown::mouseMove(wxMouseEvent &event)
|
||||
{
|
||||
wxPoint pt = event.GetPosition();
|
||||
if (pressedDown) {
|
||||
wxPoint pt2 = offset + pt - dragStart;
|
||||
dragStart = pt;
|
||||
if (pt2.y > 0)
|
||||
pt2.y = 0;
|
||||
else if (pt2.y + rowSize.y * texts.size() < GetSize().y)
|
||||
pt2.y = GetSize().y - rowSize.y * texts.size();
|
||||
if (pt2.y != offset.y) {
|
||||
offset = pt2;
|
||||
hover_item = -1; // moved
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!pressedDown || hover_item >= 0) {
|
||||
int hover = (pt.y - offset.y) / rowSize.y;
|
||||
if (hover >= (int) texts.size()) hover = -1;
|
||||
if (hover == hover_item) return;
|
||||
hover_item = hover;
|
||||
if (hover >= 0)
|
||||
SetToolTip(texts[hover]);
|
||||
}
|
||||
paintNow();
|
||||
}
|
||||
|
||||
void DropDown::mouseWheelMoved(wxMouseEvent &event)
|
||||
{
|
||||
auto delta = event.GetWheelRotation() > 0 ? rowSize.y : -rowSize.y;
|
||||
wxPoint pt2 = offset + wxPoint{0, delta};
|
||||
if (pt2.y > 0)
|
||||
pt2.y = 0;
|
||||
else if (pt2.y + rowSize.y * texts.size() < GetSize().y)
|
||||
pt2.y = GetSize().y - rowSize.y * texts.size();
|
||||
if (pt2.y != offset.y) {
|
||||
offset = pt2;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
int hover = (event.GetPosition().y - offset.y) / rowSize.y;
|
||||
if (hover >= (int) texts.size()) hover = -1;
|
||||
if (hover != hover_item) {
|
||||
hover_item = hover;
|
||||
if (hover >= 0) SetToolTip(texts[hover]);
|
||||
}
|
||||
paintNow();
|
||||
}
|
||||
|
||||
// currently unused events
|
||||
void DropDown::sendDropDownEvent()
|
||||
{
|
||||
selection = hover_item;
|
||||
wxCommandEvent event(wxEVT_COMBOBOX, GetId());
|
||||
event.SetEventObject(this);
|
||||
event.SetInt(selection);
|
||||
event.SetString(GetValue());
|
||||
GetEventHandler()->ProcessEvent(event);
|
||||
}
|
||||
|
||||
void DropDown::OnDismiss()
|
||||
{
|
||||
dismissTime = boost::posix_time::microsec_clock::universal_time();
|
||||
hover_item = -1;
|
||||
wxCommandEvent e(EVT_DISMISS);
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
}
|
111
src/slic3r/GUI/Widgets/DropDown.hpp
Normal file
111
src/slic3r/GUI/Widgets/DropDown.hpp
Normal file
@ -0,0 +1,111 @@
|
||||
#ifndef slic3r_GUI_DropDown_hpp_
|
||||
#define slic3r_GUI_DropDown_hpp_
|
||||
|
||||
#include <wx/stattext.h>
|
||||
#include "../wxExtensions.hpp"
|
||||
#include "StateHandler.hpp"
|
||||
|
||||
#define DD_NO_CHECK_ICON 0x0001
|
||||
#define DD_NO_TEXT 0x0002
|
||||
#define DD_STYLE_MASK 0x0003
|
||||
|
||||
wxDECLARE_EVENT(EVT_DISMISS, wxCommandEvent);
|
||||
|
||||
class DropDown : public wxPopupTransientWindow
|
||||
{
|
||||
std::vector<wxString> & texts;
|
||||
std::vector<wxBitmap> & icons;
|
||||
bool need_sync = false;
|
||||
int selection = -1;
|
||||
int hover_item = -1;
|
||||
|
||||
double radius = 0;
|
||||
bool use_content_width = false;
|
||||
bool align_icon = false;
|
||||
bool text_off = false;
|
||||
|
||||
wxSize textSize;
|
||||
wxSize iconSize;
|
||||
wxSize rowSize;
|
||||
|
||||
StateHandler state_handler;
|
||||
StateColor text_color;
|
||||
StateColor border_color;
|
||||
StateColor selector_border_color;
|
||||
StateColor selector_background_color;
|
||||
ScalableBitmap check_bitmap;
|
||||
|
||||
bool pressedDown = false;
|
||||
boost::posix_time::ptime dismissTime;
|
||||
wxPoint offset; // x not used
|
||||
wxPoint dragStart;
|
||||
|
||||
public:
|
||||
DropDown(std::vector<wxString> &texts,
|
||||
std::vector<wxBitmap> &icons);
|
||||
|
||||
DropDown(wxWindow * parent,
|
||||
std::vector<wxString> &texts,
|
||||
std::vector<wxBitmap> &icons,
|
||||
long style = 0);
|
||||
|
||||
void Create(wxWindow * parent,
|
||||
long style = 0);
|
||||
|
||||
public:
|
||||
void Invalidate(bool clear = false);
|
||||
|
||||
int GetSelection() const { return selection; }
|
||||
|
||||
void SetSelection(int n);
|
||||
|
||||
wxString GetValue() const;
|
||||
void SetValue(const wxString &value);
|
||||
|
||||
public:
|
||||
void SetCornerRadius(double radius);
|
||||
|
||||
void SetBorderColor(StateColor const & color);
|
||||
|
||||
void SetSelectorBorderColor(StateColor const & color);
|
||||
|
||||
void SetTextColor(StateColor const &color);
|
||||
|
||||
void SetSelectorBackgroundColor(StateColor const &color);
|
||||
|
||||
void SetUseContentWidth(bool use);
|
||||
|
||||
void SetAlignIcon(bool align);
|
||||
|
||||
public:
|
||||
void Rescale();
|
||||
|
||||
bool HasDismissLongTime();
|
||||
|
||||
protected:
|
||||
void OnDismiss() override;
|
||||
|
||||
private:
|
||||
void paintEvent(wxPaintEvent& evt);
|
||||
void paintNow();
|
||||
|
||||
void render(wxDC& dc);
|
||||
|
||||
friend class ComboBox;
|
||||
void messureSize();
|
||||
void autoPosition();
|
||||
|
||||
// some useful events
|
||||
void mouseDown(wxMouseEvent& event);
|
||||
void mouseReleased(wxMouseEvent &event);
|
||||
void mouseCaptureLost(wxMouseCaptureLostEvent &event);
|
||||
void mouseMove(wxMouseEvent &event);
|
||||
void mouseWheelMoved(wxMouseEvent &event);
|
||||
|
||||
void sendDropDownEvent();
|
||||
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_DropDown_hpp_
|
124
src/slic3r/GUI/Widgets/Label.cpp
Normal file
124
src/slic3r/GUI/Widgets/Label.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
#include "Label.hpp"
|
||||
#include "StaticBox.hpp"
|
||||
|
||||
wxFont Label::sysFont(int size, bool bold)
|
||||
{
|
||||
//#ifdef __linux__
|
||||
// return wxFont{};
|
||||
//#endif
|
||||
#ifndef __APPLE__
|
||||
size = size * 4 / 5;
|
||||
#endif
|
||||
|
||||
auto face = wxString::FromUTF8("HarmonyOS Sans SC");
|
||||
wxFont font{size, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, bold ? wxFONTWEIGHT_BOLD : wxFONTWEIGHT_NORMAL, false, face};
|
||||
font.SetFaceName(face);
|
||||
if (!font.IsOk()) {
|
||||
font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
||||
if (bold) font.MakeBold();
|
||||
font.SetPointSize(size);
|
||||
}
|
||||
return font;
|
||||
}
|
||||
wxFont Label::Head_24;
|
||||
wxFont Label::Head_20;
|
||||
wxFont Label::Head_18;
|
||||
wxFont Label::Head_16;
|
||||
wxFont Label::Head_15;
|
||||
wxFont Label::Head_14;
|
||||
wxFont Label::Head_13;
|
||||
wxFont Label::Head_12;
|
||||
wxFont Label::Head_10;
|
||||
|
||||
wxFont Label::Body_16;
|
||||
wxFont Label::Body_15;
|
||||
wxFont Label::Body_14;
|
||||
wxFont Label::Body_13;
|
||||
wxFont Label::Body_12;
|
||||
wxFont Label::Body_11;
|
||||
wxFont Label::Body_10;
|
||||
wxFont Label::Body_9;
|
||||
|
||||
void Label::initSysFont()
|
||||
{
|
||||
Head_24 = Label::sysFont(24, true);
|
||||
Head_20 = Label::sysFont(20, true);
|
||||
Head_18 = Label::sysFont(18, true);
|
||||
Head_16 = Label::sysFont(16, true);
|
||||
Head_15 = Label::sysFont(15, true);
|
||||
Head_14 = Label::sysFont(14, true);
|
||||
Head_13 = Label::sysFont(13, true);
|
||||
Head_12 = Label::sysFont(12, true);
|
||||
Head_10 = Label::sysFont(10, true);
|
||||
|
||||
Body_16 = Label::sysFont(16, false);
|
||||
Body_15 = Label::sysFont(15, false);
|
||||
Body_14 = Label::sysFont(14, false);
|
||||
Body_13 = Label::sysFont(13, false);
|
||||
Body_12 = Label::sysFont(12, false);
|
||||
Body_11 = Label::sysFont(11, false);
|
||||
Body_10 = Label::sysFont(10, false);
|
||||
Body_9 = Label::sysFont(9, false);
|
||||
}
|
||||
|
||||
wxSize Label::split_lines(wxDC &dc, int width, const wxString &text, wxString &multiline_text)
|
||||
{
|
||||
multiline_text = text;
|
||||
if (width > 0 && dc.GetTextExtent(text).x > width) {
|
||||
size_t start = 0;
|
||||
while (true) {
|
||||
size_t idx = size_t(-1);
|
||||
for (size_t i = start; i < multiline_text.Len(); i++) {
|
||||
if (multiline_text[i] == ' ') {
|
||||
if (dc.GetTextExtent(multiline_text.SubString(start, i)).x < width)
|
||||
idx = i;
|
||||
else {
|
||||
if (idx == size_t(-1)) idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (idx == size_t(-1)) break;
|
||||
multiline_text[idx] = '\n';
|
||||
start = idx + 1;
|
||||
if (dc.GetTextExtent(multiline_text.Mid(start)).x < width) break;
|
||||
}
|
||||
}
|
||||
return dc.GetMultiLineTextExtent(multiline_text);
|
||||
}
|
||||
|
||||
Label::Label(wxWindow *parent, wxString const &text, long style) : Label(parent, Body_14, text, style) {}
|
||||
|
||||
Label::Label(wxWindow *parent, wxFont const &font, wxString const &text, long style)
|
||||
: wxStaticText(parent, wxID_ANY, text, wxDefaultPosition, wxDefaultSize, style)
|
||||
{
|
||||
this->font = font;
|
||||
SetFont(font);
|
||||
SetBackgroundColour(StaticBox::GetParentBackgroundColor(parent));
|
||||
Bind(wxEVT_ENTER_WINDOW, [this](auto &e) {
|
||||
if (GetWindowStyle() & LB_HYPERLINK) {
|
||||
SetFont(this->font.Underlined());
|
||||
Refresh();
|
||||
}
|
||||
});
|
||||
Bind(wxEVT_LEAVE_WINDOW, [this](auto &e) {
|
||||
SetFont(this->font);
|
||||
Refresh();
|
||||
});
|
||||
}
|
||||
|
||||
void Label::SetWindowStyleFlag(long style)
|
||||
{
|
||||
if (style == GetWindowStyle())
|
||||
return;
|
||||
wxStaticText::SetWindowStyleFlag(style);
|
||||
if (style & LB_HYPERLINK) {
|
||||
this->color = GetForegroundColour();
|
||||
static wxColor clr_url("#00AE42");
|
||||
SetForegroundColour(clr_url);
|
||||
} else {
|
||||
SetForegroundColour(this->color);
|
||||
SetFont(this->font);
|
||||
}
|
||||
Refresh();
|
||||
}
|
49
src/slic3r/GUI/Widgets/Label.hpp
Normal file
49
src/slic3r/GUI/Widgets/Label.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef slic3r_GUI_Label_hpp_
|
||||
#define slic3r_GUI_Label_hpp_
|
||||
|
||||
#include <wx/stattext.h>
|
||||
|
||||
#define LB_HYPERLINK 0x0001
|
||||
|
||||
|
||||
class Label : public wxStaticText
|
||||
{
|
||||
public:
|
||||
Label(wxWindow *parent, wxString const &text = {}, long style = 0);
|
||||
|
||||
Label(wxWindow *parent, wxFont const &font, wxString const &text = {}, long style = 0);
|
||||
|
||||
void SetWindowStyleFlag(long style) override;
|
||||
|
||||
private:
|
||||
wxFont font;
|
||||
wxColour color;
|
||||
|
||||
public:
|
||||
static wxFont Head_24;
|
||||
static wxFont Head_20;
|
||||
static wxFont Head_18;
|
||||
static wxFont Head_16;
|
||||
static wxFont Head_15;
|
||||
static wxFont Head_14;
|
||||
static wxFont Head_13;
|
||||
static wxFont Head_12;
|
||||
static wxFont Head_10;
|
||||
|
||||
static wxFont Body_16;
|
||||
static wxFont Body_15;
|
||||
static wxFont Body_14;
|
||||
static wxFont Body_13;
|
||||
static wxFont Body_12;
|
||||
static wxFont Body_10;
|
||||
static wxFont Body_11;
|
||||
static wxFont Body_9;
|
||||
|
||||
static void initSysFont();
|
||||
|
||||
static wxFont sysFont(int size, bool bold = false);
|
||||
|
||||
static wxSize split_lines(wxDC &dc, int width, const wxString &text, wxString &multiline_text);
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_Label_hpp_
|
323
src/slic3r/GUI/Widgets/SpinInput.cpp
Normal file
323
src/slic3r/GUI/Widgets/SpinInput.cpp
Normal file
@ -0,0 +1,323 @@
|
||||
#include "SpinInput.hpp"
|
||||
#include "Label.hpp"
|
||||
#include "Button.hpp"
|
||||
|
||||
#include <wx/dcgraph.h>
|
||||
|
||||
BEGIN_EVENT_TABLE(SpinInput, wxPanel)
|
||||
|
||||
EVT_KEY_DOWN(SpinInput::keyPressed)
|
||||
EVT_MOUSEWHEEL(SpinInput::mouseWheelMoved)
|
||||
|
||||
EVT_PAINT(SpinInput::paintEvent)
|
||||
|
||||
END_EVENT_TABLE()
|
||||
|
||||
/*
|
||||
* Called by the system of by wxWidgets when the panel needs
|
||||
* to be redrawn. You can also trigger this call by
|
||||
* calling Refresh()/Update().
|
||||
*/
|
||||
|
||||
SpinInput::SpinInput()
|
||||
: label_color(std::make_pair(0x909090, (int) StateColor::Disabled), std::make_pair(0x6B6B6B, (int) StateColor::Normal))
|
||||
, text_color(std::make_pair(0x909090, (int) StateColor::Disabled), std::make_pair(0x262E30, (int) StateColor::Normal))
|
||||
{
|
||||
radius = 0;
|
||||
border_width = 1;
|
||||
border_color = StateColor(std::make_pair(0xDBDBDB, (int) StateColor::Disabled), std::make_pair(0x00AE42, (int) StateColor::Hovered),
|
||||
std::make_pair(0xDBDBDB, (int) StateColor::Normal));
|
||||
background_color = StateColor(std::make_pair(0xF0F0F0, (int) StateColor::Disabled), std::make_pair(*wxWHITE, (int) StateColor::Normal));
|
||||
}
|
||||
|
||||
|
||||
SpinInput::SpinInput(wxWindow *parent,
|
||||
wxString text,
|
||||
wxString label,
|
||||
const wxPoint &pos,
|
||||
const wxSize & size,
|
||||
long style,
|
||||
int min, int max, int initial)
|
||||
: SpinInput()
|
||||
{
|
||||
Create(parent, text, label, pos, size, style, min, max, initial);
|
||||
}
|
||||
|
||||
void SpinInput::Create(wxWindow *parent,
|
||||
wxString text,
|
||||
wxString label,
|
||||
const wxPoint &pos,
|
||||
const wxSize & size,
|
||||
long style,
|
||||
int min, int max, int initial)
|
||||
{
|
||||
StaticBox::Create(parent, wxID_ANY, pos, size);
|
||||
SetFont(Label::Body_12);
|
||||
wxWindow::SetLabel(label);
|
||||
state_handler.attach({&label_color, &text_color});
|
||||
state_handler.update_binds();
|
||||
text_ctrl = new wxTextCtrl(this, wxID_ANY, text, {20, 4}, wxDefaultSize, style | wxBORDER_NONE | wxTE_PROCESS_ENTER, wxTextValidator(wxFILTER_DIGITS));
|
||||
text_ctrl->SetFont(Label::Body_14);
|
||||
text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states()));
|
||||
text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states()));
|
||||
text_ctrl->SetInitialSize(text_ctrl->GetBestSize());
|
||||
state_handler.attach_child(text_ctrl);
|
||||
text_ctrl->Bind(wxEVT_KILL_FOCUS, &SpinInput::onTextLostFocus, this);
|
||||
text_ctrl->Bind(wxEVT_TEXT_ENTER, &SpinInput::onTextEnter, this);
|
||||
text_ctrl->Bind(wxEVT_KEY_DOWN, &SpinInput::keyPressed, this);
|
||||
text_ctrl->Bind(wxEVT_RIGHT_DOWN, [this](auto &e) {}); // disable context menu
|
||||
button_inc = createButton(true);
|
||||
button_dec = createButton(false);
|
||||
delta = 0;
|
||||
timer.Bind(wxEVT_TIMER, &SpinInput::onTimer, this);
|
||||
|
||||
long initialFromText;
|
||||
if (text.ToLong(&initialFromText)) initial = initialFromText;
|
||||
SetRange(min, max);
|
||||
SetValue(initial);
|
||||
messureSize();
|
||||
}
|
||||
|
||||
void SpinInput::SetCornerRadius(double radius)
|
||||
{
|
||||
this->radius = radius;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void SpinInput::SetLabel(const wxString &label)
|
||||
{
|
||||
wxWindow::SetLabel(label);
|
||||
messureSize();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void SpinInput::SetLabelColor(StateColor const &color)
|
||||
{
|
||||
label_color = color;
|
||||
state_handler.update_binds();
|
||||
}
|
||||
|
||||
void SpinInput::SetTextColor(StateColor const &color)
|
||||
{
|
||||
text_color = color;
|
||||
state_handler.update_binds();
|
||||
}
|
||||
|
||||
void SpinInput::SetSize(wxSize const &size)
|
||||
{
|
||||
wxWindow::SetSize(size);
|
||||
Rescale();
|
||||
}
|
||||
|
||||
void SpinInput::SetValue(const wxString &text)
|
||||
{
|
||||
long value;
|
||||
if ( text.ToLong(&value) )
|
||||
SetValue(value);
|
||||
}
|
||||
|
||||
void SpinInput::SetValue(int value)
|
||||
{
|
||||
if (value < min) value = min;
|
||||
else if (value > max) value = max;
|
||||
this->val = value;
|
||||
text_ctrl->SetValue(wxString::FromDouble(value));
|
||||
}
|
||||
|
||||
int SpinInput::GetValue()const
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
void SpinInput::SetRange(int min, int max)
|
||||
{
|
||||
this->min = min;
|
||||
this->max = max;
|
||||
}
|
||||
|
||||
void SpinInput::DoSetToolTipText(wxString const &tip)
|
||||
{
|
||||
wxWindow::DoSetToolTipText(tip);
|
||||
text_ctrl->SetToolTip(tip);
|
||||
}
|
||||
|
||||
void SpinInput::Rescale()
|
||||
{
|
||||
button_inc->Rescale();
|
||||
button_dec->Rescale();
|
||||
messureSize();
|
||||
}
|
||||
|
||||
bool SpinInput::Enable(bool enable)
|
||||
{
|
||||
bool result = text_ctrl->Enable(enable) && wxWindow::Enable(enable);
|
||||
if (result) {
|
||||
wxCommandEvent e(EVT_ENABLE_CHANGED);
|
||||
e.SetEventObject(this);
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states()));
|
||||
text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states()));
|
||||
button_inc->Enable(enable);
|
||||
button_dec->Enable(enable);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void SpinInput::paintEvent(wxPaintEvent& evt)
|
||||
{
|
||||
// depending on your system you may need to look at double-buffered dcs
|
||||
wxPaintDC dc(this);
|
||||
render(dc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we do the actual rendering. I put it in a separate
|
||||
* method so that it can work no matter what type of DC
|
||||
* (e.g. wxPaintDC or wxClientDC) is used.
|
||||
*/
|
||||
void SpinInput::render(wxDC& dc)
|
||||
{
|
||||
StaticBox::render(dc);
|
||||
int states = state_handler.states();
|
||||
wxSize size = GetSize();
|
||||
// draw seperator of buttons
|
||||
wxPoint pt = button_inc->GetPosition();
|
||||
pt.y = size.y / 2;
|
||||
dc.SetPen(wxPen(border_color.defaultColor()));
|
||||
dc.DrawLine(pt, pt + wxSize{button_inc->GetSize().x - 2, 0});
|
||||
// draw label
|
||||
auto label = GetLabel();
|
||||
if (!label.IsEmpty()) {
|
||||
pt.x = size.x - labelSize.x - 5;
|
||||
pt.y = (size.y - labelSize.y) / 2;
|
||||
dc.SetFont(GetFont());
|
||||
dc.SetTextForeground(label_color.colorForStates(states));
|
||||
dc.DrawText(label, pt);
|
||||
}
|
||||
}
|
||||
|
||||
void SpinInput::messureSize()
|
||||
{
|
||||
wxSize size = GetSize();
|
||||
wxSize textSize = text_ctrl->GetSize();
|
||||
int h = textSize.y + 8;
|
||||
if (size.y < h) {
|
||||
size.y = h;
|
||||
SetSize(size);
|
||||
SetMinSize(size);
|
||||
} else {
|
||||
textSize.y = size.y * 14 / 24;
|
||||
}
|
||||
wxSize btnSize = {14, (size.y - 4) / 2};
|
||||
btnSize.x = btnSize.x * btnSize.y / 10;
|
||||
wxClientDC dc(this);
|
||||
labelSize = dc.GetMultiLineTextExtent(GetLabel());
|
||||
textSize.x = size.x - labelSize.x - btnSize.x - 16;
|
||||
text_ctrl->SetSize(textSize);
|
||||
text_ctrl->SetPosition({6 + btnSize.x, (size.y - textSize.y) / 2});
|
||||
button_inc->SetSize(btnSize);
|
||||
button_dec->SetSize(btnSize);
|
||||
button_inc->SetPosition({3, size.y / 2 - btnSize.y - 1});
|
||||
button_dec->SetPosition({3, size.y / 2 + 1});
|
||||
}
|
||||
|
||||
Button *SpinInput::createButton(bool inc)
|
||||
{
|
||||
auto btn = new Button(this, "", inc ? "spin_inc" : "spin_dec", wxBORDER_NONE, 6);
|
||||
btn->SetCornerRadius(0);
|
||||
btn->DisableFocusFromKeyboard();
|
||||
btn->Bind(wxEVT_LEFT_DOWN, [=](auto &e) {
|
||||
delta = inc ? 1 : -1;
|
||||
SetValue(val + delta);
|
||||
text_ctrl->SetFocus();
|
||||
btn->CaptureMouse();
|
||||
delta *= 8;
|
||||
timer.Start(100);
|
||||
sendSpinEvent();
|
||||
});
|
||||
btn->Bind(wxEVT_LEFT_DCLICK, [=](auto &e) {
|
||||
delta = inc ? 1 : -1;
|
||||
btn->CaptureMouse();
|
||||
SetValue(val + delta);
|
||||
sendSpinEvent();
|
||||
});
|
||||
btn->Bind(wxEVT_LEFT_UP, [=](auto &e) {
|
||||
btn->ReleaseMouse();
|
||||
timer.Stop();
|
||||
text_ctrl->SelectAll();
|
||||
delta = 0;
|
||||
});
|
||||
return btn;
|
||||
}
|
||||
|
||||
void SpinInput::onTimer(wxTimerEvent &evnet) {
|
||||
if (delta < -1 || delta > 1) {
|
||||
delta /= 2;
|
||||
return;
|
||||
}
|
||||
SetValue(val + delta);
|
||||
sendSpinEvent();
|
||||
}
|
||||
|
||||
void SpinInput::onTextLostFocus(wxEvent &event)
|
||||
{
|
||||
timer.Stop();
|
||||
for (auto * child : GetChildren())
|
||||
if (auto btn = dynamic_cast<Button*>(child))
|
||||
if (btn->HasCapture())
|
||||
btn->ReleaseMouse();
|
||||
wxCommandEvent e;
|
||||
onTextEnter(e);
|
||||
// pass to outer
|
||||
event.SetId(GetId());
|
||||
ProcessEventLocally(event);
|
||||
e.Skip();
|
||||
}
|
||||
|
||||
void SpinInput::onTextEnter(wxCommandEvent &event)
|
||||
{
|
||||
long value;
|
||||
if (!text_ctrl->GetValue().ToLong(&value)) { value = val; }
|
||||
if (value != val) {
|
||||
SetValue(value);
|
||||
sendSpinEvent();
|
||||
}
|
||||
event.SetId(GetId());
|
||||
ProcessEventLocally(event);
|
||||
}
|
||||
|
||||
void SpinInput::mouseWheelMoved(wxMouseEvent &event)
|
||||
{
|
||||
auto delta = (event.GetWheelRotation() < 0 == event.IsWheelInverted()) ? 1 : -1;
|
||||
SetValue(val + delta);
|
||||
sendSpinEvent();
|
||||
text_ctrl->SetFocus();
|
||||
}
|
||||
|
||||
void SpinInput::keyPressed(wxKeyEvent &event)
|
||||
{
|
||||
switch (event.GetKeyCode()) {
|
||||
case WXK_UP:
|
||||
case WXK_DOWN:
|
||||
long value;
|
||||
if (!text_ctrl->GetValue().ToLong(&value)) { value = val; }
|
||||
if (event.GetKeyCode() == WXK_DOWN && value > min) {
|
||||
--value;
|
||||
} else if (event.GetKeyCode() == WXK_UP && value + 1 < max) {
|
||||
++value;
|
||||
}
|
||||
if (value != val) {
|
||||
SetValue(value);
|
||||
sendSpinEvent();
|
||||
}
|
||||
break;
|
||||
default: event.Skip(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void SpinInput::sendSpinEvent()
|
||||
{
|
||||
wxCommandEvent event(wxEVT_SPINCTRL, GetId());
|
||||
event.SetEventObject(this);
|
||||
GetEventHandler()->ProcessEvent(event);
|
||||
}
|
96
src/slic3r/GUI/Widgets/SpinInput.hpp
Normal file
96
src/slic3r/GUI/Widgets/SpinInput.hpp
Normal file
@ -0,0 +1,96 @@
|
||||
#ifndef slic3r_GUI_SpinInput_hpp_
|
||||
#define slic3r_GUI_SpinInput_hpp_
|
||||
|
||||
#include <wx/textctrl.h>
|
||||
#include "StaticBox.hpp"
|
||||
|
||||
class Button;
|
||||
|
||||
class SpinInput : public wxNavigationEnabled<StaticBox>
|
||||
{
|
||||
wxSize labelSize;
|
||||
StateColor label_color;
|
||||
StateColor text_color;
|
||||
wxTextCtrl * text_ctrl;
|
||||
Button * button_inc;
|
||||
Button * button_dec;
|
||||
wxTimer timer;
|
||||
|
||||
int val;
|
||||
int min;
|
||||
int max;
|
||||
int delta;
|
||||
|
||||
static const int SpinInputWidth = 200;
|
||||
static const int SpinInputHeight = 50;
|
||||
|
||||
public:
|
||||
SpinInput();
|
||||
|
||||
SpinInput(wxWindow * parent,
|
||||
wxString text,
|
||||
wxString label = "",
|
||||
const wxPoint &pos = wxDefaultPosition,
|
||||
const wxSize & size = wxDefaultSize,
|
||||
long style = 0,
|
||||
int min = 0, int max = 100, int initial = 0);
|
||||
|
||||
void Create(wxWindow * parent,
|
||||
wxString text,
|
||||
wxString label = "",
|
||||
const wxPoint &pos = wxDefaultPosition,
|
||||
const wxSize & size = wxDefaultSize,
|
||||
long style = 0,
|
||||
int min = 0,
|
||||
int max = 100,
|
||||
int initial = 0);
|
||||
|
||||
void SetCornerRadius(double radius);
|
||||
|
||||
void SetLabel(const wxString &label) wxOVERRIDE;
|
||||
|
||||
void SetLabelColor(StateColor const &color);
|
||||
|
||||
void SetTextColor(StateColor const &color);
|
||||
|
||||
void SetSize(wxSize const &size);
|
||||
|
||||
void Rescale();
|
||||
|
||||
virtual bool Enable(bool enable = true) wxOVERRIDE;
|
||||
|
||||
wxTextCtrl * GetTextCtrl() { return text_ctrl; }
|
||||
|
||||
void SetValue(const wxString &text);
|
||||
|
||||
void SetValue (int value);
|
||||
|
||||
int GetValue () const;
|
||||
|
||||
void SetRange(int min, int max);
|
||||
|
||||
protected:
|
||||
void DoSetToolTipText(wxString const &tip) override;
|
||||
|
||||
private:
|
||||
void paintEvent(wxPaintEvent& evt);
|
||||
|
||||
void render(wxDC& dc);
|
||||
|
||||
void messureSize();
|
||||
|
||||
Button *createButton(bool inc);
|
||||
|
||||
// some useful events
|
||||
void mouseWheelMoved(wxMouseEvent& event);
|
||||
void keyPressed(wxKeyEvent& event);
|
||||
void onTimer(wxTimerEvent &evnet);
|
||||
void onTextLostFocus(wxEvent &event);
|
||||
void onTextEnter(wxCommandEvent &event);
|
||||
|
||||
void sendSpinEvent();
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_SpinInput_hpp_
|
93
src/slic3r/GUI/Widgets/StateColor.cpp
Normal file
93
src/slic3r/GUI/Widgets/StateColor.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
#include "StateColor.hpp"
|
||||
|
||||
StateColor::StateColor(wxColour const &color) { append(color, 0); }
|
||||
|
||||
StateColor::StateColor(wxString const &color) { append(color, 0); }
|
||||
|
||||
StateColor::StateColor(unsigned long color) { append(color, 0); }
|
||||
|
||||
void StateColor::append(wxColour const & color, int states)
|
||||
{
|
||||
statesList_.push_back(states);
|
||||
colors_.push_back(color);
|
||||
}
|
||||
|
||||
void StateColor::append(wxString const & color, int states)
|
||||
{
|
||||
wxColour c1(color);
|
||||
append(c1, states);
|
||||
}
|
||||
|
||||
void StateColor::append(unsigned long color, int states)
|
||||
{
|
||||
if ((color & 0xff000000) == 0)
|
||||
color |= 0xff000000;
|
||||
wxColour cl; cl.SetRGBA(color & 0xff00ff00 | ((color & 0xff) << 16) | ((color >> 16) & 0xff));
|
||||
append(cl, states);
|
||||
}
|
||||
|
||||
void StateColor::clear()
|
||||
{
|
||||
statesList_.clear();
|
||||
colors_.clear();
|
||||
}
|
||||
|
||||
int StateColor::states() const
|
||||
{
|
||||
int states = 0;
|
||||
for (auto s : statesList_) states |= s;
|
||||
states = (states & 0xffff) | (states >> 16);
|
||||
if (takeFocusedAsHovered_ && (states & Hovered))
|
||||
states |= Focused;
|
||||
return states;
|
||||
}
|
||||
|
||||
wxColour StateColor::defaultColor() {
|
||||
return colorForStates(0);
|
||||
}
|
||||
|
||||
wxColour StateColor::colorForStates(int states)
|
||||
{
|
||||
bool focused = takeFocusedAsHovered_ && (states & Focused);
|
||||
for (int i = 0; i < statesList_.size(); ++i) {
|
||||
int s = statesList_[i];
|
||||
int on = s & 0xffff;
|
||||
int off = s >> 16;
|
||||
if ((on & states) == on && (off & ~states) == off) {
|
||||
return colors_[i];
|
||||
}
|
||||
if (focused && (on & Hovered)) {
|
||||
on |= Focused;
|
||||
on &= ~Hovered;
|
||||
if ((on & states) == on && (off & ~states) == off) {
|
||||
return colors_[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return wxColour(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
int StateColor::colorIndexForStates(int states)
|
||||
{
|
||||
for (int i = 0; i < statesList_.size(); ++i) {
|
||||
int s = statesList_[i];
|
||||
int on = s & 0xffff;
|
||||
int off = s >> 16;
|
||||
if ((on & states) == on && (off & ~states) == off) { return i; }
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool StateColor::setColorForStates(wxColour const &color, int states)
|
||||
{
|
||||
for (int i = 0; i < statesList_.size(); ++i) {
|
||||
if (statesList_[i] == states) {
|
||||
colors_[i] = color;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void StateColor::setTakeFocusedAsHovered(bool set) { takeFocusedAsHovered_ = set; }
|
||||
|
84
src/slic3r/GUI/Widgets/StateColor.hpp
Normal file
84
src/slic3r/GUI/Widgets/StateColor.hpp
Normal file
@ -0,0 +1,84 @@
|
||||
#ifndef slic3r_GUI_StateColor_hpp_
|
||||
#define slic3r_GUI_StateColor_hpp_
|
||||
|
||||
#include <wx/colour.h>
|
||||
|
||||
class StateColor
|
||||
{
|
||||
public:
|
||||
enum State {
|
||||
Normal = 0,
|
||||
Enabled = 1,
|
||||
Checked = 2,
|
||||
Focused = 4,
|
||||
Hovered = 8,
|
||||
Pressed = 16,
|
||||
Disabled = 1 << 16,
|
||||
NotChecked = 2 << 16,
|
||||
NotFocused = 4 << 16,
|
||||
NotHovered = 8 << 16,
|
||||
NotPressed = 16 << 16,
|
||||
};
|
||||
|
||||
public:
|
||||
template<typename ...Colors>
|
||||
StateColor(std::pair<Colors, int>... colors) {
|
||||
fill(colors...);
|
||||
}
|
||||
|
||||
// single color
|
||||
StateColor(wxColour const & color);
|
||||
|
||||
// single color
|
||||
StateColor(wxString const &color);
|
||||
|
||||
// single color
|
||||
StateColor(unsigned long color);
|
||||
|
||||
public:
|
||||
void append(wxColour const & color, int states);
|
||||
|
||||
void append(wxString const &color, int states);
|
||||
|
||||
void append(unsigned long color, int states);
|
||||
|
||||
void clear();
|
||||
|
||||
public:
|
||||
int count() const { return statesList_.size(); }
|
||||
|
||||
int states() const;
|
||||
|
||||
public:
|
||||
wxColour defaultColor();
|
||||
|
||||
wxColour colorForStates(int states);
|
||||
|
||||
int colorIndexForStates(int states);
|
||||
|
||||
bool setColorForStates(wxColour const & color, int states);
|
||||
|
||||
void setTakeFocusedAsHovered(bool set);
|
||||
|
||||
private:
|
||||
template<typename Color, typename ...Colors>
|
||||
void fill(std::pair<Color, int> color, std::pair<Colors, int>... colors) {
|
||||
fillOne(color);
|
||||
fill(colors...);
|
||||
}
|
||||
|
||||
template<typename Color>
|
||||
void fillOne(std::pair<Color, int> color) {
|
||||
append(color.first, color.second);
|
||||
}
|
||||
|
||||
void fill() {
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<int> statesList_;
|
||||
std::vector<wxColour> colors_;
|
||||
bool takeFocusedAsHovered_ = true;
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_StateColor_hpp_
|
122
src/slic3r/GUI/Widgets/StateHandler.cpp
Normal file
122
src/slic3r/GUI/Widgets/StateHandler.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
#include "StateHandler.hpp"
|
||||
|
||||
wxDEFINE_EVENT(EVT_ENABLE_CHANGED, wxCommandEvent);
|
||||
|
||||
StateHandler::StateHandler(wxWindow * owner)
|
||||
: owner_(owner)
|
||||
{
|
||||
owner_->PushEventHandler(this);
|
||||
if (owner->IsEnabled())
|
||||
states_ |= Enabled;
|
||||
if (owner->HasFocus())
|
||||
states_ |= Focused;
|
||||
}
|
||||
|
||||
StateHandler::~StateHandler() { owner_->RemoveEventHandler(this); }
|
||||
|
||||
void StateHandler::attach(StateColor const &color)
|
||||
{
|
||||
colors_.push_back(&color);
|
||||
}
|
||||
|
||||
void StateHandler::attach(std::vector<StateColor const *> const & colors)
|
||||
{
|
||||
colors_.insert(colors_.end(), colors.begin(), colors.end());
|
||||
}
|
||||
|
||||
void StateHandler::attach_child(wxWindow *child)
|
||||
{
|
||||
auto ch = new StateHandler(this, child);
|
||||
children_.emplace_back(ch);
|
||||
ch->update_binds();
|
||||
states2_ |= ch->states();
|
||||
}
|
||||
|
||||
void StateHandler::remove_child(wxWindow *child)
|
||||
{
|
||||
children_.erase(std::remove_if(children_.begin(), children_.end(),
|
||||
[child](auto &c) { return c->owner_ == child; }), children_.end());
|
||||
states2_ = 0;
|
||||
for (auto & c : children_) states2_ |= c->states();
|
||||
}
|
||||
|
||||
void StateHandler::update_binds()
|
||||
{
|
||||
int bind_states = parent_ ? (parent_->bind_states_ & ~Enabled) : 0;
|
||||
for (auto c : colors_) {
|
||||
bind_states |= c->states();
|
||||
}
|
||||
bind_states = bind_states | (bind_states >> 16);
|
||||
int diff = bind_states ^ bind_states_;
|
||||
State states[] = {Enabled, Checked, Focused, Hovered, Pressed};
|
||||
wxEventType events[] = {EVT_ENABLE_CHANGED, wxEVT_CHECKBOX, wxEVT_SET_FOCUS, wxEVT_ENTER_WINDOW, wxEVT_LEFT_DOWN};
|
||||
wxEventType events2[] = {{0}, {0}, wxEVT_KILL_FOCUS, wxEVT_LEAVE_WINDOW, wxEVT_LEFT_UP};
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
int s = states[i];
|
||||
if (diff & s) {
|
||||
if (bind_states & s) {
|
||||
Bind(events[i], &StateHandler::changed, this);
|
||||
if (events2[i])
|
||||
Bind(events2[i], &StateHandler::changed, this);
|
||||
} else {
|
||||
Unbind(events[i], &StateHandler::changed, this);
|
||||
if (events2[i])
|
||||
owner_->Unbind(events2[i], &StateHandler::changed, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
bind_states_ = bind_states;
|
||||
for (auto &c : children_) c->update_binds();
|
||||
}
|
||||
|
||||
StateHandler::StateHandler(StateHandler *parent, wxWindow *owner)
|
||||
: StateHandler(owner)
|
||||
{
|
||||
states_ &= ~Enabled;
|
||||
parent_ = parent;
|
||||
}
|
||||
|
||||
void StateHandler::changed(wxEvent &event)
|
||||
{
|
||||
event.Skip();
|
||||
wxEventType events[] = {EVT_ENABLE_CHANGED, wxEVT_CHECKBOX, wxEVT_SET_FOCUS, wxEVT_ENTER_WINDOW, wxEVT_LEFT_DOWN};
|
||||
wxEventType events2[] = {{0}, {0}, wxEVT_KILL_FOCUS, wxEVT_LEAVE_WINDOW, wxEVT_LEFT_UP};
|
||||
int old = states_;
|
||||
// some events are from another window (ex: text_ctrl of TextInput), save state in states2_ to avoid conflicts
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
if (events2[i]) {
|
||||
if (event.GetEventType() == events[i]) {
|
||||
states_ |= 1 << i;
|
||||
break;
|
||||
} else if (event.GetEventType() == events2[i]) {
|
||||
states_ &= ~(1 << i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (event.GetEventType() == events[i]) {
|
||||
states_ ^= (1 << i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (old != states_ && (old | states2_) != (states_ | states2_)) {
|
||||
if (parent_)
|
||||
parent_->changed(states_ | states2_);
|
||||
else
|
||||
owner_->Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void StateHandler::changed(int)
|
||||
{
|
||||
int old = states2_;
|
||||
states2_ = 0;
|
||||
for (auto &c : children_) states2_ |= c->states();
|
||||
if (old != states2_ && (old | states_) != (states_ | states2_)) {
|
||||
if (parent_)
|
||||
parent_->changed(states_ | states2_);
|
||||
else
|
||||
owner_->Refresh();
|
||||
}
|
||||
}
|
61
src/slic3r/GUI/Widgets/StateHandler.hpp
Normal file
61
src/slic3r/GUI/Widgets/StateHandler.hpp
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef slic3r_GUI_StateHandler_hpp_
|
||||
#define slic3r_GUI_StateHandler_hpp_
|
||||
|
||||
#include <wx/event.h>
|
||||
|
||||
#include "StateColor.hpp"
|
||||
|
||||
wxDECLARE_EVENT(EVT_ENABLE_CHANGED, wxCommandEvent);
|
||||
|
||||
class StateHandler : public wxEvtHandler
|
||||
{
|
||||
public:
|
||||
enum State {
|
||||
Enabled = 1,
|
||||
Checked = 2,
|
||||
Focused = 4,
|
||||
Hovered = 8,
|
||||
Pressed = 16,
|
||||
Disabled = 1 << 16,
|
||||
NotChecked = 2 << 16,
|
||||
NotFocused = 4 << 16,
|
||||
NotHovered = 8 << 16,
|
||||
NotPressed = 16 << 16,
|
||||
};
|
||||
|
||||
public:
|
||||
StateHandler(wxWindow * owner);
|
||||
|
||||
~StateHandler();
|
||||
|
||||
public:
|
||||
void attach(StateColor const & color);
|
||||
|
||||
void attach(std::vector<StateColor const *> const & colors);
|
||||
|
||||
void attach_child(wxWindow *child);
|
||||
|
||||
void remove_child(wxWindow *child);
|
||||
|
||||
void update_binds();
|
||||
|
||||
int states() const { return states_ | states2_; }
|
||||
|
||||
private:
|
||||
StateHandler(StateHandler * parent, wxWindow *owner);
|
||||
|
||||
void changed(wxEvent &event);
|
||||
|
||||
void changed(int state2);
|
||||
|
||||
private:
|
||||
wxWindow * owner_;
|
||||
std::vector<StateColor const *> colors_;
|
||||
int bind_states_ = 0;
|
||||
int states_ = 0;
|
||||
int states2_ = 0; // from children
|
||||
std::vector<std::unique_ptr<StateHandler>> children_;
|
||||
StateHandler * parent_ = nullptr;
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_StateHandler_hpp_
|
214
src/slic3r/GUI/Widgets/StaticBox.cpp
Normal file
214
src/slic3r/GUI/Widgets/StaticBox.cpp
Normal file
@ -0,0 +1,214 @@
|
||||
#include "StaticBox.hpp"
|
||||
#include "../GUI.hpp"
|
||||
#include <wx/dcgraph.h>
|
||||
|
||||
BEGIN_EVENT_TABLE(StaticBox, wxWindow)
|
||||
|
||||
// catch paint events
|
||||
//EVT_ERASE_BACKGROUND(StaticBox::eraseEvent)
|
||||
EVT_PAINT(StaticBox::paintEvent)
|
||||
|
||||
END_EVENT_TABLE()
|
||||
|
||||
/*
|
||||
* Called by the system of by wxWidgets when the panel needs
|
||||
* to be redrawn. You can also trigger this call by
|
||||
* calling Refresh()/Update().
|
||||
*/
|
||||
|
||||
StaticBox::StaticBox()
|
||||
: state_handler(this)
|
||||
, radius(8)
|
||||
{
|
||||
border_color = StateColor(
|
||||
std::make_pair(*wxLIGHT_GREY, (int) StateColor::Disabled),
|
||||
std::make_pair(0x303A3C, (int) StateColor::Normal));
|
||||
}
|
||||
|
||||
StaticBox::StaticBox(wxWindow* parent,
|
||||
wxWindowID id,
|
||||
const wxPoint & pos,
|
||||
const wxSize & size, long style)
|
||||
: StaticBox()
|
||||
{
|
||||
Create(parent, id, pos, size, style);
|
||||
}
|
||||
|
||||
bool StaticBox::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
|
||||
{
|
||||
if (style & wxBORDER_NONE)
|
||||
border_width = 0;
|
||||
wxWindow::Create(parent, id, pos, size, style);
|
||||
state_handler.attach({&border_color, &background_color, &background_color2});
|
||||
state_handler.update_binds();
|
||||
SetBackgroundColour(GetParentBackgroundColor(parent));
|
||||
return true;
|
||||
}
|
||||
|
||||
void StaticBox::SetCornerRadius(double radius)
|
||||
{
|
||||
this->radius = radius;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void StaticBox::SetBorderWidth(int width)
|
||||
{
|
||||
border_width = width;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void StaticBox::SetBorderColor(StateColor const &color)
|
||||
{
|
||||
border_color = color;
|
||||
state_handler.update_binds();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void StaticBox::SetBorderColorNormal(wxColor const &color)
|
||||
{
|
||||
border_color.setColorForStates(color, 0);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void StaticBox::SetBackgroundColor(StateColor const &color)
|
||||
{
|
||||
background_color = color;
|
||||
state_handler.update_binds();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void StaticBox::SetBackgroundColorNormal(wxColor const &color)
|
||||
{
|
||||
background_color.setColorForStates(color, 0);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void StaticBox::SetBackgroundColor2(StateColor const &color)
|
||||
{
|
||||
background_color2 = color;
|
||||
state_handler.update_binds();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
wxColor StaticBox::GetParentBackgroundColor(wxWindow* parent)
|
||||
{
|
||||
if (auto box = dynamic_cast<StaticBox*>(parent)) {
|
||||
if (box->background_color.count() > 0) {
|
||||
if (box->background_color2.count() == 0)
|
||||
return box->background_color.defaultColor();
|
||||
auto s = box->background_color.defaultColor();
|
||||
auto e = box->background_color2.defaultColor();
|
||||
int r = (s.Red() + e.Red()) / 2;
|
||||
int g = (s.Green() + e.Green()) / 2;
|
||||
int b = (s.Blue() + e.Blue()) / 2;
|
||||
return wxColor(r, g, b);
|
||||
}
|
||||
}
|
||||
if (parent)
|
||||
return parent->GetBackgroundColour();
|
||||
return *wxWHITE;
|
||||
}
|
||||
|
||||
void StaticBox::eraseEvent(wxEraseEvent& evt)
|
||||
{
|
||||
// for transparent background, but not work
|
||||
#ifdef __WXMSW__
|
||||
wxDC *dc = evt.GetDC();
|
||||
wxSize size = GetSize();
|
||||
wxClientDC dc2(GetParent());
|
||||
dc->Blit({0, 0}, size, &dc2, GetPosition());
|
||||
#endif
|
||||
}
|
||||
|
||||
void StaticBox::paintEvent(wxPaintEvent& evt)
|
||||
{
|
||||
// depending on your system you may need to look at double-buffered dcs
|
||||
wxPaintDC dc(this);
|
||||
render(dc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we do the actual rendering. I put it in a separate
|
||||
* method so that it can work no matter what type of DC
|
||||
* (e.g. wxPaintDC or wxClientDC) is used.
|
||||
*/
|
||||
void StaticBox::render(wxDC& dc)
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
if (radius == 0) {
|
||||
doRender(dc);
|
||||
return;
|
||||
}
|
||||
|
||||
wxSize size = GetSize();
|
||||
wxMemoryDC memdc;
|
||||
wxBitmap bmp(size.x, size.y);
|
||||
memdc.SelectObject(bmp);
|
||||
//memdc.Blit({0, 0}, size, &dc, {0, 0});
|
||||
memdc.SetBackground(wxBrush(GetBackgroundColour()));
|
||||
memdc.Clear();
|
||||
{
|
||||
wxGCDC dc2(memdc);
|
||||
doRender(dc2);
|
||||
}
|
||||
|
||||
memdc.SelectObject(wxNullBitmap);
|
||||
dc.DrawBitmap(bmp, 0, 0);
|
||||
#else
|
||||
doRender(dc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void StaticBox::doRender(wxDC& dc)
|
||||
{
|
||||
wxSize size = GetSize();
|
||||
int states = state_handler.states();
|
||||
if (background_color2.count() == 0) {
|
||||
if ((border_width && border_color.count() > 0) || background_color.count() > 0) {
|
||||
wxRect rc(0, 0, size.x, size.y);
|
||||
if (border_width && border_color.count() > 0) {
|
||||
if (dc.GetContentScaleFactor() == 1.0) {
|
||||
int d = floor(border_width / 2.0);
|
||||
int d2 = floor(border_width - 1);
|
||||
rc.x += d;
|
||||
rc.width -= d2;
|
||||
rc.y += d;
|
||||
rc.height -= d2;
|
||||
} else {
|
||||
int d = 1;
|
||||
rc.x += d;
|
||||
rc.width -= d;
|
||||
rc.y += d;
|
||||
rc.height -= d;
|
||||
}
|
||||
dc.SetPen(wxPen(border_color.colorForStates(states), border_width));
|
||||
} else {
|
||||
dc.SetPen(wxPen(background_color.colorForStates(states)));
|
||||
}
|
||||
if (background_color.count() > 0)
|
||||
dc.SetBrush(wxBrush(background_color.colorForStates(states)));
|
||||
else
|
||||
dc.SetBrush(wxBrush(GetBackgroundColour()));
|
||||
if (radius == 0) {
|
||||
dc.DrawRectangle(rc);
|
||||
}
|
||||
else {
|
||||
dc.DrawRoundedRectangle(rc, radius - border_width);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
wxColor start = background_color.colorForStates(states);
|
||||
wxColor stop = background_color2.colorForStates(states);
|
||||
int r = start.Red(), g = start.Green(), b = start.Blue();
|
||||
int dr = (int) stop.Red() - r, dg = (int) stop.Green() - g, db = (int) stop.Blue() - b;
|
||||
int lr = 0, lg = 0, lb = 0;
|
||||
for (int y = 0; y < size.y; ++y) {
|
||||
dc.SetPen(wxPen(wxColor(r, g, b)));
|
||||
dc.DrawLine(0, y, size.x, y);
|
||||
lr += dr; while (lr >= size.y) { ++r, lr -= size.y; } while (lr <= -size.y) { --r, lr += size.y; }
|
||||
lg += dg; while (lg >= size.y) { ++g, lg -= size.y; } while (lg <= -size.y) { --g, lg += size.y; }
|
||||
lb += db; while (lb >= size.y) { ++b, lb -= size.y; } while (lb <= -size.y) { --b, lb += size.y; }
|
||||
}
|
||||
}
|
||||
}
|
62
src/slic3r/GUI/Widgets/StaticBox.hpp
Normal file
62
src/slic3r/GUI/Widgets/StaticBox.hpp
Normal file
@ -0,0 +1,62 @@
|
||||
#ifndef slic3r_GUI_StaticBox_hpp_
|
||||
#define slic3r_GUI_StaticBox_hpp_
|
||||
|
||||
#include "../wxExtensions.hpp"
|
||||
#include "StateHandler.hpp"
|
||||
|
||||
#include <wx/window.h>
|
||||
|
||||
class StaticBox : public wxWindow
|
||||
{
|
||||
public:
|
||||
StaticBox();
|
||||
|
||||
StaticBox(wxWindow* parent,
|
||||
wxWindowID id = wxID_ANY,
|
||||
const wxPoint & pos = wxDefaultPosition,
|
||||
const wxSize & size = wxDefaultSize,
|
||||
long style = 0);
|
||||
|
||||
bool Create(wxWindow* parent,
|
||||
wxWindowID id = wxID_ANY,
|
||||
const wxPoint & pos = wxDefaultPosition,
|
||||
const wxSize & size = wxDefaultSize,
|
||||
long style = 0);
|
||||
|
||||
void SetCornerRadius(double radius);
|
||||
|
||||
void SetBorderWidth(int width);
|
||||
|
||||
void SetBorderColor(StateColor const & color);
|
||||
|
||||
void SetBorderColorNormal(wxColor const &color);
|
||||
|
||||
void SetBackgroundColor(StateColor const &color);
|
||||
|
||||
void SetBackgroundColorNormal(wxColor const &color);
|
||||
|
||||
void SetBackgroundColor2(StateColor const &color);
|
||||
|
||||
static wxColor GetParentBackgroundColor(wxWindow * parent);
|
||||
|
||||
protected:
|
||||
void eraseEvent(wxEraseEvent& evt);
|
||||
|
||||
void paintEvent(wxPaintEvent& evt);
|
||||
|
||||
void render(wxDC& dc);
|
||||
|
||||
virtual void doRender(wxDC& dc);
|
||||
|
||||
protected:
|
||||
double radius;
|
||||
int border_width = 1;
|
||||
StateHandler state_handler;
|
||||
StateColor border_color;
|
||||
StateColor background_color;
|
||||
StateColor background_color2;
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_StaticBox_hpp_
|
134
src/slic3r/GUI/Widgets/SwitchButton.cpp
Normal file
134
src/slic3r/GUI/Widgets/SwitchButton.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
#include "SwitchButton.hpp"
|
||||
#include "Label.hpp"
|
||||
#include "StaticBox.hpp"
|
||||
|
||||
#include "../wxExtensions.hpp"
|
||||
#include "../Utils/MacDarkMode.hpp"
|
||||
|
||||
#include <wx/dcgraph.h>
|
||||
|
||||
SwitchButton::SwitchButton(wxWindow* parent, wxWindowID id)
|
||||
: wxBitmapToggleButton(parent, id, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE | wxBU_EXACTFIT)
|
||||
, m_on(this, "toggle_on", 16)
|
||||
, m_off(this, "toggle_off", 16)
|
||||
, text_color(std::pair{*wxWHITE, (int) StateColor::Checked}, std::pair{0x6B6B6B, (int) StateColor::Normal})
|
||||
, track_color(0xD9D9D9)
|
||||
, thumb_color(std::pair{0x00AE42, (int) StateColor::Checked}, std::pair{0xD9D9D9, (int) StateColor::Normal})
|
||||
{
|
||||
SetBackgroundColour(StaticBox::GetParentBackgroundColor(parent));
|
||||
Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { update(); e.Skip(); });
|
||||
SetFont(Label::Body_12);
|
||||
Rescale();
|
||||
}
|
||||
|
||||
void SwitchButton::SetLabels(wxString const& lbl_on, wxString const& lbl_off)
|
||||
{
|
||||
labels[0] = lbl_on;
|
||||
labels[1] = lbl_off;
|
||||
Rescale();
|
||||
}
|
||||
|
||||
void SwitchButton::SetTextColor(StateColor const& color)
|
||||
{
|
||||
text_color = color;
|
||||
}
|
||||
|
||||
void SwitchButton::SetTrackColor(StateColor const& color)
|
||||
{
|
||||
track_color = color;
|
||||
}
|
||||
|
||||
void SwitchButton::SetThumbColor(StateColor const& color)
|
||||
{
|
||||
thumb_color = color;
|
||||
}
|
||||
|
||||
void SwitchButton::SetValue(bool value)
|
||||
{
|
||||
if (value != GetValue())
|
||||
wxBitmapToggleButton::SetValue(value);
|
||||
update();
|
||||
}
|
||||
|
||||
void SwitchButton::Rescale()
|
||||
{
|
||||
if (labels[0].IsEmpty()) {
|
||||
m_on.msw_rescale();
|
||||
m_off.msw_rescale();
|
||||
}
|
||||
else {
|
||||
#ifdef __WXOSX__
|
||||
auto scale = Slic3r::GUI::mac_max_scaling_factor();
|
||||
int BS = (int) scale;
|
||||
#else
|
||||
constexpr int BS = 1;
|
||||
#endif
|
||||
wxSize thumbSize;
|
||||
wxSize trackSize;
|
||||
wxClientDC dc(this);
|
||||
#ifdef __WXOSX__
|
||||
dc.SetFont(dc.GetFont().Scaled(scale));
|
||||
#endif
|
||||
wxSize textSize[2];
|
||||
{
|
||||
textSize[0] = dc.GetTextExtent(labels[0]);
|
||||
textSize[1] = dc.GetTextExtent(labels[1]);
|
||||
}
|
||||
{
|
||||
thumbSize = textSize[0];
|
||||
auto size = textSize[1];
|
||||
if (size.x > thumbSize.x) thumbSize.x = size.x;
|
||||
else size.x = thumbSize.x;
|
||||
thumbSize.x += BS * 12;
|
||||
thumbSize.y += BS * 6;
|
||||
trackSize.x = thumbSize.x + size.x + BS * 10;
|
||||
trackSize.y = thumbSize.y + BS * 2;
|
||||
auto maxWidth = GetMaxWidth();
|
||||
#ifdef __WXOSX__
|
||||
maxWidth *= scale;
|
||||
#endif
|
||||
if (trackSize.x > maxWidth) {
|
||||
thumbSize.x -= (trackSize.x - maxWidth) / 2;
|
||||
trackSize.x = maxWidth;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
wxMemoryDC memdc(&dc);
|
||||
wxBitmap bmp(trackSize.x, trackSize.y);
|
||||
memdc.SelectObject(bmp);
|
||||
memdc.SetBackground(wxBrush(GetBackgroundColour()));
|
||||
memdc.Clear();
|
||||
memdc.SetFont(dc.GetFont());
|
||||
auto state = i == 0 ? StateColor::Enabled : (StateColor::Checked | StateColor::Enabled);
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
wxGCDC dc2(memdc);
|
||||
#else
|
||||
wxDC &dc2(memdc);
|
||||
#endif
|
||||
dc2.SetBrush(wxBrush(track_color.colorForStates(state)));
|
||||
dc2.SetPen(wxPen(track_color.colorForStates(state)));
|
||||
dc2.DrawRoundedRectangle(wxRect({0, 0}, trackSize), trackSize.y / 2);
|
||||
dc2.SetBrush(wxBrush(thumb_color.colorForStates(StateColor::Checked | StateColor::Enabled)));
|
||||
dc2.SetPen(wxPen(thumb_color.colorForStates(StateColor::Checked | StateColor::Enabled)));
|
||||
dc2.DrawRoundedRectangle(wxRect({ i == 0 ? BS : (trackSize.x - thumbSize.x - BS), BS}, thumbSize), thumbSize.y / 2);
|
||||
}
|
||||
memdc.SetTextForeground(text_color.colorForStates(state ^ StateColor::Checked));
|
||||
memdc.DrawText(labels[0], {BS + (thumbSize.x - textSize[0].x) / 2, BS + (thumbSize.y - textSize[0].y) / 2});
|
||||
memdc.SetTextForeground(text_color.colorForStates(state));
|
||||
memdc.DrawText(labels[1], {trackSize.x - thumbSize.x - BS + (thumbSize.x - textSize[1].x) / 2, BS + (thumbSize.y - textSize[1].y) / 2});
|
||||
memdc.SelectObject(wxNullBitmap);
|
||||
#ifdef __WXOSX__
|
||||
bmp = wxBitmap(bmp.ConvertToImage(), -1, scale);
|
||||
#endif
|
||||
(i == 0 ? m_off : m_on).bmp() = bmp;
|
||||
}
|
||||
}
|
||||
SetSize(m_on.GetBmpSize());
|
||||
update();
|
||||
}
|
||||
|
||||
void SwitchButton::update()
|
||||
{
|
||||
SetBitmap((GetValue() ? m_on : m_off).bmp());
|
||||
}
|
40
src/slic3r/GUI/Widgets/SwitchButton.hpp
Normal file
40
src/slic3r/GUI/Widgets/SwitchButton.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef slic3r_GUI_SwitchButton_hpp_
|
||||
#define slic3r_GUI_SwitchButton_hpp_
|
||||
|
||||
#include "../wxExtensions.hpp"
|
||||
#include "StateColor.hpp"
|
||||
|
||||
#include <wx/tglbtn.h>
|
||||
|
||||
class SwitchButton : public wxBitmapToggleButton
|
||||
{
|
||||
public:
|
||||
SwitchButton(wxWindow * parent = NULL, wxWindowID id = wxID_ANY);
|
||||
|
||||
public:
|
||||
void SetLabels(wxString const & lbl_on, wxString const & lbl_off);
|
||||
|
||||
void SetTextColor(StateColor const &color);
|
||||
|
||||
void SetTrackColor(StateColor const &color);
|
||||
|
||||
void SetThumbColor(StateColor const &color);
|
||||
|
||||
void SetValue(bool value) override;
|
||||
|
||||
void Rescale();
|
||||
|
||||
private:
|
||||
void update();
|
||||
|
||||
private:
|
||||
ScalableBitmap m_on;
|
||||
ScalableBitmap m_off;
|
||||
|
||||
wxString labels[2];
|
||||
StateColor text_color;
|
||||
StateColor track_color;
|
||||
StateColor thumb_color;
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_SwitchButton_hpp_
|
230
src/slic3r/GUI/Widgets/TextInput.cpp
Normal file
230
src/slic3r/GUI/Widgets/TextInput.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
#include "TextInput.hpp"
|
||||
#include "Label.hpp"
|
||||
|
||||
#include <wx/dcgraph.h>
|
||||
|
||||
BEGIN_EVENT_TABLE(TextInput, wxPanel)
|
||||
|
||||
EVT_PAINT(TextInput::paintEvent)
|
||||
|
||||
END_EVENT_TABLE()
|
||||
|
||||
/*
|
||||
* Called by the system of by wxWidgets when the panel needs
|
||||
* to be redrawn. You can also trigger this call by
|
||||
* calling Refresh()/Update().
|
||||
*/
|
||||
|
||||
TextInput::TextInput()
|
||||
: label_color(std::make_pair(0x909090, (int) StateColor::Disabled),
|
||||
std::make_pair(0x6B6B6B, (int) StateColor::Normal))
|
||||
, text_color(std::make_pair(0x909090, (int) StateColor::Disabled),
|
||||
std::make_pair(0x262E30, (int) StateColor::Normal))
|
||||
{
|
||||
radius = 0;
|
||||
border_width = 1;
|
||||
border_color = StateColor(std::make_pair(0xDBDBDB, (int) StateColor::Disabled), std::make_pair(0x00AE42, (int) StateColor::Hovered),
|
||||
std::make_pair(0xDBDBDB, (int) StateColor::Normal));
|
||||
background_color = StateColor(std::make_pair(0xF0F0F0, (int) StateColor::Disabled), std::make_pair(*wxWHITE, (int) StateColor::Normal));
|
||||
SetFont(Label::Body_12);
|
||||
}
|
||||
|
||||
TextInput::TextInput(wxWindow * parent,
|
||||
wxString text,
|
||||
wxString label,
|
||||
wxString icon,
|
||||
const wxPoint &pos,
|
||||
const wxSize & size,
|
||||
long style)
|
||||
: TextInput()
|
||||
{
|
||||
Create(parent, text, label, icon, pos, size, style);
|
||||
}
|
||||
|
||||
void TextInput::Create(wxWindow * parent,
|
||||
wxString text,
|
||||
wxString label,
|
||||
wxString icon,
|
||||
const wxPoint &pos,
|
||||
const wxSize & size,
|
||||
long style)
|
||||
{
|
||||
text_ctrl = nullptr;
|
||||
StaticBox::Create(parent, wxID_ANY, pos, size, style);
|
||||
wxWindow::SetLabel(label);
|
||||
style &= ~wxRIGHT;
|
||||
state_handler.attach({&label_color, & text_color});
|
||||
state_handler.update_binds();
|
||||
text_ctrl = new wxTextCtrl(this, wxID_ANY, text, {4, 4}, wxDefaultSize, style | wxBORDER_NONE | wxTE_PROCESS_ENTER);
|
||||
text_ctrl->SetFont(Label::Body_14);
|
||||
text_ctrl->SetInitialSize(text_ctrl->GetBestSize());
|
||||
text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states()));
|
||||
text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states()));
|
||||
state_handler.attach_child(text_ctrl);
|
||||
text_ctrl->Bind(wxEVT_KILL_FOCUS, [this](auto &e) {
|
||||
OnEdit();
|
||||
e.SetId(GetId());
|
||||
ProcessEventLocally(e);
|
||||
e.Skip();
|
||||
});
|
||||
text_ctrl->Bind(wxEVT_TEXT_ENTER, [this](auto &e) {
|
||||
OnEdit();
|
||||
e.SetId(GetId());
|
||||
ProcessEventLocally(e);
|
||||
});
|
||||
text_ctrl->Bind(wxEVT_RIGHT_DOWN, [this](auto &e) {}); // disable context menu
|
||||
if (!icon.IsEmpty()) {
|
||||
this->icon = ScalableBitmap(this, icon.ToStdString(), 16);
|
||||
}
|
||||
messureSize();
|
||||
}
|
||||
|
||||
void TextInput::SetCornerRadius(double radius)
|
||||
{
|
||||
this->radius = radius;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void TextInput::SetLabel(const wxString& label)
|
||||
{
|
||||
wxWindow::SetLabel(label);
|
||||
messureSize();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void TextInput::SetIcon(const wxBitmap &icon)
|
||||
{
|
||||
this->icon.bmp() = icon;
|
||||
Rescale();
|
||||
}
|
||||
|
||||
void TextInput::SetLabelColor(StateColor const &color)
|
||||
{
|
||||
label_color = color;
|
||||
state_handler.update_binds();
|
||||
}
|
||||
|
||||
void TextInput::SetTextColor(StateColor const& color)
|
||||
{
|
||||
text_color= color;
|
||||
state_handler.update_binds();
|
||||
}
|
||||
|
||||
void TextInput::Rescale()
|
||||
{
|
||||
if (!this->icon.name().empty())
|
||||
this->icon.msw_rescale();
|
||||
messureSize();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
bool TextInput::Enable(bool enable)
|
||||
{
|
||||
bool result = text_ctrl->Enable(enable) && wxWindow::Enable(enable);
|
||||
if (result) {
|
||||
wxCommandEvent e(EVT_ENABLE_CHANGED);
|
||||
e.SetEventObject(this);
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states()));
|
||||
text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void TextInput::SetMinSize(const wxSize& size)
|
||||
{
|
||||
wxSize size2 = size;
|
||||
if (size2.y < 0) {
|
||||
#ifdef __WXMAC__
|
||||
if (GetPeer()) // peer is not ready in Create on mac
|
||||
#endif
|
||||
size2.y = GetSize().y;
|
||||
}
|
||||
wxWindow::SetMinSize(size2);
|
||||
}
|
||||
|
||||
void TextInput::DoSetSize(int x, int y, int width, int height, int sizeFlags)
|
||||
{
|
||||
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
|
||||
if (sizeFlags & wxSIZE_USE_EXISTING) return;
|
||||
wxSize size = GetSize();
|
||||
wxPoint textPos = {5, 0};
|
||||
if (this->icon.bmp().IsOk()) {
|
||||
wxSize szIcon = this->icon.GetBmpSize();
|
||||
textPos.x += szIcon.x;
|
||||
}
|
||||
bool align_right = GetWindowStyle() & wxRIGHT;
|
||||
if (align_right)
|
||||
textPos.x += labelSize.x;
|
||||
if (text_ctrl) {
|
||||
wxSize textSize = text_ctrl->GetSize();
|
||||
textSize.x = size.x - textPos.x - labelSize.x - 10;
|
||||
text_ctrl->SetSize(textSize);
|
||||
text_ctrl->SetPosition({textPos.x, (size.y - textSize.y) / 2});
|
||||
}
|
||||
}
|
||||
|
||||
void TextInput::DoSetToolTipText(wxString const &tip)
|
||||
{
|
||||
wxWindow::DoSetToolTipText(tip);
|
||||
text_ctrl->SetToolTip(tip);
|
||||
}
|
||||
|
||||
void TextInput::paintEvent(wxPaintEvent &evt)
|
||||
{
|
||||
// depending on your system you may need to look at double-buffered dcs
|
||||
wxPaintDC dc(this);
|
||||
render(dc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we do the actual rendering. I put it in a separate
|
||||
* method so that it can work no matter what type of DC
|
||||
* (e.g. wxPaintDC or wxClientDC) is used.
|
||||
*/
|
||||
void TextInput::render(wxDC& dc)
|
||||
{
|
||||
StaticBox::render(dc);
|
||||
int states = state_handler.states();
|
||||
wxSize size = GetSize();
|
||||
bool align_right = GetWindowStyle() & wxRIGHT;
|
||||
// start draw
|
||||
wxPoint pt = {5, 0};
|
||||
if (icon.bmp().IsOk()) {
|
||||
wxSize szIcon = icon.GetBmpSize();
|
||||
pt.y = (size.y - szIcon.y) / 2;
|
||||
dc.DrawBitmap(icon.bmp(), pt);
|
||||
pt.x += szIcon.x + 0;
|
||||
}
|
||||
auto text = wxWindow::GetLabel();
|
||||
if (!text.IsEmpty()) {
|
||||
wxSize textSize = text_ctrl->GetSize();
|
||||
if (align_right) {
|
||||
if (pt.x + labelSize.x > size.x)
|
||||
text = wxControl::Ellipsize(text, dc, wxELLIPSIZE_END, size.x - pt.x);
|
||||
pt.y = (size.y - labelSize.y) / 2;
|
||||
} else {
|
||||
pt.x += textSize.x;
|
||||
pt.y = (size.y + textSize.y) / 2 - labelSize.y;
|
||||
}
|
||||
dc.SetTextForeground(label_color.colorForStates(states));
|
||||
dc.SetFont(GetFont());
|
||||
dc.DrawText(text, pt);
|
||||
}
|
||||
}
|
||||
|
||||
void TextInput::messureSize()
|
||||
{
|
||||
wxSize size = GetSize();
|
||||
wxClientDC dc(this);
|
||||
labelSize = dc.GetTextExtent(wxWindow::GetLabel());
|
||||
wxSize textSize = text_ctrl->GetSize();
|
||||
int h = textSize.y + 8;
|
||||
if (size.y < h) {
|
||||
size.y = h;
|
||||
}
|
||||
wxSize minSize = size;
|
||||
minSize.x = GetMinWidth();
|
||||
SetMinSize(minSize);
|
||||
SetSize(size);
|
||||
}
|
77
src/slic3r/GUI/Widgets/TextInput.hpp
Normal file
77
src/slic3r/GUI/Widgets/TextInput.hpp
Normal file
@ -0,0 +1,77 @@
|
||||
#ifndef slic3r_GUI_TextInput_hpp_
|
||||
#define slic3r_GUI_TextInput_hpp_
|
||||
|
||||
#include <wx/textctrl.h>
|
||||
#include "StaticBox.hpp"
|
||||
|
||||
class TextInput : public wxNavigationEnabled<StaticBox>
|
||||
{
|
||||
|
||||
wxSize labelSize;
|
||||
ScalableBitmap icon;
|
||||
StateColor label_color;
|
||||
StateColor text_color;
|
||||
wxTextCtrl * text_ctrl;
|
||||
|
||||
static const int TextInputWidth = 200;
|
||||
static const int TextInputHeight = 50;
|
||||
|
||||
public:
|
||||
TextInput();
|
||||
|
||||
TextInput(wxWindow * parent,
|
||||
wxString text,
|
||||
wxString label = "",
|
||||
wxString icon = "",
|
||||
const wxPoint &pos = wxDefaultPosition,
|
||||
const wxSize & size = wxDefaultSize,
|
||||
long style = 0);
|
||||
|
||||
public:
|
||||
void Create(wxWindow * parent,
|
||||
wxString text,
|
||||
wxString label = "",
|
||||
wxString icon = "",
|
||||
const wxPoint &pos = wxDefaultPosition,
|
||||
const wxSize & size = wxDefaultSize,
|
||||
long style = 0);
|
||||
|
||||
void SetCornerRadius(double radius);
|
||||
|
||||
void SetLabel(const wxString& label);
|
||||
|
||||
void SetIcon(const wxBitmap & icon);
|
||||
|
||||
void SetLabelColor(StateColor const &color);
|
||||
|
||||
void SetTextColor(StateColor const &color);
|
||||
|
||||
virtual void Rescale();
|
||||
|
||||
virtual bool Enable(bool enable = true) override;
|
||||
|
||||
virtual void SetMinSize(const wxSize& size) override;
|
||||
|
||||
wxTextCtrl *GetTextCtrl() { return text_ctrl; }
|
||||
|
||||
wxTextCtrl const *GetTextCtrl() const { return text_ctrl; }
|
||||
|
||||
protected:
|
||||
virtual void OnEdit() {}
|
||||
|
||||
virtual void DoSetSize(
|
||||
int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO);
|
||||
|
||||
void DoSetToolTipText(wxString const &tip) override;
|
||||
|
||||
private:
|
||||
void paintEvent(wxPaintEvent& evt);
|
||||
|
||||
void render(wxDC& dc);
|
||||
|
||||
void messureSize();
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_TextInput_hpp_
|
Loading…
x
Reference in New Issue
Block a user