From fd6a0d3e05f093dc5c4e94cd98128f50d2e415bf Mon Sep 17 00:00:00 2001 From: gc Date: Tue, 10 Jul 2007 21:00:17 +0000 Subject: [PATCH] much more --- bin/booh-classifier | 304 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 281 insertions(+), 23 deletions(-) diff --git a/bin/booh-classifier b/bin/booh-classifier index 963564c..f221ffb 100644 --- a/bin/booh-classifier +++ b/bin/booh-classifier @@ -181,6 +181,44 @@ def show_mem(*txt) puts get_mem end +def min(v1, v2) + return v1 < v2 ? v1 : v2 +end +def max(v1, v2) + return v1 > v2 ? v1 : v2 +end + +class Gdk::Color + def darker + color = dup + color.red = max(color.red - 10000, 0) + color.green = max(color.green - 10000, 0) + color.blue = max(color.blue - 10000, 0) + return color + end + def lighter + color = dup + color.red = min(color.red + 10000, 65535) + color.green = min(color.green + 10000, 65535) + color.blue = min(color.blue + 10000, 65535) + return color + end +end + +$colors = [ Gdk::Color.new(0, 65535, 0), + Gdk::Color.new(0, 0, 65535), + Gdk::Color.new(65535, 65535, 0), + Gdk::Color.new(0, 65535, 65535), + Gdk::Color.new(65535, 0, 65535) ] + +class Tag + attr_accessor :color, :name + def initialize(name) + @name = name + end +end +$tags = {} + class Entry @@thumbnails_height = 64 @@max_height = nil @@ -188,7 +226,7 @@ class Entry return @@thumbnails_height end - attr_accessor :path, :type, :button + attr_accessor :path, :type, :angle, :button, :removed, :tagged def initialize(path, type) @path = path @@ -266,6 +304,36 @@ class Entry return @pixbuf_thumbnail } end + def free_pixbuf_thumbnail + @protect_cleanup.synchronize { + if @pixbuf_thumbnail.nil? + return false + else + puts ">>> free_pixbuf_thumbnail #{path}" + @pixbuf_thumbnail = nil + return true + end + } + end + + def show_bg + if removed + red = Gdk::Color.new(65535, 0, 0) + button.modify_bg(Gtk::StateType::NORMAL, red) + button.modify_bg(Gtk::StateType::PRELIGHT, red.lighter) + button.modify_bg(Gtk::StateType::ACTIVE, red) + elsif tagged + button.modify_bg(Gtk::StateType::NORMAL, tagged.color) + button.modify_bg(Gtk::StateType::PRELIGHT, tagged.color.lighter) + button.modify_bg(Gtk::StateType::ACTIVE, tagged.color) + else + # TODO need to add proper undo support :/ + white = Gdk::Color.new(55535, 55535, 55535) + button.modify_bg(Gtk::StateType::NORMAL, white) + button.modify_bg(Gtk::StateType::PRELIGHT, white.lighter) + button.modify_bg(Gtk::StateType::ACTIVE, white) + end + end private def load_into_pixbuf_full @@ -278,10 +346,12 @@ class Entry return end if @pixbuf_full - angle = guess_rotate(path) - if angle != 0 - puts ">>> load_into_pixbuf_full #{path} => rotate #{angle}" - @pixbuf_full = rotate_pixbuf(@pixbuf_full, angle) + if @angle.nil? + @angle = guess_rotate(path) + end + if @angle != 0 + puts ">>> load_into_pixbuf_full #{path} => rotate #{@angle}" + @pixbuf_full = rotate_pixbuf(@pixbuf_full, @angle) end if @pixbuf_full.height > @@max_height #- save a lot of memory, don't store in actual full size @@ -344,10 +414,7 @@ class MainView < Gtk::DrawingArea else @entry = $allentries[index] end - update_shown - #- should "freeze" or something to prevent blinking - window.clear - draw + redraw @preloader.run end @@ -355,6 +422,15 @@ class MainView < Gtk::DrawingArea return @index end + def redraw + update_shown + w, h = window.size + window.begin_paint(Gdk::Rectangle.new(0, 0, w, h)) + window.clear + draw + window.end_paint + end + def update_shown if @entry width, height = window.size @@ -378,6 +454,13 @@ class MainView < Gtk::DrawingArea end end + def show_next + if @index < $allentries.size - 1 + next_entry = $allentries[get_shown_entry + 1] + next_entry.button.grab_focus + end + end + end def check_memory_free_cache_if_needed @@ -429,6 +512,169 @@ def autoscroll_if_needed(button) end end +def show_popup(parent, msg, *options) + dialog = Gtk::Dialog.new + if options[0] + options = options[0] + else + options = {} + end + if options[:title] + dialog.title = options[:title] + else + dialog.title = utf8(_("Booh message")) + end + lbl = Gtk::Label.new + if options[:nomarkup] + lbl.text = msg + else + lbl.markup = msg + end + if options[:centered] + lbl.set_justify(Gtk::Justification::CENTER) + end + if options[:selectable] + lbl.selectable = true + end + if options[:topwidget] + dialog.vbox.add(options[0][:topwidget]) + end + if options[:scrolled] + sw = Gtk::ScrolledWindow.new(nil, nil) + sw.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC) + sw.add_with_viewport(lbl) + dialog.vbox.add(sw) + dialog.set_default_size(500, 600) + else + dialog.vbox.add(lbl) + dialog.set_default_size(200, 120) + end + if options[:bottomwidget] + dialog.vbox.add(options[:bottomwidget]) + end + if options[:okcancel] + dialog.add_button(Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL) + end + dialog.add_button(Gtk::Stock::OK, Gtk::Dialog::RESPONSE_OK) + + if options[:pos_centered] + dialog.window_position = Gtk::Window::POS_CENTER + else + dialog.window_position = Gtk::Window::POS_MOUSE + end + + if options[:linkurl] + linkbut = Gtk::Button.new('') + linkbut.child.markup = "#{options[0][:linkurl]}" + linkbut.signal_connect('clicked') { + open_url(options[0][:linkurl] + '/index.html') + dialog.response(Gtk::Dialog::RESPONSE_OK) + set_mousecursor_normal + } + linkbut.relief = Gtk::RELIEF_NONE + linkbut.signal_connect('enter-notify-event') { set_mousecursor(Gdk::Cursor::HAND2, linkbut); false } + linkbut.signal_connect('leave-notify-event') { set_mousecursor(nil, linkbut); false } + dialog.vbox.add(Gtk::Alignment.new(0.5, 0.5, 0, 0).add(linkbut)) + end + + dialog.show_all + + if options[:stuff_connector] + options[:stuff_connector].call({ :dialog => dialog }) + end + + if !options[:not_transient] + dialog.transient_for = parent + dialog.run { |response| + if options[:data_getter] + options[:data_getter].call + end + dialog.destroy + if options[:okcancel] + return response == Gtk::Dialog::RESPONSE_OK + end + } + else + dialog.signal_connect('response') { dialog.destroy } + end +end + +def thumbnail_keypressed(entry, event) + if event.state & Gdk::Window::MOD1_MASK != 0 + #- ALT pressed: Alt-Left and Alft-Right rotate + if event.keyval == Gdk::Keyval::GDK_Left || event.keyval == Gdk::Keyval::GDK_Right + if event.keyval == Gdk::Keyval::GDK_Left + entry.angle = (entry.angle - 90) % 360 + else + entry.angle = (entry.angle + 90) % 360 + end + entry.free_pixbuf_full + entry.free_pixbuf_main + entry.free_pixbuf_thumbnail + $mainview.redraw + entry.button.set_image(img = Gtk::Image.new(entry.pixbuf_thumbnail)) + end + + else + if event.keyval == Gdk::Keyval::GDK_Delete + entry.removed = true + entry.tagged = nil + entry.show_bg + $mainview.show_next + + elsif event.keyval == Gdk::Keyval::GDK_space + entry.removed = false + entry.tagged = nil + entry.show_bg + $mainview.show_next + + else + char = [ Gdk::Keyval.to_unicode(event.keyval) ].pack("C*") + if char =~ /^[a-zA-z0-9]$/ + tag = $tags[char] + + if tag.nil? + vb = Gtk::VBox.new(false, 0) + vb.pack_start(entry = Gtk::Entry.new.set_text(char), false, false) + vb.pack_start(Gtk::Alignment.new(0.5, 0.5, 0, 0).add(bt = Gtk::Button.new(utf8(_(" Change color "))))) + text = nil + color = nil + bt.signal_connect('clicked') { + color = $colors.shift + if color.nil? + color = Gdk::Color.new(16384 + rand(49151), 16384 + rand(49151), 16384 + rand(49151)) + end + bt.modify_bg(Gtk::StateType::NORMAL, color) + bt.modify_bg(Gtk::StateType::PRELIGHT, color) + bt.modify_bg(Gtk::StateType::ACTIVE, color.darker) + } + bt.clicked + if show_popup($main_window, + utf8(_("You typed the text character '%s', which is not associated with a tag.\nType in the full name of the tag below to create a new one.")) % char, + { :okcancel => true, :bottomwidget => vb, :data_getter => proc { text = entry.text }, + :stuff_connector => proc { |stuff| entry.select_region(0, 0); entry.position = -1; + entry.signal_connect('activate') { stuff[:dialog].response(Gtk::Dialog::RESPONSE_OK) } } } ) + if text.length > 0 + char = text[0,1] #- in case it changed + tag = Tag.new(text) + tag.color = color + $tags[char] = tag + label = Gtk::Label.new.set_markup('(' + char + ')' + text[1..-1]).set_justify(Gtk::Justification::CENTER) + $tags_vbox.pack_start(evt = Gtk::EventBox.new.add(label).modify_bg(Gtk::StateType::NORMAL, tag.color).show_all) + end + end + + else + entry.removed = false + entry.tagged = tag + entry.show_bg + $mainview.show_next + end + end + end + end +end + def show_entries e = Thread.new { t1 = Time.now @@ -447,6 +693,7 @@ def show_entries $imagesline.pack_start(entry.button.show_all, false, false) entry.button.signal_connect('clicked') { $mainview.set_shown_entry(i) } entry.button.signal_connect('focus-in-event') { entry.button.clicked; autoscroll_if_needed(entry.button) } + entry.button.signal_connect('key-press-event') { |w, e| thumbnail_keypressed(entry, e) } if i == 0 entry.button.grab_focus end @@ -488,8 +735,7 @@ def open_dir(path) end Dir.entries(dir).each { |file| type = entry2type(file) - if type -# && $allentries.size < 5 + if type && $allentries.size < 2 $allentries << Entry.new(File.join(dir, file), type) end } @@ -594,13 +840,25 @@ def create_menubar return mb end +def reset_tags + for child in $tags_vbox.children + $tags_vbox.remove(child) + end + $tags_vbox.pack_start(Gtk::Label.new(utf8(_("Tags list:"))).set_justify(Gtk::Justification::CENTER), false, false) +end + def create_main_window mb = create_menubar main_vbox = Gtk::VBox.new(false, 0) main_vbox.pack_start(mb, false, false) - main_vbox.pack_start($mainview = MainView.new, true, true) + mainview_hbox = Gtk::HBox.new + mainview_hbox.pack_start(tags_vbox_vbox = Gtk::VBox.new(false, 0), false, true) + tags_vbox_vbox.pack_start($tags_vbox = Gtk::VBox.new(false, 5), false, false) + reset_tags + mainview_hbox.pack_start($mainview = MainView.new, true, true) + main_vbox.pack_start(mainview_hbox, true, true) $imagesline_sw = Gtk::ScrolledWindow.new(nil, nil) $imagesline_sw.set_policy(Gtk::POLICY_ALWAYS, Gtk::POLICY_NEVER) $imagesline_sw.add_with_viewport($imagesline = Gtk::HBox.new(false, 0)) @@ -656,17 +914,17 @@ Gtk.init #- Gdk::Pixbuf#rotate memory leak check (in ruby-gnome2 <= 0.16.0) -pb = Gdk::Pixbuf.new("#{$FPATH}/images/logo.png") -1.upto(5) { pb = pb.rotate(Gdk::Pixbuf::ROTATE_CLOCKWISE) } -GC.start -mem = get_mem -1.upto(5) { pb = pb.rotate(Gdk::Pixbuf::ROTATE_CLOCKWISE) } -GC.start -mem2 = get_mem -if mem2 != mem - puts _("Gdk::Pixbuf#scale memory leak detected (this is normal with unpatched ruby-gnome2 <= 0.16.0). Application would slow down to a crawl, won't proceed.") - exit 1 -end +#pb = Gdk::Pixbuf.new("#{$FPATH}/images/logo.png") +#1.upto(5) { pb = pb.rotate(Gdk::Pixbuf::ROTATE_CLOCKWISE) } +#GC.start +#mem = get_mem +#1.upto(5) { pb = pb.rotate(Gdk::Pixbuf::ROTATE_CLOCKWISE) } +#GC.start +#mem2 = get_mem +#if mem2 != mem +# puts _("Gdk::Pixbuf#scale memory leak detected (this is normal with unpatched ruby-gnome2 <= 0.16.0). Application would slow down to a crawl, won't proceed.") +# exit 1 +#end create_main_window -- 2.30.4