Cleanup comments and formatting

This commit is contained in:
Lam Wei Lun
2026-09-10 13:00:23 +08:00
parent 9fc6c45770
commit 16d285fea6
9 changed files with 488 additions and 355 deletions
+6 -7
View File
@@ -1,5 +1,5 @@
// Speed Dial launcher page. Static-safe module: no DOM access at load time so a // Speed Dial launcher page. Static-safe module: no DOM access at load time so a
// node vm can exercise the pure helpers (filterActions / actionLabel / nextSel / commandList). // node vm can exercise the pure helpers (searchActions / filterTabs / actionLabel / nextSel / commandList).
// ---- state (populated by the C++ bridge via window.HandleStudio) ---- // ---- state (populated by the C++ bridge via window.HandleStudio) ----
var ACTIONS = []; // [{id,title,source,group,input,shortcut}], already frecency-sorted by C++ var ACTIONS = []; // [{id,title,source,group,input,shortcut}], already frecency-sorted by C++
@@ -31,8 +31,8 @@ var searchNeedle = "";
var phase = "commands"; var phase = "commands";
var tabOptions = []; // [{id,title}] - notebook pages, fetched on entering the tab phase var tabOptions = []; // [{id,title}] - notebook pages, fetched on entering the tab phase
// why: fuzzy matcher (FoldChar/Norm/FuzzyRanges) lives in shared ../../js/fuzzy-search.js, loaded before // why: the fuzzy matcher (NormText/FuzzyRangesNorm/WholeWordRangesNorm) lives in shared
// this script - it is shared with the Plugins dialog. Speed dial search is always case-insensitive. // ../../js/fuzzy-search.js, loaded before this script. Search is always case-insensitive.
// element handles, assigned in OnInit (kept null so load-time touches no DOM) // element handles, assigned in OnInit (kept null so load-time touches no DOM)
var qEl = null, listEl = null, favEl = null, clearEl = null, eyeEl = null, countEl = null, headEl = null; var qEl = null, listEl = null, favEl = null, clearEl = null, eyeEl = null, countEl = null, headEl = null;
@@ -177,9 +177,8 @@ function resultCountText(total, shown, query) {
return (query || "").trim() ? "Showing " + shown + " of " + total + " actions" : total + " actions"; return (query || "").trim() ? "Showing " + shown + " of " + total + " actions" : total + " actions";
} }
// Display label for a notebook tab. Notebook's ButtonsListCtrl labels every non-empty page as // Display label for a notebook tab. Trim any stray whitespace; pages added with an empty title
// " <text>" (a leading space), so trim it; pages added with an empty title (Home, MainFrame adds // (Home, MainFrame adds TAB_ID_HOME with "") fall back to the title-cased id ("home" -> "Home").
// TAB_ID_HOME with "") fall back to the title-cased id ("home" -> "Home").
function tabTitle(t) { function tabTitle(t) {
var title = (t && t.title) ? String(t.title).trim() : ""; var title = (t && t.title) ? String(t.title).trim() : "";
return title || prettySource((t && t.id) || ""); return title || prettySource((t && t.id) || "");
@@ -537,7 +536,7 @@ function showFavMenu(x, y, id) {
} }
// Swap a favourite with its visible neighbour (dir -1/+1) and persist the new order. Swapping // Swap a favourite with its visible neighbour (dir -1/+1) and persist the new order. Swapping
// by id inside FAVS (not the visible slice) keeps any hidden pins (no live action) in place. // by id inside FAVS (not the visible slice) keeps the persisted order stable.
function moveFav(id, dir) { function moveFav(id, dir) {
var favs = currentVisibleFavs(); var favs = currentVisibleFavs();
var vi = favs.indexOf(id); var vi = favs.indexOf(id);
@@ -59,7 +59,7 @@ assert.equal(ctx.tabTitle({ id: "home" }), "Home",
assert.equal(ctx.tabTitle({ id: "prepare", title: "Prepare" }), "Prepare", assert.equal(ctx.tabTitle({ id: "prepare", title: "Prepare" }), "Prepare",
"a populated title is kept as-is"); "a populated title is kept as-is");
assert.equal(ctx.tabTitle({ id: "prepare", title: " Prepare" }), "Prepare", assert.equal(ctx.tabTitle({ id: "prepare", title: " Prepare" }), "Prepare",
"a leading space from the Notebook button label is trimmed so the label shows cleanly"); "a stray leading space in a tab title is trimmed so the label shows cleanly");
assert.equal(ctx.filterTabs([{ id: "home", title: "" }], "home").length, 1, assert.equal(ctx.filterTabs([{ id: "home", title: "" }], "home").length, 1,
"an untitled tab still matches a typed query via the id/title fallback"); "an untitled tab still matches a typed query via the id/title fallback");
assert.equal(ctx.filterTabs([{ id: "prepare", title: " Prepare" }], "prepare").length, 1, assert.equal(ctx.filterTabs([{ id: "prepare", title: " Prepare" }], "prepare").length, 1,
+178 -40
View File
@@ -1,5 +1,12 @@
* { box-sizing: border-box; } * {
html, body { margin: 0; } box-sizing: border-box;
}
html,
body {
margin: 0;
}
body { body {
font-family: var(--orca-font, "Segoe UI", sans-serif); font-family: var(--orca-font, "Segoe UI", sans-serif);
font-size: 13px; font-size: 13px;
@@ -8,6 +15,7 @@ body {
overflow: hidden; overflow: hidden;
user-select: none; user-select: none;
} }
.launcher { .launcher {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -18,6 +26,7 @@ body {
sizes the popup to match (HTML is source of truth). The list's own max-height is what sizes the popup to match (HTML is source of truth). The list's own max-height is what
bounds growth; capping the launcher would make the measurement circular. */ bounds growth; capping the launcher would make the measurement circular. */
} }
.fav-bar { .fav-bar {
flex: 0 0 auto; flex: 0 0 auto;
display: flex; display: flex;
@@ -25,17 +34,27 @@ body {
gap: 8px; gap: 8px;
padding: 9px 10px; padding: 9px 10px;
border-bottom: 1px solid var(--border, var(--orca-border, #ddd)); border-bottom: 1px solid var(--border, var(--orca-border, #ddd));
overflow-x: auto; /* scroll horizontally once favourites overflow the row */ overflow-x: auto;
/* scroll horizontally once favourites overflow the row */
scrollbar-width: thin; scrollbar-width: thin;
/* why: keep scrollIntoView (arrow-nav) from scrolling the first/last tile flush to the edge, /* why: keep scrollIntoView (arrow-nav) from scrolling the first/last tile flush to the edge,
which would clip its selected outline. Matches the 10px horizontal padding. */ which would clip its selected outline. Matches the 10px horizontal padding. */
scroll-padding-inline: 10px; scroll-padding-inline: 10px;
} }
.fav-bar[hidden] { display: none; }
.fav-bar[hidden] {
display: none;
}
/* Name of the selected favourite, above the bar; left-aligned to the tiles' 10px inset. */ /* Name of the selected favourite, above the bar; left-aligned to the tiles' 10px inset. */
.fav-eyebrow { flex: 0 0 auto; padding: 8px 10px 0; } .fav-eyebrow {
flex: 0 0 auto;
padding: 8px 10px 0;
}
.fav-tile { .fav-tile {
flex: 0 0 auto; /* keep tiles full-size; don't shrink to fit - scroll instead */ flex: 0 0 auto;
/* keep tiles full-size; don't shrink to fit - scroll instead */
width: 30px; width: 30px;
height: 30px; height: 30px;
border: 0; border: 0;
@@ -54,9 +73,17 @@ body {
background: var(--speed-tile-bg, #f0f0f0); background: var(--speed-tile-bg, #f0f0f0);
border: 1px solid var(--speed-tile-border, #d8d8d8); border: 1px solid var(--speed-tile-border, #d8d8d8);
} }
.fav-tile.sel { outline: 2px solid var(--main-color, var(--orca-accent, #009688)); outline-offset: 2px; }
.fav-tile.sel {
outline: 2px solid var(--main-color, var(--orca-accent, #009688));
outline-offset: 2px;
}
/* Hover-revealed remove button in the tile's corner; sits inside the tile bounds so overflow:hidden clips it. */ /* Hover-revealed remove button in the tile's corner; sits inside the tile bounds so overflow:hidden clips it. */
.fav-tile { position: relative; } .fav-tile {
position: relative;
}
.fav-unpin { .fav-unpin {
position: absolute; position: absolute;
top: 1px; top: 1px;
@@ -74,9 +101,16 @@ body {
cursor: pointer; cursor: pointer;
opacity: 0; opacity: 0;
} }
.fav-tile:hover .fav-unpin, .fav-tile:hover .fav-unpin,
.fav-tile.sel .fav-unpin { opacity: 1; } .fav-tile.sel .fav-unpin {
.fav-unpin:hover { background: rgba(127,127,127,.6); } opacity: 1;
}
.fav-unpin:hover {
background: rgba(127, 127, 127, .6);
}
/* Numbered quick-launch slot (Alt/Option+digit), top-left corner of the fav tile. */ /* Numbered quick-launch slot (Alt/Option+digit), top-left corner of the fav tile. */
.fav-slot { .fav-slot {
position: absolute; position: absolute;
@@ -93,6 +127,7 @@ body {
color: var(--muted, var(--orca-muted, #6b7280)); color: var(--muted, var(--orca-muted, #6b7280));
background: rgba(127, 127, 127, .22); background: rgba(127, 127, 127, .22);
} }
/* Transient flash banner pinned to the top of the launcher (e.g. "favourites are full"). */ /* Transient flash banner pinned to the top of the launcher (e.g. "favourites are full"). */
.dial-flash { .dial-flash {
flex: 0 0 auto; flex: 0 0 auto;
@@ -102,7 +137,25 @@ body {
background: var(--plugin-status-warn-bg, rgba(255, 193, 7, .22)); background: var(--plugin-status-warn-bg, rgba(255, 193, 7, .22));
animation: dial-flash-fade 2.5s ease forwards; animation: dial-flash-fade 2.5s ease forwards;
} }
@keyframes dial-flash-fade { 0% { opacity: 0; } 10% { opacity: 1; } 80% { opacity: 1; } 100% { opacity: 0; } }
@keyframes dial-flash-fade {
0% {
opacity: 0;
}
10% {
opacity: 1;
}
80% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.ctx-menu { .ctx-menu {
position: fixed; position: fixed;
z-index: 10; z-index: 10;
@@ -113,7 +166,11 @@ body {
border-radius: 7px; border-radius: 7px;
box-shadow: 0 4px 16px rgba(0, 0, 0, .18); box-shadow: 0 4px 16px rgba(0, 0, 0, .18);
} }
.ctx-menu[hidden] { display: none; }
.ctx-menu[hidden] {
display: none;
}
.ctx-item { .ctx-item {
display: block; display: block;
width: 100%; width: 100%;
@@ -126,10 +183,25 @@ body {
text-align: left; text-align: left;
cursor: pointer; cursor: pointer;
} }
.ctx-item:hover { background: var(--row-hover, rgba(127,127,127,.16)); }
.ctx-item:disabled { opacity: .4; cursor: default; } .ctx-item:hover {
.ctx-item:disabled:hover { background: transparent; } background: var(--row-hover, rgba(127, 127, 127, .16));
.dial-head { flex: 0 0 auto; padding: 8px; } }
.ctx-item:disabled {
opacity: .4;
cursor: default;
}
.ctx-item:disabled:hover {
background: transparent;
}
.dial-head {
flex: 0 0 auto;
padding: 8px;
}
.plugin-search { .plugin-search {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -140,11 +212,17 @@ body {
border: 1px solid var(--border, var(--orca-border, #ddd)); border: 1px solid var(--border, var(--orca-border, #ddd));
border-radius: 7px; border-radius: 7px;
} }
.plugin-search:focus-within { .plugin-search:focus-within {
border-color: var(--main-color, var(--orca-accent, #009688)); border-color: var(--main-color, var(--orca-accent, #009688));
box-shadow: 0 0 0 2px rgba(0, 150, 136, .25); box-shadow: 0 0 0 2px rgba(0, 150, 136, .25);
} }
.plugin-search-icon { display: inline-flex; color: var(--muted, var(--orca-muted, #6b7280)); }
.plugin-search-icon {
display: inline-flex;
color: var(--muted, var(--orca-muted, #6b7280));
}
.plugin-search-input { .plugin-search-input {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
@@ -154,6 +232,7 @@ body {
color: var(--text, var(--orca-fg, #1b1c1e)); color: var(--text, var(--orca-fg, #1b1c1e));
font: inherit; font: inherit;
} }
.plugin-search-clear { .plugin-search-clear {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
@@ -167,23 +246,22 @@ body {
cursor: pointer; cursor: pointer;
background: rgba(127, 127, 127, .20); background: rgba(127, 127, 127, .20);
} }
.plugin-search-clear[hidden] { display: none; }
.plugin-search-clear[hidden] {
display: none;
}
.dial-count { .dial-count {
padding: 4px 4px 0; padding: 4px 4px 0;
text-align: left; text-align: left;
font-size: 11px; font-size: 11px;
color: var(--muted, var(--orca-muted, #6b7280)); color: var(--muted, var(--orca-muted, #6b7280));
} }
.dial-count[hidden] { display: none; }
/* Section header inside the list (e.g. the "Recent" row above the recent entries). */ .dial-count[hidden] {
.dial-group { display: none;
padding: 8px 8px 2px;
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: .06em;
color: var(--muted, var(--orca-muted, #6b7280));
} }
.dial-list { .dial-list {
flex: 0 1 auto; flex: 0 1 auto;
min-height: 0; min-height: 0;
@@ -198,10 +276,17 @@ body {
padding: 4px 4px 6px; padding: 4px 4px 6px;
scrollbar-width: thin; scrollbar-width: thin;
} }
.dial-list.empty { overflow-y: hidden; }
.dial-list.empty {
overflow-y: hidden;
}
/* Bottom spacer for the windowed command list: fills the un-rendered tail so the scrollbar reflects /* Bottom spacer for the windowed command list: fills the un-rendered tail so the scrollbar reflects
the full match count, while only a near-viewport window of rows exists in the DOM. */ the full match count, while only a near-viewport window of rows exists in the DOM. */
.dial-spacer-bottom { flex: 0 0 auto; } .dial-spacer-bottom {
flex: 0 0 auto;
}
.row { .row {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -211,8 +296,15 @@ body {
border-radius: 7px; border-radius: 7px;
cursor: pointer; cursor: pointer;
} }
.row:hover { background: var(--row-hover, rgba(127,127,127,.16)); }
.row.sel { background: var(--row-selected, rgba(0,150,136,.18)); } .row:hover {
background: var(--row-hover, rgba(127, 127, 127, .16));
}
.row.sel {
background: var(--row-selected, rgba(0, 150, 136, .18));
}
.tile { .tile {
flex: 0 0 auto; flex: 0 0 auto;
width: 26px; width: 26px;
@@ -227,7 +319,14 @@ body {
background: var(--speed-tile-bg, #f0f0f0); background: var(--speed-tile-bg, #f0f0f0);
border: 1px solid var(--speed-tile-border, #d8d8d8); border: 1px solid var(--speed-tile-border, #d8d8d8);
} }
.row-left { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.row-left {
flex: 1 1 auto;
min-width: 0;
display: flex;
flex-direction: column;
}
.row-eyebrow { .row-eyebrow {
font-size: 10px; font-size: 10px;
line-height: 1.3; line-height: 1.3;
@@ -237,10 +336,34 @@ body {
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.row-line { display: flex; align-items: center; gap: 7px; min-width: 0; }
.row-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .row-line {
.row-name mark, .row-eyebrow mark { background: var(--plugin-status-warn-bg); color: var(--plugin-status-warn); border-radius: 2px; } display: flex;
.row-sc { flex: 0 0 auto; display: inline-flex; gap: 3px; } align-items: center;
gap: 7px;
min-width: 0;
}
.row-name {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.row-name mark,
.row-eyebrow mark {
background: var(--plugin-status-warn-bg);
color: var(--plugin-status-warn);
border-radius: 2px;
}
.row-sc {
flex: 0 0 auto;
display: inline-flex;
gap: 3px;
}
kbd { kbd {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
@@ -255,6 +378,7 @@ kbd {
border: 1px solid var(--border, var(--orca-border, #ddd)); border: 1px solid var(--border, var(--orca-border, #ddd));
border-radius: 4px; border-radius: 4px;
} }
.pin { .pin {
flex: 0 0 auto; flex: 0 0 auto;
width: 24px; width: 24px;
@@ -269,11 +393,25 @@ kbd {
justify-content: center; justify-content: center;
opacity: 0; opacity: 0;
} }
.pin svg { display: block; }
.pin svg {
display: block;
}
.row:hover .pin:not(.on), .row:hover .pin:not(.on),
.row.sel .pin:not(.on) { opacity: .5; } .row.sel .pin:not(.on) {
.pin.on { opacity: 1; color: var(--main-color, var(--orca-accent, #009688)); } opacity: .5;
.pin:hover { background: rgba(127,127,127,.18); } }
.pin.on {
opacity: 1;
color: var(--main-color, var(--orca-accent, #009688));
}
.pin:hover {
background: rgba(127, 127, 127, .18);
}
.dial-empty { .dial-empty {
min-height: 64px; min-height: 64px;
padding: 18px 10px; padding: 18px 10px;
+2 -2
View File
@@ -200,8 +200,8 @@ struct CommandAction : AppAction
private: private:
explicit CommandAction(const NativeCommand& c) explicit CommandAction(const NativeCommand& c)
: AppAction(AppActionId{AppAction::compose_id(kCommandPrefix, c.key, kOrcaSourceKey)}, c.title, kOrcaSourceKey, kOrcaSourceName), : AppAction(AppActionId{AppAction::compose_id(kCommandPrefix, c.key, kOrcaSourceKey)}, c.title, kOrcaSourceKey, kOrcaSourceName)
command_key(c.key) , command_key(c.key)
{ {
this->kind = AppActionKind::Command; this->kind = AppActionKind::Command;
this->group = c.group; this->group = c.group;
+10 -11
View File
@@ -19,7 +19,7 @@ namespace Slic3r { namespace GUI {
// How a source's action set changed. Drives the registry's refresh handlers. // How a source's action set changed. Drives the registry's refresh handlers.
enum class ActionChange { Added, Removed }; enum class ActionChange { Added, Removed };
// What kind of runnable thing an action is. Drives the palette section + dispatch. // What kind of runnable thing an action is. Drives the run-confirm gate (plugins ask, commands don't).
enum class AppActionKind { Plugin, Command }; enum class AppActionKind { Plugin, Command };
// Result of running an AppAction, in the action layer's own vocabulary. Concrete // Result of running an AppAction, in the action layer's own vocabulary. Concrete
@@ -72,8 +72,8 @@ struct AppAction
// source name); Command sets a section label (e.g. "Commands", "Mode"). // source name); Command sets a section label (e.g. "Commands", "Mode").
AppActionKind kind = AppActionKind::Plugin; AppActionKind kind = AppActionKind::Plugin;
std::string group; std::string group;
// Second-phase input descriptor for the palette: "settings" (jump to a config option) // Second-phase input descriptor for the palette: "percent" (jump to layer by a 0-100
// or "percent" (jump to layer by a 0-100 value). Empty = run immediately on activation. // value) or "tab" (pick a notebook tab). Empty = run immediately on activation.
std::string input; std::string input;
virtual ~AppAction() = default; virtual ~AppAction() = default;
@@ -87,18 +87,17 @@ protected:
// why: source_key (not the display name) carries identity, so renaming the source's // why: source_key (not the display name) carries identity, so renaming the source's
// display name leaves the id - and its persisted stats/favourite - intact. // display name leaves the id - and its persisted stats/favourite - intact.
AppAction(std::string_view prefix, std::string title, std::string source_key, std::string source_name) AppAction(std::string_view prefix, std::string title, std::string source_key, std::string source_name)
: m_id(compose_id(prefix, title, source_key)), : m_id(compose_id(prefix, title, source_key))
m_title(std::move(title)), , m_title(std::move(title))
m_source_key(std::move(source_key)), , m_source_key(std::move(source_key))
m_source_name(std::move(source_name)) {} , m_source_name(std::move(source_name))
{}
// Explicit-id ctor: for actions whose id must NOT be derived from the display title // Explicit-id ctor: for actions whose id must NOT be derived from the display title
// (e.g. a setting action keyed by opt_key+type, so a rename/localization never re-keys it). // (e.g. a setting action keyed by opt_key+type, so a rename/localization never re-keys it).
AppAction(AppActionId id, std::string title, std::string source_key, std::string source_name) AppAction(AppActionId id, std::string title, std::string source_key, std::string source_name)
: m_id(std::move(id.id)), : m_id(std::move(id.id)), m_title(std::move(title)), m_source_key(std::move(source_key)), m_source_name(std::move(source_name))
m_title(std::move(title)), {}
m_source_key(std::move(source_key)),
m_source_name(std::move(source_name)) {}
private: private:
std::string m_id; // <prefix>:<title>:<source_key> - stable identity + AppConfig key std::string m_id; // <prefix>:<title>:<source_key> - stable identity + AppConfig key
+4 -4
View File
@@ -4375,10 +4375,10 @@ void MainFrame::technology_changed()
m_menubar->SetMenuLabel(id, pt == ptFFF ? _omitL("Material Settings") : _L("Filament settings")); m_menubar->SetMenuLabel(id, pt == ptFFF ? _omitL("Material Settings") : _L("Filament settings"));
} }
// Opens the calibration wizard for `calib_kind`, reusing the cached member dialogs the Calibration // Opens the calibration wizard for `calib_kind`. Single source of truth for the wizard lifecycle:
// menu builds. This is the single source of truth for the wizard lifecycle: the Calibration menu // the Calibration menu handlers and the Speed Dial native commands both call it. Most wizards are
// handlers and the Speed Dial native commands both call it, so they share the same per-wizard // cached members reused across launches; cornering/input-shaping build a fresh transient dialog.
// member (fresh on first launch, reused thereafter). Call while the Prepare (3D) panel is shown. // Call while the Prepare (3D) panel is shown.
void MainFrame::run_calibration(CalibKind calib_kind) void MainFrame::run_calibration(CalibKind calib_kind)
{ {
switch (calib_kind) { switch (calib_kind) {
+4 -5
View File
@@ -107,7 +107,6 @@ protected:
}; };
// Calibration wizard identity, shared by MainFrame::run_calibration and the Speed Dial command runners. // Calibration wizard identity, shared by MainFrame::run_calibration and the Speed Dial command runners.
// Kept in order with the wizard list below.
enum class CalibKind : int enum class CalibKind : int
{ {
Temperature, Temperature,
@@ -364,10 +363,10 @@ public:
void technology_changed(); void technology_changed();
// Opens the calibration wizard for `kind`, reusing the cached member dialogs the Calibration // Opens the calibration wizard for `kind`. Single source of truth for the wizard lifecycle:
// menu builds (m_*_calib_dlg). Single source of truth for the wizard lifecycle: the Calibration // the Calibration menu handlers and the Speed Dial native commands both call this. Most wizards
// menu handlers and the Speed Dial native commands both call this. Call while the Prepare (3D) // are cached members; cornering/input-shaping are transient. Call while the Prepare (3D) panel
// panel is shown (menu items are gated on is_view3D_shown; the speed dial ensures it first). // is shown (menu items are gated on is_view3D_shown; the speed dial ensures it first).
void run_calibration(CalibKind calib_kind); void run_calibration(CalibKind calib_kind);
//BBS //BBS
+9 -11
View File
@@ -58,9 +58,9 @@ AppActionRunResult object_op(Plater* plater, bool (*ok)(Plater*), void (*op)(Pla
return {AppActionRunResult::Level::Success}; return {AppActionRunResult::Level::Success};
} }
// Jump the preview to a layer selected by a 0-100 percent of the layer range. Best-effort: switches // Jump the preview to a layer selected by a 0-100 percent of the layer range. The caller has already
// to the preview tab and requests a slice; if the slicer result is already present the slider is // switched to Preview (which may request a slice); if a slicer result is present the slider is
// repositioned immediately, otherwise the user can re-run after slicing. // repositioned immediately, otherwise the jump is a no-op until the user re-slices.
void go_to_layer(Plater* plater, const std::string& param) void go_to_layer(Plater* plater, const std::string& param)
{ {
if (!plater) if (!plater)
@@ -100,8 +100,8 @@ AppActionRunResult view_command(Plater* plater, const std::string& dir)
return {AppActionRunResult::Level::Success}; return {AppActionRunResult::Level::Success};
} }
// Calibration wizards. Reuses MainFrame::run_calibration so the speed dial shows the same cached // Calibration wizards. Routes through MainFrame::run_calibration, the same entry point as the
// member dialogs as the Calibration menu (the menu handlers call run_calibration too). // Calibration menu (which caches most of the wizard dialogs).
AppActionRunResult calib_command(CalibKind kind) AppActionRunResult calib_command(CalibKind kind)
{ {
MainFrame* mf = wxGetApp().mainframe; MainFrame* mf = wxGetApp().mainframe;
@@ -115,8 +115,8 @@ AppActionRunResult calib_command(CalibKind kind)
std::vector<NativeCommand> build_command_catalog() std::vector<NativeCommand> build_command_catalog()
{ {
std::vector<NativeCommand> out; std::vector<NativeCommand> out;
auto add = [&](std::string key, std::string title, std::string group, auto add = [&](std::string key, std::string title, std::string group, std::function<AppActionRunResult(const std::string&)> runner,
std::function<AppActionRunResult(const std::string&)> runner, std::string input = {}) { std::string input = {}) {
out.push_back({std::move(key), std::move(title), std::move(group), std::move(input), std::move(runner)}); out.push_back({std::move(key), std::move(title), std::move(group), std::move(input), std::move(runner)});
}; };
@@ -207,8 +207,7 @@ std::vector<NativeCommand> build_command_catalog()
plater->export_gcode_3mf(false); plater->export_gcode_3mf(false);
return AppActionRunResult{AppActionRunResult::Level::Success}; return AppActionRunResult{AppActionRunResult::Level::Success};
}); });
add("export_all_sliced_file", _u8L("Export All Sliced Files"), _u8L("Slice & Export"), add("export_all_sliced_file", _u8L("Export All Sliced Files"), _u8L("Slice & Export"), [](const std::string&) {
[](const std::string&) {
if (Plater* plater = wxGetApp().plater()) if (Plater* plater = wxGetApp().plater())
plater->export_gcode_3mf(true); plater->export_gcode_3mf(true);
return AppActionRunResult{AppActionRunResult::Level::Success}; return AppActionRunResult{AppActionRunResult::Level::Success};
@@ -231,8 +230,7 @@ std::vector<NativeCommand> build_command_catalog()
[](const std::string&) { return calib_command(CalibKind::InputShapingFreq); }); [](const std::string&) { return calib_command(CalibKind::InputShapingFreq); });
add("calib_input_shaping_damp", _u8L("Input Shaping Damping Calibration"), _u8L("Calibration"), add("calib_input_shaping_damp", _u8L("Input Shaping Damping Calibration"), _u8L("Calibration"),
[](const std::string&) { return calib_command(CalibKind::InputShapingDamp); }); [](const std::string&) { return calib_command(CalibKind::InputShapingDamp); });
add("calib_vfa", _u8L("VFA Calibration"), _u8L("Calibration"), add("calib_vfa", _u8L("VFA Calibration"), _u8L("Calibration"), [](const std::string&) { return calib_command(CalibKind::VFA); });
[](const std::string&) { return calib_command(CalibKind::VFA); });
// ---- View ---- // ---- View ----
for (auto [key, dir, title] : for (auto [key, dir, title] :
+2 -2
View File
@@ -16,12 +16,12 @@ struct NativeCommand
std::string key; std::string key;
std::string title; std::string title;
std::string group; std::string group;
std::string input; // "settings"/"percent"/"tab" or "" for immediate run std::string input; // "percent"/"tab" or "" for immediate run
std::function<AppActionRunResult(const std::string& param)> runner; std::function<AppActionRunResult(const std::string& param)> runner;
}; };
namespace NativeCommands { namespace NativeCommands {
// The full built-in command catalog, built once (init()). UI thread only. // The full built-in command catalog, built once on first use. UI thread only.
const std::vector<NativeCommand>& catalog(); const std::vector<NativeCommand>& catalog();
// Dispatches `key` to its runner (unknown keys return a quiet Info). UI thread only. // Dispatches `key` to its runner (unknown keys return a quiet Info). UI thread only.