1 /* the rhs of a tallyrow ... group together everything to the right of the
2 * button
3 */
4
5 /*
6
7 Copyright (C) 1991-2003 The National Gallery
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License along
20 with this program; if not, write to the Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
23 */
24
25 /*
26
27 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
28
29 */
30
31 #include "ip.h"
32
33 /*
34 #define DEBUG
35 */
36
37 static HeapmodelClass *parent_class = NULL;
38
39 /* child is about to be added ... update our graphic/scol/text shortcuts.
40 */
41 static void
rhs_child_add(iContainer * parent,iContainer * child,int pos)42 rhs_child_add( iContainer *parent, iContainer *child, int pos )
43 {
44 Rhs *rhs = RHS( parent );
45
46 if( IS_SUBCOLUMN( child ) ) {
47 IDESTROY( rhs->scol );
48 rhs->scol = MODEL( child );
49 }
50 else if( IS_ITEXT( child ) ) {
51 IDESTROY( rhs->itext );
52 rhs->itext = MODEL( child );
53 }
54 else {
55 IDESTROY( rhs->graphic );
56 rhs->graphic = MODEL( child );
57 }
58
59 ICONTAINER_CLASS( parent_class )->child_add( parent, child, pos );
60 }
61
62 static void
rhs_child_remove(iContainer * parent,iContainer * child)63 rhs_child_remove( iContainer *parent, iContainer *child )
64 {
65 Rhs *rhs = RHS( parent );
66
67 if( (void *) child == (void *) rhs->graphic )
68 rhs->graphic = NULL;
69 else if( (void *) child == (void *) rhs->scol )
70 rhs->scol = NULL;
71 else if( (void *) child == (void *) rhs->itext )
72 rhs->itext = NULL;
73
74 ICONTAINER_CLASS( parent_class )->child_remove( parent, child );
75 }
76
77 static void
rhs_parent_add(iContainer * child)78 rhs_parent_add( iContainer *child )
79 {
80 g_assert( IS_ROW( child->parent ) );
81
82 ICONTAINER_CLASS( parent_class )->parent_add( child );
83 }
84
85 static View *
rhs_view_new(Model * model,View * parent)86 rhs_view_new( Model *model, View *parent )
87 {
88 return( rhsview_new() );
89 }
90
91 static gboolean
rhs_load(Model * model,ModelLoadState * state,Model * parent,xmlNode * xnode)92 rhs_load( Model *model,
93 ModelLoadState *state, Model *parent, xmlNode *xnode )
94 {
95 Rhs *rhs = RHS( model );
96
97 g_assert( IS_ROW( parent ) );
98
99 /* Hmm. Is this guaranteed?
100 */
101 g_assert( sizeof( RhsFlags ) == sizeof( int ) );
102
103 if( !get_iprop( xnode, "vislevel", &rhs->vislevel ) ||
104 !get_iprop( xnode, "flags", (int *) &rhs->flags ) )
105 return( FALSE );
106
107 if( !MODEL_CLASS( parent_class )->load( model, state, parent, xnode ) )
108 return( FALSE );
109
110 return( TRUE );
111 }
112
113 static xmlNode *
rhs_save(Model * model,xmlNode * xnode)114 rhs_save( Model *model, xmlNode *xnode )
115 {
116 Rhs *rhs = RHS( model );
117
118 xmlNode *xthis;
119
120 if( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) )
121 return( NULL );
122
123 if( !set_iprop( xthis, "vislevel", rhs->vislevel ) ||
124 !set_iprop( xthis, "flags", rhs->flags ) )
125 return( NULL );
126
127 return( xthis );
128 }
129
130 /* How to spot and make a graphic display.
131 */
132 typedef struct {
133 const char *name;
134 GType (*type)( void );
135 } RhsGraphic;
136
137 /* All our graphicdisplay widgets. Order is important! Most-derived classes
138 * first.
139 */
140 static RhsGraphic rhs_graphic[] = {
141 { CLASS_CLOCK, clock_get_type },
142 { CLASS_EXPRESSION, expression_get_type },
143 { CLASS_GROUP, group_get_type },
144 { CLASS_LIST, group_get_type },
145 { CLASS_PATHNAME, pathname_get_type },
146 { CLASS_FONTNAME, fontname_get_type },
147 { CLASS_TOGGLE, toggle_get_type },
148 { CLASS_SLIDER, slider_get_type },
149 { CLASS_COLOUR, colour_get_type },
150 { CLASS_OPTION, option_get_type },
151 { CLASS_MATRIX, matrix_get_type },
152 { CLASS_ARROW, iarrow_get_type },
153 { CLASS_REGION, iregion_get_type },
154 { CLASS_PLOT, plot_get_type },
155 { CLASS_IMAGE, iimage_get_type },
156 { CLASS_NUMBER, number_get_type },
157 { CLASS_REAL, real_get_type },
158 { CLASS_VECTOR, vector_get_type },
159 { CLASS_STRING, string_get_type }
160 };
161
162 /* Create/destroy the graphic display.
163 */
164 static gboolean
rhs_refresh_graphic(Rhs * rhs,PElement * root)165 rhs_refresh_graphic( Rhs *rhs, PElement *root )
166 {
167 gboolean result;
168 Row *row = HEAPMODEL( rhs )->row;
169 int i;
170
171 if( !heap_is_class( root, &result ) )
172 return( FALSE );
173
174 /* Only for non-parameter class objects.
175 */
176 if( result &&
177 row->sym &&
178 row->sym->type != SYM_PARAM ) {
179 for( i = 0; i < IM_NUMBER( rhs_graphic ); i++ ) {
180 const char *name = rhs_graphic[i].name;
181
182 if( !heap_is_instanceof( name, root, &result ) )
183 return( FALSE );
184 if( result )
185 break;
186 }
187
188 if( i != IM_NUMBER( rhs_graphic ) ) {
189 GType type = rhs_graphic[i].type();
190
191 if( !rhs->graphic || !TYPE_EXACT( rhs->graphic, type ) )
192 classmodel_new_classmodel( type, rhs );
193 }
194 else
195 /* Not a class we know about.
196 */
197 IDESTROY( rhs->graphic );
198 }
199 else
200 /* Should be no graphic display.
201 */
202 IDESTROY( rhs->graphic );
203
204 return( TRUE );
205 }
206
207 static void *
rhs_new_heap(Heapmodel * heapmodel,PElement * root)208 rhs_new_heap( Heapmodel *heapmodel, PElement *root )
209 {
210 gboolean result;
211 Rhs *rhs = RHS( heapmodel );
212 Row *row = HEAPMODEL( rhs )->row;
213
214 #ifdef DEBUG
215 printf( "rhs_new_heap: " );
216 row_name_print( HEAPMODEL( rhs )->row );
217 printf( "\n" );
218 #endif /*DEBUG*/
219
220 /* Create/reuse/destroy the graphic display.
221 */
222 if( !rhs_refresh_graphic( rhs, root ) )
223 return( rhs );
224
225 /* Create/reuse/destroy class display. Only for non-param symbols.
226 */
227 if( !heap_is_class( root, &result ) )
228 return( rhs );
229 if( result &&
230 row->sym &&
231 row->sym->type != SYM_PARAM ) {
232 if( !rhs->scol || !IS_SUBCOLUMN( rhs->scol ) )
233 subcolumn_new( rhs, NULL );
234 }
235 else
236 /* Should be no klass display.
237 */
238 IDESTROY( rhs->scol );
239
240 /* Create/reuse/destroy text display.
241 */
242 if( !rhs->itext )
243 itext_new( rhs );
244
245 /* Recurse for children.
246 */
247 if( rhs->graphic )
248 if( heapmodel_new_heap( HEAPMODEL( rhs->graphic ), root ) )
249 return( rhs );
250
251 if( rhs->scol )
252 if( heapmodel_new_heap( HEAPMODEL( rhs->scol ), root ) )
253 return( rhs );
254
255 if( rhs->itext )
256 if( heapmodel_new_heap( HEAPMODEL( rhs->itext ), root ) )
257 return( rhs );
258
259 return( HEAPMODEL_CLASS( parent_class )->new_heap( heapmodel, root ) );
260 }
261
262 /* Rethink child visibility.
263 */
264 void
rhs_set_vislevel(Rhs * rhs,int vislevel)265 rhs_set_vislevel( Rhs *rhs, int vislevel )
266 {
267 vislevel = IM_MAX( 0, vislevel );
268
269 #ifdef DEBUG
270 printf( "rhs_set_vislevel: %d ...\n", vislevel );
271 #endif /*DEBUG*/
272
273 if( rhs->scol ) {
274 Subcolumn *scol = SUBCOLUMN( rhs->scol );
275
276 if( rhs->graphic ) {
277 switch( vislevel ) {
278 case 0:
279 rhs->flags = RHS_ITEXT;
280 break;
281
282 case 1:
283 rhs->flags = RHS_GRAPHIC;
284 break;
285
286 case 2:
287 rhs->flags = RHS_ITEXT | RHS_GRAPHIC;
288 break;
289
290 default:
291 rhs->flags = RHS_ITEXT | RHS_GRAPHIC | RHS_SCOL;
292 }
293
294 subcolumn_set_vislevel( scol, vislevel - 2 );
295 if( vislevel < 3 )
296 rhs->vislevel = vislevel;
297 else
298 rhs->vislevel = scol->vislevel + 2;
299 }
300 else {
301 vislevel = IM_MAX( 1, vislevel );
302
303 if( vislevel == 1 )
304 rhs->flags = RHS_ITEXT;
305 else
306 rhs->flags = RHS_ITEXT | RHS_SCOL;
307
308 subcolumn_set_vislevel( scol, vislevel - 1 );
309 rhs->vislevel = scol->vislevel + 1;
310 }
311 }
312 else {
313 rhs->flags = RHS_ITEXT;
314 rhs->vislevel = vislevel;
315 }
316
317 #ifdef DEBUG
318 printf( "... set to: %d\n", rhs->vislevel );
319 #endif /*DEBUG*/
320
321 iobject_changed( IOBJECT( rhs ) );
322 }
323
324 void
rhs_vislevel_up(Rhs * rhs)325 rhs_vislevel_up( Rhs *rhs )
326 {
327 rhs_set_vislevel( rhs, rhs->vislevel + 1 );
328 }
329
330 void
rhs_vislevel_down(Rhs * rhs)331 rhs_vislevel_down( Rhs *rhs )
332 {
333 rhs_set_vislevel( rhs, rhs->vislevel - 1 );
334 }
335
336 static void *
rhs_update_model(Heapmodel * heapmodel)337 rhs_update_model( Heapmodel *heapmodel )
338 {
339 Rhs *rhs = RHS( heapmodel );
340
341 /* Update visibility.
342 */
343 rhs_set_vislevel( rhs, rhs->vislevel );
344
345 return( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) );
346 }
347
348 static void
rhs_class_init(RhsClass * class)349 rhs_class_init( RhsClass *class )
350 {
351 iContainerClass *icontainer_class = (iContainerClass *) class;
352 ModelClass *model_class = (ModelClass *) class;
353 HeapmodelClass *heapmodel_class = (HeapmodelClass *) class;
354
355 parent_class = g_type_class_peek_parent( class );
356
357 /* Create signals.
358 */
359
360 /* Init methods.
361 */
362 icontainer_class->child_add = rhs_child_add;
363 icontainer_class->child_remove = rhs_child_remove;
364 icontainer_class->parent_add = rhs_parent_add;
365
366 model_class->view_new = rhs_view_new;
367 model_class->load = rhs_load;
368 model_class->save = rhs_save;
369
370 heapmodel_class->new_heap = rhs_new_heap;
371 heapmodel_class->update_model = rhs_update_model;
372
373 /* Static init.
374 */
375 model_register_loadable( MODEL_CLASS( class ) );
376 }
377
378 static void
rhs_init(Rhs * rhs)379 rhs_init( Rhs *rhs )
380 {
381 #ifdef DEBUG
382 printf( "rhs_init\n" );
383 #endif /*DEBUG*/
384
385 /* -1 means not set yet ... default vislevel set by row_new_heap()
386 * when the class members become available.
387 */
388 rhs->vislevel = -1;
389
390 rhs->graphic = NULL;
391 rhs->scol = NULL;
392 rhs->itext = NULL;
393 }
394
395 GType
rhs_get_type(void)396 rhs_get_type( void )
397 {
398 static GType type = 0;
399
400 if( !type ) {
401 static const GTypeInfo info = {
402 sizeof( RhsClass ),
403 NULL, /* base_init */
404 NULL, /* base_finalize */
405 (GClassInitFunc) rhs_class_init,
406 NULL, /* class_finalize */
407 NULL, /* class_data */
408 sizeof( Rhs ),
409 32, /* n_preallocs */
410 (GInstanceInitFunc) rhs_init,
411 };
412
413 type = g_type_register_static( TYPE_HEAPMODEL,
414 "Rhs", &info, 0 );
415 }
416
417 return( type );
418 }
419
420 Rhs *
rhs_new(Row * row)421 rhs_new( Row *row )
422 {
423 Rhs *rhs = RHS( g_object_new( TYPE_RHS, NULL ) );
424
425 icontainer_child_add( ICONTAINER( row ), ICONTAINER( rhs ), -1 );
426
427 #ifdef DEBUG
428 printf( "rhs_new: " );
429 row_name_print( HEAPMODEL( rhs )->row );
430 printf( " (%p)\n", rhs );
431 #endif /*DEBUG*/
432
433 return( rhs );
434 }
435
436 static void *
rhs_child_edited_sub(Model * model)437 rhs_child_edited_sub( Model *model )
438 {
439 Row *row = ROW( model );
440
441 if( row->child_rhs && rhs_child_edited( row->child_rhs ) )
442 return( row );
443
444 return( NULL );
445 }
446
447 /* Does this RHS have any edited children? text, graphic, or recursive.
448 */
449 gboolean
rhs_child_edited(Rhs * rhs)450 rhs_child_edited( Rhs *rhs )
451 {
452 if( rhs->itext && ITEXT( rhs->itext )->edited )
453 return( TRUE );
454 else if( rhs->graphic && CLASSMODEL( rhs->graphic )->edited )
455 return( TRUE );
456 else if( rhs->scol )
457 return( icontainer_map( ICONTAINER( rhs->scol ),
458 (icontainer_map_fn) rhs_child_edited_sub,
459 NULL, NULL ) != NULL );
460 else
461 return( FALSE );
462 }
463