新しい差分ファイル作成ツールやランチャー制作ツールの UI では、可変サイズのウィンドウで、サイズ変更に伴ってオブジェクトの位置やサイズも変わる形にしようと考えています。そこで、可変オブジェクトの設置がなるべく簡単になるように、モジュールを作りました。
位置やサイズを固定部分(ピクセル)と可変部分(ウィンドウのサイズとの割合)に分けて指定します。サンプルもあります。ちょっとした UI を実現させるためにちょっと長くなってしまいましたが。まだまだ改良の余地はありそうです。
#ifndef __MOD_OBJPOSMAN__
#define __MOD_OBJPOSMAN__
#include "user32.as"
// オブジェクトの位置やサイズを管理するモジュール
#module modObjPosMan
#const MAX_OBJECT 64 // 一つのスクリーンで管理するオブジェクトの最大個数
#const MAX_SCREEN 16 // 管理するスクリーンの最大個数
#enum SFX_POSX_FIXED = 0 // 位置のX座標 の固定部分 の添え字番号
#enum SFX_POSX_LIQUID // 位置のX座標 の可変部分 の添え字番号
#enum SFX_POSY_FIXED // 位置のY座標 の固定部分 の添え字番号
#enum SFX_POSY_LIQUID // 位置のY座標 の可変部分 の添え字番号
#enum SFX_WIDTH_FIXED // 幅 の固定部分 の添え字番号
#enum SFX_WIDTH_LIQUID // 幅 の可変部分 の添え字番号
#enum SFX_HEIGHT_FIXED // 高さ の固定部分 の添え字番号
#enum SFX_HEIGHT_LIQUID // 高さ の可変部分 の添え字番号
#enum MAX_SFX // 要素数
// 初期化
#deffunc InitObjPosMan
dim ObjectPosSize, MAX_SFX, MAX_OBJECT, MAX_SCREEN // オブジェクトの位置やサイズ
dim ManageWndIdTbl, MAX_SCREEN // 管理するウィンドウのIDのテーブル
nManageWnd = 0 // 管理するウィンドウの数
dim ManageObjIdTbl, MAX_OBJECT, MAX_SCREEN // 管理するオブジェクトのID
dim nManageObj, MAX_SCREEN // 管理するオブジェクトの数
dim IsSetOncmd, MAX_SCREEN // WM_SIZE の飛び先を設定したか
return
// ウィンドウの管理用通し番号を取得
// GetWndSerno( (ウィンドウID) )
// ウィンドウの管理用通し番号を返す
#defcfunc GetWndSerno int WndId, \
local serno
serno = -1
// 線形探索
repeat nManageWnd
if ManageWndIdTbl( cnt ) == WndId {
serno = cnt
break
}
loop
if serno == -1 {
ManageWndIdTbl( nManageWnd ) = WndId
serno = nManageWnd
nManageWnd ++
}
return serno
// オブジェクトの管理用通し番号を取得
// GetObjSerno( (ウィンドウの管理用通し番号), (オブジェクトID) )
// オブジェクトの管理用通し番号を返す
#defcfunc GetObjSerno int WndSerno, int ObjId, \
local serno
serno = -1
// 線形探索
repeat nManageObj( WndSerno )
if ManageObjIdTbl( cnt, WndSerno ) == ObjId {
serno = cnt
break
}
loop
if serno == -1 {
ManageObjIdTbl( nManageObj( WndSerno ), WndSerno ) = ObjId
serno = nManageObj( WndSerno )
nManageObj( WndSerno ) ++
}
return serno
// オブジェクトの位置・サイズを変更( フラグ1: 位置変更 フラグ2: サイズ変更 )
// MoveObj (オブジェクトID), (フラグ)
// フラグ: 1 = 位置変更
// 2 = サイズ変更
#deffunc MoveObj int ObjId, int flag, \
local WndSerno, local ObjSerno, local hObj, \
local rect, local hParentWnd, local x, local y, local w, local h
WndSerno = GetWndSerno( ginfo_sel )
ObjSerno = GetObjSerno( WndSerno, ObjId )
hObj = objinfo( ObjId, 2 )
dim rect, 4
GetWindowRect hObj, varptr( rect )
GetParent hObj : hParentWnd = stat
MapWindowPoints 0, hParentWnd, varptr( rect ), 2
x = rect( 0 )
y = rect( 1 )
w = rect( 2 ) - rect( 0 )
h = rect( 3 ) - rect( 1 )
if ( flag & 1 ) != 0 {
x = ObjectPosSize( SFX_POSX_FIXED , ObjSerno, WndSerno )
y = ObjectPosSize( SFX_POSY_FIXED , ObjSerno, WndSerno )
x += ObjectPosSize( SFX_POSX_LIQUID , ObjSerno, WndSerno ) * ginfo_winx / 10000
y += ObjectPosSize( SFX_POSY_LIQUID , ObjSerno, WndSerno ) * ginfo_winy / 10000
}
if ( flag & 2 ) != 0 {
w = ObjectPosSize( SFX_WIDTH_FIXED , ObjSerno, WndSerno )
h = ObjectPosSize( SFX_HEIGHT_FIXED , ObjSerno, WndSerno )
w += ObjectPosSize( SFX_WIDTH_LIQUID , ObjSerno, WndSerno ) * ginfo_winx / 10000
h += ObjectPosSize( SFX_HEIGHT_LIQUID , ObjSerno, WndSerno ) * ginfo_winy / 10000
}
MoveWindow hObj, x, y, w, h, 1
return
// オブジェクトの位置を指定
// SetObjPos (オブジェクトID), (固定X座標), (可変X座標), (固定Y座標), (可変Y座標)
// 可変部分はウィンドウのクライアントエリアの大きさとの割合で、10000を最大とする。
#deffunc SetObjPos int ObjId, int _PosXFixed, int _PosXLiquid, int _PosYFixed, int _PosYLiquid, \
local WndSerno, local ObjSerno
WndSerno = GetWndSerno( ginfo_sel )
ObjSerno = GetObjSerno( WndSerno, ObjId )
if IsSetOncmd( WndSerno ) == 0 {
IsSetOncmd( WndSerno ) = 1
oncmd gosub *l_Resize, $0005 // WM_SIZE
}
ObjectPosSize( SFX_POSX_FIXED , ObjSerno, WndSerno ) = _PosXFixed
ObjectPosSize( SFX_POSX_LIQUID , ObjSerno, WndSerno ) = _PosXLiquid
ObjectPosSize( SFX_POSY_FIXED , ObjSerno, WndSerno ) = _PosYFixed
ObjectPosSize( SFX_POSY_LIQUID , ObjSerno, WndSerno ) = _PosYLiquid
MoveObj ObjId, 1
return
// オブジェクトのサイズを指定
// SetObjSize (オブジェクトID), (固定幅), (可変幅), (固定高さ), (可変高さ)
// 可変部分はウィンドウのクライアントエリアの大きさとの割合で、10000を最大とする。
#deffunc SetObjSize int ObjId, int _WidthFixed, int _WidthLiquid, int _HeightFixed, int _HeightLiquid, \
local WndSerno, local ObjSerno
WndSerno = GetWndSerno( ginfo_sel )
ObjSerno = GetObjSerno( WndSerno, ObjId )
if IsSetOncmd( WndSerno ) == 0 {
IsSetOncmd( WndSerno ) = 1
oncmd gosub *l_Resize, $0005 // WM_SIZE
}
ObjectPosSize( SFX_WIDTH_FIXED , ObjSerno, WndSerno ) = _WidthFixed
ObjectPosSize( SFX_WIDTH_LIQUID , ObjSerno, WndSerno ) = _WidthLiquid
ObjectPosSize( SFX_HEIGHT_FIXED , ObjSerno, WndSerno ) = _HeightFixed
ObjectPosSize( SFX_HEIGHT_LIQUID , ObjSerno, WndSerno ) = _HeightLiquid
MoveObj ObjId, 2
return
// ウィンドウ内の全オブジェクトの位置とサイズの変更
#deffunc Resize int WndId, \
local SelWndId, local WndSerno
SelWndId = ginfo_sel : gsel WndId
WndSerno = GetWndSerno( WndId )
repeat nManageObj( WndSerno )
MoveObj ManageObjIdTbl( cnt, WndSerno ), 3
loop
gsel SelWndId
return
*l_Resize
Resize ginfo_intid
return
#global
InitObjPosMan
#endif
MoveObj の命令定義内の、
repeat 2
ScreenToClient hParentWnd, varptr( rect( cnt * 2 ) )
loop
となっていた部分を以下のように変更しました。
MapWindowPoints 0, hParentWnd, varptr( rect ), 2
どちらでも、やっていることは同じです。この MapWindowPoints API は ScreenToClient API や、 ClientToScreen API の拡張版みたいなもののようですね。
#include "user32.as"
#include "gdi32.as"
screen 0, ginfo_dispx, ginfo_dispy, 2
GetWindowLong hwnd, -16
SetWindowLong hwnd, -16, stat | $50000 // WS_MAXIMIZEBOX | WS_SIZEBOX
width 480, 320
// ステータスバー
winobj "msctls_statusbar32", "", , $50000000 // WS_VISIBLE | WS_CHILD
ObjId = stat
//ステータスバーの高さを得る
dim RectStatusBar, 4
GetWindowRect objinfo( ObjId, 2 ), varptr( RectStatusBar )
StatusBarHeight = RectStatusBar.3 - RectStatusBar.1
SetObjPos ObjId, 0, 0, -StatusBarHeight, 10000
SetObjSize ObjId, 0, 10000, StatusBarHeight, 0
// 複数行エディットボックス
sdim mesboxBuf : mesboxBuf = "複数行エディットボックス"
mesbox mesboxBuf
ObjId = stat
SetObjPos ObjId, 0, 0, 0, 0
SetObjSize ObjId, 0, 10000, -StatusBarHeight, 10000
gsel ginfo_sel, 1
#const MARGIN_TOP 10
#const MARGIN_LEFT 15
#const MARGIN_BOTTOM 10
#const MARGIN_RIGHT 15
#const BUTTON_WIDTH 72
#const BUTTON_HEIGHT 20
#const SPACE_SIZE 4
#const WINDOW_MIN_WIDTH MARGIN_LEFT + MARGIN_RIGHT + BUTTON_WIDTH * 4 + SPACE_SIZE * ( 4 - 1 )
#const WINDOW_MIN_HEIGHT MARGIN_TOP + BUTTON_HEIGHT * ( 4 + 3 + 1 ) + SPACE_SIZE * ( 4 - 1 ) + MARGIN_BOTTOM
screen 2, ginfo_dispx, ginfo_dispy, 2
GetWindowLong hwnd, -16
SetWindowLong hwnd, -16, stat | $50000 // WS_MAXIMIZEBOX | WS_SIZEBOX
width WINDOW_MIN_WIDTH, WINDOW_MIN_HEIGHT
GetStockObject 17 : hDefaultGUIFont = stat
oncmd gosub *minmaxinfo, $0024 // WM_MINMAXINFO
syscolor 15 : boxf
winobj "static", "ファイル:", 0, $50000002 // WS_VISIBLE | WS_CHILD | SS_RIGHT
ObjId = stat
SetObjPos ObjId, MARGIN_LEFT, 0, MARGIN_TOP, 0
SetObjSize ObjId, BUTTON_WIDTH, 0, BUTTON_HEIGHT, 0
sendmsg objinfo( ObjId, 2 ), $0030, hDefaultGUIFont, 1 // WM_SETFONT
sdim dummyStr
input dummyStr
ObjId = stat
SetObjPos ObjId, MARGIN_LEFT + BUTTON_WIDTH + SPACE_SIZE, 0, MARGIN_TOP, 0
SetObjSize ObjId, -( MARGIN_LEFT + ( BUTTON_WIDTH + SPACE_SIZE ) * 2 + MARGIN_RIGHT ), 10000, BUTTON_HEIGHT, 0
button gosub "参照", *dummyLabel
ObjId = stat
SetObjPos ObjId, -( MARGIN_LEFT + BUTTON_WIDTH ), 10000, MARGIN_TOP, 0
SetObjSize ObjId, BUTTON_WIDTH, 0, BUTTON_HEIGHT, 0
winobj "static", "オプション:", 0, $50000002 // WS_VISIBLE | WS_CHILD | SS_RIGHT
ObjId = stat
SetObjPos ObjId, MARGIN_LEFT, 0, MARGIN_TOP + BUTTON_HEIGHT + SPACE_SIZE, 0
SetObjSize ObjId, BUTTON_WIDTH, 0, BUTTON_HEIGHT, 0
sendmsg objinfo( ObjId, 2 ), $0030, hDefaultGUIFont, 1 // WM_SETFONT
repeat 3
chkbox strf("%c", 'A'+cnt), dummyInt
ObjId = stat
SetObjPos ObjId, MARGIN_LEFT + BUTTON_WIDTH + SPACE_SIZE, 0, MARGIN_TOP + ( BUTTON_HEIGHT + SPACE_SIZE ) * ( cnt + 1 ), 0
SetObjSize ObjId, -( MARGIN_LEFT + BUTTON_WIDTH + SPACE_SIZE + SPACE_SIZE / 2 ), 5000, BUTTON_HEIGHT, 0
loop
winobj "static", "モード:", 0, $50000002 // WS_VISIBLE | WS_CHILD | SS_RIGHT
ObjId = stat
SetObjPos ObjId, MARGIN_LEFT, 0, MARGIN_TOP + ( BUTTON_HEIGHT + SPACE_SIZE ) * 4, 0
SetObjSize ObjId, BUTTON_WIDTH, 0, BUTTON_HEIGHT, 0
sendmsg objinfo( ObjId, 2 ), $0030, hDefaultGUIFont, 1 // WM_SETFONT
listbox dummyInt,, "Apple\nOrange\nGrape"
ObjId = stat
SetObjPos ObjId, MARGIN_LEFT + BUTTON_WIDTH + SPACE_SIZE, 0, MARGIN_TOP + ( BUTTON_HEIGHT + SPACE_SIZE ) * 4, 0
SetObjSize ObjId, -( MARGIN_LEFT + BUTTON_WIDTH + SPACE_SIZE + SPACE_SIZE / 2 ), 5000, BUTTON_HEIGHT * 3, 0
winobj "static", "ログ:", 0, $50000000 // WS_VISIBLE | WS_CHILD
ObjId = stat
SetObjPos ObjId, SPACE_SIZE / 2, 5000, MARGIN_TOP + BUTTON_HEIGHT + SPACE_SIZE, 0
SetObjSize ObjId, -( SPACE_SIZE / 2 + MARGIN_RIGHT ), 5000, BUTTON_HEIGHT, 0
sendmsg objinfo( ObjId, 2 ), $0030, hDefaultGUIFont, 1 // WM_SETFONT
mesbox dummyStr
ObjId = stat
SetObjPos ObjId, SPACE_SIZE / 2, 5000, MARGIN_TOP + ( BUTTON_HEIGHT + SPACE_SIZE ) * 2, 0
SetObjSize ObjId, -( SPACE_SIZE / 2 + MARGIN_RIGHT ), 5000, -( MARGIN_TOP + ( BUTTON_HEIGHT + SPACE_SIZE ) * 2 + MARGIN_BOTTOM + BUTTON_HEIGHT + SPACE_SIZE ), 10000
button gosub "OK", *dummyLabel
ObjId = stat
SetObjPos ObjId, -( MARGIN_RIGHT + BUTTON_WIDTH * 2 + SPACE_SIZE ), 10000, -( MARGIN_BOTTOM + BUTTON_HEIGHT ), 10000
SetObjSize ObjId, BUTTON_WIDTH, 0, BUTTON_HEIGHT, 0
button gosub "キャンセル", *dummyLabel
ObjId = stat
SetObjPos ObjId, -( MARGIN_RIGHT + BUTTON_WIDTH ), 10000, -( MARGIN_BOTTOM + BUTTON_HEIGHT ), 10000
SetObjSize ObjId, BUTTON_WIDTH, 0, BUTTON_HEIGHT, 0
gsel ginfo_sel, 1
stop
*dummyLabel
return
*minmaxinfo
dupptr mmi, lParam, 40
mmi(6) = WINDOW_MIN_WIDTH + ( ginfo_sizex - ginfo_winx )
mmi(7) = WINDOW_MIN_HEIGHT + ( ginfo_sizey - ginfo_winy )
return