Ads

 

How to make a clickable label in Gtk2/ruby

Sometimes, you need a Gtk label, styled like a web link that opens an URL when you click. I need this widget for the todo-summarizer Gtk2 GUI and I don't like the look and feel of the Gtk LinkButton widget.

So, I wrote a custom ClickableLabel widget that handle the URL, opens your system's default web browser, shows the destination URL either in a tooltip or a status label and change the mouse cursor change when you hover it.
A clickable label used in todo-summarizer

This code was inspired by two articles written in perl/gtk2 you can found here : part1 and part2.

The main issue in this class is that Gtk::Label can't handle mouse events, so you have to use a Gtk:EventBox and use #pack_start to make the whole thing visible.

The last thing to implement is the mouse cursor change : just remember than you can only set the cursor of a Gdk::Window (not a Gtk one).

Here the complete source of this new widget :
# A clickable Gtk::Label styled as a web link
#
# parent:       The parent widget (or box...)
# text:         The text of the label
# uri:          The uri your browser will open if you click
# status_label: An optional label to print the destination 
#               URI when you hover the label. If no status_label 
#               is provided, URI is printed in a tooltip
class ClickableLabel < Gtk::Label
 def initialize(parent, text, uri, status_label = nil)
    super() # Avoid the 'uninitialize GLib::Object' issue
    self.set_markup("<span color=\"blue\"><u>%s</u></span>"%text)

    eb = Gtk::EventBox.new()
    eb.add(self)
    eb.signal_connect('button-press-event') do
      open uri
    end
    parent.pack_start(eb) # Make the whole thing visible

    # Do not try to change the cursor here, self.window 
    # returns nil because the widget isn't actualy created.
    
    eb.signal_connect('enter-notify-event') do
      if status_label
        status_label.set_text(uri)
      end
      # The default cursor is actually Gdk::Cursor::Type::ARROW
      cur = Gdk::Cursor.new(Gdk::Cursor::Type::HAND1)
      # Get the underlying Gdk::Window of the label and change 
      # its mouse cursor
      self.window.set_cursor(cur)
    end
    
    if status_label
      eb.signal_connect('leave-notify-event') do 
        status_label.set_text('')
      end
    else
      self.set_tooltip_text(uri)
    end

  end

  # From http://stackoverflow.com/a/14053693
  # Should be tested
  def open(link)
    if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
      system "start #{link}"
    elsif RbConfig::CONFIG['host_os'] =~ /darwin/
      system "open #{link}"
    elsif RbConfig::CONFIG['host_os'] =~ /linux|bsd/
      system "xdg-open #{link}"
    end
  end
end
You can use this with our without a status label to show the destination URL :
txt="My blog's URL"
url="https://dailycommit.blogspot.com"
# Without a status label, destination is in a tooltip
ClickableLabel.new(vbox, txt, uri)
# With a status label, destination is printed on mouse hover
ClickableLabel.new(vbox, txt, uri, status)

Comments

Ads