refactor(ui): add LabeledInputRow + LabeledInputMultiline; complete inputs layer

Extend the inputs layer with the two remaining form-field idioms, pixel-identical:
- material::LabeledInputRow(label, labelPos, ...) — horizontal label-beside-input
  (Text + SameLine + SetNextItemWidth + InputText). Adopt at the settings RPC
  host/port/user/pass rows.
- material::LabeledInputMultiline(label, id, buf, size, flags) — label above a
  sized multiline input. Adopt at the address-book notes and request-payment
  memo (drops the redundant SetNextItemWidth that InputTextMultiline's explicit
  size already governs).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-04 21:41:42 -05:00
parent 840ead3645
commit dfca9bbd92
4 changed files with 34 additions and 24 deletions

View File

@@ -370,6 +370,27 @@ inline bool LabeledInput(const char* label, const char* id, char* buf, size_t bu
return ImGui::InputText(id, buf, bufSize, flags);
}
// Horizontal variant: label on the left, input to its right on the same line (settings-style rows).
// `labelPos` is the SameLine offset the input starts at (0 = default item spacing after the label).
inline bool LabeledInputRow(const char* label, float labelPos, const char* id, char* buf, size_t bufSize,
float width = -1.0f, const char* hint = nullptr, ImGuiInputTextFlags flags = 0)
{
ImGui::Text("%s", label);
ImGui::SameLine(labelPos);
ImGui::SetNextItemWidth(width);
if (hint && hint[0]) return ImGui::InputTextWithHint(id, hint, buf, bufSize, flags);
return ImGui::InputText(id, buf, bufSize, flags);
}
// Multiline variant: label above a multiline input of the given `size` (InputTextMultiline governs its
// own width via size, so no SetNextItemWidth). Returns the input's edited bool.
inline bool LabeledInputMultiline(const char* label, const char* id, char* buf, size_t bufSize,
const ImVec2& size, ImGuiInputTextFlags flags = 0)
{
ImGui::Text("%s", label);
return ImGui::InputTextMultiline(id, buf, bufSize, size, flags);
}
// ── Frameless icon button ────────────────────────────────────────────────
// Style for IconButton. All colors default to 0 (= unset): color falls back to OnSurfaceMedium();
// hoverColor==0 means "no hover recolor"; hoverBg/restBg==0 mean "no background".

View File

@@ -118,10 +118,8 @@ void AddressBookDialog::render(App* app)
ImGui::Spacing();
ImGui::Text("%s", TR("notes_optional"));
ImGui::SetNextItemWidth(formW);
ImGui::InputTextMultiline(isEdit ? "##EditNotes" : "##AddNotes",
s_edit_notes, sizeof(s_edit_notes), ImVec2(formW, notesH));
material::LabeledInputMultiline(TR("notes_optional"), isEdit ? "##EditNotes" : "##AddNotes",
s_edit_notes, sizeof(s_edit_notes), ImVec2(formW, notesH));
bool canSubmit = std::strlen(s_edit_label) > 0 && std::strlen(s_edit_address) > 0;
float totalActionsW = actionW * 2.0f + actionGap;

View File

@@ -206,9 +206,8 @@ void RequestPaymentDialog::render(App* app)
// Memo (optional, only for z-addr)
bool is_zaddr = (s_address[0] == 'z');
if (is_zaddr) {
ImGui::Text("%s", TR("request_memo"));
ImGui::SetNextItemWidth(-1);
if (ImGui::InputTextMultiline("##Memo", s_memo, sizeof(s_memo), ImVec2(-1, memoInput.height > 0 ? memoInput.height : 60))) {
if (material::LabeledInputMultiline(TR("request_memo"), "##Memo", s_memo, sizeof(s_memo),
ImVec2(-1, memoInput.height > 0 ? memoInput.height : 60))) {
s_uri_dirty = true;
}
} else {

View File

@@ -396,28 +396,20 @@ void RenderSettingsWindow(App* app, bool* p_open)
ImGui::Separator();
ImGui::Spacing();
ImGui::Text("%s", TR("rpc_host"));
ImGui::SameLine(connLbl.position);
ImGui::SetNextItemWidth(cmb.width);
ImGui::InputText("##RPCHost", s_rpc_host, sizeof(s_rpc_host));
material::LabeledInputRow(TR("rpc_host"), connLbl.position, "##RPCHost",
s_rpc_host, sizeof(s_rpc_host), cmb.width);
ImGui::Text("%s", TR("rpc_port"));
ImGui::SameLine(connLbl.position);
ImGui::SetNextItemWidth(portInput.width);
ImGui::InputText("##RPCPort", s_rpc_port, sizeof(s_rpc_port));
material::LabeledInputRow(TR("rpc_port"), connLbl.position, "##RPCPort",
s_rpc_port, sizeof(s_rpc_port), portInput.width);
ImGui::Spacing();
ImGui::Text("%s", TR("rpc_user"));
ImGui::SameLine(connLbl.position);
ImGui::SetNextItemWidth(cmb.width);
ImGui::InputText("##RPCUser", s_rpc_user, sizeof(s_rpc_user));
material::LabeledInputRow(TR("rpc_user"), connLbl.position, "##RPCUser",
s_rpc_user, sizeof(s_rpc_user), cmb.width);
ImGui::Text("%s", TR("rpc_pass"));
ImGui::SameLine(connLbl.position);
ImGui::SetNextItemWidth(cmb.width);
ImGui::InputText("##RPCPassword", s_rpc_password, sizeof(s_rpc_password),
ImGuiInputTextFlags_Password);
material::LabeledInputRow(TR("rpc_pass"), connLbl.position, "##RPCPassword",
s_rpc_password, sizeof(s_rpc_password), cmb.width, nullptr,
ImGuiInputTextFlags_Password);
ImGui::Spacing();
ImGui::Separator();