#!/usr/bin/env ruby
# encoding: UTF-8
require File.expand_path File.join(File.dirname(__FILE__), %w{.. lib window_blessing})
include GuiGeo
include WindowBlessing::Tools
include WindowBlessing
include Widgets

class FadeSlider < Slider
  attr_accessor_with_redraw :c1, :c2
  def initialize(area, ev, c1, c2)
    super area, ev, key_press_step: 1/20.0
    @c1 = c1
    @c2 = c2
  end

  def draw_background
    size = buffer.size
    step = (c2 - c1) / (size.x-1).to_f
    line = size.x.times.collect do |x|
      (c1 + step * x).to_screen_color
    end
    buffer.bg_buffer = size.y.times.collect {line.clone}
    buffer.fill :string => " ", :fg => value > 0.5 ? Color.black : Color.white
    draw_handle
  end
end

class ColorPicker2D < Window
  include Evented
  attr_accessor_with_redraw :fixed_channel
  attr_reader :color_ev

  def initialize(area,color_ev,fixed_channel = :g)
    super area
    @color_ev = color_ev
    @fixed_channel = fixed_channel
    request_redraw_internal

    on :pointer do |event|
      loc = event[:loc]
      color = color_ev.get
      old_color = color.clone

      chan1, chan2 = variable_channels
      p = loc / (size - point(1.0,1.0))
      color[chan2] = bound(0.0, p.x, 1.0)
      color[chan1] = bound(0.0, p.y, 1.0)

      color_ev.set color
    end

    color_ev.on :refresh do
      request_redraw_internal
    end
  end

  def variable_channels
    [:r, :g, :b].select {|a| a!=fixed_channel}
  end

  def draw_background
    chan1, chan2 = variable_channels
    color = color_ev.get
    s = size
    c = color.clone
    c[chan1] = 0
    c[chan2] = 0
    buffer.bg_buffer = s.y.times.collect do |y|
      c[chan1] = c1 = y / (s.y-1.0)
      s.x.times.collect do |x|
        c[chan2] = c2 =x / (s.x-1.0)
        c.to_screen_color
      end
    end

    l = point color[chan2]*(size.x-1), color[chan1]*(size.y-1)
    buffer.fill :string => " "
    buffer.fill :area => rect(l.x.to_i,l.y.to_i,1,1), :string => "+"
  end
end

class ColorPreview < Window
  def initialize(area, color_ev)
    super area
    @color_ev = color_ev

    color_ev.on :refresh do
      request_redraw_internal
    end
  end

  def draw_background
    buffer.fill :string => "Mr. Hungerton, her father, really was the most tactless person upon earth, -- a fluffy, feathery, untidy cockatoo of a man, perfectly good-natured, but absolutely centered upon his own silly self.  If anything could have driven me from Gladys, it would have been the thought of such a father-in-law.  I am convinced that he really believed in his heart that I came round to the Chestnuts three days a week for the pleasure of his company, and very especially to hear his views upon bimetallism, a subject upon which he was by way of being an authority. ",
      :bg => @color_ev.get
  end
end

class ColorPicker < Window
  include DraggableBackground
  attr_accessor :gray_slider, :color_preview, :color2d
  attr_accessor :color_ev, :r_ev, :g_ev, :b_ev, :gray_ev

  def create_evented_variables(initial_color)
    @color_ev  = EventedVariable.new(initial_color)
    @r_ev      = EventedVariable.new(initial_color.r).on(:change)  {|event| color = color_ev.get; color.r = event[:value]; color_ev.set color}
    @g_ev      = EventedVariable.new(initial_color.g).on(:change)  {|event| color = color_ev.get; color.g = event[:value]; color_ev.set color}
    @b_ev      = EventedVariable.new(initial_color.b).on(:change)  {|event| color = color_ev.get; color.b = event[:value]; color_ev.set color}
    @gray_ev   = EventedVariable.new(initial_color.br).on(:change) {|event| color_ev.set color(event[:value]) }

    color_ev.on(:change) do |event|
      color = event[:value]
      r_ev.set color.r
      g_ev.set color.g
      b_ev.set color.b
      gray_ev.refresh color.br

      update_label
      @r_value_field.text = color.r256.to_s if @r_value_field.text != color.r256.to_s
      @g_value_field.text = color.g256.to_s if @g_value_field.text != color.g256.to_s
      @b_value_field.text = color.b256.to_s if @b_value_field.text != color.b256.to_s
    end
  end

  def current_color
    @color_ev.get
  end

  def initialize *args
    super rect(2,2,60,30)
    self.bg = gray_screen_color 0.2
    self.fg = gray_screen_color 0.5

    create_evented_variables(Color.white)

    add_child Label.new(rect(2,0,100,1),"Color Picker - Ctrl-Q to quit", :bg => self.bg, :fg => self.fg)

    @r_slider     = add_child FadeSlider.new(rect(10,area.size.y - 10,25,1), r_ev,    Color.black, Color.red  )
    @g_slider     = add_child FadeSlider.new(rect(10,area.size.y - 8,25,1),  g_ev,    Color.black, Color.green)
    @b_slider     = add_child FadeSlider.new(rect(10,area.size.y - 6,25,1),  b_ev,    Color.black, Color.blue )
    @gray_slider  = add_child FadeSlider.new(rect(10,area.size.y - 4,25,1),  gray_ev, Color.black, Color.white)

    text_field_options = {:bg => color(0.1), :fg => Color.gray, :validator => /^[0-9]{0,3}$/}
    @r_value_field = add_child TextField.new(rect(2,area.size.y - 10,5,1), "123", text_field_options)
    @g_value_field = add_child TextField.new(rect(2,area.size.y - 8 ,5,1), "123", text_field_options)
    @b_value_field = add_child TextField.new(rect(2,area.size.y - 6 ,5,1), "123", text_field_options)

    @color2d          = add_child ColorPicker2D.new(rect(area.size.x-15,area.size.y-9,12,6), color_ev)

    @color_preview    = add_child ColorPreview.new(rect(2,2,area.size.x - 20, area.size.y - 14), color_ev)

    @color_info_label = add_child Label.new(rect(2,area.size.y - 2,100,1),"info", :bg => self.bg, :fg => rgb_screen_color(1,1,1))

    @r_slider.on(:pointer, :button1_down) {@color2d.fixed_channel = :r}
    @g_slider.on(:pointer, :button1_down) {@color2d.fixed_channel = :g}
    @b_slider.on(:pointer, :button1_down) {@color2d.fixed_channel = :b}

    @r_value_field.evented_value.on(:change) {|event|r_ev.set bound(0.0,event[:value].to_i/255.0,1.0)}
    @g_value_field.evented_value.on(:change) {|event|g_ev.set bound(0.0,event[:value].to_i/255.0,1.0)}
    @b_value_field.evented_value.on(:change) {|event|b_ev.set bound(0.0,event[:value].to_i/255.0,1.0)}

    @color_info_label.name = "info_label"

    color_ev.set Color.black

    update_label
  end

  def update_label
    @color_info_label.text = "Color: #{current_color.to_hex} / (#{"%.2f, %.2f, %.2f"%current_color.to_a}) / (#{current_color.to_a256.join(', ')})"
  end
end

WindowedScreen.new.start(:full=>true, :utf8 => true) do |screen|
  screen.root_window.add_child ColorPicker.new
  screen.root_window.add_child(ColorPicker.new).loc = point
end