ruby-miyako 2.1.0

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