Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "viewer"]
path = viewer
url = https://github.com/calband/calchart-viewer.git
274 changes: 274 additions & 0 deletions DeveloperDocs/ViewerIntegration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
# CalChart Viewer Integration

The CalChart viewer is integrated as a Git submodule at `viewer/`.

## Center View Modes

CalChart supports three center view modes that can be cycled through with **Cmd+Return** (Ctrl+Return on Windows/Linux):

1. **Field View** (`mCanvas`) - The main field editor where you create and edit stuntsheets
2. **Animation View** (`mShadowAnimationPanel`) - Shows the animated preview of the show
3. **Viewer View** (`mViewerPanel`) - Shows the web-based CalChart viewer (experimental)

All three views share the same center pane position, with only one visible at a time. The architecture uses `CenterViewMode` enum to track which view is currently active.

### Experimental Feature Gate

The Viewer is an **experimental feature** that is disabled by default. To enable viewer access via Cmd+Return cycling:

1. Open **CalChart > Preferences > General Setup**
2. Check **"Enable Viewer (experimental)"**
3. Click **OK**

When disabled (default), Cmd+Return cycles: Field → Animation → Field (skipping Viewer).
When enabled, Cmd+Return cycles: Field → Animation → Viewer → Field.

The viewer can also be accessed directly via **View > Preview in Viewer (experimental)...** regardless of the preference setting.

### Implementation

The center view system is implemented in [CalChartFrame.h](../src/CalChartFrame.h) and [CalChartFrame.cpp](../src/CalChartFrame.cpp):

- **`CenterViewMode` enum** - Tracks Field, Animation, or Viewer
- **`ShowCenterView(mode)`** - Shows the requested center pane and hides others
- **`SetCenterViewMode(mode)`** - Sets the mode and updates UI labels
- **`CycleToNextCenterView()`** - Cycles views, checks `Get_AllowViewer()` config to determine if viewer should be included
- **`OnSwapAnimation()`** - Keyboard handler (Cmd+Return) that cycles views
- **`OnToggleViewerPanel()`** - Menu handler that directly toggles viewer visibility
- **`AllowViewer` config flag** - Stored in [CalChartConfiguration.h](../core/CalChartConfiguration.h), default `false`

## Architecture

### HTTP Server (ViewerServer)

CalChart runs an embedded HTTP server ([ViewerServer.cpp](../src/ViewerServer.cpp)) on port 8888 that:

- Serves the viewer HTML/CSS/JS to the embedded wxWebView browser
- Provides a REST API at `/api/show` that returns the current show as JSON
- Provides a health check endpoint at `/api/status`

**Debug vs Release behavior:**
- **Debug builds**: Serve files directly from `viewer/` directory for live editing (using `CMAKE_VIEWER_SOURCE_DIR`)
- **Release builds**: Serve pre-embedded HTML from the binary (generated by [cmake/EmbedViewerHtml.cmake](../cmake/EmbedViewerHtml.cmake))

This gives developers the flexibility to edit viewer HTML/CSS/JS and see changes immediately by refreshing the browser, while maintaining the convenience of a single-binary deployment.

**Important:** The debug file serving uses explicit file routes with regex patterns instead of httplib's `set_mount_point()` to avoid AddressSanitizer (ASAN) crashes in httplib's conditional request handling.

### ViewerPanel

[ViewerPanel.cpp](../src/ViewerPanel.cpp) is a wxPanel that embeds a wxWebView browser:

- **`GoHome()`** - Navigates to `http://localhost:8888`
- **`UpdateShowData()`** - Calls JavaScript `loadCalChartShow()` to refresh show data without page reload
- **`RefreshViewer()`** - Full page reload (rarely used, UpdateShowData preferred)
- **`OnPageLoaded()`** - Triggered when page finishes loading, calls UpdateShowData to load initial show

### JavaScript Integration

The viewer's JavaScript ([viewer/js/](../viewer/js/)) is modified to support CalChart integration:

**[viewer/js/viewer/ApplicationController.js](../viewer/js/viewer/ApplicationController.js):**
```javascript
ApplicationController.prototype.loadFromCalChart = function() {
$.ajax({
url: '/api/show',
dataType: 'json',
success: function(data) {
var show = ShowUtils.fromJSON(data);
// ... load show into viewer
}
});
};
```

**[viewer/js/application.js](../viewer/js/application.js):**
```javascript
// Expose function for CalChart to call via RunScript()
window.loadCalChartShow = function() {
applicationController.loadFromCalChart();
};
```

### Auto-Update on Edits

When editing a show in CalChart, the viewer automatically updates:

**[CalChartFrame::OnUpdate()](../src/CalChartFrame.cpp):**
```cpp
void CalChartFrame::OnUpdate() {
// ... other update logic ...

// If viewer is visible, update it with latest show data
if (mViewerPanel && mCurrentCenterView == CenterViewMode::Viewer) {
mViewerPanel->UpdateShowData();
}
}
```

This means any edit (moving points, changing continuity, etc.) triggers a viewer refresh when the viewer is active.

## Build System

The embedding is handled by:

1. **cmake/EmbedViewerHtml.cmake** - CMake function that reads `viewer/index.html` and generates `CalChartViewerHtml.h`
2. **src/CMakeLists.txt** - Calls `embed_viewer_html()` and adds the generated header to the CalChart target
3. **ViewerServer.cpp** - Uses `CalChart::ViewerHtml::GetViewerHtml()` to get the HTML content

## Development Workflow

### Initial Setup

When cloning the repository:

```bash
git submodule update --init --recursive
```

**The viewer is built automatically by CMake!** If you have Node.js installed, CMake will:
1. Run `npm install` to install dependencies (if needed)
2. Run `grunt build` to compile JavaScript and CSS
3. Create the viewer assets in `viewer/build/`

No manual setup required - just configure and build as normal!

### Building the Viewer

The viewer build is integrated into CMake and happens automatically during configuration/build.

**What CMake does:**
- Checks for Node.js and npm
- Installs npm dependencies (creates `viewer/node_modules/`)
- Builds JavaScript (`viewer/build/js/application.js`)
- Builds CSS (`viewer/build/css/app.css`, `graph.css`, etc.)

**Manual build (if needed):**
```bash
cd viewer
npm install
npm run build
```

Or use the convenience script:
```bash
./scripts/setup-viewer.sh
```

### Editing the Viewer

In debug builds, all viewer files (HTML, CSS, JS, images) are served directly from the `viewer/` directory.

**For active development:**

1. In one terminal, run the viewer's auto-rebuild:
```bash
cd viewer
npm run watch
```
This will automatically rebuild JS/CSS when you edit files.

2. Run CalChart in debug mode
3. Enable the viewer: **Preferences > General Setup > Enable Viewer (experimental)**
4. Switch to Viewer mode (Cmd+Return until you reach viewer, or **View > Preview in Viewer (experimental)...**)
5. Edit viewer files - the browser will automatically refresh via the viewer's built-in refresh mechanism
6. Make changes to CalChart - the viewer updates automatically via `UpdateShowData()`

**What gets served in debug:**
- `/` → `viewer/index.html`
- `/build/js/application.js` → `viewer/build/js/application.js`
- `/build/css/app.css` → `viewer/build/css/app.css`
- `/img/*` → `viewer/img/*`
- All other static assets from `viewer/`

### Testing Release Mode

To test the embedded version (what end users will see):

```bash
cd build/mac-release
cmake -DCMAKE_BUILD_TYPE=Release ../..
cmake --build .
```

Release builds embed the HTML at compile time, so you need to rebuild after viewer changes.

## Implementation Details

The generated header (`build/*/src/generated/CalChartViewerHtml.h`) contains:

- `GetEmbeddedHtml()` - Returns the pre-embedded HTML string
- `GetViewerHtml()` - Smart function that:
- In debug: Reads from `CMAKE_VIEWER_SOURCE_DIR/index.html` if available
- Falls back to embedded HTML if file read fails or in release mode

The `CMAKE_VIEWER_SOURCE_DIR` preprocessor define is only set in Debug builds, making the filesystem path available.

## Key Implementation Details

### ASAN Fix for Static File Serving

The debug build originally used httplib's `set_mount_point()` feature to serve static files, but this caused **AddressSanitizer (ASAN) buffer overflow crashes** when handling HTTP conditional requests (If-None-Match headers).

**Solution:** Implemented explicit file serving with regex routes ([ViewerServer.cpp lines 98-127](../src/ViewerServer.cpp)):
```cpp
#ifdef CMAKE_VIEWER_SOURCE_DIR
mServer->Get(R"(.+\.(css|js|png|jpg|jpeg|gif|svg|ico|json|woff|woff2|ttf|eot))",
[](const httplib::Request& req, httplib::Response& res) {
auto path = std::string(CMAKE_VIEWER_SOURCE_DIR) + req.path;
std::ifstream file(path, std::ios::binary);
// ... manual file reading and Content-Type setting ...
});
#endif
```

This avoids the buggy code path entirely while maintaining live file serving for development.

### Data Flow

**CalChart → Viewer:**
1. User edits show in CalChart
2. `CalChartFrame::OnUpdate()` called
3. If viewer visible: `mViewerPanel->UpdateShowData()`
4. wxWebView executes: `window.loadCalChartShow()`
5. JavaScript calls AJAX: `GET http://localhost:8888/api/show`
6. ViewerServer calls: `CalChartDoc::toViewerJSON()`
7. Viewer receives JSON and calls: `ShowUtils.fromJSON(data)`
8. Viewer re-renders with updated show

**No page reloads needed** - the viewer updates its data model in-place, providing smooth live editing experience.

## Future Enhancements

Possible improvements:

1. **~~Static asset serving~~** - ✅ **DONE** - Debug mode serves CSS/JS/images from `viewer/` directory
2. **Multiple file embedding** - Embed all viewer assets (CSS, JS) for offline use in release builds
3. **Build-time optimization** - Minify HTML/CSS/JS for release builds
4. **~~Auto-refresh on edits~~** - ✅ **DONE** - Viewer updates automatically when show is edited
5. **Configuration UI** - Add viewer-specific settings (refresh rate, layout options)
6. **Error handling** - Better UI feedback when viewer fails to load
7. **Remove experimental gate** - Once stable, enable viewer by default and remove AllowViewer flag

## Updating the Viewer Submodule

To update to the latest viewer version:

```bash
cd viewer
git checkout main # or specific branch/tag
git pull
cd ..
git add viewer
git commit -m "Update viewer submodule to latest"
```

Or to update to a specific commit:

```bash
cd viewer
git checkout <commit-hash>
cd ..
git add viewer
git commit -m "Update viewer submodule to <commit-hash>"
```
4 changes: 4 additions & 0 deletions GETTING_STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,12 @@ The CalChart3 source code lives on [Github](https://github.com/calband/calchart)

```
git clone https://github.com/calband/calchart.git ./calchart
cd calchart
git submodule update --init --recursive
```

**Note:** The CalChart viewer will be built automatically as part of the CMake build process if Node.js is installed. If you don't have Node.js and want the full viewer functionality, install it from [nodejs.org](https://nodejs.org/) before building.

You should see the project being downloaded, and it should appear to be similar to:
```
Cloning into './calchart'...
Expand Down
3 changes: 3 additions & 0 deletions LATEST_RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ Bugs addressed in this release:

Other changes:

* [#773](../../issues/773) Add the minimal integration of CalChart-Viewer


8 changes: 4 additions & 4 deletions RELEASE_INSTRUCTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,9 @@ The current calchart version is 3.8.6. In all commands below, substitute that n
awk '//; /^# Release notes/{while(getline<"LATEST_RELEASE_NOTES.md"){print}}' README.md > tmp && mv tmp README.md
```

5. Clear out LATEST_RELEASE_NOTES.md for next development effort. Update $CCVER+1 in RELEASE_INSTRUCTIONS.md.
5. Merge the branch into main

6. Merge the branch into main

7. Tag the depot
6. Tag the depot

```
$ git tag -a v3.8.6 -m "calchart-3.8.6"
Expand All @@ -40,6 +38,8 @@ $ git push origin v3.8.6

This should trigger the github action, which should publish release notes in Draft form.

7. Do a comment where we clear out LATEST_RELEASE_NOTES.md for next development effort. Update $CCVER+1 in RELEASE_INSTRUCTIONS.md.

8. Once the Release information looks good, Press the Publish Release button.

9. Download the Release artifacts to your machine.
Expand Down
Loading
Loading