Skip to content

Commit

Permalink
Merge pull request #55 from pbrown12303/diagramwidget
Browse files Browse the repository at this point in the history
DiagramWidget
  • Loading branch information
andydotxyz authored Oct 18, 2023
2 parents d8410f3 + bc06b79 commit e7104b0
Show file tree
Hide file tree
Showing 29 changed files with 4,254 additions and 11 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ Session.vim
tags
# Persistent undo
[._]*.un~
*.exe
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Diagram Widget: Charles Daniels and Paul C. Brown
54 changes: 43 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,33 @@ layout := NewResponsiveLayout(

## Widgets

Community contributed widgets.
This package contains a collection of community-contributed widgets for the [Fyne](https://fyne.io/)
toolkit. The code here is intended to be production ready, but may be lacking
some desirable functional features. If you have suggestions for changes to
existing functionality or addition of new functionality, please look at the existing
issues in the repository to see if your idea is already on the table. If it is not,
feel free to open an issue.

This collection should be considered a work in progress. When changes are made,
serious consideration will be given to backward compatibility, but compatibility
is not guaranteed.

`import "fyne.io/x/fyne/widget"`

### Calendar
### Animated Gif


A widget that will run animated gifs.

<p align="center" class="align:center;margin:auto" markdown="1">
<img src="img/gifwidget.gif" />
</p>

```go
gif, err := NewAnimatedGif(storage.NewFileURI("./testdata/gif/earth.gif"))
gif.Start()
```

### Calendar

A date picker which returns a [time](https://pkg.go.dev/time) object with the selected date.

Expand All @@ -80,18 +100,30 @@ calendar := widget.NewCalendar(time.Now(), onSelected, cellSize, padding)
```
[Demo](./cmd/hexwidget_demo/main.go) available for example usage

### Animated Gif
### DiagramWidget

A widget that will run animated gifs.
The DiagramWidget provides a drawing area within which a diagram can be created. The diagram itself is a collection of
DiagramElement widgets (an interface). There are two types of DiagramElements: DiagramNode widgets and DiagramLink widgets.
DiagramNode widgets are thin wrappers around a user-supplied CanvasObject.
Any valid CanvasObject can be used. DiagramLinks are line-based connections between DiagramElements.
Note that links can connect to other links as well as nodes.

<p align="center" class="align:center;margin:auto" markdown="1">
<img src="img/gifwidget.gif" />
While some provisions have been made for automatic layout, layouts are for the convenience
of the author and are on-demand only. The design intent is that users will place the diagram elements for human readability.

DiagramElements are managed by the DiagramWidget from a layout perspective. DiagramNodes have no size
constraints imposed by the DiagramWidget and can be placed anywhere. DiagramLinks connect
DiagramElements. The DiagramWidget keeps track of the DiagramElements to which each DiagramLink
is connected and calls the Refresh() method on the link when the connected diagram element is moved
or resized.

* [demo](./cmd/diagramdemo/main.go)
* [More Detail](./widget/diagramwidget/README.md)

<p align="center" markdown="1" style="max-width: 100%">
<img src="img/diagramdemo.png" width="1024" height="880" alt="Diagram Widget" style="max-width: 100%" />
</p>

```go
gif, err := NewAnimatedGif(storage.NewFileURI("./testdata/gif/earth.gif"))
gif.Start()
```

### FileTree

Expand Down
184 changes: 184 additions & 0 deletions cmd/diagramdemo/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package main

import (
"fmt"
"image/color"
"time"

"fyne.io/x/fyne/widget/diagramwidget"

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

var forceticks int = 0

func forceanim(diagramWidget *diagramwidget.DiagramWidget) {

for {
if forceticks > 0 {
diagramwidget.StepForceLayout(diagramWidget, 300)
diagramWidget.Refresh()
forceticks--
fmt.Printf("forceticks=%d\n", forceticks)
}

time.Sleep(time.Millisecond * (1000 / 30))
}
}

func main() {
app := app.New()
w := app.NewWindow("Diagram Demo")

w.SetMaster()

diagramWidget := diagramwidget.NewDiagramWidget("Diagram1")

scrollContainer := container.NewScroll(diagramWidget)

go forceanim(diagramWidget)

// Node 0
node0Label := widget.NewLabel("Node0")
node0 := diagramwidget.NewDiagramNode(diagramWidget, node0Label, "Node0")
node0.Move(fyne.NewPos(300, 0))

// Node 1
node1Button := widget.NewButton("Node1 Button", func() { fmt.Printf("tapped Node1!\n") })
node1 := diagramwidget.NewDiagramNode(diagramWidget, node1Button, "Node1")
node1.Move(fyne.Position{X: 100, Y: 100})

// Node 2
node2 := diagramwidget.NewDiagramNode(diagramWidget, nil, "Node2")
node2Container := container.NewVBox(
widget.NewLabel("Node2 - with structure"),
widget.NewButton("Up", func() {
node2.GetDiagram().DisplaceNode(node2, fyne.Position{X: 0, Y: -10})
node2.Refresh()
}),
widget.NewButton("Down", func() {
node2.GetDiagram().DisplaceNode(node2, fyne.Position{X: 0, Y: 10})
node2.Refresh()
}),
container.NewHBox(
widget.NewButton("Left", func() {
node2.GetDiagram().DisplaceNode(node2, fyne.Position{X: -10, Y: 0})
node2.Refresh()
}),
widget.NewButton("Right", func() {
node2.GetDiagram().DisplaceNode(node2, fyne.Position{X: 10, Y: 0})
node2.Refresh()
}),
),
)
node2.SetInnerObject(node2Container)
node2.Move(fyne.Position{X: 100, Y: 300})

// Node 3
node3 := diagramwidget.NewDiagramNode(diagramWidget, widget.NewButton("Node3: Force layout step", func() {
diagramwidget.StepForceLayout(diagramWidget, 300)
diagramWidget.Refresh()
}), "Node3")
node3.Move(fyne.Position{X: 400, Y: 100})

// Node 4
node4 := diagramwidget.NewDiagramNode(diagramWidget, widget.NewButton("Node4: auto layout", func() {
forceticks += 100
diagramWidget.Refresh()
}), "Node4")
node4.Move(fyne.Position{X: 400, Y: 400})

node5 := diagramwidget.NewDiagramNode(diagramWidget, widget.NewLabel("Node5"), "Node5")
node5.Move(fyne.NewPos(600, 200))

// Link0
link0 := diagramwidget.NewDiagramLink(diagramWidget, "Link0")
link0.SetSourcePad(node0.GetEdgePad())
link0.SetTargetPad(node1.GetEdgePad())
link0.AddSourceAnchoredText("sourceRole", "sourceRole")
link0.AddMidpointAnchoredText("linkName", "Link 0")
solidDiamond := createDiamondDecoration()
solidDiamond.SetSolid(true)
link0.AddSourceDecoration(solidDiamond)

// Link1
link1 := diagramwidget.NewDiagramLink(diagramWidget, "Link1")
link1.SetSourcePad(node2.GetEdgePad())
link1.SetTargetPad(node1.GetEdgePad())
link1.SetForegroundColor(color.RGBA{255, 64, 64, 255})
link1.AddTargetDecoration(diagramwidget.NewArrowhead())
link1.AddTargetDecoration(diagramwidget.NewArrowhead())
link1.AddMidpointDecoration(diagramwidget.NewArrowhead())
link1.AddMidpointDecoration(diagramwidget.NewArrowhead())
link1.AddMidpointAnchoredText("linkName", "Link 1")
link1.AddSourceDecoration(diagramwidget.NewArrowhead())
link1.AddSourceDecoration(diagramwidget.NewArrowhead())

// Link2
link2 := diagramwidget.NewDiagramLink(diagramWidget, "Link2")
link2.SetSourcePad(node0.GetEdgePad())
link2.SetTargetPad(node3.GetEdgePad())
link2.AddMidpointAnchoredText("linkName", "Link 2")
link2.AddSourceDecoration(createHalfArrowDecoration())

// Link3
link3 := diagramwidget.NewDiagramLink(diagramWidget, "Link3")
link3.SetSourcePad(node2.GetEdgePad())
link3.SetTargetPad(node3.GetEdgePad())
link3.AddSourceAnchoredText("sourceRole", "sourceRole")
link3.AddMidpointAnchoredText("linkName", "Link 3")
link3.AddTargetAnchoredText("targetRole", "targetRole")
link3.AddMidpointDecoration(createTriangleDecoration())

// Link4
link4 := diagramwidget.NewDiagramLink(diagramWidget, "Link4")
link4.SetSourcePad(node4.GetEdgePad())
link4.SetTargetPad(node3.GetEdgePad())
link4.AddMidpointAnchoredText("linkName", "Link 4")

// Link5
link5 := diagramwidget.NewDiagramLink(diagramWidget, "Link5")
link5.SetSourcePad(link4.GetMidPad())
link5.SetTargetPad(node5.GetEdgePad())
link5.AddMidpointAnchoredText("linkName", "Link 5")
link5.AddTargetDecoration(diagramwidget.NewArrowhead())

w.SetContent(scrollContainer)

w.Resize(fyne.NewSize(600, 400))
w.ShowAndRun()
}

func createTriangleDecoration() diagramwidget.Decoration {
points := []fyne.Position{
{X: 0, Y: 15},
{X: 15, Y: 0},
{X: 0, Y: -15},
}
polygon := diagramwidget.NewPolygon(points)
return polygon
}

func createDiamondDecoration() diagramwidget.Decoration {
points := []fyne.Position{
{X: 0, Y: 0},
{X: 8, Y: 4},
{X: 16, Y: 0},
{X: 8, Y: -4},
}
polygon := diagramwidget.NewPolygon(points)
return polygon
}

func createHalfArrowDecoration() diagramwidget.Decoration {
points := []fyne.Position{
{X: 0, Y: 0},
{X: 16, Y: 8},
{X: 16, Y: 0},
}
polygon := diagramwidget.NewPolygon(points)
return polygon
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ require (
github.com/eclipse/paho.mqtt.golang v1.3.5
github.com/gorilla/websocket v1.4.2
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef
github.com/stretchr/testify v1.8.4
github.com/twpayne/go-geom v1.0.0
github.com/wagslane/go-password-validator v0.3.0
golang.org/x/image v0.11.0
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,10 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA=
github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg=
github.com/twpayne/go-geom v1.0.0 h1:ARrRnN4+rBX3LZFZQy9NFeXXlgQqVL4OOvAcnLdgy2g=
github.com/twpayne/go-geom v1.0.0/go.mod h1:RWsl+e3XSahOul/KH2BHCfF0QxSL4RMnMlFw/TNmET0=
github.com/twpayne/go-kml v1.0.0/go.mod h1:LlvLIQSfMqYk2O7Nx8vYAbSLv4K9rjMvLlEdUKWdjq0=
github.com/twpayne/go-polyline v1.0.0/go.mod h1:ICh24bcLYBX8CknfvNPKqoTbe+eg+MX1NPyJmSBo7pU=
github.com/urfave/cli/v2 v2.4.0/go.mod h1:NX9W0zmTvedE5oDoOMs2RTC8RvdK98NTYZE5LbaEYPg=
github.com/wagslane/go-password-validator v0.3.0 h1:vfxOPzGHkz5S146HDpavl0cw1DSVP061Ry2PX0/ON6I=
github.com/wagslane/go-password-validator v0.3.0/go.mod h1:TI1XJ6T5fRdRnHqHt14pvy1tNVnrwe7m3/f1f2fDphQ=
Expand Down
Binary file added img/diagramdemo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit e7104b0

Please sign in to comment.