feat(console): parameter builder in the command explorer (phase 3)
The detail pane's Parameters section is now an editable form: each parameter is a type-hinted input field (string / number / json, optional marked), and a live "Builds" preview shows the command being assembled. String values are auto-quoted; a required field left empty keeps its placeholder and disables "Insert & run"; trailing empty optionals are omitted. Insert and Insert & run now use the assembled command (not just the template), so Insert & run works for parameterized commands once the required fields are filled — destructive commands still confirm first. Param fields reset when the selected command changes or the modal opens. Keyboard nav (Up/Down/Enter) is scoped to the search box so typing in a field doesn't move the selection. A best-effort parseParamSpecs turns the human-readable param templates into fields; JSON-array params (z_sendmany, createrawtransaction) surface as a single "json" field the user pastes into. Adds the console_ref_builds label + 8 translations. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -229,6 +229,7 @@
|
|||||||
"console_no_daemon": "Kein Daemon",
|
"console_no_daemon": "Kein Daemon",
|
||||||
"console_not_connected": "Fehler: Nicht mit Daemon verbunden",
|
"console_not_connected": "Fehler: Nicht mit Daemon verbunden",
|
||||||
"console_quit_note": "'quit'/'exit' werden hier nicht benötigt — schließen Sie einfach das Fenster.",
|
"console_quit_note": "'quit'/'exit' werden hier nicht benötigt — schließen Sie einfach das Fenster.",
|
||||||
|
"console_ref_builds": "Ergibt",
|
||||||
"console_ref_cancel": "Abbrechen",
|
"console_ref_cancel": "Abbrechen",
|
||||||
"console_ref_destructive": "Folgenreich",
|
"console_ref_destructive": "Folgenreich",
|
||||||
"console_ref_example": "Beispiel",
|
"console_ref_example": "Beispiel",
|
||||||
|
|||||||
@@ -229,6 +229,7 @@
|
|||||||
"console_no_daemon": "Sin daemon",
|
"console_no_daemon": "Sin daemon",
|
||||||
"console_not_connected": "Error: No conectado al daemon",
|
"console_not_connected": "Error: No conectado al daemon",
|
||||||
"console_quit_note": "'quit'/'exit' no son necesarios aquí — simplemente cierra la ventana.",
|
"console_quit_note": "'quit'/'exit' no son necesarios aquí — simplemente cierra la ventana.",
|
||||||
|
"console_ref_builds": "Genera",
|
||||||
"console_ref_cancel": "Cancelar",
|
"console_ref_cancel": "Cancelar",
|
||||||
"console_ref_destructive": "Delicado",
|
"console_ref_destructive": "Delicado",
|
||||||
"console_ref_example": "Ejemplo",
|
"console_ref_example": "Ejemplo",
|
||||||
|
|||||||
@@ -229,6 +229,7 @@
|
|||||||
"console_no_daemon": "Pas de daemon",
|
"console_no_daemon": "Pas de daemon",
|
||||||
"console_not_connected": "Erreur : Non connecté au daemon",
|
"console_not_connected": "Erreur : Non connecté au daemon",
|
||||||
"console_quit_note": "'quit'/'exit' ne sont pas nécessaires ici — fermez simplement la fenêtre.",
|
"console_quit_note": "'quit'/'exit' ne sont pas nécessaires ici — fermez simplement la fenêtre.",
|
||||||
|
"console_ref_builds": "Génère",
|
||||||
"console_ref_cancel": "Annuler",
|
"console_ref_cancel": "Annuler",
|
||||||
"console_ref_destructive": "Sensible",
|
"console_ref_destructive": "Sensible",
|
||||||
"console_ref_example": "Exemple",
|
"console_ref_example": "Exemple",
|
||||||
|
|||||||
@@ -229,6 +229,7 @@
|
|||||||
"console_no_daemon": "デーモンなし",
|
"console_no_daemon": "デーモンなし",
|
||||||
"console_not_connected": "エラー:デーモンに接続されていません",
|
"console_not_connected": "エラー:デーモンに接続されていません",
|
||||||
"console_quit_note": "ここでは 'quit'/'exit' は不要です — ウィンドウを閉じるだけで構いません。",
|
"console_quit_note": "ここでは 'quit'/'exit' は不要です — ウィンドウを閉じるだけで構いません。",
|
||||||
|
"console_ref_builds": "生成",
|
||||||
"console_ref_cancel": "キャンセル",
|
"console_ref_cancel": "キャンセル",
|
||||||
"console_ref_destructive": "要注意",
|
"console_ref_destructive": "要注意",
|
||||||
"console_ref_example": "例",
|
"console_ref_example": "例",
|
||||||
|
|||||||
@@ -229,6 +229,7 @@
|
|||||||
"console_no_daemon": "데몬 없음",
|
"console_no_daemon": "데몬 없음",
|
||||||
"console_not_connected": "오류: 데몬에 연결되지 않았습니다",
|
"console_not_connected": "오류: 데몬에 연결되지 않았습니다",
|
||||||
"console_quit_note": "여기서는 'quit'/'exit'가 필요 없습니다 — 그냥 창을 닫으세요.",
|
"console_quit_note": "여기서는 'quit'/'exit'가 필요 없습니다 — 그냥 창을 닫으세요.",
|
||||||
|
"console_ref_builds": "생성",
|
||||||
"console_ref_cancel": "취소",
|
"console_ref_cancel": "취소",
|
||||||
"console_ref_destructive": "주의",
|
"console_ref_destructive": "주의",
|
||||||
"console_ref_example": "예시",
|
"console_ref_example": "예시",
|
||||||
|
|||||||
@@ -229,6 +229,7 @@
|
|||||||
"console_no_daemon": "Sem daemon",
|
"console_no_daemon": "Sem daemon",
|
||||||
"console_not_connected": "Erro: Não conectado ao daemon",
|
"console_not_connected": "Erro: Não conectado ao daemon",
|
||||||
"console_quit_note": "'quit'/'exit' não são necessários aqui — basta fechar a janela.",
|
"console_quit_note": "'quit'/'exit' não são necessários aqui — basta fechar a janela.",
|
||||||
|
"console_ref_builds": "Gera",
|
||||||
"console_ref_cancel": "Cancelar",
|
"console_ref_cancel": "Cancelar",
|
||||||
"console_ref_destructive": "Sensível",
|
"console_ref_destructive": "Sensível",
|
||||||
"console_ref_example": "Exemplo",
|
"console_ref_example": "Exemplo",
|
||||||
|
|||||||
@@ -229,6 +229,7 @@
|
|||||||
"console_no_daemon": "Нет daemon",
|
"console_no_daemon": "Нет daemon",
|
||||||
"console_not_connected": "Ошибка: Не подключено к daemon",
|
"console_not_connected": "Ошибка: Не подключено к daemon",
|
||||||
"console_quit_note": "Здесь не нужны 'quit'/'exit' — просто закройте окно.",
|
"console_quit_note": "Здесь не нужны 'quit'/'exit' — просто закройте окно.",
|
||||||
|
"console_ref_builds": "Формирует",
|
||||||
"console_ref_cancel": "Отмена",
|
"console_ref_cancel": "Отмена",
|
||||||
"console_ref_destructive": "Осторожно",
|
"console_ref_destructive": "Осторожно",
|
||||||
"console_ref_example": "Пример",
|
"console_ref_example": "Пример",
|
||||||
|
|||||||
@@ -229,6 +229,7 @@
|
|||||||
"console_no_daemon": "无守护进程",
|
"console_no_daemon": "无守护进程",
|
||||||
"console_not_connected": "错误:未连接到守护进程",
|
"console_not_connected": "错误:未连接到守护进程",
|
||||||
"console_quit_note": "这里不需要 'quit'/'exit'——直接关闭窗口即可。",
|
"console_quit_note": "这里不需要 'quit'/'exit'——直接关闭窗口即可。",
|
||||||
|
"console_ref_builds": "生成",
|
||||||
"console_ref_cancel": "取消",
|
"console_ref_cancel": "取消",
|
||||||
"console_ref_destructive": "谨慎",
|
"console_ref_destructive": "谨慎",
|
||||||
"console_ref_example": "示例",
|
"console_ref_example": "示例",
|
||||||
|
|||||||
@@ -1495,6 +1495,49 @@ std::vector<std::string> splitParamTemplate(const char* params)
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A parsed parameter for the builder form. type in {string, number, json}; `raw` is the original
|
||||||
|
// template token (used as a placeholder when a required field is left empty).
|
||||||
|
struct ConsoleParamSpec {
|
||||||
|
std::string label;
|
||||||
|
std::string type;
|
||||||
|
bool optional = false;
|
||||||
|
std::string raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Best-effort parse of a param template into fillable fields. The templates are human-readable, not
|
||||||
|
// a strict schema, so heuristics: [word] / ["word"] = an optional scalar; a [ / { with JSON content
|
||||||
|
// (a brace or comma) = a JSON field the user pastes; otherwise a required string/number.
|
||||||
|
std::vector<ConsoleParamSpec> parseParamSpecs(const char* params)
|
||||||
|
{
|
||||||
|
std::vector<ConsoleParamSpec> out;
|
||||||
|
for (const std::string& t : splitParamTemplate(params)) {
|
||||||
|
ConsoleParamSpec p;
|
||||||
|
p.raw = t;
|
||||||
|
std::string inner = t;
|
||||||
|
if (inner.size() >= 2 && inner.front() == '[' && inner.back() == ']') {
|
||||||
|
std::string body = inner.substr(1, inner.size() - 2);
|
||||||
|
bool looksJson = body.find('{') != std::string::npos ||
|
||||||
|
body.find(',') != std::string::npos ||
|
||||||
|
(!body.empty() && body.front() == '[');
|
||||||
|
if (!looksJson) { p.optional = true; inner = body; } // optional scalar wrapper
|
||||||
|
}
|
||||||
|
char c0 = inner.empty() ? 0 : inner.front();
|
||||||
|
if (c0 == '"' || c0 == '\'') {
|
||||||
|
p.type = "string";
|
||||||
|
if (inner.size() >= 2 && inner.back() == c0) inner = inner.substr(1, inner.size() - 2);
|
||||||
|
p.label = inner;
|
||||||
|
} else if (c0 == '{' || c0 == '[') {
|
||||||
|
p.type = "json";
|
||||||
|
p.label = "json";
|
||||||
|
} else {
|
||||||
|
p.type = "number";
|
||||||
|
p.label = inner;
|
||||||
|
}
|
||||||
|
out.push_back(p);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
// Translate a command-category name from the static reference tables (English) for display. The
|
// Translate a command-category name from the static reference tables (English) for display. The
|
||||||
// per-command descriptions stay in English (technical RPC docs); only the 7 category labels are i18n'd.
|
// per-command descriptions stay in English (technical RPC docs); only the 7 category labels are i18n'd.
|
||||||
const char* consoleCategoryLabel(const char* name)
|
const char* consoleCategoryLabel(const char* name)
|
||||||
@@ -1554,35 +1597,72 @@ void ConsoleTab::renderCommandDetail(const ConsoleCommandEntry& cmd, const char*
|
|||||||
ImGui::PopTextWrapPos();
|
ImGui::PopTextWrapPos();
|
||||||
ImGui::Dummy(ImVec2(0, Layout::spacingMd()));
|
ImGui::Dummy(ImVec2(0, Layout::spacingMd()));
|
||||||
|
|
||||||
// Parameters — each token with a rough type tag; optional ([...]) tokens are dimmed.
|
// Parameters — an editable form that assembles the command. Reset the fields whenever the
|
||||||
|
// selected command changes so values don't carry across commands.
|
||||||
|
if (cmd_param_owner_ != &cmd) {
|
||||||
|
for (auto& b : cmd_param_bufs_) b[0] = '\0';
|
||||||
|
cmd_param_owner_ = &cmd;
|
||||||
|
}
|
||||||
|
std::vector<ConsoleParamSpec> specs = parseParamSpecs(cmd.params);
|
||||||
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(OnSurfaceMedium()), "%s", TR("console_ref_parameters"));
|
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(OnSurfaceMedium()), "%s", TR("console_ref_parameters"));
|
||||||
std::vector<std::string> toks = splitParamTemplate(cmd.params);
|
if (specs.empty()) {
|
||||||
if (toks.empty()) {
|
|
||||||
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(OnSurfaceDisabled()), "%s", TR("console_ref_no_params"));
|
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(OnSurfaceDisabled()), "%s", TR("console_ref_no_params"));
|
||||||
} else {
|
} else {
|
||||||
ImGui::Indent(Layout::spacingMd());
|
float labelW = 110.0f * dp;
|
||||||
for (const std::string& t : toks) {
|
ImGui::Indent(Layout::spacingSm());
|
||||||
bool optional = (!t.empty() && t.front() == '[');
|
for (size_t k = 0; k < specs.size() && k < 6; k++) {
|
||||||
char c0 = t.empty() ? 0 : t[0];
|
const ConsoleParamSpec& s = specs[k];
|
||||||
if (optional && t.size() >= 2) c0 = t[1];
|
ImGui::PushID((int)k);
|
||||||
const char* type = (c0 == '"' || c0 == '\'') ? "string"
|
|
||||||
: (c0 == '{' || c0 == '[') ? "json" : "number";
|
|
||||||
ImGui::PushFont(mono);
|
ImGui::PushFont(mono);
|
||||||
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(optional ? OnSurfaceMedium() : OnSurface()),
|
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(s.optional ? OnSurfaceMedium() : OnSurface()),
|
||||||
"%s", t.c_str());
|
"%s", s.label.c_str());
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
ImGui::SameLine();
|
ImGui::SameLine(labelW);
|
||||||
if (optional)
|
ImGui::SetNextItemWidth(-1);
|
||||||
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(OnSurfaceDisabled()),
|
std::string hint = s.optional
|
||||||
" %s \xC2\xB7 %s", type, TR("console_ref_optional"));
|
? (s.type + " \xC2\xB7 " + std::string(TR("console_ref_optional"))) : s.type;
|
||||||
else
|
ImGui::InputTextWithHint("##pv", hint.c_str(), cmd_param_bufs_[k], sizeof(cmd_param_bufs_[k]));
|
||||||
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(OnSurfaceDisabled()), " %s", type);
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
ImGui::Unindent(Layout::spacingMd());
|
ImGui::Unindent(Layout::spacingSm());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble the command from the filled fields. A required field left empty keeps its placeholder
|
||||||
|
// token (so Insert still shows what's needed) and marks the command incomplete (Insert & run
|
||||||
|
// disabled). String values are auto-quoted; trailing empty optionals are omitted.
|
||||||
|
auto trimStr = [](const std::string& s) -> std::string {
|
||||||
|
size_t a = s.find_first_not_of(" \t");
|
||||||
|
if (a == std::string::npos) return std::string();
|
||||||
|
return s.substr(a, s.find_last_not_of(" \t") - a + 1);
|
||||||
|
};
|
||||||
|
bool complete = specs.size() <= 6;
|
||||||
|
std::string built = cmd.name;
|
||||||
|
for (size_t k = 0, stop = 0; k < specs.size() && k < 6 && !stop; k++) {
|
||||||
|
std::string val = trimStr(cmd_param_bufs_[k]);
|
||||||
|
if (val.empty()) {
|
||||||
|
if (specs[k].optional) stop = 1; // omit this + trailing optionals
|
||||||
|
else { built += " " + specs[k].raw; complete = false; } // required placeholder
|
||||||
|
} else {
|
||||||
|
if (specs[k].type == "string" && val.front() != '"' && val.front() != '\'' &&
|
||||||
|
val.front() != '[' && val.front() != '{')
|
||||||
|
val = "\"" + val + "\"";
|
||||||
|
built += " " + val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Live "Builds" preview when the command takes parameters.
|
||||||
|
if (!specs.empty()) {
|
||||||
|
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
|
||||||
|
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(OnSurfaceMedium()), "%s", TR("console_ref_builds"));
|
||||||
|
ImGui::PushFont(mono);
|
||||||
|
ImGui::PushTextWrapPos(0.0f);
|
||||||
|
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(IM_COL32(150, 200, 150, 255)), "%s", built.c_str());
|
||||||
|
ImGui::PopTextWrapPos();
|
||||||
|
ImGui::PopFont();
|
||||||
}
|
}
|
||||||
ImGui::Dummy(ImVec2(0, Layout::spacingMd()));
|
ImGui::Dummy(ImVec2(0, Layout::spacingMd()));
|
||||||
|
|
||||||
// Example (curated commands only).
|
// Example (curated commands only) — reference alongside the builder.
|
||||||
if (cmd.example[0]) {
|
if (cmd.example[0]) {
|
||||||
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(OnSurfaceMedium()), "%s", TR("console_ref_example"));
|
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(OnSurfaceMedium()), "%s", TR("console_ref_example"));
|
||||||
ImGui::PushFont(mono);
|
ImGui::PushFont(mono);
|
||||||
@@ -1593,7 +1673,7 @@ void ConsoleTab::renderCommandDetail(const ConsoleCommandEntry& cmd, const char*
|
|||||||
ImGui::Dummy(ImVec2(0, Layout::spacingMd()));
|
ImGui::Dummy(ImVec2(0, Layout::spacingMd()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actions (or the destructive run confirmation).
|
// Actions (or the destructive run confirmation) — Insert/run use the assembled command.
|
||||||
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
|
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
|
||||||
if (run_confirm_cmd_ == &cmd) {
|
if (run_confirm_cmd_ == &cmd) {
|
||||||
ImVec4 warn = ImGui::ColorConvertU32ToFloat4(Warning());
|
ImVec4 warn = ImGui::ColorConvertU32ToFloat4(Warning());
|
||||||
@@ -1607,28 +1687,32 @@ void ConsoleTab::renderCommandDetail(const ConsoleCommandEntry& cmd, const char*
|
|||||||
if (material::TactileButton(TR("console_ref_cancel"), ImVec2(cbw, 0))) run_confirm_cmd_ = nullptr;
|
if (material::TactileButton(TR("console_ref_cancel"), ImVec2(cbw, 0))) run_confirm_cmd_ = nullptr;
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (material::TactileButton(TR("console_ref_run"), ImVec2(cbw, 0))) {
|
if (material::TactileButton(TR("console_ref_run"), ImVec2(cbw, 0))) {
|
||||||
pending_submit_ = cmd.name;
|
pending_submit_ = built;
|
||||||
command_search_[0] = '\0';
|
command_search_[0] = '\0';
|
||||||
run_confirm_cmd_ = nullptr;
|
run_confirm_cmd_ = nullptr;
|
||||||
show_commands_popup_ = false;
|
show_commands_popup_ = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (material::TactileButton(TR("console_ref_insert"), ImVec2(200.0f * dp, 0)))
|
if (material::TactileButton(TR("console_ref_insert"), ImVec2(200.0f * dp, 0))) {
|
||||||
insertCommandToInput(cmd);
|
snprintf(input_buffer_, sizeof(input_buffer_), "%s", built.c_str());
|
||||||
// "Insert & run" only for commands that take no parameters — running a template with
|
command_search_[0] = '\0';
|
||||||
// placeholders ("address", amount) would just error.
|
run_confirm_cmd_ = nullptr;
|
||||||
if (cmd.params[0] == '\0') {
|
show_commands_popup_ = false;
|
||||||
ImGui::SameLine();
|
}
|
||||||
if (material::TactileButton(TR("console_ref_insert_run"), ImVec2(140.0f * dp, 0))) {
|
// Insert & run: enabled once every required field is filled (a template with unfilled
|
||||||
if (cmd.destructive) {
|
// placeholders would just error).
|
||||||
run_confirm_cmd_ = &cmd;
|
ImGui::SameLine();
|
||||||
} else {
|
ImGui::BeginDisabled(!complete);
|
||||||
pending_submit_ = cmd.name;
|
if (material::TactileButton(TR("console_ref_insert_run"), ImVec2(140.0f * dp, 0))) {
|
||||||
command_search_[0] = '\0';
|
if (cmd.destructive) {
|
||||||
show_commands_popup_ = false;
|
run_confirm_cmd_ = &cmd;
|
||||||
}
|
} else {
|
||||||
|
pending_submit_ = built;
|
||||||
|
command_search_[0] = '\0';
|
||||||
|
show_commands_popup_ = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1652,11 +1736,15 @@ void ConsoleTab::renderCommandsPopup()
|
|||||||
else show_commands_popup_ = false;
|
else show_commands_popup_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search box — auto-focus on open so the user can type immediately.
|
// Search box — auto-focus on open so the user can type immediately. Enter inserts the selected
|
||||||
|
// command's template; reset the param-builder fields on open.
|
||||||
|
if (ImGui::IsWindowAppearing()) { ImGui::SetKeyboardFocusHere(); cmd_param_owner_ = nullptr; }
|
||||||
ImGui::SetNextItemWidth(-1);
|
ImGui::SetNextItemWidth(-1);
|
||||||
if (ImGui::IsWindowAppearing()) ImGui::SetKeyboardFocusHere();
|
bool searchEnter = ImGui::InputTextWithHint("##CmdSearch", TR("console_ref_search_hint"),
|
||||||
bool searchChanged = ImGui::InputTextWithHint("##CmdSearch", TR("console_ref_search_hint"),
|
command_search_, sizeof(command_search_),
|
||||||
command_search_, sizeof(command_search_));
|
ImGuiInputTextFlags_EnterReturnsTrue);
|
||||||
|
bool searchChanged = ImGui::IsItemEdited();
|
||||||
|
bool searchActive = ImGui::IsItemActive();
|
||||||
ImGui::Dummy(ImVec2(0, Layout::spacingXs()));
|
ImGui::Dummy(ImVec2(0, Layout::spacingXs()));
|
||||||
|
|
||||||
std::string q(command_search_);
|
std::string q(command_search_);
|
||||||
@@ -1693,15 +1781,16 @@ void ConsoleTab::renderCommandsPopup()
|
|||||||
else { cmd_sel_cat_ = cmd_sel_idx_ = -1; }
|
else { cmd_sel_cat_ = cmd_sel_idx_ = -1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keyboard nav: Up/Down move the selection, Enter inserts (disabled while a run-confirm shows).
|
// Keyboard nav from the SEARCH box only (so typing in a param field doesn't move the selection):
|
||||||
if (!run_confirm_cmd_ && !order.empty() && selPos >= 0) {
|
// Up/Down move, Enter inserts the selected command's template. Disabled while a run-confirm shows.
|
||||||
|
if (!run_confirm_cmd_ && searchActive && !order.empty() && selPos >= 0) {
|
||||||
if (ImGui::IsKeyPressed(ImGuiKey_DownArrow) && selPos + 1 < (int)order.size()) selPos++;
|
if (ImGui::IsKeyPressed(ImGuiKey_DownArrow) && selPos + 1 < (int)order.size()) selPos++;
|
||||||
else if (ImGui::IsKeyPressed(ImGuiKey_UpArrow) && selPos > 0) selPos--;
|
else if (ImGui::IsKeyPressed(ImGuiKey_UpArrow) && selPos > 0) selPos--;
|
||||||
cmd_sel_cat_ = order[selPos].first;
|
cmd_sel_cat_ = order[selPos].first;
|
||||||
cmd_sel_idx_ = order[selPos].second;
|
cmd_sel_idx_ = order[selPos].second;
|
||||||
if (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter))
|
|
||||||
insertCommandToInput(categories[cmd_sel_cat_].commands[cmd_sel_idx_]);
|
|
||||||
}
|
}
|
||||||
|
if (searchEnter && !run_confirm_cmd_ && cmd_sel_cat_ >= 0)
|
||||||
|
insertCommandToInput(categories[cmd_sel_cat_].commands[cmd_sel_idx_]);
|
||||||
|
|
||||||
// Two-pane body sized above the footer.
|
// Two-pane body sized above the footer.
|
||||||
float footerH = ImGui::GetFrameHeightWithSpacing() + Layout::spacingXs();
|
float footerH = ImGui::GetFrameHeightWithSpacing() + Layout::spacingXs();
|
||||||
|
|||||||
@@ -193,6 +193,8 @@ private:
|
|||||||
int cmd_sel_idx_ = -1; // detail-pane selection: command index within that category
|
int cmd_sel_idx_ = -1; // detail-pane selection: command index within that category
|
||||||
std::string pending_submit_; // command to run next frame (deferred so the modal needs no executor)
|
std::string pending_submit_; // command to run next frame (deferred so the modal needs no executor)
|
||||||
const ConsoleCommandEntry* run_confirm_cmd_ = nullptr; // destructive "Insert & run" awaiting confirmation
|
const ConsoleCommandEntry* run_confirm_cmd_ = nullptr; // destructive "Insert & run" awaiting confirmation
|
||||||
|
char cmd_param_bufs_[6][256] = {{0}}; // parameter-builder input fields
|
||||||
|
const ConsoleCommandEntry* cmd_param_owner_ = nullptr; // command the param buffers currently hold
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
|
|||||||
@@ -1306,6 +1306,7 @@ void I18n::loadBuiltinEnglish()
|
|||||||
strings_["console_ref_no_params"] = "Takes no parameters.";
|
strings_["console_ref_no_params"] = "Takes no parameters.";
|
||||||
strings_["console_ref_optional"] = "optional";
|
strings_["console_ref_optional"] = "optional";
|
||||||
strings_["console_ref_example"] = "Example";
|
strings_["console_ref_example"] = "Example";
|
||||||
|
strings_["console_ref_builds"] = "Builds";
|
||||||
strings_["console_ref_destructive"] = "Consequential";
|
strings_["console_ref_destructive"] = "Consequential";
|
||||||
strings_["console_ref_run_confirm"] = "Run %s now? This is a consequential command.";
|
strings_["console_ref_run_confirm"] = "Run %s now? This is a consequential command.";
|
||||||
strings_["console_ref_cancel"] = "Cancel";
|
strings_["console_ref_cancel"] = "Cancel";
|
||||||
|
|||||||
Reference in New Issue
Block a user