mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-03 00:02:14 +00:00
Merge branch 'main' into dev/bbl-network-upd
This commit is contained in:
247
src/slic3r/GUI/Widgets/DialogButtons.cpp
Normal file
247
src/slic3r/GUI/Widgets/DialogButtons.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
#include "DialogButtons.hpp"
|
||||
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
// ORCA standardize dialog buttons
|
||||
DialogButtons::DialogButtons(wxWindow* parent, std::vector<wxString> non_translated_labels, const wxString& primary_btn_translated_label)
|
||||
: wxWindow(parent, wxID_ANY)
|
||||
{
|
||||
m_parent = parent;
|
||||
m_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_primary = primary_btn_translated_label;
|
||||
m_alert = wxEmptyString;
|
||||
SetBackgroundColour(StateColor::darkModeColorFor(wxColour("#FFFFFF")));
|
||||
|
||||
// Add all to array
|
||||
for (wxString label : non_translated_labels) {
|
||||
Button* btn = new Button(this, _L(label));
|
||||
wxString l = label;
|
||||
l.LowerCase();
|
||||
auto f = m_standardIDs.find(l);
|
||||
if (f != m_standardIDs.end())
|
||||
btn->SetId(f->second);
|
||||
m_buttons.push_back(btn);
|
||||
}
|
||||
|
||||
m_parent->Bind(wxEVT_DPI_CHANGED, &DialogButtons::on_dpi_changed, this);
|
||||
|
||||
SetSizer(m_sizer);
|
||||
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
DialogButtons::~DialogButtons() {
|
||||
m_parent->Unbind(wxEVT_DPI_CHANGED, &DialogButtons::on_dpi_changed, this);
|
||||
}
|
||||
|
||||
void DialogButtons::on_dpi_changed(wxDPIChangedEvent& event) {
|
||||
UpdateButtons();
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
Button* DialogButtons::GetButtonFromID(wxStandardID id) {
|
||||
for (Button* btn : m_buttons)
|
||||
if (btn->GetId() == id)
|
||||
return btn;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Button* DialogButtons::GetButtonFromLabel(wxString translated_label) {
|
||||
for (Button* btn : m_buttons)
|
||||
if (btn->GetLabel() == translated_label)
|
||||
return btn;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Button* DialogButtons::PickFromList(std::set<wxStandardID> ID_list) {
|
||||
// Picks first button from given list
|
||||
Button* b;
|
||||
for (auto itr : ID_list) {
|
||||
b = GetButtonFromID(itr);
|
||||
if (b != nullptr)
|
||||
return b;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// shorthands for common buttons
|
||||
Button* DialogButtons::GetOK() {return GetButtonFromID(wxID_OK) ;}
|
||||
Button* DialogButtons::GetYES() {return GetButtonFromID(wxID_YES) ;}
|
||||
Button* DialogButtons::GetAPPLY() {return GetButtonFromID(wxID_APPLY) ;}
|
||||
Button* DialogButtons::GetCONFIRM(){return GetButtonFromID(wxID_APPLY) ;}
|
||||
Button* DialogButtons::GetNO() {return GetButtonFromID(wxID_NO) ;}
|
||||
Button* DialogButtons::GetCANCEL() {return GetButtonFromID(wxID_CANCEL) ;}
|
||||
Button* DialogButtons::GetBACK() {return GetButtonFromID(wxID_BACKWARD);}
|
||||
Button* DialogButtons::GetFORWARD(){return GetButtonFromID(wxID_FORWARD) ;}
|
||||
|
||||
void DialogButtons::SetPrimaryButton(wxString translated_label) {
|
||||
// use _L("Create") translated text for custom buttons
|
||||
// use non existing button name to disable primary styled button
|
||||
Button* btn;
|
||||
if(translated_label.IsEmpty()){ // prefer standard primary buttons if label empty
|
||||
if(m_buttons.size() == 1)
|
||||
btn = m_buttons.front();
|
||||
else
|
||||
btn = PickFromList(m_primaryIDs);
|
||||
}else
|
||||
btn = GetButtonFromLabel(translated_label);
|
||||
|
||||
if(btn == nullptr) return;
|
||||
|
||||
m_primary = translated_label;
|
||||
|
||||
btn->SetFocus();
|
||||
// we won't need color definations after button style management
|
||||
StateColor clr_bg = StateColor(
|
||||
std::pair(wxColour("#009688"), (int)StateColor::NotHovered),
|
||||
std::pair(wxColour("#DFDFDF"), (int)StateColor::Disabled),
|
||||
std::pair(wxColour("#009688"), (int)StateColor::Pressed),
|
||||
std::pair(wxColour("#26A69A"), (int)StateColor::Hovered),
|
||||
std::pair(wxColour("#009688"), (int)StateColor::Normal),
|
||||
std::pair(wxColour("#009688"), (int)StateColor::Enabled)
|
||||
);
|
||||
btn->SetBackgroundColor(clr_bg);
|
||||
StateColor clr_br = StateColor(
|
||||
std::pair(wxColour("#009688"), (int)StateColor::NotFocused),
|
||||
std::pair(wxColour("#26A69A"), (int)StateColor::Focused)
|
||||
);
|
||||
btn->SetBorderColor(clr_br);
|
||||
StateColor clr_tx = StateColor(
|
||||
std::pair(wxColour("#6B6A6A"), (int)StateColor::Disabled),
|
||||
std::pair(wxColour("#FEFEFE"), (int)StateColor::Hovered),
|
||||
std::pair(wxColour("#FEFEFE"), (int)StateColor::Normal)
|
||||
);
|
||||
btn->SetTextColor(clr_tx);
|
||||
}
|
||||
|
||||
void DialogButtons::SetAlertButton(wxString translated_label) {
|
||||
// use _L("Create") translated text for custom buttons
|
||||
// use non existing button name to disable alert styled button
|
||||
if(m_buttons.size() == 1)
|
||||
return;
|
||||
Button* btn;
|
||||
if(translated_label.IsEmpty()){ // prefer standard alert buttons if label empty
|
||||
btn = PickFromList(m_alertIDs);
|
||||
}else
|
||||
btn = GetButtonFromLabel(translated_label);
|
||||
|
||||
if(btn == nullptr) return;
|
||||
|
||||
m_alert = translated_label;
|
||||
|
||||
// we won't need color definations after button style management
|
||||
StateColor clr_bg = StateColor(
|
||||
std::pair(wxColour("#DFDFDF"), (int)StateColor::NotHovered),
|
||||
std::pair(wxColour("#DFDFDF"), (int)StateColor::Disabled),
|
||||
std::pair(wxColour("#DFDFDF"), (int)StateColor::Pressed),
|
||||
std::pair(wxColour("#CD1F00"), (int)StateColor::Hovered),
|
||||
std::pair(wxColour("#DFDFDF"), (int)StateColor::Normal),
|
||||
std::pair(wxColour("#DFDFDF"), (int)StateColor::Enabled)
|
||||
);
|
||||
btn->SetBackgroundColor(clr_bg);
|
||||
StateColor clr_br = StateColor(
|
||||
std::pair(wxColour("#DFDFDF"), (int)StateColor::NotFocused),
|
||||
std::pair(wxColour("#26A69A"), (int)StateColor::Focused)
|
||||
);
|
||||
btn->SetBorderColor(clr_br);
|
||||
StateColor clr_tx = StateColor(
|
||||
std::pair(wxColour("#CD1F00"), (int)StateColor::NotHovered),
|
||||
std::pair(wxColour("#6B6A6A"), (int)StateColor::Disabled),
|
||||
std::pair(wxColour("#CD1F00"), (int)StateColor::Pressed),
|
||||
std::pair(wxColour("#FFFFFD"), (int)StateColor::Hovered),
|
||||
std::pair(wxColour("#CD1F00"), (int)StateColor::Focused),
|
||||
std::pair(wxColour("#CD1F00"), (int)StateColor::Normal)
|
||||
);
|
||||
btn->SetTextColor(clr_tx);
|
||||
}
|
||||
|
||||
void DialogButtons::UpdateButtons() {
|
||||
m_sizer->Clear();
|
||||
SetBackgroundColour(StateColor::darkModeColorFor(wxColour("#FFFFFF")));
|
||||
// we won't need color definations after button style management
|
||||
StateColor clr_bg = StateColor(
|
||||
std::pair(wxColour("#DFDFDF"), (int)StateColor::NotHovered),
|
||||
std::pair(wxColour("#DFDFDF"), (int)StateColor::Disabled),
|
||||
std::pair(wxColour("#DFDFDF"), (int)StateColor::Pressed),
|
||||
std::pair(wxColour("#D4D4D4"), (int)StateColor::Hovered),
|
||||
std::pair(wxColour("#DFDFDF"), (int)StateColor::Normal),
|
||||
std::pair(wxColour("#DFDFDF"), (int)StateColor::Enabled)
|
||||
);
|
||||
StateColor clr_br = StateColor(
|
||||
std::pair(wxColour("#DFDFDF"), (int)StateColor::NotFocused),
|
||||
std::pair(wxColour("#26A69A"), (int)StateColor::Focused)
|
||||
);
|
||||
StateColor clr_tx = StateColor(
|
||||
std::pair(wxColour("#6B6A6A"), (int)StateColor::Disabled),
|
||||
std::pair(wxColour("#262E30"), (int)StateColor::Hovered),
|
||||
std::pair(wxColour("#262E30"), (int)StateColor::Normal)
|
||||
);
|
||||
|
||||
// Apply standard style to all
|
||||
for (Button* btn : m_buttons) {
|
||||
btn->SetFont(Label::Body_14);
|
||||
btn->SetMinSize(wxSize(FromDIP(100),FromDIP(32)));
|
||||
btn->SetPaddingSize(wxSize(FromDIP(12), FromDIP(8)));
|
||||
btn->SetCornerRadius(FromDIP(4));
|
||||
btn->SetBorderWidth(FromDIP(1));
|
||||
btn->SetBackgroundColor(clr_bg);
|
||||
btn->SetBorderColor(clr_br);
|
||||
btn->SetTextColor(clr_tx);
|
||||
btn->Bind(wxEVT_KEY_DOWN, &DialogButtons::on_keydown, this);
|
||||
}
|
||||
|
||||
int btn_gap = FromDIP(10);
|
||||
|
||||
auto list = m_left_align_IDs;
|
||||
auto on_left = [list](int id){
|
||||
return list.find(wxStandardID(id)) != list.end();
|
||||
};
|
||||
|
||||
for (Button* btn : m_buttons) // Left aligned
|
||||
if(on_left(btn->GetId()))
|
||||
m_sizer->Add(btn, 0, wxLEFT | wxTOP | wxBOTTOM | wxALIGN_CENTER_VERTICAL, btn_gap);
|
||||
|
||||
m_sizer->AddStretchSpacer();
|
||||
|
||||
for (Button* btn : m_buttons) // Right aligned
|
||||
if(!on_left(btn->GetId()))
|
||||
m_sizer->Add(btn, 0, wxRIGHT | wxTOP | wxBOTTOM | wxALIGN_CENTER_VERTICAL, btn_gap);
|
||||
|
||||
SetPrimaryButton(m_primary);
|
||||
SetAlertButton(m_alert);
|
||||
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
|
||||
int DialogButtons::FromDIP(int d) {
|
||||
return m_parent->FromDIP(d);
|
||||
}
|
||||
|
||||
// This might be helpful for future use
|
||||
|
||||
// Append Button
|
||||
|
||||
// Prepend Button
|
||||
|
||||
void DialogButtons::on_keydown(wxKeyEvent& e) {
|
||||
wxObject* current = e.GetEventObject();
|
||||
int key = e.GetKeyCode();
|
||||
int cnt = m_buttons.size();
|
||||
if(cnt > 1){
|
||||
int i = -1;
|
||||
for (Button* btn : m_buttons){
|
||||
i++;
|
||||
if(btn->HasFocus())
|
||||
break;
|
||||
}
|
||||
// possible issue if button hidden
|
||||
if (key == WXK_LEFT) {m_buttons[i - 1 < 0 ? (cnt - 1) : i - 1]->SetFocus();}
|
||||
else if (key == WXK_RIGHT) {m_buttons[i + 1 > (cnt - 1) ? 0 : i + 1]->SetFocus();}
|
||||
}
|
||||
e.Skip();
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
125
src/slic3r/GUI/Widgets/DialogButtons.hpp
Normal file
125
src/slic3r/GUI/Widgets/DialogButtons.hpp
Normal file
@@ -0,0 +1,125 @@
|
||||
#ifndef slic3r_GUI_DialogButtons_hpp_
|
||||
#define slic3r_GUI_DialogButtons_hpp_
|
||||
|
||||
#include "wx/wx.h"
|
||||
#include "wx/sizer.h"
|
||||
#include "map"
|
||||
#include "set"
|
||||
|
||||
#include "Button.hpp"
|
||||
#include "Label.hpp"
|
||||
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
class DialogButtons : public wxWindow{
|
||||
public:
|
||||
|
||||
DialogButtons(wxWindow* parent, std::vector<wxString> non_translated_labels, const wxString& primary_btn_label = "");
|
||||
|
||||
wxBoxSizer* GetSizer() const { return m_sizer; }
|
||||
|
||||
Button* GetButtonFromID(wxStandardID id);
|
||||
|
||||
Button* GetButtonFromLabel(wxString label);
|
||||
|
||||
Button* GetOK();
|
||||
Button* GetYES();
|
||||
Button* GetAPPLY();
|
||||
Button* GetCONFIRM();
|
||||
Button* GetNO();
|
||||
Button* GetCANCEL();
|
||||
Button* GetBACK();
|
||||
Button* GetFORWARD();
|
||||
|
||||
void SetPrimaryButton(wxString label);
|
||||
|
||||
void SetAlertButton(wxString label);
|
||||
|
||||
void UpdateButtons();
|
||||
|
||||
~DialogButtons();
|
||||
|
||||
private:
|
||||
wxWindow* m_parent;
|
||||
wxBoxSizer* m_sizer;
|
||||
std::vector<Button*> m_buttons;
|
||||
wxString m_primary;
|
||||
wxString m_alert;
|
||||
|
||||
// missing ones Transfer / Update / Create
|
||||
const std::map<wxString, wxStandardID> m_standardIDs = {
|
||||
// Choice
|
||||
{"ok" , wxID_OK},
|
||||
{"yes" , wxID_YES},
|
||||
{"apply" , wxID_APPLY},
|
||||
{"confirm" , wxID_APPLY}, // no id for confirm, reusing wxID_APPLY
|
||||
{"no" , wxID_NO},
|
||||
{"cancel" , wxID_CANCEL},
|
||||
// Action
|
||||
{"open" , wxID_PRINT},
|
||||
{"open" , wxID_OPEN},
|
||||
{"add" , wxID_ADD},
|
||||
{"copy" , wxID_COPY},
|
||||
{"new" , wxID_NEW},
|
||||
{"save" , wxID_SAVE},
|
||||
{"save as" , wxID_SAVEAS},
|
||||
{"refresh" , wxID_REFRESH},
|
||||
{"retry" , wxID_RETRY},
|
||||
{"ignore" , wxID_IGNORE},
|
||||
{"help" , wxID_HELP},
|
||||
{"clone" , wxID_DUPLICATE},
|
||||
{"duplicate" , wxID_DUPLICATE},
|
||||
{"select all" , wxID_SELECTALL},
|
||||
{"replace" , wxID_REPLACE},
|
||||
{"replace all", wxID_REPLACE_ALL},
|
||||
// Navigation
|
||||
{"back" , wxID_BACKWARD},
|
||||
{"next" , wxID_FORWARD},
|
||||
// Alert / Negative
|
||||
{"remove" , wxID_REMOVE},
|
||||
{"delete" , wxID_DELETE},
|
||||
{"abort" , wxID_ABORT},
|
||||
{"stop" , wxID_STOP},
|
||||
{"reset" , wxID_RESET},
|
||||
{"clear" , wxID_CLEAR},
|
||||
{"exit" , wxID_EXIT},
|
||||
{"quit" , wxID_EXIT}
|
||||
};
|
||||
|
||||
std::set<wxStandardID> m_primaryIDs {
|
||||
wxID_OK,
|
||||
wxID_YES,
|
||||
wxID_APPLY,
|
||||
wxID_SAVE,
|
||||
wxID_PRINT
|
||||
};
|
||||
|
||||
std::set<wxStandardID> m_alertIDs {
|
||||
wxID_REMOVE,
|
||||
wxID_DELETE,
|
||||
wxID_ABORT,
|
||||
wxID_STOP,
|
||||
wxID_RESET,
|
||||
wxID_CLEAR,
|
||||
wxID_EXIT
|
||||
};
|
||||
|
||||
std::set<wxStandardID> m_left_align_IDs {
|
||||
wxID_DELETE,
|
||||
wxID_BACKWARD,
|
||||
wxID_FORWARD
|
||||
};
|
||||
|
||||
Button* PickFromList(std::set<wxStandardID> ID_list);
|
||||
|
||||
int FromDIP(int d);
|
||||
|
||||
void on_dpi_changed(wxDPIChangedEvent& event);
|
||||
|
||||
void on_keydown(wxKeyEvent& event);
|
||||
};
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
#endif // !slic3r_GUI_DialogButtons_hpp_
|
||||
181
src/slic3r/GUI/Widgets/LabeledStaticBox.cpp
Normal file
181
src/slic3r/GUI/Widgets/LabeledStaticBox.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
#include "LabeledStaticBox.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "../GUI.hpp"
|
||||
#include "../GUI_Utils.hpp"
|
||||
#include "Label.hpp"
|
||||
|
||||
/*
|
||||
Fix label overflowing to inner frame
|
||||
Fix use elypsis if text too long
|
||||
setmin size
|
||||
*/
|
||||
|
||||
LabeledStaticBox::LabeledStaticBox()
|
||||
: state_handler(this)
|
||||
{
|
||||
m_radius = 3;
|
||||
m_border_width = 1;
|
||||
m_font = Label::Head_14;
|
||||
text_color = StateColor(
|
||||
std::make_pair(0x363636, (int) StateColor::Normal),
|
||||
std::make_pair(0x6B6B6B, (int) StateColor::Disabled)
|
||||
);
|
||||
background_color = StateColor(
|
||||
std::make_pair(0xFFFFFF, (int) StateColor::Normal),
|
||||
std::make_pair(0xF0F0F1, (int) StateColor::Disabled)
|
||||
);
|
||||
border_color = StateColor(
|
||||
std::make_pair(0xDBDBDB, (int) StateColor::Normal),
|
||||
std::make_pair(0xDBDBDB, (int) StateColor::Disabled)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
LabeledStaticBox::LabeledStaticBox(
|
||||
wxWindow* parent,
|
||||
const wxString& label,
|
||||
const wxPoint& pos,
|
||||
const wxSize& size,
|
||||
long style
|
||||
)
|
||||
: LabeledStaticBox()
|
||||
{
|
||||
Create(parent, label, pos, size, style);
|
||||
}
|
||||
|
||||
bool LabeledStaticBox::Create(
|
||||
wxWindow* parent,
|
||||
const wxString& label,
|
||||
const wxPoint& pos,
|
||||
const wxSize& size,
|
||||
long style
|
||||
)
|
||||
{
|
||||
if (style & wxBORDER_NONE)
|
||||
m_border_width = 0;
|
||||
wxStaticBox::Create(parent, wxID_ANY, label, pos, size, style);
|
||||
#ifdef __WXOSX__
|
||||
Slic3r::GUI::staticbox_remove_margin(this);
|
||||
#endif
|
||||
|
||||
m_label = label;
|
||||
m_scale = FromDIP(100) / 100.f;
|
||||
m_pos = this->GetPosition();
|
||||
|
||||
int tW,tH,descent,externalLeading;
|
||||
GetTextExtent("Yy", &tW, &tH, &descent, &externalLeading, &m_font);
|
||||
m_label_height = tH - externalLeading;
|
||||
|
||||
GetTextExtent(m_label, &tW, &tH, &descent, &externalLeading, &m_font);
|
||||
m_label_width = tW;
|
||||
|
||||
Bind(wxEVT_PAINT,([this](wxPaintEvent e) {
|
||||
wxPaintDC dc(this);
|
||||
PickDC(dc);
|
||||
}));
|
||||
|
||||
state_handler.attach({&text_color, &background_color, &border_color});
|
||||
state_handler.update_binds();
|
||||
#ifndef __WXOSX__
|
||||
SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
#endif
|
||||
SetBackgroundColour(background_color.colorForStates(state_handler.states()));
|
||||
SetForegroundColour( text_color.colorForStates(state_handler.states()));
|
||||
SetBorderColor( border_color.colorForStates(state_handler.states()));
|
||||
SetCanFocus(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
void LabeledStaticBox::SetCornerRadius(int radius)
|
||||
{
|
||||
this->m_radius = radius;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void LabeledStaticBox::SetBorderWidth(int width)
|
||||
{
|
||||
this->m_border_width = width;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void LabeledStaticBox::SetBorderColor(StateColor const &color)
|
||||
{
|
||||
border_color = color;
|
||||
state_handler.update_binds();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void LabeledStaticBox::SetFont(wxFont set_font)
|
||||
{
|
||||
m_font = set_font;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
bool LabeledStaticBox::Enable(bool enable)
|
||||
{
|
||||
bool result = this->wxStaticBox::Enable(enable);
|
||||
if (result) {
|
||||
wxCommandEvent e(EVT_ENABLE_CHANGED);
|
||||
e.SetEventObject(this);
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
this->SetForegroundColour( text_color.colorForStates(state_handler.states()));
|
||||
this->SetBorderColor( border_color.colorForStates(state_handler.states()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void LabeledStaticBox::PickDC(wxDC& dc)
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
wxSize size = GetSize();
|
||||
if (size.x <= 0 || size.y <= 0)
|
||||
return;
|
||||
wxMemoryDC memdc(&dc);
|
||||
if (!memdc.IsOk()) {
|
||||
DrawBorderAndLabel(dc);
|
||||
return;
|
||||
}
|
||||
wxBitmap bmp(size.x, size.y);
|
||||
memdc.SelectObject(bmp);
|
||||
memdc.SetBackground(wxBrush(GetBackgroundColour()));
|
||||
memdc.Clear();
|
||||
{
|
||||
wxGCDC dc2(memdc);
|
||||
DrawBorderAndLabel(dc2);
|
||||
}
|
||||
|
||||
memdc.SelectObject(wxNullBitmap);
|
||||
dc.DrawBitmap(bmp, 0, 0);
|
||||
#else
|
||||
DrawBorderAndLabel(dc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void LabeledStaticBox::DrawBorderAndLabel(wxDC& dc)
|
||||
{
|
||||
// fill full background
|
||||
dc.SetBackground(wxBrush(background_color.colorForStates(0)));
|
||||
dc.Clear();
|
||||
|
||||
wxSize wSz = GetSize();
|
||||
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.SetPen(wxPen(border_color.colorForStates(state_handler.states()), m_border_width, wxSOLID));
|
||||
dc.DrawRoundedRectangle( // Border
|
||||
std::max(0, m_pos.x),
|
||||
std::max(0, m_pos.y) + m_label_height * .5,
|
||||
wSz.GetWidth(),
|
||||
wSz.GetHeight() - m_label_height * .5,
|
||||
m_radius * m_scale
|
||||
);
|
||||
|
||||
if (!m_label.IsEmpty()) {
|
||||
dc.SetFont(m_font);
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
dc.SetBrush(wxBrush(background_color.colorForStates(0)));
|
||||
dc.DrawRectangle(wxRect(7 * m_scale,0 , m_label_width + 7 * m_scale, m_label_height)); // text background
|
||||
// NEEDFIX if text lenght > client size
|
||||
dc.SetTextForeground(text_color.colorForStates(state_handler.states()));
|
||||
dc.DrawText(m_label, wxPoint(10 * m_scale, 0));
|
||||
}
|
||||
}
|
||||
68
src/slic3r/GUI/Widgets/LabeledStaticBox.hpp
Normal file
68
src/slic3r/GUI/Widgets/LabeledStaticBox.hpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#ifndef slic3r_GUI_LabeledStaticBox_hpp_
|
||||
#define slic3r_GUI_LabeledStaticBox_hpp_
|
||||
|
||||
#include <wx/window.h>
|
||||
#include <wx/dc.h>
|
||||
#include <wx/dcgraph.h>
|
||||
#include <wx/dcclient.h>
|
||||
#include <wx/dcbuffer.h>
|
||||
#include <wx/settings.h>
|
||||
#include <wx/statbox.h>
|
||||
#include <wx/pen.h>
|
||||
|
||||
#include "libslic3r/Utils.hpp"
|
||||
|
||||
#include "slic3r/GUI/wxExtensions.hpp"
|
||||
#include "slic3r/GUI/Widgets/StateHandler.hpp"
|
||||
|
||||
class LabeledStaticBox : public wxStaticBox
|
||||
{
|
||||
public:
|
||||
LabeledStaticBox();
|
||||
|
||||
LabeledStaticBox(
|
||||
wxWindow* parent,
|
||||
const wxString& label = wxEmptyString,
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = 0
|
||||
);
|
||||
|
||||
bool Create(
|
||||
wxWindow* parent,
|
||||
const wxString& label = wxEmptyString,
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = 0
|
||||
);
|
||||
|
||||
void SetCornerRadius(int radius);
|
||||
|
||||
void SetBorderWidth(int width);
|
||||
|
||||
void SetBorderColor(StateColor const &color);
|
||||
|
||||
void SetFont(wxFont set_font);
|
||||
|
||||
bool Enable(bool enable) override;
|
||||
|
||||
private:
|
||||
void PickDC(wxDC& dc);
|
||||
virtual void DrawBorderAndLabel(wxDC& dc);
|
||||
|
||||
protected:
|
||||
StateHandler state_handler;
|
||||
StateColor text_color;
|
||||
StateColor border_color;
|
||||
StateColor background_color;
|
||||
int m_border_width;
|
||||
int m_radius;
|
||||
wxFont m_font;
|
||||
wxString m_label;
|
||||
int m_label_height;
|
||||
int m_label_width;
|
||||
float m_scale;
|
||||
wxPoint m_pos;
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_LabeledStaticBox_hpp_
|
||||
149
src/slic3r/GUI/Widgets/RadioGroup.cpp
Normal file
149
src/slic3r/GUI/Widgets/RadioGroup.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
#include "RadioGroup.hpp"
|
||||
#include "Label.hpp"
|
||||
#include "StateColor.hpp"
|
||||
|
||||
RadioGroup::RadioGroup(
|
||||
wxWindow* parent,
|
||||
const std::vector<wxString>& labels,
|
||||
long direction,
|
||||
int row_col_limit
|
||||
)
|
||||
: wxPanel(parent, wxID_ANY)
|
||||
, m_on( this, "radio_on" , 18)
|
||||
, m_off( this, "radio_off" , 18)
|
||||
, m_on_hover( this, "radio_on_hover" , 18)
|
||||
, m_off_hover(this, "radio_off_hover", 18)
|
||||
, m_disabled( this, "radio_off_hover", 18)
|
||||
, m_selectedIndex(0)
|
||||
, m_focused(false)
|
||||
{
|
||||
Create(parent, labels, direction, row_col_limit);
|
||||
}
|
||||
|
||||
void RadioGroup::Create(
|
||||
wxWindow* parent,
|
||||
const std::vector<wxString>& labels,
|
||||
long direction, /* wxHORIZONTAL / wxVERTICAL */
|
||||
int row_col_limit /* sets column/row count depends on direction. creates new row if wxHORIZONTAL used after limit reached */
|
||||
)
|
||||
{
|
||||
m_labels = labels;
|
||||
auto bg = parent->GetBackgroundColour();
|
||||
this->SetBackgroundColour(bg);
|
||||
auto bmp_size = m_on.GetBmpSize();
|
||||
int item_count = m_labels.size();
|
||||
int item_limit = row_col_limit < 0 ? 1 : row_col_limit > item_count ? item_count : row_col_limit;
|
||||
int count = (int(item_count / item_limit) + (item_count % item_limit));
|
||||
int rows = (direction & wxHORIZONTAL) ? item_limit : count;
|
||||
int cols = (direction & wxHORIZONTAL) ? count : item_limit;
|
||||
wxFlexGridSizer* f_sizer = new wxFlexGridSizer(rows, cols, 0, 0);
|
||||
|
||||
SetDoubleBuffered(true);
|
||||
AcceptsFocusFromKeyboard();
|
||||
|
||||
Bind(wxEVT_SET_FOCUS ,([this](wxFocusEvent e) {m_focused = true ;Refresh(); e.Skip();}));
|
||||
Bind(wxEVT_KILL_FOCUS,([this](wxFocusEvent e) {m_focused = false;Refresh(); e.Skip();}));
|
||||
Bind(wxEVT_PAINT,([this](wxPaintEvent e) {
|
||||
wxPaintDC dc(this);
|
||||
dc.Clear();
|
||||
dc.SetPen(wxPen(StateColor::darkModeColorFor(wxColour("#009688")), 1, wxPENSTYLE_SOLID));
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.DrawRectangle(
|
||||
m_focused ? wxRect(
|
||||
m_radioButtons[GetSelection()]->GetRect().GetTopLeft() - wxPoint(1, 3),
|
||||
m_labelButtons[GetSelection()]->GetRect().GetBottomRight() + wxPoint(4, 1)
|
||||
) : wxRect(0,0,0,0)
|
||||
);
|
||||
if (m_focused) // Required to take focus again since Refresh causing lossing focus
|
||||
SetFocus();
|
||||
}));
|
||||
// DPIDialog's uses wxEVT_CHAR_HOOK
|
||||
Bind(wxEVT_CHAR_HOOK, ([this](wxKeyEvent&e){
|
||||
int k = e.GetKeyCode();
|
||||
bool is_next = (k == WXK_DOWN || k == WXK_RIGHT);
|
||||
bool is_prev = (k == WXK_LEFT || k == WXK_UP);
|
||||
if(m_focused){
|
||||
if (is_next) SelectNext();
|
||||
else if (is_prev) SelectPrevious();
|
||||
e.Skip(!(is_next || is_prev));
|
||||
}else{
|
||||
e.Skip();
|
||||
}
|
||||
}));
|
||||
|
||||
for (int i = 0; i < item_count; ++i){
|
||||
auto rb = new wxStaticBitmap(this, wxID_ANY, m_off.bmp(), wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxNO_BORDER);
|
||||
m_radioButtons.push_back(rb);
|
||||
rb->Bind(wxEVT_LEFT_DOWN ,([this, i](wxMouseEvent e) {OnClick(i) ; e.Skip();}));
|
||||
rb->Bind(wxEVT_ENTER_WINDOW,([this, i](wxMouseEvent e) {SetRadioIcon(i, true) ; e.Skip();}));
|
||||
rb->Bind(wxEVT_LEAVE_WINDOW,([this, i](wxMouseEvent e) {
|
||||
// prevent removing hover effect while switching between button and its text
|
||||
if(wxFindWindowAtPoint(wxGetMousePosition())->GetId() != m_labelButtons[i]->GetId())
|
||||
SetRadioIcon(i, false);
|
||||
e.Skip();
|
||||
}));
|
||||
|
||||
auto tx = new wxStaticText(this, wxID_ANY, " " + m_labels[i], wxDefaultPosition, wxDefaultSize);
|
||||
tx->SetForegroundColour(wxColour("#363636"));
|
||||
tx->SetFont(Label::Body_14);
|
||||
m_labelButtons.push_back(tx);
|
||||
tx->Bind(wxEVT_LEFT_DOWN ,([this, i](wxMouseEvent e) {OnClick(i) ; e.Skip();}));
|
||||
tx->Bind(wxEVT_ENTER_WINDOW,([this, i](wxMouseEvent e) {SetRadioIcon(i, true) ; e.Skip();}));
|
||||
tx->Bind(wxEVT_LEAVE_WINDOW,([this, i](wxMouseEvent e) {
|
||||
// prevent removing hover effect while switching between button and its text
|
||||
if(wxFindWindowAtPoint(wxGetMousePosition())->GetId() != m_radioButtons[i]->GetId())
|
||||
SetRadioIcon(i, false);
|
||||
e.Skip();
|
||||
}));
|
||||
|
||||
wxBoxSizer* radio_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
radio_sizer->Add(rb, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 1);
|
||||
radio_sizer->Add(tx, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, this->FromDIP(15));
|
||||
f_sizer->Add(radio_sizer, 0, wxTOP | wxBOTTOM, this->FromDIP(4));
|
||||
}
|
||||
SetSelection(m_selectedIndex);
|
||||
SetSizer(f_sizer);
|
||||
}
|
||||
|
||||
void RadioGroup::OnClick(int i)
|
||||
{
|
||||
m_focused = true; // prevents 2 time refresh
|
||||
SetSelection(i);
|
||||
}
|
||||
|
||||
void RadioGroup::SetSelection(int index)
|
||||
{
|
||||
if (index >= 0 && index < static_cast<int>(m_labels.size())){
|
||||
m_selectedIndex = index;
|
||||
for (size_t i = 0; i < m_labels.size(); ++i)
|
||||
SetRadioIcon(i, HasFocus() && i == m_selectedIndex);
|
||||
|
||||
wxCommandEvent evt(wxEVT_COMMAND_RADIOBOX_SELECTED, GetId());
|
||||
evt.SetInt(index);
|
||||
evt.SetString(m_labels[index]);
|
||||
GetEventHandler()->ProcessEvent(evt);
|
||||
|
||||
Refresh(); // refresh on every change
|
||||
}
|
||||
}
|
||||
|
||||
int RadioGroup::GetSelection()
|
||||
{
|
||||
return m_selectedIndex;
|
||||
}
|
||||
|
||||
void RadioGroup::SelectNext(bool focus)
|
||||
{
|
||||
SetSelection(m_selectedIndex + 1 > (m_radioButtons.size() - 1) ? 0 : m_selectedIndex + 1);
|
||||
}
|
||||
|
||||
void RadioGroup::SelectPrevious(bool focus)
|
||||
{
|
||||
SetSelection(m_selectedIndex - 1 < 0 ? (m_radioButtons.size() - 1) : m_selectedIndex - 1);
|
||||
}
|
||||
|
||||
void RadioGroup::SetRadioIcon(int i, bool hover)
|
||||
{
|
||||
auto icon = m_selectedIndex == i ? (hover ? m_on_hover : m_on) : (hover ? m_off_hover : m_off);
|
||||
m_radioButtons[i]->SetBitmap(icon.bmp());
|
||||
}
|
||||
63
src/slic3r/GUI/Widgets/RadioGroup.hpp
Normal file
63
src/slic3r/GUI/Widgets/RadioGroup.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#ifndef slic3r_GUI_RADIOGROUP_hpp_
|
||||
#define slic3r_GUI_RADIOGROUP_hpp_
|
||||
|
||||
#include "../wxExtensions.hpp"
|
||||
|
||||
#include <wx/wx.h>
|
||||
#include <wx/dcclient.h>
|
||||
#include <wx/dcgraph.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class RadioGroup : public wxPanel
|
||||
{
|
||||
|
||||
public:
|
||||
RadioGroup();
|
||||
|
||||
RadioGroup(
|
||||
wxWindow* parent,
|
||||
const std::vector<wxString>& labels = {"1", "2", "3"},
|
||||
long direction = wxHORIZONTAL,
|
||||
int row_col_limit = -1
|
||||
);
|
||||
|
||||
void Create(
|
||||
wxWindow* parent,
|
||||
const std::vector<wxString>& labels = {"1", "2", "3"},
|
||||
long direction = wxHORIZONTAL,
|
||||
int row_col_limit = -1
|
||||
);
|
||||
|
||||
int GetSelection();
|
||||
|
||||
void SetSelection(int index);
|
||||
|
||||
void SelectNext(bool focus = true);
|
||||
|
||||
void SelectPrevious(bool focus = true);
|
||||
|
||||
private:
|
||||
std::vector<wxString> m_labels;
|
||||
std::vector<wxStaticBitmap*> m_radioButtons;
|
||||
std::vector<wxStaticText*> m_labelButtons;
|
||||
|
||||
int m_selectedIndex;
|
||||
bool m_focused;
|
||||
ScalableBitmap m_on;
|
||||
ScalableBitmap m_off;
|
||||
ScalableBitmap m_on_hover;
|
||||
ScalableBitmap m_off_hover;
|
||||
ScalableBitmap m_disabled;
|
||||
|
||||
void OnClick(int i);
|
||||
|
||||
void UpdateFocus(bool focus);
|
||||
|
||||
void SetRadioIcon(int i, bool hover);
|
||||
|
||||
void OnKeyDown(wxKeyEvent& e);
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_RADIOGROUP_hpp_
|
||||
Reference in New Issue
Block a user