-
Notifications
You must be signed in to change notification settings - Fork 225
Expand file tree
/
Copy pathzoom.cpp
More file actions
127 lines (108 loc) · 3.86 KB
/
zoom.cpp
File metadata and controls
127 lines (108 loc) · 3.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <wayfire/per-output-plugin.hpp>
#include <wayfire/output.hpp>
#include <wayfire/render.hpp>
#include <wayfire/render-manager.hpp>
#include <wayfire/util/duration.hpp>
class wayfire_zoom_screen : public wf::per_output_plugin_instance_t
{
enum class interpolation_method_t
{
LINEAR = 0,
NEAREST = 1,
};
wf::option_wrapper_t<wf::keybinding_t> modifier{"zoom/modifier"};
wf::option_wrapper_t<double> speed{"zoom/speed"};
wf::option_wrapper_t<wf::animation_description_t> smoothing_duration{"zoom/smoothing_duration"};
wf::option_wrapper_t<int> interpolation_method{"zoom/interpolation_method"};
wf::animation::simple_animation_t progression{smoothing_duration};
bool hook_set = false;
wf::plugin_activation_data_t grab_interface = {
.name = "zoom",
.capabilities = 0,
};
public:
void init() override
{
progression.set(1, 1);
output->add_axis(modifier, &axis);
}
void update_zoom_target(float delta)
{
float target = progression.end;
target -= target * delta * speed;
target = wf::clamp(target, 1.0f, 50.0f);
if (target != progression.end)
{
progression.animate(target);
if (!hook_set)
{
hook_set = true;
output->render->add_post(&render_hook);
output->render->set_redraw_always();
}
}
}
wf::axis_callback axis = [=] (wlr_pointer_axis_event *ev)
{
if (!output->can_activate_plugin(&grab_interface))
{
return false;
}
if (ev->orientation != WL_POINTER_AXIS_VERTICAL_SCROLL)
{
return false;
}
update_zoom_target(ev->delta);
return true;
};
wf::post_hook_t render_hook = [=] (wf::auxilliary_buffer_t& source,
const wf::render_buffer_t& destination)
{
auto w = destination.get_size().width;
auto h = destination.get_size().height;
if ((w <= 0) || (h <= 0))
{
LOGE("Invalid output size in zoom plugin!");
return;
}
auto oc = output->get_cursor_position();
double x, y;
wlr_box b = output->get_relative_geometry();
wlr_box_closest_point(&b, oc.x, oc.y, &x, &y);
/* get rotation & scale */
wlr_box box = {int(x), int(y), 1, 1};
box = output->render->get_target_framebuffer().framebuffer_box_from_geometry_box(box);
x = box.x;
y = box.y;
// Store progression once to avoid its value changing in subsequent calls, could be very tricky due to
// timing. And if we use slightly different progressions, we can get an invalid rect.
const float factor = (float)progression;
const float scale = (factor - 1) / factor;
const float x1 = std::clamp(float(x * scale), 0.0f, w - 1.0f);
const float y1 = std::clamp(float(y * scale), 0.0f, h - 1.0f);
const float tw = std::clamp(w / factor, 0.0f, w - x1);
const float th = std::clamp(h / factor, 0.0f, h - y1);
auto filter_mode = (interpolation_method == (int)interpolation_method_t::NEAREST) ?
WLR_SCALE_FILTER_NEAREST : WLR_SCALE_FILTER_BILINEAR;
destination.blit(source, {x1, y1, tw, th}, {0, 0, w, h}, filter_mode);
if (!progression.running() && (progression - 1 <= 0.01))
{
unset_hook();
}
};
void unset_hook()
{
output->render->set_redraw_always(false);
output->render->rem_post(&render_hook);
hook_set = false;
}
void fini() override
{
if (hook_set)
{
output->render->rem_post(&render_hook);
}
output->rem_binding(&axis);
}
};
DECLARE_WAYFIRE_PLUGIN(wf::per_output_plugin_t<wayfire_zoom_screen>);