Skip to content

Port Turn Watcher from C++/Gtkmm to Electron + React + Redux + Vite (TypeScript)#3

Open
dooglio wants to merge 10 commits into
masterfrom
2-port-to-nodejs-reactjs-vite-redux-electron
Open

Port Turn Watcher from C++/Gtkmm to Electron + React + Redux + Vite (TypeScript)#3
dooglio wants to merge 10 commits into
masterfrom
2-port-to-nodejs-reactjs-vite-redux-electron

Conversation

@dooglio

@dooglio dooglio commented May 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR replaces the legacy C++/Gtkmm desktop application with a modern
Electron + React + Redux Toolkit + Vite stack written in TypeScript. The
C++ source is preserved in cpp/ for historical reference.

What Changed

Repository Restructure

  • Moved all legacy C++ source (Gtkmm, molib, motk, CMake, Debian packaging, Qt5 mockups) into cpp/
  • Created app/ containing the new Electron/React application
  • Converted all legacy .xpm icon files to .png using ImageMagick
  • Generated macOS .icns, Windows .ico, and Linux .png app icons from the original artwork

New Application (app/)

Tech stack: Electron 31 · React 18 · Redux Toolkit · Vite 5 · TypeScript 5

Architecture:

  • electron/main.ts — Main process: window management (main + player HUD), file open/save dialogs via IPC
  • electron/preload.ts — Context bridge exposing file I/O to the renderer
  • electron/fileManager.ts — Load/save JSON files; full backwards compatibility with legacy .turnwatcher XML files via fast-xml-parser
  • src/store/ — Redux slices mirroring the original C++ singleton managers:
    • charactersSlice — replaces Combatant::CharacterManager (with redux-undo for undo/redo)
    • initiativeSlice — replaces Initiative::InitiativeManager
    • statsSlice — replaces Attribute::StatManager (includes all default D&D 3.x stats)
    • settingsSlice — replaces Application::AppSettings
    • uiSlice — dialog state, selection, file path
  • src/types/ — TypeScript interfaces for Character, Effect, StatDefinition, AppSettings, etc.
  • src/utils/ — Pure logic functions:
    • dice.ts — Dice rolling (1d20+mod, arbitrary NdX+Y)
    • health.ts — HP/health status (Normal/Disabled/Dying/Dead/Stabilized)
    • initiative.ts — Initiative sorting, duplicate detection, next-turn logic

UI Components:

  • Main window with menu bar (File/Edit/View/Rounds/Roll/Help), toolbar with original icons, sortable character table, status bar
  • Player HUD window (separate Electron window, player-facing filtered view)
  • Edit Character dialog (tabbed: Base Info / Abilities / Skills & Saves / Notes)
  • Damage / Heal dialog
  • Initiative Roll dialog (auto-roll or manual entry, separate PC/monster tables)
  • Effects Editor (add/edit/delete timed spell/ability effects per character)
  • Stat Manager (configure custom stats, dice formulas, HUD/toolbar visibility)
  • Preferences dialog (combat rules, death threshold, initiative options)
  • About dialog (original splash artwork)

File format:

  • Native: .json (structured to mirror the original molib property-bag hierarchy)
  • Legacy: .turnwatcher XML (read-only import, auto-converted on open)

What's Preserved

  • All original artwork (icons, splash screen, HelmLogo)
  • All game logic semantics (initiative order, health thresholds, bleed-out, ultra-init, skip-dead, alternate death rule, effect round tracking)
  • Full undo/redo stack (replaces C++ TransactionManager)
  • Backwards-compatible file loading for all existing .turnwatcher save files

How to Run

cd app
npm install
npm run dev       # development mode (Vite HMR + Electron)
npm run electron:build  # produce DMG/NSIS/AppImage installers


dooglio added 2 commits May 3, 2026 16:34
Rebuild the initiative tracker from legacy C++ (Gtkmm/Qt) to a modern
Electron + React 18 + Redux Toolkit + Vite stack with TypeScript.

- Add full Electron app under app/ with React renderer, Redux state
  management (with undo/redo), and Vite build tooling
- Move legacy C++ source from src/ to cpp/src/ for archival
- Add README with project overview, structure, and build instructions
- Update .gitignore for Node/Electron/IDE artifacts
@dooglio dooglio linked an issue May 3, 2026 that may be closed by this pull request
@dooglio dooglio self-assigned this May 3, 2026
@dooglio dooglio changed the title full port to nodejs Port Turn Watcher from C++/Gtkmm to Electron + React + Redux + Vite (TypeScript) May 3, 2026
@dooglio

dooglio commented May 3, 2026

Copy link
Copy Markdown
Collaborator Author

A half-hour of work produced this:

image

Some work needs to be done, we need to move the menus into being real, Mac-based menus.

dooglio added 2 commits May 3, 2026 16:54
Migrate from the custom React MenuBar component to a native Electron
Menu built in the main process. Menu actions are forwarded to the
renderer via IPC (`menu:action` channel), where a unified effect
handler dispatches the corresponding Redux actions (file operations,
edit, initiative, HUD, etc.). This provides a more native look and
feel with proper keyboard accelerators across macOS and other platforms.
Replaces traditional Open/Save/Save As file operations with Import/Export
and introduces autosave for crash recovery. State is persisted to a JSON
file in the platform's userData directory via new IPC handlers
(autosave:write, autosave:read, autosave:clear). Updates preload bridge
and menu items accordingly.
@dooglio dooglio requested a review from AlexisWilke May 3, 2026 20:14
dooglio added 6 commits May 3, 2026 23:15
- Add `getZoomFactor()` to apply OS display scale factor on Windows/Linux,
  since Chromium does not handle HiDPI automatically for Electron apps;
  macOS is excluded as the compositor already manages HiDPI scaling
- Set `backgroundColor` on both BrowserWindow instances using
  `nativeTheme.shouldUseDarkColors` to eliminate the white/black flash
  during renderer load on light/dark mode transitions
- Refactor `index.css` to replace all custom CSS variables with CSS System
  Color keywords (e.g. `Canvas`, `ButtonFace`, `AccentColor`) so the UI
  automatically respects OS light/dark mode, accent color, and
  high-contrast accessibility settings
- Retain only app-specific semantic colors (initiative highlight, status
  row tints, health indicators) with an explicit dark-mode override block
- Convert fixed `px` font sizes and icon dimensions to `rem`/`em` units
  so macOS/Windows accessibility font-size preferences are respected
- Add `JumpInDialog` component for characters joining combat mid-round
  with a specific initiative value, replacing the generic edit dialog
- Fix `rounds:delay` and `rounds:ready` to act on the current initiative
  character instead of selected characters, and auto-advance the turn
- Add `resetAllStatuses` dispatch when ending rounds to clear status flags
- Import and use `getCharacterAtPosition` utility for current turn lookup
- Fix initiative arrow direction from ← to → in `CharacterTable`
- Mirror C++ `NextInitTransaction` behavior: automatically reset
  Delayed/Readied status to Normal when a character's turn comes up,
  both in the main turn advance (App.tsx) and the Toolbar prev/next
  handlers
- Rework `JumpInDialog` to mirror C++ `InternalMoveCharacter` +
  `SetPositions` logic: instead of simply resetting status, the jumped-in
  character is now spliced into the sorted initiative order immediately
  after the current-initiative character, and all position values are
  reassigned sequentially (1..N) to reflect the new order
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Port to Node.js / React.js / Vite / Redux / Electron

1 participant