/* * Copyright (c) 2025 Aldrik Ramaekers * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include "strops.hpp" #include "config.hpp" #include "ui.hpp" #include "imgui.h" #include "administration.hpp" #include "administration_writer.hpp" #include "locales.hpp" static view_state current_view_state = view_state::LIST; static contact selected_for_removal; static contact active_contact; void ui_draw_address_form(address* buffer, a_err last_err) { ImGui::FormInputTextWithErrorHint(localize("contact.form.address1"), buffer->address1, IM_ARRAYSIZE(buffer->address1), last_err & A_ERR_MISSING_ADDRESS1); ImGui::FormInputTextWithErrorHint(localize("contact.form.address2"), buffer->address2, IM_ARRAYSIZE(buffer->address2), 0); ImGui::FormInputTextWithErrorHint(localize("contact.form.city"), buffer->city, IM_ARRAYSIZE(buffer->city), last_err & A_ERR_MISSING_CITY); ImGui::FormInputTextWithErrorHint(localize("contact.form.postal"), buffer->postal, IM_ARRAYSIZE(buffer->postal), last_err & A_ERR_MISSING_POSTAL); ImGui::FormInputTextWithErrorHint(localize("contact.form.region"), buffer->region, IM_ARRAYSIZE(buffer->region), 0); ImGui::FormCountryCombo(buffer->country_code, IM_ARRAYSIZE(buffer->country_code)); } void ui_setup_contacts() { current_view_state = view_state::LIST; active_contact = active_contact = administration_contact_create_empty(); memset(&selected_for_removal, 0, sizeof(contact)); } void draw_contact_form_ex(contact* buffer, bool viewing_only = false, bool with_autocomplete = false) { a_err last_err = administration_contact_is_valid(*buffer); ImGui::PushID(buffer); ImGui::Spacing(); ImGui::BeginDisabled(); if (!viewing_only) ImGui::EndDisabled(); if (with_autocomplete) ImGui::FormContactAutocomplete(buffer, last_err & A_ERR_MISSING_NAME); else ImGui::FormInputTextWithErrorHint(localize("contact.form.fullname"), buffer->name, IM_ARRAYSIZE(buffer->name), last_err & A_ERR_MISSING_NAME); ui_draw_address_form(&buffer->address, last_err); ImGui::FormContactTypeCombo(&buffer->type); // Fields only required for businesses. if (buffer->type == contact_type::CONTACT_BUSINESS) { ImGui::FormInputTextWithErrorHint(localize("contact.form.taxnumber"), buffer->taxid, IM_ARRAYSIZE(buffer->taxid), last_err & A_ERR_MISSING_TAXID); ImGui::FormInputTextWithErrorHint(localize("contact.form.businessnumber"), buffer->businessid, IM_ARRAYSIZE(buffer->businessid), last_err & A_ERR_MISSING_BUSINESSID); } ImGui::FormInputTextWithErrorHint(localize("contact.form.email"), buffer->email, IM_ARRAYSIZE(buffer->email), last_err & A_ERR_MISSING_EMAIL); ImGui::FormInputTextWithErrorHint(localize("contact.form.phonenumber"), buffer->phone_number, IM_ARRAYSIZE(buffer->phone_number), 0); ImGui::FormInputTextWithErrorHint(localize("contact.form.bankaccount"), buffer->bank_account, IM_ARRAYSIZE(buffer->bank_account), 0); if (viewing_only) ImGui::EndDisabled(); ImGui::PopID(); } void draw_contact_form(contact* buffer, bool viewing_only = false) { draw_contact_form_ex(buffer, viewing_only, false); } static void draw_contact_list() { const u32 items_per_page = 50; static s32 current_page = 0; s32 max_page = (administration_contact_count() + items_per_page - 1) / items_per_page; if (max_page == 0) max_page = 1; // Table header controls: create button and pagination. if (ImGui::Button(localize("form.create"))) { current_view_state = view_state::CREATE; active_contact = administration_contact_create_empty(); } if (current_page >= max_page-1) current_page = max_page-1; if (current_page < 0) current_page = 0; // Navigate to prev page button. ImGui::SameLine(); bool enable_prev = current_page > 0; if (!enable_prev) ImGui::BeginDisabled(); if (ImGui::Button(localize("ui.prev")) && current_page > 0) current_page--; if (!enable_prev) ImGui::EndDisabled(); ImGui::SameLine(); ImGui::Text("(%d/%d)", current_page+1, max_page); // Navigate to next page button. ImGui::SameLine(); bool enable_next = current_page < max_page-1; if (!enable_next) ImGui::BeginDisabled(); if (ImGui::Button(localize("ui.next")) && current_page < max_page-1) current_page++; if (!enable_next) ImGui::EndDisabled(); ImGui::Spacing(); if (ImGui::BeginTable("TableContacts", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { ImGui::TableSetupColumn(localize("contact.table.identifier"), ImGuiTableColumnFlags_WidthFixed, 80); ImGui::TableSetupColumn(localize("contact.table.name"), ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn(localize("contact.table.address"), ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 160); ImGui::TableHeadersRow(); contact contact_list[items_per_page]; u32 contact_count = administration_contact_get_partial_list(current_page, items_per_page, contact_list); for (u32 i = 0; i < contact_count; i++) { contact c = contact_list[i]; ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); ImGui::Text(c.id); ImGui::TableSetColumnIndex(1); ImGui::Text(c.name); ImGui::TableSetColumnIndex(2); ImGui::Text("%s %s", c.address.address1, c.address.address2); ImGui::TableSetColumnIndex(3); char btn_name[20]; snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.view"), i); if (ImGui::Button(btn_name)) { active_contact = c; current_view_state = view_state::VIEW; } ImGui::SameLine(); snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.change"), i); if (ImGui::Button(btn_name)) { active_contact = c; current_view_state = view_state::EDIT; } ImGui::SameLine(); if (administration_contact_can_be_deleted(c)) { snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.delete"), i); if (ImGui::Button(btn_name)) { selected_for_removal = c; ImGui::OpenPopup("ConfirmDeletePopup"); } } } // Confirmation popup before contact is deleted definitively. if (ImGui::BeginPopupModal("ConfirmDeletePopup", nullptr, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoTitleBar)) { ImGui::Text(localize("form.confirmDelete")); ImGui::Separator(); if (ImGui::Button(localize("form.yes"), ImVec2(120, 0))) { administration_contact_remove(selected_for_removal); ImGui::CloseCurrentPopup(); } ImGui::SameLine(); if (ImGui::Button(localize("form.no"), ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); } ImGui::EndTable(); } } static void ui_draw_contacts_create() { if (ImGui::Button(localize("form.back"))) { current_view_state = view_state::LIST; } draw_contact_form(&active_contact); a_err contact_validation_err = administration_contact_is_valid(active_contact); bool can_save = contact_validation_err == A_ERR_SUCCESS; if (!can_save) ImGui::BeginDisabled(); // Save button ImGui::Spacing(); if (ImGui::Button(localize("form.save"))) { administration_contact_add(active_contact); current_view_state = view_state::LIST; } if (!can_save) ImGui::EndDisabled(); } static void ui_draw_contacts_update() { if (ImGui::Button(localize("form.back"))) { current_view_state = view_state::LIST; } draw_contact_form(&active_contact); a_err contact_validation_err = administration_contact_is_valid(active_contact); bool can_save = contact_validation_err == A_ERR_SUCCESS; if (!can_save) ImGui::BeginDisabled(); // Save button ImGui::Spacing(); if (ImGui::Button(localize("form.save"))) { administration_contact_update(active_contact); current_view_state = view_state::LIST; } if (!can_save) ImGui::EndDisabled(); } void ui_draw_contacts() { switch(current_view_state) { case view_state::LIST: draw_contact_list(); break; case view_state::CREATE: ui_draw_contacts_create(); break; case view_state::EDIT: ui_draw_contacts_update(); break; case view_state::VIEW: if (ImGui::Button(localize("form.back"))) { current_view_state = view_state::LIST; } draw_contact_form(&active_contact, true); break; } }