Add the full source of BambuStudio

using version 1.0.10
This commit is contained in:
lane.wei 2022-07-15 23:37:19 +08:00 committed by Lane.Wei
parent 30bcadab3e
commit 1555904bef
3771 changed files with 1251328 additions and 0 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,513 @@
#ifndef slic3r_GUI_AMXCONTROL_hpp_
#define slic3r_GUI_AMXCONTROL_hpp_
#include "../wxExtensions.hpp"
#include "StaticBox.hpp"
#include "StepCtrl.hpp"
#include "Button.hpp"
#include "../DeviceManager.hpp"
#include "slic3r/GUI/Event.hpp"
#include <wx/simplebook.h>
#include <wx/hyperlink.h>
#include <wx/animate.h>
#include <wx/dynarray.h>
#define AMS_CONTROL_BRAND_COLOUR wxColour(0, 174, 66)
#define AMS_CONTROL_GRAY700 wxColour(107, 107, 107)
#define AMS_CONTROL_GRAY800 wxColour(50, 58, 61)
#define AMS_CONTROL_GRAY500 wxColour(172, 172, 172)
#define AMS_CONTROL_DISABLE_COLOUR wxColour(206, 206, 206)
#define AMS_CONTROL_DISABLE_TEXT_COLOUR wxColour(144, 144, 144)
#define AMS_CONTROL_WHITE_COLOUR wxColour(255, 255, 255)
#define AMS_CONTROL_BLACK_COLOUR wxColour(0, 0, 0)
#define AMS_CONTROL_DEF_BLOCK_BK_COLOUR wxColour(238, 238, 238)
#define AMS_EXTRUDER_DEF_COLOUR wxColour(234, 234, 234)
#define AMS_CONTROL_MAX_COUNT 4
#define AMS_CONTRO_CALIBRATION_BUTTON_SIZE wxSize(FromDIP(150), FromDIP(28))
// enum AMSRoadMode{
// AMS_ROAD_MODE_LEFT,
// AMS_ROAD_MODE_LEFT_RIGHT,
// AMS_ROAD_MODE_END,
//};
namespace Slic3r { namespace GUI {
enum class AMSRoadMode : int {
AMS_ROAD_MODE_LEFT,
AMS_ROAD_MODE_LEFT_RIGHT,
AMS_ROAD_MODE_END,
AMS_ROAD_MODE_END_ONLY,
AMS_ROAD_MODE_NONE,
};
enum class AMSPassRoadMode : int {
AMS_ROAD_MODE_NONE,
AMS_ROAD_MODE_LEFT,
AMS_ROAD_MODE_LEFT_RIGHT,
AMS_ROAD_MODE_END_TOP,
AMS_ROAD_MODE_END_RIGHT,
AMS_ROAD_MODE_END_BOTTOM,
};
enum class AMSAction : int {
AMS_ACTION_NONE,
AMS_ACTION_LOAD,
AMS_ACTION_UNLOAD,
AMS_ACTION_PRINTING,
AMS_ACTION_NORMAL,
};
enum class AMSPassRoadSTEP : int {
AMS_ROAD_STEP_NONE,
AMS_ROAD_STEP_1, // lib -> extrusion
AMS_ROAD_STEP_2, // extrusion->buffer
AMS_ROAD_STEP_3, // extrusion
AMS_ROAD_STEP_COMBO_LOAD_STEP1,
AMS_ROAD_STEP_COMBO_LOAD_STEP2,
AMS_ROAD_STEP_COMBO_LOAD_STEP3,
};
enum class AMSPassRoadType : int {
AMS_ROAD_TYPE_NONE,
AMS_ROAD_TYPE_LOAD,
AMS_ROAD_TYPE_UNLOAD,
};
enum class AMSCanType : int {
AMS_CAN_TYPE_NONE,
AMS_CAN_TYPE_BRAND,
AMS_CAN_TYPE_THIRDBRAND,
AMS_CAN_TYPE_EMPTY,
};
enum FilamentStep {
STEP_IDLE,
STEP_HEAT_NOZZLE,
STEP_CUT_FILAMENT,
STEP_PULL_CURR_FILAMENT,
STEP_PUSH_NEW_FILAMENT,
STEP_PURGE_OLD_FILAMENT,
STEP_COUNT,
};
#define AMS_ITEM_CUBE_SIZE wxSize(FromDIP(14), FromDIP(14))
#define AMS_ITEM_SIZE wxSize(FromDIP(82), FromDIP(27))
#define AMS_ITEM_HUMIDITY_SIZE wxSize(FromDIP(150), FromDIP(27))
#define AMS_CAN_LIB_SIZE wxSize(FromDIP(58), FromDIP(84))
#define AMS_CAN_ROAD_SIZE wxSize(FromDIP(66), FromDIP(60))
#define AMS_CAN_ITEM_HEIGHT_SIZE FromDIP(27)
#define AMS_CANS_SIZE wxSize(FromDIP(284), FromDIP(186))
#define AMS_CANS_WINDOW_SIZE wxSize(FromDIP(264), FromDIP(186))
#define AMS_STEP_SIZE wxSize(FromDIP(172), FromDIP(180))
#define AMS_REFRESH_SIZE wxSize(FromDIP(26), FromDIP(26))
#define AMS_EXTRUDER_SIZE wxSize(FromDIP(66), FromDIP(55))
#define AMS_EXTRUDER_BITMAP_SIZE wxSize(FromDIP(36), FromDIP(55))
struct Caninfo
{
std::string can_id;
wxString material_name;
wxColour material_colour = {*wxWHITE};
AMSCanType material_state;
};
struct AMSinfo
{
public:
std::string ams_id;
std::vector<Caninfo> cans;
std::string current_can_id;
AMSPassRoadSTEP current_step;
AMSAction current_action;
int curreent_filamentstep;
bool parse_ams_info(Ams *ams);
};
/*************************************************
Description:AMSrefresh
**************************************************/
#define AMS_REFRESH_PLAY_LOADING_TIMER 200
class AMSrefresh : public wxWindow
{
public:
AMSrefresh();
AMSrefresh(wxWindow *parent, wxWindowID id, wxString number, Caninfo info, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);
AMSrefresh(wxWindow *parent, wxWindowID id, int number, Caninfo info, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);
~AMSrefresh();
void PlayLoading();
void StopLoading();
void create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size);
void on_timer(wxTimerEvent &event);
void OnEnterWindow(wxMouseEvent &evt);
void OnLeaveWindow(wxMouseEvent &evt);
void OnClick(wxMouseEvent &evt);
void post_event(wxCommandEvent &&event);
void paintEvent(wxPaintEvent &evt);
void Update(Caninfo info);
void msw_rescale();
Caninfo m_info;
protected:
wxTimer *m_playing_timer= {nullptr};
int m_rotation_angle = {360};
wxAnimationCtrl *m_animationCtrl = {nullptr};
bool m_play_loading = {false};
bool m_selected = {false};
wxBitmap m_bitmap_rotation;
wxBitmap m_bitmap_normal;
wxBitmap m_bitmap_selected;
wxString m_text;
wxBoxSizer * m_size_body;
virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO);
};
/*************************************************
Description:AMSextruder
**************************************************/
class AMSextruderImage: public wxWindow
{
public:
void TurnOn(wxColour col);
void TurnOff();
void msw_rescale();
void paintEvent(wxPaintEvent &evt);
void render(wxDC &dc);
bool m_turn_on = {false};
wxColour m_colour;
wxBitmap m_ams_extruder;
void doRender(wxDC &dc);
AMSextruderImage(wxWindow *parent, wxWindowID id, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);
~AMSextruderImage();
};
class AMSextruder : public wxWindow
{
public:
void TurnOn(wxColour col);
void TurnOff();
void create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size);
void msw_rescale();
wxBoxSizer * m_bitmap_sizer{nullptr};
wxPanel * m_bitmap_panel{nullptr};
AMSextruderImage *m_amsSextruder{nullptr};
wxBitmap monitor_ams_extruder;
AMSextruder(wxWindow *parent, wxWindowID id, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);
~AMSextruder();
};
/*************************************************
Description:AMSLib
**************************************************/
class AMSLib : public wxWindow
{
public:
AMSLib(wxWindow *parent, wxWindowID id, Caninfo info, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);
void create(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);
public:
int m_can_index;
void Update(Caninfo info, bool refresh = true);
void UnableSelected() { m_unable_selected = true; };
void EableSelected() { m_unable_selected = false; };
wxColour GetLibColour();
void OnSelected();
void UnSelected();
virtual bool Enable(bool enable = true);
void post_event(wxCommandEvent &&event);
Caninfo m_info;
protected:
wxStaticBitmap *m_edit_bitmp = {nullptr};
wxStaticBitmap *m_edit_bitmp_light = {nullptr};
wxBitmap m_bitmap_editable;
wxBitmap m_bitmap_editable_lifht;
bool m_unable_selected = {false};
bool m_enable = {false};
bool m_selected = {false};
bool m_hover = {false};
double m_radius = {4};
wxColour m_border_color;
wxColour m_road_def_color;
wxColour m_lib_color;
void on_enter_window(wxMouseEvent &evt);
void on_leave_window(wxMouseEvent &evt);
void on_left_down(wxMouseEvent &evt);
void paintEvent(wxPaintEvent &evt);
void render(wxDC &dc);
void doRender(wxDC &dc);
};
/*************************************************
Description:AMSRoad
**************************************************/
class AMSRoad : public wxWindow
{
public:
AMSRoad();
AMSRoad(wxWindow *parent, wxWindowID id, Caninfo info, int canindex, int maxcan, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);
void create(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);
public:
Caninfo m_info;
int m_canindex = {0};
AMSRoadMode m_rode_mode = {AMSRoadMode::AMS_ROAD_MODE_LEFT_RIGHT};
std::vector<AMSPassRoadMode> m_pass_rode_mode = {AMSPassRoadMode::AMS_ROAD_MODE_NONE};
bool m_selected = {false};
int m_passroad_width = {6};
double m_radius = {4};
wxColour m_road_def_color;
wxColour m_road_color;
void Update(Caninfo info, int canindex, int maxcan);
void SetPassRoadColour(wxColour col);
void SetMode(AMSRoadMode mode);
void OnPassRoad(std::vector<AMSPassRoadMode> prord_list);
void UpdatePassRoad(int tag_index, AMSPassRoadType type, AMSPassRoadSTEP step);
void paintEvent(wxPaintEvent &evt);
void render(wxDC &dc);
void doRender(wxDC &dc);
};
/*************************************************
Description:AMSItem
**************************************************/
class AMSItem : public wxWindow
{
public:
AMSItem();
AMSItem(wxWindow *parent, wxWindowID id, AMSinfo amsinfo, const wxSize cube_size = wxSize(14, 14), const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);
bool m_open = {false};
void Open();
void Close();
void Update(AMSinfo amsinfo);
void create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size);
void OnEnterWindow(wxMouseEvent &evt);
void OnLeaveWindow(wxMouseEvent &evt);
void OnSelected();
void UnSelected();
void ShowHumidity();
void HideHumidity();
void SetHumidity(int humidity);
virtual bool Enable(bool enable = true);
AMSinfo m_amsinfo;
protected:
wxSize m_cube_size;
wxColour m_background_colour = {AMS_CONTROL_DEF_BLOCK_BK_COLOUR};
int m_padding = {6};
int m_space = {5};
bool m_hover = {false};
bool m_selected = {false};
bool m_show_humidity = {false};
int m_humidity = {0};
void paintEvent(wxPaintEvent &evt);
void render(wxDC &dc);
void doRender(wxDC &dc);
virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO);
};
/*************************************************
Description:AmsCans
**************************************************/
class Canrefreshs
{
public:
wxString canID;
AMSrefresh *canrefresh;
};
class CanLibs
{
public:
wxString canID;
AMSLib * canLib;
};
class CanRoads
{
public:
wxString canID;
AMSRoad *canRoad;
};
WX_DEFINE_ARRAY(Canrefreshs *, CanrefreshsHash);
WX_DEFINE_ARRAY(CanLibs *, CanLibsHash);
WX_DEFINE_ARRAY(CanRoads *, CansRoadsHash);
class AmsCans : public wxWindow
{
public:
AmsCans();
AmsCans(wxWindow *parent, wxWindowID id, AMSinfo info, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);
void Update(AMSinfo info);
void create(wxWindow *parent, wxWindowID id, AMSinfo info, const wxPoint &pos, const wxSize &size);
void AddCan(Caninfo caninfo, int canindex, int maxcan);
void SelectCan(std::string canid);
void SetAmsStep(wxString canid, AMSPassRoadType type, AMSPassRoadSTEP step);
//wxColour GetCanColour(wxString canid);
void PlayRridLoading(wxString canid);
void StopRridLoading(wxString canid);
void msw_rescale();
std::string GetCurrentCan();
public:
std::string m_canlib_id;
int m_canlib_selection = {-1};
int m_selection = {0};
int m_can_count = {0};
CanLibsHash m_can_lib_list;
CansRoadsHash m_can_road_list;
CanrefreshsHash m_can_refresh_list;
AMSinfo m_info;
wxBoxSizer * sizer_can = {nullptr};
AMSPassRoadSTEP m_step = {AMSPassRoadSTEP ::AMS_ROAD_STEP_NONE};
};
/*************************************************
Description:AMSControl
**************************************************/
class AmsCansWindow
{
public:
wxString amsIndex;
AmsCans *amsCans;
};
class AmsItems
{
public:
wxString amsIndex;
AMSItem *amsItem;
};
class AMSextruders
{
public:
wxString amsIndex;
AMSextruder *amsextruder;
};
WX_DEFINE_ARRAY(AmsCansWindow *, AmsCansHash);
WX_DEFINE_ARRAY(AmsItems *, AmsItemsHash);
WX_DEFINE_ARRAY(AMSextruders *, AMSextrudersHash);
class AMSControl : public wxSimplebook
{
public:
AMSControl(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);
void init_scaled_buttons();
protected:
int m_ams_count = {0};
std::map<std::string, int> m_ams_selection;
std::vector<AMSinfo> m_ams_info;
std::string m_current_ams;
AmsItemsHash m_ams_item_list;
AmsCansHash m_ams_cans_list;
AMSextruder *m_extruder = {nullptr};
wxSimplebook *m_simplebook_right = {nullptr};
wxSimplebook *m_simplebook_calibration = {nullptr};
wxSimplebook *m_simplebook_amsitems = {nullptr};
wxSimplebook *m_simplebook_ams = {nullptr};
wxSimplebook *m_simplebook_cans = {nullptr};
wxSimplebook *m_simplebook_bottom = {nullptr};
wxStaticText *m_tip_right_top = {nullptr};
wxStaticText *m_tip_load_info = {nullptr};
wxStaticText *m_text_calibration_percent = {nullptr};
wxWindow * m_none_ams_panel = {nullptr};
wxWindow * m_panel_top = {nullptr};
StaticBox * m_panel_can = {nullptr};
wxBoxSizer *m_sizer_top = {nullptr};
wxBoxSizer *m_sizer_cans = {nullptr};
wxBoxSizer *m_sizer_right_tip = {nullptr};
::StepIndicator *m_filament_load_step = {nullptr};
::StepIndicator *m_filament_unload_step = {nullptr};
Button *m_button_extruder_feed = {nullptr};
Button *m_button_extruder_back = {nullptr};
Button *m_button_ams_setting = {nullptr};
wxHyperlinkCtrl *m_hyperlink = {nullptr};
public:
std::string GetCurentAms();
std::string GetCurrentCan(std::string amsid);
wxColour GetCanColour(std::string amsid, std::string canid);
void SetActionState(AMSAction action);
void EnterNoneAMSMode();
void ExitNoneAMSMode();
void EnterCalibrationMode(bool read_to_calibration);
void ExitcClibrationMode();
void SetClibrationpercent(int percent);
void SetClibrationLink(wxString link);
void PlayRridLoading(wxString amsid, wxString canid);
void StopRridLoading(wxString amsid, wxString canid);
void SetFilamentStep(int item_idx, bool isload = true);
void ShowFilamentTip(bool hasams = true);
void SetHumidity(std::string amsid, int humidity);
void UpdateStepCtrl();
void CreateAms();
void UpdateAms(std::vector<AMSinfo> info, bool keep_selection = true);
void AddAms(AMSinfo info, bool refresh = true);
void SetAmsStep(std::string ams_id, std::string canid, AMSPassRoadType type, AMSPassRoadSTEP step);
void SwitchAms(std::string ams_id);
void msw_rescale();
void on_filament_load(wxCommandEvent &event);
void on_filament_unload(wxCommandEvent &event);
void on_ams_setting_click(wxCommandEvent &event);
void on_clibration_again_click(wxMouseEvent &event);
void on_clibration_cancel_click(wxMouseEvent &event);
void post_event(wxEvent &&event);
virtual bool Enable(bool enable = true);
public:
std::string m_current_senect;
};
wxDECLARE_EVENT(EVT_AMS_LOAD, SimpleEvent);
wxDECLARE_EVENT(EVT_AMS_UNLOAD, SimpleEvent);
wxDECLARE_EVENT(EVT_AMS_SETTINGS, SimpleEvent);
wxDECLARE_EVENT(EVT_AMS_REFRESH_RFID, wxCommandEvent);
wxDECLARE_EVENT(EVT_AMS_ON_SELECTED, wxCommandEvent);
wxDECLARE_EVENT(EVT_AMS_ON_FILAMENT_EDIT, wxCommandEvent);
wxDECLARE_EVENT(EVT_AMS_CLIBRATION_AGAIN, wxCommandEvent);
wxDECLARE_EVENT(EVT_AMS_CLIBRATION_CANCEL, wxCommandEvent);
}} // namespace Slic3r::GUI
#endif // !slic3r_GUI_amscontrol_hpp_

View file

@ -0,0 +1,367 @@
#include "AxisCtrlButton.hpp"
#include "Label.hpp"
#include <wx/dcgraph.h>
static const wxColour bd = wxColour(0x00AE42);
static const wxColour BUTTON_BG_COL = wxColour(238, 238, 238);
static const wxColour BUTTON_IN_BG_COL = wxColour(206, 206, 206);
static const wxColour blank_bg = wxColour(0xFFFFFF);
static const wxColour text_num_color = wxColour(0x898989);
static const wxColour BUTTON_PRESS_COL = wxColour(172, 172, 172);
static const double sqrt2 = std::sqrt(2);
BEGIN_EVENT_TABLE(AxisCtrlButton, wxPanel)
EVT_LEFT_DOWN(AxisCtrlButton::mouseDown)
EVT_LEFT_UP(AxisCtrlButton::mouseReleased)
EVT_MOTION(AxisCtrlButton::mouseMoving)
EVT_PAINT(AxisCtrlButton::paintEvent)
END_EVENT_TABLE()
#define OUTER_SIZE FromDIP(105)
#define INNER_SIZE FromDIP(58)
#define HOME_SIZE FromDIP(23)
#define BLANK_SIZE FromDIP(23)
#define GAP_SIZE FromDIP(4)
AxisCtrlButton::AxisCtrlButton(wxWindow *parent, wxBitmap &icon, long stlye)
: wxWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, stlye)
, r_outer(OUTER_SIZE)
, r_inner(INNER_SIZE)
, r_home(HOME_SIZE)
, r_blank(BLANK_SIZE)
, gap(GAP_SIZE)
, last_pos(UNDEFINED)
, current_pos(UNDEFINED) // don't change init value
, text_color(std::make_pair(0x6B6B6B, (int) StateColor::Disabled), std::make_pair(*wxBLACK, (int) StateColor::Normal))
, state_handler(this)
{
m_icon = icon.GetSubBitmap(wxRect(0, 0, icon.GetWidth(), icon.GetHeight()));
wxWindow::SetBackgroundColour(parent->GetBackgroundColour());
border_color.append(bd, StateColor::Hovered);
background_color.append(BUTTON_BG_COL, StateColor::Disabled);
background_color.append(BUTTON_PRESS_COL, StateColor::Pressed);
background_color.append(BUTTON_BG_COL, StateColor::Hovered);
background_color.append(BUTTON_BG_COL, StateColor::Normal);
background_color.append(BUTTON_BG_COL, StateColor::Enabled);
inner_background_color.append(BUTTON_IN_BG_COL, StateColor::Disabled);
inner_background_color.append(BUTTON_PRESS_COL, StateColor::Pressed);
inner_background_color.append(BUTTON_IN_BG_COL, StateColor::Hovered);
inner_background_color.append(BUTTON_IN_BG_COL, StateColor::Normal);
inner_background_color.append(BUTTON_IN_BG_COL, StateColor::Enabled);
state_handler.attach({ &border_color, &background_color });
state_handler.update_binds();
}
void AxisCtrlButton::updateParams() {
r_outer = OUTER_SIZE;
r_inner = INNER_SIZE;
r_home = HOME_SIZE;
r_blank = BLANK_SIZE;
gap = GAP_SIZE;
}
void AxisCtrlButton::SetMinSize(const wxSize& size)
{
wxSize cur_size = GetSize();
if (size.GetWidth() > 0 && size.GetHeight() > 0) {
stretch = std::min((double)size.GetWidth() / cur_size.x,(double)size.GetHeight() / cur_size.y);
minSize = size;
updateParams();
}
else if (size.GetWidth() > 0) {
stretch = (double)size.GetWidth() / cur_size.x;
minSize.x = size.x;
updateParams();
}
else if (size.GetHeight() > 0) {
stretch = (double)size.GetHeight() / cur_size.y;
minSize.y = size.y;
updateParams();
}
else {
stretch = 1.0;
minSize = wxSize(228, 228);
}
wxWindow::SetMinSize(minSize);
center = wxPoint(minSize.x / 2, minSize.y / 2);
}
void AxisCtrlButton::SetTextColor(StateColor const &color)
{
text_color = color;
state_handler.update_binds();
Refresh();
}
void AxisCtrlButton::SetBorderColor(StateColor const& color)
{
border_color = color;
state_handler.update_binds();
Refresh();
}
void AxisCtrlButton::SetBackgroundColor(StateColor const& color)
{
background_color = color;
state_handler.update_binds();
Refresh();
}
void AxisCtrlButton::SetInnerBackgroundColor(StateColor const& color)
{
inner_background_color = color;
state_handler.update_binds();
Refresh();
}
void AxisCtrlButton::SetBitmap(wxBitmap &bmp)
{
m_icon = bmp.GetSubBitmap(wxRect(0, 0, bmp.GetWidth(), bmp.GetHeight()));
}
void AxisCtrlButton::Rescale() {
Refresh();
}
void AxisCtrlButton::paintEvent(wxPaintEvent& evt)
{
// depending on your system you may need to look at double-buffered dcs
wxPaintDC dc(this);
wxGCDC gcdc(dc);
render(gcdc);
}
/*
* 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 AxisCtrlButton::render(wxDC& dc)
{
wxGraphicsContext* gc = dc.GetGraphicsContext();
int states = state_handler.states();
wxSize size = GetSize();
gc->PushState();
gc->Translate(center.x, center.y);
//draw the outer ring
wxGraphicsPath outer_path = gc->CreatePath();
outer_path.AddCircle(0, 0, r_outer);
outer_path.AddCircle(0, 0, r_inner);
gc->SetPen(BUTTON_BG_COL);
gc->SetBrush(BUTTON_BG_COL);
gc->DrawPath(outer_path);
//draw the inner ring
wxGraphicsPath inner_path = gc->CreatePath();
inner_path.AddCircle(0, 0, r_inner);
inner_path.AddCircle(0, 0, r_blank);
gc->SetPen(BUTTON_IN_BG_COL);
gc->SetBrush(BUTTON_IN_BG_COL);
gc->DrawPath(inner_path);
//draw an arc in corresponding position
if (current_pos != CurrentPos::UNDEFINED) {
wxGraphicsPath path = gc->CreatePath();
if (current_pos < 4) {
path.AddArc(0, 0, r_outer, (5 - 2 * current_pos) * PI / 4, (7 - 2 * current_pos) * PI / 4, true);
path.AddArc(0, 0, r_inner, (7 - 2 * current_pos) * PI / 4, (5 - 2 * current_pos) * PI / 4, false);
path.CloseSubpath();
gc->SetBrush(wxBrush(background_color.colorForStates(states)));
}
else if (current_pos < 8) {
path.AddArc(0, 0, r_inner, (5 - 2 * current_pos) * PI / 4, (7 - 2 * current_pos) * PI / 4, true);
path.AddArc(0, 0, r_blank, (7 - 2 * current_pos) * PI / 4, (5 - 2 * current_pos) * PI / 4, false);
path.CloseSubpath();
gc->SetBrush(wxBrush(inner_background_color.colorForStates(states)));
}
gc->SetPen(wxPen(border_color.colorForStates(states),2));
gc->DrawPath(path);
}
//draw rectangle gap
gc->SetPen(blank_bg);
gc->SetBrush(blank_bg);
gc->PushState();
gc->Rotate(-PI / 4);
gc->DrawRectangle(-sqrt2 * size.x / 2, -sqrt2 * gap / 2, sqrt2 * size.x, sqrt2 * gap);
gc->Rotate(-PI / 2);
gc->DrawRectangle(-sqrt2 * size.x / 2, -sqrt2 * gap / 2, sqrt2 * size.x, sqrt2 * gap);
gc->PopState();
// draw the home circle
wxGraphicsPath home_path = gc->CreatePath();
home_path.AddCircle(0, 0, r_home);
home_path.CloseSubpath();
gc->PushState();
if (current_pos == 8) {
gc->SetPen(wxPen(border_color.colorForStates(states), 2));
gc->SetBrush(wxBrush(background_color.colorForStates(states)));
} else {
gc->SetPen(BUTTON_BG_COL);
gc->SetBrush(BUTTON_BG_COL);
}
gc->DrawPath(home_path);
if (m_icon.IsOk()) {
gc->DrawBitmap(m_icon, -1 * m_icon.GetWidth() / 2, -1 * m_icon.GetHeight() / 2, m_icon.GetWidth(), m_icon.GetHeight());
}
gc->PopState();
//draw linear border of the arc
if (current_pos != CurrentPos::UNDEFINED) {
gc->PushState();
gc->SetPen(wxPen(border_color.colorForStates(states), 2));
if (current_pos == 8) {
wxGraphicsPath line_path = gc->CreatePath();
line_path.AddCircle(0, 0, r_home);
gc->StrokePath(line_path);
} else {
wxGraphicsPath line_path1 = gc->CreatePath();
wxGraphicsPath line_path2 = gc->CreatePath();
if (current_pos < 4) {
line_path1.MoveToPoint(r_inner, -sqrt2 * gap / 2);
line_path1.AddLineToPoint(r_outer, -sqrt2 * gap / 2);
line_path2.MoveToPoint(-r_inner, -sqrt2 * gap / 2);
line_path2.AddLineToPoint(-r_outer, -sqrt2 * gap / 2);
} else if (current_pos < 8) {
line_path1.MoveToPoint(r_blank, -sqrt2 * gap / 2);
line_path1.AddLineToPoint(r_inner, -sqrt2 * gap / 2);
line_path2.MoveToPoint(-r_blank, -sqrt2 * gap / 2);
line_path2.AddLineToPoint(-r_inner, -sqrt2 * gap / 2);
}
gc->Rotate(-(1 + 2 * current_pos) * PI / 4);
gc->StrokePath(line_path1);
gc->Rotate(PI / 2);
gc->StrokePath(line_path2);
}
gc->PopState();
}
//draw text
if (!IsEnabled())
gc->SetFont(Label::Body_12, text_color.colorForStates(StateColor::Disabled));
else
gc->SetFont(Label::Head_12, text_color.colorForStates(states));
wxDouble w, h;
gc->GetTextExtent("Y", &w, &h);
gc->DrawText(wxT("Y"), -w / 2, -r_outer + (r_outer - r_inner) / 2 - h / 2);
gc->GetTextExtent("-X", &w, &h);
gc->DrawText(wxT("-X"), -r_outer + (r_outer - r_inner) / 2 - w / 2, - h / 2);
gc->GetTextExtent("-Y", &w, &h);
gc->DrawText(wxT("-Y"), -w / 2, r_outer - (r_outer - r_inner) / 2 - h / 2);
gc->GetTextExtent("X", &w, &h);
gc->DrawText(wxT("X"), r_outer - (r_outer - r_inner) / 2 - w / 2, -h / 2);
gc->SetFont(Label::Body_12, text_num_color);
gc->PushState();
gc->Rotate(PI / 4);
gc->GetTextExtent("+10", &w, &h);
gc->DrawText(wxT("+10"), sqrt2 * gap, -r_outer + (r_outer - r_inner) / 2 - h / 2);
gc->GetTextExtent("+1", &w, &h);
gc->DrawText(wxT("+1"), sqrt2 * gap, -r_inner + (r_inner - r_blank) / 2 - h / 2);
gc->GetTextExtent("-1", &w, &h);
gc->DrawText(wxT("-1"), sqrt2 * gap, r_inner - (r_inner - r_blank) / 2 - h / 2);
gc->GetTextExtent("-10", &w, &h);
gc->DrawText(wxT("-10"), sqrt2 * gap, r_outer - (r_outer - r_inner) / 2 - h / 2);
gc->PopState();
gc->PopState();
}
void AxisCtrlButton::mouseDown(wxMouseEvent& event)
{
event.Skip();
pressedDown = true;
SetFocus();
CaptureMouse();
}
void AxisCtrlButton::mouseReleased(wxMouseEvent& event)
{
event.Skip();
if (pressedDown) {
pressedDown = false;
ReleaseMouse();
if (wxRect({ 0, 0 }, GetSize()).Contains(event.GetPosition()))
sendButtonEvent();
}
}
void AxisCtrlButton::mouseMoving(wxMouseEvent& event)
{
if (pressedDown)
return;
wxPoint mouse_pos(event.GetX(), event.GetY());
wxPoint transformed_mouse_pos = mouse_pos - center;
double r_temp = transformed_mouse_pos.x * transformed_mouse_pos.x + transformed_mouse_pos.y * transformed_mouse_pos.y;
if (r_temp > r_outer * r_outer) {
current_pos = CurrentPos::UNDEFINED;
}
else if (r_temp > r_inner * r_inner) {
if (transformed_mouse_pos.y < transformed_mouse_pos.x - gap && transformed_mouse_pos.y < -transformed_mouse_pos.x - gap)
{
current_pos = CurrentPos::OUTER_UP;
}
else if (transformed_mouse_pos.y > transformed_mouse_pos.x + gap && transformed_mouse_pos.y < -transformed_mouse_pos.x - gap)
{
current_pos = CurrentPos::OUTER_LEFT;
}
else if (transformed_mouse_pos.y > transformed_mouse_pos.x + gap && transformed_mouse_pos.y > -transformed_mouse_pos.x + gap)
{
current_pos = CurrentPos::OUTER_DOWN;
}
else if (transformed_mouse_pos.y < transformed_mouse_pos.x - gap && transformed_mouse_pos.y > -transformed_mouse_pos.x + gap)
{
current_pos = CurrentPos::OUTER_RIGHT;
}
else {
current_pos = CurrentPos::UNDEFINED;
}
}
else if (r_temp > r_blank * r_blank) {
if (transformed_mouse_pos.y < transformed_mouse_pos.x - gap && transformed_mouse_pos.y < -transformed_mouse_pos.x - gap)
{
current_pos = CurrentPos::INNER_UP;
}
else if (transformed_mouse_pos.y > transformed_mouse_pos.x + gap && transformed_mouse_pos.y < -transformed_mouse_pos.x - gap)
{
current_pos = CurrentPos::INNER_LEFT;
}
else if (transformed_mouse_pos.y > transformed_mouse_pos.x + gap && transformed_mouse_pos.y > -transformed_mouse_pos.x + gap)
{
current_pos = CurrentPos::INNER_DOWN;
}
else if (transformed_mouse_pos.y < transformed_mouse_pos.x - gap && transformed_mouse_pos.y > -transformed_mouse_pos.x + gap)
{
current_pos = CurrentPos::INNER_RIGHT;
}
else {
current_pos = CurrentPos::UNDEFINED;
}
} else if (r_temp <= r_home * r_home) {
current_pos = INNER_HOME;
}
if (last_pos != current_pos) {
last_pos = current_pos;
Refresh();
}
}
void AxisCtrlButton::sendButtonEvent()
{
wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
event.SetEventObject(this);
event.SetInt(current_pos);
GetEventHandler()->ProcessEvent(event);
}

View file

@ -0,0 +1,79 @@
#ifndef slic3r_GUI_AxisCtrlButton_hpp_
#define slic3r_GUI_AxisCtrlButton_hpp_
#include <wx/stattext.h>
#include <wx/vlbox.h>
#include <wx/combo.h>
#include "../wxExtensions.hpp"
#include "StateHandler.hpp"
class AxisCtrlButton : public wxWindow
{
wxSize minSize;
double stretch;
double r_outer;
double r_inner;
double r_home;
double r_blank;
double gap;
wxPoint center;
StateHandler state_handler;
StateColor text_color;
StateColor border_color;
StateColor background_color;
StateColor inner_background_color;
wxBitmap m_icon;
bool pressedDown = false;
unsigned char last_pos;
unsigned char current_pos;
enum CurrentPos {
OUTER_UP = 0,
OUTER_LEFT = 1,
OUTER_DOWN = 2,
OUTER_RIGHT = 3,
INNER_UP = 4,
INNER_LEFT = 5,
INNER_DOWN = 6,
INNER_RIGHT = 7,
INNER_HOME = 8,
UNDEFINED = 9
};
public:
AxisCtrlButton(wxWindow *parent, wxBitmap &icon, long style = 0);
void SetMinSize(const wxSize& size) override;
void SetTextColor(StateColor const& color);
void SetBorderColor(StateColor const& color);
void SetBackgroundColor(StateColor const& color);
void SetInnerBackgroundColor(StateColor const& color);
void SetBitmap(wxBitmap &bmp);
void Rescale();
private:
void updateParams();
void paintEvent(wxPaintEvent& evt);
void render(wxDC& dc);
void mouseDown(wxMouseEvent& event);
void mouseReleased(wxMouseEvent& event);
void mouseMoving(wxMouseEvent& event);
void sendButtonEvent();
DECLARE_EVENT_TABLE()
};
#endif // !slic3r_GUI_Button_hpp_

View file

@ -0,0 +1,247 @@
#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)
// 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)
, text_color(*wxBLACK)
{
background_color = StateColor(
std::make_pair(*wxLIGHT_GREY, (int) StateColor::Checked),
std::make_pair(*wxLIGHT_GREY, (int) StateColor::Hovered),
std::make_pair(*wxWHITE, (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::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.bmp().GetSize();
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.bmp().GetSize();
szContent.x += szIcon.x;
if (szIcon.y > szContent.y)
szContent.y = szIcon.y;
}
wxWindow::SetMinSize(szContent + paddingSize * 2);
}
void Button::mouseDown(wxMouseEvent& event)
{
event.Skip();
pressedDown = true;
SetFocus();
CaptureMouse();
}
void Button::mouseReleased(wxMouseEvent& event)
{
event.Skip();
if (pressedDown) {
pressedDown = false;
ReleaseMouse();
if (wxRect({0, 0}, GetSize()).Contains(event.GetPosition()))
sendButtonEvent();
}
}
void Button::sendButtonEvent()
{
wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
event.SetEventObject(this);
GetEventHandler()->ProcessEvent(event);
}

View file

@ -0,0 +1,66 @@
#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;
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);
void Rescale();
private:
void paintEvent(wxPaintEvent& evt);
void render(wxDC& dc);
void messureSize();
// some useful events
void mouseDown(wxMouseEvent& event);
void mouseReleased(wxMouseEvent& event);
void sendButtonEvent();
DECLARE_EVENT_TABLE()
};
#endif // !slic3r_GUI_Button_hpp_

View file

@ -0,0 +1,43 @@
#include "CheckBox.hpp"
#include "../wxExtensions.hpp"
CheckBox::CheckBox(wxWindow* parent)
: wxBitmapToggleButton(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE)
, m_on(this, "check_on", 16)
, m_half(this, "check_half", 16)
, m_off(this, "check_off", 16)
{
//SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
if (parent)
SetBackgroundColour(parent->GetBackgroundColour());
Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { m_half_checked = false; update(); e.Skip(); });
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_off.msw_rescale();
SetSize(m_on.GetBmpSize());
update();
}
void CheckBox::update()
{
SetBitmap((m_half_checked ? m_half : GetValue() ? m_on : m_off).bmp());
}

View file

@ -0,0 +1,30 @@
#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();
private:
void update();
private:
ScalableBitmap m_on;
ScalableBitmap m_half;
ScalableBitmap m_off;
bool m_half_checked = false;
};
#endif // !slic3r_GUI_CheckBox_hpp_

View file

@ -0,0 +1,247 @@
#include "ComboBox.hpp"
#include "Label.hpp"
#include <wx/dcgraph.h>
BEGIN_EVENT_TABLE(ComboBox, TextInput)
EVT_LEFT_DOWN(ComboBox::mouseDown)
//EVT_MOUSEWHEEL(ComboBox::mouseWheelMoved)
// 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(this, texts, icons, style & DD_STYLE_MASK)
{
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);
if (style & wxCB_READONLY)
{
GetTextCtrl()->Hide();
TextInput::SetFont(Label::Body_14);
TextInput::SetBorderColor(StateColor(std::make_pair(0xDBDBDB, (int) StateColor::Disabled),
std::make_pair(0xEDFAF2, (int) StateColor::Focused),
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)));
}
drop.Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &e) {
SetSelection(e.GetInt());
e.SetEventObject(this);
e.SetId(GetId());
wxMouseEvent e1;
mouseDown(e1);
GetEventHandler()->ProcessEvent(e);
});
drop.Bind(wxEVT_SHOW, [this](auto &e) {
if (!e.IsShown()) {
drop_down = false;
wxCommandEvent e(wxEVT_COMBOBOX_DROPDOWN);
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()->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.Show();
drop.Raise();
wxCommandEvent e(wxEVT_COMBOBOX_CLOSEUP);
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::OnEdit()
{
auto value = GetTextCtrl()->GetValue();
SetValue(value);
}
void ComboBox::sendComboBoxEvent()
{
wxCommandEvent event(wxEVT_COMBOBOX, GetId());
event.SetEventObject(this);
event.SetInt(drop.GetSelection());
event.SetString(drop.GetValue());
GetEventHandler()->ProcessEvent(event);
}

View file

@ -0,0 +1,87 @@
#ifndef slic3r_GUI_ComboBox_hpp_
#define slic3r_GUI_ComboBox_hpp_
#include "TextInput.hpp"
#include "DropDown.hpp"
#define CB_NO_DROP_ICON 0x1000000
#define CB_NO_TEXT 0x2000000
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;
private:
// some useful events
void mouseDown(wxMouseEvent &event);
void mouseWheelMoved(wxMouseEvent &event);
void sendComboBoxEvent();
DECLARE_EVENT_TABLE()
};
#endif // !slic3r_GUI_ComboBox_hpp_

View file

@ -0,0 +1,442 @@
#include "DropDown.hpp"
#include "Label.hpp"
#include <wx/dcgraph.h>
BEGIN_EVENT_TABLE(DropDown, wxPanel)
EVT_LEFT_DOWN(DropDown::mouseDown)
EVT_LEFT_UP(DropDown::mouseReleased)
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(wxWindow * parent,
std::vector<wxString> &texts,
std::vector<wxBitmap> &icons,
long style)
: wxPopupTransientWindow(parent)
, 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))
{
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__
Bind(wxEVT_ACTIVATE, [this](auto & e) {
if (!e.GetActive()) {
Hide();
OnDismiss();
}
});
#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;
selection = n;
}
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.bmp().GetSize();
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(wxDisplay::GetFromWindow(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)
{
pressedDown = true;
CaptureMouse();
dragStart = event.GetPosition();
}
void DropDown::mouseReleased(wxMouseEvent& event)
{
if (pressedDown) {
ReleaseMouse();
dragStart = wxPoint();
pressedDown = false;
if (hover_item >= 0) // not moved
sendDropDownEvent();
}
}
void DropDown::mouseMove(wxMouseEvent &event)
{
if (pressedDown) {
wxPoint pt = event.GetPosition();
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 = (event.GetPosition().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 == event.IsWheelInverted()) ? 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;
}

View file

@ -0,0 +1,100 @@
#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 0x1000000
#define DD_NO_TEXT 0x2000000
#define DD_STYLE_MASK 0x3000000
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(wxWindow * parent,
std::vector<wxString> &texts,
std::vector<wxBitmap> &icons,
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();
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 mouseMove(wxMouseEvent &event);
void mouseWheelMoved(wxMouseEvent &event);
void sendDropDownEvent();
void OnDismiss() override;
DECLARE_EVENT_TABLE()
};
#endif // !slic3r_GUI_DropDown_hpp_

View file

@ -0,0 +1,187 @@
#include "ImageSwitchButton.hpp"
#include "Label.hpp"
#include "StaticBox.hpp"
#include "../wxExtensions.hpp"
#include <wx/dcgraph.h>
BEGIN_EVENT_TABLE(ImageSwitchButton, StaticBox)
EVT_LEFT_DOWN(ImageSwitchButton::mouseDown)
EVT_ENTER_WINDOW(ImageSwitchButton::mouseEnterWindow)
EVT_LEAVE_WINDOW(ImageSwitchButton::mouseLeaveWindow)
EVT_LEFT_UP(ImageSwitchButton::mouseReleased)
EVT_PAINT(ImageSwitchButton::paintEvent)
END_EVENT_TABLE()
static const wxColour DEFAULT_HOVER_COL = wxColour(0, 174, 66);
static const wxColour DEFAULT_PRESS_COL = wxColour(238, 238, 238);
ImageSwitchButton::ImageSwitchButton(wxWindow *parent, wxBitmap &img_on, wxBitmap &img_off, long style)
: text_color(std::make_pair(0x6B6B6B, (int) StateColor::Disabled), std::make_pair(*wxBLACK, (int) StateColor::Normal))
, state_handler(this)
{
m_padding = 0;
m_on = img_on.GetSubBitmap(wxRect(0, 0, img_on.GetWidth(), img_on.GetHeight()));
m_off = img_off.GetSubBitmap(wxRect(0, 0, img_off.GetWidth(), img_off.GetHeight()));
bg_color = StateColor(std::make_pair(DEFAULT_PRESS_COL, (int) StateColor::Pressed),
std::make_pair(*wxWHITE, (int) StateColor::Normal));
border_color = StateColor(std::make_pair(DEFAULT_HOVER_COL, (int) StateColor::Hovered));
StaticBox::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style);
state_handler.attach({&bg_color});
state_handler.attach({&border_color});
state_handler.update_binds();
messureSize();
Refresh();
}
void ImageSwitchButton::SetLabels(wxString const &lbl_on, wxString const &lbl_off)
{
labels[0] = lbl_on;
labels[1] = lbl_off;
messureSize();
Refresh();
}
void ImageSwitchButton::SetImages(wxBitmap &img_on, wxBitmap &img_off)
{
m_on = img_on;
m_off = img_off;
messureSize();
Refresh();
}
void ImageSwitchButton::SetTextColor(StateColor const &color)
{
text_color = color;
state_handler.update_binds();
messureSize();
Refresh();
}
void ImageSwitchButton::SetBorderColor(StateColor const &color)
{
border_color = color;
messureSize();
Refresh();
}
void ImageSwitchButton::SetBgColor(StateColor const &color) {
bg_color = color;
messureSize();
Refresh();
}
void ImageSwitchButton::SetValue(bool value)
{
m_on_off = value;
messureSize();
Refresh();
}
void ImageSwitchButton::SetPadding(int padding)
{
m_padding = padding;
messureSize();
Refresh();
}
void ImageSwitchButton::messureSize()
{
wxClientDC dc(this);
dc.SetFont(GetFont());
textSize = dc.GetTextExtent(GetValue() ? labels[0] : labels[1]);
}
void ImageSwitchButton::paintEvent(wxPaintEvent &evt)
{
wxPaintDC dc(this);
render(dc);
}
void ImageSwitchButton::render(wxDC& dc)
{
StaticBox::render(dc);
int states = state_handler.states();
wxSize size = GetSize();
if (pressedDown) {
dc.SetBrush(bg_color.colorForStates(StateColor::Pressed));
dc.DrawRectangle(wxRect(0, 0, size.x, size.y));
}
if (hover) {
dc.SetPen(border_color.colorForStates(StateColor::Hovered));
dc.DrawRectangle(wxRect(0, 0, size.x, size.y));
}
wxSize szIcon;
wxSize szContent = textSize;
wxBitmap &icon = GetValue() ? m_on: m_off;
int content_height = icon.GetHeight() + textSize.y + m_padding;
wxPoint pt = wxPoint((size.x - icon.GetWidth()) / 2, (size.y - content_height) / 2);
if (icon.IsOk()) {
dc.DrawBitmap(icon, pt);
pt.y += m_padding + icon.GetHeight();
}
pt.x = (size.x - textSize.x) / 2;
dc.SetFont(GetFont());
if (!IsEnabled())
dc.SetTextForeground(text_color.colorForStates(StateColor::Disabled));
else
dc.SetTextForeground(text_color.colorForStates(states));
dc.DrawText(GetValue() ? labels[0] : labels[1], pt);
}
void ImageSwitchButton::Rescale()
{
messureSize();
}
void ImageSwitchButton::mouseDown(wxMouseEvent &event)
{
event.Skip();
pressedDown = true;
SetFocus();
CaptureMouse();
}
void ImageSwitchButton::mouseReleased(wxMouseEvent &event)
{
event.Skip();
if (pressedDown) {
pressedDown = false;
ReleaseMouse();
m_on_off = !m_on_off;
Refresh();
sendButtonEvent();
}
}
void ImageSwitchButton::mouseEnterWindow(wxMouseEvent &event)
{
if (!hover) {
hover = true;
Refresh();
}
}
void ImageSwitchButton::mouseLeaveWindow(wxMouseEvent &event)
{
if (hover) {
hover = false;
Refresh();
}
}
void ImageSwitchButton::sendButtonEvent()
{
wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
event.SetEventObject(this);
GetEventHandler()->ProcessEvent(event);
}

View file

@ -0,0 +1,58 @@
#ifndef slic3r_GUI_ImageSwitchButton_hpp_
#define slic3r_GUI_ImageSwitchButton_hpp_
#include "../wxExtensions.hpp"
#include "StateColor.hpp"
#include "StateHandler.hpp"
#include "Button.hpp"
#include <wx/tglbtn.h>
class ImageSwitchButton : public StaticBox
{
public:
ImageSwitchButton(wxWindow *parent, wxBitmap &img_on, wxBitmap &img_off, long style = 0);
void SetLabels(wxString const & lbl_on, wxString const & lbl_off);
void SetImages(wxBitmap &img_on, wxBitmap &img_off);
void SetTextColor(StateColor const &color);
void SetBorderColor(StateColor const &color);
void SetBgColor(StateColor const &color);
void SetValue(bool value);
void SetPadding(int padding);
bool GetValue() { return m_on_off; }
void Rescale();
private:
void messureSize();
void paintEvent(wxPaintEvent &evt);
void render(wxDC& dc);
void mouseDown(wxMouseEvent &event);
void mouseReleased(wxMouseEvent &event);
void mouseEnterWindow(wxMouseEvent &event);
void mouseLeaveWindow(wxMouseEvent &event);
void sendButtonEvent();
DECLARE_EVENT_TABLE()
private:
wxBitmap m_on;
wxBitmap m_off;
bool m_on_off;
int m_padding; // size between icon and text
bool pressedDown = false;
bool hover = false;
wxSize textSize;
wxSize minSize;
wxString labels[2];
StateColor text_color;
StateColor bg_color;
StateColor border_color;
StateHandler state_handler;
};
#endif // !slic3r_GUI_SwitchButton_hpp_

View file

@ -0,0 +1,47 @@
#include "Label.hpp"
#include "StaticBox.hpp"
wxFont Label::sysFont(int size, bool bold)
{
#ifdef __linux__
return wxFont{};
#endif
#ifdef __WIN32__
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 = Label::sysFont(24, true);
wxFont Label::Head_20 = Label::sysFont(20, true);
wxFont Label::Head_18 = Label::sysFont(18, true);
wxFont Label::Head_16 = Label::sysFont(16, true);
wxFont Label::Head_15 = Label::sysFont(15, true);
wxFont Label::Head_14 = Label::sysFont(14, true);
wxFont Label::Head_13 = Label::sysFont(13, true);
wxFont Label::Head_12 = Label::sysFont(12, true);
wxFont Label::Head_10 = Label::sysFont(10, true);
wxFont Label::Body_16 = Label::sysFont(16, false);
wxFont Label::Body_15 = Label::sysFont(15, false);
wxFont Label::Body_14 = Label::sysFont(14, false);
wxFont Label::Body_13 = Label::sysFont(13, false);
wxFont Label::Body_12 = Label::sysFont(12, false);
wxFont Label::Body_10 = Label::sysFont(10, false);
Label::Label(wxString const &text, wxWindow *parent) : Label(Body_16, text, parent) {}
Label::Label(wxFont const &font, wxWindow *parent) : Label(font, "", parent) {}
Label::Label(wxFont const &font, wxString const &text, wxWindow *parent) : wxStaticText(parent, wxID_ANY, text, wxDefaultPosition, wxDefaultSize, 0)
{
SetBackgroundColour(StaticBox::GetParentBackgroundColor(parent));
SetFont(font);
}

View file

@ -0,0 +1,36 @@
#ifndef slic3r_GUI_Label_hpp_
#define slic3r_GUI_Label_hpp_
#include <wx/stattext.h>
class Label : public wxStaticText
{
public:
Label(wxString const& text, wxWindow* parent = NULL);
Label(wxFont const& font, wxWindow* parent = NULL);
Label(wxFont const& font, wxString const& text, wxWindow* parent = NULL);
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 sysFont(int size, bool bold = false);
};
#endif // !slic3r_GUI_Label_hpp_

View file

@ -0,0 +1,237 @@
#include "ProgressBar.hpp"
#include "../I18N.hpp"
#include <wx/dcgraph.h>
#include "Label.hpp"
wxDEFINE_EVENT(wxCUSTOMEVT_SET_TEMP_FINISH, wxCommandEvent);
BEGIN_EVENT_TABLE(ProgressBar, wxPanel)
EVT_PAINT(ProgressBar::paintEvent)
END_EVENT_TABLE()
ProgressBar::ProgressBar(wxWindow *parent, wxWindowID id, int max, const wxPoint &pos, const wxSize &size, bool shown)
{
m_shownumber = shown;
SetBackgroundColour(wxColour(255,255,255));
if (size.y >= miniHeight) {
m_miniHeight = size.y;
} else {
m_miniHeight = miniHeight;
}
m_max = max;
m_radius = m_miniHeight / 2;
wxSize temp_size(size.x, m_miniHeight);
SetFont(Label::Head_12);
create(parent, id, pos, temp_size);
}
ProgressBar::~ProgressBar() {}
void ProgressBar::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, wxSize &size)
{
wxWindow::Create(parent, id, pos, size);
// m_static_info = new wxStaticText(this, wxID_ANY,wxT(""),wxPoint(this->padding, 20), wxSize(GetSize().GetWidth() - this->padding * 3, -1), wxST_ELLIPSIZE_END);
// m_static_info->Wrap(-1);
/* wxBoxSizer *m_sizer_body = new wxBoxSizer(wxHORIZONTAL);
auto m_progress_bk = new StaticBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
m_progress_bk->SetBackgroundColour(wxColour(238, 130, 238));
StateColor btn_bg_green(std::pair<wxColour, int>(wxColour(27, 136, 68), StateColor::Pressed), std::pair<wxColour, int>(wxColour(61, 203, 115), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 174, 66), StateColor::Normal));
wxBoxSizer *m_sizer_progress= new wxBoxSizer(wxHORIZONTAL);
auto m_progress = new wxPanel(m_progress_bk, wxID_ANY, wxDefaultPosition, wxSize(50, -1), wxTAB_TRAVERSAL);
m_progress->SetBackgroundColour(wxColour(128, 0, 255));
m_sizer_progress->Add(m_progress, 0, wxEXPAND, 0);
m_progress_bk->SetSizer(m_sizer_progress);
m_progress_bk->Layout();
m_sizer_progress->Fit(m_progress_bk);
m_sizer_body->Add(m_progress_bk, 1, wxEXPAND, 0);
this->SetSizer(m_sizer_body);
this->Layout();*/
}
void ProgressBar::SetRadius(double radius) {
m_radius = radius;
Refresh();
}
void ProgressBar::SetProgressForedColour(wxColour colour)
{
m_progress_background_colour = colour;
Refresh();
}
void ProgressBar::SetProgressBackgroundColour(wxColour colour)
{
m_progress_colour = colour;
Refresh();
}
void ProgressBar::Rescale()
{
;
}
void ProgressBar::ShowNumber(bool shown)
{
m_shownumber = shown;
Refresh();
}
void ProgressBar::Disable(wxString text)
{
if (m_disable) return;
m_disable_text = text;
m_disable = true;
Refresh();
}
void ProgressBar::SetValue(int step)
{
m_disable = false;
SetProgress(step);
}
void ProgressBar::Reset()
{
m_step = 0;
SetValue(0);
}
void ProgressBar::SetProgress(int step)
{
m_disable = false;
if (step < 0) return;
//if (step == m_step) return;
m_step = step;
Refresh();
}
void ProgressBar::SetMinSize(const wxSize &size)
{
if (size.y >= miniHeight) {
m_miniHeight = size.y;
} else {
return;
}
m_radius = m_miniHeight / 2.4;
wxWindow::SetMinSize({size.x, m_miniHeight});
// SetSize(size);
SetRadius(m_radius);
}
void ProgressBar::paintEvent(wxPaintEvent &evt)
{
wxPaintDC dc(this);
render(dc);
}
void ProgressBar::render(wxDC &dc)
{
#ifdef __WXMSW__
wxSize size = GetSize();
wxMemoryDC memdc;
wxBitmap bmp(size.x, size.y);
memdc.SelectObject(bmp);
memdc.Blit({0, 0}, size, &dc, {0, 0});
{
wxGCDC dc2(memdc);
doRender(dc2);
}
memdc.SelectObject(wxNullBitmap);
dc.DrawBitmap(bmp, 0, 0);
#else
doRender(dc);
#endif
}
void ProgressBar::doRender(wxDC &dc)
{
if (m_step >= m_max) m_step = m_max;
wxSize size = GetSize();
dc.SetPen(wxPen(m_progress_background_colour, 1));
dc.SetBrush(wxBrush(m_progress_background_colour));
if (m_radius == 0) {
dc.DrawRectangle(0, 0, size.x, size.y);
} else {
dc.DrawRoundedRectangle(0, 0, size.x, size.y, m_radius);
}
//draw progress
if (m_disable) {
m_proportion = float(size.x * float(this->m_step) / float(this->m_max));
if (m_proportion < m_radius * 2 && m_proportion != 0) { m_proportion = m_radius * 2; }
dc.SetPen(wxPen(m_progress_colour_disable, 1));
dc.SetBrush(wxBrush(m_progress_colour_disable));
if (m_radius == 0) {
dc.DrawRectangle(0, 0, m_proportion, size.y);
} else {
dc.DrawRoundedRectangle(0, 0, m_proportion, size.y, m_radius);
}
dc.SetFont(::Label::Head_12);
auto textSize = dc.GetMultiLineTextExtent(m_disable_text);
dc.SetTextForeground(wxColour(144, 144, 144));
auto pt = wxPoint();
pt.x = (size.x - textSize.x) / 2;
pt.y = (size.y - textSize.y) / 2;
dc.DrawText(m_disable_text, pt);
} else {
m_proportion = float(size.x * float(this->m_step) / float(this->m_max));
if (m_proportion < m_radius * 2 && m_proportion != 0) { m_proportion = m_radius * 2; }
dc.SetPen(wxPen(m_progress_colour, 1));
dc.SetBrush(wxBrush(m_progress_colour));
if (m_radius == 0) {
dc.DrawRectangle(0, 0, m_proportion, size.y);
} else {
dc.DrawRoundedRectangle(0, 0, m_proportion, size.y, m_radius);
}
dc.SetFont(GetFont());
auto textSize = dc.GetMultiLineTextExtent(wxString("000%"));
dc.SetTextForeground(wxColour(144, 144, 144));
auto pt = wxPoint();
pt.x = (size.x - textSize.x) / 2;
pt.y = (size.y - textSize.y) / 2;
auto text = wxString("");
if (m_step < 10) {
text = wxString::Format("%d", m_step);
} else {
text = wxString::Format("%d", m_step);
}
if (m_shownumber) {
dc.DrawText(text + wxString("%"), pt);
}
}
}
void ProgressBar::DoSetSize(int x, int y, int width, int height, int sizeFlags)
{
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
}

View file

@ -0,0 +1,66 @@
#ifndef slic3r_GUI_ProgressBar_hpp_
#define slic3r_GUI_ProgressBar_hpp_
#include <wx/window.h>
#include "../wxExtensions.hpp"
class ProgressBar : public wxWindow
{
public:
ProgressBar();
ProgressBar(wxWindow * parent,
wxWindowID id = wxID_ANY,
int max = 100,
const wxPoint & pos = wxDefaultPosition,
const wxSize & size = wxDefaultSize,
bool shown = false);
void create(wxWindow *parent, wxWindowID id, const wxPoint &pos, wxSize &size);
~ProgressBar();
public:
bool m_shownumber = {false};
int m_disable = {false};
int m_max = {100};
int m_step = {0};
int m_miniHeight = {0};
const int miniHeight = {14};
double m_radius = {7};
double m_proportion = {0};
wxColour m_progress_background_colour = {233, 233, 233};
wxColour m_progress_colour = {0, 174, 66};
wxColour m_progress_colour_disable = {255, 111, 0};
wxString m_disable_text;
public:
void ShowNumber(bool shown);
void Disable(wxString text);
void SetValue(int step);
void Reset();
void SetProgress(int step);
void SetRadius(double radius);
void SetProgressForedColour(wxColour colour);
void SetProgressBackgroundColour(wxColour colour);
void Rescale();
void SetHeight(int height) {
m_minHeight = height;
m_radius = m_minHeight / 2;
SetSize(GetSize().x, height);
}
virtual void SetMinSize(const wxSize &size) override;
protected:
void paintEvent(wxPaintEvent &evt);
void render(wxDC &dc);
void doRender(wxDC &dc);
virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO);
DECLARE_EVENT_TABLE()
};
#endif // !slic3r_GUI_ProgressBar_hpp_

View file

@ -0,0 +1,852 @@
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/utils.h"
#include "wx/frame.h"
#include "wx/button.h"
#include "wx/stattext.h"
#include "wx/sizer.h"
#include "wx/event.h"
#include "wx/gauge.h"
#include "wx/intl.h"
#include "wx/dcclient.h"
#include "wx/timer.h"
#include "wx/settings.h"
#include "wx/app.h"
#endif
#include "../GUI.hpp"
#include "../GUI_App.hpp"
#include "../I18N.hpp"
#include "ProgressDialog.hpp"
#include "wx/evtloop.h"
#include "Label.hpp"
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
#define LAYOUT_MARGIN 12
static const int wxID_SKIP = 32000;
namespace Slic3r { namespace GUI {
void ProgressDialog::Init()
{
// we may disappear at any moment, let the others know about it
SetExtraStyle(GetExtraStyle() | wxWS_EX_TRANSIENT);
// Initialize all our members that we always use (even when we don't
// create a valid window in this class).
m_pdStyle = 0;
m_parentTop = NULL;
m_gauge = NULL;
m_msg = NULL;
m_elapsed = m_estimated = m_remaining = NULL;
m_state = Uncancelable;
m_maximum = 0;
m_timeStart = wxGetCurrentTime();
m_timeStop = (unsigned long) -1;
m_break = 0;
m_skip = false;
m_btnAbort = NULL;
m_btnSkip = NULL;
m_display_estimated = m_last_timeupdate = m_ctdelay = 0;
m_delay = 3;
m_winDisabler = NULL;
m_tempEventLoop = NULL;
SetWindowStyle(wxDEFAULT_DIALOG_STYLE);
}
ProgressDialog::ProgressDialog() : wxDialog() { Init(); }
ProgressDialog::ProgressDialog(const wxString &title, const wxString &message, int maximum, wxWindow *parent, int style, bool adaptive) : wxDialog()
{
m_adaptive = adaptive;
Init();
Create(title, message, maximum, parent, style);
Bind(wxEVT_PAINT, &ProgressDialog::OnPaint, this);
Bind(wxEVT_CLOSE_WINDOW, &ProgressDialog::OnClose, this);
}
void ProgressDialog::OnPaint(wxPaintEvent &evt) {}
void ProgressDialog::SetTopParent(wxWindow *parent)
{
m_parent = parent;
m_parentTop = parent;
}
wxString ProgressDialog::FormatString(wxString title)
{
if (!m_adaptive) {
auto current_width = 0;
m_mode = 0;
for (int i = 0; i < title.length(); i++) {
current_width = m_msg->GetTextExtent(title.SubString(0, i)).x;
if (current_width > PROGRESSDIALOG_GAUGE_SIZE.x) {
m_mode = 1;
// title.insert(i - 1, "\n");
break;
}
}
// set mode
if (m_mode == 0) {
m_simplebook->SetSelection(0);
m_msg->SetLabel(title);
} else {
m_simplebook->SetSelection(1);
m_msg_2line->SetLabel(title);
}
} else {
m_msg->SetLabel(title);
Layout();
}
Fit();
return title;
}
bool ProgressDialog::Create(const wxString &title, const wxString &message, int maximum, wxWindow *parent, int style)
{
SetFont(wxGetApp().normal_font());
SetTopParent(parent);
m_pdStyle = style;
if (!wxDialog::Create(m_parentTop, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, GetWindowStyle())) return false;
SetBackgroundColour(PROGRESSDIALOG_DEF_BK);
/* SetSize(DESIGN_RESOUTION_PROGRESS_SIZE);
SetMinSize(DESIGN_RESOUTION_PROGRESS_SIZE);
SetMaxSize(DESIGN_RESOUTION_PROGRESS_SIZE);*/
SetMaximum(maximum);
EnsureActiveEventLoopExists();
#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
if (!HasPDFlag(wxPD_CAN_ABORT)) { EnableCloseButton(false); }
#endif // wxMSW
m_state = HasPDFlag(wxPD_CAN_ABORT) ? Continue : Uncancelable;
wxBoxSizer *m_sizer_main = new wxBoxSizer(wxVERTICAL);
m_top_line = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0);
m_top_line->SetBackgroundColour(wxColour(166, 169, 170));
m_sizer_main->Add(m_top_line, 0, wxEXPAND, 0);
m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(24));
if (!m_adaptive) {
m_simplebook = new wxSimplebook(this, wxID_ANY, wxDefaultPosition, PROGRESSDIALOG_SIMPLEBOOK_SIZE, 0);
m_panel_1line = new wxPanel(m_simplebook, wxID_ANY, wxDefaultPosition, PROGRESSDIALOG_SIMPLEBOOK_SIZE, 0);
m_panel_1line->SetMaxSize(PROGRESSDIALOG_SIMPLEBOOK_SIZE);
m_panel_1line->SetBackgroundColour(PROGRESSDIALOG_DEF_BK);
m_simplebook->AddPage(m_panel_1line, wxEmptyString, false);
m_panel_2line = new wxPanel(m_simplebook, wxID_ANY, wxDefaultPosition, PROGRESSDIALOG_SIMPLEBOOK_SIZE, 0);
m_panel_2line->SetMaxSize(PROGRESSDIALOG_SIMPLEBOOK_SIZE);
m_panel_2line->SetBackgroundColour(PROGRESSDIALOG_DEF_BK);
m_simplebook->AddPage(m_panel_2line, wxEmptyString, false);
wxBoxSizer *sizer_1line = new wxBoxSizer(wxHORIZONTAL);
m_msg = new wxStaticText(m_panel_1line, wxID_ANY, wxEmptyString, wxDefaultPosition, PROGRESSDIALOG_SIMPLEBOOK_SIZE, 0);
m_msg->Wrap(-1);
m_msg->SetFont(::Label::Body_13);
m_msg->SetForegroundColour(PROGRESSDIALOG_GREY_700);
sizer_1line->Add(m_msg, 0, wxALIGN_CENTER, 0);
m_panel_1line->SetSizer(sizer_1line);
m_panel_1line->Layout();
sizer_1line->Fit(m_panel_1line);
wxBoxSizer *sizer_2line = new wxBoxSizer(wxVERTICAL);
m_msg_2line = new wxStaticText(m_panel_2line, wxID_ANY, wxEmptyString, wxDefaultPosition, PROGRESSDIALOG_SIMPLEBOOK_SIZE, 0);
m_msg_2line->Wrap(PROGRESSDIALOG_SIMPLEBOOK_SIZE.x);
m_msg_2line->SetFont(::Label::Body_13);
m_msg_2line->SetForegroundColour(PROGRESSDIALOG_GREY_700);
m_msg_2line->SetMaxSize(PROGRESSDIALOG_SIMPLEBOOK_SIZE);
sizer_2line->Add(m_msg_2line, 1, wxALL, 0);
m_panel_2line->SetSizer(sizer_2line);
m_panel_2line->Layout();
sizer_2line->Fit(m_panel_2line);
m_sizer_main->Add(m_simplebook, 1, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(28));
} else {
m_msg = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(PROGRESSDIALOG_SIMPLEBOOK_SIZE.x, -1), 0);
m_msg->Wrap(PROGRESSDIALOG_SIMPLEBOOK_SIZE.x);
m_msg->SetFont(::Label::Body_13);
m_msg->SetForegroundColour(PROGRESSDIALOG_GREY_700);
m_sizer_main->Add(m_msg, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(28));
}
m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, 0);
int gauge_style = wxGA_HORIZONTAL;
if (style & wxPD_SMOOTH) gauge_style |= wxGA_SMOOTH;
gauge_style |= wxGA_PROGRESS;
#ifdef __WXMSW__
maximum /= m_factor;
#endif
m_gauge = new wxGauge(this, wxID_ANY, maximum, wxDefaultPosition, PROGRESSDIALOG_GAUGE_SIZE, gauge_style);
m_gauge->SetValue(0);
m_sizer_main->Add(m_gauge, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(28));
m_block_left = new wxWindow(m_gauge, wxID_ANY, wxPoint(0, 0), wxSize(FromDIP(2), PROGRESSDIALOG_GAUGE_SIZE.y * 2));
m_block_left->SetBackgroundColour(PROGRESSDIALOG_DEF_BK);
m_block_right = new wxWindow(m_gauge, wxID_ANY, wxPoint(PROGRESSDIALOG_GAUGE_SIZE.x - 2, 0), wxSize(FromDIP(2), PROGRESSDIALOG_GAUGE_SIZE.y * 2));
m_block_right->SetBackgroundColour(PROGRESSDIALOG_DEF_BK);
wxBoxSizer *m_sizer_bottom = new wxBoxSizer(wxHORIZONTAL);
m_sizer_bottom->Add(0, 0, 1, wxEXPAND, 0);
if (HasPDFlag(wxPD_CAN_ABORT)) {
m_button_cancel = new Button(this, _L("Cancel"));
m_button_cancel->SetTextColor(PROGRESSDIALOG_GREY_700);
m_button_cancel->SetMinSize(PROGRESSDIALOG_CANCEL_BUTTON_SIZE);
m_button_cancel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &event) {
if (m_state == Finished) {
event.Skip();
} else {
m_state = Canceled;
DisableAbort();
m_button_cancel->Enable(false);
DisableSkip();
m_timeStop = wxGetCurrentTime();
}
});
m_sizer_bottom->Add(m_button_cancel, 0, wxALL, 0);
}
m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(16));
m_sizer_main->Add(m_sizer_bottom, 1, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(28));
m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(10));
SetSizer(m_sizer_main);
Layout();
Fit();
Centre(wxCENTER_FRAME | wxBOTH);
DisableOtherWindows();
FormatString(message);
Show();
Enable();
if (m_elapsed) { SetTimeLabel(0, m_elapsed); }
Update();
return true;
//
// sizerTop = new wxBoxSizer(wxVERTICAL);
// auto def_size_width = wxMin(wxGetClientDisplayRect().width / 3, 305);
//
// wxStaticLine *m_staticline2 = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxSize(def_size_width, 1), wxLI_HORIZONTAL);
// sizerTop->Add(m_staticline2, 0, wxEXPAND, 0);
// auto m_block_top = new wxWindow(this, wxID_ANY, wxDefaultPosition, wxSize(def_size_width, 20));
// m_block_top->SetBackgroundColour(wxColor(DESIGN_RESOUTION_DEF_BK_COLOR));
// sizerTop->Add(m_block_top, 0, wxEXPAND);
//
// m_message_area = new wxWindow(this, wxID_ANY, wxDefaultPosition, wxSize(def_size_width, 38));
// m_message_area->SetBackgroundColour(DESIGN_RESOUTION_DEF_BK_COLOR);
// sizerTop->Add(m_message_area, 0, wxLEFT | wxRIGHT | wxBottom | wxEXPAND, 2 * LAYOUT_MARGIN);
//
// m_msg = new wxStaticText(m_message_area, wxID_ANY, wxString(""), wxPoint(0, 10), wxSize(def_size_width, 20), wxST_ELLIPSIZE_END);
// m_msg->SetForegroundColour(wxColour(107, 107, 107));
// m_msg->SetBackgroundColour(DESIGN_RESOUTION_DEF_BK_COLOR);
// m_msg->SetMinSize(wxSize(def_size_width, 20));
// m_msg->SetMaxSize(wxSize(def_size_width, 20));
//
// m_msg_2line = new wxStaticText(m_message_area, wxID_ANY, wxString(""), wxPoint(0, 0), wxSize(def_size_width, 40), wxST_ELLIPSIZE_END);
// m_msg_2line->SetForegroundColour(wxColour(107, 107, 107));
// m_msg_2line->SetBackgroundColour(DESIGN_RESOUTION_DEF_BK_COLOR);
// m_msg_2line->SetMinSize(wxSize(def_size_width, 40));
// m_msg_2line->SetMaxSize(wxSize(def_size_width, 40));
//
// auto block_left = new wxWindow(m_gauge, -1, wxPoint(0, 0), wxSize(2, m_gauge->GetSize().GetHeight()));
// block_left->SetBackgroundColour(wxColor(255, 255, 255));
//
// auto block_right = new wxWindow(m_gauge, -1, wxPoint(m_gauge->GetSize().GetWidth() - 2, 0), wxSize(2, m_gauge->GetSize().GetHeight()));
// block_right->SetBackgroundColour(wxColor(255, 255, 255));
//
// sizerTop->Add(m_gauge, 0, wxLEFT | wxRIGHT | wxBottom, 2 * LAYOUT_MARGIN);
// m_gauge->SetValue(0);
//
// m_elapsed = m_estimated = m_remaining = NULL;
// size_t nTimeLabels = 0;
//
// wxSizer *const sizerLabels = new wxFlexGridSizer(2);
//
// if (style & wxPD_ELAPSED_TIME) {
// nTimeLabels++;
//
// m_elapsed = CreateLabel(GetElapsedLabel(), sizerLabels);
// }
//
// if (style & wxPD_ESTIMATED_TIME) {
// nTimeLabels++;
//
// m_estimated = CreateLabel(GetEstimatedLabel(), sizerLabels);
// }
//
// if (style & wxPD_REMAINING_TIME) {
// nTimeLabels++;
//
// m_remaining = CreateLabel(GetRemainingLabel(), sizerLabels);
// }
// sizerTop->Add(sizerLabels, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP | wxBottom, LAYOUT_MARGIN);
//
// wxStdDialogButtonSizer *buttonSizer = wxDialog::CreateStdDialogButtonSizer(0);
//
// const int borderFlags = wxALL;
//
// std::string icon_path = (boost::format("%1%/images/common_dialog_confirm.png") % resources_dir()).str();
// /*m_btnAbort = new wxBitmapButton(this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize(52, 24), wxBU_AUTODRAW | wxBORDER_NONE);
// m_btnAbort->SetBitmap(wxBitmap(icon_path, wxBITMAP_TYPE_ANY));
// m_btnAbort->SetBitmapDisabled(wxBitmap(icon_path, wxBITMAP_TYPE_ANY));
// m_btnAbort->SetBitmapPressed(wxBitmap(icon_path, wxBITMAP_TYPE_ANY));
// m_btnAbort->SetBitmapFocus(wxBitmap(icon_path, wxBITMAP_TYPE_ANY));
// m_btnAbort->SetBitmapCurrent(wxBitmap(icon_path, wxBITMAP_TYPE_ANY));*/
//
// m_btnAbort = new wxButton(this, wxID_CANCEL, wxString(""), wxDefaultPosition, wxSize(52,24));
//
// wxStaticBitmap *m_bitmatAbort = new wxStaticBitmap(m_btnAbort, wxID_ANY, wxBitmap(icon_path, wxBITMAP_TYPE_ANY), wxDefaultPosition, wxSize(52, 24), 0);
// wxStaticText *textAbort = new wxStaticText(m_btnAbort, wxID_ANY, _T("Cancel"), wxPoint(5, 3), wxSize(42, 19));
// textAbort->SetBa
// ckgroundColour(wxColor(0, 174, 66));
// textAbort->SetForegroundColour(DESIGN_RESOUTION_DEF_BK_COLOR);
//
// textAbort->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &event) {
// if (m_state == Finished) {
// event.Skip();
// } else {
// m_state = Canceled;
// //DisableAbort();
// DisableSkip();
// m_timeStop = wxGetCurrentTime();
// }
// });
//
// wxSizerFlags sizerFlags = wxSizerFlags().Border(borderFlags, LAYOUT_MARGIN);
// wxWindow *m_button_sizer = new wxWindow(this, wxID_ANY, wxDefaultPosition, wxSize(def_size_width, 26));
// m_button_sizer->SetBackgroundColour(DESIGN_RESOUTION_DEF_BK_COLOR);
//
// if (HasPDFlag(wxPD_CAN_SKIP)) {
// m_btnSkip = new wxButton(this, wxID_SKIP, wxGetTranslation("&Skip"));
// m_btnSkip->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &ProgressDialog::OnSkip, this);
// buttonSizer->SetNegativeButton(m_btnSkip);
// }
//
// if (HasPDFlag(wxPD_CAN_ABORT)) {
// /*m_btnAbort = new wxButton(this, wxID_CANCEL);
// buttonSizer->SetCancelButton(m_btnAbort);
// m_btnAbort->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &ProgressDialog::OnCancel, this);*/
//
// m_button_calcel = new Button(m_button_sizer, _T("Cancel"));
// m_button_calcel->SetTextColor(wxColour(107, 107, 107));
// m_button_calcel->SetSize(60, 24);
// m_button_calcel->SetPosition(wxPoint(m_button_sizer->GetSize().GetWidth() - m_button_calcel->GetSize().GetWidth(), 0));
//
// m_button_calcel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &event) {
// if (m_state == Finished) {
// event.Skip();
// } else {
// m_state = Canceled;
// DisableAbort();
// m_button_calcel->Enable(false);
// DisableSkip();
// m_timeStop = wxGetCurrentTime();
// }
// });
// }
//
// if (!HasPDFlag(wxPD_CAN_SKIP | wxPD_CAN_ABORT)) buttonSizer->AddSpacer(LAYOUT_MARGIN);
//
// sizerTop->Add(m_button_sizer, 1, wxEXPAND, 0);
//
// auto m_block_bottom = new wxWindow(this, wxID_ANY, wxDefaultPosition, wxSize(def_size_width, 15));
// m_block_bottom->SetBackgroundColour(DESIGN_RESOUTION_DEF_BK_COLOR);
// sizerTop->Add(m_block_bottom, 0, wxEXPAND);
//
// SetSizerAndFit(sizerTop);
// FormatString(message);
//
// Centre(wxCENTER_FRAME | wxBOTH);
//
// DisableOtherWindows();
//
// Show();
// Enable();
// if (m_elapsed) { SetTimeLabel(0, m_elapsed); }
//
// Update();
// return true;
}
void ProgressDialog::UpdateTimeEstimates(int value, unsigned long &elapsedTime, unsigned long &estimatedTime, unsigned long &remainingTime)
{
unsigned long elapsed = wxGetCurrentTime() - m_timeStart;
if (value != 0 && (m_last_timeupdate < elapsed || value == m_maximum)) {
m_last_timeupdate = elapsed;
unsigned long estimated = m_break + (unsigned long) (((double) (elapsed - m_break) * m_maximum) / ((double) value));
if (estimated > m_display_estimated && m_ctdelay >= 0) {
++m_ctdelay;
} else if (estimated < m_display_estimated && m_ctdelay <= 0) {
--m_ctdelay;
} else {
m_ctdelay = 0;
}
if (m_ctdelay >= m_delay // enough confirmations for a higher value
|| m_ctdelay <= (m_delay * -1) // enough confirmations for a lower value
|| value == m_maximum // to stay consistent
|| elapsed > m_display_estimated // to stay consistent
|| (elapsed > 0 && elapsed < 4) // additional updates in the beginning
) {
m_display_estimated = estimated;
m_ctdelay = 0;
}
}
if (value != 0) {
long display_remaining = m_display_estimated - elapsed;
if (display_remaining < 0) { display_remaining = 0; }
estimatedTime = m_display_estimated;
remainingTime = display_remaining;
}
elapsedTime = elapsed;
}
// static
wxString ProgressDialog::GetFormattedTime(unsigned long timeInSec)
{
wxString timeAsHMS;
if (timeInSec == (unsigned long) -1) {
timeAsHMS = wxGetTranslation("Unknown");
} else {
unsigned hours = timeInSec / 3600;
unsigned minutes = (timeInSec % 3600) / 60;
unsigned seconds = timeInSec % 60;
timeAsHMS.Printf("%u:%02u:%02u", hours, minutes, seconds);
}
return timeAsHMS;
}
void ProgressDialog::EnsureActiveEventLoopExists()
{
if (!wxEventLoopBase::GetActive()) {
m_tempEventLoop = new wxEventLoop;
wxEventLoop::SetActive(m_tempEventLoop);
}
}
wxStaticText *ProgressDialog::CreateLabel(const wxString &text, wxSizer *sizer)
{
wxStaticText *label = new wxStaticText(this, wxID_ANY, text);
wxStaticText *value = new wxStaticText(this, wxID_ANY, wxGetTranslation("unknown"));
// select placement most native or nice on target GUI
#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXGTK20__)
// value and time centered in one row
sizer->Add(label, 1, wxALIGN_RIGHT | wxTOP | wxRIGHT, LAYOUT_MARGIN);
sizer->Add(value, 1, wxALIGN_LEFT | wxTOP, LAYOUT_MARGIN);
#else
// value and time to the right in one row
sizer->Add(label);
sizer->Add(value, 0, wxLEFT, LAYOUT_MARGIN);
#endif
return value;
}
// ----------------------------------------------------------------------------
// ProgressDialog operations
// ----------------------------------------------------------------------------
bool ProgressDialog::Update(int value, const wxString &newmsg, bool *skip)
{
if (!DoBeforeUpdate(skip)) return false;
wxCHECK_MSG(m_gauge, false, "dialog should be fully created");
#ifdef __WXMSW__
value /= m_factor;
#endif // __WXMSW__
wxASSERT_MSG(value <= m_maximum, wxT("invalid progress value"));
m_gauge->SetValue(value);
UpdateMessage(newmsg);
if ((m_elapsed || m_remaining || m_estimated) && (value != 0)) {
unsigned long elapsed;
unsigned long display_remaining;
UpdateTimeEstimates(value, elapsed, m_display_estimated, display_remaining);
SetTimeLabel(elapsed, m_elapsed);
SetTimeLabel(m_display_estimated, m_estimated);
SetTimeLabel(display_remaining, m_remaining);
}
if (value == m_maximum) {
if (m_state == Finished) {
// ignore multiple calls to Update(m_maximum): it may sometimes be
// troublesome to ensure that Update() is not called twice with the
// same value (e.g. because of the rounding errors) and if we don't
// return now we're going to generate asserts below
return true;
}
// so that we return true below and that out [Cancel] handler knew what
// to do
m_state = Finished;
if (!HasPDFlag(wxPD_AUTO_HIDE)) {
EnableClose();
DisableSkip();
#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
EnableCloseButton();
#endif // __WXMSW__
if (newmsg.empty()) {
// also provide the finishing message if the application didn't
m_msg->SetLabel(wxGetTranslation("Done."));
}
// allow the window to repaint:
// NOTE: since we yield only for UI events with this call, there
// should be no side-effects
wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI | wxEVT_CATEGORY_USER_INPUT);
// NOTE: this call results in a new event loop being created
// and to a call to ProcessPendingEvents() (which may generate
// unwanted re-entrancies).
(void) ShowModal();
} else // auto hide
{
// reenable other windows before hiding this one because otherwise
// Windows wouldn't give the focus back to the window which had
// been previously focused because it would still be disabled
ReenableOtherWindows();
Hide();
}
} else // not at maximum yet
{
DoAfterUpdate();
}
// update the display in case yielding above didn't do it
Update();
return m_state != Canceled;
}
bool ProgressDialog::Pulse(const wxString &newmsg, bool *skip)
{
if (!DoBeforeUpdate(skip)) return false;
wxCHECK_MSG(m_gauge, false, "dialog should be fully created");
// show a bit of progress
m_gauge->Pulse();
UpdateMessage(newmsg);
if (m_elapsed || m_remaining || m_estimated) {
unsigned long elapsed = wxGetCurrentTime() - m_timeStart;
SetTimeLabel(elapsed, m_elapsed);
SetTimeLabel((unsigned long) -1, m_estimated);
SetTimeLabel((unsigned long) -1, m_remaining);
}
DoAfterUpdate();
return m_state != Canceled;
}
bool ProgressDialog::DoBeforeUpdate(bool *skip)
{
// we have to yield because not only we want to update the display but
// also to process the clicks on the cancel and skip buttons
// NOTE: using YieldFor() this call shouldn't give re-entrancy problems
// for event handlers not interested to UI/user-input events.
wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI | wxEVT_CATEGORY_USER_INPUT);
Update();
if (m_skip && skip && !*skip) {
*skip = true;
m_skip = false;
EnableSkip();
}
return m_state != Canceled;
}
void ProgressDialog::DoAfterUpdate()
{
// allow the window to repaint:
// NOTE: since we yield only for UI events with this call, there
// should be no side-effects
wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI | wxEVT_CATEGORY_USER_INPUT);
}
void ProgressDialog::Resume()
{
m_state = Continue;
m_ctdelay = m_delay; // force an update of the elapsed/estimated/remaining time
m_break += wxGetCurrentTime() - m_timeStop;
EnableAbort();
m_button_cancel->Enable(true);
EnableSkip();
m_skip = false;
}
bool ProgressDialog::Show(bool show)
{
// reenable other windows before hiding this one because otherwise
// Windows wouldn't give the focus back to the window which had
// been previously focused because it would still be disabled
if (!show) ReenableOtherWindows();
return wxDialog::Show(show);
}
int ProgressDialog::GetValue() const
{
wxCHECK_MSG(m_gauge, -1, "dialog should be fully created");
return m_gauge->GetValue();
}
int ProgressDialog::GetRange() const { return m_maximum; }
wxString ProgressDialog::GetMessage() const { return m_msg->GetLabel(); }
void ProgressDialog::SetRange(int maximum)
{
wxCHECK_RET(m_gauge, "dialog should be fully created");
wxCHECK_RET(maximum > 0, "Invalid range");
m_gauge->SetRange(maximum);
SetMaximum(maximum);
}
void ProgressDialog::SetMaximum(int maximum)
{
m_maximum = maximum;
#if defined(__WXMSW__)
// we can't have values > 65,536 in the progress control under Windows, so
// scale everything down
m_factor = m_maximum / 65536 + 1;
m_maximum /= m_factor;
#endif // __WXMSW__
}
bool ProgressDialog::WasCancelled() const { return HasPDFlag(wxPD_CAN_ABORT) && m_state == Canceled; }
bool ProgressDialog::WasSkipped() const { return HasPDFlag(wxPD_CAN_SKIP) && m_skip; }
// static
void ProgressDialog::SetTimeLabel(unsigned long val, wxStaticText *label)
{
if (label) {
wxString s;
if (val != (unsigned long) -1) {
s = GetFormattedTime(val);
} else {
s = wxGetTranslation("Unknown");
}
if (s != label->GetLabel()) label->SetLabel(s);
}
}
// ----------------------------------------------------------------------------
// event handlers
// ----------------------------------------------------------------------------
void ProgressDialog::OnCancel(wxCommandEvent &event)
{
if (m_state == Finished) {
// this means that the count down is already finished and we're being
// shown as a modal dialog - so just let the default handler do the job
event.Skip();
} else {
// request to cancel was received, the next time Update() is called we
// will handle it
m_state = Canceled;
// update the buttons state immediately so that the user knows that the
// request has been noticed
DisableAbort();
DisableSkip();
// save the time when the dialog was stopped
m_timeStop = wxGetCurrentTime();
}
}
void ProgressDialog::OnSkip(wxCommandEvent &WXUNUSED(event))
{
DisableSkip();
m_skip = true;
}
void ProgressDialog::OnClose(wxCloseEvent &event)
{
if (m_state == Uncancelable) {
// can't close this dialog
event.Veto();
} else if (m_state == Finished) {
// let the default handler close the window as we already terminated
event.Skip();
} else {
// next Update() will notice it
m_state = Canceled;
DisableAbort();
DisableSkip();
m_timeStop = wxGetCurrentTime();
}
}
// ----------------------------------------------------------------------------
// destruction
// ----------------------------------------------------------------------------
ProgressDialog::~ProgressDialog()
{
// normally this should have been already done, but just in case
ReenableOtherWindows();
if (m_tempEventLoop) {
// If another event loop has been installed as active during the life
// time of this object, we shouldn't deactivate it, but we also can't
// delete our m_tempEventLoop in this case because it risks leaving the
// new event loop with a dangling pointer, which it will set back as
// the active loop when it exits, resulting in a crash. So we have no
// choice but to just leak this pointer then, which is, of course, bad
// and usually easily avoidable by just destroying the progress dialog
// sooner, so warn the programmer about it.
wxCHECK_RET(wxEventLoopBase::GetActive() == m_tempEventLoop, "current event loop must not be changed during "
"ProgressDialog lifetime");
wxEventLoopBase::SetActive(NULL);
delete m_tempEventLoop;
}
}
void ProgressDialog::DoSetSize(int x, int y, int width, int height, int sizeFlags /*= wxSIZE_AUTO*/)
{
if (m_button_cancel != nullptr) { m_button_cancel->SetMinSize(PROGRESSDIALOG_CANCEL_BUTTON_SIZE); }
if (m_block_left != nullptr && m_block_right != nullptr) {
m_block_left->SetPosition(wxPoint(0, 0));
m_block_right->SetPosition(wxPoint(PROGRESSDIALOG_GAUGE_SIZE.x - 2, 0));
}
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
}
void ProgressDialog::DisableOtherWindows()
{
if (HasPDFlag(wxPD_APP_MODAL)) {
#if defined(__WXOSX__)
if (m_parentTop) m_parentTop->Disable();
m_winDisabler = NULL;
#else
m_winDisabler = new wxWindowDisabler(this);
#endif
} else {
if (m_parentTop) m_parentTop->Disable();
m_winDisabler = NULL;
}
}
void ProgressDialog::ReenableOtherWindows()
{
if (HasPDFlag(wxPD_APP_MODAL)) {
#if defined(__WXOSX__)
if (m_parentTop) m_parentTop->Enable();
#else
wxDELETE(m_winDisabler);
#endif
} else {
if (m_parentTop) m_parentTop->Enable();
}
}
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
void ProgressDialog::EnableSkip(bool enable)
{
if (HasPDFlag(wxPD_CAN_SKIP)) {
if (m_btnSkip) m_btnSkip->Enable(enable);
}
}
void ProgressDialog::EnableAbort(bool enable)
{
if (HasPDFlag(wxPD_CAN_ABORT)) {
if (m_btnAbort) m_btnAbort->Enable(enable);
}
}
void ProgressDialog::EnableClose()
{
if (HasPDFlag(wxPD_CAN_ABORT)) {
if (m_btnAbort) {
m_btnAbort->Enable();
m_btnAbort->SetLabel(wxGetTranslation("Close"));
}
}
}
void ProgressDialog::UpdateMessage(const wxString &newmsg)
{
if (!newmsg.empty() && newmsg != m_msg->GetLabel()) {
const wxSize sizeOld = m_msg->GetSize();
FormatString(newmsg);
Fit();
// m_msg->SetLabel(newmsg);
if (m_msg->GetSize().x > sizeOld.x) {
// Resize the dialog to fit its new, longer contents instead of
// just truncating it.
Fit();
}
// allow the window to repaint:
// NOTE: since we yield only for UI events with this call, there
// should be no side-effects
wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI | wxEVT_CATEGORY_USER_INPUT);
}
}
}} // namespace Slic3r::GUI

View file

@ -0,0 +1,231 @@
#ifndef slic3r_GUI_PROGRESSDIALOG_hpp_
#define slic3r_GUI_PROGRESSDIALOG_hpp_
#include "wx/dialog.h"
#include "wx/weakref.h"
#include "wx/simplebook.h"
#include "Button.hpp"
#include "../wxExtensions.hpp"
class WXDLLIMPEXP_FWD_CORE wxButton;
class WXDLLIMPEXP_FWD_CORE wxEventLoop;
class WXDLLIMPEXP_FWD_CORE wxGauge;
class WXDLLIMPEXP_FWD_CORE wxStaticText;
class WXDLLIMPEXP_FWD_CORE wxWindowDisabler;
#define PROGRESSDIALOG_SIMPLEBOOK_SIZE wxSize(FromDIP(320), FromDIP(38))
#define PROGRESSDIALOG_GAUGE_SIZE wxSize(FromDIP(320), FromDIP(6))
#define PROGRESSDIALOG_CANCEL_BUTTON_SIZE wxSize(FromDIP(60), FromDIP(24))
#define PROGRESSDIALOG_DEF_BK wxColour(255,255,255)
#define PROGRESSDIALOG_GREY_700 wxColour(107,107,107)
namespace Slic3r { namespace GUI {
class WXDLLIMPEXP_CORE ProgressDialog : public wxDialog
{
public:
ProgressDialog();
ProgressDialog(const wxString &title, const wxString &message, int maximum = 100, wxWindow *parent = NULL, int style = wxPD_APP_MODAL | wxPD_AUTO_HIDE, bool adaptive = false);
void OnPaint(wxPaintEvent &evt);
virtual ~ProgressDialog();
virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO);
bool Create(const wxString &title, const wxString &message, int maximum = 100, wxWindow *parent = NULL, int style = wxPD_APP_MODAL | wxPD_AUTO_HIDE);
virtual bool Update(int value, const wxString &newmsg = wxEmptyString, bool *skip = NULL);
virtual bool Pulse(const wxString &newmsg = wxEmptyString, bool *skip = NULL);
virtual void Resume();
virtual int GetValue() const;
virtual int GetRange() const;
virtual wxString GetMessage() const;
virtual void SetRange(int maximum);
// Return whether "Cancel" or "Skip" button was pressed, always return
// false if the corresponding button is not shown.
virtual bool WasCancelled() const;
virtual bool WasSkipped() const;
// Must provide overload to avoid hiding it (and warnings about it)
virtual void Update() wxOVERRIDE { wxDialog::Update(); }
virtual bool Show(bool show = true) wxOVERRIDE;
// This enum is an implementation detail and should not be used
// by user code.
enum State {
Uncancelable = -1, // dialog can't be canceled
Canceled, // can be cancelled and, in fact, was
Continue, // can be cancelled but wasn't
Finished, // finished, waiting to be removed from screen
Dismissed // was closed by user after finishing
};
int m_mode = 0; // 0 is 1line mode 1 is 2line mode
bool m_adaptive = {false};
wxSizer * m_sizer_main = {nullptr};
wxPanel * m_top_line= {nullptr};
wxSimplebook * m_simplebook= {nullptr};
wxPanel * m_panel_2line= {nullptr};
wxPanel * m_panel_1line= {nullptr};
Button* m_button_cancel = {nullptr};
wxWindow * m_block_left = {nullptr};
wxWindow * m_block_right = {nullptr};
protected:
// Update just the m_maximum field, this is used by public SetRange() but,
// unlike it, doesn't update the controls state. This makes it useful for
// both this class and its derived classes that don't use m_gauge to
// display progress.
void SetMaximum(int maximum);
// Return the labels to use for showing the elapsed/estimated/remaining
// times respectively.
static wxString GetElapsedLabel() { return wxGetTranslation("Elapsed time:"); }
static wxString GetEstimatedLabel() { return wxGetTranslation("Estimated time:"); }
static wxString GetRemainingLabel() { return wxGetTranslation("Remaining time:"); }
// Similar to wxWindow::HasFlag() but tests for a presence of a wxPD_XXX
// flag in our (separate) flags instead of using m_windowStyle.
bool HasPDFlag(int flag) const { return (m_pdStyle & flag) != 0; }
// Return the progress dialog style. Prefer to use HasPDFlag() if possible.
int GetPDStyle() const { return m_pdStyle; }
void SetPDStyle(int pdStyle) { m_pdStyle = pdStyle; }
// Updates estimated times from a given progress bar value and stores the
// results in provided arguments.
void UpdateTimeEstimates(int value, unsigned long &elapsedTime, unsigned long &estimatedTime, unsigned long &remainingTime);
// Converts seconds to HH:mm:ss format.
static wxString GetFormattedTime(unsigned long timeInSec);
// Create a new event loop if there is no currently running one.
void EnsureActiveEventLoopExists();
// callback for optional abort button
void OnCancel(wxCommandEvent &);
// callback for optional skip button
void OnSkip(wxCommandEvent &);
// callback to disable "hard" window closing
void OnClose(wxCloseEvent &);
// called to disable the other windows while this dialog is shown
void DisableOtherWindows();
// must be called to re-enable the other windows temporarily disabled while
// the dialog was shown
void ReenableOtherWindows();
// Store the parent window as wxWindow::m_parent and also set the top level
// parent reference we store in this class itself.
void SetTopParent(wxWindow *parent);
wxString FormatString(wxString title);
// return the top level parent window of this dialog (may be NULL)
wxWindow *GetTopParent() const { return m_parentTop; }
// continue processing or not (return value for Update())
State m_state;
// the maximum value
int m_maximum;
#if defined(__WXMSW__)
// the factor we use to always keep the value in 16 bit range as the native
// control only supports ranges from 0 to 65,535
size_t m_factor;
#endif // __WXMSW__
// time when the dialog was created
unsigned long m_timeStart;
// time when the dialog was closed or cancelled
unsigned long m_timeStop;
// time between the moment the dialog was closed/cancelled and resume
unsigned long m_break;
private:
// update the label to show the given time (in seconds)
static void SetTimeLabel(unsigned long val, wxStaticText *label);
// common part of all ctors
void Init();
// create the label with given text and another one to show the time nearby
// as the next windows in the sizer, returns the created control
wxStaticText *CreateLabel(const wxString &text, wxSizer *sizer);
// updates the label message
void UpdateMessage(const wxString &newmsg);
// common part of Update() and Pulse(), returns true if not cancelled
bool DoBeforeUpdate(bool *skip);
// common part of Update() and Pulse()
void DoAfterUpdate();
// shortcuts for enabling buttons
void EnableClose();
void EnableSkip(bool enable = true);
void EnableAbort(bool enable = true);
void DisableSkip() { EnableSkip(false); }
void DisableAbort() { EnableAbort(false); }
// the widget displaying current status (may be NULL)
wxGauge *m_gauge;
// the message displayed
wxStaticText *m_msg;
wxStaticText *m_msg_2line;
// displayed elapsed, estimated, remaining time
wxStaticText *m_elapsed, *m_estimated, *m_remaining;
// Reference to the parent top level window, automatically becomes NULL if
// it it is destroyed and could be always NULL if it's not given at all.
wxWindowRef m_parentTop;
// Progress dialog styles: this is not the same as m_windowStyle because
// wxPD_XXX constants clash with the existing TLW styles so to be sure we
// don't have any conflicts we just use a separate variable for storing
// them.
int m_pdStyle;
// skip some portion
bool m_skip;
// the abort and skip buttons (or NULL if none)
wxButton *m_btnAbort;
wxButton *m_btnSkip;
// saves the time when elapsed time was updated so there is only one
// update per second
unsigned long m_last_timeupdate;
// tells how often a change of the estimated time has to be confirmed
// before it is actually displayed - this reduces the frequency of updates
// of estimated and remaining time
int m_delay;
// counts the confirmations
int m_ctdelay;
unsigned long m_display_estimated;
// for wxPD_APP_MODAL case
wxWindowDisabler *m_winDisabler;
// Temporary event loop created by the dialog itself if there is no
// currently active loop when it is created.
wxEventLoop *m_tempEventLoop;
wxDECLARE_NO_COPY_CLASS(ProgressDialog);
};
}} // namespace Slic3r::GUI
#endif // slic3r_GUI_PROGRESSDIALOG_hpp_

View file

@ -0,0 +1,42 @@
#include "RadioBox.hpp"
#include "../wxExtensions.hpp"
namespace Slic3r {
namespace GUI {
RadioBox::RadioBox(wxWindow *parent)
: wxBitmapToggleButton(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE), m_on(this, "radio_on", 18), m_off(this, "radio_off", 18)
{
// SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
if (parent) SetBackgroundColour(parent->GetBackgroundColour());
// Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { update(); e.Skip(); });
SetSize(m_on.GetBmpSize());
SetMinSize(m_on.GetBmpSize());
update();
}
void RadioBox::SetValue(bool value)
{
wxBitmapToggleButton::SetValue(value);
update();
}
bool RadioBox::GetValue()
{
return wxBitmapToggleButton::GetValue();
}
void RadioBox::Rescale()
{
m_on.msw_rescale();
m_off.msw_rescale();
SetSize(m_on.GetBmpSize());
update();
}
void RadioBox::update() { SetBitmap((GetValue() ? m_on : m_off).bmp()); }
}
}

View file

@ -0,0 +1,39 @@
#ifndef slic3r_GUI_RADIOBOX_hpp_
#define slic3r_GUI_RADIOBOX_hpp_
#include "../wxExtensions.hpp"
#include <wx/tglbtn.h>
namespace Slic3r {
namespace GUI {
class RadioBox : public wxBitmapToggleButton
{
public:
RadioBox(wxWindow *parent);
public:
void SetValue(bool value) override;
bool GetValue();
void Rescale();
bool Disable() {
return wxBitmapToggleButton::Disable();
}
bool Enable() {
return wxBitmapToggleButton::Enable();
}
private:
void update();
private:
ScalableBitmap m_on;
ScalableBitmap m_off;
};
}}
#endif // !slic3r_GUI_CheckBox_hpp_

View file

@ -0,0 +1,34 @@
#include "RoundedRectangle.hpp"
#include "../wxExtensions.hpp"
#include <wx/dcgraph.h>
BEGIN_EVENT_TABLE(RoundedRectangle, wxPanel)
EVT_PAINT(RoundedRectangle::OnPaint)
END_EVENT_TABLE()
RoundedRectangle::RoundedRectangle(wxWindow *parent, wxColour col, wxPoint pos, wxSize size, double radius, int type)
: wxWindow(parent, wxID_ANY, pos, size, wxBORDER_NONE)
{
SetBackgroundColour(wxColour(255,255,255));
m_type = type;
m_color = col;
m_radius = radius;
}
void RoundedRectangle::OnPaint(wxPaintEvent &evt)
{
//draw RoundedRectangle
if (m_type == 0) {
wxPaintDC dc(this);
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(wxBrush(m_color));
dc.DrawRoundedRectangle(0, 0, GetSize().GetWidth(), GetSize().GetHeight(), m_radius);
}
//draw RoundedRectangle only board
if (m_type == 1) {
wxPaintDC dc(this);
dc.SetPen(m_color);
dc.DrawRoundedRectangle(0, 0, GetSize().GetWidth(), GetSize().GetHeight(), m_radius);
}
}

View file

@ -0,0 +1,21 @@
#ifndef slic3r_GUI_ROUNDEDRECTANGLE_hpp_
#define slic3r_GUI_ROUNDEDRECTANGLE_hpp_
#include "../wxExtensions.hpp"
class RoundedRectangle : public wxWindow
{
public:
RoundedRectangle(wxWindow *parent, wxColour col, wxPoint pos, wxSize size, double radius, int type = 0);
~RoundedRectangle(){};
private:
double m_radius;
int m_type;
wxColour m_color;
public:
void OnPaint(wxPaintEvent &evt);
DECLARE_EVENT_TABLE()
};
#endif // !slic3r_GUI_RoundedRectangle_hpp_

View file

@ -0,0 +1,311 @@
#pragma once
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include "Scrollbar.hpp"
#include "ScrolledWindow.hpp"
MyScrollbar::MyScrollbar(wxWindow *parent, wxWindowID id, wxPoint position, wxSize size, ScrolledWindow* scrolledWindow, long direction, int scrollbarWidth, int tipLength) : wxPanel(parent, id, position, size)
{
m_parent = parent;
m_direction = direction;
m_tipLength = tipLength;
if (m_direction == wxVSCROLL)
m_virtualDim = size.GetHeight();
else
m_virtualDim = size.GetWidth(); // default values
m_actualDim = GetSize().GetHeight();
m_viewStartInScrollUnits = 0;
m_viewStartInPixels = 0;
m_minSliderSize = 30;
m_scrollbarWidth = scrollbarWidth;
m_marginWidth = scrollbarWidth;
m_tipColor = m_parent->GetBackgroundColour(); // default value. Can be changed with SetTipColour
m_marginColor = m_parent->GetBackgroundColour(); // default value. Can be changed with SetMarginColour
m_scrollbarColor = wxColour(255,255,255); // default value. Can be changed with SetScrollbarColour
m_scrolledWindow = scrolledWindow;
Bind(wxEVT_PAINT, &MyScrollbar::OnPaint, this);
Bind(wxEVT_SIZE, &MyScrollbar::OnSize, this);
Bind(wxEVT_ERASE_BACKGROUND, &MyScrollbar::OnEraseBackground, this);
Bind(wxEVT_LEFT_DOWN, &MyScrollbar::OnMouseLeftDown, this);
Bind(wxEVT_LEFT_UP, &MyScrollbar::OnMouseLeftUp, this);
Bind(wxEVT_MOTION, &MyScrollbar::OnMouseMove, this);
Bind(wxEVT_MOUSEWHEEL, &MyScrollbar::OnMouseWheel, this);
}
void MyScrollbar::SetViewStart(int start)
{
m_viewStartInScrollUnits = start;
m_viewStartInPixels = start;
}
void MyScrollbar::SetTipColor(wxColour color)
{
m_tipColor = color;
}
void MyScrollbar::SetMarginColor(wxColour color)
{
m_marginColor = color;
}
void MyScrollbar::SetScrollbarColor(wxColour color)
{
m_scrollbarColor = color;
}
void MyScrollbar::SetScrollbarTip(int len)
{
m_tipLength = len ;
}
void MyScrollbar::SetVirtualDim(int pixelsPerUnit, int noUnits)
{
m_virtualDim = pixelsPerUnit* noUnits;
m_pixelsPerUnit = pixelsPerUnit;
Refresh();
}
void MyScrollbar::OnSize(wxSizeEvent& WXUNUSED(event))
{
if (m_direction == wxVSCROLL)
{
m_actualDim = GetSize().GetHeight();
if (m_actualDim < m_virtualDim)
m_marginWidth = GetSize().GetWidth();
else
m_marginWidth = 0;
}
else
{
m_actualDim = GetSize().GetWidth();
if (m_actualDim < m_virtualDim)
m_marginWidth = GetSize().GetHeight();
else
m_marginWidth = 0;
}
}
void MyScrollbar::OnPaint(wxPaintEvent& event)
// This scrollbar is either a vertical one or an horizontal one
{
int scrollbarStart, scrollbarLength, scrollbarSide;
//wxBufferedPaintDC dc(this);
wxClientDC dc(this);
PrepareDC(dc);
int actualDim = m_actualDim;
//m_marginWidth = 10;
//m_scrollbarWidth = 10;
if (m_direction == wxVSCROLL && actualDim < m_virtualDim) // if actualDim >= m_virtualDim, the scrollbar is hidden, no need to paint it
{
scrollbarSide = (m_marginWidth - m_scrollbarWidth) / 2;
scrollbarStart = (m_pixelsPerUnit*actualDim*m_viewStartInScrollUnits) / (float)m_virtualDim + 0.5; // + 0.5 is a cheap way to round the float value
scrollbarLength = (actualDim*actualDim) / (float)m_virtualDim + 0.5;
if (scrollbarLength < m_minSliderSize)
{
scrollbarStart = (actualDim - m_minSliderSize)*(m_viewStartInScrollUnits*m_pixelsPerUnit / (float)(m_virtualDim - actualDim)) + 0.5;
scrollbarLength = m_minSliderSize;
}
if (scrollbarStart < 0) // the mouse is out of the panel
scrollbarStart = 0;
else if (scrollbarStart + scrollbarLength >= actualDim)
scrollbarStart = actualDim - scrollbarLength;
// draw the upper and lower tips
dc.SetPen(m_tipColor);
dc.SetBrush(m_tipColor);
dc.DrawRectangle(scrollbarSide, 0, m_scrollbarWidth, m_tipLength); // upper tip
dc.DrawRectangle(scrollbarSide, actualDim - m_tipLength, m_scrollbarWidth, m_tipLength); // lower tip
// draw the margins
dc.SetPen(m_marginColor);
dc.SetBrush(m_marginColor);
dc.DrawRectangle(scrollbarSide, m_tipLength, m_scrollbarWidth, scrollbarStart + m_tipLength); // above the scrollbar
dc.DrawRectangle(scrollbarSide, scrollbarStart + scrollbarLength - m_tipLength, m_scrollbarWidth, actualDim - scrollbarLength - scrollbarStart); // below the scrollbar
dc.DrawRectangle(0, 0, scrollbarSide, actualDim); // left side of the scrollbar
dc.DrawRectangle(m_marginWidth - scrollbarSide, 0, scrollbarSide, actualDim); // right side of the scrollbar
// draw the scrollbar
dc.SetPen(m_scrollbarColor);
dc.SetBrush(m_scrollbarColor);
dc.DrawRectangle(scrollbarSide, scrollbarStart + m_tipLength, m_scrollbarWidth, scrollbarLength - 2 * m_tipLength);
}
else if (m_direction == wxHSCROLL && actualDim < m_virtualDim) // if actualDim >= m_virtualDim, the scrollbar is hidden, no need to paint it
{
if (m_scrolledWindow->IsBothDirections())
actualDim -= m_marginWidth; // must take into account the right margin
scrollbarSide = (m_marginWidth - m_scrollbarWidth) / 2;
scrollbarStart = (m_pixelsPerUnit*actualDim*m_viewStartInScrollUnits) / (float)m_virtualDim + 0.5; // + 0.5 is a cheap way round the float value
scrollbarLength = (actualDim*actualDim) / (float)m_virtualDim + 0.5;
if (scrollbarLength < m_minSliderSize)
{
scrollbarStart = (actualDim - m_minSliderSize)*(m_viewStartInScrollUnits*m_pixelsPerUnit / (float)(m_virtualDim - actualDim)) + 0.5;
scrollbarLength = m_minSliderSize;
}
if (scrollbarStart < 0) // the mouse is out of the panel
scrollbarStart = 0;
else if (scrollbarStart + scrollbarLength >= actualDim)
scrollbarStart = actualDim - scrollbarLength;
// draw the left and right tips
dc.SetPen(m_tipColor);
dc.SetBrush(m_tipColor);
dc.DrawRectangle(0, scrollbarSide, m_tipLength, m_scrollbarWidth); // left tip
dc.DrawRectangle(actualDim - m_tipLength, scrollbarSide, m_tipLength, m_scrollbarWidth); // right tip
// draw the margins
dc.SetPen(m_marginColor);
dc.SetBrush(m_marginColor);
dc.DrawRectangle(m_tipLength, scrollbarSide, scrollbarStart + m_tipLength, m_scrollbarWidth); // left of the scrollbar
dc.DrawRectangle(scrollbarStart + scrollbarLength - m_tipLength, scrollbarSide, actualDim - scrollbarLength - scrollbarStart, m_scrollbarWidth); // right of the scrollbar
dc.DrawRectangle(0, 0, actualDim, scrollbarSide); // above the scrollbar
dc.DrawRectangle(0, m_marginWidth - scrollbarSide, actualDim, scrollbarSide); // below the scrollbar
dc.DrawRectangle(actualDim, 0, m_marginWidth, m_marginWidth); // lower right corner of the scrolled window
// draw the scrollbar
dc.SetPen(m_scrollbarColor);
dc.SetBrush(m_scrollbarColor);
dc.DrawRectangle(scrollbarStart + m_tipLength, scrollbarSide, scrollbarLength - 2 * m_tipLength, m_scrollbarWidth);
}
}
void MyScrollbar::OnEraseBackground(wxEraseEvent & event)
{
// necessary to avoid automatic background erasing
SetBackgroundColour(wxColor(255,255,255));
}
void MyScrollbar::OnMouseLeftDown(wxMouseEvent &event)
{
int scrollbarStart, scrollbarLength, eventPos ;
if (m_direction == wxVSCROLL)
eventPos = event.m_y;
else
eventPos = event.m_x;
int actualDim = m_actualDim;
scrollbarStart = (m_pixelsPerUnit*actualDim*m_viewStartInScrollUnits) / (float)m_virtualDim + 0.5; // + 0.5 is a cheap way to round the float value
scrollbarLength = MAX((actualDim*actualDim) / (float)m_virtualDim + 0.5, m_minSliderSize);
m_previousMouse = eventPos;
/*eventPos >= scrollbarStart &&*/
if (eventPos < scrollbarStart + scrollbarLength)
m_mouseLocation = ON_SCROLLBAR;
else
m_mouseLocation = BEFORE_SCROLLBAR;
CaptureMouse();
}
void MyScrollbar::OnMouseLeftUp(wxMouseEvent &event)
{
if (HasCapture())
{
ReleaseMouse();
}
m_mouseLocation = NOWHERE;
}
void MyScrollbar::OnMouseMove(wxMouseEvent &event)
{
int dMotion, actualDim;
if (!event.Dragging())
return; // button is not pressed, the user doesn't scroll
actualDim = m_actualDim;
if (m_direction == wxVSCROLL && m_mouseLocation == ON_SCROLLBAR)
{
dMotion = event.m_y - m_previousMouse;
m_viewStartInPixels += (dMotion*m_virtualDim) / (float)actualDim + 0.5; // in pixels
if (m_viewStartInPixels < 0)
m_viewStartInPixels = 0;
else if (m_viewStartInPixels + actualDim >= m_virtualDim)
m_viewStartInPixels = m_virtualDim - actualDim;
m_viewStartInScrollUnits = m_viewStartInPixels / (float)m_pixelsPerUnit + 0.5; // in scroll units
m_scrolledWindow->Scroll(-1, m_viewStartInScrollUnits); // -1 means no change in this direction
SetViewStart(m_viewStartInScrollUnits);
m_previousMouse = event.m_y;
}
else if (m_direction == wxHSCROLL && m_mouseLocation == ON_SCROLLBAR)
{
if (m_scrolledWindow->IsBothDirections())
actualDim -= m_marginWidth; // must take into account the right margin
dMotion = event.m_x - m_previousMouse;
m_viewStartInPixels += (dMotion*m_virtualDim) / (float)actualDim + 0.5; // in pixels
if (m_viewStartInPixels < 0)
m_viewStartInPixels = 0;
else if (m_viewStartInPixels + actualDim >= m_virtualDim)
m_viewStartInPixels = m_virtualDim - actualDim;
m_viewStartInScrollUnits = m_viewStartInPixels / (float)m_pixelsPerUnit + 0.5; // in scroll units
m_scrolledWindow->Scroll(m_viewStartInScrollUnits, -1); // -1 means no change in this direction
SetViewStart(m_viewStartInScrollUnits);
m_previousMouse = event.m_x;
}
Refresh();
Update();
}
void MyScrollbar::OnMouseWheel(wxMouseEvent &event)
{
int dMotion, actualDim;
if (event.GetWheelRotation() > 0)
dMotion = -m_pixelsPerUnit;
else
dMotion = m_pixelsPerUnit;
m_previousMouse += dMotion;
actualDim = m_actualDim;
if (m_direction == wxVSCROLL)
{
m_viewStartInPixels += (dMotion*m_virtualDim) / (float)actualDim + 0.5; // in pixels
if (m_viewStartInPixels < 0)
m_viewStartInPixels = 0;
else if (m_viewStartInPixels + actualDim >= m_virtualDim)
m_viewStartInPixels = m_virtualDim - actualDim;
m_viewStartInScrollUnits = m_viewStartInPixels / (float)m_pixelsPerUnit + 0.5; // in scroll units
m_scrolledWindow->Scroll(-1, m_viewStartInScrollUnits); // -1 means no change in this direction
SetViewStart(m_viewStartInScrollUnits);
}
else
{
dMotion = -dMotion;
if (m_scrolledWindow->IsBothDirections())
actualDim -= m_marginWidth; // must take into account the right margin
m_viewStartInPixels += (dMotion*m_virtualDim) / (float)actualDim + 0.5; // in pixels
if (m_viewStartInPixels < 0)
m_viewStartInPixels = 0;
else if (m_viewStartInPixels + actualDim >= m_virtualDim)
m_viewStartInPixels = m_virtualDim - actualDim;
m_viewStartInScrollUnits = m_viewStartInPixels / (float)m_pixelsPerUnit + 0.5; // in scroll units
m_scrolledWindow->Scroll(m_viewStartInScrollUnits, -1); // -1 means no change in this direction
SetViewStart(m_viewStartInScrollUnits);
}
Refresh();
Update();
}

View file

@ -0,0 +1,51 @@
#pragma once
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
enum {BEFORE_SCROLLBAR, ON_SCROLLBAR, AFTER_SCROLLBAR, NOWHERE};
class ScrolledWindow;
class MyScrollbar : public wxPanel
{
public:
MyScrollbar(wxWindow *parent, wxWindowID id, wxPoint position, wxSize size, ScrolledWindow* scrolledWindow, long direction, int scrollbarWidth, int tipLength = 0);
void SetViewStart(int start);
void SetTipColor(wxColour color);
void SetMarginColor(wxColour color);
void SetScrollbarColor(wxColour color);
void SetScrollbarTip(int len);
void SetVirtualDim(int pixelsPerUnit, int noUnits);
private:
long m_direction;
int m_virtualDim;
int m_actualDim;
int m_pixelsPerUnit;
int m_viewStartInPixels;
int m_viewStartInScrollUnits;
int m_scrollbarWidth;
int m_marginWidth;
int m_previousMouse;
int m_mouseLocation;
int m_tipLength;
int m_minSliderSize;
wxColour m_tipColor;
wxColour m_marginColor;
wxColour m_scrollbarColor;
ScrolledWindow* m_scrolledWindow; // the scrolledWindow whose the scrollbar is controlling
void OnPaint(wxPaintEvent& event);
void OnSize(wxSizeEvent& WXUNUSED(event));
void OnEraseBackground(wxEraseEvent & event);
void OnMouseLeftDown(wxMouseEvent &event);
void OnMouseLeftUp(wxMouseEvent &event);
void OnMouseMove(wxMouseEvent &event);
void OnMouseWheel(wxMouseEvent &event);
};

View file

@ -0,0 +1,231 @@
// for scroll
#pragma once
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/splitter.h>
#include "ScrolledWindow.hpp"
#include "Scrollbar.hpp"
ScrolledWindow::ScrolledWindow(wxWindow *parent, wxWindowID id, wxPoint position, wxSize size, long style, int marginWidth, int scrollbarWidth, int tipLength)
: wxScrolled<wxWindow>(parent, id, position, size, style)
{
bool bVertical = (style & wxVSCROLL) != 0;
bool bHorizontal = (style & wxHSCROLL) != 0;
m_bothDirections = bVertical & bHorizontal;
EnableScrolling(bHorizontal, bVertical);
ShowScrollbars(wxSHOW_SB_NEVER, wxSHOW_SB_NEVER);
m_rightScrollbar = NULL;
m_bottomScrollbar = NULL;
m_verticalSplitter = NULL;
m_horizontalSplitter = NULL;
m_marginWidth = marginWidth;
wxSize hsSize = size;
hsSize.SetWidth(hsSize.GetWidth() - marginWidth);
hsSize.SetHeight(hsSize.GetHeight() - marginWidth);
wxSize vsSize = size;
vsSize.SetWidth(vsSize.GetWidth() - marginWidth);
if (bVertical) {
m_verticalSplitter = new wxWindow(this, -1, position, vsSize);
m_userPanel = new wxPanel(m_verticalSplitter, -1, wxPoint(0, 0), wxSize(size.GetWidth() - marginWidth, size.GetHeight()));
m_scroll_win = new wxWindow(m_verticalSplitter, -1, wxPoint(size.GetWidth() - marginWidth, 0), wxSize(marginWidth, size.GetHeight()));
m_rightScrollbar = new MyScrollbar(m_scroll_win, -1, wxPoint(0, 0), wxSize(scrollbarWidth, size.GetHeight()), this, wxVSCROLL, scrollbarWidth, tipLength);
} else if (bHorizontal) {
m_horizontalSplitter = new wxSplitterWindow(this, -1, position, hsSize);
m_userPanel = new wxPanel(m_horizontalSplitter, -1, wxPoint(0, 0), wxSize(size.GetWidth() - marginWidth, size.GetHeight() - marginWidth));
m_userPanel->SetBackgroundColour(parent->GetBackgroundColour());
m_bottomScrollbar = new MyScrollbar(m_horizontalSplitter, -1, wxPoint(0, 0), wxSize(size.GetWidth() - marginWidth, marginWidth), this, wxHSCROLL, scrollbarWidth,
tipLength);
m_horizontalSplitter->SplitHorizontally(m_userPanel, m_bottomScrollbar, -marginWidth);
m_horizontalSplitter->SetSashInvisible();
}
SetTargetWindow(m_userPanel); // very very important line
Bind(wxEVT_SIZE, &ScrolledWindow::OnSize, this);
Bind(wxEVT_SCROLLWIN_TOP, &ScrolledWindow::OnScroll, this);
Bind(wxEVT_SCROLLWIN_BOTTOM, &ScrolledWindow::OnScroll, this);
Bind(wxEVT_SCROLLWIN_LINEUP, &ScrolledWindow::OnScroll, this);
Bind(wxEVT_SCROLLWIN_LINEDOWN, &ScrolledWindow::OnScroll, this);
Bind(wxEVT_SCROLLWIN_PAGEUP, &ScrolledWindow::OnScroll, this);
Bind(wxEVT_SCROLLWIN_PAGEDOWN, &ScrolledWindow::OnScroll, this);
Bind(wxEVT_SCROLLWIN_THUMBTRACK, &ScrolledWindow::OnScroll, this);
Bind(wxEVT_SCROLLWIN_THUMBRELEASE, &ScrolledWindow::OnScroll, this);
Bind(wxEVT_MOUSEWHEEL, &ScrolledWindow::OnMouseWheel, this);
}
void ScrolledWindow::OnMouseWheel(wxMouseEvent &event)
{
m_rightScrollbar->GetEventHandler()->ProcessEvent(event);
// int dMotion, actualDim;
// if (event.GetWheelRotation() > 0)
// dMotion = -m_pixelsPerUnit;
// else
// dMotion = m_pixelsPerUnit;
// m_previousMouse += dMotion;
// actualDim = m_actualDim;
// if (m_direction == wxVSCROLL) {
// m_viewStartInPixels += (dMotion * m_virtualDim) / (float) actualDim + 0.5; // in pixels
// if (m_viewStartInPixels < 0)
// m_viewStartInPixels = 0;
// else if (m_viewStartInPixels + actualDim >= m_virtualDim)
// m_viewStartInPixels = m_virtualDim - actualDim;
// m_viewStartInScrollUnits = m_viewStartInPixels / (float) m_pixelsPerUnit + 0.5; // in scroll units
// m_scrolledWindow->Scroll(-1, m_viewStartInScrollUnits); // -1 means no change in this direction
// SetViewStart(m_viewStartInScrollUnits);
//} else {
// dMotion = -dMotion;
// if (m_scrolledWindow->IsBothDirections()) actualDim -= m_marginWidth; // must take into account the right margin
// m_viewStartInPixels += (dMotion * m_virtualDim) / (float) actualDim + 0.5; // in pixels
// if (m_viewStartInPixels < 0)
// m_viewStartInPixels = 0;
// else if (m_viewStartInPixels + actualDim >= m_virtualDim)
// m_viewStartInPixels = m_virtualDim - actualDim;
// m_viewStartInScrollUnits = m_viewStartInPixels / (float) m_pixelsPerUnit + 0.5; // in scroll units
// m_scrolledWindow->Scroll(m_viewStartInScrollUnits, -1); // -1 means no change in this direction
// SetViewStart(m_viewStartInScrollUnits);
//}
// Refresh();
// Update();
}
void ScrolledWindow::SetTipColor(wxColour color)
{
if (m_rightScrollbar) m_rightScrollbar->SetTipColor(color);
if (m_bottomScrollbar) m_bottomScrollbar->SetTipColor(color);
}
void ScrolledWindow::Refresh()
{
// m_rightScrollbar->SetViewStart(0);
// m_rightScrollbar->Refresh();
// m_rightScrollbar->Update();
// m_userPanel->Refresh();
// m_bottomScrollbar->SetViewStart(0);
// m_rightScrollbar->Refresh();
// m_bottomScrollbar->Refresh();
}
void ScrolledWindow::SetBackgroundColour(wxColour color)
{
wxWindow::SetBackgroundColour(color);
m_verticalSplitter->SetBackgroundColour(color);
m_userPanel->SetBackgroundColour(color);
m_scroll_win->SetBackgroundColour(color);
}
void ScrolledWindow::SetMarginColor(wxColour color)
{
if (m_rightScrollbar) m_rightScrollbar->SetMarginColor(color);
if (m_bottomScrollbar) m_bottomScrollbar->SetMarginColor(color);
}
void ScrolledWindow::SetScrollbarColor(wxColour color)
{
if (m_rightScrollbar) m_rightScrollbar->SetScrollbarColor(color);
if (m_bottomScrollbar) m_bottomScrollbar->SetScrollbarColor(color);
}
void ScrolledWindow::SetScrollbarTip(int len)
{
if (m_rightScrollbar) m_rightScrollbar->SetScrollbarTip(len);
if (m_bottomScrollbar) m_bottomScrollbar->SetScrollbarTip(len);
}
void ScrolledWindow::SetVirtualSize(int x, int y) { SetScrollbars(1, 1, x, y); }
void ScrolledWindow::SetVirtualSize(wxSize &size) { SetScrollbars(1, 1, size.GetWidth(), size.GetHeight()); }
void ScrolledWindow::SetScrollbars(int pixelsPerUnitX, int pixelsPerUnitY, int noUnitsX, int noUnitsY, int xPos, int yPos, bool noRefresh)
{
wxScrolled<wxWindow>::SetScrollbars(pixelsPerUnitX, pixelsPerUnitY, noUnitsX, noUnitsY, xPos, yPos, noRefresh);
wxScrolled<wxWindow>::SetVirtualSize(pixelsPerUnitX * noUnitsX, pixelsPerUnitY * noUnitsY); // So that GetVirtualSize gives good values
if (m_rightScrollbar) m_rightScrollbar->SetVirtualDim(pixelsPerUnitY, noUnitsY);
if (m_bottomScrollbar) m_bottomScrollbar->SetVirtualDim(pixelsPerUnitX, noUnitsX);
}
void ScrolledWindow::OnSize(wxSizeEvent &event)
{
int startX, startY, virtX, virtY, clientW, clientH;
if (!m_verticalSplitter && !m_horizontalSplitter) return;
GetViewStart(&startX, &startY);
GetVirtualSize(&virtX, &virtY);
GetClientSize(&clientW, &clientH);
// trace / log in the output / console window
// wxString str; str.sprintf("Actual=(%d,%d). Virtual=(%d,%d)\n", clientW, clientH, virtX, virtY); OutputDebugString(str);
if (m_verticalSplitter) m_verticalSplitter->SetSize(clientW, clientH);
if (m_horizontalSplitter) m_horizontalSplitter->SetSize(clientW, clientH);
if (m_rightScrollbar) {
if (clientH >= virtY) // hide the scrollbar by enlarging the user panel
{
// m_verticalSplitter->SetSashPosition(clientW);
m_userPanel->SetSize(GetClientSize());
m_rightScrollbar->SetSize(0, clientH);
m_userPanel->Refresh();
m_userPanel->Update();
} else {
// m_verticalSplitter->SetSashPosition(clientW - m_marginWidth); // resize the splitter panes
}
m_rightScrollbar->SetViewStart(startY);
m_rightScrollbar->Refresh();
m_rightScrollbar->Update(); // we want to repaint
}
if (m_bottomScrollbar) {
if (clientW >= virtX) // hide the scrollbar by enlarging the user panel
{
m_horizontalSplitter->SetSashPosition(clientH); // we don't need horizontal scrollbar
if (m_rightScrollbar)
m_userPanel->SetSize(clientW - m_marginWidth, clientH); // don't hide the vertical scrollbar
else
m_userPanel->SetSize(GetClientSize());
m_bottomScrollbar->SetSize(clientW, 0);
m_userPanel->Refresh();
m_userPanel->Update();
} else {
m_horizontalSplitter->SetSashPosition(clientH - m_marginWidth); // resize the splitter panes
}
m_bottomScrollbar->SetViewStart(startX);
m_bottomScrollbar->Refresh();
m_bottomScrollbar->Update(); // we want to repaint even if the panel gets smaller
}
Layout();
AdjustScrollbars();
}
void ScrolledWindow::OnScroll(wxScrollWinEvent &event)
{
int startX, startY;
GetViewStart(&startX, &startY);
if (m_rightScrollbar) {
m_rightScrollbar->SetViewStart(startY);
m_rightScrollbar->Refresh();
m_rightScrollbar->Update();
}
if (m_bottomScrollbar) {
m_bottomScrollbar->SetViewStart(startX);
m_bottomScrollbar->Refresh();
m_bottomScrollbar->Update();
}
// event.Skip(); // then do the regular process // uncomment if you want to use the mouse and the trackpad in the scrolled panel
}

View file

@ -0,0 +1,45 @@
#pragma once
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/splitter.h>
#include "Scrollbar.hpp"
class MyScrollbar;
class ScrolledWindow : public wxScrolled<wxWindow>
{
public:
ScrolledWindow(wxWindow *parent, wxWindowID id, wxPoint position, wxSize size, long style, int marginWidth = 0, int scrollbarWidth = 4, int tipLength = 0);
void OnMouseWheel(wxMouseEvent &event);
void SetTipColor(wxColour color);
void Refresh();
void SetBackgroundColour(wxColour color);
void SetMarginColor(wxColour color);
void SetScrollbarColor(wxColour color);
void SetScrollbarTip(int len);
virtual void SetVirtualSize(int x, int y);
virtual void SetVirtualSize(wxSize &size);
wxPanel * GetPanel() { return m_userPanel; }
// wxSplitterWindow* GetVerticalSplitter() { return m_verticalSplitter; }
// wxSplitterWindow* GetHorizontalSplitter() { return m_horizontalSplitter; }
bool IsBothDirections() { return m_bothDirections; }
virtual void SetScrollbars(int pixelsPerUnitX, int pixelsPerUnitY, int noUnitsX, int noUnitsY, int xPos = 0, int yPos = 0, bool noRefresh = false);
private:
wxPanel * m_userPanel; // the panel targeted by the scrolled window
wxWindow * m_scroll_win;
MyScrollbar *m_rightScrollbar;
MyScrollbar *m_bottomScrollbar;
// wxSplitterWindow* m_verticalSplitter;
wxWindow * m_verticalSplitter;
wxSplitterWindow *m_horizontalSplitter;
int m_marginWidth;
bool m_bothDirections;
void OnSize(wxSizeEvent &WXUNUSED(event));
void OnScroll(wxScrollWinEvent &event);
};

View file

@ -0,0 +1,325 @@
#include "SideButton.hpp"
#include "Label.hpp"
#include <wx/dcgraph.h>
BEGIN_EVENT_TABLE(SideButton, wxPanel)
EVT_LEFT_DOWN(SideButton::mouseDown)
EVT_LEFT_UP(SideButton::mouseReleased)
EVT_PAINT(SideButton::paintEvent)
END_EVENT_TABLE()
SideButton::SideButton(wxWindow* parent, wxString text, wxString icon, long stlye, int iconSize)
: wxWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, stlye)
, state_handler(this)
{
radius = 12;
extra_size = wxSize(38, 10);
icon_offset = 0;
text_orientation = HO_Left;
text_margin = 15;
border_color.append(0x6B6B6B, StateColor::Disabled);
border_color.append(0x1B8844, StateColor::Pressed);
border_color.append(0xFFFFF, StateColor::Hovered);
border_color.append(0x00AE42, StateColor::Normal);
text_color.append(0xACACAC, StateColor::Disabled);
text_color.append(0xFFFFFF, StateColor::Pressed);
text_color.append(0xFFFFFF, StateColor::Hovered);
text_color.append(0xFFFFFF, StateColor::Normal);
background_color.append(0x6B6B6B, StateColor::Disabled);
background_color.append(0x1B8844, StateColor::Pressed);
background_color.append(0x00AE42, StateColor::Hovered);
background_color.append(0x00AE42, StateColor::Normal);
state_handler.attach({ &border_color, &text_color, &background_color });
state_handler.update_binds();
// icon only
if (!icon.IsEmpty()) {
this->icon = ScalableBitmap(this, icon.ToStdString(), iconSize > 0 ? iconSize : 14);
}
SetFont(Label::Body_14);
wxWindow::SetLabel(text);
messureSize();
}
void SideButton::SetCornerRadius(double radius)
{
this->radius = radius;
Refresh();
}
void SideButton::SetCornerEnable(const std::vector<bool>& enable)
{
radius_enable.clear();
for (auto en : enable) {
radius_enable.push_back(en);
}
}
void SideButton::SetTextLayout(EHorizontalOrientation orient, int margin)
{
text_orientation = orient;
text_margin = margin;
messureSize();
Refresh();
}
void SideButton::SetLayoutStyle(int style)
{
layout_style = style;
messureSize();
Refresh();
}
void SideButton::SetLabel(const wxString& label)
{
wxWindow::SetLabel(label);
messureSize();
Refresh();
}
bool SideButton::SetForegroundColour(wxColour const &color)
{
text_color = StateColor(color);
state_handler.update_binds();
return true;
}
bool SideButton::SetBackgroundColour(wxColour const& color)
{
background_color = StateColor(color);
state_handler.update_binds();
return true;
}
bool SideButton::SetBottomColour(wxColour const& color)
{
bottom_color = color;
return true;
}
void SideButton::SetMinSize(const wxSize& size)
{
minSize = size;
messureSize();
}
void SideButton::SetBorderColor(StateColor const &color)
{
border_color = color;
state_handler.update_binds();
Refresh();
}
void SideButton::SetForegroundColor(StateColor const &color)
{
text_color = color;
state_handler.update_binds();
Refresh();
}
void SideButton::SetBackgroundColor(StateColor const &color)
{
background_color = color;
state_handler.update_binds();
Refresh();
}
bool SideButton::Enable(bool enable)
{
bool result = wxWindow::Enable(enable);
if (result) {
wxCommandEvent e(EVT_ENABLE_CHANGED);
e.SetEventObject(this);
GetEventHandler()->ProcessEvent(e);
}
return result;
}
void SideButton::Rescale()
{
if (this->icon.bmp().IsOk())
this->icon.msw_rescale();
messureSize();
}
void SideButton::SetExtraSize(const wxSize& size)
{
extra_size = size;
messureSize();
}
void SideButton::SetIconOffset(const int offset)
{
icon_offset = offset;
messureSize();
}
void SideButton::paintEvent(wxPaintEvent& evt)
{
// depending on your system you may need to look at double-buffered dcs
wxPaintDC dc(this);
wxGCDC dc2(dc);
render(dc2);
}
/*
* 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 SideButton::render(wxDC& dc)
{
wxSize size = GetSize();
// draw background
dc.SetPen(wxNullPen);
dc.SetBrush(bottom_color);
dc.DrawRectangle(0, 0, size.x, size.y);
int states = state_handler.states();
dc.SetBrush(wxBrush(background_color.colorForStates(states)));
dc.SetPen(wxPen(border_color.colorForStates(states)));
int pen_width = dc.GetPen().GetWidth();
// draw icon style
if (icon.bmp().IsOk()) {
if (radius > 1e-5) {
dc.DrawRoundedRectangle(0, 0, size.x, size.y, radius);
dc.DrawRectangle(radius, 0, size.x - radius, size.y);
dc.SetPen(wxNullPen);
dc.DrawRectangle(radius - pen_width, pen_width, radius, size.y - 2 * pen_width);
}
else {
dc.DrawRectangle(0, 0, size.x, size.y);
}
}
// draw text style
else {
if (radius > 1e-5) {
if (layout_style == 1) {
dc.DrawRoundedRectangle(0, 0, size.x, size.y, radius);
dc.SetPen(wxNullPen);
} else {
dc.DrawRoundedRectangle(0, 0, size.x, size.y, radius);
dc.DrawRectangle(0, 0, size.x - radius, size.y);
dc.SetPen(wxNullPen);
dc.DrawRectangle(size.x - radius - pen_width, pen_width, 2 * pen_width, size.y - 2 * pen_width);
}
} else {
dc.DrawRectangle(0, 0, size.x, size.y);
}
}
dc.SetBrush(*wxTRANSPARENT_BRUSH);
// calc content size
wxSize szIcon;
wxSize szContent = textSize;
if (icon.bmp().IsOk()) {
if (szContent.y > 0) {
//BBS norrow size between text and icon
szContent.x += 5;
}
szIcon = icon.bmp().GetSize();
szContent.x += szIcon.x;
if (szIcon.y > szContent.y)
szContent.y = szIcon.y;
}
// move to center
wxRect rcContent = { {0, 0}, size };
if (text_orientation == EHorizontalOrientation::HO_Center) {
wxSize offset = (size - szContent) / 2;
rcContent.Deflate(offset.x, offset.y);
} else if (text_orientation == EHorizontalOrientation::HO_Left) {
wxSize offset = (size - szContent) / 2;
rcContent.Deflate(text_margin, offset.y);
} else if (text_orientation == EHorizontalOrientation::HO_Right) {
wxSize offset = (size - szContent) / 2;
rcContent.Deflate(size.x - text_margin, offset.y);
}
// start draw
wxPoint pt = rcContent.GetLeftTop();
if (icon.bmp().IsOk()) {
//BBS extra pixels for icon
pt.x += icon_offset;
pt.y += (rcContent.height - szIcon.y) / 2;
dc.DrawBitmap(icon.bmp(), pt);
//BBS norrow size between text and icon
pt.x += szIcon.x + 5;
pt.y = rcContent.y;
}
auto text = GetLabel();
if (!text.IsEmpty()) {
pt.y += (rcContent.height - textSize.y) / 2;
dc.SetFont(GetFont());
dc.SetTextForeground(text_color.colorForStates(states));
dc.DrawText(text, pt);
}
}
void SideButton::messureSize()
{
textSize = GetTextExtent(GetLabel());
if (minSize.GetWidth() > 0) {
wxWindow::SetMinSize(minSize);
return;
}
wxSize szContent = textSize;
if (this->icon.bmp().IsOk()) {
if (szContent.y > 0) {
szContent.x += 5;
}
wxSize szIcon = this->icon.bmp().GetSize();
szContent.x += szIcon.x;
if (szIcon.y > szContent.y)
szContent.y = szIcon.y;
//BBS icon only
wxWindow::SetMinSize(szContent + wxSize(szContent.GetX() + extra_size.GetX(), minSize.GetHeight()));
}
else {
if (minSize.GetHeight() > 0) {
//BBS with text size
wxWindow::SetMinSize(wxSize(szContent.GetX() + extra_size.GetX(), minSize.GetHeight()));
} else {
//BBS with text size
wxWindow::SetMinSize(szContent + extra_size);
}
}
}
void SideButton::mouseDown(wxMouseEvent& event)
{
event.Skip();
pressedDown = true;
SetFocus();
CaptureMouse();
}
void SideButton::mouseReleased(wxMouseEvent& event)
{
event.Skip();
if (pressedDown) {
pressedDown = false;
ReleaseMouse();
if (wxRect({0, 0}, GetSize()).Contains(event.GetPosition()))
sendButtonEvent();
}
}
void SideButton::sendButtonEvent()
{
wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
event.SetEventObject(this);
GetEventHandler()->ProcessEvent(event);
}

View file

@ -0,0 +1,93 @@
#ifndef slic3r_GUI_SideButton_hpp_
#define slic3r_GUI_SideButton_hpp_
#include <wx/stattext.h>
#include <wx/vlbox.h>
#include <wx/combo.h>
#include "../wxExtensions.hpp"
#include "StateHandler.hpp"
class SideButton : public wxWindow
{
public:
enum EHorizontalOrientation : unsigned char
{
HO_Left,
HO_Center,
HO_Right,
Num_Horizontal_Orientations
};
SideButton(wxWindow* parent, wxString text, wxString icon = "", long style = 0, int iconSize = 0);
void SetCornerRadius(double radius);
//BBS set enable array
void SetCornerEnable(const std::vector<bool>& enable);
void SetTextLayout(EHorizontalOrientation orient, int margin = 15);
void SetLayoutStyle(int style);
void SetLabel(const wxString& label);
bool SetForegroundColour(wxColour const & colour) override;
bool SetBackgroundColour(wxColour const & color) override;
bool SetBottomColour(wxColour const &color);
void SetMinSize(const wxSize& size) override;
void SetBorderColor(StateColor const & color);
void SetForegroundColor(StateColor const &color);
void SetBackgroundColor(StateColor const &color);
bool Enable(bool enable = true);
void Rescale();
void SetExtraSize(const wxSize& size);
void SetIconOffset(const int offset);
private:
wxSize textSize;
wxSize minSize;
ScalableBitmap icon;
double radius;
wxSize extra_size;
int icon_offset;
std::vector<bool> radius_enable;
StateHandler state_handler;
StateColor text_color;
StateColor border_color;
StateColor background_color;
wxColour bottom_color;
bool pressedDown = false;
int layout_style = 0;
EHorizontalOrientation text_orientation;
int text_margin;
void paintEvent(wxPaintEvent& evt);
void render(wxDC& dc);
void messureSize();
void mouseDown(wxMouseEvent& event);
void mouseReleased(wxMouseEvent& event);
void sendButtonEvent();
DECLARE_EVENT_TABLE()
};
#endif // !slic3r_GUI_Button_hpp_

View file

@ -0,0 +1,92 @@
#include "SideMenuPopup.hpp"
#include "Label.hpp"
#include <wx/dcgraph.h>
wxBEGIN_EVENT_TABLE(SidePopup,wxPopupTransientWindow)
EVT_PAINT(SidePopup::paintEvent)
wxEND_EVENT_TABLE()
SidePopup::SidePopup(wxWindow* parent)
:wxPopupTransientWindow(parent,
wxBORDER_NONE |
wxPU_CONTAINS_CONTROLS)
{
#ifdef __WINDOWS__
SetDoubleBuffered(true);
#endif //__WINDOWS__
}
SidePopup::~SidePopup()
{
;
}
void SidePopup::OnDismiss()
{
wxPopupTransientWindow::OnDismiss();
}
bool SidePopup::ProcessLeftDown(wxMouseEvent& event)
{
return wxPopupTransientWindow::ProcessLeftDown(event);
}
bool SidePopup::Show( bool show )
{
return wxPopupTransientWindow::Show(show);
}
void SidePopup::Popup(wxWindow* focus)
{
Create();
if (focus) {
wxPoint pos = focus->ClientToScreen(wxPoint(0, -6));
Position(pos, {0, focus->GetSize().y + 12});
}
wxPopupTransientWindow::Popup();
}
void SidePopup::Create()
{
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
int max_width = 0;
int height = 0;
for (auto btn : btn_list)
{
max_width = std::max(btn->GetMinSize().x, max_width);
}
for (auto btn : btn_list)
{
wxSize size = btn->GetMinSize();
height += size.y;
size.x = max_width;
btn->SetMinSize(size);
btn->SetSize(size);
sizer->Add(btn, 0, 0, 0);
}
SetSize(wxSize(max_width, height));
SetSizer(sizer, true);
Layout();
Refresh();
}
void SidePopup::paintEvent(wxPaintEvent& evt)
{
wxPaintDC dc(this);
wxSize size = GetSize();
dc.SetBrush(wxTransparentColour);
dc.DrawRectangle(0, 0, size.x, size.y);
}
void SidePopup::append_button(SideButton* btn)
{
btn_list.push_back(btn);
}

View file

@ -0,0 +1,35 @@
#ifndef slic3r_GUI_SideMenuPopup_hpp_
#define slic3r_GUI_SideMenuPopup_hpp_
#include <wx/stattext.h>
#include <wx/vlbox.h>
#include <wx/combo.h>
#include <wx/htmllbox.h>
#include <wx/frame.h>
#include "../wxExtensions.hpp"
#include "StateHandler.hpp"
#include "SideButton.hpp"
class SidePopup : public wxPopupTransientWindow
{
private:
std::vector<SideButton*> btn_list;
public:
SidePopup(wxWindow* parent);
~SidePopup();
void Create();
virtual void Popup(wxWindow *focus = NULL) wxOVERRIDE;
virtual void OnDismiss() wxOVERRIDE;
virtual bool ProcessLeftDown(wxMouseEvent& event) wxOVERRIDE;
virtual bool Show(bool show = true) wxOVERRIDE;
void append_button(SideButton* btn);
void paintEvent(wxPaintEvent& evt);
DECLARE_EVENT_TABLE()
};
#endif // !slic3r_GUI_Button_hpp_

View file

@ -0,0 +1,215 @@
#include "SideTools.hpp"
#include <wx/dcmemory.h>
#include <wx/dcgraph.h>
#include "Label.hpp"
#include "../wxExtensions.hpp"
#include "../I18N.hpp"
#include "../GUI.hpp"
namespace Slic3r { namespace GUI {
SideTools::SideTools(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size)
{
wxPanel::Create(parent, id, pos, wxSize(0, FromDIP(50)));
Bind(wxEVT_PAINT, &SideTools::OnPaint, this);
SetBackgroundColour(*wxWHITE);
m_printing_img = create_scaled_bitmap("printer", nullptr, 16);
m_arrow_img = create_scaled_bitmap("monitor_arrow", nullptr, 14);
m_none_printing_img = create_scaled_bitmap("tab_monitor_active", nullptr, 24);
m_none_arrow_img = create_scaled_bitmap("monitor_none_arrow", nullptr, 14);
m_none_add_img = create_scaled_bitmap("monitor_none_add", nullptr, 14);
m_wifi_none_img = create_scaled_bitmap("monitor_signal_no", nullptr, 18);
m_wifi_weak_img = create_scaled_bitmap("monitor_signal_weak", nullptr, 18);
m_wifi_middle_img = create_scaled_bitmap("monitor_signal_middle", nullptr, 18);
m_wifi_strong_img = create_scaled_bitmap("monitor_signal_strong", nullptr, 18);
m_intetval_timer = new wxTimer();
m_intetval_timer->SetOwner(this);
this->Bind(wxEVT_TIMER, &SideTools::stop_interval, this);
this->Bind(wxEVT_ENTER_WINDOW, &SideTools::on_mouse_enter, this);
this->Bind(wxEVT_LEAVE_WINDOW, &SideTools::on_mouse_leave, this);
this->Bind(wxEVT_LEFT_DOWN, &SideTools::on_mouse_left_down, this);
this->Bind(wxEVT_LEFT_UP, &SideTools::on_mouse_left_up, this);
}
SideTools::~SideTools() {}
void SideTools::set_none_printer_mode()
{
m_none_printer = true;
Refresh();
}
void SideTools::on_timer(wxTimerEvent &event)
{
}
void SideTools::set_current_printer_name(std::string dev_name)
{
m_none_printer = false;
m_dev_name = from_u8(dev_name);
Refresh();
}
void SideTools::set_current_printer_signal(WifiSignal sign)
{
if (last_printer_signal == sign) return;
last_printer_signal = sign;
m_none_printer = false;
m_wifi_type = sign;
Refresh();
}
void SideTools::start_interval()
{
m_intetval_timer->Start(SIDE_TOOL_CLICK_INTERVAL);
m_is_in_interval = true;
}
void SideTools::stop_interval(wxTimerEvent& event)
{
m_is_in_interval = false;
m_intetval_timer->Stop();
}
bool SideTools::is_in_interval()
{
return m_is_in_interval;
}
void SideTools::msw_rescale()
{
Refresh();
}
void SideTools::OnPaint(wxPaintEvent &event)
{
wxPaintDC dc(this);
doRender(dc);
}
void SideTools::render(wxDC &dc)
{
#ifdef __WXMSW__
wxSize size = GetSize();
wxMemoryDC memdc;
wxBitmap bmp(size.x, size.y);
memdc.SelectObject(bmp);
memdc.Blit({0, 0}, size, &dc, {0, 0});
{
wxGCDC dc2(memdc);
doRender(dc2);
}
memdc.SelectObject(wxNullBitmap);
dc.DrawBitmap(bmp, 0, 0);
#else
doRender(dc);
#endif
}
void SideTools::doRender(wxDC &dc)
{
auto left = FromDIP(15);
wxSize size = GetSize();
//if (m_none_printer) {
// dc.SetPen(SIDE_TOOLS_LIGHT_GREEN);
// dc.SetBrush(SIDE_TOOLS_LIGHT_GREEN);
// dc.DrawRectangle(0, 0, size.x, size.y);
//}
if (m_none_printer) {
dc.SetPen(SIDE_TOOLS_BRAND);
dc.SetBrush(SIDE_TOOLS_BRAND);
dc.DrawRectangle(0, 0, size.x, size.y);
dc.DrawBitmap(m_none_printing_img, left, (size.y - m_none_printing_img.GetSize().y) / 2);
left += (m_none_printing_img.GetSize().x + FromDIP(15));
dc.DrawBitmap(m_none_arrow_img, left, (size.y - m_none_arrow_img.GetSize().y) / 2);
left += (m_none_arrow_img.GetSize().x + FromDIP(6));
dc.SetFont(::Label::Body_14);
dc.SetBackgroundMode(wxTRANSPARENT);
dc.SetTextForeground(*wxWHITE);
auto sizet = dc.GetTextExtent(_L("No printer"));
dc.DrawText(_L("No printer"), wxPoint(left, (size.y - sizet.y) / 2));
left = size.x - FromDIP(30) - m_wifi_none_img.GetSize().x;
dc.DrawBitmap(m_none_add_img, left, (size.y - m_none_add_img.GetSize().y) / 2);
} else {
dc.DrawBitmap(m_printing_img, left, (size.y - m_printing_img.GetSize().y) / 2);
left += (m_printing_img.GetSize().x + FromDIP(5));
dc.DrawBitmap(m_arrow_img, left, (size.y - m_arrow_img.GetSize().y) / 2);
left += (m_arrow_img.GetSize().x + FromDIP(6));
dc.SetFont(::Label::Body_14);
dc.SetBackgroundMode(wxTRANSPARENT);
dc.SetTextForeground(SIDE_TOOLS_GREY900);
auto sizet = dc.GetTextExtent(m_dev_name);
auto text_end = size.x - m_wifi_none_img.GetSize().x - 20;
std::string finally_name = m_dev_name.ToStdString();
if (sizet.x > (text_end - left)) {
auto limit_width = text_end - left - dc.GetTextExtent("...").x - 20;
for (auto i = 0; i < m_dev_name.length(); i++) {
auto curr_width = dc.GetTextExtent(m_dev_name.substr(0, i));
if (curr_width.x >= limit_width) {
finally_name = (m_dev_name.substr(0, i) + wxString("...")).ToStdString();
break;
}
}
}
dc.DrawText(finally_name, wxPoint(left, (size.y - sizet.y) / 2));
left = size.x - FromDIP(18) - m_wifi_none_img.GetSize().x;
if (m_wifi_type == WifiSignal::NONE) dc.DrawBitmap(m_wifi_none_img, left, (size.y - m_wifi_none_img.GetSize().y) / 2);
if (m_wifi_type == WifiSignal::WEAK) dc.DrawBitmap(m_wifi_weak_img, left, (size.y - m_wifi_weak_img.GetSize().y) / 2);
if (m_wifi_type == WifiSignal::MIDDLE) dc.DrawBitmap(m_wifi_middle_img, left, (size.y - m_wifi_middle_img.GetSize().y) / 2);
if (m_wifi_type == WifiSignal::STRONG) dc.DrawBitmap(m_wifi_strong_img, left, (size.y - m_wifi_strong_img.GetSize().y) / 2);
}
if (m_hover) {
dc.SetPen(SIDE_TOOLS_BRAND);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(0, 0, size.x, size.y);
}
}
void SideTools::on_mouse_left_down(wxMouseEvent &evt)
{
m_click = true;
Refresh();
}
void SideTools::on_mouse_left_up(wxMouseEvent &evt)
{
m_click = false;
Refresh();
}
void SideTools::on_mouse_enter(wxMouseEvent &evt)
{
m_hover = true;
Refresh();
}
void SideTools::on_mouse_leave(wxMouseEvent &evt)
{
m_hover = false;
Refresh();
}
}}

View file

@ -0,0 +1,79 @@
#ifndef slic3r_GUI_SIDETOOLS_hpp_
#define slic3r_GUI_SIDETOOLS_hpp_
#include <wx/dcgraph.h>
#include <wx/gdicmn.h>
#include <wx/dcclient.h>
#include "../wxExtensions.hpp"
#define SIDE_TOOLS_GREY900 wxColour(38, 46, 48)
#define SIDE_TOOLS_GREY600 wxColour(144, 144, 144)
#define SIDE_TOOLS_GREY400 wxColour(206, 206, 206)
#define SIDE_TOOLS_BRAND wxColour(0, 174, 66)
#define SIDE_TOOLS_LIGHT_GREEN wxColour(219, 253, 231)
enum WifiSignal {
NONE,
WEAK,
MIDDLE,
STRONG,
};
#define SIDE_TOOL_CLICK_INTERVAL 20
namespace Slic3r { namespace GUI {
class SideTools : public wxPanel
{
private:
WifiSignal m_wifi_type{WifiSignal::NONE};
wxString m_dev_name;
bool m_hover{false};
bool m_click{false};
bool m_none_printer{true};
int last_printer_signal = 0;
wxBitmap m_printing_img;
wxBitmap m_arrow_img;
wxBitmap m_none_printing_img;
wxBitmap m_none_arrow_img;
wxBitmap m_none_add_img;
wxBitmap m_wifi_none_img;
wxBitmap m_wifi_weak_img;
wxBitmap m_wifi_middle_img;
wxBitmap m_wifi_strong_img;
protected:
wxBitmap m_bitmap_type;
wxStaticBitmap *m_bitmap_info;
wxStaticBitmap *m_bitmap_bind;
wxTimer * m_intetval_timer{nullptr};
bool m_is_in_interval {false};
public:
SideTools(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);
~SideTools();
void set_none_printer_mode();
void on_timer(wxTimerEvent &event);
void set_current_printer_name(std::string dev_name);
void set_current_printer_signal(WifiSignal sign);;
void start_interval();
void stop_interval(wxTimerEvent &event);
bool is_in_interval();
void msw_rescale();
protected:
void OnPaint(wxPaintEvent &event);
void render(wxDC &dc);
void doRender(wxDC &dc);
void on_mouse_enter(wxMouseEvent &evt);
void on_mouse_leave(wxMouseEvent &evt);
void on_mouse_left_down(wxMouseEvent &evt);
void on_mouse_left_up(wxMouseEvent &evt);
};
}} // namespace Slic3r::GUI
#endif // !slic3r_GUI_SIDETOOLS_hpp_

View file

@ -0,0 +1,325 @@
#include "SpinInput.hpp"
#include "Label.hpp"
#include "Button.hpp"
#include <wx/dcgraph.h>
BEGIN_EVENT_TABLE(SpinInput, wxPanel)
EVT_MOTION(SpinInput::mouseMoved)
EVT_ENTER_WINDOW(SpinInput::mouseEnterWindow)
EVT_LEAVE_WINDOW(SpinInput::mouseLeaveWindow)
EVT_KEY_DOWN(SpinInput::keyPressed)
EVT_KEY_UP(SpinInput::keyReleased)
EVT_MOUSEWHEEL(SpinInput::mouseWheelMoved)
// catch paint events
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(wxWindow * parent,
wxString text,
wxString label,
const wxPoint &pos,
const wxSize & size,
long style,
int min, int max, int initial)
: wxWindow(parent, wxID_ANY, pos, size)
, state_handler(this)
, border_color(std::make_pair(0xDBDBDB, (int) StateColor::Disabled),
std::make_pair(0x00AE42, (int) StateColor::Focused),
std::make_pair(0x00AE42, (int) StateColor::Hovered),
std::make_pair(0xDBDBDB, (int) StateColor::Normal))
, text_color(std::make_pair(0xACACAC, (int) StateColor::Disabled),
std::make_pair(*wxBLACK, (int) StateColor::Normal))
, background_color(std::make_pair(0xF0F0F0, (int) StateColor::Disabled),
std::make_pair(*wxWHITE, (int) StateColor::Normal))
{
hover = false;
radius = 0;
SetFont(Label::Body_12);
wxWindow::SetLabel(label);
state_handler.attach({&border_color, &text_color, &background_color});
state_handler.update_binds();
text_ctrl = new wxTextCtrl(this, wxID_ANY, text, {20, 5}, wxDefaultSize,
style | wxBORDER_NONE | wxTE_PROCESS_ENTER, wxTextValidator(wxFILTER_DIGITS));
text_ctrl->SetFont(Label::Body_14);
text_ctrl->Bind(wxEVT_SET_FOCUS, [this](auto &e) {
e.SetId(GetId());
ProcessEventLocally(e);
});
text_ctrl->Bind(wxEVT_ENTER_WINDOW, [this](auto &e) {
e.SetId(GetId());
ProcessEventLocally(e);
});
text_ctrl->Bind(wxEVT_LEAVE_WINDOW, [this](auto &e) {
e.SetId(GetId());
ProcessEventLocally(e);
});
text_ctrl->Bind(wxEVT_KILL_FOCUS, &SpinInput::onTextLostFocus, this);
text_ctrl->Bind(wxEVT_TEXT_ENTER, &SpinInput::onTextEnter, 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::SetTextColor(StateColor const &color)
{
text_color = color;
state_handler.update_binds();
}
void SpinInput::SetBackgroundColor(StateColor const& color)
{
background_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);
}
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)
{
int states = state_handler.states();
wxSize size = GetSize();
dc.SetPen(wxPen(border_color.colorForStates(states)));
dc.SetBrush(wxBrush(background_color.colorForStates(states)));
dc.DrawRoundedRectangle(0, 0, size.x, size.y, radius);
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});
dc.SetBrush(*wxTRANSPARENT_BRUSH);
// start draw
auto text = GetLabel();
if (!text.IsEmpty()) {
pt.x = size.x - labelSize.x - 5;
pt.y = (size.y - labelSize.y) / 2;
dc.SetFont(GetFont());
dc.SetTextForeground(text_color.colorForStates(states));
dc.DrawText(text, pt);
}
}
void SpinInput::messureSize()
{
wxSize size = GetSize();
wxSize textSize = text_ctrl->GetSize();
#ifdef __WXOSX__
textSize.y -= 3; // TODO:
#endif
int h = textSize.y * 24 / 14;
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->SetCanFocus(false);
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;
SetValue(val + delta);
sendSpinEvent();
});
btn->Bind(wxEVT_LEFT_UP, [=](auto &e) {
btn->ReleaseMouse();
timer.Stop();
text_ctrl->SelectAll();
delta = 0;
});
return btn;
}
void SpinInput::mouseEnterWindow(wxMouseEvent& event)
{
if (!hover)
{
hover = true;
Refresh();
}
}
void SpinInput::mouseLeaveWindow(wxMouseEvent& event)
{
if (hover)
{
hover = false;
Refresh();
}
}
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);
}
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();
}
// currently unused events
void SpinInput::mouseMoved(wxMouseEvent& event) {}
void SpinInput::keyPressed(wxKeyEvent& event) {}
void SpinInput::keyReleased(wxKeyEvent &event) {}
void SpinInput::sendSpinEvent()
{
wxCommandEvent event(wxEVT_SPINCTRL, GetId());
event.SetEventObject(this);
GetEventHandler()->ProcessEvent(event);
}

View file

@ -0,0 +1,94 @@
#ifndef slic3r_GUI_SpinInput_hpp_
#define slic3r_GUI_SpinInput_hpp_
#include <wx/textctrl.h>
#include "../wxExtensions.hpp"
#include "StateHandler.hpp"
class Button;
class SpinInput : public wxWindow
{
bool hover;
wxSize labelSize;
double radius;
StateHandler state_handler;
StateColor text_color;
StateColor border_color;
StateColor background_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(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 SetTextColor(StateColor const & color);
void SetBackgroundColor(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 mouseMoved(wxMouseEvent& event);
void mouseWheelMoved(wxMouseEvent& event);
void mouseEnterWindow(wxMouseEvent& event);
void mouseLeaveWindow(wxMouseEvent& event);
void keyPressed(wxKeyEvent& event);
void keyReleased(wxKeyEvent& event);
void onTimer(wxTimerEvent &evnet);
void onTextLostFocus(wxEvent &event);
void onTextEnter(wxCommandEvent &event);
void sendSpinEvent();
DECLARE_EVENT_TABLE()
};
#endif // !slic3r_GUI_SpinInput_hpp_

View file

@ -0,0 +1,80 @@
#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;
return states;
}
wxColour StateColor::defaultColor() {
return colorForStates(0);
}
wxColour StateColor::colorForStates(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 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;
}

View file

@ -0,0 +1,81 @@
#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);
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_;
};
#endif // !slic3r_GUI_StateColor_hpp_

View file

@ -0,0 +1,79 @@
#include "StateHandler.hpp"
wxDEFINE_EVENT(EVT_ENABLE_CHANGED, wxCommandEvent);
StateHandler::StateHandler(wxWindow * owner)
: owner_(owner)
{
if (owner->IsEnabled())
states_ |= Enabled;
if (owner->HasFocus())
states_ |= Focused;
}
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::update_binds()
{
int bind_states = 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) {
owner_->Bind(events[i], &StateHandler::changed, this);
if (events2[i])
owner_->Bind(events2[i], &StateHandler::changed, this);
} else {
owner_->Unbind(events[i], &StateHandler::changed, this);
if (events2[i])
owner_->Unbind(events2[i], &StateHandler::changed, this);
}
}
}
bind_states_ = bind_states;
owner_->Refresh();
}
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 = states2_ | states_;
// some events are from another window (ex: text_ctrl of TextInput), save state in states2_ to avoid conflicts
int & states = event.GetEventObject() == owner_ ? states_ : states2_;
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 != (states2_ | states_))
owner_->Refresh();
}

View file

@ -0,0 +1,49 @@
#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);
public:
void attach(StateColor const & color);
void attach(std::vector<StateColor const *> const & colors);
void update_binds();
int states() const { return states_ | states2_; }
private:
void changed(wxEvent & event);
private:
wxWindow * owner_;
std::vector<StateColor const *> colors_;
int bind_states_ = 0;
int states_ = 0;
int states2_ = 0;
};
#endif // !slic3r_GUI_StateHandler_hpp_

View file

@ -0,0 +1,185 @@
#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)
, border_color(0x303A3C)
, radius(8)
{
}
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)
{
wxWindow::Create(parent, id, pos, size, style);
#ifdef __WXMSW__
SetBackgroundStyle(wxBG_STYLE_PAINT);
#endif
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::SetBackgroundColor(StateColor const &color)
{
background_color = color;
state_handler.update_binds();
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__
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) {
#ifdef __WXOSX__
int d = ceil(border_width / 2.0);
rc.Deflate(d, d);
#endif
dc.SetPen(wxPen(border_color.colorForStates(states), border_width));
} else {
dc.SetPen(wxPen(background_color.colorForStates(states)));
}
dc.SetBrush(wxBrush(background_color.colorForStates(states)));
if (GetWindowStyle() & wxBORDER_NONE)
dc.SetPen(wxPen(background_color.colorForStates(states)));
if (radius == 0) {
dc.DrawRectangle(rc);
}
else {
dc.DrawRoundedRectangle(rc, radius);
}
}
}
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; }
}
}
}

View file

@ -0,0 +1,58 @@
#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 SetBackgroundColor(StateColor 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_

View file

@ -0,0 +1,77 @@
#include "StaticLine.hpp"
#include "Label.hpp"
#include <wx/dcgraph.h>
BEGIN_EVENT_TABLE(StaticLine, wxWindow)
// catch paint events
EVT_PAINT(StaticLine::paintEvent)
END_EVENT_TABLE()
StaticLine::StaticLine(wxWindow* parent, bool vertical, const wxString& label)
: wxWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE)
, vertical(vertical)
{
wxWindow::SetBackgroundColour(parent->GetBackgroundColour());
this->pen = wxPen(wxColour("#C4C4C4"));
SetFont(Label::Body_14);
SetLabel(label);
}
void StaticLine::SetLabel(const wxString& label)
{
wxWindow::SetLabel(label);
int s = 1;
if (!label.IsEmpty()) {
wxClientDC dc(this);
auto size = dc.GetTextExtent(label);
s = vertical ? size.x : size.y;
}
if (vertical)
SetMinSize({s, -1});
else
SetMinSize({-1, s});
Refresh();
}
void StaticLine::SetLineColour(wxColour color)
{
this->pen = wxPen(color);
}
void StaticLine::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 StaticLine::render(wxDC& dc)
{
wxSize size = GetSize();
wxSize size2 {0, 0};
auto label = GetLabel();
if (!label.IsEmpty()) {
size2 = dc.GetTextExtent(label);
dc.DrawText(label, 0, 0);
if (vertical)
size2.y += 5;
else
size2.x += 5;
}
dc.SetPen(pen);
if (vertical) {
size.x /= 2;
dc.DrawLine(size.x, size2.y, size.x, size.y);
} else {
size.y /= 2;
dc.DrawLine(size2.x, size.y, size.x, size.y);
}
}

View file

@ -0,0 +1,28 @@
#ifndef slic3r_GUI_StaticLine_hpp_
#define slic3r_GUI_StaticLine_hpp_
#include "wx/window.h"
class StaticLine : public wxWindow
{
public:
StaticLine(wxWindow* parent, bool vertical = false, const wxString& label = {});
public:
void SetLabel(const wxString& label) override;
void SetLineColour(wxColour color);
private:
wxPen pen;
bool vertical;
private:
void paintEvent(wxPaintEvent& evt);
void render(wxDC& dc);
DECLARE_EVENT_TABLE()
};
#endif // !slic3r_GUI_StaticLine_hpp_

View file

@ -0,0 +1,288 @@
#include "StepCtrl.hpp"
#include "Label.hpp"
wxDEFINE_EVENT( EVT_STEP_CHANGING, wxCommandEvent );
wxDEFINE_EVENT( EVT_STEP_CHANGED, wxCommandEvent );
BEGIN_EVENT_TABLE(StepCtrl, StepCtrlBase)
EVT_LEFT_DOWN(StepCtrl::mouseDown)
EVT_MOTION(StepCtrl::mouseMove)
EVT_LEFT_UP(StepCtrl::mouseUp)
END_EVENT_TABLE()
StepCtrlBase::StepCtrlBase(wxWindow * parent,
wxWindowID id,
const wxPoint & pos,
const wxSize & size,
long style)
: StaticBox(parent, id, pos, size, style)
, font_tip(Label::Body_14)
, clr_bar(0xACACAC)
, clr_step(0xACACAC)
, clr_text(std::make_pair(0x00AE42, (int) StateColor::Checked),
std::make_pair(0x6B6B6B, (int) StateColor::Normal))
, clr_tip(0x828280)
{
SetFont(Label::Body_14);
border_color = StateColor(*wxLIGHT_GREY);
StaticBox::radius = 0;
//wxString reason;
//IsTransparentBackgroundSupported(&reason);
}
StepCtrlBase::~StepCtrlBase()
{
}
int StepCtrlBase::GetSelection() const { return step; }
void StepCtrlBase::SelectItem(int item)
{
if (item == step || item < -1 || item >= steps.size() || !sendStepCtrlEvent(true))
return;
step = item;
sendStepCtrlEvent();
Refresh();
}
void StepCtrlBase::Idle()
{
step = -1;
sendStepCtrlEvent();
Refresh();
}
bool StepCtrlBase::SetTipFont(wxFont const& font)
{
font_tip = font;
return true;
}
int StepCtrlBase::AppendItem(const wxString &item, wxString const & tip)
{
steps.push_back(item);
tips.push_back(tip);
return steps.size() - 1;
}
void StepCtrlBase::DeleteAllItems()
{
steps.clear();
tips.clear();
if (step >= 0) {
step = -1;
sendStepCtrlEvent();
}
}
unsigned int StepCtrlBase::GetCount() const { return steps.size(); }
wxString StepCtrlBase::GetItemText(unsigned int item) const
{
return item < steps.size() ? steps[item] : wxString{};
}
void StepCtrlBase::SetItemText(unsigned int item, wxString const &value)
{
if (item >= steps.size()) return;
steps[item] = value;
}
bool StepCtrlBase::sendStepCtrlEvent(bool changing)
{
wxCommandEvent event(changing ? EVT_STEP_CHANGING : EVT_STEP_CHANGED, GetId());
event.SetEventObject(this);
event.SetInt(step);
GetEventHandler()->ProcessEvent(event);
return true;
}
/* StepCtrl */
StepCtrl::StepCtrl(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style)
: StepCtrlBase(parent, id, pos, size, style)
, bmp_thumb(this, "step_thumb", 36)
{
StaticBox::border_width = 3;
radius = radius * bmp_thumb.GetBmpHeight() / 36;
bar_width = bar_width * bmp_thumb.GetBmpHeight() / 36;
}
void StepCtrl::Rescale()
{
bmp_thumb.msw_rescale();
radius = radius * bmp_thumb.GetBmpHeight() / 36;
bar_width = bar_width * bmp_thumb.GetBmpHeight() / 36;
}
void StepCtrl::mouseDown(wxMouseEvent &event)
{
wxPoint pt;
event.GetPosition(&pt.x, &pt.y);
wxSize size = GetSize();
int itemWidth = size.x / steps.size();
wxRect rcBar = {0, (size.y - 60) / 2, size.x, 60};
int circleX = itemWidth / 2 + itemWidth * step;
wxRect rcThumb = {{circleX, size.y / 2}, bmp_thumb.GetBmpSize()};
rcThumb.x -= rcThumb.width / 2;
rcThumb.y -= rcThumb.height / 2;
if (rcThumb.Contains(pt)) {
pos_thumb = wxPoint{circleX, size.y / 2};
drag_offset = pos_thumb - pt;
} else if (rcBar.Contains(pt)) {
if (pt.x < circleX) {
if (step > 0) SelectItem(step - 1);
} else {
if (step < steps.size() - 1) SelectItem(step + 1);
}
}
}
void StepCtrl::mouseMove(wxMouseEvent &event)
{
if (pos_thumb == wxPoint{0, 0}) return;
wxPoint pt;
event.GetPosition(&pt.x, &pt.y);
pos_thumb.x = pt.x + drag_offset.x;
Refresh();
}
void StepCtrl::mouseUp(wxMouseEvent &event)
{
if (pos_thumb == wxPoint{0, 0}) return;
wxSize size = GetSize();
int itemWidth = size.x / steps.size();
int index = pos_thumb.x / itemWidth;
pos_thumb = {0, 0};
SelectItem(index < steps.size() ? index : steps.size() - 1);
}
void StepCtrl::doRender(wxDC &dc)
{
if (steps.empty()) return;
StaticBox::doRender(dc);
wxSize size = GetSize();
int states = state_handler.states();
int itemWidth = size.x / steps.size();
wxRect rcBar = {itemWidth / 2, (size.y - bar_width) / 2, size.x - itemWidth, bar_width};
dc.SetPen(wxPen(clr_bar.colorForStates(states)));
dc.SetBrush(wxBrush(clr_bar.colorForStates(states)));
dc.DrawRectangle(rcBar);
int circleX = itemWidth / 2;
int circleY = size.y / 2;
dc.SetPen(wxPen(clr_step.colorForStates(states)));
dc.SetBrush(wxBrush(clr_step.colorForStates(states)));
for (int i = 0; i < steps.size(); ++i) {
bool check = pos_thumb == wxPoint{0, 0} ? step == i : (pos_thumb.x >= circleX - itemWidth / 2 && pos_thumb.x < circleX + itemWidth / 2);
dc.DrawEllipse(circleX - radius, circleY - radius, radius * 2, radius * 2);
dc.SetFont(GetFont());
dc.SetTextForeground(clr_text.colorForStates(states | (check ? StateColor::Checked : 0)));
wxSize sz = dc.GetTextExtent(steps[i]);
dc.DrawText(steps[i], circleX - sz.x / 2, circleY + 20);
if (check) {
dc.SetFont(font_tip);
dc.SetTextForeground(clr_tip.colorForStates(states));
wxSize sz = dc.GetTextExtent(tips[i]);
dc.DrawText(tips[i], circleX - sz.x / 2, circleY - 20 - sz.y);
sz = bmp_thumb.GetBmpSize();
dc.DrawBitmap(bmp_thumb.bmp(), circleX - sz.x / 2, circleY - sz.y / 2);
}
circleX += itemWidth;
}
}
/* StepIndicator */
StepIndicator::StepIndicator(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style)
: StepCtrlBase(parent, id, pos, size, style)
, bmp_ok(this, "step_ok", 12)
{
SetFont(Label::Body_12);
font_tip = Label::Body_10;
clr_bar = 0xE1E1E1;
clr_step = StateColor(
std::make_pair(0xACACAC, (int) StateColor::Disabled),
std::make_pair(0x00AE42, 0));
clr_text = StateColor(
std::make_pair(0xACACAC, (int) StateColor::Disabled),
std::make_pair(0x323A3D, (int) StateColor::Checked),
std::make_pair(0x6B6B6B, 0));
clr_tip = *wxWHITE;
StaticBox::border_width = 0;
radius = bmp_ok.GetBmpHeight() / 2;
bar_width = bmp_ok.GetBmpHeight() / 20;
if (bar_width < 2) bar_width = 2;
}
void StepIndicator::Rescale()
{
bmp_ok.msw_rescale();
radius = bmp_ok.GetBmpHeight() / 2;
bar_width = bmp_ok.GetBmpHeight() / 20;
if (bar_width < 2) bar_width = 2;
}
void StepIndicator::SelectNext() { SelectItem(step + 1); }
void StepIndicator::doRender(wxDC &dc)
{
if (steps.empty()) return;
StaticBox::doRender(dc);
wxSize size = GetSize();
int states = state_handler.states();
if (!IsEnabled()) {
states = clr_step.Disabled;
}
int font_height = radius * 2;
if (steps.size() > 0)
font_height = dc.GetTextExtent(steps[0]).y;
int itemWidth = steps.size() == 1 ? size.y : (size.y - font_height) / (steps.size() - 1);
wxRect rcBar = {radius - bar_width / 2, radius, bar_width, size.y - radius * 4};
dc.SetPen(wxPen(clr_bar.colorForStates(states)));
dc.SetBrush(wxBrush(clr_bar.colorForStates(states)));
dc.DrawRectangle(rcBar);
int circleX = radius;
int circleY = radius;
dc.SetPen(wxPen(clr_step.colorForStates(states)));
dc.SetBrush(wxBrush(clr_step.colorForStates(states)));
for (int i = 0; i < steps.size(); ++i) {
bool disabled = step > i;
bool checked = step == i;
dc.DrawEllipse(circleX - radius, circleY - radius, radius * 2, radius * 2);
dc.SetTextForeground(clr_text.colorForStates(states
| (disabled ? StateColor::Disabled : checked ? StateColor::Checked : 0)));
dc.SetFont(checked ? GetFont().Bold() : GetFont());
wxSize textSize = dc.GetTextExtent(steps[i]);
if (steps[i].Find("\n") >= 0) {
dc.DrawText(steps[i], circleX + radius * 3, circleY - textSize.y / 4);
} else {
dc.DrawText(steps[i], circleX + radius * 3, circleY - (textSize.y/2));
}
if (disabled) {
wxSize sz = bmp_ok.GetBmpSize();
dc.DrawBitmap(bmp_ok.bmp(), circleX - radius, circleY - radius);
} else {
dc.SetFont(font_tip);
dc.SetTextForeground(clr_tip.colorForStates(states));
auto tip = tips[i];
if (tip.IsEmpty()) tip.append(1, wchar_t(L'0' + i + 1));
wxSize sz = dc.GetTextExtent(tip);
dc.DrawText(tip, circleX - sz.x / 2, circleY - sz.y / 2 + 1);
}
circleY += itemWidth;
}
}

View file

@ -0,0 +1,101 @@
#ifndef slic3r_GUI_StepCtrlBase_hpp_
#define slic3r_GUI_StepCtrlBase_hpp_
#include "StaticBox.hpp"
wxDECLARE_EVENT( EVT_STEP_CHANGING, wxCommandEvent );
wxDECLARE_EVENT( EVT_STEP_CHANGED, wxCommandEvent );
class StepCtrlBase : public StaticBox
{
protected:
wxFont font_tip;
StateColor clr_bar;
StateColor clr_step;
StateColor clr_text;
StateColor clr_tip;
int radius = 7;
int bar_width = 4;
std::vector<wxString> steps;
std::vector<wxString> tips;
int step = -1;
wxPoint drag_offset;
wxPoint pos_thumb;
public:
StepCtrlBase(wxWindow * parent,
wxWindowID id,
const wxPoint & pos = wxDefaultPosition,
const wxSize & size = wxDefaultSize,
long style = 0);
~StepCtrlBase();
public:
bool SetTipFont(wxFont const & font);
public:
int AppendItem(const wxString &item, wxString const & tip = {});
void DeleteAllItems();
unsigned int GetCount() const;
int GetSelection() const;
void SelectItem(int item);
void Idle();
wxString GetItemText(unsigned int item) const;
void SetItemText(unsigned int item, wxString const &value);
private:
// some useful events
bool sendStepCtrlEvent(bool changing = false);
};
class StepCtrl : public StepCtrlBase
{
ScalableBitmap bmp_thumb;
public:
StepCtrl(wxWindow * parent,
wxWindowID id,
const wxPoint & pos = wxDefaultPosition,
const wxSize & size = wxDefaultSize,
long style = 0);
virtual void Rescale();
private:
void mouseDown(wxMouseEvent &event);
void mouseMove(wxMouseEvent &event);
void mouseUp(wxMouseEvent &event);
void doRender(wxDC &dc) override;
DECLARE_EVENT_TABLE()
};
class StepIndicator : public StepCtrlBase
{
ScalableBitmap bmp_ok;
public:
StepIndicator(wxWindow *parent,
wxWindowID id,
const wxPoint & pos = wxDefaultPosition,
const wxSize & size = wxDefaultSize,
long style = 0);
virtual void Rescale();
void SelectNext();
private:
void doRender(wxDC &dc) override;
};
#endif // !slic3r_GUI_StepCtrlBase_hpp_

View file

@ -0,0 +1,119 @@
#include "SwitchButton.hpp"
#include "Label.hpp"
#include "StaticBox.hpp"
#include "../wxExtensions.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 {
constexpr int BS = 1;
wxSize thumbSize;
wxSize trackSize;
wxClientDC dc(this);
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 += 12;
thumbSize.y += 2;
trackSize.x = thumbSize.x + size.x + 10;
trackSize.y = thumbSize.y + BS * 2;
auto maxWidth = GetMaxWidth();
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(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);
(i == 0 ? m_off : m_on).bmp() = bmp;
}
}
SetSize(m_on.GetBmpSize());
update();
}
void SwitchButton::update()
{
SetBitmap((GetValue() ? m_on : m_off).bmp());
}

View 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_

View file

@ -0,0 +1,278 @@
#include "TabCtrl.hpp"
wxDEFINE_EVENT( wxEVT_TAB_SEL_CHANGING, wxCommandEvent );
wxDEFINE_EVENT( wxEVT_TAB_SEL_CHANGED, wxCommandEvent );
BEGIN_EVENT_TABLE(TabCtrl, StaticBox)
// 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().
*/
#define TAB_BUTTON_SPACE 2
#define TAB_BUTTON_PADDING_X 2
#define TAB_BUTTON_PADDING_Y 2
#define TAB_BUTTON_PADDING TAB_BUTTON_PADDING_X, TAB_BUTTON_PADDING_Y
TabCtrl::TabCtrl(wxWindow * parent,
wxWindowID id,
const wxPoint & pos,
const wxSize & size,
long style)
: StaticBox(parent, id, pos, size, style)
{
radius = 5;
SetBorderColor(0xcecece);
sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->AddSpacer(10);
SetSizer(sizer);
Bind(wxEVT_COMMAND_BUTTON_CLICKED, &TabCtrl::buttonClicked, this);
//wxString reason;
//IsTransparentBackgroundSupported(&reason);
}
TabCtrl::~TabCtrl()
{
delete images;
}
int TabCtrl::GetSelection() const { return sel; }
void TabCtrl::SelectItem(int item)
{
if (item == sel || !sendTabCtrlEvent(true))
return;
if (sel >= 0) {
wxCommandEvent e(wxEVT_CHECKBOX);
auto b = btns[sel];
e.SetEventObject(b);
b->GetEventHandler()->ProcessEvent(e);
}
sel = item;
if (sel >= 0) {
wxCommandEvent e(wxEVT_CHECKBOX);
auto b = btns[sel];
e.SetEventObject(b);
b->GetEventHandler()->ProcessEvent(e);
}
sendTabCtrlEvent();
relayout();
Refresh();
}
void TabCtrl::Unselect()
{
SelectItem(-1);
}
void TabCtrl::Rescale()
{
for (auto & b : btns)
b->Rescale();
}
bool TabCtrl::SetFont(wxFont const& font)
{
StaticBox::SetFont(font);
bold = font.Bold();
for (size_t i = 0; i < btns.size(); ++i)
btns[i]->SetFont(i == sel ? bold : font);
return true;
}
int TabCtrl::AppendItem(const wxString &item,
int image, int selImage,
void * clientData)
{
Button * btn = new Button();
btn->Create(this, item, "", wxBORDER_NONE);
btn->SetFont(GetFont());
btn->SetTextColor(StateColor(
std::make_pair(0x6B6B6B, (int) StateColor::NotChecked),
std::make_pair(*wxLIGHT_GREY, (int) StateColor::Normal)));
btn->SetBackgroundColor(GetBackgroundColour());
btn->SetCornerRadius(0);
btn->SetPaddingSize({TAB_BUTTON_PADDING});
btns.push_back(btn);
if (btns.size() > 1)
sizer->GetItem(sizer->GetItemCount() - 1)->SetMinSize({0, 0});
sizer->Add(btn, 0, wxALIGN_CENTER_VERTICAL | wxALL, TAB_BUTTON_SPACE * 2);
sizer->AddStretchSpacer(1);
relayout();
return btns.size() - 1;
}
bool TabCtrl::DeleteItem(int item)
{
return false;
}
void TabCtrl::DeleteAllItems()
{
sizer->Clear(true);
sizer->AddSpacer(10);
btns.clear();
if (sel >= 0) {
sel = -1;
sendTabCtrlEvent();
}
}
unsigned int TabCtrl::GetCount() const { return btns.size(); }
wxString TabCtrl::GetItemText(unsigned int item) const
{
return item < btns.size() ? btns[item]->GetLabel() : wxString{};
}
void TabCtrl::SetItemText(unsigned int item, wxString const &value)
{
if (item >= btns.size()) return;
btns[item]->SetLabel(value);
}
bool TabCtrl::GetItemBold(unsigned int item) const
{
if (item >= btns.size()) return false;
return btns[item]->GetFont() == bold;
}
void TabCtrl::SetItemBold(unsigned int item, bool bold)
{
if (item >= btns.size()) return;
btns[item]->SetFont(bold ? this->bold : GetFont());
btns[item]->Rescale();
}
void* TabCtrl::GetItemData(unsigned int item) const
{
if (item >= btns.size()) return nullptr;
return btns[item]->GetClientData();
}
void TabCtrl::SetItemData(unsigned int item, void* clientData)
{
if (item >= btns.size()) return;
btns[item]->SetClientData(clientData);
}
void TabCtrl::AssignImageList(wxImageList* imageList)
{
if (images == imageList) return;
delete images;
images = imageList;
}
void TabCtrl::SetItemTextColour(unsigned int item, const StateColor &col)
{
if (item >= btns.size()) return;
btns[item]->SetTextColor(col);
}
int TabCtrl::GetFirstVisibleItem() const
{
return btns.size() == 0 ? -1 : 0;
}
int TabCtrl::GetNextVisible(int item) const
{
return ++item < btns.size() ? item : -1;
}
bool TabCtrl::IsVisible(unsigned int item) const
{
return true;
}
void TabCtrl::DoSetSize(int x, int y, int width, int height, int sizeFlags)
{
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
if (sizeFlags & wxSIZE_USE_EXISTING) return;
relayout();
}
void TabCtrl::relayout()
{
int offset = 10;
int item = sel + 1;
int first = 0;
for (int i = 0; i < item; ++i)
offset += btns[i]->GetMinSize().x + TAB_BUTTON_SPACE * 2;
if (item < btns.size())
offset += btns[item]->GetMinSize().x + TAB_BUTTON_SPACE * 2;
int width = GetSize().x;
auto sizer = GetSizer();
for (int i = 0; i < btns.size(); ++i) {
auto size = btns[i]->GetMinSize().x + TAB_BUTTON_SPACE * 2;
if (i < sel && offset > width) {
sizer->Show(i * 2 + 1, false);
sizer->Show(i * 2 + 2, false);
offset -= size;
first = i + 1;
} else if (i <= item) {
sizer->Show(i * 2 + 1, true);
sizer->Show(i * 2 + 2, true);
} else if (offset <= width) {
sizer->Show(i * 2 + 1, true);
sizer->Show(i * 2 + 2, true);
offset += size;
item = i;
} else {
sizer->Show(i * 2 + 1, false);
sizer->Show(i * 2 + 2, false);
}
sizer->GetItem(i * 2 + 2)->SetMinSize({0, 0});
}
if (item >= btns.size())
-- item;
// Keep spacing 2 ~ 10 TAB_BUTTON_SPACE
int b = GetSize().x - offset - 10 - (item + 1 - first) * TAB_BUTTON_SPACE * 8;
sizer->GetItem(item * 2 + 2)->SetMinSize({b > 0 ? b : 0, 0});
sizer->Layout();
}
void TabCtrl::buttonClicked(wxCommandEvent &event)
{
auto btn = event.GetEventObject();
auto iter = std::find(btns.begin(), btns.end(), btn);
SelectItem(iter == btns.end() ? -1 : iter - btns.begin());
}
void TabCtrl::doRender(wxDC& dc)
{
wxSize size = GetSize();
int states = state_handler.states();
dc.SetPen(wxPen(border_color.colorForStates(states), border_width));
dc.SetBrush(*wxTRANSPARENT_BRUSH);
if (sel < 0) { return; }
auto x1 = btns[sel]->GetPosition().x;
auto x2 = x1 + btns[sel]->GetSize().x;
x1 -= TAB_BUTTON_SPACE; x2 += TAB_BUTTON_SPACE;
const int BS = border_width / 2;
const int BS2 = (1 + border_width) / 2;
dc.DrawLine(0, size.y - BS2, x1 - radius + BS2, size.y - BS2);
dc.DrawArc(x1 - radius, size.y, x1, size.y - radius, x1 - radius, size.y - radius);
dc.DrawLine(x1, size.y - radius, x1, radius);
dc.DrawArc(x1 + radius, 0, x1, radius, x1 + radius, radius);
dc.DrawLine(x1 + radius, BS, x2 - radius, BS);
dc.DrawArc(x2, radius, x2 - radius, 0, x2 - radius, radius);
dc.DrawLine(x2, radius, x2, size.y - radius);
dc.DrawArc(x2, size.y - radius, x2 + radius, size.y, x2 + radius, size.y - radius);
dc.DrawLine(x2 + radius - BS2, size.y - BS2, size.x, size.y - BS2);
}
bool TabCtrl::sendTabCtrlEvent(bool changing)
{
wxCommandEvent event(changing ? wxEVT_TAB_SEL_CHANGING : wxEVT_TAB_SEL_CHANGED, GetId());
event.SetEventObject(this);
event.SetInt(sel);
GetEventHandler()->ProcessEvent(event);
return true;
}

View file

@ -0,0 +1,80 @@
#ifndef slic3r_GUI_TabCtrl_hpp_
#define slic3r_GUI_TabCtrl_hpp_
#include "Button.hpp"
wxDECLARE_EVENT( wxEVT_TAB_SEL_CHANGING, wxCommandEvent );
wxDECLARE_EVENT( wxEVT_TAB_SEL_CHANGED, wxCommandEvent );
class TabCtrl : public StaticBox
{
std::vector<Button*> btns;
wxImageList* images = nullptr;
wxBoxSizer * sizer = nullptr;
int sel = -1;
wxFont bold;
public:
TabCtrl(wxWindow * parent,
wxWindowID id,
const wxPoint & pos = wxDefaultPosition,
const wxSize & size = wxDefaultSize,
long style = 0);
~TabCtrl();
public:
virtual bool SetFont(wxFont const & font) override;
public:
int AppendItem(const wxString &item, int image = -1, int selImage = -1, void *clientData = nullptr);
bool DeleteItem(int item);
void DeleteAllItems();
unsigned int GetCount() const;
int GetSelection() const;
void SelectItem(int item);
void Unselect();
virtual void Rescale();
wxString GetItemText(unsigned int item) const;
void SetItemText(unsigned int item, wxString const &value);
bool GetItemBold(unsigned int item) const;
void SetItemBold(unsigned int item, bool bold);
void* GetItemData(unsigned int item) const;
void SetItemData(unsigned int item, void *clientData);
void AssignImageList(wxImageList *imageList);
void SetItemTextColour(unsigned int item, const StateColor& col);
/* fakes */
int GetFirstVisibleItem() const;
int GetNextVisible(int item) const;
bool IsVisible(unsigned int item) const;
private:
virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO);
void relayout();
void buttonClicked(wxCommandEvent & event);
void doRender(wxDC & dc) override;
// some useful events
bool sendTabCtrlEvent(bool changing = false);
DECLARE_EVENT_TABLE()
};
#endif // !slic3r_GUI_TabCtrl_hpp_

View file

@ -0,0 +1,598 @@
#include "TempInput.hpp"
#include "Label.hpp"
#include "../I18N.hpp"
#include <wx/dcgraph.h>
#include "../GUI.hpp"
#include "../GUI_App.hpp"
wxDEFINE_EVENT(wxCUSTOMEVT_SET_TEMP_FINISH, wxCommandEvent);
BEGIN_EVENT_TABLE(TempInput, wxPanel)
EVT_MOTION(TempInput::mouseMoved)
EVT_ENTER_WINDOW(TempInput::mouseEnterWindow)
EVT_LEAVE_WINDOW(TempInput::mouseLeaveWindow)
EVT_KEY_DOWN(TempInput::keyPressed)
EVT_KEY_UP(TempInput::keyReleased)
EVT_MOUSEWHEEL(TempInput::mouseWheelMoved)
EVT_PAINT(TempInput::paintEvent)
END_EVENT_TABLE()
TempInput::TempInput()
: state_handler(this)
, border_color(std::make_pair(*wxWHITE, (int) StateColor::Disabled),
std::make_pair(0x00AE42, (int) StateColor::Focused),
std::make_pair(0x00AE42, (int) StateColor::Hovered),
std::make_pair(*wxWHITE, (int) StateColor::Normal))
, label_color(std::make_pair(wxColour(0xAC,0xAC,0xAC), (int) StateColor::Disabled),std::make_pair(0x323A3D, (int) StateColor::Normal))
, text_color(std::make_pair(wxColour(0xAC,0xAC,0xAC), (int) StateColor::Disabled), std::make_pair(0x6B6B6B, (int) StateColor::Normal))
, background_color(std::make_pair(*wxWHITE, (int) StateColor::Disabled),
std::make_pair(*wxWHITE, (int) StateColor::Normal))
{
hover = false;
radius = 0;
SetFont(Label::Body_12);
}
TempInput::TempInput(wxWindow *parent, int type, wxString text, wxString label, wxString normal_icon, wxString actice_icon, const wxPoint &pos, const wxSize &size, long style)
: TempInput()
{
actice = false;
temp_type = type;
Create(parent, text, label, normal_icon, actice_icon, pos, size, style);
}
void TempInput::Create(wxWindow *parent, wxString text, wxString label, wxString normal_icon, wxString actice_icon, const wxPoint &pos, const wxSize &size, long style)
{
wxWindow::Create(parent, wxID_ANY, pos, size, style);
wxWindow::SetLabel(label);
style &= ~wxALIGN_CENTER_HORIZONTAL;
state_handler.attach({&border_color, &text_color, &background_color});
state_handler.update_binds();
text_ctrl = new wxTextCtrl(this, wxID_ANY, text, {5, 5}, wxDefaultSize, wxTE_PROCESS_ENTER | wxBORDER_NONE, wxTextValidator(wxFILTER_NUMERIC), wxTextCtrlNameStr);
text_ctrl->SetMaxLength(3);
text_ctrl->Bind(wxEVT_SET_FOCUS, [this](auto &e) {
e.SetId(GetId());
ProcessEventLocally(e);
//enter input mode
auto temp = text_ctrl->GetValue();
if (temp.length() > 0 && temp[0] == (0x5f)) {
text_ctrl->SetValue(wxEmptyString);
}
if (wdialog != nullptr) { wdialog->Dismiss(); }
});
text_ctrl->Bind(wxEVT_ENTER_WINDOW, [this](auto &e) {
if (m_read_only) {SetCursor(wxCURSOR_ARROW);}
e.SetId(GetId());
ProcessEventLocally(e);
});
text_ctrl->Bind(wxEVT_LEAVE_WINDOW, [this](auto &e) {
e.SetId(GetId());
ProcessEventLocally(e);
});
text_ctrl->Bind(wxEVT_KILL_FOCUS, [this](auto &e) {
OnEdit();
e.SetId(GetId());
ProcessEventLocally(e);
auto temp = text_ctrl->GetValue();
if (temp.ToStdString().empty()) {
text_ctrl->SetValue(wxString("_"));
return;
}
if (!AllisNum(temp.ToStdString())) return;
if (max_temp <= 0) return;
auto tempint = std::stoi(temp.ToStdString());
if ((tempint > max_temp || tempint < min_temp) && !warning_mode) {
if (tempint > max_temp)
Warning(true, WARNING_TOO_HIGH);
else if (tempint < min_temp)
Warning(true, WARNING_TOO_LOW);
return;
} else {
Warning(false);
}
SetFinish();
});
text_ctrl->Bind(wxEVT_TEXT_ENTER, [this](wxCommandEvent &e) {
OnEdit();
e.SetId(GetId());
ProcessEventLocally(e);
auto temp = text_ctrl->GetValue();
if (temp.ToStdString().empty()) return;
if (!AllisNum(temp.ToStdString())) return;
if (max_temp <= 0) return;
auto tempint = std::stoi(temp.ToStdString());
if (tempint > max_temp) {
Warning(true, WARNING_TOO_HIGH);
return;
} else {
Warning(false, WARNING_TOO_LOW);
}
SetFinish();
Slic3r::GUI::wxGetApp().GetMainTopWindow()->SetFocus();
});
text_ctrl->Bind(wxEVT_RIGHT_DOWN, [this](auto &e) {}); // disable context menu
text_ctrl->Bind(wxEVT_LEFT_DOWN, [this](auto &e) {
if (m_read_only) {
return;
} else {
e.Skip();
}
});
text_ctrl->SetFont(Label::Body_13);
text_ctrl->SetForegroundColour(text_color.colorForStates(StateColor::Normal));
if (!normal_icon.IsEmpty()) { this->normal_icon = ScalableBitmap(this, normal_icon.ToStdString(), 16); }
if (!actice_icon.IsEmpty()) { this->actice_icon = ScalableBitmap(this, actice_icon.ToStdString(), 16); }
this->degree_icon = ScalableBitmap(this, "degree", 16);
messureSize();
}
bool TempInput::AllisNum(std::string str)
{
for (int i = 0; i < str.size(); i++) {
int tmp = (int) str[i];
if (tmp >= 48 && tmp <= 57) {
continue;
} else {
return false;
}
}
return true;
}
void TempInput::SetFinish()
{
wxCommandEvent event(wxCUSTOMEVT_SET_TEMP_FINISH);
event.SetInt(temp_type);
wxPostEvent(this->GetParent(), event);
}
wxString TempInput::erasePending(wxString &str)
{
wxString tmp = str;
int index = tmp.size() - 1;
while (index != -1) {
if (tmp[index] < '0' || tmp[index] > '9') {
tmp.erase(index, 1);
index--;
} else {
break;
}
}
return tmp;
}
void TempInput::SetTagTemp(int temp)
{
text_ctrl->SetValue(wxString::Format("%d", temp));
messureSize();
Refresh();
}
void TempInput::SetTagTemp(wxString temp)
{
text_ctrl->SetValue(temp);
messureSize();
Refresh();
}
void TempInput::SetCurrTemp(int temp)
{
SetLabel(wxString::Format("%d", temp));
}
void TempInput::SetCurrTemp(wxString temp)
{
SetLabel(temp);
}
void TempInput::Warning(bool warn, WarningType type)
{
warning_mode = warn;
//Refresh();
if (warning_mode) {
if (wdialog == nullptr) {
wdialog = new wxPopupTransientWindow(this);
wdialog->SetBackgroundColour(wxColour(0xFFFFFF));
wdialog->SetSizeHints(wxDefaultSize, wxDefaultSize);
wxBoxSizer *sizer_body = new wxBoxSizer(wxVERTICAL);
auto body = new wxPanel(wdialog, wxID_ANY, wxDefaultPosition, {this->GetSize().x - 4, -1}, wxTAB_TRAVERSAL);
body->SetBackgroundColour(wxColour(0xFFFFFF));
wxBoxSizer *sizer_text;
sizer_text = new wxBoxSizer(wxHORIZONTAL);
warning_text = new wxStaticText(body, wxID_ANY,
wxEmptyString,
wxDefaultPosition, wxDefaultSize,
wxALIGN_CENTER_HORIZONTAL);
warning_text->SetFont(::Label::Body_12);
warning_text->SetForegroundColour(wxColour(255, 111, 0));
warning_text->Wrap(-1);
sizer_text->Add(warning_text, 1, wxEXPAND | wxTOP | wxBOTTOM, 2);
body->SetSizer(sizer_text);
body->Layout();
sizer_body->Add(body, 0, wxEXPAND, 0);
wdialog->SetSizer(sizer_body);
wdialog->Layout();
sizer_body->Fit(wdialog);
}
wxPoint pos = this->ClientToScreen(wxPoint(2, 0));
pos.y += this->GetRect().height - (this->GetSize().y - this->text_ctrl->GetSize().y) / 2 - 2;
wdialog->SetPosition(pos);
wxString warning_string;
if (type == WarningType::WARNING_TOO_HIGH)
warning_string = _L("The maximum temperature cannot exceed" + wxString::Format("%d", max_temp));
else if (type == WarningType::WARNING_TOO_LOW)
warning_string = _L("The minmum temperature should not be less than " + wxString::Format("%d", max_temp));
warning_text->SetLabel(warning_string);
wdialog->Popup();
} else {
if (wdialog)
wdialog->Dismiss();
}
}
void TempInput::SetIconActive()
{
actice = true;
Refresh();
}
void TempInput::SetIconNormal()
{
actice = false;
Refresh();
}
void TempInput::SetMaxTemp(int temp) { max_temp = temp; }
void TempInput::SetMinTemp(int temp) { min_temp = temp; }
void TempInput::SetCornerRadius(double radius)
{
this->radius = radius;
Refresh();
}
void TempInput::SetLabel(const wxString &label)
{
wxWindow::SetLabel(label);
messureSize();
Refresh();
}
void TempInput::SetBorderColor(StateColor const &color)
{
border_color = color;
state_handler.update_binds();
}
void TempInput::SetTextColor(StateColor const &color)
{
text_color = color;
state_handler.update_binds();
}
void TempInput::SetLabelColor(StateColor const &color)
{
label_color = color;
state_handler.update_binds();
}
void TempInput::SetBackgroundColor(StateColor const &color)
{
background_color = color;
state_handler.update_binds();
}
void TempInput::Rescale()
{
if (this->normal_icon.bmp().IsOk()) this->normal_icon.msw_rescale();
if (this->degree_icon.bmp().IsOk()) this->degree_icon.msw_rescale();
messureSize();
}
bool TempInput::Enable(bool enable)
{
bool result = wxWindow::Enable(enable);
if (result) {
wxCommandEvent e(EVT_ENABLE_CHANGED);
e.SetEventObject(this);
GetEventHandler()->ProcessEvent(e);
}
return result;
}
void TempInput::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);
messureMiniSize();
}
void TempInput::DoSetSize(int x, int y, int width, int height, int sizeFlags)
{
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
if (sizeFlags & wxSIZE_USE_EXISTING) return;
auto left = padding_left;
wxClientDC dc(this);
if (normal_icon.bmp().IsOk()) {
wxSize szIcon = normal_icon.GetBmpSize();
left += szIcon.x;
}
// interval
left += 9;
// label
dc.SetFont(::Label::Head_14);
labelSize = dc.GetMultiLineTextExtent(wxWindow::GetLabel());
left += labelSize.x;
// interval
left += 10;
// separator
dc.SetFont(::Label::Body_12);
auto sepSize = dc.GetMultiLineTextExtent(wxString("/"));
left += sepSize.x;
// text text
auto textSize = text_ctrl->GetTextExtent(wxString("0000"));
text_ctrl->SetSize(textSize);
text_ctrl->SetPosition({left, (GetSize().y - text_ctrl->GetSize().y) / 2});
}
void TempInput::DoSetToolTipText(wxString const &tip)
{
wxWindow::DoSetToolTipText(tip);
text_ctrl->SetToolTip(tip);
}
void TempInput::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 TempInput::render(wxDC &dc)
{
int states = state_handler.states();
wxSize size = GetSize();
bool align_right = GetWindowStyle() & wxRIGHT;
if (warning_mode) {
dc.SetPen(wxPen(wxColour(255, 111, 0)));
} else {
dc.SetPen(wxPen(border_color.colorForStates(states)));
}
dc.SetBrush(wxBrush(background_color.colorForStates(states)));
dc.DrawRoundedRectangle(0, 0, size.x, size.y, radius);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
// start draw
wxPoint pt = {padding_left, 0};
if (actice_icon.bmp().IsOk() && actice) {
wxSize szIcon = actice_icon.GetBmpSize();
pt.y = (size.y - szIcon.y) / 2;
dc.DrawBitmap(actice_icon.bmp(), pt);
pt.x += szIcon.x + 9;
} else {
actice = false;
}
if (normal_icon.bmp().IsOk() && !actice) {
wxSize szIcon = normal_icon.GetBmpSize();
pt.y = (size.y - szIcon.y) / 2;
dc.DrawBitmap(normal_icon.bmp(), pt);
pt.x += szIcon.x + 9;
}
// label
auto text = wxWindow::GetLabel();
dc.SetFont(::Label::Head_14);
labelSize = dc.GetMultiLineTextExtent(wxWindow::GetLabel());
dc.SetTextForeground(label_color.colorForStates((int) StateColor::Normal));
if (!IsEnabled())
dc.SetTextBackground(background_color.colorForStates((int) StateColor::Disabled));
else
dc.SetTextBackground(background_color.colorForStates((int) states));
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.y = (size.y - labelSize.y) / 2;
}
dc.DrawText(text, pt);
}
// separator
dc.SetFont(::Label::Body_12);
auto sepSize = dc.GetMultiLineTextExtent(wxString("/"));
dc.SetTextForeground(text_color.colorForStates(states));
dc.SetTextBackground(background_color.colorForStates(states));
pt.x += labelSize.x + 10;
pt.y = (size.y - sepSize.y) / 2;
dc.DrawText(wxString("/"), pt);
// flag
if (degree_icon.bmp().IsOk()) {
auto pos = text_ctrl->GetPosition();
wxSize szIcon = degree_icon.GetBmpSize();
pt.y = (size.y - szIcon.y) / 2;
pt.x = pos.x + text_ctrl->GetSize().x;
dc.DrawBitmap(degree_icon.bmp(), pt);
}
}
void TempInput::messureMiniSize()
{
wxSize size = GetMinSize();
auto width = 0;
auto height = 0;
wxClientDC dc(this);
if (normal_icon.bmp().IsOk()) {
wxSize szIcon = normal_icon.GetBmpSize();
width += szIcon.x;
height = szIcon.y;
}
// interval
width += 9;
// label
dc.SetFont(::Label::Head_14);
labelSize = dc.GetMultiLineTextExtent(wxWindow::GetLabel());
width += labelSize.x;
height = labelSize.y > height ? labelSize.y : height;
// interval
width += 10;
// separator
dc.SetFont(::Label::Body_12);
auto sepSize = dc.GetMultiLineTextExtent(wxString("/"));
width += sepSize.x;
height = sepSize.y > height ? sepSize.y : height;
// text text
auto textSize = text_ctrl->GetTextExtent(wxString("0000"));
width += textSize.x;
height = textSize.y > height ? textSize.y : height;
// flag flag
auto flagSize = degree_icon.GetBmpSize();
width += flagSize.x;
height = flagSize.y > height ? flagSize.y : height;
if (size.x < width) {
size.x = width;
} else {
padding_left = (size.x - width) / 2;
}
if (size.y < height) size.y = height;
SetSize(size);
}
void TempInput::messureSize()
{
wxSize size = GetSize();
auto width = 0;
auto height = 0;
wxClientDC dc(this);
if (normal_icon.bmp().IsOk()) {
wxSize szIcon = normal_icon.GetBmpSize();
width += szIcon.x;
height = szIcon.y;
}
// interval
width += 9;
// label
dc.SetFont(::Label::Head_14);
labelSize = dc.GetMultiLineTextExtent(wxWindow::GetLabel());
width += labelSize.x;
height = labelSize.y > height ? labelSize.y : height;
// interval
width += 10;
// separator
dc.SetFont(::Label::Body_12);
auto sepSize = dc.GetMultiLineTextExtent(wxString("/"));
width += sepSize.x;
height = sepSize.y > height ? sepSize.y : height;
// text text
auto textSize = text_ctrl->GetTextExtent(wxString("0000"));
width += textSize.x;
height = textSize.y > height ? textSize.y : height;
// flag flag
auto flagSize = degree_icon.GetBmpSize();
width += flagSize.x;
height = flagSize.y > height ? flagSize.y : height;
if (size.x < width) {
size.x = width;
} else {
padding_left = (size.x - width) / 2;
}
if (size.y < height) size.y = height;
wxSize minSize = size;
minSize.x = GetMinWidth();
SetMinSize(minSize);
SetSize(size);
}
void TempInput::mouseEnterWindow(wxMouseEvent &event)
{
if (!hover) {
hover = true;
Refresh();
}
}
void TempInput::mouseLeaveWindow(wxMouseEvent &event)
{
if (hover) {
hover = false;
Refresh();
}
}
// currently unused events
void TempInput::mouseMoved(wxMouseEvent &event) {}
void TempInput::mouseWheelMoved(wxMouseEvent &event) {}
void TempInput::keyPressed(wxKeyEvent &event) {}
void TempInput::keyReleased(wxKeyEvent &event) {}

View file

@ -0,0 +1,144 @@
#ifndef slic3r_GUI_TempInput_hpp_
#define slic3r_GUI_TempInput_hpp_
#include <wx/textctrl.h>
#include "../wxExtensions.hpp"
#include "StateHandler.hpp"
wxDECLARE_EVENT(wxCUSTOMEVT_SET_TEMP_FINISH, wxCommandEvent);
class TempInput : public wxWindow
{
bool hover;
double radius;
bool m_read_only{false};
wxSize labelSize;
ScalableBitmap normal_icon;
ScalableBitmap actice_icon;
ScalableBitmap degree_icon;
StateHandler state_handler;
StateColor label_color;
StateColor text_color;
StateColor border_color;
StateColor background_color;
wxTextCtrl * text_ctrl;
wxStaticText *warning_text;
int max_temp = 0;
int min_temp = 0;
bool warning_mode = false;
int padding_left = 0;
static const int TempInputWidth = 200;
static const int TempInputHeight = 50;
public:
enum WarningType {
WARNING_TOO_HIGH,
WARNING_TOO_LOW,
WARNING_UNKNOWN,
};
TempInput();
TempInput(wxWindow * parent,
int type,
wxString text,
wxString label = "",
wxString normal_icon = "",
wxString actice_icon = "",
const wxPoint &pos = wxDefaultPosition,
const wxSize & size = wxDefaultSize,
long style = 0);
public:
void Create(wxWindow * parent,
wxString text,
wxString label = "",
wxString normal_icon = "",
wxString actice_icon = "",
const wxPoint &pos = wxDefaultPosition,
const wxSize & size = wxDefaultSize,
long style = 0);
wxPopupTransientWindow *wdialog{nullptr};
int temp_type;
bool actice = false;
wxString erasePending(wxString &str);
void SetTagTemp(int temp);
void SetTagTemp(wxString temp);
void SetCurrTemp(int temp);
void SetCurrTemp(wxString temp);
bool AllisNum(std::string str);
void SetFinish();
void Warning(bool warn, WarningType type = WARNING_UNKNOWN);
void SetIconActive();
void SetIconNormal();
void SetReadOnly(bool ro) { m_read_only = ro; }
void SetMaxTemp(int temp);
void SetMinTemp(int temp);
int GetType() { return temp_type; }
wxString GetTagTemp() { return text_ctrl->GetValue(); }
wxString GetCurrTemp() { return GetLabel(); }
void SetCornerRadius(double radius);
void SetLabel(const wxString &label);
void SetBorderColor(StateColor const &color);
void SetTextColor(StateColor const &color);
void SetLabelColor(StateColor const &color);
void SetBackgroundColor(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 messureMiniSize();
void messureSize();
// some useful events
void mouseMoved(wxMouseEvent &event);
void mouseWheelMoved(wxMouseEvent &event);
void mouseEnterWindow(wxMouseEvent &event);
void mouseLeaveWindow(wxMouseEvent &event);
void keyPressed(wxKeyEvent &event);
void keyReleased(wxKeyEvent &event);
DECLARE_EVENT_TABLE()
};
#endif // !slic3r_GUI_TempInput_hpp_

View file

@ -0,0 +1,283 @@
#include "TextInput.hpp"
#include "Label.hpp"
#include <wx/dcgraph.h>
BEGIN_EVENT_TABLE(TextInput, wxPanel)
EVT_MOTION(TextInput::mouseMoved)
EVT_ENTER_WINDOW(TextInput::mouseEnterWindow)
EVT_LEAVE_WINDOW(TextInput::mouseLeaveWindow)
EVT_KEY_DOWN(TextInput::keyPressed)
EVT_KEY_UP(TextInput::keyReleased)
EVT_MOUSEWHEEL(TextInput::mouseWheelMoved)
// catch paint events
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()
: state_handler(this)
, border_color(std::make_pair(0xDBDBDB, (int) StateColor::Disabled),
std::make_pair(0x00AE42, (int) StateColor::Focused),
std::make_pair(0x00AE42, (int) StateColor::Hovered),
std::make_pair(0xDBDBDB, (int) StateColor::Normal))
, text_color(std::make_pair(0xACACAC, (int) StateColor::Disabled),
std::make_pair(0x363636, (int) StateColor::Normal))
, background_color(std::make_pair(0xF0F0F0, (int) StateColor::Disabled),
std::make_pair(*wxWHITE, (int) StateColor::Normal))
{
hover = false;
radius = 0;
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;
wxWindow::Create(parent, wxID_ANY, pos, size, style);
wxWindow::SetLabel(label);
style &= ~wxRIGHT;
state_handler.attach({&border_color, &text_color, &background_color});
state_handler.update_binds();
text_ctrl = new wxTextCtrl(this, wxID_ANY, text, {5, 5}, wxDefaultSize,
style | wxBORDER_NONE);
text_ctrl->Bind(wxEVT_SET_FOCUS, [this](auto &e) {
e.SetId(GetId());
ProcessEventLocally(e);
});
text_ctrl->Bind(wxEVT_ENTER_WINDOW, [this](auto &e) {
e.SetId(GetId());
ProcessEventLocally(e);
});
text_ctrl->Bind(wxEVT_LEAVE_WINDOW, [this](auto &e) {
e.SetId(GetId());
ProcessEventLocally(e);
});
text_ctrl->Bind(wxEVT_KILL_FOCUS, [this](auto &e) {
OnEdit();
e.SetId(GetId());
ProcessEventLocally(e);
});
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
text_ctrl->SetFont(Label::Body_14);
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::SetBorderColor(StateColor const& color)
{
border_color = color;
state_handler.update_binds();
}
void TextInput::SetTextColor(StateColor const& color)
{
text_color= color;
state_handler.update_binds();
}
void TextInput::SetBackgroundColor(StateColor const& color)
{
background_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);
}
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.bmp().GetSize();
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)
{
int states = state_handler.states();
wxSize size = GetSize();
bool align_right = GetWindowStyle() & wxRIGHT;
dc.SetPen(wxPen(border_color.colorForStates(states)));
dc.SetBrush(wxBrush(background_color.colorForStates(states)));
dc.DrawRoundedRectangle(0, 0, size.x, size.y, radius);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
// 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 + 5;
}
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(text_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();
#ifdef __WXOSX__
textSize.y -= 3; // TODO:
#endif
int h = textSize.y * 24 / 14;
if (size.y < h) {
size.y = h;
}
wxSize minSize = size;
minSize.x = GetMinWidth();
SetMinSize(minSize);
SetSize(size);
}
void TextInput::mouseEnterWindow(wxMouseEvent& event)
{
if (!hover)
{
hover = true;
Refresh();
}
}
void TextInput::mouseLeaveWindow(wxMouseEvent& event)
{
if (hover)
{
hover = false;
Refresh();
}
}
// currently unused events
void TextInput::mouseMoved(wxMouseEvent& event) {}
void TextInput::mouseWheelMoved(wxMouseEvent& event) {}
void TextInput::keyPressed(wxKeyEvent& event) {}
void TextInput::keyReleased(wxKeyEvent& event) {}

View file

@ -0,0 +1,92 @@
#ifndef slic3r_GUI_TextInput_hpp_
#define slic3r_GUI_TextInput_hpp_
#include <wx/textctrl.h>
#include "../wxExtensions.hpp"
#include "StateHandler.hpp"
class TextInput : public wxWindow
{
bool hover;
wxSize labelSize;
ScalableBitmap icon;
double radius;
StateHandler state_handler;
StateColor text_color;
StateColor border_color;
StateColor background_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 SetBorderColor(StateColor const & color);
void SetTextColor(StateColor const &color);
void SetBackgroundColor(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();
// some useful events
void mouseMoved(wxMouseEvent& event);
void mouseWheelMoved(wxMouseEvent& event);
void mouseEnterWindow(wxMouseEvent& event);
void mouseLeaveWindow(wxMouseEvent& event);
void keyPressed(wxKeyEvent& event);
void keyReleased(wxKeyEvent& event);
DECLARE_EVENT_TABLE()
};
#endif // !slic3r_GUI_TextInput_hpp_

View file

@ -0,0 +1,121 @@
#include "WebView.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include <wx/webviewarchivehandler.h>
#include <wx/webviewfshandler.h>
#include <wx/msw/webview_edge.h>
#include <wx/uri.h>
#ifdef __WIN32__
#include "../WebView2.h"
#include "wx/private/jsscriptwrapper.h"
#endif
class FakeWebView : public wxWebView
{
virtual bool Create(wxWindow* parent, wxWindowID id, const wxString& url, const wxPoint& pos, const wxSize& size, long style, const wxString& name) override { return false; }
virtual wxString GetCurrentTitle() const override { return wxString(); }
virtual wxString GetCurrentURL() const override { return wxString(); }
virtual bool IsBusy() const override { return false; }
virtual bool IsEditable() const override { return false; }
virtual void LoadURL(const wxString& url) override { }
virtual void Print() override { }
virtual void RegisterHandler(wxSharedPtr<wxWebViewHandler> handler) override { }
virtual void Reload(wxWebViewReloadFlags flags = wxWEBVIEW_RELOAD_DEFAULT) override { }
virtual bool RunScript(const wxString& javascript, wxString* output = NULL) const override { return false; }
virtual void SetEditable(bool enable = true) override { }
virtual void Stop() override { }
virtual bool CanGoBack() const override { return false; }
virtual bool CanGoForward() const override { return false; }
virtual void GoBack() override { }
virtual void GoForward() override { }
virtual void ClearHistory() override { }
virtual void EnableHistory(bool enable = true) override { }
virtual wxVector<wxSharedPtr<wxWebViewHistoryItem>> GetBackwardHistory() override { return {}; }
virtual wxVector<wxSharedPtr<wxWebViewHistoryItem>> GetForwardHistory() override { return {}; }
virtual void LoadHistoryItem(wxSharedPtr<wxWebViewHistoryItem> item) override { }
virtual bool CanSetZoomType(wxWebViewZoomType type) const override { return false; }
virtual float GetZoomFactor() const override { return 0.0f; }
virtual wxWebViewZoomType GetZoomType() const override { return wxWebViewZoomType(); }
virtual void SetZoomFactor(float zoom) override { }
virtual void SetZoomType(wxWebViewZoomType zoomType) override { }
virtual bool CanUndo() const override { return false; }
virtual bool CanRedo() const override { return false; }
virtual void Undo() override { }
virtual void Redo() override { }
virtual void* GetNativeBackend() const override { return nullptr; }
virtual void DoSetPage(const wxString& html, const wxString& baseUrl) override { }
};
wxWebView* WebView::CreateWebView(wxWindow * parent, wxString const & url)
{
#if wxUSE_WEBVIEW_EDGE
// Check if a fixed version of edge is present in
// $executable_path/edge_fixed and use it
wxFileName edgeFixedDir(wxStandardPaths::Get().GetExecutablePath());
edgeFixedDir.SetFullName("");
edgeFixedDir.AppendDir("edge_fixed");
if (edgeFixedDir.DirExists()) {
wxWebViewEdge::MSWSetBrowserExecutableDir(edgeFixedDir.GetFullPath());
wxLogMessage("Using fixed edge version");
}
#endif
auto url2 = url;
#ifdef __WIN32__
url2.Replace("\\", "/");
#endif
if (!url2.empty()) { url2 = wxURI(url2).BuildURI(); }
auto webView = wxWebView::New();
if (webView) {
#ifdef __WIN32__
webView->SetUserAgent(wxString::Format("BBL-Slicer/v%s", SLIC3R_VERSION));
webView->Create(parent, wxID_ANY, url2, wxDefaultPosition, wxDefaultSize);
//We register the wxfs:// protocol for testing purposes
webView->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewArchiveHandler("bbl")));
//And the memory: file system
webView->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewFSHandler("memory")));
#else
// With WKWebView handlers need to be registered before creation
webView->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewArchiveHandler("wxfs")));
// And the memory: file system
webView->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewFSHandler("memory")));
webView->Create(parent, wxID_ANY, url2, wxDefaultPosition, wxDefaultSize);
webView->SetUserAgent(wxString::Format("BBL-Slicer/v%s", SLIC3R_VERSION));
#endif
#ifdef __WXMAC__
Slic3r::GUI::wxGetApp().CallAfter([webView] {
#endif
if (!webView->AddScriptMessageHandler("wx"))
wxLogError("Could not add script message handler");
#ifdef __WXMAC__
});
#endif
webView->EnableContextMenu(false);
} else {
webView = new FakeWebView;
}
return webView;
}
bool WebView::RunScript(wxWebView *webView, wxString const &javascript)
{
if (Slic3r::GUI::wxGetApp().get_mode() == Slic3r::comDevelop)
wxLogMessage("Running JavaScript:\n%s\n", javascript);
try {
#ifdef __WIN32__
ICoreWebView2 * webView2 = (ICoreWebView2 *) webView->GetNativeBackend();
if (webView2 == nullptr)
return false;
int count = 0;
wxJSScriptWrapper wrapJS(javascript, &count);
return webView2->ExecuteScript(wrapJS.GetWrappedCode(), NULL) == 0;
#else
wxString result;
return webView->RunScript(javascript, &result);
#endif
} catch (std::exception &e) {
return false;
}
}

View file

@ -0,0 +1,14 @@
#ifndef slic3r_GUI_WebView_hpp_
#define slic3r_GUI_WebView_hpp_
#include <wx/webview.h>
class WebView
{
public:
static wxWebView *CreateWebView(wxWindow *parent, wxString const &url);
static bool RunScript(wxWebView * webView, wxString const & msg);
};
#endif // !slic3r_GUI_WebView_hpp_