1 /* an ip arrow class object in a workspace
2  */
3 
4 /*
5 
6     Copyright (C) 1991-2003 The National Gallery
7 
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License along
19     with this program; if not, write to the Free Software Foundation, Inc.,
20     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21 
22  */
23 
24 /*
25 
26     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
27 
28  */
29 
30 /*
31 #define DEBUG
32  */
33 
34 #include "ip.h"
35 
36 static ClassmodelClass *parent_class = NULL;
37 
38 static void
iarrow_finalize(GObject * gobject)39 iarrow_finalize( GObject *gobject )
40 {
41 	iArrow *iarrow;
42 
43 #ifdef DEBUG
44 	printf( "iarrow_finalize\n" );
45 #endif /*DEBUG*/
46 
47 	g_return_if_fail( gobject != NULL );
48 	g_return_if_fail( IS_IARROW( gobject ) );
49 
50 	iarrow = IARROW( gobject );
51 
52 	/* My instance finalize stuff.
53 	 */
54 	iregion_instance_destroy( &iarrow->instance );
55 	vips_buf_destroy( &iarrow->caption_buffer );
56 
57 	G_OBJECT_CLASS( parent_class )->finalize( gobject );
58 }
59 
60 static void *
iarrow_generate_caption_sub(iImage * iimage,iArrow * iarrow,gboolean * first)61 iarrow_generate_caption_sub( iImage *iimage, iArrow *iarrow, gboolean *first )
62 {
63 	Workspace *ws = HEAPMODEL( iarrow )->row->ws;
64 	Row *row = HEAPMODEL( iimage )->row;
65 
66 	/* Suppress this name in the caption if it's a superclass. If this
67 	 * thing is on a super, it's on the subclass too ... not helpful to
68 	 * have it twice.
69 	 */
70 	if( !is_super( row->sym ) ) {
71 		if( *first )
72 			*first = FALSE;
73 		else
74 			vips_buf_appends( &iarrow->caption_buffer, ", " );
75 
76 		row_qualified_name_relative( ws->sym, row,
77 			&iarrow->caption_buffer );
78 	}
79 
80 	return( NULL );
81 }
82 
83 static const char *
iarrow_generate_caption(iObject * iobject)84 iarrow_generate_caption( iObject *iobject )
85 {
86 	static const char *names[] = {
87 		CLASS_HGUIDE,
88 		CLASS_VGUIDE,
89 		CLASS_MARK,
90 		CLASS_ARROW,
91 		NULL
92 	};
93 
94 	iArrow *iarrow = IARROW( iobject );
95 	VipsBuf *buf = &iarrow->caption_buffer;
96 	const int nimages = g_slist_length( CLASSMODEL( iarrow )->iimages );
97 	Expr *expr;
98 	gboolean result;
99 	gboolean first;
100 	int i;
101 
102 	if( !HEAPMODEL( iarrow )->row ||
103 		!(expr = HEAPMODEL( iarrow )->row->expr) ||
104 		!heap_is_class( &expr->root, &result ) ||
105 		!result )
106 		return( _( "No image" ) );
107 
108 	vips_buf_rewind( buf );
109 	heapmodel_name( HEAPMODEL( iarrow ), buf );
110 	vips_buf_appendf( buf, " " );
111 
112 	/* Used in (eg.) "Mark at (10, 10) on [A1, A2]"
113 	 */
114 	vips_buf_appendf( buf, _( "on" ) );
115 	vips_buf_appendf( buf, " " );
116 	if( nimages > 1 )
117 		vips_buf_appendf( buf, "[" );
118 	first = TRUE;
119 	slist_map2( CLASSMODEL( iarrow )->iimages,
120 		(SListMap2Fn) iarrow_generate_caption_sub, iarrow, &first );
121 	if( nimages > 1 )
122 		vips_buf_appendf( buf, "]" );
123 	vips_buf_appendf( buf, " " );
124 
125 	for( i = 0; names[i]; i++ ) {
126 		if( !heap_is_instanceof( names[i], &expr->root, &result ) )
127 			break;
128 
129 		if( result ) {
130 			switch( i ) {
131 			case 0:
132 				vips_buf_appendf( buf, _( "at %d" ),
133 					iarrow->instance.area.top );
134 				break;
135 
136 			case 1:
137 				vips_buf_appendf( buf, _( "at %d" ),
138 					iarrow->instance.area.left );
139 				break;
140 
141 			case 2:
142 				vips_buf_appendf( buf, _( "at (%d, %d)" ),
143 					iarrow->instance.area.left,
144 					iarrow->instance.area.top );
145 				break;
146 
147 			case 3:
148 				vips_buf_appendf( buf,
149 					_( "at (%d, %d), offset (%d, %d)" ),
150 					iarrow->instance.area.left,
151 					iarrow->instance.area.top,
152 					iarrow->instance.area.width,
153 					iarrow->instance.area.height );
154 				break;
155 
156 			default:
157 				g_assert( 0 );
158 			}
159 
160 			break;
161 		}
162 	}
163 
164 	return( vips_buf_all( buf ) );
165 }
166 
167 static View *
iarrow_view_new(Model * model,View * parent)168 iarrow_view_new( Model *model, View *parent )
169 {
170 	return( valueview_new() );
171 }
172 
173 static void *
iarrow_update_model(Heapmodel * heapmodel)174 iarrow_update_model( Heapmodel *heapmodel )
175 {
176 	/* Parent first ... this will update our instance vars.
177 	 */
178 	if( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) )
179 		return( heapmodel );
180 
181 	if( heapmodel->row->expr ) {
182 		iArrow *iarrow = IARROW( heapmodel );
183 
184 		/* Update who-has-displays-on-what stuff.
185 		 */
186 		classmodel_iimage_update( CLASSMODEL( iarrow ),
187 			iarrow->instance.ii );
188 
189 		/* Need to make sure the caption is regenerated.
190 		 */
191 		iobject_changed( IOBJECT( heapmodel ) );
192 	}
193 
194 	return( NULL );
195 }
196 
197 static void *
iarrow_get_instance(Classmodel * classmodel)198 iarrow_get_instance( Classmodel *classmodel )
199 {
200 	iArrow *iarrow = IARROW( classmodel );
201 
202 	return( &iarrow->instance );
203 }
204 
205 static void
iarrow_class_init(iArrowClass * class)206 iarrow_class_init( iArrowClass *class )
207 {
208 	GObjectClass *gobject_class = (GObjectClass *) class;
209 	iObjectClass *iobject_class = (iObjectClass *) class;
210 	iContainerClass *icontainer_class = (iContainerClass *) class;
211 	ModelClass *model_class = (ModelClass *) class;
212 	HeapmodelClass *heapmodel_class = (HeapmodelClass *) class;
213 	ClassmodelClass *classmodel_class = (ClassmodelClass *) class;
214 
215 	/* We share methods with iregion in a sort of MI way ... iregion needs
216 	 * to be initialised before we can work. Force it to start up.
217 	 */
218 	(void) iregion_get_type();
219 
220 	parent_class = g_type_class_peek_parent( class );
221 
222 	/* Create signals.
223 	 */
224 
225 	/* Init methods.
226 	 */
227 	gobject_class->finalize = iarrow_finalize;
228 
229 	iobject_class->generate_caption = iarrow_generate_caption;
230 
231 	icontainer_class->parent_add = iregion_parent_add;
232 
233 	model_class->view_new = iarrow_view_new;
234 	model_class->edit = iregion_edit;
235 	model_class->save = iregion_save;
236 	model_class->load = iregion_load;
237 
238 	heapmodel_class->update_model = iarrow_update_model;
239 	heapmodel_class->update_heap = iregion_update_heap;
240 
241 	classmodel_class->class_get = iregion_class_get;
242 	classmodel_class->class_new = iregion_class_new;
243 	classmodel_class->get_instance = iarrow_get_instance;
244 
245 	/* Static init.
246 	 */
247 	model_register_loadable( MODEL_CLASS( class ) );
248 }
249 
250 static void
iarrow_init(iArrow * iarrow)251 iarrow_init( iArrow *iarrow )
252 {
253 	iregion_instance_init( &iarrow->instance, CLASSMODEL( iarrow ) );
254 	vips_buf_init_dynamic( &iarrow->caption_buffer, MAX_LINELENGTH );
255 
256 	iobject_set( IOBJECT( iarrow ), CLASS_ARROW, NULL );
257 }
258 
259 GType
iarrow_get_type(void)260 iarrow_get_type( void )
261 {
262 	static GType type = 0;
263 
264 	if( !type ) {
265 		static const GTypeInfo info = {
266 			sizeof( iArrowClass ),
267 			NULL,           /* base_init */
268 			NULL,           /* base_finalize */
269 			(GClassInitFunc) iarrow_class_init,
270 			NULL,           /* class_finalize */
271 			NULL,           /* class_data */
272 			sizeof( iArrow ),
273 			32,             /* n_preallocs */
274 			(GInstanceInitFunc) iarrow_init,
275 		};
276 
277 		type = g_type_register_static( TYPE_CLASSMODEL,
278 			"iArrow", &info, 0 );
279 	}
280 
281 	return( type );
282 }
283