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
1 change: 1 addition & 0 deletions .azure/pipelines/build-whiteboard.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ stages:
"$(Build.BinariesDirectory)\SQLBI.Whiteboard.Core.dll"
"$(Build.BinariesDirectory)\SQLBI.Whiteboard.Dax.dll"
"$(Build.BinariesDirectory)\SQLBI.Whiteboard.Export.dll"
"$(Build.BinariesDirectory)\SQLBI.Whiteboard.Kql.dll"
"$(Build.BinariesDirectory)\SQLBI.Whiteboard.SqlServer.dll"
"$(Build.BinariesDirectory)\SQLBI.Whiteboard.ThumbnailHandler.dll"
failOnStderr: true
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ 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.3.1 - 5 September 2026

### KQL joins DAX and SQL in text containers
A text container can now be Kusto Query Language. Paste a query or drop a `.kql` file,
choose **KQL** from the title-bar chip, and it is highlighted like the rest: operators,
functions, columns, string literals, and the comments between them. **F6** formats it,
and a query that does not parse is left exactly as it was rather than half rewritten.
The spacing you chose around a join hint, as in `kind=inner`, survives formatting, because
that is how the queries people bring to a session are usually written. Highlighting and
formatting both read Kusto through Microsoft's own parser, and both run locally.

## 1.3.0 - 3 September 2026

### Export a board to PowerPoint
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.0</VersionPrefix>
<VersionPrefix>1.3.1</VersionPrefix>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ Use **Copy settings** after finding a useful combination so the exact values can
| 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 or SQL on the selected text container. In F2, formats in place |
| F6 | Format DAX, SQL, or KQL on the selected text container. In F2, formats in place |
| 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 |
| Ctrl+S / Ctrl+O | Save / open a board |
Expand All @@ -221,9 +221,9 @@ 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, so leaving it first keeps every paste as plain text. Recognized extensions (`.dax`, `.sql`, `.txt`) keep their language; other dropped text files use the same order. Choose **Plain text**, **DAX**, or **SQL Server** from the title-bar chip afterward. Press **F6** to format DAX or SQL 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 or SQL object when possible. SQL Server mode targets SQL Server 2025 T-SQL, preserves `GO` batch separators, and leaves invalid scripts 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, so leaving it first keeps every paste as plain text. 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.

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

### `.wimport` recipes

Expand Down Expand Up @@ -254,6 +254,7 @@ is installed. The source is `vscode/sqlbi-whiteboard`.
- `SQLBI.Whiteboard.Core` contains world geometry, camera math, retained board objects, commands, hit testing, and archive persistence. It has no UI-framework dependency.
- `SQLBI.Whiteboard.Dax` contains the framework-neutral DAX lexer, parser, classifier, and deterministic formatter adapted from Prompt Assistant.
- `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/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.
Expand Down
14 changes: 14 additions & 0 deletions Whiteboard.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLBI.Whiteboard.Dax", "src
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLBI.Whiteboard.SqlServer", "src\SQLBI.Whiteboard.SqlServer\SQLBI.Whiteboard.SqlServer.csproj", "{B2B15228-5085-4652-B7C7-F82F3781A486}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLBI.Whiteboard.Kql", "src\SQLBI.Whiteboard.Kql\SQLBI.Whiteboard.Kql.csproj", "{2BDED826-A102-4601-910E-15E3243ADCA2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLBI.Whiteboard.Core.SmokeTests", "tests\SQLBI.Whiteboard.Core.SmokeTests\SQLBI.Whiteboard.Core.SmokeTests.csproj", "{53EF7855-88C7-4D6A-A194-4AF36CF10615}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLBI.Whiteboard", "src\SQLBI.Whiteboard\SQLBI.Whiteboard.csproj", "{C9300257-0FA9-47E5-B719-F8C957FE5427}"
Expand Down Expand Up @@ -67,6 +69,18 @@ Global
{B2B15228-5085-4652-B7C7-F82F3781A486}.Release|Any CPU.Build.0 = Release|Any CPU
{B2B15228-5085-4652-B7C7-F82F3781A486}.Release|x86.ActiveCfg = Release|Any CPU
{B2B15228-5085-4652-B7C7-F82F3781A486}.Release|x86.Build.0 = Release|Any CPU
{2BDED826-A102-4601-910E-15E3243ADCA2}.Debug|x64.ActiveCfg = Debug|Any CPU
{2BDED826-A102-4601-910E-15E3243ADCA2}.Debug|x64.Build.0 = Debug|Any CPU
{2BDED826-A102-4601-910E-15E3243ADCA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2BDED826-A102-4601-910E-15E3243ADCA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2BDED826-A102-4601-910E-15E3243ADCA2}.Debug|x86.ActiveCfg = Debug|Any CPU
{2BDED826-A102-4601-910E-15E3243ADCA2}.Debug|x86.Build.0 = Debug|Any CPU
{2BDED826-A102-4601-910E-15E3243ADCA2}.Release|x64.ActiveCfg = Release|Any CPU
{2BDED826-A102-4601-910E-15E3243ADCA2}.Release|x64.Build.0 = Release|Any CPU
{2BDED826-A102-4601-910E-15E3243ADCA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2BDED826-A102-4601-910E-15E3243ADCA2}.Release|Any CPU.Build.0 = Release|Any CPU
{2BDED826-A102-4601-910E-15E3243ADCA2}.Release|x86.ActiveCfg = Release|Any CPU
{2BDED826-A102-4601-910E-15E3243ADCA2}.Release|x86.Build.0 = Release|Any CPU
{53EF7855-88C7-4D6A-A194-4AF36CF10615}.Debug|x64.ActiveCfg = Debug|Any CPU
{53EF7855-88C7-4D6A-A194-4AF36CF10615}.Debug|x64.Build.0 = Debug|Any CPU
{53EF7855-88C7-4D6A-A194-4AF36CF10615}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
Expand Down
5 changes: 3 additions & 2 deletions docs/wimport.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ container. The whole body, fence included, becomes plain text.
| --- | --- | --- |
| DAX | `dax` | `.dax` |
| SQL Server | `sql`, `tsql` | `.sql` |
| KQL | `kql`, `kusto` | `.kql` |

Further languages (Python, C#, TypeScript, …) will be extra rows in this table. Do not invent
fence tags Whiteboard does not list here: they import as plain text.
Expand Down Expand Up @@ -134,8 +135,8 @@ A complete sample is `docs/samples/contoso-workshop.wimport`.
- File name ends in `.wimport`.
- Every container is a `##` heading with exactly one payload.
- Images and linked code exist next to the file, using relative paths.
- Image files are png/jpeg/bmp/gif/svg. Code files you link are `.dax` or `.sql`, or the code is
embedded in a `dax` / `sql` / `tsql` fence.
- Image files are png/jpeg/bmp/gif/svg. Code files you link are `.dax`, `.sql`, or `.kql`, or the
code is embedded in a `dax` / `sql` / `tsql` / `kql` fence.
- Row breaks are a thematic break on its own line, not a fake heading.
- You did not use `http://`, YAML, or explicit positions.
- Opening the file in a Markdown preview still reads as a normal document.
Expand Down
4 changes: 2 additions & 2 deletions site/compare.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ <h1>What this is and is not</h1>

<article>
<h2>What this is</h2>
<p>A native Windows application for a live explanation: pressure-aware ink, an unbounded canvas, SQL and DAX containers with local formatting, LiveView capture of a window or a display, and portable <code>.wboard</code> files. No account. The <a href="guide.html">guide</a> is how a session runs.</p>
<p>A native Windows application for a live explanation: pressure-aware ink, an unbounded canvas, DAX, SQL, and KQL containers with local formatting, LiveView capture of a window or a display, and portable <code>.wboard</code> files. No account. The <a href="guide.html">guide</a> is how a session runs.</p>

<h2>What this is not</h2>
<ul>
Expand All @@ -66,7 +66,7 @@ <h2>Beside Microsoft Whiteboard</h2>
<tr><td>Platforms</td><td>Windows 10 version 2004 or later, 64-bit</td><td>Windows, web, and Microsoft 365 clients</td></tr>
<tr><td>Collaboration</td><td>One person at the board</td><td>Real-time, multi-user</td></tr>
<tr><td>Ink and objects</td><td>Strokes can travel with a container</td><td>Ink and objects on a shared canvas</td></tr>
<tr><td>Code</td><td>SQL and DAX containers, F6 formats locally</td><td>Not a language surface</td></tr>
<tr><td>Code</td><td>DAX, SQL, and KQL containers, F6 formats locally</td><td>Not a language surface</td></tr>
<tr><td>Live application</td><td>LiveView of a window or a display</td><td>Not a capture surface</td></tr>
</tbody>
</table>
Expand Down
4 changes: 2 additions & 2 deletions site/faq.html
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ <h2>Can Released and Dev both be installed?</h2>
<h2>What is LiveView, and why Reconnect after open?</h2>
<p>LiveView captures a window or a display onto the board so you can draw over it. Windows cannot save the capture permission. After you reload a board the last frame appears immediately; <span class="ui">Reconnect</span> restores the live feed. The <a href="guide.html">guide</a> has the session story.</p>

<h2>Can it format DAX and SQL?</h2>
<p>Yes. Paste or drop a <code>.dax</code> or <code>.sql</code> file, choose the language, press <kbd>F6</kbd>. <span class="ui">Help → Preferences</span> has Snippet format order for clipboard paste and unrecognized dropped files. Formatting is local. SQL Server mode targets SQL Server 2025 T-SQL and leaves an invalid script unchanged.</p>
<h2>Can it format DAX, SQL, and KQL?</h2>
<p>Yes. Paste or drop a <code>.dax</code>, <code>.sql</code>, or <code>.kql</code> file, choose the language, press <kbd>F6</kbd>. <span class="ui">Help → Preferences</span> has Snippet format order for clipboard paste and unrecognized dropped files. Formatting is local. SQL Server mode targets SQL Server 2025 T-SQL and leaves an invalid script unchanged; KQL reads Kusto through Microsoft's own parser and does the same.</p>

<h2>How do I bring a workshop in?</h2>
<p>A <code>.wimport</code> file is Markdown that builds image and text containers. Drop it on an open board, or use <span class="ui">Import</span>. The <a href="wimport.html">import format</a> is the contract. Save always writes a <code>.wboard</code>.</p>
Expand Down
10 changes: 5 additions & 5 deletions site/guide.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Guide · SQLBI Whiteboard</title>
<meta name="description" content="How to use SQLBI Whiteboard in a live session: ink, containers, LiveView, SQL and DAX, and board files.">
<meta name="description" content="How to use SQLBI Whiteboard in a live session: ink, containers, LiveView, DAX, SQL and KQL, and board files.">
<link rel="icon" href="favicon.ico" sizes="any">
<link rel="icon" href="favicon-32.png" type="image/png" sizes="32x32">
<link rel="apple-touch-icon" href="apple-touch-icon.png">
Expand Down Expand Up @@ -252,7 +252,7 @@ <h3>Keep ink on the slide you are discussing</h3>

<section class="story">
<h3>Explain code</h3>
<p>Paste SQL or DAX, or drop a <code>.sql</code> or <code>.dax</code> file. Use the title-bar chip to set the language, press <kbd>F6</kbd> to format it locally, then draw on the container. Formatting no longer needs edit mode: <kbd>F6</kbd> works on the container as soon as it is selected.</p>
<p>Paste DAX, SQL, or KQL, or drop a <code>.dax</code>, <code>.sql</code>, or <code>.kql</code> file. Use the title-bar chip to set the language, press <kbd>F6</kbd> to format it locally, then draw on the container. Formatting no longer needs edit mode: <kbd>F6</kbd> works on the container as soon as it is selected.</p>
<p><kbd>F2</kbd> moves the container into edit mode. <kbd>Ctrl</kbd><span class="plus">+</span><kbd>Enter</kbd> goes back to display mode and keeps the changes. <kbd>Escape</kbd> also goes back to display mode, but cancels the changes and restores the text, language, and size the container had before.</p>
<p>The two modes resize differently. In edit mode the text reflows as you change the width, so a long line wraps onto more lines at the same size. In display mode a resize scales the whole visual, like a picture of the code, so the room still sees the layout you just formatted.</p>

Expand Down Expand Up @@ -693,11 +693,11 @@ <h3>Containers</h3>
<p><span class="ui">View → Bring to front</span> and <span class="ui">View → Send to back</span> reorder the selected container and its linked strokes. Strokes cannot be reordered on their own.</p>
<p><span class="ui">View → Frame</span> adds a frame the size of the screen: a slide drawn on the board. A frame is selected by its dashed edge or by its title tab, never by its inside, so everything in it stays reachable; drag it to move it, drag the handle to resize it, press <kbd>F2</kbd> to rename it, and <span class="ui">Delete</span> removes the frame alone. Moving a frame moves nothing inside it: it is a label over content. <span class="ui">Export</span> takes frames as they are, first and in the order they were added, and cuts the rest of the board automatically. Frames never appear in an export or in a preview.</p>

<h3>Text, SQL, and DAX</h3>
<h3>Text, DAX, SQL, and KQL</h3>
<p>Paste prefers an image when the clipboard has one, including a file SnagIt or another capture tool left on the clipboard. Paste plain text to create a selected text container.</p>
<p>SVG counts as an image, whether the source application published it as SVG or the markup was simply copied as text — the output of a DAX SVG measure pastes as a picture, not as a snippet. Copying an SVG container puts the markup and a bitmap on the clipboard together, so an editor receives the source and a slide receives the picture.</p>
<p><span class="ui">Help → Preferences</span> sets Snippet format order: paste tries those languages from top to bottom. Plain text always matches, so putting it first keeps paste as plain text. Use the title-bar chip to choose Plain text, SQL Server, or DAX afterward.</p>
<p><kbd>F6</kbd> formats SQL or DAX on the selected container, without entering edit mode. <kbd>F2</kbd> edits the container, and double-click still centers it and fits it to the canvas; inside an edit <kbd>F6</kbd> formats in place and <kbd>Ctrl</kbd><span class="plus">+</span><kbd>Enter</kbd> commits that format with the rest of the edit. SQL Server mode targets SQL Server 2025 T-SQL, keeps <code>GO</code> batch separators, and leaves an invalid script unchanged. <kbd>Escape</kbd> restores the previous text, language, and size.</p>
<p><span class="ui">Help → Preferences</span> sets Snippet format order: paste tries those languages from top to bottom. Plain text always matches, so putting it first keeps paste as plain text. Use the title-bar chip to choose Plain text, DAX, SQL Server, or KQL afterward.</p>
<p><kbd>F6</kbd> formats DAX, SQL, or KQL on the selected container, without entering edit mode. <kbd>F2</kbd> edits the container, and double-click still centers it and fits it to the canvas; inside an edit <kbd>F6</kbd> formats in place and <kbd>Ctrl</kbd><span class="plus">+</span><kbd>Enter</kbd> commits that format with the rest of the edit. SQL Server mode targets SQL Server 2025 T-SQL, keeps <code>GO</code> batch separators, and leaves an invalid script unchanged; KQL reads Kusto through Microsoft's own parser and likewise leaves an invalid query alone. <kbd>Escape</kbd> restores the previous text, language, and size.</p>

<h3 id="liveview">LiveView</h3>
<p><span class="ui">View → LiveView</span> captures a window or a display. The container behaves like an image: move, resize, frame, delete, undo.</p>
Expand Down
Loading