ruby-gtkhex 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/gtkhex.rb +1142 -1154
  3. metadata +39 -59
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3f017e42155d9dc2fa6e9f139a4987c18be91f97
4
+ data.tar.gz: b42c679fdda9357a5ff5a9e99b27103f53cd9ba4
5
+ SHA512:
6
+ metadata.gz: 98170f65ba5b3af71524023cc0e429229d4cb37d48d8e83c7217bafa61cd1a622196c76212cfeb56ed1727cf12812df3cd6529e2cd8ad416d0b69b3022e4bee0
7
+ data.tar.gz: 0a621a5fd3bce92795450a10c65c1d5d107c6d6c968253327079bc3e6d8c2af646ff5c962a5043ced39417f2c5f4bbed8590dead9ef11f6c66f305528dd48a45
@@ -1,1328 +1,1316 @@
1
1
  =begin
2
2
 
3
- = File
4
- gtkhex.rb
5
-
6
- = Info
7
- This file is part of PDF Walker, a graphical PDF file browser
8
- Copyright (C) 2010 Guillaume Delugré <guillaume@security-labs.org>
9
- All right reserved.
10
-
11
- PDF Walker is free software: you can redistribute it and/or modify
12
- it under the terms of the GNU General Public License as published by
13
- the Free Software Foundation, either version 3 of the License, or
14
- (at your option) any later version.
15
-
16
- PDF Walker is distributed in the hope that it will be useful,
17
- but WITHOUT ANY WARRANTY; without even the implied warranty of
18
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
- GNU General Public License for more details.
20
-
21
- You should have received a copy of the GNU General Public License
22
- along with PDF Walker. If not, see <http://www.gnu.org/licenses/>.
23
-
24
- This work has been derived from the GHex project. Thanks to them.
25
- Original implementation: Jaka Mocnik <jaka@gnu.org>
3
+ This file is part of ruby-gtkhex.
4
+ Copyright (C) 2017 Guillaume Delugré.
5
+
6
+ ruby-gtkhex is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ ruby-gtkhex is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with ruby-gtkhex. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ This work has been derived from the GHex project. Thanks to them.
20
+ Original implementation: Jaka Mocnik <jaka@gnu.org>
26
21
  =end
27
22
 
28
23
  require 'gtk2'
29
24
 
30
25
  module Gtk
31
-
32
- class HexEditor < Fixed
33
- module View
34
- HEX = 1
35
- ASCII = 2
36
- end
37
26
 
38
- module Group
39
- BYTE = 1
40
- WORD = 2
41
- LONG = 4
42
- end
27
+ class HexEditor < Fixed
28
+ VERSION = "0.2.0"
43
29
 
44
- class Highlight
45
- attr_accessor :start, :end
46
- attr_accessor :start_line, :end_line
47
- attr_accessor :style
48
- attr_accessor :min_select
49
- attr_accessor :valid
50
- end
30
+ module View
31
+ HEX = 1
32
+ ASCII = 2
33
+ end
51
34
 
52
- class AutoHighlight
53
- attr_accessor :search_view
54
- attr_accessor :search_string
55
- attr_accessor :search_len
35
+ module Group
36
+ BYTE = 1
37
+ WORD = 2
38
+ LONG = 4
39
+ end
56
40
 
57
- attr_accessor :color
41
+ class Highlight
42
+ attr_accessor :start, :end
43
+ attr_accessor :start_line, :end_line
44
+ attr_accessor :style
45
+ attr_accessor :min_select
46
+ attr_accessor :valid
47
+ end
58
48
 
59
- attr_accessor :view_min
60
- attr_accessor :view_max
49
+ class AutoHighlight
50
+ attr_accessor :search_view
51
+ attr_accessor :search_string
52
+ attr_accessor :search_len
61
53
 
62
- attr_accessor :highlights
63
- end
54
+ attr_accessor :color
64
55
 
65
- DEFAULT_FONT = "Monospace 12"
66
- DEFAULT_CPL = 32
67
- DEFAULT_LINES = 16
68
- DISPLAY_BORDER = 4
69
- SCROLL_TIMEOUT = 100
70
-
71
- type_register
72
-
73
- @@primary = Clipboard.get(Gdk::Selection::PRIMARY)
74
- @@clipboard = Clipboard.get(Gdk::Selection::CLIPBOARD)
75
-
76
- def initialize(data = '')
77
- super()
78
-
79
- @data = data
80
- if RUBY_VERSION >= '1.9'
81
- @data.force_encoding('binary')
82
- end
83
-
84
- @scroll_timeout = -1
85
- @disp_buffer = ""
86
- @starting_offset = 0
87
-
88
- @xdisp_width = @adisp_width = 200
89
- @xdisp_gc = @adisp_gc = nil
90
- @active_view = View::HEX
91
- @group_type = Group::BYTE
92
- @lines = @vis_lines = @top_line = @cpl = 0
93
- @cursor_pos = 0
94
- @lower_nibble = false
95
- @cursor_shown = false
96
- @button = 0
97
- @insert = false
98
- @selecting = false
99
-
100
- @selection = Highlight.new
101
- @selection.start = @selection.end = 0
102
- @selection.style = nil
103
- @selection.min_select = 1
104
- @selection.valid = false
105
-
106
- @highlights = [ @selection ]
107
-
108
- @auto_highlight = nil
109
-
110
- @disp_font_metrics = load_font DEFAULT_FONT
111
- @font_desc = Pango::FontDescription.new DEFAULT_FONT
112
-
113
- @char_width = get_max_char_width(@disp_font_metrics)
114
- @char_height = Pango.pixels(@disp_font_metrics.ascent) + Pango.pixels(@disp_font_metrics.descent) + 2
115
-
116
- self.can_focus = true
117
- self.events = Gdk::Event::KEY_PRESS_MASK
118
- self.border_width = DISPLAY_BORDER
119
-
120
- mouse_handler = lambda do |widget, event|
121
- if event.event_type == Gdk::Event::BUTTON_RELEASE and event.button == 1
122
- if @scroll_timeout
123
- GLib::Source.remove @scroll_timeout
124
- @scroll_timeout = nil
125
- @scroll_dir = 0
126
- end
127
-
128
- @selecting = false
129
- Gtk.grab_remove(widget)
130
- @button = 0
131
- elsif event.event_type == Gdk::Event::BUTTON_PRESS and event.button == 1
132
- self.grab_focus unless self.has_focus?
133
-
134
- Gtk.grab_add(widget)
135
- @button = event.button
136
-
137
- focus_view = (widget == @xdisp) ? View::HEX : View::ASCII
138
-
139
- if @active_view == focus_view
140
- if @active_view == View::HEX
141
- hex_to_pointer(event.x, event.y)
142
- else
143
- ascii_to_pointer(event.x, event.y)
56
+ attr_accessor :view_min
57
+ attr_accessor :view_max
58
+
59
+ attr_accessor :highlights
60
+ end
61
+
62
+ DEFAULT_FONT = "Monospace 12"
63
+ DEFAULT_CPL = 32
64
+ DEFAULT_LINES = 16
65
+ DISPLAY_BORDER = 4
66
+ SCROLL_TIMEOUT = 100
67
+
68
+ type_register
69
+
70
+ @@primary = Clipboard.get(Gdk::Selection::PRIMARY)
71
+ @@clipboard = Clipboard.get(Gdk::Selection::CLIPBOARD)
72
+
73
+ def initialize(data = '')
74
+ super()
75
+
76
+ @data = data.force_encoding('binary')
77
+
78
+ @scroll_timeout = -1
79
+ @disp_buffer = ""
80
+ @starting_offset = 0
81
+
82
+ @xdisp_width = @adisp_width = 200
83
+ @xdisp_gc = @adisp_gc = nil
84
+ @active_view = View::HEX
85
+ @group_type = Group::BYTE
86
+ @lines = @vis_lines = @top_line = @cpl = 0
87
+ @cursor_pos = 0
88
+ @lower_nibble = false
89
+ @cursor_shown = false
90
+ @button = 0
91
+ @insert = false
92
+ @selecting = false
93
+
94
+ @selection = Highlight.new
95
+ @selection.start = @selection.end = 0
96
+ @selection.style = nil
97
+ @selection.min_select = 1
98
+ @selection.valid = false
99
+
100
+ @highlights = [ @selection ]
101
+
102
+ @auto_highlight = nil
103
+
104
+ @disp_font_metrics = load_font DEFAULT_FONT
105
+ @font_desc = Pango::FontDescription.new DEFAULT_FONT
106
+
107
+ @char_width = get_max_char_width(@disp_font_metrics)
108
+ @char_height = Pango.pixels(@disp_font_metrics.ascent) + Pango.pixels(@disp_font_metrics.descent) + 2
109
+
110
+ @show_offsets = false
111
+ @offsets_gc = nil
112
+
113
+ self.can_focus = true
114
+ self.events = Gdk::Event::KEY_PRESS_MASK
115
+ self.border_width = DISPLAY_BORDER
116
+
117
+ mouse_handler = lambda do |widget, event|
118
+ if event.event_type == Gdk::Event::BUTTON_RELEASE and event.button == 1
119
+ if @scroll_timeout
120
+ GLib::Source.remove @scroll_timeout
121
+ @scroll_timeout = nil
122
+ @scroll_dir = 0
123
+ end
124
+
125
+ @selecting = false
126
+ Gtk.grab_remove(widget)
127
+ @button = 0
128
+ elsif event.event_type == Gdk::Event::BUTTON_PRESS and event.button == 1
129
+ self.grab_focus unless self.has_focus?
130
+
131
+ Gtk.grab_add(widget)
132
+ @button = event.button
133
+
134
+ focus_view = (widget == @xdisp) ? View::HEX : View::ASCII
135
+
136
+ if @active_view == focus_view
137
+ if @active_view == View::HEX
138
+ hex_to_pointer(event.x, event.y)
139
+ else
140
+ ascii_to_pointer(event.x, event.y)
141
+ end
142
+
143
+ unless @selecting
144
+ @selecting = true
145
+ set_selection(@cursor_pos, @cursor_pos)
146
+ end
147
+ else
148
+ hide_cursor
149
+ @active_view = focus_view
150
+ show_cursor
151
+ end
152
+ elsif event.event_type == Gdk::Event::BUTTON_PRESS and event.button == 2
153
+ # TODO
154
+ else
155
+ @button = 0
156
+ end
144
157
  end
145
158
 
146
- unless @selecting
147
- @selecting = true
148
- set_selection(@cursor_pos, @cursor_pos)
159
+ @xdisp = DrawingArea.new
160
+ @xdisp.modify_font @font_desc
161
+ @xlayout = @xdisp.create_pango_layout('')
162
+ @xdisp.events =
163
+ Gdk::Event::EXPOSURE_MASK |
164
+ Gdk::Event::BUTTON_PRESS_MASK |
165
+ Gdk::Event::BUTTON_RELEASE_MASK |
166
+ Gdk::Event::BUTTON_MOTION_MASK |
167
+ Gdk::Event::SCROLL_MASK
168
+
169
+ @xdisp.signal_connect 'realize' do
170
+ @xdisp_gc = Gdk::GC.new(@xdisp.window)
171
+ @xdisp_gc.set_exposures(true)
149
172
  end
150
- else
151
- hide_cursor
152
- @active_view = focus_view
153
- show_cursor
154
- end
155
- elsif event.event_type == Gdk::Event::BUTTON_PRESS and event.button == 2
156
- # TODO
157
- else
158
- @button = 0
173
+
174
+ @xdisp.signal_connect 'expose_event' do |_xdisp, event|
175
+ imin = (event.area.y / @char_height).to_i
176
+ imax = ((event.area.y + event.area.height) / @char_height).to_i
177
+ imax += 1 if (event.area.y + event.area.height).to_i % @char_height != 0
178
+
179
+ imax = [ imax, @vis_lines ].min
180
+
181
+ render_hex_lines(imin, imax)
182
+ end
183
+
184
+ @xdisp.signal_connect 'scroll_event' do |_xdisp, event|
185
+ @scrollbar.event(event)
186
+ end
187
+
188
+ @xdisp.signal_connect 'button_press_event' do |xdisp, event|
189
+ mouse_handler[xdisp, event]
190
+ end
191
+
192
+ @xdisp.signal_connect 'button_release_event' do |xdisp, event|
193
+ mouse_handler[xdisp, event]
194
+ end
195
+
196
+ @xdisp.signal_connect 'motion_notify_event' do |xdisp, event|
197
+ _w, x, y, _m = xdisp.window.pointer
198
+
199
+ if y < 0
200
+ @scroll_dir = -1
201
+ elsif y >= xdisp.allocation.height
202
+ @scroll_dir = 1
203
+ else
204
+ @scroll_dir = 0
205
+ end
206
+
207
+ if @scroll_dir != 0
208
+ if @scroll_timeout == nil
209
+ @scroll_timeout = GLib::Timeout.add(SCROLL_TIMEOUT) {
210
+ if @scroll_dir < 0
211
+ set_cursor([ 0, @cursor_pos - @cpl ].max)
212
+ elsif @scroll_dir > 0
213
+ set_cursor([ @data.size - 1, @cursor_pos + @cpl ].min)
214
+ end
215
+
216
+ true
217
+ }
218
+ next
219
+ end
220
+ else
221
+ if @scroll_timeout != nil
222
+ GLib::Source.remove @scroll_timeout
223
+ @scroll_timeout = nil
224
+ end
225
+ end
226
+
227
+ next if event.window != xdisp.window
228
+
229
+ hex_to_pointer(x,y) if @active_view == View::HEX and @button == 1
230
+ end
231
+
232
+ put @xdisp, 0, 0
233
+ @xdisp.show
234
+
235
+ @adisp = DrawingArea.new
236
+ @adisp.modify_font @font_desc
237
+ @alayout = @adisp.create_pango_layout('')
238
+ @adisp.events =
239
+ Gdk::Event::EXPOSURE_MASK |
240
+ Gdk::Event::BUTTON_PRESS_MASK |
241
+ Gdk::Event::BUTTON_RELEASE_MASK |
242
+ Gdk::Event::BUTTON_MOTION_MASK |
243
+ Gdk::Event::SCROLL_MASK
244
+
245
+ @adisp.signal_connect 'realize' do
246
+ @adisp_gc = Gdk::GC.new(@adisp.window)
247
+ @adisp_gc.set_exposures(true)
248
+ end
249
+
250
+ @adisp.signal_connect 'expose_event' do |_adisp, event|
251
+ imin = (event.area.y / @char_height).to_i
252
+ imax = ((event.area.y + event.area.height) / @char_height).to_i
253
+ imax += 1 if (event.area.y + event.area.height).to_i % @char_height != 0
254
+
255
+ imax = [ imax, @vis_lines ].min
256
+ render_ascii_lines(imin, imax)
257
+ end
258
+
259
+ @adisp.signal_connect 'scroll_event' do |_adisp, event|
260
+ @scrollbar.event(event)
261
+ end
262
+
263
+ @adisp.signal_connect 'button_press_event' do |adisp, event|
264
+ mouse_handler[adisp, event]
265
+ end
266
+
267
+ @adisp.signal_connect 'button_release_event' do |adisp, event|
268
+ mouse_handler[adisp, event]
269
+ end
270
+
271
+ @adisp.signal_connect 'motion_notify_event' do |adisp, event|
272
+ _w, x, y, _m = adisp.window.pointer
273
+
274
+ if y < 0
275
+ @scroll_dir = -1
276
+ elsif y >= adisp.allocation.height
277
+ @scroll_dir = 1
278
+ else
279
+ @scroll_dir = 0
280
+ end
281
+
282
+ if @scroll_dir != 0
283
+ if @scroll_timeout == nil
284
+ @scroll_timeout = GLib::Timeout.add(SCROLL_TIMEOUT) {
285
+ if @scroll_dir < 0
286
+ set_cursor([ 0, @cursor_pos - @cpl ].max)
287
+ elsif @scroll_dir > 0
288
+ set_cursor([ @data.size - 1, @cursor_pos + @cpl ].min)
289
+ end
290
+
291
+ true
292
+ }
293
+ next
294
+ end
295
+ else
296
+ if @scroll_timeout != nil
297
+ GLib::Source.remove @scroll_timeout
298
+ @scroll_timeout = nil
299
+ end
300
+ end
301
+
302
+ next if event.window != adisp.window
303
+
304
+ ascii_to_pointer(x,y) if @active_view == View::ASCII and @button == 1
305
+ end
306
+
307
+ put @adisp, 0, 0
308
+ @adisp.show
309
+
310
+ @adj = Gtk::Adjustment.new(0, 0, 0, 0, 0, 0)
311
+ @scrollbar = Gtk::VScrollbar.new(@adj)
312
+ @adj.signal_connect 'value_changed' do |adj|
313
+ unless @xdisp_gc.nil? or @adisp_gc.nil? or not @xdisp.drawable? or not @adisp.drawable?
314
+ source_min = (adj.value.to_i - @top_line) * @char_height
315
+ source_max = source_min + @xdisp.allocation.height
316
+ dest_min = 0
317
+ dest_max = @xdisp.allocation.height
318
+
319
+ rect = Gdk::Rectangle.new(0, 0, 0, 0)
320
+ @top_line = adj.value.to_i
321
+ if source_min < 0
322
+ rect.y = 0
323
+ rect.height = -source_min
324
+ rect_height = [ rect.height, @xdisp.allocation.height ].min
325
+ source_min = 0
326
+ dest_min = rect.height
327
+ else
328
+ rect.y = 2 * @xdisp.allocation.height - source_max
329
+ rect.y = 0 if rect.y < 0
330
+ rect.height = @xdisp.allocation.height - rect.y
331
+ source_max = @xdisp.allocation.height
332
+ dest_max = rect.y
333
+ end
334
+
335
+ if source_min != source_max
336
+ @xdisp.window.draw_drawable(
337
+ @xdisp_gc,
338
+ @xdisp.window,
339
+ 0, source_min,
340
+ 0, dest_min,
341
+ @xdisp.allocation.width,
342
+ source_max - source_min
343
+ )
344
+ @adisp.window.draw_drawable(
345
+ @adisp_gc,
346
+ @adisp.window,
347
+ 0, source_min,
348
+ 0, dest_min,
349
+ @adisp.allocation.width,
350
+ source_max - source_min
351
+ )
352
+
353
+ if @offsets
354
+ if @offsets_gc.nil?
355
+ @offsets_gc = Gdk::GC.new(@offsets.window)
356
+ @offsets_gc.set_exposures(true)
357
+ end
358
+
359
+ @offsets.window.draw_drawable(
360
+ @offsets_gc,
361
+ @offsets.window,
362
+ 0, source_min,
363
+ 0, dest_min,
364
+ @offsets.allocation.width,
365
+ source_max - source_min
366
+ )
367
+ end
368
+
369
+ # TODO update_all_auto_highlights(true, true)
370
+ invalidate_all_highlights
371
+
372
+ rect.width = @xdisp.allocation.width
373
+ @xdisp.window.invalidate(rect, false)
374
+ rect.width = @adisp.allocation.width
375
+ @adisp.window.invalidate(rect, false)
376
+
377
+ if @offsets
378
+ rect.width = @offsets.allocation.width
379
+ @offsets.window.invalidate(rect, false)
380
+ end
381
+ end
382
+ end
383
+ end
384
+
385
+ put @scrollbar, 0, 0
386
+ @scrollbar.show
159
387
  end
160
- end
161
-
162
- @xdisp = DrawingArea.new
163
- @xdisp.modify_font @font_desc
164
- @xlayout = @xdisp.create_pango_layout('')
165
- @xdisp.events =
166
- Gdk::Event::EXPOSURE_MASK |
167
- Gdk::Event::BUTTON_PRESS_MASK |
168
- Gdk::Event::BUTTON_RELEASE_MASK |
169
- Gdk::Event::BUTTON_MOTION_MASK |
170
- Gdk::Event::SCROLL_MASK
171
-
172
- @xdisp.signal_connect 'realize' do
173
- @xdisp_gc = Gdk::GC.new(@xdisp.window)
174
- @xdisp_gc.set_exposures(true)
175
- end
176
-
177
- @xdisp.signal_connect 'expose_event' do |xdisp, event|
178
- imin = (event.area.y / @char_height).to_i
179
- imax = ((event.area.y + event.area.height) / @char_height).to_i
180
- imax += 1 if (event.area.y + event.area.height).to_i % @char_height != 0
181
-
182
- imax = [ imax, @vis_lines ].min
183
-
184
- render_hex_lines(imin, imax)
185
- end
186
-
187
- @xdisp.signal_connect 'scroll_event' do |xdisp, event|
188
- @scrollbar.event(event)
189
- end
190
-
191
- @xdisp.signal_connect 'button_press_event' do |xdisp, event|
192
- mouse_handler[xdisp, event]
193
- end
194
-
195
- @xdisp.signal_connect 'button_release_event' do |xdisp, event|
196
- mouse_handler[xdisp, event]
197
- end
198
-
199
- @xdisp.signal_connect 'motion_notify_event' do |xdisp, event|
200
- w, x, y, m = xdisp.window.pointer
201
-
202
- if y < 0
203
- @scroll_dir = -1
204
- elsif y >= xdisp.allocation.height
205
- @scroll_dir = 1
206
- else
207
- @scroll_dir = 0
388
+
389
+ def set_selection(s, e)
390
+ e = [ e, @data.size ].min
391
+
392
+ @@primary.clear if @selection.start != @selection.end
393
+
394
+ os, oe = [ @selection.start, @selection.end ].sort
395
+
396
+ @selection.start = [ 0, s ].max
397
+ @selection.start = [ @selection.start, @data.size ].min
398
+ @selection.end = [ e, @data.size ].min
399
+
400
+ invalidate_highlight(@selection)
401
+
402
+ ns, ne = [ @selection.start, @selection.end ].sort
403
+
404
+ if ns != os and ne != oe
405
+ bytes_changed([ns, os].min, [ne, oe].max)
406
+ elsif ne != oe
407
+ bytes_changed(*[ne, oe].sort)
408
+ elsif ns != os
409
+ bytes_changed(*[ns, os].sort)
410
+ end
411
+
412
+ if @selection.start != @selection.end
413
+ if @active_view == View::HEX
414
+ brk_len = 2 * @cpl + @cpl / @group_type
415
+ format_xblock(s,e)
416
+ (@disp_buffer.size / brk_len + 1).times do |i| @disp_buffer.insert(i * (brk_len + 1), $/) end
417
+ else
418
+ brk_len = @cpl
419
+ format_ablock(s,e)
420
+ end
421
+
422
+ @@primary.set_text(@disp_buffer)
423
+ end
208
424
  end
209
425
 
210
- if @scroll_dir != 0
211
- if @scroll_timeout == nil
212
- @scroll_timeout = GLib::Timeout.add(SCROLL_TIMEOUT) {
213
- if @scroll_dir < 0
214
- set_cursor([ 0, @cursor_pos - @cpl ].max)
215
- elsif @scroll_dir > 0
216
- set_cursor([ @data.size - 1, @cursor_pos + @cpl ].min)
217
- end
218
-
219
- true
220
- }
221
- next
222
- end
223
- else
224
- if @scroll_timeout != nil
225
- GLib::Source.remove @scroll_timeout
226
- @scroll_timeout = nil
227
- end
426
+ def get_selection
427
+ [ @selection.start, @selection.end ].sort
228
428
  end
229
429
 
230
- next if event.window != xdisp.window
231
-
232
- hex_to_pointer(x,y) if @active_view == View::HEX and @button == 1
233
- end
234
-
235
- put @xdisp, 0, 0
236
- @xdisp.show
237
-
238
- @adisp = DrawingArea.new
239
- @adisp.modify_font @font_desc
240
- @alayout = @adisp.create_pango_layout('')
241
- @adisp.events =
242
- Gdk::Event::EXPOSURE_MASK |
243
- Gdk::Event::BUTTON_PRESS_MASK |
244
- Gdk::Event::BUTTON_RELEASE_MASK |
245
- Gdk::Event::BUTTON_MOTION_MASK |
246
- Gdk::Event::SCROLL_MASK
247
-
248
-
249
- @adisp.signal_connect 'realize' do
250
- @adisp_gc = Gdk::GC.new(@adisp.window)
251
- @adisp_gc.set_exposures(true)
252
- end
253
-
254
- @adisp.signal_connect 'expose_event' do |adisp, event|
255
- imin = (event.area.y / @char_height).to_i
256
- imax = ((event.area.y + event.area.height) / @char_height).to_i
257
- imax += 1 if (event.area.y + event.area.height).to_i % @char_height != 0
258
-
259
- imax = [ imax, @vis_lines ].min
260
- render_ascii_lines(imin, imax)
261
- end
262
-
263
- @adisp.signal_connect 'scroll_event' do |adisp, event|
264
- @scrollbar.event(event)
265
- end
266
-
267
- @adisp.signal_connect 'button_press_event' do |adisp, event|
268
- mouse_handler[adisp, event]
269
- end
270
-
271
- @adisp.signal_connect 'button_release_event' do |adisp, event|
272
- mouse_handler[adisp, event]
273
- end
274
-
275
- @adisp.signal_connect 'motion_notify_event' do |adisp, event|
276
- w, x, y, m = adisp.window.pointer
277
-
278
- if y < 0
279
- @scroll_dir = -1
280
- elsif y >= adisp.allocation.height
281
- @scroll_dir = 1
282
- else
283
- @scroll_dir = 0
430
+ def clear_selection
431
+ set_selection(0, 0)
284
432
  end
285
433
 
286
- if @scroll_dir != 0
287
- if @scroll_timeout == nil
288
- @scroll_timeout = GLib::Timeout.add(SCROLL_TIMEOUT) {
289
- if @scroll_dir < 0
290
- set_cursor([ 0, @cursor_pos - @cpl ].max)
291
- elsif @scroll_dir > 0
292
- set_cursor([ @data.size - 1, @cursor_pos + @cpl ].min)
293
- end
294
-
295
- true
296
- }
297
- next
298
- end
299
- else
300
- if @scroll_timeout != nil
301
- GLib::Source.remove @scroll_timeout
302
- @scroll_timeout = nil
303
- end
434
+ def cursor
435
+ @cursor_pos
304
436
  end
305
437
 
306
- next if event.window != adisp.window
307
-
308
- ascii_to_pointer(x,y) if @active_view == View::ASCII and @button == 1
309
- end
310
-
311
- put @adisp, 0, 0
312
- @adisp.show
313
-
314
- @adj = Gtk::Adjustment.new(0, 0, 0, 0, 0, 0)
315
- @scrollbar = VScrollbar.new(@adj)
316
- @adj.signal_connect 'value_changed' do |adj|
317
- unless @xdisp_gc.nil? or @adisp_gc.nil? or not @xdisp.drawable? or not @adisp.drawable?
318
-
319
- source_min = (adj.value.to_i - @top_line) * @char_height
320
- source_max = source_min + @xdisp.allocation.height
321
- dest_min = 0
322
- dest_max = @xdisp.allocation.height
323
-
324
- rect = Gdk::Rectangle.new(0, 0, 0, 0)
325
- @top_line = adj.value.to_i
326
- if source_min < 0
327
- rect.y = 0
328
- rect.height = -source_min
329
- rect_height = [ rect.height, @xdisp.allocation.height ].min
330
- source_min = 0
331
- dest_min = rect.height
332
- else
333
- rect.y = 2 * @xdisp.allocation.height - source_max
334
- rect.y = 0 if rect.y < 0
335
- rect.height = @xdisp.allocation.height - rect.y
336
- source_max = @xdisp.allocation.height
337
- dest_max = rect.y
338
- end
339
-
340
- if source_min != source_max
341
- @xdisp.window.draw_drawable(
342
- @xdisp_gc,
343
- @xdisp.window,
344
- 0, source_min,
345
- 0, dest_min,
346
- @xdisp.allocation.width,
347
- source_max - source_min
348
- )
349
- @adisp.window.draw_drawable(
350
- @adisp_gc,
351
- @adisp.window,
352
- 0, source_min,
353
- 0, dest_min,
354
- @adisp.allocation.width,
355
- source_max - source_min
356
- )
438
+ def set_cursor(index)
439
+ return if index < 0 or index > @data.size
357
440
 
358
- if @offsets
359
- if @offsets_gc.nil?
360
- @offsets_gc = Gdk::GC.new(@offsets.window)
361
- @offsets_gc.set_exposures(true)
362
- end
441
+ old_pos = @cursor_pos
442
+ index -= 1 if @insert and index == @data.size
443
+ index = [ 0, index ].max
363
444
 
364
- @offsets.window.draw_drawable(
365
- @offsets_gc,
366
- @offsets.window,
367
- 0, source_min,
368
- 0, dest_min,
369
- @offsets.allocation.width,
370
- source_max - source_min
371
- )
445
+ hide_cursor
446
+
447
+ @cursor_pos = index
448
+ return if @cpl == 0
449
+
450
+ y = index / @cpl
451
+ if y >= @top_line + @vis_lines
452
+ @adj.value = [ y - @vis_lines + 1, @lines - @vis_lines ].min
453
+ @adj.value = [ 0, @adj.value ].max
454
+ @adj.signal_emit 'value_changed'
455
+ elsif y < @top_line
456
+ @adj.value = y
457
+ @adj.signal_emit 'value_changed'
372
458
  end
373
459
 
374
- # TODO update_all_auto_highlights(true, true)
375
- invalidate_all_highlights
376
-
377
- rect.width = @xdisp.allocation.width
378
- @xdisp.window.invalidate(rect, false)
379
- rect.width = @adisp.allocation.width
380
- @adisp.window.invalidate(rect, false)
460
+ @lower_nibble = false if index == @data.size
381
461
 
382
- if @offsets
383
- rect.width = @offsets.allocation.width
384
- @offsets.window.invalidate(rect, false)
462
+ if @selecting
463
+ set_selection(@selection.start, @cursor_pos)
464
+ bytes_changed(*[@cursor_pos, old_pos].sort)
465
+ else# @selection.start != @selection.end
466
+ s, e = [@selection.start, @selection.end].sort
467
+ @selection.end = @selection.start = @cursor_pos
468
+ bytes_changed(s, e)
385
469
  end
386
- end
470
+
471
+ self.signal_emit 'cursor_moved'
472
+
473
+ bytes_changed(old_pos, old_pos)
474
+ show_cursor
387
475
  end
388
- end
389
476
 
390
- put @scrollbar, 0, 0
391
- @scrollbar.show
392
- end
477
+ def set_cursor_xy(x, y)
478
+ pos = y.to_i * @cpl + x.to_i
479
+ return if y < 0 or y >= @lines or x < 0 or x >= @cpl or pos > @data.size
393
480
 
394
- def set_selection(s, e)
395
- e = [ e, @data.size ].min
481
+ set_cursor(pos)
482
+ end
396
483
 
397
- @@primary.clear if @selection.start != @selection.end
484
+ def set_cursor_on_lower_nibble(bool)
485
+ if @selecting
486
+ bytes_changed(@cursor_pos, @cursor_pos)
487
+ @lower_nibble = bool
488
+ elsif @selection.start != @selection.end
489
+ s, e = [ @selection.start, @selection.end ].sort
490
+
491
+ @selection.start = @selection.end = 0
492
+ bytes_changed(s, e)
493
+ @lower_nibble = bool
494
+ else
495
+ hide_cursor
496
+ @lower_nibble = bool
497
+ show_cursor
498
+ end
499
+ end
398
500
 
399
- os, oe = [ @selection.start, @selection.end ].sort
501
+ def set_group_type(type)
502
+ hide_cursor
503
+ @group_type = type
504
+ recalc_displays(self.allocation.width, self.allocation.height)
505
+ self.queue_resize
506
+ show_cursor
507
+ end
400
508
 
401
- @selection.start = [ 0, s ].max
402
- @selection.start = [ @selection.start, @data.size ].min
403
- @selection.end = [ e, @data.size ].min
509
+ def show_offsets(bool)
510
+ return unless @show_offsets ^ bool
511
+
512
+ @show_offsets = bool
513
+ if bool
514
+ show_offsets_widget
515
+ else
516
+ hide_offsets_widget
517
+ end
518
+ end
404
519
 
405
- invalidate_highlight(@selection)
520
+ def set_font(fontname)
521
+ @font_desc = Pango::FontDescription.new(fontname)
522
+ @disp_font_metrics = load_font(fontname)
406
523
 
407
- ns, ne = [ @selection.start, @selection.end ].sort
524
+ @xdisp.modify_font(@font_desc) if @xdisp
525
+ @adisp.modify_font(@font_desc) if @adisp
526
+ @offsets.modify_font(@font_desc) if @offsets
408
527
 
409
- if ns != os and ne != oe
410
- bytes_changed([ns, os].min, [ne, oe].max)
411
- elsif ne != oe
412
- bytes_changed(*[ne, oe].sort)
413
- elsif ns != os
414
- bytes_changed(*[ns, os].sort)
415
- end
528
+ @char_width = get_max_char_width(@disp_font_metrics)
529
+ @char_height = Pango.pixels(@disp_font_metrics.ascent) + Pango.pixels(@disp_font_metrics.descent) + 2
530
+ recalc_displays(self.allocation.width, self.allocation.height)
416
531
 
417
- if @selection.start != @selection.end
418
- if @active_view == View::HEX
419
- brk_len = 2 * @cpl + @cpl / @group_type
420
- format_xblock(s,e)
421
- (@disp_buffer.size / brk_len + 1).times do |i| @disp_buffer.insert(i * (brk_len + 1), $/) end
422
- else
423
- brk_len = @cpl
424
- format_ablock(s,e)
532
+ redraw_widget
425
533
  end
426
534
 
427
- @@primary.set_text(@disp_buffer)
428
- end
429
- end
535
+ def set_data(data)
536
+ prev_data_size = @data.size
537
+ @data = data.dup
430
538
 
431
- def get_selection
432
- [ @selection.start, @selection.end ].sort
433
- end
539
+ recalc_displays(self.allocation.width, self.allocation.height)
434
540
 
435
- def clear_selection
436
- set_selection(0, 0)
437
- end
541
+ set_cursor 0
542
+ bytes_changed(0, [ prev_data_size, @data.size ].max)
543
+ redraw_widget
544
+ end
438
545
 
439
- def cursor
440
- @cursor_pos
441
- end
546
+ def validate_highlight(hl)
547
+ unless hl.valid
548
+ hl.start_line = [ hl.start, hl.end ].min / @cpl - @top_line
549
+ hl.end_line = [ hl.start, hl.end ].max / @cpl - @top_line
550
+ hl.valid = true
551
+ end
552
+ end
442
553
 
443
- def set_cursor(index)
444
- return if index < 0 or index > @data.size
445
-
446
- old_pos = @cursor_pos
447
- index -= 1 if @insert and index == @data.size
448
- index = [ 0, index ].max
449
-
450
- hide_cursor
451
-
452
- @cursor_pos = index
453
- return if @cpl == 0
454
-
455
- y = index / @cpl
456
- if y >= @top_line + @vis_lines
457
- @adj.value = [ y - @vis_lines + 1, @lines - @vis_lines ].min
458
- @adj.value = [ 0, @adj.value ].max
459
- @adj.signal_emit 'value_changed'
460
- elsif y < @top_line
461
- @adj.value = y
462
- @adj.signal_emit 'value_changed'
463
- end
464
-
465
- @lower_nibble = false if index == @data.size
466
-
467
- if @selecting
468
- set_selection(@selection.start, @cursor_pos)
469
- bytes_changed(*[@cursor_pos, old_pos].sort)
470
- else# @selection.start != @selection.end
471
- s, e = [@selection.start, @selection.end].sort
472
- @selection.end = @selection.start = @cursor_pos
473
- bytes_changed(s, e)
474
- end
475
-
476
- self.signal_emit 'cursor_moved'
477
-
478
- bytes_changed(old_pos, old_pos)
479
- show_cursor
480
- end
554
+ def invalidate_highlight(hl)
555
+ hl.valid = false
556
+ end
481
557
 
482
- def set_cursor_xy(x, y)
483
- pos = y.to_i * @cpl + x.to_i
484
- return if y < 0 or y >= @lines or x < 0 or x >= @cpl or pos > @data.size
558
+ def invalidate_all_highlights
559
+ @highlights.each do |hl| invalidate_highlight(hl) end
560
+ end
485
561
 
486
- set_cursor(pos)
487
- end
562
+ private
488
563
 
489
- def set_cursor_on_lower_nibble(bool)
490
- if @selecting
491
- bytes_changed(@cursor_pos, @cursor_pos)
492
- @lower_nibble = bool
493
- elsif @selection.start != @selection.end
494
- s, e = [ @selection.start, @selection.end ].sort
495
-
496
- @selection.start = @selection.end = 0
497
- bytes_changed(s, e)
498
- @lower_nibble = bool
499
- else
500
- hide_cursor
501
- @lower_nibble = bool
502
- show_cursor
503
- end
504
- end
564
+ signal_new(
565
+ 'data_changed',
566
+ GLib::Signal::RUN_FIRST,
567
+ nil,
568
+ nil,
569
+ String
570
+ )
505
571
 
506
- def set_group_type(type)
507
- hide_cursor
508
- @group_type = type
509
- recalc_displays(self.allocation.width, self.allocation.height)
510
- self.queue_resize
511
- show_cursor
512
- end
572
+ signal_new(
573
+ 'cursor_moved',
574
+ GLib::Signal::RUN_FIRST,
575
+ nil,
576
+ nil
577
+ )
513
578
 
514
- def show_offsets(bool)
515
- return unless @show_offsets ^ bool
579
+ def signal_do_cursor_moved
580
+ end
516
581
 
517
- @show_offsets = bool
518
- if bool
519
- show_offsets_widget
520
- else
521
- hide_offsets_widget
522
- end
523
- end
582
+ def signal_do_data_changed(data)
583
+ # TODO
584
+ end
524
585
 
525
- def set_font(fontname)
526
- @font_desc = Pango::FontDescription.new(fontname)
527
- @disp_font_metrics = load_font(fontname)
586
+ def signal_do_realize
587
+ super
528
588
 
529
- @xdisp.modify_font(@font_desc) if @xdisp
530
- @adisp.modify_font(@font_desc) if @adisp
531
- @offsets.modify_font(@font_desc) if @offsets
589
+ self.window.set_back_pixmap(nil, true)
590
+ end
532
591
 
533
- @char_width = get_max_char_width(@disp_font_metrics)
534
- @char_height = Pango.pixels(@disp_font_metrics.ascent) + Pango.pixels(@disp_font_metrics.descent) + 2
535
- recalc_displays(self.allocation.width, self.allocation.height)
592
+ def signal_do_size_allocate(alloc)
593
+ hide_cursor
536
594
 
537
- redraw_widget
538
- end
595
+ recalc_displays(alloc.width, alloc.height)
596
+
597
+ self.set_allocation(alloc.x, alloc.y, alloc.width, alloc.height)
598
+ self.window.move_resize(
599
+ alloc.x, alloc.y,
600
+ alloc.width, alloc.height
601
+ ) if self.realized?
602
+
603
+ bw = self.border_width
604
+ xt = widget_get_xt
605
+ yt = widget_get_yt
606
+
607
+ my_alloc = Gtk::Allocation.new(0, 0, 0, 0)
608
+ my_alloc.x = bw + xt
609
+ my_alloc.y = bw + yt
610
+ my_alloc.height = [ alloc.height - 2*bw - 2*yt, 1 ].max
611
+ if @show_offsets
612
+ my_alloc.width = 8 * @char_width
613
+ @offsets.size_allocate(my_alloc)
614
+ @offsets.queue_draw
615
+ my_alloc.x += 2*xt + my_alloc.width
616
+ end
539
617
 
540
- def set_data(data)
541
- prev_data_size = @data.size
542
- @data = data.dup
618
+ my_alloc.width = @xdisp_width
619
+ @xdisp.size_allocate(my_alloc)
543
620
 
544
- recalc_displays(self.allocation.width, self.allocation.height)
545
-
546
- set_cursor 0
547
- bytes_changed(0, [ prev_data_size, @data.size ].max)
548
- redraw_widget
549
- end
621
+ my_alloc.x = alloc.width - bw - @scrollbar.requisition[0]
622
+ my_alloc.y = bw
623
+ my_alloc.width = @scrollbar.requisition[0]
624
+ my_alloc.height = [ alloc.height - 2*bw, 1 ].max
625
+ @scrollbar.size_allocate(my_alloc)
550
626
 
551
- def validate_highlight(hl)
552
- unless hl.valid
553
- hl.start_line = [ hl.start, hl.end ].min / @cpl - @top_line
554
- hl.end_line = [ hl.start, hl.end ].max / @cpl - @top_line
555
- hl.valid = true
556
- end
557
- end
627
+ my_alloc.x -= @adisp_width + xt
628
+ my_alloc.y = bw + yt
629
+ my_alloc.width = @adisp_width
630
+ my_alloc.height = [ alloc.height - 2*bw - 2*yt, 1 ].max
631
+ @adisp.size_allocate(my_alloc)
558
632
 
559
- def invalidate_highlight(hl)
560
- hl.valid = false
561
- end
633
+ show_cursor
634
+ end
562
635
 
563
- def invalidate_all_highlights
564
- @highlights.each do |hl| invalidate_highlight(hl) end
565
- end
636
+ def signal_do_size_request(req)
637
+ sb_width, _sb_height = @scrollbar.size_request
638
+ bw = self.border_width
639
+ xt, yt = widget_get_xt, widget_get_yt
566
640
 
567
- private
641
+ width = 4*xt + 2*bw + sb_width +
642
+ @char_width*(DEFAULT_CPL + (DEFAULT_CPL-1)/@group_type)
568
643
 
569
- signal_new(
570
- 'data_changed',
571
- GLib::Signal::RUN_FIRST,
572
- nil,
573
- nil,
574
- String
575
- )
644
+ width += 2*xt + 8*@char_width if @show_offsets
576
645
 
577
- signal_new(
578
- 'cursor_moved',
579
- GLib::Signal::RUN_FIRST,
580
- nil,
581
- nil
582
- )
646
+ height = DEFAULT_LINES * @char_height + 2*yt + 2*bw
583
647
 
584
- def signal_do_cursor_moved
585
- end
648
+ req[0] = width
649
+ req[1] = height
650
+ end
586
651
 
587
- def signal_do_data_changed(data)
588
- # TODO
589
- end
652
+ def signal_do_expose_event(event)
653
+ draw_shadow(event.area)
654
+ super(event)
590
655
 
591
- def signal_do_realize
592
- super
656
+ true
657
+ end
593
658
 
594
- self.window.set_back_pixmap(nil, true)
595
- end
659
+ def signal_do_key_press_event(event)
596
660
 
597
- def signal_do_size_allocate(alloc)
598
- hide_cursor
599
-
600
- recalc_displays(alloc.width, alloc.height)
601
-
602
- self.set_allocation(alloc.x, alloc.y, alloc.width, alloc.height)
603
- self.window.move_resize(
604
- alloc.x, alloc.y,
605
- alloc.width, alloc.height
606
- ) if self.realized?
607
-
608
- bw = self.border_width
609
- xt = widget_get_xt
610
- yt = widget_get_yt
611
-
612
- my_alloc = Gtk::Allocation.new(0, 0, 0, 0)
613
- my_alloc.x = bw + xt
614
- my_alloc.y = bw + yt
615
- my_alloc.height = [ alloc.height - 2*bw - 2*yt, 1 ].max
616
- if @show_offsets
617
- my_alloc.width = 8 * @char_width
618
- @offsets.size_allocate(my_alloc)
619
- @offsets.queue_draw
620
- my_alloc.x += 2*xt + my_alloc.width
621
- end
622
-
623
- my_alloc.width = @xdisp_width
624
- @xdisp.size_allocate(my_alloc)
625
-
626
- my_alloc.x = alloc.width - bw - @scrollbar.requisition[0]
627
- my_alloc.y = bw
628
- my_alloc.width = @scrollbar.requisition[0]
629
- my_alloc.height = [ alloc.height - 2*bw, 1 ].max
630
- @scrollbar.size_allocate(my_alloc)
631
-
632
- my_alloc.x -= @adisp_width + xt
633
- my_alloc.y = bw + yt
634
- my_alloc.width = @adisp_width
635
- my_alloc.height = [ alloc.height - 2*bw - 2*yt, 1 ].max
636
- @adisp.size_allocate(my_alloc)
637
-
638
- show_cursor
639
- end
661
+ hide_cursor
662
+ @selecting = (event.state & Gdk::Window::SHIFT_MASK) != 0
663
+ ret = true
664
+
665
+ case event.keyval
666
+ when Gdk::Keyval::GDK_KP_Tab, Gdk::Keyval::GDK_Tab
667
+ @active_view = (@active_view == View::HEX) ? View::ASCII : View::HEX
668
+
669
+ when Gdk::Keyval::GDK_Up
670
+ set_cursor(@cursor_pos - @cpl)
671
+
672
+ when Gdk::Keyval::GDK_Down
673
+ set_cursor(@cursor_pos + @cpl)
674
+
675
+ when Gdk::Keyval::GDK_Page_Up
676
+ set_cursor([0, @cursor_pos - @vis_lines * @cpl].max)
677
+
678
+ when Gdk::Keyval::GDK_Page_Down
679
+ set_cursor([@cursor_pos + @vis_lines * @cpl, @data.size].min)
680
+
681
+ when Gdk::Keyval::GDK_Left
682
+ if @active_view == View::HEX
683
+ if @selecting
684
+ set_cursor(@cursor_pos - 1)
685
+ else
686
+ @lower_nibble ^= 1
687
+ set_cursor(@cursor_pos - 1) if @lower_nibble
688
+ end
689
+ else
690
+ set_cursor(@cursor_pos - 1)
691
+ end
692
+
693
+ when Gdk::Keyval::GDK_Right
694
+ if @active_view == View::HEX
695
+ if @selecting
696
+ set_cursor(@cursor_pos + 1)
697
+ else
698
+ @lower_nibble ^= 1
699
+ set_cursor(@cursor_pos + 1) unless @lower_nibble
700
+ end
701
+ else
702
+ set_cursor(@cursor_pos + 1)
703
+ end
704
+
705
+ when Gdk::Keyval::GDK_c, Gdk::Keyval::GDK_C
706
+ if event.state & Gdk::Window::CONTROL_MASK != 0
707
+ s,e = @selection.start, @selection.end + 1
708
+ if @active_view == View::HEX
709
+ brk_len = 2 * @cpl + @cpl / @group_type
710
+ format_xblock(s,e)
711
+ (@disp_buffer.size / brk_len + 1).times do |i| @disp_buffer.insert(i * (brk_len + 1), $/) end
712
+ else
713
+ brk_len = @cpl
714
+ format_ablock(s,e)
715
+ end
716
+
717
+ @@clipboard.set_text(@disp_buffer)
718
+ end
719
+ else
720
+ ret = false
721
+ end
640
722
 
641
- def signal_do_size_request(req)
642
- sb_width, sb_height = @scrollbar.size_request
643
- bw = self.border_width
644
- xt, yt = widget_get_xt, widget_get_yt
723
+ show_cursor
645
724
 
646
- width = 4*xt + 2*bw + sb_width +
647
- @char_width*(DEFAULT_CPL + (DEFAULT_CPL-1)/@group_type)
725
+ ret
726
+ end
648
727
 
649
- width += 2*xt + 8*@char_width if @show_offsets
728
+ def hex_to_pointer(mx, my)
729
+ cy = @top_line + my.to_i / @char_height
650
730
 
651
- height = DEFAULT_LINES * @char_height + 2*yt + 2*bw
652
-
653
- req[0] = width
654
- req[1] = height
655
- end
731
+ cx = x = 0
732
+ while cx < 2 * @cpl
733
+ x += @char_width
656
734
 
657
- def signal_do_expose_event(event)
658
- draw_shadow(event.area)
659
- super(event)
735
+ if x > mx
736
+ set_cursor_xy(cx / 2, cy)
737
+ set_cursor_on_lower_nibble(cx % 2 != 0)
660
738
 
661
- true
662
- end
739
+ cx = 2 * @cpl
740
+ end
663
741
 
664
- def signal_do_key_press_event(event)
665
- old_cp = @cursor_pos
742
+ cx += 1
743
+ x += @char_width if ( cx % (2 * @group_type) == 0 )
744
+ end
745
+ end
666
746
 
667
- hide_cursor
668
- @selecting = (event.state & Gdk::Window::SHIFT_MASK) != 0
669
- ret = true
747
+ def ascii_to_pointer(mx, my)
748
+ cx = mx / @char_width
749
+ cy = @top_line + my / @char_height
670
750
 
671
- case event.keyval
672
- when Gdk::Keyval::GDK_KP_Tab, Gdk::Keyval::GDK_Tab
673
- @active_view = (@active_view == View::HEX) ? View::ASCII : View::HEX
674
-
675
- when Gdk::Keyval::GDK_Up
676
- set_cursor(@cursor_pos - @cpl)
751
+ set_cursor_xy(cx, cy)
752
+ end
677
753
 
678
- when Gdk::Keyval::GDK_Down
679
- set_cursor(@cursor_pos + @cpl)
754
+ def load_font(fontname)
755
+ desc = Pango::FontDescription.new(fontname)
756
+ context = Gdk::Pango.context
757
+ context.set_language(Gtk.default_language)
680
758
 
681
- when Gdk::Keyval::GDK_Page_Up
682
- set_cursor([0, @cursor_pos - @vis_lines * @cpl].max)
759
+ font = context.load_font(desc)
683
760
 
684
- when Gdk::Keyval::GDK_Page_Down
685
- set_cursor([@cursor_pos + @vis_lines * @cpl, @data.size].min)
761
+ #font.metrics(context.language)
762
+ context.get_metrics(desc)
763
+ end
686
764
 
687
- when Gdk::Keyval::GDK_Left
688
- if @active_view == View::HEX
689
- if @selecting
690
- set_cursor(@cursor_pos - 1)
691
- else
692
- @lower_nibble ^= 1
693
- set_cursor(@cursor_pos - 1) if @lower_nibble
765
+ def draw_shadow(area)
766
+ bw = self.border_width
767
+ x = bw
768
+ xt = widget_get_xt
769
+
770
+ if @show_offsets
771
+ self.style.paint_shadow(
772
+ self.window,
773
+ Gtk::STATE_NORMAL, Gtk::SHADOW_IN,
774
+ nil, self, nil,
775
+ bw, bw,
776
+ 8*@char_width + 2*xt, self.allocation.height - 2*bw
777
+ )
778
+
779
+ x += 8*@char_width + 2*xt
694
780
  end
695
- else
696
- set_cursor(@cursor_pos - 1)
697
- end
698
781
 
699
- when Gdk::Keyval::GDK_Right
700
- if @active_view == View::HEX
701
- if @selecting
702
- set_cursor(@cursor_pos + 1)
703
- else
704
- @lower_nibble ^= 1
705
- set_cursor(@cursor_pos + 1) unless @lower_nibble
706
- end
707
- else
708
- set_cursor(@cursor_pos + 1)
709
- end
710
-
711
- when Gdk::Keyval::GDK_c, Gdk::Keyval::GDK_C
712
- if event.state & Gdk::Window::CONTROL_MASK != 0
713
- s,e = @selection.start, @selection.end + 1
714
- if @active_view == View::HEX
715
- brk_len = 2 * @cpl + @cpl / @group_type
716
- format_xblock(s,e)
717
- (@disp_buffer.size / brk_len + 1).times do |i| @disp_buffer.insert(i * (brk_len + 1), $/) end
718
- else
719
- brk_len = @cpl
720
- format_ablock(s,e)
721
- end
782
+ self.style.paint_shadow(
783
+ self.window,
784
+ Gtk::STATE_NORMAL, Gtk::SHADOW_IN,
785
+ nil, self, nil,
786
+ x, bw,
787
+ @xdisp_width + 2*xt, self.allocation.height - 2*bw
788
+ )
722
789
 
723
- @@clipboard.set_text(@disp_buffer)
724
- end
725
- else
726
- ret = false
727
- end
790
+ self.style.paint_shadow(
791
+ self.window,
792
+ Gtk::STATE_NORMAL, Gtk::SHADOW_IN,
793
+ nil, self, nil,
794
+ self.allocation.width - bw - @adisp_width - @scrollbar.requisition[0] - 2*xt, bw,
795
+ @adisp_width + 2*xt, self.allocation.height - 2*bw
796
+ )
797
+ end
728
798
 
729
- show_cursor
730
-
731
- ret
732
- end
799
+ def redraw_widget
800
+ return unless self.realized?
733
801
 
734
- def hex_to_pointer(mx, my)
735
- cy = @top_line + my.to_i / @char_height
736
-
737
- cx = x = 0
738
- while cx < 2 * @cpl
739
- x += @char_width
802
+ self.window.invalidate(nil, false)
803
+ end
740
804
 
741
- if x > mx
742
- set_cursor_xy(cx / 2, cy)
743
- set_cursor_on_lower_nibble(cx % 2 != 0)
805
+ def widget_get_xt
806
+ self.style.xthickness
807
+ end
744
808
 
745
- cx = 2 * @cpl
809
+ def widget_get_yt
810
+ self.style.ythickness
746
811
  end
747
812
 
748
- cx += 1
749
- x += @char_width if ( cx % (2 * @group_type) == 0 )
750
- end
751
- end
813
+ def recalc_displays(width, height)
814
+ old_cpl = @cpl
752
815
 
753
- def ascii_to_pointer(mx, my)
754
- cx = mx / @char_width
755
- cy = @top_line + my / @char_height
816
+ w, _h = @scrollbar.size_request
817
+ @xdisp_width = 1
818
+ @adisp_width = 1
756
819
 
757
- set_cursor_xy(cx, cy)
758
- end
820
+ total_width = width - 2 * self.border_width - 4 * widget_get_xt - w
821
+ total_width -= 2 * widget_get_xt + 8 * @char_width if @show_offsets
759
822
 
760
- def load_font(fontname)
761
- desc = Pango::FontDescription.new(fontname)
762
- context = Gdk::Pango.context
763
- context.set_language(Gtk.default_language)
764
-
765
- font = context.load_font(desc)
766
-
767
- font.metrics(context.language)
768
- end
823
+ total_cpl = total_width / @char_width
824
+ if total_cpl == 0 or total_width < 0
825
+ @cpl = @lines = @vis_lines = 0
826
+ return
827
+ end
769
828
 
770
- def draw_shadow(area)
771
- bw = self.border_width
772
- x = bw
773
- xt = widget_get_xt
774
-
775
- if @show_offsets
776
- self.style.paint_shadow(
777
- self.window,
778
- Gtk::STATE_NORMAL, Gtk::SHADOW_IN,
779
- nil, self, nil,
780
- bw, bw,
781
- 8*@char_width + 2*xt, self.allocation.height - 2*bw
782
- )
829
+ @cpl = 0
830
+ begin
831
+ break if @cpl % @group_type == 0 and total_cpl < @group_type * 3
783
832
 
784
- x += 8*@char_width + 2*xt
785
- end
786
-
787
- self.style.paint_shadow(
788
- self.window,
789
- Gtk::STATE_NORMAL, Gtk::SHADOW_IN,
790
- nil, self, nil,
791
- x, bw,
792
- @xdisp_width + 2*xt, self.allocation.height - 2*bw
793
- )
794
-
795
- self.style.paint_shadow(
796
- self.window,
797
- Gtk::STATE_NORMAL, Gtk::SHADOW_IN,
798
- nil, self, nil,
799
- self.allocation.width - bw - @adisp_width - @scrollbar.requisition[0] - 2*xt, bw,
800
- @adisp_width + 2*xt, self.allocation.height - 2*bw
801
- )
802
- end
833
+ @cpl += 1
834
+ total_cpl -= 3
803
835
 
804
- def redraw_widget
805
- return unless self.realized?
836
+ total_cpl -= 1 if @cpl % @group_type == 0
837
+ end while total_cpl > 0
806
838
 
807
- self.window.invalidate(nil, false)
808
- end
839
+ return if @cpl == 0
809
840
 
810
- def widget_get_xt
811
- self.style.xthickness
812
- end
841
+ if @data.empty?
842
+ @lines = 1
843
+ else
844
+ @lines = @data.size / @cpl
845
+ @lines += 1 if @data.size % @cpl != 0
846
+ end
813
847
 
814
- def widget_get_yt
815
- self.style.ythickness
816
- end
848
+ @vis_lines = (height - 2*self.border_width - 2*widget_get_yt).to_i / @char_height.to_i
849
+ @adisp_width = @cpl * @char_width + 1
850
+ xcpl = @cpl * 2 + (@cpl - 1) / @group_type
851
+ @xdisp_width = xcpl * @char_width + 1
817
852
 
818
- def recalc_displays(width, height)
819
- old_cpl = @cpl
820
-
821
- w, h = @scrollbar.size_request
822
- @xdisp_width = 1
823
- @adisp_width = 1
824
-
825
- total_width = width - 2 * self.border_width - 4 * widget_get_xt - w
826
- total_width -= 2 * widget_get_xt + 8 * @char_width if @show_offsets
827
-
828
- total_cpl = total_width / @char_width
829
- if total_cpl == 0 or total_width < 0
830
- @cpl = @lines = @vis_lines = 0
831
- return
832
- end
833
-
834
- @cpl = 0
835
- begin
836
- break if @cpl % @group_type == 0 and total_cpl < @group_type * 3
837
-
838
- @cpl += 1
839
- total_cpl -= 3
840
-
841
- total_cpl -= 1 if @cpl % @group_type == 0
842
- end while total_cpl > 0
843
-
844
- return if @cpl == 0
845
-
846
- if @data.empty?
847
- @lines = 1
848
- else
849
- @lines = @data.size / @cpl
850
- @lines += 1 if @data.size % @cpl != 0
851
- end
852
-
853
- @vis_lines = (height - 2*self.border_width - 2*widget_get_yt).to_i / @char_height.to_i
854
- @adisp_width = @cpl * @char_width + 1
855
- xcpl = @cpl * 2 + (@cpl - 1) / @group_type
856
- @xdisp_width = xcpl * @char_width + 1
857
-
858
- @disp_buffer = ''
859
-
860
- @adj.value = [@top_line * old_cpl / @cpl, @lines - @vis_lines].min
861
- @adj.value = [ 0, @adj.value ].max
862
- if @cursor_pos / @cpl < @adj.value or @cursor_pos / @cpl > @adj.value + @vis_lines - 1
863
- @adj.value = [ @cursor_pos / @cpl, @lines - @vis_lines ].min
864
- @adj.value = [ 0, @adj.value ].max
865
- end
866
-
867
- @adj.lower = 0
868
- @adj.upper = @lines
869
- @adj.step_increment = 1
870
- @adj.page_increment = @vis_lines - 1
871
- @adj.page_size = @vis_lines
872
-
873
- @adj.signal_emit 'changed'
874
- @adj.signal_emit 'value_changed'
875
- end
853
+ @disp_buffer = ''
876
854
 
877
- def get_max_char_width(metrics)
855
+ @adj.value = [@top_line * old_cpl / @cpl, @lines - @vis_lines].min
856
+ @adj.value = [ 0, @adj.value ].max
857
+ if @cursor_pos / @cpl < @adj.value or @cursor_pos / @cpl > @adj.value + @vis_lines - 1
858
+ @adj.value = [ @cursor_pos / @cpl, @lines - @vis_lines ].min
859
+ @adj.value = [ 0, @adj.value ].max
860
+ end
878
861
 
879
- layout = self.create_pango_layout('')
880
- layout.set_font_description(@font_desc)
881
- char_widths = [ 0 ]
862
+ @adj.lower = 0
863
+ @adj.upper = @lines
864
+ @adj.step_increment = 1
865
+ @adj.page_increment = @vis_lines - 1
866
+ @adj.page_size = @vis_lines
882
867
 
883
- (1..100).each do |i|
884
- logical_rect = Pango::Rectangle.new(0, 0, 0, 0)
885
- if is_displayable(i.chr)
886
- layout.set_text(i.chr)
887
- logical_rect = layout.pixel_extents[1]
868
+ @adj.signal_emit 'changed'
869
+ @adj.signal_emit 'value_changed'
888
870
  end
889
- char_widths << logical_rect.width
890
- end
891
871
 
892
- char_widths[48..122].max
893
- end
872
+ def get_max_char_width(metrics)
873
+ layout = self.create_pango_layout('')
874
+ layout.set_font_description(@font_desc)
875
+ char_widths = [ 0 ]
876
+
877
+ (1..100).each do |i|
878
+ logical_rect = Pango::Rectangle.new(0, 0, 0, 0)
879
+ if is_displayable(i.chr)
880
+ layout.set_text(i.chr)
881
+ logical_rect = layout.pixel_extents[1]
882
+ end
883
+ char_widths << logical_rect.width
884
+ end
894
885
 
895
- def show_cursor
896
- unless @cursor_shown
897
- if @xdisp_gc and @adisp_gc and @xdisp.realized? and @adisp.realized?
898
- render_xc
899
- render_ac
886
+ char_widths[48..122].max
900
887
  end
901
888
 
902
- @cursor_shown = true
903
- end
904
- end
889
+ def show_cursor
890
+ unless @cursor_shown
891
+ if @xdisp_gc and @adisp_gc and @xdisp.realized? and @adisp.realized?
892
+ render_xc
893
+ render_ac
894
+ end
905
895
 
906
- def hide_cursor
907
- if @cursor_shown
908
- if @xdisp_gc and @adisp_gc and @xdisp.realized? and @adisp.realized?
909
- render_byte(@cursor_pos)
896
+ @cursor_shown = true
897
+ end
910
898
  end
911
899
 
912
- @cursor_shown = false
913
- end
914
- end
900
+ def hide_cursor
901
+ if @cursor_shown
902
+ if @xdisp_gc and @adisp_gc and @xdisp.realized? and @adisp.realized?
903
+ render_byte(@cursor_pos)
904
+ end
915
905
 
916
- def show_offsets_widget
917
- @offsets = DrawingArea.new
918
- @offsets.modify_font @font_desc
919
- @olayout = @offsets.create_pango_layout('')
906
+ @cursor_shown = false
907
+ end
908
+ end
920
909
 
921
- @offsets.events = Gdk::Event::EXPOSURE_MASK
922
- @offsets.signal_connect 'expose_event' do |offsets, event|
923
- imin = (event.area.y / @char_height).to_i
924
- imax = ((event.area.y + event.area.height) / @char_height).to_i
925
- imax += 1 if (event.area.y + event.area.height).to_i % @char_height != 0
910
+ def show_offsets_widget
911
+ @offsets = DrawingArea.new
912
+ @offsets.modify_font @font_desc
913
+ @olayout = @offsets.create_pango_layout('')
926
914
 
927
- imax = [ imax, @vis_lines ].min
915
+ @offsets.events = Gdk::Event::EXPOSURE_MASK
916
+ @offsets.signal_connect 'expose_event' do |_offsets, event|
917
+ imin = (event.area.y / @char_height).to_i
918
+ imax = ((event.area.y + event.area.height) / @char_height).to_i
919
+ imax += 1 if (event.area.y + event.area.height).to_i % @char_height != 0
928
920
 
929
- render_offsets(imin, imax)
930
- end
921
+ imax = [ imax, @vis_lines ].min
931
922
 
932
- put @offsets, 0, 0
933
- @offsets.show
934
- end
923
+ render_offsets(imin, imax)
924
+ end
935
925
 
936
- def hide_offsets_widget
937
- if @offsets
938
- self.remove(@offsets)
939
- @offsets = @offsets_gc = nil
940
- end
941
- end
926
+ put @offsets, 0, 0
927
+ @offsets.show
928
+ end
942
929
 
943
- def is_displayable(c)
944
- if RUBY_VERSION < '1.9'
945
- c = c[0]
946
- else
947
- c = c.ord
948
- end
930
+ def hide_offsets_widget
931
+ if @offsets
932
+ self.remove(@offsets)
933
+ @offsets = @offsets_gc = nil
934
+ end
935
+ end
949
936
 
950
- c >= 0x20 and c < 0x7f
951
- end
937
+ def is_displayable(c)
938
+ c = c.ord
939
+ c >= 0x20 and c < 0x7f
940
+ end
952
941
 
953
- def bytes_changed(s, e)
954
- start_line = s / @cpl - @top_line
955
- end_line = e / @cpl - @top_line
942
+ def bytes_changed(s, e)
943
+ start_line = s / @cpl - @top_line
944
+ end_line = e / @cpl - @top_line
956
945
 
957
- return if end_line < 0 or start_line > @vis_lines
946
+ return if end_line < 0 or start_line > @vis_lines
958
947
 
959
- start_line = [ 0, start_line ].max
948
+ start_line = [ 0, start_line ].max
960
949
 
961
- render_hex_lines(start_line, end_line)
962
- render_ascii_lines(start_line, end_line)
963
- render_offsets(start_line, end_line) if @show_offsets
964
- end
950
+ render_hex_lines(start_line, end_line)
951
+ render_ascii_lines(start_line, end_line)
952
+ render_offsets(start_line, end_line) if @show_offsets
953
+ end
965
954
 
966
- def render_hex_highlights(cursor_line)
967
- xcpl = @cpl * 2 + @cpl / @group_type
968
-
969
- @highlights.each do |hl|
970
- next if (hl.start - hl.end).abs < hl.min_select
971
-
972
- validate_highlight(hl)
973
-
974
- s, e = [ hl.start, hl.end ].sort
975
- sl, el = hl.start_line, hl.end_line
976
-
977
- hl.style.attach(@xdisp.window) if hl.style
978
- state = (@active_view == View::HEX) ? Gtk::STATE_SELECTED : Gtk::STATE_INSENSITIVE
979
-
980
- if cursor_line == sl
981
- cursor_off = 2 * (s % @cpl) + (s % @cpl) / @group_type
982
- if cursor_line == el
983
- len = 2 * (e % @cpl + 1) + (e % @cpl) / @group_type
984
- else
985
- len = xcpl
986
- end
987
-
988
- len -= cursor_off
989
- (hl.style || self.style).paint_flat_box(
990
- @xdisp.window,
991
- state, Gtk::SHADOW_NONE,
992
- nil, @xdisp, '',
993
- cursor_off * @char_width, cursor_line * @char_height,
994
- len * @char_width, @char_height
995
- ) if len > 0
996
-
997
- elsif cursor_line == el
998
- cursor_off = 2 * (e % @cpl + 1) + (e % @cpl) / @group_type
999
- (hl.style || self.style).paint_flat_box(
1000
- @xdisp.window,
1001
- state, Gtk::SHADOW_NONE,
1002
- nil, @xdisp, '',
1003
- 0, cursor_line * @char_height,
1004
- cursor_off * @char_width, @char_height
1005
- ) if cursor_off > 0
1006
-
1007
- elsif cursor_line > sl and cursor_line < el
1008
- (hl.style || self.style).paint_flat_box(
1009
- @xdisp.window,
1010
- state, Gtk::SHADOW_NONE,
1011
- nil, @xdisp, '',
1012
- 0, cursor_line * @char_height,
1013
- xcpl * @char_width, @char_height
1014
- )
955
+ def render_hex_highlights(cursor_line)
956
+ xcpl = @cpl * 2 + @cpl / @group_type
957
+
958
+ @highlights.each do |hl|
959
+ next if (hl.start - hl.end).abs < hl.min_select
960
+
961
+ validate_highlight(hl)
962
+
963
+ s, e = [ hl.start, hl.end ].sort
964
+ sl, el = hl.start_line, hl.end_line
965
+
966
+ hl.style.attach(@xdisp.window) if hl.style
967
+ state = (@active_view == View::HEX) ? Gtk::STATE_SELECTED : Gtk::STATE_INSENSITIVE
968
+
969
+ if cursor_line == sl
970
+ cursor_off = 2 * (s % @cpl) + (s % @cpl) / @group_type
971
+ if cursor_line == el
972
+ len = 2 * (e % @cpl + 1) + (e % @cpl) / @group_type
973
+ else
974
+ len = xcpl
975
+ end
976
+
977
+ len -= cursor_off
978
+ (hl.style || self.style).paint_flat_box(
979
+ @xdisp.window,
980
+ state, Gtk::SHADOW_NONE,
981
+ nil, @xdisp, '',
982
+ cursor_off * @char_width, cursor_line * @char_height,
983
+ len * @char_width, @char_height
984
+ ) if len > 0
985
+
986
+ elsif cursor_line == el
987
+ cursor_off = 2 * (e % @cpl + 1) + (e % @cpl) / @group_type
988
+ (hl.style || self.style).paint_flat_box(
989
+ @xdisp.window,
990
+ state, Gtk::SHADOW_NONE,
991
+ nil, @xdisp, '',
992
+ 0, cursor_line * @char_height,
993
+ cursor_off * @char_width, @char_height
994
+ ) if cursor_off > 0
995
+
996
+ elsif cursor_line > sl and cursor_line < el
997
+ (hl.style || self.style).paint_flat_box(
998
+ @xdisp.window,
999
+ state, Gtk::SHADOW_NONE,
1000
+ nil, @xdisp, '',
1001
+ 0, cursor_line * @char_height,
1002
+ xcpl * @char_width, @char_height
1003
+ )
1004
+ end
1005
+
1006
+ hl.style.attach(@adisp.window) if hl.style
1007
+ end
1015
1008
  end
1016
-
1017
- hl.style.attach(@adisp.window) if hl.style
1018
- end
1019
- end
1020
1009
 
1021
- def render_hex_lines(imin, imax)
1022
- return unless self.realized? and @cpl != 0
1010
+ def render_hex_lines(imin, imax)
1011
+ return unless self.realized? and @cpl != 0
1023
1012
 
1024
- cursor_line = @cursor_pos / @cpl - @top_line
1013
+ cursor_line = @cursor_pos / @cpl - @top_line
1025
1014
 
1026
- @xdisp_gc.set_foreground(self.style.base(Gtk::STATE_NORMAL))
1027
- @xdisp.window.draw_rectangle(
1028
- @xdisp_gc,
1029
- true,
1030
- 0,
1031
- imin * @char_height,
1032
- @xdisp.allocation.width,
1033
- (imax - imin + 1) * @char_height
1034
- )
1015
+ @xdisp_gc.set_foreground(self.style.base(Gtk::STATE_NORMAL))
1016
+ @xdisp.window.draw_rectangle(
1017
+ @xdisp_gc,
1018
+ true,
1019
+ 0,
1020
+ imin * @char_height,
1021
+ @xdisp.allocation.width,
1022
+ (imax - imin + 1) * @char_height
1023
+ )
1035
1024
 
1036
- imax = [ imax, @vis_lines, @lines ].min
1025
+ imax = [ imax, @vis_lines, @lines ].min
1037
1026
 
1038
- @xdisp_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL))
1027
+ @xdisp_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL))
1039
1028
 
1040
- frm_len = format_xblock((@top_line+imin) * @cpl, [(@top_line+imax+1) * @cpl, @data.size].min)
1029
+ frm_len = format_xblock((@top_line+imin) * @cpl, [(@top_line+imax+1) * @cpl, @data.size].min)
1041
1030
 
1042
- tmp = nil
1043
- xcpl = @cpl*2 + @cpl/@group_type
1044
- (imin..imax).each do |i|
1045
- return unless (tmp = frm_len - ((i - imin) * xcpl)) > 0
1046
-
1047
- render_hex_highlights(i)
1048
- text = @disp_buffer[(i-imin) * xcpl, [xcpl, tmp].min]
1049
- @xlayout.set_text(text)
1050
- @xdisp.window.draw_layout(@xdisp_gc, 0, i * @char_height, @xlayout)
1051
- end
1031
+ tmp = nil
1032
+ xcpl = @cpl*2 + @cpl/@group_type
1033
+ (imin..imax).each do |i|
1034
+ return unless (tmp = frm_len - ((i - imin) * xcpl)) > 0
1052
1035
 
1053
- render_xc if cursor_line >= imin and cursor_line <= imax and @cursor_shown
1054
- end
1036
+ render_hex_highlights(i)
1037
+ text = @disp_buffer[(i-imin) * xcpl, [xcpl, tmp].min]
1038
+ @xlayout.set_text(text)
1039
+ @xdisp.window.draw_layout(@xdisp_gc, 0, i * @char_height, @xlayout)
1040
+ end
1041
+
1042
+ render_xc if cursor_line >= imin and cursor_line <= imax and @cursor_shown
1043
+ end
1055
1044
 
1056
- def render_ascii_highlights(cursor_line)
1057
- @highlights.each do |hl|
1058
- next if (hl.start - hl.end).abs < hl.min_select
1045
+ def render_ascii_highlights(cursor_line)
1046
+ @highlights.each do |hl|
1047
+ next if (hl.start - hl.end).abs < hl.min_select
1048
+
1049
+ validate_highlight(hl)
1050
+
1051
+ s, e = [ hl.start, hl.end ].sort
1052
+ sl, el = hl.start_line, hl.end_line
1053
+
1054
+ hl.style.attach(@adisp.window) if hl.style
1055
+ state = (@active_view == View::ASCII) ? Gtk::STATE_SELECTED : Gtk::STATE_INSENSITIVE
1056
+
1057
+ if cursor_line == sl
1058
+ cursor_off = s % @cpl
1059
+ len =
1060
+ if cursor_line == el
1061
+ e - s + 1
1062
+ else
1063
+ @cpl - cursor_off
1064
+ end
1065
+
1066
+ (hl.style || self.style).paint_flat_box(
1067
+ @adisp.window,
1068
+ state, Gtk::SHADOW_NONE,
1069
+ nil, @adisp, '',
1070
+ cursor_off * @char_width, cursor_line * @char_height,
1071
+ len * @char_width, @char_height
1072
+ ) if len > 0
1073
+
1074
+ elsif cursor_line == el
1075
+ cursor_off = e % @cpl + 1
1076
+ (hl.style || self.style).paint_flat_box(
1077
+ @adisp.window,
1078
+ state, Gtk::SHADOW_NONE,
1079
+ nil, @adisp, '',
1080
+ 0, cursor_line * @char_height,
1081
+ cursor_off * @char_width, @char_height
1082
+ ) if cursor_off > 0
1083
+
1084
+ elsif cursor_line > sl and cursor_line < el
1085
+ (hl.style || self.style).paint_flat_box(
1086
+ @adisp.window,
1087
+ state, Gtk::SHADOW_NONE,
1088
+ nil, @adisp, '',
1089
+ 0, cursor_line * @char_height,
1090
+ @cpl * @char_width, @char_height
1091
+ )
1092
+ end
1093
+
1094
+ hl.style.attach(@adisp.window) if hl.style
1095
+ end
1096
+ end
1059
1097
 
1060
- validate_highlight(hl)
1098
+ def render_ascii_lines(imin, imax)
1099
+ return unless self.realized? and @cpl != 0
1061
1100
 
1062
- s, e = [ hl.start, hl.end ].sort
1063
- sl, el = hl.start_line, hl.end_line
1101
+ cursor_line = @cursor_pos / @cpl - @top_line
1064
1102
 
1065
- hl.style.attach(@adisp.window) if hl.style
1066
- state = (@active_view == View::ASCII) ? Gtk::STATE_SELECTED : Gtk::STATE_INSENSITIVE
1103
+ @adisp_gc.set_foreground(self.style.base(Gtk::STATE_NORMAL))
1104
+ @adisp.window.draw_rectangle(
1105
+ @adisp_gc,
1106
+ true,
1107
+ 0,
1108
+ imin * @char_height,
1109
+ @adisp.allocation.width,
1110
+ (imax - imin + 1) * @char_height
1111
+ )
1067
1112
 
1068
- if cursor_line == sl
1069
- cursor_off = s % @cpl
1070
- len =
1071
- if cursor_line == el
1072
- e - s + 1
1073
- else
1074
- @cpl - cursor_off
1113
+ imax = [ imax, @vis_lines, @lines ].min
1114
+
1115
+ @adisp_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL))
1116
+
1117
+ frm_len = format_ablock((@top_line+imin) * @cpl, [(@top_line+imax+1) * @cpl, @data.size].min)
1118
+
1119
+ tmp = nil
1120
+ (imin..imax).each do |i|
1121
+ return unless (tmp = frm_len - ((i - imin) * @cpl)) > 0
1122
+
1123
+ render_ascii_highlights(i)
1124
+ text = @disp_buffer[(i-imin) * @cpl, [@cpl, tmp].min]
1125
+ @alayout.set_text(text)
1126
+ @adisp.window.draw_layout(@adisp_gc, 0, i * @char_height, @alayout)
1075
1127
  end
1076
1128
 
1077
- (hl.style || self.style).paint_flat_box(
1078
- @adisp.window,
1079
- state, Gtk::SHADOW_NONE,
1080
- nil, @adisp, '',
1081
- cursor_off * @char_width, cursor_line * @char_height,
1082
- len * @char_width, @char_height
1083
- ) if len > 0
1084
-
1085
- elsif cursor_line == el
1086
- cursor_off = e % @cpl + 1
1087
- (hl.style || self.style).paint_flat_box(
1088
- @adisp.window,
1089
- state, Gtk::SHADOW_NONE,
1090
- nil, @adisp, '',
1091
- 0, cursor_line * @char_height,
1092
- cursor_off * @char_width, @char_height
1093
- ) if cursor_off > 0
1094
-
1095
- elsif cursor_line > sl and cursor_line < el
1096
- (hl.style || self.style).paint_flat_box(
1097
- @adisp.window,
1098
- state, Gtk::SHADOW_NONE,
1099
- nil, @adisp, '',
1100
- 0, cursor_line * @char_height,
1101
- @cpl * @char_width, @char_height
1102
- )
1129
+ render_ac if cursor_line >= imin and cursor_line <= imax and @cursor_shown
1103
1130
  end
1104
1131
 
1105
- hl.style.attach(@adisp.window) if hl.style
1106
- end
1107
- end
1132
+ def render_offsets(imin, imax)
1133
+ return unless self.realized?
1108
1134
 
1109
- def render_ascii_lines(imin, imax)
1110
- return unless self.realized? and @cpl != 0
1111
-
1112
- cursor_line = @cursor_pos / @cpl - @top_line
1113
-
1114
- @adisp_gc.set_foreground(self.style.base(Gtk::STATE_NORMAL))
1115
- @adisp.window.draw_rectangle(
1116
- @adisp_gc,
1117
- true,
1118
- 0,
1119
- imin * @char_height,
1120
- @adisp.allocation.width,
1121
- (imax - imin + 1) * @char_height
1122
- )
1123
-
1124
- imax = [ imax, @vis_lines, @lines ].min
1125
-
1126
- @adisp_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL))
1127
-
1128
- frm_len = format_ablock((@top_line+imin) * @cpl, [(@top_line+imax+1) * @cpl, @data.size].min)
1129
-
1130
- tmp = nil
1131
- (imin..imax).each do |i|
1132
- return unless (tmp = frm_len - ((i - imin) * @cpl)) > 0
1133
-
1134
- render_ascii_highlights(i)
1135
- text = @disp_buffer[(i-imin) * @cpl, [@cpl, tmp].min]
1136
- @alayout.set_text(text)
1137
- @adisp.window.draw_layout(@adisp_gc, 0, i * @char_height, @alayout)
1138
- end
1139
-
1140
- render_ac if cursor_line >= imin and cursor_line <= imax and @cursor_shown
1141
- end
1135
+ unless @offsets_gc
1136
+ @offsets_gc = Gdk::GC.new(@offsets.window)
1137
+ @offsets_gc.set_exposures(true)
1138
+ end
1142
1139
 
1143
- def render_offsets(imin, imax)
1144
- return unless self.realized?
1145
-
1146
- unless @offsets_gc
1147
- @offsets_gc = Gdk::GC.new(@offsets.window)
1148
- @offsets_gc.set_exposures(true)
1149
- end
1150
-
1151
- @offsets_gc.set_foreground(self.style.base(Gtk::STATE_INSENSITIVE))
1152
- @offsets.window.draw_rectangle(
1153
- @offsets_gc,
1154
- true,
1155
- 0, imin * @char_height,
1156
- @offsets.allocation.width, (imax - imin + 1) * @char_height
1157
- )
1158
-
1159
- imax = [ imax, @vis_lines, @lines - @top_line - 1 ].min
1160
- @offsets_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL))
1161
-
1162
- (imin..imax).each do |i|
1163
- text = "%08x" % ((@top_line + i) * @cpl + @starting_offset)
1164
- @olayout.set_text(text)
1165
- @offsets.window.draw_layout(@offsets_gc, 0, i * @char_height, @olayout)
1166
- end
1167
- end
1140
+ @offsets_gc.set_foreground(self.style.base(Gtk::STATE_INSENSITIVE))
1141
+ @offsets.window.draw_rectangle(
1142
+ @offsets_gc,
1143
+ true,
1144
+ 0, imin * @char_height,
1145
+ @offsets.allocation.width, (imax - imin + 1) * @char_height
1146
+ )
1168
1147
 
1169
- def render_byte(pos)
1170
- return unless @xdisp_gc and @adisp_gc and @xdisp.realized? and @adisp.realized?
1171
-
1172
- return unless (coords = get_xcoords(pos))
1173
- cx, cy = coords
1174
- c = format_xbyte(pos)
1175
-
1176
- @xdisp_gc.set_foreground(self.style.base(Gtk::STATE_NORMAL))
1177
- @xdisp.window.draw_rectangle(
1178
- @xdisp_gc,
1179
- true,
1180
- cx, cy,
1181
- 2 * @char_width, @char_height
1182
- )
1183
-
1184
- if pos < @data.size
1185
- @xdisp_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL))
1186
- @xlayout.set_text(c)
1187
- @xdisp.window.draw_layout(@xdisp_gc, cx, cy, @xlayout)
1188
- end
1189
-
1190
- return unless (coords = get_acoords(pos))
1191
- cx, cy = coords
1192
-
1193
- @adisp_gc.set_foreground(self.style.base(Gtk::STATE_NORMAL))
1194
- @adisp.window.draw_rectangle(
1195
- @adisp_gc,
1196
- true,
1197
- cx, cy,
1198
- @char_width, @char_height
1199
- )
1200
-
1201
- if pos < @data.size
1202
- @adisp_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL))
1203
- c = get_byte(pos)
1204
- c = '.' unless is_displayable(c)
1205
-
1206
- @alayout.set_text(c)
1207
- @adisp.window.draw_layout(@adisp_gc, cx, cy, @alayout)
1208
- end
1209
- end
1148
+ imax = [ imax, @vis_lines, @lines - @top_line - 1 ].min
1149
+ @offsets_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL))
1150
+
1151
+ (imin..imax).each do |i|
1152
+ text = "%08x" % ((@top_line + i) * @cpl + @starting_offset)
1153
+ @olayout.set_text(text)
1154
+ @offsets.window.draw_layout(@offsets_gc, 0, i * @char_height, @olayout)
1155
+ end
1156
+ end
1157
+
1158
+ def render_byte(pos)
1159
+ return unless @xdisp_gc and @adisp_gc and @xdisp.realized? and @adisp.realized?
1160
+
1161
+ return unless (coords = get_xcoords(pos))
1162
+ cx, cy = coords
1163
+ c = format_xbyte(pos)
1210
1164
 
1211
- def render_xc
1212
- return unless @xdisp.realized?
1165
+ @xdisp_gc.set_foreground(self.style.base(Gtk::STATE_NORMAL))
1166
+ @xdisp.window.draw_rectangle(
1167
+ @xdisp_gc,
1168
+ true,
1169
+ cx, cy,
1170
+ 2 * @char_width, @char_height
1171
+ )
1172
+
1173
+ if pos < @data.size
1174
+ @xdisp_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL))
1175
+ @xlayout.set_text(c)
1176
+ @xdisp.window.draw_layout(@xdisp_gc, cx, cy, @xlayout)
1177
+ end
1213
1178
 
1214
- if coords = get_xcoords(@cursor_pos)
1215
- cx, cy = coords
1179
+ return unless (coords = get_acoords(pos))
1180
+ cx, cy = coords
1216
1181
 
1217
- c = format_xbyte(@cursor_pos)
1218
- if @lower_nibble
1219
- cx += @char_width
1220
- c = c[1,1]
1221
- else
1222
- c = c[0,1]
1182
+ @adisp_gc.set_foreground(self.style.base(Gtk::STATE_NORMAL))
1183
+ @adisp.window.draw_rectangle(
1184
+ @adisp_gc,
1185
+ true,
1186
+ cx, cy,
1187
+ @char_width, @char_height
1188
+ )
1189
+
1190
+ if pos < @data.size
1191
+ @adisp_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL))
1192
+ c = get_byte(pos)
1193
+ c = '.' unless is_displayable(c)
1194
+
1195
+ @alayout.set_text(c)
1196
+ @adisp.window.draw_layout(@adisp_gc, cx, cy, @alayout)
1197
+ end
1223
1198
  end
1224
1199
 
1225
- @xdisp_gc.set_foreground(self.style.base(Gtk::STATE_ACTIVE))
1226
- @xdisp.window.draw_rectangle(
1227
- @xdisp_gc,
1228
- (@active_view == View::HEX),
1229
- cx, cy,
1230
- @char_width,
1231
- @char_height - 1
1232
- )
1233
- @xdisp_gc.set_foreground(self.style.text(Gtk::STATE_ACTIVE))
1234
- @xlayout.set_text(c)
1235
- @xdisp.window.draw_layout(@xdisp_gc, cx, cy, @xlayout)
1236
- end
1237
- end
1200
+ def render_xc
1201
+ return unless @xdisp.realized?
1202
+
1203
+ if coords = get_xcoords(@cursor_pos)
1204
+ cx, cy = coords
1205
+
1206
+ c = format_xbyte(@cursor_pos)
1207
+ if @lower_nibble
1208
+ cx += @char_width
1209
+ c = c[1,1]
1210
+ else
1211
+ c = c[0,1]
1212
+ end
1213
+
1214
+ @xdisp_gc.set_foreground(self.style.base(Gtk::STATE_ACTIVE))
1215
+ @xdisp.window.draw_rectangle(
1216
+ @xdisp_gc,
1217
+ (@active_view == View::HEX),
1218
+ cx, cy,
1219
+ @char_width,
1220
+ @char_height - 1
1221
+ )
1222
+ @xdisp_gc.set_foreground(self.style.text(Gtk::STATE_ACTIVE))
1223
+ @xlayout.set_text(c)
1224
+ @xdisp.window.draw_layout(@xdisp_gc, cx, cy, @xlayout)
1225
+ end
1226
+ end
1238
1227
 
1239
- def render_ac
1240
- return unless @adisp.realized?
1241
-
1242
- if coords = get_acoords(@cursor_pos)
1243
- cx, cy = coords
1244
-
1245
- c = get_byte(@cursor_pos)
1246
- c = '.' unless is_displayable(c)
1247
-
1248
- @adisp_gc.set_foreground(self.style.base(Gtk::STATE_ACTIVE))
1249
- @adisp.window.draw_rectangle(
1250
- @adisp_gc,
1251
- (@active_view == View::ASCII),
1252
- cx, cy,
1253
- @char_width,
1254
- @char_height - 1
1255
- )
1256
- @adisp_gc.set_foreground(self.style.text(Gtk::STATE_ACTIVE))
1257
- @alayout.set_text(c)
1258
- @adisp.window.draw_layout(@adisp_gc, cx, cy, @alayout)
1259
- end
1260
- end
1228
+ def render_ac
1229
+ return unless @adisp.realized?
1230
+
1231
+ if coords = get_acoords(@cursor_pos)
1232
+ cx, cy = coords
1233
+
1234
+ c = get_byte(@cursor_pos)
1235
+ c = '.' unless is_displayable(c)
1236
+
1237
+ @adisp_gc.set_foreground(self.style.base(Gtk::STATE_ACTIVE))
1238
+ @adisp.window.draw_rectangle(
1239
+ @adisp_gc,
1240
+ (@active_view == View::ASCII),
1241
+ cx, cy,
1242
+ @char_width,
1243
+ @char_height - 1
1244
+ )
1245
+ @adisp_gc.set_foreground(self.style.text(Gtk::STATE_ACTIVE))
1246
+ @alayout.set_text(c)
1247
+ @adisp.window.draw_layout(@adisp_gc, cx, cy, @alayout)
1248
+ end
1249
+ end
1261
1250
 
1262
- def get_xcoords(pos)
1263
- return nil if @cpl == 0
1251
+ def get_xcoords(pos)
1252
+ return nil if @cpl == 0
1264
1253
 
1265
- cy = pos / @cpl - @top_line
1266
- return nil if cy < 0
1254
+ cy = pos / @cpl - @top_line
1255
+ return nil if cy < 0
1267
1256
 
1268
- cx = 2 * (pos % @cpl)
1269
- spaces = (pos % @cpl) / @group_type
1257
+ cx = 2 * (pos % @cpl)
1258
+ spaces = (pos % @cpl) / @group_type
1270
1259
 
1271
- cx *= @char_width
1272
- cy *= @char_height
1273
- spaces *= @char_width
1260
+ cx *= @char_width
1261
+ cy *= @char_height
1262
+ spaces *= @char_width
1274
1263
 
1275
- [cx + spaces, cy]
1276
- end
1264
+ [cx + spaces, cy]
1265
+ end
1277
1266
 
1278
- def get_acoords(pos)
1279
- return nil if @cpl == 0
1267
+ def get_acoords(pos)
1268
+ return nil if @cpl == 0
1280
1269
 
1281
- cy = pos / @cpl - @top_line
1282
- return nil if cy < 0
1270
+ cy = pos / @cpl - @top_line
1271
+ return nil if cy < 0
1283
1272
 
1284
- cy *= @char_height
1285
- cx = @char_width * (pos % @cpl)
1273
+ cy *= @char_height
1274
+ cx = @char_width * (pos % @cpl)
1286
1275
 
1287
- [cx, cy]
1288
- end
1276
+ [cx, cy]
1277
+ end
1289
1278
 
1290
- def format_xblock(s, e)
1291
- @disp_buffer = ''
1279
+ def format_xblock(s, e)
1280
+ @disp_buffer = ''
1292
1281
 
1293
- (s+1..e).each do |i|
1294
- @disp_buffer << get_byte(i - 1).unpack('H2')[0]
1295
- @disp_buffer << ' ' if i % @group_type == 0
1296
- end
1282
+ (s+1..e).each do |i|
1283
+ @disp_buffer << get_byte(i - 1).unpack('H2')[0]
1284
+ @disp_buffer << ' ' if i % @group_type == 0
1285
+ end
1297
1286
 
1298
- @disp_buffer.size
1299
- end
1287
+ @disp_buffer.size
1288
+ end
1300
1289
 
1301
- def format_ablock(s, e)
1302
- @disp_buffer = ''
1290
+ def format_ablock(s, e)
1291
+ @disp_buffer = ''
1303
1292
 
1304
- (s..e-1).each do |i|
1305
- c = get_byte(i)
1306
- c = '.' unless is_displayable(c)
1307
- @disp_buffer << c
1308
- end
1293
+ (s..e-1).each do |i|
1294
+ c = get_byte(i)
1295
+ c = '.' unless is_displayable(c)
1296
+ @disp_buffer << c
1297
+ end
1309
1298
 
1310
- @disp_buffer.size
1311
- end
1299
+ @disp_buffer.size
1300
+ end
1312
1301
 
1313
- def get_byte(offset)
1314
- if offset >= 0 and offset < @data.size
1315
- @data[offset, 1]
1316
- else
1317
- 0.chr
1318
- end
1319
- end
1302
+ def get_byte(offset)
1303
+ if offset >= 0 and offset < @data.size
1304
+ @data[offset, 1]
1305
+ else
1306
+ 0.chr
1307
+ end
1308
+ end
1320
1309
 
1321
- def format_xbyte(pos)
1322
- get_byte(pos).unpack('H2')[0]
1310
+ def format_xbyte(pos)
1311
+ get_byte(pos).unpack('H2')[0]
1312
+ end
1323
1313
  end
1324
- end
1325
-
1326
1314
  end
1327
1315
 
1328
1316
  __END__
@@ -1330,7 +1318,7 @@ hexedit = Gtk::HexEditor.new(File.read '/bin/cat')
1330
1318
  hexedit.show_offsets(true)
1331
1319
  hexedit.set_cursor 2
1332
1320
  hexedit.set_cursor_on_lower_nibble true
1333
- hexedit.set_font 'Terminus 12'
1321
+ hexedit.set_font 'Monospace 12'
1334
1322
  hexedit.set_group_type Gtk::HexEditor::Group::LONG
1335
1323
 
1336
1324
  window = Gtk::Window.new