Skip to content
Merged
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
8 changes: 8 additions & 0 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,14 @@ jobs:
--project tests/SQLBI.Whiteboard.Core.SmokeTests/SQLBI.Whiteboard.Core.SmokeTests.csproj
--configuration Release

# The highlighting adapter runs on AvalonEdit, so its tests need WPF.
- name: Application smoke tests
if: needs.changes.outputs.code == 'true'
run: >-
dotnet run
--project tests/SQLBI.Whiteboard.SmokeTests/SQLBI.Whiteboard.SmokeTests.csproj
--configuration Release

installer:
name: Build installers
needs: changes
Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ broke. The heading is parsed by `scripts/release-notes.ps1`, so keep its shape;
under it is ordinary Markdown, and the renderer handles paragraphs, lists, links, `code`
and **bold**.

## 1.4.0 - 8 September 2026

### Eleven more languages in a text container
The title-bar chip now also offers Python, C, C++, Java, C#, JavaScript, TypeScript,
Visual Basic .NET, R, Rust, and PHP. Choose one and the text is highlighted, on the board
and in an export. These languages are not formatted and are not recognized on paste: pick
them by hand.

### F6 asks for a vote on a language it cannot format
On one of the new languages, **F6** opens a short note with a link to that language's issue
on GitHub. A thumbs-up there is how the next formatter is chosen. DAX, SQL, and KQL still
format, and Plain text is still quiet.

## 1.3.1 - 5 September 2026

### KQL joins DAX and SQL in text containers
Expand Down
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ typing the code themselves or directing a coding agent. It is deliberately tool-
```powershell
dotnet build Whiteboard.sln -c Release
dotnet run --project .\tests\SQLBI.Whiteboard.Core.SmokeTests\SQLBI.Whiteboard.Core.SmokeTests.csproj
dotnet run --project .\tests\SQLBI.Whiteboard.SmokeTests\SQLBI.Whiteboard.SmokeTests.csproj
```

The first harness is framework-neutral. The second needs WPF, and covers what only
the application can answer, such as syntax highlighting.

`TreatWarningsAsErrors` is on for every project, so a warning fails the build.
4. Open the pull request against `main`:

Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
scripts/build-installer.ps1 both read it from here, so releasing is a reviewed change
to this line rather than an edit in a pipeline variable group.
-->
<VersionPrefix>1.3.1</VersionPrefix>
<VersionPrefix>1.4.0</VersionPrefix>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ How the project is developed and shipped is documented separately:
- SVG stays vector: it is stored as its markup and redrawn at every zoom and resize rather than rasterized on arrival. Pasting SVG markup that was copied as text — the output of a DAX SVG measure, for instance — creates a picture, and copying an SVG container puts both the markup and a bitmap on the clipboard
- Image selection, movement, resizing, and deletion
- Text containers created by pasting plain text, with display and in-place edit modes
- Plain-text, DAX, and SQL Server language modes, with live syntax highlighting and local F6 formatting
- Fifteen text-container languages with live syntax highlighting, and local F6 formatting for DAX, SQL Server, and KQL
- Containers automatically carry strokes that touch only that container when moved or resized
- LiveView containers for GPU-backed capture of an application window or display, with freeze/resume and saved last-frame previews
- Double-click a container to center it and fit it to the canvas
Expand Down Expand Up @@ -198,8 +198,8 @@ Use **Copy settings** after finding a useful combination so the exact values can
| Ctrl+V | Paste prefers an image (including a file on the clipboard) over text. Otherwise create a text container from plain text |
| F2 | Edit the selected text container, or rename the selected frame |
| View > Frame | Add a frame the size of the screen: a slide drawn on the board, selected by its edge or its tab, which Export takes as it is |
| Language chip | Choose Plain text, DAX, or SQL Server on a selected text container |
| F6 | Format DAX, SQL, or KQL on the selected text container; DAX wraps to the container's columns. In F2, formats in place |
| Language chip | Choose one of fifteen languages on a selected text container |
| F6 | Format DAX, SQL, or KQL on the selected text container; DAX wraps to the container's columns. In F2, formats in place. On a language that is only highlighted, opens that language's issue on GitHub |
| Drag right edge, or Shift + drag handle | Change a text container's width in columns and reflow it; the handle shows the count. A plain drag of the corner scales it |
| Ctrl+Enter | Commit the F2 edit, including an F6 format done in that session, and return to display mode |
| Escape | Cancel the active text edit, close the command strip, or leave full screen or canvas only |
Expand All @@ -222,7 +222,7 @@ With the mouse, selection is automatic: click a container to move it, or drag th

Imported images, LiveViews, and text objects act as containers. A completed stroke is linked when it touches exactly one container, including crossing its edge; a stroke touching multiple containers remains independent. Moving or resizing a container transforms its linked strokes with it. **View → Bring to front** and **View → Send to back** reorder the selected container and those linked strokes. Deleting a container also deletes all of its linked strokes. Undo/redo treats each complete container operation as one action.

Paste plain text to create a selected text container in display mode. **Help → Preferences** has Snippet format order: paste tries those languages from top to bottom and uses the first that accepts the text. Plain text always accepts and comes last by default, so DAX, SQL, and KQL are recognized on paste; a language claims a snippet only when it carries an operator, function, or keyword, so a bare word stays a note. Put Plain text first to keep every paste plain. A language added by an update joins in front of Plain text unless Plain text is first. Recognized extensions (`.dax`, `.sql`, `.kql`, `.txt`) keep their language; other dropped text files use the same order. Choose **Plain text**, **DAX**, **SQL Server**, or **KQL** from the title-bar chip afterward. Press **F6** to format DAX, SQL, or KQL on the selected container without entering edit. Press **F2** to edit the body; the same list is in the title bar while editing. In F2, **F6** formats in place; **Ctrl+Enter** commits that edit (including the format) and returns to display. **Escape** restores the previous text, language, and dimensions. Text reflows while its edit-mode resize grip changes the width, and the height grows automatically when necessary. Double-click still centers and fits the container. Syntax highlighting applies in both edit and display modes. A language-aware title identifies a defined DAX, SQL, or KQL object when possible. SQL Server mode targets SQL Server 2025 T-SQL, preserves `GO` batch separators, and leaves invalid scripts unchanged. KQL mode reads Kusto through Microsoft's own parser and likewise leaves an invalid query unchanged. In display mode, resizing preserves the aspect ratio and scales the complete text visual without reflowing it.
Paste plain text to create a selected text container in display mode. **Help → Preferences** has Snippet format order: paste tries those languages from top to bottom and uses the first that accepts the text. Plain text always accepts and comes last by default, so DAX, SQL, and KQL are recognized on paste; a language claims a snippet only when it carries an operator, function, or keyword, so a bare word stays a note. Put Plain text first to keep every paste plain. A language added by an update joins in front of Plain text unless Plain text is first. Recognized extensions (`.dax`, `.sql`, `.kql`, `.txt`) keep their language; other dropped text files use the same order. Choose **Plain text**, **DAX**, **SQL Server**, or **KQL** from the title-bar chip afterward, or one of **Python**, **C**, **C++**, **Java**, **C#**, **JavaScript**, **TypeScript**, **Visual Basic .NET**, **R**, **Rust**, and **PHP**, which are highlighted but not formatted and are never chosen by paste; **F6** on one of them opens that language's issue on GitHub. Press **F6** to format DAX, SQL, or KQL on the selected container without entering edit. Press **F2** to edit the body; the same list is in the title bar while editing. In F2, **F6** formats in place; **Ctrl+Enter** commits that edit (including the format) and returns to display. **Escape** restores the previous text, language, and dimensions. Text reflows while its edit-mode resize grip changes the width, and the height grows automatically when necessary. Double-click still centers and fits the container. Syntax highlighting applies in both edit and display modes. A language-aware title identifies a defined DAX, SQL, or KQL object when possible. SQL Server mode targets SQL Server 2025 T-SQL, preserves `GO` batch separators, and leaves invalid scripts unchanged. KQL mode reads Kusto through Microsoft's own parser and likewise leaves an invalid query unchanged. In display mode, resizing preserves the aspect ratio and scales the complete text visual without reflowing it.

Image files, and `.txt`, `.dax`, `.sql`, and `.kql` files, can be dropped directly from File Explorer. Their initial center is the board position at which they were dropped. DAX, SQL, and KQL files open in the matching language mode. Other dropped text files use Snippet format order.

Expand Down Expand Up @@ -257,9 +257,10 @@ is installed. The source is `vscode/sqlbi-whiteboard`.
- `SQLBI.Whiteboard.SqlServer` contains the framework-neutral SQL Server 2025 adapter over Microsoft's ScriptDOM parser and script generator.
- `SQLBI.Whiteboard.Kql` contains the framework-neutral Kusto Query Language adapter over Microsoft's own Kusto parser, classifier, and formatter.
- `vscode/sqlbi-whiteboard` is a VS Code custom editor that shows `preview.png` from a `.wboard` ZIP. It is not part of the desktop installer.
- `SQLBI.Whiteboard` is the WPF shell. `TouchInkCanvas` supplies system-managed wet ink for the finger, while `BoardSurface` renders completed ink, images, text, and selection on a white canvas in camera space, plus the pen's own wet stroke. A transient AvalonEdit surface is overlaid only while a text container is being edited; language services translate parser classifications into WPF text styles.
- `SQLBI.Whiteboard` is the WPF shell. `TouchInkCanvas` supplies system-managed wet ink for the finger, while `BoardSurface` renders completed ink, images, text, and selection on a white canvas in camera space, plus the pen's own wet stroke. A transient AvalonEdit surface is overlaid only while a text container is being edited; language services translate parser classifications into WPF text styles. `Highlighting/` holds the syntax definitions for the languages read lexically rather than parsed, and the adapter that flattens them into the same styled spans.
- `SQLBI.Whiteboard/LiveView` owns Windows Graphics Capture and the Direct3D-to-WPF bridge. Capture retains one GPU frame per active LiveView; CPU bitmap conversion occurs only when copying or saving a snapshot.
- `SQLBI.Whiteboard.Core.SmokeTests` is a package-free executable test harness for camera anchoring, commands, hit testing, and archive round trips.
- `SQLBI.Whiteboard.SmokeTests` is the same kind of harness for what needs WPF: syntax highlighting, the language registry, and the runs an editable export carries. It is never published.

The current document query is deliberately linear. A spatial index can be introduced behind `BoardDocument.Query` when profiling demonstrates a need, without changing input, tools, persistence, or rendering call sites.

Expand Down
17 changes: 17 additions & 0 deletions Whiteboard.sln
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLBI.Whiteboard.Export", "src\SQLBI.Whiteboard.Export\SQLBI.Whiteboard.Export.csproj", "{EE24F5C6-7C34-4613-8C82-DF34418E2B03}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0AB3BF05-4346-4AA6-1389-037BE0695223}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLBI.Whiteboard.SmokeTests", "tests\SQLBI.Whiteboard.SmokeTests\SQLBI.Whiteboard.SmokeTests.csproj", "{39C47EAF-F18D-411F-AA1C-9F83D294725A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Expand Down Expand Up @@ -141,11 +145,24 @@ Global
{EE24F5C6-7C34-4613-8C82-DF34418E2B03}.Release|Any CPU.Build.0 = Release|Any CPU
{EE24F5C6-7C34-4613-8C82-DF34418E2B03}.Release|x86.ActiveCfg = Release|Any CPU
{EE24F5C6-7C34-4613-8C82-DF34418E2B03}.Release|x86.Build.0 = Release|Any CPU
{39C47EAF-F18D-411F-AA1C-9F83D294725A}.Debug|x64.ActiveCfg = Debug|Any CPU
{39C47EAF-F18D-411F-AA1C-9F83D294725A}.Debug|x64.Build.0 = Debug|Any CPU
{39C47EAF-F18D-411F-AA1C-9F83D294725A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{39C47EAF-F18D-411F-AA1C-9F83D294725A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{39C47EAF-F18D-411F-AA1C-9F83D294725A}.Debug|x86.ActiveCfg = Debug|Any CPU
{39C47EAF-F18D-411F-AA1C-9F83D294725A}.Debug|x86.Build.0 = Debug|Any CPU
{39C47EAF-F18D-411F-AA1C-9F83D294725A}.Release|x64.ActiveCfg = Release|Any CPU
{39C47EAF-F18D-411F-AA1C-9F83D294725A}.Release|x64.Build.0 = Release|Any CPU
{39C47EAF-F18D-411F-AA1C-9F83D294725A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{39C47EAF-F18D-411F-AA1C-9F83D294725A}.Release|Any CPU.Build.0 = Release|Any CPU
{39C47EAF-F18D-411F-AA1C-9F83D294725A}.Release|x86.ActiveCfg = Release|Any CPU
{39C47EAF-F18D-411F-AA1C-9F83D294725A}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{EE24F5C6-7C34-4613-8C82-DF34418E2B03} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{39C47EAF-F18D-411F-AA1C-9F83D294725A} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
EndGlobalSection
EndGlobal
Loading