Tooltip bottom bar for process/filament/printer settings

This commit is contained in:
Lam Wei Lun
2026-09-11 16:38:14 +08:00
parent 40693a4c94
commit c57b74731e
15 changed files with 191 additions and 15 deletions
+9 -1
View File
@@ -6,6 +6,7 @@
#include "MainFrame.hpp"
#include "NativeCommands.hpp"
#include "Notebook.hpp"
#include "OptionsGroup.hpp"
#include "Plater.hpp"
#include "Search.hpp"
#include "Tab.hpp"
@@ -571,6 +572,11 @@ void ActionRegistry::materialize_setting_actions()
}
}
// Footer description + wiki affordance; only settings whose row declared a wiki path have one.
action->tooltip = opt.tooltip;
if (!opt.wiki_path.empty())
action->help_url = into_u8(OptionsGroup::get_url(opt.wiki_path));
seed_from(stats, favs, id, *action);
auto const action_id = action->id();
auto const app_action = std::shared_ptr<AppAction>(std::move(action));
@@ -723,7 +729,9 @@ nlohmann::json ActionRegistry::snapshot()
{"kind", a->kind == AppActionKind::Plugin ? "plugin" : "command"},
{"input", a->input},
{"icon", a->icon},
{"mode", mode_key(a->required_mode)}});
{"mode", mode_key(a->required_mode)},
{"desc", a->tooltip},
{"wiki", !a->help_url.empty()}});
};
nlohmann::json actions = nlohmann::json::array();
+4
View File
@@ -83,6 +83,10 @@ struct AppAction
// Settings mode required to edit this action (SettingActions only). The palette prompts before
// running an action whose mode is above the user's current mode. comSimple for everything else.
ConfigOptionMode required_mode = comSimple;
// Description shown in the Speed Dial's footer strip (SettingActions: the localized tooltip).
std::string tooltip;
// Full wiki URL, when the action has one (SettingActions whose row declared a label_path).
std::string help_url;
virtual ~AppAction() = default;
// Re-resolves + runs (UI thread). `param` carries an optional per-run argument for
+6
View File
@@ -244,6 +244,12 @@ void OptionsGroup::append_line(const Line& line)
{
m_lines.emplace_back(line);
// Record each option's wiki path (Line::label_path) so the Speed Dial can offer an "open wiki"
// affordance for it. Settings tabs only; the searcher already exists by the time tabs are built.
if (m_use_custom_ctrl && !line.label_path.empty())
for (const auto& opt : line.get_options())
wxGetApp().sidebar().get_searcher().set_path(opt.opt_id, static_cast<Preset::Type>(config_type()), line.label_path);
if (line.full_width && (line.widget != nullptr || !line.get_extra_widgets().empty()))
return;
+5 -1
View File
@@ -250,6 +250,10 @@ protected:
virtual void back_to_initial_value(const std::string& opt_key) {}
virtual void back_to_sys_value(const std::string& opt_key) {}
// Preset::Type of a settings group; -1 for groups not tied to a preset. Used by append_line to
// register each option's wiki path with the searcher. Overridden by ConfigOptionsGroup.
virtual int config_type() const { return -1; }
public:
static wxString get_url(const std::string& path_end);
static bool launch_browser(const std::string& path_end);
@@ -273,7 +277,7 @@ public:
OptionsGroup(parent, wxEmptyString, wxEmptyString, true, nullptr) {}
const wxString& config_category() const throw() { return m_config_category; }
int config_type() const throw() { return m_config_type; }
int config_type() const throw() override { return m_config_type; }
const t_opt_map& opt_map() const throw() { return m_opt_map; }
void set_config_category_and_type(const wxString &category, int type) { m_config_category = category; m_config_type = type; }
+17 -5
View File
@@ -85,7 +85,7 @@ static std::string get_key(const std::string &opt_key, Preset::Type type) { retu
void OptionsSearcher::append_options(DynamicPrintConfig *config, Preset::Type type, ConfigOptionMode mode)
{
auto emplace = [this, type](std::vector<Option> &dst, const std::string &key, const wxString &label, ConfigOptionMode opt_mode) {
auto emplace = [this, type](std::vector<Option> &dst, const std::string &key, const wxString &label, ConfigOptionMode opt_mode, std::string tooltip) {
const GroupAndCategory &gc = groups_and_categories[key];
if (gc.group.IsEmpty() || gc.category.IsEmpty()) return;
@@ -101,7 +101,7 @@ void OptionsSearcher::append_options(DynamicPrintConfig *config, Preset::Type ty
if (!label.IsEmpty())
dst.emplace_back(Option{boost::nowide::widen(key), type, (label + suffix).ToStdWstring(), (_(label) + suffix_local).ToStdWstring(), gc.group.ToStdWstring(),
_(gc.group).ToStdWstring(), into_u8(gc.icon), gc.category.ToStdWstring(), GUI::Tab::translate_category(gc.category, type).ToStdWstring(),
false, opt_mode});
false, opt_mode, std::move(tooltip), gc.path});
};
for (std::string opt_key : config->keys()) {
@@ -131,8 +131,8 @@ void OptionsSearcher::append_options(DynamicPrintConfig *config, Preset::Type ty
std::string key = get_key(opt_key, type);
auto add = [&](const std::string &k) {
if (in_filtered)
emplace(options, k, label, opt.mode);
emplace(options_all_modes, k, label, opt.mode);
emplace(options, k, label, opt.mode, into_u8(_(opt.tooltip)));
emplace(options_all_modes, k, label, opt.mode, into_u8(_(opt.tooltip)));
};
if (cnt == 0)
add(key);
@@ -459,7 +459,19 @@ void OptionsSearcher::dlg_msw_rescale()
void OptionsSearcher::add_key(const std::string &opt_key, Preset::Type type, const wxString &group, const wxString &category, const wxString &icon)
{
groups_and_categories[get_key(opt_key, type)] = GroupAndCategory{group, category, icon};
// Update fields in place so a page rebuild (get_option after set_path) doesn't drop the
// previously recorded wiki path.
GroupAndCategory &gc = groups_and_categories[get_key(opt_key, type)];
gc.group = group;
gc.category = category;
gc.icon = icon;
}
void OptionsSearcher::set_path(const std::string &opt_key, Preset::Type type, const std::string &path)
{
if (path.empty())
return;
groups_and_categories[get_key(opt_key, type)].path = path;
}
//------------------------------------------
// SearchItem
+7
View File
@@ -46,6 +46,7 @@ struct GroupAndCategory
wxString group;
wxString category;
wxString icon; // icon of the group's own header, or empty
std::string path; // wiki path (Line::label_path) of the option's line, or empty
};
struct Option
@@ -66,6 +67,8 @@ struct Option
std::wstring category_local;
bool multi_category { false };
ConfigOptionMode mode{comSimple}; // option's visibility threshold; drives the Speed Dial's mode prompt
std::string tooltip; // localized ConfigOptionDef::tooltip, or empty
std::string wiki_path; // Line::label_path for the option's row, or empty
std::string opt_key() const;
};
@@ -133,6 +136,10 @@ public:
void add_key(const std::string &opt_key, Preset::Type type, const wxString &group, const wxString &category,
const wxString &icon = wxEmptyString);
// Records the wiki path of an option's row (Line::label_path) so the Speed Dial can offer a
// "open wiki" affordance. Empty paths are ignored.
void set_path(const std::string &opt_key, Preset::Type type, const std::string &path);
size_t size() const { return found_size(); }
const FoundOption &operator[](const size_t pos) const noexcept { return found[pos]; }
+12
View File
@@ -14,6 +14,7 @@
#include <wx/display.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/utils.h>
#ifdef __linux__
#include <gtk/gtk.h>
@@ -152,6 +153,8 @@ void SpeedDialWebDialog::handle_web_command(const nlohmann::json& payload)
wxGetApp().action_registry().reorder_favourites(ids);
} else if (command == "run_action")
run_action(payload.value("id", ""), payload.value("title", ""), payload.value("param", ""));
else if (command == "open_wiki")
open_wiki(payload.value("id", ""));
else if (command == "search_tabs")
search_tabs();
else if (command == "resize")
@@ -253,6 +256,15 @@ void SpeedDialWebDialog::run_action(const std::string& id, const std::string& ti
});
}
void SpeedDialWebDialog::open_wiki(const std::string& id)
{
const AppAction* a = wxGetApp().action_registry().by_id(id);
if (!a || a->help_url.empty())
return;
Hide();
wxLaunchDefaultBrowser(from_u8(a->help_url));
}
void SpeedDialWebDialog::send_actions()
{
nlohmann::json snap = wxGetApp().action_registry().snapshot();
+1
View File
@@ -21,6 +21,7 @@ private:
void handle_web_command(const nlohmann::json& payload);
void resize_to_content(int height);
void run_action(const std::string& id, const std::string& title, const std::string& param = "");
void open_wiki(const std::string& id);
void send_actions();
void search_tabs();