123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- #pragma once
- #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
- // Windows Header Files
- #include <windows.h>
- using namespace System;
- using namespace System::Windows::Forms;
- using namespace System::Drawing;
- // ported from https://stackoverflow.com/a/7785745
- // original code by user LarsTech https://stackoverflow.com/users/719186/larstech
- static ref class SkinnedMessageBox
- {
- private: ref class SkinnedMessageBoxForm : Form
- {
- private:
- void SkinnedMessageBoxForm_Shown(Object^ sender, EventArgs^ e)
- {
- Activate();
- }
- void SkinnedMessageBoxForm_FormClosed(Object^ sender, FormClosedEventArgs^ e)
- {
- if (CancelButton && (DialogResult == System::Windows::Forms::DialogResult::None || DialogResult == System::Windows::Forms::DialogResult::Cancel))
- DialogResult = CancelButton->DialogResult;
- }
- void InitComponentNew()
- {
- this->SuspendLayout();
- this->AutoSize = true;
- this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::FixedDialog;
- this->Width = 350;
- this->Height = 140;
- this->StartPosition = FormStartPosition::CenterScreen;
- this->MaximizeBox = false;
- this->MinimizeBox = false;
- this->ShowInTaskbar = false;
- this->ShowIcon = false;
- __try
- {
- this->Icon = Application::OpenForms[0]->Icon;
- }
- __except (1) { }
- this->Shown += gcnew EventHandler(this, &SkinnedMessageBoxForm::SkinnedMessageBoxForm_Shown);
- this->FormClosed += gcnew FormClosedEventHandler(this, &SkinnedMessageBoxForm::SkinnedMessageBoxForm_FormClosed);
- //this->Font = SystemFonts::MessageBoxFont;
- //this->Font = gcnew Font(SystemFonts::MessageBoxFont->FontFamily, SystemFonts::MessageBoxFont->SizeInPoints);
- this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::None;
- this->ResumeLayout(false);
- this->PerformLayout();
- }
- float ScaleWidth = 1.0;
- float ScaleHeight = 1.0;
- int btnWidth = 85;
- int btnHeight = 23;
- int btnPadding = 12;
- static cli::array<Button^>^ buttonrefs = gcnew cli::array<Button^>{ gcnew Button, gcnew Button, gcnew Button };
- int numbuttons = 1;
- Button^ AddBtn(String^ text, System::Windows::Forms::DialogResult result, int btnNumber)
- {
- Button^ btn = buttonrefs[btnNumber];
- btn->Text = text;
- btn->DialogResult = result;
- btn->Anchor = AnchorStyles::Bottom | AnchorStyles::Right;
- btn->Width = btnWidth;
- btn->Height = btnHeight;
- btn->Location = Point(ClientSize.Width - btnWidth * (numbuttons - btnNumber) - btnPadding * (numbuttons - btnNumber), ClientSize.Height - btnHeight - btnPadding);
- Controls->Add(btn);
- //buttonrefs[btnNumber] = btn;
- return btn;
- }
- void SetBackCol(Control^ elem, Color color)
- {
- Type^ elemType = elem->GetType();
- if ((elem->HasChildren || elemType == Button::typeid || elemType == ComboBox::typeid) && elemType != NumericUpDown::typeid)
- {
- elem->BackColor = color;
- for (int i = 0; i < elem->Controls->Count; i++)
- {
- SetBackCol(elem->Controls[i], color);
- }
- }
- }
- void SetForeCol(Control^ elem, Color color)
- {
- Type^ elemType = elem->GetType();
- if (elemType != NumericUpDown::typeid && elemType != TextBox::typeid)
- {
- elem->ForeColor = color;
- }
- if (elem->HasChildren && elemType != NumericUpDown::typeid)
- {
- for (int i = 0; i < elem->Controls->Count; i++)
- {
- SetForeCol(elem->Controls[i], color);
- }
- }
- }
- void SetUIStyle(Control^ elem, FlatStyle style)
- {
- Type^ elemType = elem->GetType();
- if (elemType == Button::typeid)
- {
- ((Button^)elem)->FlatStyle = style;
- }
- else if (elemType == ComboBox::typeid)
- {
- ((ComboBox^)elem)->FlatStyle = style;
- }
- else if (elemType == CheckBox::typeid)
- {
- ((CheckBox^)elem)->FlatStyle = style;
- }
- if (elem->HasChildren && elemType != NumericUpDown::typeid)
- {
- for (int i = 0; i < elem->Controls->Count; i++)
- {
- SetUIStyle(elem->Controls[i], style);
- }
- }
- }
- public:
- SkinnedMessageBoxForm(IWin32Window^ owner, String^ message, String^ caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultbutton, MessageBoxOptions options)
- {
- InitComponentNew();
- Graphics^ grfx = Graphics::FromHwnd(Handle);
- ScaleWidth = Font->SizeInPoints / 72 * grfx->DpiX / 10.67f;
- ScaleHeight = ScaleWidth;
- btnWidth *= ScaleWidth;
- btnHeight *= ScaleHeight;
- btnPadding *= ScaleWidth;
- Width *= ScaleWidth;
- Height *= ScaleHeight;
- if (owner->Handle != IntPtr::Zero)
- {
- Owner = Control::FromHandle(owner->Handle)->FindForm();
- }
- else
- {
- Owner = ActiveForm;
- }
- Text = caption;
- System::Windows::Forms::Padding lblMargin = System::Windows::Forms::Padding(14 * ScaleWidth, 0 * ScaleHeight, 14 * ScaleWidth, 45 * ScaleHeight);
- Point lblLocation = Point(14 * ScaleWidth, 14 * ScaleHeight);
- Drawing::Size lblMinSize = Drawing::Size(ClientSize.Width - lblLocation.X - lblMargin.Right, 0);
- Drawing::Size lblMaxSize = Drawing::Size(600 * ScaleWidth, 0 * ScaleHeight);
- Label^ MessageLbl = gcnew Label();
- MessageLbl->Text = message;
- MessageLbl->AutoSize = true;
- MessageLbl->Margin = lblMargin;
- MessageLbl->Location = lblLocation;
- MessageLbl->MinimumSize = lblMinSize;
- MessageLbl->MaximumSize = lblMaxSize;
- Controls->Add(MessageLbl);
- if (buttons == MessageBoxButtons::OK)
- {
- numbuttons = 1;
- Button^ OkBtn = AddBtn("&OK", System::Windows::Forms::DialogResult::OK, 0);
- CancelButton = OkBtn;
- //(not sure why, but this matches official .NET behaviour)
- }
- else if (buttons == MessageBoxButtons::OKCancel)
- {
- numbuttons = 2;
- AddBtn("&OK", System::Windows::Forms::DialogResult::OK, 0);
- Button^ CancelBtn = AddBtn("&Cancel", System::Windows::Forms::DialogResult::Cancel, 1);
- CancelButton = CancelBtn;
- }
- else if (buttons == MessageBoxButtons::YesNo)
- {
- numbuttons = 2;
- AddBtn("&Yes", System::Windows::Forms::DialogResult::Yes, 0);
- Button^ NoBtn = AddBtn("&No", System::Windows::Forms::DialogResult::No, 1);
- CancelButton = NoBtn;
- //(official .NET doesn't set cancel button, but this seems pretty clear to me...)
- }
- else if (buttons == MessageBoxButtons::RetryCancel)
- {
- numbuttons = 2;
- AddBtn("&Retry", System::Windows::Forms::DialogResult::Retry, 0);
- Button^ CancelBtn = AddBtn("&Cancel", System::Windows::Forms::DialogResult::Cancel, 1);
- CancelButton = CancelBtn;
- }
- else if (buttons == MessageBoxButtons::YesNoCancel)
- {
- numbuttons = 3;
- AddBtn("&Yes", System::Windows::Forms::DialogResult::Yes, 0);
- AddBtn("&No", System::Windows::Forms::DialogResult::No, 1);
- Button^ CancelBtn = AddBtn("&Cancel", System::Windows::Forms::DialogResult::Cancel, 2);
- CancelButton = CancelBtn;
- }
- else if (buttons == MessageBoxButtons::AbortRetryIgnore)
- {
- numbuttons = 3;
- AddBtn("&Abort", System::Windows::Forms::DialogResult::Abort, 0);
- AddBtn("&Retry", System::Windows::Forms::DialogResult::Retry, 1);
- AddBtn("&Ignore", System::Windows::Forms::DialogResult::Ignore, 2);
- //this.CancelButton = IgnoreBtn;
- //(official .NET doesn't set cancel button)
- }
- else
- {
- throw gcnew System::ComponentModel::InvalidEnumArgumentException("buttons", (int)buttons, MessageBoxButtons::typeid);
- }
- if (!CancelButton)
- ControlBox = false;
- if (icon != MessageBoxIcon::None)
- {
- int iconsize = 32 * ScaleWidth;
- int iconpadding = 12 * ScaleWidth;
- int textpadding = -8 * ScaleWidth;
- PictureBox^ iconPB = gcnew PictureBox();
- iconPB->Width = iconsize;
- iconPB->Height = iconsize;
- iconPB->Top = 10 * ScaleHeight;
- iconPB->Left = 10 * ScaleWidth;
- iconPB->AccessibleName = "Icon";
- iconPB->SizeMode = PictureBoxSizeMode::Zoom;
- System::Resources::ResourceManager^ ResMgr = gcnew System::Resources::ResourceManager("Launcher.SkinnedMessageBox", SkinnedMessageBox::typeid->Assembly);
- // there are many duplicated values:
- // https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.messageboxicon?view=netframework-4.7.2
- if (icon == MessageBoxIcon::Error) // also Hand and Stop
- {
- iconPB->Image = (Image^)(ResMgr->GetObject("FeelsThinkMan"));
- iconPB->AccessibleDescription = "Error";
- //this.Icon = SystemIcons.Error;
- System::Media::SystemSounds::Hand->Play();
- }
- else if (icon == MessageBoxIcon::Question)
- {
- iconPB->Image = (Image^)(ResMgr->GetObject("PokeWhat4xvc2"));
- iconPB->AccessibleDescription = "Question";
- //this.Icon = SystemIcons.Question;
- System::Media::SystemSounds::Question->Play();
- }
- else if (icon == MessageBoxIcon::Warning) // also Exclamation
- {
- iconPB->Image = (Image^)(ResMgr->GetObject("PokeSnarf4xd"));
- iconPB->AccessibleDescription = "Warning";
- //this.Icon = SystemIcons.Warning;
- //textpadding -= 2 * ScaleWidth; // triangle shape looks worse without this
- System::Media::SystemSounds::Exclamation->Play();
- }
- else if (icon == MessageBoxIcon::Information) // also Asterisk
- {
- /*Drawing::Icon^ infoicon = gcnew Drawing::Icon(SystemIcons::Information, iconsize, iconsize);
- iconPB->Image = infoicon->ToBitmap();
- iconPB->AccessibleDescription = "Information";
- //this.Icon = SystemIcons.Question;
- System::Media::SystemSounds::Asterisk->Play();*/
- iconPB->Image = (Image^)(ResMgr->GetObject("Help"));
- iconPB->AccessibleDescription = "Question";
- //this.Icon = SystemIcons.Question;
- System::Media::SystemSounds::Question->Play();
- }
- else
- {
- throw gcnew System::ComponentModel::InvalidEnumArgumentException("icon", (int)icon, MessageBoxIcon::typeid);
- }
- MessageLbl->MinimumSize = Drawing::Size(MessageLbl->MinimumSize.Width - (iconsize + iconpadding + textpadding), MessageLbl->MinimumSize.Height);
- MessageLbl->Left += (iconsize + iconpadding + textpadding);
- Controls->Add(iconPB);
- }
- if (defaultbutton == MessageBoxDefaultButton::Button1)
- {
- AcceptButton = buttonrefs[0];
- ActiveControl = buttonrefs[0];
- }
- else if (defaultbutton == MessageBoxDefaultButton::Button2)
- {
- if (!Controls->Contains(buttonrefs[1])) throw gcnew ArgumentOutOfRangeException("defaultbutton", "defaultbutton cannot be set to a button number that does not exist");
- AcceptButton = buttonrefs[1];
- ActiveControl = buttonrefs[1];
- }
- else if (defaultbutton == MessageBoxDefaultButton::Button3)
- {
- if (!Controls->Contains(buttonrefs[2])) throw gcnew ArgumentOutOfRangeException("defaultbutton", "defaultbutton cannot be set to a button number that does not exist");
- AcceptButton = buttonrefs[2];
- ActiveControl = buttonrefs[2];
- }
- else
- {
- throw gcnew System::ComponentModel::InvalidEnumArgumentException("defaultbutton", (int)defaultbutton, MessageBoxDefaultButton::typeid);
- }
- // TODO: TEXT ALIGNMENT AND RTL MODE
- /*
- // MessageBoxOptions are more like flags than concrete settings.
- // For ease of use, we assume default value is whatever winforms gives us in current locale -- but we override if any value is set
- if ((options & MessageBoxOptions.RightAlign) == MessageBoxOptions.RightAlign) MessageLbl.TextAlign = ContentAlignment.TopRight;
- else if (options != 0) MessageLbl.TextAlign = ContentAlignment.TopLeft;
-
- // RtlReading should be what actually affects layout, and RightAlign only affects the text label
- if ((options & MessageBoxOptions.RtlReading) == MessageBoxOptions.RtlReading)
- {
- foreach (Control control in this.Controls)
- {
- control.Left = this.ClientSize.Width - control.Right;
- control.RightToLeft = RightToLeft.Yes;
- }
- this.RightToLeft = RightToLeft.Yes;
- this.RightToLeftLayout = true;
- }
- else if (options != 0)
- {
- foreach (Control control in this.Controls)
- {
- control.RightToLeft = RightToLeft.No;
- }
- this.RightToLeft = RightToLeft.No;
- this.RightToLeftLayout = false;
- }
- */
- SetBackCol(this, Color::FromArgb(64, 64, 64));
- SetForeCol(this, Color::White);
- SetUIStyle(this, FlatStyle::Flat);
- }
- SkinnedMessageBoxForm(String^ message, String^ caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultbutton, MessageBoxOptions options)
- {
- SkinnedMessageBoxForm(NativeWindow::FromHandle((IntPtr::Zero)), message, caption, buttons, icon, defaultbutton, options);
- }
- };
- public:
- static DialogResult Show(IWin32Window^ owner, String^ message, String^ caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultbutton, MessageBoxOptions options)
- {
- // I probably shouldn't do this, but from what I can tell this should be safe enough -- out of thread owner is allowed
- // and it only seems to appear when debugging (???)
- Control::CheckForIllegalCrossThreadCalls = false;
- SkinnedMessageBoxForm^ mb = gcnew SkinnedMessageBoxForm(owner, message, caption, buttons, icon, defaultbutton, options);
- DialogResult res = mb->ShowDialog();
- Control::CheckForIllegalCrossThreadCalls = true;
- return res;
- }
- static DialogResult Show(IWin32Window^ owner, String^ message, String^ caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultbutton)
- {
- return Show(owner, message, caption, buttons, icon, defaultbutton, (MessageBoxOptions)0);
- }
- static DialogResult Show(IWin32Window^ owner, String^ message, String^ caption, MessageBoxButtons buttons, MessageBoxIcon icon)
- {
- return Show(owner, message, caption, buttons, icon, MessageBoxDefaultButton::Button1, (MessageBoxOptions)0);
- }
- static DialogResult Show(IWin32Window^ owner, String^ message, String^ caption, MessageBoxButtons buttons)
- {
- return Show(owner, message, caption, buttons, MessageBoxIcon::None, MessageBoxDefaultButton::Button1, (MessageBoxOptions)0);
- }
- static DialogResult Show(IWin32Window^ owner, String^ message, String^ caption)
- {
- return Show(owner, message, caption, MessageBoxButtons::OK, MessageBoxIcon::None, MessageBoxDefaultButton::Button1, (MessageBoxOptions)0);
- }
- static DialogResult Show(IWin32Window^ owner, String^ message)
- {
- return Show(owner, message, "", MessageBoxButtons::OK, MessageBoxIcon::None, MessageBoxDefaultButton::Button1, (MessageBoxOptions)0);
- }
- };
|