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 { // Draw the selection area in white so can alpha draw over the top g.FillRectangle( Brushes.White, 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( ColorUtil.VSNetBorderPen, boxRect ); } } break; case VisualStyle.Plain: if (_plainAsBlock) { g.FillRectangle( ColorUtil.VSNetBorderBrush, drawRect ); } else { Pen lighlight = SystemPens.ControlLightLight; Pen dark = SystemPens.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; } g.DrawString(mc.Text, this.Font, SystemBrushes.HighlightText, 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 g.DrawString(mc.Text, this.Font, SystemBrushes.HighlightText, rectDownRight, format); // Draw then text offset up and left g.DrawString(mc.Text, this.Font, SystemBrushes.FromSystemColor(SystemColors.GrayText), textRect, format); } } } }
internal void DrawSingleCommand(Graphics g, DrawCommand dc, bool hotCommand) { Rectangle drawRect = dc.DrawRect; MenuCommand mc = dc.MenuCommand; // Remember some often used values int textGapLeft = position[(int) style, (int)PI.TextGapLeft]; int imageGapLeft = position[(int) style, (int)PI.ImageGapLeft]; int imageGapRight = position[(int) style, (int)PI.ImageGapRight]; int imageLeft = drawRect.Left + imageGapLeft; // Calculate some common values int imageColWidth = imageGapLeft + imageWidth + imageGapRight; int subMenuWidth = position[(int) style, (int)PI.SubMenuGapLeft] + position[(int) style, (int)PI.SubMenuWidth] + position[(int) style, (int)PI.SubMenuGapRight]; int subMenuX = drawRect.Right - position[(int) style, (int)PI.SubMenuGapRight] - position[(int) style, (int)PI.SubMenuWidth]; // Text drawing rectangle needs to know the right most position for drawing // to stop. This is the width of the window minus the relevant values int shortCutX = subMenuX - position[(int) style, (int)PI.SubMenuGapLeft] - position[(int) style, (int)PI.TextGapRight]; // Is this item an expansion command? if (dc.Expansion) { Rectangle box = drawRect; // In IDE style the box is next to the image column if ( style == VisualStyle.IDE) { // Reduce the box to take into account the column box.X += imageColWidth; box.Width -= imageColWidth; } // Find centre for drawing the image int xPos = box.Left + ((box.Width - imageHeight) / 2);; int yPos = box.Top + ((box.Height - imageHeight) / 2); switch( style) { case VisualStyle.IDE: g.FillRectangle(SystemBrushes.ControlLightLight, box); break; case VisualStyle.Plain: g.FillRectangle(SystemBrushes.Control, box); break; } // Should the item look selected if (hotCommand) { switch( style) { case VisualStyle.IDE: Rectangle selectArea = new Rectangle(drawRect.Left + 1, drawRect.Top, drawRect.Width - 3, drawRect.Height - 1); // Draw the selection area white, because we are going to use an alpha brush g.FillRectangle( Brushes.White, selectArea ); using (SolidBrush selectBrush = new SolidBrush(Color.FromArgb(70,ColorUtil.VSNetBorderColor))) { // Draw the selection area g.FillRectangle(selectBrush, selectArea); // Draw a border around the selection area g.DrawRectangle( ColorUtil.VSNetBorderPen, selectArea ); } break; case VisualStyle.Plain: // Shrink the box to provide a small border box.Inflate(-2, -2); // Grab common values Color baseColor = SystemColors.Control; using (Pen lightPen = new Pen(SystemColors.ControlLightLight), darkPen = new Pen(SystemColors.ControlDarkDark)) { g.DrawLine(lightPen, box.Right, box.Top, box.Left, box.Top); g.DrawLine(lightPen, box.Left, box.Top, box.Left, box.Bottom); g.DrawLine(darkPen, box.Left, box.Bottom, box.Right, box.Bottom); g.DrawLine(darkPen, box.Right, box.Bottom, box.Right, box.Top); } break; } } else { switch( style) { case VisualStyle.IDE: // Fill the entire drawing area with white g.FillRectangle( SystemBrushes.ControlLightLight, new Rectangle(drawRect.Left + 1, drawRect.Top, drawRect.Width - 1, drawRect.Height)); Rectangle imageCol = new Rectangle(drawRect.Left, drawRect.Top, imageColWidth, drawRect.Height); // Draw the image column background g.FillRectangle(SystemBrushes.Control, imageCol); break; case VisualStyle.Plain: g.FillRectangle(SystemBrushes.Control, new Rectangle(drawRect.Left, drawRect.Top, drawRect.Width, drawRect.Height)); break; } } // Always draw the expansion bitmap g.DrawImage(menuImages.Images[(int)ImageIndex.Expansion], xPos, yPos); } else { // Is this item a separator? if (dc.Separator) { if (dc.VerticalSeparator) { switch( style) { case VisualStyle.IDE: // Draw the separator as a single line using (Pen separatorPen = new Pen(SystemColors.ControlDark)) g.DrawLine(separatorPen, drawRect.Left, drawRect.Top, drawRect.Left, drawRect.Bottom); break; case VisualStyle.Plain: Color baseColor = SystemColors.Control; ButtonBorderStyle bsInset = ButtonBorderStyle.Inset; ButtonBorderStyle bsNone = ButtonBorderStyle.Inset; Rectangle sepRect = new Rectangle(drawRect.Left + 1, drawRect.Top, 2, drawRect.Height); // Draw the separator as two lines using Inset style ControlPaint.DrawBorder(g, sepRect, baseColor, 1, bsInset, baseColor, 0, bsNone, baseColor, 1, bsInset, baseColor, 0, bsNone); break; } } else { switch( style) { case VisualStyle.IDE: // Draw the image column background Rectangle imageCol = new Rectangle(drawRect.Left, drawRect.Top, imageColWidth, drawRect.Height); g.FillRectangle( ColorUtil.VSNetBackgroundBrush, drawRect); g.FillRectangle( ColorUtil.VSNetControlBrush, imageCol); // Draw a separator using (Pen separatorPen = new Pen(Color.FromArgb(75, SystemColors.MenuText))) { // Draw the separator as a single line g.DrawLine(separatorPen, drawRect.Left + imageColWidth + textGapLeft, drawRect.Top + 1, drawRect.Right-4, drawRect.Top + 1); } break; case VisualStyle.Plain: Color baseColor = SystemColors.Control; ButtonBorderStyle bsInset = ButtonBorderStyle.Inset; ButtonBorderStyle bsNone = ButtonBorderStyle.Inset; Rectangle sepRect = new Rectangle(drawRect.Left + 2, drawRect.Top + 1, drawRect.Width - 4, 2); // Draw the separator as two lines using Inset style ControlPaint.DrawBorder(g, sepRect, baseColor, 0, bsNone, baseColor, 1, bsInset, baseColor, 0, bsNone, baseColor, 1, bsInset); break; } } } else { // Should the command be drawn selected? if (hotCommand && mc.ComboBox == null ) { switch( style) { case VisualStyle.IDE: Rectangle selectArea = new Rectangle(drawRect.Left + 1, drawRect.Top, drawRect.Width - 3, drawRect.Height - 1); // Draw the selection area white, because we are going to use an alpha brush g.FillRectangle(Brushes.White, selectArea); using (SolidBrush selectBrush = new SolidBrush(Color.FromArgb(70, ColorUtil.VSNetBorderColor))) { // Draw the selection area g.FillRectangle(selectBrush, selectArea); // Draw a border around the selection area g.DrawRectangle( ColorUtil.VSNetBorderPen, selectArea); } break; case VisualStyle.Plain: g.FillRectangle( ColorUtil.VSNetBorderBrush, drawRect); break; } } else { switch( style) { case VisualStyle.IDE: // Fill the entire drawing area with white g.FillRectangle( ColorUtil.VSNetBackgroundBrush, new Rectangle(drawRect.Left + 1, drawRect.Top, drawRect.Width - 1, drawRect.Height)); Rectangle imageCol = new Rectangle(drawRect.Left, drawRect.Top, imageColWidth, drawRect.Height); // Draw the image column background g.FillRectangle( ColorUtil.VSNetControlBrush, imageCol ); // If this is a combobox item, make sure to position the combobox a couple // of pixel after the icon area if ( mc.ComboBox != null ) { // Combobox will paint itself mc.ComboBox.Left = drawRect.Left+imageColWidth + 2; mc.ComboBox.Top = drawRect.Top + (drawRect.Height - mc.ComboBox.Height)/2; } break; case VisualStyle.Plain: g.FillRectangle(SystemBrushes.Control, new Rectangle(drawRect.Left, drawRect.Top, drawRect.Width, drawRect.Height)); break; } } int leftPos = drawRect.Left + imageColWidth + textGapLeft; // Calculate text drawing rectangle Rectangle strRect = new Rectangle(leftPos, drawRect.Top, shortCutX - leftPos, drawRect.Height); // 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.Near; format.LineAlignment = StringAlignment.Center; format.HotkeyPrefix = HotkeyPrefix.Show; SolidBrush textBrush; // Create brush depending on enabled state if (mc.Enabled) { if (!hotCommand || ( style == VisualStyle.IDE)) textBrush = new SolidBrush(SystemColors.MenuText); else textBrush = new SolidBrush(SystemColors.HighlightText); } else textBrush = new SolidBrush(SystemColors.GrayText); // Helper values used when drawing grayed text in plain style Rectangle rectDownRight = strRect; rectDownRight.Offset(1,1); if (mc.Enabled || ( style == VisualStyle.IDE)) g.DrawString(mc.Text, textFont, textBrush, strRect, format); else { // Draw grayed text by drawing white string offset down and right g.DrawString(mc.Text, textFont, SystemBrushes.HighlightText, rectDownRight, format); // And then draw in corret color offset up and left g.DrawString(mc.Text, textFont, textBrush, strRect, format); } if (mc.Shortcut != Shortcut.None) { // Right align the shortcut drawing format.Alignment = StringAlignment.Far; if (mc.Enabled || ( style == VisualStyle.IDE)) { // Draw the shortcut text g.DrawString(GetShortcutText(mc.Shortcut), textFont, textBrush, strRect, format); } else { // Draw grayed text by drawing white string offset down and right g.DrawString(GetShortcutText(mc.Shortcut), textFont, SystemBrushes.HighlightText, rectDownRight, format ); // And then draw in corret color offset up and left g.DrawString(GetShortcutText(mc.Shortcut), textFont, textBrush, strRect, format); } } // The image offset from top of cell is half the space left after // subtracting the height of the image from the cell height int imageTop = drawRect.Top + (drawRect.Height - imageHeight) / 2; Image image = null; // Should a check mark be drawn? if (mc.Checked) { switch( style) { case VisualStyle.IDE: Pen boxPen; if (mc.Enabled) boxPen = ColorUtil.VSNetBorderPen; else boxPen = SystemPens.GrayText; // Draw the box around the checkmark area g.DrawRectangle(boxPen, new Rectangle(imageLeft - 1, imageTop - 1, imageHeight + 2, imageWidth + 2)); break; case VisualStyle.Plain: break; } // Grab either tick or radio button image if (mc.RadioCheck) { if (hotCommand && ( style == VisualStyle.Plain)) image = menuImages.Images[(int)ImageIndex.RadioSelected]; else image = menuImages.Images[(int)ImageIndex.Radio]; } else { if (hotCommand && ( style == VisualStyle.Plain)) image = menuImages.Images[(int)ImageIndex.CheckSelected]; else image = menuImages.Images[(int)ImageIndex.Check]; } } else { try { // Is there an image available to be drawn? if ((mc.ImageList != null) && (mc.ImageIndex >= 0)) image = mc.ImageList.Images[mc.ImageIndex]; else if ( mc.Image != null) image = mc.Image; } catch(Exception) { // User supplied ImageList/ImageIndex are invalid, use an error image instead image = menuImages.Images[(int)ImageIndex.ImageError]; } } // Is there an image to be drawn? if (image != null) { if (mc.Enabled) { if ((hotCommand) && (!mc.Checked) && ( style == VisualStyle.IDE)) { // Draw a disabled icon offset down and right ControlPaint.DrawImageDisabled(g, image, imageLeft + 1, imageTop + 1, SystemColors.HighlightText); // Draw an enabled icon offset up and left g.DrawImage(image, imageLeft - 1, imageTop - 1); } else { // Draw an enabled icon g.DrawImage(image, imageLeft, imageTop); } } else { // Draw a image disabled ControlPaint.DrawImageDisabled(g, image, imageLeft, imageTop, SystemColors.HighlightText); } } // Does the menu have a submenu defined? if (dc.SubMenu) { // Is the item enabled? if (mc.Enabled) { int subMenuIndex = (int)ImageIndex.SubMenu; if (hotCommand && ( style == VisualStyle.Plain)) subMenuIndex = (int)ImageIndex.SubMenuSelected; // Draw the submenu arrow g.DrawImage(menuImages.Images[subMenuIndex], subMenuX, imageTop); } else { // Draw a image disabled ControlPaint.DrawImageDisabled(g, menuImages.Images[(int)ImageIndex.SubMenu], subMenuX, imageTop, SystemColors.HighlightText); } } } } }
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 _popupMenu.TrackPopup(screenPos, aboveScreenPos, _direction, dc.MenuCommand.MenuCommands, borderGap, selectFirst, this, ref returnDir); // Generate event so that caller has chance to modify MenuCommand contents OnPopupEnd(dc.MenuCommand); } // Remove unwanted object _popupMenu = null; // Was arrow key used to dismiss the submenu? if (returnDir != 0) { // Using keyboard movements means we should have the focus if (!_manualFocus) { _manualFocus = true; GrabTheFocus(); } if (returnDir < 0) { // Shift selection left one ProcessMoveLeft(true); } else { // Shift selection right one ProcessMoveRight(true); } // A WM_MOUSEMOVE is generated when we open up the new submenu for // display, ignore this as it causes the selection to move _ignoreMouseMove = true; } else { // Only if the submenu was dismissed at the request of the submenu // should the selection mode be cancelled, otherwise keep selection mode if (!_dismissTransfer) { // This item is no longer selected _selected = false; _drawUpwards = false; // Should we stop tracking this item if (trackRemove) { ReturnTheFocus(); // Unselect the current item _trackItem = SwitchTrackingItem(_trackItem, -1); } else { // Repaint the item DrawCommand(_trackItem, true); } } else { // Do not change _selected status _dismissTransfer = false; } } }
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; row++; } // Check if we need to add an infrequent expansion item if (infrequent) { // Create a minimum size cell Rectangle cellRect = new Rectangle(xStart, yPosition, cellMinWidth, cellMinHeight); // Create a draw command to represent the drawing of the expansion item DrawCommand dc = new DrawCommand(cellRect, true); // Must be last item drawCommands.Add(dc); // Add to list of items in this column columnItems.Add(dc); yPosition += cellMinHeight; // Remember the tallest column in the menu if (yPosition > xMaximumColumnHeight) xMaximumColumnHeight = yPosition; } // Apply cell width to the current column entries ApplySizeToColumnList(columnItems, xColumnMaxWidth); } // Must remember to release the HDC resource! WindowsAPI.ReleaseDC(IntPtr.Zero, hDC); // Find width/height of window int windowWidth = position[(int) style, (int)PI.BorderLeft] + xPreviousColumnWidths + xColumnMaxWidth + position[(int) style, (int)PI.BorderRight]; int windowHeight = position[(int) style, (int)PI.BorderTop] + xMaximumColumnHeight + position[(int) style, (int)PI.BorderBottom]; // Define the height of the vertical separators ApplyVerticalSeparators(xMaximumColumnHeight); // Style specific modification of window size int xAdd = position[(int) style, (int)PI.ShadowHeight]; int yAdd = position[(int) style, (int)PI.ShadowWidth]; if ( style == VisualStyle.Plain) { xAdd += SystemInformation.Border3DSize.Width * 2; yAdd += SystemInformation.Border3DSize.Height * 2; } return new Size(windowWidth + xAdd, windowHeight + yAdd); }