遥か昔にやりたいことが同じようなコードを書いたことがあったので、掘り起こしてサンプルとしてこちらに貼っておきます。
結論としては
・WM_SIZINGというメッセージを使うと今回の実装は楽
・WM_SIZINGではユーザーがどの方向でウィンドウを引っ張って変更しようとしているのかが分かる
・かつ、WM_SIZINGで渡ってきたポインタ経由で値を書き換えると、こちらの指定した大きさでウィンドウサイズを固定化できる
という感じです。
本来はウィンドウサイズのアスペクト比固定に使われるものなのですが、正方形にしたいというのもアスペクト比固定の例ですので、転用は可能かなと思います。
WM_SIZINGというキーワードで検索すればHSPのスレッドも引っかかるのですが、あんまりいい感じの処理のがにゃんか見つからなかったです、探し方が悪かったんかな…。
処理として分かりやすいようにサンプルでは横長のウィンドウサイズにしていますが、実際に使う場合はその辺の改造はご自分でお願いします、そんなに難しくはないと思いますが。
おまけで最小ウィンドウサイズも指定できるようになってますが、邪魔だったらその辺は適当に取っ払ってください。
実は探してたのがこれではなかった! とかだったら…その時はすみません。
コメントマシマシで書いたつもりですが分からないところはご随意にツッコミ貰えればと。
// user32のみ使う
#include "user32.as"
// 定数
#define GWL_STYLE (-16)
#define WS_SIZEBOX (0x00040000)
#define WM_TIMER (0x0113)
#define WM_SIZING (0x0214)
// ウィンドウサイズ
// ここを変えると正方形含め好きなアスペクト比にできる
// 今回はサンプルで分かりやすいように横長にしてる
windowSizeX = 500 : windowSizeY = 200
// 最小ウィンドウサイズ
windowSizeMinX = 250 : windowSizeMinY = 100
// ウィンドウのアス比固定か
isFixWindowAspectRatio = 1
// 自動で求まるもの:ウィンドウのアス比
windowSizeAspectRatio = double(windowSizeX) / double(windowSizeY)
// スクリーン作る
// ※可変なので最大サイズで作っておく。
// ディスプレイがもっと大きいかもしれないことを考えるなら、定数で4kとかでもいいかも
screen 0, ginfo_dispx, ginfo_dispy, , , , windowSizeX, windowSizeY
// 諸々設定
oncmd gosub *winProc_Sizing, WM_SIZING
// サイズ変更可に設定
GetWindowLong hwnd, GWL_STYLE
windowStyle = stat
windowStyle |= (WS_SIZEBOX)
SetWindowLong hwnd, GWL_STYLE, windowStyle
// チェックボックス
pos 10, 2 : objsize 200, 20 : chkbox "ウィンドウサイズアス比固定", isFixWindowAspectRatio
// タイマー
SetTimer hwnd, 100, 50, 0
oncmd gosub *winProc_Timer, WM_TIMER
stop
// タイマープロシージャ
*winProc_Timer
gsel 0
color 222, 222, 222 : boxf 10, 30, 240, 70
color 0, 0, 0
pos 10, 30 : mes "今のウィンドウサイズ"
pos 15, 50 : mes strf("(%d, %d)", ginfo_winx, ginfo_winy)
return
// サイジングプロシージャ
*winProc_Sizing
if (isFixWindowAspectRatio == 0) : return 1
// クライアントサイズからウィンドウサイズへのマージン計算
gsel 0
tMarginX = ginfo_sizex - ginfo_winx : tMarginY = ginfo_sizey - ginfo_winy
// 計算結果出力先
dupptr destLeft, lparam, 4
dupptr destTop, lparam+4, 4
dupptr destRight, lparam+8, 4
dupptr destBottom, lparam+12, 4
// 一回クライアントサイズとして計算
destRight -= tMarginX
destBottom -= tMarginY
// どの方向のドラッグか
switch( wparam )
case 1// 左
case 2// 右
twidth = limitf(destRight - destLeft, windowSizeMinX, ginfo_dispx)
// 押し返す
if (wparam == 1) {
destLeft = destRight - twidth
} else {
destRight = destLeft + twidth
}
// 上下は下を伸ばす
destBottom = int(0.0 + destTop + twidth/windowSizeAspectRatio)
swbreak
case 3// 上
case 6// 下
theight = limitf(destBottom - destTop, windowSizeMinY, ginfo_dispy)
// 押し返す
if (wparam == 3) {
destTop = destBottom - theight
} else {
destBottom = destTop + theight
}
// 左右は右を伸ばす
destRight = int(0.0 + destLeft + theight*windowSizeAspectRatio)
swbreak
case 4// 左上
case 5// 右上
case 7// 左下
case 8// 右下
twidth = limitf(destRight - destLeft, windowSizeMinX, ginfo_dispx)
theight = limitf(destBottom - destTop, windowSizeMinY, ginfo_dispy)
// 小さいほうに合わせる
if (twidth >= theight*windowSizeAspectRatio) {
// 押し返し分
if (wparam == 4 || wparam == 5) {
destTop = destBottom - theight
} else {
destBottom = destTop + theight
}
// 辻褄合わせ分
if (wparam == 4 || wparam == 7) {
destLeft = int(0.0 + destRight - theight*windowSizeAspectRatio)
} else {
destRight = int(0.0 + destLeft + theight*windowSizeAspectRatio)
}
} else {
// 押し返し分
if (wparam == 4 || wparam == 7) {
destLeft = destRight - twidth
} else {
destRight = destLeft + twidth
}
// 辻褄合わせ分
if (wparam == 4 || wparam == 5) {
destTop = int(0.0 + destBottom - twidth/windowSizeAspectRatio)
} else {
destBottom = int(0.0 + destTop + twidth/windowSizeAspectRatio)
}
}
swbreak
swend
// クライアントサイズからウィンドウサイズへ戻す
destRight += tMarginX
destBottom += tMarginY
return 1