private void ShowTooltipTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { if (!_parentForm.ShowTooltips) { return; } Point relativeCursorPosition = GetRelativeCursorPosition(Cursor.Position); TitleBarTab hoverTab = _parentForm.TabRenderer.OverTab(_parentForm.Tabs, relativeCursorPosition); if (hoverTab != null) { TitleBarTabs hoverTabForm = hoverTab.Parent; if (hoverTabForm.InvokeRequired) { hoverTabForm.Invoke(new Action(() => { ShowTooltip(hoverTabForm, hoverTab.Caption); })); } else { ShowTooltip(hoverTabForm, hoverTab.Caption); } } }
/// <summary> /// Event handler that is called when <see cref="_parentForm" /> is in the process of closing. This uninstalls <see cref="_hookproc" /> from the low- /// level hooks list and stops the consumer thread that processes those events. /// </summary> /// <param name="sender">Object from which this event originated, <see cref="_parentForm" /> in this case.</param> /// <param name="e">Arguments associated with this event.</param> private void _parentForm_Closing(object sender, CancelEventArgs e) { if (e.Cancel) { return; } TitleBarTabs form = (TitleBarTabs)sender; if (form == null) { return; } if (_parents.ContainsKey(form)) { _parents.Remove(form); } // Uninstall the mouse hook User32.UnhookWindowsHookEx(_hookId); // Kill the mouse events processing thread _mouseEvents.CompleteAdding(); _mouseEventsThread.Abort(); }
/// <summary>Constructor that initializes the various resources that we use in rendering.</summary> /// <param name="parentWindow">Parent window that this renderer belongs to.</param> public ChromeTabRenderer(TitleBarTabs parentWindow) : base(parentWindow) { // Initialize the various images to use during rendering _activeLeftSideImage = Resources.ChromeLeft; _activeRightSideImage = Resources.ChromeRight; _activeCenterImage = Resources.ChromeCenter; _inactiveLeftSideImage = Resources.ChromeInactiveLeft; _inactiveRightSideImage = Resources.ChromeInactiveRight; _inactiveCenterImage = Resources.ChromeInactiveCenter; _closeButtonImage = Resources.ChromeClose; _closeButtonHoverImage = Resources.ChromeCloseHover; _background = Resources.ChromeBackground; _addButtonImage = new Bitmap(Resources.ChromeAdd); _addButtonHoverImage = new Bitmap(Resources.ChromeAddHover); // Set the various positioning properties CloseButtonMarginTop = 6; CloseButtonMarginLeft = 2; AddButtonMarginTop = 5; AddButtonMarginLeft = -3; CaptionMarginTop = 5; IconMarginTop = 6; IconMarginRight = 5; AddButtonMarginRight = 5; }
/// <summary>Constructor that initializes the various resources that we use in rendering.</summary> /// <param name="parentWindow">Parent window that this renderer belongs to.</param> public ModernChromeTabRenderer(TitleBarTabs parentWindow) : base(parentWindow) { // Initialize the various images to use during rendering _activeLeftSideImage = Resources.ModernChromeLeft; _activeRightSideImage = Resources.ModernChromeRight; _activeCenterImage = Resources.ModernChromeCenter; _inactiveLeftSideImage = Resources.ModernChromeInactiveLeft; _inactiveRightSideImage = Resources.ModernChromeInactiveRight; _inactiveCenterImage = Resources.ModernChromeInactiveCenter; _closeButtonImage = Resources.ModernChromeClose; _closeButtonHoverImage = Resources.ModernChromeCloseHover; _background = Resources.ModernChromeBackground; _addButtonImage = new Bitmap(Resources.ModernChromeAdd); _addButtonHoverImage = new Bitmap(Resources.ModernChromeAddHover); TabFont = new Font(SystemFonts.CaptionFont.FontFamily, 9); TabColor = Brushes.Black; // Set the various positioning properties CloseButtonMarginTop = 6; CloseButtonMarginLeft = 2; AddButtonMarginTop = 7; AddButtonMarginLeft = -1; CaptionMarginTop = 6; IconMarginTop = 7; IconMarginRight = 5; AddButtonMarginRight = 60; WindowTabTopOffset = 10; MaximizedWindowTabTopOffset = 10; }
/// <summary> /// Retrieves or creates the overlay for <paramref name="s_parentForm" /> /// </summary> /// <param name="parentForm">Parent form that we are to create the overlay for</param> /// <returns>Newly-created or previously existing overlay for <paramref name="s_parentForm" /></returns> public static TitleBarTabsOverlay GetInstance(TitleBarTabs parentForm) { if (!s_parents.ContainsKey(parentForm)) { s_parents.Add(parentForm, new TitleBarTabsOverlay(parentForm)); } return(s_parents[parentForm]); }
/// <summary> /// Adds <paramref name="window" /> to <see cref="OpenWindows" /> and attaches event handlers to its <see cref="System.Windows.Forms.Form.FormClosed" /> event to keep track of it /// </summary> /// <param name="window">Window that we're opening</param> public void OpenWindow(TitleBarTabs window) { if (!OpenWindows.Contains(window)) { window.ApplicationContext = this; OpenWindows.Add(window); window.FormClosed += WindowFormClosed; } }
public WindowsSizingBoxes(TitleBarTabs parentWindow) { _parentWindow = parentWindow; _minimizeImage = LoadSvg(Encoding.UTF8.GetString(Resources.Minimize), 10, 10); _restoreImage = LoadSvg(Encoding.UTF8.GetString(Resources.Restore), 10, 10); _maximizeImage = LoadSvg(Encoding.UTF8.GetString(Resources.Maximize), 10, 10); _closeImage = LoadSvg(Encoding.UTF8.GetString(Resources.Close), 10, 10); _closeHighlightImage = LoadSvg(Encoding.UTF8.GetString(Resources.CloseHighlight), 10, 10); }
public TitleBarTabsOverlay(TitleBarTabs parentForm) { ParentForm = parentForm; ShowInTaskbar = false; FormBorderStyle = FormBorderStyle.Sizable; MinimizeBox = false; MaximizeBox = false; AeroEnabled = ParentForm.IsCompositionEnabled; Show(parentForm); AttachHandlers(); }
/// <summary> /// Constructor; takes the initial window to display and, if it's not closing, opens it and shows it /// </summary> /// <param name="initialFormInstance">Initial window to display</param> public void Start(TitleBarTabs initialFormInstance) { if (initialFormInstance.IsClosing) { ExitThread(); } else { OpenWindow(initialFormInstance); initialFormInstance.Show(); } }
/// <summary>Creates the overlay window and attaches it to <paramref name="parentForm" />.</summary> /// <param name="parentForm">Parent form that the overlay should be rendered on top of.</param> protected TitleBarTabsOverlay(TitleBarTabs parentForm) { _parentForm = parentForm; // We don't want this window visible in the taskbar ShowInTaskbar = false; FormBorderStyle = FormBorderStyle.Sizable; MinimizeBox = false; MaximizeBox = false; _aeroEnabled = _parentForm.IsCompositionEnabled; Show(_parentForm); AttachHandlers(); }
/// <summary> /// Event handler that is called when <see cref="ParentForm" /> is in the process of closing. This uninstalls <see cref="HookProc" /> from the low-level hooks list and stops the consumer thread that processes those events /// </summary> /// <param name="sender">Object from which this event originated, <see cref="ParentForm" /> in this case</param> /// <param name="e">Arguments associated with this event</param> private void ParentFormOnClosing(object sender, CancelEventArgs e) { TitleBarTabs form = (TitleBarTabs)sender; if (form == null) { return; } if (s_parents.ContainsKey(form)) { s_parents.Remove(form); } User32.UnhookWindowsHookEx(HookID); MouseEvents.CompleteAdding(); MouseEventsThread.Abort(); }
/// <summary>Default constructor that initializes the <see cref="_parentWindow" /> and <see cref="ShowAddButton" /> properties.</summary> /// <param name="parentWindow">The parent window that this renderer instance belongs to.</param> protected BaseTabRenderer(TitleBarTabs parentWindow) { _parentWindow = parentWindow; ShowAddButton = true; TabRepositionDragDistance = 10; TabTearDragDistance = 10; parentWindow.Tabs.CollectionModified += Tabs_CollectionModified; if (parentWindow._overlay != null) { parentWindow._overlay.MouseMove += Overlay_MouseMove; parentWindow._overlay.MouseUp += Overlay_MouseUp; parentWindow._overlay.MouseDown += Overlay_MouseDown; } }
/// <summary>Default constructor that initializes the <see cref="_parentWindow" /> and <see cref="ShowAddButton" /> properties.</summary> /// <param name="parentWindow">The parent window that this renderer instance belongs to.</param> protected BaseTabRenderer(TitleBarTabs parentWindow) { _parentWindow = parentWindow; ShowAddButton = true; TabRepositionDragDistance = 10; TabTearDragDistance = 10; TabFont = SystemFonts.CaptionFont; TabColor = Brushes.Black; WindowTabTopOffset = 10; //SystemInformation.VerticalResizeBorderThickness; //SystemInformation.CaptionHeight; MaximizedWindowTabTopOffset = 0; //SystemInformation.VerticalResizeBorderThickness; parentWindow.Tabs.CollectionModified += Tabs_CollectionModified; if (parentWindow._overlay != null) { parentWindow._overlay.MouseMove += Overlay_MouseMove; parentWindow._overlay.MouseUp += Overlay_MouseUp; parentWindow._overlay.MouseDown += Overlay_MouseDown; } }
/// <summary>Creates the overlay window and attaches it to <paramref name="parentForm" />.</summary> /// <param name="parentForm">Parent form that the overlay should be rendered on top of.</param> protected TitleBarTabsOverlay(TitleBarTabs parentForm) { _parentForm = parentForm; // We don't want this window visible in the taskbar ShowInTaskbar = false; FormBorderStyle = FormBorderStyle.Sizable; MinimizeBox = false; MaximizeBox = false; _aeroEnabled = _parentForm.IsCompositionEnabled; Show(_parentForm); AttachHandlers(); showTooltipTimer = new Timer { AutoReset = false }; showTooltipTimer.Elapsed += ShowTooltipTimer_Elapsed; }
/// <summary>Constructor that initializes the various resources that we use in rendering.</summary> /// <param name="parentWindow">Parent window that this renderer belongs to.</param> public ChromeTabRenderer(TitleBarTabs parentWindow) : base(parentWindow) { // Initialize the various images to use during rendering _activeLeftSideImage = Resources.ChromeLeft; _activeRightSideImage = Resources.ChromeRight; _activeCenterImage = Resources.ChromeCenter; _inactiveLeftSideImage = Resources.ChromeInactiveLeft; _inactiveRightSideImage = Resources.ChromeInactiveRight; _inactiveCenterImage = Resources.ChromeInactiveCenter; _closeButtonImage = Resources.ChromeClose; _closeButtonHoverImage = Resources.ChromeCloseHover; _background = IsWindows10 ? Resources.ChromeBackground : null; _addButtonImage = new Bitmap(Resources.ChromeAdd); _addButtonHoverImage = new Bitmap(Resources.ChromeAddHover); // Set the various positioning properties CloseButtonMarginTop = 9; CloseButtonMarginLeft = 2; CloseButtonMarginRight = 4; AddButtonMarginTop = 3; AddButtonMarginLeft = 2; CaptionMarginTop = 9; IconMarginLeft = 9; IconMarginTop = 9; IconMarginRight = 5; AddButtonMarginRight = 45; _windowsSizingBoxes = new WindowsSizingBoxes(parentWindow); _captionFont = new Font("Segoe UI", 9); if (_captionFont.Name != "Segoe UI") { _captionFont = new Font(SystemFonts.CaptionFont.Name, 9); } }
/// <summary>Default constructor that initializes the various properties.</summary> /// <param name="parent">Parent window that contains this tab.</param> public TitleBarTab(TitleBarTabs parent) { ShowCloseButton = true; Parent = parent; }
/// <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) { HideTooltip(); // ReSharper disable PossibleInvalidOperationException Point cursorPosition = new Point(hookStruct.Value.pt.x, hookStruct.Value.pt.y); // ReSharper restore PossibleInvalidOperationException bool reRender = false; if (_tornTab != null && _dropAreas != 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) { StartTooltipTimer(); // 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)))); } } }
private void ShowTooltip(TitleBarTabs tabsForm, string caption) { Point tooltipLocation = new Point(Cursor.Position.X + 7, Cursor.Position.Y + 55); tabsForm.Tooltip.Show(caption, tabsForm, tabsForm.PointToClient(tooltipLocation), tabsForm.Tooltip.AutoPopDelay); }
/// <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) { Point cursorPosition = new Point(hookStruct.Value.pt.x, hookStruct.Value.pt.y); bool reRender = false; if (s_tornTab != null && DropAreas != null) { for (int i = 0; i < DropAreas.Length; i++) { if (DropAreas[i].Item2.Contains(cursorPosition)) // If the cursor is within the drop area, combine the tab for the window that belongs to that drop area { TitleBarTab tabToCombine = null; lock (s_tornTabLock) { if (s_tornTab != null) { tabToCombine = s_tornTab; s_tornTab = null; } } if (tabToCombine != null) { int i1 = i; Invoke(new Action(() => { DropAreas[i1].Item1.TabRenderer.CombineTab(tabToCombine, cursorPosition); tabToCombine = null; s_tornTabForm.Close(); s_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; } else // Otherwise, see if any tabs' close button is being hovered over { for (int i = 0; i < ParentForm.Tabs.Count; i++) { if (ParentForm.TabRenderer.IsOverCloseButton(ParentForm.Tabs[i], GetRelativeCursorPosition(cursorPosition))) { IsOverCLoseButtonForTab = i; reRender = true; break; } } } } else { Invoke(new Action(() => { s_wasDragging = true; Rectangle dragArea = TabDropArea; dragArea.Inflate(ParentForm.TabRenderer.TabTearDragDistance, ParentForm.TabRenderer.TabTearDragDistance); if (!dragArea.Contains(cursorPosition) && s_tornTab == null) { lock (s_tornTabLock) { if (s_tornTab == null) { ParentForm.TabRenderer.IsTabRepositioning = false; s_tornTab = ParentForm.SelectedTab; s_tornTab.ClearEventSubscriptions(); s_tornTabForm = new TornTabForm(s_tornTab, ParentForm.TabRenderer); } } if (s_tornTab != null) { ParentForm.SelectedTabIndex = ParentForm.SelectedTabIndex == ParentForm.Tabs.Count - 1 ? ParentForm.SelectedTabIndex - 1 : ParentForm.SelectedTabIndex + 1; ParentForm.Tabs.Remove(s_tornTab); if (ParentForm.Tabs.Count == 0) { ParentForm.Hide(); } s_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) { s_wasDragging = false; } else if (nCode >= 0 && (int)WM.WM_LBUTTONUP == (int)wParam) { if (s_tornTab != null) { TitleBarTab tabToRelease = null; lock (s_tornTabLock) { if (s_tornTab != null) { tabToRelease = s_tornTab; s_tornTab = null; } } if (tabToRelease != null) { Invoke(new Action(() => { TitleBarTabs newWindow = (TitleBarTabs)Activator.CreateInstance(ParentForm.GetType()); 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(); s_tornTabForm.Close(); s_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)))); } } }