HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
pixel_density.hpp
1// Copyright Take Vos 2024.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "pixels_per_inch.hpp"
8#include "dips.hpp"
9#include "pixels.hpp"
10#include "font_size.hpp"
11#include "length.hpp"
12#include "../utility/utility.hpp"
13#include "../macros.hpp"
14
15namespace hi { inline namespace v1 {
16namespace unit {
17
19 pixels_per_inch_f ppi;
20 device_type type;
21
22 template<typename T>
23 [[nodiscard]] constexpr friend au::Quantity<Pixels, std::common_type_t<float, T>>
24 operator*(pixel_density const& lhs, au::Quantity<Dips, T> const& rhs) noexcept
25 {
26 return pixels(lhs.density_scale() * rhs.in(dips));
27 }
28
29 template<typename T>
30 [[nodiscard]] constexpr friend au::Quantity<Pixels, std::common_type_t<float, T>>
31 operator*(au::Quantity<Dips, T> const& lhs, pixel_density const& rhs) noexcept
32 {
33 return rhs * lhs;
34 }
35
36 template<typename Unit, typename T>
37 [[nodiscard]] constexpr friend au::Quantity<Pixels, std::common_type_t<float, T>>
38 operator*(pixel_density const& lhs, au::Quantity<Unit, T> const& rhs) noexcept requires (au::HasSameDimension<Unit, au::Inches>::value)
39 {
40 return lhs.ppi * rhs;
41 }
42
43 template<typename Unit, typename T>
44 [[nodiscard]] constexpr friend au::Quantity<Pixels, std::common_type_t<float, T>>
45 operator*(au::Quantity<Unit, T> const& lhs, pixel_density const& rhs) noexcept requires (au::HasSameDimension<Unit, au::Inches>::value)
46 {
47 return rhs * lhs;
48 }
49
50 template<typename T>
51 [[nodiscard]] constexpr friend au::Quantity<Pixels, std::common_type_t<float, T>>
52 operator*(pixel_density const& lhs, au::Quantity<Pixels, T> const& rhs) noexcept
53 {
54 return rhs;
55 }
56
57 template<typename T>
58 [[nodiscard]] constexpr friend au::Quantity<Pixels, std::common_type_t<float, T>>
59 operator*(au::Quantity<Pixels, T> const& lhs, pixel_density const& rhs) noexcept
60 {
61 return lhs;
62 }
63
64 template<typename T>
65 [[nodiscard]] constexpr friend au::Quantity<Pixels, std::common_type_t<float, T>>
66 operator*(length_quantity<T> const& lhs, pixel_density const& rhs) noexcept
67 {
68 if (auto const *pts = std::get_if<au::Quantity<Points, T>>(&lhs)) {
69 return *pts * rhs;
70 } else if (auto const *dps = std::get_if<au::Quantity<Dips, T>>(&lhs)) {
71 return *dps * rhs;
72 } else if (auto const *pxs = std::get_if<au::Quantity<Pixels, T>>(&lhs)) {
73 return *pxs * rhs;
74 } else {
75 hi_no_default();
76 }
77 }
78
79 template<typename T>
80 [[nodiscard]] constexpr friend au::Quantity<Pixels, std::common_type_t<float, T>>
81 operator*(pixel_density const& lhs, length_quantity<T> const& rhs) noexcept
82 {
83 return rhs * lhs;
84 }
85
86 template<typename T>
87 [[nodiscard]] constexpr friend au::Quantity<PixelsPerEm, std::common_type_t<float, T>>
88 operator*(pixel_density const& lhs, au::Quantity<DipsPerEm, T> const& rhs) noexcept
89 {
90 return pixels_per_em(lhs.density_scale() * rhs.in(dips_per_em));
91 }
92
93 template<typename T>
94 [[nodiscard]] constexpr friend au::Quantity<PixelsPerEm, std::common_type_t<float, T>>
95 operator*(au::Quantity<DipsPerEm, T> const& lhs, pixel_density const& rhs) noexcept
96 {
97 return rhs * lhs;
98 }
99
100 template<typename T>
101 [[nodiscard]] constexpr friend au::Quantity<PixelsPerEm, std::common_type_t<float, T>>
102 operator*(pixel_density const& lhs, au::Quantity<PointsPerEm, T> const& rhs) noexcept
103 {
104 return lhs.ppi * rhs;
105 }
106
107 template<typename T>
108 [[nodiscard]] constexpr friend au::Quantity<PixelsPerEm, std::common_type_t<float, T>>
109 operator*(au::Quantity<PointsPerEm, T> const& lhs, pixel_density const& rhs) noexcept
110 {
111 return rhs * lhs;
112 }
113
114 template<typename T>
115 [[nodiscard]] constexpr friend au::Quantity<PixelsPerEm, std::common_type_t<float, T>>
116 operator*(pixel_density const& lhs, au::Quantity<PixelsPerEm, T> const& rhs) noexcept
117 {
118 return rhs;
119 }
120
121 template<typename T>
122 [[nodiscard]] constexpr friend au::Quantity<PixelsPerEm, std::common_type_t<float, T>>
123 operator*(au::Quantity<PixelsPerEm, T> const& lhs, pixel_density const& rhs) noexcept
124 {
125 return lhs;
126 }
127
128 template<typename T>
129 [[nodiscard]] constexpr friend au::Quantity<PixelsPerEm, std::common_type_t<float, T>>
130 operator*(pixel_density const& lhs, font_size_quantity<T> const& rhs) noexcept
131 {
132 if (auto const* dips_per_em_ptr = std::get_if<au::Quantity<DipsPerEm, T>>(&rhs)) {
133 return *dips_per_em_ptr * lhs;
134 } else if (auto const* pixels_per_em_ptr = std::get_if<au::Quantity<PixelsPerEm, T>>(&rhs)) {
135 return *pixels_per_em_ptr * lhs;
136 } else if (auto const* points_per_em_ptr = std::get_if<au::Quantity<PointsPerEm, T>>(&rhs)) {
137 return *points_per_em_ptr * lhs;
138 } else {
139 hi_no_default();
140 }
141 }
142
143 template<typename T>
144 [[nodiscard]] constexpr friend au::Quantity<PixelsPerEm, std::common_type_t<float, T>>
145 operator*(font_size_quantity<T> const& lhs, pixel_density const& rhs) noexcept
146 {
147 return rhs * lhs;
148 }
149
150private:
153 [[nodiscard]] constexpr float density_scale() const noexcept
154 {
155 constexpr auto scale_table = std::array{
156 0.5f,
157 0.5f,
158 0.5f,
159
160 0.75f, // 120 dpi
161
162 1.0f, // 160 dpi
163 1.0f,
164
165 1.5f, // 240 dpi
166 1.5f,
167
168 2.0f, // 320 dpi
169 2.0f,
170 2.0f,
171 2.0f,
172
173 3.0f, // 480 dpi
174 3.0f,
175 3.0f,
176 3.0f,
177 4.0f, // 640 dpi
178 };
179
180 // The base density is based on the device type which determines
181 // the viewing distance. We strip off the last three bits as there
182 // are multiple devices that need unique values but have the same
183 // base density.
184 auto const base_density = std::to_underlying(type) & 0xf8;
185
186 // casting to unsigned int is faster than size_t.
187 auto const index = static_cast<unsigned int>(ppi.in(pixels_per_inch)) * 4 / base_density;
188
189 // Using a table here is faster than the compiler will generate with
190 // a switch statement. The bound check here will result in a conditional
191 // move instead of a conditional jump.
192 if (index < scale_table.size()) {
193 return scale_table[index];
194 } else {
195 return scale_table.back();
196 }
197 }
198};
199
200}}} // namespace hi::v1
The HikoGUI namespace.
Definition array_generic.hpp:21
The HikoGUI API version 1.
Definition array_generic.hpp:22
device_type
The device type this application is running on.
Definition device_type.hpp:14
Definition font_size.hpp:31
Definition length.hpp:26
Definition pixel_density.hpp:18
Definition au.hh:2351
Definition au.hh:3518