mirror of
https://github.com/AynaLivePlayer/AynaLivePlayer.git
synced 2025-12-11 12:48:12 +08:00
Initial commit
This commit is contained in:
85
app/fyne_demo/tutorials/advanced.go
Normal file
85
app/fyne_demo/tutorials/advanced.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package tutorials
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/driver/desktop"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
func scaleString(c fyne.Canvas) string {
|
||||
return strconv.FormatFloat(float64(c.Scale()), 'f', 2, 32)
|
||||
}
|
||||
|
||||
func texScaleString(c fyne.Canvas) string {
|
||||
pixels, _ := c.PixelCoordinateForPosition(fyne.NewPos(1, 1))
|
||||
texScale := float32(pixels) / c.Scale()
|
||||
return strconv.FormatFloat(float64(texScale), 'f', 2, 32)
|
||||
}
|
||||
|
||||
func prependTo(g *fyne.Container, s string) {
|
||||
g.Objects = append([]fyne.CanvasObject{widget.NewLabel(s)}, g.Objects...)
|
||||
g.Refresh()
|
||||
}
|
||||
|
||||
func setScaleText(scale, tex *widget.Label, win fyne.Window) {
|
||||
for scale.Visible() {
|
||||
scale.SetText(scaleString(win.Canvas()))
|
||||
tex.SetText(texScaleString(win.Canvas()))
|
||||
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
// advancedScreen loads a panel that shows details and settings that are a bit
|
||||
// more detailed than normally needed.
|
||||
func advancedScreen(win fyne.Window) fyne.CanvasObject {
|
||||
scale := widget.NewLabel("")
|
||||
tex := widget.NewLabel("")
|
||||
|
||||
screen := widget.NewCard("Screen info", "", widget.NewForm(
|
||||
&widget.FormItem{Text: "Scale", Widget: scale},
|
||||
&widget.FormItem{Text: "Texture Scale", Widget: tex},
|
||||
))
|
||||
|
||||
go setScaleText(scale, tex, win)
|
||||
|
||||
label := widget.NewLabel("Just type...")
|
||||
generic := container.NewVBox()
|
||||
desk := container.NewVBox()
|
||||
|
||||
genericCard := widget.NewCard("", "Generic", container.NewVScroll(generic))
|
||||
deskCard := widget.NewCard("", "Desktop", container.NewVScroll(desk))
|
||||
|
||||
win.Canvas().SetOnTypedRune(func(r rune) {
|
||||
prependTo(generic, "Rune: "+string(r))
|
||||
})
|
||||
win.Canvas().SetOnTypedKey(func(ev *fyne.KeyEvent) {
|
||||
prependTo(generic, "Key : "+string(ev.Name))
|
||||
})
|
||||
if deskCanvas, ok := win.Canvas().(desktop.Canvas); ok {
|
||||
deskCanvas.SetOnKeyDown(func(ev *fyne.KeyEvent) {
|
||||
prependTo(desk, "KeyDown: "+string(ev.Name))
|
||||
})
|
||||
deskCanvas.SetOnKeyUp(func(ev *fyne.KeyEvent) {
|
||||
prependTo(desk, "KeyUp : "+string(ev.Name))
|
||||
})
|
||||
}
|
||||
|
||||
return container.NewHBox(
|
||||
container.NewVBox(screen,
|
||||
widget.NewButton("Custom Theme", func() {
|
||||
fyne.CurrentApp().Settings().SetTheme(newCustomTheme())
|
||||
}),
|
||||
widget.NewButton("Fullscreen", func() {
|
||||
win.SetFullScreen(!win.FullScreen())
|
||||
}),
|
||||
),
|
||||
container.NewBorder(label, nil, nil, nil,
|
||||
container.NewGridWithColumns(2, genericCard, deskCard),
|
||||
),
|
||||
)
|
||||
}
|
||||
143
app/fyne_demo/tutorials/animation.go
Normal file
143
app/fyne_demo/tutorials/animation.go
Normal file
@@ -0,0 +1,143 @@
|
||||
package tutorials
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"time"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/canvas"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
func makeAnimationScreen(_ fyne.Window) fyne.CanvasObject {
|
||||
curves := makeAnimationCurves()
|
||||
curves.Move(fyne.NewPos(0, 140+theme.Padding()))
|
||||
return fyne.NewContainerWithoutLayout(makeAnimationCanvas(), curves)
|
||||
}
|
||||
|
||||
func makeAnimationCanvas() fyne.CanvasObject {
|
||||
rect := canvas.NewRectangle(color.Black)
|
||||
rect.Resize(fyne.NewSize(410, 140))
|
||||
|
||||
a := canvas.NewColorRGBAAnimation(theme.PrimaryColorNamed(theme.ColorBlue), theme.PrimaryColorNamed(theme.ColorGreen),
|
||||
time.Second*3, func(c color.Color) {
|
||||
rect.FillColor = c
|
||||
canvas.Refresh(rect)
|
||||
})
|
||||
a.RepeatCount = fyne.AnimationRepeatForever
|
||||
a.AutoReverse = true
|
||||
a.Start()
|
||||
|
||||
var a2 *fyne.Animation
|
||||
i := widget.NewIcon(theme.CheckButtonCheckedIcon())
|
||||
a2 = canvas.NewPositionAnimation(fyne.NewPos(0, 0), fyne.NewPos(350, 80), time.Second*3, func(p fyne.Position) {
|
||||
i.Move(p)
|
||||
|
||||
width := 10 + (p.X / 7)
|
||||
i.Resize(fyne.NewSize(width, width))
|
||||
})
|
||||
a2.RepeatCount = fyne.AnimationRepeatForever
|
||||
a2.AutoReverse = true
|
||||
a2.Curve = fyne.AnimationLinear
|
||||
a2.Start()
|
||||
|
||||
running := true
|
||||
var toggle *widget.Button
|
||||
toggle = widget.NewButton("Stop", func() {
|
||||
if running {
|
||||
a.Stop()
|
||||
a2.Stop()
|
||||
toggle.SetText("Start")
|
||||
} else {
|
||||
a.Start()
|
||||
a2.Start()
|
||||
toggle.SetText("Stop")
|
||||
}
|
||||
running = !running
|
||||
})
|
||||
toggle.Resize(toggle.MinSize())
|
||||
toggle.Move(fyne.NewPos(152, 54))
|
||||
return fyne.NewContainerWithoutLayout(rect, i, toggle)
|
||||
}
|
||||
|
||||
func makeAnimationCurves() fyne.CanvasObject {
|
||||
label1, box1, a1 := makeAnimationCurveItem("EaseInOut", fyne.AnimationEaseInOut, 0)
|
||||
label2, box2, a2 := makeAnimationCurveItem("EaseIn", fyne.AnimationEaseIn, 30+theme.Padding())
|
||||
label3, box3, a3 := makeAnimationCurveItem("EaseOut", fyne.AnimationEaseOut, 60+theme.Padding()*2)
|
||||
label4, box4, a4 := makeAnimationCurveItem("Linear", fyne.AnimationLinear, 90+theme.Padding()*3)
|
||||
|
||||
start := widget.NewButton("Compare", func() {
|
||||
a1.Start()
|
||||
a2.Start()
|
||||
a3.Start()
|
||||
a4.Start()
|
||||
})
|
||||
start.Resize(start.MinSize())
|
||||
start.Move(fyne.NewPos(0, 120+theme.Padding()*4))
|
||||
return fyne.NewContainerWithoutLayout(label1, label2, label3, label4, box1, box2, box3, box4, start)
|
||||
}
|
||||
|
||||
func makeAnimationCurveItem(label string, curve fyne.AnimationCurve, yOff float32) (
|
||||
text *widget.Label, box fyne.CanvasObject, anim *fyne.Animation) {
|
||||
text = widget.NewLabel(label)
|
||||
text.Alignment = fyne.TextAlignCenter
|
||||
text.Resize(fyne.NewSize(380, 30))
|
||||
text.Move(fyne.NewPos(0, yOff))
|
||||
box = newThemedBox()
|
||||
box.Resize(fyne.NewSize(30, 30))
|
||||
box.Move(fyne.NewPos(0, yOff))
|
||||
|
||||
anim = canvas.NewPositionAnimation(
|
||||
fyne.NewPos(0, yOff), fyne.NewPos(380, yOff), time.Second, func(p fyne.Position) {
|
||||
box.Move(p)
|
||||
box.Refresh()
|
||||
})
|
||||
anim.Curve = curve
|
||||
anim.AutoReverse = true
|
||||
anim.RepeatCount = 1
|
||||
return
|
||||
}
|
||||
|
||||
// themedBox is a simple box that change its background color according
|
||||
// to the selected theme
|
||||
type themedBox struct {
|
||||
widget.BaseWidget
|
||||
}
|
||||
|
||||
func newThemedBox() *themedBox {
|
||||
b := &themedBox{}
|
||||
b.ExtendBaseWidget(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *themedBox) CreateRenderer() fyne.WidgetRenderer {
|
||||
b.ExtendBaseWidget(b)
|
||||
bg := canvas.NewRectangle(theme.ForegroundColor())
|
||||
return &themedBoxRenderer{bg: bg, objects: []fyne.CanvasObject{bg}}
|
||||
}
|
||||
|
||||
type themedBoxRenderer struct {
|
||||
bg *canvas.Rectangle
|
||||
objects []fyne.CanvasObject
|
||||
}
|
||||
|
||||
func (r *themedBoxRenderer) Destroy() {
|
||||
}
|
||||
|
||||
func (r *themedBoxRenderer) Layout(size fyne.Size) {
|
||||
r.bg.Resize(size)
|
||||
}
|
||||
|
||||
func (r *themedBoxRenderer) MinSize() fyne.Size {
|
||||
return r.bg.MinSize()
|
||||
}
|
||||
|
||||
func (r *themedBoxRenderer) Objects() []fyne.CanvasObject {
|
||||
return r.objects
|
||||
}
|
||||
|
||||
func (r *themedBoxRenderer) Refresh() {
|
||||
r.bg.FillColor = theme.ForegroundColor()
|
||||
r.bg.Refresh()
|
||||
}
|
||||
111
app/fyne_demo/tutorials/bind.go
Normal file
111
app/fyne_demo/tutorials/bind.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package tutorials
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/data/binding"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
func bindingScreen(_ fyne.Window) fyne.CanvasObject {
|
||||
f := 0.2
|
||||
data := binding.BindFloat(&f)
|
||||
label := widget.NewLabelWithData(binding.FloatToStringWithFormat(data, "Float value: %0.2f"))
|
||||
entry := widget.NewEntryWithData(binding.FloatToString(data))
|
||||
floats := container.NewGridWithColumns(2, label, entry)
|
||||
|
||||
slide := widget.NewSliderWithData(0, 1, data)
|
||||
slide.Step = 0.01
|
||||
bar := widget.NewProgressBarWithData(data)
|
||||
|
||||
buttons := container.NewGridWithColumns(4,
|
||||
widget.NewButton("0%", func() {
|
||||
data.Set(0)
|
||||
}),
|
||||
widget.NewButton("30%", func() {
|
||||
data.Set(0.3)
|
||||
}),
|
||||
widget.NewButton("70%", func() {
|
||||
data.Set(0.7)
|
||||
}),
|
||||
widget.NewButton("100%", func() {
|
||||
data.Set(1)
|
||||
}))
|
||||
|
||||
boolData := binding.NewBool()
|
||||
check := widget.NewCheckWithData("Check me!", boolData)
|
||||
checkLabel := widget.NewLabelWithData(binding.BoolToString(boolData))
|
||||
checkEntry := widget.NewEntryWithData(binding.BoolToString(boolData))
|
||||
checks := container.NewGridWithColumns(3, check, checkLabel, checkEntry)
|
||||
item := container.NewVBox(floats, slide, bar, buttons, widget.NewSeparator(), checks, widget.NewSeparator())
|
||||
|
||||
dataList := binding.BindFloatList(&[]float64{0.1, 0.2, 0.3})
|
||||
|
||||
button := widget.NewButton("Append", func() {
|
||||
dataList.Append(float64(dataList.Length()+1) / 10)
|
||||
})
|
||||
|
||||
list := widget.NewListWithData(dataList,
|
||||
func() fyne.CanvasObject {
|
||||
return container.NewBorder(nil, nil, nil, widget.NewButton("+", nil),
|
||||
widget.NewLabel("item x.y"))
|
||||
},
|
||||
func(item binding.DataItem, obj fyne.CanvasObject) {
|
||||
f := item.(binding.Float)
|
||||
text := obj.(*fyne.Container).Objects[0].(*widget.Label)
|
||||
text.Bind(binding.FloatToStringWithFormat(f, "item %0.1f"))
|
||||
|
||||
btn := obj.(*fyne.Container).Objects[1].(*widget.Button)
|
||||
btn.OnTapped = func() {
|
||||
val, _ := f.Get()
|
||||
_ = f.Set(val + 1)
|
||||
}
|
||||
})
|
||||
|
||||
formStruct := struct {
|
||||
Name, Email string
|
||||
Subscribe bool
|
||||
}{}
|
||||
|
||||
formData := binding.BindStruct(&formStruct)
|
||||
form := newFormWithData(formData)
|
||||
form.OnSubmit = func() {
|
||||
fmt.Println("Struct:\n", formStruct)
|
||||
}
|
||||
|
||||
listPanel := container.NewBorder(nil, button, nil, nil, list)
|
||||
return container.NewBorder(item, nil, nil, nil, container.NewGridWithColumns(2, listPanel, form))
|
||||
}
|
||||
|
||||
func newFormWithData(data binding.DataMap) *widget.Form {
|
||||
keys := data.Keys()
|
||||
items := make([]*widget.FormItem, len(keys))
|
||||
for i, k := range keys {
|
||||
data, err := data.GetItem(k)
|
||||
if err != nil {
|
||||
items[i] = widget.NewFormItem(k, widget.NewLabel(err.Error()))
|
||||
}
|
||||
items[i] = widget.NewFormItem(k, createBoundItem(data))
|
||||
}
|
||||
|
||||
return widget.NewForm(items...)
|
||||
}
|
||||
|
||||
func createBoundItem(v binding.DataItem) fyne.CanvasObject {
|
||||
switch val := v.(type) {
|
||||
case binding.Bool:
|
||||
return widget.NewCheckWithData("", val)
|
||||
case binding.Float:
|
||||
s := widget.NewSliderWithData(0, 1, val)
|
||||
s.Step = 0.01
|
||||
return s
|
||||
case binding.Int:
|
||||
return widget.NewEntryWithData(binding.IntToString(val))
|
||||
case binding.String:
|
||||
return widget.NewEntryWithData(val)
|
||||
default:
|
||||
return widget.NewLabel("")
|
||||
}
|
||||
}
|
||||
49
app/fyne_demo/tutorials/canvas.go
Normal file
49
app/fyne_demo/tutorials/canvas.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package tutorials
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"time"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/canvas"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
)
|
||||
|
||||
func rgbGradient(x, y, w, h int) color.Color {
|
||||
g := int(float32(x) / float32(w) * float32(255))
|
||||
b := int(float32(y) / float32(h) * float32(255))
|
||||
|
||||
return color.NRGBA{uint8(255 - b), uint8(g), uint8(b), 0xff}
|
||||
}
|
||||
|
||||
// canvasScreen loads a graphics example panel for the demo app
|
||||
func canvasScreen(_ fyne.Window) fyne.CanvasObject {
|
||||
gradient := canvas.NewHorizontalGradient(color.NRGBA{0x80, 0, 0, 0xff}, color.NRGBA{0, 0x80, 0, 0xff})
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
|
||||
gradient.Angle += 45
|
||||
if gradient.Angle >= 360 {
|
||||
gradient.Angle -= 360
|
||||
}
|
||||
canvas.Refresh(gradient)
|
||||
}
|
||||
}()
|
||||
|
||||
return fyne.NewContainerWithLayout(layout.NewGridWrapLayout(fyne.NewSize(90, 90)),
|
||||
canvas.NewImageFromResource(theme.FyneLogo()),
|
||||
&canvas.Rectangle{FillColor: color.NRGBA{0x80, 0, 0, 0xff},
|
||||
StrokeColor: color.NRGBA{0xff, 0xff, 0xff, 0xff},
|
||||
StrokeWidth: 1},
|
||||
&canvas.Line{StrokeColor: color.NRGBA{0, 0, 0x80, 0xff}, StrokeWidth: 5},
|
||||
&canvas.Circle{StrokeColor: color.NRGBA{0, 0, 0x80, 0xff},
|
||||
FillColor: color.NRGBA{0x30, 0x30, 0x30, 0x60},
|
||||
StrokeWidth: 2},
|
||||
canvas.NewText("Text", color.NRGBA{0, 0x80, 0, 0xff}),
|
||||
canvas.NewRasterWithPixels(rgbGradient),
|
||||
gradient,
|
||||
canvas.NewRadialGradient(color.NRGBA{0x80, 0, 0, 0xff}, color.NRGBA{0, 0x80, 0x80, 0xff}),
|
||||
)
|
||||
}
|
||||
119
app/fyne_demo/tutorials/collection.go
Normal file
119
app/fyne_demo/tutorials/collection.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package tutorials
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
// collectionScreen loads a tab panel for collection widgets
|
||||
func collectionScreen(_ fyne.Window) fyne.CanvasObject {
|
||||
content := container.NewVBox(
|
||||
widget.NewLabelWithStyle("func Length() int", fyne.TextAlignLeading, fyne.TextStyle{Monospace: true}),
|
||||
widget.NewLabelWithStyle("func CreateItem() fyne.CanvasObject", fyne.TextAlignLeading, fyne.TextStyle{Monospace: true}),
|
||||
widget.NewLabelWithStyle("func UpdateItem(ListItemID, fyne.CanvasObject)", fyne.TextAlignLeading, fyne.TextStyle{Monospace: true}),
|
||||
widget.NewLabelWithStyle("func OnSelected(ListItemID)", fyne.TextAlignLeading, fyne.TextStyle{Monospace: true}),
|
||||
widget.NewLabelWithStyle("func OnUnselected(ListItemID)", fyne.TextAlignLeading, fyne.TextStyle{Monospace: true}))
|
||||
return container.NewCenter(content)
|
||||
}
|
||||
|
||||
func makeListTab(_ fyne.Window) fyne.CanvasObject {
|
||||
data := make([]string, 1000)
|
||||
for i := range data {
|
||||
data[i] = "Test Item " + strconv.Itoa(i)
|
||||
}
|
||||
|
||||
icon := widget.NewIcon(nil)
|
||||
label := widget.NewLabel("Select An Item From The List")
|
||||
hbox := container.NewHBox(icon, label)
|
||||
|
||||
list := widget.NewList(
|
||||
func() int {
|
||||
return len(data)
|
||||
},
|
||||
func() fyne.CanvasObject {
|
||||
return container.NewHBox(widget.NewIcon(theme.DocumentIcon()), widget.NewLabel("Template Object"))
|
||||
},
|
||||
func(id widget.ListItemID, item fyne.CanvasObject) {
|
||||
item.(*fyne.Container).Objects[1].(*widget.Label).SetText(data[id])
|
||||
},
|
||||
)
|
||||
list.OnSelected = func(id widget.ListItemID) {
|
||||
label.SetText(data[id])
|
||||
icon.SetResource(theme.DocumentIcon())
|
||||
}
|
||||
list.OnUnselected = func(id widget.ListItemID) {
|
||||
label.SetText("Select An Item From The List")
|
||||
icon.SetResource(nil)
|
||||
}
|
||||
list.Select(125)
|
||||
|
||||
return container.NewHSplit(list, container.NewCenter(hbox))
|
||||
}
|
||||
|
||||
func makeTableTab(_ fyne.Window) fyne.CanvasObject {
|
||||
t := widget.NewTable(
|
||||
func() (int, int) { return 500, 150 },
|
||||
func() fyne.CanvasObject {
|
||||
return widget.NewLabel("Cell 000, 000")
|
||||
},
|
||||
func(id widget.TableCellID, cell fyne.CanvasObject) {
|
||||
label := cell.(*widget.Label)
|
||||
switch id.Col {
|
||||
case 0:
|
||||
label.SetText(fmt.Sprintf("%d", id.Row+1))
|
||||
case 1:
|
||||
label.SetText("A longer cell")
|
||||
default:
|
||||
label.SetText(fmt.Sprintf("Cell %d, %d", id.Row+1, id.Col+1))
|
||||
}
|
||||
})
|
||||
t.SetColumnWidth(0, 34)
|
||||
t.SetColumnWidth(1, 102)
|
||||
return t
|
||||
}
|
||||
|
||||
func makeTreeTab(_ fyne.Window) fyne.CanvasObject {
|
||||
data := map[string][]string{
|
||||
"": {"A"},
|
||||
"A": {"B", "D", "H", "J", "L", "O", "P", "S", "V"},
|
||||
"B": {"C"},
|
||||
"C": {"abc"},
|
||||
"D": {"E"},
|
||||
"E": {"F", "G"},
|
||||
"F": {"adef"},
|
||||
"G": {"adeg"},
|
||||
"H": {"I"},
|
||||
"I": {"ahi"},
|
||||
"O": {"ao"},
|
||||
"P": {"Q"},
|
||||
"Q": {"R"},
|
||||
"R": {"apqr"},
|
||||
"S": {"T"},
|
||||
"T": {"U"},
|
||||
"U": {"astu"},
|
||||
"V": {"W"},
|
||||
"W": {"X"},
|
||||
"X": {"Y"},
|
||||
"Y": {"Z"},
|
||||
"Z": {"avwxyz"},
|
||||
}
|
||||
|
||||
tree := widget.NewTreeWithStrings(data)
|
||||
tree.OnSelected = func(id string) {
|
||||
fmt.Println("Tree node selected:", id)
|
||||
}
|
||||
tree.OnUnselected = func(id string) {
|
||||
fmt.Println("Tree node unselected:", id)
|
||||
}
|
||||
tree.OpenBranch("A")
|
||||
tree.OpenBranch("D")
|
||||
tree.OpenBranch("E")
|
||||
tree.OpenBranch("L")
|
||||
tree.OpenBranch("M")
|
||||
return tree
|
||||
}
|
||||
154
app/fyne_demo/tutorials/container.go
Normal file
154
app/fyne_demo/tutorials/container.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package tutorials
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
"strconv"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/canvas"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
// containerScreen loads a tab panel for containers
|
||||
func containerScreen(_ fyne.Window) fyne.CanvasObject {
|
||||
content := container.NewBorder(
|
||||
widget.NewLabelWithStyle("Top", fyne.TextAlignCenter, fyne.TextStyle{}),
|
||||
widget.NewLabelWithStyle("Bottom", fyne.TextAlignCenter, fyne.TextStyle{}),
|
||||
widget.NewLabel("Left"),
|
||||
widget.NewLabel("Right"),
|
||||
widget.NewLabel("Border Container"))
|
||||
return container.NewCenter(content)
|
||||
}
|
||||
|
||||
func makeAppTabsTab(_ fyne.Window) fyne.CanvasObject {
|
||||
tabs := container.NewAppTabs(
|
||||
container.NewTabItem("Tab 1", widget.NewLabel("Content of tab 1")),
|
||||
container.NewTabItem("Tab 2 bigger", widget.NewLabel("Content of tab 2")),
|
||||
container.NewTabItem("Tab 3", widget.NewLabel("Content of tab 3")),
|
||||
)
|
||||
for i := 4; i <= 12; i++ {
|
||||
tabs.Append(container.NewTabItem(fmt.Sprintf("Tab %d", i), widget.NewLabel(fmt.Sprintf("Content of tab %d", i))))
|
||||
}
|
||||
locations := makeTabLocationSelect(tabs.SetTabLocation)
|
||||
return container.NewBorder(locations, nil, nil, nil, tabs)
|
||||
}
|
||||
|
||||
func makeBorderLayout(_ fyne.Window) fyne.CanvasObject {
|
||||
top := makeCell()
|
||||
bottom := makeCell()
|
||||
left := makeCell()
|
||||
right := makeCell()
|
||||
middle := widget.NewLabelWithStyle("BorderLayout", fyne.TextAlignCenter, fyne.TextStyle{})
|
||||
|
||||
return container.NewBorder(top, bottom, left, right, middle)
|
||||
}
|
||||
|
||||
func makeBoxLayout(_ fyne.Window) fyne.CanvasObject {
|
||||
top := makeCell()
|
||||
bottom := makeCell()
|
||||
middle := widget.NewLabel("BoxLayout")
|
||||
center := makeCell()
|
||||
right := makeCell()
|
||||
|
||||
col := container.NewVBox(top, middle, bottom)
|
||||
|
||||
return container.NewHBox(col, center, right)
|
||||
}
|
||||
|
||||
func makeButtonList(count int) []fyne.CanvasObject {
|
||||
var items []fyne.CanvasObject
|
||||
for i := 1; i <= count; i++ {
|
||||
index := i // capture
|
||||
items = append(items, widget.NewButton("Button "+strconv.Itoa(index), func() {
|
||||
fmt.Println("Tapped", index)
|
||||
}))
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
|
||||
func makeCell() fyne.CanvasObject {
|
||||
rect := canvas.NewRectangle(&color.NRGBA{128, 128, 128, 255})
|
||||
rect.SetMinSize(fyne.NewSize(30, 30))
|
||||
return rect
|
||||
}
|
||||
|
||||
func makeCenterLayout(_ fyne.Window) fyne.CanvasObject {
|
||||
middle := widget.NewButton("CenterLayout", func() {})
|
||||
|
||||
return container.NewCenter(middle)
|
||||
}
|
||||
|
||||
func makeDocTabsTab(_ fyne.Window) fyne.CanvasObject {
|
||||
tabs := container.NewDocTabs(
|
||||
container.NewTabItem("Doc 1", widget.NewLabel("Content of document 1")),
|
||||
container.NewTabItem("Doc 2 bigger", widget.NewLabel("Content of document 2")),
|
||||
container.NewTabItem("Doc 3", widget.NewLabel("Content of document 3")),
|
||||
)
|
||||
i := 3
|
||||
tabs.CreateTab = func() *container.TabItem {
|
||||
i++
|
||||
return container.NewTabItem(fmt.Sprintf("Doc %d", i), widget.NewLabel(fmt.Sprintf("Content of document %d", i)))
|
||||
}
|
||||
locations := makeTabLocationSelect(tabs.SetTabLocation)
|
||||
return container.NewBorder(locations, nil, nil, nil, tabs)
|
||||
}
|
||||
|
||||
func makeGridLayout(_ fyne.Window) fyne.CanvasObject {
|
||||
box1 := makeCell()
|
||||
box2 := widget.NewLabel("Grid")
|
||||
box3 := makeCell()
|
||||
box4 := makeCell()
|
||||
|
||||
return container.NewGridWithColumns(2,
|
||||
box1, box2, box3, box4)
|
||||
}
|
||||
|
||||
func makeScrollTab(_ fyne.Window) fyne.CanvasObject {
|
||||
hlist := makeButtonList(20)
|
||||
vlist := makeButtonList(50)
|
||||
|
||||
horiz := container.NewHScroll(container.NewHBox(hlist...))
|
||||
vert := container.NewVScroll(container.NewVBox(vlist...))
|
||||
|
||||
return container.NewAdaptiveGrid(2,
|
||||
container.NewBorder(horiz, nil, nil, nil, vert),
|
||||
makeScrollBothTab())
|
||||
}
|
||||
|
||||
func makeScrollBothTab() fyne.CanvasObject {
|
||||
logo := canvas.NewImageFromResource(theme.FyneLogo())
|
||||
logo.SetMinSize(fyne.NewSize(800, 800))
|
||||
|
||||
scroll := container.NewScroll(logo)
|
||||
scroll.Resize(fyne.NewSize(400, 400))
|
||||
|
||||
return scroll
|
||||
}
|
||||
|
||||
func makeSplitTab(_ fyne.Window) fyne.CanvasObject {
|
||||
left := widget.NewMultiLineEntry()
|
||||
left.Wrapping = fyne.TextWrapWord
|
||||
left.SetText("Long text is looooooooooooooong")
|
||||
right := container.NewVSplit(
|
||||
widget.NewLabel("Label"),
|
||||
widget.NewButton("Button", func() { fmt.Println("button tapped!") }),
|
||||
)
|
||||
return container.NewHSplit(container.NewVScroll(left), right)
|
||||
}
|
||||
|
||||
func makeTabLocationSelect(callback func(container.TabLocation)) *widget.Select {
|
||||
locations := widget.NewSelect([]string{"Top", "Bottom", "Leading", "Trailing"}, func(s string) {
|
||||
callback(map[string]container.TabLocation{
|
||||
"Top": container.TabLocationTop,
|
||||
"Bottom": container.TabLocationBottom,
|
||||
"Leading": container.TabLocationLeading,
|
||||
"Trailing": container.TabLocationTrailing,
|
||||
}[s])
|
||||
})
|
||||
locations.SetSelected("Top")
|
||||
return locations
|
||||
}
|
||||
150
app/fyne_demo/tutorials/data.go
Normal file
150
app/fyne_demo/tutorials/data.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package tutorials
|
||||
|
||||
import (
|
||||
"fyne.io/fyne/v2"
|
||||
)
|
||||
|
||||
// Tutorial defines the data structure for a tutorial
|
||||
type Tutorial struct {
|
||||
Title, Intro string
|
||||
View func(w fyne.Window) fyne.CanvasObject
|
||||
}
|
||||
|
||||
var (
|
||||
// Tutorials defines the metadata for each tutorial
|
||||
Tutorials = map[string]Tutorial{
|
||||
"welcome": {"Welcome", "", welcomeScreen},
|
||||
"canvas": {"Canvas",
|
||||
"See the canvas capabilities.",
|
||||
canvasScreen,
|
||||
},
|
||||
"animations": {"Animations",
|
||||
"See how to animate components.",
|
||||
makeAnimationScreen,
|
||||
},
|
||||
"icons": {"Theme Icons",
|
||||
"Browse the embedded icons.",
|
||||
iconScreen,
|
||||
},
|
||||
"containers": {"Containers",
|
||||
"Containers group other widgets and canvas objects, organising according to their layout.\n" +
|
||||
"Standard containers are illustrated in this section, but developers can also provide custom " +
|
||||
"layouts using the fyne.NewContainerWithLayout() constructor.",
|
||||
containerScreen,
|
||||
},
|
||||
"apptabs": {"AppTabs",
|
||||
"A container to help divide up an application into functional areas.",
|
||||
makeAppTabsTab,
|
||||
},
|
||||
"border": {"Border",
|
||||
"A container that positions items around a central content.",
|
||||
makeBorderLayout,
|
||||
},
|
||||
"box": {"Box",
|
||||
"A container arranges items in horizontal or vertical list.",
|
||||
makeBoxLayout,
|
||||
},
|
||||
"center": {"Center",
|
||||
"A container to that centers child elements.",
|
||||
makeCenterLayout,
|
||||
},
|
||||
"doctabs": {"DocTabs",
|
||||
"A container to display a single document from a set of many.",
|
||||
makeDocTabsTab,
|
||||
},
|
||||
"grid": {"Grid",
|
||||
"A container that arranges all items in a grid.",
|
||||
makeGridLayout,
|
||||
},
|
||||
"split": {"Split",
|
||||
"A split container divides the container in two pieces that the user can resize.",
|
||||
makeSplitTab,
|
||||
},
|
||||
"scroll": {"Scroll",
|
||||
"A container that provides scrolling for it's content.",
|
||||
makeScrollTab,
|
||||
},
|
||||
"widgets": {"Widgets",
|
||||
"In this section you can see the features available in the toolkit widget set.\n" +
|
||||
"Expand the tree on the left to browse the individual tutorial elements.",
|
||||
widgetScreen,
|
||||
},
|
||||
"accordion": {"Accordion",
|
||||
"Expand or collapse content panels.",
|
||||
makeAccordionTab,
|
||||
},
|
||||
"button": {"Button",
|
||||
"Simple widget for user tap handling.",
|
||||
makeButtonTab,
|
||||
},
|
||||
"card": {"Card",
|
||||
"Group content and widgets.",
|
||||
makeCardTab,
|
||||
},
|
||||
"entry": {"Entry",
|
||||
"Different ways to use the entry widget.",
|
||||
makeEntryTab,
|
||||
},
|
||||
"form": {"Form",
|
||||
"Gathering input widgets for data submission.",
|
||||
makeFormTab,
|
||||
},
|
||||
"input": {"Input",
|
||||
"A collection of widgets for user input.",
|
||||
makeInputTab,
|
||||
},
|
||||
"text": {"Text",
|
||||
"Text handling widgets.",
|
||||
makeTextTab,
|
||||
},
|
||||
"toolbar": {"Toolbar",
|
||||
"A row of shortcut icons for common tasks.",
|
||||
makeToolbarTab,
|
||||
},
|
||||
"progress": {"Progress",
|
||||
"Show duration or the need to wait for a task.",
|
||||
makeProgressTab,
|
||||
},
|
||||
"collections": {"Collections",
|
||||
"Collection widgets provide an efficient way to present lots of content.\n" +
|
||||
"The List, Table, and Tree provide a cache and re-use mechanism that make it possible to scroll through thousands of elements.\n" +
|
||||
"Use this for large data sets or for collections that can expand as users scroll.",
|
||||
collectionScreen,
|
||||
},
|
||||
"list": {"List",
|
||||
"A vertical arrangement of cached elements with the same styling.",
|
||||
makeListTab,
|
||||
},
|
||||
"table": {"Table",
|
||||
"A two dimensional cached collection of cells.",
|
||||
makeTableTab,
|
||||
},
|
||||
"tree": {"Tree",
|
||||
"A tree based arrangement of cached elements with the same styling.",
|
||||
makeTreeTab,
|
||||
},
|
||||
"dialogs": {"Dialogs",
|
||||
"Work with dialogs.",
|
||||
dialogScreen,
|
||||
},
|
||||
"windows": {"Windows",
|
||||
"Window function demo.",
|
||||
windowScreen,
|
||||
},
|
||||
"binding": {"Data Binding",
|
||||
"Connecting widgets to a data source.",
|
||||
bindingScreen},
|
||||
"advanced": {"Advanced",
|
||||
"Debug and advanced information.",
|
||||
advancedScreen,
|
||||
},
|
||||
}
|
||||
|
||||
// TutorialIndex defines how our tutorials should be laid out in the index tree
|
||||
TutorialIndex = map[string][]string{
|
||||
"": {"welcome", "canvas", "animations", "icons", "widgets", "collections", "containers", "dialogs", "windows", "binding", "advanced"},
|
||||
"collections": {"list", "table", "tree"},
|
||||
"containers": {"apptabs", "border", "box", "center", "doctabs", "grid", "scroll", "split"},
|
||||
"widgets": {"accordion", "button", "card", "entry", "form", "input", "progress", "text", "toolbar"},
|
||||
}
|
||||
)
|
||||
185
app/fyne_demo/tutorials/dialog.go
Normal file
185
app/fyne_demo/tutorials/dialog.go
Normal file
@@ -0,0 +1,185 @@
|
||||
package tutorials
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/canvas"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/data/validation"
|
||||
"fyne.io/fyne/v2/dialog"
|
||||
"fyne.io/fyne/v2/storage"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
func confirmCallback(response bool) {
|
||||
fmt.Println("Responded with", response)
|
||||
}
|
||||
|
||||
func colorPicked(c color.Color, w fyne.Window) {
|
||||
log.Println("Color picked:", c)
|
||||
rectangle := canvas.NewRectangle(c)
|
||||
size := 2 * theme.IconInlineSize()
|
||||
rectangle.SetMinSize(fyne.NewSize(size, size))
|
||||
dialog.ShowCustom("Color Picked", "Ok", rectangle, w)
|
||||
}
|
||||
|
||||
// dialogScreen loads demos of the dialogs we support
|
||||
func dialogScreen(win fyne.Window) fyne.CanvasObject {
|
||||
return container.NewVScroll(container.NewVBox(
|
||||
widget.NewButton("Info", func() {
|
||||
dialog.ShowInformation("Information", "You should know this thing...", win)
|
||||
}),
|
||||
widget.NewButton("Error", func() {
|
||||
err := errors.New("a dummy error message")
|
||||
dialog.ShowError(err, win)
|
||||
}),
|
||||
widget.NewButton("Confirm", func() {
|
||||
cnf := dialog.NewConfirm("Confirmation", "Are you enjoying this demo?", confirmCallback, win)
|
||||
cnf.SetDismissText("Nah")
|
||||
cnf.SetConfirmText("Oh Yes!")
|
||||
cnf.Show()
|
||||
}),
|
||||
widget.NewButton("File Open With Filter (.jpg or .png)", func() {
|
||||
fd := dialog.NewFileOpen(func(reader fyne.URIReadCloser, err error) {
|
||||
if err != nil {
|
||||
dialog.ShowError(err, win)
|
||||
return
|
||||
}
|
||||
if reader == nil {
|
||||
log.Println("Cancelled")
|
||||
return
|
||||
}
|
||||
|
||||
imageOpened(reader)
|
||||
}, win)
|
||||
fd.SetFilter(storage.NewExtensionFileFilter([]string{".png", ".jpg", ".jpeg"}))
|
||||
fd.Show()
|
||||
}),
|
||||
widget.NewButton("File Save", func() {
|
||||
dialog.ShowFileSave(func(writer fyne.URIWriteCloser, err error) {
|
||||
if err != nil {
|
||||
dialog.ShowError(err, win)
|
||||
return
|
||||
}
|
||||
if writer == nil {
|
||||
log.Println("Cancelled")
|
||||
return
|
||||
}
|
||||
|
||||
fileSaved(writer, win)
|
||||
}, win)
|
||||
}),
|
||||
widget.NewButton("Folder Open", func() {
|
||||
dialog.ShowFolderOpen(func(list fyne.ListableURI, err error) {
|
||||
if err != nil {
|
||||
dialog.ShowError(err, win)
|
||||
return
|
||||
}
|
||||
if list == nil {
|
||||
log.Println("Cancelled")
|
||||
return
|
||||
}
|
||||
|
||||
children, err := list.List()
|
||||
if err != nil {
|
||||
dialog.ShowError(err, win)
|
||||
return
|
||||
}
|
||||
out := fmt.Sprintf("Folder %s (%d children):\n%s", list.Name(), len(children), list.String())
|
||||
dialog.ShowInformation("Folder Open", out, win)
|
||||
}, win)
|
||||
}),
|
||||
widget.NewButton("Color Picker", func() {
|
||||
picker := dialog.NewColorPicker("Pick a Color", "What is your favorite color?", func(c color.Color) {
|
||||
colorPicked(c, win)
|
||||
}, win)
|
||||
picker.Show()
|
||||
}),
|
||||
widget.NewButton("Advanced Color Picker", func() {
|
||||
picker := dialog.NewColorPicker("Pick a Color", "What is your favorite color?", func(c color.Color) {
|
||||
colorPicked(c, win)
|
||||
}, win)
|
||||
picker.Advanced = true
|
||||
picker.Show()
|
||||
}),
|
||||
widget.NewButton("Form Dialog (Login Form)", func() {
|
||||
username := widget.NewEntry()
|
||||
username.Validator = validation.NewRegexp(`^[A-Za-z0-9_-]+$`, "username can only contain letters, numbers, '_', and '-'")
|
||||
password := widget.NewPasswordEntry()
|
||||
password.Validator = validation.NewRegexp(`^[A-Za-z0-9_-]+$`, "password can only contain letters, numbers, '_', and '-'")
|
||||
remember := false
|
||||
items := []*widget.FormItem{
|
||||
widget.NewFormItem("Username", username),
|
||||
widget.NewFormItem("Password", password),
|
||||
widget.NewFormItem("Remember me", widget.NewCheck("", func(checked bool) {
|
||||
remember = checked
|
||||
})),
|
||||
}
|
||||
|
||||
dialog.ShowForm("Login...", "Log In", "Cancel", items, func(b bool) {
|
||||
if !b {
|
||||
return
|
||||
}
|
||||
var rememberText string
|
||||
if remember {
|
||||
rememberText = "and remember this login"
|
||||
}
|
||||
|
||||
log.Println("Please Authenticate", username.Text, password.Text, rememberText)
|
||||
}, win)
|
||||
}),
|
||||
))
|
||||
}
|
||||
|
||||
func imageOpened(f fyne.URIReadCloser) {
|
||||
if f == nil {
|
||||
log.Println("Cancelled")
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
showImage(f)
|
||||
}
|
||||
|
||||
func fileSaved(f fyne.URIWriteCloser, w fyne.Window) {
|
||||
defer f.Close()
|
||||
_, err := f.Write([]byte("Written by Fyne demo\n"))
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
}
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
}
|
||||
log.Println("Saved to...", f.URI())
|
||||
}
|
||||
|
||||
func loadImage(f fyne.URIReadCloser) *canvas.Image {
|
||||
data, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
fyne.LogError("Failed to load image data", err)
|
||||
return nil
|
||||
}
|
||||
res := fyne.NewStaticResource(f.URI().Name(), data)
|
||||
|
||||
return canvas.NewImageFromResource(res)
|
||||
}
|
||||
|
||||
func showImage(f fyne.URIReadCloser) {
|
||||
img := loadImage(f)
|
||||
if img == nil {
|
||||
return
|
||||
}
|
||||
img.FillMode = canvas.ImageFillOriginal
|
||||
|
||||
w := fyne.CurrentApp().NewWindow(f.URI().Name())
|
||||
w.SetContent(container.NewScroll(img))
|
||||
w.Resize(fyne.NewSize(320, 240))
|
||||
w.Show()
|
||||
}
|
||||
195
app/fyne_demo/tutorials/icons.go
Normal file
195
app/fyne_demo/tutorials/icons.go
Normal file
@@ -0,0 +1,195 @@
|
||||
package tutorials
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/canvas"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
type iconInfo struct {
|
||||
name string
|
||||
icon fyne.Resource
|
||||
}
|
||||
|
||||
type browser struct {
|
||||
current int
|
||||
icons []iconInfo
|
||||
|
||||
name *widget.Select
|
||||
icon *widget.Icon
|
||||
}
|
||||
|
||||
func (b *browser) setIcon(index int) {
|
||||
if index < 0 || index > len(b.icons)-1 {
|
||||
return
|
||||
}
|
||||
b.current = index
|
||||
|
||||
b.name.SetSelected(b.icons[index].name)
|
||||
b.icon.SetResource(b.icons[index].icon)
|
||||
}
|
||||
|
||||
// iconScreen loads a panel that shows the various icons available in Fyne
|
||||
func iconScreen(_ fyne.Window) fyne.CanvasObject {
|
||||
b := &browser{}
|
||||
b.icons = loadIcons()
|
||||
|
||||
prev := widget.NewButtonWithIcon("", theme.NavigateBackIcon(), func() {
|
||||
b.setIcon(b.current - 1)
|
||||
})
|
||||
next := widget.NewButtonWithIcon("", theme.NavigateNextIcon(), func() {
|
||||
b.setIcon(b.current + 1)
|
||||
})
|
||||
b.name = widget.NewSelect(iconList(b.icons), func(name string) {
|
||||
for i, icon := range b.icons {
|
||||
if icon.name == name {
|
||||
if b.current != i {
|
||||
b.setIcon(i)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
b.name.SetSelected(b.icons[b.current].name)
|
||||
buttons := container.NewHBox(prev, next)
|
||||
bar := container.NewBorder(nil, nil, buttons, nil, b.name)
|
||||
|
||||
background := canvas.NewRasterWithPixels(checkerPattern)
|
||||
background.SetMinSize(fyne.NewSize(280, 280))
|
||||
b.icon = widget.NewIcon(b.icons[b.current].icon)
|
||||
|
||||
return fyne.NewContainerWithLayout(layout.NewBorderLayout(
|
||||
bar, nil, nil, nil), bar, background, b.icon)
|
||||
}
|
||||
|
||||
func checkerPattern(x, y, _, _ int) color.Color {
|
||||
x /= 20
|
||||
y /= 20
|
||||
|
||||
if x%2 == y%2 {
|
||||
return theme.BackgroundColor()
|
||||
}
|
||||
|
||||
return theme.ShadowColor()
|
||||
}
|
||||
|
||||
func iconList(icons []iconInfo) []string {
|
||||
ret := make([]string, len(icons))
|
||||
for i, icon := range icons {
|
||||
ret[i] = icon.name
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func loadIcons() []iconInfo {
|
||||
return []iconInfo{
|
||||
{"CancelIcon", theme.CancelIcon()},
|
||||
{"ConfirmIcon", theme.ConfirmIcon()},
|
||||
{"DeleteIcon", theme.DeleteIcon()},
|
||||
{"SearchIcon", theme.SearchIcon()},
|
||||
{"SearchReplaceIcon", theme.SearchReplaceIcon()},
|
||||
|
||||
{"CheckButtonIcon", theme.CheckButtonIcon()},
|
||||
{"CheckButtonCheckedIcon", theme.CheckButtonCheckedIcon()},
|
||||
{"RadioButtonIcon", theme.RadioButtonIcon()},
|
||||
{"RadioButtonCheckedIcon", theme.RadioButtonCheckedIcon()},
|
||||
|
||||
{"ColorAchromaticIcon", theme.ColorAchromaticIcon()},
|
||||
{"ColorChromaticIcon", theme.ColorChromaticIcon()},
|
||||
{"ColorPaletteIcon", theme.ColorPaletteIcon()},
|
||||
|
||||
{"ContentAddIcon", theme.ContentAddIcon()},
|
||||
{"ContentRemoveIcon", theme.ContentRemoveIcon()},
|
||||
{"ContentClearIcon", theme.ContentClearIcon()},
|
||||
{"ContentCutIcon", theme.ContentCutIcon()},
|
||||
{"ContentCopyIcon", theme.ContentCopyIcon()},
|
||||
{"ContentPasteIcon", theme.ContentPasteIcon()},
|
||||
{"ContentRedoIcon", theme.ContentRedoIcon()},
|
||||
{"ContentUndoIcon", theme.ContentUndoIcon()},
|
||||
|
||||
{"InfoIcon", theme.InfoIcon()},
|
||||
{"ErrorIcon", theme.ErrorIcon()},
|
||||
{"QuestionIcon", theme.QuestionIcon()},
|
||||
{"WarningIcon", theme.WarningIcon()},
|
||||
|
||||
{"DocumentIcon", theme.DocumentIcon()},
|
||||
{"DocumentCreateIcon", theme.DocumentCreateIcon()},
|
||||
{"DocumentPrintIcon", theme.DocumentPrintIcon()},
|
||||
{"DocumentSaveIcon", theme.DocumentSaveIcon()},
|
||||
|
||||
{"FileIcon", theme.FileIcon()},
|
||||
{"FileApplicationIcon", theme.FileApplicationIcon()},
|
||||
{"FileAudioIcon", theme.FileAudioIcon()},
|
||||
{"FileImageIcon", theme.FileImageIcon()},
|
||||
{"FileTextIcon", theme.FileTextIcon()},
|
||||
{"FileVideoIcon", theme.FileVideoIcon()},
|
||||
{"FolderIcon", theme.FolderIcon()},
|
||||
{"FolderNewIcon", theme.FolderNewIcon()},
|
||||
{"FolderOpenIcon", theme.FolderOpenIcon()},
|
||||
{"ComputerIcon", theme.ComputerIcon()},
|
||||
{"HomeIcon", theme.HomeIcon()},
|
||||
{"HelpIcon", theme.HelpIcon()},
|
||||
{"HistoryIcon", theme.HistoryIcon()},
|
||||
{"SettingsIcon", theme.SettingsIcon()},
|
||||
{"StorageIcon", theme.StorageIcon()},
|
||||
{"DownloadIcon", theme.DownloadIcon()},
|
||||
{"UploadIcon", theme.UploadIcon()},
|
||||
|
||||
{"ViewFullScreenIcon", theme.ViewFullScreenIcon()},
|
||||
{"ViewRestoreIcon", theme.ViewRestoreIcon()},
|
||||
{"ViewRefreshIcon", theme.ViewRefreshIcon()},
|
||||
{"VisibilityIcon", theme.VisibilityIcon()},
|
||||
{"VisibilityOffIcon", theme.VisibilityOffIcon()},
|
||||
{"ZoomFitIcon", theme.ZoomFitIcon()},
|
||||
{"ZoomInIcon", theme.ZoomInIcon()},
|
||||
{"ZoomOutIcon", theme.ZoomOutIcon()},
|
||||
|
||||
{"MoreHorizontalIcon", theme.MoreHorizontalIcon()},
|
||||
{"MoreVerticalIcon", theme.MoreVerticalIcon()},
|
||||
|
||||
{"MoveDownIcon", theme.MoveDownIcon()},
|
||||
{"MoveUpIcon", theme.MoveUpIcon()},
|
||||
|
||||
{"NavigateBackIcon", theme.NavigateBackIcon()},
|
||||
{"NavigateNextIcon", theme.NavigateNextIcon()},
|
||||
|
||||
{"Menu", theme.MenuIcon()},
|
||||
{"MenuExpand", theme.MenuExpandIcon()},
|
||||
{"MenuDropDown", theme.MenuDropDownIcon()},
|
||||
{"MenuDropUp", theme.MenuDropUpIcon()},
|
||||
|
||||
{"MailAttachmentIcon", theme.MailAttachmentIcon()},
|
||||
{"MailComposeIcon", theme.MailComposeIcon()},
|
||||
{"MailForwardIcon", theme.MailForwardIcon()},
|
||||
{"MailReplyIcon", theme.MailReplyIcon()},
|
||||
{"MailReplyAllIcon", theme.MailReplyAllIcon()},
|
||||
{"MailSendIcon", theme.MailSendIcon()},
|
||||
|
||||
{"MediaFastForward", theme.MediaFastForwardIcon()},
|
||||
{"MediaFastRewind", theme.MediaFastRewindIcon()},
|
||||
{"MediaPause", theme.MediaPauseIcon()},
|
||||
{"MediaPlay", theme.MediaPlayIcon()},
|
||||
{"MediaStop", theme.MediaStopIcon()},
|
||||
{"MediaRecord", theme.MediaRecordIcon()},
|
||||
{"MediaReplay", theme.MediaReplayIcon()},
|
||||
{"MediaSkipNext", theme.MediaSkipNextIcon()},
|
||||
{"MediaSkipPrevious", theme.MediaSkipPreviousIcon()},
|
||||
|
||||
{"VolumeDown", theme.VolumeDownIcon()},
|
||||
{"VolumeMute", theme.VolumeMuteIcon()},
|
||||
{"VolumeUp", theme.VolumeUpIcon()},
|
||||
|
||||
{"AccountIcon", theme.AccountIcon()},
|
||||
{"LoginIcon", theme.LoginIcon()},
|
||||
{"LogoutIcon", theme.LogoutIcon()},
|
||||
|
||||
{"ListIcon", theme.ListIcon()},
|
||||
{"GridIcon", theme.GridIcon()},
|
||||
}
|
||||
}
|
||||
72
app/fyne_demo/tutorials/theme.go
Normal file
72
app/fyne_demo/tutorials/theme.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package tutorials
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
)
|
||||
|
||||
var (
|
||||
purple = &color.NRGBA{R: 128, G: 0, B: 128, A: 255}
|
||||
orange = &color.NRGBA{R: 198, G: 123, B: 0, A: 255}
|
||||
grey = &color.Gray{Y: 123}
|
||||
)
|
||||
|
||||
// customTheme is a simple demonstration of a bespoke theme loaded by a Fyne app.
|
||||
type customTheme struct {
|
||||
}
|
||||
|
||||
func (customTheme) Color(c fyne.ThemeColorName, _ fyne.ThemeVariant) color.Color {
|
||||
switch c {
|
||||
case theme.ColorNameBackground:
|
||||
return purple
|
||||
case theme.ColorNameButton, theme.ColorNameDisabled:
|
||||
return color.Black
|
||||
case theme.ColorNamePlaceHolder, theme.ColorNameScrollBar:
|
||||
return grey
|
||||
case theme.ColorNamePrimary, theme.ColorNameHover, theme.ColorNameFocus:
|
||||
return orange
|
||||
case theme.ColorNameShadow:
|
||||
return &color.RGBA{R: 0xcc, G: 0xcc, B: 0xcc, A: 0xcc}
|
||||
default:
|
||||
return color.White
|
||||
}
|
||||
}
|
||||
|
||||
func (customTheme) Font(style fyne.TextStyle) fyne.Resource {
|
||||
return theme.DarkTheme().Font(style)
|
||||
}
|
||||
|
||||
func (customTheme) Icon(n fyne.ThemeIconName) fyne.Resource {
|
||||
return theme.DefaultTheme().Icon(n)
|
||||
}
|
||||
|
||||
func (customTheme) Size(s fyne.ThemeSizeName) float32 {
|
||||
switch s {
|
||||
case theme.SizeNamePadding:
|
||||
return 8
|
||||
case theme.SizeNameInlineIcon:
|
||||
return 20
|
||||
case theme.SizeNameScrollBar:
|
||||
return 10
|
||||
case theme.SizeNameScrollBarSmall:
|
||||
return 5
|
||||
case theme.SizeNameText:
|
||||
return 18
|
||||
case theme.SizeNameHeadingText:
|
||||
return 30
|
||||
case theme.SizeNameSubHeadingText:
|
||||
return 25
|
||||
case theme.SizeNameCaptionText:
|
||||
return 15
|
||||
case theme.SizeNameInputBorder:
|
||||
return 1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func newCustomTheme() fyne.Theme {
|
||||
return &customTheme{}
|
||||
}
|
||||
42
app/fyne_demo/tutorials/welcome.go
Normal file
42
app/fyne_demo/tutorials/welcome.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package tutorials
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/canvas"
|
||||
"fyne.io/fyne/v2/cmd/fyne_demo/data"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
func parseURL(urlStr string) *url.URL {
|
||||
link, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
fyne.LogError("Could not parse URL", err)
|
||||
}
|
||||
|
||||
return link
|
||||
}
|
||||
|
||||
func welcomeScreen(_ fyne.Window) fyne.CanvasObject {
|
||||
logo := canvas.NewImageFromResource(data.FyneScene)
|
||||
logo.FillMode = canvas.ImageFillContain
|
||||
if fyne.CurrentDevice().IsMobile() {
|
||||
logo.SetMinSize(fyne.NewSize(171, 125))
|
||||
} else {
|
||||
logo.SetMinSize(fyne.NewSize(228, 167))
|
||||
}
|
||||
|
||||
return container.NewCenter(container.NewVBox(
|
||||
widget.NewLabelWithStyle("Welcome to the Fyne toolkit demo app", fyne.TextAlignCenter, fyne.TextStyle{Bold: true}),
|
||||
logo,
|
||||
container.NewHBox(
|
||||
widget.NewHyperlink("fyne.io", parseURL("https://fyne.io/")),
|
||||
widget.NewLabel("-"),
|
||||
widget.NewHyperlink("documentation", parseURL("https://developer.fyne.io/")),
|
||||
widget.NewLabel("-"),
|
||||
widget.NewHyperlink("sponsor", parseURL("https://fyne.io/sponsor/")),
|
||||
),
|
||||
))
|
||||
}
|
||||
420
app/fyne_demo/tutorials/widget.go
Normal file
420
app/fyne_demo/tutorials/widget.go
Normal file
@@ -0,0 +1,420 @@
|
||||
package tutorials
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/canvas"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/data/validation"
|
||||
"fyne.io/fyne/v2/driver/mobile"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
const (
|
||||
loremIpsum = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque quis consectetur nisi. Suspendisse id interdum felis.
|
||||
Sed egestas eget tellus eu pharetra. Praesent pulvinar sed massa id placerat. Etiam sem libero, semper vitae consequat ut, volutpat id mi.
|
||||
Mauris volutpat pellentesque convallis. Curabitur rutrum venenatis orci nec ornare. Maecenas quis pellentesque neque.
|
||||
Aliquam consectetur dapibus nulla, id maximus odio ultrices ac. Sed luctus at felis sed faucibus. Cras leo augue, congue in velit ut, mattis rhoncus lectus.
|
||||
|
||||
Praesent viverra, mauris ut ullamcorper semper, leo urna auctor lectus, vitae vehicula mi leo quis lorem.
|
||||
Nullam condimentum, massa at tempor feugiat, metus enim lobortis velit, eget suscipit eros ipsum quis tellus. Aenean fermentum diam vel felis dictum semper.
|
||||
Duis nisl orci, tincidunt ut leo quis, luctus vehicula diam. Sed velit justo, congue id augue eu, euismod dapibus lacus. Proin sit amet imperdiet sapien.
|
||||
Mauris erat urna, fermentum et quam rhoncus, fringilla consequat ante. Vivamus consectetur molestie odio, ac rutrum erat finibus a.
|
||||
Suspendisse id maximus felis. Sed mauris odio, mattis eget mi eu, consequat tempus purus.`
|
||||
)
|
||||
|
||||
var (
|
||||
progress *widget.ProgressBar
|
||||
fprogress *widget.ProgressBar
|
||||
infProgress *widget.ProgressBarInfinite
|
||||
endProgress chan interface{}
|
||||
)
|
||||
|
||||
func makeAccordionTab(_ fyne.Window) fyne.CanvasObject {
|
||||
link, err := url.Parse("https://fyne.io/")
|
||||
if err != nil {
|
||||
fyne.LogError("Could not parse URL", err)
|
||||
}
|
||||
ac := widget.NewAccordion(
|
||||
widget.NewAccordionItem("A", widget.NewHyperlink("One", link)),
|
||||
widget.NewAccordionItem("B", widget.NewLabel("Two")),
|
||||
&widget.AccordionItem{
|
||||
Title: "C",
|
||||
Detail: widget.NewLabel("Three"),
|
||||
},
|
||||
)
|
||||
ac.Append(widget.NewAccordionItem("D", &widget.Entry{Text: "Four"}))
|
||||
return ac
|
||||
}
|
||||
|
||||
func makeButtonTab(_ fyne.Window) fyne.CanvasObject {
|
||||
disabled := widget.NewButton("Disabled", func() {})
|
||||
disabled.Disable()
|
||||
|
||||
shareItem := fyne.NewMenuItem("Share via", nil)
|
||||
shareItem.ChildMenu = fyne.NewMenu("",
|
||||
fyne.NewMenuItem("Twitter", func() { fmt.Println("context menu Share->Twitter") }),
|
||||
fyne.NewMenuItem("Reddit", func() { fmt.Println("context menu Share->Reddit") }),
|
||||
)
|
||||
menuLabel := newContextMenuButton("tap me for pop-up menu with submenus", fyne.NewMenu("",
|
||||
fyne.NewMenuItem("Copy", func() { fmt.Println("context menu copy") }),
|
||||
shareItem,
|
||||
))
|
||||
|
||||
return container.NewVBox(
|
||||
widget.NewButton("Button (text only)", func() { fmt.Println("tapped text button") }),
|
||||
widget.NewButtonWithIcon("Button (text & leading icon)", theme.ConfirmIcon(), func() { fmt.Println("tapped text & leading icon button") }),
|
||||
&widget.Button{
|
||||
Alignment: widget.ButtonAlignLeading,
|
||||
Text: "Button (leading-aligned, text only)",
|
||||
OnTapped: func() { fmt.Println("tapped leading-aligned, text only button") },
|
||||
},
|
||||
&widget.Button{
|
||||
Alignment: widget.ButtonAlignTrailing,
|
||||
IconPlacement: widget.ButtonIconTrailingText,
|
||||
Text: "Button (trailing-aligned, text & trailing icon)",
|
||||
Icon: theme.ConfirmIcon(),
|
||||
OnTapped: func() { fmt.Println("tapped trailing-aligned, text & trailing icon button") },
|
||||
},
|
||||
disabled,
|
||||
layout.NewSpacer(),
|
||||
layout.NewSpacer(),
|
||||
menuLabel,
|
||||
layout.NewSpacer(),
|
||||
)
|
||||
}
|
||||
|
||||
func makeCardTab(_ fyne.Window) fyne.CanvasObject {
|
||||
card1 := widget.NewCard("Book a table", "Which time suits?",
|
||||
widget.NewRadioGroup([]string{"6:30pm", "7:00pm", "7:45pm"}, func(string) {}))
|
||||
card2 := widget.NewCard("With media", "No content, with image", nil)
|
||||
card2.Image = canvas.NewImageFromResource(theme.FyneLogo())
|
||||
card3 := widget.NewCard("Title 3", "Another card", widget.NewLabel("Content"))
|
||||
return container.NewGridWithColumns(2, container.NewVBox(card1, card3),
|
||||
container.NewVBox(card2))
|
||||
}
|
||||
|
||||
func makeEntryTab(_ fyne.Window) fyne.CanvasObject {
|
||||
entry := widget.NewEntry()
|
||||
entry.SetPlaceHolder("Entry")
|
||||
entryDisabled := widget.NewEntry()
|
||||
entryDisabled.SetText("Entry (disabled)")
|
||||
entryDisabled.Disable()
|
||||
entryValidated := newNumEntry()
|
||||
entryValidated.SetPlaceHolder("Must contain a number")
|
||||
entryMultiLine := widget.NewMultiLineEntry()
|
||||
entryMultiLine.SetPlaceHolder("MultiLine Entry")
|
||||
|
||||
return container.NewVBox(
|
||||
entry,
|
||||
entryDisabled,
|
||||
entryValidated,
|
||||
entryMultiLine)
|
||||
}
|
||||
|
||||
func makeTextGrid() *widget.TextGrid {
|
||||
grid := widget.NewTextGridFromString("TextGrid\n\tContent\nZebra")
|
||||
grid.SetStyleRange(0, 4, 0, 7,
|
||||
&widget.CustomTextGridStyle{BGColor: &color.NRGBA{R: 64, G: 64, B: 192, A: 128}})
|
||||
grid.SetRowStyle(1, &widget.CustomTextGridStyle{BGColor: &color.NRGBA{R: 64, G: 192, B: 64, A: 128}})
|
||||
|
||||
white := &widget.CustomTextGridStyle{FGColor: color.White, BGColor: color.Black}
|
||||
black := &widget.CustomTextGridStyle{FGColor: color.Black, BGColor: color.White}
|
||||
grid.Rows[2].Cells[0].Style = white
|
||||
grid.Rows[2].Cells[1].Style = black
|
||||
grid.Rows[2].Cells[2].Style = white
|
||||
grid.Rows[2].Cells[3].Style = black
|
||||
grid.Rows[2].Cells[4].Style = white
|
||||
|
||||
grid.ShowLineNumbers = true
|
||||
grid.ShowWhitespace = true
|
||||
|
||||
return grid
|
||||
}
|
||||
|
||||
func makeTextTab(_ fyne.Window) fyne.CanvasObject {
|
||||
label := widget.NewLabel("Label")
|
||||
|
||||
link, err := url.Parse("https://fyne.io/")
|
||||
if err != nil {
|
||||
fyne.LogError("Could not parse URL", err)
|
||||
}
|
||||
hyperlink := widget.NewHyperlink("Hyperlink", link)
|
||||
|
||||
entryLoremIpsum := widget.NewMultiLineEntry()
|
||||
entryLoremIpsum.SetText(loremIpsum)
|
||||
|
||||
label.Alignment = fyne.TextAlignLeading
|
||||
hyperlink.Alignment = fyne.TextAlignLeading
|
||||
|
||||
label.Wrapping = fyne.TextWrapWord
|
||||
hyperlink.Wrapping = fyne.TextWrapWord
|
||||
entryLoremIpsum.Wrapping = fyne.TextWrapWord
|
||||
|
||||
rich := widget.NewRichTextFromMarkdown(`
|
||||
# RichText Heading
|
||||
|
||||
## A Sub Heading
|
||||
|
||||
---
|
||||
|
||||
* Item1 in _three_ segments
|
||||
* Item2
|
||||
* Item3
|
||||
|
||||
Normal **Bold** *Italic* [Link](https://fyne.io/) and some ` + "`Code`" + `.
|
||||
This styled row should also wrap as expected, but only *when required*.
|
||||
|
||||
> An interesting quote here, most likely sharing some very interesting wisdom.`)
|
||||
rich.Scroll = container.ScrollBoth
|
||||
|
||||
radioAlign := widget.NewRadioGroup([]string{"Text Alignment Leading", "Text Alignment Center", "Text Alignment Trailing"}, func(s string) {
|
||||
var align fyne.TextAlign
|
||||
switch s {
|
||||
case "Text Alignment Leading":
|
||||
align = fyne.TextAlignLeading
|
||||
case "Text Alignment Center":
|
||||
align = fyne.TextAlignCenter
|
||||
case "Text Alignment Trailing":
|
||||
align = fyne.TextAlignTrailing
|
||||
}
|
||||
|
||||
label.Alignment = align
|
||||
hyperlink.Alignment = align
|
||||
for i := range rich.Segments {
|
||||
if seg, ok := rich.Segments[i].(*widget.TextSegment); ok {
|
||||
seg.Style.Alignment = align
|
||||
}
|
||||
if seg, ok := rich.Segments[i].(*widget.HyperlinkSegment); ok {
|
||||
seg.Alignment = align
|
||||
}
|
||||
}
|
||||
|
||||
label.Refresh()
|
||||
hyperlink.Refresh()
|
||||
rich.Refresh()
|
||||
})
|
||||
radioAlign.SetSelected("Text Alignment Leading")
|
||||
|
||||
radioWrap := widget.NewRadioGroup([]string{"Text Wrapping Off", "Text Wrapping Truncate", "Text Wrapping Break", "Text Wrapping Word"}, func(s string) {
|
||||
var wrap fyne.TextWrap
|
||||
switch s {
|
||||
case "Text Wrapping Off":
|
||||
wrap = fyne.TextWrapOff
|
||||
case "Text Wrapping Truncate":
|
||||
wrap = fyne.TextTruncate
|
||||
case "Text Wrapping Break":
|
||||
wrap = fyne.TextWrapBreak
|
||||
case "Text Wrapping Word":
|
||||
wrap = fyne.TextWrapWord
|
||||
}
|
||||
|
||||
label.Wrapping = wrap
|
||||
hyperlink.Wrapping = wrap
|
||||
entryLoremIpsum.Wrapping = wrap
|
||||
rich.Wrapping = wrap
|
||||
|
||||
label.Refresh()
|
||||
hyperlink.Refresh()
|
||||
entryLoremIpsum.Refresh()
|
||||
rich.Refresh()
|
||||
})
|
||||
radioWrap.SetSelected("Text Wrapping Word")
|
||||
|
||||
fixed := container.NewVBox(
|
||||
container.NewHBox(
|
||||
radioAlign,
|
||||
layout.NewSpacer(),
|
||||
radioWrap,
|
||||
),
|
||||
label,
|
||||
hyperlink,
|
||||
)
|
||||
|
||||
grid := makeTextGrid()
|
||||
return container.NewBorder(fixed, grid, nil, nil,
|
||||
container.NewGridWithRows(2, rich, entryLoremIpsum))
|
||||
}
|
||||
|
||||
func makeInputTab(_ fyne.Window) fyne.CanvasObject {
|
||||
selectEntry := widget.NewSelectEntry([]string{"Option A", "Option B", "Option C"})
|
||||
selectEntry.PlaceHolder = "Type or select"
|
||||
disabledCheck := widget.NewCheck("Disabled check", func(bool) {})
|
||||
disabledCheck.Disable()
|
||||
checkGroup := widget.NewCheckGroup([]string{"CheckGroup Item 1", "CheckGroup Item 2AAAAAAAAAAAAAA", "CheckGroup Item 3"}, func(s []string) { fmt.Println("selected", s) })
|
||||
checkGroup.Horizontal = true
|
||||
radio := widget.NewRadioGroup([]string{"Radio Item 1", "Radio Item 2"}, func(s string) { fmt.Println("selected", s) })
|
||||
radio.Horizontal = true
|
||||
disabledRadio := widget.NewRadioGroup([]string{"Disabled radio"}, func(string) {})
|
||||
disabledRadio.Disable()
|
||||
|
||||
return container.NewVBox(
|
||||
widget.NewSelect([]string{"Option 1", "Option 2", "Option 3"}, func(s string) { fmt.Println("selected", s) }),
|
||||
selectEntry,
|
||||
widget.NewCheck("Check", func(on bool) { fmt.Println("checked", on) }),
|
||||
disabledCheck,
|
||||
checkGroup,
|
||||
radio,
|
||||
disabledRadio,
|
||||
widget.NewSlider(0, 100),
|
||||
)
|
||||
}
|
||||
|
||||
func makeProgressTab(_ fyne.Window) fyne.CanvasObject {
|
||||
stopProgress()
|
||||
|
||||
progress = widget.NewProgressBar()
|
||||
|
||||
fprogress = widget.NewProgressBar()
|
||||
fprogress.TextFormatter = func() string {
|
||||
return fmt.Sprintf("%.2f out of %.2f", fprogress.Value, fprogress.Max)
|
||||
}
|
||||
|
||||
infProgress = widget.NewProgressBarInfinite()
|
||||
endProgress = make(chan interface{}, 1)
|
||||
startProgress()
|
||||
|
||||
return container.NewVBox(
|
||||
widget.NewLabel("Percent"), progress,
|
||||
widget.NewLabel("Formatted"), fprogress,
|
||||
widget.NewLabel("Infinite"), infProgress)
|
||||
}
|
||||
|
||||
func makeFormTab(_ fyne.Window) fyne.CanvasObject {
|
||||
name := widget.NewEntry()
|
||||
name.SetPlaceHolder("John Smith")
|
||||
|
||||
email := widget.NewEntry()
|
||||
email.SetPlaceHolder("test@example.com")
|
||||
email.Validator = validation.NewRegexp(`\w{1,}@\w{1,}\.\w{1,4}`, "not a valid email")
|
||||
|
||||
password := widget.NewPasswordEntry()
|
||||
password.SetPlaceHolder("Password")
|
||||
|
||||
disabled := widget.NewRadioGroup([]string{"Option 1", "Option 2"}, func(string) {})
|
||||
disabled.Horizontal = true
|
||||
disabled.Disable()
|
||||
largeText := widget.NewMultiLineEntry()
|
||||
|
||||
form := &widget.Form{
|
||||
Items: []*widget.FormItem{
|
||||
{Text: "Name", Widget: name, HintText: "Your full name"},
|
||||
{Text: "Email", Widget: email, HintText: "A valid email address"},
|
||||
},
|
||||
OnCancel: func() {
|
||||
fmt.Println("Cancelled")
|
||||
},
|
||||
OnSubmit: func() {
|
||||
fmt.Println("Form submitted")
|
||||
fyne.CurrentApp().SendNotification(&fyne.Notification{
|
||||
Title: "Form for: " + name.Text,
|
||||
Content: largeText.Text,
|
||||
})
|
||||
},
|
||||
}
|
||||
form.Append("Password", password)
|
||||
form.Append("Disabled", disabled)
|
||||
form.Append("Message", largeText)
|
||||
return form
|
||||
}
|
||||
|
||||
func makeToolbarTab(_ fyne.Window) fyne.CanvasObject {
|
||||
t := widget.NewToolbar(widget.NewToolbarAction(theme.MailComposeIcon(), func() { fmt.Println("New") }),
|
||||
widget.NewToolbarSeparator(),
|
||||
widget.NewToolbarSpacer(),
|
||||
widget.NewToolbarAction(theme.ContentCutIcon(), func() { fmt.Println("Cut") }),
|
||||
widget.NewToolbarAction(theme.ContentCopyIcon(), func() { fmt.Println("Copy") }),
|
||||
widget.NewToolbarAction(theme.ContentPasteIcon(), func() { fmt.Println("Paste") }),
|
||||
)
|
||||
|
||||
return container.NewBorder(t, nil, nil, nil)
|
||||
}
|
||||
|
||||
func startProgress() {
|
||||
progress.SetValue(0)
|
||||
fprogress.SetValue(0)
|
||||
select { // ignore stale end message
|
||||
case <-endProgress:
|
||||
default:
|
||||
}
|
||||
|
||||
go func() {
|
||||
end := endProgress
|
||||
num := 0.0
|
||||
for num < 1.0 {
|
||||
time.Sleep(16 * time.Millisecond)
|
||||
select {
|
||||
case <-end:
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
progress.SetValue(num)
|
||||
fprogress.SetValue(num)
|
||||
num += 0.002
|
||||
}
|
||||
|
||||
progress.SetValue(1)
|
||||
fprogress.SetValue(1)
|
||||
|
||||
// TODO make sure this resets when we hide etc...
|
||||
stopProgress()
|
||||
}()
|
||||
infProgress.Start()
|
||||
}
|
||||
|
||||
func stopProgress() {
|
||||
if !infProgress.Running() {
|
||||
return
|
||||
}
|
||||
|
||||
infProgress.Stop()
|
||||
endProgress <- struct{}{}
|
||||
}
|
||||
|
||||
// widgetScreen shows a panel containing widget demos
|
||||
func widgetScreen(_ fyne.Window) fyne.CanvasObject {
|
||||
content := container.NewVBox(
|
||||
widget.NewLabel("Labels"),
|
||||
widget.NewButtonWithIcon("Icons", theme.HomeIcon(), func() {}),
|
||||
widget.NewSlider(0, 1))
|
||||
return container.NewCenter(content)
|
||||
}
|
||||
|
||||
type contextMenuButton struct {
|
||||
widget.Button
|
||||
menu *fyne.Menu
|
||||
}
|
||||
|
||||
func (b *contextMenuButton) Tapped(e *fyne.PointEvent) {
|
||||
widget.ShowPopUpMenuAtPosition(b.menu, fyne.CurrentApp().Driver().CanvasForObject(b), e.AbsolutePosition)
|
||||
}
|
||||
|
||||
func newContextMenuButton(label string, menu *fyne.Menu) *contextMenuButton {
|
||||
b := &contextMenuButton{menu: menu}
|
||||
b.Text = label
|
||||
|
||||
b.ExtendBaseWidget(b)
|
||||
return b
|
||||
}
|
||||
|
||||
type numEntry struct {
|
||||
widget.Entry
|
||||
}
|
||||
|
||||
func (n *numEntry) Keyboard() mobile.KeyboardType {
|
||||
return mobile.NumberKeyboard
|
||||
}
|
||||
|
||||
func newNumEntry() *numEntry {
|
||||
e := &numEntry{}
|
||||
e.ExtendBaseWidget(e)
|
||||
e.Validator = validation.NewRegexp(`\d`, "Must contain a number")
|
||||
return e
|
||||
}
|
||||
71
app/fyne_demo/tutorials/window.go
Normal file
71
app/fyne_demo/tutorials/window.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package tutorials
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/driver/desktop"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
func windowScreen(_ fyne.Window) fyne.CanvasObject {
|
||||
windowGroup := container.NewVBox(
|
||||
widget.NewButton("New window", func() {
|
||||
w := fyne.CurrentApp().NewWindow("Hello")
|
||||
w.SetContent(widget.NewLabel("Hello World!"))
|
||||
w.Show()
|
||||
}),
|
||||
widget.NewButton("Fixed size window", func() {
|
||||
w := fyne.CurrentApp().NewWindow("Fixed")
|
||||
w.SetContent(fyne.NewContainerWithLayout(layout.NewCenterLayout(), widget.NewLabel("Hello World!")))
|
||||
|
||||
w.Resize(fyne.NewSize(240, 180))
|
||||
w.SetFixedSize(true)
|
||||
w.Show()
|
||||
}),
|
||||
widget.NewButton("Toggle between fixed/not fixed window size", func() {
|
||||
w := fyne.CurrentApp().NewWindow("Toggle fixed size")
|
||||
w.SetContent(fyne.NewContainerWithLayout(layout.NewCenterLayout(), widget.NewCheck("Fixed size", func(toggle bool) {
|
||||
if toggle {
|
||||
w.Resize(fyne.NewSize(240, 180))
|
||||
}
|
||||
w.SetFixedSize(toggle)
|
||||
})))
|
||||
w.Show()
|
||||
}),
|
||||
widget.NewButton("Centered window", func() {
|
||||
w := fyne.CurrentApp().NewWindow("Central")
|
||||
w.SetContent(fyne.NewContainerWithLayout(layout.NewCenterLayout(), widget.NewLabel("Hello World!")))
|
||||
|
||||
w.CenterOnScreen()
|
||||
w.Show()
|
||||
}))
|
||||
|
||||
drv := fyne.CurrentApp().Driver()
|
||||
if drv, ok := drv.(desktop.Driver); ok {
|
||||
windowGroup.Objects = append(windowGroup.Objects,
|
||||
widget.NewButton("Splash Window (only use on start)", func() {
|
||||
w := drv.CreateSplashWindow()
|
||||
w.SetContent(widget.NewLabelWithStyle("Hello World!\n\nMake a splash!",
|
||||
fyne.TextAlignCenter, fyne.TextStyle{Bold: true}))
|
||||
w.Show()
|
||||
|
||||
go func() {
|
||||
time.Sleep(time.Second * 3)
|
||||
w.Close()
|
||||
}()
|
||||
}))
|
||||
}
|
||||
|
||||
otherGroup := widget.NewCard("Other", "",
|
||||
widget.NewButton("Notification", func() {
|
||||
fyne.CurrentApp().SendNotification(&fyne.Notification{
|
||||
Title: "Fyne Demo",
|
||||
Content: "Testing notifications...",
|
||||
})
|
||||
}))
|
||||
|
||||
return container.NewVBox(widget.NewCard("Windows", "", windowGroup), otherGroup)
|
||||
}
|
||||
Reference in New Issue
Block a user