<commit_before>#    This file is part of Metasm, the Ruby assembly manipulation suite
#    Copyright (C) 2006-2009 <NAME>
#
#    Licence is LGPL, see LICENCE in the top-level directory


require 'gtk2'

module Metasm
module Gui

module Protect
	@@lasterror = Time.now
	def protect
		yield
	rescue Object
		puts $!.message, $!.backtrace	# also dump on stdout, for c/c
		delay = Time.now-@@lasterror
		sleep 1-delay if delay < 1	# msgbox flood protection
		@@lasterror = Time.now
		messagebox([$!.message, $!.backtrace].join("\n"), $!.class.name)
	end
end

module Msgbox
	include Protect

	def toplevel
		if self.kind_of? Gtk::Window
			self
		else
			super()
		end
	end

	# shows a message box (non-modal)
	# args: message, title/optionhash
	def messagebox(*a)
		MessageBox.new(toplevel, *a)
	end

	# asks for user input, yields the result (unless 'cancel' clicked)
	# args: prompt, :text => default text, :title => title
	def inputbox(*a)
		InputBox.new(toplevel, *a) { |*ya| protect { yield(*ya) } }
	end

	# asks to chose a file to open, yields filename
	# args: title, :path => path
	def openfile(*a)
		OpenFile.new(toplevel, *a) { |*ya| protect { yield(*ya) } }
	end

	# same as openfile, but for writing a (new) file
	def savefile(*a)
		SaveFile.new(toplevel, *a) { |*ya| protect { yield(*ya) } }
	end

	# displays a popup showing a table, yields the selected row
	# args: title, [[col0 title, col1 title...], [col0 val0, col1 val0...], [val1], [val2]...]
	def listwindow(*a)
		ListWindow.new(toplevel, *a) { |*ya| protect { yield(*ya) } }
	end
end

# clipboard = Gtk::Clipboard.get(Gdk::Selection::CLIPBOARD)
# text = clipboard.wait_for_text
# clipboard.text = 'foo'

# a widget that holds many other widgets, and displays only one of them at a time
class ContainerChoiceWidget < Gtk::Notebook
	include Msgbox

	attr_accessor :views, :view_indexes
	def initialize(*a)
		super()
		self.show_border = false
		self.show_tabs = false
		@views = {}
		@view_indexes = []

		signal_connect('realize') { initialize_visible } if respond_to? :initialize_visible

		initialize_widget(*a)

		show_all
	end

	def view(i)
		@views[i]
	end

	def showview(i)
		set_page @view_indexes.index(i)
	end

	def addview(name, w)
		@view_indexes << name
		@views[name] = w
		append_page(w, Gtk::Label.new(name.to_s))
	end

	def curview
		@views[curview_index]
	end

	def curview_index
		return if page == -1
		@view_indexes[page]
	end
end

class ContainerVBoxWidget < Gtk::VBox
	include Msgbox

	def initialize(*a)
		super()

		signal_connect('realize') { initialize_visible } if respond_to? :initialize_visible

		signal_connect('size_request') { |w, alloc| resize(*alloc) } if respond_to? :resize

		self.spacing = 2

		initialize_widget(*a)
	end

	def resize_child(cld, w, h)
		pk = query_child_packing(cld)
		if h <= 0
			pk[0] = true
			h = 1
		else
			pk[0] = false
		end
		return if h == cld.allocation.height
		set_child_packing(cld, *pk)
		cld.set_height_request(h)
	end

	def redraw
	end
end

class DrawableWidget < Gtk::DrawingArea
	include Msgbox

	attr_accessor :parent_widget, :caret_x, :caret_y, :hl_word
	# 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)
	attr_accessor :default_color_association

	# keypress event keyval traduction table
	Keyboard_trad = Gdk::Keyval.constants.grep(/^GDK_/).inject({}) { |h, cst|
		v = Gdk::Keyval.const_get(cst)
		key = cst.to_s.sub(/^GDK_/, '').sub(/^KP_/, '')
		if key.length == 1
			key = key[0]	# ?a, ?b etc
		else
			key = key.downcase.to_sym
			key = {
			:page_up => :pgup, :page_down => :pgdown, :next => :pgdown,
			:escape => :esc, :return => :enter, :l1 => :f11, :l2 => :f12,

			:space => ?\ ,
			:asciitilde => ?~, :quoteleft => ?`,
			:exclam => ?!, :at => ?@,
			:numbersign => ?#, :dollar => ?$,
			:percent => ?%, :asciicircum => ?^,
			:ampersand => ?&, :asterisk => ?*,
			:parenleft => ?(, :parenright => ?),
			:bracketleft => ?[, :bracketright => ?],
			:braceleft => ?{, :braceright => ?},
			:less  => ?<, :greater  => ?>,
			:quotedbl => ?", :quoteright => ?',
			:coma => ?,, :period => ?.,
			:colon => ?:, :semicolon => ?;,
			:slash => ?/, :equal => ?=,
			:plus => ?+, :minus => ?-,
			:question => ??, :backslash => ?\\,
			:underscore  => ?_, :bar => ?|,
			:comma => ?,,<commit_msg>gui/gtk: add key_prior alias for pgup<commit_after>#    This file is part of Metasm, the Ruby assembly manipulation suite
#    Copyright (C) 2006-2009 <NAME>
#
#    Licence is LGPL, see LICENCE in the top-level directory


require 'gtk2'

module Metasm
module Gui

module Protect
	@@lasterror = Time.now
	def protect
		yield
	rescue Object
		puts $!.message, $!.backtrace	# also dump on stdout, for c/c
		delay = Time.now-@@lasterror
		sleep 1-delay if delay < 1	# msgbox flood protection
		@@lasterror = Time.now
		messagebox([$!.message, $!.backtrace].join("\n"), $!.class.name)
	end
end

module Msgbox
	include Protect

	def toplevel
		if self.kind_of? Gtk::Window
			self
		else
			super()
		end
	end

	# shows a message box (non-modal)
	# args: message, title/optionhash
	def messagebox(*a)
		MessageBox.new(toplevel, *a)
	end

	# asks for user input, yields the result (unless 'cancel' clicked)
	# args: prompt, :text => default text, :title => title
	def inputbox(*a)
		InputBox.new(toplevel, *a) { |*ya| protect { yield(*ya) } }
	end

	# asks to chose a file to open, yields filename
	# args: title, :path => path
	def openfile(*a)
		OpenFile.new(toplevel, *a) { |*ya| protect { yield(*ya) } }
	end

	# same as openfile, but for writing a (new) file
	def savefile(*a)
		SaveFile.new(toplevel, *a) { |*ya| protect { yield(*ya) } }
	end

	# displays a popup showing a table, yields the selected row
	# args: title, [[col0 title, col1 title...], [col0 val0, col1 val0...], [val1], [val2]...]
	def listwindow(*a)
		ListWindow.new(toplevel, *a) { |*ya| protect { yield(*ya) } }
	end
end

# clipboard = Gtk::Clipboard.get(Gdk::Selection::CLIPBOARD)
# text = clipboard.wait_for_text
# clipboard.text = 'foo'

# a widget that holds many other widgets, and displays only one of them at a time
class ContainerChoiceWidget < Gtk::Notebook
	include Msgbox

	attr_accessor :views, :view_indexes
	def initialize(*a)
		super()
		self.show_border = false
		self.show_tabs = false
		@views = {}
		@view_indexes = []

		signal_connect('realize') { initialize_visible } if respond_to? :initialize_visible

		initialize_widget(*a)

		show_all
	end

	def view(i)
		@views[i]
	end

	def showview(i)
		set_page @view_indexes.index(i)
	end

	def addview(name, w)
		@view_indexes << name
		@views[name] = w
		append_page(w, Gtk::Label.new(name.to_s))
	end

	def curview
		@views[curview_index]
	end

	def curview_index
		return if page == -1
		@view_indexes[page]
	end
end

class ContainerVBoxWidget < Gtk::VBox
	include Msgbox

	def initialize(*a)
		super()

		signal_connect('realize') { initialize_visible } if respond_to? :initialize_visible

		signal_connect('size_request') { |w, alloc| resize(*alloc) } if respond_to? :resize

		self.spacing = 2

		initialize_widget(*a)
	end

	def resize_child(cld, w, h)
		pk = query_child_packing(cld)
		if h <= 0
			pk[0] = true
			h = 1
		else
			pk[0] = false
		end
		return if h == cld.allocation.height
		set_child_packing(cld, *pk)
		cld.set_height_request(h)
	end

	def redraw
	end
end

class DrawableWidget < Gtk::DrawingArea
	include Msgbox

	attr_accessor :parent_widget, :caret_x, :caret_y, :hl_word
	# 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)
	attr_accessor :default_color_association

	# keypress event keyval traduction table
	Keyboard_trad = Gdk::Keyval.constants.grep(/^GDK_/).inject({}) { |h, cst|
		v = Gdk::Keyval.const_get(cst)
		key = cst.to_s.sub(/^GDK_/, '').sub(/^KP_/, '')
		if key.length == 1
			key = key[0]	# ?a, ?b etc
		else
			key = key.downcase.to_sym
			key = {
			:page_up => :pgup, :page_down => :pgdown, :next => :pgdown,
			:escape => :esc, :return => :enter, :l1 => :f11, :l2 => :f12,
			:prior => :pgup,

			:space => ?\ ,
			:asciitilde => ?~, :quoteleft => ?`,
			:exclam => ?!, :at => ?@,
			:numbersign => ?#, :dollar => ?$,
			:percent => ?%, :asciicircum => ?^,
			:ampersand => ?&, :asterisk => ?*,
			:parenleft => ?(, :parenright => ?),
			:bracketleft => ?[, :bracketright => ?],
			:braceleft => ?{, :braceright => ?},
			:less  => ?<, :greater  => ?>,
			:quotedbl => ?", :quoteright => ?',
			:coma => ?,, :period => ?.,
			:colon => ?:, :semicolon => ?;,
			:slash => ?/, :equal => ?=,
			:plus => ?+, :minus => ?-,
			:question => ??, :backslash => ?\\,
			:underscore  => ?_, :bar => ?|,
			:comma => ?,,
{'fraction_non_alphanumeric': 0.15856980703745743, 'fraction_numerical': 0.007491486946651533, 'mean_word_length': 3.649604221635884, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 96, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6093087', 'n_tokens_mistral': 3662, 'n_tokens_neox': 3314, 'n_words': 875}