Kouhei Sutou
kous****@users*****
Thu May 11 17:21:26 JST 2006
Index: kazehakase/data/ext/ruby/kz/Makefile.am diff -u kazehakase/data/ext/ruby/kz/Makefile.am:1.2 kazehakase/data/ext/ruby/kz/Makefile.am:1.3 --- kazehakase/data/ext/ruby/kz/Makefile.am:1.2 Wed May 10 17:43:19 2006 +++ kazehakase/data/ext/ruby/kz/Makefile.am Thu May 11 17:21:26 2006 @@ -6,6 +6,8 @@ extruby_DATA = \ ruby-dialog.rb \ ruby-completion.rb \ + search-window.rb \ + utils.rb \ actions.rb EXTRA_DIST = \ Index: kazehakase/data/ext/ruby/kz/ruby-dialog.rb diff -u kazehakase/data/ext/ruby/kz/ruby-dialog.rb:1.11 kazehakase/data/ext/ruby/kz/ruby-dialog.rb:1.12 --- kazehakase/data/ext/ruby/kz/ruby-dialog.rb:1.11 Thu May 11 13:31:47 2006 +++ kazehakase/data/ext/ruby/kz/ruby-dialog.rb Thu May 11 17:21:26 2006 @@ -17,6 +17,7 @@ # require "kz/ruby-completion" +require "kz/search-window" module Kz class SandBox @@ -67,6 +68,7 @@ false end init_history + init_search init_output_area init_input_area init_buttons @@ -99,6 +101,44 @@ end end + def init_search + searcher = Object.new + def searcher.regexp(text) + /#{Regexp.quote(text)}/i + end + @search_window = SearchWindow.new(searcher) + @search_window.window.set_transient_for(@dialog) + entry = @search_window.entry + direction = @search_window.direction + entry.signal_connect("key_press_event") do |widget, event| + handled = false + if event.state.control_mask? + handled = true + case event.keyval + when Gdk::Keyval::GDK_s + search_history(true) + when Gdk::Keyval::GDK_r + search_history(false) + when Gdk::Keyval::GDK_g + stop_history_search + else + handled = false + end + end + handled + end + entry.signal_connect("changed") do + search_history_with_current_input + end + direction.signal_connect("toggled") do + search_history_with_current_input(true) + end + entry.signal_connect("activate") do + stop_history_search + true + end + end + def init_output_area init_text_view end @@ -115,7 +155,7 @@ @buffer.apply_tag(@all_tag, start, iter) false end - sw = add_scrooled_window(@view) + sw = add_scrolled_window(@view) @dialog.vbox.pack_start(sw, true, true, 0) end @@ -235,13 +275,25 @@ handled = true when Gdk::Keyval::GDK_i @ruby_exp_completion.insert_prefix if event.state.control_mask? + when Gdk::Keyval::GDK_s + if event.state.control_mask? + search_history(true) + handled = true + end + when Gdk::Keyval::GDK_r + if event.state.control_mask? + search_history(false) + handled = true + end end handled end def activate_input text =****@entry***** - unless text.empty? + if text.empty? + @history_spin.value = @@history.size + else eval_print(text) update_history(text) end @@ -280,6 +332,61 @@ handled end + def search_history(forward=false) + unless @search_window.visible? + @search_window.show + adjust_search_window + end + + if @search_window.forward? == forward + search_history_with_current_input(true) + else + @search_window.forward = forward + end + end + + def stop_history_search + @search_window.hide + @search_window.entry.text = "" + end + + def adjust_search_window + Utils.move_to_bottom_left_outer(@entry, @search_window.window) + end + + def search_history_with_current_input(search_next=false) + Kz.barrier do + return if @search_window.empty? + change_to_matched_history(@search_window.regexp, + @search_window.forward?, + search_next) + end + end + + def change_to_matched_history(reg, forward, search_next=false) + current_index = @history_spin.value.to_i + indexes = [] + @@history.each_with_index do |text, i| + indexes << i if reg =~ text + end + target_index = nil + indexes.each_with_index do |index, i| + if index == current_index + target_index = i + target_index += (forward ? 1 : -1) if search_next + break + elsif index > current_index + target_index = i + (forward ? 0 : -1) + break + end + end + target_index = indexes.size - 1 if target_index.nil? and !forward + if target_index and target_index >= 0 and target_index < indexes.size + @history_spin.value = indexes[target_index].to_f + @entry.position = reg =~ @entry.text + end + end + def eval_print(text) @buffer.insert(@buffer.end_iter, ">> ") @buffer.insert(@buffer.end_iter, text, @input_tag) @@ -293,7 +400,7 @@ @view.scroll_to_mark(@end_mark, 0, false, 0, 1) end - def add_scrooled_window(widget) + def add_scrolled_window(widget) sw = Gtk::ScrolledWindow.new sw.border_width = 5 sw.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC) Index: kazehakase/data/ext/ruby/kz/search-window.rb diff -u /dev/null kazehakase/data/ext/ruby/kz/search-window.rb:1.1 --- /dev/null Thu May 11 17:21:26 2006 +++ kazehakase/data/ext/ruby/kz/search-window.rb Thu May 11 17:21:26 2006 @@ -0,0 +1,103 @@ +module Kz + class SearchWindow + + attr_reader :window, :direction, :entry + def initialize(searcher) + @searcher = searcher + init_window + end + + def show + send_focus_change(true) + @window.show + end + + def hide + send_focus_change(false) + @window.hide + end + + def visible? + @window.visible? + end + + def destroy + hide + @window.destroy + end + + def forward=(forward) + @direction.active = forward + end + + def forward? + @direction.active? + end + + def empty? + /\A\s*\z/ =~ @entry.text + end + + def regexp + @searcher.regexp(@entry.text) + end + + private + def init_window + @window = Gtk::Window.new(Gtk::Window::POPUP) + @window.modal = true + init_frame + init_box + init_entry + init_direction + end + + def init_frame + @frame = Gtk::Frame.new + @frame.shadow_type = Gtk::ShadowType::ETCHED_IN + @frame.show + @window.add(@frame) + end + + def init_box + @box = Gtk::HBox.new + @box.border_width = 3 + @box.show + @frame.add(@box) + end + + def init_entry + @entry = Gtk::Entry.new + @entry.show + @box.add(@entry) + end + + def init_direction + @direction = Gtk::ToggleButton.new + @arrow = Gtk::Arrow.new(Gtk::Arrow::LEFT, Gtk::SHADOW_NONE) + @arrow.show + @direction.add(@arrow) + @direction.can_focus = false + @direction.show + @box.add(@direction) + @direction.signal_connect("toggled") do |button| + if forward? + type = Gtk::Arrow::RIGHT + else + type = Gtk::Arrow::LEFT + end + @arrow.set(type, Gtk::SHADOW_NONE) + end + @direction.active = true + end + + def send_focus_change(focus_in) + @entry.has_focus = focus_in + event = Gdk::EventFocus.new(Gdk::EventFocus::FOCUS_CHANGE) + event.window =****@entry***** + event.in = focus_in + @entry.event(event) + @entry.notify("has-focus") + end + end +end Index: kazehakase/data/ext/ruby/kz/utils.rb diff -u /dev/null kazehakase/data/ext/ruby/kz/utils.rb:1.1 --- /dev/null Thu May 11 17:21:26 2006 +++ kazehakase/data/ext/ruby/kz/utils.rb Thu May 11 17:21:26 2006 @@ -0,0 +1,89 @@ +module Kz + module Utils + module_function + def move_to(base, target) + window = base.window + screen = window.screen + num = screen.get_monitor(window) + monitor = screen.monitor_geometry(num) + window_x, window_y = window.origin + window_width, window_height = window.size + target_width, target_height = target.size_request + + args = [window_x, window_y, window_width, window_height] + args.concat([target_width, target_height]) + args.concat([screen.width, screen.height]) + x, y = yield(*args) + + target.move(x, y) + end + + def compute_left_x(base_x) + [base_x, 0].max + end + + def compute_right_x(base_x, base_width, target_width, max_x) + right = base_x + base_width - target_width + [[right, max_x - target_width].min, 0].max + end + + def compute_top_y(base_y) + [base_y, 0].max + end + + def compute_bottom_y(base_y, base_height, target_height, max_y) + bottom = base_y + base_height - target_height + [[bottom, max_y - target_height].min, 0].max + end + + def move_to_top_left(base, target) + move_to(base, target) do |bx, by, bw, bh, tw, th, sw, sh| + [compute_left_x(bx), compute_top_y(by)] + end + end + + def move_to_top_left_outer(base, target) + move_to(base, target) do |bx, by, bw, bh, tw, th, sw, sh| + [compute_left_x(bx), compute_top_y(by) - th] + end + end + + def move_to_top_right(base, target) + move_to(base, target) do |bx, by, bw, bh, tw, th, sw, sh| + [compute_right_x(bx, bw, tw, sw), compute_top_y(by)] + end + end + + def move_to_top_right_outer(base, target) + move_to(base, target) do |bx, by, bw, bh, tw, th, sw, sh| + [compute_right_x(bx, bw, tw, sw), compute_top_y(by) - th] + end + end + + def move_to_bottom_left(base, target) + move_to(base, target) do |bx, by, bw, bh, tw, th, sw, sh| + [compute_left_x(bx), compute_bottom_y(by, bh, th, sh)] + end + end + + def move_to_bottom_left_outer(base, target) + move_to(base, target) do |bx, by, bw, bh, tw, th, sw, sh| + [compute_left_x(bx), compute_bottom_y(by, bh, th, sh) + th] + end + end + + def move_to_bottom_right(base, target) + move_to(base, target) do |bx, by, bw, bh, tw, th, sw, sh| + [compute_right_x(bx, bw, tw, sw), + compute_bottom_y(by, bh, th, sh)] + end + end + + def move_to_bottom_right(base, target) + move_to(base, target) do |bx, by, bw, bh, tw, th, sw, sh| + [compute_right_x(bx, bw, tw, sw), + compute_bottom_y(by, bh, th, sh) + th] + end + end + end +end