mirror of
https://github.com/mogzol/BrawlBuilder.git
synced 2024-11-16 14:49:21 +01:00
Improve error messages, and numerous other fixes
Changed how the main builder method works, now uses a state-based system. Wit error messages should now show more details about the error. The "Build Completed" sometimes appearing even if the build did not complete properly bug has (hopefully) been fixed, it should give you an error now if it didn't make it to the final stage. The --show-wit-debug option has been added which keeps wit windows open after wit finishes, to help with debugging The help text for the Brawl ISO has been edited to clarify how the ssbb.d folder works A crash if building with no GCT selected has been fixed Added some files that were missing from the Resources folder in the git repo. Updated readme's Upped assembly version Other code cleanup and misc. fixes
This commit is contained in:
parent
ba4b6f6708
commit
2cbbae72cd
@ -8,12 +8,28 @@ using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using JR.Utils.GUI.Forms;
|
||||
|
||||
namespace BrawlBuilder
|
||||
{
|
||||
partial class BrawlBuilder
|
||||
{
|
||||
private enum State
|
||||
{
|
||||
Analyze,
|
||||
Extract,
|
||||
Verify,
|
||||
DeleteSSE,
|
||||
CopyModFiles,
|
||||
CopyBanner,
|
||||
Patch,
|
||||
Build,
|
||||
Finish
|
||||
}
|
||||
|
||||
private bool _remove_en;
|
||||
private bool _showWit;
|
||||
private State _state;
|
||||
|
||||
private void buildWorker_DoWork(object sender, DoWorkEventArgs e)
|
||||
{
|
||||
@ -21,14 +37,15 @@ namespace BrawlBuilder
|
||||
_remove_en = false;
|
||||
|
||||
// Set up wit
|
||||
bool showWit = Environment.GetCommandLineArgs().Contains("--show-wit");
|
||||
_showWit = Environment.GetCommandLineArgs().Contains("--show-wit") || Environment.GetCommandLineArgs().Contains("--show-wit-debug");
|
||||
|
||||
if (!File.Exists(@".\Resources\wit\wit.exe"))
|
||||
StopWorker("Unable to find wit executable, stopping build...");
|
||||
ProcessStartInfo pStartInfo = new ProcessStartInfo(@".\Resources\wit\wit.exe");
|
||||
pStartInfo.CreateNoWindow = !showWit;
|
||||
pStartInfo.UseShellExecute = showWit;
|
||||
pStartInfo.RedirectStandardOutput = !showWit;
|
||||
pStartInfo.CreateNoWindow = !_showWit;
|
||||
pStartInfo.UseShellExecute = _showWit;
|
||||
pStartInfo.RedirectStandardOutput = !_showWit;
|
||||
pStartInfo.RedirectStandardError = !_showWit;
|
||||
|
||||
if (buildWorker.CancellationPending)
|
||||
{
|
||||
@ -64,83 +81,104 @@ namespace BrawlBuilder
|
||||
return;
|
||||
}
|
||||
|
||||
// STAGE 1: Analyze GCT
|
||||
File.Delete(@"./Resources/temp.gct"); // Make sure any leftover gct gets removed
|
||||
if (!Environment.GetCommandLineArgs().Contains("--no-gct-patch"))
|
||||
|
||||
// Set state to the starting state
|
||||
_state = State.Analyze;
|
||||
|
||||
while (_state != State.Finish)
|
||||
{
|
||||
if (!Analyze())
|
||||
switch (_state)
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
case State.Analyze:
|
||||
if (gctFile.Text != "" && !Environment.GetCommandLineArgs().Contains("--no-gct-patch"))
|
||||
{
|
||||
if (!Analyze())
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
_state = State.Extract;
|
||||
break;
|
||||
|
||||
case State.Extract:
|
||||
if (!Extract(pStartInfo))
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
_state = State.Verify;
|
||||
break;
|
||||
|
||||
case State.Verify:
|
||||
if (!Verify())
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
_state = State.DeleteSSE;
|
||||
break;
|
||||
|
||||
case State.DeleteSSE:
|
||||
if (removeSubspace.Checked)
|
||||
{
|
||||
if (!DeleteSSE())
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
_state = State.CopyModFiles;
|
||||
break;
|
||||
|
||||
case State.CopyModFiles:
|
||||
if (modFolder.Text != "")
|
||||
{
|
||||
if (!CopyModFiles())
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
_state = State.CopyBanner;
|
||||
break;
|
||||
|
||||
case State.CopyBanner:
|
||||
if (customBanner.Checked)
|
||||
{
|
||||
if (!CopyBanner())
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
_state = State.Patch;
|
||||
break;
|
||||
|
||||
case State.Patch:
|
||||
if (gctFile.Text != "" || customID.Checked)
|
||||
{
|
||||
if (!Patch(pStartInfo))
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
_state = State.Build;
|
||||
break;
|
||||
|
||||
case State.Build:
|
||||
if (!Build(pStartInfo))
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
_state = State.Finish;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// STAGE 2: Extract Brawl
|
||||
if (!Extract(pStartInfo))
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// STAGE 3: Verify files
|
||||
if (!Verify())
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// STAGE 4: Delete Subspace Emissary
|
||||
if (removeSubspace.Checked)
|
||||
{
|
||||
if (!DeleteSSE())
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// STAGE 5: Apply mod files
|
||||
if (modFolder.Text != "")
|
||||
{
|
||||
if (!CopyModFiles())
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// STAGE 6: Apply banner
|
||||
if (customBanner.Checked)
|
||||
{
|
||||
if (!CopyBanner())
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// STAGE 7: Patch main.dol
|
||||
if (gctFile.Text != "" || customID.Checked)
|
||||
{
|
||||
if (!Patch(pStartInfo))
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// STAGE 8: Build Brawl
|
||||
if (!Build(pStartInfo))
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up
|
||||
DeleteBrawlFolder();
|
||||
}
|
||||
@ -185,7 +223,6 @@ namespace BrawlBuilder
|
||||
_remove_en = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
action = line;
|
||||
|
||||
@ -340,23 +377,8 @@ namespace BrawlBuilder
|
||||
// Extract brawl to ssbb.d folder
|
||||
pStartInfo.Arguments = "extract \"" + brawlIso.Text + "\" ssbb.d --psel=DATA -1ovv";
|
||||
|
||||
if (pStartInfo.RedirectStandardOutput)
|
||||
{
|
||||
if (!DoWitWithProgress(pStartInfo))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// --show-wit option was set
|
||||
Process p = Process.Start(pStartInfo);
|
||||
p.WaitForExit();
|
||||
|
||||
// Check wit exit code
|
||||
if (p.ExitCode != 0)
|
||||
StopWorker("Wit closed unexpectedly with exit code " + p.ExitCode + ", stopping build...");
|
||||
|
||||
p.Dispose();
|
||||
}
|
||||
if (!DoWit(pStartInfo))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Directory.Exists("ssbb.d"))
|
||||
@ -678,13 +700,9 @@ namespace BrawlBuilder
|
||||
SetStatus("Patching...");
|
||||
|
||||
pStartInfo.Arguments = "dolpatch ssbb.d/sys/main.dol" + patchArgs;
|
||||
Process p = Process.Start(pStartInfo);
|
||||
p.WaitForExit();
|
||||
|
||||
if (p.ExitCode != 0)
|
||||
StopWorker("Wit closed unexpectedly with exit code " + p.ExitCode + ", stopping build...");
|
||||
|
||||
p.Dispose();
|
||||
if (!DoWit(pStartInfo, true))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buildWorker.CancellationPending)
|
||||
@ -712,51 +730,33 @@ namespace BrawlBuilder
|
||||
|
||||
pStartInfo.Arguments = "copy ssbb.d \"" + _saveFileName + "\" -ovv" + (splitOutput ? "z" : "") + (customID.Checked ? " --id=" + gameID.Text : "") + (cutomTitle.Checked ? " --name \"" + gameTitle.Text + "\"" : "");
|
||||
|
||||
if (pStartInfo.RedirectStandardOutput)
|
||||
{
|
||||
if (!DoWitWithProgress(pStartInfo))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// --show-wit option set
|
||||
Process p = Process.Start(pStartInfo);
|
||||
p.WaitForExit();
|
||||
|
||||
// Check wit exit code
|
||||
if (p.ExitCode != 0)
|
||||
StopWorker("Wit closed unexpectedly with exit code " + p.ExitCode + ", stopping build...");
|
||||
|
||||
p.Dispose();
|
||||
}
|
||||
|
||||
// Make sure wit created the file
|
||||
if (!File.Exists(_saveFileName))
|
||||
StopWorker("Build failed, stopping...");
|
||||
if (!DoWit(pStartInfo))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool DoWitWithProgress(ProcessStartInfo pStartInfo)
|
||||
private bool DoWit(ProcessStartInfo pStartInfo, bool forceNoProgress = false)
|
||||
{
|
||||
// Set up blinker
|
||||
_progress = 0;
|
||||
_progressMax = 100;
|
||||
if (blinker.IsBusy)
|
||||
// Determine if we want wit to be hidden or not
|
||||
if (!_showWit && !forceNoProgress)
|
||||
{
|
||||
blinker.CancelAsync();
|
||||
while (blinker.IsBusy)
|
||||
// Set up blinker
|
||||
_progress = 0;
|
||||
_progressMax = 100;
|
||||
if (blinker.IsBusy)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
blinker.CancelAsync();
|
||||
while (blinker.IsBusy)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
blinker.RunWorkerAsync();
|
||||
blinker.RunWorkerAsync();
|
||||
|
||||
// Create outside of loop for better performance
|
||||
Regex r = new Regex(@"(\d+)%");
|
||||
// Create outside of loop for better performance
|
||||
Regex r = new Regex(@"(\d+)%");
|
||||
|
||||
if (pStartInfo.RedirectStandardOutput)
|
||||
{
|
||||
using (Process p = Process.Start(pStartInfo))
|
||||
{
|
||||
using (StreamReader reader = p.StandardOutput)
|
||||
@ -773,7 +773,7 @@ namespace BrawlBuilder
|
||||
if (!p.HasExited)
|
||||
{
|
||||
p.Kill();
|
||||
p.WaitForExit(5000);
|
||||
p.WaitForExit();
|
||||
}
|
||||
|
||||
break;
|
||||
@ -793,7 +793,7 @@ namespace BrawlBuilder
|
||||
if (!p.HasExited)
|
||||
{
|
||||
p.Kill();
|
||||
p.WaitForExit(5000);
|
||||
p.WaitForExit();
|
||||
}
|
||||
|
||||
// Didn't finish working, delete ssbb.d
|
||||
@ -806,9 +806,54 @@ namespace BrawlBuilder
|
||||
}
|
||||
}
|
||||
|
||||
string error = "";
|
||||
using (StreamReader s = p.StandardError)
|
||||
{
|
||||
error = s.ReadToEnd();
|
||||
}
|
||||
|
||||
// Check wit exit code
|
||||
if (p.ExitCode != 0)
|
||||
StopWorker("Wit closed unexpectedly with exit code " + p.ExitCode + ", stopping build...");
|
||||
{
|
||||
StopWorker("Wit closed unexpectedly with exit code " + p.ExitCode + ", stopping build..." + (error.Length > 0 ? "\n\nWit error messages:\n\n" + error : ""), error.Length > 0);
|
||||
}
|
||||
// If there were errors, but exit code was fine, notify the user, but let them continue
|
||||
else if (error.Length > 0)
|
||||
{
|
||||
DialogResult result = FlexibleMessageBox.Show("Wit didn't exit with an error code, however it did write to the error output with the following:\n\n" + error + "\n\nDo you still want to continue the build?", "Notice", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||||
|
||||
if (result == DialogResult.No)
|
||||
buildWorker.CancelAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if we want to keep the window open after, and handle that if we do
|
||||
if (Environment.GetCommandLineArgs().Contains("--show-wit-debug"))
|
||||
{
|
||||
ProcessStartInfo newStartInfo = new ProcessStartInfo();
|
||||
newStartInfo.FileName = "CMD.exe";
|
||||
newStartInfo.Arguments = "/C \"\"" + pStartInfo.FileName + "\" " + pStartInfo.Arguments + " & pause & if errorlevel 1 exit -1\"";
|
||||
pStartInfo = newStartInfo;
|
||||
}
|
||||
|
||||
using (Process p = Process.Start(pStartInfo))
|
||||
{
|
||||
p.WaitForExit();
|
||||
|
||||
if (p.ExitCode != 0)
|
||||
{
|
||||
if (Environment.GetCommandLineArgs().Contains("--show-wit-debug"))
|
||||
{
|
||||
// The exit code won't be accurate, so just say Wit closed
|
||||
StopWorker("Wit closed unexpectedly, stopping build...");
|
||||
}
|
||||
else
|
||||
{
|
||||
StopWorker("Wit closed unexpectedly with exit code " + p.ExitCode + ", stopping build...");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -843,9 +888,13 @@ namespace BrawlBuilder
|
||||
}
|
||||
}
|
||||
|
||||
private void StopWorker(string message)
|
||||
private void StopWorker(string message, bool flex = false)
|
||||
{
|
||||
MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
if (flex)
|
||||
FlexibleMessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
else
|
||||
MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
|
||||
buildWorker.CancelAsync();
|
||||
}
|
||||
|
||||
@ -859,12 +908,17 @@ namespace BrawlBuilder
|
||||
|
||||
private void buildWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
||||
{
|
||||
// Clean up temp files
|
||||
// Clean up files
|
||||
File.Delete(@".\Resources\temp.gct");
|
||||
|
||||
if (_exiting)
|
||||
Environment.Exit(1);
|
||||
|
||||
// Stop the blinker if it is running
|
||||
blinker.CancelAsync();
|
||||
while (blinker.IsBusy)
|
||||
Thread.Sleep(100);
|
||||
|
||||
// Re-enable controls
|
||||
foreach (Control c in Controls)
|
||||
{
|
||||
@ -880,8 +934,53 @@ namespace BrawlBuilder
|
||||
Activate();
|
||||
|
||||
// Show success if builder actually finished
|
||||
if (e.Cancelled != true)
|
||||
MessageBox.Show("Build Completed!", "Success!", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
if (_state == State.Finish)
|
||||
{
|
||||
if (File.Exists(_saveFileName))
|
||||
{
|
||||
MessageBox.Show("Build Completed!", "Success!", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("BrawlBuilder did not encounter any errors during the build process, but the output image doesn't seem to exist, which indicates that the build did not complete successfully. Sorry about that.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
else if (!e.Cancelled)
|
||||
{
|
||||
string message = "";
|
||||
switch(_state)
|
||||
{
|
||||
case State.Analyze:
|
||||
message = "Build failed due to an unknown error while patching the GCT file.";
|
||||
break;
|
||||
case State.Verify:
|
||||
message = "Build failed due to an unknown error while verifiying the Brawl image.";
|
||||
break;
|
||||
case State.Extract:
|
||||
message = "Build failed due to an unknown error while extracting the Brawl image.";
|
||||
break;
|
||||
case State.DeleteSSE:
|
||||
message = "Build failed due to an unknown error while deleting Subspace Emissary files.";
|
||||
break;
|
||||
case State.CopyModFiles:
|
||||
message = "Build failed due to an unknown error while copying mod files.";
|
||||
break;
|
||||
case State.CopyBanner:
|
||||
message = "Build failed due to an unknown error while copying the custom banner.";
|
||||
break;
|
||||
case State.Patch:
|
||||
message = "Build failed due to an unknown error while applying the GCT file to the Brawl image.";
|
||||
break;
|
||||
case State.Build:
|
||||
message = "Build failed due to an unkonwn error while building the modded Brawl image.";
|
||||
break;
|
||||
default:
|
||||
message = "Build failed due to an unknown error.";
|
||||
break;
|
||||
}
|
||||
|
||||
MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void blinker_DoWork(object sender, DoWorkEventArgs e)
|
||||
@ -901,7 +1000,7 @@ namespace BrawlBuilder
|
||||
if (blinker.CancellationPending)
|
||||
break;
|
||||
|
||||
// 'Sleep' for ~4000ms, but also updates
|
||||
// 'Sleep' for ~4000ms, but also update & cancel faster
|
||||
for (int i = 0; i < 40; i++)
|
||||
{
|
||||
float percent = (int)((float)_progress / _progressMax * 100);
|
||||
|
@ -80,7 +80,7 @@ namespace BrawlBuilder
|
||||
|
||||
private void brawlIso_lbl_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
{
|
||||
MessageBox.Show("Select your unmodded Brawl disk image. This can be an ISO, CISO, WBFS, WBI, WIA, or WDF file\n\nNote: If there is an ssbb.d folder containing all of Brawl's files in the same folder as this application, then this field is unnecessary.", "Help", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBox.Show("Select your unmodded Brawl disk image. This can be an ISO, CISO, WBFS, WBI, WIA, or WDF file\n\nNote: If you have a folder containing all of Brawl's files extracted using wit, then you can also just copy the contents of that folder to an 'ssbb.d' folder in the same directory as BrawlBuilder, and this field will be unnecessary.", "Help", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
|
||||
private void brawlIsoBrowse_Click(object sender, EventArgs e)
|
||||
|
@ -58,6 +58,7 @@
|
||||
<Compile Include="BrawlBuilder.WorkerCode.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="FlexibleMessageBox.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<EmbeddedResource Include="BrawlBuilder.resx">
|
||||
|
862
BrawlBuilder/FlexibleMessageBox.cs
Normal file
862
BrawlBuilder/FlexibleMessageBox.cs
Normal file
@ -0,0 +1,862 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace JR.Utils.GUI.Forms
|
||||
{
|
||||
/* FlexibleMessageBox – A flexible replacement for the .NET MessageBox
|
||||
*
|
||||
* Author: Jörg Reichert (public@jreichert.de)
|
||||
* Contributors: Thanks to: David Hall, Roink
|
||||
* Version: 1.3
|
||||
* Published at: http://www.codeproject.com/Articles/601900/FlexibleMessageBox
|
||||
*
|
||||
************************************************************************************************************
|
||||
* Features:
|
||||
* - It can be simply used instead of MessageBox since all important static "Show"-Functions are supported
|
||||
* - It is small, only one source file, which could be added easily to each solution
|
||||
* - It can be resized and the content is correctly word-wrapped
|
||||
* - It tries to auto-size the width to show the longest text row
|
||||
* - It never exceeds the current desktop working area
|
||||
* - It displays a vertical scrollbar when needed
|
||||
* - It does support hyperlinks in text
|
||||
*
|
||||
* Because the interface is identical to MessageBox, you can add this single source file to your project
|
||||
* and use the FlexibleMessageBox almost everywhere you use a standard MessageBox.
|
||||
* The goal was NOT to produce as many features as possible but to provide a simple replacement to fit my
|
||||
* own needs. Feel free to add additional features on your own, but please left my credits in this class.
|
||||
*
|
||||
************************************************************************************************************
|
||||
* Usage examples:
|
||||
*
|
||||
* FlexibleMessageBox.Show("Just a text");
|
||||
*
|
||||
* FlexibleMessageBox.Show("A text",
|
||||
* "A caption");
|
||||
*
|
||||
* FlexibleMessageBox.Show("Some text with a link: www.google.com",
|
||||
* "Some caption",
|
||||
* MessageBoxButtons.AbortRetryIgnore,
|
||||
* MessageBoxIcon.Information,
|
||||
* MessageBoxDefaultButton.Button2);
|
||||
*
|
||||
* var dialogResult = FlexibleMessageBox.Show("Do you know the answer to life the universe and everything?",
|
||||
* "One short question",
|
||||
* MessageBoxButtons.YesNo);
|
||||
*
|
||||
************************************************************************************************************
|
||||
* THE SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS", WITHOUT WARRANTY
|
||||
* OF ANY KIND, EXPRESS OR IMPLIED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF THIS
|
||||
* SOFTWARE.
|
||||
*
|
||||
************************************************************************************************************
|
||||
* History:
|
||||
* Version 1.3 - 19.Dezember 2014
|
||||
* - Added refactoring function GetButtonText()
|
||||
* - Used CurrentUICulture instead of InstalledUICulture
|
||||
* - Added more button localizations. Supported languages are now: ENGLISH, GERMAN, SPANISH, ITALIAN
|
||||
* - Added standard MessageBox handling for "copy to clipboard" with <Ctrl> + <C> and <Ctrl> + <Insert>
|
||||
* - Tab handling is now corrected (only tabbing over the visible buttons)
|
||||
* - Added standard MessageBox handling for ALT-Keyboard shortcuts
|
||||
* - SetDialogSizes: Refactored completely: Corrected sizing and added caption driven sizing
|
||||
*
|
||||
* Version 1.2 - 10.August 2013
|
||||
* - Do not ShowInTaskbar anymore (original MessageBox is also hidden in taskbar)
|
||||
* - Added handling for Escape-Button
|
||||
* - Adapted top right close button (red X) to behave like MessageBox (but hidden instead of deactivated)
|
||||
*
|
||||
* Version 1.1 - 14.June 2013
|
||||
* - Some Refactoring
|
||||
* - Added internal form class
|
||||
* - Added missing code comments, etc.
|
||||
*
|
||||
* Version 1.0 - 15.April 2013
|
||||
* - Initial Version
|
||||
*/
|
||||
public class FlexibleMessageBox
|
||||
{
|
||||
#region Public statics
|
||||
|
||||
/// <summary>
|
||||
/// Defines the maximum width for all FlexibleMessageBox instances in percent of the working area.
|
||||
///
|
||||
/// Allowed values are 0.2 - 1.0 where:
|
||||
/// 0.2 means: The FlexibleMessageBox can be at most half as wide as the working area.
|
||||
/// 1.0 means: The FlexibleMessageBox can be as wide as the working area.
|
||||
///
|
||||
/// Default is: 70% of the working area width.
|
||||
/// </summary>
|
||||
public static double MAX_WIDTH_FACTOR = 0.7;
|
||||
|
||||
/// <summary>
|
||||
/// Defines the maximum height for all FlexibleMessageBox instances in percent of the working area.
|
||||
///
|
||||
/// Allowed values are 0.2 - 1.0 where:
|
||||
/// 0.2 means: The FlexibleMessageBox can be at most half as high as the working area.
|
||||
/// 1.0 means: The FlexibleMessageBox can be as high as the working area.
|
||||
///
|
||||
/// Default is: 90% of the working area height.
|
||||
/// </summary>
|
||||
public static double MAX_HEIGHT_FACTOR = 0.9;
|
||||
|
||||
/// <summary>
|
||||
/// Defines the font for all FlexibleMessageBox instances.
|
||||
///
|
||||
/// Default is: SystemFonts.MessageBoxFont
|
||||
/// </summary>
|
||||
public static Font FONT = SystemFonts.MessageBoxFont;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public show functions
|
||||
|
||||
/// <summary>
|
||||
/// Shows the specified message box.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <returns>The dialog result.</returns>
|
||||
public static DialogResult Show(string text)
|
||||
{
|
||||
return FlexibleMessageBoxForm.Show(null, text, string.Empty, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the specified message box.
|
||||
/// </summary>
|
||||
/// <param name="owner">The owner.</param>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <returns>The dialog result.</returns>
|
||||
public static DialogResult Show(IWin32Window owner, string text)
|
||||
{
|
||||
return FlexibleMessageBoxForm.Show(owner, text, string.Empty, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the specified message box.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="caption">The caption.</param>
|
||||
/// <returns>The dialog result.</returns>
|
||||
public static DialogResult Show(string text, string caption)
|
||||
{
|
||||
return FlexibleMessageBoxForm.Show(null, text, caption, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the specified message box.
|
||||
/// </summary>
|
||||
/// <param name="owner">The owner.</param>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="caption">The caption.</param>
|
||||
/// <returns>The dialog result.</returns>
|
||||
public static DialogResult Show(IWin32Window owner, string text, string caption)
|
||||
{
|
||||
return FlexibleMessageBoxForm.Show(owner, text, caption, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the specified message box.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="caption">The caption.</param>
|
||||
/// <param name="buttons">The buttons.</param>
|
||||
/// <returns>The dialog result.</returns>
|
||||
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons)
|
||||
{
|
||||
return FlexibleMessageBoxForm.Show(null, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the specified message box.
|
||||
/// </summary>
|
||||
/// <param name="owner">The owner.</param>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="caption">The caption.</param>
|
||||
/// <param name="buttons">The buttons.</param>
|
||||
/// <returns>The dialog result.</returns>
|
||||
public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons)
|
||||
{
|
||||
return FlexibleMessageBoxForm.Show(owner, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the specified message box.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="caption">The caption.</param>
|
||||
/// <param name="buttons">The buttons.</param>
|
||||
/// <param name="icon">The icon.</param>
|
||||
/// <returns></returns>
|
||||
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon)
|
||||
{
|
||||
return FlexibleMessageBoxForm.Show(null, text, caption, buttons, icon, MessageBoxDefaultButton.Button1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the specified message box.
|
||||
/// </summary>
|
||||
/// <param name="owner">The owner.</param>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="caption">The caption.</param>
|
||||
/// <param name="buttons">The buttons.</param>
|
||||
/// <param name="icon">The icon.</param>
|
||||
/// <returns>The dialog result.</returns>
|
||||
public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon)
|
||||
{
|
||||
return FlexibleMessageBoxForm.Show(owner, text, caption, buttons, icon, MessageBoxDefaultButton.Button1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the specified message box.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="caption">The caption.</param>
|
||||
/// <param name="buttons">The buttons.</param>
|
||||
/// <param name="icon">The icon.</param>
|
||||
/// <param name="defaultButton">The default button.</param>
|
||||
/// <returns>The dialog result.</returns>
|
||||
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
|
||||
{
|
||||
return FlexibleMessageBoxForm.Show(null, text, caption, buttons, icon, defaultButton);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the specified message box.
|
||||
/// </summary>
|
||||
/// <param name="owner">The owner.</param>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="caption">The caption.</param>
|
||||
/// <param name="buttons">The buttons.</param>
|
||||
/// <param name="icon">The icon.</param>
|
||||
/// <param name="defaultButton">The default button.</param>
|
||||
/// <returns>The dialog result.</returns>
|
||||
public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
|
||||
{
|
||||
return FlexibleMessageBoxForm.Show(owner, text, caption, buttons, icon, defaultButton);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal form class
|
||||
|
||||
/// <summary>
|
||||
/// The form to show the customized message box.
|
||||
/// It is defined as an internal class to keep the public interface of the FlexibleMessageBox clean.
|
||||
/// </summary>
|
||||
class FlexibleMessageBoxForm : Form
|
||||
{
|
||||
#region Form-Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Erforderliche Designervariable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Verwendete Ressourcen bereinigen.
|
||||
/// </summary>
|
||||
/// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Erforderliche Methode für die Designerunterstützung.
|
||||
/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.button1 = new System.Windows.Forms.Button();
|
||||
this.richTextBoxMessage = new System.Windows.Forms.RichTextBox();
|
||||
this.FlexibleMessageBoxFormBindingSource = new System.Windows.Forms.BindingSource(this.components);
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.pictureBoxForIcon = new System.Windows.Forms.PictureBox();
|
||||
this.button2 = new System.Windows.Forms.Button();
|
||||
this.button3 = new System.Windows.Forms.Button();
|
||||
((System.ComponentModel.ISupportInitialize)(this.FlexibleMessageBoxFormBindingSource)).BeginInit();
|
||||
this.panel1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBoxForIcon)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// button1
|
||||
//
|
||||
this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.button1.AutoSize = true;
|
||||
this.button1.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.button1.Location = new System.Drawing.Point(11, 67);
|
||||
this.button1.MinimumSize = new System.Drawing.Size(0, 24);
|
||||
this.button1.Name = "button1";
|
||||
this.button1.Size = new System.Drawing.Size(75, 24);
|
||||
this.button1.TabIndex = 2;
|
||||
this.button1.Text = "OK";
|
||||
this.button1.UseVisualStyleBackColor = true;
|
||||
this.button1.Visible = false;
|
||||
//
|
||||
// richTextBoxMessage
|
||||
//
|
||||
this.richTextBoxMessage.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.richTextBoxMessage.BackColor = System.Drawing.Color.White;
|
||||
this.richTextBoxMessage.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this.richTextBoxMessage.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.FlexibleMessageBoxFormBindingSource, "MessageText", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||
this.richTextBoxMessage.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.richTextBoxMessage.Location = new System.Drawing.Point(50, 26);
|
||||
this.richTextBoxMessage.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.richTextBoxMessage.Name = "richTextBoxMessage";
|
||||
this.richTextBoxMessage.ReadOnly = true;
|
||||
this.richTextBoxMessage.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical;
|
||||
this.richTextBoxMessage.Size = new System.Drawing.Size(200, 20);
|
||||
this.richTextBoxMessage.TabIndex = 0;
|
||||
this.richTextBoxMessage.TabStop = false;
|
||||
this.richTextBoxMessage.Text = "<Message>";
|
||||
this.richTextBoxMessage.LinkClicked += new System.Windows.Forms.LinkClickedEventHandler(this.richTextBoxMessage_LinkClicked);
|
||||
//
|
||||
// panel1
|
||||
//
|
||||
this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.panel1.BackColor = System.Drawing.Color.White;
|
||||
this.panel1.Controls.Add(this.pictureBoxForIcon);
|
||||
this.panel1.Controls.Add(this.richTextBoxMessage);
|
||||
this.panel1.Location = new System.Drawing.Point(-3, -4);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Size = new System.Drawing.Size(268, 59);
|
||||
this.panel1.TabIndex = 1;
|
||||
//
|
||||
// pictureBoxForIcon
|
||||
//
|
||||
this.pictureBoxForIcon.BackColor = System.Drawing.Color.Transparent;
|
||||
this.pictureBoxForIcon.Location = new System.Drawing.Point(15, 19);
|
||||
this.pictureBoxForIcon.Name = "pictureBoxForIcon";
|
||||
this.pictureBoxForIcon.Size = new System.Drawing.Size(32, 32);
|
||||
this.pictureBoxForIcon.TabIndex = 8;
|
||||
this.pictureBoxForIcon.TabStop = false;
|
||||
//
|
||||
// button2
|
||||
//
|
||||
this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.button2.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.button2.Location = new System.Drawing.Point(92, 67);
|
||||
this.button2.MinimumSize = new System.Drawing.Size(0, 24);
|
||||
this.button2.Name = "button2";
|
||||
this.button2.Size = new System.Drawing.Size(75, 24);
|
||||
this.button2.TabIndex = 3;
|
||||
this.button2.Text = "OK";
|
||||
this.button2.UseVisualStyleBackColor = true;
|
||||
this.button2.Visible = false;
|
||||
//
|
||||
// button3
|
||||
//
|
||||
this.button3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.button3.AutoSize = true;
|
||||
this.button3.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.button3.Location = new System.Drawing.Point(173, 67);
|
||||
this.button3.MinimumSize = new System.Drawing.Size(0, 24);
|
||||
this.button3.Name = "button3";
|
||||
this.button3.Size = new System.Drawing.Size(75, 24);
|
||||
this.button3.TabIndex = 0;
|
||||
this.button3.Text = "OK";
|
||||
this.button3.UseVisualStyleBackColor = true;
|
||||
this.button3.Visible = false;
|
||||
//
|
||||
// FlexibleMessageBoxForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(260, 102);
|
||||
this.Controls.Add(this.button3);
|
||||
this.Controls.Add(this.button2);
|
||||
this.Controls.Add(this.panel1);
|
||||
this.Controls.Add(this.button1);
|
||||
this.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.FlexibleMessageBoxFormBindingSource, "CaptionText", true));
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.MinimumSize = new System.Drawing.Size(276, 140);
|
||||
this.Name = "FlexibleMessageBoxForm";
|
||||
this.ShowIcon = false;
|
||||
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "<Caption>";
|
||||
this.Shown += new System.EventHandler(this.FlexibleMessageBoxForm_Shown);
|
||||
((System.ComponentModel.ISupportInitialize)(this.FlexibleMessageBoxFormBindingSource)).EndInit();
|
||||
this.panel1.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBoxForIcon)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
}
|
||||
|
||||
private System.Windows.Forms.Button button1;
|
||||
private System.Windows.Forms.BindingSource FlexibleMessageBoxFormBindingSource;
|
||||
private System.Windows.Forms.RichTextBox richTextBoxMessage;
|
||||
private System.Windows.Forms.Panel panel1;
|
||||
private System.Windows.Forms.PictureBox pictureBoxForIcon;
|
||||
private System.Windows.Forms.Button button2;
|
||||
private System.Windows.Forms.Button button3;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private constants
|
||||
|
||||
//These separators are used for the "copy to clipboard" standard operation, triggered by Ctrl + C (behavior and clipboard format is like in a standard MessageBox)
|
||||
private static readonly String STANDARD_MESSAGEBOX_SEPARATOR_LINES = "---------------------------\n";
|
||||
private static readonly String STANDARD_MESSAGEBOX_SEPARATOR_SPACES = " ";
|
||||
|
||||
//These are the possible buttons (in a standard MessageBox)
|
||||
private enum ButtonID { OK = 0, CANCEL, YES, NO, ABORT, RETRY, IGNORE };
|
||||
|
||||
//These are the buttons texts for different languages.
|
||||
//If you want to add a new language, add it here and in the GetButtonText-Function
|
||||
private enum TwoLetterISOLanguageID { en, de, es, it };
|
||||
private static readonly String[] BUTTON_TEXTS_ENGLISH_EN = { "OK", "Cancel", "&Yes", "&No", "&Abort", "&Retry", "&Ignore" }; //Note: This is also the fallback language
|
||||
private static readonly String[] BUTTON_TEXTS_GERMAN_DE = { "OK", "Abbrechen", "&Ja", "&Nein", "&Abbrechen", "&Wiederholen", "&Ignorieren" };
|
||||
private static readonly String[] BUTTON_TEXTS_SPANISH_ES = { "Aceptar", "Cancelar", "&Sí", "&No", "&Abortar", "&Reintentar", "&Ignorar" };
|
||||
private static readonly String[] BUTTON_TEXTS_ITALIAN_IT = { "OK", "Annulla", "&Sì", "&No", "&Interrompi", "&Riprova", "&Ignora" };
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private members
|
||||
|
||||
private MessageBoxDefaultButton defaultButton;
|
||||
private int visibleButtonsCount;
|
||||
private TwoLetterISOLanguageID languageID = TwoLetterISOLanguageID.en;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private constructor
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FlexibleMessageBoxForm"/> class.
|
||||
/// </summary>
|
||||
private FlexibleMessageBoxForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
//Try to evaluate the language. If this fails, the fallback language English will be used
|
||||
Enum.TryParse<TwoLetterISOLanguageID>(CultureInfo.CurrentUICulture.TwoLetterISOLanguageName, out this.languageID);
|
||||
|
||||
this.KeyPreview = true;
|
||||
this.KeyUp += FlexibleMessageBoxForm_KeyUp;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private helper functions
|
||||
|
||||
/// <summary>
|
||||
/// Gets the string rows.
|
||||
/// </summary>
|
||||
/// <param name="message">The message.</param>
|
||||
/// <returns>The string rows as 1-dimensional array</returns>
|
||||
private static string[] GetStringRows(string message)
|
||||
{
|
||||
if (string.IsNullOrEmpty(message)) return null;
|
||||
|
||||
var messageRows = message.Split(new char[] { '\n' }, StringSplitOptions.None);
|
||||
return messageRows;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the button text for the CurrentUICulture language.
|
||||
/// Note: The fallback language is English
|
||||
/// </summary>
|
||||
/// <param name="buttonID">The ID of the button.</param>
|
||||
/// <returns>The button text</returns>
|
||||
private string GetButtonText(ButtonID buttonID)
|
||||
{
|
||||
var buttonTextArrayIndex = Convert.ToInt32(buttonID);
|
||||
|
||||
switch (this.languageID)
|
||||
{
|
||||
case TwoLetterISOLanguageID.de: return BUTTON_TEXTS_GERMAN_DE[buttonTextArrayIndex];
|
||||
case TwoLetterISOLanguageID.es: return BUTTON_TEXTS_SPANISH_ES[buttonTextArrayIndex];
|
||||
case TwoLetterISOLanguageID.it: return BUTTON_TEXTS_ITALIAN_IT[buttonTextArrayIndex];
|
||||
|
||||
default: return BUTTON_TEXTS_ENGLISH_EN[buttonTextArrayIndex];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure the given working area factor in the range of 0.2 - 1.0 where:
|
||||
///
|
||||
/// 0.2 means: 20 percent of the working area height or width.
|
||||
/// 1.0 means: 100 percent of the working area height or width.
|
||||
/// </summary>
|
||||
/// <param name="workingAreaFactor">The given working area factor.</param>
|
||||
/// <returns>The corrected given working area factor.</returns>
|
||||
private static double GetCorrectedWorkingAreaFactor(double workingAreaFactor)
|
||||
{
|
||||
const double MIN_FACTOR = 0.2;
|
||||
const double MAX_FACTOR = 1.0;
|
||||
|
||||
if (workingAreaFactor < MIN_FACTOR) return MIN_FACTOR;
|
||||
if (workingAreaFactor > MAX_FACTOR) return MAX_FACTOR;
|
||||
|
||||
return workingAreaFactor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the dialogs start position when given.
|
||||
/// Otherwise center the dialog on the current screen.
|
||||
/// </summary>
|
||||
/// <param name="flexibleMessageBoxForm">The FlexibleMessageBox dialog.</param>
|
||||
/// <param name="owner">The owner.</param>
|
||||
private static void SetDialogStartPosition(FlexibleMessageBoxForm flexibleMessageBoxForm, IWin32Window owner)
|
||||
{
|
||||
//If no owner given: Center on current screen
|
||||
if (owner == null)
|
||||
{
|
||||
var screen = Screen.FromPoint(Cursor.Position);
|
||||
flexibleMessageBoxForm.StartPosition = FormStartPosition.Manual;
|
||||
flexibleMessageBoxForm.Left = screen.Bounds.Left + screen.Bounds.Width / 2 - flexibleMessageBoxForm.Width / 2;
|
||||
flexibleMessageBoxForm.Top = screen.Bounds.Top + screen.Bounds.Height / 2 - flexibleMessageBoxForm.Height / 2;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the dialogs start size (Try to auto-size width to show longest text row).
|
||||
/// Also set the maximum dialog size.
|
||||
/// </summary>
|
||||
/// <param name="flexibleMessageBoxForm">The FlexibleMessageBox dialog.</param>
|
||||
/// <param name="text">The text (the longest text row is used to calculate the dialog width).</param>
|
||||
/// <param name="text">The caption (this can also affect the dialog width).</param>
|
||||
private static void SetDialogSizes(FlexibleMessageBoxForm flexibleMessageBoxForm, string text, string caption)
|
||||
{
|
||||
//First set the bounds for the maximum dialog size
|
||||
flexibleMessageBoxForm.MaximumSize = new Size(Convert.ToInt32(SystemInformation.WorkingArea.Width * FlexibleMessageBoxForm.GetCorrectedWorkingAreaFactor(MAX_WIDTH_FACTOR)),
|
||||
Convert.ToInt32(SystemInformation.WorkingArea.Height * FlexibleMessageBoxForm.GetCorrectedWorkingAreaFactor(MAX_HEIGHT_FACTOR)));
|
||||
|
||||
//Get rows. Exit if there are no rows to render...
|
||||
var stringRows = GetStringRows(text);
|
||||
if (stringRows == null) return;
|
||||
|
||||
//Calculate whole text height
|
||||
var textHeight = TextRenderer.MeasureText(text, FONT).Height;
|
||||
|
||||
//Calculate width for longest text line
|
||||
const int SCROLLBAR_WIDTH_OFFSET = 15;
|
||||
var longestTextRowWidth = stringRows.Max(textForRow => TextRenderer.MeasureText(textForRow, FONT).Width);
|
||||
var captionWidth = TextRenderer.MeasureText(caption, SystemFonts.CaptionFont).Width;
|
||||
var textWidth = Math.Max(longestTextRowWidth + SCROLLBAR_WIDTH_OFFSET, captionWidth);
|
||||
|
||||
//Calculate margins
|
||||
var marginWidth = flexibleMessageBoxForm.Width - flexibleMessageBoxForm.richTextBoxMessage.Width;
|
||||
var marginHeight = flexibleMessageBoxForm.Height - flexibleMessageBoxForm.richTextBoxMessage.Height;
|
||||
|
||||
//Set calculated dialog size (if the calculated values exceed the maximums, they were cut by windows forms automatically)
|
||||
flexibleMessageBoxForm.Size = new Size(textWidth + marginWidth,
|
||||
textHeight + marginHeight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the dialogs icon.
|
||||
/// When no icon is used: Correct placement and width of rich text box.
|
||||
/// </summary>
|
||||
/// <param name="flexibleMessageBoxForm">The FlexibleMessageBox dialog.</param>
|
||||
/// <param name="icon">The MessageBoxIcon.</param>
|
||||
private static void SetDialogIcon(FlexibleMessageBoxForm flexibleMessageBoxForm, MessageBoxIcon icon)
|
||||
{
|
||||
switch (icon)
|
||||
{
|
||||
case MessageBoxIcon.Information:
|
||||
flexibleMessageBoxForm.pictureBoxForIcon.Image = SystemIcons.Information.ToBitmap();
|
||||
break;
|
||||
case MessageBoxIcon.Warning:
|
||||
flexibleMessageBoxForm.pictureBoxForIcon.Image = SystemIcons.Warning.ToBitmap();
|
||||
break;
|
||||
case MessageBoxIcon.Error:
|
||||
flexibleMessageBoxForm.pictureBoxForIcon.Image = SystemIcons.Error.ToBitmap();
|
||||
break;
|
||||
case MessageBoxIcon.Question:
|
||||
flexibleMessageBoxForm.pictureBoxForIcon.Image = SystemIcons.Question.ToBitmap();
|
||||
break;
|
||||
default:
|
||||
//When no icon is used: Correct placement and width of rich text box.
|
||||
flexibleMessageBoxForm.pictureBoxForIcon.Visible = false;
|
||||
flexibleMessageBoxForm.richTextBoxMessage.Left -= flexibleMessageBoxForm.pictureBoxForIcon.Width;
|
||||
flexibleMessageBoxForm.richTextBoxMessage.Width += flexibleMessageBoxForm.pictureBoxForIcon.Width;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set dialog buttons visibilities and texts.
|
||||
/// Also set a default button.
|
||||
/// </summary>
|
||||
/// <param name="flexibleMessageBoxForm">The FlexibleMessageBox dialog.</param>
|
||||
/// <param name="buttons">The buttons.</param>
|
||||
/// <param name="defaultButton">The default button.</param>
|
||||
private static void SetDialogButtons(FlexibleMessageBoxForm flexibleMessageBoxForm, MessageBoxButtons buttons, MessageBoxDefaultButton defaultButton)
|
||||
{
|
||||
//Set the buttons visibilities and texts
|
||||
switch (buttons)
|
||||
{
|
||||
case MessageBoxButtons.AbortRetryIgnore:
|
||||
flexibleMessageBoxForm.visibleButtonsCount = 3;
|
||||
|
||||
flexibleMessageBoxForm.button1.Visible = true;
|
||||
flexibleMessageBoxForm.button1.Text = flexibleMessageBoxForm.GetButtonText(ButtonID.ABORT);
|
||||
flexibleMessageBoxForm.button1.DialogResult = DialogResult.Abort;
|
||||
|
||||
flexibleMessageBoxForm.button2.Visible = true;
|
||||
flexibleMessageBoxForm.button2.Text = flexibleMessageBoxForm.GetButtonText(ButtonID.RETRY);
|
||||
flexibleMessageBoxForm.button2.DialogResult = DialogResult.Retry;
|
||||
|
||||
flexibleMessageBoxForm.button3.Visible = true;
|
||||
flexibleMessageBoxForm.button3.Text = flexibleMessageBoxForm.GetButtonText(ButtonID.IGNORE);
|
||||
flexibleMessageBoxForm.button3.DialogResult = DialogResult.Ignore;
|
||||
|
||||
flexibleMessageBoxForm.ControlBox = false;
|
||||
break;
|
||||
|
||||
case MessageBoxButtons.OKCancel:
|
||||
flexibleMessageBoxForm.visibleButtonsCount = 2;
|
||||
|
||||
flexibleMessageBoxForm.button2.Visible = true;
|
||||
flexibleMessageBoxForm.button2.Text = flexibleMessageBoxForm.GetButtonText(ButtonID.OK);
|
||||
flexibleMessageBoxForm.button2.DialogResult = DialogResult.OK;
|
||||
|
||||
flexibleMessageBoxForm.button3.Visible = true;
|
||||
flexibleMessageBoxForm.button3.Text = flexibleMessageBoxForm.GetButtonText(ButtonID.CANCEL);
|
||||
flexibleMessageBoxForm.button3.DialogResult = DialogResult.Cancel;
|
||||
|
||||
flexibleMessageBoxForm.CancelButton = flexibleMessageBoxForm.button3;
|
||||
break;
|
||||
|
||||
case MessageBoxButtons.RetryCancel:
|
||||
flexibleMessageBoxForm.visibleButtonsCount = 2;
|
||||
|
||||
flexibleMessageBoxForm.button2.Visible = true;
|
||||
flexibleMessageBoxForm.button2.Text = flexibleMessageBoxForm.GetButtonText(ButtonID.RETRY);
|
||||
flexibleMessageBoxForm.button2.DialogResult = DialogResult.Retry;
|
||||
|
||||
flexibleMessageBoxForm.button3.Visible = true;
|
||||
flexibleMessageBoxForm.button3.Text = flexibleMessageBoxForm.GetButtonText(ButtonID.CANCEL);
|
||||
flexibleMessageBoxForm.button3.DialogResult = DialogResult.Cancel;
|
||||
|
||||
flexibleMessageBoxForm.CancelButton = flexibleMessageBoxForm.button3;
|
||||
break;
|
||||
|
||||
case MessageBoxButtons.YesNo:
|
||||
flexibleMessageBoxForm.visibleButtonsCount = 2;
|
||||
|
||||
flexibleMessageBoxForm.button2.Visible = true;
|
||||
flexibleMessageBoxForm.button2.Text = flexibleMessageBoxForm.GetButtonText(ButtonID.YES);
|
||||
flexibleMessageBoxForm.button2.DialogResult = DialogResult.Yes;
|
||||
|
||||
flexibleMessageBoxForm.button3.Visible = true;
|
||||
flexibleMessageBoxForm.button3.Text = flexibleMessageBoxForm.GetButtonText(ButtonID.NO);
|
||||
flexibleMessageBoxForm.button3.DialogResult = DialogResult.No;
|
||||
|
||||
flexibleMessageBoxForm.ControlBox = false;
|
||||
break;
|
||||
|
||||
case MessageBoxButtons.YesNoCancel:
|
||||
flexibleMessageBoxForm.visibleButtonsCount = 3;
|
||||
|
||||
flexibleMessageBoxForm.button1.Visible = true;
|
||||
flexibleMessageBoxForm.button1.Text = flexibleMessageBoxForm.GetButtonText(ButtonID.YES);
|
||||
flexibleMessageBoxForm.button1.DialogResult = DialogResult.Yes;
|
||||
|
||||
flexibleMessageBoxForm.button2.Visible = true;
|
||||
flexibleMessageBoxForm.button2.Text = flexibleMessageBoxForm.GetButtonText(ButtonID.NO);
|
||||
flexibleMessageBoxForm.button2.DialogResult = DialogResult.No;
|
||||
|
||||
flexibleMessageBoxForm.button3.Visible = true;
|
||||
flexibleMessageBoxForm.button3.Text = flexibleMessageBoxForm.GetButtonText(ButtonID.CANCEL);
|
||||
flexibleMessageBoxForm.button3.DialogResult = DialogResult.Cancel;
|
||||
|
||||
flexibleMessageBoxForm.CancelButton = flexibleMessageBoxForm.button3;
|
||||
break;
|
||||
|
||||
case MessageBoxButtons.OK:
|
||||
default:
|
||||
flexibleMessageBoxForm.visibleButtonsCount = 1;
|
||||
flexibleMessageBoxForm.button3.Visible = true;
|
||||
flexibleMessageBoxForm.button3.Text = flexibleMessageBoxForm.GetButtonText(ButtonID.OK);
|
||||
flexibleMessageBoxForm.button3.DialogResult = DialogResult.OK;
|
||||
|
||||
flexibleMessageBoxForm.CancelButton = flexibleMessageBoxForm.button3;
|
||||
break;
|
||||
}
|
||||
|
||||
//Set default button (used in FlexibleMessageBoxForm_Shown)
|
||||
flexibleMessageBoxForm.defaultButton = defaultButton;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private event handlers
|
||||
|
||||
/// <summary>
|
||||
/// Handles the Shown event of the FlexibleMessageBoxForm control.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the event.</param>
|
||||
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
|
||||
private void FlexibleMessageBoxForm_Shown(object sender, EventArgs e)
|
||||
{
|
||||
int buttonIndexToFocus = 1;
|
||||
Button buttonToFocus;
|
||||
|
||||
//Set the default button...
|
||||
switch (this.defaultButton)
|
||||
{
|
||||
case MessageBoxDefaultButton.Button1:
|
||||
default:
|
||||
buttonIndexToFocus = 1;
|
||||
break;
|
||||
case MessageBoxDefaultButton.Button2:
|
||||
buttonIndexToFocus = 2;
|
||||
break;
|
||||
case MessageBoxDefaultButton.Button3:
|
||||
buttonIndexToFocus = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
if (buttonIndexToFocus > this.visibleButtonsCount) buttonIndexToFocus = this.visibleButtonsCount;
|
||||
|
||||
if (buttonIndexToFocus == 3)
|
||||
{
|
||||
buttonToFocus = this.button3;
|
||||
}
|
||||
else if (buttonIndexToFocus == 2)
|
||||
{
|
||||
buttonToFocus = this.button2;
|
||||
}
|
||||
else
|
||||
{
|
||||
buttonToFocus = this.button1;
|
||||
}
|
||||
|
||||
buttonToFocus.Focus();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the LinkClicked event of the richTextBoxMessage control.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the event.</param>
|
||||
/// <param name="e">The <see cref="System.Windows.Forms.LinkClickedEventArgs"/> instance containing the event data.</param>
|
||||
private void richTextBoxMessage_LinkClicked(object sender, LinkClickedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Cursor.Current = Cursors.WaitCursor;
|
||||
Process.Start(e.LinkText);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//Let the caller of FlexibleMessageBoxForm decide what to do with this exception...
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Cursor.Current = Cursors.Default;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the KeyUp event of the richTextBoxMessage control.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the event.</param>
|
||||
/// <param name="e">The <see cref="System.Windows.Forms.KeyEventArgs"/> instance containing the event data.</param>
|
||||
void FlexibleMessageBoxForm_KeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
//Handle standard key strikes for clipboard copy: "Ctrl + C" and "Ctrl + Insert"
|
||||
if (e.Control && (e.KeyCode == Keys.C || e.KeyCode == Keys.Insert))
|
||||
{
|
||||
var buttonsTextLine = (this.button1.Visible ? this.button1.Text + STANDARD_MESSAGEBOX_SEPARATOR_SPACES : string.Empty)
|
||||
+ (this.button2.Visible ? this.button2.Text + STANDARD_MESSAGEBOX_SEPARATOR_SPACES : string.Empty)
|
||||
+ (this.button3.Visible ? this.button3.Text + STANDARD_MESSAGEBOX_SEPARATOR_SPACES : string.Empty);
|
||||
|
||||
//Build same clipboard text like the standard .Net MessageBox
|
||||
var textForClipboard = STANDARD_MESSAGEBOX_SEPARATOR_LINES
|
||||
+ this.Text + Environment.NewLine
|
||||
+ STANDARD_MESSAGEBOX_SEPARATOR_LINES
|
||||
+ this.richTextBoxMessage.Text + Environment.NewLine
|
||||
+ STANDARD_MESSAGEBOX_SEPARATOR_LINES
|
||||
+ buttonsTextLine.Replace("&", string.Empty) + Environment.NewLine
|
||||
+ STANDARD_MESSAGEBOX_SEPARATOR_LINES;
|
||||
|
||||
//Set text in clipboard
|
||||
Clipboard.SetText(textForClipboard);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties (only used for binding)
|
||||
|
||||
/// <summary>
|
||||
/// The text that is been used for the heading.
|
||||
/// </summary>
|
||||
public string CaptionText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The text that is been used in the FlexibleMessageBoxForm.
|
||||
/// </summary>
|
||||
public string MessageText { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public show function
|
||||
|
||||
/// <summary>
|
||||
/// Shows the specified message box.
|
||||
/// </summary>
|
||||
/// <param name="owner">The owner.</param>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="caption">The caption.</param>
|
||||
/// <param name="buttons">The buttons.</param>
|
||||
/// <param name="icon">The icon.</param>
|
||||
/// <param name="defaultButton">The default button.</param>
|
||||
/// <returns>The dialog result.</returns>
|
||||
public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
|
||||
{
|
||||
//Create a new instance of the FlexibleMessageBox form
|
||||
var flexibleMessageBoxForm = new FlexibleMessageBoxForm();
|
||||
flexibleMessageBoxForm.ShowInTaskbar = false;
|
||||
|
||||
//Bind the caption and the message text
|
||||
flexibleMessageBoxForm.CaptionText = caption;
|
||||
flexibleMessageBoxForm.MessageText = text;
|
||||
flexibleMessageBoxForm.FlexibleMessageBoxFormBindingSource.DataSource = flexibleMessageBoxForm;
|
||||
|
||||
//Set the buttons visibilities and texts. Also set a default button.
|
||||
SetDialogButtons(flexibleMessageBoxForm, buttons, defaultButton);
|
||||
|
||||
//Set the dialogs icon. When no icon is used: Correct placement and width of rich text box.
|
||||
SetDialogIcon(flexibleMessageBoxForm, icon);
|
||||
|
||||
//Set the font for all controls
|
||||
flexibleMessageBoxForm.Font = FONT;
|
||||
flexibleMessageBoxForm.richTextBoxMessage.Font = FONT;
|
||||
|
||||
//Calculate the dialogs start size (Try to auto-size width to show longest text row). Also set the maximum dialog size.
|
||||
SetDialogSizes(flexibleMessageBoxForm, text, caption);
|
||||
|
||||
//Set the dialogs start position when given. Otherwise center the dialog on the current screen.
|
||||
SetDialogStartPosition(flexibleMessageBoxForm, owner);
|
||||
|
||||
//Show the dialog
|
||||
return flexibleMessageBoxForm.ShowDialog(owner);
|
||||
}
|
||||
|
||||
#endregion
|
||||
} //class FlexibleMessageBoxForm
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: AssemblyVersion("1.1.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.1.0.0")]
|
||||
|
@ -1,5 +1,5 @@
|
||||
------------------------------------/
|
||||
------- BRAWLBUILDER v1.0 -------/
|
||||
------- BRAWLBUILDER v1.1 -------/
|
||||
------------------------------/
|
||||
|
||||
"The Ultimate Super Smash Bros Brawl ISO Builder"
|
||||
@ -31,6 +31,10 @@ There are a couple command line arguments if you want to use them, I will probab
|
||||
'--show-wit'
|
||||
This will show the wit command line windows rather than hiding them and displaying the progress in the UI.
|
||||
|
||||
'--show-wit-debug'
|
||||
This will do the same thing as --show-wit, but it will keep the wit windows open once wit closes, allowing you to
|
||||
read the output and figure out what is going wrong.
|
||||
|
||||
'--no-gct-patch'
|
||||
This will disable patching of the GCT based on the CodePatches.txt file in the Resources folder. Use of this
|
||||
option is not recommended.
|
||||
@ -77,6 +81,23 @@ into the same directory as the exe file, or else nothing will work. This should
|
||||
if it doesn't, just copy it manually.
|
||||
|
||||
|
||||
--------------------/
|
||||
------ Changelog --/
|
||||
------------------/
|
||||
|
||||
1.1:
|
||||
- Improve error messages, most of them should now actually be somewhat helpful
|
||||
- Fix "Build Completed" sometimes appearing even if the build did not complete properly
|
||||
- Add the --show-wit-debug option to show wit windows and keep them open after wit finishes, in order to figure
|
||||
out what is going wrong
|
||||
- Modify the help text for the Brawl ISO to clarify how the ssbb.d folder works
|
||||
- Fix crash if building with no GCT selected
|
||||
- Other code cleanup and misc. fixes
|
||||
|
||||
1.0:
|
||||
- Initial release
|
||||
|
||||
|
||||
------------------/
|
||||
------ Credits --/
|
||||
----------------/
|
||||
@ -89,5 +110,7 @@ if it doesn't, just copy it manually.
|
||||
|
||||
- The folder select dialog uses Ookii dialogs, a great little library for nice looking dialogs.
|
||||
|
||||
- Detailed wit error messages make use of FlexibleMessageBox by JReichert
|
||||
|
||||
- And thanks to the creators of all the ISO builder scripts for Project M and the like, they are what I initially
|
||||
based this off of.
|
||||
|
@ -12,6 +12,9 @@ Hopefully compatibility will be improved in the future.
|
||||
`--show-wit`
|
||||
This will show the wit command line windows rather than hiding them and displaying the progress in the UI.
|
||||
|
||||
`--show-wit-debug`
|
||||
This will do the same thing as `--show-wit`, but it will keep the wit windows open once wit closes, allowing you to read the output and figure out what is going wrong.
|
||||
|
||||
`--no-gct-patch`
|
||||
This will disable patching of the GCT based on the CodePatches.txt file in the Resources folder. Use of this option is not recommended.
|
||||
|
||||
@ -35,4 +38,5 @@ This will change the offset that the GCT is applied at (by default 80570000) to
|
||||
- First of all, thanks to Wiimm for his amazing wit tool, which is used to extract, patch, and build the game images.
|
||||
- Secondly, thanks to the Dolphin team for the awesome debug mode of Dolphin, I wouldn't have been able to get alternate stages and the replacement soundbank engine working without that.
|
||||
- The folder select dialog uses Ookii dialogs, a great little library for nice looking dialogs.
|
||||
- Detailed wit error messages make use of FlexibleMessageBox by JReichert
|
||||
- And thanks to the creators of all the ISO builder scripts for Project M and the like, they are what I initially based this off of.
|
BIN
Resources/wit/cyggcc_s-1.dll
Normal file
BIN
Resources/wit/cyggcc_s-1.dll
Normal file
Binary file not shown.
BIN
Resources/wit/cygz.dll
Normal file
BIN
Resources/wit/cygz.dll
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user