bin/gui/gtkhex.rb in origami-1.2.7 vs bin/gui/gtkhex.rb in origami-2.0.0

- old
+ new

@@ -1,1329 +1,1314 @@ =begin -= File - gtkhex.rb + This file is part of PDF Walker, a graphical PDF file browser + Copyright (C) 2016 Guillaume Delugré. -= Info - This file is part of PDF Walker, a graphical PDF file browser - Copyright (C) 2010 Guillaume Delugré <guillaume AT security-labs DOT org> - All right reserved. - - PDF Walker is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + PDF Walker is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - PDF Walker is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + PDF Walker is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with PDF Walker. If not, see <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with PDF Walker. If not, see <http://www.gnu.org/licenses/>. - This work has been derived from the GHex project. Thanks to them. - Original implementation: Jaka Mocnik <jaka@gnu.org> + This work has been derived from the GHex project. Thanks to them. + Original implementation: Jaka Mocnik <jaka@gnu.org> =end require 'gtk2' module Gtk - - class HexEditor < Fixed - module View - HEX = 1 - ASCII = 2 - end - module Group - BYTE = 1 - WORD = 2 - LONG = 4 - end + class HexEditor < Fixed + module View + HEX = 1 + ASCII = 2 + end - class Highlight - attr_accessor :start, :end - attr_accessor :start_line, :end_line - attr_accessor :style - attr_accessor :min_select - attr_accessor :valid - end + module Group + BYTE = 1 + WORD = 2 + LONG = 4 + end - class AutoHighlight - attr_accessor :search_view - attr_accessor :search_string - attr_accessor :search_len + class Highlight + attr_accessor :start, :end + attr_accessor :start_line, :end_line + attr_accessor :style + attr_accessor :min_select + attr_accessor :valid + end - attr_accessor :color + class AutoHighlight + attr_accessor :search_view + attr_accessor :search_string + attr_accessor :search_len - attr_accessor :view_min - attr_accessor :view_max + attr_accessor :color - attr_accessor :highlights - end + attr_accessor :view_min + attr_accessor :view_max - DEFAULT_FONT = "Monospace 12" - DEFAULT_CPL = 32 - DEFAULT_LINES = 16 - DISPLAY_BORDER = 4 - SCROLL_TIMEOUT = 100 + attr_accessor :highlights + end - type_register + DEFAULT_FONT = "Monospace 12" + DEFAULT_CPL = 32 + DEFAULT_LINES = 16 + DISPLAY_BORDER = 4 + SCROLL_TIMEOUT = 100 - @@primary = Clipboard.get(Gdk::Selection::PRIMARY) - @@clipboard = Clipboard.get(Gdk::Selection::CLIPBOARD) + type_register - def initialize(data = '') - super() + @@primary = Clipboard.get(Gdk::Selection::PRIMARY) + @@clipboard = Clipboard.get(Gdk::Selection::CLIPBOARD) - @data = data - if RUBY_VERSION >= '1.9' - @data.force_encoding('binary') - end + def initialize(data = '') + super() - @scroll_timeout = -1 - @disp_buffer = "" - @starting_offset = 0 + @data = data.force_encoding('binary') - @xdisp_width = @adisp_width = 200 - @xdisp_gc = @adisp_gc = nil - @active_view = View::HEX - @group_type = Group::BYTE - @lines = @vis_lines = @top_line = @cpl = 0 - @cursor_pos = 0 - @lower_nibble = false - @cursor_shown = false - @button = 0 - @insert = false - @selecting = false + @scroll_timeout = -1 + @disp_buffer = "" + @starting_offset = 0 - @selection = Highlight.new - @selection.start = @selection.end = 0 - @selection.style = nil - @selection.min_select = 1 - @selection.valid = false + @xdisp_width = @adisp_width = 200 + @xdisp_gc = @adisp_gc = nil + @active_view = View::HEX + @group_type = Group::BYTE + @lines = @vis_lines = @top_line = @cpl = 0 + @cursor_pos = 0 + @lower_nibble = false + @cursor_shown = false + @button = 0 + @insert = false + @selecting = false - @highlights = [ @selection ] + @selection = Highlight.new + @selection.start = @selection.end = 0 + @selection.style = nil + @selection.min_select = 1 + @selection.valid = false - @auto_highlight = nil + @highlights = [ @selection ] - @disp_font_metrics = load_font DEFAULT_FONT - @font_desc = Pango::FontDescription.new DEFAULT_FONT + @auto_highlight = nil - @char_width = get_max_char_width(@disp_font_metrics) - @char_height = Pango.pixels(@disp_font_metrics.ascent) + Pango.pixels(@disp_font_metrics.descent) + 2 + @disp_font_metrics = load_font DEFAULT_FONT + @font_desc = Pango::FontDescription.new DEFAULT_FONT - self.can_focus = true - self.events = Gdk::Event::KEY_PRESS_MASK - self.border_width = DISPLAY_BORDER + @char_width = get_max_char_width(@disp_font_metrics) + @char_height = Pango.pixels(@disp_font_metrics.ascent) + Pango.pixels(@disp_font_metrics.descent) + 2 - mouse_handler = lambda do |widget, event| - if event.event_type == Gdk::Event::BUTTON_RELEASE and event.button == 1 - if @scroll_timeout - GLib::Source.remove @scroll_timeout - @scroll_timeout = nil - @scroll_dir = 0 - end + @show_offsets = false + @offsets_gc = nil - @selecting = false - Gtk.grab_remove(widget) - @button = 0 - elsif event.event_type == Gdk::Event::BUTTON_PRESS and event.button == 1 - self.grab_focus unless self.has_focus? + self.can_focus = true + self.events = Gdk::Event::KEY_PRESS_MASK + self.border_width = DISPLAY_BORDER - Gtk.grab_add(widget) - @button = event.button + mouse_handler = lambda do |widget, event| + if event.event_type == Gdk::Event::BUTTON_RELEASE and event.button == 1 + if @scroll_timeout + GLib::Source.remove @scroll_timeout + @scroll_timeout = nil + @scroll_dir = 0 + end - focus_view = (widget == @xdisp) ? View::HEX : View::ASCII + @selecting = false + Gtk.grab_remove(widget) + @button = 0 + elsif event.event_type == Gdk::Event::BUTTON_PRESS and event.button == 1 + self.grab_focus unless self.has_focus? - if @active_view == focus_view - if @active_view == View::HEX - hex_to_pointer(event.x, event.y) - else - ascii_to_pointer(event.x, event.y) + Gtk.grab_add(widget) + @button = event.button + + focus_view = (widget == @xdisp) ? View::HEX : View::ASCII + + if @active_view == focus_view + if @active_view == View::HEX + hex_to_pointer(event.x, event.y) + else + ascii_to_pointer(event.x, event.y) + end + + unless @selecting + @selecting = true + set_selection(@cursor_pos, @cursor_pos) + end + else + hide_cursor + @active_view = focus_view + show_cursor + end + elsif event.event_type == Gdk::Event::BUTTON_PRESS and event.button == 2 + # TODO + else + @button = 0 + end end - unless @selecting - @selecting = true - set_selection(@cursor_pos, @cursor_pos) + @xdisp = DrawingArea.new + @xdisp.modify_font @font_desc + @xlayout = @xdisp.create_pango_layout('') + @xdisp.events = + Gdk::Event::EXPOSURE_MASK | + Gdk::Event::BUTTON_PRESS_MASK | + Gdk::Event::BUTTON_RELEASE_MASK | + Gdk::Event::BUTTON_MOTION_MASK | + Gdk::Event::SCROLL_MASK + + @xdisp.signal_connect 'realize' do + @xdisp_gc = Gdk::GC.new(@xdisp.window) + @xdisp_gc.set_exposures(true) end - else - hide_cursor - @active_view = focus_view - show_cursor - end - elsif event.event_type == Gdk::Event::BUTTON_PRESS and event.button == 2 - # TODO - else - @button = 0 - end - end - @xdisp = DrawingArea.new - @xdisp.modify_font @font_desc - @xlayout = @xdisp.create_pango_layout('') - @xdisp.events = - Gdk::Event::EXPOSURE_MASK | - Gdk::Event::BUTTON_PRESS_MASK | - Gdk::Event::BUTTON_RELEASE_MASK | - Gdk::Event::BUTTON_MOTION_MASK | - Gdk::Event::SCROLL_MASK + @xdisp.signal_connect 'expose_event' do |xdisp, event| + imin = (event.area.y / @char_height).to_i + imax = ((event.area.y + event.area.height) / @char_height).to_i + imax += 1 if (event.area.y + event.area.height).to_i % @char_height != 0 - @xdisp.signal_connect 'realize' do - @xdisp_gc = Gdk::GC.new(@xdisp.window) - @xdisp_gc.set_exposures(true) - end + imax = [ imax, @vis_lines ].min - @xdisp.signal_connect 'expose_event' do |xdisp, event| - imin = (event.area.y / @char_height).to_i - imax = ((event.area.y + event.area.height) / @char_height).to_i - imax += 1 if (event.area.y + event.area.height).to_i % @char_height != 0 + render_hex_lines(imin, imax) + end - imax = [ imax, @vis_lines ].min + @xdisp.signal_connect 'scroll_event' do |xdisp, event| + @scrollbar.event(event) + end - render_hex_lines(imin, imax) - end + @xdisp.signal_connect 'button_press_event' do |xdisp, event| + mouse_handler[xdisp, event] + end - @xdisp.signal_connect 'scroll_event' do |xdisp, event| - @scrollbar.event(event) - end + @xdisp.signal_connect 'button_release_event' do |xdisp, event| + mouse_handler[xdisp, event] + end - @xdisp.signal_connect 'button_press_event' do |xdisp, event| - mouse_handler[xdisp, event] - end + @xdisp.signal_connect 'motion_notify_event' do |xdisp, event| + _w, x, y, _m = xdisp.window.pointer - @xdisp.signal_connect 'button_release_event' do |xdisp, event| - mouse_handler[xdisp, event] - end + if y < 0 + @scroll_dir = -1 + elsif y >= xdisp.allocation.height + @scroll_dir = 1 + else + @scroll_dir = 0 + end - @xdisp.signal_connect 'motion_notify_event' do |xdisp, event| - w, x, y, m = xdisp.window.pointer + if @scroll_dir != 0 + if @scroll_timeout == nil + @scroll_timeout = GLib::Timeout.add(SCROLL_TIMEOUT) { + if @scroll_dir < 0 + set_cursor([ 0, @cursor_pos - @cpl ].max) + elsif @scroll_dir > 0 + set_cursor([ @data.size - 1, @cursor_pos + @cpl ].min) + end - if y < 0 - @scroll_dir = -1 - elsif y >= xdisp.allocation.height - @scroll_dir = 1 - else - @scroll_dir = 0 - end + true + } + next + end + else + if @scroll_timeout != nil + GLib::Source.remove @scroll_timeout + @scroll_timeout = nil + end + end - if @scroll_dir != 0 - if @scroll_timeout == nil - @scroll_timeout = GLib::Timeout.add(SCROLL_TIMEOUT) { - if @scroll_dir < 0 - set_cursor([ 0, @cursor_pos - @cpl ].max) - elsif @scroll_dir > 0 - set_cursor([ @data.size - 1, @cursor_pos + @cpl ].min) - end + next if event.window != xdisp.window - true - } - next - end - else - if @scroll_timeout != nil - GLib::Source.remove @scroll_timeout - @scroll_timeout = nil - end - end + hex_to_pointer(x,y) if @active_view == View::HEX and @button == 1 + end - next if event.window != xdisp.window + put @xdisp, 0, 0 + @xdisp.show - hex_to_pointer(x,y) if @active_view == View::HEX and @button == 1 - end - - put @xdisp, 0, 0 - @xdisp.show + @adisp = DrawingArea.new + @adisp.modify_font @font_desc + @alayout = @adisp.create_pango_layout('') + @adisp.events = + Gdk::Event::EXPOSURE_MASK | + Gdk::Event::BUTTON_PRESS_MASK | + Gdk::Event::BUTTON_RELEASE_MASK | + Gdk::Event::BUTTON_MOTION_MASK | + Gdk::Event::SCROLL_MASK - @adisp = DrawingArea.new - @adisp.modify_font @font_desc - @alayout = @adisp.create_pango_layout('') - @adisp.events = - Gdk::Event::EXPOSURE_MASK | - Gdk::Event::BUTTON_PRESS_MASK | - Gdk::Event::BUTTON_RELEASE_MASK | - Gdk::Event::BUTTON_MOTION_MASK | - Gdk::Event::SCROLL_MASK + @adisp.signal_connect 'realize' do + @adisp_gc = Gdk::GC.new(@adisp.window) + @adisp_gc.set_exposures(true) + end - - @adisp.signal_connect 'realize' do - @adisp_gc = Gdk::GC.new(@adisp.window) - @adisp_gc.set_exposures(true) - end + @adisp.signal_connect 'expose_event' do |adisp, event| + imin = (event.area.y / @char_height).to_i + imax = ((event.area.y + event.area.height) / @char_height).to_i + imax += 1 if (event.area.y + event.area.height).to_i % @char_height != 0 - @adisp.signal_connect 'expose_event' do |adisp, event| - imin = (event.area.y / @char_height).to_i - imax = ((event.area.y + event.area.height) / @char_height).to_i - imax += 1 if (event.area.y + event.area.height).to_i % @char_height != 0 + imax = [ imax, @vis_lines ].min + render_ascii_lines(imin, imax) + end - imax = [ imax, @vis_lines ].min - render_ascii_lines(imin, imax) - end + @adisp.signal_connect 'scroll_event' do |adisp, event| + @scrollbar.event(event) + end - @adisp.signal_connect 'scroll_event' do |adisp, event| - @scrollbar.event(event) - end + @adisp.signal_connect 'button_press_event' do |adisp, event| + mouse_handler[adisp, event] + end - @adisp.signal_connect 'button_press_event' do |adisp, event| - mouse_handler[adisp, event] - end + @adisp.signal_connect 'button_release_event' do |adisp, event| + mouse_handler[adisp, event] + end - @adisp.signal_connect 'button_release_event' do |adisp, event| - mouse_handler[adisp, event] - end + @adisp.signal_connect 'motion_notify_event' do |adisp, event| + _w, x, y, _m = adisp.window.pointer - @adisp.signal_connect 'motion_notify_event' do |adisp, event| - w, x, y, m = adisp.window.pointer + if y < 0 + @scroll_dir = -1 + elsif y >= adisp.allocation.height + @scroll_dir = 1 + else + @scroll_dir = 0 + end - if y < 0 - @scroll_dir = -1 - elsif y >= adisp.allocation.height - @scroll_dir = 1 - else - @scroll_dir = 0 - end + if @scroll_dir != 0 + if @scroll_timeout == nil + @scroll_timeout = GLib::Timeout.add(SCROLL_TIMEOUT) { + if @scroll_dir < 0 + set_cursor([ 0, @cursor_pos - @cpl ].max) + elsif @scroll_dir > 0 + set_cursor([ @data.size - 1, @cursor_pos + @cpl ].min) + end - if @scroll_dir != 0 - if @scroll_timeout == nil - @scroll_timeout = GLib::Timeout.add(SCROLL_TIMEOUT) { - if @scroll_dir < 0 - set_cursor([ 0, @cursor_pos - @cpl ].max) - elsif @scroll_dir > 0 - set_cursor([ @data.size - 1, @cursor_pos + @cpl ].min) - end + true + } + next + end + else + if @scroll_timeout != nil + GLib::Source.remove @scroll_timeout + @scroll_timeout = nil + end + end - true - } - next - end - else - if @scroll_timeout != nil - GLib::Source.remove @scroll_timeout - @scroll_timeout = nil - end - end + next if event.window != adisp.window - next if event.window != adisp.window + ascii_to_pointer(x,y) if @active_view == View::ASCII and @button == 1 + end - ascii_to_pointer(x,y) if @active_view == View::ASCII and @button == 1 - end - - put @adisp, 0, 0 - @adisp.show + put @adisp, 0, 0 + @adisp.show - @adj = Gtk::Adjustment.new(0, 0, 0, 0, 0, 0) - @scrollbar = Gtk::VScrollbar.new(@adj) - @adj.signal_connect 'value_changed' do |adj| - unless @xdisp_gc.nil? or @adisp_gc.nil? or not @xdisp.drawable? or not @adisp.drawable? - - source_min = (adj.value.to_i - @top_line) * @char_height - source_max = source_min + @xdisp.allocation.height - dest_min = 0 - dest_max = @xdisp.allocation.height + @adj = Gtk::Adjustment.new(0, 0, 0, 0, 0, 0) + @scrollbar = Gtk::VScrollbar.new(@adj) + @adj.signal_connect 'value_changed' do |adj| + unless @xdisp_gc.nil? or @adisp_gc.nil? or not @xdisp.drawable? or not @adisp.drawable? + source_min = (adj.value.to_i - @top_line) * @char_height + source_max = source_min + @xdisp.allocation.height + dest_min = 0 + dest_max = @xdisp.allocation.height - rect = Gdk::Rectangle.new(0, 0, 0, 0) - @top_line = adj.value.to_i - if source_min < 0 - rect.y = 0 - rect.height = -source_min - rect_height = [ rect.height, @xdisp.allocation.height ].min - source_min = 0 - dest_min = rect.height - else - rect.y = 2 * @xdisp.allocation.height - source_max - rect.y = 0 if rect.y < 0 - rect.height = @xdisp.allocation.height - rect.y - source_max = @xdisp.allocation.height - dest_max = rect.y - end + rect = Gdk::Rectangle.new(0, 0, 0, 0) + @top_line = adj.value.to_i + if source_min < 0 + rect.y = 0 + rect.height = -source_min + rect_height = [ rect.height, @xdisp.allocation.height ].min + source_min = 0 + dest_min = rect.height + else + rect.y = 2 * @xdisp.allocation.height - source_max + rect.y = 0 if rect.y < 0 + rect.height = @xdisp.allocation.height - rect.y + source_max = @xdisp.allocation.height + dest_max = rect.y + end - if source_min != source_max - @xdisp.window.draw_drawable( - @xdisp_gc, - @xdisp.window, - 0, source_min, - 0, dest_min, - @xdisp.allocation.width, - source_max - source_min - ) - @adisp.window.draw_drawable( - @adisp_gc, - @adisp.window, - 0, source_min, - 0, dest_min, - @adisp.allocation.width, - source_max - source_min - ) + if source_min != source_max + @xdisp.window.draw_drawable( + @xdisp_gc, + @xdisp.window, + 0, source_min, + 0, dest_min, + @xdisp.allocation.width, + source_max - source_min + ) + @adisp.window.draw_drawable( + @adisp_gc, + @adisp.window, + 0, source_min, + 0, dest_min, + @adisp.allocation.width, + source_max - source_min + ) - if @offsets - if @offsets_gc.nil? - @offsets_gc = Gdk::GC.new(@offsets.window) - @offsets_gc.set_exposures(true) - end + if @offsets + if @offsets_gc.nil? + @offsets_gc = Gdk::GC.new(@offsets.window) + @offsets_gc.set_exposures(true) + end - @offsets.window.draw_drawable( - @offsets_gc, - @offsets.window, - 0, source_min, - 0, dest_min, - @offsets.allocation.width, - source_max - source_min - ) - end + @offsets.window.draw_drawable( + @offsets_gc, + @offsets.window, + 0, source_min, + 0, dest_min, + @offsets.allocation.width, + source_max - source_min + ) + end - # TODO update_all_auto_highlights(true, true) - invalidate_all_highlights - - rect.width = @xdisp.allocation.width - @xdisp.window.invalidate(rect, false) - rect.width = @adisp.allocation.width - @adisp.window.invalidate(rect, false) + # TODO update_all_auto_highlights(true, true) + invalidate_all_highlights - if @offsets - rect.width = @offsets.allocation.width - @offsets.window.invalidate(rect, false) + rect.width = @xdisp.allocation.width + @xdisp.window.invalidate(rect, false) + rect.width = @adisp.allocation.width + @adisp.window.invalidate(rect, false) + + if @offsets + rect.width = @offsets.allocation.width + @offsets.window.invalidate(rect, false) + end + end + end end - end + + put @scrollbar, 0, 0 + @scrollbar.show end - end - put @scrollbar, 0, 0 - @scrollbar.show - end + def set_selection(s, e) + e = [ e, @data.size ].min - def set_selection(s, e) - e = [ e, @data.size ].min + @@primary.clear if @selection.start != @selection.end - @@primary.clear if @selection.start != @selection.end + os, oe = [ @selection.start, @selection.end ].sort - os, oe = [ @selection.start, @selection.end ].sort + @selection.start = [ 0, s ].max + @selection.start = [ @selection.start, @data.size ].min + @selection.end = [ e, @data.size ].min - @selection.start = [ 0, s ].max - @selection.start = [ @selection.start, @data.size ].min - @selection.end = [ e, @data.size ].min + invalidate_highlight(@selection) - invalidate_highlight(@selection) + ns, ne = [ @selection.start, @selection.end ].sort - ns, ne = [ @selection.start, @selection.end ].sort + if ns != os and ne != oe + bytes_changed([ns, os].min, [ne, oe].max) + elsif ne != oe + bytes_changed(*[ne, oe].sort) + elsif ns != os + bytes_changed(*[ns, os].sort) + end - if ns != os and ne != oe - bytes_changed([ns, os].min, [ne, oe].max) - elsif ne != oe - bytes_changed(*[ne, oe].sort) - elsif ns != os - bytes_changed(*[ns, os].sort) - end + if @selection.start != @selection.end + if @active_view == View::HEX + brk_len = 2 * @cpl + @cpl / @group_type + format_xblock(s,e) + (@disp_buffer.size / brk_len + 1).times do |i| @disp_buffer.insert(i * (brk_len + 1), $/) end + else + brk_len = @cpl + format_ablock(s,e) + end - if @selection.start != @selection.end - if @active_view == View::HEX - brk_len = 2 * @cpl + @cpl / @group_type - format_xblock(s,e) - (@disp_buffer.size / brk_len + 1).times do |i| @disp_buffer.insert(i * (brk_len + 1), $/) end - else - brk_len = @cpl - format_ablock(s,e) + @@primary.set_text(@disp_buffer) + end end - @@primary.set_text(@disp_buffer) - end - end + def get_selection + [ @selection.start, @selection.end ].sort + end - def get_selection - [ @selection.start, @selection.end ].sort - end + def clear_selection + set_selection(0, 0) + end - def clear_selection - set_selection(0, 0) - end + def cursor + @cursor_pos + end - def cursor - @cursor_pos - end + def set_cursor(index) + return if index < 0 or index > @data.size - def set_cursor(index) - return if index < 0 or index > @data.size + old_pos = @cursor_pos + index -= 1 if @insert and index == @data.size + index = [ 0, index ].max - old_pos = @cursor_pos - index -= 1 if @insert and index == @data.size - index = [ 0, index ].max + hide_cursor - hide_cursor - - @cursor_pos = index - return if @cpl == 0 + @cursor_pos = index + return if @cpl == 0 - y = index / @cpl - if y >= @top_line + @vis_lines - @adj.value = [ y - @vis_lines + 1, @lines - @vis_lines ].min - @adj.value = [ 0, @adj.value ].max - @adj.signal_emit 'value_changed' - elsif y < @top_line - @adj.value = y - @adj.signal_emit 'value_changed' - end + y = index / @cpl + if y >= @top_line + @vis_lines + @adj.value = [ y - @vis_lines + 1, @lines - @vis_lines ].min + @adj.value = [ 0, @adj.value ].max + @adj.signal_emit 'value_changed' + elsif y < @top_line + @adj.value = y + @adj.signal_emit 'value_changed' + end - @lower_nibble = false if index == @data.size + @lower_nibble = false if index == @data.size - if @selecting - set_selection(@selection.start, @cursor_pos) - bytes_changed(*[@cursor_pos, old_pos].sort) - else# @selection.start != @selection.end - s, e = [@selection.start, @selection.end].sort - @selection.end = @selection.start = @cursor_pos - bytes_changed(s, e) - end + if @selecting + set_selection(@selection.start, @cursor_pos) + bytes_changed(*[@cursor_pos, old_pos].sort) + else# @selection.start != @selection.end + s, e = [@selection.start, @selection.end].sort + @selection.end = @selection.start = @cursor_pos + bytes_changed(s, e) + end - self.signal_emit 'cursor_moved' + self.signal_emit 'cursor_moved' - bytes_changed(old_pos, old_pos) - show_cursor - end + bytes_changed(old_pos, old_pos) + show_cursor + end - def set_cursor_xy(x, y) - pos = y.to_i * @cpl + x.to_i - return if y < 0 or y >= @lines or x < 0 or x >= @cpl or pos > @data.size + def set_cursor_xy(x, y) + pos = y.to_i * @cpl + x.to_i + return if y < 0 or y >= @lines or x < 0 or x >= @cpl or pos > @data.size - set_cursor(pos) - end + set_cursor(pos) + end - def set_cursor_on_lower_nibble(bool) - if @selecting - bytes_changed(@cursor_pos, @cursor_pos) - @lower_nibble = bool - elsif @selection.start != @selection.end - s, e = [ @selection.start, @selection.end ].sort + def set_cursor_on_lower_nibble(bool) + if @selecting + bytes_changed(@cursor_pos, @cursor_pos) + @lower_nibble = bool + elsif @selection.start != @selection.end + s, e = [ @selection.start, @selection.end ].sort - @selection.start = @selection.end = 0 - bytes_changed(s, e) - @lower_nibble = bool - else - hide_cursor - @lower_nibble = bool - show_cursor - end - end + @selection.start = @selection.end = 0 + bytes_changed(s, e) + @lower_nibble = bool + else + hide_cursor + @lower_nibble = bool + show_cursor + end + end - def set_group_type(type) - hide_cursor - @group_type = type - recalc_displays(self.allocation.width, self.allocation.height) - self.queue_resize - show_cursor - end + def set_group_type(type) + hide_cursor + @group_type = type + recalc_displays(self.allocation.width, self.allocation.height) + self.queue_resize + show_cursor + end - def show_offsets(bool) - return unless @show_offsets ^ bool + def show_offsets(bool) + return unless @show_offsets ^ bool - @show_offsets = bool - if bool - show_offsets_widget - else - hide_offsets_widget - end - end + @show_offsets = bool + if bool + show_offsets_widget + else + hide_offsets_widget + end + end - def set_font(fontname) - @font_desc = Pango::FontDescription.new(fontname) - @disp_font_metrics = load_font(fontname) + def set_font(fontname) + @font_desc = Pango::FontDescription.new(fontname) + @disp_font_metrics = load_font(fontname) - @xdisp.modify_font(@font_desc) if @xdisp - @adisp.modify_font(@font_desc) if @adisp - @offsets.modify_font(@font_desc) if @offsets + @xdisp.modify_font(@font_desc) if @xdisp + @adisp.modify_font(@font_desc) if @adisp + @offsets.modify_font(@font_desc) if @offsets - @char_width = get_max_char_width(@disp_font_metrics) - @char_height = Pango.pixels(@disp_font_metrics.ascent) + Pango.pixels(@disp_font_metrics.descent) + 2 - recalc_displays(self.allocation.width, self.allocation.height) + @char_width = get_max_char_width(@disp_font_metrics) + @char_height = Pango.pixels(@disp_font_metrics.ascent) + Pango.pixels(@disp_font_metrics.descent) + 2 + recalc_displays(self.allocation.width, self.allocation.height) - redraw_widget - end + redraw_widget + end - def set_data(data) - prev_data_size = @data.size - @data = data.dup + def set_data(data) + prev_data_size = @data.size + @data = data.dup - recalc_displays(self.allocation.width, self.allocation.height) - - set_cursor 0 - bytes_changed(0, [ prev_data_size, @data.size ].max) - redraw_widget - end + recalc_displays(self.allocation.width, self.allocation.height) - def validate_highlight(hl) - unless hl.valid - hl.start_line = [ hl.start, hl.end ].min / @cpl - @top_line - hl.end_line = [ hl.start, hl.end ].max / @cpl - @top_line - hl.valid = true - end - end + set_cursor 0 + bytes_changed(0, [ prev_data_size, @data.size ].max) + redraw_widget + end - def invalidate_highlight(hl) - hl.valid = false - end + def validate_highlight(hl) + unless hl.valid + hl.start_line = [ hl.start, hl.end ].min / @cpl - @top_line + hl.end_line = [ hl.start, hl.end ].max / @cpl - @top_line + hl.valid = true + end + end - def invalidate_all_highlights - @highlights.each do |hl| invalidate_highlight(hl) end - end + def invalidate_highlight(hl) + hl.valid = false + end - private + def invalidate_all_highlights + @highlights.each do |hl| invalidate_highlight(hl) end + end - signal_new( - 'data_changed', - GLib::Signal::RUN_FIRST, - nil, - nil, - String - ) + private - signal_new( - 'cursor_moved', - GLib::Signal::RUN_FIRST, - nil, - nil - ) + signal_new( + 'data_changed', + GLib::Signal::RUN_FIRST, + nil, + nil, + String + ) - def signal_do_cursor_moved - end + signal_new( + 'cursor_moved', + GLib::Signal::RUN_FIRST, + nil, + nil + ) - def signal_do_data_changed(data) - # TODO - end + def signal_do_cursor_moved + end - def signal_do_realize - super + def signal_do_data_changed(data) + # TODO + end - self.window.set_back_pixmap(nil, true) - end + def signal_do_realize + super - def signal_do_size_allocate(alloc) - hide_cursor + self.window.set_back_pixmap(nil, true) + end - recalc_displays(alloc.width, alloc.height) + def signal_do_size_allocate(alloc) + hide_cursor - self.set_allocation(alloc.x, alloc.y, alloc.width, alloc.height) - self.window.move_resize( - alloc.x, alloc.y, - alloc.width, alloc.height - ) if self.realized? + recalc_displays(alloc.width, alloc.height) - bw = self.border_width - xt = widget_get_xt - yt = widget_get_yt + self.set_allocation(alloc.x, alloc.y, alloc.width, alloc.height) + self.window.move_resize( + alloc.x, alloc.y, + alloc.width, alloc.height + ) if self.realized? - my_alloc = Gtk::Allocation.new(0, 0, 0, 0) - my_alloc.x = bw + xt - my_alloc.y = bw + yt - my_alloc.height = [ alloc.height - 2*bw - 2*yt, 1 ].max - if @show_offsets - my_alloc.width = 8 * @char_width - @offsets.size_allocate(my_alloc) - @offsets.queue_draw - my_alloc.x += 2*xt + my_alloc.width - end + bw = self.border_width + xt = widget_get_xt + yt = widget_get_yt - my_alloc.width = @xdisp_width - @xdisp.size_allocate(my_alloc) + my_alloc = Gtk::Allocation.new(0, 0, 0, 0) + my_alloc.x = bw + xt + my_alloc.y = bw + yt + my_alloc.height = [ alloc.height - 2*bw - 2*yt, 1 ].max + if @show_offsets + my_alloc.width = 8 * @char_width + @offsets.size_allocate(my_alloc) + @offsets.queue_draw + my_alloc.x += 2*xt + my_alloc.width + end - my_alloc.x = alloc.width - bw - @scrollbar.requisition[0] - my_alloc.y = bw - my_alloc.width = @scrollbar.requisition[0] - my_alloc.height = [ alloc.height - 2*bw, 1 ].max - @scrollbar.size_allocate(my_alloc) + my_alloc.width = @xdisp_width + @xdisp.size_allocate(my_alloc) - my_alloc.x -= @adisp_width + xt - my_alloc.y = bw + yt - my_alloc.width = @adisp_width - my_alloc.height = [ alloc.height - 2*bw - 2*yt, 1 ].max - @adisp.size_allocate(my_alloc) + my_alloc.x = alloc.width - bw - @scrollbar.requisition[0] + my_alloc.y = bw + my_alloc.width = @scrollbar.requisition[0] + my_alloc.height = [ alloc.height - 2*bw, 1 ].max + @scrollbar.size_allocate(my_alloc) - show_cursor - end + my_alloc.x -= @adisp_width + xt + my_alloc.y = bw + yt + my_alloc.width = @adisp_width + my_alloc.height = [ alloc.height - 2*bw - 2*yt, 1 ].max + @adisp.size_allocate(my_alloc) - def signal_do_size_request(req) - sb_width, sb_height = @scrollbar.size_request - bw = self.border_width - xt, yt = widget_get_xt, widget_get_yt + show_cursor + end - width = 4*xt + 2*bw + sb_width + - @char_width*(DEFAULT_CPL + (DEFAULT_CPL-1)/@group_type) + def signal_do_size_request(req) + sb_width, _sb_height = @scrollbar.size_request + bw = self.border_width + xt, yt = widget_get_xt, widget_get_yt - width += 2*xt + 8*@char_width if @show_offsets + width = 4*xt + 2*bw + sb_width + + @char_width*(DEFAULT_CPL + (DEFAULT_CPL-1)/@group_type) - height = DEFAULT_LINES * @char_height + 2*yt + 2*bw - - req[0] = width - req[1] = height - end + width += 2*xt + 8*@char_width if @show_offsets - def signal_do_expose_event(event) - draw_shadow(event.area) - super(event) + height = DEFAULT_LINES * @char_height + 2*yt + 2*bw - true - end + req[0] = width + req[1] = height + end - def signal_do_key_press_event(event) - old_cp = @cursor_pos + def signal_do_expose_event(event) + draw_shadow(event.area) + super(event) - hide_cursor - @selecting = (event.state & Gdk::Window::SHIFT_MASK) != 0 - ret = true + true + end - case event.keyval - when Gdk::Keyval::GDK_KP_Tab, Gdk::Keyval::GDK_Tab - @active_view = (@active_view == View::HEX) ? View::ASCII : View::HEX - - when Gdk::Keyval::GDK_Up - set_cursor(@cursor_pos - @cpl) + def signal_do_key_press_event(event) - when Gdk::Keyval::GDK_Down - set_cursor(@cursor_pos + @cpl) + hide_cursor + @selecting = (event.state & Gdk::Window::SHIFT_MASK) != 0 + ret = true - when Gdk::Keyval::GDK_Page_Up - set_cursor([0, @cursor_pos - @vis_lines * @cpl].max) + case event.keyval + when Gdk::Keyval::GDK_KP_Tab, Gdk::Keyval::GDK_Tab + @active_view = (@active_view == View::HEX) ? View::ASCII : View::HEX - when Gdk::Keyval::GDK_Page_Down - set_cursor([@cursor_pos + @vis_lines * @cpl, @data.size].min) + when Gdk::Keyval::GDK_Up + set_cursor(@cursor_pos - @cpl) - when Gdk::Keyval::GDK_Left - if @active_view == View::HEX - if @selecting - set_cursor(@cursor_pos - 1) - else - @lower_nibble ^= 1 - set_cursor(@cursor_pos - 1) if @lower_nibble - end - else - set_cursor(@cursor_pos - 1) - end + when Gdk::Keyval::GDK_Down + set_cursor(@cursor_pos + @cpl) - when Gdk::Keyval::GDK_Right - if @active_view == View::HEX - if @selecting - set_cursor(@cursor_pos + 1) - else - @lower_nibble ^= 1 - set_cursor(@cursor_pos + 1) unless @lower_nibble - end - else - set_cursor(@cursor_pos + 1) - end + when Gdk::Keyval::GDK_Page_Up + set_cursor([0, @cursor_pos - @vis_lines * @cpl].max) - when Gdk::Keyval::GDK_c, Gdk::Keyval::GDK_C - if event.state & Gdk::Window::CONTROL_MASK != 0 - s,e = @selection.start, @selection.end + 1 - if @active_view == View::HEX - brk_len = 2 * @cpl + @cpl / @group_type - format_xblock(s,e) - (@disp_buffer.size / brk_len + 1).times do |i| @disp_buffer.insert(i * (brk_len + 1), $/) end + when Gdk::Keyval::GDK_Page_Down + set_cursor([@cursor_pos + @vis_lines * @cpl, @data.size].min) + + when Gdk::Keyval::GDK_Left + if @active_view == View::HEX + if @selecting + set_cursor(@cursor_pos - 1) + else + @lower_nibble ^= 1 + set_cursor(@cursor_pos - 1) if @lower_nibble + end + else + set_cursor(@cursor_pos - 1) + end + + when Gdk::Keyval::GDK_Right + if @active_view == View::HEX + if @selecting + set_cursor(@cursor_pos + 1) + else + @lower_nibble ^= 1 + set_cursor(@cursor_pos + 1) unless @lower_nibble + end + else + set_cursor(@cursor_pos + 1) + end + + when Gdk::Keyval::GDK_c, Gdk::Keyval::GDK_C + if event.state & Gdk::Window::CONTROL_MASK != 0 + s,e = @selection.start, @selection.end + 1 + if @active_view == View::HEX + brk_len = 2 * @cpl + @cpl / @group_type + format_xblock(s,e) + (@disp_buffer.size / brk_len + 1).times do |i| @disp_buffer.insert(i * (brk_len + 1), $/) end + else + brk_len = @cpl + format_ablock(s,e) + end + + @@clipboard.set_text(@disp_buffer) + end else - brk_len = @cpl - format_ablock(s,e) + ret = false end - @@clipboard.set_text(@disp_buffer) - end - else - ret = false - end + show_cursor - show_cursor - - ret - end + ret + end - def hex_to_pointer(mx, my) - cy = @top_line + my.to_i / @char_height - - cx = x = 0 - while cx < 2 * @cpl - x += @char_width + def hex_to_pointer(mx, my) + cy = @top_line + my.to_i / @char_height - if x > mx - set_cursor_xy(cx / 2, cy) - set_cursor_on_lower_nibble(cx % 2 != 0) + cx = x = 0 + while cx < 2 * @cpl + x += @char_width - cx = 2 * @cpl - end + if x > mx + set_cursor_xy(cx / 2, cy) + set_cursor_on_lower_nibble(cx % 2 != 0) - cx += 1 - x += @char_width if ( cx % (2 * @group_type) == 0 ) - end - end + cx = 2 * @cpl + end - def ascii_to_pointer(mx, my) - cx = mx / @char_width - cy = @top_line + my / @char_height + cx += 1 + x += @char_width if ( cx % (2 * @group_type) == 0 ) + end + end - set_cursor_xy(cx, cy) - end + def ascii_to_pointer(mx, my) + cx = mx / @char_width + cy = @top_line + my / @char_height - def load_font(fontname) - desc = Pango::FontDescription.new(fontname) - context = Gdk::Pango.context - context.set_language(Gtk.default_language) - - font = context.load_font(desc) - - font.metrics(context.language) - end + set_cursor_xy(cx, cy) + end - def draw_shadow(area) - bw = self.border_width - x = bw - xt = widget_get_xt + def load_font(fontname) + desc = Pango::FontDescription.new(fontname) + context = Gdk::Pango.context + context.set_language(Gtk.default_language) - if @show_offsets - self.style.paint_shadow( - self.window, - Gtk::STATE_NORMAL, Gtk::SHADOW_IN, - nil, self, nil, - bw, bw, - 8*@char_width + 2*xt, self.allocation.height - 2*bw - ) + font = context.load_font(desc) - x += 8*@char_width + 2*xt - end + font.metrics(context.language) + end - self.style.paint_shadow( - self.window, - Gtk::STATE_NORMAL, Gtk::SHADOW_IN, - nil, self, nil, - x, bw, - @xdisp_width + 2*xt, self.allocation.height - 2*bw - ) + def draw_shadow(area) + bw = self.border_width + x = bw + xt = widget_get_xt - self.style.paint_shadow( - self.window, - Gtk::STATE_NORMAL, Gtk::SHADOW_IN, - nil, self, nil, - self.allocation.width - bw - @adisp_width - @scrollbar.requisition[0] - 2*xt, bw, - @adisp_width + 2*xt, self.allocation.height - 2*bw - ) - end + if @show_offsets + self.style.paint_shadow( + self.window, + Gtk::STATE_NORMAL, Gtk::SHADOW_IN, + nil, self, nil, + bw, bw, + 8*@char_width + 2*xt, self.allocation.height - 2*bw + ) - def redraw_widget - return unless self.realized? + x += 8*@char_width + 2*xt + end - self.window.invalidate(nil, false) - end + self.style.paint_shadow( + self.window, + Gtk::STATE_NORMAL, Gtk::SHADOW_IN, + nil, self, nil, + x, bw, + @xdisp_width + 2*xt, self.allocation.height - 2*bw + ) - def widget_get_xt - self.style.xthickness - end + self.style.paint_shadow( + self.window, + Gtk::STATE_NORMAL, Gtk::SHADOW_IN, + nil, self, nil, + self.allocation.width - bw - @adisp_width - @scrollbar.requisition[0] - 2*xt, bw, + @adisp_width + 2*xt, self.allocation.height - 2*bw + ) + end - def widget_get_yt - self.style.ythickness - end + def redraw_widget + return unless self.realized? - def recalc_displays(width, height) - old_cpl = @cpl + self.window.invalidate(nil, false) + end - w, h = @scrollbar.size_request - @xdisp_width = 1 - @adisp_width = 1 + def widget_get_xt + self.style.xthickness + end - total_width = width - 2 * self.border_width - 4 * widget_get_xt - w - total_width -= 2 * widget_get_xt + 8 * @char_width if @show_offsets - - total_cpl = total_width / @char_width - if total_cpl == 0 or total_width < 0 - @cpl = @lines = @vis_lines = 0 - return - end + def widget_get_yt + self.style.ythickness + end - @cpl = 0 - begin - break if @cpl % @group_type == 0 and total_cpl < @group_type * 3 + def recalc_displays(width, height) + old_cpl = @cpl - @cpl += 1 - total_cpl -= 3 + w, _h = @scrollbar.size_request + @xdisp_width = 1 + @adisp_width = 1 - total_cpl -= 1 if @cpl % @group_type == 0 - end while total_cpl > 0 + total_width = width - 2 * self.border_width - 4 * widget_get_xt - w + total_width -= 2 * widget_get_xt + 8 * @char_width if @show_offsets - return if @cpl == 0 + total_cpl = total_width / @char_width + if total_cpl == 0 or total_width < 0 + @cpl = @lines = @vis_lines = 0 + return + end - if @data.empty? - @lines = 1 - else - @lines = @data.size / @cpl - @lines += 1 if @data.size % @cpl != 0 - end + @cpl = 0 + begin + break if @cpl % @group_type == 0 and total_cpl < @group_type * 3 - @vis_lines = (height - 2*self.border_width - 2*widget_get_yt).to_i / @char_height.to_i - @adisp_width = @cpl * @char_width + 1 - xcpl = @cpl * 2 + (@cpl - 1) / @group_type - @xdisp_width = xcpl * @char_width + 1 + @cpl += 1 + total_cpl -= 3 - @disp_buffer = '' + total_cpl -= 1 if @cpl % @group_type == 0 + end while total_cpl > 0 - @adj.value = [@top_line * old_cpl / @cpl, @lines - @vis_lines].min - @adj.value = [ 0, @adj.value ].max - if @cursor_pos / @cpl < @adj.value or @cursor_pos / @cpl > @adj.value + @vis_lines - 1 - @adj.value = [ @cursor_pos / @cpl, @lines - @vis_lines ].min - @adj.value = [ 0, @adj.value ].max - end + return if @cpl == 0 - @adj.lower = 0 - @adj.upper = @lines - @adj.step_increment = 1 - @adj.page_increment = @vis_lines - 1 - @adj.page_size = @vis_lines + if @data.empty? + @lines = 1 + else + @lines = @data.size / @cpl + @lines += 1 if @data.size % @cpl != 0 + end - @adj.signal_emit 'changed' - @adj.signal_emit 'value_changed' - end + @vis_lines = (height - 2*self.border_width - 2*widget_get_yt).to_i / @char_height.to_i + @adisp_width = @cpl * @char_width + 1 + xcpl = @cpl * 2 + (@cpl - 1) / @group_type + @xdisp_width = xcpl * @char_width + 1 - def get_max_char_width(metrics) + @disp_buffer = '' - layout = self.create_pango_layout('') - layout.set_font_description(@font_desc) - char_widths = [ 0 ] + @adj.value = [@top_line * old_cpl / @cpl, @lines - @vis_lines].min + @adj.value = [ 0, @adj.value ].max + if @cursor_pos / @cpl < @adj.value or @cursor_pos / @cpl > @adj.value + @vis_lines - 1 + @adj.value = [ @cursor_pos / @cpl, @lines - @vis_lines ].min + @adj.value = [ 0, @adj.value ].max + end - (1..100).each do |i| - logical_rect = Pango::Rectangle.new(0, 0, 0, 0) - if is_displayable(i.chr) - layout.set_text(i.chr) - logical_rect = layout.pixel_extents[1] + @adj.lower = 0 + @adj.upper = @lines + @adj.step_increment = 1 + @adj.page_increment = @vis_lines - 1 + @adj.page_size = @vis_lines + + @adj.signal_emit 'changed' + @adj.signal_emit 'value_changed' end - char_widths << logical_rect.width - end - char_widths[48..122].max - end + def get_max_char_width(metrics) + layout = self.create_pango_layout('') + layout.set_font_description(@font_desc) + char_widths = [ 0 ] - def show_cursor - unless @cursor_shown - if @xdisp_gc and @adisp_gc and @xdisp.realized? and @adisp.realized? - render_xc - render_ac + (1..100).each do |i| + logical_rect = Pango::Rectangle.new(0, 0, 0, 0) + if is_displayable(i.chr) + layout.set_text(i.chr) + logical_rect = layout.pixel_extents[1] + end + char_widths << logical_rect.width + end + + char_widths[48..122].max end - @cursor_shown = true - end - end + def show_cursor + unless @cursor_shown + if @xdisp_gc and @adisp_gc and @xdisp.realized? and @adisp.realized? + render_xc + render_ac + end - def hide_cursor - if @cursor_shown - if @xdisp_gc and @adisp_gc and @xdisp.realized? and @adisp.realized? - render_byte(@cursor_pos) + @cursor_shown = true + end end - @cursor_shown = false - end - end + def hide_cursor + if @cursor_shown + if @xdisp_gc and @adisp_gc and @xdisp.realized? and @adisp.realized? + render_byte(@cursor_pos) + end - def show_offsets_widget - @offsets = DrawingArea.new - @offsets.modify_font @font_desc - @olayout = @offsets.create_pango_layout('') + @cursor_shown = false + end + end - @offsets.events = Gdk::Event::EXPOSURE_MASK - @offsets.signal_connect 'expose_event' do |offsets, event| - imin = (event.area.y / @char_height).to_i - imax = ((event.area.y + event.area.height) / @char_height).to_i - imax += 1 if (event.area.y + event.area.height).to_i % @char_height != 0 + def show_offsets_widget + @offsets = DrawingArea.new + @offsets.modify_font @font_desc + @olayout = @offsets.create_pango_layout('') - imax = [ imax, @vis_lines ].min + @offsets.events = Gdk::Event::EXPOSURE_MASK + @offsets.signal_connect 'expose_event' do |offsets, event| + imin = (event.area.y / @char_height).to_i + imax = ((event.area.y + event.area.height) / @char_height).to_i + imax += 1 if (event.area.y + event.area.height).to_i % @char_height != 0 - render_offsets(imin, imax) - end + imax = [ imax, @vis_lines ].min - put @offsets, 0, 0 - @offsets.show - end + render_offsets(imin, imax) + end - def hide_offsets_widget - if @offsets - self.remove(@offsets) - @offsets = @offsets_gc = nil - end - end + put @offsets, 0, 0 + @offsets.show + end - def is_displayable(c) - if RUBY_VERSION < '1.9' - c = c[0] - else - c = c.ord - end + def hide_offsets_widget + if @offsets + self.remove(@offsets) + @offsets = @offsets_gc = nil + end + end - c >= 0x20 and c < 0x7f - end + def is_displayable(c) + c = c.ord + c >= 0x20 and c < 0x7f + end - def bytes_changed(s, e) - start_line = s / @cpl - @top_line - end_line = e / @cpl - @top_line + def bytes_changed(s, e) + start_line = s / @cpl - @top_line + end_line = e / @cpl - @top_line - return if end_line < 0 or start_line > @vis_lines + return if end_line < 0 or start_line > @vis_lines - start_line = [ 0, start_line ].max + start_line = [ 0, start_line ].max - render_hex_lines(start_line, end_line) - render_ascii_lines(start_line, end_line) - render_offsets(start_line, end_line) if @show_offsets - end + render_hex_lines(start_line, end_line) + render_ascii_lines(start_line, end_line) + render_offsets(start_line, end_line) if @show_offsets + end - def render_hex_highlights(cursor_line) - xcpl = @cpl * 2 + @cpl / @group_type + def render_hex_highlights(cursor_line) + xcpl = @cpl * 2 + @cpl / @group_type - @highlights.each do |hl| - next if (hl.start - hl.end).abs < hl.min_select + @highlights.each do |hl| + next if (hl.start - hl.end).abs < hl.min_select - validate_highlight(hl) + validate_highlight(hl) - s, e = [ hl.start, hl.end ].sort - sl, el = hl.start_line, hl.end_line + s, e = [ hl.start, hl.end ].sort + sl, el = hl.start_line, hl.end_line - hl.style.attach(@xdisp.window) if hl.style - state = (@active_view == View::HEX) ? Gtk::STATE_SELECTED : Gtk::STATE_INSENSITIVE + hl.style.attach(@xdisp.window) if hl.style + state = (@active_view == View::HEX) ? Gtk::STATE_SELECTED : Gtk::STATE_INSENSITIVE - if cursor_line == sl - cursor_off = 2 * (s % @cpl) + (s % @cpl) / @group_type - if cursor_line == el - len = 2 * (e % @cpl + 1) + (e % @cpl) / @group_type - else - len = xcpl - end + if cursor_line == sl + cursor_off = 2 * (s % @cpl) + (s % @cpl) / @group_type + if cursor_line == el + len = 2 * (e % @cpl + 1) + (e % @cpl) / @group_type + else + len = xcpl + end - len -= cursor_off - (hl.style || self.style).paint_flat_box( - @xdisp.window, - state, Gtk::SHADOW_NONE, - nil, @xdisp, '', - cursor_off * @char_width, cursor_line * @char_height, - len * @char_width, @char_height - ) if len > 0 + len -= cursor_off + (hl.style || self.style).paint_flat_box( + @xdisp.window, + state, Gtk::SHADOW_NONE, + nil, @xdisp, '', + cursor_off * @char_width, cursor_line * @char_height, + len * @char_width, @char_height + ) if len > 0 - elsif cursor_line == el - cursor_off = 2 * (e % @cpl + 1) + (e % @cpl) / @group_type - (hl.style || self.style).paint_flat_box( - @xdisp.window, - state, Gtk::SHADOW_NONE, - nil, @xdisp, '', - 0, cursor_line * @char_height, - cursor_off * @char_width, @char_height - ) if cursor_off > 0 + elsif cursor_line == el + cursor_off = 2 * (e % @cpl + 1) + (e % @cpl) / @group_type + (hl.style || self.style).paint_flat_box( + @xdisp.window, + state, Gtk::SHADOW_NONE, + nil, @xdisp, '', + 0, cursor_line * @char_height, + cursor_off * @char_width, @char_height + ) if cursor_off > 0 - elsif cursor_line > sl and cursor_line < el - (hl.style || self.style).paint_flat_box( - @xdisp.window, - state, Gtk::SHADOW_NONE, - nil, @xdisp, '', - 0, cursor_line * @char_height, - xcpl * @char_width, @char_height - ) + elsif cursor_line > sl and cursor_line < el + (hl.style || self.style).paint_flat_box( + @xdisp.window, + state, Gtk::SHADOW_NONE, + nil, @xdisp, '', + 0, cursor_line * @char_height, + xcpl * @char_width, @char_height + ) + end + + hl.style.attach(@adisp.window) if hl.style + end end - - hl.style.attach(@adisp.window) if hl.style - end - end - def render_hex_lines(imin, imax) - return unless self.realized? and @cpl != 0 + def render_hex_lines(imin, imax) + return unless self.realized? and @cpl != 0 - cursor_line = @cursor_pos / @cpl - @top_line + cursor_line = @cursor_pos / @cpl - @top_line - @xdisp_gc.set_foreground(self.style.base(Gtk::STATE_NORMAL)) - @xdisp.window.draw_rectangle( - @xdisp_gc, - true, - 0, - imin * @char_height, - @xdisp.allocation.width, - (imax - imin + 1) * @char_height - ) + @xdisp_gc.set_foreground(self.style.base(Gtk::STATE_NORMAL)) + @xdisp.window.draw_rectangle( + @xdisp_gc, + true, + 0, + imin * @char_height, + @xdisp.allocation.width, + (imax - imin + 1) * @char_height + ) - imax = [ imax, @vis_lines, @lines ].min + imax = [ imax, @vis_lines, @lines ].min - @xdisp_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL)) + @xdisp_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL)) - frm_len = format_xblock((@top_line+imin) * @cpl, [(@top_line+imax+1) * @cpl, @data.size].min) + frm_len = format_xblock((@top_line+imin) * @cpl, [(@top_line+imax+1) * @cpl, @data.size].min) - tmp = nil - xcpl = @cpl*2 + @cpl/@group_type - (imin..imax).each do |i| - return unless (tmp = frm_len - ((i - imin) * xcpl)) > 0 - - render_hex_highlights(i) - text = @disp_buffer[(i-imin) * xcpl, [xcpl, tmp].min] - @xlayout.set_text(text) - @xdisp.window.draw_layout(@xdisp_gc, 0, i * @char_height, @xlayout) - end + tmp = nil + xcpl = @cpl*2 + @cpl/@group_type + (imin..imax).each do |i| + return unless (tmp = frm_len - ((i - imin) * xcpl)) > 0 - render_xc if cursor_line >= imin and cursor_line <= imax and @cursor_shown - end + render_hex_highlights(i) + text = @disp_buffer[(i-imin) * xcpl, [xcpl, tmp].min] + @xlayout.set_text(text) + @xdisp.window.draw_layout(@xdisp_gc, 0, i * @char_height, @xlayout) + end - def render_ascii_highlights(cursor_line) - @highlights.each do |hl| - next if (hl.start - hl.end).abs < hl.min_select + render_xc if cursor_line >= imin and cursor_line <= imax and @cursor_shown + end - validate_highlight(hl) + def render_ascii_highlights(cursor_line) + @highlights.each do |hl| + next if (hl.start - hl.end).abs < hl.min_select - s, e = [ hl.start, hl.end ].sort - sl, el = hl.start_line, hl.end_line + validate_highlight(hl) - hl.style.attach(@adisp.window) if hl.style - state = (@active_view == View::ASCII) ? Gtk::STATE_SELECTED : Gtk::STATE_INSENSITIVE + s, e = [ hl.start, hl.end ].sort + sl, el = hl.start_line, hl.end_line - if cursor_line == sl - cursor_off = s % @cpl - len = - if cursor_line == el - e - s + 1 - else - @cpl - cursor_off - end + hl.style.attach(@adisp.window) if hl.style + state = (@active_view == View::ASCII) ? Gtk::STATE_SELECTED : Gtk::STATE_INSENSITIVE - (hl.style || self.style).paint_flat_box( - @adisp.window, - state, Gtk::SHADOW_NONE, - nil, @adisp, '', - cursor_off * @char_width, cursor_line * @char_height, - len * @char_width, @char_height - ) if len > 0 + if cursor_line == sl + cursor_off = s % @cpl + len = + if cursor_line == el + e - s + 1 + else + @cpl - cursor_off + end - elsif cursor_line == el - cursor_off = e % @cpl + 1 - (hl.style || self.style).paint_flat_box( - @adisp.window, - state, Gtk::SHADOW_NONE, - nil, @adisp, '', - 0, cursor_line * @char_height, - cursor_off * @char_width, @char_height - ) if cursor_off > 0 + (hl.style || self.style).paint_flat_box( + @adisp.window, + state, Gtk::SHADOW_NONE, + nil, @adisp, '', + cursor_off * @char_width, cursor_line * @char_height, + len * @char_width, @char_height + ) if len > 0 - elsif cursor_line > sl and cursor_line < el - (hl.style || self.style).paint_flat_box( - @adisp.window, - state, Gtk::SHADOW_NONE, - nil, @adisp, '', - 0, cursor_line * @char_height, - @cpl * @char_width, @char_height - ) + elsif cursor_line == el + cursor_off = e % @cpl + 1 + (hl.style || self.style).paint_flat_box( + @adisp.window, + state, Gtk::SHADOW_NONE, + nil, @adisp, '', + 0, cursor_line * @char_height, + cursor_off * @char_width, @char_height + ) if cursor_off > 0 + + elsif cursor_line > sl and cursor_line < el + (hl.style || self.style).paint_flat_box( + @adisp.window, + state, Gtk::SHADOW_NONE, + nil, @adisp, '', + 0, cursor_line * @char_height, + @cpl * @char_width, @char_height + ) + end + + hl.style.attach(@adisp.window) if hl.style + end end - hl.style.attach(@adisp.window) if hl.style - end - end + def render_ascii_lines(imin, imax) + return unless self.realized? and @cpl != 0 - def render_ascii_lines(imin, imax) - return unless self.realized? and @cpl != 0 + cursor_line = @cursor_pos / @cpl - @top_line - cursor_line = @cursor_pos / @cpl - @top_line + @adisp_gc.set_foreground(self.style.base(Gtk::STATE_NORMAL)) + @adisp.window.draw_rectangle( + @adisp_gc, + true, + 0, + imin * @char_height, + @adisp.allocation.width, + (imax - imin + 1) * @char_height + ) - @adisp_gc.set_foreground(self.style.base(Gtk::STATE_NORMAL)) - @adisp.window.draw_rectangle( - @adisp_gc, - true, - 0, - imin * @char_height, - @adisp.allocation.width, - (imax - imin + 1) * @char_height - ) - - imax = [ imax, @vis_lines, @lines ].min + imax = [ imax, @vis_lines, @lines ].min - @adisp_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL)) - - frm_len = format_ablock((@top_line+imin) * @cpl, [(@top_line+imax+1) * @cpl, @data.size].min) + @adisp_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL)) - tmp = nil - (imin..imax).each do |i| - return unless (tmp = frm_len - ((i - imin) * @cpl)) > 0 - - render_ascii_highlights(i) - text = @disp_buffer[(i-imin) * @cpl, [@cpl, tmp].min] - @alayout.set_text(text) - @adisp.window.draw_layout(@adisp_gc, 0, i * @char_height, @alayout) - end + frm_len = format_ablock((@top_line+imin) * @cpl, [(@top_line+imax+1) * @cpl, @data.size].min) - render_ac if cursor_line >= imin and cursor_line <= imax and @cursor_shown - end + tmp = nil + (imin..imax).each do |i| + return unless (tmp = frm_len - ((i - imin) * @cpl)) > 0 - def render_offsets(imin, imax) - return unless self.realized? + render_ascii_highlights(i) + text = @disp_buffer[(i-imin) * @cpl, [@cpl, tmp].min] + @alayout.set_text(text) + @adisp.window.draw_layout(@adisp_gc, 0, i * @char_height, @alayout) + end - unless @offsets_gc - @offsets_gc = Gdk::GC.new(@offsets.window) - @offsets_gc.set_exposures(true) - end + render_ac if cursor_line >= imin and cursor_line <= imax and @cursor_shown + end - @offsets_gc.set_foreground(self.style.base(Gtk::STATE_INSENSITIVE)) - @offsets.window.draw_rectangle( - @offsets_gc, - true, - 0, imin * @char_height, - @offsets.allocation.width, (imax - imin + 1) * @char_height - ) + def render_offsets(imin, imax) + return unless self.realized? - imax = [ imax, @vis_lines, @lines - @top_line - 1 ].min - @offsets_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL)) + unless @offsets_gc + @offsets_gc = Gdk::GC.new(@offsets.window) + @offsets_gc.set_exposures(true) + end - (imin..imax).each do |i| - text = "%08x" % ((@top_line + i) * @cpl + @starting_offset) - @olayout.set_text(text) - @offsets.window.draw_layout(@offsets_gc, 0, i * @char_height, @olayout) - end - end + @offsets_gc.set_foreground(self.style.base(Gtk::STATE_INSENSITIVE)) + @offsets.window.draw_rectangle( + @offsets_gc, + true, + 0, imin * @char_height, + @offsets.allocation.width, (imax - imin + 1) * @char_height + ) - def render_byte(pos) - return unless @xdisp_gc and @adisp_gc and @xdisp.realized? and @adisp.realized? - - return unless (coords = get_xcoords(pos)) - cx, cy = coords - c = format_xbyte(pos) - - @xdisp_gc.set_foreground(self.style.base(Gtk::STATE_NORMAL)) - @xdisp.window.draw_rectangle( - @xdisp_gc, - true, - cx, cy, - 2 * @char_width, @char_height - ) + imax = [ imax, @vis_lines, @lines - @top_line - 1 ].min + @offsets_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL)) - if pos < @data.size - @xdisp_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL)) - @xlayout.set_text(c) - @xdisp.window.draw_layout(@xdisp_gc, cx, cy, @xlayout) - end + (imin..imax).each do |i| + text = "%08x" % ((@top_line + i) * @cpl + @starting_offset) + @olayout.set_text(text) + @offsets.window.draw_layout(@offsets_gc, 0, i * @char_height, @olayout) + end + end - return unless (coords = get_acoords(pos)) - cx, cy = coords + def render_byte(pos) + return unless @xdisp_gc and @adisp_gc and @xdisp.realized? and @adisp.realized? - @adisp_gc.set_foreground(self.style.base(Gtk::STATE_NORMAL)) - @adisp.window.draw_rectangle( - @adisp_gc, - true, - cx, cy, - @char_width, @char_height - ) + return unless (coords = get_xcoords(pos)) + cx, cy = coords + c = format_xbyte(pos) - if pos < @data.size - @adisp_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL)) - c = get_byte(pos) - c = '.' unless is_displayable(c) + @xdisp_gc.set_foreground(self.style.base(Gtk::STATE_NORMAL)) + @xdisp.window.draw_rectangle( + @xdisp_gc, + true, + cx, cy, + 2 * @char_width, @char_height + ) - @alayout.set_text(c) - @adisp.window.draw_layout(@adisp_gc, cx, cy, @alayout) - end - end + if pos < @data.size + @xdisp_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL)) + @xlayout.set_text(c) + @xdisp.window.draw_layout(@xdisp_gc, cx, cy, @xlayout) + end - def render_xc - return unless @xdisp.realized? + return unless (coords = get_acoords(pos)) + cx, cy = coords - if coords = get_xcoords(@cursor_pos) - cx, cy = coords + @adisp_gc.set_foreground(self.style.base(Gtk::STATE_NORMAL)) + @adisp.window.draw_rectangle( + @adisp_gc, + true, + cx, cy, + @char_width, @char_height + ) - c = format_xbyte(@cursor_pos) - if @lower_nibble - cx += @char_width - c = c[1,1] - else - c = c[0,1] + if pos < @data.size + @adisp_gc.set_foreground(self.style.text(Gtk::STATE_NORMAL)) + c = get_byte(pos) + c = '.' unless is_displayable(c) + + @alayout.set_text(c) + @adisp.window.draw_layout(@adisp_gc, cx, cy, @alayout) + end end - @xdisp_gc.set_foreground(self.style.base(Gtk::STATE_ACTIVE)) - @xdisp.window.draw_rectangle( - @xdisp_gc, - (@active_view == View::HEX), - cx, cy, - @char_width, - @char_height - 1 - ) - @xdisp_gc.set_foreground(self.style.text(Gtk::STATE_ACTIVE)) - @xlayout.set_text(c) - @xdisp.window.draw_layout(@xdisp_gc, cx, cy, @xlayout) - end - end + def render_xc + return unless @xdisp.realized? - def render_ac - return unless @adisp.realized? + if coords = get_xcoords(@cursor_pos) + cx, cy = coords - if coords = get_acoords(@cursor_pos) - cx, cy = coords + c = format_xbyte(@cursor_pos) + if @lower_nibble + cx += @char_width + c = c[1,1] + else + c = c[0,1] + end - c = get_byte(@cursor_pos) - c = '.' unless is_displayable(c) - - @adisp_gc.set_foreground(self.style.base(Gtk::STATE_ACTIVE)) - @adisp.window.draw_rectangle( - @adisp_gc, - (@active_view == View::ASCII), - cx, cy, - @char_width, - @char_height - 1 - ) - @adisp_gc.set_foreground(self.style.text(Gtk::STATE_ACTIVE)) - @alayout.set_text(c) - @adisp.window.draw_layout(@adisp_gc, cx, cy, @alayout) - end - end + @xdisp_gc.set_foreground(self.style.base(Gtk::STATE_ACTIVE)) + @xdisp.window.draw_rectangle( + @xdisp_gc, + (@active_view == View::HEX), + cx, cy, + @char_width, + @char_height - 1 + ) + @xdisp_gc.set_foreground(self.style.text(Gtk::STATE_ACTIVE)) + @xlayout.set_text(c) + @xdisp.window.draw_layout(@xdisp_gc, cx, cy, @xlayout) + end + end - def get_xcoords(pos) - return nil if @cpl == 0 + def render_ac + return unless @adisp.realized? - cy = pos / @cpl - @top_line - return nil if cy < 0 + if coords = get_acoords(@cursor_pos) + cx, cy = coords - cx = 2 * (pos % @cpl) - spaces = (pos % @cpl) / @group_type + c = get_byte(@cursor_pos) + c = '.' unless is_displayable(c) - cx *= @char_width - cy *= @char_height - spaces *= @char_width + @adisp_gc.set_foreground(self.style.base(Gtk::STATE_ACTIVE)) + @adisp.window.draw_rectangle( + @adisp_gc, + (@active_view == View::ASCII), + cx, cy, + @char_width, + @char_height - 1 + ) + @adisp_gc.set_foreground(self.style.text(Gtk::STATE_ACTIVE)) + @alayout.set_text(c) + @adisp.window.draw_layout(@adisp_gc, cx, cy, @alayout) + end + end - [cx + spaces, cy] - end + def get_xcoords(pos) + return nil if @cpl == 0 - def get_acoords(pos) - return nil if @cpl == 0 + cy = pos / @cpl - @top_line + return nil if cy < 0 - cy = pos / @cpl - @top_line - return nil if cy < 0 + cx = 2 * (pos % @cpl) + spaces = (pos % @cpl) / @group_type - cy *= @char_height - cx = @char_width * (pos % @cpl) + cx *= @char_width + cy *= @char_height + spaces *= @char_width - [cx, cy] - end + [cx + spaces, cy] + end - def format_xblock(s, e) - @disp_buffer = '' + def get_acoords(pos) + return nil if @cpl == 0 - (s+1..e).each do |i| - @disp_buffer << get_byte(i - 1).unpack('H2')[0] - @disp_buffer << ' ' if i % @group_type == 0 - end + cy = pos / @cpl - @top_line + return nil if cy < 0 - @disp_buffer.size - end + cy *= @char_height + cx = @char_width * (pos % @cpl) - def format_ablock(s, e) - @disp_buffer = '' + [cx, cy] + end - (s..e-1).each do |i| - c = get_byte(i) - c = '.' unless is_displayable(c) - @disp_buffer << c - end + def format_xblock(s, e) + @disp_buffer = '' - @disp_buffer.size - end + (s+1..e).each do |i| + @disp_buffer << get_byte(i - 1).unpack('H2')[0] + @disp_buffer << ' ' if i % @group_type == 0 + end - def get_byte(offset) - if offset >= 0 and offset < @data.size - @data[offset, 1] - else - 0.chr - end - end + @disp_buffer.size + end - def format_xbyte(pos) - get_byte(pos).unpack('H2')[0] - end - end + def format_ablock(s, e) + @disp_buffer = '' + (s..e-1).each do |i| + c = get_byte(i) + c = '.' unless is_displayable(c) + @disp_buffer << c + end + + @disp_buffer.size + end + + def get_byte(offset) + if offset >= 0 and offset < @data.size + @data[offset, 1] + else + 0.chr + end + end + + def format_xbyte(pos) + get_byte(pos).unpack('H2')[0] + end + end end __END__ hexedit = Gtk::HexEditor.new(File.read '/bin/cat') hexedit.show_offsets(true)