Developing A Script Console

Introduction

  • The following example shows how QML was used to prototype a simple JavaScript console.

  • The resulting tool can be used to experiment with scripting in SEQUOIA.

  • It can also be extended further with more advanced features.

The Full Code

  • Here is the source code of the script:

import QtQuick 2.3

import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.3
import QtQuick.Layouts 1.0

import Thinkbox.Sequoia.Nodes 1.0
import Thinkbox.Sequoia.Documents 1.0
import Thinkbox.Sequoia.Conversion 1.0

Rectangle {
        width: 600
        height: 400
        color: "#41485B"
        property string consoleEchoString: "//Welcome to the Sequoia JavaScript Console!\n//Please type your code in the bottom pane, then press EVALUATE...\n"

        GroupBox {
                anchors.fill: parent
                ColumnLayout {
                        anchors.top: parent.top
                        anchors.left: parent.left
                        anchors.right: parent.right
                        anchors.bottom: parent.bottom

                        Button {
                                id: clearEchoButton

                                Layout.fillWidth: true
                                text: "CLEAR Console Echo..."

                                onClicked: {
                                        consoleEchoString = consoleOutputArea.text = ""
                                }
                                enabled: true
                        }

                        TextArea  {
                                id: consoleOutputArea
                                height:100
                                text: consoleEchoString
                                Layout.fillWidth: true
                                style: TextAreaStyle {
                                        backgroundColor: "#2D374D"
                                        selectionColor: "#578ED6"
                                        textColor: "#FFFFFF"
                                }
                                readOnly : true
                        }
                        Button {
                                id: evaluateScriptButton
                                Layout.fillWidth: true
                                text: "EVALUATE Console Script:"

                                onClicked: {
                                        var stringToEval = consoleTextArea.text
                                        stringToEval = stringToEval.replace(/LOG/, "console.log")

                                        stringToEval = stringToEval.replace(/GNP/, "NodeControl.getNodeProperty")
                                        stringToEval = stringToEval.replace(/SNP/, "NodeControl.setNodeProperty")

                                        stringToEval = stringToEval.replace(/NC/, "NodeCreation")
                                        stringToEval = stringToEval.replace(/CPL/, "NodeCreation.createPointLoader")
                                        stringToEval = stringToEval.replace(/CROI/, "NodeCreation.createPointROI")
                                        stringToEval = stringToEval.replace(/CMK/, "NodeCreation.createMarker")
                                        stringToEval = stringToEval.replace(/CML/, "NodeCreation.createMeshLoader")
                                        stringToEval = stringToEval.replace(/CM/, "NodeCreation.createMesher")
                                        stringToEval = stringToEval.replace(/CIP/, "NodeCreation.createImageProjection")
                                        stringToEval = stringToEval.replace(/CSP/, "NodeCreation.createPointSurface")

                                        stringToEval = stringToEval.replace(/DC/, "DocumentControl")
                                        stringToEval = stringToEval.replace(/GCD/, "DocumentControl.getCurrentDocument")


                                        eval (stringToEval)

                                        consoleEchoString += stringToEval + "\n\n"
                                        consoleTextArea.text = ""
                                        consoleOutputArea.text = consoleEchoString
                                }
                        }
                        TextArea  {
                                id: consoleTextArea
                                height:100
                                text: ""
                                Layout.fillWidth: true
                                Layout.fillHeight: true
                                style: TextAreaStyle {
                                        backgroundColor: "#2D2D37"
                                        selectionColor: "#578ED6"
                                        textColor: "#FFFFFF"
                                }
                        }
                }
        }
}

Step By Step

  • Now let’s look at the various code blocks of this script.

Importing QML Modules

  • For the design and setup of the Qt User Interface, we will need to import the modules for

    • QML itself

    • QML Controls

    • QML Control Styles

    • QML Layouts

import QtQuick 2.3

import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.3
import QtQuick.Layouts 1.0

Importing Thinkbox Sequoia Module

  • To be able to access Sequoia-related methods, we need to also import all Sequoia modules:

import Thinkbox.Sequoia.Nodes 1.0
import Thinkbox.Sequoia.Documents 1.0
import Thinkbox.Sequoia.Conversion 1.0

Dialog Frame

  • We define the dialog as a rectangle of 600x400 pixels.

  • We set the color to the default SEQUOIA dark gray-blue color.

  • We define a string property called consoleEchoString - it will be used to store the content of the top pane:

Rectangle {
        width: 600
        height: 400
        color: "#41485B"
        property string consoleEchoString: "//Welcome to the Sequoia JavaScript Console!\n//Please type your code in the bottom pane, then press EVALUATE...\n"

Group Box

  • Inside the dialog, we will define a group box filling the Rectangle.

  • Then we create a column layout - it will be achored on all 4 sides to the Rectangle and thus resize with it.

  • A column layout creates a column with rows of controls stacked vertically:

GroupBox {
        anchors.fill: parent
        ColumnLayout {
                anchors.top: parent.top
                anchors.left: parent.left
                anchors.right: parent.right
                anchors.bottom: parent.bottom

Clear Console Echo Button

  • We define a button with id clearEchoButton which will be used to clear the top pane when pressed.

  • The button wlll have the width of the group box.

  • Its caption will be “CLEAR Console Echo…”

  • When clicked, it will simply set the property consoleEchoString of the Rectangle, as well as the text area object representing the top pane, to an empty string.

Button {
        id: clearEchoButton

        Layout.fillWidth: true
        text: "CLEAR Console Echo..."

        onClicked: {
                consoleEchoString = consoleOutputArea.text = ""
        }
        enabled: true
}

Echo Pane

  • Next we define a text area control with id consoleOutputArea.

  • This control will be read-only and will show the consoleEchoString property we defined in the beginning as the script.

  • The height of the control is 100 pixels, and the width will fit the width of the parent control.

  • The style sets the background, selection and text colors to match the typical SEQUOIA UI scheme.

TextArea  {
        id: consoleOutputArea
        height:100
        text: consoleEchoString
        Layout.fillWidth: true
        style: TextAreaStyle {
                backgroundColor: "#2D374D"
                selectionColor: "#578ED6"
                textColor: "#FFFFFF"
        }
        readOnly : true
}

EVALUATE Console Script button

  • This is the button that will execute the script entered in the bottom pane.

  • It will have the id evaluateScriptButton and will fit the width of its parent.

Button {
        id: evaluateScriptButton
        Layout.fillWidth: true
        text: "EVALUATE Console Script:"

The Evaluate Button Clicked Event

  • Now let’s look at the code that should be executed when the button is pressed.

  • The event contains JavaScript code that

    • Takes the text entered in the bottom pane,

    • Filters it to expand some “macros”,

    • Evaluates it,

    • Appends it to consoleEchoString property where all previous scripts are preserved

    • Resets the bottom pane

    • Updates the top pane with the new consoleEchoString content.

  • Most SEQUOIA methods are pretty long and require a lot of typing.

  • For example, DocumentControl.getCurrentDocument needs to be entered each time you want to know what Document is active.

  • To reduce the amount of code to be typed in the bottom pane, the console implements a few custom “macros” that expand to full functions.

  • For example, typing just GCD() results in DocumentControl.getCurrentDocument() executing and appearing in the Echo top pane!

  • The multiple replace calls below make sure often used methods have fast-to-enter and easy-to-remember two or three-letter macros.

        onClicked: {
                var stringToEval = consoleTextArea.text
                stringToEval = stringToEval.replace(/LOG/, "console.log")

                stringToEval = stringToEval.replace(/GNP/, "NodeControl.getNodeProperty")
                stringToEval = stringToEval.replace(/SNP/, "NodeControl.setNodeProperty")

                stringToEval = stringToEval.replace(/NC/, "NodeCreation")
                stringToEval = stringToEval.replace(/CPL/, "NodeCreation.createPointLoader")
                stringToEval = stringToEval.replace(/CROI/, "NodeCreation.createPointROI")
                stringToEval = stringToEval.replace(/CMK/, "NodeCreation.createMarker")
                stringToEval = stringToEval.replace(/CML/, "NodeCreation.createMeshLoader")
                stringToEval = stringToEval.replace(/CM/, "NodeCreation.createMesher")
                stringToEval = stringToEval.replace(/CIP/, "NodeCreation.createImageProjection")
                stringToEval = stringToEval.replace(/CSP/, "NodeCreation.createPointSurface")

                stringToEval = stringToEval.replace(/DC/, "DocumentControl")
                stringToEval = stringToEval.replace(/GCD/, "DocumentControl.getCurrentDocument")


                eval (stringToEval)

                consoleEchoString += stringToEval + "\n\n"
                consoleTextArea.text = ""
                consoleOutputArea.text = consoleEchoString
        }
}

Bottom Pane

  • The last

TextArea  {
        id: consoleTextArea
        height:100
        text: ""
        Layout.fillWidth: true
        Layout.fillHeight: true
        style: TextAreaStyle {
                backgroundColor: "#2D2D37"
                selectionColor: "#578ED6"
                textColor: "#FFFFFF"
        }
}
  • The braces below just close the scopes of the column layout, group box, and Rectangle:

                }
        }
}