renderview

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 22, 2020 License: MIT Imports: 7 Imported by: 0

README

RenderView

================

GoDoc

Install:

go get github.com/TheGrum/renderview

Needs either Shiny (limited functionality), Gio, Fyne, go-gtk, or gotk3. The latter two require the corresponding GTK library installed. Gio and Fyne have their own requirements.

=====

A tool to quickly and easily wrap algorithms, image generation functions, web services, and the like with an interactive GUI interface offering panning, zooming, paging, and editable parameters.

This is not meant as a replacement for a general GUI toolkit. It is meant for programmers who lack the time to invest in learning yet another graphical toolkit and all of its quirks and foibles just to throw up a quick interactive interface to get a feel for the behavior of back-end code.

YouTube demo of using renderview to create a Mandelbrot viewer

Model-View-Controller

Basically, RenderView is a View+Controller combination that operates on a Model you write - except that for many tasks, the built-in models will suffice, and all you have to implement is an image generation function. (Technically, I suppose, it is actually splitting the View into two parts, one that you write for the image generation, and one that RenderView sets up for editing parameters.)

RenderView

The eponymous control, this comes in multiple flavors, and handles window creation, view rendering, and control/event-handling.

Shiny

Shiny is an experimental native cross-platform GUI package for Go. At the moment it is usable only as a framebuffer+event loop. If all you need is the output of your image generation function with panning and zooming, RenderView+Shiny supports that.

Build with -tags "shiny nogtk2" to use the Shiny backend.

Gio

Gio is an immediate-mode GUI package for Go. RenderView on the Gio backend supports automatic parameter editing widget generation in addition to the interactive image.

Build with -tags "gio nogtk2" to use the Gio backend.

Fyne

Fyne is a Material-design influenced GUI package for Go. RenderView on the Fyne backend supports automatic parameter editing widget generation in addition to the interactive image.

Build with -tags "fyne nogtk2" to use the Fyne backend.

go-gtk

go-gtk is a functional CGo based GTK2 binding. RenderView on the go-gtk backend supports automatic parameter editing widget generation in addition to the interactive image.

This is currently the default backend, so no -tags line is required.

gotk3

gotk3 is a functional CGo based GTK3 binding. RenderView on the gotk3 backend supports automatic parameter editing widget generation in addition to the interactive image. Note that on first build, the gotk3 package may be noticeably slow to build.

Build with -tags "gotk3 nogtk2" to use the gotk3 backend.

RenderParameter

Each RenderParameter carries a type string, allowing the RenderView code to read and set the values without reflection. There is also a blank parameter that is automatically returned when a missing parameter is requested, allowing the RenderView code to behave as if the parameters it uses are always present. By either including or omitting the default parameters, you can control whether your code pays attention to certain controller behaviors.

Hints can be provided to indicate whether parameters are only for use in communicating with the View and Controller, or should be exposed to the user.

ZoomRenderParameter in the Mandelbrot example provides a demonstration of using a custom parameter to react immediately to changes in a value and, by setting other parameters in response, implement custom behavior.

ChangeMonitor

A means to observe a subset of RenderParameters and determine if they have changed since the value was last checked.

RenderModel

You can implement this to customize what information gets collected from the GUI and passed to your visualization code, and what gets returned.

Basically, this boils down to a bag of parameters and a Render function that the view calls.

BasicRenderModel

In most cases, the BasicRenderModel will suffice. It provides a concrete implementation of the RenderModel interface and adds a throttling mechanism that ensures that requests for a new rendering from the view code only get passed through to your code when you do not already have a render in process, provided that you signal it by setting the Rendering bool appropriately at the start and end of your render.

It moves rendering to a separate Goroutine, preventing a long-running image generator from freezing the UI.

TileRenderModel

The TileRenderModel implements a RenderModel that operates on map tiles such as those used in the OpenStreetMaps project. Look in models/tile for a TileRenderModel specific README.md.

Usage

At its most basic, using RenderView with the BasicRenderModel can be as simple as adding a few lines of code:

    m := rv.NewBasicRenderModel()
    m.AddParameters(DefaultParameters(false, rv.HINT_SIDEBAR, rv.OPT_AUTO_ZOOM, -10, 10, 10, -10)...)
    m.InnerRender = func() {
    	// some number of m.Param[x].Value[Float64|Int|etc]() to gather the values your renderer needs
    	m.Img = your_rendering_function_here(param, param, param)
    }
    driver.Main(m)

Alternately, you can fully specify your parameters, like so:

  	m.AddParameters(
  		rv.SetHints(rv.HINT_HIDE,
  			rv.NewIntRP("width", 0),
  			rv.NewIntRP("height", 0),
  		)...)
  	m.AddParameters(
  		rv.SetHints(rv.HINT_SIDEBAR,
  		rv.NewIntRP("page", 0),
  		rv.NewIntRP("linewidth", 1),
  		rv.NewIntRP("cellwidth", 5),
  		rv.NewIntRP("mazewidth", 100),
  		rv.NewIntRP("mazeheight", 100))...)
Useful parameters

You can have as many parameters as you like, but certain paramaters if present have special meaning to the views.

  • left,top,right,bottom - these can be either int or float64, and when available, operate panning, and if float64, zooming. - two way, you can change these in your code to move the viewport if you are paying attention to them
  • width,height - these get populated with the window width and height - changing these in your code has no effect.
  • options - maybe more later, right now these just control the zooming (done with the scroll-wheel) const ( OPT_NONE = iota // 0 OPT_CENTER_ZOOM = 1 << iota // 1 OPT_AUTO_ZOOM = 1 << iota // 2 )
  • zoom - int or float64, this gets incremented/decremented when the scroll-wheel is turned, and can be used to implement your own zoom.
  • mouseX, mouseY - float64, these get populated with the current mouse position in the window
  • page - this gets incremented/decremented by PgUp and PgDown when the graphical window has the focus, allowing for a paged environment. You can manipulated these from a custom zoom parameter to tie scrolling to paging if desired.

See examples and cmd for more.

Some examples require -tags "example" to build.

cmdgui

More than an example, this is a tool that applies the automatic GUI creation concept to command line applications or, through the medium of curl and other url-grabbing applications, to web services. It uses Go Templates to perform argument rewriting, and exports all parameters to the environment as well.

    #!/bin/sh
    ./cmdgui -extraflags="func,string,sin(x);x" "./plot" "{{$.func}} {{$.left}} {{$.right}} {{$.bottom}} {{$.top}}"

This one line example takes a python command line plot generator, and turns it into an interactive function plotter supporting changing the function, panning, zooming, and hand-entering of plot axis dimensions.

Screenshots

Mandelbrot cmdgui plot maze maze2 lsystem map

Documentation

Index

Constants

View Source
const (
	HINT_NONE     = 1 << iota
	HINT_HIDE     = 1 << iota
	HINT_SIDEBAR  = 1 << iota
	HINT_FOOTER   = 1 << iota
	HINT_FULLTEXT = 1 << iota
)
View Source
const (
	OPT_NONE        = iota      // 0
	OPT_CENTER_ZOOM = 1 << iota // 1
	OPT_AUTO_ZOOM   = 1 << iota // 2
)
View Source
const ZOOM_RATE = 0.1

Variables

This section is empty.

Functions

func GetParameterStatusString

func GetParameterStatusString(params ...RenderParameter) string

func GetParameterValueAsString

func GetParameterValueAsString(p RenderParameter) string

GetParameterValueAsString replaces the need to implement GetValueString on each parameter. Custom parameters should override GetValueString to override this behavior.

func InitializeBasicRenderModel

func InitializeBasicRenderModel(m *BasicRenderModel)

Use Initialize to set up a BasicRenderModel when you have embedded it in your own model Remember to add a go m.GoRender() or call Start()

func InitializeEmptyRenderModel

func InitializeEmptyRenderModel(m *EmptyRenderModel)

InitializeEmptyRenderModel should be called to initialize the EmptyRenderModel when embedded in your own struct.

func ParseComplex

func ParseComplex(v string) (complex128, error)

func SetParameterValueFromString

func SetParameterValueFromString(p RenderParameter, v string)

SetParameterValueAsString replaces the need to implement SetValueString on each parameter. Custom parameters should override SetValueString to override this behavior.

Types

type BasicRenderModel

type BasicRenderModel struct {
	EmptyRenderModel

	RequestRender chan interface{}
	NeedsRender   bool
	Rendering     bool
	Img           image.Image

	InnerRender func()
	// contains filtered or unexported fields
}

BasicRenderModel should suffice for many users, and can be embedded to provide its functionality to your own models. It provides an easy way to attach your own rendering implementation that will be called in a separate goroutine.

func NewBasicRenderModel

func NewBasicRenderModel() *BasicRenderModel

func (*BasicRenderModel) GoRender

func (m *BasicRenderModel) GoRender()

GoRender is called by Start and calls your provided InnerRender function when needed.

func (*BasicRenderModel) Render

func (m *BasicRenderModel) Render() image.Image

Called by RenderView

func (*BasicRenderModel) Start

func (m *BasicRenderModel) Start()

Start only needs to be called if you have embedded BasicRenderModel in your own struct.

type ChangeMonitor

type ChangeMonitor struct {
	sync.Mutex
	Params []RenderParameter
	// contains filtered or unexported fields
}

ChangeMonitor implements comparing the value of a subset of parameters to determine whether a redraw or recalculation is required

func NewChangeMonitor

func NewChangeMonitor() *ChangeMonitor

func (*ChangeMonitor) AddParameters

func (c *ChangeMonitor) AddParameters(params ...RenderParameter)

func (*ChangeMonitor) HasChanged

func (c *ChangeMonitor) HasChanged() bool

type Complex128RenderParameter

type Complex128RenderParameter struct {
	EmptyParameter

	Value complex128
}

func NewComplex128RP

func NewComplex128RP(name string, value complex128) *Complex128RenderParameter

func (*Complex128RenderParameter) GetValueComplex128

func (e *Complex128RenderParameter) GetValueComplex128() complex128

func (*Complex128RenderParameter) SetValueComplex128

func (e *Complex128RenderParameter) SetValueComplex128(v complex128) complex128

type EmptyParameter

type EmptyParameter struct {
	Name string
	Type string
	Hint int
}

func (*EmptyParameter) GetHint

func (e *EmptyParameter) GetHint() int

func (*EmptyParameter) GetName

func (e *EmptyParameter) GetName() string

func (*EmptyParameter) GetType

func (e *EmptyParameter) GetType() string

func (*EmptyParameter) GetValueComplex128

func (e *EmptyParameter) GetValueComplex128() complex128

func (*EmptyParameter) GetValueFloat64

func (e *EmptyParameter) GetValueFloat64() float64

func (*EmptyParameter) GetValueInt

func (e *EmptyParameter) GetValueInt() int

func (*EmptyParameter) GetValueString

func (e *EmptyParameter) GetValueString() string

func (*EmptyParameter) GetValueUInt32

func (e *EmptyParameter) GetValueUInt32() uint32

func (*EmptyParameter) SetHint

func (e *EmptyParameter) SetHint(value int)

func (*EmptyParameter) SetValueComplex128

func (e *EmptyParameter) SetValueComplex128(value complex128) complex128

func (*EmptyParameter) SetValueFloat64

func (e *EmptyParameter) SetValueFloat64(value float64) float64

func (*EmptyParameter) SetValueInt

func (e *EmptyParameter) SetValueInt(value int) int

func (*EmptyParameter) SetValueString

func (e *EmptyParameter) SetValueString(value string) string

func (*EmptyParameter) SetValueUInt32

func (e *EmptyParameter) SetValueUInt32(value uint32) uint32

type EmptyRenderModel

type EmptyRenderModel struct {
	sync.Mutex

	Params       []RenderParameter
	RequestPaint func()
}

EmptyRenderModel concretizes the most important elements of the RenderModel, the bag of Parameters (Params) and the RequestPaint function (which the view sets) - call this latter function to inform the view that you have provided a new image or set of information needing a render. It is not usable as a RenderModel by itself, as the implementation of Render simply returns nil. Embed it in your RenderModel struct.

func (*EmptyRenderModel) AddParameters

func (e *EmptyRenderModel) AddParameters(Params ...RenderParameter)

AddParameters accepts any number of parameters and adds them to the Params bag. It does not do ANY checking for duplication!

func (*EmptyRenderModel) GetHintedParameterNames

func (e *EmptyRenderModel) GetHintedParameterNames(hints int) []string

GetHintedParameterNames returns a list of parameters with one of the passed hints

func (*EmptyRenderModel) GetHintedParameterNamesWithFallback

func (e *EmptyRenderModel) GetHintedParameterNamesWithFallback(hints int) []string

GetHintedParameterNamesWithFallback retrieves the names of parameters matching hints, if that is the empty set, it retrieves the names of parameters with no hints

func (*EmptyRenderModel) GetParameter

func (e *EmptyRenderModel) GetParameter(name string) RenderParameter

GetParameter returns a named parameter. If you implement your own RenderModel from scratch, without using the EmptyRenderModel as a basis, you must either include ALL the default parameters, or duplicate the behavior of EmptyRenderModel in returning an EmptyParameter when a non-existent parameter is requested.

func (*EmptyRenderModel) GetParameterNames

func (e *EmptyRenderModel) GetParameterNames() []string

GetParameterNames returns a list of valid parameter names

func (*EmptyRenderModel) GetRequestPaintFunc

func (e *EmptyRenderModel) GetRequestPaintFunc() func()

Included for completeness. In general, there is no need for your code to use the RenderModel interface instead of a concrete form, so you can simply access e.RequestPaint directly.

func (*EmptyRenderModel) Render

func (e *EmptyRenderModel) Render() image.Image

func (*EmptyRenderModel) SetRequestPaintFunc

func (e *EmptyRenderModel) SetRequestPaintFunc(f func())

Used by the RenderView to supply a function you can call to inform the view that it should perform a repaint.

type Float64RenderParameter

type Float64RenderParameter struct {
	EmptyParameter

	Value float64
}

func NewFloat64RP

func NewFloat64RP(name string, value float64) *Float64RenderParameter

func (*Float64RenderParameter) GetValueFloat64

func (e *Float64RenderParameter) GetValueFloat64() float64

func (*Float64RenderParameter) SetValueFloat64

func (e *Float64RenderParameter) SetValueFloat64(v float64) float64

type IntRenderParameter

type IntRenderParameter struct {
	EmptyParameter

	Value int
}

func NewIntRP

func NewIntRP(name string, value int) *IntRenderParameter

func (*IntRenderParameter) GetValueInt

func (e *IntRenderParameter) GetValueInt() int

func (*IntRenderParameter) SetValueInt

func (e *IntRenderParameter) SetValueInt(v int) int

type RenderModel

type RenderModel interface {
	Lock()
	Unlock()

	GetParameterNames() []string
	GetHintedParameterNames(hint int) []string
	GetHintedParameterNamesWithFallback(hint int) []string
	GetParameter(name string) RenderParameter
	Render() image.Image
	SetRequestPaintFunc(func())
	GetRequestPaintFunc() func()
}

RenderModel is the interface you will implement to stand between your visualization code and the RenderView. You are primarily responsible for providing a set of RenderParameters and providing an Image upon request via Render.

type RenderParameter

type RenderParameter interface {
	GetName() string
	GetType() string
	GetHint() int
	SetHint(int)
	GetValueInt() int
	GetValueUInt32() uint32
	GetValueFloat64() float64
	GetValueComplex128() complex128
	GetValueString() string
	SetValueInt(value int) int
	SetValueUInt32(value uint32) uint32
	SetValueFloat64(value float64) float64
	SetValueComplex128(value complex128) complex128
	SetValueString(value string) string
}

func DefaultParameters

func DefaultParameters(useint bool, hint int, options int, left float64, top float64, right float64, bottom float64) []RenderParameter

func SetHints

func SetHints(hint int, params ...RenderParameter) []RenderParameter

type StringRenderParameter

type StringRenderParameter struct {
	EmptyParameter

	Value string
}

func NewStringRP

func NewStringRP(name string, value string) *StringRenderParameter

func (*StringRenderParameter) GetValueString

func (e *StringRenderParameter) GetValueString() string

func (*StringRenderParameter) SetValueString

func (e *StringRenderParameter) SetValueString(v string) string

type UInt32RenderParameter

type UInt32RenderParameter struct {
	EmptyParameter

	Value uint32
}

func NewUInt32RP

func NewUInt32RP(name string, value uint32) *UInt32RenderParameter

func (*UInt32RenderParameter) GetValueString

func (e *UInt32RenderParameter) GetValueString() string

func (*UInt32RenderParameter) GetValueUInt32

func (e *UInt32RenderParameter) GetValueUInt32() uint32

func (*UInt32RenderParameter) SetValueString

func (e *UInt32RenderParameter) SetValueString(v string) string

func (*UInt32RenderParameter) SetValueUInt32

func (e *UInt32RenderParameter) SetValueUInt32(v uint32) uint32

Directories

Path Synopsis
cmd
package driver provides a generic interface to the renderview gui implementations
package driver provides a generic interface to the renderview gui implementations
examples
model

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL