VCLCommon.cpp 43 KB

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