1// Aseprite Render Library
2// Copyright (c) 2020-2022 Igara Studio S.A.
3// Copyright (c) 2001-2016 David Capello
4//
5// This file is released under the terms of the MIT license.
6// Read LICENSE.txt for more information.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "base/debug.h"
13#include "render/zoom.h"
14
15#include <algorithm>
16
17namespace render {
18
19static int scales[][2] = {
20 { 1, 64 },
21 { 1, 48 },
22 { 1, 32 },
23 { 1, 24 },
24 { 1, 16 },
25 { 1, 12 },
26 { 1, 8 },
27 { 1, 6 },
28 { 1, 5 },
29 { 1, 4 },
30 { 1, 3 },
31 { 1, 2 },
32 { 1, 1 }, // 100%
33 { 2, 1 },
34 { 3, 1 },
35 { 4, 1 },
36 { 5, 1 },
37 { 6, 1 },
38 { 8, 1 },
39 { 12, 1 },
40 { 16, 1 },
41 { 24, 1 },
42 { 32, 1 },
43 { 48, 1 },
44 { 64, 1 },
45};
46
47static int scales_size = sizeof(scales) / sizeof(scales[0]);
48
49Zoom::Zoom(int num, int den)
50 : m_num(num)
51 , m_den(den)
52{
53 ASSERT(m_num > 0);
54 ASSERT(m_den > 0);
55 m_internalScale = scale();
56}
57
58bool Zoom::in()
59{
60 int i = linearScale();
61 if (i < scales_size-1) {
62 ++i;
63 m_num = scales[i][0];
64 m_den = scales[i][1];
65 m_internalScale = scale();
66 return true;
67 }
68 else
69 return false;
70}
71
72bool Zoom::out()
73{
74 int i = linearScale();
75 if (i > 0) {
76 --i;
77 m_num = scales[i][0];
78 m_den = scales[i][1];
79 m_internalScale = scale();
80 return true;
81 }
82 else
83 return false;
84}
85
86int Zoom::linearScale() const
87{
88 for (int i=0; i<scales_size; ++i) {
89 // Exact match
90 if (scales[i][0] == m_num &&
91 scales[i][1] == m_den) {
92 return i;
93 }
94 }
95 return findClosestLinearScale(scale());
96}
97
98// static
99Zoom Zoom::fromScale(double scale)
100{
101 Zoom zoom = fromLinearScale(findClosestLinearScale(scale));
102 zoom.m_internalScale = scale;
103 return zoom;
104}
105
106// static
107Zoom Zoom::fromLinearScale(int i)
108{
109 i = std::clamp(i, 0, scales_size-1);
110 return Zoom(scales[i][0], scales[i][1]);
111}
112
113// static
114int Zoom::findClosestLinearScale(double scale)
115{
116 for (int i=1; i<scales_size-1; ++i) {
117 double min = double(scales[i-1][0]) / double(scales[i-1][1]);
118 double mid = double(scales[i ][0]) / double(scales[i ][1]);
119 double max = double(scales[i+1][0]) / double(scales[i+1][1]);
120
121 if (scale >= (min+mid)/2.0 &&
122 scale <= (mid+max)/2.0)
123 return i;
124 }
125 if (scale < 1.0)
126 return 0;
127 else
128 return scales_size-1;
129}
130
131int Zoom::linearValues()
132{
133 return scales_size;
134}
135
136} // namespace render
137