re-implement MultiHyperlink with manual layout for now
This commit is contained in:
@@ -2,6 +2,8 @@ package widgets
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/theme"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -11,7 +13,14 @@ type MultiHyperlink struct {
|
|||||||
Segments []MultiHyperlinkSegment
|
Segments []MultiHyperlinkSegment
|
||||||
OnTapped func(string)
|
OnTapped func(string)
|
||||||
|
|
||||||
provider *widget.RichText
|
minSegWidthCached float32
|
||||||
|
minHeightCached float32
|
||||||
|
separatorWCached float32
|
||||||
|
|
||||||
|
// TODO: Once https://github.com/fyne-io/fyne/issues/4336 is resolved,
|
||||||
|
// we can switch to the much cleaner RichText implementation
|
||||||
|
//provider *widget.RichText
|
||||||
|
content *fyne.Container
|
||||||
}
|
}
|
||||||
|
|
||||||
type MultiHyperlinkSegment struct {
|
type MultiHyperlinkSegment struct {
|
||||||
@@ -21,13 +30,119 @@ type MultiHyperlinkSegment struct {
|
|||||||
|
|
||||||
func NewMultiHyperlink() *MultiHyperlink {
|
func NewMultiHyperlink() *MultiHyperlink {
|
||||||
c := &MultiHyperlink{
|
c := &MultiHyperlink{
|
||||||
provider: widget.NewRichText(),
|
//provider: widget.NewRichText(),
|
||||||
|
content: container.NewWithoutLayout(),
|
||||||
}
|
}
|
||||||
c.ExtendBaseWidget(c)
|
c.ExtendBaseWidget(c)
|
||||||
c.provider.Wrapping = fyne.TextTruncate
|
//c.provider.Wrapping = fyne.TextTruncate
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *MultiHyperlink) getMinSegWidth() float32 {
|
||||||
|
if c.minSegWidthCached == 0 {
|
||||||
|
c.minSegWidthCached = fyne.MeasureText(", W", theme.TextSize(), fyne.TextStyle{}).Width
|
||||||
|
}
|
||||||
|
return c.minSegWidthCached
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MultiHyperlink) getSeparatorWidth() float32 {
|
||||||
|
if c.separatorWCached == 0 {
|
||||||
|
c.separatorWCached = fyne.MeasureText(",", theme.TextSize(), fyne.TextStyle{}).Width
|
||||||
|
}
|
||||||
|
return c.separatorWCached
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MultiHyperlink) layoutObjects() {
|
||||||
|
if len(c.Segments) == 0 {
|
||||||
|
c.content.RemoveAll()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
x := float32(0)
|
||||||
|
width := c.Size().Width
|
||||||
|
l := len(c.content.Objects)
|
||||||
|
|
||||||
|
var i int // at end of loop should be index of last seg that was laid out for display
|
||||||
|
var seg MultiHyperlinkSegment
|
||||||
|
for i, seg = range c.Segments {
|
||||||
|
if i > 0 {
|
||||||
|
// check if we have enough room to show another segment
|
||||||
|
if x+c.getMinSegWidth() > width {
|
||||||
|
i -= 1 // we are not showing this segment
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appendingSegments := 2*i >= l
|
||||||
|
var obj fyne.CanvasObject
|
||||||
|
if !appendingSegments {
|
||||||
|
obj = c.content.Objects[2*i]
|
||||||
|
} else if i > 0 {
|
||||||
|
c.content.Objects = append(c.content.Objects, c.newSeparatorLabel())
|
||||||
|
}
|
||||||
|
if seg.LinkID == "" {
|
||||||
|
obj = c.updateOrReplaceLabel(obj, seg.Text)
|
||||||
|
} else {
|
||||||
|
obj = c.updateOrReplaceHyperlink(obj, seg.Text)
|
||||||
|
}
|
||||||
|
if appendingSegments {
|
||||||
|
c.content.Objects = append(c.content.Objects, obj)
|
||||||
|
} else {
|
||||||
|
c.content.Objects[2*i] = obj
|
||||||
|
}
|
||||||
|
|
||||||
|
if i > 0 {
|
||||||
|
// move and resize separator
|
||||||
|
obj = c.content.Objects[2*i-1]
|
||||||
|
ms := obj.MinSize()
|
||||||
|
obj.Resize(ms)
|
||||||
|
obj.Move(fyne.NewPos(x-ms.Width+c.getSeparatorWidth()+1, 0)) // this is really ugly
|
||||||
|
x -= theme.Padding() * 2
|
||||||
|
}
|
||||||
|
// move and resize text object
|
||||||
|
textW := fyne.MeasureText(seg.Text, theme.TextSize(), fyne.TextStyle{}).Width + theme.Padding()*2 + theme.InnerPadding()
|
||||||
|
obj = c.content.Objects[2*i]
|
||||||
|
ms := obj.MinSize()
|
||||||
|
w := fyne.Min(width-x, textW)
|
||||||
|
obj.Resize(fyne.NewSize(w, ms.Height))
|
||||||
|
obj.Move(fyne.NewPos(x, 0))
|
||||||
|
x += w
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
c.content.Objects = c.content.Objects[:2*i-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MultiHyperlink) updateOrReplaceLabel(obj fyne.CanvasObject, text string) fyne.CanvasObject {
|
||||||
|
if obj != nil {
|
||||||
|
if label, ok := obj.(*widget.Label); ok {
|
||||||
|
label.Text = text
|
||||||
|
return label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l := widget.NewLabel(text)
|
||||||
|
l.Wrapping = fyne.TextTruncate
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MultiHyperlink) updateOrReplaceHyperlink(obj fyne.CanvasObject, text string) fyne.CanvasObject {
|
||||||
|
if obj != nil {
|
||||||
|
if link, ok := obj.(*widget.Hyperlink); ok {
|
||||||
|
link.Text = text
|
||||||
|
return link
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l := widget.NewHyperlink(text, nil)
|
||||||
|
l.Wrapping = fyne.TextTruncate
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MultiHyperlink) newSeparatorLabel() *widget.Label {
|
||||||
|
return widget.NewLabel(", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* RichText implementation
|
||||||
|
|
||||||
func (c *MultiHyperlink) syncSegments() {
|
func (c *MultiHyperlink) syncSegments() {
|
||||||
l := len(c.provider.Segments)
|
l := len(c.provider.Segments)
|
||||||
for i, seg := range c.Segments {
|
for i, seg := range c.Segments {
|
||||||
@@ -82,15 +197,26 @@ func (c *MultiHyperlink) updateOrReplaceHyperlinkSegment(seg widget.RichTextSegm
|
|||||||
return &widget.HyperlinkSegment{Text: text} // TODO: OnTapped
|
return &widget.HyperlinkSegment{Text: text} // TODO: OnTapped
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
func (c *MultiHyperlink) onSegmentTapped(linkID string) {
|
func (c *MultiHyperlink) onSegmentTapped(linkID string) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *MultiHyperlink) MinSize() fyne.Size {
|
||||||
|
if c.minHeightCached == 0 {
|
||||||
|
c.minHeightCached = widget.NewLabel("").MinSize().Height
|
||||||
|
}
|
||||||
|
return fyne.NewSize(1, c.minHeightCached)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *MultiHyperlink) Refresh() {
|
func (c *MultiHyperlink) Refresh() {
|
||||||
c.syncSegments()
|
//c.syncSegments()
|
||||||
|
c.layoutObjects()
|
||||||
c.BaseWidget.Refresh()
|
c.BaseWidget.Refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MultiHyperlink) CreateRenderer() fyne.WidgetRenderer {
|
func (c *MultiHyperlink) CreateRenderer() fyne.WidgetRenderer {
|
||||||
return widget.NewSimpleRenderer(c.provider)
|
return widget.NewSimpleRenderer(c.content)
|
||||||
|
//return widget.NewSimpleRenderer(c.provider)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user