-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patheasy_rect.h
235 lines (213 loc) · 8.05 KB
/
easy_rect.h
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
// Copyright 2020-2022 Jon Ville
#pragma once
#include <cassert>
#ifdef JON_DSP_JUCE
#include <JuceHeader.h>
#endif
namespace jon_dsp {
// Immutable constexpr 2D rectangle implementation designed to make grid-based
// layouts as easy as possible. Can export a juce rectangle if
// JON_DSP_JUCE is defined.
// (0.0, 0.0) is top left corner
template <typename NumType>
struct EasyRect {
// These are const, but making them so deletes copy and move constructors
NumType x_, y_, w_, h_;
constexpr EasyRect() : x_(0), y_(0), w_(0), h_(0) {}
constexpr EasyRect(const NumType x, const NumType y, const NumType w,
const NumType h)
: x_(x), y_(y), w_(w), h_(h) {}
#ifdef JON_DSP_JUCE
constexpr EasyRect(const juce::Rectangle<NumType>& jrect)
: x_(jrect.getX()), y_(jrect.getY()), w_(jrect.getWidth()),
h_(jrect.getHeight()) {}
#endif
constexpr NumType x() const { return x_; }
constexpr NumType y() const { return y_; }
constexpr NumType w() const { return w_; }
constexpr NumType h() const { return h_; }
#ifdef JON_DSP_JUCE
template <typename DestNumType>
juce::Rectangle<DestNumType> to_juce() const {
return juce::Rectangle<DestNumType>(static_cast<DestNumType>(x_),
static_cast<DestNumType>(y_),
static_cast<DestNumType>(w_), static_cast<DestNumType>(h_));
}
template <typename SrcNumType>
static EasyRect from_juce(const juce::Rectangle<SrcNumType>& jr) {
return EasyRect(static_cast<NumType>(jr.getX()),
static_cast<NumType>(jr.getY()),
static_cast<NumType>(jr.getWidth()),
static_cast<NumType>(jr.getHeight()));
}
#endif
template <typename DestNumType>
constexpr EasyRect to() const {
EasyRect<DestNumType> result(static_cast<DestNumType>(x_),
static_cast<DestNumType>(y_),
static_cast<DestNumType>(w_), static_cast<DestNumType>(h_));
return result;
}
// Read as "increase top by...", "decrease bottom by..."
// Only the incr/decr edge moves
constexpr EasyRect inc_top(const NumType units) const {
return EasyRect(x_, y_-units, w_, h_+units);
}
constexpr EasyRect dec_top(const NumType units) const {
return inc_top(-units);
}
constexpr EasyRect inc_left(const NumType units) const {
return EasyRect(x_-units, y_, w_+units, h_);
}
constexpr EasyRect dec_left(const NumType units) const {
return inc_left(-units);
}
constexpr EasyRect inc_right(const NumType units) const {
return EasyRect(x_, y_, w_+units, h_);
}
constexpr EasyRect dec_right(const NumType units) const {
return inc_right(-units);
}
constexpr EasyRect inc_bottom(const NumType units) const {
return EasyRect(x_, y_, w_, h_+units);
}
constexpr EasyRect dec_bottom(const NumType units) const {
return inc_bottom(-units);
}
// Grow and shrink each edge keeping centre origin
constexpr EasyRect grow(const NumType units) const {
return EasyRect(x_-units, y_-units, w_+2*units, h_+2*units);
}
constexpr EasyRect shrink(const NumType units) const {
return grow(-units);
}
// take a new rectangle consisting of ... units from the ...
// the ctor asserts units > 0.0
constexpr EasyRect take_top(const NumType units) const {
return EasyRect(x_, y_, w_, units);
}
constexpr EasyRect take_left(const NumType units) const {
return EasyRect(x_, y_, units, h_);
}
constexpr EasyRect take_right(const NumType units) const {
return EasyRect(x_+w_-units, y_, units, h_);
}
constexpr EasyRect take_bottom(const NumType units) const {
return EasyRect(x_, y_+h_-units, w_, units);
}
void split_horiz(const NumType units, EasyRect& left,
EasyRect& right) const
{
EasyRect safe_copy = *this; // In case user passes a reference to *this
left = safe_copy.take_left(units); right = safe_copy.dec_left(units);
}
void split_from_left(const NumType units, EasyRect& left,
EasyRect& right) const
{
return split_horiz(units, left, right);
}
void split_from_right(const NumType units, EasyRect& left,
EasyRect& right) const
{
EasyRect safe_copy = *this;
left = safe_copy.dec_right(units); right = safe_copy.take_right(units);
}
void split_vert(const NumType units, EasyRect& top,
EasyRect& bottom) const
{
EasyRect safe_copy = *this;
top = safe_copy.take_top(units); bottom = safe_copy.dec_top(units);
}
void split_from_top(const NumType units, EasyRect& top,
EasyRect& bottom) const
{
return split_vert(units, top, bottom);
}
void split_from_bottom(const NumType units, EasyRect& top,
EasyRect& bottom) const
{
EasyRect safe_copy = *this;
top = safe_copy.dec_bottom(units); bottom = safe_copy.take_bottom(units);
}
// Easily move around within grids
constexpr EasyRect translate(const NumType x, const NumType y) const {
return EasyRect(x_+x, y_+y, w_, h_);
}
constexpr EasyRect translate_right(const NumType units) const {
return translate(units, 0);
}
constexpr EasyRect translate_left(const NumType units) const {
return translate(-units, 0);
}
constexpr EasyRect translate_up(const NumType units) const {
return translate(0, -units);
}
constexpr EasyRect translate_down(const NumType units) const {
return translate(0, units);
}
constexpr EasyRect grid_right(const NumType pad=0) const {
return translate(w_+pad, 0);
}
constexpr EasyRect grid_left(const NumType pad=0) const {
return translate(-w_-pad, 0);
}
constexpr EasyRect grid_up(const NumType pad=0) const {
return translate(0, -h_-pad);
}
constexpr EasyRect grid_down(const NumType pad=0) const {
return translate(0, h_+pad);
}
constexpr EasyRect place_right(const EasyRect& rect,
const NumType pad=0) const
{
return EasyRect(rect.x()+rect.w()+pad, rect.y(), w_, h_);
}
constexpr EasyRect place_left(const EasyRect& rect,
const NumType pad=0) const
{
return EasyRect(rect.x()-w_-pad, rect.y(), w_, h_);
}
constexpr EasyRect place_above(const EasyRect& rect,
const NumType pad=0) const
{
return EasyRect(rect.x(), rect.y()-y_-pad, w_, h_);
}
constexpr EasyRect place_below(const EasyRect& rect,
const NumType pad=0) const
{
return EasyRect(rect.x(), rect.y()+rect.h()+pad, w_, h_);
}
// Build grids
constexpr EasyRect grid_container(const EasyRect& cell,
const NumType num_cols, const NumType num_rows) const
{
return EasyRect(cell.x(), cell.y(), cell.x()*num_cols,
cell.y().num_rows);
}
constexpr EasyRect row_container(const EasyRect& cell,
const NumType num_cols) const
{
return grid_container(cell, num_cols, 1);
}
constexpr EasyRect col_container(const EasyRect& cell,
const NumType num_rows) const
{
return grid_container(cell, 1, num_rows);
}
// contain_pad(): given a content rectangle C and some padding, generate a
// container rectangle with the same x and y coordinates as C
constexpr EasyRect contain_pad(const NumType pad_left,
const NumType pad_right, const NumType pad_top,
const NumType pad_bottom) const
{
return EasyRect(x_, y_, pad_left+pad_right, pad_top+pad_bottom);
}
// content_pad(): given a content rectangle C and some padding, move C so
// that it can be padded. Its size will not change
constexpr EasyRect content_pad(const NumType pad_left,
const NumType pad_top) const
{
return translate(pad_left, pad_top);
}
};
} // namespace jon_dsp