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
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.1.4</VersionPrefix>
<VersionPrefix>1.1.5</VersionPrefix>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ How the project is developed and shipped is documented separately:
- A normal cursor for physical mouse input, and a pen-hover indicator that shows what a tap would do: the laser with its halo and speed trail, a dashed square around what the eraser would clear, and a high-contrast dot for everything else. All of them disappear on contact
- Touch panning and two-finger pinch zoom
- Optional finger drawing (default when no pen is detected): one finger uses the current tool, two fingers still pan and pinch-zoom, and Eraser and Pan appear on the toolbar
- A notice at startup when Windows reports neither a pen tablet nor a touchscreen: the application still opens, but there is nothing to draw with, and [discussion 78](https://github.com/sql-bi/SQLBI-Whiteboard/discussions/78) collects votes for mouse-only drawing. Dismissable from the notice itself or from Preferences, since the tablet list Windows reports can miss a pen that has never been in range
- Basic palm rejection: touch navigation is suspended when the pen makes contact
- Mouse-wheel zoom and middle-button or temporary Space-key panning
- Whole-stroke erasing
Expand Down Expand Up @@ -202,7 +203,7 @@ Use **Copy settings** after finding a useful combination so the exact values can
| Delete | Delete the selected container and its linked strokes |
| Alt+L | Laser pointer |
| File / Edit / View / Help | Tab strip. Click a tab for a one-row command strip over the canvas. Click the canvas to hide it |
| Help > Preferences | Searchable settings: startup monitor, full screen, finger drawing, pen button, snippet format order, laser trail, toolbar, update checks |
| Help > Preferences | Searchable settings: startup monitor, full screen, no-pen warning, finger drawing, pen button, snippet format order, laser trail, toolbar, update checks |
| View > Bring to front / Send to back | Reorder the selected image, text, or LiveView (and its linked strokes) |
| Help > About | Version, channel, license, the product site, and a download link when a newer release is known |
| View > LiveView | Capture, freeze, disconnect, or reconnect a window or display |
Expand Down
2 changes: 1 addition & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The delivery chain works end to end: a merge to `main` builds, signs, and publis
pre-release to GitHub Releases, and one approval promotes that same build to a release.
<https://whiteboard.sqlbi.com> reads its download links from the release manifest
deployed beside it and needs no edit per release. The current product version is `VersionPrefix` in `Directory.Build.props`
(1.1.4). Identity version for the Store package is `VersionPrefix.0` (`1.1.4.0`).
(1.1.5). Identity version for the Store package is `VersionPrefix.0` (`1.1.5.0`).

Declaring that number is decision 20 in [docs/decisions.md](docs/decisions.md). What 1.0
was waiting on shipped during 0.9.x: Preferences, `.wimport`, Explorer and VS Code
Expand Down
2 changes: 1 addition & 1 deletion site/faq.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ <h2>Windows 11 or Windows 10?</h2>
<p>Built for Windows 11. It runs on Windows 10 version 2004 or later, 64-bit. That is the same floor as Windows Graphics Capture, which LiveView uses.</p>

<h2>Is a pen required?</h2>
<p>For ink, yes, unless Finger drawing is on. A mouse and touch pan, zoom, and move containers. A keyboard runs the rest. The rear eraser and palm rejection still need a pen. New installs default Finger drawing to <span class="ui">When no pen is detected</span>, which looks at the digitizer list Windows reports, not whether a pen is in the room. <span class="ui">On</span> makes one finger use the current tool; two fingers still pan and pinch-zoom, and Eraser and Pan appear on the toolbar. The <a href="shortcuts.html">shortcut list</a> is grouped by pen, mouse, touch, and keys.</p>
<p>For ink, yes, unless Finger drawing is on. On a computer where Windows reports neither a pen tablet nor a touchscreen, a notice at startup says so and points to <a href="https://github.com/sql-bi/SQLBI-Whiteboard/discussions/78">discussion 78</a>, which collects votes for mouse-only drawing; the application still opens. A mouse and touch pan, zoom, and move containers. A keyboard runs the rest. The rear eraser and palm rejection still need a pen. New installs default Finger drawing to <span class="ui">When no pen is detected</span>, which looks at the digitizer list Windows reports, not whether a pen is in the room. <span class="ui">On</span> makes one finger use the current tool; two fingers still pan and pinch-zoom, and Eraser and Pan appear on the toolbar. The <a href="shortcuts.html">shortcut list</a> is grouped by pen, mouse, touch, and keys.</p>

<h2>Mac, iPad, or a browser?</h2>
<p>No. It is a Windows application. Boards are files you can keep next to the material they document; they do not open in a browser.</p>
Expand Down
2 changes: 1 addition & 1 deletion site/guide.html
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,7 @@ <h3>The command strip</h3>
</figure>

<h3>Preferences</h3>
<p><span class="ui">Help → Preferences</span> is a searchable list: which monitor to open on, start full screen, finger drawing, what the pen's barrel button does, snippet format order, laser trail timing and weight, toolbar placement and layout, and the daily new-version check. Settings about how something looks — the trail weight, the barrel button, where the toolbar sits and how it is laid out — draw their options rather than naming them, so the choice is made by looking. <span class="ui">Help → About</span> shows the version. New settings are more rows in Preferences, not a new dialog.</p>
<p><span class="ui">Help → Preferences</span> is a searchable list: which monitor to open on, start full screen, whether to warn when there is nothing to draw with, finger drawing, what the pen's barrel button does, snippet format order, laser trail timing and weight, toolbar placement and layout, and the daily new-version check. Settings about how something looks — the trail weight, the barrel button, where the toolbar sits and how it is laid out — draw their options rather than naming them, so the choice is made by looking. <span class="ui">Help → About</span> shows the version. New settings are more rows in Preferences, not a new dialog.</p>

<figure class="fig">
<div class="figbox">
Expand Down
11 changes: 10 additions & 1 deletion src/SQLBI.Whiteboard.Core/Settings/AppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@ public sealed class AppSettings

public PenButtonSettings PenButtons { get; set; } = new();

/// <summary>
/// Whether to say at startup that Windows reports nothing to draw with. The
/// tablet list this reads is a list of digitizers rather than an answer
/// about what is plugged in, so a pen that has never been brought into
/// range can be missing from it - which is the other reason this can be
/// turned off.
/// </summary>
public bool WarnWhenNoDigitizer { get; set; } = true;

public bool CheckForUpdates { get; set; } = true;

public DateTimeOffset? LastUpdateCheckUtc { get; set; }
Expand All @@ -111,7 +120,7 @@ public sealed class AppSettings

public static class AppSettingsSerializer
{
public const int CurrentVersion = 11;
public const int CurrentVersion = 12;

private static readonly JsonSerializerOptions JsonOptions = new()
{
Expand Down
21 changes: 21 additions & 0 deletions src/SQLBI.Whiteboard/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,34 @@ private void MainWindow_SourceInitialized(object? sender, EventArgs e)
private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Loaded -= MainWindow_Loaded;
WarnWhenNothingToDrawWith();
_ = CheckForUpdatesAsync();
if (_initialBoardPath is not null)
{
await OpenPathAsync(_initialBoardPath, confirmDiscard: false);
}
}

// A whiteboard with nothing to draw on it is worth saying out loud, rather
// than leaving someone to work out why the pen tools do nothing.
private void WarnWhenNothingToDrawWith()
{
if (!_settings.WarnWhenNoDigitizer || NoDigitizerWindow.HasDrawingDevice())
{
return;
}

var notice = new NoDigitizerWindow { Owner = this };
notice.ShowDialog();
if (!notice.DoNotShowAgain)
{
return;
}

_settings.WarnWhenNoDigitizer = false;
AppSettingsStore.Save(_settings);
}

private void BoardViewport_SizeChanged(object sender, SizeChangedEventArgs e)
{
_camera.Resize(e.NewSize.Width, e.NewSize.Height);
Expand Down
60 changes: 60 additions & 0 deletions src/SQLBI.Whiteboard/NoDigitizerWindow.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<Window x:Class="SQLBI.Whiteboard.NoDigitizerWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="No pen or touchscreen found"
Width="480"
SizeToContent="Height"
ResizeMode="NoResize"
WindowStartupLocation="CenterOwner"
ShowInTaskbar="False"
Background="{DynamicResource ToolbarBackgroundBrush}"
PreviewKeyDown="Window_PreviewKeyDown">
<StackPanel Margin="28,24">
<TextBlock FontFamily="Segoe UI"
FontSize="16"
FontWeight="SemiBold"
Foreground="#FF1F2937"
TextWrapping="Wrap"
Text="No pen or touchscreen found" />
<TextBlock Margin="0,12,0,0"
FontFamily="Segoe UI"
FontSize="13"
Foreground="#FF374151"
TextWrapping="Wrap"
Text="SQLBI Whiteboard is built for drawing with a pen or a finger. Windows reports no pen tablet and no touchscreen on this computer, so there is nothing here to draw with." />
<TextBlock Margin="0,10,0,0"
FontFamily="Segoe UI"
FontSize="13"
Foreground="#FF374151"
TextWrapping="Wrap"
Text="A mouse can pan, zoom, and move containers, and the keyboard runs the rest, but there is no mouse drawing yet. The application will open, and everything that does not need ink will work." />
<TextBlock Margin="0,10,0,0"
FontFamily="Segoe UI"
FontSize="13"
Foreground="#FF374151"
TextWrapping="Wrap">
<Run Text="If you would like a mouse-only version, say so here:" />
<LineBreak />
<Hyperlink NavigateUri="https://github.com/sql-bi/SQLBI-Whiteboard/discussions/78"
RequestNavigate="DiscussionLink_RequestNavigate">
<Run Text="Vote for mouse-only support" />
</Hyperlink>
</TextBlock>
<CheckBox x:Name="DoNotShowAgainBox"
Margin="0,20,0,0"
FontFamily="Segoe UI"
FontSize="13"
Foreground="#FF374151"
Content="Do not show this again" />
<StackPanel Margin="0,16,0,0"
Orientation="Horizontal"
HorizontalAlignment="Right">
<Button MinWidth="96"
MinHeight="30"
IsDefault="True"
IsCancel="True"
Content="Continue"
Click="ContinueButton_Click" />
</StackPanel>
</StackPanel>
</Window>
63 changes: 63 additions & 0 deletions src/SQLBI.Whiteboard/NoDigitizerWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System.Diagnostics;
using System.Windows;
using System.Windows.Input;
using System.Windows.Navigation;

namespace SQLBI.Whiteboard;

/// <summary>
/// Shown once at startup when Windows reports neither a pen tablet nor a
/// touchscreen. The application still opens - everything that does not need ink
/// works with a mouse and the keyboard - so this says what is missing rather
/// than refusing to start.
/// </summary>
public partial class NoDigitizerWindow : Window
{
public NoDigitizerWindow() => InitializeComponent();

/// <summary>
/// Whether the notice was dismissed for good. Also the way out of a false
/// positive, so it is offered on the notice itself rather than only in
/// Preferences.
/// </summary>
public bool DoNotShowAgain => DoNotShowAgainBox.IsChecked == true;

/// <summary>
/// Whether Windows reports anything to draw with. The same tablet list the
/// Finger drawing setting reads, which is a list of digitizers rather than
/// an answer about what is plugged in right now: a pen that has never been
/// brought into range can be absent from it.
/// </summary>
public static bool HasDrawingDevice()
{
foreach (TabletDevice device in Tablet.TabletDevices)
{
if (device.Type is TabletDeviceType.Stylus or TabletDeviceType.Touch)
{
return true;
}
}

return false;
}

private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
Close();
e.Handled = true;
}
}

private void DiscussionLink_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri)
{
UseShellExecute = true,
});
e.Handled = true;
}

private void ContinueButton_Click(object sender, RoutedEventArgs e) => Close();
}
5 changes: 5 additions & 0 deletions src/SQLBI.Whiteboard/PreferencesWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,7 @@ private ToggleButton CreateSwitch(SettingDescriptor setting)
IsChecked = setting.Id switch
{
SettingsCatalog.Ids.StartFullScreen => _settings.StartFullScreen,
SettingsCatalog.Ids.WarnWhenNoDigitizer => _settings.WarnWhenNoDigitizer,
SettingsCatalog.Ids.CheckForUpdates => _settings.CheckForUpdates,
_ => false,
},
Expand Down Expand Up @@ -904,6 +905,10 @@ private void SetBoolean(SettingDescriptor setting, bool value)
{
_settings.StartFullScreen = value;
}
else if (setting.Id == SettingsCatalog.Ids.WarnWhenNoDigitizer)
{
_settings.WarnWhenNoDigitizer = value;
}
else if (setting.Id == SettingsCatalog.Ids.CheckForUpdates)
{
_settings.CheckForUpdates = value;
Expand Down
10 changes: 10 additions & 0 deletions src/SQLBI.Whiteboard/SettingsCatalog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public static class Ids
public const string LaserTrailWeight = "laser.trailWeight";
public const string ToolbarPlacement = "toolbar.placement";
public const string ToolbarLayout = "toolbar.layout";
public const string WarnWhenNoDigitizer = "startup.noDigitizerNotice";
public const string FingerMode = "input.fingerMode";
public const string PenButton = "input.penButton";
public const string SnippetFormatOrder = "input.snippetFormatOrder";
Expand Down Expand Up @@ -118,6 +119,15 @@ public static class Ids
Editor = SettingEditorKind.BooleanSwitch,
},
new()
{
Id = Ids.WarnWhenNoDigitizer,
Category = Startup,
Title = "Warn when there is nothing to draw with",
Description = "Say so at startup when Windows reports neither a pen tablet nor a touchscreen. The application opens either way; a mouse pans, zooms, and moves containers, but cannot draw. What Windows reports is a list of digitizers rather than what is plugged in, so a pen that has never been brought into range can be missing from it.",
Keywords = ["pen", "touch", "touchscreen", "digitizer", "tablet", "mouse", "warning", "notice", "startup"],
Editor = SettingEditorKind.BooleanSwitch,
},
new()
{
Id = Ids.FingerMode,
Category = Input,
Expand Down
8 changes: 8 additions & 0 deletions tests/SQLBI.Whiteboard.Core.SmokeTests/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,14 @@ defaultSettings.StartupMonitorName is null &&
Assert(
defaultSettings.PenButtons.Barrel == PenButtonAction.Laser,
"Missing settings should assign Laser to the pen barrel button.");
Assert(
defaultSettings.WarnWhenNoDigitizer,
"Missing settings should warn when Windows reports nothing to draw with.");
Assert(
!AppSettingsSerializer.Parse(
AppSettingsSerializer.Format(new AppSettings { WarnWhenNoDigitizer = false }))
.WarnWhenNoDigitizer,
"Dismissing the no-digitizer notice should survive a round trip.");
Assert(
AppSettingsSerializer.Parse("{ \"penButtons\": { \"barrel\": \"Sideways\" } }")
.PenButtons.Barrel == PenButtonAction.Laser,
Expand Down