GoFのCommandパターンにヒントを得て作成。
描画した履歴を文字列型配列変数に記録しておき、必要に応じて取り出します。
今回は単純な文字列型配列変数ではなく、スタックのモジュールを用意してみました。
bregexp.dll(bregonig.dll)および月影ともさんのbregexp.hspが必要です。// 文字列用スタック
#module string_stack stack, max
#modinit
max = 0
sdim stack, 32, 10
return
#deffunc new_sstack array v
newmod v, string_stack@
return
#modfunc push str s
stack(max) = s
max++
return
#defcfunc pop modvar string_stack@
if max == 0 {
logmes "引数の値が異常です。"
return ""
}
max--
return stack(max)
#defcfunc get_length modvar string_stack@
return max
#defcfunc get_last modvar string_stack@
return stack(max-1)
#defcfunc get_at modvar string_stack@, int index
if index < 0 || max <= index {
logmes "引数の値が異常です。"
return ""
}
return stack(index)
#modfunc clear_stack
max = 0
return
#global
// 矩形の塗りつぶし
// http://rpen.blogspot.com/2007/11/blog-post.html
#include "gdi32.as"
#module
#const FLOODFILLSURFACE 1
#deffunc fill int x, int y
current_color = ginfo_r, ginfo_g, ginfo_b
CreateSolidBrush (ginfo_b << 16) | (ginfo_g << 8) | ginfo_r
if stat {
hBrush = stat
} else {
dialog "ブラシの生成に失敗しました。プログラムを終了します。", 1
end
}
SelectObject hDC, hBrush
pget x, y
ExtFloodFill hdc, x, y, (ginfo_b << 16) | (ginfo_g << 8) | ginfo_r, FLOODFILLSURFACE
DeleteObject hBrush
color current_color(0), current_color(1), current_color(2)
return
#global
// 命令を解析して描画するモジュール
#include "bregexp.hsp"
#module drawer
#define ctype result(%1) int(_result(%1))
#deffunc draw str _cmd
cmd = _cmd
BSplit _result, cmd, "m/[ ,]+/"
switch _result(0)
case "moveTo" : pos result(1), result(2) : swbreak
case "lineTo" : line result(1), result(2) : swbreak
case "color" : color result(1), result(2), result(3) : swbreak
case "fill" : fill result(1), result(2) : redraw 1 : swbreak
default : logmes "未知の命令です" : swbreak
swend
return
#deffunc draw_all array cmds, int wait_time
redraw 0
color 255, 255, 255 : boxf
color
repeat get_length(cmds)
draw get_at(cmds, cnt)
if wait_time {
redraw 1
wait wait_time
redraw 0
}
loop
redraw 1
return
#global
#define push_and_do(%1,%2) push %1, %2 : draw %2
#define WM_MOUSEMOVE $00000200
#define WM_LBUTTONDOWN $00000201
#define WM_LBUTTONUP $00000202
#define WM_RBUTTONDOWN $00000204
*init
title "左ドラッグで線を描画 / 右クリックで塗りつぶし"
oncmd gosub *onLButtonDown, WM_LBUTTONDOWN
oncmd gosub *onRButtonDown, WM_RBUTTONDOWN
oncmd gosub *onLButtonUp, WM_LBUTTONUP
oncmd gosub *onMouseMove, WM_MOUSEMOVE
objsize 80
button gosub "color change", *color_change
button gosub "redraw slowly", *all_draw_slowly
button gosub "clear", *clear
button gosub "undo", *undo
new_sstack cmds
stop
// 色の変更
*color_change
hsvcolor rnd(192), 255, 255
push_and_do cmds, "color " + ginfo_r + "," + ginfo_g + "," + ginfo_b
return
// 全消去
*clear
clear_stack cmds
draw_all cmds, 0
return
// アンドゥ
*undo
tmp = pop(cmds)
draw_all cmds, 0
return
// すべて描画
*all_draw
draw_all cmds, 0
return
// ゆっくりとすべて描画
*all_draw_slowly
oncmd 0
gosub *invalidate_buttons
draw_all cmds, 4
gosub *validate_buttons
oncmd 1
return
// 左ドラッグ開始
*onLButtonDown
dragging = 1
push_and_do cmds, "moveTo " + mousex + "," + mousey
return
// 左ドラッグ終了
*onLButtonUp
dragging = 0
return
// 左ドラッグ中
*onMouseMove
if dragging {
push_and_do cmds, "lineTo " + mousex + "," + mousey
}
return
// 右クリック
*onRButtonDown
if dragging == 0 {
push_and_do cmds, "fill " + mousex + "," + mousey
}
return
#include "obj.as"
*invalidate_buttons
repeat 4
objgray cnt, 0
loop
return
*validate_buttons
repeat 4
objgray cnt, 1
loop
return
2008年2月12日火曜日
アンドゥや再生ができるペイントツール
2008年2月9日土曜日
リストビューのソート
リストビューのアイテムをLVM_SORTITEMSEXメッセージを使ってソートします。ちょくとさんのコールバック関数DLL「hscallbk.dll」が必要です。
リストビューのモジュールとしてもそこそこ利用できるかもしれません。
エクスプローラのように、「ヘッダ部分をクリックすると並び変わる」ようにもできるでしょう。(参考:http://hsp.tv/play/pforum.php?mode=pastwch&num=2749)
LVM_SORTITEMSEXメッセージの日本語情報は意外と少ないので、気が向いたら開発Wikiにフィードバックします。// 参考資料:
// リストビューを作成してみる
// http://yokohama.cool.ne.jp/chokuto/urawaza/listview1.html
// Windows32 API Constance 検索
// http://hspnext.com/tool/hsptool04.htm
// MSDN - LVM_SORTITEMSEX
// http://msdn2.microsoft.com/ja-jp/library/bb761055(en-us).aspx
#module mod_listview
#include "hscallbk.as"
#uselib ""
#func sort_items "" int, int, int
#define LVM_SETITEM $00001006
#define LVM_INSERTITEM $00001007
#define LVM_INSERTCOLUMN $0000101B
#define LVM_SORTITEMSEX $00001051
#define LVM_GETITEMTEXTA $0000102D
#define LVS_REPORT $00000001
#define WS_EX_NOPARENTNOTIFY $00000004
#define WS_VISIBLE $10000000
#define WS_CHILD $40000000
#deffunc make_listview
if vartype(proc) != vartype("callback") : gosub *init
winobj "SysListView32", "ListView", WS_EX_NOPARENTNOTIFY, WS_VISIBLE | WS_CHILD | LVS_REPORT, -1, -1
return stat
*init
setcallbk proc, sort_items, *sort_flag
sdim name, 64, 2
dim lvcolumn, 8
dim lvitem, 6
lvcolumn.0 = 0x000F
lvcolumn.2 = 100
lvitem.0 = 0x0001
lvitem.6 = 64
return
#deffunc add_column int id_list, str column_name, int index
if(index < 0 | id_list < 0) {
logmes "パラメータが不正です。"
return -1
}
name = column_name
lvcolumn.3 = varptr(name)
sendmsg objinfo_hwnd(id_list), LVM_INSERTCOLUMN, index, varptr(lvcolumn)
return stat
#deffunc add_item int id_list, array item, int index
if(index < 0 | id_list < 0) {
logmes "パラメータが不正です。"
return -1
}
if vartype(item) != vartype("str") {
logmes "配列変数の型が不正です。文字列型の変数を渡してください。"
return -1
}
// アイテムの作成
lvitem.1 = index
lvitem.2 = 0
lvitem.5 = varptr(item)
sendmsg objinfo_hwnd(id_list), LVM_INSERTITEM, 0, varptr(lvitem)
// サブアイテムの作成
repeat length(item) - 1, 1
lvitem.2 = cnt
lvitem.5 = varptr(item(cnt))
sendmsg objinfo_hwnd(id_list), LVM_SETITEM, 0, varptr(lvitem)
loop
return stat
#deffunc sort int id_list, int column, int vtype, int sortmode
if(column < 0 | id_list < 0 | vtype < 0) {
logmes "パラメータが不正です。"
return -1
}
lvitem.2 = column
var_type = vtype
sendmsg objinfo_hwnd(id_list), LVM_SORTITEMSEX, sortmode, varptr(proc)
return
#defcfunc local compareAsInt int id_list, int index1, int index2, int sortmode
gosub *startCompare
return int(name(sortmode & 1)) - int(name((sortmode & 1) ^ 1))
#defcfunc local compareAsStr int id_list, int index1, int index2, int sortmode
gosub *startCompare
return name(sortmode & 1) ! name((sortmode & 1) ^ 1)
return
*startCompare
lvitem.5 = varptr(name(0))
sendmsg objinfo_hwnd(id_list), LVM_GETITEMTEXTA, index1, varptr(lvitem)
lvitem.5 = varptr(name(1))
sendmsg objinfo_hwnd(id_list), LVM_GETITEMTEXTA, index2, varptr(lvitem)
return
// サブアイテム(ファイルサイズ)でソート
// 第3引数が0なら昇順、1なら降順
*sort_flag
if var_type == vartype("int") {
return compareAsInt@mod_listview(id_list, callbkarg(0), callbkarg(1), callbkarg(2))
} else : if var_type == vartype("str") {
return compareAsStr@mod_listview(id_list, callbkarg(0), callbkarg(1), callbkarg(2))
}
return 0
#global // end of mod_listview
// 疑似的な「ファイル」の数
#define NUM_FILES 10
randomize
gosub *createGuiObjects
stop
// ボタンクリックによって呼び出されるサブルーチン
*sort_asc_by_name
sort id_list, 0, vartype("str"), 0
return
*sort_desc_by_name
sort id_list, 0, vartype("str"), 1
return
*sort_asc_by_size
sort id_list, 1, vartype("int"), 0
return
*sort_desc_by_size
sort id_list, 1, vartype("int"), 1
return
// ボタンとリストビューの作成
*createGuiObjects
// ボタンを作成
objsize ginfo_winx / 4, 32
pos 0, 0 : button gosub "ファイル名で昇順にソート", *sort_asc_by_name
pos ginfo_winx / 4, 0 : button gosub "ファイル名で降順にソート", *sort_desc_by_name
pos ginfo_winx / 2, 0 : button gosub "ファイルサイズで昇順にソート", *sort_asc_by_size
pos ginfo_winx * 3 / 4, 0 : button gosub "ファイルサイズで降順にソート", *sort_desc_by_size
// リストビューコントロール作成
pos 0, 32 : objsize ginfo_winx, ginfo_winy - 32
make_listview : id_list = stat
// カラムを追加
column_name = "ファイル名", "ファイルサイズ"
repeat 2
add_column id_list, column_name(cnt), cnt
if stat == -1 {
dialog "カラムの追加に失敗", 1
end
}
loop
// アイテム・サブアイテムの追加
sdim item_name, 64, 2
repeat NUM_FILES
item_name = "ファイル" + cnt, "" + rnd(1000) + " KB"
add_item id_list, item_name, cnt
if stat == -1 {
dialog "アイテムの追加に失敗", 1
end
}
loop
return
2008年2月5日火曜日
正規表現でHTMLの見出しを抽出する
bregonig.dllを使いたくて「ヘッダファイル作ろうかなー」と考えていたら既に月影ともさん(と猫太さん)が作成されていました。
COMによる正規表現は何かと不便なので、今後重宝しそうです。
リンク先を変更。[08/05/03]// つーさのくーかん「物置 > HSP3 > BREGEXP.hsp」
// http://tu-sa.net/0360
#runtime "hsp3cl"
#include "bregexp.hsp"
dialog "htm;*.html", 16, "見出しを抽出するHTMLファイル"
if stat == 0 : end
notesel file
noteload refstr
position = 0
margin_left = "-", "--", "---", "----", "-----", "------"
repeat
result = BMatch(file, position, "m#<[hH]([1-6])[^>]*>(.*)</[hH]\\1>#k")
if result == -1 : break
mes margin_left(int(BMGetStr(1))-1) + BMGetStr(2)
position += BMGetNextPos()
loop
stop