Layout

To get started, we will implement the layout. The easiest way to set this up for the application we designed is to use horizontal and vertical flow layouts. Before creating the layout, we should define those widgets that will be included. For now these are represented by the placeholders created in makeBar() and makeList()—each of which simply creates a label to show the purpose. We also want to ensure that the items are padded according to our design. To do this with Shiny, we use widget.NewPadder() and a defined unit, padSize. We also define a spaceSize used later for the central padding:

 

package main

import (
"golang.org/x/exp/shiny/driver"
"golang.org/x/exp/shiny/screen"
"golang.org/x/exp/shiny/unit"
"golang.org/x/exp/shiny/widget"
"golang.org/x/exp/shiny/widget/node"
"golang.org/x/exp/shiny/widget/theme"

"image"
"log"
"os"

_ "image/jpeg"
)

var
padSize = unit.DIPs(20)
var spaceSize = unit.DIPs(10)

func makeBar() node.Node {
bar := widget.NewUniform(theme.Neutral,
widget.NewPadder(widget.AxisBoth, padSize,
widget.NewLabel("Navigation")))

return widget.WithLayoutData(bar,
widget.FlowLayoutData{ExpandAlong: true, ExpandAcross: true})
}

func makeList() node.Node {
return widget.NewUniform(theme.Background, widget.NewLabel("File list"))
}

To show the image in our layout, we can use widget.Image, but first we need to load an image from the filesystem—a helper function, loadImage(), is defined to handle this for the application. When loading an image, don't forget to import the appropriate decoder (in this case, image/jpeg):

func loadImage(name string) image.Image {
reader, err := os.Open(name)
if err != nil {
log.Fatal(err)
}
defer reader.Close()

image, _, err := image.Decode(reader)
if err != nil {
log.Fatal(err)
}

return image
}

With that in place, we're ready to implement the layout. The main method constructs the widget tree and creates widget.Sheet to manage their rendering. This is passed to widget.RunWindow() to show the contents and run the application. The main layout elements are body (a horizontal flow) and container (the vertical flow, containing the navigation and the body). Note how a nil child is passed to widget.NewPadder() between the file list and the image viewer to approximate widget spacing. You can also see that the child widget of  sheet is actually a theme.Background colored rectangle created using widget.NewUniform() – this helps to ensure that we have a consistent background color if any widgets leave part of their area unpainted. The container then fills the space by being the uniform's child widget:

func main() {
driver.Main(func(s screen.Screen) {
image := loadImage("shiny-hall.jpg")

body := widget.NewFlow(widget.AxisHorizontal, makeList(),
widget.NewPadder(widget.AxisHorizontal, spaceSize, nil),
widget.NewImage(image, image.Bounds()))
container := widget.NewFlow(widget.AxisVertical, makeBar(),
widget.NewPadder(widget.AxisBoth, padSize, body))
sheet := widget.NewSheet(widget.NewUniform(theme.Background, container))

container.Measure(theme.Default, 0, 0)
if err := widget.RunWindow(s, sheet, &widget.RunWindowOptions{
NewWindowOptions: screen.NewWindowOptions{
Title: "GoImages",
Width: container.MeasuredSize.X,
Height: container.MeasuredSize.Y,
},
}); err != nil {
log.Fatal(err)
}
})
}

Running the preceding code should result in a window showing the following contents, which broadly matches the layout we designed before. As we progress through this chapter, we will add the content to each area and polish each part of the interface:

The GoImages layout with the navigation bar and file list placeholders
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.235.62