func (b *ProgressBar) SetSize(size math.Size) { b.ProgressBar.SetSize(size) b.chevrons = nil if size.Area() > 0 { b.chevrons = b.theme.Driver().CreateCanvas(size) b.chevronWidth = size.H / 2 cw := b.chevronWidth for x := -cw * 2; x < size.W; x += cw * 2 { // x0 x2 // | x1 | x3 // | | // A-----B - y0 // \ \ // \ \ // F C - y1 // / / // / / // E-----D - y2 y0, y1, y2 := 0, size.H/2, size.H x0, x1 := x, x+cw/2 x2, x3 := x0+cw, x1+cw var chevron = gxui.Polygon{ /* A */ gxui.PolygonVertex{Position: math.Point{X: x0, Y: y0}}, /* B */ gxui.PolygonVertex{Position: math.Point{X: x2, Y: y0}}, /* C */ gxui.PolygonVertex{Position: math.Point{X: x3, Y: y1}}, /* D */ gxui.PolygonVertex{Position: math.Point{X: x2, Y: y2}}, /* E */ gxui.PolygonVertex{Position: math.Point{X: x0, Y: y2}}, /* F */ gxui.PolygonVertex{Position: math.Point{X: x1, Y: y1}}, } b.chevrons.DrawPolygon(chevron, gxui.TransparentPen, gxui.CreateBrush(gxui.Gray30)) } b.chevrons.Complete() } }
func (v *viewport) SetSizeDips(size math.Size) { v.driver.syncDriver(func() { v.sizeDips = size v.sizeDipsUnscaled = size.ScaleS(v.scaling) v.window.SetSize(v.sizeDipsUnscaled.W, v.sizeDipsUnscaled.H) }) }
func (f *font) Measure(fl *gxui.TextBlock) math.Size { size := math.Size{W: 0, H: f.glyphMaxSizeDips.H} var offset math.Point for _, r := range fl.Runes { if r == '\n' { offset.X = 0 offset.Y += f.glyphMaxSizeDips.H continue } offset.X += f.advanceDips(r) size = size.Max(math.Size{W: offset.X, H: offset.Y + f.glyphMaxSizeDips.H}) } return size }
func createGlyphPage(resolution resolution, glyphMaxSizePixels math.Size) *glyphPage { // Handle exceptionally large glyphs. size := math.Size{W: glyphPageWidth, H: glyphPageHeight}.Max(glyphMaxSizePixels) size.W = align(size.W, glyphSizeAlignment) size.H = align(size.H, glyphSizeAlignment) return &glyphPage{ resolution: resolution, glyphMaxSizePixels: glyphMaxSizePixels, size: size, image: image.NewAlpha(image.Rect(0, 0, size.W, size.H)), offsets: make(map[rune]math.Point), rowHeight: 0, rast: raster.NewRasterizer(glyphMaxSizePixels.W, glyphMaxSizePixels.H), } }
func newGlyphPage(face fnt.Face, r rune) *glyphPage { // Start the page big enough to hold the initial rune. b, _, _ := face.GlyphBounds(r) bounds := rectangle26_6toRect(b) size := math.Size{W: glyphPageWidth, H: glyphPageHeight}.Max(bounds.Size()) size.W = align(size.W, glyphSizeAlignment) size.H = align(size.H, glyphSizeAlignment) page := &glyphPage{ image: image.NewAlpha(image.Rect(0, 0, size.W, size.H)), size: size, entries: make(map[rune]glyphEntry), rowHeight: 0, } page.add(face, r) return page }
func (l *List) DesiredSize(min, max math.Size) math.Size { if l.adapter == nil { return min } count := math.Max(l.itemCount, 1) var s math.Size if l.orientation.Horizontal() { s = math.Size{W: l.itemSize.W * count, H: l.itemSize.H} } else { s = math.Size{W: l.itemSize.W, H: l.itemSize.H * count} } if l.scrollBarEnabled { if l.orientation.Horizontal() { s.H += l.scrollBar.DesiredSize(min, max).H } else { s.W += l.scrollBar.DesiredSize(min, max).W } } return s.Expand(l.outer.Padding()).Clamp(min, max) }
func (f *font) Layout(fl *gxui.TextBlock) (offsets []math.Point) { sizeDips := math.Size{} offsets = make([]math.Point, len(fl.Runes)) var offset math.Point for i, r := range fl.Runes { if r == '\n' { offset.X = 0 offset.Y += f.glyphMaxSizeDips.H continue } offsets[i] = offset offset.X += f.advanceDips(r) sizeDips = sizeDips.Max(math.Size{W: offset.X, H: offset.Y + f.glyphMaxSizeDips.H}) } origin := f.align(fl.AlignRect, sizeDips, f.ascentDips, fl.H, fl.V) for i, p := range offsets { offsets[i] = p.Add(origin) } return offsets }
func (l *ScrollLayout) SetScrollOffset(scrollOffset math.Point) bool { var cs math.Size if l.child != nil { cs = l.child.Control.Size() } s := l.innerSize scrollOffset = scrollOffset.Min(cs.Sub(s).Point()).Max(math.Point{}) l.scrollBarX.Control.SetVisible(l.canScrollX && cs.W > s.W) l.scrollBarY.Control.SetVisible(l.canScrollY && cs.H > s.H) l.scrollBarX.Control.(gxui.ScrollBar).SetScrollPosition(l.scrollOffset.X, l.scrollOffset.X+s.W) l.scrollBarY.Control.(gxui.ScrollBar).SetScrollPosition(l.scrollOffset.Y, l.scrollOffset.Y+s.H) if l.scrollOffset != scrollOffset { l.scrollOffset = scrollOffset l.Relayout() return true } return false }
func (l *LinearLayout) DesiredSize(min, max math.Size) math.Size { if l.sizeMode.Fill() { return max } bounds := min.Rect() children := l.outer.Children() horizontal := l.direction.Orientation().Horizontal() offset := math.Point{X: 0, Y: 0} for _, c := range children { cs := c.Control.DesiredSize(math.ZeroSize, max) cm := c.Control.Margin() cb := cs.Expand(cm).Rect().Offset(offset) if horizontal { offset.X += cb.W() } else { offset.Y += cb.H() } bounds = bounds.Union(cb) } return bounds.Size().Expand(l.outer.Padding()).Clamp(min, max) }
func (a *DefaultAdapter) SetSizeAsLargest(theme Theme) { s := math.Size{} font := theme.DefaultFont() for i := 0; i < a.Count(); i++ { switch t := a.ItemAt(i).(type) { case Viewer: s = s.Max(t.View(theme).DesiredSize(math.ZeroSize, math.MaxSize)) case Stringer: s = s.Max(font.Measure(&TextBlock{ Runes: []rune(t.String()), })) default: s = s.Max(font.Measure(&TextBlock{ Runes: []rune(fmt.Sprintf("%+v", t)), })) } } a.SetSize(s) }
func (l *List) LayoutChildren() { if l.adapter == nil { l.outer.RemoveAll() return } if !l.RelayoutSuspended() { // Disable relayout on AddChild / RemoveChild as we're performing layout here. l.SetRelayoutSuspended(true) defer l.SetRelayoutSuspended(false) } s := l.outer.Size().Contract(l.Padding()) o := l.Padding().LT() var itemSize math.Size if l.orientation.Horizontal() { itemSize = math.Size{W: l.itemSize.W, H: s.H} } else { itemSize = math.Size{W: s.W, H: l.itemSize.H} } startIndex, endIndex := l.VisibleItemRange(true) majorAxisItemSize := l.MajorAxisItemSize() d := startIndex*majorAxisItemSize - l.scrollOffset mark := l.layoutMark l.layoutMark++ for idx := startIndex; idx < endIndex; idx++ { item := l.adapter.ItemAt(idx) details, found := l.details[item] if found { if details.mark == mark { panic(fmt.Errorf("Adapter for control '%s' returned duplicate item (%v) for indices %v and %v", gxui.Path(l.outer), item, details.index, idx)) } } else { control := l.adapter.Create(l.theme, idx) details.onClickSubscription = control.OnClick(func(ev gxui.MouseEvent) { l.ItemClicked(ev, item) }) details.child = l.AddChildAt(0, control) } details.mark = mark details.index = idx l.details[item] = details c := details.child cm := c.Control.Margin() cs := itemSize.Contract(cm).Max(math.ZeroSize) if l.orientation.Horizontal() { c.Layout(math.CreateRect(d, cm.T, d+cs.W, cm.T+cs.H).Offset(o)) } else { c.Layout(math.CreateRect(cm.L, d, cm.L+cs.W, d+cs.H).Offset(o)) } d += majorAxisItemSize } // Reap unused items for item, details := range l.details { if details.mark != mark { details.onClickSubscription.Unlisten() l.RemoveChild(details.child.Control) delete(l.details, item) } } if l.scrollBarEnabled { ss := l.scrollBar.DesiredSize(math.ZeroSize, s) if l.Orientation().Horizontal() { l.scrollBarChild.Layout(math.CreateRect(0, s.H-ss.H, s.W, s.H).Canon().Offset(o)) } else { l.scrollBarChild.Layout(math.CreateRect(s.W-ss.W, 0, s.W, s.H).Canon().Offset(o)) } // Only show the scroll bar if needed entireContentVisible := startIndex == 0 && endIndex == l.itemCount l.scrollBar.SetVisible(!entireContentVisible) } l.UpdateItemMouseOver() }