unit TBX_DTM; interface uses classes, TBXDTMForm; {$Warn symbol_Platform off} type TThemeFolderLocation = (flRelative, flAbsolute); TThemeSettingsLocation = (slRegistry, slIniFile); TTBXDynamicThemeManager = class(TComponent) private fPersistLast: boolean; fAutoLoad: boolean; fThemeFolder: string; fFolderLocation: TThemeFolderLocation; FFilterIndex: Integer; FFilter: string; fTitle: string; fDefaultExt: string; procedure LoadThemes(Sender:TObject; ThemeFiles:TStrings); procedure UnloadTheme(Sender:TObject; ThemeIndex: Integer); procedure RefreshThemes(Sender:TObject; ThemeList:TStrings); procedure ActivateTheme(Sender:TObject; ThemeIndex:integer); protected procedure Loaded; override; function ThemePath:string; procedure AutoLoad; procedure LoadLastTheme; public procedure Execute; constructor Create(AOwner: TComponent); override; published property ThemeFolderLocation : TThemeFolderLocation read fFolderLocation write fFolderLocation default flRelative; property ThemesFolder : string read fThemeFolder write fThemeFolder; property Filter: string read FFilter write FFilter; property FilterIndex: Integer read fFilterIndex write FFilterIndex default 1; property DefaultExt : string read fDefaultExt write fDefaultExt; property Title : string read fTitle write fTitle; property AutoLoadThemes : boolean read fAutoLoad write fAutoLoad default false; property PersistLastTheme : boolean read fPersistLast write fPersistLast default true; end; procedure UnloadThemes; procedure Register; implementation uses Windows, dialogs, sysutils, IniFiles, TBX, TBXThemes, Math; procedure Register; begin RegisterComponents('Toolbar2000', [TTBXDynamicThemeManager]); end; type TThemeObj = class(TObject) PackageHandle : THandle; FileName : String; ThemeName : ShortString; end; TThemeName = function : ShortString; stdcall; TRegisterTheme = Procedure(RegisterTheme:boolean); stdcall; var gLoadedThemes : TList; procedure UnloadThemes; var wTheme : TThemeObj; P2 : TRegisterTheme; begin If CurrentTheme.Name <> 'Default' then TBXSetTheme('Default'); while gLoadedThemes.Count > 0 do begin wTheme := gLoadedThemes[0]; P2 := GetProcAddress(wTheme.PackageHandle, 'TBXRegisterTheme'); P2(False); gLoadedThemes.Delete(0); UnloadPackage(wTheme.PackageHandle); wTheme.free; end; end; { TTBXDynamicThemeManager } procedure TTBXDynamicThemeManager.ActivateTheme(Sender:TObject; ThemeIndex:integer); var wFileName : string; wThemeName : string; wTheme : TThemeObj; wIni : TIniFile; begin if fPersistLast then begin if ThemeIndex > -1 then begin wTheme := gLoadedThemes[ThemeIndex]; wFileName := wTheme.FileName; wThemeName := wTheme.ThemeName; end else begin wThemeName := ''; wFileName := ''; end; wIni := TIniFile.Create(ThemePath+'Theme.ini'); try wIni.WriteString('ActiveTheme','FileName',wFileName); wIni.WriteString('ActiveTheme','ThemeName',wThemeName); finally wIni.free; end; end; if ThemeIndex > -1 then TBXSetTheme(wThemeName) else TBXSetTheme('Default'); end; procedure TTBXDynamicThemeManager.AutoLoad; var wFileList : TStringList; dirinfo : TSearchRec; ds : integer; begin if fAutoLoad then begin wFileList := TStringList.create; try ds := findfirst(ThemePath+'*.'+defaultext, $3f, dirinfo); while ds = 0 do begin if dirinfo.Attr and fadirectory = 0 then wFileList.add(ThemePath+dirinfo.Name); ds := findnext(dirinfo); end; FindClose(dirinfo); LoadThemes(self, wFileList); finally wFileList.free; end; end; end; constructor TTBXDynamicThemeManager.Create(AOwner: TComponent); begin inherited; fFilter := 'TBX Theme Package|*.tbxt|All Files|*.*'; FFilterIndex := 1; fTitle := 'TBX Theme Manager'; fFolderLocation := flRelative; fThemeFolder := 'Themes'; fDefaultExt := 'tbxt'; fPersistLast := true; fAutoLoad := false; end; procedure TTBXDynamicThemeManager.Execute; var wFrm : TfrmTBXDTM; begin wFrm := TfrmTBXDTM.create(self); try wFrm.OnRefreshThemes := RefreshThemes; wFrm.OnLoadNewTheme := LoadThemes; wFrm.OnUnloadTheme := UnloadTheme; wFrm.OnActivateTheme := ActivateTheme; wFrm.Caption := fTitle; wFrm.OpenDialog1.InitialDir := ThemePath; wFrm.OpenDialog1.Title := fTitle; wFrm.OpenDialog1.Filter := FFilter; wFrm.OpenDialog1.FilterIndex := FFilterIndex; wFrm.ShowModal; finally wFrm.free; end; end; procedure TTBXDynamicThemeManager.Loaded; begin inherited; if not (csdesigning in componentstate) then begin AutoLoad; LoadLastTheme; end; end; procedure TTBXDynamicThemeManager.LoadLastTheme; var wIni : TIniFile; wFile : TStringList; wFileName : string; wThemeName : string; wFound : boolean; loop : integer; wTheme : TThemeObj; begin if fPersistLast and fileexists(ThemePath+'Theme.ini') then begin wIni := TIniFile.Create(ThemePath+'Theme.ini'); try wFileName := trim(wIni.ReadString('ActiveTheme','FileName','')); wThemeName := trim(wIni.ReadString('ActiveTheme','ThemeName','')); finally wIni.free; end; loop := 0; wFound := false; while not wFound and (loop < gLoadedThemes.count) do begin wTheme := gLoadedThemes[loop]; wFound := AnsiCompareText(wTheme.ThemeName, wThemeName) = 0; if not wFound then inc(loop); end; if not wFound and fileexists(wfilename) then begin wFile := TStringList.create; try wFile.add(wFileName); LoadThemes(self, wFile); finally wFile.free; end; end; if Trim(wThemeName) <> '' then TBXSetTheme(wThemeName); end; end; procedure TTBXDynamicThemeManager.LoadThemes(Sender: TObject; ThemeFiles: TStrings); var wTheme : TThemeObj; loop : integer; wFound : boolean; wFoundName : string; P1 : TThemeName; P2 : TRegisterTheme; begin while ThemeFiles.Count > 0 do begin wFound := false; loop := 0; while not wFound and (loop < gLoadedThemes.Count) do begin wTheme := gLoadedThemes[loop]; wFound := AnsiCompareText(extractfilename(wTheme.FileName), extractfilename(ThemeFiles[0])) = 0; if not wFound then inc(loop) else wFoundName := wTheme.ThemeName; end; if wFound then begin messagedlg(wFoundName+' is already loaded', mtError, [mbok], 0); end else begin wTheme := TThemeObj.create; try wTheme.FileName := ThemeFiles[0]; wTheme.PackageHandle := LoadPackage(ThemeFiles[0]); if wTheme.PackageHandle > 0 then begin P2 := GetProcAddress(wTheme.PackageHandle, 'TBXRegisterTheme'); P1 := GetProcAddress(wTheme.PackageHandle, 'TBXThemeName'); if Assigned(P1) and Assigned(P2) then begin Try P2(true); except messagedlg('An unknown error has occured while trying to register the theme file:'#13#10#13#10+ThemeFiles[0], mterror, [mbok], 0); abort; end; if IsTBXThemeAvailable(P1) then begin wTheme.ThemeName := P1; gLoadedThemes.Add(wTheme); end else begin messagedlg('An unknown error has occured while trying to load the theme file:'#13#10#13#10+ThemeFiles[0], mterror, [mbok], 0); Abort; end; end else begin messagedlg('Unable to load the specified TBX Theme file.'#13#10#13#10+ThemeFiles[0], mterror, [mbok], 0); Abort; end; end else begin messagedlg('Unable to load the specified TBX Theme file.'#13#10#13#10+ThemeFiles[0], mterror, [mbok], 0); Abort; end; except if wTheme.PackageHandle > 0 then UnloadPackage(wTheme.PackageHandle); freeandnil(wTheme); end; end; ThemeFiles.delete(0); end; end; procedure TTBXDynamicThemeManager.RefreshThemes(Sender: TObject; ThemeList: TStrings); var loop : integer; wTheme : TThemeObj; begin ThemeList.Clear; for loop := 0 to gLoadedThemes.Count-1 do begin wTheme := gLoadedThemes[loop]; ThemeList.Add(wTheme.ThemeName); end; end; function TTBXDynamicThemeManager.ThemePath: string; begin if fFolderLocation = flRelative then result := extractfilepath(ParamStr(0))+fThemeFolder else result := fThemeFolder; result := IncludeTrailingBackslash(result); if not DirectoryExists(result) then ForceDirectories(result); end; procedure TTBXDynamicThemeManager.UnloadTheme(Sender: TObject; ThemeIndex: Integer); var wTheme : TThemeObj; P2 : TRegisterTheme; begin try wTheme := gLoadedThemes[ThemeIndex]; P2 := GetProcAddress(wTheme.PackageHandle, 'TBXRegisterTheme'); P2(False); UnloadPackage(wTheme.PackageHandle); gLoadedThemes.Delete(ThemeIndex); freeandnil(wTheme); except messagedlg('Unable to remove the theme at this time.', mtinformation, [mbok], 0); end end; initialization gLoadedThemes := TList.create; finalization UnloadThemes; gLoadedThemes.free; end.