mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-27 14:12:16 +00:00
15b2adfe30
Fixed, Texture Browser Form: well, I broke "Tab" key functionality again (in previous commit)... Maintenance: changed curly braces style to match DB2 one (hopefully not breaking anything in the process...). Maintenance: changed private method names casing to match DB2 one.
793 lines
No EOL
31 KiB
C#
793 lines
No EOL
31 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Windows.Forms;
|
|
using System.Windows.Forms.VisualStyles;
|
|
|
|
//Get the latest version of SplitButton at: http://wyday.com/splitbutton/
|
|
|
|
namespace CodeImp.DoomBuilder.Controls
|
|
{
|
|
public class SplitButton : Button
|
|
{
|
|
private PushButtonState state;
|
|
private const int splitsectionwidth = 18;
|
|
private static readonly int borderSize = SystemInformation.Border3DSize.Width * 2;
|
|
private bool skipNextOpen;
|
|
private Rectangle dropDownRectangle;
|
|
private bool showSplit;
|
|
private bool isSplitMenuVisible;
|
|
private int currentmenustripitem; //mxd
|
|
private ContextMenuStrip m_SplitMenuStrip;
|
|
private TextFormatFlags textFormatFlags = TextFormatFlags.Default;
|
|
|
|
#region Properties
|
|
|
|
[Browsable(false)]
|
|
public override ContextMenuStrip ContextMenuStrip
|
|
{
|
|
get
|
|
{
|
|
return SplitMenuStrip;
|
|
}
|
|
set
|
|
{
|
|
SplitMenuStrip = value;
|
|
}
|
|
}
|
|
|
|
[DefaultValue(null)]
|
|
public ContextMenuStrip SplitMenuStrip
|
|
{
|
|
get
|
|
{
|
|
return m_SplitMenuStrip;
|
|
}
|
|
set
|
|
{
|
|
//remove the event handlers for the old SplitMenuStrip
|
|
if (m_SplitMenuStrip != null)
|
|
{
|
|
m_SplitMenuStrip.Closing -= SplitMenuStrip_Closing;
|
|
m_SplitMenuStrip.Opening -= SplitMenuStrip_Opening;
|
|
m_SplitMenuStrip.ItemClicked -= SplitMenuStrip_OnItemClicked;
|
|
}
|
|
|
|
//add the event handlers for the new SplitMenuStrip
|
|
if (value != null)
|
|
{
|
|
ShowSplit = true;
|
|
value.Closing += SplitMenuStrip_Closing;
|
|
value.Opening += SplitMenuStrip_Opening;
|
|
value.ItemClicked += SplitMenuStrip_OnItemClicked; //mxd
|
|
CurrentMenuStripItem = currentmenustripitem;
|
|
}
|
|
else
|
|
{
|
|
ShowSplit = false;
|
|
currentmenustripitem = -1; //mxd
|
|
}
|
|
|
|
m_SplitMenuStrip = value;
|
|
}
|
|
}
|
|
|
|
//mxd
|
|
public int CurrentMenuStripItem
|
|
{
|
|
get { return currentmenustripitem; }
|
|
set
|
|
{
|
|
if (value > -1 && m_SplitMenuStrip != null && m_SplitMenuStrip.Items.Count > value)
|
|
{
|
|
currentmenustripitem = value;
|
|
this.Text = m_SplitMenuStrip.Items[value].Text;
|
|
this.Image = m_SplitMenuStrip.Items[value].Image;
|
|
}
|
|
else
|
|
{
|
|
currentmenustripitem = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
[DefaultValue(false)]
|
|
public bool ShowSplit
|
|
{
|
|
set
|
|
{
|
|
if (value != showSplit)
|
|
{
|
|
showSplit = value;
|
|
Invalidate();
|
|
|
|
if (Parent != null)
|
|
Parent.PerformLayout();
|
|
}
|
|
}
|
|
}
|
|
|
|
private PushButtonState State
|
|
{
|
|
get
|
|
{
|
|
return state;
|
|
}
|
|
set
|
|
{
|
|
if (!state.Equals(value))
|
|
{
|
|
state = value;
|
|
Invalidate();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion Properties
|
|
|
|
protected override bool IsInputKey(Keys keyData)
|
|
{
|
|
if (keyData.Equals(Keys.Down) && showSplit) return true;
|
|
return base.IsInputKey(keyData);
|
|
}
|
|
|
|
protected override void OnGotFocus(EventArgs e)
|
|
{
|
|
if (!showSplit)
|
|
{
|
|
base.OnGotFocus(e);
|
|
return;
|
|
}
|
|
|
|
if (!State.Equals(PushButtonState.Pressed) && !State.Equals(PushButtonState.Disabled))
|
|
{
|
|
State = PushButtonState.Default;
|
|
}
|
|
}
|
|
|
|
protected override void OnKeyDown(KeyEventArgs kevent)
|
|
{
|
|
if (showSplit)
|
|
{
|
|
if (kevent.KeyCode.Equals(Keys.Down) && !isSplitMenuVisible)
|
|
{
|
|
ShowContextMenuStrip();
|
|
}
|
|
|
|
else if (kevent.KeyCode.Equals(Keys.Space) && kevent.Modifiers == Keys.None)
|
|
{
|
|
State = PushButtonState.Pressed;
|
|
}
|
|
}
|
|
|
|
base.OnKeyDown(kevent);
|
|
}
|
|
|
|
protected override void OnKeyUp(KeyEventArgs kevent)
|
|
{
|
|
if (kevent.KeyCode.Equals(Keys.Space))
|
|
{
|
|
if (MouseButtons == MouseButtons.None)
|
|
{
|
|
State = PushButtonState.Normal;
|
|
}
|
|
}
|
|
else if (kevent.KeyCode.Equals(Keys.Apps))
|
|
{
|
|
if (MouseButtons == MouseButtons.None && !isSplitMenuVisible)
|
|
{
|
|
ShowContextMenuStrip();
|
|
}
|
|
}
|
|
|
|
base.OnKeyUp(kevent);
|
|
}
|
|
|
|
protected override void OnEnabledChanged(EventArgs e)
|
|
{
|
|
State = (Enabled ? PushButtonState.Normal : PushButtonState.Disabled);
|
|
base.OnEnabledChanged(e);
|
|
}
|
|
|
|
protected override void OnLostFocus(EventArgs e)
|
|
{
|
|
if (!showSplit)
|
|
{
|
|
base.OnLostFocus(e);
|
|
return;
|
|
}
|
|
|
|
if (!State.Equals(PushButtonState.Pressed) && !State.Equals(PushButtonState.Disabled))
|
|
{
|
|
State = PushButtonState.Normal;
|
|
}
|
|
}
|
|
|
|
protected override void OnMouseEnter(EventArgs e)
|
|
{
|
|
if (!showSplit)
|
|
{
|
|
base.OnMouseEnter(e);
|
|
return;
|
|
}
|
|
|
|
if (!State.Equals(PushButtonState.Pressed) && !State.Equals(PushButtonState.Disabled))
|
|
{
|
|
State = PushButtonState.Hot;
|
|
}
|
|
|
|
}
|
|
|
|
protected override void OnMouseLeave(EventArgs e)
|
|
{
|
|
if (!showSplit)
|
|
{
|
|
base.OnMouseLeave(e);
|
|
return;
|
|
}
|
|
|
|
if (!State.Equals(PushButtonState.Pressed) && !State.Equals(PushButtonState.Disabled))
|
|
{
|
|
State = Focused ? PushButtonState.Default : PushButtonState.Normal;
|
|
}
|
|
}
|
|
|
|
protected override void OnMouseDown(MouseEventArgs e)
|
|
{
|
|
if (!showSplit)
|
|
{
|
|
base.OnMouseDown(e);
|
|
return;
|
|
}
|
|
|
|
if (dropDownRectangle.Contains(e.Location) && !isSplitMenuVisible && e.Button == MouseButtons.Left)
|
|
{
|
|
ShowContextMenuStrip();
|
|
}
|
|
else
|
|
{
|
|
State = PushButtonState.Pressed;
|
|
}
|
|
}
|
|
|
|
protected override void OnMouseUp(MouseEventArgs mevent)
|
|
{
|
|
if (!showSplit)
|
|
{
|
|
base.OnMouseUp(mevent);
|
|
return;
|
|
}
|
|
|
|
// if the right button was released inside the button
|
|
if (mevent.Button == MouseButtons.Right && ClientRectangle.Contains(mevent.Location) && !isSplitMenuVisible)
|
|
{
|
|
ShowContextMenuStrip();
|
|
}
|
|
else if (m_SplitMenuStrip == null || !isSplitMenuVisible)
|
|
{
|
|
SetButtonDrawState();
|
|
|
|
if (ClientRectangle.Contains(mevent.Location) && !dropDownRectangle.Contains(mevent.Location))
|
|
{
|
|
//OnClick(new EventArgs());
|
|
if(currentmenustripitem != -1) m_SplitMenuStrip.Items[currentmenustripitem].PerformClick();
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override void OnPaint(PaintEventArgs pevent)
|
|
{
|
|
base.OnPaint(pevent);
|
|
|
|
if (!showSplit) return;
|
|
|
|
Graphics g = pevent.Graphics;
|
|
Rectangle bounds = ClientRectangle;
|
|
|
|
// draw the button background as according to the current state.
|
|
if (State != PushButtonState.Pressed && IsDefault && !Application.RenderWithVisualStyles)
|
|
{
|
|
Rectangle backgroundBounds = bounds;
|
|
backgroundBounds.Inflate(-1, -1);
|
|
ButtonRenderer.DrawButton(g, backgroundBounds, State);
|
|
|
|
// button renderer doesnt draw the black frame when themes are off
|
|
g.DrawRectangle(SystemPens.WindowFrame, 0, 0, bounds.Width - 1, bounds.Height - 1);
|
|
}
|
|
else
|
|
{
|
|
ButtonRenderer.DrawButton(g, bounds, State);
|
|
}
|
|
|
|
// calculate the current dropdown rectangle.
|
|
dropDownRectangle = new Rectangle(bounds.Right - splitsectionwidth, 0, splitsectionwidth, bounds.Height);
|
|
|
|
int internalBorder = borderSize;
|
|
Rectangle focusRect =
|
|
new Rectangle(internalBorder - 1,
|
|
internalBorder - 1,
|
|
bounds.Width - dropDownRectangle.Width - internalBorder,
|
|
bounds.Height - (internalBorder * 2) + 2);
|
|
|
|
bool drawSplitLine = (State == PushButtonState.Hot || State == PushButtonState.Pressed || !Application.RenderWithVisualStyles);
|
|
|
|
|
|
if (RightToLeft == RightToLeft.Yes)
|
|
{
|
|
dropDownRectangle.X = bounds.Left + 1;
|
|
focusRect.X = dropDownRectangle.Right;
|
|
|
|
if (drawSplitLine)
|
|
{
|
|
// draw two lines at the edge of the dropdown button
|
|
g.DrawLine(SystemPens.ButtonShadow, bounds.Left + splitsectionwidth, borderSize, bounds.Left + splitsectionwidth, bounds.Bottom - borderSize);
|
|
g.DrawLine(SystemPens.ButtonFace, bounds.Left + splitsectionwidth + 1, borderSize, bounds.Left + splitsectionwidth + 1, bounds.Bottom - borderSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (drawSplitLine)
|
|
{
|
|
// draw two lines at the edge of the dropdown button
|
|
g.DrawLine(SystemPens.ButtonShadow, bounds.Right - splitsectionwidth, borderSize, bounds.Right - splitsectionwidth, bounds.Bottom - borderSize);
|
|
g.DrawLine(SystemPens.ButtonFace, bounds.Right - splitsectionwidth - 1, borderSize, bounds.Right - splitsectionwidth - 1, bounds.Bottom - borderSize);
|
|
}
|
|
}
|
|
|
|
// Draw an arrow in the correct location
|
|
PaintArrow(g, dropDownRectangle);
|
|
|
|
// paint the image and text
|
|
PaintTextandImage(g, ClientRectangle /*new Rectangle(0, 0, ClientRectangle.Width, ClientRectangle.Height)*/);
|
|
|
|
// draw the focus rectangle.
|
|
if (State != PushButtonState.Pressed && Focused && ShowFocusCues)
|
|
{
|
|
ControlPaint.DrawFocusRectangle(g, focusRect);
|
|
}
|
|
}
|
|
|
|
private void PaintTextandImage(Graphics g, Rectangle bounds)
|
|
{
|
|
// Figure out where our text and image should go
|
|
Rectangle text_rectangle;
|
|
Rectangle image_rectangle;
|
|
|
|
CalculateButtonTextAndImageLayout(ref bounds, out text_rectangle, out image_rectangle);
|
|
|
|
//draw the image
|
|
if (Image != null)
|
|
{
|
|
if (Enabled)
|
|
g.DrawImage(Image, image_rectangle.X, image_rectangle.Y, Image.Width, Image.Height);
|
|
else
|
|
ControlPaint.DrawImageDisabled(g, Image, image_rectangle.X, image_rectangle.Y, BackColor);
|
|
}
|
|
|
|
// If we dont' use mnemonic, set formatFlag to NoPrefix as this will show ampersand.
|
|
if (!UseMnemonic)
|
|
textFormatFlags = textFormatFlags | TextFormatFlags.NoPrefix;
|
|
else if (!ShowKeyboardCues)
|
|
textFormatFlags = textFormatFlags | TextFormatFlags.HidePrefix;
|
|
|
|
//draw the text
|
|
if (!string.IsNullOrEmpty(Text))
|
|
{
|
|
if (Enabled)
|
|
TextRenderer.DrawText(g, Text, Font, text_rectangle, ForeColor, textFormatFlags);
|
|
else
|
|
ControlPaint.DrawStringDisabled(g, Text, Font, BackColor, text_rectangle, textFormatFlags);
|
|
}
|
|
}
|
|
|
|
private void PaintArrow(Graphics g, Rectangle dropDownRect)
|
|
{
|
|
Point middle = new Point(Convert.ToInt32(dropDownRect.Left + dropDownRect.Width / 2), Convert.ToInt32(dropDownRect.Top + dropDownRect.Height / 2));
|
|
|
|
//if the width is odd - favor pushing it over one pixel right.
|
|
middle.X += (dropDownRect.Width % 2);
|
|
|
|
Point[] arrow = new[] { new Point(middle.X - 2, middle.Y - 1), new Point(middle.X + 3, middle.Y - 1), new Point(middle.X, middle.Y + 2) };
|
|
g.FillPolygon(Enabled ? SystemBrushes.ControlText : SystemBrushes.ButtonShadow, arrow);
|
|
}
|
|
|
|
public override Size GetPreferredSize(Size proposedSize)
|
|
{
|
|
Size preferredSize = base.GetPreferredSize(proposedSize);
|
|
|
|
//autosize correctly for splitbuttons
|
|
if (showSplit)
|
|
{
|
|
if (AutoSize) return CalculateButtonAutoSize();
|
|
|
|
if (!string.IsNullOrEmpty(Text) && TextRenderer.MeasureText(Text, Font).Width + splitsectionwidth > preferredSize.Width)
|
|
return preferredSize + new Size(splitsectionwidth + borderSize * 2, 0);
|
|
}
|
|
|
|
return preferredSize;
|
|
}
|
|
|
|
private Size CalculateButtonAutoSize()
|
|
{
|
|
Size ret_size = Size.Empty;
|
|
Size text_size = TextRenderer.MeasureText(Text, Font);
|
|
Size image_size = Image == null ? Size.Empty : Image.Size;
|
|
|
|
// Pad the text size
|
|
if (Text.Length != 0)
|
|
{
|
|
text_size.Height += 4;
|
|
text_size.Width += 4;
|
|
}
|
|
|
|
switch (TextImageRelation)
|
|
{
|
|
case TextImageRelation.Overlay:
|
|
ret_size.Height = Math.Max(Text.Length == 0 ? 0 : text_size.Height, image_size.Height);
|
|
ret_size.Width = Math.Max(text_size.Width, image_size.Width);
|
|
break;
|
|
case TextImageRelation.ImageAboveText:
|
|
case TextImageRelation.TextAboveImage:
|
|
ret_size.Height = text_size.Height + image_size.Height;
|
|
ret_size.Width = Math.Max(text_size.Width, image_size.Width);
|
|
break;
|
|
case TextImageRelation.ImageBeforeText:
|
|
case TextImageRelation.TextBeforeImage:
|
|
ret_size.Height = Math.Max(text_size.Height, image_size.Height);
|
|
ret_size.Width = text_size.Width + image_size.Width;
|
|
break;
|
|
}
|
|
|
|
// Pad the result
|
|
ret_size.Height += (Padding.Vertical + 6);
|
|
ret_size.Width += (Padding.Horizontal + 6);
|
|
|
|
//pad the splitButton arrow region
|
|
if (showSplit) ret_size.Width += splitsectionwidth;
|
|
|
|
return ret_size;
|
|
}
|
|
|
|
#region Button Layout Calculations
|
|
|
|
//The following layout functions were taken from Mono's Windows.Forms
|
|
//implementation, specifically "ThemeWin32Classic.cs",
|
|
//then modified to fit the context of this splitButton
|
|
|
|
private void CalculateButtonTextAndImageLayout(ref Rectangle content_rect, out Rectangle textRectangle, out Rectangle imageRectangle)
|
|
{
|
|
Size text_size = TextRenderer.MeasureText(Text, Font, content_rect.Size, textFormatFlags);
|
|
Size image_size = Image == null ? Size.Empty : Image.Size;
|
|
|
|
textRectangle = Rectangle.Empty;
|
|
imageRectangle = Rectangle.Empty;
|
|
|
|
switch (TextImageRelation)
|
|
{
|
|
case TextImageRelation.Overlay:
|
|
// Overlay is easy, text always goes here
|
|
textRectangle = OverlayObjectRect(ref content_rect, ref text_size, TextAlign); // Rectangle.Inflate(content_rect, -4, -4);
|
|
|
|
//Offset on Windows 98 style when button is pressed
|
|
if (state == PushButtonState.Pressed && !Application.RenderWithVisualStyles)
|
|
textRectangle.Offset(1, 1);
|
|
|
|
// Image is dependent on ImageAlign
|
|
if (Image != null)
|
|
imageRectangle = OverlayObjectRect(ref content_rect, ref image_size, ImageAlign);
|
|
|
|
break;
|
|
case TextImageRelation.ImageAboveText:
|
|
content_rect.Inflate(-4, -4);
|
|
LayoutTextAboveOrBelowImage(content_rect, false, text_size, image_size, out textRectangle, out imageRectangle);
|
|
break;
|
|
case TextImageRelation.TextAboveImage:
|
|
content_rect.Inflate(-4, -4);
|
|
LayoutTextAboveOrBelowImage(content_rect, true, text_size, image_size, out textRectangle, out imageRectangle);
|
|
break;
|
|
case TextImageRelation.ImageBeforeText:
|
|
content_rect.Inflate(-4, -4);
|
|
LayoutTextBeforeOrAfterImage(content_rect, false, text_size, image_size, out textRectangle, out imageRectangle);
|
|
break;
|
|
case TextImageRelation.TextBeforeImage:
|
|
content_rect.Inflate(-4, -4);
|
|
LayoutTextBeforeOrAfterImage(content_rect, true, text_size, image_size, out textRectangle, out imageRectangle);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private static Rectangle OverlayObjectRect(ref Rectangle container, ref Size sizeOfObject, System.Drawing.ContentAlignment alignment)
|
|
{
|
|
int x, y;
|
|
|
|
switch (alignment)
|
|
{
|
|
case System.Drawing.ContentAlignment.TopLeft:
|
|
x = 4;
|
|
y = 4;
|
|
break;
|
|
case System.Drawing.ContentAlignment.TopCenter:
|
|
x = (container.Width - sizeOfObject.Width) / 2;
|
|
y = 4;
|
|
break;
|
|
case System.Drawing.ContentAlignment.TopRight:
|
|
x = container.Width - sizeOfObject.Width - 4;
|
|
y = 4;
|
|
break;
|
|
case System.Drawing.ContentAlignment.MiddleLeft:
|
|
x = 4;
|
|
y = (container.Height - sizeOfObject.Height) / 2;
|
|
break;
|
|
case System.Drawing.ContentAlignment.MiddleCenter:
|
|
x = (container.Width - sizeOfObject.Width) / 2;
|
|
y = (container.Height - sizeOfObject.Height) / 2;
|
|
break;
|
|
case System.Drawing.ContentAlignment.MiddleRight:
|
|
x = container.Width - sizeOfObject.Width - 4;
|
|
y = (container.Height - sizeOfObject.Height) / 2;
|
|
break;
|
|
case System.Drawing.ContentAlignment.BottomLeft:
|
|
x = 4;
|
|
y = container.Height - sizeOfObject.Height - 4;
|
|
break;
|
|
case System.Drawing.ContentAlignment.BottomCenter:
|
|
x = (container.Width - sizeOfObject.Width) / 2;
|
|
y = container.Height - sizeOfObject.Height - 4;
|
|
break;
|
|
case System.Drawing.ContentAlignment.BottomRight:
|
|
x = container.Width - sizeOfObject.Width - 4;
|
|
y = container.Height - sizeOfObject.Height - 4;
|
|
break;
|
|
default:
|
|
x = 4;
|
|
y = 4;
|
|
break;
|
|
}
|
|
|
|
return new Rectangle(x, y, sizeOfObject.Width, sizeOfObject.Height);
|
|
}
|
|
|
|
private void LayoutTextBeforeOrAfterImage(Rectangle totalArea, bool textFirst, Size textSize, Size imageSize, out Rectangle textRect, out Rectangle imageRect)
|
|
{
|
|
int element_spacing = 0; // Spacing between the Text and the Image
|
|
int total_width = textSize.Width + element_spacing + imageSize.Width;
|
|
|
|
if (!textFirst)
|
|
element_spacing += 2;
|
|
|
|
// If the text is too big, chop it down to the size we have available to it
|
|
if (total_width > totalArea.Width)
|
|
{
|
|
textSize.Width = totalArea.Width - element_spacing - imageSize.Width;
|
|
total_width = totalArea.Width;
|
|
}
|
|
|
|
int excess_width = totalArea.Width - total_width;
|
|
int offset = 0;
|
|
|
|
Rectangle final_text_rect;
|
|
Rectangle final_image_rect;
|
|
|
|
HorizontalAlignment h_text = GetHorizontalAlignment(TextAlign);
|
|
HorizontalAlignment h_image = GetHorizontalAlignment(ImageAlign);
|
|
|
|
if (h_image == HorizontalAlignment.Left)
|
|
offset = 0;
|
|
else if (h_image == HorizontalAlignment.Right && h_text == HorizontalAlignment.Right)
|
|
offset = excess_width;
|
|
else if (h_image == HorizontalAlignment.Center && (h_text == HorizontalAlignment.Left || h_text == HorizontalAlignment.Center))
|
|
offset += excess_width / 3;
|
|
else
|
|
offset += 2 * (excess_width / 3);
|
|
|
|
if (textFirst)
|
|
{
|
|
final_text_rect = new Rectangle(totalArea.Left + offset, AlignInRectangle(totalArea, textSize, TextAlign).Top, textSize.Width, textSize.Height);
|
|
final_image_rect = new Rectangle(final_text_rect.Right + element_spacing, AlignInRectangle(totalArea, imageSize, ImageAlign).Top, imageSize.Width, imageSize.Height);
|
|
}
|
|
else
|
|
{
|
|
final_image_rect = new Rectangle(totalArea.Left + offset, AlignInRectangle(totalArea, imageSize, ImageAlign).Top, imageSize.Width, imageSize.Height);
|
|
final_text_rect = new Rectangle(final_image_rect.Right + element_spacing, AlignInRectangle(totalArea, textSize, TextAlign).Top, textSize.Width, textSize.Height);
|
|
}
|
|
|
|
textRect = final_text_rect;
|
|
imageRect = final_image_rect;
|
|
}
|
|
|
|
private void LayoutTextAboveOrBelowImage(Rectangle totalArea, bool textFirst, Size textSize, Size imageSize, out Rectangle textRect, out Rectangle imageRect)
|
|
{
|
|
int element_spacing = 0; // Spacing between the Text and the Image
|
|
int total_height = textSize.Height + element_spacing + imageSize.Height;
|
|
|
|
if (textFirst)
|
|
element_spacing += 2;
|
|
|
|
if (textSize.Width > totalArea.Width)
|
|
textSize.Width = totalArea.Width;
|
|
|
|
// If the there isn't enough room and we're text first, cut out the image
|
|
if (total_height > totalArea.Height && textFirst)
|
|
{
|
|
imageSize = Size.Empty;
|
|
total_height = totalArea.Height;
|
|
}
|
|
|
|
int excess_height = totalArea.Height - total_height;
|
|
int offset = 0;
|
|
|
|
Rectangle final_text_rect;
|
|
Rectangle final_image_rect;
|
|
|
|
VerticalAlignment v_text = GetVerticalAlignment(TextAlign);
|
|
VerticalAlignment v_image = GetVerticalAlignment(ImageAlign);
|
|
|
|
if (v_image == VerticalAlignment.Top)
|
|
offset = 0;
|
|
else if (v_image == VerticalAlignment.Bottom && v_text == VerticalAlignment.Bottom)
|
|
offset = excess_height;
|
|
else if (v_image == VerticalAlignment.Center && (v_text == VerticalAlignment.Top || v_text == VerticalAlignment.Center))
|
|
offset += excess_height / 3;
|
|
else
|
|
offset += 2 * (excess_height / 3);
|
|
|
|
if (textFirst)
|
|
{
|
|
final_text_rect = new Rectangle(AlignInRectangle(totalArea, textSize, TextAlign).Left, totalArea.Top + offset, textSize.Width, textSize.Height);
|
|
final_image_rect = new Rectangle(AlignInRectangle(totalArea, imageSize, ImageAlign).Left, final_text_rect.Bottom + element_spacing, imageSize.Width, imageSize.Height);
|
|
}
|
|
else
|
|
{
|
|
final_image_rect = new Rectangle(AlignInRectangle(totalArea, imageSize, ImageAlign).Left, totalArea.Top + offset, imageSize.Width, imageSize.Height);
|
|
final_text_rect = new Rectangle(AlignInRectangle(totalArea, textSize, TextAlign).Left, final_image_rect.Bottom + element_spacing, textSize.Width, textSize.Height);
|
|
|
|
if (final_text_rect.Bottom > totalArea.Bottom)
|
|
final_text_rect.Y = totalArea.Top;
|
|
}
|
|
|
|
textRect = final_text_rect;
|
|
imageRect = final_image_rect;
|
|
}
|
|
|
|
private static HorizontalAlignment GetHorizontalAlignment(System.Drawing.ContentAlignment align)
|
|
{
|
|
switch (align)
|
|
{
|
|
case System.Drawing.ContentAlignment.BottomLeft:
|
|
case System.Drawing.ContentAlignment.MiddleLeft:
|
|
case System.Drawing.ContentAlignment.TopLeft:
|
|
return HorizontalAlignment.Left;
|
|
case System.Drawing.ContentAlignment.BottomCenter:
|
|
case System.Drawing.ContentAlignment.MiddleCenter:
|
|
case System.Drawing.ContentAlignment.TopCenter:
|
|
return HorizontalAlignment.Center;
|
|
case System.Drawing.ContentAlignment.BottomRight:
|
|
case System.Drawing.ContentAlignment.MiddleRight:
|
|
case System.Drawing.ContentAlignment.TopRight:
|
|
return HorizontalAlignment.Right;
|
|
}
|
|
|
|
return HorizontalAlignment.Left;
|
|
}
|
|
|
|
private static VerticalAlignment GetVerticalAlignment(System.Drawing.ContentAlignment align)
|
|
{
|
|
switch (align)
|
|
{
|
|
case System.Drawing.ContentAlignment.TopLeft:
|
|
case System.Drawing.ContentAlignment.TopCenter:
|
|
case System.Drawing.ContentAlignment.TopRight:
|
|
return VerticalAlignment.Top;
|
|
case System.Drawing.ContentAlignment.MiddleLeft:
|
|
case System.Drawing.ContentAlignment.MiddleCenter:
|
|
case System.Drawing.ContentAlignment.MiddleRight:
|
|
return VerticalAlignment.Center;
|
|
case System.Drawing.ContentAlignment.BottomLeft:
|
|
case System.Drawing.ContentAlignment.BottomCenter:
|
|
case System.Drawing.ContentAlignment.BottomRight:
|
|
return VerticalAlignment.Bottom;
|
|
}
|
|
|
|
return VerticalAlignment.Top;
|
|
}
|
|
|
|
private static Rectangle AlignInRectangle(Rectangle outer, Size inner, System.Drawing.ContentAlignment align)
|
|
{
|
|
int x = 0;
|
|
int y = 0;
|
|
|
|
if (align == System.Drawing.ContentAlignment.BottomLeft || align == System.Drawing.ContentAlignment.MiddleLeft || align == System.Drawing.ContentAlignment.TopLeft)
|
|
x = outer.X;
|
|
else if (align == System.Drawing.ContentAlignment.BottomCenter || align == System.Drawing.ContentAlignment.MiddleCenter || align == System.Drawing.ContentAlignment.TopCenter)
|
|
x = Math.Max(outer.X + ((outer.Width - inner.Width) / 2), outer.Left);
|
|
else if (align == System.Drawing.ContentAlignment.BottomRight || align == System.Drawing.ContentAlignment.MiddleRight || align == System.Drawing.ContentAlignment.TopRight)
|
|
x = outer.Right - inner.Width;
|
|
if (align == System.Drawing.ContentAlignment.TopCenter || align == System.Drawing.ContentAlignment.TopLeft || align == System.Drawing.ContentAlignment.TopRight)
|
|
y = outer.Y;
|
|
else if (align == System.Drawing.ContentAlignment.MiddleCenter || align == System.Drawing.ContentAlignment.MiddleLeft || align == System.Drawing.ContentAlignment.MiddleRight)
|
|
y = outer.Y + (outer.Height - inner.Height) / 2;
|
|
else if (align == System.Drawing.ContentAlignment.BottomCenter || align == System.Drawing.ContentAlignment.BottomRight || align == System.Drawing.ContentAlignment.BottomLeft)
|
|
y = outer.Bottom - inner.Height;
|
|
|
|
return new Rectangle(x, y, Math.Min(inner.Width, outer.Width), Math.Min(inner.Height, outer.Height));
|
|
}
|
|
|
|
#endregion Button Layout Calculations
|
|
|
|
private void ShowContextMenuStrip()
|
|
{
|
|
if (skipNextOpen)
|
|
{
|
|
// we were called because we're closing the context menu strip
|
|
// when clicking the dropdown button.
|
|
skipNextOpen = false;
|
|
return;
|
|
}
|
|
|
|
State = PushButtonState.Pressed;
|
|
|
|
if (m_SplitMenuStrip != null)
|
|
{
|
|
m_SplitMenuStrip.Show(this, new Point(0, Height), ToolStripDropDownDirection.BelowRight);
|
|
}
|
|
}
|
|
|
|
private void SplitMenuStrip_Opening(object sender, CancelEventArgs e)
|
|
{
|
|
isSplitMenuVisible = true;
|
|
}
|
|
|
|
private void SplitMenuStrip_Closing(object sender, ToolStripDropDownClosingEventArgs e)
|
|
{
|
|
isSplitMenuVisible = false;
|
|
|
|
SetButtonDrawState();
|
|
|
|
if (e.CloseReason == ToolStripDropDownCloseReason.AppClicked)
|
|
{
|
|
skipNextOpen = (dropDownRectangle.Contains(PointToClient(Cursor.Position))) && MouseButtons == MouseButtons.Left;
|
|
}
|
|
}
|
|
|
|
//mxd
|
|
private void SplitMenuStrip_OnItemClicked(object sender, ToolStripItemClickedEventArgs e)
|
|
{
|
|
this.Text = e.ClickedItem.Text;
|
|
this.Image = e.ClickedItem.Image;
|
|
currentmenustripitem = m_SplitMenuStrip.Items.IndexOf(e.ClickedItem);
|
|
}
|
|
|
|
protected override void WndProc(ref Message m)
|
|
{
|
|
//0x0212 == WM_EXITMENULOOP
|
|
if (m.Msg == 0x0212)
|
|
{
|
|
//this message is only sent when a ContextMenu is closed (not a ContextMenuStrip)
|
|
isSplitMenuVisible = false;
|
|
SetButtonDrawState();
|
|
}
|
|
|
|
base.WndProc(ref m);
|
|
}
|
|
|
|
private void SetButtonDrawState()
|
|
{
|
|
if (Bounds.Contains(Parent.PointToClient(Cursor.Position)))
|
|
{
|
|
State = PushButtonState.Hot;
|
|
}
|
|
else if (Focused)
|
|
{
|
|
State = PushButtonState.Default;
|
|
}
|
|
else if (!Enabled)
|
|
{
|
|
State = PushButtonState.Disabled;
|
|
}
|
|
else
|
|
{
|
|
State = PushButtonState.Normal;
|
|
}
|
|
}
|
|
}
|
|
} |