#
# $Id: sizer.icn,v 1.6 2004/11/13 23:40:17 rparlett Exp $
#
# This file is in the public domain.
#
# Author: Robert Parlett (parlett@dial.pipex.com)
#

package gui
link graphics

$include "guih.icn"

#
# This class provides a component which can be dragged across the
# window, allowing panes within the window to be resized.  A SIZER_RELEASED_EVENT is
# generated when the {Sizer} has been dragged and released.  The new position
# may then be obtained and the dialog adjusted accordingly.
#
#
class Sizer : Component(
   is_held,
   is_horizontal_flag,      #                          
   temp_win,                #
   temp_w,
   temp_h,
   lo,
   hi,
   drag_offset,
   curr_pos,
   start_pos,
   end_pos,
   pointer_flag
   )

   #
   # Set the minimum and maximum values for the {Sizer}.  Whether these are
   # x or y values depends on the orientation of the {Sizer}.
   #
   method set_range(lo, hi)
      self.lo := lo
      self.hi := hi
   end

   #
   # Return the current position of the {Sizer}.  This may be invoked to determine
   # where the {Sizer} has been dragged to after it has generated an event.
   #
   method get_curr_pos()
      return curr_pos
   end

   #
   # Get the size of the move during the last drag of the {Sizer}.
   #
   method get_delta()
      return end_pos - start_pos
   end

   #
   # Configure the {Sizer} to be horizontal; the default is vertical.
   #
   method set_is_horizontal()
      return self.is_horizontal_flag := 1
   end

   #
   # Configure the {Sizer} to be vertical; the default.
   #
   method clear_is_horizontal()
      return self.is_horizontal_flag := &null
   end

   method finally()
      if \self.is_held then {
         WClose(self.temp_win)
         unique_end()
      }
      self.Component.finally()
   end

   method display(buffer_flag)
      local cw

      if \self.is_held then {
         CopyArea(temp_win, cbwin, 0, 0, temp_w, temp_h, 0, 0)
         cw := Clone(self.cbwin, "linewidth=4", "pattern=gray", "fillstyle=masked")
         if \is_horizontal_flag then {
            abs_pos := curr_pos + drag_offset + parent.get_y_reference()
            DrawLine(cw, x, abs_pos, x + w, abs_pos)
         } else {
            abs_pos := curr_pos + drag_offset + parent.get_x_reference()
            DrawLine(cw, abs_pos, y, abs_pos, y + h)
         }
         Uncouple(cw)
         CopyArea(get_parent_buffer_win(), get_parent_win(), 0, 0, temp_w, temp_h, 0, 0)
      } else {
         EraseRectangle(self.cbwin, self.x, self.y, self.w, self.h)
         DrawRaisedRectangle(self.cbwin, self.x, self.y, self.w, self.h, 1)
         self.do_shading(self.cbwin)
         if /buffer_flag then
            CopyArea(self.cbwin, self.cwin, self.x, self.y, self.w, self.h, self.x, self.y)
      }
   end

   method set_curr_pos()
      if \self.is_horizontal_flag then
         curr_pos := &y - drag_offset - parent.get_y_reference()
      else
         curr_pos := &x - drag_offset - parent.get_x_reference()

      curr_pos <:= \lo
      curr_pos >:= \hi
      return curr_pos
   end

   #
   # Change the pointer to be the double arrow (unless it is already).
   # @p
   method pointer_on()
      if /pointer_flag then {
         if \self.is_horizontal_flag then
            get_parent_dialog().change_pointer("sb v double arrow")
         else
            get_parent_dialog().change_pointer("sb h double arrow")
         pointer_flag := 1
      }
   end

   method resize()
      if /self.is_horizontal_flag then
         /self.w_spec := 6
      else
         /self.h_spec := 6
      self.Component.resize()
   end

   #
   # Reset the pointer if needed.
   #
   method pointer_off()
      if \pointer_flag then {
         get_parent_dialog().restore_pointer()
         pointer_flag := &null
      }
   end

   method handle_event(e)
      if e === -12 then {
         if self.in_region() then
            pointer_on()
         else
            pointer_off()
      } else if e === (&lpress | &rpress | &mpress) then {
         if self.in_region() then {
            unique_start()
            self.is_held := 1
            temp_w := parent_dialog.get_w_reference() 
            temp_h := parent_dialog.get_h_reference() 
            self.temp_win := WOpen("canvas=hidden", "size=" || temp_w || "," || temp_h)
            CopyArea(cwin, temp_win, 0, 0, temp_w, temp_h, 0, 0)
            if \self.is_horizontal_flag then {
               drag_offset := &y - self.y
            } else {
               drag_offset := &x - self.x
            }
            pointer_on()
            start_pos := set_curr_pos()
            self.invalidate()
         }
      } else if \self.is_held then {
         if e === (&ldrag | &rdrag | &mdrag) then {
            set_curr_pos()
            self.invalidate()
         } else if e === (&lrelease | &rrelease | &mrelease) then {
            self.is_held := &null
            pointer_off()
            end_pos := set_curr_pos()
            CopyArea(temp_win, cwin, 0, 0, temp_w, temp_h, 0, 0)
            WClose(self.temp_win)
            unique_end()
            fire(SIZER_RELEASED_EVENT, e)
         }
      }
   end

   method set_one(attr, val)
      case attr of {
         "is_horizontal" : if test_flag(attr, val) then 
            set_is_horizontal()
         else
            clear_is_horizontal()
         "range" : set_range!int_vals(attr, val)
         default: self.Component.set_one(attr, val)
      }
   end

   initially(a[])
      self.Component.initially()
      set_fields(a)
end