MessageDlg.cpp 12 KB

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