Skip to content

Commit

Permalink
## Hourglass Changes
Browse files Browse the repository at this point in the history
### Installer

- Adds the **Hourglass** executable path to the Windows App Paths, so the **Hourglass** command-line is available out of the box.

### Command-line

- New command `pause`
- New command `resume`
- New option `--digital-clock-time` / `-c`
- New option `--multi-timers` / `-mt`
- New option `--activate-next` / `-an`

See usage for details.

### UI

- Uses a Windows Task Dialog instead of a message box.
- The **Command-line usage** dialog can be accessed from the **About** dialog and vice versa.

### Notification Area

- The double click shows/hides all the timer windows.
- All the timers are arranged by the time left. The order of the timers is new, expired, paused, running.
- The red circle is shown over the notification area icon if at least one timer is expired.
- The pause sign is shown over the notification area icon if at least one timer is paused.
- The digits from 0 to 9 are hotkeys for timers in the notification area icon context menu.
- The **Open timer context menu** menu command opens the timer window context menu. The shortcut is the holding the `Shift` during right click on the notification area icon.
- The **Pause all** menu command pauses all the running timers.
- The **Resume all** menu command resumes all the paused timers.
- The **Exit** menu command asks to close all the running timer windows if the **Prompt on exit** option is on.

### Timer Windows

#### Keyboard Shortcuts

- The `Esc` shortcut minimizes the timer window.
- The `F11` shortcut makes the timer window full screen and back.
- The `Ctrl+N` shortcut creates a new timer window.

#### Context Menu

- All the timer window commands are available in the timer window context menu.
- The shortcuts are displayed in the timer window context menu.
- The **Window title** submenu is available directly from the timer window context menu.
- The **Reset bounds** menu command sets the timer window default position and size.
- The **Restore**, **Minimize** and **Maximize** timer window commands are always present in the timer window context menu.
- The **Advanced options** / **Display time in the digital clock format** timer window context menu option toggles the displayed time digital clock time format. The command-line option is `--digital-clock-time` / `-c`
- The **Advanced options** / **Activate next window when minimized or closed** timer window context menu option enables the next timer window activation when the current timer window is minimized or closed. The command-line option is `--activate-next` / `-an`
- The **Pause all** timer window context menu command pauses all the running timers. Command-line command is `pause`
- The **Resume all** timer window context menu command resumes all the paused timers. Command-line command is `resume`

#### Other

- All the timer windows are arranged by the time left. The order of the timer windows is new, expired, paused, running.
- The minimum timer window size is limited by the Windows only.
- The timer tooltip is shown if the timer window size is too small.
- The progress bar changes direction to vertical when the height is more than the width and vice versa.
- When the timer window is minimized or closed the next visible non-minimized timer window is activated.
- The time left is now used for editing instead of the original launch time.
- The timer window pops up on the current virtual desktop.
- The mouse double-click on progress border toggles full screen.
- The sound file can be placed to the `%LOCALAPPDATA%\Hourglass` or `%LOCALAPPDATA%\Hourglass\Sounds` directories. It can be the symbolic link created by the `mklink` system command.

### Misc

- The **Hourglass** is built deterministically using the GitHub Actions.
  • Loading branch information
i2van committed Feb 27, 2024
1 parent 283115a commit 31cdd0b
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 23 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<Project>
<PropertyGroup>
<Version>1.15.28.0</Version>
<Version>1.15.29.0</Version>
</PropertyGroup>
</Project>
2 changes: 1 addition & 1 deletion Hourglass.Bundle/Bundle.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
<Bundle Name="Hourglass"
Version="1.15.28.0"
Version="1.15.29.0"
Manufacturer="2021 Chris Dziemborowicz, 2024 Ivan Ivon"
UpgradeCode="f1d002c9-cfc9-40fb-84af-96e7aec26e0b"
IconSourceFile="$(var.Hourglass.ProjectDir)Resources\AppIcon.ico">
Expand Down
2 changes: 1 addition & 1 deletion Hourglass.Setup/Product.wxs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension">
<Product Id="*" Name="Hourglass" Language="1033" Version="1.15.28.0" Manufacturer="Chris Dziemborowicz, Ivan Ivon" UpgradeCode="172d3713-8820-4374-8195-3e2374e7724f">
<Product Id="*" Name="Hourglass" Language="1033" Version="1.15.29.0" Manufacturer="Chris Dziemborowicz, Ivan Ivon" UpgradeCode="172d3713-8820-4374-8195-3e2374e7724f">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine"/>

<Icon Id="AppIcon.exe" SourceFile="$(var.Hourglass.ProjectDir)Resources\AppIcon.ico"/>
Expand Down
38 changes: 37 additions & 1 deletion Hourglass/Extensions/WindowExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
namespace Hourglass.Extensions;

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media;

Expand Down Expand Up @@ -78,7 +80,7 @@ public static bool SetImmersiveDarkMode(this TimerWindow window, bool useImmersi
}

// This hack appears to be the only way to get the non-client area of the window to redraw correctly.
if (window.IsVisible && !window.IsFullScreen)
if (window is { IsVisible: true, IsFullScreen: false })
{
if (window.WindowState == WindowState.Maximized)
{
Expand Down Expand Up @@ -587,6 +589,40 @@ private static Rect Offset(this Rect rect)
return rect.CenterOnScreen();
}

/// <summary>
/// Open window context menu.
/// </summary>
/// <param name="window">The window.</param>
public static void OpenContextMenu(this Window window)
{
try
{
if (window.ContextMenu is null)
{
return;
}

ContextMenuEventArgs contextMenuEventArgs = (ContextMenuEventArgs)Activator.CreateInstance(
typeof(ContextMenuEventArgs),
#pragma warning disable S3011
BindingFlags.Instance | BindingFlags.NonPublic,
#pragma warning restore S3011
null,
[window, true],
null);

contextMenuEventArgs.RoutedEvent = FrameworkElement.ContextMenuOpeningEvent;
window.RaiseEvent(contextMenuEventArgs);

window.ContextMenu.IsOpen = !contextMenuEventArgs.Handled;
}
catch
{
// Fallback.
System.Windows.Forms.SendKeys.SendWait("+{F10}");
}
}

public static void MoveToCurrentVirtualDesktop(this Window window) =>
VirtualDesktopManager.Instance.MoveToCurrentVirtualDesktop(window);

Expand Down
4 changes: 1 addition & 3 deletions Hourglass/Lib/TaskDialog/TaskDialog/TaskDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -533,9 +533,7 @@ private static bool IsTaskDialogButtonCommitting(TaskDialogButton button)
// "button" will be null or its "IsCreated" property returns false.
// In that case the "Help" button would close the dialog, so we
// return true.
return !(button is TaskDialogStandardButton standardButton &&
standardButton.IsCreated &&
standardButton.Result == TaskDialogResult.Help);
return !(button is TaskDialogStandardButton { IsCreated: true, Result: TaskDialogResult.Help });
}

private static TaskDialogStandardButton CreatePlaceholderButton(
Expand Down
6 changes: 3 additions & 3 deletions Hourglass/Parsing/NormalTimeToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ public sealed class NormalTimeToken : TimeToken
/// Gets a value indicating whether the token is valid.
/// </summary>
public override bool IsValid =>
Hour >= 1 && Hour <= 12
&& Minute >= 0 && Minute <= 59
&& Second >= 0 && Minute <= 59;
Hour is >= 1 and <= 12
&& Minute is >= 0 and <= 59
&& Second >= 0 && Minute <= 59;

/// <summary>
/// Returns the next date and time after <paramref name="minDate"/> that is represented by this token.
Expand Down
2 changes: 1 addition & 1 deletion Hourglass/Properties/App.manifest
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<assemblyIdentity version="1.15.28.0" name="Hourglass"/>
<assemblyIdentity version="1.15.29.0" name="Hourglass"/>
<description>The simple countdown timer for Windows.</description>
<dependency>
<dependentAssembly>
Expand Down
36 changes: 25 additions & 11 deletions Hourglass/Windows/TimerWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ public void BringToFrontAndActivate(bool activate = true, bool contextMenu = fal
if (contextMenu)
{
Dispatcher.BeginInvoke(UnfocusAll);
Dispatcher.BeginInvoke(() => System.Windows.Forms.SendKeys.SendWait("+{F10}"));
Dispatcher.BeginInvoke(this.OpenContextMenu);
}

static void Sleep()
Expand Down Expand Up @@ -671,23 +671,37 @@ private void SwitchToInputMode(TextBox? textBoxToFocus = null)

TitleTextBox.Text = Timer.Options.Title ?? string.Empty;

if (Timer.Options.ShowTimeElapsed)
{
TimerTextBox.Text = Timer.TimeLeftAsString ?? string.Empty;
}

if (string.IsNullOrWhiteSpace(TimerTextBox.Text) ||
Timer.State is TimerState.Expired or TimerState.Stopped)
{
TimerTextBox.Text = LastTimerStart.ToString();
}
AdjustTimerTextBoxText();

textBoxToFocus ??= TimerTextBox;
textBoxToFocus.SelectAll();
textBoxToFocus.Focus();

EndAnimationsAndSounds();
UpdateBoundControls();

void AdjustTimerTextBoxText()
{
if (!Timer.SupportsPause)
{
TimerTextBox.Text = GetTimerStartTime();
return;
}

if (Timer.Options.ShowTimeElapsed)
{
TimerTextBox.Text = Timer.TimeLeftAsString ?? string.Empty;
}

if (string.IsNullOrWhiteSpace(TimerTextBox.Text) ||
Timer.State is TimerState.Expired or TimerState.Stopped)
{
TimerTextBox.Text = GetTimerStartTime();
}

string GetTimerStartTime() =>
Timer.TimerStart?.ToString() ?? LastTimerStart.ToString();
}
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion latest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<UpdateInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<LatestVersion>1.15.28.0</LatestVersion>
<LatestVersion>1.15.29.0</LatestVersion>
<UpdateUrl>https://github.com/i2van/hourglass/releases/latest</UpdateUrl>
</UpdateInfo>

0 comments on commit 31cdd0b

Please sign in to comment.