unit fm_settings; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Graphics, Dialogs, ComCtrls, Spin, StdCtrls, ExtCtrls, ActnList, Controls, Buttons, CheckLst, LazFileUtils, LazUTF8, Math, AppLocalizer, AppTuner, AppSettings, fm_gen, fm_importc, fm_preview, fm_map, u_encodings, u_sticking, u_strings, config_record; const LANGUAGES_DIR = 'lang'; LANGUAGE_FILE = 'matrixFont'; LANGUAGES_FILE = 'languages.ini'; type { TfmSettings } TfmSettings = class(TForm) {$INCLUDE i_settings_controls.inc} procedure FormCreate(Sender: TObject); procedure FormShow(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure acOKExecute(Sender: TObject); procedure acCancelExecute(Sender: TObject); procedure clbStickingSelectionChange(Sender: TObject; User: Boolean); procedure cbLanguageChange(Sender: TObject); procedure cbStickingCtrlChange(Sender: TObject); procedure cbCharNameClick(Sender: TObject); procedure tvTabsSelectionChanged(Sender: TObject); procedure udStickingOrderChangingEx(Sender: TObject; var AllowChange: Boolean; NewValue: SmallInt; Direction: TUpDownDirection); private procedure AdjustComponentsSizes; procedure FormAutosize; procedure InitConfig; procedure InitPages; procedure OnLangChange(Sender: TObject); procedure StickingListUpdate; end; var fmSettings: TfmSettings; implementation {$R *.lfm} { TfmSettings } procedure TfmSettings.FormCreate(Sender: TObject); var i: Integer; a: TComboBox; s: String; c: TControl; begin for a in [cbCharNameFont, cbCodeNameFont] do begin s := a.Text; a.Items := Screen.Fonts; a.Text := ''; a.Text := s; end; appLocalizerEx.AddOnLanguageChangeHandler(@OnLangChange); appLocalizerEx.Load( Format('%0:s%1:s%0:s%2:s', [DirectorySeparator, LANGUAGES_DIR, LANGUAGES_FILE]), Format('%0:s%1:s%0:s%2:s', [DirectorySeparator, LANGUAGES_DIR, LANGUAGE_FILE])); // theme selector cbTheme.Items.AddStrings(CAppTheme); cbTheme.ItemIndex := Integer(appTunerEx.Theme); cbTheme.Enabled := appTunerEx.IsDarkThemeAvailable; cbLanguage.Items.SetStrings(appLocalizerEx.Languages); cbLanguage.ItemIndex := 0; Settings.IniFile := ExtractFilePath(ParamStrUTF8(0)) + SETTINGS_FILE; InitConfig; EncodingsListAssign(cbEncoding.Items); cbEncoding.ItemIndex := 0; // add chapter titles to treeview for i := 0 to pcPageCtrl.PageCount - 1 do tvTabs.Items.Add(TTreeNode.Create(nil), pcPageCtrl.Page[i].Caption); // disable dark theme color buttons if dark theme is not available if not appTunerEx.IsDarkThemeAvailable then begin for c in [pTitle2, pValues37, pValues38, pValues39, pValues40, pValues41, cbtnActiveD, cbtnBackgroundD, cbtnGridD, cbtnImportAD, cbtnImportBGD, cbtnMapAD, cbtnMapBGD, cbtnMapExportBGD, cbtnMapSelAD, cbtnMapSelBGD, cbtnNaviAD, cbtnNaviBGD, cbtnNaviTD, cbtnPreviewAD, cbtnPreviewBGD] do c.Visible := False; end; // dark theme fixes if appTunerEx.IsDarkTheme then begin nbPages.Color := clWindow; for i := 0 to ComponentCount - 1 do if TControl(Components[i]).Color = cl3DLight then TControl(Components[i]).Color := cl3DDkShadow; end; InitPages; end; procedure TfmSettings.FormShow(Sender: TObject); begin // execute this block only once if Tag = 0 then begin Tag := 1; Settings.SyncComponents; cbCharNameClick(nil); cbLanguageChange(Sender); end; clbStickingSelectionChange(Sender, True); cbStickingCtrlChange(Sender); Position := poDefault; FormAutosize; Position := poMainFormCenter; end; procedure TfmSettings.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin if ModalResult = mrCancel then acCancel.Execute; end; procedure TfmSettings.FormAutosize; var tmp, i: Integer; begin AdjustComponentsSizes; tmp := nbPages.PageIndex; for i := 0 to nbPages.PageCount - 1 do begin nbPages.PageIndex := i; AutoSize := True; Constraints.MinWidth := Width; Constraints.MinHeight := Height; AutoSize := False; end; nbPages.PageIndex := tmp; end; procedure TfmSettings.AdjustComponentsSizes; var i: Integer; w: Integer = 0; c: TControl; g: array of TControl; begin // get tree view min width for i := 0 to tvTabs.Items.Count - 1 do w := Max(w, Canvas.GetTextWidth(tvTabs.Items.Item[i].Text)); // set tree view min sizes tvTabs.Constraints.MinWidth := w + tvTabs.Indent * 2 + VertScrollBar.Size; tvTabs.Constraints.MinHeight := tvTabs.Items.Count * tvTabs.DefaultItemHeight; // sticking forms list sizes with clbSticking do begin ItemHeight := Canvas.TextHeight('0') * 13 div 10; Constraints.MinHeight := Count * ItemHeight; Constraints.MaxHeight := Constraints.MinHeight; end; // up/down arrows width udStickingOrder.Width := cbStickingSide.Height * 13 div 10; // justify color buttons sizes i := 0; g := [lbColorEditor, lbColorNavi, lbColorPreview, lbColorImport, lbColorMap]; for c in g do i := Max(i, TLabel(c).Canvas.TextWidth(TLabel(c).Caption)); for c in g do c.Constraints.MinWidth := i; end; procedure TfmSettings.InitConfig; begin Settings.Add(cbLanguage, @cfg.app.lang); Settings.Add(seIconsScale, @cfg.app.iconscale); Settings.Add(cbLastFileAtStart, @cfg.app.loadlast); Settings.Add(cbAppUpdateWay, @cfg.app.update.wayIndex); Settings.Add(cbAppUpdateFreq, @cfg.app.update.freqIndex); Settings.Add(seBWTreshold, @cfg.import.bwlevel); Settings.Add(seCharUndoLimit, @cfg.editor.undolimit); Settings.Add(rbOpenMapSngClick, @cfg.map.sclick); Settings.Add(rbOpenMapDblClick, @cfg.map.dclick); Settings.Add(seMapExportScale, @cfg.map.export.scale); Settings.Add(seMapExportSpace, @cfg.map.export.space); Settings.Add(cbPreviewRefresh, @cfg.prev.refresh); Settings.Add(cbGenerateAuto, @cfg.gen.refresh); Settings.Add(cbtnActive, @cfg.colorl.editor.active); Settings.Add(cbtnBackground, @cfg.colorl.editor.bg); Settings.Add(cbtnGrid, @cfg.colorl.editor.grid); Settings.Add(cbtnPreviewA, @cfg.colorl.prev.active); Settings.Add(cbtnPreviewBG, @cfg.colorl.prev.bg); Settings.Add(cbtnNaviA, @cfg.colorl.nav.active); Settings.Add(cbtnNaviBG, @cfg.colorl.nav.bg); Settings.Add(cbtnNaviT, @cfg.colorl.nav.txt); Settings.Add(cbtnImportA, @cfg.colorl.import.active); Settings.Add(cbtnImportBG, @cfg.colorl.import.bg); Settings.Add(cbtnMapA, @cfg.colorl.map.active); Settings.Add(cbtnMapBG, @cfg.colorl.map.bg); Settings.Add(cbtnMapSelA, @cfg.colorl.map.selact); Settings.Add(cbtnMapSelBG, @cfg.colorl.map.selbg); Settings.Add(cbtnMapExportBG, @cfg.colorl.map.export); Settings.Add(cbtnActiveD, @cfg.colord.editor.active); Settings.Add(cbtnBackgroundD, @cfg.colord.editor.bg); Settings.Add(cbtnGridD, @cfg.colord.editor.grid); Settings.Add(cbtnPreviewAD, @cfg.colord.prev.active); Settings.Add(cbtnPreviewBGD, @cfg.colord.prev.bg); Settings.Add(cbtnNaviAD, @cfg.colord.nav.active); Settings.Add(cbtnNaviBGD, @cfg.colord.nav.bg); Settings.Add(cbtnNaviTD, @cfg.colord.nav.txt); Settings.Add(cbtnImportAD, @cfg.colord.import.active); Settings.Add(cbtnImportBGD, @cfg.colord.import.bg); Settings.Add(cbtnMapAD, @cfg.colord.map.active); Settings.Add(cbtnMapBGD, @cfg.colord.map.bg); Settings.Add(cbtnMapSelAD, @cfg.colord.map.selact); Settings.Add(cbtnMapSelBGD, @cfg.colord.map.selbg); Settings.Add(cbtnMapExportBGD, @cfg.colord.map.export); Settings.Add(seNaviHeight, @cfg.nav.rowheight); Settings.Add(cbNaviTransparent, @cfg.nav.transparent); Settings.Add(cbNaviInvert, @cfg.nav.invert); Settings.Add(cbNaviScroll, @cfg.nav.scroll); Settings.Add(cbCharName, @cfg.nav.char.enable); Settings.Add(cbCharNameFont, @cfg.nav.char.font); Settings.Add(seCharNameFontSize, @cfg.nav.char.fontsize); Settings.Add(cbCodeName, @cfg.nav.code.enable); Settings.Add(cbCodeNameFont, @cfg.nav.code.font); Settings.Add(seCodeNameFontSize, @cfg.nav.code.fontsize); Settings.Add(cbCodeHex, @cfg.nav.code.hex); Settings.Add(edFontName, @cfg.new.title); Settings.Add(edAuthor, @cfg.new.author); Settings.Add(seNewWidth, @cfg.new.w); Settings.Add(seNewHeight, @cfg.new.h); Settings.Add(seNewItemStart, @cfg.new.start); Settings.Add(seNewItemLast, @cfg.new.last); Settings.Add(cbEncoding, @cfg.new.enc); Settings.Add(cbStickingBorder, @cfg.sticking.correct); Settings.Add(cbStickingEnable, @cfg.sticking.enable); Settings.Add('_cfg.sticking.config', stString, @cfg.sticking.config, ''); end; procedure TfmSettings.InitPages; var i, k: Integer; begin { In design time we use 'TPageControl:pcPageCtrl' for convenient GUI building. But in run-time there are some issues, such as unexpected flickering. So in run time we use 'TNotebook:nbPages' to show our GUI. Here we move all content from 'pcPageCtrl' to 'nbPages' pages. } pcPageCtrl.Hide; pcPageCtrl.Align := alNone; nbPages.Align := alClient; for i := 0 to pcPageCtrl.PageCount - 1 do with pcPageCtrl.Pages[i] do begin nbPages.Pages.Add('npPage' + Name); nbPages.Page[i].ChildSizing.Assign(ChildSizing); for k := 0 to ControlCount - 1 do Controls[0].Parent := nbPages.Page[i]; end; nbPages.PageIndex := 0; end; procedure TfmSettings.OnLangChange(Sender: TObject); var i: Integer; CEncList: TStringList; begin BeginFormUpdate; appLocalizerEx.Localize(cbTheme, TXT_THEME); // translate tree view tabs for i := 0 to pcPageCtrl.PageCount - 1 do if i < tvTabs.Items.Count then tvTabs.Items.Item[i].Text := pcPageCtrl.Pages[i].Caption; try try CEncList := TStringList.Create; EncodingsListUpdate; EncodingsListAssign(CEncList); appLocalizerEx.Localize(cbEncoding, CEncList.ToStringArray); finally CEncList.Free; end; except end; fmGen.OnLanguageChange; fmImportC.OnLanguageChange; StickingFormsEx.Rename(fmPreview, FM_PREV_EXAMPLE); StickingFormsEx.Rename(fmMap, FM_MAP_CAPTION); StickingFormsEx.Rename(fmGen, FM_GEN_CAPTION); appLocalizerEx.Localize(cbStickingSide, STFM_ANCHOR_TXT); appLocalizerEx.Localize(cbStickingSize, STFM_SIZE_TXT); appLocalizerEx.Localize(cbAppUpdateWay, TXT_UPDATE_WAY); appLocalizerEx.Localize(cbAppUpdateFreq, TXT_UPDATE_FREQ); EndFormUpdate; end; procedure TfmSettings.StickingListUpdate; var i, s: Integer; begin s := clbSticking.ItemIndex; clbSticking.Clear; with StickingFormsEx do for i := 0 to Count - 1 do begin clbSticking.Items.Add(Format('%s: %s, %s', [ FormByIndex[i].Name, UTF8LowerCase(STFM_ANCHOR_TXT[FormByIndex[i].Anchor]), UTF8LowerCase(STFM_SIZE_TXT[FormByIndex[i].FullSize])])); clbSticking.Checked[i] := FormByIndex[i].Enable; end; clbSticking.ItemIndex := s; end; procedure TfmSettings.acOKExecute(Sender: TObject); begin Settings.SyncValues; appTunerEx.Theme := TAppTheme(cbTheme.ItemIndex); ModalResult := mrOk; end; procedure TfmSettings.acCancelExecute(Sender: TObject); begin Settings.SyncComponents; cbLanguageChange(Sender); StickingFormsEx.Config := cfg.sticking.config; ModalResult := mrCancel; end; procedure TfmSettings.clbStickingSelectionChange(Sender: TObject; User: Boolean); begin try with StickingFormsEx.FormByIndex[clbSticking.ItemIndex] do begin cbStickingSide.ItemIndex := Ord(Anchor); cbStickingSize.ItemIndex := Ord(FullSize); end; except end; end; procedure TfmSettings.cbLanguageChange(Sender: TObject); var c: TControl; g: array of TControl; begin BeginFormUpdate; appLocalizerEx.CurrentLanguage := cbLanguage.ItemIndex; StickingListUpdate; // light theme labels g := [lbColorsL2, lbColorsL3, lbColorsL4, lbColorsL5]; for c in g do c.Caption := lbColorsL1.Caption; for c in g do c.Hint := lbColorsL1.Hint; // dark theme labels g := [lbColorsD2, lbColorsD3, lbColorsD4, lbColorsD5]; for c in g do c.Caption := lbColorsD1.Caption; for c in g do c.Hint := lbColorsD1.Hint; EndFormUpdate; end; procedure TfmSettings.cbStickingCtrlChange(Sender: TObject); begin pStickingForms.Enabled := cbStickingEnable.Checked; clbSticking.Enabled := cbStickingEnable.Checked; if clbSticking.ItemIndex >= 0 then with StickingFormsEx.FormByIndex[clbSticking.ItemIndex] do begin Enable := clbSticking.Checked[clbSticking.ItemIndex]; Anchor := TAnchorKind(cbStickingSide.ItemIndex); FullSize := cbStickingSize.ItemIndex > 0; end; StickingListUpdate; end; procedure TfmSettings.tvTabsSelectionChanged(Sender: TObject); begin nbPages.Page[tvTabs.Selected.AbsoluteIndex].Show; end; procedure TfmSettings.cbCharNameClick(Sender: TObject); begin if (TCheckBox(Sender) = cbCharName) and not cbCharName.Checked then cbCodeName.Checked := True; if (TCheckBox(Sender) = cbCodeName) and not cbCodeName.Checked then cbCharName.Checked := True; cbCharNameFont.Enabled := cbCharName.Checked; seCharNameFontSize.Enabled := cbCharName.Checked; cbCodeNameFont.Enabled := cbCodeName.Checked; seCodeNameFontSize.Enabled := cbCodeName.Checked; cbCodeHex.Enabled := cbCodeName.Checked; end; procedure TfmSettings.udStickingOrderChangingEx(Sender: TObject; var AllowChange: Boolean; NewValue: SmallInt; Direction: TUpDownDirection); var i, j, c: Integer; begin c := clbSticking.Count - 1; i := clbSticking.ItemIndex; j := i; if (Direction = updUp) and (i > 0) then j := i - 1; if (Direction = updDown) and (i < c) then j := i + 1; if (i < 0) or (i = j) then Exit; StickingFormsEx.Exchange(i, j); StickingListUpdate; clbSticking.ItemIndex := j; end; end.