internal void DrawScroller(Graphics g) { if ((leftRightImages == null) || (leftRightImages.Images.Count != 4)) return; Rectangle clientArea = this.ClientRectangle; Win32.RECT r0 = new Win32.RECT(); Win32.GetClientRect(scroller.Handle, ref r0); // Fill background of the scroller. Decrease width and height by 1 to // account for right and bottom borders which should not be used in drawing. r0.Right--; r0.Bottom--; Rectangle scrollerRect = new Rectangle(r0.Location, r0.Size); using (Brush br = new SolidBrush(SystemColors.Control)) g.FillRectangle(br, scrollerRect); // Make a small outer border. using (Pen border = new Pen(SystemColors.ControlDark)) { Rectangle rborder = scrollerRect; rborder.Inflate(-1, -1); g.DrawRectangle(border, rborder); } int nMiddle = (r0.Width / 2); int nTop = (r0.Height - leftRightImages.ImageSize.Height) / 2 + 1; int nLeft = (nMiddle - leftRightImages.ImageSize.Width) / 2; Rectangle r1 = new Rectangle(new Point(nLeft, nTop), leftRightImages.ImageSize); Rectangle r2 = new Rectangle(new Point(nMiddle + nLeft, nTop), leftRightImages.ImageSize); // Finally draw the buttons. Image img = leftRightImages.Images[1]; if (img != null) { if (TabCount > 0) { Rectangle r3 = this.GetTabRect(0); if (r3.Left < clientArea.Left) g.DrawImage(img, r1); else { img = leftRightImages.Images[3]; if (img != null) g.DrawImage(img, r1); } } } img = leftRightImages.Images[0]; if (img != null) { if (this.TabCount > 0) { Rectangle r3 = this.GetTabRect(this.TabCount - 1); if (r3.Right > (clientArea.Width - r0.Width)) g.DrawImage(img, r2); else { img = leftRightImages.Images[2]; if (img != null) g.DrawImage(img, r2); } } } }
/// <summary> /// Adjusts the scroll offset so that the given tab is in the visible area. /// </summary> /// <param name="index">The index of the tab to make visible.</param> /// <returns>True if an adjustment was necessary, otherwise False.</returns> public bool ScrollIntoView(int index) { bool result = false; if (index < 0 || index >= TabCount) return result; // If our bounds are empty then the application is likely minimized and we delay setting // the horizontal offset until we are restored. if (Width == 0 && Height == 0) { pendingScrollIntoViewIndex = index; return result; } Rectangle area = GetTabRect(index); if (area.Left < 0) { scrollOffset -= area.Left; result = true; } else { Win32.RECT rect = new Win32.RECT(); if (scroller != null) Win32.GetClientRect(scroller.Handle, ref rect); int rightBorder = ClientSize.Width - Margin.Right - rect.Width - scrollerSpacing; if (area.Right > rightBorder) { scrollOffset -= area.Right - rightBorder; result = true; } } if (result && scroller != null) Win32.SendMessage(scroller.Handle, (int)UDM.SETPOS32, IntPtr.Zero, new IntPtr(-scrollOffset / scrollScaleFactor)); return result; }
private int ScrollerWndProc(ref Message m) { switch ((WM) m.Msg) { case WM.ERASEBKGND: m.Result = new IntPtr(1); break; case WM.PAINT: { IntPtr hDC = Win32.GetDC(m.HWnd); Graphics g = Graphics.FromHdc(hDC); DrawScroller(g); g.Dispose(); Win32.ReleaseDC(m.HWnd, hDC); Win32.RECT clientArea = new Win32.RECT(); Win32.GetClientRect(m.HWnd, ref clientArea); Win32.ValidateRect(m.HWnd, ref clientArea); // return 0 (processed) m.Result = IntPtr.Zero; } return 1; case (WM) UDM.SETRANGE: // The systab control sends this message when it wants to update the scroller, however // that works diametrically opposed to our own intents, so it is simply switched off here. // Our implementation uses UDM_SETRANGE32. m.Result = new IntPtr(1); return 1; } return 0; }
private void UpdateScroller() { // Seems the scroll is sometimes re-created, so also check for a 0 handle. if (scroller == null || scroller.Handle == IntPtr.Zero) FindScroller(); if (scroller != null) { if (tabStyle == TabStyleType.NoTabs) { scrollOffset = 0; Win32.ShowWindow(scroller.Handle, (int)SW.HIDE); return; } Win32.RECT rect = new Win32.RECT(); Win32.GetClientRect(scroller.Handle, ref rect); int totalTabWidth = GetTotalTabWidth(); int availableWidth = ClientSize.Width - Margin.Horizontal; if (totalTabWidth > availableWidth) { // Decrease available space also by that used of the scroller now. availableWidth -= rect.Width; Win32.ShowWindow(scroller.Handle, (int)SW.SHOWNOACTIVATE); // The scroll range is the number of steps (scaled pixels) we need to scroll over the full tab space. int scrollRange = (int) Math.Ceiling((totalTabWidth - availableWidth) / (float) scrollScaleFactor) + (int) ((scrollerSpacing / (float) scrollScaleFactor)); Win32.SendMessage(scroller.Handle, (int) UDM.SETRANGE32, IntPtr.Zero, new IntPtr(scrollRange)); // Make sure the scroll position is still ok before setting it in the scroller. // Always scroll so that the right border stays close to the scroller. Rectangle bounds = GetTabRect(TabCount - 1); if (bounds.Right < ClientSize.Width - Margin.Right - scrollerSpacing - rect.Width) scrollOffset += ClientSize.Width - Margin.Right - scrollerSpacing - rect.Width - bounds.Right; Win32.SendMessage(scroller.Handle, (int)UDM.SETPOS32, IntPtr.Zero, new IntPtr(-scrollOffset / scrollScaleFactor)); // Disable scroll acceleration by setting a single scroll increment. Win32.UDACCEL acceleration = new Win32.UDACCEL(); acceleration.nInc = 5; acceleration.nSec = 0; IntPtr parameter = Marshal.AllocHGlobal(Marshal.SizeOf(acceleration)); Marshal.StructureToPtr(acceleration, parameter, true); Win32.SendMessage(scroller.Handle, (int)UDM.SETACCEL, new IntPtr(1), parameter); Marshal.FreeHGlobal(parameter); } else { scrollOffset = 0; Win32.ShowWindow(scroller.Handle, (int)SW.HIDE); } Win32.InvalidateRect(scroller.Handle, ref rect, true); int scrollerWidth = rect.Width; rect.Left = Width - scrollerWidth - Margin.Right; rect.Right = rect.Left + scrollerWidth; if (tabStyle == TabStyleType.BottomNormal) rect.Top = ClientSize.Height - ItemSize.Height - Margin.Bottom; else rect.Top = Margin.Top; rect.Bottom = rect.Top + ItemSize.Height; Win32.MoveWindow(scroller.Handle, rect.Left, rect.Top, rect.Width, rect.Height, true); } }
protected override void OnSelectedIndexChanged(EventArgs e) { base.OnSelectedIndexChanged(e); ScrollIntoView(SelectedIndex); if (scroller != null) { Win32.RECT clientArea = new Win32.RECT(); Win32.GetClientRect(scroller.Handle, ref clientArea); Win32.InvalidateRect(scroller.Handle, ref clientArea, false); } Invalidate(); // We need to update border and background colors. }