📄 menucontrol.cs
字号:
length = this.Height;
// Is there space for any commands?
if (length > 0)
{
// Count the number of rows needed
int rows = 0;
// Number of items on this row
int columns = 0;
// Create a collection of drawing objects
_drawCommands = new ArrayList();
// Minimum length is a gap on either side of the text
int cellMinLength = _lengthGap * 2;
// Each cell is as broad as the whole control
int cellBreadth = this.Height;
// Accumulate starting position of each cell
int lengthStart = 0;
// If the chevron is already displayed then reduce length by its length
if (_chevronStartCommand != null)
length -= cellMinLength + _chevronLength;
// Assume chevron is not needed by default
_chevronStartCommand = null;
using(Graphics g = this.CreateGraphics())
{
// Count the item we are processing
int index = 0;
foreach(MenuCommand command in _menuCommands)
{
// Give the command a chance to update its state
command.OnUpdate(EventArgs.Empty);
// Ignore items that are marked as hidden
if (!command.Visible)
continue;
int cellLength = 0;
// Is this a separator?
if (command.Text == "-")
cellLength = _separatorWidth;
else
{
// Calculate the text width of the cell
SizeF dimension = g.MeasureString(command.Text, this.Font);
// Always add 1 to ensure that rounding is up and not down
cellLength = cellMinLength + (int)dimension.Width + 1;
}
Rectangle cellRect;
// Create a new position rectangle
if (_direction == Direction.Horizontal)
cellRect = new Rectangle(lengthStart, _rowHeight * rows, cellLength, _rowHeight);
else
cellRect = new Rectangle(_rowWidth * rows, lengthStart, _rowWidth, cellLength);
lengthStart += cellLength;
columns++;
// If this item is overlapping the control edge and it is not the first
// item on the line then we should wrap around to the next row.
if ((lengthStart > length) && (columns > 1))
{
if (_multiLine)
{
// Move to next row
rows++;
// Reset number of items on this column
columns = 1;
// Reset starting position of next item
lengthStart = cellLength;
// Reset position of this item
if (_direction == Direction.Horizontal)
{
cellRect.X = 0;
cellRect.Y += _rowHeight;
}
else
{
cellRect.X += _rowWidth;
cellRect.Y = 0;
}
}
else
{
// Is a tracked item being make invisible
if (index <= _trackItem)
{
// Need to remove tracking of this item
_trackItem = -1;
}
// Remember which item is first for the chevron submenu
_chevronStartCommand = command;
if (_direction == Direction.Horizontal)
{
cellRect.Y = 0;
cellRect.Width = cellMinLength + _chevronLength;
cellRect.X = this.Width - cellRect.Width;
cellRect.Height = _rowHeight;
}
else
{
cellRect.X = 0;
cellRect.Height = cellMinLength + _chevronLength;
cellRect.Y = this.Height - (cellMinLength + _chevronLength);
cellRect.Width = _rowWidth;
}
// Create a draw command for this chevron
_drawCommands.Add(new DrawCommand(cellRect));
// Exit, do not add the current item or any afterwards
break;
}
}
// Create a drawing object
_drawCommands.Add(new DrawCommand(command, cellRect));
index++;
}
}
if (_direction == Direction.Horizontal)
{
int controlHeight = (rows + 1) * _rowHeight;
// Ensure the control is the correct height
if (this.Height != controlHeight)
this.Height = controlHeight;
}
else
{
int controlWidth = (rows + 1) * _rowWidth;
// Ensure the control is the correct width
if (this.Width != controlWidth)
this.Width = controlWidth;
}
}
}
protected void DrawCommand(int drawItem, bool tracked)
{
// Create a graphics object for drawing
using(Graphics g = this.CreateGraphics())
DrawSingleCommand(g, _drawCommands[drawItem] as DrawCommand, tracked);
}
internal void DrawSingleCommand(Graphics g, DrawCommand dc, bool tracked)
{
Rectangle drawRect = dc.DrawRect;
MenuCommand mc = dc.MenuCommand;
// Copy the rectangle used for drawing cell
Rectangle shadowRect = drawRect;
// Expand to right and bottom to cover the area used to draw shadows
shadowRect.Width += _shadowGap;
shadowRect.Height += _shadowGap;
// Draw background color over cell and shadow area to the right
using(SolidBrush back = new SolidBrush(SystemColors.Control))
g.FillRectangle(back, shadowRect);
if (!dc.Separator)
{
Rectangle textRect;
// Text rectangle size depends on type of draw command we are drawing
if (dc.Chevron)
{
// Create chevron drawing rectangle
textRect = new Rectangle(drawRect.Left + _lengthGap, drawRect.Top + _boxExpandUpper,
drawRect.Width - _lengthGap * 2, drawRect.Height - (_boxExpandUpper * 2));
}
else
{
// Create text drawing rectangle
textRect = new Rectangle(drawRect.Left + _lengthGap, drawRect.Top + _lengthGap,
drawRect.Width - _lengthGap * 2, drawRect.Height - _lengthGap * 2);
}
if (dc.Enabled)
{
// Draw selection
if (tracked)
{
Rectangle boxRect;
// Create the rectangle for box around the text
if (_direction == Direction.Horizontal)
{
boxRect = new Rectangle(textRect.Left - _boxExpandSides,
textRect.Top - _boxExpandUpper,
textRect.Width + _boxExpandSides * 2,
textRect.Height + _boxExpandUpper);
}
else
{
if (!dc.Chevron)
{
boxRect = new Rectangle(textRect.Left,
textRect.Top - _boxExpandSides,
textRect.Width - _boxExpandSides,
textRect.Height + _boxExpandSides * 2);
}
else
boxRect = textRect;
}
switch(_style)
{
case VisualStyle.IDE:
if (_selected)
{
// Fill the entire inside
g.FillRectangle(SystemBrushes.ControlLight, boxRect);
int rightLeft = boxRect.Right + 1;
int rightBottom = boxRect.Bottom;
if (_drawUpwards && (_direction == Direction.Horizontal))
{
// Draw the box around the selection area
using(Pen dark = new Pen(SystemColors.ControlDark))
g.DrawRectangle(dark, boxRect.Left, boxRect.Top - _shadowGap,
boxRect.Width, boxRect.Height + _shadowGap);
// Remove the top line of the selection area
using(Pen dark = new Pen(SystemColors.ControlLight))
g.DrawLine(dark, boxRect.Left + 1, boxRect.Top, boxRect.Right - 2, boxRect.Top);
int rightTop = boxRect.Top;
int leftLeft = boxRect.Left + _shadowGap;
SolidBrush shadowBrush;
// Decide if we need to use an alpha brush
if (_supportsLayered && (_style == VisualStyle.IDE))
shadowBrush = new SolidBrush(Color.FromArgb(64, 0, 0, 0));
else
shadowBrush = new SolidBrush(SystemColors.ControlDark);
g.FillRectangle(shadowBrush, new Rectangle(rightLeft, rightTop + _shadowGap - 1, _shadowGap, rightBottom - rightTop - _shadowGap*2));
shadowBrush.Dispose();
}
else
{
// Draw the box around the selection area
using(Pen dark = new Pen(SystemColors.ControlDark))
g.DrawRectangle(dark, boxRect);
if (_direction == Direction.Horizontal)
{
// Remove the bottom line of the selection area
using(Pen dark = new Pen(SystemColors.ControlLight))
g.DrawLine(dark, boxRect.Left, boxRect.Bottom, boxRect.Right, boxRect.Bottom);
int rightTop = boxRect.Top + _shadowYOffset;
SolidBrush shadowBrush;
// Decide if we need to use an alpha brush
if (_supportsLayered && (_style == VisualStyle.IDE))
shadowBrush = new SolidBrush(Color.FromArgb(64, 0, 0, 0));
else
shadowBrush = new SolidBrush(SystemColors.ControlDark);
g.FillRectangle(shadowBrush, new Rectangle(rightLeft, rightTop, _shadowGap, rightBottom - rightTop));
shadowBrush.Dispose();
}
else
{
// Remove the right line of the selection area
using(Pen dark = new Pen(SystemColors.ControlLight))
g.DrawLine(dark, boxRect.Right, boxRect.Top, boxRect.Right, boxRect.Bottom);
int leftLeft = boxRect.Left + _shadowYOffset;
SolidBrush shadowBrush;
// Decide if we need to use an alpha brush
if (_supportsLayered && (_style == VisualStyle.IDE))
shadowBrush = new SolidBrush(Color.FromArgb(64, 0, 0, 0));
else
shadowBrush = new SolidBrush(SystemColors.ControlDark);
g.FillRectangle(shadowBrush, new Rectangle(leftLeft, rightBottom+1, rightBottom - leftLeft - _shadowGap, _shadowGap));
shadowBrush.Dispose();
}
}
}
else
{
using (Pen selectPen = new Pen(ColorUtil.VSNetBorderColor))
{
// Draw the selection area in white so can alpha draw over the top
using (SolidBrush whiteBrush = new SolidBrush(Color.White))
g.FillRectangle(whiteBrush, boxRect);
using (SolidBrush selectBrush = new SolidBrush(Color.FromArgb(70, ColorUtil.VSNetBorderColor)))
{
// Draw the selection area
g.FillRectangle(selectBrush, boxRect);
// Draw a border around the selection area
g.DrawRectangle(selectPen, boxRect);
}
}
}
break;
case VisualStyle.Plain:
if (_plainAsBlock)
{
using (SolidBrush selectBrush = new SolidBrush(ColorUtil.VSNetBorderColor))
g.FillRectangle(selectBrush, drawRect);
}
else
{
using(Pen lighlight = new Pen(SystemColors.ControlLightLight),
dark = new Pen(SystemColors.ControlDark))
{
if (_selected)
{
g.DrawLine(dark, boxRect.Left, boxRect.Bottom, boxRect.Left, boxRect.Top);
g.DrawLine(dark, boxRect.Left, boxRect.Top, boxRect.Right, boxRect.Top);
g.DrawLine(lighlight, boxRect.Right, boxRect.Top, boxRect.Right, boxRect.Bottom);
g.DrawLine(lighlight, boxRect.Right, boxRect.Bottom, boxRect.Left, boxRect.Bottom);
}
else
{
g.DrawLine(lighlight, boxRect.Left, boxRect.Bottom, boxRect.Left, boxRect.Top);
g.DrawLine(lighlight, boxRect.Left, boxRect.Top, boxRect.Right, boxRect.Top);
g.DrawLine(dark, boxRect.Right, boxRect.Top, boxRect.Right, boxRect.Bottom);
g.DrawLine(dark, boxRect.Right, boxRect.Bottom, boxRect.Left, boxRect.Bottom);
}
}
}
break;
}
}
}
if (dc.Chevron)
{
// Draw the chevron image in the centre of the text area
int yPos = drawRect.Top;
int xPos = drawRect.X + ((drawRect.Width - _chevronLength) / 2);
// When selected...
if (_selected)
{
// ...offset down and to the right
xPos += 1;
yPos += 1;
}
g.DrawImage(_menuImages.Images[_chevronIndex], xPos, yPos);
}
else
{
// Left align the text drawing on a single line centered vertically
// and process the & character to be shown as an underscore on next character
StringFormat format = new StringFormat();
format.FormatFlags = StringFormatFlags.NoClip | StringFormatFlags.NoWrap;
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;
format.HotkeyPrefix = HotkeyPrefix.Show;
if (_direction == Direction.Vertical)
format.FormatFlags |= StringFormatFlags.DirectionVertical;
if (dc.Enabled)
{
if (tracked && (_style == VisualStyle.Plain) && _plainAsBlock)
{
// Is the item selected as well as tracked?
if (_selected)
{
// Offset to show it is selected
textRect.X += 2;
textRect.Y += 2;
}
using (SolidBrush textBrush = new SolidBrush(SystemColors.HighlightText))
g.DrawString(mc.Text, this.Font, textBrush, textRect, format);
}
else
using (SolidBrush textBrush = new SolidBrush(SystemColors.MenuText))
g.DrawString(mc.Text, this.Font, textBrush, textRect, format);
}
else
{
// Helper values used when drawing grayed text in plain style
Rectangle rectDownRight = textRect;
rectDownRight.Offset(1,1);
// Draw then text offset down and right
using (SolidBrush whiteBrush = new SolidBrush(SystemColors.HighlightText))
g.DrawString(mc.Text, this.Font, whiteBrush, rectDownRight, format);
// Draw then text offset up and left
using (SolidBrush grayBrush = new SolidBrush(SystemColors.GrayText))
g.DrawString(mc.Text, this.Font, grayBrush, textRect, format);
}
}
}
}
protected void DrawAllCommands(Graphics g)
{
for(int i=0; i<_drawCommands.Count; i++)
{
// Grab some commonly used values
DrawCommand dc = _drawCommands[i] as DrawCommand;
// Draw this command only
DrawSingleCommand(g, dc, (i == _trackItem));
}
}
protected int SwitchTrackingItem(int oldItem, int newItem)
{
// Create a graphics object for drawinh
using(Graphics g = this.CreateGraphics())
{
// Deselect the old draw command
if (oldItem != -1)
{
DrawCommand dc = _drawCommands[oldItem] as DrawCommand;
// Draw old item not selected
DrawSingleCommand(g, _drawCommands[oldItem] as DrawCommand, false);
}
_trackItem = newItem;
// Select the new draw command
if (_trackItem != -1)
{
DrawCommand dc = _drawCommands[_trackItem] as DrawCommand;
// Draw new item selected
DrawSingleCommand(g, _drawCommands[_trackItem] as DrawCommand, true);
}
}
return _trackItem;
}
internal void OperateSubMenu(DrawCommand dc, bool selectFirst, bool trackRemove)
{
Rectangle drawRect = dc.DrawRect;
// Find screen positions for popup menu
Point screenPos;
if (_style == VisualStyle.IDE)
{
if (_direction == Direction.Horizontal)
screenPos = PointToScreen(new Point(dc.DrawRect.Left + 1, drawRect.Bottom - _lengthGap - 1));
else
screenPos = PointToScreen(new Point(dc.DrawRect.Right - _breadthGap, drawRect.Top + _boxExpandSides - 1));
}
else
{
if (_direction == Direction.Horizontal)
screenPos = PointToScreen(new Point(dc.DrawRect.Left + 1, drawRect.Bottom));
else
screenPos = PointToScreen(new Point(dc.DrawRect.Right, drawRect.Top));
}
Point aboveScreenPos;
if (_style == VisualStyle.IDE)
{
if (_direction == Direction.Horizontal)
aboveScreenPos = PointToScreen(new Point(dc.DrawRect.Left + 1, drawRect.Top + _lengthGap + 1));
else
aboveScreenPos = PointToScreen(new Point(dc.DrawRect.Right - _breadthGap, drawRect.Bottom + _lengthGap));
}
else
{
if (_direction == Direction.Horizontal)
aboveScreenPos = PointToScreen(new Point(dc.DrawRect.Left + 1, drawRect.Top));
else
aboveScreenPos = PointToScreen(new Point(dc.DrawRect.Right, drawRect.Bottom));
}
int borderGap;
// Calculate the missing gap in the PopupMenu border
if (_direction == Direction.Horizontal)
borderGap = dc.DrawRect.Width - _subMenuBorderAdjust;
else
borderGap = dc.DrawRect.Height - _subMenuBorderAdjust;
_popupMenu = new PopupMenu();
// Define the correct visual style based on ours
_popupMenu.Style = this.Style;
// Key direction when keys cause dismissal
int returnDir = 0;
if (dc.Chevron)
{
MenuCommandCollection mcc = new MenuCommandCollection();
bool addCommands = false;
// Generate a collection of menu commands for those not visible
foreach(MenuCommand command in _menuCommands)
{
if (!addCommands && (command == _chevronStartCommand))
addCommands = true;
if (addCommands)
mcc.Add(command);
}
// Track the popup using provided menu item collection
_popupMenu.TrackPopup(screenPos,
aboveScreenPos,
_direction,
mcc,
borderGap,
selectFirst,
this,
ref returnDir);
}
else
{
// Generate event so that caller has chance to modify MenuCommand contents
OnPopupStart(dc.MenuCommand);
// Track the popup using provided menu item collection
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -