|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
namespace System.Windows.Forms.Design.Behavior;
/// <summary>
/// This is the Behavior that represents DesignerActions for a particular control.
/// The DesignerActionBehavior is responsible for responding to the MouseDown message and either
/// 1) Selecting the control and changing the DesignerActionGlyph's image or
/// 2) Building up a chrome menu and requesting it to be shown.
/// Also, this Behavior acts as a proxy between "clicked" context menu items and the actual
/// DesignerActions that they represent.
/// </summary>
internal sealed class DesignerActionBehavior : Behavior
{
private readonly IServiceProvider _serviceProvider; // we need to cache the service provider here to be able to create the panel with the proper arguments
private bool _ignoreNextMouseUp;
/// <summary>
/// Constructor that calls base and caches off the action lists.
/// </summary>
internal DesignerActionBehavior(IServiceProvider serviceProvider, IComponent relatedComponent, DesignerActionListCollection actionLists, DesignerActionUI parentUI)
{
ActionLists = actionLists;
_serviceProvider = serviceProvider;
RelatedComponent = relatedComponent;
ParentUI = parentUI;
}
/// <summary>
/// Returns the collection of DesignerActionLists this Behavior is managing.
/// These will be dynamically updated (some can be removed, new ones can be added, etc...).
/// </summary>
internal DesignerActionListCollection ActionLists { get; set; }
/// <summary>
/// Returns the parenting UI (a DesignerActionUI)
/// </summary>
internal DesignerActionUI ParentUI { get; }
/// <summary>
/// Returns the Component that this glyph is attached to.
/// </summary>
internal IComponent RelatedComponent { get; }
/// <summary>
/// Hides the designer action panel UI.
/// </summary>
internal void HideUI()
{
ParentUI.HideDesignerActionPanel();
}
internal DesignerActionPanel CreateDesignerActionPanel(IComponent relatedComponent)
{
// BUILD AND SHOW THE CHROME UI
DesignerActionListCollection lists = new();
lists.AddRange(ActionLists);
DesignerActionPanel dap = new(_serviceProvider);
dap.UpdateTasks(lists, [], string.Format(SR.DesignerActionPanel_DefaultPanelTitle, relatedComponent.GetType().Name), null);
return dap;
}
/// <summary>
/// Shows the designer action panel UI associated with this glyph.
/// </summary>
internal void ShowUI(Glyph g)
{
if (g is not DesignerActionGlyph glyph)
{
Debug.Fail("Why are we trying to 'showui' on a glyph that's not a DesignerActionGlyph?");
return;
}
DesignerActionPanel dap = CreateDesignerActionPanel(RelatedComponent);
ParentUI.ShowDesignerActionPanel(RelatedComponent, dap, glyph);
}
internal bool IgnoreNextMouseUp
{
set
{
_ignoreNextMouseUp = value;
}
}
public override bool OnMouseDoubleClick(Glyph? g, MouseButtons button, Point mouseLoc)
{
_ignoreNextMouseUp = true;
return true;
}
public override bool OnMouseDown(Glyph? g, MouseButtons button, Point mouseLoc)
{
// we take the msg
return (!ParentUI.IsDesignerActionPanelVisible);
}
/// <summary>
/// In response to a MouseUp, we will either
/// 1) select the Glyph and control if not selected, or
/// 2) Build up our context menu representing our DesignerActions and show it.
/// </summary>
public override bool OnMouseUp(Glyph? g, MouseButtons button)
{
if (button != MouseButtons.Left)
{
return true;
}
bool returnValue = true;
if (ParentUI.IsDesignerActionPanelVisible)
{
HideUI();
}
else if (!_ignoreNextMouseUp)
{
if (_serviceProvider.TryGetService(out ISelectionService? selectionService) &&
selectionService.PrimarySelection != RelatedComponent)
{
List<IComponent> componentList = [RelatedComponent];
selectionService.SetSelectedComponents(componentList, SelectionTypes.Primary);
}
if (g is not null)
{
ShowUI(g);
}
}
else
{
returnValue = false;
}
_ignoreNextMouseUp = false;
return returnValue;
}
}
|