# # Sawmill Document Description (SDD) Library # # Table routines # include("lib.sdd.graphic_object"); subroutine(set_table_cell_horizontal_alignment(node tbl, int row, int column, string halign), ( node outercell = sdd_get_table_outercell(tbl, row, column); node innercell = sdd_get_table_innercell(tbl, row, column); float left_padding = @outercell{"left_padding"}; float right_padding = @outercell{"right_padding"}; # Align left if requested if (halign eq "left") then ( set_sdd_xmin(innercell, sddadd(sddleft(outercell), sddfloat(left_padding))); register_sdd_dependency(innercell, "xmin", outercell, "xmin"); ); # Align right if requested else if (halign eq "right") then set_sdd_xmin(innercell, sddrightalignpadding(innercell, outercell, right_padding)); # Align center if requested else if (halign eq "center") then set_sdd_xmin(innercell, sdd_horiz_center_align(innercell, outercell)); else error("Unknown table cell halign value: '" . halign . "'"); )); # set_table_cell_horizontal_alignment() subroutine(set_table_cell_vertical_alignment(node tbl, int row, int column, string valign), ( node outercell = sdd_get_table_outercell(tbl, row, column); node innercell = sdd_get_table_innercell(tbl, row, column); float top_padding = @outercell{"top_padding"}; float bottom_padding = @outercell{"bottom_padding"}; # Align top if requested if (valign eq "top") then ( set_sdd_ymax(innercell, sddsubtract(sddtop(outercell), sddfloat(top_padding))); register_sdd_dependency(innercell, "ymax", outercell, "ymax"); ); # Align bottom if requested else if (valign eq "bottom") then ( node sddbottomwithpadding = sddadd(sddbottom(outercell), sddfloat(bottom_padding)); set_sdd_ymax(innercell, sddadd(sddbottomwithpadding, sddheight(innercell))); register_sdd_dependency(innercell, "ymax", outercell, "ymax"); register_sdd_dependency(innercell, "ymax", outercell, "height"); register_sdd_dependency(innercell, "ymax", innercell, "height"); ); # Align center if requested else if (valign eq "center") then set_sdd_ymax(innercell, sdd_vert_center_align(innercell, outercell)); else error("Unknown table cell vertical-align value: '" . valign . "'"); )); # set_table_cell_vertical_alignment() # # new_table_sdd() # # Purpose: This creates a new SDD table # # Parameters: parentsdd: the parent SDD to add this table into # rows, columns: the number of rows and columns in the table # returns the table node # subroutine(new_table_sdd(node parentsdd, int rows, int columns), ( # Create the table SDD, and add it to the parent node tbl = new_sdd(); if (parentsdd != 0) then add_subsdd(parentsdd, tbl); # Remember the number of rows and columns tbl{"columns"} = columns; tbl{"rows"} = rows; node contents = new_box_sdd(0, sddleft(tbl), sddtop(tbl), 0, 0); register_sdd_dependency(contents, "ymax", tbl, "ymax"); remove_sdd_stroke_color(contents); add_subsdd_named(tbl, contents, "contents"); rename_node(contents, "contents"); set_sdd_width(contents, sddgroupwidth(contents)); set_sdd_height(contents, sddgroupheight(contents)); # 2010-09-21 - GMF - Table gridlines are no longer rendered, and *might* not be needed at all, with the better # box border code. Or maybe they are? Commenting it out for now, in case we need it again later. # node gridlines = new_table_gridlines_sdd(tbl, sddleft(tbl), sddtop(tbl), sddwidth(tbl), sddheight(tbl)); # node gridlines = new_table_gridlines_sdd(tbl); tbl{"border"} = "none"; # The total width and heigth of the table is the width and height of the cells together. set_sdd_width(tbl, sddwidth(contents)); set_sdd_height(tbl, sddheight(contents)); # Create a "sddtablecolumnmaxwidth" value for each column, to compute the maximum width of all cells in that column. set_node_type(tbl{"column_widths"}, 'node'); node column_widths = new_node(); @tbl{"column_widths"} = column_widths; for (int column = 0; column < columns; column++) ( set_node_type(column_widths{column}, 'node'); @column_widths{column} = sddtablecolumnmaxwidth(tbl, column); ); # Create a "sddtablerowmaxheight" value for each row, to compute the maximum height of all cells in that row. set_node_type(tbl{"row_heights"}, 'node'); node row_heights = new_node(); @tbl{"row_heights"} = row_heights; for (int row = 0; row < rows; row++) ( set_node_type(row_heights{row}, 'node'); @row_heights{row} = sddtablerowmaxheight(tbl, row); ); # This nested loop creates all rows*columns cells node xmin; node ymax; node outercell; node cell_to_left; node cell_at_start_of_previous_row; for (int row = 0; row < rows; row++) ( for (int column = 0; column < columns; column++) ( # Create the "outercell" object. This object's outline is the visible outline of the table cell. outercell = new_box_sdd(0, 0, 0, 0, 0); remove_sdd_stroke_color(outercell); add_subsdd_named(contents, outercell, 'outercell_' . row . '_' . column); rename_node(outercell, 'outercell_' . row . '_' . column); # DEBUG: uncomment this to add borders on all outercells # set_sdd_stroke_color(outercell, 0, 0, 0); @outercell{"left_padding"} = 0; @outercell{"right_padding"} = 0; @outercell{"top_padding"} = 0; @outercell{"bottom_padding"} = 0; # Pin the upper left of the (0,0) cell to the upper left of the table if ((row == 0) and (column == 0)) then ( xmin = sddleft(contents); ymax = sddtop(contents); register_sdd_dependency(outercell, "ymax", contents, "ymax"); register_sdd_dependency(outercell, "xmin", contents, "xmin"); ); # Pin the upper left of all column-0 cells to the bottom left of the previous row else if ((row != 0) and (column == 0)) then ( xmin = sddleft(cell_at_start_of_previous_row); register_sdd_dependency(outercell, "xmin", cell_at_start_of_previous_row, "xmin"); ymax = sddbottom(cell_at_start_of_previous_row); register_sdd_dependency(outercell, "ymax", cell_at_start_of_previous_row, "ymax"); register_sdd_dependency(outercell, "ymax", cell_at_start_of_previous_row, "height"); ); # Pin the upper left of all other cells to the upper right of the previous cell else ( xmin = sddright(cell_to_left); register_sdd_dependency(outercell, "xmin", cell_to_left, "xmin"); register_sdd_dependency(outercell, "xmin", cell_to_left, "width"); ymax = sddtop(cell_to_left); register_sdd_dependency(outercell, "ymax", cell_to_left, "ymax"); ); # Set the xmin and ymax to the values computed above set_sdd_xmin(outercell, xmin); set_sdd_ymax(outercell, ymax); # Set the outer cell width and height from the width and heights computed by the table layout. set_sdd_width(outercell, sddtablecolumnwidth(tbl, column)); set_sdd_height(outercell, sddtablerowheight(tbl, row)); # Create the "innercell" object. This object is the minimal bounding rectangle for the table's content. node innercell = new_box_sdd(0, 0, 0, 0, 0); remove_sdd_stroke_color(innercell); # DEBUG: uncomment this to add borders on all innercells # set_sdd_stroke_color(innercell, 0, 0, 0); # For now, always valign top set_sdd_ymax(innercell, sddsubtract(sddtop(outercell), sddfloat(@outercell{"top_padding"}))); register_sdd_dependency(innercell, "ymax", outercell, "ymax"); add_subsdd_named(outercell, innercell, 'innercell_' . row . '_' . column); rename_node(innercell, 'innercell_' . row . '_' . column); # Default to left alignment set_table_cell_horizontal_alignment(tbl, row, column, "left"); # Remember this cell for next iteration cell_to_left = outercell; # If this is column 0, remember it for next row if (column == 0) then cell_at_start_of_previous_row = outercell; ); # for column ); # for row tbl; )); # new_table_sdd() # # sdd_clear_table_innercell() # # Purpose: This clears a table cell by clearing the contents of its inner cell. # # Parameters: tbl: the table # row, column: the cell to clear # subroutine(sdd_clear_table_innercell(node tbl, int row, int column), ( node innercell = sdd_get_table_innercell(tbl, row, column); node cellitems = innercell{"items"}; while (num_subnodes(cellitems) > 0) ( node subnode = subnode_by_number(cellitems, 0); delete_node(subnode); ); )); # sdd_clear_table_innercell() # # sdd_set_table_cell_contents() # # Purpose: This sets the contents of a table cell. # # Parameters: tbl: the table # row, column: the cell to set # contents: the SDD to set it to (this becomes the new content, i.e., the sole SDD in the innercell) # subroutine(set_table_cell_contents(node tbl, int row, int column, node contents), ( sdd_clear_table_innercell(tbl, row, column); node innercell = sdd_get_table_innercell(tbl, row, column); node outercell = sdd_get_table_outercell(tbl, row, column); add_subsdd(innercell, contents); # DEBUG: table inner cell is outlined in light green (green-blue) # set_sdd_stroke_color(innercell, 0, 1.0, 1.0); # DEBUG: table outer cell is outlined in pink # set_sdd_stroke_color(outercell, 1.0, 0, 1.0); set_sdd_position_upper_left(contents, innercell); # The dimensions of innercell are computed from outercell (which is computed from the table layout size) set_sdd_width(innercell, sddsubtract(sddwidth(outercell), sddfloat(@outercell{"left_padding"} + @outercell{"right_padding"} + @outercell{"left_margin"} + @outercell{"right_margin"}))); set_sdd_height(innercell, sddsubtract(sddheight(outercell), sddfloat(@outercell{"top_padding"} + @outercell{"bottom_padding"} + @outercell{"top_margin"} + @outercell{"bottom_margin"}))); # Set the contents size to match the inner cell (which is computed from outercell, which is computed from the layout engine). set_sdd_width(contents, sddwidth(innercell)); set_sdd_height(contents, sddheight(innercell)); )); # set_table_cell_contents() subroutine(set_table_cell_background_color(node tbl, int row, int column, float red, float green, float blue), ( node outercell = sdd_get_table_outercell(tbl, row, column); set_sdd_fill_color(outercell, red, green, blue); )); # set_table_cell_background_color(); # Set the colspan of a particular cell (the number of columns it spans). subroutine(set_table_cell_colspan(node tbl, int row, int column, int colspan), ( node outercell = sdd_get_table_outercell(tbl, row, column); @outercell{"colspan"} = colspan; )); # set_table_cell_colspan() # # force_table_cell_width_outer() # # Purpose: This forces a table cell to be a particular width. # subroutine(force_table_cell_width_outer(node tbl, int row, int column, float outerwidth), ( # Set the wrap_width to the inner width node outercell = sdd_get_table_outercell(tbl, row, column); node cell_contents = sdd_get_table_cell_contents(tbl, row, column); float innerwidth = outerwidth - (@outercell{"left_padding"} + @outercell{"right_padding"} + @outercell{"left_margin"} + @outercell{"left_margin"}); @cell_contents{"wrap_width"} = innerwidth; )); # force_table_cell_width()