Is it possible to change .Font.Style
on Focus TLabel
or TNewStaticText
like it happens with cursor when we use .Cursor
?
There is no built-in support to track mouse hovering in Inno Setup at this time. However, by intercepting window procedure of the controls you can track this by yourself. For the following example you will need the InnoCallback
library:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
OutputDir=userdocs:Inno Setup Examples Output
[Files]
Source: "InnoCallback.dll"; DestDir: "{tmp}"; Flags: dontcopy
[Code]
#ifdef UNICODE
#define AW "W"
#else
#define AW "A"
#endif
const
GWL_WNDPROC = -4;
WM_MOUSEMOVE = $0200;
type
WPARAM = UINT_PTR;
LPARAM = LongInt;
LRESULT = LongInt;
TWindowProc = function(hwnd: HWND; uMsg: UINT; wParam: WPARAM;
lParam: LPARAM): LRESULT;
function SetCapture(hWnd: HWND): HWND;
external 'SetCapture@user32.dll stdcall';
function ReleaseCapture: BOOL;
external 'ReleaseCapture@user32.dll stdcall';
function GetMessagePos: DWORD;
external 'GetMessagePos@user32.dll stdcall';
function GetWindowRect(hWnd: HWND; out lpRect: TRect): BOOL;
external 'GetWindowRect@user32.dll stdcall';
function CallWindowProc(lpPrevWndFunc: LongInt; hWnd: HWND; Msg: UINT;
wParam: WPARAM; lParam: LPARAM): LRESULT;
external 'CallWindowProc{#AW}@user32.dll stdcall';
function SetWindowLong(hWnd: HWND; nIndex: Integer;
dwNewLong: LongInt): LongInt;
external 'SetWindowLong{#AW}@user32.dll stdcall';
function WrapWindowProc(Callback: TWindowProc; ParamCount: Integer): LongWord;
external 'wrapcallback@files:InnoCallback.dll stdcall';
type
TControlRec = record
Hovered: Boolean; // hovering state
WndProc: LongInt; // original window proc
Control: TWinControl; // control instance
end;
var
StaticText1: TNewStaticText;
StaticText2: TNewStaticText;
ControlList: array of TControlRec;
// helper function for finding control by handle
function GetControlRec(Handle: HWND): TControlRec;
var
I: Integer;
begin
for I := 0 to High(ControlList) do
if ControlList[I].Control.Handle = Handle then
begin
Result := ControlList[I];
Exit;
end;
end;
// function which attaches the intercepting window procedure to the control
// and creates and adds the control record to the control list
procedure AttachWndProc(Control: TWinControl; WindowProc: TWindowProc);
begin
SetArrayLength(ControlList, GetArrayLength(ControlList) + 1);
ControlList[High(ControlList)].Hovered := False;
ControlList[High(ControlList)].Control := Control;
ControlList[High(ControlList)].WndProc := SetWindowLong(Control.Handle,
GWL_WNDPROC, WrapWindowProc(WindowProc, 4));
end;
// function to restore windows procedures to all controls in the list
procedure RestoreWndProcs;
var
I: Integer;
begin
for I := 0 to High(ControlList) do
SetWindowLong(ControlList[I].Control.Handle, GWL_WNDPROC, ControlList[I].WndProc);
end;
// helper function to create a TPoint structure from the result of GetMessagePos
// function call
function MakePoint(Value: DWORD): TPoint;
begin
Result.X := Value and $FFFF;
Result.Y := Value shr 16;
end;
// helper function which substitutes PtInRect Windows API function which I wasn't
// able to import for some reason
function PointInRect(const Rect: TRect; const Point: TPoint): Boolean;
begin
Result := (Point.X >= Rect.Left) and (Point.X <= Rect.Right) and
(Point.Y >= Rect.Top) and (Point.Y <= Rect.Bottom);
end;
// interceptor window procedure
function StaticTextWndProc(hwnd: HWND; uMsg: UINT; wParam: WPARAM;
lParam: LPARAM): LRESULT;
var
P: TPoint;
R: TRect;
ControlRec: TControlRec;
begin
// get control record
ControlRec := GetControlRec(hwnd);
// if the cursor moves, then...
if uMsg = WM_MOUSEMOVE then
begin
// set mouse capture for this control to be notified by the WM_MOUSEMOVE even if
// we leave the control
SetCapture(ControlRec.Control.Handle);
// get the current cursor position and control rectangle (both screen relative)
P := MakePoint(GetMessagePos);
GetWindowRect(ControlRec.Control.Handle, R);
// check if the cursor is inside the control; if yes, then...
if PointInRect(R, P) then
begin
// if the hovering flag was not yet set, it means we just entered the control
// with the mouse, so let's change the style and remember the hovering state
if not ControlRec.Hovered then
begin
if ControlRec.Control is TNewStaticText then
TNewStaticText(ControlRec.Control).Font.Style := [fsBold];
ControlRec.Hovered := True;
end;
end
else
begin
// the cursor is not over the control, so let's release the mouse capture, set
// the style and remember the hovering state
ReleaseCapture;
if ControlRec.Control is TNewStaticText then
TNewStaticText(ControlRec.Control).Font.Style := [];
ControlRec.Hovered := False;
end;
end;
// call the original window procedure
Result := CallWindowProc(ControlRec.WndProc, hwnd, uMsg, wParam, lParam);
end;
procedure InitializeWizard;
begin
StaticText1 := TNewStaticText.Create(WizardForm);
StaticText1.Parent := WizardForm;
StaticText1.Left := 12;
StaticText1.Top := 336;
StaticText1.Caption := 'Hello';
StaticText2 := TNewStaticText.Create(WizardForm);
StaticText2.Parent := WizardForm;
StaticText2.Left := 43;
StaticText2.Top := 336;
StaticText2.Caption := 'world!';
AttachWndProc(StaticText1, @StaticTextWndProc);
AttachWndProc(StaticText2, @StaticTextWndProc);
end;
procedure DeinitializeSetup;
begin
RestoreWndProcs;
end;