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