Skip to content
Randall C. O'Reilly edited this page Jan 25, 2024 · 1 revision

The ValueView system uses the GoGi widgets to provide automatic GUI interfaces for all standard Go types.

See the giv package docs for details on all the code.

The GiEditor for example combines a TreeView with a StructView to show a Ki tree on the left panel and a view of the selected struct on the right. There are also: MapView, SliceView and TableView (which provides an interface for a slice of a struct, with the columns of a table as the fields of the struct, and a row for each such struct in the slice).

The dialogs.go file defines functions that pop up a window with each of the major types of views (StructViewDialog, SliceViewDialog, MapViewDialog, etc). So if you need a quick way for someone to edit one of your data elements, these can be very handy.

ValueView

The ValueView interface provides a manager that mediates between the reflect system and specific widgets that provide a GUI interface to a particular value. For example, the StructView iterates through its fields and gets a ValueView type for each field, and then just calls the generic API there to create an appropriate widget etc.

Each specific type that implements the ValueView interface manages a particular type of object. To create a new custom interface for something, just create a corresponding ValueView type for that type. For example, there is an IconValueView for the IconName type, which shows an Action widget whose action is to pull up the IconChooserDialog to select an icon.

The ValueViewer interface is a simple Stringer-like interface that returns the appropriate ValueView type for a given other type. You just define its ValueView() method to return the appropriate type of ValueView.

The ToValueView function handles the process of finding the best value view for each type -- because you cannot define new methods on types from other packages, and you can't have cyclic dependencies between the gi and giv packages, this function handles all those cases and the basic types, but other packages that use gi/giv can just use the ValueViewer interface. The FieldToValueView is a special front-end pass on ToValueView for struct fields.

struct field Tags

See Tags for tags that can be added to fields in structs to affect view display.

Methods

There is also support for automatically creating an interface to the methods on a type, by defining a set of ki.Props properties associated with the type (used for all Style settings in GoGi), through the kit package AddType type registration mechanism. The top-level properties actually require a ki.PropSlice which maintains the order of the elements -- ki.Props is a map which does not maintain order.

You can also use this system to directly call a method using the giv.CallMethod function, and it will automatically provide the full GUI support for user-entry of the args to that method. This is very useful for arbitrary code-initiated method calling when the gui is needed for filling in args (e.g., if a method takes a gi.FileName, calling it via giv.CallMethod will automatically pull up the FileViewDialog and set the arg from the results).

Four top-level property names are recognized:

  • "ToolBar": ki.PropSlice {...} --- defines a toolbar, which will be shown above the the content of that type in all standard views. This should contain a select subset of the most important methods, each of which is defined by a sub-property listing within this overall property, as described below.

  • "MainMenu": ki.PropSlice {...} -- defines a main menu. This will be shown in dialogs where the entire window is devoted to that type of element (e.g., a StructViewDialog showing a StructView). This can contain less-frequently-used methods, in addition to menu versions of methods available in the toolbar. The immediate sub-properties here should be the separate menu entries in the MenuBar, and then within those the method properties as described below.

  • "CtxtMenu*": ki.PropSlice {...} -- defines a context menu. For gi GUI types (e.g., Widgets), this will be shown whenever someone right-clicks on that element, assuming the right mouse button release is calls the ContextMenu() method (e.g., WidgetMouseEvents does this). For other types, the TableView will call the context menu on rows, if the widget does not steal the event. e.g., FileView calls the context menu on FileInfo elements. TreeView also attempts to create a context menu on the objects it is viewing. The immediate sub-properties here are the actions in the menu. You can create different menus for active vs. inactive gui views, using CtxtMenuActive or CtxtMenuInactive properties -- the plain CtxtMenu will be used by default if these special cases are not present.

  • "CallMethods": ki.PropSlice {...} -- any method that is not otherwise configured on any of the above lists can be added here for use via the giv.CallMethod function. CallMethod creates a cache of all registered methods and actually looks in CallMethods first, so you can also override the behavior of a method when called via CallMethod as compared to the main menu or toolbar, etc.

Method Properties

Each method should be entered with the property name that is the exact name of the method -- this is what will be looked up in the type to find the method to call. It should be of type ki.Props and have any appropriate sub-properties as defined below. E.g.:

"ToolBar": ki.PropSlice{
	{"Update", ki.Props{
		"icon": "update",
	}},
	{"sep-file", ki.BlankProp{}},
	{"Save", ki.Props{
		"icon": "file-save",
	}},
	{"sep-color", ki.BlankProp{}},
	{"Colors", ki.PropSlice{ // sub-menu
		{"LoadColors", ki.Props{
			"label": "Open Colors",
			"icon":  "file-open",
			"Args": ki.PropSlice{
				{"Color File Name", ki.Props{
					"default-field": "ColorFilename",
					"ext":           ".json",
				}},
			},
		}},
		{"SaveColors", ki.Props{
			"icon": "file-save",
			"Args": ki.PropSlice{
				{"Color File Name", ki.Props{
					"default-field": "ColorFilename",
					"ext":           ".json",
				}},
			},
		}},
	}},
	...
  • label: string -- provides an alternative label instead of the method name. Note that CamelCase names will be rendered with space separation by default, so a label is not needed for that, and depending on the application, it may be beneficial to keep the GUI method names the same as the code, so that they can be more easily remembered and used in programs.
  • shortcut: string or gi.KeyFuns -- defines a key chord shortcut -- generally put shortcuts in menus, not toolbars. Don't put in both places. In context menus it can display shortcuts that are in effect to inform the user, but does not establish new shortcuts -- passing a gi.KeyFuns (e.g., gi.KeyFunCopy for a "Copy" method) will automatically show (one of the) key commands that activates that key function.
  • keyfun: gi.KeyFun.. -- defines an action that just activates that given key function -- e.g., for Copy, Cut etc -- automatically defines the shortcut appropriately as the one for that keyfun.
  • icon: string -- name of icon for action -- generally put icons in toolbars, not menus.
  • desc: string -- for ToolBar tooltips, and when a prompt dialog is needed to fill in the argument values for a method, or a confirmation dialog is requested, this description provides info to the user about what the method will do. The description given in the source code, shown in goDoc, is not available in reflect, so you'll have to provide this separately here. Probably you want end-users to see something different from the programmer-level comment anyway :) Full HTML styling is, as always, supported.
  • confirm: bool -- for methods with no arguments, pop up an Ok / Cancel dialog to confirm the execution of this method (in general using Undo vs. confirm is preferred, except for truly irreversible actions).
  • show-return: bool -- the return value(s) of the method will be shown in a dialog after it runs.
  • submenu: field or slice -- for methods that have a single argument, this presents user with a sub-menu with the list of options from the given slice literal or field name on object that contains a slice.
  • submenu-func: giv.SubMenuFunc -- a function that takes an interface{} and *gi.Viewport2D and returns []string slice of options for the submenu. called right when the user clicks on the menu item to create the menu ("jit").
  • no-update-after: bool -- do not automatically update the window after running the method -- by default it updates the window, but if the method itself does things to update the display, then this may need to be set to prevent conflicting updates (bool is ignored).
    • You can also specify a top-level type property of: "MethViewNoUpdateAfter": true (value is ignored) to set this option generically for all methods on a given type, if it should never have it. In which case the update-after property can be set per method to override that default.
  • updtfunc: func(iv interface{}, act *gi.Action) -- defines an update function (typically specified right there) that can update the active / inactive status of the action. The interface{} should be converted to the type of the element on which the type properties are defined. Important: use Set[In]ActiveStateUpdt method in toolbars, but NOT in menus, which require the plain Set[In]ActiveState version. For example, here's one from TreeView context menu:
	"updtfunc": func(tvi interface{}, act *gi.Action) {
		tv := tvi.(*TreeView)
		act.SetInactiveState(tv.IsRootOrField(""))
	},
  • Args: ki.PropSlice{...} -- provides names and other properties for each of the arguments -- arg names are not stored in the reflect system and must be provided here, along with any other (optional) special properties for each arg. A dialog will pop up to prompt for all the argument values, and only if the user hits Ok will the method run with those values.
    • Important special case: if a method has 1 arg, and the ValueView for that arg has an "action" associated with it (e.g., choosing item from list, opening an edit dialog for that type, or a gi.FileName from FileView), then that action is performed directly instead of opening the arg dialog. For example, a method taking a single gi.FileName arg (which has an associated special FileValueView type that opens the FileViewDialog to choose a filename) will directly open the dialog, which is the natural and immediate behavior one would expect. If your method has more than one method along with the filename, then the user can just click on the button to get the fileview dialog within the arg dialog that comes up, along with filling in the other args values. The bottom line is that if you need any kind of special gui selection tool etc for an arg, you should give it a special type (if it doesn't already have it) and then associate a ValueView with that, and copy the template from e.g., FileValueView in giv/filevalueview.go for supporting your type. It is very straightforward.

General Arg Properties

Here is an example specifying arg properties:

{"StdKeyMap", ki.Props{
	"desc": "sets StdKeyMapName to selected standard keymap and installs it as the current custom keymap, as a starting point for further customization.",
	"Args": ki.PropSlice{
		{"Map Name", ki.Props{
			"default-field": "StdKeyMapName",
		}},
	}},
},

The name of the arg property provides the label to show for the argument when it is prompted.

  • default: value -- provides a default initial value for the argument -- value is an interface{} -- could be anything that is assignable directly to the arg, using the kit.SetRobust method, which does a pretty good job of assigning anything to anything that is reasonable.
  • default-field: string -- name of field on struct val (the one with the method being called) that contains the value to use for default arg value.
  • value: value -- directly sets the value for this argument to the given value -- user is not prompted for this value, and if all such args are set, the method is run directly with these args (except if confirm flag is set).
  • desc: string -- provides a tooltip description of the argument that will show up when the user mouses over it -- good place to add arg-specific tips and help.
  • any other properties will be set as tag values for the value view for that arg, supporting all the Tags for special types, including, e.g.:
    • ext: string -- for gi.FileName type arg -- specifies the extension for the FileViewDialog -- if multiple, comma separated