diff --git a/scrollbar.go b/scrollbar.go index 76a5960..1ccdf6b 100644 --- a/scrollbar.go +++ b/scrollbar.go @@ -43,6 +43,7 @@ func newScrollbar (orient string) *Scrollbar { this.OnMouseDown(this.handleMouseDown) this.OnMouseUp(this.handleMouseUp) this.OnMouseMove(this.handleMouseMove) + this.OnScroll(this.handleScroll) theme.Apply(this.handle, theme.R("objects", "SliderHandle", orient)) theme.Apply(this, theme.R("objects", "Slider", orient)) return this @@ -65,10 +66,13 @@ func (this *Scrollbar) Link (box tomo.ContentBox) event.Cookie { } func (this *Scrollbar) handleLinkedContentBoundsChange () { - if this.layout.linked == 0 { return } - this.layout.value = - this.layout.contentPos() / - (this.layout.contentLength() - this.layout.viewportLength()) + if this.layout.linked == nil { return } + trackLength := this.layout.contentLength() - this.layout.viewportLength() + if trackLength == 0 { + this.layout.value = 0 + } else { + this.layout.value = this.layout.contentPos() / trackLength + } this.SetLayout(this.layout) } @@ -171,6 +175,13 @@ func (this *Scrollbar) handleMouseMove () { this.drag() } +func (this *Scrollbar) handleScroll (x, y float64) { + if this.layout.linked == nil { return } + this.layout.linked.ScrollTo ( + this.layout.linked.ContentBounds().Min. + Add(image.Pt(int(x), int(y)))) +} + func (this *Scrollbar) drag () { pointer := this.MousePosition().Sub(this.dragOffset) gutter := this.InnerBounds() @@ -234,18 +245,44 @@ func (this scrollbarLayout) Arrange (hints tomo.LayoutHints, boxes []tomo.Box) { handle := image.Rectangle { Max: boxes[0].MinimumSize() } gutter := hints.Bounds + var gutterLength float64; + var handleMin float64; + if this.vertical { + gutterLength = float64(gutter.Dy()) + handleMin = float64(handle.Dy()) + } else { + gutterLength = float64(gutter.Dx()) + handleMin = float64(handle.Dx()) + } - // TODO - // - apply (viewportContentRatio) to length of gutter - // - constrain to minimum length of handle - // - set handle to constrained length - // - apply (value) to length of gutter minus length of handle - // - that is the handle position + // calculate handle length + handleLength := gutterLength * this.viewportContentRatio() + if handleLength < handleMin { handleLength = handleMin } + if handleLength > gutterLength { handleLength = gutterLength } + if this.vertical { + handle.Max.Y = int(handleLength) + } else { + handle.Max.X = int(handleLength) + } + + // calculate handle position + handlePosition := (gutterLength - handleLength) * this.value + var handleOffset image.Point + if this.vertical { + handleOffset = image.Pt(0, int(handlePosition)) + } else { + handleOffset = image.Pt(int(handlePosition), 0) + } + handle = handle.Add(handleOffset).Add(gutter.Min) + + // place handle + boxes[0].SetBounds(handle) + } func (this scrollbarLayout) viewportContentRatio () float64 { if this.linked == nil { return 0 } - return this.viewportLength / this.contentLength + return this.viewportLength() / this.contentLength() } func (this scrollbarLayout) viewportLength () float64 {