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
|
readonly property int previewMargin: 5
|
||||||
|
|
||||||
|
property real previewScale: 1
|
||||||
|
|
||||||
// Create a dummy parent to host the effect qml object
|
// Create a dummy parent to host the effect qml object
|
||||||
function createNewComponent() {
|
function createNewComponent() {
|
||||||
// If we have a working effect, do not show preview image as it shows through
|
// If we have a working effect, do not show preview image as it shows through
|
||||||
// transparent parts of the final image
|
// transparent parts of the final image
|
||||||
source.visible = false;
|
placeHolder.visible = false;
|
||||||
|
|
||||||
var oldComponent = componentParent.children[0];
|
var oldComponent = componentParent.children[0];
|
||||||
if (oldComponent)
|
if (oldComponent)
|
||||||
@@ -48,7 +50,7 @@ Column {
|
|||||||
errorLine = e.lineNumber;
|
errorLine = e.lineNumber;
|
||||||
}
|
}
|
||||||
effectComposerModel.setEffectError(errorString, 0, errorLine);
|
effectComposerModel.setEffectError(errorString, 0, errorLine);
|
||||||
source.visible = true;
|
placeHolder.visible = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,42 +86,42 @@ Column {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
HelperWidgets.AbstractButton {
|
HelperWidgets.AbstractButton {
|
||||||
enabled: sourceImage.scale < 3
|
enabled: root.previewScale < 3
|
||||||
style: StudioTheme.Values.viewBarButtonStyle
|
style: StudioTheme.Values.viewBarButtonStyle
|
||||||
buttonIcon: StudioTheme.Constants.zoomIn_medium
|
buttonIcon: StudioTheme.Constants.zoomIn_medium
|
||||||
tooltip: qsTr("Zoom In")
|
tooltip: qsTr("Zoom In")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
sourceImage.enableAnim(true)
|
imageScaler.enableAnim(true)
|
||||||
sourceImage.scale += .2
|
root.previewScale += .2
|
||||||
sourceImage.enableAnim(false)
|
imageScaler.enableAnim(false)
|
||||||
zoomIndicator.show()
|
zoomIndicator.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperWidgets.AbstractButton {
|
HelperWidgets.AbstractButton {
|
||||||
enabled: sourceImage.scale > .4
|
enabled: root.previewScale > .4
|
||||||
style: StudioTheme.Values.viewBarButtonStyle
|
style: StudioTheme.Values.viewBarButtonStyle
|
||||||
buttonIcon: StudioTheme.Constants.zoomOut_medium
|
buttonIcon: StudioTheme.Constants.zoomOut_medium
|
||||||
tooltip: qsTr("Zoom out")
|
tooltip: qsTr("Zoom out")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
sourceImage.enableAnim(true)
|
imageScaler.enableAnim(true)
|
||||||
sourceImage.scale -= .2
|
root.previewScale -= .2
|
||||||
sourceImage.enableAnim(false)
|
imageScaler.enableAnim(false)
|
||||||
zoomIndicator.show()
|
zoomIndicator.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperWidgets.AbstractButton {
|
HelperWidgets.AbstractButton {
|
||||||
enabled: sourceImage.scale !== 1 || sourceImage.x !== root.previewMargin
|
enabled: root.previewScale !== 1 || imageScaler.x !== root.previewMargin
|
||||||
|| sourceImage.y !== root.previewMargin
|
|| imageScaler.y !== root.previewMargin
|
||||||
style: StudioTheme.Values.viewBarButtonStyle
|
style: StudioTheme.Values.viewBarButtonStyle
|
||||||
buttonIcon: StudioTheme.Constants.fitAll_medium
|
buttonIcon: StudioTheme.Constants.fitAll_medium
|
||||||
tooltip: qsTr("Reset View")
|
tooltip: qsTr("Reset View")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
sourceImage.resetTransforms()
|
imageScaler.resetTransforms()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -187,8 +189,8 @@ Column {
|
|||||||
property bool panning: false
|
property bool panning: false
|
||||||
|
|
||||||
onPressed: {
|
onPressed: {
|
||||||
pressX = mouseX - sourceImage.x
|
pressX = mouseX - imageScaler.x
|
||||||
pressY = mouseY - sourceImage.y
|
pressY = mouseY - imageScaler.y
|
||||||
panning = true
|
panning = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,22 +199,21 @@ Column {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onWheel: (wheel) => {
|
onWheel: (wheel) => {
|
||||||
let prevScale = sourceImage.scale
|
let oldPoint = imageScaler.mapFromItem(mouseArea, Qt.point(wheel.x, wheel.y))
|
||||||
|
|
||||||
if (wheel.angleDelta.y > 0) {
|
if (wheel.angleDelta.y > 0) {
|
||||||
if (sourceImage.scale < 3)
|
if (root.previewScale < 3)
|
||||||
sourceImage.scale += .2
|
root.previewScale += .2
|
||||||
} else {
|
} else {
|
||||||
if (sourceImage.scale > .4)
|
if (root.previewScale > .4)
|
||||||
sourceImage.scale -= .2
|
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;
|
imageScaler.checkBounds()
|
||||||
sourceImage.y += (sourceImage.y + sourceImage.height * .5 - wheel.y) * dScale;
|
|
||||||
|
|
||||||
sourceImage.checkBounds()
|
|
||||||
zoomIndicator.show()
|
zoomIndicator.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,68 +223,59 @@ Column {
|
|||||||
repeat: true
|
repeat: true
|
||||||
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
sourceImage.x = mouseArea.mouseX - mouseArea.pressX
|
imageScaler.x = mouseArea.mouseX - mouseArea.pressX
|
||||||
sourceImage.y = mouseArea.mouseY - mouseArea.pressY
|
imageScaler.y = mouseArea.mouseY - mouseArea.pressY
|
||||||
sourceImage.checkBounds()
|
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
|
Item { // Source item as a canvas (render target) for effect
|
||||||
id: source
|
id: source
|
||||||
anchors.fill: parent
|
width: sourceImage.sourceSize.width
|
||||||
|
height: sourceImage.sourceSize.height
|
||||||
layer.enabled: true
|
layer.enabled: true
|
||||||
layer.mipmap: true
|
layer.mipmap: true
|
||||||
layer.smooth: true
|
layer.smooth: true
|
||||||
|
visible: false
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: sourceImage
|
id: sourceImage
|
||||||
|
|
||||||
function checkBounds() {
|
onSourceChanged: imageScaler.resetTransforms()
|
||||||
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
|
|
||||||
|
|
||||||
if (sourceImage.x < -srcW2 - imgW2 + edgeMargin + corrFactor)
|
fillMode: Image.Pad
|
||||||
sourceImage.x = -srcW2 - imgW2 + edgeMargin + corrFactor
|
|
||||||
else if (x > srcW2 + imgW2 - edgeMargin - corrFactor)
|
|
||||||
sourceImage.x = srcW2 + imgW2 - edgeMargin - corrFactor
|
|
||||||
|
|
||||||
if (sourceImage.y < -srcH2 - imgH2 + edgeMargin + corrFactor)
|
source: imagesComboBox.selectedImage
|
||||||
sourceImage.y = -srcH2 - imgH2 + edgeMargin + corrFactor
|
smooth: true
|
||||||
else if (y > srcH2 + imgH2 - edgeMargin - corrFactor)
|
}
|
||||||
sourceImage.y = srcH2 + imgH2 - edgeMargin - corrFactor
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetTransforms() {
|
BlurHelper {
|
||||||
sourceImage.enableAnim(true)
|
id: blurHelper
|
||||||
sourceImage.scale = 1
|
source: source
|
||||||
sourceImage.x = root.previewMargin
|
property int blurMax: g_propertyData.blur_helper_max_level ? g_propertyData.blur_helper_max_level : 64
|
||||||
sourceImage.y = root.previewMargin
|
property real blurMultiplier: g_propertyData.blurMultiplier ? g_propertyData.blurMultiplier : 0
|
||||||
sourceImage.enableAnim(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function enableAnim(flag) {
|
Item {
|
||||||
xBehavior.enabled = flag
|
id: imageScaler
|
||||||
yBehavior.enabled = flag
|
|
||||||
scaleBehavior.enabled = flag
|
|
||||||
}
|
|
||||||
|
|
||||||
onSourceChanged: sourceImage.resetTransforms()
|
|
||||||
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
|
|
||||||
x: root.previewMargin
|
x: root.previewMargin
|
||||||
y: root.previewMargin
|
y: root.previewMargin
|
||||||
width: parent.width - root.previewMargin * 2
|
width: parent.width - root.previewMargin * 2
|
||||||
height: parent.height - root.previewMargin * 2
|
height: parent.height - root.previewMargin * 2
|
||||||
source: imagesComboBox.selectedImage
|
|
||||||
smooth: true
|
scale: root.previewScale * (width > height ? height / sourceImage.sourceSize.height
|
||||||
|
: width / sourceImage.sourceSize.width)
|
||||||
|
|
||||||
Behavior on x {
|
Behavior on x {
|
||||||
id: xBehavior
|
id: xBehavior
|
||||||
@@ -314,14 +306,40 @@ Column {
|
|||||||
easing.type: Easing.OutQuad
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
BlurHelper {
|
function resetTransforms() {
|
||||||
id: blurHelper
|
imageScaler.enableAnim(true)
|
||||||
source: source
|
root.previewScale = 1
|
||||||
property int blurMax: g_propertyData.blur_helper_max_level ? g_propertyData.blur_helper_max_level : 64
|
imageScaler.x = root.previewMargin
|
||||||
property real blurMultiplier: g_propertyData.blurMultiplier ? g_propertyData.blurMultiplier : 0
|
imageScaler.y = root.previewMargin
|
||||||
|
imageScaler.enableAnim(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
function enableAnim(flag) {
|
||||||
|
xBehavior.enabled = flag
|
||||||
|
yBehavior.enabled = flag
|
||||||
|
scaleBehavior.enabled = flag
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
@@ -334,6 +352,7 @@ Column {
|
|||||||
layer.enabled: true
|
layer.enabled: true
|
||||||
layer.smooth: true
|
layer.smooth: true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: zoomIndicator
|
id: zoomIndicator
|
||||||
@@ -349,7 +368,7 @@ Column {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: Math.round(sourceImage.scale * 100) + "%"
|
text: Math.round(root.previewScale * 100) + "%"
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
}
|
}
|
||||||
|
@@ -178,7 +178,7 @@ private:
|
|||||||
QList<CompositionNode *> m_nodes;
|
QList<CompositionNode *> m_nodes;
|
||||||
|
|
||||||
int m_selectedIndex = -1;
|
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;
|
bool m_hasUnsavedChanges = false;
|
||||||
// True when shaders haven't changed since last baking
|
// True when shaders haven't changed since last baking
|
||||||
bool m_shadersUpToDate = true;
|
bool m_shadersUpToDate = true;
|
||||||
|
Reference in New Issue
Block a user