diff options
| author | Aldrik Ramaekers <aldrikboy@gmail.com> | 2025-08-03 19:22:36 +0200 |
|---|---|---|
| committer | Aldrik Ramaekers <aldrikboy@gmail.com> | 2025-08-03 19:22:36 +0200 |
| commit | 853bbb3752a5fa2f58ef456ffb6e3a552e13cb11 (patch) | |
| tree | ce49a533f82a42a65fa6a4771a7b8fbfe33798cf /src | |
initial commit
Diffstat (limited to 'src')
| -rw-r--r-- | src/administration.cpp | 45 | ||||
| -rw-r--r-- | src/administration.hpp | 45 | ||||
| -rw-r--r-- | src/config.hpp | 13 | ||||
| -rw-r--r-- | src/locales/en.cpp | 29 | ||||
| -rw-r--r-- | src/locales/locales.cpp | 29 | ||||
| -rw-r--r-- | src/locales/locales.hpp | 21 | ||||
| -rw-r--r-- | src/main.cpp | 246 | ||||
| -rw-r--r-- | src/views/contacts.cpp | 162 | ||||
| -rw-r--r-- | src/views/dashboard.cpp | 65 | ||||
| -rw-r--r-- | src/views/views.hpp | 6 |
10 files changed, 661 insertions, 0 deletions
diff --git a/src/administration.cpp b/src/administration.cpp new file mode 100644 index 0000000..94b1910 --- /dev/null +++ b/src/administration.cpp @@ -0,0 +1,45 @@ +#include "administration.hpp" +#include <stdio.h> +administration g_administration; + +void init_administration_obj() +{ + list_init(&g_administration.contacts); +} + +void destroy_administration_obj() +{ + list_destroy(&g_administration.contacts); +} + +bool create_contact(contact data) +{ + contact* new_contact = (contact*)malloc(sizeof(contact)); + memcpy((void*)new_contact, (void*)&data, sizeof(contact)); + list_append(&g_administration.contacts, new_contact); + + g_administration.next_id++; + + return true; +} + +bool update_contact(contact data) +{ + list_iterator_start(&g_administration.contacts); + while (list_iterator_hasnext(&g_administration.contacts)) { + contact* c = (contact *)list_iterator_next(&g_administration.contacts); + + if (strcmp(c->id, data.id) == 0) { + memcpy(c, &data, sizeof(data)); + return true; + } + } + list_iterator_stop(&g_administration.contacts); + + return false; +} + +void remove_contact(int index) +{ + list_delete_at(&g_administration.contacts, index); +}
\ No newline at end of file diff --git a/src/administration.hpp b/src/administration.hpp new file mode 100644 index 0000000..9bf790c --- /dev/null +++ b/src/administration.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include <string.h> +#include <stdlib.h> + +#include "config.hpp" +#include "simclist.h" + +typedef struct +{ + char id[16]; + char name[64]; + char address1[128]; + char address2[128]; + char taxid[32]; + char businessid[32]; + char email[64]; + char phone_number[16]; + char bank_account[32]; +} contact; + +typedef struct +{ + contact company_info; + s32 next_id; + char path[4096]; + char program_version[10]; + char country_code[2]; + list_t contacts; + // projects + // invoices + char ai_service[16]; + char ai_key[32]; + char email_service[16]; + char email_key[32]; +} administration; + +extern administration g_administration; + +void init_administration_obj(); +void destroy_administration_obj(); + +void remove_contact(int index); +bool create_contact(contact data); +bool update_contact(contact data);
\ No newline at end of file diff --git a/src/config.hpp b/src/config.hpp new file mode 100644 index 0000000..3279e2e --- /dev/null +++ b/src/config.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "stdint.h" + +#define s8 int8_t +#define s16 int16_t +#define s32 int32_t +#define s64 int64_t + +#define u8 uint8_t +#define u16 uint16_t +#define u32 uint32_t +#define u64 uint64_t
\ No newline at end of file diff --git a/src/locales/en.cpp b/src/locales/en.cpp new file mode 100644 index 0000000..5e31c5c --- /dev/null +++ b/src/locales/en.cpp @@ -0,0 +1,29 @@ +#include "locales.hpp" + +locale_entry en_locales[] = { + // General form buttons. + {"form.create", "+ Create"}, + {"form.back", "Back"}, + {"form.save", "Save"}, + {"form.yes", "Yes"}, + {"form.no", "No"}, + {"form.change", "Change"}, + {"form.delete", "Delete"}, + {"form.confirmDelete", "Are you sure you want to delete this item?"}, + + // Contact strings. + {"contact.form.identifier", "Identifier"}, + {"contact.form.fullname", "Full name / name of business"}, + {"contact.form.address1", "Street name + house number, appt. number, etc."}, + {"contact.form.address2", "Zip, city, country"}, + {"contact.form.taxnumber", "Tax number"}, + {"contact.form.businessnumber", "Business number"}, + {"contact.form.email", "Email address"}, + {"contact.form.phonenumber", "Phone number"}, + {"contact.form.bankaccount", "Bank account"}, + {"contact.table.identifier", "Identifier"}, + {"contact.table.name", "Name"}, + {"contact.table.address", "Address"}, +}; + +const int en_locale_count = sizeof(en_locales) / sizeof(en_locales[0]);
\ No newline at end of file diff --git a/src/locales/locales.cpp b/src/locales/locales.cpp new file mode 100644 index 0000000..6ec1233 --- /dev/null +++ b/src/locales/locales.cpp @@ -0,0 +1,29 @@ +#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. + +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]; + } + } +} + +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; + } + } + return "[!MISSING!]"; +}
\ No newline at end of file diff --git a/src/locales/locales.hpp b/src/locales/locales.hpp new file mode 100644 index 0000000..78bb682 --- /dev/null +++ b/src/locales/locales.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include <stdio.h> +#include <string.h> + +typedef struct { + const char* key; + const char* value; +} locale_entry; + +typedef struct { + const char* lang_code; + locale_entry* entries; + int entry_count; +} locale_map; + +extern locale_entry en_locales[]; +extern const int en_locale_count; + +void set_locale(const char key[2]); +const char* localize(const char* key);
\ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..323a5a0 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,246 @@ +#include "imgui.h" +#include "imgui_impl_win32.h" +#include "imgui_impl_dx11.h" +#include <d3d11.h> +#include <tchar.h> + +#include "views/views.hpp" +#include "administration.hpp" + +// Data +static ID3D11Device* g_pd3dDevice = nullptr; +static ID3D11DeviceContext* g_pd3dDeviceContext = nullptr; +static IDXGISwapChain* g_pSwapChain = nullptr; +static bool g_SwapChainOccluded = false; +static UINT g_ResizeWidth = 0, g_ResizeHeight = 0; +static ID3D11RenderTargetView* g_mainRenderTargetView = nullptr; + +// Forward declarations of helper functions +bool CreateDeviceD3D(HWND hWnd); +void CleanupDeviceD3D(); +void CreateRenderTarget(); +void CleanupRenderTarget(); +LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +// Main code +//int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +int main() +{ + // Make process DPI aware and obtain main monitor scale + ImGui_ImplWin32_EnableDpiAwareness(); + float main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY)); + + // Create application window + WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr }; + ::RegisterClassExW(&wc); + HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"OpenBooks", WS_OVERLAPPEDWINDOW, 100, 100, (int)(1280 * main_scale), (int)(800 * main_scale), nullptr, nullptr, wc.hInstance, nullptr); + + // Initialize Direct3D + if (!CreateDeviceD3D(hwnd)) + { + CleanupDeviceD3D(); + ::UnregisterClassW(wc.lpszClassName, wc.hInstance); + return 1; + } + + // Show the window + ::ShowWindow(hwnd, SW_SHOWDEFAULT); + ::UpdateWindow(hwnd); + + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + io.IniFilename = NULL; + io.LogFilename = NULL; + + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsLight(); + + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + + // Setup Platform/Renderer backends + ImGui_ImplWin32_Init(hwnd); + ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); + + // Load Fonts + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). + // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. + // - Read 'docs/FONTS.md' for more instructions and details. + // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + style.FontSizeBase = 18.0f; + //io.Fonts->AddFontDefault(); + io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); + //IM_ASSERT(font != nullptr); + + ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + + init_administration_obj(); + + // Main loop + bool done = false; + while (!done) + { + // Poll and handle messages (inputs, window resize, etc.) + // See the WndProc() function below for our to dispatch events to the Win32 backend. + MSG msg; + while (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE)) + { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + if (msg.message == WM_QUIT) + done = true; + } + if (done) + break; + + // Handle window being minimized or screen locked + if (g_SwapChainOccluded && g_pSwapChain->Present(0, DXGI_PRESENT_TEST) == DXGI_STATUS_OCCLUDED) + { + ::Sleep(10); + continue; + } + g_SwapChainOccluded = false; + + // Handle window resize (we don't resize directly in the WM_SIZE handler) + if (g_ResizeWidth != 0 && g_ResizeHeight != 0) + { + CleanupRenderTarget(); + g_pSwapChain->ResizeBuffers(0, g_ResizeWidth, g_ResizeHeight, DXGI_FORMAT_UNKNOWN, 0); + g_ResizeWidth = g_ResizeHeight = 0; + CreateRenderTarget(); + } + + // Start the Dear ImGui frame + ImGui_ImplDX11_NewFrame(); + ImGui_ImplWin32_NewFrame(); + ImGui::NewFrame(); + + show_dashboard(); + + // Rendering + ImGui::Render(); + const float clear_color_with_alpha[4] = { clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w }; + g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, nullptr); + g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha); + ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); + + // Present + HRESULT hr = g_pSwapChain->Present(1, 0); // Present with vsync + //HRESULT hr = g_pSwapChain->Present(0, 0); // Present without vsync + g_SwapChainOccluded = (hr == DXGI_STATUS_OCCLUDED); + } + + destroy_administration_obj(); + + // Cleanup + ImGui_ImplDX11_Shutdown(); + ImGui_ImplWin32_Shutdown(); + ImGui::DestroyContext(); + + CleanupDeviceD3D(); + ::DestroyWindow(hwnd); + ::UnregisterClassW(wc.lpszClassName, wc.hInstance); + + return 0; +} + +// Helper functions + +bool CreateDeviceD3D(HWND hWnd) +{ + // Setup swap chain + DXGI_SWAP_CHAIN_DESC sd; + ZeroMemory(&sd, sizeof(sd)); + sd.BufferCount = 2; + sd.BufferDesc.Width = 0; + sd.BufferDesc.Height = 0; + sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + sd.BufferDesc.RefreshRate.Numerator = 60; + sd.BufferDesc.RefreshRate.Denominator = 1; + sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + sd.OutputWindow = hWnd; + sd.SampleDesc.Count = 1; + sd.SampleDesc.Quality = 0; + sd.Windowed = TRUE; + sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + + UINT createDeviceFlags = 0; + //createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; + D3D_FEATURE_LEVEL featureLevel; + const D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, }; + HRESULT res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); + if (res == DXGI_ERROR_UNSUPPORTED) // Try high-performance WARP software driver if hardware is not available. + res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); + if (res != S_OK) + return false; + + CreateRenderTarget(); + return true; +} + +void CleanupDeviceD3D() +{ + CleanupRenderTarget(); + if (g_pSwapChain) { g_pSwapChain->Release(); g_pSwapChain = nullptr; } + if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = nullptr; } + if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = nullptr; } +} + +void CreateRenderTarget() +{ + ID3D11Texture2D* pBackBuffer; + g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); + g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_mainRenderTargetView); + pBackBuffer->Release(); +} + +void CleanupRenderTarget() +{ + if (g_mainRenderTargetView) { g_mainRenderTargetView->Release(); g_mainRenderTargetView = nullptr; } +} + +// Forward declare message handler from imgui_impl_win32.cpp +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +// Win32 message handler +// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. +// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. +// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. +// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. +LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) + return true; + + switch (msg) + { + case WM_SIZE: + if (wParam == SIZE_MINIMIZED) + return 0; + g_ResizeWidth = (UINT)LOWORD(lParam); // Queue resize + g_ResizeHeight = (UINT)HIWORD(lParam); + return 0; + case WM_SYSCOMMAND: + if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu + return 0; + break; + case WM_DESTROY: + ::PostQuitMessage(0); + return 0; + } + return ::DefWindowProcW(hWnd, msg, wParam, lParam); +}
\ No newline at end of file diff --git a/src/views/contacts.cpp b/src/views/contacts.cpp new file mode 100644 index 0000000..de5e766 --- /dev/null +++ b/src/views/contacts.cpp @@ -0,0 +1,162 @@ +#include <stdio.h> + +#include "views.hpp" +#include "imgui.h" +#include "../administration.hpp" + +typedef enum { + VIEW, + EDIT, + CREATE, + INSPECT, +} contact_view_state; + +contact_view_state view_state = VIEW; +static int selected_for_removal = -1; // Index in contact list selected for removal. + +static contact edit_contact; + +static void draw_required_tag() +{ + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + + const char* text = "required"; + ImVec2 text_pos = ImGui::GetCursorScreenPos(); + ImVec2 text_size = ImGui::CalcTextSize(text); + text_pos.y += text_size.y/4.0f; + + ImVec4 bg_color = ImVec4(0.9f, 0.235f, 0.235f, 0.4f); // Blue background + ImVec4 text_color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // White text + float rounding = 2.0f; + float padding = 2.0f; + + // Background rectangle + ImVec2 bg_min = ImVec2(text_pos.x - padding, text_pos.y - padding); + ImVec2 bg_max = ImVec2(text_pos.x + text_size.x + padding, text_pos.y + text_size.y + padding); + draw_list->AddRectFilled(bg_min, bg_max, ImColor(bg_color), rounding); + + // Foreground text + ImGui::PushStyleColor(ImGuiCol_Text, text_color); + ImGui::TextUnformatted(text); + ImGui::PopStyleColor(); +} + +static void show_edit_contact() +{ + if (ImGui::Button(localize("form.back"))) { + view_state = contact_view_state::VIEW; + memset(&edit_contact, 0, sizeof(contact)); + } + ImGui::Spacing(); + + // Input fields + ImGui::BeginDisabled(); + + ImGui::InputText(localize("contact.form.identifier"), edit_contact.id, IM_ARRAYSIZE(edit_contact.id)); + ImGui::EndDisabled(); + + ImGui::InputTextWithHint(localize("contact.form.fullname"), localize("contact.form.fullname"), edit_contact.name, IM_ARRAYSIZE(edit_contact.name)); + ImGui::SameLine();draw_required_tag(); + + ImGui::InputTextWithHint(localize("contact.form.address1"), localize("contact.form.address1"), edit_contact.address1, IM_ARRAYSIZE(edit_contact.address1)); + ImGui::SameLine();draw_required_tag(); + + ImGui::InputTextWithHint(localize("contact.form.address2"), localize("contact.form.address2"), edit_contact.address2, IM_ARRAYSIZE(edit_contact.address2)); + ImGui::SameLine();draw_required_tag(); + + ImGui::InputTextWithHint(localize("contact.form.taxnumber"), localize("contact.form.taxnumber"), edit_contact.taxid, IM_ARRAYSIZE(edit_contact.taxid)); + ImGui::InputTextWithHint(localize("contact.form.businessnumber"), localize("contact.form.businessnumber"), edit_contact.businessid, IM_ARRAYSIZE(edit_contact.businessid)); + ImGui::InputTextWithHint(localize("contact.form.email"), localize("contact.form.email"), edit_contact.email, IM_ARRAYSIZE(edit_contact.email)); + ImGui::InputTextWithHint(localize("contact.form.phonenumber"), localize("contact.form.phonenumber"), edit_contact.phone_number, IM_ARRAYSIZE(edit_contact.phone_number)); + ImGui::InputTextWithHint(localize("contact.form.bankaccount"), localize("contact.form.bankaccount"), edit_contact.bank_account, IM_ARRAYSIZE(edit_contact.bank_account)); + + bool can_save = strlen(edit_contact.name) > 0 && strlen(edit_contact.address1) > 0 && strlen(edit_contact.address2) > 0; + + if (!can_save) ImGui::BeginDisabled(); + + // Save button + ImGui::Spacing(); + if (ImGui::Button(localize("form.save"))) { + if (view_state == contact_view_state::CREATE) + create_contact(edit_contact); + + else if (view_state == contact_view_state::EDIT) + update_contact(edit_contact); + + memset(&edit_contact, 0, sizeof(contact)); + view_state = contact_view_state::VIEW; + } + + if (!can_save) ImGui::EndDisabled(); +} + +void show_contacts() +{ + if (view_state == contact_view_state::CREATE || view_state == contact_view_state::EDIT) { + show_edit_contact(); + return; + } + + if (ImGui::Button(localize("form.create"))) + { + view_state = contact_view_state::CREATE; + memset(&edit_contact, 0, sizeof(contact)); + snprintf(edit_contact.id, IM_ARRAYSIZE(edit_contact.id), "C/%d", g_administration.next_id); + } + ImGui::Spacing(); + + if (ImGui::BeginTable("TableContacts", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { + + ImGui::TableSetupColumn(localize("contact.table.identifier"), ImGuiTableColumnFlags_WidthFixed, 80); + ImGui::TableSetupColumn(localize("contact.table.name"), ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn(localize("contact.table.address"), ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 120); + ImGui::TableHeadersRow(); + + list_iterator_start(&g_administration.contacts); + while (list_iterator_hasnext(&g_administration.contacts)) { + contact c = *(contact *)list_iterator_next(&g_administration.contacts); + + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); ImGui::Text(c.id); + ImGui::TableSetColumnIndex(1); ImGui::Text(c.name); + ImGui::TableSetColumnIndex(2); ImGui::Text("%s %s", c.address1, c.address2); + + ImGui::TableSetColumnIndex(3); + + char btn_name[20]; + sprintf(btn_name, "%s##%d", localize("form.change"), g_administration.contacts.iter_pos); + if (ImGui::Button(btn_name)) { + edit_contact = c; + view_state = contact_view_state::EDIT; + } + + ImGui::SameLine(); + + // @TODO check to make sure no invoices are connected to this contact. + sprintf(btn_name, "%s##%d", localize("form.delete"), g_administration.contacts.iter_pos); + if (ImGui::Button(btn_name)) { + selected_for_removal = g_administration.contacts.iter_pos; + ImGui::OpenPopup("ConfirmDeletePopup"); + } + } + list_iterator_stop(&g_administration.contacts); + + if (ImGui::BeginPopupModal("ConfirmDeletePopup", nullptr, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoTitleBar)) { + ImGui::Text(localize("form.confirmDelete")); + ImGui::Separator(); + + if (ImGui::Button(localize("form.yes"), ImVec2(120, 0))) { + remove_contact(selected_for_removal-1); + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button(localize("form.no"), ImVec2(120, 0))) { + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + + ImGui::EndTable(); + } +}
\ No newline at end of file diff --git a/src/views/dashboard.cpp b/src/views/dashboard.cpp new file mode 100644 index 0000000..16d31c4 --- /dev/null +++ b/src/views/dashboard.cpp @@ -0,0 +1,65 @@ +#include "views.hpp" + +#include "imgui.h" + +void show_dashboard() +{ + if (ImGui::BeginMainMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + if (ImGui::MenuItem("Open", "Ctrl+O")) { /* Handle Open */ } + if (ImGui::MenuItem("Save", "Ctrl+S")) { /* Handle Save */ } + + ImGui::EndMenu(); + } + ImGui::EndMainMenuBar(); + } + + ImGuiIO& io = ImGui::GetIO(); + float menuBarHeight = ImGui::GetFrameHeight(); + float statusBarHeight = 26.0f; + ImGui::SetNextWindowPos(ImVec2(0, menuBarHeight)); + ImGui::SetNextWindowSize(ImVec2(io.DisplaySize.x, io.DisplaySize.y - menuBarHeight - statusBarHeight)); + + ImGui::Begin("AccountingMainWindow", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse); + + ImGui::AlignTextToFramePadding(); + const char* names[3] = { "Incoming", "Outgoing", "Contacts" }; + void (*drawcalls[3])(void) = { show_contacts, show_contacts, show_contacts }; + + if (ImGui::BeginTabBar("mainNavigationTabBar", 0)) + { + for (int n = 0; n < IM_ARRAYSIZE(names); n++) + if (ImGui::BeginTabItem(names[n], 0, ImGuiTabItemFlags_None)) + { + ImGui::Spacing(); + drawcalls[n](); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + + ImGui::End(); + + // Status bar. + ImGui::SetNextWindowPos(ImVec2(0, io.DisplaySize.y - statusBarHeight)); + ImGui::SetNextWindowSize(ImVec2(io.DisplaySize.x, statusBarHeight)); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 3)); + ImGui::Begin("StatusBar", nullptr, + ImGuiWindowFlags_NoTitleBar | + ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_NoScrollbar | + ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoBringToFrontOnFocus | + ImGuiWindowFlags_NoCollapse); + + ImGui::Text("Working on: []"); + ImGui::SameLine(); + ImGui::Text("Status: []"); + + ImGui::End(); + ImGui::PopStyleVar(); +}
\ No newline at end of file diff --git a/src/views/views.hpp b/src/views/views.hpp new file mode 100644 index 0000000..adefea2 --- /dev/null +++ b/src/views/views.hpp @@ -0,0 +1,6 @@ +#pragma once + +#include "../locales/locales.hpp" + +void show_dashboard(); +void show_contacts();
\ No newline at end of file |
