Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First commit of the new demo system #5325

Draft
wants to merge 2 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions cmd/fyne_demo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ func main() {
title := widget.NewLabel("Component name")
intro := widget.NewLabel("An introduction would probably go\nhere, as well as a")
intro.Wrapping = fyne.TextWrapWord

top := container.NewVBox(title, widget.NewSeparator(), intro)
setTutorial := func(t tutorials.Tutorial) {
if fyne.CurrentDevice().IsMobile() {
child := a.NewWindow(t.Title)
Expand All @@ -49,22 +51,23 @@ func main() {
}

title.SetText(t.Title)
intro.SetText(t.Intro)
isMarkdown := len(t.Intro) == 0
if !isMarkdown {
intro.SetText(t.Intro)
}

if t.Title == "Welcome" {
title.Hide()
intro.Hide()
if t.Title == "Welcome" || isMarkdown {
top.Hide()
} else {
title.Show()
intro.Show()
top.Show()
}

content.Objects = []fyne.CanvasObject{t.View(w)}
content.Refresh()
}

tutorial := container.NewBorder(
container.NewVBox(title, widget.NewSeparator(), intro), nil, nil, nil, content)
top, nil, nil, nil, content)
if fyne.CurrentDevice().IsMobile() {
w.SetContent(makeNav(setTutorial, false))
} else {
Expand Down
67 changes: 67 additions & 0 deletions cmd/fyne_demo/tutorials/code.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package tutorials

import (
"image/color"
"log"

"github.com/alecthomas/chroma/v2"
"github.com/alecthomas/chroma/v2/lexers"
"github.com/alecthomas/chroma/v2/styles"

"fyne.io/fyne/v2/widget"
)

func highlightTextGrid(grid *widget.TextGrid) {
content := grid.Text()
lex := lexers.Get("go")

style := styles.Get("solarized-dark")
if style == nil {
style = styles.Fallback
}

iterator, err := lex.Tokenise(nil, string(content))
if err != nil {
log.Println("Token error", err)
return
}

row, col := 0, 0
textColor := styleColor(chroma.Background, style)
grid.SetRowStyle(0, &widget.CustomTextGridStyle{
FGColor: textColor})
for _, tok := range iterator.Tokens() {
length := len(tok.Value)

if tok.Value == "\n" {
row++
col = 0

grid.SetRowStyle(row, &widget.CustomTextGridStyle{
FGColor: textColor})

continue
}

c := resolveColor(style.Get(tok.Type).Colour)
grid.SetStyleRange(row, col, row, col+length,
&widget.CustomTextGridStyle{FGColor: c})
col += length
}
}

func resolveColor(colour chroma.Colour) color.Color {
r, g, b := colour.Red(), colour.Green(), colour.Blue()

return &color.NRGBA{R: r, G: g, B: b, A: 0xff}
}

func styleBackgroundColor(name chroma.TokenType, style *chroma.Style) color.Color {
entry := style.Get(name)
return resolveColor(entry.Background)
}

func styleColor(name chroma.TokenType, style *chroma.Style) color.Color {
entry := style.Get(name)
return resolveColor(entry.Colour)
}
73 changes: 71 additions & 2 deletions cmd/fyne_demo/tutorials/data.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
//go:generate go run gen.go

package tutorials

import (
"github.com/alecthomas/chroma/v2"
"github.com/alecthomas/chroma/v2/styles"

"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"
)

// Tutorial defines the data structure for a tutorial
Expand All @@ -10,6 +20,13 @@ type Tutorial struct {
View func(w fyne.Window) fyne.CanvasObject
}

type Tutorial2 struct {
title string

content []string
code []func() fyne.CanvasObject
}

var (
// Tutorials defines the metadata for each tutorial
Tutorials = map[string]Tutorial{
Expand Down Expand Up @@ -82,8 +99,8 @@ var (
makeActivityTab,
},
"button": {"Button",
"Simple widget for user tap handling.",
makeButtonTab,
"",
func(fyne.Window) fyne.CanvasObject { return makeNewTutorial("widgets/button.md") },
},
"card": {"Card",
"Group content and widgets.",
Expand Down Expand Up @@ -161,3 +178,55 @@ var (
"widgets": {"accordion", "activity", "button", "card", "entry", "form", "input", "progress", "text", "toolbar"},
}
)

func makeNewTutorial(file string) fyne.CanvasObject {
tutorial := tutorials[file]
top := container.NewVBox(
widget.NewLabel(tutorial.title), widget.NewSeparator())
details := container.NewVBox()

for i, p := range tutorial.content {
if p == "" {
continue
}
if i%2 == 0 {
text := widget.NewRichTextFromMarkdown(p)
text.Wrapping = fyne.TextWrapWord

details.Add(text)
continue
}

usage := widget.NewTextGridFromString(p)
usage.ShowLineNumbers = true
highlightTextGrid(usage)

codeID := (i - 1) / 2
preview := tutorial.code[codeID]()

tools := widget.NewToolbar(
widget.NewToolbarAction(theme.ContentCopyIcon(), func() {
fyne.CurrentApp().Clipboard().SetContent(usage.Text())
}),
widget.NewToolbarAction(theme.MediaPlayIcon(), func() {
w := fyne.CurrentApp().NewWindow(tutorial.title + " preview")
w.SetContent(tutorial.code[codeID]())
w.Show()
}),
)

style := styles.Get("solarized-dark")
bg := styleBackgroundColor(chroma.Background, style)

details.Add(container.NewPadded(container.NewPadded(
container.NewStack(
canvas.NewRectangle(bg),
container.NewPadded(usage,
container.NewHBox(layout.NewSpacer(), container.NewVBox(
tools)))))))
details.Add(widget.NewRichTextFromMarkdown("*Preview:*"))
details.Add(container.NewPadded(container.NewHBox(preview)))
}

return container.NewBorder(top, nil, nil, nil, container.NewScroll(details))
}
36 changes: 36 additions & 0 deletions cmd/fyne_demo/tutorials/data_gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package tutorials

import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
)

var tutorials = map[string]Tutorial2{
"widgets/button.md": Tutorial2{
title: "Widgets : Button",
content: []string{"The button widget is the basic tappable interaction for an app.\nA user tapping this will run the function passed to the constructor function. \n\n## Basic usage\n\nSimply create a button using the `NewButton` constructor function, passing in a function\nthat should run when the button is tapped.", "btn := widget.NewButton(\"Tap me\", func() {})", "If you want to use an icon in your button that is possible.\nYou can also set the label to \"\" if you want icon only!", "btn := widget.NewButtonWithIcon(\"Home\",\n theme.HomeIcon(), func() {})", "## Disabled\n\nA button can also be disabled so that it cannot be tapped:", "btn := widget.NewButton(\"Tap me\", func() {})\nbtn.Disable()", "## Importance\n\nYou can change the colour / style of the button by setting its `Importance` value, like this:", "btn := widget.NewButton(\"Danger!\", func() {})\nbtn.Importance = widget.DangerImportance", ""},

code: []func() fyne.CanvasObject{
func() fyne.CanvasObject {
btn := widget.NewButton("Tap me", func() {})
return btn
},
func() fyne.CanvasObject {
btn := widget.NewButtonWithIcon("Home",
theme.HomeIcon(), func() {})
return btn
},
func() fyne.CanvasObject {
btn := widget.NewButton("Tap me", func() {})
btn.Disable()
return btn
},
func() fyne.CanvasObject {
btn := widget.NewButton("Danger!", func() {})
btn.Importance = widget.DangerImportance
return btn
},
},
},
}
104 changes: 104 additions & 0 deletions cmd/fyne_demo/tutorials/gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//go:build ignore

package main

import (
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"strings"

"fyne.io/fyne/v2"
)

const template = `
"%s": Tutorial2{
title: "%s",
content: %#v,

code: []func() fyne.CanvasObject{
%s
},
},
`

func main() {
w, _ := os.Create("data_gen.go")
_, _ = io.WriteString(w,
`package tutorials

import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
)

var tutorials = map[string]Tutorial2{`)

processDirectories(w)
io.WriteString(w, "}\n")
w.Close()

cmd := exec.Command("go", "fmt", "data_gen.go")
err := cmd.Run()
if err != nil {
fyne.LogError("failed to tidy output", err)
}
}

func processDirectories(w io.Writer) {
dir := "widgets"
files, err := os.ReadDir(dir)
if err != nil {
fyne.LogError("Failed to list directory", err)
return
}

for _, file := range files {
processFile(filepath.Join(dir, file.Name()), w)
}
}

func processFile(path string, w io.Writer) {
title, contents := parseMarkdown(path)

codes := ""
for i, str := range contents {
if i%2 == 0 {
continue
}

code := str
varName := strings.Split(code, " ")[0]
codes += fmt.Sprintf(` func() fyne.CanvasObject {
%s
return %s
},
`, code, varName)
}

fmt.Fprintf(w, template, path, title, contents, codes)
}

func parseMarkdown(path string) (title string, sections []string) {
data, err := os.ReadFile(path)
if err != nil {
fyne.LogError("Failed to parse tutorial: "+path, err)
return "", []string{}
}

sections = strings.Split(string(data), "```")

first := strings.Split(sections[0], "\n")
title = strings.TrimSpace(first[0][1:])

sections[0] = sections[0][len(first[0])+1:]

for i, s := range sections {
sections[i] = strings.TrimSpace(s)
}

return title, sections
}
Loading
Loading