Added demo
|  | @ -4,7 +4,6 @@ | |||
| *.dll | ||||
| *.so | ||||
| *.dylib | ||||
| demo | ||||
| 
 | ||||
| # Test binary, build with `go test -c` | ||||
| *.test | ||||
|  |  | |||
|  | @ -0,0 +1,16 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const absoluteLayoutDemoText = ` | ||||
| AbsoluteLayout { | ||||
| 	width = 100%, height = 100%, | ||||
| 	content = [ View { id = view1, width = 32px, height = 32px, left = 100px, top = 200px, background-color = #FF0000FF } ] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createAbsoluteLayoutDemo(session rui.Session) rui.View { | ||||
| 	return rui.CreateViewFromText(session, absoluteLayoutDemoText) | ||||
| } | ||||
|  | @ -0,0 +1,142 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const audioPlayerDemoText = ` | ||||
| GridLayout { | ||||
| 	cell-height = "auto, auto, 1fr, auto", width = 100%, height = 100%, | ||||
| 	content = [ | ||||
| 		ListLayout { | ||||
| 			row = 0, orientation = start-to-end, padding = 4px, | ||||
| 			content = [ | ||||
| 				Checkbox {  | ||||
| 					id = showAudioPlayerControls, content = "Controls" | ||||
| 				}, | ||||
| 				Checkbox {  | ||||
| 					id = showAudioPlayerLoop, content = "Loop" | ||||
| 				}, | ||||
| 				Checkbox {  | ||||
| 					id = showAudioPlayerMuted, content = "Muted" | ||||
| 				}, | ||||
| 			], | ||||
| 		}, | ||||
| 		AudioPlayer { | ||||
| 			row = 1, id = audioPlayer, src = "https://alxanosoft.com/jazzy-loop-1.mp3",  | ||||
| 		}, | ||||
| 		ListLayout { | ||||
| 			row = 2, orientation = start-to-end, vertical-align = top, padding = 8px, | ||||
| 			content = [ | ||||
| 				NumberPicker { | ||||
| 					id = audioPlayerSlider, width = 200px, type = slider | ||||
| 				} | ||||
| 				Button { | ||||
| 					id = audioPlayerPlay, content = "Play", margin-left = 16px | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		Resizable { | ||||
| 			row = 3, side = top, background-color = lightgrey, height = 200px, | ||||
| 			content = EditView { | ||||
| 				id = audioPlayerEventsLog, type = multiline, read-only = true, wrap = true, | ||||
| 			} | ||||
| 		}, | ||||
| 	] | ||||
| }` | ||||
| 
 | ||||
| var audioPlayerPause = true | ||||
| 
 | ||||
| func createAudioPlayerDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, audioPlayerDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	createListener := func(event string) func() { | ||||
| 		return func() { | ||||
| 			rui.AppendEditText(view, "audioPlayerEventsLog", event+"\n") | ||||
| 			rui.ScrollViewToEnd(view, "audioPlayerEventsLog") | ||||
| 		} | ||||
| 	} | ||||
| 	createListener2 := func(event string) func(value float64) { | ||||
| 		return func(value float64) { | ||||
| 			rui.AppendEditText(view, "audioPlayerEventsLog", fmt.Sprintf("%s: %g\n", event, value)) | ||||
| 			rui.ScrollViewToEnd(view, "audioPlayerEventsLog") | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "showAudioPlayerControls", rui.CheckboxChangedEvent, func(state bool) { | ||||
| 		rui.Set(view, "audioPlayer", rui.Controls, state) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "showAudioPlayerLoop", rui.CheckboxChangedEvent, func(state bool) { | ||||
| 		rui.Set(view, "audioPlayer", rui.Loop, state) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "showAudioPlayerMuted", rui.CheckboxChangedEvent, func(state bool) { | ||||
| 		rui.Set(view, "audioPlayer", rui.Muted, state) | ||||
| 	}) | ||||
| 
 | ||||
| 	for _, event := range []string{rui.AbortEvent, rui.CanPlayEvent, rui.CanPlayThroughEvent, | ||||
| 		rui.CompleteEvent, rui.EmptiedEvent, rui.EndedEvent, rui.LoadStartEvent, | ||||
| 		rui.LoadedMetadataEvent, rui.PlayingEvent, rui.SeekedEvent, rui.SeekingEvent, | ||||
| 		rui.StalledEvent, rui.SuspendEvent, rui.WaitingEvent} { | ||||
| 
 | ||||
| 		rui.Set(view, "audioPlayer", event, createListener(event)) | ||||
| 	} | ||||
| 
 | ||||
| 	for _, event := range []string{rui.DurationChangedEvent, rui.RateChangedEvent, rui.VolumeChangedEvent} { | ||||
| 
 | ||||
| 		rui.Set(view, "audioPlayer", event, createListener2(event)) | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "audioPlayer", rui.PlayEvent, func() { | ||||
| 		rui.AppendEditText(view, "audioPlayerEventsLog", "play-event\n") | ||||
| 		rui.ScrollViewToEnd(view, "audioPlayerEventsLog") | ||||
| 		rui.Set(view, "audioPlayerPlay", rui.Content, "Pause") | ||||
| 		audioPlayerPause = false | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "audioPlayer", rui.PauseEvent, func() { | ||||
| 		rui.AppendEditText(view, "audioPlayerEventsLog", "pause-event\n") | ||||
| 		rui.ScrollViewToEnd(view, "audioPlayerEventsLog") | ||||
| 		rui.Set(view, "audioPlayerPlay", rui.Content, "Play") | ||||
| 		audioPlayerPause = true | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "audioPlayer", rui.LoadedDataEvent, func() { | ||||
| 		rui.AppendEditText(view, "audioPlayerEventsLog", "loaded-data-event\n") | ||||
| 		rui.ScrollViewToEnd(view, "audioPlayerEventsLog") | ||||
| 		rui.Set(view, "audioPlayerSlider", rui.Max, rui.MediaPlayerDuration(view, "audioPlayer")) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "audioPlayer", rui.TimeUpdateEvent, func(time float64) { | ||||
| 		rui.AppendEditText(view, "audioPlayerEventsLog", fmt.Sprintf("time-update-event %gs\n", time)) | ||||
| 		rui.ScrollViewToEnd(view, "audioPlayerEventsLog") | ||||
| 		rui.Set(view, "audioPlayerSlider", rui.Value, time) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "audioPlayer", rui.PlayerErrorEvent, func(code int, message string) { | ||||
| 		rui.AppendEditText(view, "audioPlayerEventsLog", fmt.Sprintf("player-error-event: code = %d, message = '%s'\n", code, message)) | ||||
| 		rui.ScrollViewToEnd(view, "audioPlayerEventsLog") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "audioPlayerPlay", rui.ClickEvent, func() { | ||||
| 		if audioPlayerPause { | ||||
| 			rui.MediaPlayerPlay(view, "audioPlayer") | ||||
| 		} else { | ||||
| 			rui.MediaPlayerPause(view, "audioPlayer") | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "audioPlayerSlider", rui.NumberChangedEvent, func(value float64) { | ||||
| 		if audioPlayerPause { | ||||
| 			rui.SetMediaPlayerCurrentTime(view, "audioPlayer", value) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,81 @@ | |||
| package main | ||||
| 
 | ||||
| import "github.com/anoshenko/rui" | ||||
| 
 | ||||
| const backgroundDemoText = ` | ||||
| GridLayout { | ||||
| 	style = demoPage, | ||||
| 	content = [ | ||||
| 		ListLayout { | ||||
| 			width = 100%, height = 100%, padding = 32px, | ||||
| 			content = [ | ||||
| 				TextView { | ||||
| 					id = backgroundView, width = 100%, height = 150%, padding = 16px, | ||||
| 					text = "Sample text", text-size = 4em,  | ||||
| 					border = _{ style = dotted, width = 8px, color = #FF008800 }, | ||||
| 					background = image { src = cat.jpg } | ||||
| 				} | ||||
| 			] | ||||
| 		},		 | ||||
| 		ListLayout { | ||||
| 			style = optionsPanel, | ||||
| 			content = [ | ||||
| 				GridLayout { | ||||
| 					style = optionsTable, | ||||
| 					content = [ | ||||
| 						TextView { row = 0, text = "Image" }, | ||||
| 						DropDownList { row = 0, column = 1, id = backgroundImage1, current = 0, items = ["cat.jpg", "winds.png", "gifsInEmail.gif", "mountain.svg"]}, | ||||
| 						TextView { row = 1, text = "Fit" }, | ||||
| 						DropDownList { row = 1, column = 1, id = backgroundFit1, current = 0, items = ["none", "contain", "cover"]}, | ||||
| 						TextView { row = 2, text = "Horizontal align" }, | ||||
| 						DropDownList { row = 2, column = 1, id = backgroundHAlign1, current = 0, items = ["left", "right", "center"]}, | ||||
| 						TextView { row = 3, text = "Vertical align" }, | ||||
| 						DropDownList { row = 3, column = 1, id = backgroundVAlign1, current = 0, items = ["top", "bottom", "center"]}, | ||||
| 						TextView { row = 4, text = "Repeat" }, | ||||
| 						DropDownList { row = 4, column = 1, id = backgroundRepeat1, current = 0, items = ["no-repeat", "repeat", "repeat-x", "repeat-y", "round", "space"]}, | ||||
| 						TextView { row = 5, text = "Clip" }, | ||||
| 						DropDownList { row = 5, column = 1, id = backgroundClip1, current = 0, items = ["padding-box", "border-box", "content-box", "text"]}, | ||||
| 						TextView { row = 6, text = "Attachment" }, | ||||
| 						DropDownList { row = 6, column = 1, id = backgroundAttachment1, current = 0, items = ["scroll", "fixed", "local"]}, | ||||
| 					] | ||||
| 				} | ||||
| 			] | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createBackgroundDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, backgroundDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	updateBackground1 := func(list rui.DropDownList, number int) { | ||||
| 		images := []string{"cat.jpg", "winds.png", "gifsInEmail.gif", "mountain.svg"} | ||||
| 		image := rui.NewBackgroundImage(rui.Params{ | ||||
| 			rui.Source:          images[rui.GetDropDownCurrent(view, "backgroundImage1")], | ||||
| 			rui.Fit:             rui.GetDropDownCurrent(view, "backgroundFit1"), | ||||
| 			rui.HorizontalAlign: rui.GetDropDownCurrent(view, "backgroundHAlign1"), | ||||
| 			rui.VerticalAlign:   rui.GetDropDownCurrent(view, "backgroundVAlign1"), | ||||
| 			rui.Repeat:          rui.GetDropDownCurrent(view, "backgroundRepeat1"), | ||||
| 			rui.BackgroundClip:  rui.GetDropDownCurrent(view, "backgroundClip1"), | ||||
| 			rui.Attachment:      rui.GetDropDownCurrent(view, "backgroundAttachment1"), | ||||
| 		}) | ||||
| 		rui.Set(view, "backgroundView", rui.Background, image) | ||||
| 	} | ||||
| 
 | ||||
| 	for _, id := range []string{ | ||||
| 		"backgroundImage1", | ||||
| 		"backgroundFit1", | ||||
| 		"backgroundHAlign1", | ||||
| 		"backgroundVAlign1", | ||||
| 		"backgroundRepeat1", | ||||
| 		"backgroundClip1", | ||||
| 		"backgroundAttachment1", | ||||
| 	} { | ||||
| 		rui.Set(view, id, rui.DropDownEvent, updateBackground1) | ||||
| 	} | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,334 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| 	"strconv" | ||||
| 
 | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const canvasDemoText = ` | ||||
| GridLayout { | ||||
| 	width = 100%, height = 100%, cell-height = "auto, 1fr", | ||||
| 	content = [ | ||||
| 		DropDownList { | ||||
| 			id = canvasType, current = 0, margin = 8px, | ||||
| 			items = ["Image", "Rectangles & ellipse", "Text style", "Text align", "Line style", "Transformations"] | ||||
| 		}, | ||||
| 		CanvasView { | ||||
| 			id = canvas, row = 1, width = 100%, height = 100%, | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| var sampleImage rui.Image | ||||
| 
 | ||||
| func rectangleCanvasDemo(canvas rui.Canvas) { | ||||
| 	width := canvas.Width() | ||||
| 	height := canvas.Height() | ||||
| 
 | ||||
| 	canvas.Save() | ||||
| 
 | ||||
| 	canvas.SetSolidColorFillStyle(0xFF008000) | ||||
| 	canvas.SetSolidColorStrokeStyle(0xFFFF0000) | ||||
| 	w2 := width / 2 | ||||
| 	h2 := height / 2 | ||||
| 	canvas.FillRect(10, 10, w2-20, h2-20) | ||||
| 	canvas.StrokeRect(9.5, 9.5, w2-19, h2-19) | ||||
| 
 | ||||
| 	canvas.SetLinearGradientFillStyle(w2+10, 10, 0xFFFF0000, width-20, 10, 0xFF0000FF, []rui.GradientPoint{ | ||||
| 		{Offset: 0.3, Color: 0xFFFFFF00}, | ||||
| 		{Offset: 0.5, Color: 0xFF00FF00}, | ||||
| 		{Offset: 0.7, Color: 0xFF00FFFF}, | ||||
| 	}) | ||||
| 	canvas.SetLinearGradientStrokeStyle(10, 10, 0xFFFF00FF, 10, h2-20, 0xFF00FFFF, []rui.GradientPoint{ | ||||
| 		{Offset: 0.5, Color: 0xFF00FF00}, | ||||
| 	}) | ||||
| 	canvas.SetLineWidth(5) | ||||
| 	canvas.FillAndStrokeRoundedRect(w2+7.5, 7.5, w2-15, h2-15, 20) | ||||
| 
 | ||||
| 	canvas.SetRadialGradientFillStyle(w2/2-20, h2+h2/2-20, 10, 0xFFFF0000, w2/2+20, h2+h2/2+20, w2/2, 0xFF0000FF, []rui.GradientPoint{ | ||||
| 		{Offset: 0.3, Color: 0xFFFFFF00}, | ||||
| 		{Offset: 0.5, Color: 0xFF00FF00}, | ||||
| 		{Offset: 0.7, Color: 0xFF00FFFF}, | ||||
| 	}) | ||||
| 	canvas.SetRadialGradientStrokeStyle(w2/2, h2+h2/2, h2/2, 0xFFFFFF00, w2/2, h2+h2/2, h2, 0xFF00FFFF, []rui.GradientPoint{ | ||||
| 		{Offset: 0.5, Color: 0xFF00FF00}, | ||||
| 	}) | ||||
| 	canvas.SetLineWidth(7) | ||||
| 	canvas.FillAndStrokeRect(10, h2+10, w2-20, h2-20) | ||||
| 
 | ||||
| 	//canvas.SetSolidColorFillStyle(0xFF00FFFF)
 | ||||
| 	canvas.SetImageFillStyle(sampleImage, rui.RepeatXY) | ||||
| 	canvas.SetSolidColorStrokeStyle(0xFF0000FF) | ||||
| 	canvas.SetLineWidth(4) | ||||
| 	canvas.FillAndStrokeEllipse(w2+w2/2, h2+h2/2, w2/2-10, h2/2-10, 0) | ||||
| 
 | ||||
| 	canvas.Restore() | ||||
| } | ||||
| 
 | ||||
| func textCanvasDemo(canvas rui.Canvas) { | ||||
| 
 | ||||
| 	canvas.Save() | ||||
| 	canvas.SetTextAlign(rui.LeftAlign) | ||||
| 	canvas.SetTextBaseline(rui.TopBaseline) | ||||
| 
 | ||||
| 	canvas.SetSolidColorFillStyle(0xFF000000) | ||||
| 	canvas.FillText(10, 10, "Default font") | ||||
| 	canvas.StrokeText(300, 10, "Default font") | ||||
| 
 | ||||
| 	canvas.SetSolidColorFillStyle(0xFF800000) | ||||
| 	canvas.SetSolidColorStrokeStyle(0xFF800080) | ||||
| 	canvas.SetFont("courier", rui.Pt(12)) | ||||
| 	canvas.FillText(10, 30, "courier, 12pt") | ||||
| 	canvas.StrokeText(300, 30, "courier, 12pt") | ||||
| 
 | ||||
| 	canvas.SetSolidColorFillStyle(0xFF008000) | ||||
| 	canvas.SetSolidColorStrokeStyle(0xFF008080) | ||||
| 	canvas.SetFontWithParams("Courier new, courier", rui.Pt(12), rui.FontParams{ | ||||
| 		Italic: true, | ||||
| 	}) | ||||
| 	canvas.FillText(10, 50, `Courier new, 12pt, italic`) | ||||
| 	canvas.StrokeText(300, 50, `Courier new, 12pt, italic`) | ||||
| 
 | ||||
| 	canvas.SetSolidColorFillStyle(0xFF000080) | ||||
| 	canvas.SetLinearGradientStrokeStyle(10, 70, 0xFF00FF00, 10, 90, 0xFFFF00FF, nil) | ||||
| 	canvas.SetFontWithParams("sans-serif", rui.Pt(12), rui.FontParams{ | ||||
| 		SmallCaps: true, | ||||
| 	}) | ||||
| 	canvas.FillText(10, 70, "sans-serif, 12pt, small-caps") | ||||
| 	canvas.StrokeText(300, 70, "sans-serif, 12pt, small-caps") | ||||
| 
 | ||||
| 	canvas.SetLinearGradientFillStyle(10, 90, 0xFFFF0000, 10, 110, 0xFF0000FF, nil) | ||||
| 	canvas.SetSolidColorStrokeStyle(0xFF800080) | ||||
| 	canvas.SetFontWithParams("serif", rui.Pt(12), rui.FontParams{ | ||||
| 		Weight: 7, | ||||
| 	}) | ||||
| 	canvas.FillText(10, 90, "serif, 12pt, weight: 7(bold)") | ||||
| 	canvas.StrokeText(300, 90, "serif, 12pt, weight: 7(bold)") | ||||
| 
 | ||||
| 	widthSample := "Text width sample" | ||||
| 	w := canvas.TextWidth(widthSample, "sans-serif", rui.Px(20)) | ||||
| 	canvas.SetFont("sans-serif", rui.Px(20)) | ||||
| 	canvas.SetSolidColorFillStyle(rui.Blue) | ||||
| 	canvas.SetTextBaseline(rui.BottomBaseline) | ||||
| 	canvas.FillText(10, 150, widthSample) | ||||
| 
 | ||||
| 	canvas.SetSolidColorStrokeStyle(rui.Black) | ||||
| 	canvas.SetLineWidth(1) | ||||
| 	canvas.DrawLine(10, 150, 10, 170) | ||||
| 	canvas.DrawLine(10+w, 150, 10+w, 170) | ||||
| 	canvas.DrawLine(10, 168, 10+w, 168) | ||||
| 	canvas.DrawLine(10, 168, 20, 165) | ||||
| 	canvas.DrawLine(10, 168, 20, 171) | ||||
| 	canvas.DrawLine(10+w, 168, w, 165) | ||||
| 	canvas.DrawLine(10+w, 168, w, 171) | ||||
| 
 | ||||
| 	canvas.SetSolidColorFillStyle(rui.Black) | ||||
| 	canvas.SetFont("sans-serif", rui.Px(8)) | ||||
| 	canvas.SetTextAlign(rui.CenterAlign) | ||||
| 	canvas.FillText(10+w/2, 167, strconv.FormatFloat(w, 'g', -1, 64)) | ||||
| 
 | ||||
| 	canvas.Restore() | ||||
| } | ||||
| 
 | ||||
| func textAlignCanvasDemo(canvas rui.Canvas) { | ||||
| 	canvas.Save() | ||||
| 	canvas.SetFont("sans-serif", rui.Pt(10)) | ||||
| 	canvas.SetSolidColorFillStyle(0xFF000000) | ||||
| 	canvas.SetSolidColorStrokeStyle(0xFF00FFFF) | ||||
| 
 | ||||
| 	baseline := []string{"Alphabetic", "Top", "Middle", "Bottom", "Hanging", "Ideographic"} | ||||
| 	align := []string{"Left", "Right", "Center", "Start", "End"} | ||||
| 	center := []float64{20, 120, 70, 20, 120} | ||||
| 	for b, bText := range baseline { | ||||
| 		for a, aText := range align { | ||||
| 			canvas.SetTextAlign(a) | ||||
| 			canvas.SetTextBaseline(b) | ||||
| 			x := float64(a * 140) | ||||
| 			y := float64(b * 40) | ||||
| 
 | ||||
| 			canvas.DrawLine(x+4, y+20, x+132, y+20) | ||||
| 			canvas.DrawLine(x+center[a], y+2, x+center[a], y+38) | ||||
| 			canvas.FillText(x+center[a], y+20, bText+","+aText) | ||||
| 		} | ||||
| 	} | ||||
| 	canvas.Restore() | ||||
| } | ||||
| 
 | ||||
| func lineStyleCanvasDemo(canvas rui.Canvas) { | ||||
| 	canvas.Save() | ||||
| 
 | ||||
| 	canvas.SetSolidColorStrokeStyle(0xFF00FFFF) | ||||
| 	canvas.SetLineWidth(1) | ||||
| 	canvas.DrawLine(20, 30, 20, 90) | ||||
| 	canvas.DrawLine(170, 30, 170, 90) | ||||
| 
 | ||||
| 	canvas.SetSolidColorStrokeStyle(0xFF0000FF) | ||||
| 	canvas.SetFont("courier", rui.Pt(12)) | ||||
| 	canvas.SetTextBaseline(rui.MiddleBaseline) | ||||
| 	canvas.FillText(80, 15, "SetLineCap(...)") | ||||
| 
 | ||||
| 	canvas.SetFont("courier", rui.Pt(10)) | ||||
| 	for i, cap := range []string{"ButtCap", "RoundCap", "SquareCap"} { | ||||
| 		canvas.SetSolidColorStrokeStyle(0xFF00FFFF) | ||||
| 		canvas.SetLineWidth(1) | ||||
| 		y := float64(40 + 20*i) | ||||
| 		canvas.DrawLine(10, y, 180, y) | ||||
| 		canvas.SetSolidColorStrokeStyle(0xFF000000) | ||||
| 		canvas.SetLineWidth(10) | ||||
| 		canvas.SetLineCap(i) | ||||
| 		canvas.DrawLine(20, y, 170, y) | ||||
| 		canvas.FillText(200, y, cap) | ||||
| 	} | ||||
| 
 | ||||
| 	canvas.SetSolidColorStrokeStyle(0xFF0000FF) | ||||
| 	canvas.SetFont("courier", rui.Pt(12)) | ||||
| 	canvas.FillText(80, 115, "SetLineJoin(...)") | ||||
| 
 | ||||
| 	canvas.SetSolidColorStrokeStyle(0xFF000000) | ||||
| 	canvas.SetLineWidth(10) | ||||
| 	canvas.SetLineCap(rui.ButtCap) | ||||
| 
 | ||||
| 	canvas.SetFont("courier", rui.Pt(10)) | ||||
| 	for i, join := range []string{"MiterJoin", "RoundJoin", "BevelJoin"} { | ||||
| 		y := float64(140 + 40*i) | ||||
| 		path := rui.NewPath() | ||||
| 		path.MoveTo(20, y) | ||||
| 		path.LineTo(50, y+40) | ||||
| 		path.LineTo(80, y) | ||||
| 		path.LineTo(110, y+40) | ||||
| 		path.LineTo(140, y) | ||||
| 		path.LineTo(170, y+40) | ||||
| 		path.LineTo(200, y) | ||||
| 		canvas.SetLineJoin(i) | ||||
| 		canvas.StrokePath(path) | ||||
| 		canvas.FillText(210, y+20, join) | ||||
| 	} | ||||
| 
 | ||||
| 	canvas.SetSolidColorStrokeStyle(0xFF0000FF) | ||||
| 	canvas.SetFont("courier", rui.Pt(12)) | ||||
| 	canvas.FillText(20, 300, "SetLineDash([]float64{16, 8, 4, 8}, ...)") | ||||
| 
 | ||||
| 	canvas.SetFont("courier", rui.Pt(10)) | ||||
| 	canvas.SetLineDash([]float64{16, 8, 4, 8}, 0) | ||||
| 	canvas.SetSolidColorStrokeStyle(0xFF000000) | ||||
| 	canvas.SetLineWidth(4) | ||||
| 
 | ||||
| 	canvas.SetLineCap(rui.ButtCap) | ||||
| 	canvas.DrawLine(20, 330, 200, 330) | ||||
| 	canvas.FillText(220, 330, "SetLineCap(ButtCap)") | ||||
| 
 | ||||
| 	canvas.SetLineDash([]float64{16, 8, 4, 8}, 4) | ||||
| 	canvas.DrawLine(20, 360, 200, 360) | ||||
| 	canvas.FillText(220, 360, "offset = 4") | ||||
| 
 | ||||
| 	canvas.SetLineDash([]float64{16, 8, 4, 8}, 0) | ||||
| 	canvas.SetLineCap(rui.RoundCap) | ||||
| 	canvas.SetShadow(4, 4, 2, 0xFF808080) | ||||
| 	canvas.DrawLine(20, 390, 200, 390) | ||||
| 	canvas.ResetShadow() | ||||
| 	canvas.FillText(220, 390, "SetLineCap(RoundCap)") | ||||
| 
 | ||||
| 	canvas.Restore() | ||||
| } | ||||
| 
 | ||||
| func transformCanvasDemo(canvas rui.Canvas) { | ||||
| 	drawFigure := func() { | ||||
| 		w := int(canvas.Width() / 2) | ||||
| 		h := int(canvas.Height() / 2) | ||||
| 		nx := (w/2)/20 + 1 | ||||
| 		ny := (h/2)/20 + 1 | ||||
| 		x0 := float64((w - nx*20) / 2) | ||||
| 		y0 := float64((h - ny*20) / 2) | ||||
| 		x1 := x0 + float64((nx-1)*20) | ||||
| 		y1 := y0 + float64((ny-1)*20) | ||||
| 
 | ||||
| 		canvas.SetFont("serif", rui.Pt(10)) | ||||
| 		canvas.SetSolidColorFillStyle(rui.Black) | ||||
| 
 | ||||
| 		canvas.SetTextAlign(rui.CenterAlign) | ||||
| 		canvas.SetTextBaseline(rui.BottomBaseline) | ||||
| 		for i := 0; i < nx; i++ { | ||||
| 			x := x0 + float64(i*20) | ||||
| 			canvas.DrawLine(x, y0, x, y1) | ||||
| 			canvas.FillText(x, y0-4, strconv.Itoa(i)) | ||||
| 		} | ||||
| 
 | ||||
| 		canvas.SetTextAlign(rui.RightAlign) | ||||
| 		canvas.SetTextBaseline(rui.MiddleBaseline) | ||||
| 		for i := 0; i < ny; i++ { | ||||
| 			y := y0 + float64(i*20) | ||||
| 			canvas.DrawLine(x0, y, x1, y) | ||||
| 			canvas.FillText(x0-4, y, strconv.Itoa(i)) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	canvas.SetFont("courier", rui.Pt(14)) | ||||
| 	canvas.SetSolidColorFillStyle(rui.Black) | ||||
| 	canvas.SetTextAlign(rui.CenterAlign) | ||||
| 	canvas.SetTextBaseline(rui.TopBaseline) | ||||
| 
 | ||||
| 	canvas.FillText(canvas.Width()/4, 8, "Original") | ||||
| 	canvas.FillText(canvas.Width()*3/4, 8, "SetScale(1.2, 0.8)") | ||||
| 	canvas.FillText(canvas.Width()/4, canvas.Height()/2+8, "SetRotation(math.Pi / 6)") | ||||
| 	canvas.FillText(canvas.Width()*3/4, canvas.Height()/2+8, "SetTransformation(0.8, 1.2, 0.2, 0.4, ...)") | ||||
| 
 | ||||
| 	drawFigure() | ||||
| 
 | ||||
| 	canvas.SetScale(1.2, 0.8) | ||||
| 	canvas.SetTranslation(canvas.Width()/2.4, 0) | ||||
| 	drawFigure() | ||||
| 
 | ||||
| 	canvas.ResetTransformation() | ||||
| 	canvas.SetTranslation(canvas.Width()/8, canvas.Height()/2-canvas.Height()/8) | ||||
| 	canvas.SetRotation(math.Pi / 6) | ||||
| 	drawFigure() | ||||
| 
 | ||||
| 	canvas.ResetTransformation() | ||||
| 	//canvas.SetTranslation(canvas.Width()/2, canvas.Height()/2)
 | ||||
| 	canvas.SetTransformation(0.8, 1.2, 0.2, 0.4, canvas.Width()/(2*0.8)-canvas.Width()/8, canvas.Height()/(2*1.2)-canvas.Height()/16) | ||||
| 	drawFigure() | ||||
| } | ||||
| 
 | ||||
| var image rui.Image | ||||
| 
 | ||||
| func imageCanvasDemo(canvas rui.Canvas) { | ||||
| 	if image != nil { | ||||
| 		canvas.DrawImage(50, 20, image) | ||||
| 	} else { | ||||
| 		image = rui.LoadImage("tile00.svg", func(img rui.Image) { | ||||
| 			if img.LoadingStatus() == rui.ImageReady { | ||||
| 				canvas.View().Redraw() | ||||
| 			} | ||||
| 		}, canvas.View().Session()) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func createCanvasDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, canvasDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "canvas", rui.DrawFunction, imageCanvasDemo) | ||||
| 
 | ||||
| 	rui.Set(view, "canvasType", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		drawFuncs := []func(rui.Canvas){ | ||||
| 			imageCanvasDemo, | ||||
| 			rectangleCanvasDemo, | ||||
| 			textCanvasDemo, | ||||
| 			textAlignCanvasDemo, | ||||
| 			lineStyleCanvasDemo, | ||||
| 			transformCanvasDemo, | ||||
| 		} | ||||
| 		if number >= 0 && number < len(drawFuncs) { | ||||
| 			rui.Set(view, "canvas", rui.DrawFunction, drawFuncs[number]) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	sampleImage = rui.LoadImage("image_sample.png", nil, session) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,69 @@ | |||
| package main | ||||
| 
 | ||||
| import "github.com/anoshenko/rui" | ||||
| 
 | ||||
| const checkboxDemoText = ` | ||||
| GridLayout { | ||||
| 	style = demoPage, | ||||
| 	content = [ | ||||
| 		GridLayout { | ||||
| 			width = 100%, height = 100%, cell-vertical-align = center, cell-horizontal-align = center, | ||||
| 			content = [ | ||||
| 				GridLayout { | ||||
| 					width = 250px, height = 80px, | ||||
| 					border = _{ style = solid, width = 1px, color = gray }, | ||||
| 					content = [ | ||||
| 						Checkbox { | ||||
| 							id = checkbox, width = 100%, height = 100%, | ||||
| 							content = "Checkbox content" | ||||
| 						} | ||||
| 					] | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		ListLayout { | ||||
| 			style = optionsPanel, | ||||
| 			content = [ | ||||
| 				GridLayout { | ||||
| 					style = optionsTable, | ||||
| 					content = [ | ||||
| 						TextView { row = 0, text = "Vertical align" }, | ||||
| 						DropDownList { row = 0, column = 1, id = checkboxVAlign, current = 0, items = ["top", "bottom", "center", "stretch"]}, | ||||
| 						TextView { row = 1, text = "Horizontal align" }, | ||||
| 						DropDownList { row = 1, column = 1, id = checkboxHAlign, current = 0, items = ["left", "right", "center", "stretch"]}, | ||||
| 						TextView { row = 2, text = "Checkbox vertical align" }, | ||||
| 						DropDownList { row = 2, column = 1, id = checkboxBoxVAlign, current = 0, items = ["top", "bottom", "center"]}, | ||||
| 						TextView { row = 3, text = "Checkbox horizontal align" }, | ||||
| 						DropDownList { row = 3, column = 1, id = checkboxBoxHAlign, current = 0, items = ["left", "right", "center"]}, | ||||
| 					] | ||||
| 				} | ||||
| 			] | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createCheckboxDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, checkboxDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "checkboxVAlign", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "checkbox", rui.VerticalAlign, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "checkboxHAlign", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "checkbox", rui.HorizontalAlign, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "checkboxBoxVAlign", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "checkbox", rui.CheckboxVerticalAlign, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "checkboxBoxHAlign", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "checkbox", rui.CheckboxHorizontalAlign, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,54 @@ | |||
| package main | ||||
| 
 | ||||
| import "github.com/anoshenko/rui" | ||||
| 
 | ||||
| const clipDemoText = ` | ||||
| GridLayout { | ||||
| 	width = 100%, height = 100%, cell-height = "auto, 1fr", | ||||
| 	cell-horizontal-align = center, cell-vertical-align = center, | ||||
| 	content = [ | ||||
| 		DropDownList { | ||||
| 			id = clipType, current = 0, margin = 8px, max-width = 100%, | ||||
| 			items = ["none",  | ||||
| 				"inset(20%, 10%, 20%, 10%, 16px / 32px)",  | ||||
| 				"circle(50%, 45%, 45%)",  | ||||
| 				"ellipse(50%, 50%, 35%, 50%)", | ||||
| 				"polygon(50%, 2.4%, 34.5%, 33.8%, 0%, 38.8%, 25%, 63.1%, 19.1%, 97.6%, 50%, 81.3%, 80.9%, 97.6%, 75%, 63.1%, 100%, 38.8%, 65.5%, 33.8%)"], | ||||
| 		}, | ||||
| 		ImageView { | ||||
| 			id = clipImage, row = 1, src = "cat.jpg", | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createClipDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, clipDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "clipType", rui.DropDownEvent, func(number int) { | ||||
| 		switch number { | ||||
| 		case 0: | ||||
| 			rui.Set(view, "clipImage", rui.Clip, nil) | ||||
| 
 | ||||
| 		case 1: | ||||
| 			rui.Set(view, "clipImage", rui.Clip, rui.InsetClip(rui.Percent(20), rui.Percent(10), | ||||
| 				rui.Percent(20), rui.Percent(10), rui.NewRadiusProperty(rui.Params{ | ||||
| 					rui.X: rui.Px(16), | ||||
| 					rui.Y: rui.Px(32), | ||||
| 				}))) | ||||
| 		case 2: | ||||
| 			rui.Set(view, "clipImage", rui.Clip, rui.CircleClip(rui.Percent(50), rui.Percent(45), rui.Percent(45))) | ||||
| 
 | ||||
| 		case 3: | ||||
| 			rui.Set(view, "clipImage", rui.Clip, rui.EllipseClip(rui.Percent(50), rui.Percent(50), rui.Percent(35), rui.Percent(50))) | ||||
| 
 | ||||
| 		case 4: | ||||
| 			rui.Set(view, "clipImage", rui.Clip, rui.PolygonClip([]interface{}{"50%", "2.4%", "34.5%", "33.8%", "0%", "38.8%", "25%", "63.1%", "19.1%", "97.6%", "50%", "81.3%", "80.9%", "97.6%", "75%", "63.1%", "100%", "38.8%", "65.5%", "33.8%"})) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,139 @@ | |||
| package main | ||||
| 
 | ||||
| import "github.com/anoshenko/rui" | ||||
| 
 | ||||
| const columnLayoutText = ` | ||||
| GridLayout { | ||||
| 	style = demoPage, | ||||
| 	content = [ | ||||
| 		ColumnLayout { | ||||
| 			id = columnLayout, padding = 12px, | ||||
| 			content = [ | ||||
| 				TextView { text = "Alice’s Adventures in Wonderland", style = header1 }, | ||||
| 				TextView { text = "by Lewis Carroll", semantics = blockquote, margin-bottom = 0.5em, text-size = 0.8em, text-align = center }, | ||||
| 				TextView { text = "CHAPTER I. Down the Rabbit-Hole", style = header2 }, | ||||
| 				TextView { text = "Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, “and what is the use of a book,” thought Alice “without pictures or conversations?”", style = paragraph }, | ||||
| 				TextView { text = "So she was considering in her own mind (as well as she could, for the hot day made her feel very sleepy and stupid), whether the pleasure of making a daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly a White Rabbit with pink eyes ran close by her.", style = paragraph }, | ||||
| 				TextView { text = "There was nothing so very remarkable in that; nor did Alice think it so very much out of the way to hear the Rabbit say to itself, “Oh dear! Oh dear! I shall be late!” (when she thought it over afterwards, it occurred to her that she ought to have wondered at this, but at the time it all seemed quite natural); but when the Rabbit actually took a watch out of its waistcoat-pocket, and looked at it, and then hurried on, Alice started to her feet, for it flashed across her mind that she had never before seen a rabbit with either a waistcoat-pocket, or a watch to take out of it, and burning with curiosity, she ran across the field after it, and fortunately was just in time to see it pop down a large rabbit-hole under the hedge.", style = paragraph }, | ||||
| 				TextView { text = "In another moment down went Alice after it, never once considering how in the world she was to get out again.", style = paragraph }, | ||||
| 				TextView { text = "The rabbit-hole went straight on like a tunnel for some way, and then dipped suddenly down, so suddenly that Alice had not a moment to think about stopping herself before she found herself falling down a very deep well.", style = paragraph }, | ||||
| 				TextView { text = "Either the well was very deep, or she fell very slowly, for she had plenty of time as she went down to look about her and to wonder what was going to happen next. First, she tried to look down and make out what she was coming to, but it was too dark to see anything; then she looked at the sides of the well, and noticed that they were filled with cupboards and book-shelves; here and there she saw maps and pictures hung upon pegs. She took down a jar from one of the shelves as she passed; it was labelled “ORANGE MARMALADE”, but to her great disappointment it was empty: she did not like to drop the jar for fear of killing somebody underneath, so managed to put it into one of the cupboards as she fell past it.", style = paragraph }, | ||||
| 				TextView { text = "“Well!” thought Alice to herself, “after such a fall as this, I shall think nothing of tumbling down stairs! How brave they’ll all think me at home! Why, I wouldn’t say anything about it, even if I fell off the top of the house!” (Which was very likely true.)", style = paragraph }, | ||||
| 				TextView { text = "Down, down, down. Would the fall never come to an end? “I wonder how many miles I’ve fallen by this time?” she said aloud. “I must be getting somewhere near the centre of the earth. Let me see: that would be four thousand miles down, I think—” (for, you see, Alice had learnt several things of this sort in her lessons in the schoolroom, and though this was not a very good opportunity for showing off her knowledge, as there was no one to listen to her, still it was good practice to say it over) “—yes, that’s about the right distance—but then I wonder what Latitude or Longitude I’ve got to?” (Alice had no idea what Latitude was, or Longitude either, but thought they were nice grand words to say.)", style = paragraph }, | ||||
| 				TextView { text = "Presently she began again. “I wonder if I shall fall right through the earth! How funny it’ll seem to come out among the people that walk with their heads downward! The Antipathies, I think—” (she was rather glad there was no one listening, this time, as it didn’t sound at all the right word) “—but I shall have to ask them what the name of the country is, you know. Please, Ma’am, is this New Zealand or Australia?” (and she tried to curtsey as she spoke—fancy curtseying as you’re falling through the air! Do you think you could manage it?) “And what an ignorant little girl she’ll think me for asking! No, it’ll never do to ask: perhaps I shall see it written up somewhere.”", style = paragraph }, | ||||
| 				TextView { text = "Down, down, down. There was nothing else to do, so Alice soon began talking again. “Dinah’ll miss me very much to-night, I should think!” (Dinah was the cat.) “I hope they’ll remember her saucer of milk at tea-time. Dinah my dear! I wish you were down here with me! There are no mice in the air, I’m afraid, but you might catch a bat, and that’s very like a mouse, you know. But do cats eat bats, I wonder?” And here Alice began to get rather sleepy, and went on saying to herself, in a dreamy sort of way, “Do cats eat bats? Do cats eat bats?” and sometimes, “Do bats eat cats?” for, you see, as she couldn’t answer either question, it didn’t much matter which way she put it. She felt that she was dozing off, and had just begun to dream that she was walking hand in hand with Dinah, and saying to her very earnestly, “Now, Dinah, tell me the truth: did you ever eat a bat?” when suddenly, thump! thump! down she came upon a heap of sticks and dry leaves, and the fall was over.", style = paragraph }, | ||||
| 				TextView { text = "Alice was not a bit hurt, and she jumped up on to her feet in a moment: she looked up, but it was all dark overhead; before her was another long passage, and the White Rabbit was still in sight, hurrying down it. There was not a moment to be lost: away went Alice like the wind, and was just in time to hear it say, as it turned a corner, “Oh my ears and whiskers, how late it’s getting!” She was close behind it when she turned the corner, but the Rabbit was no longer to be seen: she found herself in a long, low hall, which was lit up by a row of lamps hanging from the roof.", style = paragraph }, | ||||
| 				TextView { text = "There were doors all round the hall, but they were all locked; and when Alice had been all the way down one side and up the other, trying every door, she walked sadly down the middle, wondering how she was ever to get out again.", style = paragraph }, | ||||
| 				TextView { text = "Suddenly she came upon a little three-legged table, all made of solid glass; there was nothing on it except a tiny golden key, and Alice’s first thought was that it might belong to one of the doors of the hall; but, alas! either the locks were too large, or the key was too small, but at any rate it would not open any of them. However, on the second time round, she came upon a low curtain she had not noticed before, and behind it was a little door about fifteen inches high: she tried the little golden key in the lock, and to her great delight it fitted!", style = paragraph }, | ||||
| 				TextView { text = "Alice opened the door and found that it led into a small passage, not much larger than a rat-hole: she knelt down and looked along the passage into the loveliest garden you ever saw. How she longed to get out of that dark hall, and wander about among those beds of bright flowers and those cool fountains, but she could not even get her head through the doorway; “and even if my head would go through,” thought poor Alice, “it would be of very little use without my shoulders. Oh, how I wish I could shut up like a telescope! I think I could, if I only knew how to begin.” For, you see, so many out-of-the-way things had happened lately, that Alice had begun to think that very few things indeed were really impossible.", style = paragraph }, | ||||
| 				TextView { text = "There seemed to be no use in waiting by the little door, so she went back to the table, half hoping she might find another key on it, or at any rate a book of rules for shutting people up like telescopes: this time she found a little bottle on it, (“which certainly was not here before,” said Alice,) and round the neck of the bottle was a paper label, with the words “DRINK ME,” beautifully printed on it in large letters.", style = paragraph }, | ||||
| 				TextView { text = "It was all very well to say “Drink me,” but the wise little Alice was not going to do that in a hurry. “No, I’ll look first,” she said, “and see whether it’s marked ‘poison’ or not”; for she had read several nice little histories about children who had got burnt, and eaten up by wild beasts and other unpleasant things, all because they would not remember the simple rules their friends had taught them: such as, that a red-hot poker will burn you if you hold it too long; and that if you cut your finger very deeply with a knife, it usually bleeds; and she had never forgotten that, if you drink much from a bottle marked “poison,” it is almost certain to disagree with you, sooner or later.", style = paragraph }, | ||||
| 				TextView { text = "However, this bottle was not marked “poison,” so Alice ventured to taste it, and finding it very nice, (it had, in fact, a sort of mixed flavour of cherry-tart, custard, pine-apple, roast turkey, toffee, and hot buttered toast,) she very soon finished it off.", style = paragraph }, | ||||
| 			] | ||||
| 		}, | ||||
| 		ListLayout { | ||||
| 			style = optionsPanel, | ||||
| 			content = [ | ||||
| 				GridLayout { | ||||
| 					style = optionsTable, | ||||
| 					content = [ | ||||
| 						TextView { row = 0, text = "Column count" }, | ||||
| 						DropDownList { row = 0, column = 1, id = columnCount, current = 0,  | ||||
| 							items = ["0", "1", "2", "3", "4", "5"], | ||||
| 						}, | ||||
| 						TextView { row = 1, text = "Column width" }, | ||||
| 						DropDownList { row = 1, column = 1, id = columnWidth, current = 0,  | ||||
| 							items = ["auto", "100px", "200px", "40em"]  | ||||
| 						}, | ||||
| 						TextView { row = 2, text = "Column gap" }, | ||||
| 						DropDownList { row = 2, column = 1, id = columnGap, current = 0,  | ||||
| 							items = ["auto", "5%", "12px", "4em"] | ||||
| 						}, | ||||
| 						TextView { row = 3, text = "Column separator" }, | ||||
| 						DropDownList { row = 3, column = 1, id = columnSeparator, current = 0,  | ||||
| 							items = ["none", "1px solid", "2px dotted red", "3px dashed blue", "4px double"]}, | ||||
| 						Checkbox { row = 4, column = 0:1, id = columnAvoidBreak, content = "Avoid break" } | ||||
| 					] | ||||
| 				}, | ||||
| 			] | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createColumnLayoutDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, columnLayoutText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "columnCount", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "columnLayout", rui.ColumnCount, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "columnWidth", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		items := []rui.SizeUnit{rui.AutoSize(), rui.Px(100), rui.Px(200), rui.Em(40)} | ||||
| 		if number >= 0 && number < len(items) { | ||||
| 			rui.Set(view, "columnLayout", rui.ColumnWidth, items[number]) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "columnGap", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		items := []rui.SizeUnit{rui.AutoSize(), rui.Percent(5), rui.Px(8), rui.Em(4)} | ||||
| 		if number >= 0 && number < len(items) { | ||||
| 			rui.Set(view, "columnLayout", rui.ColumnGap, items[number]) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "columnSeparator", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		switch number { | ||||
| 		case 0: | ||||
| 			rui.Set(view, "columnLayout", rui.ColumnSeparator, nil) | ||||
| 
 | ||||
| 		case 1: | ||||
| 			rui.Set(view, "columnLayout", rui.ColumnSeparator, | ||||
| 				rui.NewColumnSeparator(rui.Params{ | ||||
| 					rui.Width: rui.Px(1), | ||||
| 					rui.Style: rui.SolidLine, | ||||
| 				})) | ||||
| 
 | ||||
| 		case 2: | ||||
| 			rui.Set(view, "columnLayout", rui.ColumnSeparator, | ||||
| 				rui.NewColumnSeparator(rui.Params{ | ||||
| 					rui.Width:         rui.Px(2), | ||||
| 					rui.Style:         rui.DottedLine, | ||||
| 					rui.ColorProperty: rui.Red, | ||||
| 				})) | ||||
| 
 | ||||
| 		case 3: | ||||
| 			rui.Set(view, "columnLayout", rui.ColumnSeparator, | ||||
| 				rui.NewColumnSeparator(rui.Params{ | ||||
| 					rui.Width:         rui.Px(3), | ||||
| 					rui.Style:         rui.DashedLine, | ||||
| 					rui.ColorProperty: rui.Blue, | ||||
| 				})) | ||||
| 
 | ||||
| 		case 4: | ||||
| 			rui.Set(view, "columnLayout", rui.ColumnSeparator, | ||||
| 				rui.NewColumnSeparator(rui.Params{ | ||||
| 					rui.Width: rui.Px(4), | ||||
| 					rui.Style: rui.DoubleLine, | ||||
| 				})) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "columnAvoidBreak", rui.CheckboxChangedEvent, func(checkbox rui.Checkbox, checked bool) { | ||||
| 		if layout := rui.ColumnLayoutByID(view, "columnLayout"); layout != nil { | ||||
| 			for _, v := range layout.Views() { | ||||
| 				v.Set(rui.AvoidBreak, checked) | ||||
| 			} | ||||
| 		} | ||||
| 		number := rui.GetColumnCount(view, "columnLayout") | ||||
| 		if number > 0 { | ||||
| 			rui.Set(view, "columnLayout", rui.ColumnCount, 0) | ||||
| 			rui.Set(view, "columnLayout", rui.ColumnCount, number) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,148 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const controlsDemoText = ` | ||||
| ListLayout { | ||||
| 	width = 100%, height = 100%, orientation = vertical, padding = 16px, | ||||
| 	content = [ | ||||
| 		DetailsView { | ||||
| 			margin = 8px, | ||||
| 			summary = "Details title", | ||||
| 			content = "Details content" | ||||
| 		} | ||||
| 		ListLayout { orientation = horizontal, vertical-align = center, padding = 8px, | ||||
| 			border = _{ width = 1px, style = solid, color = #FF000000 }, radius = 4px, | ||||
| 			content = [ | ||||
| 				Checkbox { id = controlsCheckbox, content = "Checkbox" }, | ||||
| 				Button { id = controlsCheckboxButton, margin-left = 32px, content = "Check checkbox" }, | ||||
| 			] | ||||
| 		}, | ||||
| 		ListLayout { orientation = horizontal, margin-top = 16px, padding = 8px, vertical-align = center, | ||||
| 			border = _{ width = 1px, style = solid, color = #FF000000 }, radius = 4px, | ||||
| 			content = [ | ||||
| 				Button { id = controlsProgressDec, content = "<<" }, | ||||
| 				Button { id = controlsProgressInc, content = ">>", margin-left = 12px }, | ||||
| 				ProgressBar { id = controlsProgress, max = 100, value = 50, margin-left = 12px  }, | ||||
| 				TextView { id = controlsProgressLabel, text = "50 / 100", margin-left = 12px }, | ||||
| 			] | ||||
| 		}, | ||||
| 		ListLayout { orientation = horizontal, margin-top = 16px, padding = 8px, vertical-align = center, | ||||
| 			border = _{ width = 1px, style = solid, color = #FF000000 }, radius = 4px, | ||||
| 			content = [ | ||||
| 				"Enter number (-5...10)", | ||||
| 				NumberPicker { id = controlsNumberEditor, type = editor, width = 80px,  | ||||
| 					margin-left = 12px, min = -5, max = 10, step = 0.1, value = 0  | ||||
| 				}, | ||||
| 				NumberPicker { id = controlsNumberSlider, type = slider, width = 150px,  | ||||
| 					margin-left = 12px, min = -5, max = 10, step = 0.1, value = 0  | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		ListLayout { orientation = horizontal, margin-top = 16px, padding = 8px, vertical-align = center, | ||||
| 			border = _{ width = 1px, style = solid, color = #FF000000 }, radius = 4px, | ||||
| 			content = [ | ||||
| 				"Select color", | ||||
| 				ColorPicker { id = controlsColorPicker, value = #0000FF, | ||||
| 					margin = _{ left = 12px, right = 24px}  | ||||
| 				}, | ||||
| 				"Result", | ||||
| 				View { id = controlsColorResult, width = 24px, height = 24px, margin-left = 12px, background-color = #0000FF } | ||||
| 			] | ||||
| 		}, | ||||
| 		ListLayout { orientation = horizontal, margin-top = 16px, padding = 8px, vertical-align = center, | ||||
| 			border = _{ width = 1px, style = solid, color = #FF000000 }, radius = 4px, | ||||
| 			content = [ | ||||
| 				"Select a time and date:", | ||||
| 				TimePicker { id = controlsTimePicker, min = "00:00", margin-left = 12px }, | ||||
| 				DatePicker { id = controlsDatePicker, min = "2001-01-01", margin-right = 24px }, | ||||
| 				"Result:", | ||||
| 				TextView { id = controlsDateResult, margin-left = 12px } | ||||
| 			] | ||||
| 		}, | ||||
| 		Button { | ||||
| 			id = controlsMessage, margin-top = 16px, content = "Show message" | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createControlsDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, controlsDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "controlsCheckbox", rui.CheckboxChangedEvent, func(checkbox rui.Checkbox, checked bool) { | ||||
| 		if checked { | ||||
| 			rui.Set(view, "controlsCheckboxButton", rui.Content, "Uncheck checkbox") | ||||
| 		} else { | ||||
| 			rui.Set(view, "controlsCheckboxButton", rui.Content, "Check checkbox") | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "controlsCheckboxButton", rui.ClickEvent, func(rui.View) { | ||||
| 		checked := rui.IsCheckboxChecked(view, "controlsCheckbox") | ||||
| 		rui.Set(view, "controlsCheckbox", rui.Checked, !checked) | ||||
| 	}) | ||||
| 
 | ||||
| 	setProgressBar := func(dx float64) { | ||||
| 		if value := rui.GetProgressBarValue(view, "controlsProgress"); value >= 0 { | ||||
| 			max := rui.GetProgressBarMax(view, "controlsProgress") | ||||
| 			newValue := math.Min(math.Max(0, value+dx), max) | ||||
| 			if newValue != value { | ||||
| 				rui.Set(view, "controlsProgress", rui.Value, newValue) | ||||
| 				rui.Set(view, "controlsProgressLabel", rui.Text, fmt.Sprintf("%g / %g", newValue, max)) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "controlsProgressDec", rui.ClickEvent, func(rui.View) { | ||||
| 		setProgressBar(-1) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "controlsProgressInc", rui.ClickEvent, func(rui.View) { | ||||
| 		setProgressBar(+1) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "controlsNumberEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		rui.Set(view, "controlsNumberSlider", rui.Value, newValue) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "controlsNumberSlider", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		rui.Set(view, "controlsNumberEditor", rui.Value, newValue) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "controlsColorPicker", rui.ColorChangedEvent, func(v rui.ColorPicker, newColor rui.Color) { | ||||
| 		rui.Set(view, "controlsColorResult", rui.BackgroundColor, newColor) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "controlsTimePicker", rui.Value, demoTime) | ||||
| 	rui.Set(view, "controlsDatePicker", rui.Value, demoTime) | ||||
| 
 | ||||
| 	rui.Set(view, "controlsTimePicker", rui.TimeChangedEvent, func(v rui.TimePicker, newDate time.Time) { | ||||
| 		demoTime = time.Date(demoTime.Year(), demoTime.Month(), demoTime.Day(), newDate.Hour(), newDate.Minute(), | ||||
| 			newDate.Second(), newDate.Nanosecond(), demoTime.Location()) | ||||
| 		rui.Set(view, "controlsDateResult", rui.Text, demoTime.Format(time.RFC1123)) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "controlsDatePicker", rui.DateChangedEvent, func(v rui.DatePicker, newDate time.Time) { | ||||
| 		demoTime = time.Date(newDate.Year(), newDate.Month(), newDate.Day(), demoTime.Hour(), demoTime.Minute(), | ||||
| 			demoTime.Second(), demoTime.Nanosecond(), demoTime.Location()) | ||||
| 		rui.Set(view, "controlsDateResult", rui.Text, demoTime.Format(time.RFC1123)) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "controlsMessage", rui.ClickEvent, func(rui.View) { | ||||
| 		rui.ShowMessage("Hello", "Hello world!!!", session) | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
| 
 | ||||
| var demoTime = time.Now() | ||||
|  | @ -0,0 +1,70 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const editDemoText = ` | ||||
| ListLayout { | ||||
| 	width = 100%, height = 100%, orientation = vertical, padding = 16px, | ||||
| 	content = [ | ||||
| 		GridLayout { | ||||
| 			row-gap = 12px, column-gap = 8px, cell-width = "auto, 1fr, auto", cell-vertical-align = center, | ||||
| 			content = [ | ||||
| 				TextView { row = 0, column = 0, text = "User name" }, | ||||
| 				EditView { row = 0, column = 1, id = editUserName, min-width = 200px, hint = "Required", type = text }, | ||||
| 				TextView { row = 1, column = 0, text = "Password" }, | ||||
| 				EditView { row = 1, column = 1, id = editPassword, min-width = 200px, hint = "8 characters minimum", type = password }, | ||||
| 				TextView { row = 2, column = 0, text = "Confirm password" }, | ||||
| 				EditView { row = 2, column = 1, id = editConfirmPassword, min-width = 200px, hint = "Required", type = password }, | ||||
| 				TextView { row = 2, column = 2, id = confirmLabel, text = "" }, | ||||
| 				TextView { row = 3, column = 0, text = "Main e-mail" }, | ||||
| 				EditView { row = 3, column = 1, id = editMainEmail, min-width = 200px, hint = "Required", type = email }, | ||||
| 				TextView { row = 4, column = 0, text = "Additional e-mails" }, | ||||
| 				EditView { row = 4, column = 1, id = editAdditionalEmails, min-width = 200px, hint = "Optional", type = emails }, | ||||
| 				TextView { row = 5, column = 0, text = "Home page" }, | ||||
| 				EditView { row = 5, column = 1, id = editHomePage, min-width = 200px, hint = "Optional", type = url }, | ||||
| 				TextView { row = 6, column = 0, text = "Phone" }, | ||||
| 				EditView { row = 6, column = 1, id = editPhone, min-width = 200px, hint = "Optional", type = phone }, | ||||
| 				EditView { row = 7, column = 0:1, id = editMultiLine, height = 200px, type = multiline }, | ||||
| 				Checkbox { row = 7, column = 2, id = editMultiLineWrap, content = "Wrap", margin-left = 12px } | ||||
| 			] | ||||
| 		}, | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createEditDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, editDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	setConfirmLabel := func(password, confirmPassword string) { | ||||
| 		if password == confirmPassword { | ||||
| 			rui.Set(view, "confirmLabel", rui.TextColor, rui.Green) | ||||
| 			if password != "" { | ||||
| 				rui.Set(view, "confirmLabel", rui.Text, "✓") | ||||
| 			} else { | ||||
| 				rui.Set(view, "confirmLabel", rui.Text, "") | ||||
| 			} | ||||
| 		} else { | ||||
| 			rui.Set(view, "confirmLabel", rui.TextColor, rui.Red) | ||||
| 			rui.Set(view, "confirmLabel", rui.Text, "✗") | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "editPassword", rui.EditTextChangedEvent, func(edit rui.EditView, newText string) { | ||||
| 		setConfirmLabel(newText, rui.GetText(view, "editConfirmPassword")) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "editConfirmPassword", rui.EditTextChangedEvent, func(edit rui.EditView, newText string) { | ||||
| 		setConfirmLabel(rui.GetText(view, "editPassword"), newText) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "editMultiLineWrap", rui.CheckboxChangedEvent, func(checkbox rui.Checkbox, checked bool) { | ||||
| 		rui.Set(view, "editMultiLine", rui.Wrap, checked) | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,170 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const filterDemoText = ` | ||||
| GridLayout { | ||||
| 	style = demoPage, | ||||
| 	content = [ | ||||
| 		GridLayout { | ||||
| 			width = 100%, height = 100%, cell-vertical-align = center, cell-horizontal-align = center, | ||||
| 			content = [ | ||||
| 				ImageView { id = filterImage, src = "mountain.svg" }, | ||||
| 			] | ||||
| 		}, | ||||
| 		ListLayout { | ||||
| 			style = optionsPanel, | ||||
| 			content = [ | ||||
| 				GridLayout { | ||||
| 					style = optionsTable, | ||||
| 					content = [ | ||||
| 						Checkbox { id = blurCheckbox, row = 0, content = "Blur" }, | ||||
| 						NumberPicker { id = blurSlider, row = 1, type = slider, min = 0, max = 25, step = 0.1, disabled = true }, | ||||
| 						TextView { id = blurValue, row = 1, column = 1, text = "0px", width = 40px }, | ||||
| 						Checkbox { id = brightnessCheckbox, row = 2, content = "Brightness" }, | ||||
| 						NumberPicker { id = brightnessSlider, row = 3, type = slider, min = 0, max = 200, step = 1, disabled = true }, | ||||
| 						TextView { id = brightnessValue, row = 3, column = 1, text = "0%", width = 40px }, | ||||
| 						Checkbox { id = contrastCheckbox, row = 4, content = "Contrast" }, | ||||
| 						NumberPicker { id = contrastSlider, row = 5, type = slider, min = 0, max = 200, step = 1, disabled = true }, | ||||
| 						TextView { id = contrastValue, row = 5, column = 1, text = "0%", width = 40px }, | ||||
| 						Checkbox { id = grayscaleCheckbox, row = 6, content = "Grayscale" }, | ||||
| 						NumberPicker { id = grayscaleSlider, row = 7, type = slider, min = 0, max = 100, step = 1, disabled = true }, | ||||
| 						TextView { id = grayscaleValue, row = 7, column = 1, text = "0%", width = 40px }, | ||||
| 						Checkbox { id = invertCheckbox, row = 8, content = "Invert" }, | ||||
| 						NumberPicker { id = invertSlider, row = 9, type = slider, min = 0, max = 100, step = 1, disabled = true }, | ||||
| 						TextView { id = invertValue, row = 9, column = 1, text = "0%", width = 40px }, | ||||
| 						Checkbox { id = saturateCheckbox, row = 10, content = "Saturate" }, | ||||
| 						NumberPicker { id = saturateSlider, row = 11, type = slider, min = 0, max = 200, step = 1, disabled = true }, | ||||
| 						TextView { id = saturateValue, row = 11, column = 1, text = "0%", width = 40px }, | ||||
| 						Checkbox { id = sepiaCheckbox, row = 12, content = "Sepia" }, | ||||
| 						NumberPicker { id = sepiaSlider, row = 13, type = slider, min = 0, max = 100, step = 1, disabled = true }, | ||||
| 						TextView { id = sepiaValue, row = 13, column = 1, text = "0%", width = 40px }, | ||||
| 						Checkbox { id = opacityCheckbox, row = 14, content = "Opacity" }, | ||||
| 						NumberPicker { id = opacitySlider, row = 15, type = slider, min = 0, max = 100, step = 1, disabled = true }, | ||||
| 						TextView { id = opacityValue, row = 15, column = 1, text = "0%", width = 40px }, | ||||
| 						Checkbox { id = huerotateCheckbox, row = 16, content = "hue-rotate" }, | ||||
| 						NumberPicker { id = huerotateSlider, row = 17, type = slider, min = 0, max = 720, step = 1, disabled = true }, | ||||
| 						TextView { id = huerotateValue, row = 17, column = 1, text = "0°", width = 40px }, | ||||
| 						Checkbox { id = shadowCheckbox, row = 18, content = "drop-shadow" }, | ||||
| 						ColorPicker { id = dropShadowColor, row = 18, column = 1, color = black, disabled = true }, | ||||
| 						NumberPicker { id = shadowXSlider, row = 19, type = slider, min = -20, max = 20, step = 1, value = 0, disabled = true }, | ||||
| 						TextView { id = shadowXValue, row = 19, column = 1, text = "x:0px", width = 40px }, | ||||
| 						NumberPicker { id = shadowYSlider, row = 20, type = slider, min = -20, max = 20, step = 1, value = 0, disabled = true }, | ||||
| 						TextView { id = shadowYValue, row = 20, column = 1, text = "y:0px", width = 40px }, | ||||
| 						NumberPicker { id = shadowBlurSlider, row = 21, type = slider, min = 0, max = 40, step = 1, disabled = true }, | ||||
| 						TextView { id = shadowBlurValue, row = 21, column = 1, text = "b:0px", width = 40px }, | ||||
| 					] | ||||
| 				} | ||||
| 			] | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| var filterParams = rui.Params{} | ||||
| 
 | ||||
| func createFilterDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, filterDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	setEvents := func(tag string) { | ||||
| 		rui.Set(view, tag+"Checkbox", rui.CheckboxChangedEvent, func(state bool) { | ||||
| 			slider := tag + "Slider" | ||||
| 			rui.Set(view, slider, rui.Disabled, !state) | ||||
| 			if state { | ||||
| 				filterParams[tag] = rui.GetNumberPickerValue(view, slider) | ||||
| 			} else { | ||||
| 				delete(filterParams, tag) | ||||
| 			} | ||||
| 			rui.Set(view, "filterImage", rui.Filter, rui.NewViewFilter(filterParams)) | ||||
| 		}) | ||||
| 
 | ||||
| 		rui.Set(view, tag+"Slider", rui.NumberChangedEvent, func(value float64) { | ||||
| 			var text string | ||||
| 			if tag == rui.Blur { | ||||
| 				text = fmt.Sprintf("%.2gpx", value) | ||||
| 			} else { | ||||
| 				text = fmt.Sprintf("%g%%", value) | ||||
| 			} | ||||
| 			rui.Set(view, tag+"Value", rui.Text, text) | ||||
| 			filterParams[tag] = value | ||||
| 			rui.Set(view, "filterImage", rui.Filter, rui.NewViewFilter(filterParams)) | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tag := range []string{rui.Blur, rui.Brightness, rui.Contrast, rui.Grayscale, rui.Invert, rui.Saturate, rui.Sepia, rui.Opacity} { | ||||
| 		setEvents(tag) | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "huerotateCheckbox", rui.CheckboxChangedEvent, func(state bool) { | ||||
| 		rui.Set(view, "huerotateSlider", rui.Disabled, !state) | ||||
| 		if state { | ||||
| 			filterParams[rui.HueRotate] = rui.AngleUnit{ | ||||
| 				Type:  rui.Degree, | ||||
| 				Value: rui.GetNumberPickerValue(view, "huerotateSlider"), | ||||
| 			} | ||||
| 		} else { | ||||
| 			delete(filterParams, rui.HueRotate) | ||||
| 		} | ||||
| 		rui.Set(view, "filterImage", rui.Filter, rui.NewViewFilter(filterParams)) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "huerotateSlider", rui.NumberChangedEvent, func(value float64) { | ||||
| 		rui.Set(view, "huerotateValue", rui.Text, fmt.Sprintf("%g°", value)) | ||||
| 		filterParams[rui.HueRotate] = rui.AngleUnit{Type: rui.Degree, Value: value} | ||||
| 		rui.Set(view, "filterImage", rui.Filter, rui.NewViewFilter(filterParams)) | ||||
| 	}) | ||||
| 
 | ||||
| 	updateShadow := func() { | ||||
| 		xOff := rui.SizeUnit{ | ||||
| 			Type:  rui.SizeInPixel, | ||||
| 			Value: rui.GetNumberPickerValue(view, "shadowXSlider"), | ||||
| 		} | ||||
| 		yOff := rui.SizeUnit{ | ||||
| 			Type:  rui.SizeInPixel, | ||||
| 			Value: rui.GetNumberPickerValue(view, "shadowYSlider"), | ||||
| 		} | ||||
| 		blur := rui.SizeUnit{ | ||||
| 			Type:  rui.SizeInPixel, | ||||
| 			Value: rui.GetNumberPickerValue(view, "shadowBlurSlider"), | ||||
| 		} | ||||
| 		color := rui.GetColorPickerValue(view, "dropShadowColor") | ||||
| 
 | ||||
| 		filterParams[rui.DropShadow] = rui.NewTextShadow(xOff, yOff, blur, color) | ||||
| 		rui.Set(view, "filterImage", rui.Filter, rui.NewViewFilter(filterParams)) | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "shadowCheckbox", rui.CheckboxChangedEvent, func(state bool) { | ||||
| 		for _, tag := range []string{"shadowXSlider", "shadowYSlider", "shadowBlurSlider", "dropShadowColor"} { | ||||
| 			rui.Set(view, tag, rui.Disabled, !state) | ||||
| 		} | ||||
| 		if state { | ||||
| 			updateShadow() | ||||
| 		} else { | ||||
| 			delete(filterParams, rui.DropShadow) | ||||
| 			rui.Set(view, "filterImage", rui.Filter, rui.NewViewFilter(filterParams)) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	for _, tag := range []string{"shadowXSlider", "shadowYSlider", "shadowBlurSlider"} { | ||||
| 		rui.Set(view, tag, rui.NumberChangedEvent, func(picker rui.NumberPicker, value float64) { | ||||
| 			tag := strings.Replace(picker.ID(), "Slider", "Value", -1) | ||||
| 			text := rui.GetText(view, tag) | ||||
| 			rui.Set(view, tag, rui.Text, fmt.Sprintf("%s%gpx", text[:2], value)) | ||||
| 			updateShadow() | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "dropShadowColor", rui.ColorChangedEvent, func(value rui.Color) { | ||||
| 		updateShadow() | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,103 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const gridLayoutDemoText = ` | ||||
| GridLayout { | ||||
| 	style = demoPage, | ||||
| 	content = [ | ||||
| 		GridLayout { | ||||
| 			id = gridLayout, width = 100%, height = 100%,  | ||||
| 			cell-width = "150px, 1fr, 30%", cell-height = "25%, 200px, 1fr", | ||||
| 			content = [ | ||||
| 				TextView { row = 0, column = 0:1, | ||||
| 					text = "View 1", text-align = center, vertical-align = center,  | ||||
| 					background-color = #DDFF0000, radius = 8px, padding = 32px,  | ||||
| 					border = _{ style = solid, width = 1px, color = #FFA0A0A0 }  | ||||
| 				}, | ||||
| 				TextView { row = 0:1, column = 2, | ||||
| 					text = "View 2", text-align = center, vertical-align = center,  | ||||
| 					background-color = #DD00FF00, radius = 8px, padding = 32px,  | ||||
| 					border = _{ style = solid, width = 1px, color = #FFA0A0A0 }  | ||||
| 				}, | ||||
| 				TextView { row = 1:2, column = 0, | ||||
| 					text = "View 3", text-align = center, vertical-align = center,  | ||||
| 					background-color = #DD0000FF, radius = 8px, padding = 32px,  | ||||
| 					border = _{ style = solid, width = 1px, color = #FFA0A0A0 }  | ||||
| 				}, | ||||
| 				TextView { row = 1, column = 1,  | ||||
| 					text = "View 4", text-align = center, vertical-align = center,  | ||||
| 					background-color = #DDFF00FF, radius = 8px, padding = 32px,  | ||||
| 					border = _{ style = solid, width = 1px, color = #FFA0A0A0 }  | ||||
| 				}, | ||||
| 				TextView { row = 2, column = 1:2, | ||||
| 					text = "View 5", text-align = center, vertical-align = center,  | ||||
| 					background-color = #DD00FFFF, radius = 8px, padding = 32px,  | ||||
| 					border = _{ style = solid, width = 1px, color = #FFA0A0A0 }  | ||||
| 				}, | ||||
| 			] | ||||
| 		}, | ||||
| 		ListLayout { | ||||
| 			style = optionsPanel, | ||||
| 			content = [ | ||||
| 				GridLayout { | ||||
| 					style = optionsTable, | ||||
| 					content = [ | ||||
| 						TextView { row = 0, text = "Vertical align" }, | ||||
| 						DropDownList { row = 0, column = 1, id = gridVAlign, current = 3, | ||||
| 							items = ["top", "bottom", "center", "stretch"] | ||||
| 						}, | ||||
| 						TextView { row = 1, text = "Horizontal align" }, | ||||
| 						DropDownList { row = 1, column = 1, id = gridHAlign, current = 3,  | ||||
| 							items = ["left", "right", "center", "stretch"] | ||||
| 						}, | ||||
| 						TextView { row = 2, text = "Column gap" }, | ||||
| 						DropDownList { row = 2, column = 1, id = gridColumnGap, current = 0, items = ["0", "8px"] }, | ||||
| 						TextView { row = 3, text = "Row gap" }, | ||||
| 						DropDownList { row = 3, column = 1, id = gridRowGap, current = 0, items = ["0", "8px"] }, | ||||
| 					] | ||||
| 				} | ||||
| 			] | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createGridLayoutDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, gridLayoutDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "gridHAlign", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "gridLayout", rui.CellHorizontalAlign, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "gridVAlign", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "gridLayout", rui.CellVerticalAlign, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "gridColumnGap", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		switch number { | ||||
| 		case 0: | ||||
| 			rui.Set(view, "gridLayout", rui.GridColumnGap, rui.SizeUnit{Type: rui.Auto, Value: 0}) | ||||
| 
 | ||||
| 		case 1: | ||||
| 			rui.Set(view, "gridLayout", rui.GridColumnGap, rui.Px(8)) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "gridRowGap", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		switch number { | ||||
| 		case 0: | ||||
| 			rui.Set(view, "gridLayout", rui.GridRowGap, rui.SizeUnit{Type: rui.Auto, Value: 0}) | ||||
| 
 | ||||
| 		case 1: | ||||
| 			rui.Set(view, "gridLayout", rui.GridRowGap, rui.Px(8)) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,63 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const imageViewDemoText = ` | ||||
| GridLayout { | ||||
| 	style = demoPage, | ||||
| 	content = [ | ||||
| 		ImageView { | ||||
| 			id = imageView1, width = 100%, height = 100%, src = "cat.jpg", | ||||
| 			border = _{ style = solid, width = 1px, color = #FF008800 }  | ||||
| 		}, | ||||
| 		ListLayout { | ||||
| 			style = optionsPanel, | ||||
| 			content = [ | ||||
| 				GridLayout { | ||||
| 					style = optionsTable, | ||||
| 					content = [ | ||||
| 						TextView { row = 0, text = "Image" }, | ||||
| 						DropDownList { row = 0, column = 1, id = imageViewImage, current = 0, items = ["cat.jpg", "winds.png", "gifsInEmail.gif", "mountain.svg"]}, | ||||
| 						TextView { row = 1, text = "Fit" }, | ||||
| 						DropDownList { row = 1, column = 1, id = imageViewFit, current = 0, items = ["none", "fill", "contain", "cover", "scale-down"]}, | ||||
| 						TextView { row = 2, text = "Horizontal align" }, | ||||
| 						DropDownList { row = 2, column = 1, id = imageViewHAlign, current = 2, items = ["left", "right", "center"]}, | ||||
| 						TextView { row = 3, text = "Vertical align" }, | ||||
| 						DropDownList { row = 3, column = 1, id = imageViewVAlign, current = 2, items = ["top", "bottom", "center"]}, | ||||
| 					] | ||||
| 				} | ||||
| 			] | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createImageViewDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, imageViewDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "imageViewImage", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		images := []string{"cat.jpg", "winds.png", "gifsInEmail.gif", "mountain.svg"} | ||||
| 		if number < len(images) { | ||||
| 			rui.Set(view, "imageView1", rui.Source, images[number]) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "imageViewFit", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "imageView1", rui.Fit, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "imageViewHAlign", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "imageView1", rui.ImageHorizontalAlign, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "imageViewVAlign", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "imageView1", rui.ImageVerticalAlign, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,57 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| func keyEventHandle(view rui.View, event rui.KeyEvent, tag string) { | ||||
| 	var buffer strings.Builder | ||||
| 
 | ||||
| 	buffer.WriteString(tag) | ||||
| 	buffer.WriteString(`: TimeStamp = `) | ||||
| 	buffer.WriteString(strconv.FormatUint(event.TimeStamp, 10)) | ||||
| 	buffer.WriteString(`, Key = "`) | ||||
| 	buffer.WriteString(event.Key) | ||||
| 	buffer.WriteString(`", Code = "`) | ||||
| 	buffer.WriteString(event.Code) | ||||
| 	buffer.WriteString(`"`) | ||||
| 
 | ||||
| 	appendBool := func(name string, value bool) { | ||||
| 		buffer.WriteString(`, `) | ||||
| 		buffer.WriteString(name) | ||||
| 		if value { | ||||
| 			buffer.WriteString(` = true`) | ||||
| 		} else { | ||||
| 			buffer.WriteString(` = false`) | ||||
| 		} | ||||
| 	} | ||||
| 	appendBool("Repeat", event.Repeat) | ||||
| 	appendBool("CtrlKey", event.CtrlKey) | ||||
| 	appendBool("ShiftKey", event.ShiftKey) | ||||
| 	appendBool("AltKey", event.AltKey) | ||||
| 	appendBool("MetaKey", event.MetaKey) | ||||
| 	buffer.WriteString(";\n\n") | ||||
| 
 | ||||
| 	rui.AppendEditText(view, "", buffer.String()) | ||||
| 	rui.ScrollViewToEnd(view, "") | ||||
| } | ||||
| 
 | ||||
| func createKeyEventsDemo(session rui.Session) rui.View { | ||||
| 	return rui.NewEditView(session, rui.Params{ | ||||
| 		rui.Width:        rui.Percent(100), | ||||
| 		rui.Height:       rui.Percent(100), | ||||
| 		rui.ReadOnly:     true, | ||||
| 		rui.Wrap:         true, | ||||
| 		rui.Hint:         "Set the focus and press a key", | ||||
| 		rui.EditViewType: rui.MultiLineText, | ||||
| 		rui.KeyDownEvent: func(view rui.View, event rui.KeyEvent) { | ||||
| 			keyEventHandle(view, event, rui.KeyDownEvent) | ||||
| 		}, | ||||
| 		rui.KeyUpEvent: func(view rui.View, event rui.KeyEvent) { | ||||
| 			keyEventHandle(view, event, rui.KeyUpEvent) | ||||
| 		}, | ||||
| 	}) | ||||
| } | ||||
|  | @ -0,0 +1,90 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const listLayoutDemoText = ` | ||||
| GridLayout { | ||||
| 	style = demoPage, | ||||
| 	content = [ | ||||
| 		ListLayout { | ||||
| 			id = listLayout, width = 100%, height = 100%, orientation = up-down, | ||||
| 			content = [ | ||||
| 				GridLayout { width = 200px, height = 100px, content = ["View 1"], horizontal-align = center, vertical-align = center,  | ||||
| 					background-color = #FFAAAAAA, radius = 8px, padding = 8px, margin = 4px, | ||||
| 					border = _{ style = solid, width = 1px, color = black }  | ||||
| 				}, | ||||
| 				GridLayout { width = 100px, height = 200px, content = ["View 2"], horizontal-align = center, vertical-align = center,  | ||||
| 					background-color = #FFB0B0B0, radius = 8px, padding = 8px, margin = 4px, | ||||
| 					border = _{ style = solid, width = 1px, color = black }  | ||||
| 				}, | ||||
| 				GridLayout { width = 150px, height = 150px, content = ["View 3"], horizontal-align = center, vertical-align = center,  | ||||
| 					background-color = #FFBBBBBB, radius = 8px, padding = 8px, margin = 4px, | ||||
| 					border = _{ style = solid, width = 1px, color = black }  | ||||
| 				}, | ||||
| 				GridLayout { width = 150px, height = 100px, content = ["View 4"], horizontal-align = center, vertical-align = center,  | ||||
| 					background-color = #FFC0C0C0, radius = 8px, padding = 8px, margin = 4px, | ||||
| 					border = _{ style = solid, width = 1px, color = black }  | ||||
| 				}, | ||||
| 				GridLayout { width = 200px, height = 150px, content = ["View 5"], horizontal-align = center, vertical-align = center,  | ||||
| 					background-color = #FFCCCCCC, radius = 8px, padding = 8px, margin = 4px, | ||||
| 					border = _{ style = solid, width = 1px, color = black }  | ||||
| 				}, | ||||
| 				GridLayout { width = 100px, height = 100px, content = ["View 6"], horizontal-align = center, vertical-align = center,  | ||||
| 					background-color = #FFDDDDDD, radius = 8px, padding = 8px, margin = 4px, | ||||
| 					border = _{ style = solid, width = 1px, color = black }  | ||||
| 				}, | ||||
| 				GridLayout { width = 150px, height = 200px, content = ["View 7"], horizontal-align = center, vertical-align = center,  | ||||
| 					background-color = #FFEEEEEE, radius = 8px, padding = 8px, margin = 4px, | ||||
| 					border = _{ style = solid, width = 1px, color = black }  | ||||
| 				}, | ||||
| 			] | ||||
| 		}, | ||||
| 		ListLayout { | ||||
| 			style = optionsPanel, | ||||
| 			content = [ | ||||
| 				GridLayout { | ||||
| 					style = optionsTable, | ||||
| 					content = [ | ||||
| 						TextView { row = 0, text = "Orientation" }, | ||||
| 						DropDownList { row = 0, column = 1, id = listOrientation, current = 0, | ||||
| 							items = ["up-down", "start-to-end", "bottom-up", "end-to-start"] | ||||
| 						}, | ||||
| 						TextView { row = 1, text = "Wrap" }, | ||||
| 						DropDownList { row = 1, column = 1, id = listWrap, current = 0, items = ["off", "on", "reverse"]}, | ||||
| 						TextView { row = 2, text = "Vertical align" }, | ||||
| 						DropDownList { row = 2, column = 1, id = listVAlign, current = 0, items = ["top", "bottom", "center", "stretch"]}, | ||||
| 						TextView { row = 3, text = "Horizontal align" }, | ||||
| 						DropDownList { row = 3, column = 1, id = listHAlign, current = 0, items = ["left", "right", "center", "stretch"]}, | ||||
| 					] | ||||
| 				}, | ||||
| 			] | ||||
| 		} | ||||
| 	]		 | ||||
| }` | ||||
| 
 | ||||
| func createListLayoutDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, listLayoutDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "listOrientation", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "listLayout", rui.Orientation, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "listWrap", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "listLayout", rui.Wrap, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "listHAlign", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "listLayout", rui.HorizontalAlign, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "listVAlign", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "listLayout", rui.VerticalAlign, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,95 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const listViewDemoText = ` | ||||
| GridLayout { | ||||
| 	style = demoPage, | ||||
| 	content = [ | ||||
| 		ListView { | ||||
| 			id = listView, width = 100%, height = 100%, orientation = vertical, | ||||
| 			items = ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", "Item 9", "Item 10", "Item 11", "Item 12", "Item 13", "Item 14", "Item 15", "Item 16", "Item 17", "Item 18"] | ||||
| 		}, | ||||
| 		ListLayout { | ||||
| 			style = optionsPanel, | ||||
| 			content = [ | ||||
| 				GridLayout { | ||||
| 					style = optionsTable, | ||||
| 					content = [ | ||||
| 						TextView { row = 0, text = "Orientation" }, | ||||
| 						DropDownList { row = 0, column = 1, id = listViewOrientation, current = 0, items = ["vertical", "horizontal", "bottom up", "end to start"]}, | ||||
| 						TextView { row = 1, text = "Wrap" }, | ||||
| 						DropDownList { row = 1, column = 1, id = listWrap, current = 0, items = ["off", "on", "reverse"]}, | ||||
| 						TextView { row = 2, text = "Item height" }, | ||||
| 						DropDownList { row = 2, column = 1, id = listItemHeight, current = 0, items = ["auto", "25%", "50px"]}, | ||||
| 						TextView { row = 3, text = "Item width" }, | ||||
| 						DropDownList { row = 3, column = 1, id = listItemWidth, current = 0, items = ["auto", "25%", "200px"]}, | ||||
| 						TextView { row = 4, text = "Item vertical align" }, | ||||
| 						DropDownList { row = 4, column = 1, id = listItemVAlign, current = 0, items = ["top", "bottom", "center"]}, | ||||
| 						TextView { row = 5, text = "Item horizontal align" }, | ||||
| 						DropDownList { row = 5, column = 1, id = listItemHAlign, current = 0, items = ["left", "right", "center"]}, | ||||
| 						TextView { row = 6, text = "Checkbox" }, | ||||
| 						DropDownList { row = 6, column = 1, id = listCheckbox, current = 0, items = ["none", "single", "multiple"]}, | ||||
| 						TextView { row = 7, text = "Checkbox vertical align" }, | ||||
| 						DropDownList { row = 7, column = 1, id = listCheckboxVAlign, current = 0, items = ["top", "bottom", "center"]}, | ||||
| 						TextView { row = 8, text = "Checkbox horizontal align" }, | ||||
| 						DropDownList { row = 8, column = 1, id = listCheckboxHAlign, current = 0, items = ["left", "right", "center"]}, | ||||
| 					] | ||||
| 				} | ||||
| 			] | ||||
| 		} | ||||
| 	] | ||||
| }` | ||||
| 
 | ||||
| func createListViewDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, listViewDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "listViewOrientation", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "listView", rui.Orientation, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "listWrap", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "listView", rui.Wrap, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	setItemSize := func(tag string, number int, values []rui.SizeUnit) { | ||||
| 		if number >= 0 && number < len(values) { | ||||
| 			rui.Set(view, "listView", tag, values[number]) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "listItemWidth", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		setItemSize(rui.ItemWidth, number, []rui.SizeUnit{rui.AutoSize(), rui.Percent(25), rui.Px(200)}) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "listItemHeight", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		setItemSize(rui.ItemHeight, number, []rui.SizeUnit{rui.AutoSize(), rui.Percent(25), rui.Px(50)}) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "listItemVAlign", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "listView", rui.VerticalAlign, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "listItemHAlign", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "listView", rui.HorizontalAlign, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "listCheckbox", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "listView", rui.ItemCheckbox, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "listCheckboxVAlign", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "listView", rui.CheckboxVerticalAlign, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "listCheckboxHAlign", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "listView", rui.CheckboxHorizontalAlign, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,163 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"embed" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| //go:embed resources
 | ||||
| var resources embed.FS | ||||
| 
 | ||||
| const rootViewText = ` | ||||
| GridLayout { | ||||
| 	id = rootLayout, width = 100%, height = 100%, cell-height = "auto, 1fr", | ||||
| 	content = [ | ||||
| 		GridLayout { | ||||
| 			id = rootTitle, width = 100%, cell-width = "auto, 1fr",  | ||||
| 			cell-vertical-align = center, background-color = #ffc0ded9, | ||||
| 			content = [ | ||||
| 				ImageView {  | ||||
| 					id = rootTitleButton, padding = 8px, src = menu_icon.svg, | ||||
| 				}, | ||||
| 				TextView {  | ||||
| 					id = rootTitleText, column = 1, padding-left = 8px, text = "Title", | ||||
| 				} | ||||
| 			], | ||||
| 		}, | ||||
| 		StackLayout { | ||||
| 			id = rootViews, row = 1, | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| type demoPage struct { | ||||
| 	title   string | ||||
| 	creator func(session rui.Session) rui.View | ||||
| 	view    rui.View | ||||
| } | ||||
| 
 | ||||
| type demoSession struct { | ||||
| 	rootView rui.View | ||||
| 	pages    []demoPage | ||||
| } | ||||
| 
 | ||||
| func (demo *demoSession) OnStart(session rui.Session) { | ||||
| 	rui.DebugLog("Session start") | ||||
| } | ||||
| 
 | ||||
| func (demo *demoSession) OnFinish(session rui.Session) { | ||||
| 	rui.DebugLog("Session finish") | ||||
| } | ||||
| 
 | ||||
| func (demo *demoSession) OnResume(session rui.Session) { | ||||
| 	rui.DebugLog("Session resume") | ||||
| } | ||||
| 
 | ||||
| func (demo *demoSession) OnPause(session rui.Session) { | ||||
| 	rui.DebugLog("Session pause") | ||||
| } | ||||
| 
 | ||||
| func (demo *demoSession) OnDisconnect(session rui.Session) { | ||||
| 	rui.DebugLog("Session disconnect") | ||||
| } | ||||
| 
 | ||||
| func (demo *demoSession) OnReconnect(session rui.Session) { | ||||
| 	rui.DebugLog("Session reconnect") | ||||
| } | ||||
| 
 | ||||
| func createDemo(session rui.Session) rui.SessionContent { | ||||
| 	sessionContent := new(demoSession) | ||||
| 	sessionContent.pages = []demoPage{ | ||||
| 		{"Text style", createTextStyleDemo, nil}, | ||||
| 		{"View border", viewDemo, nil}, | ||||
| 		{"Background image", createBackgroundDemo, nil}, | ||||
| 		{"ListLayout", createListLayoutDemo, nil}, | ||||
| 		{"GridLayout", createGridLayoutDemo, nil}, | ||||
| 		{"ColumnLayout", createColumnLayoutDemo, nil}, | ||||
| 		{"StackLayout", createStackLayoutDemo, nil}, | ||||
| 		{"AbsoluteLayout", createAbsoluteLayoutDemo, nil}, | ||||
| 		{"Resizable", createResizableDemo, nil}, | ||||
| 		{"ListView", createListViewDemo, nil}, | ||||
| 		{"Checkbox", createCheckboxDemo, nil}, | ||||
| 		{"Controls", createControlsDemo, nil}, | ||||
| 		{"TableView", createTableViewDemo, nil}, | ||||
| 		{"EditView", createEditDemo, nil}, | ||||
| 		{"ImageView", createImageViewDemo, nil}, | ||||
| 		{"Canvas", createCanvasDemo, nil}, | ||||
| 		{"VideoPlayer", createVideoPlayerDemo, nil}, | ||||
| 		{"AudioPlayer", createAudioPlayerDemo, nil}, | ||||
| 		{"Popups", createPopupDemo, nil}, | ||||
| 		{"Filter", createFilterDemo, nil}, | ||||
| 		{"Clip", createClipDemo, nil}, | ||||
| 		{"Transform", transformDemo, nil}, | ||||
| 		{"Transition", createTransitionDemo, nil}, | ||||
| 		{"Key events", createKeyEventsDemo, nil}, | ||||
| 		{"Mouse events", createMouseEventsDemo, nil}, | ||||
| 		{"Pointer events", createPointerEventsDemo, nil}, | ||||
| 		{"Touch events", createTouchEventsDemo, nil}, | ||||
| 		//{"Tabs", createTabsDemo, nil},
 | ||||
| 	} | ||||
| 
 | ||||
| 	return sessionContent | ||||
| } | ||||
| 
 | ||||
| func (demo *demoSession) CreateRootView(session rui.Session) rui.View { | ||||
| 	demo.rootView = rui.CreateViewFromText(session, rootViewText) | ||||
| 	if demo.rootView == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(demo.rootView, "rootTitleButton", rui.ClickEvent, demo.clickMenuButton) | ||||
| 	demo.showPage(0) | ||||
| 
 | ||||
| 	return demo.rootView | ||||
| } | ||||
| 
 | ||||
| func (demo *demoSession) clickMenuButton() { | ||||
| 	items := make([]string, len(demo.pages)) | ||||
| 	for i, page := range demo.pages { | ||||
| 		items[i] = page.title | ||||
| 	} | ||||
| 
 | ||||
| 	rui.ShowMenu(demo.rootView.Session(), rui.Params{ | ||||
| 		rui.Items:           items, | ||||
| 		rui.OutsideClose:    true, | ||||
| 		rui.VerticalAlign:   rui.TopAlign, | ||||
| 		rui.HorizontalAlign: rui.LeftAlign, | ||||
| 		rui.PopupMenuResult: func(n int) { | ||||
| 			demo.showPage(n) | ||||
| 		}, | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func (demo *demoSession) showPage(index int) { | ||||
| 	if index < 0 || index >= len(demo.pages) { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if stackLayout := rui.StackLayoutByID(demo.rootView, "rootViews"); stackLayout != nil { | ||||
| 		if demo.pages[index].view == nil { | ||||
| 			demo.pages[index].view = demo.pages[index].creator(demo.rootView.Session()) | ||||
| 			stackLayout.Append(demo.pages[index].view) | ||||
| 		} else { | ||||
| 			stackLayout.MoveToFront(demo.pages[index].view) | ||||
| 		} | ||||
| 		rui.Set(demo.rootView, "rootTitleText", rui.Text, demo.pages[index].title) | ||||
| 	} | ||||
| 	// TODO
 | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	rui.ProtocolInDebugLog = true | ||||
| 	rui.AddEmbedResources(&resources) | ||||
| 	app := rui.NewApplication("RUI demo", "icon.svg", createDemo) | ||||
| 
 | ||||
| 	//addr := rui.GetLocalIP() + ":8080"
 | ||||
| 	addr := "localhost:8000" | ||||
| 	fmt.Print(addr) | ||||
| 	rui.OpenBrowser("http://" + addr) | ||||
| 	app.Start(addr) | ||||
| } | ||||
|  | @ -0,0 +1,111 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const mouseEventsDemoText = ` | ||||
| GridLayout { | ||||
| 	width = 100%, height = 100%, cell-height = "1fr, auto", | ||||
| 	content = [ | ||||
| 		GridLayout { | ||||
| 			padding = 12px, | ||||
| 			content = [ | ||||
| 				GridLayout { | ||||
| 					id = mouseEventsTest, cell-horizontal-align = center, cell-vertical-align = center, | ||||
| 					height = 150%, | ||||
| 					border = _{ style = solid, width = 1px, color = gray}, | ||||
| 					content = [ | ||||
| 						TextView { | ||||
| 							id = mouseEventsText, text = "Test box", | ||||
| 						} | ||||
| 					] | ||||
| 				} | ||||
| 			], | ||||
| 		}, | ||||
| 		Resizable { | ||||
| 			row = 1, side = top, background-color = lightgrey, height = 200px, | ||||
| 			content = EditView { | ||||
| 				id = mouseEventsLog, type = multiline, read-only = true, wrap = true, | ||||
| 			} | ||||
| 		}, | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createMouseEventsDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, mouseEventsDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	addToLog := func(tag string, event rui.MouseEvent) { | ||||
| 		var buffer strings.Builder | ||||
| 
 | ||||
| 		appendBool := func(name string, value bool) { | ||||
| 			buffer.WriteString(`, `) | ||||
| 			buffer.WriteString(name) | ||||
| 			if value { | ||||
| 				buffer.WriteString(` = true`) | ||||
| 			} else { | ||||
| 				buffer.WriteString(` = false`) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		appendInt := func(name string, value int) { | ||||
| 			buffer.WriteString(`, `) | ||||
| 			buffer.WriteString(name) | ||||
| 			buffer.WriteString(` = `) | ||||
| 			buffer.WriteString(strconv.Itoa(value)) | ||||
| 		} | ||||
| 
 | ||||
| 		appendPoint := func(name string, x, y float64) { | ||||
| 			buffer.WriteString(fmt.Sprintf(`, %s = (%g:%g)`, name, x, y)) | ||||
| 		} | ||||
| 
 | ||||
| 		buffer.WriteString(tag) | ||||
| 		buffer.WriteString(`: TimeStamp = `) | ||||
| 		buffer.WriteString(strconv.FormatUint(event.TimeStamp, 10)) | ||||
| 
 | ||||
| 		appendInt("Button", event.Button) | ||||
| 		appendInt("Buttons", event.Buttons) | ||||
| 		appendPoint("(X:Y)", event.X, event.Y) | ||||
| 		appendPoint("Client (X:Y)", event.ClientX, event.ClientY) | ||||
| 		appendPoint("Screen (X:Y)", event.ScreenX, event.ScreenY) | ||||
| 		appendBool("CtrlKey", event.CtrlKey) | ||||
| 		appendBool("ShiftKey", event.ShiftKey) | ||||
| 		appendBool("AltKey", event.AltKey) | ||||
| 		appendBool("MetaKey", event.MetaKey) | ||||
| 		buffer.WriteString(";\n\n") | ||||
| 
 | ||||
| 		rui.AppendEditText(view, "mouseEventsLog", buffer.String()) | ||||
| 		rui.ScrollViewToEnd(view, "mouseEventsLog") | ||||
| 	} | ||||
| 
 | ||||
| 	rui.SetParams(view, "mouseEventsTest", rui.Params{ | ||||
| 		rui.MouseDown: func(v rui.View, event rui.MouseEvent) { | ||||
| 			addToLog("mouse-down", event) | ||||
| 		}, | ||||
| 		rui.MouseUp: func(v rui.View, event rui.MouseEvent) { | ||||
| 			addToLog("mouse-up", event) | ||||
| 		}, | ||||
| 		rui.MouseOut: func(v rui.View, event rui.MouseEvent) { | ||||
| 			addToLog("mouse-out", event) | ||||
| 			rui.Set(view, "mouseEventsText", rui.Text, "Mouse out") | ||||
| 		}, | ||||
| 		rui.MouseOver: func(v rui.View, event rui.MouseEvent) { | ||||
| 			addToLog("mouse-over", event) | ||||
| 		}, | ||||
| 		rui.MouseMove: func(v rui.View, event rui.MouseEvent) { | ||||
| 			rui.Set(view, "mouseEventsText", rui.Text, | ||||
| 				fmt.Sprintf("(X:Y): (%g : %g)<br>Client (X:Y): (%g : %g)<br>Screen (X:Y): (%g : %g)", | ||||
| 					event.X, event.Y, event.ClientX, event.ClientY, event.ScreenX, event.ScreenY)) | ||||
| 		}, | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,129 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const pointerEventsDemoText = ` | ||||
| GridLayout { | ||||
| 	width = 100%, height = 100%, cell-height = "1fr, auto", | ||||
| 	content = [ | ||||
| 		GridLayout { | ||||
| 			padding = 12px, | ||||
| 			content = [ | ||||
| 				GridLayout { | ||||
| 					id = pointerEventsTest, cell-horizontal-align = center, cell-vertical-align = center, | ||||
| 					border = _{ style = solid, width = 1px, color = gray}, | ||||
| 					content = [ | ||||
| 						TextView { | ||||
| 							id = pointerEventsText, text = "Test box", | ||||
| 						} | ||||
| 					] | ||||
| 				} | ||||
| 			], | ||||
| 		}, | ||||
| 		Resizable { | ||||
| 			row = 1, side = top, background-color = lightgrey, height = 200px, | ||||
| 			content = EditView { | ||||
| 				id = pointerEventsLog, type = multiline, read-only = true, wrap = true, | ||||
| 			} | ||||
| 		}, | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createPointerEventsDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, pointerEventsDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	addToLog := func(tag string, event rui.PointerEvent) { | ||||
| 		var buffer strings.Builder | ||||
| 
 | ||||
| 		appendBool := func(name string, value bool) { | ||||
| 			buffer.WriteString(`, `) | ||||
| 			buffer.WriteString(name) | ||||
| 			if value { | ||||
| 				buffer.WriteString(` = true`) | ||||
| 			} else { | ||||
| 				buffer.WriteString(` = false`) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		appendInt := func(name string, value int) { | ||||
| 			buffer.WriteString(`, `) | ||||
| 			buffer.WriteString(name) | ||||
| 			buffer.WriteString(` = `) | ||||
| 			buffer.WriteString(strconv.Itoa(value)) | ||||
| 		} | ||||
| 
 | ||||
| 		appendFloat := func(name string, value float64) { | ||||
| 			buffer.WriteString(fmt.Sprintf(`, %s = %g`, name, value)) | ||||
| 		} | ||||
| 
 | ||||
| 		appendPoint := func(name string, x, y float64) { | ||||
| 			buffer.WriteString(fmt.Sprintf(`, %s = (%g:%g)`, name, x, y)) | ||||
| 		} | ||||
| 
 | ||||
| 		buffer.WriteString(tag) | ||||
| 		buffer.WriteString(`: TimeStamp = `) | ||||
| 		buffer.WriteString(strconv.FormatUint(event.TimeStamp, 10)) | ||||
| 
 | ||||
| 		appendInt("Button", event.Button) | ||||
| 		appendInt("Buttons", event.Buttons) | ||||
| 		appendPoint("(X:Y)", event.X, event.Y) | ||||
| 		appendPoint("Client (X:Y)", event.ClientX, event.ClientY) | ||||
| 		appendPoint("Screen (X:Y)", event.ScreenX, event.ScreenY) | ||||
| 		appendFloat("Width", event.Width) | ||||
| 		appendFloat("Height", event.Height) | ||||
| 		appendFloat("Pressure", event.Pressure) | ||||
| 		appendFloat("TangentialPressure", event.TangentialPressure) | ||||
| 		appendFloat("TiltX", event.TiltX) | ||||
| 		appendFloat("TiltY", event.TiltY) | ||||
| 		appendFloat("Twist", event.Twist) | ||||
| 
 | ||||
| 		buffer.WriteString(`, PointerType = `) | ||||
| 		buffer.WriteString(event.PointerType) | ||||
| 
 | ||||
| 		appendBool("IsPrimary", event.IsPrimary) | ||||
| 		appendBool("CtrlKey", event.CtrlKey) | ||||
| 		appendBool("ShiftKey", event.ShiftKey) | ||||
| 		appendBool("AltKey", event.AltKey) | ||||
| 		appendBool("MetaKey", event.MetaKey) | ||||
| 		buffer.WriteString(";\n\n") | ||||
| 
 | ||||
| 		rui.AppendEditText(view, "pointerEventsLog", buffer.String()) | ||||
| 		rui.ScrollViewToEnd(view, "pointerEventsLog") | ||||
| 	} | ||||
| 
 | ||||
| 	rui.SetParams(view, "pointerEventsTest", rui.Params{ | ||||
| 		rui.PointerDown: func(v rui.View, event rui.PointerEvent) { | ||||
| 			addToLog("pointer-down", event) | ||||
| 		}, | ||||
| 		rui.PointerUp: func(v rui.View, event rui.PointerEvent) { | ||||
| 			addToLog("pointer-up", event) | ||||
| 		}, | ||||
| 		rui.PointerOut: func(v rui.View, event rui.PointerEvent) { | ||||
| 			addToLog("pointer-out", event) | ||||
| 			rui.Set(view, "pointerEventsText", rui.Text, "Pointer out") | ||||
| 		}, | ||||
| 		rui.PointerOver: func(v rui.View, event rui.PointerEvent) { | ||||
| 			addToLog("pointer-over", event) | ||||
| 		}, | ||||
| 		rui.PointerCancel: func(v rui.View, event rui.PointerEvent) { | ||||
| 			addToLog("pointer-cancel", event) | ||||
| 		}, | ||||
| 		rui.PointerMove: func(v rui.View, event rui.PointerEvent) { | ||||
| 			rui.Set(view, "pointerEventsText", rui.Text, | ||||
| 				fmt.Sprintf("(X:Y): (%g : %g)<br>Client (X:Y): (%g : %g)<br>Screen (X:Y): (%g : %g)", | ||||
| 					event.X, event.Y, event.ClientX, event.ClientY, event.ScreenX, event.ScreenY)) | ||||
| 		}, | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,86 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const popupDemoText = ` | ||||
| GridLayout { | ||||
| 	width = 100%, height = 100%, cell-height = "auto, 1fr", | ||||
| 	content = GridLayout { | ||||
| 		width = 100%, cell-width = "auto, 1fr", | ||||
| 		cell-vertical-align = center, gap = 8px, | ||||
| 		content = [ | ||||
| 			Button { | ||||
| 				id = popupShowMessage, margin = 4px, content = "Show message", | ||||
| 			}, | ||||
| 			Button { | ||||
| 				id = popupShowQuestion, row = 1, margin = 4px, content = "Show question", | ||||
| 			}, | ||||
| 			TextView { | ||||
| 				id = popupShowQuestionResult, row = 1, column = 1,  | ||||
| 			}, | ||||
| 			Button { | ||||
| 				id = popupShowCancellableQuestion, row = 2, margin = 4px, content = "Show cancellable question", | ||||
| 			}, | ||||
| 			TextView { | ||||
| 				id = popupShowCancellableQuestionResult, row = 2, column = 1,  | ||||
| 			}, | ||||
| 			Button { | ||||
| 				id = popupShowMenu, row = 3, margin = 4px, content = "Show menu", | ||||
| 			}, | ||||
| 			TextView { | ||||
| 				id = popupShowMenuResult, row = 3, column = 1,  | ||||
| 			}, | ||||
| 		] | ||||
| 	} | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createPopupDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, popupDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "popupShowMessage", rui.ClickEvent, func() { | ||||
| 		rui.ShowMessage("Hello", "Hello world!!!", session) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "popupShowQuestion", rui.ClickEvent, func() { | ||||
| 		rui.ShowQuestion("Hello", "Are you alright?", session, | ||||
| 			func() { | ||||
| 				rui.Set(view, "popupShowQuestionResult", rui.Text, "Answer: Yes") | ||||
| 			}, | ||||
| 			func() { | ||||
| 				rui.Set(view, "popupShowQuestionResult", rui.Text, "Answer: No") | ||||
| 			}) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "popupShowCancellableQuestion", rui.ClickEvent, func() { | ||||
| 		rui.ShowCancellableQuestion("Hello", "Are you alright?", session, | ||||
| 			func() { | ||||
| 				rui.Set(view, "popupShowCancellableQuestionResult", rui.Text, "Answer: Yes") | ||||
| 			}, | ||||
| 			func() { | ||||
| 				rui.Set(view, "popupShowCancellableQuestionResult", rui.Text, "Answer: No") | ||||
| 			}, | ||||
| 			func() { | ||||
| 				rui.Set(view, "popupShowCancellableQuestionResult", rui.Text, "Answer: Cancel") | ||||
| 			}) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "popupShowMenu", rui.ClickEvent, func() { | ||||
| 		rui.ShowMenu(session, rui.Params{ | ||||
| 			rui.Items: []string{"Item 1", "Item 2", "Item 3", "Item 4"}, | ||||
| 			rui.Title: "Menu", | ||||
| 			rui.PopupMenuResult: func(n int) { | ||||
| 				rui.Set(view, "popupShowMenuResult", rui.Text, fmt.Sprintf("Item %d selected", n+1)) | ||||
| 			}, | ||||
| 		}) | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,79 @@ | |||
| package main | ||||
| 
 | ||||
| import "github.com/anoshenko/rui" | ||||
| 
 | ||||
| const resizableDemoText = ` | ||||
| GridLayout { | ||||
| 	cell-width = "auto, 1fr, auto", cell-height = "auto, 1fr, auto", | ||||
| 	content = [ | ||||
| 		Resizable { | ||||
| 			id = resizableTop, column = 0:2, row = 0, side = bottom, | ||||
| 			background-color = lightgrey, | ||||
| 			content = GridLayout { | ||||
| 				cell-vertical-align = center, cell-horizontal-align = center, | ||||
| 				background-color = yellow, padding = 8px, content = "Top", | ||||
| 			} | ||||
| 		}, | ||||
| 		Resizable { | ||||
| 			id = resizableBottom, column = 0:2, row = 2, side = top, | ||||
| 			background-color = lightgrey, | ||||
| 			content = GridLayout { | ||||
| 				cell-vertical-align = center, cell-horizontal-align = center, | ||||
| 				background-color = lightcoral, padding = 8px, content = "Bottom", | ||||
| 			} | ||||
| 		}, | ||||
| 		Resizable { | ||||
| 			id = resizableLeft, column = 0, row = 0:2, side = right, | ||||
| 			background-color = lightgrey, | ||||
| 			content = GridLayout { | ||||
| 				cell-vertical-align = center, cell-horizontal-align = center, | ||||
| 				background-color = lightskyblue, padding = 8px, content = "Left", | ||||
| 			} | ||||
| 		}, | ||||
| 		Resizable { | ||||
| 			id = resizableRight, column = 2, row = 0:2, side = left, | ||||
| 			background-color = lightgrey, | ||||
| 			content = GridLayout { | ||||
| 				cell-vertical-align = center, cell-horizontal-align = center, | ||||
| 				background-color = lightpink, padding = 8px, content = "Right", | ||||
| 			} | ||||
| 		} | ||||
| 		GridLayout { | ||||
| 			column = 1, row = 1, cell-vertical-align = center, cell-horizontal-align = center, | ||||
| 			content = Resizable { | ||||
| 				id = resizableRight, side = all, | ||||
| 				background-color = lightgrey, | ||||
| 				content = GridLayout { | ||||
| 					cell-vertical-align = center, cell-horizontal-align = center, | ||||
| 					background-color = lightseagreen, padding = 8px, content = "Center", | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createResizableDemo(session rui.Session) rui.View { | ||||
| 	return rui.CreateViewFromText(session, resizableDemoText) | ||||
| 	/* | ||||
| 		return rui.NewGridLayout(session, rui.Params{ | ||||
| 			rui.CellWidth:  []rui.SizeUnit{rui.AutoSize(), rui.Fr(1), rui.AutoSize()}, | ||||
| 			rui.CellHeight: []rui.SizeUnit{rui.AutoSize(), rui.Fr(1), rui.AutoSize()}, | ||||
| 			rui.Content: []rui.View{ | ||||
| 				rui.NewResizable(session, rui.Params{ | ||||
| 					rui.ID:              "resizableTop", | ||||
| 					rui.Column:          rui.Range{First: 0, Last: 2}, | ||||
| 					rui.Row:             0, | ||||
| 					rui.Side:            rui.BottomSide, | ||||
| 					rui.BackgroundColor: rui.LightGray, | ||||
| 					rui.Content: rui.NewGridLayout(session, rui.Params{ | ||||
| 						rui.BackgroundColor:     rui.Yellow, | ||||
| 						rui.CellHorizontalAlign: rui.CenterAlign, | ||||
| 						rui.CellVerticalAlign:   rui.CenterAlign, | ||||
| 						rui.Content:             "Top", | ||||
| 					}), | ||||
| 				}), | ||||
| 			}, | ||||
| 		}) | ||||
| 	*/ | ||||
| } | ||||
| After Width: | Height: | Size: 14 KiB | 
| After Width: | Height: | Size: 6.4 KiB | 
| After Width: | Height: | Size: 49 KiB | 
| After Width: | Height: | Size: 49 KiB | 
| After Width: | Height: | Size: 140 KiB | 
|  | @ -0,0 +1,73 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
| 
 | ||||
| <svg | ||||
|    width="32" | ||||
|    height="32" | ||||
|    viewBox="0 0 32 32" | ||||
|    version="1.1" | ||||
|    id="svg5" | ||||
|    inkscape:version="1.1 (c4e8f9e, 2021-05-24)" | ||||
|    sodipodi:docname="icon.svg" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg"> | ||||
|   <sodipodi:namedview | ||||
|      id="namedview7" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pagecheckerboard="true" | ||||
|      inkscape:document-units="px" | ||||
|      showgrid="false" | ||||
|      units="px" | ||||
|      inkscape:showpageshadow="false" | ||||
|      inkscape:zoom="12" | ||||
|      inkscape:cx="21.833333" | ||||
|      inkscape:cy="12.916667" | ||||
|      inkscape:window-width="1920" | ||||
|      inkscape:window-height="968" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="25" | ||||
|      inkscape:window-maximized="1" | ||||
|      inkscape:current-layer="text3598" /> | ||||
|   <defs | ||||
|      id="defs2" /> | ||||
|   <g | ||||
|      inkscape:label="Слой 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1"> | ||||
|     <g | ||||
|        aria-label="RUI" | ||||
|        id="text3598" | ||||
|        style="font-size:42.6667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial" | ||||
|        transform="translate(5.5624978,0.70835736)"> | ||||
|       <rect | ||||
|          style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3.653" | ||||
|          id="rect4231" | ||||
|          width="32" | ||||
|          height="32" | ||||
|          x="-5.5624976" | ||||
|          y="-0.70835733" /> | ||||
|       <g | ||||
|          id="g4207" | ||||
|          transform="matrix(0.5463357,0,0,0.96874999,-2.0235067,0.47786383)"> | ||||
|         <path | ||||
|            d="M -5.5624978,31.291643 V -0.70835736 H 7.9791789 q 4.0833361,0 6.2083381,0.87312414 2.125001,0.85129602 3.395836,3.03410642 1.270834,2.1828104 1.270834,4.8240109 0,3.4051849 -2.104168,5.7407909 -2.104168,2.335607 -6.500005,2.968622 1.604168,0.80764 2.437502,1.593452 1.770834,1.702592 3.354169,4.25648 l 5.312504,8.709414 h -5.083337 l -4.04167,-6.657572 Q 10.458347,21.752762 9.3125133,20.224794 8.1666791,18.696827 7.2500117,18.08564 6.3541777,17.474453 5.416677,17.234343 4.7291765,17.081547 3.1666754,17.081547 h -4.6875035 v 14.210096 z m 4.0416697,-17.877218 h 8.6875064 q 2.7708354,0 4.3333367,-0.589358 1.562501,-0.611187 2.375002,-1.920873 0.8125,-1.3315145 0.8125,-2.8813099 0,-2.2701228 -1.583334,-3.7326057 Q 11.541682,2.8277955 8.1458457,2.8277955 h -9.6666738 z" | ||||
|            id="path4000" | ||||
|            style="stroke-width:1.0236" /> | ||||
|         <path | ||||
|            d="m 41.016684,-0.70835736 h 4.041669 V 17.470046 q 0,4.743125 -1.041667,7.5332 -1.041668,2.790073 -3.770836,4.549966 -2.708336,1.738431 -7.125006,1.738431 -4.291669,0 -7.020838,-1.52381 -2.729169,-1.52381 -3.895836,-4.399732 -1.166668,-2.897384 -1.166668,-7.898055 V -0.70835736 h 4.04167 V 17.448584 q 0,4.099262 0.729167,6.052314 0.75,1.93159 2.541668,2.983233 1.812502,1.051643 4.41667,1.051643 4.458337,0 6.354172,-2.081824 1.895835,-2.081825 1.895835,-8.005366 z" | ||||
|            id="path4002" | ||||
|            style="stroke-width:1.01498" /> | ||||
|         <path | ||||
|            d="M 47.137502,31.291643 V -0.70835736 h 4.04167 V 31.291643 Z" | ||||
|            id="path4004" | ||||
|            style="stroke-width:1.0236" /> | ||||
|       </g> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 3.3 KiB | 
| After Width: | Height: | Size: 143 B | 
| After Width: | Height: | Size: 257 B | 
| After Width: | Height: | Size: 325 B | 
|  | @ -0,0 +1,64 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
| 
 | ||||
| <svg | ||||
|    width="24" | ||||
|    height="24" | ||||
|    viewBox="0 0 24 24" | ||||
|    version="1.1" | ||||
|    id="svg5" | ||||
|    inkscape:version="1.1 (c4e8f9e, 2021-05-24)" | ||||
|    sodipodi:docname="menu_icon.svg" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg"> | ||||
|   <sodipodi:namedview | ||||
|      id="namedview7" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pagecheckerboard="true" | ||||
|      inkscape:document-units="px" | ||||
|      showgrid="true" | ||||
|      units="px" | ||||
|      inkscape:showpageshadow="false" | ||||
|      inkscape:zoom="12" | ||||
|      inkscape:cx="4.2083333" | ||||
|      inkscape:cy="14.25" | ||||
|      inkscape:window-width="1920" | ||||
|      inkscape:window-height="968" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="25" | ||||
|      inkscape:window-maximized="1" | ||||
|      inkscape:current-layer="layer1" | ||||
|      width="24px"> | ||||
|     <inkscape:grid | ||||
|        type="xygrid" | ||||
|        id="grid1091" /> | ||||
|   </sodipodi:namedview> | ||||
|   <defs | ||||
|      id="defs2" /> | ||||
|   <g | ||||
|      inkscape:label="Слой 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1"> | ||||
|     <path | ||||
|        style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|        d="M 2,12 H 22" | ||||
|        id="path1126" | ||||
|        sodipodi:nodetypes="cc" /> | ||||
|     <path | ||||
|        style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|        d="M 2,4 H 22" | ||||
|        id="path2041" | ||||
|        sodipodi:nodetypes="cc" /> | ||||
|     <path | ||||
|        style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|        d="M 2,20 H 22" | ||||
|        id="path2043" | ||||
|        sodipodi:nodetypes="cc" /> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2.0 KiB | 
|  | @ -0,0 +1,94 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    version="1.0" | ||||
|    id="图层_1" | ||||
|    x="0px" | ||||
|    y="0px" | ||||
|    viewBox="0 0 400 400" | ||||
|    enable-background="new 0 0 900 1000" | ||||
|    xml:space="preserve" | ||||
|    sodipodi:docname="mountain.svg" | ||||
|    width="400" | ||||
|    height="400" | ||||
|    inkscape:version="1.0 (4035a4f, 2020-05-01)"><metadata | ||||
|    id="metadata854"><rdf:RDF><cc:Work | ||||
|        rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type | ||||
|          rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs | ||||
|    id="defs852" /><sodipodi:namedview | ||||
|    inkscape:document-rotation="0" | ||||
|    pagecolor="#ffffff" | ||||
|    bordercolor="#666666" | ||||
|    borderopacity="1" | ||||
|    objecttolerance="10" | ||||
|    gridtolerance="10" | ||||
|    guidetolerance="10" | ||||
|    inkscape:pageopacity="0" | ||||
|    inkscape:pageshadow="2" | ||||
|    inkscape:window-width="1920" | ||||
|    inkscape:window-height="981" | ||||
|    id="namedview850" | ||||
|    showgrid="false" | ||||
|    fit-margin-top="0" | ||||
|    fit-margin-left="0" | ||||
|    fit-margin-right="0" | ||||
|    fit-margin-bottom="0" | ||||
|    inkscape:showpageshadow="false" | ||||
|    inkscape:pagecheckerboard="true" | ||||
|    inkscape:zoom="0.838" | ||||
|    inkscape:cx="396.94033" | ||||
|    inkscape:cy="451.83294" | ||||
|    inkscape:window-x="0" | ||||
|    inkscape:window-y="23" | ||||
|    inkscape:window-maximized="0" | ||||
|    inkscape:current-layer="图层_1" /> | ||||
| 
 | ||||
| <g | ||||
|    transform="scale(0.47393365)" | ||||
|    id="g855"><g | ||||
|      transform="translate(-28,-78)" | ||||
|      id="图层_2"> | ||||
| 	<circle | ||||
|    id="circle833" | ||||
|    r="418" | ||||
|    cy="500" | ||||
|    cx="450" | ||||
|    stroke-miterlimit="10" | ||||
|    stroke-width="8" | ||||
|    stroke="#b3b3b3" | ||||
|    fill="#f3f3f3" /> | ||||
| </g><g | ||||
|      transform="translate(-28,-78)" | ||||
|      id="图层_1_1_"> | ||||
| 	<polygon | ||||
|    id="polygon836" | ||||
|    points="446.7,217.4 615.1,595 278.3,595 " | ||||
|    fill="#008cab" /> | ||||
| 	<polygon | ||||
|    id="polygon838" | ||||
|    points="482.7,298 448.1,220.8 446.7,217.4 331.3,476.1 " | ||||
|    fill="#007194" /> | ||||
| 	<polygon | ||||
|    id="polygon840" | ||||
|    points="330.6,300.3 499,677.9 162.2,677.9 " | ||||
|    fill="#ff931e" /> | ||||
| 	<polygon | ||||
|    id="polygon842" | ||||
|    points="365.4,378.3 331.1,301.3 330.6,300.3 216.2,556.6 " | ||||
|    fill="#ff771e" /> | ||||
| 	<polygon | ||||
|    id="polygon844" | ||||
|    points="558,300.3 726.4,677.9 389.6,677.9 " | ||||
|    fill="#009245" /> | ||||
| 	<polygon | ||||
|    id="polygon846" | ||||
|    points="593.3,379.4 559.7,300.3 558,296.3 443.6,556.6 " | ||||
|    fill="#006837" /> | ||||
| </g></g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2.6 KiB | 
|  | @ -0,0 +1,65 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
| 
 | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="324" | ||||
|    height="428" | ||||
|    id="svg3833" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.91 r13725" | ||||
|    sodipodi:docname="die00.svg"> | ||||
|   <defs | ||||
|      id="defs3835" /> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="1.4" | ||||
|      inkscape:cx="59.415221" | ||||
|      inkscape:cy="214" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="false" | ||||
|      fit-margin-top="0" | ||||
|      fit-margin-left="0" | ||||
|      fit-margin-right="0" | ||||
|      fit-margin-bottom="0" | ||||
|      inkscape:window-width="1440" | ||||
|      inkscape:window-height="808" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="1" | ||||
|      inkscape:window-maximized="1" /> | ||||
|   <metadata | ||||
|      id="metadata3838"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title /> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1" | ||||
|      transform="translate(-33.4375,-23.0625)"> | ||||
|     <path | ||||
|        style="fill:#000000" | ||||
|        d="m 176.61726,361.63944 c -12.69877,-9.9504 -6.42547,-25.85348 -3.50296,-38.65884 1.30615,-15.73529 1.76857,-31.6671 0.78046,-47.41869 -28.13824,19.70895 -52.22982,46.56757 -85.268034,58.29362 -3.332385,1.36501 -21.201204,3.34798 -14.355377,-0.79344 24.648599,-17.24978 50.886791,-32.55464 73.136291,-52.94554 5.9426,-7.62857 19.739,-16.0007 17.9799,-25.26838 -10.3488,-0.99522 -20.0746,4.1572 -26.61328,9.24717 -9.35469,-6.51048 -9.86256,-21.66977 -15.77441,-31.54928 -4.35169,-12.20471 -11.87005,-22.81122 -18.20693,-33.88728 -3.11657,-7.90333 6.45543,-4.35867 10.88293,-5.00842 11.12409,6.24649 23.68733,2.16377 35.50537,-0.69531 8.01765,-2.5196 18.38302,-3.35939 24.88498,-7.80143 -0.75046,-6.01153 4.44447,-19.66389 -6.01347,-16.26115 -13.0403,2.85429 -27.09131,3.81247 -39.33011,-2.43697 3.45219,-2.46815 14.69499,-3.73669 20.81019,-5.36864 7.99649,-1.63288 16.00444,-3.20902 24.00648,-4.81445 0.71266,-12.55012 -1.39734,-24.94455 -5.94908,-36.67572 -2.80651,-6.26534 -4.70758,-13.96635 4.2642,-8.65775 13.01397,2.73578 26.63059,11.52509 17.63244,26.14921 -6.47505,11.71948 4.20432,15.03795 13.35337,10.4718 10.77315,-3.07502 25.44943,-5.78485 33.85472,2.80361 -14.25923,8.14074 -30.92149,10.18756 -46.1548,15.75665 -5.4113,1.72162 -7.61157,16.12267 -2.86088,17.44126 17.36809,-0.19866 33.99104,-7.8095 51.36881,-7.05317 9.1089,3.39952 30.7918,9.2649 20.21322,22.42238 -12.34566,17.57355 -19.50671,38.03495 -27.95831,57.63079 -9.76055,2.2975 -12.07679,-12.23112 -22.89924,-7.25577 -5.81164,1.2728 -19.96918,1.47538 -21.3027,5.43564 33.73937,30.5473 76.07053,51.29258 120.93483,59.04398 11.58221,0.62061 10.42775,8.62392 -0.20864,8.80105 -16.26602,4.16445 -33.97245,7.38158 -50.45193,2.9739 -24.78609,-13.26925 -43.96356,-34.47207 -64.11976,-53.67733 -2.91043,-2.2401 -7.67207,-9.99299 -7.21225,-2.1967 -1.49225,26.83364 2.77643,53.86418 0.0385,80.61321 -2.70113,4.07175 -4.37247,21.13599 -11.46449,11.33999 z M 155.73574,246.70661 c 7.6798,-4.88121 23.26517,6.68077 19.64141,-6.92286 -1.34043,-3.45949 2.457,-12.83277 -3.17489,-11.383 -8.31141,-0.0574 -25.22892,4.28507 -26.47502,-5.73486 9.74896,-3.35213 19.97845,-5.05788 29.81205,-8.16029 -1.04334,-5.5525 3.37033,-18.39421 -5.54036,-15.96137 -13.36257,2.27988 -27.41611,3.06205 -40.05137,7.9989 2.91753,13.63753 8.45755,27.01047 12.8921,40.37246 1.18063,3.96324 9.69925,-0.92618 12.89608,-0.20898 z m 59.65153,-7.10355 c 15.85208,2.56496 12.30784,-18.18901 16.32145,-28.13359 3.97126,-11.46324 -0.20895,-24.26534 -14.38651,-19.908 -9.8072,-0.48288 -19.44673,1.39189 -28.78292,4.2191 -2.8e-4,4.7603 -5.5e-4,9.5206 -8.1e-4,14.2809 9.17981,0.60194 19.04175,-1.64717 27.60884,2.06085 7.56081,7.26137 -13.62617,8.07278 -18.44316,11.04427 -15.0723,-2.58124 -13.28448,22.85574 1.58041,17.26732 5.37726,0.004 10.75123,-0.32076 16.1027,-0.83085 z" | ||||
|        id="path2995" | ||||
|        inkscape:connector-curvature="0" /> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 4.5 KiB | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 2.3 KiB | 
| After Width: | Height: | Size: 3.4 KiB | 
|  | @ -0,0 +1,65 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
| 
 | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="324" | ||||
|    height="428" | ||||
|    id="svg3833" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.91 r13725" | ||||
|    sodipodi:docname="die01.svg"> | ||||
|   <defs | ||||
|      id="defs3835" /> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="1.4" | ||||
|      inkscape:cx="-26.607391" | ||||
|      inkscape:cy="214" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="false" | ||||
|      fit-margin-top="0" | ||||
|      fit-margin-left="0" | ||||
|      fit-margin-right="0" | ||||
|      fit-margin-bottom="0" | ||||
|      inkscape:window-width="1440" | ||||
|      inkscape:window-height="808" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="1" | ||||
|      inkscape:window-maximized="1" /> | ||||
|   <metadata | ||||
|      id="metadata3838"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title /> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1" | ||||
|      transform="translate(-33.4375,-23.0625)"> | ||||
|     <path | ||||
|        style="fill:#000000" | ||||
|        d="m 258.06114,360.3713 c -8.38222,-10.84325 -16.48292,-21.96519 -23.83211,-33.53157 10.31971,1.16355 24.61894,5.38455 30.81534,-6.12685 9.45061,-17.05283 6.92982,-37.35778 7.75535,-56.13319 -0.59235,-13.17989 1.74238,-27.04214 -2.74502,-39.65714 -6.40493,-10.03729 -19.37134,-7.65349 -29.45398,-7.65961 -8.02862,1.27586 -23.30374,-0.58057 -26.29971,5.74216 4.02906,3.48067 10.28723,6.07057 3.53971,10.35816 -5.37428,7.3319 -16.50498,16.43998 -17.78776,22.8786 9.43371,1.5044 22.32978,-1.5981 29.67312,1.94538 -8.93395,7.08706 -21.50748,5.77988 -32.16135,8.39044 -9.0979,-0.31249 -4.88826,10.59504 -5.78393,16.43627 -0.5703,4.70929 6.67864,0.0919 9.6519,0.57444 11.8748,-1.80185 26.37583,-4.38717 36.30232,4.18285 0.93124,11.06336 -17.17118,5.96498 -24.78396,7.61495 -6.46799,0.18339 -12.93597,0.36678 -19.40395,0.55017 -6.12799,13.17426 -3.20667,28.87926 -9.81946,41.81942 -8.51496,12.00361 -5.16672,-10.69854 -6.47119,-16.39569 -0.22066,-9.3317 0.78387,-27.99819 -13.53238,-19.65043 -9.92868,3.50377 -25.17211,6.08556 -30.86057,-5.25724 10.70555,-3.42767 22.8486,-4.28644 34.09149,-6.84131 5.98896,-0.25271 10.6952,-2.0041 8.8258,-8.60175 0.28146,-5.50092 1.08774,-14.0607 -7.26499,-8.76679 -6.65163,2.10739 -23.80786,1.46436 -24.39908,-3.95357 12.96613,-3.48997 27.04792,-3.0485 39.36575,-8.61558 8.46163,-8.34086 16.06048,-19.02693 18.29832,-30.88934 -2.5992,-10.80475 -20.84741,-1.03643 -29.66231,-2.37121 -19.26938,2.47217 -38.60131,4.65865 -57.74471,7.96252 -1.23337,31.29702 0.14531,62.67798 0.27898,94.00925 -2.613,4.09437 -5.11886,16.69717 -11.01025,9.58635 -10.093842,-8.78611 -5.417347,-22.49508 -4.233758,-33.75981 3.645938,-24.45633 3.816508,-50.3026 -6.523813,-73.26961 -8.2939,-12.67494 9.232131,-12.57482 15.872151,-6.05569 11.42918,1.14954 23.15965,-2.731 34.68144,-3.79426 9.89918,-2.65048 25.21395,0.16716 27.80436,-12.80642 3.66886,-6.8384 4.18143,-14.58079 4.03795,-22.1639 -11.82005,-0.42145 -24.80186,2.91955 -35.43674,-3.53583 -7.70473,-6.74832 12.68425,-5.45056 17.29422,-7.94181 10.20945,-2.44664 25.54694,-1.75667 24.16612,-16.40228 2.63828,-15.40631 3.87756,-31.57277 -1.16932,-46.62008 11.14527,-1.07764 22.41599,3.65459 29.33285,12.5 -4.41596,12.86321 -9.51779,25.52443 -13.09478,38.64949 11.34996,0.60089 22.4261,-4.49523 33.53791,-5.90561 4.67227,1.91397 12.54997,1.76464 14.58973,6.10372 -9.29034,12.12281 -25.98124,11.99819 -39.497,15.82751 -14.10056,-1.13423 -15.50464,13.11047 -20.70799,22.76005 -3.15155,6.094 -8.81325,17.09921 3.15285,13.95182 22.40899,-1.17841 44.32228,-6.49224 66.49157,-9.58726 10.99277,-3.56314 23.12906,-4.56061 33.12584,2.3131 12.69967,3.64607 15.99261,16.42482 8.44674,26.8622 -6.90059,15.48715 -5.07208,32.83375 -6.97116,49.31325 -2.43408,23.77264 -0.56808,50.01806 -14.88876,70.54363 -3.24219,4.17027 -10.55813,10.99268 -15.59178,5.4181 z M 160.38285,252.57675 c -4.11065,-3.85675 -12.86427,-17.21541 -6.6416,-19.95545 10.49686,-2.2602 20.32066,6.28725 17.95843,17.29732 0.89107,7.59807 -7.68813,6.4493 -11.31683,2.65813 z" | ||||
|        id="path2995" | ||||
|        inkscape:connector-curvature="0" /> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 4.7 KiB | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 2.3 KiB | 
| After Width: | Height: | Size: 3.5 KiB | 
|  | @ -0,0 +1,65 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
| 
 | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="324" | ||||
|    height="428" | ||||
|    id="svg3833" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.91 r13725" | ||||
|    sodipodi:docname="die02.svg"> | ||||
|   <defs | ||||
|      id="defs3835" /> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="1.4" | ||||
|      inkscape:cx="137.14413" | ||||
|      inkscape:cy="215.33416" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="false" | ||||
|      fit-margin-top="0" | ||||
|      fit-margin-left="0" | ||||
|      fit-margin-right="0" | ||||
|      fit-margin-bottom="0" | ||||
|      inkscape:window-width="1440" | ||||
|      inkscape:window-height="808" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="1" | ||||
|      inkscape:window-maximized="1" /> | ||||
|   <metadata | ||||
|      id="metadata3838"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title /> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1" | ||||
|      transform="translate(-33.4375,-23.0625)"> | ||||
|     <path | ||||
|        style="fill:#000000" | ||||
|        d="m 250.52594,344.85432 c -6.79438,-12.11557 -7.34792,-27.4942 -16.88867,-38.04761 -10.61834,-7.41958 -24.38913,-2.94272 -36.34524,-2.95462 -24.56038,1.99714 -49.12781,3.97242 -73.67043,6.14739 -4.62765,3.08747 -8.82545,26.29112 -12.57904,11.48506 -8.47939,-33.50337 -8.01274,-70.0042 -25.836668,-100.59526 -4.326844,-8.21368 13.58522,-1.23812 18.900238,-2.77129 16.19384,0.77712 32.16206,-2.57615 48.1201,-4.79376 -0.2936,-16.63848 1.90474,-34.5277 -7.281,-49.34285 -1.88662,-2.80241 -6.81784,-1.28649 -9.91378,-2.37366 -9.19863,-0.81825 -19.067,-3.05216 -24.91323,-10.81434 42.05137,-1.71634 82.86093,-12.66528 123.78672,-21.46166 7.65742,-0.96301 25.73127,-2.24054 25.31961,7.977 -9.0964,10.82839 -24.55151,9.91421 -37.16653,13.03859 -6.23954,1.98138 -24.14028,0.71582 -13.15006,9.89396 9.97638,7.16423 8.02272,18.34435 3.90799,28.21581 -2.39614,6.54587 -6.22935,16.65482 4.95038,12.7277 19.46935,-1.21315 38.53112,-6.12933 57.9712,-7.24861 11.58743,3.59616 23.0619,9.94148 30.87734,19.34851 0.2974,9.49357 -9.8512,17.29389 -11.35695,27.26967 -9.47107,27.27159 -8.78935,57.37366 -21.30839,83.64763 -5.17493,8.17225 -10.94488,18.44417 -20.64421,21.31991 l -1.34956,-0.19503 -1.42982,-0.47254 0,0 z m 8.73271,-39.60429 c 8.40505,-18.89122 11.34191,-39.79021 14.03738,-60.15078 0.60024,-10.58911 2.28892,-22.35644 -3.10756,-31.99349 -9.52814,-5.95652 -21.94629,-2.43972 -32.6887,-3.1619 -10.09146,0.26938 -20.18234,0.56065 -30.27354,0.83974 0,10.45819 0,20.91637 0,31.37456 6.45009,3.9147 13.80656,4.93272 21.18126,3.26979 9.03493,-3.29556 25.70625,9.95122 10.45783,13.91491 -10.81029,0.85703 -22.07429,1.49559 -32.73703,-0.80889 -9.78343,-3.69675 -14.36718,-14.29027 -13.98005,-24.21869 -1.08607,-8.13515 4.23276,-24.98531 -9.42201,-18.33046 -9.0476,1.04202 -20.77486,-0.20278 -18.41913,12.83721 -2.77979,19.86446 -10.71782,42.04379 -29.93658,51.38526 0.0874,-8.28201 7.8025,-18.98907 10.36327,-28.2991 3.61606,-9.76641 7.21916,-19.93035 6.49244,-30.49879 -12.65283,2.21933 -25.39556,3.96792 -37.9753,6.57537 1.20522,21.66898 5.09878,43.29477 4.98476,65.10077 -0.71685,13.01766 18.06776,2.15667 25.90253,3.9536 28.11887,-2.79858 56.15977,-6.84438 84.39532,-8.1977 12.24854,-0.19989 15.99821,13.18411 24.18949,19.37711 2.68267,1.00522 5.35718,-0.50525 6.53562,-2.96852 z m -70.7476,-99.02224 c 4.18032,-0.26866 7.68484,-1.18408 6.94788,-6.15877 0.88838,-14.99378 0.84832,-30.15359 -0.44599,-45.11561 -13.31569,1.13931 -26.45635,3.80972 -39.66954,5.79258 3.96094,3.76911 7.92188,7.53822 11.88283,11.30732 0.30136,12.03036 -0.77215,24.28155 1.05486,36.12729 6.47786,1.29108 13.65828,-1.16641 20.22996,-1.95281 z" | ||||
|        id="path2995" | ||||
|        inkscape:connector-curvature="0" /> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 4.3 KiB | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 2.2 KiB | 
| After Width: | Height: | Size: 3.3 KiB | 
|  | @ -0,0 +1,65 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
| 
 | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="324" | ||||
|    height="428" | ||||
|    id="svg3833" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.91 r13725" | ||||
|    sodipodi:docname="die03.svg"> | ||||
|   <defs | ||||
|      id="defs3835" /> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="1.4" | ||||
|      inkscape:cx="75.358413" | ||||
|      inkscape:cy="215.33416" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="false" | ||||
|      fit-margin-top="0" | ||||
|      fit-margin-left="0" | ||||
|      fit-margin-right="0" | ||||
|      fit-margin-bottom="0" | ||||
|      inkscape:window-width="1440" | ||||
|      inkscape:window-height="808" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="1" | ||||
|      inkscape:window-maximized="1" /> | ||||
|   <metadata | ||||
|      id="metadata3838"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title /> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1" | ||||
|      transform="translate(-33.4375,-23.0625)"> | ||||
|     <path | ||||
|        style="fill:#000000" | ||||
|        d="m 156.91061,344.13368 c -10.52811,-11.18408 -3.5767,-27.48237 -2.97518,-40.82367 1.04445,-6.68848 0.92147,-19.25602 -7.61787,-9.42003 -15.13394,10.26215 -28.73978,23.01554 -44.96806,31.51563 -9.494717,0.49654 -16.758007,-9.4777 -21.151664,-16.39958 21.730674,-5.97194 43.254554,-13.16274 63.324654,-23.6004 4.55466,-2.23564 9.10932,-4.47128 13.66398,-6.70692 0,-17.02853 0,-34.05707 0,-51.0856 -15.25264,0.8468 -28.88266,10.351 -44.22568,10.768 -6.59751,-0.42005 -18.510816,-9.40043 -5.78264,-11.22363 15.59759,-5.43032 31.25957,-11.7345 48.00672,-12.00246 1.35235,-4.29124 0.59013,-10.91784 0.63951,-15.90662 -1.49319,-16.45846 -6.8364,-32.20259 -10.63791,-48.20321 11.4283,-2.52534 22.78253,6.86274 26.86062,16.80378 0.12058,11.82085 -3.56939,23.35588 -2.94916,35.25543 -0.87992,43.66379 -0.96954,87.33911 -1.43118,131.00871 -2.64241,4.62951 -4.22518,18.18279 -10.75614,10.02057 l 0,0 z m 82.48449,-7.98625 c -14.45188,-2.80824 -27.23706,-12.68174 -32.47811,-26.56509 -0.68743,-24.73496 -0.3903,-49.70198 -0.69905,-74.5262 -0.49949,-29.93986 0.35452,-59.94338 -1.4666,-89.83564 -1.52504,-6.42107 -9.83267,-24.35987 3.50705,-15.7753 6.83479,3.06435 13.49385,6.5711 19.54782,11.00236 -5.47316,31.67949 -12.1799,63.76017 -8.08983,96.02879 13.92149,-8.19901 26.29986,-19.77686 35.70102,-33.01351 1.74898,-13.25576 16.08002,-11.47775 23.02923,-2.75313 4.92685,3.90534 9.58777,10.29965 0.11167,11.92561 -20.00803,11.15243 -39.9203,22.47534 -59.87183,33.72827 0,19.35549 0,38.71099 0,58.06648 4.90499,7.78338 13.54196,12.20332 22.70754,12.45987 14.93694,1.14094 33.27193,2.53616 43.54347,-10.76614 7.9328,-10.56613 12.36792,-23.17516 16.84818,-35.48022 1.8266,16.513 5.46902,32.73694 9.02154,48.9448 -10.05625,9.91261 -24.42073,14.69074 -38.11164,16.80176 -11.03028,1.09778 -22.33178,1.6675 -33.30046,-0.24271 z" | ||||
|        id="path3005" | ||||
|        inkscape:connector-curvature="0" /> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 3.5 KiB | 
| After Width: | Height: | Size: 959 B | 
| After Width: | Height: | Size: 1.9 KiB | 
| After Width: | Height: | Size: 2.8 KiB | 
| After Width: | Height: | Size: 18 KiB | 
|  | @ -0,0 +1,34 @@ | |||
| strings:ru { | ||||
|     "Text style" = "Стиль текста", | ||||
| 	"View border" = "Рамка", | ||||
| 	"Background image" = "Фоновое изображение", | ||||
| 	"Controls" = "Контролы", | ||||
| 	"Popups" = "Всплывающие окна", | ||||
| 	"Filter" = "Фильтр", | ||||
| 	"Clip" = "Обрезка", | ||||
| 	"Transform" = "Трансформация", | ||||
| 	"Key events" = "События клавиатуры", | ||||
| 	"Mouse events" = "События мыши", | ||||
| 	"Pointer events" = "События указателя", | ||||
| 	"Touch events" = "События касания", | ||||
|     "Font name" = "Название шрифта", | ||||
| 	"Text size" = "Размер текста", | ||||
| 	"Text color" = "Цвет текста", | ||||
| 	"Italic" = "Курсив", | ||||
| 	"Strikethrough" = "Зачеркнутый", | ||||
| 	"Overline" = "Подчеркнутый сверху", | ||||
| 	"Underline" = "Подчеркнутый", | ||||
| 	"Line style" = "Стиль линии", | ||||
| 	"Line thickness" = "Толщина линии", | ||||
| 	"Line color" = "Цвет линии", | ||||
|     "Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails. Explore. Dream. Discover." =  | ||||
|     "Через 20 лет вы будете больше разочарованы теми вещами, которые вы не делали, чем теми, которые вы сделали. Так отчальте от тихой пристани. Почувствуйте попутный ветер в вашем парусе. Двигайтесь вперед, действуйте, открывайте!", | ||||
| 	"Shadow" = "Тень", | ||||
|     "default" = "по умолчанию", | ||||
|     "Hello" = "Привет", | ||||
|     "Hello world!!!" = "Привет мир!!!", | ||||
|     "Yes" = "Да", | ||||
|     "No" = "Нет", | ||||
|     "Cancel" = "Отмена", | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,88 @@ | |||
| theme { | ||||
| 	colors = _{ | ||||
| 		optionsBackground = #FFDDDDDD, | ||||
| 		optionsTextColor = #FF000000, | ||||
| 	}, | ||||
| 	colors:dark = _{ | ||||
| 		optionsBackground = #FF404040, | ||||
| 		optionsTextColor = #FFDDDDDD, | ||||
| 	}, | ||||
| 	constants = _{ | ||||
| 		optionsFont = sans-serif, | ||||
| 		optionsTextSize = 10pt, | ||||
| 	}, | ||||
| 	styles = [ | ||||
| 		demoPage { | ||||
| 			width = 100%,  | ||||
| 			height = 100%, | ||||
| 			cell-width = "1fr, auto", | ||||
| 		}, | ||||
| 		demoPanel { | ||||
| 			width = 100%,  | ||||
| 			height = 100%, | ||||
| 			orientation = horizontal,  | ||||
| 		}, | ||||
| 		optionsPanel { | ||||
| 			column = 1, | ||||
| 			height = 100%, | ||||
| 			width = auto, | ||||
| 			background-color = @optionsBackground, | ||||
| 			text-color = @optionsTextColor, | ||||
| 			font = @optionsFont, | ||||
| 			text-size = @optionsTextSize, | ||||
| 			padding = 8px, | ||||
| 			orientation = vertical, | ||||
| 		}, | ||||
| 		optionsTable { | ||||
| 			grid-column-gap = 8px,  | ||||
| 			grid-row-gap = 8px, | ||||
| 			cell-vertical-align = center, | ||||
| 		}, | ||||
| 		optionsLine { | ||||
| 			padding = 8px, | ||||
| 			orientation = horizontal, | ||||
| 			vertical-align = center, | ||||
| 		}, | ||||
| 		transitionBar { | ||||
| 			height = 24px,  | ||||
| 			background-color = #FF00DD00,  | ||||
| 			margin-top = 4px, | ||||
| 			margin-bottom = 16px, | ||||
| 		}, | ||||
| 		header1 { | ||||
| 			semantics = h1, | ||||
| 			text-align = center, | ||||
| 			margin-bottom = 0.5em, | ||||
| 		}, | ||||
| 		header2 { | ||||
| 			semantics = h2, | ||||
| 			text-align = center, | ||||
| 			margin-bottom = 0.5em, | ||||
| 		}, | ||||
| 		paragraph { | ||||
| 			semantics = p, | ||||
| 			text-indent = 2em, | ||||
| 			margin-bottom = 0.5em, | ||||
| 		}, | ||||
| 		tableHead1 { | ||||
| 			background-color = #FFDDDDDD, | ||||
| 			text-align = left, | ||||
| 			table-vertical-align = top, | ||||
| 			text-weight = normal, | ||||
| 			italic = true, | ||||
| 			border = _{ top = _{style = solid, color = black, width = 4px }, bottom = _{style = solid, color = black, width = 4px } }, | ||||
| 			cell-border = _{ style = dashed, color = gray, width = 1px }, | ||||
| 			cell-padding = 8px, | ||||
| 		}, | ||||
| 		tableHead2 { | ||||
| 
 | ||||
| 		}, | ||||
| 		tableFoot1 { | ||||
| 			background-color = #FFfefbd8, | ||||
| 			text-align = center, | ||||
| 			text-weight = bold, | ||||
| 			border = _{ top = _{style = solid, color = black, width = 2px }, bottom = _{style = solid, color = black, width = 4px } }, | ||||
| 			cell-padding = 8px, | ||||
| 		} | ||||
| 	], | ||||
| }	 | ||||
|  | @ -0,0 +1,26 @@ | |||
| package main | ||||
| 
 | ||||
| /* | ||||
| import ( | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const splitViewDemoText = ` | ||||
| SplitView { | ||||
| 	width = 100%, height = 100%, orientation = vertical, anchor = bottom, padding = 2px, | ||||
| 	view1 = GridLayout { width = 100%, height = 75%, content = ["View 1"], cell-vertical-align = center, cell-horizontal-align = center, | ||||
| 		border = _{ width = 1px, style = solid, color = #FF000000 }, radius = 8px,}, | ||||
| 	view2 = GridLayout { width = 100%, height = 25%, content = ["View 2"], cell-align = center, | ||||
| 		border = _{ width = 1px, style = solid, color = #FF000000 }, radius = 8px,}, | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createSplitViewDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, splitViewDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
| */ | ||||
|  | @ -0,0 +1,95 @@ | |||
| package main | ||||
| 
 | ||||
| import "github.com/anoshenko/rui" | ||||
| 
 | ||||
| const stackLayoutDemoText = ` | ||||
| GridLayout { | ||||
| 	style = demoPage, | ||||
| 	content = [ | ||||
| 		StackLayout { | ||||
| 			id = stackLayout, width = 100%, height = 100% | ||||
| 		}, | ||||
| 		ListLayout { | ||||
| 			style = optionsPanel, | ||||
| 			content = [ | ||||
| 				GridLayout { | ||||
| 					style = optionsTable, | ||||
| 					content = [ | ||||
| 						Button { row = 0, column = 0:1, id = pushRed, content = "Push red view" }, | ||||
| 						Button { row = 1, column = 0:1, id = pushGreen, content = "Push green view" }, | ||||
| 						Button { row = 2, column = 0:1, id = pushBlue, content = "Push blue view" }, | ||||
| 						Button { row = 3, column = 0:1, id = popView, content = "Pop view" }, | ||||
| 						TextView { row = 4, text = "Animation" }, | ||||
| 						DropDownList { row = 4, column = 1, id = pushAnimation, current = 0, items = ["default", "start-to-end", "end-to-start", "top-down", "bottom-up"]}, | ||||
| 						TextView { row = 5, text = "Timing" }, | ||||
| 						DropDownList { row = 5, column = 1, id = pushTiming, current = 0, items = ["ease", "linear"]}, | ||||
| 						TextView { row = 6, text = "Duration" }, | ||||
| 						DropDownList { row = 6, column = 1, id = pushDuration, current = 0, items = ["0.5s", "1s", "2s"]}, | ||||
| 					] | ||||
| 				} | ||||
| 			] | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createStackLayoutDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, stackLayoutDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	animation := func() int { | ||||
| 		return rui.GetDropDownCurrent(view, "pushAnimation") | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
| 		transition := func() rui.ViewTransition { | ||||
| 			timing := rui.EaseTiming | ||||
| 			timings := []string{rui.EaseTiming, rui.LinearTiming} | ||||
| 			if n := rui.GetDropDownCurrent(view, "pushTiming"); n >= 0 && n < len(timings) { | ||||
| 				timing = timings[n] | ||||
| 			} | ||||
| 
 | ||||
| 			duration := float64(0.5) | ||||
| 			durations := []float64{0.5, 1, 2} | ||||
| 			if n := rui.GetDropDownCurrent(view, "pushDuration"); n >= 0 && n < len(durations) { | ||||
| 				duration = durations[n] | ||||
| 			} | ||||
| 
 | ||||
| 			return rui.NewTransition(duration, timing, session) | ||||
| 		} | ||||
| 	*/ | ||||
| 
 | ||||
| 	rui.Set(view, "pushRed", rui.ClickEvent, func(_ rui.View) { | ||||
| 		if stackLayout := rui.StackLayoutByID(view, "stackLayout"); stackLayout != nil { | ||||
| 			if v := rui.CreateViewFromText(session, `View { background-color = red }`); v != nil { | ||||
| 				stackLayout.Push(v, animation(), nil) | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "pushGreen", rui.ClickEvent, func(_ rui.View) { | ||||
| 		if stackLayout := rui.StackLayoutByID(view, "stackLayout"); stackLayout != nil { | ||||
| 			if v := rui.CreateViewFromText(session, `View { background-color = green }`); v != nil { | ||||
| 				stackLayout.Push(v, animation(), nil) | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "pushBlue", rui.ClickEvent, func(_ rui.View) { | ||||
| 		if stackLayout := rui.StackLayoutByID(view, "stackLayout"); stackLayout != nil { | ||||
| 			if v := rui.CreateViewFromText(session, `View { background-color = blue }`); v != nil { | ||||
| 				stackLayout.Push(v, animation(), nil) | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "popView", rui.ClickEvent, func(_ rui.View) { | ||||
| 		if stackLayout := rui.StackLayoutByID(view, "stackLayout"); stackLayout != nil { | ||||
| 			stackLayout.Pop(animation(), nil) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,206 @@ | |||
| package main | ||||
| 
 | ||||
| import "github.com/anoshenko/rui" | ||||
| 
 | ||||
| const tableViewDemoText = ` | ||||
| GridLayout { | ||||
| 	style = demoPage, | ||||
| 	content = [ | ||||
| 		ColumnLayout { | ||||
| 			width = 100%, height = 100%, | ||||
| 			content = TableView { | ||||
| 				id = demoTableView1, margin = 24px,  | ||||
| 			} | ||||
| 		}, | ||||
| 		ListLayout { | ||||
| 			style = optionsPanel, | ||||
| 			content = [ | ||||
| 				GridLayout { | ||||
| 					style = optionsTable, | ||||
| 					content = [ | ||||
| 						TextView { row = 0, text = "Cell gap" }, | ||||
| 						DropDownList { row = 0, column = 1, id = tableCellGap, current = 0, items = ["0", "2px"]}, | ||||
| 						TextView { row = 1, text = "Table border" }, | ||||
| 						DropDownList { row = 1, column = 1, id = tableBorder, current = 0, items = ["none", "solid black 1px", "4 colors"]}, | ||||
| 						TextView { row = 2, text = "Cell border" }, | ||||
| 						DropDownList { row = 2, column = 1, id = tableCellBorder, current = 0, items = ["none", "solid black 1px", "4 colors"]}, | ||||
| 						TextView { row = 3, text = "Cell padding" }, | ||||
| 						DropDownList { row = 3, column = 1, id = tableCellPadding, current = 0, items = ["default", "4px", "8px, 16px, 8px, 16px"]}, | ||||
| 						TextView { row = 4, text = "Head style" }, | ||||
| 						DropDownList { row = 4, column = 1, id = tableHeadStyle, current = 0, items = ["none", "tableHead1", "rui.Params"]}, | ||||
| 						TextView { row = 5, text = "Foot style" }, | ||||
| 						DropDownList { row = 5, column = 1, id = tableFootStyle, current = 0, items = ["none", "tableFoot1", "rui.Params"]}, | ||||
| 						Checkbox { row = 6, column = 0:1, id = tableRowStyle, content = "Row style" }, | ||||
| 						Checkbox { row = 7, column = 0:1, id = tableColumnStyle, content = "Column style" }, | ||||
| 					] | ||||
| 				} | ||||
| 			] | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createTableViewDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, tableViewDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	content := [][]interface{}{ | ||||
| 		{"Cell content", "Cell value", rui.HorizontalTableJoin{}}, | ||||
| 		{rui.VerticalTableJoin{}, "Type", "Value"}, | ||||
| 		{"Text", "string", "Text"}, | ||||
| 		{"Number", "int", 10}, | ||||
| 		{rui.VerticalTableJoin{}, "float", 10.95}, | ||||
| 		{"Boolean", "true", true}, | ||||
| 		{rui.VerticalTableJoin{}, "false", false}, | ||||
| 		{"Color", "red", rui.Red}, | ||||
| 		{rui.VerticalTableJoin{}, "green", rui.Green}, | ||||
| 		{rui.VerticalTableJoin{}, "yellow", rui.Yellow}, | ||||
| 		{"View", "Button", rui.NewButton(session, rui.Params{ | ||||
| 			rui.Content: "OK", | ||||
| 		})}, | ||||
| 		{"Foot line", rui.HorizontalTableJoin{}, rui.HorizontalTableJoin{}}, | ||||
| 	} | ||||
| 
 | ||||
| 	rui.SetParams(view, "demoTableView1", rui.Params{ | ||||
| 		rui.Content:    content, | ||||
| 		rui.HeadHeight: 2, | ||||
| 		rui.FootHeight: 1, | ||||
| 	}) | ||||
| 
 | ||||
| 	setBorder := func(borderTag string, number int) { | ||||
| 		switch number { | ||||
| 		case 1: | ||||
| 			rui.Set(view, "demoTableView1", borderTag, rui.NewBorder(rui.Params{ | ||||
| 				rui.Style:         rui.SolidLine, | ||||
| 				rui.ColorProperty: rui.Black, | ||||
| 				rui.Width:         rui.Px(1), | ||||
| 			})) | ||||
| 
 | ||||
| 		case 2: | ||||
| 			rui.Set(view, "demoTableView1", borderTag, rui.NewBorder(rui.Params{ | ||||
| 				rui.Style:       rui.SolidLine, | ||||
| 				rui.LeftColor:   rui.Blue, | ||||
| 				rui.RightColor:  rui.Magenta, | ||||
| 				rui.TopColor:    rui.Red, | ||||
| 				rui.BottomColor: rui.Green, | ||||
| 				rui.Width:       rui.Px(2), | ||||
| 			})) | ||||
| 
 | ||||
| 		default: | ||||
| 			rui.Set(view, "demoTableView1", borderTag, nil) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "tableCellGap", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		if number == 0 { | ||||
| 			rui.Set(view, "demoTableView1", rui.Gap, rui.Px(0)) | ||||
| 		} else { | ||||
| 			rui.Set(view, "demoTableView1", rui.Gap, rui.Px(2)) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "tableBorder", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		setBorder(rui.Border, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "tableCellBorder", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		setBorder(rui.CellBorder, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "tableHeadStyle", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		switch number { | ||||
| 		case 1: | ||||
| 			rui.Set(view, "demoTableView1", rui.HeadStyle, "tableHead1") | ||||
| 
 | ||||
| 		case 2: | ||||
| 			rui.Set(view, "demoTableView1", rui.HeadStyle, rui.Params{ | ||||
| 				rui.CellBorder: rui.NewBorder(rui.Params{ | ||||
| 					rui.Style:         rui.SolidLine, | ||||
| 					rui.ColorProperty: rui.Green, | ||||
| 					rui.Width:         "2px", | ||||
| 				}), | ||||
| 				rui.CellPadding:     "8px", | ||||
| 				rui.BackgroundColor: rui.LightGrey, | ||||
| 			}) | ||||
| 
 | ||||
| 		default: | ||||
| 			rui.Set(view, "demoTableView1", rui.HeadStyle, nil) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "tableFootStyle", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		switch number { | ||||
| 		case 1: | ||||
| 			rui.Set(view, "demoTableView1", rui.FootStyle, "tableFoot1") | ||||
| 
 | ||||
| 		case 2: | ||||
| 			rui.Set(view, "demoTableView1", rui.FootStyle, rui.Params{ | ||||
| 				rui.Border: rui.NewBorder(rui.Params{ | ||||
| 					rui.Style:         rui.SolidLine, | ||||
| 					rui.ColorProperty: rui.Black, | ||||
| 					rui.Width:         "2px", | ||||
| 				}), | ||||
| 				rui.CellPadding:     "4px", | ||||
| 				rui.BackgroundColor: rui.LightYellow, | ||||
| 			}) | ||||
| 
 | ||||
| 		default: | ||||
| 			rui.Set(view, "demoTableView1", rui.FootStyle, nil) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "tableCellPadding", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		switch number { | ||||
| 		case 1: | ||||
| 			rui.Set(view, "demoTableView1", rui.CellPadding, rui.Px(4)) | ||||
| 
 | ||||
| 		case 2: | ||||
| 			rui.Set(view, "demoTableView1", rui.CellPadding, rui.Bounds{ | ||||
| 				Left:   rui.Px(16), | ||||
| 				Right:  rui.Px(16), | ||||
| 				Top:    rui.Px(8), | ||||
| 				Bottom: rui.Px(8), | ||||
| 			}) | ||||
| 
 | ||||
| 		default: | ||||
| 			rui.Set(view, "demoTableView1", rui.CellPadding, nil) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "tableRowStyle", rui.CheckboxChangedEvent, func(checked bool) { | ||||
| 		if checked { | ||||
| 			rui.Set(view, "demoTableView1", rui.RowStyle, []rui.Params{ | ||||
| 				{rui.BackgroundColor: 0xffeaece5}, | ||||
| 				{rui.BackgroundColor: 0xfff0efef}, | ||||
| 				{rui.BackgroundColor: 0xffe0e2e4}, | ||||
| 				{rui.BackgroundColor: 0xffbccad6}, | ||||
| 				{rui.BackgroundColor: 0xffcfe0e8}, | ||||
| 				{rui.BackgroundColor: 0xffb7d7e8}, | ||||
| 				{rui.BackgroundColor: 0xffdaebe8}, | ||||
| 				{rui.BackgroundColor: 0xfff1e3dd}, | ||||
| 				{rui.BackgroundColor: 0xfffbefcc}, | ||||
| 				{rui.BackgroundColor: 0xfffff2df}, | ||||
| 				{rui.BackgroundColor: 0xffffeead}, | ||||
| 				{rui.BackgroundColor: 0xfff2e394}, | ||||
| 			}) | ||||
| 		} else { | ||||
| 			rui.Set(view, "demoTableView1", rui.RowStyle, nil) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "tableColumnStyle", rui.CheckboxChangedEvent, func(checked bool) { | ||||
| 		if checked { | ||||
| 			rui.Set(view, "demoTableView1", rui.ColumnStyle, []rui.Params{ | ||||
| 				{rui.BackgroundColor: 0xffeaece5}, | ||||
| 				{rui.BackgroundColor: 0xffdaebe8}, | ||||
| 				{rui.BackgroundColor: 0xfff2e394}, | ||||
| 			}) | ||||
| 		} else { | ||||
| 			rui.Set(view, "demoTableView1", rui.RowStyle, nil) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,48 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const tabsDemoText = ` | ||||
| GridLayout { | ||||
| 	style = demoPage, | ||||
| 	content = [ | ||||
| 		TabsLayout { id = tabsLayout, width = 100%, height = 100%, tabs = top,  | ||||
| 			content = [ | ||||
| 				View { width = 300px, height = 200px, background-color = #FFFF0000, title = "Red tab"}, | ||||
| 				View { width = 400px, height = 250px, background-color = #FF00FF00, title = "Green tab"}, | ||||
| 				View { width = 100px, height = 400px, background-color = #FF0000FF, title = "Blue tab"}, | ||||
| 				View { width = 300px, height = 200px, background-color = #FF000000, title = "Black tab"}, | ||||
| 			] | ||||
| 		}, | ||||
| 		ListLayout { | ||||
| 			style = optionsPanel, | ||||
| 			content = [ | ||||
| 				GridLayout { | ||||
| 					style = optionsTable, | ||||
| 					content = [ | ||||
| 						TextView { row = 0, text = "Tabs location" }, | ||||
| 						DropDownList { row = 0, column = 1, id = tabsTypeList, current = 1, | ||||
| 							items = ["hidden", "top", "bottom", "left", "right", "left list", "right list"] | ||||
| 						} | ||||
| 					] | ||||
| 				} | ||||
| 			] | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createTabsDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, tabsDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "tabsTypeList", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		rui.Set(view, "tabsLayout", rui.Tabs, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,143 @@ | |||
| package main | ||||
| 
 | ||||
| import "github.com/anoshenko/rui" | ||||
| 
 | ||||
| const textStyleDemoText = ` | ||||
| GridLayout { | ||||
| 	style = demoPage, | ||||
| 	content = [ | ||||
| 		GridLayout { | ||||
| 			width = 100%, height = 100%, cell-vertical-align = center, cell-horizontal-align = center, | ||||
| 			content = [ | ||||
| 				TextView { | ||||
| 					id = textStyleText, padding = 16px, max-width = 80%, | ||||
| 					border = _{ style = solid, width = 1px, color = darkgray }, | ||||
| 					text = "Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails. Explore. Dream. Discover." | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		ListLayout { | ||||
| 			style = optionsPanel, | ||||
| 			content = [ | ||||
| 				GridLayout { | ||||
| 					style = optionsTable, | ||||
| 					content = [ | ||||
| 						TextView { row = 0, text = "Font name" }, | ||||
| 						DropDownList { row = 0, column = 1, id = textStyleFont, current = 0, items = ["default", "serif", "sans-serif", "\"Courier new\",  monospace", "cursive", "fantasy"]}, | ||||
| 						TextView { row = 1, text = "Text size" }, | ||||
| 						DropDownList { row = 1, column = 1, id = textStyleSize, current = 0, items = ["1em", "14pt", "12px", "1.5em"]}, | ||||
| 						TextView { row = 2, text = "Text color" }, | ||||
| 						ColorPicker { row = 2, column = 1, id = textStyleColor }, | ||||
| 						TextView { row = 3, text = "Text weight" }, | ||||
| 						DropDownList { row = 3, column = 1, id = textStyleWeight, current = 0, items = ["default", "thin", "extra-light", "light", "normal", "medium", "semi-bold", "bold", "extra-bold", "black"]}, | ||||
| 						Checkbox { row = 4, column = 0:1, id = textStyleItalic, content = "Italic" }, | ||||
| 						Checkbox { row = 5, column = 0:1, id = textStyleSmallCaps, content = "Small-caps" }, | ||||
| 						Checkbox { row = 6, column = 0:1, id = textStyleStrikethrough, content = "Strikethrough" }, | ||||
| 						Checkbox { row = 7, column = 0:1, id = textStyleOverline, content = "Overline" }, | ||||
| 						Checkbox { row = 8, column = 0:1, id = textStyleUnderline, content = "Underline" }, | ||||
| 						TextView { row = 9, text = "Line style" }, | ||||
| 						DropDownList { row = 9, column = 1, id = textStyleLineStyle, current = 0, items = ["default", "solid", "dashed", "dotted", "double", "wavy"]}, | ||||
| 						TextView { row = 10, text = "Line thickness" }, | ||||
| 						DropDownList { row = 10, column = 1, id = textStyleLineThickness, current = 0, items = ["default", "1px", "1.5px", "2px", "3px", "4px"]}, | ||||
| 						TextView { row = 11, text = "Line color" }, | ||||
| 						ColorPicker { row = 11, column = 1, id = textStyleLineColor }, | ||||
| 						TextView { row = 12, text = "Shadow" }, | ||||
| 						DropDownList { row = 12, column = 1, id = textStyleShadow, current = 0, items = ["none", "gray, (x, y)=(1px, 1px), blur=0", "blue, (x, y)=(-2px, -2px), blur=1", "green, (x, y)=(0px, 0px), blur=3px"]}, | ||||
| 					] | ||||
| 				} | ||||
| 			] | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createTextStyleDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, textStyleDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "textStyleFont", rui.DropDownEvent, func(number int) { | ||||
| 		fonts := []string{"", "serif", "sans-serif", "\"Courier new\", monospace", "cursive", "fantasy"} | ||||
| 		if number > 0 && number < len(fonts) { | ||||
| 			rui.Set(view, "textStyleText", rui.FontName, fonts[number]) | ||||
| 		} else { | ||||
| 			rui.Set(view, "textStyleText", rui.FontName, nil) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "textStyleSize", rui.DropDownEvent, func(number int) { | ||||
| 		sizes := []string{"1em", "14pt", "12px", "1.5em"} | ||||
| 		if number >= 0 && number < len(sizes) { | ||||
| 			rui.Set(view, "textStyleText", rui.TextSize, sizes[number]) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "textStyleColor", rui.ColorChangedEvent, func(color rui.Color) { | ||||
| 		rui.Set(view, "textStyleText", rui.TextColor, color) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "textStyleWeight", rui.DropDownEvent, func(number int) { | ||||
| 		rui.Set(view, "textStyleText", rui.TextWeight, number) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "textStyleItalic", rui.CheckboxChangedEvent, func(state bool) { | ||||
| 		rui.Set(view, "textStyleText", rui.Italic, state) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "textStyleSmallCaps", rui.CheckboxChangedEvent, func(state bool) { | ||||
| 		rui.Set(view, "textStyleText", rui.SmallCaps, state) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "textStyleStrikethrough", rui.CheckboxChangedEvent, func(state bool) { | ||||
| 		rui.Set(view, "textStyleText", rui.Strikethrough, state) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "textStyleOverline", rui.CheckboxChangedEvent, func(state bool) { | ||||
| 		rui.Set(view, "textStyleText", rui.Overline, state) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "textStyleUnderline", rui.CheckboxChangedEvent, func(state bool) { | ||||
| 		rui.Set(view, "textStyleText", rui.Underline, state) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "textStyleLineStyle", rui.DropDownEvent, func(number int) { | ||||
| 		styles := []string{"inherit", "solid", "dashed", "dotted", "double", "wavy"} | ||||
| 		if number > 0 && number < len(styles) { | ||||
| 			rui.Set(view, "textStyleText", rui.TextLineStyle, styles[number]) | ||||
| 		} else { | ||||
| 			rui.Set(view, "textStyleText", rui.TextLineStyle, nil) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "textStyleLineThickness", rui.DropDownEvent, func(number int) { | ||||
| 		sizes := []string{"", "1px", "1.5px", "2px", "3px", "4px"} | ||||
| 		if number > 0 && number < len(sizes) { | ||||
| 			rui.Set(view, "textStyleText", rui.TextLineThickness, sizes[number]) | ||||
| 		} else { | ||||
| 			rui.Set(view, "textStyleText", rui.TextLineThickness, nil) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "textStyleLineColor", rui.ColorChangedEvent, func(color rui.Color) { | ||||
| 		rui.Set(view, "textStyleText", rui.TextLineColor, color) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "textStyleShadow", rui.DropDownEvent, func(number int) { | ||||
| 		switch number { | ||||
| 		case 0: | ||||
| 			rui.Set(view, "textStyleText", rui.TextShadow, nil) | ||||
| 
 | ||||
| 		case 1: | ||||
| 			rui.Set(view, "textStyleText", rui.TextShadow, rui.NewTextShadow(rui.Px(1), rui.Px(1), rui.Px(0), rui.Gray)) | ||||
| 
 | ||||
| 		case 2: | ||||
| 			rui.Set(view, "textStyleText", rui.TextShadow, rui.NewTextShadow(rui.Px(-2), rui.Px(-2), rui.Px(1), rui.Blue)) | ||||
| 
 | ||||
| 		case 3: | ||||
| 			rui.Set(view, "textStyleText", rui.TextShadow, rui.NewTextShadow(rui.Px(0), rui.Px(0), rui.Px(3), rui.Green)) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,122 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const touchEventsDemoText = ` | ||||
| GridLayout { | ||||
| 	width = 100%, height = 100%, cell-height = "1fr, auto", | ||||
| 	content = [ | ||||
| 		GridLayout { | ||||
| 			padding = 12px, | ||||
| 			content = [ | ||||
| 				GridLayout { | ||||
| 					id = touchEventsTest, cell-horizontal-align = center, cell-vertical-align = center, | ||||
| 					height = 150%, | ||||
| 					border = _{ style = solid, width = 1px, color = gray}, | ||||
| 					content = [ | ||||
| 						TextView { | ||||
| 							id = touchEventsText, text = "Test box", | ||||
| 						} | ||||
| 					] | ||||
| 				} | ||||
| 			], | ||||
| 		}, | ||||
| 		Resizable { | ||||
| 			row = 1, side = top, background-color = lightgrey, height = 300px, | ||||
| 			content = EditView { | ||||
| 				id = touchEventsLog, type = multiline, read-only = true, wrap = true, | ||||
| 			} | ||||
| 		}, | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func createTouchEventsDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, touchEventsDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	addToLog := func(tag string, event rui.TouchEvent) { | ||||
| 		var buffer strings.Builder | ||||
| 
 | ||||
| 		appendBool := func(name string, value bool) { | ||||
| 			buffer.WriteString(`, `) | ||||
| 			buffer.WriteString(name) | ||||
| 			if value { | ||||
| 				buffer.WriteString(` = true`) | ||||
| 			} else { | ||||
| 				buffer.WriteString(` = false`) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		/* | ||||
| 			appendInt := func(name string, value int) { | ||||
| 				buffer.WriteString(`, `) | ||||
| 				buffer.WriteString(name) | ||||
| 				buffer.WriteString(` = `) | ||||
| 				buffer.WriteString(strconv.Itoa(value)) | ||||
| 			}*/ | ||||
| 
 | ||||
| 		appendFloat := func(name string, value float64) { | ||||
| 			buffer.WriteString(fmt.Sprintf(`, %s = %g`, name, value)) | ||||
| 		} | ||||
| 
 | ||||
| 		appendPoint := func(name string, x, y float64) { | ||||
| 			buffer.WriteString(fmt.Sprintf(`, %s = (%g:%g)`, name, x, y)) | ||||
| 		} | ||||
| 
 | ||||
| 		buffer.WriteString(tag) | ||||
| 		buffer.WriteString(`: TimeStamp = `) | ||||
| 		buffer.WriteString(strconv.FormatUint(event.TimeStamp, 10)) | ||||
| 
 | ||||
| 		buffer.WriteString(`, touches = [`) | ||||
| 		for i, touch := range event.Touches { | ||||
| 			if i > 0 { | ||||
| 				buffer.WriteString(`, `) | ||||
| 			} | ||||
| 			buffer.WriteString(`{ Identifier = `) | ||||
| 			buffer.WriteString(strconv.Itoa(touch.Identifier)) | ||||
| 			appendPoint("(X:Y)", touch.X, touch.Y) | ||||
| 			appendPoint("Client (X:Y)", touch.ClientX, touch.ClientY) | ||||
| 			appendPoint("Screen (X:Y)", touch.ScreenX, touch.ScreenY) | ||||
| 			appendPoint("Radius (X:Y)", touch.RadiusX, touch.RadiusY) | ||||
| 			appendFloat("RotationAngle", touch.RotationAngle) | ||||
| 			appendFloat("Force", touch.Force) | ||||
| 			buffer.WriteString(`}`) | ||||
| 		} | ||||
| 		buffer.WriteString(`]`) | ||||
| 
 | ||||
| 		appendBool("CtrlKey", event.CtrlKey) | ||||
| 		appendBool("ShiftKey", event.ShiftKey) | ||||
| 		appendBool("AltKey", event.AltKey) | ||||
| 		appendBool("MetaKey", event.MetaKey) | ||||
| 		buffer.WriteString(";\n\n") | ||||
| 
 | ||||
| 		rui.AppendEditText(view, "touchEventsLog", buffer.String()) | ||||
| 		rui.ScrollViewToEnd(view, "touchEventsLog") | ||||
| 	} | ||||
| 
 | ||||
| 	rui.SetParams(view, "touchEventsTest", rui.Params{ | ||||
| 		rui.TouchStart: func(v rui.View, event rui.TouchEvent) { | ||||
| 			addToLog("touch-start", event) | ||||
| 		}, | ||||
| 		rui.TouchEnd: func(v rui.View, event rui.TouchEvent) { | ||||
| 			addToLog("touch-end", event) | ||||
| 		}, | ||||
| 		rui.TouchCancel: func(v rui.View, event rui.TouchEvent) { | ||||
| 			addToLog("touch-cancel", event) | ||||
| 		}, | ||||
| 		rui.TouchMove: func(v rui.View, event rui.TouchEvent) { | ||||
| 			addToLog("touch-move", event) | ||||
| 		}, | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,361 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const transformDemoText = ` | ||||
| GridLayout { | ||||
| 	style = demoPage, | ||||
| 	content = [ | ||||
| 		GridLayout { | ||||
| 			id = listLayout, width = 100%, height = 100%, cell-horizontal-align = center, cell-vertical-align = center, | ||||
| 			content = [ | ||||
| 				TextView { id = transformView, width = 200px, height = 100px,  | ||||
| 					text = "View", text-align = center, text-size = 32pt,  | ||||
| 					background-color = #FFBBBBBB, radius = 8px, padding = 8px, margin = 4px, | ||||
| 					border = _{ style = solid, width = 1px, color = #FF000080 }, | ||||
| 					shadow = _{ spread-radius = 1px, blur = 16px, color = #80000000}, | ||||
| 				},	 | ||||
| 			] | ||||
| 		}, | ||||
| 		ListLayout { | ||||
| 			style = optionsPanel, | ||||
| 			content = [ | ||||
| 				"Perspective", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = PerspectiveEditor, type = slider, width = 120px,  | ||||
| 							min = -500, max = 500, step = 10, value = 0  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = PerspectiveValue, text = "0px", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"Perspective origin X (pixels)", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = xPerspectiveOriginEditor, type = slider, width = 120px,  | ||||
| 							min = -1000, max = 1000, step = 10, value = 0  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = xPerspectiveOriginValue, text = "0px", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"Perspective origin Y (pixels)", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = yPerspectiveOriginEditor, type = slider, width = 120px,  | ||||
| 							min = -1000, max = 1000, step = 10, value = 0  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = yPerspectiveOriginValue, text = "0px", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"Origin X (pixels)", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = xOriginEditor, type = slider, width = 120px,  | ||||
| 							min = -1000, max = 1000, step = 10, value = 0  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = xOriginValue, text = "0px", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"Origin Y (pixels)", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = yOriginEditor, type = slider, width = 120px,  | ||||
| 							min = -1000, max = 1000, step = 10, value = 0  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = yOriginValue, text = "0px", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"Origin Z (pixels)", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = zOriginEditor, type = slider, width = 120px,  | ||||
| 							min = -1000, max = 1000, step = 10, value = 0  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = zOriginValue, text = "0px", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"Translate X (pixels)", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = xTranslateEditor, type = slider, width = 120px,  | ||||
| 							min = -100, max = 100, step = 1, value = 0  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = xTranslateValue, text = "0px", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"Translate Y (pixels)", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = yTranslateEditor, type = slider, width = 120px,  | ||||
| 							min = -100, max = 100, step = 1, value = 0  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = yTranslateValue, text = "0px", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"Translate Z (pixels)", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = zTranslateEditor, type = slider, width = 120px,  | ||||
| 							min = -100, max = 100, step = 1, value = 0  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = zTranslateValue, text = "0px", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"Scale X", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = xScaleEditor, type = slider, width = 120px,  | ||||
| 							min = -5, max = 5, step = 0.1, value = 1  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = xScaleValue, text = "1", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"Scale Y", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = yScaleEditor, type = slider, width = 120px,  | ||||
| 							min = -5, max = 5, step = 0.1, value = 1  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = yScaleValue, text = "1", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"Scale Z", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = zScaleEditor, type = slider, width = 120px,  | ||||
| 							min = -5, max = 5, step = 0.1, value = 1  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = zScaleValue, text = "1", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"Skew X (degree)", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = xSkewEditor, type = slider, width = 120px,  | ||||
| 							min = -90, max = 90, step = 1, value = 0  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = xSkewValue, text = "0°", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"Skew Y (degree)", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = ySkewEditor, type = slider, width = 120px,  | ||||
| 							min = -90, max = 90, step = 1, value = 0  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = ySkewValue, text = "0°", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"Rotate (degree)", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = RotateEditor, type = slider, width = 120px,  | ||||
| 							min = -180, max = 180, step = 1, value = 0  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = RotateValue, text = "0°", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"Rotate X", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = xRotateEditor, type = slider, width = 120px,  | ||||
| 							min = 0, max = 1, step = 0.01, value = 1  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = xRotateValue, text = "1", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"Rotate Y", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = yRotateEditor, type = slider, width = 120px,  | ||||
| 							min = 0, max = 1, step = 0.01, value = 1  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = yRotateValue, text = "1", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"Rotate Z", | ||||
| 				ListLayout {  | ||||
| 					margin-bottom = 12px, orientation = horizontal, vertical-align = center, | ||||
| 					content = [ | ||||
| 						NumberPicker { id = zRotateEditor, type = slider, width = 120px,  | ||||
| 							min = 0, max = 1, step = 0.01, value = 1  | ||||
| 						}, | ||||
| 						TextView { | ||||
| 							id = zRotateValue, text = "1", margin-left = 12px, width = 32px | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				Checkbox { id = backfaceVisibility, content = "backface-visibility", checked = true }				 | ||||
| 			] | ||||
| 		} | ||||
| 	]		 | ||||
| }` | ||||
| 
 | ||||
| func transformDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, transformDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	// 		transform := rui.NewTransform(view.Session())
 | ||||
| 
 | ||||
| 	transformView := rui.ViewByID(view, "transformView") | ||||
| 	if transformView == nil { | ||||
| 		return view | ||||
| 	} | ||||
| 
 | ||||
| 	updateSliderText := func(tag string, value float64, unit string) { | ||||
| 		rui.Set(view, tag, rui.Text, fmt.Sprintf("%g%s", value, unit)) | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "PerspectiveEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.Perspective, rui.Px(newValue)) | ||||
| 		updateSliderText("PerspectiveValue", newValue, "px") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "xPerspectiveOriginEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.PerspectiveOriginX, rui.Px(newValue)) | ||||
| 		updateSliderText("xPerspectiveOriginValue", newValue, "px") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "yPerspectiveOriginEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.PerspectiveOriginY, rui.Px(newValue)) | ||||
| 		updateSliderText("yPerspectiveOriginValue", newValue, "px") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "xOriginEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.OriginX, rui.Px(newValue)) | ||||
| 		updateSliderText("xOriginValue", newValue, "px") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "yOriginEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.OriginY, rui.Px(newValue)) | ||||
| 		updateSliderText("yOriginValue", newValue, "px") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "zOriginEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.OriginZ, rui.Px(newValue)) | ||||
| 		updateSliderText("zOriginValue", newValue, "px") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "xTranslateEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.TranslateX, rui.Px(newValue)) | ||||
| 		updateSliderText("xTranslateValue", newValue, "px") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "yTranslateEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.TranslateY, rui.Px(newValue)) | ||||
| 		updateSliderText("yTranslateValue", newValue, "px") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "zTranslateEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.TranslateZ, rui.Px(newValue)) | ||||
| 		updateSliderText("zTranslateValue", newValue, "px") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "xScaleEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.ScaleX, newValue) | ||||
| 		updateSliderText("xScaleValue", newValue, "") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "yScaleEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.ScaleY, newValue) | ||||
| 		updateSliderText("yScaleValue", newValue, "") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "zScaleEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.ScaleZ, newValue) | ||||
| 		updateSliderText("zScaleValue", newValue, "") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "RotateEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.Rotate, rui.Deg(newValue)) | ||||
| 		updateSliderText("RotateValue", newValue, "°") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "xRotateEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.RotateX, newValue) | ||||
| 		updateSliderText("xRotateValue", newValue, "") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "yRotateEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.RotateY, newValue) | ||||
| 		updateSliderText("yRotateValue", newValue, "") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "zRotateEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.RotateZ, newValue) | ||||
| 		updateSliderText("zRotateValue", newValue, "") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "xSkewEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.SkewX, rui.Deg(newValue)) | ||||
| 		updateSliderText("xSkewValue", newValue, "°") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "ySkewEditor", rui.NumberChangedEvent, func(v rui.NumberPicker, newValue float64) { | ||||
| 		transformView.Set(rui.SkewY, rui.Deg(newValue)) | ||||
| 		updateSliderText("ySkewValue", newValue, "°") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "backfaceVisibility", rui.CheckboxChangedEvent, func(checkbox rui.Checkbox, checked bool) { | ||||
| 		transformView.Set(rui.BackfaceVisible, checked) | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,70 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const transitionDemoText = ` | ||||
| ListLayout { | ||||
| 	width = 100%, height = 100%, orientation = vertical, padding = 12px, | ||||
| 	content = [ | ||||
| 		"ease", | ||||
| 		View { id = bar1, width = 20%, style = transitionBar }, | ||||
| 		"ease-in", | ||||
| 		View { id = bar2, width = 20%, style = transitionBar }, | ||||
| 		"ease-out", | ||||
| 		View { id = bar3, width = 20%, style = transitionBar }, | ||||
| 		"ease-in-out", | ||||
| 		View { id = bar4, width = 20%, style = transitionBar }, | ||||
| 		"linear", | ||||
| 		View { id = bar5, width = 20%, style = transitionBar }, | ||||
| 		"steps(5)", | ||||
| 		View { id = bar6, width = 20%, style = transitionBar }, | ||||
| 		"cubic-bezier(0.1, -0.6, 0.2, 0)", | ||||
| 		View { id = bar7, width = 20%, style = transitionBar }, | ||||
| 		Button { id = startTransition, content = "Start" } | ||||
| 	] | ||||
| }` | ||||
| 
 | ||||
| func createTransitionDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, transitionDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	bars := map[string]string{ | ||||
| 		"bar1": rui.EaseTiming, | ||||
| 		"bar2": rui.EaseInTiming, | ||||
| 		"bar3": rui.EaseOutTiming, | ||||
| 		"bar4": rui.EaseInOutTiming, | ||||
| 		"bar5": rui.LinearTiming, | ||||
| 		"bar6": rui.StepsTiming(5), | ||||
| 		"bar7": rui.CubicBezierTiming(0.1, -0.6, 0.2, 0), | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "startTransition", rui.ClickEvent, func(button rui.View) { | ||||
| 		for id, timing := range bars { | ||||
| 			if bar := rui.ViewByID(view, id); bar != nil { | ||||
| 				if rui.GetWidth(bar, "").Value == 100 { | ||||
| 					bar.SetAnimated(rui.Width, rui.Percent(20), rui.Animation{ | ||||
| 						Duration:       2, | ||||
| 						TimingFunction: timing, | ||||
| 					}) | ||||
| 				} else { | ||||
| 					bar.SetAnimated(rui.Width, rui.Percent(100), rui.Animation{ | ||||
| 						Duration:       2, | ||||
| 						TimingFunction: timing, | ||||
| 						FinishListener: rui.AnimationFinishedFunc(func(v rui.View, tag string) { | ||||
| 							bar.SetAnimated(rui.Width, rui.Percent(20), rui.Animation{ | ||||
| 								Duration:       2, | ||||
| 								TimingFunction: bars[v.ID()], | ||||
| 							}) | ||||
| 						}), | ||||
| 					}) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
|  | @ -0,0 +1,152 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const videoPlayerDemoText = ` | ||||
| GridLayout { | ||||
| 	cell-height = "auto, 1fr, auto, auto", width = 100%, height = 100%, | ||||
| 	content = [ | ||||
| 		ListLayout { | ||||
| 			row = 0, orientation = start-to-end, padding = 4px, | ||||
| 			content = [ | ||||
| 				Checkbox {  | ||||
| 					id = showVideoPlayerControls, content = "Controls" | ||||
| 				}, | ||||
| 				Checkbox {  | ||||
| 					id = showVideoPlayerLoop, content = "Loop" | ||||
| 				}, | ||||
| 				Checkbox {  | ||||
| 					id = showVideoPlayerMuted, content = "Muted" | ||||
| 				}, | ||||
| 			], | ||||
| 		}, | ||||
| 		GridLayout { | ||||
| 			row = 1, id = videoPlayerContainer, | ||||
| 			content = VideoPlayer { | ||||
| 				id = videoPlayer, src = "https://alxanosoft.com/testVideo.mp4", video-width = 320, | ||||
| 			}, | ||||
| 		}, | ||||
| 		ListLayout { | ||||
| 			row = 2, orientation = start-to-end, vertical-align = top, padding = 8px, | ||||
| 			content = [ | ||||
| 				NumberPicker { | ||||
| 					id = videoPlayerSlider, width = 200px, type = slider | ||||
| 				} | ||||
| 				Button { | ||||
| 					id = videoPlayerPlay, content = "Play", margin-left = 16px | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		Resizable { | ||||
| 			row = 3, side = top, background-color = lightgrey, height = 200px, | ||||
| 			content = EditView { | ||||
| 				id = videoPlayerEventsLog, type = multiline, read-only = true, wrap = true, | ||||
| 			} | ||||
| 		}, | ||||
| 	] | ||||
| }` | ||||
| 
 | ||||
| var videoPlayerPause = true | ||||
| 
 | ||||
| func createVideoPlayerDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, videoPlayerDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	createListener := func(event string) func() { | ||||
| 		return func() { | ||||
| 			rui.AppendEditText(view, "videoPlayerEventsLog", event+"\n") | ||||
| 			rui.ScrollViewToEnd(view, "videoPlayerEventsLog") | ||||
| 		} | ||||
| 	} | ||||
| 	createListener2 := func(event string) func(value float64) { | ||||
| 		return func(value float64) { | ||||
| 			rui.AppendEditText(view, "videoPlayerEventsLog", fmt.Sprintf("%s: %g\n", event, value)) | ||||
| 			rui.ScrollViewToEnd(view, "videoPlayerEventsLog") | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "videoPlayerContainer", rui.ResizeEvent, func(frame rui.Frame) { | ||||
| 		rui.Set(view, "videoPlayer", rui.VideoWidth, frame.Width) | ||||
| 		rui.Set(view, "videoPlayer", rui.VideoHeight, frame.Height) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "showVideoPlayerControls", rui.CheckboxChangedEvent, func(state bool) { | ||||
| 		rui.Set(view, "videoPlayer", rui.Controls, state) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "showVideoPlayerLoop", rui.CheckboxChangedEvent, func(state bool) { | ||||
| 		rui.Set(view, "videoPlayer", rui.Loop, state) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "showVideoPlayerMuted", rui.CheckboxChangedEvent, func(state bool) { | ||||
| 		rui.Set(view, "videoPlayer", rui.Muted, state) | ||||
| 	}) | ||||
| 
 | ||||
| 	for _, event := range []string{rui.AbortEvent, rui.CanPlayEvent, rui.CanPlayThroughEvent, | ||||
| 		rui.CompleteEvent, rui.EmptiedEvent, rui.EndedEvent, rui.LoadStartEvent, | ||||
| 		rui.LoadedMetadataEvent, rui.PlayingEvent, rui.SeekedEvent, rui.SeekingEvent, | ||||
| 		rui.StalledEvent, rui.SuspendEvent, rui.WaitingEvent} { | ||||
| 
 | ||||
| 		rui.Set(view, "videoPlayer", event, createListener(event)) | ||||
| 	} | ||||
| 
 | ||||
| 	for _, event := range []string{rui.DurationChangedEvent, rui.RateChangedEvent, rui.VolumeChangedEvent} { | ||||
| 
 | ||||
| 		rui.Set(view, "videoPlayer", event, createListener2(event)) | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "videoPlayer", rui.PlayEvent, func() { | ||||
| 		rui.AppendEditText(view, "videoPlayerEventsLog", "play-event\n") | ||||
| 		rui.ScrollViewToEnd(view, "videoPlayerEventsLog") | ||||
| 		rui.Set(view, "videoPlayerPlay", rui.Content, "Pause") | ||||
| 		videoPlayerPause = false | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "videoPlayer", rui.PauseEvent, func() { | ||||
| 		rui.AppendEditText(view, "videoPlayerEventsLog", "pause-event\n") | ||||
| 		rui.ScrollViewToEnd(view, "videoPlayerEventsLog") | ||||
| 		rui.Set(view, "videoPlayerPlay", rui.Content, "Play") | ||||
| 		videoPlayerPause = true | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "videoPlayer", rui.LoadedDataEvent, func() { | ||||
| 		rui.AppendEditText(view, "videoPlayerEventsLog", "loaded-data-event\n") | ||||
| 		rui.ScrollViewToEnd(view, "videoPlayerEventsLog") | ||||
| 		rui.Set(view, "videoPlayerSlider", rui.Max, rui.MediaPlayerDuration(view, "videoPlayer")) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "videoPlayer", rui.TimeUpdateEvent, func(time float64) { | ||||
| 		rui.AppendEditText(view, "videoPlayerEventsLog", fmt.Sprintf("time-update-event %gs\n", time)) | ||||
| 		rui.ScrollViewToEnd(view, "videoPlayerEventsLog") | ||||
| 		rui.Set(view, "videoPlayerSlider", rui.Value, time) | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "vodeoPlayer", rui.PlayerErrorEvent, func(code int, message string) { | ||||
| 		rui.AppendEditText(view, "vodeoPlayerEventsLog", fmt.Sprintf("player-error-event: code = %d, message = '%s'\n", code, message)) | ||||
| 		rui.ScrollViewToEnd(view, "vodeoPlayerEventsLog") | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "videoPlayerPlay", rui.ClickEvent, func() { | ||||
| 		if videoPlayerPause { | ||||
| 			rui.MediaPlayerPlay(view, "videoPlayer") | ||||
| 		} else { | ||||
| 			rui.MediaPlayerPause(view, "videoPlayer") | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "videoPlayerSlider", rui.NumberChangedEvent, func(value float64) { | ||||
| 		if videoPlayerPause { | ||||
| 			rui.SetMediaPlayerCurrentTime(view, "videoPlayer", value) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||
| 
 | ||||
| //MAH00054.MP4
 | ||||
|  | @ -0,0 +1,116 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/anoshenko/rui" | ||||
| ) | ||||
| 
 | ||||
| const viewDemoText = ` | ||||
| GridLayout { | ||||
| 	style = demoPage, | ||||
| 	content = [ | ||||
| 		GridLayout { | ||||
| 			width = 100%, height = 100%, cell-vertical-align = center, cell-horizontal-align = center, | ||||
| 			content = [ | ||||
| 				View {  | ||||
| 					id = demoView, width = 250px, height = 150px, | ||||
| 					background-color = #FFFF0000, border-width = 1px | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		ListLayout { | ||||
| 			style = optionsPanel, | ||||
| 			content = [ | ||||
| 				GridLayout { | ||||
| 					style = optionsTable, | ||||
| 					content = [ | ||||
| 						TextView { row = 0, text = "Border style" }, | ||||
| 						DropDownList { row = 0, column = 1, id = viewBorderStyle, current = 0, | ||||
| 							items = ["none", "solid", "dashed", "dotted", "double", "4 styles"] | ||||
| 						}, | ||||
| 						TextView { row = 1, text = "Border width" }, | ||||
| 						DropDownList { row = 1, column = 1, id = viewBorderWidth, current = 0, | ||||
| 							items = ["1px", "2px", "3.5px", "5px", "1px,2px,3px,4px"] | ||||
| 						}, | ||||
| 						TextView { row = 2, text = "Border color" }, | ||||
| 						DropDownList { row = 2, column = 1, id = viewBorderColor, current = 0, | ||||
| 							items = ["black", "blue", "4 colors"] | ||||
| 						}, | ||||
| 						TextView { row = 3, text = "Radius" }, | ||||
| 						DropDownList { row = 3, column = 1, id = viewRadius, current = 0, | ||||
| 							items = ["0", "8px", "12px/24px", "0 48px/24px 0 48px/24px"] | ||||
| 						}, | ||||
|                  | ||||
| 					] | ||||
| 				} | ||||
| 			] | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| func viewDemo(session rui.Session) rui.View { | ||||
| 	view := rui.CreateViewFromText(session, viewDemoText) | ||||
| 	if view == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	rui.Set(view, "viewBorderStyle", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		if number < 5 { | ||||
| 			rui.Set(view, "demoView", rui.BorderStyle, number) | ||||
| 		} else { | ||||
| 			rui.Set(view, "demoView", rui.BorderTopStyle, 1) | ||||
| 			rui.Set(view, "demoView", rui.BorderRightStyle, 2) | ||||
| 			rui.Set(view, "demoView", rui.BorderBottomStyle, 3) | ||||
| 			rui.Set(view, "demoView", rui.BorderLeftStyle, 4) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "viewBorderWidth", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		widths := []rui.SizeUnit{rui.Px(1), rui.Px(2), rui.Px(3.5), rui.Px(5)} | ||||
| 		if number < len(widths) { | ||||
| 			rui.Set(view, "demoView", rui.BorderWidth, widths[number]) | ||||
| 		} else { | ||||
| 			rui.SetParams(view, "demoView", rui.Params{ | ||||
| 				rui.BorderTopWidth:    rui.Px(1), | ||||
| 				rui.BorderRightWidth:  rui.Px(2), | ||||
| 				rui.BorderBottomWidth: rui.Px(3), | ||||
| 				rui.BorderLeftWidth:   rui.Px(4)}) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "viewBorderColor", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		colors := []rui.Color{rui.Black, rui.Blue} | ||||
| 		if number < len(colors) { | ||||
| 			rui.Set(view, "demoView", rui.BorderColor, colors[number]) | ||||
| 		} else { | ||||
| 			rui.SetParams(view, "demoView", rui.Params{ | ||||
| 				rui.BorderTopColor:    rui.Blue, | ||||
| 				rui.BorderRightColor:  rui.Green, | ||||
| 				rui.BorderBottomColor: rui.Magenta, | ||||
| 				rui.BorderLeftColor:   rui.Aqua}) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	rui.Set(view, "viewRadius", rui.DropDownEvent, func(list rui.DropDownList, number int) { | ||||
| 		switch number { | ||||
| 		case 0: | ||||
| 			rui.Set(view, "demoView", rui.Radius, nil) | ||||
| 
 | ||||
| 		case 1: | ||||
| 			rui.Set(view, "demoView", rui.Radius, rui.Px(8)) | ||||
| 
 | ||||
| 		case 2: | ||||
| 			rui.Set(view, "demoView", rui.RadiusX, rui.Px(12)) | ||||
| 			rui.Set(view, "demoView", rui.RadiusY, rui.Px(24)) | ||||
| 
 | ||||
| 		case 3: | ||||
| 			rui.Set(view, "demoView", rui.Radius, nil) | ||||
| 			rui.Set(view, "demoView", rui.RadiusTopRightX, rui.Px(48)) | ||||
| 			rui.Set(view, "demoView", rui.RadiusTopRightY, rui.Px(24)) | ||||
| 			rui.Set(view, "demoView", rui.RadiusBottomLeftX, rui.Px(48)) | ||||
| 			rui.Set(view, "demoView", rui.RadiusBottomLeftY, rui.Px(24)) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	return view | ||||
| } | ||||