2007年9月3日月曜日

ドラッグできる矩形の表示

モジュール変数を利用し、ドラッグできるカラフルな矩形を表示します。メインループを使わない完全なイベントドリヴン形式であることも特徴です。
2007/09/05:コメントなど微調整。

// ドラッグできる矩形
// マウスカーソル変更用命令(参考:http://lhsp.s206.xrea.com/hsp_mouse.html#3)
#uselib "user32"
#cfunc LoadCursor   "LoadCursorA"   nullptr, int
#func  SetClassLong "SetClassLongA" int, int, int
// ウィンドウメッセージ
#const WM_LBUTTONDOWN 0x0201
#const WM_LBUTTONUP   0x0202
#const WM_MOUSEMOVE   0x0200
// LoadCursor用引数
#const IDC_ARROW      0x7F00
#const IDC_HAND       0x7F89
//
// 矩形を扱うモジュール
#module mdl_rect x, y, w, h, c
#const BORDER_WIDTH 2
#modinit int _x, int _y, int _w, int _h, int _c
    x = _x : y = _y
    w = _w : h = _h
    c = _c \ 192
    return
//
// 矩形を描画
#modfunc draw_rect
    hsvcolor c, 255191
    boxf x, y, x + w, y + h
    hsvcolor c, 255255
    boxf x + BORDER_WIDTH, y + BORDER_WIDTH, x + w - BORDER_WIDTH, y + h - BORDER_WIDTH
    return
//
// 矩形を移動
#modfunc move_rect int _x, int _y
    x = _x : y = _y
    return
//
// 点(px, py)が矩形内にあるか否かを返す
#modfunc point_rect int px, int py
    return ( x <= px ) & ( y <= py ) & ( px < x + w ) & ( py < y + h )
//
// 矩形のX座標を返す
#modfunc get_x var ret
    ret = x
    return
//
// 矩形のY座標を返す
#modfunc get_y var ret
    ret = y
    return
//
// 今ポイントしている矩形を調べ、その配列要素番号をstatに返す(なにもない時は-1)
#deffunc get_pointing_rect array rects, local result
    result = -1
    foreach rects
        point_rect rects( cnt ), mousexmousey
        if stat : result = cnt ; break
    loop
    return result

#global
*init
    // 乱数初期化
    randomize
    // Windowsメッセージ割り込み実行指定
    oncmd gosub *LButtonDownWM_LBUTTONDOWN
    oncmd gosub *LButtonUp,   WM_LBUTTONUP
    oncmd gosub *MouseMove,   WM_MOUSEMOVE
    // 矩形を5つ作成
    repeat 5
        w = rnd100 ) + 100 : h = rnd100 ) +  50
        newmod rects, mdl_rect, rndginfo_winx - w ), rndginfo_winy - h ), w, h, rnd191 )
    loop
    // マウスカーソルの種類を記録する変数を初期化
    cursor_type = IDC_ARROW
    // 画面の更新
    gosub *renew_screen
    stop
//
// 画面の更新
*renew_screen
    redraw 0
    color 255255255 : boxf
    foreach rects
        draw_rect rects( cnt )
    loop
    redraw 1
    return
//
// マウスの左ボタンを離した時の処理
*LButtonUp
    dragging = 0    // ドラッグ終了
    return
//
// マウスの左ボタンを押した時の処理
*LButtonDown
    if ( pointing_rect >= 0 ) {
        // 矩形をポイントしている場合はその矩形をドラッグする
        dx = mousex : dy = mousey
        dragging = 1
    }
    return
//
// マウスが動いたときの処理
*MouseMove
    if ( pointing_rect >= 0 ) & ( cursor_type != IDC_HAND ) {
        // 矩形の上ではカーソルを手の形に変更
        cursor_type = IDC_HAND
        gosub *ChangeCursor
    }
    if ( pointing_rect < 0 ) & ( cursor_type != IDC_ARROW ) {
        // 矩形の外ではカーソルを通常の形に変更
        cursor_type = IDC_ARROW
        gosub *ChangeCursor
    }
    if dragging {
        // ドラッグ中ならば矩形を移動
        get_x rects( pointing_rect ), x
        get_y rects( pointing_rect ), y
        move_rect rects( pointing_rect ), x + mousex - dx, y + mousey - dy
        dx = mousex : dy = mousey
    } else {
        // ドラッグ中でないならばポイントしている矩形を調べる
        get_pointing_rect rects
        pointing_rect = stat
    }
    // 画面を更新
    gosub *renew_screen
    return
//
// マウスカーソルの変更
*ChangeCursor
    SetClassLong hwnd, -12LoadCursor( cursor_type )
    mouse       // マウスカーソルの更新(これがないと即座に反映されない)
    return

2 件のコメント:

匿名 さんのコメント...

すごいですー!
これにサイズ変更とかつけたりもできるんですか!?

eller さんのコメント...

もちろんです。今回はコードを簡略化させるために省略しましたが、本来このスクリプトはそうした機能も持たせる予定でした。

例えばこの矩形のサイズを変更する命令は次のようになるでしょう。

#modfunc rect_resize int _w, int _h
w = _w : h = _h
return

あとは「マウスが辺の上にあるか否か」を判定するスクリプトを記述すれば、可能なはずです。