StructBond Module

The StructBondModule submodule of PlutoExtras defines and exports functionality to easily create widgets for custom structure and combine multiple bonds together in a convenient floating side table.

Note

The StructBondModule is currently not re-exported by PlutoExtras so it has to be explicitly used with using PlutoExtras.StructBondModule

Open the structbond test notebook static html to see the look of the widgets exported.
Or open the related notebook directy in Pluto to check their functionality in action!

Note

The notebook must be run from the original folder (test/notebooks) within the PlutoExtras package folder to properly load the PlutoExtras package

StructBond

Generating automatic widgets for custom structs is quite straightforward with the aid of the @fielddata macro and the StructBond type.

The StructBond structure wraps another structure and generates a widget that can be used together with @bind to obtain instances of a custom structure. In order to correctly display the widget, the description and widget associated to each field of the structure must be specified either.

This can be done either using @fielddata as in the example video below or by using the separate @fieldbond and @fielddescription separately.

@NTBond

Sometimes custom structs are not needed and it would be useful to just use the same nice bond structure of StructBond to simply create arbitrary NamedTuples.

This is possible with the convenience macro @NTBond which can be called as shown below to create a nice display for an interactive bond creating an arbitrary NamedTuple.

The macro simply create a StructBond wrapping the desired NamedTuple type.

@BondsList

In some cases, one does not want to have a single bond wrapping either a Structure or a NamedTuple because single independent bonds are more convenient.

@BondsList is a convenience macro to create an object of type BondsList which simply allow to add a description to separate bonds and group them all together in a table-like format equivalent to those of StructBond.

Note

Unlike StructBond, a BondsList is already composed of bond created with @bind and it just groups them up with a description. The output of @BondsList is not supposed to be bound to a variable using @bind.
The bonds grouped in a BondsList still act and update independently from one another.

See the example below for understanding the synthax. The header of a BondsList is shown in an orange background to easily differentiate it from StructBond.

Popout/popoutwrap

The structures above can also be used nested within one another. To facilitate accessing nested structures, one can use the Popout type.

In its simple form, you can give an instance of a StructBond, a bond wrapping a StructBond or a BondsList as input to Popout to create a table that is hidden behind a popup window. If an instance present, but you want a custom type for which you have defined custom bonds and descriptions with @fielddata to appear as popout, you can use the function popoutwrap(TYPE) to generate a small icon which hides a popup containing the StructBond of the provided type TYPE.

The StructBond table appears on hover upon the icon, can be made fixed by clicking on the icon and can then be moved around or resized. A double click on the header of the popout hides it again:

The ability to also wrap pre-existing bonds around StructBonds is convenient for organizing the various bonds one have in a BondsList or BondTable

As an example, one can create a BondsList containing the two StructBond bonds generated at the beginning of this notebook (the videos in the structbond section above) like in the following example:

BondTable

The final convenience structure provided by this module is the BondTable. It can be created to group a list of bonds in a floating table that stays on the left side of the notebook (similar to the TableOfContents of PlutoUI) and can be moved around and resized or hidden for convenience.

The BondTable is intended to be used either with bonds containing StructBond or with BondsList. Future types with similar structure will also be added.

Here is an example of a bondtable containing all the examples seen so far.

API

Main

PlutoExtras.StructBondModule.StructBondType
StructBond(T;description = typedescription(T))

Create an HTML widget to be used with @bind from Pluto that allows to define the custom type T by assigning a widget to each of its fields. The widget will automatically use the docstring of each field as its description if present, or the fieldname otherwise.

When used with @bind, it automatically generates a instance of T by using the various fields as keyword arguments. *This means that the the structure T has to support a keyword-only contruction, such as those generated with Base.@kwdef or Parameters.@with_kw.

In order to work, the widget (and optionally the description) to associate to eachfield of type T has to be provided using the convenience macro @fielddata.

The optional description kwarg default to the Type name but can be overridden with anything showable as MIME"text/html"

See also: BondTable, @NTBond, @BondsList, Popout, popoutwrap, @fielddata, @fieldhtml, @typeasfield, @popoutasfield

source
PlutoExtras.StructBondModule.@fielddataMacro
@fielddata typename block

Convenience macro to define custom widgets for each field of typename. This is mostly inteded to be used in combintation with StructBond.

Given for example the following structure ASD, one can create a nice widget to create instances of type ASD wih the following code:

begin
Base.@kwdef struct ASD
	a::Int 
	b::Int
	c::String
	d::String
end
@fielddata ASD begin
	a = (md"Magical field with markdown description", Slider(1:10))
	b = (@htl("<span>Field with HTML description</span>"), Scrubbable(1:10))
	c = ("Normal String Description", TextField())
	d = TextField()
end
@bind asd StructBond(ASD)
end

where asd will be an instance of type ASD with each field interactively controllable by the specified widgets and showing the field description next to each widget. The rightside argument of each :(=) in the block can either be a single element or a tuple of 2 elements. In case a single elemnent is provided, the provided value is interpreted as the fieldbond, so the bond/widget to show for that field. If two elements are given, the first is assigned to the description and the second as the bond to show

See also: BondTable, StructBond, @NTBond, Popout, popoutwrap, @fieldbond, @fielddescription, @fieldhtml, @typeasfield, @popoutasfield

source
PlutoExtras.StructBondModule.@NTBondMacro
@NTBond description block

Convenience macro to create a StructBond wrapping a NamedTuple with field names provided in the second argument block.

Useful when one wants a quick way of generating a bond that creates a NamedTuple. An example usage is given in the code below:

@bind nt @NTBond "My Fancy NTuple" begin
	a = ("Description", Slider(1:10))
	b = (md"*Bold* field", Slider(1:10))
	c = Slider(1:10) # No description, defaults to the name of the field
end

which will create a NamedTuple{(:a, :b, :c)} and assign it to variable nt.

See also: BondTable, @NTBond, @BondsList, Popout, popoutwrap, @fielddata, @fieldhtml, @typeasfield, @popoutasfield

source
PlutoExtras.StructBondModule.@BondsListMacro
@BondsList description block

Convenience macro to create a BondsList, which is a grouping of a various bonds (created with @bind) inside a table-like HTML output that can be used inside BondTable. Each bond can additionally be associated to a custom description. The block given as second input to this macro must be a begin or let block where each line is an assignment of the type description = bond. The description can be anything that has a show method for MIME type text/html.

An example usage is given in the code below:

@BondsList "My Group of Bonds" let tv = PlutoUI.Experimental.transformed_value
	 # We use transformed_value to translate GHz to Hz in the bound variable `freq`
	"Frequency [GHz]" = @bind freq tv(x -> x * 1e9, Slider(1:10))
	md"Altitude ``h`` [m]" = @bind alt Scrubbable(100:10:200)
end

which will create a table-like display grouping together the bonds for the frequency freq and the altitude alt.

Unlike StructBond, the output of @BondsList is not supposed to be bound using @bind, as it just groups pre-existing bonds. Also unlike StructBond, each row of a BondsList upates its corresponding bond independently from the other rows.

To help identify and differentiate a BondsList from a StructBond

See also: BondTable, @NTBond, StructBond, Popout, popoutwrap, @fielddata, @fieldhtml, @typeasfield, @popoutasfield

source
PlutoExtras.StructBondModule.popoutwrapFunction
popoutwrap(T)

Convenience function to construct a Popout wrapping a StructBond of type T. This is convenient when one wants to create nested StructBond types.

Given for example the following two structures

Base.@kwdef struct ASD
	a::Int 
	b::Int
	c::String
end
Base.@kwdef struct LOL
	asd::ASD 
	text::String
end

one can create a nice widget to create instances of type LOL that also include a popout of widget generating ASD wih the following code:

# Define the widget for ASD
@fieldbond ASD begin
	a = Slider(1:10)
	b = Scrubbable(1:10)
	c = TextField()
end
@fielddescription ASD begin
	a = md"Magical field with markdown description"
	b = @htl "<span>Field with HTML description</span>"
	c = "Normal String Description"
end

# Define the widget for LOL
@fieldbond LOL begin
	asd = popoutwrap(ASD)
	text = TextField(;default = "Some Text")
end
@fielddescription LOL begin
	asd = "Click on the icon to show the widget to generate this field"
	text = "Boring Description"
end
@bind lol StructBond(LOL)

where lol will be an instance of type LOL with each field interactively controllable by the specified widgets and showing the field description next to each widget.

See also: BondTable, StructBond, Popout, @fieldbond, @fielddescription, @fieldhtml, @typeasfield, @popoutasfield

source

Secondary/Advanced

PlutoExtras.StructBondModule.@fieldbondMacro
@fieldbond typename block

Convenience macro to define custom widgets for each field of typename. This is mostly inteded to be used in combintation with StructBond.

Given for example the following structure

Base.@kwdef struct ASD
	a::Int 
	b::Int
	c::String
end

one can create a nice widget to create instances of type ASD wih the following code:

@fieldbond ASD begin
	a = Slider(1:10)
	b = Scrubbable(1:10)
	c = TextField()
end
@fielddescription ASD begin
	a = md"Magical field with markdown description"
	b = @htl "<span>Field with HTML description</span>"
	c = "Normal String Description"
end
@bind asd StructBond(ASD)

where asd will be an instance of type ASD with each field interactively controllable by the specified widgets and showing the field description next to each widget.

See also: BondTable, StructBond, Popout, popoutwrap, @fielddescription, @fieldhtml, @typeasfield, @popoutasfield

source
PlutoExtras.StructBondModule.@fielddescriptionMacro
@fielddescription typename block

Convenience macro to define custom descriptions for the widgets of each field of typename. This is mostly inteded to be used in combintation with StructBond.

Given for example the following structure

Base.@kwdef struct ASD
	a::Int 
	b::Int
	c::String
end

one can create a nice widget to create instances of type ASD wih the following code:

@fieldbond ASD begin
	a = Slider(1:10)
	b = Scrubbable(1:10)
	c = TextField()
end
@fielddescription ASD begin
	a = md"Magical field with markdown description"
	b = @htl "<span>Field with HTML description</span>"
	c = "Normal String Description"
end
@bind asd StructBond(ASD)

where asd will be an instance of type ASD with each field interactively controllable by the specified widgets and showing the field description next to each widget.

See also: BondTable, StructBond, Popout, popoutwrap, @fieldbond, @fieldhtml, @typeasfield, @popoutasfield

source
PlutoExtras.StructBondModule.PopoutType
Popout(T)

Create an HTML widget wrapping the widget T and showing it either on hover or upon click.

This is useful to generat widgets to be used with StructBond for custom fields whose types are custom Types.

The convenience function popoutwrap can be used to directly create a Popup of a StructBond{T} to facilitate nested StructBond views.

See also: BondTable, StructBond, popoutwrap, @fieldbond, @fielddescription, @fieldhtml, @typeasfield, @popoutasfield

source
PlutoExtras.StructBondModule.@popoutasfieldMacro
@popoutasfield T
@popoutasfield T1 T2 ...

This macro will make the default widget for fields of type T a Popout wrapping a StructBond{T} type. For this to work, the StructBond{T} must have a default widget associated to each of its field, either by using @fieldbond or @typeasfield

Example (in Pluto)

# ╔═╡ 8db82e94-5c81-4c52-9228-7e22395fb68f
using PlutoExtras.StructBondModule

# ╔═╡ 86a80228-f495-43e8-b1d4-c93b7b52c8d8
begin
	@kwdef struct MAH
		a::Int
	end
	@kwdef struct BOH
		mah::MAH
	end
	
	# This will make the default widget for an Int a Slider
	@typeasfield Int = Slider(1:10)
	# This will make the default widget for fields of type ASD a popout that wraps a StructBond{ASD}
	@popoutasfield MAH
	
	@bind boh StructBond(BOH)
end

# ╔═╡ 2358f686-1950-40f9-9d5c-dac2d98f4c24
boh === BOH(MAH(1))
source
PlutoExtras.StructBondModule.@typeasfieldMacro
@typeasfield T = Widget
@typeasfield begin
	T1 = Widget1
	T2 = Widget2
	...
end

Macro to give a default widget for a specific type T, T1, or T2. This can be over-ridden by specifying a more specific default for a custom type using @fieldbond When a custom type is wrapped inside a StructBond and a custom widget for one of its field is not defined, the show method will use the one defined by this macro for the field type.

Examples

The following julia code will error because a default widget is not defined for field a

using PlutoExtras.StructBondModule
struct ASD 
	a::Int
end
StructBond(ASD)

Apart from defining a specific value for ASD with @fieldbond, one can also define a default widget for Int with:

@typeasfield Int = Slider(1:10)

Now calling StructBond(ASD) will not error and will default to showing a Slider(1:10) as bond for field a of ASD.

source