Merge branch '15.06'

* 15.06:
  Add a background to the tool additional controls
  Rescale the current layer number based on the maximum layer
  Add a text field style that can be used for generic text fields
  Implemented feature described by #30
  Handle finished signal for the ReadMeshJob started from command line args
  Updated name in menu for firmware update
  Added exception handling to listen thread join
  Render a transparent ghost of the selection when things are selected.
  Fix for #29
This commit is contained in:
Arjen Hiemstra 2015-06-08 16:41:46 +02:00
commit 8c12426760
8 changed files with 212 additions and 26 deletions

View file

@ -162,6 +162,7 @@ class CuraApplication(QtApplication):
for file in self.getCommandLineOption("file", []): for file in self.getCommandLineOption("file", []):
job = ReadMeshJob(os.path.abspath(file)) job = ReadMeshJob(os.path.abspath(file))
job.finished.connect(self._onFileLoaded)
job.start() job.start()
self.exec_() self.exec_()
@ -447,3 +448,15 @@ class CuraApplication(QtApplication):
def _onMessageActionTriggered(self, message, action): def _onMessageActionTriggered(self, message, action):
if action == "eject": if action == "eject":
self.getStorageDevice("LocalFileStorage").ejectRemovableDrive(message._sdcard) self.getStorageDevice("LocalFileStorage").ejectRemovableDrive(message._sdcard)
def _onFileLoaded(self, job):
mesh = job.getResult()
if mesh != None:
node = SceneNode()
node.setSelectable(True)
node.setMeshData(mesh)
node.setName(os.path.basename(job.getFileName()))
op = AddSceneNodeOperation(node, self.getController().getScene().getRoot())
op.push()

View file

@ -5,8 +5,11 @@ from UM.View.View import View
from UM.View.Renderer import Renderer from UM.View.Renderer import Renderer
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Resources import Resources from UM.Resources import Resources
from UM.Event import Event, KeyEvent
from UM.Signal import Signal
from UM.Scene.Selection import Selection from UM.Scene.Selection import Selection
from UM.Math.Color import Color from UM.Math.Color import Color
from . import LayerViewProxy
## View used to display g-code paths. ## View used to display g-code paths.
class LayerView(View): class LayerView(View):
@ -15,6 +18,19 @@ class LayerView(View):
self._material = None self._material = None
self._num_layers = 0 self._num_layers = 0
self._layer_percentage = 0 # what percentage of layers need to be shown (SLider gives value between 0 - 100) self._layer_percentage = 0 # what percentage of layers need to be shown (SLider gives value between 0 - 100)
self._proxy = LayerViewProxy.LayerViewProxy()
self._controller.getScene().sceneChanged.connect(self._onSceneChanged)
self._max_layers = 10
self._current_layer_num = 10
def getCurrentLayer(self):
return self._current_layer_num
def _onSceneChanged(self, node):
self.calculateMaxLayers()
def getMaxLayers(self):
return self._max_layers
def beginRendering(self): def beginRendering(self):
scene = self.getController().getScene() scene = self.getController().getScene()
@ -39,24 +55,69 @@ class LayerView(View):
except AttributeError: except AttributeError:
continue continue
if self._layer_percentage < 100:
start = 0 start = 0
end_layer = round(len(layer_data.getLayers()) * (self._layer_percentage / 100))
end = 0 end = 0
element_counts = layer_data.getElementCounts() element_counts = layer_data.getElementCounts()
for layer, counts in element_counts.items(): for layer, counts in element_counts.items():
end += sum(counts) end += sum(counts)
## Hack to ensure the end is correct. Not quite sure what causes this
end += 2 * len(counts)
if layer >= end_layer: if layer >= self._current_layer_num:
break break
renderer.queueNode(node, mesh = layer_data, material = self._material, mode = Renderer.RenderLines, start = start, end = end, overlay = True) renderer.queueNode(node, mesh = layer_data, material = self._material, mode = Renderer.RenderLines, start = start, end = end)
else:
renderer.queueNode(node, mesh = layer_data, material = self._material, mode = Renderer.RenderLines, overlay = True)
def setLayer(self, value): def setLayer(self, value):
self._layer_percentage = value if self._current_layer_num != value:
self._current_layer_num = value
if self._current_layer_num < 0:
self._current_layer_num = 0
if self._current_layer_num > self._max_layers:
self._current_layer_num = self._max_layers
self.currentLayerNumChanged.emit()
currentLayerNumChanged = Signal()
def calculateMaxLayers(self):
scene = self.getController().getScene()
renderer = self.getRenderer()
if renderer and self._material:
renderer.setRenderSelection(False)
self._old_max_layers = self._max_layers
## Recalculate num max layers
new_max_layers = 0
for node in DepthFirstIterator(scene.getRoot()):
if not node.render(renderer):
if node.getMeshData() and node.isVisible():
try:
layer_data = node.getMeshData().layerData
except AttributeError:
continue
if new_max_layers < len(layer_data.getLayers()):
new_max_layers = len(layer_data.getLayers())
if new_max_layers > 0 and new_max_layers != self._old_max_layers:
self._max_layers = new_max_layers
self.maxLayersChanged.emit()
# This makes sure we update the current layer
self.setLayer(int(self._max_layers * (self._current_layer_num / self._old_max_layers)))
maxLayersChanged = Signal()
## Hackish way to ensure the proxy is already created, which ensures that the layerview.qml is already created
# as this caused some issues.
def getProxy(self, engine, script_engine):
return self._proxy
def endRendering(self): def endRendering(self):
pass pass
def event(self, event):
if event.type == Event.KeyPressEvent:
if event.key == KeyEvent.UpKey:
self.setLayer(self._current_layer_num + 1)
if event.key == KeyEvent.DownKey:
self.setLayer(self._current_layer_num - 1)

View file

@ -20,10 +20,11 @@ Item
anchors.right : parent.right anchors.right : parent.right
orientation: Qt.Vertical orientation: Qt.Vertical
minimumValue: 0; minimumValue: 0;
maximumValue: 100; maximumValue: UM.LayerView.numLayers;
stepSize: 1
value: 100; value: UM.LayerView.currentLayer
onValueChanged: UM.ActiveView.triggerAction("setLayer", value) onValueChanged: UM.LayerView.setCurrentLayer(value)
style: UM.Theme.styles.slider; style: UM.Theme.styles.slider;
} }

View file

@ -0,0 +1,44 @@
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, pyqtProperty
from UM.Application import Application
import LayerView
class LayerViewProxy(QObject):
def __init__(self, parent = None):
super().__init__(parent)
self._current_layer = 0
self._controller = Application.getInstance().getController()
self._controller.activeViewChanged.connect(self._onActiveViewChanged)
self._onActiveViewChanged()
currentLayerChanged = pyqtSignal()
maxLayersChanged = pyqtSignal()
@pyqtProperty(int, notify = maxLayersChanged)
def numLayers(self):
active_view = self._controller.getActiveView()
#print("num max layers " , active_view.getMaxLayers())
return active_view.getMaxLayers()
#return 100
@pyqtProperty(int, notify = currentLayerChanged)
def currentLayer(self):
active_view = self._controller.getActiveView()
if type(active_view) == LayerView.LayerView.LayerView:
return active_view.getCurrentLayer()
@pyqtSlot(int)
def setCurrentLayer(self, layer_num):
active_view = self._controller.getActiveView()
if type(active_view) == LayerView.LayerView.LayerView:
active_view.setLayer(layer_num)
def _onLayerChanged(self):
self.currentLayerChanged.emit()
def _onMaxLayersChanged(self):
self.maxLayersChanged.emit()
def _onActiveViewChanged(self):
active_view = self._controller.getActiveView()
if type(active_view) == LayerView.LayerView.LayerView:
active_view.currentLayerNumChanged.connect(self._onLayerChanged)
active_view.maxLayersChanged.connect(self._onMaxLayersChanged)

View file

@ -1,7 +1,8 @@
# Copyright (c) 2015 Ultimaker B.V. # Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
from . import LayerView from . import LayerView, LayerViewProxy
from PyQt5.QtQml import qmlRegisterType, qmlRegisterSingletonType
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
@ -21,6 +22,10 @@ def getMetaData():
} }
} }
def createLayerViewProxy(engine, script_engine):
return LayerViewProxy.LayerViewProxy()
def register(app): def register(app):
layer_view = LayerView.LayerView()
qmlRegisterSingletonType(LayerViewProxy.LayerViewProxy, "UM", 1, 0, "LayerView", layer_view.getProxy)
return { "view": LayerView.LayerView() } return { "view": LayerView.LayerView() }

View file

@ -14,6 +14,23 @@ Item {
width: buttons.width; width: buttons.width;
height: buttons.height + panel.height; height: buttons.height + panel.height;
Rectangle {
id: activeItemBackground;
anchors.bottom: parent.bottom;
width: UM.Theme.sizes.button.width;
height: UM.Theme.sizes.button.height * 2;
opacity: panelBackground.opacity;
color: UM.Theme.colors.tool_panel_background
function setActive(new_x) {
x = new_x;
}
}
RowLayout { RowLayout {
id: buttons; id: buttons;
@ -34,6 +51,7 @@ Item {
checkable: true; checkable: true;
checked: model.active; checked: model.active;
onCheckedChanged: if (checked) activeItemBackground.setActive(x);
style: UM.Theme.styles.tool_button; style: UM.Theme.styles.tool_button;
@ -42,21 +60,35 @@ Item {
MouseArea { MouseArea {
anchors.fill: parent; anchors.fill: parent;
onClicked: parent.checked ? UM.Controller.setActiveTool(null) : UM.Controller.setActiveTool(model.id); onClicked: parent.checked ? UM.Controller.setActiveTool(null) : UM.Controller.setActiveTool(model.id);
} }
} }
} }
} }
UM.AngledCornerRectangle {
id: panelBackground;
anchors.left: parent.left;
anchors.bottom: buttons.top;
anchors.bottomMargin: UM.Theme.sizes.default_margin.height;
width: panel.item ? panel.width + 2 * UM.Theme.sizes.default_margin.width : 0;
height: panel.item ? panel.height + 2 * UM.Theme.sizes.default_margin.height : 0;
opacity: panel.item ? 1 : 0
Behavior on opacity { NumberAnimation { duration: 100 } }
color: UM.Theme.colors.tool_panel_background;
cornerSize: width > 0 ? UM.Theme.sizes.default_margin.width : 0;
Loader { Loader {
id: panel id: panel
anchors.left: parent.left; x: UM.Theme.sizes.default_margin.width;
anchors.right: parent.right; y: UM.Theme.sizes.default_margin.height;
anchors.bottom: buttons.top;
anchors.bottomMargin: UM.Theme.sizes.default_margin.height;
height: childrenRect.height;
source: UM.ActiveTool.valid ? UM.ActiveTool.activeToolPanel : ""; source: UM.ActiveTool.valid ? UM.ActiveTool.activeToolPanel : "";
} }
}
} }

View file

@ -246,4 +246,32 @@ QtObject {
} }
} }
} }
property Component text_field: Component {
TextFieldStyle {
textColor: UM.Theme.colors.setting_control_text;
font: UM.Theme.fonts.default;
background: Rectangle
{
implicitHeight: control.height;
implicitWidth: control.width;
border.width: 1;
border.color: UM.Theme.colors.setting_control_border;
color: UM.Theme.colors.setting_validation_ok;
Label {
anchors.right: parent.right;
anchors.rightMargin: UM.Theme.sizes.setting_unit_margin.width;
anchors.verticalCenter: parent.verticalCenter;
text: control.unit ? control.unit : ""
color: UM.Theme.colors.setting_unit;
font: UM.Theme.fonts.default;
}
}
}
}
} }

View file

@ -110,7 +110,9 @@
"save_button_text": [35, 35, 35, 255], "save_button_text": [35, 35, 35, 255],
"message": [205, 202, 201, 255], "message": [205, 202, 201, 255],
"message_text": [35, 35, 35, 255] "message_text": [35, 35, 35, 255],
"tool_panel_background": [255, 255, 255, 255]
}, },
"sizes": { "sizes": {