-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathmoveResizeWindow.js
275 lines (241 loc) · 8.75 KB
/
moveResizeWindow.js
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
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
// https://akelpad.sourceforge.net/forum/viewtopic.php?p=17270#p17270
// https://infocatcher.ucoz.net/js/akelpad_scripts/moveResizeWindow.js
// https://github.com/Infocatcher/AkelPad_scripts/blob/master/moveResizeWindow.js
// (c) Infocatcher 2012-2020
// Version: 0.1.3 - 2020-07-27
// Author: Infocatcher
//// Move or/and align AkelPad's main window
// Icons for context menu:
// https://infocatcher.ucoz.net/js/akelpad_scripts/moveResizeWindow_icons.zip
// or https://github.com/Infocatcher/AkelPad_menu/tree/master/icons window_*.ico + window.xcf
// (based on Actual Window Manager's icons: http://www.actualtools.com/windowmanager/)
// Arguments:
// -resize={width}*{height}
// =800*600 - resize window to 800 x 600
// =100%* - resize window to 100% of work area width
// =*100% - resize window to 100% of work area height
// =100%*100% - resize window to work area (like maximize)
// -move={x}*{y}
// =center*center - move window to center of work area
// =left*top - move window to top left corner of work area
// =right*top - move window to top right corner of work area
// =left*bottom - move window to bottom left corner of work area
// =right*bottom - move window to bottom right corner of work area
// =left* - move window to left side of work area
// =50%* - move window to 50% of work area width
// =*50% - move window to 50% of work area height
// =10*150 - move to x=10, y=150
// -allowRestore=true - allow save last used size and position and restore them after second call
// Note: use "%%" to specify "%" in ContextMenu ant Toolbar
// Usage:
// -"Stretch to width" Call("Scripts::Main", 1, "moveResizeWindow.js", "-resize=100%%* -move=left*")
// -"Move down and left + 1280x720" Call("Scripts::Main", 1, "moveResizeWindow.js", "-resize=1280*720 -move=left*bottom")
var hMainWnd = AkelPad.GetMainWnd();
var oSys = AkelPad.SystemFunction();
if(hMainWnd && !AkelPad.IsInclude()) {
var resize = AkelPad.GetArgValue("resize", "");
var move = AkelPad.GetArgValue("move", "");
var allowRestore = AkelPad.GetArgValue("allowRestore", true);
if(allowRestore)
var pos = getWindowPos(hMainWnd);
var changed = false;
if(resize)
resizeWindow(hMainWnd, resize) && (changed = true);
if(move)
moveWindow(hMainWnd, move) && (changed = true);
if(allowRestore) {
if(changed)
saveWindowPos("main", hMainWnd, pos);
else
restoreWindowPos("main", hMainWnd);
}
}
function resizeWindow(hWnd, resize, hWndParent) {
var tokens = resize.split("*");
var rsW = tokens[0];
var rsH = tokens[1];
var rcWnd = getWindowRect(hWnd);
var rcWork = hWndParent
? getWindowRect(hWndParent)
: getWorkArea(hWnd);
if(!rcWnd || !rcWork)
return;
var shadow = getShadow(rcWnd);
var ww = rcWork.right - rcWork.left - (shadow.right - shadow.left);
var wh = rcWork.bottom - rcWork.top - (shadow.bottom - shadow.top);
var w = rcWnd.right - rcWnd.left;
var h = rcWnd.bottom - rcWnd.top;
if(isPersent(rsW))
rsW = Math.round(parseFloat(rsW)/100*ww);
else if(!rsW)
rsW = w;
else
rsW = parseInt(rsW);
if(isPersent(rsH))
rsH = Math.round(parseFloat(rsH)/100*wh);
else if(!rsH)
rsH = h;
else
rsH = parseInt(rsH);
rsW = Math.min(ww, rsW);
rsH = Math.min(wh, rsH);
if(rsW == w && rsH == h)
return false;
return setWindowPos(hWnd, null, null, rsW, rsH);
}
function moveWindow(hWnd, move, hWndParent) {
var tokens = move.split("*");
var mvX = tokens[0];
var mvY = tokens[1];
var rcWnd = getWindowRect(hWnd);
var rcWork = hWndParent
? getWindowRect(hWndParent)
: getWorkArea(hWnd);
if(!rcWnd || !rcWork)
return;
var shadow = getShadow(rcWnd);
var w = rcWnd.right - rcWnd.left;
var h = rcWnd.bottom - rcWnd.top;
if (mvX == "left") mvX = rcWork.left - shadow.left;
else if(mvX == "center") mvX = centerX(rcWnd, rcWork);
else if(mvX == "right") mvX = rcWork.right - w - shadow.right;
else if(!mvX) mvX = rcWnd.left;
else if(isPersent(mvX)) mvX = parseFloat(mvX)/100*(rcWork.right - rcWork.left);
else mvX = parseInt(mvX);
if (mvY == "top") mvY = rcWork.top - shadow.top;
else if(mvY == "center") mvY = centerY(rcWnd, rcWork);
else if(mvY == "bottom") mvY = rcWork.bottom - h - shadow.bottom;
else if(!mvY) mvY = rcWnd.top;
else if(isPersent(mvY)) mvY = parseFloat(mvY)/100*(rcWork.bottom - rcWork.top);
else mvY = parseInt(mvY);
mvX = Math.round(Math.max(rcWork.left - shadow.left, Math.min(rcWork.right - w - shadow.right, mvX)));
mvY = Math.round(Math.max(rcWork.top - shadow.top, Math.min(rcWork.bottom - h - shadow.bottom, mvY)));
if(mvX == rcWnd.left && mvY == rcWnd.top)
return false;
return setWindowPos(hWnd, mvX, mvY, null, null);
}
function centerX(rcWnd, rcWndParent) {
return rcWndParent.left + ((rcWndParent.right - rcWndParent.left)/2 - (rcWnd.right - rcWnd.left)/2);
}
function centerY(rcWnd, rcWndParent) {
return rcWndParent.top + ((rcWndParent.bottom - rcWndParent.top)/2 - (rcWnd.bottom - rcWnd.top)/2);
}
function isPersent(s) {
return s.slice(-1) == "%";
}
function getWindowPos(hWnd) {
var rcWnd = getWindowRect(hWnd);
if(!rcWnd)
return false;
if(oSys.Call("user32::IsZoomed", hWnd))
return "maximized";
return rcWnd.left + "x" + rcWnd.top + "|"
+ (rcWnd.right - rcWnd.left) + "x" + (rcWnd.bottom - rcWnd.top);
}
function saveWindowPos(windowId, hWnd, pos) {
if(!pos)
pos = getWindowPos(hWnd);
if(!pos)
return;
var oSet = AkelPad.ScriptSettings();
if(!oSet.Begin(WScript.ScriptBaseName, 0x2 /*POB_SAVE*/))
return false;
oSet.Write(windowId, 3 /*PO_STRING*/, pos);
return oSet.End();
}
function restoreWindowPos(windowId, hWnd) {
var oSet = AkelPad.ScriptSettings();
if(!oSet.Begin(WScript.ScriptBaseName, 0x1 /*POB_READ*/))
return false;
var pos = oSet.Read(windowId, 3 /*PO_STRING*/, "");
oSet.End();
if(pos == "maximized")
return oSys.Call("user32::ShowWindow", hWnd, 3 /*SW_MAXIMIZE*/);
if(!/^(-?\d+)x(-?\d+)\|(\d+)x(\d+)$/.test(pos))
return false;
var x = +RegExp.$1;
var y = +RegExp.$2;
var w = +RegExp.$3;
var h = +RegExp.$4;
return setWindowPos(hWnd, x, y, w, h);
}
function getWorkArea(hWnd) {
var lpRect = AkelPad.MemAlloc(16); //sizeof(RECT)
if(!lpRect)
return null;
oSys.Call("user32::GetWindowRect", hWnd, lpRect);
var hMonitor = oSys.Call("user32::MonitorFromRect", lpRect, 0x2 /*MONITOR_DEFAULTTONEAREST*/);
if(hMonitor) {
//typedef struct tagMONITORINFO {
// DWORD cbSize;
// RECT rcMonitor;
// RECT rcWork;
// DWORD dwFlags;
//} MONITORINFO, *LPMONITORINFO;
var sizeofMonitorInfo = 4 + 16 + 16 + 4;
var lpMi = AkelPad.MemAlloc(sizeofMonitorInfo);
if(lpMi) {
AkelPad.MemCopy(lpMi, sizeofMonitorInfo, 3 /*DT_DWORD*/);
oSys.Call("user32::GetMonitorInfo" + _TCHAR, hMonitor, lpMi);
var rcWork = parseRect(_PtrAdd(lpMi, 4 + 16));
AkelPad.MemFree(lpMi);
}
}
else { //?
oSys.Call("user32::SystemParametersInfo" + _TCHAR, 48 /*SPI_GETWORKAREA*/, 0, lpRect, 0);
var rcWork = parseRect(lpRect);
}
AkelPad.MemFree(lpRect);
return rcWork;
}
function setWindowPos(hWnd, x, y, w, h) {
var flags = 0x14 /*SWP_NOZORDER|SWP_NOACTIVATE*/
| (x === null || y === null ? 0x2 /*SWP_NOMOVE*/ : 0)
| (w === null || h === null ? 0x1 /*SWP_NOSIZE*/ : 0);
ensureRestored(hWnd);
return oSys.Call("user32::SetWindowPos", hWnd, 0, x, y, w, h, flags);
}
function ensureRestored(hWnd) {
// Also exit from Windows 7+ docked to half screen state
//if(oSys.Call("user32::IsZoomed", hWnd))
oSys.Call("user32::ShowWindow", hWnd, 9 /*SW_RESTORE*/);
}
function getWindowRect(hWnd, hWndParent) {
var lpRect = AkelPad.MemAlloc(16); //sizeof(RECT)
getRect: if(lpRect) {
if(!oSys.Call("user32::GetWindowRect", hWnd, lpRect))
break getRect;
if(hWndParent && !oSys.Call("user32::ScreenToClient", hWndParent, lpRect))
break getRect;
var rcWnd = parseRect(lpRect);
if(!oSys.Call("dwmapi::DwmGetWindowAttribute", hWnd, 9 /*DWMWA_EXTENDED_FRAME_BOUNDS*/, lpRect, 16 /*sizeof(RECT)*/)) {
var rcWndNS = parseRect(lpRect);
if(rcWndNS.left || rcWndNS.right) {
rcWnd.shadow = {
left: rcWndNS.left - rcWnd.left,
top: rcWndNS.top - rcWnd.top,
right: rcWndNS.right - rcWnd.right,
bottom: rcWndNS.bottom - rcWnd.bottom
};
}
}
}
lpRect && AkelPad.MemFree(lpRect);
return rcWnd;
}
function getShadow(rcWnd) {
return rcWnd.shadow || {
left: 0,
top: 0,
right: 0,
bottom: 0
};
}
function parseRect(lpRect) {
return {
left: AkelPad.MemRead(_PtrAdd(lpRect, 0), 3 /*DT_DWORD*/),
top: AkelPad.MemRead(_PtrAdd(lpRect, 4), 3 /*DT_DWORD*/),
right: AkelPad.MemRead(_PtrAdd(lpRect, 8), 3 /*DT_DWORD*/),
bottom: AkelPad.MemRead(_PtrAdd(lpRect, 12), 3 /*DT_DWORD*/)
};
}