ImageViewer.qml 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // Copyright (C) 2025 The Qt Company Ltd.
  2. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
  3. import QtQuick
  4. import LightmapFile 1.0
  5. Rectangle {
  6. id: scrollView
  7. clip: true
  8. color: "black"
  9. property real lastMouseX: 0
  10. property real lastMouseY: 0
  11. function clamp() {
  12. // If the image is smaller than the scroll view, center it
  13. if (image.width <= scrollView.width) {
  14. imageCenterX = 0
  15. } else {
  16. const maxOffsetX = (image.width - scrollView.width) / 2
  17. imageCenterX = Math.max(-maxOffsetX,
  18. Math.min(imageCenterX,
  19. maxOffsetX))
  20. }
  21. if (image.height <= scrollView.height) {
  22. imageCenterY = 0
  23. } else {
  24. const maxOffsetY = (image.height - scrollView.height) / 2
  25. imageCenterY = Math.max(-maxOffsetY,
  26. Math.min(imageCenterY,
  27. maxOffsetY))
  28. }
  29. }
  30. onWidthChanged: clamp()
  31. onHeightChanged: clamp()
  32. Connections {
  33. target: window
  34. function onSelectedEntryChanged() {
  35. if (imageLoader.item === scrollView) {
  36. imageZoom = 1
  37. imageCenterX = 0
  38. imageCenterY = 0
  39. }
  40. }
  41. }
  42. MouseArea {
  43. id: mouseArea
  44. property bool dragging: false
  45. anchors.fill: parent
  46. onPressed: mouse => {
  47. scrollView.lastMouseX = mouse.x
  48. scrollView.lastMouseY = mouse.y
  49. dragging = true
  50. }
  51. onReleased: mouse => {
  52. dragging = false
  53. }
  54. onPositionChanged: mouse => {
  55. var dx = mouse.x - scrollView.lastMouseX
  56. var dy = mouse.y - scrollView.lastMouseY
  57. scrollView.lastMouseX = mouse.x
  58. scrollView.lastMouseY = mouse.y
  59. imageCenterX += dx
  60. imageCenterY += dy
  61. clamp()
  62. }
  63. cursorShape: mouseArea.dragging ? Qt.ClosedHandCursor : Qt.ArrowCursor
  64. onWheel: event => {
  65. const oldZoom = imageZoom
  66. const zoomDelta = event.angleDelta.y / 256
  67. const newZoom = Math.max(
  68. 1, Math.min(32, oldZoom + zoomDelta))
  69. if (newZoom === oldZoom)
  70. return
  71. // Adjust center offset so the same point remains at the center
  72. const scaleFactor = newZoom / oldZoom
  73. imageCenterX *= scaleFactor
  74. imageCenterY *= scaleFactor
  75. imageZoom = newZoom
  76. clamp()
  77. event.accepted = true
  78. }
  79. }
  80. Image {
  81. id: baseGrid
  82. anchors.fill: scrollView
  83. source: "grid.png"
  84. fillMode: Image.Tile
  85. opacity: 0.75
  86. }
  87. Rectangle {
  88. width: image.width + (border.width * 2)
  89. height: image.height + (border.width * 2)
  90. x: image.x - border.width
  91. y: image.y - border.width
  92. color: "white" // This is the border color
  93. border.width: 0
  94. border.color: "white"
  95. opacity: 0.25
  96. visible: window.isImage(window.selectedEntry)
  97. }
  98. Image {
  99. id: image
  100. x: Math.round(parent.width / 2 - width / 2) + imageCenterX
  101. y: Math.round(parent.height / 2 - height / 2) + imageCenterY
  102. source: window.isImage(
  103. window.selectedEntry) ? `image://lightmaps/key=${selectedEntry.key}&tag=${selectedEntry.tag}&file=${LightmapFile.source}&alpha=${alphaSwitch.checked}` : ""
  104. onWidthChanged: clamp()
  105. onHeightChanged: clamp()
  106. fillMode: Image.PreserveAspectFit
  107. smooth: false
  108. antialiasing: false
  109. // Let the image scale visibly
  110. width: sourceSize.width * imageZoom
  111. height: sourceSize.height * imageZoom
  112. }
  113. }