9#include <spdlog/spdlog.h>
22 spdlog::debug(
"[ViewportManager::ViewportManager]: Created");
35 if (!viewport_logical.isValid() || viewport_logical.isEmpty()) {
36 spdlog::error(
"[ViewportManager::initialize]: Invalid viewport size");
41 spdlog::error(
"[ViewportManager::initialize]: Invalid screen info");
49 m_viewport_logical = viewport_logical;
58 m_viewport_physical = QSize(
59 static_cast<int>(std::round(viewport_logical.width() * screen.
dpr)),
60 static_cast<int>(std::round(viewport_logical.height() * screen.
dpr))
75 updateMaxDownsample();
87 spdlog::info(
"[ViewportManager::initialize]: Initialized:");
88 spdlog::info(
"[ViewportManager::initialize]: Screen: {}x{}, DPR: {:.2f}",
90 spdlog::info(
"[ViewportManager::initialize]: Viewport: {}x{} (physical: {}x{})",
91 m_viewport_logical.width(), m_viewport_logical.height(),
92 m_viewport_physical.width(), m_viewport_physical.height());
93 spdlog::info(
"[ViewportManager::initialize]: Plafond: {}px, Max downsample: {}px",
94 m_plafond, m_max_downsample);
101 if (!viewport_logical.isValid() || viewport_logical.isEmpty()) {
102 spdlog::warn(
"[ViewportManager::setViewportSize]: Invalid viewport size");
106 if (m_viewport_logical == viewport_logical) {
110 m_viewport_logical = viewport_logical;
111 m_viewport_physical = QSize(
112 static_cast<int>(std::round(viewport_logical.width() * m_screen.
dpr)),
113 static_cast<int>(std::round(viewport_logical.height() * m_screen.
dpr))
116 updateMaxDownsample();
118 spdlog::debug(
"[ViewportManager::setViewportSize]: Viewport resized: {}x{}",
119 m_viewport_logical.width(), m_viewport_logical.height());
129 updateMaxDownsample();
132 spdlog::debug(
"[ViewportManager::setQualityMargin]: Quality margin: {:.2f}", m_quality_margin);
138 spdlog::info(
"[ViewportManager::setMaxDownsample]: Max downsample set: {}px", m_max_downsample);
154 if (!source_size.isValid() || source_size.isEmpty()) {
155 spdlog::warn(
"[ViewportManager::calculateDisplay]: Invalid source size");
159 if (!m_initialized) {
160 spdlog::warn(
"[ViewportManager::calculateDisplay]: Not initialized");
164 const int src_w = source_size.width();
165 const int src_h = source_size.height();
181 static_cast<int>(std::round(src_w * result.
fit_zoom)),
182 static_cast<int>(std::round(src_h * result.
fit_zoom))
209 spdlog::debug(
"[ViewportManager::calculateDisplay]: Display calc: source={}x{}, display={}x{}, downsample={}x{}, fit_zoom={:.3f}",
224 if (!source_size.isValid() || source_size.isEmpty()) {
228 if (!m_viewport_logical.isValid() || m_viewport_logical.isEmpty()) {
236 const float scale_x {
static_cast<float>(m_viewport_logical.width()) /
237 static_cast<float>(source_size.width()) };
238 const float scale_y {
static_cast<float>(m_viewport_logical.height()) /
239 static_cast<float>(source_size.height()) };
245 float fit_zoom { std::min(scale_x, scale_y) };
251 return std::min(fit_zoom, 1.0f);
260 if (!source_size.isValid() || source_size.isEmpty()) {
264 const int src_w { source_size.width() };
265 const int src_h { source_size.height() };
272 if (src_w <= m_max_downsample && src_h <= m_max_downsample) {
273 spdlog::trace(
"[ViewportManager::calculateDownsampleSize]: No downsample needed (source {}x{} <= max {})",
274 src_w, src_h, m_max_downsample);
283 const float scale {
static_cast<float>(m_max_downsample) /
284 static_cast<float>(std::max(src_w, src_h)) };
286 const int down_w {
static_cast<int>(std::round(src_w * scale)) };
287 const int down_h {
static_cast<int>(std::round(src_h * scale)) };
289 return QSize(down_w, down_h);
300 if (!display_size.isValid() || !m_viewport_logical.isValid()) {
315 (m_viewport_logical.width() - display_size.width()) / 2.0f,
316 (m_viewport_logical.height() - display_size.height()) / 2.0f
328void ViewportManager::updateMaxDownsample()
334 const int viewport_max { std::max(m_viewport_physical.width(),
335 m_viewport_physical.height()) };
336 const int with_margin {
static_cast<int>(std::round(viewport_max * m_quality_margin)) };
343 m_max_downsample = std::min(with_margin, m_plafond);
351 spdlog::debug(
"[ViewportManager::updateMaxDownsample]: Max downsample: {}px (viewport={}, plafond={})",
352 m_max_downsample, with_margin, m_plafond);
QSize calculateDownsampleSize(const QSize &source_size) const
Calculates the downsample size for a source image.
void setMaxDownsample(int max_dim)
Sets the maximum downsample dimension manually.
float calculateFitZoom(const QSize &source_size) const noexcept
Calculates the zoom factor to fit an image in the viewport.
void setQualityMargin(float margin)
Sets the quality margin for zoom headroom.
void initialize(const QSize &viewport_logical, const ScreenInfo &screen)
Initializes the manager with screen and viewport parameters.
ViewportCalculation calculateDisplay(const QSize &source_size) const
Calculates optimal display parameters for a source image.
void viewportSizeChanged(const QSize &size)
ViewportState calculateFitToView(const QSize &display_size) const noexcept
Calculates viewport state for fit-to-view.
void setViewportSize(const QSize &viewport_logical)
Updates the viewport size.
ViewportManager(QObject *parent=nullptr)
void maxDownsampleChanged(int max_dim)
Namespace containing Qt-specific UI components for CaptureMoment.
int determinePlafond(int screen_physical_width, int screen_physical_height) noexcept
Determines the plafond based on physical screen size.
size_t calculateTextureMemoryMB(const QSize &size, int bytes_per_pixel=4) noexcept
Calculates texture memory usage in megabytes.
static consteval float minQualityMargin() noexcept
Minimum quality margin.
static consteval float maxQualityMargin() noexcept
Maximum quality margin.
static consteval int minDisplayDimension() noexcept
Minimum display dimension to prevent too small textures.
Physical screen characteristics.
float dpr
Device pixel ratio (density)
int physical_width
Physical screen width in pixels.
int physical_height
Physical screen height in pixels.
bool isValid() const noexcept
Result of viewport calculation for an image.
QSize display_size
Size to display in QML (logical pixels)
bool needs_downsample
True if downsample is required.
QSize downsample_size
Size to downsample source image to (GPU texture)
float fit_zoom
Zoom factor to fit image in viewport (0.0-1.0)
size_t texture_memory_mb
Estimated GPU memory usage in MB.
Current viewport state for zoom/pan operations.
QPointF center_offset
Offset to center image in viewport.
QPointF pan
Current pan offset in logical pixels.
float zoom
Current zoom level (1.0 = 100%)
Central viewport management for optimal display across all screen types.