#
# $Id: treetable.icn,v 1.1 2004/11/19 16:21:42 rparlett Exp $
#
# This file is in the public domain.
#
# Author: Robert Parlett (parlett@dial.pipex.com)
#

package gui
link graphics

$include "guih.icn"

#
# A node in a {TreeTable}.  It provides the column data
# for the extra (non-tree) columns.  For example if
# the TreeTable's columns were named A, B, C, then a
# {TreeTableNode} might be created as follows :-
#
# @example
# @ n := TreeTableNode("label=Col A label")
# @ n.set_col_data(["Col B data", "Col C data"])
#
class TreeTableNode:Node(col_data)
   #
   # Set the column data to fill the columns 2 onwards.
   #
   method set_col_data(l)
      self.col_data := l
   end

   #
   # Get the data for column number c, where c ranges
   # from 2 up; fails if not available.
   #
   method get_col(c)
      return (\self.col_data)[c - 1]
   end

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

#
# This class provides the table content for a TreeTable.  It extends
# Tree, and uses that class's methods for event handling and drawing
# of the first column.
#
class TreeTableContent:Tree()
   method get_subject_width()
      subject_width := 0
      every subject_width +:= (!parent.table_header.children).column_width
      return subject_width
   end

   method refresh(redraw)
      # Need to resize buttons because of the horizontal scroll bar moving.
      parent.table_header.resize()
      parent.table_header.invalidate()
      self.ScrollArea.refresh(redraw)
   end

   #
   # Draw an individual column for one row's data.  This could
   # be over-ridden to give a custom table with data 
   # other than strings.
   #
   # @param row the row number to draw
   # @param col the column number to draw
   # @param cx the x position of the cell
   # @param cy the y position of the cell
   # @param cw the width of the cell
   # @param ch the height of the cell
   #
   method draw_cell(row, col, cx, cy, cw, ch)
      local s, l 

      s := self.contents[row].get_col(col) | fail
      case get_column(col).internal_alignment of {
         "r" :          right_string(self.cbwin, cx + cw, cy, s)
         "c" :          center_string(self.cbwin, cx + cw / 2, cy, s)
         "l" :          left_string(self.cbwin, cx, cy, s)
      }
   end

   method get_column(n)
      return parent.table_header.children[n]
   end

   method draw_line(xp, yp, i, selection_cw, cursor_cw, highlight_cw)
      local j, l, cols, x1, w1, clip_x1, clip_x2, col
      N := self.contents[i]
      cols := parent.table_header.children
      every j := 1 to *cols do {
         col := cols[j]
         if j = 1 then {
            # The tree column has slightly different bounds.
            x1 := col.x
            w1 := col.w - DEFAULT_TEXT_X_SURROUND
         } else {
            x1 := col.x + DEFAULT_TEXT_X_SURROUND
            w1 := col.w - 2 * DEFAULT_TEXT_X_SURROUND
         }
         clip_x1 := x1
         clip_x1 <:= self.view.x
         clip_x2 := x1 + w1
         clip_x2 >:= self.view.x + self.view.w
         Clip(self.cbwin, clip_x1, self.view.y, clip_x2 - clip_x1, self.view.h)
         if j = 1 then
            self.Tree.draw_line(xp, yp, i, selection_cw, cursor_cw, highlight_cw)
         else
            draw_cell(i, j, x1, yp, w1, self.line_height)
         Clip(self.cbwin)
      }
   end
end

#
# A {TreeTable} is a {Table} where the first column is
# a Tree.  The data for the component is provided as
# a tree of {TreeTableNode}s.
#
# See the example program ttexplorer.icn for one in use.
#
class TreeTable:Table()
   initially(a[])
      self.Table.initially()
      set_table_content(TreeTableContent())
      set_fields(a)
end