OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::GUI::ActionRegistry Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/slic3r/GUI/ActionRegistry.hpp>

Collaboration diagram for Slic3r::GUI::ActionRegistry:

Public Member Functions

 ~ActionRegistry ()
void init ()
void relocalize_builtins ()
void upsert (std::unique_ptr< AppAction > action)
void remove (const std::string &id)
const AppAction * by_id (const std::string &id) const
AppActionRunResult run (const std::string &id, const std::string &param={})
bool set_favourite (const std::string &id, bool on)
void reorder_favourites (const std::vector< std::string > &ids)
std::vector< std::string > favourite_ids () const
bool should_ask (const std::string &id) const
void suppress_ask (const std::string &id)
bool tooltip_expanded () const
void set_tooltip_expanded (bool expanded)
nlohmann::json snapshot ()
nlohmann::json tab_options () const

Static Public Attributes

static constexpr size_t kFavLimit = 10

Private Member Functions

void seed_state (AppAction &a) const
AppAction * find (const std::string &id)
void load_persisted (nlohmann::json &stats, std::vector< std::string > &favs) const
void materialize_setting_actions ()
void materialize_plate_actions ()
void materialize_recent_project_actions ()
void refresh_source (const std::string &plugin_key, ActionChange change)
void refresh_capability (const std::string &plugin_key, const std::string &capability, ActionChange change)
void refresh_page_capability (const std::string &plugin_key, const std::string &capability, ActionChange change)

Private Attributes

bool m_started = false
std::unordered_map< std::string, std::shared_ptr< AppAction > > m_actions

Detailed Description

Constructor & Destructor Documentation

◆ ~ActionRegistry()

Slic3r::GUI::ActionRegistry::~ActionRegistry ( )
default

Member Function Documentation

◆ by_id()

const AppAction * Slic3r::GUI::ActionRegistry::by_id ( const std::string & id) const
682{
683 assert(wxThread::IsMain());
684 auto it = m_actions.find(id);
685 return it == m_actions.end() ? nullptr : it->second.get();
686}
std::unordered_map< std::string, std::shared_ptr< AppAction > > m_actions
Definition ActionRegistry.hpp:258

References m_actions.

Referenced by find(), and Slic3r::GUI::SpeedDialWebDialog::run_action().

Here is the caller graph for this function:

◆ favourite_ids()

std::vector< std::string > Slic3r::GUI::ActionRegistry::favourite_ids ( ) const
743{
744 assert(wxThread::IsMain());
745 // Enforce the cap + dedupe on read so the persisted order can never grow past kFavLimit, even from an older config.
746 return cap_favourites(read_string_array("favourite_actions"), kFavLimit);
747}
static constexpr size_t kFavLimit
Definition ActionRegistry.hpp:195
std::vector< std::string > read_string_array(const char *key)
Definition ActionRegistry.cpp:75
std::vector< std::string > cap_favourites(const std::vector< std::string > &ids, size_t limit)
Definition ActionRegistry.cpp:47

References Slic3r::GUI::cap_favourites(), and kFavLimit.

Referenced by load_persisted(), seed_state(), set_favourite(), and snapshot().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ find()

AppAction * Slic3r::GUI::ActionRegistry::find ( const std::string & id)
private
688{ return const_cast<AppAction*>(by_id(id)); }
const AppAction * by_id(const std::string &id) const
Definition ActionRegistry.cpp:681

References by_id().

Referenced by run(), and set_favourite().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ init()

void Slic3r::GUI::ActionRegistry::init ( )
470{
471 assert(wxThread::IsMain());
472 assert(!m_started);
473 m_started = true;
474
475 PluginManager& manager = PluginManager::instance();
476
477 auto on_source = [this](const std::string& plugin_key, ActionChange change) {
478 if (!wxTheApp || wxGetApp().is_closing())
479 return;
480 wxGetApp().CallAfter([this, plugin_key, change] {
481 if (!wxGetApp().is_closing())
482 this->refresh_source(plugin_key, change);
483 });
484 };
485 auto on_capability = [this](const PluginCapabilityId& capability, ActionChange change) {
486 if (capability.type != PluginCapabilityType::Script && capability.type != PluginCapabilityType::Pages)
487 return;
488 if (!wxTheApp || wxGetApp().is_closing())
489 return;
490 const PluginCapabilityType type = capability.type;
491 const std::string plugin_key = capability.plugin_key;
492 const std::string name = capability.name;
493 wxGetApp().CallAfter([this, type, plugin_key, name, change] {
494 if (wxGetApp().is_closing())
495 return;
497 this->refresh_capability(plugin_key, name, change);
498 else
499 this->refresh_page_capability(plugin_key, name, change);
500 });
501 };
502
503 // Subscribe before enumerating so a concurrent load cannot land between the initial
504 // snapshot and callback registration. Duplicate notifications are safe: upsert is by
505 // id and the m_actions scan in refresh_source is idempotent.
506 manager.subscribe_on_load_callback([on_source](const std::string& key) { on_source(key, ActionChange::Added); });
507 manager.subscribe_on_unload_callback([on_source](const std::string& key) { on_source(key, ActionChange::Removed); });
508 manager.subscribe_on_capability_load_callback(
509 [on_capability](const PluginCapabilityId& capability) { on_capability(capability, ActionChange::Added); });
510 manager.subscribe_on_capability_unload_callback(
511 [on_capability](const PluginCapabilityId& capability) { on_capability(capability, ActionChange::Removed); });
512
513 // enumerate current script capabilities
514 std::unordered_map<std::string, std::string> source_names;
515 for (const PluginDescriptor& desc : manager.get_plugin_descriptors())
516 if (!desc.name.empty())
517 source_names.emplace(desc.plugin_key, desc.name);
518
519 for (const auto& capability : manager.get_plugin_capabilities("", PluginCapabilityType::Script)) {
520 if (!capability)
521 continue;
522 const std::string& key = capability->audit_plugin_key();
523 auto it = source_names.find(key);
524 const std::string& source_name = it == source_names.end() ? key : it->second;
525 if (auto action = make_action(key, capability->name(), source_name))
526 upsert(std::move(action));
527 }
528
529 for (const auto& capability : manager.get_plugin_capabilities("", PluginCapabilityType::Pages)) {
530 if (!capability)
531 continue;
532 const std::string& key = capability->audit_plugin_key();
533 auto it = source_names.find(key);
534 const std::string& source_name = it == source_names.end() ? key : it->second;
535 if (auto action = make_page_action(key, capability->name(), source_name))
536 upsert(std::move(action));
537 }
538
539 // Built-in palette commands (Save/Load, Preferences, Mode switch, Slice/Preview, Go to layer).
540 // Register after plugins so the plugin ids win on any (unlikely) id collision - ids are distinct
541 // by prefix, so this is order-independent. The catalog (and its thin AppAction adapter) lives in
542 // NativeCommands; the registry only stores and dispatches the result.
543 for (const NativeCommand& c : NativeCommands::catalog())
545}
void refresh_capability(const std::string &plugin_key, const std::string &capability, ActionChange change)
Definition ActionRegistry.cpp:601
void refresh_page_capability(const std::string &plugin_key, const std::string &capability, ActionChange change)
Definition ActionRegistry.cpp:618
void refresh_source(const std::string &plugin_key, ActionChange change)
Definition ActionRegistry.cpp:568
bool m_started
Definition ActionRegistry.hpp:257
void upsert(std::unique_ptr< AppAction > action)
Definition ActionRegistry.cpp:635
static PluginManager & instance()
Definition PluginManager.cpp:74
std::unique_ptr< AppAction > make_action(const NativeCommand &command)
Definition NativeCommands.cpp:663
const std::vector< NativeCommand > & catalog()
Definition NativeCommands.cpp:657
std::unique_ptr< AppAction > make_action(const std::string &plugin_key, const std::string &capability, const std::string &source_name)
Definition ActionRegistry.cpp:204
std::unique_ptr< AppAction > make_page_action(const std::string &plugin_key, const std::string &capability, const std::string &source_name)
Definition ActionRegistry.cpp:254
ActionChange
Definition ActionRegistry.hpp:22
@ Removed
Definition ActionRegistry.hpp:22
@ Added
Definition ActionRegistry.hpp:22
PluginCapabilityType
Definition PythonPluginInterface.hpp:17
@ Pages
Definition PythonPluginInterface.hpp:17
@ Script
Definition PythonPluginInterface.hpp:17

References Slic3r::GUI::Added, Slic3r::GUI::NativeCommands::catalog(), Slic3r::PluginManager::get_plugin_capabilities(), Slic3r::PluginManager::get_plugin_descriptors(), Slic3r::PluginManager::instance(), m_started, Slic3r::GUI::NativeCommands::make_action(), Slic3r::PluginCapabilityId::name, Slic3r::Pages, Slic3r::PluginCapabilityId::plugin_key, refresh_capability(), refresh_page_capability(), refresh_source(), Slic3r::GUI::Removed, Slic3r::Script, Slic3r::PluginManager::subscribe_on_capability_load_callback(), Slic3r::PluginManager::subscribe_on_capability_unload_callback(), Slic3r::PluginManager::subscribe_on_load_callback(), Slic3r::PluginManager::subscribe_on_unload_callback(), Slic3r::PluginCapabilityId::type, and upsert().

Here is the call graph for this function:

◆ load_persisted()

void Slic3r::GUI::ActionRegistry::load_persisted ( nlohmann::json & stats,
std::vector< std::string > & favs ) const
private
672{
673 stats = read_section("stats", nlohmann::json::object());
674 if (!stats.is_object())
675 stats = nlohmann::json::object();
676 favs = favourite_ids();
677}
std::vector< std::string > favourite_ids() const
Definition ActionRegistry.cpp:742
nlohmann::json read_section(const char *key, nlohmann::json fallback)
Definition ActionRegistry.cpp:70

References favourite_ids().

Referenced by materialize_plate_actions(), materialize_recent_project_actions(), and materialize_setting_actions().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ materialize_plate_actions()

void Slic3r::GUI::ActionRegistry::materialize_plate_actions ( )
private
842{
843 assert(wxThread::IsMain());
844
845 // Plates are a filament (FFF) feature: SLA has a single plate and no plate UI, and gcode-only
846 // mode has no editable project - so no "Go to Plate N" actions are offered there.
847 Plater* plater = wxTheApp ? wxGetApp().plater() : nullptr;
849 // Drop any stale plate actions (e.g. the printer technology switched to SLA).
850 drop_stale(m_actions, kPlateGotoPrefix, {});
851 return;
852 }
853
854 // Persisted per-action state, read ONCE (mirrors materialize_setting_actions) so a relisted
855 // "Go to Plate N" keeps its recency/favourite when the plate is renamed - the id is index-keyed.
856 nlohmann::json stats;
857 std::vector<std::string> favs;
858 load_persisted(stats, favs);
859
860 const std::vector<PartPlate*>& list = plater->get_partplate_list().get_plate_list();
861 std::unordered_set<std::string> seen;
862 for (size_t i = 0; i < list.size(); ++i) {
863 PartPlate* plate = list[i];
864 if (!plate)
865 continue;
866 const std::string id = PlateAction::id_for(int(i));
867 seen.insert(id);
868
869 // "Go to Plate N" + " (name)" when the plate is named, matching the object-list label.
870 const char* go_to_plate = L("Go to Plate");
871 std::string suffix = " " + std::to_string(i + 1);
872 const std::string name = plate->get_plate_name();
873 if (!name.empty())
874 suffix += " (" + name + ")";
875
876 auto action = std::make_unique<PlateAction>(int(i), I18N::translate_utf8(go_to_plate) + suffix, kOrcaSourceName);
877 action->title_en = go_to_plate + suffix;
878 seed_from(stats, favs, id, *action);
879 auto const action_id = action->id();
880 auto const app_action = std::shared_ptr<AppAction>(std::move(action));
881 m_actions.insert_or_assign(action_id, app_action);
882 }
883
884 // Drop plate actions whose index no longer exists (a plate was deleted / moved to the front).
885 drop_stale(m_actions, kPlateGotoPrefix, seen);
886}
#define L(s)
Definition ExtrusionEntity.cpp:25
void load_persisted(nlohmann::json &stats, std::vector< std::string > &favs) const
Definition ActionRegistry.cpp:671
std::vector< PartPlate * > & get_plate_list()
Definition PartPlate.hpp:965
PartPlateList & get_partplate_list()
Definition Plater.cpp:22578
PrinterTechnology printer_technology() const
Definition Plater.cpp:22155
bool only_gcode_mode()
Definition Plater.hpp:419
std::string translate_utf8(const char *s)
Definition I18N.hpp:59
void seed_from(const nlohmann::json &stats, const std::vector< std::string > &favs, const std::string &id, AppAction &a)
Definition ActionRegistry.cpp:370
void drop_stale(std::unordered_map< std::string, std::shared_ptr< AppAction > > &actions, const char *prefix, const std::unordered_set< std::string > &seen)
Definition ActionRegistry.cpp:380
static Plater * plater()
Definition GUI_Factories.cpp:400
@ Plater
Definition Shortcuts.hpp:21
constexpr const char * kOrcaSourceName
Definition ActionRegistry.hpp:136
@ ptFFF
Definition Config.hpp:231

References Slic3r::GUI::PartPlate::get_plate_name(), Slic3r::GUI::kOrcaSourceName, L, load_persisted(), m_actions, Slic3r::GUI::plater(), Slic3r::ptFFF, and Slic3r::GUI::I18N::translate_utf8().

Referenced by snapshot().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ materialize_recent_project_actions()

void Slic3r::GUI::ActionRegistry::materialize_recent_project_actions ( )
private
889{
890 assert(wxThread::IsMain());
891
892 // Persisted per-action state, read ONCE (mirrors materialize_plate_actions) so a relisted recent
893 // project keeps its recency/favourite when the recents list reorders - the id is path-keyed.
894 nlohmann::json stats;
895 std::vector<std::string> favs;
896 load_persisted(stats, favs);
897
898 // app_config stores recents oldest-first; the palette shows newest-first.
899 std::vector<std::string> recents = wxGetApp().app_config->get_recent_projects();
900 std::reverse(recents.begin(), recents.end());
901
902 std::unordered_set<std::string> seen;
903 for (const std::string& path : recents) {
904 // Skip projects whose file is gone; the stale id is dropped below.
905 boost::system::error_code ec;
906 if (path.empty() || !boost::filesystem::exists(boost::filesystem::path(path), ec))
907 continue;
908
909 const std::string id = RecentProjectAction::id_for(path);
910 seen.insert(id);
911
912 // Title = file basename; source/eyebrow = the full path so search can match either.
913 boost::filesystem::path p(path);
914 std::string title = p.filename().string();
915 if (title.empty())
916 title = path;
917
918 auto action = std::make_unique<RecentProjectAction>(path, std::move(title), path);
919 seed_from(stats, favs, id, *action);
920 auto const action_id = action->id();
921 auto const app_action = std::shared_ptr<AppAction>(std::move(action));
922 m_actions.insert_or_assign(action_id, app_action);
923 }
924
925 // Drop recent-project actions whose file no longer exists / was removed from the recents list.
926 drop_stale(m_actions, kRecentProjectPrefix, seen);
927}

References load_persisted(), and m_actions.

Referenced by snapshot().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ materialize_setting_actions()

void Slic3r::GUI::ActionRegistry::materialize_setting_actions ( )
private
768{
769 assert(wxThread::IsMain());
770
771 // Reuse the Sidebar's live settings index: it's the only catalog whose group/category map is
772 // populated (Tab::add_key feeds it at build time), and it already mirrors the current
773 // configs/printer-technology. Use the all-modes view so the Speed Dial lists every setting,
774 // including those above the user's current mode, and can prompt to switch before jumping.
775 const std::vector<Search::Option>& options = wxGetApp().sidebar().settings_index().all_options();
776
777 // Load the persisted per-action state ONCE (not per-option) so a re-materialised setting keeps
778 // its recency/favourite; mirroring seed_state but amortised over the whole option set.
779 nlohmann::json stats;
780 std::vector<std::string> favs;
781 load_persisted(stats, favs);
782
783 std::unordered_set<std::string> seen;
784 for (const Search::Option& opt : options) {
785 // The row's live state drives both the hidden filter and the title (labels can change at
786 // runtime, e.g. brim_width -> "Brim ear radius"). Hidden rows are skipped, not marked seen.
787 Tab* tab = wxGetApp().get_tab(opt.type);
788 Tab::SettingRowState row;
789 if (tab)
790 row = tab->setting_row_state(opt.opt_key());
791 if (!row.visible)
792 continue;
793
794 const std::string id = SettingAction::id_for(opt.opt_key(), opt.type);
795 seen.insert(id);
796
797 // The localized text the page shows, and its English search aliases from the untranslated row
798 // label, def name and breadcrumb.
799 const char* type_context = setting_type_context(opt.type);
800 SettingText local = setting_text(opt.label_local.empty() ? opt.label : opt.label_local, opt.display_label, row.label, row.multi,
801 I18N::translate_utf8(type_context), opt.category_local, opt.group_local);
802 SettingText english = setting_text(opt.label, opt.display_label_en, row.label_en, row.multi, type_context,
803 Tab::translate_category(opt.category, opt.type, false).ToStdWstring(), opt.group);
804
805 // group stays empty so the source path is the single display/search breadcrumb rather than
806 // being duplicated.
807 auto action = std::make_unique<SettingAction>(opt.opt_key(), opt.type, local.title, std::string(), opt.category, local.source,
808 opt.mode);
809 action->full_label = std::move(local.full_label);
810 action->title_en = std::move(english.title);
811 action->full_label_en = std::move(english.full_label);
812 action->source_en = std::move(english.source);
813
814 // Tile pictogram = the icon of the setting's own group header (e.g. Advanced -> param_advanced),
815 // the one shown next to it in the page. Fall back to the page/category icon for groups
816 // without one. Keys are the English titles the GUI registers.
817 action->icon = opt.group_icon;
818 if (action->icon.empty() && !opt.category.empty() && tab) {
819 const auto& icons = tab->get_category_icon_map();
820 auto it = icons.find(wxString(opt.category));
821 if (it != icons.end())
822 action->icon = it->second;
823 }
824
825 // Footer description + wiki affordance; only settings whose row declared a wiki path have one.
826 action->tooltip = opt.tooltip;
827 if (!opt.wiki_path.empty())
828 action->help_url = into_u8(OptionsGroup::get_url(opt.wiki_path));
829
830 seed_from(stats, favs, id, *action);
831 auto const action_id = action->id();
832 auto const app_action = std::shared_ptr<AppAction>(std::move(action));
833 m_actions.insert_or_assign(action_id, app_action);
834 }
835
836 // Drop SettingActions whose option no longer exists in the current configs (e.g. the printer
837 // technology / UI mode changed). Non-setting actions are untouched.
838 drop_stale(m_actions, kSettingPrefix, seen);
839}
static wxString get_url(const std::string &path_end)
Definition OptionsGroup.cpp:1404
static wxString translate_category(const wxString &title, Preset::Type preset_type, bool translate=true)
Definition Tab.cpp:823
const char * setting_type_context(Preset::Type type)
Definition ActionRegistry.cpp:274
SettingText setting_text(const std::wstring &def_label, const std::string &display_label, const wxString &row_label, bool row_multi, const std::string &type_name, const std::wstring &category, const std::wstring &group)
Definition ActionRegistry.cpp:298
std::string into_u8(const wxString &str)
Definition GUI.cpp:549
@ local
Definition Time.hpp:13

References Slic3r::GUI::Tab::get_category_icon_map(), Slic3r::GUI::OptionsGroup::get_url(), Slic3r::GUI::into_u8(), Slic3r::GUI::Tab::SettingRowState::label, Slic3r::GUI::Tab::SettingRowState::label_en, load_persisted(), m_actions, Slic3r::GUI::Tab::SettingRowState::multi, Slic3r::GUI::Tab::setting_row_state(), Slic3r::GUI::Tab::translate_category(), Slic3r::GUI::I18N::translate_utf8(), and Slic3r::GUI::Tab::SettingRowState::visible.

Referenced by snapshot().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ refresh_capability()

void Slic3r::GUI::ActionRegistry::refresh_capability ( const std::string & plugin_key,
const std::string & capability,
ActionChange change )
private
602{
603 assert(wxThread::IsMain());
604
605 const std::string id = PluginScriptAction::id_for(plugin_key, capability);
606 if (change == ActionChange::Removed) {
607 remove(id);
608 return;
609 }
610
611 PluginManager& manager = PluginManager::instance();
612 if (auto action = make_action(plugin_key, capability, find_loaded_source_name(manager, plugin_key)))
613 upsert(std::move(action));
614 else
615 remove(id);
616}
void remove(const std::string &id)
Definition ActionRegistry.cpp:647
std::string find_loaded_source_name(PluginManager &manager, const std::string &plugin_key)
Definition ActionRegistry.cpp:97

References Slic3r::PluginManager::instance(), remove(), Slic3r::GUI::Removed, and upsert().

Referenced by init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ refresh_page_capability()

void Slic3r::GUI::ActionRegistry::refresh_page_capability ( const std::string & plugin_key,
const std::string & capability,
ActionChange change )
private
619{
620 assert(wxThread::IsMain());
621
622 const std::string id = PluginPageAction::id_for(plugin_key, capability);
623 if (change == ActionChange::Removed) {
624 remove(id);
625 return;
626 }
627
628 PluginManager& manager = PluginManager::instance();
629 if (auto action = make_page_action(plugin_key, capability, find_loaded_source_name(manager, plugin_key)))
630 upsert(std::move(action));
631 else
632 remove(id);
633}

References Slic3r::PluginManager::instance(), remove(), Slic3r::GUI::Removed, and upsert().

Referenced by init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ refresh_source()

void Slic3r::GUI::ActionRegistry::refresh_source ( const std::string & plugin_key,
ActionChange change )
private
569{
570 assert(wxThread::IsMain());
571
572 // Remove this source's current actions. Collect first - erasing from m_actions while
573 // iterating invalidates the iterator. why: m_actions (not the loader) is the source of
574 // truth, so this is correct even after the plugin has already unloaded.
575 std::vector<std::string> stale;
576 for (const auto& [id, action] : m_actions)
577 if (action->source_key() == plugin_key)
578 stale.push_back(id);
579 for (const std::string& id : stale)
580 remove(id);
581
582 if (change == ActionChange::Removed)
583 return;
584
585 PluginManager& manager = PluginManager::instance();
586 const std::string source_name = find_loaded_source_name(manager, plugin_key);
587 for (const auto& capability : manager.get_plugin_capabilities(plugin_key, PluginCapabilityType::Script)) {
588 if (!capability)
589 continue;
590 if (auto action = make_action(plugin_key, capability->name(), source_name))
591 upsert(std::move(action));
592 }
593 for (const auto& capability : manager.get_plugin_capabilities(plugin_key, PluginCapabilityType::Pages)) {
594 if (!capability)
595 continue;
596 if (auto action = make_page_action(plugin_key, capability->name(), source_name))
597 upsert(std::move(action));
598 }
599}

References Slic3r::PluginManager::get_plugin_capabilities(), Slic3r::PluginManager::instance(), m_actions, Slic3r::Pages, remove(), Slic3r::GUI::Removed, Slic3r::Script, and upsert().

Referenced by init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ relocalize_builtins()

void Slic3r::GUI::ActionRegistry::relocalize_builtins ( )
548{
549 assert(wxThread::IsMain());
550 if (!m_started)
551 return;
552
553 // Drop only the built-in commands; plugins and the dynamically materialised families are
554 // either unlocalized or rebuilt per snapshot. remove() only erases the map entry, and upsert()
555 // re-seeds favourites/stats from config, so key-based ids keep their pinned state. make_action()
556 // translates in the new locale.
557 std::vector<std::string> stale;
558 for (const auto& [id, action] : m_actions)
559 if (action->source_key() == kOrcaSourceKey && action->kind == AppActionKind::Command)
560 stale.push_back(id);
561 for (const std::string& id : stale)
562 remove(id);
563
564 for (const NativeCommand& c : NativeCommands::catalog())
566}
@ Command
Definition ActionRegistry.hpp:25
constexpr const char * kOrcaSourceKey
Definition ActionRegistry.hpp:135

References Slic3r::GUI::NativeCommands::catalog(), Slic3r::GUI::Command, Slic3r::GUI::kOrcaSourceKey, m_actions, m_started, Slic3r::GUI::NativeCommands::make_action(), remove(), and upsert().

Here is the call graph for this function:

◆ remove()

void Slic3r::GUI::ActionRegistry::remove ( const std::string & id)
648{
649 assert(wxThread::IsMain());
650 m_actions.erase(id);
651}

References m_actions.

Referenced by refresh_capability(), refresh_page_capability(), refresh_source(), and relocalize_builtins().

Here is the caller graph for this function:

◆ reorder_favourites()

void Slic3r::GUI::ActionRegistry::reorder_favourites ( const std::vector< std::string > & ids)
750{
751 assert(wxThread::IsMain());
752 auto cur = read_string_array("favourite_actions");
753 std::vector<std::string> next;
754 // keep the requested order, but only ids that are actually favourites (guard a bad payload)
755 for (const auto& id : ids)
756 if (std::find(cur.begin(), cur.end(), id) != cur.end() && std::find(next.begin(), next.end(), id) == next.end())
757 next.push_back(id);
758 // why: don't drop favourites the page omitted (e.g. pins with no live action hidden from the bar)
759 for (const auto& id : cur)
760 if (std::find(next.begin(), next.end(), id) == next.end())
761 next.push_back(id);
762 // never write the bar back larger than the quick-launch slots
763 next = cap_favourites(next, kFavLimit);
764 write_section("favourite_actions", nlohmann::json(next));
765}
void write_section(const char *key, const nlohmann::json &j)
Definition ActionRegistry.cpp:73

References Slic3r::GUI::cap_favourites(), and kFavLimit.

Here is the call graph for this function:

◆ run()

AppActionRunResult Slic3r::GUI::ActionRegistry::run ( const std::string & id,
const std::string & param = {} )
693{
694 assert(wxThread::IsMain());
695 auto it = m_actions.find(id);
696 if (it == m_actions.end())
697 return {}; // default Info, empty message
698 // why: hold a shared_ptr keep-alive, never a bare map entry. A runner may pump a
699 // nested event loop; a queued source refresh can erase the entry while the
700 // keep-alive preserves the action until run returns.
701 std::shared_ptr<AppAction> keep = it->second;
702 AppActionRunResult o = keep->run(param);
703 if (o.level == AppActionRunResult::Level::Busy)
704 return o;
705
706 // Bump stats (write-through). Re-read to avoid clobbering a concurrent field.
707 nlohmann::json stats = read_section("stats", nlohmann::json::object());
708 if (!stats.is_object()) // corrupt (valid-JSON, non-object) value degrades to empty
709 stats = nlohmann::json::object();
710 nlohmann::json& e = stats[id];
711 if (!e.is_object())
712 e = nlohmann::json::object();
713 e["count"] = e.value("count", 0) + 1;
714 e["last"] = (long long) std::time(nullptr);
715 write_section("stats", stats);
716 if (AppAction* live = find(id)) {
717 live->count = e["count"];
718 live->last = e["last"];
719 }
720 return o;
721}
AppAction * find(const std::string &id)
Definition ActionRegistry.cpp:688
@ Busy
Definition ActionRegistry.hpp:31

References Slic3r::GUI::AppActionRunResult::Busy, find(), Slic3r::GUI::AppActionRunResult::level, and m_actions.

Here is the call graph for this function:

◆ seed_state()

void Slic3r::GUI::ActionRegistry::seed_state ( AppAction & a) const
private
654{
655 // Favourites carry the quick-launch order, so the persisted list is the source of truth
656 // (not re-derived from the frecency sort). Cap it so stale configs can't exceed kFavLimit.
657 auto favs = favourite_ids();
658 a.favourite = std::find(favs.begin(), favs.end(), a.id()) != favs.end();
659
660 nlohmann::json stats = read_section("stats", nlohmann::json::object());
661 auto it = stats.find(a.id());
662 if (it != stats.end() && it->is_object()) {
663 a.count = it->value("count", 0);
664 a.last = it->value("last", 0LL);
665 } else {
666 a.count = 0;
667 a.last = 0;
668 }
669}

References Slic3r::GUI::AppAction::count, Slic3r::GUI::AppAction::favourite, favourite_ids(), Slic3r::GUI::AppAction::id(), and Slic3r::GUI::AppAction::last.

Referenced by upsert().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_favourite()

bool Slic3r::GUI::ActionRegistry::set_favourite ( const std::string & id,
bool on )
724{
725 assert(wxThread::IsMain());
726 // Start from the capped, deduped list so a persisted config can never be written back larger.
727 auto favs = favourite_ids();
728 auto it = std::find(favs.begin(), favs.end(), id);
729 if (on && it == favs.end()) {
730 if (favs.size() >= kFavLimit)
731 return false; // bar is full - the caller surfaces a hint
732 favs.push_back(id);
733 }
734 if (!on && it != favs.end())
735 favs.erase(it);
736 write_section("favourite_actions", nlohmann::json(favs));
737 if (AppAction* live = find(id))
738 live->favourite = on;
739 return true;
740}

References favourite_ids(), find(), and kFavLimit.

Here is the call graph for this function:

◆ set_tooltip_expanded()

void Slic3r::GUI::ActionRegistry::set_tooltip_expanded ( bool expanded)
953{
954 assert(wxThread::IsMain());
955 write_section("tooltip_expanded", nlohmann::json(expanded));
956}

◆ should_ask()

bool Slic3r::GUI::ActionRegistry::should_ask ( const std::string & id) const
930{
931 assert(wxThread::IsMain());
932 auto arr = read_string_array("ask_suppressed");
933 return std::find(arr.begin(), arr.end(), id) == arr.end();
934}

Referenced by Slic3r::GUI::SpeedDialWebDialog::run_action().

Here is the caller graph for this function:

◆ snapshot()

nlohmann::json Slic3r::GUI::ActionRegistry::snapshot ( )
961{
962 assert(wxThread::IsMain());
963 // Settings and plates are first-class actions; make sure the current visible option set and the
964 // live plate list are materialised before we serialise the pool (tabs_list is built by the time
965 // the palette opens).
969
970 std::vector<const AppAction*> sorted;
971 sorted.reserve(m_actions.size());
972 for (const auto& entry : m_actions)
973 sorted.push_back(entry.second.get());
974
975 const long long now = (long long) std::time(nullptr);
976 std::sort(sorted.begin(), sorted.end(), [&](const AppAction* a, const AppAction* b) {
977 double sa = frecency_score(a->count, a->last, now);
978 double sb = frecency_score(b->count, b->last, now);
979 if (sa != sb)
980 return sa > sb;
981 if (a->title() != b->title())
982 return a->title() < b->title();
983 if (a->source_name() != b->source_name())
984 return a->source_name() < b->source_name();
985 return a->id() < b->id();
986 });
987
988 nlohmann::json actions = nlohmann::json::array();
989 for (const AppAction* a : sorted)
990 actions.push_back(action_json(*a));
991
992 // why: favourites is the ORDERED pin list - it must come from favourite_actions
993 // as stored, not be re-derived from the frecency-sorted actions (that would
994 // reorder the favourites bar). Drop pins with no live action (an option hidden by the
995 // current mode, an unloaded plugin, a gone plate/project) and persist the pruned list, so
996 // invisible pins can't silently fill the quick-launch cap. Order is preserved.
997 std::vector<std::string> favs = favourite_ids();
998 std::vector<std::string> live_favs;
999 live_favs.reserve(favs.size());
1000 for (const auto& id : favs)
1001 if (m_actions.count(id))
1002 live_favs.push_back(id);
1003 if (live_favs.size() != favs.size())
1004 write_section("favourite_actions", nlohmann::json(live_favs));
1005 nlohmann::json favourites(live_favs);
1006
1007 // Recent = the last-N launched actions by recency (only actions with a run history). N is a
1008 // user preference; 0 hides recents without affecting the frecency order below.
1009 const size_t recent_limit = size_t(wxGetApp().app_config->get_speed_dial_recent_count());
1010 std::vector<const AppAction*> recent;
1011 for (const auto& entry : m_actions)
1012 if (entry.second->last > 0)
1013 recent.push_back(entry.second.get());
1014 std::sort(recent.begin(), recent.end(), [](const AppAction* a, const AppAction* b) {
1015 if (a->last != b->last)
1016 return a->last > b->last;
1017 return a->id() < b->id();
1018 });
1019 if (recent.size() > recent_limit)
1020 recent.resize(recent_limit);
1021 nlohmann::json recent_json = nlohmann::json::array();
1022 for (const AppAction* a : recent)
1023 recent_json.push_back(action_json(*a));
1024
1025 return {{"actions", std::move(actions)},
1026 {"favourites", std::move(favourites)},
1027 {"recent", std::move(recent_json)},
1028 {"user_mode", mode_key(wxGetApp().get_mode())},
1029 {"tooltip_expanded", tooltip_expanded()}};
1030}
void materialize_setting_actions()
Definition ActionRegistry.cpp:767
void materialize_plate_actions()
Definition ActionRegistry.cpp:841
void materialize_recent_project_actions()
Definition ActionRegistry.cpp:888
bool tooltip_expanded() const
Definition ActionRegistry.cpp:945
const char * mode_key(ConfigOptionMode mode)
Definition ActionRegistry.cpp:319
nlohmann::json action_json(const AppAction &a)
Definition ActionRegistry.cpp:443

References Slic3r::GUI::action_json(), favourite_ids(), m_actions, materialize_plate_actions(), materialize_recent_project_actions(), materialize_setting_actions(), and tooltip_expanded().

Here is the call graph for this function:

◆ suppress_ask()

void Slic3r::GUI::ActionRegistry::suppress_ask ( const std::string & id)
937{
938 assert(wxThread::IsMain());
939 auto arr = read_string_array("ask_suppressed");
940 if (std::find(arr.begin(), arr.end(), id) == arr.end())
941 arr.push_back(id);
942 write_section("ask_suppressed", nlohmann::json(arr));
943}

◆ tab_options()

nlohmann::json Slic3r::GUI::ActionRegistry::tab_options ( ) const
1035{
1036 assert(wxThread::IsMain());
1037 nlohmann::json out = nlohmann::json::array();
1038 if (!wxTheApp || wxGetApp().is_closing())
1039 return out;
1040 MainFrame* mf = wxGetApp().mainframe;
1041 if (!mf || !mf->m_tabpanel)
1042 return out;
1043 // English labels of the built-in pages whose id is not already their English name, so the tab
1044 // picker can be searched in English in any UI language.
1045 static const std::unordered_map<std::string, const char*> english_labels{
1046 {TAB_ID_MONITOR, L("Device")}, {TAB_ID_MONITOR_WEB, L("Device (Web)")}, {TAB_ID_MULTI_DEVICE, L("Multi-device")}};
1047
1048 Notebook* notebook = mf->m_tabpanel;
1049 for (size_t i = 0; i < notebook->GetPageCount(); ++i) {
1050 const wxString id = notebook->GetPageName(i);
1051 if (id.empty())
1052 continue;
1053 const std::string title = notebook->GetPageLabel(i).ToStdString();
1054 nlohmann::json tab({{"id", id.ToStdString()}, {"title", title}, {"icon", notebook->GetPageIcon(i)}});
1055 if (auto it = english_labels.find(id.ToStdString()); it != english_labels.end() && title != it->second)
1056 tab["title_en"] = it->second;
1057 out.push_back(std::move(tab));
1058 }
1059 return out;
1060}
#define TAB_ID_MULTI_DEVICE
Definition MainFrame.hpp:67
#define TAB_ID_MONITOR_WEB
Definition MainFrame.hpp:66
#define TAB_ID_MONITOR
Definition MainFrame.hpp:62
wxString GetPageLabel(size_t n) const
Definition Notebook.hpp:267
wxString GetPageName(size_t n) const
Definition Notebook.hpp:351
std::string GetPageIcon(size_t n) const
Definition Notebook.hpp:274
bool empty(const BoundingBoxBase< PointType, PointsType > &bb)
Definition BoundingBox.hpp:273

References Slic3r::empty(), Notebook::GetPageIcon(), Notebook::GetPageLabel(), Notebook::GetPageName(), L, Slic3r::GUI::MainFrame::m_tabpanel, TAB_ID_MONITOR, TAB_ID_MONITOR_WEB, and TAB_ID_MULTI_DEVICE.

Here is the call graph for this function:

◆ tooltip_expanded()

bool Slic3r::GUI::ActionRegistry::tooltip_expanded ( ) const
946{
947 assert(wxThread::IsMain());
948 const nlohmann::json j = read_section("tooltip_expanded", nlohmann::json(true));
949 return j.is_boolean() ? j.get<bool>() : true;
950}

Referenced by snapshot().

Here is the caller graph for this function:

◆ upsert()

void Slic3r::GUI::ActionRegistry::upsert ( std::unique_ptr< AppAction > action)
636{
637 assert(wxThread::IsMain());
638 if (!action)
639 return;
640
641 seed_state(*action);
642 std::string id = action->id();
643 std::shared_ptr<AppAction> stored = std::move(action);
644 m_actions.insert_or_assign(std::move(id), std::move(stored));
645}
void seed_state(AppAction &a) const
Definition ActionRegistry.cpp:653

References m_actions, and seed_state().

Referenced by init(), refresh_capability(), refresh_page_capability(), refresh_source(), and relocalize_builtins().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ kFavLimit

size_t Slic3r::GUI::ActionRegistry::kFavLimit = 10
staticconstexpr

◆ m_actions

std::unordered_map<std::string, std::shared_ptr<AppAction> > Slic3r::GUI::ActionRegistry::m_actions
private

◆ m_started

bool Slic3r::GUI::ActionRegistry::m_started = false
private

Referenced by init(), and relocalize_builtins().


The documentation for this class was generated from the following files: