Files
OrcaSlicer-KX/src/slic3r/GUI/Widgets/SpinInput.cpp
SoftFever 5ef51f6c8a Merge branch 'master-remote' into feature/1.5
Signed-off-by: SoftFever <softfeverever@gmail.com>

# Conflicts:
#	bbl/i18n/BambuStudio.pot
#	bbl/i18n/de/BambuStudio_de.po
#	bbl/i18n/en/BambuStudio_en.po
#	bbl/i18n/es/BambuStudio_es.po
#	bbl/i18n/fr/BambuStudio_fr.po
#	bbl/i18n/hu/BambuStudio_hu.po
#	bbl/i18n/it/BambuStudio_it.po
#	bbl/i18n/nl/BambuStudio_nl.po
#	bbl/i18n/sv/BambuStudio_sv.po
#	bbl/i18n/zh_cn/BambuStudio_zh_CN.po
#	deps/Boost/Boost.cmake
#	deps/wxWidgets/wxWidgets.cmake
#	resources/config.json
#	resources/i18n/de/BambuStudio.mo
#	resources/i18n/en/BambuStudio.mo
#	resources/i18n/es/BambuStudio.mo
#	resources/i18n/fr/BambuStudio.mo
#	resources/i18n/hu/BambuStudio.mo
#	resources/i18n/it/BambuStudio.mo
#	resources/i18n/nl/BambuStudio.mo
#	resources/i18n/sv/BambuStudio.mo
#	resources/i18n/zh_cn/BambuStudio.mo
#	resources/images/tips_arrow.svg
#	resources/profiles/Anycubic.json
#	resources/profiles/Anycubic/filament/Anycubic Generic ABS.json
#	resources/profiles/Anycubic/filament/Anycubic Generic ASA.json
#	resources/profiles/Anycubic/filament/Anycubic Generic PA-CF.json
#	resources/profiles/Anycubic/filament/Anycubic Generic PA.json
#	resources/profiles/Anycubic/filament/Anycubic Generic PC.json
#	resources/profiles/Anycubic/filament/Anycubic Generic PETG.json
#	resources/profiles/Anycubic/filament/Anycubic Generic PLA-CF.json
#	resources/profiles/Anycubic/filament/Anycubic Generic PLA.json
#	resources/profiles/Anycubic/filament/Anycubic Generic PVA.json
#	resources/profiles/Anycubic/filament/Anycubic Generic TPU.json
#	resources/profiles/Anycubic/filament/fdm_filament_common.json
#	resources/profiles/Anycubic/machine/Anycubic 4Max Pro 0.4 nozzle.json
#	resources/profiles/Anycubic/machine/Anycubic 4Max Pro.json
#	resources/profiles/Anycubic/process/0.20mm Standard @4MaxPro.json
#	resources/profiles/Anycubic/process/fdm_process_common.json
#	resources/profiles/BBL.json
#	resources/profiles/BBL/machine/Bambu Lab P1P 0.2 nozzle.json
#	resources/profiles/BBL/machine/Bambu Lab P1P 0.4 nozzle.json
#	resources/profiles/BBL/machine/Bambu Lab P1P 0.6 nozzle.json
#	resources/profiles/BBL/machine/Bambu Lab P1P 0.8 nozzle.json
#	resources/profiles/BBL/machine/Bambu Lab X1 0.2 nozzle.json
#	resources/profiles/BBL/machine/Bambu Lab X1 0.4 nozzle.json
#	resources/profiles/BBL/machine/Bambu Lab X1 0.6 nozzle.json
#	resources/profiles/BBL/machine/Bambu Lab X1 0.8 nozzle.json
#	resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.2 nozzle.json
#	resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.4 nozzle.json
#	resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.6 nozzle.json
#	resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.8 nozzle.json
#	resources/profiles/BBL/machine/fdm_bbl_3dp_001_common.json
#	resources/profiles/Voron.json
#	resources/web/data/text.js
#	resources/web/image/printer/Anycubic 4Max Pro_cover.png
#	src/BambuStudio.cpp
#	src/libslic3r/GCode.cpp
#	src/libslic3r/GCode.hpp
#	src/libslic3r/GCode/GCodeProcessor.cpp
#	src/libslic3r/GCodeWriter.hpp
#	src/libslic3r/PerimeterGenerator.cpp
#	src/libslic3r/PresetBundle.cpp
#	src/libslic3r/Print.cpp
#	src/libslic3r/Print.hpp
#	src/libslic3r/PrintConfig.cpp
#	src/libslic3r/PrintConfig.hpp
#	src/libslic3r/PrintObject.cpp
#	src/slic3r/GUI/AMSMaterialsSetting.cpp
#	src/slic3r/GUI/AMSMaterialsSetting.hpp
#	src/slic3r/GUI/AmsMappingPopup.cpp
#	src/slic3r/GUI/AmsMappingPopup.hpp
#	src/slic3r/GUI/Auxiliary.cpp
#	src/slic3r/GUI/BackgroundSlicingProcess.cpp
#	src/slic3r/GUI/ConfigManipulation.cpp
#	src/slic3r/GUI/DeviceManager.cpp
#	src/slic3r/GUI/DeviceManager.hpp
#	src/slic3r/GUI/ExtrusionCalibration.cpp
#	src/slic3r/GUI/GCodeViewer.cpp
#	src/slic3r/GUI/GCodeViewer.hpp
#	src/slic3r/GUI/GUI_App.cpp
#	src/slic3r/GUI/IMSlider.cpp
#	src/slic3r/GUI/Jobs/PrintJob.cpp
#	src/slic3r/GUI/Jobs/PrintJob.hpp
#	src/slic3r/GUI/Jobs/SendJob.cpp
#	src/slic3r/GUI/Jobs/SendJob.hpp
#	src/slic3r/GUI/MainFrame.cpp
#	src/slic3r/GUI/MainFrame.hpp
#	src/slic3r/GUI/MediaPlayCtrl.cpp
#	src/slic3r/GUI/OptionsGroup.cpp
#	src/slic3r/GUI/PhysicalPrinterDialog.cpp
#	src/slic3r/GUI/Plater.cpp
#	src/slic3r/GUI/PrintHostDialogs.cpp
#	src/slic3r/GUI/Printer/BambuTunnel.h
#	src/slic3r/GUI/Printer/PrinterFileSystem.cpp
#	src/slic3r/GUI/Printer/gstbambusrc.c
#	src/slic3r/GUI/Printer/gstbambusrc.h
#	src/slic3r/GUI/ReleaseNote.cpp
#	src/slic3r/GUI/ReleaseNote.hpp
#	src/slic3r/GUI/SelectMachine.cpp
#	src/slic3r/GUI/SendToPrinter.cpp
#	src/slic3r/GUI/SetBedTypeDialog.cpp
#	src/slic3r/GUI/StatusPanel.cpp
#	src/slic3r/GUI/StatusPanel.hpp
#	src/slic3r/GUI/Tab.cpp
#	src/slic3r/GUI/Widgets/AMSControl.cpp
#	src/slic3r/GUI/Widgets/AMSControl.hpp
#	src/slic3r/GUI/Widgets/ImageSwitchButton.cpp
#	src/slic3r/GUI/Widgets/Label.cpp
#	src/slic3r/GUI/WipeTowerDialog.cpp
#	src/slic3r/Utils/Process.cpp
#	src/slic3r/Utils/bambu_networking.hpp
#	version.inc
2023-03-08 00:08:26 +08:00

328 lines
9.1 KiB
C++

#include "SpinInput.hpp"
#include "Label.hpp"
#include "Button.hpp"
#include "TextCtrl.h"
#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(0x009688, (int) StateColor::Hovered),
std::make_pair(0xDBDBDB, (int) StateColor::Normal));
background_color = StateColor(std::make_pair(0xF0F0F1, (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 TextCtrl(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)
{
StaticBox::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;
}
wxSize minSize = size;
minSize.x = GetMinWidth();
StaticBox::SetSize(size);
SetMinSize(size);
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();
if (!btn->HasCapture())
btn->CaptureMouse();
delta *= 8;
timer.Start(100);
sendSpinEvent();
});
btn->Bind(wxEVT_LEFT_DCLICK, [=](auto &e) {
delta = inc ? 1 : -1;
if (!btn->HasCapture())
btn->CaptureMouse();
SetValue(val + delta);
sendSpinEvent();
});
btn->Bind(wxEVT_LEFT_UP, [=](auto &e) {
if (btn->HasCapture())
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 ? 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);
}