Ruby GTK3移行後のメインリポジトリ
Revisão | 0bfbaaa049fec0604a0bf9d7253a86cbc1472157 (tree) |
---|---|
Hora | 2014-06-04 23:42:49 |
Autor | Shyouzou Sugitani <shy@user...> |
Commiter | Shyouzou Sugitani |
add balloon.rb
@@ -0,0 +1,2007 @@ | ||
1 | +# -*- coding: utf-8 -*- | |
2 | +# | |
3 | +# Copyright (C) 2001, 2002 by Tamito KAJIYAMA | |
4 | +# Copyright (C) 2002, 2003 by MATSUMURA Namihiko <nie@counterghost.net> | |
5 | +# Copyright (C) 2002-2014 by Shyouzou Sugitani <shy@users.sourceforge.jp> | |
6 | +# Copyright (C) 2003 by Shun-ichi TAHARA <jado@flowernet.gr.jp> | |
7 | +# | |
8 | +# This program is free software; you can redistribute it and/or modify it | |
9 | +# under the terms of the GNU General Public License (version 2) as | |
10 | +# published by the Free Software Foundation. It is distributed in the | |
11 | +# hope that it will be useful, but WITHOUT ANY WARRANTY; without even the | |
12 | +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | |
13 | +# PURPOSE. See the GNU General Public License for more details. | |
14 | +# | |
15 | + | |
16 | +require "gtk3" | |
17 | + | |
18 | +require "ninix/pix" | |
19 | + | |
20 | + | |
21 | +module Balloon | |
22 | + | |
23 | + class Balloon | |
24 | + | |
25 | + def initialize | |
26 | + @parent = nil | |
27 | + @synchronized = [] | |
28 | + @user_interaction = false | |
29 | + @window = [] | |
30 | + # create communicatebox | |
31 | + @communicatebox = CommunicateBox.new() | |
32 | + @communicatebox.set_responsible(self) | |
33 | + # create teachbox | |
34 | + @teachbox = TeachBox.new() | |
35 | + @teachbox.set_responsible(self) | |
36 | + # create inputbox | |
37 | + @inputbox = InputBox.new() | |
38 | + @inputbox.set_responsible(self) | |
39 | + # create passwordinputbox | |
40 | + @passwordinputbox = PasswordInputBox.new() | |
41 | + @passwordinputbox.set_responsible(self) | |
42 | + end | |
43 | + | |
44 | + def set_responsible(parent) | |
45 | + @parent = parent | |
46 | + end | |
47 | + | |
48 | + def handle_request(event_type, event, *arglist, **argdict) | |
49 | + #assert event_type in ['GET', 'NOTIFY'] | |
50 | + handlers = { | |
51 | + 'reset_user_interaction' => 'reset_user_interaction', | |
52 | + } | |
53 | +# handler = handlers.get(event) | |
54 | +# if handler == nil | |
55 | + if !handlers.include?(event) | |
56 | + result = @parent.handle_request( | |
57 | + event_type, event, *arglist, **argdict) | |
58 | + else | |
59 | + result = handler(*arglist, **argdict) | |
60 | + end | |
61 | + if event_type == 'GET' | |
62 | + return result | |
63 | + end | |
64 | + end | |
65 | + | |
66 | + def reset_user_interaction | |
67 | + @user_interaction = false | |
68 | + end | |
69 | + | |
70 | + def get_text_count(side) | |
71 | + if @window.length > side | |
72 | + return @window[side].get_text_count() | |
73 | + else | |
74 | + return 0 | |
75 | + end | |
76 | + end | |
77 | + | |
78 | + def get_window(side) | |
79 | + if @window.length > side | |
80 | + return @window[side].window ## FIXME | |
81 | + else | |
82 | + return nil | |
83 | + end | |
84 | + end | |
85 | + | |
86 | + def reset_text_count(side) | |
87 | + if @window.length > side | |
88 | + @window[side].reset_text_count() | |
89 | + end | |
90 | + end | |
91 | + | |
92 | + def reset_balloon | |
93 | + for balloon_window in @window | |
94 | + balloon_window.reset_balloon() | |
95 | + end | |
96 | + end | |
97 | + | |
98 | + def create_gtk_window(title) | |
99 | + window = Pix::TransparentWindow.new() | |
100 | + window.set_title(title) | |
101 | + window.set_skip_pager_hint(false) | |
102 | + window.set_skip_taskbar_hint(true) | |
103 | + window.signal_connect('delete_event') do |w, e| | |
104 | + delete(w, e) | |
105 | + end | |
106 | + window.realize() | |
107 | + return window | |
108 | + end | |
109 | + | |
110 | + def identify_window(win) | |
111 | + for balloon_window in @window | |
112 | + if win == balloon_window.window.window | |
113 | + return true | |
114 | + end | |
115 | + end | |
116 | + return false | |
117 | + end | |
118 | + | |
119 | + def delete(window, event) | |
120 | + return true | |
121 | + end | |
122 | + | |
123 | + def finalize | |
124 | + for balloon_window in @window | |
125 | + balloon_window.destroy() | |
126 | + end | |
127 | + @window = [] | |
128 | + @communicatebox.destroy() | |
129 | + @teachbox.destroy() | |
130 | + @inputbox.destroy() | |
131 | + @passwordinputbox.destroy() | |
132 | + end | |
133 | + | |
134 | + def new_(desc, balloon) | |
135 | + @desc = desc | |
136 | + @directory = balloon['balloon_dir'][0] | |
137 | + balloon0 = {} | |
138 | + balloon1 = {} | |
139 | + communicate0 = nil | |
140 | + communicate1 = nil | |
141 | + communicate2 = nil | |
142 | + communicate3 = nil | |
143 | + for key in balloon.keys | |
144 | + value = balloon[key] | |
145 | +# for key, value in balloon.items() | |
146 | + if ['arrow0', 'arrow1'].include?(key) | |
147 | + balloon0[key] = value | |
148 | + balloon1[key] = value | |
149 | + elsif key == 'sstp' | |
150 | + balloon0[key] = value # sstp marker | |
151 | + elsif key.start_with?('s') | |
152 | + balloon0[key] = value # Sakura | |
153 | + elsif key.start_with?('k') | |
154 | + balloon1[key] = value # Unyuu | |
155 | + elsif key == 'c0' | |
156 | + communicate0 = value # send box | |
157 | + elsif key == 'c1' | |
158 | + communicate1 = value # communicate box | |
159 | + elsif key == 'c2' | |
160 | + communicate2 = value # teach box | |
161 | + elsif key == 'c3' | |
162 | + communicate3 = value # input box | |
163 | + end | |
164 | + end | |
165 | + @balloon0 = balloon0 | |
166 | + @balloon1 = balloon1 | |
167 | + # create balloon windows | |
168 | + for balloon_window in @window | |
169 | + balloon_window.destroy() | |
170 | + end | |
171 | + @window = [] | |
172 | + add_window(0) | |
173 | + add_window(1) | |
174 | + # configure communicatebox | |
175 | + @communicatebox.new_(desc, communicate1) | |
176 | + # configure teachbox | |
177 | + @teachbox.new_(desc, communicate2) | |
178 | + # configure inputbox | |
179 | + @inputbox.new_(desc, communicate3) | |
180 | + # configure passwordinputbox | |
181 | + @passwordinputbox.new_(desc, communicate3) | |
182 | + end | |
183 | + | |
184 | + def add_window(side) | |
185 | +# assert @window.length == side | |
186 | + if side == 0 | |
187 | + name = 'balloon.sakura' | |
188 | + id_format = 's' | |
189 | + balloon = @balloon0 | |
190 | + elsif side == 1 | |
191 | + name = 'balloon.kero' | |
192 | + id_format = 'k' | |
193 | + balloon = @balloon1 | |
194 | + else | |
195 | + name = 'balloon.char' + side.to_s | |
196 | + id_format = 'k' | |
197 | + balloon = @balloon1 | |
198 | + end | |
199 | + gtk_window = create_gtk_window(name) | |
200 | + balloon_window = BalloonWindow.new( | |
201 | + gtk_window, side, @desc, balloon, | |
202 | + id_format) | |
203 | + balloon_window.set_responsible(self) | |
204 | + @window << balloon_window | |
205 | + end | |
206 | + | |
207 | + def reset_fonts | |
208 | + for window in @window | |
209 | + window.reset_fonts() | |
210 | + end | |
211 | + end | |
212 | + | |
213 | + def get_balloon_directory | |
214 | + return @directory | |
215 | + end | |
216 | + | |
217 | + def get_balloon_size(side) | |
218 | + if @window.length > side | |
219 | + return @window[side].get_balloon_size() | |
220 | + else | |
221 | + return [0, 0] | |
222 | + end | |
223 | + end | |
224 | + | |
225 | + def get_balloon_windowposition(side) | |
226 | + if @window.length > side | |
227 | + return @window[side].get_balloon_windowposition() | |
228 | + else | |
229 | + return [0, 0] | |
230 | + end | |
231 | + end | |
232 | + | |
233 | + def set_balloon_default | |
234 | + default_id = @parent.handle_request('GET', 'get_balloon_default_id') | |
235 | + begin | |
236 | + default_id = default_id.to_i | |
237 | + rescue # except: | |
238 | + default_id = 0 | |
239 | + end | |
240 | + for side in range(@window.length) | |
241 | + @window[side].set_balloon(default_id) | |
242 | + end | |
243 | + end | |
244 | + | |
245 | + def set_balloon(side, num) | |
246 | + if @window.length > side | |
247 | + @window[side].set_balloon(num) | |
248 | + end | |
249 | + end | |
250 | + | |
251 | + def set_position(side, base_x, base_y) | |
252 | + if @window.length > side | |
253 | + @window[side].set_position(base_x, base_y) | |
254 | + end | |
255 | + end | |
256 | + | |
257 | + def get_position(side) | |
258 | + if @window.length > side | |
259 | + return @window[side].get_position() | |
260 | + else | |
261 | + return [0, 0] | |
262 | + end | |
263 | + end | |
264 | + | |
265 | + def set_autoscroll(flag) | |
266 | + for side in range(@window.length) | |
267 | + @window[side].set_autoscroll(flag) | |
268 | + end | |
269 | + end | |
270 | + | |
271 | + def is_shown(side) | |
272 | + if @window.length <= side | |
273 | + return 0 | |
274 | + else | |
275 | + return @window[side].is_shown() | |
276 | + end | |
277 | + end | |
278 | + | |
279 | + def show(side) | |
280 | + if @window.length > side | |
281 | + @window[side].show() | |
282 | + end | |
283 | + end | |
284 | + | |
285 | + def hide_all | |
286 | + for side in range(@window.length) | |
287 | + @window[side].hide() | |
288 | + end | |
289 | + end | |
290 | + | |
291 | + def hide(side) | |
292 | + if @window.length > side | |
293 | + @window[side].hide() | |
294 | + end | |
295 | + end | |
296 | + | |
297 | + def raise_all | |
298 | + for side in range(@window.length) | |
299 | + @window[side].raise_() | |
300 | + end | |
301 | + end | |
302 | + | |
303 | + def raise_(side) | |
304 | + if @window.length > side | |
305 | + @window[side].raise_() | |
306 | + end | |
307 | + end | |
308 | + | |
309 | + def lower_all | |
310 | + for side in range(@window.length) | |
311 | + @window[side].lower() | |
312 | + end | |
313 | + end | |
314 | + | |
315 | + def lower(side) | |
316 | + if @window.length > side | |
317 | + @window[side].lower() | |
318 | + end | |
319 | + end | |
320 | + | |
321 | + def synchronize(list) | |
322 | + @synchronized = list | |
323 | + end | |
324 | + | |
325 | + def clear_text_all | |
326 | + for side in range(@window.length) | |
327 | + clear_text(side) | |
328 | + end | |
329 | + end | |
330 | + | |
331 | + def clear_text(side) | |
332 | + if not @synchronized.empty? | |
333 | + for side in @synchronized | |
334 | + if @window.length > side | |
335 | + @window[side].clear_text() | |
336 | + end | |
337 | + end | |
338 | + else | |
339 | + if @window.length > side | |
340 | + @window[side].clear_text() | |
341 | + end | |
342 | + end | |
343 | + end | |
344 | + | |
345 | + def append_text(side, text) | |
346 | + if not @synchronized.empty? | |
347 | + for side in @synchronized | |
348 | + if @window.length > side | |
349 | + @window[side].append_text(text) | |
350 | + end | |
351 | + end | |
352 | + else | |
353 | + if @window.length > side | |
354 | + @window[side].append_text(text) | |
355 | + end | |
356 | + end | |
357 | + end | |
358 | + | |
359 | + def append_sstp_marker(side) | |
360 | + if @window.length > side | |
361 | + @window[side].append_sstp_marker() | |
362 | + end | |
363 | + end | |
364 | + | |
365 | + def append_link_in(side, label) | |
366 | + if not @synchronized.empty? | |
367 | + for side in @synchronized | |
368 | + if @window.length > side | |
369 | + @window[side].append_link_in(label) | |
370 | + end | |
371 | + end | |
372 | + else | |
373 | + if @window.length > side | |
374 | + @window[side].append_link_in(label) | |
375 | + end | |
376 | + end | |
377 | + end | |
378 | + | |
379 | + def append_link_out(side, label, value) | |
380 | + if not @synchronized.empty? | |
381 | + for side in @synchronized | |
382 | + if @window.length > side | |
383 | + @window[side].append_link_out(label, value) | |
384 | + end | |
385 | + end | |
386 | + else | |
387 | + if @window.length > side | |
388 | + @window[side].append_link_out(label, value) | |
389 | + end | |
390 | + end | |
391 | + end | |
392 | + | |
393 | + def append_link(side, label, value, newline_required=0) | |
394 | + if not @synchronized.empty? | |
395 | + for side in @synchronized | |
396 | + if @window.length > side | |
397 | + @window[side].append_link_in(label) | |
398 | + @window[side].append_text(value) | |
399 | + @window[side].append_link_out(label, value) | |
400 | + if newline_required | |
401 | + @window[side].set_newline() | |
402 | + end | |
403 | + end | |
404 | + end | |
405 | + else | |
406 | + if @window.length > side | |
407 | + @window[side].append_link_in(label) | |
408 | + @window[side].append_text(value) | |
409 | + @window[side].append_link_out(label, value) | |
410 | + if newline_required | |
411 | + @window[side].set_newline() | |
412 | + end | |
413 | + end | |
414 | + end | |
415 | + end | |
416 | + | |
417 | + def append_meta(side, tag) | |
418 | + if not @synchronized.empty? | |
419 | + for side in @synchronized | |
420 | + if @window.length > side | |
421 | + @window[side].append_meta(tag) | |
422 | + end | |
423 | + end | |
424 | + else | |
425 | + if @window.length > side | |
426 | + @window[side].append_meta(tag) | |
427 | + end | |
428 | + end | |
429 | + end | |
430 | + | |
431 | + def append_image(side, path, x, y) | |
432 | + if @window.length > side | |
433 | + @window[side].append_image(path, x, y) | |
434 | + end | |
435 | + end | |
436 | + | |
437 | + def show_sstp_message(message, sender) | |
438 | + @window[0].show_sstp_message(message, sender) | |
439 | + end | |
440 | + | |
441 | + def hide_sstp_message | |
442 | + @window[0].hide_sstp_message() | |
443 | + end | |
444 | + | |
445 | + def open_communicatebox | |
446 | + if not @user_interaction | |
447 | + @user_interaction = true | |
448 | + @communicatebox.show() | |
449 | + end | |
450 | + end | |
451 | + | |
452 | + def open_teachbox | |
453 | + if not @user_interaction | |
454 | + @user_interaction = true | |
455 | + @parent.handle_request('NOTIFY', 'notify_event', 'OnTeachStart') | |
456 | + @teachbox.show() | |
457 | + end | |
458 | + end | |
459 | + | |
460 | + def open_inputbox(symbol, limittime=-1, default=nil) | |
461 | + if not @user_interaction | |
462 | + @user_interaction = true | |
463 | + @inputbox.set_symbol(symbol) | |
464 | + @inputbox.set_limittime(limittime) | |
465 | + @inputbox.show(default) | |
466 | + end | |
467 | + end | |
468 | + | |
469 | + def open_passwordinputbox(symbol, limittime=-1, default=nil) | |
470 | + if not @user_interaction | |
471 | + @user_interaction = true | |
472 | + @passwordinputbox.set_symbol(symbol) | |
473 | + @passwordinputbox.set_limittime(limittime) | |
474 | + @passwordinputbox.show(default) | |
475 | + end | |
476 | + end | |
477 | + | |
478 | + def close_inputbox(symbol) | |
479 | + if not @user_interaction | |
480 | + return | |
481 | + end | |
482 | + @inputbox.close(symbol) | |
483 | + @passwordinputbox.close(symbol) | |
484 | + end | |
485 | + end | |
486 | + | |
487 | + | |
488 | + class BalloonWindow | |
489 | + | |
490 | + def initialize(window, side, desc, balloon, id_format) | |
491 | + @window = window | |
492 | + @side = side | |
493 | + @parent = nil | |
494 | + @desc = desc | |
495 | + @balloon = balloon | |
496 | + @balloon_id = nil | |
497 | + @id_format = id_format | |
498 | + @num = 0 | |
499 | + @__shown = false | |
500 | + @sstp_marker = [] | |
501 | + @sstp_region = nil | |
502 | + @sstp_message = nil | |
503 | + @images = [] | |
504 | + @width = 0 | |
505 | + @height = 0 | |
506 | + @__font_name = '' | |
507 | + @text_count = 0 | |
508 | + @balloon_surface = nil | |
509 | + @autoscroll = true | |
510 | + @dragged = false | |
511 | + @x_root = nil | |
512 | + @y_root = nil | |
513 | + @x_fractions = 0 | |
514 | + @y_fractions = 0 | |
515 | + @darea = @window.darea # get_child() | |
516 | + @darea.set_events(Gdk::Event::EXPOSURE_MASK| | |
517 | + Gdk::Event::BUTTON_PRESS_MASK| | |
518 | + Gdk::Event::BUTTON_RELEASE_MASK| | |
519 | + Gdk::Event::POINTER_MOTION_MASK| | |
520 | + Gdk::Event::POINTER_MOTION_HINT_MASK| | |
521 | + Gdk::Event::SCROLL_MASK) | |
522 | + @darea.signal_connect('draw') do |w, e| | |
523 | + redraw(w, e) | |
524 | + end | |
525 | + @darea.signal_connect('button_press_event') do |w, e| | |
526 | + button_press(w, e) | |
527 | + end | |
528 | + @darea.signal_connect('button_release_event') do |w, e| | |
529 | + button_release(w, e) | |
530 | + end | |
531 | + @darea.signal_connect('motion_notify_event') do |w, e| | |
532 | + motion_notify(w, e) | |
533 | + end | |
534 | + @darea.signal_connect('scroll_event') do |w, e| | |
535 | + scroll(w, e) | |
536 | + end | |
537 | + @layout = Pango::Layout.new(@darea.pango_context) | |
538 | + @sstp_layout = Pango::Layout.new(@darea.pango_context()) | |
539 | + mask_r = desc.get('maskcolor.r', 128).to_i | |
540 | + mask_g = desc.get('maskcolor.g', 128).to_i | |
541 | + mask_b = desc.get('maskcolor.b', 128).to_i | |
542 | + @cursor_color = [mask_r / 255.0, mask_g / 255.0, mask_b / 255.0] | |
543 | + text_r = desc.get(['font.color.r', 'fontcolor.r'], 0).to_i | |
544 | + text_g = desc.get(['font.color.g', 'fontcolor.g'], 0).to_i | |
545 | + text_b = desc.get(['font.color.b', 'fontcolor.b'], 0).to_i | |
546 | + @text_normal_color = [text_r / 255.0, text_g / 255.0, text_b / 255.0] | |
547 | + if desc.get('maskmethod').to_i == 1 | |
548 | + text_r = 255 - text_r | |
549 | + text_g = 255 - text_g | |
550 | + text_b = 255 - text_b | |
551 | + end | |
552 | + @text_active_color = [text_r / 255.0, text_g / 255.0, text_b / 255.0] | |
553 | + sstp_r = desc.get('sstpmessage.font.color.r', text_r).to_i | |
554 | + sstp_g = desc.get('sstpmessage.font.color.g', text_g).to_i | |
555 | + sstp_b = desc.get('sstpmessage.font.color.b', text_b).to_i | |
556 | + @sstp_message_color = [sstp_r / 255.0, sstp_g / 255.0, sstp_b / 255.0] | |
557 | + # initialize | |
558 | + @__direction = [side, 1].min ## kluge: multi character | |
559 | + @position = [0, 0] | |
560 | + reset_fonts() | |
561 | + clear_text() | |
562 | + end | |
563 | + | |
564 | + def set_responsible(parent) | |
565 | + @parent = parent | |
566 | + end | |
567 | + | |
568 | +# @property | |
569 | + def scale | |
570 | + scaling = @parent.handle_request('GET', 'get_preference', 'balloon_scaling') | |
571 | + scale = @parent.handle_request('GET', 'get_preference', 'surface_scale') | |
572 | + if scaling | |
573 | + return scale | |
574 | + else | |
575 | + return 100 # [%] | |
576 | + end | |
577 | + end | |
578 | + | |
579 | +# @property | |
580 | + def direction | |
581 | + return @__direction | |
582 | + end | |
583 | + | |
584 | +# @direction.setter | |
585 | + def direction(direction) | |
586 | + if @__direction != direction | |
587 | + @__direction = direction # 0: left, 1: right | |
588 | + reset_balloon() | |
589 | + end | |
590 | + end | |
591 | + | |
592 | + def get_balloon_windowposition | |
593 | + x = __get_with_scaling('windowposition.x', 0).to_i | |
594 | + y = __get_with_scaling('windowposition.y', 0).to_i | |
595 | + return x, y | |
596 | + end | |
597 | + | |
598 | + def get_image_surface(balloon_id) | |
599 | + if not @balloon.include?(balloon_id) | |
600 | + return nil | |
601 | + end | |
602 | + begin | |
603 | + path, config = @balloon[balloon_id] | |
604 | + use_pna = @parent.handle_request('GET', 'get_preference', 'use_pna') | |
605 | + surface = Pix.create_surface_from_file(path, use_pna=use_pna) | |
606 | + rescue # except: | |
607 | + return nil | |
608 | + end | |
609 | + return surface | |
610 | + end | |
611 | + | |
612 | + def reset_fonts | |
613 | + if @parent != nil | |
614 | + font_name = @parent.handle_request('GET', 'get_preference', 'balloon_fonts') | |
615 | + else | |
616 | + font_name = nil | |
617 | + end | |
618 | + if @__font_name == font_name | |
619 | + return | |
620 | + end | |
621 | + @font_desc = Pango::FontDescription.new(font_name) | |
622 | + pango_size = @font_desc.size | |
623 | + if pango_size == 0 | |
624 | + default_size = 12 # for Windows environment | |
625 | + size = @desc.get(['font.height', 'font.size'], default_size).to_i | |
626 | + pango_size = size * 3 / 4 # convert from Windows to GTK+ | |
627 | + pango_size *= Pango::SCALE | |
628 | + end | |
629 | + @font_desc.set_size(pango_size) | |
630 | + @__font_name = font_name | |
631 | + @layout.set_font_description(@font_desc) | |
632 | + @layout.set_wrap(Pango::WRAP_CHAR) # XXX | |
633 | + # font for sstp message | |
634 | + if @side == 0 | |
635 | + @sstp_font_desc = Pango::FontDescription.new(font_name) | |
636 | + pango_size = @sstp_font_desc.size | |
637 | + if pango_size == 0 | |
638 | + default_size = 10 # for Windows environment | |
639 | + size = @desc.get('sstpmessage.font.height', default_size).to_i | |
640 | + pango_size = size * 3 / 4 # convert from Windows to GTK+ | |
641 | + pango_size *= Pango::SCALE | |
642 | + end | |
643 | + @sstp_font_desc.set_size(pango_size) | |
644 | + @sstp_layout.set_font_description(@sstp_font_desc) | |
645 | + @sstp_layout.set_wrap(Pango::WRAP_CHAR) | |
646 | + end | |
647 | + if @balloon_id != nil | |
648 | + reset_message_regions() | |
649 | + if @__shown | |
650 | + @darea.queue_draw() | |
651 | + end | |
652 | + end | |
653 | + end | |
654 | + | |
655 | + def reset_sstp_marker | |
656 | + if @side == 0 | |
657 | +# assert @balloon_surface != nil | |
658 | + w = @balloon_surface.width | |
659 | + h = @balloon_surface.height | |
660 | + # sstp marker position | |
661 | + @sstp = [] | |
662 | + x = config_adjust('sstpmarker.x', w, 30) | |
663 | + y = config_adjust('sstpmarker.y', h, -20) | |
664 | + @sstp << [x, y] # sstp marker | |
665 | + x = config_adjust('sstpmessage.x', w, 50) | |
666 | + y = config_adjust('sstpmessage.y', h, -20) | |
667 | + @sstp << [x, y] # sstp message | |
668 | + end | |
669 | + # sstp marker surface (not only for @side == 0) | |
670 | + @sstp_surface = get_image_surface('sstp') | |
671 | + end | |
672 | + | |
673 | + def reset_arrow | |
674 | + # arrow positions | |
675 | + @arrow = [] | |
676 | +# assert @balloon_surface != nil | |
677 | + w = @balloon_surface.width | |
678 | + h = @balloon_surface.height | |
679 | + x = config_adjust('arrow0.x', w, -10) | |
680 | + y = config_adjust('arrow0.y', h, 10) | |
681 | + @arrow << [x, y] | |
682 | + x = config_adjust('arrow1.x', w, -10) | |
683 | + y = config_adjust('arrow1.y', h, -20) | |
684 | + @arrow << [x, y] | |
685 | + # arrow surfaces and sizes | |
686 | + @arrow0_surface = get_image_surface('arrow0') | |
687 | + @arrow1_surface = get_image_surface('arrow1') | |
688 | + end | |
689 | + | |
690 | + def reset_message_regions | |
691 | + w, h = @layout.pixel_size | |
692 | + @font_height = h | |
693 | + @line_space = 1 | |
694 | + @layout.set_spacing(@line_space) | |
695 | + # font metrics | |
696 | + origin_x = __get('origin.x', | |
697 | + __get('zeropoint.x', | |
698 | + __get('validrect.left', 14).to_i).to_i).to_i | |
699 | + origin_y = __get('origin.y', | |
700 | + __get('zeropoint.y', | |
701 | + __get('validrect.top', 14).to_i).to_i).to_i | |
702 | + wpx = __get('wordwrappoint.x', | |
703 | + __get('validrect.right', -14).to_i).to_i | |
704 | + if wpx > 0 | |
705 | + line_width = wpx - origin_x | |
706 | + elsif wpx < 0 | |
707 | + line_width = @width - origin_x + wpx | |
708 | + else | |
709 | + line_width = @width - origin_x * 2 | |
710 | + end | |
711 | + wpy = __get('validrect.bottom', -14).to_i | |
712 | + if wpy > 0 | |
713 | + text_height = [wpy, @height].min - origin_y | |
714 | + elsif wpy < 0 | |
715 | + text_height = @height - origin_y + wpy | |
716 | + else | |
717 | + text_height = @height - origin_y * 2 | |
718 | + end | |
719 | + line_height = @font_height + @line_space | |
720 | + @lines = (text_height / line_height).to_i | |
721 | + @line_regions = [] | |
722 | + y = origin_y | |
723 | + for _ in 0..@lines | |
724 | + @line_regions << [origin_x, y, line_width, line_height] | |
725 | + y = y + line_height | |
726 | + end | |
727 | + @line_width = line_width | |
728 | + # sstp message region | |
729 | + if @side == 0 | |
730 | + w, h = @sstp_layout.pixel_size | |
731 | + x, y = @sstp[1] | |
732 | + w = line_width + origin_x - x | |
733 | + @sstp_region = [x, y, w, h] | |
734 | + end | |
735 | + end | |
736 | + | |
737 | + def update_line_regions(offset, new_y) | |
738 | + origin_y = __get('origin.y', | |
739 | + __get('zeropoint.y', | |
740 | + __get('validrect.top', 14).to_i).to_i).to_i | |
741 | + wpy = __get('validrect.bottom', -14).to_i | |
742 | + if wpy > 0 | |
743 | + text_height = [wpy, @height].min - origin_y | |
744 | + elsif wpy < 0 | |
745 | + text_height = @height - origin_y + wpy | |
746 | + else | |
747 | + text_height = @height - origin_y * 2 | |
748 | + end | |
749 | + line_height = @font_height + @line_space | |
750 | + origin_x, y, line_width, line_height = @line_regions[offset] | |
751 | + @lines = offset + ((text_height - new_y) / line_height).to_i | |
752 | + y = new_y | |
753 | + for i in offset..(@line_regions.length - 1) | |
754 | + @line_regions[i] = [origin_x, y, line_width, line_height] | |
755 | + y += line_height | |
756 | + end | |
757 | + for i in @line_regions.length..@lines | |
758 | + @line_regions << [origin_x, y, line_width, line_height] | |
759 | + y += line_height | |
760 | + end | |
761 | + end | |
762 | + | |
763 | + def get_balloon_size(scaling=true) | |
764 | + w = @width | |
765 | + h = @height | |
766 | +# scale = @scale | |
767 | + if scaling | |
768 | + w = (w * scale / 100.0).to_i | |
769 | + h = (h * scale / 100.0).to_i | |
770 | + end | |
771 | + return w, h | |
772 | + end | |
773 | + | |
774 | + def reset_balloon | |
775 | + set_balloon(@num) | |
776 | + end | |
777 | + | |
778 | + def set_balloon(num) | |
779 | + @num = num | |
780 | + balloon_id = @id_format + (num * 2 + @__direction).to_i.to_s | |
781 | + @balloon_surface = get_image_surface(balloon_id) | |
782 | + if @balloon_surface == nil | |
783 | + balloon_id = @id_format + (0 + @__direction).to_i.to_s | |
784 | + @balloon_surface = get_image_surface(balloon_id) | |
785 | + end | |
786 | +# assert @balloon_surface != nil | |
787 | + @balloon_id = balloon_id | |
788 | + # change surface and window position | |
789 | + x, y = @position | |
790 | + @width = @balloon_surface.width | |
791 | + @height = @balloon_surface.height | |
792 | +# scale = @scale | |
793 | + w = (@width * scale / 100.0).to_i | |
794 | + h = (@height * scale / 100.0).to_i | |
795 | + @window.update_size(w, h) | |
796 | + reset_arrow() | |
797 | + reset_sstp_marker() | |
798 | + reset_message_regions() | |
799 | + @parent.handle_request('NOTIFY', 'position_balloons') | |
800 | + if @__shown | |
801 | + @darea.queue_draw() | |
802 | + end | |
803 | + end | |
804 | + | |
805 | + def set_autoscroll(flag) | |
806 | + @autoscroll = bool(flag) | |
807 | + end | |
808 | + | |
809 | + def config_adjust(name, base, default_value) | |
810 | + path, config = @balloon[@balloon_id] | |
811 | + value = config.get(name).to_i | |
812 | + if value == nil | |
813 | + value = @desc.get(name).to_i | |
814 | + end | |
815 | + if value == nil | |
816 | + value = default_value | |
817 | + end | |
818 | + if value < 0 | |
819 | + value = base + value | |
820 | + end | |
821 | + return value.to_i | |
822 | + end | |
823 | + | |
824 | + def __get_with_type(name, conv, default_value) | |
825 | + path, config = @balloon[@balloon_id] | |
826 | + value = config.get_with_type(name, conv) | |
827 | + if value == nil | |
828 | + value = @desc.get_with_type(name, conv) | |
829 | + if value == nil | |
830 | + value = default_value | |
831 | + end | |
832 | + end | |
833 | + return conv(value) | |
834 | + end | |
835 | + | |
836 | + def __get(name, default_value) | |
837 | + path, config = @balloon[@balloon_id] | |
838 | + value = config.get(name) | |
839 | + if value == nil | |
840 | + value = @desc.get(name) | |
841 | + if value == nil | |
842 | + value = default_value | |
843 | + end | |
844 | + end | |
845 | + return value | |
846 | + end | |
847 | + | |
848 | +# def __get_with_scaling(name, conv, default_value) | |
849 | +# path, config = @balloon[@balloon_id] | |
850 | +# value = config.get_with_type(name, conv) | |
851 | +# if value == nil | |
852 | +# value = @desc.get_with_type(name, conv) | |
853 | +# if value == nil | |
854 | +# value = default_value | |
855 | +# end | |
856 | +# end | |
857 | +# return conv(value * scale / 100) | |
858 | +# end | |
859 | + | |
860 | + def __get_with_scaling(name, default_value) | |
861 | + path, config = @balloon[@balloon_id] | |
862 | + value = config.get(name) | |
863 | + if value == nil | |
864 | + value = @desc.get(name) | |
865 | + if value == nil | |
866 | + value = default_value | |
867 | + end | |
868 | + end | |
869 | + return (value.to_f * scale / 100) | |
870 | + end | |
871 | + | |
872 | + def __move | |
873 | + x, y = get_position() | |
874 | + @window.move(x, y) | |
875 | + end | |
876 | + | |
877 | + def set_position(base_x, base_y) | |
878 | + if @balloon_id == nil ## FIXME | |
879 | + return | |
880 | + end | |
881 | + px, py = get_balloon_windowposition() | |
882 | + w, h = get_balloon_size() | |
883 | + if @__direction == 0 | |
884 | + x = base_x + px - w | |
885 | + else | |
886 | + x = base_x + px | |
887 | + end | |
888 | + y = base_y + py | |
889 | + left, top, scrn_w, scrn_h = Pix.get_workarea() | |
890 | + if y + h > scrn_h # XXX | |
891 | + y = scrn_h - h | |
892 | + end | |
893 | + if y < top # XXX | |
894 | + y = top | |
895 | + end | |
896 | + @position = [x, y] | |
897 | + __move() | |
898 | + end | |
899 | + | |
900 | + def get_position | |
901 | + return @position | |
902 | + end | |
903 | + | |
904 | + def destroy(finalize=0) | |
905 | + @window.destroy() | |
906 | + end | |
907 | + | |
908 | + def is_shown | |
909 | + if @__shown | |
910 | + return 1 | |
911 | + else | |
912 | + return 0 | |
913 | + end | |
914 | + end | |
915 | + | |
916 | + def show | |
917 | + if @parent.handle_request('GET', 'lock_repaint') | |
918 | + return | |
919 | + end | |
920 | + if @__shown | |
921 | + return | |
922 | + end | |
923 | + @__shown = true | |
924 | + # make sure window is in its position (call before showing the window) | |
925 | + __move() | |
926 | + @window.show() | |
927 | + # make sure window is in its position (call after showing the window) | |
928 | + __move() | |
929 | + raise_() | |
930 | + end | |
931 | + | |
932 | + def hide | |
933 | + if not @__shown | |
934 | + return | |
935 | + end | |
936 | + @window.hide() | |
937 | + @__shown = false | |
938 | + @images = [] | |
939 | + end | |
940 | + | |
941 | + def raise_ | |
942 | + if @__shown | |
943 | + @window.window.raise | |
944 | + end | |
945 | + end | |
946 | + | |
947 | + def lower | |
948 | + if @__shown | |
949 | + @window.get_window().lower() | |
950 | + end | |
951 | + end | |
952 | + | |
953 | + def show_sstp_message(message, sender) | |
954 | + if @sstp_region == nil | |
955 | + show() | |
956 | + end | |
957 | + @sstp_message = message.to_s + " (" + sender.to_s + ")" | |
958 | + x, y, w, h = @sstp_region | |
959 | +# @sstp_layout.set_text(@sstp_message, -1) | |
960 | + @sstp_layout.set_text(@sstp_message) | |
961 | + message_width, message_height = @sstp_layout.pixel_size | |
962 | + if message_width > w | |
963 | + @sstp_message = '... ({0})'.format(sender) | |
964 | + i = 0 | |
965 | + while 1 | |
966 | + i += 1 | |
967 | + s = '{0}... ({1})'.format(message[0, i], sender) | |
968 | + @sstp_layout.set_text(s, -1) | |
969 | + message_width, message_height = \ | |
970 | + @sstp_layout.get_pixel_size() | |
971 | + if message_width > w | |
972 | + break | |
973 | + end | |
974 | + @sstp_message = s | |
975 | + end | |
976 | + end | |
977 | + @darea.queue_draw() | |
978 | + end | |
979 | + | |
980 | + def hide_sstp_message | |
981 | + @sstp_message = nil | |
982 | + @darea.queue_draw() | |
983 | + end | |
984 | + | |
985 | + def redraw_sstp_message(widget, cr) | |
986 | + if @sstp_message == nil | |
987 | + return | |
988 | + end | |
989 | + cr.save() | |
990 | + # draw sstp marker | |
991 | + if @sstp_surface != nil | |
992 | + x, y = @sstp[0] | |
993 | + cr.set_source(@sstp_surface, x, y) | |
994 | + cr.paint() | |
995 | + end | |
996 | + # draw sstp message | |
997 | + x, y, w, h = @sstp_region | |
998 | +# @sstp_layout.set_text(@sstp_message, -1) | |
999 | + @sstp_layout.set_text(@sstp_message) | |
1000 | + cr.set_source_rgba(*@sstp_message_color) | |
1001 | + cr.move_to(x, y) | |
1002 | + cr.show_pango_layout(@sstp_layout) | |
1003 | +# PangoCairo.update_layout(cr, @sstp_layout) | |
1004 | +# PangoCairo.show_layout(cr, @sstp_layout) | |
1005 | + cr.restore() | |
1006 | + end | |
1007 | + | |
1008 | + def redraw_arrow0(widget, cr) | |
1009 | + if @lineno <= 0 | |
1010 | + return | |
1011 | + end | |
1012 | + cr.save() | |
1013 | + x, y = @arrow[0] | |
1014 | + cr.set_source(@arrow0_surface, x, y) | |
1015 | + cr.paint() | |
1016 | + cr.restore() | |
1017 | + end | |
1018 | + | |
1019 | + def redraw_arrow1(widget, cr) | |
1020 | + if @lineno + @lines >= @text_buffer.length | |
1021 | + return | |
1022 | + end | |
1023 | + cr.save() | |
1024 | + x, y = @arrow[1] | |
1025 | + cr.set_source(@arrow1_surface, x, y) | |
1026 | + cr.paint() | |
1027 | + cr.restore() | |
1028 | + end | |
1029 | + | |
1030 | + def set_markup(index, text) | |
1031 | + tags_ = ['sup', 'sub', 's', 'u'] | |
1032 | + count_ = {} | |
1033 | + for tag_ in tags_ | |
1034 | + count_[tag_] = 0 | |
1035 | + end | |
1036 | + markup_list = [] | |
1037 | + for sl, sn, tag in @meta_buffer | |
1038 | + if sl == index | |
1039 | + markup_list << [sn, tag] | |
1040 | + end | |
1041 | + end | |
1042 | + if not markup_list | |
1043 | + return GLib.markup_escape_text(text) | |
1044 | + end | |
1045 | + markup_list.sort() | |
1046 | + markup_list.reverse() | |
1047 | + pn = text.length | |
1048 | + for sn, tag in markup_list | |
1049 | + text = [text[0, sn], tag, | |
1050 | + GLib.markup_escape_text(text[sn, pn]), text[pn, text.length]].join('') | |
1051 | + pn = sn | |
1052 | + if tag[1] == '/' | |
1053 | + tag_ = tag[2, tag.length - 1] | |
1054 | + assert tags_.include?(tag_) | |
1055 | + count_[tag_] -= 1 | |
1056 | + if count_[tag_] < 0 | |
1057 | + text = ['<', tag_, '>', text].join('') | |
1058 | + count_[tag_] += 1 | |
1059 | + end | |
1060 | + else | |
1061 | + tag_ = tag[1, tag.length - 1] | |
1062 | + assert tags_.include?(tag_) | |
1063 | + count_[tag_] += 1 | |
1064 | + if count_[tag_] > 0 | |
1065 | + text = [text, '</', tag_, '>'].join('') | |
1066 | + count_[tag_] -= 1 | |
1067 | + end | |
1068 | + end | |
1069 | + end | |
1070 | + return text | |
1071 | + end | |
1072 | + | |
1073 | + def redraw(widget, cr) | |
1074 | + if @parent.handle_request('GET', 'lock_repaint') | |
1075 | + return | |
1076 | + end | |
1077 | + if not @__shown | |
1078 | + return true | |
1079 | + end | |
1080 | +# assert @balloon_surface != nil | |
1081 | +# scale = @scale | |
1082 | + cr.scale(scale / 100.0, scale / 100.0) | |
1083 | + cr.set_source(@balloon_surface, 0, 0) | |
1084 | + cr.set_operator(Cairo::OPERATOR_SOURCE) | |
1085 | + cr.paint() | |
1086 | + cr.set_operator(Cairo::OPERATOR_OVER) # restore default | |
1087 | + # draw images | |
1088 | + for i in 0..(@images.length - 1) | |
1089 | + image_surface, (x, y) = @images[i] | |
1090 | + w = image_surface.get_width() | |
1091 | + h = image_surface.get_height() | |
1092 | + if x == 'centerx' | |
1093 | + bw, bh = get_balloon_size(scaling=false) | |
1094 | + x = (bw - w) / 2 | |
1095 | + else | |
1096 | + begin | |
1097 | + x = x.to_i | |
1098 | + rescue # except: | |
1099 | + next | |
1100 | + end | |
1101 | + end | |
1102 | + if y == 'centery' | |
1103 | + bw, bh = get_balloon_size(scaling=false) | |
1104 | + y = (bh - h) / 2 | |
1105 | + else | |
1106 | + begin | |
1107 | + y = y.to_i | |
1108 | + rescue # except: | |
1109 | + next | |
1110 | + end | |
1111 | + end | |
1112 | + cr.set_source_surface(image_surface, x, y) | |
1113 | + cr.paint() | |
1114 | + end | |
1115 | + # draw text | |
1116 | + i = @lineno | |
1117 | + j = @text_buffer.length | |
1118 | + line = 0 | |
1119 | + while line < @lines | |
1120 | + if i >= j | |
1121 | + break | |
1122 | + end | |
1123 | + x, y, w, h = @line_regions[line] | |
1124 | + if @text_buffer[i].end_with?('\n[half]') | |
1125 | + new_y = (y + (@font_height + @line_space) / 2).to_i | |
1126 | + markup = set_markup(i, @text_buffer[i][0, @text_buffer.length - 7]) | |
1127 | + else | |
1128 | + new_y = (y + @font_height + @line_space).to_i | |
1129 | + markup = set_markup(i, @text_buffer[i]) | |
1130 | + end | |
1131 | + update_line_regions(line + 1, new_y) | |
1132 | + @layout.set_markup(markup, -1) | |
1133 | + cr.set_source_rgba(*@text_normal_color) | |
1134 | + cr.move_to(x, y) | |
1135 | + cr.show_pango_layout(@layout) | |
1136 | +# PangoCairo.update_layout(cr, @layout) | |
1137 | +# PangoCairo.show_layout(cr, @layout) | |
1138 | + if @sstp_surface != nil | |
1139 | + for l, c in @sstp_marker | |
1140 | + if l == i | |
1141 | + mw = @sstp_surface.get_width() | |
1142 | + mh = @sstp_surface.get_height() | |
1143 | + @layout.set_text(@text_buffer[i][0, c], -1) | |
1144 | + text_w, text_h = @layout.get_pixel_size() | |
1145 | + mx = x + text_w | |
1146 | + my = y + (@font_height + @line_space) / 2 | |
1147 | + my = my - mh / 2 | |
1148 | + cr.set_source_surface(@sstp_surface, mx, my) | |
1149 | + cr.paint() | |
1150 | + end | |
1151 | + end | |
1152 | + end | |
1153 | + i += 1 | |
1154 | + line += 1 | |
1155 | + end | |
1156 | + if @side == 0 and @sstp_message | |
1157 | + redraw_sstp_message(widget, cr) | |
1158 | + end | |
1159 | + if @selection != nil | |
1160 | + update_link_region(widget, cr, @selection) | |
1161 | + end | |
1162 | + redraw_arrow0(widget, cr) | |
1163 | + redraw_arrow1(widget, cr) | |
1164 | + return false | |
1165 | + end | |
1166 | + | |
1167 | + def update_link_region(widget, cr, index) | |
1168 | + cr.save() | |
1169 | + sl = @link_buffer[index][0] | |
1170 | + el = @link_buffer[index][2] | |
1171 | + if @lineno <= sl <= @lineno + @lines | |
1172 | + sn = @link_buffer[index][1] | |
1173 | + en = @link_buffer[index][3] | |
1174 | + for n in range(sl, el + 1) | |
1175 | + if n - @lineno >= @line_regions.length | |
1176 | + break | |
1177 | + x, y, w, h = @line_regions[n - @lineno] | |
1178 | + if sl == el | |
1179 | + markup = set_markup(n, @text_buffer[n][0, sn]) | |
1180 | + @layout.set_markup(markup, -1) | |
1181 | + text_w, text_h = @layout.get_pixel_size() | |
1182 | + x += text_w | |
1183 | + markup = set_markup(n, @text_buffer[n][sn, en]) | |
1184 | + @layout.set_markup(markup, -1) | |
1185 | + text_w, text_h = @layout.get_pixel_size() | |
1186 | + w = text_w | |
1187 | + start = sn | |
1188 | + end_ = en | |
1189 | + elsif n == sl | |
1190 | + markup = set_markup(n, @text_buffer[n][0, sn]) | |
1191 | + @layout.set_markup(markup, -1) | |
1192 | + text_w, text_h = @layout.get_pixel_size() | |
1193 | + x += text_w | |
1194 | + markup = set_markup(n, @text_buffer[n][sn, @text_buffer.length]) | |
1195 | + @layout.set_markup(markup, -1) | |
1196 | + text_w, text_h = @layout.get_pixel_size() | |
1197 | + w = text_w | |
1198 | + start = sn | |
1199 | + end_ = @text_buffer[n].length | |
1200 | + elsif n == el | |
1201 | + markup = set_markup(n, @text_buffer[n][0, en]) | |
1202 | + @layout.set_markup(markup, -1) | |
1203 | + text_w, text_h = @layout.get_pixel_size() | |
1204 | + w = text_w | |
1205 | + start = 0 | |
1206 | + end_ = en | |
1207 | + else | |
1208 | + markup = set_markup(n, @text_buffer[n]) | |
1209 | + @layout.set_markup(markup, -1) | |
1210 | + text_w, text_h = @layout.get_pixel_size() | |
1211 | + w = text_w | |
1212 | + start = 0 | |
1213 | + end_ = @text_buffer[n].length | |
1214 | + end | |
1215 | + markup = set_markup(n, @text_buffer[n][start, end_]) | |
1216 | + @layout.set_markup(markup, -1) | |
1217 | + cr.set_source_rgba(*@cursor_color) | |
1218 | + cr.rectangle(x, y, w, h) | |
1219 | + cr.fill() | |
1220 | + cr.move_to(x, y) | |
1221 | + cr.set_source_rgba(*@text_active_color) | |
1222 | + PangoCairo.update_layout(cr, @layout) | |
1223 | + PangoCairo.show_layout(cr, @layout) | |
1224 | + end | |
1225 | + end | |
1226 | + end | |
1227 | + cr.restore() | |
1228 | + end | |
1229 | + | |
1230 | + def check_link_region(px, py) | |
1231 | + new_selection = nil | |
1232 | + for i in 0..(@link_buffer.length - 1) | |
1233 | + sl = @link_buffer[i][0] | |
1234 | + el = @link_buffer[i][2] | |
1235 | + if @lineno <= sl <= @lineno + @lines | |
1236 | + sn = @link_buffer[i][1] | |
1237 | + en = @link_buffer[i][3] | |
1238 | + for n in range(sl,el + 1) | |
1239 | + if n - @lineno >= @line_regions.length | |
1240 | + break | |
1241 | + end | |
1242 | + x, y, w, h = @line_regions[n - @lineno] | |
1243 | + if n == sl | |
1244 | + markup = set_markup(n, @text_buffer[n][0, sn]) | |
1245 | + @layout.set_markup(markup, -1) | |
1246 | + text_w, text_h = @layout.get_pixel_size() | |
1247 | + x += text_w | |
1248 | + end | |
1249 | + if n == sl and n == el | |
1250 | + markup = set_markup(n, @text_buffer[n][sn, en]) | |
1251 | + elsif n == el | |
1252 | + markup = set_markup(n, @text_buffer[n][0, en]) | |
1253 | + else | |
1254 | + markup = set_markup(n, @text_buffer[n]) | |
1255 | + end | |
1256 | + @layout.set_markup(markup, -1) | |
1257 | + text_w, text_h = @layout.get_pixel_size() | |
1258 | + w = text_w | |
1259 | + if x <= px < x + w and y <= py < y + h | |
1260 | + new_selection = i | |
1261 | + break | |
1262 | + end | |
1263 | + end | |
1264 | + end | |
1265 | + end | |
1266 | + if new_selection != nil | |
1267 | + if @selection != new_selection | |
1268 | + sl, sn, el, en, link_id, raw_text, text = \ | |
1269 | + @link_buffer[new_selection] | |
1270 | + @parent.handle_request( | |
1271 | + 'NOTIFY', 'notify_event', | |
1272 | + 'OnChoiceEnter', raw_text, link_id, @selection) | |
1273 | + end | |
1274 | + else | |
1275 | + if @selection != nil | |
1276 | + @parent.handle_request('NOTIFY', 'notify_event', 'OnChoiceEnter') | |
1277 | + end | |
1278 | + end | |
1279 | + if new_selection == @selection | |
1280 | + return 0 | |
1281 | + else | |
1282 | + @selection = new_selection | |
1283 | + return 1 # dirty flag | |
1284 | + end | |
1285 | + end | |
1286 | + | |
1287 | + def motion_notify(widget, event) | |
1288 | + if event.hint? | |
1289 | + _, x, y, state = widget.window.get_device_position(event.device) | |
1290 | + else | |
1291 | + x, y, state = event.x, event.y, event.get_state() | |
1292 | + end | |
1293 | +# scale = @scale | |
1294 | + px, py = @window.winpos_to_surfacepos(x, y, scale) | |
1295 | + if @link_buffer | |
1296 | + if check_link_region(px, py) | |
1297 | + widget.queue_draw() | |
1298 | + end | |
1299 | + end | |
1300 | + if not @parent.handle_request('GET', 'busy') | |
1301 | + if state & Gdk.ModifierType.BUTTON1_MASK | |
1302 | + if @x_root != nil and \ | |
1303 | + @y_root != nil | |
1304 | + @dragged = true | |
1305 | + x_delta = (event.x_root - @x_root) * 100 / scale + @x_fractions | |
1306 | + y_delta = (event.y_root - @y_root) * 100 / scale + @y_fractions | |
1307 | + @x_fractions = x_delta - x_delta.to_i | |
1308 | + @y_fractions = y_delta - y_delta.to_i | |
1309 | + @parent.handle_request( | |
1310 | + 'NOTIFY', 'update_balloon_offset', | |
1311 | + @side, x_delta.to_i, y_delta.to_i) | |
1312 | + @x_root = event.x_root | |
1313 | + @y_root = event.y_root | |
1314 | + end | |
1315 | + end | |
1316 | + end | |
1317 | + return true | |
1318 | + end | |
1319 | + | |
1320 | + def scroll(darea, event) | |
1321 | + px, py = @window.winpos_to_surfacepos( | |
1322 | + event.x.to_i, event.y.to_i, scale) | |
1323 | + if event.direction == Gdk.ScrollDirection.UP | |
1324 | + if @lineno > 0 | |
1325 | + @lineno = [@lineno - 2, 0].max | |
1326 | + check_link_region(px, py) | |
1327 | + @darea.queue_draw() | |
1328 | + end | |
1329 | + elsif event.direction == Gdk.ScrollDirection.DOWN | |
1330 | + if @lineno + @lines < @text_buffer.length | |
1331 | + @lineno = [@lineno + 2, | |
1332 | + @text_buffer.length - @lines].min | |
1333 | + check_link_region(px, py) | |
1334 | + @darea.queue_draw() | |
1335 | + end | |
1336 | + end | |
1337 | + return true | |
1338 | + end | |
1339 | + | |
1340 | + def button_press(darea, event) | |
1341 | + @parent.handle_request('NOTIFY', 'reset_idle_time') | |
1342 | + if event.event_type == Gdk::Event::BUTTON_PRESS | |
1343 | + click = 1 | |
1344 | + else | |
1345 | + click = 2 | |
1346 | + end | |
1347 | + if @parent.handle_request('GET', 'is_paused') | |
1348 | + @parent.handle_request('NOTIFY', 'notify_balloon_click', | |
1349 | + event.button, click, @side) | |
1350 | + return true | |
1351 | + end | |
1352 | + # arrows | |
1353 | + px, py = @window.winpos_to_surfacepos( | |
1354 | + event.x.to_i, event.y.to_i, scale) | |
1355 | + # up arrow | |
1356 | + w = @arrow0_surface.get_width() | |
1357 | + h = @arrow0_surface.get_height() | |
1358 | + x, y = @arrow[0] | |
1359 | + if x <= px <= x + w and y <= py <= y + h | |
1360 | + if @lineno > 0 | |
1361 | + @lineno = [@lineno - 2, 0].max | |
1362 | + @darea.queue_draw() | |
1363 | + end | |
1364 | + return true | |
1365 | + end | |
1366 | + # down arrow | |
1367 | + w = @arrow1_surface.get_width() | |
1368 | + h = @arrow1_surface.get_height() | |
1369 | + x, y = @arrow[1] | |
1370 | + if x <= px <= x + w and y <= py <= y + h | |
1371 | + if @lineno + @lines < @text_buffer.length | |
1372 | + @lineno = [@lineno + 2, | |
1373 | + @text_buffer.length - @lines].min | |
1374 | + @darea.queue_draw() | |
1375 | + end | |
1376 | + return true | |
1377 | + end | |
1378 | + # links | |
1379 | + if @selection != nil | |
1380 | + sl, sn, el, en, link_id, raw_text, text = \ | |
1381 | + @link_buffer[@selection] | |
1382 | + @parent.handle_request('NOTIFY', 'notify_link_selection', | |
1383 | + link_id, raw_text, @selection) | |
1384 | + return true | |
1385 | + end | |
1386 | + # balloon's background | |
1387 | + @parent.handle_request('NOTIFY', 'notify_balloon_click', | |
1388 | + event.button, click, @side) | |
1389 | + @x_root = event.x_root | |
1390 | + @y_root = event.y_root | |
1391 | + return true | |
1392 | + end | |
1393 | + | |
1394 | + def button_release(window, event) | |
1395 | + x, y = @window.winpos_to_surfacepos( | |
1396 | + event.x.to_i, event.y.to_i, scale) | |
1397 | + if @dragged | |
1398 | + @dragged = false | |
1399 | + end | |
1400 | + @x_root = nil | |
1401 | + @y_root = nil | |
1402 | + @y_fractions = 0 | |
1403 | + @y_fractions = 0 | |
1404 | + return true | |
1405 | + end | |
1406 | + | |
1407 | + def clear_text | |
1408 | + @selection = nil | |
1409 | + @lineno = 0 | |
1410 | + @text_buffer = [] | |
1411 | + @meta_buffer = [] | |
1412 | + @link_buffer = [] | |
1413 | + @newline_required = 0 | |
1414 | + @images = [] | |
1415 | + @sstp_marker = [] | |
1416 | + @darea.queue_draw() | |
1417 | + end | |
1418 | + | |
1419 | + def get_text_count | |
1420 | + return @text_count | |
1421 | + end | |
1422 | + | |
1423 | + def reset_text_count | |
1424 | + @text_count = 0 | |
1425 | + end | |
1426 | + | |
1427 | + def set_newline | |
1428 | + @newline_required = 1 | |
1429 | + end | |
1430 | + | |
1431 | + def append_text(text) | |
1432 | + if @text_buffer.empty? | |
1433 | + s = '' | |
1434 | + column = 0 | |
1435 | + index = 0 | |
1436 | + elsif @newline_required | |
1437 | + s = '' | |
1438 | + column = 0 | |
1439 | + @newline_required = 0 | |
1440 | + index = @text_buffer.length | |
1441 | + else | |
1442 | + index = @text_buffer.length - 1 | |
1443 | + s = @text_buffer.pop(-1) | |
1444 | + column = s.length | |
1445 | + end | |
1446 | + i = s.length | |
1447 | + text = [s, text].join('') | |
1448 | + j = text.length | |
1449 | + @text_count += j | |
1450 | + p = 0 | |
1451 | + while 1 | |
1452 | + if i >= j | |
1453 | + @text_buffer << text[p, i] | |
1454 | + draw_last_line(column) | |
1455 | + break | |
1456 | + end | |
1457 | + if text[i] == '\n' | |
1458 | + if j >= i + 7 and text[i, i + 7] == '\n[half]' | |
1459 | + @text_buffer << [text[p, i], '\n[half]'].join('') | |
1460 | + p = i = i + 7 | |
1461 | + else | |
1462 | + @text_buffer << text[p, i] | |
1463 | + p = i = i + 1 | |
1464 | + end | |
1465 | + draw_last_line(column) | |
1466 | + column = 0 | |
1467 | + next | |
1468 | + end | |
1469 | + n = i + 1 | |
1470 | + if not @__shown | |
1471 | + show() | |
1472 | + end | |
1473 | + markup = set_markup(index, text[p, n]) | |
1474 | + @layout.set_markup(markup, -1) | |
1475 | + text_width, text_height = @layout.pixel_size | |
1476 | + if text_width > @line_width | |
1477 | + @text_buffer << text[p, i] | |
1478 | + draw_last_line(column) | |
1479 | + column = 0 | |
1480 | + p = i | |
1481 | + end | |
1482 | + i = n | |
1483 | + end | |
1484 | + end | |
1485 | + | |
1486 | + def append_sstp_marker | |
1487 | + if @sstp_surface != nil | |
1488 | + return | |
1489 | + end | |
1490 | + if @text_buffer.empty? | |
1491 | + line = 0 | |
1492 | + offset = 0 | |
1493 | + else | |
1494 | + line = @text_buffer.length - 1 | |
1495 | + offset = @text_buffer[-1].length | |
1496 | + end | |
1497 | + if @newline_required | |
1498 | + line = line + 1 | |
1499 | + offset = 0 | |
1500 | + end | |
1501 | + @sstp_marker << [line, offset] | |
1502 | + w = @sstp_surface.get_width() | |
1503 | + h = @sstp_surface.get_height() | |
1504 | + i = 1 | |
1505 | + while 1 | |
1506 | + space = '\u3000' * i ## FIXME | |
1507 | + @layout.set_text(space, -1) | |
1508 | + text_w, text_h = @layout.get_pixel_size() | |
1509 | + if text_w > w | |
1510 | + break | |
1511 | + else | |
1512 | + i += 1 | |
1513 | + end | |
1514 | + end | |
1515 | + append_text(space) | |
1516 | + draw_last_line(offset) | |
1517 | + end | |
1518 | + | |
1519 | + def append_link_in(link_id) | |
1520 | + if @text_buffer.empty? | |
1521 | + sl = 0 | |
1522 | + sn = 0 | |
1523 | + else | |
1524 | + sl = @text_buffer.length - 1 | |
1525 | + sn = @text_buffer[-1].length | |
1526 | + end | |
1527 | + @link_buffer << [sl, sn, sl, sn, link_id, '', ''] | |
1528 | + end | |
1529 | + | |
1530 | + def append_link_out(link_id, text) | |
1531 | + if not text | |
1532 | + return | |
1533 | + end | |
1534 | + raw_text = text | |
1535 | + if @text_buffer.empty? | |
1536 | + el = 0 | |
1537 | + en = 0 | |
1538 | + else | |
1539 | + el = @text_buffer.length - 1 | |
1540 | + en = @text_buffer[-1].length | |
1541 | + end | |
1542 | + for i in range(@link_buffer.length) | |
1543 | + if @link_buffer[i][4] == link_id | |
1544 | + sl = @link_buffer[i][0] | |
1545 | + sn = @link_buffer[i][1] | |
1546 | + @link_buffer.pop(i) | |
1547 | + @link_buffer.insert(i, [sl, sn, el, en, link_id, raw_text, text]) | |
1548 | + break | |
1549 | + end | |
1550 | + end | |
1551 | + end | |
1552 | + | |
1553 | + def append_meta(tag) | |
1554 | + if not tag | |
1555 | + return | |
1556 | + end | |
1557 | + if @text_buffer.empty? | |
1558 | + sl = 0 | |
1559 | + sn = 0 | |
1560 | + else | |
1561 | + sl = @text_buffer.length - 1 | |
1562 | + sn = @text_buffer[-1].length | |
1563 | + end | |
1564 | + @meta_buffer << [sl, sn, tag] | |
1565 | + end | |
1566 | + | |
1567 | + def append_image(path, x, y) | |
1568 | + begin | |
1569 | + image_surface = Pix.create_surface_from_file(path) | |
1570 | + rescue # except: | |
1571 | + return | |
1572 | + end | |
1573 | + show() | |
1574 | + @images << [image_surface, [x, y]] | |
1575 | + @darea.queue_draw() | |
1576 | + end | |
1577 | + | |
1578 | + def draw_last_line(column=0) | |
1579 | + if not @__shown | |
1580 | + return | |
1581 | + end | |
1582 | + line = @text_buffer.length - 1 | |
1583 | + if @lineno <= line && line < @lineno + @lines | |
1584 | + x, y, w, h = @line_regions[line - @lineno] | |
1585 | + if @text_buffer[line].end_with?('\n[half]') | |
1586 | + offset = line - @lineno + 1 | |
1587 | + new_y = (y + (@font_height + @line_space) / 2).to_i | |
1588 | + update_line_regions(offset, new_y) | |
1589 | + else | |
1590 | + @darea.queue_draw() | |
1591 | + end | |
1592 | + if @sstp_surface != nil | |
1593 | + for l, c in @sstp_marker | |
1594 | + if l == line | |
1595 | + mw = @sstp_surface.get_width() | |
1596 | + mh = @sstp_surface.get_height() | |
1597 | + @layout.set_text(@text_buffer[l][0, c], -1) | |
1598 | + text_w, text_h = @layout.get_pixel_size() | |
1599 | + mx = x + text_w | |
1600 | + my = y + (@font_height + @line_space) / 2 | |
1601 | + my = my - mh / 2 | |
1602 | + cr = @darea.get_window().cairo_create() | |
1603 | + cr.set_source_surface(@sstp_surface, mx, my) | |
1604 | + cr.paint() | |
1605 | + del cr | |
1606 | + end | |
1607 | + end | |
1608 | + end | |
1609 | + else | |
1610 | + @darea.queue_draw() | |
1611 | + if @autoscroll | |
1612 | + while line >= @lineno + @lines | |
1613 | + @lineno += 1 | |
1614 | + @darea.queue_draw() | |
1615 | + end | |
1616 | + end | |
1617 | + end | |
1618 | + end | |
1619 | + end | |
1620 | + | |
1621 | + | |
1622 | + class CommunicateWindow | |
1623 | + | |
1624 | + NAME = '' | |
1625 | + ENTRY = '' | |
1626 | + | |
1627 | + def initialize | |
1628 | + @parent = nil | |
1629 | + @window = nil | |
1630 | + end | |
1631 | + | |
1632 | + def set_responsible(parent) | |
1633 | + @parent = parent | |
1634 | + end | |
1635 | + | |
1636 | + def new_(desc, balloon) | |
1637 | + if @window != nil | |
1638 | + @window.destroy() | |
1639 | + end | |
1640 | + @window = Pix::BaseTransparentWindow.new() | |
1641 | + @window.set_title('communicate') | |
1642 | + @window.signal_connect('delete_event') do |w ,e| | |
1643 | + delete(w, e) | |
1644 | + end | |
1645 | + @window.signal_connect('key_press_event') do |w, e| | |
1646 | + key_press(w, e) | |
1647 | + end | |
1648 | + @window.signal_connect('button_press_event') do |w, e| | |
1649 | + button_press(w, e) | |
1650 | + end | |
1651 | + @window.signal_connect('drag_data_received') do |w, e| | |
1652 | + drag_data_received(w, e) | |
1653 | + end | |
1654 | + # DnD data types | |
1655 | +# dnd_targets = [Gtk.TargetEntry.new('text/plain', 0, 0)] | |
1656 | +# @window.drag_dest_set(Gtk.DestDefaults.ALL, dnd_targets, | |
1657 | +# Gdk.DragAction.COPY) | |
1658 | +# @window.drag_dest_add_text_targets() | |
1659 | + @window.set_events(Gdk::Event::BUTTON_PRESS_MASK) | |
1660 | + @window.set_modal(true) | |
1661 | + @window.set_window_position(Gtk::Window::Position::CENTER) | |
1662 | + @window.realize() | |
1663 | + w = desc.get('communicatebox.width', 250).to_i | |
1664 | + h = desc.get('communicatebox.height', -1).to_i | |
1665 | + @entry = Gtk::Entry.new | |
1666 | + @entry.signal_connect('activate') do |w| | |
1667 | + activate(w) | |
1668 | + end | |
1669 | + @entry.set_inner_border(nil) | |
1670 | + @entry.set_has_frame(false) | |
1671 | + font_desc = Pango::FontDescription.new() | |
1672 | + font_desc.set_size(9 * 3 / 4 * Pango::SCALE) # XXX | |
1673 | + @entry.modify_font(font_desc) | |
1674 | + @entry.set_size_request(w, h) | |
1675 | + @entry.show() | |
1676 | + surface = nil | |
1677 | + if balloon | |
1678 | + path, config = balloon | |
1679 | + # load pixbuf | |
1680 | + begin | |
1681 | + surface = Pix.create_surface_from_file(path) | |
1682 | + rescue # except: | |
1683 | + surface = nil | |
1684 | + end | |
1685 | + end | |
1686 | + if surface != nil | |
1687 | + darea = Gtk::DrawingArea.new() | |
1688 | + darea.set_events(Gdk::Event::EXPOSURE_MASK) | |
1689 | + darea.signal_connect('draw') do |w, e| | |
1690 | + redraw(w, e, surface) | |
1691 | + end | |
1692 | + darea.show() | |
1693 | + x = desc.get('communicatebox.x', 10).to_i | |
1694 | + y = desc.get('communicatebox.y', 20).to_i | |
1695 | + overlay = Gtk::Overlay.new() | |
1696 | + @entry.set_margin_left(x) | |
1697 | + @entry.set_margin_top(y) | |
1698 | + @entry.set_halign(Gtk::Alignment::Align::START) | |
1699 | + @entry.set_valign(Gtk::Alignment::Align::START) | |
1700 | + overlay.add_overlay(@entry) | |
1701 | + overlay.add(darea) | |
1702 | + overlay.show() | |
1703 | + @window.add(overlay) | |
1704 | + w = surface.width | |
1705 | + h = surface.height | |
1706 | + darea.set_size_request(w, h) | |
1707 | + else | |
1708 | + box = Gtk::HBox.new(spacing=10) | |
1709 | + box.set_border_width(10) | |
1710 | + if ENTRY | |
1711 | + label = Gtk::Label.new(label=ENTRY) | |
1712 | + box.pack_start(label, false, true, 0) | |
1713 | + label.show() | |
1714 | + end | |
1715 | + box.pack_start(@entry, true, true, 0) | |
1716 | + @window.add(box) | |
1717 | + box.show() | |
1718 | + end | |
1719 | + end | |
1720 | + | |
1721 | + def drag_data_received(widget, context, x, y, data, info, time) | |
1722 | + @entry.set_text(data.get_text()) | |
1723 | + end | |
1724 | + | |
1725 | + def redraw(widget, cr, surface) | |
1726 | + cr.set_source_surface(surface, 0, 0) | |
1727 | + cr.set_operator(cairo.OPERATOR_SOURCE) | |
1728 | + cr.paint() | |
1729 | + region = Gdk.cairo_region_create_from_surface(cr.get_target()) | |
1730 | + # XXX: to avoid losing focus in the text input region | |
1731 | + x = @entry.get_margin_left() | |
1732 | + y = @entry.get_margin_top() | |
1733 | + w = @entry.get_allocated_width() | |
1734 | + h = @entry.get_allocated_height() | |
1735 | + region.union(cairo.RectangleInt(x, y, w, h)) | |
1736 | + @window.input_shape_combine_region(region) | |
1737 | + end | |
1738 | + | |
1739 | + def destroy | |
1740 | + if @window | |
1741 | + @window.destroy() | |
1742 | + @window = nil | |
1743 | + end | |
1744 | + end | |
1745 | + | |
1746 | + def delete(widget, event) | |
1747 | + @window.hide() | |
1748 | + cancel() | |
1749 | + return true | |
1750 | + end | |
1751 | + | |
1752 | + def key_press(widget, event) | |
1753 | + if event.keyval == Gdk.KEY_Escape | |
1754 | + @window.hide() | |
1755 | + cancel() | |
1756 | + return true | |
1757 | + end | |
1758 | + return false | |
1759 | + end | |
1760 | + | |
1761 | + def button_press(widget, event) | |
1762 | + if [1, 2].include?(event.button) | |
1763 | + @window.begin_move_drag( | |
1764 | + event.button, event.x_root.to_i, event.y_root.to_i, | |
1765 | + Gtk.get_current_event_time()) | |
1766 | + end | |
1767 | + return true | |
1768 | + end | |
1769 | + | |
1770 | + def activate(widget) | |
1771 | + @window.hide() | |
1772 | + enter() | |
1773 | + return true | |
1774 | + end | |
1775 | + | |
1776 | + def show(default='') | |
1777 | + @entry.set_text(default) | |
1778 | + @window.show() | |
1779 | + end | |
1780 | + | |
1781 | +# @abc.abstractmethod | |
1782 | + def enter | |
1783 | +# pass | |
1784 | + end | |
1785 | + | |
1786 | +# @abc.abstractmethod | |
1787 | + def cancel | |
1788 | +# pass | |
1789 | + end | |
1790 | + end | |
1791 | + | |
1792 | + | |
1793 | + class CommunicateBox < CommunicateWindow | |
1794 | + | |
1795 | + NAME = 'communicatebox' | |
1796 | + ENTRY = 'Communicate' | |
1797 | + | |
1798 | + def new_(desc, balloon) | |
1799 | + super | |
1800 | + @window.set_modal(false) | |
1801 | + end | |
1802 | + | |
1803 | + def delete(widget, event) | |
1804 | + @window.hide() | |
1805 | + cancel() | |
1806 | + @parent.handle_request('NOTIFY', 'reset_user_interaction') | |
1807 | + return true | |
1808 | + end | |
1809 | + | |
1810 | + def key_press(widget, event) | |
1811 | + if event.keyval == Gdk.KEY_Escape | |
1812 | + @window.hide() | |
1813 | + cancel() | |
1814 | + @parent.handle_request('NOTIFY', 'reset_user_interaction') | |
1815 | + return true | |
1816 | + end | |
1817 | + return false | |
1818 | + end | |
1819 | + | |
1820 | + def activate(widget) | |
1821 | + enter() | |
1822 | + @entry.set_text('') | |
1823 | + return true | |
1824 | + end | |
1825 | + | |
1826 | + def enter | |
1827 | + send(@entry.get_text()) | |
1828 | + end | |
1829 | + | |
1830 | + def cancel | |
1831 | + @parent.handle_request('NOTIFY', 'notify_event', | |
1832 | + 'OnCommunicateInputCancel', '', 'cancel') | |
1833 | + end | |
1834 | + | |
1835 | + def send(data) | |
1836 | + if data != nil | |
1837 | + @parent.handle_request('NOTIFY', 'notify_event', | |
1838 | + 'OnCommunicate', 'user', data) | |
1839 | + end | |
1840 | + end | |
1841 | + end | |
1842 | + | |
1843 | + class TeachBox < CommunicateWindow | |
1844 | + | |
1845 | + NAME = 'teachbox' | |
1846 | + ENTRY = 'Teach' | |
1847 | + | |
1848 | + def enter | |
1849 | + send(@entry.get_text()) | |
1850 | + end | |
1851 | + | |
1852 | + def cancel | |
1853 | + @parent.handle_request('NOTIFY', 'notify_event', | |
1854 | + 'OnTeachInputCancel', '', 'cancel') | |
1855 | + @parent.handle_request('NOTIFY', 'reset_user_interaction') | |
1856 | + end | |
1857 | + | |
1858 | + def send(data) | |
1859 | + @parent.handle_request('NOTIFY', 'notify_user_teach', data) | |
1860 | + @parent.handle_request('NOTIFY', 'reset_user_interaction') | |
1861 | + end | |
1862 | + end | |
1863 | + | |
1864 | + | |
1865 | + class InputBox < CommunicateWindow | |
1866 | + | |
1867 | + NAME = 'inputbox' | |
1868 | + ENTRY = 'Input' | |
1869 | + | |
1870 | + def new_(desc, balloon) | |
1871 | + super | |
1872 | + @symbol = nil | |
1873 | + @limittime = -1 | |
1874 | + end | |
1875 | + | |
1876 | + def set_symbol(symbol) | |
1877 | + @symbol = symbol | |
1878 | + end | |
1879 | + | |
1880 | + def set_limittime(limittime) | |
1881 | + begin | |
1882 | + limittime = limittime.to_i | |
1883 | + rescue # except ValueError: | |
1884 | + limittime = -1 | |
1885 | + end | |
1886 | + @limittime = limittime | |
1887 | + end | |
1888 | + | |
1889 | + def show(default) | |
1890 | + if default != nil | |
1891 | + begin | |
1892 | + text = str(default) | |
1893 | + rescue # except: | |
1894 | + text = '' | |
1895 | + end | |
1896 | + else | |
1897 | + text = '' | |
1898 | + end | |
1899 | + if @limittime.to_i < 0 | |
1900 | + @timeout_id = nil | |
1901 | + else | |
1902 | + @timeout_id = GLib.timeout_add(@limittime, @timeout) | |
1903 | + end | |
1904 | + CommunicateWindow.show(self, text) | |
1905 | + end | |
1906 | + | |
1907 | + def timeout | |
1908 | + @window.hide() | |
1909 | + send('timeout', timeout=true) | |
1910 | + end | |
1911 | + | |
1912 | + def enter | |
1913 | + send(@entry.get_text()) | |
1914 | + end | |
1915 | + | |
1916 | + def cancel | |
1917 | + send(nil, cancel=true) | |
1918 | + end | |
1919 | + | |
1920 | + def close(symbol) | |
1921 | + if @symbol == nil | |
1922 | + return | |
1923 | + end | |
1924 | + if symbol != '__SYSTEM_ALL_INPUT__' and @symbol != symbol | |
1925 | + return | |
1926 | + end | |
1927 | + @window.hide() | |
1928 | + cancel() | |
1929 | + end | |
1930 | + | |
1931 | + def send(data, cancel=false, timeout=false) | |
1932 | + if @timeout_id != nil | |
1933 | + GLib.source_remove(@timeout_id) | |
1934 | + end | |
1935 | + if data == nil | |
1936 | + data = '' | |
1937 | + end | |
1938 | + ## CHECK: symbol | |
1939 | + if cancel | |
1940 | + @parent.handle_request('NOTIFY', 'notify_event', | |
1941 | + 'OnUserInputCancel', '', 'cancel') | |
1942 | + elsif timeout and \ | |
1943 | + @parent.handle_request('GET', 'notify_event', | |
1944 | + 'OnUserInputCancel', '', 'timeout') | |
1945 | + # pass | |
1946 | + elsif @symbol == 'OnUserInput' and \ | |
1947 | + @parent.handle_request('GET', 'notify_event', 'OnUserInput', data) | |
1948 | + # pass | |
1949 | + elsif @parent.handle_request('GET', 'notify_event', | |
1950 | + 'OnUserInput', @symbol, data) | |
1951 | + # pass | |
1952 | + elsif @parent.handle_request('GET', 'notify_event', @symbol, data) | |
1953 | + # pass | |
1954 | + end | |
1955 | + @symbol = nil | |
1956 | + @parent.handle_request('NOTIFY', 'reset_user_interaction') | |
1957 | + end | |
1958 | + end | |
1959 | + | |
1960 | + class PasswordInputBox < InputBox | |
1961 | + | |
1962 | + NAME = 'passwordinputbox' | |
1963 | + ENTRY = 'PasswordInput' | |
1964 | + | |
1965 | + def new_(desc, balloon) | |
1966 | + super | |
1967 | + @entry.set_visibility(false) | |
1968 | + end | |
1969 | + end | |
1970 | + | |
1971 | + | |
1972 | + class TEST | |
1973 | + | |
1974 | + def initialize | |
1975 | + require "ninix/home" | |
1976 | + balloons = Home.search_balloons() | |
1977 | + key = balloons.keys.sample | |
1978 | +# print(key, balloons[key], "\n") | |
1979 | + balloon = Balloon.new | |
1980 | + balloon.set_responsible(self) | |
1981 | + balloon.new_(*balloons[key]) | |
1982 | + balloon.set_balloon(0, 0) | |
1983 | + balloon.set_balloon(1, 0) | |
1984 | + balloon.set_position(0, 200, 200) | |
1985 | + balloon.set_position(1, 100, 100) | |
1986 | + balloon.show(0) | |
1987 | + balloon.show(1) | |
1988 | + balloon.show_sstp_message("TEST: SSTP", "TEST class") | |
1989 | + for i in 0..20 | |
1990 | + balloon.append_text(0, "TEST: SAKURA") | |
1991 | + end | |
1992 | + balloon.append_text(1, "TEST: KERO") | |
1993 | + Gtk.main | |
1994 | + end | |
1995 | + | |
1996 | + def handle_request(event_type, event, *arglist, **argdict) | |
1997 | + if event == 'lock_repaint' | |
1998 | + return false | |
1999 | + else | |
2000 | + return 100 # XXX | |
2001 | + end | |
2002 | + end | |
2003 | + | |
2004 | + end | |
2005 | +end | |
2006 | + | |
2007 | +Balloon::TEST.new() |