Add to git.
[monolith.git] / src / ml_table_layout.c
1 /* Monolith table layout class.
2  * - by Richard W.M. Jones <rich@annexia.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  *
18  * $Id: ml_table_layout.c,v 1.3 2002/11/13 20:46:38 rich Exp $
19  */
20
21 #include "config.h"
22
23 #ifdef HAVE_ASSERT_H
24 #include <assert.h>
25 #endif
26
27 #include <pthr_iolib.h>
28
29 #include "ml_widget.h"
30 #include "monolith.h"
31 #include "ml_table_layout.h"
32
33 static void repaint (void *, ml_session, const char *, io_handle);
34 static struct ml_widget_property properties[];
35
36 struct ml_widget_operations table_layout_ops =
37   {
38     repaint: repaint,
39     properties: properties
40   };
41
42 struct cell
43 {
44   ml_widget w;                  /* Widget stored in the cell. */
45   const char *clazz;            /* Stylesheet class. */
46   unsigned char rowspan;        /* Rowspan. */
47   unsigned char colspan;        /* Colspan. */
48   unsigned char flags;          /* Various flags. */
49 #define CELL_FLAGS_NO_PAINT  0x01
50 #define CELL_FLAGS_IS_HEADER 0x02
51   char align;                   /* l|r|c */
52   char valign;                  /* t|b|m */
53 };
54
55 struct ml_table_layout
56 {
57   struct ml_widget_operations *ops;
58   pool pool;                    /* Pool for allocations. */
59   int rows, cols;               /* Number of rows, columns. */
60   const char *clazz;            /* Stylesheet class for the whole table. */
61
62   /* Cells are stored in this 2D array. */
63   struct cell **cells;
64 };
65
66 static struct ml_widget_property properties[] =
67   {
68     { name: "class",
69       offset: ml_offsetof (struct ml_table_layout, clazz),
70       type: ML_PROP_STRING },
71     { 0 }
72   };
73
74 static inline struct cell *
75 get_cell (ml_table_layout w, int row, int col)
76 {
77   assert (0 <= row && row < w->rows);
78   assert (0 <= col && col < w->cols);
79   return &w->cells[row][col];
80 }
81
82 static inline void
83 init_cell (ml_table_layout w, int r, int c)
84 {
85   w->cells[r][c].w = 0;
86   w->cells[r][c].clazz = 0;
87   w->cells[r][c].rowspan = 1;
88   w->cells[r][c].colspan = 1;
89   w->cells[r][c].flags = 0;
90   w->cells[r][c].align = 'l';
91   w->cells[r][c].valign = 'm';
92 }
93
94 ml_table_layout
95 new_ml_table_layout (pool pool, int rows, int cols)
96 {
97   ml_table_layout w = pmalloc (pool, sizeof *w);
98   int r, c;
99
100   w->ops = &table_layout_ops;
101   w->pool = pool;
102   w->rows = rows;
103   w->cols = cols;
104   w->clazz = 0;
105
106   w->cells = pmalloc (pool, sizeof (struct cell *) * rows);
107   for (r = 0; r < rows; ++r)
108     {
109       w->cells[r] = pmalloc (pool, sizeof (struct cell) * cols);
110       for (c = 0; c < cols; ++c)
111         init_cell (w, r, c);
112     }
113
114   return w;
115 }
116
117 void
118 ml_table_layout_pack (ml_table_layout w, ml_widget _w, int row, int col)
119 {
120   get_cell (w, row, col)->w = _w;
121 }
122
123 void
124 ml_table_layout_add_row (ml_table_layout w)
125 {
126   int c;
127
128   w->cells = prealloc (w->pool,
129                        w->cells, sizeof (struct cell *) * (w->rows+1));
130   w->cells[w->rows] = pmalloc (w->pool, sizeof (struct cell) * w->cols);
131
132   for (c = 0; c < w->cols; ++c)
133     init_cell (w, w->rows, c);
134
135   w->rows++;
136 }
137
138 void
139 ml_table_layout_set_colspan (ml_table_layout w, int row, int col, int colspan)
140 {
141   assert (colspan > 0);
142   assert (col + colspan <= w->cols);
143   get_cell (w, row, col)->colspan = colspan;
144 }
145
146 void
147 ml_table_layout_set_rowspan (ml_table_layout w, int row, int col, int rowspan)
148 {
149   assert (rowspan > 0);
150   assert (row + rowspan <= w->rows);
151   get_cell (w, row, col)->rowspan = rowspan;
152 }
153
154 void
155 ml_table_layout_set_align (ml_table_layout w, int row, int col,
156                            const char *align)
157 {
158   get_cell (w, row, col)->align = align[0];
159 }
160
161 void
162 ml_table_layout_set_valign (ml_table_layout w, int row, int col,
163                             const char *valign)
164 {
165   get_cell (w, row, col)->valign = valign[0];
166 }
167
168 void
169 ml_table_layout_set_class (ml_table_layout w, int row, int col,
170                            const char *clazz)
171 {
172   get_cell (w, row, col)->clazz = clazz;
173 }
174
175 void
176 ml_table_layout_set_header (ml_table_layout w, int row, int col,
177                             int is_header)
178 {
179   if (is_header)
180     get_cell (w, row, col)->flags |= CELL_FLAGS_IS_HEADER;
181   else
182     get_cell (w, row, col)->flags &= ~CELL_FLAGS_IS_HEADER;
183 }
184
185 static void
186 repaint (void *vw, ml_session session, const char *windowid, io_handle io)
187 {
188   ml_table_layout w = (ml_table_layout) vw;
189   int r, c;
190
191   /* Clear all the NO_PAINT flags. */
192   for (r = 0; r < w->rows; ++r)
193     for (c = 0; c < w->cols; ++c)
194       get_cell (w, r, c)->flags &= ~CELL_FLAGS_NO_PAINT;
195
196   /* Start of the table. */
197   io_fputs ("<table", io);
198   if (w->clazz) io_fprintf (io, " class=\"%s\"", w->clazz);
199   io_fputs (">", io);
200
201   /* Paint the cells. */
202   for (r = 0; r < w->rows; ++r)
203     {
204       io_fprintf (io, "<tr>");
205
206       for (c = 0; c < w->cols; ++c)
207         {
208           struct cell *cl = get_cell (w, r, c);
209
210           if (!(cl->flags & CELL_FLAGS_NO_PAINT))
211             {
212               int i, j;
213
214               /* If there is a row or column span > 1, then we need to mark
215                * the cells in the "shadow" as not painted.
216                */
217               for (i = 0; i < cl->rowspan; ++i)
218                 for (j = 0; j < cl->colspan; ++j)
219                   get_cell (w, r+i, c+j)->flags |= CELL_FLAGS_NO_PAINT;
220
221               if (!(cl->flags & CELL_FLAGS_IS_HEADER))
222                 io_fprintf (io, "<td");
223               else
224                 io_fprintf (io, "<th");
225               if (cl->clazz)
226                 io_fprintf (io, " class=\"%s\"", cl->clazz);
227               if (cl->rowspan > 1)
228                 io_fprintf (io, " rowspan=\"%d\"", cl->rowspan);
229               if (cl->colspan > 1)
230                 io_fprintf (io, " colspan=\"%d\"", cl->colspan);
231               if (cl->align == 'r')
232                 io_fprintf (io, " align=\"right\"");
233               else if (cl->align == 'c')
234                 io_fprintf (io, " align=\"center\"");
235               if (cl->valign == 't')
236                 io_fprintf (io, " valign=\"top\"");
237               else if (cl->valign == 'b')
238                 io_fprintf (io, " valign=\"bottom\"");
239               io_fprintf (io, ">");
240               if (cl->w)
241                 ml_widget_repaint (cl->w, session, windowid, io);
242               else
243                 io_fprintf (io, "&nbsp;");
244               if (!(cl->flags & CELL_FLAGS_IS_HEADER))
245                 io_fprintf (io, "</td>\n");
246               else
247                 io_fprintf (io, "</th>\n");
248             }
249         }
250
251       io_fprintf (io, "</tr>\n");
252     }
253
254   io_fprintf (io, "</table>");
255 }