Пример #1
0
        /// <summary>
        /// When items are added to the tabs collection, we need to ensure that the <see cref="_parentWindow" />'s minimum width is set so that we can display at
        /// least each tab and its close buttons.
        /// </summary>
        /// <param name="sender">List of tabs in the <see cref="_parentWindow" />.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void Tabs_CollectionModified(object sender, NotifyCollectionChangedEventArgs e)
        {
            ListWithEvents <TitleBarTabItem> tabs = (ListWithEvents <TitleBarTabItem>)sender;

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

            int minimumWidth = tabs.Sum(
                tab => (tab.Active
                                        ? _activeLeftSideImage.Width
                                        : _inactiveLeftSideImage.Width) + (tab.Active
                                                ? _activeRightSideImage.Width
                                                : _inactiveRightSideImage.Width) +
                (tab.ShowCloseButton
                                               ? tab.CloseButtonArea.Width + CloseButtonMarginLeft
                                               : 0));

            minimumWidth += OverlapWidth;

            minimumWidth += (_parentWindow.ControlBox
                                ? SystemInformation.CaptionButtonSize.Width
                                : 0) -
                            (_parentWindow.MinimizeBox
                                                ? SystemInformation.CaptionButtonSize.Width
                                                : 0) -
                            (_parentWindow.MaximizeBox
                                                ? SystemInformation.CaptionButtonSize.Width
                                                : 0) + (ShowAddButton
                                                        ? _addButtonImage.Width + AddButtonMarginLeft +
                                                        AddButtonMarginRight
                                                        : 0);

            _parentWindow.MinimumSize = new Size(minimumWidth, 0);
        }
Пример #2
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(ListWithEvents <TitleBarTabItem> 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 <TitleBarTabItem, Rectangle> > activeTabs = new List <Tuple <TitleBarTabItem, 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)
                    {
                        TitleBarTabItem tab = tabs[selectedIndex];

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

                activeTabs.Add(new Tuple <TitleBarTabItem, 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 (TitleBarTabItem tab in ((IEnumerable <TitleBarTabItem>)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 <TitleBarTabItem, 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);
            }
        }