/* Part of XPCE --- The SWI-Prolog GUI toolkit Author: Jan Wielemaker and Anjo Anjewierden E-mail: jan@swi.psy.uva.nl WWW: http://www.swi.psy.uva.nl/projects/xpce/ Copyright (c) 1998-2011, University of Amsterdam All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include /******************************* * (TYPE) UTIL * *******************************/ static inline Table table_of_cell(TableCell cell) { Table tab = (Table)cell->layout_manager; if ( isNil(tab) ) fail; answer(tab); } /******************************* * CREATE * *******************************/ static status initialiseTableCell(TableCell c, Graphical image) { initialiseLayoutInterface(c, image); assign(c, halign, DEFAULT); assign(c, valign, DEFAULT); assign(c, col_span, ONE); assign(c, row_span, ONE); assign(c, cell_padding, DEFAULT); assign(c, selected, OFF); assign(c, background, DEFAULT); /*assign(c, hrubber, NIL); assign(c, vrubber, NIL); */ succeed; } static status unlinkTableCell(TableCell cell) { Table tab; if ( (tab=table_of_cell(cell)) ) qadSendv(tab, NAME_delete, 1, (Any *)&cell); return unlinkLayoutInterface(cell); } static LayoutInterface getConvertTableCell(Any context, Graphical image) { answer(answerObject(ClassTableCell, image, EAV)); } /******************************* * MODIFIED * *******************************/ static status modifiedImageTableCell(TableCell c) { Table tab = table_of_cell(c); Device dev; if ( tab && notNil(dev=tab->device) ) { table_cell_dimensions d; dims_table_cell(c, &d); changedImageGraphical(dev, toInt(d.x), toInt(d.y), toInt(d.w), toInt(d.h)); } succeed; } /******************************* * ATTRIBUTES * *******************************/ static status imageTableCell(TableCell c, Graphical gr) { if ( c->image != gr ) { Graphical old = c->image; Table tab = table_of_cell(c); if ( notNil(old) && !onFlag(old, F_FREEING|F_FREED) ) { Any nil = NIL; qadSendv(old, NAME_layoutInterface, 1, &nil); send(old, NAME_destroy, EAV); } assign(c, image, gr); qadSendv(gr, NAME_layoutInterface, 1, (Any *)&c); if ( tab && notNil(tab->device) ) send(tab->device, NAME_display, gr, EAV); requestComputeLayoutManager(c->layout_manager, DEFAULT); } succeed; } static status selectedTableCell(TableCell c, BoolObj selected) { if ( c->selected != selected ) { assign(c, selected, selected); modifiedImageTableCell(c); } succeed; } static status backgroundTableCell(TableCell c, Any bg) { if ( c->background != bg ) { assign(c, background, bg); modifiedImageTableCell(c); } succeed; } static status noteMarkTableCell(TableCell c, Image mark) { if ( c->note_mark != mark ) { assign(c, note_mark, mark); modifiedImageTableCell(c); } succeed; } static status halignTableCell(TableCell c, Name align) { if ( c->halign != align ) { assign(c, halign, align); /* or placeImageTableCell()? */ requestComputeLayoutManager(c->layout_manager, DEFAULT); } succeed; } static status valignTableCell(TableCell c, Name align) { if ( c->valign != align ) { assign(c, valign, align); requestComputeLayoutManager(c->layout_manager, DEFAULT); } succeed; } static status hrubberTableCell(TableCell c, Rubber r) { if ( c->hrubber != r ) { assign(c, hrubber, r); requestComputeLayoutManager(c->layout_manager, DEFAULT); } succeed; } static status vrubberTableCell(TableCell c, Rubber r) { if ( c->vrubber != r ) { assign(c, vrubber, r); requestComputeLayoutManager(c->layout_manager, DEFAULT); } succeed; } static status cellPaddingTableCell(TableCell c, Size padding) { if ( !(c->cell_padding == padding || (classOfObject(c->cell_padding) == classOfObject(padding) && equalSize(c->cell_padding, padding))) ) { assign(c, cell_padding, padding); requestComputeLayoutManager(c->layout_manager, DEFAULT); } succeed; } Name getHalignTableCell(TableCell cell) { Table tab; if ( notDefault(cell->halign) ) answer(cell->halign); if ( (tab=table_of_cell(cell)) && notNil(tab->columns) ) { TableColumn col = getColumnTable(tab, cell->column, OFF); if ( col ) answer(col->alignment); } answer(NAME_left); } Name getValignTableCell(TableCell cell) { Table tab; if ( notDefault(cell->valign) ) answer(cell->valign); if ( (tab=table_of_cell(cell)) && notNil(tab->rows) ) { TableRow row = getRowTable(tab, cell->row, OFF); if ( row ) answer(row->alignment); } answer(NAME_top); } static Table getTableTableCell(TableCell cell) { answer(table_of_cell(cell)); } static status colSpanTableCell(TableCell cell, Int span) { if ( cell->col_span != span ) { Table tab = table_of_cell(cell); if ( tab ) { int x,y; int fx = valInt(cell->column); int w = valInt(span); int ow = valInt(cell->col_span); int tx = max(w,ow)+fx; for(y=valInt(cell->row); yrow)+valInt(cell->row_span); y++) { TableRow row = getRowTable(tab, toInt(y), ON); for(x=fx+1; xrow_span != span ) { Table tab = table_of_cell(cell); if ( tab ) { int x,y; int fy = valInt(cell->row); int h = valInt(span); int oh = valInt(cell->row_span); int ty = max(h,oh)+fy; for(y=fy+1; ycolumn); xcolumn)+valInt(cell->col_span); x++) { Any e; if ( y-fy < h ) e = cell; else e = NIL; cellTableRow(row, toInt(x), e); } } assign(cell, row_span, span); changedTable(tab); /* changed line-pattern */ requestComputeLayoutManager((LayoutManager)tab, DEFAULT); } else { assign(cell, row_span, span); } } succeed; } /******************************* * COMPUTE * *******************************/ void table_cell_padding(TableCell cell, int *pxptr, int* pyptr) { Size size; Table tab; if ( notDefault(cell->cell_padding) ) size = cell->cell_padding; else if ( (tab=table_of_cell(cell)) ) size = tab->cell_padding; else return; /* should not happen */ *pxptr = valInt(size->w); *pyptr = valInt(size->h); } void dims_table_cell(TableCell cell, TableCellDimensions dims) { int w=0, h=0; TableRow row; TableColumn col; int cx, cy; int ncols = valInt(cell->col_span); int nrows = valInt(cell->row_span); int n; Table tab = table_of_cell(cell); int x = valInt(cell->column); int y = valInt(cell->row); table_cell_padding(cell, &dims->px, &dims->py); row = getRowTable(tab, cell->row, ON); /* play safe */ col = getColumnTable(tab, cell->column, ON); dims->x = valInt(col->position); dims->y = valInt(row->position); dims->rx = valInt(col->reference); dims->ry = valInt(row->reference); w = valInt(col->width); h = valInt(row->width); if ( ncols > 1 || nrows > 1 ) { int rowspace = valInt(tab->cell_spacing->h); int colspace = valInt(tab->cell_spacing->w); /* cells spanned */ for(n=1, cx=x+1; nwidth); for(n=1, cy=y+1; nwidth); } dims->w = w; dims->h = h; } static Area getAreaTableCell(TableCell c) { Table tab = table_of_cell(c); Device dev; if ( tab && notNil(dev=tab->device) ) { table_cell_dimensions d; ComputeGraphical(dev); /* make sure area is up-to-date */ dims_table_cell(c, &d); answer(answerObject(ClassArea, toInt(d.x), toInt(d.y), toInt(d.w), toInt(d.h), EAV)); } fail; } /******************************* * LAYOUT * *******************************/ static Any getIf(Any cell, Name method, Any def) /* can be optimised further */ { Any rval; if ( hasGetMethodObject(cell, method) && (rval = getv(cell, method, 0, NULL)) ) answer(rval); answer(def); } status placeImageTableCell(TableCell cell) { Graphical gr = cell->image; Table tab = table_of_cell(cell); table_cell_dimensions d; int grx, gry; Any av[4]; Point ref = NULL; Name halign = getHalignTableCell(cell); Name valign = getValignTableCell(cell); ComputeGraphical(gr); /* make sure */ av[2] = DEFAULT; /* width */ av[3] = DEFAULT; /* height */ dims_table_cell(cell, &d); if ( halign == NAME_left ) /* determine X-placement */ grx = d.x + d.px; else if ( halign == NAME_right ) grx = d.x + d.w-d.px-valInt(gr->area->w); else if ( halign == NAME_center ) grx = d.x + (d.w-valInt(gr->area->w)+1)/2; else if ( halign == NAME_stretch ) { grx = d.x + d.px; av[2] = toInt(d.w-2*d.px); } else /* if ( halign == NAME_reference ) */ { ref = getIf(gr, NAME_reference, NIL); if ( notNil(ref) ) grx = d.x + d.rx - valInt(ref->x); else grx = d.x + d.px; } if ( valign == NAME_top ) /* determine Y-placement */ gry = d.y + d.py; else if ( valign == NAME_bottom ) gry = d.y + d.h-d.py-valInt(gr->area->h); else if ( valign == NAME_center ) gry = d.y + (d.h-valInt(gr->area->h)+1)/2; else if ( valign == NAME_stretch ) { gry = d.y + d.py; av[3] = toInt(d.h-2*d.py); } else /* if ( halign == NAME_reference ) */ { if ( !ref ) ref = getIf(gr, NAME_reference, NIL); if ( notNil(ref) ) gry = d.y + d.ry - valInt(ref->y); else gry = d.y + d.py; } av[0] = toInt(grx); av[1] = toInt(gry); if ( instanceOfObject(gr, ClassWindow) && /* HACK */ notNil(((PceWindow)gr)->decoration) ) gr = (Graphical)((PceWindow)gr)->decoration; qadSendv(gr, NAME_doSet, 4, av); if ( gr->device != tab->device ) send(tab->device, NAME_display, gr, EAV); succeed; } /******************************* * CLASS DECLARATION * *******************************/ /* Type declarations */ /* Instance Variables */ static vardecl var_table_cell[] = { IV(NAME_column, "int*", IV_GET, NAME_location, "X-location in table environment"), IV(NAME_row, "int*", IV_GET, NAME_location, "Y-location in table environment"), SV(NAME_halign, "[{left,center,right,reference,stretch}]", IV_NONE|IV_STORE, halignTableCell, NAME_layout, "Horizontal alignment of <-image in cell"), SV(NAME_valign, "[{top,center,bottom,reference,stretch}]", IV_NONE|IV_STORE, valignTableCell, NAME_layout, "Vertical alignment of <-image in cell"), SV(NAME_hrubber, "rubber*", IV_GET|IV_STORE, hrubberTableCell, NAME_layout, "Horizontal stretchability"), SV(NAME_vrubber, "rubber*", IV_GET|IV_STORE, vrubberTableCell, NAME_layout, "Vertical stretchability"), SV(NAME_colSpan, "1..", IV_GET|IV_STORE, colSpanTableCell, NAME_layout, "Number of columns spanned"), SV(NAME_rowSpan, "1..", IV_GET|IV_STORE, rowSpanTableCell, NAME_layout, "Number of rows spanned"), SV(NAME_cellPadding, "[size]", IV_GET|IV_STORE, cellPaddingTableCell, NAME_layout, "Size around contents of the cell"), SV(NAME_selected, "bool", IV_GET|IV_STORE, selectedTableCell, NAME_selection, "Is cell selected?"), SV(NAME_background, "[colour|pixmap]", IV_GET|IV_STORE, backgroundTableCell, NAME_colour, "Backround colour for the cell"), SV(NAME_noteMark, "image*", IV_GET|IV_STORE, noteMarkTableCell, NAME_appearance, "Image painted in the top-right corner") }; /* Send Methods */ static senddecl send_table_cell[] = { SM(NAME_initialise, 1, "graphical", initialiseTableCell, DEFAULT, "Initialise abstract instance"), SM(NAME_unlink, 0, NULL, unlinkTableCell, DEFAULT, "Remove <-image from device"), SM(NAME_image, 1, "graphical", imageTableCell, NAME_content, "Replace the graphical in the cell") }; /* Get Methods */ static getdecl get_table_cell[] = { GM(NAME_convert, 1, "table_cell", "graphical", getConvertTableCell, DEFAULT, "Convert graphical object"), GM(NAME_halign, 0, "{left,center,right,reference,stretch}", NULL, getHalignTableCell, DEFAULT, "Current horizontal alignment"), GM(NAME_valign, 0, "{top,center,bottom,reference,stretch}", NULL, getValignTableCell, DEFAULT, "Current vertical alignment"), GM(NAME_table, 0, "table", NULL, getTableTableCell, DEFAULT, "The <-layout_manager if not @nil"), GM(NAME_area, 0, "area", NULL, getAreaTableCell, NAME_area, "Area in device coordinates") }; /* Resources */ #define rc_table_cell NULL /* static classvardecl rc_table_cell[] = { }; */ /* Class Declaration */ static Name table_cell_termnames[] = { NAME_image }; ClassDecl(table_cell_decls, var_table_cell, send_table_cell, get_table_cell, rc_table_cell, 1, table_cell_termnames, "$Rev$"); status makeClassTableCell(Class class) { return declareClass(class, &table_cell_decls); }