Skip to content

Configuration

George Joseph edited this page Apr 11, 2021 · 7 revisions

Introduction

The dueui_config.json file is organized as a tree of "elements". Not to be confused with HTML elements, a DueUI element is either a container such as a "panel" or a "widget" such as a "button".

In DueUI 3.x, although the configuration file has the ".json" file suffix, it's actually a full-fledged Javascsript script. The UI layout is contained in a class named DueUIConfig which can contain not only layout settings but actual code as well.

New in DueUI 3.2.0 is the ability to specify DueUI settings like the Duet hostname, password, theme, etc. in the dueui_config.json file. It's contained in an object named DueUISettings and looks like the following:

configFileSettings = {
	duet_host: "<your_duet_or_DSF_address>",
	duet_password: "reprap",
	duet_poll_interval_1: 500,
	duet_debug_polling_enabled: 0,
	dueui_settings_dont_send_gcode: 0,
	dueui_test_mode: 0,
	duet_polling_enabled: 0,
	hide_settings: 0,
	theme_name: "Darkly"
};

class DueUIConfig {
 ...
}

You don't need to specify all of the settings, just the ones you want changed from the defaults. See the Settings page for more info on these settings.

Functions, Templates, and Constants

One of the new features this enables is the capability of creating functions, templates and constants for things you use often. For instance, I have an axis "position" widget on 3 different pages that are formatted exactly the same. Only the "id" and the screen "position" attributes differ. Here's an example of how I do that:

class DueUIConfig {

// Define all the common stuff in a variable named "axis_position"
	axes_position = {
		"type": "position",
		"style": {
			"width": "15ch",
			"margin": "5px",
		},
		"button_defaults": {
			"style": {
				"height": "2.5em",
				"margin": "5px"
			},
			"state": {
				"states": [
					{"state": false, "classes": "btn-warning"},
					{"state": true, "classes": "btn-success"}
				]
			}
		},
		"direction": "column",
		"axes": [
			{"label": "X:  ", "gcode_axis": "X",
				"position_field": "${state.move.axes[0].machinePosition.toFixed(3).padStart(7)}",
				"state_field": "${state.move.axes[0].homed}"
			},
			{"label": "Y:  ", "gcode_axis": "Y",
				"position_field": "${state.move.axes[1].machinePosition.toFixed(3).padStart(7)}",
				"state_field": "${state.move.axes[1].homed}"
			},
			{"label": "Z:  ", "gcode_axis": "Z",
				"position_field": "${state.move.axes[2].machinePosition.toFixed(3).padStart(7)}",
				"state_field": "${state.move.axes[2].homed}"
			},
		]
	};

	dueui_content = {
		"id": "dueui",
		"type": "tabbed_panel",
		// yada yada
		
		// The "Main" tab
		element_configs = [
			extendObject(this.axis_position, {
			"id": "position_widget_Home",
			"position": {
				"my": "left top",
				"at": "left bottom",
				"of": "#some_other_widget_on_the Home_tab"
			}),
		];
		
		// The "Movement" tab
		element_configs = [
			extendObject(this.axis_position, {
			"id": "position_widget_Movement",
			"position": {
				"my": "left top",
				"at": "left bottom",
				"of": "#some_other_widget_on_the Movement_tab"
			}),
		];
	};
}

At the top-level, we've defined a variable that contains all of the common stuff needed for a "position" widget. Notice it's missing the "id" and screen "position" attributes.

When we want to create an actual position widget, we use extendObject which is a helper function that does a deep clone of the first parameter, in this case, this.axis_position, and merges the second argument on top of it. The result is a new object with the id and position attributes applied.

Let's take another simple example...

class DueUIConfig {

	MyButtonStyle = {
		"height": "50px",
		"width": "100px",
		"padding": "5px"
	};
	
	///////
	
	{
		"type": "button",
		"style": this.MyButtonStyle,
	}
}

If you have lots of buttons that you want styled the same way, this is an easy way to share the style parameters. It also allows you to make changes in MyButtonStyle that are automatically applied to all the buttons that use it.

Here's an example of a function that you can use in your config:

class DueUIConfig {
	calculateLayers(state) {
		let rtn = "";
		if (state.state.status == 'idle' || state.job.file.height == 0) {
			rtn += "0/";
		} else {
			rtn += ((state.move.axes[2].machinePosition / state.job.file.height) * state.job.file.numLayers).toFixed(0) + "/";
		}

		if (state.job.file.numLayers != null) {
			rtn += state.job.file.numLayers;
		} else {
			rtn += "0";
		}
		return rtn;
	}
	
	...
	
		{
			"id": "bylayer",
			"type": "button",
			"classes": "btn-primary",
			"style": {
				"text-align": "right",
				"width": "10ch"
			},
			"read_only": true,
			"value": "${DueUIConfig.calculateLayers(state)}",
			"position": {
				"my": "left top",
				"at": "left bottom+8",
				"of": "#byfilament"
			}
		},
	

Early on in the development of the Duet Software Framework, the ability to retrieve the currently printing layer was missing. I had to create a function to calculate the layer based on the total height of the print, the total number of layers, and the current Z position. By adding this function to the top of DueUIConfig, I was able to reference it in a button further down in the config.

Things to note:

  • You can only reference top-level objects. One parameter in dueui_contents cannot reference another parameter in dueui_contents. This is a Javascript thing.
  • All references must start with "this." with "this" being the DueUIConfig class.

Referencing Printer State

You'll have noticed many config references like "${state...}". This is how you reference the current state of the printer. See Printer State for more information

IDs

Every config element in the dueui_contents object needs an "id". If you don't supply one, one will be automatically generated. BUT if you'll need to reference this element later in your config, you must give it an id yourself.

When you assign an id to an element you should use only a combination of letters, numbers and the '_' character. There are other valid characters but to be safe, use only these. When you reference an element by id, you must ALWAYS prefix it with the '#' character.

Examnple:

{
	/* The assignment */
	"id": "mybutton",
	"type": "button"
},

{
	"id": "some_other_element",
	"position": {
		"my": "left top",
		"at": "right+10 top",
		/* A reference to the "mybutton" button */ 
		"of": "#mybutton"
	}
}

Config Order and Position

The config file is parsed and the elements drawn top to bottom. For this reason, if you reference another element in a "position" object, that other element MUST be defined before the one that's referencing it. In the above example, if "mybutton" isn't already defined, "some_other_element" won't be able to position itself and will fail.

Sample Configs

dueui_config_default

Problems

If your config file fails to load, the easiest way to figure out where the issue is is by opening your browser's debugger (in Chrome it's ctrl-shift-I) then reloading the page. You'll probably see something like:

Notice the line that has Unexpected token '{'? Off to the right there's a field that tells you where the error was: VM34462:28. The VM number will probably be different for you but the :28 tells you that it was line 28 where the problem was encountered. You should be able to click on that "VM" link and get the config file showing the error.

Clone this wiki locally