extract_curves 0.0.1-i586-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. data/CVS/Entries +4 -0
  2. data/CVS/Repository +1 -0
  3. data/CVS/Root +1 -0
  4. data/bin/CVS/Entries +5 -0
  5. data/bin/CVS/Repository +1 -0
  6. data/bin/CVS/Root +1 -0
  7. data/bin/ec_rect2polar.rb +22 -0
  8. data/bin/ec_rev_lines.rb +5 -0
  9. data/bin/ec_sph_area.rb +30 -0
  10. data/bin/extract_curves.rb +2145 -0
  11. data/ruby_ext/CVS/Entries +1 -0
  12. data/ruby_ext/CVS/Repository +1 -0
  13. data/ruby_ext/CVS/Root +1 -0
  14. data/ruby_ext/pav/CVS/Entries +14 -0
  15. data/ruby_ext/pav/CVS/Repository +1 -0
  16. data/ruby_ext/pav/CVS/Root +1 -0
  17. data/ruby_ext/pav/extconf.rb +22 -0
  18. data/ruby_ext/pav/pav.so +0 -0
  19. data/ruby_libs/CVS/Entries +1 -0
  20. data/ruby_libs/CVS/Repository +1 -0
  21. data/ruby_libs/CVS/Root +1 -0
  22. data/ruby_libs/pav/CVS/Entries +20 -0
  23. data/ruby_libs/pav/CVS/Repository +1 -0
  24. data/ruby_libs/pav/CVS/Root +1 -0
  25. data/ruby_libs/pav/attr_cache.rb +211 -0
  26. data/ruby_libs/pav/attr_cache.t1.rb +32 -0
  27. data/ruby_libs/pav/cache.rb +31 -0
  28. data/ruby_libs/pav/dbg_log.rb +458 -0
  29. data/ruby_libs/pav/floatsio.rb +53 -0
  30. data/ruby_libs/pav/generator_cache.rb +165 -0
  31. data/ruby_libs/pav/gtk/CVS/Entries +4 -0
  32. data/ruby_libs/pav/gtk/CVS/Repository +1 -0
  33. data/ruby_libs/pav/gtk/CVS/Root +1 -0
  34. data/ruby_libs/pav/gtk/button.rb +130 -0
  35. data/ruby_libs/pav/gtk/icons.rb +87 -0
  36. data/ruby_libs/pav/gtk/toolbar.rb +192 -0
  37. data/ruby_libs/pav/heap.rb +54 -0
  38. data/ruby_libs/pav/icons/CVS/Entries +17 -0
  39. data/ruby_libs/pav/icons/CVS/Repository +1 -0
  40. data/ruby_libs/pav/icons/CVS/Root +1 -0
  41. data/ruby_libs/pav/icons/alt_handle.xpm +3832 -0
  42. data/ruby_libs/pav/icons/alt_handle_hover.xpm +3368 -0
  43. data/ruby_libs/pav/icons/alt_handle_pressed.xpm +3828 -0
  44. data/ruby_libs/pav/icons/extract_curves/CVS/Entries +6 -0
  45. data/ruby_libs/pav/icons/extract_curves/CVS/Repository +1 -0
  46. data/ruby_libs/pav/icons/extract_curves/CVS/Root +1 -0
  47. data/ruby_libs/pav/icons/extract_curves/extract_curves-icon-rgb.ppm +14 -0
  48. data/ruby_libs/pav/icons/extract_curves/extract_curves-logo-rgb.gif +0 -0
  49. data/ruby_libs/pav/icons/extract_curves/trace_mark.xpm +38 -0
  50. data/ruby_libs/pav/icons/handle.xpm +213 -0
  51. data/ruby_libs/pav/icons/next.xpm +29 -0
  52. data/ruby_libs/pav/icons/next_hover.xpm +315 -0
  53. data/ruby_libs/pav/icons/next_pressed.xpm +144 -0
  54. data/ruby_libs/pav/icons/prev.xpm +29 -0
  55. data/ruby_libs/pav/icons/prev_hover.xpm +315 -0
  56. data/ruby_libs/pav/icons/prev_pressed.xpm +144 -0
  57. data/ruby_libs/pav/icons/vnext.xpm +29 -0
  58. data/ruby_libs/pav/icons/vprev.xpm +29 -0
  59. data/ruby_libs/pav/numeric/CVS/Entries +2 -0
  60. data/ruby_libs/pav/numeric/CVS/Repository +1 -0
  61. data/ruby_libs/pav/numeric/CVS/Root +1 -0
  62. data/ruby_libs/pav/numeric/ext.rb +13 -0
  63. data/ruby_libs/pav/pav_find.rb +90 -0
  64. data/ruby_libs/pav/pix/CVS/Entries +11 -0
  65. data/ruby_libs/pav/pix/CVS/Repository +1 -0
  66. data/ruby_libs/pav/pix/CVS/Root +1 -0
  67. data/ruby_libs/pav/pix/aapix.rb +378 -0
  68. data/ruby_libs/pav/pix/blob.rb +543 -0
  69. data/ruby_libs/pav/pix/circle.rb +73 -0
  70. data/ruby_libs/pav/pix/contour/CVS/Entries +5 -0
  71. data/ruby_libs/pav/pix/contour/CVS/Repository +1 -0
  72. data/ruby_libs/pav/pix/contour/CVS/Root +1 -0
  73. data/ruby_libs/pav/pix/contour/calc_situations.rb +9 -0
  74. data/ruby_libs/pav/pix/contour/carp_calc.rb +212 -0
  75. data/ruby_libs/pav/pix/contour/situations.dmp +0 -0
  76. data/ruby_libs/pav/pix/contour/situations.rb +21 -0
  77. data/ruby_libs/pav/pix/contour.rb +644 -0
  78. data/ruby_libs/pav/pix/curve.rb +1508 -0
  79. data/ruby_libs/pav/pix/img_obj.rb +751 -0
  80. data/ruby_libs/pav/pix/node.rb +712 -0
  81. data/ruby_libs/pav/pix/node_grp.rb +853 -0
  82. data/ruby_libs/pav/pix/shaved_core.rb +534 -0
  83. data/ruby_libs/pav/pix/subpix.rb +212 -0
  84. data/ruby_libs/pav/pix.rb +402 -0
  85. data/ruby_libs/pav/rand_accessible.rb +16 -0
  86. data/ruby_libs/pav/rangeset.rb +63 -0
  87. data/ruby_libs/pav/search.rb +210 -0
  88. data/ruby_libs/pav/set.rb +20 -0
  89. data/ruby_libs/pav/string/CVS/Entries +6 -0
  90. data/ruby_libs/pav/string/CVS/Repository +1 -0
  91. data/ruby_libs/pav/string/CVS/Root +1 -0
  92. data/ruby_libs/pav/string/bits.rb +523 -0
  93. data/ruby_libs/pav/string/ext.rb +58 -0
  94. data/ruby_libs/pav/string/observable.rb +155 -0
  95. data/ruby_libs/pav/string/text.rb +79 -0
  96. data/ruby_libs/pav/string/words.rb +42 -0
  97. data/ruby_libs/pav/sub_arr.rb +55 -0
  98. data/ruby_libs/pav/traced_obj.rb +79 -0
  99. metadata +147 -0
@@ -0,0 +1,2145 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'gtk2'
4
+
5
+ if str = Gtk.check_version(2, 6, 0)
6
+ puts "This program requires GTK+ 2.6.0 or later"
7
+ puts str
8
+ exit
9
+ end
10
+
11
+ require 'thread'
12
+ require 'pav/pix'
13
+ require 'pav/dbg_log'
14
+ require 'pav/floatsio'
15
+ require 'pav/pix/blob'
16
+ require 'pav/pix/curve'
17
+ require 'pav/gtk/icons'
18
+ require 'pav/attr_cache'
19
+ require 'pav/string/ext'
20
+ require 'pav/gtk/toolbar'
21
+ require 'pav/pix/contour'
22
+ require 'pav/pix/img_obj'
23
+ require 'pav/string/words'
24
+ require 'pav/pix/shaved_core'
25
+
26
+ Gtk.init
27
+
28
+ module PPix
29
+
30
+ class Blob
31
+ attr_accessor :extract_curves_args
32
+ end
33
+
34
+ class Curve
35
+ self.img_obj_add_to_sub_objs :shaved_core
36
+
37
+ def shaved_core
38
+ ec =self.curve_carpet.blob.extract_curves_args['extract_curves']
39
+ self.c_shaved_core(ec.min_hair_len, ec.min_hair_lp_len)
40
+ end
41
+
42
+ def delete_shaved_core
43
+ self.c_delete_shaved_core
44
+ end
45
+ end
46
+
47
+ end
48
+
49
+ class ECLogProgrBar < PLogProgrBar
50
+ attr_reader :progr_bar, :progr_box, :progr_label
51
+
52
+ def initialize(dbg_log, progr_bar, progr_label, progr_box)
53
+ super(dbg_log)
54
+ @progr_bar = progr_bar
55
+ @progr_label = progr_label
56
+ @progr_box = progr_box
57
+ @progr_label.text = ""
58
+ @progr_bar.orientation = @progr_bar_orientation = 0
59
+ @progr_bar.fraction = 0.0
60
+ @progr_bar.show_text = false
61
+ @progr_box.pack_start(@progr_bar)
62
+ @progr_box.pack_start(@progr_label, false, false)
63
+ @tot_progr_units = 100.0
64
+ i = -1
65
+ Gtk.main_iteration_do(false) while (i += 1) < 10 &&
66
+ Gtk.events_pending?
67
+ end
68
+
69
+ def total_progr_units=(val)
70
+ super(val)
71
+ if val
72
+ @progr_bar.show_text = true
73
+ else
74
+ @progr_bar.show_text = false
75
+ end
76
+ i = -1
77
+ Gtk.main_iteration_do(false) while (i += 1) < 10 &&
78
+ Gtk.events_pending?
79
+ end
80
+
81
+ def disp_progr(progr_units_change)
82
+ if self.total_progr_units
83
+ if self.show_as[0,1] == "%"
84
+ pct = self.fmt_str % (100.0*self.progr_units /
85
+ self.total_progr_units)
86
+ else
87
+ pct = "#{self.progr_units}/#{
88
+ self.total_progr_units}"
89
+ end
90
+ pct += self.show_as[1, self.show_as.length-1]
91
+ @progr_bar.fraction = Float(self.progr_units) /
92
+ self.total_progr_units
93
+ else
94
+ while self.progr_units > @tot_progr_units
95
+ @tot_progr_units *= 2
96
+ @progr_bar_orientation += 1
97
+ end
98
+ if self.show_as[0,1] == "%"
99
+ pct = ""
100
+ else
101
+ pct = "#{self.progr_units}" +
102
+ self.show_as[1,self.show_as.length-1]
103
+ end
104
+ @progr_bar.fraction = Float(self.progr_units) /
105
+ @tot_progr_units
106
+ @progr_bar.orientation = @progr_bar_orientation %= 2
107
+ end
108
+ @progr_label.text = pct
109
+ i = -1
110
+ Gtk.main_iteration_do(false) while (i += 1) < 10 &&
111
+ Gtk.events_pending?
112
+ end
113
+
114
+ def finish
115
+ super
116
+ @progr_box.remove(@progr_label)
117
+ @progr_box.remove(@progr_bar)
118
+ i = -1
119
+ Gtk.main_iteration_do(false) while (i += 1) < 10 &&
120
+ Gtk.events_pending?
121
+ end
122
+ end
123
+
124
+ class StatusbarIO < IO
125
+ attr_reader :dbg_log, :statusbar, :tee_to, :last_ln
126
+
127
+ def initialize(dbg_log, statusbar, tee_to=nil)
128
+ @dbg_log = dbg_log
129
+ @statusbar = statusbar
130
+ @tee_to = tee_to
131
+ @last_ln = ""
132
+ end
133
+
134
+ def print_to_statusbar(str)
135
+ (@last_ln + str).each_line { |ln| @last_ln = ln }
136
+ @last_ln.eval_backspace!(@dbg_log.backspc)
137
+ @statusbar.pop(0)
138
+ @statusbar.push(0, @last_ln.chomp)
139
+ i = -1
140
+ Gtk.main_iteration_do(false) while (i += 1) < 10 &&
141
+ Gtk.events_pending?
142
+ end
143
+
144
+ def print(str)
145
+ @tee_to.print(str) if @tee_to
146
+ self.print_to_statusbar(str)
147
+ end
148
+
149
+ def puts(str)
150
+ @tee_to.puts(str) if @tee_to
151
+ self.print_to_statusbar(str)
152
+ end
153
+
154
+ def tty?
155
+ if @tee_to
156
+ @tee_to.tty?
157
+ else
158
+ true
159
+ end
160
+ end
161
+ end
162
+
163
+ class ExtractCurvesApp < Gtk::Window
164
+ VERSION = [0, 0, 1]
165
+ VERSION_SUFFIX = "-beta"
166
+ MARK_WAYS = ["mark", "blink", "trace"]
167
+
168
+ attr_reader :min_hair_len, :min_hair_lp_len
169
+
170
+ def initialize
171
+ @job = nil
172
+ @in_progr = Mutex.new
173
+ @pixbuf = nil
174
+ @pixbuf_backing = @pixbuf_marked = @pixbuf_blinking = nil
175
+ @pixbuf_marked_objs = []
176
+ @pixbuf_blinking_objs = []
177
+ @pixbuf_traced_objs = []
178
+ @pixbuf_traced_obj_i = @pixbuf_traced_pix_i = 0
179
+ @blink_area = @blink_area_rect = nil
180
+ @drw_area_in_procs = false
181
+ @blob = nil
182
+ @external_contours = true
183
+ @min_hair_len = 10
184
+ @min_hair_lp_len = 10
185
+ @min_subblob_size = 1
186
+ @min_outer_lp_length = 0
187
+ @mark_blob = {""=>"blink"}
188
+ @pixels_mark_proc = proc { |pix| self.pixels_mark(pix) }
189
+ @pixels_unmark_proc = proc { |pix| self.pixels_unmark(pix) }
190
+ @fuzzy_clr_r = @fuzzy_clr_g = @fuzzy_clr_b = 10
191
+ @fuzzy_clr_h = @fuzzy_clr_s = @fuzzy_clr_v = 0.0
192
+ @clr_match_scheme = "rgb"
193
+ @clr_show_scheme = "rgb"
194
+ @pix_trace_tm_out = 100
195
+ @contour_geometry = 8
196
+ @ctxt_menu_m_cb = self.method("ctxt_menu_m_cb").to_proc
197
+ @ctxt_menu_d_cb = self.method("ctxt_menu_d_cb").to_proc
198
+ @ctxt_menu_s_cb = self.method("ctxt_menu_s_cb").to_proc
199
+ @ctxt_menu_e_cb = self.method("ctxt_menu_e_cb").to_proc
200
+ super(Gtk::Window::TOPLEVEL)
201
+ self.set_title("Extract Curves")
202
+ begin
203
+ icon = Gdk::Pixbuf.new(PGtk.find_icon_file(
204
+ 'pav/icons/extract_curves/extract_curves-icon-rgb.ppm').to_s)
205
+ self.set_icon(icon)
206
+ rescue IOError, Gdk::PixbufError
207
+ warn self.class.name + ".initialize: Error: Failed to load " +
208
+ "icon:\n" + $!.class.name + ": #{$!}\n\tfrom " +
209
+ $!.backtrace.join("\n\tfrom ")
210
+ end
211
+ @trace_mark = Gdk::Pixbuf.new(PGtk.find_icon_file(
212
+ 'pav/icons/extract_curves/trace_mark.xpm'))
213
+ quit_cb = proc { self.destroy; true }
214
+ signal_connect('delete_event', &quit_cb)
215
+ set_default_size(450, 450)
216
+
217
+ # Root container:
218
+ table = Gtk::Table.new(1, 4, false)
219
+ add(table)
220
+
221
+ # Menubar:
222
+ accel_group = Gtk::AccelGroup.new
223
+ add_accel_group(accel_group)
224
+ open_cb = self.method("open_cb").to_proc
225
+ load_blob_cb = self.method('load_blob_cb').to_proc
226
+ save_cb = proc { |*args|
227
+ objs = @pixbuf_marked_objs + @pixbuf_blinking_objs +
228
+ @pixbuf_traced_objs
229
+ return if objs.empty?
230
+ self.save_img_obj(*objs)
231
+ }
232
+ cancel_cb = proc { |*args| Thread.kill(@job) if @job }
233
+ ctxt_cb = proc { |*args| self.img_pop_context_menu }
234
+ del_cb = proc { |*args| return unless @blob
235
+ self.img_exit_blob
236
+ @pixbuf.delete_blob(@blob)
237
+ self.del_blob
238
+ @blob = nil
239
+ }
240
+ zoom_100_cb = proc { |widget, event|
241
+ win, x, y, state = @drw_area.window.pointer
242
+ width = @drw_area.allocation.width
243
+ height = @drw_area.allocation.height
244
+ if x >= 0 && x < width && y >= 0 && y < height
245
+ @scrl_win.window.cursor = Gdk::Cursor.new(
246
+ Gdk::Cursor::TARGET)
247
+ end
248
+ self.drw_area_in_procs = true
249
+ @spinbtn_x.value = 1
250
+ @spinbtn_y.value = 1
251
+ self.drw_area_in_procs = false
252
+ @scrl_win.window.cursor = nil }
253
+ zoom_fit_cb = proc { |widget, event|
254
+ if @pixbuf
255
+ win, x, y, state = @drw_area.window.pointer
256
+ width = @drw_area.allocation.width
257
+ height = @drw_area.allocation.height
258
+ if x >= 0 && x < width && y >= 0 && y < height
259
+ @scrl_win.window.cursor = Gdk::Cursor.new(
260
+ Gdk::Cursor::TARGET)
261
+ end
262
+ self.drw_area_in_procs = true
263
+ k = [Float(@scrl_win.allocation.width-10)/@pixbuf.width,
264
+ Float(@scrl_win.allocation.height-10)/@pixbuf.height].
265
+ min
266
+ @spinbtn_x.value = k
267
+ @spinbtn_y.value = k
268
+ self.drw_area_in_procs = false
269
+ @scrl_win.window.cursor = nil
270
+ end
271
+ }
272
+ zoom_in_cb = proc { |widget, event|
273
+ win, x, y, state = @drw_area.window.pointer
274
+ width = @drw_area.allocation.width
275
+ height = @drw_area.allocation.height
276
+ if x >= 0 && x < width && y >= 0 && y < height
277
+ @scrl_win.window.cursor = Gdk::Cursor.new(
278
+ Gdk::Cursor::TARGET)
279
+ end
280
+ self.drw_area_in_procs = true
281
+ @spinbtn_x.value = @kx*1.5
282
+ @spinbtn_y.value = @ky*1.5
283
+ self.drw_area_in_procs = false
284
+ @scrl_win.window.cursor = nil }
285
+ zoom_out_cb = proc { |wgt, ev|
286
+ win, x, y, state = @drw_area.window.pointer
287
+ width = @drw_area.allocation.width
288
+ height = @drw_area.allocation.height
289
+ if x >= 0 && x < width && y >= 0 && y < height
290
+ @scrl_win.window.cursor = Gdk::Cursor.new(
291
+ Gdk::Cursor::TARGET)
292
+ end
293
+ self.drw_area_in_procs = true
294
+ @spinbtn_x.value = @kx/1.5
295
+ @spinbtn_y.value = @ky/1.5
296
+ self.drw_area_in_procs = false
297
+ @scrl_win.window.cursor = nil }
298
+ item_factory = Gtk::ItemFactory.new(
299
+ Gtk::ItemFactory::TYPE_MENU_BAR, '<main>', accel_group)
300
+ item_factory.create_items([
301
+ ["/_File"],
302
+ ["/File/_Open ...", "<StockItem>", "<control>O",
303
+ Gtk::Stock::OPEN, open_cb],
304
+ ["/File/_Load blob ...", "<StockItem>", "<control>L",
305
+ Gtk::Stock::OPEN, load_blob_cb],
306
+ ["/File/_Save ...", "<StockItem>", "<control>S",
307
+ Gtk::Stock::SAVE, save_cb],
308
+ ["/File/sep1", "<Separator>", nil, nil],
309
+ ["/File/_Quit", "<StockItem>", "<control>Q",
310
+ Gtk::Stock::QUIT, quit_cb],
311
+ ["/_Edit"],
312
+ ["/Edit/_Select blob"],
313
+ ["/Edit/_Delete blob", "<StockItem>", "KP_Delete",
314
+ Gtk::Stock::DELETE, del_cb],
315
+ ["/Edit/Cont_ext menu ...", "<Item>", "<control>E",
316
+ nil, ctxt_cb],
317
+ ["/_View"],
318
+ ["/View/_Center selection", "<StockItem>", "c",
319
+ Gtk::Stock::FIND,
320
+ self.method('center_selection_cb').to_proc],
321
+ ["/View/Center _marked", "<StockItem>", "<control>M",
322
+ Gtk::Stock::FIND,self.method('center_objs_cb').to_proc,
323
+ @pixbuf_marked_objs],
324
+ ["/View/Center _blinking", "<StockItem>", "<control>B",
325
+ Gtk::Stock::FIND,self.method('center_objs_cb').to_proc,
326
+ @pixbuf_blinking_objs],
327
+ ["/View/Center _traced", "<StockItem>", "<control>T",
328
+ Gtk::Stock::FIND,self.method('center_objs_cb').to_proc,
329
+ @pixbuf_traced_objs],
330
+ ["/View/Zoom _100", "<StockItem>", "equal",
331
+ Gtk::Stock::ZOOM_100, zoom_100_cb],
332
+ ["/View/Zoom _fit", "<StockItem>", "asterisk",
333
+ Gtk::Stock::ZOOM_FIT, zoom_fit_cb],
334
+ ["/View/Zoom _in", "<StockItem>", "plus",
335
+ Gtk::Stock::ZOOM_IN, zoom_in_cb],
336
+ ["/View/Zoom _out", "<StockItem>", "minus",
337
+ Gtk::Stock::ZOOM_OUT, zoom_out_cb],
338
+ ["/_Help"],
339
+ ["/Help/_About", "<StockItem>", nil, Gtk::Stock::ABOUT,
340
+ self.method("about_cb").to_proc],
341
+ ])
342
+ @select_blob_menu_branch = item_factory.get_widget(
343
+ '<main>/Edit').children.first
344
+ table.attach(item_factory.get_widget('<main>'),
345
+ # X direction # Y direction
346
+ 0, 1, 0, 1,
347
+ Gtk::EXPAND | Gtk::FILL, 0,
348
+ 0, 0)
349
+
350
+ # Toolbars:
351
+ tooltips = Gtk::Tooltips.new
352
+ tb_box = Gtk::HBox.new(false, 3)
353
+ toolbar = PGtk::Toolbar.new
354
+ toolbar.append(Gtk::Stock::OPEN,
355
+ "Open image file for curve recognition (^O)", &open_cb)
356
+ toolbar.append(Gtk::Stock::SAVE,
357
+ "Save all marked, blinking and traced image objects to a " +
358
+ "file (^S)",
359
+ &save_cb)
360
+ #toolbar.append(Gtk::Stock::CANCEL,
361
+ # "Cancel the last started operation (^C)", &cancel_cb)
362
+ toolbar.append_space
363
+ toolbar.append(Gtk::Stock::QUIT, "Quit program (^Q)", &quit_cb)
364
+ tb_box.pack_start(toolbar, false, false)
365
+ # Options toolbar:
366
+ subtb = PGtk::Toolbar.new
367
+ subtb.dir_size_request = 400
368
+ tb_box.pack_start(subtb, true, true)
369
+ # Trace delay:
370
+ vbox = Gtk::VBox.new(true, 1)
371
+ subtb.append(vbox, "Time in miliseconds between the display " +
372
+ "of two subsequent pixels in an image object when " +
373
+ "tracing.", nil)
374
+ label = Gtk::Label.new("Trace delay:")
375
+ vbox.pack_start(label, false, false)
376
+ @trace_delay_adj = Gtk::Adjustment.new(@pix_trace_tm_out, 10.0,
377
+ 100000.0, 1.0, 50.0, 50.0)
378
+ @trace_delay_spinbtn = Gtk::SpinButton.new(@trace_delay_adj,0,0)
379
+ tooltips.set_tip(@trace_delay_spinbtn, "Time in miliseconds " +
380
+ "spent by the tracing pixel at a given pixel position "+
381
+ "before moving to the next one when tracing an image " +
382
+ "object.", nil)
383
+ @trace_delay_adj.signal_connect("value_changed") { |wgt, ev|
384
+ self.pix_trace_tm_out=@trace_delay_spinbtn.value }
385
+ vbox.pack_start(@trace_delay_spinbtn, false, false)
386
+ # Compare pixel color to:
387
+ cmp_pix_clr_to_cb = proc { |data, wgt|
388
+ @cmp_pix_to = Gtk::ItemFactory.path_from_widget(wgt)
389
+ @cmp_pix_to[0, '<cmp_to>/'.length] = ''
390
+ if @cmp_pix_to == 'Blob mean color in circle; R='
391
+ @cmp_pix_hbox.pack_start(
392
+ @pix_cmp_circ_r_spinbtn)
393
+ else
394
+ @cmp_pix_hbox.remove(@pix_cmp_circ_r_spinbtn)
395
+ end
396
+ }
397
+ vbox = Gtk::VBox.new(true, 1)
398
+ subtb.append_space
399
+ subtb.append(vbox)
400
+ label = Gtk::Label.new("Compare matched pixel's color to:")
401
+ vbox.pack_start(label, true, true, 0)
402
+ @cmp_pix_hbox = Gtk::HBox.new(false, 0)
403
+ vbox.pack_start(@cmp_pix_hbox, true, true, 0)
404
+ optmenu = Gtk::OptionMenu.new
405
+ item_factory = Gtk::ItemFactory.new(Gtk::ItemFactory::TYPE_MENU,
406
+ '<cmp_to>', accel_group)
407
+ item_factory.create_items([
408
+ ['/'+(@cmp_pix_to="Blob 8 neighbors' colors"), "<Item>",
409
+ nil, nil, cmp_pix_clr_to_cb],
410
+ ["/Blob 4 neighbors' colors", "<Item>", nil, nil,
411
+ cmp_pix_clr_to_cb],
412
+ ["/Blob mean color", "<Item>", nil, nil,
413
+ cmp_pix_clr_to_cb],
414
+ ["/Blob mean color in circle; R=", "<Item>", nil, nil,
415
+ cmp_pix_clr_to_cb],
416
+ ])
417
+ optmenu.menu = item_factory.get_widget('<cmp_to>')
418
+ @cmp_pix_hbox.pack_start(optmenu, false, false, 0)
419
+ adj = Gtk::Adjustment.new(1.0,1.0,1e6,1.0,10.0,1.0)
420
+ @pix_cmp_circ_r_spinbtn = Gtk::SpinButton.new(adj, 0, 0)
421
+ @cmp_pix_hbox.pack_start(@pix_cmp_circ_r_spinbtn,false,false,0)
422
+ # Color match tolerance:
423
+ match_clr_scheme_cb = proc { |data, wgt|
424
+ if Gtk::ItemFactory.path_from_widget(wgt).ends_with(
425
+ "RGB")
426
+ return if @clr_match_scheme == "rgb"
427
+ @clr_match_scheme = "rgb"
428
+ @clr_match_vbox.remove(@hsv_item_box)
429
+ @clr_match_vbox.pack_start(@rgb_item_box)
430
+ else
431
+ return if @clr_match_scheme == "hsv"
432
+ @clr_match_scheme = "hsv"
433
+ @clr_match_vbox.remove(@rgb_item_box)
434
+ @clr_match_vbox.pack_start(@hsv_item_box)
435
+ end
436
+ }
437
+ @clr_match_vbox = Gtk::VBox.new(true, 1)
438
+ label = Gtk::Label.new("Color matching tolerance:")
439
+ @clr_match_vbox.pack_start(label)
440
+ optmenu = Gtk::OptionMenu.new
441
+ item_factory = Gtk::ItemFactory.new(Gtk::ItemFactory::TYPE_MENU,
442
+ '<clr_scheme>', accel_group)
443
+ item_factory.create_items([
444
+ ["/RGB", "<Item>", nil, nil, match_clr_scheme_cb],
445
+ ["/HSV", "<Item>", nil, nil, match_clr_scheme_cb],
446
+ ])
447
+ optmenu.menu = item_factory.get_widget('<clr_scheme>')
448
+ subtb.append_space
449
+ subtb.append(optmenu)
450
+ @rgb_item_box = Gtk::HBox.new(true, 2)
451
+ @clr_match_vbox.pack_start(@rgb_item_box, false, false)
452
+ #@clr_match_vbox.attach(@rgb_item_box, 0,1, 1,2, 0, 0, 0, 0)
453
+ subtb.append(@clr_match_vbox, nil, nil)
454
+ # Red:
455
+ hbox = Gtk::HBox.new(false, 1)
456
+ label = Gtk::Label.new("R:"); label.set_alignment(0, 0.5)
457
+ hbox.pack_start(label, false, false)
458
+ @fuzzy_clr_adj_r=Gtk::Adjustment.new(@fuzzy_clr_r, 0.0, 255.0,
459
+ 1.0, 10.0, 1.0)
460
+ @fuzzy_clr_spinbtn_r = Gtk::SpinButton.new(@fuzzy_clr_adj_r,0,0)
461
+ tooltips.set_tip(@fuzzy_clr_spinbtn_r, ttip="When identifying "+
462
+ "a blob, match adjacent pixels whose color components "+
463
+ "differ not more than these settings.", nil)
464
+ @fuzzy_clr_adj_r.signal_connect("value_changed") { |wgt, ev|
465
+ @fuzzy_clr_r=@fuzzy_clr_spinbtn_r.value_as_int }
466
+ hbox.pack_start(@fuzzy_clr_spinbtn_r, false, false)
467
+ @rgb_item_box.pack_start(hbox)
468
+ # Green:
469
+ hbox = Gtk::HBox.new(false, 1)
470
+ label = Gtk::Label.new("G:"); label.set_alignment(0, 0.5)
471
+ hbox.pack_start(label, false, false)
472
+ @fuzzy_clr_adj_g=Gtk::Adjustment.new(@fuzzy_clr_g, 0.0, 255.0,
473
+ 1.0, 10.0, 1.0)
474
+ @fuzzy_clr_spinbtn_g = Gtk::SpinButton.new(@fuzzy_clr_adj_g,0,0)
475
+ tooltips.set_tip(@fuzzy_clr_spinbtn_g, ttip, nil)
476
+ @fuzzy_clr_adj_g.signal_connect("value_changed") { |wgt, ev|
477
+ @fuzzy_clr_g=@fuzzy_clr_spinbtn_g.value_as_int }
478
+ hbox.pack_start(@fuzzy_clr_spinbtn_g, false, false)
479
+ @rgb_item_box.pack_start(hbox)
480
+ # Blue:
481
+ hbox = Gtk::HBox.new(false, 1)
482
+ label = Gtk::Label.new("B:"); label.set_alignment(0, 0.5)
483
+ hbox.pack_start(label, false, false)
484
+ @fuzzy_clr_adj_b=Gtk::Adjustment.new(@fuzzy_clr_b, 0.0, 255.0,
485
+ 1.0, 10.0, 1.0)
486
+ @fuzzy_clr_spinbtn_b = Gtk::SpinButton.new(@fuzzy_clr_adj_b,0,0)
487
+ tooltips.set_tip(@fuzzy_clr_spinbtn_b, ttip, nil)
488
+ @fuzzy_clr_adj_b.signal_connect("value_changed") { |wgt, ev|
489
+ @fuzzy_clr_b=@fuzzy_clr_spinbtn_b.value_as_int }
490
+ hbox.pack_start(@fuzzy_clr_spinbtn_b, false, false)
491
+ @rgb_item_box.pack_start(hbox)
492
+ # Hue:
493
+ @hsv_item_box = Gtk::HBox.new(true, 2)
494
+ hbox = Gtk::HBox.new(false, 1)
495
+ label = Gtk::Label.new("H:"); label.set_alignment(0, 0.5)
496
+ hbox.pack_start(label, false, false)
497
+ @fuzzy_clr_adj_h=Gtk::Adjustment.new(0.0,0.0,360.0,1.0,10.0,1.0)
498
+ @fuzzy_clr_spinbtn_h = Gtk::SpinButton.new(@fuzzy_clr_adj_h,0,0)
499
+ tooltips.set_tip(@fuzzy_clr_spinbtn_h, ttip, nil)
500
+ @fuzzy_clr_adj_h.signal_connect("value_changed") { |wgt, ev|
501
+ @fuzzy_clr_h=@fuzzy_clr_spinbtn_h.value / 360.0 }
502
+ hbox.pack_start(@fuzzy_clr_spinbtn_h, false, false)
503
+ @hsv_item_box.pack_start(hbox)
504
+ # Saturation:
505
+ hbox = Gtk::HBox.new(false, 1)
506
+ label = Gtk::Label.new("S:"); label.set_alignment(0, 0.5)
507
+ hbox.pack_start(label, false, false)
508
+ @fuzzy_clr_adj_s=Gtk::Adjustment.new(0.0,0.0,100.0,1.0,10.0,1.0)
509
+ @fuzzy_clr_spinbtn_s = Gtk::SpinButton.new(@fuzzy_clr_adj_s,0,0)
510
+ tooltips.set_tip(@fuzzy_clr_spinbtn_s, ttip, nil)
511
+ @fuzzy_clr_adj_s.signal_connect("value_changed") { |wgt, ev|
512
+ @fuzzy_clr_s=@fuzzy_clr_spinbtn_s.value / 100.0 }
513
+ hbox.pack_start(@fuzzy_clr_spinbtn_s, false, false)
514
+ @hsv_item_box.pack_start(hbox)
515
+ # Value:
516
+ hbox = Gtk::HBox.new(false, 1)
517
+ label = Gtk::Label.new("V:"); label.set_alignment(0, 0.5)
518
+ hbox.pack_start(label, false, false)
519
+ @fuzzy_clr_adj_v=Gtk::Adjustment.new(0.0,0.0,100.0,1.0,10.0,1.0)
520
+ @fuzzy_clr_spinbtn_v = Gtk::SpinButton.new(@fuzzy_clr_adj_v,0,0)
521
+ tooltips.set_tip(@fuzzy_clr_spinbtn_v, ttip, nil)
522
+ @fuzzy_clr_adj_v.signal_connect("value_changed") { |wgt, ev|
523
+ @fuzzy_clr_v=@fuzzy_clr_spinbtn_v.value / 100.0 }
524
+ hbox.pack_start(@fuzzy_clr_spinbtn_v, false, false)
525
+ @hsv_item_box.pack_start(hbox)
526
+ @clr_match_vbox.pack_start(@hsv_item_box, false, false)
527
+ # Contour geometry:
528
+ ctr_geom_cb = proc { |data, wgt|
529
+ @contour_geometry = Gtk::ItemFactory.path_from_widget(
530
+ wgt)[-1,1].to_i
531
+ }
532
+ optmenu = Gtk::OptionMenu.new
533
+ item_factory = Gtk::ItemFactory.new(Gtk::ItemFactory::TYPE_MENU,
534
+ '<ctr_geom>', accel_group)
535
+ item_factory.create_items([
536
+ ["/8", "<Item>", nil, nil, ctr_geom_cb],
537
+ ["/4", "<Item>", nil, nil, ctr_geom_cb],
538
+ ])
539
+ optmenu.menu = item_factory.get_widget('<ctr_geom>')
540
+ hbox = Gtk::HBox.new(false, 1)
541
+ hbox.pack_start(Gtk::Label.new("Contour\ngeometry:"),true,true)
542
+ hbox.pack_start(optmenu)
543
+ subtb.append_space
544
+ subtb.append(hbox)
545
+ # External contours?
546
+ btn = Gtk::CheckButton.new("E_xternal\ncontours")
547
+ btn.active = @external_contours = true
548
+ subtb.append_space
549
+ subtb.append(btn)
550
+ btn.signal_connect('clicked') { |wgt|
551
+ @external_contours = wgt.active? }
552
+
553
+ # Min. subblob size, outer lp len, hair length, ...:
554
+ vbox = Gtk::VBox.new(true, 1)
555
+ subtb.append_space
556
+ subtb.append(vbox, nil, nil)
557
+ # Min. subblob size:
558
+ hbox = Gtk::HBox.new(false, 1)
559
+ #vbox.pack_start(hbox, false, false)
560
+ label = Gtk::Label.new("Min. subblob size:")
561
+ label.set_alignment(0.5, 0.5)
562
+ vbox.pack_start(label, false, false)
563
+ vbox.pack_start(hbox, false, false)
564
+ adj = Gtk::Adjustment.new(@min_subblob_size, 1.0, 1e12,
565
+ 1.0, 100.0, 0.0)
566
+ @min_subblob_size_spinbtn = Gtk::SpinButton.new(adj, 0, 0)
567
+ @min_subblob_size_spinbtn.set_snap_to_ticks(true)
568
+ tooltips.set_tip(@min_subblob_size_spinbtn, "Blobs surrounded "+
569
+ "by a blob in detection, containing less than these " +
570
+ "many pixels will be incorporated in the surronding " +
571
+ "blob.", nil)
572
+ hbox.pack_start(@min_subblob_size_spinbtn, false, false)
573
+ adj.signal_connect("value_changed") { |wgt, ev|
574
+ @min_subblob_size = @min_subblob_size_spinbtn.value.to_i
575
+ }
576
+ label = Gtk::Label.new("pix"); label.set_alignment(0, 0.5)
577
+ hbox.pack_start(label, false, false)
578
+ # Min. outer loop length:
579
+ vbox = Gtk::VBox.new(true, 1)
580
+ subtb.append_space
581
+ subtb.append(vbox, nil, nil)
582
+ label = Gtk::Label.new("Min. outer loop len.:")
583
+ label.set_alignment(0.5, 0.5)
584
+ vbox.pack_start(label, false, false)
585
+ hbox = Gtk::HBox.new(false, 1)
586
+ vbox.pack_start(hbox, false, false)
587
+ adj = Gtk::Adjustment.new(@min_outer_lp_length, 1.0, 1e12,
588
+ 1.0, 100.0, 0.0)
589
+ @min_outer_lp_length_spinbtn = Gtk::SpinButton.new(adj, 0, 0)
590
+ @min_outer_lp_length_spinbtn.set_snap_to_ticks(true)
591
+ tooltips.set_tip(@min_outer_lp_length_spinbtn, "Drop loops " +
592
+ "from a blob's outer contour carpet of length less " +
593
+ "than this one.", nil)
594
+ hbox.pack_start(@min_outer_lp_length_spinbtn, false, false)
595
+ adj.signal_connect("value_changed") { |wgt, ev|
596
+ @min_outer_lp_length =
597
+ @min_outer_lp_length_spinbtn.value.to_i
598
+ }
599
+ label = Gtk::Label.new("pix"); label.set_alignment(0, 0.5)
600
+ hbox.pack_start(label, false, false)
601
+ # Min. hair length:
602
+ vbox = Gtk::VBox.new(true, 1)
603
+ subtb.append_space
604
+ subtb.append(vbox, nil, nil)
605
+ hbox = Gtk::HBox.new(false, 1)
606
+ vbox.pack_start(hbox, true, true)
607
+ label = Gtk::Label.new("Min. hair length:")
608
+ label.set_alignment(0.5, 0.5)
609
+ hbox.pack_start(label, true, true)
610
+ hbox = Gtk::HBox.new(false, 1)
611
+ vbox.pack_start(hbox, false, false)
612
+ adj = Gtk::Adjustment.new(@min_hair_len, 0.0, 1e12,
613
+ 1.0, 100.0, 0.0)
614
+ @min_hair_len_spinbtn = Gtk::SpinButton.new(adj, 0, 0)
615
+ @min_hair_len_spinbtn.set_snap_to_ticks(false)
616
+ tooltips.set_tip(@min_hair_len_spinbtn, "Branches of the " +
617
+ "curve of length less than this one will be shaved " +
618
+ "off for curve's shaved core.", nil)
619
+ hbox.pack_start(@min_hair_len_spinbtn, false, false)
620
+ adj.signal_connect("value_changed") { |wgt, ev|
621
+ @min_hair_len = @min_hair_len_spinbtn.value }
622
+ label = Gtk::Label.new("pix")
623
+ label.set_alignment(0, 0.5)
624
+ hbox.pack_start(label, false, false)
625
+ # Min. hair loop length:
626
+ vbox = Gtk::VBox.new(true, 1)
627
+ subtb.append_space
628
+ subtb.append(vbox, nil, nil)
629
+ hbox = Gtk::HBox.new(false, 1)
630
+ vbox.pack_start(hbox, false, false)
631
+ label = Gtk::Label.new("Min. hair loop len.:")
632
+ label.set_alignment(0.5, 0.5)
633
+ hbox.pack_end(label, false, false)
634
+ hbox = Gtk::HBox.new(false, 1)
635
+ vbox.pack_start(hbox, false, false)
636
+ adj = Gtk::Adjustment.new(@min_hair_lp_len, 0.0, 1e12,
637
+ 1.0, 100.0, 0.0)
638
+ @min_hair_lp_len_spinbtn = Gtk::SpinButton.new(adj, 0, 0)
639
+ @min_hair_lp_len_spinbtn.set_snap_to_ticks(false)
640
+ tooltips.set_tip(@min_hair_lp_len_spinbtn, "Shortest loops of "+
641
+ "the curve of length less than this one will be " +
642
+ "deloopified for curve's shaved core.", nil)
643
+ hbox.pack_start(@min_hair_lp_len_spinbtn, false, false)
644
+ adj.signal_connect("value_changed") { |wgt, ev|
645
+ @min_hair_lp_len = @min_hair_lp_len_spinbtn.value }
646
+ label = Gtk::Label.new("pix")
647
+ label.set_alignment(0, 0.5)
648
+ hbox.pack_start(label, false, false)
649
+
650
+ table.attach(tb_box,
651
+ # X direction # Y direction
652
+ 0, 1, 1, 2,
653
+ Gtk::EXPAND | Gtk::FILL, 0,
654
+ 0, 0)
655
+
656
+ # Image display frame:
657
+ @scrl_win = Gtk::ScrolledWindow.new
658
+ @scrl_win.set_policy(Gtk::POLICY_AUTOMATIC,
659
+ Gtk::POLICY_AUTOMATIC)
660
+ @scrl_win.shadow_type = Gtk::SHADOW_IN
661
+ table.attach(@scrl_win,
662
+ # X direction # Y direction
663
+ 0, 1, 2, 3,
664
+ Gtk::EXPAND | Gtk::FILL, Gtk::EXPAND | Gtk::FILL,
665
+ 0, 0)
666
+ self.set_default_size(200, 200)
667
+ @drw_area = Gtk::DrawingArea.new
668
+ @scrl_win.add_with_viewport(@drw_area)
669
+ img_expose_cb = self.method("img_expose_cb").to_proc
670
+ img_motion_notify_cb=self.method("img_motion_notify_cb").to_proc
671
+ img_button_press_cb = self.method("img_button_press_cb").to_proc
672
+ @drw_area.signal_connect('expose_event', &img_expose_cb)
673
+ @drw_area.signal_connect('motion_notify_event',
674
+ &img_motion_notify_cb)
675
+ @drw_area.signal_connect('button_press_event',
676
+ &img_button_press_cb)
677
+ @drw_area.events |= Gdk::Event::LEAVE_NOTIFY_MASK |
678
+ Gdk::Event::BUTTON_PRESS_MASK |
679
+ Gdk::Event::POINTER_MOTION_MASK |
680
+ Gdk::Event::POINTER_MOTION_HINT_MASK
681
+ @scrl_win.hadjustment.signal_connect('value_changed',
682
+ &img_motion_notify_cb)
683
+ @scrl_win.vadjustment.signal_connect('value_changed',
684
+ &img_motion_notify_cb)
685
+
686
+ # x, y, kx, ky, statusbar:
687
+ bottom_box = Gtk::VBox.new(false, 3)
688
+ @progr_bar = Gtk::ProgressBar.new
689
+ @progr_label = Gtk::Label.new
690
+ @progr_bar_box = Gtk::HBox.new(false, 0)
691
+ @progr_bar_box.pack_start(@progr_bar)
692
+ @progr_bar_box.pack_start(@progr_label, false, false)
693
+ bottom_box.pack_start(@progr_bar_box)
694
+ hbox = Gtk::HBox.new(false, 3)
695
+ bottom_box.pack_start(hbox)
696
+ table.attach(bottom_box,
697
+ # X direction # Y direction
698
+ 0, 1, 3, 4,
699
+ Gtk::EXPAND | Gtk::FILL, 0,
700
+ 0, 0)
701
+
702
+ label = Gtk::Label.new("x="); label.set_alignment(1, 0.5)
703
+ hbox.pack_start(label, false, false)
704
+ @label_x = Gtk::Label.new; @label_x.set_alignment(0,0.5)
705
+ hbox.pack_start(@label_x,false,false)
706
+ label = Gtk::Label.new("y="); label.set_alignment(1, 0.5)
707
+ hbox.pack_start(label, false, false)
708
+ @label_y = Gtk::Label.new; @label_y.set_alignment(0,0.5)
709
+ hbox.pack_start(@label_y, false, false)
710
+
711
+ # kx:
712
+ label = Gtk::Label.new("kx=")
713
+ label.set_alignment(1, 0.5)
714
+ hbox.pack_start(label, false, false)
715
+ adj = Gtk::Adjustment.new(1.0, 1.0e-10, 1000.0, 1.0, 5.0, 1.0)
716
+ @spinbtn_x = Gtk::SpinButton.new(adj, 0, 3)
717
+ adj.signal_connect("value_changed") { |wgt, ev|
718
+ self.kx=@spinbtn_x.value }
719
+ hbox.pack_start(@spinbtn_x, false, false)
720
+ #@scrl_win.hadjustment.step_increment =
721
+ @kx = 1
722
+
723
+ # ky:
724
+ label = Gtk::Label.new("ky=")
725
+ label.set_alignment(1, 0.5)
726
+ hbox.pack_start(label, false, false)
727
+ adj = Gtk::Adjustment.new(1.0, 1.0e-10, 1000.0, 1.0, 5.0, 1.0)
728
+ @spinbtn_y = Gtk::SpinButton.new(adj, 0, 3)
729
+ adj.signal_connect("value_changed") { |wgt, ev|
730
+ self.ky=@spinbtn_y.value }
731
+ hbox.pack_start(@spinbtn_y, false, false)
732
+ #@scrl_win.vadjustment.step_increment =
733
+ @ky = 1
734
+
735
+ # RGB/HSV:
736
+ show_clr_scheme_cb = proc { |data, wgt|
737
+ if Gtk::ItemFactory.path_from_widget(wgt).ends_with(
738
+ "RGB:")
739
+ @clr_show_scheme = "rgb"
740
+ else
741
+ @clr_show_scheme = "hsv"
742
+ end
743
+ }
744
+ optmenu = Gtk::OptionMenu.new
745
+ item_factory = Gtk::ItemFactory.new(Gtk::ItemFactory::TYPE_MENU,
746
+ '<clr_scheme>', accel_group)
747
+ item_factory.create_items([
748
+ ["/RGB:","<Item>","<control>R",nil,show_clr_scheme_cb],
749
+ ["/HSV:","<Item>","<control>H",nil,show_clr_scheme_cb],
750
+ ])
751
+ optmenu.menu = item_factory.get_widget('<clr_scheme>')
752
+ hbox.pack_start(optmenu, false, false)
753
+ @label_clr = Gtk::Label.new
754
+ @label_clr.width_chars = 11
755
+ @label_clr.set_alignment(0, 0.5)
756
+ hbox.pack_start(@label_clr,false,false)
757
+
758
+ # Statusbar:
759
+ @statusbar = Gtk::Statusbar.new
760
+ hbox.pack_start(@statusbar, true, true)
761
+
762
+ # Timeout:
763
+ @prev_traced_x = @prev_traced_y = 0
764
+ @pix_trace_proc = proc {
765
+ tx = @prev_traced_x*@kx; ty = @prev_traced_y*@ky
766
+ if @kx >= @trace_mark.width
767
+ tw = @kx.ceil
768
+ else
769
+ tw = @trace_mark.width
770
+ tx = tx + @kx/2.0 - tw/2.0
771
+ end
772
+ if @ky >= @trace_mark.height
773
+ th = @ky.ceil
774
+ else
775
+ th = @trace_mark.height
776
+ ty = ty + @ky/2.0 - th/2.0
777
+ end
778
+ @drw_area.window.invalidate(Gdk::Rectangle.new(tx, ty,
779
+ tw+1, th+1), false)
780
+ if (obj = @pixbuf_traced_objs[@pixbuf_traced_obj_i])
781
+ if (@pixbuf_traced_pix_i+=1) >= obj.length
782
+ if (@pixbuf_traced_obj_i += 1) >=
783
+ @pixbuf_traced_objs.length
784
+ @pixbuf_traced_obj_i = 0
785
+ end
786
+ @pixbuf_traced_pix_i = 0
787
+ end
788
+ else
789
+ @pixbuf_traced_obj_i = 0
790
+ @pixbuf_traced_pix_i = 0
791
+ end
792
+ if (obj = @pixbuf_traced_objs[@pixbuf_traced_obj_i]) &&
793
+ (pix = obj[@pixbuf_traced_pix_i])
794
+ @prev_traced_x = pix.x + @pixbuf.border_width
795
+ @prev_traced_y = pix.y + @pixbuf.border_width
796
+ tx = @prev_traced_x*@kx; ty = @prev_traced_y*@ky
797
+ if @kx >= @trace_mark.width
798
+ tw = @kx.ceil
799
+ else
800
+ tw = @trace_mark.width
801
+ tx = tx + @kx/2.0 - tw/2.0
802
+ end
803
+ if @ky >= @trace_mark.height
804
+ th = @ky.ceil
805
+ else
806
+ th = @trace_mark.height
807
+ ty = ty + @ky/2.0 - th/2.0
808
+ end
809
+ @drw_area.window.invalidate(Gdk::Rectangle.new(
810
+ tx, ty, tw+1, th+1), false)
811
+ end
812
+ true
813
+ }
814
+ self.add_timeouts
815
+
816
+ signal_connect('destroy'){ self.remove_timeouts; Gtk.main_quit }
817
+
818
+ self.show_all
819
+ Gtk.main_iteration
820
+ @cmp_pix_hbox.remove(@pix_cmp_circ_r_spinbtn)
821
+ @clr_match_vbox.remove(@hsv_item_box)
822
+ @progr_bar_box.remove(@progr_label)
823
+ @progr_bar_box.remove(@progr_bar)
824
+ subtb.hide
825
+ Gtk.main_iteration
826
+ if $VERBOSE || $DEBUG
827
+ tee_to = $stdout
828
+ else
829
+ tee_to = nil
830
+ end
831
+ #$PDbgLog.outp = StatusbarIO.new($PDbgLog, @statusbar, tee_to)
832
+ $PDbgLog.progr_class = ECLogProgrBar
833
+ $PDbgLog.progr_init_args = [@progr_bar, @progr_label,
834
+ @progr_bar_box]
835
+ end
836
+
837
+ def add_timeouts
838
+ #$PDbgLog.sig_call(self)
839
+ #$PDbgLog.puts_msg caller(1).join("\t\n")
840
+ unless @blink_timeout_id
841
+ t = Gdk::Screen.default.get_setting("gtk-cursor-blink-time")
842
+ @blink_timeout_id = Gtk.timeout_add(t ? t.to_i : 1000) {
843
+ #return true if @job && @job.alive?
844
+ if @pixbuf_blinking
845
+ if @pixbuf_backing.equal?(@pixbuf_blinking)
846
+ @pixbuf_backing = @pixbuf_marked
847
+ else
848
+ @pixbuf_backing = @pixbuf_blinking
849
+ end
850
+ @drw_area.window.invalidate(@blink_area_rect,
851
+ false) if @blink_area_rect
852
+ end
853
+ true
854
+ }
855
+ end
856
+ unless @pix_trace_timeout_id
857
+ @pix_trace_timeout_id = Gtk.timeout_add(@pix_trace_tm_out,
858
+ &@pix_trace_proc)
859
+ end
860
+ #$PDbgLog.sig_return("Done.")
861
+ end
862
+
863
+ def remove_timeouts
864
+ #$PDbgLog.sig_call(self)
865
+ #$PDbgLog.puts_msg caller(1).join("\t\n")
866
+ if @blink_timeout_id
867
+ Gtk.timeout_remove(@blink_timeout_id)
868
+ @blink_timeout_id = nil
869
+ end
870
+ if @pix_trace_timeout_id
871
+ Gtk.timeout_remove(@pix_trace_timeout_id)
872
+ @pix_trace_timeout_id = nil
873
+ end
874
+ #$PDbgLog.sig_return("Done.")
875
+ end
876
+
877
+ def show_exc_dialog
878
+ dialog = Gtk::MessageDialog.new(self,
879
+ Gtk::Dialog::MODAL | Gtk::Dialog::DESTROY_WITH_PARENT,
880
+ Gtk::MessageDialog::ERROR,
881
+ Gtk::MessageDialog::BUTTONS_CLOSE)
882
+ dialog.title = $!.class.name
883
+ dialog.markup = "<b>#{$!.class.name}:</b> <b><i>#{$!.to_s}</i></b>\n\tfrom #{$!.backtrace.join("\n\tfrom ")}"
884
+ dialog.run
885
+ dialog.destroy
886
+ end
887
+
888
+ def drw_area_in_procs=(val)
889
+ if val
890
+ return if @drw_area_in_procs
891
+ @drw_area_in_procs = true
892
+ @scrl_win.freeze_child_notify
893
+ else
894
+ return unless @drw_area_in_procs
895
+ @drw_area_in_procs = false
896
+ @scrl_win.thaw_child_notify
897
+ @drw_area.queue_draw
898
+ end
899
+ end
900
+
901
+ def pixbuf=(val)
902
+ @pixbuf_backing = @pixbuf_marked = @pixbuf_blinking = nil
903
+ @pixbuf = val
904
+ if @pixbuf.bits_per_sample != 8
905
+ raise NotImplementError,
906
+ "pixbuf with #{@pixbuf.bits_per_sample} bits/sample"
907
+ end
908
+ if @pixbuf.n_channels == 3
909
+ @pixbuf_drw_meth = Gdk::RGB.method("draw_rgb_image")
910
+ elsif @pixbuf.n_channels == 4
911
+ @pixbuf_drw_meth = Gdk::RGB.method("draw_rgb_32_image")
912
+ else
913
+ raise NotImplementError,
914
+ "pixbuf with #{@pixbuf.n_channels} channels"
915
+ end
916
+ @pixbuf = @pixbuf.add_border(1)
917
+ @pixbuf_blinking = nil
918
+ @pixbuf_backing = @pixbuf_marked = @pixbuf.dup
919
+ @blob = nil
920
+ @blink_area_rect = nil
921
+ @pixbuf_marked_objs.clear
922
+ @pixbuf_blinking_objs.clear
923
+ @pixbuf_traced_objs.clear
924
+ @drw_area.set_size_request(@pixbuf.width*@kx,@pixbuf.height*@ky)
925
+ @scrl_win.queue_draw
926
+ @label_x.width_chars = @pixbuf.width.to_s.length
927
+ @label_y.width_chars = @pixbuf.height.to_s.length
928
+ end
929
+
930
+ def kx=(val)
931
+ return if val == @kx
932
+ #@scrl_win.hadjustment.step_increment =
933
+ dx = val - @kx
934
+ @kx = val
935
+ return unless @pixbuf
936
+ if @blink_area
937
+ @blink_area_rect = Gdk::Rectangle.new(
938
+ (@blink_area.x + @pixbuf.border_width)*@kx,
939
+ (@blink_area.y + @pixbuf.border_width)*@ky,
940
+ (@blink_area.width*@kx).ceil + 1,
941
+ (@blink_area.height*@ky).ceil + 1)
942
+ end
943
+ win, x, y, state = *@drw_area.window.pointer
944
+ @drw_area.set_size_request(@pixbuf.width*@kx,@pixbuf.height*@ky)
945
+ viewport = @scrl_win.children[0]
946
+ win, vx, vy, state = viewport.window.pointer
947
+ width = viewport.allocation.width
948
+ height = viewport.allocation.height
949
+ if @drw_area.allocation.width > width
950
+ if vx >= 0 && vx < width && vy >= 0 && vy < height
951
+ viewport.hadjustment.value += x*dx / (@kx-dx)
952
+ else
953
+ k_x = viewport.hadjustment.value + width/2
954
+ viewport.hadjustment.value += k_x*dx / (@kx-dx)
955
+ end
956
+ end
957
+ @scrl_win.queue_draw
958
+ end
959
+
960
+ def ky=(val)
961
+ return if val == @ky
962
+ #@scrl_win.vadjustment.step_increment =
963
+ dy = val - @ky
964
+ @ky = val
965
+ return unless @pixbuf
966
+ if @blink_area
967
+ @blink_area_rect = Gdk::Rectangle.new(
968
+ (@blink_area.x + @pixbuf.border_width)*@kx,
969
+ (@blink_area.y + @pixbuf.border_width)*@ky,
970
+ (@blink_area.width*@kx).ceil + 1,
971
+ (@blink_area.height*@ky).ceil + 1)
972
+ end
973
+ win, x, y, state = *@drw_area.window.pointer
974
+ @drw_area.set_size_request(@pixbuf.width*@kx,@pixbuf.height*@ky)
975
+ viewport = @scrl_win.children[0]
976
+ win, vx, vy, state = viewport.window.pointer
977
+ width = viewport.allocation.width
978
+ height = viewport.allocation.height
979
+ if @drw_area.allocation.height > height
980
+ if vx >= 0 && vx < width && vy >= 0 && vy < height
981
+ viewport.vadjustment.value += y*dy / (@ky-dy)
982
+ else
983
+ k_y = viewport.vadjustment.value + height/2
984
+ viewport.vadjustment.value += k_y*dy / (@ky-dy)
985
+ end
986
+ end
987
+ @scrl_win.queue_draw
988
+ end
989
+
990
+ def pix_trace_tm_out=(val)
991
+ return if val == @pix_trace_tm_out
992
+ @pix_trace_tm_out = val
993
+ if @pix_trace_timeout_id
994
+ Gtk.timeout_remove(@pix_trace_timeout_id)
995
+ @pix_trace_timeout_id = Gtk.timeout_add(
996
+ @pix_trace_tm_out, &@pix_trace_proc)
997
+ end
998
+ end
999
+
1000
+ def center_selection_cb(*args)
1001
+ min_x = min_y = 1.0/0.0
1002
+ max_x = max_y = 0
1003
+ pr = proc { |obj|
1004
+ min_x = obj.img_obj_min_ax.floor if
1005
+ obj.img_obj_min_ax.floor < min_x
1006
+ max_x = obj.img_obj_max_ax.ceil if
1007
+ obj.img_obj_max_ax.ceil > max_x
1008
+ min_y = obj.img_obj_min_ay.floor if
1009
+ obj.img_obj_min_ay.floor < min_y
1010
+ max_y = obj.img_obj_max_ay.ceil if
1011
+ obj.img_obj_max_ay.ceil > max_y
1012
+ }
1013
+ @pixbuf_marked_objs.each(&pr)
1014
+ @pixbuf_blinking_objs.each(&pr)
1015
+ @pixbuf_traced_objs.each(&pr)
1016
+ c_x = (min_x + max_x) * @kx / 2
1017
+ c_y = (min_y + max_y) * @ky / 2
1018
+ alloc = @scrl_win.children[0].allocation
1019
+ tmp = c_x - alloc.width/2
1020
+ @scrl_win.hadjustment.value = tmp > 0 ? tmp : 0
1021
+ tmp = c_y - alloc.height/2
1022
+ @scrl_win.vadjustment.value = tmp > 0 ? tmp : 0
1023
+ end
1024
+
1025
+ def center_objs_cb(objs, widget)
1026
+ min_x = min_y = 1.0/0.0
1027
+ max_x = max_y = 0
1028
+ objs.each { |obj|
1029
+ min_x = obj.img_obj_min_ax.floor if
1030
+ obj.img_obj_min_ax.floor < min_x
1031
+ max_x = obj.img_obj_max_ax.ceil if
1032
+ obj.img_obj_max_ax.ceil > max_x
1033
+ min_y = obj.img_obj_min_ay.floor if
1034
+ obj.img_obj_min_ay.floor < min_y
1035
+ max_y = obj.img_obj_max_ay.ceil if
1036
+ obj.img_obj_max_ay.ceil > max_y
1037
+ }
1038
+ c_x = (min_x + max_x) * @kx / 2
1039
+ c_y = (min_y + max_y) * @ky / 2
1040
+ alloc = @scrl_win.children[0].allocation
1041
+ tmp = c_x - alloc.width/2
1042
+ @scrl_win.hadjustment.value = tmp > 0 ? tmp : 0
1043
+ tmp = c_y - alloc.height/2
1044
+ @scrl_win.vadjustment.value = tmp > 0 ? tmp : 0
1045
+ end
1046
+
1047
+ def write_img_obj(file, obj)
1048
+ #$PDbgLog.sig_call(self)
1049
+ #$PDbgLog.puts_msg "file: #{file.inspect}, obj: #{obj}"
1050
+ obj.each { |pix|
1051
+ file.puts "#{pix.ax}\t#{pix.ay}"
1052
+ }
1053
+ #$PDbgLog.sig_return
1054
+ end
1055
+
1056
+ def open_imagef(fpath)
1057
+ begin
1058
+ self.pixbuf = PPix::Pixbuf.new(fpath)
1059
+ dir, name = *File.split(fpath)
1060
+ self.title = "#{name} #{@pixbuf.picture_width}x#{
1061
+ @pixbuf.picture_height} (#{dir}) -- Extract Curves"
1062
+ rescue IOError, Gdk::PixbufError
1063
+ self.show_exc_dialog
1064
+ end
1065
+ end
1066
+
1067
+ def load_blob_cb(*args)
1068
+ return false unless @pixbuf && @in_progr.try_lock
1069
+ dialog = Gtk::FileChooserDialog.new("Open blob", self,
1070
+ Gtk::FileChooser::ACTION_OPEN, "gnome-vfs",
1071
+ [Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_ACCEPT],
1072
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL])
1073
+ dialog.add_shortcut_folder("/tmp") if File.directory?("/tmp")
1074
+ fpath = nil
1075
+ resp = dialog.run
1076
+ fpath = dialog.filename
1077
+ dialog.destroy
1078
+ i = -1
1079
+ Gtk.main_iteration_do(false) while (i += 1) < 10 &&
1080
+ Gtk.events_pending?
1081
+ if resp != Gtk::Dialog::RESPONSE_ACCEPT || !fpath
1082
+ @in_progr.unlock
1083
+ return
1084
+ end
1085
+ begin
1086
+ File.open(fpath, 'r') { |f|
1087
+ blob = nil
1088
+ FloatsInp.new(f).each_rec { |rec| x, y = *rec
1089
+ x = x.to_i; y = y.to_i
1090
+ next unless x >= 0 && x<@pixbuf.picture_width &&
1091
+ y >= 0 && y < @pixbuf.picture_height &&
1092
+ @pixbuf.blob_id_at?(x, y, 0)
1093
+ unless blob
1094
+ blob_id = @pixbuf.add_blob(blob =
1095
+ PPix::Blob.new(@pixbuf,
1096
+ @contour_geometry,
1097
+ @external_contours,
1098
+ @min_outer_lp_length))
1099
+ blob.blob_id = blob_id
1100
+ end
1101
+ blob.add(@pixbuf.get_pix(x, y))
1102
+ }
1103
+ if blob
1104
+ self.img_exit_blob
1105
+ @blob = blob
1106
+ @blob.extract_curves_args =
1107
+ {'extract_curves' => self,
1108
+ 'ctxt_menu_known_objs' => Set.new}
1109
+ self.img_enter_blob
1110
+ self.add_blob
1111
+ end
1112
+ }
1113
+ rescue IOError
1114
+ self.show_exc_dialog
1115
+ ensure
1116
+ @in_progr.unlock
1117
+ end
1118
+ end
1119
+
1120
+ def open_cb(*args)
1121
+ return false unless @in_progr.try_lock
1122
+ dialog = Gtk::FileChooserDialog.new(
1123
+ "Open raster image file for curve extraction", nil,
1124
+ Gtk::FileChooser::ACTION_OPEN, "gnome-vfs",
1125
+ [Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_ACCEPT],
1126
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL])
1127
+
1128
+ # Filters:
1129
+ filters = []
1130
+ filter_any = Gtk::FileFilter.new
1131
+ filter_any.name = "Recognized Images"
1132
+ filter_any.add_pixbuf_formats
1133
+ filter = Gtk::FileFilter.new; filter.name = "JPEG"
1134
+ filter.add_pattern(pat="*.jpg"); filter_any.add_pattern(pat)
1135
+ filter.add_pattern(pat="*.JPG"); filter_any.add_pattern(pat)
1136
+ filter.add_pattern(pat="*.jpeg"); filter_any.add_pattern(pat)
1137
+ filter.add_pattern(pat="*.JPEG"); filter_any.add_pattern(pat)
1138
+ filters << filter
1139
+ filter = Gtk::FileFilter.new; filter.name = "GIF"
1140
+ filter.add_pattern(pat="*.gif"); filter_any.add_pattern(pat)
1141
+ filter.add_pattern(pat="*.GIF"); filter_any.add_pattern(pat)
1142
+ filters << filter
1143
+ filter = Gtk::FileFilter.new; filter.name = "BitMap"
1144
+ filter.add_pattern(pat="*.bmp"); filter_any.add_pattern(pat)
1145
+ filter.add_pattern(pat="*.BMP"); filter_any.add_pattern(pat)
1146
+ filters << filter
1147
+ filter = Gtk::FileFilter.new; filter.name = "Portable PixMap"
1148
+ filter.add_pattern(pat="*.ppm"); filter_any.add_pattern(pat)
1149
+ filter.add_pattern(pat="*.PPM"); filter_any.add_pattern(pat)
1150
+ filters << filter
1151
+ filter = Gtk::FileFilter.new
1152
+ filter.name = "Portable Network Graphics"
1153
+ filter.add_pattern(pat="*.png"); filter_any.add_pattern(pat)
1154
+ filter.add_pattern(pat="*.PNG"); filter_any.add_pattern(pat)
1155
+ filters << filter
1156
+ dialog.add_filter(filter_any)
1157
+ filter = Gtk::FileFilter.new; filter.name = "All files"
1158
+ filter.add_pattern("*")
1159
+ dialog.add_filter(filter)
1160
+ filters.each { |f| dialog.add_filter(f) }
1161
+
1162
+ dialog.add_shortcut_folder("/tmp") if File.directory?("/tmp")
1163
+ fpath = nil
1164
+ resp = dialog.run
1165
+ fpath = dialog.filename
1166
+ dialog.destroy
1167
+ i = -1
1168
+ Gtk.main_iteration_do(false) while (i += 1) < 10 &&
1169
+ Gtk.events_pending?
1170
+ if resp != Gtk::Dialog::RESPONSE_ACCEPT || !fpath
1171
+ @in_progr.unlock
1172
+ return
1173
+ end
1174
+ begin
1175
+ self.open_imagef(fpath)
1176
+ ensure
1177
+ @in_progr.unlock
1178
+ end
1179
+ end
1180
+
1181
+ def arr_del_obj(arr, which)
1182
+ #$PDbgLog.sig_call(self)
1183
+ obj_i = nil
1184
+ arr.each_with_index { |obj, idx|
1185
+ #$PDbgLog.print_msg " obj#{idx}:%x" % obj.object_id
1186
+ if obj.equal?(which)
1187
+ obj_i = idx
1188
+ break
1189
+ end
1190
+ }
1191
+ if obj_i
1192
+ #$PDbgLog.print_msg "; obj_i=#{obj_i}"
1193
+ arr[obj_i,1] = nil
1194
+ else
1195
+ warn "#{self.class.name}.arr_del_obj: Image object "+
1196
+ "to remove not found!"
1197
+ end
1198
+ #$PDbgLog.sig_return
1199
+ end
1200
+
1201
+ def xy_toggle_buf(buf, x, y, pix_done, rowstride, pix_length)
1202
+ unless pix_done[k=[y, x]]
1203
+ s = @pixbuf.ofs0 + y*rowstride + x*pix_length
1204
+ s.upto(s + pix_length - 1) { |i|
1205
+ buf[i] ^= 0xff
1206
+ }
1207
+ pix_done[k] = true
1208
+ end
1209
+ end
1210
+
1211
+ def xy_toggle_2bufs(buf1, buf2, x, y, pix_done, rowstride, pix_length)
1212
+ unless pix_done[k=[y, x]]
1213
+ s = @pixbuf.ofs0 + y*rowstride + x*pix_length
1214
+ s.upto(s + pix_length - 1) { |i|
1215
+ buf1[i] ^= 0xff
1216
+ buf2[i] ^= 0xff
1217
+ }
1218
+ pix_done[k] = true
1219
+ end
1220
+ end
1221
+
1222
+ def pixels_mark_toggle(which)
1223
+ #$PDbgLog.sig_call(self)
1224
+ #$PDbgLog.puts_msg("#{which.length} pixel#{
1225
+ # which.length==1? "" : "s"}")
1226
+ pix_done = {}
1227
+ rowstride = @pixbuf.rowstride; pix_length = @pixbuf.pix_length
1228
+ marked_pix = @pixbuf_marked.pixels
1229
+ if @pixbuf_blinking
1230
+ blinking_pix = @pixbuf_blinking.pixels
1231
+ which.each { |pt| ax, ay = pt.ax, pt.ay
1232
+ x1 = ax.floor; y1 = ay.floor
1233
+ x2 = ax.ceil; y2 = ay.ceil
1234
+ self.xy_toggle_2bufs(marked_pix, blinking_pix,
1235
+ x1, y1, pix_done, rowstride, pix_length)
1236
+ if x1 != x2
1237
+ if y1 != y2
1238
+ self.xy_toggle_2bufs(marked_pix,
1239
+ blinking_pix, x2, y1, pix_done,
1240
+ rowstride, pix_length)
1241
+ self.xy_toggle_2bufs(marked_pix,
1242
+ blinking_pix, x1, y2, pix_done,
1243
+ rowstride, pix_length)
1244
+ self.xy_toggle_2bufs(marked_pix,
1245
+ blinking_pix, x2, y2, pix_done,
1246
+ rowstride, pix_length)
1247
+ else
1248
+ self.xy_toggle_2bufs(marked_pix,
1249
+ blinking_pix, x2, y1, pix_done,
1250
+ rowstride, pix_length)
1251
+ end
1252
+ elsif y1 != y2
1253
+ self.xy_toggle_2bufs(marked_pix,
1254
+ blinking_pix, x1, y2, pix_done,
1255
+ rowstride, pix_length)
1256
+ end
1257
+ }
1258
+ else
1259
+ which.each { |pt| ax, ay = pt.ax, pt.ay
1260
+ x1 = ax.floor; y1 = ay.floor
1261
+ x2 = ax.ceil; y2 = ay.ceil
1262
+ self.xy_toggle_buf(marked_pix, x1, y1, pix_done,
1263
+ rowstride, pix_length)
1264
+ if x1 != x2
1265
+ if y1 != y2
1266
+ self.xy_toggle_buf(marked_pix, x2, y1,
1267
+ pix_done, rowstride, pix_length)
1268
+ self.xy_toggle_buf(marked_pix, x1, y2,
1269
+ pix_done, rowstride, pix_length)
1270
+ self.xy_toggle_buf(marked_pix, x2, y2,
1271
+ pix_done, rowstride, pix_length)
1272
+ else
1273
+ self.xy_toggle_buf(marked_pix, x2, y1,
1274
+ pix_done, rowstride, pix_length)
1275
+ end
1276
+ elsif y1 != y2
1277
+ self.xy_toggle_buf(marked_pix, x1, y2,
1278
+ pix_done, rowstride, pix_length)
1279
+ end
1280
+ }
1281
+ end
1282
+ @drw_area.window.invalidate(Gdk::Rectangle.new(
1283
+ (which.img_obj_min_ax.floor+@pixbuf.border_width)*@kx,
1284
+ (which.img_obj_min_ay.floor+@pixbuf.border_width)*@ky,
1285
+ (which.img_obj_max_ax.ceil+1-which.img_obj_min_x) *@kx,
1286
+ (which.img_obj_max_ay.ceil+1-which.img_obj_min_y) *@ky),
1287
+ false)
1288
+ #$PDbgLog.sig_return
1289
+ end
1290
+
1291
+ def pixels_blink_toggle(which)
1292
+ unless @pixbuf_blinking
1293
+ @pixbuf_blinking = @pixbuf_marked.dup
1294
+ end
1295
+ pix_done = {}
1296
+ rowstride = @pixbuf.rowstride; pix_length = @pixbuf.pix_length
1297
+ blinking_pix = @pixbuf_blinking.pixels
1298
+ which.each { |pt| ax, ay = pt.ax, pt.ay
1299
+ x1 = ax.floor; y1 = ay.floor
1300
+ x2 = ax.ceil; y2 = ay.ceil
1301
+ self.xy_toggle_buf(blinking_pix, x1, y1, pix_done,
1302
+ rowstride, pix_length)
1303
+ if x1 != x2
1304
+ if y1 != y2
1305
+ self.xy_toggle_buf(blinking_pix, x2, y1,
1306
+ pix_done, rowstride, pix_length)
1307
+ self.xy_toggle_buf(blinking_pix, x1, y2,
1308
+ pix_done, rowstride, pix_length)
1309
+ self.xy_toggle_buf(blinking_pix, x2, y2,
1310
+ pix_done, rowstride, pix_length)
1311
+ else
1312
+ self.xy_toggle_buf(blinking_pix, x2, y1,
1313
+ pix_done, rowstride, pix_length)
1314
+ end
1315
+ elsif y1 != y2
1316
+ self.xy_toggle_buf(blinking_pix, x1, y2,
1317
+ pix_done, rowstride, pix_length)
1318
+ end
1319
+ }
1320
+ @drw_area.window.invalidate(Gdk::Rectangle.new(
1321
+ (which.img_obj_min_ax.floor+@pixbuf.border_width)*@kx,
1322
+ (which.img_obj_min_ay.floor+@pixbuf.border_width)*@ky,
1323
+ 1+((which.img_obj_max_ax.ceil+1-which.img_obj_min_x)*@kx).ceil,
1324
+ 1+((which.img_obj_max_ay.ceil+1-which.img_obj_min_y)*@ky).ceil),
1325
+ false)
1326
+ end
1327
+
1328
+ def pixels_mark(which)
1329
+ self.pixels_mark_toggle(which)
1330
+ @pixbuf_marked_objs.push(which)
1331
+ end
1332
+
1333
+ def pixels_unmark(which)
1334
+ self.pixels_mark_toggle(which)
1335
+ self.arr_del_obj(@pixbuf_marked_objs, which)
1336
+ end
1337
+
1338
+ def pixels_blink(which)
1339
+ self.pixels_blink_toggle(which)
1340
+ @pixbuf_blinking_objs.push(which)
1341
+ return if which.empty?
1342
+ @blink_area = Gdk::Rectangle.new(
1343
+ which.first.x, which.first.y, 0, 0) unless @blink_area
1344
+ end_x = [@blink_area.x + @blink_area.width-1,
1345
+ which.img_obj_max_ax.ceil].max
1346
+ end_y = [@blink_area.y + @blink_area.height-1,
1347
+ which.img_obj_max_ay.ceil].max
1348
+ @blink_area.x = [@blink_area.x, which.img_obj_min_ax.floor].min
1349
+ @blink_area.y = [@blink_area.y, which.img_obj_min_ay.floor].min
1350
+ @blink_area.width = end_x - @blink_area.x + 1
1351
+ @blink_area.height = end_y - @blink_area.y + 1
1352
+ if @blink_area_rect
1353
+ @blink_area_rect.x =
1354
+ (@blink_area.x + @pixbuf.border_width)*@kx
1355
+ @blink_area_rect.width = (@blink_area.width*@kx).ceil+1
1356
+ @blink_area_rect.y =
1357
+ (@blink_area.y + @pixbuf.border_width)*@ky
1358
+ @blink_area_rect.height =(@blink_area.height*@ky).ceil+1
1359
+ else
1360
+ @blink_area_rect = Gdk::Rectangle.new(
1361
+ (@blink_area.x + @pixbuf.border_width)*@kx,
1362
+ (@blink_area.y + @pixbuf.border_width)*@ky,
1363
+ (@blink_area.width*@kx).ceil + 1,
1364
+ (@blink_area.height*@ky).ceil + 1)
1365
+ end
1366
+ end
1367
+
1368
+ def pixels_unblink(which)
1369
+ self.pixels_blink_toggle(which) if @pixbuf_blinking
1370
+ self.arr_del_obj(@pixbuf_blinking_objs, which)
1371
+ return if which.empty?
1372
+ end_x = @blink_area.x + @blink_area.width - 1
1373
+ end_y = @blink_area.y + @blink_area.height - 1
1374
+ if which.img_obj_max_ax.ceil >= end_x ||
1375
+ which.img_obj_min_ax.floor <= @blink_area.x ||
1376
+ which.img_obj_max_ay.ceil >= end_y ||
1377
+ which.img_obj_min_ay.floor <= @blink_area.y
1378
+ if @pixbuf_blinking_objs.empty?
1379
+ @blink_area = nil
1380
+ @blink_area_rect = nil
1381
+ else
1382
+ end_x = @blink_area.x = @pixbuf_blinking_objs[0].first.x
1383
+ end_y = @blink_area.y = @pixbuf_blinking_objs[0].first.y
1384
+ @pixbuf_blinking_objs.each { |obj|
1385
+ @blink_area.x = [@blink_area.x,
1386
+ obj.img_obj_min_ax.floor].min
1387
+ end_x = [end_x, obj.img_obj_max_ax.ceil].max
1388
+ @blink_area.y = [@blink_area.y,
1389
+ obj.img_obj_min_ay.floor].min
1390
+ end_y = [end_y, obj.img_obj_max_ay.ceil].max
1391
+ }
1392
+ @blink_area.width = end_x - @blink_area.x + 1
1393
+ @blink_area.height = end_y - @blink_area.y + 1
1394
+ @blink_area_rect.x =
1395
+ (@blink_area.x + @pixbuf.border_width)*@kx
1396
+ @blink_area_rect.width = (@blink_area.width*@kx).ceil+1
1397
+ @blink_area_rect.y =
1398
+ (@blink_area.y + @pixbuf.border_width)*@ky
1399
+ @blink_area_rect.height =(@blink_area.height*@ky).ceil+1
1400
+ end
1401
+ end
1402
+ end
1403
+
1404
+ def pixels_trace(which)
1405
+ @pixbuf_traced_objs.push(which)
1406
+ end
1407
+
1408
+ def pixels_untrace(which)
1409
+ self.arr_del_obj(@pixbuf_traced_objs, which)
1410
+ end
1411
+
1412
+ def img_exit_blob
1413
+ #$PDbgLog.sig_call(self)
1414
+ while !@pixbuf_marked_objs.empty?
1415
+ # $PDbgLog.puts_msg "unmark "+@pixbuf_marked_objs.first.inspect
1416
+ self.pixels_unmark(@pixbuf_marked_objs.first)
1417
+ end
1418
+ while !@pixbuf_blinking_objs.empty?
1419
+ #$PDbgLog.puts_msg "unblink " +
1420
+ # @pixbuf_blinking_objs.first.inspect
1421
+ self.pixels_unblink(@pixbuf_blinking_objs.first)
1422
+ end
1423
+ while !@pixbuf_traced_objs.empty?
1424
+ # $PDbgLog.puts_msg "untrace "+@pixbuf_traced_objs.first.inspect
1425
+ self.pixels_untrace(@pixbuf_traced_objs.first)
1426
+ end
1427
+ #$PDbgLog.sig_call(self)
1428
+ end
1429
+
1430
+ def ref_img_obj(path)
1431
+ #$PDbgLog.sig_call(self)
1432
+ #$PDbgLog.print_msg "path=#{path.inspect}:"
1433
+ obj = @blob
1434
+ path = path[1...path.length] if path.starts_with("/")
1435
+ while path.length > 0
1436
+ if (i = path.index("/"))
1437
+ attr_name = path[0, i].downcase_first
1438
+ path = path[i+1...path.length]
1439
+ else
1440
+ attr_name = path.downcase_first
1441
+ path = ""
1442
+ end
1443
+ #$PDbgLog.print_msg "obj=#{obj}:methods=#{[obj.
1444
+ # public_methods.sort-Object.methods].inspect},"
1445
+ #$PDbgLog.print_msg "path=#{path.inspect},attr_name=#{
1446
+ # attr_name.inspect} "
1447
+ if attr_name =~ /([A-Za-z =?]+) ([0-9]+)/
1448
+ i = $2.to_i
1449
+ attr_name = $1.gsub(" ", "_")
1450
+ #$PDbgLog.print_msg "attr_name=#{attr_name.
1451
+ # inspect}, i=#{i} "
1452
+ if obj.public_methods.include?(attr_name)
1453
+ obj = obj.send(attr_name)[i]
1454
+ elsif obj.public_methods.include?(mname=
1455
+ attr_name.plural)
1456
+ obj = obj.send(mname)[i]
1457
+ else
1458
+ #$PDbgLog.sig_return(
1459
+ # "no indexed method: nil")
1460
+ return nil
1461
+ end
1462
+ else
1463
+ attr_name.gsub!(" ", "_")
1464
+ if obj.public_methods.include?(attr_name)
1465
+ obj = obj.send(attr_name)
1466
+ else
1467
+ #$PDbgLog.sig_return("no method #{attr_name.
1468
+ # inspect}: nil")
1469
+ return nil
1470
+ end
1471
+ end
1472
+ end
1473
+ #$PDbgLog.sig_return(obj)
1474
+ obj
1475
+ end
1476
+
1477
+ def img_enter_blob
1478
+ #$PDbgLog.sig_call(self)
1479
+ self.remove_timeouts
1480
+ @mark_blob.each_pair { |path, mw|
1481
+ next if !(obj = self.ref_img_obj(path)) || obj.empty?
1482
+ #$PDbgLog.puts_msg path + ": " + mw
1483
+ self.method("pixels_"+mw).call(obj)
1484
+ }
1485
+ self.add_timeouts
1486
+ #$PDbgLog.sig_return
1487
+ end
1488
+
1489
+ def img_motion_notify_cb(*args)
1490
+ win, x, y, state = *@drw_area.window.pointer
1491
+ x = (x/@kx).to_i; y = (y/@ky).to_i
1492
+ if !@pixbuf || x < 0 || x >= @pixbuf.width || y < 0 ||
1493
+ y >= @pixbuf.height
1494
+ @label_x.text = " "
1495
+ @label_y.text = " "
1496
+ return
1497
+ end
1498
+ @label_x.text = "%-3d" % (rx=x - @pixbuf.border_width)
1499
+ @label_y.text = "%-3d" % (ry=y - @pixbuf.border_width)
1500
+ if rx >= 0 && rx < @pixbuf.picture_width &&
1501
+ ry >= 0 && ry < @pixbuf.picture_height
1502
+ rgb = *@pixbuf.get_pix(rx, ry).color_rgb
1503
+ if @clr_show_scheme == "rgb"
1504
+ clr_text = "%3d,%3d,%3d" % rgb
1505
+ else
1506
+ h, s, v = *@pixbuf.get_pix(rx,ry).color_hsv
1507
+ clr_text = "%3.0f,%3.0f,%3.0f" %
1508
+ [360.0*h, 100.0*s, 100.0*v]
1509
+ end
1510
+ bg = "\#%02x%02x%02x" % rgb
1511
+ fg = "\#%02x%02x%02x" % [rgb[0] > 127 ? 0 : 255,
1512
+ rgb[1] > 127 ? 0 : 255, rgb[2] > 127 ? 0 : 255]
1513
+ @label_clr.set_markup("<span foreground=\"#{fg
1514
+ }\" background=\"#{bg}\">#{clr_text}</span>")
1515
+ end
1516
+ true
1517
+ end
1518
+
1519
+ def img_expose_cb(drw_area, event)
1520
+ #$PDbgLog.sig_call(self)
1521
+ #$PDbgLog.print_msg "area: #{event.area.x}, #{event.area.y}, #{
1522
+ # event.area.width}, #{event.area.height}: "
1523
+ if !@pixbuf || !@pixbuf_backing || !@pixbuf_drw_meth ||
1524
+ (x0=event.area.x/@kx) >= @pixbuf.width ||
1525
+ (y0=event.area.y/@ky) >= @pixbuf.height || @drw_area_in_procs
1526
+ #$PDbgLog.sig_return(@drw_area_in_procs)
1527
+ return @drw_area_in_procs
1528
+ end
1529
+ #$PDbgLog.puts_msg "pb_pix_cnt=#{@pixbuf.width*@pixbuf.height}"
1530
+ pb = @pixbuf_backing
1531
+ pb_pix = pb.pixels
1532
+ end_x = (event.area.x + event.area.width-1)/@kx
1533
+ end_y = (event.area.y + event.area.height-1)/@ky
1534
+ end_x = @pixbuf.width-1 if end_x >= @pixbuf.width
1535
+ end_y = @pixbuf.height-1 if end_y >= @pixbuf.height
1536
+ rowstride = @pixbuf.rowstride; pix_length = @pixbuf.pix_length
1537
+ ofs = ofs0 = y0 * rowstride + x0 * pix_length
1538
+ end_ofs = end_y * rowstride + end_x * pix_length
1539
+ width = end_x-x0 + 1; width_stride = width * pix_length
1540
+ height = end_y-y0 + 1
1541
+ t_width_stride = width_stride - pix_length
1542
+ #sub_x0 = @kx - event.area.x % @kx
1543
+ #sub_y0 = @ky - event.area.y % @ky
1544
+ view_width = (width*@kx).ceil + 1
1545
+ view_height = (height*@ky).ceil + 1
1546
+ start_x = event.area.x; start_y = event.area.y
1547
+ #$PDbgLog.print_msg "x0=#{x0}, y0=#{y0}, sub_x0=#{sub_x0
1548
+ # }, sub_y0=#{sub_y0}, end_x=#{end_x}, end_y=#{end_y
1549
+ # }, rowstride=#{rowstride}, pix_length=#{pix_length} "
1550
+ if (trc_obj = @pixbuf_traced_objs[@pixbuf_traced_obj_i]) &&
1551
+ (trc_pix = trc_obj[@pixbuf_traced_pix_i]) && (trc_pix_ofs=
1552
+ @pixbuf.ofs0+rowstride*trc_pix.y+pix_length*trc_pix.x) >= ofs0&&
1553
+ trc_pix_ofs <= end_ofs
1554
+ trc_pix_ofs.upto(trc_pix_ofs+pix_length-1) { |tmp_ofs|
1555
+ pb_pix[tmp_ofs] ^= 0xff
1556
+ }
1557
+ tw = @trace_mark.width
1558
+ tx = tx0 = (@kx*(trc_pix.x+@pixbuf.border_width+0.5) -
1559
+ tw/2 - start_x).to_i
1560
+ if tx < 0
1561
+ tw += tx
1562
+ tx = 0
1563
+ end
1564
+ e_x = ((@pixbuf.width+2*@pixbuf.border_width)*@kx).ceil
1565
+ tw = e_x - tx if tx + tw > e_x
1566
+ th = @trace_mark.height
1567
+ ty = ty0 = (@ky*(trc_pix.y+@pixbuf.border_width+0.5) -
1568
+ th/2 - start_y).to_i
1569
+ if ty < 0
1570
+ th += ty
1571
+ ty = 0
1572
+ end
1573
+ e_y = ((@pixbuf.height+2*@pixbuf.border_width)*@ky).ceil
1574
+ th = e_y - ty if ty + th > e_y
1575
+ else
1576
+ trc_pix = nil
1577
+ end
1578
+ sc_pb = pb.gdk_scaled(@kx, @ky, start_x, start_y,
1579
+ view_width, view_height, @kx < 1 || @ky < 1 ?
1580
+ Gdk::Pixbuf::INTERP_BILINEAR : Gdk::Pixbuf::INTERP_NEAREST);
1581
+ if trc_pix
1582
+ sc_pb.composite!(@trace_mark,tx,ty, tw,th, tx0,ty0, 1,1,
1583
+ Gdk::Pixbuf::INTERP_NEAREST, 255)
1584
+ trc_pix_ofs.upto(trc_pix_ofs+pix_length-1) { |tmp_ofs|
1585
+ pb_pix[tmp_ofs] ^= 0xff
1586
+ }
1587
+ end
1588
+ #@pixbuf_drw_meth.call(drw_area.window,drw_area.style.black_gc,
1589
+ # event.area.x, event.area.y,
1590
+ # (width-1)*@kx + sub_x0,(height-1)*@ky + sub_y0,
1591
+ # Gdk::RGB::Dither::NORMAL, pixels, rowstride,
1592
+ # (width-1)*@kx + sub_x0, (height-1)*@ky + sub_y0)
1593
+ #@pixbuf_drw_meth.call(drw_area.window,drw_area.style.black_gc,
1594
+ # event.area.x, event.area.y,
1595
+ # event.area.width, event.area.height,
1596
+ # Gdk::RGB::Dither::NORMAL, pixels, rowstride,
1597
+ # event.area.width, event.area.height)
1598
+ @pixbuf_drw_meth.call(drw_area.window,drw_area.style.black_gc,
1599
+ start_x, start_y, view_width, view_height,
1600
+ Gdk::RGB::Dither::NORMAL, sc_pb.pixels, sc_pb.rowstride,
1601
+ view_width, view_height)
1602
+ #$PDbgLog.sig_return
1603
+ true
1604
+ end
1605
+
1606
+ def add_blob
1607
+ #$PDbgLog.sig_call(self)
1608
+ items = []
1609
+ sel_cb = proc { |bl, wgt|
1610
+ return if bl.equal?(@blob)
1611
+ #$PDbgLog.sig_call(self)
1612
+ #$PDbgLog.puts_msg "bl: #{bl.inspect}"
1613
+ self.img_exit_blob
1614
+ @blob = bl
1615
+ self.img_enter_blob
1616
+ #$PDbgLog.sig_return
1617
+ }
1618
+ if @pixbuf
1619
+ @pixbuf.blob_id2ref_arr.each { |blob|
1620
+ items << ["/Blob #{blob.blob_id} (#{blob.length
1621
+ } pix)", "<Item>", nil, nil, sel_cb, blob]
1622
+ }
1623
+ end
1624
+ item_factory = Gtk::ItemFactory.new(Gtk::ItemFactory::TYPE_MENU,
1625
+ '<blobs>', nil)
1626
+ item_factory.create_items(items)
1627
+ oldmenu = @select_blob_menu_branch.submenu
1628
+ @select_blob_menu_branch.submenu = item_factory.get_widget(
1629
+ '<blobs>')
1630
+ oldmenu.destroy
1631
+ #$PDbgLog.sig_return
1632
+ end
1633
+
1634
+ alias_method :del_blob, :add_blob
1635
+
1636
+ def img_get_objs_at(drw_arr, event)
1637
+ return false unless @pixbuf
1638
+ ## Pop the motion event and allow the registering of the next:
1639
+ #win, x, y, state = event.window.pointer
1640
+ x, y = event.x.to_i, event.y.to_i
1641
+ x = (x/@kx).to_i - @pixbuf.border_width
1642
+ y = (y/@ky).to_i - @pixbuf.border_width
1643
+ return true if x < 0 || x >= @pixbuf.picture_width ||
1644
+ y < 0 || y >= @pixbuf.picture_height ||
1645
+ (@blob && @pixbuf.blob_id_at?(x, y, @blob.blob_id))
1646
+ $PDbgLog.sig_call(self)
1647
+ self.img_exit_blob
1648
+ if @cmp_pix_to == "Blob mean color in circle; R="
1649
+ cmp_pix_to = ['Blob mean color in a circle',
1650
+ @pix_cmp_circ_r_spinbtn.value_as_int]
1651
+ else
1652
+ cmp_pix_to = @cmp_pix_to
1653
+ end
1654
+ $PDbgLog.print_msg "Getting blob(#{x}, #{y}): cmp. to: #{
1655
+ cmp_pix_to.inspect}, #{@clr_match_scheme} tolerance: "
1656
+ if @clr_match_scheme == "rgb"
1657
+ $PDbgLog.print_msg "#{@fuzzy_clr_r},#{@fuzzy_clr_g},#{
1658
+ @fuzzy_clr_b}"
1659
+ toler_1 = @fuzzy_clr_r
1660
+ toler_2 = @fuzzy_clr_g
1661
+ toler_3 = @fuzzy_clr_b
1662
+ else
1663
+ $PDbgLog.print_msg "#{@fuzzy_clr_h},#{@fuzzy_clr_s},#{
1664
+ @fuzzy_clr_v}"
1665
+ toler_1 = @fuzzy_clr_h
1666
+ toler_2 = @fuzzy_clr_s
1667
+ toler_3 = @fuzzy_clr_v
1668
+ end
1669
+ $PDbgLog.puts_msg "; contour geometry=#{@contour_geometry
1670
+ }, external contours?=#{@external_contours
1671
+ }, min. subblob size=#{@min_subblob_size}."
1672
+ @blob = @pixbuf.get_pix(x,y).blob(@contour_geometry,
1673
+ @external_contours, @min_subblob_size-1,
1674
+ @min_outer_lp_length, &PPix::Blob.mk_get_neighbs_proc(
1675
+ @clr_match_scheme, cmp_pix_to, toler_1,toler_2,toler_3))
1676
+ @blob.extract_curves_args =
1677
+ {'extract_curves' => self,
1678
+ 'ctxt_menu_known_objs' => Set.new} unless
1679
+ @blob.extract_curves_args
1680
+ self.img_enter_blob
1681
+ self.add_blob
1682
+ $PDbgLog.sig_return
1683
+ true
1684
+ end
1685
+
1686
+ def mark_blob_switch_obj(obj, path, new_mark_way)
1687
+ #$PDbgLog.sig_call(self)
1688
+ #$PDbgLog.print_msg "path=#{path.inspect}"
1689
+ new_mark_way = new_mark_way.downcase
1690
+ return if @mark_blob[path] == new_mark_way ||
1691
+ (!MARK_WAYS.include?(new_mark_way) && !@mark_blob[path])
1692
+ if mw=@mark_blob[path]
1693
+ self.method("pixels_un"+mw).call(obj)
1694
+ end
1695
+ if MARK_WAYS.include?(new_mark_way)
1696
+ self.method("pixels_"+new_mark_way).call(obj)
1697
+ @mark_blob[path] = new_mark_way
1698
+ else
1699
+ @mark_blob.delete(path)
1700
+ end
1701
+ #$PDbgLog.sig_return
1702
+ end
1703
+
1704
+ def save_img_obj(*objs)
1705
+ dialog = Gtk::FileChooserDialog.new("Save image object to file",
1706
+ nil, Gtk::FileChooser::ACTION_SAVE, "gnome-vfs",
1707
+ [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT],
1708
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL])
1709
+ resp = dialog.run
1710
+ path = dialog.filename
1711
+ dialog.destroy
1712
+ return if resp != Gtk::Dialog::RESPONSE_ACCEPT
1713
+ if FileTest.exist?(path)
1714
+ dialog = Gtk::Dialog.new('Output File Exists',
1715
+ self, Gtk::Dialog::MODAL |
1716
+ Gtk::Dialog::DESTROY_WITH_PARENT,
1717
+ ['_Replace', 0],
1718
+ ['_Extend with new objects', 1],
1719
+ [Gtk::Stock::CANCEL, 2])
1720
+ hbox = Gtk::HBox.new(false, 0)
1721
+ hbox.set_border_width(8)
1722
+ dialog.vbox.pack_start(hbox, false, false, 0)
1723
+ hbox.pack_start(Gtk::Image.new(
1724
+ Gtk::Stock::DIALOG_QUESTION, Gtk::IconSize::DIALOG),
1725
+ false, false, 0)
1726
+ label = Gtk::Label.new
1727
+ label.markup = "File <b>#{path}</b> already exists."
1728
+ hbox.pack_start(label, false, false, 0)
1729
+ hbox.show_all
1730
+ resp = dialog.run
1731
+ dialog.destroy
1732
+ return if resp == 2
1733
+ mode = ['w', 'a'].at(resp)
1734
+ else
1735
+ mode = 'w'
1736
+ end
1737
+ begin
1738
+ open(path, mode) { |file| objs.each { |obj|
1739
+ self.write_img_obj(file, obj)
1740
+ }}
1741
+ rescue IOError
1742
+ self.show_exc_dialog
1743
+ end
1744
+ end
1745
+
1746
+ def each_img_obj_with_details(obj, parent, attr_name, attr_key=nil,
1747
+ path="", excl_set={}, &block)
1748
+ #$PDbgLog.sig_call(self)
1749
+ #$PDbgLog.print_msg "path=#{path.inspect}: "
1750
+ obj.get_sub_img_objs(excl_set).each_pair { |name, val|
1751
+ #$PDbgLog.print_msg "#{name} "
1752
+ if val.kind_of?(PPix::ImageObject)
1753
+ self.each_img_obj_with_details(val,obj,name,nil,
1754
+ path+"/"+name.cap_first.gsub("_", " "),
1755
+ excl_set,&block)
1756
+ elsif val.kind_of?(Array)
1757
+ if name[-1,1] == "s"
1758
+ rname = name.singular.cap_first
1759
+ else
1760
+ rname = name.cap_first
1761
+ end
1762
+ rname.gsub!("_", " ")
1763
+ val.each_with_index { |v, i|
1764
+ self.each_img_obj_with_details(v, obj,
1765
+ name, i, path+"/#{rname} #{i}",
1766
+ excl_set, &block)
1767
+ }
1768
+ else
1769
+ warn "#{self.class.name
1770
+ }.each_img_obj_with_details_: " +
1771
+ "NotImplementError: Image object container " +
1772
+ "of type #{val.class.name}; ignoring #{path
1773
+ }/#{name}"
1774
+ end
1775
+ }
1776
+ yield(obj, parent, attr_name, attr_key, path)
1777
+ #$PDbgLog.sig_return
1778
+ end
1779
+
1780
+ def ctxt_menu_m_cb(spec, widget)
1781
+ return true unless widget.active?
1782
+ obj, path = *spec
1783
+ mw = Gtk::ItemFactory.path_from_widget(widget)
1784
+ mw = mw['<root>/'.length...mw.length]
1785
+ #$PDbgLog.sig_call(self)
1786
+ #$PDbgLog.puts_msg("path=#{path.inspect}, mw=#{mw}")
1787
+ self.mark_blob_switch_obj(obj, path, mw)
1788
+ #$PDbgLog.sig_return
1789
+ true
1790
+ end
1791
+
1792
+ def ctxt_menu_d_cb(spec, widget)
1793
+ obj,parent,parent_mfactory,attr_name,path,del_meth,del_args =
1794
+ *spec
1795
+ del_meth.call(*del_args)
1796
+ #$PDbgLog.sig_call(self)
1797
+ if obj.equal?(@blob)
1798
+ self.img_exit_blob
1799
+ self.del_blob
1800
+ @blob = nil
1801
+ else
1802
+ #$PDbgLog.puts_msg "obj: #{obj.object_id
1803
+ # }, parent: #{parent.object_id}; marked: #{
1804
+ # @pixbuf_marked_objs.collect { |o|
1805
+ # o.object_id }.inspect }; blinking: #{
1806
+ # @pixbuf_blinking_objs.collect { |o|
1807
+ # o.object_id }.inspect }; traced: #{
1808
+ # @pixbuf_traced_objs.collect { |o| o.object_id
1809
+ # }.inspect }"
1810
+ #$PDbgLog.puts_msg(path)
1811
+ pos = nil
1812
+ item = nil
1813
+ parent_menu = parent_mfactory.get_widget('<root>')
1814
+ if obj.kind_of?(Array) || obj.kind_of?(Hash)
1815
+ dtext = 'Delete ' + attr_name.gsub('_', ' ')
1816
+ parent_menu.children.each_with_index { |item, pos|
1817
+ next unless (text = item.children[0])
1818
+ text = text.text
1819
+ break if text == dtext
1820
+ }
1821
+ parent_menu.remove(item); item.destroy
1822
+ aname=attr_name.cap_first; aname.gsub!('_',' ')
1823
+ aname = (aname[-1,1] == 's' ? aname.singular : aname)
1824
+ aname.concat(' ')
1825
+ p = parent_menu.children.length
1826
+ while (p -= 1) >= 0
1827
+ i = parent_menu.children.at(p)
1828
+ next unless (text = i.children[0])
1829
+ text = text.text
1830
+ self.mark_blob_switch_obj(obj, path+'/'+text,
1831
+ "None")
1832
+ if text.starts_with(aname)
1833
+ pos = p
1834
+ parent_menu.remove(i); i.destroy
1835
+ end
1836
+ end
1837
+ if obj.kind_of?(Array)
1838
+ obj.each { |o| @blob.extract_curves_args[
1839
+ 'ctxt_menu_known_objs'].delete(o.object_id) }
1840
+ else
1841
+ obj.each_value { |o| @blob.extract_curves_args[
1842
+ 'ctxt_menu_known_objs'].delete(o.object_id) }
1843
+ end
1844
+ epath = path
1845
+ else
1846
+ self.mark_blob_switch_obj(obj, path, "None")
1847
+ parent_menu.children.each_with_index { |item, pos|
1848
+ submenu = item.submenu
1849
+ break if submenu && submenu.children.detect{|ch|
1850
+ ch.object_id == widget.object_id }
1851
+ }
1852
+ @blob.extract_curves_args['ctxt_menu_known_objs'].
1853
+ delete(obj.object_id)
1854
+ parent_menu.remove(item); item.destroy
1855
+ epath = path[0, path.rindex('/')]
1856
+ end
1857
+ m = attr_name.cap_first; m.gsub!('_', ' ')
1858
+ parent_mfactory.create_item('/'+m, '<StockItem>', nil,
1859
+ Gtk::Stock::EXECUTE, [parent, attr_name, epath,
1860
+ parent_mfactory], &@ctxt_menu_e_cb)
1861
+ item = parent_mfactory.get_widget('/'+m)
1862
+ parent_menu.remove(item)
1863
+ parent_menu.insert(item, pos)
1864
+ end
1865
+ #$PDbgLog.sig_return
1866
+ true
1867
+ end
1868
+
1869
+ def ctxt_menu_s_cb(obj, widget)
1870
+ path = Gtk::ItemFactory.path_from_widget(widget)
1871
+ self.save_img_obj(obj)
1872
+ true
1873
+ end
1874
+
1875
+ def ctxt_menu_e_cb(spec, widget)
1876
+ pobj, attr_name, path, parent_mfactory = *spec
1877
+ self.remove_timeouts
1878
+ val = pobj.method(attr_name).call
1879
+ self.add_timeouts
1880
+ if @blob.extract_curves_args['ctxt_menu_known_objs'].include?(
1881
+ val.object_id)
1882
+ subitems = []
1883
+ elsif val.kind_of?(PPix::ImageObject)
1884
+ aname=attr_name.cap_first; aname.gsub!('_',' ')
1885
+ subitems = [Gtk::MenuItem.new(aname)]
1886
+ subitems[0].submenu=self.img_obj_mk_ctxt_menu(val, pobj,
1887
+ parent_mfactory, path + '/' + aname, attr_name, nil)
1888
+ @blob.extract_curves_args['ctxt_menu_known_objs'] <<
1889
+ val.object_id
1890
+ elsif val.kind_of?(Array)
1891
+ if !val.empty? &&
1892
+ val.first.kind_of?(PPix::ImageObject)
1893
+ subitems = []
1894
+ aname=attr_name.cap_first; aname.gsub!('_',' ')
1895
+ aname = (aname[-1,1] == 's' ? aname.singular :
1896
+ aname)
1897
+ pfx = path + '/' + aname
1898
+ val.each_with_index { |obj, i| next if obj.empty?
1899
+ item = Gtk::MenuItem.new(aname + " #{i}")
1900
+ item.submenu = self.img_obj_mk_ctxt_menu(obj, pobj,
1901
+ parent_mfactory, pfx + " #{i}", attr_name, i)
1902
+ subitems << item
1903
+ @blob.extract_curves_args['ctxt_menu_known_objs'] <<
1904
+ obj.object_id
1905
+ }
1906
+ if pobj.methods.include?(dmeth="delete_"+attr_name)
1907
+ parent_mfactory.create_item(text='/Delete '+
1908
+ attr_name.gsub('_', ' '), '<StockItem>', '',
1909
+ Gtk::Stock::DELETE, [val, pobj,
1910
+ parent_mfactory, attr_name, path,
1911
+ pobj.method(dmeth), []], &@ctxt_menu_d_cb)
1912
+ item = parent_mfactory.get_widget('<root>'+text)
1913
+ parent_menu=parent_mfactory.get_widget('<root>')
1914
+ parent_menu.remove(item)
1915
+ pos = parent_menu.children.length
1916
+ parent_menu.children.reverse_each { |i|
1917
+ pos -= 1
1918
+ break if i.gtype ==
1919
+ GLib::Type['GtkRadioMenuItem']
1920
+ }
1921
+ parent_menu.insert(item, pos-MARK_WAYS.length-1)
1922
+ end
1923
+ end
1924
+ elsif val.kind_of?(Hash)
1925
+ unless val.empty?
1926
+ flag = false
1927
+ val.each_value { |v|
1928
+ flag=v.kind_of?(PPix::ImageObject); break }
1929
+ if flag
1930
+ subitems = []
1931
+ aname=attr_name.cap_first; aname.gsub!('_',' ')
1932
+ aname = (aname[-1,1] == 's' ? aname.singular :
1933
+ aname)
1934
+ pfx = path + '/' + aname
1935
+ val.each_pair { |key, obj| next if obj.empty?
1936
+ item = Gtk::MenuItem.new(aname + " #{key}")
1937
+ item.submenu = self.img_obj_mk_ctxt_menu(obj, pobj,
1938
+ parent_mfactory, pfx + " #{key}", attr_name, key)
1939
+ subitems << item
1940
+ @blob.extract_curves_args['ctxt_menu_known_objs'] <<
1941
+ obj.object_id
1942
+ }
1943
+ if pobj.methods.include?(dmeth="delete_"+attr_name)
1944
+ parent_mfactory.create_item(text='/Delete '+
1945
+ attr_name.gsub('_', ' '), '<StockItem>', '',
1946
+ Gtk::Stock::DELETE, [val, pobj,
1947
+ parent_mfactory, attr_name, path,
1948
+ pobj.method(dmeth), []], &@ctxt_menu_d_cb)
1949
+ item = parent_mfactory.get_widget('<root>'+text)
1950
+ parent_menu=parent_mfactory.get_widget('<root>')
1951
+ parent_menu.remove(item)
1952
+ pos = parent_menu.children.length
1953
+ parent_menu.children.reverse_each { |i|
1954
+ pos -= 1
1955
+ break if i.gtype ==
1956
+ GLib::Type['GtkRadioMenuItem']
1957
+ }
1958
+ parent_menu.insert(item, pos-MARK_WAYS.length-1)
1959
+ end
1960
+ end
1961
+ end
1962
+ end
1963
+ pos = nil
1964
+ item = nil
1965
+ parent_menu = parent_mfactory.get_widget('<root>')
1966
+ parent_menu.children.each_with_index { |item, pos|
1967
+ break if item.object_id == widget.object_id }
1968
+ parent_menu.remove(item)
1969
+ item.destroy
1970
+ if subitems
1971
+ subitems.reverse.each { |item|
1972
+ parent_menu.insert(item, pos)
1973
+ item.show_all
1974
+ }
1975
+ end
1976
+ end
1977
+
1978
+ def img_obj_mk_ctxt_menu(obj, parent, parent_mfactory, path, attr_name,
1979
+ attr_key)
1980
+ #$PDbgLog.sig_call(self)
1981
+ #$PDbgLog.print_msg "path=#{path.inspect}: "
1982
+ mfactory = Gtk::ItemFactory.new(Gtk::ItemFactory::TYPE_MENU,
1983
+ '<root>', nil)
1984
+ meths = obj.img_obj_possible_sub_obj_meths unless
1985
+ (meths = obj.class.img_obj_sub_obj_meths)
1986
+ menu = mfactory.get_widget('<root>')
1987
+ unless meths.empty?
1988
+ meths.each { |meth|
1989
+ m = meth.cap_first; m.gsub!('_', ' ')
1990
+ mfactory.create_item('/'+m, '<StockItem>', nil,
1991
+ Gtk::Stock::EXECUTE, [obj,meth,path,mfactory],
1992
+ &@ctxt_menu_e_cb)
1993
+ }
1994
+ mfactory.create_item('/sep1', '<Separator>')
1995
+ end
1996
+ mw = MARK_WAYS[0]
1997
+ mfactory.create_item('/_'+mw.cap_first,
1998
+ '<RadioItem>', nil, nil, [obj, path], &@ctxt_menu_m_cb)
1999
+ fpath = '/' + mw.cap_first
2000
+ MARK_WAYS[1, MARK_WAYS.length].each { |mw|
2001
+ mfactory.create_item('/_' + mw.cap_first, fpath,
2002
+ nil, nil, [obj, path], &@ctxt_menu_m_cb)
2003
+ }
2004
+ mfactory.create_item('/_None', fpath,
2005
+ nil, nil, [obj, path], &@ctxt_menu_m_cb)
2006
+ cur_mw = @mark_blob[path] || 'none'
2007
+ mfactory.get_widget('/'+cur_mw.cap_first).activate
2008
+ mfactory.create_item('/sep2', '<Separator>')
2009
+ if attr_key
2010
+ if parent.methods.include?(dmeth="delete_"+attr_name.singular)
2011
+ mfactory.create_item('/_Delete', '<StockItem>', nil,
2012
+ Gtk::Stock::DELETE, [obj,parent,parent_mfactory,
2013
+ attr_name,path,parent.method(dmeth),[attr_key]],
2014
+ &@ctxt_menu_d_cb)
2015
+ end
2016
+ elsif parent.methods.include?(dmeth="delete_"+attr_name)
2017
+ mfactory.create_item('/_Delete', '<StockItem>', nil,
2018
+ Gtk::Stock::DELETE, [obj,parent,parent_mfactory,
2019
+ attr_name,path,parent.method(dmeth),[]],
2020
+ &@ctxt_menu_d_cb)
2021
+ end
2022
+ mfactory.create_item('/_Save', '<StockItem>', '',
2023
+ Gtk::Stock::SAVE, obj, &@ctxt_menu_s_cb)
2024
+ mfactory.get_widget('<root>')
2025
+ #$PDbgLog.sig_return
2026
+ end
2027
+
2028
+ def img_get_context_menu
2029
+ return nil unless @blob
2030
+ tmp = @blob.extract_curves_args['ctxt_menu']
2031
+ return tmp if tmp
2032
+ $PDbgLog.sig_call(self)
2033
+ tmp = @blob.extract_curves_args['ctxt_menu'] =
2034
+ self.img_obj_mk_ctxt_menu(@blob, @pixbuf, nil, "",
2035
+ "blob", @blob)
2036
+ item = Gtk::MenuItem.new("Blob #{@blob.blob_id}:")
2037
+ item.sensitive = false
2038
+ tmp.prepend(item)
2039
+ $PDbgLog.sig_return
2040
+ tmp
2041
+ end
2042
+
2043
+ def img_pop_context_menu
2044
+ menu = nil
2045
+ #@job = Thread.new(Thread.current) {
2046
+ # Thread.stop
2047
+ # $PDbgLog.sig_call(self)
2048
+ menu = self.img_get_context_menu
2049
+ # $PDbgLog.sig_return("OK")
2050
+ #}
2051
+ #@job.run
2052
+ #Thread.pass while @job.alive?
2053
+ return unless menu
2054
+ $PDbgLog.sig_call(self)
2055
+ #$PDbgLog.puts_msg "#{(menu.methods.sort - Object.methods).
2056
+ # join("\n")}"
2057
+ menu.visible = true
2058
+ menu.activate
2059
+ menu.parent.modal = true
2060
+ menu.parent.window_position = Gtk::Window::POS_MOUSE
2061
+ menu.parent.show_all
2062
+ menu.grab_focus
2063
+
2064
+ while menu.visible?
2065
+ Gtk.main_iteration
2066
+ end
2067
+ #menu.destroy
2068
+ @scrl_win.queue_draw
2069
+ $PDbgLog.sig_return("Done.")
2070
+ end
2071
+
2072
+ def img_button_press_cb(drw_area, event)
2073
+ #$PDbgLog.sig_call(self)
2074
+ unless @in_progr.try_lock
2075
+ #$PDbgLog.sig_return(false)
2076
+ return false
2077
+ end
2078
+ case event.button
2079
+ when 1 then self.img_get_objs_at(drw_area, event)
2080
+ when 3 then self.img_pop_context_menu
2081
+ end
2082
+ @in_progr.unlock
2083
+ #$PDbgLog.sig_return(true)
2084
+ return true
2085
+ end
2086
+
2087
+ def about_cb(*args)
2088
+ authors = ["Pavel Penev <pavpen@berkeley.edu>"]
2089
+ documentors = []
2090
+ license = %Q[
2091
+ This program is free software; you can redistribute it and/or
2092
+ modify it under the terms of the GNU General Public License as
2093
+ published by the Free Software Foundation; either version 2 of the
2094
+ License, or (at your option) any later version.
2095
+
2096
+ This program is distributed in the hope that it will be useful,
2097
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2098
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2099
+ General Public License for more details.
2100
+
2101
+ You should have received a copy of the GNU General Public
2102
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
2103
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2104
+ Boston, MA 02111-1307, USA.
2105
+ ]
2106
+ transparent = Gdk::Pixbuf.new(PGtk.find_icon_file(
2107
+ "pav/icons/extract_curves/extract_curves-logo-rgb.gif"))
2108
+ #.add_alpha(true, 0xff, 0xff, 0xff)
2109
+
2110
+ Gtk::AboutDialog.set_email_hook {|about, link|
2111
+ puts "send mail to #{link}"
2112
+ }
2113
+ Gtk::AboutDialog.set_url_hook {|about, link|
2114
+ puts "show url #{link}"
2115
+ }
2116
+ Gtk::AboutDialog.show(self,
2117
+ :name => "Extract Curves",
2118
+ :version => VERSION.join(".") + VERSION_SUFFIX,
2119
+ :copyright => "(C) 2005 Pavel Minev Penev",
2120
+ :license => license,
2121
+ #:website => "http://www.gtk.org",
2122
+ :comments => "Program to identify the specific " +
2123
+ "characteristics of a motion which produced a "+
2124
+ "geometric curve.",
2125
+ :authors => authors,
2126
+ #:documenters => documentors,
2127
+ :logo => transparent)
2128
+ end
2129
+ end
2130
+
2131
+ if ARGV[0]
2132
+ case ARGV[0]
2133
+ when '--version'
2134
+ puts ExtractCurvesApp::VERSION.join('.')
2135
+ exit 0
2136
+ when '--file-path'
2137
+ puts File.expand_path(__FILE__)
2138
+ exit 0
2139
+ end
2140
+ end
2141
+ #PApp.new(ExtractCurvesApp).run
2142
+ app_win = ExtractCurvesApp.new
2143
+ app_win.show_all
2144
+ app_win.open_imagef(ARGV[0]) if ARGV[0]
2145
+ Gtk.main