private void Recalculate(bool doLayout) { if (!IsHandleCreated) { return; } Size canvas = canvas_size; Size client = ClientSize; canvas.Width += auto_scroll_margin.Width; canvas.Height += auto_scroll_margin.Height; int right_edge = client.Width; int bottom_edge = client.Height; int prev_right_edge; int prev_bottom_edge; bool hscroll_visible; bool vscroll_visible; do { prev_right_edge = right_edge; prev_bottom_edge = bottom_edge; if ((force_hscroll_visible || (canvas.Width > right_edge && auto_scroll)) && client.Width > 0) { hscroll_visible = true; bottom_edge = client.Height - SystemInformation.HorizontalScrollBarHeight; } else { hscroll_visible = false; bottom_edge = client.Height; } if ((force_vscroll_visible || (canvas.Height > bottom_edge && auto_scroll)) && client.Height > 0) { vscroll_visible = true; right_edge = client.Width - SystemInformation.VerticalScrollBarWidth; } else { vscroll_visible = false; right_edge = client.Width; } } while (right_edge != prev_right_edge || bottom_edge != prev_bottom_edge); if (right_edge < 0) { right_edge = 0; } if (bottom_edge < 0) { bottom_edge = 0; } Rectangle hscroll_bounds; Rectangle vscroll_bounds; hscroll_bounds = new Rectangle(0, client.Height - SystemInformation.HorizontalScrollBarHeight, ClientRectangle.Width, SystemInformation.HorizontalScrollBarHeight); vscroll_bounds = new Rectangle(client.Width - SystemInformation.VerticalScrollBarWidth, 0, SystemInformation.VerticalScrollBarWidth, ClientRectangle.Height); /* the ScrollWindow calls here are needed * because (this explanation sucks): * * when we transition from having a scrollbar to * not having one, we won't receive a scrollbar * moved (value changed) event, so we need to * manually scroll the canvas. * * if you can fix this without requiring the * ScrollWindow calls, pdb and toshok will each * pay you $5. */ if (!vscrollbar.Visible) { vscrollbar.Value = 0; } if (!hscrollbar.Visible) { hscrollbar.Value = 0; } /* Manually setting the size of the thumb should be done before * the other assignments */ if (hscroll_visible) { hscrollbar.manual_thumb_size = right_edge; hscrollbar.LargeChange = right_edge; hscrollbar.SmallChange = 5; hscrollbar.Maximum = canvas.Width - 1; } else { if (hscrollbar != null && hscrollbar.VisibleInternal) { ScrollWindow(-scroll_position.X, 0); } scroll_position.X = 0; } if (vscroll_visible) { vscrollbar.manual_thumb_size = bottom_edge; vscrollbar.LargeChange = bottom_edge; vscrollbar.SmallChange = 5; vscrollbar.Maximum = canvas.Height - 1; } else { if (vscrollbar != null && vscrollbar.VisibleInternal) { ScrollWindow(0, -scroll_position.Y); } scroll_position.Y = 0; } if (hscroll_visible && vscroll_visible) { hscroll_bounds.Width -= SystemInformation.VerticalScrollBarWidth; vscroll_bounds.Height -= SystemInformation.HorizontalScrollBarHeight; sizegrip.Bounds = new Rectangle(hscroll_bounds.Right, vscroll_bounds.Bottom, SystemInformation.VerticalScrollBarWidth, SystemInformation.HorizontalScrollBarHeight); } SuspendLayout(); hscrollbar.SetBoundsInternal(hscroll_bounds.X, hscroll_bounds.Y, hscroll_bounds.Width, hscroll_bounds.Height, BoundsSpecified.None); hscrollbar.Visible = hscroll_visible; if (hscrollbar.Visible) { XplatUI.SetZOrder(hscrollbar.Handle, IntPtr.Zero, true, false); } vscrollbar.SetBoundsInternal(vscroll_bounds.X, vscroll_bounds.Y, vscroll_bounds.Width, vscroll_bounds.Height, BoundsSpecified.None); vscrollbar.Visible = vscroll_visible; if (vscrollbar.Visible) { XplatUI.SetZOrder(vscrollbar.Handle, IntPtr.Zero, true, false); } UpdateSizeGripVisible(); ResumeLayout(doLayout); // We should now scroll the active control into view, // the funny part is that ScrollableControl does not have // the concept of active control. ContainerControl container = this as ContainerControl; if (container != null && container.ActiveControl != null) { ScrollControlIntoView(container.ActiveControl); } }