forked from qt-creator/qt-creator
EffectComposer: Fix effect preview zoom
Zoom must scale the component showing the preview, not the source image. This way the effect stays consistent regardless of the zoom level. Fixes: QDS-11899 Change-Id: I550eb9ff693c24a853f5c25d9d79fa146448663f Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
@@ -22,11 +22,13 @@ Column {
|
||||
|
||||
readonly property int previewMargin: 5
|
||||
|
||||
property real previewScale: 1
|
||||
|
||||
// Create a dummy parent to host the effect qml object
|
||||
function createNewComponent() {
|
||||
// If we have a working effect, do not show preview image as it shows through
|
||||
// transparent parts of the final image
|
||||
source.visible = false;
|
||||
placeHolder.visible = false;
|
||||
|
||||
var oldComponent = componentParent.children[0];
|
||||
if (oldComponent)
|
||||
@@ -48,7 +50,7 @@ Column {
|
||||
errorLine = e.lineNumber;
|
||||
}
|
||||
effectComposerModel.setEffectError(errorString, 0, errorLine);
|
||||
source.visible = true;
|
||||
placeHolder.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,42 +86,42 @@ Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
HelperWidgets.AbstractButton {
|
||||
enabled: sourceImage.scale < 3
|
||||
enabled: root.previewScale < 3
|
||||
style: StudioTheme.Values.viewBarButtonStyle
|
||||
buttonIcon: StudioTheme.Constants.zoomIn_medium
|
||||
tooltip: qsTr("Zoom In")
|
||||
|
||||
onClicked: {
|
||||
sourceImage.enableAnim(true)
|
||||
sourceImage.scale += .2
|
||||
sourceImage.enableAnim(false)
|
||||
imageScaler.enableAnim(true)
|
||||
root.previewScale += .2
|
||||
imageScaler.enableAnim(false)
|
||||
zoomIndicator.show()
|
||||
}
|
||||
}
|
||||
|
||||
HelperWidgets.AbstractButton {
|
||||
enabled: sourceImage.scale > .4
|
||||
enabled: root.previewScale > .4
|
||||
style: StudioTheme.Values.viewBarButtonStyle
|
||||
buttonIcon: StudioTheme.Constants.zoomOut_medium
|
||||
tooltip: qsTr("Zoom out")
|
||||
|
||||
onClicked: {
|
||||
sourceImage.enableAnim(true)
|
||||
sourceImage.scale -= .2
|
||||
sourceImage.enableAnim(false)
|
||||
imageScaler.enableAnim(true)
|
||||
root.previewScale -= .2
|
||||
imageScaler.enableAnim(false)
|
||||
zoomIndicator.show()
|
||||
}
|
||||
}
|
||||
|
||||
HelperWidgets.AbstractButton {
|
||||
enabled: sourceImage.scale !== 1 || sourceImage.x !== root.previewMargin
|
||||
|| sourceImage.y !== root.previewMargin
|
||||
enabled: root.previewScale !== 1 || imageScaler.x !== root.previewMargin
|
||||
|| imageScaler.y !== root.previewMargin
|
||||
style: StudioTheme.Values.viewBarButtonStyle
|
||||
buttonIcon: StudioTheme.Constants.fitAll_medium
|
||||
tooltip: qsTr("Reset View")
|
||||
|
||||
onClicked: {
|
||||
sourceImage.resetTransforms()
|
||||
imageScaler.resetTransforms()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,8 +189,8 @@ Column {
|
||||
property bool panning: false
|
||||
|
||||
onPressed: {
|
||||
pressX = mouseX - sourceImage.x
|
||||
pressY = mouseY - sourceImage.y
|
||||
pressX = mouseX - imageScaler.x
|
||||
pressY = mouseY - imageScaler.y
|
||||
panning = true
|
||||
}
|
||||
|
||||
@@ -197,22 +199,21 @@ Column {
|
||||
}
|
||||
|
||||
onWheel: (wheel) => {
|
||||
let prevScale = sourceImage.scale
|
||||
let oldPoint = imageScaler.mapFromItem(mouseArea, Qt.point(wheel.x, wheel.y))
|
||||
|
||||
if (wheel.angleDelta.y > 0) {
|
||||
if (sourceImage.scale < 3)
|
||||
sourceImage.scale += .2
|
||||
if (root.previewScale < 3)
|
||||
root.previewScale += .2
|
||||
} else {
|
||||
if (sourceImage.scale > .4)
|
||||
sourceImage.scale -= .2
|
||||
if (root.previewScale > .4)
|
||||
root.previewScale -= .2
|
||||
}
|
||||
|
||||
let dScale = sourceImage.scale - prevScale
|
||||
let newPoint = imageScaler.mapFromItem(mouseArea, Qt.point(wheel.x, wheel.y))
|
||||
imageScaler.x -= (oldPoint.x - newPoint.x) * imageScaler.scale
|
||||
imageScaler.y -= (oldPoint.y - newPoint.y) * imageScaler.scale
|
||||
|
||||
sourceImage.x += (sourceImage.x + sourceImage.width * .5 - wheel.x) * dScale;
|
||||
sourceImage.y += (sourceImage.y + sourceImage.height * .5 - wheel.y) * dScale;
|
||||
|
||||
sourceImage.checkBounds()
|
||||
imageScaler.checkBounds()
|
||||
zoomIndicator.show()
|
||||
}
|
||||
|
||||
@@ -222,98 +223,40 @@ Column {
|
||||
repeat: true
|
||||
|
||||
onTriggered: {
|
||||
sourceImage.x = mouseArea.mouseX - mouseArea.pressX
|
||||
sourceImage.y = mouseArea.mouseY - mouseArea.pressY
|
||||
sourceImage.checkBounds()
|
||||
imageScaler.x = mouseArea.mouseX - mouseArea.pressX
|
||||
imageScaler.y = mouseArea.mouseY - mouseArea.pressY
|
||||
imageScaler.checkBounds()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: placeHolder
|
||||
anchors.fill: parent
|
||||
anchors.margins: root.previewMargin
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: imagesComboBox.selectedImage
|
||||
smooth: true
|
||||
}
|
||||
|
||||
Item { // Source item as a canvas (render target) for effect
|
||||
id: source
|
||||
anchors.fill: parent
|
||||
width: sourceImage.sourceSize.width
|
||||
height: sourceImage.sourceSize.height
|
||||
layer.enabled: true
|
||||
layer.mipmap: true
|
||||
layer.smooth: true
|
||||
visible: false
|
||||
|
||||
Image {
|
||||
id: sourceImage
|
||||
|
||||
function checkBounds() {
|
||||
let edgeMargin = 10
|
||||
// correction factor to account for an observation that edgeMargin decreases
|
||||
// with increased zoom
|
||||
let corrFactor = 10 * sourceImage.scale
|
||||
let imgW2 = sourceImage.paintedWidth * sourceImage.scale * .5
|
||||
let imgH2 = sourceImage.paintedHeight * sourceImage.scale * .5
|
||||
let srcW2 = source.width * .5
|
||||
let srcH2 = source.height * .5
|
||||
onSourceChanged: imageScaler.resetTransforms()
|
||||
|
||||
if (sourceImage.x < -srcW2 - imgW2 + edgeMargin + corrFactor)
|
||||
sourceImage.x = -srcW2 - imgW2 + edgeMargin + corrFactor
|
||||
else if (x > srcW2 + imgW2 - edgeMargin - corrFactor)
|
||||
sourceImage.x = srcW2 + imgW2 - edgeMargin - corrFactor
|
||||
fillMode: Image.Pad
|
||||
|
||||
if (sourceImage.y < -srcH2 - imgH2 + edgeMargin + corrFactor)
|
||||
sourceImage.y = -srcH2 - imgH2 + edgeMargin + corrFactor
|
||||
else if (y > srcH2 + imgH2 - edgeMargin - corrFactor)
|
||||
sourceImage.y = srcH2 + imgH2 - edgeMargin - corrFactor
|
||||
}
|
||||
|
||||
function resetTransforms() {
|
||||
sourceImage.enableAnim(true)
|
||||
sourceImage.scale = 1
|
||||
sourceImage.x = root.previewMargin
|
||||
sourceImage.y = root.previewMargin
|
||||
sourceImage.enableAnim(false)
|
||||
}
|
||||
|
||||
function enableAnim(flag) {
|
||||
xBehavior.enabled = flag
|
||||
yBehavior.enabled = flag
|
||||
scaleBehavior.enabled = flag
|
||||
}
|
||||
|
||||
onSourceChanged: sourceImage.resetTransforms()
|
||||
|
||||
fillMode: Image.PreserveAspectFit
|
||||
|
||||
x: root.previewMargin
|
||||
y: root.previewMargin
|
||||
width: parent.width - root.previewMargin * 2
|
||||
height: parent.height - root.previewMargin * 2
|
||||
source: imagesComboBox.selectedImage
|
||||
smooth: true
|
||||
|
||||
Behavior on x {
|
||||
id: xBehavior
|
||||
|
||||
enabled: false
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on y {
|
||||
id: yBehavior
|
||||
|
||||
enabled: false
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
id: scaleBehavior
|
||||
|
||||
enabled: false
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,14 +268,90 @@ Column {
|
||||
}
|
||||
|
||||
Item {
|
||||
id: componentParent
|
||||
width: source.width
|
||||
height: source.height
|
||||
anchors.centerIn: parent
|
||||
// Cache the layer. This way heavy shaders rendering doesn't
|
||||
// slow down code editing & rest of the UI.
|
||||
layer.enabled: true
|
||||
layer.smooth: true
|
||||
id: imageScaler
|
||||
x: root.previewMargin
|
||||
y: root.previewMargin
|
||||
width: parent.width - root.previewMargin * 2
|
||||
height: parent.height - root.previewMargin * 2
|
||||
|
||||
scale: root.previewScale * (width > height ? height / sourceImage.sourceSize.height
|
||||
: width / sourceImage.sourceSize.width)
|
||||
|
||||
Behavior on x {
|
||||
id: xBehavior
|
||||
|
||||
enabled: false
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on y {
|
||||
id: yBehavior
|
||||
|
||||
enabled: false
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
id: scaleBehavior
|
||||
|
||||
enabled: false
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
}
|
||||
|
||||
function checkBounds() {
|
||||
let edgeMargin = 10
|
||||
// correction factor to account for an observation that edgeMargin decreases
|
||||
// with increased zoom
|
||||
let corrFactor = 10 * imageScaler.scale
|
||||
let imgW2 = sourceImage.paintedWidth * imageScaler.scale * .5
|
||||
let imgH2 = sourceImage.paintedHeight * imageScaler.scale * .5
|
||||
let srcW2 = width * .5
|
||||
let srcH2 = height * .5
|
||||
|
||||
if (imageScaler.x < -srcW2 - imgW2 + edgeMargin + corrFactor)
|
||||
imageScaler.x = -srcW2 - imgW2 + edgeMargin + corrFactor
|
||||
else if (x > srcW2 + imgW2 - edgeMargin - corrFactor)
|
||||
imageScaler.x = srcW2 + imgW2 - edgeMargin - corrFactor
|
||||
|
||||
if (imageScaler.y < -srcH2 - imgH2 + edgeMargin + corrFactor)
|
||||
imageScaler.y = -srcH2 - imgH2 + edgeMargin + corrFactor
|
||||
else if (y > srcH2 + imgH2 - edgeMargin - corrFactor)
|
||||
imageScaler.y = srcH2 + imgH2 - edgeMargin - corrFactor
|
||||
}
|
||||
|
||||
function resetTransforms() {
|
||||
imageScaler.enableAnim(true)
|
||||
root.previewScale = 1
|
||||
imageScaler.x = root.previewMargin
|
||||
imageScaler.y = root.previewMargin
|
||||
imageScaler.enableAnim(false)
|
||||
}
|
||||
|
||||
function enableAnim(flag) {
|
||||
xBehavior.enabled = flag
|
||||
yBehavior.enabled = flag
|
||||
scaleBehavior.enabled = flag
|
||||
}
|
||||
|
||||
Item {
|
||||
id: componentParent
|
||||
width: source.width
|
||||
height: source.height
|
||||
anchors.centerIn: parent
|
||||
// Cache the layer. This way heavy shaders rendering doesn't
|
||||
// slow down code editing & rest of the UI.
|
||||
layer.enabled: true
|
||||
layer.smooth: true
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -349,7 +368,7 @@ Column {
|
||||
}
|
||||
|
||||
Text {
|
||||
text: Math.round(sourceImage.scale * 100) + "%"
|
||||
text: Math.round(root.previewScale * 100) + "%"
|
||||
color: StudioTheme.Values.themeTextColor
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
@@ -178,7 +178,7 @@ private:
|
||||
QList<CompositionNode *> m_nodes;
|
||||
|
||||
int m_selectedIndex = -1;
|
||||
bool m_isEmpty = true;
|
||||
bool m_isEmpty = false; // Init to false to force initial bake after setup
|
||||
bool m_hasUnsavedChanges = false;
|
||||
// True when shaders haven't changed since last baking
|
||||
bool m_shadersUpToDate = true;
|
||||
|
Reference in New Issue
Block a user