Merge branch main into feat/printer-agent-infra

This commit is contained in:
Ian Chua
2026-09-22 12:11:40 +08:00
361 changed files with 12492 additions and 1599 deletions
+175 -139
View File
@@ -56,6 +56,7 @@
#include "../Utils/PrintHost.hpp"
#include "GUI_App.hpp"
#include "Shortcuts.hpp"
#include "UnsavedChangesDialog.hpp"
#include "PublishSettingsDialog.hpp"
#include "MsgDialog.hpp"
@@ -310,17 +311,6 @@ static wxIcon main_frame_icon(GUI_App::EAppMode app_mode)
wxDEFINE_EVENT(EVT_SYNC_CLOUD_PRESET, SimpleEvent);
#ifdef __APPLE__
static const wxString ctrl = ("Ctrl+");
// FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent?
static const std::string ctrl_t = u8"\u2318+"; // "⌘" (Mac Command)
#else
static const wxString ctrl = _L("Ctrl+");
// FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent?
static const wxString ctrl_t = ctrl;
#endif
static const wxString shift = _L("Shift+");
MainFrame::MainFrame() :
DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_STYLE, "mainframe")
, m_printhost_queue_dlg(new PrintHostQueueDialog(this))
@@ -730,69 +720,8 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
}
return;}
#endif
// Orca: open the speed dial from any page with a bare Space. Only when no modifier is held (so
// editing shortcuts like Ctrl+Shift+Space in the canvas still reach it) and the focused window
// doesn't use Space to activate itself (buttons, checkboxes, list/choice controls, text fields),
// so a bare Space there still clicks/toggles instead of being hijacked. Gated by a preference
// (default on) so users can hand Space back to the focused control entirely.
if (wxGetApp().app_config->get_bool("enable_speed_dial") && !evt.CmdDown() && !evt.ShiftDown() &&
!evt.AltDown() && evt.GetKeyCode() == WXK_SPACE) {
if (focus_keeps_space(wxWindow::FindFocus())) {
evt.Skip(); // let the focused control keep Space
return;
}
// Defer out of the native key-event stack: open_speed_dial() may create a WebView and
// run script, the same window work the codebase avoids doing on native callbacks.
this->CallAfter([] { wxGetApp().open_speed_dial(); });
return;
}
if (evt.CmdDown() && evt.GetKeyCode() == 'R') { if (m_slice_enable) { wxGetApp().plater()->update(true, true); wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_PLATE)); this->m_tabpanel->SelectPageByName(TAB_ID_PREVIEW); } return; }
if (evt.CmdDown() && evt.ShiftDown() && evt.GetKeyCode() == 'G') {
m_plater->apply_background_progress();
m_print_enable = get_enable_print_status();
m_print_btn->Enable(m_print_enable);
if (m_print_enable) {
if (wxGetApp().preset_bundle->use_bbl_network() || wxGetApp().app_config->get_bool("use_printer_agents"))
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_PRINT_PLATE));
else
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SEND_GCODE));
}
if (!handle_global_shortcut(KeyChord::from_event(evt)))
evt.Skip();
return;
}
else if (evt.CmdDown() && evt.GetKeyCode() == 'G') { if (can_export_gcode()) { wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_EXPORT_SLICED_FILE)); } evt.Skip(); return; }
if (evt.CmdDown() && evt.GetKeyCode() == 'J') { m_printhost_queue_dlg->Show(); return; }
if (evt.CmdDown() && evt.GetKeyCode() == 'N') { m_plater->new_project(); return;}
if (evt.CmdDown() && evt.GetKeyCode() == 'O') { m_plater->load_project(); return;}
if (evt.CmdDown() && evt.ShiftDown() && evt.GetKeyCode() == 'S') { if (can_save_as()) m_plater->save_project(true); return;}
else if (evt.CmdDown() && evt.GetKeyCode() == 'S') { if (can_save()) m_plater->save_project(); return;}
if (evt.CmdDown() && evt.GetKeyCode() == 'F') {
if (m_plater && is_prepare_or_preview_tab()) {
m_plater->sidebar().can_search();
}
}
#ifdef __APPLE__
if (evt.CmdDown() && evt.GetKeyCode() == ',')
#else
if (evt.CmdDown() && evt.GetKeyCode() == 'P')
#endif
{
// Orca: Use GUI_App::open_preferences instead of direct call so windows associations are updated on exit
wxGetApp().open_preferences();
plater()->get_current_canvas3D()->force_set_focus();
return;
}
if (evt.CmdDown() && evt.GetKeyCode() == 'I' && !evt.ShiftDown()) {
if (!can_add_models()) return;
if (m_plater) { m_plater->add_file(); }
return;
}
if (evt.CmdDown() && evt.ShiftDown() && evt.GetKeyCode() == 'E') {
if (can_export_model()) publish_project();
return;
}
evt.Skip();
});
Bind(wxEVT_SHOW, [](wxShowEvent &evt) {
@@ -813,6 +742,96 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
bind_diff_dialog();
}
bool MainFrame::handle_global_shortcut(const KeyChord& chord)
{
const std::optional<Shortcut> shortcut = wxGetApp().shortcuts().lookup(ShortcutContext::Global, chord);
if (!shortcut.has_value())
return false;
switch (*shortcut) {
case Shortcut::SlicePlate:
if (m_slice_enable) {
wxGetApp().plater()->update(true, true);
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_PLATE));
m_tabpanel->SelectPageByName(TAB_ID_PREVIEW);
}
break;
case Shortcut::PrintPlate:
m_plater->apply_background_progress();
m_print_enable = get_enable_print_status();
m_print_btn->Enable(m_print_enable);
if (m_print_enable) {
if (wxGetApp().preset_bundle->use_bbl_network() || wxGetApp().app_config->get_bool("use_printer_agents"))
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_PRINT_PLATE));
else
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SEND_GCODE));
}
return false;
case Shortcut::ExportSlicedFile:
if (can_export_gcode())
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_EXPORT_SLICED_FILE));
return false;
case Shortcut::PrintHostQueue: m_printhost_queue_dlg->Show(); break;
case Shortcut::SpeedDial:
if (!wxGetApp().app_config->get_bool("enable_speed_dial") || (chord == KeyChord{ WXK_SPACE } && focus_keeps_space(wxWindow::FindFocus())))
return false;
// Deferred out of the native key-event stack: open_speed_dial() may create a WebView and run script.
CallAfter([] { wxGetApp().open_speed_dial(); });
break;
case Shortcut::NewProject: m_plater->new_project(); break;
case Shortcut::OpenProject: m_plater->load_project(); break;
case Shortcut::SaveProjectAs:
if (can_save_as())
m_plater->save_project(true);
break;
case Shortcut::SaveProject:
if (can_save())
m_plater->save_project();
break;
case Shortcut::Search:
if (m_plater && is_prepare_or_preview_tab())
m_plater->sidebar().can_search();
return false;
case Shortcut::Preferences:
// Orca: Use GUI_App::open_preferences instead of direct call so windows associations are updated on exit
wxGetApp().open_preferences();
plater()->get_current_canvas3D()->force_set_focus();
break;
case Shortcut::ImportModel:
if (can_add_models() && m_plater)
m_plater->add_file();
break;
case Shortcut::Publish3mf:
if (can_export_model())
publish_project();
break;
case Shortcut::ShowLabels:
if (m_plater && m_plater->is_view3D_shown()) {
m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown());
m_plater->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT));
}
break;
case Shortcut::ViewDefault:
if (m_plater) {
select_view("plate");
m_plater->get_current_canvas3D()->zoom_to_bed();
}
break;
case Shortcut::ViewTop: select_view("top"); break;
case Shortcut::ViewBottom: select_view("bottom"); break;
case Shortcut::ViewFront: select_view("front"); break;
case Shortcut::ViewRear: select_view("rear"); break;
case Shortcut::ViewLeft: select_view("left"); break;
case Shortcut::ViewRight: select_view("right"); break;
case Shortcut::ViewPlate:
if (m_plater)
m_plater->get_current_canvas3D()->select_plate();
break;
default: return false;
}
return true;
}
void MainFrame::bind_diff_dialog()
{
auto get_tab = [](Preset::Type type) {
@@ -2766,13 +2785,31 @@ static const wxString sep = " - ";
static const wxString sep = "\t";
#endif
static wxMenu* generate_help_menu()
wxString MainFrame::shortcut_label(const wxString& label, Shortcut shortcut, bool accelerator)
{
const ShortcutRegistry& shortcuts = wxGetApp().shortcuts();
if (accelerator) {
const std::string accel = shortcuts.accelerator(shortcut);
if (!accel.empty())
return label + " " + from_u8(accel);
}
const std::string text = shortcuts.display(shortcut);
return text.empty() ? label : label + sep + from_u8(text);
}
void MainFrame::update_shortcut_labels()
{
for (const ShortcutMenuItem& entry : m_shortcut_menu_items)
entry.item->SetItemLabel(shortcut_label(entry.label, entry.shortcut, entry.accelerator));
}
wxMenu* MainFrame::generate_help_menu()
{
wxMenu* helpMenu = new wxMenu();
// shortcut key
append_menu_item(helpMenu, wxID_ANY, _L("Keyboard Shortcuts") + sep + "&?", _L("Show the list of keyboard shortcuts"),
[](wxCommandEvent&) { wxGetApp().keyboard_shortcuts(); });
append_shortcut_item(helpMenu, Shortcut::KeyboardShortcuts, false, _L("Keyboard Shortcuts"), _L("Show the list of keyboard shortcuts"),
[](wxCommandEvent&) { wxGetApp().keyboard_shortcuts(ShortcutContext::Global); });
// Show Beginner's Tutorial
append_menu_item(helpMenu, wxID_ANY, _L("Setup Wizard"), _L("Setup Wizard"), [](wxCommandEvent &) {wxGetApp().ShowUserGuide();});
@@ -2854,29 +2891,28 @@ static void add_common_publish_menu_items(wxMenu* publish_menu, MainFrame* mainF
#endif
}
static void add_common_view_menu_items(wxMenu* view_menu, MainFrame* mainFrame, std::function<bool(void)> can_change_view)
void MainFrame::add_common_view_menu_items(wxMenu* view_menu, std::function<bool(void)> can_change_view)
{
// The camera control accelerators are captured by GLCanvas3D::on_char().
append_menu_item(view_menu, wxID_ANY, _L("Default View") + "\t" + ctrl + "0", _L("Default View"), [mainFrame](wxCommandEvent&) {
mainFrame->select_view("plate");
mainFrame->plater()->get_current_canvas3D()->zoom_to_bed();
append_shortcut_item(view_menu, Shortcut::ViewDefault, true, _L("Default View"), _L("Default View"), [this](wxCommandEvent&) {
select_view("plate");
plater()->get_current_canvas3D()->zoom_to_bed();
},
"", nullptr, [can_change_view]() { return can_change_view(); }, mainFrame);
"", nullptr, [can_change_view]() { return can_change_view(); }, this);
//view_menu->AppendSeparator();
//TRN To be shown in the main menu View->Top
append_menu_item(view_menu, wxID_ANY, _L_CONTEXT("Top", "Camera View") + "\t" + ctrl + "1", _L("Top View"), [mainFrame](wxCommandEvent&) { mainFrame->select_view("top"); },
"", nullptr, [can_change_view]() { return can_change_view(); }, mainFrame);
append_shortcut_item(view_menu, Shortcut::ViewTop, true, _L_CONTEXT("Top", "Camera View"), _L("Top View"), [this](wxCommandEvent&) { select_view("top"); },
"", nullptr, [can_change_view]() { return can_change_view(); }, this);
//TRN To be shown in the main menu View->Bottom
append_menu_item(view_menu, wxID_ANY, _L_CONTEXT("Bottom", "Camera View") + "\t" + ctrl + "2", _L("Bottom View"), [mainFrame](wxCommandEvent&) { mainFrame->select_view("bottom"); },
"", nullptr, [can_change_view]() { return can_change_view(); }, mainFrame);
append_menu_item(view_menu, wxID_ANY, _L_CONTEXT("Front", "Camera View") + "\t" + ctrl + "3", _L("Front View"), [mainFrame](wxCommandEvent&) { mainFrame->select_view("front"); },
"", nullptr, [can_change_view]() { return can_change_view(); }, mainFrame);
append_menu_item(view_menu, wxID_ANY, _L_CONTEXT("Rear", "Camera View") + "\t" + ctrl + "4", _L("Rear View"), [mainFrame](wxCommandEvent&) { mainFrame->select_view("rear"); },
"", nullptr, [can_change_view]() { return can_change_view(); }, mainFrame);
append_menu_item(view_menu, wxID_ANY, _L_CONTEXT("Left", "Camera View") + "\t" + ctrl + "5", _L("Left View"),[mainFrame](wxCommandEvent &) {mainFrame->select_view("left"); },
"", nullptr, [can_change_view]() { return can_change_view(); }, mainFrame);
append_menu_item(view_menu, wxID_ANY, _L_CONTEXT("Right", "Camera View") + "\t" + ctrl + "6", _L("Right View"),[mainFrame](wxCommandEvent &) { mainFrame->select_view("right"); },
"", nullptr, [can_change_view]() { return can_change_view(); }, mainFrame);
append_shortcut_item(view_menu, Shortcut::ViewBottom, true, _L_CONTEXT("Bottom", "Camera View"), _L("Bottom View"), [this](wxCommandEvent&) { select_view("bottom"); },
"", nullptr, [can_change_view]() { return can_change_view(); }, this);
append_shortcut_item(view_menu, Shortcut::ViewFront, true, _L_CONTEXT("Front", "Camera View"), _L("Front View"), [this](wxCommandEvent&) { select_view("front"); },
"", nullptr, [can_change_view]() { return can_change_view(); }, this);
append_shortcut_item(view_menu, Shortcut::ViewRear, true, _L_CONTEXT("Rear", "Camera View"), _L("Rear View"), [this](wxCommandEvent&) { select_view("rear"); },
"", nullptr, [can_change_view]() { return can_change_view(); }, this);
append_shortcut_item(view_menu, Shortcut::ViewLeft, true, _L_CONTEXT("Left", "Camera View"), _L("Left View"), [this](wxCommandEvent &) { select_view("left"); },
"", nullptr, [can_change_view]() { return can_change_view(); }, this);
append_shortcut_item(view_menu, Shortcut::ViewRight, true, _L_CONTEXT("Right", "Camera View"), _L("Right View"), [this](wxCommandEvent &) { select_view("right"); },
"", nullptr, [can_change_view]() { return can_change_view(); }, this);
}
void MainFrame::init_menubar_as_editor()
@@ -2895,17 +2931,17 @@ void MainFrame::init_menubar_as_editor()
[this] { return m_plater != nullptr && wxGetApp().app_config->get("app", "single_instance") == "false"; }, this);
#endif
// New Project
append_menu_item(fileMenu, wxID_ANY, _L("New Project") + "\t" + ctrl + "N", _L("Start a new project"),
append_shortcut_item(fileMenu, Shortcut::NewProject, true, _L("New Project"), _L("Start a new project"),
[this](wxCommandEvent&) { if (m_plater) m_plater->new_project(); }, "", nullptr,
[this](){return can_start_new_project(); }, this);
// Open Project
#ifndef __APPLE__
append_menu_item(fileMenu, wxID_ANY, _L("Open Project") + dots + "\t" + ctrl + "O", _L("Open a project file"),
append_shortcut_item(fileMenu, Shortcut::OpenProject, true, _L("Open Project") + dots, _L("Open a project file"),
[this](wxCommandEvent&) { if (m_plater) m_plater->load_project(); }, "menu_open", nullptr,
[this](){return can_open_project(); }, this);
#else
append_menu_item(fileMenu, wxID_ANY, _L("Open Project") + dots + "\t" + ctrl + "O", _L("Open a project file"),
append_shortcut_item(fileMenu, Shortcut::OpenProject, true, _L("Open Project") + dots, _L("Open a project file"),
[this](wxCommandEvent&) { if (m_plater) m_plater->load_project(); }, "", nullptr,
[this](){return can_open_project(); }, this);
#endif
@@ -2932,21 +2968,21 @@ void MainFrame::init_menubar_as_editor()
// BBS: close save project
#ifndef __APPLE__
append_menu_item(fileMenu, wxID_ANY, _L("Save Project") + "\t" + ctrl + "S", _L("Save current project to file"),
append_shortcut_item(fileMenu, Shortcut::SaveProject, true, _L("Save Project"), _L("Save current project to file"),
[this](wxCommandEvent&) { if (m_plater) m_plater->save_project(); }, "menu_save", nullptr,
[this](){return m_plater != nullptr && can_save(); }, this);
#else
append_menu_item(fileMenu, wxID_ANY, _L("Save Project") + "\t" + ctrl + "S", _L("Save current project to file"),
append_shortcut_item(fileMenu, Shortcut::SaveProject, true, _L("Save Project"), _L("Save current project to file"),
[this](wxCommandEvent&) { if (m_plater) m_plater->save_project(); }, "", nullptr,
[this](){return m_plater != nullptr && can_save(); }, this);
#endif
#ifndef __APPLE__
append_menu_item(fileMenu, wxID_ANY, _L("Save Project as") + dots + "\t" + ctrl + shift + "S", _L("Save current project as"),
append_shortcut_item(fileMenu, Shortcut::SaveProjectAs, true, _L("Save Project as") + dots, _L("Save current project as"),
[this](wxCommandEvent&) { if (m_plater) m_plater->save_project(true); }, "menu_save", nullptr,
[this](){return m_plater != nullptr && can_save_as(); }, this);
#else
append_menu_item(fileMenu, wxID_ANY, _L("Save Project as") + dots + "\t" + ctrl + shift + "S", _L("Save current project as"),
append_shortcut_item(fileMenu, Shortcut::SaveProjectAs, true, _L("Save Project as") + dots, _L("Save current project as"),
[this](wxCommandEvent&) { if (m_plater) m_plater->save_project(true); }, "", nullptr,
[this](){return m_plater != nullptr && can_save_as(); }, this);
#endif
@@ -2956,11 +2992,11 @@ void MainFrame::init_menubar_as_editor()
auto publish_handler = [this](wxCommandEvent&) { publish_project(); };
#ifndef __APPLE__
append_menu_item(fileMenu, wxID_ANY, _L("Publish 3MF") + dots + "\t" + ctrl + shift + "E", _L("Export a 3MF file with the selected settings embedded"),
append_shortcut_item(fileMenu, Shortcut::Publish3mf, true, _L("Publish 3MF") + dots, _L("Export a 3MF file with the selected settings embedded"),
publish_handler, "menu_publish", nullptr,
[this](){return can_export_model(); }, this);
#else
append_menu_item(fileMenu, wxID_ANY, _L("Publish 3MF") + dots + "\t" + ctrl + shift + "E", _L("Export a 3MF file with the selected settings embedded"),
append_shortcut_item(fileMenu, Shortcut::Publish3mf, true, _L("Publish 3MF") + dots, _L("Export a 3MF file with the selected settings embedded"),
publish_handler, "", nullptr,
[this](){return can_export_model(); }, this);
#endif
@@ -2971,13 +3007,13 @@ void MainFrame::init_menubar_as_editor()
// BBS
wxMenu *import_menu = new wxMenu();
#ifndef __APPLE__
append_menu_item(import_menu, wxID_ANY, _L("Import 3MF/STL/STEP/SVG/OBJ/AMF") + dots + "\t" + ctrl + "I", _L("Load a model"),
append_shortcut_item(import_menu, Shortcut::ImportModel, true, _L("Import 3MF/STL/STEP/SVG/OBJ/AMF") + dots, _L("Load a model"),
[this](wxCommandEvent&) { if (m_plater) {
m_plater->add_file();
} }, "menu_import", nullptr,
[this](){return can_add_models(); }, this);
#else
append_menu_item(import_menu, wxID_ANY, _L("Import 3MF/STL/STEP/SVG/OBJ/AMF") + dots + "\t" + ctrl + "I", _L("Load a model"),
append_shortcut_item(import_menu, Shortcut::ImportModel, true, _L("Import 3MF/STL/STEP/SVG/OBJ/AMF") + dots, _L("Load a model"),
[this](wxCommandEvent&) { if (m_plater) { m_plater->add_model(); } }, "", nullptr,
[this](){return can_add_models(); }, this);
#endif
@@ -3009,7 +3045,7 @@ void MainFrame::init_menubar_as_editor()
[this](wxCommandEvent&) { if (m_plater) m_plater->export_core_3mf(); }, "menu_export_sliced_file", nullptr,
[this](){return can_export_model(); }, this);
// BBS export .gcode.3mf
append_menu_item(export_menu, wxID_ANY, _L("Export plate sliced file") + dots + "\t" + ctrl + "G", _L("Export current sliced file"),
append_shortcut_item(export_menu, Shortcut::ExportSlicedFile, true, _L("Export plate sliced file") + dots, _L("Export current sliced file"),
[this](wxCommandEvent&) { if (m_plater) wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_EXPORT_SLICED_FILE)); }, "menu_export_sliced_file", nullptr,
[this](){return can_export_gcode(); }, this);
@@ -3059,37 +3095,37 @@ void MainFrame::init_menubar_as_editor()
};
#ifndef __APPLE__
// BBS undo
append_menu_item(editMenu, wxID_ANY, _L("Undo") + "\t" + ctrl + "Z",
append_shortcut_item(editMenu, Shortcut::Undo, true, _L("Undo"),
_L("Undo"), [this](wxCommandEvent&) { m_plater->undo(); },
"menu_undo", nullptr, [this](){return m_plater->can_undo(); }, this);
// BBS redo
append_menu_item(editMenu, wxID_ANY, _L("Redo") + "\t" + ctrl + "Y",
append_shortcut_item(editMenu, Shortcut::Redo, true, _L("Redo"),
_L("Redo"), [this](wxCommandEvent&) { m_plater->redo(); },
"menu_redo", nullptr, [this](){return m_plater->can_redo(); }, this);
editMenu->AppendSeparator();
// BBS Cut TODO
append_menu_item(editMenu, wxID_ANY, _L("Cut") + "\t" + ctrl + "X",
append_shortcut_item(editMenu, Shortcut::Cut, true, _L("Cut"),
_L("Cut selection to clipboard"), [this](wxCommandEvent&) {m_plater->cut_selection_to_clipboard(); },
"menu_cut", nullptr, [this]() {return m_plater->can_copy_to_clipboard(); }, this);
// BBS Copy
append_menu_item(editMenu, wxID_ANY, _L("Copy") + "\t" + ctrl + "C",
append_shortcut_item(editMenu, Shortcut::Copy, true, _L("Copy"),
_L("Copy selection to clipboard"), [this](wxCommandEvent&) { m_plater->copy_selection_to_clipboard(); },
"menu_copy", nullptr, [this](){return m_plater->can_copy_to_clipboard(); }, this);
// BBS Paste
append_menu_item(editMenu, wxID_ANY, _L("Paste") + "\t" + ctrl + "V",
append_shortcut_item(editMenu, Shortcut::Paste, true, _L("Paste"),
_L("Paste clipboard"), [this](wxCommandEvent&) { m_plater->paste_from_clipboard(); },
"menu_paste", nullptr, [this](){return m_plater->can_paste_from_clipboard(); }, this);
// BBS Delete selected
append_menu_item(editMenu, wxID_ANY, _L("Delete Selected") + "\t" + _L_CONTEXT("Del", "Keyboard Shortcut"),
append_shortcut_item(editMenu, Shortcut::DeleteSelected, true, _L("Delete Selected"),
_L("Deletes the current selection"),[this](wxCommandEvent&) { m_plater->remove_selected(); },
"menu_remove", nullptr, [this](){return can_delete(); }, this);
//BBS: delete all
append_menu_item(editMenu, wxID_ANY, _L("Delete All") + "\t" + ctrl + "D",
append_shortcut_item(editMenu, Shortcut::DeleteAll, true, _L("Delete All"),
_L("Deletes all objects"),[this](wxCommandEvent&) { m_plater->delete_all_objects_from_model(); },
"menu_remove", nullptr, [this](){return can_delete_all(); }, this);
editMenu->AppendSeparator();
// BBS Clone Selected
append_menu_item(editMenu, wxID_ANY, _L("Clone Selected") /*+ "\t" + ctrl + "M"*/,
append_shortcut_item(editMenu, Shortcut::CloneSelected, true, _L("Clone Selected"),
_L("Clone copies of selections"),[this](wxCommandEvent&) {
m_plater->clone_selection();
},
@@ -3103,7 +3139,7 @@ void MainFrame::init_menubar_as_editor()
editMenu->AppendSeparator();
#else
// BBS undo
append_menu_item(editMenu, wxID_ANY, _L("Undo") + sep + ctrl_t + "Z",
append_shortcut_item(editMenu, Shortcut::Undo, false, _L("Undo"),
_L("Undo"), [this, handle_key_event](wxCommandEvent&) {
wxKeyEvent e;
e.SetEventType(wxEVT_KEY_DOWN);
@@ -3115,7 +3151,7 @@ void MainFrame::init_menubar_as_editor()
m_plater->undo(); },
"", nullptr, [this](){return m_plater->can_undo(); }, this);
// BBS redo
append_menu_item(editMenu, wxID_ANY, _L("Redo") + sep + ctrl_t + "Y",
append_shortcut_item(editMenu, Shortcut::Redo, false, _L("Redo"),
_L("Redo"), [this, handle_key_event](wxCommandEvent&) {
wxKeyEvent e;
e.SetEventType(wxEVT_KEY_DOWN);
@@ -3128,7 +3164,7 @@ void MainFrame::init_menubar_as_editor()
"", nullptr, [this](){return m_plater->can_redo(); }, this);
editMenu->AppendSeparator();
// BBS Cut TODO
append_menu_item(editMenu, wxID_ANY, _L("Cut") + sep + ctrl_t + "X",
append_shortcut_item(editMenu, Shortcut::Cut, false, _L("Cut"),
_L("Cut selection to clipboard"), [this, handle_key_event](wxCommandEvent&) {
wxKeyEvent e;
e.SetEventType(wxEVT_KEY_DOWN);
@@ -3140,7 +3176,7 @@ void MainFrame::init_menubar_as_editor()
m_plater->cut_selection_to_clipboard(); },
"", nullptr, [this]() {return m_plater->can_copy_to_clipboard(); }, this);
// BBS Copy
append_menu_item(editMenu, wxID_ANY, _L("Copy") + sep + ctrl_t + "C",
append_shortcut_item(editMenu, Shortcut::Copy, false, _L("Copy"),
_L("Copy selection to clipboard"), [this, handle_key_event](wxCommandEvent&) {
wxKeyEvent e;
e.SetEventType(wxEVT_KEY_DOWN);
@@ -3152,7 +3188,7 @@ void MainFrame::init_menubar_as_editor()
m_plater->copy_selection_to_clipboard(); },
"", nullptr, [this](){return m_plater->can_copy_to_clipboard(); }, this);
// BBS Paste
append_menu_item(editMenu, wxID_ANY, _L("Paste") + sep + ctrl_t + "V",
append_shortcut_item(editMenu, Shortcut::Paste, false, _L("Paste"),
_L("Paste clipboard"), [this, handle_key_event](wxCommandEvent&) {
wxKeyEvent e;
e.SetEventType(wxEVT_KEY_DOWN);
@@ -3165,14 +3201,14 @@ void MainFrame::init_menubar_as_editor()
"", nullptr, [this](){return m_plater->can_paste_from_clipboard(); }, this);
#if 0
// BBS Delete selected
append_menu_item(editMenu, wxID_ANY, _L("Delete Selected") + "\t" + _L_CONTEXT("Backspace", "Keyboard Shortcut"),
append_shortcut_item(editMenu, Shortcut::DeleteSelected, true, _L("Delete Selected"),
_L("Deletes the current selection"),[this](wxCommandEvent&) {
m_plater->remove_selected();
},
"", nullptr, [this](){return can_delete(); }, this);
#endif
//BBS: delete all
append_menu_item(editMenu, wxID_ANY, _L("Delete All") + "\t" + ctrl + "D",
append_shortcut_item(editMenu, Shortcut::DeleteAll, true, _L("Delete All"),
_L("Deletes all objects"),[this, handle_key_event](wxCommandEvent&) {
wxKeyEvent e;
e.SetEventType(wxEVT_KEY_DOWN);
@@ -3185,7 +3221,7 @@ void MainFrame::init_menubar_as_editor()
"", nullptr, [this](){return can_delete_all(); }, this);
editMenu->AppendSeparator();
// BBS Clone Selected
append_menu_item(editMenu, wxID_ANY, _L("Clone Selected") + "\t" + ctrl + "K",
append_shortcut_item(editMenu, Shortcut::CloneSelected, true, _L("Clone Selected"),
_L("Clone copies of selections"),[this, handle_key_event](wxCommandEvent&) {
wxKeyEvent e;
e.SetEventType(wxEVT_KEY_DOWN);
@@ -3208,7 +3244,7 @@ void MainFrame::init_menubar_as_editor()
#endif
// BBS Select All
append_menu_item(editMenu, wxID_ANY, _L("Select All") + sep + ctrl_t + "A",
append_shortcut_item(editMenu, Shortcut::SelectAll, false, _L("Select All"),
_L("Selects all objects"), [this, handle_key_event](wxCommandEvent&) {
wxKeyEvent e;
e.SetEventType(wxEVT_KEY_DOWN);
@@ -3260,7 +3296,7 @@ void MainFrame::init_menubar_as_editor()
wxMenu* viewMenu = nullptr;
if (m_plater) {
viewMenu = new wxMenu();
add_common_view_menu_items(viewMenu, this, std::bind(&MainFrame::can_change_view, this));
add_common_view_menu_items(viewMenu, std::bind(&MainFrame::can_change_view, this));
viewMenu->AppendSeparator();
//BBS perspective view
@@ -3291,13 +3327,14 @@ void MainFrame::init_menubar_as_editor()
[]() { return wxGetApp().app_config->get_bool("auto_perspective"); }, this);
viewMenu->AppendSeparator();
append_menu_check_item(viewMenu, wxID_ANY, _L("Show &G-code Window") + sep + "C", _L("Show G-code window in Preview scene."),
wxMenuItem* gcode_window = append_menu_check_item(viewMenu, wxID_ANY, shortcut_label(_L("Show &G-code Window"), Shortcut::ToggleGcodeWindow, true), _L("Show G-code window in Preview scene."),
[this](wxCommandEvent &) {
wxGetApp().toggle_show_gcode_window();
m_plater->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT));
},
this, [this]() { return m_tabpanel->GetSelectedPageName() == TAB_ID_PREVIEW; },
[]() { return wxGetApp().show_gcode_window(); }, this);
m_shortcut_menu_items.push_back({ gcode_window, Shortcut::ToggleGcodeWindow, _L("Show &G-code Window"), true });
append_menu_check_item(
viewMenu, wxID_ANY, _L("Show 3D Navigator"), _L("Show 3D navigator in Prepare and Preview scene."),
@@ -3325,9 +3362,10 @@ void MainFrame::init_menubar_as_editor()
this);
viewMenu->AppendSeparator();
append_menu_check_item(viewMenu, wxID_ANY, _L("Show &Labels") + "\t" + ctrl + "E", _L("Show object labels in 3D scene."),
wxMenuItem* show_labels = append_menu_check_item(viewMenu, wxID_ANY, shortcut_label(_L("Show &Labels"), Shortcut::ShowLabels, true), _L("Show object labels in 3D scene."),
[this](wxCommandEvent&) { m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown()); m_plater->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT)); }, this,
[this]() { return m_plater->is_view3D_shown(); }, [this]() { return m_plater->are_view3D_labels_shown(); }, this);
m_shortcut_menu_items.push_back({ show_labels, Shortcut::ShowLabels, _L("Show &Labels"), true });
append_menu_check_item(viewMenu, wxID_ANY, _L("Show &Overhang"), _L("Show object overhang highlight in 3D scene."),
[this](wxCommandEvent &) {
@@ -3372,8 +3410,6 @@ void MainFrame::init_menubar_as_editor()
//auto preference_item = new wxMenuItem(parent_menu, OrcaSlicerMenuPreferences + bambu_studio_id_base, _L("Preferences") + "\t" + ctrl + ",", "");
#else
wxMenu* parent_menu = m_topbar->GetTopMenu();
auto preference_item = new wxMenuItem(parent_menu, ConfigMenuPreferences + config_id_base, _L("Preferences") + "\t" + ctrl + "P", "");
#endif
#ifdef __APPLE__
@@ -3382,15 +3418,15 @@ void MainFrame::init_menubar_as_editor()
parent_menu, wxID_ANY, _L(about_title), "",
[](wxCommandEvent &) { Slic3r::GUI::about();},
"", nullptr, []() { return true; }, this, 0);
append_menu_item(
parent_menu, wxID_ANY, _L("Preferences") + "\t" + ctrl + ",", "",
append_shortcut_item(
parent_menu, Shortcut::Preferences, true, _L("Preferences"), "",
[](wxCommandEvent &) {
wxGetApp().open_preferences();
},
"", nullptr, []() { return true; }, this, 1);
parent_menu->AppendSeparator();
append_menu_item(
parent_menu, wxID_ANY, _L("Open speed dial...") + sep + "Space", "",
append_shortcut_item(
parent_menu, Shortcut::SpeedDial, false, _L("Open speed dial..."), "",
[](wxCommandEvent &) { wxGetApp().open_speed_dial(); },
"", nullptr, []() { return true; }, this);
//parent_menu->Insert(1, preference_item);
@@ -3406,8 +3442,8 @@ void MainFrame::init_menubar_as_editor()
m_topbar->AddDropDownSubMenu(viewMenu, _L("View"));
//BBS add Preference
append_menu_item(
m_topbar->GetTopMenu(), wxID_ANY, _L("Preferences") + "\t" + ctrl + "P", "",
append_shortcut_item(
m_topbar->GetTopMenu(), Shortcut::Preferences, true, _L("Preferences"), "",
[](wxCommandEvent &) {
// Orca: Use GUI_App::open_preferences instead of direct call so windows associations are updated on exit
wxGetApp().open_preferences();
@@ -3417,8 +3453,8 @@ void MainFrame::init_menubar_as_editor()
auto top_menu = m_topbar->GetTopMenu();
top_menu->AppendSeparator();
append_menu_item(
top_menu, wxID_ANY, _L("Open speed dial...") + "\t" + "Space", "",
append_shortcut_item(
top_menu, Shortcut::SpeedDial, false, _L("Open speed dial..."), "",
[](wxCommandEvent &) { wxGetApp().open_speed_dial(); },
"", nullptr, []() { return true; }, this);
top_menu->AppendSeparator();
@@ -3524,8 +3560,8 @@ void MainFrame::init_menubar_as_editor()
#else
// On Mac, the Apple menu ignores non-standard custom items, so add Preset Bundle to the File menu
fileMenu->AppendSeparator();
append_menu_item(
fileMenu, wxID_ANY, _L("Open speed dial...") + sep + "Space", "",
append_shortcut_item(
fileMenu, Shortcut::SpeedDial, false, _L("Open speed dial..."), "",
[](wxCommandEvent&) { wxGetApp().open_speed_dial(); },
"", nullptr, []() { return true; }, this);
append_menu_item(
@@ -3728,7 +3764,7 @@ void MainFrame::init_menubar_as_gcodeviewer()
wxMenu* viewMenu = nullptr;
if (m_plater != nullptr) {
viewMenu = new wxMenu();
add_common_view_menu_items(viewMenu, this, std::bind(&MainFrame::can_change_view, this));
add_common_view_menu_items(viewMenu, std::bind(&MainFrame::can_change_view, this));
}
// helpmenu