Files

442 lines
14 KiB
C#

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace PDFPatcher.Common
{
static class FormHelper
{
public const int ProcMsg = NativeMethods.WM_COPYDATA;
public static bool IsCtrlKeyDown => (Control.ModifierKeys & Keys.Control) != 0;
public static bool IsShiftKeyDown => (Control.ModifierKeys & Keys.Shift) != 0;
public static bool IsAltKeyDown => (Control.ModifierKeys & Keys.Alt) != 0;
public static bool IsEmptyOrTransparent(this Color color) {
return color.IsEmpty || color.A == 0;
}
public static Point Round(this PointF point) {
return new Point(point.X.ToInt32(), point.Y.ToInt32());
}
public static RectangleF Union(this RectangleF rectangle, RectangleF other) {
return RectangleF.FromLTRB(
Math.Min(rectangle.Left, other.Left),
Math.Min(rectangle.Top, other.Top),
Math.Max(rectangle.Right, other.Right),
Math.Max(rectangle.Bottom, other.Bottom)
);
}
public static Point Transpose(this Point point, int x, int y) {
return new Point(point.X + x, point.Y + y);
}
public static Point Transpose(this Point point, Point transpose) {
return new Point(point.X + transpose.X, point.Y + transpose.Y);
}
public static Size Scale(this Size size, float scale) {
return new Size((int)(size.Width * scale), (int)(size.Height * scale));
}
public static void OnFirstLoad(this Form form, Action handler) {
new FormEventHandler(form, handler);
}
public static void SetIcon(this Form form, Bitmap bitmap) {
form.Icon = Icon.FromHandle(bitmap.GetHicon());
}
public static void OnFirstLoad(this UserControl control, Action handler) {
new UserControlLoadHandler(control, handler);
}
public static ProgressBar SetValue(this ProgressBar control, int value) {
control.Value = value < control.Minimum ? control.Minimum
: value > control.Maximum ? control.Maximum
: value;
return control;
}
public static NumericUpDown SetValue(this NumericUpDown box, int value) {
return box.SetValue((decimal)value);
}
public static NumericUpDown SetValue(this NumericUpDown box, float value) {
return box.SetValue((decimal)value);
}
public static NumericUpDown SetValue(this NumericUpDown box, double value) {
return box.SetValue((decimal)value);
}
public static NumericUpDown SetValue(this NumericUpDown box, decimal value) {
box.Value =
value >= box.Minimum && value <= box.Maximum ? value
: value > box.Maximum ? box.Maximum
: box.Minimum;
return box;
}
public static ListBox Select(this ListBox control, string item) {
if (control.Items.Count == 0) {
return control;
}
var i = control.FindString(item);
if (i != -1) {
control.SelectedIndex = i;
}
return control;
}
public static ComboBox Select(this ComboBox control, string item) {
if (control.Items.Count == 0) {
return control;
}
var i = control.FindString(item);
if (i != -1) {
control.SelectedIndex = i;
}
return control;
}
public static ListBox Select(this ListBox control, int index) {
var items = control.Items;
if (items.Count == 0) {
return control;
}
control.SelectedIndex = index < 0 ? 0
: index > items.Count - 1 ? items.Count - 1
: index;
return control;
}
public static ComboBox Select(this ComboBox control, int index) {
var items = control.Items;
if (items.Count == 0) {
return control;
}
control.SelectedIndex = index < 0 ? 0
: index > items.Count - 1 ? items.Count - 1
: index;
return control;
}
public static ComboBox AddRange(this ComboBox view, params object[] values) {
view.Items.AddRange(values);
return view;
}
public static TTextBox AppendLine<TTextBox>(this TTextBox box) where TTextBox : TextBoxBase {
box.AppendText(Environment.NewLine);
return box;
}
public static TTextBox AppendLine<TTextBox>(this TTextBox box, string text) where TTextBox : TextBoxBase {
box.AppendText(text + Environment.NewLine);
return box;
}
public static void SetLocation(this FileDialog dialog, string path) {
if (!FileHelper.IsPathValid(path)) {
return;
}
dialog.InitialDirectory = System.IO.Path.GetDirectoryName(path);
dialog.FileName = System.IO.Path.GetFileName(path);
}
public static ToolStrip ToggleEnabled(this ToolStrip toolStrip, bool enabled, params string[] names) {
foreach (ToolStripItem item in toolStrip.Items) {
if (Array.IndexOf(names, item.Name) != -1) {
item.Enabled = enabled;
}
}
return toolStrip;
}
public static float GetDpiScale(this Control control) {
using (var g = control.CreateGraphics()) {
return g.DpiX / 96;
}
}
public static void ScaleColumnWidths(this ListView listView, float scale) {
foreach (ColumnHeader column in listView.Columns) {
column.Width = (int)(column.Width * scale);
}
}
public static void ScaleColumnWidths(this ListView listView) {
float scale = GetDpiScale(listView);
foreach (ColumnHeader column in listView.Columns) {
column.Width = (int)(column.Width * scale);
}
}
public static ToolStrip ScaleElements(this ToolStrip toolStrip, float scale = 0) {
if (scale <= 0) {
scale = toolStrip.GetDpiScale();
}
var iconSize = (int)(scale * 16);
var splitButtonWidth = (int)(11 * scale);
return toolStrip.DpiAwareScale(new Size(iconSize, iconSize), splitButtonWidth);
}
public static ToolStrip DpiAwareScale(this ToolStrip toolStrip, Size size, int splitButtonWidth) {
toolStrip.SuspendLayout();
toolStrip.AutoSize = false;
toolStrip.ImageScalingSize = size;
toolStrip.ResumeLayout();
toolStrip.AutoSize = true;
foreach (var item in toolStrip.Items) {
if (item is ToolStripSplitButton sb) {
sb.DropDownButtonWidth = splitButtonWidth;
}
}
return toolStrip;
}
internal static void InsertLinkedText(this RichTextBoxLinks.RichTextBoxEx textBox, string text) {
const int TokenLength = 2;
int p1 = text.IndexOf("<<");
int p2 = text.IndexOf(">>");
if (p1 != -1 && p2 != -1 && p2 > p1) {
textBox.AppendText(text.Substring(0, p1));
var c = textBox.SelectionColor;
var f = textBox.SelectionFont;
textBox.InsertLink(text.Substring(p1 + TokenLength, p2 - p1 - TokenLength));
if (p2 < text.Length - TokenLength) {
textBox.SelectionColor = c;
textBox.SelectionFont = f;
textBox.AppendText(text.Substring(p2 + TokenLength));
}
}
else {
textBox.AppendText(text);
}
}
public static void FeedbackDragFileOver(this DragEventArgs args, params string[] allowedFileExtension) {
if (args.Data.GetDataPresent(DataFormats.FileDrop)) {
var files = args.Data.GetData(DataFormats.FileDrop) as string[];
if (Array.Exists(files,
f => {
return Array.Exists(allowedFileExtension,
ext => f.EndsWith(ext, StringComparison.InvariantCultureIgnoreCase));
})) {
args.Effect = DragDropEffects.Copy;
}
}
}
public static string[] DropFileOver(this DragEventArgs args, params string[] allowedFileExtension) {
if (args.Data.GetDataPresent(DataFormats.FileDrop)) {
var files = (string[])args.Data.GetData(DataFormats.FileDrop);
return Array.FindAll(files, f => {
return Array.Exists(allowedFileExtension,
ext => f.EndsWith(ext, StringComparison.InvariantCultureIgnoreCase));
});
}
return [];
}
public static bool DropFileOver(this Control control, DragEventArgs args, params string[] allowedFileExtension) {
var files = DropFileOver(args, allowedFileExtension);
if (files.Length > 0) {
control.Text = files[0];
return true;
}
return false;
}
public static void HidePopupMenu(this ToolStripItem item) {
if (item is ToolStripDropDownItem mi && mi.HasDropDownItems) {
return;
}
var oo = item.Owner as ToolStripDropDownMenu;
oo?.Hide();
var oi = item.OwnerItem as ToolStripDropDownItem;
while (oi != null) {
oi.DropDown.Close();
oo = oi.Owner as ToolStripDropDownMenu;
oo?.Hide();
oi = oi.OwnerItem as ToolStripDropDownItem;
}
}
public static void ClearDropDownItems(this ToolStripItemCollection items, int keepItems = 0) {
if (items.Count == 0) {
return;
}
keepItems--;
for (var i = items.Count - 1; i > keepItems; i--) {
items[i].Dispose();
}
}
public static void ToggleVisibility(bool visible, params Control[] controls) {
foreach (var item in controls) {
item.Visible = visible;
}
}
public static DialogResult ShowDialog<TForm>() where TForm : Form, new() {
using (var f = new TForm()) {
return f.ShowDialog();
}
}
public static DialogResult ShowDialog<TForm>(this IWin32Window form) where TForm : Form, new() {
using (var f = new TForm()) {
f.StartPosition = FormStartPosition.CenterParent;
return f.ShowDialog(form);
}
}
public static DialogResult ShowDialog<TForm>(this IWin32Window form, object formParameter)
where TForm : Form, new() {
using (var f = new TForm()) {
f.Tag = formParameter;
return f.ShowDialog(form);
}
}
public static DialogResult ShowDialog<TForm>(this IWin32Window form, Action<TForm> formConfigurator, Action<TForm> formConfirmationHandler) where TForm : Form, new() {
using (var f = new TForm()) {
formConfigurator?.Invoke(f);
var r = f.ShowDialog(form);
if (formConfirmationHandler != null && (r == DialogResult.OK || r == DialogResult.Yes)) {
formConfirmationHandler(f);
}
return r;
}
}
public static DialogResult ShowCommonDialog<TDialog>(this IWin32Window form, Action<TDialog> formConfigurator, Action<TDialog> formConfirmationHandler) where TDialog : CommonDialog, new() {
using (var f = new TDialog()) {
formConfigurator?.Invoke(f);
var r = f.ShowDialog(form);
if (formConfirmationHandler != null && (r == DialogResult.OK || r == DialogResult.Yes)) {
formConfirmationHandler(f);
}
return r;
}
}
internal static void ErrorBox(string text) {
MessageBox.Show(text, Constants.AppName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
public static void ErrorBox(this Control control, string text) {
MessageBox.Show(text, control.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
public static void ErrorBox(this Control control, string title, Exception exception) {
var s = new System.Text.StringBuilder(title);
s.AppendLine().AppendLine();
s.AppendLine(exception.Message);
#if DEBUG
s.AppendLine(exception.StackTrace);
#endif
while ((exception = exception.InnerException) != null) {
s.AppendLine();
s.Append(exception.Message);
}
MessageBox.Show(s.ToString(), control.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
internal static void InfoBox(string text) {
MessageBox.Show(text, Constants.AppName, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
internal static DialogResult YesNoBox(string text) {
return MessageBox.Show(text, Constants.AppName, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
}
internal static DialogResult YesNoCancelBox(string text) {
return MessageBox.Show(text, Constants.AppName, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
}
public static bool ConfirmOKBox(string text) {
return MessageBox.Show(text, Constants.AppName, MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK;
}
public static bool ConfirmOKBox(this Control control, string text) {
return MessageBox.Show(text, control.Text, MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK;
}
public static bool ConfirmYesBox(this Control control, string text) {
return MessageBox.Show(text, control.Text, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes;
}
public static int SendCopyDataMessage(this System.Diagnostics.Process process, string text) {
var s = new CopyDataStruct(text);
var r = NativeMethods.SendMessage(process.MainWindowHandle, ProcMsg, 0, ref s);
s.Dispose();
return r;
}
public static string GetCopyDataContent(ref Message message) {
if (message.Msg == ProcMsg) {
return Marshal.PtrToStringUni(((CopyDataStruct)Marshal.PtrToStructure(message.LParam, typeof(CopyDataStruct))).lpData);
}
return null;
}
public static IDisposable BatchUpdate(this RichTextBox box) {
return new RichTextDrawingSuspender(box);
}
sealed class FormEventHandler
{
readonly Form _Form;
readonly Action _Handler;
public FormEventHandler(Form form, Action handler) {
_Form = form;
_Handler = handler;
form.Load += OnLoadHandler;
}
public void OnLoadHandler(object s, EventArgs args) {
_Form.Load -= OnLoadHandler;
_Handler();
}
}
sealed class RichTextDrawingSuspender : IDisposable
{
bool _Resumed;
public RichTextDrawingSuspender(RichTextBox box) {
Box = box;
box.SuspendLayout();
NativeMethods.SuspendDrawing(box);
}
public RichTextBox Box { get; }
public void Dispose() {
if (!_Resumed) {
_Resumed = true;
Box.ResumeLayout();
NativeMethods.ResumeDrawing(Box);
}
}
}
sealed class UserControlLoadHandler
{
readonly UserControl _Control;
readonly Action _Handler;
public UserControlLoadHandler(UserControl control, Action handler) {
_Control = control;
_Handler = handler;
control.Load += OnLoadHandler;
}
public void OnLoadHandler(object s, EventArgs args) {
_Control.Load -= OnLoadHandler;
_Handler();
}
}
static class NativeMethods
{
const string User32DLL = "User32.dll";
internal const int WM_COPYDATA = 0x004A;
[DllImport(User32DLL, SetLastError = false, CharSet = CharSet.Unicode)]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, ref CopyDataStruct lParam);
[DllImport(User32DLL, SetLastError = false)]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LocalFree(IntPtr p);
const int WM_SETREDRAW = 0x000B;
public static void SuspendDrawing(RichTextBox rtb) {
SendMessage(rtb.Handle, WM_SETREDRAW, IntPtr.Zero, IntPtr.Zero);
}
public static void ResumeDrawing(RichTextBox rtb) {
SendMessage(rtb.Handle, WM_SETREDRAW, new IntPtr(1), IntPtr.Zero);
rtb.Invalidate(); // 强制重绘
}
}
struct CopyDataStruct(string text) : IDisposable
{
readonly IntPtr dwData = (IntPtr)1;
readonly int cbData = (text.Length + 1) * 2;
internal IntPtr lpData = Marshal.StringToBSTR(text);
public void Dispose() {
NativeMethods.LocalFree(lpData);
lpData = IntPtr.Zero;
}
}
}
}