-
Notifications
You must be signed in to change notification settings - Fork 35
/
resizer.h
142 lines (122 loc) · 4.67 KB
/
resizer.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
/**
* Part of WinLamb - Win32 API Lambda Library
* https://github.com/rodrigocfd/winlamb
* Copyright 2017-present Rodrigo Cesar de Freitas Dias
* This library is released under the MIT License
*/
#pragma once
#include <vector>
#include "internals/params.h"
#include "wnd.h"
namespace wl {
// Allows the resizing of multiple controls when the parent window is resized.
class resizer final {
public:
enum class go {
REPOS, // control size is fixed; control moves around anchored
RESIZE, // control size stretches; control doesn't move
NOTHING // control doesn't move or resize
};
private:
struct _ctrl final {
HWND hChild;
RECT rcOrig; // original coordinates relative to parent
go modeHorz; // horizontal mode
go modeVert; // vertical mode
};
std::vector<_ctrl> _ctrls;
SIZE _szOrig;
public:
resizer& add(HWND hCtrl, go modeHorz, go modeVert) {
return this->_add_one(hCtrl, modeHorz, modeVert);
}
resizer& add(const wnd& ctrl, go modeHorz, go modeVert) {
return this->add(ctrl.hwnd(), modeHorz, modeVert);
}
resizer& add(std::initializer_list<HWND> hCtrls, go modeHorz, go modeVert) {
this->_ctrls.reserve(this->_ctrls.size() + hCtrls.size());
for (const HWND hCtrl : hCtrls) {
this->_add_one(hCtrl, modeHorz, modeVert);
}
return *this;
}
resizer& add(std::initializer_list<std::reference_wrapper<const wnd>> ctrls,
go modeHorz, go modeVert)
{
this->_ctrls.reserve(this->_ctrls.size() + ctrls.size());
for (const wnd& pCtrl : ctrls) {
this->_add_one(pCtrl.hwnd(), modeHorz, modeVert);
}
return *this;
}
resizer& add(HWND hParent, int ctrlId, go modeHorz, go modeVert) {
return this->add(GetDlgItem(hParent, ctrlId), modeHorz, modeVert);
}
resizer& add(const wnd* parent, int ctrlId, go modeHorz, go modeVert) {
return this->add(parent->hwnd(), ctrlId, modeHorz, modeVert);
}
resizer& add(HWND hParent, std::initializer_list<int> ctrlIds, go modeHorz, go modeVert) {
this->_ctrls.reserve(this->_ctrls.size() + ctrlIds.size());
for (int ctrlId : ctrlIds) {
this->_add_one(GetDlgItem(hParent, ctrlId), modeHorz, modeVert);
}
return *this;
}
resizer& add(const wnd* parent, std::initializer_list<int> ctrlIds, go modeHorz, go modeVert) {
this->_ctrls.reserve(this->_ctrls.size() + ctrlIds.size());
for (int ctrlId : ctrlIds) {
this->_add_one(GetDlgItem(parent->hwnd(), ctrlId), modeHorz, modeVert);
}
return *this;
}
// Updates controls, intended to be called with parent's WM_SIZE processing.
void adjust(const params& p) const noexcept {
int state = static_cast<int>(p.wParam);
int cx = LOWORD(p.lParam);
int cy = HIWORD(p.lParam);
if (this->_ctrls.empty() || state == SIZE_MINIMIZED) {
return; // only if created() was called; if minimized, no need to resize
}
HDWP hdwp = BeginDeferWindowPos(static_cast<int>(this->_ctrls.size()));
for (const _ctrl& control : this->_ctrls) {
UINT uFlags = SWP_NOZORDER;
if (control.modeHorz == go::REPOS && control.modeVert == go::REPOS) { // reposition both vert & horz
uFlags |= SWP_NOSIZE;
} else if (control.modeHorz == go::RESIZE && control.modeVert == go::RESIZE) { // resize both vert & horz
uFlags |= SWP_NOMOVE;
}
DeferWindowPos(hdwp, control.hChild, nullptr,
control.modeHorz == go::REPOS ?
cx - this->_szOrig.cx + control.rcOrig.left :
control.rcOrig.left, // keep original pos
control.modeVert == go::REPOS ?
cy - this->_szOrig.cy + control.rcOrig.top :
control.rcOrig.top, // keep original pos
control.modeHorz == go::RESIZE ?
cx - this->_szOrig.cx + control.rcOrig.right - control.rcOrig.left :
control.rcOrig.right - control.rcOrig.left, // keep original width
control.modeVert == go::RESIZE ?
cy - this->_szOrig.cy + control.rcOrig.bottom - control.rcOrig.top :
control.rcOrig.bottom - control.rcOrig.top, // keep original height
uFlags);
}
EndDeferWindowPos(hdwp);
}
private:
resizer& _add_one(HWND hChild, go modeHorz, go modeVert) {
HWND hParent = GetParent(hChild);
if (this->_ctrls.empty()) { // first call to _addOne()
RECT rcP{};
GetClientRect(hParent, &rcP);
this->_szOrig.cx = rcP.right;
this->_szOrig.cy = rcP.bottom; // save original size of parent
}
RECT rcCtrl{};
GetWindowRect(hChild, &rcCtrl);
this->_ctrls.push_back({hChild, rcCtrl, modeHorz, modeVert});
ScreenToClient(hParent, reinterpret_cast<POINT*>(&this->_ctrls.back().rcOrig)); // client coordinates relative to parent
ScreenToClient(hParent, reinterpret_cast<POINT*>(&this->_ctrls.back().rcOrig.right));
return *this;
}
};
}//namespace wl