ncca-ngl 0.3.0__tar.gz → 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/PKG-INFO +1 -1
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/pyproject.toml +1 -1
- ncca_ngl-0.3.1/src/ncca/ngl/widgets/NGLDebug.log +0 -0
- ncca_ngl-0.3.1/src/ncca/ngl/widgets/__init__.py +12 -0
- ncca_ngl-0.3.1/src/ncca/ngl/widgets/__main__.py +77 -0
- ncca_ngl-0.3.1/src/ncca/ngl/widgets/glsl/phong.frag +27 -0
- ncca_ngl-0.3.1/src/ncca/ngl/widgets/glsl/phong.vert +14 -0
- ncca_ngl-0.3.1/src/ncca/ngl/widgets/glsl/picking.frag +7 -0
- ncca_ngl-0.3.1/src/ncca/ngl/widgets/glsl/picking.vert +7 -0
- ncca_ngl-0.3.1/src/ncca/ngl/widgets/lookatwidget.py +77 -0
- ncca_ngl-0.3.1/src/ncca/ngl/widgets/mat4widget.py +7 -0
- ncca_ngl-0.3.1/src/ncca/ngl/widgets/rgbacolourwidget.py +157 -0
- ncca_ngl-0.3.1/src/ncca/ngl/widgets/rgbcolourwidget.py +143 -0
- ncca_ngl-0.3.1/src/ncca/ngl/widgets/transformation_widget.py +299 -0
- ncca_ngl-0.3.1/src/ncca/ngl/widgets/transformwidget.py +81 -0
- ncca_ngl-0.3.1/src/ncca/ngl/widgets/vec2widget.py +141 -0
- ncca_ngl-0.3.1/src/ncca/ngl/widgets/vec3widget.py +157 -0
- ncca_ngl-0.3.1/src/ncca/ngl/widgets/vec4widget.py +178 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/LICENSE.txt +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/.ruff_cache/.gitignore +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/.ruff_cache/0.13.0/10564494386971134025 +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/.ruff_cache/0.13.0/7783445477288392980 +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/.ruff_cache/CACHEDIR.TAG +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/PrimData/NGLDebug.log +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/PrimData/Primitives.npz +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/PrimData/buddah.npy +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/PrimData/bunny.npy +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/PrimData/cube.npy +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/PrimData/dodecahedron.npy +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/PrimData/dragon.npy +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/PrimData/football.npy +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/PrimData/icosahedron.npy +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/PrimData/octahedron.npy +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/PrimData/pack_arrays.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/PrimData/teapot.npy +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/PrimData/tetrahedron.npy +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/PrimData/troll.npy +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/__init__.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/abstract_vao.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/base_mesh.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/base_mesh.pyi +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/bbox.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/bezier_curve.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/first_person_camera.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/image.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/log.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/mat2.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/mat3.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/mat4.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/multi_buffer_vao.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/obj.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/plane.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/prim_data.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/primitives.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/pyside_event_handling_mixin.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/quaternion.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/random.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/shader.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/shader_lib.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/shader_program.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/shaders/checker_fragment.glsl +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/shaders/checker_vertex.glsl +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/shaders/colour_fragment.glsl +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/shaders/colour_vertex.glsl +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/shaders/diffuse_fragment.glsl +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/shaders/diffuse_vertex.glsl +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/shaders/text_fragment.glsl +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/shaders/text_geometry.glsl +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/shaders/text_vertex.glsl +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/simple_index_vao.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/simple_vao.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/text.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/texture.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/transform.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/util.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/vao_factory.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/vec2.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/vec2_array.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/vec3.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/vec3_array.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/vec4.py +0 -0
- {ncca_ngl-0.3.0 → ncca_ngl-0.3.1}/src/ncca/ngl/vec4_array.py +0 -0
|
File without changes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from .lookatwidget import LookAtWidget
|
|
5
|
+
from .rgbacolourwidget import RGBAColourWidget
|
|
6
|
+
from .rgbcolourwidget import RGBColourWidget
|
|
7
|
+
from .transformwidget import TransformWidget
|
|
8
|
+
from .vec2widget import Vec2Widget
|
|
9
|
+
from .vec3widget import Vec3Widget
|
|
10
|
+
from .vec4widget import Vec4Widget
|
|
11
|
+
|
|
12
|
+
__all__ = ["Vec2Widget", "Vec3Widget", "Vec4Widget", "TransformWidget", "LookAtWidget", "RGBColourWidget"]
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
from PySide6.QtWidgets import QApplication, QDialog, QGridLayout, QLabel
|
|
4
|
+
|
|
5
|
+
from ncca.ngl import Vec2, Vec3, Vec4
|
|
6
|
+
from ncca.ngl.widgets import (
|
|
7
|
+
LookAtWidget,
|
|
8
|
+
RGBAColourWidget,
|
|
9
|
+
RGBColourWidget,
|
|
10
|
+
TransformWidget,
|
|
11
|
+
Vec2Widget,
|
|
12
|
+
Vec3Widget,
|
|
13
|
+
Vec4Widget,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SimpleDialog(QDialog):
|
|
18
|
+
def __init__(self, parent=None):
|
|
19
|
+
super(SimpleDialog, self).__init__(parent)
|
|
20
|
+
self.setWindowTitle("PyNGL ncca.widgets library ")
|
|
21
|
+
self.setMinimumWidth(200)
|
|
22
|
+
layout = QGridLayout()
|
|
23
|
+
|
|
24
|
+
self.vec2_widget = Vec2Widget("Vec2 Widget", Vec2(1, 2), self)
|
|
25
|
+
self.vec2_widget.set_x_range(-1, 1)
|
|
26
|
+
self.vec2_widget.set_y_range(-2, 2)
|
|
27
|
+
layout.addWidget(self.vec2_widget, 0, 0)
|
|
28
|
+
self.vec2_label = QLabel("[0.0,0.0]")
|
|
29
|
+
layout.addWidget(self.vec2_label, 0, 1)
|
|
30
|
+
self.vec2_widget.valueChanged.connect(self._update_vec2)
|
|
31
|
+
|
|
32
|
+
self.vec3_widget = Vec3Widget("Vec3 Widget", Vec3(1, 2, 3), self)
|
|
33
|
+
self.vec3_widget.set_y_range(-2, 2)
|
|
34
|
+
self.vec3_widget.set_z_range(-3, 3)
|
|
35
|
+
layout.addWidget(self.vec3_widget, 1, 0)
|
|
36
|
+
self.vec3_label = QLabel("[0.0,0.0,0.0]")
|
|
37
|
+
layout.addWidget(self.vec3_label, 1, 1)
|
|
38
|
+
self.vec3_widget.valueChanged.connect(self._update_vec3)
|
|
39
|
+
|
|
40
|
+
self.vec4_widget = Vec4Widget("Vec4 Widget", Vec4(1, 2, 3, 1.0), self)
|
|
41
|
+
self.vec4_widget.set_y_range(-2, 2)
|
|
42
|
+
self.vec4_widget.set_z_range(-3, 3)
|
|
43
|
+
layout.addWidget(self.vec4_widget, 2, 0)
|
|
44
|
+
self.vec4_label = QLabel("[0.0,0.0,0.0,1.0]")
|
|
45
|
+
layout.addWidget(self.vec4_label, 2, 1)
|
|
46
|
+
self.vec4_widget.valueChanged.connect(self._update_vec4)
|
|
47
|
+
|
|
48
|
+
self.transform_widget = TransformWidget("Transform Widget", self)
|
|
49
|
+
layout.addWidget(self.transform_widget, 3, 0)
|
|
50
|
+
|
|
51
|
+
self.lookat = LookAtWidget("Look At", parent=self)
|
|
52
|
+
layout.addWidget(self.lookat, 4, 0)
|
|
53
|
+
|
|
54
|
+
self.rgb_colour_widget = RGBColourWidget("RGB Colour Widget", 1.0, 0.0, 0.0, self)
|
|
55
|
+
layout.addWidget(self.rgb_colour_widget, 5, 0)
|
|
56
|
+
self.rgba_colour_widget = RGBAColourWidget("RGB Colour Widget", 1.0, 0.0, 0.0, 1.0, self)
|
|
57
|
+
layout.addWidget(self.rgba_colour_widget, 6, 0)
|
|
58
|
+
|
|
59
|
+
self.setLayout(layout)
|
|
60
|
+
|
|
61
|
+
def _update_vec3(self, value):
|
|
62
|
+
self.vec3_label.setText(f"[{value.x:0.2f}, {value.y:0.2f}, {value.z:0.2f}]")
|
|
63
|
+
|
|
64
|
+
def _update_vec2(self, value):
|
|
65
|
+
self.vec2_label.setText(f"[{value.x:0.2f}, {value.y:0.2f}]")
|
|
66
|
+
|
|
67
|
+
def _update_vec4(self, value):
|
|
68
|
+
self.vec4_label.setText(f"[{value.x:0.2f}, {value.y:0.2f}, {value.z:0.2f}, {value.w:0.2f}]")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
if __name__ == "__main__":
|
|
72
|
+
app = QApplication(sys.argv)
|
|
73
|
+
print("NCCA Widgets")
|
|
74
|
+
|
|
75
|
+
dialog = SimpleDialog()
|
|
76
|
+
dialog.show()
|
|
77
|
+
app.exec()
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#version 330 core
|
|
2
|
+
out vec4 FragColor;
|
|
3
|
+
in vec3 FragPos;
|
|
4
|
+
in vec3 Normal;
|
|
5
|
+
uniform vec3 light_pos;
|
|
6
|
+
uniform vec3 view_pos;
|
|
7
|
+
uniform vec3 light_color;
|
|
8
|
+
uniform vec3 object_color;
|
|
9
|
+
void main()
|
|
10
|
+
{
|
|
11
|
+
// Ambient
|
|
12
|
+
float ambient_strength = 0.1;
|
|
13
|
+
vec3 ambient = ambient_strength * light_color;
|
|
14
|
+
// Diffuse
|
|
15
|
+
vec3 norm = normalize(Normal);
|
|
16
|
+
vec3 light_dir = normalize(light_pos - FragPos);
|
|
17
|
+
float diff = max(dot(norm, light_dir), 0.0);
|
|
18
|
+
vec3 diffuse = diff * light_color;
|
|
19
|
+
// Specular
|
|
20
|
+
float specular_strength = 0.5;
|
|
21
|
+
vec3 view_dir = normalize(view_pos - FragPos);
|
|
22
|
+
vec3 reflect_dir = reflect(-light_dir, norm);
|
|
23
|
+
float spec = pow(max(dot(view_dir, reflect_dir), 0.0), 32);
|
|
24
|
+
vec3 specular = specular_strength * spec * light_color;
|
|
25
|
+
vec3 result = (ambient + diffuse + specular) * object_color;
|
|
26
|
+
FragColor = vec4(result, 1.0);
|
|
27
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#version 330 core
|
|
2
|
+
layout (location = 0) in vec3 aPos;
|
|
3
|
+
layout (location = 1) in vec3 aNormal;
|
|
4
|
+
out vec3 FragPos;
|
|
5
|
+
out vec3 Normal;
|
|
6
|
+
uniform mat4 model;
|
|
7
|
+
uniform mat4 MVP;
|
|
8
|
+
uniform mat3 normal_matrix;
|
|
9
|
+
void main()
|
|
10
|
+
{
|
|
11
|
+
FragPos = vec3(model * vec4(aPos, 1.0));
|
|
12
|
+
Normal = normal_matrix * aNormal;
|
|
13
|
+
gl_Position = MVP * vec4(aPos, 1.0);
|
|
14
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from PySide6.QtCore import Property, QSignalBlocker, Qt, Signal, Slot
|
|
2
|
+
from PySide6.QtWidgets import QComboBox, QFrame, QLabel, QToolButton, QVBoxLayout, QWidget
|
|
3
|
+
|
|
4
|
+
from ncca.ngl import Mat4, Vec3, look_at
|
|
5
|
+
|
|
6
|
+
from .vec3widget import Vec3Widget
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class LookAtWidget(QFrame):
|
|
10
|
+
"""A widget for displaying and editing a Transform object, with foldable sections."""
|
|
11
|
+
|
|
12
|
+
valueChanged = Signal(Mat4)
|
|
13
|
+
|
|
14
|
+
def __init__(self, name: str, eye=Vec3(2, 2, 2), look=Vec3(0, 0, 0), parent: QWidget | None = None) -> None:
|
|
15
|
+
"""
|
|
16
|
+
Args:
|
|
17
|
+
name: The name of the widget.
|
|
18
|
+
parent: The parent widget.
|
|
19
|
+
"""
|
|
20
|
+
super().__init__(parent)
|
|
21
|
+
self.setFrameShape(QFrame.Shape.StyledPanel)
|
|
22
|
+
self._name = name
|
|
23
|
+
self._view = Mat4()
|
|
24
|
+
main_layout = QVBoxLayout(self)
|
|
25
|
+
main_layout.setContentsMargins(2, 2, 2, 2)
|
|
26
|
+
main_layout.setSpacing(0)
|
|
27
|
+
|
|
28
|
+
self._toggle_button = QToolButton(self)
|
|
29
|
+
self._toggle_button.setText(self._name)
|
|
30
|
+
self._toggle_button.setCheckable(True)
|
|
31
|
+
self._toggle_button.setChecked(True)
|
|
32
|
+
self._toggle_button.setStyleSheet("QToolButton { border: none; }")
|
|
33
|
+
self._toggle_button.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
|
|
34
|
+
self._toggle_button.setArrowType(Qt.ArrowType.DownArrow)
|
|
35
|
+
self._toggle_button.clicked.connect(self.toggle_collapsed)
|
|
36
|
+
|
|
37
|
+
self._content_widget = QWidget(self)
|
|
38
|
+
content_layout = QVBoxLayout(self._content_widget)
|
|
39
|
+
content_layout.setContentsMargins(0, 0, 0, 0)
|
|
40
|
+
|
|
41
|
+
self._eye = Vec3Widget("Eye", eye, self)
|
|
42
|
+
self._look = Vec3Widget("Look", look, self)
|
|
43
|
+
self._up = QComboBox(self)
|
|
44
|
+
for v in ["y-up", "x-up", "z-up"]:
|
|
45
|
+
self._up.addItem(v)
|
|
46
|
+
self._eye.valueChanged.connect(self._update_matrix)
|
|
47
|
+
self._look.valueChanged.connect(self._update_matrix)
|
|
48
|
+
self._up.currentIndexChanged.connect(self._update_matrix)
|
|
49
|
+
content_layout.addWidget(self._eye)
|
|
50
|
+
content_layout.addWidget(self._look)
|
|
51
|
+
content_layout.addWidget(QLabel("World Up"))
|
|
52
|
+
content_layout.addWidget(self._up)
|
|
53
|
+
main_layout.addWidget(self._toggle_button)
|
|
54
|
+
main_layout.addWidget(self._content_widget)
|
|
55
|
+
|
|
56
|
+
def toggle_collapsed(self, checked: bool) -> None:
|
|
57
|
+
"""Toggles the visibility of the content widget."""
|
|
58
|
+
if checked:
|
|
59
|
+
self._toggle_button.setArrowType(Qt.ArrowType.DownArrow)
|
|
60
|
+
self._content_widget.setVisible(True)
|
|
61
|
+
else:
|
|
62
|
+
self._toggle_button.setArrowType(Qt.ArrowType.RightArrow)
|
|
63
|
+
self._content_widget.setVisible(False)
|
|
64
|
+
|
|
65
|
+
def _update_matrix(self) -> None:
|
|
66
|
+
"""Updates the view matrix based on the widget values."""
|
|
67
|
+
eye = self._eye.value
|
|
68
|
+
look = self._look.value
|
|
69
|
+
world_up = [Vec3(0, 1, 0), Vec3(1, 0, 0), Vec3(0, 0, 1)]
|
|
70
|
+
up = world_up[self._up.currentIndex()]
|
|
71
|
+
|
|
72
|
+
self._view = look_at(eye, look, up)
|
|
73
|
+
self.valueChanged.emit(self._view)
|
|
74
|
+
|
|
75
|
+
def view(self) -> Mat4:
|
|
76
|
+
"""Returns the current view matrix."""
|
|
77
|
+
return self._view
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
from PySide6.QtCore import Property, QSignalBlocker, Signal
|
|
2
|
+
from PySide6.QtGui import QColor
|
|
3
|
+
from PySide6.QtWidgets import (
|
|
4
|
+
QColorDialog,
|
|
5
|
+
QDoubleSpinBox,
|
|
6
|
+
QFrame,
|
|
7
|
+
QHBoxLayout,
|
|
8
|
+
QLabel,
|
|
9
|
+
QPushButton,
|
|
10
|
+
QWidget,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
from ncca.ngl import Vec4
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class RGBAColourWidget(QFrame):
|
|
17
|
+
"""A widget for displaying and editing a Vec4 object."""
|
|
18
|
+
|
|
19
|
+
colourChanged = Signal(Vec4)
|
|
20
|
+
rValueChanged = Signal(float)
|
|
21
|
+
gValueChanged = Signal(float)
|
|
22
|
+
bValueChanged = Signal(float)
|
|
23
|
+
aValueChanged = Signal(float)
|
|
24
|
+
|
|
25
|
+
def __init__(self, name: str, r: float, g: float, b: float, a: float, parent: QWidget | None = None) -> None:
|
|
26
|
+
"""
|
|
27
|
+
Args:
|
|
28
|
+
name: The name of the widget.
|
|
29
|
+
r: The initial red component of the colour.
|
|
30
|
+
g: The initial green component of the colour.
|
|
31
|
+
b: The initial blue component of the colour.
|
|
32
|
+
a: The initial alpha component of the colour.
|
|
33
|
+
parent: The parent widget.
|
|
34
|
+
"""
|
|
35
|
+
super().__init__(parent)
|
|
36
|
+
self.setFrameShape(QFrame.Shape.StyledPanel)
|
|
37
|
+
self._colour = Vec4(r, g, b, a)
|
|
38
|
+
self._name = name
|
|
39
|
+
layout = QHBoxLayout()
|
|
40
|
+
|
|
41
|
+
self.r_spinbox = self._create_spinbox(self._colour.x)
|
|
42
|
+
self.g_spinbox = self._create_spinbox(self._colour.y)
|
|
43
|
+
self.b_spinbox = self._create_spinbox(self._colour.z)
|
|
44
|
+
self.a_spinbox = self._create_spinbox(self._colour.w)
|
|
45
|
+
self._label = QLabel(self._name)
|
|
46
|
+
self._color_button = QPushButton()
|
|
47
|
+
self._color_button.setFixedSize(20, 20)
|
|
48
|
+
self._color_button.clicked.connect(self._show_color_dialog)
|
|
49
|
+
self._update_button_color()
|
|
50
|
+
|
|
51
|
+
layout.addWidget(self._label)
|
|
52
|
+
layout.addWidget(self.r_spinbox)
|
|
53
|
+
layout.addWidget(self.g_spinbox)
|
|
54
|
+
layout.addWidget(self.b_spinbox)
|
|
55
|
+
layout.addWidget(self.a_spinbox)
|
|
56
|
+
layout.addWidget(self._color_button)
|
|
57
|
+
self.setLayout(layout)
|
|
58
|
+
|
|
59
|
+
def _create_spinbox(self, value: float) -> QDoubleSpinBox:
|
|
60
|
+
"""Helper method to create and configure a QDoubleSpinBox.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
value: The initial value of the spinbox.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
A configured QDoubleSpinBox.
|
|
67
|
+
"""
|
|
68
|
+
spinbox = QDoubleSpinBox()
|
|
69
|
+
spinbox.setValue(value)
|
|
70
|
+
spinbox.setRange(0.0, 1.0)
|
|
71
|
+
spinbox.setSingleStep(0.01)
|
|
72
|
+
spinbox.valueChanged.connect(self._on_value_changed)
|
|
73
|
+
return spinbox
|
|
74
|
+
|
|
75
|
+
def colour(self) -> Vec4:
|
|
76
|
+
"""
|
|
77
|
+
Returns:
|
|
78
|
+
The current value of the widget.
|
|
79
|
+
"""
|
|
80
|
+
return self._colour
|
|
81
|
+
|
|
82
|
+
def _on_value_changed(self, value: float) -> None:
|
|
83
|
+
"""This slot is called when the value of a spinbox changes.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
value: The new value of the spinbox.
|
|
87
|
+
"""
|
|
88
|
+
sender = self.sender()
|
|
89
|
+
if sender == self.r_spinbox:
|
|
90
|
+
self._colour.x = value
|
|
91
|
+
self.rValueChanged.emit(value)
|
|
92
|
+
elif sender == self.g_spinbox:
|
|
93
|
+
self._colour.y = value
|
|
94
|
+
self.gValueChanged.emit(value)
|
|
95
|
+
elif sender == self.b_spinbox:
|
|
96
|
+
self._colour.z = value
|
|
97
|
+
self.bValueChanged.emit(value)
|
|
98
|
+
elif sender == self.a_spinbox:
|
|
99
|
+
self._colour.w = value
|
|
100
|
+
self.aValueChanged.emit(value)
|
|
101
|
+
# emit the Vec4 value changed signal
|
|
102
|
+
self.colourChanged.emit(self._colour)
|
|
103
|
+
self._update_button_color()
|
|
104
|
+
|
|
105
|
+
def set_colour(self, value: Vec4) -> None:
|
|
106
|
+
"""Sets the value of the widget.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
value: The new value of the widget.
|
|
110
|
+
"""
|
|
111
|
+
with (
|
|
112
|
+
QSignalBlocker(self.r_spinbox),
|
|
113
|
+
QSignalBlocker(self.g_spinbox),
|
|
114
|
+
QSignalBlocker(self.b_spinbox),
|
|
115
|
+
QSignalBlocker(self.a_spinbox),
|
|
116
|
+
):
|
|
117
|
+
self.r_spinbox.setValue(value.x)
|
|
118
|
+
self.g_spinbox.setValue(value.y)
|
|
119
|
+
self.b_spinbox.setValue(value.z)
|
|
120
|
+
self.a_spinbox.setValue(value.w)
|
|
121
|
+
self._colour = value
|
|
122
|
+
self.colourChanged.emit(self._colour)
|
|
123
|
+
self._update_button_color()
|
|
124
|
+
|
|
125
|
+
def _update_button_color(self) -> None:
|
|
126
|
+
"""Updates the background color of the color button."""
|
|
127
|
+
color = QColor.fromRgbF(self._colour.x, self._colour.y, self._colour.z, self._colour.w)
|
|
128
|
+
self._color_button.setStyleSheet(f"background-color: {color.name(QColor.NameFormat.HexArgb)}")
|
|
129
|
+
|
|
130
|
+
def _show_color_dialog(self) -> None:
|
|
131
|
+
"""Shows a QColorDialog to select a new color."""
|
|
132
|
+
current_color = QColor.fromRgbF(self._colour.x, self._colour.y, self._colour.z, self._colour.w)
|
|
133
|
+
color = QColorDialog.getColor(
|
|
134
|
+
current_color, self, "Select Color", options=QColorDialog.ColorDialogOption.ShowAlphaChannel
|
|
135
|
+
)
|
|
136
|
+
if color.isValid():
|
|
137
|
+
new_colour = Vec4(color.redF(), color.greenF(), color.blueF(), color.alphaF())
|
|
138
|
+
self.set_colour(new_colour)
|
|
139
|
+
|
|
140
|
+
def name(self) -> str:
|
|
141
|
+
"""
|
|
142
|
+
Returns:
|
|
143
|
+
The name of the widget.
|
|
144
|
+
"""
|
|
145
|
+
return self._name
|
|
146
|
+
|
|
147
|
+
def set_name(self, name: str) -> None:
|
|
148
|
+
"""Sets the name of the widget.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
name: The new name of the widget.
|
|
152
|
+
"""
|
|
153
|
+
self._name = name
|
|
154
|
+
self._label.setText(name)
|
|
155
|
+
|
|
156
|
+
value = Property(Vec4, colour, set_colour)
|
|
157
|
+
name = Property(str, name, set_name)
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
from PySide6.QtCore import Property, QSignalBlocker, Signal
|
|
2
|
+
from PySide6.QtGui import QColor
|
|
3
|
+
from PySide6.QtWidgets import (
|
|
4
|
+
QColorDialog,
|
|
5
|
+
QDoubleSpinBox,
|
|
6
|
+
QFrame,
|
|
7
|
+
QHBoxLayout,
|
|
8
|
+
QLabel,
|
|
9
|
+
QPushButton,
|
|
10
|
+
QWidget,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
from ncca.ngl import Vec3
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class RGBColourWidget(QFrame):
|
|
17
|
+
"""A widget for displaying and editing a Vec3 object."""
|
|
18
|
+
|
|
19
|
+
colourChanged = Signal(Vec3)
|
|
20
|
+
rValueChanged = Signal(float)
|
|
21
|
+
gValueChanged = Signal(float)
|
|
22
|
+
bValueChanged = Signal(float)
|
|
23
|
+
|
|
24
|
+
def __init__(self, name: str, r: float, g: float, b: float, parent: QWidget | None = None) -> None:
|
|
25
|
+
"""
|
|
26
|
+
Args:
|
|
27
|
+
name: The name of the widget.
|
|
28
|
+
r: The initial red component of the colour.
|
|
29
|
+
g: The initial green component of the colour.
|
|
30
|
+
b: The initial blue component of the colour.
|
|
31
|
+
parent: The parent widget.
|
|
32
|
+
"""
|
|
33
|
+
super().__init__(parent)
|
|
34
|
+
self.setFrameShape(QFrame.Shape.StyledPanel)
|
|
35
|
+
self._colour = Vec3(r, g, b)
|
|
36
|
+
self._name = name
|
|
37
|
+
layout = QHBoxLayout()
|
|
38
|
+
|
|
39
|
+
self.r_spinbox = self._create_spinbox(self._colour.x)
|
|
40
|
+
self.g_spinbox = self._create_spinbox(self._colour.y)
|
|
41
|
+
self.b_spinbox = self._create_spinbox(self._colour.z)
|
|
42
|
+
|
|
43
|
+
self._label = QLabel(self._name)
|
|
44
|
+
self._color_button = QPushButton()
|
|
45
|
+
self._color_button.setFixedSize(20, 20)
|
|
46
|
+
self._color_button.clicked.connect(self._show_color_dialog)
|
|
47
|
+
self._update_button_color()
|
|
48
|
+
|
|
49
|
+
layout.addWidget(self._label)
|
|
50
|
+
layout.addWidget(self.r_spinbox)
|
|
51
|
+
layout.addWidget(self.g_spinbox)
|
|
52
|
+
layout.addWidget(self.b_spinbox)
|
|
53
|
+
layout.addWidget(self._color_button)
|
|
54
|
+
self.setLayout(layout)
|
|
55
|
+
|
|
56
|
+
def _create_spinbox(self, value: float) -> QDoubleSpinBox:
|
|
57
|
+
"""Helper method to create and configure a QDoubleSpinBox.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
value: The initial value of the spinbox.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
A configured QDoubleSpinBox.
|
|
64
|
+
"""
|
|
65
|
+
spinbox = QDoubleSpinBox()
|
|
66
|
+
spinbox.setValue(value)
|
|
67
|
+
spinbox.setRange(0.0, 1.0)
|
|
68
|
+
spinbox.setSingleStep(0.01)
|
|
69
|
+
spinbox.valueChanged.connect(self._on_value_changed)
|
|
70
|
+
return spinbox
|
|
71
|
+
|
|
72
|
+
def colour(self) -> Vec3:
|
|
73
|
+
"""
|
|
74
|
+
Returns:
|
|
75
|
+
The current value of the widget.
|
|
76
|
+
"""
|
|
77
|
+
return self._colour
|
|
78
|
+
|
|
79
|
+
def _on_value_changed(self, value: float) -> None:
|
|
80
|
+
"""This slot is called when the value of a spinbox changes.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
value: The new value of the spinbox.
|
|
84
|
+
"""
|
|
85
|
+
sender = self.sender()
|
|
86
|
+
if sender == self.r_spinbox:
|
|
87
|
+
self._colour.x = value
|
|
88
|
+
self.rValueChanged.emit(value)
|
|
89
|
+
elif sender == self.g_spinbox:
|
|
90
|
+
self._colour.y = value
|
|
91
|
+
self.gValueChanged.emit(value)
|
|
92
|
+
elif sender == self.b_spinbox:
|
|
93
|
+
self._colour.z = value
|
|
94
|
+
self.bValueChanged.emit(value)
|
|
95
|
+
# emit the Vec3 value changed signal
|
|
96
|
+
self.colourChanged.emit(self._colour)
|
|
97
|
+
self._update_button_color()
|
|
98
|
+
|
|
99
|
+
def set_colour(self, value: Vec3) -> None:
|
|
100
|
+
"""Sets the value of the widget.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
value: The new value of the widget.
|
|
104
|
+
"""
|
|
105
|
+
with QSignalBlocker(self.r_spinbox), QSignalBlocker(self.g_spinbox), QSignalBlocker(self.b_spinbox):
|
|
106
|
+
self.r_spinbox.setValue(value.x)
|
|
107
|
+
self.g_spinbox.setValue(value.y)
|
|
108
|
+
self.b_spinbox.setValue(value.z)
|
|
109
|
+
self._colour = value
|
|
110
|
+
self.colourChanged.emit(self._colour)
|
|
111
|
+
self._update_button_color()
|
|
112
|
+
|
|
113
|
+
def _update_button_color(self) -> None:
|
|
114
|
+
"""Updates the background color of the color button."""
|
|
115
|
+
color = QColor.fromRgbF(self._colour.x, self._colour.y, self._colour.z)
|
|
116
|
+
self._color_button.setStyleSheet(f"background-color: {color.name()}")
|
|
117
|
+
|
|
118
|
+
def _show_color_dialog(self) -> None:
|
|
119
|
+
"""Shows a QColorDialog to select a new color."""
|
|
120
|
+
current_color = QColor.fromRgbF(self._colour.x, self._colour.y, self._colour.z)
|
|
121
|
+
color = QColorDialog.getColor(current_color, self, "Select Color")
|
|
122
|
+
if color.isValid():
|
|
123
|
+
new_colour = Vec3(color.redF(), color.greenF(), color.blueF())
|
|
124
|
+
self.set_colour(new_colour)
|
|
125
|
+
|
|
126
|
+
def name(self) -> str:
|
|
127
|
+
"""
|
|
128
|
+
Returns:
|
|
129
|
+
The name of the widget.
|
|
130
|
+
"""
|
|
131
|
+
return self._name
|
|
132
|
+
|
|
133
|
+
def set_name(self, name: str) -> None:
|
|
134
|
+
"""Sets the name of the widget.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
name: The new name of the widget.
|
|
138
|
+
"""
|
|
139
|
+
self._name = name
|
|
140
|
+
self._label.setText(name)
|
|
141
|
+
|
|
142
|
+
value = Property(Vec3, colour, set_colour)
|
|
143
|
+
name = Property(str, name, set_name)
|