WIP: Experiments with New simple top bar

This commit is contained in:
YuSanka 2023-07-26 16:31:15 +02:00 committed by David Kocik
parent 5f34abf473
commit ada1fc37ff
9 changed files with 861 additions and 72 deletions

View File

@ -252,6 +252,8 @@ set(SLIC3R_GUI_SOURCES
GUI/DoubleSlider.hpp
GUI/Notebook.cpp
GUI/Notebook.hpp
GUI/TopBar.cpp
GUI/TopBar.hpp
GUI/ObjectDataViewModel.cpp
GUI/ObjectDataViewModel.hpp
GUI/InstanceCheck.cpp

View File

@ -103,7 +103,8 @@
#include "WebViewDialog.hpp"
#include "BitmapCache.hpp"
#include "Notebook.hpp"
//#include "Notebook.hpp"
#include "TopBar.hpp"
#ifdef __WXMSW__
#include <dbt.h>
@ -1519,16 +1520,16 @@ void GUI_App::init_ui_colours()
m_mode_palette = get_mode_default_palette();
bool is_dark_mode = dark_mode();
#ifdef _WIN32
//#ifdef _WIN32
m_color_label_default = is_dark_mode ? wxColour(250, 250, 250): wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
m_color_highlight_label_default = is_dark_mode ? wxColour(230, 230, 230): wxSystemSettings::GetColour(/*wxSYS_COLOUR_HIGHLIGHTTEXT*/wxSYS_COLOUR_WINDOWTEXT);
m_color_highlight_default = is_dark_mode ? wxColour(78, 78, 78) : wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT);
m_color_hovered_btn_label = is_dark_mode ? wxColour(253, 111, 40) : wxColour(252, 77, 1);
m_color_default_btn_label = is_dark_mode ? wxColour(255, 181, 100): wxColour(203, 61, 0);
m_color_selected_btn_bg = is_dark_mode ? wxColour(95, 73, 62) : wxColour(228, 220, 216);
#else
m_color_label_default = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
#endif
//#else
// m_color_label_default = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
//#endif
m_color_window_default = is_dark_mode ? wxColour(43, 43, 43) : wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
}
@ -1564,12 +1565,13 @@ void GUI_App::update_label_colours()
tab->update_label_colours();
}
#ifdef _WIN32
#if 0//def _WIN32
static bool is_focused(HWND hWnd)
{
HWND hFocusedWnd = ::GetFocus();
return hFocusedWnd && hWnd == hFocusedWnd;
}
#endif
static bool is_default(wxWindow* win)
{
@ -1579,7 +1581,6 @@ static bool is_default(wxWindow* win)
return win == tlw->GetDefaultItem();
}
#endif
void GUI_App::UpdateDarkUI(wxWindow* window, bool highlited/* = false*/, bool just_font/* = false*/)
{
@ -1592,6 +1593,7 @@ void GUI_App::UpdateDarkUI(wxWindow* window, bool highlited/* = false*/, bool ju
highlited = true;
}
// button marking
if (!dynamic_cast<TopBarItemsCtrl*>(window->GetParent())) // don't marking the button if it is from TopBar
{
auto mark_button = [this, btn, highlited](const bool mark) {
if (btn->GetLabel().IsEmpty())
@ -1604,12 +1606,12 @@ void GUI_App::UpdateDarkUI(wxWindow* window, bool highlited/* = false*/, bool ju
// hovering
btn->Bind(wxEVT_ENTER_WINDOW, [mark_button](wxMouseEvent& event) { mark_button(true); event.Skip(); });
btn->Bind(wxEVT_LEAVE_WINDOW, [mark_button, btn](wxMouseEvent& event) { mark_button(is_focused(btn->GetHWND())); event.Skip(); });
btn->Bind(wxEVT_LEAVE_WINDOW, [mark_button, btn](wxMouseEvent& event) { mark_button(btn->HasFocus()); event.Skip(); });
// focusing
btn->Bind(wxEVT_SET_FOCUS, [mark_button](wxFocusEvent& event) { mark_button(true); event.Skip(); });
btn->Bind(wxEVT_KILL_FOCUS, [mark_button](wxFocusEvent& event) { mark_button(false); event.Skip(); });
is_focused_button = is_focused(btn->GetHWND());
is_focused_button = btn->HasFocus();// is_focused(btn->GetHWND());
is_default_button = is_default(btn);
if (is_focused_button || is_default_button)
mark_button(is_focused_button);
@ -2471,10 +2473,8 @@ void GUI_App::update_mode()
{
sidebar().update_mode();
#ifdef _WIN32 //_MSW_DARK_MODE
if (!wxGetApp().tabs_as_menu())
dynamic_cast<Notebook*>(mainframe->m_tabpanel)->UpdateMode();
#endif
dynamic_cast<TopBar*>(mainframe->m_tabpanel)->UpdateMode();
for (auto tab : tabs_list)
tab->update_mode();
@ -2483,7 +2483,8 @@ void GUI_App::update_mode()
plater()->canvas3D()->update_gizmos_on_off_state();
}
void GUI_App::add_config_menu(wxMenuBar *menu)
//void GUI_App::add_config_menu(wxMenuBar *menu)
wxMenu* GUI_App::get_config_menu()
{
auto local_menu = new wxMenu();
wxWindowID config_id_base = wxWindow::NewControlId(int(ConfigMenuCnt));
@ -2518,6 +2519,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
"\tCtrl+P",
#endif
_L("Application preferences"));
/*
wxMenu* mode_menu = nullptr;
if (is_editor()) {
local_menu->AppendSeparator();
@ -2532,6 +2534,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
local_menu->AppendSubMenu(mode_menu, _L("Mode"), wxString::Format(_L("%s View Mode"), SLIC3R_APP_NAME));
}
*/
local_menu->AppendSeparator();
local_menu->Append(config_id_base + ConfigMenuLanguage, _L("&Language"));
if (is_editor()) {
@ -2677,6 +2680,10 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
}
});
#if 1
return local_menu;
#else
using std::placeholders::_1;
if (mode_menu != nullptr) {
@ -2687,6 +2694,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
}
menu->Append(local_menu, _L("&Configuration"));
#endif
}
void GUI_App::update_config_menu()
{

View File

@ -146,12 +146,13 @@ private:
wxColour m_color_label_sys;
wxColour m_color_label_default;
wxColour m_color_window_default;
#ifdef _WIN32
//#ifdef _WIN32
wxColour m_color_highlight_label_default;
wxColour m_color_hovered_btn_label;
wxColour m_color_default_btn_label;
wxColour m_color_highlight_default;
wxColour m_color_selected_btn_bg;
#ifdef _WIN32
bool m_force_colors_update { false };
#endif
std::vector<std::string> m_mode_palette;
@ -251,7 +252,7 @@ public:
std::vector<wxColour> get_mode_palette();
void set_mode_palette(const std::vector<wxColour> &palette);
#ifdef _WIN32
//#ifdef _WIN32
const wxColour& get_label_highlight_clr() { return m_color_highlight_label_default; }
const wxColour& get_highlight_default_clr() { return m_color_highlight_default; }
const wxColour& get_color_hovered_btn_label() { return m_color_hovered_btn_label; }
@ -260,7 +261,7 @@ public:
#ifdef _MSW_DARK_MODE
void force_menu_update();
#endif //_MSW_DARK_MODE
#endif
//#endif
const wxFont& small_font() { return m_small_font; }
const wxFont& bold_font() { return m_bold_font; }
@ -297,7 +298,8 @@ public:
bool save_mode(const /*ConfigOptionMode*/int mode) ;
void update_mode();
void add_config_menu(wxMenuBar *menu);
// void add_config_menu(wxMenuBar *menu);
wxMenu* get_config_menu();
void update_config_menu();
bool has_unsaved_preset_changes() const;
bool has_current_preset_changes() const;

View File

@ -56,7 +56,8 @@
#include "GUI_App.hpp"
#include "UnsavedChangesDialog.hpp"
#include "MsgDialog.hpp"
#include "Notebook.hpp"
//#include "Notebook.hpp"
#include "TopBar.hpp"
#include "GUI_Factories.hpp"
#include "GUI_ObjectList.hpp"
#include "GalleryDialog.hpp"
@ -457,13 +458,15 @@ void MainFrame::update_layout()
case ESettingsLayout::Old:
{
m_plater->Reparent(m_tabpanel);
#ifdef _MSW_DARK_MODE
m_plater->Layout();
#ifdef _WIN32
if (!wxGetApp().tabs_as_menu())
dynamic_cast<Notebook*>(m_tabpanel)->InsertPage(0, m_plater, _L("Plater"), std::string("plater"), true);
else
#endif
dynamic_cast<TopBar*>(m_tabpanel)->InsertPage(0, m_plater, _L("Plater"), std::string("plater"), true);
#ifdef _WIN32
else
m_tabpanel->InsertPage(0, m_plater, _L("Plater"));
#endif
m_main_sizer->Add(m_tabpanel, 1, wxEXPAND | wxTOP, 1);
m_plater->Show();
m_tabpanel->Show();
@ -483,12 +486,14 @@ void MainFrame::update_layout()
m_tabpanel->Hide();
m_main_sizer->Add(m_tabpanel, 1, wxEXPAND);
m_plater_page = new wxPanel(m_tabpanel);
#ifdef _MSW_DARK_MODE
#ifdef _WIN32
if (!wxGetApp().tabs_as_menu())
dynamic_cast<Notebook*>(m_tabpanel)->InsertPage(0, m_plater_page, _L("Plater"), std::string("plater"), true);
else
#endif
dynamic_cast<TopBar*>(m_tabpanel)->InsertPage(0, m_plater_page, _L("Plater"), std::string("plater"), true);
#ifdef _WIN32
else
m_tabpanel->InsertPage(0, m_plater_page, _L("Plater")); // empty panel just for Plater tab */
#endif
m_plater->Show();
break;
}
@ -500,7 +505,7 @@ void MainFrame::update_layout()
m_tabpanel->Show();
m_plater->Show();
#ifdef _MSW_DARK_MODE
#ifdef _WIN32
if (wxGetApp().tabs_as_menu())
show_tabs_menu(false);
#endif
@ -697,22 +702,14 @@ void MainFrame::init_tabpanel()
// wxGetApp().UpdateDarkUI(m_tabpanel);
}
else
m_tabpanel = new Notebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME, true);
#else
m_tabpanel = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME);
#endif
wxGetApp().UpdateDarkUI(m_tabpanel);
m_tabpanel = new TopBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME, true);
m_tabpanel->SetFont(Slic3r::GUI::wxGetApp().normal_font());
m_tabpanel->Hide();
m_settings_dialog.set_tabpanel(m_tabpanel);
#ifdef __WXMSW__
m_tabpanel->Bind(wxEVT_BOOKCTRL_PAGE_CHANGED, [this](wxBookCtrlEvent& e) {
#else
m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, [this](wxBookCtrlEvent& e) {
#endif
if (int old_selection = e.GetOldSelection();
old_selection != wxNOT_FOUND && old_selection < static_cast<int>(m_tabpanel->GetPageCount())) {
Tab* old_tab = dynamic_cast<Tab*>(m_tabpanel->GetPage(old_selection));
@ -853,12 +850,14 @@ void MainFrame::add_created_tab(Tab* panel, const std::string& bmp_name /*= ""*
const auto printer_tech = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology();
if (panel->supports_printer_technology(printer_tech))
#ifdef _MSW_DARK_MODE
#ifdef _WIN32
if (!wxGetApp().tabs_as_menu())
dynamic_cast<Notebook*>(m_tabpanel)->AddPage(panel, panel->title(), bmp_name);
else
#endif
dynamic_cast<TopBar*>(m_tabpanel)->AddPage(panel, panel->title(), bmp_name);
#ifdef _WIN32
else
m_tabpanel->AddPage(panel, panel->title());
#endif
}
bool MainFrame::is_active_and_shown_tab(Tab* tab)
@ -1041,10 +1040,10 @@ void MainFrame::on_dpi_changed(const wxRect& suggested_rect)
wxGetApp().update_fonts(this);
this->SetFont(this->normal_font());
#ifdef _MSW_DARK_MODE
#ifdef _WIN32
// update common mode sizer
if (!wxGetApp().tabs_as_menu())
dynamic_cast<Notebook*>(m_tabpanel)->Rescale();
dynamic_cast<TopBar*>(m_tabpanel)->Rescale();
#endif
// update Plater
@ -1089,12 +1088,9 @@ void MainFrame::on_sys_color_changed()
wxGetApp().update_ui_colours_from_appconfig();
#ifdef __WXMSW__
wxGetApp().UpdateDarkUI(m_tabpanel);
#ifdef _MSW_DARK_MODE
// update common mode sizer
if (!wxGetApp().tabs_as_menu())
dynamic_cast<Notebook*>(m_tabpanel)->OnColorsChanged();
#endif
#endif
dynamic_cast<TopBar*>(m_tabpanel)->OnColorsChanged();
// update Plater
wxGetApp().plater()->sys_color_changed();
@ -1112,13 +1108,9 @@ void MainFrame::on_sys_color_changed()
void MainFrame::update_mode_markers()
{
#ifdef __WXMSW__
#ifdef _MSW_DARK_MODE
// update markers in common mode sizer
if (!wxGetApp().tabs_as_menu())
dynamic_cast<Notebook*>(m_tabpanel)->UpdateModeMarkers();
#endif
#endif
dynamic_cast<TopBar*>(m_tabpanel)->UpdateModeMarkers();
// update mode markers on side_bar
wxGetApp().sidebar().update_mode_markers();
@ -1547,6 +1539,28 @@ void MainFrame::init_menubar_as_editor()
// Help menu
auto helpMenu = generate_help_menu();
#if 1
// append menus for Menu button from TopBar
TopBar* top_bar = dynamic_cast<TopBar*>(m_tabpanel);
top_bar->AppendMenuItem(fileMenu, _L("&File"));
if (editMenu)
top_bar->AppendMenuItem(editMenu, _L("&Edit"));
top_bar->AppendMenuSeparaorItem();
top_bar->AppendMenuItem(windowMenu, _L("&Window"));
if (viewMenu)
top_bar->AppendMenuItem(viewMenu, _L("&View"));
top_bar->AppendMenuItem(wxGetApp().get_config_menu(), _L("&Configuration"));
top_bar->AppendMenuSeparaorItem();
top_bar->AppendMenuItem(helpMenu, _L("&Help"));
#else
// menubar
// assign menubar to frame after appending items, otherwise special items
// will not be handled correctly
@ -1569,6 +1583,8 @@ void MainFrame::init_menubar_as_editor()
#endif
SetMenuBar(m_menubar);
#endif
#ifdef _MSW_DARK_MODE
if (wxGetApp().tabs_as_menu())
m_menubar->EnableTop(6, false);
@ -1662,7 +1678,7 @@ void MainFrame::init_menubar_as_gcodeviewer()
m_menubar->Append(fileMenu, _L("&File"));
if (viewMenu != nullptr) m_menubar->Append(viewMenu, _L("&View"));
// Add additional menus from C++
wxGetApp().add_config_menu(m_menubar);
// wxGetApp().add_config_menu(m_menubar);
m_menubar->Append(helpMenu, _L("&Help"));
SetMenuBar(m_menubar);
@ -2243,10 +2259,10 @@ void SettingsDialog::on_dpi_changed(const wxRect& suggested_rect)
const int& em = em_unit();
const wxSize& size = wxSize(85 * em, 50 * em);
#ifdef _MSW_DARK_MODE
#ifdef _WIN32
// update common mode sizer
if (!wxGetApp().tabs_as_menu())
dynamic_cast<Notebook*>(m_tabpanel)->Rescale();
dynamic_cast<TopBar*>(m_tabpanel)->Rescale();
#endif
// update Tabs

View File

@ -67,7 +67,8 @@
#include "SavePresetDialog.hpp"
#include "EditGCodeDialog.hpp"
#include "MsgDialog.hpp"
#include "Notebook.hpp"
//#include "Notebook.hpp"
#include "TopBar.hpp"
#include "Widgets/CheckBox.hpp"
@ -3648,13 +3649,6 @@ void Tab::load_current_preset()
// m_undo_to_sys_btn->Enable(!preset.is_default);
#if 0
// use CallAfter because some field triggers schedule on_change calls using CallAfter,
// and we don't want them to be called after this update_dirty() as they would mark the
// preset dirty again
// (not sure this is true anymore now that update_dirty is idempotent)
wxTheApp->CallAfter([this]
#endif
{
// checking out if this Tab exists till this moment
if (!wxGetApp().checked_tab(this))
@ -3682,16 +3676,15 @@ void Tab::load_current_preset()
}
if (tab->supports_printer_technology(printer_technology))
{
#ifdef _MSW_DARK_MODE
#ifdef _WIN32
if (!wxGetApp().tabs_as_menu()) {
std::string bmp_name = tab->type() == Slic3r::Preset::TYPE_FILAMENT ? "spool" :
tab->type() == Slic3r::Preset::TYPE_SLA_MATERIAL ? "resin" : "cog";
tab->Hide(); // #ys_WORKAROUND : Hide tab before inserting to avoid unwanted rendering of the tab
dynamic_cast<Notebook*>(wxGetApp().tab_panel())->InsertPage(wxGetApp().tab_panel()->FindPage(this), tab, tab->title(), bmp_name);
#endif
dynamic_cast<TopBar*>(wxGetApp().tab_panel())->InsertPage(wxGetApp().tab_panel()->FindPage(this), tab, tab->title(),"");
#ifdef _WIN32
}
else
#endif
wxGetApp().tab_panel()->InsertPage(wxGetApp().tab_panel()->FindPage(this), tab, tab->title());
#endif
#ifdef __linux__ // the tabs apparently need to be explicitly shown on Linux (pull request #1563)
int page_id = wxGetApp().tab_panel()->FindPage(tab);
wxGetApp().tab_panel()->GetPage(page_id)->Show(true);
@ -3705,10 +3698,6 @@ void Tab::load_current_preset()
}
static_cast<TabPrinter*>(this)->m_printer_technology = printer_technology;
m_active_page = tmp_page;
#ifdef _MSW_DARK_MODE
if (!wxGetApp().tabs_as_menu())
dynamic_cast<Notebook*>(wxGetApp().tab_panel())->SetPageImage(wxGetApp().tab_panel()->FindPage(this), printer_technology == ptFFF ? "printer" : "sla_printer");
#endif
}
on_presets_changed();
if (printer_technology == ptFFF) {

View File

@ -478,7 +478,8 @@ class TabFilament : public Tab
std::map<std::string, wxWindow*> m_overrides_options;
public:
TabFilament(wxBookCtrlBase* parent) :
Tab(parent, _(L("Filament Settings")), Slic3r::Preset::TYPE_FILAMENT) {}
// Tab(parent, _(L("Filament Settings")), Slic3r::Preset::TYPE_FILAMENT) {}
Tab(parent, _L("Filaments"), Slic3r::Preset::TYPE_FILAMENT) {}
~TabFilament() {}
void build() override;
@ -536,7 +537,8 @@ public:
PrinterTechnology m_printer_technology = ptFFF;
TabPrinter(wxBookCtrlBase* parent) :
Tab(parent, _L("Printer Settings"), Slic3r::Preset::TYPE_PRINTER) {}
// Tab(parent, _L("Printer Settings"), Slic3r::Preset::TYPE_PRINTER) {}
Tab(parent, _L("Printers"), Slic3r::Preset::TYPE_PRINTER) {}
~TabPrinter() {}
void build() override;
@ -574,7 +576,8 @@ class TabSLAMaterial : public Tab
std::map<std::string, wxWindow*> m_overrides_options;
public:
TabSLAMaterial(wxBookCtrlBase* parent) :
Tab(parent, _(L("Material Settings")), Slic3r::Preset::TYPE_SLA_MATERIAL) {}
// Tab(parent, _(L("Material Settings")), Slic3r::Preset::TYPE_SLA_MATERIAL) {}
Tab(parent, _L("Materials"), Slic3r::Preset::TYPE_SLA_MATERIAL) {}
~TabSLAMaterial() {}
void build() override;

308
src/slic3r/GUI/TopBar.cpp Normal file
View File

@ -0,0 +1,308 @@
#include "TopBar.hpp"
#include "GUI_App.hpp"
#include "Plater.hpp"
//#include "wxExtensions.hpp"
#include "format.hpp"
#include "I18N.hpp"
#include <wx/button.h>
#include <wx/sizer.h>
wxDEFINE_EVENT(wxCUSTOMEVT_TOPBAR_SEL_CHANGED, wxCommandEvent);
using namespace Slic3r::GUI;
#define down_arrow L"\u23f7";
TopBarItemsCtrl::Button::Button(wxWindow* parent, const wxString& label, const std::string& icon_name, const int px_cnt)
:ScalableButton(parent, wxID_ANY, icon_name, label, wxDefaultSize, wxDefaultPosition, wxNO_BORDER, px_cnt)
{
int btn_margin = em_unit(this);
wxSize size = GetTextExtent(label) + wxSize(6 * btn_margin, int(1.5 * btn_margin));
if (icon_name.empty())
this->SetMinSize(size);
else
this->SetMinSize(wxSize(-1, size.y));
const wxColour& selected_btn_bg = wxGetApp().get_label_clr_default();
const wxColour& default_btn_bg = wxGetApp().get_window_default_clr();
this->Bind(wxEVT_SET_FOCUS, [this, selected_btn_bg, default_btn_bg](wxFocusEvent& event) {
this->SetBackgroundColour(selected_btn_bg);
this->SetForegroundColour(default_btn_bg);
event.Skip();
});
this->Bind(wxEVT_KILL_FOCUS, [this, selected_btn_bg, default_btn_bg](wxFocusEvent& event) {
if (!m_is_selected) {
this->SetBackgroundColour(default_btn_bg);
this->SetForegroundColour(selected_btn_bg);
}
event.Skip();
});
}
TopBarItemsCtrl::ButtonWithPopup::ButtonWithPopup(wxWindow* parent, const wxString& label, const std::string& icon_name)
:TopBarItemsCtrl::Button(parent, label, icon_name, 24)
{
this->SetLabel(label);
}
void TopBarItemsCtrl::ButtonWithPopup::SetLabel(const wxString& label)
{
wxString full_label = " " + label + " " + down_arrow;
ScalableButton::SetLabel(full_label);
}
static wxString get_workspace_name(Slic3r::ConfigOptionMode mode)
{
return mode == Slic3r::ConfigOptionMode::comSimple ? _L("Beginner workspace") :
mode == Slic3r::ConfigOptionMode::comAdvanced ? _L("Regular workspace") : _L("Josef Prusa's workspace");
}
TopBarItemsCtrl::TopBarItemsCtrl(wxWindow *parent, bool add_mode_buttons/* = false*/) :
wxControl(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE | wxTAB_TRAVERSAL)
{
#ifdef __WINDOWS__
SetDoubleBuffered(true);
#endif //__WINDOWS__
int em = em_unit(this);// Slic3r::GUI::wxGetApp().em_unit();
m_btn_margin = std::lround(0.9 * em);
m_line_margin = std::lround(0.1 * em);
m_sizer = new wxBoxSizer(wxHORIZONTAL);
this->SetSizer(m_sizer);
m_menu_btn = new ButtonWithPopup(this, _L("Menu"), wxGetApp().logo_name());
m_sizer->Add(m_menu_btn, 1, wxALIGN_CENTER_VERTICAL | wxALL, m_btn_margin);
m_buttons_sizer = new wxFlexGridSizer(1, m_btn_margin, m_btn_margin);
m_sizer->Add(m_buttons_sizer, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 2 * m_btn_margin);
if (add_mode_buttons) {
m_mode_sizer = new ModeSizer(this, m_btn_margin);
m_sizer->AddStretchSpacer(20);
m_sizer->Add(m_mode_sizer, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT | wxBOTTOM, m_btn_margin);
m_mode_sizer->ShowItems(false);
}
m_workspace_btn = new ButtonWithPopup(this, _L("Workspace"), "mode_simple");
m_sizer->AddStretchSpacer(20);
m_sizer->Add(m_workspace_btn, 1, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxRIGHT, 2 * m_btn_margin);
// create modes menu
{
for (const Slic3r::ConfigOptionMode& mode : { Slic3r::ConfigOptionMode::comSimple, Slic3r::ConfigOptionMode::comAdvanced, Slic3r::ConfigOptionMode::comExpert } ) {
const wxString label = get_workspace_name(mode);
append_menu_item(&m_workspace_modes, wxID_ANY, label, label,
[this, mode](wxCommandEvent&) {
if (wxGetApp().get_mode() != mode)
wxGetApp().save_mode(mode);
}, get_bmp_bundle("mode", 16, -1, wxGetApp().get_mode_btn_color(mode)), nullptr, []() { return true; }, this);
if (mode < Slic3r::ConfigOptionMode::comExpert)
m_workspace_modes.AppendSeparator();
}
}
this->Bind(wxEVT_PAINT, &TopBarItemsCtrl::OnPaint, this);
m_menu_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) {
wxPoint pos = m_menu_btn->GetPosition();
wxGetApp().plater()->PopupMenu(&m_menu, pos);
});
m_menu.Bind(wxEVT_MENU_CLOSE, [this](wxMenuEvent&) {
if (m_menu_btn->HasFocus()) {
wxPostEvent(m_menu_btn->GetEventHandler(), wxFocusEvent(wxEVT_KILL_FOCUS));
}
});
m_workspace_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) {
wxPoint pos = m_workspace_btn->GetPosition();
wxGetApp().plater()->PopupMenu(&m_workspace_modes, pos);
});
m_workspace_modes.Bind(wxEVT_MENU_CLOSE, [this](wxMenuEvent&) {
if (m_workspace_btn->HasFocus()) {
wxPostEvent(m_workspace_btn->GetEventHandler(), wxFocusEvent(wxEVT_KILL_FOCUS));
}
});
}
void TopBarItemsCtrl::OnPaint(wxPaintEvent&)
{
wxGetApp().UpdateDarkUI(this);
const wxSize sz = GetSize();
wxPaintDC dc(this);
if (m_selection < 0 || m_selection >= (int)m_pageButtons.size())
return;
const wxColour& selected_btn_bg = wxGetApp().get_label_clr_default();
const wxColour& default_btn_bg = wxGetApp().get_window_default_clr();
const wxColour& btn_marker_color = wxGetApp().get_highlight_default_clr();
// highlight selected notebook button
for (int idx = 0; idx < int(m_pageButtons.size()); idx++) {
wxButton* btn = m_pageButtons[idx];
btn->SetBackgroundColour(idx == m_selection ? selected_btn_bg : default_btn_bg);
btn->SetForegroundColour(idx == m_selection ? default_btn_bg : selected_btn_bg);
}
// highlight selected mode button
//bool mode_is_focused = m_workspace_btn->HasFocus();
//m_workspace_btn->SetBackgroundColour(mode_is_focused ? selected_btn_bg : default_btn_bg);
//m_workspace_btn->SetForegroundColour(mode_is_focused ? default_btn_bg : selected_btn_bg);
//if (m_mode_sizer) {
// const std::vector<ModeButton*>& mode_btns = m_mode_sizer->get_btns();
// for (int idx = 0; idx < int(mode_btns.size()); idx++) {
// ModeButton* btn = mode_btns[idx];
// btn->SetBackgroundColour(btn->is_selected() ? selected_btn_bg : default_btn_bg);
// //wxPoint pos = btn->GetPosition();
// //wxSize size = btn->GetSize();
// //const wxColour& clr = btn->is_selected() ? btn_marker_color : default_btn_bg;
// //dc.SetPen(clr);
// //dc.SetBrush(clr);
// //dc.DrawRectangle(pos.x, pos.y + size.y, size.x, sz.y - size.y);
// }
//}
// Draw orange bottom line
dc.SetPen(btn_marker_color);
dc.SetBrush(btn_marker_color);
dc.DrawRectangle(1, sz.y - m_line_margin, sz.x, m_line_margin);
}
void TopBarItemsCtrl::UpdateMode()
{
auto mode = wxGetApp().get_mode();
m_mode_sizer->SetMode(mode);
auto m_bmp = *get_bmp_bundle("mode", 16, -1, wxGetApp().get_mode_btn_color(mode));
m_workspace_btn->SetBitmap(m_bmp);
m_workspace_btn->SetBitmapCurrent(m_bmp);
m_workspace_btn->SetBitmapPressed(m_bmp);
m_workspace_btn->SetLabel(get_workspace_name(mode));
m_workspace_btn->SetBitmapMargins(int(0.5 * em_unit(this)), 0);
this->Layout();
}
void TopBarItemsCtrl::Rescale()
{
int em = em_unit(this);
m_btn_margin = std::lround(0.3 * em);
m_line_margin = std::lround(0.1 * em);
m_buttons_sizer->SetVGap(m_btn_margin);
m_buttons_sizer->SetHGap(m_btn_margin);
m_sizer->Layout();
}
void TopBarItemsCtrl::OnColorsChanged()
{
m_menu_btn->sys_color_changed();
for (ScalableButton* btn : m_pageButtons)
btn->sys_color_changed();
m_mode_sizer->sys_color_changed();
m_sizer->Layout();
}
void TopBarItemsCtrl::UpdateModeMarkers()
{
m_mode_sizer->update_mode_markers();
}
void TopBarItemsCtrl::UpdateSelection()
{
for (Button* btn : m_pageButtons)
btn->set_selected(false);
if (m_selection >= 0)
m_pageButtons[m_selection]->set_selected(true);
Refresh();
}
void TopBarItemsCtrl::SetSelection(int sel)
{
if (m_selection == sel)
return;
m_selection = sel;
UpdateSelection();
}
bool TopBarItemsCtrl::InsertPage(size_t n, const wxString& text, bool bSelect/* = false*/, const std::string& bmp_name/* = ""*/)
{
Button* btn = new Button(this, text);
btn->Bind(wxEVT_BUTTON, [this, btn](wxCommandEvent& event) {
if (auto it = std::find(m_pageButtons.begin(), m_pageButtons.end(), btn); it != m_pageButtons.end()) {
m_selection = it - m_pageButtons.begin();
wxCommandEvent evt = wxCommandEvent(wxCUSTOMEVT_TOPBAR_SEL_CHANGED);
evt.SetId(m_selection);
wxPostEvent(this->GetParent(), evt);
UpdateSelection();
}
});
m_pageButtons.insert(m_pageButtons.begin() + n, btn);
m_buttons_sizer->Insert(n, new wxSizerItem(btn, 0, wxALIGN_CENTER_VERTICAL));
m_buttons_sizer->SetCols(m_buttons_sizer->GetCols() + 1);
m_sizer->Layout();
return true;
}
void TopBarItemsCtrl::RemovePage(size_t n)
{
ScalableButton* btn = m_pageButtons[n];
m_pageButtons.erase(m_pageButtons.begin() + n);
m_buttons_sizer->Remove(n);
btn->Reparent(nullptr);
btn->Destroy();
m_sizer->Layout();
}
void TopBarItemsCtrl::SetPageText(size_t n, const wxString& strText)
{
ScalableButton* btn = m_pageButtons[n];
btn->SetLabel(strText);
}
wxString TopBarItemsCtrl::GetPageText(size_t n) const
{
ScalableButton* btn = m_pageButtons[n];
return btn->GetLabel();
}
void TopBarItemsCtrl::AppendMenuItem(wxMenu* menu, const wxString& title)
{
append_submenu(&m_menu, menu, wxID_ANY, title, "cog");
}
void TopBarItemsCtrl::AppendMenuSeparaorItem()
{
m_menu.AppendSeparator();
}
void TopBarItemsCtrl::ShowMenu()
{
wxPoint pos = m_menu_btn->GetPosition();
wxGetApp().plater()->PopupMenu(&m_menu, pos);
}

459
src/slic3r/GUI/TopBar.hpp Normal file
View File

@ -0,0 +1,459 @@
#ifndef slic3r_TopBar_hpp_
#define slic3r_TopBar_hpp_
//#ifdef _WIN32
#include <wx/bookctrl.h>
#include "wxExtensions.hpp"
class ModeSizer;
//class ScalableButton;
// custom message the TopBarItemsCtrl sends to its parent (TopBar) to notify a selection change:
wxDECLARE_EVENT(wxCUSTOMEVT_TOPBAR_SEL_CHANGED, wxCommandEvent);
class TopBarItemsCtrl : public wxControl
{
class Button : public ScalableButton
{
bool m_is_selected{ false };
public:
Button() {};
Button( wxWindow* parent,
const wxString& label,
const std::string& icon_name = "",
const int px_cnt = 16);
~Button() {}
void set_selected(bool selected) { m_is_selected = selected; }
};
class ButtonWithPopup : public Button
{
public:
ButtonWithPopup() {};
ButtonWithPopup(wxWindow* parent,
const wxString& label,
const std::string& icon_name = "");
~ButtonWithPopup() {}
void SetLabel(const wxString& label) override;
};
MenuWithSeparators m_menu;
MenuWithSeparators m_workspace_modes;
public:
TopBarItemsCtrl(wxWindow* parent, bool add_mode_buttons = false);
~TopBarItemsCtrl() {}
void OnPaint(wxPaintEvent&);
void SetSelection(int sel);
void UpdateMode();
void Rescale();
void OnColorsChanged();
void UpdateModeMarkers();
void UpdateSelection();
bool InsertPage(size_t n, const wxString& text, bool bSelect = false, const std::string& bmp_name = "");
void RemovePage(size_t n);
void SetPageText(size_t n, const wxString& strText);
wxString GetPageText(size_t n) const;
void AppendMenuItem(wxMenu* menu, const wxString& title);
void AppendMenuSeparaorItem();
void ShowMenu();
void AddModeItem();
void ShowModes();
private:
wxWindow* m_parent;
wxFlexGridSizer* m_buttons_sizer;
wxBoxSizer* m_sizer;
ButtonWithPopup* m_menu_btn {nullptr};
ButtonWithPopup* m_workspace_btn {nullptr};
std::vector<Button*> m_pageButtons;
int m_selection {-1};
int m_btn_margin;
int m_line_margin;
ModeSizer* m_mode_sizer {nullptr};
};
class TopBar : public wxBookCtrlBase
{
public:
TopBar(wxWindow * parent,
wxWindowID winid = wxID_ANY,
const wxPoint & pos = wxDefaultPosition,
const wxSize & size = wxDefaultSize,
long style = 0,
bool add_mode_buttons = false)
{
Init();
Create(parent, winid, pos, size, style, add_mode_buttons);
}
bool Create(wxWindow * parent,
wxWindowID winid = wxID_ANY,
const wxPoint & pos = wxDefaultPosition,
const wxSize & size = wxDefaultSize,
long style = 0,
bool add_mode_buttons = false)
{
if (!wxBookCtrlBase::Create(parent, winid, pos, size, style | wxBK_TOP))
return false;
m_bookctrl = new TopBarItemsCtrl(this, add_mode_buttons);
wxSizer* mainSizer = new wxBoxSizer(IsVertical() ? wxVERTICAL : wxHORIZONTAL);
if (style & wxBK_RIGHT || style & wxBK_BOTTOM)
mainSizer->Add(0, 0, 1, wxEXPAND, 0);
m_controlSizer = new wxBoxSizer(IsVertical() ? wxHORIZONTAL : wxVERTICAL);
m_controlSizer->Add(m_bookctrl, wxSizerFlags(1).Expand());
wxSizerFlags flags;
if (IsVertical())
flags.Expand();
else
flags.CentreVertical();
mainSizer->Add(m_controlSizer, flags.Border(wxALL, m_controlMargin));
SetSizer(mainSizer);
this->Bind(wxCUSTOMEVT_TOPBAR_SEL_CHANGED, [this](wxCommandEvent& evt)
{
if (int page_idx = evt.GetId(); page_idx >= 0)
SetSelection(page_idx);
});
this->Bind(wxEVT_NAVIGATION_KEY, &TopBar::OnNavigationKey, this);
return true;
}
// Methods specific to this class.
// A method allowing to add a new page without any label (which is unused
// by this control) and show it immediately.
bool ShowNewPage(wxWindow * page)
{
return AddPage(page, wxString(), ""/*true *//* select it */);
}
// Set effect to use for showing/hiding pages.
void SetEffects(wxShowEffect showEffect, wxShowEffect hideEffect)
{
m_showEffect = showEffect;
m_hideEffect = hideEffect;
}
// Or the same effect for both of them.
void SetEffect(wxShowEffect effect)
{
SetEffects(effect, effect);
}
// And the same for time outs.
void SetEffectsTimeouts(unsigned showTimeout, unsigned hideTimeout)
{
m_showTimeout = showTimeout;
m_hideTimeout = hideTimeout;
}
void SetEffectTimeout(unsigned timeout)
{
SetEffectsTimeouts(timeout, timeout);
}
// Implement base class pure virtual methods.
// adds a new page to the control
bool AddPage(wxWindow* page,
const wxString& text,
const std::string& bmp_name,
bool bSelect = false)
{
DoInvalidateBestSize();
return InsertPage(GetPageCount(), page, text, bmp_name, bSelect);
}
// Page management
virtual bool InsertPage(size_t n,
wxWindow * page,
const wxString & text,
bool bSelect = false,
int imageId = NO_IMAGE) override
{
if (!wxBookCtrlBase::InsertPage(n, page, text, bSelect, imageId))
return false;
GetTopBarItemsCtrl()->InsertPage(n, text, bSelect);
if (!DoSetSelectionAfterInsertion(n, bSelect))
page->Hide();
return true;
}
bool InsertPage(size_t n,
wxWindow * page,
const wxString & text,
const std::string& bmp_name = "",
bool bSelect = false)
{
if (!wxBookCtrlBase::InsertPage(n, page, text, bSelect))
return false;
GetTopBarItemsCtrl()->InsertPage(n, text, bSelect, bmp_name);
if (bSelect)
SetSelection(n);
return true;
}
virtual int SetSelection(size_t n) override
{
GetTopBarItemsCtrl()->SetSelection(n);
int ret = DoSetSelection(n, SetSelection_SendEvent);
// check that only the selected page is visible and others are hidden:
for (size_t page = 0; page < m_pages.size(); page++)
if (page != n)
m_pages[page]->Hide();
return ret;
}
virtual int ChangeSelection(size_t n) override
{
GetTopBarItemsCtrl()->SetSelection(n);
return DoSetSelection(n);
}
// Neither labels nor images are supported but we still store the labels
// just in case the user code attaches some importance to them.
virtual bool SetPageText(size_t n, const wxString & strText) override
{
wxCHECK_MSG(n < GetPageCount(), false, wxS("Invalid page"));
GetTopBarItemsCtrl()->SetPageText(n, strText);
return true;
}
virtual wxString GetPageText(size_t n) const override
{
wxCHECK_MSG(n < GetPageCount(), wxString(), wxS("Invalid page"));
return GetTopBarItemsCtrl()->GetPageText(n);
}
virtual bool SetPageImage(size_t WXUNUSED(n), int WXUNUSED(imageId)) override
{
return false;
}
virtual int GetPageImage(size_t WXUNUSED(n)) const override
{
return NO_IMAGE;
}
// Override some wxWindow methods too.
virtual void SetFocus() override
{
wxWindow* const page = GetCurrentPage();
if (page)
page->SetFocus();
}
TopBarItemsCtrl* GetTopBarItemsCtrl() const { return static_cast<TopBarItemsCtrl*>(m_bookctrl); }
void UpdateMode()
{
GetTopBarItemsCtrl()->UpdateMode();
}
void Rescale()
{
GetTopBarItemsCtrl()->Rescale();
}
void OnColorsChanged()
{
GetTopBarItemsCtrl()->OnColorsChanged();
}
void UpdateModeMarkers()
{
GetTopBarItemsCtrl()->UpdateModeMarkers();
}
void OnNavigationKey(wxNavigationKeyEvent& event)
{
if (event.IsWindowChange()) {
// change pages
AdvanceSelection(event.GetDirection());
}
else {
// we get this event in 3 cases
//
// a) one of our pages might have generated it because the user TABbed
// out from it in which case we should propagate the event upwards and
// our parent will take care of setting the focus to prev/next sibling
//
// or
//
// b) the parent panel wants to give the focus to us so that we
// forward it to our selected page. We can't deal with this in
// OnSetFocus() because we don't know which direction the focus came
// from in this case and so can't choose between setting the focus to
// first or last panel child
//
// or
//
// c) we ourselves (see MSWTranslateMessage) generated the event
//
wxWindow* const parent = GetParent();
// the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE
const bool isFromParent = event.GetEventObject() == (wxObject*)parent;
const bool isFromSelf = event.GetEventObject() == (wxObject*)this;
const bool isForward = event.GetDirection();
if (isFromSelf && !isForward)
{
// focus is currently on notebook tab and should leave
// it backwards (Shift-TAB)
event.SetCurrentFocus(this);
parent->HandleWindowEvent(event);
}
else if (isFromParent || isFromSelf)
{
// no, it doesn't come from child, case (b) or (c): forward to a
// page but only if entering notebook page (i.e. direction is
// backwards (Shift-TAB) comething from out-of-notebook, or
// direction is forward (TAB) from ourselves),
if (m_selection != wxNOT_FOUND &&
(!event.GetDirection() || isFromSelf))
{
// so that the page knows that the event comes from it's parent
// and is being propagated downwards
event.SetEventObject(this);
wxWindow* page = m_pages[m_selection];
if (!page->HandleWindowEvent(event))
{
page->SetFocus();
}
//else: page manages focus inside it itself
}
else // otherwise set the focus to the notebook itself
{
SetFocus();
}
}
else
{
// it comes from our child, case (a), pass to the parent, but only
// if the direction is forwards. Otherwise set the focus to the
// notebook itself. The notebook is always the 'first' control of a
// page.
if (!isForward)
{
SetFocus();
}
else if (parent)
{
event.SetCurrentFocus(this);
parent->HandleWindowEvent(event);
}
}
}
}
// Methods for extensions of this class
void AppendMenuItem(wxMenu* menu, const wxString& title) {
GetTopBarItemsCtrl()->AppendMenuItem(menu, title);
}
void AppendMenuSeparaorItem() {
GetTopBarItemsCtrl()->AppendMenuSeparaorItem();
}
protected:
virtual void UpdateSelectedPage(size_t WXUNUSED(newsel)) override
{
// Nothing to do here, but must be overridden to avoid the assert in
// the base class version.
}
virtual wxBookCtrlEvent * CreatePageChangingEvent() const override
{
return new wxBookCtrlEvent(wxEVT_BOOKCTRL_PAGE_CHANGING,
GetId());
}
virtual void MakeChangedEvent(wxBookCtrlEvent & event) override
{
event.SetEventType(wxEVT_BOOKCTRL_PAGE_CHANGED);
}
virtual wxWindow * DoRemovePage(size_t page) override
{
wxWindow* const win = wxBookCtrlBase::DoRemovePage(page);
if (win)
{
GetTopBarItemsCtrl()->RemovePage(page);
DoSetSelectionAfterRemoval(page);
}
return win;
}
virtual void DoSize() override
{
wxWindow* const page = GetCurrentPage();
if (page)
page->SetSize(GetPageRect());
}
virtual void DoShowPage(wxWindow * page, bool show) override
{
if (show)
page->ShowWithEffect(m_showEffect, m_showTimeout);
else
page->HideWithEffect(m_hideEffect, m_hideTimeout);
}
private:
void Init()
{
// We don't need any border as we don't have anything to separate the
// page contents from.
SetInternalBorder(0);
// No effects by default.
m_showEffect =
m_hideEffect = wxSHOW_EFFECT_NONE;
m_showTimeout =
m_hideTimeout = 0;
}
wxShowEffect m_showEffect,
m_hideEffect;
unsigned m_showTimeout,
m_hideTimeout;
TopBarItemsCtrl* m_ctrl{ nullptr };
};
//#endif // _WIN32
#endif // slic3r_TopBar_hpp_

View File

@ -906,6 +906,8 @@ int ScalableButton::GetBitmapHeight()
void ScalableButton::sys_color_changed()
{
if (m_current_icon_name.empty())
return;
Slic3r::GUI::wxGetApp().UpdateDarkUI(this, m_has_border);
wxBitmapBundle bmp = *get_bmp_bundle(m_current_icon_name, m_bmp_width, m_bmp_height);