📄 popupmenu.cs
字号:
Region drawRegion = new Region();
// Can draw anywhere
drawRegion.MakeInfinite();
// Remove the area above the right hand shadow
drawRegion.Xor(new Rectangle(winSize.Width - shadowWidth, 0, shadowWidth, shadowHeight));
// When drawing upwards from a vertical menu we need to allow a connection between the
// MenuControl selection box and the PopupMenu shadow
if (!((_direction == Direction.Vertical) && !_excludeTop))
{
// Remove the area left of the bottom shadow
drawRegion.Xor(new Rectangle(0, winSize.Height - shadowHeight, shadowWidth, shadowHeight));
}
// Define a region to prevent drawing over exposed corners of shadows
using(Graphics g = Graphics.FromHwnd(this.Handle))
WindowsAPI.SetWindowRgn(this.Handle, drawRegion.GetHrgn(g), false);
}
}
protected Point CorrectPositionForScreen(Size winSize)
{
Point screenPos = _screenPos;
int screenWidth = SystemInformation.WorkingArea.Width;
int screenHeight = SystemInformation.WorkingArea.Height;
// Default to excluding menu border from top
_excludeTop = true;
_excludeOffset = 0;
// Calculate the downward position first
if (_popupDown)
{
// Ensure the end of the menu is not off the bottom of the screen
if ((screenPos.Y + winSize.Height) > screenHeight)
{
// If the parent control exists then try and position upwards instead
if ((_parentControl != null) && (_parentMenu == null))
{
// Is there space above the required position?
if ((_aboveScreenPos.Y - winSize.Height) > 0)
{
// Great...do that instead
screenPos.Y = _aboveScreenPos.Y - winSize.Height;
// Reverse direction of drawing this and submenus
_popupDown = false;
// Remember to exclude border from bottom of menu and not the top
_excludeTop = false;
// Inform parent it needs to redraw the selection upwards
_parentControl.DrawSelectionUpwards();
}
}
// Did the above logic still fail?
if ((screenPos.Y + winSize.Height) > screenHeight)
{
// If not a top level PopupMenu then..
if (_parentMenu != null)
{
// Reverse direction of drawing this and submenus
_popupDown = false;
// Is there space above the required position?
if ((_aboveScreenPos.Y - winSize.Height) > 0)
screenPos.Y = _aboveScreenPos.Y - winSize.Height;
else
screenPos.Y = 0;
}
else
screenPos.Y = screenHeight - winSize.Height - 1;
}
}
}
else
{
// Ensure the end of the menu is not off the top of the screen
if ((screenPos.Y - winSize.Height) < 0)
{
// Reverse direction
_popupDown = true;
// Is there space below the required position?
if ((screenPos.Y + winSize.Height) > screenHeight)
screenPos.Y = screenHeight - winSize.Height - 1;
}
else
screenPos.Y -= winSize.Height;
}
// Calculate the across position next
if (_popupRight)
{
// Ensure that right edge of menu is not off right edge of screen
if ((screenPos.X + winSize.Width) > screenWidth)
{
// If not a top level PopupMenu then...
if (_parentMenu != null)
{
// Reverse direction
_popupRight = false;
// Adjust across position
screenPos.X = _leftScreenPos.X - winSize.Width;
if (screenPos.X < 0)
screenPos.X = 0;
}
else
{
// Find new position of X coordinate
int newX = screenWidth - winSize.Width - 1;
// Modify the adjust needed when drawing top/bottom border
_excludeOffset = screenPos.X - newX;
// Use new position for popping up menu
screenPos.X = newX;
}
}
}
else
{
// Start by using the left screen pos instead
screenPos.X = _leftScreenPos.X;
// Ensure the left edge of the menu is not off the left of the screen
if ((screenPos.X - winSize.Width) < 0)
{
// Reverse direction
_popupRight = true;
// Is there space below the required position?
if ((_screenPos.X + winSize.Width) > screenWidth)
screenPos.X = screenWidth - winSize.Width - 1;
else
screenPos.X = _screenPos.X;
}
else
screenPos.X -= winSize.Width;
}
return screenPos;
}
protected void RegenerateExpansion()
{
// Remove all existing draw commands
_drawCommands.Clear();
// Move into the expanded mode
_showInfrequent = true;
// Generate new ones
Size newSize = GenerateDrawPositions();
// Find the new screen location for the window
Point newPos = CorrectPositionForScreen(newSize);
// Update the window clipping region
if (!_layered)
{
SetWindowRegion(newSize);
// Alter size and location of window
WindowsAPI.MoveWindow(this.Handle, newPos.X, newPos.Y, newSize.Width, newSize.Height, true);
}
else
{
// Remember the correct screen drawing details
_currentPoint = newPos;
_currentSize = newSize;
// Update the image for display
UpdateLayeredWindow();
}
// Lets repaint everything
RefreshAllCommands();
}
protected Size GenerateDrawPositions()
{
// Create a collection of drawing objects
_drawCommands = new ArrayList();
// Calculate the minimum cell width and height
int cellMinHeight = _position[(int)_style, (int)PI.ImageGapTop] +
_imageHeight +
_position[(int)_style, (int)PI.ImageGapBottom];
int cellMinWidth = _position[(int)_style, (int)PI.ImageGapLeft] +
_imageWidth +
_position[(int)_style, (int)PI.ImageGapRight] +
_position[(int)_style, (int)PI.TextGapLeft] +
_position[(int)_style, (int)PI.TextGapRight] +
_position[(int)_style, (int)PI.SubMenuGapLeft] +
_position[(int)_style, (int)PI.SubMenuWidth] +
_position[(int)_style, (int)PI.SubMenuGapRight];
// Find cell height needed to draw text
int textHeight = _textFont.Height;
// If height needs to be more to handle image then use image height
if (textHeight < cellMinHeight)
textHeight = cellMinHeight;
// Make sure no column in the menu is taller than the screen
int screenHeight = SystemInformation.WorkingArea.Height;
// Define the starting positions for calculating cells
int xStart = _position[(int)_style, (int)PI.BorderLeft];
int yStart =_position[(int)_style, (int)PI.BorderTop];
int yPosition = yStart;
// Largest cell for column defaults to minimum cell width
int xColumnMaxWidth = cellMinWidth;
int xPreviousColumnWidths = 0;
int xMaximumColumnHeight = 0;
// Track the row/col of each cell
int row = 0;
int col = 0;
// Are there any infrequent items
bool infrequent = false;
// Get hold of the DC for the desktop
IntPtr hDC = WindowsAPI.GetDC(IntPtr.Zero);
// Contains the collection of items in the current column
ArrayList columnItems = new ArrayList();
using(Graphics g = Graphics.FromHdc(hDC))
{
// Handle any extra text drawing
if (_menuCommands.ExtraText.Length > 0)
{
// Calculate the column width needed to show this text
SizeF dimension = g.MeasureString(_menuCommands.ExtraText, _menuCommands.ExtraFont);
// Always add 1 to ensure that rounding is up and not down
int extraHeight = (int)dimension.Height + 1;
// Find the total required as the text requirement plus style specific spacers
_extraSize = extraHeight +
_position[(int)_style, (int)PI.ExtraRightGap] +
_position[(int)_style, (int)PI.ExtraWidthGap] * 2;
// Push first column of items across from the extra text
xStart += _extraSize;
// Add this extra width to the total width of the window
xPreviousColumnWidths = _extraSize;
}
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;
// If this command has menu items (and so it a submenu item) then check
// if any of the submenu items are visible. If none are visible then there
// is no point in showing this submenu item
if ((command.MenuCommands.Count > 0) && (!command.MenuCommands.VisibleItems()))
continue;
// Ignore infrequent items unless flag set to show them
if (command.Infrequent && !_showInfrequent)
{
infrequent = true;
continue;
}
int cellWidth = 0;
int cellHeight = 0;
// Shift across to the next column?
if (command.Break)
{
// Move row/col tracking to the next column
row = 0;
col++;
// Apply cell width to the current column entries
ApplySizeToColumnList(columnItems, xColumnMaxWidth);
// Move cell position across to start of separator position
xStart += xColumnMaxWidth;
// Get width of the separator area
int xSeparator = _position[(int)_style, (int)PI.SeparatorWidth];
DrawCommand dcSep = new DrawCommand(new Rectangle(xStart, 0, xSeparator, 0), false);
// Add to list of items for drawing
_drawCommands.Add(dcSep);
// Move over the separator
xStart += xSeparator;
// Reset cell position to top of column
yPosition = yStart;
// Accumulate total width of previous columns
xPreviousColumnWidths += xColumnMaxWidth + xSeparator;
// Largest cell for column defaults to minimum cell width
xColumnMaxWidth = cellMinWidth;
}
// Is this a horizontal separator?
if (command.Text == "-")
{
cellWidth = cellMinWidth;
cellHeight = _position[(int)_style, (int)PI.SeparatorHeight];
}
else
{
// Use precalculated height
cellHeight = textHeight;
// Calculate the text width portion of the cell
SizeF dimension = g.MeasureString(command.Text, _textFont);
// Always add 1 to ensure that rounding is up and not down
cellWidth = cellMinWidth + (int)dimension.Width + 1;
// Does the menu command have a shortcut defined?
if (command.Shortcut != Shortcut.None)
{
// Find the width of the shortcut text
dimension = g.MeasureString(GetShortcutText(command.Shortcut), _textFont);
// Add to the width of the cell
cellWidth += _position[(int)_style, (int)PI.ShortcutGap] + (int)dimension.Width + 1;
}
// If this is a combobox, then add the combobox dimension
if ( command.ComboBox != null )
{
cellWidth += command.ComboBox.Width;
}
}
// If the new cell expands past the end of the screen...
if ((yPosition + cellHeight) >= screenHeight)
{
// .. then need to insert a column break
// Move row/col tracking to the next column
row = 0;
col++;
// Apply cell width to the current column entries
ApplySizeToColumnList(columnItems, xColumnMaxWidth);
// Move cell position across to start of separator position
xStart += xColumnMaxWidth;
// Get width of the separator area
int xSeparator = _position[(int)_style, (int)PI.SeparatorWidth];
DrawCommand dcSep = new DrawCommand(new Rectangle(xStart, yStart, xSeparator, 0), false);
// Add to list of items for drawing
_drawCommands.Add(dcSep);
// Move over the separator
xStart += xSeparator;
// Reset cell position to top of column
yPosition = yStart;
// Accumulate total width of previous columns
xPreviousColumnWidths += xColumnMaxWidth + xSeparator;
// Largest cell for column defaults to minimum cell width
xColumnMaxWidth = cellMinWidth;
}
// Create a new position rectangle (the width will be reset later once the
// width of the column has been determined but the other values are correct)
Rectangle cellRect = new Rectangle(xStart, yPosition, cellWidth, cellHeight);
// Create a drawing object
DrawCommand dc = new DrawCommand(command, cellRect, row, col);
// Add to list of items for drawing
_drawCommands.Add(dc);
// Add to list of items in this column
columnItems.Add(dc);
// Remember the biggest cell width in this column
if (cellWidth > xColumnMaxWidth)
xColumnMaxWidth = cellWidth;
// Move down to start of next cell in column
yPosition += cellHeight;
// Remember the tallest column in the menu
if (yPosition > xMaximumColumnHeight)
xMaximumColumnHeight = yPosition;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -