From 2855642dd16cea260f3b32351f0529328a0bcb15 Mon Sep 17 00:00:00 2001 From: Aldrik Ramaekers Date: Sat, 4 Oct 2025 15:54:30 +0200 Subject: namespacing locale, config, file_templates --- include/config.hpp | 21 +- include/file_templates.hpp | 516 +++++++++++---------- include/import_service.hpp | 57 --- include/importer.hpp | 57 +++ include/locales.hpp | 31 +- libs/imgui-1.92.1/docs/CHANGELOG.txt | 6 +- .../examples/libs/glfw/include/GLFW/glfw3.h | 6 +- src/administration.cpp | 4 +- src/administration_reader.cpp | 6 +- src/administration_writer.cpp | 26 +- src/ai_providers/DeepSeek.cpp | 6 +- src/ai_providers/openAI.cpp | 2 +- src/config.cpp | 24 - src/import_service.cpp | 190 -------- src/importer.cpp | 188 ++++++++ src/locales.cpp | 52 ++- src/locales/en.cpp | 4 +- src/ui/imgui_extensions.cpp | 46 +- src/ui/ui_contacts.cpp | 58 +-- src/ui/ui_earnings.cpp | 22 +- src/ui/ui_expenses.cpp | 74 +-- src/ui/ui_invoices.cpp | 86 ++-- src/ui/ui_main.cpp | 22 +- src/ui/ui_projects.cpp | 34 +- src/ui/ui_settings.cpp | 50 +- 25 files changed, 792 insertions(+), 796 deletions(-) delete mode 100644 include/import_service.hpp create mode 100644 include/importer.hpp delete mode 100644 src/config.cpp delete mode 100644 src/import_service.cpp create mode 100644 src/importer.cpp diff --git a/include/config.hpp b/include/config.hpp index 9598841..df99ab2 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -16,10 +16,8 @@ #pragma once -// major.minor.patch -#define PROGRAM_VERSION "0.1.0" - #include "stdint.h" +#include "imgui.h" #define s8 int8_t #define s16 int16_t @@ -31,7 +29,18 @@ #define u32 uint32_t #define u64 uint64_t -extern const char* country_codes[]; -extern s32 country_count; +namespace config { + static const char* PROGRAM_VERSION = "0.1.0"; // major.minor.patch + + static const char* country_codes[] = { + "AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR", + "DE", "GR", "HU", "IE", "IT", "LV", "LT", "LU", "MT", "NL", + "PL", "PT", "RO", "SK", "SI", "ES", "SE" + }; + + static s32 country_count = sizeof(country_codes) / sizeof(country_codes[0]); -#define COLOR_ERROR_OUTLINE IM_COL32(255, 0, 0, 80) \ No newline at end of file + namespace colors { + static const ImU32 COLOR_ERROR_OUTLINE = IM_COL32(255, 0, 0, 80); + } +} \ No newline at end of file diff --git a/include/file_templates.hpp b/include/file_templates.hpp index c1420f9..506df67 100644 --- a/include/file_templates.hpp +++ b/include/file_templates.hpp @@ -14,274 +14,278 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -const char* project_save_template = -"\n" -" {{PROJECT_ID}}\n" -" {{PROJECT_DESCRIPTION}}\n" -" {{PROJECT_STATE}}\n" -" {{PROJECT_STARTDATE}}\n" -" {{PROJECT_ENDDATE}}\n" -""; +namespace file_template { -const char* costcenter_save_template = -"\n" -" {{COSTCENTER_ID}}\n" -" {{COSTCENTER_CODE}}\n" -" {{COSTCENTER_DESCRIPTION}}\n" -""; + static const char* project_save_template = + "\n" + " {{PROJECT_ID}}\n" + " {{PROJECT_DESCRIPTION}}\n" + " {{PROJECT_STATE}}\n" + " {{PROJECT_STARTDATE}}\n" + " {{PROJECT_ENDDATE}}\n" + ""; -const char* taxrate_save_template = -"\n" -" {{TAXBRACKET_ID}}\n" -" {{TAXBRACKET_COUNTRY}}\n" -" {{TAXBRACKET_RATE}}\n" -" {{TAXBRACKET_CATEGORY}}\n" -""; + static const char* costcenter_save_template = + "\n" + " {{COSTCENTER_ID}}\n" + " {{COSTCENTER_CODE}}\n" + " {{COSTCENTER_DESCRIPTION}}\n" + ""; -const char* contact_save_template = -"\n" -" {{CONTACT_ID}}\n" -" {{CONTACT_NAME}}\n" -" {{CONTACT_TYPE}}\n" -" {{CONTACT_TAXID}}\n" -" {{CONTACT_BUSINESSID}}\n" -" {{CONTACT_EMAIL}}\n" -" {{CONTACT_PHONENUMBER}}\n" -" {{CONTACT_BANKACCOUNT}}\n" -"
\n" -" {{CONTACT_ADDRESS1}}\n" -" {{CONTACT_ADDRESS2}}\n" -" {{CONTACT_COUNTRY}}\n" -" {{CONTACT_CITY}}\n" -" {{CONTACT_POSTAL}}\n" -" {{CONTACT_REGION}}\n" -"
\n" -"
"; + static const char* taxrate_save_template = + "\n" + " {{TAXBRACKET_ID}}\n" + " {{TAXBRACKET_COUNTRY}}\n" + " {{TAXBRACKET_RATE}}\n" + " {{TAXBRACKET_CATEGORY}}\n" + ""; -const char* administration_save_template = -"\n" -" {{NEXT_ID}}\n" -" {{NEXT_SEQUENCE_NUMBER}}\n" -" {{PROGRAM_VERSION}}\n" -" \n" -" {{AI_SERVICE_PROVIDER}}\n" -" {{AI_SERVICE_PUBLIC_KEY}}\n" -" \n" -""; + static const char* contact_save_template = + "\n" + " {{CONTACT_ID}}\n" + " {{CONTACT_NAME}}\n" + " {{CONTACT_TYPE}}\n" + " {{CONTACT_TAXID}}\n" + " {{CONTACT_BUSINESSID}}\n" + " {{CONTACT_EMAIL}}\n" + " {{CONTACT_PHONENUMBER}}\n" + " {{CONTACT_BANKACCOUNT}}\n" + "
\n" + " {{CONTACT_ADDRESS1}}\n" + " {{CONTACT_ADDRESS2}}\n" + " {{CONTACT_COUNTRY}}\n" + " {{CONTACT_CITY}}\n" + " {{CONTACT_POSTAL}}\n" + " {{CONTACT_REGION}}\n" + "
\n" + "
"; -const char* peppol_invoice_tax_subtotal_template = -" \n" -" {{TAXABLE_AMOUNT}}\n" -" {{TAX_AMOUNT}}\n" -" \n" -" {{TAX_CATEGORY}}\n" -" {{TAX_PERCENT}}\n" -" \n" -" VAT\n" -" \n" -" \n" -" \n"; + static const char* administration_save_template = + "\n" + " {{NEXT_ID}}\n" + " {{NEXT_SEQUENCE_NUMBER}}\n" + " {{PROGRAM_VERSION}}\n" + " \n" + " {{AI_SERVICE_PROVIDER}}\n" + " {{AI_SERVICE_PUBLIC_KEY}}\n" + " \n" + ""; -const char* peppol_invoice_line_template = -" \n" -" {{LINE_ID}}\n" -" {{QUANTITY}}\n" -" {{LINE_AMOUNT}}\n" + static const char* peppol_invoice_tax_subtotal_template = + " \n" + " {{TAXABLE_AMOUNT}}\n" + " {{TAX_AMOUNT}}\n" + " \n" + " {{TAX_CATEGORY}}\n" + " {{TAX_PERCENT}}\n" + " \n" + " VAT\n" + " \n" + " \n" + " \n"; -" \n" -" false\n" -" Discount\n" -" {{DISCOUNT_TOTAL_PERCENTAGE}}\n" -" {{DISCOUNT_TOTAL}}\n" -" {{DISCOUNT_BASE_AMOUNT}}\n" -" \n" + static const char* peppol_invoice_line_template = + " \n" + " {{LINE_ID}}\n" + " {{QUANTITY}}\n" + " {{LINE_AMOUNT}}\n" -" \n" -" {{ITEM_NAME}}\n" + " \n" + " false\n" + " Discount\n" + " {{DISCOUNT_TOTAL_PERCENTAGE}}\n" + " {{DISCOUNT_TOTAL}}\n" + " {{DISCOUNT_BASE_AMOUNT}}\n" + " \n" -" \n" -" Internal Tax Rate ID\n" -" {{LINE_TAX_ID}}\n" -" \n" + " \n" + " {{ITEM_NAME}}\n" -" \n" -" {{LINE_TAX_CATEGORY}}\n" -" {{LINE_TAX_PERCENT}}\n" -" \n" -" VAT\n" -" \n" -" \n" -" \n" + " \n" + " Internal Tax Rate ID\n" + " {{LINE_TAX_ID}}\n" + " \n" -" \n" -" {{UNIT_PRICE}}\n" -" \n" -" \n"; + " \n" + " {{LINE_TAX_CATEGORY}}\n" + " {{LINE_TAX_PERCENT}}\n" + " \n" + " VAT\n" + " \n" + " \n" + " \n" -const char *peppol_invoice_template = -/*"\n"*/ -"\n" -"\n" -" urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0\n" -" urn:fdc:peppol.eu:2017:poacc:billing:01:1.0\n" -"\n" -" {{INVOICE_ID}}\n" -" {{ISSUE_DATE}}\n" -" {{DUE_DATE}}\n" -" 380\n" -" {{CURRENCY}}\n" -"\n" -" \n" -" {{INVOICE_STATUS}}\n" -" \n" -"\n" -" \n" -" {{INVOICE_DOCUMENT_COPY}}\n" -" {{INVOICE_DOCUMENT_ORIG}}\n" -" \n" -"\n" -" \n" -" {{INVOICE_SEQUENCE_ID}}\n" -" \n" -"\n" -" \n" -" {{PROJECT_ID}}\n" -" \n" -" {{COST_CENTER_ID}}\n" -"\n" -" \n" -" \n" -" {{SUPPLIER_ENDPOINT_ID}}\n" -" \n" -" {{SUPPLIER_BUSINESS_ID}}\n" -" \n" -" \n" -" {{SUPPLIER_NAME}}\n" -" \n" -" \n" -" {{SUPPLIER_STREET}}\n" -" {{SUPPLIER_STREET2}}\n" -" {{SUPPLIER_CITY}}\n" -" {{SUPPLIER_POSTAL}}\n" -" {{SUPPLIER_REGION}}\n" -" \n" -" {{SUPPLIER_COUNTRY}}\n" -" \n" -" \n" -" \n" -" {{SUPPLIER_VAT_ID}}\n" -" \n" -" VAT\n" -" \n" -" \n" -"\n" -" \n" -" {{SUPPLIER_LEGAL_NAME}}\n" -" \n" -"\n" -" \n" -" {{SUPPLIER_ID}}\n" -" {{SUPPLIER_PHONE_NUMBER}}\n" -" {{SUPPLIER_EMAIL}}\n" -" \n" -"\n" -" \n" -" \n" -"\n" -" \n" -" \n" -" {{CUSTOMER_ENDPOINT_ID}}\n" -" \n" -" {{CUSTOMER_BUSINESS_ID}}\n" -" \n" -" \n" -" {{CUSTOMER_NAME}}\n" -" \n" -" \n" -" {{CUSTOMER_STREET}}\n" -" {{CUSTOMER_STREET2}}\n" -" {{CUSTOMER_CITY}}\n" -" {{CUSTOMER_POSTAL}}\n" -" {{CUSTOMER_REGION}}\n" -" \n" -" {{CUSTOMER_COUNTRY}}\n" -" \n" -" \n" -" \n" -" {{CUSTOMER_VAT_ID}}\n" -" \n" -" VAT\n" -" \n" -" \n" -"\n" -" \n" -" {{CUSTOMER_LEGAL_NAME}}\n" -" \n" -"\n" -" \n" -" {{CUSTOMER_ID}}\n" -" {{CUSTOMER_PHONE_NUMBER}}\n" -" {{CUSTOMER_EMAIL}}\n" -" \n" -"\n" -" \n" -" \n" -"\n" -"\n" -" {{DELIVERY_DATE}}\n" -" \n" -" \n" -" {{DELIVERY_STREET}}\n" -" {{DELIVERY_STREET2}}\n" -" {{DELIVERY_CITY}}\n" -" {{DELIVERY_POSTAL}}\n" -" {{DELIVERY_REGION}}\n" -" \n" -" {{DELIVERY_COUNTRY}}\n" -" \n" -" \n" -" \n" -" \n" -" \n" -" {{DELIVERY_NAME}}\n" -" \n" -" \n" -"\n" -"\n" -" \n" -" {{PAYMENT_TYPE}}\n" -" {{INVOICE_ID}}\n" + " \n" + " {{UNIT_PRICE}}\n" + " \n" + " \n"; -" \n" -" {{RECIPIENT_IBAN}}\n" -" {{RECIPIENT_NAME}}\n" -" \n" -" \n" -" {{RECIPIENT_BIC}}\n" -" \n" -" \n" -" \n" + static const char *peppol_invoice_template = + /*"\n"*/ + "\n" + "\n" + " urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0\n" + " urn:fdc:peppol.eu:2017:poacc:billing:01:1.0\n" + "\n" + " {{INVOICE_ID}}\n" + " {{ISSUE_DATE}}\n" + " {{DUE_DATE}}\n" + " 380\n" + " {{CURRENCY}}\n" + "\n" + " \n" + " {{INVOICE_STATUS}}\n" + " \n" + "\n" + " \n" + " {{INVOICE_DOCUMENT_COPY}}\n" + " {{INVOICE_DOCUMENT_ORIG}}\n" + " \n" + "\n" + " \n" + " {{INVOICE_SEQUENCE_ID}}\n" + " \n" + "\n" + " \n" + " {{PROJECT_ID}}\n" + " \n" + " {{COST_CENTER_ID}}\n" + "\n" + " \n" + " \n" + " {{SUPPLIER_ENDPOINT_ID}}\n" + " \n" + " {{SUPPLIER_BUSINESS_ID}}\n" + " \n" + " \n" + " {{SUPPLIER_NAME}}\n" + " \n" + " \n" + " {{SUPPLIER_STREET}}\n" + " {{SUPPLIER_STREET2}}\n" + " {{SUPPLIER_CITY}}\n" + " {{SUPPLIER_POSTAL}}\n" + " {{SUPPLIER_REGION}}\n" + " \n" + " {{SUPPLIER_COUNTRY}}\n" + " \n" + " \n" + " \n" + " {{SUPPLIER_VAT_ID}}\n" + " \n" + " VAT\n" + " \n" + " \n" + "\n" + " \n" + " {{SUPPLIER_LEGAL_NAME}}\n" + " \n" + "\n" + " \n" + " {{SUPPLIER_ID}}\n" + " {{SUPPLIER_PHONE_NUMBER}}\n" + " {{SUPPLIER_EMAIL}}\n" + " \n" + "\n" + " \n" + " \n" + "\n" + " \n" + " \n" + " {{CUSTOMER_ENDPOINT_ID}}\n" + " \n" + " {{CUSTOMER_BUSINESS_ID}}\n" + " \n" + " \n" + " {{CUSTOMER_NAME}}\n" + " \n" + " \n" + " {{CUSTOMER_STREET}}\n" + " {{CUSTOMER_STREET2}}\n" + " {{CUSTOMER_CITY}}\n" + " {{CUSTOMER_POSTAL}}\n" + " {{CUSTOMER_REGION}}\n" + " \n" + " {{CUSTOMER_COUNTRY}}\n" + " \n" + " \n" + " \n" + " {{CUSTOMER_VAT_ID}}\n" + " \n" + " VAT\n" + " \n" + " \n" + "\n" + " \n" + " {{CUSTOMER_LEGAL_NAME}}\n" + " \n" + "\n" + " \n" + " {{CUSTOMER_ID}}\n" + " {{CUSTOMER_PHONE_NUMBER}}\n" + " {{CUSTOMER_EMAIL}}\n" + " \n" + "\n" + " \n" + " \n" + "\n" + "\n" + " {{DELIVERY_DATE}}\n" + " \n" + " \n" + " {{DELIVERY_STREET}}\n" + " {{DELIVERY_STREET2}}\n" + " {{DELIVERY_CITY}}\n" + " {{DELIVERY_POSTAL}}\n" + " {{DELIVERY_REGION}}\n" + " \n" + " {{DELIVERY_COUNTRY}}\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " {{DELIVERY_NAME}}\n" + " \n" + " \n" + "\n" + "\n" + " \n" + " {{PAYMENT_TYPE}}\n" + " {{INVOICE_ID}}\n" -" \n" -" {{SENDER_IBAN}}\n" -" \n" + " \n" + " {{RECIPIENT_IBAN}}\n" + " {{RECIPIENT_NAME}}\n" + " \n" + " \n" + " {{RECIPIENT_BIC}}\n" + " \n" + " \n" + " \n" -" \n" -"\n" -" \n" -" {{TOTAL_TAX_AMOUNT}}\n" -" {{TAX_SUBTOTAL_LIST}}" -" \n" -"\n" -" \n" -" {{LINE_EXTENSION_AMOUNT}}\n" -" {{TAX_EXCLUSIVE_AMOUNT}}\n" -" {{TAX_INCLUSIVE_AMOUNT}}\n" -" {{PAYABLE_AMOUNT}}\n" -" \n" -"\n" -" {{INVOICE_LINE_LIST}}" -"\n" -""; + " \n" + " {{SENDER_IBAN}}\n" + " \n" + + " \n" + "\n" + " \n" + " {{TOTAL_TAX_AMOUNT}}\n" + " {{TAX_SUBTOTAL_LIST}}" + " \n" + "\n" + " \n" + " {{LINE_EXTENSION_AMOUNT}}\n" + " {{TAX_EXCLUSIVE_AMOUNT}}\n" + " {{TAX_INCLUSIVE_AMOUNT}}\n" + " {{PAYABLE_AMOUNT}}\n" + " \n" + "\n" + " {{INVOICE_LINE_LIST}}" + "\n" + ""; + +} \ No newline at end of file diff --git a/include/import_service.hpp b/include/import_service.hpp deleted file mode 100644 index 7e23e20..0000000 --- a/include/import_service.hpp +++ /dev/null @@ -1,57 +0,0 @@ -/* -* 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. -*/ - -#pragma once - -#include "administration.hpp" - -typedef uint32_t i_err; - -#define I_ERR_SUCCESS 0 -#define I_ERR_FAILED_UPLOAD 1 -#define I_ERR_FAILED_QUERY 2 -#define I_ERR_FAILED_IMPORT 3 - -typedef enum -{ - IMPORT_STARTING, - IMPORT_UPLOADING_FILE, - IMPORT_QUERYING, - IMPORT_WAITING_FOR_RESPONSE, - IMPORT_DONE, -} import_status; - -typedef struct -{ - time_t started_at; - invoice result; - char file_path[MAX_LEN_PATH]; - i_err error; - import_status status; -} import_invoice_request; - -typedef struct -{ - bool (*upload_file)(char* file_path, char* file_id, size_t file_id_len); - bool (*query_with_file)(char* query, size_t query_length, char* file_id, char** response); -} ai_provider_impl; - -extern ai_provider_impl _chatgpt_api_provider; -extern ai_provider_impl _deepseek_api_provider; - -const char* import_error_to_str(i_err error); -const char* import_status_to_str(import_status status); -import_invoice_request* ai_document_to_invoice(char* file_path); \ No newline at end of file diff --git a/include/importer.hpp b/include/importer.hpp new file mode 100644 index 0000000..7e23e20 --- /dev/null +++ b/include/importer.hpp @@ -0,0 +1,57 @@ +/* +* 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. +*/ + +#pragma once + +#include "administration.hpp" + +typedef uint32_t i_err; + +#define I_ERR_SUCCESS 0 +#define I_ERR_FAILED_UPLOAD 1 +#define I_ERR_FAILED_QUERY 2 +#define I_ERR_FAILED_IMPORT 3 + +typedef enum +{ + IMPORT_STARTING, + IMPORT_UPLOADING_FILE, + IMPORT_QUERYING, + IMPORT_WAITING_FOR_RESPONSE, + IMPORT_DONE, +} import_status; + +typedef struct +{ + time_t started_at; + invoice result; + char file_path[MAX_LEN_PATH]; + i_err error; + import_status status; +} import_invoice_request; + +typedef struct +{ + bool (*upload_file)(char* file_path, char* file_id, size_t file_id_len); + bool (*query_with_file)(char* query, size_t query_length, char* file_id, char** response); +} ai_provider_impl; + +extern ai_provider_impl _chatgpt_api_provider; +extern ai_provider_impl _deepseek_api_provider; + +const char* import_error_to_str(i_err error); +const char* import_status_to_str(import_status status); +import_invoice_request* ai_document_to_invoice(char* file_path); \ No newline at end of file diff --git a/include/locales.hpp b/include/locales.hpp index d361f1e..ec6cc74 100644 --- a/include/locales.hpp +++ b/include/locales.hpp @@ -16,20 +16,23 @@ #pragma once -typedef struct { - const char* key; - const char* value; -} locale_entry; +namespace locale { -typedef struct { - const char* lang_code; - locale_entry* entries; - int entry_count; -} locale_map; + typedef struct { + const char* key; + const char* value; + } locale_entry; -extern locale_entry en_locales[]; -extern const int en_locale_count; + typedef struct { + const char* lang_code; + locale_entry* entries; + int entry_count; + } locale_map; -const char* get_locale(); -void set_locale(const char key[2]); -const char* localize(const char* key); \ No newline at end of file + extern locale_entry en_locales[]; + extern const int en_locale_count; + + const char* get_locale(); + void set_locale(const char key[2]); + const char* get(const char* key); +} \ No newline at end of file diff --git a/libs/imgui-1.92.1/docs/CHANGELOG.txt b/libs/imgui-1.92.1/docs/CHANGELOG.txt index 7f12f6a..2241825 100644 --- a/libs/imgui-1.92.1/docs/CHANGELOG.txt +++ b/libs/imgui-1.92.1/docs/CHANGELOG.txt @@ -3232,7 +3232,7 @@ Other Changes: - Platform IME: add ImGuiPlatformImeData::WantVisible, hide IME composition window when not used. (#2589) [@actboy168] - Platform IME: add ImGuiPlatformImeData::InputLineHeight. (#3113) [@liuliu] - Platform IME: [windows] call ImmSetCandidateWindow() to position candidate window. -- Backends: GLFW: Pass localized keys (matching keyboard layout). Fix e.g. CTRL+A, CTRL+Z, CTRL+Y shortcuts. +- Backends: GLFW: Pass locale::getd keys (matching keyboard layout). Fix e.g. CTRL+A, CTRL+Z, CTRL+Y shortcuts. We are now converting GLFW untranslated keycodes back to translated keycodes in order to match the behavior of other backend, and facilitate the use of GLFW with lettered-shortcuts API. (#456, #2625) - Backends: GLFW: Submit keys and key mods using io.AddKeyEvent(). (#2625, #4921) @@ -3246,7 +3246,7 @@ Other Changes: - Backends: Win32: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4921) - Backends: Win32: Maintain a MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted. - Backends: Win32: Submit gamepad data using io.AddKeyEvent/AddKeyAnalogEvent() functions, stopped writing to io.NavInputs[]. (#4921) -- Backends: SDL: Pass localized keys (matching keyboard layout). Fix e.g. CTRL+A, CTRL+Z, CTRL+Y shortcuts. (#456, #2625) +- Backends: SDL: Pass locale::getd keys (matching keyboard layout). Fix e.g. CTRL+A, CTRL+Z, CTRL+Y shortcuts. (#456, #2625) - Backends: SDL: Submit key data using io.AddKeyEvent(). Submit keymods using io.AddKeyModsEvent() at the same time. (#2625) - Backends: SDL: Retrieve mouse position using SDL_MOUSEMOTION/SDL_WINDOWEVENT_LEAVE + fallback when focused but not hovered/captured. - Backends: SDL: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4921) @@ -5112,7 +5112,7 @@ Other Changes: erroneously wrapped the value to one of the min/max edge. (#2024, #708, #320, #2075). - DragFloat: Disabled using power curve when one edge is FLT_MAX (broken in 1.61). (#2024) - DragFloat: Disabled setting a default drag speed when one edge is FLT_MAX. (#2024) -- SliderAngle: Added optional format argument to alter precision or localize the string. (#2150) [@podsvirov] +- SliderAngle: Added optional format argument to alter precision or locale::get the string. (#2150) [@podsvirov] - Window: Resizing from edges (with io.ConfigResizeWindowsFromEdges Beta flag) extends the hit region of root floating windows outside the window, making it easier to resize windows. Resize grips are also extended accordingly so there are no discontinuity when hovering between borders and corners. (#1495, #822) diff --git a/libs/imgui-1.92.1/examples/libs/glfw/include/GLFW/glfw3.h b/libs/imgui-1.92.1/examples/libs/glfw/include/GLFW/glfw3.h index f8ca3d6..c2e4ab1 100644 --- a/libs/imgui-1.92.1/examples/libs/glfw/include/GLFW/glfw3.h +++ b/libs/imgui-1.92.1/examples/libs/glfw/include/GLFW/glfw3.h @@ -2927,9 +2927,9 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); */ GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); -/*! @brief Returns the localized name of the specified printable key. +/*! @brief Returns the locale::getd name of the specified printable key. * - * This function returns the localized name of the specified printable key. + * This function returns the locale::getd name of the specified printable key. * This is intended for displaying key bindings to the user. * * If the key is `GLFW_KEY_UNKNOWN`, the scancode is used instead, otherwise @@ -2965,7 +2965,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); * * @param[in] key The key to query, or `GLFW_KEY_UNKNOWN`. * @param[in] scancode The scancode of the key to query. - * @return The localized name of the key, or `NULL`. + * @return The locale::getd name of the key, or `NULL`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. diff --git a/src/administration.cpp b/src/administration.cpp index a07e79a..4f996bf 100644 --- a/src/administration.cpp +++ b/src/administration.cpp @@ -337,7 +337,7 @@ void administration_create_from_file(char* save_file) administration_create(); strops_copy(g_administration.path, save_file, sizeof(g_administration.path)); - strops_copy(g_administration.program_version, PROGRAM_VERSION, sizeof(g_administration.program_version)); + strops_copy(g_administration.program_version, config::PROGRAM_VERSION, sizeof(g_administration.program_version)); } void administration_create_empty(char* save_file) @@ -349,7 +349,7 @@ void administration_create_empty(char* save_file) g_administration.next_sequence_number = 1; strops_copy(g_administration.path, save_file, sizeof(g_administration.path)); - strops_copy(g_administration.program_version, PROGRAM_VERSION, sizeof(g_administration.program_version)); + strops_copy(g_administration.program_version, config::PROGRAM_VERSION, sizeof(g_administration.program_version)); administration_company_info_set(administration_contact_create_empty()); } diff --git a/src/administration_reader.cpp b/src/administration_reader.cpp index e845e7c..801941b 100644 --- a/src/administration_reader.cpp +++ b/src/administration_reader.cpp @@ -30,7 +30,7 @@ bool administration_reader_open_new() { - // @localize + // @locale::get char const * lFilterPatterns[1] = { "*.openbook" }; char* save_path = tinyfd_saveFileDialog("Select destination", NULL, 1, lFilterPatterns, NULL); @@ -43,7 +43,7 @@ bool administration_reader_open_new() bool administration_reader_save_new() { - // @localize + // @locale::get char const * lFilterPatterns[1] = { "*.openbook" }; char* save_path = tinyfd_saveFileDialog("Select destination", NULL, 1, lFilterPatterns, NULL); @@ -58,7 +58,7 @@ bool administration_reader_save_new() bool administration_reader_open_existing(char* file_path) { if (file_path == NULL) { - // @localize + // @locale::get char const * lFilterPatterns[1] = { "*.openbook" }; file_path = tinyfd_openFileDialog("Select save file", NULL, 1, lFilterPatterns, NULL, 0); diff --git a/src/administration_writer.cpp b/src/administration_writer.cpp index 0ac0b40..6f58a21 100644 --- a/src/administration_writer.cpp +++ b/src/administration_writer.cpp @@ -35,10 +35,10 @@ mtx_t _save_file_mutex; static void on_administration_data_changed() { if (administration_writer_save_all_administration_info_blocking()) { - ui_set_status(localize("status.saved")); + ui_set_status(locale::get("status.saved")); } else { - ui_set_status(localize("status.saveFailed")); + ui_set_status(locale::get("status.saveFailed")); } } @@ -337,7 +337,7 @@ bool administration_writer_save_invoice_blocking(invoice inv) int buf_length = 150000; // Ballpark file content size. char* file_content = (char*)malloc(buf_length); memset(file_content, 0, buf_length); - memcpy(file_content, peppol_invoice_template, strlen(peppol_invoice_template)); + memcpy(file_content, file_template::peppol_invoice_template, strlen(file_template::peppol_invoice_template)); struct tm *tm_info = 0; char date_buffer[11]; // "YYYY-MM-DD" + null terminator @@ -412,7 +412,7 @@ bool administration_writer_save_invoice_blocking(invoice inv) tax_rate* tax_rate_buffer = (tax_rate*)malloc(sizeof(tax_rate)*administration_billing_item_count(&inv)); u32 tax_rate_count = administration_invoice_get_tax_rates(&inv, tax_rate_buffer); - u32 tax_subtotal_list_buffer_size = (u32)strlen(peppol_invoice_tax_subtotal_template) * 2 * tax_rate_count; // Ballpark list size. + u32 tax_subtotal_list_buffer_size = (u32)strlen(file_template::peppol_invoice_tax_subtotal_template) * 2 * tax_rate_count; // Ballpark list size. char* tax_subtotal_list_buffer = (char*)malloc(tax_subtotal_list_buffer_size); memset(tax_subtotal_list_buffer, 0, tax_subtotal_list_buffer_size); u32 tax_subtotal_list_buffer_cursor = 0; @@ -420,7 +420,7 @@ bool administration_writer_save_invoice_blocking(invoice inv) for (u32 i = 0; i < tax_rate_count; i++) { int tax_entry_buf_length = 0; - char* tax_entry_file_content = administration_writer_copy_template(peppol_invoice_tax_subtotal_template, &tax_entry_buf_length); + char* tax_entry_file_content = administration_writer_copy_template(file_template::peppol_invoice_tax_subtotal_template, &tax_entry_buf_length); tax_subtotal subtotal; administration_invoice_get_subtotal_for_tax_rate(&inv, tax_rate_buffer[i], &subtotal); @@ -455,7 +455,7 @@ bool administration_writer_save_invoice_blocking(invoice inv) billing_item* billing_item_buffer = (billing_item*)malloc(sizeof(billing_item) * administration_billing_item_count(&inv)); u32 billing_item_count = administration_billing_item_get_all_for_invoice(&inv, billing_item_buffer); - u32 billing_item_list_buffer_size = (u32)strlen(peppol_invoice_line_template) * 2 * billing_item_count; // Ballpark list size. + u32 billing_item_list_buffer_size = (u32)strlen(file_template::peppol_invoice_line_template) * 2 * billing_item_count; // Ballpark list size. char* billing_item_list_buffer = (char*)malloc(billing_item_list_buffer_size); memset(billing_item_list_buffer, 0, billing_item_list_buffer_size); u32 billing_item_list_buffer_cursor = 0; @@ -463,7 +463,7 @@ bool administration_writer_save_invoice_blocking(invoice inv) for (u32 i = 0; i < billing_item_count; i++) { int billing_item_buf_length = 0; - char* billing_item_file_content = administration_writer_copy_template(peppol_invoice_line_template, &billing_item_buf_length); + char* billing_item_file_content = administration_writer_copy_template(file_template::peppol_invoice_line_template, &billing_item_buf_length); billing_item bi = billing_item_buffer[i]; tax_rate rate; @@ -557,7 +557,7 @@ bool administration_writer_save_project_blocking(project project) bool result = 1; int buf_length = 0; - char* file_content = administration_writer_copy_template(project_save_template, &buf_length); + char* file_content = administration_writer_copy_template(file_template::project_save_template, &buf_length); struct tm *tm_info = 0; char date_buffer[11]; // "YYYY-MM-DD" + null terminator @@ -616,7 +616,7 @@ bool administration_writer_save_cost_center_blocking(cost_center cost) bool result = 1; int buf_length = 0; - char* file_content = administration_writer_copy_template(costcenter_save_template, &buf_length); + char* file_content = administration_writer_copy_template(file_template::costcenter_save_template, &buf_length); strops_replace(file_content, buf_length, "{{COSTCENTER_ID}}", cost.id); strops_replace(file_content, buf_length, "{{COSTCENTER_CODE}}", cost.code); @@ -664,7 +664,7 @@ bool administration_writer_save_tax_rate_blocking(tax_rate rate) bool result = 1; int buf_length = 0; - char* file_content = administration_writer_copy_template(taxrate_save_template, &buf_length); + char* file_content = administration_writer_copy_template(file_template::taxrate_save_template, &buf_length); strops_replace(file_content, buf_length, "{{TAXBRACKET_ID}}", rate.id); strops_replace(file_content, buf_length, "{{TAXBRACKET_COUNTRY}}", rate.country_code); @@ -715,7 +715,7 @@ bool administration_writer_save_contact_blocking(contact c) bool result = 1; int buf_length = 0; - char* file_content = administration_writer_copy_template(contact_save_template, &buf_length); + char* file_content = administration_writer_copy_template(file_template::contact_save_template, &buf_length); strops_replace(file_content, buf_length, "{{CONTACT_ID}}", c.id); strops_replace(file_content, buf_length, "{{CONTACT_NAME}}", c.name); @@ -779,11 +779,11 @@ bool administration_writer_save_all_administration_info_blocking() bool result = 1; int buf_length = 0; - char* file_content = administration_writer_copy_template(administration_save_template, &buf_length); + char* file_content = administration_writer_copy_template(file_template::administration_save_template, &buf_length); strops_replace_int32(file_content, buf_length, "{{NEXT_ID}}", administration_get_next_id()); strops_replace_int32(file_content, buf_length, "{{NEXT_SEQUENCE_NUMBER}}", administration_get_next_sequence_number()); - strops_replace(file_content, buf_length, "{{PROGRAM_VERSION}}", PROGRAM_VERSION); + strops_replace(file_content, buf_length, "{{PROGRAM_VERSION}}", config::PROGRAM_VERSION); ai_service ai_service = administration_get_ai_service(); strops_replace_int32(file_content, buf_length, "{{AI_SERVICE_PROVIDER}}", (s32)ai_service.provider); diff --git a/src/ai_providers/DeepSeek.cpp b/src/ai_providers/DeepSeek.cpp index 67d17c2..334f024 100644 --- a/src/ai_providers/DeepSeek.cpp +++ b/src/ai_providers/DeepSeek.cpp @@ -24,13 +24,15 @@ #include "httplib.h" #include "strops.hpp" #include "log.hpp" -#include "import_service.hpp" +#include "importer.hpp" #define QUERY_BUFFER_SIZE 1000000 char* query_buffer = 0; static bool _DeepSeek_query_with_file(char* query, size_t query_length, char* file_id, char** response) { + (void)file_id; + (void)query_length; assert(query_buffer); const char *api_key = administration_get_ai_service().api_key_public; @@ -78,6 +80,8 @@ static bool _DeepSeek_query_with_file(char* query, size_t query_length, char* fi static bool _DeepSeek_upload_file(char* file_path, char* file_id, size_t file_id_len) { + (void)file_id; + (void)file_id_len; const char *filename = strops_get_filename(file_path); FILE* orig_file = fopen(file_path, "r"); diff --git a/src/ai_providers/openAI.cpp b/src/ai_providers/openAI.cpp index 20c1fa4..415d8ce 100644 --- a/src/ai_providers/openAI.cpp +++ b/src/ai_providers/openAI.cpp @@ -24,7 +24,7 @@ #include "httplib.h" #include "strops.hpp" #include "log.hpp" -#include "import_service.hpp" +#include "importer.hpp" static bool _openAI_query_with_file(char* query, size_t query_length, char* file_id, char** response) { diff --git a/src/config.cpp b/src/config.cpp deleted file mode 100644 index 9ab8e90..0000000 --- a/src/config.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* -* 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 "config.hpp" - -const char* country_codes[] = { - // "AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR", - /*"DE", "GR", "HU", "IE", "IT", "LV", "LT", "LU", "MT",*/ "NL", - // "PL", "PT", "RO", "SK", "SI", "ES", "SE" -}; -s32 country_count = sizeof(country_codes) / sizeof(country_codes[0]); \ No newline at end of file diff --git a/src/import_service.cpp b/src/import_service.cpp deleted file mode 100644 index cff7fdb..0000000 --- a/src/import_service.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/* -* 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. -*/ - -#define _CRT_SECURE_NO_WARNINGS - -#include -#include -#include -#include - -#define CPPHTTPLIB_OPENSSL_SUPPORT -#include "httplib.h" -#include "log.hpp" -#include "import_service.hpp" -#include "strops.hpp" -#include "administration_reader.hpp" -#include "locales.hpp" - -ai_provider_impl _ai_get_impl() -{ - ai_provider provider = administration_get_ai_service().provider; - - switch(provider) - { - case AI_PROVIDER_OPENAI: return _chatgpt_api_provider; - case AI_PROVIDER_DEEPSEEK: return _deepseek_api_provider; - default: assert(0); break; - } - - return ai_provider_impl {0}; -} - -extern const char* peppol_invoice_template; -extern const char* peppol_invoice_line_template; - -static int _ai_document_to_invoice_t(void *arg) { - import_invoice_request* request = (import_invoice_request*)arg; - char* file_path = request->file_path; - ai_provider_impl impl = _ai_get_impl(); - - request->status = import_status::IMPORT_UPLOADING_FILE; - - char file_id[100]; - if (!impl.upload_file(file_path, file_id, 100)) { - request->status = import_status::IMPORT_DONE; - request->error = I_ERR_FAILED_UPLOAD; - return 0; - } - - request->status = import_status::IMPORT_QUERYING; - - size_t query_buffer_len = 50000; - char* template_buffer = (char*)malloc(query_buffer_len); - memset(template_buffer, 0, query_buffer_len); - - strncpy(template_buffer, peppol_invoice_template, query_buffer_len); - strops_replace(template_buffer, 50000, "{{INVOICE_LINE_LIST}}", peppol_invoice_line_template); - - char* ai_query = - "\n\nI have provided a file containing an invoice. Fill in the above Peppol 3.0 template with the information from the invoice.\n" - "Do not add any fields to the template. If you can't find data for a given field, leave it empty. Do not make up any information.\n" - "Only return the filled out template in valid XML format. Nothing else.\n\n" - "{{LINE_AMOUNT}} equals the net paid amount for an order line.\n" - "{{UNIT_PRICE}} is the net price per unit in an order line.\n" - "{{QUANTITY}} is the amount of units per order line. If this is not defined, default to 1.\n" - "If {{UNIT_PRICE}} is less than 1.00 and {{QUANTITY}} is more than 10, {{QUANTITY}} should equal 1, {{UNIT_PRICE}} should equal {{LINE_AMOUNT}} and {{ITEM_NAME}} should include the original {{QUANTITY}}.\n" // High quantity, small price, might result in incorrect unit price. e.g. 700x resistor for 2,00 total. - "{{UNIT_CODE}} should always be 'X' unless you know for sure know the line item amount is defined as a percentage, in which case it should be '%'.\n" - "Every invoice line will atleast have {{LINE_AMOUNT}} and {{ITEM_NAME}} defined.\n" - "{{LINE_TAX_PERCENT}} is the tax rate for the line item. This could also be described as VAT rate. Often an invoice only has 1 tax rate defined intstead of per line item.\n" - "{{LINE_TAX_ID}} should be set to the country code and tax rate, in the format 'CC/PP' where CC is the 2 letter country code and PP is the tax rate as a number with 2 decimals.\n" - "If a line item is taxted with vat reverse Charge, {{LINE_TAX_ID}} should be set to '00/AE'.\n" - "If a line item is exempt from Tax, {{LINE_TAX_ID}} should be set to '00/E'.\n" - "If a line item is categorized as zero rated goods, {{LINE_TAX_ID}} should be set to '00/Z'.\n" - "If a line item is a service outside scope of tax, {{LINE_TAX_ID}} should be set to '00/O'.\n" - "If a line item is VAT exempt for EEA intra-community supply of goods and services, {{LINE_TAX_ID}} should be set to '00/K'.\n" - "All of there tax rates can be declared as per line item, or per invoice.\n" - "If you can find the tax rate for 1 line item but not another, assume they are taxed at the same rate and their {{LINE_TAX_ID}} should match.\n" - "If shipping costs are provided, these should also be added to the result as a cac:InvoiceLine.\n" - "{{INVOICE_SEQUENCE_ID}} should be set to the provided invoice id or invoice number. This is always defined.\n" - "{{ISSUE_DATE}} is the date the invoice was issued and should be stored in format 'YYYY-MM-DD'.\n" - "{{DUE_DATE}} is the date the invoice is due and should be stored in format 'YYYY-MM-DD'. If the due date is not defined, {{DUE_DATE}} should equal 0.\n" - "{{DELIVERY_DATE}} might be defined and should be stored in format 'YYYY-MM-DD'. If the delivery date is not defined, {{DELIVERY_DATE}} should equal 0.\n" - "cac:AccountingSupplierParty contains all information of the supplier. This information might be under the section 'Supplier', 'Seller', 'Sold by' or something similar.\n" - "cac:AccountingCustomerParty contains all information of the customer. This information might be under the section 'Customer', 'Ordered by', 'Billing address' or something similar.\n" - "cac:Delivery contains the delivery address for physical goods. This information might be under the section 'Shipping address', 'Shipped to' or something similar. If this is not explicitly set, leave this section empty.\n" - ; - - size_t query_len = strlen(template_buffer); - strncpy(template_buffer + query_len, ai_query, query_buffer_len - query_len); - - request->status = import_status::IMPORT_WAITING_FOR_RESPONSE; - - char* response; - if (!impl.query_with_file(template_buffer, query_buffer_len, file_id, &response)) { - request->status = import_status::IMPORT_DONE; - request->error = I_ERR_FAILED_QUERY; - return 0; - } - - invoice inv; - if (!administration_reader_read_invoice_from_xml(&inv, response, strlen(response))) { - request->status = import_status::IMPORT_DONE; - request->error = I_ERR_FAILED_IMPORT; - return 0; - } - - inv.status = invoice_status::INVOICE_RECEIVED; - - // Set customer or supplier depending on incomming or outgoing. - contact my_info = administration_company_info_get(); - memcpy(&inv.customer, &my_info, sizeof(contact)); - strops_copy(inv.customer.id, MY_COMPANY_ID, MAX_LEN_ID); - - // Project and cost centers cannot be interpreted from file so are set to 0. - strops_copy(inv.project_id, "", MAX_LEN_ID); - strops_copy(inv.cost_center_id, "", MAX_LEN_ID); - - // Set document references and save copy to disk. - strops_copy(inv.document.original_path, file_path, MAX_LEN_PATH); - strops_copy(inv.document.copy_path, "", MAX_LEN_PATH); - - // Set dates. - if (inv.expires_at == 0) { - inv.expires_at = inv.issued_at + administration_get_default_invoice_expire_duration(); - } - - if (inv.delivered_at == 0) { - inv.delivered_at = inv.issued_at; - } - - free(template_buffer); - free(response); - - request->status = import_status::IMPORT_DONE; - request->result = administration_invoice_create_copy(&inv); - return 0; -} - -import_invoice_request* ai_document_to_invoice(char* file_path) -{ - import_invoice_request* result = (import_invoice_request*)malloc(sizeof(import_invoice_request)); - result->started_at = time(NULL); - result->error = I_ERR_SUCCESS; - result->status = import_status::IMPORT_STARTING; - strops_copy(result->file_path, file_path, MAX_LEN_PATH); - - thrd_t thr; - if (thrd_create(&thr, _ai_document_to_invoice_t, result) != thrd_success) { - return 0; - } - - return result; -} - -const char* import_status_to_str(import_status status) -{ - switch(status) - { - case import_status::IMPORT_STARTING: return localize("import.status.starting"); - case import_status::IMPORT_UPLOADING_FILE: return localize("import.status.uploading_file"); - case import_status::IMPORT_QUERYING: return localize("import.status.querying"); - case import_status::IMPORT_WAITING_FOR_RESPONSE: return localize("import.status.waiting_for_result"); - case import_status::IMPORT_DONE: return localize("import.status.done"); - } - return ""; -} - -const char* import_error_to_str(i_err error) -{ - switch(error) - { - case I_ERR_FAILED_UPLOAD: return localize("import.error.upload"); - case I_ERR_FAILED_QUERY: return localize("import.error.query"); - case I_ERR_FAILED_IMPORT: return localize("import.error.import"); - } - return ""; -} \ No newline at end of file diff --git a/src/importer.cpp b/src/importer.cpp new file mode 100644 index 0000000..404ee8c --- /dev/null +++ b/src/importer.cpp @@ -0,0 +1,188 @@ +/* +* 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. +*/ + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include + +#define CPPHTTPLIB_OPENSSL_SUPPORT +#include "httplib.h" +#include "log.hpp" +#include "importer.hpp" +#include "strops.hpp" +#include "administration_reader.hpp" +#include "locales.hpp" +#include "file_templates.hpp" + +ai_provider_impl _ai_get_impl() +{ + ai_provider provider = administration_get_ai_service().provider; + + switch(provider) + { + case AI_PROVIDER_OPENAI: return _chatgpt_api_provider; + case AI_PROVIDER_DEEPSEEK: return _deepseek_api_provider; + default: assert(0); break; + } + + return ai_provider_impl {0}; +} + +static int _ai_document_to_invoice_t(void *arg) { + import_invoice_request* request = (import_invoice_request*)arg; + char* file_path = request->file_path; + ai_provider_impl impl = _ai_get_impl(); + + request->status = import_status::IMPORT_UPLOADING_FILE; + + char file_id[100]; + if (!impl.upload_file(file_path, file_id, 100)) { + request->status = import_status::IMPORT_DONE; + request->error = I_ERR_FAILED_UPLOAD; + return 0; + } + + request->status = import_status::IMPORT_QUERYING; + + size_t query_buffer_len = 50000; + char* template_buffer = (char*)malloc(query_buffer_len); + memset(template_buffer, 0, query_buffer_len); + + strncpy(template_buffer, file_template::peppol_invoice_template, query_buffer_len); + strops_replace(template_buffer, 50000, "{{INVOICE_LINE_LIST}}", file_template::peppol_invoice_line_template); + + char* ai_query = + "\n\nI have provided a file containing an invoice. Fill in the above Peppol 3.0 template with the information from the invoice.\n" + "Do not add any fields to the template. If you can't find data for a given field, leave it empty. Do not make up any information.\n" + "Only return the filled out template in valid XML format. Nothing else.\n\n" + "{{LINE_AMOUNT}} equals the net paid amount for an order line.\n" + "{{UNIT_PRICE}} is the net price per unit in an order line.\n" + "{{QUANTITY}} is the amount of units per order line. If this is not defined, default to 1.\n" + "If {{UNIT_PRICE}} is less than 1.00 and {{QUANTITY}} is more than 10, {{QUANTITY}} should equal 1, {{UNIT_PRICE}} should equal {{LINE_AMOUNT}} and {{ITEM_NAME}} should include the original {{QUANTITY}}.\n" // High quantity, small price, might result in incorrect unit price. e.g. 700x resistor for 2,00 total. + "{{UNIT_CODE}} should always be 'X' unless you know for sure know the line item amount is defined as a percentage, in which case it should be '%'.\n" + "Every invoice line will atleast have {{LINE_AMOUNT}} and {{ITEM_NAME}} defined.\n" + "{{LINE_TAX_PERCENT}} is the tax rate for the line item. This could also be described as VAT rate. Often an invoice only has 1 tax rate defined intstead of per line item.\n" + "{{LINE_TAX_ID}} should be set to the country code and tax rate, in the format 'CC/PP' where CC is the 2 letter country code and PP is the tax rate as a number with 2 decimals.\n" + "If a line item is taxted with vat reverse Charge, {{LINE_TAX_ID}} should be set to '00/AE'.\n" + "If a line item is exempt from Tax, {{LINE_TAX_ID}} should be set to '00/E'.\n" + "If a line item is categorized as zero rated goods, {{LINE_TAX_ID}} should be set to '00/Z'.\n" + "If a line item is a service outside scope of tax, {{LINE_TAX_ID}} should be set to '00/O'.\n" + "If a line item is VAT exempt for EEA intra-community supply of goods and services, {{LINE_TAX_ID}} should be set to '00/K'.\n" + "All of there tax rates can be declared as per line item, or per invoice.\n" + "If you can find the tax rate for 1 line item but not another, assume they are taxed at the same rate and their {{LINE_TAX_ID}} should match.\n" + "If shipping costs are provided, these should also be added to the result as a cac:InvoiceLine.\n" + "{{INVOICE_SEQUENCE_ID}} should be set to the provided invoice id or invoice number. This is always defined.\n" + "{{ISSUE_DATE}} is the date the invoice was issued and should be stored in format 'YYYY-MM-DD'.\n" + "{{DUE_DATE}} is the date the invoice is due and should be stored in format 'YYYY-MM-DD'. If the due date is not defined, {{DUE_DATE}} should equal 0.\n" + "{{DELIVERY_DATE}} might be defined and should be stored in format 'YYYY-MM-DD'. If the delivery date is not defined, {{DELIVERY_DATE}} should equal 0.\n" + "cac:AccountingSupplierParty contains all information of the supplier. This information might be under the section 'Supplier', 'Seller', 'Sold by' or something similar.\n" + "cac:AccountingCustomerParty contains all information of the customer. This information might be under the section 'Customer', 'Ordered by', 'Billing address' or something similar.\n" + "cac:Delivery contains the delivery address for physical goods. This information might be under the section 'Shipping address', 'Shipped to' or something similar. If this is not explicitly set, leave this section empty.\n" + ; + + size_t query_len = strlen(template_buffer); + strncpy(template_buffer + query_len, ai_query, query_buffer_len - query_len); + + request->status = import_status::IMPORT_WAITING_FOR_RESPONSE; + + char* response; + if (!impl.query_with_file(template_buffer, query_buffer_len, file_id, &response)) { + request->status = import_status::IMPORT_DONE; + request->error = I_ERR_FAILED_QUERY; + return 0; + } + + invoice inv; + if (!administration_reader_read_invoice_from_xml(&inv, response, strlen(response))) { + request->status = import_status::IMPORT_DONE; + request->error = I_ERR_FAILED_IMPORT; + return 0; + } + + inv.status = invoice_status::INVOICE_RECEIVED; + + // Set customer or supplier depending on incomming or outgoing. + contact my_info = administration_company_info_get(); + memcpy(&inv.customer, &my_info, sizeof(contact)); + strops_copy(inv.customer.id, MY_COMPANY_ID, MAX_LEN_ID); + + // Project and cost centers cannot be interpreted from file so are set to 0. + strops_copy(inv.project_id, "", MAX_LEN_ID); + strops_copy(inv.cost_center_id, "", MAX_LEN_ID); + + // Set document references and save copy to disk. + strops_copy(inv.document.original_path, file_path, MAX_LEN_PATH); + strops_copy(inv.document.copy_path, "", MAX_LEN_PATH); + + // Set dates. + if (inv.expires_at == 0) { + inv.expires_at = inv.issued_at + administration_get_default_invoice_expire_duration(); + } + + if (inv.delivered_at == 0) { + inv.delivered_at = inv.issued_at; + } + + free(template_buffer); + free(response); + + request->status = import_status::IMPORT_DONE; + request->result = administration_invoice_create_copy(&inv); + return 0; +} + +import_invoice_request* ai_document_to_invoice(char* file_path) +{ + import_invoice_request* result = (import_invoice_request*)malloc(sizeof(import_invoice_request)); + result->started_at = time(NULL); + result->error = I_ERR_SUCCESS; + result->status = import_status::IMPORT_STARTING; + strops_copy(result->file_path, file_path, MAX_LEN_PATH); + + thrd_t thr; + if (thrd_create(&thr, _ai_document_to_invoice_t, result) != thrd_success) { + return 0; + } + + return result; +} + +const char* import_status_to_str(import_status status) +{ + switch(status) + { + case import_status::IMPORT_STARTING: return locale::get("import.status.starting"); + case import_status::IMPORT_UPLOADING_FILE: return locale::get("import.status.uploading_file"); + case import_status::IMPORT_QUERYING: return locale::get("import.status.querying"); + case import_status::IMPORT_WAITING_FOR_RESPONSE: return locale::get("import.status.waiting_for_result"); + case import_status::IMPORT_DONE: return locale::get("import.status.done"); + } + return ""; +} + +const char* import_error_to_str(i_err error) +{ + switch(error) + { + case I_ERR_FAILED_UPLOAD: return locale::get("import.error.upload"); + case I_ERR_FAILED_QUERY: return locale::get("import.error.query"); + case I_ERR_FAILED_IMPORT: return locale::get("import.error.import"); + } + return ""; +} \ No newline at end of file diff --git a/src/locales.cpp b/src/locales.cpp index 62bf6fb..ef2ff6a 100644 --- a/src/locales.cpp +++ b/src/locales.cpp @@ -19,35 +19,37 @@ #include "locales.hpp" -locale_map locales[] = { - {"en", en_locales, en_locale_count}, - // Add new locales here. -}; - -const int locale_map_count = sizeof(locales) / sizeof(locales[0]); - -locale_map g_locale = locales[0]; // Default to english. - -const char* get_locale() -{ - return g_locale.lang_code; -} +namespace locale { + static locale_map locales[] = { + {"en", locale::en_locales, locale::en_locale_count}, + // Add new locales here. + }; + + static const int locale_map_count = sizeof(locales) / sizeof(locales[0]); + static locale_map g_locale = locales[0]; // Default to english. + + const char* locale::get_locale() + { + return g_locale.lang_code; + } -void set_locale(const char* key) -{ - for (int i = 0; i < locale_map_count; ++i) { - if (strcmp(locales[i].lang_code, key) == 0) { - g_locale = locales[i]; + void locale::set_locale(const char* key) + { + for (int i = 0; i < locale_map_count; ++i) { + if (strcmp(locales[i].lang_code, key) == 0) { + g_locale = locales[i]; + } } } -} -const char* localize(const char* key) -{ - for (int i = 0; i < g_locale.entry_count; ++i) { - if (strcmp(g_locale.entries[i].key, key) == 0) { - return g_locale.entries[i].value; + const char* locale::get(const char* key) + { + for (int i = 0; i < g_locale.entry_count; ++i) { + if (strcmp(g_locale.entries[i].key, key) == 0) { + return g_locale.entries[i].value; + } } + return key; } - return key; + } \ No newline at end of file diff --git a/src/locales/en.cpp b/src/locales/en.cpp index d311b36..9410663 100644 --- a/src/locales/en.cpp +++ b/src/locales/en.cpp @@ -16,7 +16,7 @@ #include "locales.hpp" -locale_entry en_locales[] = { +locale::locale_entry locale::en_locales[] = { // General UI strings. {"ui.unsavedProject", "[unsaved project]"}, {"ui.workingOn", "Working on"}, @@ -209,4 +209,4 @@ locale_entry en_locales[] = { {"import.error.import","Failure: Failed to import result from service"}, }; -const int en_locale_count = sizeof(en_locales) / sizeof(en_locales[0]); \ No newline at end of file +const int locale::en_locale_count = sizeof(locale::en_locales) / sizeof(locale::en_locales[0]); \ No newline at end of file diff --git a/src/ui/imgui_extensions.cpp b/src/ui/imgui_extensions.cpp index 4a0117b..8c8f4c4 100644 --- a/src/ui/imgui_extensions.cpp +++ b/src/ui/imgui_extensions.cpp @@ -13,7 +13,7 @@ namespace ImGui void InputTextWithError(const char* text, char* buffer, size_t buf_size, bool has_error) { if (has_error) { - ImGui::PushStyleColor(ImGuiCol_Border, COLOR_ERROR_OUTLINE); + ImGui::PushStyleColor(ImGuiCol_Border, config::colors::COLOR_ERROR_OUTLINE); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.5f); } ImGui::InputText(text, buffer, buf_size); @@ -29,7 +29,7 @@ namespace ImGui ImGui::SetNextItemWidth(widthAvailable*0.5f); if (has_error) { - ImGui::PushStyleColor(ImGuiCol_Border, COLOR_ERROR_OUTLINE); + ImGui::PushStyleColor(ImGuiCol_Border, config::colors::COLOR_ERROR_OUTLINE); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.5f); } ImGui::InputTextWithHint(hint, hint, buffer, buf_size); @@ -53,7 +53,7 @@ namespace ImGui { const char *filterPatterns[] = { "*.pdf" }; const char *file = tinyfd_openFileDialog( - "Choose a file", // dialog title // @localize + "Choose a file", // dialog title // @locale::get NULL, // default path 1, // number of filter patterns filterPatterns, // filter patterns array @@ -76,7 +76,7 @@ namespace ImGui result = true; } ImGui::SameLine(); - ImGui::TextWrapped("Selected: %s", buffer); // @localize + ImGui::TextWrapped("Selected: %s", buffer); // @locale::get } @@ -90,16 +90,16 @@ namespace ImGui ImGui::SetNextItemWidth(widthAvailable*0.5f); const char* countries[30]; - for (int x = 0; x < country_count; x++) + for (int x = 0; x < config::country_count; x++) { char locale_str[20]; - snprintf(locale_str, 20, "country.%s", country_codes[x]); - countries[x] = localize(locale_str); + snprintf(locale_str, 20, "country.%s", config::country_codes[x]); + countries[x] = locale::get(locale_str); } - for (int i = 0; i < country_count; i++) + for (int i = 0; i < config::country_count; i++) { - if (strcmp(country_codes[i], buffer) == 0) + if (strcmp(config::country_codes[i], buffer) == 0) { selected_country = countries[i]; break; @@ -109,13 +109,13 @@ namespace ImGui int selected_country_index = -1; if (!has_a_selection) { - ImGui::PushStyleColor(ImGuiCol_Border, COLOR_ERROR_OUTLINE); + ImGui::PushStyleColor(ImGuiCol_Border, config::colors::COLOR_ERROR_OUTLINE); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.5f); } - if (ImGui::BeginCombo(localize("contact.form.country"), selected_country)) + if (ImGui::BeginCombo(locale::get("contact.form.country"), selected_country)) { - for (int n = 0; n < country_count; n++) + for (int n = 0; n < config::country_count; n++) { bool is_selected = (selected_country == countries[n]); if (ImGui::Selectable(countries[n], is_selected)) { @@ -136,7 +136,7 @@ namespace ImGui } if (selected_country_index != -1) { - strops_copy(buffer, country_codes[selected_country_index], buf_size); + strops_copy(buffer, config::country_codes[selected_country_index], buf_size); } } @@ -144,9 +144,9 @@ namespace ImGui { float widthAvailable = ImGui::GetContentRegionAvail().x; ImGui::SetNextItemWidth(widthAvailable*0.5f); - const char* customer_types[2] = { localize("contact.form.type.business"), localize("contact.form.type.consumer") }; + const char* customer_types[2] = { locale::get("contact.form.type.business"), locale::get("contact.form.type.consumer") }; int currentItem = static_cast(*type); - if (ImGui::Combo(localize("contact.form.type"), ¤tItem, customer_types, IM_ARRAYSIZE(customer_types))) + if (ImGui::Combo(locale::get("contact.form.type"), ¤tItem, customer_types, IM_ARRAYSIZE(customer_types))) { *type = static_cast(currentItem); } @@ -159,7 +159,7 @@ namespace ImGui static bool is_open = false; if (has_error) { - ImGui::PushStyleColor(ImGuiCol_Border, COLOR_ERROR_OUTLINE); + ImGui::PushStyleColor(ImGuiCol_Border, config::colors::COLOR_ERROR_OUTLINE); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.5f); } ImGui::InputTextWithHint(hint, hint, buffer, buf_size); @@ -230,7 +230,7 @@ namespace ImGui snprintf(autocomplete_strings[i], 200, "%s (%s %s)", autocomplete_list[i].name, autocomplete_list[i].address.address1, autocomplete_list[i].address.address2); } - int autocomplete_index = ImGui::TextInputWithAutocomplete(localize("contact.form.fullname"), + int autocomplete_index = ImGui::TextInputWithAutocomplete(locale::get("contact.form.fullname"), buffer->name, IM_ARRAYSIZE(buffer->name), (char**)autocomplete_strings, autocomplete_count, has_error); if (autocomplete_index != -1) @@ -266,12 +266,12 @@ namespace ImGui } int selected_costcenter_index = -1; - if (ImGui::BeginCombo(localize("invoice.form.costcenter"), selected_costcenter == NULL ? NULL : localize(selected_costcenter->description))) + if (ImGui::BeginCombo(locale::get("invoice.form.costcenter"), selected_costcenter == NULL ? NULL : locale::get(selected_costcenter->description))) { for (u32 n = 0; n < costcenter_count; n++) { bool is_selected = selected_costcenter && strcmp(selected_costcenter->id, buffer[n].id) == 0; - if (ImGui::Selectable(localize(buffer[n].description), is_selected)) { + if (ImGui::Selectable(locale::get(buffer[n].description), is_selected)) { selected_costcenter_index = n; } } @@ -307,7 +307,7 @@ namespace ImGui } int selected_project_index = -1; - if (ImGui::BeginCombo(localize("invoice.form.project"), selected_project == NULL ? NULL : selected_project->description)) + if (ImGui::BeginCombo(locale::get("invoice.form.project"), selected_project == NULL ? NULL : selected_project->description)) { for (u32 n = 0; n < project_count; n++) { @@ -356,13 +356,13 @@ namespace ImGui if (strcmp(selected_tax_rate->country_code, "00") == 0) { char category_code_desc[MAX_LEN_LONG_DESC]; snprintf(category_code_desc, MAX_LEN_LONG_DESC, "taxcategory.%s", selected_tax_rate->category_code); - snprintf(rate_str_buf, 40, "%s", localize(category_code_desc)); + snprintf(rate_str_buf, 40, "%s", locale::get(category_code_desc)); } else snprintf(rate_str_buf, 40, "%s/%.1f%%", selected_tax_rate->country_code, selected_tax_rate->rate); } if (has_error) { - ImGui::PushStyleColor(ImGuiCol_Border, COLOR_ERROR_OUTLINE); + ImGui::PushStyleColor(ImGuiCol_Border, config::colors::COLOR_ERROR_OUTLINE); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.5f); } @@ -375,7 +375,7 @@ namespace ImGui if (strcmp(buffer[n].country_code, "00") == 0) { char category_code_desc[MAX_LEN_LONG_DESC]; snprintf(category_code_desc, MAX_LEN_LONG_DESC, "taxcategory.%s", buffer[n].category_code); - snprintf(rate_str_buf, 40, "%s", localize(category_code_desc)); + snprintf(rate_str_buf, 40, "%s", locale::get(category_code_desc)); } else snprintf(rate_str_buf, 40, "%s/%.1f%%", buffer[n].country_code, buffer[n].rate); diff --git a/src/ui/ui_contacts.cpp b/src/ui/ui_contacts.cpp index ffed39a..e282374 100644 --- a/src/ui/ui_contacts.cpp +++ b/src/ui/ui_contacts.cpp @@ -32,11 +32,11 @@ 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::FormInputTextWithErrorHint(locale::get("contact.form.address1"), buffer->address1, IM_ARRAYSIZE(buffer->address1), last_err & A_ERR_MISSING_ADDRESS1); + ImGui::FormInputTextWithErrorHint(locale::get("contact.form.address2"), buffer->address2, IM_ARRAYSIZE(buffer->address2), 0); + ImGui::FormInputTextWithErrorHint(locale::get("contact.form.city"), buffer->city, IM_ARRAYSIZE(buffer->city), last_err & A_ERR_MISSING_CITY); + ImGui::FormInputTextWithErrorHint(locale::get("contact.form.postal"), buffer->postal, IM_ARRAYSIZE(buffer->postal), last_err & A_ERR_MISSING_POSTAL); + ImGui::FormInputTextWithErrorHint(locale::get("contact.form.region"), buffer->region, IM_ARRAYSIZE(buffer->region), 0); ImGui::FormCountryCombo(buffer->country_code, IM_ARRAYSIZE(buffer->country_code)); } @@ -59,7 +59,7 @@ void draw_addressee_form_ex(delivery_info* buffer, bool viewing_only = false) if (!viewing_only) ImGui::EndDisabled(); - ImGui::FormInputTextWithErrorHint(localize("contact.form.fullname"), buffer->name, IM_ARRAYSIZE(buffer->name), last_err & A_ERR_MISSING_NAME); + ImGui::FormInputTextWithErrorHint(locale::get("contact.form.fullname"), buffer->name, IM_ARRAYSIZE(buffer->name), last_err & A_ERR_MISSING_NAME); ui_draw_address_form(&buffer->address, last_err); @@ -79,7 +79,7 @@ void draw_contact_form_ex(contact* buffer, bool viewing_only = false, bool with_ 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); + else ImGui::FormInputTextWithErrorHint(locale::get("contact.form.fullname"), buffer->name, IM_ARRAYSIZE(buffer->name), last_err & A_ERR_MISSING_NAME); ui_draw_address_form(&buffer->address, last_err); @@ -88,13 +88,13 @@ void draw_contact_form_ex(contact* buffer, bool viewing_only = false, bool with_ // 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(locale::get("contact.form.taxnumber"), buffer->taxid, IM_ARRAYSIZE(buffer->taxid), last_err & A_ERR_MISSING_TAXID); + ImGui::FormInputTextWithErrorHint(locale::get("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); + ImGui::FormInputTextWithErrorHint(locale::get("contact.form.email"), buffer->email, IM_ARRAYSIZE(buffer->email), last_err & A_ERR_MISSING_EMAIL); + ImGui::FormInputTextWithErrorHint(locale::get("contact.form.phonenumber"), buffer->phone_number, IM_ARRAYSIZE(buffer->phone_number), 0); + ImGui::FormInputTextWithErrorHint(locale::get("contact.form.bankaccount"), buffer->bank_account, IM_ARRAYSIZE(buffer->bank_account), 0); if (viewing_only) ImGui::EndDisabled(); ImGui::PopID(); @@ -113,7 +113,7 @@ static void draw_contact_list() if (max_page == 0) max_page = 1; // Table header controls: create button and pagination. - if (ImGui::Button(localize("form.create"))) + if (ImGui::Button(locale::get("form.create"))) { current_view_state = view_state::CREATE; active_contact = administration_contact_create_empty(); @@ -126,7 +126,7 @@ static void draw_contact_list() 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 (ImGui::Button(locale::get("ui.prev")) && current_page > 0) current_page--; if (!enable_prev) ImGui::EndDisabled(); ImGui::SameLine(); @@ -136,16 +136,16 @@ static void draw_contact_list() 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 (ImGui::Button(locale::get("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(locale::get("contact.table.identifier"), ImGuiTableColumnFlags_WidthFixed, 80); + ImGui::TableSetupColumn(locale::get("contact.table.name"), ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn(locale::get("contact.table.address"), ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 160); ImGui::TableHeadersRow(); @@ -163,7 +163,7 @@ static void draw_contact_list() ImGui::TableSetColumnIndex(3); char btn_name[20]; - snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.view"), i); + snprintf(btn_name, sizeof(btn_name), "%s##%d", locale::get("form.view"), i); if (ImGui::Button(btn_name)) { active_contact = c; current_view_state = view_state::VIEW; @@ -171,14 +171,14 @@ static void draw_contact_list() ImGui::SameLine(); - snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.change"), i); + snprintf(btn_name, sizeof(btn_name), "%s##%d", locale::get("form.change"), i); if (ImGui::Button(btn_name)) { active_contact = c; current_view_state = view_state::EDIT; } ImGui::SameLine(); - snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.delete"), i); + snprintf(btn_name, sizeof(btn_name), "%s##%d", locale::get("form.delete"), i); if (ImGui::Button(btn_name)) { selected_for_removal = c; ImGui::OpenPopup("ConfirmDeletePopup"); @@ -187,15 +187,15 @@ static void draw_contact_list() // Confirmation popup before contact is deleted definitively. if (ImGui::BeginPopupModal("ConfirmDeletePopup", nullptr, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoTitleBar)) { - ImGui::Text(localize("form.confirmDelete")); + ImGui::Text(locale::get("form.confirmDelete")); ImGui::Separator(); - if (ImGui::Button(localize("form.yes"), ImVec2(120, 0))) { + if (ImGui::Button(locale::get("form.yes"), ImVec2(120, 0))) { administration_contact_remove(selected_for_removal); ImGui::CloseCurrentPopup(); } ImGui::SameLine(); - if (ImGui::Button(localize("form.no"), ImVec2(120, 0))) { + if (ImGui::Button(locale::get("form.no"), ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); @@ -207,7 +207,7 @@ static void draw_contact_list() static void ui_draw_contacts_create() { - if (ImGui::Button(localize("form.back"))) { + if (ImGui::Button(locale::get("form.back"))) { current_view_state = view_state::LIST; } @@ -218,7 +218,7 @@ static void ui_draw_contacts_create() if (!can_save) ImGui::BeginDisabled(); // Save button ImGui::Spacing(); - if (ImGui::Button(localize("form.save"))) { + if (ImGui::Button(locale::get("form.save"))) { administration_contact_add(active_contact); current_view_state = view_state::LIST; } @@ -227,7 +227,7 @@ static void ui_draw_contacts_create() static void ui_draw_contacts_update() { - if (ImGui::Button(localize("form.back"))) { + if (ImGui::Button(locale::get("form.back"))) { current_view_state = view_state::LIST; } @@ -238,7 +238,7 @@ static void ui_draw_contacts_update() if (!can_save) ImGui::BeginDisabled(); // Save button ImGui::Spacing(); - if (ImGui::Button(localize("form.save"))) { + if (ImGui::Button(locale::get("form.save"))) { administration_contact_update(active_contact); current_view_state = view_state::LIST; } @@ -254,7 +254,7 @@ void ui_draw_contacts() case view_state::EDIT: ui_draw_contacts_update(); break; case view_state::VIEW: - if (ImGui::Button(localize("form.back"))) { + if (ImGui::Button(locale::get("form.back"))) { current_view_state = view_state::LIST; } diff --git a/src/ui/ui_earnings.cpp b/src/ui/ui_earnings.cpp index 82fe1af..2106015 100644 --- a/src/ui/ui_earnings.cpp +++ b/src/ui/ui_earnings.cpp @@ -45,7 +45,7 @@ void ui_draw_earnings() bool enable_prev = current_page > 0; if (!enable_prev) ImGui::BeginDisabled(); - if (ImGui::Button(localize("ui.prev")) && current_page > 0) current_page--; + if (ImGui::Button(locale::get("ui.prev")) && current_page > 0) current_page--; if (!enable_prev) ImGui::EndDisabled(); ImGui::SameLine(); @@ -54,7 +54,7 @@ void ui_draw_earnings() 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 (ImGui::Button(locale::get("ui.next")) && current_page < max_page-1) current_page++; if (!enable_next) ImGui::EndDisabled(); ImGui::Spacing(); @@ -100,7 +100,7 @@ void ui_draw_earnings() // Uncategorized income and expenses if (has_uncategorized_revenue || has_uncategorized_taxes || has_uncategorized_expenses) { ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); ImGui::Text("(%s)", localize("statement.uncategorized")); + ImGui::TableSetColumnIndex(0); ImGui::Text("(%s)", locale::get("statement.uncategorized")); ImGui::TableSetColumnIndex(1); ImGui::Text(""); ImGui::TableSetColumnIndex(2); ImGui::Text(""); ImGui::TableSetColumnIndex(3); ImGui::Text(""); @@ -109,7 +109,7 @@ void ui_draw_earnings() if (has_uncategorized_revenue) { ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); ImGui::Text(" %s", localize("statement.revenue")); + ImGui::TableSetColumnIndex(0); ImGui::Text(" %s", locale::get("statement.revenue")); ImGui::TableSetColumnIndex(1); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 0].uncategorized_revenue, currency_symbol); ImGui::TableSetColumnIndex(2); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 1].uncategorized_revenue, currency_symbol); ImGui::TableSetColumnIndex(3); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 2].uncategorized_revenue, currency_symbol); @@ -118,7 +118,7 @@ void ui_draw_earnings() if (has_uncategorized_taxes) { ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); ImGui::Text(" %s", localize("statement.tax")); + ImGui::TableSetColumnIndex(0); ImGui::Text(" %s", locale::get("statement.tax")); ImGui::TableSetColumnIndex(1); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 0].uncategorized_taxes, currency_symbol); ImGui::TableSetColumnIndex(2); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 1].uncategorized_taxes, currency_symbol); ImGui::TableSetColumnIndex(3); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 2].uncategorized_taxes, currency_symbol); @@ -127,7 +127,7 @@ void ui_draw_earnings() if (has_uncategorized_expenses) { ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); ImGui::Text(" %s", localize("statement.expenses")); + ImGui::TableSetColumnIndex(0); ImGui::Text(" %s", locale::get("statement.expenses")); ImGui::TableSetColumnIndex(1); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 0].uncategorized_expenses, currency_symbol); ImGui::TableSetColumnIndex(2); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 1].uncategorized_expenses, currency_symbol); ImGui::TableSetColumnIndex(3); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 2].uncategorized_expenses, currency_symbol); @@ -154,7 +154,7 @@ void ui_draw_earnings() ImGui::PushFont(fontBold); ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); ImGui::Text(" %s", localize("statement.revenue")); + ImGui::TableSetColumnIndex(0); ImGui::Text(" %s", locale::get("statement.revenue")); ImGui::TableSetColumnIndex(1); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 0].reports[p].revenue, currency_symbol); ImGui::TableSetColumnIndex(2); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 1].reports[p].revenue, currency_symbol); ImGui::TableSetColumnIndex(3); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 2].reports[p].revenue, currency_symbol); @@ -162,7 +162,7 @@ void ui_draw_earnings() ImGui::PopFont(); ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); ImGui::Text(" %s", localize("statement.tax")); + ImGui::TableSetColumnIndex(0); ImGui::Text(" %s", locale::get("statement.tax")); ImGui::TableSetColumnIndex(1); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 0].reports[p].taxes, currency_symbol); ImGui::TableSetColumnIndex(2); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 1].reports[p].taxes, currency_symbol); ImGui::TableSetColumnIndex(3); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 2].reports[p].taxes, currency_symbol); @@ -170,7 +170,7 @@ void ui_draw_earnings() ImGui::PushFont(fontBold); ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); ImGui::Text(" %s", localize("statement.expenses")); + ImGui::TableSetColumnIndex(0); ImGui::Text(" %s", locale::get("statement.expenses")); ImGui::TableSetColumnIndex(1); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 0].reports[p].expenses_total, currency_symbol); ImGui::TableSetColumnIndex(2); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 1].reports[p].expenses_total, currency_symbol); ImGui::TableSetColumnIndex(3); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 2].reports[p].expenses_total, currency_symbol); @@ -182,7 +182,7 @@ void ui_draw_earnings() project_expense* expense = &report->expenses[e]; if (!expense->expense_used_in_project) continue; ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); ImGui::Text(" %s", localize(expense->description)); + ImGui::TableSetColumnIndex(0); ImGui::Text(" %s", locale::get(expense->description)); ImGui::TableSetColumnIndex(1); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 0].reports[p].expenses[e].total, currency_symbol); ImGui::TableSetColumnIndex(2); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 1].reports[p].expenses[e].total, currency_symbol); ImGui::TableSetColumnIndex(3); ImGui::Text("%.0f %s", statement->quarters[quarter_start + 2].reports[p].expenses[e].total, currency_symbol); @@ -194,7 +194,7 @@ void ui_draw_earnings() ImGui::PushFont(fontBold); ImGui::TableNextRow(); - ImGui::TableNextColumn(); ImGui::TextUnformatted(localize("statement.profit")); + ImGui::TableNextColumn(); ImGui::TextUnformatted(locale::get("statement.profit")); #define PUSH_PROFIT_COLUMN(_profit)\ ImGui::TableNextColumn(); \ diff --git a/src/ui/ui_expenses.cpp b/src/ui/ui_expenses.cpp index c02cdce..acb53a8 100644 --- a/src/ui/ui_expenses.cpp +++ b/src/ui/ui_expenses.cpp @@ -27,7 +27,7 @@ #include "administration.hpp" #include "administration_writer.hpp" #include "locales.hpp" -#include "import_service.hpp" +#include "importer.hpp" static import_invoice_request* active_import_request = 0; @@ -65,8 +65,8 @@ static void draw_expense_form(invoice* buffer, bool viewing_only = false) { if (viewing_only) ImGui::BeginDisabled(); - ImGui::Text("%s: %s", localize("invoice.form.invoicenumber"), buffer->sequential_number); - ImGui::Text("%s: %s", localize("invoice.form.billedTo"), buffer->customer.name); + ImGui::Text("%s: %s", locale::get("invoice.form.invoicenumber"), buffer->sequential_number); + ImGui::Text("%s: %s", locale::get("invoice.form.billedTo"), buffer->customer.name); tm issued_at_date = *gmtime(&buffer->issued_at); if (ImGui::DatePicker("##issuedAt", issued_at_date)) @@ -74,7 +74,7 @@ static void draw_expense_form(invoice* buffer, bool viewing_only = false) buffer->issued_at = mktime(&issued_at_date); } ImGui::SameLine(); - ImGui::Text(localize("invoice.form.issuedat")); + ImGui::Text(locale::get("invoice.form.issuedat")); tm expires_at_date = *gmtime(&buffer->expires_at); if (ImGui::DatePicker("##expiresAt", expires_at_date)) @@ -82,7 +82,7 @@ static void draw_expense_form(invoice* buffer, bool viewing_only = false) buffer->expires_at = mktime(&expires_at_date); } ImGui::SameLine(); - ImGui::Text(localize("invoice.form.expiresat")); + ImGui::Text(locale::get("invoice.form.expiresat")); tm delivered_at_date = *gmtime(&buffer->delivered_at); if (ImGui::DatePicker("##deliveredAt", delivered_at_date)) @@ -90,23 +90,23 @@ static void draw_expense_form(invoice* buffer, bool viewing_only = false) buffer->delivered_at = mktime(&delivered_at_date); } ImGui::SameLine(); - ImGui::Text(localize("invoice.form.deliveredat")); + ImGui::Text(locale::get("invoice.form.deliveredat")); ImGui::Separator(); - if (ImGui::FormInvoiceFileSelector("Select file...", buffer->document.original_path)) { // @localize + if (ImGui::FormInvoiceFileSelector("Select file...", buffer->document.original_path)) { // @locale::get buffer->document.copy_path[0] = 0; } ImGui::Separator(); - ImGui::Text(localize("invoice.form.supplier")); + ImGui::Text(locale::get("invoice.form.supplier")); draw_contact_form_ex(&buffer->supplier, false, true); - ImGui::Checkbox(localize("invoice.form.triangulation"), &buffer->is_triangulation); + ImGui::Checkbox(locale::get("invoice.form.triangulation"), &buffer->is_triangulation); if (buffer->is_triangulation) { ImGui::Spacing(); - ImGui::Text(localize("invoice.form.shippinginformation")); + ImGui::Text(locale::get("invoice.form.shippinginformation")); draw_addressee_form_ex(&buffer->addressee, 0); } ImGui::Separator(); @@ -122,7 +122,7 @@ static void draw_expense_form(invoice* buffer, bool viewing_only = false) bool max_items_reached = administration_billing_item_count(buffer) >= MAX_BILLING_ITEMS; if (max_items_reached) ImGui::BeginDisabled(); - if (ImGui::Button(localize(localize("invoice.form.add")))) + if (ImGui::Button(locale::get(locale::get("invoice.form.add")))) { billing_item item = administration_billing_item_create_empty(); administration_billing_item_add_to_invoice(buffer, item); @@ -130,7 +130,7 @@ static void draw_expense_form(invoice* buffer, bool viewing_only = false) if (max_items_reached) ImGui::EndDisabled(); ImGui::SameLine(); - ImGui::Text("| %s: ", localize("invoice.form.currency")); + ImGui::Text("| %s: ", locale::get("invoice.form.currency")); ImGui::SameLine(); if (ImGui::FormCurrencyCombo(buffer->currency)) { @@ -146,7 +146,7 @@ static void ui_draw_expenses_list() { if (!administration_can_create_invoices()) { ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(0, 102, 204, 255)); // blue - ImGui::Text(localize("ui.invoiceRequirementP1")); + ImGui::Text(locale::get("ui.invoiceRequirementP1")); ImGui::PopStyleColor(); if (ImGui::IsItemHovered()) { @@ -157,7 +157,7 @@ static void ui_draw_expenses_list() } ImGui::SameLine(); - ImGui::Text(localize("ui.invoiceRequirementP2")); + ImGui::Text(locale::get("ui.invoiceRequirementP2")); return; } @@ -172,7 +172,7 @@ static void ui_draw_expenses_list() if (max_page == 0) max_page = 1; // Table header controls: create, import, and pagination. - if (ImGui::Button(localize("form.create"))) + if (ImGui::Button(locale::get("form.create"))) { current_view_state = view_state::CREATE; active_invoice = administration_invoice_create_empty(); // @leak @@ -183,7 +183,7 @@ static void ui_draw_expenses_list() char import_file_path[MAX_LEN_PATH] = {0}; ImGui::SameLine(); - if (ImGui::FormInvoiceFileSelector("+ Import", import_file_path)) { // @localize + if (ImGui::FormInvoiceFileSelector("+ Import", import_file_path)) { // @locale::get current_view_state = view_state::VIEW_IMPORT_REQUEST; active_invoice = administration_invoice_create_empty(); // @leak active_invoice.customer = administration_company_info_get(); @@ -200,7 +200,7 @@ static void ui_draw_expenses_list() 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 (ImGui::Button(locale::get("ui.prev")) && current_page > 0) current_page--; if (!enable_prev) ImGui::EndDisabled(); ImGui::SameLine(); @@ -210,19 +210,19 @@ static void ui_draw_expenses_list() 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 (ImGui::Button(locale::get("ui.next")) && current_page < max_page-1) current_page++; if (!enable_next) ImGui::EndDisabled(); ImGui::Spacing(); if (ImGui::BeginTable("TableInvoices", 7, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { - ImGui::TableSetupColumn(localize("invoice.table.invoicenumber"), ImGuiTableColumnFlags_WidthFixed, 120); - ImGui::TableSetupColumn(localize("invoice.table.sender")); - ImGui::TableSetupColumn(localize("invoice.table.customer")); - ImGui::TableSetupColumn(localize("invoice.table.issuedat")); - ImGui::TableSetupColumn(localize("invoice.table.total")); - ImGui::TableSetupColumn(localize("invoice.table.status")); + ImGui::TableSetupColumn(locale::get("invoice.table.invoicenumber"), ImGuiTableColumnFlags_WidthFixed, 120); + ImGui::TableSetupColumn(locale::get("invoice.table.sender")); + ImGui::TableSetupColumn(locale::get("invoice.table.customer")); + ImGui::TableSetupColumn(locale::get("invoice.table.issuedat")); + ImGui::TableSetupColumn(locale::get("invoice.table.total")); + ImGui::TableSetupColumn(locale::get("invoice.table.status")); ImGui::TableSetupColumn(""); ImGui::TableHeadersRow(); @@ -240,11 +240,11 @@ static void ui_draw_expenses_list() ImGui::TableSetColumnIndex(3); ImGui::Text(buf); ImGui::TableSetColumnIndex(4); ImGui::Text("%.2f %s", c.total, c.currency); - ImGui::TableSetColumnIndex(5); ImGui::Text("%s", localize(administration_invoice_get_status_string(&c))); + ImGui::TableSetColumnIndex(5); ImGui::Text("%s", locale::get(administration_invoice_get_status_string(&c))); ImGui::TableSetColumnIndex(6); char btn_name[20]; - snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.view"), i); + snprintf(btn_name, sizeof(btn_name), "%s##%d", locale::get("form.view"), i); if (ImGui::Button(btn_name)) { active_invoice = c; current_view_state = view_state::VIEW; @@ -252,14 +252,14 @@ static void ui_draw_expenses_list() ImGui::SameLine(); - snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.change"), i); + snprintf(btn_name, sizeof(btn_name), "%s##%d", locale::get("form.change"), i); if (ImGui::Button(btn_name)) { active_invoice = administration_invoice_create_copy(&c); // We create a copy because of billing item list pointers. current_view_state = view_state::EDIT; } ImGui::SameLine(); - snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.delete"), i); + snprintf(btn_name, sizeof(btn_name), "%s##%d", locale::get("form.delete"), i); if (ImGui::Button(btn_name)) { selected_for_removal = c; ImGui::OpenPopup("ConfirmDeletePopup"); @@ -268,15 +268,15 @@ static void ui_draw_expenses_list() // Confirmation popup before contact is deleted definitively. if (ImGui::BeginPopupModal("ConfirmDeletePopup", nullptr, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoTitleBar)) { - ImGui::Text(localize("form.confirmDelete")); + ImGui::Text(locale::get("form.confirmDelete")); ImGui::Separator(); - if (ImGui::Button(localize("form.yes"), ImVec2(120, 0))) { + if (ImGui::Button(locale::get("form.yes"), ImVec2(120, 0))) { administration_invoice_remove(&selected_for_removal); ImGui::CloseCurrentPopup(); } ImGui::SameLine(); - if (ImGui::Button(localize("form.no"), ImVec2(120, 0))) { + if (ImGui::Button(locale::get("form.no"), ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); @@ -289,7 +289,7 @@ static void ui_draw_expenses_list() static void ui_draw_expense_update() { - if (ImGui::Button(localize("form.back"))) { + if (ImGui::Button(locale::get("form.back"))) { current_view_state = view_state::LIST; } @@ -299,7 +299,7 @@ static void ui_draw_expense_update() if (!can_save) ImGui::BeginDisabled(); ImGui::Spacing(); - if (ImGui::Button(localize("form.save"))) { + if (ImGui::Button(locale::get("form.save"))) { administration_invoice_update(&active_invoice); current_view_state = view_state::LIST; @@ -313,7 +313,7 @@ static void ui_draw_expense_update() static void ui_draw_expense_create() { - if (ImGui::Button(localize("form.back"))) { + if (ImGui::Button(locale::get("form.back"))) { current_view_state = view_state::LIST; } @@ -323,7 +323,7 @@ static void ui_draw_expense_create() if (!can_save) ImGui::BeginDisabled(); ImGui::Spacing(); - if (ImGui::Button(localize("form.save"))) { + if (ImGui::Button(locale::get("form.save"))) { administration_invoice_add(&active_invoice); current_view_state = view_state::LIST; @@ -337,7 +337,7 @@ static void ui_draw_expense_create() static void ui_draw_expense_view() { - if (ImGui::Button(localize("form.back"))) { + if (ImGui::Button(locale::get("form.back"))) { current_view_state = view_state::LIST; } @@ -356,7 +356,7 @@ static void ui_draw_import_request() return; } else { - if (ImGui::Button(localize("form.back"))) { + if (ImGui::Button(locale::get("form.back"))) { current_view_state = view_state::LIST; active_import_request = 0; return; diff --git a/src/ui/ui_invoices.cpp b/src/ui/ui_invoices.cpp index 4a087be..ee816a9 100644 --- a/src/ui/ui_invoices.cpp +++ b/src/ui/ui_invoices.cpp @@ -60,14 +60,14 @@ void draw_invoice_items_form(invoice* invoice) if (ImGui::BeginTable("TableBillingItems", 9, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { ImGui::TableSetupColumn("##actions", ImGuiTableColumnFlags_WidthFixed, 20); - ImGui::TableSetupColumn(localize("invoice.table.amount"), ImGuiTableColumnFlags_WidthFixed, 80); - ImGui::TableSetupColumn(localize("invoice.table.description")); - ImGui::TableSetupColumn(localize("invoice.table.price"), ImGuiTableColumnFlags_WidthFixed, 100); - ImGui::TableSetupColumn(localize("invoice.table.discount"), ImGuiTableColumnFlags_WidthFixed, 100); - ImGui::TableSetupColumn(localize("invoice.table.net"), ImGuiTableColumnFlags_WidthFixed, 100); - ImGui::TableSetupColumn(localize("invoice.table.tax%"), ImGuiTableColumnFlags_WidthFixed, 120); - ImGui::TableSetupColumn(localize("invoice.table.tax"), ImGuiTableColumnFlags_WidthFixed, 100); - ImGui::TableSetupColumn(localize("invoice.table.total"), ImGuiTableColumnFlags_WidthFixed, 100); + ImGui::TableSetupColumn(locale::get("invoice.table.amount"), ImGuiTableColumnFlags_WidthFixed, 80); + ImGui::TableSetupColumn(locale::get("invoice.table.description")); + ImGui::TableSetupColumn(locale::get("invoice.table.price"), ImGuiTableColumnFlags_WidthFixed, 100); + ImGui::TableSetupColumn(locale::get("invoice.table.discount"), ImGuiTableColumnFlags_WidthFixed, 100); + ImGui::TableSetupColumn(locale::get("invoice.table.net"), ImGuiTableColumnFlags_WidthFixed, 100); + ImGui::TableSetupColumn(locale::get("invoice.table.tax%"), ImGuiTableColumnFlags_WidthFixed, 120); + ImGui::TableSetupColumn(locale::get("invoice.table.tax"), ImGuiTableColumnFlags_WidthFixed, 100); + ImGui::TableSetupColumn(locale::get("invoice.table.total"), ImGuiTableColumnFlags_WidthFixed, 100); ImGui::TableHeadersRow(); @@ -145,7 +145,7 @@ void draw_invoice_items_form(invoice* invoice) ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, IM_COL32(50, 50, 50, 255)); ImGui::TableSetColumnIndex(2); - ImGui::Text("%s %s", localize("invoice.form.finalSettlement"), administration_get_default_currency()); + ImGui::Text("%s %s", locale::get("invoice.form.finalSettlement"), administration_get_default_currency()); ImGui::TableSetColumnIndex(4); ImGui::InputFloat("##final_allowance", &invoice->allowance, 0.0f, 0.0f, "%.2f"); @@ -176,8 +176,8 @@ static void draw_invoice_form(invoice* buffer, bool viewing_only = false) { ImGui::BeginDisabled(); - ImGui::Text("%s: %s", localize("invoice.form.invoicenumber"), buffer->sequential_number); - ImGui::Text("%s: %s", localize("invoice.form.supplier"), buffer->supplier.name); + ImGui::Text("%s: %s", locale::get("invoice.form.invoicenumber"), buffer->sequential_number); + ImGui::Text("%s: %s", locale::get("invoice.form.supplier"), buffer->supplier.name); tm issued_at_date = *gmtime(&buffer->issued_at); if (ImGui::DatePicker("##issuedAt", issued_at_date)) @@ -185,7 +185,7 @@ static void draw_invoice_form(invoice* buffer, bool viewing_only = false) buffer->issued_at = mktime(&issued_at_date); } ImGui::SameLine(); - ImGui::Text(localize("invoice.form.issuedat")); + ImGui::Text(locale::get("invoice.form.issuedat")); tm expires_at_date = *gmtime(&buffer->expires_at); if (ImGui::DatePicker("##expiresAt", expires_at_date)) @@ -193,7 +193,7 @@ static void draw_invoice_form(invoice* buffer, bool viewing_only = false) buffer->expires_at = mktime(&expires_at_date); } ImGui::SameLine(); - ImGui::Text(localize("invoice.form.expiresat")); + ImGui::Text(locale::get("invoice.form.expiresat")); if (!viewing_only) ImGui::EndDisabled(); tm delivered_at_date = *gmtime(&buffer->delivered_at); @@ -202,23 +202,23 @@ static void draw_invoice_form(invoice* buffer, bool viewing_only = false) buffer->delivered_at = mktime(&delivered_at_date); } ImGui::SameLine(); - ImGui::Text(localize("invoice.form.deliveredat")); + ImGui::Text(locale::get("invoice.form.deliveredat")); ImGui::Separator(); - if (ImGui::FormInvoiceFileSelector("Select file...", buffer->document.original_path)) { // @localize + if (ImGui::FormInvoiceFileSelector("Select file...", buffer->document.original_path)) { // @locale::get buffer->document.copy_path[0] = 0; } ImGui::Separator(); - ImGui::Text(localize("invoice.form.billinginformation")); + ImGui::Text(locale::get("invoice.form.billinginformation")); draw_contact_form_ex(&buffer->customer, false, true); - ImGui::Checkbox(localize("invoice.form.triangulation"), &buffer->is_triangulation); + ImGui::Checkbox(locale::get("invoice.form.triangulation"), &buffer->is_triangulation); if (buffer->is_triangulation) { ImGui::Spacing(); - ImGui::Text(localize("invoice.form.shippinginformation")); + ImGui::Text(locale::get("invoice.form.shippinginformation")); draw_addressee_form_ex(&buffer->addressee, 0); } ImGui::Separator(); @@ -231,7 +231,7 @@ static void draw_invoice_form(invoice* buffer, bool viewing_only = false) bool max_items_reached = administration_billing_item_count(buffer) >= MAX_BILLING_ITEMS; if (max_items_reached) ImGui::BeginDisabled(); - if (ImGui::Button(localize(localize("invoice.form.add")))) + if (ImGui::Button(locale::get(locale::get("invoice.form.add")))) { billing_item item = administration_billing_item_create_empty(); administration_billing_item_add_to_invoice(buffer, item); @@ -239,7 +239,7 @@ static void draw_invoice_form(invoice* buffer, bool viewing_only = false) if (max_items_reached) ImGui::EndDisabled(); ImGui::SameLine(); - ImGui::Text("| %s: ", localize("invoice.form.currency")); + ImGui::Text("| %s: ", locale::get("invoice.form.currency")); ImGui::SameLine(); if (ImGui::FormCurrencyCombo(buffer->currency)) { @@ -255,7 +255,7 @@ static void ui_draw_invoices_list() { if (!administration_can_create_invoices()) { ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(0, 102, 204, 255)); // blue - ImGui::Text(localize("ui.invoiceRequirementP1")); + ImGui::Text(locale::get("ui.invoiceRequirementP1")); ImGui::PopStyleColor(); if (ImGui::IsItemHovered()) { @@ -266,7 +266,7 @@ static void ui_draw_invoices_list() } ImGui::SameLine(); - ImGui::Text(localize("ui.invoiceRequirementP2")); + ImGui::Text(locale::get("ui.invoiceRequirementP2")); return; } @@ -281,7 +281,7 @@ static void ui_draw_invoices_list() if (max_page == 0) max_page = 1; // Table header controls: create button and pagination. - if (ImGui::Button(localize("form.create"))) + if (ImGui::Button(locale::get("form.create"))) { current_view_state = view_state::CREATE; active_invoice = administration_invoice_create_empty(); // @leak @@ -297,7 +297,7 @@ static void ui_draw_invoices_list() 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 (ImGui::Button(locale::get("ui.prev")) && current_page > 0) current_page--; if (!enable_prev) ImGui::EndDisabled(); ImGui::SameLine(); @@ -307,19 +307,19 @@ static void ui_draw_invoices_list() 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 (ImGui::Button(locale::get("ui.next")) && current_page < max_page-1) current_page++; if (!enable_next) ImGui::EndDisabled(); ImGui::Spacing(); if (ImGui::BeginTable("TableInvoices", 7, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { - ImGui::TableSetupColumn(localize("invoice.table.invoicenumber"), ImGuiTableColumnFlags_WidthFixed, 120); - ImGui::TableSetupColumn(localize("invoice.table.customer")); - ImGui::TableSetupColumn(localize("invoice.table.addressee")); - ImGui::TableSetupColumn(localize("invoice.table.issuedat")); - ImGui::TableSetupColumn(localize("invoice.table.total")); - ImGui::TableSetupColumn(localize("invoice.table.status")); + ImGui::TableSetupColumn(locale::get("invoice.table.invoicenumber"), ImGuiTableColumnFlags_WidthFixed, 120); + ImGui::TableSetupColumn(locale::get("invoice.table.customer")); + ImGui::TableSetupColumn(locale::get("invoice.table.addressee")); + ImGui::TableSetupColumn(locale::get("invoice.table.issuedat")); + ImGui::TableSetupColumn(locale::get("invoice.table.total")); + ImGui::TableSetupColumn(locale::get("invoice.table.status")); ImGui::TableSetupColumn(""); ImGui::TableHeadersRow(); @@ -337,11 +337,11 @@ static void ui_draw_invoices_list() ImGui::TableSetColumnIndex(3); ImGui::Text(buf); ImGui::TableSetColumnIndex(4); ImGui::Text("%.2f %s", c.total, c.currency); - ImGui::TableSetColumnIndex(5); ImGui::Text("%s", localize(administration_invoice_get_status_string(&c))); + ImGui::TableSetColumnIndex(5); ImGui::Text("%s", locale::get(administration_invoice_get_status_string(&c))); ImGui::TableSetColumnIndex(6); char btn_name[20]; - snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.view"), i); + snprintf(btn_name, sizeof(btn_name), "%s##%d", locale::get("form.view"), i); if (ImGui::Button(btn_name)) { active_invoice = c; current_view_state = view_state::VIEW; @@ -351,14 +351,14 @@ static void ui_draw_invoices_list() if (c.status == invoice_status::INVOICE_CONCEPT) { - snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.change"), i); + snprintf(btn_name, sizeof(btn_name), "%s##%d", locale::get("form.change"), i); if (ImGui::Button(btn_name)) { active_invoice = administration_invoice_create_copy(&c); // We create a copy because of billing item list pointers. current_view_state = view_state::EDIT; } ImGui::SameLine(); - snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.delete"), i); + snprintf(btn_name, sizeof(btn_name), "%s##%d", locale::get("form.delete"), i); if (ImGui::Button(btn_name)) { selected_for_removal = c; ImGui::OpenPopup("ConfirmDeletePopup"); @@ -368,15 +368,15 @@ static void ui_draw_invoices_list() // Confirmation popup before contact is deleted definitively. if (ImGui::BeginPopupModal("ConfirmDeletePopup", nullptr, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoTitleBar)) { - ImGui::Text(localize("form.confirmDelete")); + ImGui::Text(locale::get("form.confirmDelete")); ImGui::Separator(); - if (ImGui::Button(localize("form.yes"), ImVec2(120, 0))) { + if (ImGui::Button(locale::get("form.yes"), ImVec2(120, 0))) { administration_invoice_remove(&selected_for_removal); ImGui::CloseCurrentPopup(); } ImGui::SameLine(); - if (ImGui::Button(localize("form.no"), ImVec2(120, 0))) { + if (ImGui::Button(locale::get("form.no"), ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); @@ -389,7 +389,7 @@ static void ui_draw_invoices_list() static void ui_draw_invoice_update() { - if (ImGui::Button(localize("form.back"))) { + if (ImGui::Button(locale::get("form.back"))) { current_view_state = view_state::LIST; } @@ -399,7 +399,7 @@ static void ui_draw_invoice_update() if (!can_save) ImGui::BeginDisabled(); ImGui::Spacing(); - if (ImGui::Button(localize("form.save"))) { + if (ImGui::Button(locale::get("form.save"))) { administration_invoice_update(&active_invoice); current_view_state = view_state::LIST; @@ -413,7 +413,7 @@ static void ui_draw_invoice_update() static void ui_draw_invoice_create() { - if (ImGui::Button(localize("form.back"))) { + if (ImGui::Button(locale::get("form.back"))) { current_view_state = view_state::LIST; } @@ -423,7 +423,7 @@ static void ui_draw_invoice_create() if (!can_save) ImGui::BeginDisabled(); ImGui::Spacing(); - if (ImGui::Button(localize("form.save"))) { + if (ImGui::Button(locale::get("form.save"))) { administration_invoice_add(&active_invoice); current_view_state = view_state::LIST; @@ -437,7 +437,7 @@ static void ui_draw_invoice_create() static void ui_draw_invoice_view() { - if (ImGui::Button(localize("form.back"))) { + if (ImGui::Button(locale::get("form.back"))) { current_view_state = view_state::LIST; } diff --git a/src/ui/ui_main.cpp b/src/ui/ui_main.cpp index 45b787b..f918ce8 100644 --- a/src/ui/ui_main.cpp +++ b/src/ui/ui_main.cpp @@ -67,7 +67,7 @@ void ui_draw_main() { if (ui_state == main_state::UI_END) ui_set_state(main_state::UI_INVOICES); - // @localize + // @locale::get if (ImGui::BeginMainMenuBar()) { if (ImGui::BeginMenu("File")) @@ -107,22 +107,22 @@ void ui_draw_main() float buttonWidth = sidePanelWidth; - if (ImGui::Button(localize("nav.invoices"), ImVec2(buttonWidth, 24))) ui_set_state(main_state::UI_INVOICES); - if (ImGui::Button(localize("nav.expenses"), ImVec2(buttonWidth, 24))) ui_set_state(main_state::UI_EXPENSES); - if (ImGui::Button(localize("nav.contacts"), ImVec2(buttonWidth, 24))) ui_set_state(main_state::UI_CONTACTS); + if (ImGui::Button(locale::get("nav.invoices"), ImVec2(buttonWidth, 24))) ui_set_state(main_state::UI_INVOICES); + if (ImGui::Button(locale::get("nav.expenses"), ImVec2(buttonWidth, 24))) ui_set_state(main_state::UI_EXPENSES); + if (ImGui::Button(locale::get("nav.contacts"), ImVec2(buttonWidth, 24))) ui_set_state(main_state::UI_CONTACTS); static bool reports_opened = true; - if (ImGui::Button(localize("nav.reports"), ImVec2(buttonWidth, 24))) reports_opened = !reports_opened; + if (ImGui::Button(locale::get("nav.reports"), ImVec2(buttonWidth, 24))) reports_opened = !reports_opened; if (reports_opened) { ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(20.0f, 0.0f)); - if (ImGui::Button(localize("nav.reports.results"), ImVec2(buttonWidth, 24))) ui_set_state(main_state::UI_REPORT_RESULTS); - if (ImGui::Button(localize("nav.reports.tax"), ImVec2(buttonWidth, 24))) ui_set_state(main_state::UI_REPORT_TAX); + if (ImGui::Button(locale::get("nav.reports.results"), ImVec2(buttonWidth, 24))) ui_set_state(main_state::UI_REPORT_RESULTS); + if (ImGui::Button(locale::get("nav.reports.tax"), ImVec2(buttonWidth, 24))) ui_set_state(main_state::UI_REPORT_TAX); ImGui::PopStyleVar(); } - if (ImGui::Button(localize("nav.projects"), ImVec2(buttonWidth, 24))) ui_set_state(main_state::UI_PROJECTS); - if (ImGui::Button(localize("nav.settings"), ImVec2(buttonWidth, 24))) ui_set_state(main_state::UI_SETTINGS); + if (ImGui::Button(locale::get("nav.projects"), ImVec2(buttonWidth, 24))) ui_set_state(main_state::UI_PROJECTS); + if (ImGui::Button(locale::get("nav.settings"), ImVec2(buttonWidth, 24))) ui_set_state(main_state::UI_SETTINGS); ImGui::PopStyleColor(1); ImGui::PopStyleVar(3); @@ -154,10 +154,10 @@ void ui_draw_main() char* path = administration_get_file_path(); if (path == NULL) { - ImGui::Text("%s: %s", localize("ui.workingOn"), localize("ui.unsavedProject")); + ImGui::Text("%s: %s", locale::get("ui.workingOn"), locale::get("ui.unsavedProject")); } else { - ImGui::Text("%s: %s", localize("ui.workingOn"), path); + ImGui::Text("%s: %s", locale::get("ui.workingOn"), path); } ImGui::SameLine(); diff --git a/src/ui/ui_projects.cpp b/src/ui/ui_projects.cpp index e7fa86f..560bc72 100644 --- a/src/ui/ui_projects.cpp +++ b/src/ui/ui_projects.cpp @@ -39,7 +39,7 @@ static void draw_project_form() bool viewing_only = (current_view_state == view_state::VIEW); static const char* selected_country = NULL; - if (ImGui::Button(localize("form.back"))) { + if (ImGui::Button(locale::get("form.back"))) { current_view_state = view_state::LIST; active_project = administration_project_create_empty(); selected_country = 0; @@ -51,10 +51,10 @@ static void draw_project_form() a_err last_err = administration_project_is_valid(active_project); ImGui::SetNextItemWidth(widthAvailable*0.2f); - ImGui::InputText(localize("project.form.identifier"), active_project.id, IM_ARRAYSIZE(active_project.id)); + ImGui::InputText(locale::get("project.form.identifier"), active_project.id, IM_ARRAYSIZE(active_project.id)); if (!viewing_only) ImGui::EndDisabled(); - ImGui::FormInputTextWithErrorHint(localize("project.form.description"), active_project.description, IM_ARRAYSIZE(active_project.description), last_err & A_ERR_MISSING_DESCRIPTION); + ImGui::FormInputTextWithErrorHint(locale::get("project.form.description"), active_project.description, IM_ARRAYSIZE(active_project.description), last_err & A_ERR_MISSING_DESCRIPTION); if (viewing_only) ImGui::EndDisabled(); @@ -64,7 +64,7 @@ static void draw_project_form() if (!can_save) ImGui::BeginDisabled(); // Save button ImGui::Spacing(); - if (ImGui::Button(localize("form.save"))) { + if (ImGui::Button(locale::get("form.save"))) { if (current_view_state == view_state::CREATE) { administration_project_add(active_project); } @@ -91,7 +91,7 @@ static void draw_project_list() s32 max_page = (administration_project_count() + items_per_page - 1) / items_per_page; if (max_page == 0) max_page = 1; - if (ImGui::Button(localize("form.create"))) + if (ImGui::Button(locale::get("form.create"))) { current_view_state = view_state::CREATE; active_project = administration_project_create_empty(); @@ -103,7 +103,7 @@ static void draw_project_list() 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 (ImGui::Button(locale::get("ui.prev")) && current_page > 0) current_page--; if (!enable_prev) ImGui::EndDisabled(); ImGui::SameLine(); @@ -112,16 +112,16 @@ static void draw_project_list() 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 (ImGui::Button(locale::get("ui.next")) && current_page < max_page-1) current_page++; if (!enable_next) ImGui::EndDisabled(); ImGui::Spacing(); if (ImGui::BeginTable("TableProjects", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { - ImGui::TableSetupColumn(localize("project.table.identifier"), ImGuiTableColumnFlags_WidthFixed, 80); - ImGui::TableSetupColumn(localize("project.table.status"), ImGuiTableColumnFlags_WidthFixed, 140); - ImGui::TableSetupColumn(localize("project.table.description"), ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn(locale::get("project.table.identifier"), ImGuiTableColumnFlags_WidthFixed, 80); + ImGui::TableSetupColumn(locale::get("project.table.status"), ImGuiTableColumnFlags_WidthFixed, 140); + ImGui::TableSetupColumn(locale::get("project.table.description"), ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 160); ImGui::TableHeadersRow(); @@ -133,13 +133,13 @@ static void draw_project_list() ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); ImGui::Text(c.id); - ImGui::TableSetColumnIndex(1); ImGui::Text(localize(administration_project_get_status_string(c))); + ImGui::TableSetColumnIndex(1); ImGui::Text(locale::get(administration_project_get_status_string(c))); ImGui::TableSetColumnIndex(2); ImGui::Text(c.description); ImGui::TableSetColumnIndex(3); char btn_name[20]; - snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.view"), i); + snprintf(btn_name, sizeof(btn_name), "%s##%d", locale::get("form.view"), i); if (ImGui::Button(btn_name)) { active_project = c; current_view_state = view_state::VIEW; @@ -148,14 +148,14 @@ static void draw_project_list() if (c.state == project_state::PROJECT_RUNNING) { ImGui::SameLine(); - snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.change"), i); + snprintf(btn_name, sizeof(btn_name), "%s##%d", locale::get("form.change"), i); if (ImGui::Button(btn_name)) { active_project = c; current_view_state = view_state::EDIT; } ImGui::SameLine(); - snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.cancel"), i); + snprintf(btn_name, sizeof(btn_name), "%s##%d", locale::get("form.cancel"), i); if (ImGui::Button(btn_name)) { selected_for_cancellation = c; ImGui::OpenPopup("ConfirmCancelProject"); @@ -164,15 +164,15 @@ static void draw_project_list() } if (ImGui::BeginPopupModal("ConfirmCancelProject", nullptr, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoTitleBar)) { - ImGui::Text(localize("form.confirmCancelProject")); + ImGui::Text(locale::get("form.confirmCancelProject")); ImGui::Separator(); - if (ImGui::Button(localize("form.yes"), ImVec2(120, 0))) { + if (ImGui::Button(locale::get("form.yes"), ImVec2(120, 0))) { administration_project_cancel(selected_for_cancellation); ImGui::CloseCurrentPopup(); } ImGui::SameLine(); - if (ImGui::Button(localize("form.no"), ImVec2(120, 0))) { + if (ImGui::Button(locale::get("form.no"), ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); diff --git a/src/ui/ui_settings.cpp b/src/ui/ui_settings.cpp index d7dfd4d..79d65da 100644 --- a/src/ui/ui_settings.cpp +++ b/src/ui/ui_settings.cpp @@ -69,8 +69,8 @@ static void ui_draw_vat_rates() if (ImGui::BeginTable("TableVatRates", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { - ImGui::TableSetupColumn(localize("settings.vat.table.country"), ImGuiTableColumnFlags_WidthFixed, 220); - ImGui::TableSetupColumn(localize("settings.vat.table.rates")); + ImGui::TableSetupColumn(locale::get("settings.vat.table.country"), ImGuiTableColumnFlags_WidthFixed, 220); + ImGui::TableSetupColumn(locale::get("settings.vat.table.rates")); // Used to generate headers for each individual country. char prev_country[MAX_LEN_COUNTRY_CODE]; @@ -105,7 +105,7 @@ static void ui_draw_vat_rates() char locale_buf[20]; snprintf(locale_buf, sizeof(locale_buf), "country.%s", c.country_code); ImGui::TableSetColumnIndex(0); - ImGui::Text(localize(locale_buf)); + ImGui::Text(locale::get(locale_buf)); // If not adding an item already, show + button next to country name. if (!is_adding_item) @@ -132,7 +132,7 @@ static void ui_draw_vat_rates() char category_code_desc[MAX_LEN_LONG_DESC]; snprintf(category_code_desc, MAX_LEN_LONG_DESC, "taxcategory.%s", c.category_code); - ImGui::Text(can_be_modified ? "" : localize(category_code_desc)); + ImGui::Text(can_be_modified ? "" : locale::get(category_code_desc)); // Column 2: When editing, show input for new rate. Else we display the stored rate and check for modify request. @@ -145,7 +145,7 @@ static void ui_draw_vat_rates() if (new_tax_rate.rate > 100.0f) new_tax_rate.rate = 100.0f; ImGui::SameLine(); - if (ImGui::Button(localize("form.save"))) { + if (ImGui::Button(locale::get("form.save"))) { is_editing_item = false; is_adding_item = false; @@ -156,7 +156,7 @@ static void ui_draw_vat_rates() } ImGui::SameLine(); - if (ImGui::Button(localize("form.cancel"))) { + if (ImGui::Button(locale::get("form.cancel"))) { is_editing_item = false; is_adding_item = false; memset(&new_tax_rate, 0, sizeof(new_tax_rate)); @@ -191,7 +191,7 @@ static void ui_draw_vat_rates() if (new_tax_rate.rate > 100.0f) new_tax_rate.rate = 100.0f; ImGui::SameLine(); - if (ImGui::Button(localize("form.save"))) { + if (ImGui::Button(locale::get("form.save"))) { is_editing_item = false; is_adding_item = false; @@ -202,7 +202,7 @@ static void ui_draw_vat_rates() } ImGui::SameLine(); - if (ImGui::Button(localize("form.cancel"))) { + if (ImGui::Button(locale::get("form.cancel"))) { is_editing_item = false; is_adding_item = false; memset(&new_tax_rate, 0, sizeof(new_tax_rate)); @@ -225,8 +225,8 @@ static void ui_draw_cost_centers() if (ImGui::BeginTable("TableCostCenters", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { - ImGui::TableSetupColumn(localize("settings.costcenters.table.code"), ImGuiTableColumnFlags_WidthFixed, 140); - ImGui::TableSetupColumn(localize("settings.costcenters.table.description")); + ImGui::TableSetupColumn(locale::get("settings.costcenters.table.code"), ImGuiTableColumnFlags_WidthFixed, 140); + ImGui::TableSetupColumn(locale::get("settings.costcenters.table.description")); for (u32 i = 0; i < cost_center_count; i++) { cost_center c = cost_centers[i]; @@ -247,7 +247,7 @@ static void ui_draw_cost_centers() if (!is_desc_valid) ImGui::BeginDisabled(); ImGui::SameLine(); - if (ImGui::Button(localize("form.save"))) { + if (ImGui::Button(locale::get("form.save"))) { is_editing_item = false; is_adding_item = false; @@ -261,7 +261,7 @@ static void ui_draw_cost_centers() if (!is_desc_valid) ImGui::EndDisabled(); ImGui::SameLine(); - if (ImGui::Button(localize("form.cancel"))) { + if (ImGui::Button(locale::get("form.cancel"))) { is_editing_item = false; is_adding_item = false; memset(&new_cost_center, 0, sizeof(new_cost_center)); @@ -269,7 +269,7 @@ static void ui_draw_cost_centers() } else { - ImGui::Text(localize(c.description)); + ImGui::Text(locale::get(c.description)); if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { @@ -302,7 +302,7 @@ static void ui_draw_cost_centers() if (!can_save) ImGui::BeginDisabled(); ImGui::SameLine(); - if (ImGui::Button(localize("form.create"))) + if (ImGui::Button(locale::get("form.create"))) { is_adding_item = false; is_editing_item = false; @@ -314,7 +314,7 @@ static void ui_draw_cost_centers() if (!can_save) ImGui::EndDisabled(); ImGui::SameLine(); - if (ImGui::Button(localize("form.cancel"))) { + if (ImGui::Button(locale::get("form.cancel"))) { is_adding_item = false; is_editing_item = false; memset(&new_cost_center, 0, sizeof(new_cost_center)); @@ -325,7 +325,7 @@ static void ui_draw_cost_centers() } // If not adding a new item already, show create button at bottom of list. - if (!is_adding_item && ImGui::Button(localize("form.create"))) + if (!is_adding_item && ImGui::Button(locale::get("form.create"))) { new_cost_center = administration_cost_center_create_empty(); is_adding_item = true; @@ -336,7 +336,7 @@ static void ui_draw_cost_centers() static void ui_draw_services() { // AI service - if (ImGui::CollapsingHeader(localize("settings.services.ai_service"))) + if (ImGui::CollapsingHeader(locale::get("settings.services.ai_service"))) { // TODO: get this from iterator over ai_get_impl char* services[2] = { @@ -344,7 +344,7 @@ static void ui_draw_services() "DeepSeek", }; - if (ImGui::BeginCombo(localize("settings.services.ai_service.provider"), services[new_service.provider])) + if (ImGui::BeginCombo(locale::get("settings.services.ai_service.provider"), services[new_service.provider])) { for (u32 n = 0; n < 2; n++) { @@ -356,10 +356,10 @@ static void ui_draw_services() ImGui::EndCombo(); } - ImGui::InputTextWithHint(localize("settings.services.ai_service.pubkey"), localize("settings.services.ai_service.pubkey"), + ImGui::InputTextWithHint(locale::get("settings.services.ai_service.pubkey"), locale::get("settings.services.ai_service.pubkey"), new_service.api_key_public, sizeof(new_service.api_key_public)); - if (ImGui::Button(localize("form.save"))) { + if (ImGui::Button(locale::get("form.save"))) { administration_set_ai_service(new_service); } } @@ -369,7 +369,7 @@ void ui_draw_settings() { if (ImGui::BeginTabBar("SettingsTabBar")) { - if (ImGui::BeginTabItem(localize("settings.table.company"), nullptr, select_company_tab == 1 ? ImGuiTabItemFlags_SetSelected : 0)) + if (ImGui::BeginTabItem(locale::get("settings.table.company"), nullptr, select_company_tab == 1 ? ImGuiTabItemFlags_SetSelected : 0)) { select_company_tab = 0; draw_contact_form(&company_info); @@ -378,24 +378,24 @@ void ui_draw_settings() bool can_save = administration_contact_is_valid(company_info) == A_ERR_SUCCESS; if (!can_save) ImGui::BeginDisabled(); ImGui::Spacing(); - if (ImGui::Button(localize("form.save"))) { + if (ImGui::Button(locale::get("form.save"))) { administration_company_info_set(company_info); } if (!can_save) ImGui::EndDisabled(); ImGui::EndTabItem(); } - if (ImGui::BeginTabItem(localize("settings.table.vatrates"))) + if (ImGui::BeginTabItem(locale::get("settings.table.vatrates"))) { ui_draw_vat_rates(); ImGui::EndTabItem(); } - if (ImGui::BeginTabItem(localize("settings.table.costcenters"))) + if (ImGui::BeginTabItem(locale::get("settings.table.costcenters"))) { ui_draw_cost_centers(); ImGui::EndTabItem(); } - if (ImGui::BeginTabItem(localize("settings.table.services"))) + if (ImGui::BeginTabItem(locale::get("settings.table.services"))) { ui_draw_services(); ImGui::EndTabItem(); -- cgit v1.2.3-70-g09d2