/// /// Copyright © 2003-2008 JetBrains s.r.o. /// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder). /// using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; using JetBrains.Omea.OpenAPI; namespace JetBrains.Omea.GUIControls { /// /// A control that displays a resource icon and its name as a clickable link. /// public class ResourceLinkLabel : System.Windows.Forms.UserControl { private GUIControls.ImageListPictureBox _iconBox; private JetLinkLabel _label; /// /// Required designer variable. /// private System.ComponentModel.Container components = null; private IResource _resource; private IResource _linkOwnerResource; private int _linkType; private Point _dragStartPoint; private bool _clickableLink = true; private bool _executeDoubleClickAction = true; private bool _showIcon = true; private IResourceList _resourceList; private static Color _linkColor = Color.FromArgb( 70, 70, 211 ); public event ResourceLinkLabelEventHandler LinkContextMenu; public event CancelEventHandler ResourceLinkClicked; public event ResourceDragEventHandler ResourceDragOver; public event ResourceDragEventHandler ResourceDrop; public event ResourcePropEventHandler ResourceChanged; public ResourceLinkLabel() { // This call is required by the Windows.Forms Form Designer. InitializeComponent(); SetStyle( ControlStyles.UserPaint | ControlStyles.SupportsTransparentBackColor | ControlStyles.AllPaintingInWmPaint | ControlStyles.CacheText , true ); _label.BackColor = Color.FromArgb( 0, DefaultBackColor ); _label.ForeColor = _linkColor; if ( ICore.Instance != null ) { _iconBox.ImageList = Core.ResourceIconManager.ImageList; } } /// /// Clean up any resources being used. /// protected override void Dispose( bool disposing ) { if( disposing ) { if(components != null) { components.Dispose(); } if ( _resourceList != null ) { _resourceList.Dispose(); } } base.Dispose( disposing ); } #region Component Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this._iconBox = new JetBrains.Omea.GUIControls.ImageListPictureBox(); this._label = new JetBrains.Omea.GUIControls.JetLinkLabel(); this.SuspendLayout(); // // _iconBox // this._iconBox.ImageIndex = 0; this._iconBox.ImageLeftTopPoint = new System.Drawing.Point(0, 0); this._iconBox.Location = new System.Drawing.Point(1, 2); this._iconBox.Name = "_iconBox"; this._iconBox.Size = new System.Drawing.Size(16, 16); this._iconBox.TabIndex = 0; this._iconBox.Text = "imageListPictureBox1"; this._iconBox.MouseUp += new System.Windows.Forms.MouseEventHandler(this._iconBox_MouseUp); this._iconBox.DoubleClick += new System.EventHandler(this.OnResourceIconDoubleClick); this._iconBox.MouseMove += new System.Windows.Forms.MouseEventHandler(this.OnLinkMouseMove); this._iconBox.MouseDown += new System.Windows.Forms.MouseEventHandler(this.OnLinkMouseDown); // // _label // this._label.AllowDrop = true; this._label.Cursor = System.Windows.Forms.Cursors.Hand; this._label.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(204))); this._label.ForeColor = System.Drawing.Color.FromArgb(((System.Byte)(70)), ((System.Byte)(70)), ((System.Byte)(211))); this._label.Location = new System.Drawing.Point(21, 2); this._label.Name = "_label"; this._label.Size = new System.Drawing.Size(34, 17); this._label.TabIndex = 1; this._label.DragEnter += new System.Windows.Forms.DragEventHandler(this.OnLinkDragEnter); this._label.Resize += new System.EventHandler(this._label_Resize); this._label.DragLeave += new System.EventHandler(this.OnLinkDragLeave); this._label.MouseUp += new System.Windows.Forms.MouseEventHandler(this.OnLinkMouseUp); this._label.MouseEnter += new System.EventHandler(this.OnLinkEnter); this._label.DragDrop += new System.Windows.Forms.DragEventHandler(this.OnLinkDrop); this._label.MouseLeave += new System.EventHandler(this.OnLinkLeave); this._label.MouseDown += new System.Windows.Forms.MouseEventHandler(this.OnLinkMouseDown); // // ResourceLinkLabel // this.Controls.Add(this._label); this.Controls.Add(this._iconBox); this.Name = "ResourceLinkLabel"; this.Size = new System.Drawing.Size(256, 20); this.Enter += new System.EventHandler(this.ResourceLinkLabel_Enter); this.Paint += new System.Windows.Forms.PaintEventHandler(this.ResourceLinkLabel_Paint); this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ResourceLinkLabel_KeyDown); this.Leave += new System.EventHandler(this.ResourceLinkLabel_Leave); this.ResumeLayout(false); } #endregion public IResource Resource { get { return _resource; } set { if ( _resource != value ) { if ( _resourceList != null ) { _resourceList.ResourceChanged -= new ResourcePropIndexEventHandler( HandleResourceChanged ); _resourceList.Dispose(); } _resource = value; if ( _resource != null ) { _resourceList = _resource.ToResourceListLive(); _resourceList.ResourceChanged += new ResourcePropIndexEventHandler( HandleResourceChanged ); UpdateContents(); } } } } private void UpdateContents() { if ( _showIcon ) { int[] overlayIconIndices = Core.ResourceIconManager.GetOverlayIconIndices( _resource ); if ( overlayIconIndices != null && overlayIconIndices.Length > 0 ) { int[] indices = new int [overlayIconIndices.Length+1]; indices [0] = Core.ResourceIconManager.GetIconIndex( _resource ); Array.Copy( overlayIconIndices, 0, indices, 1, overlayIconIndices.Length ); _iconBox.ImageIndices = indices; } else { _iconBox.ImageIndex = Core.ResourceIconManager.GetIconIndex( _resource ); } } Text = _resource.DisplayName; } public string PostfixText { get { return _label.PostfixText; } set { _label.PostfixText = value; } } [DefaultValue( true )] public bool AutoSize { get { return _label.AutoSize; } set { _label.AutoSize = value; } } [DefaultValue( false )] public bool EndEllipsis { get { return _label.EndEllipsis; } set { _label.EndEllipsis = value; } } private void HandleResourceChanged( object sender, ResourcePropIndexEventArgs e ) { if ( e.ChangeSet.IsDisplayNameAffected || _showIcon ) { Core.UIManager.QueueUIJob( new MethodInvoker( RefreshResource ) ); } if ( ResourceChanged != null ) { ResourceChanged( this, new ResourcePropEventArgs( e.Resource, e.ChangeSet ) ); } } private void RefreshResource() { UpdateContents(); Invalidate(); // redraw the focus frame for new text size } public IResource LinkOwnerResource { get { return _linkOwnerResource; } set { _linkOwnerResource = value; } } public int LinkType { get { return _linkType; } set { _linkType = value; } } [DefaultValue(true)] public bool ClickableLink { get { return _clickableLink; } set { _clickableLink = value; _label.ClickableLink = value; } } [DefaultValue(true)] public bool ShowIcon { get { return _showIcon; } set { if ( _showIcon != value ) { _showIcon = value; _iconBox.Visible = _showIcon; _label.Left = _showIcon ? 21 : 1; if ( _showIcon ) { UpdateContents(); } } } } public Control NameLabel { get { return _label; } } public int PreferredWidth { get { return _label.Left + _label.PreferredWidth + 2; /* extra space for the focus frame */ } } /** * Enables or disables executing the double-click action when an item is double-clicked * or Enter is pressed on an item. */ [DefaultValue(true)] public bool ExecuteDoubleClickAction { get { return _executeDoubleClickAction; } set { _executeDoubleClickAction = value; } } /** * When the text of the control is changed, updates the link label * text to match. */ protected override void OnTextChanged( EventArgs e ) { base.OnTextChanged( e ); _label.Text = Text; } /** * When the mouse is pressed down on a link label or resource icon, * remembers the coordinates so that we can check to start a drag later. */ private void OnLinkMouseDown( object sender, System.Windows.Forms.MouseEventArgs e ) { if ( e.Button == MouseButtons.Left ) { _dragStartPoint = new Point( e.X, e.Y ); } Focus(); Invalidate(); } /** * WHen the mouse is moved over the link label or resource icon, * checks if it's time to start a drag. */ private void OnLinkMouseMove( object sender, System.Windows.Forms.MouseEventArgs e ) { if ( e.Button == MouseButtons.Left && _dragStartPoint.X != -1 && _resource != null ) { int dx = Math.Abs( _dragStartPoint.X - e.X ); int dy = Math.Abs( _dragStartPoint.Y - e.Y ); if ( dx >= 4 || dy >= 4 ) { _dragStartPoint = new Point( -1, -1 ); DataObject dataObj = new DataObject(); dataObj.SetData( typeof(IResourceList), _resource.ToResourceList() ); DoDragDrop( dataObj, DragDropEffects.Link | DragDropEffects.Move ); } } } /** * When a link label is clicked, displays the respective resource. * When it is right-clicked, shows the resource popup menu. */ private void OnLinkMouseUp( object sender, System.Windows.Forms.MouseEventArgs e ) { _dragStartPoint = new Point( -1, -1 ); if ( e.Button == MouseButtons.Left && _clickableLink && ClientRectangle.Contains( e.X, e.Y ) ) { CancelEventArgs args = new CancelEventArgs( false ); if ( ResourceLinkClicked != null ) { ResourceLinkClicked( this, args ); } if ( !args.Cancel ) { ActionContext context = GetActionContext( ActionContextKind.Other ); if ( !Core.ActionManager.ExecuteLinkClickAction( context ) ) { if ( !_resource.IsDeleted ) { // the link label may get reused, and _resource may be replaced IResource resourceToDisplay = _resource; IResource linkOwner = _linkOwnerResource; Core.UIManager.DisplayResourceInContext( _resource ); if ( linkOwner != null && Core.ResourceBrowser.OwnerResource != null && !Core.ResourceBrowser.VisibleResources.Contains( resourceToDisplay ) ) { Core.ResourceBrowser.SelectResource( linkOwner ); } } } } } else if ( e.Button == MouseButtons.Right ) { if ( LinkContextMenu != null ) { LinkContextMenu( this, new ResourceLinkLabelEventArgs( new Point( e.X, e.Y ), _resource) ); } } } private ActionContext GetActionContext( ActionContextKind kind ) { IResourceList resList = null; if ( _resource != null ) { resList = _resource.ToResourceList(); } ActionContext context = new ActionContext( kind, null, resList ); context.SetLinkTarget( _linkType, _linkOwnerResource ); return context; } private void _iconBox_MouseUp( object sender, System.Windows.Forms.MouseEventArgs e ) { if ( e.Button == MouseButtons.Right ) { if ( LinkContextMenu != null ) { LinkContextMenu( this, new ResourceLinkLabelEventArgs( new Point( e.X, e.Y ), _resource) ); } } } /// /// When a resource icon is double-clicked, executes the double-click action /// of the resource. /// private void OnResourceIconDoubleClick( object sender, System.EventArgs e ) { if ( _executeDoubleClickAction && _resource != null ) { Core.ActionManager.ExecuteDoubleClickAction( _resource.ToResourceList() ); } } /** * When the cursor enters the link label, highlights it as a link. */ private void OnLinkEnter( object sender, System.EventArgs e ) { } private void OnLinkLeave( object sender, System.EventArgs e ) { _dragStartPoint = new Point( -1, -1 ); } /** * When a IResourceList drag enters the link label, highlights it * as a drop target. */ private void OnLinkDragEnter( object sender, System.Windows.Forms.DragEventArgs e ) { if ( e.Data.GetDataPresent( typeof(IResourceList) ) ) { _label.BackColor = SystemColors.Highlight; _label.ForeColor = SystemColors.HighlightText; IResourceList resList = (IResourceList) e.Data.GetData( typeof(IResourceList) ); if ( ResourceDragOver != null ) { ResourceDragEventArgs args = new ResourceDragEventArgs( _resource, resList ); ResourceDragOver( this, args ); e.Effect = args.Effect; } else { if ( Core.UIManager.CanDropResource( _resource, resList ) ) e.Effect = DragDropEffects.Link; else e.Effect = DragDropEffects.None; } } } /** * When a drag leaves the link label, removes its highlighting. */ private void OnLinkDragLeave( object sender, System.EventArgs e ) { _label.BackColor = BackColor; _label.ForeColor = _linkColor; } /** * When a resource is dropped over the link label, pops up the "Add Link" * dialog. */ private void OnLinkDrop( object sender, System.Windows.Forms.DragEventArgs e ) { if ( e.Data.GetDataPresent( typeof(IResourceList ) ) ) { IResourceList resList = (IResourceList) e.Data.GetData( typeof( IResourceList ) ); _label.BackColor = BackColor; _label.ForeColor = _linkColor; if ( ResourceDrop != null ) { ResourceDrop( this, new ResourceDragEventArgs( _resource, resList ) ); } else { Core.UIManager.ProcessResourceDrop( _resource, resList ); } } } private void ResourceLinkLabel_Paint( object sender, System.Windows.Forms.PaintEventArgs e ) { if ( ContainsFocus ) { ControlPaint.DrawFocusRectangle( e.Graphics, new Rectangle( 0, 0, _label.Width+22, Height ) ); } } private void ResourceLinkLabel_Enter(object sender, System.EventArgs e) { Invalidate(); } private void ResourceLinkLabel_Leave(object sender, System.EventArgs e) { Invalidate(); } protected override void OnBackColorChanged( EventArgs e ) { base.OnBackColorChanged( e ); _label.BackColor = BackColor; _iconBox.BackColor = BackColor; } private void ResourceLinkLabel_KeyDown( object sender, KeyEventArgs e ) { if ( Core.ActionManager.ExecuteKeyboardAction( GetActionContext( ActionContextKind.Keyboard ), e.KeyCode | e.Modifiers ) ) { e.Handled = true; } } private void _label_Resize(object sender, System.EventArgs e) { Width = _label.Width+23; } protected override void OnPaint(PaintEventArgs e) { if( BackColor != Color.Transparent ) { using( Brush brush = new SolidBrush( BackColor ) ) e.Graphics.FillRectangle( brush, ClientRectangle ); } } protected override void OnLayout(LayoutEventArgs levent) { // Center the controls vertically _iconBox.Top = 0 + (Height - _iconBox.Height) / 2; _label.Top = 0 + (Height - _label.Height) / 2; } } public class ResourceLinkLabelEventArgs: EventArgs { private Point _pnt; private IResource _res; internal ResourceLinkLabelEventArgs( Point pnt, IResource res ) { _pnt = pnt; _res = res; } public Point Point { get { return _pnt; } } public IResource Resource { get { return _res; } } } public delegate void ResourceLinkLabelEventHandler( object sender, ResourceLinkLabelEventArgs e ); }