9 changed files with 374 additions and 7 deletions
@ -0,0 +1,29 @@ |
|||
# Frame Placement Example |
|||
|
|||
 |
|||
|
|||
## About |
|||
|
|||
This demonstrates using the Place() method of the MainWindow and Frame to |
|||
position widgets around the window. The MainWindow itself and two child frames |
|||
(red and blue) are given the same set of buttons, placed relative to their own |
|||
parent widget. |
|||
|
|||
The options for frame placing are: |
|||
|
|||
* **Point:** Absolute X,Y coordinate relative to parent |
|||
* **Side:** binding the widget relative to a side of its parent. |
|||
* Top, Bottom, Left and Right to anchor to a side. In Bottom and Right, the |
|||
child widget's size is taken into account, so the right edge of the widget |
|||
would be `Right` pixels from the parent's right edge. |
|||
* Center and Middle options allow to anchor it to the center horizontally or |
|||
middle vertically. |
|||
|
|||
Click any button and the title bar will update to show the name of the |
|||
button clicked and which parent it belonged to. |
|||
|
|||
## Run it |
|||
|
|||
``` |
|||
go run main.go |
|||
``` |
@ -0,0 +1,144 @@ |
|||
// Example script for using the Place strategy of ui.Frame.
|
|||
package main |
|||
|
|||
import ( |
|||
"git.kirsle.net/go/render" |
|||
"git.kirsle.net/go/ui" |
|||
) |
|||
|
|||
func main() { |
|||
mw, err := ui.NewMainWindow("Frame Placement Demo | Click a Button", 800, 600) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
mw.SetBackground(render.White) |
|||
|
|||
// Create a sub-frame with its own buttons packed within.
|
|||
frame := ui.NewFrame("Blue Frame") |
|||
frame.Configure(ui.Config{ |
|||
Width: 300, |
|||
Height: 150, |
|||
Background: render.DarkBlue, |
|||
BorderSize: 1, |
|||
BorderStyle: ui.BorderSunken, |
|||
}) |
|||
mw.Place(frame, ui.Place{ |
|||
Point: render.NewPoint(80, 80), |
|||
}) |
|||
|
|||
// Create another frame that attaches itself to the bottom right
|
|||
// of the window.
|
|||
frame2 := ui.NewFrame("Red Frame") |
|||
frame2.Configure(ui.Config{ |
|||
Width: 300, |
|||
Height: 150, |
|||
Background: render.DarkRed, |
|||
}) |
|||
mw.Place(frame2, ui.Place{ |
|||
Right: 80, |
|||
Bottom: 80, |
|||
}) |
|||
|
|||
// Draw rings of buttons around various widgets. The buttons say things
|
|||
// like "Top Left", "Top Center", "Left Middle", "Center" etc. encompassing
|
|||
// all 9 side placement options.
|
|||
CreateButtons(mw, frame) |
|||
CreateButtons(mw, frame2) |
|||
CreateButtons(mw, mw.Frame()) |
|||
|
|||
mw.MainLoop() |
|||
} |
|||
|
|||
// CreateButtons creates a set of Placed buttons around all the edges and
|
|||
// center of the parent frame.
|
|||
func CreateButtons(window *ui.MainWindow, parent *ui.Frame) { |
|||
// Draw buttons around the edges of the window.
|
|||
buttons := []struct { |
|||
Label string |
|||
Place ui.Place |
|||
}{ |
|||
{ |
|||
Label: "Top Left", |
|||
Place: ui.Place{ |
|||
Point: render.NewPoint(12, 12), |
|||
}, |
|||
}, |
|||
{ |
|||
Label: "Top Middle", |
|||
Place: ui.Place{ |
|||
Top: 12, |
|||
Center: true, |
|||
}, |
|||
}, |
|||
{ |
|||
Label: "Top Right", |
|||
Place: ui.Place{ |
|||
Top: 12, |
|||
Right: 12, |
|||
}, |
|||
}, |
|||
{ |
|||
Label: "Left Middle", |
|||
Place: ui.Place{ |
|||
Left: 12, |
|||
Middle: true, |
|||
}, |
|||
}, |
|||
{ |
|||
Label: "Center", |
|||
Place: ui.Place{ |
|||
Center: true, |
|||
Middle: true, |
|||
}, |
|||
}, |
|||
{ |
|||
Label: "Right Middle", |
|||
Place: ui.Place{ |
|||
Right: 12, |
|||
Middle: true, |
|||
}, |
|||
}, |
|||
{ |
|||
Label: "Bottom Left", |
|||
Place: ui.Place{ |
|||
Left: 12, |
|||
Bottom: 12, |
|||
}, |
|||
}, |
|||
{ |
|||
Label: "Bottom Center", |
|||
Place: ui.Place{ |
|||
Bottom: 12, |
|||
Center: true, |
|||
}, |
|||
}, |
|||
{ |
|||
Label: "Bottom Right", |
|||
Place: ui.Place{ |
|||
Bottom: 12, |
|||
Right: 12, |
|||
}, |
|||
}, |
|||
} |
|||
for _, setting := range buttons { |
|||
setting := setting |
|||
|
|||
button := ui.NewButton(setting.Label, ui.NewLabel(ui.Label{ |
|||
Text: setting.Label, |
|||
Font: render.Text{ |
|||
FontFilename: "../DejaVuSans.ttf", |
|||
Size: 12, |
|||
Color: render.Black, |
|||
}, |
|||
})) |
|||
|
|||
// When clicked, change the window title to ID this button.
|
|||
button.Handle(ui.Click, func(p render.Point) { |
|||
window.SetTitle(parent.Name + ": " + setting.Label) |
|||
}) |
|||
|
|||
parent.Place(button, setting.Place) |
|||
window.Add(button) |
|||
} |
|||
} |
After Width: | Height: | Size: 23 KiB |
@ -0,0 +1,97 @@ |
|||
package ui |
|||
|
|||
import ( |
|||
"git.kirsle.net/go/render" |
|||
) |
|||
|
|||
// Place provides configuration fields for Frame.Place().
|
|||
type Place struct { |
|||
// X and Y coordinates for explicit location of widget within its parent.
|
|||
// This placement option trumps all others.
|
|||
Point render.Point |
|||
|
|||
// Place relative to an edge of the window. The widget will stick to the
|
|||
// edge of the window even as it resizes. Options are ignored if Point
|
|||
// is set.
|
|||
Top int |
|||
Left int |
|||
Right int |
|||
Bottom int |
|||
Center bool |
|||
Middle bool |
|||
} |
|||
|
|||
// Strategy returns the placement strategy for a Place config struct.
|
|||
// Returns 'Point' if a render.Point is used (even if zero, zero)
|
|||
// Returns 'Side' if the side values are set.
|
|||
func (p Place) Strategy() string { |
|||
if p.Top != 0 || p.Left != 0 || p.Right != 0 || p.Bottom != 0 || p.Center || p.Middle { |
|||
return "Side" |
|||
} |
|||
return "Point" |
|||
} |
|||
|
|||
// placedWidget holds the data for a widget placed in a frame.
|
|||
type placedWidget struct { |
|||
widget Widget |
|||
place Place |
|||
} |
|||
|
|||
// Place a widget into the frame.
|
|||
func (w *Frame) Place(child Widget, config Place) { |
|||
w.placed = append(w.placed, placedWidget{ |
|||
widget: child, |
|||
place: config, |
|||
}) |
|||
w.widgets = append(w.widgets, child) |
|||
|
|||
// Adopt the child widget so it can access the Frame.
|
|||
child.SetParent(w) |
|||
} |
|||
|
|||
// computePlaced processes all the Place layout widgets in the Frame,
|
|||
// determining their X,Y location and whether they need to change.
|
|||
func (w *Frame) computePlaced(e render.Engine) { |
|||
var ( |
|||
frameSize = w.BoxSize() |
|||
) |
|||
|
|||
for _, row := range w.placed { |
|||
// X,Y placement takes priority.
|
|||
switch row.place.Strategy() { |
|||
case "Point": |
|||
row.widget.MoveTo(row.place.Point) |
|||
case "Side": |
|||
var moveTo render.Point |
|||
|
|||
// Compute the initial X,Y based on Top, Left, Right, Bottom.
|
|||
if row.place.Left > 0 { |
|||
moveTo.X = row.place.Left |
|||
} |
|||
if row.place.Top > 0 { |
|||
moveTo.Y = row.place.Top |
|||
} |
|||
if row.place.Right > 0 { |
|||
moveTo.X = frameSize.W - row.widget.Size().W - row.place.Right |
|||
} |
|||
if row.place.Bottom > 0 { |
|||
moveTo.Y = frameSize.H - row.widget.Size().H - row.place.Bottom |
|||
} |
|||
|
|||
// Center and Middle aligned values override Left/Right, Top/Bottom
|
|||
// settings respectively.
|
|||
if row.place.Center { |
|||
moveTo.X = frameSize.W - (w.Size().W / 2) - (row.widget.Size().W / 2) |
|||
} |
|||
if row.place.Middle { |
|||
moveTo.Y = frameSize.H - (w.Size().H / 2) - (row.widget.Size().H / 2) |
|||
} |
|||
row.widget.MoveTo(moveTo) |
|||
} |
|||
|
|||
// If this widget itself has placed widgets, call its function too.
|
|||
if frame, ok := row.widget.(*Frame); ok { |
|||
frame.computePlaced(e) |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,9 @@ |
|||
module git.kirsle.net/go/ui |
|||
|
|||
go 1.13 |
|||
|
|||
require ( |
|||
git.kirsle.net/go/render v0.0.0-20200102014411-4d008b5c468d |
|||
github.com/veandco/go-sdl2 v0.4.1 // indirect |
|||
golang.org/x/image v0.0.0-20200119044424-58c23975cae1 // indirect |
|||
) |
@ -0,0 +1,7 @@ |
|||
git.kirsle.net/go/render v0.0.0-20200102014411-4d008b5c468d h1:vErak6oVRT2dosyQzcwkjXyWQ2NRIVL8q9R8NOUTtsg= |
|||
git.kirsle.net/go/render v0.0.0-20200102014411-4d008b5c468d/go.mod h1:ywZtC+zE2SpeObfkw0OvG01pWHQadsVQ4WDKOYzaejc= |
|||
github.com/veandco/go-sdl2 v0.4.1 h1:HmSBvVmKWI8LAOeCfTTM8R33rMyPcs6U3o8n325c9Qg= |
|||
github.com/veandco/go-sdl2 v0.4.1/go.mod h1:FB+kTpX9YTE+urhYiClnRzpOXbiWgaU3+5F2AB78DPg= |
|||
golang.org/x/image v0.0.0-20200119044424-58c23975cae1 h1:5h3ngYt7+vXCDZCup/HkCQgW5XwmSvR/nA2JmJ0RErg= |
|||
golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= |
|||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
Loading…
Reference in new issue