From e3fc3be38f803fcdb53f66756dcf625e69dc25cd Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 7 Dec 2020 22:15:46 +0300 Subject: [PATCH 01/31] Multiple monitors fix (issue #4) --- docs/README-ru.md | 3 ++- docs/README.md | 3 ++- uAutoScreen.pas | 17 +++++++++++++---- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/docs/README-ru.md b/docs/README-ru.md index f5a16c7..8e21da6 100644 --- a/docs/README-ru.md +++ b/docs/README-ru.md @@ -1,4 +1,4 @@ -Auto Screenshot +Auto Screenshot =============== [![GitHub release (latest by date)](https://img.shields.io/github/v/release/artem78/AutoScreenshot?style=plastic)](https://github.com/artem78/AutoScreenshot/releases/latest)   [![GitHub license](https://img.shields.io/github/license/artem78/AutoScreenshot?style=plastic)](https://github.com/artem78/AutoScreenshot/blob/master/LICENSE.txt) @@ -14,6 +14,7 @@ * Возможность приостановки захвата при бездействии пользователя (определяется по движениям мыши и нажатиям клавиш) * Настраиваемые имена выходных файлов с использованием переменных (дата, время, название компьютера/пользователя) и возможностью группировки по папкам (например, по дням или месяцам) * Возможность автоматического запуска вместе с Windows +* Захват с нескольких экранов ## Снимки экрана ![](images/main_window_ru.png "Основное окно программы") diff --git a/docs/README.md b/docs/README.md index 597e7fa..af4e76a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,4 @@ -[![Russian](images/russian_icon.png) RU](README-ru.md "Russian") +[![Russian](images/russian_icon.png) RU](README-ru.md "Russian") ------------------------- @@ -16,6 +16,7 @@ Auto Screenshot * Pause capture when user is inactive (depending on mouse moves and keyboard events) * Customizable output filenames with variables (date, time, user, computer name) and ability of grouping by folders (for example: by day or month) * Automatic capture can be started on Windows startup +* Multiple screens support ## Screenshots ![](images/main_window.png "Main program window") diff --git a/uAutoScreen.pas b/uAutoScreen.pas index 54ea517..7f494c8 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -406,6 +406,9 @@ procedure TMainForm.MakeScreenshot; JPG: TJPEGImage; GIF: TGIFImage; ScreenDC: HDC; + ScreenWidth, ScreenHeight: Integer; + ScreenX, ScreenY: Integer; + //Rect: TRect; begin Bitmap := TBitmap.Create; @@ -424,11 +427,17 @@ procedure TMainForm.MakeScreenshot; // Leave bitmap pixel format as default end; - Bitmap.Width := Screen.Width; - Bitmap.Height := Screen.Height; + ScreenWidth := GetSystemMetrics(SM_CXVIRTUALSCREEN); + ScreenHeight := GetSystemMetrics(SM_CYVIRTUALSCREEN); + ScreenX := GetSystemMetrics(SM_XVIRTUALSCREEN); + ScreenY := GetSystemMetrics(SM_YVIRTUALSCREEN); + //Rect := GetClientRect(0); + + Bitmap.Width := ScreenWidth; + Bitmap.Height := ScreenHeight; ScreenDC := GetDC(0); - BitBlt(Bitmap.Canvas.Handle, 0, 0, Screen.Width, Screen.Height, - ScreenDC, 0, 0, SRCCOPY); + BitBlt(Bitmap.Canvas.Handle, 0, 0, ScreenWidth, ScreenHeight, + ScreenDC, ScreenX, ScreenY, SRCCOPY); ReleaseDC(0, ScreenDC); TrayIconState := tisFlashAnimation; From c29ab7df7bc257f033b1fa48e2e16884c5bffdd8 Mon Sep 17 00:00:00 2001 From: Artem Date: Tue, 8 Dec 2020 20:58:00 +0300 Subject: [PATCH 02/31] Snap bottom components to the form bottom --- uAutoScreen.dfm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/uAutoScreen.dfm b/uAutoScreen.dfm index ddf45ac..0ad3cd6 100755 --- a/uAutoScreen.dfm +++ b/uAutoScreen.dfm @@ -16,6 +16,9 @@ object MainForm: TMainForm Position = poScreenCenter OnCreate = FormCreate OnDestroy = FormDestroy + DesignSize = ( + 633 + 328) PixelsPerInch = 96 TextHeight = 15 object OutputDirLabel: TTntLabel @@ -95,6 +98,7 @@ object MainForm: TMainForm Top = 276 Width = 121 Height = 25 + Anchors = [akLeft, akBottom] Caption = 'Take screenshot' TabOrder = 14 OnClick = TakeScreenshotButtonClick @@ -161,6 +165,7 @@ object MainForm: TMainForm Top = 248 Width = 281 Height = 65 + Anchors = [akLeft, akBottom] Caption = 'Automatic capture' TabOrder = 17 object StartAutoCaptureButton: TTntBitBtn @@ -191,6 +196,7 @@ object MainForm: TMainForm Top = 272 Width = 97 Height = 25 + Anchors = [akLeft, akBottom] Caption = 'About' TabOrder = 16 OnClick = AboutButtonClick From 5ea4995f0d8215b96f8dc3804bb7d437dd57ff71 Mon Sep 17 00:00:00 2001 From: Artem Date: Tue, 8 Dec 2020 21:02:13 +0300 Subject: [PATCH 03/31] [Settings] Add choose of captured area for multiple monitors (all or only primary) --- lang/en.ini | Bin 3002 -> 3258 bytes lang/ru.ini | Bin 3172 -> 3438 bytes uAutoScreen.dfm | 31 +++++++++++++++++++++---- uAutoScreen.pas | 59 ++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 81 insertions(+), 9 deletions(-) diff --git a/lang/en.ini b/lang/en.ini index 359e20182b13b1a50da3169766ecd59fdd2af29d..aced6ac6cdbfd3e8c23c15a3015a6016e86e39a2 100644 GIT binary patch delta 255 zcmdlbzDsh04VSksLn%WJLkUABLjjOZW$l8SL85MG6Vo!kqNXZ5lB~}nFVqy#BDIu W3UWYiAZtJ~eDZ%T(akq4?hGH;31t@OIAkJdI;>uzK zB%N3k7#xAvmc^9Ck;RI|j>VeA2S{50=@nWk>|lm1stSoDOlS65L53b3snE1DXwS5QsDe S+Xr&! 'all') and (MultipleMonitorsMode <> 'primary') then + MultipleMonitorsMode := DefaultMultipleMonitorsMode; + if MultipleMonitorsMode = 'all' then + MultipleMonitorsModeComboBox.ItemIndex := 0 + else if MultipleMonitorsMode = 'primary' then + MultipleMonitorsModeComboBox.ItemIndex := 1; end; procedure TMainForm.FormCreate(Sender: TObject); @@ -427,10 +442,24 @@ procedure TMainForm.MakeScreenshot; // Leave bitmap pixel format as default end; - ScreenWidth := GetSystemMetrics(SM_CXVIRTUALSCREEN); - ScreenHeight := GetSystemMetrics(SM_CYVIRTUALSCREEN); - ScreenX := GetSystemMetrics(SM_XVIRTUALSCREEN); - ScreenY := GetSystemMetrics(SM_YVIRTUALSCREEN); + case MultipleMonitorsModeComboBox.ItemIndex of + 1: // Only primary screen + begin + ScreenWidth := Screen.Width; + ScreenHeight := ScreenHeight; + ScreenX := 0; + ScreenY := 0; + end; + + //0: + else // Full area + begin + ScreenWidth := GetSystemMetrics(SM_CXVIRTUALSCREEN); + ScreenHeight := GetSystemMetrics(SM_CYVIRTUALSCREEN); + ScreenX := GetSystemMetrics(SM_XVIRTUALSCREEN); + ScreenY := GetSystemMetrics(SM_YVIRTUALSCREEN); + end; + end; //Rect := GetClientRect(0); Bitmap.Width := ScreenWidth; @@ -677,6 +706,8 @@ procedure TMainForm.SetLanguageByCode(LangCode: String); end; procedure TMainForm.TranslateForm; +var + Idx: Integer; begin // Main form LanguageRadioGroup.Caption := I18N('Language'); @@ -699,6 +730,17 @@ procedure TMainForm.TranslateForm; StartCaptureOnStartUpCheckBox.Caption := I18N('StartCaptureOnStartUp'); StartMinimizedCheckBox.Caption := I18N('StartMinimized'); AutoRunCheckBox.Caption := I18N('AutoRun'); + MultipleMonitorsModeLabel.Caption := I18N('MultipleMonitorsMode') + ':'; + with MultipleMonitorsModeComboBox do + begin + Idx := ItemIndex; + + Items.Strings[0] := I18N('AllMonitorsMode'); + Items.Strings[1] := I18N('OnlyPrimaryMonitorMode'); + + // Restore previous selected item after strings updated + ItemIndex := Idx; + end; // Tray icon RestoreWindowTrayMenuItem.Caption := I18N('Restore'); @@ -906,4 +948,13 @@ procedure TMainForm.AutoRunCheckBoxClick(Sender: TObject); Ini.WriteBool(DefaultConfigIniSection, 'AutoRun', AutoRunEnabled); end; +procedure TMainForm.MultipleMonitorsModeComboBoxChange(Sender: TObject); +begin + case MultipleMonitorsModeComboBox.ItemIndex of + 0: Ini.WriteString(DefaultConfigIniSection, 'MultipleMonitorsMode', 'all'); + 1: Ini.WriteString(DefaultConfigIniSection, 'MultipleMonitorsMode', 'primary'); + end; +end; + end. + From 233503da3156423f7758533b59bdef0324a63029 Mon Sep 17 00:00:00 2001 From: Artem Date: Sat, 12 Dec 2020 22:58:06 +0300 Subject: [PATCH 04/31] Remake multiscreen --- lang/en.ini | Bin 3258 -> 3238 bytes lang/ru.ini | Bin 3438 -> 3414 bytes uAutoScreen.dfm | 12 +++--- uAutoScreen.pas | 112 ++++++++++++++++++++++++++++++------------------ 4 files changed, 76 insertions(+), 48 deletions(-) diff --git a/lang/en.ini b/lang/en.ini index aced6ac6cdbfd3e8c23c15a3015a6016e86e39a2..86ba5e883b1bd39a9390f8f12814e80892d268e3 100644 GIT binary patch delta 227 zcmdlbxlD3{4VQi>Loq`tLkfd0Lq0>s5CC*yCeUGt VK)Mp>i~?l-$q)cEITNTm5lB~}*$CAGv=63Q R0q8Ph^=S5PR_1PI1ONwFE0X{K diff --git a/lang/ru.ini b/lang/ru.ini index 40615f8bebbd8cb48fde485c0db01a179539d00f..2f9d329437a820fa8c2637361acce4c2cb20d582 100644 GIT binary patch delta 233 zcmaDSbxmr+BQEPuhGK?Ph7<;0hJ1!RhD?SMAYH^@%OJtx$YRf8$70Rm!(z_j%wo!7 z!{W_i$)dpE%VNdiz+%8+JK2$2y51A0D-Ec}mO%)p!xUK_s9u3VgFzK&x&lK55QA8n z47?0nXtp8D(1n=|)G4M2(TUxJ0H7-~8FD2U5`m0Lp!Ie@>urG!HUg8DlQ;5+ZvMkv G#0UUowI-JU delta 244 zcmca6^-gNTBd&N~hEj$ch7yKMh5{g+%HYe8&yWY?l>q4?hGH;31t@OIAkJdI;>uzK zB%N3k7#xAvmc^9Ck;RI|j>VeA2S{503Wcv5Hl2kVhRjK zKwYMoYFT(0xETC_w&yTZG6Vo^&t%ADNCeWAXs$w-rv$efWG=`}c0jYiHiJoHkbRRE Mvj}d!!rjCO02`$$5dZ)H diff --git a/uAutoScreen.dfm b/uAutoScreen.dfm index a1fe764..1cff46f 100755 --- a/uAutoScreen.dfm +++ b/uAutoScreen.dfm @@ -76,13 +76,13 @@ object MainForm: TMainForm Alignment = taRightJustify Caption = 'Color depth:' end - object MultipleMonitorsModeLabel: TLabel - Left = 8 + object MonitorLabel: TLabel + Left = 123 Top = 236 - Width = 193 + Width = 78 Height = 15 Alignment = taRightJustify - Caption = 'Captured area for multiple monitors:' + Caption = 'Used monitor:' end object OutputDirEdit: TTntEdit Left = 208 @@ -292,7 +292,7 @@ object MainForm: TMainForm TabOrder = 15 OnClick = AutoRunCheckBoxClick end - object MultipleMonitorsModeComboBox: TComboBox + object MonitorComboBox: TComboBox Left = 208 Top = 232 Width = 265 @@ -300,7 +300,7 @@ object MainForm: TMainForm Style = csDropDownList ItemHeight = 15 TabOrder = 18 - OnChange = MultipleMonitorsModeComboBoxChange + OnChange = MonitorComboBoxChange Items.Strings = ( '' '') diff --git a/uAutoScreen.pas b/uAutoScreen.pas index 8202a89..cf3e26c 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -66,8 +66,8 @@ TMainForm = class({TTntForm} TForm) CaptureInterval: TTntDateTimePicker; TrayIconAnimationTimer: TTimer; AutoRunCheckBox: TTntCheckBox; - MultipleMonitorsModeLabel: TLabel; - MultipleMonitorsModeComboBox: TComboBox; + MonitorLabel: TLabel; + MonitorComboBox: TComboBox; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure ChooseOutputDirButtonClick(Sender: TObject); @@ -96,7 +96,7 @@ TMainForm = class({TTntForm} TForm) procedure ColorDepthComboBoxChange(Sender: TObject); procedure TrayIconAnimationTimerTimer(Sender: TObject); procedure AutoRunCheckBoxClick(Sender: TObject); - procedure MultipleMonitorsModeComboBoxChange(Sender: TObject); + procedure MonitorComboBoxChange(Sender: TObject); private { Private declarations } FLanguage: TLanguage; @@ -124,6 +124,7 @@ TMainForm = class({TTntForm} TForm) procedure InitUI; procedure ReadSettings; procedure UpdateColorDepthValues; + procedure FillMonitorList; property IsTimerEnabled: Boolean read GetTimerEnabled write SetTimerEnabled; property FinalOutputDir: String read GetFinalOutputDir; @@ -211,7 +212,7 @@ procedure TMainForm.ReadSettings; DefaultJPEGQuality = 80; //DefaultLanguage = lngEnglish; DefaultColorDepth = cd24Bit; - DefaultMultipleMonitorsMode = 'all'; + DefaultMonitorId = -1; var DefaultOutputDir: String; SystemLanguageCode: String; @@ -219,7 +220,7 @@ procedure TMainForm.ReadSettings; FmtStr: String; LangCode: String; Seconds: Integer; - MultipleMonitorsMode: String; + MonitorId: Integer; begin DefaultOutputDir := IncludeTrailingPathDelimiter(JoinPath(ExtractFilePath(Application.ExeName), 'screenshots')); OutputDirEdit.Text := Ini.ReadString(DefaultConfigIniSection, 'OutputDir', DefaultOutputDir); @@ -297,14 +298,12 @@ procedure TMainForm.ReadSettings; RestoreFromTray; // Multiple monitors - MultipleMonitorsMode := Ini.ReadString(DefaultConfigIniSection, - 'MultipleMonitorsMode', DefaultMultipleMonitorsMode); - if (MultipleMonitorsMode <> 'all') and (MultipleMonitorsMode <> 'primary') then - MultipleMonitorsMode := DefaultMultipleMonitorsMode; - if MultipleMonitorsMode = 'all' then - MultipleMonitorsModeComboBox.ItemIndex := 0 - else if MultipleMonitorsMode = 'primary' then - MultipleMonitorsModeComboBox.ItemIndex := 1; + MonitorId := Ini.ReadInteger(DefaultConfigIniSection, 'Screen', DefaultMonitorId); + if MonitorId = -1 then + MonitorId := 0 + else + Inc(MonitorId, 1); + MonitorComboBox.ItemIndex := MonitorId; end; procedure TMainForm.FormCreate(Sender: TObject); @@ -424,6 +423,7 @@ procedure TMainForm.MakeScreenshot; ScreenWidth, ScreenHeight: Integer; ScreenX, ScreenY: Integer; //Rect: TRect; + UsedMonitor: TMonitor; begin Bitmap := TBitmap.Create; @@ -442,23 +442,23 @@ procedure TMainForm.MakeScreenshot; // Leave bitmap pixel format as default end; - case MultipleMonitorsModeComboBox.ItemIndex of - 1: // Only primary screen - begin - ScreenWidth := Screen.Width; - ScreenHeight := ScreenHeight; - ScreenX := 0; - ScreenY := 0; - end; - - //0: - else // Full area - begin + case MonitorComboBox.ItemIndex of + 0: + begin // All displays ScreenWidth := GetSystemMetrics(SM_CXVIRTUALSCREEN); ScreenHeight := GetSystemMetrics(SM_CYVIRTUALSCREEN); ScreenX := GetSystemMetrics(SM_XVIRTUALSCREEN); ScreenY := GetSystemMetrics(SM_YVIRTUALSCREEN); end; + + else // Only one display + begin + UsedMonitor := Screen.Monitors[MonitorComboBox.ItemIndex - 1]; + ScreenWidth := UsedMonitor.Width; + ScreenHeight := UsedMonitor.Height; + ScreenX := UsedMonitor.Left; + ScreenY := UsedMonitor.Top; + end; end; //Rect := GetClientRect(0); @@ -706,8 +706,6 @@ procedure TMainForm.SetLanguageByCode(LangCode: String); end; procedure TMainForm.TranslateForm; -var - Idx: Integer; begin // Main form LanguageRadioGroup.Caption := I18N('Language'); @@ -730,17 +728,8 @@ procedure TMainForm.TranslateForm; StartCaptureOnStartUpCheckBox.Caption := I18N('StartCaptureOnStartUp'); StartMinimizedCheckBox.Caption := I18N('StartMinimized'); AutoRunCheckBox.Caption := I18N('AutoRun'); - MultipleMonitorsModeLabel.Caption := I18N('MultipleMonitorsMode') + ':'; - with MultipleMonitorsModeComboBox do - begin - Idx := ItemIndex; - - Items.Strings[0] := I18N('AllMonitorsMode'); - Items.Strings[1] := I18N('OnlyPrimaryMonitorMode'); - - // Restore previous selected item after strings updated - ItemIndex := Idx; - end; + MonitorLabel.Caption := I18N('UsedMonitor') + ':'; + FillMonitorList; // Tray icon RestoreWindowTrayMenuItem.Caption := I18N('Restore'); @@ -948,11 +937,50 @@ procedure TMainForm.AutoRunCheckBoxClick(Sender: TObject); Ini.WriteBool(DefaultConfigIniSection, 'AutoRun', AutoRunEnabled); end; -procedure TMainForm.MultipleMonitorsModeComboBoxChange(Sender: TObject); +procedure TMainForm.MonitorComboBoxChange(Sender: TObject); +var + Idx: Integer; +begin + if MonitorComboBox.ItemIndex = 0 then // All screens + Idx := -1 + else + Idx := MonitorComboBox.ItemIndex - 1; + + Ini.WriteInteger(DefaultConfigIniSection, 'Screen', Idx); +end; + +procedure TMainForm.FillMonitorList; +var + Idx, SelIdx: Integer; + Str: String; + begin - case MultipleMonitorsModeComboBox.ItemIndex of - 0: Ini.WriteString(DefaultConfigIniSection, 'MultipleMonitorsMode', 'all'); - 1: Ini.WriteString(DefaultConfigIniSection, 'MultipleMonitorsMode', 'primary'); + with MonitorComboBox do + begin + SelIdx := ItemIndex; + + Items.Clear; + Items.Append(Format(I18N('AllMonitorsInfo'), + [GetSystemMetrics(SM_CXVIRTUALSCREEN), + GetSystemMetrics(SM_CYVIRTUALSCREEN)] + )); + + for Idx := 0 to Screen.MonitorCount - 1 do + begin + Str := Format(I18N('MonitorInfo'), + [Screen.Monitors[Idx].MonitorNum, + Screen.Monitors[Idx].Width, + Screen.Monitors[Idx].Height] + ); + // ToDo: Also may show screen model, diagonal size + if Screen.Monitors[Idx].Primary then + Str := Str + ' - ' + I18N('Primary'); + + Items.Append(Str); + end; + + // Restore previous selected item after strings updated + ItemIndex := SelIdx; end; end; From 8ea905ec0456b288eb49f8b639f2e27594e23556 Mon Sep 17 00:00:00 2001 From: Artem Date: Sun, 13 Dec 2020 17:36:20 +0300 Subject: [PATCH 05/31] Fill image background to black --- uAutoScreen.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/uAutoScreen.pas b/uAutoScreen.pas index cf3e26c..a0ec421 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -464,6 +464,8 @@ procedure TMainForm.MakeScreenshot; Bitmap.Width := ScreenWidth; Bitmap.Height := ScreenHeight; + Bitmap.Canvas.Brush.Color := clBlack; + Bitmap.Canvas.FillRect(Rect(0, 0, ScreenWidth, ScreenHeight)); ScreenDC := GetDC(0); BitBlt(Bitmap.Canvas.Handle, 0, 0, ScreenWidth, ScreenHeight, ScreenDC, ScreenX, ScreenY, SRCCOPY); From 89945964adcc24d34b1b8b2a3b973201d8360f93 Mon Sep 17 00:00:00 2001 From: Artem Date: Sun, 13 Dec 2020 17:51:32 +0300 Subject: [PATCH 06/31] Start monitors numeration from one instead zero --- uAutoScreen.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uAutoScreen.pas b/uAutoScreen.pas index a0ec421..cd5d43a 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -970,7 +970,7 @@ procedure TMainForm.FillMonitorList; for Idx := 0 to Screen.MonitorCount - 1 do begin Str := Format(I18N('MonitorInfo'), - [Screen.Monitors[Idx].MonitorNum, + [Screen.Monitors[Idx].MonitorNum + 1, // Start numeration from 1 Screen.Monitors[Idx].Width, Screen.Monitors[Idx].Height] ); From 5d6e41fe46d0110cf2fb87dd821fd0b769fad0b1 Mon Sep 17 00:00:00 2001 From: Artem Date: Sun, 13 Dec 2020 18:03:06 +0300 Subject: [PATCH 07/31] Fix Unicode encoding --- uAutoScreen.dfm | 4 ++-- uAutoScreen.pas | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/uAutoScreen.dfm b/uAutoScreen.dfm index 1cff46f..70237b6 100755 --- a/uAutoScreen.dfm +++ b/uAutoScreen.dfm @@ -76,7 +76,7 @@ object MainForm: TMainForm Alignment = taRightJustify Caption = 'Color depth:' end - object MonitorLabel: TLabel + object MonitorLabel: TTntLabel Left = 123 Top = 236 Width = 78 @@ -292,7 +292,7 @@ object MainForm: TMainForm TabOrder = 15 OnClick = AutoRunCheckBoxClick end - object MonitorComboBox: TComboBox + object MonitorComboBox: TTntComboBox Left = 208 Top = 232 Width = 265 diff --git a/uAutoScreen.pas b/uAutoScreen.pas index cd5d43a..32b578e 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -66,8 +66,8 @@ TMainForm = class({TTntForm} TForm) CaptureInterval: TTntDateTimePicker; TrayIconAnimationTimer: TTimer; AutoRunCheckBox: TTntCheckBox; - MonitorLabel: TLabel; - MonitorComboBox: TComboBox; + MonitorLabel: TTntLabel; + MonitorComboBox: TTntComboBox; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure ChooseOutputDirButtonClick(Sender: TObject); @@ -954,7 +954,7 @@ procedure TMainForm.MonitorComboBoxChange(Sender: TObject); procedure TMainForm.FillMonitorList; var Idx, SelIdx: Integer; - Str: String; + Str: WideString; begin with MonitorComboBox do @@ -962,14 +962,14 @@ procedure TMainForm.FillMonitorList; SelIdx := ItemIndex; Items.Clear; - Items.Append(Format(I18N('AllMonitorsInfo'), + Items.Append(WideFormat(I18N('AllMonitorsInfo'), [GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN)] )); for Idx := 0 to Screen.MonitorCount - 1 do begin - Str := Format(I18N('MonitorInfo'), + Str := WideFormat(I18N('MonitorInfo'), [Screen.Monitors[Idx].MonitorNum + 1, // Start numeration from 1 Screen.Monitors[Idx].Width, Screen.Monitors[Idx].Height] From 52231ef8b302c700c3e6e298aed89ff7d4b918a1 Mon Sep 17 00:00:00 2001 From: Artem Date: Sun, 13 Dec 2020 20:51:32 +0300 Subject: [PATCH 08/31] Refactoring --- uAutoScreen.pas | 85 ++++++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/uAutoScreen.pas b/uAutoScreen.pas index 32b578e..c5461f3 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -125,6 +125,8 @@ TMainForm = class({TTntForm} TForm) procedure ReadSettings; procedure UpdateColorDepthValues; procedure FillMonitorList; + procedure SetMonitorId(MonitorId: Integer); + function GetMonitorId: Integer; property IsTimerEnabled: Boolean read GetTimerEnabled write SetTimerEnabled; property FinalOutputDir: String read GetFinalOutputDir; @@ -133,6 +135,7 @@ TMainForm = class({TTntForm} TForm) property ImageFormat: TImageFormat read GetImageFormat write SetImageFormat; property ColorDepth: TColorDepth read GetColorDepth write SetColorDepth; property TrayIconState: TTrayIconState write SetTrayIconState; + property MonitorId: Integer read GetMonitorId write SetMonitorId; public { Public declarations } end; @@ -173,6 +176,7 @@ TMainForm = class({TTntForm} TForm) DefaultConfigIniSection = 'main'; MinCaptureIntervalInSeconds = 1; + NoMonitorId = -1; var MainForm: TMainForm; @@ -212,7 +216,7 @@ procedure TMainForm.ReadSettings; DefaultJPEGQuality = 80; //DefaultLanguage = lngEnglish; DefaultColorDepth = cd24Bit; - DefaultMonitorId = -1; + DefaultMonitorId = NoMonitorId; var DefaultOutputDir: String; SystemLanguageCode: String; @@ -220,7 +224,6 @@ procedure TMainForm.ReadSettings; FmtStr: String; LangCode: String; Seconds: Integer; - MonitorId: Integer; begin DefaultOutputDir := IncludeTrailingPathDelimiter(JoinPath(ExtractFilePath(Application.ExeName), 'screenshots')); OutputDirEdit.Text := Ini.ReadString(DefaultConfigIniSection, 'OutputDir', DefaultOutputDir); @@ -298,12 +301,11 @@ procedure TMainForm.ReadSettings; RestoreFromTray; // Multiple monitors - MonitorId := Ini.ReadInteger(DefaultConfigIniSection, 'Screen', DefaultMonitorId); - if MonitorId = -1 then - MonitorId := 0 - else - Inc(MonitorId, 1); - MonitorComboBox.ItemIndex := MonitorId; + try + MonitorId := Ini.ReadInteger(DefaultConfigIniSection, 'Screen', DefaultMonitorId); + except + MonitorId := DefaultMonitorId; + end; end; procedure TMainForm.FormCreate(Sender: TObject); @@ -442,23 +444,20 @@ procedure TMainForm.MakeScreenshot; // Leave bitmap pixel format as default end; - case MonitorComboBox.ItemIndex of - 0: - begin // All displays - ScreenWidth := GetSystemMetrics(SM_CXVIRTUALSCREEN); - ScreenHeight := GetSystemMetrics(SM_CYVIRTUALSCREEN); - ScreenX := GetSystemMetrics(SM_XVIRTUALSCREEN); - ScreenY := GetSystemMetrics(SM_YVIRTUALSCREEN); - end; - + if MonitorId = NoMonitorId then + begin // All displays + ScreenWidth := GetSystemMetrics(SM_CXVIRTUALSCREEN); + ScreenHeight := GetSystemMetrics(SM_CYVIRTUALSCREEN); + ScreenX := GetSystemMetrics(SM_XVIRTUALSCREEN); + ScreenY := GetSystemMetrics(SM_YVIRTUALSCREEN); + end else // Only one display - begin - UsedMonitor := Screen.Monitors[MonitorComboBox.ItemIndex - 1]; - ScreenWidth := UsedMonitor.Width; - ScreenHeight := UsedMonitor.Height; - ScreenX := UsedMonitor.Left; - ScreenY := UsedMonitor.Top; - end; + begin + UsedMonitor := Screen.Monitors[MonitorId]; + ScreenWidth := UsedMonitor.Width; + ScreenHeight := UsedMonitor.Height; + ScreenX := UsedMonitor.Left; + ScreenY := UsedMonitor.Top; end; //Rect := GetClientRect(0); @@ -940,26 +939,19 @@ procedure TMainForm.AutoRunCheckBoxClick(Sender: TObject); end; procedure TMainForm.MonitorComboBoxChange(Sender: TObject); -var - Idx: Integer; begin - if MonitorComboBox.ItemIndex = 0 then // All screens - Idx := -1 - else - Idx := MonitorComboBox.ItemIndex - 1; - - Ini.WriteInteger(DefaultConfigIniSection, 'Screen', Idx); + SetMonitorId(GetMonitorId); end; procedure TMainForm.FillMonitorList; var - Idx, SelIdx: Integer; + Idx, SelId: Integer; Str: WideString; - + begin with MonitorComboBox do begin - SelIdx := ItemIndex; + SelId := MonitorId; Items.Clear; Items.Append(WideFormat(I18N('AllMonitorsInfo'), @@ -982,9 +974,30 @@ procedure TMainForm.FillMonitorList; end; // Restore previous selected item after strings updated - ItemIndex := SelIdx; + if SelId <> -1 then + MonitorId := SelId; end; end; +function TMainForm.GetMonitorId: Integer; +begin + if MonitorComboBox.ItemIndex <= 0 then + Result := NoMonitorId + else + Result := MonitorComboBox.ItemIndex - 1; +end; + +procedure TMainForm.SetMonitorId(MonitorId: Integer); +begin + if MonitorId = NoMonitorId then + MonitorComboBox.ItemIndex := 0 + else if (MonitorId >= 0) and (MonitorId < {Screen.MonitorCount} MonitorComboBox.Items.Count) then + MonitorComboBox.ItemIndex := MonitorId + 1 + else + raise Exception.CreateFmt('Monitor id=%d not exists', [MonitorId]); + + Ini.WriteInteger(DefaultConfigIniSection, 'Screen', MonitorId); +end; + end. From 4f431f7d20571aefe346a047ddf12f2e58a230e3 Mon Sep 17 00:00:00 2001 From: Artem Date: Sun, 13 Dec 2020 20:51:54 +0300 Subject: [PATCH 09/31] Localization --- lang/ru.ini | Bin 3414 -> 3426 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/lang/ru.ini b/lang/ru.ini index 2f9d329437a820fa8c2637361acce4c2cb20d582..4051856a4b2ca3d51b8bf86dd8857ef2547f4ad6 100644 GIT binary patch delta 62 tcmca6^+;-i2sf_{iyezCiv^1lkan0X%dLwh63lJPD}$_Nb3gZSMgWWp3^@P* delta 50 qcmaDPbxmr62sfuMixrClivf%6WJPXWBwjSPF{ds}Zu4yJ Date: Sun, 13 Dec 2020 20:58:24 +0300 Subject: [PATCH 10/31] Rename parameter in config --- uAutoScreen.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uAutoScreen.pas b/uAutoScreen.pas index c5461f3..f14ba39 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -302,7 +302,7 @@ procedure TMainForm.ReadSettings; // Multiple monitors try - MonitorId := Ini.ReadInteger(DefaultConfigIniSection, 'Screen', DefaultMonitorId); + MonitorId := Ini.ReadInteger(DefaultConfigIniSection, 'Monitor', DefaultMonitorId); except MonitorId := DefaultMonitorId; end; @@ -996,7 +996,7 @@ procedure TMainForm.SetMonitorId(MonitorId: Integer); else raise Exception.CreateFmt('Monitor id=%d not exists', [MonitorId]); - Ini.WriteInteger(DefaultConfigIniSection, 'Screen', MonitorId); + Ini.WriteInteger(DefaultConfigIniSection, 'Monitor', MonitorId); end; end. From dcbac2f12a40f1c24264771a0ebd036a3c7a71ba Mon Sep 17 00:00:00 2001 From: Artem Date: Sun, 13 Dec 2020 21:15:51 +0300 Subject: [PATCH 11/31] [UI] Do not allow user to change monitor if computer have only one monitor --- uAutoScreen.pas | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/uAutoScreen.pas b/uAutoScreen.pas index f14ba39..aa0b9c6 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -301,11 +301,21 @@ procedure TMainForm.ReadSettings; RestoreFromTray; // Multiple monitors - try - MonitorId := Ini.ReadInteger(DefaultConfigIniSection, 'Monitor', DefaultMonitorId); - except - MonitorId := DefaultMonitorId; - end; + if Screen.MonitorCount >= 2 then + begin + try + MonitorId := Ini.ReadInteger(DefaultConfigIniSection, 'Monitor', DefaultMonitorId); + except + MonitorId := DefaultMonitorId; + end; + end + else + begin // Only one monitor available + MonitorLabel.Enabled := False; + MonitorComboBox.Enabled := False; + //MonitorId := NoMonitorId; + MonitorId := 0; + end end; procedure TMainForm.FormCreate(Sender: TObject); From 83e96d7160d58f3e65a51bb9bafa00e6bb0b2993 Mon Sep 17 00:00:00 2001 From: Artem Date: Sun, 13 Dec 2020 21:35:00 +0300 Subject: [PATCH 12/31] Ui fix --- uAutoScreen.pas | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/uAutoScreen.pas b/uAutoScreen.pas index aa0b9c6..506efe5 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -955,13 +955,14 @@ procedure TMainForm.MonitorComboBoxChange(Sender: TObject); procedure TMainForm.FillMonitorList; var - Idx, SelId: Integer; + Idx, SelIdx: Integer; Str: WideString; begin with MonitorComboBox do begin - SelId := MonitorId; + //SelId := MonitorId; + SelIdx := MonitorComboBox.ItemIndex; Items.Clear; Items.Append(WideFormat(I18N('AllMonitorsInfo'), @@ -984,8 +985,8 @@ procedure TMainForm.FillMonitorList; end; // Restore previous selected item after strings updated - if SelId <> -1 then - MonitorId := SelId; + //MonitorId := SelId; + MonitorComboBox.ItemIndex := SelIdx; end; end; From 76f1d073e5fb535bdcce0eac312937ac3ce70a68 Mon Sep 17 00:00:00 2001 From: Artem Date: Sun, 13 Dec 2020 22:03:20 +0300 Subject: [PATCH 13/31] [UI] Create main menu and add "About" item to it --- uAutoScreen.dfm | 32 +++++++++++++++++--------------- uAutoScreen.pas | 24 +++++++++++++----------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/uAutoScreen.dfm b/uAutoScreen.dfm index 0ad3cd6..b7c7854 100755 --- a/uAutoScreen.dfm +++ b/uAutoScreen.dfm @@ -4,7 +4,7 @@ object MainForm: TMainForm BorderIcons = [biSystemMenu, biMinimize] BorderStyle = bsSingle Caption = 'Auto Screenshot' - ClientHeight = 328 + ClientHeight = 308 ClientWidth = 633 Color = clBtnFace Font.Charset = DEFAULT_CHARSET @@ -12,13 +12,14 @@ object MainForm: TMainForm Font.Height = -12 Font.Name = 'Arial' Font.Style = [] + Menu = MainMenu OldCreateOrder = False Position = poScreenCenter OnCreate = FormCreate OnDestroy = FormDestroy DesignSize = ( 633 - 328) + 308) PixelsPerInch = 96 TextHeight = 15 object OutputDirLabel: TTntLabel @@ -95,7 +96,7 @@ object MainForm: TMainForm end object TakeScreenshotButton: TTntButton Left = 32 - Top = 276 + Top = 256 Width = 121 Height = 25 Anchors = [akLeft, akBottom] @@ -162,12 +163,12 @@ object MainForm: TMainForm end object AutoCaptureControlGroup: TTntGroupBox Left = 208 - Top = 248 + Top = 228 Width = 281 Height = 65 Anchors = [akLeft, akBottom] Caption = 'Automatic capture' - TabOrder = 17 + TabOrder = 16 object StartAutoCaptureButton: TTntBitBtn Left = 24 Top = 24 @@ -191,16 +192,6 @@ object MainForm: TMainForm Spacing = 8 end end - object AboutButton: TTntButton - Left = 520 - Top = 272 - Width = 97 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'About' - TabOrder = 16 - OnClick = AboutButtonClick - end object StartCaptureOnStartUpCheckBox: TTntCheckBox Left = 208 Top = 160 @@ -336,4 +327,15 @@ object MainForm: TMainForm Left = 16 Top = 168 end + object MainMenu: TMainMenu + Left = 40 + Top = 40 + object HelpSubMenu: TMenuItem + Caption = 'Help' + object AboutMenuItem: TMenuItem + Caption = 'About...' + OnClick = AboutMenuItemClick + end + end + end end diff --git a/uAutoScreen.pas b/uAutoScreen.pas index 7f494c8..1480eeb 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -53,7 +53,6 @@ TMainForm = class({TTntForm} TForm) RestoreWindowTrayMenuItem: TTntMenuItem; ToggleAutoCaptureTrayMenuItem: TTntMenuItem; Separator2TrayMenuItem: TTntMenuItem; - AboutButton: TTntButton; StartCaptureOnStartUpCheckBox: TTntCheckBox; StartMinimizedCheckBox: TTntCheckBox; Separator1TrayMenuItem: TTntMenuItem; @@ -66,6 +65,9 @@ TMainForm = class({TTntForm} TForm) CaptureInterval: TTntDateTimePicker; TrayIconAnimationTimer: TTimer; AutoRunCheckBox: TTntCheckBox; + MainMenu: TMainMenu; + HelpSubMenu: TMenuItem; + AboutMenuItem: TMenuItem; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure ChooseOutputDirButtonClick(Sender: TObject); @@ -84,7 +86,6 @@ TMainForm = class({TTntForm} TForm) procedure RestoreWindowTrayMenuItemClick(Sender: TObject); procedure TakeScreenshotTrayMenuItemClick(Sender: TObject); procedure ExitTrayMenuItemClick(Sender: TObject); - procedure AboutButtonClick(Sender: TObject); procedure LanguageRadioGroupClick(Sender: TObject); procedure StartCaptureOnStartUpCheckBoxClick(Sender: TObject); procedure StartMinimizedCheckBoxClick(Sender: TObject); @@ -94,6 +95,7 @@ TMainForm = class({TTntForm} TForm) procedure ColorDepthComboBoxChange(Sender: TObject); procedure TrayIconAnimationTimerTimer(Sender: TObject); procedure AutoRunCheckBoxClick(Sender: TObject); + procedure AboutMenuItemClick(Sender: TObject); private { Private declarations } FLanguage: TLanguage; @@ -635,14 +637,6 @@ procedure TMainForm.RestoreFromTray; Application.BringToFront(); end; -procedure TMainForm.AboutButtonClick(Sender: TObject); -begin - with TAboutForm.Create(Application) do - begin - ShowModal; - end; -end; - procedure TMainForm.LanguageRadioGroupClick(Sender: TObject); begin Language := TLanguage(LanguageRadioGroup.ItemIndex) @@ -695,7 +689,7 @@ procedure TMainForm.TranslateForm; StartAutoCaptureButton.Caption := I18N('StartCapture'); StopAutoCaptureButton.Caption := I18N('StopCapture'); TakeScreenshotButton.Caption := I18N('TakeScreenshot'); - AboutButton.Caption := I18N('About'); + AboutMenuItem.Caption := I18N('About'); StartCaptureOnStartUpCheckBox.Caption := I18N('StartCaptureOnStartUp'); StartMinimizedCheckBox.Caption := I18N('StartMinimized'); AutoRunCheckBox.Caption := I18N('AutoRun'); @@ -906,4 +900,12 @@ procedure TMainForm.AutoRunCheckBoxClick(Sender: TObject); Ini.WriteBool(DefaultConfigIniSection, 'AutoRun', AutoRunEnabled); end; +procedure TMainForm.AboutMenuItemClick(Sender: TObject); +begin + with TAboutForm.Create(Application) do + begin + ShowModal; + end; +end; + end. From 36b059bb477e299606f2fcc2f4c22b75de44a6cd Mon Sep 17 00:00:00 2001 From: Artem Date: Wed, 16 Dec 2020 16:07:39 +0300 Subject: [PATCH 14/31] Constant --- uAutoScreen.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uAutoScreen.pas b/uAutoScreen.pas index 506efe5..9bf0980 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -475,7 +475,7 @@ procedure TMainForm.MakeScreenshot; Bitmap.Height := ScreenHeight; Bitmap.Canvas.Brush.Color := clBlack; Bitmap.Canvas.FillRect(Rect(0, 0, ScreenWidth, ScreenHeight)); - ScreenDC := GetDC(0); + ScreenDC := GetDC(HWND_DESKTOP); // Get DC for all monitors BitBlt(Bitmap.Canvas.Handle, 0, 0, ScreenWidth, ScreenHeight, ScreenDC, ScreenX, ScreenY, SRCCOPY); ReleaseDC(0, ScreenDC); From 67a010df2ea05ebe07bbd8879b9bc7fbe500727f Mon Sep 17 00:00:00 2001 From: Artem Date: Sun, 13 Dec 2020 22:30:30 +0300 Subject: [PATCH 15/31] [UI] Move language selection to menu --- lang/en.ini | Bin 3002 -> 3058 bytes lang/ru.ini | Bin 3172 -> 3236 bytes uAutoScreen.dfm | 34 +++++++++++++++++++--------------- uAutoScreen.pas | 35 ++++++++++++++++++++++++----------- 4 files changed, 43 insertions(+), 26 deletions(-) diff --git a/lang/en.ini b/lang/en.ini index 359e20182b13b1a50da3169766ecd59fdd2af29d..4a6f4ebac66be8f548cf8584f1a6cfb9efe6a64b 100644 GIT binary patch delta 62 ycmdlb{z-g-pRqqf0YeExCPO|$9z!vMEdwf_mw}7HgCUh62dK&x#@gsv$PED2j1AoY delta 10 Rcmew)zDs<9-^R8aZU7qH1ZMyM diff --git a/lang/ru.ini b/lang/ru.ini index c7b3c3cab4687771af537779bdb1bf0bd8ebdd98..6cf7d36017881082e088acddb5a4dc2fa3825dd1 100644 GIT binary patch delta 71 zcmaDNu|#r$pN&650YeExCPO|$9z!vMErUFZ0gD3=+pw6jI00GSEW8X{3?2-r3^_oR TAbC5WoE?iNix102FDV`X2MG+I delta 10 RcmZ1?`9xxZ-^M;M9sn4p1Ni^| diff --git a/uAutoScreen.dfm b/uAutoScreen.dfm index b7c7854..e8d6fb4 100755 --- a/uAutoScreen.dfm +++ b/uAutoScreen.dfm @@ -101,7 +101,7 @@ object MainForm: TMainForm Height = 25 Anchors = [akLeft, akBottom] Caption = 'Take screenshot' - TabOrder = 14 + TabOrder = 13 OnClick = TakeScreenshotButtonClick end object JPEGQualitySpinEdit: TSpinEdit @@ -137,18 +137,6 @@ object MainForm: TMainForm TabOrder = 10 OnClick = StopWhenInactiveCheckBoxClick end - object LanguageRadioGroup: TTntRadioGroup - Left = 520 - Top = 160 - Width = 97 - Height = 57 - Caption = 'Language' - Items.Strings = ( - 'English' - #1056#1091#1089#1089#1082#1080#1081) - TabOrder = 13 - OnClick = LanguageRadioGroupClick - end object ImageFormatComboBox: TTntComboBox Left = 208 Top = 104 @@ -168,7 +156,7 @@ object MainForm: TMainForm Height = 65 Anchors = [akLeft, akBottom] Caption = 'Automatic capture' - TabOrder = 16 + TabOrder = 15 object StartAutoCaptureButton: TTntBitBtn Left = 24 Top = 24 @@ -272,7 +260,7 @@ object MainForm: TMainForm Width = 265 Height = 17 Caption = 'Run application at system startup' - TabOrder = 15 + TabOrder = 14 OnClick = AutoRunCheckBoxClick end object Timer: TTimer @@ -330,6 +318,22 @@ object MainForm: TMainForm object MainMenu: TMainMenu Left = 40 Top = 40 + object OptionsSubMenu: TMenuItem + Caption = 'Options' + object LanguageSubMenu: TMenuItem + Caption = 'Language' + object EnglishLanguageMenuItem: TMenuItem + Caption = 'English' + RadioItem = True + OnClick = EnglishLanguageMenuItemClick + end + object RussianLanguageMenuItem: TMenuItem + Caption = #1056#1091#1089#1089#1082#1080#1081 + RadioItem = True + OnClick = RussianLanguageMenuItemClick + end + end + end object HelpSubMenu: TMenuItem Caption = 'Help' object AboutMenuItem: TMenuItem diff --git a/uAutoScreen.pas b/uAutoScreen.pas index 1480eeb..c704794 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -41,7 +41,6 @@ TMainForm = class({TTntForm} TForm) JPEGQualitySpinEdit: TSpinEdit; OpenOutputDirButton: TTntButton; StopWhenInactiveCheckBox: TTntCheckBox; - LanguageRadioGroup: TTntRadioGroup; ImageFormatComboBox: TTntComboBox; JPEGQualityPercentLabel: TTntLabel; AutoCaptureControlGroup: TTntGroupBox; @@ -68,6 +67,10 @@ TMainForm = class({TTntForm} TForm) MainMenu: TMainMenu; HelpSubMenu: TMenuItem; AboutMenuItem: TMenuItem; + OptionsSubMenu: TMenuItem; + LanguageSubMenu: TMenuItem; + EnglishLanguageMenuItem: TMenuItem; + RussianLanguageMenuItem: TMenuItem; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure ChooseOutputDirButtonClick(Sender: TObject); @@ -86,7 +89,6 @@ TMainForm = class({TTntForm} TForm) procedure RestoreWindowTrayMenuItemClick(Sender: TObject); procedure TakeScreenshotTrayMenuItemClick(Sender: TObject); procedure ExitTrayMenuItemClick(Sender: TObject); - procedure LanguageRadioGroupClick(Sender: TObject); procedure StartCaptureOnStartUpCheckBoxClick(Sender: TObject); procedure StartMinimizedCheckBoxClick(Sender: TObject); procedure FileNameTemplateComboBoxChange(Sender: TObject); @@ -96,6 +98,8 @@ TMainForm = class({TTntForm} TForm) procedure TrayIconAnimationTimerTimer(Sender: TObject); procedure AutoRunCheckBoxClick(Sender: TObject); procedure AboutMenuItemClick(Sender: TObject); + procedure EnglishLanguageMenuItemClick(Sender: TObject); + procedure RussianLanguageMenuItemClick(Sender: TObject); private { Private declarations } FLanguage: TLanguage; @@ -637,11 +641,6 @@ procedure TMainForm.RestoreFromTray; Application.BringToFront(); end; -procedure TMainForm.LanguageRadioGroupClick(Sender: TObject); -begin - Language := TLanguage(LanguageRadioGroup.ItemIndex) -end; - procedure TMainForm.SetLanguage(Lang: TLanguage); begin {if (FLanguage = Lang) then @@ -649,7 +648,7 @@ procedure TMainForm.SetLanguage(Lang: TLanguage); FLanguage := Lang; Ini.WriteString(DefaultConfigIniSection, 'Language', LanguageCodes[Lang]); - LanguageRadioGroup.ItemIndex := Ord(Lang); + LanguageSubMenu.Items[Ord(Lang)].Checked := True; I18NSetLang(LanguageCodes[Lang]); TranslateForm; end; @@ -672,8 +671,13 @@ procedure TMainForm.SetLanguageByCode(LangCode: String); procedure TMainForm.TranslateForm; begin - // Main form - LanguageRadioGroup.Caption := I18N('Language'); + // Menubar + OptionsSubMenu.Caption := I18N('Options'); + LanguageSubMenu.Caption := I18N('Language'); + HelpSubMenu.Caption := I18N('Help'); + AboutMenuItem.Caption := I18N('About') + '...'; + + // Main form components OutputDirLabel.Caption := I18N('OutputDirectory') + ':'; OpenOutputDirButton.Caption := I18N('OpenDirectory'); OpenOutputDirButton.Hint := I18N('OpenDirectoryHint'); @@ -689,7 +693,6 @@ procedure TMainForm.TranslateForm; StartAutoCaptureButton.Caption := I18N('StartCapture'); StopAutoCaptureButton.Caption := I18N('StopCapture'); TakeScreenshotButton.Caption := I18N('TakeScreenshot'); - AboutMenuItem.Caption := I18N('About'); StartCaptureOnStartUpCheckBox.Caption := I18N('StartCaptureOnStartUp'); StartMinimizedCheckBox.Caption := I18N('StartMinimized'); AutoRunCheckBox.Caption := I18N('AutoRun'); @@ -908,4 +911,14 @@ procedure TMainForm.AboutMenuItemClick(Sender: TObject); end; end; +procedure TMainForm.EnglishLanguageMenuItemClick(Sender: TObject); +begin + Language := lngEnglish; +end; + +procedure TMainForm.RussianLanguageMenuItemClick(Sender: TObject); +begin + Language := lngRussian; +end; + end. From 1b20e0bde2b1c22b14d090653204f77a1d4005fe Mon Sep 17 00:00:00 2001 From: Artem Date: Fri, 18 Dec 2020 20:41:56 +0300 Subject: [PATCH 16/31] Fix line endings --- uLocalization.pas | 110 +++++++++++++++++++++++----------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/uLocalization.pas b/uLocalization.pas index ef8796f..26cb208 100644 --- a/uLocalization.pas +++ b/uLocalization.pas @@ -1,56 +1,56 @@ -unit uLocalization; - -interface - -uses - TntIniFiles; - -procedure I18NSetLang(ALang: String); -function I18N(Str: String): WideString; - -implementation - -uses SysUtils, uUtils; - -var - Lang: String; - Ini: TTntMemIniFile; - -const - LangSubDir = 'lang'; - -procedure I18NSetLang(ALang: String); -var - LangDir: String; -begin - Lang := ALang; - - LangDir := ExtractFilePath(ParamStr(0)) + LangSubDir + PathDelim; - - // Load ini file with strings for selected language - FreeAndNil(Ini); - Ini := TTntMemIniFile.Create(LangDir + Lang + '.ini'); -end; - -function I18N(Str: String): WideString; -begin - //Result := '[' + Lang + ']' + Str + ''; - Result := ini.ReadString('translation', Str, {Str}''); - - Result := DecodeControlCharacters(Result); -end; - -initialization -begin - // Sets default language - Lang := 'en'; - Ini := nil; -end; - -finalization -begin - FreeAndNil(Ini); -end; - -end. +unit uLocalization; + +interface + +uses + TntIniFiles; + +procedure I18NSetLang(ALang: String); +function I18N(Str: String): WideString; + +implementation + +uses SysUtils, uUtils; + +var + Lang: String; + Ini: TTntMemIniFile; + +const + LangSubDir = 'lang'; + +procedure I18NSetLang(ALang: String); +var + LangDir: String; +begin + Lang := ALang; + + LangDir := ExtractFilePath(ParamStr(0)) + LangSubDir + PathDelim; + + // Load ini file with strings for selected language + FreeAndNil(Ini); + Ini := TTntMemIniFile.Create(LangDir + Lang + '.ini'); +end; + +function I18N(Str: String): WideString; +begin + //Result := '[' + Lang + ']' + Str + ''; + Result := ini.ReadString('translation', Str, {Str}''); + + Result := DecodeControlCharacters(Result); +end; + +initialization +begin + // Sets default language + Lang := 'en'; + Ini := nil; +end; + +finalization +begin + FreeAndNil(Ini); +end; + +end. \ No newline at end of file From d5df1f1b987a7e15863d4d6e2105b9f1ac5b3f9f Mon Sep 17 00:00:00 2001 From: Artem Date: Fri, 18 Dec 2020 20:51:36 +0300 Subject: [PATCH 17/31] [Refactoring] Make class in localization unit --- uLocalization.pas | 63 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/uLocalization.pas b/uLocalization.pas index 26cb208..211d050 100644 --- a/uLocalization.pas +++ b/uLocalization.pas @@ -5,6 +5,19 @@ interface uses TntIniFiles; +type + TLocalizer = class + private + Lang: String; + Ini: TTntMemIniFile; + public + constructor Create; + destructor Destroy; override; + + procedure SetLang(ALang: String); + function I18N(Str: String): WideString; + end; + procedure I18NSetLang(ALang: String); function I18N(Str: String): WideString; @@ -13,43 +26,65 @@ implementation uses SysUtils, uUtils; var - Lang: String; - Ini: TTntMemIniFile; + Localizer: TLocalizer; const LangSubDir = 'lang'; procedure I18NSetLang(ALang: String); -var - LangDir: String; begin - Lang := ALang; + Localizer.SetLang(ALang); +end; - LangDir := ExtractFilePath(ParamStr(0)) + LangSubDir + PathDelim; +function I18N(Str: String): WideString; +begin + Result := Localizer.I18N(Str); +end; - // Load ini file with strings for selected language +{ TLocalizer } + +constructor TLocalizer.Create; +begin + Lang := 'en'; + Ini := nil; +end; + +destructor TLocalizer.Destroy; +begin FreeAndNil(Ini); - Ini := TTntMemIniFile.Create(LangDir + Lang + '.ini'); + + inherited; end; -function I18N(Str: String): WideString; +function TLocalizer.I18N(Str: String): WideString; begin //Result := '[' + Lang + ']' + Str + ''; - Result := ini.ReadString('translation', Str, {Str}''); + Result := Ini.ReadString('translation', Str, {Str}''); Result := DecodeControlCharacters(Result); end; +procedure TLocalizer.SetLang(ALang: String); +var + LangDir: String; +begin + Lang := ALang; + + LangDir := ExtractFilePath(ParamStr(0)) + LangSubDir + PathDelim; + + // Load ini file with strings for selected language + FreeAndNil(Ini); + Ini := TTntMemIniFile.Create(LangDir + Lang + '.ini'); +end; + initialization begin - // Sets default language - Lang := 'en'; - Ini := nil; + Localizer := TLocalizer.Create; end; finalization begin - FreeAndNil(Ini); + FreeAndNil(Localizer); end; end. From 50228d3899a4a0f4346f6f50a188615a7391e652 Mon Sep 17 00:00:00 2001 From: Artem Date: Fri, 18 Dec 2020 21:21:09 +0300 Subject: [PATCH 18/31] [Refactoring] Remove functions --- uAbout.pas | 10 ++++---- uAutoScreen.pas | 58 +++++++++++++++++++++++------------------------ uLocalization.pas | 17 ++------------ 3 files changed, 36 insertions(+), 49 deletions(-) diff --git a/uAbout.pas b/uAbout.pas index 44f0321..1ee398a 100644 --- a/uAbout.pas +++ b/uAbout.pas @@ -46,14 +46,14 @@ procedure TAboutForm.FormCreate(Sender: TObject); BuildDate: TDateTime; BuildDateStr: WideString; begin - Caption := I18N('About'); + Caption := Localizer.I18N('About'); Logo.Picture.Icon.Handle := LoadImage(HInstance, 'MAINICON', IMAGE_ICON, 64, 64, LR_DEFAULTCOLOR); ProgramNameLabel.Caption := TntApplication.Title; - VersionLabel.Caption := I18N('Version') + ': ' + GetProgramVersionStr(True); - AuthorLabel.Caption := I18N('Author') + ': ' + 'Artem Demin (artem78) '; + VersionLabel.Caption := Localizer.I18N('Version') + ': ' + GetProgramVersionStr(True); + AuthorLabel.Caption := Localizer.I18N('Author') + ': ' + 'Artem Demin (artem78) '; LinkLabel.Caption := ProjectGitHubURL; BuildDate := GetLinkerTimeStamp; @@ -64,9 +64,9 @@ procedure TAboutForm.FormCreate(Sender: TObject); BuildDateStr := 'unknown' else BuildDateStr := FormatDateTime({'dddddd tt'} 'dddddd', BuildDate); - BuildDateLabel.Caption := I18N('BuildDate') + ': ' + BuildDateStr; + BuildDateLabel.Caption := Localizer.I18N('BuildDate') + ': ' + BuildDateStr; - CloseButton.Caption := I18N('Close'); + CloseButton.Caption := Localizer.I18N('Close'); end; procedure TAboutForm.LinkLabelClick(Sender: TObject); diff --git a/uAutoScreen.pas b/uAutoScreen.pas index c704794..9ebc68a 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -325,7 +325,7 @@ procedure TMainForm.ChooseOutputDirButtonClick(Sender: TObject); begin Dir := OutputDirEdit.Text; - if WideSelectDirectory(I18N('SelectOutputDirectory'), '' {savepath.Text}, Dir) then + if WideSelectDirectory(Localizer.I18N('SelectOutputDirectory'), '' {savepath.Text}, Dir) then //if SelectDirectory(dir, [sdAllowCreate, sdPerformCreate], 0) then begin OutputDirEdit.Text := Dir; @@ -649,7 +649,7 @@ procedure TMainForm.SetLanguage(Lang: TLanguage); FLanguage := Lang; Ini.WriteString(DefaultConfigIniSection, 'Language', LanguageCodes[Lang]); LanguageSubMenu.Items[Ord(Lang)].Checked := True; - I18NSetLang(LanguageCodes[Lang]); + Localizer.SetLang(LanguageCodes[Lang]); TranslateForm; end; @@ -672,36 +672,36 @@ procedure TMainForm.SetLanguageByCode(LangCode: String); procedure TMainForm.TranslateForm; begin // Menubar - OptionsSubMenu.Caption := I18N('Options'); - LanguageSubMenu.Caption := I18N('Language'); - HelpSubMenu.Caption := I18N('Help'); - AboutMenuItem.Caption := I18N('About') + '...'; + OptionsSubMenu.Caption := Localizer.I18N('Options'); + LanguageSubMenu.Caption := Localizer.I18N('Language'); + HelpSubMenu.Caption := Localizer.I18N('Help'); + AboutMenuItem.Caption := Localizer.I18N('About') + '...'; // Main form components - OutputDirLabel.Caption := I18N('OutputDirectory') + ':'; - OpenOutputDirButton.Caption := I18N('OpenDirectory'); - OpenOutputDirButton.Hint := I18N('OpenDirectoryHint'); - FileNameTemplateLabel.Caption := I18N('FileNameTemplate') + ':'; - CaptureIntervalLabel.Caption := I18N('CaptureInterval') + ':'; - StopWhenInactiveCheckBox.Caption := I18N('PauseCaptureWhenIdle'); - StopWhenInactiveCheckBox.Hint := I18N('PauseCaptureWhenIdleHint'); - ImageFormatLabel.Caption := I18N('Format') + ':'; - ColorDepthLabel.Caption := I18N('ColorDepth') + ':'; - JPEGQualityLabel.Caption := I18N('Quality') + ':'; - GrayscaleCheckBox.Caption := I18N('Grayscale'); - AutoCaptureControlGroup.Caption := I18N('AutoCapture'); - StartAutoCaptureButton.Caption := I18N('StartCapture'); - StopAutoCaptureButton.Caption := I18N('StopCapture'); - TakeScreenshotButton.Caption := I18N('TakeScreenshot'); - StartCaptureOnStartUpCheckBox.Caption := I18N('StartCaptureOnStartUp'); - StartMinimizedCheckBox.Caption := I18N('StartMinimized'); - AutoRunCheckBox.Caption := I18N('AutoRun'); + OutputDirLabel.Caption := Localizer.I18N('OutputDirectory') + ':'; + OpenOutputDirButton.Caption := Localizer.I18N('OpenDirectory'); + OpenOutputDirButton.Hint := Localizer.I18N('OpenDirectoryHint'); + FileNameTemplateLabel.Caption := Localizer.I18N('FileNameTemplate') + ':'; + CaptureIntervalLabel.Caption := Localizer.I18N('CaptureInterval') + ':'; + StopWhenInactiveCheckBox.Caption := Localizer.I18N('PauseCaptureWhenIdle'); + StopWhenInactiveCheckBox.Hint := Localizer.I18N('PauseCaptureWhenIdleHint'); + ImageFormatLabel.Caption := Localizer.I18N('Format') + ':'; + ColorDepthLabel.Caption := Localizer.I18N('ColorDepth') + ':'; + JPEGQualityLabel.Caption := Localizer.I18N('Quality') + ':'; + GrayscaleCheckBox.Caption := Localizer.I18N('Grayscale'); + AutoCaptureControlGroup.Caption := Localizer.I18N('AutoCapture'); + StartAutoCaptureButton.Caption := Localizer.I18N('StartCapture'); + StopAutoCaptureButton.Caption := Localizer.I18N('StopCapture'); + TakeScreenshotButton.Caption := Localizer.I18N('TakeScreenshot'); + StartCaptureOnStartUpCheckBox.Caption := Localizer.I18N('StartCaptureOnStartUp'); + StartMinimizedCheckBox.Caption := Localizer.I18N('StartMinimized'); + AutoRunCheckBox.Caption := Localizer.I18N('AutoRun'); // Tray icon - RestoreWindowTrayMenuItem.Caption := I18N('Restore'); - ToggleAutoCaptureTrayMenuItem.Caption := I18N('EnableAutoCapture'); - TakeScreenshotTrayMenuItem.Caption := I18N('TakeScreenshot'); - ExitTrayMenuItem.Caption := I18N('Exit'); + RestoreWindowTrayMenuItem.Caption := Localizer.I18N('Restore'); + ToggleAutoCaptureTrayMenuItem.Caption := Localizer.I18N('EnableAutoCapture'); + TakeScreenshotTrayMenuItem.Caption := Localizer.I18N('TakeScreenshot'); + ExitTrayMenuItem.Caption := Localizer.I18N('Exit'); end; procedure TMainForm.StartCaptureOnStartUpCheckBoxClick(Sender: TObject); @@ -721,7 +721,7 @@ procedure TMainForm.FileNameTemplateComboBoxChange(Sender: TObject); procedure TMainForm.FileNameTemplateHelpButtonClick(Sender: TObject); begin - WideShowMessage(I18N('FileNameTemplateHelpText')); + WideShowMessage(Localizer.I18N('FileNameTemplateHelpText')); end; function TMainForm.GetImageFormat: TImageFormat; diff --git a/uLocalization.pas b/uLocalization.pas index 211d050..abd637c 100644 --- a/uLocalization.pas +++ b/uLocalization.pas @@ -18,29 +18,16 @@ TLocalizer = class function I18N(Str: String): WideString; end; -procedure I18NSetLang(ALang: String); -function I18N(Str: String): WideString; +var + Localizer: TLocalizer; implementation uses SysUtils, uUtils; -var - Localizer: TLocalizer; - const LangSubDir = 'lang'; -procedure I18NSetLang(ALang: String); -begin - Localizer.SetLang(ALang); -end; - -function I18N(Str: String): WideString; -begin - Result := Localizer.I18N(Str); -end; - { TLocalizer } constructor TLocalizer.Create; From 579d61e3e7fa4e5f458ec5061996530863c32253 Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 4 Jan 2021 14:03:08 +0300 Subject: [PATCH 19/31] [Localization] Add support for many languages --- lang/en.ini | Bin 3058 -> 3188 bytes lang/ru.ini | Bin 3236 -> 3366 bytes uAutoScreen.dfm | 10 ---- uAutoScreen.pas | 119 ++++++++++++++++++++++++++++++---------------- uLocalization.pas | 63 ++++++++++++++++++++++++ 5 files changed, 142 insertions(+), 50 deletions(-) diff --git a/lang/en.ini b/lang/en.ini index 4a6f4ebac66be8f548cf8584f1a6cfb9efe6a64b..51e2ff4b4c95da5b2aa664c0eeaa3a2452eda092 100644 GIT binary patch delta 142 zcmew){zanx|G#L4Oolv$G=_YJSO#7OE(RZlL?Az%!5Ju$!jQ^f3&eRSGJZf6xnLPr eu*w{u3B?Q<7-~v@;$=W}c+|6kHEm@2zzqP4Q5&QH delta 11 Scmew&@kyNN|G$kbAGiS}>IOvs diff --git a/lang/ru.ini b/lang/ru.ini index 6cf7d36017881082e088acddb5a4dc2fa3825dd1..fca833de5198ab08f7e17d5cb4658c8d5e5b001a 100644 GIT binary patch delta 142 zcmZ1?xlF45|G#L4Oolv$G=_YJSO#7OE(RZlL?Az%!5Ju$!jQ^f%TUBniX!6&RFMmo v2?EL#17Rju53+8Mni8OR8BiTUy#k9fiz5(Pu~@KJvH;byf(_otw1@`)FS!}e delta 11 ScmZ1`wM3HX|G$kbi+BJZTLoYM diff --git a/uAutoScreen.dfm b/uAutoScreen.dfm index e8d6fb4..0ecd937 100755 --- a/uAutoScreen.dfm +++ b/uAutoScreen.dfm @@ -322,16 +322,6 @@ object MainForm: TMainForm Caption = 'Options' object LanguageSubMenu: TMenuItem Caption = 'Language' - object EnglishLanguageMenuItem: TMenuItem - Caption = 'English' - RadioItem = True - OnClick = EnglishLanguageMenuItemClick - end - object RussianLanguageMenuItem: TMenuItem - Caption = #1056#1091#1089#1089#1082#1080#1081 - RadioItem = True - OnClick = RussianLanguageMenuItemClick - end end end object HelpSubMenu: TMenuItem diff --git a/uAutoScreen.pas b/uAutoScreen.pas index 9ebc68a..4c0364c 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -6,7 +6,8 @@ interface Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, ExtCtrls, StdCtrls, inifiles, Spin, FileCtrl, pngImage, TrayIcon, XPMan, jpeg, ShellAPI, Menus, GifImage, Buttons, TntForms, TntStdCtrls, - TntMenus, TntComCtrls, TntButtons, TntExtCtrls, TntDialogs, TntFileCtrl; + TntMenus, TntComCtrls, TntButtons, TntExtCtrls, TntDialogs, TntFileCtrl, + uLocalization; type TImageFormat = (fmtPNG=0, fmtJPG, fmtBMP, fmtGIF); @@ -23,8 +24,6 @@ TImageFormatInfo = record TImageFormatInfoArray = array [TImageFormat] of TImageFormatInfo; - TLanguage = (lngEnglish=0, lngRussian); - TTrayIconState = (tisDefault, tisBlackWhite, tisFlashAnimation); TMainForm = class({TTntForm} TForm) @@ -69,8 +68,6 @@ TMainForm = class({TTntForm} TForm) AboutMenuItem: TMenuItem; OptionsSubMenu: TMenuItem; LanguageSubMenu: TMenuItem; - EnglishLanguageMenuItem: TMenuItem; - RussianLanguageMenuItem: TMenuItem; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure ChooseOutputDirButtonClick(Sender: TObject); @@ -98,11 +95,10 @@ TMainForm = class({TTntForm} TForm) procedure TrayIconAnimationTimerTimer(Sender: TObject); procedure AutoRunCheckBoxClick(Sender: TObject); procedure AboutMenuItemClick(Sender: TObject); - procedure EnglishLanguageMenuItemClick(Sender: TObject); - procedure RussianLanguageMenuItemClick(Sender: TObject); private { Private declarations } - FLanguage: TLanguage; + AvailableLanguages: TLanguagesArray; + FLanguage: TLanguageCode; { ??? } FColorDepth: TColorDepth; FTrayIconState: TTrayIconState; @@ -121,17 +117,19 @@ TMainForm = class({TTntForm} TForm) procedure MakeScreenshot; procedure MinimizeToTray; procedure RestoreFromTray; - procedure SetLanguage(Lang: TLanguage); - procedure SetLanguageByCode(LangCode: String); + //procedure SetLanguage(Lang: TLanguage); + procedure SetLanguageByCode(LangCode: TLanguageCode); procedure TranslateForm(); procedure InitUI; procedure ReadSettings; procedure UpdateColorDepthValues; + procedure UpdateLanguages; + procedure LanguageClick(Sender: TObject); property IsTimerEnabled: Boolean read GetTimerEnabled write SetTimerEnabled; property FinalOutputDir: String read GetFinalOutputDir; property ImagePath: String read GetImagePath; - property Language: TLanguage read FLanguage write SetLanguage; + //property Language: TLanguage read FLanguage write SetLanguage; property ImageFormat: TImageFormat read GetImageFormat write SetImageFormat; property ColorDepth: TColorDepth read GetColorDepth write SetColorDepth; property TrayIconState: TTrayIconState write SetTrayIconState; @@ -170,8 +168,7 @@ TMainForm = class({TTntForm} TForm) ColorDepth: [] ) ); - - LanguageCodes: array [TLanguage] of String = ('en', 'ru'); + DefaultConfigIniSection = 'main'; MinCaptureIntervalInSeconds = 1; @@ -182,7 +179,7 @@ TMainForm = class({TTntForm} TForm) implementation -uses uAbout, DateUtils, uLocalization, uUtils, Math, VistaAltFixUnit; +uses uAbout, DateUtils, uUtils, Math, VistaAltFixUnit; {$R *.dfm} @@ -204,6 +201,9 @@ procedure TMainForm.InitUI; // Icons StartAutoCaptureButton.Glyph.LoadFromResourceName(HInstance, '_START_ICON'); StopAutoCaptureButton.Glyph.LoadFromResourceName(HInstance, '_STOP_ICON'); + + // Available languages + UpdateLanguages; end; procedure TMainForm.ReadSettings; @@ -217,9 +217,9 @@ procedure TMainForm.ReadSettings; var DefaultOutputDir: String; SystemLanguageCode: String; - DefaultLanguage: TLanguage; + DefaultLanguage: TLanguageCode; FmtStr: String; - LangCode: String; + LangCode: TLanguageCode; Seconds: Integer; begin DefaultOutputDir := IncludeTrailingPathDelimiter(JoinPath(ExtractFilePath(Application.ExeName), 'screenshots')); @@ -267,15 +267,15 @@ procedure TMainForm.ReadSettings; or (SystemLanguageCode = 'be') {Belorussian} or (SystemLanguageCode = 'bl') {Belorussian} or (SystemLanguageCode = 'uk') {Ukrainian} then - DefaultLanguage := lngRussian + DefaultLanguage := 'ru' else - DefaultLanguage := lngEnglish; + DefaultLanguage := 'en'; - LangCode := Ini.ReadString(DefaultConfigIniSection, 'Language', LanguageCodes[DefaultLanguage]); + LangCode := Ini.ReadString(DefaultConfigIniSection, 'Language', DefaultLanguage); try SetLanguageByCode(LangCode); except - SetLanguage(DefaultLanguage); + SetLanguageByCode(DefaultLanguage); end; // Start autocapture @@ -641,27 +641,33 @@ procedure TMainForm.RestoreFromTray; Application.BringToFront(); end; -procedure TMainForm.SetLanguage(Lang: TLanguage); -begin - {if (FLanguage = Lang) then - Exit;} - - FLanguage := Lang; - Ini.WriteString(DefaultConfigIniSection, 'Language', LanguageCodes[Lang]); - LanguageSubMenu.Items[Ord(Lang)].Checked := True; - Localizer.SetLang(LanguageCodes[Lang]); - TranslateForm; -end; +//procedure TMainForm.SetLanguage(Lang: TLanguage); +//begin +// {if (FLanguage = Lang) then +// Exit;} +// +// FLanguage := Lang; +// Ini.WriteString(DefaultConfigIniSection, 'Language', LanguageCodes[Lang]); +// LanguageSubMenu.Items[Ord(Lang)].Checked := True; +// Localizer.SetLang(LanguageCodes[Lang]); +// TranslateForm; +//end; -procedure TMainForm.SetLanguageByCode(LangCode: String); +procedure TMainForm.SetLanguageByCode(LangCode: TLanguageCode); var - LangIdx: TLanguage; + LangIdx: integer; begin - for LangIdx := Low(TLanguage) to High(TLanguage) do + for LangIdx := 0 to Length(AvailableLanguages) - 1 do begin - if LangCode = LanguageCodes[LangIdx] then + if LangCode = AvailableLanguages[LangIdx].Code then begin - SetLanguage(LangIdx); + FLanguage := LangCode; + + Ini.WriteString(DefaultConfigIniSection, 'Language', LangCode); + LanguageSubMenu.Items[LangIdx].Checked := True; { ??? } + Localizer.SetLang(LangCode); + TranslateForm; + Exit; end; end; @@ -911,14 +917,47 @@ procedure TMainForm.AboutMenuItemClick(Sender: TObject); end; end; -procedure TMainForm.EnglishLanguageMenuItemClick(Sender: TObject); +procedure TMainForm.UpdateLanguages; +{const + GroupIdx = 1;} +var + Lang: TLanguageInfo; + I: integer; + MenuItem: TMenuItem; begin - Language := lngEnglish; + while LanguageSubMenu.Count > 0 do + LanguageSubMenu.Items[0].Free; + LanguageSubMenu.Clear; + + Localizer.GetLanguages(AvailableLanguages); + for I := 0 to Length(AvailableLanguages) - 1 do + begin + Lang := AvailableLanguages[I]; + + if (Lang.Name <> '') and (Lang.Code <> '') then + begin + MenuItem := TMenuItem.Create(LanguageSubMenu); + MenuItem.Caption := AvailableLanguages[I].Name; + if (Lang.NativeName <> '') and (Lang.NativeName <> Lang.Name) then + MenuItem.Caption := MenuItem.Caption + ' (' + Lang.NativeName + ')'; + MenuItem.OnClick := LanguageClick; + MenuItem.RadioItem := True; + //MenuItem.GroupIndex := GroupIdx; + + LanguageSubMenu.Add(MenuItem); + end + end; end; -procedure TMainForm.RussianLanguageMenuItemClick(Sender: TObject); + +procedure TMainForm.LanguageClick(Sender: TObject); +var + Idx: integer; + LangCode: TLanguageCode; begin - Language := lngRussian; + Idx := (Sender as TMenuItem).MenuIndex; + LangCode := AvailableLanguages[Idx].Code; + SetLanguageByCode(LangCode); end; end. diff --git a/uLocalization.pas b/uLocalization.pas index abd637c..cb0fa87 100644 --- a/uLocalization.pas +++ b/uLocalization.pas @@ -6,6 +6,16 @@ interface TntIniFiles; type + TLanguageCode = String[2]; + + TLanguageInfo = record + Code: TLanguageCode; + Name, NativeName: WideString; + FileName: String; + end; + + TLanguagesArray = array of TLanguageInfo; + TLocalizer = class private Lang: String; @@ -16,6 +26,7 @@ TLocalizer = class procedure SetLang(ALang: String); function I18N(Str: String): WideString; + procedure GetLanguages(var LangsArr: TLanguagesArray); end; var @@ -43,6 +54,58 @@ destructor TLocalizer.Destroy; inherited; end; +procedure TLocalizer.GetLanguages(var LangsArr: TLanguagesArray); +const + IniSection = 'info'; +var + LangDir: String; + SearchRes: TSearchRec; + LangsCount: integer; + Idx: integer; + Ini: TTntMemIniFile; +begin + LangDir := ExtractFilePath(ParamStr(0)) + LangSubDir + PathDelim; + + // Get amount of available languages + LangsCount := 0; + if FindFirst(LangDir + '*.ini', faAnyFile, SearchRes) = 0 then + begin + repeat + Inc(LangsCount); + until FindNext(SearchRes) <> 0; + + FindClose(SearchRes); + end; + + // Allocate memory for array of languages + SetLength(LangsArr, LangsCount); + + // Write language info in array + Idx := -1; + if FindFirst(LangDir + '*.ini', faAnyFile, SearchRes) = 0 then + begin + repeat + Ini := TTntMemIniFile.Create(LangDir + SearchRes.Name); + try + try + Inc(Idx); + + LangsArr[Idx].Code := {Wide}LowerCase(Ini.ReadString(IniSection, 'LangCode', '')); + LangsArr[Idx].Name := Ini.ReadString(IniSection, 'LangName', ''); + LangsArr[Idx].NativeName := Ini.ReadString(IniSection, 'LangNativeName', ''); + LangsArr[Idx].FileName := LangDir + SearchRes.Name; + finally + //Ini.Free; + FreeAndNil(Ini); + end; + except + end; + until FindNext(SearchRes) <> 0; + + FindClose(SearchRes); + end; +end; + function TLocalizer.I18N(Str: String): WideString; begin //Result := '[' + Lang + ']' + Str + ''; From e799428307797fe4db5b5bb93d5de4ddeb411a42 Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 4 Jan 2021 14:13:09 +0300 Subject: [PATCH 20/31] [Refactoring] Localization: change type --- uLocalization.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uLocalization.pas b/uLocalization.pas index cb0fa87..1823ffb 100644 --- a/uLocalization.pas +++ b/uLocalization.pas @@ -18,13 +18,13 @@ TLanguageInfo = record TLocalizer = class private - Lang: String; + Lang: TLanguageCode; Ini: TTntMemIniFile; public constructor Create; destructor Destroy; override; - procedure SetLang(ALang: String); + procedure SetLang(ALang: TLanguageCode); function I18N(Str: String): WideString; procedure GetLanguages(var LangsArr: TLanguagesArray); end; @@ -114,7 +114,7 @@ function TLocalizer.I18N(Str: String): WideString; Result := DecodeControlCharacters(Result); end; -procedure TLocalizer.SetLang(ALang: String); +procedure TLocalizer.SetLang(ALang: TLanguageCode); var LangDir: String; begin From 4c848fa7fcfced1221854e42fc867bbcf18d4404 Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 4 Jan 2021 14:31:48 +0300 Subject: [PATCH 21/31] [Refactoring] Localization --- uLocalization.pas | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/uLocalization.pas b/uLocalization.pas index 1823ffb..b9e4227 100644 --- a/uLocalization.pas +++ b/uLocalization.pas @@ -20,8 +20,9 @@ TLocalizer = class private Lang: TLanguageCode; Ini: TTntMemIniFile; + LangsDir: String; public - constructor Create; + constructor Create(ALangsDir: String); destructor Destroy; override; procedure SetLang(ALang: TLanguageCode); @@ -36,15 +37,13 @@ implementation uses SysUtils, uUtils; -const - LangSubDir = 'lang'; - { TLocalizer } -constructor TLocalizer.Create; +constructor TLocalizer.Create(ALangsDir: String); begin Lang := 'en'; Ini := nil; + LangsDir := IncludeTrailingBackslash(ALangsDir); end; destructor TLocalizer.Destroy; @@ -58,17 +57,14 @@ procedure TLocalizer.GetLanguages(var LangsArr: TLanguagesArray); const IniSection = 'info'; var - LangDir: String; SearchRes: TSearchRec; LangsCount: integer; Idx: integer; Ini: TTntMemIniFile; begin - LangDir := ExtractFilePath(ParamStr(0)) + LangSubDir + PathDelim; - // Get amount of available languages LangsCount := 0; - if FindFirst(LangDir + '*.ini', faAnyFile, SearchRes) = 0 then + if FindFirst(LangsDir + '*.ini', faAnyFile, SearchRes) = 0 then begin repeat Inc(LangsCount); @@ -82,10 +78,10 @@ procedure TLocalizer.GetLanguages(var LangsArr: TLanguagesArray); // Write language info in array Idx := -1; - if FindFirst(LangDir + '*.ini', faAnyFile, SearchRes) = 0 then + if FindFirst(LangsDir + '*.ini', faAnyFile, SearchRes) = 0 then begin repeat - Ini := TTntMemIniFile.Create(LangDir + SearchRes.Name); + Ini := TTntMemIniFile.Create(LangsDir + SearchRes.Name); try try Inc(Idx); @@ -93,7 +89,7 @@ procedure TLocalizer.GetLanguages(var LangsArr: TLanguagesArray); LangsArr[Idx].Code := {Wide}LowerCase(Ini.ReadString(IniSection, 'LangCode', '')); LangsArr[Idx].Name := Ini.ReadString(IniSection, 'LangName', ''); LangsArr[Idx].NativeName := Ini.ReadString(IniSection, 'LangNativeName', ''); - LangsArr[Idx].FileName := LangDir + SearchRes.Name; + LangsArr[Idx].FileName := LangsDir + SearchRes.Name; finally //Ini.Free; FreeAndNil(Ini); @@ -115,21 +111,17 @@ function TLocalizer.I18N(Str: String): WideString; end; procedure TLocalizer.SetLang(ALang: TLanguageCode); -var - LangDir: String; begin Lang := ALang; - LangDir := ExtractFilePath(ParamStr(0)) + LangSubDir + PathDelim; - // Load ini file with strings for selected language FreeAndNil(Ini); - Ini := TTntMemIniFile.Create(LangDir + Lang + '.ini'); + Ini := TTntMemIniFile.Create(LangsDir + Lang + '.ini'); end; initialization begin - Localizer := TLocalizer.Create; + Localizer := TLocalizer.Create(ExtractFilePath(ParamStr(0)) + 'lang' + PathDelim); end; finalization From 909191b2d1e010232d8283a097978f2d99d4baa5 Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 4 Jan 2021 15:19:37 +0300 Subject: [PATCH 22/31] [Refactoring] Localizer exception --- uLocalization.pas | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/uLocalization.pas b/uLocalization.pas index b9e4227..a0796be 100644 --- a/uLocalization.pas +++ b/uLocalization.pas @@ -3,7 +3,7 @@ interface uses - TntIniFiles; + TntIniFiles, SysUtils; type TLanguageCode = String[2]; @@ -16,6 +16,8 @@ TLanguageInfo = record TLanguagesArray = array of TLanguageInfo; + ELocalizerException = class(Exception); + TLocalizer = class private Lang: TLanguageCode; @@ -35,7 +37,7 @@ TLocalizer = class implementation -uses SysUtils, uUtils; +uses uUtils; { TLocalizer } @@ -111,12 +113,18 @@ function TLocalizer.I18N(Str: String): WideString; end; procedure TLocalizer.SetLang(ALang: TLanguageCode); +var + FileName: String; begin Lang := ALang; - // Load ini file with strings for selected language FreeAndNil(Ini); - Ini := TTntMemIniFile.Create(LangsDir + Lang + '.ini'); + + // Load ini file with strings for selected language + FileName := LangsDir + Lang + '.ini'; + if not FileExists(FileName) then + raise ELocalizerException.CreateFmt('Can`t open localization file "%s"', [FileName]); + Ini := TTntMemIniFile.Create(FileName); end; initialization From 03fab2d7e31350ae6fae7120531a1e244ba37525 Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 4 Jan 2021 20:53:26 +0300 Subject: [PATCH 23/31] [Refactoring] Localization --- uAutoScreen.pas | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/uAutoScreen.pas b/uAutoScreen.pas index 4c0364c..d0ca34e 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -125,6 +125,8 @@ TMainForm = class({TTntForm} TForm) procedure UpdateColorDepthValues; procedure UpdateLanguages; procedure LanguageClick(Sender: TObject); + function GetLangCodeOfLangMenuItem(const LangItem: TMenuItem): TLanguageCode; + function FindLangMenuItem(ALangCode: TLanguageCode): TMenuItem; property IsTimerEnabled: Boolean read GetTimerEnabled write SetTimerEnabled; property FinalOutputDir: String read GetFinalOutputDir; @@ -183,6 +185,9 @@ implementation {$R *.dfm} +const + LanguageSubMenuItemNamePrefix = 'LanguageSubMenuItem_'; + procedure TMainForm.InitUI; var Fmt: TImageFormat; @@ -664,7 +669,7 @@ procedure TMainForm.SetLanguageByCode(LangCode: TLanguageCode); FLanguage := LangCode; Ini.WriteString(DefaultConfigIniSection, 'Language', LangCode); - LanguageSubMenu.Items[LangIdx].Checked := True; { ??? } + FindLangMenuItem(LangCode).Checked := True; Localizer.SetLang(LangCode); TranslateForm; @@ -937,12 +942,13 @@ procedure TMainForm.UpdateLanguages; if (Lang.Name <> '') and (Lang.Code <> '') then begin MenuItem := TMenuItem.Create(LanguageSubMenu); - MenuItem.Caption := AvailableLanguages[I].Name; + MenuItem.Caption := Lang.Name; if (Lang.NativeName <> '') and (Lang.NativeName <> Lang.Name) then MenuItem.Caption := MenuItem.Caption + ' (' + Lang.NativeName + ')'; MenuItem.OnClick := LanguageClick; MenuItem.RadioItem := True; //MenuItem.GroupIndex := GroupIdx; + MenuItem.Name := LanguageSubMenuItemNamePrefix + Lang.Code; LanguageSubMenu.Add(MenuItem); end @@ -960,4 +966,32 @@ procedure TMainForm.LanguageClick(Sender: TObject); SetLanguageByCode(LangCode); end; +function TMainForm.FindLangMenuItem(ALangCode: TLanguageCode): TMenuItem; +var + I: integer; + LangCode: TLanguageCode; +begin + for I := 0 to LanguageSubMenu.Count - 1 do + begin + LangCode := GetLangCodeOfLangMenuItem(LanguageSubMenu.Items[I]); + if LangCode = ALangCode then + begin + Result := LanguageSubMenu.Items[I]; + Exit; + end; + end; + + raise Exception.CreateFmt('Language code "%s" not found', [ALangCode]); +end; + +function TMainForm.GetLangCodeOfLangMenuItem( + const LangItem: TMenuItem): TLanguageCode; +begin + if Pos(LanguageSubMenuItemNamePrefix, LangItem.Name) = 1 then + Result := Copy(LangItem.Name, Length(LanguageSubMenuItemNamePrefix) + 1, 2) + else + raise Exception.CreateFmt('Can`t get language code from language menu item' + + ' "%s" (name=%s)', [LangItem.Caption, LangItem.Name]); +end; + end. From 9fa9f2d13a78e841c7baaf58a330af89ec9d7e5b Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 4 Jan 2021 21:13:50 +0300 Subject: [PATCH 24/31] [Refactoring] Localization --- uAutoScreen.pas | 2 +- uLocalization.pas | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/uAutoScreen.pas b/uAutoScreen.pas index d0ca34e..82ca733 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -670,7 +670,7 @@ procedure TMainForm.SetLanguageByCode(LangCode: TLanguageCode); Ini.WriteString(DefaultConfigIniSection, 'Language', LangCode); FindLangMenuItem(LangCode).Checked := True; - Localizer.SetLang(LangCode); + Localizer.LoadFromFile(AvailableLanguages[LangIdx].FileName); TranslateForm; Exit; diff --git a/uLocalization.pas b/uLocalization.pas index a0796be..5b51154 100644 --- a/uLocalization.pas +++ b/uLocalization.pas @@ -20,14 +20,14 @@ ELocalizerException = class(Exception); TLocalizer = class private - Lang: TLanguageCode; Ini: TTntMemIniFile; LangsDir: String; public constructor Create(ALangsDir: String); destructor Destroy; override; - procedure SetLang(ALang: TLanguageCode); + //procedure LoadByCode(ALang: TLanguageCode); + procedure LoadFromFile(AFileName: String); function I18N(Str: String): WideString; procedure GetLanguages(var LangsArr: TLanguagesArray); end; @@ -43,7 +43,6 @@ implementation constructor TLocalizer.Create(ALangsDir: String); begin - Lang := 'en'; Ini := nil; LangsDir := IncludeTrailingBackslash(ALangsDir); end; @@ -106,25 +105,25 @@ procedure TLocalizer.GetLanguages(var LangsArr: TLanguagesArray); function TLocalizer.I18N(Str: String): WideString; begin + if not Assigned(Ini) then + raise ELocalizerException.Create('No localization loaded'); + //Result := '[' + Lang + ']' + Str + ''; Result := Ini.ReadString('translation', Str, {Str}''); Result := DecodeControlCharacters(Result); end; -procedure TLocalizer.SetLang(ALang: TLanguageCode); +procedure TLocalizer.LoadFromFile(AFileName: String); var FileName: String; begin - Lang := ALang; - FreeAndNil(Ini); // Load ini file with strings for selected language - FileName := LangsDir + Lang + '.ini'; - if not FileExists(FileName) then + if not FileExists(AFileName) then raise ELocalizerException.CreateFmt('Can`t open localization file "%s"', [FileName]); - Ini := TTntMemIniFile.Create(FileName); + Ini := TTntMemIniFile.Create(AFileName); end; initialization From 8fac4dcd5260c14cb85046a0c5b2c09f43f22f1f Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 4 Jan 2021 21:56:51 +0300 Subject: [PATCH 25/31] [Localization] Show translation author in About dialog --- lang/en.ini | Bin 3188 -> 3294 bytes lang/ru.ini | Bin 3366 -> 3454 bytes uAbout.dfm | 15 +++++++++++---- uAbout.pas | 11 +++++++++++ uLocalization.pas | 28 +++++++++++++++++++++++----- 5 files changed, 45 insertions(+), 9 deletions(-) diff --git a/lang/en.ini b/lang/en.ini index 51e2ff4b4c95da5b2aa664c0eeaa3a2452eda092..14e02c9aae4d70c26fc16b01bbc7a1eda99103ff 100644 GIT binary patch delta 112 zcmew&aZhqWgR~<42{$YiJj b(j`DTpCOL{RUa-@3JggMl?+ysb$Q$Y3&t5_ delta 14 Wcmca7`9)$v!^Q=hxF^ryaRLA~)CQjb diff --git a/lang/ru.ini b/lang/ru.ini index fca833de5198ab08f7e17d5cb4658c8d5e5b001a..d3a5ef9fe03c413b1f9480daf87b913e4fc56916 100644 GIT binary patch delta 95 zcmZ1`^-pR-gN!3XDMJZE217nW5rZv5B9JU$NM*=nFlVq}*jSUqW9$QzN(M^gFk~`R f0qGJTozIZRfT~fR#gxSXh>ck6SWG70'; + with Localizer.LanguageInfo do + begin + if (Code <> 'en') and (Author <> '') then + begin + LocalizationAuthorLabel.Caption := Localizer.I18N('LocalizationAuthor') + ': ' + Author; + LocalizationAuthorLabel.Show; + end + else + LocalizationAuthorLabel.Hide; + end; LinkLabel.Caption := ProjectGitHubURL; BuildDate := GetLinkerTimeStamp; diff --git a/uLocalization.pas b/uLocalization.pas index 5b51154..53822db 100644 --- a/uLocalization.pas +++ b/uLocalization.pas @@ -12,6 +12,7 @@ TLanguageInfo = record Code: TLanguageCode; Name, NativeName: WideString; FileName: String; + Author: WideString; end; TLanguagesArray = array of TLanguageInfo; @@ -22,6 +23,9 @@ TLocalizer = class private Ini: TTntMemIniFile; LangsDir: String; + + function GetLanguageInfo: TLanguageInfo; + class function GetLanguageInfoFromIni(const AnIni: TTntMemIniFile): TLanguageInfo; public constructor Create(ALangsDir: String); destructor Destroy; override; @@ -30,6 +34,8 @@ TLocalizer = class procedure LoadFromFile(AFileName: String); function I18N(Str: String): WideString; procedure GetLanguages(var LangsArr: TLanguagesArray); + + property LanguageInfo: TLanguageInfo read GetLanguageInfo; end; var @@ -54,9 +60,24 @@ destructor TLocalizer.Destroy; inherited; end; -procedure TLocalizer.GetLanguages(var LangsArr: TLanguagesArray); +function TLocalizer.GetLanguageInfo: TLanguageInfo; +begin + Result := TLocalizer.GetLanguageInfoFromIni(Ini); +end; + +class function TLocalizer.GetLanguageInfoFromIni( + const AnIni: TTntMemIniFile): TLanguageInfo; const IniSection = 'info'; +begin + Result.Code := {Wide}LowerCase(AnIni.ReadString(IniSection, 'LangCode', '')); + Result.Name := AnIni.ReadString(IniSection, 'LangName', ''); + Result.NativeName := AnIni.ReadString(IniSection, 'LangNativeName', ''); + Result.FileName := AnIni.FileName; + Result.Author := AnIni.ReadString(IniSection, 'Author', ''); +end; + +procedure TLocalizer.GetLanguages(var LangsArr: TLanguagesArray); var SearchRes: TSearchRec; LangsCount: integer; @@ -87,10 +108,7 @@ procedure TLocalizer.GetLanguages(var LangsArr: TLanguagesArray); try Inc(Idx); - LangsArr[Idx].Code := {Wide}LowerCase(Ini.ReadString(IniSection, 'LangCode', '')); - LangsArr[Idx].Name := Ini.ReadString(IniSection, 'LangName', ''); - LangsArr[Idx].NativeName := Ini.ReadString(IniSection, 'LangNativeName', ''); - LangsArr[Idx].FileName := LangsDir + SearchRes.Name; + LangsArr[Idx] := TLocalizer.GetLanguageInfoFromIni(Ini); finally //Ini.Free; FreeAndNil(Ini); From 4caaba373fddc535e36133555c23e87e93ab0c28 Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 4 Jan 2021 22:48:29 +0300 Subject: [PATCH 26/31] Fix non-Unicode components --- uAbout.dfm | 2 +- uAbout.pas | 2 +- uAutoScreen.dfm | 10 +++++----- uAutoScreen.pas | 30 ++++++++++++++++-------------- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/uAbout.dfm b/uAbout.dfm index 2f1027f..e3349dc 100644 --- a/uAbout.dfm +++ b/uAbout.dfm @@ -74,7 +74,7 @@ object AboutForm: TAboutForm Height = 15 Caption = 'Build date: XX.XX.XXXX' end - object LocalizationAuthorLabel: TLabel + object LocalizationAuthorLabel: TTntLabel Left = 104 Top = 112 Width = 80 diff --git a/uAbout.pas b/uAbout.pas index af978fd..5018581 100644 --- a/uAbout.pas +++ b/uAbout.pas @@ -15,7 +15,7 @@ TAboutForm = class(TTntForm) LinkLabel: TTntLabel; Logo: TTntImage; BuildDateLabel: TTntLabel; - LocalizationAuthorLabel: TLabel; + LocalizationAuthorLabel: TTntLabel; procedure CloseButtonClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure LinkLabelClick(Sender: TObject); diff --git a/uAutoScreen.dfm b/uAutoScreen.dfm index 0ecd937..8212e3e 100755 --- a/uAutoScreen.dfm +++ b/uAutoScreen.dfm @@ -315,18 +315,18 @@ object MainForm: TMainForm Left = 16 Top = 168 end - object MainMenu: TMainMenu + object MainMenu: TTntMainMenu Left = 40 Top = 40 - object OptionsSubMenu: TMenuItem + object OptionsSubMenu: TTntMenuItem Caption = 'Options' - object LanguageSubMenu: TMenuItem + object LanguageSubMenu: TTntMenuItem Caption = 'Language' end end - object HelpSubMenu: TMenuItem + object HelpSubMenu: TTntMenuItem Caption = 'Help' - object AboutMenuItem: TMenuItem + object AboutMenuItem: TTntMenuItem Caption = 'About...' OnClick = AboutMenuItemClick end diff --git a/uAutoScreen.pas b/uAutoScreen.pas index 82ca733..9df543a 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -63,11 +63,11 @@ TMainForm = class({TTntForm} TForm) CaptureInterval: TTntDateTimePicker; TrayIconAnimationTimer: TTimer; AutoRunCheckBox: TTntCheckBox; - MainMenu: TMainMenu; - HelpSubMenu: TMenuItem; - AboutMenuItem: TMenuItem; - OptionsSubMenu: TMenuItem; - LanguageSubMenu: TMenuItem; + MainMenu: TTntMainMenu; + HelpSubMenu: TTntMenuItem; + AboutMenuItem: TTntMenuItem; + OptionsSubMenu: TTntMenuItem; + LanguageSubMenu: TTntMenuItem; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure ChooseOutputDirButtonClick(Sender: TObject); @@ -125,8 +125,8 @@ TMainForm = class({TTntForm} TForm) procedure UpdateColorDepthValues; procedure UpdateLanguages; procedure LanguageClick(Sender: TObject); - function GetLangCodeOfLangMenuItem(const LangItem: TMenuItem): TLanguageCode; - function FindLangMenuItem(ALangCode: TLanguageCode): TMenuItem; + function GetLangCodeOfLangMenuItem(const LangItem: TTntMenuItem): TLanguageCode; + function FindLangMenuItem(ALangCode: TLanguageCode): TTntMenuItem; property IsTimerEnabled: Boolean read GetTimerEnabled write SetTimerEnabled; property FinalOutputDir: String read GetFinalOutputDir; @@ -928,7 +928,7 @@ procedure TMainForm.UpdateLanguages; var Lang: TLanguageInfo; I: integer; - MenuItem: TMenuItem; + MenuItem: TTntMenuItem; begin while LanguageSubMenu.Count > 0 do LanguageSubMenu.Items[0].Free; @@ -941,7 +941,7 @@ procedure TMainForm.UpdateLanguages; if (Lang.Name <> '') and (Lang.Code <> '') then begin - MenuItem := TMenuItem.Create(LanguageSubMenu); + MenuItem := TTntMenuItem.Create(LanguageSubMenu); MenuItem.Caption := Lang.Name; if (Lang.NativeName <> '') and (Lang.NativeName <> Lang.Name) then MenuItem.Caption := MenuItem.Caption + ' (' + Lang.NativeName + ')'; @@ -961,22 +961,24 @@ procedure TMainForm.LanguageClick(Sender: TObject); Idx: integer; LangCode: TLanguageCode; begin - Idx := (Sender as TMenuItem).MenuIndex; + Idx := (Sender as TTntMenuItem).MenuIndex; LangCode := AvailableLanguages[Idx].Code; SetLanguageByCode(LangCode); end; -function TMainForm.FindLangMenuItem(ALangCode: TLanguageCode): TMenuItem; +function TMainForm.FindLangMenuItem(ALangCode: TLanguageCode): TTntMenuItem; var I: integer; LangCode: TLanguageCode; + MenuItem: TTntMenuItem; begin for I := 0 to LanguageSubMenu.Count - 1 do begin - LangCode := GetLangCodeOfLangMenuItem(LanguageSubMenu.Items[I]); + MenuItem := (LanguageSubMenu.Items[I] as TTntMenuItem); // Items[] returns TMenuItem instead od TTntMenuItem + LangCode := GetLangCodeOfLangMenuItem(MenuItem); if LangCode = ALangCode then begin - Result := LanguageSubMenu.Items[I]; + Result := MenuItem; Exit; end; end; @@ -985,7 +987,7 @@ function TMainForm.FindLangMenuItem(ALangCode: TLanguageCode): TMenuItem; end; function TMainForm.GetLangCodeOfLangMenuItem( - const LangItem: TMenuItem): TLanguageCode; + const LangItem: TTntMenuItem): TLanguageCode; begin if Pos(LanguageSubMenuItemNamePrefix, LangItem.Name) = 1 then Result := Copy(LangItem.Name, Length(LanguageSubMenuItemNamePrefix) + 1, 2) From e7d2694ae74cb55c9467fe3b1ae1949881651069 Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 4 Jan 2021 22:53:05 +0300 Subject: [PATCH 27/31] Localization fix --- uAutoScreen.pas | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/uAutoScreen.pas b/uAutoScreen.pas index 9df543a..e7b5d47 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -961,8 +961,7 @@ procedure TMainForm.LanguageClick(Sender: TObject); Idx: integer; LangCode: TLanguageCode; begin - Idx := (Sender as TTntMenuItem).MenuIndex; - LangCode := AvailableLanguages[Idx].Code; + LangCode := GetLangCodeOfLangMenuItem(Sender as TTntMenuItem); SetLanguageByCode(LangCode); end; From e558b2993cf180d83864adec2cd90987e227010b Mon Sep 17 00:00:00 2001 From: Artem Date: Tue, 5 Jan 2021 14:48:49 +0300 Subject: [PATCH 28/31] [Localization] Alternative languages --- lang/ru.ini | Bin 3454 -> 3504 bytes uAutoScreen.pas | 31 +++++++++++++++---------------- uLocalization.pas | 14 +++++++++++++- uUtils.pas | 24 +++++++++++++++++++++++- 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/lang/ru.ini b/lang/ru.ini index d3a5ef9fe03c413b1f9480daf87b913e4fc56916..3ca499ce465002707ed1b209912a2dbb50a2bdfd 100644 GIT binary patch delta 55 zcmew-wLyA9lTHpp2}3GF5knqBB9N8IPzL0=G2{b9Y#EXmau{@gWGav>WyogOSi{5% E0F`wN%>V!Z delta 10 RcmdlW{ZDE_)5a}-cmN$y1!DjJ diff --git a/uAutoScreen.pas b/uAutoScreen.pas index e7b5d47..41c6e07 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -217,14 +217,12 @@ procedure TMainForm.ReadSettings; DefaultCaptureInterval = 5; DefaultImageFormat = fmtPNG; DefaultJPEGQuality = 80; - //DefaultLanguage = lngEnglish; + DefaultLanguage = 'en'; DefaultColorDepth = cd24Bit; var DefaultOutputDir: String; - SystemLanguageCode: String; - DefaultLanguage: TLanguageCode; + CfgLang, SysLang, AltLang: TLanguageCode; FmtStr: String; - LangCode: TLanguageCode; Seconds: Integer; begin DefaultOutputDir := IncludeTrailingPathDelimiter(JoinPath(ExtractFilePath(Application.ExeName), 'screenshots')); @@ -267,20 +265,21 @@ procedure TMainForm.ReadSettings; end; // Language - SystemLanguageCode := GetSystemLanguageCode; - if (SystemLanguageCode = 'ru') {Russian} - or (SystemLanguageCode = 'be') {Belorussian} - or (SystemLanguageCode = 'bl') {Belorussian} - or (SystemLanguageCode = 'uk') {Ukrainian} then - DefaultLanguage := 'ru' - else - DefaultLanguage := 'en'; - - LangCode := Ini.ReadString(DefaultConfigIniSection, 'Language', DefaultLanguage); try - SetLanguageByCode(LangCode); + CfgLang := Ini.ReadString(DefaultConfigIniSection, 'Language', ''); + SetLanguageByCode(CfgLang); except - SetLanguageByCode(DefaultLanguage); + try + SysLang := GetSystemLanguageCode; + SetLanguageByCode(SysLang); + except + try + AltLang := GetAlternativeLanguage(AvailableLanguages, SysLang); + SetLanguageByCode(AltLang); + except + SetLanguageByCode(DefaultLanguage); + end; + end; end; // Start autocapture diff --git a/uLocalization.pas b/uLocalization.pas index 53822db..bcf3c5c 100644 --- a/uLocalization.pas +++ b/uLocalization.pas @@ -12,6 +12,7 @@ TLanguageInfo = record Code: TLanguageCode; Name, NativeName: WideString; FileName: String; + AlternativeFor: array of TLanguageCode; Author: WideString; end; @@ -43,7 +44,7 @@ TLocalizer = class implementation -uses uUtils; +uses uUtils, Classes; { TLocalizer } @@ -69,11 +70,22 @@ class function TLocalizer.GetLanguageInfoFromIni( const AnIni: TTntMemIniFile): TLanguageInfo; const IniSection = 'info'; +var + AlternativeForStr: TStringList; + I: integer; begin Result.Code := {Wide}LowerCase(AnIni.ReadString(IniSection, 'LangCode', '')); Result.Name := AnIni.ReadString(IniSection, 'LangName', ''); Result.NativeName := AnIni.ReadString(IniSection, 'LangNativeName', ''); Result.FileName := AnIni.FileName; + + AlternativeForStr := TStringList.Create; + AlternativeForStr.CommaText := AnIni.ReadString(IniSection, 'AlternativeFor', ''); + SetLength(Result.AlternativeFor, AlternativeForStr.Count); + for I := 0 to AlternativeForStr.Count - 1 do + Result.AlternativeFor[I] := AlternativeForStr.Strings[I]; + AlternativeForStr.Free; + Result.Author := AnIni.ReadString(IniSection, 'Author', ''); end; diff --git a/uUtils.pas b/uUtils.pas index fb2e45e..1c7ac68 100644 --- a/uUtils.pas +++ b/uUtils.pas @@ -5,7 +5,7 @@ interface uses - Windows; + Windows, uLocalization; // Retrieves the time (in ms) of the last input event (mouse moved or key pressed). // Also works if current application window has no focus (hidden or minimized). @@ -73,6 +73,8 @@ function GetCurrentUserName: string; { Returns two-letter language code from ISO 639 standard. } function GetSystemLanguageCode: String{[2]}; +function GetAlternativeLanguage(const ALangs: TLanguagesArray; + ALangCode: TLanguageCode): TLanguageCode; procedure AutoRun(const FileName: String; const AppTitle: String; Enabled: Boolean = True); @@ -307,6 +309,26 @@ function GetSystemLanguageCode: String{[2]}; end; end; +function GetAlternativeLanguage(const ALangs: TLanguagesArray; + ALangCode: TLanguageCode): TLanguageCode; +var + LangIdx, AltIdx: Integer; +begin + for LangIdx := 0 to Length(ALangs) - 1 do + begin + for AltIdx := 0 to Length(ALangs[LangIdx].AlternativeFor) - 1 do + begin + if ALangs[LangIdx].AlternativeFor[AltIdx] = ALangCode then + begin + Result := ALangs[LangIdx].Code; + Exit; + end; + end; + end; + + Result := ''; // Not found +end; + procedure SetAutoRun(const FileName: String; const AppTitle: String); const Section = 'Software\Microsoft\Windows\CurrentVersion\Run' + #0; From d58c0be6bd66d7e14813e725941890170de85c30 Mon Sep 17 00:00:00 2001 From: Artem Date: Tue, 5 Jan 2021 20:37:49 +0300 Subject: [PATCH 29/31] Remove unused variable --- uAutoScreen.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/uAutoScreen.pas b/uAutoScreen.pas index 41c6e07..846d086 100755 --- a/uAutoScreen.pas +++ b/uAutoScreen.pas @@ -957,7 +957,6 @@ procedure TMainForm.UpdateLanguages; procedure TMainForm.LanguageClick(Sender: TObject); var - Idx: integer; LangCode: TLanguageCode; begin LangCode := GetLangCodeOfLangMenuItem(Sender as TTntMenuItem); From b0a9ab98e5d17f908c3a387853405f0a05151076 Mon Sep 17 00:00:00 2001 From: Artem Date: Tue, 5 Jan 2021 21:06:37 +0300 Subject: [PATCH 30/31] Comment --- uUtils.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/uUtils.pas b/uUtils.pas index 1c7ac68..402166c 100644 --- a/uUtils.pas +++ b/uUtils.pas @@ -289,6 +289,7 @@ function GetCurrentUserName: string; function GetSystemLanguageCode: String{[2]}; { FixMe: Not always returns code in ISO 639 standard. For example, Belorussian ISO 639 code is BE/BEL, but function returns BL/BLR. } + // List of ISO 639 codes: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes var //LID: LangID; Buffer: PChar; From 14d081df7ab7ed19d0918e338759ca87cd153574 Mon Sep 17 00:00:00 2001 From: Artem Date: Wed, 6 Jan 2021 11:22:12 +0300 Subject: [PATCH 31/31] English localization --- lang/en.ini | Bin 3530 -> 3526 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/lang/en.ini b/lang/en.ini index bc16265ee448fad802b472e0143ee1d62d1d984e..28d2f5f28c3374f2736711a228fb90f2062021da 100644 GIT binary patch delta 21 ccmX>leN1{o882rlLkfceLlQ&fmeM)*m8Smr(UN&|Gh9rhc2CK>SyzT&5zXp;3