CnSkinTheme.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. {******************************************************************************}
  2. { CnPack For Delphi/C++Builder }
  3. { 中国人自己的开放源码第三方开发包 }
  4. { (C)Copyright 2001-2018 CnPack 开发组 }
  5. { ------------------------------------ }
  6. { }
  7. { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
  8. { 改和重新发布这一程序。 }
  9. { }
  10. { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
  11. { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
  12. { }
  13. { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
  14. { 还没有,可访问我们的网站: }
  15. { }
  16. { 网站地址:http://www.cnpack.org }
  17. { 电子邮件:master@cnpack.org }
  18. { }
  19. {******************************************************************************}
  20. unit CnSkinTheme;
  21. interface
  22. uses
  23. Windows, Messages, Classes, SysUtils, Graphics, Forms, Controls,
  24. CnSkinStyle;
  25. const
  26. CM_THEMECHANGE = CM_BASE + $CE0;
  27. SBSIZE = 17;
  28. {$EXTERNALSYM COLOR_MENUHILIGHT}
  29. COLOR_MENUHILIGHT = 29;
  30. {$EXTERNALSYM COLOR_MENUBAR}
  31. COLOR_MENUBAR = 30;
  32. clSystemColor = $FF000000;
  33. clMenuHighlight = TColor(clSystemColor or COLOR_MENUHILIGHT);
  34. clMenuBar = TColor(clSystemColor or COLOR_MENUBAR);
  35. type
  36. TScrollBarButton = (sbNone, sbUp, sbDown, sbLeft, sbRight, sbButton, sbButtonH);
  37. TCnSkinThemes = class(TObject)
  38. private
  39. FSkins: TList;
  40. FControls: TList;
  41. FOldSkinIndex: Integer;
  42. FSkinIndex: Integer;
  43. FCurrentSkin: TCnSkinStyle;
  44. FActive: Boolean;
  45. function GetSkinCount: Integer;
  46. procedure SetSkinIndex(const Value: Integer);
  47. function GetSkins(Index: Integer): TCnSkinStyle;
  48. procedure SetActive(const Value: Boolean);
  49. protected
  50. procedure LoadStyle(Skin: TCnSkinStyle);
  51. public
  52. constructor Create; virtual;
  53. {* 构造函数}
  54. destructor Destroy; override;
  55. {* 析构函数}
  56. procedure AddSkin(Skin: TCnSkinStyle);
  57. {* 添加一个 SkinStyle 到列表中,一般不需直接调用}
  58. procedure RemoveSkin(Skin: TCnSkinStyle);
  59. {* 从列表中删除一个 SkinStyle,一般不需直接调用}
  60. property Active: Boolean read FActive write SetActive;
  61. {* 是否使能皮肤效果}
  62. property Controls: TList read FControls;
  63. {* 所有 CnSkin 界面组件的实例列表,供通知之用}
  64. property SkinCount: Integer read GetSkinCount;
  65. {* 已记录的 SkinStyle 的数量}
  66. property SkinIndex: Integer read FSkinIndex write SetSkinIndex;
  67. {* 当前 SkinStyle 的索引号,从 0 到 SkinCount - 1}
  68. property Skins[Index: Integer]: TCnSkinStyle read GetSkins;
  69. {* 已记录的 SkinStyle 列表}
  70. property CurrentSkin: TCnSkinStyle read FCurrentSkin;
  71. {* 当前使用的 SkinStyle,是一内部实例,内容从 Skins 的当前实例复制而来}
  72. end;
  73. function CnSkinThemes: TCnSkinThemes;
  74. {* 全局函数,返回 CnSkinThemes 的实例}
  75. function CnGetScrollInfo(Control: TWinControl; I: Integer; var I1, I2: Integer;
  76. Kind: TScrollBarKind): Boolean;
  77. procedure CnDrawScrollBar(Canvas: TCanvas; R: TRect; I1, I2: Integer;
  78. Over, Down: TScrollBarButton; Kind: TScrollBarKind; Enabled: Boolean);
  79. function CnGetScrollCount(Control: TWinControl; Button: TScrollBarButton;
  80. I, Pos: Integer; Kind: TScrollBarKind): Integer;
  81. implementation
  82. var
  83. FCnSkinThemes: TCnSkinThemes;
  84. function CnSkinThemes: TCnSkinThemes;
  85. begin
  86. Result := FCnSkinThemes;
  87. end;
  88. { TCnSkinThemes }
  89. procedure TCnSkinThemes.AddSkin(Skin: TCnSkinStyle);
  90. begin
  91. if Skin <> nil then
  92. FSkins.Add(Skin);
  93. end;
  94. constructor TCnSkinThemes.Create;
  95. begin
  96. inherited;
  97. FCnSkinThemes := Self;
  98. FControls := TList.Create;
  99. FSkins := TList.Create;
  100. FSkinIndex := -1;
  101. FCurrentSkin := TCnSkinStyle.Create(nil);
  102. FSkins.Clear; // Don't add internal store
  103. end;
  104. destructor TCnSkinThemes.Destroy;
  105. begin
  106. FCurrentSkin.Free;
  107. FControls.Free;
  108. FSkins.Free;
  109. inherited;
  110. end;
  111. function TCnSkinThemes.GetSkinCount: Integer;
  112. begin
  113. Result := FSkins.Count;
  114. end;
  115. function TCnSkinThemes.GetSkins(Index: Integer): TCnSkinStyle;
  116. begin
  117. if (Index < SkinCount) and (Index >= 0) then
  118. begin;
  119. Result := TCnSkinStyle(FSkins[Index]);
  120. end
  121. else
  122. Result := nil;
  123. end;
  124. procedure TCnSkinThemes.LoadStyle(Skin: TCnSkinStyle);
  125. begin
  126. if Skin <> nil then
  127. FCurrentSkin.Assign(Skin)
  128. else
  129. begin
  130. FCurrentSkin.Clear;
  131. FActive := False;
  132. FSkinIndex := -1;
  133. end;
  134. end;
  135. procedure TCnSkinThemes.RemoveSkin(Skin: TCnSkinStyle);
  136. begin
  137. FSkins.Remove(Skin);
  138. end;
  139. procedure TCnSkinThemes.SetActive(const Value: Boolean);
  140. var
  141. I: Integer;
  142. begin
  143. if FActive <> Value then
  144. begin
  145. FActive := Value;
  146. if not FActive then
  147. begin
  148. FOldSkinIndex := SkinIndex;
  149. SkinIndex := -1;
  150. for I := 0 to Controls.Count - 1 do
  151. TWinControl(Controls[I]).Perform(CM_THEMECHANGE, 0, 0);
  152. end
  153. else
  154. begin
  155. SkinIndex := FOldSkinIndex;
  156. end;
  157. end;
  158. end;
  159. procedure TCnSkinThemes.SetSkinIndex(const Value: Integer);
  160. var
  161. I: Integer;
  162. begin
  163. if Value <> FSkinIndex then
  164. begin
  165. FSkinIndex := Value;
  166. LoadStyle(Skins[FSkinIndex]);
  167. if Active then
  168. for I := 0 to Controls.Count - 1 do
  169. TWinControl(Controls[I]).Perform(CM_THEMECHANGE, 0, 0);
  170. end;
  171. end;
  172. { Other Routines }
  173. function CnGetScrollInfo(Control: TWinControl; I: Integer; var I1, I2: Integer;
  174. Kind: TScrollBarKind): Boolean;
  175. var
  176. ScrollInfo: TScrollInfo;
  177. Count: Integer;
  178. begin
  179. Result := False;
  180. FillChar(ScrollInfo, SizeOf(TScrollInfo), 0);
  181. ScrollInfo.cbSize := SizeOf(TScrollInfo);
  182. ScrollInfo.fMask := SIF_ALL;
  183. Windows.GetScrollInfo(Control.Handle, Ord(Kind), ScrollInfo);
  184. with ScrollInfo do
  185. begin
  186. Dec(nMax, nMin - 1);
  187. Dec(nPos, nMin);
  188. Count := nMax - Integer(nPage);
  189. if Count > 0 then
  190. begin
  191. Result := True;
  192. Dec(I, SBSIZE + SBSIZE);
  193. I2 := I - I * Count div nMax;
  194. if I2 < 10 then I2 := 10;
  195. Inc(I1, (I - I2) * nPos div Count);
  196. end;
  197. end;
  198. end;
  199. procedure CnDrawScrollBar(Canvas: TCanvas; R: TRect; I1, I2: Integer;
  200. Over, Down: TScrollBarButton; Kind: TScrollBarKind; Enabled: Boolean);
  201. var
  202. SrcR, DestR: TRect;
  203. SrcW, DestW, Offset, W: Integer;
  204. function GetSrcR(Button: TScrollBarButton): TRect;
  205. begin
  206. Result := Rect(0, 0, SrcW, SrcW);
  207. Offset := 0;
  208. if not Enabled then
  209. Offset := SrcW * 3 else
  210. if Over = Button then
  211. begin
  212. Inc(Offset, SrcW);
  213. if Down = Button then Inc(Offset, SrcW);
  214. end;
  215. OffsetRect(Result, 0, Offset);
  216. end;
  217. function GetSrcR2(Button: TScrollBarButton): TRect;
  218. begin
  219. Result := Rect(0, 0, SrcW, SrcW);
  220. Offset := 5 + Ord(Button);
  221. if not Enabled then Inc(Offset, 4);
  222. OffsetRect(Result, 0, Offset * SrcW);
  223. end;
  224. begin
  225. Canvas.Brush.Style := bsClear;
  226. SrcW := CnSkinThemes.CurrentSkin.ScrollBarBmp.Width;
  227. if Kind = sbHorizontal then
  228. begin
  229. DestW := R.Bottom - R.Top;
  230. DestR := R;
  231. DestR.Right := R.Left + DestW;
  232. Canvas.CopyRect(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp.Canvas, GetSrcR(sbLeft));
  233. Canvas.BrushCopy(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp, GetSrcR2(sbLeft), clFuchsia);
  234. DestR := R;
  235. DestR.Left := DestR.Right - DestW;
  236. Canvas.CopyRect(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp.Canvas, GetSrcR(sbRight));
  237. Canvas.BrushCopy(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp, GetSrcR2(sbRight), clFuchsia);
  238. DestR.Right := DestR.Left;
  239. DestR.Left := R.Left + DestW;
  240. SrcR := Rect(0, 0, SrcW, SrcW);
  241. OffsetRect(SrcR, 0, 5 * SrcW);
  242. Canvas.CopyRect(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp.Canvas, SrcR);
  243. if Enabled then
  244. begin
  245. SrcR := GetSrcR(sbButton);
  246. W := SrcW div 3;
  247. SrcR.Right := W;
  248. DestR.Left := I1;
  249. DestR.Right := DestR.Left + W;
  250. Canvas.CopyRect(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp.Canvas, SrcR);
  251. DestR.Right := I1 + I2;
  252. DestR.Left := DestR.Right - W;
  253. OffsetRect(SrcR, W + W, 0);
  254. Canvas.CopyRect(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp.Canvas, SrcR);
  255. if I2 > W + W then
  256. begin
  257. DestR.Right := DestR.Left;
  258. DestR.Left := I1 + W;
  259. OffsetRect(SrcR, - W, 0);
  260. Canvas.CopyRect(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp.Canvas, SrcR);
  261. if I2 > DestW then
  262. begin
  263. SrcR := Rect(0, 0, SrcW, SrcW);
  264. OffsetRect(SrcR, 0, 15 * SrcW);
  265. DestR.Left := I1 + (I2 - SrcW) div 2;
  266. DestR.Top := R.Top + (DestW - SrcW) div 2;
  267. DestR.Right := DestR.Left + SrcW;
  268. DestR.Bottom := DestR.Top + SrcW;
  269. Canvas.BrushCopy(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp, SrcR, clFuchsia);
  270. end;
  271. end;
  272. end;
  273. end
  274. else
  275. begin
  276. DestW := R.Right - R.Left;
  277. DestR := R;
  278. DestR.Bottom := R.Top + DestW;
  279. Canvas.CopyRect(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp.Canvas, GetSrcR(sbUp));
  280. Canvas.BrushCopy(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp, GetSrcR2(sbUp), clFuchsia);
  281. DestR := R;
  282. DestR.Top := DestR.Bottom - DestW;
  283. Canvas.CopyRect(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp.Canvas, GetSrcR(sbDown));
  284. Canvas.BrushCopy(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp, GetSrcR2(sbDown), clFuchsia);
  285. DestR.Bottom := DestR.Top;
  286. DestR.Top := R.Top + DestW;
  287. SrcR := Rect(0, 0, SrcW, SrcW);
  288. OffsetRect(SrcR, 0, 4 * SrcW);
  289. Canvas.CopyRect(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp.Canvas, SrcR);
  290. if Enabled then
  291. begin
  292. SrcR := GetSrcR(sbButton);
  293. W := SrcW div 3;
  294. SrcR.Bottom := SrcR.Top + W;
  295. DestR.Top := I1;
  296. DestR.Bottom := DestR.Top + W;
  297. Canvas.CopyRect(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp.Canvas, SrcR);
  298. DestR.Bottom := I1 + I2;
  299. DestR.Top := DestR.Bottom - W;
  300. OffsetRect(SrcR, 0, W + W);
  301. Canvas.CopyRect(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp.Canvas, SrcR);
  302. if I2 > W + W then
  303. begin
  304. DestR.Bottom := DestR.Top;
  305. DestR.Top := I1 + W;
  306. OffsetRect(SrcR, 0, - W);
  307. Canvas.CopyRect(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp.Canvas, SrcR);
  308. if I2 > DestW then
  309. begin
  310. SrcR := Rect(0, 0, SrcW, SrcW);
  311. OffsetRect(SrcR, 0, 14 * SrcW);
  312. DestR.Top := I1 + (I2 - SrcW) div 2;
  313. DestR.Left := R.Left + (DestW - SrcW) div 2;
  314. DestR.Bottom := DestR.Top + SrcW;
  315. DestR.Right := DestR.Left + SrcW;
  316. Canvas.BrushCopy(DestR, CnSkinThemes.CurrentSkin.ScrollBarBmp, SrcR, clFuchsia);
  317. end;
  318. end;
  319. end;
  320. end;
  321. end;
  322. function CnGetScrollCount(Control: TWinControl; Button: TScrollBarButton;
  323. I, Pos: Integer; Kind: TScrollBarKind): Integer;
  324. var
  325. ScrollInfo: TScrollInfo;
  326. NewPos, Count, I2: Integer;
  327. begin
  328. Result := 0;
  329. FillChar(ScrollInfo, SizeOf(TScrollInfo), 0);
  330. ScrollInfo.cbSize := SizeOf(TScrollInfo);
  331. ScrollInfo.fMask := SIF_ALL;
  332. Windows.GetScrollInfo(Control.Handle, Ord(Kind), ScrollInfo);
  333. with ScrollInfo do
  334. begin
  335. NewPos := nPos;
  336. Count := nMax - Integer(nPage);
  337. Dec(nMax, nMin - 1);
  338. Dec(nPos, nMin);
  339. case Button of
  340. sbUp, sbLeft: if nPos > 0 then Dec(NewPos);
  341. sbDOwn, sbRight: if nPos <= Count then Inc(NewPos);
  342. sbNone, sbButton:
  343. begin
  344. Dec(I, SBSIZE + SBSIZE);
  345. I2 := I - I * Count div nMax;
  346. if I2 < 10 then I2 := 10;
  347. Dec(Pos, SBSIZE);
  348. NewPos := Pos * Count div (I - I2 div 2);
  349. if NewPos < 0 then
  350. NewPos := 0 else
  351. if NewPos > Count + 1 then NewPos := Count + 1;
  352. end;
  353. end;
  354. if NewPos <> nPos then Result := NewPos - nPos;
  355. end;
  356. end;
  357. initialization
  358. FCnSkinThemes := TCnSkinThemes.Create;
  359. finalization
  360. FreeAndNil(FCnSkinThemes);
  361. end.