11 changed files with 534 additions and 22 deletions
@ -0,0 +1,11 @@ |
|||
.PHONY: run |
|||
run: |
|||
go run main.go |
|||
|
|||
.PHONY: wasm |
|||
wasm: |
|||
GOOS=js GOARCH=wasm go build -v -o windows.wasm main_wasm.go |
|||
|
|||
.PHONY: wasm-serve |
|||
wasm-serve: wasm |
|||
../wasm-common/serve.sh |
@ -0,0 +1,107 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"os" |
|||
|
|||
"git.kirsle.net/go/render" |
|||
"git.kirsle.net/go/render/event" |
|||
"git.kirsle.net/go/render/sdl" |
|||
"git.kirsle.net/go/ui" |
|||
"git.kirsle.net/go/ui/theme" |
|||
) |
|||
|
|||
// Program globals.
|
|||
var ( |
|||
// Size of the MainWindow.
|
|||
Width = 1024 |
|||
Height = 768 |
|||
) |
|||
|
|||
func init() { |
|||
sdl.DefaultFontFilename = "../DejaVuSans.ttf" |
|||
} |
|||
|
|||
func main() { |
|||
mw, err := ui.NewMainWindow("Theme Demo", Width, Height) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
// Menu bar.
|
|||
menu := ui.NewMenuBar("Main Menu") |
|||
file := menu.AddMenu("Select Theme") |
|||
file.AddItem("Default", func() { |
|||
addWindow(mw, theme.Default) |
|||
}) |
|||
file.AddItem("DefaultFlat", func() { |
|||
addWindow(mw, theme.DefaultFlat) |
|||
}) |
|||
file.AddItem("DefaultDark", func() { |
|||
addWindow(mw, theme.DefaultDark) |
|||
}) |
|||
|
|||
menu.Supervise(mw.Supervisor()) |
|||
menu.Compute(mw.Engine) |
|||
mw.Pack(menu, menu.PackTop()) |
|||
|
|||
mw.SetBackground(render.White) |
|||
|
|||
mw.OnLoop(func(e *event.State) { |
|||
if e.Escape { |
|||
os.Exit(0) |
|||
} |
|||
}) |
|||
|
|||
mw.MainLoop() |
|||
} |
|||
|
|||
// Add a new child window.
|
|||
func addWindow(mw *ui.MainWindow, theme theme.Theme) { |
|||
ui.Theme = theme |
|||
|
|||
win1 := ui.NewWindow(theme.Name) |
|||
win1.SetButtons(ui.CloseButton) |
|||
win1.Configure(ui.Config{ |
|||
Width: 320, |
|||
Height: 240, |
|||
}) |
|||
win1.Compute(mw.Engine) |
|||
win1.Supervise(mw.Supervisor()) |
|||
|
|||
// Draw a label.
|
|||
label := ui.NewLabel(ui.Label{ |
|||
Text: theme.Name, |
|||
}) |
|||
win1.Place(label, ui.Place{ |
|||
Top: 10, |
|||
Left: 10, |
|||
}) |
|||
|
|||
// Add a button with tooltip.
|
|||
btn2 := ui.NewButton(theme.Name+":Button2", ui.NewLabel(ui.Label{ |
|||
Text: "Button", |
|||
})) |
|||
btn2.Handle(ui.Click, func(ed ui.EventData) error { |
|||
return nil |
|||
}) |
|||
mw.Add(btn2) |
|||
win1.Place(btn2, ui.Place{ |
|||
Top: 10, |
|||
Right: 10, |
|||
}) |
|||
ui.NewTooltip(btn2, ui.Tooltip{ |
|||
Text: "Hello world!", |
|||
Edge: ui.Bottom, |
|||
}) |
|||
|
|||
// Add a checkbox.
|
|||
var b bool |
|||
cb := ui.NewCheckbox("Checkbox", &b, ui.NewLabel(ui.Label{ |
|||
Text: "Check me!", |
|||
})) |
|||
mw.Add(cb) |
|||
win1.Place(cb, ui.Place{ |
|||
Top: 30, |
|||
Left: 10, |
|||
}) |
|||
} |
@ -0,0 +1,169 @@ |
|||
// +build js,wasm
|
|||
|
|||
// WebAssembly version of the window manager demo.
|
|||
// To build: make wasm
|
|||
// To test: make wasm-serve
|
|||
|
|||
package main |
|||
|
|||
import ( |
|||
"fmt" |
|||
"time" |
|||
|
|||
"git.kirsle.net/go/render" |
|||
"git.kirsle.net/go/render/canvas" |
|||
"git.kirsle.net/go/ui" |
|||
) |
|||
|
|||
// Program globals.
|
|||
var ( |
|||
ThrottleFPS = 1000 / 60 |
|||
|
|||
// Size of the MainWindow.
|
|||
Width = 1024 |
|||
Height = 768 |
|||
|
|||
// Cascade offset for creating multiple windows.
|
|||
Cascade = render.NewPoint(10, 32) |
|||
CascadeStep = render.NewPoint(24, 24) |
|||
CascadeLoops = 1 |
|||
|
|||
// Colors for each window created.
|
|||
WindowColors = []render.Color{ |
|||
render.Blue, |
|||
render.Red, |
|||
render.DarkYellow, |
|||
render.DarkGreen, |
|||
render.DarkCyan, |
|||
render.DarkBlue, |
|||
render.DarkRed, |
|||
} |
|||
WindowID int |
|||
OpenWindows int |
|||
) |
|||
|
|||
func main() { |
|||
mw, err := canvas.New("canvas") |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
// Bind DOM event handlers.
|
|||
mw.AddEventListeners() |
|||
|
|||
supervisor := ui.NewSupervisor() |
|||
|
|||
frame := ui.NewFrame("Main Frame") |
|||
frame.Resize(render.NewRect(mw.WindowSize())) |
|||
frame.Compute(mw) |
|||
|
|||
_, height := mw.WindowSize() |
|||
lbl := ui.NewLabel(ui.Label{ |
|||
Text: "Window Manager Demo", |
|||
Font: render.Text{ |
|||
FontFilename: "DejaVuSans.ttf", |
|||
Size: 32, |
|||
Color: render.SkyBlue, |
|||
Shadow: render.SkyBlue.Darken(60), |
|||
}, |
|||
}) |
|||
lbl.Compute(mw) |
|||
lbl.MoveTo(render.NewPoint( |
|||
20, |
|||
height-lbl.Size().H-20, |
|||
)) |
|||
|
|||
// Menu bar.
|
|||
menu := ui.NewMenuBar("Main Menu") |
|||
file := menu.AddMenu("Options") |
|||
file.AddItem("New window", func() { |
|||
addWindow(mw, frame, supervisor) |
|||
}) |
|||
file.AddItem("Close all windows", func() { |
|||
OpenWindows -= supervisor.CloseAllWindows() |
|||
}) |
|||
|
|||
menu.Supervise(supervisor) |
|||
menu.Compute(mw) |
|||
frame.Pack(menu, menu.PackTop()) |
|||
|
|||
// Add some windows to play with.
|
|||
addWindow(mw, frame, supervisor) |
|||
addWindow(mw, frame, supervisor) |
|||
|
|||
for { |
|||
mw.Clear(render.RGBA(255, 255, 200, 255)) |
|||
start := time.Now() |
|||
ev, err := mw.Poll() |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
frame.Present(mw, frame.Point()) |
|||
lbl.Present(mw, lbl.Point()) |
|||
supervisor.Loop(ev) |
|||
supervisor.Present(mw) |
|||
|
|||
var delay uint32 |
|||
elapsed := time.Now().Sub(start) |
|||
tmp := elapsed / time.Millisecond |
|||
if ThrottleFPS-int(tmp) > 0 { |
|||
delay = uint32(ThrottleFPS - int(tmp)) |
|||
} |
|||
mw.Delay(delay) |
|||
} |
|||
} |
|||
|
|||
// Add a new child window.
|
|||
func addWindow(engine render.Engine, parent *ui.Frame, sup *ui.Supervisor) { |
|||
var ( |
|||
color = WindowColors[WindowID%len(WindowColors)] |
|||
title = fmt.Sprintf("Window %d", WindowID+1) |
|||
) |
|||
WindowID++ |
|||
|
|||
win1 := ui.NewWindow(title) |
|||
win1.SetButtons(ui.CloseButton) |
|||
win1.ActiveTitleBackground = color |
|||
win1.InactiveTitleBackground = color.Darken(60) |
|||
win1.InactiveTitleForeground = render.Grey |
|||
win1.Configure(ui.Config{ |
|||
Width: 320, |
|||
Height: 240, |
|||
}) |
|||
win1.Compute(engine) |
|||
win1.Supervise(sup) |
|||
|
|||
// Re-open a window when the last one is closed.
|
|||
OpenWindows++ |
|||
win1.Handle(ui.CloseWindow, func(ed ui.EventData) error { |
|||
OpenWindows-- |
|||
if OpenWindows <= 0 { |
|||
addWindow(engine, parent, sup) |
|||
} |
|||
return nil |
|||
}) |
|||
|
|||
// Default placement via cascade.
|
|||
win1.MoveTo(Cascade) |
|||
Cascade.Add(CascadeStep) |
|||
if Cascade.Y > Height-240-64 { |
|||
CascadeLoops++ |
|||
Cascade.Y = 24 |
|||
Cascade.X = 24 * CascadeLoops |
|||
} |
|||
|
|||
// Add a window duplicator button.
|
|||
btn2 := ui.NewButton(title+":Button2", ui.NewLabel(ui.Label{ |
|||
Text: "New Window", |
|||
})) |
|||
btn2.Handle(ui.Click, func(ed ui.EventData) error { |
|||
addWindow(engine, parent, sup) |
|||
return nil |
|||
}) |
|||
sup.Add(btn2) |
|||
win1.Place(btn2, ui.Place{ |
|||
Top: 10, |
|||
Right: 10, |
|||
}) |
|||
} |
@ -0,0 +1,71 @@ |
|||
// Package style provides style definitions for UI components.
|
|||
package style |
|||
|
|||
import "git.kirsle.net/go/render" |
|||
|
|||
// Default styles for widgets without a theme.
|
|||
var ( |
|||
DefaultWindow = Window{ |
|||
ActiveTitleBackground: render.Blue, |
|||
ActiveTitleForeground: render.White, |
|||
InactiveTitleBackground: render.DarkGrey, |
|||
InactiveTitleForeground: render.Grey, |
|||
ActiveBackground: render.Grey, |
|||
InactiveBackground: render.Grey, |
|||
} |
|||
|
|||
DefaultLabel = Label{ |
|||
Background: render.Invisible, |
|||
Foreground: render.Black, |
|||
} |
|||
|
|||
DefaultButton = Button{ |
|||
Background: render.RGBA(200, 200, 200, 255), |
|||
Foreground: render.Black, |
|||
OutlineColor: render.Black, |
|||
OutlineSize: 1, |
|||
HoverBackground: render.RGBA(200, 255, 255, 255), |
|||
HoverForeground: render.Black, |
|||
BorderStyle: BorderRaised, |
|||
BorderSize: 2, |
|||
} |
|||
|
|||
DefaultTooltip = Tooltip{ |
|||
Background: render.RGBA(0, 0, 0, 230), |
|||
Foreground: render.White, |
|||
} |
|||
) |
|||
|
|||
// Window style configuration.
|
|||
type Window struct { |
|||
ActiveTitleBackground render.Color |
|||
ActiveTitleForeground render.Color |
|||
ActiveBackground render.Color |
|||
InactiveTitleBackground render.Color |
|||
InactiveTitleForeground render.Color |
|||
InactiveBackground render.Color |
|||
} |
|||
|
|||
// Label style configuration.
|
|||
type Label struct { |
|||
Background render.Color |
|||
Foreground render.Color |
|||
} |
|||
|
|||
// Button style configuration.
|
|||
type Button struct { |
|||
Background render.Color |
|||
Foreground render.Color // Labels only
|
|||
OutlineColor render.Color |
|||
OutlineSize int |
|||
HoverBackground render.Color |
|||
HoverForeground render.Color |
|||
BorderStyle BorderStyle |
|||
BorderSize int |
|||
} |
|||
|
|||
// Tooltip style configuration.
|
|||
type Tooltip struct { |
|||
Background render.Color |
|||
Foreground render.Color |
|||
} |
@ -0,0 +1,13 @@ |
|||
// Package style provides style definitions for UI components.
|
|||
package style |
|||
|
|||
// BorderStyle options for widget.SetBorderStyle()
|
|||
type BorderStyle string |
|||
|
|||
// Styles for a widget border.
|
|||
const ( |
|||
BorderNone BorderStyle = "" |
|||
BorderSolid BorderStyle = "solid" |
|||
BorderRaised = "raised" |
|||
BorderSunken = "sunken" |
|||
) |
@ -0,0 +1,6 @@ |
|||
package ui |
|||
|
|||
import "git.kirsle.net/go/ui/theme" |
|||
|
|||
// Theme sets the default theme used when creating new widgets.
|
|||
var Theme = theme.Default |
Loading…
Reference in new issue