VCLCommon.cpp 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include "WinInterface.h"
  5. #include "VCLCommon.h"
  6. #include <Common.h>
  7. #include <TextsWin.h>
  8. #include <RemoteFiles.h>
  9. #include <GUITools.h>
  10. #include <Tools.h>
  11. #include <FileCtrl.hpp>
  12. #include <ThemeMgr.hpp>
  13. #include <PathLabel.hpp>
  14. #include <PasTools.hpp>
  15. //---------------------------------------------------------------------------
  16. #pragma package(smart_init)
  17. //---------------------------------------------------------------------------
  18. static TThemeManager * ThemeManager = NULL;
  19. //---------------------------------------------------------------------------
  20. void __fastcall AdjustListColumnsWidth(TListView* ListView, int RowCount, int RightPad)
  21. {
  22. int OriginalWidth, NewWidth, i, CWidth, LastResizible;
  23. OriginalWidth = 0;
  24. LastResizible = -1;
  25. for (i = 0; i < ListView->Columns->Count; i++)
  26. {
  27. OriginalWidth += ListView->Columns->Items[i]->Width;
  28. if (ListView->Columns->Items[i]->Tag == 0)
  29. {
  30. LastResizible = i;
  31. }
  32. }
  33. assert(LastResizible >= 0);
  34. // when listview is virtual, ListView->Items->Count seems to return invalid
  35. // value, thus provide a method to pass actual count explicitly
  36. if (RowCount < 0)
  37. {
  38. RowCount = ListView->Items->Count;
  39. }
  40. NewWidth = 0;
  41. CWidth = ListView->ClientWidth - RightPad;
  42. if ((ListView->VisibleRowCount < RowCount) &&
  43. (ListView->Width - ListView->ClientWidth < GetSystemMetrics(SM_CXVSCROLL)))
  44. {
  45. CWidth -= GetSystemMetrics(SM_CXVSCROLL);
  46. }
  47. for (i = 0; i < ListView->Columns->Count; i++)
  48. {
  49. if (i != LastResizible)
  50. {
  51. if (ListView->Columns->Items[i]->Tag == 0)
  52. {
  53. ListView->Columns->Items[i]->Width =
  54. (CWidth * ListView->Columns->Items[i]->Width) / OriginalWidth;
  55. }
  56. NewWidth += ListView->Columns->Items[i]->Width;
  57. }
  58. }
  59. ListView->Columns->Items[LastResizible]->Width = CWidth-NewWidth;
  60. }
  61. //---------------------------------------------------------------------------
  62. static void __fastcall SetParentColor(TControl * Control)
  63. {
  64. TColor Color;
  65. assert(ThemeManager != NULL);
  66. if (ThemeManager->ThemesEnabled)
  67. {
  68. bool OnTabSheet = false;
  69. TWinControl * Parent = Control->Parent;
  70. while ((Parent != NULL) && !OnTabSheet)
  71. {
  72. TTabSheet * TabSheet = dynamic_cast<TTabSheet *>(Parent);
  73. OnTabSheet = (TabSheet != NULL) && TabSheet->TabVisible;
  74. Parent = Parent->Parent;
  75. }
  76. if (OnTabSheet)
  77. {
  78. Color = ThemeManager->GetColor(teTab, ::TABP_BODY, 0, ::TMT_FILLCOLORHINT);
  79. }
  80. else
  81. {
  82. Color = ThemeManager->GetColor(teWindow, ::WP_DIALOG, 0, ::TMT_FILLCOLOR);
  83. }
  84. }
  85. else
  86. {
  87. Color = clBtnFace;
  88. }
  89. ((TEdit*)Control)->Color = Color;
  90. }
  91. //---------------------------------------------------------------------------
  92. void __fastcall EnableControl(TControl * Control, bool Enable)
  93. {
  94. if (Control->Enabled != Enable)
  95. {
  96. if (Control->InheritsFrom(__classid(TWinControl)) &&
  97. (((TWinControl*)Control)->ControlCount > 0))
  98. {
  99. for (Integer Index = 0; Index < ((TWinControl*)Control)->ControlCount; Index++)
  100. EnableControl(((TWinControl*)Control)->Controls[Index], Enable);
  101. }
  102. Control->Enabled = Enable;
  103. }
  104. if (Control->InheritsFrom(__classid(TCustomEdit)) ||
  105. Control->InheritsFrom(__classid(TCustomComboBox)) ||
  106. Control->InheritsFrom(__classid(TCustomListView)))
  107. {
  108. if (Enable)
  109. {
  110. ((TEdit*)Control)->Color = clWindow;
  111. }
  112. else
  113. {
  114. ((TEdit*)Control)->Color = clBtnFace;
  115. }
  116. }
  117. };
  118. //---------------------------------------------------------------------------
  119. void __fastcall ReadOnlyControl(TControl * Control, bool ReadOnly)
  120. {
  121. if (Control->InheritsFrom(__classid(TCustomEdit)))
  122. {
  123. ((TEdit*)Control)->ReadOnly = ReadOnly;
  124. if (ReadOnly)
  125. {
  126. SetParentColor(Control);
  127. }
  128. else
  129. {
  130. ((TEdit*)Control)->Color = clWindow;
  131. }
  132. }
  133. else
  134. {
  135. assert(false);
  136. }
  137. }
  138. //---------------------------------------------------------------------------
  139. struct TSavedSystemSettings
  140. {
  141. TCustomForm * Form;
  142. AnsiString FontName;
  143. bool Flipped;
  144. TWndMethod OldWndProc;
  145. };
  146. //---------------------------------------------------------------------------
  147. static void __fastcall ThemeManagerAllowSubclassing(void * /*Data*/,
  148. TThemeManager * /*Sender*/, TControl * Control, bool & Allow)
  149. {
  150. TPathLabel * PathLabel = dynamic_cast<TPathLabel *>(Control);
  151. // intent is to only exclude path labels on the main window
  152. if ((PathLabel != NULL) && (PathLabel->FocusControl != NULL))
  153. {
  154. Allow = false;
  155. }
  156. }
  157. //---------------------------------------------------------------------------
  158. class TPublicControl : public TWinControl
  159. {
  160. friend TWndMethod __fastcall ControlWndProc(TWinControl * Control);
  161. };
  162. //---------------------------------------------------------------------------
  163. TWndMethod __fastcall ControlWndProc(TWinControl * Control)
  164. {
  165. TPublicControl * PublicControl = static_cast<TPublicControl *>(Control);
  166. return &PublicControl->WndProc;
  167. }
  168. //---------------------------------------------------------------------------
  169. static TMonitor * LastMonitor = NULL;
  170. //---------------------------------------------------------------------------
  171. inline void __fastcall DoFormWindowProc(TCustomForm * Form, TWndMethod WndProc,
  172. TMessage & Message)
  173. {
  174. if ((Message.Msg == WM_SYSCOMMAND) &&
  175. (Message.WParam == SC_CONTEXTHELP))
  176. {
  177. InvokeHelp(Form->ActiveControl);
  178. Message.Result = 1;
  179. }
  180. else if (Message.Msg == CM_SHOWINGCHANGED)
  181. {
  182. TForm * AForm = dynamic_cast<TForm *>(Form);
  183. assert(AForm != NULL);
  184. if ((Application->MainForm == Form) ||
  185. // this particularly happens if error occurs while main
  186. // window is being shown (e.g. non existent local directory when opening
  187. // explorer)
  188. ((Application->MainForm != NULL) && !Application->MainForm->Visible))
  189. {
  190. if (!Form->Showing)
  191. {
  192. // when closing main form, remember its monitor,
  193. // so that the next form is shown on the same one
  194. LastMonitor = Form->Monitor;
  195. }
  196. else if ((LastMonitor != NULL) && (LastMonitor != Form->Monitor) &&
  197. Form->Showing)
  198. {
  199. // would actually always be poScreenCenter, see _SafeFormCreate
  200. if ((AForm->Position == poMainFormCenter) ||
  201. (AForm->Position == poScreenCenter))
  202. {
  203. // this would typically be an authentication dialog,
  204. // but it may as well be an message box
  205. // taken from TCustomForm::SetWindowToMonitor
  206. AForm->SetBounds(LastMonitor->Left + ((LastMonitor->Width - AForm->Width) / 2),
  207. LastMonitor->Top + ((LastMonitor->Height - AForm->Height) / 2),
  208. AForm->Width, AForm->Height);
  209. AForm->Position = poDesigned;
  210. }
  211. else if ((AForm->Position != poDesigned) &&
  212. (AForm->Position != poDefaultPosOnly))
  213. {
  214. // we do not expect any other positioning
  215. assert(false);
  216. }
  217. }
  218. else
  219. {
  220. TForm * AForm = dynamic_cast<TForm *>(Form);
  221. assert(AForm != NULL);
  222. // otherwise it would not get centered
  223. if (AForm->Position == poMainFormCenter)
  224. {
  225. AForm->Position = poScreenCenter;
  226. }
  227. }
  228. }
  229. bool WasMainFormCenter = (AForm->Position == poMainFormCenter);
  230. WndProc(Message);
  231. // Make sure dialogs are shown on-screen even if center of the main window
  232. // is off-screen. Occurs e.g. if you move the main window so that
  233. // only window title is visible above taksbar.
  234. if (Form->Showing && WasMainFormCenter && (AForm->Position == poDesigned))
  235. {
  236. TRect Rect;
  237. // Reading Form.Left/Form.Top instead here does not work, likely due to some
  238. // bug, when querying TProgressForm opened from TEditorForm (reloading remote file)
  239. GetWindowRect(Form->Handle, &Rect);
  240. int Left = Rect.Left;
  241. int Top = Rect.Top;
  242. TRect WorkArea = AForm->Monitor->WorkareaRect;
  243. if (Left + Rect.Width() > WorkArea.Right)
  244. {
  245. Left = WorkArea.Right - Rect.Width();
  246. }
  247. if (Left < WorkArea.Left)
  248. {
  249. Left = WorkArea.Left;
  250. }
  251. if (Top + Rect.Height() > WorkArea.Bottom)
  252. {
  253. Top = WorkArea.Bottom - Rect.Height();
  254. }
  255. if (Top < WorkArea.Top)
  256. {
  257. Top = WorkArea.Top;
  258. }
  259. if ((Left != Rect.Left) ||
  260. (Top != Rect.Top))
  261. {
  262. SetWindowPos(Form->Handle, 0, Left, Top, Rect.Width(), Rect.Height(),
  263. SWP_NOZORDER + SWP_NOACTIVATE);
  264. }
  265. }
  266. }
  267. else
  268. {
  269. WndProc(Message);
  270. }
  271. }
  272. //---------------------------------------------------------------------------
  273. static void __fastcall FormWindowProc(void * Data, TMessage & Message)
  274. {
  275. TCustomForm * Form = static_cast<TCustomForm *>(Data);
  276. DoFormWindowProc(Form, ControlWndProc(Form), Message);
  277. }
  278. //---------------------------------------------------------------------------
  279. static void __fastcall FormWindowProcEx(void * Data, TMessage & Message)
  280. {
  281. TSavedSystemSettings * SSettings = static_cast<TSavedSystemSettings *>(Data);
  282. DoFormWindowProc(SSettings->Form, SSettings->OldWndProc, Message);
  283. }
  284. //---------------------------------------------------------------------------
  285. void __fastcall InitializeSystemSettings()
  286. {
  287. if (ThemeManager == NULL)
  288. {
  289. ThemeManager = new TThemeManager(Application);
  290. ThemeManager->Name = "ThemeManager";
  291. // ListView subclassing breaks TDirView
  292. ThemeManager->Options = (ThemeManager->Options >> toSubclassListView);
  293. // Speed Button subclassing on rights frame does not work somehow
  294. // and they are not used elsewhere
  295. ThemeManager->Options = (ThemeManager->Options >> toSubclassSpeedButtons);
  296. TAllowSubclassingEvent OnAllowSubclassing;
  297. ((TMethod*)&OnAllowSubclassing)->Code = ThemeManagerAllowSubclassing;
  298. ThemeManager->OnAllowSubclassing = OnAllowSubclassing;
  299. }
  300. }
  301. //---------------------------------------------------------------------------
  302. void __fastcall FinalizeSystemSettings()
  303. {
  304. if (ThemeManager != NULL)
  305. {
  306. SAFE_DESTROY(ThemeManager);
  307. }
  308. }
  309. //---------------------------------------------------------------------------
  310. // Settings that must be set as soon as possible.
  311. void __fastcall UseSystemSettingsPre(TCustomForm * Control, void ** Settings)
  312. {
  313. LocalSystemSettings(Control);
  314. TWndMethod WindowProc;
  315. if (Settings)
  316. {
  317. TSavedSystemSettings * SSettings;
  318. SSettings = new TSavedSystemSettings();
  319. *Settings = static_cast<void*>(SSettings);
  320. SSettings->Form = Control;
  321. SSettings->FontName = Control->Font->Name;
  322. SSettings->OldWndProc = Control->WindowProc;
  323. ((TMethod*)&WindowProc)->Data = SSettings;
  324. ((TMethod*)&WindowProc)->Code = FormWindowProcEx;
  325. }
  326. else
  327. {
  328. ((TMethod*)&WindowProc)->Data = Control;
  329. ((TMethod*)&WindowProc)->Code = FormWindowProc;
  330. }
  331. Control->WindowProc = WindowProc;
  332. assert(Control && Control->Font);
  333. Control->Font->Name = "MS Shell Dlg";
  334. if (Control->HelpKeyword.IsEmpty())
  335. {
  336. // temporary help keyword to enable F1 key in all forms
  337. Control->HelpKeyword = "start";
  338. }
  339. // especially on login dialog, we need to reapply themes with language change
  340. if ((ThemeManager != NULL) && ThemeManager->ThemesEnabled)
  341. {
  342. ThemeManager->CollectForms(Control);
  343. }
  344. };
  345. //---------------------------------------------------------------------------
  346. // Settings that must be set only after whole form is constructed
  347. void __fastcall UseSystemSettingsPost(TCustomForm * Control, void * Settings)
  348. {
  349. bool Flip;
  350. AnsiString FlipStr = LoadStr(FLIP_CHILDREN);
  351. Flip = !FlipStr.IsEmpty() && static_cast<bool>(StrToInt(FlipStr));
  352. if (Settings != NULL)
  353. {
  354. static_cast<TSavedSystemSettings*>(Settings)->Flipped = Flip;
  355. }
  356. if (Flip)
  357. {
  358. Control->FlipChildren(true);
  359. }
  360. ResetSystemSettings(Control);
  361. };
  362. //---------------------------------------------------------------------------
  363. void __fastcall UseSystemSettings(TCustomForm * Control, void ** Settings)
  364. {
  365. UseSystemSettingsPre(Control, Settings);
  366. UseSystemSettingsPost(Control, (Settings != NULL) ? *Settings : NULL);
  367. };
  368. //---------------------------------------------------------------------------
  369. void __fastcall ResetSystemSettings(TCustomForm * /*Control*/)
  370. {
  371. // noop
  372. }
  373. //---------------------------------------------------------------------------
  374. void __fastcall DeleteSystemSettings(TCustomForm * Control, void * Settings)
  375. {
  376. assert(Settings);
  377. TSavedSystemSettings * SSettings = static_cast<TSavedSystemSettings *>(Settings);
  378. Control->WindowProc = SSettings->OldWndProc;
  379. delete SSettings;
  380. }
  381. //---------------------------------------------------------------------------
  382. void __fastcall RevokeSystemSettings(TCustomForm * Control, void * Settings)
  383. {
  384. assert(Settings);
  385. TSavedSystemSettings* SSettings = static_cast<TSavedSystemSettings*>(Settings);
  386. if (SSettings->Flipped)
  387. {
  388. Control->FlipChildren(true);
  389. }
  390. DeleteSystemSettings(Control, Settings);
  391. };
  392. //---------------------------------------------------------------------------
  393. class TPublicForm : public TForm
  394. {
  395. friend void __fastcall ShowAsModal(TForm * Form, void *& Storage);
  396. friend void __fastcall HideAsModal(TForm * Form, void *& Storage);
  397. };
  398. //---------------------------------------------------------------------------
  399. struct TShowAsModalStorage
  400. {
  401. void * FocusWindowList;
  402. void * FocusActiveWindow;
  403. TFocusState FocusState;
  404. };
  405. //---------------------------------------------------------------------------
  406. static TCustomForm ** __fastcall FocusedForm()
  407. {
  408. return reinterpret_cast<TCustomForm **>(reinterpret_cast<char *>(Screen) + 0x78);
  409. }
  410. //---------------------------------------------------------------------------
  411. static TList * __fastcall SaveFocusedList()
  412. {
  413. return *reinterpret_cast<TList **>(reinterpret_cast<char *>(Screen) + 0x7C);
  414. }
  415. //---------------------------------------------------------------------------
  416. void __fastcall ShowAsModal(TForm * Form, void *& Storage)
  417. {
  418. SetCorrectFormParent(Form);
  419. CancelDrag();
  420. if (GetCapture() != 0) SendMessage(GetCapture(), WM_CANCELMODE, 0, 0);
  421. ReleaseCapture();
  422. (static_cast<TPublicForm*>(Form))->FFormState << fsModal;
  423. TShowAsModalStorage * AStorage = new TShowAsModalStorage;
  424. AStorage->FocusActiveWindow = GetActiveWindow();
  425. AStorage->FocusState = SaveFocusState();
  426. SaveFocusedList()->Insert(0, *FocusedForm());
  427. *FocusedForm() = Form;
  428. AStorage->FocusWindowList = DisableTaskWindows(0);
  429. Form->Show();
  430. SendMessage(Form->Handle, CM_ACTIVATE, 0, 0);
  431. Storage = AStorage;
  432. }
  433. //---------------------------------------------------------------------------
  434. void __fastcall HideAsModal(TForm * Form, void *& Storage)
  435. {
  436. assert((static_cast<TPublicForm*>(Form))->FFormState.Contains(fsModal));
  437. TShowAsModalStorage * AStorage = static_cast<TShowAsModalStorage *>(Storage);
  438. Storage = NULL;
  439. SendMessage(Form->Handle, CM_DEACTIVATE, 0, 0);
  440. if (GetActiveWindow() != Form->Handle)
  441. {
  442. AStorage->FocusActiveWindow = 0;
  443. }
  444. Form->Hide();
  445. EnableTaskWindows(AStorage->FocusWindowList);
  446. TList * ASaveFocusedList = SaveFocusedList();
  447. TCustomForm ** AFocusedForm = FocusedForm();
  448. if (ASaveFocusedList->Count > 0)
  449. {
  450. *AFocusedForm = static_cast<TCustomForm *>(ASaveFocusedList->First());
  451. ASaveFocusedList->Remove(*AFocusedForm);
  452. }
  453. else
  454. {
  455. *AFocusedForm = NULL;
  456. }
  457. if (AStorage->FocusActiveWindow != 0)
  458. {
  459. SetActiveWindow(AStorage->FocusActiveWindow);
  460. }
  461. RestoreFocusState(AStorage->FocusState);
  462. (static_cast<TPublicForm*>(Form))->FFormState >> fsModal;
  463. delete AStorage;
  464. }
  465. //---------------------------------------------------------------------------
  466. void __fastcall ReleaseAsModal(TForm * Form, void *& Storage)
  467. {
  468. if (Storage != NULL)
  469. {
  470. HideAsModal(Form, Storage);
  471. }
  472. }
  473. //---------------------------------------------------------------------------
  474. bool __fastcall SelectDirectory(AnsiString & Path, const AnsiString Prompt,
  475. bool PreserveFileName)
  476. {
  477. bool Result;
  478. unsigned int ErrorMode;
  479. ErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  480. try
  481. {
  482. AnsiString Directory;
  483. AnsiString FileName;
  484. if (!PreserveFileName || DirectoryExists(Path))
  485. {
  486. Directory = Path;
  487. }
  488. else
  489. {
  490. Directory = ExtractFilePath(Path);
  491. FileName = ExtractFileName(Path);
  492. }
  493. Result = SelectDirectory(Prompt, "", Directory);
  494. if (Result)
  495. {
  496. Path = Directory;
  497. if (!FileName.IsEmpty())
  498. {
  499. Path = IncludeTrailingBackslash(Path) + FileName;
  500. }
  501. }
  502. }
  503. __finally
  504. {
  505. SetErrorMode(ErrorMode);
  506. }
  507. return Result;
  508. }
  509. //---------------------------------------------------------------------------
  510. bool __fastcall ListViewAnyChecked(TListView * ListView, bool Checked)
  511. {
  512. bool AnyChecked = false;
  513. for (int Index = 0; Index < ListView->Items->Count; Index++)
  514. {
  515. if (ListView->Items->Item[Index]->Checked == Checked)
  516. {
  517. AnyChecked = true;
  518. break;
  519. }
  520. }
  521. return AnyChecked;
  522. }
  523. //---------------------------------------------------------------------------
  524. void __fastcall ListViewCheckAll(TListView * ListView,
  525. TListViewCheckAll CheckAll)
  526. {
  527. bool Check;
  528. if (CheckAll == caToggle)
  529. {
  530. Check = ListViewAnyChecked(ListView, false);
  531. }
  532. else
  533. {
  534. Check = (CheckAll == caCheck);
  535. }
  536. for (int Index = 0; Index < ListView->Items->Count; Index++)
  537. {
  538. ListView->Items->Item[Index]->Checked = Check;
  539. }
  540. }
  541. //---------------------------------------------------------------------------
  542. void __fastcall ComboAutoSwitchInitialize(TComboBox * ComboBox)
  543. {
  544. int PrevIndex = ComboBox->ItemIndex;
  545. ComboBox->Items->BeginUpdate();
  546. try
  547. {
  548. ComboBox->Clear();
  549. ComboBox->Items->Add(LoadStr(AUTO_SWITCH_AUTO));
  550. ComboBox->Items->Add(LoadStr(AUTO_SWITCH_OFF));
  551. ComboBox->Items->Add(LoadStr(AUTO_SWITCH_ON));
  552. }
  553. __finally
  554. {
  555. ComboBox->Items->EndUpdate();
  556. }
  557. assert(PrevIndex < ComboBox->Items->Count);
  558. ComboBox->ItemIndex = PrevIndex;
  559. }
  560. //---------------------------------------------------------------------------
  561. void __fastcall ComboAutoSwitchLoad(TComboBox * ComboBox, TAutoSwitch Value)
  562. {
  563. ComboBox->ItemIndex = 2 - Value;
  564. if (ComboBox->ItemIndex < 0)
  565. {
  566. ComboBox->ItemIndex = 0;
  567. }
  568. }
  569. //---------------------------------------------------------------------------
  570. TAutoSwitch __fastcall ComboAutoSwitchSave(TComboBox * ComboBox)
  571. {
  572. return (TAutoSwitch)(2 - ComboBox->ItemIndex);
  573. }
  574. //---------------------------------------------------------------------------
  575. // Windows algorithm is as follows (tested on W2k):
  576. // right:
  577. // is_delimiter(current)
  578. // false:
  579. // right(left(current) + 1)
  580. // true:
  581. // right(right(current) + 1)
  582. // left:
  583. // right(left(current) + 1)
  584. int CALLBACK PathWordBreakProc(char * Ch, int Current, int Len, int Code)
  585. {
  586. char Delimiters[] = "\\/ ;,.";
  587. int Result;
  588. AnsiString ACh;
  589. // stupid unicode autodetection
  590. // (on WinXP (or rather for RichEdit 2.0) we get unicode on input)
  591. if ((Len > 1) && (Ch[1] == '\0'))
  592. {
  593. // this convertes the unicode to ansi
  594. ACh = (wchar_t*)Ch;
  595. }
  596. else
  597. {
  598. ACh = Ch;
  599. }
  600. // it may not be NULL terminated
  601. ACh.SetLength(Len);
  602. if (Code == WB_ISDELIMITER)
  603. {
  604. // we return negacy of what WinAPI docs says
  605. Result = (strchr(Delimiters, ACh[Current + 1]) == NULL);
  606. }
  607. else if (Code == WB_LEFT)
  608. {
  609. Result = ACh.SubString(1, Current - 1).LastDelimiter(Delimiters);
  610. }
  611. else if (Code == WB_RIGHT)
  612. {
  613. if (Current == 0)
  614. {
  615. // will be called again with Current == 1
  616. Result = 0;
  617. }
  618. else
  619. {
  620. const char * P = strpbrk(ACh.c_str() + Current - 1, Delimiters);
  621. if (P == NULL)
  622. {
  623. Result = Len;
  624. }
  625. else
  626. {
  627. Result = P - ACh.c_str() + 1;
  628. }
  629. }
  630. }
  631. else
  632. {
  633. assert(false);
  634. Result = 0;
  635. }
  636. return Result;
  637. }
  638. //---------------------------------------------------------------------------
  639. class TPublicCustomCombo : public TCustomCombo
  640. {
  641. friend void __fastcall InstallPathWordBreakProc(TWinControl * Control);
  642. };
  643. //---------------------------------------------------------------------------
  644. void __fastcall InstallPathWordBreakProc(TWinControl * Control)
  645. {
  646. HWND Wnd;
  647. if (dynamic_cast<TCustomCombo*>(Control) != NULL)
  648. {
  649. TPublicCustomCombo * Combo =
  650. static_cast<TPublicCustomCombo *>(dynamic_cast<TCustomCombo *>(Control));
  651. Combo->HandleNeeded();
  652. Wnd = Combo->EditHandle;
  653. }
  654. else
  655. {
  656. Wnd = Control->Handle;
  657. }
  658. SendMessage(Wnd, EM_SETWORDBREAKPROC, 0, (LPARAM)(EDITWORDBREAKPROC)PathWordBreakProc);
  659. }
  660. //---------------------------------------------------------------------------
  661. static void __fastcall RemoveHiddenControlsFromOrder(TControl ** ControlsOrder, int & Count)
  662. {
  663. int Shift = 0;
  664. for (int Index = 0; Index < Count; Index++)
  665. {
  666. if (ControlsOrder[Index]->Visible)
  667. {
  668. ControlsOrder[Index - Shift] = ControlsOrder[Index];
  669. }
  670. else
  671. {
  672. Shift++;
  673. }
  674. }
  675. Count -= Shift;
  676. }
  677. //---------------------------------------------------------------------------
  678. void __fastcall RepaintStatusBar(TCustomStatusBar * StatusBar)
  679. {
  680. StatusBar->SimplePanel = !StatusBar->SimplePanel;
  681. StatusBar->SimplePanel = !StatusBar->SimplePanel;
  682. }
  683. //---------------------------------------------------------------------------
  684. void __fastcall SetVerticalControlsOrder(TControl ** ControlsOrder, int Count)
  685. {
  686. RemoveHiddenControlsFromOrder(ControlsOrder, Count);
  687. if (Count > 0)
  688. {
  689. TWinControl * CommonParent = ControlsOrder[0]->Parent;
  690. CommonParent->DisableAlign();
  691. try
  692. {
  693. int Top = 0;
  694. for (int Index = 0; Index < Count; Index++)
  695. {
  696. assert(ControlsOrder[Index]->Parent == CommonParent);
  697. if ((Index == 0) || (Top > ControlsOrder[Index]->Top))
  698. {
  699. Top = ControlsOrder[Index]->Top;
  700. }
  701. }
  702. for (int Index = 0; Index < Count; Index++)
  703. {
  704. TControl * Control = ControlsOrder[Index];
  705. Control->Top = Top;
  706. if (((Control->Align == alTop) || (Control->Align == alBottom)) ||
  707. ((Index == Count - 1) || (ControlsOrder[Index + 1]->Align == alBottom)))
  708. {
  709. Top += Control->Height;
  710. }
  711. }
  712. }
  713. __finally
  714. {
  715. CommonParent->EnableAlign();
  716. }
  717. }
  718. }
  719. //---------------------------------------------------------------------------
  720. void __fastcall SetHorizontalControlsOrder(TControl ** ControlsOrder, int Count)
  721. {
  722. RemoveHiddenControlsFromOrder(ControlsOrder, Count);
  723. if (Count > 0)
  724. {
  725. TWinControl * CommonParent = ControlsOrder[0]->Parent;
  726. CommonParent->DisableAlign();
  727. try
  728. {
  729. int Left = 0;
  730. for (int Index = 0; Index < Count; Index++)
  731. {
  732. assert(ControlsOrder[Index]->Parent == CommonParent);
  733. if ((Index == 0) || (Left > ControlsOrder[Index]->Left))
  734. {
  735. Left = ControlsOrder[Index]->Left;
  736. }
  737. }
  738. for (int Index = 0; Index < Count; Index++)
  739. {
  740. TControl * Control = ControlsOrder[Index];
  741. Control->Left = Left;
  742. if (((Control->Align == alLeft) || (Control->Align == alRight)) ||
  743. ((Index == Count - 1) || (ControlsOrder[Index + 1]->Align == alRight)))
  744. {
  745. Left += Control->Width;
  746. }
  747. // vertical alignment has priority, so alBottom-aligned controls start
  748. // at the very left, even if there are any alLeft/alRight controls.
  749. // for the reason this code is not necessary in SetVerticalControlsOrder.
  750. // we could exit the loop as well here.
  751. if ((Index == Count - 1) || (ControlsOrder[Index + 1]->Align == alBottom))
  752. {
  753. Left = 0;
  754. }
  755. }
  756. }
  757. __finally
  758. {
  759. CommonParent->EnableAlign();
  760. }
  761. }
  762. }
  763. //---------------------------------------------------------------------------
  764. TPoint __fastcall GetAveCharSize(TCanvas* Canvas)
  765. {
  766. Integer I;
  767. Char Buffer[52];
  768. TSize Result;
  769. for (I = 0; I <= 25; I++) Buffer[I] = (Char)('A' + I);
  770. for (I = 0; I <= 25; I++) Buffer[I+26] = (Char)('a' + I);
  771. GetTextExtentPoint(Canvas->Handle, Buffer, 52, &Result);
  772. return TPoint(Result.cx / 52, Result.cy);
  773. }
  774. //---------------------------------------------------------------------------
  775. void __fastcall MakeNextInTabOrder(TWinControl * Control, TWinControl * After)
  776. {
  777. if (After->TabOrder > Control->TabOrder)
  778. {
  779. After->TabOrder = Control->TabOrder;
  780. }
  781. else if (After->TabOrder < Control->TabOrder - 1)
  782. {
  783. After->TabOrder = static_cast<TTabOrder>(Control->TabOrder - 1);
  784. }
  785. }
  786. //---------------------------------------------------------------------------
  787. void __fastcall CutFormToDesktop(TForm * Form)
  788. {
  789. assert(Form->Monitor != NULL);
  790. TRect Workarea = Form->Monitor->WorkareaRect;
  791. if (Form->Top + Form->Height > Workarea.Bottom)
  792. {
  793. Form->Height = Workarea.Bottom - Form->Top;
  794. }
  795. if (Form->Left + Form->Width >= Workarea.Right)
  796. {
  797. Form->Width = Workarea.Right - Form->Left;
  798. }
  799. }
  800. //---------------------------------------------------------------------------
  801. void __fastcall UpdateFormPosition(TCustomForm * Form, TPosition Position)
  802. {
  803. if ((Position == poScreenCenter) ||
  804. (Position == poOwnerFormCenter) ||
  805. (Position == poMainFormCenter))
  806. {
  807. TCustomForm * CenterForm = NULL;
  808. if ((Position == poOwnerFormCenter) ||
  809. (Position == poMainFormCenter))
  810. {
  811. CenterForm = Application->MainForm;
  812. if ((Position == poOwnerFormCenter) &&
  813. (dynamic_cast<TCustomForm*>(Form->Owner) != NULL))
  814. {
  815. CenterForm = dynamic_cast<TCustomForm*>(Form->Owner);
  816. }
  817. }
  818. TRect Bounds = Form->BoundsRect;
  819. int X, Y;
  820. if (CenterForm != NULL)
  821. {
  822. X = ((((TForm *)CenterForm)->Width - Bounds.Width()) / 2) +
  823. ((TForm *)CenterForm)->Left;
  824. Y = ((((TForm *)CenterForm)->Height - Bounds.Height()) / 2) +
  825. ((TForm *)CenterForm)->Top;
  826. }
  827. else
  828. {
  829. X = (Screen->Width - Bounds.Width()) / 2;
  830. Y = (Screen->Height - Bounds.Height()) / 2;
  831. }
  832. if (X < 0)
  833. {
  834. X = 0;
  835. }
  836. if (Y < 0)
  837. {
  838. Y = 0;
  839. }
  840. Form->SetBounds(X, Y, Bounds.Width(), Bounds.Height());
  841. }
  842. }
  843. //---------------------------------------------------------------------------
  844. void __fastcall ResizeForm(TCustomForm * Form, int Width, int Height)
  845. {
  846. if (Height > Screen->WorkAreaHeight)
  847. {
  848. Height = Screen->WorkAreaHeight;
  849. }
  850. if (Width > Screen->WorkAreaWidth)
  851. {
  852. Width = Screen->WorkAreaWidth;
  853. }
  854. if (Height < Form->Constraints->MinHeight)
  855. {
  856. Height = Form->Constraints->MinHeight;
  857. }
  858. if (Width < Form->Constraints->MinWidth)
  859. {
  860. Width = Form->Constraints->MinWidth;
  861. }
  862. TRect Bounds = Form->BoundsRect;
  863. int Top = Bounds.Top + ((Bounds.Height() - Height) / 2);
  864. int Left = Bounds.Left + ((Bounds.Width() - Width) / 2);
  865. if (Top + Height > Screen->WorkAreaTop + Screen->WorkAreaHeight)
  866. {
  867. Top = Screen->WorkAreaTop + Screen->WorkAreaHeight - Height;
  868. }
  869. if (Left + Width >= Screen->WorkAreaLeft + Screen->WorkAreaWidth)
  870. {
  871. Left = Screen->WorkAreaLeft + Screen->WorkAreaWidth - Width;
  872. }
  873. if (Top < 0)
  874. {
  875. Top = 0;
  876. }
  877. if (Left < 0)
  878. {
  879. Left = 0;
  880. }
  881. Form->SetBounds(Left, Top, Width, Height);
  882. Bounds = Form->BoundsRect;
  883. // due to constraints, form can remain larger, make sure it is centered although
  884. Left = Bounds.Left + ((Width - Bounds.Width()) / 2);
  885. Top = Bounds.Top + ((Height - Bounds.Height()) / 2);
  886. Form->SetBounds(Left, Top, Width, Height);
  887. }
  888. //---------------------------------------------------------------------------
  889. HWND __fastcall GetCorrectFormParent()
  890. {
  891. HWND Result = NULL;
  892. // Kind of hack (i do not understand this much).
  893. // Rationale: for example when the preferences window is opened from login dialog
  894. // settings Parent to Screen->ActiveForm leads to "cannot focus disabled control",
  895. // so we set Parent only when absolutelly necessary
  896. // (dialog opened from log window or editor)
  897. // TODO: does not work for dialogs opened from preferences dialog
  898. if ((Application->MainForm != NULL) &&
  899. (Application->MainForm != Screen->ActiveForm))
  900. {
  901. if (Screen->ActiveForm != NULL)
  902. {
  903. // the case when we are invoking dialog from (e.g. prefences) dialog
  904. // invokend form non modal window (e.g. editor)
  905. if (Screen->ActiveForm->ParentWindow != NULL)
  906. {
  907. Result = Screen->ActiveForm->Handle;
  908. }
  909. // this should better be check for modal form
  910. else if (Screen->ActiveForm->BorderStyle != bsDialog)
  911. {
  912. Result = Screen->ActiveForm->Handle;
  913. }
  914. }
  915. }
  916. return Result;
  917. }
  918. //---------------------------------------------------------------------------
  919. void __fastcall SetCorrectFormParent(TForm * Form)
  920. {
  921. try
  922. {
  923. HWND Parent = GetCorrectFormParent();
  924. if (Parent != NULL)
  925. {
  926. Form->ParentWindow = Parent;
  927. }
  928. }
  929. catch(...)
  930. {
  931. // avoid any errors, however we want to know about this in debug version.
  932. #ifdef _DEBUG
  933. throw;
  934. #endif
  935. }
  936. }
  937. //---------------------------------------------------------------------------
  938. void __fastcall InvokeHelp(TWinControl * Control)
  939. {
  940. assert(Control != NULL);
  941. HELPINFO HelpInfo;
  942. HelpInfo.cbSize = sizeof(HelpInfo);
  943. HelpInfo.iContextType = HELPINFO_WINDOW;
  944. HelpInfo.iCtrlId = 0;
  945. HelpInfo.hItemHandle = Control->Handle;
  946. HelpInfo.dwContextId = 0;
  947. HelpInfo.MousePos.x = 0;
  948. HelpInfo.MousePos.y = 0;
  949. SendMessage(Control->Handle, WM_HELP, NULL, reinterpret_cast<long>(&HelpInfo));
  950. }
  951. //---------------------------------------------------------------------------
  952. //---------------------------------------------------------------------------
  953. static void __fastcall FocusableLabelCanvas(TStaticText * StaticText,
  954. TControlCanvas ** ACanvas, TRect & R)
  955. {
  956. TControlCanvas * Canvas = new TControlCanvas();
  957. try
  958. {
  959. Canvas->Control = StaticText;
  960. R = StaticText->ClientRect;
  961. AnsiString Caption = StaticText->Caption;
  962. bool AccelChar = false;
  963. if (StaticText->ShowAccelChar)
  964. {
  965. Caption = StripHotkey(Caption);
  966. AccelChar = (Caption != StaticText->Caption);
  967. }
  968. TSize TextSize = Canvas->TextExtent(Caption);
  969. assert(StaticText->BorderStyle == sbsNone); // not taken into account
  970. if (AccelChar)
  971. {
  972. TextSize.cy += 2;
  973. }
  974. R.Bottom = R.Top + TextSize.cy;
  975. switch (StaticText->Alignment)
  976. {
  977. case taLeftJustify:
  978. R.Right = R.Left + TextSize.cx;
  979. break;
  980. case taRightJustify:
  981. R.Left = R.Right - TextSize.cx;
  982. break;
  983. case taCenter:
  984. {
  985. int Diff = R.Width() - TextSize.cx;
  986. R.Left += Diff / 2;
  987. R.Right -= Diff - (Diff / 2);
  988. }
  989. break;
  990. }
  991. }
  992. __finally
  993. {
  994. if (ACanvas == NULL)
  995. {
  996. delete Canvas;
  997. }
  998. }
  999. if (ACanvas != NULL)
  1000. {
  1001. *ACanvas = Canvas;
  1002. }
  1003. }
  1004. //---------------------------------------------------------------------------
  1005. static void __fastcall FocusableLabelWindowProc(void * Data, TMessage & Message,
  1006. bool & Clicked)
  1007. {
  1008. Clicked = false;
  1009. TStaticText * StaticText = static_cast<TStaticText *>(Data);
  1010. if (Message.Msg == WM_LBUTTONDOWN)
  1011. {
  1012. StaticText->SetFocus();
  1013. // in case the action takes long, make sure focus is shown immediatelly
  1014. UpdateWindow(StaticText->Handle);
  1015. Clicked = true;
  1016. Message.Result = 1;
  1017. }
  1018. else if (Message.Msg == WM_RBUTTONDOWN)
  1019. {
  1020. StaticText->SetFocus();
  1021. Message.Result = 1;
  1022. }
  1023. else if (Message.Msg == WM_CHAR)
  1024. {
  1025. if (reinterpret_cast<TWMChar &>(Message).CharCode == ' ')
  1026. {
  1027. Clicked = true;
  1028. Message.Result = 1;
  1029. }
  1030. else
  1031. {
  1032. ControlWndProc(StaticText)(Message);
  1033. }
  1034. }
  1035. else if (Message.Msg == CM_DIALOGCHAR)
  1036. {
  1037. if (StaticText->CanFocus() && StaticText->ShowAccelChar &&
  1038. IsAccel(reinterpret_cast<TCMDialogChar &>(Message).CharCode, StaticText->Caption))
  1039. {
  1040. StaticText->SetFocus();
  1041. // in case the action takes long, make sure focus is shown immediatelly
  1042. UpdateWindow(StaticText->Handle);
  1043. Clicked = true;
  1044. Message.Result = 1;
  1045. }
  1046. else
  1047. {
  1048. ControlWndProc(StaticText)(Message);
  1049. }
  1050. }
  1051. else
  1052. {
  1053. ControlWndProc(StaticText)(Message);
  1054. }
  1055. if (Message.Msg == WM_PAINT)
  1056. {
  1057. TRect R;
  1058. TControlCanvas * Canvas;
  1059. FocusableLabelCanvas(StaticText, &Canvas, R);
  1060. try
  1061. {
  1062. if (StaticText->Focused())
  1063. {
  1064. Canvas->DrawFocusRect(R);
  1065. }
  1066. else if (!StaticText->Font->Style.Contains(fsUnderline))
  1067. {
  1068. Canvas->Pen->Style = psDot;
  1069. Canvas->Brush->Style = bsClear;
  1070. if (!StaticText->Enabled)
  1071. {
  1072. Canvas->Pen->Color = clBtnHighlight;
  1073. Canvas->MoveTo(R.Left + 1 + 1, R.Bottom);
  1074. Canvas->LineTo(R.Right + 1, R.Bottom);
  1075. Canvas->Pen->Color = clGrayText;
  1076. }
  1077. Canvas->MoveTo(R.Left + 1, R.Bottom - 1);
  1078. Canvas->LineTo(R.Right, R.Bottom - 1);
  1079. }
  1080. }
  1081. __finally
  1082. {
  1083. delete Canvas;
  1084. }
  1085. }
  1086. else if ((Message.Msg == WM_SETFOCUS) || (Message.Msg == WM_KILLFOCUS) ||
  1087. (Message.Msg == CM_ENABLEDCHANGED))
  1088. {
  1089. StaticText->Invalidate();
  1090. }
  1091. }
  1092. //---------------------------------------------------------------------------
  1093. static THintWindow * PersistentHintWindow = NULL;
  1094. static TControl * PersistentHintControl = NULL;
  1095. //---------------------------------------------------------------------------
  1096. void __fastcall CancelPersistentHint()
  1097. {
  1098. if (PersistentHintWindow != NULL)
  1099. {
  1100. PersistentHintControl = NULL;
  1101. SAFE_DESTROY(PersistentHintWindow);
  1102. }
  1103. }
  1104. //---------------------------------------------------------------------------
  1105. void __fastcall ShowPersistentHint(TControl * Control, TPoint HintPos)
  1106. {
  1107. CancelPersistentHint();
  1108. THintInfo HintInfo;
  1109. HintInfo.HintControl = Control;
  1110. HintInfo.HintPos = HintPos;
  1111. HintInfo.HintMaxWidth = Screen->Width;
  1112. HintInfo.HintColor = Application->HintColor;
  1113. HintInfo.HintStr = GetShortHint(Control->Hint);
  1114. HintInfo.HintData = NULL;
  1115. bool CanShow = true;
  1116. if (Application->OnShowHint != NULL)
  1117. {
  1118. Application->OnShowHint(HintInfo.HintStr, CanShow, HintInfo);
  1119. }
  1120. if (CanShow)
  1121. {
  1122. PersistentHintControl = Control;
  1123. PersistentHintWindow = new THintWindow(Application);
  1124. PersistentHintWindow->BiDiMode = Control->BiDiMode;
  1125. PersistentHintWindow->Color = HintInfo.HintColor;
  1126. TRect HintWinRect;
  1127. if (HintInfo.HintMaxWidth < Control->Width)
  1128. {
  1129. HintInfo.HintMaxWidth = Control->Width;
  1130. }
  1131. HintWinRect = PersistentHintWindow->CalcHintRect(
  1132. HintInfo.HintMaxWidth, HintInfo.HintStr, HintInfo.HintData);
  1133. OffsetRect(HintWinRect, HintInfo.HintPos.x, HintInfo.HintPos.y);
  1134. // TODO: right align window placement for UseRightToLeftAlignment, see Forms.pas
  1135. PersistentHintWindow->ActivateHintData(HintWinRect, HintInfo.HintStr, HintInfo.HintData);
  1136. }
  1137. }
  1138. //---------------------------------------------------------------------------
  1139. static void __fastcall HintLabelWindowProc(void * Data, TMessage & Message)
  1140. {
  1141. bool Clicked = false;
  1142. bool Cancel = false;
  1143. TStaticText * StaticText = static_cast<TStaticText *>(Data);
  1144. if (Message.Msg == CM_HINTSHOW)
  1145. {
  1146. TCMHintShow & HintShow = reinterpret_cast<TCMHintShow &>(Message);
  1147. if (PersistentHintControl == StaticText)
  1148. {
  1149. // do not allow standard hint when persistent is already shown
  1150. HintShow.Result = 1;
  1151. }
  1152. else
  1153. {
  1154. HintShow.HintInfo->HideTimeout = 100000; // never
  1155. }
  1156. }
  1157. else if (Message.Msg == CN_KEYDOWN)
  1158. {
  1159. if ((reinterpret_cast<TWMKey &>(Message).CharCode == VK_ESCAPE) &&
  1160. (PersistentHintControl == StaticText))
  1161. {
  1162. CancelPersistentHint();
  1163. StaticText->Invalidate();
  1164. Message.Result = 1;
  1165. }
  1166. else
  1167. {
  1168. FocusableLabelWindowProc(Data, Message, Clicked);
  1169. }
  1170. }
  1171. else
  1172. {
  1173. FocusableLabelWindowProc(Data, Message, Clicked);
  1174. }
  1175. if (Message.Msg == CM_CANCELMODE)
  1176. {
  1177. TCMCancelMode & CancelMessage = (TCMCancelMode&)Message;
  1178. if ((CancelMessage.Sender != StaticText) &&
  1179. (CancelMessage.Sender != PersistentHintWindow))
  1180. {
  1181. Cancel = true;
  1182. }
  1183. }
  1184. if ((Message.Msg == WM_DESTROY) || (Message.Msg == WM_KILLFOCUS))
  1185. {
  1186. Cancel = true;
  1187. }
  1188. if (Cancel && (PersistentHintControl == StaticText))
  1189. {
  1190. CancelPersistentHint();
  1191. }
  1192. if (Clicked && (PersistentHintControl != StaticText))
  1193. {
  1194. TRect R;
  1195. TPoint HintPos;
  1196. FocusableLabelCanvas(StaticText, NULL, R);
  1197. HintPos.y = R.Bottom - R.Top;
  1198. HintPos.x = R.Left;
  1199. ShowPersistentHint(StaticText, StaticText->ClientToScreen(HintPos));
  1200. }
  1201. }
  1202. //---------------------------------------------------------------------------
  1203. void __fastcall HintLabel(TStaticText * StaticText, AnsiString Hint)
  1204. {
  1205. StaticText->ParentFont = true;
  1206. if (!Hint.IsEmpty())
  1207. {
  1208. StaticText->Hint = Hint;
  1209. }
  1210. StaticText->ShowHint = true;
  1211. StaticText->Cursor = crHandPoint;
  1212. TWndMethod WindowProc;
  1213. ((TMethod*)&WindowProc)->Data = StaticText;
  1214. ((TMethod*)&WindowProc)->Code = HintLabelWindowProc;
  1215. StaticText->WindowProc = WindowProc;
  1216. }
  1217. //---------------------------------------------------------------------------
  1218. void __fastcall HintLabelRestore(TStaticText * StaticText)
  1219. {
  1220. StaticText->WindowProc = ControlWndProc(StaticText);
  1221. StaticText->ShowHint = false;
  1222. StaticText->Cursor = crDefault;
  1223. }
  1224. //---------------------------------------------------------------------------
  1225. static void __fastcall ComboBoxFixWindowProc(void * Data, TMessage & Message)
  1226. {
  1227. // it is TCustomComboxBox, but the properties are published only by TComboBox
  1228. TComboBox * ComboBox = static_cast<TComboBox *>(Data);
  1229. if (Message.Msg == WM_SIZE)
  1230. {
  1231. AnsiString Text = ComboBox->Text;
  1232. try
  1233. {
  1234. ControlWndProc(ComboBox)(Message);
  1235. }
  1236. __finally
  1237. {
  1238. // workaround for bug in combo box, that causes it to change text to any
  1239. // item from drop down list which starts with current text,
  1240. // after control is resized (unless the text is in drop down list as well)
  1241. ComboBox->Text = Text;
  1242. // hide selection, which is wrongly shown when form is resized, even when the box has not focus
  1243. if (!ComboBox->Focused())
  1244. {
  1245. ComboBox->SelLength = 0;
  1246. }
  1247. }
  1248. }
  1249. else
  1250. {
  1251. ControlWndProc(ComboBox)(Message);
  1252. }
  1253. }
  1254. //---------------------------------------------------------------------------
  1255. void __fastcall FixComboBoxResizeBug(TCustomComboBox * ComboBox)
  1256. {
  1257. TWndMethod WindowProc;
  1258. ((TMethod*)&WindowProc)->Data = ComboBox;
  1259. ((TMethod*)&WindowProc)->Code = ComboBoxFixWindowProc;
  1260. ComboBox->WindowProc = WindowProc;
  1261. }
  1262. //---------------------------------------------------------------------------
  1263. static void __fastcall LinkLabelClick(TStaticText * StaticText)
  1264. {
  1265. if (StaticText->OnClick != NULL)
  1266. {
  1267. StaticText->OnClick(StaticText);
  1268. }
  1269. else
  1270. {
  1271. AnsiString Url = StaticText->Caption;
  1272. if (!AnsiSameText(Url.SubString(1, 4), "http") && (Url.Pos("@") > 0))
  1273. {
  1274. Url = "mailto:" + Url;
  1275. }
  1276. OpenBrowser(Url);
  1277. }
  1278. }
  1279. //---------------------------------------------------------------------------
  1280. static void __fastcall LinkLabelWindowProc(void * Data, TMessage & Message)
  1281. {
  1282. bool Clicked = false;
  1283. TStaticText * StaticText = static_cast<TStaticText *>(Data);
  1284. if (Message.Msg == WM_CONTEXTMENU)
  1285. {
  1286. TWMContextMenu & ContextMenu = reinterpret_cast<TWMContextMenu &>(Message);
  1287. if ((ContextMenu.Pos.x < 0) && (ContextMenu.Pos.y < 0))
  1288. {
  1289. TRect R;
  1290. FocusableLabelCanvas(StaticText, NULL, R);
  1291. TPoint P = StaticText->ClientToScreen(TPoint(R.Left, R.Bottom));
  1292. ContextMenu.Pos.x = static_cast<short>(P.x);
  1293. ContextMenu.Pos.y = static_cast<short>(P.y);
  1294. }
  1295. }
  1296. else if (Message.Msg == WM_KEYDOWN)
  1297. {
  1298. TWMKey & Key = reinterpret_cast<TWMKey &>(Message);
  1299. if ((GetKeyState(VK_CONTROL) < 0) && (Key.CharCode == 'C'))
  1300. {
  1301. CopyToClipboard(StaticText->Caption);
  1302. Message.Result = 1;
  1303. }
  1304. else
  1305. {
  1306. FocusableLabelWindowProc(Data, Message, Clicked);
  1307. }
  1308. }
  1309. FocusableLabelWindowProc(Data, Message, Clicked);
  1310. if (Message.Msg == WM_DESTROY)
  1311. {
  1312. delete StaticText->PopupMenu;
  1313. assert(StaticText->PopupMenu == NULL);
  1314. }
  1315. if (Clicked)
  1316. {
  1317. LinkLabelClick(StaticText);
  1318. }
  1319. }
  1320. //---------------------------------------------------------------------------
  1321. static void __fastcall LinkLabelContextMenuClick(void * Data, TObject * Sender)
  1322. {
  1323. TStaticText * StaticText = static_cast<TStaticText *>(Data);
  1324. TMenuItem * MenuItem = dynamic_cast<TMenuItem *>(Sender);
  1325. assert(MenuItem != NULL);
  1326. if (MenuItem->Tag == 0)
  1327. {
  1328. LinkLabelClick(StaticText);
  1329. }
  1330. else
  1331. {
  1332. CopyToClipboard(StaticText->Caption);
  1333. }
  1334. }
  1335. //---------------------------------------------------------------------------
  1336. void __fastcall LinkLabel(TStaticText * StaticText, AnsiString Url,
  1337. TNotifyEvent OnEnter)
  1338. {
  1339. StaticText->ParentFont = true;
  1340. StaticText->Font->Style = StaticText->Font->Style << fsUnderline;
  1341. StaticText->Font->Color = clBlue;
  1342. StaticText->Cursor = crHandPoint;
  1343. reinterpret_cast<TButton*>(StaticText)->OnEnter = OnEnter;
  1344. if (!Url.IsEmpty())
  1345. {
  1346. StaticText->Caption = Url;
  1347. }
  1348. if (StaticText->OnClick == NULL)
  1349. {
  1350. assert(StaticText->PopupMenu == NULL);
  1351. StaticText->PopupMenu = new TPopupMenu(StaticText);
  1352. try
  1353. {
  1354. TNotifyEvent ContextMenuOnClick;
  1355. ((TMethod*)&ContextMenuOnClick)->Data = StaticText;
  1356. ((TMethod*)&ContextMenuOnClick)->Code = LinkLabelContextMenuClick;
  1357. TMenuItem * Item;
  1358. Item = new TMenuItem(StaticText->PopupMenu);
  1359. Item->Caption = LoadStr(URL_LINK_OPEN);
  1360. Item->Tag = 0;
  1361. Item->ShortCut = ShortCut(' ', TShiftState());
  1362. Item->OnClick = ContextMenuOnClick;
  1363. StaticText->PopupMenu->Items->Add(Item);
  1364. Item = new TMenuItem(StaticText->PopupMenu);
  1365. Item->Caption = LoadStr(URL_LINK_COPY);
  1366. Item->Tag = 1;
  1367. Item->ShortCut = ShortCut('C', TShiftState() << ssCtrl);
  1368. Item->OnClick = ContextMenuOnClick;
  1369. StaticText->PopupMenu->Items->Add(Item);
  1370. }
  1371. catch(...)
  1372. {
  1373. delete StaticText->PopupMenu;
  1374. assert(StaticText->PopupMenu == NULL);
  1375. throw;
  1376. }
  1377. }
  1378. TWndMethod WindowProc;
  1379. ((TMethod*)&WindowProc)->Data = StaticText;
  1380. ((TMethod*)&WindowProc)->Code = LinkLabelWindowProc;
  1381. StaticText->WindowProc = WindowProc;
  1382. }
  1383. //---------------------------------------------------------------------------
  1384. TMonitor * __fastcall FormMonitor(TCustomForm * Form)
  1385. {
  1386. TMonitor * Result;
  1387. if ((Application->MainForm != NULL) && (Application->MainForm != Form))
  1388. {
  1389. Result = Application->MainForm->Monitor;
  1390. }
  1391. else if (LastMonitor != NULL)
  1392. {
  1393. Result = LastMonitor;
  1394. }
  1395. else
  1396. {
  1397. int i = 0;
  1398. while ((i < Screen->MonitorCount) && !Screen->Monitors[i]->Primary)
  1399. {
  1400. i++;
  1401. }
  1402. assert(Screen->Monitors[i]->Primary);
  1403. Result = Screen->Monitors[i];
  1404. }
  1405. return Result;
  1406. }
  1407. //---------------------------------------------------------------------------
  1408. int __fastcall GetLastMonitor()
  1409. {
  1410. if (LastMonitor != NULL)
  1411. {
  1412. return LastMonitor->MonitorNum;
  1413. }
  1414. else
  1415. {
  1416. return -1;
  1417. }
  1418. }
  1419. //---------------------------------------------------------------------------
  1420. void __fastcall SetLastMonitor(int MonitorNum)
  1421. {
  1422. if ((MonitorNum >= 0) && (MonitorNum < Screen->MonitorCount))
  1423. {
  1424. LastMonitor = Screen->Monitors[MonitorNum];
  1425. }
  1426. else
  1427. {
  1428. LastMonitor = NULL;
  1429. }
  1430. }
  1431. //---------------------------------------------------------------------------
  1432. TForm * __fastcall _SafeFormCreate(TMetaClass * FormClass, TComponent * Owner)
  1433. {
  1434. // we do ignore owner atm, as we do not know how to set it,
  1435. // but it should not cause any problems as we always manage memory
  1436. // destruction ourselves
  1437. assert(Owner == Application);
  1438. USEDPARAM(Owner);
  1439. TForm * Form;
  1440. // if there is no main form yet, make this one main.
  1441. // this, among other, makes other forms (dialogs invoked from this one),
  1442. // be placed on the same monitor (otherwise all new forms get placed
  1443. // on primary monitor)
  1444. if (Application->MainForm == NULL)
  1445. {
  1446. Application->CreateForm(FormClass, &Form);
  1447. assert(Application->MainForm == Form);
  1448. }
  1449. else
  1450. {
  1451. Form = dynamic_cast<TForm *>(Construct(FormClass, Application));
  1452. assert(Form != NULL);
  1453. }
  1454. return Form;
  1455. }
  1456. //---------------------------------------------------------------------------
  1457. TImageList * __fastcall SharedSystemImageList(bool Large)
  1458. {
  1459. TSHFileInfo FileInfo;
  1460. TImageList * Result = new TImageList(Application);
  1461. int ImageListHandle = SHGetFileInfo("", 0, &FileInfo, sizeof(FileInfo),
  1462. SHGFI_SYSICONINDEX | (Large ? SHGFI_LARGEICON : SHGFI_SMALLICON));
  1463. if (ImageListHandle != 0)
  1464. {
  1465. Result->ShareImages = true;
  1466. Result->Handle = ImageListHandle;
  1467. }
  1468. return Result;
  1469. }