Menu

[r375]: / trunk / Src / UTVCheckBoxes.pas  Maximize  Restore  History

Download this file

357 lines (319 with data), 11.4 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
{
* UTVCheckBoxes.pas
*
* Implements class that is used to manage image lists containing check box
* images for display in tree views.
*
* $Rev$
* $Date$
*
* ***** BEGIN LICENSE BLOCK *****
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The Original Code is UTVCheckBoxes.pas
*
* The Initial Developer of the Original Code is Peter Johnson
* (http://www.delphidabbler.com/).
*
* Portions created by the Initial Developer are Copyright (C) 2006-2009 Peter
* Johnson. All Rights Reserved.
*
* Contributor(s)
* NONE
*
* ***** END LICENSE BLOCK *****
}
unit UTVCheckBoxes;
interface
uses
// Delphi
Controls, Classes, StdCtrls, SyncObjs, Windows;
type
{
TTVCheckBoxes:
Class used to manage image lists containing check box images for display in
tree views and to map check box identifiers to indexes into image lists.
Class loads image list with different images depending on whether XP themes
are active. Update method can be called to change bitmaps in themes are
changed.
}
TTVCheckBoxes = class(TObject)
strict private
fLock: TSimpleEvent;
{Simple signalling event object used to prevent Update method being called
when themes change if it is already running}
fImgList: TImageList;
{Reference to image list used to store checkbox images}
fOnChange: TNotifyEvent;
{Handler for OnChange event}
function CheckboxSize: TSize;
{Gets size of check box. Size may differ depending on whether XP themes
are active or not.
@return Size of check box in pixels.
}
procedure SetImgListSize;
{Sets size of bitmaps expected by image list. Size depends on dimensions
of check boxes used.
}
procedure Update;
{Updates check boxes in image list. Check boxes used depend on whether XP
themes are active.
}
procedure ThemeChangeListener(Sender: TObject);
{Handles theme services change event. Updates check boxes according to
whether themes are in use or not.
@param Sender [in] Not used.
}
public
constructor Create(const ImgList: TImageList);
{Class constructor. Sets up object and loads check box images into image
list.
@param ImgList [in] Image list to receive check box images.
}
destructor Destroy; override;
{Class destructor. Tears down object.
}
class function CheckImageIdx(const CheckState: TCheckBoxState;
const Hot: Boolean): Integer;
{Gets image list index of a check box.
@param CheckState [in] State of check box.
@param Hot [in] Flag indicating whether check box is to be hot or
normal.
@return Required image index.
}
class function ImageIdxToCheckState(const ImgIdx: Integer): TCheckBoxState;
{Finds state of checkbox referenced by an image list index.
@param ImgIdx [in] Image index to be checked.
@return Associated check box state.
}
property OnChange: TNotifyEvent
read fOnChange write fOnChange;
{Event triggered when check boxes change, i.e. when themes change}
end;
implementation
uses
// Delphi
SysUtils, Graphics, ImgList, Themes,
// Project
UStructs, UThemesEx;
const
// Map of index of check boxes in image list to XP theme element representing
// check box in normal and hot style
cXPCheckBoxes: array[TCheckBoxState, Boolean] of TThemedButton =
(
(tbCheckBoxUncheckedNormal, tbCheckBoxUncheckedHot),
(tbCheckBoxCheckedNormal, tbCheckBoxCheckedHot),
(tbCheckBoxMixedNormal, tbCheckBoxMixedHot)
);
// Name of resource storing checkbox bitmap used when XP themes not active
cCheckBoxResName = 'TVCHECKBOXES';
// Timeout used when waiting for an event to signal
cLockTimeout = 10000; // 10 secs
{ TTVCheckBoxes }
function TTVCheckBoxes.CheckboxSize: TSize;
{Gets size of check box. Size may differ depending on whether XP themes are
active or not.
@return Size of check box in pixels.
}
// ---------------------------------------------------------------------------
function ThemedCheckBoxSize: TSize;
{Calculates size of a XP themed check box used when themes active.
@return Size of check box.
}
begin
// We get size from theme manager (assume all check boxes same size)
Result := ThemeServicesEx.GetElementSize(tbCheckBoxUncheckedNormal);
end;
function NonThemedCheckBoxSize: TSize;
{Calculates size of check box used when XP themes not active.
@return Size of check box.
}
const
// Dimension of checkbox bitmap resource, i.e. number of checkboxes across
// and down bitmap
cBmpResDim: TSize = (
cx: 6;
cy: 1
);
var
ChkBmp: TBitmap; // Bitmap used to load checkbox resource
begin
// When themes not active we get check boxes from resources.
// We get size of each bitmap by loading bitmap from resources and checking
// size of resulting bitmap. We divide each dimension in pixels by number of
// checkboxes in that dimension
ChkBmp := TBitmap.Create;
try
ChkBmp.LoadFromResourceName(HInstance, cCheckBoxResName);
Result.cx := ChkBmp.Width div cBmpResDim.cx;
Result.cy := ChkBmp.Height div cBmpResDim.cy;
finally
FreeAndNil(ChkBmp);
end;
end;
// ---------------------------------------------------------------------------
begin
inherited;
if ThemeServicesEx.ThemesEnabled then
Result := ThemedCheckBoxSize
else
Result := NonThemedCheckBoxSize;
end;
class function TTVCheckBoxes.CheckImageIdx(const CheckState: TCheckBoxState;
const Hot: Boolean): Integer;
{Gets image list index of a check box.
@param CheckState [in] State of check box.
@param Hot [in] Flag indicating whether check box is to be hot or normal.
@return Required image index.
}
begin
Result := Ord(CheckState);
if Hot then
Result := Result + Ord(High(TCheckBoxState)) - Ord(Low(TCheckBoxState)) + 1;
end;
constructor TTVCheckBoxes.Create(const ImgList: TImageList);
{Class constructor. Sets up object and loads check box images into image list.
@param ImgList [in] Image list to receive check box images.
}
begin
Assert(Assigned(ImgList), // ** do not localise
'TTVCheckBoxes.Create: ImgList is nil');
inherited Create;
fImgList := ImgList;
fLock := TSimpleEvent.Create; // lock for protected sections: needed by Update
fLock.SetEvent;
Update; // loads check boxes into image list
ThemeServicesEx.AddChangeEventHandler(ThemeChangeListener);
end;
destructor TTVCheckBoxes.Destroy;
{Class destructor. Tears down object.
}
begin
ThemeServicesEx.RemoveChangeEventHandler(ThemeChangeListener);
FreeAndNil(fLock);
inherited;
end;
class function TTVCheckBoxes.ImageIdxToCheckState(
const ImgIdx: Integer): TCheckBoxState;
{Finds state of checkbox referenced by an image list index.
@param ImgIdx [in] Image index to be checked.
@return Associated check box state.
}
var
TVCheck: TCheckBoxState; // loops thru all check box states
begin
Result := cbUnchecked; // keep compiler happy
// Loop thru all check boxes looking for image index in hot or normal state
for TVCheck := Low(TCheckBoxState) to High(TCheckBoxState) do
begin
if (CheckImageIdx(TVCheck, False) = ImgIdx) or
(CheckImageIdx(TVCheck, True) = ImgIdx) then
begin
Result := TVCheck;
Break;
end;
end;
end;
procedure TTVCheckBoxes.SetImgListSize;
{Sets size of bitmaps expected by image list. Size depends on dimensions of
check boxes used.
}
var
Size: TSize; // required size
begin
Size := CheckboxSize;
fImgList.Width := Size.cx;
fImgList.Height := Size.cy;
end;
procedure TTVCheckBoxes.ThemeChangeListener(Sender: TObject);
{Handles theme services change event. Updates check boxes according to whether
themes are in use or not.
@param Sender [in] Not used.
}
begin
Update;
end;
procedure TTVCheckBoxes.Update;
{Updates check boxes in image list. Check boxes used depend on whether XP
themes are active.
}
const
cMaskColour: TColor = clFuchsia; // image list mask colour
// ---------------------------------------------------------------------------
procedure LoadThemedCheckBoxes;
{Loads image list with check boxes used when XP themes are active.
}
var
CheckBmp: TBitmap; // bitmap on which check boxes are drawn
CheckRect: TRect; // bounds rectangle in bitmap to receive checkbox
TVCheck: TCheckBoxState; // loops thru all check box states
Hot: Boolean; // loops thru not-hot / hot
begin
// We use theme manager to draw check boxes on a bitmap which is then added
// to image list.
CheckBmp := TBitmap.Create;
try
// Prepare bitmap
CheckBmp.Width := fImgList.Width;
CheckBmp.Height := fImgList.Height;
CheckBmp.Canvas.Brush.Color := cMaskColour;
CheckRect := TRectEx.Create(0, 0, CheckBmp.Width, CheckBmp.Height);
// Draw normal then hot bitmaps
for Hot := Low(Boolean) to High(Boolean) do
begin
// Draw each check box state in normal and hot states
for TVCheck := Low(TCheckBoxState) to High(TCheckBoxState) do
begin
// Draw each checkbox to bitmap and add to image list
CheckBmp.Canvas.FillRect(CheckRect);
ThemeServicesEx.DrawElement(
cXPCheckBoxes[TVCheck, Hot], CheckBmp, CheckRect
);
fImgList.AddMasked(CheckBmp, cMaskColour);
end;
end;
finally
FreeAndNil(CheckBmp);
end;
end;
procedure LoadNonThemedCheckBoxes;
{Loads image list with check boxes used when XP themes not active.
}
begin
// We load required checkbox bitmaps from resources
fImgList.ResourceLoad(rtBitmap, cCheckBoxResName, cMaskColour);
end;
// ---------------------------------------------------------------------------
begin
// Wair for any lock to be opened
fLock.WaitFor(cLockTimeout);
// Close lock: this is used to prevent image list from being modified
// asynchronously
fLock.ResetEvent;
try
// Initialise image list
fImgList.Clear;
SetImgListSize;
// Load check boxes into image list
if ThemeServicesEx.ThemesEnabled then
LoadThemedCheckBoxes
else
LoadNonThemedCheckBoxes;
finally
// Open lock: this permits modification of image list
fLock.SetEvent;
end;
// Trigger event notifying that check boxes have changed
if Assigned(fOnChange) then
fOnChange(Self);
end;
end.
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.