Rewording code for better structure - pascal

program GameMain;
uses SwinGame, sgTypes;
function buttonClicked(p1, Next_PARAM_thingie: Single; W, lastOne: Integer): Boolean;
var blah, blee: Single; _r_, BTMOB: Single;
begin blah := MouseX(); blee := MouseY(); _r_ := p1 + W; BTMOB := Next_PARAM_thingie + lastOne; result := false;
if MouseClicked( LeftButton ) then
begin
if (blah >= p1) and (blah <= _r_) then
begin result := true;
end;
end;
end;
procedure Main();
var
clr: Color;
begin
OpenGraphicsWindow('Test Program for Button Click Code', 800, 600);
ShowSwinGameSplashScreen();
clr := ColorWhite;
repeat
clearScreen(clr);
drawframerate(0,0);
fillRectangle(ColorGrey, 50, 50, 100, 30);
drawtext('Click Me', ColorBlack, 'arial.ttf', 14, 55, 55);
RefreshScreen();
Processevents();
if buttonClicked(50, 50, 100, 30) then
begin
clr := RandomRGBcolor(255);
end;
until WindowCloseRequested();
end;
begin
main();
end.
I have been trying to figure out what does what but it isn't going to well. I could use some help trying to figure out what each of these random words do so I can change the name so the code is more understanding

The first thing that I would do is work through removing things that are unneeded. In the code sample given, BTMOB is entirely unused, so I would remove it and the code that sets its value. With BTMOB removed, the lastOne parameter is no longer needed, so it goes away.
Keep chipping away things that don't belong at all and using whatever context clues are available to give things that are used more meaningful names. There will be some things that you may not be able to guess just by analyzing the code and potentially not even through runtime debugging, but you should be able to make it far more readable. Here's an example of how buttonClicked might look after the first pass (you'd also have to change the code that calls it to no longer pass the unused parameters that were removed).
function buttonClicked(p1: Single; W: Integer): Boolean;
var posX: Single; _r_: Single;
begin posX := MouseX(); _r_ := p1 + W; result := false;
if MouseClicked( LeftButton ) then
begin
if (posX >= p1) and (posX <= _r_) then
begin result := true;
end;
end;
end;

Related

If statement inside repeat until loop

I'm creating a toggle button using the SwinGame library. Right now I'm struggling with actually making it toggle. That bit looks like this:
var
clr: Color;
clicked: Boolean;
boolcheck: String;
begin
OpenGraphicsWindow('Toggle button test', windowsWidth, windowsHeight);
clr := ColorWhite;
clicked := true;
boolcheck := 'true';
repeat
ClearScreen(clr);
ProcessEvents();
//Play button and Pause button
if (ButtonClicked(buttonX-buttonRadius, buttonY-buttonRadius, buttonRadius*2, buttonRadius*2) = true) and (clicked = true) then
begin
clr := ColorRed;
clicked := false;
boolcheck := 'false';
DrawAButton();
end
else if (ButtonClicked(buttonX-buttonRadius, buttonY-buttonRadius, buttonRadius*2, buttonRadius*2) = true) and (clicked = false) then
begin
clr := ColorBlue;
clicked := true;
boolcheck := 'true';
DrawADifferentButton();
end;
DrawText(echo, ColorBlack, 'arial.ttf', 14, 55, 55);
RefreshScreen();
until WindowCloseRequested();
end;
Basically I intended to make it so if the user clicks on this area of the window via ButtonClicked() (a SwinGame function), and the clicked variable is false, then the background color will be red, if not then blue. But for some reason I could only change it to red, blue did not appear at all. I did some troubleshooting by creating a boolcheck variable and I saw the variable was constantly being put at true, I did see it change to false for a fraction of a second then back to true....But I did not put the clicked variable initial definition inside the loop, so why isn't it staying false?
EDIT: Here's the definition to the ButtonClicked function
function ButtonClicked(posX, posY: Single; w, h: Integer): Boolean;
var
x, y: Single;
begin
x := MouseX();
y := MouseY();
result := false;
if MouseClicked(LeftButton) then
begin
if (x >= posX) and (x <= w + posX) and (y >= posY) and (y <= h + posY) then
begin
result := true;
end;
end;
end;
Ok, thanks to #lurker 's suggestion, I've solved it. After spending some time thinking about #lurker 's suggestion, I realized that once the procedure gets reset, it'll start off with clicked being at 0 again. So what I had to do, was making the the ButtonClicked check a function that returns 1 or 0, or true or false into clicked in Main(). That way clicked will always be updated, and the procedure won't be reset with clicked being at 0 all the time.
function Toggle(clicked): Integer;
if ButtonClicked(buttonX-buttonRadius, buttonY-buttonRadius, buttonRadius*2, buttonRadius*2) then
if (clicked := true) then
begin
clr := ColorRed;
result := false;
DrawAButton();
end
else
begin
clr := ColorBlue;
result := true;
DrawADifferentButton();
end;
then in `Main()` I would call it as follow:
//Stuffs
begin
clicked := true;
repeat
clicked := Toggle(clicked);
//Other stuffs

How to avoid flickering when animating GUI components in Lazarus

I'm moving a TMemo object left and right in my GUI application. The problem is, is that the letters in my TMemo are flickering as soon as the movement starts.
I've looked this up, and, apparently, setting the DoubleBuffering property of my main form should've helped me, but it didn't. So I tried setting that property to true on all objects that were moving, but flickering was still present.
Are there any ways to achieve flicker-free animations of GUI components in Lazarus? I'm a novice in Lazarus, so I'm kind of blindly googling for solutions right now. I would really appreciate some help.
To provide further context, here's how I animate my TMemo: I've got a TTimer with an interval value of 10, and its OnTimer event moves my TMemo left and right contiguously. To make the movement slightly smoother, I added a simple cosine interpolation function.
In the end here's the code:
procedure TServerSideForm.ControlPanelHideTimerTimer(Sender: TObject);
begin
if (hideAnimVal < 1) then
begin
hideAnimVal := hideAnimVal + 0.025;
end
else
begin
MemoHideTimer.Enabled:=false;
end;
// hideStart - starting position of my TMemo, hideEnd - end position of my TMemo
hideCurr := Round(CosineInterpolation(hideStart, hideEnd, hideAnimVal));
Memo.Left:=hideCurr;
end;
Cosine interpolation:
function CosineInterpolation(Val1, Val2, Angle: Double): Double;
var
Percent: Double;
begin
Percent := (1-Cos(Angle*PI))/2;
Result := (Val1 * (1 - Percent) + Val2 * Percent);
end;
I would try to move an image instead:
var
Memo1dc: hdc;
Cnv: TCanvas;
Rct: TRect;
implementation
procedure TForm1.MemoHideTimerTimer(Sender: TObject);
begin
if Memo1.Visible then
begin
Memo1dc := GetDC(Memo1.Handle);
Cnv.Handle := Memo1dc;
Rct.Height := Memo1.Height;
Rct.Width := Memo1.Width;
Image1.Left := Memo1.Left;
Image1.Top := Memo1.Top;
Image1.Width := Memo1.Width;
Image1.Height := Memo1.Height;
Image1.Canvas.CopyRect(Rct, Cnv, Rct);
Memo1.Visible := False;
Image1.Visible := True;
end;
if (hideAnimVal < 1) then
begin
hideAnimVal := hideAnimVal + 0.025;
end
else
begin
MemoHideTimer.Enabled := False;
end;
// hideStart - starting position of my TMemo, hideEnd - end position of my TMemo
hideCurr := Round(CosineInterpolation(hideStart, hideEnd, hideAnimVal));
Image1.Left := hideCurr;
if MemoHideTimer.Enabled = False then
begin
Memo1.Left := Image1.Left;
Memo1.Visible := True;
Image1.Visible := False;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Cnv := TCanvas.Create;
end;

Delphi: Hiding/showing TWinControl objects in a form is pretty slow. How to get it faster?

I have simple VCL form application in Delphi XE5. In the main form there are hudreds of TEdit components. Now I realized that setting visibility of all these edits is pretty slow. It takes ca 1 second on my computer while they are hidden/shown.
Please note that this is sample intended only for demostrate the issue. I know that this can be solved by inserting edits to a panel and hiding/showing the panel. But this is not possible in our application where edits are inserted to a form by an end user. Also we don't know which edits visibility will be controlled.
How to get it faster?
Note that when I use TLabel (TGraphicControl) instead of TEdit (TWinControl) then it is fast!
procedure TForm1.CheckBox1Click(Sender: TObject);
var
C: TControl;
i: Integer;
begin
for i := 0 to ControlCount - 1 do
begin
C := Controls[i];
if C.ClassName <> 'TCheckBox' then
C.Visible := CheckBox1.Checked;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
C: TEdit;
i: Integer;
j: Integer;
begin
for i := 0 to 60 do
for j := 0 to 20 do
begin
C := TEdit.Create(Self);
C.Width := 40;
C.Left := 20 + 50 * j;
C.Top := 50 + 25 * i;
C.Parent := Self;
end;
end;
Your controls are parented directly by the form. Instead create a panel with alClient align and set the panel's Parent to be the form.
When you create the edit controls, make their Parent be the panel. When you wish to hide the edit controls, hide the panel.
If you don't want to, or cannot, make such a drastic change, then you can batch the changes with BeginDeferWindowPos, DeferWindowPos and EndDeferWindowPos. You might have code along these lines:
const
Flags = SWP_NOZORDER or SWP_NOOWNERZORDER or SWP_NOACTIVATE or SWP_NOSIZE or
SWP_NOMOVE or SWP_HIDEWINDOW;
var
i: Integer;
wpi: HDWP;
wnd: HWND;
begin
wpi := BeginDeferWindowPos(10);
Win32Check(wpi <> 0);
Try
for i := 1 to 10 do begin
wnd := (FindComponent('Edit' + IntToStr(i)) as TWinControl).Handle;
Win32Check(DeferWindowPos(wpi, wnd, 0, 0, 0, 0, 0, Flags) <> 0);
end;
Finally
Win32Check(EndDeferWindowPos(wpi));
End;
end;
Clearly you'll use a different mechanism to obtain your window handles, but I don't feel that detracts from this example.

Why does the image collision causes flashings?

Ok so first of all i'm just messing around in delphi, and still really new to it, but i noticed that whenever i try to make some kind of game , where W,A,S, and D are the buttons which moves an object (TImage) , it starts flashing randomly, i noticed that it happens if the speed is fast, or when it's moving and there is another image (background) behind it...
Most of my "moving" code looks like this:
if key = 's' then begin
for I := 1 to 5 do
sleep(1);
x:=x-2;
Image1.Top := x;
end;
Maybe that causes it, but still it's really annoying. I would be really pleased if you could help with this.
Something like this is better handled using TPaintBox instead.
Have the keystrokes set variables as needed and then call TPaintBox.Invalidate() to trigger a repaint when the OS is ready for it.
The TPaintBox.OnPaint event handler can then draw a TGraphic at the appropriate coordinates specified by the current variable values as needed.
var
X: Integer = 0;
Y: Integer = 0;
procedure TMyForm.KeyPress(Sender: TObject; var Key: Char);
begin
case Key of
'W': begin
Dec(Y, 2);
PaintBox.Invalidate;
end;
'A': begin
Dec(X, 2);
PaintBox.Invalidate;
end;
'S': begin
Inc(Y, 2);
PaintBox.Invalidate;
end;
'D': begin
Inc(X, 2);
PaintBox.Invalidate;
end;
end;
end;
procedure TMyForm.PaintBoxPaint(Sender: TObject);
begin
PaintBox.Canvas.Draw(X, Y, SomeGraphic);
end;

Make Disabled Menu and Toolbar Images look better?

Please see the attached screenshot which illustrates a TToolBar from one of my programs:
Notice the last two images of the Toolbar, they are disabled. The way they have been drawn to appear disabled is not very appealing, in fact in the Delphi IDE some of the images look the same.
The issue I have with it is I want my application to look a lot cleaner. The way the disabled items are drawn doesn't look very good. The TToolBar allows to set a disabled TImageList, I tried making my images black & white but they didn't look right, and would rather not have to always make the images black and white (time and effort). This problem also shows in my menus and popup menus, which don't allow for disabled images anyway.
Is there a way to paint the disabled items to look better on the eye?
If possible I would rather not look to use 3rd Party Controls. I know the Jedi Components allow disabled images for the menu etc, but would prefer a way to not resort too 3rd Party Components, when possible I would much prefer to use the standard issue VCL, especially as sometimes I use the TActionMainMenuBar to draw Office Style menus, which match the TToolBar when DrawingStyle is set to gradient.
EDIT
I have accepted RRUZ's answer, is it possible though to accept David's answer as well, both are very good answers and would like the answer to be shared between them if possible.
Thanks.
Sometime Ago i wrote a patch to fix this behavior. the key is patch the code of the TCustomImageList.DoDraw function, the technique used is similar to the used by the delphi-nice-toolbar app, but instead of patch a bpl IDE in this case we patch the function in memory.
Just include this unit in your project
unit uCustomImageDrawHook;
interface
uses
Windows,
SysUtils,
Graphics,
ImgList,
CommCtrl,
Math;
implementation
type
TJumpOfs = Integer;
PPointer = ^Pointer;
PXRedirCode = ^TXRedirCode;
TXRedirCode = packed record
Jump: Byte;
Offset: TJumpOfs;
end;
PAbsoluteIndirectJmp = ^TAbsoluteIndirectJmp;
TAbsoluteIndirectJmp = packed record
OpCode: Word;
Addr: PPointer;
end;
TCustomImageListHack = class(TCustomImageList);
var
DoDrawBackup : TXRedirCode;
function GetActualAddr(Proc: Pointer): Pointer;
begin
if Proc <> nil then
begin
if (Win32Platform = VER_PLATFORM_WIN32_NT) and (PAbsoluteIndirectJmp(Proc).OpCode = $25FF) then
Result := PAbsoluteIndirectJmp(Proc).Addr^
else
Result := Proc;
end
else
Result := nil;
end;
procedure HookProc(Proc, Dest: Pointer; var BackupCode: TXRedirCode);
var
n: DWORD;
Code: TXRedirCode;
begin
Proc := GetActualAddr(Proc);
Assert(Proc <> nil);
if ReadProcessMemory(GetCurrentProcess, Proc, #BackupCode, SizeOf(BackupCode), n) then
begin
Code.Jump := $E9;
Code.Offset := PAnsiChar(Dest) - PAnsiChar(Proc) - SizeOf(Code);
WriteProcessMemory(GetCurrentProcess, Proc, #Code, SizeOf(Code), n);
end;
end;
procedure UnhookProc(Proc: Pointer; var BackupCode: TXRedirCode);
var
n: Cardinal;
begin
if (BackupCode.Jump <> 0) and (Proc <> nil) then
begin
Proc := GetActualAddr(Proc);
Assert(Proc <> nil);
WriteProcessMemory(GetCurrentProcess, Proc, #BackupCode, SizeOf(BackupCode), n);
BackupCode.Jump := 0;
end;
end;
procedure Bitmap2GrayScale(const BitMap: TBitmap);
type
TRGBArray = array[0..32767] of TRGBTriple;
PRGBArray = ^TRGBArray;
var
x, y, Gray: Integer;
Row : PRGBArray;
begin
BitMap.PixelFormat := pf24Bit;
for y := 0 to BitMap.Height - 1 do
begin
Row := BitMap.ScanLine[y];
for x := 0 to BitMap.Width - 1 do
begin
Gray := (Row[x].rgbtRed + Row[x].rgbtGreen + Row[x].rgbtBlue) div 3;
Row[x].rgbtRed := Gray;
Row[x].rgbtGreen := Gray;
Row[x].rgbtBlue := Gray;
end;
end;
end;
//from ImgList.GetRGBColor
function GetRGBColor(Value: TColor): DWORD;
begin
Result := ColorToRGB(Value);
case Result of
clNone:
Result := CLR_NONE;
clDefault:
Result := CLR_DEFAULT;
end;
end;
procedure New_Draw(Self: TObject; Index: Integer; Canvas: TCanvas; X, Y: Integer; Style: Cardinal; Enabled: Boolean);
var
MaskBitMap : TBitmap;
GrayBitMap : TBitmap;
begin
with TCustomImageListHack(Self) do
begin
if not HandleAllocated then Exit;
if Enabled then
ImageList_DrawEx(Handle, Index, Canvas.Handle, X, Y, 0, 0, GetRGBColor(BkColor), GetRGBColor(BlendColor), Style)
else
begin
GrayBitMap := TBitmap.Create;
MaskBitMap := TBitmap.Create;
try
GrayBitMap.SetSize(Width, Height);
MaskBitMap.SetSize(Width, Height);
GetImages(Index, GrayBitMap, MaskBitMap);
Bitmap2GrayScale(GrayBitMap);
BitBlt(Canvas.Handle, X, Y, Width, Height, MaskBitMap.Canvas.Handle, 0, 0, SRCERASE);
BitBlt(Canvas.Handle, X, Y, Width, Height, GrayBitMap.Canvas.Handle, 0, 0, SRCINVERT);
finally
GrayBitMap.Free;
MaskBitMap.Free;
end;
end;
end;
end;
procedure HookDraw;
begin
HookProc(#TCustomImageListHack.DoDraw, #New_Draw, DoDrawBackup);
end;
procedure UnHookDraw;
begin
UnhookProc(#TCustomImageListHack.DoDraw, DoDrawBackup);
end;
initialization
HookDraw;
finalization
UnHookDraw;
end.
and the result will be
I submitted a QC report for a related issue over a year ago, but that was for menus. I've never seen this for TToolbar since it is a wrapper to the common control and the drawing is handled by Windows.
However, the images you are seeing are clearly as result of the VCL calling TImageList.Draw and passing Enabled=False – nothing else looks that bad! Are you 100% sure this really is a TToolbar?
The fix will surely be to avoid TImageList.Draw and call ImageList_DrawIndirect with the ILS_SATURATE.
You may need to modify some VCL source. First find the location where the toolbar is being custom drawn and call this routine instead of the calls to TImageList.Draw.
procedure DrawDisabledImage(DC: HDC; ImageList: TCustomImageList; Index, X, Y: Integer);
var
Options: TImageListDrawParams;
begin
ZeroMemory(#Options, SizeOf(Options));
Options.cbSize := SizeOf(Options);
Options.himl := ImageList.Handle;
Options.i := Index;
Options.hdcDst := DC;
Options.x := X;
Options.y := Y;
Options.fState := ILS_SATURATE;
ImageList_DrawIndirect(#Options);
end;
An even better fix would be to work out why the toolbar is being custom drawn and find a way to let the system do it.
EDIT 1
I've looked at the Delphi source code and I'd guess that you are custom drawing the toolbar, perhaps because it has a gradient. I never even knew that TToolbar could handle custom drawing but I'm just a plain vanilla kind of guy!
Anyway, I can see code in TToolBar.GradientDrawButton calling the TImageList.Draw so I think the explanation above is on the right track.
I'm fairly sure that calling my DrawDisabledImage function above will give you better results. If could find a way to make that happen when you call TImageList.Draw then that would, I suppose, be the very best fix since it would apply wholesale.
EDIT 2
Combine the function above with #RRUZ's answer and you have an excellent solution.
Solution from #RRUZ dosn't work if you use LargeImages in ActionToolBar. I made changes to the #RRUZ code to work with LargeImages in ActionToolBar.
unit unCustomImageDrawHook;
interface
uses
Windows,
SysUtils,
Graphics,
ImgList,
CommCtrl,
Math,
Vcl.ActnMan,
System.Classes;
implementation
type
TJumpOfs = Integer;
PPointer = ^Pointer;
PXRedirCode = ^TXRedirCode;
TXRedirCode = packed record
Jump: Byte;
Offset: TJumpOfs;
end;
PAbsoluteIndirectJmp = ^TAbsoluteIndirectJmp;
TAbsoluteIndirectJmp = packed record
OpCode: Word;
Addr: PPointer;
end;
TCustomImageListHack = class(TCustomImageList);
TCustomActionControlHook = class(TCustomActionControl);
var
DoDrawBackup : TXRedirCode;
DoDrawBackup2 : TXRedirCode;
function GetActualAddr(Proc: Pointer): Pointer;
begin
if Proc <> nil then
begin
if (Win32Platform = VER_PLATFORM_WIN32_NT) and (PAbsoluteIndirectJmp(Proc).OpCode = $25FF) then
Result := PAbsoluteIndirectJmp(Proc).Addr^
else
Result := Proc;
end
else
Result := nil;
end;
procedure HookProc(Proc, Dest: Pointer; var BackupCode: TXRedirCode);
var
n: SIZE_T;
Code: TXRedirCode;
begin
Proc := GetActualAddr(Proc);
Assert(Proc <> nil);
if ReadProcessMemory(GetCurrentProcess, Proc, #BackupCode, SizeOf(BackupCode), n) then
begin
Code.Jump := $E9;
Code.Offset := PAnsiChar(Dest) - PAnsiChar(Proc) - SizeOf(Code);
WriteProcessMemory(GetCurrentProcess, Proc, #Code, SizeOf(Code), n);
end;
end;
procedure UnhookProc(Proc: Pointer; var BackupCode: TXRedirCode);
var
n: SIZE_T;
begin
if (BackupCode.Jump <> 0) and (Proc <> nil) then
begin
Proc := GetActualAddr(Proc);
Assert(Proc <> nil);
WriteProcessMemory(GetCurrentProcess, Proc, #BackupCode, SizeOf(BackupCode), n);
BackupCode.Jump := 0;
end;
end;
procedure Bitmap2GrayScale(const BitMap: TBitmap);
type
TRGBArray = array[0..32767] of TRGBTriple;
PRGBArray = ^TRGBArray;
var
x, y, Gray: Integer;
Row : PRGBArray;
begin
BitMap.PixelFormat := pf24Bit;
for y := 0 to BitMap.Height - 1 do
begin
Row := BitMap.ScanLine[y];
for x := 0 to BitMap.Width - 1 do
begin
Gray := (Row[x].rgbtRed + Row[x].rgbtGreen + Row[x].rgbtBlue) div 3;
Row[x].rgbtRed := Gray;
Row[x].rgbtGreen := Gray;
Row[x].rgbtBlue := Gray;
end;
end;
end;
//from ImgList.GetRGBColor
function GetRGBColor(Value: TColor): DWORD;
begin
Result := ColorToRGB(Value);
case Result of
clNone:
Result := CLR_NONE;
clDefault:
Result := CLR_DEFAULT;
end;
end;
procedure New_Draw(Self: TObject; Index: Integer; Canvas: TCanvas; X, Y: Integer; Style: Cardinal; Enabled: Boolean);
var
MaskBitMap : TBitmap;
GrayBitMap : TBitmap;
begin
with TCustomImageListHack(Self) do
begin
if not HandleAllocated then Exit;
if Enabled then
ImageList_DrawEx(Handle, Index, Canvas.Handle, X, Y, 0, 0, GetRGBColor(BkColor), GetRGBColor(BlendColor), Style)
else
begin
GrayBitMap := TBitmap.Create;
MaskBitMap := TBitmap.Create;
try
GrayBitMap.SetSize(Width, Height);
MaskBitMap.SetSize(Width, Height);
GetImages(Index, GrayBitMap, MaskBitMap);
Bitmap2GrayScale(GrayBitMap);
BitBlt(Canvas.Handle, X, Y, Width, Height, MaskBitMap.Canvas.Handle, 0, 0, SRCERASE);
BitBlt(Canvas.Handle, X, Y, Width, Height, GrayBitMap.Canvas.Handle, 0, 0, SRCINVERT);
finally
GrayBitMap.Free;
MaskBitMap.Free;
end;
end;
end;
end;
procedure New_Draw2(Self: TObject; const Location: TPoint);
var
ImageList: TCustomImageList;
DrawEnabled: Boolean;
LDisabled: Boolean;
begin
with TCustomActionControlHook(Self) do
begin
if not HasGlyph then Exit;
ImageList := FindImageList(True, LDisabled, ActionClient.ImageIndex);
if not Assigned(ImageList) then Exit;
DrawEnabled := LDisabled or Enabled and (ActionClient.ImageIndex <> -1) or
(csDesigning in ComponentState);
ImageList.Draw(Canvas, Location.X, Location.Y, ActionClient.ImageIndex,
dsTransparent, itImage, DrawEnabled);
end;
end;
procedure HookDraw;
begin
HookProc(#TCustomImageListHack.DoDraw, #New_Draw, DoDrawBackup);
HookProc(#TCustomActionControlHook.DrawLargeGlyph, #New_Draw2, DoDrawBackup2);
end;
procedure UnHookDraw;
begin
UnhookProc(#TCustomImageListHack.DoDraw, DoDrawBackup);
UnhookProc(#TCustomActionControlHook.DrawLargeGlyph, DoDrawBackup2);
end;
initialization
HookDraw;
finalization
UnHookDraw;
end.
Take a look at this Delphi IDE fix. Maybe you can mimic it's implementation.
Use TActionToolbar , TActionmanager , Timagelist
Set action managers image list to a Timagelist. and set Disabledimages to another imagelist

Resources