# # $Id: table.icn,v 1.9 2004/11/11 20:01:54 rparlett Exp $ # # This file is in the public domain. # # Author: Robert Parlett (parlett@dial.pipex.com) # package gui link graphics $include "guih.icn" class TableContent : SelectableScrollArea() method get_line_height() return WAttrib(self.cwin, "fheight") end 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 s := get_contents()[row][col] 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 l := self.contents[i] cols := parent.table_header.children every j := 1 to *cols do { col := cols[j] 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) draw_cell(i, j, x1, yp, w1, self.line_height) Clip(self.cbwin) } if \selection_cw then FillRectangle(selection_cw, self.view.x, yp - self.line_height / 2, self.view.w, self.line_height) if \cursor_cw then Rectangle(cursor_cw, self.view.x, yp - self.line_height / 2, self.view.w, self.line_height) if \highlight_cw then Rectangle(highlight_cw, self.view.x, yp - self.line_height / 2, self.view.w, self.line_height) end initially self.SelectableScrollArea.initially() end class TableHeader : Component( button_x, button_y, button_w, button_h ) method get_x_reference() return parent.table_content.get_left_pos() end method resize() local i, b self.Component.compute_absolutes() self.button_x := self.x + DEFAULT_SP_X_PADDING self.button_w := self.w - 2 * DEFAULT_SP_X_PADDING self.button_y := self.y + BORDER_WIDTH self.button_h := self.h - 2 * BORDER_WIDTH i := 0 every b := !self.children do { b.set_pos(i, BORDER_WIDTH) b.set_size(b.column_width, self.button_h) b.resize() i +:= b.w } end method display(buffer_flag) EraseRectangle(self.cbwin, self.x, self.y, self.w, self.h) DrawSunkenRectangle(self.cbwin, self.x, self.y, self.w, self.h) every (!self.children).display(1) if /buffer_flag then CopyArea(self.cbwin, self.cwin, self.x, self.y, self.w, self.h, self.x, self.y) end end # # This class displays a table, the columns of which are set up # using TableColumns. # class Table : Component( table_header, table_content, head_h ) # # Set the height of the buttons at the top in pixels. If not # invoked, a sensible default will be used. # @param x The height # method set_header_height(x) return self.head_h := x end # # Return the nth {TableColumn}. # method get_column(n) return table_header.children[n] end method get_contents() return self.table_content.get_contents() end method set_checked(l) return self.table_content.set_checked(l) end method get_checked() return self.table_content.get_checked() end # # Move to the given position. Either parameter may be omitted. # @param line The row to move to # @param horiz The left offset to move to # method goto_pos(line, horiz) return self.table_content.goto_pos(line, horiz) end # # # Present number of lines on screen # method get_curr_lines() return self.table_content.get_curr_lines() end # # Set the contents of the table. The parameter should be a # two dimensional list. Each element of the list should # correspond to one row of the table. # @param x The contents # method set_contents(x) return self.table_content.set_contents(x) end # # Call this method if the contents list, previously # set with {set_contents()}, has changed. # method contents_changed() return self.table_content.contents_changed() end method clear_selections() return self.table_content.clear_selections() end # # Return a list of rows selected # @return A list of rows currently selected # method get_selections() return self.table_content.get_selections() end # # Set the current selections to the list l, which is a list of # row numbers. # @param l The list of item numbers. # method set_selections(l) return self.table_content.set_selections(l) end # # Set the cursor # # @p method set_cursor(row) self.table_content.set_cursor(row) end # # Return item currently under the clicked cursor # # @p method get_cursor() return self.table_content.get_cursor() end # # Return row currently under the clicked cursor # # @p method row_get_cursor() return self.table_content.object_get_cursor() end # # Return row number previously under the clicked cursor # # @p method get_prev_down() return self.table_content.get_prev_down() end # # Return row previously under the clicked cursor # # @p method row_get_prev_down() return self.table_content.object_get_prev_down() end # # Get the number of the first visible line # method get_first_line() return self.table_content.get_first_line() end # # The index of the last line in the area, or zero if there are no # lines. # method get_last_line() return self.table_content.get_last_line() end # # Add the given TableColumn to the Table. # @param c The column to add. # method add_column(c) table_header.add(c) end # # Get the columns of the table # method get_columns() return table_header.get_children() end # # Configure the table so that one row of the table may be highlighted. # method set_select_one() self.table_content.set_select_one() end # # Configure the table so that several rows of the table may be highlighted. # method set_select_many() self.table_content.set_select_many() end # # Configure the table so that no lines may be highlighted (this # is the default). # method set_select_none() self.table_content.set_select_none() end method resize() self.Component.compute_absolutes() /self.head_h := WAttrib(self.cwin, "fheight") + 2 * DEFAULT_TEXT_Y_SURROUND + 2 * BORDER_WIDTH self.table_content.set_pos(0, self.head_h) self.table_content.set_size(self.w, self.h - self.head_h) self.table_content.resize() self.table_header.set_pos(0, 0) self.table_header.set_size(self.w, self.head_h) self.table_header.resize() end method display(buffer_flag) EraseRectangle(self.cbwin, self.x, self.y, self.w, self.h) DrawSunkenRectangle(self.cbwin, self.x, self.y, self.w, self.h) self.table_content.display(1) self.table_header.display(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 on_table_content(ev) # Fire the event with self as source. fire(ev.get_type(), ev) end # # Return the component used to display the table contents, which is a # subclass of SelectableScrollArea. # method get_table_content() return self.table_content end method set_one(attr, val) case attr of { "select_one" : set_select_one() "select_many" : set_select_many() "select_none" : set_select_none() "header_height" : set_header_height(int_val(attr, val)) default: self.Component.set_one(attr, val) } end # # This method can be used to change the TableContent object, which # makes up the main area of the component. To use it, extend TableContent # and insert the customized object with this method. # method set_table_content(tc) self.remove(\self.table_content) self.table_content := tc every self.table_content.connect(self, "on_table_content", CURSOR_MOVED_EVENT | SELECTION_CHANGED_EVENT) self.add(table_content) end # # This method can be used to change the TableHeader object, which # makes up the header of the table. To use it, extend TableHeader # and insert the customized object with this method. # method set_table_header(th) self.remove(\self.table_header) self.table_header := th self.add(table_header) end # # Send accelerator focus to the table_content. # method find_accel(e) if self.Component.find_accel(e) then return table_content end initially(a[]) self.Component.initially() # Set default content and header components. set_table_content(TableContent()) set_table_header(TableHeader()) set_fields(a) end