NewCheckListBox.pas 73 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182
  1. unit NewCheckListBox;
  2. { TNewCheckListBox by Martijn Laan for Inno Setup
  3. Based on TPBCheckListBox by Patrick Brisacier and TCheckListBox by Borland
  4. Group item support, child item support, exclusive item support,
  5. ShowLines support and 'WantTabs mode' by Alex Yackimoff.
  6. Note: TNewCheckListBox uses Items.Objects to store the item state. Don't use
  7. Item.Objects yourself, use ItemObject instead.
  8. }
  9. interface
  10. uses
  11. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  12. StdCtrls, NewUxTheme;
  13. const
  14. WM_UPDATEUISTATE = $0128;
  15. type
  16. TItemType = (itGroup, itCheck, itRadio);
  17. TCheckBoxState2 = (cb2Normal, cb2Hot, cb2Pressed, cb2Disabled);
  18. TItemState = class (TObject)
  19. public
  20. Enabled: Boolean;
  21. HasInternalChildren: Boolean;
  22. CheckWhenParentChecked: Boolean;
  23. IsLastChild: Boolean;
  24. ItemType: TItemType;
  25. Level: Byte;
  26. Obj: TObject;
  27. State: TCheckBoxState;
  28. SubItem: string;
  29. ThreadCache: set of Byte;
  30. MeasuredHeight: Integer;
  31. ItemFontStyle: TFontStyles;
  32. SubItemFontStyle: TFontStyles;
  33. end;
  34. TCheckItemOperation = (coUncheck, coCheck, coCheckWithChildren);
  35. TEnumChildrenProc = procedure(Index: Integer; HasChildren: Boolean; Ext: Longint) of object;
  36. TNewCheckListBox = class (TCustomListBox)
  37. private
  38. FAccObjectInstance: TObject;
  39. FCaptureIndex: Integer;
  40. FSpaceDown: Boolean;
  41. FCheckHeight: Integer;
  42. FCheckWidth: Integer;
  43. FFormFocusChanged: Boolean;
  44. FFlat: Boolean;
  45. FLastMouseMoveIndex: Integer;
  46. FMinItemHeight: Integer;
  47. FOffset: Integer;
  48. FOnClickCheck: TNotifyEvent;
  49. FRequireRadioSelection: Boolean;
  50. FShowLines: Boolean;
  51. FStateList: TList;
  52. FWantTabs: Boolean;
  53. FThemeData: HTHEME;
  54. FThreadsUpToDate: Boolean;
  55. FHotIndex: Integer;
  56. FDisableItemStateDeletion: Integer;
  57. FWheelAccum: Integer;
  58. FUseRightToLeft: Boolean;
  59. procedure UpdateThemeData(const Close, Open: Boolean);
  60. function CanFocusItem(Item: Integer): Boolean;
  61. function CheckPotentialRadioParents(Index, ALevel: Integer): Boolean;
  62. procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR;
  63. procedure CMEnter(var Message: TCMEnter); message CM_ENTER;
  64. procedure CMExit(var Message: TCMExit); message CM_EXIT;
  65. procedure CMFocusChanged(var Message: TCMFocusChanged); message CM_FOCUSCHANGED;
  66. procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  67. procedure CMWantSpecialKey(var Message: TMessage); message CM_WANTSPECIALKEY;
  68. procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM;
  69. procedure EndCapture(Cancel: Boolean);
  70. function AddItem2(AType: TItemType; const ACaption, ASubItem: string;
  71. ALevel: Byte; AChecked, AEnabled, AHasInternalChildren,
  72. ACheckWhenParentChecked: Boolean; AObject: TObject): Integer;
  73. function FindAccel(VK: Word): Integer;
  74. function FindCheckedSibling(const AIndex: Integer): Integer;
  75. function FindNextItem(StartFrom: Integer; GoForward,
  76. SkipUncheckedRadios: Boolean): Integer;
  77. function GetItemState(Index: Integer): TItemState;
  78. procedure InvalidateCheck(Index: Integer);
  79. function RemeasureItem(Index: Integer): Integer;
  80. procedure Toggle(Index: Integer);
  81. procedure UpdateScrollRange;
  82. procedure LBDeleteString(var Message: TMessage); message LB_DELETESTRING;
  83. procedure LBResetContent(var Message: TMessage); message LB_RESETCONTENT;
  84. procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
  85. procedure WMGetObject(var Message: TMessage); message WM_GETOBJECT;
  86. procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
  87. procedure WMMouseMove(var Message: TWMMouseMove); message WM_MOUSEMOVE;
  88. procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;
  89. procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
  90. procedure WMSize(var Message: TWMSize); message WM_SIZE;
  91. procedure WMThemeChanged(var Message: TMessage); message WM_THEMECHANGED;
  92. procedure WMUpdateUIState(var Message: TMessage); message WM_UPDATEUISTATE;
  93. protected
  94. procedure CreateParams(var Params: TCreateParams); override;
  95. procedure CreateWnd; override;
  96. procedure MeasureItem(Index: Integer; var Height: Integer); override;
  97. procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState);
  98. override;
  99. function GetCaption(Index: Integer): String;
  100. function GetChecked(Index: Integer): Boolean;
  101. function GetItemEnabled(Index: Integer): Boolean;
  102. function GetItemFontStyle(Index: Integer): TFontStyles;
  103. function GetLevel(Index: Integer): Byte;
  104. function GetObject(Index: Integer): TObject;
  105. function GetState(Index: Integer): TCheckBoxState;
  106. function GetSubItem(Index: Integer): string;
  107. function GetSubItemFontStyle(Index: Integer): TFontStyles;
  108. procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  109. procedure KeyUp(var Key: Word; Shift: TShiftState); override;
  110. procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  111. override;
  112. procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  113. procedure UpdateHotIndex(NewHotIndex: Integer);
  114. procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
  115. procedure SetCaption(Index: Integer; const Value: String);
  116. procedure SetChecked(Index: Integer; const AChecked: Boolean);
  117. procedure SetFlat(Value: Boolean);
  118. procedure SetItemEnabled(Index: Integer; const AEnabled: Boolean);
  119. procedure SetItemFontStyle(Index: Integer; const AItemFontStyle: TFontStyles);
  120. procedure SetObject(Index: Integer; const AObject: TObject);
  121. procedure SetOffset(AnOffset: Integer);
  122. procedure SetShowLines(Value: Boolean);
  123. procedure SetSubItem(Index: Integer; const ASubItem: String);
  124. procedure SetSubItemFontStyle(Index: Integer; const ASubItemFontStyle: TFontStyles);
  125. property ItemStates[Index: Integer]: TItemState read GetItemState;
  126. public
  127. constructor Create(AOwner: TComponent); override;
  128. procedure CreateWindowHandle(const Params: TCreateParams); override;
  129. destructor Destroy; override;
  130. function AddCheckBox(const ACaption, ASubItem: string; ALevel: Byte;
  131. AChecked, AEnabled, AHasInternalChildren, ACheckWhenParentChecked: Boolean;
  132. AObject: TObject): Integer;
  133. function AddGroup(const ACaption, ASubItem: string; ALevel: Byte;
  134. AObject: TObject): Integer;
  135. function AddRadioButton(const ACaption, ASubItem: string;
  136. ALevel: Byte; AChecked, AEnabled: Boolean; AObject: TObject): Integer;
  137. function CheckItem(const Index: Integer; const AOperation: TCheckItemOperation): Boolean;
  138. procedure EnumChildrenOf(Item: Integer; Proc: TEnumChildrenProc; Ext: Longint);
  139. function GetParentOf(Item: Integer): Integer;
  140. procedure UpdateThreads;
  141. property Checked[Index: Integer]: Boolean read GetChecked write SetChecked;
  142. property ItemCaption[Index: Integer]: String read GetCaption write SetCaption;
  143. property ItemEnabled[Index: Integer]: Boolean read GetItemEnabled write SetItemEnabled;
  144. property ItemFontStyle[Index: Integer]: TFontStyles read GetItemFontStyle write SetItemFontStyle;
  145. property ItemLevel[Index: Integer]: Byte read GetLevel;
  146. property ItemObject[Index: Integer]: TObject read GetObject write SetObject;
  147. property ItemSubItem[Index: Integer]: string read GetSubItem write SetSubItem;
  148. property State[Index: Integer]: TCheckBoxState read GetState;
  149. property SubItemFontStyle[Index: Integer]: TFontStyles read GetSubItemFontStyle write SetSubItemFontStyle;
  150. published
  151. property Align;
  152. property Anchors;
  153. property BorderStyle;
  154. property Color;
  155. property Ctl3D;
  156. property DragCursor;
  157. property DragMode;
  158. property Enabled;
  159. property Flat: Boolean read FFlat write SetFlat default False;
  160. property Font;
  161. property Items;
  162. property MinItemHeight: Integer read FMinItemHeight write FMinItemHeight default 16;
  163. property Offset: Integer read FOffset write SetOffset default 4;
  164. property OnClick;
  165. property OnClickCheck: TNotifyEvent read FOnClickCheck write FOnClickCheck;
  166. property OnDblClick;
  167. property OnDragDrop;
  168. property OnDragOver;
  169. property OnEndDrag;
  170. property OnEnter;
  171. property OnExit;
  172. property OnKeyDown;
  173. property OnKeyPress;
  174. property OnKeyUp;
  175. property OnMouseDown;
  176. property OnMouseMove;
  177. property OnMouseUp;
  178. property OnStartDrag;
  179. property ParentColor;
  180. property ParentCtl3D;
  181. property ParentFont;
  182. property ParentShowHint;
  183. property PopupMenu;
  184. property RequireRadioSelection: Boolean read FRequireRadioSelection write FRequireRadioSelection default False;
  185. property ShowHint;
  186. property ShowLines: Boolean read FShowLines write SetShowLines default True;
  187. property TabOrder;
  188. property Visible;
  189. property WantTabs: Boolean read FWantTabs write FWantTabs default False;
  190. end;
  191. procedure Register;
  192. implementation
  193. uses
  194. Themes, NewUxTheme.TmSchema, PathFunc, ActiveX, BidiUtils, UITypes, Types;
  195. const
  196. sRadioCantHaveDisabledChildren = 'Radio item cannot have disabled child items';
  197. OBM_CHECKBOXES = 32759;
  198. WM_CHANGEUISTATE = $0127;
  199. WM_QUERYUISTATE = $0129;
  200. UIS_SET = 1;
  201. UIS_CLEAR = 2;
  202. UIS_INITIALIZE = 3;
  203. UISF_HIDEFOCUS = $1;
  204. UISF_HIDEACCEL = $2;
  205. DT_HIDEPREFIX = $00100000;
  206. OBJID_CLIENT = $FFFFFFFC;
  207. CHILDID_SELF = 0;
  208. ROLE_SYSTEM_OUTLINE = $23;
  209. ROLE_SYSTEM_STATICTEXT = $29;
  210. ROLE_SYSTEM_CHECKBUTTON = $2c;
  211. ROLE_SYSTEM_RADIOBUTTON = $2d;
  212. STATE_SYSTEM_UNAVAILABLE = $1;
  213. STATE_SYSTEM_CHECKED = $10;
  214. STATE_SYSTEM_MIXED = $20;
  215. EVENT_OBJECT_STATECHANGE = $800A;
  216. IID_IUnknown: TGUID = (
  217. D1:$00000000; D2:$0000; D3:$0000; D4:($C0,$00,$00,$00,$00,$00,$00,$46));
  218. IID_IDispatch: TGUID = (
  219. D1:$00020400; D2:$0000; D3:$0000; D4:($C0,$00,$00,$00,$00,$00,$00,$46));
  220. IID_IAccessible: TGUID = (
  221. D1:$618736e0; D2:$3c3d; D3:$11cf; D4:($81,$0c,$00,$aa,$00,$38,$9b,$71));
  222. type
  223. TWinControlAccess = class (TWinControl);
  224. { Note: We have to use TVariantArg for Delphi 2 compat., because D2 passes
  225. Variant parameters by reference (wrong), unlike D3+ which pass
  226. Variant/OleVariant parameters by value }
  227. NewOleVariant = TVariantArg;
  228. NewWideString = Pointer;
  229. TIUnknown = class
  230. public
  231. function QueryInterface(const iid: TIID; var obj): HRESULT; virtual; stdcall; abstract;
  232. function AddRef: Longint; virtual; stdcall; abstract;
  233. function Release: Longint; virtual; stdcall; abstract;
  234. end;
  235. TIDispatch = class(TIUnknown)
  236. public
  237. function GetTypeInfoCount(var ctinfo: Integer): HRESULT; virtual; stdcall; abstract;
  238. function GetTypeInfo(itinfo: Integer; lcid: TLCID; var tinfo: ITypeInfo): HRESULT; virtual; stdcall; abstract;
  239. function GetIDsOfNames(const iid: TIID; rgszNames: POleStrList;
  240. cNames: Integer; lcid: TLCID; rgdispid: PDispIDList): HRESULT; virtual; stdcall; abstract;
  241. function Invoke(dispIDMember: TDispID; const iid: TIID; lcid: TLCID;
  242. flags: Word; var dispParams: TDispParams; varResult: PVariant;
  243. excepInfo: PExcepInfo; argErr: PInteger): HRESULT; virtual; stdcall; abstract;
  244. end;
  245. TIAccessible = class(TIDispatch)
  246. public
  247. function get_accParent(var ppdispParent: IDispatch): HRESULT; virtual; stdcall; abstract;
  248. function get_accChildCount(var pcountChildren: Integer): HRESULT; virtual; stdcall; abstract;
  249. function get_accChild(varChild: NewOleVariant; var ppdispChild: IDispatch): HRESULT; virtual; stdcall; abstract;
  250. function get_accName(varChild: NewOleVariant; var pszName: NewWideString): HRESULT; virtual; stdcall; abstract;
  251. function get_accValue(varChild: NewOleVariant; var pszValue: NewWideString): HRESULT; virtual; stdcall; abstract;
  252. function get_accDescription(varChild: NewOleVariant; var pszDescription: NewWideString): HRESULT; virtual; stdcall; abstract;
  253. function get_accRole(varChild: NewOleVariant; var pvarRole: NewOleVariant): HRESULT; virtual; stdcall; abstract;
  254. function get_accState(varChild: NewOleVariant; var pvarState: NewOleVariant): HRESULT; virtual; stdcall; abstract;
  255. function get_accHelp(varChild: NewOleVariant; var pszHelp: NewWideString): HRESULT; virtual; stdcall; abstract;
  256. function get_accHelpTopic(var pszHelpFile: NewWideString; varChild: NewOleVariant; var pidTopic: Integer): HRESULT; virtual; stdcall; abstract;
  257. function get_accKeyboardShortcut(varChild: NewOleVariant; var pszKeyboardShortcut: NewWideString): HRESULT; virtual; stdcall; abstract;
  258. function get_accFocus(var pvarID: NewOleVariant): HRESULT; virtual; stdcall; abstract;
  259. function get_accSelection(var pvarChildren: NewOleVariant): HRESULT; virtual; stdcall; abstract;
  260. function get_accDefaultAction(varChild: NewOleVariant; var pszDefaultAction: NewWideString): HRESULT; virtual; stdcall; abstract;
  261. function accSelect(flagsSelect: Integer; varChild: NewOleVariant): HRESULT; virtual; stdcall; abstract;
  262. function accLocation(var pxLeft: Integer; var pyTop: Integer; var pcxWidth: Integer;
  263. var pcyHeight: Integer; varChild: NewOleVariant): HRESULT; virtual; stdcall; abstract;
  264. function accNavigate(navDir: Integer; varStart: NewOleVariant; var pvarEnd: NewOleVariant): HRESULT; virtual; stdcall; abstract;
  265. function accHitTest(xLeft: Integer; yTop: Integer; var pvarID: NewOleVariant): HRESULT; virtual; stdcall; abstract;
  266. function accDoDefaultAction(varChild: NewOleVariant): HRESULT; virtual; stdcall; abstract;
  267. function put_accName(varChild: NewOleVariant; const pszName: NewWideString): HRESULT; virtual; stdcall; abstract;
  268. function put_accValue(varChild: NewOleVariant; const pszValue: NewWideString): HRESULT; virtual; stdcall; abstract;
  269. end;
  270. TAccObject = class(TIAccessible)
  271. private
  272. FControl: TNewCheckListBox;
  273. FRefCount: Integer;
  274. FStdAcc: TIAccessible;
  275. { TIUnknown }
  276. function QueryInterface(const iid: TIID; var obj): HRESULT; override;
  277. function AddRef: Longint; override;
  278. function Release: Longint; override;
  279. { TIDispatch }
  280. function GetTypeInfoCount(var ctinfo: Integer): HRESULT; override;
  281. function GetTypeInfo(itinfo: Integer; lcid: TLCID; var tinfo: ITypeInfo): HRESULT; override;
  282. function GetIDsOfNames(const iid: TIID; rgszNames: POleStrList;
  283. cNames: Integer; lcid: TLCID; rgdispid: PDispIDList): HRESULT; override;
  284. function Invoke(dispIDMember: TDispID; const iid: TIID; lcid: TLCID;
  285. flags: Word; var dispParams: TDispParams; varResult: PVariant;
  286. excepInfo: PExcepInfo; argErr: PInteger): HRESULT; override;
  287. { TIAccessible }
  288. function get_accParent(var ppdispParent: IDispatch): HRESULT; override;
  289. function get_accChildCount(var pcountChildren: Integer): HRESULT; override;
  290. function get_accChild(varChild: NewOleVariant; var ppdispChild: IDispatch): HRESULT; override;
  291. function get_accName(varChild: NewOleVariant; var pszName: NewWideString): HRESULT; override;
  292. function get_accValue(varChild: NewOleVariant; var pszValue: NewWideString): HRESULT; override;
  293. function get_accDescription(varChild: NewOleVariant; var pszDescription: NewWideString): HRESULT; override;
  294. function get_accRole(varChild: NewOleVariant; var pvarRole: NewOleVariant): HRESULT; override;
  295. function get_accState(varChild: NewOleVariant; var pvarState: NewOleVariant): HRESULT; override;
  296. function get_accHelp(varChild: NewOleVariant; var pszHelp: NewWideString): HRESULT; override;
  297. function get_accHelpTopic(var pszHelpFile: NewWideString; varChild: NewOleVariant; var pidTopic: Integer): HRESULT; override;
  298. function get_accKeyboardShortcut(varChild: NewOleVariant; var pszKeyboardShortcut: NewWideString): HRESULT; override;
  299. function get_accFocus(var pvarID: NewOleVariant): HRESULT; override;
  300. function get_accSelection(var pvarChildren: NewOleVariant): HRESULT; override;
  301. function get_accDefaultAction(varChild: NewOleVariant; var pszDefaultAction: NewWideString): HRESULT; override;
  302. function accSelect(flagsSelect: Integer; varChild: NewOleVariant): HRESULT; override;
  303. function accLocation(var pxLeft: Integer; var pyTop: Integer; var pcxWidth: Integer;
  304. var pcyHeight: Integer; varChild: NewOleVariant): HRESULT; override;
  305. function accNavigate(navDir: Integer; varStart: NewOleVariant; var pvarEnd: NewOleVariant): HRESULT; override;
  306. function accHitTest(xLeft: Integer; yTop: Integer; var pvarID: NewOleVariant): HRESULT; override;
  307. function accDoDefaultAction(varChild: NewOleVariant): HRESULT; override;
  308. function put_accName(varChild: NewOleVariant; const pszName: NewWideString): HRESULT; override;
  309. function put_accValue(varChild: NewOleVariant; const pszValue: NewWideString): HRESULT; override;
  310. public
  311. constructor Create(AControl: TNewCheckListBox);
  312. destructor Destroy; override;
  313. procedure ControlDestroying;
  314. end;
  315. function CoDisconnectObject(unk: TIUnknown; dwReserved: DWORD): HRESULT;
  316. stdcall; external 'ole32.dll';
  317. var
  318. NotifyWinEventFunc: procedure(event: DWORD; hwnd: HWND; idObject: DWORD;
  319. idChild: Longint); stdcall;
  320. OleAccInited: BOOL;
  321. OleAccAvailable: BOOL;
  322. LresultFromObjectFunc: function(const riid: TGUID; wParam: WPARAM;
  323. pUnk: TIUnknown): LRESULT; stdcall;
  324. CreateStdAccessibleObjectFunc: function(hwnd: HWND; idObject: Longint;
  325. const riidInterface: TGUID; var ppvObject: Pointer): HRESULT; stdcall;
  326. function InitializeOleAcc: Boolean;
  327. function GetSystemDir: String;
  328. var
  329. Buf: array[0..MAX_PATH-1] of Char;
  330. begin
  331. GetSystemDirectory(Buf, SizeOf(Buf) div SizeOf(Buf[0]));
  332. Result := StrPas(Buf);
  333. end;
  334. var
  335. M: HMODULE;
  336. begin
  337. if not OleAccInited then begin
  338. M := LoadLibrary(PChar(AddBackslash(GetSystemDir) + 'oleacc.dll'));
  339. if M <> 0 then begin
  340. LresultFromObjectFunc := GetProcAddress(M, 'LresultFromObject');
  341. CreateStdAccessibleObjectFunc := GetProcAddress(M, 'CreateStdAccessibleObject');
  342. if Assigned(LresultFromObjectFunc) and
  343. Assigned(CreateStdAccessibleObjectFunc) then
  344. OleAccAvailable := True;
  345. end;
  346. OleAccInited := True;
  347. end;
  348. Result := OleAccAvailable;
  349. end;
  350. { TNewCheckListBox }
  351. constructor TNewCheckListBox.Create(AOwner: TComponent);
  352. begin
  353. inherited Create(AOwner);
  354. with TBitmap.Create do
  355. begin
  356. try
  357. Handle := LoadBitmap(0, PChar(OBM_CHECKBOXES));
  358. FCheckWidth := Width div 4;
  359. FCheckHeight := Height div 3;
  360. finally
  361. Free;
  362. end;
  363. end;
  364. FStateList := TList.Create;
  365. FMinItemHeight := 16;
  366. FOffset := 4;
  367. FShowLines := True;
  368. Style := lbOwnerDrawVariable;
  369. FHotIndex := -1;
  370. FCaptureIndex := -1;
  371. end;
  372. procedure TNewCheckListBox.CreateParams(var Params: TCreateParams);
  373. begin
  374. inherited;
  375. FUseRightToLeft := SetBiDiStyles(Self, Params);
  376. end;
  377. procedure TNewCheckListBox.CreateWnd;
  378. begin
  379. { TCustomListBox.CreateWnd causes a LB_RESETCONTENT message to be sent when
  380. it's restoring FSaveItems. Increment FDisableItemStateDeletion so that
  381. our LB_RESETCONTENT handler doesn't delete any item states. }
  382. Inc(FDisableItemStateDeletion);
  383. try
  384. inherited;
  385. finally
  386. Dec(FDisableItemStateDeletion);
  387. end;
  388. end;
  389. procedure TNewCheckListBox.UpdateThemeData(const Close, Open: Boolean);
  390. begin
  391. if Close then begin
  392. if FThemeData <> 0 then begin
  393. CloseThemeData(FThemeData);
  394. FThemeData := 0;
  395. end;
  396. end;
  397. if Open then begin
  398. if UseThemes then
  399. FThemeData := OpenThemeData(Handle, 'Button')
  400. else
  401. FThemeData := 0;
  402. end;
  403. end;
  404. procedure TNewCheckListBox.CreateWindowHandle(const Params: TCreateParams);
  405. begin
  406. inherited CreateWindowHandle(Params);
  407. UpdateThemeData(True, True);
  408. end;
  409. destructor TNewCheckListBox.Destroy;
  410. var
  411. I: Integer;
  412. begin
  413. if Assigned(FAccObjectInstance) then begin
  414. { Detach from FAccObjectInstance if someone still has a reference to it }
  415. TAccObject(FAccObjectInstance).ControlDestroying;
  416. FAccObjectInstance := nil;
  417. end;
  418. if Assigned(FStateList) then begin
  419. for I := FStateList.Count-1 downto 0 do
  420. TItemState(FStateList[I]).Free;
  421. FStateList.Free;
  422. end;
  423. UpdateThemeData(True, False);
  424. inherited Destroy;
  425. end;
  426. function TNewCheckListBox.AddCheckBox(const ACaption, ASubItem: string;
  427. ALevel: Byte; AChecked, AEnabled, AHasInternalChildren,
  428. ACheckWhenParentChecked: Boolean; AObject: TObject): Integer;
  429. begin
  430. if not AEnabled and CheckPotentialRadioParents(Items.Count, ALevel) then
  431. raise Exception.Create(sRadioCantHaveDisabledChildren);
  432. Result := AddItem2(itCheck, ACaption, ASubItem, ALevel, AChecked, AEnabled,
  433. AHasInternalChildren, ACheckWhenParentChecked, AObject);
  434. end;
  435. function TNewCheckListBox.AddGroup(const ACaption, ASubItem: string;
  436. ALevel: Byte; AObject: TObject): Integer;
  437. begin
  438. Result := AddItem2(itGroup, ACaption, ASubItem, ALevel, False, True, False,
  439. True, AObject);
  440. end;
  441. function TNewCheckListBox.AddRadioButton(const ACaption, ASubItem: string;
  442. ALevel: Byte; AChecked, AEnabled: Boolean; AObject: TObject): Integer;
  443. begin
  444. if not AEnabled then
  445. AChecked := False;
  446. Result := AddItem2(itRadio, ACaption, ASubItem, ALevel, AChecked, AEnabled,
  447. False, True, AObject);
  448. end;
  449. function TNewCheckListBox.CanFocusItem(Item: Integer): Boolean;
  450. begin
  451. with ItemStates[Item] do
  452. Result := Self.Enabled and Enabled and (ItemType <> itGroup);
  453. end;
  454. function TNewCheckListBox.CheckPotentialRadioParents(Index, ALevel: Integer): Boolean;
  455. begin
  456. Result := True;
  457. Dec(Index);
  458. Dec(ALevel);
  459. while Index >= 0 do
  460. begin
  461. with ItemStates[Index] do
  462. if Level = ALevel then
  463. if ItemType = itRadio then
  464. Exit
  465. else
  466. Break;
  467. Dec(Index);
  468. end;
  469. if Index >= 0 then
  470. begin
  471. Index := GetParentOf(Index);
  472. while Index >= 0 do
  473. begin
  474. if ItemStates[Index].ItemType = itRadio then
  475. Exit;
  476. Index := GetParentOf(Index);
  477. end;
  478. end;
  479. Result := False;
  480. end;
  481. procedure TNewCheckListBox.CMDialogChar(var Message: TCMDialogChar);
  482. var
  483. I: Integer;
  484. begin
  485. if FWantTabs and CanFocus then
  486. with Message do
  487. begin
  488. I := FindAccel(CharCode);
  489. if I >= 0 then
  490. begin
  491. SetFocus;
  492. if (FCaptureIndex <> I) or FSpaceDown then EndCapture(not FSpaceDown);
  493. ItemIndex := I;
  494. Toggle(I);
  495. Result := 1
  496. end;
  497. end;
  498. end;
  499. procedure TNewCheckListBox.CMEnter(var Message: TCMEnter);
  500. var
  501. GoForward, Arrows: Boolean;
  502. begin
  503. if FWantTabs and FFormFocusChanged and (GetKeyState(VK_LBUTTON) >= 0) then
  504. begin
  505. if GetKeyState(VK_TAB) < 0 then begin
  506. Arrows := False;
  507. GoForward := (GetKeyState(VK_SHIFT) >= 0);
  508. end
  509. else if (GetKeyState(VK_UP) < 0) or (GetKeyState(VK_LEFT) < 0) then begin
  510. Arrows := True;
  511. GoForward := False;
  512. end
  513. else if (GetKeyState(VK_DOWN) < 0) or (GetKeyState(VK_RIGHT) < 0) then begin
  514. Arrows := True;
  515. GoForward := True;
  516. end
  517. else begin
  518. { Otherwise, just select the first item }
  519. Arrows := False;
  520. GoForward := True;
  521. end;
  522. if GoForward then
  523. ItemIndex := FindNextItem(-1, True, not Arrows)
  524. else
  525. ItemIndex := FindNextItem(Items.Count, False, not Arrows)
  526. end;
  527. inherited;
  528. end;
  529. procedure TNewCheckListBox.CMExit(var Message: TCMExit);
  530. begin
  531. EndCapture(not FSpaceDown or (GetKeyState(VK_MENU) >= 0));
  532. inherited;
  533. end;
  534. procedure TNewCheckListBox.CMFocusChanged(var Message: TCMFocusChanged);
  535. begin
  536. FFormFocusChanged := True;
  537. inherited;
  538. end;
  539. procedure TNewCheckListBox.CMFontChanged(var Message: TMessage);
  540. begin
  541. inherited;
  542. Canvas.Font := Font;
  543. end;
  544. procedure LineDDAProc(X, Y: Integer; Canvas: TCanvas); stdcall;
  545. begin
  546. if ((X xor Y) and 1) = 0 then
  547. begin
  548. Canvas.MoveTo(X, Y);
  549. Canvas.LineTo(X + 1, Y)
  550. end;
  551. end;
  552. procedure TNewCheckListBox.CMWantSpecialKey(var Message: TMessage);
  553. begin
  554. Message.Result := Ord(FWantTabs and (Message.WParam = VK_TAB));
  555. end;
  556. procedure TNewCheckListBox.CNDrawItem(var Message: TWMDrawItem);
  557. var
  558. L: Integer;
  559. begin
  560. with Message.DrawItemStruct^ do
  561. begin
  562. { Note: itemID is -1 when there are no items }
  563. if Integer(itemID) >= 0 then begin
  564. L := ItemStates[itemID].Level;
  565. if ItemStates[itemID].ItemType <> itGroup then Inc(L);
  566. rcItem.Left := rcItem.Left + (FCheckWidth + 2 * FOffset) * L;
  567. FlipRect(rcItem, ClientRect, FUseRightToLeft);
  568. end;
  569. { Don't let TCustomListBox.CNDrawItem draw the focus }
  570. if FWantTabs or
  571. (SendMessage(Handle, WM_QUERYUISTATE, 0, 0) and UISF_HIDEFOCUS <> 0) then
  572. itemState := itemState and not ODS_FOCUS;
  573. inherited;
  574. end;
  575. end;
  576. function TNewCheckListBox.RemeasureItem(Index: Integer): Integer;
  577. { Recalculates an item's height. Does not repaint and does not update the
  578. vertical scroll range (as the LB_SETITEMHEIGHT message does neither). }
  579. begin
  580. Result := ItemHeight;
  581. MeasureItem(Index, Result);
  582. SendMessage(Handle, LB_SETITEMHEIGHT, Index, Result);
  583. end;
  584. procedure TNewCheckListBox.UpdateScrollRange;
  585. { Updates the vertical scroll range, hiding/showing the scroll bar if needed.
  586. This should be called after any RemeasureItem call. }
  587. begin
  588. { Update the scroll bounds by sending a seemingly-ineffectual LB_SETTOPINDEX
  589. message. This works on Windows 95 and 2000.
  590. NOTE: This causes the selected item to be repainted for no apparent reason!
  591. I wish I knew of a better way to do this... }
  592. SendMessage(Handle, LB_SETTOPINDEX, SendMessage(Handle, LB_GETTOPINDEX, 0, 0), 0);
  593. end;
  594. procedure TNewCheckListBox.MeasureItem(Index: Integer; var Height: Integer);
  595. var
  596. DrawTextFormat: Integer;
  597. Rect, SubItemRect: TRect;
  598. ItemState: TItemState;
  599. L, SubItemWidth: Integer;
  600. S: String;
  601. begin
  602. with Canvas do begin
  603. ItemState := ItemStates[Index];
  604. Rect := Classes.Rect(0, 0, ClientWidth, 0);
  605. L := ItemState.Level;
  606. if ItemState.ItemType <> itGroup then
  607. Inc(L);
  608. Rect.Left := Rect.Left + (FCheckWidth + 2 * FOffset) * L;
  609. Inc(Rect.Left);
  610. if ItemState.SubItem <> '' then begin
  611. DrawTextFormat := DT_CALCRECT or DT_NOCLIP or DT_NOPREFIX or DT_SINGLELINE;
  612. if FUseRightToLeft then
  613. DrawTextFormat := DrawTextFormat or (DT_RIGHT or DT_RTLREADING);
  614. SetRectEmpty(SubItemRect);
  615. DrawText(Canvas.Handle, PChar(ItemState.SubItem), Length(ItemState.SubItem),
  616. SubItemRect, DrawTextFormat);
  617. SubItemWidth := SubItemRect.Right + 2 * FOffset;
  618. Dec(Rect.Right, SubItemWidth)
  619. end else
  620. Dec(Rect.Right, FOffset);
  621. if not FWantTabs then
  622. Inc(Rect.Left);
  623. DrawTextFormat := DT_NOCLIP or DT_CALCRECT or DT_WORDBREAK or DT_WORD_ELLIPSIS;
  624. if not FWantTabs or (ItemState.ItemType = itGroup) then
  625. DrawTextFormat := DrawTextFormat or DT_NOPREFIX;
  626. if FUseRightToLeft then
  627. DrawTextFormat := DrawTextFormat or (DT_RIGHT or DT_RTLREADING);
  628. S := Items[Index]; { Passing Items[Index] directly into DrawText doesn't work on Unicode build. }
  629. ItemState.MeasuredHeight := DrawText(Canvas.Handle, PChar(S), Length(S), Rect, DrawTextFormat);
  630. if ItemState.MeasuredHeight < FMinItemHeight then
  631. Height := FMinItemHeight
  632. else
  633. Height := ItemState.MeasuredHeight + 4;
  634. { The height must be an even number for tree lines to be painted correctly }
  635. if Odd(Height) then
  636. Inc(Height);
  637. end;
  638. end;
  639. procedure TNewCheckListBox.DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState);
  640. const
  641. ButtonStates: array [TItemType] of Integer =
  642. (
  643. 0,
  644. DFCS_BUTTONCHECK,
  645. DFCS_BUTTONRADIO
  646. );
  647. ButtonPartIds: array [TItemType] of Integer =
  648. (
  649. 0,
  650. BP_CHECKBOX,
  651. BP_RADIOBUTTON
  652. );
  653. ButtonStateIds: array [TCheckBoxState, TCheckBoxState2] of Integer =
  654. (
  655. //Can be used for both checkboxes and radiobuttons because RBS_... constants
  656. //equal CBS_... constants
  657. (CBS_UNCHECKEDNORMAL, CBS_UNCHECKEDHOT, CBS_UNCHECKEDPRESSED, CBS_UNCHECKEDDISABLED),
  658. (CBS_CHECKEDNORMAL, CBS_CHECKEDHOT, CBS_CHECKEDPRESSED, CBS_CHECKEDDISABLED),
  659. (CBS_MIXEDNORMAL, CBS_MIXEDHOT, CBS_MIXEDPRESSED, CBS_MIXEDDISABLED)
  660. );
  661. FontColorStates: array[Boolean] of TStyleFont = (sfListItemTextDisabled, sfListItemTextNormal);
  662. CheckListItemStates: array[Boolean] of TThemedCheckListBox = (tclListItemDisabled, tclListItemNormal);
  663. CheckBoxCheckedStates: array[Boolean] of TThemedButton = (tbCheckBoxCheckedDisabled, tbCheckBoxCheckedNormal);
  664. CheckBoxUncheckedStates: array[Boolean] of TThemedButton = (tbCheckBoxUncheckedDisabled, tbCheckBoxUncheckedNormal);
  665. CheckBoxMixedStates: array[Boolean] of TThemedButton = (tbCheckBoxMixedDisabled, tbCheckBoxMixedNormal);
  666. RadioButtonCheckedStates: array[Boolean] of TThemedButton = (tbRadioButtonCheckedDisabled, tbRadioButtonCheckedNormal);
  667. RadioButtonUncheckedStates: array[Boolean] of TThemedButton = (tbRadioButtonUncheckedDisabled, tbRadioButtonUncheckedNormal);
  668. var
  669. SavedClientRect: TRect;
  670. function FlipX(const X: Integer): Integer;
  671. begin
  672. if FUseRightToLeft then
  673. Result := (SavedClientRect.Right - 1) - X
  674. else
  675. Result := X;
  676. end;
  677. procedure InternalDrawText(const S: string; var R: TRect; Format: Integer;
  678. Embossed: Boolean);
  679. begin
  680. if Embossed then
  681. begin
  682. Canvas.Brush.Style := bsClear;
  683. OffsetRect(R, 1, 1);
  684. SetTextColor(Canvas.Handle, GetSysColor(COLOR_BTNHIGHLIGHT));
  685. DrawText(Canvas.Handle, PChar(S), Length(S), R, Format);
  686. OffsetRect(R, -1, -1);
  687. SetTextColor(Canvas.Handle, GetSysColor(COLOR_BTNSHADOW));
  688. DrawText(Canvas.Handle, PChar(S), Length(S), R, Format);
  689. end
  690. else
  691. DrawText(Canvas.Handle, PChar(S), Length(S), R, Format);
  692. end;
  693. var
  694. Disabled: Boolean;
  695. uState, I, ThreadPosX, ThreadBottom, ThreadLevel, ItemMiddle,
  696. DrawTextFormat: Integer;
  697. CheckRect, SubItemRect, FocusRect: TRect;
  698. NewTextColor: TColor;
  699. OldColor: TColorRef;
  700. ItemState: TItemState;
  701. UIState: DWORD;
  702. SubItemWidth: Integer;
  703. PartId, StateId: Integer;
  704. Size: TSize;
  705. begin
  706. if FShowLines and not FThreadsUpToDate then begin
  707. UpdateThreads;
  708. FThreadsUpToDate := True;
  709. end;
  710. SavedClientRect := ClientRect;
  711. { Undo flipping performed by TNewCheckListBox.CNDrawItem }
  712. FlipRect(Rect, SavedClientRect, FUseRightToLeft);
  713. ItemState := ItemStates[Index];
  714. UIState := SendMessage(Handle, WM_QUERYUISTATE, 0, 0);
  715. Disabled := not Enabled or not ItemState.Enabled;
  716. { Style code below is based on Vcl.StdCtrls' TCustomListBox.CNDrawItem and Vcl.CheckLst's
  717. TCustomCheckListBox.DrawItem and .DrawCheck }
  718. var LStyle := StyleServices(Self);
  719. if not LStyle.Enabled or LStyle.IsSystemStyle then
  720. LStyle := nil;
  721. with Canvas do begin
  722. { Initialize colors }
  723. if not FWantTabs and (odSelected in State) and Focused then begin
  724. NewTextColor := clHighlightText;
  725. if (LStyle <> nil) and (seClient in StyleElements) then begin
  726. Brush.Color := LStyle.GetSystemColor(clHighlight);
  727. if seFont in StyleElements then
  728. NewTextColor := LStyle.GetStyleFontColor(sfListItemTextSelected);
  729. end else
  730. Brush.Color := clHighlight;
  731. end else begin
  732. if Disabled then
  733. NewTextColor := clGrayText
  734. else
  735. NewTextColor := Self.Font.Color;
  736. if (LStyle <> nil) and (seClient in StyleElements) then begin
  737. Brush.Color := LStyle.GetStyleColor(scListBox);
  738. if seFont in StyleElements then begin
  739. NewTextColor := LStyle.GetStyleFontColor(FontColorStates[not Disabled]);
  740. const Details = LStyle.GetElementDetails(CheckListItemStates[Enabled]);
  741. var LColor: TColor;
  742. if LStyle.GetElementColor(Details, ecTextColor, LColor) and (LColor <> clNone) then
  743. NewTextColor := LColor;
  744. end;
  745. end else
  746. Brush.Color := Self.Color;
  747. end;
  748. { Draw threads }
  749. if FShowLines then begin
  750. Pen.Color := clGrayText;
  751. ThreadLevel := ItemLevel[Index];
  752. for I := 0 to ThreadLevel - 1 do
  753. if I in ItemStates[Index].ThreadCache then begin
  754. ThreadPosX := (FCheckWidth + 2 * FOffset) * I + FCheckWidth div 2 + FOffset;
  755. ItemMiddle := (Rect.Bottom - Rect.Top) div 2 + Rect.Top;
  756. ThreadBottom := Rect.Bottom;
  757. if I = ThreadLevel - 1 then begin
  758. if ItemStates[Index].IsLastChild then
  759. ThreadBottom := ItemMiddle;
  760. LineDDA(FlipX(ThreadPosX), ItemMiddle, FlipX(ThreadPosX + FCheckWidth div 2 + FOffset),
  761. ItemMiddle, @LineDDAProc, Integer(Canvas));
  762. end;
  763. LineDDA(FlipX(ThreadPosX), Rect.Top, FlipX(ThreadPosX), ThreadBottom,
  764. @LineDDAProc, Integer(Canvas));
  765. end;
  766. end;
  767. { Draw checkmark}
  768. if ItemState.ItemType <> itGroup then begin
  769. CheckRect := Bounds(Rect.Left - (FCheckWidth + FOffset),
  770. Rect.Top + ((Rect.Bottom - Rect.Top - FCheckHeight) div 2),
  771. FCheckWidth, FCheckHeight);
  772. FlipRect(CheckRect, SavedClientRect, FUseRightToLeft);
  773. if LStyle <> nil then begin
  774. var Detail: TThemedButton;
  775. if ItemState.State <> cbGrayed then begin
  776. if ItemState.ItemType = itCheck then begin
  777. if ItemState.State = cbChecked then
  778. Detail := CheckBoxCheckedStates[not Disabled]
  779. else
  780. Detail := CheckBoxUncheckedStates[not Disabled];
  781. end else begin
  782. if ItemState.State = cbChecked then
  783. Detail := RadioButtonCheckedStates[not Disabled]
  784. else
  785. Detail := RadioButtonUncheckedStates[not Disabled];
  786. end;
  787. end else
  788. Detail := CheckBoxMixedStates[not Disabled];
  789. const ElementDetails = LStyle.GetElementDetails(Detail);
  790. const SaveColor = Brush.Color;
  791. const SaveIndex = SaveDC(Handle);
  792. try
  793. LStyle.DrawElement(Handle, ElementDetails, CheckRect, nil, CurrentPPI);
  794. finally
  795. RestoreDC(Handle, SaveIndex);
  796. end;
  797. Brush.Color := SaveColor;
  798. end else if FThemeData = 0 then begin
  799. case ItemState.State of
  800. cbChecked: uState := ButtonStates[ItemState.ItemType] or DFCS_CHECKED;
  801. cbUnchecked: uState := ButtonStates[ItemState.ItemType];
  802. else
  803. uState := DFCS_BUTTON3STATE or DFCS_CHECKED;
  804. end;
  805. if FFlat then
  806. uState := uState or DFCS_FLAT;
  807. if Disabled then
  808. uState := uState or DFCS_INACTIVE;
  809. if (FCaptureIndex = Index) and (FSpaceDown or (FLastMouseMoveIndex = Index)) then
  810. uState := uState or DFCS_PUSHED;
  811. DrawFrameControl(Handle, CheckRect, DFC_BUTTON, uState)
  812. end else begin
  813. PartId := ButtonPartIds[ItemState.ItemType];
  814. if Disabled then
  815. StateId := ButtonStateIds[ItemState.State][cb2Disabled]
  816. else if Index = FCaptureIndex then
  817. if FSpaceDown or (FLastMouseMoveIndex = Index) then
  818. StateId := ButtonStateIds[ItemState.State][cb2Pressed]
  819. else
  820. StateId := ButtonStateIds[ItemState.State][cb2Hot]
  821. else if (FCaptureIndex < 0) and (Index = FHotIndex) then
  822. StateId := ButtonStateIds[ItemState.State][cb2Hot]
  823. else
  824. StateId := ButtonStateIds[ItemState.State][cb2Normal];
  825. GetThemePartSize(FThemeData, Handle, PartId, StateId, @CheckRect, TS_TRUE, Size);
  826. if (Size.cx <> FCheckWidth) or (Size.cy <> FCheckHeight) then begin
  827. CheckRect := Bounds(Rect.Left - (Size.cx + FOffset),
  828. Rect.Top + ((Rect.Bottom - Rect.Top - Size.cy) div 2),
  829. Size.cx, Size.cy);
  830. FlipRect(CheckRect, SavedClientRect, FUseRightToLeft);
  831. end;
  832. //if IsThemeBackgroundPartiallyTransparent(FThemeData, PartId, StateId) then
  833. // DrawThemeParentBackground(Self.Handle, Handle, @CheckRect);
  834. DrawThemeBackGround(FThemeData, Handle, PartId, StateId, CheckRect, @CheckRect);
  835. end;
  836. end;
  837. { Draw SubItem }
  838. FlipRect(Rect, SavedClientRect, FUseRightToLeft);
  839. FillRect(Rect);
  840. FlipRect(Rect, SavedClientRect, FUseRightToLeft);
  841. Inc(Rect.Left);
  842. OldColor := SetTextColor(Handle, ColorToRGB(NewTextColor));
  843. if ItemState.SubItem <> '' then
  844. begin
  845. DrawTextFormat := DT_NOCLIP or DT_NOPREFIX or DT_SINGLELINE or DT_VCENTER;
  846. if FUseRightToLeft then
  847. DrawTextFormat := DrawTextFormat or (DT_RIGHT or DT_RTLREADING);
  848. Font.Style := ItemState.SubItemFontStyle;
  849. SetRectEmpty(SubItemRect);
  850. InternalDrawText(ItemState.SubItem, SubItemRect, DrawTextFormat or
  851. DT_CALCRECT, False);
  852. SubItemWidth := SubItemRect.Right + 2 * FOffset;
  853. SubItemRect := Rect;
  854. SubItemRect.Left := SubItemRect.Right - SubItemWidth + FOffset;
  855. FlipRect(SubItemRect, SavedClientRect, FUseRightToLeft);
  856. InternalDrawText(ItemState.SubItem, SubItemRect, DrawTextFormat,
  857. FWantTabs and Disabled);
  858. Dec(Rect.Right, SubItemWidth);
  859. end
  860. else
  861. Dec(Rect.Right, FOffset);
  862. { Draw item text }
  863. if not FWantTabs then
  864. Inc(Rect.Left);
  865. OffsetRect(Rect, 0, (Rect.Bottom - Rect.Top - ItemState.MeasuredHeight) div 2);
  866. DrawTextFormat := DT_NOCLIP or DT_WORDBREAK or DT_WORD_ELLIPSIS;
  867. if not FWantTabs or (ItemState.ItemType = itGroup) then
  868. DrawTextFormat := DrawTextFormat or DT_NOPREFIX;
  869. if (UIState and UISF_HIDEACCEL) <> 0 then
  870. DrawTextFormat := DrawTextFormat or DT_HIDEPREFIX;
  871. if FUseRightToLeft then
  872. DrawTextFormat := DrawTextFormat or (DT_RIGHT or DT_RTLREADING);
  873. Font.Style := ItemState.ItemFontStyle;
  874. { When you call DrawText with the DT_CALCRECT flag and there's a word wider
  875. than the rectangle width, it increases the rectangle width and wraps
  876. at the new Right point. On the other hand, when you call DrawText
  877. _without_ the DT_CALCRECT flag, it always wraps at the Right point you
  878. specify -- it doesn't check for long words first.
  879. Therefore, to ensure we wrap at the same place when drawing as when
  880. measuring, pass our rectangle to DrawText with DT_CALCRECT first.
  881. Wrapping at the same place is important because it can affect how many
  882. lines are drawn -- and we mustn't draw too many. }
  883. InternalDrawText(Items[Index], Rect, DrawTextFormat or DT_CALCRECT, False);
  884. FlipRect(Rect, SavedClientRect, FUseRightToLeft);
  885. InternalDrawText(Items[Index], Rect, DrawTextFormat, FWantTabs and Disabled and (LStyle = nil));
  886. { Draw focus rectangle }
  887. if FWantTabs and not Disabled and (odSelected in State) and Focused and
  888. (UIState and UISF_HIDEFOCUS = 0) then
  889. begin
  890. FocusRect := Rect;
  891. InflateRect(FocusRect, 1, 1);
  892. DrawFocusRect(FocusRect);
  893. end;
  894. SetTextColor(Handle, OldColor);
  895. end;
  896. end;
  897. procedure TNewCheckListBox.EndCapture(Cancel: Boolean);
  898. var
  899. InvalidateItem: Boolean;
  900. Item: Integer;
  901. begin
  902. Item := FCaptureIndex;
  903. if Item >= 0 then
  904. begin
  905. InvalidateItem := FSpaceDown or (FCaptureIndex = FLastMouseMoveIndex) or (FThemeData <> 0);
  906. FSpaceDown := False;
  907. FCaptureIndex := -1;
  908. FLastMouseMoveIndex := -1;
  909. if not Cancel then
  910. Toggle(Item);
  911. if InvalidateItem then
  912. InvalidateCheck(Item);
  913. end;
  914. if MouseCapture then
  915. MouseCapture := False;
  916. end;
  917. procedure TNewCheckListBox.EnumChildrenOf(Item: Integer; Proc: TEnumChildrenProc;
  918. Ext: Longint);
  919. var
  920. L: Integer;
  921. begin
  922. if (Item < -1) or (Item >= Items.Count) then
  923. Exit;
  924. if Item = -1 then
  925. begin
  926. L := 0;
  927. Item := 0;
  928. end
  929. else
  930. begin
  931. L := ItemLevel[Item] + 1;
  932. Inc(Item);
  933. end;
  934. while (Item < Items.Count) and (ItemLevel[Item] >= L) do
  935. begin
  936. if ItemLevel[Item] = L then
  937. Proc(Item, (Item < Items.Count - 1) and (ItemLevel[Item + 1] > L), Ext);
  938. Inc(Item);
  939. end;
  940. end;
  941. function TNewCheckListBox.AddItem2(AType: TItemType;
  942. const ACaption, ASubItem: string; ALevel: Byte;
  943. AChecked, AEnabled, AHasInternalChildren, ACheckWhenParentChecked: Boolean;
  944. AObject: TObject): Integer;
  945. var
  946. ItemState: TItemState;
  947. I: Integer;
  948. begin
  949. if Items.Count <> FStateList.Count then { sanity check }
  950. raise Exception.Create('List item and state item count mismatch');
  951. if Items.Count > 0 then
  952. begin
  953. if ItemLevel[Items.Count - 1] + 1 < ALevel then
  954. ALevel := ItemLevel[Items.Count - 1] + 1;
  955. end
  956. else
  957. ALevel := 0;
  958. FThreadsUpToDate := False;
  959. { Use our own grow code to minimize heap fragmentation }
  960. if FStateList.Count = FStateList.Capacity then begin
  961. if FStateList.Capacity < 64 then
  962. FStateList.Capacity := 64
  963. else
  964. FStateList.Capacity := FStateList.Capacity * 2;
  965. end;
  966. ItemState := TItemState.Create;
  967. try
  968. ItemState.ItemType := AType;
  969. ItemState.Enabled := AEnabled;
  970. ItemState.Obj := AObject;
  971. ItemState.Level := ALevel;
  972. ItemState.SubItem := ASubItem;
  973. ItemState.HasInternalChildren := AHasInternalChildren;
  974. ItemState.CheckWhenParentChecked := ACheckWhenParentChecked;
  975. except
  976. ItemState.Free;
  977. raise;
  978. end;
  979. FStateList.Add(ItemState);
  980. try
  981. Result := Items.Add(ACaption);
  982. except
  983. FStateList.Delete(FStateList.Count-1);
  984. ItemState.Free;
  985. raise;
  986. end;
  987. { If the first item in a radio group is being added, and it is top-level or
  988. has a checked parent, force it to be checked. (We don't want to allow radio
  989. groups with no selection.) }
  990. if (AType = itRadio) and not AChecked and AEnabled then begin
  991. I := GetParentOf(Result);
  992. { FRequireRadioSelection only affects top-level items; we never allow
  993. child radio groups with no selection (because nobody should need that) }
  994. if FRequireRadioSelection or (I <> -1) then
  995. if (I = -1) or (GetState(I) <> cbUnchecked) then
  996. if FindCheckedSibling(Result) = -1 then
  997. AChecked := True;
  998. end;
  999. SetChecked(Result, AChecked);
  1000. end;
  1001. function TNewCheckListBox.FindAccel(VK: Word): Integer;
  1002. begin
  1003. for Result := 0 to Items.Count - 1 do
  1004. if CanFocusItem(Result) and IsAccel(VK, Items[Result]) then
  1005. Exit;
  1006. Result := -1;
  1007. end;
  1008. function TNewCheckListBox.FindNextItem(StartFrom: Integer; GoForward,
  1009. SkipUncheckedRadios: Boolean): Integer;
  1010. function ShouldSkip(Index: Integer): Boolean;
  1011. begin
  1012. with ItemStates[Index] do
  1013. Result := (ItemType = itRadio) and (State <> cbChecked)
  1014. end;
  1015. var
  1016. Delta: Integer;
  1017. begin
  1018. if StartFrom < -1 then
  1019. StartFrom := ItemIndex;
  1020. if Items.Count > 0 then
  1021. begin
  1022. Delta := Ord(GoForward) * 2 - 1;
  1023. Result := StartFrom + Delta;
  1024. while (Result >= 0) and (Result < Items.Count) and
  1025. (not CanFocusItem(Result) or SkipUncheckedRadios and ShouldSkip(Result)) do
  1026. Result := Result + Delta;
  1027. if (Result < 0) or (Result >= Items.Count) then
  1028. Result := -1;
  1029. end
  1030. else
  1031. Result := -1;
  1032. end;
  1033. function TNewCheckListBox.GetCaption(Index: Integer): String;
  1034. begin
  1035. Result := Items[Index];
  1036. end;
  1037. function TNewCheckListBox.GetChecked(Index: Integer): Boolean;
  1038. begin
  1039. Result := GetState(Index) <> cbUnchecked;
  1040. end;
  1041. function TNewCheckListBox.GetItemEnabled(Index: Integer): Boolean;
  1042. begin
  1043. Result := ItemStates[Index].Enabled;
  1044. end;
  1045. function TNewCheckListBox.GetItemFontStyle(Index: Integer): TFontStyles;
  1046. begin
  1047. Result := ItemStates[Index].ItemFontStyle;
  1048. end;
  1049. function TNewCheckListBox.GetItemState(Index: Integer): TItemState;
  1050. begin
  1051. Result := FStateList[Index];
  1052. end;
  1053. function TNewCheckListBox.GetLevel(Index: Integer): Byte;
  1054. begin
  1055. Result := ItemStates[Index].Level;
  1056. end;
  1057. function TNewCheckListBox.GetObject(Index: Integer): TObject;
  1058. begin
  1059. Result := ItemStates[Index].Obj;
  1060. end;
  1061. function TNewCheckListBox.GetParentOf(Item: Integer): Integer;
  1062. { Gets index of Item's parent, or -1 if there is none. }
  1063. var
  1064. Level, I: Integer;
  1065. begin
  1066. Level := ItemStates[Item].Level;
  1067. if Level > 0 then
  1068. for I := Item-1 downto 0 do begin
  1069. if ItemStates[I].Level < Level then begin
  1070. Result := I;
  1071. Exit;
  1072. end;
  1073. end;
  1074. Result := -1;
  1075. end;
  1076. function TNewCheckListBox.GetState(Index: Integer): TCheckBoxState;
  1077. begin
  1078. Result := ItemStates[Index].State;
  1079. end;
  1080. function TNewCheckListBox.GetSubItem(Index: Integer): String;
  1081. begin
  1082. Result := ItemStates[Index].SubItem;
  1083. end;
  1084. function TNewCheckListBox.GetSubItemFontStyle(Index: Integer): TFontStyles;
  1085. begin
  1086. Result := ItemStates[Index].SubItemFontStyle;
  1087. end;
  1088. procedure TNewCheckListBox.InvalidateCheck(Index: Integer);
  1089. var
  1090. IRect: TRect;
  1091. begin
  1092. IRect := ItemRect(Index);
  1093. Inc(IRect.Left, (FCheckWidth + 2 * Offset) * (ItemLevel[Index]));
  1094. IRect.Right := IRect.Left + (FCheckWidth + 2 * Offset);
  1095. FlipRect(IRect, ClientRect, FUseRightToLeft);
  1096. InvalidateRect(Handle, @IRect, FThemeData <> 0);
  1097. end;
  1098. procedure TNewCheckListBox.KeyDown(var Key: Word; Shift: TShiftState);
  1099. begin
  1100. if (Key = VK_SPACE) and not (ssAlt in Shift) and (ItemIndex >= 0) and
  1101. (FCaptureIndex < 0) and CanFocusItem(ItemIndex) then
  1102. if FWantTabs then begin
  1103. if not FSpaceDown then begin
  1104. FCaptureIndex := ItemIndex;
  1105. FSpaceDown := True;
  1106. InvalidateCheck(ItemIndex);
  1107. if (FHotIndex <> ItemIndex) and (FHotIndex <> -1) and (FThemeData <> 0) then
  1108. InvalidateCheck(FHotIndex);
  1109. end;
  1110. end
  1111. else
  1112. Toggle(ItemIndex);
  1113. inherited;
  1114. end;
  1115. procedure TNewCheckListBox.KeyUp(var Key: Word; Shift: TShiftState);
  1116. begin
  1117. if (Key = VK_SPACE) and FWantTabs and FSpaceDown and (FCaptureIndex >= 0) then begin
  1118. EndCapture(False);
  1119. if (FHotIndex <> -1) and (FThemeData <> 0) then
  1120. InvalidateCheck(FHotIndex);
  1121. end;
  1122. inherited;
  1123. end;
  1124. procedure TNewCheckListBox.MouseDown(Button: TMouseButton; Shift: TShiftState;
  1125. X, Y: Integer);
  1126. var
  1127. Index: Integer;
  1128. begin
  1129. if Button = mbLeft then begin
  1130. Index := ItemAtPos(Point(X, Y), True);
  1131. if (Index <> -1) and CanFocusItem(Index) then
  1132. begin
  1133. if FWantTabs then begin
  1134. if not FSpaceDown then begin
  1135. if not MouseCapture then
  1136. MouseCapture := True;
  1137. FCaptureIndex := Index;
  1138. FLastMouseMoveIndex := Index;
  1139. InvalidateCheck(Index);
  1140. end;
  1141. end
  1142. else
  1143. Toggle(Index);
  1144. end;
  1145. end;
  1146. inherited;
  1147. end;
  1148. procedure TNewCheckListBox.MouseUp(Button: TMouseButton; Shift: TShiftState;
  1149. X, Y: Integer);
  1150. var
  1151. Index: Integer;
  1152. begin
  1153. if (Button = mbLeft) and FWantTabs and not FSpaceDown and (FCaptureIndex >= 0) then
  1154. begin
  1155. Index := ItemAtPos(Point(X, Y), True);
  1156. EndCapture(Index <> FCaptureIndex);
  1157. if (FHotIndex <> -1) and (FThemeData <> 0) then
  1158. InvalidateCheck(FHotIndex);
  1159. end;
  1160. end;
  1161. procedure TNewCheckListBox.UpdateHotIndex(NewHotIndex: Integer);
  1162. var
  1163. OldHotIndex: Integer;
  1164. begin
  1165. OldHotIndex := FHotIndex;
  1166. if NewHotIndex <> OldHotIndex then
  1167. begin
  1168. FHotIndex := NewHotIndex;
  1169. if FCaptureIndex = -1 then begin
  1170. if (OldHotIndex <> -1) and (FThemeData <> 0) then
  1171. InvalidateCheck(OldHotIndex);
  1172. if (NewHotIndex <> -1) and (FThemeData <> 0) then
  1173. InvalidateCheck(NewHotIndex);
  1174. end;
  1175. end;
  1176. end;
  1177. procedure TNewCheckListBox.CMMouseLeave(var Message: TMessage);
  1178. begin
  1179. UpdateHotIndex(-1);
  1180. inherited;
  1181. end;
  1182. procedure TNewCheckListBox.SetCaption(Index: Integer; const Value: String);
  1183. begin
  1184. { Changing an item's text actually involves deleting and re-inserting the
  1185. item. Increment FDisableItemStateDeletion so the item state isn't lost. }
  1186. Inc(FDisableItemStateDeletion);
  1187. try
  1188. Items[Index] := Value;
  1189. finally
  1190. Dec(FDisableItemStateDeletion);
  1191. end;
  1192. end;
  1193. procedure TNewCheckListBox.SetChecked(Index: Integer; const AChecked: Boolean);
  1194. begin
  1195. if AChecked then
  1196. CheckItem(Index, coCheck)
  1197. else
  1198. CheckItem(Index, coUncheck);
  1199. end;
  1200. function TNewCheckListBox.FindCheckedSibling(const AIndex: Integer): Integer;
  1201. { Finds a checked sibling of AIndex (which is assumed to be a radio button).
  1202. Returns -1 if no checked sibling was found. }
  1203. var
  1204. ThisLevel, I: Integer;
  1205. begin
  1206. ThisLevel := ItemStates[AIndex].Level;
  1207. for I := AIndex-1 downto 0 do begin
  1208. if ItemStates[I].Level < ThisLevel then
  1209. Break;
  1210. if ItemStates[I].Level = ThisLevel then begin
  1211. if ItemStates[I].ItemType <> itRadio then
  1212. Break;
  1213. if GetState(I) <> cbUnchecked then begin
  1214. Result := I;
  1215. Exit;
  1216. end;
  1217. end;
  1218. end;
  1219. for I := AIndex+1 to Items.Count-1 do begin
  1220. if ItemStates[I].Level < ThisLevel then
  1221. Break;
  1222. if ItemStates[I].Level = ThisLevel then begin
  1223. if ItemStates[I].ItemType <> itRadio then
  1224. Break;
  1225. if GetState(I) <> cbUnchecked then begin
  1226. Result := I;
  1227. Exit;
  1228. end;
  1229. end;
  1230. end;
  1231. Result := -1;
  1232. end;
  1233. function TNewCheckListBox.CheckItem(const Index: Integer;
  1234. const AOperation: TCheckItemOperation): Boolean;
  1235. { Tries to update the checked state of Index. Returns True if any changes were
  1236. made to the state of Index or any of its children. }
  1237. procedure SetItemState(const AIndex: Integer; const AState: TCheckBoxState);
  1238. begin
  1239. if ItemStates[AIndex].State <> AState then begin
  1240. ItemStates[AIndex].State := AState;
  1241. InvalidateCheck(AIndex);
  1242. { Notify MSAA of the state change }
  1243. if Assigned(NotifyWinEventFunc) then
  1244. NotifyWinEventFunc(EVENT_OBJECT_STATECHANGE, Handle, OBJID_CLIENT,
  1245. 1 + AIndex);
  1246. end;
  1247. end;
  1248. function CalcState(const AIndex: Integer; ACheck: Boolean): TCheckBoxState;
  1249. { Determines new state for AIndex based on desired checked state (ACheck) and
  1250. current state of the item's immediate children. }
  1251. var
  1252. RootLevel, I: Integer;
  1253. HasChecked, HasUnchecked: Boolean;
  1254. begin
  1255. HasChecked := False;
  1256. HasUnchecked := False;
  1257. RootLevel := ItemStates[AIndex].Level;
  1258. for I := AIndex+1 to Items.Count-1 do begin
  1259. if ItemStates[I].Level <= RootLevel then
  1260. Break;
  1261. if (ItemStates[I].Level = RootLevel+1) and
  1262. (ItemStates[I].ItemType in [itCheck, itRadio]) then begin
  1263. case GetState(I) of
  1264. cbUnchecked: begin
  1265. if (ItemStates[I].ItemType <> itRadio) or
  1266. (FindCheckedSibling(I) = -1) then
  1267. HasUnchecked := True;
  1268. end;
  1269. cbChecked: begin
  1270. HasChecked := True;
  1271. end;
  1272. cbGrayed: begin
  1273. HasChecked := True;
  1274. HasUnchecked := True;
  1275. end;
  1276. end;
  1277. end;
  1278. end;
  1279. { If the parent is a check box with children, don't allow it to be checked
  1280. if none of its children are checked, unless it "has internal children" }
  1281. if HasUnchecked and not HasChecked and
  1282. (ItemStates[AIndex].ItemType = itCheck) and
  1283. not ItemStates[AIndex].HasInternalChildren then
  1284. ACheck := False;
  1285. if ACheck or HasChecked then begin
  1286. if HasUnchecked and (ItemStates[AIndex].ItemType = itCheck) then
  1287. Result := cbGrayed
  1288. else
  1289. Result := cbChecked;
  1290. end
  1291. else
  1292. Result := cbUnchecked;
  1293. end;
  1294. function RecursiveCheck(const AIndex: Integer;
  1295. const AOperation: TCheckItemOperation): Boolean;
  1296. { Checks or unchecks AIndex and all enabled child items of AIndex at any
  1297. level. In radio button groups, only one item per group is checked.
  1298. Returns True if any of the items' states were changed. }
  1299. var
  1300. RootLevel, I: Integer;
  1301. NewState: TCheckBoxState;
  1302. begin
  1303. Result := False;
  1304. RootLevel := ItemStates[AIndex].Level;
  1305. for I := AIndex+1 to Items.Count-1 do begin
  1306. if ItemStates[I].Level <= RootLevel then
  1307. Break;
  1308. if (ItemStates[I].Level = RootLevel+1) and ItemStates[I].Enabled and
  1309. ((AOperation = coUncheck) or
  1310. ((AOperation = coCheckWithChildren) and ItemStates[I].CheckWhenParentChecked) or
  1311. (ItemStates[I].ItemType = itRadio)) then
  1312. { If checking and I is a radio button, don't recurse if a sibling
  1313. already got checked in a previous iteration of this loop. This is
  1314. needed in the following case to prevent all three radio buttons from
  1315. being checked when "Parent check" is checked. In addition, it
  1316. prevents "Child check" from being checked.
  1317. [ ] Parent check
  1318. ( ) Radio 1
  1319. ( ) Radio 2
  1320. ( ) Radio 3
  1321. [ ] Child check
  1322. }
  1323. if (AOperation = coUncheck) or (ItemStates[I].ItemType <> itRadio) or
  1324. (FindCheckedSibling(I) = -1) then
  1325. if RecursiveCheck(I, AOperation) then
  1326. Result := True;
  1327. end;
  1328. NewState := CalcState(AIndex, AOperation <> coUncheck);
  1329. if GetState(AIndex) <> NewState then begin
  1330. SetItemState(AIndex, NewState);
  1331. Result := True;
  1332. end;
  1333. end;
  1334. procedure UncheckSiblings(const AIndex: Integer);
  1335. { Unchecks all siblings (and their children) of AIndex, which is assumed to
  1336. be a radio button. }
  1337. var
  1338. I: Integer;
  1339. begin
  1340. while True do begin
  1341. I := FindCheckedSibling(AIndex);
  1342. if I = -1 then
  1343. Break;
  1344. RecursiveCheck(I, coUncheck);
  1345. end;
  1346. end;
  1347. procedure EnsureChildRadioItemsHaveSelection(const AIndex: Integer);
  1348. { Ensures all radio button groups that are immediate children of AIndex have
  1349. a selected item. }
  1350. var
  1351. RootLevel, I: Integer;
  1352. begin
  1353. RootLevel := ItemStates[AIndex].Level;
  1354. for I := AIndex+1 to Items.Count-1 do begin
  1355. if ItemStates[I].Level <= RootLevel then
  1356. Break;
  1357. if (ItemStates[I].Level = RootLevel+1) and
  1358. (ItemStates[I].ItemType = itRadio) and
  1359. ItemStates[I].Enabled and
  1360. (GetState(I) <> cbChecked) and
  1361. (FindCheckedSibling(I) = -1) then
  1362. { Note: This uses coCheck instead of coCheckWithChildren (or the value
  1363. of AOperation) in order to keep side effects to a minimum. Seems
  1364. like the most logical behavior. For example, in this case:
  1365. [ ] A
  1366. ( ) B
  1367. [ ] C
  1368. [ ] D
  1369. clicking D will cause the radio button B to be checked (out of
  1370. necessity), but won't automatically check its child check box, C.
  1371. (If C were instead a radio button, it *would* be checked.) }
  1372. RecursiveCheck(I, coCheck);
  1373. end;
  1374. end;
  1375. procedure UpdateParentStates(const AIndex: Integer);
  1376. var
  1377. I: Integer;
  1378. ChildChecked: Boolean;
  1379. NewState: TCheckBoxState;
  1380. begin
  1381. I := AIndex;
  1382. while True do begin
  1383. ChildChecked := (GetState(I) <> cbUnchecked);
  1384. I := GetParentOf(I);
  1385. if I = -1 then
  1386. Break;
  1387. { When a child item is checked, must ensure that all sibling radio button
  1388. groups have selections }
  1389. if ChildChecked then
  1390. EnsureChildRadioItemsHaveSelection(I);
  1391. NewState := CalcState(I, GetState(I) <> cbUnchecked);
  1392. { If a parent radio button is becoming checked, uncheck any previously
  1393. selected sibling of that radio button }
  1394. if (NewState <> cbUnchecked) and (ItemStates[I].ItemType = itRadio) then
  1395. UncheckSiblings(I);
  1396. SetItemState(I, NewState);
  1397. end;
  1398. end;
  1399. begin
  1400. if ItemStates[Index].ItemType = itRadio then begin
  1401. { Setting Checked to False on a radio button is a no-op. (A radio button
  1402. may only be unchecked by checking another radio button in the group, or
  1403. by unchecking a parent check box.) }
  1404. if AOperation = coUncheck then begin
  1405. Result := False;
  1406. Exit;
  1407. end;
  1408. { Before checking a new item in a radio group, uncheck any siblings and
  1409. their children }
  1410. UncheckSiblings(Index);
  1411. end;
  1412. { Check or uncheck this item and all its children }
  1413. Result := RecursiveCheck(Index, AOperation);
  1414. { Update state of parents. For example, if a child check box is being
  1415. checked, its parent must also become checked if it isn't already. }
  1416. UpdateParentStates(Index);
  1417. end;
  1418. procedure TNewCheckListBox.SetFlat(Value: Boolean);
  1419. begin
  1420. if Value <> FFlat then
  1421. begin
  1422. FFlat := Value;
  1423. Invalidate;
  1424. end;
  1425. end;
  1426. procedure TNewCheckListBox.SetItemEnabled(Index: Integer; const AEnabled: Boolean);
  1427. begin
  1428. if ItemStates[Index].Enabled <> AEnabled then
  1429. begin
  1430. ItemStates[Index].Enabled := AEnabled;
  1431. InvalidateCheck(Index);
  1432. end;
  1433. end;
  1434. procedure TNewCheckListBox.SetItemFontStyle(Index: Integer; const AItemFontStyle: TFontStyles);
  1435. var
  1436. R: TRect;
  1437. begin
  1438. if ItemStates[Index].ItemFontStyle <> AItemFontStyle then begin
  1439. ItemStates[Index].ItemFontStyle := AItemFontStyle;
  1440. R := ItemRect(Index);
  1441. InvalidateRect(Handle, @R, True);
  1442. end;
  1443. end;
  1444. procedure TNewCheckListBox.SetObject(Index: Integer; const AObject: TObject);
  1445. begin
  1446. ItemStates[Index].Obj := AObject;
  1447. end;
  1448. procedure TNewCheckListBox.SetOffset(AnOffset: Integer);
  1449. begin
  1450. if FOffset <> AnOffset then
  1451. begin
  1452. FOffset := AnOffset;
  1453. Invalidate;
  1454. end;
  1455. end;
  1456. procedure TNewCheckListBox.SetShowLines(Value: Boolean);
  1457. begin
  1458. if FShowLines <> Value then
  1459. begin
  1460. FShowLines := Value;
  1461. Invalidate;
  1462. end;
  1463. end;
  1464. procedure TNewCheckListBox.SetSubItem(Index: Integer; const ASubItem: String);
  1465. var
  1466. OldHeight, NewHeight: Integer;
  1467. R, R2: TRect;
  1468. begin
  1469. if ItemStates[Index].SubItem <> ASubItem then
  1470. begin
  1471. ItemStates[Index].SubItem := ASubItem;
  1472. OldHeight := SendMessage(Handle, LB_GETITEMHEIGHT, Index, 0);
  1473. NewHeight := RemeasureItem(Index);
  1474. R := ItemRect(Index);
  1475. { Scroll subsequent items down or up, if necessary }
  1476. if NewHeight <> OldHeight then begin
  1477. if Index >= TopIndex then begin
  1478. R2 := ClientRect;
  1479. R2.Top := R.Top + OldHeight;
  1480. if not IsRectEmpty(R2) then
  1481. ScrollWindowEx(Handle, 0, NewHeight - OldHeight, @R2, nil, 0, nil,
  1482. SW_INVALIDATE or SW_ERASE);
  1483. end;
  1484. UpdateScrollRange;
  1485. end;
  1486. InvalidateRect(Handle, @R, True);
  1487. end;
  1488. end;
  1489. procedure TNewCheckListBox.SetSubItemFontStyle(Index: Integer; const ASubItemFontStyle: TFontStyles);
  1490. var
  1491. R: TRect;
  1492. begin
  1493. if ItemStates[Index].SubItemFontStyle <> ASubItemFontStyle then begin
  1494. ItemStates[Index].SubItemFontStyle := ASubItemFontStyle;
  1495. R := ItemRect(Index);
  1496. InvalidateRect(Handle, @R, True);
  1497. end;
  1498. end;
  1499. procedure TNewCheckListBox.Toggle(Index: Integer);
  1500. begin
  1501. case ItemStates[Index].ItemType of
  1502. itCheck:
  1503. case ItemStates[Index].State of
  1504. cbUnchecked: CheckItem(Index, coCheckWithChildren);
  1505. cbChecked: CheckItem(Index, coUncheck);
  1506. cbGrayed:
  1507. { First try checking, but if that doesn't work because of children
  1508. that are disabled and unchecked, try unchecking }
  1509. if not CheckItem(Index, coCheckWithChildren) then
  1510. CheckItem(Index, coUncheck);
  1511. end;
  1512. itRadio: CheckItem(Index, coCheckWithChildren);
  1513. end;
  1514. if Assigned(FOnClickCheck) then
  1515. FOnClickCheck(Self);
  1516. end;
  1517. procedure TNewCheckListBox.UpdateThreads;
  1518. function LastImmediateChildOf(Item: Integer): Integer;
  1519. var
  1520. L: Integer;
  1521. begin
  1522. Result := -1;
  1523. L := ItemLevel[Item] + 1;
  1524. Inc(Item);
  1525. while (Item < Items.Count) and (ItemLevel[Item] >= L) do
  1526. begin
  1527. if ItemLevel[Item] = L then
  1528. Result := Item;
  1529. Inc(Item);
  1530. end;
  1531. if Result >= 0 then
  1532. ItemStates[Result].IsLastChild := True;
  1533. end;
  1534. var
  1535. I, J, LastChild, L: Integer;
  1536. begin
  1537. for I := 0 to Items.Count - 1 do
  1538. begin
  1539. ItemStates[I].ThreadCache := [0]; //Doing ':= []' causes a "F2084 Internal Error: C21846" compiler error on Delphi 10.3 Rio }
  1540. Exclude(ItemStates[I].ThreadCache, 0); //
  1541. ItemStates[I].IsLastChild := False;
  1542. end;
  1543. for I := 0 to Items.Count - 1 do
  1544. begin
  1545. LastChild := LastImmediateChildOf(I);
  1546. L := ItemLevel[I];
  1547. for J := I + 1 to LastChild do
  1548. Include(ItemStates[J].ThreadCache, L);
  1549. end;
  1550. end;
  1551. procedure TNewCheckListBox.LBDeleteString(var Message: TMessage);
  1552. var
  1553. I: Integer;
  1554. ItemState: TItemState;
  1555. begin
  1556. inherited;
  1557. if FDisableItemStateDeletion = 0 then begin
  1558. I := Message.WParam;
  1559. if (I >= 0) and (I < FStateList.Count) then begin
  1560. ItemState := FStateList[I];
  1561. FStateList.Delete(I);
  1562. ItemState.Free;
  1563. end;
  1564. end;
  1565. end;
  1566. procedure TNewCheckListBox.LBResetContent(var Message: TMessage);
  1567. var
  1568. I: Integer;
  1569. ItemState: TItemState;
  1570. begin
  1571. inherited;
  1572. if FDisableItemStateDeletion = 0 then
  1573. for I := FStateList.Count-1 downto 0 do begin
  1574. ItemState := FStateList[I];
  1575. FStateList.Delete(I);
  1576. ItemState.Free;
  1577. end;
  1578. end;
  1579. procedure TNewCheckListBox.WMGetDlgCode(var Message: TWMGetDlgCode);
  1580. begin
  1581. inherited;
  1582. if FWantTabs then
  1583. Message.Result := Message.Result and not DLGC_WANTCHARS;
  1584. end;
  1585. procedure TNewCheckListBox.WMKeyDown(var Message: TWMKeyDown);
  1586. var
  1587. GoForward, Arrows: Boolean;
  1588. I: Integer;
  1589. Prnt, Ctrl: TWinControl;
  1590. begin
  1591. { If space is pressed, avoid flickering -- exit now. }
  1592. if not FWantTabs or (Message.CharCode = VK_SPACE) then
  1593. begin
  1594. inherited;
  1595. Exit;
  1596. end;
  1597. Arrows := True;
  1598. case Message.CharCode of
  1599. VK_TAB:
  1600. begin
  1601. GoForward := GetKeyState(VK_SHIFT) >= 0;
  1602. Arrows := False
  1603. end;
  1604. VK_DOWN, VK_RIGHT: GoForward := True;
  1605. VK_UP, VK_LEFT: GoForward := False
  1606. else
  1607. if FSpaceDown then EndCapture(True);
  1608. inherited;
  1609. Exit;
  1610. end;
  1611. EndCapture(not FSpaceDown);
  1612. SendMessage(Handle, WM_CHANGEUISTATE, UIS_CLEAR or (UISF_HIDEFOCUS shl 16), 0);
  1613. if Arrows or TabStop then
  1614. I := FindNextItem(-2, GoForward, not Arrows)
  1615. else
  1616. I := -1;
  1617. if I < 0 then
  1618. begin
  1619. Prnt := nil;
  1620. if not Arrows then
  1621. Prnt := GetParentForm(Self);
  1622. if Prnt = nil then Prnt := Parent;
  1623. if Prnt <> nil then
  1624. begin
  1625. Ctrl := TWinControlAccess(Prnt).FindNextControl(Self, GoForward, True, Arrows);
  1626. if (Ctrl <> nil) and (Ctrl <> Self) then
  1627. begin
  1628. Ctrl.SetFocus;
  1629. Exit;
  1630. end;
  1631. end;
  1632. if GoForward then
  1633. I := FindNextItem(-1, True, not Arrows)
  1634. else
  1635. I := FindNextItem(Items.Count, False, not Arrows);
  1636. end;
  1637. ItemIndex := I;
  1638. if (I <> -1) and (ItemStates[I].ItemType = itRadio) and Arrows then
  1639. Toggle(I);
  1640. end;
  1641. procedure TNewCheckListBox.WMMouseMove(var Message: TWMMouseMove);
  1642. var
  1643. Pos: TPoint;
  1644. Index, NewHotIndex: Integer;
  1645. Rect: TRect;
  1646. Indent: Integer;
  1647. begin
  1648. Pos := SmallPointToPoint(Message.Pos);
  1649. Index := ItemAtPos(Pos, True);
  1650. if FCaptureIndex >= 0 then begin
  1651. if not FSpaceDown and (Index <> FLastMouseMoveIndex) then begin
  1652. if (FLastMouseMoveIndex = FCaptureIndex) or (Index = FCaptureIndex) then
  1653. InvalidateCheck(FCaptureIndex);
  1654. FLastMouseMoveIndex := Index;
  1655. end
  1656. end;
  1657. NewHotIndex := -1;
  1658. if (Index <> -1) and CanFocusItem(Index) then
  1659. begin
  1660. Rect := ItemRect(Index);
  1661. Indent := (FOffset * 2 + FCheckWidth);
  1662. if FWantTabs or ((Pos.X >= Rect.Left + Indent * ItemLevel[Index]) and
  1663. (Pos.X < Rect.Left + Indent * (ItemLevel[Index] + 1))) then
  1664. NewHotIndex := Index;
  1665. end;
  1666. UpdateHotIndex(NewHotIndex);
  1667. end;
  1668. procedure TNewCheckListBox.WMNCHitTest(var Message: TWMNCHitTest);
  1669. var
  1670. I: Integer;
  1671. begin
  1672. inherited;
  1673. if FWantTabs and not (csDesigning in ComponentState) then
  1674. begin
  1675. if Message.Result = HTCLIENT then
  1676. begin
  1677. I := ItemAtPos(ScreenToClient(SmallPointToPoint(Message.Pos)), True);
  1678. if (I < 0) or not CanFocusItem(I) then
  1679. begin
  1680. UpdateHotIndex(-1);
  1681. Message.Result := 12345;
  1682. Exit;
  1683. end;
  1684. end;
  1685. end;
  1686. end;
  1687. procedure TNewCheckListBox.WMSetFocus(var Message: TWMSetFocus);
  1688. begin
  1689. FWheelAccum := 0;
  1690. inherited;
  1691. end;
  1692. procedure TNewCheckListBox.WMSize(var Message: TWMSize);
  1693. var
  1694. I: Integer;
  1695. begin
  1696. inherited;
  1697. { When the scroll bar appears/disappears, the client width changes and we
  1698. must recalculate the height of the items }
  1699. for I := Items.Count-1 downto 0 do
  1700. RemeasureItem(I);
  1701. UpdateScrollRange;
  1702. end;
  1703. procedure TNewCheckListBox.WMThemeChanged(var Message: TMessage);
  1704. begin
  1705. { Don't Run to Cursor into this function, it will interrupt up the theme change }
  1706. UpdateThemeData(True, True);
  1707. inherited;
  1708. end;
  1709. procedure TNewCheckListBox.WMUpdateUIState(var Message: TMessage);
  1710. begin
  1711. Invalidate;
  1712. inherited;
  1713. end;
  1714. procedure TNewCheckListBox.WMGetObject(var Message: TMessage);
  1715. begin
  1716. if (Message.LParam = Integer(OBJID_CLIENT)) and InitializeOleAcc then begin
  1717. if FAccObjectInstance = nil then begin
  1718. try
  1719. FAccObjectInstance := TAccObject.Create(Self);
  1720. except
  1721. inherited;
  1722. Exit;
  1723. end;
  1724. end;
  1725. Message.Result := LresultFromObjectFunc(IID_IAccessible, Message.WParam,
  1726. TAccObject(FAccObjectInstance));
  1727. end
  1728. else
  1729. inherited;
  1730. end;
  1731. { TAccObject }
  1732. constructor TAccObject.Create(AControl: TNewCheckListBox);
  1733. begin
  1734. inherited Create;
  1735. if CreateStdAccessibleObjectFunc(AControl.Handle, Integer(OBJID_CLIENT),
  1736. IID_IAccessible, Pointer(FStdAcc)) <> S_OK then begin
  1737. { Note: The user will never actually see this message since the call to
  1738. TAccObject.Create in TNewCheckListBox.WMGetObject is protected by a
  1739. try..except. }
  1740. raise Exception.Create('CreateStdAccessibleObject failed');
  1741. end;
  1742. FControl := AControl;
  1743. end;
  1744. destructor TAccObject.Destroy;
  1745. begin
  1746. { If FControl is assigned, then we are being destroyed before the control --
  1747. the usual case. Clear FControl's reference to us. }
  1748. if Assigned(FControl) then begin
  1749. FControl.FAccObjectInstance := nil;
  1750. FControl := nil;
  1751. end;
  1752. if Assigned(FStdAcc) then
  1753. FStdAcc.Release;
  1754. inherited;
  1755. end;
  1756. procedure TAccObject.ControlDestroying;
  1757. begin
  1758. { Set FControl to nil, since it's no longer valid }
  1759. FControl := nil;
  1760. { Take this opportunity to disconnect remote clients, i.e. don't allow them
  1761. to call us anymore. This prevents invalid memory accesses if this unit's
  1762. code is in a DLL, and the application subsequently unloads the DLL while
  1763. remote clients still hold (and are using) references to this TAccObject. }
  1764. CoDisconnectObject(Self, 0);
  1765. { NOTE: Don't access Self in any way at this point. The CoDisconnectObject
  1766. call likely caused all references to be relinquished and Self to be
  1767. destroyed. }
  1768. end;
  1769. function TAccObject.QueryInterface(const iid: TIID; var obj): HRESULT;
  1770. begin
  1771. if IsEqualIID(iid, IID_IUnknown) or
  1772. IsEqualIID(iid, IID_IDispatch) or
  1773. IsEqualIID(iid, IID_IAccessible) then begin
  1774. Pointer(obj) := Self;
  1775. AddRef;
  1776. Result := S_OK;
  1777. end
  1778. else begin
  1779. Pointer(obj) := nil;
  1780. Result := E_NOINTERFACE;
  1781. end;
  1782. end;
  1783. function TAccObject.AddRef: Longint;
  1784. begin
  1785. Inc(FRefCount);
  1786. Result := FRefCount;
  1787. end;
  1788. function TAccObject.Release: Longint;
  1789. begin
  1790. Dec(FRefCount);
  1791. Result := FRefCount;
  1792. if Result = 0 then
  1793. Destroy;
  1794. end;
  1795. function TAccObject.GetTypeInfoCount(var ctinfo: Integer): HRESULT;
  1796. begin
  1797. Result := E_NOTIMPL;
  1798. end;
  1799. function TAccObject.GetTypeInfo(itinfo: Integer; lcid: TLCID; var tinfo: ITypeInfo): HRESULT;
  1800. begin
  1801. Result := E_NOTIMPL;
  1802. end;
  1803. function TAccObject.GetIDsOfNames(const iid: TIID; rgszNames: POleStrList;
  1804. cNames: Integer; lcid: TLCID; rgdispid: PDispIDList): HRESULT;
  1805. begin
  1806. Result := E_NOTIMPL;
  1807. end;
  1808. function TAccObject.Invoke(dispIDMember: TDispID; const iid: TIID; lcid: TLCID;
  1809. flags: Word; var dispParams: TDispParams; varResult: PVariant;
  1810. excepInfo: PExcepInfo; argErr: PInteger): HRESULT;
  1811. begin
  1812. Result := E_NOTIMPL;
  1813. end;
  1814. function TAccObject.accDoDefaultAction(varChild: NewOleVariant): HRESULT;
  1815. begin
  1816. { A list box's default action is Double Click, which is useless for a
  1817. list of check boxes. }
  1818. Result := DISP_E_MEMBERNOTFOUND;
  1819. end;
  1820. function TAccObject.accHitTest(xLeft, yTop: Integer;
  1821. var pvarID: NewOleVariant): HRESULT;
  1822. begin
  1823. Result := FStdAcc.accHitTest(xLeft, yTop, pvarID);
  1824. end;
  1825. function TAccObject.accLocation(var pxLeft, pyTop, pcxWidth,
  1826. pcyHeight: Integer; varChild: NewOleVariant): HRESULT;
  1827. begin
  1828. Result := FStdAcc.accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varChild);
  1829. end;
  1830. function TAccObject.accNavigate(navDir: Integer; varStart: NewOleVariant;
  1831. var pvarEnd: NewOleVariant): HRESULT;
  1832. begin
  1833. Result := FStdAcc.accNavigate(navDir, varStart, pvarEnd);
  1834. end;
  1835. function TAccObject.accSelect(flagsSelect: Integer;
  1836. varChild: NewOleVariant): HRESULT;
  1837. begin
  1838. Result := FStdAcc.accSelect(flagsSelect, varChild);
  1839. end;
  1840. function TAccObject.get_accChild(varChild: NewOleVariant;
  1841. var ppdispChild: IDispatch): HRESULT;
  1842. begin
  1843. Result := FStdAcc.get_accChild(varChild, ppdispChild);
  1844. end;
  1845. function TAccObject.get_accChildCount(var pcountChildren: Integer): HRESULT;
  1846. begin
  1847. Result := FStdAcc.get_accChildCount(pcountChildren);
  1848. end;
  1849. function TAccObject.get_accDefaultAction(varChild: NewOleVariant;
  1850. var pszDefaultAction: NewWideString): HRESULT;
  1851. begin
  1852. { A list box's default action is Double Click, which is useless for a
  1853. list of check boxes. }
  1854. pszDefaultAction := nil;
  1855. Result := S_FALSE;
  1856. end;
  1857. function TAccObject.get_accDescription(varChild: NewOleVariant;
  1858. var pszDescription: NewWideString): HRESULT;
  1859. begin
  1860. Result := FStdAcc.get_accDescription(varChild, pszDescription);
  1861. end;
  1862. function TAccObject.get_accFocus(var pvarID: NewOleVariant): HRESULT;
  1863. begin
  1864. Result := FStdAcc.get_accFocus(pvarID);
  1865. end;
  1866. function TAccObject.get_accHelp(varChild: NewOleVariant;
  1867. var pszHelp: NewWideString): HRESULT;
  1868. begin
  1869. Result := FStdAcc.get_accHelp(varChild, pszHelp);
  1870. end;
  1871. function TAccObject.get_accHelpTopic(var pszHelpFile: NewWideString;
  1872. varChild: NewOleVariant; var pidTopic: Integer): HRESULT;
  1873. begin
  1874. Result := FStdAcc.get_accHelpTopic(pszHelpFile, varChild, pidTopic);
  1875. end;
  1876. function TAccObject.get_accKeyboardShortcut(varChild: NewOleVariant;
  1877. var pszKeyboardShortcut: NewWideString): HRESULT;
  1878. begin
  1879. Result := FStdAcc.get_accKeyboardShortcut(varChild, pszKeyboardShortcut);
  1880. end;
  1881. function TAccObject.get_accName(varChild: NewOleVariant;
  1882. var pszName: NewWideString): HRESULT;
  1883. begin
  1884. Result := FStdAcc.get_accName(varChild, pszName);
  1885. end;
  1886. function TAccObject.get_accParent(var ppdispParent: IDispatch): HRESULT;
  1887. begin
  1888. Result := FStdAcc.get_accParent(ppdispParent);
  1889. end;
  1890. function TAccObject.get_accRole(varChild: NewOleVariant;
  1891. var pvarRole: NewOleVariant): HRESULT;
  1892. begin
  1893. pvarRole.vt := VT_EMPTY;
  1894. if FControl = nil then begin
  1895. Result := E_FAIL;
  1896. Exit;
  1897. end;
  1898. if varChild.vt <> VT_I4 then begin
  1899. Result := E_INVALIDARG;
  1900. Exit;
  1901. end;
  1902. if varChild.lVal = CHILDID_SELF then begin
  1903. pvarRole.lVal := ROLE_SYSTEM_OUTLINE;
  1904. pvarRole.vt := VT_I4;
  1905. Result := S_OK;
  1906. end
  1907. else begin
  1908. try
  1909. case FControl.ItemStates[varChild.lVal-1].ItemType of
  1910. itCheck: pvarRole.lVal := ROLE_SYSTEM_CHECKBUTTON;
  1911. itRadio: pvarRole.lVal := ROLE_SYSTEM_RADIOBUTTON;
  1912. else
  1913. pvarRole.lVal := ROLE_SYSTEM_STATICTEXT;
  1914. end;
  1915. pvarRole.vt := VT_I4;
  1916. Result := S_OK;
  1917. except
  1918. Result := E_INVALIDARG;
  1919. end;
  1920. end;
  1921. end;
  1922. function TAccObject.get_accSelection(var pvarChildren: NewOleVariant): HRESULT;
  1923. begin
  1924. Result := FStdAcc.get_accSelection(pvarChildren);
  1925. end;
  1926. function TAccObject.get_accState(varChild: NewOleVariant;
  1927. var pvarState: NewOleVariant): HRESULT;
  1928. var
  1929. ItemState: TItemState;
  1930. begin
  1931. Result := FStdAcc.get_accState(varChild, pvarState);
  1932. try
  1933. if (Result = S_OK) and (varChild.vt = VT_I4) and
  1934. (varChild.lVal <> CHILDID_SELF) and (pvarState.vt = VT_I4) and
  1935. Assigned(FControl) then begin
  1936. ItemState := FControl.ItemStates[varChild.lVal-1];
  1937. case ItemState.State of
  1938. cbChecked: pvarState.lVal := pvarState.lVal or STATE_SYSTEM_CHECKED;
  1939. cbGrayed: pvarState.lVal := pvarState.lVal or STATE_SYSTEM_MIXED;
  1940. end;
  1941. if not ItemState.Enabled then
  1942. pvarState.lVal := pvarState.lVal or STATE_SYSTEM_UNAVAILABLE;
  1943. end;
  1944. except
  1945. Result := E_INVALIDARG;
  1946. end;
  1947. end;
  1948. function TAccObject.get_accValue(varChild: NewOleVariant;
  1949. var pszValue: NewWideString): HRESULT;
  1950. begin
  1951. pszValue := nil;
  1952. if FControl = nil then begin
  1953. Result := E_FAIL;
  1954. Exit;
  1955. end;
  1956. if varChild.vt <> VT_I4 then begin
  1957. Result := E_INVALIDARG;
  1958. Exit;
  1959. end;
  1960. if varChild.lVal = CHILDID_SELF then
  1961. Result := S_FALSE
  1962. else begin
  1963. { Return the level as the value, like standard tree view controls do.
  1964. Not sure if any screen readers will actually use this, seeing as we
  1965. aren't a real tree view control. }
  1966. try
  1967. pszValue := StringToOleStr(IntToStr(FControl.ItemStates[varChild.lVal-1].Level));
  1968. Result := S_OK;
  1969. except
  1970. Result := E_INVALIDARG;
  1971. end;
  1972. end;
  1973. end;
  1974. function TAccObject.put_accName(varChild: NewOleVariant;
  1975. const pszName: NewWideString): HRESULT;
  1976. begin
  1977. Result := S_FALSE;
  1978. end;
  1979. function TAccObject.put_accValue(varChild: NewOleVariant;
  1980. const pszValue: NewWideString): HRESULT;
  1981. begin
  1982. Result := S_FALSE;
  1983. end;
  1984. procedure Register;
  1985. begin
  1986. RegisterComponents('JR', [TNewCheckListBox]);
  1987. end;
  1988. { Note: This COM initialization code based on code from DBTables }
  1989. var
  1990. SaveInitProc: Pointer;
  1991. NeedToUninitialize: Boolean;
  1992. procedure InitCOM;
  1993. begin
  1994. if SaveInitProc <> nil then TProcedure(SaveInitProc);
  1995. NeedToUninitialize := SUCCEEDED(CoInitialize(nil));
  1996. end;
  1997. initialization
  1998. if not IsLibrary then begin
  1999. SaveInitProc := InitProc;
  2000. InitProc := @InitCOM;
  2001. end;
  2002. InitThemeLibrary;
  2003. NotifyWinEventFunc := GetProcAddress(GetModuleHandle(user32), 'NotifyWinEvent');
  2004. finalization
  2005. if NeedToUninitialize then
  2006. CoUninitialize;
  2007. end.