#!/usr/bin/ruby # # @file Styler # # @copyright (c) 2010-2011, Christoph Kappel # @version $Id$ # # This program can be distributed under the terms of the GNU GPLv2. # See the file COPYING for details. # # Styler is a helper to create or change subtle color themes # # http://subforge.org/projects/subtle-contrib/wiki/Styler # require 'singleton' begin require 'subtle/subtlext' rescue LoadError puts ">>> ERROR: Couldn't find subtlext" exit end begin require 'gtk2' rescue LoadError puts <>> ERROR: Couldn't find the gem `gtk2' >>> Please install it with following command: >>> gem install gtk2 EOF exit end # Check whether subtle is running unless(Subtlext::Subtle.running?) puts ">>> WARNING: Couldn't find running subtle" #exit end # Check for subtlext version major, minor, teeny = Subtlext::VERSION.split(".").map(&:to_i) if(major == 0 and minor == 10 and 2945 > teeny) puts ">>> ERROR: styler needs at least subtle `0.10.2945' (found: %s)" % [ Subtlext::VERSION ] exit end # Styler class module Subtle # {{{ module Contrib # {{{ class ColorButton DEFAULT_COLOR = '#000000' attr_reader :value ## initialize {{{ # Create a new color button # @param [String] color Default color ## def initialize(color = DEFAULT_COLOR, &block) @value = color @original = color @callback = nil # Create color button @button = Gtk::ColorButton.new( Gdk::Color.parse(color) ) # Signal handler @button.signal_connect('color-set') do |button| # Assemble hex color @value = '#%02x%02x%02x' % [ factor_round((button.color.red.to_f / 65535), 255), factor_round((button.color.green.to_f / 65535), 255), factor_round((button.color.blue.to_f / 65535), 255) ] @callback.call(@value) unless(@callback.nil?) Styler.instance.render end end # }}} ## value= {{{ # Set value # @param [Fixnum] value New value ## def value=(value) @value = value @button.set_color(Gdk::Color.parse(@value)) end # }}} ## attach {{{ # Attach color button to table # @param [Table] table A #Gtk::Table # @param [Fixnum] x X slot # @param [Fixnum] y Y slot ## def attach(table, x, y) table.attach(@button, x, x + 1, y, y + 1, Gtk::FILL, Gtk::SHRINK) end # }}} ## reset {{{ # Reset color button to default color ## def reset @value = @original @button.set_color(Gdk::Color.parse(@original)) end # }}} ## callback {{{ # Add event callback ## def callback(&block) @callback = block end # }}} private def factor_round(val, factor) # {{{ val = (val * factor + 0.5).floor val = val > 0 ? val : 0 #< Min val = val > factor ? factor : val #< Max val end # }}} end class SpinButton attr_reader :value ## initialize {{{ # Create a new spin button # @param [Fixnum] value Default value # @param [Fixnum] min Minimum value # @param [Fixnum] max Maximum value ## def initialize(value = 0, min = 0, max = 100) @value = value @original = value @callback = nil # Create adjustment adjustment = Gtk::Adjustment.new(value, min, max, 1, 5, 0) # Create spin button @spinner = Gtk::SpinButton.new(adjustment, 0, 0) @spinner.set_size_request(40, -1) # Signal handler @spinner.signal_connect('value_changed') do |spinner| @value = spinner.value_as_int @callback.call(@value) unless(@callback.nil?) Styler.instance.render end end # }}} ## value= {{{ # Set value # @param [Fixnum] value New value ## def value=(value) @value = value @spinner.value = value end # }}} ## attach {{{ # Attach spin button to table # @param [Table] table A #Gtk::Table # @param [Fixnum] x X slot # @param [Fixnum] y Y slot ## def attach(table, x, y) table.attach(@spinner, x, x + 1, y, y + 1, Gtk::FILL, Gtk::SHRINK) end # }}} ## reset {{{ # Reset spin button to default value ## def reset @value = @original @spinner.value = @original end # }}} ## callback {{{ # Add event callback ## def callback(&block) @callback = block end # }}} end class Style attr_accessor :buttons ## reset {{{ # Reset elements of style ## def reset @buttons.each do |k, v| if v.respond_to?(:reset) v.reset elsif(v.is_a?(Hash)) v.each do |side, spin| spin.reset if(spin.respond_to?(:reset)) end end end end # }}} ## append {{{ # Append to notebook # @param [Notebook] notebook A #Gtk::Notebook ## def append(notebook) label = Gtk::Label.new(@name) notebook.append_page(@table, label) end # }}} ## [] {{{ # Acces values # @param [Symbol] name Value name ## def [](name) case @buttons[name] when ColorButton then @buttons[name].value when Hash then @buttons[name] end end # }}} ## attach_label {{{ # Attach a label to the table # @param [Fixnum] x X slot # @param [Fixnum] y Y slot # @param [String] caption Label caption ## def attach_label(x, y, caption) label = Gtk::Label.new(caption) @table.attach(label, x, x + 1, y, y + 1) end # }}} ## sum {{{ # Get total width of given styles # @param [Array] List of styles # @return [Fixnum] Width in pixel ## def sum(list) width = 0 [ :border, :padding, :margin ].each do |button| list.each do |l| if(@buttons[button][l].respond_to?(:value)) width += @buttons[button][l].value end end end width end # }}} private def compact(name) # {{{ ret = [] val = @buttons[name] # Compact padding/margin values if(val[:top].value == val[:bottom].value and val[:top].value == val[:right].value and val[:top].value == val[:left].value) ret << val[:top].value elsif(val[:top].value == val[:bottom].value and val[:left].value == val[:right].value) ret << val[:top].value ret << val[:left].value elsif(val[:left].value == val[:right].value) ret << val[:top].value ret << val[:left].value ret << val[:bottom].value else ret = val.values.map(&:value) end ret.join(', ') end # }}} end class StyleNormal < Style ## initialize {{{ # Create a new style element # @param [String] name Element name # @param [Array] colors Color array ## def initialize(name, colors) @name = name @buttons = {} # Table @table = Gtk::Table.new(5, 7) # Labels: Vertical attach_label(0, 1, 'Foreground') attach_label(0, 2, 'Background') attach_label(0, 3, 'Top') attach_label(0, 4, 'Right') attach_label(0, 5, 'Bottom') attach_label(0, 6, 'Left') # Labels: Horizontal attach_label(1, 0, 'Color') attach_label(2, 0, 'Border') attach_label(3, 0, 'Padding') attach_label(4, 0, 'Margin') # Color buttons y = 1 { :fg => 'fg', :bg => 'bg', :top => 'bo_top', :right => 'bo_right', :bottom => 'bo_bottom', :left => 'bo_left' }.each do |name, suffix| @buttons[name] = ColorButton.new( colors[('%s_%s' % [ @name.downcase, suffix ]).to_sym] || ColorButton::DEFAULT_COLOR ) @buttons[name].attach(@table, 1, y) y += 1 end # Spin buttons x = 2 [ :border, :padding, :margin ].each do |name| @buttons[name] = {} y = 3 [ :top, :right, :bottom, :left ].each do |side| @buttons[name][side] = SpinButton.new(0) @buttons[name][side].attach(@table, x, y) y += 1 end x += 1 end end # }}} ## dump {{{ # Print style element ## def dump puts "style :#{@name.downcase} do" puts " foreground '#{@buttons[:fg].value}'" puts " background '#{@buttons[:bg].value}'" # Compact borders if(@buttons[:top].value == @buttons[:right].value and @buttons[:top].value == @buttons[:bottom].value and @buttons[:top].value == @buttons[:left].value and @buttons[:border][:top].value == @buttons[:border][:left].value and @buttons[:border][:top].value == @buttons[:border][:bottom].value and @buttons[:border][:top].value == @buttons[:border][:right].value) puts " border '#{@buttons[:top].value}', #{@buttons[:border][:top].value}" else puts " border_top '#{@buttons[:top].value}', #{@buttons[:border][:top].value}" puts " border_right '#{@buttons[:right].value}', #{@buttons[:border][:right].value}" puts " border_bottom '#{@buttons[:bottom].value}', #{@buttons[:border][:bottom].value}" puts " border_left '#{@buttons[:left].value}', #{@buttons[:border][:left].value}" end puts " padding #{compact(:padding)}" puts " margin #{compact(:margin)}" puts "end" puts end # }}} end class StyleClients < Style ## initialize {{{ # Create a new other element # @param [String] name Element name # @param [Array] colors Color array ## def initialize(name, colors) @name = name @table = Gtk::Table.new(5, 7) @buttons = {} # Labels: Vertical attach_label(0, 1, 'Client active') attach_label(0, 2, 'Client inactive') attach_label(0, 3, 'Top') attach_label(0, 4, 'Right') attach_label(0, 5, 'Bottom') attach_label(0, 6, 'Left') # Labels: Horizontal attach_label(1, 0, 'Color') attach_label(2, 0, 'Border') attach_label(3, 0, 'Padding') attach_label(4, 0, 'Margin') # Buttons y = 1 [ :active, :inactive ].each do |name| # Color button @buttons[name] = ColorButton.new( colors[('client_%s' % name).to_sym] ) @buttons[name].attach(@table, 1, y) # Border spinner sym = ('%s_border' % [ name ]).to_sym @buttons[sym] = SpinButton.new(2) @buttons[sym].attach(@table, 2, y) y += 1 end # Margin @buttons[:margin] = {} [ :top, :right, :bottom, :left ].each do |side| @buttons[:margin][side] = SpinButton.new(0) @buttons[:margin][side].attach(@table, 4, y) y += 1 end # Fill remaining fields @buttons[:fg] = @buttons[:active] @buttons[:bg] = @buttons[:inactive] @buttons[:border ] = { top: @buttons[:active_border], right: @buttons[:active_border], bottom: @buttons[:active_border], left: @buttons[:active_border] } # Just for text placement @buttons[:padding] = { top: 5, right: 0, bottom: 0, left: 5 } end # }}} ## dump {{{ # Print style element ## def dump puts <