⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 popupmenu.cs

📁 c#编写的仿OUTLOOK工具条的Winform菜单
💻 CS
📖 第 1 页 / 共 5 页
字号:
				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 + -