Compare commits
	
		
			10 Commits
		
	
	
		
			c076fd969e
			...
			1b2ef4240d
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1b2ef4240d | |||
| 844b32a6fd | |||
| c1f798be7a | |||
| 8b0efde52a | |||
| 489824b1f9 | |||
| ecca252027 | |||
| ab198d6778 | |||
| d60cedf10d | |||
| fd6a14675b | |||
| bf96e3bc9c | 
| @ -1,5 +1,5 @@ | |||||||
| # Mainspring app CMakeLists.txt | # Mainspring app CMakeLists.txt | ||||||
| add_executable(Mainspring WIN32 "src/main.cpp" "src/pch.h" "src/Application.h" "src/Application.cpp" "resource.rc" "src/resources.h") | add_executable(Mainspring WIN32 "src/main.cpp" "src/pch.h" "src/Application.h" "src/Application.cpp" "resource.rc" "src/resources.h" "src/utility.h" "src/utility.cpp") | ||||||
| 
 | 
 | ||||||
| set_property(TARGET Mainspring PROPERTY CXX_STANDARD 20) | set_property(TARGET Mainspring PROPERTY CXX_STANDARD 20) | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										
											BIN
										
									
								
								Mainspring/res/mainspring.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Mainspring/res/mainspring.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 6.0 KiB | 
| @ -2,12 +2,61 @@ | |||||||
| #include "windows.h" | #include "windows.h" | ||||||
| #include "winres.h" | #include "winres.h" | ||||||
| #include "src/resources.h" | #include "src/resources.h" | ||||||
|  | #include "version.h" | ||||||
| 
 | 
 | ||||||
| IDD_DIALOGMAIN DIALOGEX 0, 0, 175, 75 | IDI_ICONMAIN ICON "res/mainspring.ico" | ||||||
|  | 
 | ||||||
|  | IDR_MENUMAIN MENU | ||||||
|  | BEGIN | ||||||
|  |     POPUP "&File" | ||||||
|  |     BEGIN | ||||||
|  |         MENUITEM "&Reset\tCtrl+R" ID_FILE_RESET | ||||||
|  |         MENUITEM "&Save Time\tCtrl+S" ID_FILE_SAVE | ||||||
|  |         MENUITEM "Save Time &As...\tCtrl+Shift+S" ID_FILE_SAVEAS | ||||||
|  |         MENUITEM "&Open Time\tCtrl+O" ID_FILE_OPEN | ||||||
|  |         MENUITEM SEPARATOR | ||||||
|  |         MENUITEM "&Exit\tAlt+F4" ID_FILE_EXIT | ||||||
|  |     END | ||||||
|  | 
 | ||||||
|  |     POPUP "&Help" | ||||||
|  |     BEGIN | ||||||
|  |         MENUITEM "&About" ID_HELP_ABOUT | ||||||
|  |     END | ||||||
|  | END | ||||||
|  | 
 | ||||||
|  | IDD_DIALOGMAIN DIALOGEX 0, 0, 200, 70 | ||||||
| STYLE WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | DS_SETFONT | STYLE WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | DS_SETFONT | ||||||
| FONT 8, "MS Shell Dlg", 400, 0, 0x1 | FONT 8, "MS Shell Dlg", 400, 0, 0x1 | ||||||
|  | MENU IDR_MENUMAIN | ||||||
| BEGIN | BEGIN | ||||||
|     CTEXT "APPNAME", IDC_STATICTITLE, 30, 5, 115, 20, SS_CENTERIMAGE |     CTEXT "APPNAME", IDC_STATICTITLE, 0, 0, 200, 20, SS_CENTERIMAGE | ||||||
|     CTEXT "TIME", IDC_STATICTIME, 10, 25, 155, 25, SS_CENTERIMAGE |     CTEXT "TIME", IDC_STATICTIME, 8, 20, 184, 28, SS_CENTERIMAGE | SS_SUNKEN | ||||||
|     DEFPUSHBUTTON "STARTPAUSE" IDC_BUTTONSTARTPAUSE, 63, 55, 50, 15 |     DEFPUSHBUTTON "STARTPAUSE" IDC_BUTTONSTARTPAUSE, 75, 53, 50, 15 | ||||||
|  | END | ||||||
|  | 
 | ||||||
|  | IDA_ACCELMAIN ACCELERATORS | ||||||
|  | BEGIN | ||||||
|  |     "R",    ID_FILE_RESET,    CONTROL, VIRTKEY | ||||||
|  |     "S",    ID_FILE_SAVE,   CONTROL, VIRTKEY | ||||||
|  |     "S",    ID_FILE_SAVEAS, CONTROL, SHIFT, VIRTKEY | ||||||
|  |     "O",    ID_FILE_OPEN,   CONTROL, VIRTKEY | ||||||
|  | END | ||||||
|  | 
 | ||||||
|  | VS_VERSION_INFO VERSIONINFO | ||||||
|  | BEGIN | ||||||
|  |     BLOCK "StringFileInfo" | ||||||
|  |     BEGIN | ||||||
|  |         BLOCK "040904b0" | ||||||
|  |         BEGIN | ||||||
|  |             VALUE "CompanyName", "Grayson Riffe" | ||||||
|  |             VALUE "FileDescription", "Mainspring" | ||||||
|  |             VALUE "ProductName", "Mainspring - A simple timekeeper" | ||||||
|  |             VALUE "ProductVersion", APPVERSION | ||||||
|  |             VALUE "LegalCopyright", "Copyright (C) 2025" | ||||||
|  |         END | ||||||
|  |     END | ||||||
|  |     BLOCK "VarFileInfo" | ||||||
|  |     BEGIN | ||||||
|  |         VALUE "Translation", 0x409, 1200 | ||||||
|  |     END | ||||||
| END | END | ||||||
| @ -2,6 +2,14 @@ | |||||||
| #include "pch.h" | #include "pch.h" | ||||||
| #include "Application.h" | #include "Application.h" | ||||||
| #include "resources.h" | #include "resources.h" | ||||||
|  | #include "utility.h" | ||||||
|  | 
 | ||||||
|  | // Define timer IDs
 | ||||||
|  | #define IDT_UPDATEAPP 1 | ||||||
|  | #define IDT_SAVEDTEXT 2 | ||||||
|  | 
 | ||||||
|  | // Define window message to update the timer display
 | ||||||
|  | #define WM_UPDATEAPP WM_USER + 1 | ||||||
| 
 | 
 | ||||||
| // Enable visual styles
 | // Enable visual styles
 | ||||||
| #pragma comment(linker, "\"/manifestdependency:type='win32' \ | #pragma comment(linker, "\"/manifestdependency:type='win32' \ | ||||||
| @ -12,12 +20,31 @@ namespace mainspring { | |||||||
|     Application::Application(const char* appName, const char* appVersion) |     Application::Application(const char* appName, const char* appVersion) | ||||||
|         : m_appName(appName) |         : m_appName(appName) | ||||||
|         , m_appVersion(appVersion) |         , m_appVersion(appVersion) | ||||||
|  |         , m_dlg() | ||||||
|  |         , m_timing(false) | ||||||
|  |         , m_startpauseButtonPressed(false) | ||||||
|  |         , m_elapsedSaved() | ||||||
|  |         , m_startTime() | ||||||
|  |         , m_file() | ||||||
|  |         , m_showSavedText(false) | ||||||
|     { |     { | ||||||
|         std::cout << std::format("{} {}\n", m_appName, m_appVersion); |         std::cout << std::format("{} {}\n", m_appName, m_appVersion); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void Application::run() { |     void Application::run() { | ||||||
|         DialogBoxParam(nullptr, MAKEINTRESOURCE(IDD_DIALOGMAIN), nullptr, reinterpret_cast<DLGPROC>(mainDlgProc), reinterpret_cast<LPARAM>(this)); |         std::string configPath = getConfigPath(); | ||||||
|  |         std::string recentFile; | ||||||
|  |         if (readFile(configPath.c_str(), recentFile) && !recentFile.empty()) | ||||||
|  |             open(recentFile); | ||||||
|  | 
 | ||||||
|  |         m_dlg = CreateDialogParam(nullptr, MAKEINTRESOURCE(IDD_DIALOGMAIN), nullptr, reinterpret_cast<DLGPROC>(mainDlgProc), reinterpret_cast<LPARAM>(this)); | ||||||
|  | 
 | ||||||
|  |         HACCEL hAccel = LoadAccelerators(GetModuleHandle(NULL), MAKEINTRESOURCE(IDA_ACCELMAIN)); | ||||||
|  |         MSG msg = {}; | ||||||
|  |         ShowWindow(m_dlg, SW_SHOW); | ||||||
|  |         while (GetMessage(&msg, nullptr, 0, 0)) | ||||||
|  |             if (!TranslateAccelerator(m_dlg, hAccel, &msg)) | ||||||
|  |                 IsDialogMessage(m_dlg, &msg); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     BOOL CALLBACK Application::mainDlgProc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam) { |     BOOL CALLBACK Application::mainDlgProc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam) { | ||||||
| @ -28,6 +55,7 @@ namespace mainspring { | |||||||
|                 app = reinterpret_cast<Application*>(lParam); |                 app = reinterpret_cast<Application*>(lParam); | ||||||
| 
 | 
 | ||||||
|                 SetWindowText(dlg, app->m_appName); |                 SetWindowText(dlg, app->m_appName); | ||||||
|  |                 SendMessage(dlg, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICONMAIN)))); | ||||||
| 
 | 
 | ||||||
|                 POINT cursor = {}; |                 POINT cursor = {}; | ||||||
|                 GetCursorPos(&cursor); |                 GetCursorPos(&cursor); | ||||||
| @ -36,30 +64,206 @@ namespace mainspring { | |||||||
|                 GetMonitorInfo(MonitorFromPoint(cursor, MONITOR_DEFAULTTONEAREST), &mi); |                 GetMonitorInfo(MonitorFromPoint(cursor, MONITOR_DEFAULTTONEAREST), &mi); | ||||||
|                 SetWindowPos(dlg, nullptr, mi.rcMonitor.left + 100, mi.rcMonitor.top + 100, 0, 0, SWP_NOZORDER | SWP_NOSIZE); |                 SetWindowPos(dlg, nullptr, mi.rcMonitor.left + 100, mi.rcMonitor.top + 100, 0, 0, SWP_NOZORDER | SWP_NOSIZE); | ||||||
| 
 | 
 | ||||||
|                 SetDlgItemText(dlg, IDC_STATICTITLE, app->m_appName); |  | ||||||
|                 LOGFONT lFont = {}; |                 LOGFONT lFont = {}; | ||||||
|                 lFont.lfHeight = 30; |                 lFont.lfHeight = 30; | ||||||
|                 HFONT titleFont = CreateFontIndirect(&lFont); |                 HFONT titleFont = CreateFontIndirect(&lFont); | ||||||
|                 SendMessage(GetDlgItem(dlg, IDC_STATICTITLE), WM_SETFONT, reinterpret_cast<WPARAM>(titleFont), NULL); |                 SendMessage(GetDlgItem(dlg, IDC_STATICTITLE), WM_SETFONT, reinterpret_cast<WPARAM>(titleFont), NULL); | ||||||
| 
 | 
 | ||||||
|                 lFont.lfHeight = 40; |                 std::memcpy(lFont.lfFaceName, "Consolas", 9); | ||||||
|  |                 lFont.lfHeight = 60; | ||||||
|                 HFONT timeFont = CreateFontIndirect(&lFont); |                 HFONT timeFont = CreateFontIndirect(&lFont); | ||||||
|                 SendMessage(GetDlgItem(dlg, IDC_STATICTIME), WM_SETFONT, reinterpret_cast<WPARAM>(timeFont), NULL); |                 SendMessage(GetDlgItem(dlg, IDC_STATICTIME), WM_SETFONT, reinterpret_cast<WPARAM>(timeFont), NULL); | ||||||
| 
 | 
 | ||||||
|                 SetDlgItemText(dlg, IDC_BUTTONSTARTPAUSE, "Start"); |                 SendMessage(dlg, WM_UPDATEAPP, NULL, NULL); | ||||||
|  |                 SetTimer(dlg, IDT_UPDATEAPP, 50, nullptr); | ||||||
| 
 | 
 | ||||||
|                 return TRUE; |                 return TRUE; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             case WM_CLOSE: |             case WM_COMMAND: | ||||||
|                 EndDialog(dlg, 0); |                 switch (LOWORD(wParam)) { | ||||||
|  |                     case IDC_BUTTONSTARTPAUSE: | ||||||
|  |                         app->m_startpauseButtonPressed = true; | ||||||
|  |                         return TRUE; | ||||||
|  | 
 | ||||||
|  |                     case ID_FILE_RESET: { | ||||||
|  |                         if (!app->m_file.empty()) | ||||||
|  |                             app->save(); | ||||||
|  | 
 | ||||||
|  |                         app->reset(); | ||||||
|  |                         return TRUE; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     case ID_FILE_SAVE: { | ||||||
|  |                         app->save(); | ||||||
|  |                         return TRUE; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     case ID_FILE_SAVEAS: { | ||||||
|  |                         app->save(true); | ||||||
|  |                         return TRUE; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     case ID_FILE_OPEN: { | ||||||
|  |                         if (!app->m_file.empty()) | ||||||
|  |                             app->save(); | ||||||
|  | 
 | ||||||
|  |                         app->open(); | ||||||
|  |                         return TRUE; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     case ID_FILE_EXIT: { | ||||||
|  |                         SendMessage(dlg, WM_CLOSE, NULL, NULL); | ||||||
|  |                         return TRUE; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     case ID_HELP_ABOUT: | ||||||
|  |                         MessageBox(dlg, std::format("{} {}\nCopyright Grayson Riffe 2025\ngraysonriffe.com\n\n" | ||||||
|  |                             "\tMainspring is a simple timekeeper. It can be used as a simple stopwatch for short-term activities, or " | ||||||
|  |                             "it can log hours on a longer-term project. Times can be saved to a file, and any subsequent uses will autosave to that file. The most recent " | ||||||
|  |                             "time will be loaded when Mainspring starts.", app->m_appName, app->m_appVersion).c_str(), std::format("About {}", app->m_appName).c_str(), MB_OK); | ||||||
|  |                         return TRUE; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 return FALSE; | ||||||
|  | 
 | ||||||
|  |             case WM_TIMER: | ||||||
|  |                 switch (wParam) { | ||||||
|  |                     case IDT_UPDATEAPP: | ||||||
|  |                         SendMessage(dlg, WM_UPDATEAPP, NULL, NULL); | ||||||
|  |                         return TRUE; | ||||||
|  | 
 | ||||||
|  |                     case IDT_SAVEDTEXT: | ||||||
|  |                         app->m_showSavedText = false; | ||||||
|  |                         return TRUE; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 return FALSE; | ||||||
|  | 
 | ||||||
|  |                 return TRUE; | ||||||
|  | 
 | ||||||
|  |             case WM_UPDATEAPP: { | ||||||
|  |                 if (app->m_startpauseButtonPressed) { | ||||||
|  |                     app->m_startpauseButtonPressed = false; | ||||||
|  | 
 | ||||||
|  |                     if (!app->m_timing) | ||||||
|  |                         app->m_startTime = Clock::now(); | ||||||
|  |                     else | ||||||
|  |                         app->m_elapsedSaved += app->getElapsed(); | ||||||
|  | 
 | ||||||
|  |                     app->m_timing = !app->m_timing; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if (app->m_showSavedText) | ||||||
|  |                     SetDlgItemText(dlg, IDC_STATICTITLE, "Saved!"); | ||||||
|  | 
 | ||||||
|  |                 else if (!app->m_file.empty()) { | ||||||
|  |                     std::string filename = app->m_file.substr(app->m_file.find_last_of('\\') + 1); | ||||||
|  |                     SetDlgItemText(dlg, IDC_STATICTITLE, filename.c_str()); | ||||||
|  |                 } | ||||||
|  |                 else | ||||||
|  |                     SetDlgItemText(dlg, IDC_STATICTITLE, app->m_appName); | ||||||
|  | 
 | ||||||
|  |                 if (app->m_timing) | ||||||
|  |                     SetDlgItemText(dlg, IDC_BUTTONSTARTPAUSE, "Pause"); | ||||||
|  |                 else | ||||||
|  |                     SetDlgItemText(dlg, IDC_BUTTONSTARTPAUSE, !app->m_elapsedSaved ? "Start" : "Resume"); | ||||||
|  | 
 | ||||||
|  |                 Seconds totalTime = app->m_elapsedSaved + app->getElapsed(); | ||||||
|  | 
 | ||||||
|  |                 uint32_t hr = totalTime / (3600), min = totalTime % (3600) / 60, sec = totalTime % 60; | ||||||
|  |                 SetDlgItemText(dlg, IDC_STATICTIME, std::format("{:03}:{:02}:{:02}", hr, min, sec).c_str()); | ||||||
|  | 
 | ||||||
|  |                 return TRUE; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             case WM_CLOSE: { | ||||||
|  |                 if (!app->m_file.empty()) | ||||||
|  |                     app->save(); | ||||||
|  | 
 | ||||||
|  |                 std::string configPath = app->getConfigPath(); | ||||||
|  |                 writeFile(configPath.c_str(), app->m_file); | ||||||
|  | 
 | ||||||
|  |                 KillTimer(dlg, 1); | ||||||
|  |                 DestroyWindow(dlg); | ||||||
|  |                 return TRUE; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             case WM_DESTROY: | ||||||
|  |                 PostQuitMessage(0); | ||||||
|                 return TRUE; |                 return TRUE; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return FALSE; |         return FALSE; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Application::~Application() { |     std::string Application::getConfigPath() { | ||||||
|  |         char appDataPath[MAX_PATH] = {}; | ||||||
|  |         SHGetFolderPath(nullptr, CSIDL_APPDATA, nullptr, NULL, appDataPath); | ||||||
|  |         return std::string(appDataPath) + "\\" + m_appName + "\\last"; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|  |     Seconds Application::getElapsed() { | ||||||
|  |         if (m_timing) | ||||||
|  |             return Duration(Clock::now() - m_startTime).count(); | ||||||
|  |         else | ||||||
|  |             return 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void Application::reset() { | ||||||
|  |         m_timing = false; | ||||||
|  |         m_elapsedSaved = 0; | ||||||
|  |         m_file.clear(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void Application::save(bool saveas) { | ||||||
|  |         if (m_file.empty() || saveas) { | ||||||
|  |             OPENFILENAME ofn = {}; | ||||||
|  |             ofn.lStructSize = sizeof(ofn); | ||||||
|  |             ofn.hwndOwner = m_dlg; | ||||||
|  |             ofn.lpstrFilter = "Mainspring Time File (*.mspring)\0*.mspring\0\0"; | ||||||
|  |             ofn.lpstrDefExt = "mspring"; | ||||||
|  |             char fileBuf[MAX_PATH] = {}; | ||||||
|  |             ofn.lpstrFile = fileBuf; | ||||||
|  |             ofn.nMaxFile = MAX_PATH; | ||||||
|  |             ofn.Flags = OFN_OVERWRITEPROMPT; | ||||||
|  | 
 | ||||||
|  |             if (GetSaveFileName(&ofn)) | ||||||
|  |                 m_file = fileBuf; | ||||||
|  |             else | ||||||
|  |                 return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Seconds totalTime = m_elapsedSaved + getElapsed(); | ||||||
|  |         std::string saveData = std::to_string(totalTime); | ||||||
|  |         writeFile(m_file.c_str(), saveData); | ||||||
|  |         m_showSavedText = true; | ||||||
|  |         SetTimer(m_dlg, IDT_SAVEDTEXT, 3000, nullptr); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void Application::open(std::string path) { | ||||||
|  |         if (path.empty()) { | ||||||
|  |             OPENFILENAME ofn = {}; | ||||||
|  |             ofn.lStructSize = sizeof(ofn); | ||||||
|  |             ofn.hwndOwner = m_dlg; | ||||||
|  |             ofn.lpstrFilter = "Mainspring Time File (*.mspring)\0*.mspring\0\0"; | ||||||
|  |             ofn.lpstrDefExt = "mspring"; | ||||||
|  |             char fileBuf[MAX_PATH] = {}; | ||||||
|  |             ofn.lpstrFile = fileBuf; | ||||||
|  |             ofn.nMaxFile = MAX_PATH; | ||||||
|  |             ofn.Flags = OFN_FILEMUSTEXIST; | ||||||
|  | 
 | ||||||
|  |             if (GetOpenFileName(&ofn)) | ||||||
|  |                 m_file = fileBuf; | ||||||
|  |             else | ||||||
|  |                 return; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |             m_file = path; | ||||||
|  | 
 | ||||||
|  |         std::string openData; | ||||||
|  |         if (readFile(m_file.c_str(), openData)) | ||||||
|  |             // Update status text;
 | ||||||
|  |             m_elapsedSaved = std::stoull(openData); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -1,17 +1,39 @@ | |||||||
| // Application class header
 | // Application class header
 | ||||||
| 
 | 
 | ||||||
| namespace mainspring { | namespace mainspring { | ||||||
|  |     using Clock = std::chrono::high_resolution_clock; | ||||||
|  |     using TimePoint = std::chrono::time_point<Clock>; | ||||||
|  |     using Duration = std::chrono::duration<double, std::ratio<1, 1>>; | ||||||
|  | 
 | ||||||
|  |     using Seconds = uint64_t; | ||||||
|  | 
 | ||||||
|     class Application { |     class Application { | ||||||
|     public: |     public: | ||||||
|         Application(const char* appName, const char* appVersion); |         Application(const char* appName, const char* appVersion); | ||||||
| 
 | 
 | ||||||
|         void run(); |         void run(); | ||||||
| 
 |  | ||||||
|         ~Application(); |  | ||||||
|     private: |     private: | ||||||
|         static BOOL CALLBACK mainDlgProc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam); |         static BOOL CALLBACK mainDlgProc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam); | ||||||
| 
 | 
 | ||||||
|  |         std::string getConfigPath(); | ||||||
|  | 
 | ||||||
|  |         Seconds getElapsed(); // Gets the current timing session time
 | ||||||
|  | 
 | ||||||
|  |         void reset(); | ||||||
|  |         void save(bool saveas = false); | ||||||
|  |         void open(std::string path = ""); | ||||||
|  | 
 | ||||||
|         const char* m_appName; |         const char* m_appName; | ||||||
|         const char* m_appVersion; |         const char* m_appVersion; | ||||||
|  | 
 | ||||||
|  |         HWND m_dlg; | ||||||
|  | 
 | ||||||
|  |         // Current state of the app
 | ||||||
|  |         bool m_timing; // Currently timing?
 | ||||||
|  |         bool m_startpauseButtonPressed; // Was the start / pause button pressed?
 | ||||||
|  |         Seconds m_elapsedSaved; // Time saved
 | ||||||
|  |         TimePoint m_startTime; // When the current timing session was started
 | ||||||
|  |         std::string m_file; // Current time file path
 | ||||||
|  |         bool m_showSavedText; // Save confirmation
 | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| @ -3,6 +3,7 @@ | |||||||
| // IO and strings
 | // IO and strings
 | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <fstream> | #include <fstream> | ||||||
|  | #include <filesystem> | ||||||
| #include <string> | #include <string> | ||||||
| #include <format> | #include <format> | ||||||
| 
 | 
 | ||||||
| @ -11,4 +12,6 @@ | |||||||
| 
 | 
 | ||||||
| // Windows
 | // Windows
 | ||||||
| #define WIN32_LEAN_AND_MEAN | #define WIN32_LEAN_AND_MEAN | ||||||
| #include <Windows.h> | #include <Windows.h> | ||||||
|  | #include <commdlg.h> | ||||||
|  | #include <ShlObj.h> | ||||||
| @ -1,6 +1,26 @@ | |||||||
| // Win32 resources
 | // Win32 resources
 | ||||||
| #define IDD_DIALOGMAIN 101 |  | ||||||
| 
 | 
 | ||||||
| #define IDC_BUTTONSTARTPAUSE 1001 | // Icon
 | ||||||
| #define IDC_STATICTITLE 1002 | #define IDI_ICONMAIN 101 | ||||||
| #define IDC_STATICTIME 1003 | 
 | ||||||
|  | // Dialog
 | ||||||
|  | #define IDD_DIALOGMAIN  201 | ||||||
|  | 
 | ||||||
|  | // Menu
 | ||||||
|  | #define IDR_MENUMAIN    301 | ||||||
|  | #define ID_FILE_RESET     302 | ||||||
|  | #define ID_FILE_SAVE    303 | ||||||
|  | #define ID_FILE_SAVEAS  304 | ||||||
|  | #define ID_FILE_OPEN    305 | ||||||
|  | #define ID_FILE_EXIT    306 | ||||||
|  | 
 | ||||||
|  | #define ID_HELP_ABOUT   311 | ||||||
|  | 
 | ||||||
|  | // Accelerators
 | ||||||
|  | #define IDA_ACCELMAIN 401 | ||||||
|  | 
 | ||||||
|  | // Controls (text and buttons)
 | ||||||
|  | #define IDC_BUTTONSTARTPAUSE    1001 | ||||||
|  | #define IDC_STATICTITLE         1002 | ||||||
|  | #define IDC_STATICTIME          1003 | ||||||
|  | #define IDC_STATICICON          1004 | ||||||
|  | |||||||
							
								
								
									
										30
									
								
								Mainspring/src/utility.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Mainspring/src/utility.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | // Utility implementation
 | ||||||
|  | #include "pch.h" | ||||||
|  | #include "utility.h" | ||||||
|  | 
 | ||||||
|  | namespace mainspring { | ||||||
|  |     bool readFile(const char* filename, std::string& out) { | ||||||
|  |         std::ifstream fileStream(filename, std::ios::binary | std::ios::ate); | ||||||
|  |         if (!fileStream.is_open()) | ||||||
|  |             return false; | ||||||
|  | 
 | ||||||
|  |         size_t fileSize = fileStream.tellg(); | ||||||
|  |         fileStream.seekg(0); | ||||||
|  |         out.resize(fileSize); | ||||||
|  |         fileStream.read(out.data(), fileSize); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool writeFile(const char* filename, const std::string& in) { | ||||||
|  |         std::string folder = filename; | ||||||
|  |         folder.resize(folder.find_last_of('\\')); | ||||||
|  |         if (!std::filesystem::exists(folder)) | ||||||
|  |             std::filesystem::create_directories(folder); | ||||||
|  |         std::ofstream fileStream(filename, std::ios::binary | std::ios::trunc); | ||||||
|  |         if (!fileStream.is_open()) | ||||||
|  |             return false; | ||||||
|  | 
 | ||||||
|  |         fileStream << in; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										6
									
								
								Mainspring/src/utility.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Mainspring/src/utility.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | // Utility header
 | ||||||
|  | 
 | ||||||
|  | namespace mainspring { | ||||||
|  |     bool readFile(const char* filename, std::string& out); | ||||||
|  |     bool writeFile(const char* filename, const std::string& in); | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user