mirror of
https://github.com/hyprwm/Hyprland
synced 2025-12-20 08:50:05 +01:00
renderer: add zoom with detached camera (#12548)
This commit is contained in:
parent
6535ff07c9
commit
e4a8f2b14f
6 changed files with 129 additions and 15 deletions
|
|
@ -1658,6 +1658,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||||
.type = CONFIG_OPTION_BOOL,
|
.type = CONFIG_OPTION_BOOL,
|
||||||
.data = SConfigOptionDescription::SBoolData{false},
|
.data = SConfigOptionDescription::SBoolData{false},
|
||||||
},
|
},
|
||||||
|
SConfigOptionDescription{
|
||||||
|
.value = "cursor:zoom_detached_camera",
|
||||||
|
.description = "Detaches the camera from the mouse when zoomed in, only ever moving to keep the mouse in view",
|
||||||
|
.type = CONFIG_OPTION_BOOL,
|
||||||
|
.data = SConfigOptionDescription::SBoolData{true},
|
||||||
|
},
|
||||||
SConfigOptionDescription{
|
SConfigOptionDescription{
|
||||||
.value = "cursor:enable_hyprcursor",
|
.value = "cursor:enable_hyprcursor",
|
||||||
.description = "whether to enable hyprcursor support",
|
.description = "whether to enable hyprcursor support",
|
||||||
|
|
|
||||||
|
|
@ -734,6 +734,7 @@ CConfigManager::CConfigManager() {
|
||||||
registerConfigVar("cursor:zoom_factor", {1.f});
|
registerConfigVar("cursor:zoom_factor", {1.f});
|
||||||
registerConfigVar("cursor:zoom_rigid", Hyprlang::INT{0});
|
registerConfigVar("cursor:zoom_rigid", Hyprlang::INT{0});
|
||||||
registerConfigVar("cursor:zoom_disable_aa", Hyprlang::INT{0});
|
registerConfigVar("cursor:zoom_disable_aa", Hyprlang::INT{0});
|
||||||
|
registerConfigVar("cursor:zoom_detached_camera", Hyprlang::INT{1});
|
||||||
registerConfigVar("cursor:enable_hyprcursor", Hyprlang::INT{1});
|
registerConfigVar("cursor:enable_hyprcursor", Hyprlang::INT{1});
|
||||||
registerConfigVar("cursor:sync_gsettings_theme", Hyprlang::INT{1});
|
registerConfigVar("cursor:sync_gsettings_theme", Hyprlang::INT{1});
|
||||||
registerConfigVar("cursor:hide_on_key_press", Hyprlang::INT{0});
|
registerConfigVar("cursor:hide_on_key_press", Hyprlang::INT{0});
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include "CMType.hpp"
|
#include "CMType.hpp"
|
||||||
|
|
||||||
#include <xf86drmMode.h>
|
#include <xf86drmMode.h>
|
||||||
|
#include "MonitorZoomController.hpp"
|
||||||
#include "time/Timer.hpp"
|
#include "time/Timer.hpp"
|
||||||
#include "math/Math.hpp"
|
#include "math/Math.hpp"
|
||||||
#include "../desktop/reserved/ReservedArea.hpp"
|
#include "../desktop/reserved/ReservedArea.hpp"
|
||||||
|
|
@ -130,6 +131,8 @@ class CMonitor {
|
||||||
uint32_t m_drmFormat = DRM_FORMAT_INVALID;
|
uint32_t m_drmFormat = DRM_FORMAT_INVALID;
|
||||||
uint32_t m_prevDrmFormat = DRM_FORMAT_INVALID;
|
uint32_t m_prevDrmFormat = DRM_FORMAT_INVALID;
|
||||||
|
|
||||||
|
CMonitorZoomController m_zoomController;
|
||||||
|
|
||||||
bool m_dpmsStatus = true;
|
bool m_dpmsStatus = true;
|
||||||
bool m_vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
|
bool m_vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
|
||||||
bool m_enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
|
bool m_enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
|
||||||
|
|
|
||||||
97
src/helpers/MonitorZoomController.cpp
Normal file
97
src/helpers/MonitorZoomController.cpp
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
#include "MonitorZoomController.hpp"
|
||||||
|
|
||||||
|
#include <hyprlang.hpp>
|
||||||
|
#include "../config/ConfigValue.hpp"
|
||||||
|
#include "../managers/input/InputManager.hpp"
|
||||||
|
#include "../render/OpenGL.hpp"
|
||||||
|
#include "desktop/DesktopTypes.hpp"
|
||||||
|
#include "render/Renderer.hpp"
|
||||||
|
|
||||||
|
void CMonitorZoomController::zoomWithDetachedCamera(CBox& result, const SCurrentRenderData& m_renderData) {
|
||||||
|
const auto m = m_renderData.pMonitor;
|
||||||
|
auto monbox = CBox(0, 0, m->m_size.x, m->m_size.y);
|
||||||
|
const auto ZOOM = m_renderData.mouseZoomFactor;
|
||||||
|
const auto MOUSE = g_pInputManager->getMouseCoordsInternal() - m->m_position;
|
||||||
|
|
||||||
|
if (m_lastZoomLevel != ZOOM) {
|
||||||
|
if (m_resetCameraState) {
|
||||||
|
m_resetCameraState = false;
|
||||||
|
m_camera = CBox(0, 0, m->m_size.x, m->m_size.y);
|
||||||
|
m_lastZoomLevel = 1.0f;
|
||||||
|
}
|
||||||
|
const CBox old = m_camera;
|
||||||
|
|
||||||
|
// mouse normalized inside screen (0..1)
|
||||||
|
const float mx = MOUSE.x / m->m_size.x;
|
||||||
|
const float my = MOUSE.y / m->m_size.y;
|
||||||
|
// world-space point under the cursor before zoom
|
||||||
|
const float mouseWorldX = old.x + (mx * old.w);
|
||||||
|
const float mouseWorldY = old.y + (my * old.h);
|
||||||
|
|
||||||
|
const auto CAMERAW = monbox.w / ZOOM;
|
||||||
|
const auto CAMERAH = monbox.h / ZOOM;
|
||||||
|
|
||||||
|
// compute new top-left so the same world point stays under the cursor
|
||||||
|
const float newX = mouseWorldX - (mx * CAMERAW);
|
||||||
|
const float newY = mouseWorldY - (my * CAMERAH);
|
||||||
|
|
||||||
|
m_camera = CBox(newX, newY, CAMERAW, CAMERAH);
|
||||||
|
// Detect if this zoom would've caused jerk to keep mouse in view and disable edges if so
|
||||||
|
if (!m_camera.copy().scaleFromCenter(.9).containsPoint(MOUSE))
|
||||||
|
m_padCamEdges = false;
|
||||||
|
m_lastZoomLevel = ZOOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep mouse inside cameraview
|
||||||
|
auto smallerbox = m_camera;
|
||||||
|
// Prevent zoom step from causing us to jerk to keep mouse in padded camera view,
|
||||||
|
// but let us switch to the padded camera once the mouse moves into the safe area
|
||||||
|
if (!m_padCamEdges)
|
||||||
|
if (smallerbox.copy().scaleFromCenter(.9).containsPoint(MOUSE))
|
||||||
|
m_padCamEdges = true;
|
||||||
|
if (m_padCamEdges)
|
||||||
|
smallerbox.scaleFromCenter(.9);
|
||||||
|
if (!smallerbox.containsPoint(MOUSE)) {
|
||||||
|
if (MOUSE.x < smallerbox.x)
|
||||||
|
m_camera.x -= smallerbox.x - MOUSE.x;
|
||||||
|
if (MOUSE.y < smallerbox.y)
|
||||||
|
m_camera.y -= smallerbox.y - MOUSE.y;
|
||||||
|
if (MOUSE.y > smallerbox.y + smallerbox.h)
|
||||||
|
m_camera.y += MOUSE.y - (smallerbox.y + smallerbox.h);
|
||||||
|
if (MOUSE.x > smallerbox.x + smallerbox.w)
|
||||||
|
m_camera.x += MOUSE.x - (smallerbox.x + smallerbox.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto z = ZOOM * m->m_scale;
|
||||||
|
monbox.scale(z).translate(-m_camera.pos() * z);
|
||||||
|
|
||||||
|
result = monbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMonitorZoomController::applyZoomTransform(CBox& monbox, const SCurrentRenderData& m_renderData) {
|
||||||
|
static auto PZOOMRIGID = CConfigValue<Hyprlang::INT>("cursor:zoom_rigid");
|
||||||
|
static auto PZOOMDETACHEDCAMERA = CConfigValue<Hyprlang::INT>("cursor:zoom_detached_camera");
|
||||||
|
const auto ZOOM = m_renderData.mouseZoomFactor;
|
||||||
|
|
||||||
|
if (ZOOM == 1.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto m = m_renderData.pMonitor;
|
||||||
|
const auto ORIGINAL = monbox;
|
||||||
|
const auto INITANIM = m->m_zoomAnimProgress->value() != 1.0;
|
||||||
|
|
||||||
|
if (*PZOOMDETACHEDCAMERA && !INITANIM)
|
||||||
|
zoomWithDetachedCamera(monbox, m_renderData);
|
||||||
|
else {
|
||||||
|
const auto ZOOMCENTER = m_renderData.mouseZoomUseMouse ? (g_pInputManager->getMouseCoordsInternal() - m->m_position) * m->m_scale : m->m_transformedSize / 2.f;
|
||||||
|
|
||||||
|
monbox.translate(-ZOOMCENTER).scale(ZOOM).translate(*PZOOMRIGID ? m->m_transformedSize / 2.0 : ZOOMCENTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
monbox.x = std::min(monbox.x, 0.0);
|
||||||
|
monbox.y = std::min(monbox.y, 0.0);
|
||||||
|
if (monbox.x + monbox.width < ORIGINAL.w)
|
||||||
|
monbox.x = ORIGINAL.w - monbox.width;
|
||||||
|
if (monbox.y + monbox.height < ORIGINAL.h)
|
||||||
|
monbox.y = ORIGINAL.h - monbox.height;
|
||||||
|
}
|
||||||
19
src/helpers/MonitorZoomController.hpp
Normal file
19
src/helpers/MonitorZoomController.hpp
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "./math/Math.hpp"
|
||||||
|
|
||||||
|
struct SCurrentRenderData;
|
||||||
|
|
||||||
|
class CMonitorZoomController {
|
||||||
|
public:
|
||||||
|
bool m_resetCameraState = true;
|
||||||
|
|
||||||
|
void applyZoomTransform(CBox& monbox, const SCurrentRenderData& m_renderData);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void zoomWithDetachedCamera(CBox& result, const SCurrentRenderData& m_renderData);
|
||||||
|
|
||||||
|
CBox m_camera;
|
||||||
|
float m_lastZoomLevel = 1.0f;
|
||||||
|
bool m_padCamEdges = true;
|
||||||
|
};
|
||||||
|
|
@ -849,7 +849,6 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFrameb
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHyprOpenGLImpl::end() {
|
void CHyprOpenGLImpl::end() {
|
||||||
static auto PZOOMRIGID = CConfigValue<Hyprlang::INT>("cursor:zoom_rigid");
|
|
||||||
static auto PZOOMDISABLEAA = CConfigValue<Hyprlang::INT>("cursor:zoom_disable_aa");
|
static auto PZOOMDISABLEAA = CConfigValue<Hyprlang::INT>("cursor:zoom_disable_aa");
|
||||||
|
|
||||||
TRACY_GPU_ZONE("RenderEnd");
|
TRACY_GPU_ZONE("RenderEnd");
|
||||||
|
|
@ -861,20 +860,9 @@ void CHyprOpenGLImpl::end() {
|
||||||
|
|
||||||
CBox monbox = {0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y};
|
CBox monbox = {0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y};
|
||||||
|
|
||||||
if (m_renderData.mouseZoomFactor != 1.f) {
|
if (g_pHyprRenderer->m_renderMode == RENDER_MODE_NORMAL && m_renderData.mouseZoomFactor == 1.0f)
|
||||||
const auto ZOOMCENTER = m_renderData.mouseZoomUseMouse ?
|
m_renderData.pMonitor->m_zoomController.m_resetCameraState = true;
|
||||||
(g_pInputManager->getMouseCoordsInternal() - m_renderData.pMonitor->m_position) * m_renderData.pMonitor->m_scale :
|
m_renderData.pMonitor->m_zoomController.applyZoomTransform(monbox, m_renderData);
|
||||||
m_renderData.pMonitor->m_transformedSize / 2.f;
|
|
||||||
|
|
||||||
monbox.translate(-ZOOMCENTER).scale(m_renderData.mouseZoomFactor).translate(*PZOOMRIGID ? m_renderData.pMonitor->m_transformedSize / 2.0 : ZOOMCENTER);
|
|
||||||
|
|
||||||
monbox.x = std::min(monbox.x, 0.0);
|
|
||||||
monbox.y = std::min(monbox.y, 0.0);
|
|
||||||
if (monbox.x + monbox.width < m_renderData.pMonitor->m_transformedSize.x)
|
|
||||||
monbox.x = m_renderData.pMonitor->m_transformedSize.x - monbox.width;
|
|
||||||
if (monbox.y + monbox.height < m_renderData.pMonitor->m_transformedSize.y)
|
|
||||||
monbox.y = m_renderData.pMonitor->m_transformedSize.y - monbox.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_applyFinalShader = !m_renderData.blockScreenShader;
|
m_applyFinalShader = !m_renderData.blockScreenShader;
|
||||||
if (m_renderData.mouseZoomUseMouse && *PZOOMDISABLEAA)
|
if (m_renderData.mouseZoomUseMouse && *PZOOMDISABLEAA)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue