MessageDlg.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include <Consts.hpp>
  5. #include <MoreButton.hpp>
  6. #include <GUITools.h>
  7. #include <Common.h>
  8. #include <VCLCommon.h>
  9. #include <WinInterface.h>
  10. #include <TextsWin.h>
  11. //---------------------------------------------------------------------------
  12. #pragma package(smart_init)
  13. //---------------------------------------------------------------------------
  14. class TMessageForm : public TForm
  15. {
  16. public:
  17. static TForm * __fastcall Create(const AnsiString & Msg, TStrings * MoreMessages,
  18. TMsgDlgType DlgType, TMsgDlgButtons Buttons,
  19. TQueryButtonAlias * Aliases, unsigned int AliasesCount,
  20. TMsgDlgBtn TimeoutResult, TButton ** TimeoutButton);
  21. protected:
  22. __fastcall TMessageForm(TComponent * AOwner);
  23. DYNAMIC void __fastcall KeyDown(Word & Key, TShiftState Shift);
  24. AnsiString __fastcall GetFormText();
  25. virtual void __fastcall CreateParams(TCreateParams & Params);
  26. DYNAMIC void __fastcall DoShow();
  27. private:
  28. TLabel * Message;
  29. TMemo * MessageMemo;
  30. void __fastcall HelpButtonClick(TObject * Sender);
  31. };
  32. //---------------------------------------------------------------------------
  33. __fastcall TMessageForm::TMessageForm(TComponent * AOwner) : TForm(AOwner, 0)
  34. {
  35. Message = NULL;
  36. MessageMemo = NULL;
  37. TNonClientMetrics NonClientMetrics;
  38. NonClientMetrics.cbSize = sizeof(NonClientMetrics);
  39. if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &NonClientMetrics, 0))
  40. {
  41. Font->Handle = CreateFontIndirect(&NonClientMetrics.lfMessageFont);
  42. }
  43. UseSystemSettingsPre(this);
  44. }
  45. //---------------------------------------------------------------------------
  46. void __fastcall TMessageForm::HelpButtonClick(TObject * /*Sender*/)
  47. {
  48. FormHelp(this);
  49. }
  50. //---------------------------------------------------------------------------
  51. void __fastcall TMessageForm::KeyDown(Word & Key, TShiftState Shift)
  52. {
  53. if (Shift.Contains(ssCtrl) && (Key == 'C'))
  54. {
  55. CopyToClipboard(GetFormText());
  56. }
  57. }
  58. //---------------------------------------------------------------------------
  59. AnsiString __fastcall TMessageForm::GetFormText()
  60. {
  61. AnsiString DividerLine, ButtonCaptions;
  62. DividerLine = AnsiString::StringOfChar('-', 27) + sLineBreak;
  63. for (int i = 0; i < ComponentCount - 1; i++)
  64. {
  65. if ((dynamic_cast<TButton*>(Components[i]) != NULL) &&
  66. (dynamic_cast<TMoreButton*>(Components[i]) == NULL))
  67. {
  68. ButtonCaptions += dynamic_cast<TButton*>(Components[i])->Caption +
  69. AnsiString::StringOfChar(' ', 3);
  70. }
  71. }
  72. ButtonCaptions = StringReplace(ButtonCaptions, "&", "",
  73. TReplaceFlags() << rfReplaceAll);
  74. AnsiString MoreMessages;
  75. if (MessageMemo != NULL)
  76. {
  77. MoreMessages = MessageMemo->Text + DividerLine;
  78. }
  79. AnsiString MessageCaption;
  80. MessageCaption = StringReplace(Message->Caption, "\r", "", TReplaceFlags() << rfReplaceAll);
  81. MessageCaption = StringReplace(MessageCaption, "\n", "\r\n", TReplaceFlags() << rfReplaceAll);
  82. AnsiString Result = FORMAT("%s%s%s%s%s%s%s%s%s%s%s", (DividerLine, Caption, sLineBreak,
  83. DividerLine, MessageCaption, sLineBreak, DividerLine, MoreMessages,
  84. ButtonCaptions, sLineBreak, DividerLine));
  85. return Result;
  86. }
  87. //---------------------------------------------------------------------------
  88. void __fastcall TMessageForm::CreateParams(TCreateParams & Params)
  89. {
  90. TForm::CreateParams(Params);
  91. if ((Screen != NULL) && (Screen->ActiveForm != NULL) &&
  92. Screen->ActiveForm->HandleAllocated())
  93. {
  94. Params.WndParent = Screen->ActiveForm->Handle;
  95. }
  96. }
  97. //---------------------------------------------------------------------------
  98. void __fastcall TMessageForm::DoShow()
  99. {
  100. UseSystemSettingsPost(this);
  101. TForm::DoShow();
  102. }
  103. //---------------------------------------------------------------------------
  104. const ResourceString * Captions[] = { &_SMsgDlgWarning, &_SMsgDlgError, &_SMsgDlgInformation,
  105. &_SMsgDlgConfirm, NULL };
  106. const char * IconIDs[] = { IDI_EXCLAMATION, IDI_HAND, IDI_ASTERISK,
  107. IDI_QUESTION, NULL };
  108. const int ButtonCount = 11;
  109. const AnsiString ButtonNames[ButtonCount] = {
  110. "Yes", "No", "OK", "Cancel", "Abort", "Retry", "Ignore", "All", "NoToAll",
  111. "YesToAll", "Help" };
  112. const ResourceString * ButtonCaptions[ButtonCount] = {
  113. &_SMsgDlgYes, &_SMsgDlgNo, &_SMsgDlgOK, &_SMsgDlgCancel, &_SMsgDlgAbort,
  114. &_SMsgDlgRetry, &_SMsgDlgIgnore, &_SMsgDlgAll, &_SMsgDlgNoToAll, &_SMsgDlgYesToAll,
  115. &_SMsgDlgHelp };
  116. extern const int ModalResults[ButtonCount] = {
  117. mrYes, mrNo, mrOk, mrCancel, mrAbort, mrRetry, mrIgnore, mrAll, mrNoToAll,
  118. mrYesToAll, 0 };
  119. const int mcHorzMargin = 8;
  120. const int mcVertMargin = 8;
  121. const int mcHorzSpacing = 10;
  122. const int mcVertSpacing = 10;
  123. const int mcButtonWidth = 50;
  124. const int mcButtonHeight = 14;
  125. const int mcButtonSpacing = 4;
  126. const int mcMoreMessageWidth = 320;
  127. const int mcMoreMessageHeight = 80;
  128. //---------------------------------------------------------------------------
  129. TForm * __fastcall TMessageForm::Create(const AnsiString & Msg,
  130. TStrings * MoreMessages, TMsgDlgType DlgType, TMsgDlgButtons Buttons,
  131. TQueryButtonAlias * Aliases, unsigned int AliasesCount,
  132. TMsgDlgBtn TimeoutResult, TButton ** TimeoutButton)
  133. {
  134. TRect TextRect;
  135. TMsgDlgBtn DefaultButton, CancelButton;
  136. if (Buttons.Contains(mbOK))
  137. {
  138. DefaultButton = mbOK;
  139. }
  140. else if (Buttons.Contains(mbYes))
  141. {
  142. DefaultButton = mbYes;
  143. }
  144. else
  145. {
  146. DefaultButton = mbRetry;
  147. }
  148. if (Buttons.Contains(mbCancel))
  149. {
  150. CancelButton = mbCancel;
  151. }
  152. else if (Buttons.Contains(mbNo))
  153. {
  154. CancelButton = mbNo;
  155. }
  156. else if (Buttons.Contains(mbAbort))
  157. {
  158. CancelButton = mbAbort;
  159. }
  160. else
  161. {
  162. CancelButton = mbOK;
  163. }
  164. if (TimeoutButton != NULL)
  165. {
  166. *TimeoutButton = NULL;
  167. }
  168. TMessageForm * Result = SafeFormCreate<TMessageForm>();
  169. Result->BiDiMode = Application->BiDiMode;
  170. Result->BorderStyle = bsDialog;
  171. Result->Canvas->Font = Result->Font;
  172. Result->KeyPreview = true;
  173. Result->Position = poMainFormCenter;
  174. TPoint DialogUnits = GetAveCharSize(Result->Canvas);
  175. int HorzMargin = MulDiv(mcHorzMargin, DialogUnits.x, 4);
  176. int VertMargin = MulDiv(mcVertMargin, DialogUnits.y, 8);
  177. int HorzSpacing = MulDiv(mcHorzSpacing, DialogUnits.x, 4);
  178. int VertSpacing = MulDiv(mcVertSpacing, DialogUnits.y, 8);
  179. int ButtonWidth = MulDiv(mcButtonWidth, DialogUnits.x, 4);
  180. TButton * ButtonControls[ButtonCount + 1];
  181. int ButtonControlsCount = 0;
  182. for (unsigned int B = mbYes; B <= mbHelp; B++)
  183. {
  184. assert(B < ButtonCount);
  185. if (Buttons.Contains(TMsgDlgBtn(B)))
  186. {
  187. TextRect = Rect(0,0,0,0);
  188. AnsiString Caption = LoadResourceString(ButtonCaptions[B]);
  189. // temporary fix of accelerators (&Abort vs. &All/Yes to &All)
  190. // must be removed
  191. if (Caption == "&All")
  192. {
  193. Caption = "A&ll";
  194. }
  195. else if (Caption == "Yes to &All")
  196. {
  197. Caption = "Yes to A&ll";
  198. }
  199. TNotifyEvent OnClick = NULL;
  200. if (Aliases != NULL)
  201. {
  202. for (unsigned int i = 0; i < AliasesCount; i++)
  203. {
  204. if (B == Aliases[i].Button)
  205. {
  206. Caption = Aliases[i].Alias;
  207. OnClick = Aliases[i].OnClick;
  208. break;
  209. }
  210. }
  211. }
  212. TButton * Button = new TButton(Result);
  213. AnsiString MeasureCaption = Caption;
  214. if ((TimeoutButton != NULL) && (B == TimeoutResult))
  215. {
  216. MeasureCaption = FMTLOAD(TIMEOUT_BUTTON, (MeasureCaption, 99));
  217. *TimeoutButton = Button;
  218. }
  219. DrawText(Result->Canvas->Handle,
  220. MeasureCaption.c_str(), -1,
  221. &TextRect, DT_CALCRECT | DT_LEFT | DT_SINGLELINE |
  222. Result->DrawTextBiDiModeFlagsReadingOnly());
  223. int CurButtonWidth = TextRect.Right - TextRect.Left + 8;
  224. if (CurButtonWidth > ButtonWidth)
  225. {
  226. ButtonWidth = CurButtonWidth;
  227. }
  228. Button->Name = ButtonNames[TMsgDlgBtn(B)];
  229. Button->Parent = Result;
  230. Button->Caption = Caption;
  231. if (OnClick != NULL)
  232. {
  233. Button->OnClick = OnClick;
  234. }
  235. else
  236. {
  237. Button->ModalResult = ModalResults[B];
  238. Button->Default = (B == DefaultButton);
  239. Button->Cancel = (B == CancelButton);
  240. }
  241. if (MoreMessages != NULL)
  242. {
  243. Button->Anchors = TAnchors() << akBottom << akLeft;
  244. }
  245. if (B == mbHelp)
  246. {
  247. Button->OnClick = Result->HelpButtonClick;
  248. }
  249. ButtonControls[ButtonControlsCount] = Button;
  250. ButtonControlsCount++;
  251. }
  252. }
  253. int ButtonHeight = MulDiv(mcButtonHeight, DialogUnits.y, 8);
  254. int ButtonSpacing = MulDiv(mcButtonSpacing, DialogUnits.x, 4);
  255. SetRect(&TextRect, 0, 0, Screen->Width / 2, 0);
  256. DrawText(Result->Canvas->Handle, Msg.c_str(), Msg.Length() + 1, &TextRect,
  257. DT_EXPANDTABS | DT_CALCRECT | DT_WORDBREAK |
  258. Result->DrawTextBiDiModeFlagsReadingOnly());
  259. const char * IconID = IconIDs[DlgType];
  260. int IconTextWidth = TextRect.Right;
  261. int IconTextHeight = TextRect.Bottom;
  262. if (IconID != NULL)
  263. {
  264. IconTextWidth += 32 + HorzSpacing;
  265. if (IconTextHeight < 32)
  266. {
  267. IconTextHeight = 32;
  268. }
  269. }
  270. if (MoreMessages != NULL)
  271. {
  272. TMemo * MessageMemo = new TMemo(Result);
  273. MessageMemo->Parent = Result;
  274. MessageMemo->ReadOnly = true;
  275. MessageMemo->WantReturns = False;
  276. MessageMemo->ScrollBars = ssVertical;
  277. MessageMemo->Anchors = TAnchors() << akLeft << akRight << akTop; //akBottom;
  278. MessageMemo->Color = clBtnFace;
  279. MessageMemo->Lines->Text = MoreMessages->Text;
  280. Result->MessageMemo = MessageMemo;
  281. TMoreButton * MoreButton = new TMoreButton(Result);
  282. MoreButton->Parent = Result;
  283. MoreButton->Panel = MessageMemo;
  284. MoreButton->RepositionForm = true;
  285. MoreButton->Name = "MoreButton";
  286. MessageMemo->TabOrder = static_cast<short>(MoreButton->TabOrder + 1);
  287. ButtonControls[ButtonControlsCount] = MoreButton;
  288. ButtonControlsCount++;
  289. }
  290. int ButtonGroupWidth = 0;
  291. if (ButtonControlsCount > 0)
  292. {
  293. ButtonGroupWidth = ButtonWidth * ButtonControlsCount +
  294. ButtonSpacing * (ButtonControlsCount - 1);
  295. }
  296. int MoreMessageWidth = (MoreMessages != NULL ?
  297. MulDiv(mcMoreMessageWidth, DialogUnits.x, 4) : 0);
  298. int MoreMessageHeight = (MoreMessages != NULL ?
  299. MulDiv(mcMoreMessageHeight, DialogUnits.y, 8) : 0);
  300. int AClientWidth =
  301. (IconTextWidth > ButtonGroupWidth ? IconTextWidth : ButtonGroupWidth) +
  302. HorzMargin * 2;
  303. Result->ClientWidth = (AClientWidth > MoreMessageWidth ?
  304. AClientWidth : MoreMessageWidth);
  305. Result->ClientHeight = IconTextHeight + ButtonHeight + VertSpacing +
  306. VertMargin * 2 + MoreMessageHeight;
  307. Result->Left = (Screen->Width / 2) - (Result->Width / 2);
  308. Result->Top = (Screen->Height / 2) - (Result->Height / 2);
  309. if (DlgType != mtCustom)
  310. {
  311. Result->Caption = LoadResourceString(Captions[DlgType]);
  312. }
  313. else
  314. {
  315. Result->Caption = Application->Title;
  316. }
  317. if (IconID != NULL)
  318. {
  319. TImage * Image = new TImage(Result);
  320. Image->Name = "Image";
  321. Image->Parent = Result;
  322. Image->Picture->Icon->Handle = LoadIcon(0, IconID);
  323. Image->SetBounds(HorzMargin, VertMargin, 32, 32);
  324. }
  325. TLabel * Message = new TLabel(Result);
  326. Result->Message = Message;
  327. Message->Name = "Message";
  328. Message->Parent = Result;
  329. Message->WordWrap = true;
  330. Message->Caption = Msg;
  331. Message->BoundsRect = TextRect;
  332. Message->BiDiMode = Result->BiDiMode;
  333. // added to show & as & for messages containing !& pattern of custom commands
  334. // (suppose that we actually never want to use & as accel in message text)
  335. Message->ShowAccelChar = false;
  336. int ALeft = IconTextWidth - TextRect.Right + HorzMargin;
  337. Message->SetBounds(ALeft, VertMargin, TextRect.Right, TextRect.Bottom);
  338. int ButtonTop = IconTextHeight + VertMargin + VertSpacing + MoreMessageHeight;
  339. if (Result->MessageMemo != NULL)
  340. {
  341. Result->MessageMemo->BoundsRect = TRect(Message->Left,
  342. Message->Top + Message->Height + VertSpacing,
  343. Result->ClientWidth - HorzMargin,
  344. Message->Top + Message->Height + VertSpacing + MoreMessageHeight);
  345. // rather hack, whole control positioning is wrong
  346. if (Result->MessageMemo->Top + Result->MessageMemo->Height > ButtonTop - VertSpacing)
  347. {
  348. Result->MessageMemo->Height =
  349. (ButtonTop - VertSpacing) - Result->MessageMemo->Top;
  350. }
  351. }
  352. int X = (Result->ClientWidth - ButtonGroupWidth) / 2;
  353. for (int i = 0; i < ButtonControlsCount; i++)
  354. {
  355. ButtonControls[i]->SetBounds(X,
  356. ButtonTop, ButtonWidth, ButtonHeight);
  357. X += ButtonWidth + ButtonSpacing;
  358. }
  359. return Result;
  360. }
  361. //---------------------------------------------------------------------------
  362. TForm * __fastcall CreateMoreMessageDialog(const AnsiString & Msg,
  363. TStrings * MoreMessages, TMsgDlgType DlgType, TMsgDlgButtons Buttons,
  364. TQueryButtonAlias * Aliases, unsigned int AliasesCount,
  365. TMsgDlgBtn TimeoutResult, TButton ** TimeoutButton)
  366. {
  367. return TMessageForm::Create(Msg, MoreMessages, DlgType, Buttons,
  368. Aliases, AliasesCount, TimeoutResult, TimeoutButton);
  369. }