cyross-ruby-miyako 2.0.5.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. data/README +1092 -929
  2. data/Rakefile +7 -7
  3. data/defines.h +144 -144
  4. data/extern.h +29 -29
  5. data/install_miyako.rb +87 -87
  6. data/lib/Miyako/API/audio.rb +572 -198
  7. data/lib/Miyako/API/basic_data.rb +825 -573
  8. data/lib/Miyako/API/bitmap.rb +534 -507
  9. data/lib/Miyako/API/choices.rb +481 -475
  10. data/lib/Miyako/API/collision.rb +486 -460
  11. data/lib/Miyako/API/diagram.rb +586 -561
  12. data/lib/Miyako/API/drawing.rb +151 -151
  13. data/lib/Miyako/API/exceptions.rb +105 -0
  14. data/lib/Miyako/API/fixedmap.rb +462 -428
  15. data/lib/Miyako/API/font.rb +430 -403
  16. data/lib/Miyako/API/input.rb +456 -447
  17. data/lib/Miyako/API/layout.rb +636 -433
  18. data/lib/Miyako/API/map.rb +583 -529
  19. data/lib/Miyako/API/map_event.rb +222 -198
  20. data/lib/Miyako/API/modules.rb +357 -109
  21. data/lib/Miyako/API/movie.rb +166 -154
  22. data/lib/Miyako/API/parts.rb +276 -189
  23. data/lib/Miyako/API/plane.rb +205 -166
  24. data/lib/Miyako/API/screen.rb +341 -325
  25. data/lib/Miyako/API/shape.rb +443 -443
  26. data/lib/Miyako/API/sprite.rb +771 -752
  27. data/lib/Miyako/API/sprite_animation.rb +490 -481
  28. data/lib/Miyako/API/sprite_list.rb +1135 -0
  29. data/lib/Miyako/API/spriteunit.rb +168 -147
  30. data/lib/Miyako/API/story.rb +350 -300
  31. data/lib/Miyako/API/textbox.rb +770 -725
  32. data/lib/Miyako/API/utility.rb +419 -388
  33. data/lib/Miyako/API/viewport.rb +189 -139
  34. data/lib/Miyako/API/yuki.rb +1226 -996
  35. data/lib/Miyako/EXT/miyako_cairo.rb +62 -62
  36. data/lib/Miyako/EXT/raster_scroll.rb +138 -138
  37. data/lib/Miyako/EXT/slides.rb +157 -157
  38. data/lib/Miyako/miyako.rb +201 -171
  39. data/lib/Miyako/miyako_require_only.rb +35 -0
  40. data/miyako_basicdata.c +590 -590
  41. data/miyako_bitmap.c +1225 -1225
  42. data/miyako_collision.c +403 -403
  43. data/miyako_drawing.c +187 -187
  44. data/miyako_font.c +334 -334
  45. data/miyako_hsv.c +830 -830
  46. data/miyako_input_audio.c +254 -0
  47. data/miyako_layout.c +191 -191
  48. data/miyako_no_katana.c +1078 -1074
  49. data/miyako_sprite2.c +431 -0
  50. data/miyako_transform.c +438 -438
  51. data/miyako_utility.c +288 -288
  52. data/sample/Animation1/m1ku.rb +68 -68
  53. data/sample/Animation2/lex.rb +96 -96
  54. data/sample/Diagram_sample/diagram_sample_yuki2.rb +328 -386
  55. data/sample/Room3/blue.rb +297 -297
  56. data/sample/Room3/ending.rb +180 -180
  57. data/sample/Room3/green.rb +220 -220
  58. data/sample/Room3/main.rb +119 -119
  59. data/sample/Room3/main_component.rb +59 -59
  60. data/sample/Room3/red.rb +227 -227
  61. data/sample/Room3/room3.rb +25 -27
  62. data/sample/Room3/title.rb +184 -184
  63. data/sample/ball_action_sample.rb +204 -204
  64. data/sample/blit_rop.rb +70 -70
  65. data/sample/cairo_sample.rb +25 -25
  66. data/sample/circle_collision_test.rb +66 -66
  67. data/sample/collision_test.rb +33 -33
  68. data/sample/collision_test2.rb +108 -108
  69. data/sample/fixed_map_test/fixed_map_sample.rb +140 -140
  70. data/sample/fixed_map_test/readme.txt +72 -72
  71. data/sample/map_test/chara.rb +58 -58
  72. data/sample/map_test/main_parts.rb +69 -69
  73. data/sample/map_test/main_scene.rb +153 -153
  74. data/sample/map_test/map_manager.rb +75 -75
  75. data/sample/map_test/map_test.rb +23 -23
  76. data/sample/map_test/oasis.rb +71 -71
  77. data/sample/map_test/readme.txt +89 -89
  78. data/sample/map_test/route.rb +157 -157
  79. data/sample/map_test/town.rb +74 -74
  80. data/sample/polygon_test.rb +35 -35
  81. data/sample/rasterscroll.rb +24 -24
  82. data/sample/takahashi.rb +42 -42
  83. data/sample/textbox_sample.rb +189 -189
  84. data/sample/transform.rb +54 -54
  85. data/sample/utility_test.rb +73 -73
  86. data/sample/utility_test2.rb +61 -61
  87. data/sample/utility_test3.rb +64 -64
  88. data/sample/utility_test4.rb +73 -73
  89. data/uninstall_miyako.rb +19 -19
  90. data/win/miyako_no_katana.so +0 -0
  91. metadata +7 -2
@@ -1,725 +1,770 @@
1
- # -*- encoding: utf-8 -*-
2
- =begin
3
- --
4
- Miyako v2.0
5
- Copyright (C) 2007-2008 Cyross Makoto
6
-
7
- This library is free software; you can redistribute it and/or
8
- modify it under the terms of the GNU Lesser General Public
9
- License as published by the Free Software Foundation; either
10
- version 2.1 of the License, or (at your option) any later version.
11
-
12
- This library is distributed in the hope that it will be useful,
13
- but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
- Lesser General Public License for more details.
16
-
17
- You should have received a copy of the GNU Lesser General Public
18
- License along with this library; if not, write to the Free Software
19
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
- ++
21
- =end
22
-
23
- module Miyako
24
- #==テキストボックスを構成するクラス
25
- #テキスト表示部、ウェイトカーソル、選択カーソルで構成される
26
- class TextBox
27
- include SpriteBase
28
- include Animation
29
- include Layout
30
- extend Forwardable
31
-
32
- attr_accessor :textarea
33
- attr_accessor :select_type, :waiting, :selecting
34
- attr_accessor :font, :margin
35
- attr_reader :wait_cursor, :select_cursor, :choices
36
- attr_reader :locate, :size, :max_height
37
-
38
- #===インスタンスの作成
39
- #テキストボックスを生成する。パラメータは以下の通り。
40
- #(括弧内は省略形)
41
- #_:font_:: 描画フォント(Fontクラスのインスタンス) デフォルトはFont.sans_serif
42
- #_:size_:: 描画文字数(2要素の配列またはSize構造体のインスタンス) デフォルトはSize(20,8)
43
- #_:wait_cursor(:wc)_:: ボタン入力待ちを示すカーソル(SpriteもしくはSpriteAnimationクラスのインスタンス)
44
- #_:select_cursor(:sc)_:: 選択カーソル(SpriteもしくはSpriteAnimationクラスのインスタンス)
45
- #_:page_size_:: 一度にテキストボックスに表示させる選択肢の数(縦方向、デフォルトは8)
46
- #
47
- #_params_:: 生成時のパラメータ(ハッシュ引数)
48
- #返却値:: TextBoxクラスのインスタンス
49
- def initialize(params = {})
50
- init_layout
51
- @visible = true
52
- @font = params[:font] || Font.sans_serif
53
- @max_height = @font.line_height
54
- @locate = Point.new(0, 0)
55
-
56
- @base = params[:size] || Size.new(20, 8)
57
- @size = Size.new((@font.size + @font.hspace) * @base[0] - @font.hspace +
58
- (@font.use_shadow ? @font.shadow_margin[0] : 0),
59
- @font.line_height *
60
- @base[1] - @font.vspace)
61
- @pos = Point.new(0, 0)
62
- set_layout_size(*@size)
63
-
64
- @margin = 0
65
-
66
- @textarea = Sprite.new({:size => @size, :type => :ac, :is_fill => true})
67
-
68
- @default_wait_cursor_position = lambda{|wcursor, tbox| wcursor.center.outside_bottom}
69
- @default_select_cursor_position = lambda{|scursor, tbox| scursor.outside_left.middle}
70
-
71
- @wait_cursor = params[:wait_cursor] || params[:wc] || nil
72
- @wait_cursor_position = @default_wait_cursor_position
73
- @select_cursor = params[:select_cursor] || params[:sc] || nil
74
- @select_cursor_position = @default_select_cursor_position
75
-
76
- @on_pause = lambda{}
77
-
78
- @on_release = lambda{}
79
-
80
- @on_draw = lambda{}
81
-
82
- @command_page_size = params[:page_size] || @base[1]
83
-
84
- @choices = Choices.new
85
- @choices.snap(self)
86
- @choices.left.top
87
-
88
- @now_choice = nil
89
- @pre_attach = false
90
-
91
- @waiting = false
92
- @select_type = :left
93
- @selecting = false
94
-
95
- @textarea.snap(self)
96
- @textarea.centering
97
-
98
- @fiber = nil
99
-
100
- if @wait_cursor
101
- @wait_cursor.snap(self)
102
- @default_wait_cursor_position.call(@wait_cursor, self)
103
- end
104
- @select_cursor.snap(self) if @select_cursor
105
-
106
- @move_list = [
107
- [lambda{ },
108
- lambda{ @choices.right_choice },
109
- lambda{ @choices.left_choice }],
110
- [lambda{ @choices.down_choice },
111
- lambda{ },
112
- lambda{ }],
113
- [lambda{ @choices.up_choice },
114
- lambda{ },
115
- lambda{ }]
116
- ]
117
-
118
- end
119
-
120
- #===表示可能な文字行数を取得する
121
- #返却値:: 表示可能な行数
122
- def rows
123
- return @base.h
124
- end
125
-
126
- #===一列に表示可能な文字数を取得する
127
- # 返却される値は全角文字の数だが、半角文字も全角文字1文字と計算されるので注意
128
- #返却値:: 表示可能な文字数
129
- def columns
130
- return @base.w
131
- end
132
-
133
- #===一列に表示可能な文字数と行数を取得する
134
- # 文字数はcolumns、行数はrowsの値と同一
135
- # Size構造体のインスタンスとして取得
136
- #返却値:: 表示可能な文字数と行数
137
- def text_size
138
- return Size.new(@base.w, @base.h)
139
- end
140
-
141
- #===並行なブロック処理を開始する
142
- # ブロックをFiberに渡して、並行実行できるようにして、Fiberを開始する
143
- # ブロックには引数を必ず一つ付けること。引数には自分自身と、
144
- #executeメソッドの引数リスト(配列化されて渡ってくる)が渡ってくる。
145
- # 渡したブロックは、現在の処理と切り替えて実行することになる
146
- # 現在の処理からブロック処理へ切り替えるときは、TextBox#updateメソッドを呼び出す
147
- # ブロック処理から現在の処理に戻るには、ブロックから抜け出すか、
148
- #draw_text・command・pause・clear・cr・spaceのどれかのメソッドを呼び出す。
149
- #_params_:: Fiberに渡す引数リスト。Fiberへは配列として渡される
150
- def execute(*params, &block)
151
- raise MiyakoError, "This method needs a block!" unless block
152
- raise MiyakoError, "This method needs a block with one parameter!" unless block.arity == 2
153
- @fiber = Fiber.new(&block)
154
- @fiber.resume(self, params)
155
- end
156
-
157
- #===並行ブロック処理が実行中かどうかを問い合わせる
158
- #返却値:: Fiberが評価中ならば、trueを返す
159
- def execute?
160
- return @fiber != nil
161
- end
162
-
163
- #===並行ブロック処理を更新する
164
- # 内部でFiberが評価中ならば、Fiberに処理を移す
165
- #返却値:: 自分自身を返す
166
- def update
167
- begin
168
- @fiber.resume if @fiber
169
- rescue FiberError
170
- @fiber = nil
171
- end
172
- return self
173
- end
174
-
175
- #===テキストボックスのアニメーションを開始する
176
- #返却値:: 自分自身を返す
177
- def start
178
- @textarea.start
179
- @wait_cursor.start if @wait_cursor
180
- @choices.start
181
- @select_cursor.start if @select_cursor
182
- return self
183
- end
184
-
185
- #===テキストボックスのアニメーションを停止する
186
- #返却値:: 自分自身を返す
187
- def stop
188
- @textarea.stop
189
- @wait_cursor.stop if @wait_cursor
190
- @choices.stop
191
- @select_cursor.stop if @select_cursor
192
- return self
193
- end
194
-
195
- #===テキストボックスのアニメーションを先頭に戻す
196
- #返却値:: 自分自身を返す
197
- def reset
198
- @textarea.reset
199
- @wait_cursor.reset if @wait_cursor
200
- @choices.reset
201
- @select_cursor.reset if @select_cursor
202
- return self
203
- end
204
-
205
- #===テキストボックスの表示を更新する
206
- #テキストボックス・選択カーソル・選択肢・ウェイトカーソルのアニメーションを更新する
207
- #返却値:: 常にfalseを返す
208
- def update_animation
209
- @textarea.update_animation
210
- @wait_cursor.update_animation if (@wait_cursor && @waiting)
211
- if @selecting
212
- @choices.update_animation
213
- @select_cursor.update_animation if @select_cursor
214
- end
215
- return false
216
- end
217
-
218
- #===スプライトに変換した画像を表示する
219
- #すべてのパーツを貼り付けた、1枚のスプライトを返す
220
- #引数1個のブロックを渡せば、スプライトに補正をかけることが出来る
221
- #返却値:: 描画したスプライト
222
- def to_sprite
223
- rect = self.broad_rect
224
- sprite = Sprite.new(:size=>rect.to_a[2,2], :type=>:ac)
225
- Drawing.fill(sprite, [0,0,0])
226
- Bitmap.ck_to_ac!(sprite, [0,0,0])
227
- self.render_to(sprite){|sunit, dunit| sunit.x -= rect.x; sunit.y -= rect.y }
228
- yield sprite if block_given?
229
- return sprite
230
- end
231
-
232
- #===SpriteUnit構造体を生成する
233
- #いったんSpriteインスタンスを作成し、それをもとにSpriteUnit構造体を生成する。
234
- #返却値:: 生成したSpriteUnit構造体
235
- def to_unit
236
- return self.to_sprite.to_unit
237
- end
238
-
239
- #===現在の画面の最大の大きさを矩形で取得する
240
- #テキストボックスの状態により、取得できる矩形の大きさが変わる
241
- #返却値:: 生成された矩形(Rect構造体のインスタンス)
242
- def broad_rect
243
- rect = self.rect.to_a
244
- rect_list = []
245
- rect_list << @wait_cursor.broad_rect if (@wait_cursor && @waiting)
246
- if @selecting
247
- rect_list << @choices.broad_rect
248
- rect_list << @select_cursor.broad_rect if @select_cursor
249
- end
250
- return self.rect if rect_list.length == 0
251
- rect_list = rect.zip(*rect_list)
252
- # width -> right
253
- rect_list[2] = rect_list[2].zip(rect_list[0]).map{|xw| xw[0] + xw[1]}
254
- # height -> bottom
255
- rect_list[3] = rect_list[3].zip(rect_list[1]).map{|xw| xw[0] + xw[1]}
256
- x, y = rect_list[0].min, rect_list[1].min
257
- return Rect.new(x, y, rect_list[2].max - x, rect_list[3].max - y)
258
- end
259
-
260
- #===画面に描画する
261
- #現在のテキストエリア・カーソルを、現在の状態で描画する
262
- #ブロック付きで呼び出し可能(レシーバに対応したSpriteUnit構造体が引数として得られるので、補正をかけることが出来る。
263
- #ブロックの引数は、|インスタンスのSpriteUnit, 画面のSpriteUnit|となる。
264
- #visibleメソッドの値がfalseのときは描画されない。
265
- #返却値:: 自分自身を返す
266
- def render(&block)
267
- return unless @visible
268
- @textarea.render(&block)
269
- @wait_cursor.render(&block) if (@wait_cursor && @waiting)
270
- if @selecting
271
- @choices.render(&block)
272
- @select_cursor.render(&block) if @select_cursor
273
- end
274
- return self
275
- end
276
-
277
- #===画面に描画する
278
- #現在のテキストエリア・カーソルを、現在の状態で描画する
279
- #ブロック付きで呼び出し可能(レシーバに対応したSpriteUnit構造体が引数として得られるので、補正をかけることが出来る。
280
- #ブロックの引数は、|インスタンスのSpriteUnit, 転送先のSpriteUnit|となる。
281
- #visibleメソッドの値がfalseのときは描画されない。
282
- #返却値:: 自分自身を返す
283
- def render_to(dst, &block)
284
- return unless @visible
285
- @textarea.render_to(dst, &block)
286
- @wait_cursor.render(dst, &block) if (@wait_cursor && @waiting)
287
- if @selecting
288
- @choices.render(dst, &block)
289
- @select_cursor.render(dst, &block) if @select_cursor
290
- end
291
- return self
292
- end
293
-
294
- #===文字の描画位置にマージンを設定する
295
- #marginで指定したピクセルぶん、下に描画する
296
- #ブロックを渡すと、ブロックを評価している間だけマージンが有効になる
297
- #_margin_:: 設定するマージン
298
- #返却値:: 自分自身を返す
299
- def margin_during(margin)
300
- raise MiyakoError, "not given block!" unless block_given?
301
- omargin, @margin = @margin, margin
302
- yield
303
- @margin = omargin
304
- return self
305
- end
306
-
307
- #===指定した高さで描画する際のマージンを求める
308
- #現在のフォントの設定で指定の文字列を描画したとき、予想される描画サイズを返す。実際に描画は行われない。
309
- #第1引数に渡す"align"は、以下の3種類のシンボルのどれかを渡す
310
- #_:top_:: 上側に描画(マージンはゼロ)
311
- #_:middle_:: 中間に描画
312
- #_:bottom_:: 下部に描画
313
- #
314
- #_align_:: 描画位置
315
- #_height_:: 描画する高さ(デフォルトは、描画した最大の高さ)
316
- #返却値:: マージンの値
317
- def margin_height(align, height = @max_height)
318
- return @font.margin_height(align, height)
319
- end
320
-
321
- #===ブロックを評価している間、文字色を変更する
322
- #_color_:: 変更する文字色([r,g,b]の3要素の配列(値:0~255))
323
- #返却値:: 自分自身を返す
324
- def color_during(color)
325
- raise MiyakoError, "not given block!" unless block_given?
326
- @font.color_during(Color.to_rgb(color)){ yield }
327
- return self
328
- end
329
-
330
- #===フォントサイズを変更する
331
- #行中の最大フォントサイズが更新されるので、見栄えの良い表示のためにこちらを使用することをお薦めします
332
- #_size_:: 変更するフォントサイズ
333
- #返却値:: 自分自身を返す
334
- def font_size=(size)
335
- @font.size = size
336
- @max_height = @font.line_height if @max_height < @font.line_height
337
- return self
338
- end
339
-
340
- #===ブロックを評価している間、フォントサイズを変更する
341
- #_size_:: 変更するフォントサイズ
342
- #返却値:: 自分自身を返す
343
- def font_size_during(size)
344
- raise MiyakoError, "not given block!" unless block_given?
345
- @font.size_during(size){
346
- @max_height = @font.line_height if @max_height < @font.line_height
347
- yield
348
- }
349
- return self
350
- end
351
-
352
- #===ブロックを評価している間、太字に変更する
353
- #文字が領域外にはみ出る場合があるので注意!
354
- #返却値:: 自分自身を返す
355
- def font_bold
356
- raise MiyakoError, "not given block!" unless block_given?
357
- @font.bold{ yield }
358
- return self
359
- end
360
-
361
- #===ブロックを評価している間、斜体文字に変更する
362
- #文字が領域外にはみ出る場合があるので注意!
363
- #返却値:: 自分自身を返す
364
- def font_italic
365
- raise MiyakoError, "not given block!" unless block_given?
366
- @font.italic{ yield }
367
- return self
368
- end
369
-
370
- #===ブロックを評価している間、下線付き文字に変更する
371
- #返却値:: 自分自身を返す
372
- def font_under_line
373
- raise MiyakoError, "not given block!" unless block_given?
374
- @font.under_line{ yield }
375
- return self
376
- end
377
-
378
- #===テキストエリアに文字を描画する
379
- #_text_:: 描画する文字列
380
- #返却値:: 自分自身を返す
381
- def draw_text(text)
382
- @locate.x = @font.draw_text(@textarea, text, @locate.x, @locate.y + @margin)
383
- @max_height = [@max_height, @font.line_height].max
384
- @on_draw.call
385
- Fiber.yield if @fiber
386
- return self
387
- end
388
-
389
- #===文字描画時に行う処理を記述したブロックを登録する
390
- #処理を行うブロックはオブジェクトとして渡す。
391
- #ブロック引数の時は、そのブロックを処理している間のみ、そのオブジェクトを呼び出して処理させる
392
- #_event_:: 文字描画時処理するブロック
393
- #返却値:: 自分自身を返す
394
- def on_draw=(event)
395
- tdraw = @on_draw
396
- @on_draw = event
397
- if block_given?
398
- yield
399
- @on_draw = tdraw
400
- end
401
- return self
402
- end
403
-
404
- #===選択肢の集合をTextBoxインスタンスに見合う形のChoicesクラスインスタンスの配列に変換する
405
- #ブロック(引数一つのブロックのみ有効)を渡したときは、ブロックを評価して変換したChoicesクラスの配列を作成する。
406
- #引数は、以下の構成を持つ配列のリスト。
407
- #[非選択時スプライト(文字列可),選択時スプライト(文字列・nil可),選択結果インスタンス]
408
- # 非選択時スプライト:自身が選択されていない時に表示するスプライト。文字列の時は、Shapeクラスなどでスプライトに変更する
409
- # 選択時スプライト:自身が選択されている時に表示するスプライト。文字列の時は、Shapeクラスなどでスプライトに変更する
410
- # (そのとき、文字色が赤色になる)。
411
- # nilを渡すと、非選択時スプライトが使われる
412
- # 注:スプライトは、画面にスナップしておくこと
413
- # 選択結果インスタンス:コマンドが決定したときに、resultメソッドの値として渡すインスタンス。
414
- # デフォルト処理の選択肢の位置は、画面左上から下へ順番に設定される
415
- # 注:ブロックを渡すとき、選択肢の位置計算が、全選択肢の左上位置が[0,0]とする相対座標になっていること
416
- #_choices_:: 選択肢の集合(上記参照)
417
- #返却値:: Choicesクラスのインスタンスの配列
418
- def create_choices_chain(choices)
419
- if block_given?
420
- return yield(choices)
421
- end
422
- choices = choices.map{|v|
423
- org_font_color = @font.color
424
- @font.color = Color[:white]
425
- body = v[0].method(:to_sprite).arity == 0 ? v[0].to_sprite : v[0].to_sprite(@font)
426
- @font.color = Color[:red]
427
- body_selected = v[1] ? (v[1].method(:to_sprite).arity == 0 ? v[1].to_sprite : v[1].to_sprite(@font)) : body
428
- @font.color = org_font_color
429
- choice = Choices.create_choice(body, body_selected)
430
- choice.result = v[2]
431
- choice.end_select_proc = v[3]
432
- next choice
433
- }
434
- choices2 = choices.each_slice(@command_page_size).to_a
435
- choices2.each_with_index{|cc, x|
436
- len = cc.length
437
- right = choices2[x + 1] || choices2[0]
438
- left = choices2[x - 1]
439
- yp = 0
440
- cc.each_with_index{|v, y|
441
- v.down = cc[y + 1] || cc[0]
442
- v.up = cc[y - 1]
443
- v.right = right[y] || right.last
444
- v.left = left[y] || left.last
445
- v.body.move_to(0, yp)
446
- v.body_selected.move_to(0, yp)
447
- yp += [v.body.broad_rect.h, v.body_selected.broad_rect.h].max
448
- }
449
- }
450
- return choices2
451
- end
452
-
453
- #===コマンド選択を設定する
454
- #コマンド選択処理に移る(self#selecting?メソッドがtrueになる)
455
- #
456
- # 引数choicesに配列を渡すとき、各要素の構成は以下のようになる
457
- # [コマンド文字列・画像,選択時コマンド文字列・画像,選択した結果(オブジェクト)]
458
- #
459
- # 引数choicesにChoicesクラスインスタンスを渡したとき、内部で、インスタンスを複写したものに置き換える
460
- #
461
- # このメソッドが呼び出された時、選択肢はlocateメソッドの値となる位置に移動する
462
- # 引数dx,dyともにnil以外の数値を渡すと、上記の位置から更に移動する(位置が補正される)
463
- # body_selectedをnilにした場合は、bodyと同一となる
464
- # body_selectedを文字列を指定した場合は、文字色が赤色になることに注意
465
- #_choices_:: 選択肢の配列、もしくはChoicesクラスのインスタンス
466
- #_dx_:: 選択肢を表示するx座標の移動量。デフォルトはnil(移動しない)
467
- #_dy_:: 選択肢を表示するy座標の移動量。デフォルトはnil(移動しない)
468
- #返却値:: 自分自身を返す
469
- def command(choices, dx = nil, dy = nil)
470
- if choices.methods.include?(:start_choice)
471
- @choices = choices.dup
472
- @choices.snap(self)
473
- else
474
- @choices.clear
475
- choices.each{|cc| @choices.create_choices(cc) }
476
- end
477
- @choices.left{|b| @locate.x}.top{|b| @locate.y}
478
- @choices.move(dx, dy) if (dx != nil && dy != nil)
479
- start_command
480
- Fiber.yield if @fiber
481
- return self
482
- end
483
-
484
- #===コマンド選択を開始する
485
- #但し、commandメソッドを呼び出したときは自動的に呼ばれる
486
- #返却値:: 自分自身を返す
487
- def start_command
488
- raise MiyakoError, "don't set Choice!" if @choices.length == 0
489
- @choices.start_choice
490
- if @select_cursor
491
- @select_cursor.snap(@choices.body)
492
- @select_cursor_position.call(@select_cursor, @choices.body)
493
- end
494
- @selecting = true
495
- return self
496
- end
497
-
498
- #===コマンド選択を終了する
499
- # 選択した選択肢(Choice構造体)にend_select_procブロックが設定されていれば自動的に評価される
500
- #返却値:: 自分自身を返す
501
- def finish_command
502
- @choices.end_choice(self)
503
- @choices.left.top
504
- @selecting = false
505
- return self
506
- end
507
-
508
- #===選択肢・選択カーソルを移動させる
509
- #但し、非選択状態だったときは、選択状態に戻るだけ
510
- #(そのときの選択肢は、最後に選択した選択肢を指定する)
511
- #_dx_:: 移動量(x軸方向)。-1,0,1の3種類
512
- #_dy_:: 移動量(y軸方向)。-1,0,1の3種類
513
- #返却値:: 自分自身を返す
514
- def move_cursor(dx, dy)
515
- unless @choices.any_select?
516
- @choices.start_choice(nil) # 選択状態を元に戻す
517
- return self
518
- end
519
- @move_list[dy][dx].call
520
- if @select_cursor
521
- @select_cursor.snap(@choices.body)
522
- @select_cursor_position.call(@select_cursor, @choices.body)
523
- end
524
- return self
525
- end
526
-
527
- #===マウスカーソルの位置とコマンドを照合する
528
- #選択肢・選択カーソルを、マウスカーソルが当たっているコマンドに移動させる
529
- #どのコマンドにも当たっていない場合は、すべてのコマンドは非選択状態になる
530
- #_x_:: マウスカーソルの位置(x軸方向)
531
- #_y_:: マウスカーソルの位置(y軸方向)
532
- #返却値:: 自分自身を返す
533
- def attach_cursor(x, y)
534
- attach = @choices.attach(x, y)
535
- if attach
536
- if @select_cursor
537
- @select_cursor.snap(@choices.body)
538
- @select_cursor_position.call(@select_cursor, @choices.body)
539
- end
540
- else
541
- @choices.non_select if @pre_attach
542
- end
543
- @pre_attach = attach
544
- return self
545
- end
546
-
547
- #===マウスカーソルの位置にコマンドがあるかどうかを問い合わせる
548
- #マウスカーソルがどれかのコマンドの上にあるときはtrue、どれにも当たっていないときはfalseを返す
549
- #_x_:: マウスカーソルの位置(x軸方向)
550
- #_y_:: マウスカーソルの位置(y軸方向)
551
- #返却値:: マウスカーソルがどれかのコマンドにあるときはtrueを返す
552
- def attach_any_command?(x, y)
553
- return @choices.attach(x, y)
554
- end
555
-
556
- def update_layout_position #:nodoc:
557
- @pos.move_to(*@layout.pos)
558
- end
559
-
560
- #===入力待ち状態(ポーズ)に表示するカーソルの位置を設定する
561
- #ポーズカーソルの位置を、パラメータ二つ(カーソル本体・テキストボックス)を引数に取るブロックで実装する
562
- #位置は、テキストエリアをsnapしていると想定して実装する
563
- #デフォルトは、テキストエリアの中下に置かれる(center.bottom)
564
- # (例)テキストボックスの中下(テキストエリアの外) -> {|wc, tbox| wc.center.outside_bottom }
565
- #   テキストボックスの右下(テキストエリアの中) -> {|wc, tbox| wc.right.bottom }
566
- #   テキストの最後尾 -> {|wc, tbox| wc.left{|b| tbox.locate.x }.top{|b| tbox.locate.y} }
567
- # (テキストエリアの左上から右下へ現在の描画開始位置(tbox.locateメソッドで示した値)の距離移動した箇所)
568
- #ブロックを渡していなかったり、ブロックの引数が2個でなければエラーを返す
569
- #返却値:: 自分自身を返す
570
- def set_wait_cursor_position(&proc)
571
- raise MiyakoError, "Can't find block!" unless proc
572
- raise MiyakoError, "This method must have two parameters!" unless proc.arity == 2
573
- @wait_cursor_position = proc
574
- @wait_cursor_position.call(@wait_cursor, self) if @wait_cursor
575
- return self
576
- end
577
-
578
- #===入力待ち状態(ポーズ)に表示するカーソルの位置をデフォルトに戻す
579
- #デフォルトの位置は、テキストエリアの中下(center.bottom)に設定されている
580
- #返却値:: 自分自身を返す
581
- def reset_wait_cursor_position
582
- @wait_cursor_position = @default_wait_cursor_position
583
- @wait_cursor_position.call(@wait_cursor, self) if @wait_cursor
584
- return self
585
- end
586
-
587
- #===コマンド選択時に表示するカーソルの位置を設定する
588
- #カーソルの位置を、パラメータ二つ(カーソル本体・選択肢)を引数に取るブロックで実装する
589
- #位置は、テキストエリアをsnapしていると想定して実装する
590
- #デフォルトは、選択肢の左側に置かれる(outside_left.middle)
591
- # (例)選択肢の右側 -> {|wc, choice| wc.outside_right.middle }
592
- #   選択肢の真上 -> {|wc, choice| wc.centering }
593
- #ブロックを渡していなかったり、ブロックの引数が2個でなければエラーを返す
594
- #返却値:: 自分自身を返す
595
- def set_select_cursor_position(&proc)
596
- raise MiyakoError, "Can't find block!" unless proc
597
- raise MiyakoError, "This method must have two parameters!" unless proc.arity == 2
598
- @select_cursor_position = proc
599
- @select_cursor_position.call(@select_cursor, @choices.body) if (@select_cursor && @choices.body)
600
- return self
601
- end
602
-
603
- #===入力待ち状態(ポーズ)に表示するカーソルの位置をデフォルトに戻す
604
- #デフォルトの位置は、テキストエリアの中下(center.bottom)に設定されている
605
- #返却値:: 自分自身を返す
606
- def reset_select_cursor_position
607
- @select_cursor_position = @default_select_cursor_position
608
- @select_cursor_position.call(@select_cursor, @choices.body) if (@select_cursor && @choices.body)
609
- return self
610
- end
611
-
612
- #===入力待ち状態(ポーズ)にする
613
- #ポーズカーソルを表示する。pause?メソッドの結果がtrueになる
614
- #ポーズカーソルの位置は、set_wait_cursor_positionで設定したブロックが評価されて決定される
615
- #(デフォルトはテキストエリアの中下
616
- #返却値:: 自分自身を返す
617
- def pause
618
- @waiting = true
619
- return self unless @wait_cursor
620
- @wait_cursor_position.call(@wait_cursor, self)
621
- @on_pause.call
622
- Fiber.yield if @fiber
623
- return self
624
- end
625
-
626
- #===ポーズ時に行う処理を記述したブロックを登録する
627
- #処理を行うブロックはオブジェクトとして渡す。
628
- #ブロック引数の時は、そのブロックを処理している間のみ、そのオブジェクトを呼び出して処理させる
629
- #_event_:: ポーズ時処理するブロック
630
- #返却値:: 自分自身を返す
631
- def on_pause=(event)
632
- tpause = @on_pause
633
- @on_pause = event
634
- if block_given?
635
- yield
636
- @on_pause = tpause
637
- end
638
- return self
639
- end
640
-
641
- #===入力待ち状態を解除する
642
- #同時に、ポーズカーソルを隠蔽する。pause?メソッドの結果がfalseになる
643
- #返却値:: 自分自身を返す
644
- def release
645
- @waiting = false
646
- @on_release.call
647
- return self
648
- end
649
-
650
- #===ポーズ解除時に行う処理を記述したブロックを登録する
651
- #処理を行うブロックはオブジェクトとして渡す。
652
- #ブロック引数の時は、そのブロックを処理している間のみ、そのオブジェクトを呼び出して処理させる
653
- #_event_:: ポーズ解除時処理するブロック
654
- #返却値:: 自分自身を返す
655
- def on_release=(event)
656
- trelease = @on_release
657
- @on_release = event
658
- if block_given?
659
- yield
660
- @on_release = trelease
661
- end
662
- return self
663
- end
664
-
665
- #===入力待ち状態かを確認する
666
- #返却値:: 入力待ち状態の時はtrueを返す
667
- def pause?
668
- return @waiting
669
- end
670
-
671
- #===コマンド選択中かどうかを確認する
672
- #返却値:: 選択中の時はtrueを返す
673
- def selecting?
674
- return @selecting
675
- end
676
-
677
- #===選択結果を取得する
678
- #返却値:: コマンドの選択結果(選択中のnilを返す)
679
- def result
680
- return @choices.result
681
- end
682
-
683
- #===テキストエリアに描画している文字を消去する
684
- #透明色で消去したあと、描画開始位置を左上(0,0)に移動する
685
- #返却値:: 自分自身を返す
686
- def clear
687
- @textarea.bitmap.fillRect(0, 0, @size[0], @size[1], [0, 0, 0, 0])
688
- @locate = Point.new(0, 0)
689
- @max_height = @font.line_height
690
- Fiber.yield if @fiber
691
- return self
692
- end
693
-
694
- #===縦方向のスペースを空ける
695
- #現在描画可能な位置から、指定したピクセルで下方向に移動する
696
- #但し、文字の大きさもピクセル数に含むことに注意すること
697
- #_height_:: スペースを空けるピクセル数
698
- #返却値:: 自分自身を返す
699
- def cr(height = @max_height)
700
- @locate.x = 0
701
- @locate.y += height
702
- @max_height = @font.line_height
703
- Fiber.yield if @fiber
704
- return self
705
- end
706
-
707
- #===横方向のスペースを空ける
708
- #現在描画可能な位置から、指定したピクセルで右方向に移動する
709
- #_length_:: スペースを空けるピクセル数
710
- #返却値:: 自分自身を返す
711
- def space(length)
712
- @locate.x += length
713
- Fiber.yield if @fiber
714
- return self
715
- end
716
-
717
- #===情報を解放する
718
- def dispose
719
- @textarea.dispose
720
- @textarea = nil
721
- end
722
-
723
- def_delegators(:@pos, :x, :y)
724
- end
725
- end
1
+ # -*- encoding: utf-8 -*-
2
+ =begin
3
+ --
4
+ Miyako v2.1
5
+ Copyright (C) 2007-2008 Cyross Makoto
6
+
7
+ This library is free software; you can redistribute it and/or
8
+ modify it under the terms of the GNU Lesser General Public
9
+ License as published by the Free Software Foundation; either
10
+ version 2.1 of the License, or (at your option) any later version.
11
+
12
+ This library is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ Lesser General Public License for more details.
16
+
17
+ You should have received a copy of the GNU Lesser General Public
18
+ License along with this library; if not, write to the Free Software
19
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
+ ++
21
+ =end
22
+
23
+ module Miyako
24
+ #==テキストボックスを構成するクラス
25
+ #テキスト表示部、ウェイトカーソル、選択カーソルで構成される
26
+ class TextBox
27
+ include SpriteBase
28
+ include Animation
29
+ include Layout
30
+ extend Forwardable
31
+
32
+ attr_accessor :textarea
33
+ attr_accessor :select_type, :waiting, :selecting
34
+ attr_accessor :font, :margin
35
+ attr_reader :wait_cursor, :select_cursor, :choices
36
+ attr_reader :locate, :size, :max_height
37
+
38
+ #===インスタンスの作成
39
+ #テキストボックスを生成する。パラメータは以下の通り。
40
+ #(括弧内は省略形)
41
+ #_:font_:: 描画フォント(Fontクラスのインスタンス) デフォルトはFont.sans_serif
42
+ #_:size_:: 描画文字数(2要素の配列またはSize構造体のインスタンス) デフォルトはSize(20,8)
43
+ #_:wait_cursor(:wc)_:: ボタン入力待ちを示すカーソル(SpriteもしくはSpriteAnimationクラスのインスタンス)
44
+ #_:select_cursor(:sc)_:: 選択カーソル(SpriteもしくはSpriteAnimationクラスのインスタンス)
45
+ #_:page_size_:: 一度にテキストボックスに表示させる選択肢の数(縦方向、デフォルトは8)
46
+ #
47
+ #_params_:: 生成時のパラメータ(ハッシュ引数)
48
+ #返却値:: TextBoxクラスのインスタンス
49
+ def initialize(params = {})
50
+ init_layout
51
+ @visible = true
52
+ @font = params[:font] || Font.sans_serif
53
+ @max_height = @font.line_height
54
+ @locate = Point.new(0, 0)
55
+
56
+ @base = params[:size] || Size.new(20, 8)
57
+ @size = Size.new((@font.size + @font.hspace) * @base[0] - @font.hspace +
58
+ (@font.use_shadow ? @font.shadow_margin[0] : 0),
59
+ @font.line_height *
60
+ @base[1] - @font.vspace)
61
+ @pos = Point.new(0, 0)
62
+ set_layout_size(*@size)
63
+
64
+ @margin = 0
65
+
66
+ @textarea = Sprite.new({:size => @size, :type => :ac, :is_fill => true})
67
+
68
+ @default_wait_cursor_position = lambda{|wcursor, tbox| wcursor.center!.outside_bottom!}
69
+ @default_select_cursor_position = lambda{|scursor, tbox| scursor.outside_left!.middle!}
70
+
71
+ @wait_cursor = params[:wait_cursor] || params[:wc] || nil
72
+ @wait_cursor_position = @default_wait_cursor_position
73
+ @select_cursor = params[:select_cursor] || params[:sc] || nil
74
+ @select_cursor_position = @default_select_cursor_position
75
+
76
+ @on_pause = lambda{}
77
+
78
+ @on_release = lambda{}
79
+
80
+ @on_draw = lambda{}
81
+
82
+ @command_page_size = params[:page_size] || @base[1]
83
+
84
+ @choices = Choices.new
85
+ @choices.snap(self)
86
+ @choices.left!.top!
87
+
88
+ @now_choice = nil
89
+ @pre_attach = false
90
+
91
+ @waiting = false
92
+ @select_type = :left
93
+ @selecting = false
94
+
95
+ @textarea.snap(self)
96
+ @textarea.centering!
97
+
98
+ @fiber = nil
99
+
100
+ if @wait_cursor
101
+ @wait_cursor.snap(self)
102
+ @default_wait_cursor_position.call(@wait_cursor, self)
103
+ end
104
+ @select_cursor.snap(self) if @select_cursor
105
+
106
+ @move_list = [
107
+ [lambda{ },
108
+ lambda{ @choices.right_choice },
109
+ lambda{ @choices.left_choice }],
110
+ [lambda{ @choices.down_choice },
111
+ lambda{ },
112
+ lambda{ }],
113
+ [lambda{ @choices.up_choice },
114
+ lambda{ },
115
+ lambda{ }]
116
+ ]
117
+
118
+ end
119
+
120
+ def initialize_copy(obj) #:nodoc:
121
+ copy_layout
122
+ reset_snap
123
+
124
+ @locate = @locate.dup
125
+ @base = @base.dup
126
+ @size = @size.dup
127
+ @pos = @pos.dup
128
+
129
+ @default_wait_cursor_position = @default_wait_cursor_position.dup
130
+ @default_select_cursor_position = @default_select_cursor_position.dup
131
+
132
+ @wait_cursor = @wait_cursor.dup
133
+ @wait_cursor_position = @wait_cursor_position.dup
134
+ @select_cursor = @select_cursor.dup
135
+ @select_cursor_position = @select_cursor_position.dup
136
+
137
+ @on_pause = @on_pause.dup
138
+
139
+ @on_release = @on_release.dup
140
+
141
+ @on_draw = @on_draw.dup
142
+
143
+ @choices = @choices.dup
144
+ @choices.snap(self)
145
+ @choices.left!.top!
146
+
147
+ @waiting = false
148
+ @select_type = :left
149
+ @selecting = false
150
+
151
+ @textarea = @textarea.dup
152
+ @textarea.snap(self)
153
+ @textarea.centering!
154
+
155
+ if @wait_cursor
156
+ @wait_cursor.snap(self)
157
+ @default_wait_cursor_position.call(@wait_cursor, self)
158
+ end
159
+ @select_cursor.snap(self) if @select_cursor
160
+
161
+ @move_list = @move_list.dup
162
+ end
163
+
164
+ #===表示可能な文字行数を取得する
165
+ #返却値:: 表示可能な行数
166
+ def rows
167
+ return @base.h
168
+ end
169
+
170
+ #===一列に表示可能な文字数を取得する
171
+ # 返却される値は全角文字の数だが、半角文字も全角文字1文字と計算されるので注意
172
+ #返却値:: 表示可能な文字数
173
+ def columns
174
+ return @base.w
175
+ end
176
+
177
+ #===一列に表示可能な文字数と行数を取得する
178
+ # 文字数はcolumns、行数はrowsの値と同一
179
+ # Size構造体のインスタンスとして取得
180
+ #返却値:: 表示可能な文字数と行数
181
+ def text_size
182
+ return Size.new(@base.w, @base.h)
183
+ end
184
+
185
+ #===並行なブロック処理を開始する
186
+ # ブロックをFiberに渡して、並行実行できるようにして、Fiberを開始する
187
+ # ブロックには引数を必ず一つ付けること。引数には自分自身と、
188
+ #executeメソッドの引数リスト(配列化されて渡ってくる)が渡ってくる。
189
+ # 渡したブロックは、現在の処理と切り替えて実行することになる
190
+ # 現在の処理からブロック処理へ切り替えるときは、TextBox#updateメソッドを呼び出す
191
+ # ブロック処理から現在の処理に戻るには、ブロックから抜け出すか、
192
+ #draw_text・command・pause・clear・cr・spaceのどれかのメソッドを呼び出す。
193
+ #_params_:: Fiberに渡す引数リスト。Fiberへは配列として渡される
194
+ def execute(*params, &block)
195
+ raise MiyakoProcError, "This method needs a block!" unless block
196
+ raise MiyakoProcError, "This method needs a block with one parameter!" unless block.arity == 2
197
+ @fiber = Fiber.new(&block)
198
+ @fiber.resume(self, params)
199
+ end
200
+
201
+ #===並行ブロック処理が実行中かどうかを問い合わせる
202
+ #返却値:: Fiberが評価中ならば、trueを返す
203
+ def execute?
204
+ return @fiber != nil
205
+ end
206
+
207
+ #===並行ブロック処理を更新する
208
+ # 内部でFiberが評価中ならば、Fiberに処理を移す
209
+ #返却値:: 自分自身を返す
210
+ def update
211
+ begin
212
+ @fiber.resume if @fiber
213
+ rescue FiberError
214
+ @fiber = nil
215
+ end
216
+ return self
217
+ end
218
+
219
+ #===テキストボックスのアニメーションを開始する
220
+ #返却値:: 自分自身を返す
221
+ def start
222
+ @textarea.start
223
+ @wait_cursor.start if @wait_cursor
224
+ @choices.start
225
+ @select_cursor.start if @select_cursor
226
+ return self
227
+ end
228
+
229
+ #===テキストボックスのアニメーションを停止する
230
+ #返却値:: 自分自身を返す
231
+ def stop
232
+ @textarea.stop
233
+ @wait_cursor.stop if @wait_cursor
234
+ @choices.stop
235
+ @select_cursor.stop if @select_cursor
236
+ return self
237
+ end
238
+
239
+ #===テキストボックスのアニメーションを先頭に戻す
240
+ #返却値:: 自分自身を返す
241
+ def reset
242
+ @textarea.reset
243
+ @wait_cursor.reset if @wait_cursor
244
+ @choices.reset
245
+ @select_cursor.reset if @select_cursor
246
+ return self
247
+ end
248
+
249
+ #===テキストボックスの表示を更新する
250
+ #テキストボックス・選択カーソル・選択肢・ウェイトカーソルのアニメーションを更新する
251
+ #返却値:: どれか一つ変更があったときはtrueを返す。それ以外はfalseを返す
252
+ def update_animation
253
+ f = false
254
+ f |= @textarea.update_animation
255
+ f |= @wait_cursor.update_animation if (@wait_cursor && @waiting)
256
+ if @selecting
257
+ f |= @choices.update_animation.any?
258
+ f |= @select_cursor.update_animation if @select_cursor
259
+ end
260
+ return f
261
+ end
262
+
263
+ #===スプライトに変換した画像を表示する
264
+ #すべてのパーツを貼り付けた、1枚のスプライトを返す
265
+ #引数1個のブロックを渡せば、スプライトに補正をかけることが出来る
266
+ #返却値:: 描画したスプライト
267
+ def to_sprite
268
+ rect = self.broad_rect
269
+ sprite = Sprite.new(:size=>rect.to_a[2,2], :type=>:ac)
270
+ Drawing.fill(sprite, [0,0,0])
271
+ Bitmap.ck_to_ac!(sprite, [0,0,0])
272
+ self.render_to(sprite){|sunit, dunit| sunit.x -= rect.x; sunit.y -= rect.y }
273
+ yield sprite if block_given?
274
+ return sprite
275
+ end
276
+
277
+ #===SpriteUnit構造体を生成する
278
+ #いったんSpriteインスタンスを作成し、それをもとにSpriteUnit構造体を生成する。
279
+ #返却値:: 生成したSpriteUnit構造体
280
+ def to_unit
281
+ return self.to_sprite.to_unit
282
+ end
283
+
284
+ #===現在の画面の最大の大きさを矩形で取得する
285
+ #テキストボックスの状態により、取得できる矩形の大きさが変わる
286
+ #返却値:: 生成された矩形(Rect構造体のインスタンス)
287
+ def broad_rect
288
+ rect = self.rect.to_a
289
+ rect_list = []
290
+ rect_list << @wait_cursor.broad_rect if (@wait_cursor && @waiting)
291
+ if @selecting
292
+ rect_list << @choices.broad_rect
293
+ rect_list << @select_cursor.broad_rect if @select_cursor
294
+ end
295
+ return self.rect if rect_list.length == 0
296
+ rect_list = rect.zip(*rect_list)
297
+ # width -> right
298
+ rect_list[2] = rect_list[2].zip(rect_list[0]).map{|xw| xw[0] + xw[1]}
299
+ # height -> bottom
300
+ rect_list[3] = rect_list[3].zip(rect_list[1]).map{|xw| xw[0] + xw[1]}
301
+ x, y = rect_list[0].min, rect_list[1].min
302
+ return Rect.new(x, y, rect_list[2].max - x, rect_list[3].max - y)
303
+ end
304
+
305
+ #===画面に描画する
306
+ #現在のテキストエリア・カーソルを、現在の状態で描画する
307
+ #ブロック付きで呼び出し可能(レシーバに対応したSpriteUnit構造体が引数として得られるので、補正をかけることが出来る。
308
+ #ブロックの引数は、|インスタンスのSpriteUnit, 画面のSpriteUnit|となる。
309
+ #visibleメソッドの値がfalseのときは描画されない。
310
+ #返却値:: 自分自身を返す
311
+ def render(&block)
312
+ return unless @visible
313
+ @textarea.render(&block)
314
+ @wait_cursor.render(&block) if (@wait_cursor && @waiting)
315
+ if @selecting
316
+ @choices.render(&block)
317
+ @select_cursor.render(&block) if @select_cursor
318
+ end
319
+ return self
320
+ end
321
+
322
+ #===画面に描画する
323
+ #現在のテキストエリア・カーソルを、現在の状態で描画する
324
+ #ブロック付きで呼び出し可能(レシーバに対応したSpriteUnit構造体が引数として得られるので、補正をかけることが出来る。
325
+ #ブロックの引数は、|インスタンスのSpriteUnit, 転送先のSpriteUnit|となる。
326
+ #visibleメソッドの値がfalseのときは描画されない。
327
+ #返却値:: 自分自身を返す
328
+ def render_to(dst, &block)
329
+ return unless @visible
330
+ @textarea.render_to(dst, &block)
331
+ @wait_cursor.render(dst, &block) if (@wait_cursor && @waiting)
332
+ if @selecting
333
+ @choices.render(dst, &block)
334
+ @select_cursor.render(dst, &block) if @select_cursor
335
+ end
336
+ return self
337
+ end
338
+
339
+ #===文字の描画位置にマージンを設定する
340
+ #marginで指定したピクセルぶん、下に描画する
341
+ #ブロックを渡すと、ブロックを評価している間だけマージンが有効になる
342
+ #_margin_:: 設定するマージン
343
+ #返却値:: 自分自身を返す
344
+ def margin_during(margin)
345
+ raise MiyakoError, "not given block!" unless block_given?
346
+ omargin, @margin = @margin, margin
347
+ yield
348
+ @margin = omargin
349
+ return self
350
+ end
351
+
352
+ #===指定した高さで描画する際のマージンを求める
353
+ #現在のフォントの設定で指定の文字列を描画したとき、予想される描画サイズを返す。実際に描画は行われない。
354
+ #第1引数に渡す"align"は、以下の3種類のシンボルのどれかを渡す
355
+ #_:top_:: 上側に描画(マージンはゼロ)
356
+ #_:middle_:: 中間に描画
357
+ #_:bottom_:: 下部に描画
358
+ #
359
+ #_align_:: 描画位置
360
+ #_height_:: 描画する高さ(デフォルトは、描画した最大の高さ)
361
+ #返却値:: マージンの値
362
+ def margin_height(align, height = @max_height)
363
+ return @font.margin_height(align, height)
364
+ end
365
+
366
+ #===ブロックを評価している間、文字色を変更する
367
+ #_color_:: 変更する文字色([r,g,b]の3要素の配列(値:0~255))
368
+ #返却値:: 自分自身を返す
369
+ def color_during(color)
370
+ raise MiyakoProcError, "not given block!" unless block_given?
371
+ @font.color_during(Color.to_rgb(color)){ yield }
372
+ return self
373
+ end
374
+
375
+ #===フォントサイズを変更する
376
+ #行中の最大フォントサイズが更新されるので、見栄えの良い表示のためにこちらを使用することをお薦めします
377
+ #_size_:: 変更するフォントサイズ
378
+ #返却値:: 自分自身を返す
379
+ def font_size=(size)
380
+ @font.size = size
381
+ @max_height = @font.line_height if @max_height < @font.line_height
382
+ return self
383
+ end
384
+
385
+ #===ブロックを評価している間、フォントサイズを変更する
386
+ #_size_:: 変更するフォントサイズ
387
+ #返却値:: 自分自身を返す
388
+ def font_size_during(size)
389
+ raise MiyakoProcError, "not given block!" unless block_given?
390
+ @font.size_during(size){
391
+ @max_height = @font.line_height if @max_height < @font.line_height
392
+ yield
393
+ }
394
+ return self
395
+ end
396
+
397
+ #===ブロックを評価している間、太字に変更する
398
+ #文字が領域外にはみ出る場合があるので注意!
399
+ #返却値:: 自分自身を返す
400
+ def font_bold
401
+ raise MiyakoProcError, "not given block!" unless block_given?
402
+ @font.bold{ yield }
403
+ return self
404
+ end
405
+
406
+ #===ブロックを評価している間、斜体文字に変更する
407
+ #文字が領域外にはみ出る場合があるので注意!
408
+ #返却値:: 自分自身を返す
409
+ def font_italic
410
+ raise MiyakoProcError, "not given block!" unless block_given?
411
+ @font.italic{ yield }
412
+ return self
413
+ end
414
+
415
+ #===ブロックを評価している間、下線付き文字に変更する
416
+ #返却値:: 自分自身を返す
417
+ def font_under_line
418
+ raise MiyakoProcError, "not given block!" unless block_given?
419
+ @font.under_line{ yield }
420
+ return self
421
+ end
422
+
423
+ #===テキストエリアに文字を描画する
424
+ #_text_:: 描画する文字列
425
+ #返却値:: 自分自身を返す
426
+ def draw_text(text)
427
+ @locate.x = @font.draw_text(@textarea, text, @locate.x, @locate.y + @margin)
428
+ @max_height = [@max_height, @font.line_height].max
429
+ @on_draw.call
430
+ Fiber.yield if @fiber
431
+ return self
432
+ end
433
+
434
+ #===文字描画時に行う処理を記述したブロックを登録する
435
+ #処理を行うブロックはオブジェクトとして渡す。
436
+ #ブロック引数の時は、そのブロックを処理している間のみ、そのオブジェクトを呼び出して処理させる
437
+ #_event_:: 文字描画時処理するブロック
438
+ #返却値:: 自分自身を返す
439
+ def on_draw=(event)
440
+ tdraw = @on_draw
441
+ @on_draw = event
442
+ if block_given?
443
+ yield
444
+ @on_draw = tdraw
445
+ end
446
+ return self
447
+ end
448
+
449
+ #===選択肢の集合をTextBoxインスタンスに見合う形のChoicesクラスインスタンスの配列に変換する
450
+ #ブロック(引数一つのブロックのみ有効)を渡したときは、ブロックを評価して変換したChoicesクラスの配列を作成する。
451
+ #引数は、以下の構成を持つ配列のリスト。
452
+ #[非選択時スプライト(文字列可),選択時スプライト(文字列・nil可),選択結果インスタンス]
453
+ # 非選択時スプライト:自身が選択されていない時に表示するスプライト。文字列の時は、Shapeクラスなどでスプライトに変更する
454
+ # 選択時スプライト:自身が選択されている時に表示するスプライト。文字列の時は、Shapeクラスなどでスプライトに変更する
455
+ # (そのとき、文字色が赤色になる)。
456
+ # nilを渡すと、非選択時スプライトが使われる
457
+ # 注:スプライトは、画面にスナップしておくこと
458
+ # 選択結果インスタンス:コマンドが決定したときに、resultメソッドの値として渡すインスタンス。
459
+ # デフォルト処理の選択肢の位置は、画面左上から下へ順番に設定される
460
+ # 注:ブロックを渡すとき、選択肢の位置計算が、全選択肢の左上位置が[0,0]とする相対座標になっていること
461
+ #_choices_:: 選択肢の集合(上記参照)
462
+ #返却値:: Choicesクラスのインスタンスの配列
463
+ def create_choices_chain(choices)
464
+ if block_given?
465
+ return yield(choices)
466
+ end
467
+ choices = choices.map{|v|
468
+ org_font_color = @font.color
469
+ @font.color = Color[:white]
470
+ body = v[0].method(:to_sprite).arity == 0 ? v[0].to_sprite : v[0].to_sprite(@font)
471
+ @font.color = Color[:red]
472
+ body_selected = v[1] ? (v[1].method(:to_sprite).arity == 0 ? v[1].to_sprite : v[1].to_sprite(@font)) : body
473
+ @font.color = org_font_color
474
+ choice = Choices.create_choice(body, body_selected)
475
+ choice.result = v[2]
476
+ choice.end_select_proc = v[3]
477
+ next choice
478
+ }
479
+ choices2 = choices.each_slice(@command_page_size).to_a
480
+ choices2.each_with_index{|cc, x|
481
+ len = cc.length
482
+ right = choices2[x + 1] || choices2[0]
483
+ left = choices2[x - 1]
484
+ yp = 0
485
+ cc.each_with_index{|v, y|
486
+ v.down = cc[y + 1] || cc[0]
487
+ v.up = cc[y - 1]
488
+ v.right = right[y] || right.last
489
+ v.left = left[y] || left.last
490
+ v.body.move_to!(0, yp)
491
+ v.body_selected.move_to!(0, yp)
492
+ yp += [v.body.broad_rect.h, v.body_selected.broad_rect.h].max
493
+ }
494
+ }
495
+ return choices2
496
+ end
497
+
498
+ #===コマンド選択を設定する
499
+ #コマンド選択処理に移る(self#selecting?メソッドがtrueになる)
500
+ #
501
+ # 引数choicesに配列を渡すとき、各要素の構成は以下のようになる
502
+ # [コマンド文字列・画像,選択時コマンド文字列・画像,選択した結果(オブジェクト)]
503
+ #
504
+ # 引数choicesにChoicesクラスインスタンスを渡したとき、内部で、インスタンスを複写したものに置き換える
505
+ #
506
+ # このメソッドが呼び出された時、選択肢はlocateメソッドの値となる位置に移動する
507
+ # 引数dx,dyともにnil以外の数値を渡すと、上記の位置から更に移動する(位置が補正される)
508
+ # body_selectedをnilにした場合は、bodyと同一となる
509
+ # body_selectedを文字列を指定した場合は、文字色が赤色になることに注意
510
+ #_choices_:: 選択肢の配列、もしくはChoicesクラスのインスタンス
511
+ #_dx_:: 選択肢を表示するx座標の移動量。デフォルトはnil(移動しない)
512
+ #_dy_:: 選択肢を表示するy座標の移動量。デフォルトはnil(移動しない)
513
+ #返却値:: 自分自身を返す
514
+ def command(choices, dx = nil, dy = nil)
515
+ if choices.methods.include?(:start_choice)
516
+ @choices = choices.dup
517
+ @choices.snap(self)
518
+ else
519
+ @choices.clear
520
+ choices.each{|cc| @choices.create_choices(cc) }
521
+ end
522
+ @choices.left!{|b| @locate.x}.top!{|b| @locate.y}
523
+ @choices.move!(dx, dy) if (dx != nil && dy != nil)
524
+ start_command
525
+ Fiber.yield if @fiber
526
+ return self
527
+ end
528
+
529
+ #===コマンド選択を開始する
530
+ #但し、commandメソッドを呼び出したときは自動的に呼ばれる
531
+ #返却値:: 自分自身を返す
532
+ def start_command
533
+ raise MiyakoValueError, "don't set Choice!" if @choices.length == 0
534
+ @choices.start_choice
535
+ if @select_cursor
536
+ @select_cursor.snap(@choices.body)
537
+ @select_cursor_position.call(@select_cursor, @choices.body)
538
+ end
539
+ @selecting = true
540
+ return self
541
+ end
542
+
543
+ #===コマンド選択を終了する
544
+ # 選択した選択肢(Choice構造体)にend_select_procブロックが設定されていれば自動的に評価される
545
+ #返却値:: 自分自身を返す
546
+ def finish_command
547
+ @choices.end_choice(self)
548
+ @choices.left!.top!
549
+ @selecting = false
550
+ return self
551
+ end
552
+
553
+ #===選択肢・選択カーソルを移動させる
554
+ #但し、非選択状態だったときは、選択状態に戻るだけ
555
+ #(そのときの選択肢は、最後に選択した選択肢を指定する)
556
+ #_dx_:: 移動量(x軸方向)。-1,0,1の3種類
557
+ #_dy_:: 移動量(y軸方向)。-1,0,1の3種類
558
+ #返却値:: 自分自身を返す
559
+ def move_cursor(dx, dy)
560
+ unless @choices.any_select?
561
+ @choices.start_choice(nil) # 選択状態を元に戻す
562
+ return self
563
+ end
564
+ @move_list[dy][dx].call
565
+ if @select_cursor
566
+ @select_cursor.snap(@choices.body)
567
+ @select_cursor_position.call(@select_cursor, @choices.body)
568
+ end
569
+ return self
570
+ end
571
+
572
+ #===マウスカーソルの位置とコマンドを照合する
573
+ #選択肢・選択カーソルを、マウスカーソルが当たっているコマンドに移動させる
574
+ #どのコマンドにも当たっていない場合は、すべてのコマンドは非選択状態になる
575
+ #_x_:: マウスカーソルの位置(x軸方向)
576
+ #_y_:: マウスカーソルの位置(y軸方向)
577
+ #返却値:: 自分自身を返す
578
+ def attach_cursor(x, y)
579
+ attach = @choices.attach(x, y)
580
+ if attach
581
+ if @select_cursor
582
+ @select_cursor.snap(@choices.body)
583
+ @select_cursor_position.call(@select_cursor, @choices.body)
584
+ end
585
+ else
586
+ @choices.non_select if @pre_attach
587
+ end
588
+ @pre_attach = attach
589
+ return self
590
+ end
591
+
592
+ #===マウスカーソルの位置にコマンドがあるかどうかを問い合わせる
593
+ #マウスカーソルがどれかのコマンドの上にあるときはtrue、どれにも当たっていないときはfalseを返す
594
+ #_x_:: マウスカーソルの位置(x軸方向)
595
+ #_y_:: マウスカーソルの位置(y軸方向)
596
+ #返却値:: マウスカーソルがどれかのコマンドにあるときはtrueを返す
597
+ def attach_any_command?(x, y)
598
+ return @choices.attach(x, y)
599
+ end
600
+
601
+ def update_layout_position #:nodoc:
602
+ @pos.move_to!(*@layout.pos)
603
+ end
604
+
605
+ #===入力待ち状態(ポーズ)に表示するカーソルの位置を設定する
606
+ #ポーズカーソルの位置を、パラメータ二つ(カーソル本体・テキストボックス)を引数に取るブロックで実装する
607
+ #位置は、テキストエリアをsnapしていると想定して実装する
608
+ #デフォルトは、テキストエリアの中下に置かれる(center!.bottom!)
609
+ # (例)テキストボックスの中下(テキストエリアの外) -> {|wc, tbox| wc.center!.outside_bottom! }
610
+ #   テキストボックスの右下(テキストエリアの中) -> {|wc, tbox| wc.right!.bottom! }
611
+ #   テキストの最後尾 -> {|wc, tbox| wc.left!{|b| tbox.locate.x }.top!{|b| tbox.locate.y} }
612
+ # (テキストエリアの左上から右下へ現在の描画開始位置(tbox.locateメソッドで示した値)の距離移動した箇所)
613
+ #ブロックを渡していなかったり、ブロックの引数が2個でなければエラーを返す
614
+ #返却値:: 自分自身を返す
615
+ def set_wait_cursor_position(&proc)
616
+ raise MiyakoProcError, "Can't find block!" unless proc
617
+ raise MiyakoProcError, "This method must have two parameters!" unless proc.arity == 2
618
+ @wait_cursor_position = proc
619
+ @wait_cursor_position.call(@wait_cursor, self) if @wait_cursor
620
+ return self
621
+ end
622
+
623
+ #===入力待ち状態(ポーズ)に表示するカーソルの位置をデフォルトに戻す
624
+ #デフォルトの位置は、テキストエリアの中下(center!.bottom!)に設定されている
625
+ #返却値:: 自分自身を返す
626
+ def reset_wait_cursor_position
627
+ @wait_cursor_position = @default_wait_cursor_position
628
+ @wait_cursor_position.call(@wait_cursor, self) if @wait_cursor
629
+ return self
630
+ end
631
+
632
+ #===コマンド選択時に表示するカーソルの位置を設定する
633
+ #カーソルの位置を、パラメータ二つ(カーソル本体・選択肢)を引数に取るブロックで実装する
634
+ #位置は、テキストエリアをsnapしていると想定して実装する
635
+ #デフォルトは、選択肢の左側に置かれる(outside_left!.middle!)
636
+ # (例)選択肢の右側 -> {|wc, choice| wc.outside_right!.middle! }
637
+ #   選択肢の真上 -> {|wc, choice| wc.centering! }
638
+ #ブロックを渡していなかったり、ブロックの引数が2個でなければエラーを返す
639
+ #返却値:: 自分自身を返す
640
+ def set_select_cursor_position(&proc)
641
+ raise MiyakoProcError, "Can't find block!" unless proc
642
+ raise MiyakoProcError, "This method must have two parameters!" unless proc.arity == 2
643
+ @select_cursor_position = proc
644
+ @select_cursor_position.call(@select_cursor, @choices.body) if (@select_cursor && @choices.body)
645
+ return self
646
+ end
647
+
648
+ #===入力待ち状態(ポーズ)に表示するカーソルの位置をデフォルトに戻す
649
+ #デフォルトの位置は、テキストエリアの中下(center!.bottom!)に設定されている
650
+ #返却値:: 自分自身を返す
651
+ def reset_select_cursor_position
652
+ @select_cursor_position = @default_select_cursor_position
653
+ @select_cursor_position.call(@select_cursor, @choices.body) if (@select_cursor && @choices.body)
654
+ return self
655
+ end
656
+
657
+ #===入力待ち状態(ポーズ)にする
658
+ #ポーズカーソルを表示する。pause?メソッドの結果がtrueになる
659
+ #ポーズカーソルの位置は、set_wait_cursor_positionで設定したブロックが評価されて決定される
660
+ #(デフォルトはテキストエリアの中下
661
+ #返却値:: 自分自身を返す
662
+ def pause
663
+ @waiting = true
664
+ return self unless @wait_cursor
665
+ @wait_cursor_position.call(@wait_cursor, self)
666
+ @on_pause.call
667
+ Fiber.yield if @fiber
668
+ return self
669
+ end
670
+
671
+ #===ポーズ時に行う処理を記述したブロックを登録する
672
+ #処理を行うブロックはオブジェクトとして渡す。
673
+ #ブロック引数の時は、そのブロックを処理している間のみ、そのオブジェクトを呼び出して処理させる
674
+ #_event_:: ポーズ時処理するブロック
675
+ #返却値:: 自分自身を返す
676
+ def on_pause=(event)
677
+ tpause = @on_pause
678
+ @on_pause = event
679
+ if block_given?
680
+ yield
681
+ @on_pause = tpause
682
+ end
683
+ return self
684
+ end
685
+
686
+ #===入力待ち状態を解除する
687
+ #同時に、ポーズカーソルを隠蔽する。pause?メソッドの結果がfalseになる
688
+ #返却値:: 自分自身を返す
689
+ def release
690
+ @waiting = false
691
+ @on_release.call
692
+ return self
693
+ end
694
+
695
+ #===ポーズ解除時に行う処理を記述したブロックを登録する
696
+ #処理を行うブロックはオブジェクトとして渡す。
697
+ #ブロック引数の時は、そのブロックを処理している間のみ、そのオブジェクトを呼び出して処理させる
698
+ #_event_:: ポーズ解除時処理するブロック
699
+ #返却値:: 自分自身を返す
700
+ def on_release=(event)
701
+ trelease = @on_release
702
+ @on_release = event
703
+ if block_given?
704
+ yield
705
+ @on_release = trelease
706
+ end
707
+ return self
708
+ end
709
+
710
+ #===入力待ち状態かを確認する
711
+ #返却値:: 入力待ち状態の時はtrueを返す
712
+ def pause?
713
+ return @waiting
714
+ end
715
+
716
+ #===コマンド選択中かどうかを確認する
717
+ #返却値:: 選択中の時はtrueを返す
718
+ def selecting?
719
+ return @selecting
720
+ end
721
+
722
+ #===選択結果を取得する
723
+ #返却値:: コマンドの選択結果(選択中のnilを返す)
724
+ def result
725
+ return @choices.result
726
+ end
727
+
728
+ #===テキストエリアに描画している文字を消去する
729
+ #透明色で消去したあと、描画開始位置を左上(0,0)に移動する
730
+ #返却値:: 自分自身を返す
731
+ def clear
732
+ @textarea.bitmap.fillRect(0, 0, @size[0], @size[1], [0, 0, 0, 0])
733
+ @locate = Point.new(0, 0)
734
+ @max_height = @font.line_height
735
+ Fiber.yield if @fiber
736
+ return self
737
+ end
738
+
739
+ #===縦方向のスペースを空ける
740
+ #現在描画可能な位置から、指定したピクセルで下方向に移動する
741
+ #但し、文字の大きさもピクセル数に含むことに注意すること
742
+ #_height_:: スペースを空けるピクセル数
743
+ #返却値:: 自分自身を返す
744
+ def cr(height = @max_height)
745
+ @locate.x = 0
746
+ @locate.y += height
747
+ @max_height = @font.line_height
748
+ Fiber.yield if @fiber
749
+ return self
750
+ end
751
+
752
+ #===横方向のスペースを空ける
753
+ #現在描画可能な位置から、指定したピクセルで右方向に移動する
754
+ #_length_:: スペースを空けるピクセル数
755
+ #返却値:: 自分自身を返す
756
+ def space(length)
757
+ @locate.x += length
758
+ Fiber.yield if @fiber
759
+ return self
760
+ end
761
+
762
+ #===情報を解放する
763
+ def dispose
764
+ @textarea.dispose
765
+ @textarea = nil
766
+ end
767
+
768
+ def_delegators(:@pos, :x, :y)
769
+ end
770
+ end