Пример #1
0
        /// <summary>Callback that is invoked whenever anything is added or removed from <see cref="Tabs" /> so that we can trigger a redraw of the tabs.</summary>
        /// <param name="sender">Object for which this event was raised.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void _tabs_CollectionModified(object sender, ListModificationEventArgs e)
        {
            SetFrameSize();

            if (e.Modification == ListModification.ItemAdded || e.Modification == ListModification.RangeAdded)
            {
                for (int i = 0; i < e.Count; i++)
                {
                    TitleBarTab currentTab = Tabs[i + e.StartIndex];

                    currentTab.Content.TextChanged += Content_TextChanged;
                    currentTab.Closing             += TitleBarTabs_Closing;

                    if (AeroPeekEnabled)
                    {
                        TaskbarManager.Instance.TabbedThumbnail.SetActiveTab(CreateThumbnailPreview(currentTab));
                    }
                }
            }

            if (_overlay != null)
            {
                _overlay.Render(true);
            }
        }
Пример #2
0
        /// <summary>
        /// Called when a torn tab is dragged into the <see cref="TitleBarTabs.TabDropArea" /> of <see cref="_parentWindow" />.  Places the tab in the list and
        /// sets <see cref="IsTabRepositioning" /> to true to simulate the user continuing to drag the tab around in the window.
        /// </summary>
        /// <param name="tab">Tab that was dragged into this window.</param>
        /// <param name="cursorLocation">Location of the user's cursor.</param>
        internal virtual void CombineTab(TitleBarTab tab, Point cursorLocation)
        {
            // Stop rendering to prevent weird stuff from happening like the wrong tab being focused
            _suspendRendering = true;

            // Find out where to insert the tab in the list
            int dropIndex = _parentWindow.Tabs.FindIndex(t => t.Area.Left <= cursorLocation.X && t.Area.Right >= cursorLocation.X);

            // Simulate the user having clicked in the middle of the tab when they started dragging it so that the tab will move correctly within the window
            // when the user continues to move the mouse
            _tabClickOffset    = _parentWindow.Tabs.First().Area.Width / 2;
            IsTabRepositioning = true;

            tab.Parent = _parentWindow;

            if (dropIndex == -1)
            {
                _parentWindow.Tabs.Add(tab);
                dropIndex = _parentWindow.Tabs.Count - 1;
            }

            else
            {
                _parentWindow.Tabs.Insert(dropIndex, tab);
            }

            // Resume rendering
            _suspendRendering = false;

            _parentWindow.SelectedTabIndex = dropIndex;
            _parentWindow.ResizeTabContents();
        }
Пример #3
0
        /// <summary>Calls <see cref="CreateTab" />, adds the resulting tab to the <see cref="Tabs" /> collection, and activates it.</summary>
        public virtual void AddNewTab()
        {
            TitleBarTab newTab = CreateTab();

            Tabs.Add(newTab);
            ResizeTabContents(newTab);

            SelectedTabIndex = _tabs.Count - 1;
        }
Пример #4
0
        /// <summary>Checks to see if the <paramref name="cursor" /> is over the <see cref="TitleBarTab.CloseButtonArea" /> of the given <paramref name="tab" />.</summary>
        /// <param name="tab">The tab whose <see cref="TitleBarTab.CloseButtonArea" /> we are to check to see if it contains <paramref name="cursor" />.</param>
        /// <param name="cursor">Current position of the cursor.</param>
        /// <returns>True if the <paramref name="tab" />'s <see cref="TitleBarTab.CloseButtonArea" /> contains <paramref name="cursor" />, false otherwise.</returns>
        public virtual bool IsOverCloseButton(TitleBarTab tab, Point cursor)
        {
            if (!tab.ShowCloseButton || _wasTabRepositioning)
            {
                return(false);
            }

            Rectangle absoluteCloseButtonArea = new Rectangle(
                tab.Area.X + tab.CloseButtonArea.X, tab.Area.Y + tab.CloseButtonArea.Y, tab.CloseButtonArea.Width, tab.CloseButtonArea.Height);

            return(absoluteCloseButtonArea.Contains(cursor));
        }
Пример #5
0
        /// <summary>Constructor; initializes the window and constructs the tab thumbnail image to use when dragging.</summary>
        /// <param name="tab">Tab that was torn out of its parent window.</param>
        /// <param name="tabRenderer">Renderer instance to use when drawing the actual tab.</param>
        public TornTabForm(TitleBarTab tab, base_tab_renderer tabRenderer)
        {
            _layeredWindow = new LayeredWindow();
            _initialized   = false;

            // Set drawing styles
            SetStyle(ControlStyles.DoubleBuffer, true);

            // This should show up as a semi-transparent borderless window
            Opacity         = 0.70;
            ShowInTaskbar   = false;
            FormBorderStyle = FormBorderStyle.None;
// ReSharper disable DoNotCallOverridableMethodsInConstructor
            BackColor = Color.Fuchsia;
// ReSharper restore DoNotCallOverridableMethodsInConstructor
            TransparencyKey   = Color.Fuchsia;
            AllowTransparency = true;

            Disposed += TornTabForm_Disposed;

            // Get the tab thumbnail (full size) and then draw the actual representation of the tab onto it as well
            Bitmap   tabContents    = tab.GetImage();
            Bitmap   contentsAndTab = new Bitmap(tabContents.Width, tabContents.Height + tabRenderer.TabHeight, tabContents.PixelFormat);
            Graphics tabGraphics    = Graphics.FromImage(contentsAndTab);

            tabGraphics.DrawImage(tabContents, 0, tabRenderer.TabHeight);

            bool oldShowAddButton = tabRenderer.ShowAddButton;

            tabRenderer.ShowAddButton = false;
            tabRenderer.Render(
                new List <TitleBarTab>
            {
                tab
            }, tabGraphics, new Point(0, 0), new Point(0, 0), true);
            tabRenderer.ShowAddButton = oldShowAddButton;

            // Scale the thumbnail down to half size
            _tabThumbnail = new Bitmap(contentsAndTab.Width / 2, contentsAndTab.Height / 2, contentsAndTab.PixelFormat);
            Graphics thumbnailGraphics = Graphics.FromImage(_tabThumbnail);

            thumbnailGraphics.InterpolationMode  = InterpolationMode.High;
            thumbnailGraphics.CompositingQuality = CompositingQuality.HighQuality;
            thumbnailGraphics.SmoothingMode      = SmoothingMode.AntiAlias;
            thumbnailGraphics.DrawImage(contentsAndTab, 0, 0, _tabThumbnail.Width, _tabThumbnail.Height);

            Width  = _tabThumbnail.Width - 1;
            Height = _tabThumbnail.Height - 1;

            _cursorOffset = new Point(tabRenderer.TabContentWidth / 4, tabRenderer.TabHeight / 4);

            SetWindowPosition(Cursor.Position);
        }
Пример #6
0
        /// <summary>Resizes the <see cref="TitleBarTab.Content" /> form of the <paramref name="tab" /> to match the size of the client area for this window.</summary>
        /// <param name="tab">Tab whose <see cref="TitleBarTab.Content" /> form we should resize; if not specified, we default to
        /// <see cref="SelectedTab" />.</param>
        public void ResizeTabContents(TitleBarTab tab = null)
        {
            if (tab == null)
            {
                tab = SelectedTab;
            }

            if (tab != null)
            {
                tab.Content.Location = new Point(0, Padding.Top - 1);
                tab.Content.Size     = new Size(ClientRectangle.Width, ClientRectangle.Height - Padding.Top + 1);
            }
        }
Пример #7
0
        /// <summary>
        /// Callback for the <see cref="TabSelected" /> event.  Called when a <see cref="TitleBarTab" /> gains focus.  Sets the active window in Aero Peek via a
        /// call to <see cref="TabbedThumbnailManager.SetActiveTab(Control)" />.
        /// </summary>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnTabSelected(TitleBarTabEventArgs e)
        {
            if (SelectedTabIndex != -1 && _previews.ContainsKey(SelectedTab.Content) && AeroPeekEnabled)
            {
                TaskbarManager.Instance.TabbedThumbnail.SetActiveTab(SelectedTab.Content);
            }

            _previousActiveTab = SelectedTab;

            if (TabSelected != null)
            {
                TabSelected(this, e);
            }
        }
Пример #8
0
        /// <summary>
        /// Creates a new thumbnail for <paramref name="tab" /> when the application is initially enabled for AeroPeek or when it is turned on sometime during
        /// execution.
        /// </summary>
        /// <param name="tab">Tab that we are to create the thumbnail for.</param>
        /// <returns>Thumbnail created for <paramref name="tab" />.</returns>
        protected virtual TabbedThumbnail CreateThumbnailPreview(TitleBarTab tab)
        {
            TabbedThumbnail preview = new TabbedThumbnail(Handle, tab.Content)
            {
                Title   = tab.Content.Text,
                Tooltip = tab.Content.Text
            };

            preview.SetWindowIcon(tab.Content.Icon);
            preview.TabbedThumbnailActivated       += preview_TabbedThumbnailActivated;
            preview.TabbedThumbnailClosed          += preview_TabbedThumbnailClosed;
            preview.TabbedThumbnailBitmapRequested += preview_TabbedThumbnailBitmapRequested;
            preview.PeekOffset = new Vector(Padding.Left, Padding.Top - 1);

            TaskbarManager.Instance.TabbedThumbnail.AddThumbnailPreview(preview);

            return(preview);
        }
Пример #9
0
        /// <summary>Removes <paramref name="closingTab" /> from <see cref="Tabs" /> and selects the next applicable tab in the list.</summary>
        /// <param name="closingTab">Tab that is being closed.</param>
        protected virtual void CloseTab(TitleBarTab closingTab)
        {
            int removeIndex      = Tabs.IndexOf(closingTab);
            int selectedTabIndex = SelectedTabIndex;

            Tabs.Remove(closingTab);

            if (selectedTabIndex > removeIndex)
            {
                SelectedTabIndex = selectedTabIndex - 1;
            }

            else if (selectedTabIndex == removeIndex)
            {
                SelectedTabIndex = Math.Min(selectedTabIndex, Tabs.Count - 1);
            }

            else
            {
                SelectedTabIndex = selectedTabIndex;
            }

            if (_previews.ContainsKey(closingTab.Content))
            {
                _previews[closingTab.Content].Dispose();
                _previews.Remove(closingTab.Content);
            }

            if (_previousActiveTab != null && closingTab.Content == _previousActiveTab.Content)
            {
                _previousActiveTab = null;
            }

            if (!closingTab.Content.IsDisposed && AeroPeekEnabled)
            {
                TaskbarManager.Instance.TabbedThumbnail.RemoveThumbnailPreview(closingTab.Content);
            }

            if (Tabs.Count == 0 && ExitOnLastTabClose)
            {
                Close();
            }
        }
Пример #10
0
        /// <summary>Generate a new thumbnail image for <paramref name="tab" />.</summary>
        /// <param name="tab">Tab that we need to generate a thumbnail for.</param>
        protected void UpdateTabThumbnail(TitleBarTab tab)
        {
            TabbedThumbnail preview = TaskbarManager.Instance.TabbedThumbnail.GetThumbnailPreview(tab.Content);

            if (preview == null)
            {
                return;
            }

            Bitmap bitmap = TabbedThumbnailScreenCapture.GrabWindowBitmap(tab.Content.Handle, tab.Content.Size);

            preview.SetImage(bitmap);

            // If we already had a preview image for the tab, dispose of it
            if (_previews.ContainsKey(tab.Content) && _previews[tab.Content] != null)
            {
                _previews[tab.Content].Dispose();
            }

            _previews[tab.Content] = bitmap;
        }
Пример #11
0
        /// <summary>
        /// Called from the <see cref="_parentWindow" /> to determine which, if any, of the <paramref name="tabs" /> the <paramref name="cursor" /> is
        /// over.
        /// </summary>
        /// <param name="tabs">The list of tabs that we should check.</param>
        /// <param name="cursor">The relative position of the cursor within the window.</param>
        /// <returns>The tab within <paramref name="tabs" /> that the <paramref name="cursor" /> is over; if none, then null is returned.</returns>
        public virtual TitleBarTab OverTab(IEnumerable <TitleBarTab> tabs, Point cursor)
        {
            TitleBarTab overTab = null;

            foreach (TitleBarTab tab in tabs.Where(tab => tab.TabImage != null))
            {
                // We have to loop through each of the tabs in turn and check their status; if the tabs overlap, then their areas overlap as well, which means
                // that we may find see that the cursor is over an inactive tab, but we need to check the active tabs as well, since they may overlap their
                // areas and take precedence.
                if (tab.Active && IsOverTab(tab, cursor))
                {
                    overTab = tab;
                    break;
                }

                if (IsOverTab(tab, cursor))
                {
                    overTab = tab;
                }
            }

            return(overTab);
        }
Пример #12
0
        /// <summary>
        /// Consumer method that processes mouse events in <see cref="_mouseEvents" /> that are recorded by <see cref="MouseHookCallback" />.
        /// </summary>
        protected void InterpretMouseEvents()
        {
            foreach (MouseEvent mouseEvent in _mouseEvents.GetConsumingEnumerable())
            {
                int            nCode      = mouseEvent.nCode;
                IntPtr         wParam     = mouseEvent.wParam;
                MSLLHOOKSTRUCT?hookStruct = mouseEvent.MouseData;

                if (nCode >= 0 && (int)WM.WM_MOUSEMOVE == (int)wParam)
                {
// ReSharper disable PossibleInvalidOperationException
                    Point cursorPosition = new Point(hookStruct.Value.pt.x, hookStruct.Value.pt.y);
// ReSharper restore PossibleInvalidOperationException
                    bool reRender = false;

                    if (_tornTab != null)
                    {
                        // ReSharper disable ForCanBeConvertedToForeach
                        for (int i = 0; i < _dropAreas.Length; i++)
                        // ReSharper restore ForCanBeConvertedToForeach
                        {
                            // If the cursor is within the drop area, combine the tab for the window that belongs to that drop area
                            if (_dropAreas[i].Item2.Contains(cursorPosition))
                            {
                                TitleBarTab tabToCombine = null;

                                lock (_tornTabLock)
                                {
                                    if (_tornTab != null)
                                    {
                                        tabToCombine = _tornTab;
                                        _tornTab     = null;
                                    }
                                }

                                if (tabToCombine != null)
                                {
                                    int i1 = i;

                                    // In all cases where we need to affect the UI, we call Invoke so that those changes are made on the main UI thread since
                                    // we are on a separate processing thread in this case
                                    Invoke(
                                        new Action(
                                            () =>
                                    {
                                        _dropAreas[i1].Item1.TabRenderer.CombineTab(tabToCombine, cursorPosition);

                                        tabToCombine = null;
                                        _tornTabForm.Close();
                                        _tornTabForm = null;

                                        if (_parentForm.Tabs.Count == 0)
                                        {
                                            _parentForm.Close();
                                        }
                                    }));
                                }
                            }
                        }
                    }

                    else if (!_parentForm.TabRenderer.IsTabRepositioning)
                    {
                        // If we were over a close button previously, check to see if the cursor is still over that tab's
                        // close button; if not, re-render
                        if (_isOverCloseButtonForTab != -1 &&
                            (_isOverCloseButtonForTab >= _parentForm.Tabs.Count ||
                             !_parentForm.TabRenderer.IsOverCloseButton(_parentForm.Tabs[_isOverCloseButtonForTab], GetRelativeCursorPosition(cursorPosition))))
                        {
                            reRender = true;
                            _isOverCloseButtonForTab = -1;
                        }

                        // Otherwise, see if any tabs' close button is being hovered over
                        else
                        {
                            // ReSharper disable ForCanBeConvertedToForeach
                            for (int i = 0; i < _parentForm.Tabs.Count; i++)
                            // ReSharper restore ForCanBeConvertedToForeach
                            {
                                if (_parentForm.TabRenderer.IsOverCloseButton(_parentForm.Tabs[i], GetRelativeCursorPosition(cursorPosition)))
                                {
                                    _isOverCloseButtonForTab = i;
                                    reRender = true;

                                    break;
                                }
                            }
                        }
                    }

                    else
                    {
                        Invoke(
                            new Action(
                                () =>
                        {
                            _wasDragging = true;

                            // When determining if a tab has been torn from the window while dragging, we take the drop area for this window and inflate it by the
                            // TabTearDragDistance setting
                            Rectangle dragArea = TabDropArea;
                            dragArea.Inflate(_parentForm.TabRenderer.TabTearDragDistance, _parentForm.TabRenderer.TabTearDragDistance);

                            // If the cursor is outside the tear area, tear it away from the current window
                            if (!dragArea.Contains(cursorPosition) && _tornTab == null)
                            {
                                lock (_tornTabLock)
                                {
                                    if (_tornTab == null)
                                    {
                                        _parentForm.TabRenderer.IsTabRepositioning = false;

                                        // Clear the event handler subscriptions from the tab and then create a thumbnail representation of it to use when dragging
                                        _tornTab = _parentForm.SelectedTab;
                                        _tornTab.ClearSubscriptions();
                                        _tornTabForm = new TornTabForm(_tornTab, _parentForm.TabRenderer);
                                    }
                                }

                                if (_tornTab != null)
                                {
                                    _parentForm.SelectedTabIndex = (_parentForm.SelectedTabIndex == _parentForm.Tabs.Count - 1
                                                                                                                                        ? _parentForm.SelectedTabIndex - 1
                                                                                                                                        : _parentForm.SelectedTabIndex + 1);
                                    _parentForm.Tabs.Remove(_tornTab);

                                    // If this tab was the only tab in the window, hide the parent window
                                    if (_parentForm.Tabs.Count == 0)
                                    {
                                        _parentForm.Hide();
                                    }

                                    _tornTabForm.Show();
                                    _dropAreas = (from window in _parentForm.ApplicationContext.OpenWindows.Where(w => w.Tabs.Count > 0)
                                                  select new Tuple <TitleBarTabs, Rectangle>(window, window.TabDropArea)).ToArray();
                                }
                            }
                        }));
                    }

                    Invoke(new Action(() => OnMouseMove(new MouseEventArgs(MouseButtons.None, 0, cursorPosition.X, cursorPosition.Y, 0))));

                    if (_parentForm.TabRenderer.IsTabRepositioning)
                    {
                        reRender = true;
                    }

                    if (reRender)
                    {
                        Invoke(new Action(() => Render(cursorPosition, true)));
                    }
                }

                else if (nCode >= 0 && (int)WM.WM_LBUTTONDOWN == (int)wParam)
                {
                    _wasDragging = false;
                }

                else if (nCode >= 0 && (int)WM.WM_LBUTTONUP == (int)wParam)
                {
                    // If we released the mouse button while we were dragging a torn tab, put that tab into a new window
                    if (_tornTab != null)
                    {
                        TitleBarTab tabToRelease = null;

                        lock (_tornTabLock)
                        {
                            if (_tornTab != null)
                            {
                                tabToRelease = _tornTab;
                                _tornTab     = null;
                            }
                        }

                        if (tabToRelease != null)
                        {
                            Invoke(
                                new Action(
                                    () =>
                            {
                                TitleBarTabs newWindow = (TitleBarTabs)Activator.CreateInstance(_parentForm.GetType());

                                // Set the initial window position and state properly
                                if (newWindow.WindowState == FormWindowState.Maximized)
                                {
                                    Screen screen = Screen.AllScreens.First(s => s.WorkingArea.Contains(Cursor.Position));

                                    newWindow.StartPosition = FormStartPosition.Manual;
                                    newWindow.WindowState   = FormWindowState.Normal;
                                    newWindow.Left          = screen.WorkingArea.Left;
                                    newWindow.Top           = screen.WorkingArea.Top;
                                    newWindow.Width         = screen.WorkingArea.Width;
                                    newWindow.Height        = screen.WorkingArea.Height;
                                }

                                else
                                {
                                    newWindow.Left = Cursor.Position.X;
                                    newWindow.Top  = Cursor.Position.Y;
                                }

                                tabToRelease.Parent = newWindow;
                                _parentForm.ApplicationContext.OpenWindow(newWindow);

                                newWindow.Show();
                                newWindow.Tabs.Add(tabToRelease);
                                newWindow.SelectedTabIndex = 0;
                                newWindow.ResizeTabContents();

                                _tornTabForm.Close();
                                _tornTabForm = null;

                                if (_parentForm.Tabs.Count == 0)
                                {
                                    _parentForm.Close();
                                }
                            }));
                        }
                    }

                    Invoke(new Action(() => OnMouseUp(new MouseEventArgs(MouseButtons.Left, 1, Cursor.Position.X, Cursor.Position.Y, 0))));
                }
            }
        }
Пример #13
0
        /// <summary>Internal method for rendering an individual <paramref name="tab" /> to the screen.</summary>
        /// <param name="graphicsContext">Graphics context to use when rendering the tab.</param>
        /// <param name="tab">Individual tab that we are to render.</param>
        /// <param name="area">Area of the screen that the tab should be rendered to.</param>
        /// <param name="cursor">Current position of the cursor.</param>
        protected virtual void Render(Graphics graphicsContext, TitleBarTab tab, Rectangle area, Point cursor)
        {
            if (_suspendRendering)
            {
                return;
            }

            // If we need to redraw the tab image
            if (tab.TabImage == null)
            {
                // We render the tab to an internal property so that we don't necessarily have to redraw it in every rendering pass, only if its width or
                // status have changed
                tab.TabImage = new Bitmap(
                    area.Width, tab.Active
                                                ? _activeCenterImage.Height
                                                : _inactiveCenterImage.Height);

                using (Graphics tabGraphicsContext = Graphics.FromImage(tab.TabImage))
                {
                    // Draw the left, center, and right portions of the tab
                    tabGraphicsContext.DrawImage(
                        tab.Active
                                                        ? _activeLeftSideImage
                                                        : _inactiveLeftSideImage, new Rectangle(
                            0, 0, tab.Active
                                                                        ? _activeLeftSideImage
                            .Width
                                                                        : _inactiveLeftSideImage
                            .Width,
                            tab.Active
                                                                        ? _activeLeftSideImage.
                            Height
                                                                        : _inactiveLeftSideImage
                            .Height), 0, 0,
                        tab.Active
                                                        ? _activeLeftSideImage.Width
                                                        : _inactiveLeftSideImage.Width, tab.Active
                                                                ? _activeLeftSideImage.Height
                                                                : _inactiveLeftSideImage.Height,
                        GraphicsUnit.Pixel);

                    tabGraphicsContext.DrawImage(
                        tab.Active
                                                        ? _activeCenterImage
                                                        : _inactiveCenterImage, new Rectangle(
                            (tab.Active
                                                                        ? _activeLeftSideImage.
                             Width
                                                                        : _inactiveLeftSideImage
                             .Width), 0,
                            _tabContentWidth, tab.Active
                                                                        ? _activeCenterImage
                            .
                            Height
                                                                        : _inactiveCenterImage
                            .
                            Height),
                        0, 0, _tabContentWidth, tab.Active
                                                        ? _activeCenterImage.Height
                                                        : _inactiveCenterImage.Height,
                        GraphicsUnit.Pixel);

                    tabGraphicsContext.DrawImage(
                        tab.Active
                                                        ? _activeRightSideImage
                                                        : _inactiveRightSideImage, new Rectangle(
                            (tab.Active
                                                                        ? _activeLeftSideImage
                             .Width
                                                                        : _inactiveLeftSideImage
                             .Width) +
                            _tabContentWidth, 0,
                            tab.Active
                                                                        ? _activeRightSideImage
                            .Width
                                                                        : _inactiveRightSideImage
                            .Width,
                            tab.Active
                                                                        ? _activeRightSideImage
                            .Height
                                                                        : _inactiveRightSideImage
                            .Height), 0, 0,
                        tab.Active
                                                        ? _activeRightSideImage.Width
                                                        : _inactiveRightSideImage.Width, tab.Active
                                                                ? _activeRightSideImage.Height
                                                                : _inactiveRightSideImage.
                        Height,
                        GraphicsUnit.Pixel);

                    // Draw the close button
                    if (tab.ShowCloseButton)
                    {
                        Image closeButtonImage = IsOverCloseButton(tab, cursor)
                                                        ? _closeButtonHoverImage
                                                        : _closeButtonImage;

                        tab.CloseButtonArea = new Rectangle(
                            area.Width - (tab.Active
                                                                ? _activeRightSideImage.Width
                                                                : _inactiveRightSideImage.Width) -
                            CloseButtonMarginRight - closeButtonImage.Width,
                            CloseButtonMarginTop, closeButtonImage.Width,
                            closeButtonImage.Height);

                        tabGraphicsContext.DrawImage(
                            closeButtonImage, tab.CloseButtonArea, 0, 0,
                            closeButtonImage.Width, closeButtonImage.Height,
                            GraphicsUnit.Pixel);
                    }
                }

                tab.Area = area;
            }

            // Render the tab's saved image to the screen
            graphicsContext.DrawImage(
                tab.TabImage, area, 0, 0, tab.TabImage.Width, tab.TabImage.Height,
                GraphicsUnit.Pixel);

            // Render the icon for the tab's content, if it exists and there's room for it in the tab's content area
            if (tab.Content.ShowIcon && _tabContentWidth > 16 + IconMarginLeft + (tab.ShowCloseButton
                                ? CloseButtonMarginLeft +
                                                                                  tab.CloseButtonArea.Width +
                                                                                  CloseButtonMarginRight
                                : 0))
            {
                graphicsContext.DrawIcon(
                    new Icon(tab.Content.Icon, 16, 16),
                    new Rectangle(area.X + OverlapWidth + IconMarginLeft, IconMarginTop + area.Y, 16, 16));
            }

            // Render the caption for the tab's content if there's room for it in the tab's content area
            if (_tabContentWidth > (tab.Content.ShowIcon
                                ? 16 + IconMarginLeft + IconMarginRight
                                : 0) + CaptionMarginLeft + CaptionMarginRight + (tab.ShowCloseButton
                                        ? CloseButtonMarginLeft +
                                                                                 tab.CloseButtonArea.Width +
                                                                                 CloseButtonMarginRight
                                        : 0))
            {
                graphicsContext.DrawString(
                    tab.Caption, SystemFonts.CaptionFont, Brushes.Black,
                    new Rectangle(
                        area.X + OverlapWidth + CaptionMarginLeft + (tab.Content.ShowIcon
                                                        ? IconMarginLeft +
                                                                     16 +
                                                                     IconMarginRight
                                                        : 0),
                        CaptionMarginTop + area.Y,
                        _tabContentWidth - (tab.Content.ShowIcon
                                                        ? IconMarginLeft + 16 + IconMarginRight
                                                        : 0) - (tab.ShowCloseButton
                                                                ? _closeButtonImage.Width +
                                                                CloseButtonMarginRight +
                                                                CloseButtonMarginLeft
                                                                : 0), tab.TabImage.Height),
                    new StringFormat(StringFormatFlags.NoWrap)
                {
                    Trimming = StringTrimming.EllipsisCharacter
                });
            }
        }
Пример #14
0
        /// <summary>Renders the list of <paramref name="tabs" /> to the screen using the given <paramref name="graphicsContext" />.</summary>
        /// <param name="tabs">List of tabs that we are to render.</param>
        /// <param name="graphicsContext">Graphics context that we should use while rendering.</param>
        /// <param name="cursor">Current location of the cursor on the screen.</param>
        /// <param name="forceRedraw">Flag indicating whether or not the redraw should be forced.</param>
        /// <param name="offset">Offset within <paramref name="graphicsContext" /> that the tabs should be rendered.</param>
        public virtual void Render(List <TitleBarTab> tabs, Graphics graphicsContext, Point offset, Point cursor, bool forceRedraw = false)
        {
            if (_suspendRendering)
            {
                return;
            }

            if (tabs == null || tabs.Count == 0)
            {
                return;
            }

            Point screenCoordinates = _parentWindow.PointToScreen(_parentWindow.ClientRectangle.Location);

            // Calculate the maximum tab area, excluding the add button and any minimize/maximize/close buttons in the window
            _maxTabArea.Location = new Point(SystemInformation.BorderSize.Width + offset.X + screenCoordinates.X, offset.Y + screenCoordinates.Y);
            _maxTabArea.Width    = (_parentWindow.ClientRectangle.Width - offset.X -
                                    (ShowAddButton
                                                     ? _addButtonImage.Width + AddButtonMarginLeft +
                                     AddButtonMarginRight
                                                     : 0) - (tabs.Count() * OverlapWidth) -
                                    (_parentWindow.ControlBox
                                                     ? SystemInformation.CaptionButtonSize.Width
                                                     : 0) -
                                    (_parentWindow.MinimizeBox
                                                     ? SystemInformation.CaptionButtonSize.Width
                                                     : 0) -
                                    (_parentWindow.MaximizeBox
                                                     ? SystemInformation.CaptionButtonSize.Width
                                                     : 0));
            _maxTabArea.Height = _activeCenterImage.Height;

            // Get the width of the content area for each tab by taking the parent window's client width, subtracting the left and right border widths and the
            // add button area (if applicable) and then dividing by the number of tabs
            int tabContentWidth = Math.Min(_activeCenterImage.Width, Convert.ToInt32(Math.Floor(Convert.ToDouble(_maxTabArea.Width / tabs.Count()))));

            // Determine if we need to redraw the TabImage properties for each tab by seeing if the content width that we calculated above is equal to content
            // width we had in the previous rendering pass
            bool redraw = (tabContentWidth != _tabContentWidth || forceRedraw);

            if (redraw)
            {
                _tabContentWidth = tabContentWidth;
            }

            int i = tabs.Count - 1;
            List <Tuple <TitleBarTab, Rectangle> > activeTabs = new List <Tuple <TitleBarTab, Rectangle> >();

            // Render the background image
            if (_background != null)
            {
                graphicsContext.DrawImage(_background, offset.X, offset.Y, _parentWindow.Width, _activeCenterImage.Height);
            }

            int selectedIndex = tabs.FindIndex(t => t.Active);

            if (selectedIndex != -1)
            {
                Rectangle tabArea = new Rectangle(
                    SystemInformation.BorderSize.Width + offset.X +
                    (selectedIndex * (tabContentWidth + _activeLeftSideImage.Width + _activeRightSideImage.Width - OverlapWidth)),
                    offset.Y, tabContentWidth + _activeLeftSideImage.Width + _activeRightSideImage.Width,
                    _activeCenterImage.Height);

                if (IsTabRepositioning && _tabClickOffset != null)
                {
                    // Make sure that the user doesn't move the tab past the beginning of the list or the outside of the window
                    tabArea.X = cursor.X - _tabClickOffset.Value;
                    tabArea.X = Math.Max(SystemInformation.BorderSize.Width + offset.X, tabArea.X);
                    tabArea.X =
                        Math.Min(
                            SystemInformation.BorderSize.Width + (_parentWindow.WindowState == FormWindowState.Maximized
                                                                ? _parentWindow.ClientRectangle.Width - (_parentWindow.ControlBox
                                                                        ? SystemInformation.CaptionButtonSize.Width
                                                                        : 0) -
                                                                  (_parentWindow.MinimizeBox
                                                                          ? SystemInformation.CaptionButtonSize.Width
                                                                          : 0) -
                                                                  (_parentWindow.MaximizeBox
                                                                          ? SystemInformation.CaptionButtonSize.Width
                                                                          : 0)
                                                                : _parentWindow.ClientRectangle.Width) - tabArea.Width, tabArea.X);

                    int dropIndex = 0;

                    // Figure out which slot the active tab is being "dropped" over
                    if (tabArea.X - SystemInformation.BorderSize.Width - offset.X - TabRepositionDragDistance > 0)
                    {
                        dropIndex =
                            Math.Min(
                                Convert.ToInt32(
                                    Math.Round(
                                        Convert.ToDouble(tabArea.X - SystemInformation.BorderSize.Width - offset.X - TabRepositionDragDistance) /
                                        Convert.ToDouble(tabArea.Width - OverlapWidth))), tabs.Count - 1);
                    }

                    // If the tab has been moved over another slot, move the tab object in the window's tab list
                    if (dropIndex != selectedIndex)
                    {
                        TitleBarTab tab = tabs[selectedIndex];

                        _parentWindow.Tabs.SuppressEvents();
                        _parentWindow.Tabs.Remove(tab);
                        _parentWindow.Tabs.Insert(dropIndex, tab);
                        _parentWindow.Tabs.ResumeEvents();
                    }
                }

                activeTabs.Add(new Tuple <TitleBarTab, Rectangle>(tabs[selectedIndex], tabArea));
            }

            // Loop through the tabs in reverse order since we need the ones farthest on the left to overlap those to their right
            foreach (TitleBarTab tab in ((IEnumerable <TitleBarTab>)tabs).Reverse())
            {
                Rectangle tabArea =
                    new Rectangle(
                        SystemInformation.BorderSize.Width + offset.X +
                        (i * (tabContentWidth + _activeLeftSideImage.Width + _activeRightSideImage.Width - OverlapWidth)),
                        offset.Y, tabContentWidth + _activeLeftSideImage.Width + _activeRightSideImage.Width,
                        _activeCenterImage.Height);

                // If we need to redraw the tab image, null out the property so that it will be recreated in the call to Render() below
                if (redraw)
                {
                    tab.TabImage = null;
                }

                // In this first pass, we only render the inactive tabs since we need the active tabs to show up on top of everything else
                if (!tab.Active)
                {
                    Render(graphicsContext, tab, tabArea, cursor);
                }

                i--;
            }

            // In the second pass, render all of the active tabs identified in the previous pass
            foreach (Tuple <TitleBarTab, Rectangle> tab in activeTabs)
            {
                Render(graphicsContext, tab.Item1, tab.Item2, cursor);
            }

            _previousTabCount = tabs.Count;

            // Render the add tab button to the screen
            if (ShowAddButton && !IsTabRepositioning)
            {
                _addButtonArea =
                    new Rectangle(
                        (_previousTabCount *
                         (tabContentWidth + _activeLeftSideImage.Width + _activeRightSideImage.Width - OverlapWidth)) +
                        _activeRightSideImage.Width + AddButtonMarginLeft + offset.X,
                        AddButtonMarginTop + offset.Y, _addButtonImage.Width, _addButtonImage.Height);

                bool cursorOverAddButton = IsOverAddButton(cursor);

                graphicsContext.DrawImage(
                    cursorOverAddButton
                                                ? _addButtonHoverImage
                                                : _addButtonImage, _addButtonArea, 0, 0, cursorOverAddButton
                                                        ? _addButtonHoverImage.Width
                                                        : _addButtonImage.Width,
                    cursorOverAddButton
                                                ? _addButtonHoverImage.Height
                                                : _addButtonImage.Height, GraphicsUnit.Pixel);
            }
        }
Пример #15
0
 /// <summary>Tests whether the <paramref name="cursor" /> is hovering over the given <paramref name="tab" />.</summary>
 /// <param name="tab">Tab that we are to see if the cursor is hovering over.</param>
 /// <param name="cursor">Current location of the cursor.</param>
 /// <returns>
 /// True if the <paramref name="cursor" /> is within the <see cref="TitleBarTab.Area" /> of the <paramref name="tab" /> and is over a non- transparent
 /// pixel of <see cref="TitleBarTab.TabImage" />, false otherwise.
 /// </returns>
 protected virtual bool IsOverTab(TitleBarTab tab, Point cursor)
 {
     return(IsOverNonTransparentArea(tab.Area, tab.TabImage, cursor));
 }
Пример #16
0
        /// <summary>Overrides the message pump for the window so that we can respond to click events on the tabs themselves.</summary>
        /// <param name="m">Message received by the pump.</param>
        protected override void WndProc(ref Message m)
        {
            switch ((WM)m.Msg)
            {
            case WM.WM_NCLBUTTONDOWN:
            case WM.WM_LBUTTONDOWN:
                Point relativeCursorPosition = GetRelativeCursorPosition(Cursor.Position);

                // If we were over a tab, set the capture state for the window so that we'll actually receive a WM_LBUTTONUP message
                if (_parentForm.TabRenderer.OverTab(_parentForm.Tabs, relativeCursorPosition) == null &&
                    !_parentForm.TabRenderer.IsOverAddButton(relativeCursorPosition))
                {
                    _parentForm.ForwardMessage(ref m);
                }

                else
                {
                    // When the user clicks a mouse button, save the tab that the user was over so we can respond properly when the mouse button is released
                    TitleBarTab clickedTab = _parentForm.TabRenderer.OverTab(_parentForm.Tabs, relativeCursorPosition);

                    if (clickedTab != null)
                    {
                        // If the user clicked the close button, remove the tab from the list
                        if (!_parentForm.TabRenderer.IsOverCloseButton(clickedTab, relativeCursorPosition))
                        {
                            _parentForm.ResizeTabContents(clickedTab);
                            _parentForm.SelectedTabIndex = _parentForm.Tabs.IndexOf(clickedTab);

                            Render();
                        }

                        OnMouseDown(new MouseEventArgs(MouseButtons.Left, 1, Cursor.Position.X, Cursor.Position.Y, 0));
                    }

                    _parentForm.Activate();
                }

                break;

            case WM.WM_LBUTTONDBLCLK:
                _parentForm.ForwardMessage(ref m);
                break;

            // We always return HTCAPTION for the hit test message so that the underlying window doesn't have its focus removed
            case WM.WM_NCHITTEST:
                m.Result = new IntPtr((int)HT.HTCAPTION);
                break;

            case WM.WM_LBUTTONUP:
            case WM.WM_NCLBUTTONUP:
                Point relativeCursorPosition2 = GetRelativeCursorPosition(Cursor.Position);

                if (_parentForm.TabRenderer.OverTab(_parentForm.Tabs, relativeCursorPosition2) == null &&
                    !_parentForm.TabRenderer.IsOverAddButton(relativeCursorPosition2))
                {
                    _parentForm.ForwardMessage(ref m);
                }

                else
                {
                    // When the user clicks a mouse button, save the tab that the user was over so we can respond properly when the mouse button is released
                    TitleBarTab clickedTab = _parentForm.TabRenderer.OverTab(_parentForm.Tabs, relativeCursorPosition2);

                    if (clickedTab != null)
                    {
                        // If the user clicked the close button, remove the tab from the list
                        if (_parentForm.TabRenderer.IsOverCloseButton(clickedTab, relativeCursorPosition2))
                        {
                            clickedTab.Content.Close();
                            Render();
                        }

                        else
                        {
                            _parentForm.OnTabClicked(
                                new TitleBarTabEventArgs
                            {
                                Tab         = clickedTab,
                                TabIndex    = _parentForm.SelectedTabIndex,
                                Action      = TabControlAction.Selected,
                                WasDragging = _wasDragging
                            });
                        }
                    }

                    // Otherwise, if the user clicked the add button, call CreateTab to add a new tab to the list and select it
                    else if (_parentForm.TabRenderer.IsOverAddButton(relativeCursorPosition2))
                    {
                        _parentForm.AddNewTab();
                    }

                    OnMouseUp(new MouseEventArgs(MouseButtons.Left, 1, Cursor.Position.X, Cursor.Position.Y, 0));
                }

                break;

            default:
                base.WndProc(ref m);
                break;
            }
        }
Пример #17
0
        /// <summary>
        /// Consumer method that processes mouse events in <see cref="_mouseEvents" /> that are recorded by <see cref="MouseHookCallback" />.
        /// </summary>
        protected void InterpretMouseEvents()
        {
            foreach (MouseEvent mouseEvent in _mouseEvents.GetConsumingEnumerable())
            {
                int nCode = mouseEvent.nCode;
                IntPtr wParam = mouseEvent.wParam;
                MSLLHOOKSTRUCT? hookStruct = mouseEvent.MouseData;

                if (nCode >= 0 && (int) WM.WM_MOUSEMOVE == (int) wParam)
                {
            // ReSharper disable PossibleInvalidOperationException
                    Point cursorPosition = new Point(hookStruct.Value.pt.x, hookStruct.Value.pt.y);
            // ReSharper restore PossibleInvalidOperationException
                    bool reRender = false;

                    if (_tornTab != null)
                    {
                        // ReSharper disable ForCanBeConvertedToForeach
                        for (int i = 0; i < _dropAreas.Length; i++)
                            // ReSharper restore ForCanBeConvertedToForeach
                        {
                            // If the cursor is within the drop area, combine the tab for the window that belongs to that drop area
                            if (_dropAreas[i].Item2.Contains(cursorPosition))
                            {
                                TitleBarTab tabToCombine = null;

                                lock (_tornTabLock)
                                {
                                    if (_tornTab != null)
                                    {
                                        tabToCombine = _tornTab;
                                        _tornTab = null;
                                    }
                                }

                                if (tabToCombine != null)
                                {
                                    int i1 = i;

                                    // In all cases where we need to affect the UI, we call Invoke so that those changes are made on the main UI thread since
                                    // we are on a separate processing thread in this case
                                    Invoke(
                                        new Action(
                                            () =>
                                                {
                                                    _dropAreas[i1].Item1.TabRenderer.CombineTab(tabToCombine, cursorPosition);

                                                    tabToCombine = null;
                                                    _tornTabForm.Close();
                                                    _tornTabForm = null;

                                                    if (_parentForm.Tabs.Count == 0)
                                                        _parentForm.Close();
                                                }));
                                }
                            }
                        }
                    }

                    else if (!_parentForm.TabRenderer.IsTabRepositioning)
                    {
                        // If we were over a close button previously, check to see if the cursor is still over that tab's
                        // close button; if not, re-render
                        if (_isOverCloseButtonForTab != -1 &&
                            (_isOverCloseButtonForTab >= _parentForm.Tabs.Count ||
                             !_parentForm.TabRenderer.IsOverCloseButton(_parentForm.Tabs[_isOverCloseButtonForTab], GetRelativeCursorPosition(cursorPosition))))
                        {
                            reRender = true;
                            _isOverCloseButtonForTab = -1;
                        }

                            // Otherwise, see if any tabs' close button is being hovered over
                        else
                        {
                            // ReSharper disable ForCanBeConvertedToForeach
                            for (int i = 0; i < _parentForm.Tabs.Count; i++)
                                // ReSharper restore ForCanBeConvertedToForeach
                            {
                                if (_parentForm.TabRenderer.IsOverCloseButton(_parentForm.Tabs[i], GetRelativeCursorPosition(cursorPosition)))
                                {
                                    _isOverCloseButtonForTab = i;
                                    reRender = true;

                                    break;
                                }
                            }
                        }
                    }

                    else
                    {
                        Invoke(
                            new Action(
                                () =>
                                    {
                                        _wasDragging = true;

                                        // When determining if a tab has been torn from the window while dragging, we take the drop area for this window and inflate it by the
                                        // TabTearDragDistance setting
                                        Rectangle dragArea = TabDropArea;
                                        dragArea.Inflate(_parentForm.TabRenderer.TabTearDragDistance, _parentForm.TabRenderer.TabTearDragDistance);

                                        // If the cursor is outside the tear area, tear it away from the current window
                                        if (!dragArea.Contains(cursorPosition) && _tornTab == null)
                                        {
                                            lock (_tornTabLock)
                                            {
                                                if (_tornTab == null)
                                                {
                                                    _parentForm.TabRenderer.IsTabRepositioning = false;

                                                    // Clear the event handler subscriptions from the tab and then create a thumbnail representation of it to use when dragging
                                                    _tornTab = _parentForm.SelectedTab;
                                                    _tornTab.ClearSubscriptions();
                                                    _tornTabForm = new TornTabForm(_tornTab, _parentForm.TabRenderer);
                                                }
                                            }

                                            if (_tornTab != null)
                                            {
                                                _parentForm.SelectedTabIndex = (_parentForm.SelectedTabIndex == _parentForm.Tabs.Count - 1
                                                                                    ? _parentForm.SelectedTabIndex - 1
                                                                                    : _parentForm.SelectedTabIndex + 1);
                                                _parentForm.Tabs.Remove(_tornTab);

                                                // If this tab was the only tab in the window, hide the parent window
                                                if (_parentForm.Tabs.Count == 0)
                                                    _parentForm.Hide();

                                                _tornTabForm.Show();
                                                _dropAreas = (from window in _parentForm.ApplicationContext.OpenWindows.Where(w => w.Tabs.Count > 0)
                                                              select new Tuple<TitleBarTabs, Rectangle>(window, window.TabDropArea)).ToArray();
                                            }
                                        }
                                    }));
                    }

                    Invoke(new Action(() => OnMouseMove(new MouseEventArgs(MouseButtons.None, 0, cursorPosition.X, cursorPosition.Y, 0))));

                    if (_parentForm.TabRenderer.IsTabRepositioning)
                        reRender = true;

                    if (reRender)
                        Invoke(new Action(() => Render(cursorPosition, true)));
                }

                else if (nCode >= 0 && (int) WM.WM_LBUTTONDOWN == (int) wParam)
                    _wasDragging = false;

                else if (nCode >= 0 && (int) WM.WM_LBUTTONUP == (int) wParam)
                {
                    // If we released the mouse button while we were dragging a torn tab, put that tab into a new window
                    if (_tornTab != null)
                    {
                        TitleBarTab tabToRelease = null;

                        lock (_tornTabLock)
                        {
                            if (_tornTab != null)
                            {
                                tabToRelease = _tornTab;
                                _tornTab = null;
                            }
                        }

                        if (tabToRelease != null)
                        {
                            Invoke(
                                new Action(
                                    () =>
                                        {
                                            TitleBarTabs newWindow = (TitleBarTabs) Activator.CreateInstance(_parentForm.GetType());

                                            // Set the initial window position and state properly
                                            if (newWindow.WindowState == FormWindowState.Maximized)
                                            {
                                                Screen screen = Screen.AllScreens.First(s => s.WorkingArea.Contains(Cursor.Position));

                                                newWindow.StartPosition = FormStartPosition.Manual;
                                                newWindow.WindowState = FormWindowState.Normal;
                                                newWindow.Left = screen.WorkingArea.Left;
                                                newWindow.Top = screen.WorkingArea.Top;
                                                newWindow.Width = screen.WorkingArea.Width;
                                                newWindow.Height = screen.WorkingArea.Height;
                                            }

                                            else
                                            {
                                                newWindow.Left = Cursor.Position.X;
                                                newWindow.Top = Cursor.Position.Y;
                                            }

                                            tabToRelease.Parent = newWindow;
                                            _parentForm.ApplicationContext.OpenWindow(newWindow);

                                            newWindow.Show();
                                            newWindow.Tabs.Add(tabToRelease);
                                            newWindow.SelectedTabIndex = 0;
                                            newWindow.ResizeTabContents();

                                            _tornTabForm.Close();
                                            _tornTabForm = null;

                                            if (_parentForm.Tabs.Count == 0)
                                                _parentForm.Close();
                                        }));
                        }
                    }

                    Invoke(new Action(() => OnMouseUp(new MouseEventArgs(MouseButtons.Left, 1, Cursor.Position.X, Cursor.Position.Y, 0))));
                }
            }
        }