summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAldrik Ramaekers <aldrikboy@gmail.com>2025-09-12 16:35:40 +0200
committerAldrik Ramaekers <aldrikboy@gmail.com>2025-09-12 16:35:40 +0200
commitabf01f657d068aa6b22ab962cbe01b88f3b5f7ea (patch)
tree2a354a6112ef0b9ef6975613f12865831f5d4a69
parentd174d803de2296061731c3698980a6a51e6fc3ef (diff)
event logging
-rw-r--r--docs/README.rst3
-rw-r--r--include/log.hpp7
-rw-r--r--include/ui.hpp1
-rw-r--r--libs/timer_lib/.gitattributes22
-rw-r--r--libs/timer_lib/.gitignore163
-rw-r--r--libs/timer_lib/Makefile23
-rw-r--r--libs/timer_lib/README37
-rw-r--r--libs/timer_lib/test.vcxproj169
-rw-r--r--libs/timer_lib/timer.c174
-rw-r--r--libs/timer_lib/timer.h77
-rw-r--r--libs/timer_lib/timer.sln36
-rw-r--r--libs/timer_lib/timer.vcxproj225
-rw-r--r--run.bat3
-rw-r--r--src/administration.cpp11
-rw-r--r--src/administration_writer.cpp24
-rw-r--r--src/log.cpp33
-rw-r--r--src/main.cpp4
-rw-r--r--src/ui/ui_expenses.cpp10
-rw-r--r--src/ui/ui_invoices.cpp9
-rw-r--r--src/ui/ui_log.cpp20
-rw-r--r--src/ui/ui_main.cpp11
21 files changed, 1047 insertions, 15 deletions
diff --git a/docs/README.rst b/docs/README.rst
index 4436a53..e8aab29 100644
--- a/docs/README.rst
+++ b/docs/README.rst
@@ -43,4 +43,5 @@ This section lists all supported countries. If the country you operate from is n
- ImGuiDatePicker (https://github.com/DnA-IntRicate/ImGuiDatePicker)
- tinyfiledialogs (https://sourceforge.net/projects/tinyfiledialogs/)
- xml.c (https://github.com/ooxi/xml.c)
-- zip (https://github.com/kuba--/zip) \ No newline at end of file
+- zip (https://github.com/kuba--/zip)
+- timer_lib (https://github.com/mjansson/timer_lib) \ No newline at end of file
diff --git a/include/log.hpp b/include/log.hpp
index dcb2987..f34cc27 100644
--- a/include/log.hpp
+++ b/include/log.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include "timer.h"
#include "imgui.h"
#include "config.hpp"
@@ -12,4 +13,8 @@ typedef struct {
char history[MAX_LEN_LOG_HISTORY][MAX_LEN_LOG_TXT];
} log;
-void log_add(double timestamp, const char* fmt, ...) IM_FMTARGS(2); \ No newline at end of file
+#define STOPWATCH_START tick_t timestamp_start = timer_current();
+#define STOPWATCH_TIME (timer_elapsed(timestamp_start)*1000.0f)
+
+log* get_log();
+void log_add(const char* fmt, ...) IM_FMTARGS(2); \ No newline at end of file
diff --git a/include/ui.hpp b/include/ui.hpp
index ddfb824..7bbdd5a 100644
--- a/include/ui.hpp
+++ b/include/ui.hpp
@@ -46,6 +46,7 @@ void ui_draw_invoices();
void ui_draw_settings();
void ui_draw_expenses();
void ui_draw_earnings();
+void ui_draw_log();
void ui_setup_invoices();
void ui_setup_contacts();
diff --git a/libs/timer_lib/.gitattributes b/libs/timer_lib/.gitattributes
new file mode 100644
index 0000000..412eeda
--- /dev/null
+++ b/libs/timer_lib/.gitattributes
@@ -0,0 +1,22 @@
+# Auto detect text files and perform LF normalization
+* text=auto
+
+# Custom for Visual Studio
+*.cs diff=csharp
+*.sln merge=union
+*.csproj merge=union
+*.vbproj merge=union
+*.fsproj merge=union
+*.dbproj merge=union
+
+# Standard to msysgit
+*.doc diff=astextplain
+*.DOC diff=astextplain
+*.docx diff=astextplain
+*.DOCX diff=astextplain
+*.dot diff=astextplain
+*.DOT diff=astextplain
+*.pdf diff=astextplain
+*.PDF diff=astextplain
+*.rtf diff=astextplain
+*.RTF diff=astextplain
diff --git a/libs/timer_lib/.gitignore b/libs/timer_lib/.gitignore
new file mode 100644
index 0000000..5ebd21a
--- /dev/null
+++ b/libs/timer_lib/.gitignore
@@ -0,0 +1,163 @@
+#################
+## Eclipse
+#################
+
+*.pydevproject
+.project
+.metadata
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.classpath
+.settings/
+.loadpath
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# PDT-specific
+.buildpath
+
+
+#################
+## Visual Studio
+#################
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+[Dd]ebug/
+[Rr]elease/
+*_i.c
+*_p.c
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.vspscc
+.builds
+*.dotCover
+
+## TODO: If you have NuGet Package Restore enabled, uncomment this
+#packages/
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+
+# Visual Studio profiler
+*.psess
+*.vsp
+
+# ReSharper is a .NET coding add-in
+_ReSharper*
+
+# Installshield output folder
+[Ee]xpress
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish
+
+# Others
+[Bb]in
+[Oo]bj
+sql
+TestResults
+*.Cache
+ClientBin
+stylecop.*
+~$*
+*.dbmdl
+Generated_Code #added for RIA/Silverlight projects
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+
+
+
+############
+## Windows
+############
+
+# Windows image file caches
+Thumbs.db
+
+# Folder config file
+Desktop.ini
+
+
+#############
+## Python
+#############
+
+*.py[co]
+
+# Packages
+*.egg
+*.egg-info
+dist
+build
+eggs
+parts
+bin
+var
+sdist
+develop-eggs
+.installed.cfg
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
+
+#Translations
+*.mo
+
+#Mr Developer
+.mr.developer.cfg
+
+# Mac crap
+.DS_Store
diff --git a/libs/timer_lib/Makefile b/libs/timer_lib/Makefile
new file mode 100644
index 0000000..3edaf73
--- /dev/null
+++ b/libs/timer_lib/Makefile
@@ -0,0 +1,23 @@
+SRC = timer.c
+OBJ = $(SRC:.c=.o)
+OUT = libtimer.a
+TST = timertest
+TSR = test.c
+TOB = $(TSR:.c=.o)
+
+CFLAGS = -O3
+LDFLAGS =
+
+default: $(OUT) $(TST)
+
+.c.o:
+ gcc $(CFLAGS) -c $< -o $@
+
+$(OUT): $(OBJ)
+ ar rcs $(OUT) $(OBJ)
+
+$(TST): $(OUT) $(TOB)
+ gcc $(CFLAGS) $(LDFLAGS) -o $(TST) $(TOB) $(OUT) -lrt
+
+clean:
+ rm -f $(OBJ) $(OUT) $(TOB) $(TST)
diff --git a/libs/timer_lib/README b/libs/timer_lib/README
new file mode 100644
index 0000000..16f604b
--- /dev/null
+++ b/libs/timer_lib/README
@@ -0,0 +1,37 @@
+timer_lib - v1.0 - Public Domain - 2011 Mattias Jansson
+
+This library provides a cross-platform interface to measure
+elapsed time with (at least) millisecond accuracy. The latest
+source code is always available at
+
+https://github.com/mjansson/timer_lib
+
+This library is put in the public domain; you can redistribute
+it and/or modify it without any restrictions.
+
+For a complete cross-platform application framework, look at
+the foundation library available at
+
+https://github.com/mjansson/foundation_lib
+
+
+VERSION HISTORY
+
+ 0.1 (2011-03-15) Initial release
+ 0.2 (2011-03-20) Removed timer type (always high precision)
+ Fixed timer_ticks_per_second declaration
+ Added test application
+ 0.3 (2011-03-22) Removed unused error checks in POSIX code
+ Made timeGetTime fallback optional in Windows code (define USE_FALLBACK to 1)
+ Fixed check of QPC weirdness (signed issue)
+ 0.4 (2011-03-23) timer_lib_initialize() returns non-zero if failed (no high precision timer available)
+ Changed POSIX path to use CLOCK_MONOTONIC
+ POSIX timer_system use CLOCK_REALTIME for actual timestamp
+ Addded Mach-O path for MacOS X
+ Changed POSIX path to use nanosecond frequency as returned by clock_gettime
+ 0.5 (2012-10-01) Merged (cleaned up) MacOSX build fixes from Nicolas Léveillé
+ 0.6 (2013-01-11) Simplified API, only using tick_t type as timestamp and removing custom timer struct
+ Removed old legacy fallback code for Windows platform
+ 0.7 (2013-01-11) Using platform_lib for platform and compiler abstraction
+ 0.8 (2013-07-30) Made library standalone with no deps (not using deprecated platform_lib)
+ 1.0 (2021-12-15) Updated and cleaned up for clang 10+ and Visual Studio 2022
diff --git a/libs/timer_lib/test.vcxproj b/libs/timer_lib/test.vcxproj
new file mode 100644
index 0000000..468b70e
--- /dev/null
+++ b/libs/timer_lib/test.vcxproj
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{54E95B82-7759-4825-9478-91E76F1C1C89}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>test</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v143</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v143</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v143</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v143</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>build\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
+ <IntDir>build\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>build\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
+ <IntDir>build\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <AdditionalIncludeDirectories>../platform_lib</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <AdditionalIncludeDirectories>../platform_lib</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <AdditionalIncludeDirectories>../platform_lib</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <AdditionalIncludeDirectories>../platform_lib</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="test.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="timer.vcxproj">
+ <Project>{321bab92-2ede-4b3b-939d-bd0be0248c8f}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/libs/timer_lib/timer.c b/libs/timer_lib/timer.c
new file mode 100644
index 0000000..dd6434c
--- /dev/null
+++ b/libs/timer_lib/timer.c
@@ -0,0 +1,174 @@
+/* timer.h - Cross-platform timer library - Public Domain - 2011 Mattias Jansson / Rampant Pixels
+ *
+ * This library provides a cross-platform interface to measure
+ * elapsed time with (at least) millisecond accuracy.
+ *
+ * This library is put in the public domain; you can redistribute
+ * it and/or modify it without any restrictions.
+ *
+ */
+
+#include "timer.h"
+
+#define TIMER_PLATFORM_WINDOWS 0
+#define TIMER_PLATFORM_APPLE 0
+#define TIMER_PLATFORM_POSIX 0
+
+#if defined( _WIN32 ) || defined( _WIN64 )
+# undef TIMER_PLATFORM_WINDOWS
+# define TIMER_PLATFORM_WINDOWS 1
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#elif defined( __APPLE__ )
+# undef TIMER_PLATFORM_APPLE
+# define TIMER_PLATFORM_APPLE 1
+# include <mach/mach_time.h>
+# include <string.h>
+static mach_timebase_info_data_t timerlib_info;
+static void absolutetime_to_nanoseconds (uint64_t mach_time, uint64_t* clock ) { *clock = mach_time * timerlib_info.numer / timerlib_info.denom; }
+#else
+# undef TIMER_PLATFORM_POSIX
+# define TIMER_PLATFORM_POSIX 1
+# include <unistd.h>
+# include <time.h>
+# include <string.h>
+#endif
+
+static tick_t timerlib_freq = 0;
+static double timerlib_oofreq = 0;
+
+
+int timer_lib_initialize( void )
+{
+#if TIMER_PLATFORM_WINDOWS
+ tick_t unused;
+ if( !QueryPerformanceFrequency( (LARGE_INTEGER*)&timerlib_freq ) ||
+ !QueryPerformanceCounter( (LARGE_INTEGER*)&unused ) )
+ return -1;
+#elif TIMER_PLATFORM_APPLE
+ if( mach_timebase_info( &timerlib_info ) )
+ return -1;
+ timerlib_freq = 1000000000ULL;
+#elif TIMER_PLATFORM_POSIX
+ struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
+ if( clock_gettime( CLOCK_MONOTONIC, &ts ) )
+ return -1;
+ timerlib_freq = 1000000000ULL;
+#endif
+
+ timerlib_oofreq = 1.0 / (double)timerlib_freq;
+
+ return 0;
+}
+
+
+void timer_lib_shutdown( void )
+{
+}
+
+
+tick_t timer_current( void )
+{
+#if TIMER_PLATFORM_WINDOWS
+
+ tick_t curclock;
+ QueryPerformanceCounter( (LARGE_INTEGER*)&curclock );
+ return curclock;
+
+#elif TIMER_PLATFORM_APPLE
+
+ tick_t curclock = 0;
+ absolutetime_to_nanoseconds( mach_absolute_time(), &curclock );
+ return curclock;
+
+#elif TIMER_PLATFORM_POSIX
+
+ struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
+ clock_gettime( CLOCK_MONOTONIC, &ts );
+ return ( (uint64_t)ts.tv_sec * 1000000000ULL ) + ts.tv_nsec;
+
+#endif
+}
+
+
+tick_t timer_ticks_per_second( void )
+{
+ return timerlib_freq;
+}
+
+
+deltatime_t timer_elapsed( const tick_t t )
+{
+ return (deltatime_t)( (double)timer_elapsed_ticks( t ) * timerlib_oofreq );
+}
+
+
+tick_t timer_elapsed_ticks( const tick_t t )
+{
+ tick_t dt = 0;
+
+#if TIMER_PLATFORM_WINDOWS
+
+ tick_t curclock = t;
+ QueryPerformanceCounter( (LARGE_INTEGER*)&curclock );
+ dt = curclock - t;
+
+#elif TIMER_PLATFORM_APPLE
+
+ tick_t curclock = t;
+ absolutetime_to_nanoseconds( mach_absolute_time(), &curclock );
+ dt = curclock - t;
+
+#elif TIMER_PLATFORM_POSIX
+
+ tick_t curclock;
+ struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
+ clock_gettime( CLOCK_MONOTONIC, &ts );
+
+ curclock = ( (tick_t)ts.tv_sec * 1000000000ULL ) + ts.tv_nsec;
+ dt = curclock - t;
+
+#endif
+
+ return dt;
+}
+
+
+deltatime_t timer_ticks_to_seconds( const tick_t dt )
+{
+ return (deltatime_t)( (double)dt * timerlib_oofreq );
+}
+
+
+#if TIMER_PLATFORM_WINDOWS
+struct __timeb64 {
+ __time64_t time;
+ unsigned short millitm;
+ short timezone;
+ short dstflag;
+ };
+_CRTIMP errno_t __cdecl _ftime64_s(_Out_ struct __timeb64 * _Time);
+#endif
+
+tick_t timer_system( void )
+{
+#if TIMER_PLATFORM_WINDOWS
+
+ struct __timeb64 tb;
+ _ftime64_s( &tb );
+ return ( (tick_t)tb.time * 1000ULL ) + (tick_t)tb.millitm;
+
+#elif TIMER_PLATFORM_APPLE
+
+ tick_t curclock = 0;
+ absolutetime_to_nanoseconds( mach_absolute_time(), &curclock );
+ return ( curclock / 1000000ULL );
+
+#elif TIMER_PLATFORM_POSIX
+
+ struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
+ clock_gettime( CLOCK_REALTIME, &ts );
+ return ( (uint64_t)ts.tv_sec * 1000ULL ) + ( ts.tv_nsec / 1000000ULL );
+
+#endif
+}
diff --git a/libs/timer_lib/timer.h b/libs/timer_lib/timer.h
new file mode 100644
index 0000000..c7d8bba
--- /dev/null
+++ b/libs/timer_lib/timer.h
@@ -0,0 +1,77 @@
+/* timer.h - Cross-platform timer library - Public Domain - 2011 Mattias Jansson / Rampant Pixels
+ *
+ * This library provides a cross-platform interface to measure
+ * elapsed time with (at least) millisecond accuracy.
+ *
+ * This library is put in the public domain; you can redistribute
+ * it and/or modify it without any restrictions.
+ *
+ */
+
+#pragma once
+
+/*! \file timer.h
+ Time measurements */
+
+#if TIMER_COMPILE
+#define TIMER_API
+#else
+#if __cplusplus
+#define TIMER_API extern "C"
+#else
+#define TIMER_API extern
+#endif
+#endif
+
+#if defined( _WIN32 ) || defined( _WIN64 )
+
+//! Tick type
+typedef unsigned __int64 tick_t;
+
+#else
+
+#include <stdint.h>
+//! Tick type
+typedef uint64_t tick_t;
+
+#endif
+
+//! Deltatime type (float or double)
+//typedef float deltatime_t;
+typedef double deltatime_t;
+
+
+/*! Initialize timer library */
+TIMER_API int timer_lib_initialize( void );
+
+/*! Shutdown timer library */
+TIMER_API void timer_lib_shutdown( void );
+
+/*! Get current timestamp, in ticks of system-specific frequency (queryable with timer_ticks_per_second), measured from some system-specific base timestamp
+ and not in sync with other timestamps
+ \return Current timestamp */
+TIMER_API tick_t timer_current( void );
+
+/*! Get elapsed time since given timestamp
+ \param t Timestamp
+ \return Number of seconds elapsed */
+TIMER_API deltatime_t timer_elapsed( const tick_t t );
+
+/*! Get elapsed ticks since given timestamp
+ \param t Timestamp
+ \return Number of ticks elapsed */
+TIMER_API tick_t timer_elapsed_ticks( const tick_t t );
+
+/*! Get timer frequency, as number of ticks per second
+ \return Ticks per second */
+TIMER_API tick_t timer_ticks_per_second( void );
+
+/*! Get ticks as seconds (effectively calculating ticks/timer_ticks_per_second())
+ \param dt Deltatime in ticks
+ \return Deltatime in seconds */
+TIMER_API deltatime_t timer_ticks_to_seconds( const tick_t dt );
+
+/*! Get system time, in milliseconds since the epoch (UNIX time)
+ \return Current timestamp, in milliseconds */
+TIMER_API tick_t timer_system( void );
+
diff --git a/libs/timer_lib/timer.sln b/libs/timer_lib/timer.sln
new file mode 100644
index 0000000..0146411
--- /dev/null
+++ b/libs/timer_lib/timer.sln
@@ -0,0 +1,36 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "timer", "timer.vcxproj", "{321BAB92-2EDE-4B3B-939D-BD0BE0248C8F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcxproj", "{54E95B82-7759-4825-9478-91E76F1C1C89}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {321BAB92-2EDE-4B3B-939D-BD0BE0248C8F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {321BAB92-2EDE-4B3B-939D-BD0BE0248C8F}.Debug|Win32.Build.0 = Debug|Win32
+ {321BAB92-2EDE-4B3B-939D-BD0BE0248C8F}.Debug|x64.ActiveCfg = Debug|x64
+ {321BAB92-2EDE-4B3B-939D-BD0BE0248C8F}.Debug|x64.Build.0 = Debug|x64
+ {321BAB92-2EDE-4B3B-939D-BD0BE0248C8F}.Release|Win32.ActiveCfg = Release|Win32
+ {321BAB92-2EDE-4B3B-939D-BD0BE0248C8F}.Release|Win32.Build.0 = Release|Win32
+ {321BAB92-2EDE-4B3B-939D-BD0BE0248C8F}.Release|x64.ActiveCfg = Release|x64
+ {321BAB92-2EDE-4B3B-939D-BD0BE0248C8F}.Release|x64.Build.0 = Release|x64
+ {54E95B82-7759-4825-9478-91E76F1C1C89}.Debug|Win32.ActiveCfg = Debug|Win32
+ {54E95B82-7759-4825-9478-91E76F1C1C89}.Debug|Win32.Build.0 = Debug|Win32
+ {54E95B82-7759-4825-9478-91E76F1C1C89}.Debug|x64.ActiveCfg = Debug|x64
+ {54E95B82-7759-4825-9478-91E76F1C1C89}.Debug|x64.Build.0 = Debug|x64
+ {54E95B82-7759-4825-9478-91E76F1C1C89}.Release|Win32.ActiveCfg = Release|Win32
+ {54E95B82-7759-4825-9478-91E76F1C1C89}.Release|Win32.Build.0 = Release|Win32
+ {54E95B82-7759-4825-9478-91E76F1C1C89}.Release|x64.ActiveCfg = Release|x64
+ {54E95B82-7759-4825-9478-91E76F1C1C89}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/libs/timer_lib/timer.vcxproj b/libs/timer_lib/timer.vcxproj
new file mode 100644
index 0000000..83e5ded
--- /dev/null
+++ b/libs/timer_lib/timer.vcxproj
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="timer.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="timer.h" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{321BAB92-2EDE-4B3B-939D-BD0BE0248C8F}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>timer</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v143</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v143</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v143</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v143</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <OutDir>$(SolutionDir)</OutDir>
+ <IntDir>$(Platform)\$(Configuration)\</IntDir>
+ <TargetName>$(ProjectName)32d</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <OutDir>$(SolutionDir)</OutDir>
+ <IntDir>build\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
+ <TargetName>$(ProjectName)64d</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <OutDir>$(SolutionDir)</OutDir>
+ <IntDir>$(Platform)\$(Configuration)\</IntDir>
+ <TargetName>$(ProjectName)32</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <OutDir>$(SolutionDir)</OutDir>
+ <IntDir>build\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
+ <TargetName>$(ProjectName)64</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>TIMER_COMPILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <CompileAsManaged>false</CompileAsManaged>
+ <MultiProcessorCompilation>false</MultiProcessorCompilation>
+ <OmitFramePointers>false</OmitFramePointers>
+ <StringPooling>false</StringPooling>
+ <MinimalRebuild>false</MinimalRebuild>
+ <ExceptionHandling>false</ExceptionHandling>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <FunctionLevelLinking>false</FunctionLevelLinking>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <FloatingPointExceptions>false</FloatingPointExceptions>
+ <CreateHotpatchableImage>false</CreateHotpatchableImage>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <OpenMPSupport>false</OpenMPSupport>
+ <AdditionalIncludeDirectories>
+ </AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>TIMER_COMPILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <CompileAsManaged>false</CompileAsManaged>
+ <MultiProcessorCompilation>false</MultiProcessorCompilation>
+ <OmitFramePointers>false</OmitFramePointers>
+ <StringPooling>false</StringPooling>
+ <MinimalRebuild>false</MinimalRebuild>
+ <ExceptionHandling>false</ExceptionHandling>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <FunctionLevelLinking>false</FunctionLevelLinking>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <FloatingPointExceptions>false</FloatingPointExceptions>
+ <CreateHotpatchableImage>false</CreateHotpatchableImage>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <OpenMPSupport>false</OpenMPSupport>
+ <AdditionalIncludeDirectories>
+ </AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>false</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>TIMER_COMPILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <CompileAsManaged>false</CompileAsManaged>
+ <MultiProcessorCompilation>false</MultiProcessorCompilation>
+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+ <OmitFramePointers>false</OmitFramePointers>
+ <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <FloatingPointExceptions>false</FloatingPointExceptions>
+ <CreateHotpatchableImage>false</CreateHotpatchableImage>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <OpenMPSupport>false</OpenMPSupport>
+ <AdditionalIncludeDirectories>
+ </AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>false</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>TIMER_COMPILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <CompileAsManaged>false</CompileAsManaged>
+ <MultiProcessorCompilation>false</MultiProcessorCompilation>
+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+ <OmitFramePointers>false</OmitFramePointers>
+ <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <FloatingPointExceptions>false</FloatingPointExceptions>
+ <CreateHotpatchableImage>false</CreateHotpatchableImage>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <OpenMPSupport>false</OpenMPSupport>
+ <AdditionalIncludeDirectories>
+ </AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/run.bat b/run.bat
index 739b15b..9795267 100644
--- a/run.bat
+++ b/run.bat
@@ -24,11 +24,12 @@ set LIB_SOURCES=libs\imgui-1.92.1\backends\imgui_impl_dx11.cpp^
libs\ImGuiDatePicker\*.cpp^
libs\zip\src\*.c^
libs\xml.c\src\*.c^
+ libs\timer_lib\*.c^
libs\tinyfiledialogs\tinyfiledialogs.c
@set SOURCES= src\*.cpp src\ui\*.cpp src\locales\*.cpp
@set LIBS=opengl32.lib Advapi32.lib Shell32.lib Ole32.lib User32.lib Pathcch.lib D3D11.lib Comdlg32.lib Kernel32.lib
@set FLAGS=/nologo /Ob0 /MD /Oy- /Zi /FS /W4 /EHsc /utf-8
-@set INCLUDE_DIRS=/I"libs/imgui-1.92.1" /I"libs/imgui-1.92.1/backends" /I"/" /I"libs/simclist-1.5" /I"libs/tinyfiledialogs" /I"libs/zip/src" /I"libs/xml.c/src" /I"libs/" /Iinclude
+@set INCLUDE_DIRS=/I"libs/imgui-1.92.1" /I"libs/imgui-1.92.1/backends" /I"/" /I"libs/timer_lib" /I"libs/simclist-1.5" /I"libs/tinyfiledialogs" /I"libs/zip/src" /I"libs/xml.c/src" /I"libs/" /Iinclude
cl %FLAGS% %INCLUDE_DIRS% %SOURCES% %LIB_SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fd%OUT_DIR%/vc140.pdb /Fo%OUT_DIR%/ /link %LIBS%
if "%1"=="-r" call "%OUT_DIR%/%OUT_EXE%.exe"
diff --git a/src/administration.cpp b/src/administration.cpp
index bbc9a65..ab72647 100644
--- a/src/administration.cpp
+++ b/src/administration.cpp
@@ -6,6 +6,7 @@
#include <time.h>
#include <stdio.h>
+#include "log.hpp"
#include "strops.hpp"
#include "administration.hpp"
#include "administration_writer.hpp"
@@ -395,6 +396,8 @@ static s32 administration_create_sequence_number()
// =======================
void administration_create()
{
+ STOPWATCH_START;
+
g_administration.next_id = 1;
g_administration.next_sequence_number = 1;
@@ -412,8 +415,8 @@ void administration_create()
administration_create_debug_data();
//administration_writer_save_all_async();
- income_statement* statement = (income_statement*)malloc(sizeof(income_statement));
- administration_create_income_statement(statement);
+
+ log_add("Setup took %.3fms.", STOPWATCH_TIME);
}
static void administration_destroy_list(list_t *list)
@@ -520,6 +523,8 @@ static void administration_debug_print_income_statement(income_statement* statem
void administration_create_income_statement(income_statement* statement)
{
+ STOPWATCH_START;
+
assert(statement);
statement->quarter_count = 0;
@@ -702,6 +707,8 @@ void administration_create_income_statement(income_statement* statement)
//administration_debug_print_income_statement(statement);
free(invoice_buffer);
+
+ log_add("Created income statement in %.3fms.", STOPWATCH_TIME);
}
char* administration_file_path_get()
diff --git a/src/administration_writer.cpp b/src/administration_writer.cpp
index c97a828..6a0aba3 100644
--- a/src/administration_writer.cpp
+++ b/src/administration_writer.cpp
@@ -170,6 +170,8 @@ static char* administration_writer_get_eas_scheme_for_address(address addr)
bool administration_writer_save_invoice_blocking(invoice inv)
{
+ STOPWATCH_START;
+
bool result = 1;
int buf_length = 150000; // Ballpark file content size.
char* file_content = (char*)malloc(buf_length);
@@ -312,8 +314,7 @@ bool administration_writer_save_invoice_blocking(invoice inv)
free(file_content);
- log_add(ImGui::GetTime(), "Saved file.");
-
+ log_add("Saved invoice '%s' in %.3fms.", inv.sequential_number, STOPWATCH_TIME);
return result;
}
@@ -339,6 +340,8 @@ static bool administration_writer_save_all_invoices_blocking()
/////////////////////////////
bool administration_writer_save_project_blocking(project project)
{
+ STOPWATCH_START;
+
bool result = 1;
int buf_length = 0;
char* file_content = administration_writer_copy_template(project_save_template, &buf_length);
@@ -358,6 +361,8 @@ bool administration_writer_save_project_blocking(project project)
else if (!administration_writer_write_to_zip(final_path, file_content, final_length)) result = 0;
free(file_content);
+
+ log_add("Saved project '%s' in %.3fms.", project.description, STOPWATCH_TIME);
return result;
}
@@ -383,6 +388,8 @@ static bool administration_writer_save_all_projects_blocking()
/////////////////////////////
bool administration_writer_save_cost_center_blocking(cost_center cost)
{
+ STOPWATCH_START;
+
bool result = 1;
int buf_length = 0;
char* file_content = administration_writer_copy_template(costcenter_save_template, &buf_length);
@@ -400,6 +407,8 @@ bool administration_writer_save_cost_center_blocking(cost_center cost)
else if (!administration_writer_write_to_zip(final_path, file_content, final_length)) result = 0;
free(file_content);
+
+ log_add("Saved cost center '%s' in %.3fms.", cost.code, STOPWATCH_TIME);
return result;
}
@@ -425,6 +434,8 @@ static bool administration_writer_save_all_cost_centers_blocking()
/////////////////////////////
bool administration_writer_save_tax_bracket_blocking(country_tax_bracket bracket)
{
+ STOPWATCH_START;
+
bool result = 1;
int buf_length = 0;
char* file_content = administration_writer_copy_template(taxbracket_save_template, &buf_length);
@@ -443,6 +454,8 @@ bool administration_writer_save_tax_bracket_blocking(country_tax_bracket bracket
else if (!administration_writer_write_to_zip(final_path, file_content, final_length)) result = 0;
free(file_content);
+
+ log_add("Saved tax bracket '%s/%.1f' in %.3fms.", bracket.country_code, bracket.rate, STOPWATCH_TIME);
return result;
}
@@ -470,6 +483,8 @@ static bool administration_writer_save_all_tax_brackets_blocking()
/////////////////////////////
bool administration_writer_save_contact_blocking(contact c)
{
+ STOPWATCH_START;
+
bool result = 1;
int buf_length = 0;
char* file_content = administration_writer_copy_template(contact_save_template, &buf_length);
@@ -497,6 +512,8 @@ bool administration_writer_save_contact_blocking(contact c)
else if (!administration_writer_write_to_zip(final_path, file_content, final_length)) result = 0;
free(file_content);
+
+ log_add("Saved contact '%s' in %.3fms.", c.name, STOPWATCH_TIME);
return result;
}
@@ -528,6 +545,8 @@ static bool administration_writer_save_all_contacts_blocking()
/////////////////////////////
bool administration_writer_save_all_administration_info_blocking()
{
+ STOPWATCH_START;
+
bool result = 1;
int buf_length = 0;
char* file_content = administration_writer_copy_template(administration_save_template, &buf_length);
@@ -543,6 +562,7 @@ bool administration_writer_save_all_administration_info_blocking()
free(file_content);
+ log_add("Saved administration info in %.3fms.", STOPWATCH_TIME);
return result;
}
diff --git a/src/log.cpp b/src/log.cpp
index 960ee85..058b594 100644
--- a/src/log.cpp
+++ b/src/log.cpp
@@ -1,24 +1,47 @@
#include <stdio.h>
#include <stdarg.h>
-
+#include <time.h>
+#include "timer.h"
#include "log.hpp"
log g_log = {0};
-void log_add(double timestamp, const char* fmt, ...)
+log* get_log()
+{
+ return &g_log;
+}
+
+void log_add(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
vsnprintf(g_log.history[g_log.write_cursor], MAX_LEN_LOG_TXT, fmt, args);
va_end(args);
+ tick_t ms_since_epoch = timer_system();
+ char time_buf[50];
+ time_t seconds = (time_t)(ms_since_epoch / 1000);
+ int milliseconds = (int)(ms_since_epoch % 1000);
+
+ // Convert to local time
+ struct tm tm_time;
+ #if defined(_WIN32)
+ localtime_s(&tm_time, &seconds);
+ #else
+ localtime_r(&seconds, &tm_time);
+ #endif
+
+ snprintf(time_buf, 50, "%02d:%02d %02d.%03d",
+ tm_time.tm_hour,
+ tm_time.tm_min,
+ tm_time.tm_sec,
+ milliseconds);
+
char tmp[MAX_LEN_LOG_TXT];
- snprintf(tmp, MAX_LEN_LOG_TXT, "[%.3f] %s", timestamp, g_log.history[g_log.write_cursor]);
+ snprintf(tmp, MAX_LEN_LOG_TXT, "[%s] %s", time_buf, g_log.history[g_log.write_cursor]);
tmp[MAX_LEN_LOG_TXT-1] = 0;
memcpy(g_log.history[g_log.write_cursor], tmp, MAX_LEN_LOG_TXT);
- printf(g_log.history[g_log.write_cursor]);
-
g_log.write_cursor++;
if (g_log.write_cursor >= MAX_LEN_LOG_HISTORY) g_log.write_cursor = 0;
diff --git a/src/main.cpp b/src/main.cpp
index 289ca57..d579a19 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -3,7 +3,7 @@
#include "imgui_impl_dx11.h"
#include <d3d11.h>
#include <tchar.h>
-
+#include "timer.h"
#include "ui.hpp"
#include "administration.hpp"
#include "administration_writer.hpp"
@@ -89,6 +89,7 @@ int main()
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
+ timer_lib_initialize();
administration_writer_create();
administration_create();
@@ -148,6 +149,7 @@ int main()
administration_destroy();
administration_writer_destroy();
+ timer_lib_shutdown();
// Cleanup
ImGui_ImplDX11_Shutdown();
diff --git a/src/ui/ui_expenses.cpp b/src/ui/ui_expenses.cpp
index eb8d8c1..bb23ba9 100644
--- a/src/ui/ui_expenses.cpp
+++ b/src/ui/ui_expenses.cpp
@@ -438,7 +438,15 @@ static void ui_draw_expenses_list()
ImGui::Separator();
if (ImGui::Button(localize("form.yes"), ImVec2(120, 0))) {
- administration_invoice_remove(&selected_for_removal);
+ if (administration_invoice_remove(&selected_for_removal)) {
+ if (administration_writer_delete_entry(selected_for_removal.id)) {
+ ui_set_status(localize("status.saved"));
+ }
+ else {
+ ui_set_status_error(localize("status.saveFailed"));
+ }
+ }
+
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
diff --git a/src/ui/ui_invoices.cpp b/src/ui/ui_invoices.cpp
index fd748c8..d64147f 100644
--- a/src/ui/ui_invoices.cpp
+++ b/src/ui/ui_invoices.cpp
@@ -471,7 +471,14 @@ static void ui_draw_invoices_list()
ImGui::Separator();
if (ImGui::Button(localize("form.yes"), ImVec2(120, 0))) {
- administration_invoice_remove(&selected_for_removal);
+ if (administration_invoice_remove(&selected_for_removal)) {
+ if (administration_writer_delete_entry(selected_for_removal.id)) {
+ ui_set_status(localize("status.saved"));
+ }
+ else {
+ ui_set_status_error(localize("status.saveFailed"));
+ }
+ }
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
diff --git a/src/ui/ui_log.cpp b/src/ui/ui_log.cpp
new file mode 100644
index 0000000..08a0a72
--- /dev/null
+++ b/src/ui/ui_log.cpp
@@ -0,0 +1,20 @@
+#include <stdio.h>
+
+#include "ui.hpp"
+#include "imgui.h"
+#include "log.hpp"
+#include "locales.hpp"
+
+void ui_draw_log()
+{
+ log* l = get_log();
+
+ for (int i = (int)l->history_length-1; i >= 0; i--)
+ {
+ u32 cursor = l->write_cursor - l->history_length + i;
+ if (cursor < 0) {
+ cursor = (l->write_cursor + i) % MAX_LEN_LOG_HISTORY;
+ }
+ ImGui::Text(l->history[cursor]);
+ }
+} \ No newline at end of file
diff --git a/src/ui/ui_main.cpp b/src/ui/ui_main.cpp
index 9ff965d..61c4784 100644
--- a/src/ui/ui_main.cpp
+++ b/src/ui/ui_main.cpp
@@ -12,6 +12,7 @@ typedef enum
REPORT_TAX = 4,
PROJECTS = 5,
SETTINGS = 6,
+ LOG = 7,
END
} dashboard_view_state;
@@ -25,6 +26,7 @@ void (*drawcalls[dashboard_view_state::END])(void) = {
0,
ui_draw_projects,
ui_draw_settings,
+ ui_draw_log,
};
void (*setupcalls[dashboard_view_state::END])(void) = {
@@ -35,6 +37,7 @@ void (*setupcalls[dashboard_view_state::END])(void) = {
0,
ui_setup_projects,
ui_setup_settings,
+ 0,
};
void (*destroycalls[dashboard_view_state::END])(void) = {
@@ -45,6 +48,7 @@ void (*destroycalls[dashboard_view_state::END])(void) = {
0,
0,
ui_destroy_settings,
+ 0,
};
static void set_dashboard_state(dashboard_view_state state)
@@ -68,6 +72,13 @@ void ui_draw_main()
ImGui::EndMenu();
}
+
+ if (ImGui::BeginMenu("Help"))
+ {
+ if (ImGui::MenuItem("Event Log")) { set_dashboard_state(dashboard_view_state::LOG); }
+
+ ImGui::EndMenu();
+ }
ImGui::EndMainMenuBar();
}