func ChildToParent(coord math.Point, from Control, to Parent) math.Point { c := from for { p := c.Parent() if p == nil { panic(fmt.Errorf("Control detached: %s", Path(c))) } child := p.Children().Find(c) if child == nil { Dump(p) panic(fmt.Errorf("Control's parent (%p %T) did not contain control (%p %T).", &p, p, &c, c)) } coord = coord.Add(child.Offset) if p == to { return coord } if control, ok := p.(Control); ok { c = control } else { Dump(p) panic(fmt.Errorf("ChildToParent (%p %T) -> (%p %T) reached non-control parent (%p %T).", &from, from, &to, to, &p, p)) } } }
func (l *CodeEditorLine) PaintEditorSelections(c gxui.Canvas, info CodeEditorLinePaintInfo) { controller := l.textbox.controller ls, le := uint64(controller.LineStart(l.lineIndex)), uint64(controller.LineEnd(l.lineIndex)) selections := controller.Selections() if l.textbox.selectionDragging { interval.Replace(&selections, l.textbox.selectionDrag) } interval.Visit(&selections, gxui.CreateTextSelection(int(ls), int(le), false), func(s, e uint64, _ int) { if s < e { var startOffset math.Point if s > ls { startOffset = l.endOfChar(info.GlyphOffsets[s-ls-1]) } var endOffset math.Point if e > ls { endOffset = l.endOfChar(info.GlyphOffsets[e-ls-1]) } width := endOffset.X - startOffset.X m := l.outer.MeasureRunes(int(s), int(e)) m.W = width top := math.Point{X: l.caretWidth + startOffset.X, Y: 0} bottom := top.Add(m.Point()) l.outer.PaintSelection(c, top, bottom) } }) }
func (i *Image) PixelAt(p math.Point) (math.Point, bool) { ir := i.calculateDrawRect() if tex := i.Texture(); tex != nil { s := tex.SizePixels() p = p.Sub(ir.Min). ScaleX(float32(s.W) / float32(ir.W())). ScaleY(float32(s.H) / float32(ir.H())) if s.Rect().Contains(p) { return p, true } } return math.Point{X: -1, Y: -1}, false }
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 (c *Container) ContainsPoint(p math.Point) bool { if !c.outer.IsVisible() || !c.outer.Size().Rect().Contains(p) { return false } for _, v := range c.children { if v.Control.ContainsPoint(p.Sub(v.Offset)) { return true } } if c.IsMouseEventTarget() { return true } return false }
func (t *DefaultTextBoxLine) PaintCarets(c gxui.Canvas) { controller := t.textbox.controller for i, cnt := 0, controller.SelectionCount(); i < cnt; i++ { e := controller.Caret(i) l := controller.LineIndex(e) if l == t.lineIndex { s := controller.LineStart(l) m := t.outer.MeasureRunes(s, e) top := math.Point{X: t.caretWidth + m.W, Y: 0} bottom := top.Add(math.Point{X: 0, Y: t.Size().H}) t.outer.PaintCaret(c, top, bottom) } } }
func TopControlsUnder(p math.Point, c Parent) ControlPointList { children := c.Children() for i := len(children) - 1; i >= 0; i-- { child := children[i] cp := p.Sub(child.Offset) if child.Control.ContainsPoint(cp) { l := ControlPointList{ControlPoint{child.Control, cp}} if cc, ok := child.Control.(Parent); ok { l = append(l, TopControlsUnder(cp, cc)...) } return l } } return ControlPointList{} }
func BreadcrumbsAt(p Container, pnt math.Point) string { s := reflect.TypeOf(p).String() for _, c := range p.Children() { b := c.Control.Size().Rect().Offset(c.Offset) if b.Contains(pnt) { switch t := c.Control.(type) { case Container: return s + " > " + BreadcrumbsAt(t, pnt.Sub(c.Offset)) default: return s + " > " + reflect.TypeOf(c.Control).String() } } } return s }
func (l *CodeEditorLine) PaintEditorCarets(c gxui.Canvas, info CodeEditorLinePaintInfo) { controller := l.textbox.controller for i, count := 0, controller.SelectionCount(); i < count; i++ { caret := controller.Caret(i) line := controller.LineIndex(caret) if line == l.lineIndex { var offset math.Point start := controller.LineStart(line) if len(info.GlyphOffsets) > 0 && caret > start { caretOffsetIndex := caret - start - 1 offset = l.endOfChar(info.GlyphOffsets[caretOffsetIndex]) } top := math.Point{X: l.caretWidth + offset.X, Y: 0} bottom := top.Add(math.Point{X: 0, Y: l.Size().H}) l.outer.PaintCaret(c, top, bottom) } } }
func ControlsUnder(p math.Point, c Parent) ControlPointList { toVisit := []ParentPoint{ParentPoint{c, p}} l := ControlPointList{} for len(toVisit) > 0 { c = toVisit[0].C p = toVisit[0].P toVisit = toVisit[1:] for _, child := range c.Children() { cp := p.Sub(child.Offset) if child.Control.ContainsPoint(cp) { l = append(l, ControlPoint{child.Control, cp}) if cc, ok := child.Control.(Parent); ok { toVisit = append(toVisit, ParentPoint{cc, cp}) } } } } return l }
func WindowToChild(coord math.Point, to Control) math.Point { c := to for { p := c.Parent() if p == nil { panic("Control's parent was nil") } child := p.Children().Find(c) if child == nil { Dump(p) panic(fmt.Errorf("Control's parent (%p %T) did not contain control (%p %T).", &p, p, &c, c)) } coord = coord.Sub(child.Offset) if _, ok := p.(Window); ok { return coord } c = p.(Control) } }
func (t *DefaultTextBoxLine) PaintSelections(c gxui.Canvas) { controller := t.textbox.controller ls, le := controller.LineStart(t.lineIndex), controller.LineEnd(t.lineIndex) selections := controller.Selections() if t.textbox.selectionDragging { interval.Replace(&selections, t.textbox.selectionDrag) } interval.Visit(&selections, gxui.CreateTextSelection(ls, le, false), func(s, e uint64, _ int) { if s < e { x := t.outer.MeasureRunes(ls, int(s)).W m := t.outer.MeasureRunes(int(s), int(e)) top := math.Point{X: t.caretWidth + x, Y: 0} bottom := top.Add(m.Point()) t.outer.PaintSelection(c, top, bottom) } }) }
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 (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 *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 (f *font) align(rect math.Rect, size math.Size, ascent int, h gxui.HorizontalAlignment, v gxui.VerticalAlignment) math.Point { var origin math.Point switch h { case gxui.AlignLeft: origin.X = rect.Min.X case gxui.AlignCenter: origin.X = rect.Mid().X - (size.W / 2) case gxui.AlignRight: origin.X = rect.Max.X - size.W } switch v { case gxui.AlignTop: origin.Y = rect.Min.Y + ascent case gxui.AlignMiddle: origin.Y = rect.Mid().Y - (size.H / 2) + ascent case gxui.AlignBottom: origin.Y = rect.Max.Y - size.H + ascent } return origin }
func ParentToChild(coord math.Point, from Parent, to Control) math.Point { return coord.Sub(ChildToParent(math.ZeroPoint, to, from)) }
// endOfChar takes a position of a character and returns the position // of its end. func (l *CodeEditorLine) endOfChar(position math.Point) math.Point { return position.AddX(l.ce.Font().GlyphMaxSize().W / 2) }
func (s *ScrollBar) positionAt(p math.Point) int { o := s.orientation frac := float32(o.Major(p.XY())) / float32(o.Major(s.Size().WH())) max := s.ScrollLimit() return int(float32(max) * frac) }