From fa7713c335e74d468f1c8181f22ec0b9971f49d7 Mon Sep 17 00:00:00 2001 From: neo85 Date: Sat, 13 Feb 2021 17:37:50 +0100 Subject: [PATCH 1/8] ui directory --- snaptimer.lpi | 27 ++++----- snaptimer.lpr | 2 +- snaptimer.lps | 96 +++++++++++++++++++++++++++++++ about.lfm => ui/about.lfm | 0 about.lrt => ui/about.lrt | 0 about.pas => ui/about.pas | 0 floating.lfm => ui/floating.lfm | 0 floating.pas => ui/floating.pas | 0 mainform1.lfm => ui/mainform1.lfm | 0 mainform1.lrt => ui/mainform1.lrt | 0 mainform1.pas => ui/mainform1.pas | 0 settings.lfm => ui/settings.lfm | 0 settings.pas => ui/settings.pas | 0 version.inc | 2 +- 14 files changed, 110 insertions(+), 17 deletions(-) create mode 100644 snaptimer.lps rename about.lfm => ui/about.lfm (100%) rename about.lrt => ui/about.lrt (100%) rename about.pas => ui/about.pas (100%) rename floating.lfm => ui/floating.lfm (100%) rename floating.pas => ui/floating.pas (100%) rename mainform1.lfm => ui/mainform1.lfm (100%) rename mainform1.lrt => ui/mainform1.lrt (100%) rename mainform1.pas => ui/mainform1.pas (100%) rename settings.lfm => ui/settings.lfm (100%) rename settings.pas => ui/settings.pas (100%) diff --git a/snaptimer.lpi b/snaptimer.lpi index ce79283..eee14c5 100644 --- a/snaptimer.lpi +++ b/snaptimer.lpi @@ -26,6 +26,7 @@ + @@ -63,9 +64,6 @@ - - - @@ -84,34 +82,32 @@ - + - + - - - + - + - - - - + - - + + + + + @@ -122,6 +118,7 @@ + diff --git a/snaptimer.lpr b/snaptimer.lpr index 3f45b9a..8f18071 100644 --- a/snaptimer.lpr +++ b/snaptimer.lpr @@ -3,7 +3,7 @@ {$mode objfpc}{$H+} uses - Forms, Interfaces, MainForm1, About, settings; + Forms, Interfaces, MainForm1; {$R *.res} diff --git a/snaptimer.lps b/snaptimer.lps new file mode 100644 index 0000000..10e0f18 --- /dev/null +++ b/snaptimer.lps @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/about.lfm b/ui/about.lfm similarity index 100% rename from about.lfm rename to ui/about.lfm diff --git a/about.lrt b/ui/about.lrt similarity index 100% rename from about.lrt rename to ui/about.lrt diff --git a/about.pas b/ui/about.pas similarity index 100% rename from about.pas rename to ui/about.pas diff --git a/floating.lfm b/ui/floating.lfm similarity index 100% rename from floating.lfm rename to ui/floating.lfm diff --git a/floating.pas b/ui/floating.pas similarity index 100% rename from floating.pas rename to ui/floating.pas diff --git a/mainform1.lfm b/ui/mainform1.lfm similarity index 100% rename from mainform1.lfm rename to ui/mainform1.lfm diff --git a/mainform1.lrt b/ui/mainform1.lrt similarity index 100% rename from mainform1.lrt rename to ui/mainform1.lrt diff --git a/mainform1.pas b/ui/mainform1.pas similarity index 100% rename from mainform1.pas rename to ui/mainform1.pas diff --git a/settings.lfm b/ui/settings.lfm similarity index 100% rename from settings.lfm rename to ui/settings.lfm diff --git a/settings.pas b/ui/settings.pas similarity index 100% rename from settings.pas rename to ui/settings.pas diff --git a/version.inc b/version.inc index 89274e3..e0e84b5 100644 --- a/version.inc +++ b/version.inc @@ -1 +1 @@ -'0.2' \ No newline at end of file +'0.3' \ No newline at end of file From 51d0c8cc7555d93471bf29f20e5e225f0ab949f2 Mon Sep 17 00:00:00 2001 From: neo85 Date: Sat, 13 Feb 2021 17:40:15 +0100 Subject: [PATCH 2/8] settings file renamed to options File name should match the class/form. --- snaptimer.lpi | 4 +++- snaptimer.lps | 30 ++++++++++++++++++++++-------- ui/mainform1.pas | 2 +- ui/{settings.lfm => options.lfm} | 0 ui/{settings.pas => options.pas} | 4 ++-- 5 files changed, 28 insertions(+), 12 deletions(-) rename ui/{settings.lfm => options.lfm} (100%) rename ui/{settings.pas => options.pas} (99%) diff --git a/snaptimer.lpi b/snaptimer.lpi index eee14c5..917dfa4 100644 --- a/snaptimer.lpi +++ b/snaptimer.lpi @@ -102,11 +102,13 @@ + - + + diff --git a/snaptimer.lps b/snaptimer.lps index 10e0f18..9009816 100644 --- a/snaptimer.lps +++ b/snaptimer.lps @@ -4,7 +4,7 @@ - + @@ -40,7 +40,6 @@ - @@ -61,15 +60,14 @@ - - - - + + + + - @@ -77,8 +75,20 @@ + + + + + + + + + + + + - + @@ -87,6 +97,10 @@ + + + + diff --git a/ui/mainform1.pas b/ui/mainform1.pas index 7fcd141..b46aa61 100644 --- a/ui/mainform1.pas +++ b/ui/mainform1.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, - Menus, StdCtrls, Spin, ExtCtrls, About, LCLType, IniFiles, Settings, MMSystem, + Menus, StdCtrls, Spin, ExtCtrls, About, LCLType, IniFiles, Options, MMSystem, Windows, StrUtils, DateUtils; type diff --git a/ui/settings.lfm b/ui/options.lfm similarity index 100% rename from ui/settings.lfm rename to ui/options.lfm diff --git a/ui/settings.pas b/ui/options.pas similarity index 99% rename from ui/settings.pas rename to ui/options.pas index d1ed05a..5d8ff1e 100644 --- a/ui/settings.pas +++ b/ui/options.pas @@ -1,4 +1,4 @@ -unit settings; +unit Options; {$mode objfpc}{$H+} @@ -225,6 +225,6 @@ procedure TOptionsForm.TestTrayMsg(Sender: TObject); end; initialization - {$I settings.lrs} + {$I options.lrs} end. From d1213d8d455beea1dea63768e68813a4eb2535a4 Mon Sep 17 00:00:00 2001 From: neo85 Date: Mon, 15 Feb 2021 20:28:17 +0100 Subject: [PATCH 3/8] Config class --- model/config.pas | 385 +++++++++++++++++++++++++++++++++ snaptimer.lpi | 20 +- snaptimer.lps | 291 ++++++++++++++++++++----- ui/mainform1.lfm | 125 ++++++----- ui/mainform1.pas | 538 +++++++++++++++-------------------------------- ui/options.lfm | 2 +- ui/options.pas | 37 ++-- 7 files changed, 896 insertions(+), 502 deletions(-) create mode 100644 model/config.pas diff --git a/model/config.pas b/model/config.pas new file mode 100644 index 0000000..3e5bae9 --- /dev/null +++ b/model/config.pas @@ -0,0 +1,385 @@ +unit Config; + +{$mode objfpc} + +interface + +uses + Classes, SysUtils, Graphics; + +type + TPosition = (Center, Remember, TopLeft, TopRight, BottomLeft, BottomRight); + + TFontConfig = class + Name: String; + Charset: Integer; + Color: Integer; + BgColor: Integer; + Size: Integer; + Style: TFontStyles; + end; + + TConfig = class + private + // Main + FMinutes: Integer; + FAlwaysOnTop: boolean; + FMinToTray: boolean; + FAutoStart: boolean; + FHideSeconds: boolean; + FClickTime: boolean; + FDblClickTime: boolean; + FAutoRestart: boolean; + FLoopAudio: boolean; + FTickingOn: boolean; + FAutoSave: boolean; + FSecondsMode: boolean; + FCompactMode: boolean; + // Placement + FWndHeight: integer; + FWndWidth: integer; + FWndLeft: integer; + FWndTop: integer; + FWndPosition: TPosition; + // Alarms + FDoneMessage: string; + FDoneMessageEnabled: boolean; + FDoneTrayMsg: string; + FDoneTrayMsgEnabled: boolean; + FDoneAudio: string; + FDoneAudioEnabled: boolean; + FDoneApp: string; + FDoneAppEnabled: boolean; + // Font + FFont: TFontConfig; + FDefaultFont: TFontConfig; + procedure SetDoneMessage(Msg: String); + procedure SetDoneTrayMessage(Msg: String); + public + constructor Create; + destructor Free; + function Load : Boolean; + function Save : Boolean; + function GetDefaultFont : TFontConfig; + + // Main + property Minutes: Integer read FMinutes write FMinutes; + property AlwaysOnTop: boolean read FAlwaysOnTop write FAlwaysOnTop; + property MinToTray: boolean read FMinToTray write FMinToTray; + property AutoStart: boolean read FAutoStart write FAutoStart; + property HideSeconds: boolean read FHideSeconds write FHideSeconds; + property ClickTime: boolean read FClickTime write FClickTime; + property DblClickTime: boolean read FDblClickTime write FDblClickTime; + property AutoRestart: boolean read FAutoRestart write FAutoRestart; + property LoopAudio: boolean read FLoopAudio write FLoopAudio; + property TickingOn: boolean read FTickingOn write FTickingOn; + property AutoSave: boolean read FAutoSave write FAutoSave; + property SecondsMode: boolean read FSecondsMode write FSecondsMode; // Undocumented mode to treat minutes as seconds + property CompactMode: boolean read FCompactMode write FCompactMode; // not implemented + // Placement + property WndHeight: integer read FWndHeight write FWndHeight; + property WndWidth: integer read FWndWidth write FWndWidth; + property WndLeft: integer read FWndLeft write FWndLeft; + property WndTop: integer read FWndTop write FWndTop; + property WndPosition: TPosition read FWndPosition write FWndPosition; + // Alarm + property DoneMessage: string read FDoneMessage write SetDoneMessage; + property DoneMessageEnabled: boolean read FDoneMessageEnabled write FDoneMessageEnabled; + property DoneTrayMsg: string read FDoneTrayMsg write SetDoneTrayMessage; + property DoneTrayMsgEnabled: boolean read FDoneTrayMsgEnabled write FDoneTrayMsgEnabled; + property DoneAudio: string read FDoneAudio write FDoneAudio; + property DoneAudioEnabled: boolean read FDoneAudioEnabled write FDoneAudioEnabled; + property DoneApp: string read FDoneApp write FDoneApp; + property DoneAppEnabled: boolean read FDoneAppEnabled write FDoneAppEnabled; + // Fonts + property Font: TFontConfig read FFont write FFont; +end; + +function GetConfig : TConfig; + +implementation + +uses + IniFiles; + +// Default values +const + INI_SEC_MAIN = 'Main'; + INI_SEC_ALARMS = 'Alarms'; + INI_SEC_PLACEMENT = 'Placement'; + INI_SEC_FONTS = 'Fonts'; + INI_MINUTES = 'Minutes'; + INI_ALWAYS_ON_TOP = 'AlwaysOnTop'; + INI_MIN_TO_TRAY = 'MinToTray'; + INI_AUTOSTART = 'AutoStart'; + INI_HIDESECONDS = 'HideSeconds'; + INI_CLICKTIME = 'ClickTime'; + INI_DBLCLICKTIME = 'DoubleClickTime'; + INI_AUTORESTART = 'AutoRestart'; + INI_LOOP_AUDIO = 'LoopAudio'; + INI_TICKING_ON = 'TickingEnabled'; + INI_AUTOSAVE = 'AutoSave'; + INI_HEIGHT = 'WinHeight'; + INI_WIDTH = 'WinWidth'; + INI_LEFT = 'WinLeft'; + INI_TOP = 'WinTop'; + INI_POSITION = 'WinPosition'; + INI_DONE_MESSAGE = 'Message'; + INI_DONE_MESSAGE_ON = 'MessageEnabled'; + INI_DONE_TRAY_MESSAGE = 'TrayMessage'; + INI_DONE_TRAY_MESSAGE_ON = 'TrayMessageEnabled'; + INI_DONE_AUDIO = 'AudioFile'; + INI_DONE_AUDIO_ON = 'AudioFileEnabled'; + INI_DONE_APP = 'RunApp'; + INI_DONE_APP_ON = 'RunAppEnabled'; + INI_SECONDS_MODE = 'SecondsMode'; + INI_FONT_NAME = 'Name'; + INI_FONT_CHARSET = 'Charset'; + INI_FONT_COLOR = 'Color'; + INI_FONT_SIZE = 'Size'; + INI_FONT_STYLE = 'Style'; + INI_BG_COLOR = 'BgColor'; + + INI_FILE_NAME = 'SnapTimer.ini'; + DEF_TIME = 15; + DEF_DONE_MSG = 'Time''s up'; + DEF_DONE_MSG_ON = True; + DEF_DONE_TRAY_MSG = 'Countdown completed'; + DEF_DONE_TRAY_MSG_ON = False; + DEF_DONE_AUDIO = '.\sounds\alarm_clock_bell.wav'; + DEF_DONE_AUDIO_ON = False; + DEF_DONE_APP = ''; + DEF_DONE_APP_ON = False; + DEF_ALWAYS_ON_TOP = False; + DEF_MIN_TO_TRAY = False; + DEF_AUTOSTART = False; + DEF_HIDESECONDS = False; + DEF_CLICKTIME = True; + DEF_DBLCLICKTIME = True; + DEF_AUTORESTART = False; + DEF_LOOP_AUDIO = False; + DEF_TICKING_ON = False; + DEF_TICKING_PATH = '.\sounds\ticking\ticking.wav'; + DEF_AUTOSAVE = True; + DEF_SECONDS_MODE = False; + DEF_POSITION = Ord(Center); + DEF_HEIGHT = 149; + DEF_WIDTH = 214; + DEF_FONT_NAME = 'Arial'; + DEF_FONT_CHARSET = 0; + DEF_FONT_COLOR = clNavy; + DEF_FONT_BG_COLOR = clNone; + DEF_FONT_SIZE = 38; + DEF_FONT_STYLE = 0; + + var + ConfigInstance : TConfig; + + +procedure TConfig.SetDoneMessage(Msg: String); +begin + // TODO Set some reasonable length limit + FDoneMessage:= Msg; +end; + +procedure TConfig.SetDoneTrayMessage(Msg: String); +begin + // TODO Set some reasonable length limit + FDoneTrayMsg:= Msg; +end; + +function FontStylesToInt(FontStyles: TFontStyles): integer; +var + Mask: integer; + Style: TFontStyle; +begin + // Translate the set into a bit mask + Mask := 0; + for Style := Low(TFontStyle) to High(TFontStyle) do + if Style in FontStyles then + Mask := Mask or (1 shl Ord(Style)); + Result := Mask; +end; + +function IntToFontStyles(Mask: integer): TFontStyles; +var + i: integer; + StyleSet: TFontStyles; +begin + // Translate the bit mask into a set + StyleSet := []; + for i := 0 to Ord(High(TFontStyle)) do + if Mask and (1 shl i) <> 0 then + StyleSet := StyleSet + [TFontStyle(i)]; + Result := StyleSet; +end; + +constructor TConfig.Create; +begin + // Main + Minutes:= DEF_TIME; + AlwaysOnTop := DEF_ALWAYS_ON_TOP; + MinToTray:= DEF_MIN_TO_TRAY; + AutoStart:= DEF_AUTOSTART; + HideSeconds:= DEF_HIDESECONDS; + ClickTime:= DEF_CLICKTIME; + DblClickTime:= DEF_DBLCLICKTIME; + AutoRestart:= DEF_AUTORESTART; + LoopAudio:= DEF_LOOP_AUDIO; + TickingOn:= DEF_TICKING_ON; + AutoSave:= DEF_AUTOSAVE; + SecondsMode:= DEF_SECONDS_MODE; + CompactMode := False; + // Placement + WndPosition:= TPosition(DEF_POSITION); + WndWidth:= DEF_WIDTH; + WndHeight:= DEF_HEIGHT; + // Alarms + DoneMessage:= DEF_DONE_MSG; + DoneMessageEnabled:= DEF_DONE_MSG_ON; + DoneTrayMsg:= DEF_DONE_TRAY_MSG; + DoneTrayMsgEnabled:= DEF_DONE_TRAY_MSG_ON; + DoneAudio:= DEF_DONE_AUDIO; + DoneAudioEnabled:= DEF_DONE_AUDIO_ON; + DoneApp:= DEF_DONE_APP; + DoneAppEnabled:= DEF_DONE_APP_ON; + // Fonts + FFont:= TFontConfig.Create; + Font.Name:= DEF_FONT_NAME; + Font.Charset:= DEF_FONT_CHARSET; + Font.Color:= DEF_FONT_COLOR; + Font.BgColor:= DEF_FONT_BG_COLOR; + Font.Size:= DEF_FONT_SIZE; + Font.Style:= IntToFontStyles(DEF_FONT_STYLE); + + FDefaultFont:= TFontConfig.Create; + FDefaultFont.Name:= DEF_FONT_NAME; + FDefaultFont.Charset:= DEF_FONT_CHARSET; + FDefaultFont.Color:= DEF_FONT_COLOR; + FDefaultFont.BgColor:= DEF_FONT_BG_COLOR; + FDefaultFont.Size:= DEF_FONT_SIZE; + FDefaultFont.Style:= IntToFontStyles(DEF_FONT_STYLE); +end; + +destructor TConfig.Free; +begin + FFont.Free; + FDefaultFont.Free; +end; + +function TConfig.Load : Boolean; +var IniFile: TIniFile; +begin + try + IniFile := TIniFile.Create(INI_FILE_NAME); + // Main + Minutes := IniFile.ReadInteger(INI_SEC_MAIN, INI_MINUTES, DEF_TIME); + AlwaysOnTop := IniFile.ReadBool(INI_SEC_MAIN, INI_ALWAYS_ON_TOP, DEF_ALWAYS_ON_TOP); + MinToTray := IniFile.ReadBool(INI_SEC_MAIN, INI_MIN_TO_TRAY, DEF_MIN_TO_TRAY); + AutoStart := IniFile.ReadBool(INI_SEC_MAIN, INI_AUTOSTART, DEF_AUTOSTART); + HideSeconds := IniFile.ReadBool(INI_SEC_MAIN, INI_HIDESECONDS, DEF_HIDESECONDS); + ClickTime := IniFile.ReadBool(INI_SEC_MAIN, INI_CLICKTIME, DEF_CLICKTIME); + DblClickTime := IniFile.ReadBool(INI_SEC_MAIN, INI_DBLCLICKTIME, DEF_DBLCLICKTIME); + AutoRestart := IniFile.ReadBool(INI_SEC_MAIN, INI_AUTORESTART, DEF_AUTORESTART); + LoopAudio := IniFile.ReadBool(INI_SEC_MAIN, INI_LOOP_AUDIO, DEF_LOOP_AUDIO); + TickingOn := IniFile.ReadBool(INI_SEC_MAIN, INI_TICKING_ON, DEF_TICKING_ON); + AutoSave := IniFile.ReadBool(INI_SEC_MAIN, INI_AUTOSAVE, DEF_AUTOSAVE); + SecondsMode := IniFile.ReadBool(INI_SEC_MAIN, INI_SECONDS_MODE, DEF_SECONDS_MODE); + // Placement + WndHeight := IniFile.ReadInteger(INI_SEC_PLACEMENT, INI_HEIGHT, DEF_HEIGHT); + WndWidth := IniFile.ReadInteger(INI_SEC_PLACEMENT, INI_WIDTH, DEF_WIDTH); + WndLeft := IniFile.ReadInteger(INI_SEC_PLACEMENT, INI_LEFT, 0); + WndTop := IniFile.ReadInteger(INI_SEC_PLACEMENT, INI_TOP, 0); + WndPosition := TPosition(IniFile.ReadInteger(INI_SEC_PLACEMENT, INI_POSITION, DEF_POSITION)); + // Alarm + DoneMessage := IniFile.ReadString(INI_SEC_ALARMS, INI_DONE_MESSAGE, DEF_DONE_MSG); + DoneMessageEnabled := IniFile.ReadBool(INI_SEC_ALARMS, INI_DONE_MESSAGE_ON, DEF_DONE_MSG_ON); + DoneTrayMsg := IniFile.ReadString(INI_SEC_ALARMS, INI_DONE_TRAY_MESSAGE, DEF_DONE_TRAY_MSG); + DoneTrayMsgEnabled := IniFile.ReadBool(INI_SEC_ALARMS, INI_DONE_TRAY_MESSAGE_ON, DEF_DONE_TRAY_MSG_ON); + DoneAudio := IniFile.ReadString(INI_SEC_ALARMS, INI_DONE_AUDIO, DEF_DONE_AUDIO); + DoneAudioEnabled := IniFile.ReadBool(INI_SEC_ALARMS, INI_DONE_AUDIO_ON, DEF_DONE_AUDIO_ON); + DoneApp := IniFile.ReadString(INI_SEC_ALARMS, INI_DONE_APP, DEF_DONE_APP); + DoneAppEnabled := IniFile.ReadBool(INI_SEC_ALARMS, INI_DONE_APP_ON, DEF_DONE_APP_ON); + // Fonts + Font.Name := IniFile.ReadString(INI_SEC_FONTS, INI_FONT_NAME, DEF_FONT_NAME); + Font.Charset := IniFile.ReadInteger(INI_SEC_FONTS, INI_FONT_CHARSET, DEF_FONT_CHARSET); + Font.Color := IniFile.ReadInteger(INI_SEC_FONTS, INI_FONT_COLOR, DEF_FONT_COLOR); + Font.BgColor := IniFile.ReadInteger(INI_SEC_FONTS, INI_BG_COLOR, DEF_FONT_BG_COLOR); + Font.Size := IniFile.ReadInteger(INI_SEC_FONTS, INI_FONT_SIZE, DEF_FONT_SIZE); + Font.Style := IntToFontStyles(IniFile.ReadInteger(INI_SEC_FONTS, INI_FONT_STYLE, DEF_FONT_STYLE)); + except + Result:= False; + end; + Result:= True; + + if Assigned(IniFile) then + IniFile.Free; +end; + +function TConfig.Save : Boolean; +var IniFile: TIniFile; +begin + try + IniFile := TIniFile.Create(INI_FILE_NAME); + IniFile.CacheUpdates := True; + // Main + IniFile.WriteInteger(INI_SEC_MAIN, INI_MINUTES, Minutes); + IniFile.WriteBool(INI_SEC_MAIN, INI_ALWAYS_ON_TOP, AlwaysOnTop); + IniFile.WriteBool(INI_SEC_MAIN, INI_MIN_TO_TRAY, MinToTray); + IniFile.WriteBool(INI_SEC_MAIN, INI_AUTOSTART, AutoStart); + IniFile.WriteBool(INI_SEC_MAIN, INI_HIDESECONDS, HideSeconds); + IniFile.WriteBool(INI_SEC_MAIN, INI_CLICKTIME, ClickTime); + IniFile.WriteBool(INI_SEC_MAIN, INI_DBLCLICKTIME, DblClickTime); + IniFile.WriteBool(INI_SEC_MAIN, INI_AUTORESTART, AutoRestart); + IniFile.WriteBool(INI_SEC_MAIN, INI_LOOP_AUDIO, LoopAudio); + IniFile.WriteBool(INI_SEC_MAIN, INI_TICKING_ON, TickingOn); + IniFile.WriteBool(INI_SEC_MAIN, INI_AUTOSAVE, AutoSave); + IniFile.WriteBool(INI_SEC_MAIN, INI_SECONDS_MODE, SecondsMode); + // Placement + IniFile.WriteInteger(INI_SEC_PLACEMENT, INI_HEIGHT, WndHeight); + IniFile.WriteInteger(INI_SEC_PLACEMENT, INI_WIDTH, WndWidth); + IniFile.WriteInteger(INI_SEC_PLACEMENT, INI_LEFT, WndLeft); + IniFile.WriteInteger(INI_SEC_PLACEMENT, INI_TOP, WndTop); + IniFile.WriteInteger(INI_SEC_PLACEMENT, INI_POSITION, Ord(WndPosition)); + // Alarms + IniFile.WriteString(INI_SEC_ALARMS, INI_DONE_MESSAGE, DoneMessage); + IniFile.WriteBool(INI_SEC_ALARMS, INI_DONE_MESSAGE_ON, DoneMessageEnabled); + IniFile.WriteString(INI_SEC_ALARMS, INI_DONE_TRAY_MESSAGE, DoneTrayMsg); + IniFile.WriteBool(INI_SEC_ALARMS, INI_DONE_TRAY_MESSAGE_ON, DoneTrayMsgEnabled); + IniFile.WriteString(INI_SEC_ALARMS, INI_DONE_AUDIO, DoneAudio); + IniFile.WriteBool(INI_SEC_ALARMS, INI_DONE_AUDIO_ON, DoneAudioEnabled); + IniFile.WriteString(INI_SEC_ALARMS, INI_DONE_APP, DoneApp); + IniFile.WriteBool(INI_SEC_ALARMS, INI_DONE_APP_ON, DoneAppEnabled); + // Fonts + IniFile.WriteString(INI_SEC_FONTS, INI_FONT_NAME, Font.Name); + IniFile.WriteInteger(INI_SEC_FONTS, INI_FONT_CHARSET, Font.Charset); + IniFile.WriteInteger(INI_SEC_FONTS, INI_FONT_COLOR, Font.Color); + IniFile.WriteInteger(INI_SEC_FONTS, INI_BG_COLOR, Font.BgColor); + IniFile.WriteInteger(INI_SEC_FONTS, INI_FONT_SIZE, Font.Size); + IniFile.WriteInteger(INI_SEC_FONTS, INI_FONT_STYLE, FontStylesToInt(Font.Style)); + + IniFile.UpdateFile; + except + Result:= False; + end; + Result:= True; + + if Assigned(IniFile) then + IniFile.Free; +end; + +function TConfig.GetDefaultFont : TFontConfig; +begin + Result:= FDefaultFont; +end; + +function GetConfig : TConfig; +begin + Result:= ConfigInstance; +end; + +initialization + ConfigInstance:= TConfig.Create; + +end. + diff --git a/snaptimer.lpi b/snaptimer.lpi index 917dfa4..0064e5b 100644 --- a/snaptimer.lpi +++ b/snaptimer.lpi @@ -26,7 +26,7 @@ - + @@ -64,6 +64,9 @@ + + + @@ -82,7 +85,7 @@ - + @@ -101,15 +104,24 @@ + + + - + + + + + + + @@ -120,7 +132,7 @@ - + diff --git a/snaptimer.lps b/snaptimer.lps index 9009816..dca158c 100644 --- a/snaptimer.lps +++ b/snaptimer.lps @@ -4,107 +4,288 @@ - + - - + + - - + + - - - + + + + + - - + + - - - + + + + + - - + + + - + + + + + + + - + + - - - - - + + + + + + + - + - - - - - - + + + + + + - - + + + - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + - + - - + + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/ui/mainform1.lfm b/ui/mainform1.lfm index 58778bf..cc89aa5 100644 --- a/ui/mainform1.lfm +++ b/ui/mainform1.lfm @@ -1,8 +1,8 @@ object MainForm: TMainForm Left = 533 - Height = 363 + Height = 242 Top = 312 - Width = 392 + Width = 261 HorzScrollBar.Page = 274 HorzScrollBar.Range = 275 HorzScrollBar.Visible = False @@ -11,11 +11,10 @@ object MainForm: TMainForm VertScrollBar.Visible = False ActiveControl = Minutes Caption = 'SnapTimer' - ClientHeight = 333 - ClientWidth = 392 - Constraints.MinHeight = 105 - Constraints.MinWidth = 240 - DesignTimePPI = 144 + ClientHeight = 222 + ClientWidth = 261 + Constraints.MinHeight = 70 + Constraints.MinWidth = 160 KeyPreview = True Menu = MainMenu1 OnActivate = FormActivate @@ -28,13 +27,13 @@ object MainForm: TMainForm LCLVersion = '2.0.10.0' object TimeLabel: TLabel AnchorSideRight.Control = Minutes - Left = 10 - Height = 24 - Top = 8 - Width = 70 + Left = 7 + Height = 16 + Top = 5 + Width = 47 AutoSize = False - BorderSpacing.Left = 8 - BorderSpacing.Right = 3 + BorderSpacing.Left = 5 + BorderSpacing.Right = 2 Caption = 'Minutes:' FocusControl = Minutes Layout = tlCenter @@ -42,11 +41,11 @@ object MainForm: TMainForm ParentFont = False end object ImgStart: TImage - Left = 168 - Height = 38 + Left = 112 + Height = 25 Hint = 'Start' - Top = 3 - Width = 38 + Top = 2 + Width = 25 OnClick = ToggleCountdown ParentShowHint = False Picture.Data = { @@ -110,11 +109,11 @@ object MainForm: TMainForm ShowHint = True end object ImgReset: TImage - Left = 208 - Height = 38 + Left = 139 + Height = 25 Hint = 'Reset' - Top = 3 - Width = 38 + Top = 2 + Width = 25 OnClick = ResetCountdown ParentShowHint = False Picture.Data = { @@ -179,11 +178,11 @@ object MainForm: TMainForm ShowHint = True end object ImgPause: TImage - Left = 168 - Height = 38 + Left = 112 + Height = 25 Hint = 'Pause' - Top = 3 - Width = 38 + Top = 2 + Width = 25 OnClick = ToggleCountdown ParentShowHint = False Picture.Data = { @@ -252,10 +251,10 @@ object MainForm: TMainForm Visible = False end object ImgIconRunning: TImage - Left = 232 - Height = 22 - Top = 60 - Width = 15 + Left = 155 + Height = 15 + Top = 40 + Width = 10 Picture.Data = { 055449636F6E7E04000000000100010010100000010020006804000016000000 2800000010000000200000000100200000000000000000000000000000000000 @@ -298,10 +297,10 @@ object MainForm: TMainForm Visible = False end object ImgIconPaused: TImage - Left = 240 - Height = 22 - Top = 60 - Width = 15 + Left = 160 + Height = 15 + Top = 40 + Width = 10 Picture.Data = { 055449636F6E7E04000000000100010010100000010020006804000016000000 2800000010000000200000000100200000000000000000000000000000000000 @@ -344,10 +343,10 @@ object MainForm: TMainForm Visible = False end object ImgIconDone: TImage - Left = 240 - Height = 22 - Top = 60 - Width = 15 + Left = 160 + Height = 15 + Top = 40 + Width = 10 Picture.Data = { 055449636F6E7E04000000000100010010100000010020006804000016000000 2800000010000000200000000100200000000000000000000000000000000000 @@ -390,10 +389,10 @@ object MainForm: TMainForm Visible = False end object ImgIconMain: TImage - Left = 240 - Height = 22 - Top = 60 - Width = 15 + Left = 160 + Height = 15 + Top = 40 + Width = 10 Picture.Data = { 055449636F6E7E04000000000100010010100000010020006804000016000000 2800000010000000200000000100200000000000000000000000000000000000 @@ -437,11 +436,11 @@ object MainForm: TMainForm end object Minutes: TSpinEdit AnchorSideLeft.Side = asrBottom - Left = 88 - Height = 33 - Top = 3 - Width = 70 - BorderSpacing.Right = 8 + Left = 59 + Height = 23 + Top = 2 + Width = 47 + BorderSpacing.Right = 5 Increment = 5 MaxValue = 5999 OnChange = MinutesChanged @@ -450,20 +449,20 @@ object MainForm: TMainForm end object Count: TStaticText Cursor = crHandPoint - Left = 3 - Height = 301 + Left = 2 + Height = 190 Top = 32 - Width = 386 + Width = 257 Align = alBottom Alignment = taCenter Anchors = [akTop, akLeft, akRight] - BorderSpacing.Left = 3 - BorderSpacing.Top = 6 - BorderSpacing.Right = 3 + BorderSpacing.Left = 2 + BorderSpacing.Top = 4 + BorderSpacing.Right = 2 BorderStyle = sbsSunken Caption = '00:00:00' Font.CharSet = ANSI_CHARSET - Font.Height = -72 + Font.Height = -48 Font.Name = 'Arial Narrow' Font.Pitch = fpVariable Font.Quality = fqDraft @@ -477,8 +476,8 @@ object MainForm: TMainForm Enabled = False OnTimer = Countdown OnStartTimer = Countdown - Left = 288 - Top = 240 + Left = 192 + Top = 160 end object TrayIconMain: TTrayIcon BalloonFlags = bfInfo @@ -524,12 +523,12 @@ object MainForm: TMainForm } Visible = True OnClick = ToggleCountdown - Left = 168 - Top = 240 + Left = 112 + Top = 160 end object MainMenu1: TMainMenu - Left = 36 - Top = 156 + Left = 24 + Top = 104 object MenuFile: TMenuItem Caption = 'File' object MenuToggle: TMenuItem @@ -570,8 +569,8 @@ object MainForm: TMainForm end end object TrayMenu: TPopupMenu - Left = 36 - Top = 240 + Left = 24 + Top = 160 object MenuCount: TMenuItem Caption = 'Countdown' Enabled = False @@ -609,8 +608,8 @@ object MainForm: TMainForm end end object PopupMenuCompact: TPopupMenu - Left = 192 - Top = 156 + Left = 128 + Top = 104 object MenuCompact: TMenuItem Caption = 'Toggle compact mode' OnClick = ToggleCompact diff --git a/ui/mainform1.pas b/ui/mainform1.pas index b46aa61..8e36127 100644 --- a/ui/mainform1.pas +++ b/ui/mainform1.pas @@ -6,15 +6,13 @@ interface uses Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, - Menus, StdCtrls, Spin, ExtCtrls, About, LCLType, IniFiles, Options, MMSystem, + Menus, StdCtrls, Spin, ExtCtrls, About, LCLType, Options, MMSystem, Windows, StrUtils, DateUtils; type - TMode = (Timer, Stopwatch); - TPosition = (Center, Remember, TopLeft, TopRight, BottomLeft, BottomRight); + TMode = (Timer, Stopwatch); { TMainForm } - TMainForm = class(TForm) ImgIconMain: TImage; ImgIconRunning: TImage; @@ -76,103 +74,43 @@ TMainForm = class(TForm) procedure RunApp(Path: string); procedure ShowDoneMessage(Msg: string); procedure ShowTrayMessage(Msg: string); - function GetHandle(): HWND; - procedure SetDefaults(Sender: TObject); - function FontStylesToInt(Fnt: TFont): integer; - function IntToFontStyles(Mask: integer): TFontStyles; + //f GetHandle(): HWND; procedure SetFieldsVisible(showFields: boolean); - procedure UpdateAlwaysOnTop(onTop: boolean); procedure PlayTicking(); function IsInteger(S: String): boolean; - procedure UpdateTimeCaption(newSecondsMode: boolean); + //procedure UpdateTimeCaption(newSecondsMode: boolean); private { private declarations } - IniFile: TIniFile; - AlwaysOnTop: boolean; - MinToTray: boolean; - AutoStart: boolean; - HideSeconds: boolean; - ClickTime: boolean; - DblClickTime: boolean; - AutoRestart: boolean; - LoopAudio: boolean; AudioPlaying: boolean; - TickingOn: boolean; - AutoSave: boolean; - DoneMessage: string; - DoneMessageEnabled: boolean; - DoneTrayMsg: string; - DoneTrayMsgEnabled: boolean; - DoneAudio: string; - DoneAudioEnabled: boolean; - DoneApp: string; - DoneAppEnabled: boolean; - WndPosition: TPosition; - WndPositions: TStrings; - WndHeight: integer; - WndWidth: integer; - WndTop: integer; - WndLeft: integer; WndHandle: HWND; - SecondsMode: boolean; // Undocumented mode to treat minutes as seconds + WndPositions: TStrings; Mode: TMode; - CompactMode: boolean; FontSizeChanged : boolean; //FormerWidth : integer; //FormerHeight : integer; EndTime: TDateTime; StartTime: TDateTime; CountdownDone: boolean; + OnShowFormFirstTime: Boolean; + procedure ApplyConfig(APosition: Boolean); public { public declarations } end; var MainForm: TMainForm; - AppName: string; - IniFilename: string; + //AppName: string; + implementation +uses + Config; + { TMainForm } const APP_NAME = 'SnapTimer'; - INI_SEC_MAIN = 'Main'; - INI_SEC_ALARMS = 'Alarms'; - INI_SEC_PLACEMENT = 'Placement'; - INI_SEC_FONTS = 'Fonts'; - INI_MINUTES = 'Minutes'; - INI_ALWAYS_ON_TOP = 'AlwaysOnTop'; - INI_MIN_TO_TRAY = 'MinToTray'; - INI_AUTOSTART = 'AutoStart'; - INI_HIDESECONDS = 'HideSeconds'; - INI_CLICKTIME = 'ClickTime'; - INI_DBLCLICKTIME = 'DoubleClickTime'; - INI_AUTORESTART = 'AutoRestart'; - INI_LOOP_AUDIO = 'LoopAudio'; - INI_TICKING_ON = 'TickingEnabled'; - INI_AUTOSAVE = 'AutoSave'; - INI_HEIGHT = 'WinHeight'; - INI_WIDTH = 'WinWidth'; - INI_LEFT = 'WinLeft'; - INI_TOP = 'WinTop'; - INI_POSITION = 'WinPosition'; - INI_DONE_MESSAGE = 'Message'; - INI_DONE_MESSAGE_ON = 'MessageEnabled'; - INI_DONE_TRAY_MESSAGE = 'TrayMessage'; - INI_DONE_TRAY_MESSAGE_ON = 'TrayMessageEnabled'; - INI_DONE_AUDIO = 'AudioFile'; - INI_DONE_AUDIO_ON = 'AudioFileEnabled'; - INI_DONE_APP = 'RunApp'; - INI_DONE_APP_ON = 'RunAppEnabled'; - INI_SECONDS_MODE = 'SecondsMode'; - INI_FONT_NAME = 'Name'; - INI_FONT_CHARSET = 'Charset'; - INI_FONT_COLOR = 'Color'; - INI_FONT_SIZE = 'Size'; - INI_FONT_STYLE = 'Style'; - INI_BG_COLOR = 'BgColor'; // Menu items MENU_FILE = '&File'; @@ -192,45 +130,17 @@ implementation LBL_MINUTES = '&Minutes:'; LBL_SECONDS = '&Seconds:'; - // Default values - DEF_TIME = 15; - DEF_DONE_MSG = 'Time''s up'; - DEF_DONE_MSG_ON = True; - DEF_DONE_TRAY_MSG = 'Countdown completed'; - DEF_DONE_TRAY_MSG_ON = False; - DEF_DONE_AUDIO = '.\sounds\alarm_clock_bell.wav'; - DEF_DONE_AUDIO_ON = False; - DEF_DONE_APP = ''; - DEF_DONE_APP_ON = False; - DEF_ALWAYS_ON_TOP = False; - DEF_MIN_TO_TRAY = False; - DEF_AUTOSTART = False; - DEF_HIDESECONDS = False; - DEF_CLICKTIME = True; - DEF_DBLCLICKTIME = True; - DEF_AUTORESTART = False; - DEF_LOOP_AUDIO = False; - DEF_TICKING_ON = False; - DEF_TICKING_PATH = '.\sounds\ticking\ticking.wav'; - DEF_AUTOSAVE = True; - DEF_SECONDS_MODE = False; - DEF_POSITION = Ord(Center); - DEF_HEIGHT = 149; - DEF_WIDTH = 214; - DEF_FONT_NAME = 'Arial'; - DEF_FONT_CHARSET = 0; - DEF_FONT_COLOR = clNavy; - DEF_FONT_SIZE = 38; - DEF_FONT_STYLE = 0; - DEF_BG_COLOR = clNone; - // Messages MSG_OPEN_INI = 'An error occurred opening the .ini file, settings won''t be saved'; MSG_WRITE_INI = 'An error occurred trying to write to the .ini file, settings won''t be saved.'; procedure TMainForm.OnCreateForm(Sender: TObject); +var + Config: TConfig; begin + Config:= GetConfig; + MenuFile.Caption := MENU_FILE; MenuToggle.Caption := BTN_START; MenuReset.Caption := BTN_RESET; @@ -247,27 +157,7 @@ procedure TMainForm.OnCreateForm(Sender: TObject); TrayMenuExit.Caption := MENU_EXIT; // Set all defaults, then load from .ini - Minutes.Value := DEF_TIME; - AlwaysOnTop := DEF_ALWAYS_ON_TOP; - MinToTray := DEF_MIN_TO_TRAY; - AutoStart := DEF_AUTOSTART; - HideSeconds := DEF_HIDESECONDS; - ClickTime := DEF_CLICKTIME; - DblClickTime := DEF_DBLCLICKTIME; - AutoRestart := DEF_AUTORESTART; - LoopAudio := DEF_LOOP_AUDIO; - TickingOn := DEF_TICKING_ON; - AutoSave := DEF_AUTOSAVE; - DoneMessage := DEF_DONE_MSG; - DoneMessageEnabled := DEF_DONE_MSG_ON; - DoneTrayMsg := DEF_DONE_TRAY_MSG; - DoneTrayMsgEnabled := DEF_DONE_TRAY_MSG_ON; - DoneAudio := DEF_DONE_AUDIO; - DoneAudioEnabled := DEF_DONE_AUDIO_ON; - DoneApp := DEF_DONE_APP; - DoneAppEnabled := DEF_DONE_APP_ON; - SecondsMode := DEF_SECONDS_MODE; - WndPosition := TPosition(DEF_POSITION); + WndPositions := TStringList.Create; WndPositions.Add('Centered'); @@ -278,15 +168,14 @@ procedure TMainForm.OnCreateForm(Sender: TObject); WndPositions.Add('Bottom right'); Mode := Timer; - CompactMode := False; AudioPlaying := False; Self.DoubleBuffered := True; Count.DoubleBuffered := True; Timer1.Interval := 150; CountdownDone := False; + OnShowFormFirstTime:= True; - AppName := ExtractFileName(Application.ExeName); - IniFilename := ExtractFilePath(Application.ExeName) + ChangeFileExt(AppName, '.ini'); + //AppName := ExtractFileName(Application.ExeName); // TODO For some reason this isn't working at all //WriteLn('checking for options: ' + IntToStr(ParamCount)); @@ -302,70 +191,27 @@ procedure TMainForm.OnCreateForm(Sender: TObject); // WriteLn('ini option found'); //end; //end; - try - IniFile := TIniFile.Create(IniFilename); - Minutes.Value := IniFile.ReadInteger(INI_SEC_MAIN, INI_MINUTES, DEF_TIME); - AlwaysOnTop := IniFile.ReadBool(INI_SEC_MAIN, INI_ALWAYS_ON_TOP, DEF_ALWAYS_ON_TOP); - MinToTray := IniFile.ReadBool(INI_SEC_MAIN, INI_MIN_TO_TRAY, DEF_MIN_TO_TRAY); - AutoStart := IniFile.ReadBool(INI_SEC_MAIN, INI_AUTOSTART, DEF_AUTOSTART); - HideSeconds := IniFile.ReadBool(INI_SEC_MAIN, INI_HIDESECONDS, DEF_HIDESECONDS); - ClickTime := IniFile.ReadBool(INI_SEC_MAIN, INI_CLICKTIME, DEF_CLICKTIME); - DblClickTime := IniFile.ReadBool(INI_SEC_MAIN, INI_DBLCLICKTIME, DEF_DBLCLICKTIME); - AutoRestart := IniFile.ReadBool(INI_SEC_MAIN, INI_AUTORESTART, DEF_AUTORESTART); - LoopAudio := IniFile.ReadBool(INI_SEC_MAIN, INI_LOOP_AUDIO, DEF_LOOP_AUDIO); - TickingOn := IniFile.ReadBool(INI_SEC_MAIN, INI_TICKING_ON, DEF_TICKING_ON); - AutoSave := IniFile.ReadBool(INI_SEC_MAIN, INI_AUTOSAVE, DEF_AUTOSAVE); - SecondsMode := IniFile.ReadBool(INI_SEC_MAIN, INI_SECONDS_MODE, DEF_SECONDS_MODE); - DoneMessage := IniFile.ReadString(INI_SEC_ALARMS, INI_DONE_MESSAGE, DEF_DONE_MSG); - DoneMessageEnabled := IniFile.ReadBool(INI_SEC_ALARMS, INI_DONE_MESSAGE_ON, - DEF_DONE_MSG_ON); - DoneTrayMsg := IniFile.ReadString(INI_SEC_ALARMS, INI_DONE_TRAY_MESSAGE, - DEF_DONE_TRAY_MSG); - DoneTrayMsgEnabled := IniFile.ReadBool(INI_SEC_ALARMS, - INI_DONE_TRAY_MESSAGE_ON, DEF_DONE_TRAY_MSG_ON); - DoneAudio := IniFile.ReadString(INI_SEC_ALARMS, INI_DONE_AUDIO, DEF_DONE_AUDIO); - DoneAudioEnabled := IniFile.ReadBool(INI_SEC_ALARMS, INI_DONE_AUDIO_ON, - DEF_DONE_AUDIO_ON); - DoneApp := IniFile.ReadString(INI_SEC_ALARMS, INI_DONE_APP, DEF_DONE_APP); - DoneAppEnabled := IniFile.ReadBool(INI_SEC_ALARMS, INI_DONE_APP_ON, DEF_DONE_APP_ON); - WndHeight := IniFile.ReadInteger(INI_SEC_PLACEMENT, INI_HEIGHT, DEF_HEIGHT); - WndWidth := IniFile.ReadInteger(INI_SEC_PLACEMENT, INI_WIDTH, DEF_WIDTH); - WndPosition := TPosition(IniFile.ReadInteger(INI_SEC_PLACEMENT, INI_POSITION, DEF_POSITION)); - WndLeft := IniFile.ReadInteger(INI_SEC_PLACEMENT, INI_LEFT, 0); - WndTop := IniFile.ReadInteger(INI_SEC_PLACEMENT, INI_TOP, 0); - - Count.Font.Quality := fqAntialiased; - Count.Font.Name := IniFile.ReadString(INI_SEC_FONTS, INI_FONT_NAME, - DEF_FONT_NAME); - Count.Font.CharSet := IniFile.ReadInteger(INI_SEC_FONTS, INI_FONT_CHARSET, - DEF_FONT_CHARSET); - Count.Font.Color := IniFile.ReadInteger(INI_SEC_FONTS, INI_FONT_COLOR, - DEF_FONT_COLOR); - Count.Font.Size := IniFile.ReadInteger(INI_SEC_FONTS, INI_FONT_SIZE, - DEF_FONT_SIZE); - Count.Font.Style := IntToFontStyles(IniFile.ReadInteger(INI_SEC_FONTS, - INI_FONT_STYLE, DEF_FONT_STYLE)); - Count.Color := IniFile.ReadInteger(INI_SEC_FONTS, INI_BG_COLOR, DEF_BG_COLOR); - - except + + if Config.Load = False then + begin + // When will this code execute? MessageDlg(MSG_OPEN_INI, mtError, [mbOK], 0); + Exit; end; - if Assigned(IniFile) then - IniFile.Free; // Use minutes argument if it's the only parameter and it's numeric if (ParamCount = 1) and (IsInteger(ParamStr(1))) then Minutes.Value := StrToInt(ParamStr(1)); - UpdateTimeCaption(SecondsMode); + //UpdateTimeCaption(SecondsMode); ApplyConfig will do this ResetCountdown(Sender); - if AutoStart then + if Config.AutoStart then ToggleCountdown(Sender); end; procedure TMainForm.ResetCountdown(Sender: TObject); begin - if (Sender.ClassName = Count.ClassName) and (not DblClickTime) then + if (Sender.ClassName = Count.ClassName) and (not GetConfig.DblClickTime) then Exit; // Turn off both looping audio and ticking StopAudio(); @@ -393,13 +239,13 @@ procedure TMainForm.EnableTimer(); TrayMenuToggle.Caption := BTN_PAUSE; TrayIconMain.Icon := ImgIconRunning.Picture.Icon; - if TickingOn then + if GetConfig.TickingOn then PlayTicking(); end; procedure TMainForm.SetTimer(); begin - if SecondsMode then + if GetConfig.SecondsMode then Timer1.Tag := Minutes.Value else Timer1.Tag := Minutes.Value * 60; @@ -407,36 +253,40 @@ procedure TMainForm.SetTimer(); end; procedure TMainForm.ShowOptions(Sender: TObject); +var + Config: TConfig; begin + Config:= GetConfig; + // TODO move this to TOptionsForm OptionsForm := TOptionsForm.Create(Self); with OptionsForm do begin - NotifyMsg.Text := DoneMessage; - NotifyMsgOn.Checked := DoneMessageEnabled; - - NotifyTrayMsg.Text := DoneTrayMsg; - NotifyTrayMsgOn.Checked := DoneTrayMsgEnabled; - - NotifyAudio.Text := DoneAudio; - NotifyAudioOn.Checked := DoneAudioEnabled; - - NotifyRunApp.Text := DoneApp; - NotifyRunAppOn.Checked := DoneAppEnabled; - - CheckAlwaysOnTop.Checked := AlwaysOnTop; - CheckMinToTray.Checked := MinToTray; - CheckAutostart.Checked := AutoStart; - CheckHideSeconds.Checked := HideSeconds; - CheckClicktime.Checked := ClickTime; - CheckDblClickTime.Checked := DblClickTime; - CheckAutoRestart.Checked := AutoRestart; - CheckLoopAudio.Checked := LoopAudio; - CheckTicking.Checked := TickingOn; - CheckAutoSave.Checked := AutoSave; - CheckSecondsMode.Checked := SecondsMode; + NotifyMsg.Text:= Config.DoneMessage; + NotifyMsgOn.Checked:= Config.DoneMessageEnabled; + + NotifyTrayMsg.Text:= Config.DoneTrayMsg; + NotifyTrayMsgOn.Checked:= Config.DoneTrayMsgEnabled; + + NotifyAudio.Text:= Config.DoneAudio; + NotifyAudioOn.Checked:= Config.DoneAudioEnabled; + + NotifyRunApp.Text:= Config.DoneApp; + NotifyRunAppOn.Checked:= Config.DoneAppEnabled; + + CheckAlwaysOnTop.Checked:= Config.AlwaysOnTop; + CheckMinToTray.Checked:= Config.MinToTray; + CheckAutostart.Checked:= Config.AutoStart; + CheckHideSeconds.Checked:= Config.HideSeconds; + CheckClicktime.Checked:= Config.ClickTime; + CheckDblClickTime.Checked:= Config.DblClickTime; + CheckAutoRestart.Checked:= Config.AutoRestart; + CheckLoopAudio.Checked:= Config.LoopAudio; + CheckTicking.Checked:= Config.TickingOn; + CheckAutoSave.Checked:= Config.AutoSave; + CheckSecondsMode.Checked:= Config.SecondsMode; PositionCombo.Items := WndPositions; - PositionCombo.ItemIndex := Ord(WndPosition); + PositionCombo.ItemIndex := Ord(Config.WndPosition); PageControl1.TabIndex := 0; @@ -451,28 +301,29 @@ procedure TMainForm.ShowOptions(Sender: TObject); if ShowModal = mrOk then begin - UpdateTimeCaption(CheckSecondsMode.Checked); - - DoneMessage := NotifyMsg.Text; - DoneMessageEnabled := NotifyMsgOn.Checked; - DoneTrayMsg := NotifyTrayMsg.Text; - DoneTrayMsgEnabled := NotifyTrayMsgOn.Checked; - DoneAudio := NotifyAudio.Text; - DoneAudioEnabled := NotifyAudioOn.Checked; - DoneApp := NotifyRunApp.Text; - DoneAppEnabled := NotifyRunAppOn.Checked; - AlwaysOnTop := CheckAlwaysOnTop.Checked; - MinToTray := CheckMinToTray.Checked; - AutoStart := CheckAutostart.Checked; - HideSeconds := CheckHideSeconds.Checked; - ClickTime := CheckClicktime.Checked; - DblClickTime := CheckDblClickTime.Checked; - AutoRestart := CheckAutoRestart.Checked; - LoopAudio := CheckLoopAudio.Checked; - TickingOn := CheckTicking.Checked; - AutoSave := CheckAutoSave.Checked; - SecondsMode := CheckSecondsMode.Checked; - WndPosition := TPosition(PositionCombo.ItemIndex); + // replace with ApplyConig(False) + //UpdateTimeCaption(CheckSecondsMode.Checked); + + Config.DoneMessage:= NotifyMsg.Text; + Config.DoneMessageEnabled:= NotifyMsgOn.Checked; + Config.DoneTrayMsg:= NotifyTrayMsg.Text; + Config.DoneTrayMsgEnabled:= NotifyTrayMsgOn.Checked; + Config.DoneAudio:= NotifyAudio.Text; + Config.DoneAudioEnabled:= NotifyAudioOn.Checked; + Config.DoneApp:= NotifyRunApp.Text; + Config.DoneAppEnabled:= NotifyRunAppOn.Checked; + Config.AlwaysOnTop:= CheckAlwaysOnTop.Checked; + Config.MinToTray:= CheckMinToTray.Checked; + Config.AutoStart:= CheckAutostart.Checked; + Config.HideSeconds:= CheckHideSeconds.Checked; + Config.ClickTime:= CheckClicktime.Checked; + Config.DblClickTime:= CheckDblClickTime.Checked; + Config.AutoRestart:= CheckAutoRestart.Checked; + Config.LoopAudio:= CheckLoopAudio.Checked; + Config.TickingOn:= CheckTicking.Checked; + Config.AutoSave:= CheckAutoSave.Checked; + Config.SecondsMode:= CheckSecondsMode.Checked; + Config.WndPosition:= TPosition(PositionCombo.ItemIndex); //if not (Count.Font.Size = f.Size) then //begin //FontSizeChanged := True; @@ -491,17 +342,17 @@ procedure TMainForm.ShowOptions(Sender: TObject); //if FontSizeChanged then OnShowForm(Sender); - UpdateAlwaysOnTop(AlwaysOnTop); + //UpdateAlwaysOnTop(AlwaysOnTop); if Timer1.Enabled then begin - if TickingOn then + if Config.TickingOn then PlayTicking else StopAudio(); end; - if AutoSave then + if Config.AutoSave then SaveSettings(Sender); // TODO Resize the window if necessary to accomodate larger text // Get the text size from the font for '00:00:00'? @@ -513,7 +364,7 @@ procedure TMainForm.ShowOptions(Sender: TObject); procedure TMainForm.ToggleCountdown(Sender: TObject); begin - if (Sender.ClassName = Count.ClassName) and (not ClickTime) then + if (Sender.ClassName = Count.ClassName) and (not GetConfig.ClickTime) then Exit; if Minutes.Value = 0 then @@ -547,7 +398,9 @@ procedure TMainForm.ToggleCountdown(Sender: TObject); end; procedure TMainForm.Countdown(Sender: TObject); +var Config: TConfig; begin + Config:= GetConfig; if MODE = Stopwatch then begin Timer1.Tag := SecondsBetween(StartTime, Now); @@ -562,16 +415,16 @@ procedure TMainForm.Countdown(Sender: TObject); DisableTimer(); CountdownDone := True; Application.Title := APP_NAME; - if DoneAudioEnabled then - PlayAudio(DoneAudio, LoopAudio); - if DoneAppEnabled then - RunApp(DoneApp); - if DoneTrayMsgEnabled then - ShowTrayMessage(DoneTrayMsg); - if DoneMessageEnabled then - ShowDoneMessage(DoneMessage); - - if AutoRestart then + if Config.DoneAudioEnabled then + PlayAudio(Config.DoneAudio, Config.LoopAudio); + if Config.DoneAppEnabled then + RunApp(Config.DoneApp); + if Config.DoneTrayMsgEnabled then + ShowTrayMessage(Config.DoneTrayMsg); + if Config.DoneMessageEnabled then + ShowDoneMessage(Config.DoneMessage); + + if Config.AutoRestart then ToggleCountdown(Sender) else TrayIconMain.Icon := ImgIconDone.Picture.Icon; @@ -593,36 +446,16 @@ procedure TMainForm.ShowAbout(Sender: TObject); procedure TMainForm.OnDestroyForm(Sender: TObject); begin - if AutoSave then + if GetConfig.AutoSave then SaveSettings(Sender); end; procedure TMainForm.OnShowForm(Sender: TObject); -var - //w: integer; - //h: integer; - wRect: TRect; - //cRect: TRect; - flags: integer; - -begin - Self.Position := poDesigned; - WndHandle := GetHandle(); - GetWindowRect(WndHandle, wRect); - flags := SWP_SHOWWINDOW; - - case WndPosition of - Remember: SetWindowPos(WndHandle, HWND_TOP, WndLeft, WndTop, WndWidth, WndHeight, flags); - TopLeft: SetWindowPos(WndHandle, HWND_TOP, 0, 0, WndWidth, WndHeight, flags); - TopRight: SetWindowPos(WndHandle, HWND_TOP, Monitor.WorkareaRect.Right - WndWidth, 0, WndWidth, WndHeight, flags); - BottomLeft: SetWindowPos(WndHandle, HWND_TOP, 0, Monitor.WorkareaRect.Bottom - WndHeight, WndWidth, WndHeight, flags); - BottomRight: SetWindowPos(WndHandle, HWND_TOP, Monitor.WorkareaRect.Right - WndWidth, - Monitor.WorkareaRect.Bottom - WndHeight, WndWidth, WndHeight, flags); - Center: - begin - SetWindowPos(WndHandle, HWND_TOP, 0, 0, WndWidth, WndHeight, SWP_SHOWWINDOW or SWP_NOMOVE); - Self.Position := poScreenCenter; - end; +begin + if OnShowFormFirstTime then + begin + OnShowFormFirstTime:= False; + ApplyConfig(True); end; // TODO Get this working for window size (getpreferred size gets form, not window) @@ -662,56 +495,23 @@ procedure TMainForm.OnShowForm(Sender: TObject); //exit; end; - UpdateAlwaysOnTop(AlwaysOnTop); + //UpdateAlwaysOnTop(AlwaysOnTop); end; procedure TMainForm.SaveSettings(Sender: TObject); var + Config: TConfig; wRect: TRect; begin - try - IniFile := TIniFile.Create(IniFilename); - IniFile.CacheUpdates := True; - IniFile.WriteInteger(INI_SEC_MAIN, INI_MINUTES, Minutes.Value); - IniFile.WriteBool(INI_SEC_MAIN, INI_ALWAYS_ON_TOP, AlwaysOnTop); - IniFile.WriteBool(INI_SEC_MAIN, INI_MIN_TO_TRAY, MinToTray); - IniFile.WriteBool(INI_SEC_MAIN, INI_AUTOSTART, AutoStart); - IniFile.WriteBool(INI_SEC_MAIN, INI_HIDESECONDS, HideSeconds); - IniFile.WriteBool(INI_SEC_MAIN, INI_CLICKTIME, ClickTime); - IniFile.WriteBool(INI_SEC_MAIN, INI_DBLCLICKTIME, DblClickTime); - IniFile.WriteBool(INI_SEC_MAIN, INI_AUTORESTART, AutoRestart); - IniFile.WriteBool(INI_SEC_MAIN, INI_LOOP_AUDIO, LoopAudio); - IniFile.WriteBool(INI_SEC_MAIN, INI_TICKING_ON, TickingOn); - IniFile.WriteBool(INI_SEC_MAIN, INI_AUTOSAVE, AutoSave); - IniFile.WriteBool(INI_SEC_MAIN, INI_SECONDS_MODE, SecondsMode); - - GetWindowRect(GetHandle(), wRect); - - IniFile.WriteInteger(INI_SEC_PLACEMENT, INI_HEIGHT, wRect.Bottom - wRect.Top); - IniFile.WriteInteger(INI_SEC_PLACEMENT, INI_WIDTH, wRect.Right - wRect.Left); - IniFile.WriteInteger(INI_SEC_PLACEMENT, INI_LEFT, wRect.Left); - IniFile.WriteInteger(INI_SEC_PLACEMENT, INI_TOP, wRect.Top); - IniFile.WriteInteger(INI_SEC_PLACEMENT, INI_POSITION, Ord(WndPosition)); - - IniFile.WriteString(INI_SEC_ALARMS, INI_DONE_MESSAGE, DoneMessage); - IniFile.WriteBool(INI_SEC_ALARMS, INI_DONE_MESSAGE_ON, DoneMessageEnabled); - IniFile.WriteString(INI_SEC_ALARMS, INI_DONE_TRAY_MESSAGE, DoneTrayMsg); - IniFile.WriteBool(INI_SEC_ALARMS, INI_DONE_TRAY_MESSAGE_ON, DoneTrayMsgEnabled); - IniFile.WriteString(INI_SEC_ALARMS, INI_DONE_AUDIO, DoneAudio); - IniFile.WriteBool(INI_SEC_ALARMS, INI_DONE_AUDIO_ON, DoneAudioEnabled); - IniFile.WriteString(INI_SEC_ALARMS, INI_DONE_APP, DoneApp); - IniFile.WriteBool(INI_SEC_ALARMS, INI_DONE_APP_ON, DoneAppEnabled); - - IniFile.WriteString(INI_SEC_FONTS, INI_FONT_NAME, Count.Font.Name); - IniFile.WriteInteger(INI_SEC_FONTS, INI_FONT_CHARSET, Count.Font.CharSet); - IniFile.WriteInteger(INI_SEC_FONTS, INI_FONT_COLOR, Count.Font.Color); - IniFile.WriteInteger(INI_SEC_FONTS, INI_FONT_SIZE, Count.Font.Size); - IniFile.WriteInteger(INI_SEC_FONTS, INI_FONT_STYLE, FontStylesToInt(Count.Font)); - IniFile.WriteInteger(INI_SEC_FONTS, INI_BG_COLOR, Count.Color); - IniFile.UpdateFile; - except + Config:= GetConfig; + GetWindowRect(self.Handle, wRect); + Config.WndWidth:= wRect.Right - wRect.Left; + Config.WndHeight:= wRect.Bottom - wRect.Top; + Config.WndLeft:= wRect.Left; + Config.WndTop:= wRect.Top; + + if Config.Save = False then MessageDlg(MSG_WRITE_INI, mtError, [mbOK], 0); - end; end; procedure TMainForm.MinutesChanged(Sender: TObject); @@ -722,8 +522,9 @@ procedure TMainForm.MinutesChanged(Sender: TObject); procedure TMainForm.ToggleCompact(Sender: TObject); begin - SetFieldsVisible(CompactMode); - CompactMode := not CompactMode; + // todo +// SetFieldsVisible(GetConfig.CompactMode); +// CompactMode := not CompactMode; end; // TODO Figure out how to remove the fields from the form so they don't @@ -760,7 +561,7 @@ function TMainForm.SecondsToTime(Seconds: integer): string; h := Seconds div 3600; m := Seconds div 60 - h * 60; s := Seconds - (h * 3600 + m * 60); - if HideSeconds then + if GetConfig.HideSeconds then begin Result := SysUtils.Format('%.2d:%.2d', [h, m]); end @@ -803,7 +604,7 @@ procedure TMainForm.UpdateTime(); procedure TMainForm.FormWindowStateChange(Sender: TObject); begin - if not MinToTray then + if not GetConfig.MinToTray then Exit; if WindowState = wsMinimized then @@ -845,7 +646,8 @@ procedure TMainForm.StopAudio(); procedure TMainForm.PlayTicking(); begin - sndPlaySound(PChar(GetFilePath(DEF_TICKING_PATH)), SND_NODEFAULT or + // TODO replace hard-coded path with Config + sndPlaySound(PChar(GetFilePath('.\sounds\ticking\ticking.wav')), SND_NODEFAULT or SND_ASYNC or SND_LOOP); end; @@ -867,60 +669,15 @@ procedure TMainForm.ShowTrayMessage(Msg: string); procedure TMainForm.ShowDoneMessage(Msg: string); begin // http://msdn.microsoft.com/en-us/library/ms645505(VS.85).aspx - Windows.MessageBox(GetHandle(), pChar(msg), 'Done', + Windows.MessageBox(self.Handle, pChar(msg), 'Done', MB_SYSTEMMODAL or MB_SETFOREGROUND or MB_TOPMOST or MB_ICONINFORMATION); StopAudio(); end; -function TMainForm.GetHandle(): HWND; +{function TMainForm.GetHandle(): HWND; begin Result := Application.MainForm.Handle; -end; - -procedure TMainForm.SetDefaults(Sender: TObject); -begin - with Sender as TOptionsForm do - BgColor.ButtonColor := DEF_BG_COLOR; - f.Name := DEF_FONT_NAME; - f.Color := DEF_FONT_COLOR; - f.CharSet := DEF_FONT_CHARSET; - f.Size := DEF_FONT_SIZE; - f.Style := IntToFontStyles(DEF_FONT_STYLE); -end; - -function TMainForm.FontStylesToInt(Fnt: TFont): integer; -var - Mask: integer; - Style: TFontStyle; -begin - // Translate the set into a bit mask - Mask := 0; - for Style := Low(TFontStyle) to High(TFontStyle) do - if Style in Fnt.Style then - Mask := Mask or (1 shl Ord(Style)); - Result := Mask; -end; - -function TMainForm.IntToFontStyles(Mask: integer): TFontStyles; -var - i: integer; - StyleSet: TFontStyles; -begin - // Translate the bit mask into a set - StyleSet := []; - for i := 0 to Ord(High(TFontStyle)) do - if Mask and (1 shl i) <> 0 then - StyleSet := StyleSet + [TFontStyle(i)]; - Result := StyleSet; -end; - -procedure TMainForm.UpdateAlwaysOnTop(onTop: boolean); -begin - if onTop then - FormStyle:= fsSystemStayOnTop - else - FormStyle:= fsNormal -end; +end;} procedure TMainForm.FormActivate(Sender: TObject); begin @@ -942,7 +699,7 @@ function TMainForm.IsInteger(S: String): boolean; // TODO Only update the time if this value changed (otherwise it resets // the time every time you modify settings) // It's not working - test it thoroughly and fix it. -procedure TMainForm.UpdateTimeCaption(newSecondsMode: boolean); +{procedure TMainForm.UpdateTimeCaption(newSecondsMode: boolean); begin if newSecondsMode <> SecondsMode then begin @@ -953,6 +710,55 @@ procedure TMainForm.UpdateTimeCaption(newSecondsMode: boolean); SetTimer(); end; +end; } + + +procedure TMainForm.ApplyConfig(APosition: Boolean); +var + wRect: TRect; + flags: Integer; + Config: TConfig; +begin + Config:= GetConfig; + if Config.AlwaysOnTop then + FormStyle:= fsSystemStayOnTop + else + FormStyle:= fsNormal; + + if Config.SecondsMode then + TimeLabel.Caption := LBL_SECONDS + else + TimeLabel.Caption := LBL_MINUTES; + + Count.Font.Quality := fqAntialiased; + Count.Font.Name := Config.Font.Name; + Count.Font.CharSet := Config.Font.Charset; + Count.Font.Color := Config.Font.Color; + Count.Font.Size := Config.Font.Size; + Count.Font.Style := Config.Font.Style; + Count.Color := Config.Font.BgColor; + + if APosition then + begin + Self.Position := poDesigned; + WndHandle := self.Handle; + GetWindowRect(WndHandle, wRect); + flags := SWP_SHOWWINDOW; + + case Config.WndPosition of + Remember: SetWindowPos(WndHandle, HWND_TOP, Config.WndLeft, Config.WndTop, Config.WndWidth, Config.WndHeight, flags); + TopLeft: SetWindowPos(WndHandle, HWND_TOP, 0, 0, Config.WndWidth, Config.WndHeight, flags); + TopRight: SetWindowPos(WndHandle, HWND_TOP, Monitor.WorkareaRect.Right - Config.WndWidth, 0, Config.WndWidth, Config.WndHeight, flags); + BottomLeft: SetWindowPos(WndHandle, HWND_TOP, 0, Monitor.WorkareaRect.Bottom - Config.WndHeight, Config.WndWidth, Config.WndHeight, flags); + BottomRight: SetWindowPos(WndHandle, HWND_TOP, Monitor.WorkareaRect.Right - Config.WndWidth, + Monitor.WorkareaRect.Bottom - Config.WndHeight, Config.WndWidth, Config.WndHeight, flags); + Center: + begin + SetWindowPos(WndHandle, HWND_TOP, 0, 0, Config.WndWidth, Config.WndHeight, SWP_SHOWWINDOW or SWP_NOMOVE); + Self.Position := poScreenCenter; + end; + end; + end; end; initialization diff --git a/ui/options.lfm b/ui/options.lfm index 2cf15ee..63bd39e 100644 --- a/ui/options.lfm +++ b/ui/options.lfm @@ -465,7 +465,7 @@ object OptionsForm: TOptionsForm Top = 201 Width = 112 Caption = '&Defaults' - OnClick = SetDefaults + OnClick = SetFontDefaults ParentFont = False ParentShowHint = False ShowHint = True diff --git a/ui/options.pas b/ui/options.pas index 5d8ff1e..e90c343 100644 --- a/ui/options.pas +++ b/ui/options.pas @@ -5,7 +5,7 @@ interface uses - SysUtils, LResources, Forms, Graphics, Dialogs, StdCtrls, ComCtrls, Spin; + SysUtils, LResources, Forms, Graphics, Dialogs, StdCtrls, ComCtrls, Spin, Classes; type @@ -62,7 +62,7 @@ TOptionsForm = class(TForm) procedure GetAppFile(Sender: TObject); function GetFile(Orig: String; FilterStr: String; Dir : String): String; procedure EnableFields(Sender: TObject); - procedure SetDefaults(Sender: TObject); + procedure SetFontDefaults(Sender: TObject); procedure TestAudio(Sender: TObject); procedure TestMessage(Sender: TObject); procedure TestRunApp(Sender: TObject); @@ -71,17 +71,17 @@ TOptionsForm = class(TForm) procedure UpdateFonts(Sender: TObject); procedure UpdateFontSize(Sender: TObject); private - { private declarations } public { public declarations } end; var OptionsForm: TOptionsForm; - f: TFont; + f: TFont; // TODO make private implementation -uses MainForm1; + +uses MainForm1, Config; { TOptionsForm } // TODO Move all text strings to the top @@ -98,9 +98,9 @@ procedure TOptionsForm.FormKeyPress(Sender: TObject; var Key: char); procedure TOptionsForm.ChooseFont(Sender: TObject); var - dlg : TFontDialog; + dlg : TFontDialog; begin - dlg := TFontDialog.Create(nil); + dlg := TFontDialog.Create(nil); dlg.Font := f; if dlg.Execute then @@ -118,6 +118,7 @@ procedure TOptionsForm.ChooseFont(Sender: TObject); dlg.Free; end; + procedure TOptionsForm.UpdateFonts(Sender: TObject); begin FontName.Caption := f.Name + ' : 1234567890'; @@ -159,9 +160,10 @@ function TOptionsForm.GetFile(Orig: String; FilterStr: String; Dir : String): St begin dlg := TOpenDialog.Create(nil); dlg.FileName := ''; - if DirectoryExists(Dir) - then dlg.InitialDir := Dir - else dlg.InitialDir := GetCurrentDir; + if DirectoryExists(Dir) then + dlg.InitialDir := Dir + else + dlg.InitialDir := GetCurrentDir; dlg.Options := [ofFileMustExist]; dlg.Filter := FilterStr; dlg.FilterIndex := 1; @@ -180,7 +182,7 @@ function TOptionsForm.GetFile(Orig: String; FilterStr: String; Dir : String): St procedure TOptionsForm.EnableFields(Sender: TObject); begin - NotifyMsg.Enabled := NotifyMsgOn.Checked; + NotifyMsg.Enabled := NotifyMsgOn.Checked; NotifyMsgTest.Enabled := NotifyMsgOn.Checked; NotifyTrayMsg.Enabled := NotifyTrayMsgOn.Checked; NotifyTrayMsgTest.Enabled := NotifyTrayMsgOn.Checked; @@ -194,9 +196,18 @@ procedure TOptionsForm.EnableFields(Sender: TObject); NotifyRunTest.Enabled := NotifyRunAppOn.Checked; end; -procedure TOptionsForm.SetDefaults(Sender: TObject); + +procedure TOptionsForm.SetFontDefaults(Sender: TObject); +var + Cfg : TFontConfig; begin - (Self.Owner as TMainForm).SetDefaults(Self); + Cfg:= GetConfig.GetDefaultFont; + BgColor.ButtonColor:= Cfg.BgColor; + f.Name:= Cfg.Name; + f.Color:= Cfg.Color; + f.CharSet:= Cfg.Charset; + f.Size:= Cfg.Size; + f.Style:= Cfg.Style; UpdateFonts(Sender); end; From 549a8074e3605542c541078526f692e724986b91 Mon Sep 17 00:00:00 2001 From: neo85 Date: Tue, 16 Feb 2021 17:36:57 +0100 Subject: [PATCH 4/8] OptionsForm rewrite --- snaptimer.lps | 191 +++++++++++++----------- ui/mainform1.pas | 219 ++++++++------------------- ui/options.lfm | 376 +++++++++++++++++++++++------------------------ ui/options.pas | 212 +++++++++++++++++++------- 4 files changed, 507 insertions(+), 491 deletions(-) diff --git a/snaptimer.lps b/snaptimer.lps index dca158c..2286cdb 100644 --- a/snaptimer.lps +++ b/snaptimer.lps @@ -4,12 +4,12 @@ - + - - + + @@ -17,9 +17,9 @@ - + - + @@ -30,7 +30,7 @@ - + @@ -39,10 +39,10 @@ - - - - + + + + @@ -54,21 +54,21 @@ - - - - + + + + + - - - - - + + + + @@ -76,7 +76,7 @@ - + @@ -84,14 +84,14 @@ - + - + @@ -100,7 +100,7 @@ - + @@ -108,180 +108,197 @@ - + - + - - - + + + - - + + - + - - + - + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - + - + - - + + - - - - diff --git a/ui/mainform1.pas b/ui/mainform1.pas index 8e36127..0871ca4 100644 --- a/ui/mainform1.pas +++ b/ui/mainform1.pas @@ -74,16 +74,12 @@ TMainForm = class(TForm) procedure RunApp(Path: string); procedure ShowDoneMessage(Msg: string); procedure ShowTrayMessage(Msg: string); - //f GetHandle(): HWND; procedure SetFieldsVisible(showFields: boolean); procedure PlayTicking(); function IsInteger(S: String): boolean; - //procedure UpdateTimeCaption(newSecondsMode: boolean); private { private declarations } AudioPlaying: boolean; - WndHandle: HWND; - WndPositions: TStrings; Mode: TMode; FontSizeChanged : boolean; //FormerWidth : integer; @@ -92,7 +88,7 @@ TMainForm = class(TForm) StartTime: TDateTime; CountdownDone: boolean; OnShowFormFirstTime: Boolean; - procedure ApplyConfig(APosition: Boolean); + procedure ApplyConfig; public { public declarations } end; @@ -158,15 +154,6 @@ procedure TMainForm.OnCreateForm(Sender: TObject); // Set all defaults, then load from .ini - - WndPositions := TStringList.Create; - WndPositions.Add('Centered'); - WndPositions.Add('Remember position'); - WndPositions.Add('Top left'); - WndPositions.Add('Top right'); - WndPositions.Add('Bottom left'); - WndPositions.Add('Bottom right'); - Mode := Timer; AudioPlaying := False; Self.DoubleBuffered := True; @@ -198,6 +185,7 @@ procedure TMainForm.OnCreateForm(Sender: TObject); MessageDlg(MSG_OPEN_INI, mtError, [mbOK], 0); Exit; end; + Minutes.Value:= Config.Minutes; // Use minutes argument if it's the only parameter and it's numeric if (ParamCount = 1) and (IsInteger(ParamStr(1))) then @@ -255,111 +243,47 @@ procedure TMainForm.SetTimer(); procedure TMainForm.ShowOptions(Sender: TObject); var Config: TConfig; + Ok: Boolean; + r: TRect; begin - Config:= GetConfig; - // TODO move this to TOptionsForm OptionsForm := TOptionsForm.Create(Self); - with OptionsForm do + Ok:= OptionsForm.ShowModal = mrOk; + OptionsForm.Free; + + if Ok then begin - NotifyMsg.Text:= Config.DoneMessage; - NotifyMsgOn.Checked:= Config.DoneMessageEnabled; - - NotifyTrayMsg.Text:= Config.DoneTrayMsg; - NotifyTrayMsgOn.Checked:= Config.DoneTrayMsgEnabled; - - NotifyAudio.Text:= Config.DoneAudio; - NotifyAudioOn.Checked:= Config.DoneAudioEnabled; - - NotifyRunApp.Text:= Config.DoneApp; - NotifyRunAppOn.Checked:= Config.DoneAppEnabled; - - CheckAlwaysOnTop.Checked:= Config.AlwaysOnTop; - CheckMinToTray.Checked:= Config.MinToTray; - CheckAutostart.Checked:= Config.AutoStart; - CheckHideSeconds.Checked:= Config.HideSeconds; - CheckClicktime.Checked:= Config.ClickTime; - CheckDblClickTime.Checked:= Config.DblClickTime; - CheckAutoRestart.Checked:= Config.AutoRestart; - CheckLoopAudio.Checked:= Config.LoopAudio; - CheckTicking.Checked:= Config.TickingOn; - CheckAutoSave.Checked:= Config.AutoSave; - CheckSecondsMode.Checked:= Config.SecondsMode; - - PositionCombo.Items := WndPositions; - PositionCombo.ItemIndex := Ord(Config.WndPosition); - - PageControl1.TabIndex := 0; - - f := TFont.Create; - f.Name := Count.Font.Name; - f.Size := Count.Font.Size; - f.CharSet := Count.Font.CharSet; - f.Color := Count.Font.Color; - f.Style := Count.Font.Style; - BgColor.ButtonColor := Count.Color; - FontSizeChanged := False; - - if ShowModal = mrOk then + Config:= GetConfig; + GetWindowRect(MainForm.Handle, r); + Config.WndLeft:= r.Left; + Config.WndTop:= r.Top; + Config.WndWidth:= r.Right - r. Left; + Config.WndHeight:= r.Bottom - r.Top; + ApplyConfig; + + //if not (Count.Font.Size = f.Size) then + //begin + //FontSizeChanged := True; + //GetPreferredSize(FormerWidth, FormerHeight, True); + //ShowMessageFmt('width: %d, height: %d', [FormerWidth, FormerHeight]); + //end; + //Count.Font := f; + // TODO Get font colors and background color to be shown - what's up? + + //if FontSizeChanged then OnShowForm(Sender); + if Timer1.Enabled then begin - // replace with ApplyConig(False) - //UpdateTimeCaption(CheckSecondsMode.Checked); - - Config.DoneMessage:= NotifyMsg.Text; - Config.DoneMessageEnabled:= NotifyMsgOn.Checked; - Config.DoneTrayMsg:= NotifyTrayMsg.Text; - Config.DoneTrayMsgEnabled:= NotifyTrayMsgOn.Checked; - Config.DoneAudio:= NotifyAudio.Text; - Config.DoneAudioEnabled:= NotifyAudioOn.Checked; - Config.DoneApp:= NotifyRunApp.Text; - Config.DoneAppEnabled:= NotifyRunAppOn.Checked; - Config.AlwaysOnTop:= CheckAlwaysOnTop.Checked; - Config.MinToTray:= CheckMinToTray.Checked; - Config.AutoStart:= CheckAutostart.Checked; - Config.HideSeconds:= CheckHideSeconds.Checked; - Config.ClickTime:= CheckClicktime.Checked; - Config.DblClickTime:= CheckDblClickTime.Checked; - Config.AutoRestart:= CheckAutoRestart.Checked; - Config.LoopAudio:= CheckLoopAudio.Checked; - Config.TickingOn:= CheckTicking.Checked; - Config.AutoSave:= CheckAutoSave.Checked; - Config.SecondsMode:= CheckSecondsMode.Checked; - Config.WndPosition:= TPosition(PositionCombo.ItemIndex); - //if not (Count.Font.Size = f.Size) then - //begin - //FontSizeChanged := True; - //GetPreferredSize(FormerWidth, FormerHeight, True); - //ShowMessageFmt('width: %d, height: %d', [FormerWidth, FormerHeight]); - //end; - //Count.Font := f; - // TODO Get font colors and background color to be shown - what's up? - Count.Font.Name := f.Name; - Count.Font.Size := f.Size; - Count.Font.CharSet := f.CharSet; - Count.Font.Color := f.Color; - Count.Font.Style := f.Style; - Count.Font.Quality := fqAntialiased; - Count.Color := BgColor.ButtonColor; - - //if FontSizeChanged then OnShowForm(Sender); - - //UpdateAlwaysOnTop(AlwaysOnTop); - - if Timer1.Enabled then - begin - if Config.TickingOn then - PlayTicking - else - StopAudio(); - end; - - if Config.AutoSave then - SaveSettings(Sender); - // TODO Resize the window if necessary to accomodate larger text - // Get the text size from the font for '00:00:00'? - + if Config.TickingOn then + PlayTicking + else + StopAudio(); end; + + if Config.AutoSave then + SaveSettings(Sender); + // TODO Resize the window if necessary to accomodate larger text + // Get the text size from the font for '00:00:00'? + end; - OptionsForm.Free; end; procedure TMainForm.ToggleCountdown(Sender: TObject); @@ -455,7 +379,7 @@ procedure TMainForm.OnShowForm(Sender: TObject); if OnShowFormFirstTime then begin OnShowFormFirstTime:= False; - ApplyConfig(True); + ApplyConfig; end; // TODO Get this working for window size (getpreferred size gets form, not window) @@ -504,6 +428,9 @@ procedure TMainForm.SaveSettings(Sender: TObject); wRect: TRect; begin Config:= GetConfig; + + // These config values are not set in OptionsForm. + Config.Minutes:= Minutes.Value; GetWindowRect(self.Handle, wRect); Config.WndWidth:= wRect.Right - wRect.Left; Config.WndHeight:= wRect.Bottom - wRect.Top; @@ -646,7 +573,6 @@ procedure TMainForm.StopAudio(); procedure TMainForm.PlayTicking(); begin - // TODO replace hard-coded path with Config sndPlaySound(PChar(GetFilePath('.\sounds\ticking\ticking.wav')), SND_NODEFAULT or SND_ASYNC or SND_LOOP); end; @@ -674,11 +600,6 @@ procedure TMainForm.ShowDoneMessage(Msg: string); StopAudio(); end; -{function TMainForm.GetHandle(): HWND; -begin - Result := Application.MainForm.Handle; -end;} - procedure TMainForm.FormActivate(Sender: TObject); begin WindowState := wsNormal; @@ -696,28 +617,11 @@ function TMainForm.IsInteger(S: String): boolean; end; end; -// TODO Only update the time if this value changed (otherwise it resets -// the time every time you modify settings) -// It's not working - test it thoroughly and fix it. -{procedure TMainForm.UpdateTimeCaption(newSecondsMode: boolean); -begin - if newSecondsMode <> SecondsMode then - begin - if newSecondsMode then - TimeLabel.Caption := LBL_SECONDS - else - TimeLabel.Caption := LBL_MINUTES; - SetTimer(); - end; - -end; } - - -procedure TMainForm.ApplyConfig(APosition: Boolean); +procedure TMainForm.ApplyConfig; var - wRect: TRect; - flags: Integer; Config: TConfig; + WndHandle: HWND; + flags: Integer; begin Config:= GetConfig; if Config.AlwaysOnTop then @@ -738,26 +642,21 @@ procedure TMainForm.ApplyConfig(APosition: Boolean); Count.Font.Style := Config.Font.Style; Count.Color := Config.Font.BgColor; - if APosition then - begin - Self.Position := poDesigned; - WndHandle := self.Handle; - GetWindowRect(WndHandle, wRect); - flags := SWP_SHOWWINDOW; - - case Config.WndPosition of - Remember: SetWindowPos(WndHandle, HWND_TOP, Config.WndLeft, Config.WndTop, Config.WndWidth, Config.WndHeight, flags); - TopLeft: SetWindowPos(WndHandle, HWND_TOP, 0, 0, Config.WndWidth, Config.WndHeight, flags); - TopRight: SetWindowPos(WndHandle, HWND_TOP, Monitor.WorkareaRect.Right - Config.WndWidth, 0, Config.WndWidth, Config.WndHeight, flags); - BottomLeft: SetWindowPos(WndHandle, HWND_TOP, 0, Monitor.WorkareaRect.Bottom - Config.WndHeight, Config.WndWidth, Config.WndHeight, flags); - BottomRight: SetWindowPos(WndHandle, HWND_TOP, Monitor.WorkareaRect.Right - Config.WndWidth, - Monitor.WorkareaRect.Bottom - Config.WndHeight, Config.WndWidth, Config.WndHeight, flags); - Center: - begin - SetWindowPos(WndHandle, HWND_TOP, 0, 0, Config.WndWidth, Config.WndHeight, SWP_SHOWWINDOW or SWP_NOMOVE); - Self.Position := poScreenCenter; - end; - end; + WndHandle:= self.Handle; + Self.Position := poDesigned; + flags:= SWP_SHOWWINDOW; + case Config.WndPosition of + Remember: SetWindowPos(WndHandle, HWND_TOP, Config.WndLeft, Config.WndTop, Config.WndWidth, Config.WndHeight, flags); + TopLeft: SetWindowPos(WndHandle, HWND_TOP, 0, 0, Config.WndWidth, Config.WndHeight, flags); + TopRight: SetWindowPos(WndHandle, HWND_TOP, Monitor.WorkareaRect.Right - Config.WndWidth, 0, Config.WndWidth, Config.WndHeight, flags); + BottomLeft: SetWindowPos(WndHandle, HWND_TOP, 0, Monitor.WorkareaRect.Bottom - Config.WndHeight, Config.WndWidth, Config.WndHeight, flags); + BottomRight: SetWindowPos(WndHandle, HWND_TOP, Monitor.WorkareaRect.Right - Config.WndWidth, + Monitor.WorkareaRect.Bottom - Config.WndHeight, Config.WndWidth, Config.WndHeight, flags); + Center: + begin + SetWindowPos(WndHandle, HWND_TOP, 0, 0, Config.WndWidth, Config.WndHeight, SWP_SHOWWINDOW or SWP_NOMOVE); + Self.Position := poScreenCenter; + end; end; end; diff --git a/ui/options.lfm b/ui/options.lfm index 63bd39e..9caaea3 100644 --- a/ui/options.lfm +++ b/ui/options.lfm @@ -1,25 +1,25 @@ object OptionsForm: TOptionsForm Left = 465 - Height = 351 + Height = 234 Top = 319 - Width = 825 + Width = 550 BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'Options' - ClientHeight = 351 - ClientWidth = 825 - DesignTimePPI = 144 + ClientHeight = 234 + ClientWidth = 550 KeyPreview = True - OnCreate = EnableFields + OnCreate = FormCreate + OnDestroy = FormDestroy OnKeyPress = FormKeyPress Position = poScreenCenter ShowInTaskBar = stNever LCLVersion = '2.0.10.0' object BtnOk: TButton - Left = 576 - Height = 38 - Top = 300 - Width = 112 + Left = 384 + Height = 25 + Top = 200 + Width = 75 Caption = '&OK' Default = True ModalResult = 1 @@ -27,10 +27,10 @@ object OptionsForm: TOptionsForm TabOrder = 1 end object BtnCancel: TButton - Left = 696 - Height = 38 - Top = 300 - Width = 112 + Left = 464 + Height = 25 + Top = 200 + Width = 75 Caption = '&Cancel' ModalResult = 2 ParentFont = False @@ -38,24 +38,24 @@ object OptionsForm: TOptionsForm end object PageControl1: TPageControl Left = 0 - Height = 288 + Height = 192 Top = 0 - Width = 828 - ActivePage = GeneralTab + Width = 552 + ActivePage = FontsTab ParentFont = False - TabIndex = 0 + TabIndex = 2 TabOrder = 0 object GeneralTab: TTabSheet Caption = 'General' - ClientHeight = 250 - ClientWidth = 820 + ClientHeight = 164 + ClientWidth = 544 ParentFont = False object CheckAutostart: TCheckBox - Left = 256 - Height = 29 + Left = 171 + Height = 19 Hint = 'Begin counting down when the application starts' - Top = 111 - Width = 150 + Top = 74 + Width = 100 Caption = '&Autostart timer' ParentFont = False ParentShowHint = False @@ -63,11 +63,11 @@ object OptionsForm: TOptionsForm TabOrder = 4 end object CheckMinToTray: TCheckBox - Left = 18 - Height = 29 + Left = 12 + Height = 19 Hint = 'Don''t show the application in the taskbar when minimized' - Top = 159 - Width = 158 + Top = 106 + Width = 106 Caption = '&Minimize to tray' ParentFont = False ParentShowHint = False @@ -75,23 +75,23 @@ object OptionsForm: TOptionsForm TabOrder = 2 end object GroupBox2: TGroupBox - Left = 6 - Height = 72 - Top = 19 - Width = 240 + Left = 4 + Height = 48 + Top = 13 + Width = 160 Caption = 'Starting position' - ClientHeight = 42 - ClientWidth = 236 + ClientHeight = 28 + ClientWidth = 156 ParentFont = False TabOrder = 0 object PositionCombo: TComboBox - Left = 9 - Height = 33 + Left = 6 + Height = 23 Hint = 'Where to place the application window when it starts' - Top = 3 - Width = 216 + Top = 2 + Width = 144 DropDownCount = 6 - ItemHeight = 25 + ItemHeight = 15 ParentFont = False ParentShowHint = False ShowHint = True @@ -100,11 +100,11 @@ object OptionsForm: TOptionsForm end end object CheckClickTime: TCheckBox - Left = 256 - Height = 29 + Left = 171 + Height = 19 Hint = 'Click the timer numerals to start/pause the timer' - Top = 159 - Width = 168 + Top = 106 + Width = 113 Caption = 'Cl&ick time to start' ParentFont = False ParentShowHint = False @@ -112,11 +112,11 @@ object OptionsForm: TOptionsForm TabOrder = 5 end object CheckDblClickTime: TCheckBox - Left = 256 - Height = 29 + Left = 171 + Height = 19 Hint = 'Double-click the timer numerals to reset the timer' - Top = 207 - Width = 233 + Top = 138 + Width = 156 Caption = '&Double-click time to reset' ParentFont = False ParentShowHint = False @@ -124,11 +124,11 @@ object OptionsForm: TOptionsForm TabOrder = 6 end object CheckAutoRestart: TCheckBox - Left = 522 - Height = 29 + Left = 348 + Height = 19 Hint = 'Start the timer again when the time reaches zero' - Top = 111 - Width = 239 + Top = 74 + Width = 161 Caption = 'Automatically &restart timer' ParentFont = False ParentShowHint = False @@ -136,11 +136,11 @@ object OptionsForm: TOptionsForm TabOrder = 8 end object CheckLoopAudio: TCheckBox - Left = 522 - Height = 29 + Left = 348 + Height = 19 Hint = 'Continue playing the audio file until timer is reset' - Top = 159 - Width = 170 + Top = 106 + Width = 113 Caption = '&Loop audio alarm' ParentFont = False ParentShowHint = False @@ -148,11 +148,11 @@ object OptionsForm: TOptionsForm TabOrder = 9 end object CheckAutoSave: TCheckBox - Left = 18 - Height = 29 + Left = 12 + Height = 19 Hint = 'Automatically save settings to the .ini file on exit' - Top = 207 - Width = 171 + Top = 138 + Width = 113 Caption = 'Auto&save settings' ParentFont = False ParentShowHint = False @@ -160,11 +160,11 @@ object OptionsForm: TOptionsForm TabOrder = 3 end object CheckAlwaysOnTop: TCheckBox - Left = 18 - Height = 29 + Left = 12 + Height = 19 Hint = 'Show the window even when it''s deactivated' - Top = 111 - Width = 144 + Top = 74 + Width = 95 Caption = 'Al&ways on top' ParentFont = False ParentShowHint = False @@ -172,11 +172,11 @@ object OptionsForm: TOptionsForm TabOrder = 1 end object CheckTicking: TCheckBox - Left = 522 - Height = 29 + Left = 348 + Height = 19 Hint = 'Play a ticking sound when timer is running' - Top = 204 - Width = 174 + Top = 136 + Width = 117 Caption = '&Play ticking sound' ParentFont = False ParentShowHint = False @@ -184,11 +184,11 @@ object OptionsForm: TOptionsForm TabOrder = 10 end object CheckSecondsMode: TCheckBox - Left = 522 - Height = 29 + Left = 348 + Height = 19 Hint = 'Enter seconds instead of minutes' - Top = 62 - Width = 204 + Top = 41 + Width = 135 Caption = '&Enable seconds mode' ParentFont = False ParentShowHint = False @@ -196,11 +196,11 @@ object OptionsForm: TOptionsForm TabOrder = 7 end object CheckHideSeconds: TCheckBox - Left = 256 - Height = 29 + Left = 171 + Height = 19 Hint = 'Begin counting down when the application starts' - Top = 62 - Width = 137 + Top = 41 + Width = 91 Caption = '&Hide seconds' ParentFont = False ParentShowHint = False @@ -210,148 +210,148 @@ object OptionsForm: TOptionsForm end object AlarmsTab: TTabSheet Caption = 'Alarms' - ClientHeight = 166 + ClientHeight = 164 ClientWidth = 544 ParentFont = False object GroupBox1: TGroupBox - Left = 6 - Height = 216 - Top = 15 - Width = 801 + Left = 4 + Height = 144 + Top = 10 + Width = 534 Caption = 'Notification actions' - ClientHeight = 186 - ClientWidth = 797 + ClientHeight = 124 + ClientWidth = 530 ParentFont = False TabOrder = 0 object NotifyRunAppOn: TCheckBox - Left = 8 - Height = 17 - Top = 138 - Width = 84 + Left = 5 + Height = 19 + Top = 92 + Width = 93 Caption = '&Run program:' OnClick = EnableFields ParentFont = False TabOrder = 10 end object NotifyAudioOn: TCheckBox - Left = 8 - Height = 17 - Top = 94 - Width = 88 + Left = 5 + Height = 19 + Top = 63 + Width = 94 Caption = '&Play wave file:' OnClick = EnableFields ParentFont = False TabOrder = 6 end object NotifyTrayMsgOn: TCheckBox - Left = 8 - Height = 17 - Top = 48 - Width = 104 + Left = 5 + Height = 19 + Top = 32 + Width = 113 Caption = '&Show tray popup:' OnClick = EnableFields ParentFont = False TabOrder = 3 end object NotifyMsgOn: TCheckBox - Left = 8 - Height = 17 - Top = 4 - Width = 101 + Left = 5 + Height = 19 + Top = 3 + Width = 110 Caption = '&Display message:' OnClick = EnableFields ParentFont = False TabOrder = 0 end object NotifyTrayMsgTest: TButton - Left = 678 - Height = 38 - Top = 45 - Width = 112 + Left = 452 + Height = 25 + Top = 30 + Width = 75 Caption = 'Test' OnClick = TestTrayMsg ParentFont = False TabOrder = 5 end object NotifyMsgTest: TButton - Left = 678 - Height = 38 - Top = 2 - Width = 112 + Left = 452 + Height = 25 + Top = 1 + Width = 75 Caption = 'Test' OnClick = TestMessage ParentFont = False TabOrder = 2 end object NotifyRunTest: TButton - Left = 678 - Height = 38 - Top = 135 - Width = 112 + Left = 452 + Height = 25 + Top = 90 + Width = 75 Caption = 'Test' OnClick = TestRunApp ParentFont = False TabOrder = 13 end object NotifyAudioTest: TButton - Left = 678 - Height = 38 - Top = 92 - Width = 112 + Left = 452 + Height = 25 + Top = 61 + Width = 75 Caption = 'Test' OnClick = TestAudio ParentFont = False TabOrder = 9 end object NotifyTrayMsg: TEdit - Left = 195 - Height = 21 - Top = 48 - Width = 472 + Left = 130 + Height = 23 + Top = 32 + Width = 315 ParentFont = False TabOrder = 4 end object NotifyRunBtn: TButton - Left = 558 - Height = 38 - Top = 135 - Width = 112 + Left = 372 + Height = 25 + Top = 90 + Width = 75 Caption = 'Browse' OnClick = GetAppFile ParentFont = False TabOrder = 12 end object NotifyRunApp: TEdit - Left = 195 - Height = 21 - Top = 138 - Width = 348 + Left = 130 + Height = 23 + Top = 92 + Width = 232 ParentFont = False TabOrder = 11 end object NotifyAudioBtn: TButton - Left = 558 - Height = 38 - Top = 92 - Width = 112 + Left = 372 + Height = 25 + Top = 61 + Width = 75 Caption = 'Browse' OnClick = GetAudioFile ParentFont = False TabOrder = 8 end object NotifyAudio: TEdit - Left = 195 - Height = 21 - Top = 94 - Width = 348 + Left = 130 + Height = 23 + Top = 63 + Width = 232 ParentFont = False TabOrder = 7 end object NotifyMsg: TEdit - Left = 195 - Height = 21 - Top = 4 - Width = 472 + Left = 130 + Height = 23 + Top = 3 + Width = 315 ParentFont = False TabOrder = 1 end @@ -359,34 +359,33 @@ object OptionsForm: TOptionsForm end object FontsTab: TTabSheet Caption = 'Font' - ClientHeight = 250 - ClientWidth = 820 - OnShow = UpdateFonts + ClientHeight = 164 + ClientWidth = 544 ParentFont = False object TimerFontBox: TGroupBox - Left = 6 - Height = 156 - Top = 15 - Width = 801 + Left = 4 + Height = 104 + Top = 10 + Width = 534 Caption = 'Timer font' - ClientHeight = 126 - ClientWidth = 797 + ClientHeight = 84 + ClientWidth = 530 ParentFont = False TabOrder = 0 object Label1: TLabel - Left = 9 - Height = 25 - Top = 9 - Width = 35 + Left = 6 + Height = 15 + Top = 6 + Width = 23 Caption = 'Size:' ParentColor = False ParentFont = False end object FontColor: TColorButton - Left = 252 - Height = 38 - Top = 2 - Width = 112 + Left = 168 + Height = 25 + Top = 1 + Width = 75 BorderWidth = 2 ButtonColorSize = 16 ButtonColor = clBlack @@ -394,64 +393,65 @@ object OptionsForm: TOptionsForm ParentFont = False end object BgColor: TColorButton - Left = 543 - Height = 38 - Top = 2 - Width = 112 + Left = 362 + Height = 25 + Top = 1 + Width = 75 BorderWidth = 2 ButtonColorSize = 16 ButtonColor = clSilver - OnColorChanged = UpdateFonts + OnColorChanged = UpdateFontBgColor ParentFont = False end object LabelTextColor: TLabel - Left = 189 - Height = 25 - Top = 9 - Width = 47 + Left = 126 + Height = 15 + Top = 6 + Width = 32 Caption = 'Color:' ParentColor = False ParentFont = False end object LabelTextColor1: TLabel - Left = 429 - Height = 25 - Top = 9 - Width = 99 + Left = 286 + Height = 15 + Top = 6 + Width = 67 Caption = 'Background:' ParentColor = False ParentFont = False end object FontSize: TSpinEdit - Left = 69 - Height = 33 - Top = 4 - Width = 70 + Left = 46 + Height = 23 + Top = 3 + Width = 47 MaxValue = 1000 OnChange = UpdateFontSize ParentFont = False TabOrder = 0 end - object FontName: TStaticText - Left = 141 - Height = 41 - Top = 70 - Width = 96 + object FontPreview: TStaticText + Left = 94 + Height = 28 + Top = 47 + Width = 66 Alignment = taCenter AutoSize = True - BorderSpacing.InnerBorder = 4 + BorderSpacing.InnerBorder = 3 Caption = '00:00:00' - Color = clCaptionText - Font.Height = -24 + Color = clDefault + Font.Height = -16 ParentFont = False ParentColor = False TabOrder = 2 + Transparent = False end object FontNameBtn: TButton - Left = 8 - Height = 38 - Top = 72 - Width = 112 + Left = 5 + Height = 25 + Top = 48 + Width = 75 Caption = '&Font...' OnClick = ChooseFont ParentFont = False @@ -459,11 +459,11 @@ object OptionsForm: TOptionsForm end end object BtnDefaults: TButton - Left = 15 - Height = 38 + Left = 10 + Height = 25 Hint = 'Reset font to default settings' - Top = 201 - Width = 112 + Top = 134 + Width = 75 Caption = '&Defaults' OnClick = SetFontDefaults ParentFont = False diff --git a/ui/options.pas b/ui/options.pas index e90c343..70ad474 100644 --- a/ui/options.pas +++ b/ui/options.pas @@ -31,7 +31,7 @@ TOptionsForm = class(TForm) BgColor: TColorButton; FontSize: TSpinEdit; Label1: TLabel; - FontName: TStaticText; + FontPreview: TStaticText; LabelTextColor: TLabel; LabelTextColor1: TLabel; TimerFontBox: TGroupBox; @@ -57,18 +57,20 @@ TOptionsForm = class(TForm) AlarmsTab: TTabSheet; FontsTab: TTabSheet; procedure ChooseFont(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure EnableFields(Sender: TObject); + procedure FormDestroy(Sender: TObject); procedure FormKeyPress(Sender: TObject; var Key: char); procedure GetAudioFile(Sender: TObject); procedure GetAppFile(Sender: TObject); function GetFile(Orig: String; FilterStr: String; Dir : String): String; - procedure EnableFields(Sender: TObject); procedure SetFontDefaults(Sender: TObject); procedure TestAudio(Sender: TObject); procedure TestMessage(Sender: TObject); procedure TestRunApp(Sender: TObject); procedure TestTrayMsg(Sender: TObject); procedure UpdateFontColor(Sender: TObject); - procedure UpdateFonts(Sender: TObject); + procedure UpdateFontBgColor(Sender: TObject); procedure UpdateFontSize(Sender: TObject); private public @@ -77,13 +79,16 @@ TOptionsForm = class(TForm) var OptionsForm: TOptionsForm; - f: TFont; // TODO make private +// f: TFont; // TODO make private implementation -uses MainForm1, Config; +uses Controls, MainForm1, Config; { TOptionsForm } +const + FONT_PREVIEW_FONT_SIZE = 18; + // TODO Move all text strings to the top procedure TOptionsForm.GetAudioFile(Sender: TObject); @@ -101,49 +106,155 @@ procedure TOptionsForm.ChooseFont(Sender: TObject); dlg : TFontDialog; begin dlg := TFontDialog.Create(nil); - dlg.Font := f; - + dlg.Font:= FontPreview.Font; + dlg.Font.Size:= FontSize.Value; if dlg.Execute then begin - f.Name := dlg.Font.Name; - f.Size := dlg.Font.Size; - // TODO Only set color if user changed it (XP dialog doesn't support custom colors) - // Works fine on Win7 - //if not (f.Color = dlg.Font.Color) then f.Color:= dlg.Font.Color; - //f.Color:= dlg.Font.Color; - f.CharSet:= dlg.Font.CharSet; - f.Style:= dlg.Font.Style; - UpdateFonts(Sender); + FontSize.Value:= Dlg.Font.Size; + FontColor.ButtonColor:= Dlg.Font.Color; + FontPreview.Caption:= Dlg.Font.Name + ' : 1234567890'; + FontPreview.Font:= Dlg.Font; + FontPreview.Font.Size:= FONT_PREVIEW_FONT_SIZE; end; dlg.Free; end; +procedure TOptionsForm.FormCreate(Sender: TObject); +var Config: TConfig; + WndPositions: TStrings; +begin + Config:= GetConfig; + + PageControl1.TabIndex := 0; + + // Main + WndPositions := TStringList.Create; + WndPositions.Add('Centered'); + WndPositions.Add('Remember position'); + WndPositions.Add('Top left'); + WndPositions.Add('Top right'); + WndPositions.Add('Bottom left'); + WndPositions.Add('Bottom right'); + PositionCombo.Items := WndPositions; + PositionCombo.ItemIndex := Ord(Config.WndPosition); + + CheckAlwaysOnTop.Checked:= Config.AlwaysOnTop; + CheckMinToTray.Checked:= Config.MinToTray; + CheckAutoSave.Checked:= Config.AutoSave; + + CheckHideSeconds.Checked:= Config.HideSeconds; + CheckAutostart.Checked:= Config.AutoStart; + CheckClicktime.Checked:= Config.ClickTime; + CheckDblClickTime.Checked:= Config.DblClickTime; + + CheckSecondsMode.Checked:= Config.SecondsMode; + CheckAutoRestart.Checked:= Config.AutoRestart; + CheckLoopAudio.Checked:= Config.LoopAudio; + CheckTicking.Checked:= Config.TickingOn; + + // Alarms + NotifyMsg.Text:= Config.DoneMessage; + NotifyMsgOn.Checked:= Config.DoneMessageEnabled; + + NotifyTrayMsg.Text:= Config.DoneTrayMsg; + NotifyTrayMsgOn.Checked:= Config.DoneTrayMsgEnabled; + + NotifyAudio.Text:= Config.DoneAudio; + NotifyAudioOn.Checked:= Config.DoneAudioEnabled; + + NotifyRunApp.Text:= Config.DoneApp; + NotifyRunAppOn.Checked:= Config.DoneAppEnabled; + + // Fonts + FontSize.Value:= Config.Font.Size; + FontColor.ButtonColor:= Config.Font.Color; + BgColor.ButtonColor:= Config.Font.BgColor; + FontPreview.Caption:= Config.Font.Name + ' : 1234567890'; + FontPreview.Font.Name:= Config.Font.Name; + //FontPreview.Font.Size:= Config.Font.Size; // size is fixed + FontPreview.Font.Size:= FONT_PREVIEW_FONT_SIZE; + FontPreview.Font.CharSet:= Config.Font.Charset; + FontPreview.Font.Color:= Config.Font.Color; + FontPreview.Font.Style:= Config.Font.Style; + FontPreview.Color:= Config.Font.BgColor; + + EnableFields(Sender); +end; + +procedure TOptionsForm.FormDestroy(Sender: TObject); +var Config : TConfig; +begin + if ModalResult = mrOk then + begin + // Update Config + Config:= GetConfig; + // Main + Config.AlwaysOnTop:= CheckAlwaysOnTop.Checked; + Config.MinToTray:= CheckMinToTray.Checked; + Config.AutoStart:= CheckAutostart.Checked; + Config.HideSeconds:= CheckHideSeconds.Checked; + Config.ClickTime:= CheckClicktime.Checked; + Config.DblClickTime:= CheckDblClickTime.Checked; + Config.AutoRestart:= CheckAutoRestart.Checked; + Config.LoopAudio:= CheckLoopAudio.Checked; + Config.TickingOn:= CheckTicking.Checked; + Config.AutoSave:= CheckAutoSave.Checked; + Config.SecondsMode:= CheckSecondsMode.Checked; + + // Placement + Config.WndPosition:= TPosition(PositionCombo.ItemIndex); + + // Alarms + Config.DoneMessage:= NotifyMsg.Text; + Config.DoneMessageEnabled:= NotifyMsgOn.Checked; + Config.DoneTrayMsg:= NotifyTrayMsg.Text; + Config.DoneTrayMsgEnabled:= NotifyTrayMsgOn.Checked; + Config.DoneAudio:= NotifyAudio.Text; + Config.DoneAudioEnabled:= NotifyAudioOn.Checked; + Config.DoneApp:= NotifyRunApp.Text; + Config.DoneAppEnabled:= NotifyRunAppOn.Checked; + + // Fonts + Config.Font.Name:= FontPreview.Font.Name; + Config.Font.Charset:= FontPreview.Font.CharSet; + Config.Font.Color:= FontPreview.Font.Color; + Config.Font.BgColor:= FontPreview.Color; + Config.Font.Size:= FontSize.Value; // FontPreview has fixed size + Config.Font.Style:= FontPreview.Font.Style; + end; +end; -procedure TOptionsForm.UpdateFonts(Sender: TObject); +procedure TOptionsForm.EnableFields(Sender: TObject); begin - FontName.Caption := f.Name + ' : 1234567890'; - FontName.Font.Name := f.Name; - FontName.Font.Color := f.Color; - FontName.Font.CharSet := f.CharSet; - FontName.Font.Style := f.Style; - FontName.Font.Quality:= fqAntialiased; - FontName.Font.Size := 18; + NotifyMsg.Enabled := NotifyMsgOn.Checked; + NotifyMsgTest.Enabled := NotifyMsgOn.Checked; + NotifyTrayMsg.Enabled := NotifyTrayMsgOn.Checked; + NotifyTrayMsgTest.Enabled := NotifyTrayMsgOn.Checked; - FontName.Color := BgColor.ButtonColor; - FontSize.Value := f.Size; - FontColor.ButtonColor := f.Color; + NotifyAudio.Enabled := NotifyAudioOn.Checked; + NotifyAudioBtn.Enabled := NotifyAudioOn.Checked; + NotifyAudioTest.Enabled := NotifyAudioOn.Checked; + + NotifyRunApp.Enabled := NotifyRunAppOn.Checked; + NotifyRunBtn.Enabled := NotifyRunAppOn.Checked; + NotifyRunTest.Enabled := NotifyRunAppOn.Checked; end; + procedure TOptionsForm.UpdateFontSize(Sender: TObject); begin - f.Size := FontSize.Value; - UpdateFonts(Sender); + //FontPreview.Font.Size:= FontSize.Value; end; procedure TOptionsForm.UpdateFontColor(Sender: TObject); begin - f.Color := FontColor.ButtonColor; - UpdateFonts(Sender); + FontPreview.Font.Color:= FontColor.ButtonColor; +end; + +procedure TOptionsForm.UpdateFontBgColor(Sender: TObject); +begin + FontPreview.Color:= BgColor.ButtonColor; + end; procedure TOptionsForm.GetAppFile(Sender: TObject); @@ -180,35 +291,24 @@ function TOptionsForm.GetFile(Orig: String; FilterStr: String; Dir : String): St dlg.Free; end; -procedure TOptionsForm.EnableFields(Sender: TObject); -begin - NotifyMsg.Enabled := NotifyMsgOn.Checked; - NotifyMsgTest.Enabled := NotifyMsgOn.Checked; - NotifyTrayMsg.Enabled := NotifyTrayMsgOn.Checked; - NotifyTrayMsgTest.Enabled := NotifyTrayMsgOn.Checked; - - NotifyAudio.Enabled := NotifyAudioOn.Checked; - NotifyAudioBtn.Enabled := NotifyAudioOn.Checked; - NotifyAudioTest.Enabled := NotifyAudioOn.Checked; - - NotifyRunApp.Enabled := NotifyRunAppOn.Checked; - NotifyRunBtn.Enabled := NotifyRunAppOn.Checked; - NotifyRunTest.Enabled := NotifyRunAppOn.Checked; -end; procedure TOptionsForm.SetFontDefaults(Sender: TObject); var - Cfg : TFontConfig; -begin - Cfg:= GetConfig.GetDefaultFont; - BgColor.ButtonColor:= Cfg.BgColor; - f.Name:= Cfg.Name; - f.Color:= Cfg.Color; - f.CharSet:= Cfg.Charset; - f.Size:= Cfg.Size; - f.Style:= Cfg.Style; - UpdateFonts(Sender); + DefFont : TFontConfig; +begin + DefFont:= GetConfig.GetDefaultFont; + + FontSize.Value:= DefFont.Size; + FontColor.ButtonColor:= DefFont.Color; + BgColor.ButtonColor:= DefFont.BgColor; + FontPreview.Caption:= DefFont.Name + ' : 1234567890'; + FontPreview.Font.Name:= DefFont.Name; + //FontPreview.Font.Size:= DefFont.Size; + FontPreview.Font.CharSet:= DefFont.Charset; + FontPreview.Font.Color:= DefFont.Color; + FontPreview.Font.Style:= DefFont.Style; + FontPreview.Color:= DefFont.BgColor; end; procedure TOptionsForm.TestAudio(Sender: TObject); From 20e54a2e77badcaf92d27cb087c64aecc59994a2 Mon Sep 17 00:00:00 2001 From: neo85 Date: Wed, 17 Feb 2021 10:20:30 +0100 Subject: [PATCH 5/8] MyTimer class --- model/mytimer.pas | 181 ++++++++++++++++++++++ snaptimer.lpi | 6 +- snaptimer.lps | 222 ++++++++++++++++----------- snaptimer.lrs | 374 ---------------------------------------------- ui/mainform1.pas | 144 +++++++++--------- 5 files changed, 398 insertions(+), 529 deletions(-) create mode 100644 model/mytimer.pas delete mode 100644 snaptimer.lrs diff --git a/model/mytimer.pas b/model/mytimer.pas new file mode 100644 index 0000000..cbdeb01 --- /dev/null +++ b/model/mytimer.pas @@ -0,0 +1,181 @@ +unit mytimer; + +{$mode objfpc} + +interface + +uses + Classes, SysUtils, ExtCtrls; + +type + TMode = (Timer, Stopwatch); + TState = (Running, Stopped, Paused); + + // TODO find better name + TMyTimer = class + private + FTimer: TTimer; + // Start or End time, depending on the Mode. + FTime: TDateTime; + FSeconds: Integer; + + FState: TState; + FMode: TMode; + FOnSecondElapsed: TNotifyEvent; + FOnFinished: TNotifyEvent; + + function GetSeconds : Integer; + procedure SetSeconds(AValue: Integer); + function GetMinutes : Integer; + procedure SetMinutes(AValue: Integer); + + procedure OnTimer(Sender: TObject); + procedure UpdateSeconds; + procedure UpdateTime; + public + constructor Create; + destructor Free; + procedure Start; + procedure Pause; + procedure Resume; + procedure StartPauseResume; + procedure Stop; + + property Seconds: Integer read GetSeconds write SetSeconds; + property Minutes: Integer read GetMinutes write SetMinutes; + property State: TState read FState; + property Mode: TMode read FMode write FMode; + property OnSecondElapsed: TNotifyEvent read FOnSecondElapsed write FOnSecondElapsed; + property OnFinished: TNotifyEvent read FOnFinished write FOnFinished; +end; + +implementation + +uses DateUtils; + +function TMyTimer.GetSeconds : Integer; +begin + Result:= FSeconds; +end; + +procedure TMyTimer.SetSeconds(AValue: Integer); +begin + if State <> Stopped then + Raise Exception.Create('Timer is not in `Stopped` state'); + FSeconds:= AValue; +end; + +function TMyTimer.GetMinutes : Integer; +begin + Result:= FSeconds div 60; +end; + +procedure TMyTimer.SetMinutes(AValue: Integer); +begin + if State <> Stopped then + Raise Exception.Create('Timer is not in `Stopped` state'); + FSeconds:= AValue * 60; +end; + +procedure TMyTimer.OnTimer(Sender: TObject); +begin + if Mode = Timer then + begin + if Now >= FTime then + begin + FTimer.Enabled:= False; + FSeconds:= 0; + FState:= Stopped; + OnFinished(self); + end + else + UpdateSeconds; + end + else + begin + // Stopwatch + UpdateSeconds; + end +end; + +procedure TMyTimer.UpdateSeconds; +var s : Integer; +begin + s:= SecondsBetween(FTime, Now); + if s <> FSeconds then + begin + FSeconds:= s; + OnSecondElapsed(self); + end; +end; + +procedure TMyTimer.UpdateTime; +begin + if Mode = Timer then + FTime:= Now + (FSeconds * OneSecond) // FTime is the end time + else + FTime:= Now - (FSeconds * OneSecond) // FTime is the start time +end; + +constructor TMyTimer.Create; +begin + FTimer:= TTimer.Create(nil); + FTimer.Interval:= 160; + FTimer.OnTimer:= @OnTimer; + FMode:= Timer; +end; + +destructor TMyTimer.Free; +begin + FTimer.Free; +end; + + +procedure TMyTimer.Start; +begin + if State <> Stopped then + Raise Exception.Create('Timer is not in `Stopped` state'); + + FState:= Running; + UpdateTime; + FTimer.Enabled:= True; +end; + +procedure TMyTimer.Pause; +begin + if State <> Running then + Raise Exception.Create('Timer is not in `Running` state'); + + FState:= Paused; + FTimer.Enabled:= False; +end; + +procedure TMyTimer.Resume; +begin + if State <> Paused then + Raise Exception.Create('Timer is not in `Paused` state'); + + FState:= Running; + UpdateTime; + FTimer.Enabled:= True; +end; + +procedure TMyTimer.StartPauseResume; +begin + case State of + Running : Pause; + Stopped : Start; + Paused : Resume; + end; +end; + +procedure TMyTimer.Stop; +begin + FTimer.Enabled:= False; + FState:= Stopped; + // TODO reset FTime, FSeconds?? + // Call OnFinished? +end; + +end. + diff --git a/snaptimer.lpi b/snaptimer.lpi index 0064e5b..10cf8d2 100644 --- a/snaptimer.lpi +++ b/snaptimer.lpi @@ -85,7 +85,7 @@ - + @@ -122,6 +122,10 @@ + + + + diff --git a/snaptimer.lps b/snaptimer.lps index 2286cdb..76770a8 100644 --- a/snaptimer.lps +++ b/snaptimer.lps @@ -4,23 +4,22 @@ - + - - - + + + - + - - + @@ -30,7 +29,7 @@ - + @@ -39,10 +38,11 @@ - - - - + + + + + @@ -53,47 +53,52 @@ - - - - - - - + + + + - - - + + + + + + + + + + + - - + + - - + + - - + + @@ -101,204 +106,247 @@ - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - - + + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - - + + - - + + - - + + + + + + diff --git a/snaptimer.lrs b/snaptimer.lrs deleted file mode 100644 index f371f79..0000000 --- a/snaptimer.lrs +++ /dev/null @@ -1,374 +0,0 @@ -LazarusResources.Add('MAINICON','ICO',[ - #0#0#1#0#4#0' '#0#0#1#0#8#0#168#8#0#0'F'#0#0#0#16#16#0#0#1#0#8#0'h'#5#0#0#238 - +#8#0#0' '#0#0#1#0' '#0#168#16#0#0'V'#14#0#0#16#16#0#0#1#0' '#0'h'#4#0#0#254 - +#30#0#0'('#0#0#0' '#0#0#0'@'#0#0#0#1#0#8#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#0#0#0#0#0'711'#0'<44'#0'A88'#0'C=;'#0'H?='#0'NFC'#0'OGE'#0'ULJ' - +#0'\RO'#0'nxz'#0'p{}'#0#175'k'#19#0#175'l'#19#0#175'l'#20#0#176'm'#22#0#177 - +'o'#24#0#178'p'#25#0#177'q'#29#0#180'q'#28#0#183'u!'#0#186'w$'#0#185'x%'#0 - +#177'v*'#0#178'x+'#0#181'y,'#0#188'z)'#0#184'|/'#0#190#127'.'#0#208#130','#0 - +#193#129'3'#0#196#128'2'#0#195#132'7'#0#198#132'6'#0#203#136';'#0#201#136'<' - +#0#204#136'<'#0#214#141':'#0#217#145'='#0#177#134'M'#0#183#140'S'#0#179#156 - +'~'#0#202#139'D'#0#205#141'D'#0#209#141'B'#0#209#143'G'#0#207#145'L'#0#218 - +#145'B'#0#218#148'A'#0#218#147'D'#0#210#145'I'#0#213#145'I'#0#211#147'M'#0 - +#217#151'N'#0#221#153'I'#0#219#155'M'#0#220#155'M'#0#221#156'N'#0#192#149'\' - +#0#212#153'T'#0#219#154'Q'#0#220#157'Q'#0#223#158'U'#0#209#155'Z'#0#217#158 - +'Z'#0#220#156'Y'#0#224#158'M'#0#224#155'Q'#0#227#159'W'#0#225#158'X'#0#222 - +#161'U'#0#226#162'Q'#0#225#167'Z'#0#224#161'^'#0#199#155'a'#0#197#158'j'#0 - +#219#163'b'#0#220#163'b'#0#222#167'g'#0#198#166'z'#0#230#165'a'#0#227#170'l' - +#0#228#171'm'#0#231#172'o'#0#234#173'l'#0#232#174'r'#0#237#176'q'#0#233#176 - +'v'#0#235#178'y'#0#237#183'~'#0#240#181'z'#0'm~'#129#0'n'#128#130#0't'#128 - +#128#0'r'#131#134#0'u'#131#133#0'q'#132#135#0'x'#132#133#0'q'#133#136#0'z' - +#134#136#0'}'#137#138#0#130#138#139#0#129#139#141#0#129#141#142#0#133#141#142 - +#0#131#144#145#0#132#144#146#0#133#147#148#0#137#145#144#0#142#151#152#0#148 - +#157#156#0#189#165#135#0#178#174#153#0#153#162#161#0#181#182#167#0#207#176 - +#130#0#238#184#128#0#242#186#130#0#216#197#156#0#242#193#141#0#249#198#146#0 - +#252#201#150#0#220#207#171#0#227#206#163#0#255#213#168#0#226#211#176#0#164 - +#191#200#0#154#204#235#0#153#205#236#0#172#211#230#0#166#211#233#0#162#210 - +#238#0#170#218#234#0#174#221#240#0#176#222#245#0#175#224#238#0#178#228#240#0 - +#182#228#241#0#182#231#244#0#184#231#244#0#183#232#241#0#183#232#245#0#185 - +#232#241#0#188#234#241#0#190#236#243#0#186#234#244#0#187#236#245#0#190#237 - +#246#0#185#228#250#0#191#236#249#0#190#242#253#0#210#213#196#0#196#217#216#0 - +#213#228#216#0#222#241#235#0#192#235#242#0#194#236#243#0#193#237#245#0#197 - +#237#244#0#196#239#248#0#195#240#247#0#198#241#247#0#200#240#245#0#205#241 - +#246#0#193#240#249#0#197#241#248#0#196#240#255#0#197#247#255#0#201#242#249#0 - +#206#243#248#0#202#244#249#0#205#245#250#0#207#245#252#0#202#249#255#0#205 - +#250#254#0#207#252#255#0#210#244#248#0#213#246#249#0#209#246#252#0#216#247 - +#250#0#215#248#251#0#210#249#254#0#214#249#253#0#208#253#255#0#214#254#255#0 - +#217#248#251#0#221#250#251#0#217#249#252#0#221#250#252#0#218#253#255#0#221 - +#253#254#0#231#238#224#0#226#243#236#0#225#254#254#0#229#255#255#0#233#255 - +#255#0#144#0'b'#0#176#0'x'#0#207#0#142#0#240#0#164#0#255#17#179#0#255'1'#190 - +#0#255'Q'#199#0#255'q'#209#0#255#145#220#0#255#177#229#0#255#209#240#0#255 - +#255#255#0#0#0#0#0','#0'/'#0'K'#0'P'#0'i'#0'p'#0#135#0#144#0#165#0#176#0#196 - +#0#207#0#225#0#240#0#240#17#255#0#242'1'#255#0#244'Q'#255#0#246'q'#255#0#247 - +#145#255#0#249#177#255#0#251#209#255#0#255#255#255#0#0#0#0#0#27#0'/'#0'-'#0 - +'P'#0'?'#0'p'#0'R'#0#144#0'c'#0#176#0'v'#0#207#0#136#0#240#0#153#17#255#0#166 - +'1'#255#0#180'Q'#255#0#194'q'#255#0#207#145#255#0#220#177#255#0#235#209#255#0 - +#255#255#255#0#0#0#0#0#8#0'/'#0#14#0'P'#0#21#0'p'#0#27#0#144#0'!'#0#176#0'&' - +#0#207#0','#0#240#0'>'#17#255#0'X1'#255#0'qQ'#255#0#140'q'#255#0#166#145#255 - +#0#191#177#255#0#218#209#255#0#255#255#255#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0''''#24#17#17#19#17#18#24''''#0#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#0#0#0#0#0#0')'#18#20#31'$,,,,,$'#31#20#18')'#0#0#0#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#23#21'$389GGGGG973$'#21#23#0#0#0#0#0#0#0#0#0#0#0#0#0#0#17'!39H{' - +#191#195#195#195#195#195#191'{H93!'#17#0#0#0#0#0#0#0#0#0#0#0#0#19'25B}'#194 - +#194#194#194#194#195#194#194#194#194#194'}B52'#19#0#0#0#0#0#0#0#0#0#0#17'2v'#184#182#187#180#177#177#187#189#190#189 - +#179#177#177#177#179#177#177#180#187#182#184'v>+('#0#0#0#24'@6'#153#181#177 - +#177#177#176#177#189'he'#190#182#177#176#176#176#177#177#177#176#177#181#153 - +'6@'#24#0#0#0#16'S0'#183#181#176#178#176#176#176#184'l'#7'd'#190#182#177#176 - ,#176#176#176#176#176#176#178#183'0S'#16#0#0#0#16'U&'#175#172#178#182#178#176 - +#169#178#184'h'#4']'#189#178#169#169#169#176#178#181#181#172#174'0U'#15#0#0#0 - +#15'W&'#174#172'jki'#172#163#169#178#189'g'#1#10#181#169#163#163#171'iki'#178 - +#173'&W'#15#0#0#0#15'X%'#183#170#171#172#171#168#162#168#171#184'c'#2#11#181 - +#162#162#162#168#171#171#171#170#183'%X'#15#0#0#0#15'Y%'#175#161#162#162#162 - +#162#162#170#183'a'#3'a'#183#170#162#162#162#162#162#162#162#161#175'%Y'#15#0 - +#0#0#25'R1'#175#159#158#158#158#162#168#175'c'#5'c'#183#168#162#158#158#158 - +#158#158#158#158#165#175'1R'#25#0#0#0':;E'#151#150#159#160#159#165#173'd'#6 - +'d'#174#165#157#156#156#158#156#156#160#160#160#164#151'E;:'#0#0#0#0#26'Zs' - +#166#160'_'#165#173'g'#8'g'#173#160#157#155#156#155#155#155#155#160'_'#160 - +#166'sZ'#26#0#0#0#0#0#18'RC'#152#149#164#164'i'#9'j'#167#160#144#157#144#143 - +#143#143#143#144#144#147#149#152'CR'#18#0#0#0#0#0#0#30'u?'#148#146#164'ik' - +#167#147#144#149'^'#149#143#143#144#147#144#146#146#148'?u'#30#0#0#0#0#0#0#0 - +#25'@TO'#134#139#150'b'#147#145#142#147'b'#147#139#140#145'['#146#137#134'OV' - +'@'#25#0#0#0#0#0#0#0#0#14'tTK'#129#133#141#145#140#140#146'\'#146#140#140#145 - +#138#133#129'KTt'#14#0#0#0#0#0#0#0#0#0#0#19'uV.r'#131#130#132#135#136#137#136 - +#135#132#130#131'r.Zt'#19#0#0#0#0#0#0#0#0#0#0#0#0#14'MxD*p~'#128#127#127#127 - +#128'~p*DxL'#13#0#0#0#0#0#0#0#0#0#0#0#0#0#0#25' tyP/'#29#29#29#29#29'/Pyt ' - +#25#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#18#28'Nw|||||wN'#28#18#0#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#0#0#0#0#0#0#0'J'#27#12#12#12#12#12#27'J'#0#0#0#0#0#0#0#0#0#0#0 - +#255#255#255#255#255#255#255#255#255#255#255#255#255#240#7#255#255#128#0#255 - +#255#0#0#127#254#0#0'?'#252#0#0#31#248#0#0#15#240#0#0#7#224#0#0#3#224#0#0#3 - +#224#0#0#3#192#0#0#1#192#0#0#1#192#0#0#1#192#0#0#1#192#0#0#1#192#0#0#1#192#0 - +#0#1#192#0#0#1#192#0#0#1#224#0#0#3#224#0#0#3#240#0#0#7#240#0#0#7#248#0#0#15 - +#252#0#0#31#254#0#0'?'#255#0#0#127#255#192#1#255#255#240#7#255'('#0#0#0#16#0 - +#0#0' '#0#0#0#1#0#8#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 - +#180'~='#0#194#127'/'#0#173'~E'#0#167'~J'#0#200#134'9'#0#201#136':'#0#185#132 - +'C'#0#184#139'R'#0#150#129'e'#0#153#133'l'#0#163#134'`'#0#164#146'z'#0#162 - +#147'~'#0#167#150#127#0#180#153'v'#0#182#155'x'#0#185#158'z'#0#200#138'A'#0 - +#204#142'E'#0#209#143'B'#0#199#144'N'#0#206#145'I'#0#207#147'N'#0#209#145'G' - +#0#213#147'G'#0#215#149'G'#0#217#151'I'#0#217#153'O'#0#192#149'^'#0#199#152 - +']'#0#207#155'['#0#210#152'T'#0#221#157'V'#0#212#157'['#0#215#160']'#0#224 - +#160'Y'#0#204#158'd'#0#223#164'c'#0#221#167'e'#0#220#168'g'#0#220#168'h'#0 - +#215#169'u'#0#222#182'~'#0#226#168'i'#0#224#171'n'#0#229#170'l'#0#227#174't' - +#0'|'#138#138#0'}'#140#141#0#130#145#146#0#133#148#149#0#137#149#149#0#135 - +#152#154#0#137#153#154#0#181#167#139#0#181#167#140#0#185#167#137#0#142#166 - +#170#0#151#184#190#0#183#189#178#0#197#168#129#0#203#172#131#0#206#180#142#0 - +#215#192#151#0#214#195#152#0#210#197#157#0#225#197#149#0#205#197#170#0#220 - +#214#183#0#216#214#187#0#227#220#190#0#171#196#199#0#175#197#199#0#163#205 - +#214#0#168#208#215#0#173#211#219#0#174#213#219#0#175#211#222#0#191#208#208#0 - +#186#212#215#0#173#221#239#0#189#219#224#0#188#220#225#0#175#224#238#0#177 - +#226#238#0#180#230#241#0#186#232#242#0#190#234#241#0#191#236#243#0#185#232 - +#246#0#188#235#244#0#190#238#247#0#224#228#208#0#197#224#227#0#197#225#228#0 - +#203#228#230#0#207#230#230#0#201#235#237#0#194#233#242#0#194#236#243#0#195 - +#237#245#0#196#237#245#0#200#239#244#0#201#241#246#0#205#241#246#0#194#241 - +#248#0#199#242#249#0#201#242#248#0#206#243#248#0#203#247#251#0#205#245#250#0 - +#205#248#253#0#210#244#244#0#209#245#248#0#215#246#249#0#214#250#253#0#219 - +#249#251#0#220#250#250#0#217#249#252#0#220#250#252#0#220#252#254#0#228#238 - +#224#0#230#250#247#0#225#252#250#0#225#252#253#0#231#255#255#0#255#255#255#0 - +#0#0#0#0'/&'#0#0'PA'#0#0'p['#0#0#144't'#0#0#176#142#0#0#207#169#0#0#240#195#0 - +#0#255#210#17#0#255#216'1'#0#255#221'Q'#0#255#228'q'#0#255#234#145#0#255#240 - +#177#0#255#246#209#0#255#255#255#0#0#0#0#0'/'#20#0#0'P"'#0#0'p0'#0#0#144'>'#0 - +#0#176'M'#0#0#207'['#0#0#240'i'#0#0#255'y'#17#0#255#138'1'#0#255#157'Q'#0#255 - +#175'q'#0#255#193#145#0#255#210#177#0#255#229#209#0#255#255#255#0#0#0#0#0'/' - +#3#0#0'P'#4#0#0'p'#6#0#0#144#9#0#0#176#10#0#0#207#12#0#0#240#14#0#0#255' '#18 - +#0#255'>1'#0#255'\Q'#0#255'zq'#0#255#151#145#0#255#182#177#0#255#212#209#0 - +#255#255#255#0#0#0#0#0'/'#0#14#0'P'#0#23#0'p'#0'!'#0#144#0'+'#0#176#0'6'#0 - +#207#0'@'#0#240#0'I'#0#255#17'Z'#0#255'1p'#0#255'Q'#134#0#255'q'#156#0#255 - +#145#178#0#255#177#200#0#255#209#223#0#255#255#255#0#0#0#0#0'/'#0' '#0'P'#0 - +'6'#0'p'#0'L'#0#144#0'b'#0#176#0'x'#0#207#0#142#0#240#0#164#0#255#17#179#0 - +#255'1'#190#0#255'Q'#199#0#255'q'#209#0#255#145#220#0#255#177#229#0#255#209 - +#240#0#255#255#255#0#0#0#0#0','#0'/'#0'K'#0'P'#0'i'#0'p'#0#135#0#144#0#165#0 - +#176#0#196#0#207#0#225#0#240#0#240#17#255#0#242'1'#255#0#244'Q'#255#0#246'q' - +#255#0#247#145#255#0#249#177#255#0#251#209#255#0#255#255#255#0#0#0#0#0#27#0 - ,'/'#0'-'#0'P'#0'?'#0'p'#0'R'#0#144#0'c'#0#176#0'v'#0#207#0#136#0#240#0#153#17 - +#255#0#166'1'#255#0#180'Q'#255#0#194'q'#255#0#207#145#255#0#220#177#255#0#235 - +#209#255#0#255#255#255#0#0#0#0#0#8#0'/'#0#14#0'P'#0#21#0'p'#0#27#0#144#0'!'#0 - +#176#0'&'#0#207#0','#0#240#0'>'#17#255#0'X1'#255#0'qQ'#255#0#140'q'#255#0#166 - +#145#255#0#191#177#255#0#218#209#255#0#255#255#255#0#0#0#0#0#0#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#0#0#0#0#13#9#9#10#0#0#0#0#0#0#0#0#0#0#11#2#20#27#27#26#6#1#0#0#0 - +#0#0#0#0#3#26'Cz~~{G'''#5#0#0#0#0#0#4#28']a}~O}a|+'#6#0#0#0#0#24'Eyxux`vxxv)' - +#7#0#0#8')t^swwwssw_F'#24#0#0#18'ArrrI4trrrrq!'#14#0#19'BSHmr40oiRHp$'#12#0 - +#22'Bllho21lghln$'#12#0#21'@efk32kddffb!'#0#0#15'-cM65jYXXYLD'#22#0#0#0#23'?' - +'Z:\[;WKWP,'#16#0#0#0#0'&>NTVJUQ'#255#205#251#255#255#207#245#252#255#210#247#252#255#211#248 - +#253#255#210#247#252#255#208#244#249#255#206#243#248#255#209#245#250#255#215 - +#255#255#255#132#142#142#255'C=;'#255't'#128#128#255#218#255#255#255#209#246 - +#251#255#206#242#247#255#206#242#247#255#206#242#247#255#208#244#249#255#210 - +#247#252#255#211#248#253#255#210#247#252#255#207#245#252#255#205#251#255#255 - +#217#146'>'#255#232#174'r'#255#176'n'#22#255#0#0#0#22#0#0#0#0#0#0#0#22#176'm' - +#22#255#233#176'v'#255#217#144'='#255#203#250#255#255#207#246#252#255#131#144 - +#145#255#133#147#148#255#131#144#145#255#207#244#250#255#204#241#247#255#205 - +#242#247#255#208#246#252#255#218#255#255#255#129#139#141#255'711'#255'nxz' - +#255#211#250#255#255#205#242#247#255#204#241#246#255#204#241#246#255#207#244 - +#250#255#131#144#145#255#133#147#148#255#131#144#145#255#207#246#252#255#203 - +#250#255#255#217#144'='#255#233#176'v'#255#176'm'#22#255#0#0#0#22#0#0#0#0#0#0 - +#0#22#176'm'#22#255#235#178'y'#255#215#142';'#255#208#253#255#255#202#243#250 - +#255#205#245#250#255#206#246#251#255#205#245#250#255#202#242#247#255#201#240 - +#245#255#201#241#246#255#205#246#251#255#215#255#255#255'y'#135#137#255'<44' - +#255'p{}'#255#207#249#254#255#202#241#246#255#201#240#245#255#201#240#245#255 - +#202#242#247#255#205#245#250#255#206#246#251#255#205#245#250#255#202#243#250 - +#255#208#253#255#255#215#142';'#255#235#178'y'#255#176'm'#22#255#0#0#0#22#0#0 - +#0#0#0#0#0#19#176'm'#22#255#237#183'~'#255#214#141':'#255#207#252#255#255#198 - +#241#247#255#200#240#245#255#200#240#245#255#200#240#245#255#199#239#244#255 - +#200#240#245#255#202#244#249#255#210#253#255#255'x'#132#133#255'A88'#255'w' - +#131#133#255#210#254#255#255#202#243#248#255#199#239#244#255#199#239#244#255 - +#199#239#244#255#199#239#244#255#200#240#245#255#200#240#245#255#200#240#245 - +#255#198#241#247#255#207#252#255#255#214#141':'#255#237#183'~'#255#176'm'#22 - +#255#0#0#0#19#0#0#0#0#0#0#0#14#172'k'#22#230#227#170'l'#255#218#147'D'#255 - +#208#251#255#255#196#239#248#255#197#237#245#255#197#237#245#255#197#237#244 - +#255#198#238#245#255#200#241#249#255#207#251#255#255'{'#134#136#255'H?='#255 - +'z'#134#136#255#208#252#255#255#201#242#249#255#198#238#245#255#197#237#244 - +#255#197#237#244#255#197#237#244#255#197#237#244#255#197#237#244#255#197#237 - +#245#255#197#237#245#255#196#239#248#255#208#251#255#255#218#147'D'#255#227 - ,#170'l'#255#172'k'#22#230#0#0#0#14#0#0#0#0#0#0#0#7#166'i'#23#179#212#153'T' - +#255#225#158'X'#255#210#213#196#255#193#240#251#255#195#238#246#255#196#239 - +#246#255#196#238#246#255#197#241#248#255#203#249#255#255'~'#138#139#255'NFC' - +#255'}'#137#139#255#204#250#255#255#197#241#248#255#194#237#244#255#194#236 - +#243#255#194#236#243#255#194#236#243#255#194#236#243#255#194#236#243#255#195 - +#238#245#255#196#239#246#255#195#238#246#255#193#240#251#255#210#213#196#255 - +#225#158'X'#255#212#153'T'#255#166'i'#23#179#0#0#0#7#0#0#0#0#0#0#0#1#148'^' - +#22'V'#188'{*'#255#240#182'{'#255#207#176#130#255#196#240#255#255#194#240#248 - +#255'u'#131#133#255#197#241#249#255#200#248#255#255#128#141#143#255'ULJ'#255 - +#128#141#142#255#201#249#255#255#195#240#247#255#193#237#244#255#192#235#242 - +#255#192#235#242#255#192#235#242#255#192#235#242#255#192#235#242#255#192#235 - +#243#255#194#238#245#255'u'#131#133#255#194#240#248#255#196#240#255#255#207 - +#176#130#255#240#182'{'#255#188'{*'#255#148'^'#22'V'#0#0#0#1#0#0#0#0#0#0#0#0 - +#0#0#0#9#175'm'#22#247#228#171'm'#255#224#155'Q'#255#196#217#216#255#191#236 - +#249#255#191#239#247#255#194#242#250#255#130#142#142#255'\RO'#255#132#144#146 - +#255#198#247#255#255#192#239#246#255#191#237#244#255#192#238#245#255#191#236 - +#243#255#189#234#241#255#189#234#241#255#189#234#241#255#189#235#241#255#189 - +#235#242#255#190#236#243#255#191#239#246#255#191#236#249#255#196#217#216#255 - +#224#155'Q'#255#228#171'm'#255#175'm'#22#247#0#0#0#9#0#0#0#0#0#0#0#0#0#0#0#0 - +#0#0#0#2#157'b'#23'f'#193#129'3'#255#242#186#131#255#209#155'Z'#255#185#228 - +#250#255#187#235#246#255#192#241#250#255#131#143#143#255#134#147#148#255#196 - +#247#255#255#190#237#246#255#188#235#243#255#191#238#247#255'r'#131#134#255 - +#191#238#247#255#188#234#242#255#187#233#241#255#189#235#243#255#189#236#245 - +#255#189#235#243#255#187#235#244#255#187#234#245#255#185#228#250#255#209#155 - +'Z'#255#242#186#130#255#193#129'3'#255#157'b'#23'g'#0#0#0#2#0#0#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#0#0#0#0#6#175'm'#23#231#217#159'['#255#234#173'l'#255#198#166'z' - +#255#177#222#245#255#184#231#244#255#190#242#253#255'q'#133#136#255#189#238 - +#247#255#185#232#242#255#185#232#242#255#189#237#247#255'q'#132#135#255#189 - +#237#247#255#185#232#242#255#184#232#241#255#187#235#244#255'm~'#129#255#187 - +#237#246#255#182#228#241#255#176#222#245#255#198#166'z'#255#237#176'q'#255 - +#217#159'['#255#175'm'#23#231#0#0#0#6#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 - +#0#0#0#1#142'Z'#21''''#175'l'#20#255#238#184#128#255#235#174'm'#255#198#158 - +'k'#255#172#211#230#255#175#221#241#255#183#232#245#255#184#235#244#255#183 - +#232#241#255#183#232#241#255#187#236#245#255'n'#128#130#255#187#236#245#255 - +#183#232#241#255#183#232#241#255#184#235#244#255#182#231#244#255#174#221#240 - +#255#172#211#230#255#197#158'j'#255#235#174'm'#255#238#184#128#255#175'l'#20 - +#255'nE'#17#18#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 - +#1#157'b'#23'8'#180'r'#28#255#239#186#131#255#237#177'r'#255#207#145'L'#255 - +#181#182#167#255#162#210#238#255#166#211#233#255#170#218#234#255#175#224#238 - +#255#178#228#240#255#179#229#242#255#178#228#240#255#175#224#238#255#170#218 - +#234#255#166#211#233#255#162#210#238#255#181#182#167#255#207#145'L'#255#240 - +#181'x'#255#239#186#130#255#180'r'#28#255#143'Z'#21'#'#0#0#0#1#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#147'\'#21'"'#175 - +'l'#20#255#220#163'b'#255#249#198#146#255#227#159'W'#255#202#139'D'#255#178 - +#174#153#255#164#191#200#255#153#205#236#255#154#204#235#255#154#204#235#255 - +#154#204#235#255#153#205#236#255#164#191#200#255#178#174#153#255#202#139'D' - +#255#227#159'W'#255#249#198#146#255#219#163'b'#255#175'l'#19#255#148']'#22'#' - +#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#0#0#0#0'pF'#17#16#175'l'#22#230#195#132'7'#255#237#184#128#255 - +#252#201#150#255#230#165'a'#255#218#144'C'#255#208#130'-'#255#209#130','#255 - +#209#130','#255#209#130','#255#208#130'-'#255#218#144'C'#255#230#165'a'#255 - +#252#201#150#255#237#184#128#255#195#132'7'#255#175'l'#22#230'pF'#17#16#0#0#0 - +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2#167'i'#23'_'#175'm'#21#247#190#127'.' - +#255#222#167'g'#255#242#193#141#255#255#213#169#255#255#213#168#255#255#213 - +#168#255#255#213#168#255#255#213#169#255#242#193#141#255#222#167'g'#255#190 - +#127'.'#255#175'm'#21#247#167'i'#23'_'#0#0#0#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#167'i'#24'L'#172'k'#22#172#175'l'#21 - +#226#175'k'#19#255#175'k'#19#255#175'k'#19#255#175'k'#19#255#175'k'#19#255 - +#175'l'#21#226#172'k'#22#172#167'i'#24'L'#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255#255#255#255#192#1#255 - +#255#0#0#127#254#0#0'?'#248#0#0#15#240#0#0#7#240#0#0#7#224#0#0#3#192#0#0#1 - +#192#0#0#1#128#0#0#0#128#0#0#0#128#0#0#0#128#0#0#0#128#0#0#0#128#0#0#0#128#0 - ,#0#0#128#0#0#0#128#0#0#0#128#0#0#0#128#0#0#0#128#0#0#0#128#0#0#0#192#0#0#1 - +#192#0#0#1#224#0#0#3#224#0#0#7#240#0#0#7#248#0#0#15#254#0#0'?'#255#0#0#127 - +#255#192#1#255'('#0#0#0#16#0#0#0' '#0#0#0#1#0' '#0#0#0#0#0#0#0#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2#0#0#0 - +#8#0#0#0#11#0#0#0#11#0#0#0#10#0#0#0#5#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2#0#0#0#18#25#16#4' Date: Wed, 17 Feb 2021 13:07:05 +0100 Subject: [PATCH 6/8] TUtils class --- model/mytimer.pas | 2 + model/utils.pas | 64 ++++++++++++++++++++++ snaptimer.lpi | 6 +- snaptimer.lpr | 2 +- snaptimer.lps | 137 +++++++++++++++++++++++++--------------------- ui/mainform1.pas | 63 ++++----------------- ui/options.pas | 11 ++-- 7 files changed, 162 insertions(+), 123 deletions(-) create mode 100644 model/utils.pas diff --git a/model/mytimer.pas b/model/mytimer.pas index cbdeb01..73d4ca8 100644 --- a/model/mytimer.pas +++ b/model/mytimer.pas @@ -120,9 +120,11 @@ procedure TMyTimer.UpdateTime; constructor TMyTimer.Create; begin FTimer:= TTimer.Create(nil); + FTimer.Enabled:= False; FTimer.Interval:= 160; FTimer.OnTimer:= @OnTimer; FMode:= Timer; + FState:= Stopped; end; destructor TMyTimer.Free; diff --git a/model/utils.pas b/model/utils.pas new file mode 100644 index 0000000..eb00194 --- /dev/null +++ b/model/utils.pas @@ -0,0 +1,64 @@ +unit utils; + +{$mode objfpc}{$H+} + +interface + +// TUtils class serves as a namespace. +type + TUtils = class + class function SecondsToTime(Seconds: integer; HideSeconds: Boolean): string; + class function GetFilePath(Path: string): string; + class procedure RunApp(Path: string); + class function IsInteger(S: String): boolean; + end; + +implementation + +uses + Classes, SysUtils, StrUtils, Forms, Windows; + +class function TUtils.SecondsToTime(Seconds: integer; HideSeconds: Boolean): string; +var + h, m, s: integer; +begin + h := Seconds div 3600; + m := Seconds div 60 - h * 60; + s := Seconds - (h * 3600 + m * 60); + if HideSeconds then + begin + Result := SysUtils.Format('%.2d:%.2d', [h, m]); + end + else + begin + Result := SysUtils.Format('%.2d:%.2d:%.2d', [h, m, s]); + end; +end; + +// TODO Interpret env vars in the path +class function TUtils.GetFilePath(Path: string): string; +begin + if AnsiStartsStr('.', Path) then + begin + Result := ExtractFilePath(Application.ExeName) + Path; + end else + Result := Path; +end; + +class procedure TUtils.RunApp(Path: string); +begin + ShellExecute(0, 'open', PChar(GetFilePath(Path)), nil, nil, SW_SHOWNORMAL); +end; + +class function TUtils.IsInteger(S: String): boolean; +begin + try + Result := True; + StrToInt(S); + except on E: EConvertError do + Result := False; + end; +end; + +end. + diff --git a/snaptimer.lpi b/snaptimer.lpi index 10cf8d2..9981d7c 100644 --- a/snaptimer.lpi +++ b/snaptimer.lpi @@ -85,7 +85,7 @@ - + @@ -126,6 +126,10 @@ + + + + diff --git a/snaptimer.lpr b/snaptimer.lpr index 8f18071..22de19c 100644 --- a/snaptimer.lpr +++ b/snaptimer.lpr @@ -3,7 +3,7 @@ {$mode objfpc}{$H+} uses - Forms, Interfaces, MainForm1; + Forms, Interfaces, MainForm1, utils; {$R *.res} diff --git a/snaptimer.lps b/snaptimer.lps index 76770a8..504b6a7 100644 --- a/snaptimer.lps +++ b/snaptimer.lps @@ -4,13 +4,13 @@ - + - - + + @@ -19,7 +19,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -40,9 +40,9 @@ - - - + + + @@ -54,9 +54,9 @@ - - - + + + @@ -65,14 +65,14 @@ - + - - - + + + @@ -111,8 +111,8 @@ - - + + @@ -211,142 +211,155 @@ - + - - + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - - + + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - - + - + - + - + - + - - + + - - + + - - - - - - - - - - + + diff --git a/ui/mainform1.pas b/ui/mainform1.pas index 940dda1..0be36fa 100644 --- a/ui/mainform1.pas +++ b/ui/mainform1.pas @@ -7,7 +7,7 @@ interface uses Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Menus, StdCtrls, Spin, ExtCtrls, About, LCLType, Options, MMSystem, - Windows, StrUtils, DateUtils, MyTimer; + Windows, DateUtils, MyTimer; type TMode = (Timer, Stopwatch); @@ -64,19 +64,15 @@ TMainForm = class(TForm) procedure ShowOptions(Sender: TObject); procedure ToggleCountdown(Sender: TObject); procedure FormKeyPress(Sender: TObject; var Key: char); - function SecondsToTime(Seconds: integer): string; procedure FormWindowStateChange(Sender: TObject); procedure UpdateTime(); procedure SaveSettings(Sender: TObject); - class function GetFilePath(Path: string): string; procedure PlayAudio(Path: string; Loop: boolean); procedure StopAudio(); - procedure RunApp(Path: string); procedure ShowDoneMessage(Msg: string); procedure ShowTrayMessage(Msg: string); procedure SetFieldsVisible(showFields: boolean); procedure PlayTicking(); - function IsInteger(S: String): boolean; private { private declarations } MyTimer : TMyTimer; @@ -102,7 +98,7 @@ TMainForm = class(TForm) implementation uses - Config; + Config, Utils; { TMainForm } @@ -131,6 +127,7 @@ implementation MSG_OPEN_INI = 'An error occurred opening the .ini file, settings won''t be saved'; MSG_WRITE_INI = 'An error occurred trying to write to the .ini file, settings won''t be saved.'; + procedure TMainForm.OnCreateForm(Sender: TObject); var Config: TConfig; @@ -187,7 +184,7 @@ procedure TMainForm.OnCreateForm(Sender: TObject); end; // Use minutes argument if it's the only parameter and it's numeric - if (ParamCount = 1) and (IsInteger(ParamStr(1))) then + if (ParamCount = 1) and (TUtils.IsInteger(ParamStr(1))) then Minutes.Value := StrToInt(ParamStr(1)); //UpdateTimeCaption(SecondsMode); ApplyConfig will do this @@ -405,7 +402,7 @@ procedure TMainForm.Countdown(Sender: TObject); if Config.DoneAudioEnabled then PlayAudio(Config.DoneAudio, Config.LoopAudio); if Config.DoneAppEnabled then - RunApp(Config.DoneApp); + TUtils.RunApp(Config.DoneApp); if Config.DoneTrayMsgEnabled then ShowTrayMessage(Config.DoneTrayMsg); if Config.DoneMessageEnabled then @@ -497,22 +494,6 @@ procedure TMainForm.CloseApp(Sender: TObject); Close; end; -function TMainForm.SecondsToTime(Seconds: integer): string; -var - h, m, s: integer; -begin - h := Seconds div 3600; - m := Seconds div 60 - h * 60; - s := Seconds - (h * 3600 + m * 60); - if GetConfig.HideSeconds then - begin - Result := SysUtils.Format('%.2d:%.2d', [h, m]); - end - else - begin - Result := SysUtils.Format('%.2d:%.2d:%.2d', [h, m, s]); - end; -end; procedure TMainForm.FormKeyPress(Sender: TObject; var Key: char); begin @@ -530,7 +511,7 @@ procedure TMainForm.UpdateTime(); begin // Changing caption while it's not visible keeps time from flashing Count.Visible := False; - Count.Caption := SecondsToTime(Timer1.Tag); + Count.Caption := TUtils.SecondsToTime(Timer1.Tag, GetConfig.HideSeconds); Count.Visible := True; MenuCount.Caption := Count.Caption; if Timer1.Enabled then @@ -558,15 +539,7 @@ procedure TMainForm.FormWindowStateChange(Sender: TObject); end; end; -// TODO Interpret env vars in the path -class function TMainForm.GetFilePath(Path: string): string; -begin - if AnsiStartsStr('.', Path) then - begin - Result := ExtractFilePath(Application.ExeName) + Path; - end else - Result := Path; -end; + procedure TMainForm.PlayAudio(Path: string; Loop: boolean); begin @@ -575,10 +548,10 @@ procedure TMainForm.PlayAudio(Path: string; Loop: boolean); if Loop then begin AudioPlaying := True; - sndPlaySound(PChar(GetFilePath(Path)), SND_NODEFAULT or SND_ASYNC or SND_LOOP); + sndPlaySound(PChar(TUtils.GetFilePath(Path)), SND_NODEFAULT or SND_ASYNC or SND_LOOP); end else - sndPlaySound(PChar(GetFilePath(Path)), SND_NODEFAULT or SND_ASYNC); + sndPlaySound(PChar(TUtils.GetFilePath(Path)), SND_NODEFAULT or SND_ASYNC); end; procedure TMainForm.StopAudio(); @@ -589,15 +562,10 @@ procedure TMainForm.StopAudio(); procedure TMainForm.PlayTicking(); begin - sndPlaySound(PChar(GetFilePath('.\sounds\ticking\ticking.wav')), SND_NODEFAULT or + sndPlaySound(PChar(TUtils.GetFilePath('.\sounds\ticking\ticking.wav')), SND_NODEFAULT or SND_ASYNC or SND_LOOP); end; -procedure TMainForm.RunApp(Path: string); -begin - ShellExecute(0, 'open', PChar(GetFilePath(Path)), nil, nil, SW_SHOWNORMAL); -end; - procedure TMainForm.ShowTrayMessage(Msg: string); begin with TrayIconMain do @@ -616,17 +584,6 @@ procedure TMainForm.ShowDoneMessage(Msg: string); StopAudio(); end; - -function TMainForm.IsInteger(S: String): boolean; -begin - try - Result := True; - StrToInt(S); - except on E: EConvertError do - Result := False; - end; -end; - procedure TMainForm.ApplyConfig; var Config: TConfig; diff --git a/ui/options.pas b/ui/options.pas index 70ad474..a08d236 100644 --- a/ui/options.pas +++ b/ui/options.pas @@ -79,11 +79,10 @@ TOptionsForm = class(TForm) var OptionsForm: TOptionsForm; -// f: TFont; // TODO make private implementation -uses Controls, MainForm1, Config; +uses Controls, MainForm1, Config, Utils; { TOptionsForm } const @@ -325,14 +324,14 @@ procedure TOptionsForm.TestMessage(Sender: TObject); procedure TOptionsForm.TestRunApp(Sender: TObject); begin -with Self.Owner as TMainForm do - RunApp(NotifyRunApp.Text); + with Self.Owner as TMainForm do + TUtils.RunApp(NotifyRunApp.Text); end; procedure TOptionsForm.TestTrayMsg(Sender: TObject); begin -with Self.Owner as TMainForm do - ShowTrayMessage(NotifyTrayMsg.Text); + with Self.Owner as TMainForm do + ShowTrayMessage(NotifyTrayMsg.Text); end; initialization From ebd7df4b1d500b799510aa1c0258e36b316f1c94 Mon Sep 17 00:00:00 2001 From: neo85 Date: Thu, 18 Feb 2021 09:21:31 +0100 Subject: [PATCH 7/8] TMyTimer class integration --- model/config.pas | 53 +++--- model/mytimer.pas | 70 +++++--- model/utils.pas | 19 +- snaptimer.lps | 222 ++++++++++++----------- ui/mainform1.lfm | 23 +-- ui/mainform1.pas | 449 ++++++++++++++++++++-------------------------- ui/options.pas | 4 +- 7 files changed, 419 insertions(+), 421 deletions(-) diff --git a/model/config.pas b/model/config.pas index 3e5bae9..2710348 100644 --- a/model/config.pas +++ b/model/config.pas @@ -53,6 +53,7 @@ TConfig = class // Font FFont: TFontConfig; FDefaultFont: TFontConfig; + procedure SetDoneMessage(Msg: String); procedure SetDoneTrayMessage(Msg: String); public @@ -176,6 +177,32 @@ implementation ConfigInstance : TConfig; + function FontStylesToInt(FontStyles: TFontStyles): integer; + var + Mask: integer; + Style: TFontStyle; + begin + // Translate the set into a bit mask + Mask := 0; + for Style := Low(TFontStyle) to High(TFontStyle) do + if Style in FontStyles then + Mask := Mask or (1 shl Ord(Style)); + Result := Mask; + end; + + function IntToFontStyles(Mask: integer): TFontStyles; + var + i: integer; + StyleSet: TFontStyles; + begin + // Translate the bit mask into a set + StyleSet := []; + for i := 0 to Ord(High(TFontStyle)) do + if Mask and (1 shl i) <> 0 then + StyleSet := StyleSet + [TFontStyle(i)]; + Result := StyleSet; + end; + procedure TConfig.SetDoneMessage(Msg: String); begin // TODO Set some reasonable length limit @@ -188,31 +215,6 @@ procedure TConfig.SetDoneTrayMessage(Msg: String); FDoneTrayMsg:= Msg; end; -function FontStylesToInt(FontStyles: TFontStyles): integer; -var - Mask: integer; - Style: TFontStyle; -begin - // Translate the set into a bit mask - Mask := 0; - for Style := Low(TFontStyle) to High(TFontStyle) do - if Style in FontStyles then - Mask := Mask or (1 shl Ord(Style)); - Result := Mask; -end; - -function IntToFontStyles(Mask: integer): TFontStyles; -var - i: integer; - StyleSet: TFontStyles; -begin - // Translate the bit mask into a set - StyleSet := []; - for i := 0 to Ord(High(TFontStyle)) do - if Mask and (1 shl i) <> 0 then - StyleSet := StyleSet + [TFontStyle(i)]; - Result := StyleSet; -end; constructor TConfig.Create; begin @@ -373,6 +375,7 @@ function TConfig.GetDefaultFont : TFontConfig; Result:= FDefaultFont; end; + function GetConfig : TConfig; begin Result:= ConfigInstance; diff --git a/model/mytimer.pas b/model/mytimer.pas index 73d4ca8..a523802 100644 --- a/model/mytimer.pas +++ b/model/mytimer.pas @@ -9,7 +9,7 @@ interface type TMode = (Timer, Stopwatch); - TState = (Running, Stopped, Paused); + TState = (Ready, Running, Finished, Paused); // TODO find better name TMyTimer = class @@ -18,11 +18,11 @@ TMyTimer = class // Start or End time, depending on the Mode. FTime: TDateTime; FSeconds: Integer; - + FSecondsInitial: Integer; FState: TState; FMode: TMode; FOnSecondElapsed: TNotifyEvent; - FOnFinished: TNotifyEvent; + FOnStateChanged: TNotifyEvent; function GetSeconds : Integer; procedure SetSeconds(AValue: Integer); @@ -38,15 +38,17 @@ TMyTimer = class procedure Start; procedure Pause; procedure Resume; - procedure StartPauseResume; - procedure Stop; + procedure Toggle; + procedure Reset; property Seconds: Integer read GetSeconds write SetSeconds; property Minutes: Integer read GetMinutes write SetMinutes; property State: TState read FState; property Mode: TMode read FMode write FMode; property OnSecondElapsed: TNotifyEvent read FOnSecondElapsed write FOnSecondElapsed; - property OnFinished: TNotifyEvent read FOnFinished write FOnFinished; + property OnStateChanged: TNotifyEvent read FOnStateChanged write FOnStateChanged; + private + end; implementation @@ -60,9 +62,10 @@ function TMyTimer.GetSeconds : Integer; procedure TMyTimer.SetSeconds(AValue: Integer); begin - if State <> Stopped then - Raise Exception.Create('Timer is not in `Stopped` state'); + if State <> Ready then + Raise Exception.Create('Timer is not in `Ready` state'); FSeconds:= AValue; + FSecondsInitial:= AValue; end; function TMyTimer.GetMinutes : Integer; @@ -72,9 +75,10 @@ function TMyTimer.GetMinutes : Integer; procedure TMyTimer.SetMinutes(AValue: Integer); begin - if State <> Stopped then - Raise Exception.Create('Timer is not in `Stopped` state'); + if State <> Ready then + Raise Exception.Create('Timer is not in `Ready` or `Finished` state'); FSeconds:= AValue * 60; + FSecondsInitial:= FSeconds; end; procedure TMyTimer.OnTimer(Sender: TObject); @@ -85,8 +89,9 @@ procedure TMyTimer.OnTimer(Sender: TObject); begin FTimer.Enabled:= False; FSeconds:= 0; - FState:= Stopped; - OnFinished(self); + FState:= Finished; + if Assigned(FOnStateChanged) then + FOnStateChanged(self); end else UpdateSeconds; @@ -105,7 +110,8 @@ procedure TMyTimer.UpdateSeconds; if s <> FSeconds then begin FSeconds:= s; - OnSecondElapsed(self); + if Assigned(FOnSecondElapsed) then + FOnSecondElapsed(self); end; end; @@ -123,8 +129,12 @@ constructor TMyTimer.Create; FTimer.Enabled:= False; FTimer.Interval:= 160; FTimer.OnTimer:= @OnTimer; + FSeconds:= 10 * 60; + FSecondsInitial:= FSeconds; + FState:= Ready; FMode:= Timer; - FState:= Stopped; + FOnSecondElapsed:= nil; + FOnStateChanged:= nil; end; destructor TMyTimer.Free; @@ -135,49 +145,61 @@ destructor TMyTimer.Free; procedure TMyTimer.Start; begin - if State <> Stopped then - Raise Exception.Create('Timer is not in `Stopped` state'); + if State <> Ready then + Raise Exception.Create('Timer is not in `Ready` state'); FState:= Running; UpdateTime; + if Assigned(FOnStateChanged) then + FOnStateChanged(self); FTimer.Enabled:= True; end; procedure TMyTimer.Pause; begin if State <> Running then - Raise Exception.Create('Timer is not in `Running` state'); + Raise Exception.Create('Timer is not in `Running` state'); FState:= Paused; + if Assigned(FOnStateChanged) then + FOnStateChanged(self); FTimer.Enabled:= False; end; procedure TMyTimer.Resume; begin if State <> Paused then - Raise Exception.Create('Timer is not in `Paused` state'); + Raise Exception.Create('Timer is not in `Paused` state'); FState:= Running; UpdateTime; + if Assigned(FOnStateChanged) then + FOnStateChanged(self); FTimer.Enabled:= True; end; -procedure TMyTimer.StartPauseResume; +procedure TMyTimer.Toggle; begin case State of + Ready : Start; Running : Pause; - Stopped : Start; + Finished : Reset; Paused : Resume; end; end; -procedure TMyTimer.Stop; +procedure TMyTimer.Reset; +var PrevState: TState; begin + PrevState:= FState; FTimer.Enabled:= False; - FState:= Stopped; - // TODO reset FTime, FSeconds?? - // Call OnFinished? + FState:= Ready; + FSeconds:= FSecondsInitial; + // We want FOnStateChanged to be called even if we are in `Ready` state. + if Assigned(FOnStateChanged) {and (PrevState <> Ready)} then + FOnStateChanged(self); end; + end. diff --git a/model/utils.pas b/model/utils.pas index eb00194..1a0812d 100644 --- a/model/utils.pas +++ b/model/utils.pas @@ -11,12 +11,14 @@ TUtils = class class function GetFilePath(Path: string): string; class procedure RunApp(Path: string); class function IsInteger(S: String): boolean; + class procedure PlayAudio(Path: string; Loop: boolean); + class procedure StopAudio; end; implementation uses - Classes, SysUtils, StrUtils, Forms, Windows; + Classes, SysUtils, StrUtils, Forms, Windows, MMSystem; class function TUtils.SecondsToTime(Seconds: integer; HideSeconds: Boolean): string; var @@ -60,5 +62,20 @@ class function TUtils.IsInteger(S: String): boolean; end; end; + +class procedure TUtils.PlayAudio(Path: string; Loop: boolean); +begin + if Loop then + sndPlaySound(PChar(GetFilePath(Path)), SND_NODEFAULT or SND_ASYNC or SND_LOOP) + else + sndPlaySound(PChar(GetFilePath(Path)), SND_NODEFAULT or SND_ASYNC); +end; + +class procedure TUtils.StopAudio; +begin + sndPlaySound(nil, 0); +end; + + end. diff --git a/snaptimer.lps b/snaptimer.lps index 504b6a7..7884853 100644 --- a/snaptimer.lps +++ b/snaptimer.lps @@ -4,13 +4,13 @@ - + - + @@ -19,7 +19,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -39,10 +39,10 @@ - - - - + + + + @@ -54,51 +54,59 @@ - - - + + + - - - + + + - - - + + + + + + + + + + + - - + + - - + + - - + + @@ -106,131 +114,123 @@ - - + + - - - - - + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - - - - - - - - @@ -247,119 +247,135 @@ + + + + + + + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - - + + - - + + - - + + - - + + - - + + - - + + - + + - + - + - + - + - + - + - + - + + + + + + + + + diff --git a/ui/mainform1.lfm b/ui/mainform1.lfm index cc89aa5..e60bcfe 100644 --- a/ui/mainform1.lfm +++ b/ui/mainform1.lfm @@ -1,7 +1,7 @@ object MainForm: TMainForm - Left = 533 + Left = 701 Height = 242 - Top = 312 + Top = 305 Width = 261 HorzScrollBar.Page = 274 HorzScrollBar.Range = 275 @@ -9,7 +9,7 @@ object MainForm: TMainForm VertScrollBar.Page = 137 VertScrollBar.Range = 26 VertScrollBar.Visible = False - ActiveControl = Minutes + ActiveControl = TimeEdit Caption = 'SnapTimer' ClientHeight = 222 ClientWidth = 261 @@ -26,7 +26,7 @@ object MainForm: TMainForm Position = poScreenCenter LCLVersion = '2.0.10.0' object TimeLabel: TLabel - AnchorSideRight.Control = Minutes + AnchorSideRight.Control = TimeEdit Left = 7 Height = 16 Top = 5 @@ -35,7 +35,7 @@ object MainForm: TMainForm BorderSpacing.Left = 5 BorderSpacing.Right = 2 Caption = 'Minutes:' - FocusControl = Minutes + FocusControl = TimeEdit Layout = tlCenter ParentColor = False ParentFont = False @@ -181,7 +181,7 @@ object MainForm: TMainForm Left = 112 Height = 25 Hint = 'Pause' - Top = 2 + Top = 0 Width = 25 OnClick = ToggleCountdown ParentShowHint = False @@ -434,7 +434,7 @@ object MainForm: TMainForm } Visible = False end - object Minutes: TSpinEdit + object TimeEdit: TSpinEdit AnchorSideLeft.Side = asrBottom Left = 59 Height = 23 @@ -443,7 +443,7 @@ object MainForm: TMainForm BorderSpacing.Right = 5 Increment = 5 MaxValue = 5999 - OnChange = MinutesChanged + OnChange = TimeEditChanged ParentFont = False TabOrder = 0 end @@ -472,13 +472,6 @@ object MainForm: TMainForm TabOrder = 1 Transparent = False end - object Timer1: TTimer - Enabled = False - OnTimer = Countdown - OnStartTimer = Countdown - Left = 192 - Top = 160 - end object TrayIconMain: TTrayIcon BalloonFlags = bfInfo PopUpMenu = TrayMenu diff --git a/ui/mainform1.pas b/ui/mainform1.pas index 0be36fa..08ffc1c 100644 --- a/ui/mainform1.pas +++ b/ui/mainform1.pas @@ -6,12 +6,10 @@ interface uses Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, - Menus, StdCtrls, Spin, ExtCtrls, About, LCLType, Options, MMSystem, - Windows, DateUtils, MyTimer; + Menus, StdCtrls, Spin, ExtCtrls, About, LCLType, Options, Windows, DateUtils, + MyTimer; type - TMode = (Timer, Stopwatch); - { TMainForm } TMainForm = class(TForm) ImgIconMain: TImage; @@ -44,46 +42,39 @@ TMainForm = class(TForm) MenuEdit: TMenuItem; TrayMenu: TPopupMenu; TimeLabel: TLabel; - Minutes: TSpinEdit; + TimeEdit: TSpinEdit; Count: TStaticText; - Timer1: TTimer; TrayIconMain: TTrayIcon; procedure OnCreateForm(Sender: TObject); procedure OnDestroyForm(Sender: TObject); procedure OnShowForm(Sender: TObject); procedure FormActivate(Sender: TObject); - procedure ToggleCompact(Sender: TObject); - procedure MinutesChanged(Sender: TObject); - procedure ShowAbout(Sender: TObject); + procedure FormWindowStateChange(Sender: TObject); + procedure FormKeyPress(Sender: TObject; var Key: char); procedure CloseApp(Sender: TObject); - procedure Countdown(Sender: TObject); - procedure ResetCountdown(Sender: TObject); - procedure DisableTimer(); - procedure EnableTimer(); - procedure SetTimer(); - procedure ShowOptions(Sender: TObject); + procedure ToggleCountdown(Sender: TObject); - procedure FormKeyPress(Sender: TObject; var Key: char); - procedure FormWindowStateChange(Sender: TObject); + procedure ResetCountdown(Sender: TObject); + + procedure OnTick(Sender: TObject); + procedure OnTimerStateChanged(Sender: TObject); + procedure UpdateButtonsAndMenus; procedure UpdateTime(); + + procedure ToggleCompact(Sender: TObject); + procedure TimeEditChanged(Sender: TObject); + procedure ShowAbout(Sender: TObject); + procedure ShowOptions(Sender: TObject); procedure SaveSettings(Sender: TObject); - procedure PlayAudio(Path: string; Loop: boolean); - procedure StopAudio(); procedure ShowDoneMessage(Msg: string); procedure ShowTrayMessage(Msg: string); procedure SetFieldsVisible(showFields: boolean); procedure PlayTicking(); private - { private declarations } MyTimer : TMyTimer; - AudioPlaying: boolean; - Mode: TMode; FontSizeChanged : boolean; //FormerWidth : integer; //FormerHeight : integer; - EndTime: TDateTime; - StartTime: TDateTime; - CountdownDone: boolean; OnShowFormFirstTime: Boolean; procedure ApplyConfig; public @@ -133,6 +124,8 @@ procedure TMainForm.OnCreateForm(Sender: TObject); Config: TConfig; begin MyTimer:= TMyTimer.Create; + MyTimer.OnSecondElapsed:= @OnTick; + MyTimer.OnStateChanged:= @OnTimerStateChanged; Config:= GetConfig; MenuFile.Caption := MENU_FILE; MenuToggle.Caption := BTN_START; @@ -151,12 +144,8 @@ procedure TMainForm.OnCreateForm(Sender: TObject); // Set all defaults, then load from .ini - Mode := Timer; - AudioPlaying := False; Self.DoubleBuffered := True; Count.DoubleBuffered := True; - Timer1.Interval := 150; - CountdownDone := False; OnShowFormFirstTime:= True; //AppName := ExtractFileName(Application.ExeName); @@ -183,16 +172,15 @@ procedure TMainForm.OnCreateForm(Sender: TObject); Exit; end; - // Use minutes argument if it's the only parameter and it's numeric + // Use TimeEdit argument if it's the only parameter and it's numeric if (ParamCount = 1) and (TUtils.IsInteger(ParamStr(1))) then - Minutes.Value := StrToInt(ParamStr(1)); + TimeEdit.Value := StrToInt(ParamStr(1)); - //UpdateTimeCaption(SecondsMode); ApplyConfig will do this - ResetCountdown(Sender); if Config.AutoStart then ToggleCountdown(Sender); end; + procedure TMainForm.OnDestroyForm(Sender: TObject); begin if GetConfig.AutoSave then @@ -205,9 +193,9 @@ procedure TMainForm.OnShowForm(Sender: TObject); begin OnShowFormFirstTime:= False; ApplyConfig; - // ApplyConfig does not set MainForm dimensions and - Minutes.Value:= GetConfig.Minutes; - // TODO count value? + // ApplyConfig does not set MainForm dimensions and TimeEdit(TSpinEdit) + TimeEdit.Value:= GetConfig.Minutes; + MyTimer.Reset; // This will trigger OnTimerStateChanged end; // TODO Get this working for window size (getpreferred size gets form, not window) @@ -246,8 +234,6 @@ procedure TMainForm.OnShowForm(Sender: TObject); //ShowMessageFmt('width: %d, height: %d', [w, h]); //exit; end; - - //UpdateAlwaysOnTop(AlwaysOnTop); end; procedure TMainForm.FormActivate(Sender: TObject); @@ -257,49 +243,157 @@ procedure TMainForm.FormActivate(Sender: TObject); Show; end; +procedure TMainForm.FormWindowStateChange(Sender: TObject); +begin + if not GetConfig.MinToTray then + Exit; + + if WindowState = wsMinimized then + begin + WindowState := wsNormal; + ShowInTaskBar := stNever; + Hide; + end; +end; + +procedure TMainForm.FormKeyPress(Sender: TObject; var Key: char); +begin + // TMainForm's KeyPreview property must be set to True for this to work. + if key = #27 then + Close; // 27 = Escape + if (TimeEdit.Focused) and (key = #13) then + ToggleCountdown(Sender); +end; + +procedure TMainForm.CloseApp(Sender: TObject); +begin + OnDestroyForm(Sender); + Close; +end; + + +procedure TMainForm.ToggleCountdown(Sender: TObject); +begin + if (Sender.ClassName = Count.ClassName) and (not GetConfig.ClickTime) then + Exit; + + // We want to go from `Finished` state directly to `Running` state. (or not?) + if MyTimer.State = TState.Finished then + MyTimer.Reset; + + MyTimer.Toggle; +end; + procedure TMainForm.ResetCountdown(Sender: TObject); begin if (Sender.ClassName = Count.ClassName) and (not GetConfig.DblClickTime) then Exit; - // Turn off both looping audio and ticking - StopAudio(); - DisableTimer(); - SetTimer(); - TrayIconMain.Icon := ImgIconMain.Picture.Icon; + + MyTimer.Reset; end; -procedure TMainForm.DisableTimer(); +procedure TMainForm.OnTick(Sender: TObject); begin - Timer1.Enabled := False; - ImgPause.Visible := False; - ImgStart.Visible := True; - MenuToggle.Caption := BTN_START; - TrayMenuToggle.Caption := BTN_START; - StopAudio(); + UpdateTime(); +end; + +procedure TMainForm.OnTimerStateChanged(Sender: TObject); +var Config: TConfig; +begin + Config:= GetConfig; + + case MyTimer.State of + Ready: + begin + if Config.SecondsMode then + MyTimer.Seconds := TimeEdit.Value + else + MyTimer.Minutes:= TimeEdit.Value; + UpdateTime(); + UpdateButtonsAndMenus; + TrayIconMain.Icon:= ImgIconMain.Picture.Icon; + end; + + Running: + begin + UpdateButtonsAndMenus; + TrayIconMain.Icon:= ImgIconRunning.Picture.Icon; + if Config.TickingOn then + TUtils.PlayAudio('.\sounds\ticking\ticking.wav', True); + end; + + Paused: + begin + UpdateButtonsAndMenus; + TrayIconMain.Icon:= ImgIconPaused.Picture.Icon; + TUtils.StopAudio; + end; + + Finished: + begin + UpdateTime(); + UpdateButtonsAndMenus; + TUtils.StopAudio; + + Application.Title := APP_NAME; + if Config.DoneAudioEnabled then + TUtils.PlayAudio(Config.DoneAudio, Config.LoopAudio); + if Config.DoneAppEnabled then + TUtils.RunApp(Config.DoneApp); + if Config.DoneTrayMsgEnabled then + ShowTrayMessage(Config.DoneTrayMsg); + if Config.DoneMessageEnabled then + ShowDoneMessage(Config.DoneMessage); + if Config.AutoRestart then + ToggleCountdown(Sender) + else + TrayIconMain.Icon := ImgIconDone.Picture.Icon; + end; + end; end; -procedure TMainForm.EnableTimer(); +// When it comes to buttons and menus, there are only two states. +procedure TMainForm.UpdateButtonsAndMenus; begin - Timer1.Enabled := True; - ImgPause.Visible := True; - ImgStart.Visible := False; - MenuToggle.Caption := BTN_PAUSE; - TrayMenuToggle.Caption := BTN_PAUSE; - TrayIconMain.Icon := ImgIconRunning.Picture.Icon; - - if GetConfig.TickingOn then - PlayTicking(); + if MyTimer.State = TState.Running then + begin + ImgPause.Visible := True; + ImgStart.Visible := False; + MenuToggle.Caption := BTN_PAUSE; + TrayMenuToggle.Caption := BTN_PAUSE; + end + else + begin + ImgPause.Visible := False; + ImgStart.Visible := True; + MenuToggle.Caption := BTN_START; + TrayMenuToggle.Caption := BTN_START; + end; end; -procedure TMainForm.SetTimer(); +// TODO Animate icon between alarm icon and main so it blinks every second +// Instead of playing icon, animate the clock hands so they go around? +// http://delphi.about.com/od/kbwinshell/l/aa122501a.htm +procedure TMainForm.UpdateTime(); begin - if GetConfig.SecondsMode then - Timer1.Tag := Minutes.Value + // Changing caption while it's not visible keeps time from flashing + Count.Visible := False; + Count.Caption := TUtils.SecondsToTime(MyTimer.Seconds, GetConfig.HideSeconds); + Count.Visible := True; + MenuCount.Caption := Count.Caption; + if MyTimer.State = TState.Running then + begin + Application.Title := Count.Caption + ' - ' + APP_NAME; + TrayIconMain.Hint := Count.Caption; + end else - Timer1.Tag := Minutes.Value * 60; - UpdateTime(); + begin + Application.Title := APP_NAME; + TrayIconMain.Hint := APP_NAME; + end; end; + procedure TMainForm.ShowOptions(Sender: TObject); var Config: TConfig; @@ -330,12 +424,12 @@ procedure TMainForm.ShowOptions(Sender: TObject); // TODO Get font colors and background color to be shown - what's up? //if FontSizeChanged then OnShowForm(Sender); - if Timer1.Enabled then + if MyTimer.State = TState.Running then begin if Config.TickingOn then PlayTicking else - StopAudio(); + TUtils.StopAudio; end; if Config.AutoSave then @@ -346,83 +440,6 @@ procedure TMainForm.ShowOptions(Sender: TObject); end; end; -procedure TMainForm.ToggleCountdown(Sender: TObject); -begin - if (Sender.ClassName = Count.ClassName) and (not GetConfig.ClickTime) then - Exit; - - if Minutes.Value = 0 then - begin - Mode := Stopwatch; - StartTime := Now - (Timer1.Tag * OneSecond); - end - else - begin - Mode := Timer; - EndTime := Now + (Timer1.Tag * OneSecond); - end; - - if Timer1.Enabled then - begin - TrayIconMain.Icon := ImgIconPaused.Picture.Icon; - DisableTimer(); - end - else - begin - if CountdownDone then - begin - // TODO When restarting after countdown has elapsed, quickly jumps from - // starting number to next one - fix? - CountdownDone := False; - ResetCountdown(Sender); - EndTime := Now + (Timer1.Tag * OneSecond); - end; - EnableTimer(); - end -end; - -procedure TMainForm.Countdown(Sender: TObject); -var Config: TConfig; -begin - Config:= GetConfig; - if MODE = Stopwatch then - begin - Timer1.Tag := SecondsBetween(StartTime, Now); - UpdateTime(); - end - else - begin - if EndTime <= Now then - begin - Timer1.Tag := 0; - UpdateTime(); - DisableTimer(); - CountdownDone := True; - Application.Title := APP_NAME; - if Config.DoneAudioEnabled then - PlayAudio(Config.DoneAudio, Config.LoopAudio); - if Config.DoneAppEnabled then - TUtils.RunApp(Config.DoneApp); - if Config.DoneTrayMsgEnabled then - ShowTrayMessage(Config.DoneTrayMsg); - if Config.DoneMessageEnabled then - ShowDoneMessage(Config.DoneMessage); - - if Config.AutoRestart then - ToggleCountdown(Sender) - else - TrayIconMain.Icon := ImgIconDone.Picture.Icon; - end - else - UpdateTime(); - Timer1.Tag := SecondsBetween(EndTime, Now); - end; -end; - -{procedure TMainForm.Countdown(Sender: TObject); -var Config: TConfig; -begin -end;} procedure TMainForm.ShowAbout(Sender: TObject); var @@ -434,7 +451,6 @@ procedure TMainForm.ShowAbout(Sender: TObject); end; - procedure TMainForm.SaveSettings(Sender: TObject); var Config: TConfig; @@ -443,7 +459,7 @@ procedure TMainForm.SaveSettings(Sender: TObject); Config:= GetConfig; // These config values are not set in OptionsForm. - Config.Minutes:= Minutes.Value; + Config.Minutes:= TimeEdit.Value; GetWindowRect(self.Handle, wRect); Config.WndWidth:= wRect.Right - wRect.Left; Config.WndHeight:= wRect.Bottom - wRect.Top; @@ -454,9 +470,9 @@ procedure TMainForm.SaveSettings(Sender: TObject); MessageDlg(MSG_WRITE_INI, mtError, [mbOK], 0); end; -procedure TMainForm.MinutesChanged(Sender: TObject); +procedure TMainForm.TimeEditChanged(Sender: TObject); begin - if not Timer1.Enabled then + if (MyTimer.State <> TState.Running) and (MyTimer.State <> TState.Paused) then ResetCountdown(Sender); end; @@ -467,104 +483,6 @@ procedure TMainForm.ToggleCompact(Sender: TObject); // CompactMode := not CompactMode; end; - // TODO Figure out how to remove the fields from the form so they don't - // take up space anymore (and count can expand to top) - // Easier to create a new form, hide this one and show the other one - // Set border style to none too. -procedure TMainForm.SetFieldsVisible(showFields: boolean); -begin - if showFields then - begin - MainForm.Menu := MainMenu1; - end - else - begin - MainForm.Menu := nil; - TimeLabel.Visible := showFields; - Minutes.Visible := showFields; - ImgStart.Visible := showFields; - ImgReset.Visible := showFields; - ImgPause.Visible := showFields; - end; -end; - -procedure TMainForm.CloseApp(Sender: TObject); -begin - OnDestroyForm(Sender); - Close; -end; - - -procedure TMainForm.FormKeyPress(Sender: TObject; var Key: char); -begin - // TMainForm's KeyPreview property must be set to True for this to work. - if key = #27 then - Close; // 27 = Escape - if (Minutes.Focused) and (key = #13) then - ToggleCountdown(Sender); -end; - - // TODO Animate icon between alarm icon and main so it blinks every second - // Instead of playing icon, animate the clock hands so they go around? - // http://delphi.about.com/od/kbwinshell/l/aa122501a.htm -procedure TMainForm.UpdateTime(); -begin - // Changing caption while it's not visible keeps time from flashing - Count.Visible := False; - Count.Caption := TUtils.SecondsToTime(Timer1.Tag, GetConfig.HideSeconds); - Count.Visible := True; - MenuCount.Caption := Count.Caption; - if Timer1.Enabled then - begin - Application.Title := Count.Caption + ' - ' + APP_NAME; - TrayIconMain.Hint := Count.Caption; - end - else - begin - Application.Title := APP_NAME; - TrayIconMain.Hint := APP_NAME; - end; -end; - -procedure TMainForm.FormWindowStateChange(Sender: TObject); -begin - if not GetConfig.MinToTray then - Exit; - - if WindowState = wsMinimized then - begin - WindowState := wsNormal; - ShowInTaskBar := stNever; - Hide; - end; -end; - - - -procedure TMainForm.PlayAudio(Path: string; Loop: boolean); -begin - if AudioPlaying then - Exit; - if Loop then - begin - AudioPlaying := True; - sndPlaySound(PChar(TUtils.GetFilePath(Path)), SND_NODEFAULT or SND_ASYNC or SND_LOOP); - end - else - sndPlaySound(PChar(TUtils.GetFilePath(Path)), SND_NODEFAULT or SND_ASYNC); -end; - -procedure TMainForm.StopAudio(); -begin - sndPlaySound(nil, 0); - AudioPlaying := False; -end; - -procedure TMainForm.PlayTicking(); -begin - sndPlaySound(PChar(TUtils.GetFilePath('.\sounds\ticking\ticking.wav')), SND_NODEFAULT or - SND_ASYNC or SND_LOOP); -end; procedure TMainForm.ShowTrayMessage(Msg: string); begin @@ -581,9 +499,38 @@ procedure TMainForm.ShowDoneMessage(Msg: string); // http://msdn.microsoft.com/en-us/library/ms645505(VS.85).aspx Windows.MessageBox(self.Handle, pChar(msg), 'Done', MB_SYSTEMMODAL or MB_SETFOREGROUND or MB_TOPMOST or MB_ICONINFORMATION); - StopAudio(); + TUtils.StopAudio; +end; + +// TODO Figure out how to remove the fields from the form so they don't +// take up space anymore (and count can expand to top) +// Easier to create a new form, hide this one and show the other one +// Set border style to none too. +procedure TMainForm.SetFieldsVisible(showFields: boolean); +begin + if showFields then + begin + MainForm.Menu := MainMenu1; + end + else + begin + MainForm.Menu := nil; + TimeLabel.Visible := showFields; + TimeEdit.Visible := showFields; + ImgStart.Visible := showFields; + ImgReset.Visible := showFields; + ImgPause.Visible := showFields; + end; end; + + +procedure TMainForm.PlayTicking(); +begin + TUtils.PlayAudio('.\sounds\ticking\ticking.wav', True); +end; + + procedure TMainForm.ApplyConfig; var Config: TConfig; @@ -592,14 +539,14 @@ procedure TMainForm.ApplyConfig; begin Config:= GetConfig; if Config.AlwaysOnTop then - FormStyle:= fsSystemStayOnTop + FormStyle:= fsSystemStayOnTop else - FormStyle:= fsNormal; + FormStyle:= fsNormal; if Config.SecondsMode then - TimeLabel.Caption := LBL_SECONDS + TimeLabel.Caption := LBL_SECONDS else - TimeLabel.Caption := LBL_MINUTES; + TimeLabel.Caption := LBL_MINUTES; Count.Font.Quality := fqAntialiased; Count.Font.Name := Config.Font.Name; diff --git a/ui/options.pas b/ui/options.pas index a08d236..92258d7 100644 --- a/ui/options.pas +++ b/ui/options.pas @@ -312,8 +312,8 @@ procedure TOptionsForm.SetFontDefaults(Sender: TObject); procedure TOptionsForm.TestAudio(Sender: TObject); begin -with Self.Owner as TMainForm do - PlayAudio(NotifyAudio.Text, False); + with Self.Owner as TMainForm do + TUtils.PlayAudio(NotifyAudio.Text, False); end; procedure TOptionsForm.TestMessage(Sender: TObject); From 7ba843dc4fa05179c87998d3cf2cb2c0e6131236 Mon Sep 17 00:00:00 2001 From: neo85 Date: Thu, 18 Feb 2021 18:29:08 +0100 Subject: [PATCH 8/8] minor fixes --- snaptimer.lps | 145 ++++++++++++++++++++++++++--------------------- ui/mainform1.pas | 8 +-- 2 files changed, 84 insertions(+), 69 deletions(-) diff --git a/snaptimer.lps b/snaptimer.lps index 7884853..6dfeb25 100644 --- a/snaptimer.lps +++ b/snaptimer.lps @@ -4,7 +4,7 @@ - + @@ -40,8 +40,8 @@ - - + + @@ -63,7 +63,7 @@ - + @@ -78,10 +78,9 @@ - + - @@ -147,8 +146,8 @@ - - + + @@ -161,8 +160,8 @@ - - + + @@ -226,11 +225,10 @@ - + - @@ -254,128 +252,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - - + + - + - - + + - - + + - - + + - - + + - - + + - + - + - + - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - + - + - + - + - + - + - - - - - - - - - - - - diff --git a/ui/mainform1.pas b/ui/mainform1.pas index 08ffc1c..c94348d 100644 --- a/ui/mainform1.pas +++ b/ui/mainform1.pas @@ -319,7 +319,7 @@ procedure TMainForm.OnTimerStateChanged(Sender: TObject); UpdateButtonsAndMenus; TrayIconMain.Icon:= ImgIconRunning.Picture.Icon; if Config.TickingOn then - TUtils.PlayAudio('.\sounds\ticking\ticking.wav', True); + PlayTicking(); end; Paused: @@ -345,9 +345,9 @@ procedure TMainForm.OnTimerStateChanged(Sender: TObject); if Config.DoneMessageEnabled then ShowDoneMessage(Config.DoneMessage); if Config.AutoRestart then - ToggleCountdown(Sender) - else - TrayIconMain.Icon := ImgIconDone.Picture.Icon; + ToggleCountdown(Sender) + else + TrayIconMain.Icon := ImgIconDone.Picture.Icon; end; end; end;