#  -*- indent-tabs-mode: nil -*-

# Original copyright
#
# canvas-curve.c: bezier curve demo.
#
# Copyright (C) 2002 Mark McLoughlin
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
#
# Authors:
#     Mark McLoughlin <mark@skynet.ie>

class CanvasSampleBezierCurve < Gtk::VBox

  STATE_INIT = 0
  STATE_FIRST_PRESS = 1
  STATE_FIRST_RELEASE = 2
  STATE_SECOND_PRESS = 3

  def draw_curve(item, x, y)
    root = item.parent
    
    case @current_state
    when STATE_INIT
      @current_points = [] if @current_points.nil?

      @current_points[0] = x
      @current_points[1] = y
    when STATE_FIRST_PRESS
      @current_points[2] = x
      @current_points[3] = y

      path_def = Gnome::CanvasPathDef.new()

      path_def.moveto(@current_points[0], @current_points[1])
      path_def.lineto(@current_points[2], @current_points[3])

      unless @current_item.nil?
        @current_item.set({:bpath => path_def})
      else
        @current_item = Gnome::CanvasBpath.new(root,
                                               {:bpath => path_def,
                                                 :outline_color => "blue",
                                                 :width_pixels => 5,
                                                 :cap_style => Gdk::GC::CAP_ROUND})
        @current_item.signal_connect("event") do |item, event|
          item_event(item, event)
        end
      end
    when STATE_FIRST_RELEASE
      @current_points[4] = x
      @current_points[5] = y

      path_def = Gnome::CanvasPathDef.new()

      path_def.moveto(@current_points[0], @current_points[1])
      path_def.curveto(@current_points[4], @current_points[5],
                       @current_points[4], @current_points[5],
                       @current_points[2], @current_points[3])

      @current_item.set({:bpath => path_def})

    when STATE_SECOND_PRESS
      @current_points[6] = x;
      @current_points[7] = y;

      path_def = Gnome::CanvasPathDef.new();

      path_def.moveto(@current_points[0], @current_points[1])

      path_def.curveto(@current_points[4], @current_points[5],
                       @current_points[6], @current_points[7],
                       @current_points[2], @current_points[3])

      @current_item.set({:bpath => path_def})
      @current_item = nil
      
    else
      raise "not reached here"
    end
  end

  def item_event(item, event)
    if (event.event_type == Gdk::Event::BUTTON_PRESS &&
        event.button == 1 &&
        (event.state & Gdk::Window::SHIFT_MASK == Gdk::Window::SHIFT_MASK))
      if (item == @current_item)
        @current_item = nil
        @current_state = STATE_INIT
      end

      item.destroy()
      return true
    end
    false
  end


  def canvas_event(item, event)
    case event.event_type
    when Gdk::Event::BUTTON_PRESS
      return false if event.button != 1

      case @current_state
      when STATE_INIT
        draw_curve(item, event.x, event.y)
        @current_state = STATE_FIRST_PRESS
      when STATE_FIRST_RELEASE
        draw_curve(item, event.x, event.y)
        @current_state = STATE_SECOND_PRESS
      when STATE_SECOND_PRESS
        draw_curve(item, event.x, event.y)
        @current_state = STATE_INIT
      else
        raise format("shouldn't have reached here %d", @current_state)
      end
    when Gdk::Event::BUTTON_RELEASE
      return false if event.button != 1

      case @current_state
      when STATE_FIRST_PRESS
        draw_curve(item, event.x, event.y)
        @current_state = STATE_FIRST_RELEASE
      end
    when Gdk::Event::MOTION_NOTIFY
      case @current_state
      when STATE_FIRST_PRESS
        draw_curve(item, event.x, event.y)
      end
    end
    false
  end

  def create_canvas(aa)
    Gtk::Widget.push_colormap(Gdk::RGB.colormap())

    canvas = Gnome::Canvas.new(aa)

    canvas.set_size_request(600, 250) #?
    canvas.set_scroll_region(0, 0, 600, 250)
    canvas.show()

    root = canvas.root

    item = Gnome::CanvasRect.new(root,
                                 {:outline_color => "black",
                                   :fill_color => "white",
                                   :x1 => 0.0,
                                   :y1 => 0.0,
                                   :x2 => 600.0,
                                   :y2 => 250.0})

    Gnome::CanvasText.new(root,
                          {:text => aa ? "AntiAlias" : "Non-AntiAlias",
                            :x => 270.0,
                            :y => 5.0,
                            :font => "Sans 12",
                            :anchor => Gtk::ANCHOR_N,
                            :fill_color => "black"})

    Gtk::Widget.pop_colormap()

    item.signal_connect("event") do |item, event|
      canvas_event(item, event)
    end

    frame = Gtk::Frame.new()
    frame.shadow_type = Gtk::SHADOW_IN

    frame.add(canvas)
    frame
  end

  def initialize
    super(false, 4)
    self.border_width = 4
    self.show()

    @current_state = STATE_INIT

    label = Gtk::Label.new(<<EOS)
Drag a line with button 1. Then mark 2 control points with
button 1. Shift+click with button 1 to destroy the curve.
EOS
    self.pack_start(label, false, false, 0)
    label.show()

    canvas = create_canvas(false)
    self.pack_start(canvas, true, true, 0)
    canvas.show()

    aa_canvas = create_canvas(true)
    self.pack_start(aa_canvas, true, true, 0)
    aa_canvas.show()
  end
end
