Skip to content

Commit d77b7a3

Browse files
committed
[ui] Coloring a Node: Added ColorSelector to the Graph Editor
The color selector in the Graph Editor provides a quick way to color nodes with predefined palette of colors. Added Command to allow the Coloring to be undone and redone using QUndoStack
1 parent 58a9b74 commit d77b7a3

File tree

5 files changed

+213
-0
lines changed

5 files changed

+213
-0
lines changed

meshroom/ui/commands.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,54 @@ def undoImpl(self):
205205
self.graph.removeNode(duplicate)
206206

207207

208+
class UpdateNodeColorCommand(GraphCommand):
209+
""" Command representing the work for Coloring nodes in the Graph.
210+
"""
211+
212+
def __init__(self, graph, nodes, color, parent=None):
213+
""" Command Constructor.
214+
215+
Args:
216+
graph (meshroom.core.Graph): Current Graph instance.
217+
nodes (list<Node>): Array of nodes.
218+
color (str): Hex code for the color.
219+
220+
Keyword Args:
221+
parent (QObject): Parent QObject instance.
222+
"""
223+
super(UpdateNodeColorCommand, self).__init__(graph, parent)
224+
self._nodes = nodes
225+
self._color = color
226+
227+
# Existing colors
228+
# Map <Node: str>
229+
# Holds the existing color of the node which can be applied on the node back in case of an undo
230+
self._colorMap = {}
231+
232+
self.setText("Update Selected Node Color")
233+
234+
def redoImpl(self) -> bool:
235+
""" Redo implementation.
236+
"""
237+
for node in self._nodes:
238+
# Update the existing color for the node in the map
239+
self._colorMap[node] = node.color
240+
241+
# Now update the color of the node with the provided one
242+
node.color = self._color
243+
244+
return True
245+
246+
def undoImpl(self):
247+
""" Undo Implementation.
248+
"""
249+
with GraphModification(self.graph):
250+
# Revert the color for the nodes
251+
for node in self._nodes:
252+
# Get the color which was saved for the node
253+
node.color = self._colorMap.get(node)
254+
255+
208256
class PasteNodesCommand(GraphCommand):
209257
"""
210258
Handle node pasting in a Graph.

meshroom/ui/graph.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,17 @@ def selectFollowing(self, node):
952952
""" Select all the nodes the depend on 'node'. """
953953
self.selectNodes(self._graph.dfsOnDiscover(startNodes=[node], reverse=True, dependenciesOnly=True)[0])
954954

955+
@Slot(str)
956+
def updateNodeColor(self, color):
957+
""" Sets the Provided color on the selected Nodes.
958+
959+
Args:
960+
color (str): Hex code of the color to be set on the nodes.
961+
"""
962+
# Update the color attribute of the nodes which are currently selected
963+
with self.groupedGraphModification("Update Color for Select Nodes"):
964+
self.push(commands.UpdateNodeColorCommand(self._graph, list(self._selectedNodes), color))
965+
955966
@Slot(QObject, QObject)
956967
def boxSelect(self, selection, draggable):
957968
"""
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import QtQuick
2+
import QtQuick.Controls
3+
4+
import Utils 1.0
5+
import MaterialIcons 2.2
6+
7+
/**
8+
* ColorSelector is a color picker based on a set of predefined colors.
9+
* It takes the form of a ToolButton that pops-up its palette when pressed.
10+
*/
11+
MaterialToolButton {
12+
id: root
13+
14+
text: MaterialIcons.palette
15+
16+
// Internal property holding when the popup remains visible and when is it toggled off
17+
property var isVisible: false
18+
19+
property var colors: [
20+
"#FF6600",
21+
"#FFAD7D",
22+
"#FFF82F",
23+
"#FFFB8B",
24+
"#BDFF07",
25+
"#E8FF97",
26+
"#0BFFCA",
27+
"#8EFFF7",
28+
"#1158FF",
29+
"#77A7FF",
30+
"#9318FF",
31+
"#EAACFF",
32+
"#B61518",
33+
"#FF989A",
34+
]
35+
36+
// When a color gets selected/choosen
37+
signal colorSelected(var color)
38+
39+
// Toggles the visibility of the popup
40+
onPressed: toggle()
41+
42+
function toggle() {
43+
/*
44+
* Toggles the visibility of the color palette.
45+
*/
46+
if (!isVisible) {
47+
palettePopup.open()
48+
isVisible = true
49+
}
50+
else {
51+
palettePopup.close()
52+
isVisible = false
53+
}
54+
}
55+
56+
// Popup for the color palette
57+
Popup {
58+
id: palettePopup
59+
60+
// The popup will not get closed unless explicitly closed
61+
closePolicy: Popup.NoAutoClose
62+
63+
// Bounds
64+
padding: 4
65+
width: (root.height * 4) + (padding * 4)
66+
67+
// center the current color
68+
y: -height
69+
x: -width + root.width + padding
70+
71+
// Layout of the Colors
72+
Grid {
73+
// Allow only 4 columns and all the colors can be adjusted in row multiples of 4
74+
columns: 4
75+
76+
spacing: 2
77+
anchors.centerIn: parent
78+
79+
// Default -- Reset Colour button
80+
ToolButton {
81+
id: defaultButton
82+
padding: 0
83+
width: root.height
84+
height: root.height
85+
86+
// Emit no color so the graph sets None as the color of the Node
87+
onClicked: {
88+
root.colorSelected("")
89+
}
90+
91+
background: Rectangle {
92+
color: "#FFFFFF"
93+
// display border of current/selected item
94+
border.width: defaultButton.hovered ? 1 : 0
95+
border.color: "#000000"
96+
97+
// Another Rectangle
98+
Rectangle {
99+
color: "#FF0000"
100+
width: parent.width + 8
101+
height: 2
102+
anchors.centerIn: parent
103+
rotation: 135 // Diagonally creating a Red line from bottom left to top right
104+
}
105+
}
106+
}
107+
108+
// Colors palette
109+
Repeater {
110+
model: root.colors
111+
// display each color as a ToolButton with a custom background
112+
delegate: ToolButton {
113+
padding: 0
114+
width: root.height
115+
height: root.height
116+
117+
// Emit the model data as the color to update
118+
onClicked: {
119+
colorSelected(modelData)
120+
}
121+
122+
// Model color as the background of the button
123+
background: Rectangle {
124+
color: modelData
125+
// display border of current/selected item
126+
border.width: hovered ? 1 : 0
127+
border.color: "#000000"
128+
}
129+
}
130+
}
131+
}
132+
}
133+
}

meshroom/ui/qml/Controls/qmldir

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module Controls
22

33
ColorChart 1.0 ColorChart.qml
4+
ColorSelector 1.0 ColorSelector.qml
45
ExpandableGroup 1.0 ExpandableGroup.qml
56
FloatingPane 1.0 FloatingPane.qml
67
Group 1.0 Group.qml

meshroom/ui/qml/GraphEditor/GraphEditor.qml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ Item {
136136
Keys.onPressed: function(event) {
137137
if (event.key === Qt.Key_F) {
138138
fit()
139+
} else if (event.key === Qt.Key_C) {
140+
colorSelector.toggle()
139141
} else if (event.key === Qt.Key_Delete) {
140142
if (event.modifiers === Qt.AltModifier) {
141143
uigraph.removeNodesFrom(uigraph.selectedNodes)
@@ -1048,6 +1050,24 @@ Item {
10481050
}
10491051
}
10501052
}
1053+
1054+
// Separator
1055+
Rectangle {
1056+
Layout.fillHeight: true
1057+
Layout.margins: 2
1058+
implicitWidth: 1
1059+
color: activePalette.window
1060+
}
1061+
1062+
ColorSelector {
1063+
id: colorSelector
1064+
Layout.minimumWidth: colorSelector.width
1065+
1066+
// When a Color is selected
1067+
onColorSelected: (color)=> {
1068+
uigraph.updateNodeColor(color)
1069+
}
1070+
}
10511071
}
10521072
}
10531073

0 commit comments

Comments
 (0)