ruby-gtkhex 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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