Widget Classes

See the Qt Widgets guide for an introduction and usage examples.

Vec2Widget

Bases: QFrame

A widget for displaying and editing a Vec3 object.

Source code in ncca/ngl/widgets/vec2widget.py
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
class Vec2Widget(QFrame):
    """A widget for displaying and editing a Vec3 object."""

    valueChanged = Signal(Vec2)
    xValueChanged = Signal(float)
    yValueChanged = Signal(float)

    def __init__(
        self,
        parent: QWidget | None = None,
        name: str = "",
        value: Vec2 = Vec2(0.0, 0.0),
    ) -> None:
        """Initialize the widget.

        Args:
        name: The name of the widget.
        value: The initial value of the widget.
        parent: The parent widget.
        """
        super().__init__(parent)
        self.setFrameShape(QFrame.Shape.StyledPanel)
        self._value = value
        self._name = name
        layout = QHBoxLayout()

        self.x_spinbox = self._create_spinbox(self._value.x)
        self.y_spinbox = self._create_spinbox(self._value.y)

        self._label = QLabel(self._name)
        layout.addWidget(self._label)
        layout.addWidget(self.x_spinbox)
        layout.addWidget(self.y_spinbox)
        self.setLayout(layout)

    def _create_spinbox(self, value: float) -> QDoubleSpinBox:
        """Helper method to create and configure a QDoubleSpinBox.

        Args:
            value: The initial value of the spinbox.

        Returns:
            A configured QDoubleSpinBox.
        """
        spinbox = QDoubleSpinBox()
        spinbox.setValue(value)
        spinbox.setRange(-5.0, 5.0)
        spinbox.setSingleStep(0.01)
        spinbox.valueChanged.connect(self._on_value_changed)
        return spinbox

    def get_value(self) -> Vec2:
        """Get the value described below.

        Returns:
        The current value of the widget.
        """
        return self._value

    def _on_value_changed(self, value: float) -> None:
        """This slot is called when the value of a spinbox changes.

        Args:
            value: The new value of the spinbox.
        """
        sender = self.sender()
        if sender == self.x_spinbox:
            self._value.x = value
            self.xValueChanged.emit(value)
        elif sender == self.y_spinbox:
            self._value.y = value
            self.yValueChanged.emit(value)
        # emit the Vec2 value changed signal
        self.valueChanged.emit(self._value)

    def set_value(self, value: Vec2) -> None:
        """Sets the value of the widget.

        Args:
            value: The new value of the widget.
        """
        with QSignalBlocker(self.x_spinbox), QSignalBlocker(self.y_spinbox):
            self.x_spinbox.setValue(value.x)
            self.y_spinbox.setValue(value.y)
        self._value = value
        self.valueChanged.emit(self._value)

    def get_name(self) -> str:
        """Get the value described below.

        Returns:
        The name of the widget.
        """
        return self._name

    def set_range(self, min_val: float, max_val: float) -> None:
        """Sets the range for all spinboxes.

        Args:
            min_val: The minimum value.
            max_val: The maximum value.
        """
        for spinbox in (self.x_spinbox, self.y_spinbox):
            spinbox.setRange(min_val, max_val)

    def set_x_range(self, min_val: float, max_val: float) -> None:
        """Sets the range for the x spinbox.

        Args:
            min_val: The minimum value.
            max_val: The maximum value.
        """
        self.x_spinbox.setRange(min_val, max_val)

    def set_y_range(self, min_val: float, max_val: float) -> None:
        """Sets the range for the y spinbox.

        Args:
            min_val: The minimum value.
            max_val: The maximum value.
        """
        self.y_spinbox.setRange(min_val, max_val)

    def set_single_step(self, step: float) -> None:
        """Sets the single step for all spinboxes.

        Args:
            step: The single step value.
        """
        for spinbox in (self.x_spinbox, self.y_spinbox):
            spinbox.setSingleStep(step)

    def set_name(self, name: str) -> None:
        """Sets the name of the widget.

        Args:
            name: The new name of the widget.
        """
        self._name = name
        self._label.setText(name)

    value = Property(Vec2, get_value, set_value)
    name = Property(str, get_name, set_name)

__init__(parent=None, name='', value=Vec2(0.0, 0.0))

Initialize the widget.

Args: name: The name of the widget. value: The initial value of the widget. parent: The parent widget.

Source code in ncca/ngl/widgets/vec2widget.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
def __init__(
    self,
    parent: QWidget | None = None,
    name: str = "",
    value: Vec2 = Vec2(0.0, 0.0),
) -> None:
    """Initialize the widget.

    Args:
    name: The name of the widget.
    value: The initial value of the widget.
    parent: The parent widget.
    """
    super().__init__(parent)
    self.setFrameShape(QFrame.Shape.StyledPanel)
    self._value = value
    self._name = name
    layout = QHBoxLayout()

    self.x_spinbox = self._create_spinbox(self._value.x)
    self.y_spinbox = self._create_spinbox(self._value.y)

    self._label = QLabel(self._name)
    layout.addWidget(self._label)
    layout.addWidget(self.x_spinbox)
    layout.addWidget(self.y_spinbox)
    self.setLayout(layout)

get_name()

Get the value described below.

Returns: The name of the widget.

Source code in ncca/ngl/widgets/vec2widget.py
 96
 97
 98
 99
100
101
102
def get_name(self) -> str:
    """Get the value described below.

    Returns:
    The name of the widget.
    """
    return self._name

get_value()

Get the value described below.

Returns: The current value of the widget.

Source code in ncca/ngl/widgets/vec2widget.py
60
61
62
63
64
65
66
def get_value(self) -> Vec2:
    """Get the value described below.

    Returns:
    The current value of the widget.
    """
    return self._value

set_name(name)

Sets the name of the widget.

Parameters:
  • name (str) –

    The new name of the widget.

Source code in ncca/ngl/widgets/vec2widget.py
141
142
143
144
145
146
147
148
def set_name(self, name: str) -> None:
    """Sets the name of the widget.

    Args:
        name: The new name of the widget.
    """
    self._name = name
    self._label.setText(name)

set_range(min_val, max_val)

Sets the range for all spinboxes.

Parameters:
  • min_val (float) –

    The minimum value.

  • max_val (float) –

    The maximum value.

Source code in ncca/ngl/widgets/vec2widget.py
104
105
106
107
108
109
110
111
112
def set_range(self, min_val: float, max_val: float) -> None:
    """Sets the range for all spinboxes.

    Args:
        min_val: The minimum value.
        max_val: The maximum value.
    """
    for spinbox in (self.x_spinbox, self.y_spinbox):
        spinbox.setRange(min_val, max_val)

set_single_step(step)

Sets the single step for all spinboxes.

Parameters:
  • step (float) –

    The single step value.

Source code in ncca/ngl/widgets/vec2widget.py
132
133
134
135
136
137
138
139
def set_single_step(self, step: float) -> None:
    """Sets the single step for all spinboxes.

    Args:
        step: The single step value.
    """
    for spinbox in (self.x_spinbox, self.y_spinbox):
        spinbox.setSingleStep(step)

set_value(value)

Sets the value of the widget.

Parameters:
  • value (Vec2) –

    The new value of the widget.

Source code in ncca/ngl/widgets/vec2widget.py
84
85
86
87
88
89
90
91
92
93
94
def set_value(self, value: Vec2) -> None:
    """Sets the value of the widget.

    Args:
        value: The new value of the widget.
    """
    with QSignalBlocker(self.x_spinbox), QSignalBlocker(self.y_spinbox):
        self.x_spinbox.setValue(value.x)
        self.y_spinbox.setValue(value.y)
    self._value = value
    self.valueChanged.emit(self._value)

set_x_range(min_val, max_val)

Sets the range for the x spinbox.

Parameters:
  • min_val (float) –

    The minimum value.

  • max_val (float) –

    The maximum value.

Source code in ncca/ngl/widgets/vec2widget.py
114
115
116
117
118
119
120
121
def set_x_range(self, min_val: float, max_val: float) -> None:
    """Sets the range for the x spinbox.

    Args:
        min_val: The minimum value.
        max_val: The maximum value.
    """
    self.x_spinbox.setRange(min_val, max_val)

set_y_range(min_val, max_val)

Sets the range for the y spinbox.

Parameters:
  • min_val (float) –

    The minimum value.

  • max_val (float) –

    The maximum value.

Source code in ncca/ngl/widgets/vec2widget.py
123
124
125
126
127
128
129
130
def set_y_range(self, min_val: float, max_val: float) -> None:
    """Sets the range for the y spinbox.

    Args:
        min_val: The minimum value.
        max_val: The maximum value.
    """
    self.y_spinbox.setRange(min_val, max_val)

Vec3Widget

Bases: QFrame

A widget for displaying and editing a Vec3 object.

Source code in ncca/ngl/widgets/vec3widget.py
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
class Vec3Widget(QFrame):
    """A widget for displaying and editing a Vec3 object."""

    valueChanged = Signal(Vec3)
    xValueChanged = Signal(float)
    yValueChanged = Signal(float)
    zValueChanged = Signal(float)

    def __init__(
        self,
        parent: QWidget | None = None,
        name: str = "",
        value: Vec3 = Vec3(0.0, 0.0, 0.0),
    ) -> None:
        """Initialize the widget.

        Args:
        name: The name of the widget.
        value: The initial value of the widget.
        parent: The parent widget.
        """
        super().__init__(parent)
        self.setFrameShape(QFrame.Shape.StyledPanel)
        self._value = value

        self._name = name
        layout = QHBoxLayout()

        self.x_spinbox = self._create_spinbox(self._value.x)
        self.y_spinbox = self._create_spinbox(self._value.y)
        self.z_spinbox = self._create_spinbox(self._value.z)

        self._label = QLabel(self._name)
        layout.addWidget(self._label)
        layout.addWidget(self.x_spinbox)
        layout.addWidget(self.y_spinbox)
        layout.addWidget(self.z_spinbox)
        self.setLayout(layout)

    def _create_spinbox(self, value: float) -> QDoubleSpinBox:
        """Helper method to create and configure a QDoubleSpinBox.

        Args:
            value: The initial value of the spinbox.

        Returns:
            A configured QDoubleSpinBox.
        """
        spinbox = QDoubleSpinBox()
        spinbox.setValue(value)
        spinbox.setRange(-5.0, 5.0)
        spinbox.setSingleStep(0.01)
        spinbox.valueChanged.connect(self._on_value_changed)
        return spinbox

    def get_value(self) -> Vec3:
        """Get the value described below.

        Returns:
        The current value of the widget.
        """
        return self._value

    def _on_value_changed(self, value: float) -> None:
        """This slot is called when the value of a spinbox changes.

        Args:
            value: The new value of the spinbox.
        """
        sender = self.sender()
        if sender == self.x_spinbox:
            self._value.x = value
            self.xValueChanged.emit(value)
        elif sender == self.y_spinbox:
            self._value.y = value
            self.yValueChanged.emit(value)
        elif sender == self.z_spinbox:
            self._value.z = value
            self.zValueChanged.emit(value)
        # emit the Vec3 value changed signal
        self.valueChanged.emit(self._value)

    def set_value(self, value: Vec3) -> None:
        """Sets the value of the widget.

        Args:
            value: The new value of the widget.
        """
        with (
            QSignalBlocker(self.x_spinbox),
            QSignalBlocker(self.y_spinbox),
            QSignalBlocker(self.z_spinbox),
        ):
            self.x_spinbox.setValue(value.x)
            self.y_spinbox.setValue(value.y)
            self.z_spinbox.setValue(value.z)
        self._value = value
        self.valueChanged.emit(self._value)

    def get_name(self) -> str:
        """Get the value described below.

        Returns:
        The name of the widget.
        """
        return self._name

    def set_range(self, min_val: float, max_val: float) -> None:
        """Sets the range for all spinboxes.

        Args:
            min_val: The minimum value.
            max_val: The maximum value.
        """
        for spinbox in (self.x_spinbox, self.y_spinbox, self.z_spinbox):
            spinbox.setRange(min_val, max_val)

    def set_x_range(self, min_val: float, max_val: float) -> None:
        """Sets the range for the x spinbox.

        Args:
            min_val: The minimum value.
            max_val: The maximum value.
        """
        self.x_spinbox.setRange(min_val, max_val)

    def set_y_range(self, min_val: float, max_val: float) -> None:
        """Sets the range for the y spinbox.

        Args:
            min_val: The minimum value.
            max_val: The maximum value.
        """
        self.y_spinbox.setRange(min_val, max_val)

    def set_z_range(self, min_val: float, max_val: float) -> None:
        """Sets the range for the z spinbox.

        Args:
            min_val: The minimum value.
            max_val: The maximum value.
        """
        self.z_spinbox.setRange(min_val, max_val)

    def set_single_step(self, step: float) -> None:
        """Sets the single step for all spinboxes.

        Args:
            step: The single step value.
        """
        for spinbox in (self.x_spinbox, self.y_spinbox, self.z_spinbox):
            spinbox.setSingleStep(step)

    def set_name(self, name: str) -> None:
        """Sets the name of the widget.

        Args:
            name: The new name of the widget.
        """
        self._name = name
        self._label.setText(name)

    value = Property(Vec3, get_value, set_value)
    name = Property(str, get_name, set_name)

__init__(parent=None, name='', value=Vec3(0.0, 0.0, 0.0))

Initialize the widget.

Args: name: The name of the widget. value: The initial value of the widget. parent: The parent widget.

Source code in ncca/ngl/widgets/vec3widget.py
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
def __init__(
    self,
    parent: QWidget | None = None,
    name: str = "",
    value: Vec3 = Vec3(0.0, 0.0, 0.0),
) -> None:
    """Initialize the widget.

    Args:
    name: The name of the widget.
    value: The initial value of the widget.
    parent: The parent widget.
    """
    super().__init__(parent)
    self.setFrameShape(QFrame.Shape.StyledPanel)
    self._value = value

    self._name = name
    layout = QHBoxLayout()

    self.x_spinbox = self._create_spinbox(self._value.x)
    self.y_spinbox = self._create_spinbox(self._value.y)
    self.z_spinbox = self._create_spinbox(self._value.z)

    self._label = QLabel(self._name)
    layout.addWidget(self._label)
    layout.addWidget(self.x_spinbox)
    layout.addWidget(self.y_spinbox)
    layout.addWidget(self.z_spinbox)
    self.setLayout(layout)

get_name()

Get the value described below.

Returns: The name of the widget.

Source code in ncca/ngl/widgets/vec3widget.py
108
109
110
111
112
113
114
def get_name(self) -> str:
    """Get the value described below.

    Returns:
    The name of the widget.
    """
    return self._name

get_value()

Get the value described below.

Returns: The current value of the widget.

Source code in ncca/ngl/widgets/vec3widget.py
64
65
66
67
68
69
70
def get_value(self) -> Vec3:
    """Get the value described below.

    Returns:
    The current value of the widget.
    """
    return self._value

set_name(name)

Sets the name of the widget.

Parameters:
  • name (str) –

    The new name of the widget.

Source code in ncca/ngl/widgets/vec3widget.py
162
163
164
165
166
167
168
169
def set_name(self, name: str) -> None:
    """Sets the name of the widget.

    Args:
        name: The new name of the widget.
    """
    self._name = name
    self._label.setText(name)

set_range(min_val, max_val)

Sets the range for all spinboxes.

Parameters:
  • min_val (float) –

    The minimum value.

  • max_val (float) –

    The maximum value.

Source code in ncca/ngl/widgets/vec3widget.py
116
117
118
119
120
121
122
123
124
def set_range(self, min_val: float, max_val: float) -> None:
    """Sets the range for all spinboxes.

    Args:
        min_val: The minimum value.
        max_val: The maximum value.
    """
    for spinbox in (self.x_spinbox, self.y_spinbox, self.z_spinbox):
        spinbox.setRange(min_val, max_val)

set_single_step(step)

Sets the single step for all spinboxes.

Parameters:
  • step (float) –

    The single step value.

Source code in ncca/ngl/widgets/vec3widget.py
153
154
155
156
157
158
159
160
def set_single_step(self, step: float) -> None:
    """Sets the single step for all spinboxes.

    Args:
        step: The single step value.
    """
    for spinbox in (self.x_spinbox, self.y_spinbox, self.z_spinbox):
        spinbox.setSingleStep(step)

set_value(value)

Sets the value of the widget.

Parameters:
  • value (Vec3) –

    The new value of the widget.

Source code in ncca/ngl/widgets/vec3widget.py
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
def set_value(self, value: Vec3) -> None:
    """Sets the value of the widget.

    Args:
        value: The new value of the widget.
    """
    with (
        QSignalBlocker(self.x_spinbox),
        QSignalBlocker(self.y_spinbox),
        QSignalBlocker(self.z_spinbox),
    ):
        self.x_spinbox.setValue(value.x)
        self.y_spinbox.setValue(value.y)
        self.z_spinbox.setValue(value.z)
    self._value = value
    self.valueChanged.emit(self._value)

set_x_range(min_val, max_val)

Sets the range for the x spinbox.

Parameters:
  • min_val (float) –

    The minimum value.

  • max_val (float) –

    The maximum value.

Source code in ncca/ngl/widgets/vec3widget.py
126
127
128
129
130
131
132
133
def set_x_range(self, min_val: float, max_val: float) -> None:
    """Sets the range for the x spinbox.

    Args:
        min_val: The minimum value.
        max_val: The maximum value.
    """
    self.x_spinbox.setRange(min_val, max_val)

set_y_range(min_val, max_val)

Sets the range for the y spinbox.

Parameters:
  • min_val (float) –

    The minimum value.

  • max_val (float) –

    The maximum value.

Source code in ncca/ngl/widgets/vec3widget.py
135
136
137
138
139
140
141
142
def set_y_range(self, min_val: float, max_val: float) -> None:
    """Sets the range for the y spinbox.

    Args:
        min_val: The minimum value.
        max_val: The maximum value.
    """
    self.y_spinbox.setRange(min_val, max_val)

set_z_range(min_val, max_val)

Sets the range for the z spinbox.

Parameters:
  • min_val (float) –

    The minimum value.

  • max_val (float) –

    The maximum value.

Source code in ncca/ngl/widgets/vec3widget.py
144
145
146
147
148
149
150
151
def set_z_range(self, min_val: float, max_val: float) -> None:
    """Sets the range for the z spinbox.

    Args:
        min_val: The minimum value.
        max_val: The maximum value.
    """
    self.z_spinbox.setRange(min_val, max_val)

Vec4Widget

Bases: QFrame

A widget for displaying and editing a Vec4 object.

Source code in ncca/ngl/widgets/vec4widget.py
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
class Vec4Widget(QFrame):
    """A widget for displaying and editing a Vec4 object."""

    valueChanged = Signal(Vec4)
    xValueChanged = Signal(float)
    yValueChanged = Signal(float)
    zValueChanged = Signal(float)
    wValueChanged = Signal(float)

    def __init__(
        self,
        parent: QWidget | None = None,
        name: str = "",
        value: Vec4 = Vec4(0.0, 0.0, 0.0, 1.0),
    ) -> None:
        """Initialize the widget.

        Args:
        name: The name of the widget.
        value: The initial value of the widget.
        parent: The parent widget.
        """
        super().__init__(parent)
        self.setFrameShape(QFrame.Shape.StyledPanel)
        self._value = value
        self._name = name
        layout = QHBoxLayout()

        self.x_spinbox = self._create_spinbox(self._value.x)
        self.y_spinbox = self._create_spinbox(self._value.y)
        self.z_spinbox = self._create_spinbox(self._value.z)
        self.w_spinbox = self._create_spinbox(self._value.w)

        self._label = QLabel(self._name)
        layout.addWidget(self._label)
        layout.addWidget(self.x_spinbox)
        layout.addWidget(self.y_spinbox)
        layout.addWidget(self.z_spinbox)
        layout.addWidget(self.w_spinbox)
        self.setLayout(layout)

    def _create_spinbox(self, value: float) -> QDoubleSpinBox:
        """Helper method to create and configure a QDoubleSpinBox.

        Args:
            value: The initial value of the spinbox.

        Returns:
            A configured QDoubleSpinBox.
        """
        spinbox = QDoubleSpinBox()
        spinbox.setValue(value)
        spinbox.setRange(-5.0, 5.0)
        spinbox.setSingleStep(0.01)
        spinbox.valueChanged.connect(self._on_value_changed)
        return spinbox

    def get_value(self) -> Vec4:
        """Get the value described below.

        Returns:
        The current value of the widget.
        """
        return self._value

    def _on_value_changed(self, value: float) -> None:
        """This slot is called when the value of a spinbox changes.

        Args:
            value: The new value of the spinbox.
        """
        sender = self.sender()
        if sender == self.x_spinbox:
            self._value.x = value
            self.xValueChanged.emit(value)
        elif sender == self.y_spinbox:
            self._value.y = value
            self.yValueChanged.emit(value)
        elif sender == self.z_spinbox:
            self._value.z = value
            self.zValueChanged.emit(value)
        elif sender == self.w_spinbox:
            self._value.w = value
            self.wValueChanged.emit(value)
        # emit the Vec4 value changed signal
        self.valueChanged.emit(self._value)

    def set_value(self, value: Vec4) -> None:
        """Sets the value of the widget.

        Args:
            value: The new value of the widget.
        """
        with (
            QSignalBlocker(self.x_spinbox),
            QSignalBlocker(self.y_spinbox),
            QSignalBlocker(self.z_spinbox),
            QSignalBlocker(self.w_spinbox),
        ):
            self.x_spinbox.setValue(value.x)
            self.y_spinbox.setValue(value.y)
            self.z_spinbox.setValue(value.z)
            self.w_spinbox.setValue(value.w)
        self._value = value
        self.valueChanged.emit(self._value)

    def get_name(self) -> str:
        """Get the value described below.

        Returns:
        The name of the widget.
        """
        return self._name

    def set_range(self, min_val: float, max_val: float) -> None:
        """Sets the range for all spinboxes.

        Args:
            min_val: The minimum value.
            max_val: The maximum value.
        """
        for spinbox in (self.x_spinbox, self.y_spinbox, self.z_spinbox, self.w_spinbox):
            spinbox.setRange(min_val, max_val)

    def set_x_range(self, min_val: float, max_val: float) -> None:
        """Sets the range for the x spinbox.

        Args:
            min_val: The minimum value.
            max_val: The maximum value.
        """
        self.x_spinbox.setRange(min_val, max_val)

    def set_y_range(self, min_val: float, max_val: float) -> None:
        """Sets the range for the y spinbox.

        Args:
            min_val: The minimum value.
            max_val: The maximum value.
        """
        self.y_spinbox.setRange(min_val, max_val)

    def set_z_range(self, min_val: float, max_val: float) -> None:
        """Sets the range for the z spinbox.

        Args:
            min_val: The minimum value.
            max_val: The maximum value.
        """
        self.z_spinbox.setRange(min_val, max_val)

    def set_w_range(self, min_val: float, max_val: float) -> None:
        """Sets the range for the w spinbox.

        Args:
            min_val: The minimum value.
            max_val: The maximum value.
        """
        self.w_spinbox.setRange(min_val, max_val)

    def set_single_step(self, step: float) -> None:
        """Sets the single step for all spinboxes.

        Args:
            step: The single step value.
        """
        for spinbox in (self.x_spinbox, self.y_spinbox, self.z_spinbox, self.w_spinbox):
            spinbox.setSingleStep(step)

    def set_name(self, name: str) -> None:
        """Sets the name of the widget.

        Args:
            name: The new name of the widget.
        """
        self._name = name
        self._label.setText(name)

    value = Property(Vec4, get_value, set_value)
    name = Property(str, get_name, set_name)

__init__(parent=None, name='', value=Vec4(0.0, 0.0, 0.0, 1.0))

Initialize the widget.

Args: name: The name of the widget. value: The initial value of the widget. parent: The parent widget.

Source code in ncca/ngl/widgets/vec4widget.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
def __init__(
    self,
    parent: QWidget | None = None,
    name: str = "",
    value: Vec4 = Vec4(0.0, 0.0, 0.0, 1.0),
) -> None:
    """Initialize the widget.

    Args:
    name: The name of the widget.
    value: The initial value of the widget.
    parent: The parent widget.
    """
    super().__init__(parent)
    self.setFrameShape(QFrame.Shape.StyledPanel)
    self._value = value
    self._name = name
    layout = QHBoxLayout()

    self.x_spinbox = self._create_spinbox(self._value.x)
    self.y_spinbox = self._create_spinbox(self._value.y)
    self.z_spinbox = self._create_spinbox(self._value.z)
    self.w_spinbox = self._create_spinbox(self._value.w)

    self._label = QLabel(self._name)
    layout.addWidget(self._label)
    layout.addWidget(self.x_spinbox)
    layout.addWidget(self.y_spinbox)
    layout.addWidget(self.z_spinbox)
    layout.addWidget(self.w_spinbox)
    self.setLayout(layout)

get_name()

Get the value described below.

Returns: The name of the widget.

Source code in ncca/ngl/widgets/vec4widget.py
115
116
117
118
119
120
121
def get_name(self) -> str:
    """Get the value described below.

    Returns:
    The name of the widget.
    """
    return self._name

get_value()

Get the value described below.

Returns: The current value of the widget.

Source code in ncca/ngl/widgets/vec4widget.py
66
67
68
69
70
71
72
def get_value(self) -> Vec4:
    """Get the value described below.

    Returns:
    The current value of the widget.
    """
    return self._value

set_name(name)

Sets the name of the widget.

Parameters:
  • name (str) –

    The new name of the widget.

Source code in ncca/ngl/widgets/vec4widget.py
178
179
180
181
182
183
184
185
def set_name(self, name: str) -> None:
    """Sets the name of the widget.

    Args:
        name: The new name of the widget.
    """
    self._name = name
    self._label.setText(name)

set_range(min_val, max_val)

Sets the range for all spinboxes.

Parameters:
  • min_val (float) –

    The minimum value.

  • max_val (float) –

    The maximum value.

Source code in ncca/ngl/widgets/vec4widget.py
123
124
125
126
127
128
129
130
131
def set_range(self, min_val: float, max_val: float) -> None:
    """Sets the range for all spinboxes.

    Args:
        min_val: The minimum value.
        max_val: The maximum value.
    """
    for spinbox in (self.x_spinbox, self.y_spinbox, self.z_spinbox, self.w_spinbox):
        spinbox.setRange(min_val, max_val)

set_single_step(step)

Sets the single step for all spinboxes.

Parameters:
  • step (float) –

    The single step value.

Source code in ncca/ngl/widgets/vec4widget.py
169
170
171
172
173
174
175
176
def set_single_step(self, step: float) -> None:
    """Sets the single step for all spinboxes.

    Args:
        step: The single step value.
    """
    for spinbox in (self.x_spinbox, self.y_spinbox, self.z_spinbox, self.w_spinbox):
        spinbox.setSingleStep(step)

set_value(value)

Sets the value of the widget.

Parameters:
  • value (Vec4) –

    The new value of the widget.

Source code in ncca/ngl/widgets/vec4widget.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
def set_value(self, value: Vec4) -> None:
    """Sets the value of the widget.

    Args:
        value: The new value of the widget.
    """
    with (
        QSignalBlocker(self.x_spinbox),
        QSignalBlocker(self.y_spinbox),
        QSignalBlocker(self.z_spinbox),
        QSignalBlocker(self.w_spinbox),
    ):
        self.x_spinbox.setValue(value.x)
        self.y_spinbox.setValue(value.y)
        self.z_spinbox.setValue(value.z)
        self.w_spinbox.setValue(value.w)
    self._value = value
    self.valueChanged.emit(self._value)

set_w_range(min_val, max_val)

Sets the range for the w spinbox.

Parameters:
  • min_val (float) –

    The minimum value.

  • max_val (float) –

    The maximum value.

Source code in ncca/ngl/widgets/vec4widget.py
160
161
162
163
164
165
166
167
def set_w_range(self, min_val: float, max_val: float) -> None:
    """Sets the range for the w spinbox.

    Args:
        min_val: The minimum value.
        max_val: The maximum value.
    """
    self.w_spinbox.setRange(min_val, max_val)

set_x_range(min_val, max_val)

Sets the range for the x spinbox.

Parameters:
  • min_val (float) –

    The minimum value.

  • max_val (float) –

    The maximum value.

Source code in ncca/ngl/widgets/vec4widget.py
133
134
135
136
137
138
139
140
def set_x_range(self, min_val: float, max_val: float) -> None:
    """Sets the range for the x spinbox.

    Args:
        min_val: The minimum value.
        max_val: The maximum value.
    """
    self.x_spinbox.setRange(min_val, max_val)

set_y_range(min_val, max_val)

Sets the range for the y spinbox.

Parameters:
  • min_val (float) –

    The minimum value.

  • max_val (float) –

    The maximum value.

Source code in ncca/ngl/widgets/vec4widget.py
142
143
144
145
146
147
148
149
def set_y_range(self, min_val: float, max_val: float) -> None:
    """Sets the range for the y spinbox.

    Args:
        min_val: The minimum value.
        max_val: The maximum value.
    """
    self.y_spinbox.setRange(min_val, max_val)

set_z_range(min_val, max_val)

Sets the range for the z spinbox.

Parameters:
  • min_val (float) –

    The minimum value.

  • max_val (float) –

    The maximum value.

Source code in ncca/ngl/widgets/vec4widget.py
151
152
153
154
155
156
157
158
def set_z_range(self, min_val: float, max_val: float) -> None:
    """Sets the range for the z spinbox.

    Args:
        min_val: The minimum value.
        max_val: The maximum value.
    """
    self.z_spinbox.setRange(min_val, max_val)

TransformWidget

Bases: QFrame

A widget for displaying and editing a Transform object, with foldable sections.

Source code in ncca/ngl/widgets/transformwidget.py
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
class TransformWidget(QFrame):
    """A widget for displaying and editing a Transform object, with foldable sections."""

    valueChanged = Signal(Mat4)
    _rotation_order = ["xyz", "yzx", "zxy", "xzy", "yxz", "zyx"]

    def __init__(self, parent: QWidget | None = None, name: str = "") -> None:
        """Initialize the widget.

        Args:
        name: The name of the widget.
        parent: The parent widget.
        """
        super().__init__(parent)
        self.setFrameShape(QFrame.Shape.StyledPanel)
        self._name = name

        main_layout = QVBoxLayout(self)
        main_layout.setContentsMargins(2, 2, 2, 2)
        main_layout.setSpacing(0)

        self._toggle_button = QToolButton(self)
        self._toggle_button.setText(self._name)
        self._toggle_button.setCheckable(True)
        self._toggle_button.setChecked(True)
        self._toggle_button.setStyleSheet("QToolButton { border: none; }")
        self._toggle_button.setToolButtonStyle(
            Qt.ToolButtonStyle.ToolButtonTextBesideIcon
        )
        self._toggle_button.setArrowType(Qt.ArrowType.DownArrow)
        self._toggle_button.clicked.connect(self.toggle_collapsed)

        self._content_widget = QWidget(self)
        content_layout = QVBoxLayout(self._content_widget)
        content_layout.setContentsMargins(0, 0, 0, 0)

        self._position = Vec3Widget(self, "Position", Vec3(0.0, 0.0, 0.0))
        self._position.set_range(-20, 20)
        self._rotation = Vec3Widget(self, "Rotation", Vec3(0.0, 0.0, 0.0))
        self._rotation.set_range(-360, 360)
        self._scale = Vec3Widget(self, "Scale", Vec3(1.0, 1.0, 1.0))
        self._scale.set_range(-20, 20)

        self._rot_order = QComboBox(self)
        for v in self._rotation_order:
            self._rot_order.addItem(v)
        self._position.valueChanged.connect(self._update_matrix)
        self._rotation.valueChanged.connect(self._update_matrix)
        self._scale.valueChanged.connect(self._update_matrix)
        self._rot_order.currentIndexChanged.connect(self._update_matrix)
        content_layout.addWidget(self._position)
        content_layout.addWidget(self._rotation)
        content_layout.addWidget(self._scale)
        content_layout.addWidget(QLabel("Rotation Order"))
        content_layout.addWidget(self._rot_order)
        main_layout.addWidget(self._toggle_button)
        main_layout.addWidget(self._content_widget)

    def toggle_collapsed(self, checked: bool) -> None:
        """Toggles the visibility of the content widget."""
        if checked:
            self._toggle_button.setArrowType(Qt.ArrowType.DownArrow)
            self._content_widget.setVisible(True)
        else:
            self._toggle_button.setArrowType(Qt.ArrowType.RightArrow)
            self._content_widget.setVisible(False)

    def _update_matrix(self) -> None:
        """Updates the transformation matrix based on the widget values."""
        position = self._position.get_value()
        rotation = self._rotation.get_value()
        scale = self._scale.get_value()

        tx = Transform()
        tx.set_order(self._rot_order.currentText())
        tx.set_position(position.x, position.y, position.z)
        tx.set_rotation(rotation.x, rotation.y, rotation.z)
        tx.set_scale(scale.x, scale.y, scale.z)
        print(tx.matrix())
        self.valueChanged.emit(tx.matrix())

    def name(self) -> str:
        """Get the value described below.

        Returns:
        The name of the widget.
        """
        return self._name

    def set_name(self, name: str) -> None:
        """Sets the name of the widget.

        Args:
            name: The new name of the widget.
        """
        self._name = name
        self._toggle_button.setText(name)

    name = Property(str, name, set_name)

name = Property(str, name, set_name) class-attribute instance-attribute

Get the value described below.

Returns: The name of the widget.

__init__(parent=None, name='')

Initialize the widget.

Args: name: The name of the widget. parent: The parent widget.

Source code in ncca/ngl/widgets/transformwidget.py
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
def __init__(self, parent: QWidget | None = None, name: str = "") -> None:
    """Initialize the widget.

    Args:
    name: The name of the widget.
    parent: The parent widget.
    """
    super().__init__(parent)
    self.setFrameShape(QFrame.Shape.StyledPanel)
    self._name = name

    main_layout = QVBoxLayout(self)
    main_layout.setContentsMargins(2, 2, 2, 2)
    main_layout.setSpacing(0)

    self._toggle_button = QToolButton(self)
    self._toggle_button.setText(self._name)
    self._toggle_button.setCheckable(True)
    self._toggle_button.setChecked(True)
    self._toggle_button.setStyleSheet("QToolButton { border: none; }")
    self._toggle_button.setToolButtonStyle(
        Qt.ToolButtonStyle.ToolButtonTextBesideIcon
    )
    self._toggle_button.setArrowType(Qt.ArrowType.DownArrow)
    self._toggle_button.clicked.connect(self.toggle_collapsed)

    self._content_widget = QWidget(self)
    content_layout = QVBoxLayout(self._content_widget)
    content_layout.setContentsMargins(0, 0, 0, 0)

    self._position = Vec3Widget(self, "Position", Vec3(0.0, 0.0, 0.0))
    self._position.set_range(-20, 20)
    self._rotation = Vec3Widget(self, "Rotation", Vec3(0.0, 0.0, 0.0))
    self._rotation.set_range(-360, 360)
    self._scale = Vec3Widget(self, "Scale", Vec3(1.0, 1.0, 1.0))
    self._scale.set_range(-20, 20)

    self._rot_order = QComboBox(self)
    for v in self._rotation_order:
        self._rot_order.addItem(v)
    self._position.valueChanged.connect(self._update_matrix)
    self._rotation.valueChanged.connect(self._update_matrix)
    self._scale.valueChanged.connect(self._update_matrix)
    self._rot_order.currentIndexChanged.connect(self._update_matrix)
    content_layout.addWidget(self._position)
    content_layout.addWidget(self._rotation)
    content_layout.addWidget(self._scale)
    content_layout.addWidget(QLabel("Rotation Order"))
    content_layout.addWidget(self._rot_order)
    main_layout.addWidget(self._toggle_button)
    main_layout.addWidget(self._content_widget)

set_name(name)

Sets the name of the widget.

Parameters:
  • name (str) –

    The new name of the widget.

Source code in ncca/ngl/widgets/transformwidget.py
107
108
109
110
111
112
113
114
def set_name(self, name: str) -> None:
    """Sets the name of the widget.

    Args:
        name: The new name of the widget.
    """
    self._name = name
    self._toggle_button.setText(name)

toggle_collapsed(checked)

Toggles the visibility of the content widget.

Source code in ncca/ngl/widgets/transformwidget.py
76
77
78
79
80
81
82
83
def toggle_collapsed(self, checked: bool) -> None:
    """Toggles the visibility of the content widget."""
    if checked:
        self._toggle_button.setArrowType(Qt.ArrowType.DownArrow)
        self._content_widget.setVisible(True)
    else:
        self._toggle_button.setArrowType(Qt.ArrowType.RightArrow)
        self._content_widget.setVisible(False)

LookAtWidget

Bases: QFrame

A widget for displaying and editing a Transform object, with foldable sections.

Source code in ncca/ngl/widgets/lookatwidget.py
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
class LookAtWidget(QFrame):
    """A widget for displaying and editing a Transform object, with foldable sections."""

    valueChanged = Signal(Mat4)
    world_up = [Vec3(0, 1, 0), Vec3(1, 0, 0), Vec3(0, 0, 1)]

    def __init__(
        self,
        parent: QWidget | None = None,
        name: str = "",
        eye: Vec3 = Vec3(2, 2, 2),
        look: Vec3 = Vec3(0, 0, 0),
    ) -> None:
        """Initialize the widget.

        Args:
        name: The name of the widget.
        parent: The parent widget.
        eye: Initial eye position.
        look: Initial look-at position.
        """
        super().__init__(parent)
        self.setFrameShape(QFrame.Shape.StyledPanel)
        self._name = name
        self._view = Mat4()
        main_layout = QVBoxLayout(self)
        main_layout.setContentsMargins(2, 2, 2, 2)
        main_layout.setSpacing(0)

        self._toggle_button = QToolButton(self)
        self._toggle_button.setText(self._name)
        self._toggle_button.setCheckable(True)
        self._toggle_button.setChecked(True)
        self._toggle_button.setStyleSheet("QToolButton { border: none; }")
        self._toggle_button.setToolButtonStyle(
            Qt.ToolButtonStyle.ToolButtonTextBesideIcon
        )
        self._toggle_button.setArrowType(Qt.ArrowType.DownArrow)
        self._toggle_button.clicked.connect(self.toggle_collapsed)

        self._content_widget = QWidget(self)
        content_layout = QVBoxLayout(self._content_widget)
        content_layout.setContentsMargins(0, 0, 0, 0)

        self._eye = Vec3Widget(self, "Eye", eye)
        self._look = Vec3Widget(self, "Look", look)
        self._up = QComboBox(self)
        for v in ["y-up", "x-up", "z-up"]:
            self._up.addItem(v)
        self._eye.valueChanged.connect(self._update_matrix)
        self._look.valueChanged.connect(self._update_matrix)
        self._up.currentIndexChanged.connect(self._update_matrix)
        content_layout.addWidget(self._eye)
        content_layout.addWidget(self._look)
        content_layout.addWidget(QLabel("World Up"))
        content_layout.addWidget(self._up)
        main_layout.addWidget(self._toggle_button)
        main_layout.addWidget(self._content_widget)
        self._update_matrix()

    def set_eye(self, eye: Vec3) -> None:
        """Set the eye position."""
        self._eye.set_value(eye)

    def set_look(self, look: Vec3) -> None:
        """Set the look-at position."""
        self._look.set_value(look)

    def set_up(self, up: int) -> None:
        """Set the up vector by world_up index."""
        self._up.setCurrentIndex(up)

    def set_name(self, name: str) -> None:
        """Set the widget name shown on the toggle button."""
        self._name = name
        self._toggle_button.setText(name)

    def get_name(self) -> str:
        """Return the widget name."""
        return self._name

    def get_eye(self) -> Vec3:
        """Return the eye position."""
        return self._eye.value

    def get_look(self) -> Vec3:
        """Return the look-at position."""
        return self._look.value

    def get_up(self) -> Vec3:
        """Return the currently selected up vector."""
        return self.world_up[self._up.currentIndex()]

    def toggle_collapsed(self, checked: bool) -> None:
        """Toggles the visibility of the content widget."""
        if checked:
            self._toggle_button.setArrowType(Qt.ArrowType.DownArrow)
            self._content_widget.setVisible(True)
        else:
            self._toggle_button.setArrowType(Qt.ArrowType.RightArrow)
            self._content_widget.setVisible(False)

    def _update_matrix(self) -> None:
        """Updates the view matrix based on the widget values."""
        eye = self._eye.value
        look = self._look.value

        up = self.world_up[self._up.currentIndex()]

        self._view = look_at(eye, look, up)
        self.valueChanged.emit(self._view)

    def view(self) -> Mat4:
        """Returns the current view matrix."""
        return self._view

    name = Property(str, get_name, set_name)
    eye = Property(Vec3, get_eye, set_eye)
    look = Property(Vec3, get_look, set_look)
    up = Property(Vec3, get_up, set_up)

__init__(parent=None, name='', eye=Vec3(2, 2, 2), look=Vec3(0, 0, 0))

Initialize the widget.

Args: name: The name of the widget. parent: The parent widget. eye: Initial eye position. look: Initial look-at position.

Source code in ncca/ngl/widgets/lookatwidget.py
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
def __init__(
    self,
    parent: QWidget | None = None,
    name: str = "",
    eye: Vec3 = Vec3(2, 2, 2),
    look: Vec3 = Vec3(0, 0, 0),
) -> None:
    """Initialize the widget.

    Args:
    name: The name of the widget.
    parent: The parent widget.
    eye: Initial eye position.
    look: Initial look-at position.
    """
    super().__init__(parent)
    self.setFrameShape(QFrame.Shape.StyledPanel)
    self._name = name
    self._view = Mat4()
    main_layout = QVBoxLayout(self)
    main_layout.setContentsMargins(2, 2, 2, 2)
    main_layout.setSpacing(0)

    self._toggle_button = QToolButton(self)
    self._toggle_button.setText(self._name)
    self._toggle_button.setCheckable(True)
    self._toggle_button.setChecked(True)
    self._toggle_button.setStyleSheet("QToolButton { border: none; }")
    self._toggle_button.setToolButtonStyle(
        Qt.ToolButtonStyle.ToolButtonTextBesideIcon
    )
    self._toggle_button.setArrowType(Qt.ArrowType.DownArrow)
    self._toggle_button.clicked.connect(self.toggle_collapsed)

    self._content_widget = QWidget(self)
    content_layout = QVBoxLayout(self._content_widget)
    content_layout.setContentsMargins(0, 0, 0, 0)

    self._eye = Vec3Widget(self, "Eye", eye)
    self._look = Vec3Widget(self, "Look", look)
    self._up = QComboBox(self)
    for v in ["y-up", "x-up", "z-up"]:
        self._up.addItem(v)
    self._eye.valueChanged.connect(self._update_matrix)
    self._look.valueChanged.connect(self._update_matrix)
    self._up.currentIndexChanged.connect(self._update_matrix)
    content_layout.addWidget(self._eye)
    content_layout.addWidget(self._look)
    content_layout.addWidget(QLabel("World Up"))
    content_layout.addWidget(self._up)
    main_layout.addWidget(self._toggle_button)
    main_layout.addWidget(self._content_widget)
    self._update_matrix()

get_eye()

Return the eye position.

Source code in ncca/ngl/widgets/lookatwidget.py
 99
100
101
def get_eye(self) -> Vec3:
    """Return the eye position."""
    return self._eye.value

get_look()

Return the look-at position.

Source code in ncca/ngl/widgets/lookatwidget.py
103
104
105
def get_look(self) -> Vec3:
    """Return the look-at position."""
    return self._look.value

get_name()

Return the widget name.

Source code in ncca/ngl/widgets/lookatwidget.py
95
96
97
def get_name(self) -> str:
    """Return the widget name."""
    return self._name

get_up()

Return the currently selected up vector.

Source code in ncca/ngl/widgets/lookatwidget.py
107
108
109
def get_up(self) -> Vec3:
    """Return the currently selected up vector."""
    return self.world_up[self._up.currentIndex()]

set_eye(eye)

Set the eye position.

Source code in ncca/ngl/widgets/lookatwidget.py
78
79
80
def set_eye(self, eye: Vec3) -> None:
    """Set the eye position."""
    self._eye.set_value(eye)

set_look(look)

Set the look-at position.

Source code in ncca/ngl/widgets/lookatwidget.py
82
83
84
def set_look(self, look: Vec3) -> None:
    """Set the look-at position."""
    self._look.set_value(look)

set_name(name)

Set the widget name shown on the toggle button.

Source code in ncca/ngl/widgets/lookatwidget.py
90
91
92
93
def set_name(self, name: str) -> None:
    """Set the widget name shown on the toggle button."""
    self._name = name
    self._toggle_button.setText(name)

set_up(up)

Set the up vector by world_up index.

Source code in ncca/ngl/widgets/lookatwidget.py
86
87
88
def set_up(self, up: int) -> None:
    """Set the up vector by world_up index."""
    self._up.setCurrentIndex(up)

toggle_collapsed(checked)

Toggles the visibility of the content widget.

Source code in ncca/ngl/widgets/lookatwidget.py
111
112
113
114
115
116
117
118
def toggle_collapsed(self, checked: bool) -> None:
    """Toggles the visibility of the content widget."""
    if checked:
        self._toggle_button.setArrowType(Qt.ArrowType.DownArrow)
        self._content_widget.setVisible(True)
    else:
        self._toggle_button.setArrowType(Qt.ArrowType.RightArrow)
        self._content_widget.setVisible(False)

view()

Returns the current view matrix.

Source code in ncca/ngl/widgets/lookatwidget.py
130
131
132
def view(self) -> Mat4:
    """Returns the current view matrix."""
    return self._view

PerspectiveWidget

Bases: QFrame

A widget for editing fov/aspect/near/far and viewing the resulting perspective Mat4.

Source code in ncca/ngl/widgets/perspectivewidget.py
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
class PerspectiveWidget(QFrame):
    """A widget for editing fov/aspect/near/far and viewing the resulting perspective Mat4."""

    valueChanged = Signal(Mat4)

    def __init__(
        self,
        parent: QWidget | None = None,
        name: str = "",
        fov: float = 45.0,
        aspect: float = 1.333,
        near: float = 0.1,
        far: float = 100.0,
        show_mode: bool = False,
    ) -> None:
        """Initialize the widget.

        Args:
            parent: The parent widget.
            name: The name of the widget.
            fov: Initial field of view in degrees.
            aspect: Initial aspect ratio.
            near: Initial near clipping plane distance.
            far: Initial far clipping plane distance.
            show_mode: If True, show a combo box to choose the clip-space
                convention (OpenGL/Vulkan/WebGPU); otherwise mode is fixed
                to PerspMode.OpenGL (but can still be set programmatically).
        """
        super().__init__(parent)
        self.setFrameShape(QFrame.Shape.StyledPanel)
        self._name = name
        self._mode = PerspMode.OpenGL
        self._matrix = Mat4()

        main_layout = QVBoxLayout(self)
        main_layout.setContentsMargins(2, 2, 2, 2)
        main_layout.setSpacing(0)

        self._toggle_button = QToolButton(self)
        self._toggle_button.setText(self._name)
        self._toggle_button.setCheckable(True)
        self._toggle_button.setChecked(True)
        self._toggle_button.setStyleSheet("QToolButton { border: none; }")
        self._toggle_button.setToolButtonStyle(
            Qt.ToolButtonStyle.ToolButtonTextBesideIcon
        )
        self._toggle_button.setArrowType(Qt.ArrowType.DownArrow)
        self._toggle_button.clicked.connect(self.toggle_collapsed)

        self._content_widget = QWidget(self)
        content_layout = QVBoxLayout(self._content_widget)
        content_layout.setContentsMargins(0, 0, 0, 0)

        self._fov_spinbox = self._create_row(
            content_layout, "Fov", fov, 1.0, 179.0, 1.0
        )
        self._aspect_spinbox = self._create_row(
            content_layout, "Aspect", aspect, 0.1, 4.0, 0.01
        )
        self._near_spinbox = self._create_row(
            content_layout, "Near", near, 0.01, 10.0, 0.01
        )
        self._far_spinbox = self._create_row(
            content_layout, "Far", far, 1.0, 1000.0, 1.0
        )

        if show_mode:
            self._mode_combo = QComboBox(self)
            for item in _MODE_NAMES:
                self._mode_combo.addItem(item)
            self._mode_combo.currentIndexChanged.connect(self._on_mode_index_changed)
            row = QHBoxLayout()
            row.addWidget(QLabel("Mode"))
            row.addWidget(self._mode_combo)
            content_layout.addLayout(row)

        main_layout.addWidget(self._toggle_button)
        main_layout.addWidget(self._content_widget)
        self._update_matrix()

    def _create_row(
        self,
        layout: QVBoxLayout,
        label: str,
        value: float,
        minimum: float,
        maximum: float,
        step: float,
    ) -> QDoubleSpinBox:
        """Create a labelled spinbox row and add it to the content layout.

        Args:
            layout: The layout to add the row to.
            label: The row's label text.
            value: The spinbox's initial value.
            minimum: The spinbox's minimum value.
            maximum: The spinbox's maximum value.
            step: The spinbox's single step.

        Returns:
            The created QDoubleSpinBox.
        """
        spinbox = QDoubleSpinBox()
        spinbox.setRange(minimum, maximum)
        spinbox.setSingleStep(step)
        spinbox.setDecimals(3)
        spinbox.setValue(value)
        spinbox.valueChanged.connect(self._update_matrix)
        row = QHBoxLayout()
        row.addWidget(QLabel(label))
        row.addWidget(spinbox)
        layout.addLayout(row)
        return spinbox

    def _on_mode_index_changed(self, index: int) -> None:
        """Update the mode from the combo box index and recompute the matrix.

        Args:
            index: The new combo box index.
        """
        self._mode = _MODE_BY_NAME[_MODE_NAMES[index]]
        self._update_matrix()

    def _update_matrix(self) -> None:
        """Recompute the perspective matrix from the current widget values."""
        self._matrix = perspective(
            self._fov_spinbox.value(),
            self._aspect_spinbox.value(),
            self._near_spinbox.value(),
            self._far_spinbox.value(),
            self._mode,
        )
        self.valueChanged.emit(self._matrix)

    def matrix(self) -> Mat4:
        """Return the current perspective matrix.

        Returns:
            The current Mat4.
        """
        return self._matrix

    def toggle_collapsed(self, checked: bool) -> None:
        """Toggle the visibility of the content widget.

        Args:
            checked: Whether the section should be expanded.
        """
        if checked:
            self._toggle_button.setArrowType(Qt.ArrowType.DownArrow)
            self._content_widget.setVisible(True)
        else:
            self._toggle_button.setArrowType(Qt.ArrowType.RightArrow)
            self._content_widget.setVisible(False)

    def get_fov(self) -> float:
        """Return the field of view in degrees."""
        return self._fov_spinbox.value()

    def set_fov(self, fov: float) -> None:
        """Set the field of view in degrees."""
        self._fov_spinbox.setValue(fov)

    def get_aspect(self) -> float:
        """Return the aspect ratio."""
        return self._aspect_spinbox.value()

    def set_aspect(self, aspect: float) -> None:
        """Set the aspect ratio."""
        self._aspect_spinbox.setValue(aspect)

    def get_near(self) -> float:
        """Return the near clipping plane distance."""
        return self._near_spinbox.value()

    def set_near(self, near: float) -> None:
        """Set the near clipping plane distance."""
        self._near_spinbox.setValue(near)

    def get_far(self) -> float:
        """Return the far clipping plane distance."""
        return self._far_spinbox.value()

    def set_far(self, far: float) -> None:
        """Set the far clipping plane distance."""
        self._far_spinbox.setValue(far)

    def get_mode(self) -> PerspMode:
        """Return the current clip-space convention."""
        return self._mode

    def set_mode(self, mode: PerspMode | int) -> None:
        """Set the clip-space convention.

        Args:
            mode: A PerspMode, or an index into the mode combo box order
                (OpenGL, Vulkan, WebGPU).
        """
        if isinstance(mode, int):
            mode = _MODE_BY_NAME[_MODE_NAMES[mode]]
        self._mode = mode
        if hasattr(self, "_mode_combo"):
            self._mode_combo.setCurrentIndex(_MODE_NAMES.index(mode.value))
        else:
            self._update_matrix()

    def get_name(self) -> str:
        """Return the widget name shown on the toggle button."""
        return self._name

    def set_name(self, name: str) -> None:
        """Set the widget name shown on the toggle button."""
        self._name = name
        self._toggle_button.setText(name)

    name = Property(str, get_name, set_name)
    fov = Property(float, get_fov, set_fov)
    aspect = Property(float, get_aspect, set_aspect)
    near = Property(float, get_near, set_near)
    far = Property(float, get_far, set_far)
    mode = Property(PerspMode, get_mode, set_mode)

__init__(parent=None, name='', fov=45.0, aspect=1.333, near=0.1, far=100.0, show_mode=False)

Initialize the widget.

Parameters:
  • parent (QWidget | None, default: None ) –

    The parent widget.

  • name (str, default: '' ) –

    The name of the widget.

  • fov (float, default: 45.0 ) –

    Initial field of view in degrees.

  • aspect (float, default: 1.333 ) –

    Initial aspect ratio.

  • near (float, default: 0.1 ) –

    Initial near clipping plane distance.

  • far (float, default: 100.0 ) –

    Initial far clipping plane distance.

  • show_mode (bool, default: False ) –

    If True, show a combo box to choose the clip-space convention (OpenGL/Vulkan/WebGPU); otherwise mode is fixed to PerspMode.OpenGL (but can still be set programmatically).

Source code in ncca/ngl/widgets/perspectivewidget.py
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
def __init__(
    self,
    parent: QWidget | None = None,
    name: str = "",
    fov: float = 45.0,
    aspect: float = 1.333,
    near: float = 0.1,
    far: float = 100.0,
    show_mode: bool = False,
) -> None:
    """Initialize the widget.

    Args:
        parent: The parent widget.
        name: The name of the widget.
        fov: Initial field of view in degrees.
        aspect: Initial aspect ratio.
        near: Initial near clipping plane distance.
        far: Initial far clipping plane distance.
        show_mode: If True, show a combo box to choose the clip-space
            convention (OpenGL/Vulkan/WebGPU); otherwise mode is fixed
            to PerspMode.OpenGL (but can still be set programmatically).
    """
    super().__init__(parent)
    self.setFrameShape(QFrame.Shape.StyledPanel)
    self._name = name
    self._mode = PerspMode.OpenGL
    self._matrix = Mat4()

    main_layout = QVBoxLayout(self)
    main_layout.setContentsMargins(2, 2, 2, 2)
    main_layout.setSpacing(0)

    self._toggle_button = QToolButton(self)
    self._toggle_button.setText(self._name)
    self._toggle_button.setCheckable(True)
    self._toggle_button.setChecked(True)
    self._toggle_button.setStyleSheet("QToolButton { border: none; }")
    self._toggle_button.setToolButtonStyle(
        Qt.ToolButtonStyle.ToolButtonTextBesideIcon
    )
    self._toggle_button.setArrowType(Qt.ArrowType.DownArrow)
    self._toggle_button.clicked.connect(self.toggle_collapsed)

    self._content_widget = QWidget(self)
    content_layout = QVBoxLayout(self._content_widget)
    content_layout.setContentsMargins(0, 0, 0, 0)

    self._fov_spinbox = self._create_row(
        content_layout, "Fov", fov, 1.0, 179.0, 1.0
    )
    self._aspect_spinbox = self._create_row(
        content_layout, "Aspect", aspect, 0.1, 4.0, 0.01
    )
    self._near_spinbox = self._create_row(
        content_layout, "Near", near, 0.01, 10.0, 0.01
    )
    self._far_spinbox = self._create_row(
        content_layout, "Far", far, 1.0, 1000.0, 1.0
    )

    if show_mode:
        self._mode_combo = QComboBox(self)
        for item in _MODE_NAMES:
            self._mode_combo.addItem(item)
        self._mode_combo.currentIndexChanged.connect(self._on_mode_index_changed)
        row = QHBoxLayout()
        row.addWidget(QLabel("Mode"))
        row.addWidget(self._mode_combo)
        content_layout.addLayout(row)

    main_layout.addWidget(self._toggle_button)
    main_layout.addWidget(self._content_widget)
    self._update_matrix()

get_aspect()

Return the aspect ratio.

Source code in ncca/ngl/widgets/perspectivewidget.py
188
189
190
def get_aspect(self) -> float:
    """Return the aspect ratio."""
    return self._aspect_spinbox.value()

get_far()

Return the far clipping plane distance.

Source code in ncca/ngl/widgets/perspectivewidget.py
204
205
206
def get_far(self) -> float:
    """Return the far clipping plane distance."""
    return self._far_spinbox.value()

get_fov()

Return the field of view in degrees.

Source code in ncca/ngl/widgets/perspectivewidget.py
180
181
182
def get_fov(self) -> float:
    """Return the field of view in degrees."""
    return self._fov_spinbox.value()

get_mode()

Return the current clip-space convention.

Source code in ncca/ngl/widgets/perspectivewidget.py
212
213
214
def get_mode(self) -> PerspMode:
    """Return the current clip-space convention."""
    return self._mode

get_name()

Return the widget name shown on the toggle button.

Source code in ncca/ngl/widgets/perspectivewidget.py
231
232
233
def get_name(self) -> str:
    """Return the widget name shown on the toggle button."""
    return self._name

get_near()

Return the near clipping plane distance.

Source code in ncca/ngl/widgets/perspectivewidget.py
196
197
198
def get_near(self) -> float:
    """Return the near clipping plane distance."""
    return self._near_spinbox.value()

matrix()

Return the current perspective matrix.

Returns:
  • Mat4

    The current Mat4.

Source code in ncca/ngl/widgets/perspectivewidget.py
159
160
161
162
163
164
165
def matrix(self) -> Mat4:
    """Return the current perspective matrix.

    Returns:
        The current Mat4.
    """
    return self._matrix

set_aspect(aspect)

Set the aspect ratio.

Source code in ncca/ngl/widgets/perspectivewidget.py
192
193
194
def set_aspect(self, aspect: float) -> None:
    """Set the aspect ratio."""
    self._aspect_spinbox.setValue(aspect)

set_far(far)

Set the far clipping plane distance.

Source code in ncca/ngl/widgets/perspectivewidget.py
208
209
210
def set_far(self, far: float) -> None:
    """Set the far clipping plane distance."""
    self._far_spinbox.setValue(far)

set_fov(fov)

Set the field of view in degrees.

Source code in ncca/ngl/widgets/perspectivewidget.py
184
185
186
def set_fov(self, fov: float) -> None:
    """Set the field of view in degrees."""
    self._fov_spinbox.setValue(fov)

set_mode(mode)

Set the clip-space convention.

Parameters:
  • mode (PerspMode | int) –

    A PerspMode, or an index into the mode combo box order (OpenGL, Vulkan, WebGPU).

Source code in ncca/ngl/widgets/perspectivewidget.py
216
217
218
219
220
221
222
223
224
225
226
227
228
229
def set_mode(self, mode: PerspMode | int) -> None:
    """Set the clip-space convention.

    Args:
        mode: A PerspMode, or an index into the mode combo box order
            (OpenGL, Vulkan, WebGPU).
    """
    if isinstance(mode, int):
        mode = _MODE_BY_NAME[_MODE_NAMES[mode]]
    self._mode = mode
    if hasattr(self, "_mode_combo"):
        self._mode_combo.setCurrentIndex(_MODE_NAMES.index(mode.value))
    else:
        self._update_matrix()

set_name(name)

Set the widget name shown on the toggle button.

Source code in ncca/ngl/widgets/perspectivewidget.py
235
236
237
238
def set_name(self, name: str) -> None:
    """Set the widget name shown on the toggle button."""
    self._name = name
    self._toggle_button.setText(name)

set_near(near)

Set the near clipping plane distance.

Source code in ncca/ngl/widgets/perspectivewidget.py
200
201
202
def set_near(self, near: float) -> None:
    """Set the near clipping plane distance."""
    self._near_spinbox.setValue(near)

toggle_collapsed(checked)

Toggle the visibility of the content widget.

Parameters:
  • checked (bool) –

    Whether the section should be expanded.

Source code in ncca/ngl/widgets/perspectivewidget.py
167
168
169
170
171
172
173
174
175
176
177
178
def toggle_collapsed(self, checked: bool) -> None:
    """Toggle the visibility of the content widget.

    Args:
        checked: Whether the section should be expanded.
    """
    if checked:
        self._toggle_button.setArrowType(Qt.ArrowType.DownArrow)
        self._content_widget.setVisible(True)
    else:
        self._toggle_button.setArrowType(Qt.ArrowType.RightArrow)
        self._content_widget.setVisible(False)

RGBColourWidget

Bases: QFrame

A widget for displaying and editing a Vec3 object.

Source code in ncca/ngl/widgets/rgbcolourwidget.py
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
class RGBColourWidget(QFrame):
    """A widget for displaying and editing a Vec3 object."""

    colourChanged = Signal(Vec3)
    rValueChanged = Signal(float)
    gValueChanged = Signal(float)
    bValueChanged = Signal(float)

    def __init__(
        self,
        parent: QWidget | None = None,
        name: str = "",
        r: float = 1.0,
        g: float = 1.0,
        b: float = 1.0,
    ) -> None:
        """Initialize the widget.

        Args:
        name: The name of the widget.
        r: The initial red component of the colour.
        g: The initial green component of the colour.
        b: The initial blue component of the colour.
        parent: The parent widget.
        """
        super().__init__(parent)
        self.setFrameShape(QFrame.Shape.StyledPanel)
        self._colour = Vec3(r, g, b)
        self._name = name
        layout = QHBoxLayout()

        self.r_spinbox = self._create_spinbox(self._colour.x)
        self.g_spinbox = self._create_spinbox(self._colour.y)
        self.b_spinbox = self._create_spinbox(self._colour.z)

        self._label = QLabel(self._name)
        self._color_button = QPushButton()
        self._color_button.setFixedSize(20, 20)
        self._color_button.clicked.connect(self._show_color_dialog)
        self._update_button_color()

        layout.addWidget(self._label)
        layout.addWidget(self.r_spinbox)
        layout.addWidget(self.g_spinbox)
        layout.addWidget(self.b_spinbox)
        layout.addWidget(self._color_button)
        self.setLayout(layout)

    def _create_spinbox(self, value: float) -> QDoubleSpinBox:
        """Helper method to create and configure a QDoubleSpinBox.

        Args:
            value: The initial value of the spinbox.

        Returns:
            A configured QDoubleSpinBox.
        """
        spinbox = QDoubleSpinBox()
        spinbox.setValue(value)
        spinbox.setRange(0.0, 1.0)
        spinbox.setSingleStep(0.01)
        spinbox.valueChanged.connect(self._on_value_changed)
        return spinbox

    def colour(self) -> Vec3:
        """Get the value described below.

        Returns:
        The current value of the widget.
        """
        return self._colour

    def _on_value_changed(self, value: float) -> None:
        """This slot is called when the value of a spinbox changes.

        Args:
            value: The new value of the spinbox.
        """
        sender = self.sender()
        if sender == self.r_spinbox:
            self._colour.x = value
            self.rValueChanged.emit(value)
        elif sender == self.g_spinbox:
            self._colour.y = value
            self.gValueChanged.emit(value)
        elif sender == self.b_spinbox:
            self._colour.z = value
            self.bValueChanged.emit(value)
        # emit the Vec3 value changed signal
        self.colourChanged.emit(self._colour)
        self._update_button_color()

    def set_colour(self, value: Vec3) -> None:
        """Sets the value of the widget.

        Args:
            value: The new value of the widget.
        """
        with (
            QSignalBlocker(self.r_spinbox),
            QSignalBlocker(self.g_spinbox),
            QSignalBlocker(self.b_spinbox),
        ):
            self.r_spinbox.setValue(value.x)
            self.g_spinbox.setValue(value.y)
            self.b_spinbox.setValue(value.z)
        self._colour = value
        self.colourChanged.emit(self._colour)
        self._update_button_color()

    def _update_button_color(self) -> None:
        """Updates the background color of the color button."""
        color = QColor.fromRgbF(self._colour.x, self._colour.y, self._colour.z)
        self._color_button.setStyleSheet(f"background-color: {color.name()}")

    def _show_color_dialog(self) -> None:
        """Shows a QColorDialog to select a new color."""
        current_color = QColor.fromRgbF(self._colour.x, self._colour.y, self._colour.z)
        color = QColorDialog.getColor(current_color, self, "Select Color")
        if color.isValid():
            new_colour = Vec3(color.redF(), color.greenF(), color.blueF())
            self.set_colour(new_colour)

    def name(self) -> str:
        """Get the value described below.

        Returns:
        The name of the widget.
        """
        return self._name

    def set_name(self, name: str) -> None:
        """Sets the name of the widget.

        Args:
            name: The new name of the widget.
        """
        self._name = name
        self._label.setText(name)

    value = Property(Vec3, colour, set_colour)
    name = Property(str, name, set_name)

name = Property(str, name, set_name) class-attribute instance-attribute

Get the value described below.

Returns: The name of the widget.

__init__(parent=None, name='', r=1.0, g=1.0, b=1.0)

Initialize the widget.

Args: name: The name of the widget. r: The initial red component of the colour. g: The initial green component of the colour. b: The initial blue component of the colour. parent: The parent widget.

Source code in ncca/ngl/widgets/rgbcolourwidget.py
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
def __init__(
    self,
    parent: QWidget | None = None,
    name: str = "",
    r: float = 1.0,
    g: float = 1.0,
    b: float = 1.0,
) -> None:
    """Initialize the widget.

    Args:
    name: The name of the widget.
    r: The initial red component of the colour.
    g: The initial green component of the colour.
    b: The initial blue component of the colour.
    parent: The parent widget.
    """
    super().__init__(parent)
    self.setFrameShape(QFrame.Shape.StyledPanel)
    self._colour = Vec3(r, g, b)
    self._name = name
    layout = QHBoxLayout()

    self.r_spinbox = self._create_spinbox(self._colour.x)
    self.g_spinbox = self._create_spinbox(self._colour.y)
    self.b_spinbox = self._create_spinbox(self._colour.z)

    self._label = QLabel(self._name)
    self._color_button = QPushButton()
    self._color_button.setFixedSize(20, 20)
    self._color_button.clicked.connect(self._show_color_dialog)
    self._update_button_color()

    layout.addWidget(self._label)
    layout.addWidget(self.r_spinbox)
    layout.addWidget(self.g_spinbox)
    layout.addWidget(self.b_spinbox)
    layout.addWidget(self._color_button)
    self.setLayout(layout)

colour()

Get the value described below.

Returns: The current value of the widget.

Source code in ncca/ngl/widgets/rgbcolourwidget.py
82
83
84
85
86
87
88
def colour(self) -> Vec3:
    """Get the value described below.

    Returns:
    The current value of the widget.
    """
    return self._colour

set_colour(value)

Sets the value of the widget.

Parameters:
  • value (Vec3) –

    The new value of the widget.

Source code in ncca/ngl/widgets/rgbcolourwidget.py
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
def set_colour(self, value: Vec3) -> None:
    """Sets the value of the widget.

    Args:
        value: The new value of the widget.
    """
    with (
        QSignalBlocker(self.r_spinbox),
        QSignalBlocker(self.g_spinbox),
        QSignalBlocker(self.b_spinbox),
    ):
        self.r_spinbox.setValue(value.x)
        self.g_spinbox.setValue(value.y)
        self.b_spinbox.setValue(value.z)
    self._colour = value
    self.colourChanged.emit(self._colour)
    self._update_button_color()

set_name(name)

Sets the name of the widget.

Parameters:
  • name (str) –

    The new name of the widget.

Source code in ncca/ngl/widgets/rgbcolourwidget.py
149
150
151
152
153
154
155
156
def set_name(self, name: str) -> None:
    """Sets the name of the widget.

    Args:
        name: The new name of the widget.
    """
    self._name = name
    self._label.setText(name)

RGBAColourWidget

Bases: QFrame

A widget for displaying and editing a Vec4 object.

Source code in ncca/ngl/widgets/rgbacolourwidget.py
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
class RGBAColourWidget(QFrame):
    """A widget for displaying and editing a Vec4 object."""

    colourChanged = Signal(Vec4)
    rValueChanged = Signal(float)
    gValueChanged = Signal(float)
    bValueChanged = Signal(float)
    aValueChanged = Signal(float)

    def __init__(
        self,
        parent: QWidget | None = None,
        name: str = "",
        r: float = 1.0,
        g: float = 1.0,
        b: float = 1.0,
        a: float = 1.0,
    ) -> None:
        """Initialize the widget.

        Args:
        name: The name of the widget.
        r: The initial red component of the colour.
        g: The initial green component of the colour.
        b: The initial blue component of the colour.
        a: The initial alpha component of the colour.
        parent: The parent widget.
        """
        super().__init__(parent)
        self.setFrameShape(QFrame.Shape.StyledPanel)
        self._colour = Vec4(r, g, b, a)
        self._name = name
        layout = QHBoxLayout()

        self.r_spinbox = self._create_spinbox(self._colour.x)
        self.g_spinbox = self._create_spinbox(self._colour.y)
        self.b_spinbox = self._create_spinbox(self._colour.z)
        self.a_spinbox = self._create_spinbox(self._colour.w)
        self._label = QLabel(self._name)
        self._color_button = QPushButton()
        self._color_button.setFixedSize(20, 20)
        self._color_button.clicked.connect(self._show_color_dialog)
        self._update_button_color()

        layout.addWidget(self._label)
        layout.addWidget(self.r_spinbox)
        layout.addWidget(self.g_spinbox)
        layout.addWidget(self.b_spinbox)
        layout.addWidget(self.a_spinbox)
        layout.addWidget(self._color_button)
        self.setLayout(layout)

    def _create_spinbox(self, value: float) -> QDoubleSpinBox:
        """Helper method to create and configure a QDoubleSpinBox.

        Args:
            value: The initial value of the spinbox.

        Returns:
            A configured QDoubleSpinBox.
        """
        spinbox = QDoubleSpinBox()
        spinbox.setValue(value)
        spinbox.setRange(0.0, 1.0)
        spinbox.setSingleStep(0.01)
        spinbox.valueChanged.connect(self._on_value_changed)
        return spinbox

    def colour(self) -> Vec4:
        """Get the value described below.

        Returns:
        The current value of the widget.
        """
        return self._colour

    def _on_value_changed(self, value: float) -> None:
        """This slot is called when the value of a spinbox changes.

        Args:
            value: The new value of the spinbox.
        """
        sender = self.sender()
        if sender == self.r_spinbox:
            self._colour.x = value
            self.rValueChanged.emit(value)
        elif sender == self.g_spinbox:
            self._colour.y = value
            self.gValueChanged.emit(value)
        elif sender == self.b_spinbox:
            self._colour.z = value
            self.bValueChanged.emit(value)
        elif sender == self.a_spinbox:
            self._colour.w = value
            self.aValueChanged.emit(value)
        # emit the Vec4 value changed signal
        self.colourChanged.emit(self._colour)
        self._update_button_color()

    def set_colour(self, value: Vec4) -> None:
        """Sets the value of the widget.

        Args:
            value: The new value of the widget.
        """
        with (
            QSignalBlocker(self.r_spinbox),
            QSignalBlocker(self.g_spinbox),
            QSignalBlocker(self.b_spinbox),
            QSignalBlocker(self.a_spinbox),
        ):
            self.r_spinbox.setValue(value.x)
            self.g_spinbox.setValue(value.y)
            self.b_spinbox.setValue(value.z)
            self.a_spinbox.setValue(value.w)
        self._colour = value
        self.colourChanged.emit(self._colour)
        self._update_button_color()

    def _update_button_color(self) -> None:
        """Updates the background color of the color button."""
        color = QColor.fromRgbF(
            self._colour.x, self._colour.y, self._colour.z, self._colour.w
        )
        self._color_button.setStyleSheet(
            f"background-color: {color.name(QColor.NameFormat.HexArgb)}"
        )

    def _show_color_dialog(self) -> None:
        """Shows a QColorDialog to select a new color."""
        current_color = QColor.fromRgbF(
            self._colour.x, self._colour.y, self._colour.z, self._colour.w
        )
        color = QColorDialog.getColor(
            current_color,
            self,
            "Select Color",
            options=QColorDialog.ColorDialogOption.ShowAlphaChannel,
        )
        if color.isValid():
            new_colour = Vec4(
                color.redF(), color.greenF(), color.blueF(), color.alphaF()
            )
            self.set_colour(new_colour)

    def name(self) -> str:
        """Get the value described below.

        Returns:
        The name of the widget.
        """
        return self._name

    def set_name(self, name: str) -> None:
        """Sets the name of the widget.

        Args:
            name: The new name of the widget.
        """
        self._name = name
        self._label.setText(name)

    value = Property(Vec4, colour, set_colour)
    name = Property(str, name, set_name)

name = Property(str, name, set_name) class-attribute instance-attribute

Get the value described below.

Returns: The name of the widget.

__init__(parent=None, name='', r=1.0, g=1.0, b=1.0, a=1.0)

Initialize the widget.

Args: name: The name of the widget. r: The initial red component of the colour. g: The initial green component of the colour. b: The initial blue component of the colour. a: The initial alpha component of the colour. parent: The parent widget.

Source code in ncca/ngl/widgets/rgbacolourwidget.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
def __init__(
    self,
    parent: QWidget | None = None,
    name: str = "",
    r: float = 1.0,
    g: float = 1.0,
    b: float = 1.0,
    a: float = 1.0,
) -> None:
    """Initialize the widget.

    Args:
    name: The name of the widget.
    r: The initial red component of the colour.
    g: The initial green component of the colour.
    b: The initial blue component of the colour.
    a: The initial alpha component of the colour.
    parent: The parent widget.
    """
    super().__init__(parent)
    self.setFrameShape(QFrame.Shape.StyledPanel)
    self._colour = Vec4(r, g, b, a)
    self._name = name
    layout = QHBoxLayout()

    self.r_spinbox = self._create_spinbox(self._colour.x)
    self.g_spinbox = self._create_spinbox(self._colour.y)
    self.b_spinbox = self._create_spinbox(self._colour.z)
    self.a_spinbox = self._create_spinbox(self._colour.w)
    self._label = QLabel(self._name)
    self._color_button = QPushButton()
    self._color_button.setFixedSize(20, 20)
    self._color_button.clicked.connect(self._show_color_dialog)
    self._update_button_color()

    layout.addWidget(self._label)
    layout.addWidget(self.r_spinbox)
    layout.addWidget(self.g_spinbox)
    layout.addWidget(self.b_spinbox)
    layout.addWidget(self.a_spinbox)
    layout.addWidget(self._color_button)
    self.setLayout(layout)

colour()

Get the value described below.

Returns: The current value of the widget.

Source code in ncca/ngl/widgets/rgbacolourwidget.py
86
87
88
89
90
91
92
def colour(self) -> Vec4:
    """Get the value described below.

    Returns:
    The current value of the widget.
    """
    return self._colour

set_colour(value)

Sets the value of the widget.

Parameters:
  • value (Vec4) –

    The new value of the widget.

Source code in ncca/ngl/widgets/rgbacolourwidget.py
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
def set_colour(self, value: Vec4) -> None:
    """Sets the value of the widget.

    Args:
        value: The new value of the widget.
    """
    with (
        QSignalBlocker(self.r_spinbox),
        QSignalBlocker(self.g_spinbox),
        QSignalBlocker(self.b_spinbox),
        QSignalBlocker(self.a_spinbox),
    ):
        self.r_spinbox.setValue(value.x)
        self.g_spinbox.setValue(value.y)
        self.b_spinbox.setValue(value.z)
        self.a_spinbox.setValue(value.w)
    self._colour = value
    self.colourChanged.emit(self._colour)
    self._update_button_color()

set_name(name)

Sets the name of the widget.

Parameters:
  • name (str) –

    The new name of the widget.

Source code in ncca/ngl/widgets/rgbacolourwidget.py
171
172
173
174
175
176
177
178
def set_name(self, name: str) -> None:
    """Sets the name of the widget.

    Args:
        name: The new name of the widget.
    """
    self._name = name
    self._label.setText(name)

Mat2Widget

Bases: _MatGridWidget

A widget for displaying and editing a Mat2 object as an editable grid.

Source code in ncca/ngl/widgets/mat2widget.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Mat2Widget(_MatGridWidget):
    """A widget for displaying and editing a Mat2 object as an editable grid."""

    valueChanged = Signal(Mat2)

    def __init__(
        self,
        parent: QWidget | None = None,
        name: str = "",
        read_only: bool = False,
    ) -> None:
        """Initialize the widget.

        Args:
            parent: The parent widget.
            name: The name of the widget.
            read_only: If True, the grid is a view-only display: no
                editing, no reset buttons.
        """
        super().__init__(Mat2, 2, parent, name, read_only)

    value = Property(Mat2, _MatGridWidget.get_value, _MatGridWidget.set_value)

__init__(parent=None, name='', read_only=False)

Initialize the widget.

Parameters:
  • parent (QWidget | None, default: None ) –

    The parent widget.

  • name (str, default: '' ) –

    The name of the widget.

  • read_only (bool, default: False ) –

    If True, the grid is a view-only display: no editing, no reset buttons.

Source code in ncca/ngl/widgets/mat2widget.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def __init__(
    self,
    parent: QWidget | None = None,
    name: str = "",
    read_only: bool = False,
) -> None:
    """Initialize the widget.

    Args:
        parent: The parent widget.
        name: The name of the widget.
        read_only: If True, the grid is a view-only display: no
            editing, no reset buttons.
    """
    super().__init__(Mat2, 2, parent, name, read_only)

Mat3Widget

Bases: _MatGridWidget

A widget for displaying and editing a Mat3 object as an editable grid.

Source code in ncca/ngl/widgets/mat3widget.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Mat3Widget(_MatGridWidget):
    """A widget for displaying and editing a Mat3 object as an editable grid."""

    valueChanged = Signal(Mat3)

    def __init__(
        self,
        parent: QWidget | None = None,
        name: str = "",
        read_only: bool = False,
    ) -> None:
        """Initialize the widget.

        Args:
            parent: The parent widget.
            name: The name of the widget.
            read_only: If True, the grid is a view-only display: no
                editing, no reset buttons, no method combo box.
        """
        super().__init__(Mat3, 3, parent, name, read_only)
        if not read_only:
            self._add_method_combo(
                {
                    "rotate_x": ("angle", Mat3.rotate_x),
                    "rotate_y": ("angle", Mat3.rotate_y),
                    "rotate_z": ("angle", Mat3.rotate_z),
                    "scale": ("xyz", Mat3.scale),
                }
            )

    value = Property(Mat3, _MatGridWidget.get_value, _MatGridWidget.set_value)

__init__(parent=None, name='', read_only=False)

Initialize the widget.

Parameters:
  • parent (QWidget | None, default: None ) –

    The parent widget.

  • name (str, default: '' ) –

    The name of the widget.

  • read_only (bool, default: False ) –

    If True, the grid is a view-only display: no editing, no reset buttons, no method combo box.

Source code in ncca/ngl/widgets/mat3widget.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
def __init__(
    self,
    parent: QWidget | None = None,
    name: str = "",
    read_only: bool = False,
) -> None:
    """Initialize the widget.

    Args:
        parent: The parent widget.
        name: The name of the widget.
        read_only: If True, the grid is a view-only display: no
            editing, no reset buttons, no method combo box.
    """
    super().__init__(Mat3, 3, parent, name, read_only)
    if not read_only:
        self._add_method_combo(
            {
                "rotate_x": ("angle", Mat3.rotate_x),
                "rotate_y": ("angle", Mat3.rotate_y),
                "rotate_z": ("angle", Mat3.rotate_z),
                "scale": ("xyz", Mat3.scale),
            }
        )

Mat4Widget

Bases: _MatGridWidget

A widget for displaying and editing a Mat4 object as an editable grid.

Source code in ncca/ngl/widgets/mat4widget.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Mat4Widget(_MatGridWidget):
    """A widget for displaying and editing a Mat4 object as an editable grid."""

    valueChanged = Signal(Mat4)

    def __init__(
        self,
        parent: QWidget | None = None,
        name: str = "",
        read_only: bool = False,
    ) -> None:
        """Initialize the widget.

        Args:
            parent: The parent widget.
            name: The name of the widget.
            read_only: If True, the grid is a view-only display: no
                editing, no reset buttons, no method combo box.
        """
        super().__init__(Mat4, 4, parent, name, read_only)
        if not read_only:
            self._add_method_combo(
                {
                    "rotate_x": ("angle", Mat4.rotate_x),
                    "rotate_y": ("angle", Mat4.rotate_y),
                    "rotate_z": ("angle", Mat4.rotate_z),
                    "scale": ("xyz", Mat4.scale),
                    "translate": ("xyz", Mat4.translate),
                }
            )

    value = Property(Mat4, _MatGridWidget.get_value, _MatGridWidget.set_value)

__init__(parent=None, name='', read_only=False)

Initialize the widget.

Parameters:
  • parent (QWidget | None, default: None ) –

    The parent widget.

  • name (str, default: '' ) –

    The name of the widget.

  • read_only (bool, default: False ) –

    If True, the grid is a view-only display: no editing, no reset buttons, no method combo box.

Source code in ncca/ngl/widgets/mat4widget.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
def __init__(
    self,
    parent: QWidget | None = None,
    name: str = "",
    read_only: bool = False,
) -> None:
    """Initialize the widget.

    Args:
        parent: The parent widget.
        name: The name of the widget.
        read_only: If True, the grid is a view-only display: no
            editing, no reset buttons, no method combo box.
    """
    super().__init__(Mat4, 4, parent, name, read_only)
    if not read_only:
        self._add_method_combo(
            {
                "rotate_x": ("angle", Mat4.rotate_x),
                "rotate_y": ("angle", Mat4.rotate_y),
                "rotate_z": ("angle", Mat4.rotate_z),
                "scale": ("xyz", Mat4.scale),
                "translate": ("xyz", Mat4.translate),
            }
        )