class Metasm::Gui::DrawableWidget

Constants

BasicColor
ColorTheme
Keyboard_trad

keypress event keyval traduction table

Attributes

buttons[RW]
caret_x[RW]
caret_y[RW]
default_color_association[RW]

this hash is used to determine the colors of the Gui elements (background, caret, …) modifications to it are only useful before the widget is first rendered (IE before Metasm::Gui.main)

hl_word[RW]
hl_word_re[RW]
parent_widget[RW]

Public Class Methods

new(*a, &b) click to toggle source
Calls superclass method
# File metasm/gui/gtk.rb, line 201
def initialize(*a, &b)
        @parent_widget = nil

        @caret_x = @caret_y = 0               # text cursor position
        @oldcaret_x = @oldcaret_y = 1
        @hl_word = nil

        @layout = Pango::Layout.new Gdk::Pango.context        # text rendering

        @color = {}
        @default_color_association = {:background => :palegrey}

        super()

        # events callbacks
        signal_connect('expose_event') {
                @w = window ; @gc = Gdk::GC.new(@w)
                protect { paint }
                @w = @gc = nil
                true
        }

        signal_connect('size_allocate') { |w, alloc|
                protect { resized(alloc.width, alloc.height) }
        }

        signal_connect('button_press_event') { |w, ev|
                @last_kb_ev = ev
                if keyboard_state(:control)
                        next protect { click_ctrl(ev.x, ev.y) } if ev.event_type == Gdk::Event::Type::BUTTON_PRESS and ev.button == 1 and respond_to? :click_ctrl
                        next
                end
                case ev.event_type
                when Gdk::Event::Type::BUTTON_PRESS
                        grab_focus
                        case ev.button
                        when 1; protect { click(ev.x, ev.y) } if respond_to? :click
                        end
                when Gdk::Event::Type::BUTTON2_PRESS
                        case ev.button
                        when 1; protect { doubleclick(ev.x, ev.y) } if respond_to? :doubleclick
                        end
                end
        }

        signal_connect('motion_notify_event') { |w, ev|
                @last_kb_ev = ev
                if keyboard_state(:control)
                        protect { mousemove_ctrl(ev.x, ev.y) } if respond_to? :mousemove_ctrl
                else
                        protect { mousemove(ev.x, ev.y) }
                end
        } if respond_to? :mousemove

        signal_connect('button_release_event') { |w, ev|
                case ev.button
                when 1; protect { mouserelease(ev.x, ev.y) } if respond_to? :mouserelease
                when 3; protect { rightclick(ev.x, ev.y) } if respond_to? :rightclick
                end
        }

        signal_connect('scroll_event') { |w, ev|
                dir = case ev.direction
                when Gdk::EventScroll::Direction::UP; :up
                when Gdk::EventScroll::Direction::DOWN; :down
                else next
                end
                @last_kb_ev = ev
                if keyboard_state(:control)
                        protect { mouse_wheel_ctrl(dir, ev.x, ev.y) } if respond_to? :mouse_wheel_ctrl
                else
                        protect { mouse_wheel(dir, ev.x, ev.y) }
                end
        } if respond_to? :mouse_wheel

        signal_connect('key_press_event') { |w, ev|
                @last_kb_ev = ev
                key = Keyboard_trad[ev.keyval]
                if keyboard_state(:control)
                        protect { keypress_ctrl(key) or (@parent_widget and @parent_widget.keypress_ctrl(key)) }
                else
                        protect { keypress(key) or (@parent_widget and @parent_widget.keypress(key)) }
                end
        }

        signal_connect('realize') {
                BasicColor.each { |tag, val|
                        @color[tag] = color(val)
                }

                set_color_association @default_color_association

                initialize_visible if respond_to? :initialize_visible
        }

        initialize_widget(*a, &b)

        # receive keyboard/mouse signals
        set_events Gdk::Event::ALL_EVENTS_MASK
        set_can_focus true
        set_font 'courier 10'
end

Public Instance Methods

add_button(text='Ok', *a, &b) click to toggle source

add a new button to the widget

# File metasm/gui/win32.rb, line 2000
def add_button(text='Ok', *a, &b)
        @buttons ||= []
        @buttons << Button.new(text, *a, &b)
end
addsubmenu(*a, &b) click to toggle source
# File metasm/gui/gtk.rb, line 357
def addsubmenu(*a, &b)
        toplevel.addsubmenu(*a, &b)
end
click_buttons(x, y) click to toggle source

checks if the click is inside a button, returns true if it is should be called during click

# File metasm/gui/win32.rb, line 2013
def click_buttons(x, y)
        @buttons.find { |b| b.click(x, y) }
end
clipboard_copy(buf) click to toggle source
# File metasm/gui/gtk.rb, line 508
def clipboard_copy(buf)
        clipboard = Gtk::Clipboard.get(Gdk::Selection::PRIMARY)
        clipboard.text = buf
end
clipboard_paste() click to toggle source
# File metasm/gui/gtk.rb, line 513
def clipboard_paste
        clipboard = Gtk::Clipboard.get(Gdk::Selection::PRIMARY)
        clipboard.wait_for_text
end
color(val) click to toggle source

create a color from a 'rgb' description

# File metasm/gui/gtk.rb, line 309
def color(val)
        if not @color[val]
                v = case val.length
                when 3; val.scan(/./).map { |c| (c*4).to_i(16) }
                when 6; val.scan(/../).map { |c| (c+c).to_i(16) }
                end
                @color[val] = Gdk::Color.new(*v)
                window.colormap.alloc_color(@color[val], true, true)
        end
        @color[val]
end
draw_color(col) click to toggle source
# File metasm/gui/gtk.rb, line 421
def draw_color(col)
        @gc.set_foreground color(col)
end
draw_line(x, y, ex, ey) click to toggle source
# File metasm/gui/gtk.rb, line 448
def draw_line(x, y, ex, ey)
        if x.abs > 0x7000
                return if ex.abs > 0x7000 and ((ex < 0) == (x < 0))
                ox = x
                x = ((x > 0) ? 0x7000 : -0x7000)
                y = ey+(x-ex)*(y-ey)/(ox-ex)
        end
        if ex.abs > 0x7000
                oex = ex
                ex = ((ex > 0) ? 0x7000 : -0x7000)
                ey = y+(ex-x)*(ey-y)/(oex-x)
        end
        if y.abs > 0x7000
                return if ey.abs > 0x7000 and ((ey < 0) == (y < 0))
                oy = y
                y = ((y > 0) ? 0x7000 : -0x7000)
                x = ex+(y-ey)*(x-ex)/(oy-ey)
        end
        if ey.abs > 0x7000
                oey = ey
                ey = ((ey > 0) ? 0x7000 : -0x7000)
                ex = x+(ey-y)*(ex-x)/(oey-y)
        end

        @w.draw_line(@gc, x, y, ex, ey)
end
draw_line_color(col, x, y, ex, ey) click to toggle source
# File metasm/gui/gtk.rb, line 475
def draw_line_color(col, x, y, ex, ey)
        draw_color(col)
        draw_line(x, y, ex, ey)
end
draw_rectangle(x, y, w, h) click to toggle source
# File metasm/gui/gtk.rb, line 425
def draw_rectangle(x, y, w, h)
        # GTK clips coords around 0x8000
        return if x > 0x7000 or y > 0x7000
        if x < -0x7000
                w += x + 100
                x = -100
        end
        if y < -0x7000
                h += y + 100
                y = -100
        end
        return if w <= 0 or h <= 0
        w = 0x7000 if w > 0x7000
        h = 0x7000 if h > 0x7000

        @w.draw_rectangle(@gc, true, x, y, w, h)
end
draw_rectangle_color(col, x, y, w, h) click to toggle source
# File metasm/gui/gtk.rb, line 443
def draw_rectangle_color(col, x, y, w, h)
        draw_color(col)
        draw_rectangle(x, y, w, h)
end
draw_string(x, y, str) click to toggle source
# File metasm/gui/gtk.rb, line 480
def draw_string(x, y, str)
        return if x.abs > 0x7000 or y.abs > 0x7000
        @layout.text = str
        @w.draw_layout(@gc, x, y, @layout)
end
draw_string_color(col, x, y, str) click to toggle source
# File metasm/gui/gtk.rb, line 486
def draw_string_color(col, x, y, str)
        draw_color(col)
        draw_string(x, y, str)
end
draw_string_hl(col, x, y, str) click to toggle source

same as #draw_string_color + hilight @hl_word_re

# File metasm/gui/gtk.rb, line 492
def draw_string_hl(col, x, y, str)
        if @hl_word
                while str =~ @hl_word_re
                        s1, s2 = $1, $2
                        draw_string_color(col, x, y, s1)
                        x += s1.length*@font_width
                        hl_w = s2.length*@font_width
                        draw_rectangle_color(:hl_word_bg, x, y, hl_w, @font_height)
                        draw_string_color(:hl_word, x, y, s2)
                        x += hl_w
                        str = str[s1.length+s2.length..-1]
                end
        end
        draw_string_color(col, x, y, str)
end
grab_focus() click to toggle source
# File metasm/gui/qt.rb, line 276
def grab_focus; set_focus end
gui_update() click to toggle source
# File metasm/gui/gtk.rb, line 417
def gui_update
        redraw
end
height() click to toggle source
# File metasm/gui/gtk.rb, line 403
def height
        allocation.height
end
initialize_visible_() click to toggle source
# File metasm/gui/win32.rb, line 1818
def initialize_visible_
        BasicColor.each { |tag, val|
                @color[tag] = color(val)
        }
        @color[:winbg] = Win32Gui.getsyscolor(Win32Gui::COLOR_BTNFACE)
        set_color_association(@default_color_association)     # should be called after Gui.main
        set_font('courier 10')
        initialize_visible if respond_to? :initialize_visible
end
initialize_widget() click to toggle source
# File metasm/gui/gtk.rb, line 304
def initialize_widget
end
invalidate(x, y, w, h) click to toggle source
# File metasm/gui/gtk.rb, line 394
def invalidate(x, y, w, h)
        return if not window
        window.invalidate Gdk::Rectangle.new(x, y, w, h), false
end
invalidate_caret(cx, cy, x=0, y=0) click to toggle source
# File metasm/gui/gtk.rb, line 390
def invalidate_caret(cx, cy, x=0, y=0)
        invalidate(x + cx*@font_width, y + cy*@font_height, 2, @font_height)
end
keyPressEvent(key) click to toggle source
# File metasm/gui/qt.rb, line 224
def keyPressEvent(key)
        val = key.key >= 128 ? Keyboard_trad[key.key] : key.text[0].ord       # must use text[0] to differenciate downcase/upcase
        if key.modifiers.to_i & Qt::ControlModifier.to_i > 0  # AONETHUAAAAAAAAAAAAAAA
                protect { keypress_ctrl(val) } if respond_to? :keypress_ctrl
        else
                protect { keypress(val) } if respond_to? :keypress
        end
end
keyboard_state(query=nil) click to toggle source
# File metasm/gui/gtk.rb, line 518
def keyboard_state(query=nil)
        case query
        when :control, :ctrl
                ev = @last_kb_ev and ev.state & Gdk::Window::CONTROL_MASK == Gdk::Window::CONTROL_MASK
        when :shift
                ev = @last_kb_ev and ev.state & Gdk::Window::SHIFT_MASK   == Gdk::Window::SHIFT_MASK
        when :alt
                ev = @last_kb_ev and ev.state & Gdk::Window::MOD1_MASK    == Gdk::Window::MOD1_MASK
        else
                [:control, :shift, :alt].find_all { |s| keyboard_state(s) }
        end
end
keypress(key) click to toggle source
# File metasm/gui/gtk.rb, line 411
def keypress(key)
end
keypress_(key) click to toggle source
# File metasm/gui/win32.rb, line 1868
def keypress_(key)
        # XXX my gtk api sux
        if not respond_to? :keypress or not protect { keypress(key) }
                protect { @parent.keypress(key) } if @parent.respond_to? :keypress
        end
end
keypress_ctrl(key) click to toggle source
# File metasm/gui/gtk.rb, line 414
def keypress_ctrl(key)
end
keypress_ctrl_(key) click to toggle source
# File metasm/gui/win32.rb, line 1875
def keypress_ctrl_(key)
        if not respond_to? :keypress_ctrl or not protect { keypress_ctrl(key) }
                protect { @parent.keypress_ctrl(key) } if @parent.respond_to? :keypress_ctrl
        end
end
mouseDoubleClickEvent(ev) click to toggle source
# File metasm/gui/qt.rb, line 245
def mouseDoubleClickEvent(ev)
        protect { doubleclick(ev.x, ev.y) } if respond_to? :doubleclick
end
mouseMoveEvent(ev) click to toggle source
# File metasm/gui/qt.rb, line 255
def mouseMoveEvent(ev)
        if ev.modifiers.to_i & Qt::ControlModifier.to_i > 0
                protect { mousemove_ctrl(ev.x, ev.y) } if respond_to? :mousemove_ctrl
        else
                protect { mousemove(ev.x, ev.y) } if respond_to? :mousemove
        end
end
mousePressEvent(ev) click to toggle source
# File metasm/gui/qt.rb, line 233
def mousePressEvent(ev)
        if ev.modifiers.to_i & Qt::ControlModifier.to_i > 0
                protect { click_ctrl(ev.x, ev.y) } if respond_to? :click_ctrl
        else
                if ev.button == Qt::LeftButton
                        protect { click(ev.x, ev.y) }
                elsif ev.button == Qt::RightButton
                        protect { rightclick(ev.x, ev.y) } if respond_to? :rightclick
                end
        end
end
mouseReleaseEvent(ev) click to toggle source
# File metasm/gui/qt.rb, line 249
def mouseReleaseEvent(ev)
        if ev.button == Qt::LeftButton
                protect { mouserelease(ev.x, ev.y) } if respond_to? :mouserelease
        end
end
mouserelease_buttons(x, y) click to toggle source

the mouse was released, call button action if it is pressed should be called during mouserelease

# File metasm/gui/win32.rb, line 2019
def mouserelease_buttons(x, y)
        @buttons.find { |b| b.mouserelease(x, y) }
end
new_menu() click to toggle source
# File metasm/gui/gtk.rb, line 354
def new_menu
        toplevel.new_menu
end
paint() click to toggle source
# File metasm/gui/gtk.rb, line 382
def paint
end
paintEvent(*a) click to toggle source
# File metasm/gui/qt.rb, line 278
def paintEvent(*a)
        @painter = Qt::Painter.new(self)
        protect { paint }
        @painter.end
        @painter = nil
end
paint_(realhdc) click to toggle source
# File metasm/gui/win32.rb, line 1846
def paint_(realhdc)
        @hdc = Win32Gui.createcompatibledc(realhdc)
        bmp = Win32Gui.createcompatiblebitmap(realhdc, @width, @height)
        Win32Gui.selectobject(@hdc, bmp)
        Win32Gui.selectobject(@hdc, Win32Gui.getstockobject(Win32Gui::DC_BRUSH))
        Win32Gui.selectobject(@hdc, Win32Gui.getstockobject(Win32Gui::DC_PEN))
        Win32Gui.selectobject(@hdc, Win32Gui.getstockobject(Win32Gui::ANSI_FIXED_FONT))
        Win32Gui.setbkmode(@hdc, Win32Gui::TRANSPARENT)
        draw_rectangle_color(:background, 0, 0, @width, @height)
        paint
        Win32Gui.bitblt(realhdc, @x, @y, @width, @height, @hdc, 0, 0, Win32Gui::SRCCOPY)
        Win32Gui.deleteobject(bmp)
        Win32Gui.deletedc(@hdc)
        @hdc = nil
end
paint_buttons() click to toggle source

render the buttons on the widget should be called during paint

# File metasm/gui/win32.rb, line 2007
def paint_buttons
        @buttons.each { |b| b.paint(self) }
end
popupmenu(m, x, y) click to toggle source
# File metasm/gui/gtk.rb, line 360
def popupmenu(m, x, y)
        toplevel.popupmenu(m, (x+allocation.x).to_i, (y+allocation.y).to_i)
end
redraw() click to toggle source

invalidate the whole widget area

# File metasm/gui/gtk.rb, line 386
def redraw
        invalidate(0, 0, 1000000, 1000000)
end
resizeEvent(ev) click to toggle source
# File metasm/gui/qt.rb, line 272
def resizeEvent(ev)
        protect { resized(ev.size.width, ev.size.height) } if respond_to? :resized
end
resized(w, h) click to toggle source
# File metasm/gui/gtk.rb, line 407
def resized(w, h)
        redraw
end
resized_(w, h) click to toggle source
# File metasm/gui/win32.rb, line 1862
def resized_(w, h)
        @width = w
        @height = h
        resized(w, h) if respond_to? :resized
end
set_caret_from_click(x, y) click to toggle source
# File metasm/gui/gtk.rb, line 321
def set_caret_from_click(x, y)
        @caret_x = (x-1).to_i / @font_width
        @caret_y = y.to_i / @font_height
        update_caret
end
set_color_association(hash) click to toggle source

change the color association arg is a hash function symbol => color symbol check initialize/sig('realize') for initial function/color list if called before the widget is first displayed onscreen, will register a hook to re-call itself later

# File metasm/gui/gtk.rb, line 340
def set_color_association(hash)
        if not realized?
                sid = signal_connect('realize') {
                        signal_handler_disconnect(sid)
                        set_color_association(hash)
                }
        else
                hord = Hash.new { |h, k| h[k] = (hash[k] ? h[hash[k]] + 1 : 0) }
                hash.sort_by { |k, v| hord[k] }.each { |k, v| @color[k] = color(v) }
                modify_bg Gtk::STATE_NORMAL, @color[:background]
                gui_update
        end
end
set_font(descr) click to toggle source

change the font of the widget arg is a Gtk Fontdescription string (eg 'courier 10')

# File metasm/gui/gtk.rb, line 329
def set_font(descr)
        @layout.font_description = Pango::FontDescription.new(descr)
        @layout.text = 'x'
        @font_width, @font_height = @layout.pixel_size
        gui_update
end
update_hl_word(line, offset, mode=:asm) click to toggle source

update @hl_word from a line & offset, return nil if unchanged

# File metasm/gui/gtk.rb, line 365
def update_hl_word(line, offset, mode=:asm)
        return if not line
        word = line[0...offset].to_s[/\w*$/] << line[offset..-1].to_s[/^\w*/]
        word = nil if word == ''
        if @hl_word != word
                if word
                        if mode == :asm and defined?(@dasm) and @dasm
                                re = @dasm.gui_hilight_word_regexp(word)
                        else
                                re = Regexp.escape word
                        end
                        @hl_word_re = /^(.*?)(\b(?:#{re})\b)/
                end
                @hl_word = word
        end
end
wheelEvent(ev) click to toggle source
# File metasm/gui/qt.rb, line 263
def wheelEvent(ev)
        dir = ev.delta > 0 ? :up : :down
        if ev.modifiers.to_i & Qt::ControlModifier.to_i > 0
                protect { mouse_wheel_ctrl(dir, ev.x, ev.y) } if respond_to? :mouse_wheel_ctrl
        else
                protect { mouse_wheel(dir, ev.x, ev.y) } if respond_to? :mouse_wheel
        end
end
width() click to toggle source
# File metasm/gui/gtk.rb, line 399
def width
        allocation.width
end