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 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 206
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 362
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 513
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 518
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 314
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 426
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 453
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 480
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 430
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 448
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 485
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 491
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 497
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 422
def gui_update
        redraw
end
height() click to toggle source
# File metasm/gui/gtk.rb, line 408
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 309
def initialize_widget
end
invalidate(x, y, w, h) click to toggle source
# File metasm/gui/gtk.rb, line 399
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 395
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 523
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 416
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 419
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 359
def new_menu
        toplevel.new_menu
end
paint() click to toggle source
# File metasm/gui/gtk.rb, line 387
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 365
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 391
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 412
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 326
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 345
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 334
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 370
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 404
def width
        allocation.width
end