1 /*****************************************************************************
2 Major portions of this software are copyrighted by the Medical College
3 of Wisconsin, 1994-2000, and are released under the Gnu General Public
4 License, Version 2. See the file README.Copyright for details.
5 ******************************************************************************/
6
7 /*----------------------------------------------------------------------------*/
8 /* Please note that this file is not "integrated" into AFNI. By this I
9 mean that it doesn't know about AFNI controllers, datasets, and so on.
10 It is an image viewing server, and the caller needs to provide a
11 callback function to get data to be displayed, and also provide some
12 other info. The callback function provide a sequence of 2D images
13 to be displayed at the user's whim. Besides being used in the AFNI GUI
14 to view slices from a 3D dataset, the imseq functionality is also used
15 in the Rendering plugin to view 3D renderings, in the aiv program for
16 generic image viewing, and in SUMA for capturing image snapshots.
17 *//*--------------------------------------------------------------------------*/
18
19 /*----------------------------------------------------------------------------*/
20 /* Structure of this AFNI image viewer:
21
22 * An image viewer's data structure is an MCW_imseq, created by
23 calling open_MCW_imseq(). Each AFNI controller has 3 MCW_imseq's:
24 the axial, sagittal, and coronal viewers.
25
26 * The prototype is
27 MCW_imseq * open_MCW_imseq( MCW_DC *dc ,
28 get_ptr get_image , XtPointer aux )
29 dc = "display context" (display.[ch]) that holds the
30 information about X11 display, colors, fonts,
31 graphics contexts, .... This information is
32 used when actually drawing to the display.
33 get_image = function that returns a pointer, which is the
34 way the MCW_imseq gets information from AFNI.
35 aux = pointer to any information that AFNI wants when
36 get_image() is called -- information that lets
37 AFNI identify what image viewer is calling.
38
39 * get_image() is called by get_image(n,type,aux), where
40 n = (int) calling parameter - for example, image index
41 type = (int) one of the isqCR_xxx codes in imseq.h,
42 indicating the "Callback Reason" -- what AFNI is
43 to do with this call.
44 aux = the same "aux" as above, to give back to AFNI the
45 auxiliary information needed to identify this viewer.
46 The type of object pointed to by get_image()'s return depends on
47 "type" -- at this date [Jan 2021] there are 33 isqCR_xxx codes.
48
49 * In turn, AFNI can control what the image viewer does by calling
50 the function drive_MCW_imseq(), which will carry out some action
51 specified by one of the isqDR_xxx "Drive Reason" codes in imseq.h.
52 At this date, there are 73 such isqDR_xxx codes.
53
54 * And of course, the user can control what the viewer does by using
55 the Widgets created in open_MCW_imseq(). Most user actions also
56 result in a call to get_image() to inform AFNI about the change;
57 for example, if the slice viewed is changed, AFNI needs to know
58 to update the crosshairs, the displayed coordinates, etc.
59
60 * This image viewer is also used in programs aiv, to3d, Xphace (a toy),
61 and in SUMA via the ISQ_snap*() functions -- which are located
62 in imseq.c and xim.c, and provide a way for a program to snapshot
63 an image or a Widget and save it to a viewer or directly to a file.
64
65 * Over the years (starting July 1994), the image viewer has grown
66 to have more and more functionality, which makes the code below
67 more and more ugly. However, the basic structure is not complicated:
68 User does something
69 imseq.c may make a change itself (e.g., Zoom current image)
70 or it may call AFNI to do something (e.g., provide a new image)
71 AFNI drives viewer to do something
72 which may in turn call AFNI back to provide data
73 (there are safeguards to prevent infinite recursion)
74 The ugliness comes from the many operations included in the word
75 "something" above, and the necessity for providing controls and
76 functions for all of them. And from the fact that the image viewer
77 has far outgrown its original scope, and pieces were added over
78 Lo These Many Years, so the code is kind of a mess.
79
80 * As a measure of the growth of the code, on 1997-11-05 (the date
81 I put AFNI under code version control via SCCS), there were 3409
82 lines in this file. As of right now (2021-01-13), the line count
83 has expanded to 14510 -- 426% growth over 23 years.
84
85 * Good luck, and be careful in here -- Bob Cox.
86 *//*--------------------------------------------------------------------------*/
87
88 #include <stdio.h>
89 #include <string.h>
90 #include <errno.h> /* 01 May 2003 - rickr */
91 #include <X11/keysym.h> /* 24 Jan 2003 */
92
93 #undef IMSEQ_DEBUG
94
95 #include "mrilib.h"
96 #include "imseq.h"
97 #include "xutil.h"
98 #include "xim.h"
99
100 #if 0 /* used to debug only this file */
101 # undef DBG_trace
102 # define DBG_trace 2
103 #endif
104
105 #define DPRI(st,ijk) \
106 if(PRINT_TRACING){ char str[256]; sprintf(str,"%s %d",st,ijk); STATUS(str); }
107
108 #define COLSIZE AV_colsize() /* for optmenus -- 11 Dec 2001 */
109
110 #define DONT_ONOFF_ONE /* 29 Jul 2002 */
111
112 /* macro to send information to AFNI */
113 #define SEND(sq,cb) \
114 AFNI_CALL_VOID_3ARG( (sq)->status->send_CB , \
115 MCW_imseq * , sq , \
116 XtPointer , (sq)->getaux , \
117 ISQ_cbs * , &(cb) )
118
119 static Widget wwtem ;
120
121 #define SWL_TMASK_DEFAULT (Mod1Mask | Mod2Mask)
122
123 static int scrollwheel_tmask = SWL_TMASK_DEFAULT ;
124 static int scrollwheel_debug = 0 ;
125
126 void ISQ_set_scale( Widget wscal , int percent ) ;
127 void ISQ_render_scal_CB( Widget w, XtPointer client_data, XtPointer call_data ) ;
128 void ISQ_popdown_render_scal( MCW_imseq *seq ) ;
129 void ISQ_popup_render_scal( MCW_imseq *seq ) ;
130
131 /* stuff for the VG effect */
132
133 static float vgize_sigfac = 0.02f ;
134 static MRI_IMAGE * mri_vgize( MRI_IMAGE *im ) ;
135 #define VGFAC(sss) \
136 ( ((sss)->opt.improc_code & ISQ_IMPROC_VG) ? (sss)->vgize_fac : 0.0f )
137 #if 1
138 # define VGSCAL 1.27537f
139 # define INDEX_TO_VGFAC(qq) ( powf(VGSCAL,(float)((qq)-1))*0.01f )
140 # define VGFAC_TO_INDEX(vf) ( (int)(logf(100.01f*(vf))/logf(VGSCAL)+1.01f))
141 #else
142 # define INDEX_TO_VGFAC(qq) (0.01f*(qq))
143 # define VGFAC_TO_INDEX(vf) ((int)(100.01f*(vf)))
144 #endif
145
146 /************************************************************************
147 Define the buttons and boxes that go in the "Disp" dialog
148 *************************************************************************/
149
150 /*-- structures defining action buttons (at bottom of dialog) --*/
151
152 #define NACT_DISP 2 /* number of action buttons */
153 #define DISP_OK 1 /* indices for button labels */
154 #define DISP_UNDO 0
155
156 /*** do NOT re-enable group statistics -- it's very old code ***/
157 #define NO_GROUP_SCALE /* button box NTOG_SCL will be disabled */
158 #ifdef NO_GROUP_SCALE /* and no group statistics will be computed */
159 # undef AUTOMATE_STATISTICS
160 #endif
161
162 static MCW_action_item ISQ_disp_act[NACT_DISP] = {
163 {"Reset",ISQ_disp_act_CB,NULL,"Sets all options back\nto earlier values","Undo changes", 0 },
164 {"Done" ,ISQ_disp_act_CB,NULL,"Closes this window" ,"Close window", 1 }
165 } ;
166
167 /*-- structures defining the 9 toggle button boxes --*/
168
169 /* number of buttons in each button box */
170 #define NBUT_DISP1 4 /* Rotation box */
171 #define NBUT_DISP2 1 /* Mirror box */
172 #define NBUT_DISP3 1 /* No overlay box */
173 #define NBUT_DISP4 3 /* Range scaling box */
174 #define NBUT_DISP5 2 /* Auto- or Group- scale box [will be hidden] */
175 #define NBUT_DISP6 1 /* Free aspect box */
176 #define NBUT_DISP7 2 /* Save box */ /* 26 Jul 2001: was 3, now 2 */
177 #define NBUT_DISP8 4 /* IMPROC buttons */
178 #define NBUT_DISP9 4 /* CX buttons */
179
180 #define NTOG_ROT 0 /* index of which button box control which option(s) */
181 #define NTOG_MIR 1
182 #define NTOG_COL 2
183 #define NTOG_RNG 3
184 #define NTOG_SCL 4
185 #define NTOG_ASP 5
186 #define NTOG_SAV 6
187 #define NTOG_IMP 7
188 #define NTOG_CX 8
189
190 #define ALLOW_CLIPPING(ss,tt) \
191 do{ int za = (int)(tt) ; \
192 int zb = ( ISQ_REALZ(ss) && (ss)->dialog != NULL && \
193 (ss)->dialog_starter == NBUT_DISP && \
194 (ss)->bbox[NTOG_RNG] != NULL ) ; \
195 if(zb) SENSITIZE((ss)->bbox[NTOG_RNG]->wbut[2],za) ; \
196 if( (ss)->opt.scale_range == ISQ_RNG_CLIPPED && !za ){ \
197 (ss)->opt.scale_range = ISQ_RNG_02TO98 ; \
198 if(zb) MCW_set_bbox((ss)->bbox[NTOG_RNG],ISQ_RNG_02TO98); \
199 } else if( za && (ss)->redo_clip ){ \
200 (ss)->opt.scale_range = ISQ_RNG_CLIPPED ; \
201 if(zb) MCW_set_bbox((ss)->bbox[NTOG_RNG],ISQ_RNG_CLIPPED);\
202 } \
203 } while(0)
204
205 /* labels for the toggle buttons in each box */
206
207 static char * ISQ_dl1[NBUT_DISP1] = {
208 "No Rotation" , "CCW 90" , "Rot 180" , "CW 90" } ;
209 static char * ISQ_dl2[NBUT_DISP2] = { "+ LR Mirror" } ;
210 static char * ISQ_dl3[NBUT_DISP3] = { "No Overlay" } ;
211 static char * ISQ_dl4[NBUT_DISP4] = { "Min-to-Max" , "2%-to-98%" , "Clipped" } ;
212 static char * ISQ_dl5[NBUT_DISP5] = { "Autoscale" , "Groupscale" } ;
213 static char * ISQ_dl6[NBUT_DISP6] = { "Free Aspect" } ;
214 static char * ISQ_dl7[NBUT_DISP7] = { "Nsize Save" , "PNM Save" } ;
215 static char * ISQ_dl8[NBUT_DISP8] = { "Flatten" , "Sharpen" , "Edge Detect" , "VG paint" } ;
216 static char * ISQ_dl9[NBUT_DISP9] = {
217 "Complex->Mag" , "Complex->Arg" , "Complex->Real" , "Complex->Imag" } ;
218
219 /* collect info about boxes, including the type (see bbox.c):
220 radio_one = exactly one button can be pressed in
221 radio_zero = zero or one button can be pressed in
222 check = any combination of buttons can be pressed in */
223
224 static ISQ_boxdef ISQ_dispbb[] = {
225 { NBUT_DISP1 , ISQ_dl1 , MCW_BB_radio_one , MCW_BB_frame } ,
226 { NBUT_DISP2 , ISQ_dl2 , MCW_BB_check , MCW_BB_frame } ,
227 { NBUT_DISP3 , ISQ_dl3 , MCW_BB_check , MCW_BB_frame } ,
228 { NBUT_DISP4 , ISQ_dl4 , MCW_BB_radio_one , MCW_BB_frame } ,
229 { NBUT_DISP5 , ISQ_dl5 , MCW_BB_radio_one , MCW_BB_frame } ,
230 { NBUT_DISP6 , ISQ_dl6 , MCW_BB_check , MCW_BB_frame } ,
231 { NBUT_DISP7 , ISQ_dl7 , MCW_BB_radio_zero , MCW_BB_frame } ,
232 { NBUT_DISP8 , ISQ_dl8 , MCW_BB_check , MCW_BB_frame } ,
233 { NBUT_DISP9 , ISQ_dl9 , MCW_BB_radio_one , MCW_BB_frame } ,
234 } ;
235
236 /* helps and hints for the ignorant */
237
238 static char * ISQ_bb1_help[NBUT_DISP1] = {
239 "Sets orientation to the\noriginal in the data set" ,
240 "Rotate 90 degrees\ncounterclockwise\nfrom original" ,
241 "Rotate 180 degrees\nfrom original" ,
242 "Rotate 90 degrees\nclockwise\nfrom original"
243 } ;
244
245 static char * ISQ_bb1_hint[NBUT_DISP1] = {
246 "No extra rotation of image" ,
247 "90 degrees counterclockwise" ,
248 "Rotate 180 degrees" ,
249 "90 degrees clockwise"
250 } ;
251
252 static char * ISQ_bb2_help[NBUT_DISP2] = {
253 "pressed IN means\nleft-right mirror AFTER rotation"
254 } ;
255
256 static char * ISQ_bb2_hint[NBUT_DISP2] = {
257 "IN: mirror image AFTER rotation"
258 } ;
259
260 static char * ISQ_bb3_help[NBUT_DISP3] = {
261 "pressed IN means\nturn color overlays off"
262 } ;
263
264 static char * ISQ_bb3_hint[NBUT_DISP3] = {
265 "IN: turn color overlays off"
266 } ;
267
268 static char * ISQ_bb4_help[NBUT_DISP4] = {
269 "Intensities mapped\nover full range of data\n(min->lowest,max->highest)" ,
270 "Intensities mapped\nover partial range of data\n(%ages in data histogram)" ,
271 "Intensities mapped\nover auto-clipped range\nof data in all images"
272 } ;
273
274 static char * ISQ_bb4_hint[NBUT_DISP4] = {
275 "Background intensity = min to max pixel values" ,
276 "Background intensity = 2% to 98% pixel values" ,
277 "Background intensity = auto-clipped from volume"
278 } ;
279
280 static char * ISQ_bb5_help[NBUT_DISP5] = {
281 "Intensities mapped\nfor each image separately" ,
282 "Intensities mapped\nfor all images in common"
283 } ;
284
285 static char * ISQ_bb5_hint[NBUT_DISP5] = {
286 "Intensities computed for each slice" ,
287 "Intensities computed for all slices at once"
288 } ;
289
290 static char * ISQ_bb6_help[NBUT_DISP6] = {
291 "pressed IN means allow arbitrary resizing of window\n"
292 "pressed OUT means restrict window aspect ratio"
293 } ;
294
295 static char * ISQ_bb6_hint[NBUT_DISP6] = {
296 "IN: Allow arbitrary resizing of window"
297 } ;
298
299 static char * ISQ_bb7_help[NBUT_DISP7] = {
300 "Nsize: IN = 'normal' (power of 2) saved images sizes\n"
301 " OUT= 'natural' (data given) saved images sizes" ,
302
303 "PNM: IN = saved images are color (PNM format)\n"
304 " OUT= saved images are background data only\n"
305 } ;
306
307 static char * ISQ_bb7_hint[NBUT_DISP7] = {
308 "IN: Save background images in power-of-2 sizes" ,
309 "IN: Save background images in PNM format"
310 } ;
311
312 static char * ISQ_bb8_help[NBUT_DISP8] = {
313 "Flatten: IN = Flatten histogram of background\n"
314 " OUT= Don't flatten histogram\n" ,
315
316 "Sharpen: IN = Apply sharpening filter to background\n"
317 " OUT= Don't apply sharpening filter" ,
318
319 "Edge: IN = Use Sobel edge detection filter on background\n"
320 " OUT= Don't use Sobel edge detector" ,
321
322 "VG: IN = Apply a painting effect to the image.\n"
323 " OUT= Don't do this (which is just for fun)."
324 } ;
325
326 static char * ISQ_bb8_hint[NBUT_DISP8] = {
327 "Flatten histogram of background" ,
328 "Apply sharpening filter to background" ,
329 "Apply Sobel edge detector to background" ,
330 "Apply painting effect (for fun)"
331 } ;
332
333 #define ISQ_CX_HELP \
334 "Complex-> options control how complex-\n" \
335 "valued images are displayed:\n" \
336 " ->Mag == Display magnitude\n" \
337 " ->Arg == Display argument (phase)\n" \
338 " ->Real == Display real part\n" \
339 " ->Imag == Display imaginary part"
340
341 static char * ISQ_bb9_help[NBUT_DISP9] = {
342 ISQ_CX_HELP , ISQ_CX_HELP , ISQ_CX_HELP , ISQ_CX_HELP
343 } ;
344
345 static char * ISQ_bb9_hint[NBUT_DISP9] = {
346 "Display magnitude" ,
347 "Display argument (phase)"
348 "Display real part" ,
349 "Display imaginary part"
350 } ;
351
352 static char ** ISQ_bb_allhelp[] = {
353 ISQ_bb1_help , ISQ_bb2_help , ISQ_bb3_help ,
354 ISQ_bb4_help , ISQ_bb5_help , ISQ_bb6_help ,
355 ISQ_bb7_help , ISQ_bb8_help , ISQ_bb9_help
356 } ;
357
358 static char ** ISQ_bb_allhint[] = {
359 ISQ_bb1_hint , ISQ_bb2_hint , ISQ_bb3_hint ,
360 ISQ_bb4_hint , ISQ_bb5_hint , ISQ_bb6_hint ,
361 ISQ_bb7_hint , ISQ_bb8_hint , ISQ_bb9_hint
362 } ;
363 /*************************************************************************/
364
365 /*------ 27 Jun 2001: list of external programs that may be of use ------*/
366
367 /* ppmto = programs to take as image input the simple PPM format
368 and convert the image to something more useful, like JPEG */
369
370 static char ** ppmto_filter = NULL ;
371 static char ** ppmto_suffix = NULL ;
372 static int * ppmto_bval = NULL ;
373 static int ppmto_num = -1 ;
374 static int * ppmto_gimpize = NULL ;
375
376 static char * ppmto_gif_filter = NULL ; /* 27 Jul 2001 */
377 static char * ppmto_agif_filter = NULL ;
378
379 #define USE_GIFF /* use Fixed colormap GIF for animations */
380 #ifdef USE_GIFF
381 static char * ppmto_giff_filter = NULL ; /* 05 Oct 2004 */
382 #define GIFF_MAPFILE "Qwerty53211.ppm" /* 53211 was my Zip code in WI */
383 #endif
384
385 static char * ppmto_mpeg_filter = NULL ; /* 02 Aug 2001 */
386 static char * ppmto_ppm_filter = NULL ;
387
388 static char * ppmto_jpg75_filter = NULL ; /* 27 Mar 2002 */
389 static char * ppmto_jpg95_filter = NULL ; /* 28 Jul 2005 */
390 static char * ppmto_png_filter = NULL ; /* 07 Dec 2006 */
391
392 static char * gimp_path = NULL ; /* 27 Oct 2017 */
393
394 /* the first %s will be the list of input gif filenames */
395 /* the second %s is the single output animated gif filename */
396
397 #define GIFSICLE_SUFFIX "-O2 -d %d -k 127 -l %%s > %%s"
398 #define WHIRLGIF_SUFFIX "-time %d -loop %%s > %%s"
399 #define FFMPEG_SUFFIX "-loglevel quiet -y"
400
401 #define DO_AGIF(sq) ((sq)->opt.save_agif)
402 #define DO_MPEG(sq) ((sq)->opt.save_mpeg)
403 #define DO_ANIM(sq) (DO_AGIF(sq) || DO_MPEG(sq))
404
405 /* below: the first DO_BLOWUP will let montages be blown up
406 the second will not [20 Dec 2016] */
407
408 #if 1
409 # define DO_BLOWUP(sss) \
410 ((sss)->zoom_fac > 1 || (sss)->saver_blowup > 1)
411 #else
412 # define DO_BLOWUP(sss) \
413 ( ((sss)->zoom_fac > 1 || (sss)->saver_blowup > 1) && \
414 ((sss)->mont_nx == 1 && (sss)->mont_ny == 1) )
415 #endif
416
417 #define ADDTO_PPMTO(pnam,suff,bbb,ggg) \
418 do{ ppmto_filter = (char **) realloc( ppmto_filter , \
419 sizeof(char *)*(ppmto_num+1) ) ; \
420 ppmto_suffix = (char **) realloc( ppmto_suffix , \
421 sizeof(char *)*(ppmto_num+1) ) ; \
422 ppmto_bval = (int *) realloc( ppmto_bval , \
423 sizeof(int) *(ppmto_num+1) ) ; \
424 ppmto_gimpize= (int *) realloc( ppmto_gimpize , \
425 sizeof(int) *(ppmto_num+1) ) ; \
426 ppmto_filter [ppmto_num] = (pnam) ; \
427 ppmto_suffix [ppmto_num] = (suff) ; \
428 ppmto_bval [ppmto_num] = (bbb) ; \
429 ppmto_gimpize[ppmto_num] = (ggg)&&(gimp_path!=NULL); ppmto_num++; \
430 if( dbg ) fprintf(stderr,"IMSAVE: filter '%s' for suffix '%s'\n", \
431 (pnam) , (suff) ) ; \
432 } while(0)
433
434 /** 16 Nov 2004: warning messages when can't find Save filters? **/
435
436 #define CANT_FIND(nm,fm) \
437 do{ if( !AFNI_noenv("AFNI_IMSAVE_WARNINGS") ){ \
438 if( ncant == 0 ) \
439 fprintf(stderr,"\n++++++++ IMAGE SAVE SETUP WARNINGS ++++++++\n");\
440 fprintf(stderr, \
441 "++ Can't find program %s for Save to %s\n",(nm),(fm)) ; \
442 } ncant++ ; \
443 } while(0)
444
445 /*------------------------------------------------------------------*/
446 /*---- Setup programs as filters: ppm stdin to some output file ----*/
447 /*---- Doing image output this way avoids having to incorporate ----*/
448 /*---- external libraries, but means NETPBM needs to be present ----*/
449 /*------------------------------------------------------------------*/
450
ISQ_setup_ppmto_filters(void)451 void ISQ_setup_ppmto_filters(void)
452 {
453 char *pg , *pg2 , *str , *eee ;
454 int bv ;
455 int dbg ;
456 int ncant=0 , need_netpbm=0 ; /* 16 Nov 2004 */
457 int jpeg_compress;
458
459 ppmto_num = 0 ; bv = ISQ_SAV_PNM ;
460
461 dbg = AFNI_yesenv("AFNI_IMSAVE_DEBUG") ; /* 03 Sep 2004 */
462
463 /*-- path to open gimp [27 Oct 2017] --*/
464
465 pg = THD_find_executable( "gimp" ) ;
466 if( pg != NULL ) gimp_path = strdup(pg) ;
467 #ifdef DARWIN /* for MacosX, if in the App directory */
468 else if( THD_is_directory("/Applications/GIMP.app") )
469 gimp_path = strdup("open -a /Applications/GIMP.app") ;
470 else if( THD_is_directory("/Applications/MacPorts/GIMP.app") )
471 gimp_path = strdup("open -a /Applications/MacPorts/GIMP.app") ;
472 #endif
473
474 /*-- the cheap way to write PPM --*/
475 /*-- [this must always be first] --*/
476
477 pg = THD_find_executable( "cat" ) ; /* should always find this! */
478 if( pg != NULL ){
479 str = AFMALL( char, strlen(pg)+32) ;
480 sprintf(str,"%s > %%s",pg) ;
481 bv <<= 1 ; ADDTO_PPMTO(str,"ppm",bv,0) ;
482
483 /* 02 Aug 2001: also try for mpeg */
484
485 ppmto_ppm_filter = str ; /* save this filter string */
486
487 pg = THD_find_executable( "ffmpeg" ) ; /* ffmpeg replaces mpeg_encode [09 Dec 2019] */
488 if( pg != NULL ){
489 str = AFMALL( char, strlen(pg)+64) ;
490 sprintf(str,"%s %s",pg,FFMPEG_SUFFIX) ;
491 ppmto_mpeg_filter = str ;
492 if( dbg ) fprintf(stderr,"IMSAVE: animation filter '%s' for suffix '%s'\n",
493 str , "mpg" ) ;
494 }
495 else CANT_FIND("ffmpeg","MPEG-1") ;
496 }
497 else CANT_FIND("cat","PPM") ; /* this is the end of the world! */
498
499 /*-- write JPEG --*/
500
501 pg = THD_find_executable( "cjpeg" ) ;
502 if( pg != NULL ){
503 /* user environment variable compression quality - mod 5/10/2006 drg */
504 eee = my_getenv("AFNI_JPEG_COMPRESS");
505 if(eee!=NULL) {
506 jpeg_compress = (int) strtod(eee, NULL);
507 if((jpeg_compress<=5) || (jpeg_compress>100)) jpeg_compress = 95;
508 }
509 else jpeg_compress = 95;
510
511 #if 0
512 printf("\njpeg_compress %d\n", jpeg_compress);
513 #endif
514 str = AFMALL( char, strlen(pg)+32) ;
515 sprintf(str,"%s -quality %d > %%s",pg,jpeg_compress);
516 bv <<= 1 ; ADDTO_PPMTO(str,"jpg",bv,1) ;
517 ppmto_jpg95_filter = strdup(str) ; /* 28 Jul 2005 */
518
519 /* lower quality JPEGs */
520
521 ppmto_jpg75_filter = AFMALL( char, strlen(pg)+32);
522 sprintf(ppmto_jpg75_filter,"%s -quality 80 > %%s",pg) ;
523 }
524 else CANT_FIND("cjpeg","JPEG") ;
525
526 /*-- write GIF --*/
527
528 pg = THD_find_executable( "ppmtogif" ) ;
529 pg2 = THD_find_executable( "ppmquant" ) ;
530 if( pg2 == NULL ) pg2 = THD_find_executable( "pnmquant" ) ;
531 if( pg != NULL && pg2 != NULL ){
532 int adel=20 ; char asuff[64] ; /* 16 Jan 2003 */
533
534 str = AFMALL( char, strlen(pg)+strlen(pg2)+32) ;
535 sprintf(str,"%s 255 | %s > %%s",pg2,pg) ;
536 bv <<= 1 ; ADDTO_PPMTO(str,"gif",bv,0) ;
537
538 /*-- 27 Jul 2001: also try for Animated GIF --*/
539
540 ppmto_gif_filter = str ; /* save this filter string */
541
542 #ifdef USE_GIFF /* filter for Fixed GIF colormap */
543 str = AFMALL( char , strlen(pg)+128 ) ; /* 05 Oct 2004 */
544 sprintf(str,"%s -map %s > %%s",pg,GIFF_MAPFILE) ;
545 ppmto_giff_filter = str ;
546 #endif
547
548 /* 16 Jan 2003: get animated GIF delay (centiseconds) from environment */
549
550 eee = getenv( "AFNI_AGIF_DELAY" ) ;
551 if( eee != NULL ){ adel=(int)strtod(eee,NULL); if(adel < 2)adel=20; }
552
553 pg = THD_find_executable( "gifsicle" ) ; /* preferred */
554 if( pg != NULL ){
555 sprintf(asuff,GIFSICLE_SUFFIX,adel) ; /* 16 Jan 2003 */
556 str = AFMALL( char, strlen(pg)+64) ;
557 sprintf(str,"%s %s",pg,asuff) ;
558 ppmto_agif_filter = str ;
559 if( dbg ) fprintf(stderr,"IMSAVE: animation filter '%s' for suffix '%s'\n",
560 str , "gif" ) ;
561 } else {
562 pg = THD_find_executable( "whirlgif" ) ; /* but is OK */
563 if( pg != NULL ){
564 sprintf(asuff,WHIRLGIF_SUFFIX,adel) ; /* 16 Jan 2003 */
565 str = AFMALL( char, strlen(pg)+64) ;
566 sprintf(str,"%s %s",pg,asuff) ;
567 ppmto_agif_filter = str ;
568 if( dbg ) fprintf(stderr,"IMSAVE: animation filter '%s' for suffix '%s'\n",
569 str , "gif" ) ;
570 }
571 }
572 if( ppmto_agif_filter == NULL )
573 CANT_FIND("gifsicle OR whirlgif","Animated GIF") ;
574 }
575 else { CANT_FIND("ppmtogif AND/OR ppmquant","GIF"); need_netpbm++; }
576
577 /*-- write TIFF --*/
578
579 pg = THD_find_executable( "ppm2tiff" ) ;
580 if( pg != NULL ){
581 str = AFMALL( char, strlen(pg)+32) ;
582 sprintf(str,"%s -c none %%s",pg) ;
583 bv <<= 1 ; ADDTO_PPMTO(str,"tif",bv,1) ;
584 } else { /* 03 Jul 2001: */
585 pg = THD_find_executable( "pnmtotiff" ) ;
586 if( pg == NULL )
587 pg = THD_find_executable( "pamtotiff" ); /* must use ppm2tiff */
588 if( pg != NULL ){ /* and pnmtotiff */
589 str = AFMALL( char, strlen(pg)+32) ; /* differently */
590 sprintf(str,"%s > %%s",pg) ;
591 bv <<= 1 ; ADDTO_PPMTO(str,"tif",bv,1) ;
592 }
593 else { CANT_FIND("ppm2tiff OR pnmtotiff OR pamtotiff","TIFF"); need_netpbm++; }
594 }
595
596 /*-- write Windows BMP --*/
597
598 pg = THD_find_executable( "ppmtobmp" ) ;
599
600 if( AFNI_yesenv("AFNI_OLD_PPMTOBMP") ){ /* the old way: quantize */
601 pg2 = THD_find_executable( "ppmquant" ) ;
602 if( pg != NULL && pg2 != NULL ){
603 str = AFMALL( char, strlen(pg)+strlen(pg2)+32) ;
604 sprintf(str,"%s 255 | %s -windows > %%s",pg2,pg) ;
605 bv <<= 1 ; ADDTO_PPMTO(str,"bmp",bv,0) ;
606 }
607 else { CANT_FIND("ppmtobmp AND/OR ppmquant","BMP"); need_netpbm++; }
608 } else if( pg != NULL ){ /* 21 Feb 2003: don't quantize */
609 str = AFMALL( char, strlen(pg)+32) ;
610 sprintf(str,"%s -bpp 24 -windows > %%s",pg) ;
611 bv <<= 1 ; ADDTO_PPMTO(str,"bmp",bv,0) ;
612 }
613 else { CANT_FIND("ppmtobmp","BMP"); need_netpbm++; }
614
615 #if 0
616 /*-- write Encapsulated PostScript [removed 02 Mar 2021] --*/
617
618 pg = THD_find_executable( "pnmtops" ) ;
619 if( pg != NULL ){
620 str = AFMALL( char, strlen(pg)+32) ;
621 sprintf(str,"%s -noturn > %%s",pg) ;
622 bv <<= 1 ; ADDTO_PPMTO(str,"eps",bv,0) ;
623 }
624 #if 0
625 else { CANT_FIND("pnmtops","EPS"); need_netpbm++; }
626 #endif
627 #endif
628
629 #if 0
630 /*-- write a PDF file (God only knows why) --*/
631
632 pg2 = THD_find_executable( "epstopdf" ) ; /* 19 Oct 2001: */
633 if( pg != NULL && pg2 != NULL ){ /* check pg!=NULL */
634 str = AFMALL( char, strlen(pg)+strlen(pg2)+32) ;
635 sprintf(str,"%s -noturn | %s --filter > %%s",pg,pg2) ;
636 bv <<= 1 ; ADDTO_PPMTO(str,"pdf",bv,0) ;
637 }
638 else CANT_FIND("pnmtops AND/OR epstopdf","PDF") ;
639 #endif
640
641 /*-- Write a PNG file --*/
642
643 pg = THD_find_executable( "pnmtopng" ) ;
644 if( pg != NULL ){
645 str = AFMALL( char, strlen(pg)+32) ;
646 sprintf(str,"%s -compression 9 > %%s",pg) ;
647 bv <<= 1 ; ADDTO_PPMTO(str,"png",bv,1) ;
648 ppmto_png_filter = strdup(str) ; /* 07 Dec 2007 */
649 }
650 else { CANT_FIND("pnmtopng","PNG"); need_netpbm++; }
651
652 /*----- 16 Nov 2004: output more warnings? -----*/
653
654 if( !AFNI_noenv("AFNI_IMSAVE_WARNINGS") && ncant > 0 ){
655
656 if( need_netpbm > 0 ){ /* warnings for netpbm filters */
657 fprintf(stderr,"++\n") ;
658 fprintf(stderr,
659 "++ Some of the missing image Save programs are in\n"
660 "++ the netpbm software package, which is freeware.\n" ) ;
661 fprintf(stderr,"++\n") ;
662 #ifdef DARWIN
663 fprintf(stderr,
664 "++ Netpbm can be installed on MacOS X using one of these systems:\n"
665 "++ brew https://brew.sh/\n"
666 "++ fink https://www.finkproject.org/\n"
667 "++ ports https://www.macports.org/\n"
668 "++ brew is the system currently recommended at the AFNI Mac installation page\n"
669 "++ https://afni.nimh.nih.gov/pub/dist/doc/htmldoc/background_install/install_instructs/steps_mac.html\n"
670 ) ;
671 fprintf(stderr,"++\n") ;
672 #endif
673 }
674 /* warnings for all problems */
675 fprintf(stderr,
676 "++ To disable these warnings, set environment\n"
677 "++ variable AFNI_IMSAVE_WARNINGS to 'NO'.\n"
678 "+++++++++++++++++++++++++++++++++++++++++++++\n" ) ;
679 }
680
681 return ;
682 }
683
684 /*-------------------------------------------------------------------------
685 routine to create a new window for displaying an image sequence:
686
687 dc = pointer to a display context (MCW_DC)
688 (stores all the X11 stuff, like the Display *).
689
690 get_image = pointer to a routine that returns the images to be displayed.
691
692 - get_image(n,type,aux) should return a "MRI_IMAGE *" of the
693 n-th image for n=0,1,...,nim-1, where "type" is one
694 of isqCR_getimage (for the underlay image) or
695 isqCR_getoverlay (for the overlay image);
696
697 - get_image(n,isqCR_getstatus,aux) should return a
698 "MCW_imseq_status *" (n is ignored)
699
700 - get_image(n,isqCR_getmemplot,aux) should return a
701 "MEM_plotdata *" (see coxplot.h -- 21 Feb 2001);
702 NULL means no plot
703
704 - get_image(n,isqCR_getlabel,aux) should return a
705 "char *": a NUL-terminated string to be plotted
706 on top of the image; NULL means no label string
707
708 Thus, get_image takes as input 2 "int"s and an "XtPointer",
709 and returns a "XtPointer". Note that the MRI_IMAGEs returned
710 will be mri_free-d after being used internally. Therefore,
711 if you want to keep them, you should send a copy, not the
712 original. The same applies to the MCW_imseq_status struct,
713 the MEM_plotdata struct, and the char *.
714
715 aux = XtPointer supplied by user, pointing to data to be passed
716 get_image for its own internal use (similar in concept to
717 "client_data" for callbacks).
718 -------------------------------------------------------------------------*/
719
720 /*-- structure defining buttons in main window --*/
721
722 static const ISQ_bdef ISQ_but_bot_def[NBUTTON_BOT] = { /* label, callback */
723 { "Disp" , ISQ_but_disp_CB } ,
724 { "Save:bkg" , ISQ_but_save_CB } ,
725 { "Mont" , ISQ_montage_CB } ,
726 { "Done" , ISQ_but_done_CB }
727 } ;
728
729 static const RwcBoolean ISQ_but_bot_dial[NBUTTON_BOT] = { /* use seq->dialog? */
730 True , False , True , False
731 } ;
732
733 static char *ISQ_but_done_label1 = "Done" ;
734 static char *ISQ_but_done_label2 = "DONE" ;
735 #define NBUT_DONE (NBUTTON_BOT-1)
736 #define NBUT_SAVE 1
737 #define NBUT_DISP 0
738 #define NBUT_MONT 2
739
740 static char *ISQ_save_label_bg = "Save:bkg" ;
741 static char *ISQ_save_label_all = "Save:pnm" ;
742
743 #define SET_SAVE_LABEL(seq) \
744 do{ char sl[16] ; \
745 if( (seq)->opt.save_filter < 0 ){ \
746 strcpy(sl, (seq)->opt.save_pnm ? ISQ_save_label_all \
747 : ISQ_save_label_bg ); \
748 }else{ \
749 sprintf(sl,"Save.%.3s",ppmto_suffix[(seq)->opt.save_filter]) ; \
750 } \
751 if( (seq)->opt.save_agif ) strcpy(sl,"Sav:aGif") ; \
752 else if( (seq)->opt.save_mpeg ) strcpy(sl,"Sav:mpeg") ; \
753 else if( (seq)->opt.save_one ) sl[3] = '1' ; \
754 MCW_set_widget_label( (seq)->wbut_bot[NBUT_SAVE] , sl ) ; } while(0)
755
756 static const ISQ_bdef ISQ_but_rig_def[NBUTTON_RIG] = {
757 { "Colr" , ISQ_but_color_CB } ,
758 { "Swap" , ISQ_but_cswap_CB } ,
759 { "Norm" , ISQ_but_cnorm_CB }
760 } ;
761
762 /* popup help for these buttons */
763
764 static char * ISQ_but_bot_hint[NBUTTON_BOT] = {
765 "Extra image controls" ,
766 "Save images controls" ,
767 "Image montage controls" ,
768 "Close window"
769 } ;
770
771 static char * ISQ_but_bot_help[NBUTTON_BOT] = {
772 "Pops up a window with options\n"
773 "to control the image display\n"
774 "and how the Save button works" ,
775
776 "Will popup control panels to let you save images from this window.\n"
777 "The type of save operation is indicated on the button label, and\n"
778 "is selected from the 'Disp' button options window.\n"
779 " :bkg = Will save only the background image data values\n"
780 " (in a recorder window, the background image IS in color)\n"
781 " :pnm = Will save the actual displayed focus image in color (PNM format)\n"
782 "NOTES:\n"
783 " * Saved images will NOT be stretched to match window resizing.\n"
784 " * The PNM format requires the 'netpbm' package to be useful.\n"
785 " Alternatively, the 'xv' program will read/write PNM images." ,
786
787 "Will popup a control box to let you\n"
788 "display a montage of images, instead\n"
789 "of just one image at a time.\n\n"
790 "WARNING: this can be quite slow!" ,
791
792 "Closes this\n"
793 "viewing window"
794 } ;
795
796 static char * ISQ_but_rig_help[NBUTTON_RIG] = {
797 "Switches the colormap\nbetween False Color\nand Grayscale" ,
798 "Swaps the colormap\nend for end" ,
799 "Restores the colormap\nto its `normal' state"
800 } ;
801
802 static char * ISQ_but_rig_hint[NBUTTON_RIG] = {
803 "Switch between color and gray" ,
804 "Invert color/gray levels" ,
805 "Return color/gray scale to normal"
806 } ;
807
808 static char * ISQ_scale_help =
809 "Moves between images:\nDrag bar, or click in trough" ;
810
811 /* The next 2 helps will be overwritten by AFNI */
812
813 static char * ISQ_default_image_help = "This is the image!" ;
814
815 static char * ISQ_form_help =
816 "************************************************\n"
817 "* Image Sequence Display Module *\n"
818 "* *\n"
819 "* Released under the GPL (v2 or later) *\n"
820 "* *\n"
821 "* Author: Robert W Cox, PhD *\n"
822 "************************************************" ;
823
824 /*-- arrow definitions for widgets down the right side of viewer --*/
825
826 static char * ISQ_arrow_label[NARROW] = { "c" , "b" , "r" , "g" , "i" } ;
827
828 #define NARR_SQUEEZE 0 /* arrow action codes */
829 #define NARR_BRIGHT 1
830 #define NARR_ROTATE 2
831 #define NARR_GAMMA 3
832 #define NARR_FRAC 4
833
834 static char * ISQ_arrow_help[NARROW] = {
835 "Change constrast\nin colormap" ,
836 "Change brightness\nin colormap" ,
837 "Rotate\ncolormap" ,
838 "Alter\ndisplay\ngamma" ,
839 "Alter\nimage\nfraction\nin window"
840 } ;
841
842 static char * ISQ_arrow_hint[NARROW] = {
843 "Contrast" ,
844 "Brightness" ,
845 "Rotate" ,
846 "Gamma" ,
847 "Image fraction"
848 } ;
849
850 /*........................................................................*/
851
852 static int ISQ_anim_dup = 0 ;
ISQ_set_anim_dup(int ii)853 void ISQ_set_anim_dup( int ii ){ ISQ_anim_dup = ii ; }
854
855 /*........................................................................*/
856
857 #define DEFAULT_MINFRAC 0.02
858 #define DEFAULT_MAXFRAC 0.90
859
860 #define OPACITY_FAC 0.11111 /* 06-07 Mar 2001: overlay opacity stuff */
861 #define OPACITY_BOT 1
862 #define OPACITY_TOP 9
863
864 #define ZOOM_BOT 1 /* 11 Mar 2002: zoom controls */
865 #define ZOOM_TOP 4
866
open_MCW_imseq(MCW_DC * dc,get_ptr get_image,XtPointer aux)867 MCW_imseq * open_MCW_imseq( MCW_DC *dc ,
868 get_ptr get_image , XtPointer aux )
869 {
870 MCW_imseq *newseq ;
871 MCW_imseq_status *imstatus=NULL ;
872 int ii , xwide , yhigh , one_image ;
873 float fac ;
874 MRI_IMAGE *tim=NULL ;
875 float minfrac=DEFAULT_MINFRAC ; char *eee ; /* 27 Feb 2001 */
876 Widget wtemp ; /* 11 Mar 2002 */
877 float maxfrac=DEFAULT_MAXFRAC ; /* 13 Jun 2003 */
878
879 ENTRY("open_MCW_imseq") ;
880
881 #define ERREX { myXtFree(newseq) ; XBell(dc->display,100) ; RETURN(NULL) ; }
882
883 /*- 27 Jun 2001: setup filters for saving images -*/
884
885 if( ppmto_num < 0 ){
886 ISQ_setup_ppmto_filters() ; /* get filter program names */
887
888 if( ppmto_num > 0 ){ /* modify Save button box setup for Disp */
889
890 int nbut_old = ISQ_dispbb[NTOG_SAV].nbut , qq,pp ;
891 char ** lbut_old = ISQ_dispbb[NTOG_SAV].lbut ;
892 char ** help_old = ISQ_bb_allhelp[NTOG_SAV] ;
893 char ** hint_old = ISQ_bb_allhint[NTOG_SAV] ;
894
895 ISQ_dispbb[NTOG_SAV].nbut += ppmto_num ;
896 ISQ_dispbb[NTOG_SAV].lbut = (char **) malloc(sizeof(char *)
897 *ISQ_dispbb[NTOG_SAV].nbut);
898 for( qq=0 ; qq < nbut_old ; qq++ )
899 ISQ_dispbb[NTOG_SAV].lbut[qq] = lbut_old[qq] ;
900 for( pp=0 ; pp < ppmto_num ; pp++,qq++ ){
901 ISQ_dispbb[NTOG_SAV].lbut[qq] = AFMALL( char, 32) ;
902 sprintf(ISQ_dispbb[NTOG_SAV].lbut[qq] ,
903 "Save to .%.3s(s)" , ppmto_suffix[pp] ) ;
904 }
905
906 ISQ_bb_allhelp[NTOG_SAV] = (char **) malloc(sizeof(char *)
907 *ISQ_dispbb[NTOG_SAV].nbut);
908 ISQ_bb_allhint[NTOG_SAV] = (char **) malloc(sizeof(char *)
909 *ISQ_dispbb[NTOG_SAV].nbut);
910 for( qq=0 ; qq < nbut_old ; qq++ ){
911 ISQ_bb_allhelp[NTOG_SAV][qq] = help_old[qq] ;
912 ISQ_bb_allhint[NTOG_SAV][qq] = hint_old[qq] ;
913 }
914 for( pp=0 ; pp < ppmto_num ; pp++,qq++ )
915 ISQ_bb_allhelp[NTOG_SAV][qq] = ISQ_bb_allhint[NTOG_SAV][qq] = NULL ;
916 }
917 }
918
919 /* Creation ex nihilo! */
920
921 newseq = (MCW_imseq *) XtMalloc( sizeof(MCW_imseq) ) ; /* new structure */
922 memset(newseq, 0, sizeof(MCW_imseq));
923
924 newseq->dc = dc ; /* copy input pointers */
925 newseq->getim = get_image ;
926 newseq->getaux = aux ;
927
928 newseq->never_drawn = 1 ; /* used when viewer is first opened */
929
930 /*** The way the get_image function is called was changed
931 to use a macro that casts the arguments to the proper
932 types, to avoid bitter complaints from C++ compilers.
933 See Amalloc.h for these macros and other similar fixes. ***/
934
935 /* get the status of the images to be supplied */
936 #if 0
937 imstatus = (MCW_imseq_status *) get_image(0,isqCR_getstatus,aux) ;
938 #else
939 AFNI_CALL_VALU_3ARG( get_image , MCW_imseq_status *,imstatus ,
940 int,0 , int,isqCR_getstatus , XtPointer,aux ) ;
941 #endif
942 if( imstatus->num_total < 1 ){ ERREX ; } /* bad */
943 one_image = (imstatus->num_total == 1) ; /* special case */
944
945 /* get the first image, for sizing purposes */
946 #if 0
947 tim = (MRI_IMAGE *) get_image(0,isqCR_getqimage,aux) ; /* fake image */
948 #else
949 AFNI_CALL_VALU_3ARG( get_image , MRI_IMAGE *,tim ,
950 int,0 , int,isqCR_getqimage , XtPointer,aux ) ;
951 #endif
952
953 newseq->horig = tim->nx ; /* save original dimensions */
954 newseq->vorig = tim->ny ;
955
956 newseq->last_width_mm = IM_WIDTH(tim) ; /* dimensions in real space */
957 newseq->last_height_mm = IM_HEIGHT(tim) ;
958
959 newseq->last_dx = newseq->last_dy = 1.0 ; /* 08 Jun 2004 */
960
961 newseq->cropit = 0 ; /* Cropping stuff - 11 Jun 2002 */
962 newseq->crop_allowed = 1 ;
963 newseq->crop_nxorg = newseq->crop_nyorg = -1 ;
964 newseq->crop_autocenter = AFNI_yesenv("AFNI_CROP_AUTOCENTER") ;
965
966 fac = (newseq->last_width_mm / newseq->horig) /* width per pixel over */
967 /(newseq->last_height_mm / newseq->vorig) ; /* height per pixel */
968
969 if( fac >= 1.0 ){ /* initial display size */
970 xwide = newseq->horig * fac + 0.49 ;
971 yhigh = newseq->vorig ;
972 } else {
973 xwide = newseq->horig ;
974 yhigh = newseq->vorig / fac + 0.49 ;
975 }
976
977 if( PRINT_TRACING ){
978 char str[256] ;
979 sprintf(str,"nx=%d ny=%d dx=%f dy=%f wid=%f hei=%f xwide=%d yhigh=%d",
980 tim->nx,tim->ny,tim->dx,tim->dy,newseq->last_width_mm,
981 newseq->last_height_mm , xwide,yhigh ) ;
982 STATUS(str);
983 }
984
985 KILL_1MRI(tim) ; /* don't need tim no more */
986
987 newseq->hbase = newseq->hactual =
988 newseq->old_hact = xwide ; /* store display sizes */
989
990 newseq->vbase = newseq->vactual =
991 newseq->old_vact = yhigh ;
992
993 newseq->status = imstatus ;
994 newseq->im_nr = imstatus->num_total / 2 ; /* do middle image 1st */
995 newseq->scl = 0.0 ; /* autoscaling */
996 newseq->lev = dc->ncol_im-1 ; /* to range 0..ncol_im-1 */
997 newseq->bot = 0 ;
998 newseq->top = dc->ncol_im-1 ;
999
1000 newseq->clbot = newseq->cltop = 0.0f ; /* 29 Jul 2001 */
1001 newseq->barbot = newseq->bartop = 0.0f ;
1002
1003 /* color curve correction parameters */
1004 newseq->rgb_gamma = 1.0 ; /* 25 Apr 2005 */
1005 newseq->rgb_offset = 0.0 ;
1006
1007 strcpy( newseq->im_label , "hi bob" ) ;
1008 newseq->scl_label[0] = '\0' ;
1009 newseq->overlay_label = NULL ;
1010
1011 /* set display processing options */
1012
1013 ISQ_DEFAULT_OPT(newseq->opt) ; /* 09 Oct 1998: macro replaces explicit code */
1014 if( ppmto_num > 0 ) newseq->opt.save_filter = 0 ; /* 26 Mar 2002 */
1015 newseq->opt.parent = (XtPointer) newseq ;
1016 newseq->old_opt = newseq->opt ; /* backup copy */
1017
1018 newseq->last_image_type = -1 ; /* not a legal datum type */
1019
1020 newseq->dialog = NULL ; /* no dialog at present */
1021 newseq->num_bbox = 0 ; /* dialog = Disp, etc */
1022 newseq->dialog_starter = -1 ;
1023 newseq->dont_place_dialog = 0 ; /* 23 Jan 2004 */
1024
1025 newseq->imim = newseq->ovim = NULL ; /* NULL out all stored images */
1026
1027 newseq->orim = NULL ; /* original image - 30 Dec 1998 */
1028 newseq->set_orim = 0 ;
1029 newseq->need_orim = 0 ;
1030
1031 newseq->last_automask = NULL ; /* 12 Dec 2014 */
1032
1033 newseq->saver_blowup = 1 ; /* image save blowup factor */
1034
1035 newseq->given_xim = newseq->sized_xim /* XImages for actual drawing */
1036 = newseq->given_xbar /* saved for re-use when possible */
1037 = newseq->sized_xbar = NULL ;
1038
1039 /* Feb 1998: button2 drawing stuff [enabled/used by Draw Dataset plugin] */
1040
1041 newseq->button2_enabled = 0 ;
1042 newseq->button2_active = 0 ;
1043 newseq->button2_pixel = dc->ovc->pixov_greenest ;
1044 newseq->button2_drawmode = BUTTON2_OPENPOLY ;
1045 newseq->button2_width = 0 ; /* 08 Oct 2002 */
1046 newseq->wimage_width = -1 ;
1047 newseq->wimage_height = -1 ;
1048
1049 newseq->cursor_state = CURSOR_NORMAL ; /* 10 Mar 2003 */
1050
1051 /* initialize image statistics */
1052
1053 newseq->imstat = (ISQ_indiv_statistics *)
1054 XtMalloc( sizeof(ISQ_indiv_statistics)
1055 * imstatus->num_total ) ;
1056
1057 /* the global statistics are no longer used */
1058
1059 newseq->glstat = (ISQ_glob_statistics * )
1060 XtMalloc( sizeof(ISQ_glob_statistics) ) ;
1061
1062 for( ii=0 ; ii < imstatus->num_total ; ii++ ){
1063 newseq->imstat[ii].one_done = newseq->imstat[ii].glob_done = False ;
1064 newseq->imstat[ii].parent = (XtPointer) newseq ;
1065 }
1066
1067 newseq->glstat->parent = (XtPointer) newseq ;
1068
1069 for( ii=0 ; ii < NHISTOG ; ii++ )
1070 newseq->glstat->hist[ii] = 0 ; /* initialize */
1071
1072 newseq->glstat->mm_done =
1073 newseq->glstat->per_done = (newseq->status->num_series < 2 ) ;
1074
1075 #ifdef AUTOMATE_STATISTICS
1076 if( newseq->glstat->mm_done ){
1077 newseq->glstat->worker = 0 ;
1078 } else {
1079 newseq->glstat->worker = XtAppAddWorkProc(
1080 newseq->dc->appcontext ,
1081 ISQ_statistics_WP , newseq ) ;
1082 }
1083 #else
1084 newseq->glstat->worker = 0 ;
1085 #endif
1086
1087 /***--------- create widgets ---------- ***/
1088
1089 newseq->image_frac = IMAGE_FRAC ; /* 25 Oct 1996 */
1090
1091 /** 27 Feb 2001: set minimum size for image windows,
1092 as a fraction of the overall screen area **/
1093
1094 eee = my_getenv("AFNI_IMAGE_MINFRAC") ;
1095 if( eee != NULL ){
1096 float fff=0.0 ;
1097 ii = sscanf(eee,"%f",&fff) ;
1098 if( ii > 0 && fff > 0.0 && fff <= 0.9 ) minfrac = fff ;
1099 else minfrac = DEFAULT_MINFRAC ;
1100 }
1101
1102 eee = my_getenv("AFNI_IMAGE_MAXFRAC") ;
1103 if( eee != NULL ){
1104 float fff=0.0 ;
1105 ii = sscanf(eee,"%f",&fff) ;
1106 if( ii > 0 && fff > 0.0 && fff <= 1.0 ) maxfrac = fff ;
1107 else maxfrac = DEFAULT_MAXFRAC ;
1108 }
1109
1110 { float xxx = newseq->hactual , yyy = newseq->vactual ;
1111 float fff = (xxx*yyy)/(dc->width*dc->height) , ggg ;
1112
1113 /* modify if window too small for display */
1114
1115 if( fff < minfrac ){
1116 fff = sqrt(minfrac/fff); xxx *= fff; yyy *= fff; /* expand area */
1117 }
1118
1119 /* modify if window too big for display */
1120
1121 fff = ggg = 1.0 ;
1122 if( xxx >= maxfrac*dc->width ) fff = maxfrac*dc->width / xxx; /* don't let */
1123 if( yyy >= maxfrac*dc->height) ggg = maxfrac*dc->height/ yyy; /* be too big */
1124 fff = MIN(fff,ggg) ; xxx *= fff ; yyy *= fff ;
1125 if( xxx < 1.0 || yyy < 1.0 ){ /* weird result?? */
1126 xxx = newseq->hactual ; yyy = newseq->vactual; /* back to old way */
1127 }
1128 xwide = (int) ( 0.49 + xxx / IMAGE_FRAC ) ;
1129 yhigh = (int) ( 0.49 + yyy / IMAGE_FRAC ) ;
1130
1131 fff = ggg = 1.0 ;
1132 if( xwide >= maxfrac*dc->width ) fff = maxfrac*dc->width / xwide; /* don't let */
1133 if( yhigh >= maxfrac*dc->height) ggg = maxfrac*dc->height/ yhigh; /* be too big */
1134 fff = MIN(fff,ggg) ; xwide *= fff ; yhigh *= fff ;
1135 }
1136
1137 /* toggles for widget controls on or off */
1138
1139 newseq->onoff_num = 0 ;
1140 newseq->onoff_state = 1 ; /* initially are on */
1141
1142 /* top level shell to hold all */
1143
1144 newseq->wtop =
1145 XtVaAppCreateShell(
1146 "AFNI" , "AFNI" ,
1147 topLevelShellWidgetClass , dc->display ,
1148
1149 XmNminAspectX , xwide , /* fix aspect ratio! */
1150 XmNminAspectY , yhigh ,
1151 XmNmaxAspectX , xwide ,
1152 XmNmaxAspectY , yhigh ,
1153
1154 XmNmaxWidth , dc->width , /* not bigger than the screen! */
1155 XmNmaxHeight , dc->height ,
1156
1157 XmNdeleteResponse , XmDO_NOTHING , /* deletion handled below */
1158
1159 XmNallowShellResize , False , /* let code resize shell */
1160
1161
1162 XmNinitialResourcesPersistent , False ,
1163 NULL ) ;
1164
1165 DC_yokify( newseq->wtop , dc ) ; /* 14 Sep 1998 */
1166
1167 #if 1
1168 if( MCW_isitmwm( newseq->wtop ) )
1169 XtVaSetValues( newseq->wtop ,
1170 XmNmwmDecorations , MWM_DECOR_ALL | MWM_DECOR_MAXIMIZE ,
1171 NULL ) ;
1172 #endif
1173
1174 XmAddWMProtocolCallback( /* make "Close" window menu work */
1175 newseq->wtop ,
1176 XmInternAtom( dc->display , "WM_DELETE_WINDOW" , False ) ,
1177 ISQ_but_done_CB , newseq ) ;
1178
1179 newseq->done_first = True ; /* for the first press of "Done" */
1180
1181 /* form to attach all contents to */
1182
1183 newseq->wform =
1184 XtVaCreateWidget(
1185 "imseq" , xmFormWidgetClass , newseq->wtop ,
1186
1187 XmNwidth , xwide , /* initial size */
1188 XmNheight , yhigh ,
1189
1190 XmNborderWidth , 0 ,
1191
1192 XmNfractionBase , FORM_FRAC_BASE ,
1193
1194 XmNhorizontalSpacing , 0 , /* 17 Jun 2002 */
1195 XmNverticalSpacing , 0 ,
1196
1197 XmNtraversalOn , False ,
1198 XmNinitialResourcesPersistent , False ,
1199 NULL ) ;
1200
1201 MCW_register_help( newseq->wform , ISQ_form_help ) ;
1202
1203 #define METER_HEIGHT 10
1204 newseq->render_scal = /* will be hidden later */
1205 XtVaCreateManagedWidget(
1206 "menu" , xmScaleWidgetClass , newseq->wform ,
1207 XmNminimum , 0 ,
1208 XmNmaximum , 100 ,
1209 XmNscaleMultiple , 1 ,
1210 XmNshowValue , True ,
1211 XmNvalue , 50 ,
1212 XmNorientation , XmHORIZONTAL ,
1213 /** XmNscaleWidth , wid , **/
1214 XmNscaleHeight , METER_HEIGHT ,
1215 XmNborderWidth , 0 ,
1216 XmNhighlightThickness , 0 ,
1217 XmNshadowThickness , 0 ,
1218 XmNtraversalOn , True ,
1219 XmNinitialResourcesPersistent , False ,
1220 XmNtopAttachment , XmATTACH_FORM ,
1221 XmNleftAttachment , XmATTACH_FORM ,
1222 XmNrightAttachment , XmATTACH_FORM ,
1223 NULL ) ;
1224 XtAddCallback( newseq->render_scal , XmNvalueChangedCallback ,
1225 ISQ_render_scal_CB , newseq ) ;
1226 XtAddCallback( newseq->render_scal , XmNdragCallback ,
1227 ISQ_render_scal_CB , newseq ) ;
1228
1229 /* drawing area for image space */
1230
1231 newseq->wimage =
1232 XtVaCreateManagedWidget(
1233 "imseq" , xmDrawingAreaWidgetClass , newseq->wform ,
1234
1235 XmNtopAttachment , XmATTACH_FORM ,
1236 XmNleftAttachment , XmATTACH_FORM ,
1237 XmNrightAttachment , XmATTACH_POSITION ,
1238 XmNrightPosition , (int)( 0.49 + IMAGE_FRAC * FORM_FRAC_BASE ) ,
1239 XmNbottomAttachment , XmATTACH_POSITION ,
1240 XmNbottomPosition , (int)( 0.49 + IMAGE_FRAC * FORM_FRAC_BASE ) ,
1241
1242 XmNtraversalOn , False ,
1243 XmNinitialResourcesPersistent , False ,
1244 NULL ) ;
1245
1246 XtInsertEventHandler( newseq->wimage , /* handle events in image */
1247
1248 0
1249 | KeyPressMask /* get keystrokes */
1250 | ButtonPressMask /* button presses */
1251 | ExposureMask /* exposures */
1252 | StructureNotifyMask /* resizes (Configure events) */
1253 | Button1MotionMask /* motion while #1 is down */
1254 | ButtonReleaseMask /* button releases */
1255 ,
1256 FALSE , /* nonmaskable events? */
1257 ISQ_drawing_EV , /* super-handler! */
1258 (XtPointer) newseq , /* client data */
1259 XtListTail ) ; /* last in queue */
1260
1261 strcpy( newseq->im_helptext , ISQ_default_image_help ) ;
1262 newseq->im_helptext[ISQ_NHELP] = '\0' ;
1263
1264 MCW_register_help( newseq->wimage , newseq->im_helptext ) ;
1265
1266 /* all pushbuttons (these are next so they overlay the scale and bar) */
1267
1268 for( ii=0 ; ii < NBUTTON_BOT ; ii++){
1269
1270 Arg wa[30] ;
1271 int na ;
1272
1273 na = 0 ;
1274
1275 XtSetArg( wa[na] , XmNmarginWidth , 1 ) ; na++ ;
1276 XtSetArg( wa[na] , XmNmarginHeight , 0 ) ; na++ ;
1277 XtSetArg( wa[na] , XmNmarginBottom , 0 ) ; na++ ;
1278 XtSetArg( wa[na] , XmNmarginTop , 0 ) ; na++ ;
1279 XtSetArg( wa[na] , XmNmarginLeft , 0 ) ; na++ ;
1280 XtSetArg( wa[na] , XmNmarginRight , 0 ) ; na++ ;
1281 XtSetArg( wa[na] , XmNtraversalOn , False ) ; na++ ;
1282 XtSetArg( wa[na] , XmNrecomputeSize , False ) ; na++ ;
1283
1284 XtSetArg( wa[na] , XmNinitialResourcesPersistent , False ) ; na++ ;
1285
1286 /* attach all buttons to edge of form */
1287
1288 XtSetArg( wa[na] , EDGING_BOT , XmATTACH_FORM ) ; na++ ;
1289
1290 if( ii == 0 ){ /* attach 1st button to leading edge of form */
1291
1292 XtSetArg( wa[na] , LEADING_BOT , XmATTACH_FORM ) ; na++ ;
1293
1294 } else if( ii == NBUTTON_BOT-1 ){ /* last button */
1295
1296 XtSetArg(wa[na],LEADING_BOT ,XmATTACH_WIDGET) ; na++ ;
1297 XtSetArg(wa[na],LEADING_WIDGET_BOT,newseq->wbut_bot[ii-1]) ; na++ ;
1298
1299 } else { /* other buttons to the widget to their LEADING edge */
1300
1301 XtSetArg(wa[na],LEADING_BOT ,XmATTACH_WIDGET ) ; na++ ;
1302 XtSetArg(wa[na],LEADING_WIDGET_BOT,newseq->wbut_bot[ii-1] ); na++ ;
1303 }
1304
1305 newseq->onoff_widgets[(newseq->onoff_num)++] =
1306 newseq->wbut_bot[ii] =
1307 XtCreateManagedWidget(
1308 ISQ_but_bot_def[ii].name ,
1309 xmPushButtonWidgetClass , newseq->wform ,
1310 wa , na ) ;
1311
1312 XtAddCallback( newseq->wbut_bot[ii] , XmNactivateCallback ,
1313 ISQ_but_bot_def[ii].func_CB , newseq ) ;
1314
1315 MCW_register_help( newseq->wbut_bot[ii] , ISQ_but_bot_help[ii] ) ;
1316 MCW_register_hint( newseq->wbut_bot[ii] , ISQ_but_bot_hint[ii] ) ;
1317
1318 } /* end of loop over bottom buttons */
1319 SET_SAVE_LABEL(newseq) ;
1320
1321 MCW_set_widget_bg( newseq->wbut_bot[NBUT_DONE] ,
1322 MCW_hotcolor(newseq->wbut_bot[0]) , 0 ) ;
1323
1324 /* 27 Jun 2001: popup menu for Save: button */
1325
1326 if( ppmto_num > 0 )
1327 XtInsertEventHandler( newseq->wbut_bot[NBUT_SAVE] ,
1328 ButtonPressMask , /* button presses */
1329 FALSE , /* nonmaskable events? */
1330 ISQ_butsave_EV , /* handler */
1331 (XtPointer) newseq , /* client data */
1332 XtListTail /* last in queue */
1333 ) ;
1334
1335 /* 17 Jun 2011: Button3 actions for Disp button */
1336
1337 XtInsertEventHandler( newseq->wbut_bot[NBUT_DISP] ,
1338 ButtonPressMask , /* button presses */
1339 FALSE , /* nonmaskable events? */
1340 ISQ_butdisp_EV , /* handler */
1341 (XtPointer) newseq , /* client data */
1342 XtListTail /* last in queue */
1343 ) ;
1344
1345 /* 24 Apr 2001: initialize recording stuff */
1346
1347 ISQ_record_button( newseq ) ;
1348
1349 /* buttons on right */
1350
1351 STATUS("creating buttons on right") ;
1352 for( ii=0 ; ii < NBUTTON_RIG ; ii++){
1353
1354 Arg wa[30] ;
1355 int na ;
1356
1357 na = 0 ;
1358
1359 XtSetArg( wa[na] , XmNmarginWidth , 1 ) ; na++ ;
1360 XtSetArg( wa[na] , XmNmarginHeight , 0 ) ; na++ ;
1361 XtSetArg( wa[na] , XmNmarginBottom , 0 ) ; na++ ;
1362 XtSetArg( wa[na] , XmNmarginTop , 0 ) ; na++ ;
1363 XtSetArg( wa[na] , XmNmarginLeft , 0 ) ; na++ ;
1364 XtSetArg( wa[na] , XmNmarginRight , 0 ) ; na++ ;
1365 XtSetArg( wa[na] , XmNtraversalOn , False ) ; na++ ;
1366 XtSetArg( wa[na] , XmNrecomputeSize , False ) ; na++ ;
1367
1368 XtSetArg( wa[na] , XmNinitialResourcesPersistent , False ) ; na++ ;
1369
1370 /* attach all buttons to edge of form */
1371
1372 XtSetArg( wa[na] , EDGING_RIG , XmATTACH_FORM ) ; na++ ;
1373
1374 if( ii == 0 ){ /* attach 1st button to leading edge of form */
1375
1376 XtSetArg( wa[na] , LEADING_RIG , XmATTACH_FORM ) ; na++ ;
1377
1378 } else { /* other buttons to the widget to their LEADING edge */
1379
1380 XtSetArg(wa[na],LEADING_RIG ,XmATTACH_WIDGET ); na++ ;
1381 XtSetArg(wa[na],LEADING_WIDGET_RIG,newseq->wbut_rig[ii-1] ); na++ ;
1382 }
1383
1384 newseq->onoff_widgets[(newseq->onoff_num)++] =
1385 newseq->wbut_rig[ii] =
1386 XtCreateManagedWidget(
1387 ISQ_but_rig_def[ii].name ,
1388 xmPushButtonWidgetClass , newseq->wform ,
1389 wa , na ) ;
1390
1391 XtAddCallback( newseq->wbut_rig[ii] , XmNactivateCallback ,
1392 ISQ_but_rig_def[ii].func_CB , newseq ) ;
1393
1394 MCW_register_help( newseq->wbut_rig[ii] , ISQ_but_rig_help[ii] ) ;
1395 MCW_register_hint( newseq->wbut_rig[ii] , ISQ_but_rig_hint[ii] ) ;
1396 }
1397
1398 /* arrows on right */
1399
1400 STATUS("creating arrows on right") ;
1401 for( ii=0 ; ii < NARROW ; ii++ ){
1402
1403 newseq->arrow[ii] = new_MCW_arrowval(
1404 newseq->wform , ISQ_arrow_label[ii] ,
1405 MCW_AV_downup , 0,0,0 ,
1406 MCW_AV_notext , 0 ,
1407 ISQ_arrow_CB , (XtPointer) newseq ,
1408 NULL,NULL ) ;
1409
1410 newseq->onoff_widgets[(newseq->onoff_num)++] = newseq->arrow[ii]->wrowcol ;
1411
1412 XtVaSetValues( newseq->arrow[ii]->wrowcol ,
1413 EDGING_RIG , XmATTACH_FORM ,
1414 LEADING_RIG , XmATTACH_WIDGET ,
1415
1416 LEADING_WIDGET_RIG ,
1417 (ii==0) ? (newseq->wbut_rig[NBUTTON_RIG-1])
1418 : (newseq->arrow[ii-1]->wrowcol) ,
1419 NULL ) ;
1420
1421 if( ii != NARR_FRAC )
1422 newseq->arrow[ii]->fastdelay = 10 ; /* fast */
1423 newseq->arrow[ii]->parent = (XtPointer) newseq ; /* set parent */
1424
1425 MCW_reghelp_children( newseq->arrow[ii]->wrowcol, ISQ_arrow_help[ii] );
1426 MCW_reghint_children( newseq->arrow[ii]->wrowcol, ISQ_arrow_hint[ii] );
1427 }
1428
1429 /** 07 Mar 2001 - add opacity control for overlay, maybe **/
1430
1431 wtemp = newseq->arrow[NARROW-1]->wrowcol ; /* 11 Mar 2002 */
1432
1433 newseq->ov_opacity = 1.0 ; /* 06 Mar 2001 */
1434
1435 if( newseq->dc->visual_class == TrueColor ){
1436 int iov = (int)rint(newseq->ov_opacity/OPACITY_FAC) ;
1437 char *buf = ISQ_opacity_label(iov) ;
1438
1439 /** 08 Mar 2001 - put a line between the arrows above and this control **/
1440
1441 STATUS("creating opacity control") ;
1442 newseq->ov_opacity_sep = XtVaCreateManagedWidget(
1443 "imseq" , xmSeparatorWidgetClass , newseq->wform ,
1444 XmNseparatorType , XmSINGLE_LINE ,
1445 EDGING_RIG , XmATTACH_FORM ,
1446 LEADING_RIG , XmATTACH_WIDGET ,
1447 LEADING_WIDGET_RIG , wtemp ,
1448 XmNleftAttachment , XmATTACH_OPPOSITE_WIDGET ,
1449 XmNleftWidget , wtemp ,
1450 XmNleftOffset , 7 ,
1451 NULL ) ;
1452 newseq->onoff_widgets[(newseq->onoff_num)++] = newseq->ov_opacity_sep ;
1453
1454 newseq->ov_opacity_av = new_MCW_arrowval(
1455 newseq->wform , /* parent */
1456 buf , /* label */
1457 MCW_AV_downup , /* direction */
1458 OPACITY_BOT , /* min */
1459 OPACITY_TOP , /* max */
1460 iov , /* init */
1461 MCW_AV_notext , /* type */
1462 0 , /* decim */
1463 ISQ_opacity_CB , /* action CB */
1464 (XtPointer) newseq , /* and its data */
1465 NULL , /* text maker */
1466 NULL /* and its data */
1467 ) ;
1468
1469 newseq->ov_opacity_av->parent = (XtPointer) newseq ;
1470 newseq->onoff_widgets[(newseq->onoff_num)++] = newseq->ov_opacity_av->wrowcol ;
1471
1472 XtVaSetValues( newseq->ov_opacity_av->wrowcol ,
1473 EDGING_RIG , XmATTACH_FORM ,
1474 LEADING_RIG , XmATTACH_WIDGET ,
1475 LEADING_WIDGET_RIG , newseq->ov_opacity_sep ,
1476 NULL ) ;
1477
1478 wtemp = newseq->ov_opacity_av->wrowcol ; /* 11 Mar 2002 */
1479
1480 MCW_reghelp_children( newseq->ov_opacity_av->wrowcol,
1481 "Controls the opacity\n"
1482 "of the color overlay:\n"
1483 " 1 = barely visible \n"
1484 " 9 = totally opaque" ) ;
1485 MCW_reghint_children( newseq->ov_opacity_av->wrowcol, "Color overlay opacity" );
1486
1487 } else {
1488 newseq->ov_opacity_av = NULL ;
1489 newseq->ov_opacity_sep = NULL ;
1490 }
1491
1492 STATUS("creating zoom control") ;
1493 newseq->zoom_sep = XtVaCreateManagedWidget(
1494 "imseq" , xmSeparatorWidgetClass , newseq->wform ,
1495 XmNseparatorType , XmSINGLE_LINE ,
1496 EDGING_RIG , XmATTACH_FORM ,
1497 LEADING_RIG , XmATTACH_WIDGET ,
1498 LEADING_WIDGET_RIG , wtemp ,
1499 XmNleftAttachment , XmATTACH_OPPOSITE_WIDGET ,
1500 XmNleftWidget , wtemp ,
1501 XmNleftOffset , 7 ,
1502 NULL ) ;
1503 newseq->onoff_widgets[(newseq->onoff_num)++] = newseq->zoom_sep ;
1504
1505 newseq->zoom_val_av = new_MCW_arrowval(
1506 newseq->wform , /* parent */
1507 "z" , /* label */
1508 MCW_AV_downup , /* direction */
1509 ZOOM_BOT , /* min */
1510 ZOOM_TOP , /* max */
1511 ZOOM_BOT , /* init */
1512 MCW_AV_notext , /* type */
1513 0 , /* decim */
1514 ISQ_zoom_av_CB , /* action CB */
1515 (XtPointer) newseq , /* and its data */
1516 NULL , /* text maker */
1517 NULL /* and its data */
1518 ) ;
1519 newseq->zoom_val_av->parent = (XtPointer) newseq ;
1520 newseq->onoff_widgets[(newseq->onoff_num)++] = newseq->zoom_val_av->wrowcol ;
1521 XtVaSetValues( newseq->zoom_val_av->wrowcol ,
1522 EDGING_RIG , XmATTACH_FORM ,
1523 LEADING_RIG , XmATTACH_WIDGET ,
1524 LEADING_WIDGET_RIG , newseq->zoom_sep ,
1525 NULL ) ;
1526 MCW_reghelp_children( newseq->zoom_val_av->wrowcol,
1527 "- Images can be zoomed in by\n"
1528 " a factor of 2, 3, or 4.\n"
1529 "- These 'Z' buttons change\n"
1530 " the zoom factor up and down.\n"
1531 "- Panning the zoomed image is\n"
1532 " done by pressing the 'pan'\n"
1533 " button and then clicking and\n"
1534 " dragging with Button #1 down\n\n"
1535 "**WARNING: zooming in by 4 can\n"
1536 " consume so much memory that\n"
1537 " AFNI or the X11 server will\n"
1538 " crash. If this happens, then\n"
1539 " avoid zooming that much (duh).\n" ) ;
1540 MCW_reghint_children( newseq->zoom_val_av->wrowcol, "Image zoom factor" );
1541 AV_SENSITIZE_DOWN( newseq->zoom_val_av , False ) ;
1542
1543 STATUS("creating pan control") ;
1544 newseq->zoom_drag_pb =
1545 XtVaCreateManagedWidget(
1546 "imseq" , xmPushButtonWidgetClass , newseq->wform ,
1547 LABEL_ARG("pan") ,
1548 XmNmarginWidth , 1 ,
1549 XmNmarginHeight , 0 ,
1550 XmNmarginBottom , 0 ,
1551 XmNmarginTop , 0 ,
1552 XmNmarginLeft , 0 ,
1553 XmNmarginRight , 0 ,
1554 XmNtraversalOn , False ,
1555 XmNinitialResourcesPersistent , False ,
1556 NULL ) ;
1557 XtAddCallback( newseq->zoom_drag_pb , XmNactivateCallback ,
1558 ISQ_zoom_pb_CB , newseq ) ;
1559
1560 newseq->onoff_widgets[(newseq->onoff_num)++] = newseq->zoom_drag_pb ;
1561
1562 XtVaSetValues( newseq->zoom_drag_pb ,
1563 EDGING_RIG , XmATTACH_FORM ,
1564 LEADING_RIG , XmATTACH_WIDGET ,
1565 LEADING_WIDGET_RIG , newseq->zoom_val_av->wrowcol ,
1566 NULL ) ;
1567
1568 MCW_register_help( newseq->zoom_drag_pb ,
1569 "To pan the zoomed image window:\n"
1570 "- Click on this 'pan' button\n"
1571 "- Then drag the image with mouse\n"
1572 " Button #1 (the cursor in the\n"
1573 " image window will be hand-shaped)\n"
1574 "- When you finish dragging, panning\n"
1575 " mode will be turned off\n"
1576 "- If you want panning mode to stay\n"
1577 " turned on until you click 'pan'\n"
1578 " again, set environment variable\n"
1579 " AFNI_KEEP_PANNING to YES" ) ;
1580 MCW_register_hint( newseq->zoom_drag_pb ,
1581 "Pan zoomed image" );
1582
1583 SENSITIZE( newseq->zoom_drag_pb , 0 ) ;
1584
1585 wtemp = newseq->zoom_drag_pb ;
1586
1587 newseq->zoom_fac = 1 ; /* initialize data for zooming */
1588 newseq->zoom_hor_off = 0.0 ;
1589 newseq->zoom_ver_off = 0.0 ;
1590 newseq->zoom_pixmap = (Pixmap) 0 ;
1591 newseq->zoom_pw = 0 ;
1592 newseq->zoom_ph = 0 ;
1593 newseq->zoom_xim = NULL ;
1594 newseq->zoom_button1 = 0 ; /* 15 Mar 2002 */
1595
1596 /* 17 Jun 2002: crop pushbutton */
1597
1598 STATUS("creating crop control") ;
1599 newseq->crop_drag_pb =
1600 XtVaCreateManagedWidget(
1601 "imseq" , xmPushButtonWidgetClass , newseq->wform ,
1602 LABEL_ARG("crop") ,
1603 XmNmarginWidth , 1 ,
1604 XmNmarginHeight , 0 ,
1605 XmNmarginBottom , 0 ,
1606 XmNmarginTop , 0 ,
1607 XmNmarginLeft , 0 ,
1608 XmNmarginRight , 0 ,
1609 XmNtraversalOn , False ,
1610 XmNinitialResourcesPersistent , False ,
1611 NULL ) ;
1612 XtAddCallback( newseq->crop_drag_pb , XmNactivateCallback ,
1613 ISQ_crop_pb_CB , newseq ) ;
1614 newseq->crop_drag = 0 ;
1615
1616 newseq->onoff_widgets[(newseq->onoff_num)++] = newseq->crop_drag_pb ;
1617
1618 XtVaSetValues( newseq->crop_drag_pb ,
1619 EDGING_RIG , XmATTACH_FORM ,
1620 LEADING_RIG , XmATTACH_WIDGET ,
1621 LEADING_WIDGET_RIG , wtemp ,
1622 NULL ) ;
1623
1624 MCW_register_help( newseq->crop_drag_pb ,
1625 "To crop the image window:\n"
1626 "- Click on the 'crop' button;\n"
1627 "- Then click and hold down mouse Button #1\n"
1628 " at a corner of the rectangle to crop;\n"
1629 "- Then drag a rectangle to set the crop size,\n"
1630 " and then release the mouse button.\n"
1631 "\n"
1632 "To uncrop (back to original image size):\n"
1633 "- Click on the 'crop' button;\n"
1634 "- Click on it again without cropping.\n"
1635 "\n"
1636 "* Another way to crop without using the 'crop'\n"
1637 " button is to drag the crop rectangle using\n"
1638 " Shift+Button #2.\n"
1639 "\n"
1640 "* Another way to uncrop is to click Shift+Button #2\n"
1641 " in the image without any dragging.\n"
1642 "\n"
1643 "* Button #3 (right-click) on the 'crop' pushbutton\n"
1644 " will popup a menu that lets you set the crop\n"
1645 " rectangle size exactly.\n"
1646 "\n"
1647 "* Scroll the crop region using Shift+keyboard arrows.\n"
1648 "* Resize the crop region using Ctrl+keyboard arrows."
1649 ) ;
1650 MCW_register_hint( newseq->crop_drag_pb , "Crop image" );
1651
1652 XtInsertEventHandler( newseq->crop_drag_pb ,
1653 ButtonPressMask , /* button presses */
1654 FALSE , /* nonmaskable events? */
1655 ISQ_butcrop_EV , /* handler */
1656 (XtPointer) newseq , /* client data */
1657 XtListTail /* last in queue */
1658 ) ;
1659
1660 wtemp = newseq->crop_drag_pb ;
1661
1662 /*-- Label for other info at right [11 Mar 2020] --*/
1663
1664 newseq->rinfo_sep = XtVaCreateManagedWidget(
1665 "imseq" , xmSeparatorWidgetClass , newseq->wform ,
1666 XmNseparatorType , XmSINGLE_LINE ,
1667 EDGING_RIG , XmATTACH_FORM ,
1668 LEADING_RIG , XmATTACH_WIDGET ,
1669 LEADING_WIDGET_RIG , wtemp ,
1670 XmNleftAttachment , XmATTACH_OPPOSITE_WIDGET ,
1671 XmNleftWidget , wtemp ,
1672 XmNleftOffset , 7 ,
1673 XmNrecomputeSize , True ,
1674 NULL ) ;
1675 wtemp = newseq->onoff_widgets[(newseq->onoff_num)++] = newseq->rinfo_sep ;
1676
1677 newseq->onoff_widgets[(newseq->onoff_num)++] =
1678 newseq->rinfo = XtVaCreateManagedWidget(
1679 "font7" , xmLabelWidgetClass , newseq->wform ,
1680 EDGING_RIG , XmATTACH_FORM ,
1681 LEADING_RIG , XmATTACH_WIDGET ,
1682 LEADING_WIDGET_RIG , wtemp ,
1683 XmNinitialResourcesPersistent , False ,
1684 NULL ) ;
1685 BLACK_AND_WHITE_WIDGET(newseq->rinfo) ;
1686 strcpy(newseq->rinfo_label,"OK") ;
1687 MCW_register_hint( newseq->rinfo ,
1688 "Dataset axes: Card=parallel to LR-AP-IS; Obliq=not parallel" ) ;
1689 MCW_register_help( newseq->rinfo ,
1690 " \n"
1691 "This label shows the underlay dataset axes\n"
1692 "orientation with respect to anatomical\n"
1693 "xyz axis (L-R, A-P, I-S):\n"
1694 " Card = dataset parallel with anatomical xyz\n"
1695 " Obliq = dataset NOT parallel\n"
1696 " in which case the default AFNI image\n"
1697 " viewers won't show the underlay\n"
1698 " slices in the 'standard' cut planes.\n " ) ;
1699 wtemp = newseq->rinfo ;
1700
1701 /* 18 Jul 2003: toggle button for pen (drawing mode) */
1702
1703 { char *lbl = "pen" ;
1704 STATUS("creating pen control") ;
1705 newseq->pen_bbox = new_MCW_bbox( newseq->wform ,
1706 1 , &lbl ,
1707 MCW_BB_check , MCW_BB_noframe ,
1708 ISQ_pen_bbox_CB , (XtPointer)newseq ) ;
1709
1710 newseq->onoff_widgets[(newseq->onoff_num)++] = newseq->pen_bbox->wrowcol ;
1711
1712 XtVaSetValues( newseq->pen_bbox->wrowcol ,
1713 EDGING_RIG , XmATTACH_FORM ,
1714 LEADING_RIG , XmATTACH_WIDGET ,
1715 LEADING_WIDGET_RIG , wtemp ,
1716 NULL ) ;
1717
1718 MCW_reghelp_children( newseq->pen_bbox->wrowcol ,
1719 "In ROI drawing mode, toggles\n"
1720 "the cursor to a pen shape,\n"
1721 "and turn on drawing with\n"
1722 "mouse Button-1."
1723 ) ;
1724 MCW_reghint_children( newseq->pen_bbox->wrowcol ,
1725 "Toggle pen drawing" ) ;
1726
1727 XtUnmanageChild( newseq->pen_bbox->wrowcol ) ;
1728 wtemp = newseq->pen_bbox->wrowcol ;
1729 }
1730
1731 /* scale for image number */
1732
1733 ii = (one_image) ? 1 : newseq->status->num_total - 1 ;
1734
1735 STATUS("creating image scale") ;
1736 newseq->onoff_widgets[(newseq->onoff_num)++] =
1737 newseq->wscale =
1738 XtVaCreateManagedWidget(
1739 "imseq" , xmScaleWidgetClass , newseq->wform ,
1740
1741 XmNtopAttachment , XmATTACH_WIDGET ,
1742 XmNtopWidget , newseq->wimage ,
1743 XmNleftAttachment , XmATTACH_FORM ,
1744 XmNrightAttachment , XmATTACH_POSITION ,
1745 XmNrightPosition , (int)( 0.49 + IMAGE_FRAC * FORM_FRAC_BASE ),
1746
1747 XmNminimum , 0 , /* range of scale */
1748 XmNmaximum , ii ,
1749 XmNvalue , newseq->im_nr , /* initial image */
1750 XmNshowValue , True , /* show image num */
1751 XmNscaleMultiple , 1 , /* single step */
1752 XmNorientation , XmHORIZONTAL , /* sideways */
1753
1754 XmNtraversalOn , False ,
1755 XmNinitialResourcesPersistent , False ,
1756 NULL ) ;
1757
1758 XtAddCallback( newseq->wscale , XmNvalueChangedCallback ,
1759 ISQ_scale_CB , newseq ) ;
1760
1761 MCW_reghelp_children( newseq->wscale , ISQ_scale_help ) ;
1762 #if 0
1763 MCW_register_hint( newseq->wscale , "Moves between images" ) ;
1764 #endif
1765
1766 /* arrowpad at lower right corner */
1767
1768 STATUS("creating arrowpad") ;
1769 newseq->arrowpad = new_MCW_arrowpad(
1770 newseq->wform ,
1771 ISQ_arrowpad_CB , (XtPointer) newseq ) ;
1772
1773 newseq->onoff_widgets[(newseq->onoff_num)++] = newseq->arrowpad->wform ;
1774
1775 XtVaSetValues( newseq->arrowpad->wform ,
1776 XmNbottomAttachment , XmATTACH_FORM ,
1777 XmNrightAttachment , XmATTACH_FORM ,
1778 XtNmappedWhenManaged , False , /* managed later */
1779 NULL ) ;
1780
1781 newseq->arrowpad->parent = (XtPointer) newseq ;
1782
1783 /* drawing area for color bar */
1784
1785 STATUS("creating intensity bar") ;
1786 newseq->onoff_widgets[(newseq->onoff_num)++] =
1787 newseq->wbar =
1788 XtVaCreateManagedWidget(
1789 "imseq" , xmDrawingAreaWidgetClass , newseq->wform ,
1790
1791 XmNtopAttachment , XmATTACH_FORM ,
1792 XmNleftAttachment , XmATTACH_WIDGET ,
1793 XmNleftWidget , newseq->wimage ,
1794 XmNleftOffset , COLOR_BAR_SPACE ,
1795 XmNbottomAttachment , XmATTACH_POSITION ,
1796 XmNbottomPosition , (int)( 0.49 + IMAGE_FRAC * FORM_FRAC_BASE ),
1797
1798 XmNwidth , COLOR_BAR_WIDTH ,
1799
1800 XmNtraversalOn , False ,
1801 XmNinitialResourcesPersistent , False ,
1802 NULL ) ;
1803
1804 XtInsertEventHandler( newseq->wbar , /* handle events in bar */
1805
1806 0
1807 | ButtonPressMask /* button presses */
1808 | ExposureMask /* exposures */
1809 | StructureNotifyMask /* resizes (Configure events) */
1810 ,
1811 FALSE , /* nonmaskable events? */
1812 ISQ_drawing_EV , /* super-handler! */
1813 (XtPointer) newseq , /* client data */
1814 XtListTail ) ; /* last in queue */
1815
1816 /* popup menu on wbar */
1817
1818 MCW_register_help( newseq->wbar ,
1819 "Use Button 3 to popup\n"
1820 "a display control menu\n"
1821 "\n"
1822 "Use Button 1 to enforce\n"
1823 "image aspect ratio" ) ;
1824
1825 STATUS("creating intensity bar menu") ;
1826
1827 #ifdef BAD_BUTTON3_POPUPS /* 21 Jul 2003 */
1828 newseq->wbar_menu = XmCreatePopupMenu( newseq->wscale, "menu",NULL,0 ) ;
1829 #else
1830 newseq->wbar_menu = XmCreatePopupMenu( newseq->wbar , "menu",NULL,0 ) ;
1831 #endif
1832
1833 SAVEUNDERIZE(XtParent(newseq->wbar_menu)) ; /* 27 Feb 2001 */
1834
1835 VISIBILIZE_WHEN_MAPPED(newseq->wbar_menu) ;
1836 #if 0
1837 if( !AFNI_yesenv("AFNI_DISABLE_TEAROFF") ) TEAROFFIZE(newseq->wbar_menu) ;
1838 #else
1839 (void) XtVaCreateManagedWidget(
1840 "dialog" , xmPushButtonWidgetClass , newseq->wbar_menu ,
1841 LABEL_ARG("--- Cancel ---") ,
1842 XmNrecomputeSize , False ,
1843 XmNtraversalOn , False ,
1844 XmNinitialResourcesPersistent , False ,
1845 NULL ) ;
1846 #endif
1847
1848 newseq->wbar_rng_but =
1849 XtVaCreateManagedWidget(
1850 "menu" , xmPushButtonWidgetClass , newseq->wbar_menu ,
1851 LABEL_ARG("Choose Display Range") ,
1852 XmNtraversalOn , False ,
1853 XmNinitialResourcesPersistent , False ,
1854 NULL ) ;
1855 XtAddCallback( newseq->wbar_rng_but, XmNactivateCallback, ISQ_wbar_menu_CB, newseq ) ;
1856 MCW_register_hint(newseq->wbar_rng_but,"Fix bot,top values for underlay") ;
1857
1858 newseq->wbar_zer_but =
1859 XtVaCreateManagedWidget(
1860 "menu" , xmPushButtonWidgetClass , newseq->wbar_menu ,
1861 LABEL_ARG("Choose Zero Color") ,
1862 XmNtraversalOn , False ,
1863 XmNinitialResourcesPersistent , False ,
1864 NULL ) ;
1865 XtAddCallback( newseq->wbar_zer_but, XmNactivateCallback, ISQ_wbar_menu_CB, newseq ) ;
1866 MCW_register_hint(newseq->wbar_zer_but,"Color for zero value in underlay") ;
1867
1868 { char *blab[1] = { "Automask?" } ;
1869 newseq->wbar_amask_bbox = new_MCW_bbox( newseq->wbar_menu , /* 14 Jun 2010 */
1870 1 , blab ,
1871 MCW_BB_check , MCW_BB_noframe ,
1872 ISQ_wbar_amask_CB , (XtPointer)newseq ) ;
1873 MCW_reghint_children(newseq->wbar_amask_bbox->wrowcol,"Automatically zero out image exterior") ;
1874 }
1875
1876 { char *blab[1] = { "Invert?" } ;
1877 newseq->wbar_invrt_bbox = new_MCW_bbox( newseq->wbar_menu , /* 14 Jun 2010 */
1878 1 , blab ,
1879 MCW_BB_check , MCW_BB_noframe ,
1880 ISQ_wbar_invrt_CB , (XtPointer)newseq ) ;
1881 MCW_reghint_children(newseq->wbar_invrt_bbox->wrowcol,"Invert contrast?") ;
1882 }
1883
1884
1885 newseq->wbar_flat_but =
1886 XtVaCreateManagedWidget(
1887 "menu" , xmPushButtonWidgetClass , newseq->wbar_menu ,
1888 LABEL_ARG("Choose Flatten Range") ,
1889 XmNtraversalOn , False ,
1890 XmNinitialResourcesPersistent , False ,
1891 NULL ) ;
1892 XtAddCallback( newseq->wbar_flat_but, XmNactivateCallback, ISQ_wbar_menu_CB, newseq ) ;
1893
1894 newseq->wbar_sharp_but =
1895 XtVaCreateManagedWidget(
1896 "menu" , xmPushButtonWidgetClass , newseq->wbar_menu ,
1897 LABEL_ARG("Choose Sharpen factor") ,
1898 XmNtraversalOn , False ,
1899 XmNinitialResourcesPersistent , False ,
1900 NULL ) ;
1901 XtAddCallback( newseq->wbar_sharp_but, XmNactivateCallback, ISQ_wbar_menu_CB, newseq ) ;
1902
1903 newseq->wbar_vgize_but =
1904 XtVaCreateManagedWidget(
1905 "menu" , xmPushButtonWidgetClass , newseq->wbar_menu ,
1906 LABEL_ARG("Choose VG factor") ,
1907 XmNtraversalOn , False ,
1908 XmNinitialResourcesPersistent , False ,
1909 NULL ) ;
1910 XtAddCallback( newseq->wbar_vgize_but, XmNactivateCallback, ISQ_wbar_menu_CB, newseq ) ;
1911
1912 newseq->rng_bot = newseq->rng_top = newseq->rng_ztop = 0 ;
1913 newseq->flat_bot = newseq->flat_top = 0.0 ;
1914 newseq->sharp_fac = 0.60f ; newseq->rng_extern = 0 ;
1915 newseq->vgize_fac = INDEX_TO_VGFAC(2) ;
1916
1917 newseq->zer_color = 0 ;
1918 ii = DC_find_closest_overlay_color( newseq->dc ,
1919 getenv("AFNI_IMAGE_ZEROCOLOR") ) ;
1920 if( ii > 0 ) newseq->zer_color = ii ;
1921
1922 { char *blab[1] = { "Crop Autocenter?" } ;
1923 newseq->wbar_crop_bbox = new_MCW_bbox( newseq->wbar_menu , /* 15 Jan 2014 */
1924 1 , blab ,
1925 MCW_BB_check , MCW_BB_noframe ,
1926 ISQ_wbar_crop_CB , (XtPointer)newseq ) ;
1927 MCW_reghint_children(newseq->wbar_crop_bbox->wrowcol,"Automatically center crop window on crosshairs") ;
1928 if( newseq->crop_autocenter ) MCW_set_bbox( newseq->wbar_crop_bbox , 1 ) ;
1929 }
1930
1931
1932 /* label for informational display */
1933
1934 newseq->onoff_widgets[(newseq->onoff_num)++] =
1935 newseq->winfo = XtVaCreateManagedWidget(
1936 "font7" , xmLabelWidgetClass , newseq->wform ,
1937 XmNtopAttachment , XmATTACH_WIDGET ,
1938 XmNtopWidget , newseq->wscale ,
1939 XmNleftAttachment , XmATTACH_FORM ,
1940 XmNrightAttachment , XmATTACH_POSITION ,
1941 XmNrightPosition ,
1942 (int)( 0.49 + IMAGE_FRAC * FORM_FRAC_BASE ) ,
1943 XmNrecomputeSize , False ,
1944 XmNalignment , XmALIGNMENT_END ,
1945 XmNinitialResourcesPersistent , False ,
1946 NULL ) ;
1947 LABELIZE(newseq->winfo) ;
1948 newseq->winfo_extra[0] = '\0' ; /* 07 Aug 1999 */
1949
1950 newseq->winfo_sides[0][0] =
1951 newseq->winfo_sides[1][0] =
1952 newseq->winfo_sides[2][0] =
1953 newseq->winfo_sides[3][0] = '\0' ; /* 01 Dec 1999 */
1954 newseq->winfo_prefix[0] = '\0' ; /* 10 Dec 2007 */
1955
1956 /***---------- all widgets now created ------------***/
1957
1958 newseq->mont_across_av = NULL ;
1959 newseq->mont_down_av = NULL ;
1960 newseq->mont_skip_av = NULL ;
1961 newseq->mont_gap_av = NULL ;
1962 newseq->mont_gapcolor_av = NULL ;
1963 newseq->mont_type_av = NULL ;
1964
1965 newseq->mont_nx = newseq->mont_nx_old = 1 ;
1966 newseq->mont_ny = newseq->mont_ny_old = 1 ;
1967 newseq->mont_skip = newseq->mont_skip_old = 0 ;
1968 newseq->mont_gap = newseq->mont_gap_old = 0 ;
1969 newseq->mont_gapcolor = newseq->mont_gapcolor_old = 0 ;
1970 newseq->mont_periodic = 1 ; /* default = periodic */
1971 newseq->mont_mode = MONT_SPATIAL ;
1972
1973 STATUS("creation: widgets created") ;
1974
1975 XtManageChild( newseq->wform ) ;
1976
1977 #if 0
1978 XtRealizeWidget( newseq->wtop ) ;
1979 newseq->valid = 2 ; /* mark this structure as ready to roll */
1980
1981 NORMAL_cursorize( newseq->wtop ) ;
1982
1983 #else
1984 newseq->valid = 1 ; /* mark this structure as valid but not realized */
1985 #endif
1986
1987 newseq->ignore_redraws = 0 ;
1988
1989 /* 30 Oct 1996 -- transformations */
1990
1991 newseq->transform0D_func = NULL ; /* no function to start with */
1992 newseq->transform0D_av = NULL ;
1993 newseq->transform0D_index = 0 ;
1994
1995 newseq->transform2D_func = NULL ; /* no function to start with */
1996 newseq->transform2D_av = NULL ;
1997 newseq->transform2D_index = 0 ;
1998
1999 newseq->slice_proj_av = NULL ; /* 31 Jan 2002 */
2000 newseq->slice_proj_func = NULL ;
2001 newseq->slice_proj_index = 0 ;
2002 newseq->slice_proj_range_av = NULL ;
2003 newseq->slice_proj_range = 0 ;
2004
2005 newseq->rowgraph_av = NULL ; /* 30 Dec 1998 */
2006 newseq->rowgraph_num = 0 ;
2007 newseq->rowgraph_mtd = NULL ;
2008
2009 newseq->graymap_mtd = NULL ; /* 24 Oct 2003 */
2010 newseq->cmap_changed = 0 ;
2011
2012 newseq->shft_ctrl_dragged = 0 ; /* 17 Mar 2010 */
2013
2014 #define DEFAULT_THETA 55.0
2015 #define DEFAULT_PHI 285.0
2016
2017 newseq->surfgraph_av = NULL ; /* 21 Jan 1999 */
2018 newseq->surfgraph_num = 0 ;
2019 newseq->surfgraph_mtd = NULL ;
2020 newseq->surfgraph_theta = DEFAULT_THETA ;
2021 newseq->surfgraph_phi = DEFAULT_PHI ;
2022 newseq->surfgraph_arrowpad = NULL ;
2023
2024 newseq->mplot = NULL ; /* 19 Sep 2001 */
2025
2026 /* 20 Sep 2001: add a button box to control plots
2027 and arrowvals to control labels */
2028
2029 { static char *plabel[1] = { "Plot Overlay Plots" } ;
2030 static char *alabel[7] = { "Off", "UpperLeft", "UpperRight",
2031 "LowerLeft", "LowerRight",
2032 "UpperMid" , "LowerMid" } ;
2033 static char *slabel[6] = { "Tiny" , "Small" , "Medium" , "Large" , "Huge" , "Enormous" } ;
2034 static char *mlabel[3] = { "Slice", "Volume", "Dataset" };
2035
2036 char *eee ; int iii ;
2037
2038 (void) XtVaCreateManagedWidget( "menu",
2039 xmSeparatorWidgetClass, newseq->wbar_menu,
2040 XmNseparatorType , XmSINGLE_LINE ,
2041 NULL ) ;
2042
2043 #if 1
2044 iii = THD_get_image_globalrange();
2045 if( iii < 0 || iii > 3 ) iii = 0 ;
2046
2047 newseq->wbar_globrange_av =
2048 new_MCW_arrowval( newseq->wbar_menu ,
2049 "Image Global Range" ,
2050 MCW_AV_optmenu , /* option menu style */
2051 0 , /* first option */
2052 2 , /* last option */
2053 iii , /* initial selection */
2054 MCW_AV_readtext , /* ignored but needed */
2055 0 , /* ditto */
2056 ISQ_wbar_globrange_CB , /* callback when changed */
2057 (XtPointer)newseq , /* data for above */
2058 MCW_av_substring_CB , /* text creation routine */
2059 mlabel /* data for above */
2060 ) ;
2061 MCW_reghint_children(newseq->wbar_globrange_av->wrowcol,
2062 "Set how images are scaled in display - sets AFNI_IMAGE_GLOBALRANGE") ;
2063 #endif
2064
2065 /*-- plots stuff --*/
2066
2067 newseq->wbar_plots_bbox = new_MCW_bbox( newseq->wbar_menu ,
2068 1 , plabel ,
2069 MCW_BB_check , MCW_BB_noframe ,
2070 ISQ_wbar_plots_CB , (XtPointer)newseq ) ;
2071 MCW_set_bbox( newseq->wbar_plots_bbox , 1 ) ;
2072 MCW_reghint_children(newseq->wbar_plots_bbox->wrowcol,"Allow line drawing overlay stuff") ;
2073
2074 newseq->wbar_graymap_pb =
2075 XtVaCreateManagedWidget(
2076 "menu" , xmPushButtonWidgetClass , newseq->wbar_menu ,
2077 LABEL_ARG("Display Graymap Plot") ,
2078 XmNtraversalOn , False ,
2079 XmNinitialResourcesPersistent , False ,
2080 NULL ) ;
2081 XtAddCallback( newseq->wbar_graymap_pb, XmNactivateCallback, ISQ_wbar_menu_CB, newseq ) ;
2082 MCW_register_hint(newseq->wbar_graymap_pb,"Graph intensity vs underlay image value") ;
2083
2084 (void) XtVaCreateManagedWidget( "menu",
2085 xmSeparatorWidgetClass, newseq->wbar_menu,
2086 XmNseparatorType , XmSINGLE_LINE ,
2087 NULL ) ;
2088
2089 newseq->timer_id = 0 ; /* 03 Dec 2003 */
2090
2091 newseq->render_mode = RENDER_DEFAULT ; /* 0 */
2092 newseq->render_fac = 0.0f ; /* 22 Aug 2014 */
2093 newseq->allowmerger = 0 ;
2094
2095 /*-- labels stuff --*/
2096
2097 iii = 0 ;
2098 eee = getenv("AFNI_IMAGE_LABEL_MODE") ;
2099 if( eee != NULL ){
2100 iii = strtol(eee,NULL,10) ; if( iii < 0 || iii > 6 ) iii = 1 ;
2101 }
2102 newseq->wbar_label_av =
2103 new_MCW_arrowval( newseq->wbar_menu ,
2104 "Label" ,
2105 MCW_AV_optmenu , /* option menu style */
2106 0 , /* first option */
2107 6 , /* last option */
2108 iii , /* initial selection */
2109 MCW_AV_readtext , /* ignored but needed */
2110 0 , /* ditto */
2111 ISQ_wbar_label_CB , /* callback when changed */
2112 (XtPointer)newseq , /* data for above */
2113 MCW_av_substring_CB , /* text creation routine */
2114 alabel /* data for above */
2115 ) ;
2116 MCW_reghint_children(newseq->wbar_label_av->wrowcol,"Show coordinate label") ;
2117
2118 iii = 2 ;
2119 eee = getenv("AFNI_IMAGE_LABEL_SIZE") ;
2120 if( eee != NULL ){
2121 iii = strtol(eee,NULL,10) ; if( iii < 0 || iii > 5 ) iii = 2 ;
2122 }
2123 newseq->wbar_labsz_av =
2124 new_MCW_arrowval( newseq->wbar_menu ,
2125 "Size " ,
2126 MCW_AV_optmenu , /* option menu style */
2127 0 , /* first option */
2128 5 , /* last option */
2129 iii , /* initial selection */
2130 MCW_AV_readtext , /* ignored but needed */
2131 0 , /* ditto */
2132 ISQ_wbar_label_CB , /* callback when changed */
2133 (XtPointer)newseq , /* data for above */
2134 MCW_av_substring_CB , /* text creation routine */
2135 slabel /* data for above */
2136 ) ;
2137 MCW_reghint_children(newseq->wbar_labsz_av->wrowcol,"Set coordinate label size") ;
2138
2139 newseq->wbar_labst_pb =
2140 XtVaCreateManagedWidget(
2141 "menu" , xmPushButtonWidgetClass , newseq->wbar_menu ,
2142 LABEL_ARG("Label Append String") ,
2143 XmNtraversalOn , False ,
2144 XmNinitialResourcesPersistent , False ,
2145 NULL ) ;
2146 XtAddCallback( newseq->wbar_labst_pb, XmNactivateCallback, ISQ_wbar_menu_CB, newseq ) ;
2147 MCW_register_hint(newseq->wbar_labst_pb,"Set string to append to overlay label") ;
2148
2149 } /* end of plots & labels stuff */
2150
2151 /** 23 Feb 2003: menu items to control tic marks */
2152
2153 (void) XtVaCreateManagedWidget( "menu",
2154 xmSeparatorWidgetClass, newseq->wbar_menu,
2155 XmNseparatorType , XmSINGLE_LINE ,
2156 NULL ) ;
2157 newseq->wbar_ticnum_av =
2158 new_MCW_arrowval( newseq->wbar_menu ,
2159 "Tick Div." ,
2160 MCW_AV_optmenu , /* option menu style */
2161 0 , /* first option */
2162 21 , /* last option */
2163 0 , /* initial selection */
2164 MCW_AV_readtext , /* ignored but needed */
2165 0 , /* ditto */
2166 ISQ_wbar_label_CB , /* callback when changed */
2167 (XtPointer)newseq , /* data for above */
2168 NULL , /* text creation routine */
2169 NULL /* data for above */
2170 ) ;
2171 AVOPT_columnize(newseq->wbar_ticnum_av,2) ;
2172 MCW_reghint_children( newseq->wbar_ticnum_av->wrowcol ,
2173 "Number of tick marks on image edges [cf. AFNI_IMAGE_TICK_DIV_IN_MM]" ) ;
2174 newseq->wbar_ticsiz_av =
2175 new_MCW_arrowval( newseq->wbar_menu ,
2176 "Tick Size" ,
2177 MCW_AV_optmenu , /* option menu style */
2178 1 , /* first option */
2179 10 , /* last option */
2180 1 , /* initial selection */
2181 MCW_AV_readtext , /* ignored but needed */
2182 0 , /* ditto */
2183 ISQ_wbar_label_CB , /* callback when changed */
2184 (XtPointer)newseq , /* data for above */
2185 NULL , /* text creation routine */
2186 NULL /* data for above */
2187 ) ;
2188 AVOPT_columnize(newseq->wbar_ticsiz_av,2) ;
2189 MCW_reghint_children( newseq->wbar_ticsiz_av->wrowcol ,
2190 "Size of tick marks around image edges" ) ;
2191
2192 /** 27 Oct 2008: menu item to control checkerboarding */
2193
2194 (void) XtVaCreateManagedWidget( "menu",
2195 xmSeparatorWidgetClass, newseq->wbar_menu,
2196 XmNseparatorType , XmSINGLE_LINE ,
2197 NULL ) ;
2198 newseq->wbar_checkbrd_av =
2199 new_MCW_arrowval( newseq->wbar_menu ,
2200 "CheckBrd#" ,
2201 MCW_AV_optmenu , /* option menu style */
2202 0 , /* first option */
2203 43 , /* last option */
2204 0 , /* initial selection */
2205 MCW_AV_readtext , /* ignored but needed */
2206 0 , /* ditto */
2207 ISQ_wbar_label_CB , /* callback when changed */
2208 (XtPointer)newseq , /* data for above */
2209 NULL , /* text creation routine */
2210 NULL /* data for above */
2211 ) ;
2212 AVOPT_columnize(newseq->wbar_checkbrd_av,4) ;
2213 MCW_reghint_children( newseq->wbar_checkbrd_av->wrowcol ,
2214 "Size of checks in the checkerboard display [# key]" );
2215
2216 /** 10 Feb 2009: menu item to control animation duplicates **/
2217
2218 newseq->wbar_animdup_av =
2219 new_MCW_arrowval( newseq->wbar_menu ,
2220 "Anim_Dup " ,
2221 MCW_AV_optmenu , /* option menu style */
2222 0 , /* first option */
2223 19 , /* last option */
2224 ISQ_anim_dup , /* initial selection */
2225 MCW_AV_readtext , /* ignored but needed */
2226 0 , /* ditto */
2227 ISQ_wbar_label_CB , /* callback when changed */
2228 (XtPointer)newseq , /* data for above */
2229 NULL , /* text creation routine */
2230 NULL /* data for above */
2231 ) ;
2232 AVOPT_columnize(newseq->wbar_animdup_av,2) ;
2233 MCW_reghint_children( newseq->wbar_animdup_av->wrowcol ,
2234 "Duplicate images for Save:aGif and Save:mpeg" ) ;
2235
2236 newseq->top_clip = 0.0f ; /* 17 Sep 2007 */
2237 newseq->redo_clip = 0 ;
2238
2239 /* 23 Jan 2003: set default save? */
2240
2241 drive_MCW_imseq( newseq , isqDR_setimsave ,
2242 (XtPointer)getenv("AFNI_DEFAULT_IMSAVE") ) ;
2243
2244 /* 23 Jan 2003: set opacity? */
2245
2246 { int opval = (int)AFNI_numenv("AFNI_DEFAULT_OPACITY") ;
2247 if( opval > 0 && opval <= 9 )
2248 drive_MCW_imseq( newseq , isqDR_setopacity , (XtPointer)ITOP(opval) ) ;
2249 }
2250
2251 newseq->parent = NULL ;
2252
2253 { static int first=1 ;
2254 if( first ){
2255 memplot_topshell_setsaver( ".jpg" , memplot_to_jpg ) ; /* 05 Dec 2007 */
2256 memplot_topshell_setsaver( ".png" , memplot_to_png ) ;
2257 first = 0 ;
2258 }
2259 }
2260
2261 /* set scrollwheel threshold modifier mask [14 Feb 2014] */
2262
2263 { char *eee = my_getenv("AFNI_IMAGE_SCROLLWHEEL_TMASK") ;
2264 int swt = 0 ;
2265 if( eee != NULL ){
2266 if( strcasestr(eee,"shift") != NULL ) swt |= ShiftMask ;
2267 if( strcasestr(eee,"shft") != NULL ) swt |= ShiftMask ;
2268 if( strcasestr(eee,"ctrl") != NULL ) swt |= ControlMask ;
2269 if( strcasestr(eee,"control") != NULL ) swt |= ControlMask ;
2270 if( strcasestr(eee,"mod1") != NULL ) swt |= Mod1Mask ;
2271 if( strcasestr(eee,"mod2") != NULL ) swt |= Mod2Mask ;
2272 if( strcasestr(eee,"mod3") != NULL ) swt |= Mod3Mask ;
2273 if( strcasestr(eee,"mod4") != NULL ) swt |= Mod4Mask ;
2274 if( strcasestr(eee,"mod5") != NULL ) swt |= Mod5Mask ;
2275
2276 if( strcasestr(eee,"debug") != NULL ) scrollwheel_debug = 1 ;
2277 }
2278 scrollwheel_tmask = (swt == 0) ? SWL_TMASK_DEFAULT : swt ;
2279 }
2280
2281 XtUnmanageChild(newseq->render_scal) ;
2282 RETURN(newseq) ;
2283 }
2284
2285 /*----------------------------------------------------------------------
2286 set the image dimensions in "physical units"
2287 (based on the dx and dy fields of the input image);
2288 the goal is to keep the same scaling from pixels -> mm even
2289 if the image is a different size
2290 ------------------------------------------------------------------------*/
2291
ISQ_reset_dimen(MCW_imseq * seq,float new_width_mm,float new_height_mm)2292 void ISQ_reset_dimen( MCW_imseq *seq, float new_width_mm, float new_height_mm )
2293 {
2294 int xwide , yhigh , oldx,oldy ;
2295 float scale_x , scale_y ;
2296 int wx,hy,xx,yy ; /* geometry of shell */
2297 int xp,yp ;
2298 MCW_DC *dc ;
2299
2300 float minfrac=DEFAULT_MINFRAC ; char *eee ; /* 12 Jun 2002 */
2301 float maxfrac=DEFAULT_MAXFRAC ;
2302
2303 ENTRY("ISQ_reset_dimen") ;
2304
2305 if( ! ISQ_VALID(seq) ) EXRETURN ;
2306
2307 MCW_widget_geom( seq->wimage , &oldx , &oldy , NULL,NULL ) ;
2308
2309 scale_x = seq->last_width_mm / oldx ; /* mm/pixel as displayed now */
2310 scale_y = seq->last_height_mm/ oldy ;
2311
2312 if( ! seq->opt.free_aspect ){ /* fixed aspect */
2313 scale_x = scale_y = sqrt( scale_x * scale_y ) ; /* means use */
2314 } /* same scales! */
2315
2316 xwide = new_width_mm / scale_x + 0.5 ; /* so scale to new # of pixels */
2317 yhigh = new_height_mm/ scale_y + 0.5 ;
2318
2319 /** 12 Jun 2002: set minimum size for image windows,
2320 as a fraction of the overall screen area **/
2321
2322 eee = my_getenv("AFNI_IMAGE_MINFRAC") ;
2323 if( eee != NULL ){
2324 float fff=0.0 ; int ii ;
2325 ii = sscanf(eee,"%f",&fff) ;
2326 if( ii > 0 && fff > 0.0 && fff <= 1.0 ) minfrac = fff ;
2327 else minfrac = DEFAULT_MINFRAC ;
2328 }
2329
2330 eee = my_getenv("AFNI_IMAGE_MAXFRAC") ;
2331 if( eee != NULL ){
2332 float fff=0.0 ; int ii ;
2333 ii = sscanf(eee,"%f",&fff) ;
2334 if( ii > 0 && fff > 0.0 && fff <= 1.0 ) maxfrac = fff ;
2335 else maxfrac = DEFAULT_MAXFRAC ;
2336 }
2337
2338 dc = seq->dc ;
2339
2340 { float xxx = xwide , yyy = yhigh ;
2341 float fff = (xxx*yyy)/(dc->width*dc->height) , ggg ;
2342
2343 /* modify if window too small */
2344
2345 if( fff < minfrac ){
2346 fff = sqrt(minfrac/fff) ; xxx *= fff ; yyy *= fff ; /* expand area */
2347 }
2348
2349 /* modify if window too big */
2350
2351 fff = ggg = 1.0 ;
2352 if( xxx >= maxfrac*dc->width ) fff = maxfrac*dc->width / xxx ; /* don't let */
2353 if( yyy >= maxfrac*dc->height) ggg = maxfrac*dc->height/ yyy ; /* be too big */
2354 fff = MIN(fff,ggg) ; xxx *= fff ; yyy *= fff ;
2355 if( xxx < 1.0 || yyy < 1.0 ){ /* weird result?? */
2356 xxx = xwide ; yyy = yhigh ; /* back to old way */
2357 }
2358
2359 xwide = (int)( 0.49 + xxx ) ;
2360 yhigh = (int)( 0.49 + yyy ) ;
2361 }
2362
2363 if( PRINT_TRACING ){
2364 char str[256] ;
2365 sprintf(str,"last wid=%f hei=%f new wid=%f hei=%f",
2366 seq->last_width_mm,seq->last_height_mm,new_width_mm,new_height_mm ) ;
2367 STATUS(str) ;
2368 sprintf(str,"new xwide=%d yhigh=%d scale_x=%f _y=%f",
2369 xwide,yhigh,scale_x,scale_y) ;
2370 STATUS(str) ;
2371 }
2372
2373 seq->last_width_mm = new_width_mm ;
2374 seq->last_height_mm = new_height_mm ;
2375
2376 /* possibly expand to include control widgets (if they are on) */
2377
2378 if( seq->onoff_state ){
2379 float fff,ggg ;
2380 xwide = (int) ( 0.49 + xwide / seq->image_frac ) ; /* new size of shell */
2381 yhigh = (int) ( 0.49 + yhigh / seq->image_frac ) ;
2382
2383 fff = ggg = 1.0 ;
2384 if( xwide >= maxfrac*dc->width ) fff = maxfrac*dc->width /xwide; /* 13 Jun 2003 */
2385 if( yhigh >= maxfrac*dc->height) ggg = maxfrac*dc->height/yhigh; /* Fri the 13th */
2386 fff = MIN(fff,ggg) ;
2387 fff = MIN(fff,ggg) ; xwide *= fff ; yhigh *= fff ;
2388 }
2389
2390 if( seq->opt.free_aspect ){
2391 XtVaSetValues( seq->wtop ,
2392 XmNminAspectX , 1 , /* free up aspect ratio */
2393 XmNminAspectY , 20 ,
2394 XmNmaxAspectX , 20 ,
2395 XmNmaxAspectY , 1 ,
2396 NULL ) ;
2397 } else {
2398 XtVaSetValues( seq->wtop ,
2399 XmNminAspectX , xwide , /* reset aspect ratio */
2400 XmNminAspectY , yhigh ,
2401 XmNmaxAspectX , xwide ,
2402 XmNmaxAspectY , yhigh ,
2403 NULL ) ;
2404 }
2405
2406 XtVaSetValues( seq->wtop ,
2407 XmNwidth , xwide , /* reset size of form */
2408 XmNheight , yhigh ,
2409 NULL ) ;
2410
2411 /* it is possible that the image has flipped off the screen now -- fix that! */
2412
2413 MCW_widget_geom( seq->wtop , &wx,&hy,&xx,&yy ) ;
2414
2415 if( xx+wx/2 < 1 ) xp = 10 ; else xp = xx ;
2416 if( yy+hy/2 < 1 ) yp = 10 ; else yp = yy ;
2417
2418 if( xp != xx || yp != yy )
2419 XtVaSetValues( seq->wtop , XmNx , xp , XmNy , yp , NULL ) ;
2420
2421 /* if there is a dialog, move it too [modified 05 Jan 1999] */
2422
2423 if( seq->dialog != NULL && XtIsRealized( seq->dialog ) )
2424 ISQ_place_dialog( seq ) ;
2425
2426 EXRETURN ;
2427 }
2428
2429 /*-----------------------------------------------------------------------
2430 copy an imseq status structure
2431 -------------------------------------------------------------------------*/
2432
ISQ_copy_status(MCW_imseq_status * instat)2433 MCW_imseq_status * ISQ_copy_status( MCW_imseq_status * instat )
2434 {
2435 MCW_imseq_status * outstat ;
2436
2437 ENTRY("ISQ_copy_status") ;
2438
2439 outstat = (MCW_imseq_status *) XtMalloc( sizeof(MCW_imseq_status) ) ;
2440
2441 *outstat = *instat ; /* shallow copy for now (no pointers) */
2442 RETURN(outstat) ;
2443 }
2444
2445 /*-----------------------------------------------------------------------*/
2446 /* Labels for the opacity arrow at the right of the viewer */
2447
ISQ_opacity_label(int val)2448 char * ISQ_opacity_label( int val ) /* 07 Mar 2001 */
2449 {
2450 static char dig[] = "0123456789" , buf[3] ;
2451
2452 buf[0] = dig[val] ; buf[1] = '\0' ; return buf ;
2453 }
2454
2455 /*-----------------------------------------------------------------------*/
2456 /* Return the (i,j,k) of the current image crosshairs,
2457 retrieved from AFNI (if available)
2458 *//*---------------------------------------------------------------------*/
2459
ISQ_get_crosshairs(MCW_imseq * seq)2460 int_triple ISQ_get_crosshairs( MCW_imseq *seq ) /* 27 Aug 2009 */
2461 {
2462 int_triple xyn ; ISQ_cbs cbs ;
2463
2464 cbs.reason = isqCR_getxynim ;
2465 cbs.xim = cbs.yim = cbs.nim = -666 ; /* initialize to badness */
2466 if( seq->status->send_CB != NULL ) SEND(seq,cbs) ;
2467 xyn.i = cbs.xim ; xyn.j = cbs.yim ; xyn.k = cbs.nim ;
2468 return xyn ;
2469 }
2470
2471 /*-----------------------------------------------------------------------*/
2472 /* What happens when the opacity arrow is clicked up or down */
2473
ISQ_opacity_CB(MCW_arrowval * av,XtPointer cd)2474 void ISQ_opacity_CB( MCW_arrowval *av , XtPointer cd ) /* 07 Mar 2001 */
2475 {
2476 MCW_imseq *seq = (MCW_imseq *) cd ;
2477 char *buf = ISQ_opacity_label(av->ival) ;
2478 XmString xstr = XmStringCreateLtoR( buf , XmFONTLIST_DEFAULT_TAG ) ;
2479
2480 XtVaSetValues( av->wlabel , XmNlabelString , xstr , NULL ) ;
2481 XmStringFree( xstr ) ;
2482
2483 seq->ov_opacity = OPACITY_FAC * av->ival ;
2484 ISQ_redisplay( seq , -1 , isqDR_display ) ;
2485
2486 if( AFNI_yesenv("AFNI_OPACITY_LOCK") ) /* 06 Jun 2019 */
2487 OPACITY_CHANGE(seq,av->ival) ;
2488
2489 return ;
2490 }
2491
2492 /*-----------------------------------------------------------------------*/
2493 /*! Callback for the zoom arrowval buttons */
2494
ISQ_zoom_av_CB(MCW_arrowval * apv,XtPointer cd)2495 void ISQ_zoom_av_CB( MCW_arrowval *apv , XtPointer cd ) /* 11 Mar 2002 */
2496 {
2497 MCW_imseq *seq = (MCW_imseq *) cd ;
2498 MCW_arrowval *av = seq->zoom_val_av ;
2499 XmString xstr ;
2500 int zlev=av->ival , /* new zoom level */
2501 zold=seq->zoom_fac ; /* old zoom level */
2502
2503 ENTRY("ISQ_zoom_av_CB") ;
2504
2505 if( !ISQ_REALZ(seq) || av != apv ) EXRETURN ; /* bad */
2506
2507 /* don't allow zoom > 1 if montage-izing */
2508
2509 if( seq->mont_nx > 1 || seq->mont_ny > 1 ){ /* 18 Nov 2003 */
2510 AV_assign_ival(av,ZOOM_BOT) ; seq->zoom_fac = 1 ;
2511 XBell(seq->dc->display,100); EXRETURN;
2512 }
2513 if( seq->dialog != NULL && seq->dialog_starter == NBUT_MONT ){
2514 AV_assign_ival(av,ZOOM_BOT) ; seq->zoom_fac = 1 ;
2515 XBell(seq->dc->display,100); EXRETURN;
2516 }
2517
2518 /*-- change zoom factor (and label) --*/
2519
2520 xstr = XmStringCreateLtoR( (zlev==1)?"z":"Z" , XmFONTLIST_DEFAULT_TAG );
2521 XtVaSetValues( av->wlabel , XmNlabelString , xstr , NULL ) ;
2522 XmStringFree( xstr ) ;
2523
2524 seq->zoom_fac = zlev ; /* change recorded zoom factor */
2525 if( zlev == 1 ){
2526 seq->zoom_hor_off = seq->zoom_ver_off = 0.0 ; /* no image offsets */
2527 } else {
2528 float mh = (zlev-1.001f)/zlev ; /* max offset allowed */
2529 float dh = 0.5f*(1.0f/zold-1.0f/zlev) ; /* change in offset to */
2530 /* keep current center */
2531 seq->zoom_hor_off += dh ;
2532 seq->zoom_ver_off += dh ;
2533 if( seq->zoom_hor_off > mh ){ seq->zoom_hor_off = mh ; }
2534 else if( seq->zoom_hor_off < 0.0 ){ seq->zoom_hor_off = 0.0 ; }
2535 if( seq->zoom_ver_off > mh ){ seq->zoom_ver_off = mh ; }
2536 else if( seq->zoom_ver_off < 0.0 ){ seq->zoom_ver_off = 0.0 ; }
2537 }
2538
2539 /* change some widgets depending on zoom level */
2540
2541 SENSITIZE( seq->zoom_drag_pb , (zlev>1) ) ;
2542
2543 AV_SENSITIZE_DOWN( av , (zlev > 1 ) ) ;
2544 AV_SENSITIZE_UP ( av , (zlev < ZOOM_TOP) ) ;
2545
2546 if( zlev == 1 && seq->zoom_button1 ){ /* can't pan at zlev=1 */
2547 seq->zoom_button1 = 0 ;
2548 MCW_invert_widget( seq->zoom_drag_pb ) ;
2549 POPUP_cursorize( seq->wimage ) ;
2550 }
2551
2552 /* free the zooming pixmap (need a new one for a new image size) */
2553
2554 if( seq->zoom_pixmap != (Pixmap) 0 ){
2555 XFreePixmap( seq->dc->display , seq->zoom_pixmap ) ;
2556 seq->zoom_pixmap = (Pixmap) 0 ; seq->zoom_pw = seq->zoom_ph = 0 ;
2557 }
2558
2559 /* free zoomed image (need a new one for a new image size) */
2560
2561 MCW_kill_XImage(seq->zoom_xim) ; seq->zoom_xim = NULL ;
2562
2563 /* must redisplay image totally */
2564
2565 ISQ_redisplay( seq , -1 , isqDR_display ) ;
2566 ZOOM_CHANGE(seq) ; /* 10 Dec 2019 */
2567
2568 EXRETURN ;
2569 }
2570
2571 /*--------------------------------------------------------------------------*/
2572 /*! Callback for 'pan' button - used when zoom is on, of course */
2573
ISQ_zoom_pb_CB(Widget w,XtPointer client_data,XtPointer call_data)2574 void ISQ_zoom_pb_CB( Widget w , XtPointer client_data , XtPointer call_data )
2575 {
2576 MCW_imseq *seq = (MCW_imseq *) client_data ;
2577
2578 ENTRY("ISQ_zoom_pb_CB") ;
2579
2580 if( ! ISQ_REALZ(seq) ||
2581 w != seq->zoom_drag_pb ||
2582 seq->zoom_fac == 1 ) EXRETURN ; /* bad */
2583
2584 if( seq->cursor_state != CURSOR_NORMAL ){ /* really bad */
2585 XBell(XtDisplay(w),100); EXRETURN;
2586 }
2587
2588 seq->zoom_button1 = !seq->zoom_button1 ; /* toggle dragging */
2589
2590 /* change the cursor */
2591 if( seq->zoom_button1 ) HAND_cursorize ( seq->wimage ) ;
2592 else POPUP_cursorize( seq->wimage ) ;
2593
2594 MCW_invert_widget( seq->zoom_drag_pb ) ;
2595
2596 if( seq->crop_drag ){ /* turn off crop */
2597 MCW_invert_widget( seq->crop_drag_pb ) ; /* button, if on */
2598 seq->crop_drag = 0 ;
2599 }
2600
2601 EXRETURN ;
2602 }
2603
2604 /*-------------------------------------------------------------------------*/
2605 /*! Actually pan the zoomed image, lr steps left/right, ud steps up/down.
2606 ---------------------------------------------------------------------------*/
2607
ISQ_actually_pan(MCW_imseq * seq,int lr,int ud)2608 void ISQ_actually_pan( MCW_imseq *seq , int lr , int ud ) /* 24 Jan 2003 */
2609 {
2610 float hh,vv , mh,dh , hhold,vvold ;
2611
2612 ENTRY("ISQ_actually_pan") ;
2613
2614 if( !ISQ_REALZ(seq) || seq->zoom_fac == 1 || seq->zoom_xim == NULL ) EXRETURN;
2615
2616 mh = (seq->zoom_fac-1.001f)/seq->zoom_fac ; /* max offset */
2617 dh = 0.020/seq->zoom_fac ; /* delta offset */
2618 hh=seq->zoom_hor_off ; hhold=hh ; /* current offsets */
2619 vv=seq->zoom_ver_off ; vvold=vv ;
2620
2621 hh += lr*dh ;
2622 if( hh < 0.0) hh = 0.0 ;
2623 else if( hh > mh ) hh = mh ;
2624
2625 vv += ud*dh ;
2626 if( vv < 0.0) vv = 0.0 ;
2627 else if( vv > mh ) vv = mh ;
2628
2629 if( vv == vvold && hh == hhold ) EXRETURN ; /* no changes? */
2630
2631 seq->zoom_hor_off = hh ; /* changes! */
2632 seq->zoom_ver_off = vv ;
2633 ISQ_show_zoom( seq ) ; /* redraw */
2634 ZOOM_CHANGE(seq) ; /* 10 Dec 2019 */
2635 EXRETURN ;
2636 }
2637
2638 /*--------------------------------------------------------------------------*/
2639 /*! Callback for 'crop' button. */
2640
ISQ_crop_pb_CB(Widget w,XtPointer client_data,XtPointer call_data)2641 void ISQ_crop_pb_CB( Widget w , XtPointer client_data , XtPointer call_data )
2642 {
2643 MCW_imseq *seq = (MCW_imseq *) client_data ;
2644
2645 ENTRY("ISQ_crop_pb_CB") ;
2646
2647 if( !ISQ_REALZ(seq) ||
2648 w != seq->crop_drag_pb ||
2649 ! seq->crop_allowed ){ /* XBell(XtDisplay(w),100); */ EXRETURN; }
2650
2651 MCW_invert_widget( seq->crop_drag_pb ) ;
2652 seq->crop_drag = !seq->crop_drag ;
2653
2654 if( !seq->crop_drag && seq->cropit ){ /* turn crop off */
2655 seq->cropit = 0; seq->crop_nxorg = seq->crop_nyorg = -1; /* if double-pressed */
2656 ISQ_redisplay( seq , -1 , isqDR_display ) ;
2657 }
2658
2659 if( seq->zoom_button1 ){ /* turn pan off if on */
2660 POPUP_cursorize( seq->wimage ) ;
2661 MCW_invert_widget( seq->zoom_drag_pb ) ;
2662 seq->zoom_button1 = 0 ;
2663 }
2664
2665 EXRETURN ;
2666 }
2667
2668 /*-----------------------------------------------------------------------*/
2669
ISQ_adjust_crop(MCW_imseq * seq,int dxa,int dxb,int dya,int dyb,int doit)2670 void ISQ_adjust_crop( MCW_imseq *seq ,
2671 int dxa , int dxb , int dya , int dyb , int doit )
2672 {
2673 int new_xa, new_xb, new_ya, new_yb , ii,jj ;
2674
2675 ENTRY("ISQ_adjust_crop") ;
2676
2677 if( !ISQ_REALZ(seq) || seq->cropit == 0 ) EXRETURN ;
2678
2679 if( dxa==0 && dxb==0 && dya==0 && dyb==0 ){ /* recenter */
2680 int_triple xyn ; int xcen,ycen , xwid,ywid ;
2681
2682 /* find current location of crosshairs (if any) */
2683
2684 xyn = ISQ_get_crosshairs( seq ) ; xcen = xyn.i ; ycen = xyn.j ;
2685 if( xcen < 0 || ycen < 0 ) EXRETURN ; /* check for bad return */
2686
2687 xwid = seq->crop_xb - seq->crop_xa ; /* crop region sizes */
2688 ywid = seq->crop_yb - seq->crop_ya ;
2689
2690 /* compute new left-upper corner */
2691
2692 new_xa = xcen - xwid/2 ; if( new_xa < 0 ) new_xa = 0 ;
2693 new_ya = ycen - ywid/2 ; if( new_ya < 0 ) new_ya = 0 ;
2694
2695 /* compute new right-lower corner */
2696
2697 new_xb = new_xa + xwid ;
2698 if( new_xb >= seq->crop_nxorg ){
2699 new_xb = seq->crop_nxorg - 1 ; new_xa = new_xb - xwid ;
2700 }
2701
2702 new_yb = new_ya + ywid ;
2703 if( new_yb >= seq->crop_nyorg ){
2704 new_yb = seq->crop_nyorg - 1 ; new_ya = new_yb - ywid ;
2705 }
2706
2707 } else { /* change one or more crop window coordinate manually */
2708
2709 /* get current corner coords */
2710
2711 new_xa = seq->crop_xa ; new_xb = seq->crop_xb ;
2712 new_ya = seq->crop_ya ; new_yb = seq->crop_yb ;
2713
2714 /* 27 Aug 2009: allow for flipped image,
2715 to give the user a uniform experience */
2716
2717 ISQ_unflipxy( seq , &new_xa , &new_ya ) ; /* flip to screen coords */
2718 ISQ_unflipxy( seq , &new_xb , &new_yb ) ;
2719
2720 /* make sure (xa,ya) is before (xb,yb) */
2721
2722 ii = MIN(new_xa,new_xb); jj = MAX(new_xa,new_xb); new_xa = ii; new_xb = jj;
2723 ii = MIN(new_ya,new_yb); jj = MAX(new_ya,new_yb); new_ya = ii; new_yb = jj;
2724
2725 new_xa += dxa ; new_xb += dxb ; /* NOW adjust crop window coords */
2726 new_ya += dya ; new_yb += dyb ; /* in screen coords, not image */
2727
2728 ISQ_flipxy( seq , &new_xa , &new_ya ) ; /* flip back to image coords */
2729 ISQ_flipxy( seq , &new_xb , &new_yb ) ;
2730
2731 /* make sure (xa,ya) is before (xb,yb) */
2732
2733 ii = MIN(new_xa,new_xb); jj = MAX(new_xa,new_xb); new_xa = ii; new_xb = jj;
2734 ii = MIN(new_ya,new_yb); jj = MAX(new_ya,new_yb); new_ya = ii; new_yb = jj;
2735
2736 } /* new_?? variables now contain image coords of new crop region */
2737
2738 /* check for bad-ositiness */
2739
2740 if( new_xa < 0 || new_ya < 0 ) EXRETURN ; /* all these are bad */
2741 if( new_xa+MINCROP >= new_xb ) EXRETURN ;
2742 if( new_ya+MINCROP >= new_yb ) EXRETURN ;
2743 if( new_xb >= seq->crop_nxorg ) EXRETURN ;
2744 if( new_yb >= seq->crop_nyorg ) EXRETURN ;
2745
2746 /* now apply the new crop window coordinates */
2747
2748 seq->crop_xa = new_xa ; seq->crop_xb = new_xb ;
2749 seq->crop_ya = new_ya ; seq->crop_yb = new_yb ;
2750 if( doit ) ISQ_redisplay( seq , -1 , isqDR_display ) ;
2751 EXRETURN ;
2752 }
2753
2754 /*---------------------------------------------------------------------*/
2755
ISQ_set_crop_hint(MCW_imseq * seq)2756 void ISQ_set_crop_hint( MCW_imseq *seq )
2757 {
2758 if( !ISQ_REALZ(seq) ) return ;
2759
2760 if( !seq->cropit ){
2761 MCW_register_hint( seq->crop_drag_pb , "Crop image" ) ;
2762 } else {
2763 static char str[256] ;
2764 sprintf(str,"Crop image: %d..%d[w=%d] X %d..%d[h=%d]" ,
2765 seq->crop_xa , seq->crop_xb , seq->crop_xb-seq->crop_xa+1 ,
2766 seq->crop_ya , seq->crop_yb , seq->crop_yb-seq->crop_ya+1 ) ;
2767 MCW_register_hint( seq->crop_drag_pb , str ) ;
2768 }
2769
2770 return ;
2771 }
2772
2773 /*---------------------------------------------------------------------
2774 Handle the user's action on the Button 3 popup on the crop button
2775 -----------------------------------------------------------------------*/
2776
ISQ_butcrop_choice_CB(Widget w,XtPointer client_data,MCW_choose_cbs * cbs)2777 void ISQ_butcrop_choice_CB( Widget w , XtPointer client_data ,
2778 MCW_choose_cbs *cbs )
2779 {
2780 MCW_imseq *seq = (MCW_imseq *)client_data ;
2781 float *vec = (float *)(cbs->cval) ;
2782 int ww , hh , new_xa , new_xb , new_ya , new_yb , oww,ohh ;
2783
2784 if( !ISQ_REALZ(seq) || vec == NULL ) return ;
2785
2786 ww = (int)vec[0] ; hh = (int)vec[1] ;
2787
2788 if( seq->cropit && seq->crop_nxorg > 0 ){
2789 oww = seq->crop_nxorg ; ohh = seq->crop_nyorg ;
2790 } else {
2791 oww = seq->horig ; ohh = seq->vorig ;
2792 }
2793
2794 if( ww < MINCROP || hh < MINCROP ) return ;
2795 if( ww >= oww || hh >= ohh ) return ;
2796
2797 new_xa = (oww - ww) / 2 ; new_xb = new_xa + ww-1 ;
2798 new_ya = (ohh - hh) / 2 ; new_yb = new_ya + hh-1 ;
2799
2800 if( new_xa < 0 ) return ;
2801 if( new_ya < 0 ) return ;
2802 if( new_xa+MINCROP >= new_xb ) return ;
2803 if( new_ya+MINCROP >= new_yb ) return ;
2804 if( new_xb >= oww ) return ;
2805 if( new_yb >= ohh ) return ;
2806
2807 seq->crop_xa = new_xa ; seq->crop_xb = new_xb ;
2808 seq->crop_ya = new_ya ; seq->crop_yb = new_yb ;
2809 seq->cropit = 1 ;
2810 ISQ_redisplay( seq , -1 , isqDR_display ) ;
2811 return ;
2812 }
2813
2814 /*--------------------------------------------------------------------
2815 Button 3 action for Disp button [17 Jun 2011]
2816 ----------------------------------------------------------------------*/
2817
ISQ_butdisp_EV(Widget w,XtPointer client_data,XEvent * ev,RwcBoolean * continue_to_dispatch)2818 void ISQ_butdisp_EV( Widget w , XtPointer client_data ,
2819 XEvent *ev , RwcBoolean *continue_to_dispatch )
2820 {
2821 MCW_imseq *seq = (MCW_imseq *)client_data ;
2822
2823 if( !ISQ_REALZ(seq) ) return ;
2824 ISQ_timer_stop(seq) ;
2825
2826 switch( ev->type ){
2827 default: break ;
2828 case ButtonPress:{
2829 XButtonEvent *event = (XButtonEvent *)ev ;
2830 if( event->button == Button3 && seq->status->send_CB != NULL ){
2831 ISQ_cbs cbs ;
2832 cbs.reason = isqCR_raiseupthedead ; SEND(seq,cbs) ;
2833 } else if( event->button == Button2 ){
2834 XBell(XtDisplay(w),100) ;
2835 MCW_popup_message( w, " \n Don't! \n " , MCW_USER_KILL|MCW_QUICK_KILL );
2836 } else if( event->button == Button4 ){
2837 MCW_popup_message( w, " \n That tickles! \n " , MCW_USER_KILL|MCW_QUICK_KILL ) ;
2838 } else if( event->button == Button5 ){
2839 MCW_popup_message( w, " \n Please stop \n " , MCW_USER_KILL|MCW_QUICK_KILL ) ;
2840 }
2841 }
2842 break ;
2843 }
2844 return ;
2845 }
2846
2847 /*--------------------------------------------------------------------
2848 make Button 3 popup for Crop button
2849 ----------------------------------------------------------------------*/
2850
ISQ_butcrop_EV(Widget w,XtPointer client_data,XEvent * ev,RwcBoolean * continue_to_dispatch)2851 void ISQ_butcrop_EV( Widget w , XtPointer client_data ,
2852 XEvent *ev , RwcBoolean *continue_to_dispatch )
2853 {
2854 MCW_imseq *seq = (MCW_imseq *)client_data ;
2855
2856 if( !ISQ_REALZ(seq) ) return ;
2857 ISQ_timer_stop(seq) ;
2858
2859 switch( ev->type ){
2860 default: break ;
2861 case ButtonPress:{
2862 XButtonEvent *event = (XButtonEvent *) ev ;
2863 if( event->button == Button3 ){
2864 char *lvec[2] = { "Width " , "Height" } ;
2865 float fvec[2] ; int oww=0,ohh=0 ;
2866 if( seq->cropit ){
2867 oww = seq->crop_xb -seq->crop_xa + 1 ;
2868 ohh = seq->crop_yb -seq->crop_ya + 1 ;
2869 }
2870 if( oww < MINCROP ) oww = seq->horig / 2 ;
2871 if( ohh < MINCROP ) ohh = seq->vorig / 2 ;
2872 if( oww < MINCROP ) oww = MINCROP ;
2873 if( ohh < MINCROP ) ohh = MINCROP ;
2874 fvec[0] = oww ; fvec[1] = ohh ;
2875 if( oww >= MINCROP && ohh >= MINCROP ){
2876 MCW_choose_vector(
2877 seq->crop_drag_pb ,
2878 "--------------------------------------------\n"
2879 "Choose width and height of image crop window\n"
2880 " (minimum allowed size is 9 pixels)\n"
2881 " Crop window will be centered on image:\n"
2882 " Adjust with Shift+Keypad_Arrow_Keys.\n"
2883 "--------------------------------------------" ,
2884 2 , lvec , fvec , ISQ_butcrop_choice_CB , (XtPointer)seq ) ;
2885 }
2886
2887 } else if( event->button == Button2 ){
2888 XBell(XtDisplay(w),100) ;
2889 MCW_popup_message( w,
2890 lrand48()%2 == 0 ? " \n Ooch! \n "
2891 : "Don't\n DO\nthat!" ,
2892 MCW_USER_KILL|MCW_QUICK_KILL );
2893 /** AFNI_speak( "Ouch!" , 0 ) ; **/
2894 }
2895 }
2896 break ;
2897 }
2898 return ;
2899 }
2900
2901 /*-----------------------------------------------------------------------*/
2902 /* Convert a short image of indexes into color tables to RGB.
2903 overlay != 0 ==> use overlay color table only
2904 otherwise, use underlay table for positive values
2905 and use overlay table for netative values
2906 *//*---------------------------------------------------------------------*/
2907
ISQ_index_to_rgb(MCW_DC * dc,int overlay,MRI_IMAGE * im)2908 MRI_IMAGE * ISQ_index_to_rgb( MCW_DC *dc , int overlay , MRI_IMAGE *im ) /* 07 Mar 2001 */
2909 {
2910 register int npix,ii,jj ;
2911 MRI_IMAGE *outim ;
2912 register byte *our ;
2913 register short *iar ;
2914
2915 ENTRY("ISQ_short_to_rgb") ;
2916
2917 if( dc == NULL || im == NULL || im->kind != MRI_short ) RETURN(NULL) ;
2918
2919 npix = im->nvox ;
2920 iar = MRI_SHORT_PTR(im) ;
2921 outim = mri_new_conforming( im , MRI_rgb ) ;
2922 our = MRI_RGB_PTR(outim) ;
2923
2924 if( !overlay ){
2925 for( jj=ii=0 ; ii < npix ; ii++,jj+=3 ){
2926 if( iar[ii] >= 0 ){ /* pos => underlay table */
2927 our[jj ] = DC_REDBYTE (dc,iar[ii]) ;
2928 our[jj+1] = DC_GREENBYTE(dc,iar[ii]) ;
2929 our[jj+2] = DC_BLUEBYTE (dc,iar[ii]) ;
2930 } else { /* neg => overlay table */
2931 our[jj ] = DCOV_REDBYTE (dc,-iar[ii]) ;
2932 our[jj+1] = DCOV_GREENBYTE(dc,-iar[ii]) ;
2933 our[jj+2] = DCOV_BLUEBYTE (dc,-iar[ii]) ;
2934 }
2935 }
2936 } else { /* use overlay table only */
2937 for( jj=ii=0 ; ii < npix ; ii++,jj+=3 ){
2938 if( iar[ii] > 0 ){ /* valid overlay index */
2939 our[jj ] = DCOV_REDBYTE(dc,iar[ii]) ;
2940 our[jj+1] = DCOV_GREENBYTE(dc,iar[ii]) ;
2941 our[jj+2] = DCOV_BLUEBYTE(dc,iar[ii]) ;
2942 } else { /* not valid */
2943 our[jj] = our[jj+1] = our[jj+2] = 0 ;
2944 }
2945 }
2946 }
2947
2948 RETURN(outim) ;
2949 }
2950
2951 /*-----------------------------------------------------------------------
2952 Overlay one image onto another. Underlay (ulim) and overlay (ovim)
2953 must be either shorts or rgb. If they are shorts, they are indices
2954 into the underlay and overlay color index tables, respectively.
2955 * Usually the underlay table is grayscale, and the overlay table colors,
2956 but the underlay table can be colors if the user turns 'Colr' on.
2957 The overlay opacity is alpha (0 < alpha <= 1).
2958 If both are shorts and alpha=1, the output is shorts.
2959 If either is rgb, or alpha < 1, then the output is rgb.
2960 If ulim is rgba, then output is rgba [13 Feb 2020].
2961 The output is NULL if the inputs are invalid.
2962 Pixels from ovim are overlaid only if they are NOT zero.
2963 -- 06 Mar 2001 -- RWCox
2964 -------------------------------------------------------------------------*/
2965
ISQ_overlay(MCW_DC * dc,MRI_IMAGE * ulim,MRI_IMAGE * ovim,float alpha)2966 MRI_IMAGE * ISQ_overlay( MCW_DC *dc , MRI_IMAGE *ulim, MRI_IMAGE *ovim, float alpha )
2967 {
2968 register int npix,ii,jj ;
2969 MRI_IMAGE *outim=NULL , *orim ;
2970 register byte *orr, *our ;
2971
2972 ENTRY("ISQ_overlay") ;
2973
2974 if( dc == NULL || ulim == NULL || ovim == NULL || alpha <= 0.0 ) RETURN(NULL) ;
2975
2976 npix = ulim->nvox ;
2977
2978 if( ovim->nvox != npix ) RETURN(NULL) ; /* this is bad - user = loser */
2979
2980 if( alpha > 1.0f ) alpha = 1.0f ; /* stoopid user loser */
2981
2982 /*-- Case: both are short indices, no transparency (alpha == 1) --*/
2983 /*-- output image will be shorts as well --*/
2984
2985 if( ulim->kind == MRI_short && ovim->kind == MRI_short && alpha > 0.99f ){
2986 register short *tar , *oar=MRI_SHORT_PTR(ovim) , *iar=MRI_SHORT_PTR(ulim) ;
2987
2988 outim = mri_new_conforming( ulim , MRI_short ) ;
2989 tar = MRI_SHORT_PTR( outim ) ;
2990 for( ii=0 ; ii < npix ; ii++ )
2991 tar[ii] = (oar[ii] <= 0) ? iar[ii] : -oar[ii] ;
2992
2993 RETURN(outim) ;
2994 }
2995
2996 /*-- Case: underlay input is RGBA [13 Feb 2020] --*/
2997 /*-- output image will be RGBA as well --*/
2998
2999 if( ulim->kind == MRI_rgba ){
3000 outim = ISQ_overlay_rgba( dc , ulim , ovim , alpha ) ;
3001 RETURN(outim) ;
3002 }
3003
3004 /*-- Convert underlay to RGB, if needed --*/
3005 /*-- Output image will be RGB below here --*/
3006
3007 switch( ulim->kind ){ /* we always make a new RGB underlay, */
3008 case MRI_rgb: /* since this will be the output image */
3009 outim = mri_copy(ulim) ;
3010 our = MRI_RGB_PTR(outim) ;
3011 break ;
3012
3013 #if 0 /* should no longer be possible */
3014 case MRI_rgba:
3015 outim = mri_to_rgb(ulim) ;
3016 our = MRI_RGB_PTR(outim) ;
3017 break ;
3018 #endif
3019
3020 default:
3021 RETURN(NULL) ; break ; /* bad bad bad - user should be flogged */
3022
3023 case MRI_short:
3024 outim = ISQ_index_to_rgb( dc , 0 , ulim ) ; /* grayscale from indexes */
3025 our = MRI_RGB_PTR(outim) ;
3026 break ;
3027 }
3028
3029 /*-- overlay conversion --*/
3030
3031 switch( ovim->kind ){ /* but we don't make a new overlay unless needed */
3032 case MRI_rgb:
3033 orim = ovim ; orr = MRI_RGB_PTR(orim) ; break ;
3034
3035 default:
3036 mri_free(outim) ;
3037 RETURN(NULL) ; break ; /* bad bad bad */
3038
3039 case MRI_short:
3040 orim = ISQ_index_to_rgb( dc , 1 , ovim ) ; /* colors from indexes */
3041 orr = MRI_RGB_PTR(orim) ;
3042 break ;
3043
3044 case MRI_rgba:{ /* 08 Dec 2014 */
3045 rgba *ovar = MRI_RGBA_PTR(ovim) ; byte rr,gg,bb,aa ; /* RGBA special case */
3046 register float al=alpha , am,bm ;
3047 for( jj=ii=0 ; ii < npix ; ii++,jj+=3 ){
3048 rr = ovar[ii].r; gg = ovar[ii].g; bb = ovar[ii].b; aa = ovar[ii].a;
3049 if( aa > 0 && (rr > 0 || gg > 0 || bb > 0 ) ){
3050 am = aa*al/255.0f ; bm = 1.0f-am ; /* pixelwise mixing fracs */
3051 our[jj ] = am*rr + bm*our[jj ] ; /* mix colors betwixt ovar */
3052 our[jj+1] = am*gg + bm*our[jj+1] ; /* and our; overwrite our */
3053 our[jj+2] = am*bb + bm*our[jj+2] ;
3054 }
3055 }
3056 RETURN(outim) ;
3057 }
3058 break ;
3059 }
3060
3061 /* now overlay (same mixing frac per pixel) */
3062
3063 if( alpha > 0.99f ){ /* opaque overlay */
3064 for( jj=ii=0 ; ii < npix ; ii++,jj+=3 ){
3065 if( orr[jj] > 0 || orr[jj+1] > 0 || orr[jj+2] > 0 ){
3066 our[jj ] = orr[jj ] ;
3067 our[jj+1] = orr[jj+1] ;
3068 our[jj+2] = orr[jj+2] ;
3069 }
3070 }
3071 } else if (!my_getenv("AFNI_MIX_BY_BRIGHT")) { /* translucent overlay */
3072 register float aa=alpha , bb=1.0-alpha ;
3073 for( jj=ii=0 ; ii < npix ; ii++,jj+=3 ){
3074 if( orr[jj] > 0 || orr[jj+1] > 0 || orr[jj+2] > 0 ){
3075 our[jj ] = aa*orr[jj ] + bb*our[jj ] ; /* mix colors */
3076 our[jj+1] = aa*orr[jj+1] + bb*our[jj+1] ;
3077 our[jj+2] = aa*orr[jj+2] + bb*our[jj+2] ;
3078 }
3079 }
3080 } else { /* mix by scaling color with brightness of background - ZSS */
3081 register float aa=alpha, bb,
3082 mings, maxgs, *gs=NULL,
3083 MaxGain = 2.0-alpha*alpha,
3084 MinGain = alpha*alpha ;
3085 gs = (float *)malloc(sizeof(float)*npix);
3086 /* calculate grey scale, keep track of range */
3087 mings = 255*3.0; maxgs = 0;
3088 for( jj=ii=0 ; ii < npix ; ii++,jj+=3 ){
3089 if( orr[jj] > 0 || orr[jj+1] > 0 || orr[jj+2] > 0 ){
3090 gs[ii] = (our[jj ]+our[jj+1]+orr[jj+2]);
3091 if (gs[ii] < mings) mings = gs[ii];
3092 else if (gs[ii] > maxgs) maxgs = gs[ii];
3093 } else {
3094 gs[ii] = 0.0;
3095 }
3096 }
3097 /* now scale gs values */
3098 bb = (MaxGain - MinGain)/(maxgs-mings);
3099 for( ii=0 ; ii < npix ; ii++ ){
3100 if( gs[ii] ) gs[ii] = bb * (gs[ii]-mings)+MinGain;
3101 }
3102 for( jj=ii=0 ; ii < npix ; ii++,jj+=3 ){
3103 if( gs[ii] ){ /* Colors will change here, not just a brightness
3104 modulation. Need much fancier method to deal
3105 with mixing appropriately */
3106 bb = (gs[ii])*orr[jj ] ; /* mix colors */
3107 if (bb > 255) our[jj ] = 255; else our[jj ] = (byte)bb;
3108 bb = (gs[ii])*orr[jj+1] ;
3109 if (bb > 255) our[jj+1] = 255; else our[jj+1] = (byte)bb;
3110 bb = (gs[ii])*orr[jj+2] ;
3111 if (bb > 255) our[jj+2] = 255; else our[jj+2] = (byte)bb;
3112 }
3113 }
3114 free(gs); gs=NULL;
3115 }
3116
3117 if( orim != ovim ) mri_free(orim) ; /* destroy copy of overlay, if any */
3118
3119 RETURN(outim) ;
3120 }
3121
3122 /*-----------------------------------------------------------------------*/
3123 /* Always produce RGBA output [13 Feb 2020] */
3124
ISQ_overlay_rgba(MCW_DC * dc,MRI_IMAGE * ulim,MRI_IMAGE * ovim,float alpha)3125 MRI_IMAGE * ISQ_overlay_rgba( MCW_DC *dc , MRI_IMAGE *ulim, MRI_IMAGE *ovim, float alpha )
3126 {
3127 register int npix,ii,jj ;
3128 MRI_IMAGE *outim , *ulimNEW , *ovimNEW , *qim ;
3129 rgba *outar , *ular , *ovar ;
3130 int jill = AFNI_yesenv("AFNI_JILL_TRAVESTY") ; /* Jill is trouble */
3131
3132 ENTRY("ISQ_overlay_rgba") ;
3133
3134 if( dc == NULL || ulim == NULL || ovim == NULL || alpha <= 0.0 ) RETURN(NULL) ;
3135
3136 npix = ulim->nvox ;
3137
3138 if( ovim->nvox != npix ) RETURN(NULL) ; /* this is bad */
3139
3140 if( alpha > 1.0f ) alpha = 1.0f ; /* stoopid user */
3141
3142 /*-- Convert both inputs to RGBA, if needed --*/
3143
3144 switch( ulim->kind ){
3145 default:
3146 if( jill ) ININFO_message(" - underlay = ILLEGAL type") ;
3147 RETURN(NULL) ; break ; /* bad bad bad */
3148
3149 case MRI_rgba: /* no conversion needed */
3150 ulimNEW = ulim ;
3151 if( jill ) ININFO_message(" - underlay = RGBA");
3152 break ;
3153
3154 case MRI_rgb:
3155 ulimNEW = mri_to_rgba(ulim) ;
3156 if( jill ) ININFO_message(" - underlay = RGB to RGBA");
3157 break ;
3158
3159 case MRI_short:
3160 qim = ISQ_index_to_rgb( dc , 1 , ulim ) ; /* colors from indexes */
3161 ulimNEW = mri_to_rgba(qim) ; /* NOT grayscale */
3162 mri_free(qim) ;
3163 if( jill ) ININFO_message(" - underlay = SHORT to RGBA");
3164 break ;
3165 }
3166
3167 outim = mri_copy(ulimNEW) ; /* initial output = copy of underlay input */
3168 outar = MRI_RGBA_PTR(outim) ;
3169 ular = MRI_RGBA_PTR(ulimNEW) ;
3170
3171 /*-- conversion of the overlay input image --*/
3172
3173 switch( ovim->kind ){
3174 case MRI_rgba: /* no conversion needed */
3175 ovimNEW = ovim ;
3176 if( jill ) ININFO_message(" - overlay = RGBA");
3177 break ;
3178
3179 case MRI_rgb:
3180 ovimNEW = mri_to_rgba(ovim) ;
3181 if( jill ) ININFO_message(" - overlay = RGB to RGBA");
3182 break ;
3183
3184 default: /* bad bad bad */
3185 mri_free(outim) ;
3186 if( ulimNEW != ulim ) mri_free(ulimNEW) ;
3187 if( jill ) ININFO_message(" - overlay = ILLEGAL type") ;
3188 RETURN(NULL) ; break ;
3189
3190 case MRI_short:
3191 qim = ISQ_index_to_rgb( dc , 1 , ovim ) ; /* colors from indexes */
3192 ovimNEW = mri_to_rgba(qim) ;
3193 mri_free(qim) ;
3194 if( jill ) ININFO_message(" - overlay = SHORT to RGBA");
3195 break ;
3196 }
3197
3198 ovar = MRI_RGBA_PTR(ovimNEW) ;
3199
3200 /* merger of RGBA data -- see
3201 https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending */
3202
3203 if( jill ) ININFO_message(" - begin alpha blending") ;
3204
3205 { float al=alpha , oam,obm , uuu ;
3206 byte orr,ogg,obb,oaa , urr,ugg,ubb,uaa ; int n1=0,n2=0,n3=0 ;
3207 for( ii=0 ; ii < npix ; ii++ ){
3208 orr = ovar[ii].r; ogg = ovar[ii].g; obb = ovar[ii].b; oaa = ovar[ii].a;
3209 urr = ular[ii].r; ugg = ular[ii].g; ubb = ular[ii].b; uaa = ular[ii].a;
3210 if( oaa > 0 && (orr > 0 || ogg > 0 || obb > 0 ) ){
3211 oam = oaa*al/255.0f ; obm = 1.0f-oam ; /* mixing fracs for overlay */
3212 if( oam > 0.99f ){ /* opaque overlay */
3213 outar[ii].r = orr ;
3214 outar[ii].g = ogg ;
3215 outar[ii].b = obb ;
3216 outar[ii].a = 255 ; n1++ ;
3217 } else if( uaa > 252 ){ /* opaque underlay */
3218 outar[ii].r = (byte)(oam*orr + obm*urr + 0.4f) ;
3219 outar[ii].g = (byte)(oam*ogg + obm*ugg + 0.4f) ;
3220 outar[ii].b = (byte)(oam*obb + obm*ubb + 0.4f) ;
3221 outar[ii].a = 255 ; n2++ ;
3222 } else { /* non-opaque underlay */
3223 obm *= (uaa/255.0f) ; /* shrink obm */
3224 uuu = oam + obm ;
3225 oam = oam / uuu ; obm = 1.0f-oam ;
3226 outar[ii].r = (byte)(oam*orr + obm*urr + 0.4f) ;
3227 outar[ii].g = (byte)(oam*ogg + obm*ugg + 0.4f) ;
3228 outar[ii].b = (byte)(oam*obb + obm*ubb + 0.4f) ;
3229 outar[ii].a = (byte)(255.0f*uuu+0.4f) ; n3++ ;
3230 }
3231 }
3232 }
3233 if( jill ) ININFO_message(" - images merged: n1=%d n2=%d n3=%d npix=%d",n1,n2,n3,npix) ;
3234 }
3235
3236 if( ulimNEW != ulim ) mri_free(ulimNEW) ; /* only toss them if they */
3237 if( ovimNEW != ovim ) mri_free(ovimNEW) ; /* aren't the actual inputs */
3238
3239 RETURN(outim) ;
3240 }
3241
3242 /*-----------------------------------------------------------------------*/
3243 /* Produce a 0-1 mask from an overlay-type dataset */
3244
ISQ_binarize_overlay(MRI_IMAGE * tim)3245 MRI_IMAGE * ISQ_binarize_overlay( MRI_IMAGE *tim ) /* Mar 2013 */
3246 {
3247 MRI_IMAGE *bim ; byte *bar ;
3248 int npix ;
3249
3250 ENTRY("ISQ_binarize_overlay") ;
3251
3252 if( tim == NULL || !ISQ_GOOD_OVERLAY_TYPE(tim->kind) ) RETURN(NULL) ;
3253
3254 npix = tim->nvox ;
3255 bim = mri_new_conforming(tim,MRI_byte) ; bar = MRI_BYTE_PTR(bim) ;
3256
3257 switch( tim->kind ){
3258
3259 default: mri_free(bim) ; RETURN(NULL) ; /* should be impossible */
3260
3261 case MRI_short:{
3262 short *tar = MRI_SHORT_PTR(tim) ; int ii ;
3263 for( ii=0 ; ii < npix ; ii++ )
3264 bar[ii] = (tar[ii] > 0) ;
3265 }
3266 break ;
3267
3268 case MRI_rgb:{
3269 byte *tar = MRI_RGB_PTR(tim) ; int ii,jj ;
3270 for( ii=jj=0 ; ii < npix ; ii++,jj+=3 )
3271 bar[ii] = ( tar[jj] > 0 || tar[jj+1] > 0 || tar[jj+2] > 0 ) ;
3272 }
3273 break ;
3274
3275 case MRI_rgba:{ /* Oops, forgot about this [18 Aug 2020] */
3276 rgba *tar = MRI_RGBA_PTR(tim) ; int ii ;
3277 for( ii=0 ; ii < npix ; ii++ ){
3278 bar[ii] = ( tar[ii].a > 254 ) &&
3279 ( tar[ii].r > 0 || tar[ii].g > 0 || tar[ii].b > 0 ) ;
3280 }
3281 }
3282 break ;
3283
3284 }
3285
3286 RETURN(bim) ;
3287 }
3288
3289 /*-----------------------------------------------------------------------
3290 Make a color bar "given" XImage, for display next to the image
3291 viewer. Here, the MRI_IMAGE is just the short-valued indexes
3292 into the color map, which mri_to_XImage() will convert to
3293 the actual colors for pushing out the window.
3294 -------------------------------------------------------------------------*/
3295
ISQ_make_bar(MCW_imseq * seq)3296 void ISQ_make_bar( MCW_imseq *seq )
3297 {
3298 MRI_IMAGE *im ;
3299 int iy , ny ;
3300 short *ar ;
3301
3302 ENTRY("ISQ_make_bar") ;
3303
3304 if( ! ISQ_VALID(seq) ) EXRETURN ;
3305
3306 KILL_2XIM( seq->given_xbar , seq->sized_xbar ) ;
3307
3308 ny = seq->dc->ncol_im ;
3309 im = mri_new( 1 , ny , MRI_short ) ;
3310 ar = mri_data_pointer( im ) ;
3311 for( iy=0 ; iy < ny ; iy++ ) ar[iy] = ny-1-iy ;
3312
3313 seq->given_xbar = mri_to_XImage( seq->dc , im ) ;
3314
3315 KILL_1MRI( im ) ;
3316 EXRETURN ;
3317 }
3318
3319 /*------------------------------------------------------------------------*/
3320 /* Apply a binary mask to an image iim */
3321
ISQ_apply_mask(MRI_IMAGE * maskim,MRI_IMAGE * iim)3322 void ISQ_apply_mask( MRI_IMAGE *maskim , MRI_IMAGE *iim )
3323 {
3324 byte *mmm ; int ii , npix ;
3325
3326 if( maskim == NULL || maskim->kind != MRI_byte || iim == NULL ) return ;
3327 npix = iim->nvox ; if( maskim->nvox != npix ) return ;
3328 mmm = MRI_BYTE_PTR(maskim) ; if( mmm == NULL ) return ;
3329
3330 switch( iim->kind ){
3331 default: break ;
3332 case MRI_byte:{
3333 byte *ar = mri_data_pointer(iim) ;
3334 for( ii=0 ; ii < npix ; ii++ ) if( mmm[ii] == 0 ) ar[ii] = 0 ;
3335 }
3336 return ;
3337
3338 case MRI_short:{
3339 short *ar = mri_data_pointer(iim) ;
3340 for( ii=0 ; ii < npix ; ii++ ) if( mmm[ii] == 0 ) ar[ii] = 0 ;
3341 }
3342 return ;
3343
3344 case MRI_float:{
3345 float *ar = mri_data_pointer(iim) ;
3346 for( ii=0 ; ii < npix ; ii++ ) if( mmm[ii] == 0 ) ar[ii] = 0 ;
3347 }
3348 return ;
3349
3350 case MRI_rgb:{
3351 byte *ar = mri_data_pointer(iim) ;
3352 for( ii=0 ; ii < npix ; ii++ ) if( mmm[ii] == 0 ) ar[3*ii] = ar[3*ii+1] = ar[3*ii+2] = 0 ;
3353 }
3354 return ;
3355
3356 case MRI_rgba:{
3357 rgba *ar = mri_data_pointer(iim) ;
3358 for( ii=0 ; ii < npix ; ii++ ) if( mmm[ii] == 0 ) ar[ii].r = ar[ii].g = ar[ii].b = ar[ii].a = 0 ;
3359 }
3360 return ;
3361
3362 case MRI_complex:{
3363 complex *ar = mri_data_pointer(iim) ;
3364 for( ii=0 ; ii < npix ; ii++ ) if( mmm[ii] == 0 ) ar[ii].r = ar[ii].i = 0 ;
3365 }
3366 return ;
3367 }
3368
3369 return ; /* should never be reached */
3370 }
3371
3372
3373 /*------------------------------------------------------------------------
3374 make the MRI_IMAGE and the XImage, given the sequence status:
3375 - if imim is NULL, get it from the user routine and process it,
3376 if imim is not NULL, leave it alone
3377 - convert into an XImage
3378 - here is where changes to the toggled display options are processed
3379 -------------------------------------------------------------------------*/
3380
ISQ_make_image(MCW_imseq * seq)3381 void ISQ_make_image( MCW_imseq *seq )
3382 {
3383 MRI_IMAGE *im , *ovim , *tim ;
3384 RwcBoolean reset_done = False ;
3385 float vfac = VGFAC(seq) ;
3386
3387 ENTRY("ISQ_make_image") ;
3388
3389 if( ! ISQ_VALID(seq) ) EXRETURN ;
3390
3391 /*-- if doing a montage, make it in a separate function --*/
3392
3393 if( seq->mont_nx > 1 || seq->mont_ny > 1 ){
3394 ISQ_make_montage( seq ) ;
3395 EXRETURN ;
3396 }
3397
3398 KILL_2XIM( seq->given_xim , seq->sized_xim ) ; /* erase the XImages */
3399
3400 if( seq->mplot != NULL ){ /* 19 Sep 2001 */
3401 delete_memplot( seq->mplot ) ; seq->mplot = NULL ;
3402 }
3403
3404 /* process toggled options that affect the image that may be stored */
3405
3406 if( seq->opt.rot != seq->old_opt.rot ||
3407 seq->opt.mirror != seq->old_opt.mirror ||
3408 seq->opt.scale_group != seq->old_opt.scale_group ||
3409 seq->opt.scale_range != seq->old_opt.scale_range ||
3410 seq->mont_nx != seq->mont_nx_old ||
3411 seq->mont_ny != seq->mont_ny_old ){
3412
3413 KILL_1MRI( seq->imim ) ; /* must re-get image for new processing */
3414 KILL_1MRI( seq->ovim ) ;
3415 }
3416
3417 /*--- set the image to process ---*/
3418
3419 im = seq->imim ;
3420
3421 if( im == NULL ){
3422 float new_width_mm , new_height_mm ;
3423
3424 switch( seq->render_mode ){
3425 default:
3426 tim = ISQ_getimage( seq->im_nr , seq ) ; /* might be cropped */
3427 if( tim == NULL ) EXRETURN ;
3428 seq->last_image_type = tim->kind ;
3429 seq->set_orim = (seq->need_orim != 0) ; /* 30 Dec 1998 */
3430 seq->imim = im = ISQ_process_mri( seq->im_nr , seq , tim , 0 ) ;
3431 KILL_1MRI(tim) ;
3432 seq->set_orim = 0 ;
3433 seq->barbot = seq->clbot ; /* 29 Jul 2001 */
3434 seq->bartop = seq->cltop ;
3435 break ;
3436
3437 case RENDER_WIPE_LEFT: /* WIPE stuff 22 Aug 2014 */
3438 case RENDER_WIPE_BOT:
3439 case RENDER_MIX:
3440 case RENDER_WIPE_RIGHT:
3441 case RENDER_WIPE_TOP:
3442 case RENDER_CHECK_UO:
3443 case RENDER_CHECK_OU:
3444 seq->set_orim = 0 ;
3445 seq->imim = im = ISQ_getchecked( seq->im_nr ,seq ) ;
3446 if( im == NULL ) EXRETURN ;
3447 seq->last_image_type = im->kind ;
3448 seq->barbot = seq->bartop = 0.0f ;
3449 break ;
3450 }
3451 ISQ_set_barhint(seq,NULL) ;
3452
3453 /* fix window dimensions if image size is different from before */
3454
3455 new_width_mm = IM_WIDTH(im) ;
3456 new_height_mm = IM_HEIGHT(im) ;
3457
3458 seq->horig = im->nx ; seq->last_dx = fabs(im->dx) ;
3459 seq->vorig = im->ny ; seq->last_dy = fabs(im->dy) ;
3460
3461 if( FLDIF(new_width_mm ,seq->last_width_mm ) ||
3462 FLDIF(new_height_mm,seq->last_height_mm) ){
3463
3464 if( PRINT_TRACING ){
3465 char str[256] ;
3466 sprintf(str,"nx=%d ny=%d dx=%f dy=%f wid=%f hei=%f",
3467 im->nx,im->ny,im->dx,im->dy,new_width_mm,new_height_mm) ;
3468 STATUS(str) ;
3469 }
3470
3471 ISQ_reset_dimen( seq , new_width_mm , new_height_mm ) ;
3472 reset_done = True ;
3473 }
3474 }
3475
3476 if( seq->opt.free_aspect != seq->old_opt.free_aspect && !reset_done )
3477 ISQ_reset_dimen( seq , seq->last_width_mm , seq->last_height_mm ) ;
3478
3479 /*--- set the overlay to process ---*/
3480
3481 if( ISQ_SKIP_OVERLAY(seq) ){
3482 KILL_1MRI( seq->ovim ) ;
3483 ovim = NULL ;
3484 } else {
3485 char *lab ; /* 20 Sep 2001 */
3486 byte *mmm=NULL ; /* 12 Dec 2014 */
3487
3488 ovim = seq->ovim ;
3489 if( ovim == NULL ){
3490 tim = ISQ_getoverlay( seq->im_nr , seq ) ;
3491 if( tim != NULL && !ISQ_GOOD_OVERLAY_TYPE(tim->kind) ){
3492 fprintf(stderr,"\a\n*** Illegal overlay image kind=%d! ***\n",(int)tim->kind) ;
3493 KILL_1MRI(tim) ;
3494 }
3495 if( tim != NULL )
3496 ovim = seq->ovim =
3497 mri_flippo( ISQ_TO_MRI_ROT(seq->opt.rot) , seq->opt.mirror , tim ) ;
3498 if( tim != ovim ) KILL_1MRI(tim) ;
3499 ISQ_apply_mask( seq->last_automask , ovim ) ;
3500 }
3501
3502 /*-- 19 Sep 2001: get an overlay plot, if there is one --*/
3503
3504 if( MCW_val_bbox(seq->wbar_plots_bbox) != 0 ){
3505 seq->mplot = ISQ_getmemplot( seq->im_nr , seq ) ;
3506 if( seq->mplot != NULL )
3507 flip_memplot( ISQ_TO_MRI_ROT(seq->opt.rot),seq->opt.mirror, seq->mplot );
3508 }
3509
3510 /*-- 20 Sep 2001: get a label, if there is one --*/
3511
3512 if( seq->wbar_label_av->ival != 0 ){
3513 lab = ISQ_getlabel( seq->im_nr , seq ) ;
3514 if( lab != NULL ){
3515 MEM_plotdata *mp = ISQ_plot_label( seq , lab ) ;
3516 if( mp != NULL ){
3517 if( seq->mplot != NULL ){
3518 append_to_memplot( seq->mplot , mp ) ; delete_memplot( mp ) ;
3519 } else {
3520 seq->mplot = mp ;
3521 }
3522 }
3523 free(lab) ;
3524 }
3525 }
3526
3527 } /* end of overlay-osity */
3528
3529 /* set old_opt to current options */
3530
3531 seq->old_opt = seq->opt ;
3532
3533 seq->mont_nx_old = seq->mont_ny_old = 1 ;
3534
3535 STATUS("making given_xim");
3536
3537 /* overlay, if needed */
3538
3539 if( ovim == NULL || ISQ_SKIP_OVERLAY(seq) ){ /* nothing to do */
3540 tim = im ;
3541 } else { /* 06 Mar 2001 */
3542 tim = ISQ_overlay( seq->dc, im, ovim, seq->ov_opacity ) ;
3543 if( tim == NULL ) tim = im ; /* shouldn't happen */
3544 }
3545
3546 if( vfac > 0.0f ){ /* the Van Gogh effect - just for fun, not for science! */
3547 MRI_IMAGE *qim ;
3548 MCW_invert_widget(seq->wbut_bot[NBUT_DISP]) ;
3549 vgize_sigfac = vfac ; qim = mri_vgize(tim) ;
3550 MCW_invert_widget(seq->wbut_bot[NBUT_DISP]) ;
3551 if( qim != NULL ){
3552 if( tim != im ) KILL_1MRI(tim);
3553 tim = qim;
3554 }
3555 }
3556
3557 /* convert result to XImage for display */
3558
3559 STATUS("converting to XImage") ;
3560 seq->given_xim = mri_to_XImage( seq->dc , tim ) ;
3561
3562 if( tim != im ) KILL_1MRI(tim) ;
3563
3564 EXRETURN ;
3565 }
3566
3567 /*-----------------------------------------------------------------------
3568 Plot a label into a structure for later display
3569 -------------------------------------------------------------------------*/
3570
ISQ_plot_label(MCW_imseq * seq,char * lab)3571 MEM_plotdata * ISQ_plot_label( MCW_imseq *seq , char *lab )
3572 {
3573 MEM_plotdata *mp ; int ww , nlin ; float asp , dd ;
3574 static int sz[6] = { 12 , 20 , 28 , 40 , 56 , 80 } ;
3575 static float th[6] = { 0.001f , 0.002f, 0.003f, 0.004f, 0.005f, 0.007f } ;
3576 char *eee ; float rr=1.0f,gg=1.0f,bb=0.7f , sb=0.003f , thk ;
3577
3578 ENTRY("ISQ_plot_label") ;
3579
3580 if( !ISQ_REALZ(seq) || lab == NULL || lab[0] == '\0' ) RETURN(NULL) ;
3581
3582 asp = 1.0f ; /* aspect ratio of plot */
3583
3584 /** In the following, all coordinates are in the 'units'
3585 where the plot window runs over (x,y) = [0..1,0..asp] */
3586
3587 /* set character size (units = 0.001 of plot width) */
3588
3589 ww = sz[seq->wbar_labsz_av->ival] ;
3590 if( asp > 1.0f ) ww = (int)(ww/asp+0.5f) ;
3591
3592 thk = th[seq->wbar_labsz_av->ival] ; /* line thickness */
3593
3594 /* find number of lines in label [15 Jul 2021] */
3595
3596 nlin = 1 ;
3597 for( eee=lab ; *eee != '\0' ; eee++ ){
3598 if( *eee == '\n' || strncmp(eee,"\\newline",8) == 0 ) nlin++ ;
3599 }
3600
3601 /* get the setback from edge in x direction [default = 0.003 * plot width] */
3602
3603 eee = getenv("AFNI_IMAGE_LABEL_SETBACK") ;
3604 if( eee != NULL ){
3605 float ss = strtod(eee,NULL) ;
3606 if( ss >= 0.0 && ss < 0.5 ) sb = ss ;
3607 }
3608
3609 /** AFNI_REPLACE_XDRAWLINES ; **/
3610
3611 /* If string is 'long':
3612 create a temporary memplot to draw string into to get it bounding box;
3613 then use that box to change the drawing scale if the box is too wide. */
3614
3615 #define TSIZ 4 /* smallest font size pwritf will take is 4 */
3616 if( strlen(lab) > 9 ){ /* 19 Aug 2021 */
3617 float_quad bbox ; float xsiz,ysiz,test ;
3618 create_memplot_surely( "JunkPlot" , asp ) ;
3619 plotpak_pwritf( 0.01,0.5 , lab , TSIZ , 0 , -1 ) ;
3620 mp = get_active_memplot() ;
3621 bbox = memplot_bbox( mp ) ; /* min and max x,y coords */
3622 delete_memplot( mp ) ;
3623 xsiz = bbox.b - bbox.a ; /* ysiz = bbox.d - bbox.c ; */
3624 test = (ww*xsiz)/TSIZ ;
3625 if( test > 0.97f ){ /* too wide ==> shrink font */
3626 int wwnew = (int)(TSIZ/xsiz) ;
3627 if( wwnew < ww ) ww = wwnew ; /* don't go up */
3628 if( ww < 8 ) ww = 8 ; /* smallest font */
3629 if( test > 1.111f ) thk /= test ; /* thinner strokes */
3630 }
3631 }
3632
3633 dd = 0.0007f*ww*(nlin+0.123f) ; /* offset from edge in y direction */
3634
3635 /* create a blank plot to be drawn into (the output from this func);
3636 this plot will be merged with other overlay plots at a later date */
3637
3638 create_memplot_surely( "Ilabelplot" , asp ) ;
3639
3640 set_thick_memplot(thk) ;
3641 set_opacity_memplot(1.0f) ;
3642
3643 /* get the [initial] color to plot with */
3644 /* colors in coxplot are RGB triples, values from 0.0 to 1.0 */
3645 /* [note: the string might contain color changing commands!] */
3646
3647 eee = getenv("AFNI_IMAGE_LABEL_COLOR") ;
3648 if( eee != NULL ) DC_parse_color( seq->dc , eee , &rr,&gg,&bb ) ;
3649 set_color_memplot(rr,gg,bb) ;
3650
3651 /* plot the label */
3652
3653 /** Arguments to plotpak_pwritf(xx,yy,ch,isiz,ior,icent):
3654 xx = x coordinate of string start
3655 yy = y coordinate of string start
3656 ch = character string
3657 isiz = size of characters in units of 0.001 * plot width
3658 ior = orientation in degrees (0 = horizontal text)
3659 icent = centering code (assuming ior==0==horizontal text)):
3660 First, the size of the box that contains the string
3661 is computed, running from (xbot..xtop,ybot..ytop)
3662 Note that xbot is usually 0, but ybot might be negative
3663 due to descenders (e.g., 'y').
3664 Second, the origin of box is moved to (xorg,yorg)
3665 icent == -1 ==> xorg = xx+xbot yorg = yy+(ybot+ytop)/2
3666 ==> text centered in the y direction about yy
3667 text starts at xx (left justified)
3668 icent == 0 ==> xorg = xx+(xbot+xtop)/2 yorg = yy+(ybot+ytop)/2
3669 text is centered in x and y directions about (xx,yy)
3670 icent == 1 ==> xorg = xx+xtop yorg = yy+(ybot+ytop)/2
3671 ==> text centered in the y direction about yy
3672 text ends at xx (right justified)
3673 icent == -3 ==> xorg = xx+max(xbot,0) yorg = yy+max(ybot,0)
3674 ==> text lower left corner starts at (xx,yy)
3675 Why is this so intricate and non-intuitive?
3676 It's a hangover from the original NCAR graphics code,
3677 which was code for driving pen plotters, and this library was
3678 written by the pre-Zhark RWC to emulate NCAR graphics for non-pen devices.
3679 Which also explains why these are line-drawn characters, not from fonts :( */
3680
3681 switch( seq->wbar_label_av->ival ){
3682 default:
3683 case ISQ_LABEL_UPLF: /* upper left */
3684 plotpak_pwritf( sb,1.0-dd-sb , lab , ww , 0 , -1 ) ; break ;
3685
3686 case ISQ_LABEL_UPRT: /* upper right */
3687 plotpak_pwritf( asp-sb,1.0-dd-sb , lab , ww , 0 , 1 ) ; break ;
3688
3689 case ISQ_LABEL_DNLF: /* lower left */
3690 plotpak_pwritf( sb,dd+sb , lab , ww , 0 , -1 ) ; break ;
3691
3692 case ISQ_LABEL_DNRT: /* lower right */
3693 plotpak_pwritf( asp-sb,dd+sb , lab , ww , 0 , 1 ) ; break ;
3694
3695 case ISQ_LABEL_UPMD: /* upper middle */
3696 plotpak_pwritf( 0.5*asp,1.0-dd-sb , lab , ww , 0 , 0 ) ; break ;
3697
3698 case ISQ_LABEL_DNMD: /* lower middle */
3699 plotpak_pwritf( 0.5*asp,dd+sb , lab , ww , 0 , 0 ) ; break ;
3700 }
3701
3702 /** AFNI_RESTORE_XDRAWLINES ; **/
3703
3704 mp = get_active_memplot() ; RETURN(mp) ;
3705 }
3706
3707 /*-----------------------------------------------------------------------
3708 process an MRI_IMAGE from the user into a scaled format for display
3709 -- the output will be MRI_short (grayscale index) or MRI_rgb
3710 -- this is where the 'image processing' options from the
3711 Disp control panel are applied
3712 -------------------------------------------------------------------------*/
3713
ISQ_process_mri(int nn,MCW_imseq * seq,MRI_IMAGE * im,int flags)3714 MRI_IMAGE * ISQ_process_mri( int nn , MCW_imseq *seq , MRI_IMAGE *im , int flags )
3715 {
3716 MRI_IMAGE *newim , *flipim , *lim ;
3717 int scl_grp ;
3718 short clbot=0 , cltop=0 ;
3719 int must_rescale = 1 ; /* 31 Jan 2002: always turn this on */
3720 int have_transform ;
3721 int do_0D = (flags & PFLAG_NOTRAN0D) == 0; /* 02 Sep 2014 */
3722 int do_2D = (flags & PFLAG_NOTRAN2D) == 0;
3723 int do_improc = (flags & PFLAG_NOIMPROC) == 0 ;
3724 char scalestring[8];
3725
3726 ENTRY("ISQ_process_mri") ;
3727
3728 seq->clbot = seq->cltop = 0.0f ; /* 29 Jul 2001 */
3729
3730 if( ! ISQ_VALID(seq) || im == NULL ) RETURN(NULL) ;
3731
3732 /*** Feb 7, 1996: deal with complex-valued images ***/
3733
3734 lim = im ; /* local image = input image, unless complex */
3735
3736 if( im->kind == MRI_complex ){
3737 float *lar ; complex *cxar ; int ii , npix ;
3738
3739 DPRI("complex to real code = ",seq->opt.cx_code) ;
3740
3741 lim = mri_new( im->nx , im->ny , MRI_float ) ;
3742 lar = MRI_FLOAT_PTR(lim) ;
3743 cxar = MRI_COMPLEX_PTR(im) ;
3744 npix = im->nx * im->ny ;
3745 MRI_COPY_AUX(lim,im) ;
3746 must_rescale = 1 ; /** force rescaling of image later **/
3747
3748 switch( seq->opt.cx_code ){
3749
3750 default:
3751 case ISQ_CX_MAG:
3752 for( ii=0 ; ii < npix ; ii++ ) lar[ii] = CABS(cxar[ii]) ;
3753 break ;
3754
3755 case ISQ_CX_PHASE:
3756 for( ii=0 ; ii < npix ; ii++ ) lar[ii] = CARG(cxar[ii]) ;
3757 break ;
3758
3759 case ISQ_CX_REAL:
3760 for( ii=0 ; ii < npix ; ii++ ) lar[ii] = cxar[ii].r ;
3761 break ;
3762
3763 case ISQ_CX_IMAG:
3764 for( ii=0 ; ii < npix ; ii++ ) lar[ii] = cxar[ii].i ;
3765 break ;
3766 }
3767
3768 (void)thd_floatscan( npix , lar ) ; /* 24 Aug 2009 */
3769 }
3770
3771 have_transform = (seq->transform0D_func != NULL ||
3772 seq->transform2D_func != NULL ) && (do_0D || do_2D) ;
3773
3774 /****** 11 Feb 1999: if input RGB image, do limited processing *****/
3775
3776 if( lim->kind == MRI_rgb ){
3777 MRI_IMAGE *tim , *qim ;
3778
3779 /** 26 Apr 2005: apply transforms to the intensity channel? **/
3780
3781 if( have_transform ) qim = mri_copy( lim ) ;
3782 else qim = lim ;
3783
3784 if( seq->transform0D_func != NULL && do_0D )
3785 mri_rgb_transform_nD( qim, 0, seq->transform0D_func ) ;
3786
3787 if( seq->transform2D_func != NULL && do_2D )
3788 mri_rgb_transform_nD( qim, 2, seq->transform2D_func ) ;
3789
3790 /** histogram flattening (very useless) **/
3791
3792 if( (seq->opt.improc_code & ISQ_IMPROC_FLAT) != 0 ){
3793 tim = mri_flatten_rgb( qim ) ;
3794 if( qim != lim ) mri_free(qim) ;
3795 qim = tim ;
3796 }
3797
3798 /** sharpening (sometimes useful) **/
3799
3800 if( (seq->opt.improc_code & ISQ_IMPROC_SHARP) != 0 && do_improc ){
3801 tim = mri_sharpen_rgb( seq->sharp_fac , qim ) ;
3802 if( qim != lim ) mri_free(qim) ;
3803 qim = tim ;
3804 }
3805
3806 /** create output:
3807 copy of input, if input was unmodified above,
3808 otherwise, the edited/filtered result from above **/
3809
3810 if( qim == lim )
3811 newim = mri_copy( lim ) ; /* just copy it */
3812 else
3813 newim = qim ; /* is already what we want */
3814
3815 /** 25 Apr 2005: modify image via rgb_gamma exponent? **/
3816
3817 if( fabs(1.0-seq->rgb_gamma) > 0.02 || fabs(seq->rgb_offset) > 0.01 ){
3818 register int npix = newim->nx * newim->ny , ii ;
3819 register byte *ar = MRI_RGB_PTR(newim) ;
3820 double gg = seq->rgb_gamma ;
3821 float aa = seq->rgb_offset , rv,gv,bv , mx ;
3822
3823 if( aa > 0.9 ) aa = 0.9; else if( aa < -0.9 ) aa = -0.9;
3824 for( ii=0 ; ii < npix ; ii++ ){
3825 if( ar[3*ii] > 0 || ar[3*ii+1] > 0 || ar[3*ii+2] > 0 ){
3826 if( aa != 0.0 ){
3827 rv = ar[3*ii] ; gv = ar[3*ii+1] ; bv = ar[3*ii+2] ;
3828 mx = MAX(rv,gv) ; mx = (255.0*aa) / MAX(mx,bv) ;
3829 rv *= mx; gv *= mx; bv *= mx;
3830 } else {
3831 rv = gv = bv = 0.0 ;
3832 }
3833 rv += (float)(255.0*pow(ar[3*ii ]/255.0,gg)) ;
3834 gv += (float)(255.0*pow(ar[3*ii+1]/255.0,gg)) ;
3835 bv += (float)(255.0*pow(ar[3*ii+2]/255.0,gg)) ;
3836 mx = MAX(rv,gv) ; mx = MAX(mx,bv) ;
3837 if( mx > 255.0 ){ mx = 255.0/mx; rv *= mx; gv *= mx; bv *= mx; }
3838 ar[3*ii ] = BYTEIZE(rv) ;
3839 ar[3*ii+1] = BYTEIZE(gv) ;
3840 ar[3*ii+2] = BYTEIZE(bv) ;
3841 }
3842 }
3843 }
3844
3845 /** save the 'original' image in float format? **/
3846
3847 if( seq->set_orim ){ /* for graphs */
3848 KILL_1MRI(seq->orim) ;
3849 seq->orim = mri_to_float(newim) ; /* intensity image */
3850 }
3851
3852 /** 11 May 2004: fill (0,0,0) pixels with zero color? **/
3853
3854 if( seq->zer_color > 0 ){
3855 register int npix = newim->nx * newim->ny , ii ;
3856 register byte rz,gz,bz , *ar = MRI_RGB_PTR(newim) ;
3857 rz = DCOV_REDBYTE (seq->dc,seq->zer_color) ; /* zero */
3858 gz = DCOV_GREENBYTE(seq->dc,seq->zer_color) ; /* color */
3859 bz = DCOV_BLUEBYTE (seq->dc,seq->zer_color) ; /* RGBs */
3860 for( ii=0 ; ii < npix ; ii++ )
3861 if( ar[3*ii] == 0 && ar[3*ii+1] == 0 && ar[3*ii+2] == 0 ){
3862 ar[3*ii] = rz ; ar[3*ii+1] = gz ; ar[3*ii+2] = bz ;
3863 }
3864 }
3865
3866 seq->scl_label[0] = '\0' ;
3867 } /** end of RGB processing **/
3868
3869 /****** Not RGB ==> ******/
3870 /****** process image in normal fashion if no IMPROC code given ******/
3871
3872 else if( ! have_transform && seq->opt.improc_code == ISQ_IMPROC_NONE ){
3873
3874 if( seq->set_orim ){ /* 30 Dec 1998 */
3875 KILL_1MRI(seq->orim) ;
3876 seq->orim = mri_to_float( lim ) ;
3877 }
3878
3879 if( !must_rescale && ISQ_DOING_SLICE_PROJ(seq) ) must_rescale = 1 ;
3880
3881 /*----- first, set scaling based on user desires -----*/
3882
3883 if( nn < seq->status->num_series ){
3884 scl_grp = seq->opt.scale_group ; /* in series -> can groupscale */
3885 } else {
3886 scl_grp = ISQ_SCL_AUTO ; /* not in series -> must autoscale */
3887 }
3888
3889 if( seq->rng_bot < seq->rng_top ) scl_grp = ISQ_SCL_USER ;
3890
3891 switch( scl_grp ){
3892
3893 case ISQ_SCL_USER:{ /* scale from user input ranges */
3894 ISQ_SCLEV( seq->rng_bot,seq->rng_top ,
3895 seq->dc->ncol_im , seq->scl,seq->lev ) ;
3896 clbot = seq->clbot = seq->rng_bot ;
3897 cltop = seq->cltop = seq->rng_top ;
3898 /* if( seq->rng_extern ) strcpy(seq->scl_label,"[Glob]") ;*/
3899 if( seq->rng_extern ) sprintf(seq->scl_label,"[%s]",
3900 THD_get_image_globalrange_str()) ;
3901 else strcpy(seq->scl_label,"[User]") ;
3902 }
3903 break ; /* end of user input range scaling */
3904
3905 default: /* scale on individual image statistics */
3906 case ISQ_SCL_AUTO:{
3907 ISQ_indiv_statistics *st = &( seq->imstat[nn] ) ;
3908 int scrang = seq->opt.scale_range ;
3909
3910 if( seq->top_clip <= 0.0f && scrang == ISQ_RNG_CLIPPED ){
3911 ALLOW_CLIPPING( seq , 0 ) ;
3912 scrang = seq->opt.scale_range ;
3913 }
3914
3915 if( must_rescale ) st->one_done = False ;
3916
3917 if( ! st->one_done ) ISQ_statify_one( seq , nn , lim ) ;
3918
3919 /* 09 Jan 2004: adjust scaling method for image entropy */
3920
3921 if( scrang == ISQ_RNG_02TO98 ){
3922 double ent_th=AFNI_numenv("AFNI_IMAGE_ENTROPY") ;
3923 if( ent_th >= 0.0 ){
3924 if( ent_th == 0.0 ) ent_th = 0.05 ; /* 10 Jan 2004 */
3925 if( st->entropy < ent_th ) scrang = ISQ_RNG_MINTOMAX ;
3926 }
3927 }
3928
3929 switch( scrang ){
3930
3931 default:
3932 case ISQ_RNG_MINTOMAX:
3933 seq->scl = st->scl_mm ;
3934 seq->lev = st->lev_mm ;
3935 seq->clbot = st->min ; /* 29 Jul 2001 */
3936 seq->cltop = st->max ;
3937 strcpy(seq->scl_label,"[Min2Max]") ;
3938 break ;
3939
3940 case ISQ_RNG_02TO98:
3941 seq->scl = st->scl_per ;
3942 seq->lev = st->lev_per ;
3943 clbot = seq->clbot = st->per02 ;
3944 cltop = seq->cltop = st->per98 ;
3945 strcpy(seq->scl_label,"[2%-98%]") ;
3946 break ;
3947
3948 case ISQ_RNG_CLIPPED:{
3949 float bf=AFNI_numenv("AFNI_IMAGE_CLIPBOT") , bc ;
3950 float tf=AFNI_numenv("AFNI_IMAGE_CLIPTOP") , tc ;
3951 if( bf < 0.0f || bf > 0.5f ) bf = 0.25f ;
3952 if( tf < 0.6f || bf > 1.9f ) tf = 1.00f ;
3953 bc = bf * seq->top_clip ;
3954 tc = tf * seq->top_clip ;
3955 ISQ_SCLEV( bc,tc ,
3956 seq->dc->ncol_im , seq->scl,seq->lev ) ;
3957 clbot = seq->clbot = bc ;
3958 cltop = seq->cltop = tc ;
3959 strcpy(seq->scl_label,"[clipped]") ;
3960 seq->redo_clip = 1 ;
3961 }
3962 break ;
3963 }
3964 }
3965 break ; /* end of autoscaling */
3966
3967 #ifndef NO_GROUP_SCALE
3968 case ISQ_SCL_GRP:{ /* scale on group statistics */
3969 ISQ_glob_statistics *gl = seq->glstat ;
3970
3971 switch( seq->opt.scale_range ){
3972
3973 default:
3974 case ISQ_RNG_MINTOMAX:
3975 if( ! gl->mm_done ) ISQ_statify_all( seq , True ) ;
3976 seq->scl = gl->scl_mm ;
3977 seq->lev = gl->lev_mm ;
3978 seq->clbot = gl->min ; /* 29 Jul 2001 */
3979 seq->cltop = gl->max ;
3980 strcpy(seq->scl_label,"[Min2Max]") ;
3981 break ;
3982
3983 case ISQ_RNG_02TO98:
3984 if( ! gl->per_done ) ISQ_statify_all( seq , False ) ;
3985 seq->scl = gl->scl_per ;
3986 seq->lev = gl->lev_per ;
3987 clbot = seq->clbot = gl->per02 ;
3988 cltop = seq->cltop = gl->per98 ;
3989 strcpy(seq->scl_label,"[2%-98%]") ;
3990 break ;
3991 }
3992 }
3993 break ; /* end of groupscaling */
3994 #endif
3995 } /* end of scaling */
3996 floatfix(seq->clbot) ; floatfix(seq->cltop) ; /* 24 Aug 2009 */
3997
3998 /* 11/30/94 fix: mri_to_short_sclip has problems with short overflow */
3999
4000 #if 0
4001 if( lim->kind == MRI_short && clbot < cltop ){
4002
4003 int npix = lim->nx * lim->ny , ii ;
4004 short *ar = MRI_SHORT_PTR(lim) ;
4005
4006 if( seq->rng_ztop == 0 ){
4007 for( ii=0 ; ii < npix ; ii++ )
4008 if( ar[ii] < clbot ) ar[ii] = clbot ;
4009 else if( ar[ii] > cltop ) ar[ii] = cltop ;
4010 } else {
4011 for( ii=0 ; ii < npix ; ii++ )
4012 if( ar[ii] < clbot || ar[ii] > cltop ) ar[ii] = clbot ;
4013 }
4014
4015 } else if( lim->kind == MRI_byte && clbot < cltop ){
4016
4017 int npix = lim->nx * lim->ny , ii ;
4018 byte *ar = MRI_BYTE_PTR(lim) ;
4019
4020 if( seq->rng_ztop == 0 ){
4021 for( ii=0 ; ii < npix ; ii++ )
4022 if( ar[ii] < clbot ) ar[ii] = clbot ;
4023 else if( ar[ii] > cltop ) ar[ii] = cltop ;
4024 } else {
4025 for( ii=0 ; ii < npix ; ii++ )
4026 if( ar[ii] < clbot || ar[ii] > cltop ) ar[ii] = clbot ;
4027 }
4028 }
4029 #endif
4030
4031 /*----- next, scale image as defined above -----*/
4032
4033 STATUS("scaling to shorts") ;
4034
4035 /* scaling to zero clip bot clip top */
4036 /* -------- -------- -------- -------- */
4037 newim = mri_to_short_sclip( seq->scl, seq->lev, seq->bot, seq->top, lim );
4038
4039 /****** end of normal processing; handle special image processing below ******/
4040
4041 } else {
4042 MRI_IMAGE *tim , *qim ;
4043 double scl , lev ;
4044 float hbot,htop ;
4045
4046 STATUS("begin IMPROCessing") ;
4047
4048 qim = lim ; /* at the start of each process stage,
4049 qim is the image to process;
4050 tim is an intermediate temporary image */
4051
4052 /***** 30 Oct 1996: transform image *****/
4053
4054 if( seq->transform0D_func != NULL && do_0D ){
4055 tim = mri_to_float(qim) ;
4056 #if 0
4057 seq->transform0D_func( tim->nvox , MRI_FLOAT_PTR(tim) ) ;
4058 #else
4059 AFNI_CALL_0D_function( seq->transform0D_func ,
4060 tim->nvox , MRI_FLOAT_PTR(tim) ) ;
4061 #endif
4062 if( qim != lim ) mri_free(qim) ;
4063 qim = tim ;
4064 }
4065
4066 if( seq->transform2D_func != NULL && do_2D ){
4067 tim = mri_to_float(qim) ;
4068 #if 0
4069 seq->transform2D_func( tim->nx , tim->ny ,
4070 tim->dx , tim->dy , MRI_FLOAT_PTR(tim) ) ;
4071 #else
4072 AFNI_CALL_2D_function( seq->transform2D_func ,
4073 tim->nx , tim->ny ,
4074 tim->dx , tim->dy , MRI_FLOAT_PTR(tim) ) ;
4075 #endif
4076 if( qim != lim ) mri_free(qim) ;
4077 qim = tim ;
4078 }
4079
4080 /*** flatten ***/
4081
4082 if( (seq->opt.improc_code & ISQ_IMPROC_FLAT) != 0 && do_improc ){
4083 STATUS("call mri_flatten") ;
4084 tim = mri_flatten( qim ) ;
4085 if( qim != lim ) mri_free(qim) ;
4086 qim = tim ;
4087
4088 if( seq->opt.scale_range == ISQ_RNG_02TO98 &&
4089 seq->flat_top > seq->flat_bot ){
4090
4091 float *qar = MRI_FLOAT_PTR(qim) ;
4092 int ii , npix = qim->nx * qim->ny ;
4093
4094 STATUS("clip flattened image") ;
4095
4096 for( ii=0 ; ii < npix ; ii++ ){
4097 if( qar[ii] < seq->flat_bot ) qar[ii] = seq->flat_bot ;
4098 else if( qar[ii] > seq->flat_top ) qar[ii] = seq->flat_top ;
4099 }
4100 }
4101 }
4102
4103 /*** sharpen ***/
4104
4105 if( (seq->opt.improc_code & ISQ_IMPROC_SHARP) != 0 && do_improc ){
4106 STATUS("call mri_sharpen") ;
4107 tim = mri_sharpen( seq->sharp_fac , 0 , qim ) ;
4108 if( qim != lim ) mri_free(qim) ;
4109 qim = tim ;
4110 }
4111
4112 /*** Sobel edge detection ***/
4113
4114 if( (seq->opt.improc_code & ISQ_IMPROC_SOBEL) != 0 && do_improc ){
4115 int ii , npix ;
4116 float *tar ;
4117
4118 STATUS("call mri_edit_image") ;
4119 tim = mri_edit_image( 0.10 , 1.0 , qim ) ; /* soft clip small values */
4120 if( qim != lim ) mri_free(qim) ;
4121 qim = tim ;
4122
4123 STATUS("call mri_sobel") ;
4124 tim = mri_sobel( 0 , 2 , qim ) ; /* edge detect */
4125
4126 #if 0
4127 npix = tim->nx * tim->ny ; /* take square root */
4128 tar = mri_data_pointer(tim) ;
4129 for( ii=0 ; ii < npix ; ii++ ) tar[ii] = sqrt(tar[ii]) ;
4130 #endif
4131
4132 if( qim != lim ) mri_free(qim) ;
4133 qim = tim ;
4134 }
4135
4136 if( seq->set_orim ){ /* 30 Dec 1998 */
4137 KILL_1MRI(seq->orim) ;
4138 seq->orim = mri_to_float( qim ) ;
4139 }
4140
4141 /*** scale to shorts (cf. ISQ_statify_one) ***/
4142
4143 hbot = mri_min(qim) ; htop = mri_max(qim) ;
4144
4145 STATUS("scale to shorts") ;
4146 switch( seq->opt.scale_range ){
4147 default:
4148 case ISQ_RNG_MINTOMAX:
4149 ISQ_SCLEV( hbot,htop , seq->dc->ncol_im , scl,lev ) ;
4150 seq->clbot = hbot ; /* 29 Jul 2001 */
4151 seq->cltop = htop ;
4152 strcpy(seq->scl_label,"[Min2Max]") ;
4153 break ;
4154
4155 case ISQ_RNG_02TO98:{
4156 static int hist[NHISTOG] ;
4157 float h02 , h98 ;
4158
4159 STATUS("call mri_histogram") ;
4160 mri_histogram( qim , hbot,htop , True , NHISTOG,hist ) ;
4161 STATUS("call ISQ_perpoints") ;
4162 ISQ_perpoints( hbot,htop , hist , &h02 , &h98 ) ;
4163 ISQ_SCLEV( h02,h98 , seq->dc->ncol_im , scl,lev ) ;
4164 seq->clbot = h02 ; /* 29 Jul 2001 */
4165 seq->cltop = h98 ;
4166 strcpy(seq->scl_label,"[2%-98%]") ;
4167 }
4168 break ;
4169
4170 case ISQ_RNG_CLIPPED:{
4171 float bf=AFNI_numenv("AFNI_IMAGE_CLIPBOT") , bc ;
4172 float tf=AFNI_numenv("AFNI_IMAGE_CLIPTOP") , tc ;
4173 if( bf < 0.0f || bf > 0.5f ) bf = 0.25f ;
4174 if( tf < 0.6f || bf > 1.9f ) tf = 1.00f ;
4175 bc = bf * seq->top_clip ;
4176 tc = tf * seq->top_clip ;
4177 ISQ_SCLEV( bc,tc ,
4178 seq->dc->ncol_im , scl,lev ) ;
4179 seq->clbot = bc ;
4180 seq->cltop = tc ;
4181 strcpy(seq->scl_label,"[clipped]") ;
4182 seq->redo_clip = 1 ;
4183 }
4184 break ;
4185 }
4186
4187 newim = mri_to_short_sclip( scl , lev , seq->bot, seq->top, qim ) ;
4188 if( qim != lim ) mri_free(qim) ;
4189 }
4190
4191 /**** at this point, the processed image is in "newim" ****/
4192 /**** and will be in short or RGB format ****/
4193
4194 /** 14 Jun 2010: automask 2D image **/
4195
4196 if( MCW_val_bbox(seq->wbar_amask_bbox) > 0 ){
4197 byte *mmm = mri_automask_image2D(newim) ; MRI_IMAGE *qim ;
4198 if( mmm != NULL ){
4199 int npix = newim->nx * newim->ny , ii ;
4200 switch( newim->kind ){
4201 case MRI_short:{
4202 short zz = -seq->zer_color ;
4203 short *ar = MRI_SHORT_PTR(newim) ;
4204 for( ii=0 ; ii < npix ; ii++ )
4205 if( !mmm[ii] ) ar[ii] = zz ;
4206 }
4207 break ;
4208
4209 case MRI_rgb:{
4210 byte *ar = MRI_RGB_PTR(newim) ;
4211 for( ii=0 ; ii < npix ; ii++ )
4212 if( !mmm[ii] ) ar[3*ii] = ar[3*ii+1] = ar[3*ii+2] = 0 ;
4213 }
4214 break ;
4215 default: break ;
4216 } /* end of switch on newim->kind */
4217 /* now save the automask for usage later (soon later) [12 Dec 2014] */
4218 KILL_1MRI(seq->last_automask) ;
4219 qim = mri_empty_conforming(newim,MRI_byte) ; mri_fix_data_pointer(mmm,qim) ;
4220 seq->last_automask = mri_flippo( ISQ_TO_MRI_ROT(seq->opt.rot) , seq->opt.mirror , qim ) ;
4221 if( qim != seq->last_automask ) mri_free(qim) ;
4222 } else {
4223 KILL_1MRI(seq->last_automask) ;
4224 }
4225 } else {
4226 KILL_1MRI(seq->last_automask) ;
4227 }
4228
4229 /* 14 Sep 2020: invert contrast */
4230
4231 if( MCW_val_bbox(seq->wbar_invrt_bbox) > 0 ){
4232 mri_invertcontrast_inplace( newim , 91.1f , NULL ) ;
4233 }
4234
4235 /** Aug 31, 1995: put zer_color in at bottom, if nonzero **/
4236
4237 if( newim->kind == MRI_short && seq->zer_color > 0 ){
4238 short zz = -seq->zer_color ;
4239 short *ar = MRI_SHORT_PTR(newim) ;
4240 int npix = newim->nx * newim->ny , ii ;
4241
4242 #if 0
4243 for( ii=0 ; ii < npix ; ii++ )
4244 if( ar[ii] == seq->bot ) ar[ii] = zz ; /* the olden way */
4245 #else
4246 switch( lim->kind ){ /* the new way: 14 Jun 2010 */
4247 default: break ;
4248 case MRI_short:{
4249 short *lar = MRI_SHORT_PTR(lim) ;
4250 for( ii=0 ; ii < npix ; ii++ ) if( lar[ii] == 0 ) ar[ii] = zz ;
4251 }
4252 break ;
4253
4254 case MRI_byte:{
4255 byte *lar = MRI_BYTE_PTR(lim) ;
4256 for( ii=0 ; ii < npix ; ii++ ) if( lar[ii] == 0 ) ar[ii] = zz ;
4257 }
4258 break ;
4259
4260 case MRI_float:{
4261 float *lar = MRI_FLOAT_PTR(lim) ;
4262 for( ii=0 ; ii < npix ; ii++ ) if( lar[ii] == 0.0f ) ar[ii] = zz ;
4263 }
4264 break ;
4265 }
4266 #endif
4267 }
4268
4269 /** copy pixel sizes, etc. (fixup for mrilib to be happy) **/
4270
4271 MRI_COPY_AUX( newim , lim ) ;
4272
4273 /*----- last, rotate/flip image to desired orientation -----*/
4274
4275 STATUS("call mri_flippo") ;
4276 flipim = mri_flippo( ISQ_TO_MRI_ROT(seq->opt.rot) , seq->opt.mirror , newim ) ;
4277
4278 if( newim != flipim ) KILL_1MRI(newim) ; /* discard the trash */
4279 if( lim != im ) KILL_1MRI(lim) ; /* (if there is any) */
4280
4281 if( seq->set_orim && seq->orim != NULL ){ /* 30 Dec 1998 */
4282 MRI_IMAGE *qim ;
4283 qim = mri_flippo( ISQ_TO_MRI_ROT(seq->opt.rot), seq->opt.mirror, seq->orim ) ;
4284 if( qim != seq->orim ){ KILL_1MRI(seq->orim) ; seq->orim = qim ; } ;
4285 MRI_COPY_AUX( seq->orim , flipim ) ;
4286 seq->set_orim = 0 ;
4287 }
4288
4289 RETURN(flipim) ;
4290 }
4291
4292 /*-------------------------------------------------------------------
4293 Callback handlers for color palette manipulation
4294 ---------------------------------------------------------------------*/
4295
ISQ_but_color_CB(Widget w,XtPointer client_data,XtPointer call_data)4296 void ISQ_but_color_CB( Widget w , XtPointer client_data ,
4297 XtPointer call_data )
4298 {
4299 MCW_imseq *seq = (MCW_imseq *) client_data ;
4300
4301 ENTRY("ISQ_but_color_CB") ;
4302
4303 if( ! ISQ_REALZ(seq) ) EXRETURN ;
4304
4305 /* change the color bar */
4306
4307 if( seq->dc->use_xcol_im ) DC_palette_setgray( seq->dc ) ;
4308 else DC_palette_setcolor( seq->dc ) ;
4309
4310 COLORMAP_CHANGE(seq) ; /* 22 Aug 1998 */
4311 ISQ_but_done_reset( seq ) ;
4312 EXRETURN ;
4313 }
4314
4315 /*-------------------------------------------------------------------*/
4316 /* Color bar inversion */
4317
ISQ_but_cswap_CB(Widget w,XtPointer client_data,XtPointer call_data)4318 void ISQ_but_cswap_CB( Widget w , XtPointer client_data ,
4319 XtPointer call_data )
4320 {
4321 MCW_imseq *seq = (MCW_imseq *) client_data ;
4322
4323 ENTRY("ISQ_but_cswap_CB") ;
4324
4325 if( ! ISQ_REALZ(seq) ) EXRETURN ;
4326
4327 DC_palette_swap( seq->dc ) ;
4328 COLORMAP_CHANGE(seq) ; /* 22 Aug 1998 */
4329 ISQ_but_done_reset( seq ) ;
4330 EXRETURN ;
4331 }
4332
4333 /*-------------------------------------------------------------------
4334 Execute the image saving options, called from ISQ_but_save_CB(),
4335 which will use MCW_choose_stuff() to let the user select the
4336 parameters for the saving -- which are in array val.
4337 * nval == 2 is the Save One case (val = prefix, blowup)
4338 nval == 3 is Save One case, but with option to invoke Gimp
4339 nval == 4 is the Save Many case (val = prefix, blowup, from, to)
4340 ---------------------------------------------------------------------*/
4341
4342 #define POPDOWN_first_one POPDOWN_stuff_chooser
4343
ISQ_saver_CB(Widget w,XtPointer cd,int nval,void ** val)4344 void ISQ_saver_CB( Widget w , XtPointer cd , int nval , void **val )
4345 {
4346 MCW_imseq *seq = (MCW_imseq *) cd ;
4347 int ii , kf ;
4348 MRI_IMAGE *tim , *flim ;
4349 char fname[256] ;
4350 THD_string_array *agif_list=NULL ; /* 27 Jul 2001 */
4351 char tsuf[8] ; /* 09 Dec 2002 */
4352 float dx,dy ; /* 08 Jun 2004 */
4353 int dbg ; /* 03 Sep 2004 */
4354 int adup=1 , akk,aa ; /* 09 Feb 2009 */
4355
4356 char *cval1; int ival2, ival3=0, ival4=0, ll, use_gimp=0 ; /* 26 Nov 2013 */
4357
4358 #ifndef DONT_USE_METER
4359 # define METER_MINCOUNT 20
4360 Widget meter = NULL ;
4361 int meter_perc , meter_pold=0 , meter_pbase ;
4362 #endif
4363
4364 ENTRY("ISQ_saver_CB") ;
4365
4366 if( nval < 2 || nval > 4 ) EXRETURN ; /* bad inputs */
4367
4368 cval1 = (char *)val[0] ; /* copy input values to local variables */
4369 ival2 = (int)(intptr_t)val[1] ;
4370 if( nval == 4 ){
4371 ival3 = (int)(intptr_t)val[2] ;
4372 ival4 = (int)(intptr_t)val[3] ;
4373 } else if( nval == 3 ){ /* 27 Oct 2017 */
4374 char *cpt = (char *)val[2] ;
4375 use_gimp = (cpt != NULL) && *cpt == 'Y' ;
4376 }
4377 if( cval1 == NULL || *cval1 == '\0' ) EXRETURN ;
4378 ll = strlen(cval1) ; if( ll > 32 ) EXRETURN ;
4379
4380 dbg = AFNI_yesenv("AFNI_IMSAVE_DEBUG") ; /* 03 Sep 2004 */
4381
4382 /* check if we are ordered to save an animation
4383 but do not actually have the animation conversion filter */
4384
4385 if( ppmto_agif_filter == NULL && DO_AGIF(seq) ){ /* 07 Apr 2005! */
4386 (void) MCW_popup_message( seq->wtop ,
4387 "Animated GIF AFNI logic error!\n"
4388 "Report to " COXEMAIL , MCW_USER_KILL ) ;
4389 seq->opt.save_agif = 0 ;
4390 EXRETURN ;
4391 }
4392 if( ppmto_mpeg_filter == NULL && DO_MPEG(seq) ){
4393 (void) MCW_popup_message( seq->wtop ,
4394 "MPEG-1 AFNI logic error!\n"
4395 "Report to " COXEMAIL , MCW_USER_KILL ) ;
4396 seq->opt.save_mpeg = 0 ;
4397 EXRETURN ;
4398 }
4399
4400 /*---------------*/
4401
4402 { /* process input prefix string */
4403
4404 seq->saver_prefix = (char*)XtMalloc( sizeof(char) * (ll+8) ) ;
4405 strcpy( seq->saver_prefix , cval1 ) ;
4406
4407 if( seq->saver_prefix[ll-1] != '.' ){ /* add a . at the end */
4408 seq->saver_prefix[ll++] = '.' ; /* if one isn't there */
4409 seq->saver_prefix[ll] = '\0' ;
4410 }
4411
4412 /*-- check that the prefix is acceptable --*/
4413
4414 if( dbg ) fprintf(stderr,"IMSAVE: got prefix '%s'\n",seq->saver_prefix);
4415
4416 ll = strlen(seq->saver_prefix) ;
4417
4418 for( ii=0 ; ii < ll ; ii++ )
4419 if( iscntrl(seq->saver_prefix[ii]) ||
4420 isspace(seq->saver_prefix[ii]) ) break ;
4421
4422 if( ii < ll || ll < 2 || ll > 240 ){
4423 XBell( XtDisplay(w) , 100 ) ;
4424 myXtFree( seq->saver_prefix ) ; seq->saver_prefix = NULL ;
4425 EXRETURN ;
4426 }
4427
4428 seq->saver_blowup = ival2 ;
4429
4430 /*-- April 1996: Save One case here --*/
4431
4432 if( nval == 2 || nval == 3 ){
4433 char *ppnm = strstr( seq->saver_prefix , ".pnm." ) ;
4434 int sll = strlen( seq->saver_prefix ) ;
4435
4436 int mcod = X2M_USE_CMAP ; /* 21 Sep 2001: */
4437 if( seq->opt.save_filter >= 0 ||
4438 seq->mplot != NULL ) /* compute mcod rather than */
4439 mcod |= X2M_FORCE_RGB ; /* use fixed X2M_USE_CMAP */
4440
4441 /* undump XImage to MRI_IMAGE (rgb format) */
4442
4443 if( dbg ) fprintf(stderr,"IMSAVE: convert XImage to RGB\n") ;
4444
4445 /* we take the XImage used to draw the window
4446 and convert it back to an MRI_IMAGE for saving */
4447
4448 reload_DC_colordef( seq->dc ) ; /* 23 Mar 1999 */
4449 tim = XImage_to_mri( seq->dc , seq->given_xim , mcod ) ; /* 21 Sep 2001: */
4450 /* X2M_USE_CMAP -> mcod */
4451
4452 /* save in square aspect? */
4453
4454 if( AFNI_yesenv("AFNI_IMAGE_SAVESQUARE") ){ /* 08 Jun 2004 */
4455 tim->dx = seq->last_dx ; tim->dy = seq->last_dy ;
4456 if( dbg ) fprintf(stderr," square-ize aspect\n") ;
4457 flim = mri_squareaspect( tim ) ;
4458 if( flim != NULL ){ mri_free(tim); tim = flim; }
4459 }
4460
4461 /* Apply VG filter? [20 Jun 2019] -- only for fun */
4462
4463 { float vfac = VGFAC(seq) ;
4464 if( vfac > 0.0f ){
4465 vgize_sigfac = vfac ; flim = mri_vgize(tim) ;
4466 if( flim != NULL ){ mri_free(tim); tim = flim; }
4467 }
4468 }
4469
4470 /* 23 Mar 2002: zoom out, if ordered */
4471
4472 if( DO_BLOWUP(seq) && tim != NULL && tim->kind == MRI_rgb ){
4473
4474 int zf = MAX(seq->zoom_fac,seq->saver_blowup) ;
4475 MRI_IMAGE *qim ;
4476
4477 if( dbg ) fprintf(stderr," zooming\n") ;
4478 // [PT: Dec 19, 2018] Change default behavior to be NN interp.
4479 // Here and below, this condition **used** to be:
4480 // if( !AFNI_yesenv("AFNI_IMAGE_ZOOM_NN") ) mri_dup2D_mode(-7) ;
4481 if( AFNI_noenv("AFNI_IMAGE_ZOOM_NN") ) mri_dup2D_mode(-7) ;
4482 qim = mri_dup2D(zf,tim) ;
4483 mri_dup2D_mode(7) ;
4484 mri_free(tim) ; tim = qim ;
4485 }
4486
4487 /* 23 Mar 2002: draw overlay lines on top, if any,
4488 since they are not in the XImage, only in the window */
4489
4490 if( tim != NULL && seq->mplot != NULL && tim->kind == MRI_rgb ){
4491 if( dbg ) fprintf(stderr," overlay geometry stuff\n") ;
4492 /* mri_draw_force_opaque(1) ; */
4493 memplot_to_mri_set_dothick(1) ;
4494 memplot_to_RGB_sef( tim, seq->mplot, 0,0,MEMPLOT_FREE_ASPECT ) ;
4495 memplot_to_mri_set_dothick(0) ;
4496 /* mri_draw_force_opaque(0) ; */
4497 }
4498
4499 /* 25 Mar 2002: perhaps cut up zoomed image
4500 (after overlay is drawn on it, that is) */
4501
4502 if( seq->zoom_fac > 1 &&
4503 seq->saver_blowup == 1 &&
4504 seq->mont_nx == 1 &&
4505 seq->mont_ny == 1 &&
4506 tim != NULL &&
4507 tim->kind == MRI_rgb &&
4508 AFNI_yesenv("AFNI_CROP_ZOOMSAVE") ) {
4509
4510 MRI_IMAGE *qim ;
4511 int xa,ya , iw=tim->nx/seq->zoom_fac , ih=tim->ny/seq->zoom_fac ;
4512
4513 if( dbg ) fprintf(stderr," crop zoomed image\n") ;
4514 xa = seq->zoom_hor_off * tim->nx ;
4515 if( xa+iw > tim->nx ) xa = tim->nx-iw ;
4516 ya = seq->zoom_ver_off * tim->nx ;
4517 if( ya+ih > tim->ny ) ya = tim->ny-ih ;
4518 qim = mri_cut_2D( tim , xa,xa+iw-1 , ya,ya+ih-1 ) ;
4519 mri_free(tim) ; tim = qim ;
4520 }
4521
4522 /* save image to file */
4523
4524 if( tim != NULL ){ /* if we have image, that is */
4525 static int warned=0 ;
4526
4527 if( seq->opt.save_filter < 0 ){ /* the old code: dump to PNM file */
4528
4529 if( ppnm == seq->saver_prefix + (sll-5) ) /* 17 June 1997 */
4530 seq->saver_prefix[sll-1] = '\0' ;
4531 else
4532 strcat(seq->saver_prefix,"pnm") ;
4533
4534 INFO_message("Writing one %dx%d PNM image to file %s",
4535 tim->nx,tim->ny,seq->saver_prefix) ;
4536 mri_write_pnm( seq->saver_prefix , tim ) ;
4537
4538 } else { /* 26 Jul 2001: allow Save One in filtered formats */
4539
4540 char filt[512] ; int ff=seq->opt.save_filter ; FILE *fp ;
4541 int pc ;
4542
4543 /* create the output filename with the correct suffix */
4544
4545 sprintf(filt,".%s.",ppmto_suffix[ff]) ;
4546 if( STRING_HAS_SUFFIX_CASE(seq->saver_prefix,filt) ){
4547 strcpy(fname,seq->saver_prefix) ;
4548 fname[sll-1] = '\0' ;
4549 } else {
4550 sprintf( fname, "%s%s", seq->saver_prefix, ppmto_suffix[ff] ) ;
4551 }
4552
4553 /* create the command to do the image conversion and output */
4554
4555 sprintf( filt , ppmto_filter[ff] , fname ) ;
4556 INFO_message("Writing one %dx%d image to file %s",
4557 tim->nx,tim->ny,fname) ;
4558
4559 /* open a pipe to the filter function */
4560 #ifndef CYGWIN
4561 signal( SIGPIPE , SIG_IGN ) ; /* if the pipe fails, ignore it */
4562 #endif
4563 errno = 0 ;
4564 fp = popen( filt , "w" ) ; /* filter command waiting for data */
4565 if( fp == NULL ){
4566 fprintf(stderr,"** Can't open output filter: %s\a\n",filt) ;
4567 if( errno != 0 ) perror("** Unix error message") ;
4568 POPDOWN_first_one ;
4569 mri_free(tim) ; EXRETURN ;
4570 }
4571
4572 /* write a PPM file to the filter pipe */
4573
4574 fprintf(fp,"P6\n%d %d\n255\n" , tim->nx,tim->ny ) ;
4575 fwrite( MRI_RGB_PTR(tim), sizeof(byte), 3*tim->nvox, fp ) ;
4576 pc = pclose(fp) ; /* close the pipe */
4577 if( pc == -1 ){ /* this error should be nearly impossible */
4578 perror("** Error in image output pipe") ;
4579 fprintf(stderr,"** filter command was %s\n",filt) ;
4580 POPDOWN_first_one ; mri_free(tim) ; EXRETURN ;
4581 }
4582
4583 /* Open Gimp with this new file? [27 Oct 2017] */
4584 if( gimp_path != NULL && use_gimp && THD_is_file(fname) ){
4585 sprintf(filt,"%s %s &",gimp_path,fname) ;
4586 system(filt) ;
4587 }
4588 } /* finished outputting the single image */
4589
4590 mri_free( tim ) ; tim = NULL ; /* 17 June 1997 */
4591
4592 if( seq->dc->visual_class == TrueColor &&
4593 seq->dc->depth == 16 && !warned ){ /* 30 May 2000 */
4594
4595 warned = 1 ; /* This can happen because colors R G B */
4596 fprintf(stderr, /* might not all use the same number of bits */
4597 "\n" /* For example, with R=B=5 bits, G=6 bits */
4598 "*** WARNING: Save One with X11 TrueColor depth=16 can ***\n"
4599 "*** result in gray pixels not having R=G=B. ***\n");
4600 }
4601
4602 } else {
4603 XBell( XtDisplay(w) , 100 ) ; /* image creation failed! */
4604 }
4605 myXtFree( seq->saver_prefix ) ; seq->saver_prefix = NULL ;
4606 EXRETURN ;
4607 }
4608 }
4609
4610 /*--- save many case here ---*/
4611
4612 seq->saver_from = ival3 ; /* saving images from..to (inclusive) */
4613 seq->saver_to = ival4 ;
4614
4615 /* check if all inputs are good */
4616
4617 if( seq->saver_prefix == NULL ||
4618 seq->saver_from < 0 ||
4619 seq->saver_to < 0 ||
4620 seq->saver_from > seq->status->num_total-1 ||
4621 seq->saver_to > seq->status->num_total-1 ){ /* error */
4622
4623 XBell( XtDisplay(w) , 100 ) ;
4624 myXtFree( seq->saver_prefix ) ; seq->saver_prefix = NULL ;
4625 EXRETURN ;
4626 }
4627
4628 if( seq->saver_from > seq->saver_to ){ /* inverted order? */
4629 ii = seq->saver_from ;
4630 seq->saver_from = seq->saver_to ;
4631 seq->saver_to = ii ;
4632 }
4633
4634 #ifndef DONT_USE_METER
4635 meter_pbase = seq->saver_to - seq->saver_from ;
4636 if( meter_pbase >= METER_MINCOUNT ){
4637 meter = MCW_popup_meter( seq->wtop , METER_TOP_WIDE ) ;
4638 meter_pold = 0 ;
4639 } else {
4640 meter = NULL ;
4641 }
4642 #endif
4643
4644 /* special stuff for animation temp files */
4645
4646 if( DO_ANIM(seq) ){ /* 09 Dec 2002: */
4647 tsuf[0] = (lrand48()>>5)%26 + 'A' ; /* random suffix */
4648 tsuf[1] = (lrand48()>>5)%26 + 'A' ; /* for animation */
4649 tsuf[2] = (lrand48()>>5)%26 + 'A' ; /* temp files */
4650 tsuf[3] = '\0' ;
4651 adup = (ISQ_anim_dup > 0) ? ISQ_anim_dup : AFNI_numenv("AFNI_ANIM_DUP") ;
4652 if( adup <= 0 ) adup = 1 ; else if( adup > 99 ) adup = 99 ;
4653 if( dbg ) fprintf(stderr,"IMSAVE: animation suffix='%s' adup=%d\n",tsuf,adup) ;
4654 } else {
4655 tsuf[0] = '\0' ; /* not used */
4656 adup = 1 ;
4657 }
4658
4659 #ifdef USE_GIFF /* create the fixed GIF colormap for animations */
4660 if( DO_AGIF(seq) ){
4661 MRI_IMAGE *im = mri_colorsetup( 76 , 6,6,5 ); /* 76 gray levels + */
4662 remove( GIFF_MAPFILE ) ; /* 6*red X 6*green X 5*blue */
4663 mri_write_pnm( GIFF_MAPFILE , im ) ;
4664 mri_free( im ) ;
4665 }
4666 #endif
4667
4668 /*---------------- loop thru, get images, save them -----------------*/
4669 /*-- In this instance, we have to re-create the image as displayed --*/
4670
4671 for( akk=0,kf=seq->saver_from ; kf <= seq->saver_to ; kf++ ){
4672
4673 /* get the underlay image */
4674
4675 if( dbg ) fprintf(stderr,"IMSAVE: fetch underlay image #%d\n",kf) ;
4676
4677 tim = ISQ_getimage( kf , seq ) ;
4678
4679 /* if we failed to get the image? */
4680
4681 if( tim == NULL ){
4682 if( kf == seq->saver_to && agif_list != NULL ){ /* 19 Sep 2001 */
4683 fprintf(stderr,
4684 "** Can't save animation: last image in list is NULL!\n");
4685 DESTROY_SARR(agif_list) ;
4686 }
4687 continue ; /* skip to next one */
4688 }
4689
4690 /* image to save will be in flim */
4691
4692 flim = tim ;
4693
4694 #ifndef DONT_USE_METER
4695 if( meter != NULL ){
4696 meter_perc = (int)(100.9 * (kf - seq->saver_from) / meter_pbase) ;
4697 if( meter_perc != meter_pold ){
4698 if( dbg ) fprintf(stderr," set meter to %d\n",meter_perc) ;
4699 MCW_set_meter( meter , meter_perc ) ;
4700 meter_pold = meter_perc ;
4701 }
4702 }
4703 #endif
4704
4705 /*-- 27 Jun 2001: write image through a filter? --*/
4706
4707 if( seq->opt.save_filter >= 0 || DO_ANIM(seq) ){
4708 char filt[512] ; int ff=seq->opt.save_filter ; FILE *fp ;
4709 MRI_IMAGE *ovim=NULL ;
4710 int nx , ny , npix , pc ;
4711
4712 /* process image to make the grayscale index */
4713
4714 if( dbg ) fprintf(stderr," process image\n") ;
4715
4716 seq->set_orim = 0 ;
4717 tim = flim ;
4718 flim = ISQ_process_mri( kf , seq , tim , 0 ) ;
4719 if( tim != flim ) KILL_1MRI( tim ) ;
4720
4721 /* get overlay and flip it */
4722
4723 if( !ISQ_SKIP_OVERLAY(seq) ){
4724 if( dbg ) fprintf(stderr," fetch overlay image\n") ;
4725 tim = ISQ_getoverlay( kf , seq ) ;
4726 if( tim != NULL && !ISQ_GOOD_OVERLAY_TYPE(tim->kind) ){
4727 KILL_1MRI(tim) ;
4728 }
4729 if( dbg ) fprintf(stderr," flip overlay?\n") ;
4730 if( tim != NULL )
4731 ovim = mri_flippo( ISQ_TO_MRI_ROT(seq->opt.rot), seq->opt.mirror, tim );
4732 if( tim != ovim ) KILL_1MRI(tim) ;
4733 ISQ_apply_mask( seq->last_automask , ovim ) ;
4734 }
4735
4736 /* and perform overlay onto flim */
4737
4738 if( ovim != NULL ){
4739 tim = flim ;
4740 if( dbg ) fprintf(stderr," merge overlay and underlay images\n") ;
4741 flim = ISQ_overlay( seq->dc , tim , ovim , seq->ov_opacity ) ;
4742 if( flim == NULL ){ flim = tim ; } /* shouldn't happen */
4743 else { KILL_1MRI(tim) ; }
4744 mri_free( ovim ) ;
4745 }
4746
4747 /* INFO_message("AFNI_IMAGE_SAVESQUARE = %s",getenv("AFNI_IMAGE_SAVESQUARE")); */
4748 if( AFNI_yesenv("AFNI_IMAGE_SAVESQUARE") ){ /* 08 Jun 2004 */
4749 flim->dx = seq->last_dx ; flim->dy = seq->last_dy ;
4750 if( dbg ) fprintf(stderr," square-ize aspect ratio\n") ;
4751 tim = mri_squareaspect( flim ) ;
4752 if( tim != NULL ){ mri_free(flim); flim = tim; }
4753 }
4754
4755 /* if needed, convert image from indices to RGB */
4756
4757 if( flim->kind == MRI_short ){
4758 if( dbg ) fprintf(stderr," convert to RGB\n") ;
4759 tim = ISQ_index_to_rgb( seq->dc , 0 , flim ) ;
4760 mri_free(flim) ; flim = tim ;
4761 }
4762
4763 /* 26 Mar 2002: zoom out, and geometry overlay, maybe */
4764
4765 if( DO_BLOWUP(seq) ){
4766 int zf = MAX(seq->zoom_fac,seq->saver_blowup) ;
4767 if( dbg ) fprintf(stderr," zoom zoom zoom\n") ;
4768 // [PT: Dec 19, 2018] Change default behavior to be NN interp
4769 if( AFNI_noenv("AFNI_IMAGE_ZOOM_NN") ) mri_dup2D_mode(-7) ;
4770 tim = mri_dup2D(zf,flim) ;
4771 mri_dup2D_mode(7) ;
4772 mri_free(flim) ; flim = tim ;
4773 }
4774
4775 if( MCW_val_bbox(seq->wbar_plots_bbox) != 0 ){ /* draw geometry overlay */
4776 MEM_plotdata *mp ;
4777 if( dbg ) fprintf(stderr," get geometry overlay?\n") ;
4778 mp = ISQ_getmemplot( kf , seq ) ;
4779 if( mp != NULL ){
4780 if( dbg ) fprintf(stderr," perform geometry overlay\n") ;
4781 flip_memplot( ISQ_TO_MRI_ROT(seq->opt.rot),seq->opt.mirror,mp );
4782 /* mri_draw_force_opaque(1) ; */
4783 memplot_to_RGB_sef( flim, mp, 0,0,MEMPLOT_FREE_ASPECT ) ;
4784 /* mri_draw_force_opaque(0) ; */
4785 delete_memplot(mp) ;
4786 }
4787 }
4788
4789 if( seq->wbar_label_av->ival != 0 ){ /* Label overlay - 17 Jun 2005 */
4790 char *lab = ISQ_getlabel( kf , seq ) ;
4791 if( lab != NULL ){
4792 MEM_plotdata *mp = ISQ_plot_label( seq , lab ) ;
4793 if( mp != NULL ){
4794 /* mri_draw_force_opaque(1) ; */
4795 memplot_to_mri_set_dothick(1) ;
4796 memplot_to_RGB_sef( flim, mp, 0,0,MEMPLOT_FREE_ASPECT ) ;
4797 memplot_to_mri_set_dothick(0) ;
4798 /* mri_draw_force_opaque(0) ; */
4799 delete_memplot(mp) ;
4800 }
4801 free(lab) ;
4802 }
4803 }
4804
4805 if( seq->zoom_fac > 1 && /* crop zoomed image */
4806 seq->saver_blowup == 1 &&
4807 seq->mont_nx == 1 && /* to displayed part? */
4808 seq->mont_ny == 1 &&
4809 AFNI_yesenv("AFNI_CROP_ZOOMSAVE") ) {
4810
4811 int xa,ya , iw=flim->nx/seq->zoom_fac , ih=flim->ny/seq->zoom_fac ;
4812
4813 if( dbg ) fprintf(stderr," crop zoomed image\n") ;
4814 xa = seq->zoom_hor_off * flim->nx ;
4815 if( xa+iw > flim->nx ) xa = flim->nx-iw ;
4816 ya = seq->zoom_ver_off * flim->nx ;
4817 if( ya+ih > flim->ny ) ya = flim->ny-ih ;
4818 tim = mri_cut_2D( flim , xa,xa+iw-1 , ya,ya+ih-1 ) ;
4819 if( tim != NULL ){ mri_free(flim); flim = tim; }
4820 }
4821
4822 /* image dimensions we are saving */
4823
4824 nx = flim->nx ; ny = flim->ny ; npix = nx*ny ;
4825
4826 /* write the output file */
4827
4828 if( !DO_ANIM(seq) ){ /* don't write progress for animation */
4829 if( kf == seq->saver_from )
4830 printf("writing %d x %d .%s files",nx,ny,ppmto_suffix[ff]) ;
4831 else if( kf%10 == 5 )
4832 printf("." ) ;
4833 fflush(stdout) ;
4834 }
4835
4836 /* create the filter command into string 'filt' */
4837
4838 for( aa=0 ; aa < adup ; aa++,akk++ ){ /* adup==1 if no animation */
4839 if( !DO_ANIM(seq) ){ /* arbitrary filtering */
4840 sprintf( fname, "%s%04d.%s", seq->saver_prefix, kf, ppmto_suffix[ff] ) ;
4841 sprintf( filt , ppmto_filter[ff] , fname ) ;
4842 } else if( DO_AGIF(seq) ){ /* use the gif filter */
4843 sprintf( fname, "%s%s.%05d.gif" , seq->saver_prefix,tsuf, akk) ;
4844 #ifndef USE_GIFF
4845 sprintf( filt , ppmto_gif_filter , fname ) ; /* free colormap */
4846 #else
4847 sprintf( filt , ppmto_giff_filter , fname ) ; /* fixed colormap */
4848 #endif
4849 if( agif_list == NULL ) INIT_SARR(agif_list) ;
4850 ADDTO_SARR(agif_list,fname) ;
4851 } else if( DO_MPEG(seq) ){ /* use the ppm filter */
4852 sprintf( fname, "%s%s.%06d.ppm" , seq->saver_prefix,tsuf, akk) ;
4853 sprintf( filt , ppmto_ppm_filter , fname ) ;
4854 if( agif_list == NULL ) INIT_SARR(agif_list) ;
4855 ADDTO_SARR(agif_list,fname) ;
4856 }
4857 #ifndef CYGWIN
4858 signal( SIGPIPE , SIG_IGN ) ; /* ignore broken pipe */
4859 #endif
4860 if( dbg ) fprintf(stderr," piping image to '%s'\n",filt) ;
4861 fp = popen( filt , "w" ) ; /* open pipe to filter */
4862 if( fp == NULL ){ /* should not happen */
4863 ERROR_message("Can't open output filter %s",filt) ;
4864 break ; /* out of loop over aa */
4865 }
4866
4867 /* write RGB image to pipe as a PPM file */
4868
4869 fprintf(fp,"P6\n%d %d\n255\n" , nx,ny ) ;
4870 fwrite( MRI_RGB_PTR(flim), sizeof(byte), 3*npix, fp ) ;
4871 pc = pclose(fp) ;
4872 if( pc == -1 ) perror("Error in image output pipe") ;
4873 if( dbg ) fprintf(stderr," pipe done\n") ;
4874 } /* loop over aa = image duplicates for animations */
4875
4876 /* done with this image */
4877
4878 mri_free(flim) ; flim = NULL ;
4879
4880 /* 27 Jul 2001: if doing animation,
4881 and if at final image, then create result */
4882
4883 if( kf == seq->saver_to && agif_list != NULL ){
4884
4885 int af ;
4886
4887 if( agif_list->num == 0 ){
4888 ERROR_message("Can't save animation: no images in list!");
4889 goto AnimationCleanup ;
4890 }
4891
4892 /* animated GIF */
4893
4894 if( DO_AGIF(seq) ){
4895 int alen ; char *alc , *alf , *oof ;
4896 #ifdef USE_GIFF
4897 remove( GIFF_MAPFILE ) ; /* don't need this any longer */
4898 #endif
4899
4900 for( alen=af=0 ; af < agif_list->num ; af++ ) /* size of all */
4901 alen += strlen( agif_list->ar[af] ) ; /* filename strings */
4902
4903 alen += 3*agif_list->num + 32 ; /* all filenames */
4904 alc = AFMALL ( char, alen) ; alc[0] = '\0' ; /* in one string */
4905 for( alen=af=0 ; af < agif_list->num ; af++ ){
4906 strcat(alc," ") ; strcat(alc,agif_list->ar[af]) ;
4907 }
4908
4909 oof = AFMALL( char, strlen(seq->saver_prefix)+32 ) ; /* output fname */
4910 sprintf(oof,"%sgif",seq->saver_prefix) ;
4911
4912 alen = strlen(alc)+strlen(ppmto_agif_filter)+strlen(oof)+32 ;
4913 alf = AFMALL( char, alen) ;
4914 sprintf(alf , ppmto_agif_filter, alc, oof ) ; /* command to run */
4915 INFO_message("Running '%s'\n",alf) ;
4916 system(alf) ; /* so run it! */
4917 free(alf) ; free(oof) ; free(alc) ; /* free trash */
4918 }
4919
4920 /* MPEG-1 */
4921
4922 else if( DO_MPEG(seq) ){ /* 02 Aug 2001 */
4923 int alen ; char *alf , *oof , *frate ;
4924 char *qscale , *pattrn ;
4925
4926 /* compose ffmpeg parameters */
4927 oof = AFMALL( char, strlen(seq->saver_prefix)+32 ) ; /* output fname */
4928 sprintf(oof,"%smpg",seq->saver_prefix) ;
4929 qscale=getenv("AFNI_MPEG_QSCALE") ; if(qscale==NULL) qscale="11" ;
4930 frate =getenv("AFNI_MPEG_FRAMERATE"); if(frate ==NULL) frate ="24" ;
4931 pattrn=getenv("AFNI_MPEG_PATTERN") ;
4932 if( pattrn == NULL ){ /* 07 Apr 2009 */
4933 /* by default use only I-frames */
4934 if( adup <= 1 ) pattrn="-intra";
4935 /* otherwise go with ffmpegs default */
4936 else pattrn="";
4937 }
4938 /* make command to run */
4939 alen = strlen(seq->saver_prefix) + strlen(ppmto_mpeg_filter)
4940 +1000 ;
4941 alf = AFMALL( char, alen) ;
4942 /* output fps default to 25 */
4943 sprintf(alf,
4944 "%s -r %s -f image2 -i %s%s.%%06d.ppm -b 400k -qscale %s %s %s",
4945 ppmto_mpeg_filter, frate, seq->saver_prefix, tsuf, qscale,
4946 pattrn, oof) ; /* command to run */
4947 INFO_message("Running '%s' to produce %s\n",alf,oof) ;
4948 system(alf) ; /* so run it! */
4949 free(alf); free(oof); /* free trash */
4950 }
4951
4952 /* animation is done, for good or for ill */
4953
4954 for( af=0 ; af < agif_list->num ; af++ ) /* erase temp files */
4955 remove( agif_list->ar[af] ) ;
4956
4957 AnimationCleanup:
4958 DESTROY_SARR(agif_list) ; /* free more trash */
4959 }
4960 }
4961
4962 /*---------------*/
4963
4964 else if( flim->kind == MRI_rgb ){ /* 11 Feb 1998: write color image */
4965 /* directly as PPM */
4966 if( kf == seq->saver_from )
4967 printf("writing %d x %d RGB images",flim->nx,flim->ny) ;
4968 else if( kf%10 == 5 )
4969 printf("." ) ;
4970 fflush(stdout) ;
4971
4972 seq->set_orim = 0 ; /* 30 Dec 1998 */
4973 tim = flim ;
4974 flim = ISQ_process_mri( kf , seq , tim , 0 ) ; /* image processing */
4975 if( tim != flim ) KILL_1MRI( tim ) ;
4976
4977 /* INFO_message("AFNI_IMAGE_SAVESQUARE = %s",getenv("AFNI_IMAGE_SAVESQUARE")); */
4978 if( AFNI_yesenv("AFNI_IMAGE_SAVESQUARE") ){ /* 08 Jun 2004 */
4979 flim->dx = seq->last_dx ; flim->dy = seq->last_dy ;
4980 if( dbg ) fprintf(stderr," square-ate aspect ratio\n") ;
4981 tim = mri_squareaspect( flim ) ;
4982 if( tim != NULL ){ mri_free(flim); flim = tim; }
4983 }
4984
4985 sprintf( fname , "%s%04d.pnm" , seq->saver_prefix , kf ) ;
4986 mri_write_pnm( fname , flim ) ;
4987
4988 mri_free(flim) ; flim = NULL ; /* done with this image */
4989
4990 /*---------------*/
4991
4992 } else if( ! seq->opt.save_pnm ){ /** write background only **/
4993
4994 if( seq->opt.save_nsize ){
4995 tim = mri_nsize( flim ) ;
4996 if( tim != NULL && tim != flim ){ mri_free(flim) ; flim = tim ; }
4997 }
4998
4999 tim = flim ;
5000 flim = mri_flippo( ISQ_TO_MRI_ROT(seq->opt.rot) , seq->opt.mirror , tim ) ;
5001 if( tim != flim ) KILL_1MRI( tim ) ;
5002
5003 if( kf == seq->saver_from )
5004 printf("writing %d x %d images",flim->nx,flim->ny) ;
5005 else if( kf%10 == 5 )
5006 printf("." ) ;
5007 fflush(stdout) ;
5008
5009 if( flim->kind == MRI_byte ){ /* 17 Feb 1999 */
5010 sprintf( fname , "%s%04d.pnm" , seq->saver_prefix , kf ) ;
5011 mri_write_pnm( fname , flim ) ; mri_free( flim ) ; flim = NULL ;
5012 } else {
5013 sprintf( fname , "%s%04d" , seq->saver_prefix , kf ) ;
5014 mri_write( fname , flim ) ; mri_free( flim ) ; flim = NULL ;
5015 }
5016
5017 /*---------------*/
5018
5019 } else { /** write color overlay and everything **/
5020
5021 MRI_IMAGE *ovim=NULL ;
5022 int ii , nx , ny , npix , bb , allgray , ncode,nout ;
5023 byte *rgb ; /* "byte" is defined in mrilib.h */
5024 short *flar ;
5025 XColor *ulc , *ovc , *xc ;
5026 FILE *fd ;
5027 byte rrr,ggg,bbb ;
5028
5029 /* process given image to make the grayscale index */
5030
5031 seq->set_orim = 0 ; /* 30 Dec 1998 */
5032 tim = flim ;
5033 flim = ISQ_process_mri( kf , seq , tim , 0 ) ; /* will be shorts now */
5034 if( tim != flim ) KILL_1MRI( tim ) ;
5035
5036 flar = mri_data_pointer(flim) ; /* underlay image data */
5037 nx = flim->nx ;
5038 ny = flim->ny ; npix = flim->nx * flim->ny ;
5039
5040 /* get overlay and flip it */
5041
5042 if( !ISQ_SKIP_OVERLAY(seq) ){
5043 tim = ISQ_getoverlay( kf , seq ) ;
5044 if( tim != NULL && !ISQ_GOOD_OVERLAY_TYPE(tim->kind) ){
5045 KILL_1MRI(tim) ;
5046 }
5047 if( tim != NULL )
5048 ovim = mri_flippo( ISQ_TO_MRI_ROT(seq->opt.rot), seq->opt.mirror, tim ) ;
5049 if( tim != ovim ) KILL_1MRI(tim) ;
5050 ISQ_apply_mask( seq->last_automask , ovim ) ;
5051 }
5052
5053 /* perform overlay onto flim [modified 07 Mar 2001] */
5054
5055 if( ovim != NULL ){
5056 tim = flim ;
5057 flim = ISQ_overlay( seq->dc , tim , ovim , seq->ov_opacity ) ;
5058 if( flim == NULL ){ flim = tim ; } /* shouldn't happen */
5059 else { KILL_1MRI(tim) ; }
5060 mri_free( ovim ) ;
5061 }
5062
5063 /* INFO_message("AFNI_IMAGE_SAVESQUARE = %s",getenv("AFNI_IMAGE_SAVESQUARE")); */
5064 if( AFNI_yesenv("AFNI_IMAGE_SAVESQUARE") ){ /* 08 Jun 2004 */
5065 flim->dx = seq->last_dx ; flim->dy = seq->last_dy ;
5066 tim = mri_squareaspect( flim ) ;
5067 if( tim != NULL ){ mri_free(flim); flim = tim; }
5068 }
5069
5070 /* write the output file */
5071
5072 if( kf == seq->saver_from )
5073 printf("writing %d x %d PNM files",nx,ny) ;
5074 else if( kf%10 == 5 )
5075 printf("." ) ;
5076 fflush(stdout) ;
5077
5078 sprintf( fname , "%s%04d.pnm" , seq->saver_prefix , kf ) ;
5079
5080 if( flim->kind == MRI_rgb ){ /* 07 Mar 2001 */
5081 mri_write_pnm( fname , flim ) ; mri_free(flim) ; flim = NULL ;
5082 } else { /* the old way */
5083
5084 /* XColor arrays for underlay and overlay */
5085
5086 ulc = ( seq->dc->use_xcol_im ) ? seq->dc->xcol_im
5087 : seq->dc->xgry_im ;
5088 ovc = seq->dc->ovc->xcol_ov ;
5089
5090 fd = fopen( fname , "r" ) ;
5091 if( fd != NULL ){
5092 fclose(fd) ;
5093 fprintf(stderr,"(FAILED) attempt to overwrite file %s\n",fname) ;
5094 continue ;
5095 }
5096 fd = fopen( fname , "w" ) ;
5097 if( fd == NULL ){
5098 fprintf(stderr,"couldn't open output file %s\n",fname) ;
5099 continue ;
5100 }
5101
5102 /* write the XColor intensities into the output */
5103
5104 rgb = (byte *) XtMalloc( sizeof(byte) * 3 * npix ) ;
5105 bb = 0 ;
5106
5107 allgray = 1 ; /* June 1995: check if all are gray */
5108
5109 flar = mri_data_pointer(flim) ; /* underlay image data */
5110
5111 for( ii=0 ; ii < npix ; ii++ ){
5112 xc = (flar[ii] >= 0) ? (ulc+flar[ii]) : (ovc-flar[ii]) ;
5113 rrr = rgb[bb++] = INTEN_TO_BYTE( xc->red ) ;
5114 ggg = rgb[bb++] = INTEN_TO_BYTE( xc->green ) ;
5115 bbb = rgb[bb++] = INTEN_TO_BYTE( xc->blue ) ;
5116
5117 if( allgray ) allgray = ((rrr==ggg) && (ggg==bbb)) ;
5118 }
5119
5120 /* if all are gray, compress to a PGM, else leave as a PPM */
5121
5122 if( allgray ){
5123 bb = 3 ;
5124 for( ii=1 ; ii < npix ; ii++ ){ rgb[ii] = rgb[bb] ; bb += 3 ; }
5125 ncode = 5 ; /* PGM */
5126 nout = npix ;
5127 } else {
5128 ncode = 6 ; /* PPM */
5129 nout = 3*npix ;
5130 }
5131
5132 fprintf(fd,"P%d\n%d %d\n255\n",ncode,nx,ny) ; /* write PNM header */
5133 fwrite( rgb , sizeof(byte) , nout , fd ) ; /* write bytes */
5134 fclose( fd ); mri_free(flim); flim = NULL; myXtFree(rgb); /* DONE */
5135 }
5136 }
5137 } /* end of loop over images */
5138
5139 printf(". **DONE**\n") ; fflush(stdout) ;
5140
5141 /*--- go home ---*/
5142
5143 #ifndef DONT_USE_METER
5144 if( meter != NULL ) MCW_popdown_meter(meter) ;
5145 #endif
5146
5147 myXtFree( seq->saver_prefix ) ; seq->saver_prefix = NULL ;
5148 EXRETURN ;
5149 }
5150
5151
5152 /*----------------------------------------------------------------------*/
5153 /*! Called from the 'Save' button; starts the save image dialog. */
5154
ISQ_but_save_CB(Widget w,XtPointer client_data,XtPointer call_data)5155 void ISQ_but_save_CB( Widget w , XtPointer client_data ,
5156 XtPointer call_data )
5157 {
5158 MCW_imseq *seq = (MCW_imseq *) client_data ;
5159 int ibl = (seq->saver_blowup > 0 && seq->saver_blowup < 9 ) ? seq->saver_blowup : 1 ;
5160
5161 ENTRY("ISQ_but_save_CB") ;
5162
5163 if( ! ISQ_REALZ(seq) || w == NULL || ! XtIsWidget(w) ) EXRETURN ;
5164
5165 seq->saver_prefix = NULL ;
5166 seq->saver_from = seq->saver_to = -1 ;
5167
5168 /* popup a chooser to choose 'stuff' = items of different kinds */
5169
5170 if( seq->opt.save_one && !DO_ANIM(seq) ){
5171 if( seq->opt.save_filter >= 0 &&
5172 ppmto_gimpize != NULL && ppmto_gimpize[seq->opt.save_filter] ){
5173 MCW_choose_stuff( w , "Image Saver (One)" , ISQ_saver_CB , (XtPointer)seq ,
5174 MSTUF_STRING , "Prefix" ,
5175 MSTUF_INT , "Blowup " , 1 , 8 , ibl ,
5176 MSTUF_YESNO , "Open in Gimp?",
5177 MSTUF_END ) ;
5178 } else {
5179 MCW_choose_stuff( w , "Image Saver (One)" , ISQ_saver_CB , (XtPointer)seq ,
5180 MSTUF_STRING , "Prefix" ,
5181 MSTUF_INT , "Blowup " , 1 , 8 , ibl ,
5182 MSTUF_END ) ;
5183 }
5184 } else {
5185 MCW_choose_stuff( w , "Image Saver (Multiple)" , ISQ_saver_CB , (XtPointer)seq ,
5186 MSTUF_STRING , "Prefix" ,
5187 MSTUF_INT , "Blowup " , 1 , 8 , ibl ,
5188 MSTUF_INT , "From: " , 0 , seq->status->num_total-1 , 0 ,
5189 MSTUF_INT , "To: " , 0 , seq->status->num_total-1 , seq->status->num_total-1 ,
5190 MSTUF_END ) ;
5191 }
5192
5193 ISQ_but_done_reset( seq ) ;
5194 EXRETURN ;
5195 }
5196
5197 /*------------------------------------------------------------------------
5198 Set the "DONE" button back to be the "Done" button
5199 --------------------------------------------------------------------------*/
5200
5201 #ifdef REQUIRE_TWO_DONES
ISQ_but_done_reset(MCW_imseq * seq)5202 void ISQ_but_done_reset( MCW_imseq *seq )
5203 {
5204 if( ! ISQ_VALID(seq) || seq->done_first ) return ;
5205
5206 MCW_set_widget_label( seq->wbut_bot[NBUT_DONE] , ISQ_but_done_label1 ) ;
5207 seq->done_first = True ;
5208 return ;
5209 }
5210 #endif
5211
5212 /*-----------------------------------------------------------------------
5213 Deletion of an imseq from the Macrocosmic All
5214 -------------------------------------------------------------------------*/
5215
ISQ_but_done_CB(Widget w,XtPointer client_data,XtPointer call_data)5216 void ISQ_but_done_CB( Widget w , XtPointer client_data ,
5217 XtPointer call_data )
5218 {
5219 MCW_imseq *seq = (MCW_imseq *)client_data ;
5220
5221 ENTRY("ISQ_but_done_CB") ;
5222
5223 if( ! ISQ_VALID(seq) ) EXRETURN ;
5224
5225 #ifdef REQUIRE_TWO_DONES
5226 /*-- first call from "Done" button --> change label, return */
5227
5228 if( w == seq->wbut_bot[NBUT_DONE] && seq->done_first ){
5229 MCW_set_widget_label( w , ISQ_but_done_label2 ) ;
5230 seq->done_first = False ;
5231 EXRETURN ;
5232 }
5233 #endif
5234
5235 /*-- second call: kill --*/
5236
5237 #ifdef AUTOMATE_STATISTICS /* no longer allowed */
5238 if( seq->glstat->worker != 0 ){ /* remove work process, if started */
5239 XtRemoveWorkProc( seq->glstat->worker ) ;
5240 seq->glstat->worker = 0 ;
5241 }
5242 #endif
5243
5244 ISQ_timer_stop(seq) ;
5245
5246 if( seq->dialog != NULL ){ /* 13 Aug 2002 */
5247 XtDestroyWidget( seq->dialog ) ; NI_sleep(1) ;
5248 }
5249
5250 ISQ_free_alldata( seq ) ;
5251 XtDestroyWidget( seq->wtop ) ; NI_sleep(3) ;
5252 seq->valid = 0 ; /* WE do not deallocate the data structure! */
5253
5254 STATUS("IMSEQ: data destroyed!") ;
5255
5256 if( seq->status->send_CB != NULL ){
5257 ISQ_cbs cbs ;
5258
5259 STATUS("IMSEQ: sending destroy message") ;
5260
5261 cbs.reason = isqCR_destroy ;
5262 #if 0
5263 seq->status->send_CB( seq , seq->getaux , &cbs ) ;
5264 #else
5265 SEND(seq,cbs) ;
5266 #endif
5267 }
5268
5269 EXRETURN ;
5270 }
5271
5272 /*-----------------------------------------------------------------------
5273 delete malloc-ed data in an imseq
5274 -------------------------------------------------------------------------*/
5275
ISQ_free_alldata(MCW_imseq * seq)5276 void ISQ_free_alldata( MCW_imseq *seq )
5277 {
5278 int ib ;
5279
5280 ENTRY("ISQ_free_alldata") ;
5281
5282 if( ! ISQ_VALID(seq) ) EXRETURN ;
5283
5284 KILL_1MRI( seq->imim ) ;
5285 KILL_1MRI( seq->ovim ) ;
5286 KILL_1MRI( seq->orim ) ; /* 30 Dec 1998 */
5287 KILL_1MRI( seq->last_automask ) ; /* 12 Dec 2014 */
5288
5289 KILL_2XIM( seq->given_xim , seq->sized_xim ) ;
5290 KILL_2XIM( seq->given_xbar , seq->sized_xbar ) ;
5291
5292 myXtFree( seq->imstat ) ; seq->imstat = NULL ;
5293 myXtFree( seq->glstat ) ; seq->glstat = NULL ;
5294
5295 for( ib=0 ; ib < seq->num_bbox ; ib++ )
5296 myXtFree( seq->bbox[ib] ) ;
5297 seq->num_bbox = 0 ;
5298
5299 for( ib=0 ; ib < NARROW ; ib++ ) myXtFree( seq->arrow[ib] ) ;
5300
5301 myXtFree( seq->arrowpad ) ;
5302 FREE_AV( seq->mont_across_av ) ;
5303 FREE_AV( seq->mont_down_av ) ;
5304 FREE_AV( seq->mont_skip_av ) ;
5305 FREE_AV( seq->mont_gap_av ) ;
5306 FREE_AV( seq->mont_gapcolor_av ) ;
5307 FREE_AV( seq->mont_type_av ) ;
5308 FREE_AV( seq->transform0D_av ) ; /* 30 Oct 1996 */
5309 FREE_AV( seq->transform2D_av ) ;
5310 FREE_AV( seq->rowgraph_av ) ; /* 30 Dec 1998 */
5311 FREE_AV( seq->surfgraph_av ) ; /* 21 Jan 1999 */
5312 myXtFree( seq->surfgraph_arrowpad );
5313 FREE_AV( seq->ov_opacity_av ) ; /* 07 Mar 2001 */
5314 FREE_AV( seq->wbar_label_av ) ; /* 20 Sep 2001 */
5315 myXtFree( seq->wbar_plots_bbox ) ;
5316
5317 FREE_AV( seq->wbar_labsz_av ) ; /* 06 Jan 2005: oopsie */
5318 myXtFree( seq->pen_bbox ) ; /* 06 Jan 2005: oopsie again */
5319
5320 FREE_AV( seq->slice_proj_av ) ; /* 31 Jan 2002 */
5321 FREE_AV( seq->slice_proj_range_av );
5322
5323 FREE_AV( seq->wbar_ticnum_av ) ; /* 23 Feb 2004 */
5324 FREE_AV( seq->wbar_ticsiz_av ) ; /* 23 Feb 2004 */
5325
5326 FREE_AV( seq->zoom_val_av ) ;
5327 if( seq->zoom_pixmap != (Pixmap) 0 ){
5328 XFreePixmap( seq->dc->display , seq->zoom_pixmap ) ;
5329 seq->zoom_pixmap = (Pixmap) 0 ;
5330 }
5331 MCW_kill_XImage( seq->zoom_xim ) ; seq->zoom_xim = NULL ;
5332
5333 if( seq->rowgraph_mtd != NULL ){ /* 30 Dec 1998 */
5334 seq->rowgraph_mtd->killfunc = NULL ;
5335 plotkill_topshell( seq->rowgraph_mtd ) ;
5336 }
5337
5338 if( seq->surfgraph_mtd != NULL ){ /* 21 Jan 1999 */
5339 seq->surfgraph_mtd->killfunc = NULL ;
5340 plotkill_topshell( seq->surfgraph_mtd ) ;
5341 }
5342
5343 if( seq->graymap_mtd != NULL ){ /* 24 Oct 2003 */
5344 seq->graymap_mtd->killfunc = NULL ;
5345 plotkill_topshell( seq->graymap_mtd ) ;
5346 }
5347
5348 #if 0
5349 myXtFree(seq->status) ; /* 05 Feb 2000 */
5350 #endif
5351
5352 /* 24 Apr 2001: destroy any recorded images */
5353
5354 /* 05 Jan 2005: include the memplot recordings */
5355 if( seq->record_mplot != NULL && seq->record_imarr != NULL ){
5356 for( ib=0 ; ib < IMARR_COUNT(seq->record_imarr) ; ib++ )
5357 delete_memplot( seq->record_mplot[ib] ) ;
5358 free((void *)seq->record_mplot) ; seq->record_mplot = NULL ;
5359 }
5360 if( seq->record_imarr != NULL ) DESTROY_IMARR(seq->record_imarr) ;
5361 if( seq->record_imseq != NULL )
5362 drive_MCW_imseq( seq->record_imseq , isqDR_destroy , NULL ) ;
5363
5364 myXtFree( seq->record_status_bbox ) ;
5365 myXtFree( seq->record_method_bbox ) ;
5366
5367 if( seq->mplot != NULL ){ /* 19 Sep 2001 */
5368 delete_memplot( seq->mplot ); seq->mplot = NULL;
5369 }
5370
5371 if( seq->overlay_label != NULL ){ /* 23 Dec 2011 */
5372 free(seq->overlay_label) ; seq->overlay_label = NULL ;
5373 }
5374
5375 EXRETURN ;
5376 }
5377
5378 /*----------------------------------------------------------------------
5379 callback when the slider (scale) is moved
5380 ------------------------------------------------------------------------*/
5381
ISQ_scale_CB(Widget w,XtPointer client_data,XtPointer call_data)5382 void ISQ_scale_CB( Widget w , XtPointer client_data , XtPointer call_data )
5383 {
5384 MCW_imseq *seq = (MCW_imseq *) client_data ;
5385 XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *) call_data ;
5386
5387 ENTRY("ISQ_scale_CB") ;
5388
5389 if( ! ISQ_REALZ(seq) ) EXRETURN ;
5390
5391 if( seq->status->num_total < 2 ){ /* 29 Jul 2002 */
5392 XmScaleSetValue( seq->wscale , 0 ) ;
5393 EXRETURN ;
5394 }
5395
5396 ISQ_redisplay( seq , cbs->value , isqDR_display ) ;
5397
5398 ISQ_but_done_reset( seq ) ;
5399 EXRETURN ;
5400 }
5401
5402 /*-----------------------------------------------------------------------
5403 Redo the display for a particular image:
5404 n < 0 , type = isqDR_display ==> redisplay current image and overlay
5405 type = isqDR_overlay ==> redisplay current overlay only
5406 type = isqDR_reimage ==> redisplay current image only
5407 type = isqDR_reshow ==> just reshow (same as ISQ_show_image)
5408
5409 n >= 0, type = isqDR_display ==> redisplay image n and overlay n
5410 type = isqDR_overlay ==> if current image is n, just
5411 redisplay overlay n, otherwise both
5412 type = isqDR_reimage ==> if current image is n, just
5413 redisplay image n, otherwise both
5414 -------------------------------------------------------------------------*/
5415
5416 /***
5417 Modified Mar 25 1996:
5418 If the image number scale is moved, then this routine is called,
5419 and then ISQ_set_image_number is called, which then calls the
5420 send_CB callback, which may end up calling this routine again
5421 (via drive_MCW_imseq -- for example, see AFNI_seq_send_CB).
5422 This will result in redisplaying the desired image twice, with
5423 the resulting speed penalty. To prevent this, ISQ_redisplay
5424 now checks if the call is recursive. If it is recursive, and
5425 it is being called with the same seq and n parameters as before,
5426 the routine exits.
5427 ***/
5428
5429 #define RECUR (recur_flg && seq == recur_seq && n == recur_n)
5430
ISQ_redisplay(MCW_imseq * seq,int n,int type)5431 void ISQ_redisplay( MCW_imseq *seq , int n , int type )
5432 {
5433 RwcBoolean kill_im , kill_ov ;
5434 int nrold ;
5435 static int recur_flg = FALSE ;
5436 static int recur_n = -1 ;
5437 static MCW_imseq *recur_seq = NULL ;
5438
5439 if( seq == NULL || seq->ignore_redraws ) return ; /* 16 Aug 2002 */
5440 ENTRY("ISQ_redisplay") ;
5441
5442 if( ! ISQ_VALID(seq) ) EXRETURN ;
5443
5444 /** check for identical recursive call **/
5445
5446 if( RECUR ){
5447 DPRI("ABORTED FOR RECURSION at n =",n) ;
5448 recur_flg = FALSE ; EXRETURN ;
5449 }
5450
5451 /** If no recursion is now occurring, mark for possible recursion later.
5452 This assumes that each level of recursion does not spawn new levels
5453 yet again via the send_CB callback. If this were possible, the
5454 code for recursion prevention would need to be more complicated! **/
5455
5456 if( ! recur_flg ){ recur_flg = TRUE ; recur_n = n ; recur_seq = seq ; }
5457
5458 /** find the image that is being seen right now **/
5459
5460 nrold = seq->im_nr ;
5461 seq->im_label[0] = '\0' ; /* forces redraw of text */
5462
5463 /** set the image number to be displayed now **/
5464
5465 if( n >= 0 && !ISQ_set_image_number(seq,n) ){
5466 if( RECUR ) recur_flg = FALSE ; EXRETURN ;
5467 }
5468
5469 MCW_discard_events_all( seq->wimage , ButtonPressMask ) ; /* 20 Mar 2007 */
5470
5471 switch( type ){
5472 default: { if( RECUR ) recur_flg = FALSE ; EXRETURN ; }
5473
5474 case isqDR_display:
5475 kill_im = kill_ov = True ; /* do both images */
5476 break ;
5477
5478 case isqDR_overlay:
5479 kill_im = (n >=0 ) && (n != nrold) ; /* only do im if new */
5480 kill_ov = True ; /* do overlay */
5481 break ;
5482
5483 case isqDR_reimage:
5484 kill_ov = (n >=0 ) && (n != nrold) ;
5485 kill_im = True ;
5486 break ;
5487
5488 case isqDR_reshow:
5489 kill_ov = kill_im = (n >=0 ) && (n != nrold) ; /* only if new */
5490 break ;
5491 }
5492
5493 if( kill_im ) KILL_1MRI( seq->imim ) ;
5494 if( kill_ov ) KILL_1MRI( seq->ovim ) ;
5495
5496 if( kill_ov || kill_im ) KILL_2XIM( seq->given_xim , seq->sized_xim ) ;
5497
5498 if( kill_ov || kill_im ){
5499 MCW_kill_XImage( seq->zoom_xim ) ; seq->zoom_xim = NULL ;
5500 }
5501
5502 seq->scl_label[0] = '\0' ;
5503 ISQ_show_image( seq ) ;
5504 ISQ_rowgraph_draw( seq ) ;
5505 ISQ_surfgraph_draw( seq ) ; /* 21 Jan 1999 */
5506 ISQ_set_crop_hint( seq ) ; /* 25 Aug 2009 */
5507
5508 if( seq->graymap_mtd != NULL ) ISQ_graymap_draw( seq ) ; /* 24 Oct 2003 */
5509
5510 /* 24 Apr 2001: handle image recording */
5511
5512 if( RECORD_ISON(seq->record_status) && seq->zoom_fac == 1 ){
5513 int pos , meth ;
5514
5515 /* compute where to put this sucker */
5516
5517 switch( seq->record_method ){
5518 default:
5519 case RECORD_METHOD_AFTEREND: pos = 987654321; meth = 1; break;
5520 case RECORD_METHOD_BEFORESTART: pos = 0 ; meth = -1; break;
5521 case RECORD_METHOD_INSERT_MM: pos = -1 ; meth = -1; break;
5522 case RECORD_METHOD_INSERT_PP: pos = -1 ; meth = 1; break;
5523 case RECORD_METHOD_OVERWRITE: pos = -1 ; meth = 0; break;
5524 case RECORD_METHOD_OVERWRITE_MM: pos = -2 ; meth = 0; break;
5525 case RECORD_METHOD_OVERWRITE_PP: pos = -3 ; meth = 0; break;
5526 }
5527
5528 /* put it there */
5529
5530 ISQ_record_addim( seq , pos , meth ) ;
5531
5532 /* if recording just one, switch status off */
5533
5534 if( seq->record_status == RECORD_STATUS_NEXTONE ){
5535 seq->record_status = RECORD_STATUS_OFF ;
5536 MCW_set_bbox( seq->record_status_bbox , RECORD_STATUS_OFF ) ;
5537 MCW_invert_widget( seq->record_cbut ) ;
5538 }
5539 }
5540
5541 /* exit stage left */
5542
5543 if( RECUR ) recur_flg = FALSE ;
5544 EXRETURN ;
5545 }
5546
5547 /*------------------------------------------------------------------------
5548 set image number in an imseq;
5549 return value is 0 if this can't be done, 1 if things go OK
5550 --------------------------------------------------------------------------*/
5551
ISQ_set_image_number(MCW_imseq * seq,int n)5552 int ISQ_set_image_number( MCW_imseq *seq , int n )
5553 {
5554 ENTRY("ISQ_set_image_number") ;
5555
5556 if( ! ISQ_VALID(seq) ) RETURN(0) ;
5557
5558 if( n < 0 || n >= seq->status->num_total ){
5559
5560 if( seq->status->num_total > 1 ){
5561 XBell( seq->dc->display , 100 ) ;
5562 fprintf(stderr,"\n*** ILLEGAL IMAGING:\n"
5563 " ISQ_set_image_number %d\n",n);
5564
5565 fprintf(stderr," status: num_total=%d num_series=%d\n",
5566 seq->status->num_total , seq->status->num_series ) ;
5567 } else {
5568 XmScaleSetValue( seq->wscale , 0 ) ; /* 08 Aug 2001 */
5569 }
5570
5571 RETURN(0) ;
5572 }
5573
5574 if( seq->im_nr != n ){
5575 XmScaleSetValue( seq->wscale , n ) ; /* be sure to change scale */
5576
5577 if( seq->status->send_CB != NULL ){ /* send info to AFNI */
5578 ISQ_cbs cbs ;
5579 seq->im_nr = n ;
5580 cbs.reason = isqCR_newimage ;
5581 cbs.nim = seq->im_nr ;
5582 #if 0
5583 seq->status->send_CB( seq , seq->getaux , &cbs ) ;
5584 #else
5585 SEND(seq,cbs) ; /* AFNI will do the redisplay for all viewers */
5586 #endif
5587 } else { /* no AFNI == do the redisplay now myself */
5588 #if 0
5589 ISQ_redisplay( seq , n , isqDR_display ) ; /* 07 Nov 2002 */
5590 #endif
5591 }
5592 }
5593 RETURN(1) ;
5594 }
5595
5596 /*-------------------------------------------------------------------------*/
5597
5598 /* 15 Mar 2002: stuff for processing X11 errors */
5599
5600 static volatile int xwasbad ;
5601 typedef int (*xhandler)(Display *, XErrorEvent *) ;
qhandler(Display * dpy,XErrorEvent * xev)5602 static int qhandler( Display *dpy , XErrorEvent *xev ){ xwasbad=1; return 0; }
5603
5604 /*-----------------------------------------------------------------------*/
5605
ISQ_center_zoom(MCW_imseq * seq)5606 void ISQ_center_zoom( MCW_imseq *seq ) /* 27 Aug 2009 */
5607 {
5608 int zlev,xcen,ycen ; int_triple xyn ; float mh,zwid , xch,ych ;
5609
5610 ENTRY("ISQ_center_zoom") ;
5611
5612 if( !ISQ_REALZ(seq) || seq->imim == NULL || seq->zoom_fac <= 1 ) EXRETURN ;
5613
5614 #if 0
5615 if( seq->cropit ) /* centering on crop region not implemented */ EXRETURN ;
5616 #endif
5617
5618 xyn = ISQ_get_crosshairs(seq) ; xcen = xyn.i ; ycen = xyn.j ;
5619 if( xcen < 0 || ycen < 0 ) EXRETURN ;
5620 ISQ_unflipxy( seq , &xcen , &ycen ) ; /* flip to screen coord */
5621 if( xcen < 0 || ycen < 0 ) EXRETURN ;
5622 xch = xcen / (float)seq->imim->nx ; if( xch >= 1.0f ) EXRETURN ;
5623 ych = ycen / (float)seq->imim->ny ; if( ych >= 1.0f ) EXRETURN ;
5624
5625 zlev = seq->zoom_fac ;
5626 mh = (zlev-1.001f)/zlev ; /* max offset allowed */
5627 zwid = 0.5f / zlev ;
5628
5629 seq->zoom_hor_off = xch - zwid ;
5630 seq->zoom_ver_off = ych - zwid ;
5631 if( seq->zoom_hor_off > mh ) seq->zoom_hor_off = mh ;
5632 else if( seq->zoom_hor_off < 0.0f ) seq->zoom_hor_off = 0.0f ;
5633 if( seq->zoom_ver_off > mh ) seq->zoom_ver_off = mh ;
5634 else if( seq->zoom_ver_off < 0.0f ) seq->zoom_ver_off = 0.0f ;
5635
5636 ISQ_redisplay( seq , -1 , isqDR_display ) ;
5637
5638 EXRETURN ;
5639 }
5640
5641 /*-----------------------------------------------------------------------*/
5642 /* Put the zoomed image fragment to the display */
5643
ISQ_show_zoom(MCW_imseq * seq)5644 int ISQ_show_zoom( MCW_imseq *seq ) /* 11 Mar 2002 */
5645 {
5646 int iw,ih , zlev=seq->zoom_fac , pw,ph , xoff,yoff , newim=0 , flash=0 ;
5647 static int busy=0 ; /* 23 Jan 2004 */
5648
5649 ENTRY("ISQ_show_zoom") ;
5650
5651 if( busy ){ STATUS(" recursive entry!"); RETURN(-1); } /* recursion = bad */
5652 busy = 1 ;
5653
5654 /* find the size of the image window */
5655
5656 MCW_widget_geom( seq->wimage, &iw,&ih , NULL,NULL ) ;
5657
5658 /* pixmap should be size of image window, scaled up;
5659 if it isn't that size already, free it right now */
5660
5661 pw = iw*zlev ; ph = ih*zlev ;
5662
5663 if( seq->zoom_pixmap != (Pixmap) 0 &&
5664 (pw != seq->zoom_pw || ph != seq->zoom_ph) ){
5665
5666 STATUS("freeing old pixmap") ;
5667 XFreePixmap( seq->dc->display , seq->zoom_pixmap ) ;
5668 seq->zoom_pixmap = (Pixmap) 0 ;
5669 newim++ ;
5670 }
5671
5672 /* (re)make the pixmap, if needed;
5673 it will be saved in the seq struct for next time */
5674
5675 if( seq->zoom_pixmap == (Pixmap) 0 ){
5676 xhandler old_handler = XSetErrorHandler(qhandler); xwasbad = 0;
5677
5678 STATUS("creating new pixmap") ;
5679 seq->zoom_pixmap = XCreatePixmap( seq->dc->display ,
5680 XtWindow(seq->wimage) ,
5681 pw , ph , seq->dc->depth ) ;
5682
5683 (void) XSetErrorHandler(old_handler) ;
5684
5685 /* if allocating pixmap failed, exit now */
5686
5687 if( xwasbad ){
5688 fprintf(stderr,"** Can't zoom - out of memory! **\n\a");
5689 AV_assign_ival( seq->zoom_val_av , ZOOM_BOT ) ;
5690 ISQ_zoom_av_CB( seq->zoom_val_av , seq ) ;
5691 busy = 0 ; RETURN(-1) ;
5692 }
5693
5694 seq->zoom_pw = pw ; seq->zoom_ph = ph ;
5695 newim++ ;
5696 }
5697
5698 /* if we made a new pixmap, we'll need a new zoomed image for it */
5699
5700 if( newim && seq->zoom_xim != NULL ){
5701 STATUS("killing old XImage because have new image") ;
5702 MCW_kill_XImage( seq->zoom_xim ) ; seq->zoom_xim = NULL ;
5703 }
5704
5705 /* scale up the XImage given_xim, if needed;
5706 it will be save in the seq struct for next time,
5707 unless the image changes, in which case it will have been axed */
5708
5709 if( seq->zoom_xim == NULL ){ /* zoom_xim will be the thing we pan around */
5710 MRI_IMAGE *im , *tim ;
5711 STATUS("inverting zoom label") ;
5712 flash = 1 ; MCW_invert_widget( seq->zoom_val_av->wlabel ) ;
5713 STATUS("converting given XImage to MRI_IMAGE") ;
5714 im = XImage_to_mri( seq->dc, seq->given_xim, X2M_USE_CMAP|X2M_FORCE_RGB ) ;
5715 STATUS("zooming up MRI_IMAGE") ;
5716 tim = mri_dup2D(zlev,im) ; mri_free(im) ;
5717 STATUS("converting zoomed MRI_IMAGE back to XImage") ;
5718 seq->zoom_xim = mri_to_XImage(seq->dc,tim) ; mri_free(tim) ;
5719 newim++ ;
5720 }
5721
5722 /* if zoomed image isn't same size as pixmap, resize it here */
5723
5724 if( pw != seq->zoom_xim->width || ph != seq->zoom_xim->height ){
5725 XImage *sxim ;
5726 sxim = resize_XImage( seq->dc , seq->zoom_xim , pw , ph ) ;
5727 STATUS("killing old XImage because doesn't fit pixmap") ;
5728 MCW_kill_XImage( seq->zoom_xim ) ;
5729 seq->zoom_xim = sxim ;
5730 newim++ ;
5731 }
5732
5733 /* if have a new image, put the zoomed XImage into the Pixmap */
5734
5735 if( newim ){
5736 STATUS("putting new image into pixmap") ;
5737 XPutImage( seq->dc->display ,
5738 seq->zoom_pixmap ,
5739 seq->dc->origGC , seq->zoom_xim , 0,0,0,0 , pw,ph ) ;
5740
5741 /* draw the overlay graph into the Pixmap */
5742
5743 if( !seq->opt.no_overlay && seq->mplot != NULL ){
5744 STATUS("drawing overlay plot into pixmap") ;
5745 memplot_to_X11_sef( seq->dc->display ,
5746 seq->zoom_pixmap , seq->mplot ,
5747 0,0,MEMPLOT_FREE_ASPECT ) ;
5748 }
5749 }
5750
5751 /* now we can copy the relevant area
5752 from the pixmap into the image window, which is very fast and smooth */
5753
5754 xoff = seq->zoom_hor_off * pw ; if( xoff+iw > pw ) xoff = pw-iw ;
5755 yoff = seq->zoom_ver_off * ph ; if( yoff+ih > ph ) yoff = ph-ih ;
5756
5757 STATUS("copying from pixmap to image window") ;
5758 XCopyArea( seq->dc->display ,
5759 seq->zoom_pixmap ,
5760 XtWindow(seq->wimage) , seq->dc->origGC ,
5761 xoff , yoff , iw,ih , 0,0 ) ;
5762
5763 if( flash ) MCW_invert_widget( seq->zoom_val_av->wlabel ) ;
5764
5765 #if defined(DISCARD_EXCESS_EXPOSES)
5766 STATUS("discarding excess Expose events") ;
5767 MCW_discard_events( seq->wimage , ExposureMask ) ;
5768 #endif
5769
5770 busy = 0 ; RETURN(1) ;
5771 }
5772
5773 /*-----------------------------------------------------------------------
5774 actually put the image into window
5775 23 Apr 2001 - modified to deal with case of NULL image from
5776 ISQ_make_image() - by drawing a string
5777 -------------------------------------------------------------------------*/
5778
ISQ_show_image(MCW_imseq * seq)5779 void ISQ_show_image( MCW_imseq *seq )
5780 {
5781 if( seq == NULL || seq->ignore_redraws ) return ; /* 16 Aug 2002 */
5782 ENTRY("ISQ_show_image") ;
5783
5784 if( ! ISQ_REALZ(seq) ) EXRETURN ;
5785
5786 if( seq->given_xbar == NULL ) ISQ_show_bar( seq ) ; /* 22 Aug 1998 */
5787
5788 if( seq->given_xim == NULL ) ISQ_make_image( seq ) ;
5789
5790 if( seq->given_xim == NULL ) STATUS("bad news: given_xim == NULL!") ;
5791
5792 if( ! MCW_widget_visible(seq->wimage) ) EXRETURN ; /* 03 Jan 1999 */
5793
5794 if( seq->given_xim != NULL &&
5795 seq->zoom_fac > 1 &&
5796 seq->mont_nx == 1 &&
5797 seq->mont_ny == 1 ){ /* show a zoomed image instead */
5798
5799 int ss = ISQ_show_zoom( seq ) ; /* ss > 0 is good zoom */
5800 if( ss > 0 ){ /* if failed, fall through to code farther below */
5801 EXRETURN ;
5802 }
5803 }
5804
5805 if( seq->given_xim != NULL && seq->sized_xim == NULL ){
5806 int nx , ny ;
5807
5808 STATUS("making sized_xim");
5809
5810 MCW_widget_geom( seq->wimage , &nx , &ny , NULL,NULL ) ;
5811
5812 seq->sized_xim = resize_XImage( seq->dc , seq->given_xim , nx , ny ) ;
5813 }
5814
5815 if( seq->sized_xim != NULL ){
5816 STATUS("putting sized_xim to screen");
5817
5818 #if 0
5819 if( AFNI_yesenv("AFNI_IMSEQ_DEBUG") ){
5820 fprintf(stderr,"==== imseq->wimage: XPutImage w=%d h=%d\n",
5821 seq->sized_xim->width , seq->sized_xim->height ) ;
5822 DBG_traceback() ;
5823 }
5824 #endif
5825
5826 /**** actually put the image to the screen ****/
5827
5828 #if 0
5829 INFO_message("ISQ_show_image(seq=%p) %d x %d",
5830 (void *)seq ,
5831 (int)seq->sized_xim->width , (int)seq->sized_xim->height ) ;
5832 #endif
5833
5834 XPutImage( seq->dc->display , XtWindow(seq->wimage) , seq->dc->origGC ,
5835 seq->sized_xim , 0,0,0,0,
5836 seq->sized_xim->width , seq->sized_xim->height ) ;
5837
5838 } else { /* 23 Apr 2001 - draw 'EMPTY IMAGE' */
5839
5840 static MEM_plotdata *empt=NULL ; /* only create once */
5841
5842 if( empt == NULL ){
5843 STATUS("create EMPTY IMAGE plot") ;
5844 create_memplot_surely("EmptyImagePlot",1.0) ;
5845 /** AFNI_REPLACE_XDRAWLINES ; **/
5846 empt = get_active_memplot() ;
5847 set_color_memplot(1.0,1.0,1.0) ;
5848 set_thick_memplot(0.009) ;
5849 plotpak_pwritf( 0.4,0.83 , "EMPTY" , 96 , 0 , 0 ) ;
5850 plotpak_pwritf( 0.4,0.67 , "IMAGE" , 96 , 0 , 0 ) ;
5851 set_color_memplot(0.0,0.0,0.0) ;
5852 plotpak_pwritf( 0.6,0.33 , "EMPTY" , 96 , 0 , 0 ) ;
5853 plotpak_pwritf( 0.6,0.17 , "IMAGE" , 96 , 0 , 0 ) ;
5854 set_color_memplot(1.0,1.0,0.0) ;
5855 set_thick_memplot(0.019) ;
5856 plotpak_line( 0.01,0.01 , 0.99,0.01 ) ;
5857 plotpak_line( 0.99,0.01 , 0.99,0.99 ) ;
5858 plotpak_line( 0.99,0.99 , 0.01,0.99 ) ;
5859 plotpak_line( 0.01,0.99 , 0.01,0.01 ) ;
5860 set_thick_memplot(0.0) ;
5861 /** AFNI_RESTORE_XDRAWLINES ; **/
5862 }
5863 STATUS("display EMPTY IMAGE plot") ;
5864 XClearWindow( seq->dc->display , XtWindow(seq->wimage) ) ;
5865 memplot_to_X11_sef( seq->dc->display ,
5866 XtWindow(seq->wimage) , empt ,
5867 0,0,MEMPLOT_FREE_ASPECT ) ;
5868 }
5869
5870 /*-- 26 Feb 2001: draw some line overlay, a la coxplot? --*/
5871 /*-- 19 Sep 2001: modified to use memplot stored in seq --*/
5872
5873 if( !seq->opt.no_overlay && seq->mplot != NULL )
5874 memplot_to_X11_sef( seq->dc->display ,
5875 XtWindow(seq->wimage) , seq->mplot ,
5876 0,0,MEMPLOT_FREE_ASPECT ) ;
5877
5878 seq->never_drawn = 0 ;
5879
5880 ISQ_draw_winfo( seq ) ;
5881
5882 #ifdef DISCARD_EXCESS_EXPOSES
5883 MCW_discard_events( seq->wimage , ExposureMask ) ;
5884 #endif
5885
5886 EXRETURN ;
5887 }
5888
5889 /*-------------------------------------------------------------------
5890 Draw the message data in the winfo label (below the image)
5891 ---------------------------------------------------------------------*/
5892
ISQ_draw_winfo(MCW_imseq * seq)5893 void ISQ_draw_winfo( MCW_imseq *seq )
5894 {
5895 char buf[128] = "\0" ;
5896 int nn , ibuf ;
5897 ISQ_indiv_statistics *st ;
5898
5899 ENTRY("ISQ_draw_winfo") ;
5900
5901 if( ! ISQ_REALZ(seq) ) EXRETURN ;
5902
5903 if( seq->last_image_type >= 0 ){
5904 sprintf( buf , "%s" , MRI_TYPE_name[seq->last_image_type] ) ;
5905
5906 if( seq->last_image_type == MRI_complex ){
5907 switch( seq->opt.cx_code ){
5908 case ISQ_CX_MAG: strcat( buf , "[mag]" ) ; break ;
5909 case ISQ_CX_PHASE: strcat( buf , "[arg]" ) ; break ;
5910 case ISQ_CX_REAL: strcat( buf , "[re]" ) ; break ;
5911 case ISQ_CX_IMAG: strcat( buf , "[im]" ) ; break ;
5912 default: break ;
5913 }
5914 }
5915 }
5916 ibuf = strlen(buf) ;
5917
5918 nn = seq->im_nr ; if( nn < 0 ) EXRETURN ;
5919
5920 st = &( seq->imstat[nn] ) ;
5921 #if 0
5922 if( st->one_done ){
5923 #if 0
5924 if( seq->opt.scale_group == ISQ_SCL_AUTO &&
5925 seq->opt.scale_range == ISQ_RNG_02TO98 )
5926
5927 sprintf( buf+ibuf , " 2%%=%g 98%%=%g", st->per02 , st->per98 ) ;
5928 else
5929 #endif
5930
5931 #if 0
5932 sprintf( buf+ibuf , "=%g..%g ent=%.2f" ,
5933 st->min , st->max , st->entropy ) ;
5934 #endif
5935 sprintf( buf+ibuf , "=%g..%g" , st->min , st->max ) ;
5936 }
5937 #endif
5938
5939 if( seq->scl_label[0] != '\0' )
5940 sprintf(buf+strlen(buf)," %s",seq->scl_label) ;
5941 if( (seq->opt.improc_code & ISQ_IMPROC_SHARP) )
5942 sprintf(buf+strlen(buf)," s=%d",(int)(10.0*seq->sharp_fac+.01)) ;
5943 if( seq->render_mode ) strcat(buf,"#") ;
5944
5945 if( seq->im_label[0] == '\0' || strcmp(buf,seq->im_label) != 0 ){
5946 char qbuf[128] ; qbuf[0] = '\0' ;
5947 if( seq->winfo_prefix[0] != '\0' ){ /* 10 Dec 2007 */
5948 strcat(qbuf,seq->winfo_prefix) ; strcat(qbuf,": ") ;
5949 }
5950 if( seq->winfo_extra[0] == '\0' ){
5951
5952 int iw=0 ; /* winfo_sides stuff */
5953 switch( seq->opt.rot ){ /* from 01 Dec 1999 */
5954 case ISQ_ROT_0 : iw=0 ; break ;
5955 case ISQ_ROT_90 : iw=1 ; break ;
5956 case ISQ_ROT_180: iw=2 ; break ;
5957 case ISQ_ROT_270: iw=3 ; break ;
5958 default: break ;
5959 }
5960 if( seq->opt.mirror ) iw = (iw+2)%4 ;
5961
5962 if( seq->winfo_sides[iw][0] != '\0' ){
5963 strcat(qbuf,"left=") ;
5964 strcat(qbuf,seq->winfo_sides[iw]) ;
5965 strcat(qbuf," ") ; strcat(qbuf,buf) ;
5966 MCW_set_widget_label( seq->winfo , qbuf ) ;
5967 } else if( seq->opt.mirror || seq->opt.rot != ISQ_ROT_0 ){
5968 switch( seq->opt.rot ){
5969 case ISQ_ROT_0 : strcat(qbuf,"[" ) ; break ;
5970 case ISQ_ROT_90 : strcat(qbuf,"[90" ) ; break ;
5971 case ISQ_ROT_180: strcat(qbuf,"[180") ; break ;
5972 case ISQ_ROT_270: strcat(qbuf,"[270") ; break ;
5973 default: break ;
5974 }
5975 if( seq->opt.mirror ){
5976 if( seq->opt.rot == ISQ_ROT_0 ) strcat(qbuf,"l] " ) ;
5977 else strcat(qbuf,"+l] ") ;
5978 } else strcat(qbuf,"] " ) ;
5979 strcat(qbuf,buf) ;
5980 MCW_set_widget_label( seq->winfo , qbuf ) ;
5981 } else {
5982 MCW_set_widget_label( seq->winfo , buf ) ; /* default label! */
5983 }
5984
5985 } else { /* winfo_extra stuff */
5986 strcpy(qbuf,seq->winfo_extra) ; /* from 07 Aug 1999 */
5987 strcat(qbuf," ") ; strcat(qbuf,buf) ;
5988 MCW_set_widget_label( seq->winfo , qbuf ) ;
5989 }
5990 strcpy(seq->im_label,buf) ;
5991 }
5992
5993 MCW_set_widget_label( seq->rinfo , seq->rinfo_label ) ;
5994 EXRETURN ;
5995 }
5996
5997 /*-----------------------------------------------------------------------
5998 Put a range hint on the color bar, if possible -- 29 Jul 2001
5999 -------------------------------------------------------------------------*/
6000
ISQ_set_barhint(MCW_imseq * seq,char * lab)6001 void ISQ_set_barhint( MCW_imseq *seq , char *lab )
6002 {
6003 char sbot[16],stop[16] , hint[64] , *sb,*st ;
6004
6005 ENTRY("ISQ_set_barhint") ;
6006
6007 if( !ISQ_REALZ(seq) ) EXRETURN ; /* bad news */
6008
6009 floatfix(seq->barbot) ; floatfix(seq->bartop) ; /* 24 Aug 2009 */
6010
6011 if( seq->barbot < seq->bartop ){ /* can make a hint */
6012 AV_fval_to_char( seq->barbot , sbot ) ; /* convert to nice strings */
6013 AV_fval_to_char( seq->bartop , stop ) ;
6014 sb = (sbot[0] == ' ') ? sbot+1 : sbot ; /* skip leading blanks */
6015 st = (stop[0] == ' ') ? stop+1 : stop ;
6016 if( lab != NULL && strlen(lab) < 32 ) /* create hint */
6017 sprintf(hint,"%s: %s .. %s",lab,sb,st) ;
6018 else
6019 sprintf(hint,"%s .. %s",sb,st) ;
6020 MCW_register_hint( seq->wbar , hint ) ; /* send to hint system */
6021 } else {
6022 MCW_unregister_hint( seq->wbar ) ; /* don't have a hint */
6023 }
6024
6025 EXRETURN ;
6026 }
6027
6028 /*-------------------------------------------------------------------*/
6029
ISQ_set_cursor_state(MCW_imseq * seq,int cstat)6030 void ISQ_set_cursor_state( MCW_imseq *seq , int cstat ) /* 10 Mar 2003 */
6031 {
6032 if( seq->zoom_button1 || seq->record_mode ){
6033 /* XBell(seq->dc->display,100); */ return;
6034 }
6035
6036 #if 0
6037 fprintf(stderr,"ISQ_set_cursor_state: old=%d new=%d\n",seq->cursor_state,cstat);
6038 #endif
6039
6040 switch( cstat ){
6041 default:
6042 POPUP_cursorize( seq->wimage ) ;
6043 seq->cursor_state = CURSOR_NORMAL ;
6044 MCW_set_bbox( seq->pen_bbox , 0 ) ;
6045 break ;
6046
6047 case CURSOR_PENCIL:
6048 PENCIL_cursorize( seq->wimage ) ;
6049 seq->cursor_state = CURSOR_PENCIL ;
6050 MCW_set_bbox( seq->pen_bbox , 1 ) ;
6051 break ;
6052
6053 case CURSOR_CROSSHAIR:
6054 CROSSHAIR_cursorize( seq->wimage ) ;
6055 seq->cursor_state = CURSOR_CROSSHAIR ;
6056 MCW_set_bbox( seq->pen_bbox , 0 ) ;
6057 break ;
6058 }
6059 return ;
6060 }
6061
6062 /*-------------------------------------------------------------------
6063 actually put the color bar into its window
6064 ---------------------------------------------------------------------*/
6065
ISQ_show_bar(MCW_imseq * seq)6066 void ISQ_show_bar( MCW_imseq *seq )
6067 {
6068 if( seq == NULL || seq->ignore_redraws ) return ; /* 16 Aug 2002 */
6069 ENTRY("ISQ_show_bar") ;
6070
6071 if( ! ISQ_REALZ(seq) ) EXRETURN ;
6072
6073 if( ! MCW_widget_visible(seq->wbar) ) EXRETURN ; /* 03 Jan 1999 */
6074
6075 if( seq->given_xbar == NULL ) ISQ_make_bar( seq ) ;
6076
6077 if( seq->sized_xbar == NULL ){
6078 int nx , ny ; char *eee ;
6079 STATUS("making sized_xbar");
6080
6081 MCW_widget_geom( seq->wbar , &nx , &ny , NULL,NULL ) ;
6082
6083 seq->sized_xbar = resize_XImage( seq->dc, seq->given_xbar, nx, ny ) ;
6084
6085 eee = getenv("AFNI_PBAR_TICK") ;
6086 if( eee == NULL || ( toupper(*eee) != 'N' && *eee != '0' ) ){
6087 int jj,kk ;
6088 for( kk=1 ; kk <= 9 ; kk++ ){ /* tic marks [25 Jun 2013] */
6089 jj = (int)rintf( 0.1f*kk*ny ) ;
6090 rectzero_XImage( seq->dc , seq->sized_xbar , 0 ,jj , 2 ,jj ) ;
6091 rectzero_XImage( seq->dc , seq->sized_xbar , nx-3,jj , nx-1,jj ) ;
6092 }
6093 }
6094 }
6095
6096 if( seq->sized_xbar != NULL ){
6097 STATUS("putting sized_xbar to screen");
6098
6099 XPutImage( seq->dc->display , XtWindow(seq->wbar) , seq->dc->origGC ,
6100 seq->sized_xbar , 0,0,0,0,
6101 seq->sized_xbar->width , seq->sized_xbar->height ) ;
6102 }
6103
6104 #ifdef DISCARD_EXCESS_EXPOSES
6105 MCW_discard_events( seq->wbar , ExposureMask ) ;
6106 #endif
6107
6108 EXRETURN ;
6109 }
6110
6111 /*-----------------------------------------------------------------------
6112 Handle all events in an imseq drawing area widget (image or bar).
6113 Feb 1998: Button2 events are passed to their own handler.
6114 -------------------------------------------------------------------------*/
6115
ISQ_drawing_EV(Widget w,XtPointer client_data,XEvent * ev,RwcBoolean * continue_to_dispatch)6116 void ISQ_drawing_EV( Widget w , XtPointer client_data ,
6117 XEvent *ev , RwcBoolean *continue_to_dispatch )
6118 {
6119 MCW_imseq *seq = (MCW_imseq *) client_data ;
6120 static ISQ_cbs cbs ;
6121 static int busy=0 ; /* 23 Jan 2004: prevent recursion */
6122
6123 static int doing_icor=0 ; /* 27 Sep 2021 */
6124
6125 ENTRY("ISQ_drawing_EV") ;
6126
6127 if( busy ){ STATUS("recursive entry!"); EXRETURN; } /* bad! */
6128 if( !ISQ_REALZ(seq) ) EXRETURN ;
6129 busy = 1 ;
6130
6131 if(PRINT_TRACING){
6132 char str[256], *wn ;
6133 if( w == seq->wimage ) wn = "wimage" ;
6134 else if ( w == seq->wbar ) wn = "wbar" ;
6135 else wn = XtName(w) ;
6136 sprintf(str,"Widget=%s Event type=%d",wn,ev->type);
6137 STATUS(str) ;
6138 }
6139
6140 /** memset(&cbs,0,sizeof(ISQ_cbs)) ; **/
6141
6142 switch( ev->type ){
6143
6144 /*----- button release event -----*/
6145
6146 case ButtonRelease:{
6147 XButtonEvent *event = (XButtonEvent *) ev ;
6148 int but = event->button ;
6149
6150 /** 03 Oct 2002: change Shift+Button1 into Button2, then send to that event handler **/
6151
6152 if( but == Button1 &&
6153 ( seq->cursor_state == CURSOR_PENCIL ||
6154 ((event->state & ShiftMask) && !(event->state & ControlMask)) ) ){
6155 event->button = but = Button2 ;
6156 if( seq->button2_enabled && w == seq->wimage )
6157 ISQ_button2_EV( w , client_data , ev , continue_to_dispatch ) ;
6158 else
6159 { /* XBell(seq->dc->display,100); */ busy=0;EXRETURN; }
6160 }
6161
6162 /* Button1 release: turn off zoom-pan mode, if it was on */
6163
6164 if( event->button == Button1 && w == seq->wimage ){
6165 int xrel=event->x , yrel=event->y ; int scd=seq->shft_ctrl_dragged ;
6166
6167 seq->shft_ctrl_dragged = 0 ; /* 17 Mar 2010 */
6168
6169 if( seq->zoom_button1 && !AFNI_yesenv("AFNI_KEEP_PANNING") ){
6170 seq->zoom_button1 = 0 ;
6171 POPUP_cursorize( seq->wimage ) ;
6172 MCW_invert_widget( seq->zoom_drag_pb ) ;
6173 } else if( !seq->zoom_button1 ){ /* 23 Oct 2003 */
6174 if( seq->cmap_changed ){
6175 COLORMAP_CHANGE(seq); seq->cmap_changed = 0;
6176 if( seq->graymap_mtd != NULL && AFNI_yesenv("AFNI_STROKE_AUTOPLOT") ){
6177 NI_sleep(666) ; /* pop down after a short delay */
6178 plotkill_topshell( seq->graymap_mtd ) ;
6179 seq->graymap_mtd = NULL ;
6180 }
6181 } else if( seq->status->send_CB != NULL ){ /* 04 Nov 2003 */
6182 int imx,imy,nim;
6183 seq->wimage_width = -1 ;
6184 if( scd || abs(seq->last_bx-xrel)+abs(seq->last_by-yrel) < 8 ){
6185 int xuse,yuse ;
6186 if( scd ){ xuse = xrel ; yuse = yrel ; }
6187 else { xuse = seq->last_bx; yuse = seq->last_by; }
6188 ISQ_mapxy( seq , xuse,yuse , &imx,&imy,&nim ) ;
6189 cbs.reason = isqCR_buttonpress ;
6190 cbs.event = ev ;
6191 cbs.xim = imx ; /* delayed send of Button1 */
6192 cbs.yim = imy ; /* event to AFNI now */
6193 cbs.nim = nim ;
6194
6195 if( doing_icor ){ /* 27 Sep 2021 */
6196 event->state &= ~ShiftMask ;
6197 event->state &= ~ControlMask ;
6198 doing_icor = 0 ;
6199 }
6200 #if 0
6201 seq->status->send_CB( seq , seq->getaux , &cbs ) ;
6202 #else
6203 SEND(seq,cbs) ;
6204 #endif
6205 }
6206 }
6207 }
6208 }
6209 }
6210 break ; /*--- end of ButtonRelease ---*/
6211
6212 /*----- motion with Button #1 pressed down -----*/
6213
6214 case MotionNotify:{
6215 XMotionEvent *event = (XMotionEvent *) ev ;
6216 int bx,by ;
6217
6218 /** 03 Oct 2002: change Shift+Button1 into Button2, send to event handler **/
6219
6220 if( (event->state & Button1Mask) &&
6221 ( seq->cursor_state == CURSOR_PENCIL ||
6222 ((event->state & ShiftMask) && !(event->state & ControlMask)) ) ){
6223 event->state |= Button2Mask ;
6224 if( seq->button2_enabled && w == seq->wimage )
6225 ISQ_button2_EV( w , client_data , ev , continue_to_dispatch ) ;
6226 else
6227 { /* XBell(seq->dc->display,100); */ busy=0;EXRETURN; }
6228 busy=0;EXRETURN ;
6229 }
6230
6231 /** 17 Mar 2010: Shift+Ctrl+Button1 = send to our master [InstaCorr] **/
6232
6233 if( (event->state & Button1Mask) && (seq->status->send_CB != NULL) &&
6234 (event->state & ShiftMask) && (event->state & ControlMask) ){
6235 int imx,imy,nim;
6236 seq->wimage_width = -1 ;
6237 ISQ_mapxy( seq , event->x,event->y , &imx,&imy,&nim ) ;
6238 cbs.reason = isqCR_buttonmove ;
6239 cbs.event = ev ;
6240 cbs.xim = imx ; /* delayed send of Button1 */
6241 cbs.yim = imy ; /* event to AFNI now */
6242 cbs.nim = nim ;
6243 doing_icor = 1 ;
6244 SEND(seq,cbs) ; busy=0 ; seq->shft_ctrl_dragged=1 ; EXRETURN ;
6245 }
6246
6247 /* Button1 motion: if not panning, changing the color/gray map? */
6248
6249 if( !seq->zoom_button1 && (event->state & Button1Mask) ){
6250 int xdif = (event->x - seq->last_bx) ;
6251 int ydif = (event->y - seq->last_by) ;
6252 if( !seq->dc->use_xcol_im && (xdif || ydif) ){
6253 double denom = AFNI_numenv("AFNI_STROKE_THRESHOLD") ;
6254 if( denom < 1.0l ){
6255 if( getenv("AFNI_STROKE_THRESHOLD") != NULL ){ busy=0;EXRETURN ;}
6256 denom = 32.0l ;
6257 }
6258 xdif = rint(xdif/denom) ; ydif = rint(ydif/denom) ;
6259 if( xdif || ydif ){ /* if big enough change */
6260 if( seq->imim != NULL && seq->imim->kind == MRI_rgb ){ /* 26 Apr 2005 */
6261
6262 if( xdif > 0 ){ seq->rgb_gamma *= 0.95 ; } /* change the RGB */
6263 else if( xdif < 0 ){ seq->rgb_gamma /= 0.95 ; } /* colorizing */
6264 if( ydif < 0 ){ seq->rgb_offset += 0.014; }
6265 else if( ydif > 0 ){ seq->rgb_offset -= 0.014; }
6266 ISQ_redisplay( seq , -1 , isqDR_reimage ) ;
6267 seq->cmap_changed = 1 ;
6268 seq->last_bx = event->x ; seq->last_by = event->y;
6269
6270 } else { /* the old way: change the gray map */
6271
6272 if( xdif ){ DC_gray_conbrio(seq->dc, xdif); seq->last_bx=event->x;}
6273 if( ydif ){ DC_gray_change (seq->dc,-ydif); seq->last_by=event->y;}
6274 seq->cmap_changed = 1 ;
6275 if( seq->dc->visual_class == TrueColor ){
6276 if( seq->graymap_mtd == NULL &&
6277 AFNI_yesenv("AFNI_STROKE_AUTOPLOT") ) ISQ_graymap_draw( seq ) ;
6278 KILL_2XIM( seq->given_xbar , seq->sized_xbar ) ;
6279 ISQ_redisplay( seq , -1 , isqDR_display ) ;
6280 } else {
6281 if( seq->graymap_mtd != NULL ) ISQ_graymap_draw( seq ) ;
6282 }
6283 }
6284 }
6285 }
6286 busy=0; EXRETURN ;
6287 } /* end of altering colormap */
6288
6289 /* Button1 motion: check for being in zoom-pan mode */
6290
6291 if( !seq->zoom_button1 ||
6292 seq->zoom_fac == 1 ||
6293 seq->zoom_xim == NULL ||
6294 (event->state & Button1Mask)==0 ){ busy=0; EXRETURN; } /* not zoom-pan? */
6295
6296 /*-- if here, change panning offset --*/
6297
6298 bx = event->x ; by = event->y ;
6299 ISQ_actually_pan( seq , (bx>seq->zoom_xp) ? -1
6300 :(bx<seq->zoom_xp) ? 1 : 0 ,
6301 (by>seq->zoom_yp) ? -1
6302 :(by<seq->zoom_yp) ? 1 : 0 ) ;
6303
6304 seq->zoom_xp = bx ; seq->zoom_yp = by ;
6305
6306 busy=0; EXRETURN ;
6307 }
6308 break ; /*--- end of MotionNotify ---*/
6309
6310 /*----- redraw -----*/
6311
6312 case Expose:{
6313 XExposeEvent *event = (XExposeEvent *) ev ;
6314
6315 DPRI(" .. Expose; count=",event->count) ;
6316
6317 XSync( XtDisplay(w) , False ) ;
6318 if( event->count == 0 ){ /* don't bother if more Expose to come */
6319 if( w == seq->wimage ){ /* 25 Sep 2000: check for hidden resizes */
6320 int nx,ny ;
6321 MCW_widget_geom( seq->wimage , &nx , &ny , NULL,NULL ) ;
6322
6323 if( seq->sized_xim != NULL &&
6324 ( (nx != seq->sized_xim->width ) ||
6325 (ny != seq->sized_xim->height) ) ){ /* found a hidden resize */
6326 /* so let's un-hide it! */
6327 XConfigureEvent nev ;
6328
6329 STATUS(" .. really a hidden resize") ;
6330
6331 #if 0
6332 INFO_message("convert Expose to ConfigureNotify") ;
6333 #endif
6334 nev.type = ConfigureNotify ; nev.width = nx ; nev.height = ny ;
6335 ISQ_drawing_EV( w, client_data, (XEvent *) &nev, continue_to_dispatch ) ;
6336
6337 } else
6338 #if 0
6339 INFO_message("Expose") ;
6340 #endif
6341 ISQ_show_image( seq ) ;
6342 }
6343 else if( w == seq->wbar )
6344 ISQ_show_bar( seq ) ;
6345
6346 #ifdef DISCARD_EXCESS_EXPOSES
6347 STATUS("discarding excess Expose events") ;
6348 MCW_discard_events( w , ExposureMask ) ;
6349 #endif
6350 }
6351 }
6352 break ; /*--- end of Expose ---*/
6353
6354 /*----- take key press -----*/
6355
6356 case KeyPress:{
6357 XKeyEvent *event = (XKeyEvent *) ev ;
6358 char buf[32] ;
6359 int nbuf ;
6360 KeySym ks ;
6361
6362 STATUS(" .. KeyPress") ;
6363
6364 ISQ_timer_stop(seq) ; /* 03 Dec 2003 */
6365 doing_icor = 0 ;
6366
6367 /* discard if a mouse button is also pressed at this time */
6368
6369 if( event->state & (Button1Mask|Button2Mask|Button3Mask) ){
6370 /* XBell(seq->dc->display,100); */ busy=0; EXRETURN;
6371 }
6372
6373 /* get the string corresponding to the key pressed */
6374
6375 buf[0] = '\0' ;
6376 ks = 0 ;
6377 nbuf = XLookupString( event , buf , 32 , &ks , NULL ) ;
6378 #if 0
6379 fprintf(stderr,"KeySym=%04x nbuf=%d state=%u\n",(unsigned int)ks,nbuf,event->state) ;
6380 #endif
6381
6382 /* 24 Jan 2003: deal with special function keys */
6383
6384 if( nbuf == 0 || ks > 255 ){
6385 if( seq->record_mode ){ busy=0; EXRETURN ; }
6386 nbuf = ISQ_handle_keypress( seq , (unsigned long)ks ,
6387 (unsigned int )event->state ) ;
6388 busy=0; EXRETURN ;
6389 }
6390
6391 nbuf = ISQ_handle_keypress( seq , (unsigned long)buf[0] , 0 ) ;
6392 if( nbuf ){ busy=0; EXRETURN; }
6393
6394 /* in special modes (record, Button2, zoom-pan) mode, this is bad */
6395
6396 if( seq->record_mode || seq->button2_active || seq->zoom_button1 ){
6397 /* XBell(seq->dc->display,100); */ busy=0; EXRETURN;
6398 }
6399
6400 /* un-handled as yet? notify the master, if we have one */
6401
6402 if( w == seq->wimage && seq->status->send_CB != NULL ){
6403 cbs.reason = isqCR_keypress ;
6404 cbs.event = ev ;
6405 cbs.key = buf[0] ;
6406 cbs.nim = seq->im_nr ;
6407 #if 0
6408 seq->status->send_CB( seq , seq->getaux , &cbs ) ;
6409 #else
6410 SEND(seq,cbs) ;
6411 #endif
6412 }
6413 }
6414 break ; /*--- end of KeyPress ---*/
6415
6416 /*----- take button press -----*/
6417
6418 case ButtonPress:{
6419 XButtonEvent *event = (XButtonEvent *) ev ;
6420 int bx,by , width,height , but ;
6421
6422 STATUS(" .. ButtonPress") ;
6423
6424 doing_icor = 0 ;
6425
6426 /* don't allow button presses in a recorder window, or in zoom-pan mode */
6427
6428 if( seq->record_mode || seq->zoom_button1 ){
6429 /* if( seq->record_mode || event->button != Button1 ) XBell(seq->dc->display,100); */
6430 busy=0; EXRETURN;
6431 }
6432
6433 but = event->button ;
6434
6435 /* button press in the wbar => popup menu */
6436
6437 if( w == seq->wbar ){ /* moved here 18 Oct 2001 */
6438 if( but == Button1 ){ /* 21 Oct 2003 */
6439 bx = seq->opt.free_aspect ; seq->opt.free_aspect = 0 ;
6440 ISQ_reset_dimen( seq, seq->last_width_mm, seq->last_height_mm ) ;
6441 seq->opt.free_aspect = bx ;
6442 } else if( but == Button3 ){
6443 XmMenuPosition( seq->wbar_menu , event ) ; /* where */
6444 XtManageChild ( seq->wbar_menu ) ; /* popup */
6445 }
6446 else if( but == Button4 || but == Button5 ){ /* Scroll Wheel */
6447 int ddd = (but==Button4) ? -1 : 1 ;
6448 if( scrollwheel_debug ){
6449 INFO_message("Scrollwheel (wbar): button=%u ; state mask=%xx",but,event->state) ;
6450 ININFO_message(" (mask: shift=%xx ctrl=%xx mod1=%xx mod2=%xx mod3=%xx mod4=%xx mod5=%xx)" ,
6451 ShiftMask , ControlMask , Mod1Mask , Mod2Mask , Mod3Mask , Mod4Mask , Mod5Mask ) ;
6452 }
6453 if( (event->state & scrollwheel_tmask) )
6454 DC_palette_bright( seq->dc , ddd ) ; /* brightness */
6455 else
6456 DC_palette_squeeze( seq->dc , ddd ) ; /* contrast */
6457 COLORMAP_CHANGE(seq) ;
6458 }
6459 else {
6460 #if 0
6461 XUngrabPointer( event->display , CurrentTime ) ;
6462 #else
6463 /* XBell(seq->dc->display,100) ; */
6464 #endif
6465 }
6466 MCW_discard_events( w , ButtonPressMask ) ;
6467 busy=0; EXRETURN ;
6468 }
6469
6470 /* below here, button press was in the image */
6471
6472 seq->last_bx = bx = event->x ; /* 23 Oct 2003: save last button */
6473 seq->last_by = by = event->y ; /* press (x,y) coords */
6474 seq->cmap_changed = 0 ;
6475
6476 /* 26 Feb 2007: Buttons 4 and 5 = Scroll Wheel = change slice */
6477
6478 if( but == Button4 || but == Button5 ){
6479 if( seq->button2_enabled ){ busy=0; EXRETURN; } /* 10 Oct 2007 */
6480 if( scrollwheel_debug ){
6481 INFO_message("Scrollwheel (imag): button=%u ; state mask=%xx",but,event->state) ;
6482 ININFO_message(" (mask: shift=%xx ctrl=%xx mod1=%xx mod2=%xx mod3=%xx mod4=%xx mod5=%xx)" ,
6483 ShiftMask , ControlMask , Mod1Mask , Mod2Mask , Mod3Mask , Mod4Mask , Mod5Mask ) ;
6484 }
6485 if( (event->state & scrollwheel_tmask) ){ /* mod+scroll == '{}' */
6486 if( scrollwheel_debug ) ININFO_message(" change threshold") ;
6487 STATUS("scroll wheel ==> change threshold") ;
6488 cbs.reason = isqCR_keypress ;
6489 cbs.event = ev ;
6490 cbs.key = (but==Button4) ? '}' : '{' ; /* == change threshold */
6491 cbs.nim = seq->im_nr ;
6492 SEND(seq,cbs) ;
6493 } else { /* no modifiers == change slice */
6494 int nold=seq->im_nr , dd=(but==Button4)?-1:+1 , nnew ;
6495 if( scrollwheel_debug ) ININFO_message(" change slice") ;
6496 STATUS("scroll wheel ==> change slice") ;
6497 if( AFNI_yesenv("AFNI_INDEX_SCROLLREV") ) dd = -dd ;
6498 nnew = nold + dd ;
6499 ISQ_timer_stop(seq) ;
6500 if( nnew >= 0 && nnew < seq->status->num_total )
6501 ISQ_redisplay( seq , nnew , isqDR_display ) ;
6502 }
6503 MCW_discard_events( w , ButtonPressMask ) ;
6504 busy=0; EXRETURN;
6505 }
6506
6507 MCW_widget_geom( w , &width , &height , NULL,NULL ) ;
6508 seq->wimage_width = width ;
6509 seq->wimage_height = height ;
6510
6511 MCW_discard_events( w , ButtonPressMask ) ;
6512
6513 /* 12-17 Jun 2002: Shift+Button2 for picking crop rectangle */
6514
6515 if( w == seq->wimage &&
6516 ( (but==Button2 && (event->state & ShiftMask)) ||
6517 (seq->crop_drag) ) ){
6518
6519 ISQ_cropper( seq , event ) ;
6520 busy=0; EXRETURN ;
6521
6522 } /* end of cropping stuff */
6523
6524 /** 03 Oct 2002: change Shift+Button1 into Button2 **/
6525
6526 if( but == Button1 &&
6527 ( seq->cursor_state == CURSOR_PENCIL ||
6528 ((event->state & ShiftMask) && !(event->state & ControlMask)) ) )
6529 event->button = but = Button2 ;
6530
6531 /*-- default processing --*/
6532
6533 switch( but ){
6534
6535 case Button3:
6536 case Button1:{
6537 int imx,imy,nim;
6538
6539 /* while Button2 is active, nothing else is allowed */
6540
6541 if( seq->button2_active ){
6542 /*** XBell(seq->dc->display,100) ; ***/
6543 busy=0; EXRETURN ;
6544 }
6545
6546 /* Button3 presses in the image with a modifier
6547 key pressed also means to popup some menu */
6548
6549 if( w == seq->wimage && but == Button3 &&
6550 (event->state & (ShiftMask|ControlMask|Mod1Mask)) ){
6551
6552 /* 23 Oct 1996: Simulation of bottom buttons */
6553
6554 if( (event->state & ShiftMask) && !(event->state & ControlMask) )
6555 ISQ_but_disp_CB( seq->wbut_bot[NBUT_DISP] , seq , NULL ) ;
6556
6557 else if( (event->state & ControlMask) ){
6558 if( seq->status->num_total > 1 && !(event->state & ShiftMask) ){
6559 ISQ_montage_CB( seq->wbut_bot[NBUT_MONT] , seq , NULL ) ;
6560 } else {
6561 XmMenuPosition( seq->wbar_menu , event ) ;
6562 XtManageChild ( seq->wbar_menu ) ;
6563 }
6564 }
6565
6566 else if( (seq->opt.save_one || seq->status->num_total > 1)
6567 && (event->state & Mod1Mask) )
6568 ISQ_but_save_CB( seq->wbut_bot[NBUT_SAVE] , seq , NULL ) ;
6569
6570 /* else
6571 XBell( seq->dc->display , 100 ) ; */
6572
6573 /* Button1: compute the location in the image
6574 where the button event transpired, and send to AFNI */
6575
6576 } else if( w == seq->wimage && seq->status->send_CB != NULL ){
6577
6578 seq->wimage_width = -1 ;
6579 ISQ_mapxy( seq , bx,by , &imx,&imy,&nim ) ;
6580 cbs.reason = isqCR_buttonpress ;
6581 cbs.event = ev ;
6582 cbs.xim = imx ;
6583 cbs.yim = imy ;
6584 cbs.nim = nim ;
6585
6586 doing_icor = ( (event->state&ShiftMask) && (event->state&ControlMask) ) ;
6587
6588 if( but == Button1 &&
6589 (event->state & ControlMask) && !(event->state & ShiftMask) ){ /* 18 Oct 2001 */
6590 event->button = Button3 ; /* fake Button3 press */
6591 }
6592
6593 if( event->button == Button3 || /* 04 Nov 2003: only for Button3 */
6594 (event->button == Button1 && event->state&ShiftMask && event->state&ControlMask) )
6595 #if 0
6596 seq->status->send_CB( seq , seq->getaux , &cbs ) ;
6597 #else
6598 SEND(seq,cbs) ;
6599 #endif
6600 }
6601 }
6602 break ;
6603
6604 /* pass this event to the separate handler, if allowed */
6605
6606 case Button2:{
6607
6608 /* drawing mode */
6609
6610 if( seq->button2_enabled && w == seq->wimage )
6611 ISQ_button2_EV( w , client_data , ev , continue_to_dispatch ) ;
6612 else
6613 { /* XBell(seq->dc->display,100); */ busy=0; EXRETURN; }
6614 }
6615 break ;
6616
6617 default: break ;
6618 }
6619 }
6620 ISQ_but_done_reset( seq ) ;
6621 break ; /*--- end of ButtonPress ---*/
6622
6623 /*----- window changed size -----*/
6624
6625 case ConfigureNotify:{
6626 XConfigureEvent *event = (XConfigureEvent *) ev ;
6627
6628 static int am_active = 0 ; /* 09 Oct 1999 */
6629
6630 #if 0
6631 /* 04 Nov 2003: don't do anything while mouse is down */
6632 /* [doesn't work well - usually prevents anything at all] */
6633
6634 { Window rW,cW ; int rx,ry,x,y ; unsigned int mask ;
6635 XQueryPointer(XtDisplay(w),XtWindow(w),&rW,&cW,&rx,&ry,&x,&y,&mask) ;
6636 if( mask & (Button1Mask|Button2Mask|Button3Mask) ) break ;
6637 }
6638 #endif
6639
6640 if( am_active ) break ; /* prevent recursion */
6641 am_active = 1 ;
6642
6643 #if 0
6644 /* Scan forward and see if another such event is
6645 pending. If so, don't process this one.
6646 [doesn't work well - can result in not redrawing at proper size?] */
6647
6648 { XEvent evjunk ; int egood ;
6649 egood = XCheckWindowEvent(XtDisplay(w),XtWindow(w),StructureNotifyMask,&evjunk) ;
6650 if( egood && evjunk.type == ConfigureNotify ){
6651 am_active = 0 ; break ;
6652 }
6653 }
6654 #endif
6655
6656
6657 if(PRINT_TRACING){
6658 char str[256] ;
6659 sprintf(str," .. ConfigureNotify: width=%d height=%d",
6660 event->width,event->height);
6661 STATUS(str) ;
6662 }
6663
6664 /* simply delete the XImage sized to the window;
6665 redisplay will then automatically size it when called */
6666
6667 if( w == seq->wimage ){
6668
6669 int nx,ny ;
6670 #if 0
6671 int ntime=NI_clock_time(); /* 09 May 2018 [useless?] */
6672 static int ltime=-666;
6673 if( ntime-ltime < 2 ){ am_active = 0 ; break ; } /* too fast? */
6674 ltime = ntime ;
6675 #endif
6676
6677 MCW_widget_geom( seq->wimage , &nx , &ny , NULL,NULL ) ;
6678 if( (seq->sized_xim == NULL) ||
6679 (nx != seq->sized_xim->width ) || /* modified 09 May 2018 */
6680 (ny != seq->sized_xim->height) ){ /* to check nx and ny */
6681
6682 seq->wimage_width = seq->wimage_height = -1 ; /* Feb 1998 */
6683
6684 KILL_2ndXIM( seq->given_xim , seq->sized_xim ) ;
6685
6686 /*-- 09 Oct 1999: if ordered, enforce aspect --*/
6687 /*-- 21 Oct 2003: only if it's been a while --*/
6688
6689 #if 0
6690 fprintf(stderr,"ConfigureNotify: width=%d height=%d\n",event->width,event->height);
6691 #endif
6692
6693 #if 0 /* removed 10 May 2018 */
6694 if( AFNI_yesenv("AFNI_ENFORCE_ASPECT") && !seq->opt.free_aspect ){
6695 static int last_time=-666 ; int now_time=NI_clock_time() ;
6696 if( now_time-last_time > 555 )
6697 ISQ_reset_dimen( seq, seq->last_width_mm, seq->last_height_mm ) ;
6698 #if 0
6699 else fprintf(stderr," -- too soon to enforce aspect!\n") ;
6700 #endif
6701 last_time = now_time ;
6702 }
6703 #endif
6704
6705 /*-- now show the image in the new window size --*/
6706
6707 #if 0
6708 INFO_message("ConfigureNotify") ;
6709 #endif
6710 ISQ_show_image( seq ) ;
6711 } else {
6712 #if 0
6713 INFO_message("reject image ConfigureNotify") ;
6714 #endif
6715 }
6716
6717 } else if( w == seq->wbar ){
6718 int nx,ny ;
6719 MCW_widget_geom( seq->wbar , &nx , &ny , NULL,NULL ) ;
6720 if( (seq->sized_xbar == NULL) ||
6721 (nx != seq->sized_xbar->width ) ||
6722 (ny != seq->sized_xbar->height) ){
6723
6724 KILL_2ndXIM( seq->given_xbar , seq->sized_xbar ) ;
6725 ISQ_show_bar( seq ) ;
6726 } else {
6727 #if 0
6728 INFO_message("reject wbar ConfigureNotify") ;
6729 #endif
6730 }
6731 }
6732
6733 am_active = 0 ;
6734 }
6735 break ; /*--- end of ConfigureNotify ---*/
6736
6737 /*----- ignore all other events -----*/
6738
6739 default: break ;
6740
6741 } /* end of switch ev->type */
6742
6743 busy=0; EXRETURN ;
6744 }
6745
6746 /*-----------------------------------------------------------------------
6747 Handle Button2 events in the image window -- Feb 1998
6748 -------------------------------------------------------------------------*/
6749
6750 #define NPTS_MAX 4095 /* max # points in a single button2 operation */
6751
ISQ_button2_EV(Widget w,XtPointer client_data,XEvent * ev,RwcBoolean * continue_to_dispatch)6752 void ISQ_button2_EV( Widget w , XtPointer client_data ,
6753 XEvent *ev , RwcBoolean *continue_to_dispatch )
6754 {
6755 MCW_imseq *seq = (MCW_imseq *) client_data ;
6756 ISQ_cbs cbs ;
6757 static int nsav ;
6758 static int *bxsav=NULL , *bysav=NULL , *xyout=NULL ;
6759
6760 ENTRY("ISQ_button2_EV") ;
6761
6762 /* check for legality */
6763
6764 if( !ISQ_REALZ(seq) || !seq->button2_enabled || w != seq->wimage ) EXRETURN ;
6765
6766 ISQ_timer_stop(seq) ;
6767
6768 switch( ev->type ){
6769
6770 /*----- take button press -----*/
6771
6772 case ButtonPress:{
6773 XButtonEvent *event = (XButtonEvent *) ev ;
6774 int bx,by , but , xim,yim,zim ;
6775
6776 but = event->button ; if( but != Button2 ) EXRETURN ;
6777
6778 seq->button2_active = 1 ; /* allow other button2 stuff to happen */
6779
6780 /* 1st time in: allocate space to save points */
6781
6782 if( bxsav == NULL ){
6783 bxsav = (int *) malloc( sizeof(int) * (NPTS_MAX+1) ) ;
6784 bysav = (int *) malloc( sizeof(int) * (NPTS_MAX+1) ) ;
6785 }
6786
6787 /* save this point */
6788
6789 bx = event->x ; by = event->y ;
6790 bxsav[0] = bx ; bysav[0] = by ; nsav = 1 ;
6791
6792 /* find where this point is in original images --
6793 if it is illegal, quit this mockery of a travesty of a sham */
6794
6795 seq->wimage_width = -1 ;
6796 ISQ_mapxy( seq , bx,by , &xim,&yim,&zim ) ;
6797 if( xim < 0 || yim < 0 || zim < 0 || zim >= seq->status->num_total ){
6798 seq->button2_active = 0 ; /* disallow button2 stuff */
6799 XBell( seq->dc->display , 100 ) ; /* express our displeasure */
6800 EXRETURN ;
6801 }
6802
6803 /* draw this point */
6804
6805 if( seq->button2_drawmode != BUTTON2_NODRAW ){
6806 DC_fg_colorpix( seq->dc , seq->button2_pixel ) ;
6807 XDrawPoint( seq->dc->display , XtWindow(seq->wimage) ,
6808 seq->dc->myGC , bx,by ) ;
6809 }
6810 }
6811 break ;
6812
6813 /*----- take button release -----*/
6814
6815 case ButtonRelease:{
6816 XButtonEvent *event = (XButtonEvent *) ev ;
6817 int bx,by ;
6818 int ii,nout , nim , xim,yim,zim ;
6819
6820 /* check for legality */
6821
6822 if( !seq->button2_active || event->button != Button2 ) EXRETURN ;
6823
6824 bx = event->x ; by = event->y ; /* where did it happen? */
6825
6826 /* if a new point, save it and draw it */
6827
6828 if( bx != bxsav[nsav-1] || by != bysav[nsav-1] ){
6829
6830 if( seq->button2_drawmode == BUTTON2_POINTS ){
6831 XDrawPoint( seq->dc->display , XtWindow(seq->wimage) ,
6832 seq->dc->myGC , bx,by ) ;
6833 } else if( seq->button2_drawmode != BUTTON2_NODRAW ){
6834 if( seq->button2_width > 0 ) /* 08 Oct 2002 */
6835 DC_linewidth( seq->dc , seq->button2_width ) ;
6836 XDrawLine( seq->dc->display , XtWindow(seq->wimage) ,
6837 seq->dc->myGC , bxsav[nsav-1],bysav[nsav-1],bx,by ) ;
6838 if( seq->button2_width > 0 ) DC_linewidth( seq->dc , 0 ) ;
6839 }
6840
6841 bxsav[nsav] = bx ; bysav[nsav] = by ;
6842 if( nsav < NPTS_MAX ) nsav++ ;
6843 }
6844
6845 /* this is the last point in this sequence --
6846 if we are drawing closed polygon, then close it now */
6847
6848 if( seq->button2_drawmode == BUTTON2_CLOSEDPOLY && nsav > 2 ){
6849 if( seq->button2_width > 0 ) /* 08 Oct 2002 */
6850 DC_linewidth( seq->dc , seq->button2_width ) ;
6851 XDrawLine( seq->dc->display , XtWindow(seq->wimage) ,
6852 seq->dc->myGC , bxsav[nsav-1],bysav[nsav-1] ,
6853 bxsav[0] ,bysav[0] ) ;
6854 if( seq->button2_width > 0 ) DC_linewidth( seq->dc , 0 ) ;
6855
6856 /* and add the 1st point to the list again */
6857
6858 bxsav[nsav] = bxsav[0] ; bysav[nsav] = bysav[0] ;
6859 if( nsav < NPTS_MAX ) nsav++ ;
6860 }
6861
6862 /* 1st time here: make space for output list */
6863
6864 if( xyout == NULL )
6865 xyout = (int *) malloc( sizeof(int) * 2*NPTS_MAX ) ;
6866
6867 /* now assemble output list of (x,y) pairs,
6868 in the original image grid --
6869 but only save points that are in the same image as the 1st point */
6870
6871 seq->wimage_width = -1 ;
6872 ISQ_mapxy( seq , bxsav[0] , bysav[0] , &xim,&yim,&zim ) ;
6873 nim = zim ; xyout[0] = xim ; xyout[1] = yim ; nout = 1 ;
6874 for( ii=1 ; ii < nsav ; ii++ ){
6875 ISQ_mapxy( seq , bxsav[ii] , bysav[ii] , &xim,&yim,&zim ) ;
6876 if( zim == nim && xim >= 0 && yim >= 0 ){
6877 xyout[2*nout] = xim ; xyout[2*nout+1] = yim ;
6878 nout++ ;
6879 }
6880 }
6881
6882 /* send to the almighty AFNI */
6883
6884 cbs.reason = isqCR_button2_points ;
6885 cbs.event = ev ;
6886 cbs.key = ii ; /* number of points */
6887 cbs.nim = nim ; /* z coord */
6888 cbs.userdata = (XtPointer) xyout ; /* x & y coords */
6889 #if 0
6890 seq->status->send_CB( seq , seq->getaux , &cbs ) ;
6891 #else
6892 SEND(seq,cbs) ;
6893 #endif
6894
6895 seq->button2_active = 0 ; /* disallow button2 stuff */
6896 }
6897 break ;
6898
6899 /*----- take motion events:
6900 this is minimal so as to keep up with mouse movements -----*/
6901
6902 case MotionNotify:{
6903 XMotionEvent *event = (XMotionEvent *) ev ;
6904 int bx,by ;
6905
6906 /* check for legality */
6907
6908 if( !seq->button2_active || (event->state & Button2Mask) == 0 ) EXRETURN ;
6909
6910 /* if point is redundant with last one, skip it */
6911
6912 bx = event->x ; by = event->y ;
6913 if( bx == bxsav[nsav-1] && by == bysav[nsav-1] ) EXRETURN ;
6914
6915 /* draw point or line to point */
6916
6917 if( seq->button2_drawmode == BUTTON2_POINTS ){
6918 XDrawPoint( seq->dc->display , XtWindow(seq->wimage) ,
6919 seq->dc->myGC , bx,by ) ;
6920 } else if( seq->button2_drawmode != BUTTON2_NODRAW ){
6921 if( seq->button2_width > 0 ) /* 08 Oct 2002 */
6922 DC_linewidth( seq->dc , seq->button2_width ) ;
6923 XDrawLine( seq->dc->display , XtWindow(seq->wimage) ,
6924 seq->dc->myGC , bxsav[nsav-1],bysav[nsav-1],bx,by ) ;
6925 if( seq->button2_width > 0 ) DC_linewidth( seq->dc , 0 ) ;
6926 }
6927
6928 /* save it */
6929
6930 bxsav[nsav] = bx ; bysav[nsav] = by ;
6931 if( nsav < NPTS_MAX ) nsav++ ;
6932 }
6933 break ;
6934
6935 }
6936 EXRETURN ;
6937 }
6938
6939 /*---------------------------------------------------------------------
6940 process Disp button press for an imseq:
6941 change the way the image is displayed (flip, rotate, ...),
6942 by popping up a dialog
6943 -----------------------------------------------------------------------*/
6944
ISQ_but_disp_CB(Widget w,XtPointer client_data,XtPointer call_data)6945 void ISQ_but_disp_CB( Widget w, XtPointer client_data, XtPointer call_data )
6946 {
6947 MCW_imseq *seq = (MCW_imseq *) client_data ;
6948 int ib ;
6949 Widget rctop , rcboxes , shtop ;
6950 Widget swtop=NULL ;
6951
6952 ENTRY("ISQ_but_disp_CB") ;
6953
6954 if( ! ISQ_REALZ(seq) || seq->dialog != NULL ) EXRETURN ;
6955
6956 for( ib=0 ; ib < NBUTTON_BOT-1 ; ib++ ) /* turn off buttons */
6957 if( ISQ_but_bot_dial[ib] == True ) /* that also want to */
6958 SENSITIZE( seq->wbut_bot[ib] , False ) ; /* use seq->dialog */
6959
6960 seq->dialog = XtVaCreatePopupShell(
6961 "font8" , xmDialogShellWidgetClass , seq->wtop ,
6962 XmNtitle , "Display Options" ,
6963 XmNdeleteResponse , XmDO_NOTHING ,
6964 XmNinitialResourcesPersistent , False ,
6965 NULL ) ;
6966
6967 SAVEUNDERIZE(seq->dialog) ; /* 27 Feb 2001 */
6968
6969 DC_yokify( seq->dialog , seq->dc ) ; /* 14 Sep 1998 */
6970
6971 seq->dialog_starter = NBUT_DISP ;
6972
6973 #if 1
6974 if( MCW_isitmwm(w) )
6975 XtVaSetValues( seq->dialog ,
6976 XmNmwmDecorations , MWM_DECOR_BORDER ,
6977 XmNmwmFunctions , MWM_FUNC_MOVE
6978 | MWM_FUNC_CLOSE ,
6979 NULL ) ;
6980 #endif
6981
6982 XmAddWMProtocolCallback( /* make "Close" window menu work */
6983 seq->dialog ,
6984 XmInternAtom( seq->dc->display , "WM_DELETE_WINDOW" , False ) ,
6985 ISQ_disp_act_CB , seq ) ;
6986
6987 for( ib=0 ; ib < NACT_DISP ; ib++ )
6988 ISQ_disp_act[ib].data = (XtPointer) seq ;
6989
6990 if( seq->dc->height < 1024 || /* 21 Jun 2005 */
6991 AFNI_yesenv("AFNI_DISP_SCROLLBARS") ){ /* 31 Jan 2002 */
6992
6993 shtop = swtop = XtVaCreateManagedWidget(
6994 "menu" , xmScrolledWindowWidgetClass , seq->dialog ,
6995 XmNscrollingPolicy , XmAUTOMATIC ,
6996 XmNvisualPolicy , XmVARIABLE ,
6997 XmNscrollBarDisplayPolicy , XmAS_NEEDED /* XmSTATIC */ ,
6998 XmNinitialResourcesPersistent , False ,
6999 NULL ) ;
7000 } else {
7001 shtop = seq->dialog ;
7002 }
7003
7004 rctop = XtVaCreateWidget(
7005 "menu" , xmRowColumnWidgetClass , shtop ,
7006 XmNpacking , XmPACK_TIGHT ,
7007 XmNnumColumns , 1 ,
7008
7009 XmNinitialResourcesPersistent , False ,
7010 NULL ) ;
7011
7012 rcboxes = XtVaCreateWidget(
7013 "menu" , xmRowColumnWidgetClass , rctop ,
7014 XmNpacking , XmPACK_TIGHT ,
7015 XmNnumColumns , 2 ,
7016
7017 XmNinitialResourcesPersistent , False ,
7018 NULL ) ;
7019
7020 for( ib=0 ; ib < NBOX_DISP ; ib++ ){
7021 int jh ;
7022 char **bbh = ISQ_bb_allhelp[ib] ;
7023 char **cch = ISQ_bb_allhint[ib] ;
7024
7025 /*** 30 Oct 1996: transformations just above the IMPROC buttons ***/
7026
7027 if( ib == NTOG_IMP ){
7028 int nav = 0 ;
7029
7030 /*---- FIRST, add some check boxes for special options ----*/
7031
7032 char *save_one_label[] = { "Save One" } ; /* 26 Jul 2001 */
7033 char *save_agif_label = "Save Anim GIF" ; /* 27 Jul 2001 */
7034 char *save_mpeg_label = "Save Anim MPG" ; /* 02 Aug 2001 */
7035 char *save_anim_label[2] ;
7036
7037 seq->save_one_bbox = new_MCW_bbox( rcboxes ,
7038 1 ,
7039 save_one_label ,
7040 MCW_BB_check ,
7041 MCW_BB_frame ,
7042 ISQ_disp_act_CB , (XtPointer) seq ) ;
7043 MCW_reghelp_children( seq->save_one_bbox->wrowcol ,
7044 " \n"
7045 "When pressed IN, then the 'Save' button\n"
7046 "will only save a snapshot of the current\n"
7047 "display. This is the ONLY way to save\n"
7048 "a montage.\n"
7049 "\n"
7050 "When pressed OUT, then the 'Save' button\n"
7051 "asks for the first and last image indexes\n"
7052 "to save, and then saves each individual\n"
7053 "image (no montage) to a file.\n"
7054 ) ;
7055 MCW_reghint_children( seq->save_one_bbox->wrowcol ,
7056 "Save just 1 (including montage)" ) ;
7057
7058 if( ppmto_agif_filter != NULL || ppmto_mpeg_filter != NULL ){
7059 int nb = 0 ;
7060 if( ppmto_agif_filter != NULL ) save_anim_label[nb++]=save_agif_label;
7061 if( ppmto_mpeg_filter != NULL ) save_anim_label[nb++]=save_mpeg_label;
7062 seq->save_agif_bbox = new_MCW_bbox( rcboxes ,
7063 nb ,
7064 save_anim_label ,
7065 MCW_BB_radio_zero ,
7066 MCW_BB_frame ,
7067 ISQ_disp_act_CB, (XtPointer)seq );
7068 MCW_reghelp_children( seq->save_agif_bbox->wrowcol ,
7069 " \n"
7070 "Controls if image sequence is saved to\n"
7071 "an animation file, rather than a bunch\n"
7072 "of separate image files.\n"
7073 "* This takes precedence over 'Save One',\n"
7074 " if it is also turned on.\n"
7075 "* GIF animations require gifsicle.\n"
7076 "* MPEG-1 animations require ffmpeg.\n"
7077 ) ;
7078 MCW_reghint_children( seq->save_agif_bbox->wrowcol ,
7079 "Save image sequence to animation" ) ;
7080 } else {
7081 seq->save_agif_bbox = NULL ;
7082 }
7083
7084 /*---- OK, do the transforms NOW ----*/
7085
7086 if( seq->status->slice_proj != NULL &&
7087 seq->status->slice_proj->num > 0 ){ /* 31 Jan 2002 */
7088
7089 (void) XtVaCreateManagedWidget(
7090 "menu" , xmSeparatorWidgetClass , rcboxes ,
7091 XmNseparatorType , XmSINGLE_LINE ,
7092 XmNinitialResourcesPersistent , False ,
7093 NULL ) ;
7094
7095 seq->slice_proj_av =
7096 new_MCW_optmenu( rcboxes , "Project" ,
7097 0 , seq->status->slice_proj->num ,
7098 seq->slice_proj_index , 0 ,
7099 ISQ_slice_proj_CB , (XtPointer) seq ,
7100 ISQ_transform_label ,
7101 (XtPointer) seq->status->slice_proj ) ;
7102
7103 if( seq->status->slice_proj->num >= COLSIZE )
7104 AVOPT_columnize( seq->slice_proj_av ,
7105 (seq->status->slice_proj->num/COLSIZE)+1 ) ;
7106
7107 MCW_reghelp_children( seq->slice_proj_av->wrowcol ,
7108 "Choose a projection function\n"
7109 "to apply to plus-or-minus\n"
7110 "'Slab' images from each pixel.\n"
7111 "Built-in projections:\n"
7112 " Minimum = smallest value in slab\n"
7113 " Maximum = largest value in slab\n"
7114 " Mean = average value in slab\n"
7115 " Median = median value in slab\n"
7116 " Extreme = value farthest from median" ) ;
7117
7118 MCW_reghint_children( seq->slice_proj_av->wrowcol ,
7119 "Image projection function" ) ;
7120
7121 seq->slice_proj_range_av =
7122 new_MCW_optmenu( rcboxes , "Slab +-" ,
7123 0 , 19 , seq->slice_proj_range , 0 ,
7124 ISQ_slice_proj_CB , (XtPointer) seq ,
7125 NULL , NULL ) ;
7126 MCW_reghelp_children( seq->slice_proj_range_av->wrowcol ,
7127 "Choose thickness of Project slice\n"
7128 "package (in each direction from\n"
7129 "central slice). For example:\n"
7130 " 2 ==> slab is 5 images thick\n"
7131 " (2 before, 2 after, central)" ) ;
7132 MCW_reghint_children( seq->slice_proj_range_av->wrowcol ,
7133 "Slab half-thickness" ) ;
7134 nav++ ;
7135 }
7136
7137 /* 0D transforms */
7138
7139 if( seq->status->transforms0D != NULL &&
7140 seq->status->transforms0D->num > 0 ){
7141
7142 (void) XtVaCreateManagedWidget(
7143 "menu" , xmSeparatorWidgetClass , rcboxes ,
7144 XmNseparatorType , XmSINGLE_LINE ,
7145 XmNinitialResourcesPersistent , False ,
7146 NULL ) ;
7147
7148 seq->transform0D_av =
7149 new_MCW_optmenu( rcboxes , "Tran 0D" ,
7150 0 , seq->status->transforms0D->num ,
7151 seq->transform0D_index , 0 ,
7152 ISQ_transform_CB , (XtPointer) seq ,
7153 ISQ_transform_label ,
7154 (XtPointer) seq->status->transforms0D ) ;
7155
7156 if( seq->status->transforms0D->num >= COLSIZE )
7157 AVOPT_columnize( seq->transform0D_av ,
7158 (seq->status->transforms0D->num/COLSIZE)+1 ) ;
7159
7160 MCW_reghelp_children( seq->transform0D_av->wrowcol ,
7161 "Choose a function to apply to\n"
7162 "each point in the image." ) ;
7163 MCW_reghint_children( seq->transform0D_av->wrowcol ,
7164 "Pointwise transformations" ) ;
7165 nav++ ;
7166 }
7167
7168 /* 2D transforms */
7169
7170 if( seq->status->transforms2D != NULL &&
7171 seq->status->transforms2D->num > 0 ){
7172
7173 (void) XtVaCreateManagedWidget(
7174 "menu" , xmSeparatorWidgetClass , rcboxes ,
7175 XmNseparatorType , XmSINGLE_LINE ,
7176 XmNinitialResourcesPersistent , False ,
7177 NULL ) ;
7178
7179 seq->transform2D_av =
7180 new_MCW_optmenu( rcboxes , "Tran 2D" ,
7181 0 , seq->status->transforms2D->num ,
7182 seq->transform2D_index , 0 ,
7183 ISQ_transform_CB , (XtPointer) seq ,
7184 ISQ_transform_label ,
7185 (XtPointer) seq->status->transforms2D ) ;
7186
7187 if( seq->status->transforms2D->num >= COLSIZE )
7188 AVOPT_columnize( seq->transform2D_av ,
7189 (seq->status->transforms2D->num/COLSIZE)+1 ) ;
7190
7191 MCW_reghelp_children( seq->transform2D_av->wrowcol ,
7192 "Choose a function to apply to\n"
7193 "the underlay image as a whole." ) ;
7194 MCW_reghint_children( seq->transform2D_av->wrowcol ,
7195 "Global transformations" ) ;
7196 nav++ ;
7197 }
7198
7199 /* 30 Dec 1998: rowgraphs */
7200
7201 if( nav > 0 && seq->status->send_CB != NULL ){
7202 (void) XtVaCreateManagedWidget(
7203 "menu" , xmSeparatorWidgetClass , rcboxes ,
7204 XmNseparatorType , XmSINGLE_LINE ,
7205 XmNinitialResourcesPersistent , False ,
7206 NULL ) ;
7207
7208 seq->rowgraph_av =
7209 new_MCW_optmenu( rcboxes , "RowGraphs" ,
7210 0 , ROWGRAPH_MAX , seq->rowgraph_num , 0 ,
7211 ISQ_rowgraph_CB , (XtPointer) seq ,
7212 ISQ_rowgraph_label , NULL ) ;
7213 AVOPT_columnize( seq->rowgraph_av , 2 ) ;
7214
7215 MCW_reghelp_children( seq->rowgraph_av->wrowcol ,
7216 "Rowgraphs are plots of the underlay\n"
7217 "(grayscale) image intensity as\n"
7218 "x vs. y graphs. Each graph is from\n"
7219 "one displayed horizontal row of the\n"
7220 "image. The bottom rowgraph is from\n"
7221 "the image row under the crosshairs.\n"
7222 "Upper rowgraphs are from higher image\n"
7223 "rows. Note that image transformations\n"
7224 "functions and image rotations/flips\n"
7225 "will affect the rowgraphs as well as\n"
7226 "the image display.\n\n"
7227 "N.B.: The color 'UK Flag' marker indicates\n"
7228 " the crosshair focus point. It can be\n"
7229 " turned off via the 'No Overlay' button."
7230 ) ;
7231 MCW_reghint_children( seq->rowgraph_av->wrowcol ,
7232 "Number of image rows to graph" ) ;
7233 nav++ ;
7234 }
7235
7236 /* 21 Jan 1999: surfgraph */
7237
7238 if( nav > 0 && seq->status->send_CB != NULL ){
7239 (void) XtVaCreateManagedWidget(
7240 "menu" , xmSeparatorWidgetClass , rcboxes ,
7241 XmNseparatorType , XmSINGLE_LINE ,
7242 XmNinitialResourcesPersistent , False ,
7243 NULL ) ;
7244
7245 seq->surfgraph_av =
7246 new_MCW_optmenu( rcboxes , "SurfGraph" ,
7247 0 , SURFGRAPH_MAX , seq->surfgraph_num , 0 ,
7248 ISQ_surfgraph_CB , (XtPointer) seq ,
7249 ISQ_surfgraph_label , NULL ) ;
7250
7251 MCW_reghelp_children( seq->surfgraph_av->wrowcol ,
7252 "The SurfGraph is a wiremesh plot of the\n"
7253 "underlay (grayscale) image intensity vs.\n"
7254 "x and y. Use the arrows in the SurfGraph\n"
7255 "window to rotate the viewpoint; use the\n"
7256 "middle button between the arrows to reset\n"
7257 "the viewpoint to the default orientation.\n"
7258 "\n"
7259 "N.B.: The plotting routine may produce some\n"
7260 " erroneous vertical lines on occasion.\n"
7261 " The color 'UK Flag' marker indicates\n"
7262 " crosshair focus point. It is drawn\n"
7263 " on top of the surface at the end, and\n"
7264 " so is always visible, even if it should\n"
7265 " be hidden behind the surface; that is,\n"
7266 " it shines through, no matter what.\n"
7267 " The color marker can be turned off with\n"
7268 " the 'No Overlay' button."
7269 ) ;
7270 MCW_reghint_children( seq->surfgraph_av->wrowcol ,
7271 "Plot wiremesh surface?" ) ;
7272 nav++ ;
7273 }
7274
7275 /* final separator */
7276
7277 if( nav ) (void) XtVaCreateManagedWidget(
7278 "menu" , xmSeparatorWidgetClass , rcboxes ,
7279 XmNseparatorType , XmSINGLE_LINE ,
7280 XmNinitialResourcesPersistent , False ,
7281 NULL ) ;
7282 }
7283
7284 /*** back to the button box stuff ***/
7285
7286 seq->bbox[ib] = new_MCW_bbox( rcboxes ,
7287 ISQ_dispbb[ib].nbut ,
7288 ISQ_dispbb[ib].lbut ,
7289 ISQ_dispbb[ib].type ,
7290 ISQ_dispbb[ib].frame ,
7291 ISQ_disp_act_CB , (XtPointer) seq ) ;
7292
7293 seq->bbox[ib]->parent = (XtPointer) seq ;
7294
7295 seq->num_bbox ++ ;
7296
7297 for( jh=0 ; jh < seq->bbox[ib]->nbut ; jh++ ){
7298 MCW_register_help( seq->bbox[ib]->wbut[jh] , bbh[jh] ) ;
7299 MCW_register_hint( seq->bbox[ib]->wbut[jh] , cch[jh] ) ;
7300 }
7301
7302 } /* end of loop creating widgets in Disp */
7303
7304 #ifdef NO_GROUP_SCALE
7305 XtUnmanageChild( seq->bbox[NTOG_SCL]->wtop ) ; /* turn this box off! */
7306 #endif
7307
7308 if( seq->last_image_type != MRI_complex )
7309 XtUnmanageChild( seq->bbox[NTOG_CX]->wtop ) ;
7310
7311 XtManageChild( rcboxes ) ;
7312
7313 (void) MCW_action_area( rctop , ISQ_disp_act , NACT_DISP ) ;
7314
7315 XtManageChild( rctop ) ;
7316
7317 if( swtop != NULL ){ /* 31 Jan 2002 */
7318 int wx,hy , cmax ;
7319 MCW_widget_geom( rctop , &wx,&hy,NULL,NULL ) ;
7320 cmax = seq->dc->height-128 ; if( hy > cmax ) hy = cmax ;
7321 XtVaSetValues( seq->dialog , XmNwidth,wx+33,XmNheight,hy+19 , NULL ) ;
7322 }
7323
7324 ISQ_place_dialog( seq ) ; /* 05 Jan 1999 */
7325
7326 XtPopup( seq->dialog , XtGrabNone ) ; NI_sleep(1);
7327
7328 if( seq->top_clip <= 0.0f ) ALLOW_CLIPPING( seq , 0 ) ;
7329
7330 ISQ_disp_options( seq , False ) ; /* set toggles from option list */
7331 seq->save_opt = seq->opt ; /* for use with Reset button */
7332
7333 NORMAL_cursorize( seq->dialog ) ;
7334
7335 ISQ_but_done_reset( seq ) ;
7336 EXRETURN ;
7337 }
7338
7339 /*-----------------------------------------------------------------------
7340 05 Jan 1999: place the dialog near the image window
7341 -------------------------------------------------------------------------*/
7342
ISQ_place_dialog(MCW_imseq * seq)7343 void ISQ_place_dialog( MCW_imseq *seq )
7344 {
7345 if( ISQ_REALZ(seq) && !seq->dont_place_dialog )
7346 ISQ_place_widget( seq->wtop , seq->dialog ) ;
7347
7348 return ;
7349 }
7350
7351 /*-----------------------------------------------------------------------*/
7352
ISQ_place_widget(Widget wmain,Widget w)7353 void ISQ_place_widget( Widget wmain , Widget w ) /* 27 Oct 2003 */
7354 {
7355 int dw,dh,dx,dy , xp,yp , wx,hy,xx,yy , sh,sw ;
7356
7357 ENTRY("ISQ_place_widget") ;
7358
7359 if( wmain == (Widget)NULL || w == (Widget)NULL ) EXRETURN ;
7360 if( !XtIsRealized(wmain) || !XtIsRealized(w) ) EXRETURN ;
7361
7362 MCW_widget_geom( wmain , &wx,&hy,&xx,&yy ) ; /* geometry of shell */
7363 MCW_widget_geom( w , &dw,&dh,&dx,&dy ) ; /* of dialog */
7364
7365 sh = HeightOfScreen(XtScreen(wmain)) ;
7366 sw = WidthOfScreen (XtScreen(wmain)) ;
7367
7368 xp = xx+wx+8 ;
7369 if( xp+dw > sw ) xp = xx-dw-8 ;
7370 if( xp < 0 ) xp = 0 ;
7371
7372 yp = yy-4 ;
7373 if( yp+dh > sh ) yp = sh - dh ;
7374 if( yp < 0 ) yp = 0 ;
7375
7376 RWC_xineramize( XtDisplay(wmain) , xp,yp,dw,dh , &xp,&yp ); /* 27 Sep 2000 */
7377
7378 XtVaSetValues( w , XmNx , xp , XmNy , yp , NULL ) ;
7379 EXRETURN ;
7380 }
7381
7382 /*-----------------------------------------------------------------------
7383 Callback for button and toggle actions in the display dialog
7384 -------------------------------------------------------------------------*/
7385
ISQ_disp_act_CB(Widget w,XtPointer client_data,XtPointer call_data)7386 void ISQ_disp_act_CB( Widget w, XtPointer client_data, XtPointer call_data )
7387 {
7388 MCW_imseq *seq = (MCW_imseq *)client_data ;
7389 XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *)call_data ;
7390
7391 int ib , close_window ;
7392 char *wname ;
7393 RwcBoolean new_opt = False ;
7394
7395 #ifdef FLASH_TOGGLE
7396 RwcBoolean flasher ;
7397 #endif
7398
7399 ENTRY("ISQ_disp_act_CB") ;
7400
7401 if( !ISQ_REALZ(seq) || seq->dialog==NULL || seq->dialog_starter!=NBUT_DISP ) EXRETURN ;
7402
7403 wname = XtName(w) ;
7404
7405 for( ib=0 ; ib < NACT_DISP ; ib++ ) /* button index, if any */
7406 if( strcmp(wname,ISQ_disp_act[ib].label) == 0 ) break ;
7407
7408 close_window = (ib == DISP_OK) /* button to exit */
7409 ||
7410 ( cbs->reason != XmCR_ACTIVATE && /* exit if */
7411 cbs->reason != XmCR_DISARM ); /* not button */
7412
7413 #ifdef FLASH_TOGGLE
7414 flasher = (cbs->reason == XmCR_DISARM) && (!close_window) ;
7415 if( flasher ) MCW_invert_widget( w ) ;
7416 #endif
7417
7418 if( ib == DISP_UNDO ){ /* restore options from entry */
7419 seq->opt = seq->save_opt ; /* and then set toggles */
7420 ISQ_disp_options( seq , False ) ;
7421 new_opt = True ;
7422 AV_SENSITIZE(seq->ov_opacity_av,!seq->opt.no_overlay) ; /* 09 Mar 2001 */
7423
7424 } else { /* any other activation: */
7425 new_opt = ISQ_disp_options( seq , True ); /* --> set options */
7426 }
7427
7428 if( close_window ){ /* close the window */
7429 XtDestroyWidget( seq->dialog ) ; NI_sleep(1) ;
7430 seq->dialog = NULL ;
7431 for( ib=0 ; ib < NBUTTON_BOT-1 ; ib++ ) /* turn buttons back on */
7432 if( ISQ_but_bot_dial[ib] == True ) /* that also want to */
7433 SENSITIZE( seq->wbut_bot[ib] , True ) ; /* use seq->dialog */
7434
7435 for( ib=0 ; ib < seq->num_bbox ; ib++ ) myXtFree( seq->bbox[ib] ) ;
7436 seq->num_bbox = 0 ;
7437 seq->dialog_starter = -1 ;
7438
7439 FREE_AV( seq->transform0D_av ) ;
7440 FREE_AV( seq->transform2D_av ) ;
7441 FREE_AV( seq->rowgraph_av ) ;
7442 FREE_AV( seq->surfgraph_av ) ; /* 21 Jan 1999 */
7443 }
7444
7445 if( new_opt ){
7446 ISQ_redisplay( seq , -1 , isqDR_reimage ) ; /* redo current image */
7447
7448 /* 01 Dec 1999: perhaps redraw winfo label */
7449
7450 if( ISQ_USE_SIDES(seq) ){
7451 seq->im_label[0] = '\0' ; /* will force redraw */
7452 ISQ_draw_winfo( seq ) ;
7453 }
7454 }
7455
7456 #ifdef FLASH_TOGGLE
7457 if( flasher ) MCW_invert_widget( w ) ; /* flash togglebutton */
7458 #endif
7459
7460 ISQ_but_done_reset( seq ) ;
7461 EXRETURN ;
7462 }
7463
7464 /*----------------------------------------------------------------------
7465 map the toggle-button states TO the options if set == True,
7466 FROM the options if set == False
7467
7468 in the former case, return True if any options changed, False otherwise
7469 in the latter case, return False always (options ARE unchanged)
7470 ------------------------------------------------------------------------*/
7471
ISQ_disp_options(MCW_imseq * seq,RwcBoolean set)7472 RwcBoolean ISQ_disp_options( MCW_imseq *seq , RwcBoolean set )
7473 {
7474 int bval[NBOX_DISP] ;
7475 int ib ;
7476
7477 ENTRY("ISQ_disp_options") ;
7478
7479 if( !ISQ_VALID(seq) || seq->dialog==NULL || seq->dialog_starter!=NBUT_DISP )
7480 RETURN(False) ;
7481
7482 if( set ){ /* set structure from widgets */
7483 ISQ_options inopt = seq->opt ;
7484 RwcBoolean changed ;
7485
7486 for( ib=0 ; ib < NBOX_DISP ; ib++ )
7487 bval[ib] = MCW_val_bbox( seq->bbox[ib] ) ;
7488
7489 seq->opt.mirror = ( bval[NTOG_MIR] & 1 ) != 0 ;
7490
7491 seq->opt.rot = bval[NTOG_ROT] ;
7492
7493 seq->opt.no_overlay = ( bval[NTOG_COL] & 1 ) != 0 ;
7494
7495 AV_SENSITIZE(seq->ov_opacity_av,!seq->opt.no_overlay) ; /* 09 Mar 2001 */
7496
7497 seq->opt.scale_group = bval[NTOG_SCL] ;
7498
7499 seq->opt.scale_range = bval[NTOG_RNG] ;
7500
7501 seq->opt.free_aspect = ( bval[NTOG_ASP] & ISQ_ASPECT ) != 0 ;
7502 seq->opt.save_nsize = ( bval[NTOG_SAV] & ISQ_SAV_NSIZE ) != 0 ;
7503 seq->opt.save_pnm = ( bval[NTOG_SAV] & ISQ_SAV_PNM ) != 0 ;
7504
7505 seq->opt.save_one = MCW_val_bbox(seq->save_one_bbox) != 0 ; /* 26 Jul 2001 */
7506
7507 seq->opt.save_agif = seq->opt.save_mpeg = 0 ;
7508 if( seq->save_agif_bbox != NULL ){
7509 int bv = MCW_val_bbox(seq->save_agif_bbox) ;
7510 /* 07 Apr 2005: oops */
7511 switch( bv ){ /* need to handle case when agif isn't allowed */
7512 case 1:
7513 if( ppmto_agif_filter != NULL ) seq->opt.save_agif = 1 ;
7514 else if( ppmto_mpeg_filter != NULL ) seq->opt.save_mpeg = 1 ;
7515 break ;
7516
7517 case 2:
7518 if( ppmto_mpeg_filter != NULL ) seq->opt.save_mpeg = 1 ;
7519 break ;
7520 }
7521 }
7522
7523 seq->opt.save_filter = -1 ;
7524 if( bval[NTOG_SAV] > ISQ_SAV_PNM && ppmto_num > 0 ){ /* 27 Jun 2001 */
7525 int ii ;
7526 for( ii=0 ; ii < ppmto_num ; ii++ ){
7527 if( bval[NTOG_SAV] == ppmto_bval[ii] ){
7528 seq->opt.save_filter = ii ; break ;
7529 }
7530 }
7531 }
7532
7533 SET_SAVE_LABEL(seq) ;
7534
7535 seq->opt.improc_code = bval[NTOG_IMP] ;
7536
7537 seq->opt.cx_code = bval[NTOG_CX] ;
7538
7539 /*-- sanity checks --*/
7540
7541 if( seq->opt.rot != ISQ_ROT_0 &&
7542 seq->opt.rot != ISQ_ROT_90 &&
7543 seq->opt.rot != ISQ_ROT_180 &&
7544 seq->opt.rot != ISQ_ROT_270 ) seq->opt.rot = inopt.rot ;
7545
7546 if( seq->opt.scale_group != ISQ_SCL_AUTO &&
7547 seq->opt.scale_group != ISQ_SCL_GRP )
7548 seq->opt.scale_group = inopt.scale_group ;
7549
7550 if( seq->opt.scale_range != ISQ_RNG_CLIPPED ) seq->redo_clip = 0 ;
7551 DPRI("set scale_range =",seq->opt.scale_range) ;
7552
7553 if( seq->opt.scale_range != ISQ_RNG_MINTOMAX &&
7554 seq->opt.scale_range != ISQ_RNG_02TO98 &&
7555 seq->opt.scale_range != ISQ_RNG_CLIPPED )
7556 seq->opt.scale_range = inopt.scale_range ;
7557
7558 if( seq->opt.scale_range == ISQ_RNG_CLIPPED ){ /* 17 Sep 2007 */
7559 if( seq->top_clip <= 0.0f ){
7560 ALLOW_CLIPPING( seq , 0 ) ;
7561 } else {
7562 seq->redo_clip = 1 ;
7563 }
7564 }
7565
7566 changed = ! ISQ_OPT_EQUAL( seq->opt , inopt ) ;
7567
7568 RETURN(changed) ;
7569
7570 } else { /* set widgets from structure */
7571
7572 bval[NTOG_MIR] = (seq->opt.mirror) ? 1 : 0 ;
7573 bval[NTOG_ROT] = seq->opt.rot ;
7574
7575 bval[NTOG_COL] = (seq->opt.no_overlay << 0 ) ;
7576
7577 bval[NTOG_SCL] = seq->opt.scale_group ;
7578 bval[NTOG_RNG] = seq->opt.scale_range ;
7579
7580 if( seq->opt.scale_range == ISQ_RNG_CLIPPED &&
7581 seq->top_clip <= 0.0f ){ /* 17 Sep 2007 */
7582
7583 ALLOW_CLIPPING( seq , 0 ) ;
7584 bval[NTOG_RNG] = seq->opt.scale_range ;
7585 }
7586
7587 bval[NTOG_ASP] = (seq->opt.free_aspect) ? ISQ_ASPECT : 0 ;
7588
7589 bval[NTOG_SAV] = ( (seq->opt.save_nsize)? ISQ_SAV_NSIZE : 0 )
7590 +( (seq->opt.save_pnm) ? ISQ_SAV_PNM : 0 ) ;
7591
7592 if( seq->opt.save_filter >= 0 && ppmto_num > 0 ) /* 27 Jun 2001 */
7593 bval[NTOG_SAV] = ppmto_bval[seq->opt.save_filter] ;
7594
7595 bval[NTOG_IMP] = seq->opt.improc_code ;
7596
7597 bval[NTOG_CX] = seq->opt.cx_code ;
7598
7599 for( ib=0 ; ib < NBOX_DISP ; ib++ )
7600 MCW_set_bbox( seq->bbox[ib] , bval[ib] ) ;
7601
7602 MCW_set_bbox( seq->save_one_bbox ,
7603 (seq->opt.save_one) ? 1 : 0 ) ; /* 26 Jul 2001 */
7604
7605 if( seq->save_agif_bbox != NULL ){ /* 07 Apr 2005: oops */
7606 int bv=0 ; /* need to handle case when agif isn't allowed */
7607 if( ppmto_agif_filter != NULL )
7608 bv = (seq->opt.save_agif) + (seq->opt.save_mpeg)*2 ;
7609 else if( ppmto_mpeg_filter != NULL )
7610 bv = (seq->opt.save_mpeg) ;
7611 MCW_set_bbox( seq->save_agif_bbox , bv ) ;
7612 }
7613
7614 RETURN(False) ;
7615 }
7616 }
7617
7618 /*----------------------------------------------------------------------*/
7619 /** Group scaling is disabled, and should be removed entirely someday. **/
7620 #ifndef NO_GROUP_SCALE
7621 /*----------------------------------------------------------------------
7622 routines to collect statistics for scaling these images;
7623 ISQ_statify_all -> do all statistics (individual then global)
7624 ISQ_statistics_WP -> Xt work process to do statistics on one image
7625 *** The functions below should not be removed, though ***
7626 ISQ_statify_one -> actually do statistics on one image
7627 ISQ_perpoints -> get the percentage points for 2%-to-98% scaling
7628 ------------------------------------------------------------------------*/
7629
ISQ_statify_all(MCW_imseq * seq,RwcBoolean stop_on_minmax)7630 void ISQ_statify_all( MCW_imseq *seq , RwcBoolean stop_on_minmax )
7631 {
7632 RwcBoolean done ;
7633 Widget wmsg ;
7634
7635 ENTRY("ISQ_statify_all") ;
7636
7637 if( ! ISQ_VALID(seq) ) EXRETURN ;
7638
7639 /* this routine just drives the work process until it is done */
7640
7641 if( !seq->glstat->mm_done ){
7642 wmsg = MCW_popup_message( seq->wtop ,
7643 "Please Wait.\nComputing Statistics." ,
7644 MCW_CALLER_KILL ) ;
7645 } else {
7646 wmsg = MCW_popup_message( seq->wtop ,
7647 "Please Wait.\nComputing Histogram." ,
7648 MCW_CALLER_KILL ) ;
7649 }
7650
7651 XBell( seq->dc->display , 100 ) ;
7652
7653 WATCH_cursorize( seq->wtop ) ;
7654 WATCH_cursorize( wmsg ) ;
7655 if( seq->dialog != NULL )
7656 WATCH_cursorize( seq->dialog ) ;
7657
7658 XFlush( seq->dc->display ) ;
7659
7660 if( seq->glstat->worker != 0 ){ /* remove work process, if started */
7661 XtRemoveWorkProc( seq->glstat->worker ) ;
7662 seq->glstat->worker = 0 ;
7663 }
7664
7665 /**************************************************************/
7666 do{
7667
7668 done = ISQ_statistics_WP( (XtPointer) seq ) ;
7669 done = done || ( stop_on_minmax && seq->glstat->mm_done ) ;
7670
7671 } while ( ! done ) ;
7672 /**************************************************************/
7673
7674 XtDestroyWidget( wmsg ) ; NI_sleep(1) ;
7675
7676 NORMAL_cursorize( seq->wtop ) ;
7677 if( seq->dialog != NULL )
7678 NORMAL_cursorize( seq->dialog ) ;
7679
7680 EXRETURN;
7681 }
7682
7683 /*-----------------------------------------------------------------------*/
7684
ISQ_statistics_WP(XtPointer client_data)7685 RwcBoolean ISQ_statistics_WP( XtPointer client_data )
7686 {
7687 MCW_imseq *seq = (MCW_imseq *) client_data ;
7688 ISQ_glob_statistics *gl ;
7689
7690 MRI_IMAGE *im=NULL ;
7691 register int ntot , nser , nn ;
7692
7693 ENTRY("ISQ_statistics_WP") ;
7694
7695 if( ! ISQ_VALID(seq) ) RETURN( True );
7696
7697 gl = seq->glstat ;
7698 ntot = seq->status->num_total ; /* image counts */
7699 nser = seq->status->num_series ;
7700
7701 /*-- first, check if all individual statistics are done --*/
7702
7703 if( ! gl->mm_done ){ /* not marked as done: check them */
7704
7705 for( nn=0 ; nn < ntot ; nn++ )
7706 if( ! seq->imstat[nn].one_done ) break ;
7707
7708 if( nn >= ntot ){ /* all were done, so finish them off */
7709
7710 gl->min = seq->imstat[0].min ;
7711 gl->max = seq->imstat[0].max ;
7712 for( nn=1 ; nn < nser ; nn++ ){ /* global: images in the series */
7713 gl->min = MIN( gl->min , seq->imstat[nn].min ) ;
7714 gl->max = MAX( gl->max , seq->imstat[nn].max ) ;
7715 }
7716 ISQ_SCLEV(gl->min,gl->max,seq->dc->ncol_im,gl->scl_mm,gl->lev_mm);
7717 gl->mm_done = True ;
7718
7719 RETURN( False ); /* continue next time on global histogramming */
7720 }
7721
7722 /* if here, image nn has yet to be done for local statistics */
7723
7724 #if 0
7725 im = (MRI_IMAGE *) seq->getim( nn , isqCR_getimage , seq->getaux ) ;
7726 #else
7727 AFNI_CALL_VALU_3ARG( seq->getim , MRI_IMAGE *,im ,
7728 int,nn , int,isqCR_getimage , XtPointer,seq->getaux ) ;
7729 #endif
7730 if( im != NULL ){
7731 ISQ_statify_one( seq , nn , im ) ; KILL_1MRI(im) ;
7732 }
7733 RETURN( False ); /* continue next time on next un-statted image */
7734 }
7735
7736 /* all individual statistics are done --> global histogramming */
7737 /* (note only images in the "series" are used for this purpose) */
7738
7739 if( ! gl->per_done ){ /* global statistics not marked as done */
7740
7741 for( nn=0 ; nn < nser ; nn++ )
7742 if( ! seq->imstat[nn].glob_done ) break ;
7743
7744 if( nn >= nser ){ /* all were done, so finish them off */
7745
7746 ISQ_perpoints( gl->min,gl->max,gl->hist ,
7747 &(gl->per02) , &(gl->per98) ) ;
7748
7749 ISQ_SCLEV( gl->per02 , gl->per98 ,
7750 seq->dc->ncol_im , gl->scl_per , gl->lev_per ) ;
7751
7752 gl->per_done = True ;
7753
7754 RETURN( True ); /* don't need to do any more statistics! */
7755 }
7756
7757 /* if here, image nn has yet to be done for global histogram */
7758
7759 #if 0
7760 im = (MRI_IMAGE *) seq->getim( nn , isqCR_getimage , seq->getaux ) ;
7761 #else
7762 AFNI_CALL_VALU_3ARG( seq->getim , MRI_IMAGE *,im ,
7763 int,nn , int,isqCR_getimage , XtPointer,seq->getaux ) ;
7764 #endif
7765 if( im != NULL ){
7766 ISQ_statify_one( seq , nn , im ) ; KILL_1MRI(im) ;
7767 }
7768 RETURN( False ); /* continue next time on next un-statted image */
7769 }
7770
7771 /* shouldn't get here, but if do, print a message and stop work process */
7772
7773 fprintf(stderr,"\a\n*** imseq work process error!\n") ;
7774 RETURN( True );
7775 }
7776 #endif /*---------- NO_GROUP_SCALE not defined --------------------------*/
7777
7778 /*-----------------------------------------------------------------------
7779 collect statistics on an image and put into location n in table
7780 -------------------------------------------------------------------------*/
7781
ISQ_statify_one(MCW_imseq * seq,int n,MRI_IMAGE * im)7782 void ISQ_statify_one( MCW_imseq *seq , int n , MRI_IMAGE *im )
7783 {
7784 ISQ_indiv_statistics *st ;
7785 ISQ_glob_statistics *gl ;
7786 static int hist[NHISTOG] ; /* static to avoid create/destroy overhead */
7787
7788 ENTRY("ISQ_statify_one") ;
7789
7790 /* exit if bad data */
7791
7792 if( ! ISQ_VALID(seq) || n < 0 || n >= seq->status->num_total ) EXRETURN ;
7793
7794 st = &( seq->imstat[n] ) ;
7795 gl = seq->glstat ;
7796
7797 if( im->kind == MRI_rgb ) EXRETURN ; /* 11 Feb 1999 */
7798
7799 if( ! st->one_done ){ /* must do individual statistics */
7800
7801 st->min = mri_min( im ) ; floatfix(st->min) ;
7802 st->max = mri_max( im ) ; floatfix(st->max) ;
7803
7804 ISQ_SCLEV( st->min , st->max ,
7805 seq->dc->ncol_im , st->scl_mm , st->lev_mm ) ;
7806
7807 mri_histogram( im , st->min , st->max , True , NHISTOG,hist ) ;
7808
7809 ISQ_perpoints( st->min,st->max,hist , &(st->per02) , &(st->per98) ) ;
7810
7811 ISQ_SCLEV( st->per02 , st->per98 ,
7812 seq->dc->ncol_im , st->scl_per , st->lev_per ) ;
7813
7814 /* 12 Jan 2004: compute entropy in bits/byte */
7815
7816 switch( im->kind ){
7817 default: st->entropy = mri_entropy8(im) ; break;
7818 case MRI_short:
7819 case MRI_float: st->entropy = 0.5l * mri_entropy16(im); break;
7820 }
7821
7822 st->one_done = True ;
7823
7824 } else if( n < seq->status->num_series &&
7825 ! st->glob_done ){ /* do global */
7826
7827 mri_histogram( im , gl->min , gl->max , False , NHISTOG , gl->hist ) ;
7828 st->glob_done = True ;
7829 }
7830
7831 EXRETURN ;
7832 }
7833
7834 /*-----------------------------------------------------------------------*/
7835 /* Percentage points for the 2%-98% scaling. */
7836 /*-----------------------------------------------------------------------*/
7837
ISQ_perpoints(float bot,float top,int hist[],float * per02,float * per98)7838 void ISQ_perpoints( float bot , float top ,
7839 int hist[] , float *per02 , float *per98 )
7840 {
7841 register int ih , nsum , ns02 , ns98 ;
7842 float prev , cur , frac , dbin ;
7843 static int hcum[NHISTOG] ; /* static to avoid create-destroy overhead */
7844
7845 ENTRY("ISQ_perpoints") ;
7846
7847 nsum = 0 ;
7848 for( ih=0 ; ih < NHISTOG ; ih++ ) hcum[ih] = nsum += hist[ih] ;
7849
7850 ns02 = 0.02 * nsum ; /* here is where 2% and 98% are fixed */
7851 ns98 = 0.98 * nsum ;
7852 dbin = (top-bot) / NHISTOG ;
7853
7854 /*-------*/
7855
7856 for( ih=0 ; ih < NHISTOG ; ih++ ) if( hcum[ih] >= ns02 ) break ;
7857
7858 if( ih == NHISTOG ) ih-- ;
7859
7860 prev = (ih == 0) ? (0.0) : hcum[ih-1] ;
7861 cur = hcum[ih] ; if( cur <= prev ) cur = 1.01 * prev + 1.0 ;
7862 frac = ih + (ns02-prev)/(cur-prev) ;
7863 *per02 = bot + dbin * frac ;
7864
7865 if( *per02 < bot ) *per02 = bot ;
7866
7867 /*-------*/
7868
7869 for( ; ih < NHISTOG ; ih++ ) if( hcum[ih] >= ns98 ) break ;
7870
7871 if( ih == NHISTOG ) ih-- ;
7872
7873 prev = (ih == 0) ? (0.0) : hcum[ih-1] ;
7874 cur = hcum[ih] ; if( cur <= prev ) cur = 1.01 * prev + 1.0 ;
7875 frac = ih + (ns98-prev)/(cur-prev) ;
7876 *per98 = bot + dbin * frac ;
7877
7878 if( *per98 > top ) *per98 = top ;
7879
7880 EXRETURN ;
7881 }
7882
7883 /*------------------------------------------------------------------------
7884 change the palette based on the arrow actions
7885 --------------------------------------------------------------------------*/
7886
ISQ_arrow_CB(MCW_arrowval * av,XtPointer client_data)7887 void ISQ_arrow_CB( MCW_arrowval *av , XtPointer client_data )
7888 {
7889 MCW_imseq *seq = (MCW_imseq *) client_data ;
7890 int ddd ;
7891
7892 ENTRY("ISQ_arrow_CB") ;
7893
7894 if( ! ISQ_REALZ(seq) ) EXRETURN ;
7895
7896 if( av->fval > av->old_fval ) ddd = -1 ;
7897 else ddd = 1 ;
7898
7899 /*
7900 ddd = (av->fval > av->old_fval) ? (-1) : (1) ;
7901 */
7902
7903 if( av == seq->arrow[NARR_SQUEEZE] ){
7904 DC_palette_squeeze( seq->dc , ddd ) ;
7905 COLORMAP_CHANGE(seq) ; /* 22 Aug 1998 */
7906
7907 } else if( av == seq->arrow[NARR_BRIGHT] ){
7908 DC_palette_bright( seq->dc , ddd ) ;
7909 COLORMAP_CHANGE(seq) ; /* 22 Aug 1998 */
7910
7911 } else if( av == seq->arrow[NARR_ROTATE] ){
7912 DC_palette_rotate( seq->dc ,-ddd ) ;
7913 COLORMAP_CHANGE(seq) ; /* 22 Aug 1998 */
7914
7915 } else if( av == seq->arrow[NARR_GAMMA] ){
7916 if( seq->imim == NULL || seq->imim->kind != MRI_rgb ){
7917 double new_gamma = seq->dc->gamma ;
7918 if( ddd > 0 ) new_gamma *= 0.95 ;
7919 else new_gamma /= 0.95 ;
7920 DC_palette_restore( seq->dc , new_gamma ) ;
7921 COLORMAP_CHANGE(seq) ; /* 22 Aug 1998 */
7922
7923 } else { /* 25 Apr 2005: delta gamma on RGB images */
7924 if( ddd > 0 ) seq->rgb_gamma *= 0.95 ;
7925 else seq->rgb_gamma /= 0.95 ;
7926 ISQ_redisplay( seq , -1 , isqDR_reimage ) ;
7927 }
7928
7929 } else if( av == seq->arrow[NARR_FRAC] ){ /* 25 Oct 1996 */
7930 float nfrac = seq->image_frac ;
7931
7932 nfrac += (ddd < 0) ? DFRAC : -DFRAC ;
7933
7934 if( nfrac >= FRAC_MIN && nfrac <= FRAC_MAX ){
7935 seq->image_frac = nfrac ;
7936
7937 XtVaSetValues( seq->wimage ,
7938 XmNrightPosition ,(int)(0.49 + nfrac * FORM_FRAC_BASE),
7939 XmNbottomPosition,(int)(0.49 + nfrac * FORM_FRAC_BASE),
7940 NULL ) ;
7941 XtVaSetValues( seq->wscale ,
7942 XmNrightPosition ,(int)(0.49 + nfrac * FORM_FRAC_BASE),
7943 NULL ) ;
7944 XtVaSetValues( seq->wbar ,
7945 XmNbottomPosition,(int)(0.49 + nfrac * FORM_FRAC_BASE),
7946 NULL ) ;
7947 XtVaSetValues( seq->winfo ,
7948 XmNrightPosition ,(int)(0.49 + nfrac * FORM_FRAC_BASE),
7949 NULL ) ;
7950 } else {
7951 /* XBell( seq->dc->display , 100 ) ; */
7952 }
7953 }
7954
7955 ISQ_but_done_reset( seq ) ;
7956 EXRETURN ;
7957 }
7958
7959 /*-----------------------------------------------------------------------
7960 Norm button callback: normalize the palette
7961 -------------------------------------------------------------------------*/
7962
ISQ_but_cnorm_CB(Widget w,XtPointer client_data,XtPointer call_data)7963 void ISQ_but_cnorm_CB( Widget w, XtPointer client_data, XtPointer call_data )
7964 {
7965 MCW_imseq *seq = (MCW_imseq *) client_data ;
7966
7967 ENTRY("ISQ_but_cnorm_CB") ;
7968
7969 if( ! ISQ_REALZ(seq) ) EXRETURN ;
7970
7971 DC_palette_restore( seq->dc , 0.0 ) ;
7972 seq->rgb_gamma = 1.0 ; /* 25 Apr 2005 */
7973 seq->rgb_offset = 0.0 ;
7974 COLORMAP_CHANGE(seq) ; /* 22 Aug 1998 */
7975 ISQ_but_done_reset( seq ) ;
7976 EXRETURN ;
7977 }
7978
7979 /*-----------------------------------------------------------------------
7980 External interface to drive an MCW_imseq:
7981 seq = pointer to structure returned by open_MCW_imseq
7982 drive_code = integer indicating which action to take
7983 drive_data = data or pointer to data controlling action
7984 (you will probably have to cast this to
7985 XtPointer to avoid ugly warnings from the compiler)
7986
7987 drive_code drive_data should be
7988 ---------- --------------------
7989 * isqDR_imhelptext (char *) with new help string for image window
7990 N.B.: this string is copied and so may be
7991 deleted after the call if you like
7992
7993 * isqDR_options (ISQ_options *) with new options for display
7994
7995 * isqDR_numtotal (int) with new number of images available;
7996 WARNING: you cannot reduce numtotal above
7997 the value num_series in the "status"
7998
7999 * isqDR_cursor (int) with new cursor id for the image window;
8000 (if negative, means from cursorfont)
8001
8002 * isqDR_unrealize (ignored) the viewer is unrealized [hidden], but
8003 not destroyed
8004
8005 * isqDR_realize (ignored) an unrealized viewer is re-realized
8006
8007 * isqDR_display (int) call this int "n":
8008 n < 0 -> re-get current image and overlay
8009 n >= 0 -> move to image # n
8010
8011 * isqDR_overlay (int) call this int "n"
8012 if n == current image, just re-get overlay
8013 otherwise, move to image # n
8014 (setting n=-1 is the same as n=current image)
8015
8016 * isqDR_destroy (ignored) destroy this MCW_imseq, and delete its
8017 own XtMalloc-ed internal data structures;
8018 after this call, you must myXtFree(seq) to finish
8019 the job.
8020
8021 * isqDR_arrowpadon (char *) with help string for arrowpad;
8022 this call turns the arrowpad on; after this, it
8023 will be visible and send callbacks
8024
8025 * isqDR_arrowpadoff (ignored) turn the arrowpad off
8026
8027 * isqDR_newseq (XtPointer) contains new auxiliary data for getim;
8028 this call switches the image sequence to a
8029 new one entirely; this call should be followed
8030 immediately by one to display the desired
8031 image from the new sequence!
8032
8033 * isqDR_title (char *) contains new string for window title bar
8034
8035 * isqDR_clearstat (ignored) clears the statistics saved for the
8036 sequence of images; usually used for a change
8037 in the way the images are rendered
8038
8039 * isqDR_onoffwid (int) if 0, turns non-image widgets "off" (0=isqDR_offwid)
8040 if 1, turns non-image widgets "on" (1=isqDR_onwid)
8041 if 2, toggles their current state (2=isqDR_togwid)
8042
8043 * isqDR_getimnr (int *) returns the current image index in the sequence
8044 in the location pointed to by this argument
8045
8046 * isqDR_icon (Pixmap) sets the icon for this window
8047
8048 * isqDR_bgicon (Pixmap) sets the background for this window
8049
8050 * isqDR_sendmontage (ignored) tells the MCW_imseq to send the
8051 montage information back via isqCR_newmontage
8052
8053 * isqDR_periodicmont (int) tells whether to use periodic montages
8054 * isqDR_montmode (int) sets the montage mode
8055
8056 * isqDR_button2_enable (ignored) tells to enable processing of Button2 events
8057 * isqDR_button2_disable (ignored) tells to disable such processing
8058 * isqDR_button2_pixel (Pixel) use argument for button2 drawing color
8059 * isqDR_button2_mode (int) tells how to draw; the argument is
8060 BUTTON2_OPENPOLY == open polygon
8061 BUTTON2_CLOSEDPOLY == closed polygon
8062 BUTTON2_POINTS == only draw points
8063 BUTTON2_NODRAW == don't draw anything
8064 * isqDR_button2_width (int) tells width of lines to draw in button2 mode
8065
8066 * isqDR_rebar (ignored) erase the color bar and show it again
8067
8068 * isqDR_winfotext (char *) sets the winfo extra text
8069
8070 * isqDR_winfosides (char **) sets the winfo_sides text
8071 * isqDR_winfoprefix (char *) set the winfo_prefix text
8072
8073 * isqDR_rinfolabel (char *) set the rinfo label [11 Mar 2020]
8074
8075 * isqDR_getoptions (ISQ_options *) to get the current options
8076
8077 * isqDR_setmontage (int *) sets the montage parameters
8078 [0] = nx [1] = ny [2] = spacing
8079 [3] = gap [4] = gap_color (overlay index)
8080
8081 * isqDR_setifrac (float *) sets the image fraction
8082 between FRAC_MIN and FRAC_MAX
8083
8084 * isqDR_opacitybut (int) turns opacity control on/off
8085
8086 * isqDR_setopacity (int) sets opacity (value=0..9)
8087 * isqDR_getopacity (int *) get opacity setting
8088
8089 * isqDR_zoombut (int) turns zoom control on/off
8090 * isqDR_penbbox (int) turns pen bbox on/off
8091
8092 * isqDR_record_mode (ignored)
8093 makes this an image recorder (irreversibly)
8094
8095 * isqDR_record_disable (ignored)
8096 disables the Rec button (irreversibly)
8097
8098 * isqDR_plot_label (int)
8099 0..6 for label position; -1=toggle widgets
8100
8101 * isqDR_plot_plot (int)
8102 1=show overlay plot; 0=don't; -1=toggle widget
8103
8104 * isqDR_ignore_redraws (int)
8105 1=ignore redraw commands
8106 0=don't ignore redraw commands
8107
8108 * isqDR_setimsave (char *) suffix of image save mode
8109
8110 * isqDR_setrange (float *) points to rng_bot,rng_top
8111 * isqDR_settopclip (float *) points to top_clip
8112
8113 * isqDR_keypress (unsigned int) character or KeySym to send
8114
8115 * isqDR_save_jpeg (char *) save current image to this filename
8116 * isqDR_save_png (char *) save current image to this filename
8117 * isqDR_save_raw (char *) save current image to this filename
8118 * isqDR_save_rawmont (char *) save current montage to this filename
8119 * isqDR_save_filtered (char *) save current image to this filter
8120 * isqDR_save_agif (char *) save current image series to this filename
8121 * isqDR_save_mpeg (char *) save current image series to this filename
8122 * isqDR_save_jpegall (char *) save current image series to bunch of files
8123 * isqDR_save_pngall (char *) save current image series to bunch of files
8124
8125 * isqDR_get_crop (int *) 4 ints that specify current crop status
8126 * isqDR_set_crop (int *) 4 ints to change current crop status
8127 * isqDR_get_zoom (int *) 1 int to receive zoom level (1-4)
8128 * isqDR_set_zoom (int *) 1 int to set zoom level (1-4)
8129 * isqDR_get_panoff (float *) 2 floats = panning offsets
8130 * isqDR_set_panoff (float *) 2 floats to set panning offsets
8131
8132 * isqDR_allowmerger (ignored) allows the 3,4,5,6 'merger' buttons
8133
8134 * isqDR_pressbut_Colr (ignored) presses the 'Colr' button
8135 * isqDR_pressbut_Swap (ignored) presses the 'Swap' button
8136 * isqDR_pressbut_Norm (ignored) presses the 'Norm' button
8137
8138 The RwcBoolean return value is True for success, False for failure.
8139 -------------------------------------------------------------------------*/
8140
drive_MCW_imseq(MCW_imseq * seq,int drive_code,XtPointer drive_data)8141 RwcBoolean drive_MCW_imseq( MCW_imseq *seq ,
8142 int drive_code , XtPointer drive_data )
8143 {
8144 ENTRY("drive_MCW_imseq") ;
8145 if( ! ISQ_VALID(seq) ) RETURN( False );
8146
8147 switch( drive_code ){
8148
8149 /*------- error! -------*/
8150
8151 default:{
8152 fprintf(stderr,"\a\n*** drive_MCW_imseq: code=%d illegal!\n",
8153 drive_code) ;
8154 /* XBell( seq->dc->display , 100 ) ; */
8155 RETURN( False );
8156 }
8157 break ;
8158
8159 /*--------- pressbut_Colr [25 Oct 2019] ----------*/
8160
8161 case isqDR_pressbut_Colr:{
8162 ISQ_but_color_CB( NULL , (XtPointer)seq , NULL ) ;
8163 }
8164 break ;
8165
8166 /*--------- pressbut_Swap [25 Oct 2019] ----------*/
8167
8168 case isqDR_pressbut_Swap:{
8169 ISQ_but_cswap_CB( NULL , (XtPointer)seq , NULL ) ;
8170 }
8171 break ;
8172
8173 /*--------- pressbut_Norm [25 Oct 2019] ----------*/
8174
8175 case isqDR_pressbut_Norm:{
8176 ISQ_but_cnorm_CB( NULL , (XtPointer)seq , NULL ) ;
8177 }
8178 break ;
8179
8180 /*--------- set top_clip [14 Sep 2007] ----------*/
8181
8182 case isqDR_settopclip:{
8183 float *tc=(float *)drive_data ; int zz=0 ;
8184 if( tc == NULL ){
8185 seq->top_clip = 0.0f ; seq->redo_clip = 0 ;
8186 } else {
8187 seq->top_clip = *tc ; zz = (seq->top_clip > 0.0f) ;
8188 }
8189 #if 0
8190 printf("set top_clip=%g redo_clip=%d zz=%d\n",seq->top_clip,seq->redo_clip,zz);
8191 #endif
8192 ALLOW_CLIPPING( seq , zz ) ;
8193 if( tc == NULL ) ISQ_redisplay( seq , -1 , isqDR_display ) ;
8194 RETURN( True ) ;
8195 }
8196 break ;
8197
8198 /*--------- save image type? [23 Jan 2003] ----------*/
8199
8200 case isqDR_setimsave:{
8201 char *suf = (char *)drive_data ;
8202 int ii ;
8203 if( suf == NULL || *suf == '\0' || ppmto_num < 1 ) RETURN(False) ;
8204 for( ii=0 ; ii < ppmto_num ; ii++ ){
8205 if( strcmp(suf ,ppmto_suffix[ii]) == 0 ) break ;
8206 if( strcmp(suf+1,ppmto_suffix[ii]) == 0 ) break ;
8207 }
8208 if( ii == ppmto_num ) RETURN(False) ;
8209 seq->opt.save_filter = ii ;
8210 SET_SAVE_LABEL(seq) ;
8211 if( seq->num_bbox > 0 && seq->bbox[NTOG_SAV] != NULL )
8212 MCW_set_bbox( seq->bbox[NTOG_SAV] , ppmto_bval[ii] ) ;
8213 RETURN( True ) ;
8214 }
8215 break ;
8216
8217 /*--------- ignore redraws? [16 Aug 2002] -------------*/
8218
8219 case isqDR_ignore_redraws:{
8220 int dd = PTOI(drive_data) ;
8221 seq->ignore_redraws = dd ;
8222 RETURN( True ) ;
8223 }
8224 break ;
8225
8226 /*--------- allowmerger [25 Aug 2014] ----------*/
8227
8228 case isqDR_allowmerger:{
8229 seq->allowmerger = 1 ;
8230 RETURN( True ) ;
8231 }
8232 break ;
8233
8234 /*--------- set display range [04 Nov 2003] ----------*/
8235
8236 case isqDR_setrange:{
8237 float *rng = (float *)drive_data ;
8238 if( rng == NULL ){
8239 seq->rng_bot = seq->rng_top = seq->rng_ztop = 0.0f ;
8240 } else {
8241 seq->rng_bot = rng[0] ; seq->rng_top = rng[1] ; seq->rng_ztop = 0.0 ;
8242 seq->rng_extern = 1 ;
8243 }
8244 if( rng == NULL || rng[2] == 0.0f )
8245 ISQ_redisplay( seq , -1 , isqDR_display ) ;
8246 RETURN( True ) ;
8247 }
8248 break ;
8249
8250 /*--------- overlay plot stuff [20 Sep 2001] ----------*/
8251
8252 case isqDR_plot_label:{
8253 int dd = PTOI(drive_data) ;
8254
8255 if( dd < 0 ){
8256 INVERT_manage( seq->wbar_label_av->wrowcol ) ;
8257 INVERT_manage( seq->wbar_labsz_av->wrowcol ) ;
8258 } else if( dd != seq->wbar_label_av->ival && dd >= 0 && dd <= 5 ){
8259 AV_assign_ival( seq->wbar_label_av , dd ) ;
8260 ISQ_redisplay( seq , -1 , isqDR_display ) ;
8261 }
8262 RETURN( True ) ;
8263 }
8264
8265 /*.....................................................*/
8266
8267 case isqDR_save_jpeg:{ /* 28 Jul 2005 */
8268 char *fname = (char *)drive_data ;
8269 ISQ_save_jpeg( seq , fname ) ;
8270 RETURN( True ) ;
8271 }
8272
8273 case isqDR_save_png:{ /* 11 Dec 2006 */
8274 char *fname = (char *)drive_data ;
8275 ISQ_save_png( seq , fname ) ;
8276 RETURN( True ) ;
8277 }
8278
8279 case isqDR_save_raw:{ /* 13 Nov 2007 */
8280 char *fname = (char *)drive_data ;
8281 ISQ_save_raw( seq , fname ) ;
8282 RETURN( True ) ;
8283 }
8284
8285 case isqDR_save_rawmont:{ /* 13 Nov 2007 */
8286 char *fname = (char *)drive_data ;
8287 ISQ_save_rawmont( seq , fname ) ;
8288 RETURN( True ) ;
8289 }
8290
8291 case isqDR_save_filtered:{ /* 14 Dec 2006 */
8292 char *fname = (char *)drive_data ;
8293 ISQ_save_image( seq , NULL , fname , NULL ) ;
8294 RETURN( True ) ;
8295 }
8296
8297 case isqDR_save_agif:{
8298 char *fname = (char *)drive_data ;
8299 ISQ_save_anim( seq , fname , 0,0, AGIF_MODE ) ;
8300 RETURN(True) ;
8301 }
8302
8303 case isqDR_save_mpeg:{
8304 char *fname = (char *)drive_data ;
8305 ISQ_save_anim( seq , fname , 0,0, MPEG_MODE ) ;
8306 RETURN(True) ;
8307 }
8308
8309 case isqDR_save_jpegall:{
8310 char *fname = (char *)drive_data ;
8311 ISQ_save_anim( seq , fname , 0,0, JPEG_MODE ) ;
8312 RETURN(True) ;
8313 }
8314
8315 case isqDR_save_pngall:{
8316 char *fname = (char *)drive_data ;
8317 ISQ_save_anim( seq , fname , 0,0, PNG_MODE ) ;
8318 RETURN(True) ;
8319 }
8320
8321 /*.....................................................*/
8322
8323 case isqDR_plot_plot:{
8324 int dd = PTOI(drive_data) ;
8325
8326 if( dd < 0 ){
8327 INVERT_manage( seq->wbar_plots_bbox->wrowcol ) ;
8328 } else {
8329 dd = (dd != 0) ;
8330 if( dd != MCW_val_bbox(seq->wbar_plots_bbox) ){
8331 MCW_set_bbox( seq->wbar_plots_bbox , dd ) ;
8332 ISQ_redisplay( seq , -1 , isqDR_display ) ;
8333 }
8334 }
8335 RETURN( True ) ;
8336 }
8337
8338 /*--------- record off forever [24 Apr 2001] ----------*/
8339
8340 case isqDR_record_disable:{
8341 ISQ_remove_widget( seq , seq->record_rc ) ;
8342 seq->record_status = RECORD_STATUS_OFF ;
8343 RETURN( True ) ;
8344 }
8345 break ;
8346
8347 /*--------- record mode [24 Apr 2001] ----------*/
8348
8349 case isqDR_record_mode:{
8350 int ii ;
8351 static Pixmap record_pixmap = XmUNSPECIFIED_PIXMAP ;
8352 #define record_width 64
8353 #define record_height 32
8354 static unsigned char record_bits[] = {
8355 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
8356 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8357 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x0f, 0x00, 0x00,
8358 0x00, 0x00, 0x00, 0x00, 0x81, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8359 0x81, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00,
8360 0x00, 0x00, 0x00, 0x02, 0x81, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
8361 0x81, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x81, 0x40, 0x00, 0x00,
8362 0x00, 0x00, 0x00, 0x02, 0x81, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
8363 0x81, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x81, 0x10, 0x00, 0x00,
8364 0x00, 0x00, 0x00, 0x02, 0x81, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
8365 0x81, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x81, 0x10, 0x00, 0x00,
8366 0x00, 0x00, 0x00, 0x02, 0x81, 0x10, 0x70, 0x00, 0xe0, 0xf0, 0x01, 0x02,
8367 0x81, 0x20, 0x8c, 0xf0, 0x10, 0x21, 0xe2, 0x03, 0x81, 0x20, 0x02, 0x09,
8368 0x09, 0x22, 0x12, 0x02, 0x81, 0x20, 0x02, 0x09, 0x08, 0x22, 0x10, 0x02,
8369 0x81, 0x20, 0xfe, 0x09, 0x08, 0x22, 0x10, 0x02, 0x81, 0x40, 0x02, 0x08,
8370 0x08, 0x22, 0x10, 0x02, 0x81, 0x40, 0x02, 0x08, 0x08, 0x22, 0x10, 0x02,
8371 0x81, 0x40, 0x02, 0x08, 0x08, 0x22, 0x10, 0x02, 0x81, 0x40, 0x02, 0x08,
8372 0x08, 0x22, 0x10, 0x02, 0x81, 0x40, 0x04, 0x11, 0x11, 0x21, 0x20, 0x02,
8373 0x81, 0x40, 0xf8, 0xe0, 0xe0, 0x20, 0xc0, 0x01, 0x01, 0x00, 0x00, 0x00,
8374 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8375 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
8376 0x00, 0x00, 0x00, 0x00};
8377
8378 if( seq->record_mode ) RETURN( False ) ; /* already on */
8379 seq->record_mode = 1 ;
8380 seq->cropit = seq->crop_allowed = 0 ; /* 12 Jun 2002 */
8381
8382 /* create background pixmap */
8383
8384 if( record_pixmap == XmUNSPECIFIED_PIXMAP )
8385 record_pixmap = XCreatePixmapFromBitmapData(
8386 seq->dc->display ,
8387 RootWindowOfScreen(seq->dc->screen) ,
8388 (char *)record_bits, record_width, record_height ,
8389 seq->dc->ovc->pixov_brightest ,
8390 seq->dc->ovc->pixov_darkest ,
8391 DefaultDepthOfScreen(seq->dc->screen) ) ;
8392
8393 XtVaSetValues( seq->wform, XmNbackgroundPixmap, record_pixmap, NULL ) ;
8394
8395 /* disable various widgets */
8396
8397 ISQ_remove_widget( seq , seq->wbut_bot[NBUT_MONT] ) ;
8398 ISQ_remove_widget( seq , seq->record_rc ) ;
8399 for( ii=0 ; ii < NBUTTON_RIG ; ii++)
8400 ISQ_remove_widget( seq , seq->wbut_rig[ii] ) ;
8401 for( ii=0 ; ii < NARROW-1 ; ii++ ) /* keep "i" arrow */
8402 ISQ_remove_widget( seq , seq->arrow[ii]->wrowcol ) ;
8403 if( seq->ov_opacity_av != NULL ){
8404 ISQ_remove_widget( seq , seq->ov_opacity_sep ) ;
8405 ISQ_remove_widget( seq , seq->ov_opacity_av->wrowcol ) ;
8406 }
8407
8408 ISQ_remove_widget( seq , seq->zoom_sep ) ;
8409 ISQ_remove_widget( seq , seq->zoom_val_av->wrowcol ) ;
8410 ISQ_remove_widget( seq , seq->zoom_drag_pb ) ;
8411 ISQ_remove_widget( seq , seq->crop_drag_pb ) ;
8412 ISQ_remove_widget( seq , seq->pen_bbox->wrowcol ) ;
8413
8414 ISQ_remove_widget( seq , seq->arrowpad->wform ) ;
8415 ISQ_remove_widget( seq , seq->wbar ) ;
8416 ISQ_remove_widget( seq , seq->winfo ) ;
8417 ISQ_remove_widget( seq , seq->rinfo ) ;
8418
8419 /* change to Save:bkg */
8420
8421 seq->opt.save_one = 0 ;
8422 seq->opt.save_agif = 0 ; /* 27 Jul 2001 */
8423 seq->opt.save_mpeg = 0 ;
8424 seq->opt.save_pnm = 0 ;
8425 seq->opt.save_filter = -1 ; /* 27 Jun 2001 */
8426 SET_SAVE_LABEL(seq) ;
8427 drive_MCW_imseq( seq , isqDR_setimsave ,
8428 (XtPointer)getenv("AFNI_DEFAULT_IMSAVE") ) ;
8429
8430 /* 27 Jun 2001: change help on Save: */
8431
8432 MCW_unregister_help( seq->wbut_bot[NBUT_DISP] ) ;
8433 if( ppmto_num > 0 ){
8434 MCW_register_help( seq->wbut_bot[NBUT_SAVE] ,
8435 "Save controls:\n"
8436 " Press with Button 1 (left) to save images\n"
8437 " Press with Button 3 (right) to change the\n"
8438 " format of the saved images"
8439 ) ;
8440 MCW_register_hint( seq->wbut_bot[NBUT_SAVE] ,
8441 "Button 3 => change save format" ) ;
8442 } else {
8443 MCW_register_help( seq->wbut_bot[NBUT_SAVE] ,
8444 "Save controls:\n"
8445 " Press with Button 1 (left) to\n"
8446 " in the PNM format save images" ) ;
8447 MCW_register_hint( seq->wbut_bot[NBUT_SAVE] ,
8448 "Save images as PNM" ) ;
8449 }
8450
8451 /* change Disp to Kill */
8452
8453 XtRemoveCallback( seq->wbut_bot[NBUT_DISP] , XmNactivateCallback ,
8454 ISQ_but_bot_def[NBUT_DISP].func_CB , seq ) ;
8455
8456 XtAddCallback( seq->wbut_bot[NBUT_DISP] , XmNactivateCallback ,
8457 ISQ_record_kill_CB , seq ) ;
8458
8459 MCW_set_widget_label( seq->wbut_bot[NBUT_DISP] , "Kill" ) ;
8460 MCW_unregister_help( seq->wbut_bot[NBUT_DISP] ) ;
8461 MCW_register_hint( seq->wbut_bot[NBUT_DISP] , "Erase current image" ) ;
8462 MCW_register_help( seq->wbut_bot[NBUT_DISP] ,
8463 "Erase the current image in the recorded sequence.\n"
8464 "If not later overwritten, this image will NOT\n"
8465 "be saved when you use Save:bkg to write the image\n"
8466 "sequence to disk.\n"
8467 ) ;
8468
8469 /* attach Done to Save (since Mont is now hidden) */
8470
8471 XtVaSetValues( seq->wbut_bot[NBUT_DONE] ,
8472 LEADING_BOT , XmATTACH_WIDGET ,
8473 LEADING_WIDGET_BOT, seq->wbut_bot[NBUT_SAVE] ,
8474 NULL ) ;
8475
8476 /* Miscellaneous stuff */
8477
8478 XtVaSetValues( seq->wtop , XmNtitle , "Image Recorder" , NULL ) ;
8479 if( MCW_isitmwm( seq->wtop ) )
8480 XtVaSetValues( seq->wtop ,
8481 XmNmwmDecorations, MWM_DECOR_ALL | MWM_DECOR_MAXIMIZE,
8482 NULL ) ;
8483
8484 RETURN( True ) ;
8485 }
8486 break ;
8487
8488 /*--------- opacity button [07 Mar 2001] ----------*/
8489
8490 case isqDR_opacitybut:{
8491 int val = PTOI(drive_data) ;
8492 if( seq->ov_opacity_av == NULL ) RETURN( False ) ;
8493 if( val == 0 ){
8494 XtUnmanageChild( seq->ov_opacity_sep ) ;
8495 XtUnmanageChild( seq->ov_opacity_av->wrowcol ) ;
8496 }
8497 else {
8498 XtManageChild( seq->ov_opacity_sep ) ;
8499 XtManageChild( seq->ov_opacity_av->wrowcol ) ;
8500 }
8501 RETURN( True ) ;
8502 }
8503 break ;
8504
8505 /*--------- set opacity value [21 Jan 2003] ----------*/
8506
8507 case isqDR_setopacity:{
8508 int val = PTOI(drive_data) ;
8509 if( seq->ov_opacity_av == NULL ) RETURN( False ) ;
8510 if( val < OPACITY_BOT || val > OPACITY_TOP ) RETURN( False ) ;
8511 if( val == seq->ov_opacity_av->ival ) RETURN( True ) ;
8512 AV_assign_ival( seq->ov_opacity_av , val ) ;
8513 ISQ_opacity_CB( seq->ov_opacity_av , seq ) ;
8514 RETURN( True ) ;
8515 }
8516 break ;
8517
8518 /*--------- get opacity value [21 Jan 2003] ----------*/
8519
8520 case isqDR_getopacity:{
8521 int *val = (int *) drive_data ;
8522 if( seq->ov_opacity_av == NULL || val == NULL ) RETURN( False ) ;
8523 *val = seq->ov_opacity_av->ival ;
8524 RETURN( True ) ;
8525 }
8526 break ;
8527
8528 /*--------- get zoom data [10 Dec 2019] -----------*/
8529
8530 case isqDR_get_zoom:{
8531 int *iar = (int *)drive_data ;
8532 if( iar != NULL ){
8533 iar[0] = seq->zoom_fac ;
8534 }
8535 RETURN(True) ;
8536 }
8537 break ;
8538
8539 /*--------- set zoom data [10 Dec 2019] -----------*/
8540
8541 case isqDR_set_zoom:{
8542 int *val = (int *)drive_data ;
8543 if( val != NULL && *val >= ZOOM_BOT && *val <= ZOOM_TOP &&
8544 *val != seq->zoom_fac ){
8545 AV_assign_ival( seq->zoom_val_av , *val ) ;
8546 ISQ_zoom_av_CB( seq->zoom_val_av , seq ) ;
8547 }
8548 RETURN(True) ;
8549 }
8550 break ;
8551
8552 /*--------- set the panning offsets [10 Dec 2019] ----------*/
8553
8554 case isqDR_set_panoff:{
8555 float *val = (float *)drive_data , zlev = seq->zoom_fac ;;
8556 if( val != NULL && zlev > 1.0f ){
8557 float hoff = val[0] , voff = val[1] , mh = (zlev-1.001f)/zlev ;
8558 if( hoff > mh ) hoff = mh ;
8559 else if( hoff < 0.0 ) hoff = 0.0 ;
8560 if( voff > mh ) voff = mh ;
8561 else if( voff < 0.0 ) voff = 0.0 ;
8562 if( hoff != seq->zoom_hor_off || voff != seq->zoom_ver_off ){
8563 seq->zoom_hor_off = hoff ;
8564 seq->zoom_ver_off = voff ;
8565 ISQ_show_zoom( seq ) ; /* no visible panning widgets to alter */
8566 ZOOM_CHANGE(seq) ;
8567 }
8568 }
8569 RETURN(True) ;
8570 }
8571 break ;
8572
8573 /*--------- get the panning offsets [10 Dec 2019] ----------*/
8574
8575 case isqDR_get_panoff:{
8576 float *val = (float *)drive_data , zlev = seq->zoom_fac ;
8577 if( val != NULL ){
8578 if( zlev > 1.0f ){
8579 val[0] = seq->zoom_hor_off ;
8580 val[1] = seq->zoom_ver_off ;
8581 } else {
8582 val[0] = val[1] = 0.0f ;
8583 }
8584 }
8585 RETURN(True) ;
8586 }
8587 break ;
8588
8589 /*--------- get crop data [03 May 2007] -----------*/
8590
8591 case isqDR_get_crop:{
8592 int *iar = (int *)drive_data ;
8593 if( iar != NULL ){
8594 if( !seq->cropit ){
8595 iar[0] = iar[1] = iar[2] = iar[3] = -1 ;
8596 } else {
8597 iar[0] = seq->crop_xa ; iar[1] = seq->crop_xb ;
8598 iar[2] = seq->crop_ya ; iar[3] = seq->crop_yb ;
8599 }
8600 }
8601 RETURN(True) ;
8602 }
8603 break ;
8604
8605 /*--------- set crop data [03 May 2007] -----------*/
8606
8607 case isqDR_set_crop:{
8608 int *iar = (int *)drive_data ;
8609 if( iar == NULL ||
8610 iar[0] < 0 || iar[2] < 0 ||
8611 iar[0]+MINCROP >= iar[1] || iar[2]+MINCROP >= iar[3] ){
8612 seq->cropit = 0 ;
8613 } else {
8614 seq->cropit = 1 ;
8615 seq->crop_xa = iar[0] ; seq->crop_xb = iar[1] ;
8616 seq->crop_ya = iar[2] ; seq->crop_yb = iar[3] ;
8617 if( seq->crop_nxorg > 0 && seq->crop_xb >= seq->crop_nxorg )
8618 seq->crop_xb = seq->crop_nxorg-1 ;
8619 if( seq->crop_nyorg > 0 && seq->crop_yb >= seq->crop_nyorg )
8620 seq->crop_yb = seq->crop_nyorg-1 ;
8621 }
8622 ISQ_redisplay( seq , -1 , isqDR_display ) ;
8623 RETURN(True) ;
8624 }
8625 break ;
8626
8627 /*--------- zoom buttons [11 Mar 2002] ----------*/
8628
8629 case isqDR_zoombut:{
8630 int val = PTOI(drive_data) ;
8631 if( val == 0 ){
8632 XtUnmanageChild( seq->zoom_sep ) ;
8633 XtUnmanageChild( seq->zoom_val_av->wrowcol ) ;
8634 XtUnmanageChild( seq->zoom_drag_pb ) ;
8635 XtUnmanageChild( seq->crop_drag_pb ) ;
8636 } else {
8637 XtManageChild( seq->zoom_sep ) ;
8638 XtManageChild( seq->zoom_val_av->wrowcol ) ;
8639 XtManageChild( seq->zoom_drag_pb ) ;
8640 XtManageChild( seq->crop_drag_pb ) ;
8641 }
8642 RETURN( True ) ;
8643 }
8644 break ;
8645
8646 /*--------- pen bbox [18 Jul 2003] ----------*/
8647
8648 case isqDR_penbbox:{
8649 int val = PTOI(drive_data) ;
8650 if( val == 0 )
8651 XtUnmanageChild( seq->pen_bbox->wrowcol ) ;
8652 else
8653 XtManageChild( seq->pen_bbox->wrowcol ) ;
8654 RETURN( True ) ;
8655 }
8656 break ;
8657
8658 /*--------- set montage [22 Sep 2000] ----------*/
8659 /* [mostly copied from ISQ_montage_action_CB()] */
8660
8661 case isqDR_setmontage:{
8662 int *mm = (int *) drive_data ;
8663
8664 if( mm == NULL ) RETURN( False ); /* sanity */
8665 if( mm[0] < 1 || mm[0] > MONT_NMAX ) RETURN( False ); /* checks */
8666 if( mm[1] < 1 || mm[1] > MONT_NMAX ) RETURN( False );
8667
8668 seq->mont_nx_old = seq->mont_nx ; /* save */
8669 seq->mont_ny_old = seq->mont_ny ;
8670 seq->mont_skip_old = seq->mont_skip ;
8671 seq->mont_gap_old = seq->mont_gap ;
8672 seq->mont_gapcolor_old = seq->mont_gapcolor ;
8673
8674 /* set new values, if legal */
8675
8676 seq->mont_nx = mm[0] ;
8677 seq->mont_ny = mm[1] ;
8678 if( mm[2] > 0 && mm[2] <= MONT_SMAX ) seq->mont_skip = mm[2]-1 ;
8679 if( mm[3] >= 0 && mm[3] <= MONT_GMAX ) seq->mont_gap = mm[3] ;
8680 if( mm[4] >= 0 &&
8681 mm[4] <= seq->dc->ovc->ncol_ov-1 ) seq->mont_gapcolor = mm[4] ;
8682
8683 /* set Save One */
8684
8685 if( seq->mont_nx * seq->mont_ny > 1 && !seq->opt.save_one ){
8686 seq->opt.save_one = 1 ;
8687 seq->opt.save_agif = 0 ; /* 27 Jul 2001 */
8688 seq->opt.save_mpeg = 0 ;
8689 SET_SAVE_LABEL(seq) ;
8690 }
8691
8692 /* now do the redisplay */
8693
8694 ISQ_redisplay( seq , -1 , isqDR_display ) ; /* local redraw */
8695
8696 if( seq->status->send_CB != NULL ){ /* tell AFNI */
8697
8698 ISQ_cbs cbs ;
8699 THD_ivec3 minf ;
8700 int ijcen = (seq->mont_nx)/2 + (seq->mont_ny/2) * seq->mont_nx ,
8701 nmont = seq->mont_nx * seq->mont_ny ;
8702
8703 minf.ijk[0] = ijcen ; /* number of slices before center */
8704 minf.ijk[1] = nmont-ijcen-1 ; /* number after */
8705 minf.ijk[2] = seq->mont_skip ; /* number between slices */
8706 cbs.reason = isqCR_newmontage ;
8707 cbs.userdata = (XtPointer) &minf ;
8708
8709 seq->ignore_redraws = 1 ; /* don't listen to redraws */
8710 #if 0
8711 seq->status->send_CB( seq , seq->getaux , &cbs ) ;
8712 #else
8713 SEND(seq,cbs) ;
8714 #endif
8715 seq->ignore_redraws = 0 ; /* can listen again */
8716 }
8717
8718 #if 0
8719 ISQ_redisplay( seq , -1 , isqDR_display ) ; /* local redraw */
8720 #endif
8721
8722 RETURN( True );
8723 }
8724 break ;
8725
8726 /*------- winfo_prefix text [10 Dec 2007] -------*/
8727
8728 case isqDR_winfoprefix:{
8729 char *pf=(char *)drive_data , lab[2]=" " ;
8730 if( pf == NULL || *pf == '\0' ){
8731 seq->winfo_prefix[0] = '\0' ;
8732 } else {
8733 strncpy( seq->winfo_prefix , pf , 15 ) ;
8734 seq->winfo_prefix[15] = '\0' ;
8735 if( isgraph(*pf) ) lab[0]=*pf ;
8736 }
8737 MCW_set_widget_label( seq->arrowpad->wbut[4] , lab ) ;
8738 seq->im_label[0] = '\0' ; /* will force redraw */
8739 ISQ_draw_winfo( seq ) ;
8740 RETURN( True );
8741 }
8742
8743 /*------- rinfo label text [11 Mar 2020] -------*/
8744
8745 case isqDR_rinfolabel:{
8746 char *pf=(char *)drive_data ;
8747 if( pf == NULL || *pf == '\0' ) pf = "OK" ;
8748 strncpy( seq->rinfo_label , pf , 6 ) ;
8749 seq->rinfo_label[6] = '\0' ;
8750 MCW_set_widget_label( seq->rinfo , seq->rinfo_label ) ;
8751 RETURN( True );
8752 }
8753
8754 /*------- winfo_sides text [01 Dec 1999] -------*/
8755
8756 case isqDR_winfosides:{
8757 char **ws = (char **) drive_data ;
8758 int iw ;
8759
8760 if( ws == NULL ){ /* remove the label data */
8761 seq->winfo_sides[0][0] =
8762 seq->winfo_sides[1][0] =
8763 seq->winfo_sides[2][0] =
8764 seq->winfo_sides[3][0] = '\0' ;
8765
8766 } else { /* change the label data */
8767 for( iw=0 ; iw < 4 ; iw++ ){
8768 if( ws[iw] == NULL || ws[iw][0] == '\0' ){
8769 seq->winfo_sides[iw][0] = '\0' ;
8770 } else {
8771 strncpy( seq->winfo_sides[iw] , ws[iw] , 15 ) ;
8772 seq->winfo_sides[iw][15] = '\0' ;
8773 }
8774 }
8775 }
8776 seq->im_label[0] = '\0' ; /* will force redraw */
8777 ISQ_draw_winfo( seq ) ;
8778
8779 if( ws == NULL ) /* 18 May 2005: add a hint */
8780 MCW_unregister_hint( seq->winfo ) ; /* for the clueless newbie */
8781 else
8782 MCW_register_hint( seq->winfo ,
8783 "setenv AFNI_LEFT_IS_LEFT YES disables 'radiology mode'" );
8784
8785 RETURN( True );
8786 }
8787
8788 /*------- setifrac [22 Sep 2000] -------*/
8789 /* [mostly copied from ISQ_arrow_CB()] */
8790
8791 case isqDR_setifrac:{
8792 float *ff = (float *) drive_data ;
8793
8794 if( ff == NULL || *ff < FRAC_MIN || *ff > 1.0 ) RETURN( False );
8795
8796 if( *ff <= FRAC_MAX ){ /* from ISQ_arrow_CB() */
8797 float nfrac = *ff ;
8798 seq->image_frac = nfrac ;
8799
8800 if( !seq->onoff_state ) /* turn widgets on first, recursively */
8801 drive_MCW_imseq( seq,isqDR_onoffwid,(XtPointer)isqDR_onwid );
8802
8803 XtVaSetValues( seq->wimage ,
8804 XmNrightPosition ,(int)(0.49+nfrac*FORM_FRAC_BASE),
8805 XmNbottomPosition,(int)(0.49+nfrac*FORM_FRAC_BASE),
8806 NULL ) ;
8807 XtVaSetValues( seq->wscale ,
8808 XmNrightPosition ,(int)(0.49+nfrac*FORM_FRAC_BASE),
8809 NULL ) ;
8810 XtVaSetValues( seq->wbar ,
8811 XmNbottomPosition,(int)(0.49+nfrac*FORM_FRAC_BASE),
8812 NULL ) ;
8813 XtVaSetValues( seq->winfo ,
8814 XmNrightPosition ,(int)(0.49+nfrac*FORM_FRAC_BASE),
8815 NULL ) ;
8816
8817 } else if( seq->onoff_state ) { /* turn widgets off */
8818
8819 drive_MCW_imseq( seq,isqDR_onoffwid,(XtPointer)isqDR_offwid );
8820
8821 }
8822 RETURN( True );
8823 }
8824 break ;
8825
8826 /*------- send a simulated key press [18 Feb 2005] -------*/
8827
8828 case isqDR_keypress:{
8829 unsigned int key = (unsigned int)PTOI(drive_data) ;
8830 (void )ISQ_handle_keypress( seq , key , 0 ) ;
8831 RETURN( True );
8832 }
8833 break ;
8834
8835 /*------- winfo extra text [07 Aug 1999] -------*/
8836
8837 case isqDR_winfotext:{
8838 char *wt = (char *) drive_data ;
8839
8840 if( wt == NULL || wt[0] == '\0' ){
8841 seq->winfo_extra[0] = '\0' ;
8842 } else {
8843 strncpy( seq->winfo_extra , wt , 63 ) ;
8844 seq->winfo_extra[63] = '\0' ;
8845 }
8846 seq->im_label[0] = '\0' ; /* will force redraw */
8847 ISQ_draw_winfo( seq ) ;
8848 RETURN( True );
8849 }
8850
8851 /*------- button2 stuff -------*/
8852
8853 case isqDR_button2_pixel:{
8854 seq->button2_pixel = (Pixel) drive_data ;
8855 RETURN( True );
8856 }
8857
8858 case isqDR_button2_mode:{
8859 seq->button2_drawmode = PTOI(drive_data) ;
8860 RETURN( True );
8861 }
8862
8863 case isqDR_button2_width:{ /* 08 Oct 2002 */
8864 seq->button2_width = PTOI(drive_data) ;
8865 RETURN( True );
8866 }
8867
8868 case isqDR_button2_enable:{
8869 ISQ_timer_stop(seq) ;
8870 if( seq->status->send_CB == NULL ) RETURN( False ); /* makes no sense */
8871 if( seq->button2_enabled ) RETURN( True ); /* already on */
8872
8873 XtInsertEventHandler(
8874 seq->wimage , /* handle events in image */
8875
8876 0
8877 | ButtonReleaseMask /* button releases (only #2 is used) */
8878 | Button2MotionMask /* motion while #2 is down */
8879 ,
8880 FALSE , /* nonmaskable events? */
8881 ISQ_button2_EV , /* handler routine */
8882 (XtPointer) seq , /* client data */
8883 XtListTail /* last in queue */
8884 ) ;
8885
8886 seq->button2_enabled = 1 ;
8887 seq->button2_active = 0 ;
8888
8889 XtManageChild( seq->pen_bbox->wrowcol ) ;
8890 RETURN( True );
8891 }
8892
8893 case isqDR_button2_disable:{
8894 if( seq->status->send_CB == NULL ) RETURN( False ); /* makes no sense */
8895 if( !seq->button2_enabled ) RETURN( True ); /* already off */
8896
8897 XtRemoveEventHandler(
8898 seq->wimage , /* unhandle events in image */
8899
8900 0
8901 | ButtonReleaseMask /* button releases (only #2 is used) */
8902 | Button2MotionMask /* motion while #2 is down */
8903 ,
8904 TRUE , /* nonmaskable events? */
8905 ISQ_button2_EV , /* handler routine */
8906 (XtPointer) seq /* client data */
8907 ) ;
8908
8909 seq->button2_enabled = seq->button2_active = 0 ;
8910 ISQ_set_cursor_state( seq , CURSOR_NORMAL ) ;
8911 XtUnmanageChild( seq->pen_bbox->wrowcol ) ;
8912 RETURN( True );
8913 }
8914
8915 /*------- montage stuff -------*/
8916
8917 case isqDR_periodicmont:{
8918 int per = (PTOI(drive_data)) != 0 ;
8919
8920 if( per != seq->mont_periodic ){
8921 seq->mont_periodic = per ;
8922 if( ISQ_REALZ(seq) ) ISQ_redisplay( seq , -1 , isqDR_display ) ;
8923 }
8924 RETURN( True );
8925 }
8926
8927 case isqDR_montmode:{
8928 int mmm = (PTOI(drive_data)) != 0 ;
8929
8930 if( mmm != seq->mont_mode ){
8931 seq->mont_mode = mmm ;
8932 if( ISQ_REALZ(seq) ) ISQ_redisplay( seq , -1 , isqDR_display ) ;
8933 }
8934 RETURN( True );
8935 }
8936
8937 case isqDR_sendmontage:{
8938 if( seq->status->send_CB != NULL ){
8939 ISQ_cbs cbs ;
8940 THD_ivec3 minf ;
8941 int ijcen = (seq->mont_nx)/2 + (seq->mont_ny/2) * seq->mont_nx ,
8942 nmont = seq->mont_nx * seq->mont_ny ;
8943
8944 minf.ijk[0] = ijcen ; /* number of slices before center */
8945 minf.ijk[1] = nmont-ijcen-1 ; /* number after */
8946 minf.ijk[2] = seq->mont_skip ; /* number between slices */
8947 cbs.reason = isqCR_newmontage ;
8948 cbs.userdata = (XtPointer) &minf ;
8949 #if 0
8950 seq->status->send_CB( seq , seq->getaux , &cbs ) ;
8951 #else
8952 SEND(seq,cbs) ;
8953 #endif
8954 RETURN( True );
8955 } else {
8956 RETURN( False );
8957 }
8958 }
8959 break ;
8960
8961 /*------ set icon -----*/
8962
8963 case isqDR_icon:{
8964 XtVaSetValues( seq->wtop, XmNiconPixmap,(Pixmap)drive_data , NULL ) ;
8965 RETURN( True );
8966 }
8967 break ;
8968
8969 /*------ set background icon [28 Jan 2004] -------*/
8970
8971 case isqDR_bgicon:{
8972 XtVaSetValues( seq->wform,
8973 XmNbackgroundPixmap, (Pixmap)drive_data ,
8974 NULL ) ;
8975 RETURN( True );
8976 }
8977 break ;
8978
8979 /*------ get image number -----*/
8980
8981 case isqDR_getimnr:{
8982 int *retval = (int *) drive_data ;
8983
8984 if( retval != NULL ) *retval = seq->im_nr ;
8985 RETURN( True );
8986 }
8987 break ;
8988
8989 /*------ widgets on or off -----*/
8990
8991 case isqDR_onoffwid:{
8992 int mode = PTOI(drive_data) , turn_on ;
8993 int ww , hh ;
8994
8995 switch( mode ){
8996 default:
8997 case isqDR_togwid: turn_on = ! seq->onoff_state ; break ;
8998 case isqDR_onwid: turn_on = 1 ; break ;
8999 case isqDR_offwid: turn_on = 0 ; break ;
9000 }
9001
9002 if( turn_on == seq->onoff_state ) RETURN( True );
9003
9004 MCW_widget_geom( seq->wimage , &ww , &hh , NULL,NULL ) ;
9005
9006 if( turn_on ){
9007 MCW_manage_widgets( seq->onoff_widgets , seq->onoff_num ) ;
9008 XtVaSetValues(
9009 seq->wimage ,
9010 XmNrightPosition ,(int)( 0.49+seq->image_frac*FORM_FRAC_BASE ),
9011 XmNbottomPosition,(int)( 0.49+seq->image_frac*FORM_FRAC_BASE ),
9012 NULL ) ;
9013 XtVaSetValues( seq->wtop ,
9014 XmNwidth , (int)(0.49+ww/seq->image_frac) ,
9015 XmNheight , (int)(0.49+hh/seq->image_frac) ,
9016 NULL ) ;
9017 if( !seq->button2_enabled ) XtUnmanageChild(seq->pen_bbox->wrowcol);
9018 } else {
9019 MCW_unmanage_widgets( seq->onoff_widgets , seq->onoff_num ) ;
9020 XtVaSetValues( seq->wimage ,
9021 XmNrightPosition , FORM_FRAC_BASE ,
9022 XmNbottomPosition, FORM_FRAC_BASE ,
9023 NULL ) ;
9024 XtVaSetValues( seq->wtop ,
9025 XmNwidth , ww ,
9026 XmNheight , hh ,
9027 NULL ) ;
9028 }
9029
9030 seq->onoff_state = turn_on ;
9031 RETURN( True );
9032 }
9033 break ;
9034
9035 /*------- title --------*/
9036
9037 case isqDR_title:{
9038 char *title = (char *) drive_data ;
9039
9040 if( title == NULL || strlen(title) == 0 ) title = "AFNI" ;
9041
9042 XtVaSetValues( seq->wtop , XmNtitle , title , NULL ) ;
9043 #if 1
9044 if( MCW_isitmwm( seq->wtop ) )
9045 XtVaSetValues( seq->wtop ,
9046 XmNmwmDecorations, MWM_DECOR_ALL | MWM_DECOR_MAXIMIZE,
9047 NULL ) ;
9048 #endif
9049 RETURN( True );
9050 }
9051 break ;
9052
9053 /*------- death! -------*/
9054
9055 case isqDR_destroy:{
9056 ISQ_timer_stop(seq) ; NI_sleep(1) ;
9057 ISQ_but_done_CB( NULL , (XtPointer)seq , NULL ) ; NI_sleep(1) ;
9058 RETURN( True );
9059 }
9060 break ;
9061
9062 /*------- unrealize! -------*/
9063
9064 case isqDR_unrealize:{
9065 ISQ_timer_stop(seq) ;
9066 if( ISQ_REALZ(seq) ){ XtUnrealizeWidget(seq->wtop); NI_sleep(1); }
9067 seq->valid = 1 ;
9068 RETURN( True );
9069 }
9070 break ;
9071
9072 /*------- realize! -------*/
9073
9074 case isqDR_realize:{
9075 if( ! ISQ_REALZ(seq) ){
9076 XtRealizeWidget( seq->wtop ) ; NI_sleep(1) ;
9077 WAIT_for_window( seq->wtop ) ;
9078 NORMAL_cursorize( seq->wtop ) ;
9079 POPUP_cursorize( seq->wimage ) ;
9080 POPUP_cursorize( seq->wbar ) ;
9081 POPUP_cursorize( seq->wbut_bot[NBUT_SAVE] ) ;
9082 POPUP_cursorize( seq->crop_drag_pb ) ;
9083 XmUpdateDisplay( seq->wtop ) ;
9084 }
9085 #ifndef DONT_ONOFF_ONE
9086 if( seq->status->num_total == 1 ) /* 08 Aug 2001 */
9087 drive_MCW_imseq( seq , isqDR_onoffwid , (XtPointer) isqDR_offwid ) ;
9088 #endif
9089 ALLOW_CLIPPING( seq , (0.0f < seq->top_clip) ) ;
9090 seq->valid = 2 ;
9091 RETURN( True );
9092 }
9093 break ;
9094
9095 /*------- change helptext! -------*/
9096
9097 case isqDR_imhelptext:{
9098 char *newtxt = (char *) drive_data ;
9099 int ii ;
9100
9101 if( newtxt == NULL ) RETURN( False );
9102 ii = strlen(newtxt) ;
9103 if( ii == 0 ) RETURN( False );
9104
9105 strncpy( seq->im_helptext , newtxt , ISQ_NHELP ) ;
9106 seq->im_helptext[ISQ_NHELP] = '\0' ;
9107 RETURN( True );
9108 }
9109 break ;
9110
9111 /*------- display anew! -------*/
9112
9113 case isqDR_reimage:
9114 case isqDR_reshow:
9115 case isqDR_overlay:
9116 case isqDR_display:{
9117 int n = PTOI(drive_data) ;
9118
9119 if( ! seq->ignore_redraws )
9120 ISQ_redisplay( seq , n , drive_code ) ;
9121 RETURN( True );
9122 }
9123 break ;
9124
9125 /*------- display bar anew [23 Aug 1998] -------*/
9126
9127 case isqDR_rebar:{
9128 KILL_2XIM( seq->given_xbar , seq->sized_xbar ) ; /* destroy old */
9129 if( seq->onoff_state ) ISQ_show_bar( seq ) ; /* show new? */
9130 RETURN( True );
9131 }
9132 break ;
9133
9134 /*------- new cursor for image -------*/
9135
9136 case isqDR_cursor:{
9137 int cur = PTOI(drive_data) ;
9138
9139 MCW_alter_widget_cursor( seq->wimage , cur , "yellow" , "blue" ) ;
9140 RETURN( True );
9141 }
9142 break ;
9143
9144 /*------- new options -------*/
9145
9146 case isqDR_options:{
9147 ISQ_options *newopt = (ISQ_options *) drive_data ;
9148 int sf=0 ;
9149
9150 if( ppmto_num > 0 ) /* 27 Mar 2002: keep the old */
9151 sf = seq->opt.save_filter ; /* save filter */
9152
9153 if( newopt != NULL ) seq->opt = *newopt ;
9154
9155 if( ppmto_num > 0 )
9156 seq->opt.save_filter = sf ;
9157
9158 seq->opt.parent = (XtPointer) seq ;
9159 SET_SAVE_LABEL(seq) ;
9160 AV_SENSITIZE(seq->ov_opacity_av,!seq->opt.no_overlay) ; /* 09 Mar 2001 */
9161
9162
9163 if( ISQ_REALZ(seq) ) ISQ_redisplay( seq , -1 , isqDR_display ) ;
9164 RETURN( True );
9165 }
9166 break ;
9167
9168 /*------- get current options [07 Aug 1999] -------*/
9169
9170 case isqDR_getoptions:{
9171 ISQ_options *opt = (ISQ_options *) drive_data ;
9172
9173 if( opt == NULL ) RETURN( False );
9174 *opt = seq->opt ;
9175 RETURN( True );
9176 }
9177
9178 /*------- turn arrowpad on -------*/
9179
9180 case isqDR_arrowpadon:{
9181 char *helptext = (char *) drive_data ;
9182
9183 XtSetMappedWhenManaged( seq->arrowpad->wform , True ); /* on */
9184
9185 if( helptext != NULL && strlen(helptext) > 0 ){
9186 char *str = XtNewString( helptext ) ;
9187 MCW_reghelp_children( seq->arrowpad->wform , str ) ;
9188 XtFree(str) ; /* 28 Sep 1998: via Purify */
9189 }
9190 RETURN( True );
9191 }
9192 break ;
9193
9194 case isqDR_arrowpadhint:{
9195 int ib ;
9196 char ** hint = (char **) drive_data ;
9197 if( hint == NULL ) RETURN( False );
9198 for( ib=0 ; ib < 5 ; ib++ )
9199 MCW_register_hint( seq->arrowpad->wbut[ib] , hint[ib] ) ;
9200 RETURN( True );
9201 }
9202 break ;
9203
9204 /*------- turn arrowpad off -------*/
9205
9206 case isqDR_arrowpadoff:{
9207 XtSetMappedWhenManaged( seq->arrowpad->wform , False ); /* off */
9208 RETURN( True );
9209 }
9210 break ;
9211
9212 /*------- new numtotal -------*/
9213
9214 #if 0 /* 29 Jul 2002: removed from the canon for unuse */
9215 case isqDR_numtotal:{
9216 int newtot = (int) drive_data ,
9217 oldtot = seq->status->num_total ,
9218 numser = seq->status->num_series , ii ;
9219 char *msg =
9220 "illegal change to image\n"
9221 "count from driver routine\n"
9222 "(press here to continue)" ;
9223
9224 /* check for error conditions */
9225
9226 if( newtot == oldtot ) RETURN( True );
9227
9228 if( newtot < 2 || newtot < numser ){
9229 if( ISQ_REALZ(seq) )
9230 MCW_popup_message( seq->wimage , msg , MCW_USER_KILL ) ;
9231 fprintf(stderr,"\n%s\n",msg) ;
9232 RETURN( False );
9233 }
9234
9235 /* stop the automatic statistics calculations, if started */
9236
9237 #ifdef AUTOMATE_STATISTICS /* no longer allowed */
9238 if( seq->glstat->worker != 0 ){
9239 XtRemoveWorkProc( seq->glstat->worker ) ;
9240 seq->glstat->worker = 0 ;
9241 }
9242 #endif
9243
9244 /* setup new space for the per image statistics */
9245
9246 seq->imstat = (ISQ_indiv_statistics *)
9247 XtRealloc( (char *) seq->imstat ,
9248 sizeof(ISQ_indiv_statistics) * newtot ) ;
9249
9250 for( ii=oldtot ; ii < newtot ; ii++ )
9251 seq->imstat[ii].one_done = seq->imstat[ii].glob_done = False ;
9252
9253 /* let the imseq know that the number of images is different */
9254
9255 seq->status->num_total = newtot ;
9256
9257 XtVaSetValues( seq->wscale ,
9258 XmNmaximum , newtot-1 ,
9259 NULL ) ;
9260
9261 if( seq->im_nr >= newtot )
9262 ISQ_redisplay( seq , newtot-1 , isqDR_display ) ;
9263
9264 RETURN( True );
9265 }
9266 break ;
9267 #endif
9268
9269 /*------- new image sequence!!! -------*/
9270
9271 case isqDR_newseq:{
9272 RwcBoolean good ;
9273 ISQ_timer_stop(seq) ;
9274 good = ISQ_setup_new( seq , drive_data ) ;
9275 RETURN( good );
9276 }
9277 break ;
9278
9279 /*------ re-initialize image statistics -----*/
9280
9281 case isqDR_clearstat:{
9282 int ii ;
9283
9284 seq->opt.scale_group = ISQ_SCL_AUTO ; /* autoscaling */
9285 ISQ_disp_options( seq , False ) ; /* set buttons */
9286
9287 #ifdef AUTOMATE_STATISTICS /* no longer allowed */
9288 if( seq->glstat->worker != 0 ){ /* remove work process */
9289 XtRemoveWorkProc( seq->glstat->worker ) ;
9290 seq->glstat->worker = 0 ;
9291 }
9292 #endif
9293
9294 for( ii=0 ; ii < seq->status->num_total ; ii++ )
9295 seq->imstat[ii].one_done = seq->imstat[ii].glob_done = False ;
9296
9297 for( ii=0 ; ii < NHISTOG ; ii++ )
9298 seq->glstat->hist[ii] = 0 ; /* initialize histogram */
9299
9300 seq->glstat->mm_done =
9301 seq->glstat->per_done = (seq->status->num_series < 2 ) ;
9302
9303 #ifdef AUTOMATE_STATISTICS
9304 if( seq->glstat->mm_done ){
9305 seq->glstat->worker = 0 ;
9306 } else {
9307 seq->glstat->worker = XtAppAddWorkProc(
9308 seq->dc->appcontext ,
9309 ISQ_statistics_WP , seq ) ;
9310 }
9311 #else
9312 seq->glstat->worker = 0 ;
9313 #endif
9314 }
9315 break ;
9316
9317 } /* end of switch on drive_code */
9318
9319 RETURN( False ); /* should never be reached! */
9320 }
9321
9322 /*---------------------------------------------------------------------*/
9323
9324 #define XYORG 128
9325 #define DXY 64
9326
ISQ_arrowpad_CB(MCW_arrowpad * apad,XtPointer client_data)9327 void ISQ_arrowpad_CB( MCW_arrowpad *apad , XtPointer client_data )
9328 {
9329 MCW_imseq *seq = (MCW_imseq *) client_data ;
9330
9331 ISQ_cbs cbs ;
9332 int xorg,yorg , xwin,ywin , xoff,yoff ;
9333
9334 ENTRY("ISQ_arrowpad_CB") ;
9335
9336 if( ! ISQ_REALZ(seq) || seq->status->send_CB == NULL ) EXRETURN ;
9337
9338 cbs.event = &(apad->xev) ; /* copy event for user's edification */
9339
9340 if( apad->which_pressed == AP_MID ){
9341 cbs.reason = isqCR_appress ;
9342 #if 0
9343 seq->status->send_CB( seq , seq->getaux , &cbs ) ;
9344 #else
9345 SEND(seq,cbs) ;
9346 #endif
9347 EXRETURN ;
9348 }
9349
9350 /* 24 Jan 2003: pan a zoomed image */
9351
9352 if( seq->zoom_button1 && seq->zoom_fac > 1 && seq->zoom_xim != NULL ){
9353 switch( apad->which_pressed ){
9354 default:
9355 case AP_DOWN: xoff = 0 ; yoff = -1 ; break ;
9356 case AP_UP: xoff = 0 ; yoff = 1 ; break ;
9357 case AP_LEFT: xoff = 1 ; yoff = 0 ; break ;
9358 case AP_RIGHT: xoff = -1 ; yoff = 0 ; break ;
9359 }
9360 ISQ_actually_pan( seq , xoff , yoff ) ;
9361 EXRETURN ;
9362 }
9363
9364 xwin = ywin = XYORG ;
9365
9366 switch( apad->which_pressed ){
9367 default:
9368 case AP_DOWN: ywin = XYORG + DXY ; break ;
9369 case AP_UP: ywin = XYORG - DXY ; break ;
9370 case AP_LEFT: xwin = XYORG - DXY ; break ;
9371 case AP_RIGHT: xwin = XYORG + DXY ; break ;
9372 }
9373
9374 xorg = yorg = XYORG ; ISQ_flipxy( seq , &xorg,&yorg ) ;
9375 xoff = xwin ; yoff = ywin ; ISQ_flipxy( seq , &xoff,&yoff ) ;
9376
9377 if( xoff > xorg ) cbs.reason = isqCR_dxplus ;
9378 else if( xoff < xorg ) cbs.reason = isqCR_dxminus ;
9379 else if( yoff > yorg ) cbs.reason = isqCR_dyplus ;
9380 else if( yoff < yorg ) cbs.reason = isqCR_dyminus ;
9381 else EXRETURN ; /* error! */
9382
9383 #if 0
9384 seq->status->send_CB( seq , seq->getaux , &cbs ) ;
9385 #else
9386 SEND(seq,cbs) ;
9387 #endif
9388 EXRETURN ;
9389 }
9390
9391 /*-------------------------------------------------------------------
9392 Setup the data structures to handle a new sequence of images;
9393 this should be immediately followed by a call to set the image
9394 to the correct number (or things won't look good at all).
9395 ---------------------------------------------------------------------*/
9396
ISQ_setup_new(MCW_imseq * seq,XtPointer newaux)9397 RwcBoolean ISQ_setup_new( MCW_imseq *seq , XtPointer newaux )
9398 {
9399 MCW_imseq_status *imstatus=NULL ;
9400 int ii ;
9401 MRI_IMAGE *tim ;
9402
9403 ENTRY("ISQ_setup_new") ;
9404
9405 if( !ISQ_VALID(seq) ) RETURN( False );
9406
9407 #if 0
9408 imstatus = (MCW_imseq_status *)seq->getim(0,isqCR_getstatus,newaux);
9409 #else
9410 AFNI_CALL_VALU_3ARG( seq->getim , MCW_imseq_status *,imstatus ,
9411 int,0 , int,isqCR_getstatus , XtPointer,newaux ) ;
9412 #endif
9413 if( imstatus->num_total < 1 ){ RETURN( False ); } /* 09 Feb 1999: allow 1 */
9414
9415 #if 0
9416 tim = (MRI_IMAGE *) seq->getim(0,isqCR_getqimage,newaux) ; /* 1st image */
9417 KILL_1MRI(tim) ; /* don't need tim no more */
9418 #endif
9419
9420 #if 1
9421 if( seq->status != NULL ) myXtFree(seq->status) ; /* 05 Feb 2000 */
9422 #endif
9423
9424 seq->status = imstatus ;
9425 seq->im_nr = imstatus->num_total / 2 ; /* do this image 1st */
9426
9427 KILL_1MRI(seq->imim) ; /* NULL out all internally stored images */
9428 KILL_1MRI(seq->ovim) ;
9429 KILL_1MRI(seq->orim) ; /* 09 Feb 1999 */
9430
9431 KILL_2XIM( seq->given_xim , seq->sized_xim ) ;
9432 KILL_2XIM( seq->given_xbar , seq->sized_xbar ) ;
9433
9434 seq->given_xim = seq->sized_xim
9435 = seq->given_xbar
9436 = seq->sized_xbar = NULL ;
9437
9438 seq->imim = seq->ovim = NULL ;
9439
9440 /* re-initialize image statistics */
9441
9442 seq->opt.scale_group = ISQ_SCL_AUTO ;
9443 ISQ_disp_options( seq , False ) ; /* set toggles from option list */
9444
9445 seq->imstat = (ISQ_indiv_statistics *)
9446 XtRealloc( (char *) seq->imstat ,
9447 sizeof(ISQ_indiv_statistics)
9448 * imstatus->num_total ) ;
9449
9450 #ifdef AUTOMATE_STATISTICS /* no longer allowed */
9451 if( seq->glstat->worker != 0 ){ /* remove work process, if started */
9452 XtRemoveWorkProc( seq->glstat->worker ) ;
9453 seq->glstat->worker = 0 ;
9454 }
9455 #endif
9456
9457 for( ii=0 ; ii < imstatus->num_total ; ii++ ){
9458 seq->imstat[ii].one_done = seq->imstat[ii].glob_done = False ;
9459 seq->imstat[ii].parent = (XtPointer) seq ;
9460 }
9461 seq->glstat->parent = (XtPointer) seq ;
9462
9463 for( ii=0 ; ii < NHISTOG ; ii++ )
9464 seq->glstat->hist[ii] = 0 ; /* initialize histogram */
9465
9466 seq->glstat->mm_done =
9467 seq->glstat->per_done = (seq->status->num_series < 2 ) ;
9468
9469 #ifdef AUTOMATE_STATISTICS
9470 if( seq->glstat->mm_done ){
9471 seq->glstat->worker = 0 ;
9472 } else {
9473 seq->glstat->worker = XtAppAddWorkProc(
9474 seq->dc->appcontext ,
9475 ISQ_statistics_WP , seq ) ;
9476 }
9477 #else
9478 seq->glstat->worker = 0 ;
9479 #endif
9480
9481 /* OOPS! I forgot to reset the scale max value! */
9482
9483 ii = seq->status->num_total - 1 ; if( ii <= 0 ) ii = 1 ; /* 09 Feb 1999 */
9484
9485 XtVaSetValues( seq->wscale ,
9486 XmNmaximum , ii ,
9487 XmNvalue , seq->im_nr ,
9488 NULL ) ;
9489
9490 #ifndef DONT_ONOFF_ONE
9491 if( seq->status->num_total == 1 )
9492 drive_MCW_imseq( seq , isqDR_onoffwid , (XtPointer) isqDR_offwid ) ;
9493 #endif
9494
9495 if(PRINT_TRACING){
9496 char str[256] ;
9497 sprintf(str,"hbase=%d vbase=%d nim=%d lev=%g",
9498 seq->hbase,seq->vbase, seq->status->num_total,seq->lev ) ;
9499 STATUS(str) ;
9500 }
9501
9502 seq->getaux = newaux ;
9503
9504 seq->top_clip = 0.0f ; /* 17 Sep 2007 */
9505 if( seq->opt.scale_range == ISQ_RNG_CLIPPED ) seq->redo_clip = 1 ;
9506 ALLOW_CLIPPING(seq,0) ;
9507
9508 RETURN( True ) ;
9509 }
9510
9511 /*----------------------------------------------------------------------------*/
9512 /*---- Stuff for the menu hidden on the color bar ----*/
9513
ISQ_wbar_plots_CB(Widget w,XtPointer cld,XtPointer cad)9514 void ISQ_wbar_plots_CB( Widget w , XtPointer cld , XtPointer cad ) /* 20 Sep 2001 */
9515 {
9516 MCW_imseq *seq = (MCW_imseq *) cld ;
9517 ENTRY("ISQ_wbar_plots_CB") ;
9518 if( ISQ_REALZ(seq) ) ISQ_redisplay( seq , -1 , isqDR_display ) ;
9519 EXRETURN ;
9520 }
9521
9522 /*----------------------------------------------------------------------------*/
9523
ISQ_wbar_amask_CB(Widget w,XtPointer client_data,XtPointer call_data)9524 void ISQ_wbar_amask_CB( Widget w, XtPointer client_data, XtPointer call_data )
9525 {
9526 MCW_imseq *seq = (MCW_imseq *)client_data ; /* 14 Jun 2010 */
9527 ENTRY("ISQ_wbar_amask_CB") ;
9528 KILL_1MRI(seq->last_automask) ;
9529 if( ISQ_REALZ(seq) ) ISQ_redisplay( seq , -1 , isqDR_display ) ;
9530 EXRETURN ;
9531 }
9532
9533 /*----------------------------------------------------------------------------*/
9534
ISQ_wbar_invrt_CB(Widget w,XtPointer client_data,XtPointer call_data)9535 void ISQ_wbar_invrt_CB( Widget w, XtPointer client_data, XtPointer call_data )
9536 {
9537 MCW_imseq *seq = (MCW_imseq *)client_data ; /* 14 Jun 2010 */
9538 ENTRY("ISQ_wbar_invrt_CB") ;
9539 if( ISQ_REALZ(seq) ) ISQ_redisplay( seq , -1 , isqDR_display ) ;
9540 EXRETURN ;
9541 }
9542
9543 /*----------------------------------------------------------------------------*/
9544
ISQ_wbar_crop_CB(Widget w,XtPointer client_data,XtPointer call_data)9545 void ISQ_wbar_crop_CB( Widget w, XtPointer client_data, XtPointer call_data )
9546 {
9547 MCW_imseq *seq = (MCW_imseq *)client_data ; /* 14 Jun 2010 */
9548 ENTRY("ISQ_wbar_crop_CB") ;
9549 if( ISQ_REALZ(seq) ){
9550 seq->crop_autocenter = MCW_val_bbox(seq->wbar_crop_bbox) ;
9551 ISQ_redisplay( seq , -1 , isqDR_display ) ;
9552 }
9553 EXRETURN ;
9554 }
9555
9556 /*----------------------------------------------------------------------*/
9557
ISQ_wbar_label_CB(MCW_arrowval * av,XtPointer cd)9558 void ISQ_wbar_label_CB( MCW_arrowval *av , XtPointer cd )
9559 {
9560 MCW_imseq *seq = (MCW_imseq *)cd ;
9561
9562 ENTRY("ISQ_wbar_label_CB") ;
9563
9564 if( !ISQ_REALZ(seq) ) EXRETURN ;
9565
9566 if( av == seq->wbar_animdup_av )
9567 ISQ_anim_dup = av->ival; /* 10 Feb 2009 */
9568 else
9569 ISQ_redisplay( seq , -1 , isqDR_display ) ;
9570
9571 EXRETURN ;
9572 }
9573
9574 #if 1
ISQ_wbar_globrange_CB(MCW_arrowval * av,XtPointer cd)9575 void ISQ_wbar_globrange_CB( MCW_arrowval *av , XtPointer cd )
9576 {
9577 MCW_imseq *seq = (MCW_imseq *)cd ;
9578 ISQ_cbs cbs ;
9579
9580 ENTRY("ISQ_wbar_globrange_CB") ;
9581
9582 if( !ISQ_REALZ(seq) ) EXRETURN ;
9583
9584 THD_set_image_globalrange(av->ival);
9585 cbs.reason = isqCR_resetglobalrange ;
9586 /* cbs.key = ii ;*/ /* number of points */
9587
9588 SEND(seq,cbs) ; /* send this back to a callback function now in afni.c
9589 imseq doesn't have access directly to dataset info */
9590
9591 /* THD_set_image_globalrange_env(av->ival);*/
9592
9593 EXRETURN ;
9594 }
9595 #endif
9596
9597
9598 /*----------------------------------------------------------------------*/
9599 /* Finalize the overlay label append string [23 Dec 2011] */
9600
ISQ_overlay_label_CB(Widget w,XtPointer fd,MCW_choose_cbs * cbs)9601 void ISQ_overlay_label_CB( Widget w , XtPointer fd , MCW_choose_cbs *cbs )
9602 {
9603 MCW_imseq *seq = (MCW_imseq *)fd ;
9604 ENTRY("ISQ_overlay_label_CB") ;
9605 if( seq->overlay_label != NULL ){
9606 free(seq->overlay_label) ; seq->overlay_label = NULL ;
9607 }
9608 if( cbs != NULL && cbs->reason == mcwCR_string &&
9609 cbs->cval != NULL && strcasecmp(cbs->cval,"NULL") != 0 ){
9610 seq->overlay_label = strdup(cbs->cval) ;
9611 }
9612 ISQ_redisplay( seq , -1 , isqDR_display ) ;
9613 EXRETURN ;
9614 }
9615
9616 /*----------------------------------------------------------------------*/
9617
ISQ_wbar_menu_CB(Widget w,XtPointer client_data,XtPointer call_data)9618 void ISQ_wbar_menu_CB( Widget w , XtPointer client_data ,
9619 XtPointer call_data )
9620 {
9621 MCW_imseq *seq = (MCW_imseq *) client_data ;
9622
9623 ENTRY("ISQ_wbar_menu_CB") ;
9624
9625 if( ! ISQ_REALZ(seq) ) EXRETURN ;
9626
9627 /*** User range toggle ***/
9628
9629 if( w == seq->wbar_rng_but ){
9630 MCW_choose_string( seq->wimage , "Display range: bot top [ztop]" ,
9631 NULL , ISQ_set_rng_CB , seq ) ;
9632 }
9633
9634 else if( w == seq->wbar_zer_but ){
9635 MCW_choose_ovcolor( seq->wimage , seq->dc , seq->zer_color ,
9636 ISQ_set_zcol_CB , seq ) ;
9637 }
9638
9639 else if( w == seq->wbar_flat_but ){
9640 MCW_choose_string( seq->wimage , "Flatten range: bot top" ,
9641 NULL , ISQ_set_flat_CB , seq ) ;
9642 }
9643
9644 else if( w == seq->wbar_sharp_but ){
9645 MCW_choose_integer( seq->wimage , "Sharpen Factor" ,
9646 1 , 9 , (int)(10.01*seq->sharp_fac) ,
9647 ISQ_set_sharp_CB , seq ) ;
9648 }
9649
9650 else if( w == seq->wbar_vgize_but ){
9651 MCW_choose_integer( seq->wimage , "VG Factor" ,
9652 1 , 9 , VGFAC_TO_INDEX(seq->vgize_fac) ,
9653 ISQ_set_vgize_CB , seq ) ;
9654 }
9655
9656 else if( w == seq->wbar_graymap_pb ){ /* 24 Oct 2003 */
9657 ISQ_graymap_draw( seq ) ;
9658 }
9659
9660 else if( w == seq->wbar_labst_pb ){ /* 23 Dec 2011 */
9661 MCW_choose_string( w , "Overlay Label Append String" ,
9662 seq->overlay_label , ISQ_overlay_label_CB , seq ) ;
9663 }
9664
9665 EXRETURN ;
9666 }
9667
9668 /*----------------------------------------------------------------------*/
9669
ISQ_set_rng_CB(Widget w,XtPointer cd,MCW_choose_cbs * cbs)9670 void ISQ_set_rng_CB( Widget w , XtPointer cd , MCW_choose_cbs *cbs )
9671 {
9672 MCW_imseq *seq = (MCW_imseq *) cd ;
9673
9674 ENTRY("ISQ_set_rng_CB") ;
9675
9676 if( ! ISQ_REALZ(seq) || w == NULL || ! XtIsWidget(w) ) EXRETURN ;
9677
9678 seq->rng_bot = seq->rng_top = seq->rng_ztop = 0.0 ;
9679 seq->rng_extern = 0 ;
9680 sscanf( cbs->cval , "%f%f%f" ,
9681 &(seq->rng_bot) , &(seq->rng_top) , &(seq->rng_ztop) ) ;
9682 ISQ_redisplay( seq , -1 , isqDR_reimage ) ; /* redo current image */
9683 EXRETURN ;
9684 }
9685
9686 /*----------------------------------------------------------------------*/
9687
ISQ_set_zcol_CB(Widget w,XtPointer cd,MCW_choose_cbs * cbs)9688 void ISQ_set_zcol_CB( Widget w , XtPointer cd , MCW_choose_cbs *cbs )
9689 {
9690 MCW_imseq *seq = (MCW_imseq *) cd ;
9691
9692 ENTRY("ISQ_set_zcol_CB") ;
9693
9694 if( ! ISQ_REALZ(seq) || w == NULL || ! XtIsWidget(w) ) EXRETURN ;
9695
9696 seq->zer_color = cbs->ival ;
9697 ISQ_redisplay( seq , -1 , isqDR_reimage ) ; /* redo current image */
9698 EXRETURN ;
9699 }
9700
9701 /*----------------------------------------------------------------------*/
9702
ISQ_set_flat_CB(Widget w,XtPointer cd,MCW_choose_cbs * cbs)9703 void ISQ_set_flat_CB( Widget w , XtPointer cd , MCW_choose_cbs *cbs )
9704 {
9705 MCW_imseq *seq = (MCW_imseq *) cd ;
9706
9707 ENTRY("ISQ_set_flat_CB") ;
9708
9709 if( ! ISQ_REALZ(seq) || w == NULL || ! XtIsWidget(w) ) EXRETURN ;
9710
9711 seq->flat_bot = seq->flat_top = 0.0 ;
9712 sscanf( cbs->cval , "%f%f" ,
9713 &(seq->flat_bot) , &(seq->flat_top) ) ;
9714
9715 if( seq->flat_bot < 0.0 ) seq->flat_bot = 0.0 ;
9716 if( seq->flat_bot > 1.0 ) seq->flat_bot*= 0.01 ;
9717 if( seq->flat_top < 0.0 ) seq->flat_top = 0.0 ;
9718 if( seq->flat_top > 1.0 ) seq->flat_top*= 0.01 ;
9719
9720 if( seq->flat_bot >= seq->flat_top || seq->flat_top > 1.0 )
9721 seq->flat_bot = seq->flat_top = 0.0 ;
9722
9723 ISQ_redisplay( seq , -1 , isqDR_reimage ) ; /* redo current image */
9724 EXRETURN ;
9725 }
9726
9727 /*----------------------------------------------------------------------*/
9728
ISQ_set_sharp_CB(Widget w,XtPointer cd,MCW_choose_cbs * cbs)9729 void ISQ_set_sharp_CB( Widget w , XtPointer cd , MCW_choose_cbs *cbs )
9730 {
9731 MCW_imseq *seq = (MCW_imseq *) cd ;
9732
9733 ENTRY("ISQ_set_sharp_CB") ;
9734
9735 if( ! ISQ_REALZ(seq) || w == NULL || ! XtIsWidget(w) ) EXRETURN ;
9736
9737 seq->sharp_fac = 0.1 * cbs->ival ;
9738
9739 ISQ_redisplay( seq , -1 , isqDR_reimage ) ; /* redo current image */
9740 EXRETURN ;
9741 }
9742
9743 /*----------------------------------------------------------------------*/
9744
ISQ_set_vgize_CB(Widget w,XtPointer cd,MCW_choose_cbs * cbs)9745 void ISQ_set_vgize_CB( Widget w , XtPointer cd , MCW_choose_cbs *cbs )
9746 {
9747 MCW_imseq *seq = (MCW_imseq *) cd ;
9748
9749 ENTRY("ISQ_set_vgize_CB") ;
9750
9751 if( ! ISQ_REALZ(seq) || w == NULL || ! XtIsWidget(w) ) EXRETURN ;
9752
9753 seq->vgize_fac = INDEX_TO_VGFAC(cbs->ival) ;
9754
9755 ISQ_redisplay( seq , -1 , isqDR_reimage ) ; /* redo current image */
9756 EXRETURN ;
9757 }
9758
9759 /*----------------------------------------------------------------------------
9760 April 1996: Routines to process the montage stuff
9761 ------------------------------------------------------------------------------*/
9762
9763 #define MONT_quit_label "Quit"
9764 #define MONT_1x1_label "1x1"
9765 #define MONT_apply_label "Draw"
9766 #define MONT_done_label "Set"
9767
9768 #define MONT_quit_help "Press to close\nthis control box"
9769 #define MONT_1x1_help "Press to set the controls\nto Across=1 and Down=1"
9770 #define MONT_apply_help "Press to apply this choice\nand keep this control box"
9771 #define MONT_done_help "Press to apply this choice\nand close this control box"
9772
9773 #define NUM_MONT_ACT 4
9774
9775 static MCW_action_item MONT_act[NUM_MONT_ACT] = {
9776 { MONT_quit_label , ISQ_montage_action_CB, NULL, MONT_quit_help ,"Close window" ,0 },
9777 { MONT_1x1_label , ISQ_montage_action_CB, NULL, MONT_1x1_help ,"Set Across=Down=1" ,0 },
9778 { MONT_apply_label, ISQ_montage_action_CB, NULL, MONT_apply_help,"Apply choice and keep window" ,0 },
9779 { MONT_done_label , ISQ_montage_action_CB, NULL, MONT_done_help ,"Apply choice and close window",1 },
9780 } ;
9781
9782 #define MONT_QUIT 0
9783 #define MONT_1X1 1
9784 #define MONT_APPLY 2
9785 #define MONT_DONE 3
9786
ISQ_montage_CB(Widget w,XtPointer client_data,XtPointer call_data)9787 void ISQ_montage_CB( Widget w, XtPointer client_data, XtPointer call_data )
9788 {
9789 MCW_imseq *seq = (MCW_imseq *) client_data ;
9790 int ib ;
9791 Widget wrc ;
9792
9793 ENTRY("ISQ_montage_CB") ;
9794
9795 if( ! ISQ_REALZ(seq) || seq->dialog != NULL ) EXRETURN ;
9796
9797 if( seq->zoom_fac != 1 ){
9798 #if 0
9799 fprintf(stderr,"montage: zoom_fac = %d\n",seq->zoom_fac) ;
9800 #endif
9801 /* XBell(seq->dc->display,100); */ EXRETURN; /* 18 Nov 2003 */
9802 }
9803
9804 for( ib=0 ; ib < NBUTTON_BOT-1 ; ib++ ) /* turn off buttons */
9805 if( ISQ_but_bot_dial[ib] == True ) /* that also want to */
9806 SENSITIZE( seq->wbut_bot[ib] , False ) ; /* use seq->dialog */
9807
9808 seq->dialog = XtVaCreatePopupShell(
9809 "menu" , xmDialogShellWidgetClass , seq->wtop ,
9810 XmNtitle , "Montage" ,
9811 XmNdeleteResponse , XmDO_NOTHING ,
9812 XmNinitialResourcesPersistent , False ,
9813 NULL ) ;
9814
9815 SAVEUNDERIZE(seq->dialog) ; /* 27 Feb 2001 */
9816
9817 DC_yokify( seq->dialog , seq->dc ) ; /* 14 Sep 1998 */
9818
9819 seq->dialog_starter = NBUT_MONT ;
9820
9821 #if 1
9822 if( MCW_isitmwm(w) )
9823 XtVaSetValues( seq->dialog ,
9824 XmNmwmDecorations , MWM_DECOR_BORDER ,
9825 XmNmwmFunctions , MWM_FUNC_MOVE
9826 | MWM_FUNC_CLOSE ,
9827 NULL ) ;
9828 #endif
9829
9830 XmAddWMProtocolCallback( /* make "Close" window menu work */
9831 seq->dialog ,
9832 XmInternAtom( seq->dc->display , "WM_DELETE_WINDOW" , False ) ,
9833 ISQ_montage_action_CB , seq ) ;
9834
9835 wrc = XtVaCreateWidget( /* RowColumn to hold all */
9836 "menu" , xmRowColumnWidgetClass , seq->dialog ,
9837 XmNpacking , XmPACK_TIGHT ,
9838 XmNorientation , XmVERTICAL ,
9839 XmNtraversalOn , False ,
9840 XmNinitialResourcesPersistent , False ,
9841 NULL ) ;
9842
9843 wwtem = XtVaCreateManagedWidget(
9844 "menu" , xmLabelWidgetClass , wrc ,
9845 LABEL_ARG("-- Montage Controls --") ,
9846 XmNalignment , XmALIGNMENT_CENTER ,
9847 XmNinitialResourcesPersistent , False ,
9848 NULL ) ; LABELIZE(wwtem) ;
9849
9850 (void) XtVaCreateManagedWidget(
9851 "menu" , xmSeparatorWidgetClass , wrc ,
9852 XmNseparatorType , XmSHADOW_ETCHED_IN ,
9853 XmNinitialResourcesPersistent , False ,
9854 NULL ) ;
9855
9856 seq->mont_across_av = new_MCW_arrowval(
9857 wrc , "Across:" ,
9858 MCW_AV_optmenu ,
9859 1 , MONT_NMAX , seq->mont_nx ,
9860 MCW_AV_edittext , 0 ,
9861 NULL , NULL , NULL , NULL ) ;
9862
9863 if( MONT_NMAX > COLSIZE )
9864 AVOPT_columnize( seq->mont_across_av , 1+(MONT_NMAX-1)/COLSIZE ) ;
9865
9866 if( seq->mont_across_av->wtext != NULL )
9867 XtVaSetValues( seq->mont_across_av->wtext , XmNcolumns , 4 , NULL ) ;
9868
9869 seq->mont_down_av = new_MCW_arrowval(
9870 wrc , "Down: " ,
9871 MCW_AV_optmenu ,
9872 1 , MONT_NMAX , seq->mont_ny ,
9873 MCW_AV_edittext , 0 ,
9874 NULL , NULL , NULL , NULL ) ;
9875
9876 if( MONT_NMAX > COLSIZE )
9877 AVOPT_columnize( seq->mont_down_av , 1+(MONT_NMAX-1)/COLSIZE ) ;
9878
9879 if( seq->mont_down_av->wtext != NULL )
9880 XtVaSetValues( seq->mont_down_av->wtext , XmNcolumns , 4 , NULL ) ;
9881
9882 seq->mont_skip_av = new_MCW_arrowval(
9883 wrc , "Spacing" ,
9884 MCW_AV_optmenu ,
9885 1 , MONT_SMAX , seq->mont_skip + 1 ,
9886 MCW_AV_edittext , 0 ,
9887 NULL , NULL , NULL , NULL ) ;
9888
9889 if( MONT_SMAX > COLSIZE )
9890 AVOPT_columnize( seq->mont_skip_av , 1+(MONT_SMAX-1)/COLSIZE ) ;
9891
9892 if( seq->mont_skip_av->wtext != NULL )
9893 XtVaSetValues( seq->mont_skip_av->wtext , XmNcolumns , 4 , NULL ) ;
9894
9895 seq->mont_gap_av = new_MCW_arrowval(
9896 wrc , "Border:" ,
9897 MCW_AV_optmenu ,
9898 0 , MONT_GMAX , seq->mont_gap,
9899 MCW_AV_edittext , 0 ,
9900 NULL , NULL , NULL , NULL ) ;
9901
9902 if( MONT_GMAX > COLSIZE )
9903 AVOPT_columnize( seq->mont_gap_av , 1+(MONT_GMAX-1)/COLSIZE ) ;
9904
9905 if( seq->mont_gap_av->wtext != NULL )
9906 XtVaSetValues( seq->mont_gap_av->wtext , XmNcolumns , 4 , NULL ) ;
9907
9908 seq->mont_gapcolor_av = new_MCW_colormenu( wrc ,
9909 "Color: " , seq->dc ,
9910 0 , seq->dc->ovc->ncol_ov - 1 , seq->mont_gapcolor ,
9911 NULL , NULL ) ;
9912
9913 if( AFNI_yesenv("TMONT") ){
9914 seq->mont_type_av = new_MCW_arrowval(
9915 wrc , "Type: " ,
9916 MCW_AV_optmenu ,
9917 0 , MONT_LAST_TYPE , seq->mont_mode,
9918 MCW_AV_edittext , 0 ,
9919 NULL , NULL , MCW_av_substring_CB , mont_types ) ;
9920 MCW_reghint_children( seq->mont_across_av->wrowcol ,
9921 "Spatial or Temporal montage?" ) ;
9922 } else {
9923 seq->mont_type_av = NULL ;
9924 }
9925
9926 #if 0
9927 seq->mont_across_av->allow_wrap = 1 ; /* allow wrap at limits of values */
9928 seq->mont_down_av->allow_wrap = 1 ;
9929 seq->mont_skip_av->allow_wrap = 1 ;
9930 seq->mont_gap_av->allow_wrap = 1 ;
9931 seq->mont_gapcolor_av->allow_wrap = 1 ;
9932
9933 seq->mont_across_av->fastdelay = 250 ; /* slow down arrow repeat action */
9934 seq->mont_down_av->fastdelay = 250 ;
9935 seq->mont_skip_av->fastdelay = 250 ;
9936 seq->mont_gap_av->fastdelay = 250 ;
9937 seq->mont_gapcolor_av->fastdelay = 250 ;
9938 #endif
9939
9940 seq->mont_nx_old = seq->mont_nx ; /* in case something is changed */
9941 seq->mont_ny_old = seq->mont_ny ;
9942 seq->mont_skip_old = seq->mont_skip ;
9943 seq->mont_gap_old = seq->mont_gap ;
9944 seq->mont_gapcolor_old = seq->mont_gapcolor ;
9945 seq->mont_mode_old = seq->mont_mode ;
9946
9947 MCW_reghelp_children( seq->mont_across_av->wrowcol ,
9948 "This controls the number\n"
9949 "of images displayed across\n"
9950 "(horizontally) the window."
9951 ) ;
9952 MCW_reghint_children( seq->mont_across_av->wrowcol ,
9953 "Number of images horizontal" ) ;
9954
9955 MCW_reghelp_children( seq->mont_down_av->wrowcol ,
9956 "This controls the number\n"
9957 "of images displayed down\n"
9958 "(vertically) the window."
9959 ) ;
9960 MCW_reghint_children( seq->mont_down_av->wrowcol ,
9961 "Number of images vertical" ) ;
9962
9963 MCW_reghelp_children( seq->mont_skip_av->wrowcol ,
9964 "This controls the spacing between\n"
9965 "slice images displayed in the\n"
9966 "montage. For example, if Spacing\n"
9967 "is 4, every fourth slice will be\n"
9968 "displayed (from left to right, then\n"
9969 "top to bottom)."
9970 ) ;
9971 MCW_reghint_children( seq->mont_skip_av->wrowcol ,
9972 "Spacing between images" ) ;
9973
9974 MCW_reghelp_children( seq->mont_gap_av->wrowcol ,
9975 "This controls the number\n"
9976 "of pixels left as borders\n"
9977 "between the sub-images"
9978 ) ;
9979 MCW_reghint_children( seq->mont_gap_av->wrowcol ,
9980 "Borders between images" ) ;
9981
9982 MCW_reghelp_children( seq->mont_gapcolor_av->wrowcol ,
9983 "This controls the color\n"
9984 "put in the borders between\n"
9985 "the sub-images"
9986 ) ;
9987 MCW_reghint_children( seq->mont_gapcolor_av->wrowcol ,
9988 "Border color" ) ;
9989
9990 for( ib=0 ; ib < NUM_MONT_ACT ; ib++ )
9991 MONT_act[ib].data = (XtPointer) seq ;
9992
9993 (void) MCW_action_area( wrc , MONT_act , NUM_MONT_ACT ) ;
9994
9995 XtManageChild( wrc ) ;
9996 ISQ_place_dialog( seq ) ; /* 05 Jan 1999 */
9997 XtPopup( seq->dialog , XtGrabNone ) ; NI_sleep(1);
9998 NORMAL_cursorize( seq->dialog ) ;
9999 ISQ_but_done_reset( seq ) ;
10000 EXRETURN ;
10001 }
10002
10003 /*----------------------------------------------------------------------------*/
10004
ISQ_montage_action_CB(Widget w,XtPointer client_data,XtPointer call_data)10005 void ISQ_montage_action_CB( Widget w , XtPointer client_data , XtPointer call_data )
10006 {
10007 MCW_imseq *seq = (MCW_imseq *) client_data ;
10008 XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *) call_data ;
10009 char *wname ;
10010 int ib , close_window , new_mont ;
10011
10012 ENTRY("ISQ_montage_action_CB") ;
10013
10014 if( !ISQ_REALZ(seq) || seq->dialog==NULL || seq->dialog_starter!=NBUT_MONT ) EXRETURN ;
10015
10016 wname = XtName(w) ;
10017
10018 for( ib=0 ; ib < NUM_MONT_ACT ; ib++ ) /* button index, if any */
10019 if( strcmp(wname,MONT_act[ib].label) == 0 ) break ;
10020
10021 close_window = (ib == MONT_DONE || ib == MONT_QUIT || ib == NUM_MONT_ACT) ;
10022
10023 if( close_window ){
10024 RWC_XtPopdown( seq->dialog ) ;
10025 XSync( XtDisplay(w) , False ) ;
10026 XmUpdateDisplay( w ) ;
10027 seq->dont_place_dialog = 1 ; /* 23 Jan 2004 */
10028 }
10029
10030 switch( ib ){
10031
10032 case MONT_APPLY:
10033 case MONT_DONE:
10034 seq->mont_nx = seq->mont_across_av->ival ;
10035 seq->mont_ny = seq->mont_down_av->ival ;
10036 seq->mont_skip = seq->mont_skip_av->ival - 1 ;
10037 seq->mont_gap = seq->mont_gap_av->ival ;
10038 seq->mont_gapcolor = seq->mont_gapcolor_av->ival ;
10039
10040 new_mont = ( seq->mont_nx != seq->mont_nx_old ||
10041 seq->mont_ny != seq->mont_ny_old ||
10042 seq->mont_skip != seq->mont_skip_old ) ;
10043
10044 if( seq->mont_type_av != NULL ){
10045 seq->mont_mode = seq->mont_type_av->ival ;
10046 new_mont = new_mont || (seq->mont_mode != seq->mont_mode_old) ;
10047 }
10048
10049 if( ib == MONT_APPLY ) MCW_invert_widget(w) ;
10050
10051 ISQ_redisplay( seq , -1 , isqDR_display ) ; /* local redraw */
10052
10053 if( seq->status->send_CB != NULL && new_mont ){
10054
10055 ISQ_cbs cbs ;
10056 THD_ivec3 minf ;
10057 int ijcen = (seq->mont_nx)/2 + (seq->mont_ny/2) * seq->mont_nx ,
10058 nmont = seq->mont_nx * seq->mont_ny ;
10059
10060 minf.ijk[0] = ijcen ; /* number of slices before center */
10061 minf.ijk[1] = nmont-ijcen-1 ; /* number after */
10062 minf.ijk[2] = seq->mont_skip ; /* number between slices */
10063 cbs.reason = isqCR_newmontage ;
10064 cbs.userdata = (XtPointer) &minf ;
10065
10066 seq->ignore_redraws = 1 ; /* don't listen to redraws */
10067 #if 0
10068 seq->status->send_CB( seq , seq->getaux , &cbs ) ;
10069 #else
10070 SEND(seq,cbs) ;
10071 #endif
10072 seq->ignore_redraws = 0 ; /* can listen again */
10073 }
10074
10075 #if 0
10076 ISQ_redisplay( seq , -1 , isqDR_display ) ; /* local redraw */
10077 #endif
10078
10079 if( ib == MONT_APPLY ) MCW_invert_widget(w) ;
10080
10081 seq->mont_nx_old = seq->mont_nx ;
10082 seq->mont_ny_old = seq->mont_ny ;
10083 seq->mont_skip_old = seq->mont_skip ;
10084 seq->mont_gap_old = seq->mont_gap ;
10085 seq->mont_gapcolor_old = seq->mont_gapcolor ;
10086
10087 /* set to "Save One" if have an actual montage going now */
10088
10089 if( seq->mont_nx * seq->mont_ny > 1 && !seq->opt.save_one ){
10090 seq->opt.save_one = 1 ;
10091 seq->opt.save_agif = 0 ; /* 27 Jul 2001 */
10092 seq->opt.save_mpeg = 0 ;
10093 SET_SAVE_LABEL(seq) ;
10094 }
10095 break ;
10096
10097 case MONT_1X1:
10098 MCW_invert_widget(w) ;
10099 AV_assign_ival( seq->mont_across_av , 1 ) ;
10100 AV_assign_ival( seq->mont_down_av , 1 ) ;
10101 MCW_invert_widget(w) ;
10102 break ;
10103 }
10104
10105 /*** done -- close the window if ordered ***/
10106
10107 if( close_window ){ /* close the window */
10108 XtDestroyWidget( seq->dialog ) ; NI_sleep(1) ;
10109 seq->dialog = NULL ;
10110 for( ib=0 ; ib < NBUTTON_BOT-1 ; ib++ ) /* turn buttons back on */
10111 if( ISQ_but_bot_dial[ib] == True ) /* that also want to */
10112 SENSITIZE( seq->wbut_bot[ib] , True ) ; /* use seq->dialog */
10113
10114 FREE_AV( seq->mont_across_av ) ;
10115 FREE_AV( seq->mont_down_av ) ;
10116 FREE_AV( seq->mont_skip_av ) ;
10117 FREE_AV( seq->mont_gap_av ) ;
10118 FREE_AV( seq->mont_gapcolor_av ) ;
10119 FREE_AV( seq->mont_type_av ) ;
10120
10121 seq->dialog_starter = -1 ;
10122 seq->dont_place_dialog = 0 ; /* 23 Jan 2004 */
10123 }
10124
10125 EXRETURN ;
10126 }
10127
10128 /*---------------------------------------------------------------------------
10129 Routine to get one image for the montage display.
10130 Output image is MRI_short (underlay or overlay index), or MRI_rgb.
10131 -----------------------------------------------------------------------------*/
10132
ISQ_manufacture_one(int nim,int overlay,MCW_imseq * seq)10133 MRI_IMAGE * ISQ_manufacture_one( int nim , int overlay , MCW_imseq *seq )
10134 {
10135 MRI_IMAGE *im , *ovim , *tim ;
10136 int nrold ;
10137
10138 ENTRY("ISQ_manufacture_one") ;
10139
10140 if( ! ISQ_VALID(seq) ) RETURN( NULL );
10141
10142 if( seq->mont_periodic ){
10143 while( nim < 0 ) nim += seq->status->num_total ;
10144 while( nim >= seq->status->num_total ) nim -= seq->status->num_total ;
10145 } else {
10146 if( nim < 0 || nim >= seq->status->num_total ) RETURN( NULL );
10147 }
10148
10149 /** Not an overlay image **/
10150
10151 if( !overlay ){
10152 switch( seq->render_mode ){
10153 default:
10154 tim = ISQ_getimage( nim , seq ) ;
10155 if( tim == NULL ) RETURN(NULL) ;
10156 im = ISQ_process_mri( nim , seq , tim , 0 ) ; mri_free(tim) ;
10157 break ;
10158
10159 case RENDER_WIPE_LEFT: /* WIPE stuff 22 Aug 2014 */
10160 case RENDER_WIPE_BOT:
10161 case RENDER_MIX:
10162 case RENDER_WIPE_RIGHT:
10163 case RENDER_WIPE_TOP:
10164 case RENDER_CHECK_UO:
10165 case RENDER_CHECK_OU:
10166 im = ISQ_getchecked( nim , seq ) ;
10167 if( im == NULL ) RETURN(NULL) ;
10168 break ;
10169 }
10170 RETURN(im) ;
10171 }
10172
10173 /** Get the overlay image **/
10174
10175 if( ISQ_SKIP_OVERLAY(seq) ) RETURN( NULL );
10176
10177 tim = ISQ_getoverlay( nim , seq ) ;
10178 if( tim == NULL ) RETURN( NULL );
10179 if( !ISQ_GOOD_OVERLAY_TYPE(tim->kind) ){
10180 fprintf(stderr,"\a\n*** Illegal overlay image kind=%d! ***\n",(int)tim->kind) ;
10181 mri_free(tim) ; RETURN( NULL );
10182 }
10183 ovim = mri_flippo( ISQ_TO_MRI_ROT(seq->opt.rot),seq->opt.mirror,tim ) ;
10184 if( tim != ovim ) mri_free(tim) ;
10185 ISQ_apply_mask( seq->last_automask , ovim ) ;
10186 RETURN( ovim );
10187 }
10188
10189 /*---------------------------------------------------------------------------
10190 Routine to make a montage of images
10191 (version of ISQ_make_image when more than one is needed).
10192 -----------------------------------------------------------------------------*/
10193
10194 #define ISQ_set_deltival(sss,dv) \
10195 AFNI_CALL_VOID_3ARG( (sss)->getim , \
10196 int,(dv), int,isqCR_deltival, XtPointer,(sss)->getaux )
10197
ISQ_make_montage(MCW_imseq * seq)10198 void ISQ_make_montage( MCW_imseq *seq )
10199 {
10200 MRI_IMAGE *im , *ovim , *tim ;
10201 RwcBoolean reset_done = False ;
10202 float fac , wmm , hmm ;
10203 short gap_ov ;
10204 float vfac = VGFAC(seq) ;
10205
10206 byte gap_rgb[3] ; /* 11 Feb 1999 */
10207 void *gapval ;
10208 int isrgb ;
10209 int isrgb_ov ; /* 07 Mar 2001 */
10210 int div=0 ;
10211
10212 rgba gap_rgba ; /* 09 Dec 2014 */
10213
10214 ENTRY("ISQ_make_montage");
10215
10216 if( ! ISQ_VALID(seq) ) EXRETURN ;
10217
10218 KILL_2XIM( seq->given_xim , seq->sized_xim ) ; /* erase the XImages */
10219
10220 if( seq->mplot != NULL ){ /* 19 Sep 2001 */
10221 delete_memplot( seq->mplot ) ; seq->mplot = NULL ;
10222 }
10223
10224 /*-- process toggled options that affect the image that may be stored --*/
10225
10226 if( seq->opt.rot != seq->old_opt.rot ||
10227 seq->opt.mirror != seq->old_opt.mirror ||
10228 seq->opt.scale_group != seq->old_opt.scale_group ||
10229 seq->opt.scale_range != seq->old_opt.scale_range ||
10230 seq->mont_nx != seq->mont_nx_old ||
10231 seq->mont_ny != seq->mont_ny_old ||
10232 seq->mont_skip != seq->mont_skip_old ){
10233
10234 KILL_1MRI( seq->imim ) ; /* must re-get image for new processing */
10235 KILL_1MRI( seq->ovim ) ;
10236 }
10237
10238 /*--- set the image to process ---*/
10239
10240 im = seq->imim ;
10241
10242 if( im == NULL ){
10243 float new_width_mm = 0.0 , new_height_mm = 0.0 ;
10244 int nxim = 0 , nyim = 0 , nxyim = 0 ;
10245 int ij , nim , nmont = seq->mont_nx * seq->mont_ny , ijcen ;
10246 MRI_IMARR *mar ;
10247
10248 INIT_IMARR(mar) ;
10249
10250 /** Compute ijcen = montage index of subimage that will
10251 be the "center" (crosshairs, etc.).
10252 N.B.: If the algorithm for this is changed here, it
10253 must be changed in a number of other places,
10254 including the AFNI multiple crosshairs code! **/
10255
10256 if( AFNI_yesenv("TMONT") )
10257 INFO_message("Start Montagizing") ;
10258 isrgb = 0 ;
10259 ijcen = (seq->mont_nx)/2 + (seq->mont_ny/2) * seq->mont_nx ;
10260 for( ij=0 ; ij < nmont ; ij++ ){ /* loop to get all montage underlays */
10261 if( seq->mont_mode > 0 ){
10262 nim = seq->im_nr ;
10263 div = (seq->mont_skip + 1) * (ij - ijcen) ;
10264 if( AFNI_yesenv("TMONT") )
10265 ININFO_message("set deltival=%d nim=%d",div,nim) ;
10266 ISQ_set_deltival( seq , div ) ;
10267 } else {
10268 nim = seq->im_nr + (seq->mont_skip + 1) * (ij - ijcen) ;
10269 }
10270
10271 seq->set_orim = (seq->need_orim != 0 && nim == seq->im_nr && div == 0) ;
10272 tim = ISQ_manufacture_one( nim , 0 , seq ) ;
10273 seq->set_orim = 0 ;
10274 ADDTO_IMARR(mar,tim) ;
10275
10276 if( nim == seq->im_nr && div == 0 && tim != NULL ){
10277 new_width_mm = IM_WIDTH(tim) ; nxim = tim->nx ;
10278 new_height_mm = IM_HEIGHT(tim) ; nyim = tim->ny ;
10279 seq->last_image_type = tim->kind ;
10280 seq->barbot = seq->clbot ; /* 29 Jul 2001 */
10281 seq->bartop = seq->cltop ;
10282 ISQ_set_barhint(seq,"Focus") ;
10283 seq->last_dx = fabs(tim->dx) ; seq->last_dy = fabs(tim->dy) ;
10284 }
10285
10286 if( tim != NULL ){
10287 isrgb = isrgb || (tim != NULL && tim->kind == MRI_rgb) ;
10288 nxyim++ ;
10289 }
10290 }
10291 if( seq->mont_mode > 0 ){ div = 0; ISQ_set_deltival(seq,div); }
10292
10293 if( nxyim == 0 ){ /* bad bad bad bad bad */
10294 fprintf(stderr,"** Montage error: no images found!\n") ;
10295 DESTROY_IMARR(mar) ; EXRETURN ;
10296 }
10297
10298 if( isrgb ){ /* 11 Feb 1999 */
10299 if( seq->mont_gapcolor > 0 )
10300 DC_pixel_to_rgb( seq->dc , seq->dc->ovc->pix_ov[seq->mont_gapcolor],
10301 gap_rgb , gap_rgb+1 , gap_rgb+2 ) ;
10302 else
10303 gap_rgb[0] = gap_rgb[1] = gap_rgb[2] = 0 ;
10304
10305 gapval = (void *) gap_rgb ;
10306 } else {
10307 gap_ov = -(seq->mont_gapcolor) ; /* negative ==> overlay palette */
10308 gapval = (void *) &gap_ov ;
10309 }
10310
10311 /* 17 Feb 1999: if any are rgb, must convert all to that format */
10312
10313 if( isrgb ){
10314 for( ij=0 ; ij < nmont ; ij++ ){
10315 tim = IMARR_SUBIMAGE(mar,ij) ;
10316 if( tim != NULL && tim->kind != MRI_rgb ){
10317 MRI_IMAGE *qim ;
10318
10319 if( tim->kind == MRI_short )
10320 qim = ISQ_index_to_rgb( seq->dc , 0 , tim ) ; /* 07 Mar 2001 */
10321 else
10322 qim = mri_to_rgb( tim ) ; /* the old way */
10323
10324 mri_free(tim) ; /* replace in image array */
10325 IMARR_SUBIMAGE(mar,ij) = qim ;
10326 }
10327 }
10328 }
10329
10330 /* put them all together into one honking image (short or rgb)! */
10331
10332 seq->imim = im = mri_cat2D( seq->mont_nx , seq->mont_ny , /* save this */
10333 seq->mont_gap , gapval , mar ) ; /* underlay */
10334
10335 STATUS("Destroying underlay image array") ;
10336
10337 DESTROY_IMARR(mar) ;
10338
10339 /* fix window dimensions if individual image size is different */
10340
10341 seq->horig = nxim ; seq->vorig = nyim ;
10342
10343 wmm = ( nxim*seq->mont_nx + seq->mont_gap*(seq->mont_nx-1) )
10344 / (float) nxim ;
10345
10346 hmm = ( nyim*seq->mont_ny + seq->mont_gap*(seq->mont_ny-1) )
10347 / (float) nyim ;
10348
10349 fac = sqrt( wmm / hmm ) ;
10350
10351 new_width_mm *= fac ;
10352 new_height_mm /= fac ;
10353
10354 if( FLDIF(new_width_mm ,seq->last_width_mm ) ||
10355 FLDIF(new_height_mm,seq->last_height_mm) ){
10356
10357 ISQ_reset_dimen( seq , new_width_mm , new_height_mm ) ;
10358 reset_done = True ;
10359 }
10360 }
10361
10362 /** at this point, im contains the underlay image, which may be short or rgb **/
10363
10364 if( seq->opt.free_aspect != seq->old_opt.free_aspect && !reset_done )
10365 ISQ_reset_dimen( seq , seq->last_width_mm , seq->last_height_mm ) ;
10366
10367 /*--- set the overlay to process ---*/
10368
10369 if( ISQ_SKIP_OVERLAY(seq) ){
10370 KILL_1MRI( seq->ovim ) ; ovim = NULL ; /* that was easy */
10371 } else {
10372 int ij , nim , nmont=seq->mont_nx * seq->mont_ny , nov=0 , ijcen ;
10373
10374 MEM_plotdata *mp ; /* 19 Sep 2001 */
10375 int ii,jj ;
10376 float sx,sy,st , xb,xt,yb,yt , tx,ty ;
10377
10378 ijcen = (seq->mont_nx)/2 + (seq->mont_ny/2) * seq->mont_nx ;
10379
10380 /*--- get overlay images and montage them, if needed ---*/
10381
10382 ovim = seq->ovim ;
10383 if( ovim == NULL ){
10384 MRI_IMARR *mar ;
10385
10386 INIT_IMARR(mar) ;
10387
10388 isrgb_ov = 0 ; /* 07 Mar 2001 */
10389
10390 for( ij=0 ; ij < nmont ; ij++ ){
10391 if( seq->mont_mode > 0 ){
10392 nim = seq->im_nr ;
10393 div = (seq->mont_skip + 1) * (ij - ijcen) ;
10394 ISQ_set_deltival( seq , div ) ;
10395 } else {
10396 nim = seq->im_nr + (seq->mont_skip + 1) * (ij - ijcen) ;
10397 }
10398
10399 tim = ISQ_manufacture_one( nim , 1 , seq ) ;
10400 ADDTO_IMARR(mar,tim) ;
10401 if( tim != NULL ){
10402 nov++ ;
10403 if( tim->kind == MRI_rgb && isrgb_ov == 0 ) isrgb_ov = 1 ;
10404 else if( tim->kind == MRI_rgba ) isrgb_ov = 2 ;
10405 }
10406 }
10407 if( seq->mont_mode > 0 ){ div = 0; ISQ_set_deltival(seq,div); }
10408
10409 /* 07 Mar 2001: deal with possible RGB overlays */
10410
10411 if( isrgb_ov == 1 ){
10412 for( ij=0 ; ij < nmont ; ij++ ){
10413 tim = IMARR_SUBIMAGE(mar,ij) ;
10414 if( tim != NULL && tim->kind != MRI_rgb ){
10415 MRI_IMAGE *qim ;
10416
10417 if( tim->kind == MRI_short )
10418 qim = ISQ_index_to_rgb( seq->dc , 1 , tim ) ; /* 07 Mar 2001 */
10419 else
10420 qim = mri_to_rgb( tim ) ; /* the old way */
10421
10422 mri_free(tim) ; /* replace in image array */
10423 IMARR_SUBIMAGE(mar,ij) = qim ;
10424 }
10425 }
10426 } else if( isrgb_ov == 2 ){ /* 09 Dec 2014 */
10427 for( ij=0 ; ij < nmont ; ij++ ){
10428 tim = IMARR_SUBIMAGE(mar,ij) ;
10429 if( tim != NULL && tim->kind != MRI_rgba ){
10430 MRI_IMAGE *qim , *zim ;
10431
10432 if( tim->kind == MRI_short ){
10433 zim = ISQ_index_to_rgb( seq->dc , 1 , tim ) ;
10434 qim = mri_to_rgba(zim) ; mri_free(zim) ;
10435 } else {
10436 qim = mri_to_rgba(tim) ;
10437 }
10438
10439 mri_free(tim) ; IMARR_SUBIMAGE(mar,ij) = qim ;
10440 }
10441 }
10442 }
10443
10444 if( isrgb_ov == 1 ){
10445 gap_rgb[0] = gap_rgb[1] = gap_rgb[2] = 0 ;
10446 gapval = (void *)gap_rgb ;
10447 } else if( isrgb_ov == 2 ){ /* 09 Dec 2014 */
10448 gap_rgba.r = gap_rgba.g = gap_rgba.b = gap_rgba.a = 0 ;
10449 gapval = (void *)(&gap_rgba) ;
10450 } else {
10451 gap_ov = 0 ;
10452 gapval = (void *)(&gap_ov) ;
10453 }
10454
10455 if( nov > 0 ){
10456 ovim = seq->ovim = /* save this */
10457 mri_cat2D( seq->mont_nx , seq->mont_ny , /* overlay */
10458 seq->mont_gap , gapval , mar ) ;
10459 } else
10460 ovim = seq->ovim = NULL ; /* nothing */
10461
10462 STATUS("Destroying overlay image array") ;
10463
10464 DESTROY_IMARR( mar ) ;
10465 }
10466
10467 /*--- 19 Sep 2001: make overlay line plots for image? ---*/
10468
10469 /*-- get sub-plots for each sub-image,
10470 merge into a superplot for the montage --*/
10471
10472 if( MCW_val_bbox(seq->wbar_plots_bbox) != 0 ){
10473 for( ij=0 ; ij < nmont ; ij++ ){
10474
10475 nim = seq->im_nr + (seq->mont_skip + 1) * (ij - ijcen) ;
10476 if( seq->mont_periodic ){
10477 while( nim < 0 ) nim += seq->status->num_total ;
10478 while( nim >= seq->status->num_total ) nim -= seq->status->num_total ;
10479 } else {
10480 if( nim < 0 || nim >= seq->status->num_total ) continue ; /* skip */
10481 }
10482
10483 mp = ISQ_getmemplot( nim , seq ) ;
10484
10485 if( mp == NULL ) continue ; /* skip */
10486
10487 ii = ij % seq->mont_nx ; /* sub-image x index in montage */
10488 jj = ij / seq->mont_nx ; /* sub-image y index in montage */
10489
10490 tx = im->nx ; ty = im->ny ; /* size of underlay image */
10491
10492 /* sub-image is inside (xb..xt) X (yb..yt) in
10493 plot coordinates -- y is down-to-up,
10494 whereas image coordinates run y is up-to-down */
10495
10496 xb = (seq->horig + seq->mont_gap) * ii ;
10497 xt = xb + seq->horig ;
10498 yb = (seq->vorig + seq->mont_gap) * (seq->mont_ny - 1 - jj) ;
10499 yt = yb + seq->vorig ;
10500
10501 /* scale factors to put this sub-plot
10502 in the correct place in the montage */
10503
10504 sx = (xt-xb) / tx ; tx = xb / tx ;
10505 sy = (yt-yb) / ty ; ty = yb / ty ; st = sqrt(sx*sy) ;
10506
10507 /* rotate/flip to same orientation as sub-image */
10508
10509 flip_memplot( ISQ_TO_MRI_ROT(seq->opt.rot),seq->opt.mirror, mp ) ;
10510
10511 /* scale to correct location as sub-image */
10512
10513 scale_memplot( sx,tx , sy,ty , st , mp ) ;
10514
10515 /* attach to superplot */
10516
10517 if( seq->mplot == NULL ){ /* make 1st one the superplot */
10518 seq->mplot = mp ;
10519 } else { /* attach later ones to superplot */
10520 append_to_memplot( seq->mplot , mp ) ;
10521 delete_memplot( mp ) ;
10522 }
10523
10524 } /* end of loop over sub-images' sub-plots */
10525 } /* end of if over whether to plot the plot */
10526
10527 /*--- 20 Sep 2001: plot labels ---*/
10528
10529 if( seq->wbar_label_av->ival != 0 ){
10530 char *lab ;
10531
10532 for( ij=0 ; ij < nmont ; ij++ ){
10533
10534 nim = seq->im_nr + (seq->mont_skip + 1) * (ij - ijcen) ;
10535 if( seq->mont_periodic ){
10536 while( nim < 0 ) nim += seq->status->num_total ;
10537 while( nim >= seq->status->num_total ) nim -= seq->status->num_total ;
10538 } else {
10539 if( nim < 0 || nim >= seq->status->num_total ) continue ; /* skip */
10540 }
10541
10542 /*- get label string -*/
10543
10544 lab = ISQ_getlabel( nim , seq ) ;
10545 if( lab != NULL ){
10546 mp = ISQ_plot_label( seq , lab ) ; /* plot it */
10547 if( mp != NULL ){
10548 ii = ij % seq->mont_nx ; /* sub-image x index in montage */
10549 jj = ij / seq->mont_nx ; /* sub-image y index in montage */
10550 tx = im->nx ; ty = im->ny ; /* size of underlay image */
10551 xb = (seq->horig + seq->mont_gap) * ii ;
10552 xt = xb + seq->horig ;
10553 yb = (seq->vorig + seq->mont_gap) * (seq->mont_ny - 1 - jj) ;
10554 yt = yb + seq->vorig ;
10555 sx = (xt-xb) / tx ; tx = xb / tx ;
10556 sy = (yt-yb) / ty ; ty = yb / ty ; st = sqrt(sx*sy) ;
10557 scale_memplot( sx,tx , sy,ty , st , mp ) ;
10558 if( seq->mplot != NULL ){
10559 append_to_memplot( seq->mplot , mp ) ; delete_memplot( mp ) ;
10560 } else {
10561 seq->mplot = mp ;
10562 }
10563 }
10564 free(lab) ;
10565 }
10566 } /* end of loop over sub-images */
10567 } /* end of plot labels */
10568
10569 } /* end of making overlay stuff */
10570
10571 /*--- set old_opt to current options ---*/
10572
10573 seq->old_opt = seq->opt ;
10574
10575 seq->mont_nx_old = seq->mont_nx ;
10576 seq->mont_ny_old = seq->mont_ny ;
10577 seq->mont_skip_old = seq->mont_skip ;
10578 seq->mont_gap_old = seq->mont_gap ;
10579 seq->mont_gapcolor_old = seq->mont_gapcolor ;
10580
10581 /*--- overlay ovim onto im, producing tim, if needed ---*/
10582
10583 if( ovim == NULL || ISQ_SKIP_OVERLAY(seq) ){ /* no processing of overlay */
10584 tim = im ;
10585 } else {
10586 tim = ISQ_overlay( seq->dc , im, ovim, seq->ov_opacity ) ;
10587 if( tim == NULL ) tim = im ; /* shouldn't happen */
10588 }
10589
10590 if( vfac > 0.0f ){
10591 MRI_IMAGE *qim ;
10592 MCW_invert_widget(seq->wbut_bot[NBUT_DISP]) ;
10593 vgize_sigfac = vfac ; qim = mri_vgize(tim) ;
10594 MCW_invert_widget(seq->wbut_bot[NBUT_DISP]) ;
10595 if( qim != NULL ){
10596 if( tim != im ) KILL_1MRI(tim);
10597 tim = qim;
10598 }
10599 }
10600
10601 /*--- convert result to XImage for display ---*/
10602
10603 seq->given_xim = mri_to_XImage( seq->dc , tim ) ;
10604
10605 if( tim != im ) KILL_1MRI(tim) ;
10606 EXRETURN ;
10607 }
10608
10609 /*----------------------------------------------------------------------
10610 Given a pair of coordinates in the image window, find the original
10611 coordinates they come from in the image, allowing for rotations,
10612 mirroring, and montaging. This new version (April 1996) also
10613 returns the image number that the coordinates occurred in, since
10614 that may vary with montaging.
10615
10616 12 Mar 2002: modified to allow for possibility of zoom
10617 12 Jun 2002: and to allow for cropping
10618 -------------------------------------------------------------------------*/
10619
ISQ_mapxy(MCW_imseq * seq,int xwin,int ywin,int * xim,int * yim,int * nim)10620 void ISQ_mapxy( MCW_imseq *seq, int xwin, int ywin,
10621 int *xim, int *yim, int *nim )
10622 {
10623 int win_wide,win_high , nxim,nyim ;
10624 int monx,mony,monsk,mongap , win_wide_orig,win_high_orig ;
10625 int xorg , yorg , ijcen , xcol,yrow , ij ;
10626 int zlev = seq->zoom_fac ;
10627
10628 ENTRY("ISQ_mapxy") ;
10629
10630 if( ! ISQ_REALZ(seq) ) EXRETURN ;
10631
10632 nxim = seq->horig ; nyim = seq->vorig ; /* sizes of original images */
10633 monx = seq->mont_nx ; mony = seq->mont_ny ; /* montage layout parameters */
10634 monsk = seq->mont_skip ; mongap = seq->mont_gap ;
10635
10636 win_wide_orig = nxim * monx + mongap * (monx-1) ; /* un-resized (original) */
10637 win_high_orig = nyim * mony + mongap * (mony-1) ; /* displayed image sizes */
10638
10639 /* get actual (display) image sizes */
10640
10641 if( seq->wimage_width <= 0 ){
10642 MCW_widget_geom( seq->wimage , &win_wide , &win_high , NULL,NULL ) ;
10643 seq->wimage_width = win_wide ;
10644 seq->wimage_height = win_high ;
10645 } else {
10646 win_wide = seq->wimage_width ;
10647 win_high = seq->wimage_height ;
10648 }
10649
10650 /* convert actual coordinates input to
10651 equivalent coordinates in the original (montaged) image */
10652
10653 /* conversion if zoom is not on */
10654
10655 if( zlev == 1 || monx > 1 || mony > 1 ){
10656
10657 xorg = ( (float) xwin / win_wide ) * win_wide_orig /* + 0.49 */ ;
10658 yorg = ( (float) ywin / win_high ) * win_high_orig /* + 0.49 */ ;
10659
10660 } else { /* conversion if zoom is on (only in 1x1 montages) */
10661
10662 int pw=seq->zoom_pw , ph=seq->zoom_ph ;
10663 float xoff,yoff ;
10664
10665 xoff = seq->zoom_hor_off*pw; if( xoff+win_wide > pw ) xoff = pw-win_wide;
10666 yoff = seq->zoom_ver_off*ph; if( yoff+win_high > ph ) yoff = ph-win_high;
10667
10668 xorg = nxim * (xoff+xwin) / pw ;
10669 yorg = nyim * (yoff+ywin) / ph ;
10670 }
10671
10672 /* compute the coordinates within the sub-image (*xim and *yim),
10673 and the grid column and row number of the sub-image (xcol,yrow) */
10674
10675 *xim = xorg % (nxim+mongap) ; xcol = xorg / (nxim+mongap) ;
10676 *yim = yorg % (nyim+mongap) ; yrow = yorg / (nyim+mongap) ;
10677
10678 /* compute the image number in the sequence that (xcol,yrow)
10679 came from, using the same algorithm as in ISQ_make_montage */
10680
10681 ij = xcol + yrow * monx ;
10682 ijcen = monx/2 + (mony/2) * monx ;
10683 *nim = seq->im_nr + (monsk+1) * (ij-ijcen) ;
10684
10685 if( seq->mont_periodic ){
10686 while( *nim < 0 ) *nim += seq->status->num_total ;
10687 while( *nim >= seq->status->num_total ) *nim -= seq->status->num_total ;
10688 }
10689
10690 /* flip the (xim,yim) coordinates in case the stupid user used
10691 one of the rotate or mirror buttons in the "Disp" control box */
10692
10693 ISQ_flipxy( seq , xim , yim ) ;
10694
10695 if( seq->cropit ){ /* 12 Jun 2002: allow for cropping */
10696 *xim += seq->crop_xa ;
10697 *yim += seq->crop_ya ;
10698 }
10699
10700 EXRETURN ;
10701 }
10702
10703 /*---------------------------------------------------------------------
10704 Inputs: xflip,yflip = pointers to coordinates in the flipped image
10705 Output: xflip,yflip = values are changed to original image coords
10706
10707 Note that these coordinates are relative to original (un-resized)
10708 image dimensions.
10709
10710 Also see ISQ_unflipxy().
10711 -----------------------------------------------------------------------*/
10712
ISQ_flipxy(MCW_imseq * seq,int * xflip,int * yflip)10713 void ISQ_flipxy( MCW_imseq *seq, int *xflip, int *yflip )
10714 {
10715 int fopt , xim , yim , nx,ny ;
10716
10717 ENTRY("ISQ_flipxy") ;
10718
10719 fopt = ISQ_TO_MRI_ROT(seq->opt.rot) ;
10720 if( seq->opt.mirror ) fopt += MRI_FLMADD ;
10721
10722 nx = seq->horig ; ny = seq->vorig ;
10723
10724 switch( fopt ){
10725
10726 default: /* ROT_0, no mirror */
10727 case (MRI_ROT_0):
10728 xim = *xflip ; yim = *yflip ; break ;
10729
10730 case (MRI_ROT_90): /* ROT_90, no mirror */
10731 xim = ny-1-*yflip ; yim = *xflip ; break ;
10732
10733 case (MRI_ROT_180): /* ROT_180, no mirror */
10734 xim = nx-1-*xflip ; yim = ny-1-*yflip ; break ;
10735
10736 case (MRI_ROT_270): /* ROT_270, no mirror */
10737 xim = *yflip ; yim = nx-1-*xflip ; break ;
10738
10739 case (MRI_ROT_0+MRI_FLMADD): /* ROT_0, mirror */
10740 xim = nx-1-*xflip ; yim = *yflip ; break ;
10741
10742 case (MRI_ROT_90+MRI_FLMADD): /* ROT_90, mirror */
10743 xim = ny-1-*yflip ; yim = nx-1-*xflip ; break ;
10744
10745 case (MRI_ROT_180+MRI_FLMADD): /* ROT_180, mirror */
10746 xim = *xflip ; yim = ny-1-*yflip ; break ;
10747
10748 case (MRI_ROT_270+MRI_FLMADD): /* ROT_270, mirror */
10749 xim = *yflip ; yim = *xflip ; break ;
10750 }
10751
10752 *xflip = xim ; *yflip = yim ; EXRETURN ;
10753 }
10754
10755 /*-------------------------------------------------------------------*/
10756 /* The inverse to ISQ_flipxy() */
10757
ISQ_unflipxy(MCW_imseq * seq,int * xflip,int * yflip)10758 void ISQ_unflipxy( MCW_imseq *seq, int *xflip, int *yflip )
10759 {
10760 int fopt , xim , yim , nx,ny ;
10761
10762 ENTRY("ISQ_unflipxy") ;
10763
10764 fopt = ISQ_TO_MRI_ROT(seq->opt.rot) ;
10765 if( seq->opt.mirror ) fopt += MRI_FLMADD ;
10766
10767 nx = seq->horig ; ny = seq->vorig ;
10768
10769 switch( fopt ){
10770
10771 default: /* ROT_0, no mirror */
10772 case (MRI_ROT_0):
10773 xim = *xflip ; yim = *yflip ; break ;
10774
10775 case (MRI_ROT_90): /* ROT_90, no mirror */
10776 yim = ny-1-*xflip ; xim = *yflip ; break ;
10777
10778 case (MRI_ROT_180): /* ROT_180, no mirror */
10779 xim = nx-1-*xflip ; yim = ny-1-*yflip ; break ;
10780
10781 case (MRI_ROT_270): /* ROT_270, no mirror */
10782 yim = *xflip ; xim = nx-1-*yflip ; break ;
10783
10784 case (MRI_ROT_0+MRI_FLMADD): /* ROT_0, mirror */
10785 xim = nx-1-*xflip ; yim = *yflip ; break ;
10786
10787 case (MRI_ROT_90+MRI_FLMADD): /* ROT_90, mirror */
10788 yim = ny-1-*xflip ; xim = nx-1-*yflip ; break ;
10789
10790 case (MRI_ROT_180+MRI_FLMADD): /* ROT_180, mirror */
10791 xim = *xflip ; yim = ny-1-*yflip ; break ;
10792
10793 case (MRI_ROT_270+MRI_FLMADD): /* ROT_270, mirror */
10794 xim = *yflip ; yim = *xflip ; break ;
10795 }
10796
10797 *xflip = xim ; *yflip = yim ; EXRETURN ;
10798 }
10799
10800 /*-----------------------------------------------------------------------------
10801 Routines to handle transformations of an image.
10802 -------------------------------------------------------------------------------*/
10803
ISQ_transform_label(MCW_arrowval * av,XtPointer cd)10804 char * ISQ_transform_label( MCW_arrowval *av , XtPointer cd )
10805 {
10806 MCW_function_list *xforms = (MCW_function_list *) cd ;
10807
10808 if( av == NULL || xforms == NULL ||
10809 av->ival <= 0 || av->ival > xforms->num ) return "-none-" ;
10810
10811 return xforms->labels[av->ival - 1] ; /* label for each function */
10812 }
10813
10814 /*-----------------------------------------------------------------------------*/
10815
ISQ_transform_CB(MCW_arrowval * av,XtPointer cd)10816 void ISQ_transform_CB( MCW_arrowval *av , XtPointer cd )
10817 {
10818 MCW_imseq *seq = (MCW_imseq *) cd ;
10819
10820 ENTRY("ISQ_transform_CB") ;
10821
10822 if( ! ISQ_VALID(seq) ) EXRETURN ;
10823
10824 /** set the 0D transform function pointer **/
10825
10826 if( av != NULL && av == seq->transform0D_av ){
10827 if( seq->status->transforms0D == NULL || av->ival <= 0 ||
10828 av->ival > seq->status->transforms0D->num ){
10829
10830 seq->transform0D_func = NULL ; /* no transform */
10831 seq->transform0D_index = 0 ;
10832 } else {
10833 seq->transform0D_func = seq->status->transforms0D->funcs[av->ival - 1] ;
10834 seq->transform0D_index = av->ival ;
10835
10836 /* 21 Jul 2003: do initializing func call, if present */
10837
10838 if( seq->status->transforms0D->func_init[av->ival-1] != NULL )
10839 seq->status->transforms0D->func_init[av->ival-1]() ;
10840
10841 }
10842 }
10843
10844 /** set the 2D transform function pointer **/
10845
10846 if( av != NULL && av == seq->transform2D_av ){
10847 if( seq->status->transforms2D == NULL || av->ival <= 0 ||
10848 av->ival > seq->status->transforms2D->num ){
10849
10850 seq->transform2D_func = NULL ; /* no transform */
10851 seq->transform2D_index = 0 ;
10852 } else {
10853 seq->transform2D_func = seq->status->transforms2D->funcs[av->ival - 1] ;
10854 seq->transform2D_index = av->ival ;
10855
10856 /* 21 Jul 2003: do initializing func call, if present */
10857
10858 if( seq->status->transforms2D->func_init[av->ival-1] != NULL )
10859 seq->status->transforms2D->func_init[av->ival-1]() ;
10860 }
10861 }
10862
10863 ISQ_redisplay( seq , -1 , isqDR_reimage ) ; /* redo current image */
10864 EXRETURN ;
10865 }
10866
10867 /*-----------------------------------------------------------------------------*/
10868
ISQ_slice_proj_CB(MCW_arrowval * av,XtPointer cd)10869 void ISQ_slice_proj_CB( MCW_arrowval *av , XtPointer cd )
10870 {
10871 MCW_imseq *seq = (MCW_imseq *) cd ;
10872
10873 ENTRY("ISQ_slice_proj_CB") ;
10874
10875 if( ! ISQ_VALID(seq) ) EXRETURN ;
10876
10877 /** set the slice_proj function pointer **/
10878
10879 if( av != NULL && av == seq->slice_proj_av ){
10880 if( seq->status->slice_proj == NULL || av->ival <= 0 ||
10881 av->ival > seq->status->slice_proj->num ){
10882
10883 seq->slice_proj_func = NULL ; /* no slice_proj */
10884 seq->slice_proj_index = 0 ;
10885 } else {
10886 seq->slice_proj_func = (float_func *)
10887 seq->status->slice_proj->funcs[av->ival - 1] ;
10888 seq->slice_proj_index = av->ival ;
10889 }
10890 }
10891
10892 seq->slice_proj_range = seq->slice_proj_range_av->ival ;
10893
10894 ISQ_redisplay( seq , -1 , isqDR_reimage ) ; /* redo current image */
10895 EXRETURN ;
10896 }
10897
10898 /*--------------------------------------------------------------------------
10899 30 Dec 1998: Handle the row graphs
10900 ----------------------------------------------------------------------------*/
10901
ISQ_rowgraph_label(MCW_arrowval * av,XtPointer cd)10902 char * ISQ_rowgraph_label( MCW_arrowval *av , XtPointer cd )
10903 {
10904 static char buf[16] ;
10905 sprintf(buf,"%2d ",av->ival) ;
10906 return buf ;
10907 }
10908
10909 /*--------------------------------------------------------------------------*/
10910
ISQ_rowgraph_CB(MCW_arrowval * av,XtPointer cd)10911 void ISQ_rowgraph_CB( MCW_arrowval *av , XtPointer cd )
10912 {
10913 MCW_imseq *seq = (MCW_imseq *) cd ;
10914
10915 ENTRY("ISQ_rowgraph_CB") ;
10916
10917 if( ! ISQ_VALID(seq) ) EXRETURN ; /* bad input */
10918 if( av->ival == seq->rowgraph_num ) EXRETURN ; /* nothing changed */
10919
10920 seq->rowgraph_num = av->ival ;
10921
10922 if( seq->rowgraph_num > 0 ) seq->need_orim |= ROWGRAPH_MASK ;
10923 else seq->need_orim &= ~ROWGRAPH_MASK ;
10924 if( seq->need_orim == 0 ) KILL_1MRI(seq->orim) ;
10925
10926 ISQ_redisplay( seq , -1 , isqDR_reimage ) ; /* redo current image */
10927 EXRETURN ;
10928 }
10929
10930 /*--------------------------------------------------------------------------*/
10931
ISQ_rowgraph_draw(MCW_imseq * seq)10932 void ISQ_rowgraph_draw( MCW_imseq *seq )
10933 {
10934 MEM_plotdata *mp ;
10935 ISQ_cbs cbs ;
10936 int jbot,ix,jy , nrow , jj , nx,ny , ymask ;
10937 float *yar[ROWGRAPH_MAX] ;
10938
10939 ENTRY("ISQ_rowgraph_draw") ;
10940
10941 if( ! ISQ_REALZ(seq) ) EXRETURN ; /* error */
10942
10943 /* marked for no graphs? */
10944
10945 if( seq->rowgraph_num == 0 ){
10946 if( seq->rowgraph_mtd != NULL ){
10947 plotkill_topshell( seq->rowgraph_mtd ) ;
10948 seq->rowgraph_mtd = NULL ;
10949 }
10950 EXRETURN ;
10951 }
10952
10953 if( seq->orim == NULL ) EXRETURN ;
10954
10955 /* find current location of crosshairs (if any) */
10956
10957 cbs.reason = isqCR_getxynim ;
10958 cbs.xim = cbs.yim = cbs.nim = -666 ;
10959 if( seq->status->send_CB != NULL )
10960 #if 0
10961 seq->status->send_CB( seq , seq->getaux , &cbs ) ;
10962 #else
10963 SEND(seq,cbs) ;
10964 #endif
10965 if( cbs.xim < 0 || cbs.yim < 0 ){
10966 ERROR_message("in ISQ_rowgraph_draw: xim=%d yim=%d",cbs.xim,cbs.yim) ;
10967 EXRETURN ; /* bad result */
10968 }
10969 ISQ_unflipxy( seq , &(cbs.xim) , &(cbs.yim) ) ;
10970 jy = jbot = cbs.yim ; ix = cbs.xim ;
10971
10972 /* get pointers to data rows */
10973
10974 if( jbot < 0 || jbot >= seq->orim->ny ){
10975 ERROR_message("in ISQ_rowgraph_draw: jbot=%d",jbot) ;
10976 EXRETURN ; /* no data? */
10977 }
10978
10979 nrow = MIN( seq->rowgraph_num , jbot+1 ) ;
10980 nx = seq->orim->nx ;
10981 ny = seq->orim->ny ;
10982
10983 for( jj=0 ; jj < nrow ; jj++ ){
10984 yar[jj] = MRI_FLOAT_PTR(seq->orim) + (jbot-jj)*nx ;
10985 (void)thd_floatscan( nx , yar[jj] ) ;
10986 }
10987
10988 /* make a plot in memory */
10989
10990 ymask = TSP_SEPARATE_YBOX ;
10991
10992 plot_ts_setTHIK(0.0034567f) ;
10993 mp = plot_ts_mem( nx , NULL , nrow,ymask,yar , "Column (pixels)",NULL,NULL,NULL ) ;
10994 if( mp == NULL ){
10995 ERROR_message("in ISQ_rowgraph_draw: can't make plot_ts_mem") ;
10996 EXRETURN ; /* error */
10997 }
10998
10999 /*-- plot a * at the selected point (if it is in range) --*/
11000
11001 if( !ISQ_SKIP_OVERLAY(seq) && ix >= 0 && ix < nx && jy >= 0 && jy < ny ){
11002 float xx , yy , dx , dy , xbot,xtop, ybot,ytop ;
11003
11004 xx = ix ; dx = 0.016 * nx ; yy = yar[0][ix] ;
11005 #if 0
11006 ybot = ytop = yar[0][0] ;
11007 for( jj=1 ; jj < nx ; jj++ )
11008 if( yar[0][jj] < ybot ) ybot = yar[0][jj] ;
11009 else if( yar[0][jj] > ytop ) ytop = yar[0][jj] ;
11010 dy = 0.016 * nrow * (ytop-ybot) ;
11011 #else
11012 plotpak_getset( NULL,NULL,NULL,NULL , &xbot,&xtop , &ybot,&ytop ) ;
11013 dx = 0.016 * fabs(xtop-xbot) ;
11014 dy = 0.016 * fabs(ytop-ybot) * nrow ;
11015 #endif
11016
11017 #undef THIK
11018 #define THIK 0.004
11019
11020 set_color_memplot( 0.8 , 0.0 , 0.2 ) ;
11021 set_thick_memplot( THIK ) ;
11022 plotpak_line( xx-dx , yy , xx+dx , yy ) ; /* - stroke */
11023 plotpak_line( xx , yy-dy , xx , yy+dy ) ; /* | stroke */
11024 plotpak_line( xx-dx , yy-dy , xx+dx , yy+dy ) ; /* / stroke */
11025 plotpak_line( xx+dx , yy-dy , xx-dx , yy+dy ) ; /* \ stroke */
11026 set_color_memplot( 0.2 , 0.0 , 0.8 ) ;
11027 plotpak_line( xx+dx , yy-dy , xx+dx , yy+dy ) ; /* box around outside */
11028 plotpak_line( xx+dx , yy+dy , xx-dx , yy+dy ) ;
11029 plotpak_line( xx-dx , yy+dy , xx-dx , yy-dy ) ;
11030 plotpak_line( xx-dx , yy-dy , xx+dx , yy-dy ) ;
11031 set_color_memplot( 0.0 , 0.0 , 0.0 ) ;
11032 set_thick_memplot( 0.0 ) ;
11033 }
11034
11035 /* if there is a plot window open, plot into it, otherwise open a new window */
11036
11037 if( seq->rowgraph_mtd != NULL ){
11038
11039 MTD_replace_plotdata( seq->rowgraph_mtd , mp ) ;
11040 redraw_topshell( seq->rowgraph_mtd ) ;
11041
11042 } else { /* make a new plot window */
11043
11044 X11_SET_NEW_PLOT ;
11045 seq->rowgraph_mtd = memplot_to_topshell( seq->dc->display, mp,
11046 ISQ_rowgraph_mtdkill ) ;
11047
11048 if( seq->rowgraph_mtd == NULL ){ delete_memplot( mp ); EXRETURN; }
11049
11050 seq->rowgraph_mtd->userdata = (void *) seq ;
11051 }
11052
11053 EXRETURN ;
11054 }
11055
11056 /*-----------------------------------------------------------------------*/
11057 /*! This function is called when then rowgraph_mtd is killed. */
11058
ISQ_rowgraph_mtdkill(MEM_topshell_data * mp)11059 void ISQ_rowgraph_mtdkill( MEM_topshell_data *mp )
11060 {
11061 MCW_imseq *seq ;
11062
11063 ENTRY("ISQ_rowgraph_mtdkill") ;
11064
11065 if( mp == NULL ) EXRETURN ;
11066 seq = (MCW_imseq *) mp->userdata ; if( ! ISQ_VALID(seq) ) EXRETURN ;
11067
11068 seq->rowgraph_mtd = NULL ;
11069
11070 AV_assign_ival( seq->rowgraph_av , 0 ) ;
11071 seq->rowgraph_num = 0 ;
11072 EXRETURN ;
11073 }
11074
11075 /*-----------------------------------------------------------------------*/
11076 /*! This function is called when the graymap_mtd is killed. */
11077
ISQ_graymap_mtdkill(MEM_topshell_data * mp)11078 void ISQ_graymap_mtdkill( MEM_topshell_data *mp ) /* 24 Oct 2003 */
11079 {
11080 MCW_imseq *seq ;
11081
11082 ENTRY("ISQ_graymap_mtdkill") ;
11083
11084 if( mp == NULL ) EXRETURN ;
11085 seq = (MCW_imseq *) mp->userdata ;
11086 if( ISQ_VALID(seq) ){
11087 seq->graymap_mtd = NULL ;
11088 seq->need_orim &= ~GRAYMAP_MASK ; /* turn off need for orim for graymap */
11089 }
11090
11091 EXRETURN ;
11092 }
11093
11094 /*-----------------------------------------------------------------------*/
11095
ISQ_graymap_draw(MCW_imseq * seq)11096 void ISQ_graymap_draw( MCW_imseq *seq ) /* 24 Oct 2003 */
11097 {
11098 MEM_plotdata *mp ;
11099 int ix , nx , ny , nxx ;
11100 float *yar[2] , *xar , dx , *ar ;
11101
11102 ENTRY("ISQ_graymap_draw") ;
11103
11104 if( !ISQ_REALZ(seq) || seq->dc->use_xcol_im ) EXRETURN ; /* error */
11105
11106 seq->need_orim |= GRAYMAP_MASK ;
11107
11108 /* make float arrays with grayscales and data range */
11109 /* Modifed 12 Jan 2004 to plot in histogram style. */
11110
11111 nx = seq->dc->ncol_im ;
11112 nxx = 2*nx+2 ;
11113 ny = 1 ;
11114 dx = (seq->bartop - seq->barbot) / nx ; if( dx == 0.0 ) EXRETURN ;
11115 yar[0] = (float *) malloc( sizeof(float)*nxx ) ;
11116 xar = (float *) malloc( sizeof(float)*nxx ) ;
11117 xar[0] = seq->barbot ;
11118 for( ix=0 ; ix < nx ; ix++ ){
11119 xar[2*ix+1] = seq->barbot + ix*dx ;
11120 xar[2*ix+2] = seq->barbot + (ix+1)*dx ;
11121 yar[0][2*ix+1] = seq->dc->xint_im[ix] ;
11122 if( yar[0][2*ix+1] < 0.0 ){
11123 yar[0][2*ix+1] = 0.0 ;
11124 } else {
11125 yar[0][2*ix+1] *= (255.0/65280.0);
11126 if( yar[0][2*ix+1] > 255.0 ) yar[0][2*ix+1] = 255.0;
11127 }
11128 yar[0][2*ix+2] = yar[0][2*ix+1] ;
11129 }
11130 xar[2*nx+1] = seq->bartop ;
11131 yar[0][0] = yar[0][1] ;
11132 yar[0][2*nx+1] = yar[0][2*nx] ;
11133
11134 /* histogram the image? */
11135
11136 if( seq->orim != NULL ){
11137 float *iar=MRI_FLOAT_PTR(seq->orim) , *har , val ;
11138 float scl=nx/(seq->bartop-seq->barbot) ; int ii,jj ;
11139 har = (float *) calloc( sizeof(float),nx ) ;
11140 for( ii=0 ; ii < seq->orim->nvox ; ii++ ){
11141 jj = (int)( scl*(iar[ii]-seq->barbot) ) ;
11142 if( jj < 0 ) jj = 0 ; else if( jj > nx-1 ) jj = nx-1 ;
11143 har[jj] += 1.0 ;
11144 }
11145 for( scl=0.0,ii=1 ; ii < nx ; ii++ )
11146 if( har[ii] > scl ) scl = har[ii] ;
11147 if( scl > 0.0 ){
11148 ny = 2 ;
11149 yar[1] = (float *) malloc( sizeof(float)*nxx ) ;
11150 scl = 255.0/sqrt(scl) ;
11151 yar[1][0] = yar[1][2*nx+1] = 0.0 ;
11152 for( ii=0 ; ii < nx ; ii++ ){
11153 val = scl*sqrt(har[ii]) ; if( val > 255.0 ) val = 255.0 ;
11154 yar[1][2*ii+1] = yar[1][2*ii+2] = val ;
11155 }
11156 }
11157 free( (void *)har ) ;
11158 }
11159
11160 /* make a plot in memory */
11161
11162 plot_ts_setTHIK(0.002468f) ;
11163 mp = plot_ts_mem( nxx,xar, ny,0,yar, "Data Value",
11164 (ny == 1) ? "GrayLevel"
11165 : "GrayLevel\\red/Histogram\\black" ,
11166 NULL,NULL ) ;
11167 free(xar); free(yar[0]); if( ny == 2 ) free(yar[1]) ;
11168 if( mp == NULL ){
11169 fprintf(stderr,"*** error in ISQ_graymap_draw: can't make plot_ts_mem\n") ;
11170 EXRETURN ; /* error */
11171 }
11172
11173 /* if there is a plot window open, plot into it, otherwise open a new window */
11174
11175 if( seq->graymap_mtd != NULL ){
11176
11177 MTD_replace_plotdata( seq->graymap_mtd , mp ) ;
11178 redraw_topshell( seq->graymap_mtd ) ;
11179
11180 } else { /* make a new plot window */
11181
11182 seq->graymap_mtd = memplot_to_topshell( seq->dc->display, mp, ISQ_graymap_mtdkill ) ;
11183 if( seq->graymap_mtd == NULL ){ delete_memplot(mp); EXRETURN; }
11184 seq->graymap_mtd->userdata = (void *) seq ;
11185 ISQ_place_widget( seq->wtop , seq->graymap_mtd->top ) ;
11186 }
11187
11188 EXRETURN ;
11189 }
11190
11191 /*-----------------------------------------------------------------------
11192 21 Jan 1999: Handle the surface graph stuff
11193 -------------------------------------------------------------------------*/
11194
ISQ_surfgraph_label(MCW_arrowval * av,XtPointer cd)11195 char * ISQ_surfgraph_label( MCW_arrowval *av , XtPointer cd )
11196 {
11197 switch( av->ival ){
11198 case 0: return "No" ;
11199 case 1: return "Yes" ;
11200 case 2: return "Inv" ;
11201 }
11202 return "?*?" ;
11203 }
11204
11205 /*-------- called when the user changes the SurfGraph menu button --------*/
11206
ISQ_surfgraph_CB(MCW_arrowval * av,XtPointer cd)11207 void ISQ_surfgraph_CB( MCW_arrowval *av , XtPointer cd )
11208 {
11209 MCW_imseq *seq = (MCW_imseq *) cd ;
11210
11211 ENTRY("ISQ_surfgraph_CB") ;
11212
11213 if( ! ISQ_VALID(seq) ) EXRETURN ; /* bad input */
11214 if( av->ival == seq->surfgraph_num ) EXRETURN ; /* nothing changed */
11215
11216 seq->surfgraph_num = av->ival ;
11217
11218 if( seq->surfgraph_num > 0 ) seq->need_orim |= SURFGRAPH_MASK ;
11219 else seq->need_orim &= ~SURFGRAPH_MASK ;
11220 if( seq->need_orim == 0 ) KILL_1MRI(seq->orim) ;
11221
11222 ISQ_redisplay( seq , -1 , isqDR_reimage ) ; /* redo current image */
11223 EXRETURN ;
11224 }
11225
11226 /*---------------- called to redraw the surface graph -------------------*/
11227
ISQ_surfgraph_draw(MCW_imseq * seq)11228 void ISQ_surfgraph_draw( MCW_imseq *seq )
11229 {
11230 MEM_plotdata *mp ;
11231 ISQ_cbs cbs ;
11232 int ix , jy ;
11233
11234 ENTRY("ISQ_surfgraph_draw") ;
11235
11236 if( ! ISQ_REALZ(seq) ) EXRETURN ; /* error */
11237
11238 /* marked for no graph? */
11239
11240 if( seq->surfgraph_num == 0 ){
11241 if( seq->surfgraph_mtd != NULL ){
11242 plotkill_topshell( seq->surfgraph_mtd ) ;
11243 seq->surfgraph_mtd = NULL ;
11244 }
11245 EXRETURN ;
11246 }
11247
11248 if( seq->orim == NULL ) EXRETURN ;
11249
11250 /* find current location */
11251
11252 if( ISQ_SKIP_OVERLAY(seq) ){
11253 ix = jy = -1 ;
11254 } else {
11255 cbs.reason = isqCR_getxynim ;
11256 cbs.xim = cbs.yim = cbs.nim = -666 ;
11257 if( seq->status->send_CB != NULL )
11258 #if 0
11259 seq->status->send_CB( seq , seq->getaux , &cbs ) ;
11260 #else
11261 SEND(seq,cbs) ;
11262 #endif
11263 if( cbs.xim < 0 || cbs.yim < 0 ){
11264 ix = jy = -1 ;
11265 } else {
11266 ISQ_unflipxy( seq , &(cbs.xim) , &(cbs.yim) ) ;
11267 ix = cbs.xim ; jy = cbs.yim ;
11268 }
11269 }
11270
11271 /* plot the data */
11272
11273 mp = plot_image_surface( seq->orim , (seq->surfgraph_num == 2) ? -1.0 : 1.0 ,
11274 seq->surfgraph_theta , seq->surfgraph_phi ,
11275 ix , jy ) ;
11276 if( mp == NULL ) EXRETURN ;
11277
11278 /* if there is a plot window open, plot into it, otherwise open a new window */
11279
11280 if( seq->surfgraph_mtd != NULL ){
11281
11282 MTD_replace_plotdata( seq->surfgraph_mtd , mp ) ;
11283 redraw_topshell( seq->surfgraph_mtd ) ;
11284
11285 } else { /* make a new plot window */
11286
11287 seq->surfgraph_mtd = memplot_to_topshell( seq->dc->display, mp, ISQ_surfgraph_mtdkill ) ;
11288
11289 if( seq->surfgraph_mtd == NULL ){ delete_memplot(mp); EXRETURN; }
11290
11291 seq->surfgraph_mtd->userdata = (void *)seq ;
11292
11293 /* add an arrowpad to it (lower right corner) */
11294
11295 WAIT_for_window(seq->surfgraph_mtd->top) ;
11296
11297 seq->surfgraph_arrowpad = new_MCW_arrowpad( seq->surfgraph_mtd->form ,
11298 ISQ_surfgraph_arrowpad_CB ,
11299 (XtPointer)seq ) ;
11300
11301 /* XtUnmanageChild( seq->surfgraph_arrowpad->wform ) ; */
11302
11303 XtVaSetValues( seq->surfgraph_arrowpad->wform ,
11304 XmNbottomAttachment , XmATTACH_FORM ,
11305 XmNrightAttachment , XmATTACH_FORM ,
11306 XmNleftAttachment , XmATTACH_NONE ,
11307 XmNtopAttachment , XmATTACH_NONE ,
11308 XmNwidth , 60 ,
11309 XmNheight , 60 ,
11310 NULL ) ;
11311
11312 MCW_set_widget_bg( seq->surfgraph_arrowpad->wform , "white" , 0 ) ;
11313
11314 XtManageChild( seq->surfgraph_arrowpad->wform ) ;
11315
11316 seq->surfgraph_arrowpad->parent = (XtPointer)seq ;
11317 seq->surfgraph_arrowpad->fastdelay = MCW_AV_longdelay ;
11318 }
11319
11320 EXRETURN ;
11321 }
11322
11323 /*-----------------------------------------------------------*/
11324 /*--- Called when the user kills the surface graph window ---*/
11325
ISQ_surfgraph_mtdkill(MEM_topshell_data * mp)11326 void ISQ_surfgraph_mtdkill( MEM_topshell_data *mp )
11327 {
11328 MCW_imseq *seq ;
11329
11330 ENTRY("ISQ_surfgraph_mtdkill") ;
11331
11332 if( mp == NULL ) EXRETURN ;
11333 seq = (MCW_imseq *) mp->userdata ; if( ! ISQ_VALID(seq) ) EXRETURN ;
11334
11335 seq->surfgraph_mtd = NULL ;
11336 seq->surfgraph_theta = DEFAULT_THETA ;
11337 seq->surfgraph_phi = DEFAULT_PHI ;
11338 myXtFree( seq->surfgraph_arrowpad ) ;
11339
11340 seq->surfgraph_num = 0 ;
11341 AV_assign_ival( seq->surfgraph_av , 0 ) ;
11342 EXRETURN ;
11343 }
11344
11345 /*--- actually draws an image to a wiremesh, in memory ---*/
11346
plot_image_surface(MRI_IMAGE * im,float fac,float theta,float phi,int ix,int jy)11347 MEM_plotdata * plot_image_surface( MRI_IMAGE *im , float fac ,
11348 float theta , float phi , int ix , int jy )
11349 {
11350 MRI_IMAGE *fim , *qim ;
11351 MEM_plotdata *mp ;
11352 float *x , *y , *z ;
11353 float dx , dy , zbot,ztop ;
11354 int ii , nx , ny , nxy ;
11355 char str[128] ;
11356
11357 ENTRY("plot_image_surface") ;
11358
11359 if( im == NULL ) RETURN( NULL );
11360
11361 /*-- setup to plot --*/
11362
11363 nx = im->nx ; ny = im->ny ;
11364 if( nx < 3 || ny < 3 ) RETURN( NULL );
11365
11366 create_memplot_surely( "imsurf" , 1.1 ) ;
11367
11368 dx = im->dx ; if( dx <= 0.0 ) dx = 1.0 ;
11369 dy = im->dy ; if( dy <= 0.0 ) dy = 1.0 ;
11370
11371 x = (float *) malloc( sizeof(float) * nx ) ;
11372 for( ii=0 ; ii < nx ; ii++ ) x[ii] = ii * dx ;
11373
11374 y = (float *) malloc( sizeof(float) * ny ) ;
11375 for( ii=0 ; ii < ny ; ii++ ) y[ii] = ii * dy ;
11376
11377 (void)thd_floatscan( nx , x ) ;
11378 (void)thd_floatscan( ny , y ) ;
11379
11380 /*-- scale image data --*/
11381
11382 qim = mri_flippo( MRI_ROT_180 , 1 , im ) ;
11383 if( fac == 1.0 || fac == 0.0 ) fim = mri_to_float(qim) ;
11384 else fim = mri_scale_to_float(fac,qim) ;
11385 z = MRI_FLOAT_PTR(fim) ; mri_free(qim) ;
11386 nxy = nx * ny ; zbot = ztop = z[0] ;
11387 for( ii=1 ; ii < nxy ; ii++ ){
11388 if( z[ii] < zbot ) zbot = z[ii] ;
11389 else if( z[ii] > ztop ) ztop = z[ii] ;
11390 }
11391 ztop = ztop - zbot ;
11392 if( ztop > 0.0 ){
11393 ztop = 0.85 * sqrt( x[nx-1] * y[ny-1] ) / ztop ;
11394 for( ii=0 ; ii < nxy ; ii++ ) z[ii] = (z[ii]-zbot) * ztop ;
11395 }
11396
11397 /*-- plot surface --*/
11398
11399 set_color_memplot( 0.0 , 0.0 , 0.0 ) ;
11400 set_thick_memplot( 0.0 ) ;
11401 plotpak_srface( x , y , z , nx , ny , theta, phi ) ;
11402
11403 /*-- plot a * at the selected point (if it is in range) --*/
11404
11405 if( ix >= 0 && ix < nx && jy >= 0 && jy < ny ){
11406 real xi,yi,zi ; float xt,yt,zt , xtp,ytp,ztp ;
11407 ii = 1 ;
11408 xi = x[ix] ; yi = y[ny-1-jy] ; zi = z[ix+(ny-1-jy)*nx] ;
11409 (void) trn32s_( &xi , &yi , &zi ,
11410 (real *)(&xt) , (real *)(&yt) , (real *)(&zt) ,
11411 (integer *)(&ii) ) ;
11412
11413 #undef THIK
11414 #define THIK 0.00333
11415
11416 dx = 0.016 * x[nx-1] ; dy = 0.016 * y[ny-1] ; dx = MAX(dx,dy) ;
11417 xi = x[ix]+dx ; yi = y[ny-1-jy]+dx ; zi = z[ix+(ny-1-jy)*nx] ;
11418 (void) trn32s_( &xi , &yi , &zi ,
11419 (real *)(&xtp) , (real *)(&ytp) , (real *)(&ztp) ,
11420 (integer *)(&ii) ) ;
11421 dx = fabs(xtp-xt) ; dy = fabs(ytp-yt) ; dx = MAX(dx,dy) ;
11422
11423 set_color_memplot( 0.8 , 0.0 , 0.2 ) ;
11424 set_thick_memplot( THIK ) ;
11425 plotpak_line( xt-dx , yt , xt+dx , yt ) ; /* - stroke */
11426 plotpak_line( xt , yt-dx , xt , yt+dx ) ; /* | stroke */
11427 plotpak_line( xt-dx , yt-dx , xt+dx , yt+dx ) ; /* / stroke */
11428 plotpak_line( xt+dx , yt-dx , xt-dx , yt+dx ) ; /* \ stroke */
11429 set_color_memplot( 0.2 , 0.0 , 0.8 ) ;
11430 plotpak_line( xt+dx , yt-dx , xt+dx , yt+dx ) ; /* box around outside */
11431 plotpak_line( xt+dx , yt+dx , xt-dx , yt+dx ) ;
11432 plotpak_line( xt-dx , yt+dx , xt-dx , yt-dx ) ;
11433 plotpak_line( xt-dx , yt-dx , xt+dx , yt-dx ) ;
11434 set_color_memplot( 0.0 , 0.0 , 0.0 ) ;
11435 set_thick_memplot( 0.0 ) ;
11436 }
11437
11438 free(x); free(y) ; mri_free(fim);
11439
11440 plotpak_set( 0.0,1.0 , 0.0,1.0 , 0.0,1.0 , 0.0,1.0 , 1 ) ;
11441 sprintf(str,"\\theta=%.0f\\degree \\phi=%.0f\\degree",theta,phi) ;
11442 plotpak_pwritf( 1.099 , 0.97 , str, 19 , 0 , 1 ) ;
11443
11444 mp = get_active_memplot() ; RETURN( mp );
11445 }
11446
11447 /*--- called when the user presses a surface graph arrowpad button ---*/
11448
ISQ_surfgraph_arrowpad_CB(MCW_arrowpad * apad,XtPointer client_data)11449 void ISQ_surfgraph_arrowpad_CB( MCW_arrowpad *apad , XtPointer client_data )
11450 {
11451 MCW_imseq *seq = (MCW_imseq *) client_data ;
11452 XButtonEvent *xev = (XButtonEvent *) &(apad->xev) ;
11453 float step = 10.0 ;
11454
11455 ENTRY("ISQ_surfgraph_arrowpad_CB") ;
11456
11457 if( ! ISQ_REALZ(seq) ) EXRETURN ; /* error */
11458
11459 if( ( xev->type == ButtonPress || xev->type == ButtonRelease ) ){
11460 if( xev->state & (ShiftMask|ControlMask) ) step = 90.0 ; /* big step */
11461 if( xev->state & Mod1Mask ) step = 2.0 ; /* small step */
11462 }
11463
11464 switch( apad->which_pressed ){
11465 case AP_MID: seq->surfgraph_theta = DEFAULT_THETA ;
11466 seq->surfgraph_phi = DEFAULT_PHI ; break ;
11467
11468 case AP_DOWN: seq->surfgraph_theta += step ; break ;
11469 case AP_UP: seq->surfgraph_theta -= step ; break ;
11470 case AP_LEFT: seq->surfgraph_phi += step ; break ;
11471 case AP_RIGHT: seq->surfgraph_phi -= step ; break ;
11472
11473 default: EXRETURN ; /* error */
11474 }
11475
11476 while( seq->surfgraph_theta < 0.0 ) seq->surfgraph_theta += 360.0 ;
11477 while( seq->surfgraph_theta >= 360.0 ) seq->surfgraph_theta -= 360.0 ;
11478
11479 while( seq->surfgraph_phi < 0.0 ) seq->surfgraph_phi += 360.0 ;
11480 while( seq->surfgraph_phi >= 360.0 ) seq->surfgraph_phi -= 360.0 ;
11481
11482 ISQ_surfgraph_draw( seq ) ; EXRETURN ;
11483 }
11484
11485 /*-----------------------------------------------------------------------
11486 24 Apr 2001: remove a widget from the onoff list,
11487 and permanently unmanage it (for the recorder)
11488 -------------------------------------------------------------------------*/
11489
ISQ_remove_widget(MCW_imseq * seq,Widget w)11490 void ISQ_remove_widget( MCW_imseq *seq , Widget w )
11491 {
11492 int ii ;
11493 ENTRY("ISQ_remove_onoff") ;
11494
11495 if( !ISQ_VALID(seq) || w == NULL ) EXRETURN ;
11496
11497 XtUnmanageChild( w ) ; /* turn it off */
11498
11499 for( ii=0 ; ii < seq->onoff_num ; ii++ ){ /* find in list */
11500 if( w == seq->onoff_widgets[ii] ){
11501 seq->onoff_widgets[ii] = NULL ;
11502 break ;
11503 }
11504 }
11505
11506 for( ii=seq->onoff_num-1 ; ii > 0 ; ii-- ){ /* truncate list */
11507 if( seq->onoff_widgets[ii] == NULL )
11508 seq->onoff_num = ii ;
11509 else
11510 break ;
11511 }
11512
11513 EXRETURN ;
11514 }
11515
11516 /*-----------------------------------------------------------------------
11517 24 Apr 2001: recording button and accoutrements
11518 -------------------------------------------------------------------------*/
11519
ISQ_record_button(MCW_imseq * seq)11520 void ISQ_record_button( MCW_imseq *seq )
11521 {
11522 Widget rc , mbar , menu , cbut , wpar ;
11523 XmString xstr ;
11524
11525 ENTRY("ISQ_record_button") ;
11526
11527 /*--- make the widgets ---*/
11528
11529 /* rowcol to hold the menubar */
11530
11531 seq->onoff_widgets[(seq->onoff_num)++] = seq->record_rc = rc =
11532 XtVaCreateWidget(
11533 "imseq" , xmRowColumnWidgetClass , seq->wform ,
11534 XmNorientation , XmHORIZONTAL ,
11535 XmNpacking , XmPACK_TIGHT ,
11536
11537 LEADING_BOT , XmATTACH_WIDGET ,
11538 LEADING_WIDGET_BOT, seq->wbut_bot[NBUTTON_BOT-1] ,
11539 EDGING_BOT , XmATTACH_FORM ,
11540
11541 XmNmarginWidth , 1 ,
11542 XmNmarginHeight , 0 ,
11543 XmNmarginBottom , 0 ,
11544 XmNmarginTop , 0 ,
11545 XmNmarginLeft , 0 ,
11546 XmNmarginRight , 0 ,
11547 XmNspacing , 0 ,
11548 XmNborderWidth , 0 ,
11549 XmNborderColor , 0 ,
11550
11551 XmNrecomputeSize , False ,
11552 XmNtraversalOn , False ,
11553 XmNinitialResourcesPersistent , False ,
11554 NULL ) ;
11555
11556 /* menubar to hold the cascade button */
11557
11558 mbar = XmCreateMenuBar( rc , "imseq" , NULL,0 ) ;
11559 XtVaSetValues( mbar ,
11560 XmNmarginWidth , 1 ,
11561 XmNmarginHeight , 0 ,
11562 XmNmarginBottom , 0 ,
11563 XmNmarginTop , 0 ,
11564 XmNmarginLeft , 0 ,
11565 XmNmarginRight , 0 ,
11566 XmNspacing , 0 ,
11567 XmNborderWidth , 0 ,
11568 XmNborderColor , 0 ,
11569 XmNtraversalOn , False ,
11570 XmNbackground , seq->dc->ovc->pixov_brightest ,
11571 NULL ) ;
11572
11573 /* the menu pane */
11574
11575 menu = XmCreatePulldownMenu( mbar , "menu" , NULL,0 ) ;
11576 VISIBILIZE_WHEN_MAPPED(menu) ;
11577 #if 0 /* doesn't work well */
11578 if( !AFNI_yesenv("AFNI_DISABLE_TEAROFF") ) TEAROFFIZE(menu) ;
11579 #endif
11580
11581 /* the cascade button (what the user sees) */
11582
11583 xstr = XmStringCreateLtoR( "Rec" , XmFONTLIST_DEFAULT_TAG ) ;
11584 seq->record_cbut = cbut =
11585 XtVaCreateManagedWidget(
11586 "imseq" , xmCascadeButtonWidgetClass , mbar ,
11587 XmNlabelString , xstr ,
11588 XmNsubMenuId , menu ,
11589 XmNmarginWidth , 1 ,
11590 XmNmarginHeight, 0 ,
11591 XmNmarginBottom, 0 ,
11592 XmNmarginTop , 0 ,
11593 XmNmarginRight , 0 ,
11594 XmNmarginLeft , 0 ,
11595 XmNtraversalOn , False ,
11596 XmNinitialResourcesPersistent , False ,
11597 NULL ) ;
11598 XmStringFree( xstr ) ;
11599 XtManageChild( mbar ) ;
11600 MCW_register_hint( cbut , "Turn image recording on/off" ) ;
11601 MCW_register_help( cbut ,
11602 " \n"
11603 "This menu controls image recording. Whenever the image\n"
11604 "displayed is altered, an RGB copy of it can be saved\n"
11605 "into a separate image buffer. In this way, you can\n"
11606 "build a sequence of images that can later be written\n"
11607 "to disk for further processing (e.g., animation).\n"
11608 "\n"
11609 "---- These options control WHEN images ----\n"
11610 "---- will be recorded into the sequence ----\n"
11611 "\n"
11612 " Off = don't record\n"
11613 " Next One = record next image, then turn Off\n"
11614 " Stay On = record all images\n"
11615 "\n"
11616 "---- These options control WHERE new images ----\n"
11617 "---- are to be stored into the sequence ----\n"
11618 "\n"
11619 " After End = at tail of sequence\n"
11620 " Before Start = at head of sequence\n"
11621 " Insert -- = insert before current sequence position\n"
11622 " Insert ++ = insert after current sequence position\n"
11623 " OverWrite = replace current sequence position\n"
11624 " -- OverWrite = replace image before current position\n"
11625 " ++ OverWrite = replace image after current position\n"
11626 "\n"
11627 "---- HINTS and NOTES ----\n"
11628 "\n"
11629 "* You may want to set Xhairs to 'Off' on the AFNI\n"
11630 " control panel before recording images.\n"
11631 "* The recording window is like a dataset image\n"
11632 " viewing window with most controls removed.\n"
11633 " The slider moves between recorded images, rather\n"
11634 " than between slices.\n"
11635 "* The new 'Kill' button in the recording window lets\n"
11636 " you erase one image from the recorded sequence.\n"
11637 " Erased images, if not overwritten, will NOT be\n"
11638 " saved to disk.\n"
11639 "* Use 'Save:bkg' in the recording window to save the\n"
11640 " sequence of recorded images to disk in PPM format.\n"
11641 " The recorded images are in color, and will be saved\n"
11642 " in color (despite the :bkg label on the Save button).\n"
11643 "* You may want to use set 'Warp Anat on Demand' on\n"
11644 " the Datamode control panel to force the display\n"
11645 " voxels to be cubical. Otherwise, the saved image\n"
11646 " pixels will have the same aspect ratio as the voxels\n"
11647 " in the dataset, which may not be square!\n"
11648 ) ;
11649
11650 /*-- top of menu = a label to click on that does nothing at all --*/
11651
11652 /* This --- Cancel --- label does not cause the hangup, so it is
11653 left alone. See related comments in afni_graph.c LessTif patrol, Jan 07 09 */
11654
11655 xstr = XmStringCreateLtoR( "-- Cancel --" , XmFONTLIST_DEFAULT_TAG ) ;
11656 wwtem = XtVaCreateManagedWidget(
11657 "menu" , xmLabelWidgetClass , menu ,
11658 XmNlabelString , xstr ,
11659 XmNrecomputeSize , False ,
11660 XmNinitialResourcesPersistent , False ,
11661 NULL ) ;
11662 XmStringFree(xstr) ; LABELIZE(wwtem) ;
11663
11664 (void) XtVaCreateManagedWidget(
11665 "menu" , xmSeparatorWidgetClass , menu ,
11666 XmNseparatorType , XmSINGLE_LINE ,
11667 NULL ) ;
11668
11669 /*-- menu toggles switches --*/
11670
11671 { static char *status_label[3] = { "Off" , "Next One" , "Stay On" } ;
11672 static char *method_label[7] = { "After End" ,
11673 "Before Start" ,
11674 "Insert --" ,
11675 "Insert ++" ,
11676 "OverWrite" ,
11677 "-- OverWrite" ,
11678 "++ OverWrite" } ;
11679
11680 seq->record_status_bbox =
11681 new_MCW_bbox( menu , 3,status_label ,
11682 MCW_BB_radio_one , MCW_BB_noframe ,
11683 ISQ_record_CB , (XtPointer) seq ) ;
11684 seq->record_status = RECORD_STATUS_OFF ;
11685
11686 (void) XtVaCreateManagedWidget(
11687 "menu" , xmSeparatorWidgetClass , menu ,
11688 XmNseparatorType , XmSINGLE_LINE ,
11689 NULL ) ;
11690
11691 seq->record_method_bbox =
11692 new_MCW_bbox( menu , 7,method_label ,
11693 MCW_BB_radio_one , MCW_BB_noframe ,
11694 ISQ_record_CB , (XtPointer) seq ) ;
11695 seq->record_method = RECORD_METHOD_AFTEREND ;
11696 }
11697
11698 /*-- done with Widgets --*/
11699
11700 XtManageChild( rc ) ;
11701
11702 /*-- setup other variables --*/
11703
11704 seq->record_mode = 0 ; /* not a recorder itself (yet) */
11705 seq->record_imseq = NULL ; /* doesn't have a recorder */
11706 seq->record_imarr = NULL ; /* doesn't have a recorded sequence */
11707 seq->record_mplot = NULL ; /* 05 Jan 2005 */
11708
11709 EXRETURN ;
11710 }
11711
11712 /*-----------------------------------------------------------------------
11713 Callback for toggle actions in the record menu
11714 -------------------------------------------------------------------------*/
11715
ISQ_record_CB(Widget w,XtPointer client_data,XtPointer call_data)11716 void ISQ_record_CB( Widget w, XtPointer client_data, XtPointer call_data )
11717 {
11718 MCW_imseq *seq = (MCW_imseq *) client_data ;
11719 int ib ;
11720
11721 ENTRY("ISQ_record_CB") ;
11722
11723 if( !ISQ_REALZ(seq) ) EXRETURN ;
11724
11725 ib = MCW_val_bbox( seq->record_status_bbox ) ;
11726 if( ib != seq->record_status ){
11727 if( RECORD_ISON(ib) != RECORD_ISON(seq->record_status) )
11728 MCW_invert_widget( seq->record_cbut ) ;
11729 seq->record_status = ib ;
11730 }
11731
11732 ib = MCW_val_bbox( seq->record_method_bbox ) ;
11733 if( ib != seq->record_method ){
11734 seq->record_method = ib ;
11735 }
11736
11737 EXRETURN ;
11738 }
11739
11740 /*----------------------------------------------------------------------
11741 Insert the current image from seq into seq's recorder, at index pos,
11742 with method meth: -1 => insert before pos
11743 +1 => insert after pos
11744 0 => overwrite pos
11745 If pos < 0, then it means
11746 -1 => current position
11747 -2 => before current position
11748 -3 => after current position
11749 If pos >= 0, then it is an index into the recorded image sequence.
11750 If it is past the end of the sequence, then it means the end.
11751 The recorder is left positioned at the new image.
11752 ------------------------------------------------------------------------*/
11753
ISQ_record_addim(MCW_imseq * seq,int pos,int meth)11754 void ISQ_record_addim( MCW_imseq *seq , int pos , int meth )
11755 {
11756 MRI_IMAGE *tim ;
11757 int opos , ii,bot,top ;
11758
11759 ENTRY("ISQ_record_addim") ;
11760
11761 /* sanity checks */
11762
11763 if( !ISQ_REALZ(seq) ||
11764 seq->record_mode ||
11765 seq->given_xim == NULL ) EXRETURN; /* bad */
11766
11767 /* if recorded image sequence doesn't exist, create it */
11768
11769 if( seq->record_imarr == NULL ){
11770 INIT_IMARR(seq->record_imarr) ;
11771 meth = 1 ; /* change meth for this special case */
11772
11773 seq->record_mplot = NULL ; /* 05 Jan 2005 */
11774 }
11775
11776 /* convert current XImage to RGB format */
11777
11778 tim = XImage_to_mri( seq->dc, seq->given_xim, X2M_USE_CMAP|X2M_FORCE_RGB );
11779
11780 if( tim == NULL ) EXRETURN ; /* bad */
11781
11782 /* figure out where to put this image in the list */
11783
11784 opos = pos ;
11785 if( opos < 0 ){ /* need current position of recorder */
11786
11787 if( seq->record_imseq != NULL ){
11788 drive_MCW_imseq( seq->record_imseq, isqDR_getimnr, (XtPointer)&opos );
11789 if( pos == -2 && opos > 0 ) opos--;
11790 else if( pos == -3 && opos < IMARR_COUNT(seq->record_imarr)-1 ) opos++;
11791 }
11792 else
11793 opos = -1 ; /* special case */
11794
11795 } else if( opos >= IMARR_COUNT(seq->record_imarr)-1 ) {
11796
11797 opos = IMARR_COUNT(seq->record_imarr)-1 ;
11798 }
11799
11800 if( opos < 0 ) meth = 1 ; /* special case: sequence is empty now */
11801
11802 /* if we are inserting, we need to add an image */
11803
11804 if( meth != 0 ){
11805
11806 ADDTO_IMARR( seq->record_imarr , NULL ) ; /* add at end */
11807 seq->record_mplot =(MEM_plotdata **) /* 05 Jan 2005 */
11808 realloc( (void *)seq->record_mplot ,
11809 sizeof(MEM_plotdata *)
11810 *IMARR_COUNT(seq->record_imarr) ) ;
11811 bot = (meth < 0) ? opos : opos+1 ; /* move images up */
11812 top = IMARR_COUNT(seq->record_imarr)-2 ;
11813 for( ii=top ; ii >= bot ; ii-- ){
11814 IMARR_SUBIM(seq->record_imarr,ii+1) = IMARR_SUBIM(seq->record_imarr,ii);
11815 seq->record_mplot[ii+1] = seq->record_mplot[ii] ; /* 05 Jan 2005 */
11816 }
11817
11818 IMARR_SUBIM(seq->record_imarr,bot) = tim ; /* insert */
11819 seq->record_mplot[bot] = copy_memplot( seq->mplot ) ;
11820
11821 } else { /* overwrite image */
11822
11823 bot = opos ;
11824 mri_free( IMARR_SUBIM(seq->record_imarr,bot) ) ; /* out with the old */
11825 IMARR_SUBIM(seq->record_imarr,bot) = tim ; /* in with the new */
11826
11827 delete_memplot( seq->record_mplot[bot] ) ; /* 05 Jan 2005 */
11828 seq->record_mplot[bot] = copy_memplot( seq->mplot ) ;
11829 }
11830
11831 /* at this point, we have put the new image into location bot in the array */
11832
11833 /* if the recorder isn't open now, open it, otherwise update it */
11834
11835 if( seq->record_imseq == NULL )
11836 ISQ_record_open( seq ) ;
11837 else
11838 ISQ_record_update( seq , bot ) ;
11839
11840 EXRETURN ;
11841 }
11842
11843 /*-----------------------------------------------------------------------*/
11844
ISQ_record_open(MCW_imseq * seq)11845 void ISQ_record_open( MCW_imseq *seq )
11846 {
11847 int ntot ;
11848
11849 ENTRY("ISQ_record_open") ;
11850
11851 if( !ISQ_REALZ(seq) ||
11852 seq->record_imarr == NULL ||
11853 IMARR_COUNT(seq->record_imarr) == 0 ) EXRETURN ;
11854
11855 ntot = IMARR_COUNT(seq->record_imarr) ;
11856
11857 seq->record_imseq = open_MCW_imseq( seq->dc , ISQ_record_getim , seq ) ;
11858 seq->record_imseq->parent = seq ;
11859
11860 drive_MCW_imseq( seq->record_imseq , isqDR_record_mode , NULL ) ;
11861
11862 drive_MCW_imseq( seq->record_imseq , isqDR_realize, NULL ) ;
11863
11864 #ifndef DONT_ONOFF_ONE
11865 if( ntot == 1 )
11866 drive_MCW_imseq( seq->record_imseq,isqDR_onoffwid,(XtPointer)isqDR_offwid);
11867 else
11868 drive_MCW_imseq( seq->record_imseq,isqDR_onoffwid,(XtPointer)isqDR_onwid );
11869 #endif
11870
11871 drive_MCW_imseq( seq->record_imseq , isqDR_reimage , (XtPointer)ITOP(ntot-1) ) ;
11872
11873 ISQ_set_cursor_state( seq , -1 ) ; /* 10 Mar 2003 */
11874 NORMAL_cursorize( seq->wbar ) ;
11875
11876 EXRETURN ;
11877 }
11878
11879 /*-----------------------------------------------------------------------*/
11880
ISQ_record_update(MCW_imseq * seq,int npos)11881 void ISQ_record_update( MCW_imseq *seq , int npos )
11882 {
11883 int ntot , ii ;
11884
11885 ENTRY("ISQ_record_update") ;
11886
11887 if( !ISQ_REALZ(seq) ||
11888 seq->record_imseq == NULL ||
11889 seq->record_imarr == NULL ||
11890 IMARR_COUNT(seq->record_imarr) == 0 ) EXRETURN ;
11891
11892 ntot = IMARR_COUNT(seq->record_imarr) ;
11893
11894 if( npos < 0 ) npos = 0 ;
11895 else if( npos >= ntot ) npos = ntot-1 ;
11896
11897 drive_MCW_imseq( seq->record_imseq , isqDR_newseq , seq ) ;
11898
11899 #ifndef DONT_ONOFF_ONE
11900 if( ntot == 1 )
11901 drive_MCW_imseq( seq->record_imseq,isqDR_onoffwid,(XtPointer)ITOP(isqDR_offwid));
11902 else
11903 drive_MCW_imseq( seq->record_imseq,isqDR_onoffwid,(XtPointer)ITOP(isqDR_onwid) );
11904 #endif
11905
11906 drive_MCW_imseq( seq->record_imseq , isqDR_reimage , (XtPointer)ITOP(npos) ) ;
11907
11908 EXRETURN ;
11909 }
11910
11911 /*------------------------------------------------------------------
11912 Routine to provide data to the recording imseq.
11913 Just returns the control information, or the selected image.
11914 --------------------------------------------------------------------*/
11915
ISQ_record_getim(int n,int type,XtPointer handle)11916 XtPointer ISQ_record_getim( int n , int type , XtPointer handle )
11917 {
11918 int ntot = 0 ;
11919 MCW_imseq *seq = (MCW_imseq *) handle ; /* parent of recorder */
11920
11921 ENTRY("ISQ_record_getim") ;
11922
11923 if( seq->record_imarr != NULL ) ntot = IMARR_COUNT(seq->record_imarr) ;
11924 if( ntot < 1 ) ntot = 1 ;
11925
11926 /*--- send control info ---*/
11927
11928 if( type == isqCR_getstatus ){
11929 MCW_imseq_status *stat = myXtNew( MCW_imseq_status ); /* will be free-d */
11930 /* when imseq is */
11931 /* destroyed */
11932 stat->num_total = ntot ;
11933 stat->num_series = stat->num_total ;
11934 stat->send_CB = ISQ_record_send_CB ;
11935 stat->parent = NULL ;
11936 stat->aux = NULL ;
11937
11938 stat->transforms0D = NULL ;
11939 stat->transforms2D = NULL ;
11940
11941 RETURN( (XtPointer)stat ) ;
11942 }
11943
11944 /*--- overlay [05 Jan 2005] ---*/
11945
11946 if( type == isqCR_getoverlay ) RETURN(NULL) ; /* no image overlay */
11947
11948 if( type == isqCR_getmemplot ){ /* graphics overlay */
11949 MEM_plotdata *mp ;
11950 if( seq->record_mplot == NULL ) RETURN(NULL) ;
11951 if( n < 0 ) n = 0 ; else if( n >= ntot ) n = ntot-1 ;
11952 mp = copy_memplot( seq->record_mplot[n] ) ;
11953 RETURN( (XtPointer)mp ) ; /* may be NULL */
11954 }
11955
11956 /*--- return a copy of a recorded image
11957 (since the imseq will delete it when it is done) ---*/
11958
11959 if( type == isqCR_getimage || type == isqCR_getqimage ){
11960 MRI_IMAGE *im = NULL , *rim ;
11961
11962 if( seq->record_imarr != NULL ){
11963 if( n < 0 ) n = 0 ; else if( n >= ntot ) n = ntot-1 ;
11964 rim = IMARR_SUBIMAGE(seq->record_imarr,n) ;
11965 if( rim != NULL ) im = mri_to_rgb( rim ) ;
11966 }
11967 RETURN( (XtPointer)im ) ;
11968 }
11969
11970 RETURN( NULL ) ; /* should not occur, but who knows? */
11971 }
11972
11973 /*---------------------------------------------------------------------------
11974 Routine called when the recording imseq wants to send a message.
11975 In this case, all we need to handle is the destroy message,
11976 so that we can free some memory.
11977 -----------------------------------------------------------------------------*/
11978
ISQ_record_send_CB(MCW_imseq * seq,XtPointer handle,ISQ_cbs * cbs)11979 void ISQ_record_send_CB( MCW_imseq *seq , XtPointer handle , ISQ_cbs *cbs )
11980 {
11981 ENTRY("ISQ_record_send_CB") ;
11982
11983 switch( cbs->reason ){
11984
11985 case isqCR_destroy:{
11986 MCW_imseq *pseq = (MCW_imseq *) seq->parent ;
11987
11988 /* turn off recording in the parent */
11989
11990 pseq->record_imseq = NULL ;
11991 if( pseq->record_mplot != NULL && pseq->record_imarr != NULL ){
11992 int ib ;
11993 for( ib=0 ; ib < IMARR_COUNT(pseq->record_imarr) ; ib++ )
11994 delete_memplot( pseq->record_mplot[ib] ) ;
11995 free((void *)pseq->record_mplot) ; pseq->record_mplot = NULL ;
11996 }
11997 if( pseq->record_imarr != NULL ) DESTROY_IMARR(pseq->record_imarr) ;
11998 if( RECORD_ISON(pseq->record_status) ){
11999 pseq->record_status = RECORD_STATUS_OFF ;
12000 MCW_set_bbox( pseq->record_status_bbox , RECORD_STATUS_OFF ) ;
12001 MCW_invert_widget( pseq->record_cbut ) ;
12002 }
12003
12004 /* can now clean out the recording imseq */
12005
12006 myXtFree(seq->status) ; myXtFree(seq) ;
12007 }
12008 break ;
12009
12010 }
12011
12012 EXRETURN ;
12013 }
12014
12015 /*----------------------------------------------------------------------------*/
12016
ISQ_record_kill_CB(Widget w,XtPointer client_data,XtPointer call_data)12017 void ISQ_record_kill_CB( Widget w, XtPointer client_data, XtPointer call_data )
12018 {
12019 MCW_imseq *seq = (MCW_imseq *) client_data ;
12020 MCW_imseq *pseq ;
12021 int pos=-1 ;
12022
12023 ENTRY("ISQ_record_kill_CB") ;
12024
12025 if( !ISQ_REALZ(seq) || !seq->record_mode ) EXRETURN ; /* bad */
12026
12027 pseq = (MCW_imseq *) seq->parent ; /* the one driving this recorder */
12028
12029 if( pseq->record_imarr == NULL ) EXRETURN ; /* bad */
12030
12031 drive_MCW_imseq( seq , isqDR_getimnr, (XtPointer)&pos ) ; /* where am us? */
12032
12033 if( pos < 0 || pos >= IMARR_COUNT(pseq->record_imarr) ) EXRETURN ;
12034
12035 /* empty out the image in the recorded sequence */
12036
12037 mri_free( IMARR_SUBIM(pseq->record_imarr,pos) ) ;
12038 IMARR_SUBIM(pseq->record_imarr,pos) = NULL ;
12039 delete_memplot( pseq->record_mplot[pos] ) ; /* 05 Jan 2005 */
12040 pseq->record_mplot[pos] = NULL ;
12041
12042 ISQ_redisplay( seq , -1 , isqDR_display ) ; /* show the empty image */
12043
12044 EXRETURN ;
12045 }
12046
12047 /*---------------------------------------------------------------------
12048 Handle the user's action on the Button 3 popup on the Save: button
12049 -----------------------------------------------------------------------*/
12050
ISQ_butsave_choice_CB(Widget w,XtPointer client_data,MCW_choose_cbs * cbs)12051 void ISQ_butsave_choice_CB( Widget w , XtPointer client_data ,
12052 MCW_choose_cbs *cbs )
12053 {
12054 MCW_imseq *seq = (MCW_imseq *) client_data ;
12055 int pp , agif_ind=0 , mpeg_ind=0 , nstr ;
12056
12057 if( !ISQ_REALZ(seq) ||
12058 cbs->reason != mcwCR_integer ||
12059 seq->dialog_starter==NBUT_DISP ){ /* bad things */
12060
12061 XBell(XtDisplay(w),100); POPDOWN_strlist_chooser ; return ;
12062 }
12063
12064 nstr = ppmto_num+1 ;
12065 if( ppmto_agif_filter != NULL ) agif_ind = nstr++ ;
12066 if( ppmto_mpeg_filter != NULL ) mpeg_ind = nstr++ ;
12067
12068 seq->opt.save_nsize = seq->opt.save_pnm
12069 = seq->opt.save_agif = seq->opt.save_mpeg = 0 ;
12070
12071 pp = cbs->ival ;
12072 if( pp == 0 ) seq->opt.save_filter=-1 ; /* Save:bkg */
12073 else if( pp <= ppmto_num ) seq->opt.save_filter=pp-1; /* Save.typ */
12074 else if( pp == agif_ind ) seq->opt.save_agif = 1 ; /* Sav:aGif */
12075 else if( pp == mpeg_ind ) seq->opt.save_mpeg = 1 ; /* Sav:mpeg */
12076
12077 if( ppmto_agif_filter == NULL ) seq->opt.save_agif = 0 ; /* 07 Apr 2005 */
12078 if( ppmto_mpeg_filter == NULL ) seq->opt.save_mpeg = 0 ;
12079
12080 SET_SAVE_LABEL(seq) ; return ;
12081 }
12082
12083 /*--------------------------------------------------------------------
12084 make Button 3 popup for Save button
12085 -- 27 Jul 2001: add stuff for animated GIF (ppmto_num+1 index)
12086 ----------------------------------------------------------------------*/
12087
ISQ_butsave_EV(Widget w,XtPointer client_data,XEvent * ev,RwcBoolean * continue_to_dispatch)12088 void ISQ_butsave_EV( Widget w , XtPointer client_data ,
12089 XEvent *ev , RwcBoolean *continue_to_dispatch )
12090 {
12091 MCW_imseq *seq = (MCW_imseq *) client_data ;
12092
12093 if( !ISQ_REALZ(seq) ) return ;
12094
12095 ISQ_timer_stop(seq) ;
12096
12097 switch( ev->type ){
12098 case ButtonPress:{
12099 XButtonEvent *event = (XButtonEvent *) ev ;
12100 if( event->button == Button3 ){
12101 char **strlist ; int pp , nstr , agif_ind=0 , mpeg_ind=0 ;
12102 if( seq->dialog_starter==NBUT_DISP ){XBell(XtDisplay(w),100); return; }
12103 strlist = (char **) malloc(sizeof(char *)*(ppmto_num+3)) ;
12104 strlist[0] = strdup("Save:bkg") ; /* special case */
12105 for( pp=0 ; pp < ppmto_num ; pp++ ){ /* filters */
12106 strlist[pp+1] = AFMALL( char, 16) ;
12107 sprintf(strlist[pp+1],"Save.%.3s",ppmto_suffix[pp]) ;
12108 }
12109 nstr = ppmto_num+1 ;
12110 if( ppmto_agif_filter != NULL ){
12111 agif_ind = nstr ;
12112 strlist[nstr++] = strdup("Sav:aGif") ; /* special case */
12113 }
12114 if( ppmto_mpeg_filter != NULL ){
12115 mpeg_ind = nstr ;
12116 strlist[nstr++] = strdup("Sav:mpeg") ; /* special case */
12117 }
12118 if(seq->opt.save_agif && agif_ind > 0 ) pp=agif_ind ;
12119 else if(seq->opt.save_mpeg && mpeg_ind > 0 ) pp=mpeg_ind ;
12120 else if(seq->opt.save_filter < 0) pp=0 ;
12121 else pp=seq->opt.save_filter+1 ;
12122 MCW_choose_strlist( w , "Image Save format" ,
12123 nstr , pp , strlist ,
12124 ISQ_butsave_choice_CB , (XtPointer) seq ) ;
12125 for( pp=0 ; pp < nstr ; pp++ ) free(strlist[pp]) ;
12126 free(strlist) ;
12127 } else if( event->button == Button2 ){
12128 XBell(XtDisplay(w),100) ;
12129 MCW_popup_message( w, " \n Ouch! \n ", MCW_USER_KILL|MCW_QUICK_KILL );
12130 /** AFNI_speak( "Ouch!" , 0 ) ; **/
12131 }
12132 }
12133 break ;
12134 }
12135 return ;
12136 }
12137
12138 /*--------------------------------------------------------------------------*/
12139 /*! Get the label for overlay. [11 Jun 2002]
12140 ----------------------------------------------------------------------------*/
12141
ISQ_getlabel(int nn,MCW_imseq * seq)12142 char * ISQ_getlabel( int nn , MCW_imseq *seq )
12143 {
12144 char *lab=NULL , *labadd=NULL ;
12145
12146 ENTRY("ISQ_getlabel") ;
12147
12148 #if 0
12149 lab = (char *) seq->getim( nn,isqCR_getlabel,seq->getaux );
12150 #else
12151 AFNI_CALL_VALU_3ARG( seq->getim , char *,lab ,
12152 int,nn , int,isqCR_getlabel , XtPointer,seq->getaux ) ;
12153 #endif
12154
12155 /* 23 Dec 2011: stuff to append to the label */
12156
12157 labadd = seq->overlay_label ;
12158
12159 if( labadd == NULL || *labadd == '\0' )
12160 labadd = getenv("AFNI_IMAGE_LABEL_STRING") ;
12161
12162 if( labadd != NULL && *labadd != '\0' ){
12163 if( lab == NULL ) lab = strdup(labadd) ;
12164 else {
12165 lab = (char *)realloc(lab,sizeof(char)*(strlen(lab)+strlen(labadd)+4)) ;
12166 strcat(lab,labadd) ;
12167 }
12168 }
12169
12170 RETURN(lab) ;
12171 }
12172
12173 /*--------------------------------------------------------------------------*/
12174 /*! Get the memplot for overlay. [11 Jun 2002]
12175 ----------------------------------------------------------------------------*/
12176
ISQ_getmemplot(int nn,MCW_imseq * seq)12177 MEM_plotdata * ISQ_getmemplot( int nn , MCW_imseq *seq )
12178 {
12179 MEM_plotdata *mp=NULL ;
12180 int ntic ;
12181
12182 ENTRY("ISQ_getmemplot") ;
12183
12184 #if 0
12185 mp = (MEM_plotdata *) seq->getim( nn,isqCR_getmemplot,seq->getaux );
12186 #else
12187 AFNI_CALL_VALU_3ARG( seq->getim , MEM_plotdata *,mp ,
12188 int,nn , int,isqCR_getmemplot , XtPointer,seq->getaux ) ;
12189 #endif
12190
12191 if( mp != NULL && seq->cropit ){ /* scale memplot for cropping region */
12192 float sx,sy,tx,ty ;
12193 float xa=seq->crop_xa, xb=seq->crop_xb, ya=seq->crop_ya, yb=seq->crop_yb ;
12194 float nxorg=seq->crop_nxorg , nyorg=seq->crop_nyorg ;
12195 MEM_plotdata *np ;
12196
12197 if( xb >= nxorg ) xb = nxorg-1 ;
12198 if( yb >= nyorg ) yb = nyorg-1 ;
12199
12200 /**
12201 Original plot has [0..1]x[0..1] mapped to [0..nxorg]x[nyorg..0].
12202 Now, image will be cropped to [xa..xb]x[ya..yb], which will be
12203 mapped from plot coords [0..1]x[1..0]. So we need to transform
12204 plot coords so that the new
12205 x_plot=0 is at x_image=xa
12206 x_plot=1 is at x_image=xb
12207 y_plot=0 is at y_image=yb
12208 y_plot=1 is at y_image=ya
12209
12210 Input: x_plot = x_image / nxorg
12211 y_plot = 1 - y_image / nyorg
12212
12213 Output: x_plot' = sx * x_plot + tx > This is done in
12214 y_plot' = sy * y_plot + ty > scale_memplot function
12215
12216 Find sx,tx so that x_plot'[x_image=xa ]=0 and x_plot'[x_image=xb+1]=1.
12217 Find sy,ty so that y_plot'[y_image=yb+1]=0 and y_plot'[y_image=ya ]=1.
12218 **/
12219
12220 sx = nxorg / (xb+1-xa) ;
12221 tx = -sx * xa / nxorg ;
12222
12223 sy = nyorg / (yb+1-ya) ;
12224 ty = -sy * (1.0 - (yb+1) / nyorg) ;
12225
12226 scale_memplot( sx,tx , sy,ty , 1.0 , mp ) ; /* expand scale */
12227 np = clip_memplot( 0.0,0.0 , 1.0,1.0 , mp ) ; /* clip to window */
12228 DESTROY_MEMPLOT(mp) ; mp = np ;
12229 }
12230
12231 /*** 23 Feb 2004: tick marks around the edge of the image? ***/
12232
12233 ntic = seq->wbar_ticnum_av->ival ;
12234
12235 if( ntic > 0 ){
12236 MEM_plotdata *tp ;
12237 char *eee ;
12238 /* float tic, fac=1.0/ntic ; */
12239 float rr=0.8,gg=1.0,bb=0.6 , tic, xfac, yfac;
12240 float xlen = 0.0, ylen = 0.0; /* when ntics is in mm */
12241 int it, nticx, nticy;
12242
12243 /* plot ntic as separation distance for J Binder 23 Feb 2006 [rickr] */
12244
12245 if( seq->imim && AFNI_yesenv("AFNI_IMAGE_TICK_DIV_IN_MM") ){
12246 /* get image size */
12247 if( mp != NULL && seq->cropit ){ /* cropped size */
12248 xlen = abs(seq->crop_xb - seq->crop_xa);
12249 ylen = abs(seq->crop_yb - seq->crop_ya);
12250 } else { /* full size */
12251 xlen = seq->imim->nx * seq->imim->dx;
12252 ylen = seq->imim->ny * seq->imim->dy;
12253 }
12254
12255 nticx = xlen/ntic;
12256 nticy = ylen/ntic;
12257 xfac=ntic/xlen;
12258 yfac=ntic/ylen;
12259 } else {
12260 nticx = nticy = ntic;
12261 xfac=1.0/ntic;
12262 yfac=1.0/ntic;
12263 }
12264
12265 create_memplot_surely( "Iticplot" , 1.0 ) ;
12266 set_thick_memplot(0.0) ;
12267 eee = getenv("AFNI_IMAGE_LABEL_COLOR") ;
12268 if( eee != NULL )
12269 DC_parse_color( seq->dc , eee , &rr,&gg,&bb ) ;
12270 set_color_memplot(rr,gg,bb) ;
12271
12272 tic = 0.01 * seq->wbar_ticsiz_av->ival ; /* percent of image size */
12273
12274 /* x and y are separate, in case ntic is in mm */
12275 for( it=0 ; it <= nticy ; it++ ){
12276 plotpak_line( 0.0,it*yfac , tic ,it*yfac ) ;
12277 plotpak_line( 1.0,it*yfac , 1.0-tic,it*yfac ) ;
12278 }
12279 for( it=0 ; it <= nticx ; it++ ){
12280 plotpak_line( it*xfac,0.0 , it*xfac ,tic ) ;
12281 plotpak_line( it*xfac,1.0 , it*xfac ,1.0-tic) ;
12282 }
12283
12284 /* append tick plot to existing plot, if any */
12285
12286 tp = get_active_memplot() ;
12287 if( mp != NULL ){ append_to_memplot(mp,tp); delete_memplot(tp); }
12288 else mp = tp ;
12289 }
12290
12291 RETURN(mp) ;
12292 }
12293
12294 /*--------------------------------------------------------------------------*/
12295 /*! Get the image for overlay. [11 Jun 2002]
12296 ----------------------------------------------------------------------------*/
12297
ISQ_getoverlay(int nn,MCW_imseq * seq)12298 MRI_IMAGE * ISQ_getoverlay( int nn , MCW_imseq *seq )
12299 {
12300 MRI_IMAGE *tim=NULL ;
12301
12302 ENTRY("ISQ_getoverlay") ;
12303
12304 #if 0
12305 tim = (MRI_IMAGE *) seq->getim( nn , isqCR_getoverlay , seq->getaux ) ;
12306 #else
12307 AFNI_CALL_VALU_3ARG( seq->getim , MRI_IMAGE *,tim ,
12308 int,nn , int,isqCR_getoverlay , XtPointer,seq->getaux ) ;
12309 #endif
12310
12311 if( tim == NULL ) RETURN(NULL) ;
12312
12313 MRI_floatscan(tim) ; /* 10 Jun 2021 */
12314
12315 /*--- cut out cropped region, if any ---*/
12316
12317 if( seq->cropit ){
12318 MRI_IMAGE *qim = mri_cut_2D( tim, seq->crop_xa,seq->crop_xb,
12319 seq->crop_ya,seq->crop_yb ) ;
12320 if( qim != NULL ){ mri_free(tim); tim = qim; }
12321 }
12322
12323 RETURN(tim) ;
12324 }
12325
12326 /*--------------------------------------------------------------------------*/
12327 /*! Get the image for display. Maybe use projections. [31 Jan 2002] */
12328
ISQ_getimage(int nn,MCW_imseq * seq)12329 MRI_IMAGE * ISQ_getimage( int nn , MCW_imseq *seq )
12330 {
12331 int ii , rr , jj , ns , npix , ktim ;
12332 MRI_IMAGE *tim=NULL , *qim=NULL , *fim=NULL ;
12333 MRI_IMARR *imar ;
12334 float *far , val=0.0f , *qar , **iar ;
12335
12336 ENTRY("ISQ_getimage") ;
12337
12338 /* get the commanded slice */
12339
12340 #if 0
12341 tim = (MRI_IMAGE *) seq->getim( nn, isqCR_getimage, seq->getaux ) ;
12342 #else
12343 AFNI_CALL_VALU_3ARG( seq->getim , MRI_IMAGE *,tim ,
12344 int,nn , int,isqCR_getimage , XtPointer,seq->getaux ) ;
12345 #endif
12346
12347 if( tim == NULL ) RETURN(NULL) ;
12348
12349 MRI_floatscan(tim) ; /* 10 Jun 2021 */
12350
12351 if( seq->cropit ){
12352
12353 if( seq->crop_nxorg < 0 || seq->crop_nyorg < 0 ){ /* orig image size not set yet */
12354 seq->crop_nxorg = tim->nx ;
12355 seq->crop_nyorg = tim->ny ;
12356 }
12357
12358 if( tim->nx != seq->crop_nxorg || /* image changed size? */
12359 tim->ny != seq->crop_nyorg ){ /* => turn cropping off */
12360
12361 seq->cropit = 0 ; seq->crop_nxorg = seq->crop_nyorg = -1 ;
12362
12363 if( seq->crop_drag ){ /* should not happen */
12364 MCW_invert_widget( seq->crop_drag_pb ) ;
12365 seq->crop_drag = 0 ;
12366 }
12367
12368 } else {
12369 MRI_IMAGE *cim ;
12370 if( seq->crop_xb >= seq->crop_nxorg ) seq->crop_xb = seq->crop_nxorg - 1 ;
12371 if( seq->crop_yb >= seq->crop_nyorg ) seq->crop_yb = seq->crop_nyorg - 1 ;
12372 cim = mri_cut_2D( tim, seq->crop_xa,seq->crop_xb,
12373 seq->crop_ya,seq->crop_yb ) ;
12374 if( cim != NULL ){ mri_free(tim); tim = cim; }
12375 }
12376 }
12377
12378 /* the old way - return this slice */
12379
12380 if( !ISQ_DOING_SLICE_PROJ(seq) ) RETURN(tim) ;
12381
12382 ns = seq->status->num_series ;
12383 rr = seq->slice_proj_range ; if( rr > ns/2 ) rr = ns/2 ;
12384
12385 if( rr == 0 ||
12386 seq->slice_proj_index == 0 ||
12387 seq->slice_proj_func == NULL ||
12388 tim == NULL ||
12389 tim->kind == MRI_rgb ||
12390 tim->kind == MRI_complex ){
12391
12392 RETURN(tim) ;
12393 }
12394
12395 /* the new way - return the projection of a bunch of images */
12396
12397 INIT_IMARR(imar) ;
12398
12399 ktim = tim->kind ; /* save for later use */
12400
12401 /* get the images into imar */
12402
12403 for( ii=-rr ; ii <= rr ; ii++ ){
12404
12405 if( ii == 0 ){ /* at the middle, just put a */
12406 fim = mri_to_float(tim) ; /* copy of the commanded slice */
12407 ADDTO_IMARR(imar,fim) ;
12408 continue ;
12409 }
12410
12411 jj = nn+ii ; /* offset slice */
12412 if( jj < 0 ) jj = 0 ; /* but not past the edges */
12413 else if( jj >= ns ) jj = ns-1 ;
12414
12415 #if 0
12416 qim = (MRI_IMAGE *) seq->getim( jj, isqCR_getimage, seq->getaux ) ;
12417 #else
12418 AFNI_CALL_VALU_3ARG( seq->getim , MRI_IMAGE *,qim ,
12419 int,jj , int,isqCR_getimage , XtPointer,seq->getaux ) ;
12420 #endif
12421
12422 if( qim == NULL )
12423 fim = mri_to_float(tim) ; /* need something */
12424 else if( qim->kind != MRI_float ){
12425 fim = mri_to_float(qim) ; mri_free(qim) ; /* convert it */
12426 } else
12427 fim = qim ; /* just put it here */
12428
12429 if( seq->cropit ){
12430 MRI_IMAGE *cim = mri_cut_2D( fim , seq->crop_xa,seq->crop_xb,
12431 seq->crop_ya,seq->crop_yb ) ;
12432 if( cim != NULL ){ mri_free(fim); fim = cim; }
12433 }
12434
12435 ADDTO_IMARR(imar,fim) ;
12436 }
12437
12438 /* project images, put results into qim */
12439
12440 qim = mri_new_conforming( tim , MRI_float ) ;
12441 qar = MRI_FLOAT_PTR(qim) ; MRI_COPY_AUX(qim,tim) ;
12442 mri_free(tim) ;
12443
12444 npix = qim->nvox ;
12445 rr = 2*rr+1 ;
12446 far = (float * ) malloc( sizeof(float ) * rr ) ;
12447 iar = (float **) malloc( sizeof(float *) * rr ) ;
12448
12449 for( ii=0 ; ii < rr ; ii++ )
12450 iar[ii] = MRI_FLOAT_PTR(IMARR_SUBIM(imar,ii)) ;
12451
12452 for( jj=0 ; jj < npix ; jj++ ){
12453
12454 for( ii=0 ; ii < rr ; ii++ ) far[ii] = iar[ii][jj] ;
12455
12456 #if 0
12457 val = seq->slice_proj_func( rr , far ) ;
12458 #else
12459 AFNI_CALL_proj_function( seq->slice_proj_func , rr,far , val ) ;
12460 #endif
12461
12462 qar[jj] = val ;
12463 }
12464
12465 free(iar) ; free(far) ; DESTROY_IMARR(imar) ;
12466
12467 if( ktim != MRI_float ){
12468 tim = mri_to_mri(ktim,qim); mri_free(qim); qim = tim;
12469 }
12470
12471 RETURN(qim) ;
12472 }
12473
12474 /*---------------------------------------------------------------------*/
12475
ISQ_cropim(MRI_IMAGE * tim,MCW_imseq * seq)12476 MRI_IMAGE * ISQ_cropim( MRI_IMAGE *tim , MCW_imseq *seq )
12477 {
12478 if( tim == NULL || !seq->cropit ) return NULL ;
12479
12480 if( seq->crop_nxorg < 0 || seq->crop_nyorg < 0 ){ /* orig image size not set yet */
12481 seq->crop_nxorg = tim->nx ;
12482 seq->crop_nyorg = tim->ny ;
12483 }
12484
12485 if( tim->nx != seq->crop_nxorg || /* image changed size? */
12486 tim->ny != seq->crop_nyorg ){ /* => turn cropping off */
12487
12488 seq->cropit = 0 ; seq->crop_nxorg = seq->crop_nyorg = -1 ;
12489
12490 if( seq->crop_drag ){ /* should not happen */
12491 MCW_invert_widget( seq->crop_drag_pb ) ;
12492 seq->crop_drag = 0 ;
12493 }
12494
12495 } else {
12496 MRI_IMAGE *cim ;
12497 if( seq->crop_xb >= seq->crop_nxorg ) seq->crop_xb = seq->crop_nxorg - 1 ;
12498 if( seq->crop_yb >= seq->crop_nyorg ) seq->crop_yb = seq->crop_nyorg - 1 ;
12499 cim = mri_cut_2D( tim, seq->crop_xa,seq->crop_xb,
12500 seq->crop_ya,seq->crop_yb ) ;
12501 if( cim != NULL ){ MRI_COPY_AUX(cim,tim); return cim; }
12502 }
12503
12504 return NULL ;
12505 }
12506
12507 /*---------------------------------------------------------------------*/
12508
ISQ_get_improj(int nn,MCW_imseq * seq,int getcode)12509 MRI_IMAGE * ISQ_get_improj( int nn , MCW_imseq *seq , int getcode )
12510 {
12511 MRI_IMAGE *tim=NULL , *cim ;
12512 int ii , rr , jj , ns , npix , ktim ;
12513 MRI_IMAGE *qim=NULL , *fim=NULL ;
12514 MRI_IMARR *imar ;
12515 float *far , val=0.0f , *qar , **iar ;
12516
12517 ENTRY("ISQ_get_improj") ;
12518
12519 /* get central slice */
12520
12521 AFNI_CALL_VALU_3ARG( seq->getim , MRI_IMAGE *,tim ,
12522 int,nn , int,getcode , XtPointer,seq->getaux ) ;
12523
12524 if( tim == NULL ) RETURN(NULL) ; /* should not happen */
12525
12526 cim = ISQ_cropim(tim,seq) ; if( cim != NULL ){ mri_free(tim); tim=cim; }
12527
12528 /* return just this slice? */
12529
12530 if( !ISQ_DOING_SLICE_PROJ(seq) ) RETURN(tim) ;
12531
12532 ns = seq->status->num_series ;
12533 rr = seq->slice_proj_range ; if( rr > ns/2 ) rr = ns/2 ;
12534
12535 if( rr == 0 ||
12536 seq->slice_proj_index == 0 ||
12537 seq->slice_proj_func == NULL ||
12538 tim == NULL ||
12539 tim->kind == MRI_rgb ||
12540 tim->kind == MRI_complex ){
12541
12542 RETURN(tim) ;
12543 }
12544
12545 /* return the projection of a bunch of images */
12546
12547 INIT_IMARR(imar) ;
12548
12549 ktim = tim->kind ; /* save for later use */
12550
12551 /* get the images into imar */
12552
12553 STATUS("projection loop") ;
12554
12555 for( ii=-rr ; ii <= rr ; ii++ ){
12556
12557 if( ii == 0 ){ /* at the middle, just put a */
12558 fim = mri_to_float(tim) ; /* copy of the commanded slice */
12559 ADDTO_IMARR(imar,fim) ;
12560 continue ;
12561 }
12562
12563 jj = nn+ii ; /* offset slice */
12564 if( jj < 0 ) jj = 0 ; /* but not past the edges */
12565 else if( jj >= ns ) jj = ns-1 ;
12566
12567 STATUS("call getim") ;
12568
12569 AFNI_CALL_VALU_3ARG( seq->getim , MRI_IMAGE *,qim ,
12570 int,jj , int,getcode , XtPointer,seq->getaux ) ;
12571
12572 if( qim == NULL )
12573 fim = mri_to_float(tim) ; /* need something */
12574 else if( qim->kind != MRI_float ){
12575 fim = mri_to_float(qim) ; mri_free(qim) ; /* convert it */
12576 } else
12577 fim = qim ; /* just put it here */
12578
12579 cim = ISQ_cropim(fim,seq) ; if( cim != NULL ){ mri_free(fim); fim=cim; }
12580 ADDTO_IMARR(imar,fim) ;
12581 }
12582
12583 /* project images, put results into qim */
12584
12585 qim = mri_new_conforming( tim , MRI_float ) ;
12586 qar = MRI_FLOAT_PTR(qim) ; MRI_COPY_AUX(qim,tim) ;
12587 mri_free(tim) ; tim = NULL ;
12588
12589 npix = qim->nvox ;
12590 rr = 2*rr+1 ;
12591 far = (float * )malloc( sizeof(float ) * rr ) ;
12592 iar = (float **)malloc( sizeof(float *) * rr ) ;
12593
12594 for( ii=0 ; ii < rr ; ii++ )
12595 iar[ii] = MRI_FLOAT_PTR(IMARR_SUBIM(imar,ii)) ;
12596
12597 for( jj=0 ; jj < npix ; jj++ ){
12598 for( ii=0 ; ii < rr ; ii++ ) far[ii] = iar[ii][jj] ;
12599 AFNI_CALL_proj_function( seq->slice_proj_func , rr,far , val ) ;
12600 qar[jj] = val ;
12601 }
12602
12603 free(iar) ; free(far) ; DESTROY_IMARR(imar) ;
12604
12605 if( ktim != MRI_float ){
12606 tim = mri_to_mri(ktim,qim); mri_free(qim); qim = tim;
12607 }
12608
12609 RETURN(qim) ;
12610 }
12611
12612 /*---------------------------------------------------------------------*/
12613
ISQ_getulay(int nn,MCW_imseq * seq)12614 MRI_IMAGE * ISQ_getulay( int nn , MCW_imseq *seq )
12615 {
12616 MRI_IMAGE *tim=NULL , *cim=NULL ;
12617
12618 ENTRY("ISQ_getulay") ;
12619
12620 #if 0
12621 AFNI_CALL_VALU_3ARG( seq->getim , MRI_IMAGE *,tim ,
12622 int,nn , int,isqCR_getulayim , XtPointer,seq->getaux ) ;
12623
12624 cim = ISQ_cropim( tim , seq ) ;
12625 if( cim != NULL ){ mri_free(tim) ; tim = cim ; }
12626 #else
12627 tim = ISQ_get_improj( nn , seq , isqCR_getulayim ) ;
12628 #endif
12629 RETURN(tim) ;
12630 }
12631
12632 /*---------------------------------------------------------------------*/
12633
ISQ_getolay(int nn,MCW_imseq * seq)12634 MRI_IMAGE * ISQ_getolay( int nn , MCW_imseq *seq )
12635 {
12636 MRI_IMAGE *tim=NULL , *cim ;
12637
12638 ENTRY("ISQ_getolay") ;
12639
12640 AFNI_CALL_VALU_3ARG( seq->getim , MRI_IMAGE *,tim ,
12641 int,nn , int,isqCR_getolayim , XtPointer,seq->getaux ) ;
12642
12643 cim = ISQ_cropim( tim , seq ) ;
12644 if( cim != NULL ){ mri_free(tim) ; tim = cim ; }
12645 RETURN(tim) ;
12646 }
12647
12648 /*---------------------------------------------------------------------*/
12649
ISQ_getchecked(int nn,MCW_imseq * seq)12650 MRI_IMAGE *ISQ_getchecked( int nn , MCW_imseq *seq )
12651 {
12652 MRI_IMAGE *qim=NULL , *uim , *oim ; float dx,dy ;
12653
12654 ENTRY("ISQ_getchecked") ;
12655
12656 qim = ISQ_getulay(nn,seq) ; if( qim == NULL ) RETURN(NULL) ;
12657 dx = qim->dx ; dy = qim->dy ;
12658 uim = ISQ_process_mri(nn,seq,qim,0) ; mri_free(qim) ;
12659
12660 qim = ISQ_getolay(nn,seq) ; if( qim == NULL ) RETURN(uim) ;
12661 oim = ISQ_process_mri(nn,seq,qim,PFLAG_NOTHING) ; mri_free(qim) ;
12662
12663 if( uim->kind == MRI_rgb && oim->kind == MRI_short ){
12664 qim = ISQ_index_to_rgb( seq->dc , 0 , oim ) ;
12665 mri_free(oim) ; oim = qim ;
12666 } else if( uim->kind == MRI_short && oim->kind == MRI_rgb ){
12667 qim = ISQ_index_to_rgb( seq->dc , 0 , uim ) ;
12668 mri_free(uim) ; uim = qim ;
12669 }
12670
12671 if( seq->render_mode == RENDER_CHECK_OU )
12672 qim = mri_check_2D( seq->wbar_checkbrd_av->ival , oim , uim ) ;
12673 else if( seq->render_mode == RENDER_CHECK_UO )
12674 qim = mri_check_2D( seq->wbar_checkbrd_av->ival , uim , oim ) ;
12675 else if( seq->render_mode == RENDER_WIPE_LEFT ) /* WIPE stuff 22 Aug 2014 */
12676 qim = mri_wiper_2D( WIPER_FROM_LEFT , seq->render_fac , oim,uim ) ;
12677 else if( seq->render_mode == RENDER_WIPE_BOT )
12678 qim = mri_wiper_2D( WIPER_FROM_BOTTOM , seq->render_fac , oim,uim ) ;
12679 else if( seq->render_mode == RENDER_MIX )
12680 qim = mri_mix_2D ( seq->render_fac , uim,oim ) ;
12681 else if( seq->render_mode == RENDER_WIPE_RIGHT )
12682 qim = mri_wiper_2D( WIPER_FROM_LEFT , seq->render_fac , uim,oim ) ;
12683 else if( seq->render_mode == RENDER_WIPE_TOP )
12684 qim = mri_wiper_2D( WIPER_FROM_BOTTOM , seq->render_fac , uim,oim ) ;
12685
12686 mri_free(oim) ;
12687 if( qim == NULL ){ uim->dx = dx ; uim->dy = dy ; RETURN(uim) ; }
12688
12689 mri_free(uim) ; qim->dx = dx ; qim->dy = dy ; RETURN(qim) ;
12690 }
12691
12692 /*--------------------------------------------------------------------*/
12693
ISQ_set_scale(Widget wscal,int percent)12694 void ISQ_set_scale( Widget wscal , int percent )
12695 {
12696 int val , old ;
12697
12698 val = percent ;
12699 if( wscal == NULL || val < 0 || val > 100 ) return ;
12700 XmScaleGetValue( wscal , &old ) ; if( val == old ) return ;
12701 XtVaSetValues( wscal , XmNvalue , val , NULL ) ;
12702 XmUpdateDisplay(wscal) ;
12703 return ;
12704 }
12705
12706 /*---------------------------------------------------------------------*/
12707
ISQ_popdown_render_scal(MCW_imseq * seq)12708 void ISQ_popdown_render_scal( MCW_imseq *seq )
12709 {
12710 if( seq->render_scal != NULL ) XtUnmanageChild( seq->render_scal ) ;
12711 return ;
12712 }
12713
12714 /*---------------------------------------------------------------------*/
12715
ISQ_popup_render_scal(MCW_imseq * seq)12716 void ISQ_popup_render_scal( MCW_imseq *seq )
12717 {
12718 #undef NCOL
12719 #define NCOL 30
12720 static char *cname[] = {
12721 "#0000ff", "#3300ff", "#6600ff", "#9900ff", "#cc00ff",
12722 "#ff00ff", "#ff00cc", "#ff0099", "#ff0066", "#ff0033",
12723 "#ff0000", "#ff3300", "#ff6600", "#ff9900", "#ffcc00",
12724 "#ffff00", "#ccff00", "#99ff00", "#66ff00", "#33ff00",
12725 "#00ff00", "#00ff33", "#00ff66", "#00ff99", "#00ffcc",
12726 "#00ffff", "#00ccff", "#0099ff", "#0066ff", "#0033ff"
12727 } ;
12728 int wid , icol ; Widget ws ;
12729
12730 if( seq->render_scal == NULL ) return ;
12731
12732 XtManageChild( seq->render_scal ) ;
12733 XtVaSetValues( seq->render_scal , XmNrightAttachment,XmATTACH_FORM , NULL ) ;
12734
12735 ws = XtNameToWidget(seq->render_scal,"Scrollbar") ;
12736 icol = lrand48() % NCOL ;
12737 MCW_widget_geom( seq->wform , &wid , NULL,NULL,NULL ) ;
12738 if( ws != NULL ){
12739 XtVaSetValues( ws ,
12740 XtVaTypedArg , XmNtroughColor , XmRString ,
12741 cname[icol] , strlen(cname[icol])+1 ,
12742 NULL ) ;
12743 XWarpPointer( XtDisplay(ws) , None , XtWindow(ws) ,
12744 0,0,0,0 , wid/2+1 , METER_HEIGHT/4 ) ;
12745 }
12746
12747 MCW_widget_geom( seq->wform , &wid , NULL,NULL,NULL ) ;
12748 XtVaSetValues( seq->render_scal , XmNwidth , wid , NULL ) ;
12749 XmUpdateDisplay(seq->render_scal) ;
12750 return ;
12751 }
12752
12753 /*---------------------------------------------------------------------*/
12754
ISQ_render_scal_CB(Widget w,XtPointer client_data,XtPointer call_data)12755 void ISQ_render_scal_CB( Widget w, XtPointer client_data, XtPointer call_data )
12756 {
12757 MCW_imseq *seq = (MCW_imseq *)client_data ;
12758 XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)call_data ;
12759 float fff ;
12760 int ival ;
12761
12762 if( ! ISQ_VALID(seq) ) return ;
12763
12764 if( cbs != NULL ) ival = cbs->value ;
12765 else XmScaleGetValue( w , &ival ) ;
12766
12767 seq->render_fac = 0.01f * ival ;
12768 ISQ_redisplay( seq , -1 , isqDR_display ) ;
12769 ISQ_draw_winfo( seq ) ;
12770 return ;
12771 }
12772
12773 /*---------------------------------------------------------------------*/
12774 /*! Deal with dragging a crop window after a button has been pressed.
12775 -----------------------------------------------------------------------*/
12776
ISQ_cropper(MCW_imseq * seq,XButtonEvent * event)12777 void ISQ_cropper( MCW_imseq *seq , XButtonEvent *event )
12778 {
12779 int x1=event->x,y1=event->y , x2,y2 ;
12780 int imx1,imy1,nim1 , imx2,imy2,nim2 , tt ;
12781 int zlev = seq->zoom_fac ;
12782
12783 ENTRY("ISQ_cropper") ;
12784
12785 if( !seq->crop_allowed ){
12786 XBell(seq->dc->display,100); EXRETURN;
12787 }
12788
12789 /*** make the user drag a rectangle while button is pressed:
12790 (x1,y1) = window coords of rectangle start
12791 (x2,y2) = window coords of rectangle finish ***/
12792
12793 #if 1
12794 RWC_drag_rectangle( seq->wimage , x1,y1,&x2,&y2 ) ;
12795 #else
12796 { int rad ;
12797 RWC_drag_circle( seq->wimage , x1,y1 , &rad ) ; /** just a test **/
12798 fprintf(stderr,"rad=%d\n",rad) ; EXRETURN ;
12799 }
12800 #endif
12801
12802 /*** find corners of rectangle in original image pixels ***/
12803
12804 ISQ_mapxy( seq , x1,y1 , &imx1,&imy1,&nim1 ) ;
12805 ISQ_mapxy( seq , x2,y2 , &imx2,&imy2,&nim2 ) ;
12806
12807 /*** ensure coords of rectangle run upwards (upperleft to lowerright) ***/
12808
12809 if( imx1 > imx2 ){ tt = imx1; imx1 = imx2; imx2 = tt; }
12810 if( imy1 > imy2 ){ tt = imy1; imy1 = imy2; imy2 = tt; }
12811
12812 /*** if dragging occured across sub-images in a montage,
12813 or if rectangle edge is in a Montage's inter-image border */
12814
12815 if( nim1 != nim2 || imx1 < 0 || imy1 < 0 ){
12816 static int npop=0 ;
12817 char str[64] ;
12818 if( npop < 5 ){
12819 sprintf(str,
12820 " \n %s \n crop\n rectangle! \n\n[Crosses montage border]\n",
12821 Random_Insult()) ;
12822 MCW_popup_message( seq->wimage,str, MCW_USER_KILL|MCW_TIMER_KILL ) ;
12823 npop++ ;
12824 }
12825 XBell(seq->dc->display,100); goto CropDone;
12826 }
12827
12828 /*** if crop window is too small, then deal with that ***/
12829
12830 if( imx2-imx1 < MINCROP || imy2-imy1 < MINCROP ){ /* too small */
12831 if( imx2-imx1 < 2 || imy2-imy1 < 2 ){
12832 seq->cropit = 0 ; seq->crop_nxorg = seq->crop_nyorg = -1 ; /* turn crop off */
12833 } else {
12834 XBell(seq->dc->display,100); /* do nothing */
12835 }
12836
12837 /*** otherwise (not too small), set the crop region ***/
12838
12839 } else {
12840
12841 /* 14 Jun 2002: if we are also zoomed, things are more complex */
12842
12843 if( zlev > 1 ){
12844
12845 /* xmid = middle of crop region */
12846 /* xh = half-width of crop region, as drawn */
12847 /* xhw = half-width enlarged by zoom factor */
12848
12849 int xmid=(imx2+imx1)/2, xh=(imx2-imx1)/2, xhw=zlev*xh ;
12850 int ymid=(imy2+imy1)/2, yh=(imy2-imy1)/2, yhw=zlev*yh ;
12851 int nx,ny ;
12852 float mh = (zlev-1.001f)/zlev ; /* max offset allowed */
12853
12854 /* set size of original image from which cropping will be done */
12855
12856 nx = (seq->crop_nxorg > 0) ? seq->crop_nxorg : seq->horig ;
12857 ny = (seq->crop_nyorg > 0) ? seq->crop_nyorg : seq->vorig ;
12858 #if 0
12859 fprintf(stderr,"Crop: imx1=%d imx2=%d xmid=%d xh=%d xhw=%d nx=%d\n",imx1,imx2,xmid,xh,xhw,nx);
12860 fprintf(stderr," imy1=%d imy2=%d ymid=%d yh=%d yhw=%d ny=%d\n",imy1,imy2,ymid,yh,yhw,ny);
12861 #endif
12862
12863 /* cropping should run from imx1-xhw to imx2+xhw
12864 (since we want the image window to show what the user
12865 drew, so we have to crop a larger rectangle and then
12866 zoom in on THAT),
12867 but we can't go outside the original image boundaries,
12868 so we recompute imx1..imx2 here */
12869
12870 imx1 = xmid-xhw ; imx2 = xmid+xhw ;
12871 if( imx1 < 0 ){ imx1 = 0 ; imx2 = imx1+2*xhw; }
12872 else if( imx2 >= nx-1 ){ imx2 = nx-1; imx1 = imx2-2*xhw; }
12873 imy1 = ymid-yhw ; imy2 = ymid+yhw ;
12874 if( imy1 < 0 ){ imy1 = 0 ; imy2 = imy1+2*yhw; }
12875 else if( imy2 >= ny-1 ){ imy2 = ny-1; imy1 = imy2-2*yhw; }
12876
12877 /* set the offset for the zoom window so that we'll show
12878 the crop region just computed in the image display */
12879
12880 if( seq->opt.mirror )
12881 seq->zoom_hor_off = ((float)(imx2-xmid-xh))
12882 /((float)(imx2-imx1)) ;
12883 else
12884 seq->zoom_hor_off = ((float)(xmid-xh-imx1))
12885 /((float)(imx2-imx1)) ;
12886
12887 seq->zoom_ver_off = ((float)(ymid-yh-imy1))
12888 /((float)(imy2-imy1)) ;
12889 #if 0
12890 fprintf(stderr," imx1=%d imx2=%d hor_off=%f\n",imx1,imx2,seq->zoom_hor_off);
12891 fprintf(stderr," imy1=%d imy2=%d ver_off=%f\n",imy1,imy2,seq->zoom_ver_off);
12892 #endif
12893
12894 /* safeguard: don't let the zoom window offset be out of range! */
12895
12896 if( seq->zoom_hor_off > mh ) seq->zoom_hor_off = mh ;
12897 else if( seq->zoom_hor_off < 0.0 ) seq->zoom_hor_off = 0.0 ;
12898 if( seq->zoom_ver_off > mh ) seq->zoom_ver_off = mh ;
12899 else if( seq->zoom_ver_off < 0.0 ) seq->zoom_ver_off = 0.0 ;
12900
12901 } /* end of mangling crop+zoom interaction */
12902
12903 /* now set crop parameters */
12904
12905 seq->crop_xa = imx1 ; seq->crop_xb = imx2 ;
12906 seq->crop_ya = imy1 ; seq->crop_yb = imy2 ;
12907 seq->cropit = 1 ; seq->crop_nxorg = seq->crop_nyorg = -1 ;
12908 }
12909
12910 /*** force image redisplay ***/
12911
12912 CropDone:
12913 if( seq->crop_drag ){ /* turn off crop */
12914 MCW_invert_widget( seq->crop_drag_pb ) ; /* button, if on */
12915 seq->crop_drag = 0 ;
12916 }
12917
12918 ISQ_redisplay( seq , -1 , isqDR_display ) ;
12919 EXRETURN ;
12920 }
12921
12922 /**************************************************************************/
12923 /*** 20 Jun 2003: snapshot stuff for recording the contents of a widget ***/
12924
12925 /*! Xt warning handler (to avoid messages to screen). */
12926
SNAP_warnhandler(char * msg)12927 static void SNAP_warnhandler(char *msg){ return ; }
12928
12929 /*----------------------------------------------------------------------*/
12930
12931 static MCW_imseq *snap_isq = NULL ;
12932 static MCW_DC *snap_dc = NULL ; /* cf. SNAP_make_dc() */
12933 static MRI_IMARR *snap_imar = NULL ;
12934
12935 static void SNAP_imseq_send_CB( MCW_imseq *, XtPointer, ISQ_cbs * ) ;
12936
12937 /*------------------------------------------------------------------*/
12938
ISQ_snap_agif(char * prefix)12939 void ISQ_snap_agif( char *prefix )
12940 {
12941 ISQ_save_anim( snap_isq , prefix , 0,0 , AGIF_MODE ) ;
12942 }
ISQ_snap_agif_rng(char * prefix,int a,int b)12943 void ISQ_snap_agif_rng( char *prefix , int a, int b )
12944 {
12945 ISQ_save_anim( snap_isq , prefix , a,b , AGIF_MODE ) ;
12946 }
12947
12948 /*------------------------------------------------------------------*/
12949
ISQ_snap_mpeg(char * prefix)12950 void ISQ_snap_mpeg( char *prefix )
12951 {
12952 ISQ_save_anim( snap_isq , prefix , 0,0 , MPEG_MODE ) ;
12953 }
ISQ_snap_mpeg_rng(char * prefix,int a,int b)12954 void ISQ_snap_mpeg_rng( char *prefix , int a, int b )
12955 {
12956 ISQ_save_anim( snap_isq , prefix , a,b , MPEG_MODE ) ;
12957 }
12958
12959 /*------------------------------------------------------------------*/
12960
ISQ_snap_jpeg(char * prefix)12961 void ISQ_snap_jpeg( char *prefix )
12962 {
12963 ISQ_save_anim( snap_isq , prefix , 0,0 , JPEG_MODE ) ;
12964 }
ISQ_snap_jpeg_rng(char * prefix,int a,int b)12965 void ISQ_snap_jpeg_rng( char *prefix , int a, int b )
12966 {
12967 ISQ_save_anim( snap_isq , prefix , a,b , JPEG_MODE ) ;
12968 }
12969
12970 /*------------------------------------------------------------------*/
12971
ISQ_snap_png(char * prefix)12972 void ISQ_snap_png( char *prefix )
12973 {
12974 ISQ_save_anim( snap_isq , prefix , 0,0 , PNG_MODE ) ;
12975 }
ISQ_snap_png_rng(char * prefix,int a,int b)12976 void ISQ_snap_png_rng( char *prefix , int a, int b )
12977 {
12978 ISQ_save_anim( snap_isq , prefix , a,b , PNG_MODE ) ;
12979 }
12980
12981 /*------------------------------------------------------------------
12982 Routine to provide data to the imseq.
12983 Just returns the control information, or the selected image.
12984 --------------------------------------------------------------------*/
12985
SNAP_imseq_getim(int n,int type,XtPointer handle)12986 static XtPointer SNAP_imseq_getim( int n, int type, XtPointer handle )
12987 {
12988 int ntot = 0 ;
12989
12990 ENTRY("SNAP_imseq_getim") ;
12991
12992 if( snap_imar != NULL ) ntot = IMARR_COUNT(snap_imar) ;
12993 if( ntot < 1 ) ntot = 1 ;
12994
12995 /*--- send control info ---*/
12996
12997 if( type == isqCR_getstatus ){
12998 MCW_imseq_status *stat = myXtNew( MCW_imseq_status ) ; /* will be freed */
12999 /* when imseq is */
13000 /* destroyed */
13001 stat->num_total = ntot ;
13002 stat->num_series = ntot ;
13003 stat->send_CB = SNAP_imseq_send_CB ;
13004 stat->parent = NULL ;
13005 stat->aux = NULL ;
13006
13007 stat->transforms0D = NULL ;
13008 stat->transforms2D = NULL ;
13009 stat->slice_proj = NULL ;
13010
13011 RETURN( (XtPointer)stat ) ;
13012 }
13013
13014 /*--- return a copy of an image
13015 (since the imseq will delete it when it is done) ---*/
13016
13017 if( type == isqCR_getimage || type == isqCR_getqimage ){
13018 MRI_IMAGE *im = NULL , *rim ;
13019
13020 if( snap_imar != NULL ){
13021 if( n < 0 ) n = 0 ; else if( n >= ntot ) n = ntot-1 ;
13022 rim = IMARR_SUBIMAGE(snap_imar,n) ;
13023 im = mri_copy( rim ) ;
13024 }
13025 RETURN( (XtPointer)im );
13026 }
13027
13028 RETURN( NULL ) ; /* all other cases */
13029 }
13030
13031 /*---------------------------------------------------------------------------
13032 Routine called when the imseq wants to send a message.
13033 In this case, all we need to handle is the destroy message,
13034 so that we can free some memory.
13035 -----------------------------------------------------------------------------*/
13036
SNAP_imseq_send_CB(MCW_imseq * seq,XtPointer handle,ISQ_cbs * cbs)13037 static void SNAP_imseq_send_CB( MCW_imseq *seq, XtPointer handle, ISQ_cbs *cbs )
13038 {
13039 ENTRY("SNAP_imseq_send_CB") ;
13040 switch( cbs->reason ){
13041 case isqCR_destroy:{
13042 myXtFree(snap_isq) ; snap_isq = NULL ;
13043 DESTROY_IMARR( snap_imar ) ; snap_imar = NULL ;
13044 }
13045 break ;
13046 }
13047 EXRETURN ;
13048 }
13049 /*------------------------------------------------------------------------*/
13050 /*! Create display context if we don't have one. [03 Jul 2003] */
13051
SNAP_make_dc(Widget w)13052 static void SNAP_make_dc( Widget w )
13053 {
13054 ENTRY("SNAP_make_dc") ;
13055 if( snap_dc == NULL ){
13056 if( first_dc != NULL ) snap_dc = first_dc ;
13057 else{
13058 if( w == (Widget) NULL ){
13059 fprintf(stderr,"** Can't snapshot/save with NULL widget!\n") ;
13060 EXRETURN ;
13061 }
13062 (void ) XtAppSetWarningHandler( XtWidgetToApplicationContext(w),
13063 SNAP_warnhandler ) ;
13064 snap_dc = MCW_new_DC( w, 4,0, NULL,NULL, 1.0,0 ) ;
13065 }
13066 }
13067 EXRETURN ;
13068 }
13069
13070 static int NoDuplicates = 1;
SNAP_NoDuplicates(void)13071 void SNAP_NoDuplicates (void) { NoDuplicates = 1; return; }
SNAP_OkDuplicates(void)13072 void SNAP_OkDuplicates (void) { NoDuplicates = 0; return; }
13073
13074 /*-------------------------------------------------------------------------*/
13075 /*! Save image into a viewer, which should be opened near the widget w. */
13076
SNAP_store_image(MRI_IMAGE * tim,Widget w)13077 static void SNAP_store_image( MRI_IMAGE *tim , Widget w )
13078 {
13079 ENTRY("SNAP_store_image") ;
13080
13081 if( tim == NULL ) EXRETURN ;
13082
13083 if( snap_imar == NULL ) INIT_IMARR(snap_imar) ;
13084
13085 if( NoDuplicates && IMARR_COUNT(snap_imar) > 0 ){
13086 MRI_IMAGE *qim = IMARR_LASTIM( snap_imar ) ;
13087 if( mri_equal(qim,tim) ){
13088 fprintf(stderr,"++ Image recorder: reject duplicate image at #%d\n",
13089 IMARR_COUNT(snap_imar)-1 ) ;
13090 mri_free(tim); EXRETURN;
13091 }
13092 }
13093
13094 ADDTO_IMARR(snap_imar,tim) ;
13095
13096 /* create viewer, if not present already */
13097
13098 if( snap_isq == NULL ){
13099 int xr,yr , wx,hy , xx,yy ;
13100 Position xroot,yroot ;
13101 Widget wpar ;
13102
13103 SNAP_make_dc( w ) ; if( snap_dc == NULL ) EXRETURN ;
13104
13105 snap_isq = open_MCW_imseq( snap_dc, SNAP_imseq_getim, NULL ) ;
13106
13107 drive_MCW_imseq( snap_isq, isqDR_periodicmont, (XtPointer) 0 ) ;
13108 drive_MCW_imseq( snap_isq, isqDR_realize , NULL ) ;
13109 drive_MCW_imseq( snap_isq, isqDR_title , "Snapshots" ) ;
13110
13111 /* put next to top shell of widget we are snapshotting */
13112
13113 if( w != (Widget) NULL ){
13114 wpar = w ;
13115 while( XtParent(wpar) != NULL ) wpar = XtParent(wpar) ; /* find top */
13116 XtTranslateCoords( wpar , 0,0 , &xroot,&yroot ) ;
13117 xr = (int) xroot ; yr = (int) yroot ;
13118 MCW_widget_geom( wpar , &wx,NULL , NULL,NULL ) ;
13119 xx = 1+wx+xr ; yy = 1+yr ;
13120 if( xx >= snap_dc->width-wx/3 ){
13121 XLowerWindow( snap_dc->display , XtWindow(wpar) ) ; xx = yy = 2 ;
13122 }
13123 XtVaSetValues( snap_isq->wtop , XmNx,xx , XmNy,yy , NULL ) ;
13124 }
13125 }
13126
13127 /* tell the image viewer about the new image */
13128
13129 if( IMARR_COUNT(snap_imar) > 1 ){
13130 int ii ;
13131 drive_MCW_imseq( snap_isq, isqDR_newseq , NULL ) ;
13132 drive_MCW_imseq( snap_isq, isqDR_onoffwid , (XtPointer)isqDR_onwid );
13133
13134 /* turn off some controls that don't make sense here */
13135
13136 XtUnmanageChild( snap_isq->wbar ) ;
13137 XtUnmanageChild( snap_isq->arrowpad->wform ) ;
13138 for( ii=0 ; ii < NBUTTON_RIG ; ii++)
13139 XtUnmanageChild( snap_isq->wbut_rig[ii] ) ;
13140 for( ii=0 ; ii < NARROW-1 ; ii++ ) /* keep "i" arrow */
13141 XtUnmanageChild( snap_isq->arrow[ii]->wrowcol ) ;
13142 XtUnmanageChild( snap_isq->ov_opacity_sep ) ;
13143 XtUnmanageChild( snap_isq->ov_opacity_av->wrowcol ) ;
13144 XtUnmanageChild( snap_isq->winfo ) ;
13145 XtUnmanageChild( snap_isq->pen_bbox->wrowcol ) ;
13146
13147 } else {
13148 drive_MCW_imseq( snap_isq, isqDR_onoffwid , (XtPointer)isqDR_offwid );
13149 }
13150
13151 /* force display of the new image */
13152
13153 ISQ_redisplay( snap_isq , IMARR_COUNT(snap_imar)-1 , isqDR_display ) ;
13154
13155 EXRETURN ;
13156 }
13157
13158 /*----------------------------------------------------------------------*/
13159 /*! Call this function to get a snapshot of a widget and save
13160 it into an image viewer. Also see ISQ_snapsave().
13161 ------------------------------------------------------------------------*/
13162
ISQ_snapshot(Widget w)13163 void ISQ_snapshot( Widget w )
13164 {
13165 MRI_IMAGE *tim ;
13166 Window win ;
13167
13168 ENTRY("ISQ_snapshot") ;
13169
13170 if( w == NULL || !XtIsWidget(w) ) EXRETURN ;
13171 if( !XtIsRealized(w) || !XtIsManaged(w) ) EXRETURN ;
13172 win = XtWindow(w); if( win == (Window)0 ) EXRETURN ;
13173
13174 /* try to get image */
13175
13176 SNAP_make_dc( w ) ; if( snap_dc == NULL ) EXRETURN ;
13177
13178 tim = SNAP_grab_image( w , snap_dc ) ;
13179 if( tim == NULL ) EXRETURN ;
13180
13181 /* got image; save it and display it */
13182
13183 SNAP_store_image( tim , w ) ;
13184 EXRETURN ;
13185 }
13186
13187 /*----------------------------------------------------------------------------*/
13188 /*! Called to add an image directly to the snapshot save sequence.
13189 - ww, hh = width and height of image
13190 - if(hh < 0) ==> flip image vertically (e.g., from glReadPixels)
13191 - pix = pointer to 3*ww*hh bytes of RGB data
13192 - w = Widget that the view should popup next to (can't be NULL)
13193 - RWCox - 03 Jul 2003
13194 ------------------------------------------------------------------------------*/
13195
ISQ_snapsave(int ww,int hh,byte * pix,Widget w)13196 void ISQ_snapsave( int ww , int hh , byte *pix , Widget w )
13197 {
13198 MRI_IMAGE *tim ;
13199 byte *qix ;
13200 int ii , jj , flip=0 ;
13201
13202 ENTRY("ISQ_snapsave") ;
13203
13204 if( ww < 2 || pix == NULL ) EXRETURN ;
13205 if( hh < 0 ){ hh = -hh ; flip = 1 ; }
13206 if( hh < 2 ) EXRETURN ;
13207
13208 SNAP_make_dc( w ) ; if( snap_dc == NULL ) EXRETURN ;
13209
13210 tim = mri_new( ww,hh, MRI_rgb ) ; qix = MRI_RGB_PTR(tim) ;
13211
13212 if( flip ){ /* flipper, flipper, faster than lightning */
13213 for( jj=0 ; jj < hh ; jj++ )
13214 memcpy( qix+3*ww*(hh-jj-1) , pix+3*ww*jj , 3*ww ) ;
13215 } else { /* simple copy */
13216 memcpy( qix , pix , 3*ww*hh ) ;
13217 }
13218
13219 SNAP_store_image( tim , w ) ;
13220 EXRETURN ;
13221 }
13222
13223 /*----------------------------------------------------------------------------*/
13224 /*! Like ISQ_snapsave, but don't store the image, return it instead.
13225 - ww, hh = width and height of image
13226 - if(hh < 0) ==> flip image vertically (e.g., from glReadPixels)
13227 - pix = pointer to 3*ww*hh bytes of RGB data
13228 ------------------------------------------------------------------------------*/
13229
ISQ_snap_to_mri_image(int ww,int hh,byte * pix)13230 MRI_IMAGE * ISQ_snap_to_mri_image( int ww , int hh , byte *pix )
13231 {
13232 MRI_IMAGE *tim ;
13233 byte *qix ;
13234 int ii , jj , flip=0 ;
13235
13236 ENTRY("ISQ_snap_to_mri_image") ;
13237
13238 if( ww < 2 || pix == NULL ) RETURN(NULL) ;
13239 if( hh < 0 ){ hh = -hh ; flip = 1 ; }
13240 if( hh < 2 ) RETURN(NULL) ;
13241
13242 tim = mri_new( ww,hh, MRI_rgb ) ; qix = MRI_RGB_PTR(tim) ;
13243
13244 if( flip ){ /* flipper, flipper, faster than lightning */
13245 for( jj=0 ; jj < hh ; jj++ )
13246 memcpy( qix+3*ww*(hh-jj-1) , pix+3*ww*jj , 3*ww ) ;
13247 } else { /* simple copy */
13248 memcpy( qix , pix , 3*ww*hh ) ;
13249 }
13250
13251 RETURN(tim) ;
13252 }
13253
13254 /*----------------------------------------------------------------------------*/
13255 /*! Like ISQ_snap_to_mri_image, but pix is a pointer to RGBA data.
13256 Returned image is still MRI_rbg, so alphas are ignored.
13257 ------------------------------------------------------------------------------*/
13258
ISQ_snap4_to_mri_image(int ww,int hh,byte * pix)13259 MRI_IMAGE * ISQ_snap4_to_mri_image( int ww , int hh , byte *pix )
13260 {
13261 MRI_IMAGE *tim ;
13262 byte *qix ;
13263 int ii , jj , flip=0, nn3, nn4 ;
13264
13265 ENTRY("ISQ_snap4_to_mri_image") ;
13266
13267 if( ww < 2 || pix == NULL ) RETURN(NULL) ;
13268 if( hh < 0 ){ hh = -hh ; flip = 1 ; }
13269 if( hh < 2 ) RETURN(NULL) ;
13270
13271 tim = mri_new( ww,hh, MRI_rgb ) ; qix = MRI_RGB_PTR(tim) ;
13272
13273 if( flip ){ /* flip vertically */
13274 for (jj=(hh-1), nn3=0; jj>=0; --jj) {
13275 for (ii=0; ii < ww; ii++ ) {
13276 nn4 = (jj*ww+ii)*4;
13277 qix[nn3++] = pix[nn4];
13278 qix[nn3++] = pix[nn4+1];
13279 qix[nn3++] = pix[nn4+2];
13280 } }
13281 } else { /* simple copy */
13282 for (jj=0, nn3=0, nn4=0; jj < hh; jj++ ) {
13283 for (ii=0; ii < ww; ii++ ) {
13284 qix[nn3++] = pix[nn4++];
13285 qix[nn3++] = pix[nn4++];
13286 qix[nn3++] = pix[nn4++]; ++nn4;
13287 }}
13288 }
13289
13290 RETURN(tim) ;
13291 }
13292
13293 /*----------------------------------------------------------------------------*/
13294
ISQ_pen_bbox_CB(Widget w,XtPointer client_data,XtPointer call_data)13295 void ISQ_pen_bbox_CB( Widget w, XtPointer client_data, XtPointer call_data )
13296 {
13297 MCW_imseq *seq = (MCW_imseq *)client_data ;
13298 int val ;
13299
13300 ENTRY("ISQ_pen_bbox_CB") ;
13301 if( !ISQ_REALZ(seq) ) EXRETURN ; /* bad, but impossible */
13302
13303 if( !seq->button2_enabled ){ /* shouldn't happen */
13304 MCW_set_bbox( seq->pen_bbox , 0 ) ;
13305 ISQ_set_cursor_state( seq, CURSOR_NORMAL ) ;
13306 XtUnmanageChild( seq->pen_bbox->wrowcol ) ;
13307 EXRETURN ;
13308 }
13309
13310 val = MCW_val_bbox( seq->pen_bbox ) ;
13311 ISQ_set_cursor_state( seq, (val==0) ? CURSOR_NORMAL : CURSOR_PENCIL ) ;
13312 EXRETURN ;
13313 }
13314
13315 /*----------------------------------------------------------------------------*/
13316 /*! Do something every so often. */
13317
ISQ_timer_CB(XtPointer cd,XtIntervalId * id)13318 void ISQ_timer_CB( XtPointer cd , XtIntervalId *id ) /* 03 Dec 2003 */
13319 {
13320 MCW_imseq *seq = (MCW_imseq *)cd ;
13321 int redo = 0 ;
13322
13323 ENTRY("ISQ_timer_CB") ;
13324
13325 if( !ISQ_REALZ(seq) || seq->timer_id == 0 ) EXRETURN ;
13326
13327 switch( seq->timer_func ){
13328
13329 case ISQ_TIMERFUNC_INDEX:{
13330 int nn=seq->im_nr , nt=seq->status->num_total ;
13331 if( nt > 1 && seq->timer_param != 0 ){
13332 nn = (nn+seq->timer_param+nt) % nt ;
13333 ISQ_redisplay( seq , nn , isqDR_display ) ;
13334 redo = 1 ;
13335 }
13336 }
13337 break ;
13338
13339 case ISQ_TIMERFUNC_BOUNCE:{
13340 int nn=seq->im_nr , nt=seq->status->num_total ;
13341 if( nt > 1 && seq->timer_param != 0 ){
13342 nn = nn + seq->timer_param ;
13343 if( nn < 0 ){
13344 nn = -nn; seq->timer_param = -seq->timer_param;
13345 } else if( nn >= nt ){
13346 nn = 2*(nt-1)-nn; seq->timer_param = -seq->timer_param;
13347 }
13348 ISQ_redisplay( seq , nn , isqDR_display ) ;
13349 redo = 1 ;
13350 }
13351 }
13352 break ;
13353
13354 }
13355
13356 if( redo ) seq->timer_id = XtAppAddTimeOut(
13357 XtWidgetToApplicationContext(seq->wform) ,
13358 seq->timer_delay , ISQ_timer_CB , seq ) ;
13359 else seq->timer_id = 0 ;
13360
13361 EXRETURN ;
13362 }
13363
ISQ_timer_stop(MCW_imseq * seq)13364 void ISQ_timer_stop( MCW_imseq *seq )
13365 {
13366 ENTRY("ISQ_timer_stop") ;
13367 if( seq != NULL && seq->timer_id > 0 ){
13368 XtRemoveTimeOut(seq->timer_id); seq->timer_id = 0;
13369 }
13370 EXRETURN ;
13371 }
13372
13373 /*--------------------------------------------------------------------*/
13374 /*! Deal with a single keypress in an image viewer window.
13375 Return value is 1 if processed OK, 0 if not.
13376 ----------------------------------------------------------------------*/
13377
ISQ_handle_keypress(MCW_imseq * seq,unsigned long key,unsigned int state)13378 int ISQ_handle_keypress( MCW_imseq *seq , unsigned long key , unsigned int state )
13379 {
13380 static int busy=0 ; /* prevent recursion */
13381
13382 int shft = (state & ShiftMask) ; /* 25 Aug 2009: stuff for */
13383 int ctrl = (state & ControlMask) ; /* editing crop window via */
13384 int astp ; /* arrow keypresses */
13385
13386 ENTRY("ISQ_handle_keypress") ;
13387
13388 ISQ_timer_stop(seq) ; /* 03 Dec 2003 */
13389
13390 if( busy || key == 0 ) RETURN(1) ;
13391 busy = 1 ;
13392
13393 astp = (int)AFNI_numenv("AFNI_IMAGE_CROPSTEP") ;
13394 if( astp == 0 ) astp = 1 ; /* default */
13395 else if( astp > 9 ) astp = 9 ; /* maximum */
13396 else if( astp < -9 ) astp = -9 ; /* minimum */
13397
13398 /* 24 Jan 2003: deal with special function keys */
13399
13400 if( key > 255 ){
13401 KeySym ks = (KeySym)key ;
13402 switch( ks ){
13403
13404 case XK_Home: /* 27 Aug 2009 : center crop or pan at crosshairs */
13405 if( shft ){
13406 ISQ_adjust_crop( seq, 0,0,0,0 , 1 ) ; /* crop center */
13407 } else if (ctrl ){
13408 /* nada */
13409 } else {
13410 ISQ_center_zoom( seq ) ; /* pan center */
13411 }
13412 break ;
13413
13414 case XK_Left:
13415 case XK_KP_Left:
13416 if( shft ){ /* 25 Aug 2009: edit crop window */
13417 ISQ_adjust_crop( seq , +astp,+astp , 0,0 , 1 ) ;
13418 } else if( ctrl ){
13419 ISQ_adjust_crop( seq , +1,-1 , 0,0 , 1 ) ;
13420 } else {
13421 seq->arrowpad->which_pressed = AP_LEFT ;
13422 seq->arrowpad->xev.type = 0 ;
13423 ISQ_arrowpad_CB( seq->arrowpad , (XtPointer)seq ) ;
13424 }
13425 break ;
13426
13427 case XK_Right:
13428 case XK_KP_Right:
13429 if( shft ){
13430 ISQ_adjust_crop( seq , -astp,-astp , 0,0 , 1 ) ;
13431 } else if( ctrl ){
13432 ISQ_adjust_crop( seq , -1,+1 , 0,0 , 1 ) ;
13433 } else {
13434 seq->arrowpad->which_pressed = AP_RIGHT ;
13435 seq->arrowpad->xev.type = 0 ;
13436 ISQ_arrowpad_CB( seq->arrowpad , (XtPointer)seq ) ;
13437 }
13438 break ;
13439
13440 case XK_Down:
13441 case XK_KP_Down:
13442 if( shft ){
13443 ISQ_adjust_crop( seq , 0,0 , -astp,-astp , 1 ) ;
13444 } else if( ctrl ){
13445 ISQ_adjust_crop( seq , 0,0 , -1,+1 , 1 ) ;
13446 } else {
13447 seq->arrowpad->which_pressed = AP_DOWN ;
13448 seq->arrowpad->xev.type = 0 ;
13449 ISQ_arrowpad_CB( seq->arrowpad , (XtPointer)seq ) ;
13450 }
13451 break ;
13452
13453 case XK_Up:
13454 case XK_KP_Up:
13455 if( shft ){
13456 ISQ_adjust_crop( seq , 0,0 , +astp,+astp , 1 ) ;
13457 } else if( ctrl ){
13458 ISQ_adjust_crop( seq , 0,0 , +1,-1 , 1 ) ;
13459 } else {
13460 seq->arrowpad->which_pressed = AP_UP ;
13461 seq->arrowpad->xev.type = 0 ;
13462 ISQ_arrowpad_CB( seq->arrowpad , (XtPointer)seq ) ;
13463 }
13464 break ;
13465
13466 case XK_Page_Up:
13467 case XK_KP_Page_Up:
13468 case XK_Page_Down:
13469 case XK_KP_Page_Down:{
13470 int nn=seq->im_nr , nt=seq->status->num_total ;
13471 if( nt > 1 ){
13472 if( ks==XK_Page_Down || ks==XK_KP_Page_Down ){ nn--; if(nn< 0 ) nn=nt-1; }
13473 else { nn++; if(nn>=nt) nn=0 ; }
13474 #if 1
13475 ISQ_redisplay( seq , nn , isqDR_display ) ;
13476 #else
13477 ISQ_set_image_number( seq , nn ) ;
13478 #endif
13479 }
13480 }
13481 break ;
13482
13483 case XK_Delete: /* 20 Feb 2003: drawing undo */
13484 case XK_KP_Delete:
13485 if( seq->button2_enabled && seq->status->send_CB != NULL ){
13486 ISQ_cbs cbs ;
13487 cbs.reason = isqCR_button2_key ;
13488 cbs.key = (int) XK_Delete ;
13489 #if 0
13490 seq->status->send_CB( seq , seq->getaux , &cbs ) ;
13491 #else
13492 SEND(seq,cbs) ;
13493 #endif
13494 }
13495 break ;
13496
13497 /* 10 Mar 2003: change cursor state to drawing pencil */
13498
13499 case XK_F2:{
13500 if( !seq->button2_enabled ){
13501 MCW_popup_message( seq->wimage,
13502 " \n Only when \n"
13503 " Drawing!! \n ", MCW_USER_KILL|MCW_TIMER_KILL );
13504 XBell(seq->dc->display,100); busy=0; RETURN(0);
13505 }
13506 ISQ_set_cursor_state( seq ,
13507 (seq->cursor_state == CURSOR_PENCIL)
13508 ? CURSOR_NORMAL : CURSOR_PENCIL ) ;
13509 }
13510 break ;
13511
13512 case XK_F4:
13513 case XK_F3:{ /* 13 Sep 2008 */
13514 ISQ_cbs cbs ;
13515 if( !seq->button2_enabled ){
13516 MCW_popup_message( seq->wimage,
13517 " \n Only when \n"
13518 " Drawing!! \n ", MCW_USER_KILL|MCW_TIMER_KILL );
13519 XBell(seq->dc->display,100); busy=0; RETURN(0);
13520 }
13521 cbs.reason = isqCR_button2_key ;
13522 cbs.key = (int)ks ;
13523 SEND(seq,cbs) ;
13524 }
13525 break ;
13526
13527 #if 0
13528 case XK_F5:
13529 MCW_melt_widget( seq->wform ) ;
13530 break ;
13531 #endif
13532
13533 default:
13534 /* case XK_F5: */
13535 case XK_F6:
13536 case XK_F7:
13537 case XK_F8:
13538 case XK_F9:
13539 case XK_F10:
13540 case XK_F11:
13541 case XK_F12:
13542 #if 0
13543 XBell(seq->dc->display,100) ;
13544 MCW_popup_message( seq->wimage, " \n Ouch! \n ", MCW_USER_KILL|MCW_QUICK_KILL );
13545 AFNI_speak( "Ouch!" , 0 ) ;
13546 #endif
13547 break ;
13548 }
13549 busy=0; RETURN(1) ;
13550 }
13551
13552 /* 07 Dec 2002: modified ad hoc series of if-s into a switch */
13553
13554 switch( key ){
13555
13556 /* 10 Mar 2002: quit if 'q' or 'Q' is pressed */
13557
13558 case 'q':
13559 case 'Q':{
13560 ISQ_but_done_CB( NULL, (XtPointer)seq, NULL ) ; NI_sleep(1) ;
13561 busy=0; RETURN(1) ;
13562 }
13563 break ;
13564
13565 /* 03 Dec 2003: advance picture continuously? */
13566
13567 case 'v':
13568 case 'V':{
13569 if( seq->button2_enabled ){
13570 MCW_popup_message( seq->wimage,
13571 " \n Not when \n"
13572 " Drawing! \n ", MCW_USER_KILL|MCW_TIMER_KILL );
13573 XBell(seq->dc->display,100) ;
13574 } else if( seq->status->num_total > 1 ){ /* bring it on */
13575 seq->timer_func = ISQ_TIMERFUNC_INDEX ;
13576 seq->timer_delay = (int) AFNI_numenv("AFNI_VIDEO_DELAY") ;
13577 if( seq->timer_delay <= 0 ) seq->timer_delay = 1 ;
13578 seq->timer_param = (key == 'v') ? 1 : -1 ;
13579 seq->timer_id =
13580 XtAppAddTimeOut( XtWidgetToApplicationContext(seq->wform) ,
13581 seq->timer_delay , ISQ_timer_CB , seq ) ;
13582 }
13583 busy=0; RETURN(1) ;
13584 }
13585 break ;
13586
13587 case 'r':
13588 case 'R':{
13589 if( seq->button2_enabled ){
13590 MCW_popup_message( seq->wimage,
13591 " \n Not when \n"
13592 " Drawing! \n ", MCW_USER_KILL|MCW_TIMER_KILL );
13593 XBell(seq->dc->display,100) ;
13594 } else if( seq->status->num_total > 1 ){ /* bring it on */
13595 seq->timer_func = ISQ_TIMERFUNC_BOUNCE ;
13596 seq->timer_delay = (int) AFNI_numenv("AFNI_VIDEO_DELAY") ;
13597 if( seq->timer_delay <= 0 ) seq->timer_delay = 1 ;
13598 seq->timer_param = (key == 'r') ? 1 : -1 ;
13599 seq->timer_id =
13600 XtAppAddTimeOut( XtWidgetToApplicationContext(seq->wform) ,
13601 seq->timer_delay , ISQ_timer_CB , seq ) ;
13602 }
13603 busy=0; RETURN(1);
13604 }
13605 break ;
13606
13607 /* 07 Dec 2002: scroll forward or backward
13608 using '<' or '>' keys (like graphs) */
13609
13610 case '>':
13611 case '<':
13612 case ',':
13613 case '.':{
13614 int nn=seq->im_nr , nt=seq->status->num_total ;
13615 if( nt > 1 ){
13616 if( key == '<' || key == ',' ){ nn--; if( nn < 0 ) nn = nt-1; }
13617 else { nn++; if( nn >= nt) nn = 0 ; }
13618 #if 1
13619 ISQ_redisplay( seq , nn , isqDR_display ) ;
13620 #else
13621 ISQ_set_image_number( seq , nn ) ;
13622 #endif
13623 }
13624 busy=0; RETURN(1) ;
13625 }
13626 break ;
13627
13628 /* 05 Apr 2002: zoom out/in for 'z' or 'Z' */
13629
13630 case 'z':
13631 case 'Z':{
13632 int call=0 , zlev=seq->zoom_fac ;
13633 if( key == 'z' && zlev > ZOOM_BOT ){
13634 AV_assign_ival( seq->zoom_val_av , zlev-1 ) ; call = 1 ;
13635 } else if( key == 'Z' && zlev < ZOOM_TOP ){
13636 AV_assign_ival( seq->zoom_val_av , zlev+1 ) ; call = 1 ;
13637 }
13638 if( call )
13639 ISQ_zoom_av_CB( seq->zoom_val_av , (XtPointer)seq ) ;
13640 else
13641 XBell(seq->dc->display,100) ;
13642 busy=0; RETURN(1) ;
13643 }
13644 break ;
13645
13646 /* and toggle panning with 'p' or 'P' */
13647
13648 case 'P':
13649 case 'p':{
13650 if( seq->zoom_fac > 1 )
13651 ISQ_zoom_pb_CB( seq->zoom_drag_pb , (XtPointer)seq , NULL ) ;
13652 else
13653 XBell(seq->dc->display,100) ;
13654 busy=0; RETURN(1) ;
13655 }
13656 break ;
13657
13658 /* 17 Jun 2002: toggle cropping with 'c' or 'C' */
13659
13660 case 'c':
13661 case 'C':{
13662 ISQ_crop_pb_CB( seq->crop_drag_pb , (XtPointer)seq , NULL ) ;
13663 busy=0; RETURN(1) ;
13664 }
13665 break ;
13666
13667 /* 17 May 2002: do image fraction up or down */
13668
13669 case 'i':
13670 case 'I':{
13671 int iv = seq->arrow[NARR_FRAC]->ival ;
13672 if( key == 'i' )
13673 AV_assign_ival( seq->arrow[NARR_FRAC] , iv-1 ) ;
13674 else if( key == 'I' )
13675 AV_assign_ival( seq->arrow[NARR_FRAC] , iv+1 ) ;
13676 ISQ_arrow_CB( seq->arrow[NARR_FRAC] , seq ) ;
13677 busy=0; RETURN(1) ;
13678 }
13679 break ;
13680
13681 /* ctrl-m to cycle globalranges */
13682 case 13 : {
13683 ISQ_cbs cbs ;
13684 cbs.reason = isqCR_globalrange ;
13685 SEND(seq,cbs) ; /* send this back to a callback function now in afni.c
13686 imseq doesn't have access directly to dataset info */
13687
13688 busy=0 ; RETURN(1) ;
13689 }
13690 break;
13691
13692 /* 22 Aug 2005: 'm' == Min-to-Max toggle */
13693 case 'm':{
13694 if( seq->dialog_starter==NBUT_DISP ){XBell(seq->dc->display,100); break;}
13695 switch( seq->opt.scale_range ){
13696 default:
13697 case ISQ_RNG_MINTOMAX: seq->opt.scale_range = ISQ_RNG_02TO98; break;
13698 case ISQ_RNG_CLIPPED: seq->opt.scale_range = ISQ_RNG_MINTOMAX;break;
13699 case ISQ_RNG_02TO98: seq->opt.scale_range = ISQ_RNG_MINTOMAX;break;
13700 }
13701 }
13702 ISQ_redisplay( seq , -1 , isqDR_display ) ;
13703 busy=0 ; RETURN(1) ;
13704
13705 break ;
13706
13707 /* 22 Aug 2005: 'l' == LR mirror toggle */
13708
13709 case 'l':{
13710 if( seq->dialog_starter==NBUT_DISP ){XBell(seq->dc->display,100); break;}
13711 seq->opt.mirror = ! seq->opt.mirror ;
13712 ISQ_redisplay( seq , -1 , isqDR_display ) ;
13713 busy=0 ; RETURN(1) ;
13714 }
13715 break ;
13716
13717 /* 22 Aug 2005: 'a' = fix aspect ratio */
13718
13719 case 'A':
13720 case 'a':{
13721 int bx = seq->opt.free_aspect ; seq->opt.free_aspect = 0 ;
13722 ISQ_reset_dimen( seq, seq->last_width_mm, seq->last_height_mm ) ;
13723 seq->opt.free_aspect = bx ;
13724 busy=0 ; RETURN(1) ;
13725 }
13726 break ;
13727
13728 /* 23 Aug 2005: 's' = sharpen */
13729
13730 case 's':{
13731 if( seq->dialog_starter==NBUT_DISP ){XBell(seq->dc->display,100); break;}
13732 if( !(seq->opt.improc_code & ISQ_IMPROC_SHARP) ){
13733 seq->opt.improc_code |= ISQ_IMPROC_SHARP ;
13734 } else {
13735 int ss = (int)(10.01*seq->sharp_fac)+1 ;
13736 if( ss > 9 ) ss = 1 ;
13737 seq->sharp_fac = 0.1 * ss ;
13738 }
13739 ISQ_redisplay( seq , -1 , isqDR_display ) ;
13740 busy=0 ; RETURN(1) ;
13741 }
13742 break ;
13743
13744 /* 24 Apr 2014: 'e' = edge detect toggle */
13745
13746 case 'e':{
13747 if( seq->dialog_starter==NBUT_DISP ){XBell(seq->dc->display,100); break;}
13748 if( !(seq->opt.improc_code & ISQ_IMPROC_SOBEL) ){
13749 seq->opt.improc_code |= ISQ_IMPROC_SOBEL ; /* turn on edge detection */
13750 } else {
13751 seq->opt.improc_code &= !ISQ_IMPROC_SOBEL ; /* turn off edge detection */
13752 }
13753 ISQ_redisplay( seq , -1 , isqDR_display ) ;
13754 busy=0 ; RETURN(1) ;
13755 }
13756 break ;
13757
13758 /* 26 Apr 2007: time indexing */
13759
13760 case '[':
13761 case ']':{
13762 ISQ_cbs cbs ;
13763 cbs.reason = isqCR_setindex ;
13764 cbs.key = (key == '[') ? -1 : +1 ;
13765 SEND(seq,cbs) ;
13766 }
13767 break ; /** N.B.: '{' and '}' are reserved for threshold changing! **/
13768
13769 /* 23 Aug 2005: open some windows */
13770
13771 case 'D':
13772 ISQ_but_disp_CB( seq->wbut_bot[NBUT_DISP] , seq , NULL ) ;
13773 busy=0 ; RETURN(1) ;
13774 break ;
13775
13776 case 'M':
13777 if( seq->status->num_total > 1 )
13778 ISQ_montage_CB( seq->wbut_bot[NBUT_MONT] , seq , NULL ) ;
13779 busy=0 ; RETURN(1) ;
13780 break ;
13781
13782 case 'S':
13783 if( (seq->opt.save_one || seq->status->num_total > 1) )
13784 ISQ_but_save_CB( seq->wbut_bot[NBUT_SAVE] , seq , NULL ) ;
13785 busy=0 ; RETURN(1) ;
13786 break ;
13787
13788 case '3':
13789 case '#':{
13790 int rr = seq->render_mode ;
13791 if( !seq->allowmerger ){ busy=0 ; RETURN(1) ; }
13792
13793 if( key == '3' ) rr = 0 ;
13794 else if( rr == RENDER_CHECK_OU ) rr = RENDER_CHECK_UO ;
13795 else rr = RENDER_CHECK_OU ;
13796 if( seq->render_scal != NULL ) ISQ_popdown_render_scal(seq) ;
13797 seq->render_mode = rr ;
13798 ISQ_redisplay( seq , -1 , isqDR_display ) ;
13799 ISQ_draw_winfo( seq ) ;
13800 busy=0 ; RETURN(1) ;
13801 }
13802 break ;
13803
13804 case '$':
13805 case '%':
13806 case '4':
13807 case '5':
13808 case '6':{ /* 22 Aug 2014 */
13809 if( !seq->allowmerger ){ busy=0 ; RETURN(1) ; }
13810 if( seq->render_mode != 0 ){
13811 ISQ_popdown_render_scal(seq) ; seq->render_mode = 0 ; seq->render_fac = 0.0f ;
13812 } else {
13813 ISQ_popup_render_scal(seq) ;
13814 switch( key ){
13815 case '4': seq->render_mode = RENDER_WIPE_LEFT ; break ;
13816 case '5': seq->render_mode = RENDER_WIPE_BOT ; break ;
13817 case '6': seq->render_mode = RENDER_MIX ; break ;
13818 case '$': seq->render_mode = RENDER_WIPE_RIGHT ; break ;
13819 case '%': seq->render_mode = RENDER_WIPE_TOP ; break ;
13820 }
13821 ISQ_set_scale( seq->render_scal , 50 ) ; seq->render_fac = 0.50f ;
13822 }
13823 ISQ_redisplay( seq , -1 , isqDR_display ) ;
13824 ISQ_draw_winfo( seq ) ;
13825 busy=0 ; RETURN(1) ;
13826 }
13827 break ;
13828
13829 #if 0
13830 case 'G':
13831 case 'H':
13832 case 'J':
13833 case 'K':{
13834 int mode = (key=='G') ? AGIF_MODE
13835 :(key=='H') ? MPEG_MODE
13836 :(key=='J') ? JPEG_MODE
13837 : PNG_MODE ;
13838 ISQ_save_anim( seq , NULL , 0,0 , mode ) ;
13839 busy=0 ; RETURN(1) ;
13840 }
13841 break ;
13842 #endif
13843
13844 } /* end of switch on character typed */
13845
13846 busy=0; RETURN(0);
13847 }
13848
13849 /*----------------------------------------------------------------------------*/
13850 /*! Carry out a scalar filter on the intensity component of an RGB image.
13851 Afterwards, the color for each pixel is rescaled from the old to the
13852 new by the filtered intensity. This transform is done in-place.
13853 ------------------------------------------------------------------------------*/
13854
mri_rgb_transform_nD(MRI_IMAGE * im,int ndim,generic_func * tfunc)13855 void mri_rgb_transform_nD( MRI_IMAGE *im, int ndim, generic_func *tfunc )
13856 {
13857 MRI_IMAGE *flim , *shim ;
13858 float *sar , *far ;
13859 int ii , nvox , rr,gg,bb ;
13860 float fac , smax,fmax,fsrat ;
13861
13862 ENTRY("mri_rgb_transform_nD") ;
13863
13864 if( im == NULL || (im->kind != MRI_rgb && im->kind != MRI_rgba) ) EXRETURN ; /* bad image? */
13865 if( tfunc == NULL || (ndim !=0 && ndim != 2 ) ) EXRETURN ; /* bad tfunc? */
13866
13867 flim = mri_to_float( im ) ; /* input intensity image */
13868 fmax = mri_max( flim ) ;
13869 if( fmax == 0.0 ){ mri_free(flim); EXRETURN; } /* nothing to do? */
13870
13871 shim = mri_copy( flim ) ; /* will be transformed intensity */
13872
13873 switch( ndim ){ /* call in-place transform function */
13874 case 0:
13875 AFNI_CALL_0D_function( tfunc , shim->nvox , MRI_FLOAT_PTR(shim) ) ;
13876 break ;
13877
13878 case 2:
13879 AFNI_CALL_2D_function( tfunc ,
13880 shim->nx , shim->ny ,
13881 shim->dx , shim->dy , MRI_FLOAT_PTR(shim) ) ;
13882 break ;
13883 }
13884
13885 /* get scale factor to adjust for changes in overall amplitude */
13886
13887 smax = mri_max(shim) ;
13888 if( smax == 0.0 ){ mri_free(flim); mri_free(shim); EXRETURN; }
13889 fsrat = fmax / smax ;
13890
13891 far = MRI_FLOAT_PTR(flim) ; sar = MRI_FLOAT_PTR(shim) ;
13892
13893 /* loop over pixels, adjusting color of each one by transformed intensity */
13894
13895 switch( im->kind ){
13896 default: break ; /* unreachable - just to stifle compiler warning */
13897 case MRI_rgb:{
13898 byte *iar = MRI_BYTE_PTR(im) ;
13899 nvox = im->nvox ;
13900 for( ii=0 ; ii < nvox ; ii++ ){
13901 if( far[ii] <= 0.0 || sar[ii] <= 0.0 ){ /* inten <= 0? */
13902 iar[3*ii] = iar[3*ii+1] = iar[3*ii+2] = 0 ;
13903 } else {
13904 fac = fsrat * sar[ii] / far[ii] ; /* will be positive */
13905 rr = fac * iar[3*ii] ; iar[3*ii ] = (rr > 255) ? 255 : rr ;
13906 gg = fac * iar[3*ii+1] ; iar[3*ii+1] = (gg > 255) ? 255 : gg ;
13907 bb = fac * iar[3*ii+2] ; iar[3*ii+2] = (bb > 255) ? 255 : bb ;
13908 }
13909 }
13910 }
13911 break ;
13912
13913 case MRI_rgba:{
13914 rgba *jar = MRI_RGBA_PTR(im) ;
13915 nvox = im->nvox ;
13916 for( ii=0 ; ii < nvox ; ii++ ){
13917 if( far[ii] <= 0.0 || sar[ii] <= 0.0 ){ /* inten <= 0? */
13918 jar[ii].r = jar[ii].g = jar[ii].b = 0 ;
13919 } else {
13920 fac = fsrat * sar[ii] / far[ii] ; /* will be positive */
13921 rr = fac * jar[ii].r ; jar[ii].r = (rr > 255) ? 255 : rr ;
13922 gg = fac * jar[ii].g ; jar[ii].g = (gg > 255) ? 255 : gg ;
13923 bb = fac * jar[ii].b ; jar[ii].b = (bb > 255) ? 255 : bb ;
13924 }
13925 }
13926 }
13927 break ;
13928 }
13929
13930 mri_free(flim) ; mri_free(shim) ; /* toss the trash */
13931 EXRETURN ;
13932 }
13933
13934 /*--------------------------------------------------------------------------*/
13935 /*! Save the current image to a file thru a filter.
13936 - Refactored from the former ISQ_save_jpeg() - 11 Dec 2006
13937 - Modified for use as a filter (no fname or suffix) - 14 Dec 2006 */
13938
ISQ_save_image(MCW_imseq * seq,char * fname,char * filtername,char * suffix)13939 void ISQ_save_image( MCW_imseq *seq , char *fname ,
13940 char *filtername, char *suffix )
13941 {
13942 MRI_IMAGE *tim , *flim ;
13943 char fn[299], filt[512] ;
13944 FILE *fp ;
13945 int sll ;
13946
13947 ENTRY("ISQ_save_image") ;
13948
13949 if( !ISQ_REALZ(seq) || filtername == NULL ) EXRETURN;
13950
13951 if( fname != NULL ){
13952 sll = strlen(fname) ; if( sll < 1 || sll > 255 ) EXRETURN ;
13953 }
13954 if( filtername == NULL ){
13955 if( fname == NULL ){ filtername = "cat > AFNI.ppm" ; }
13956 else { filtername = "cat > %s" ; suffix = ".ppm" ; }
13957 }
13958
13959 /*-- get image that's stored for display, then process it --*/
13960
13961 reload_DC_colordef( seq->dc ) ;
13962 tim = XImage_to_mri( seq->dc, seq->given_xim, X2M_USE_CMAP | X2M_FORCE_RGB );
13963 if( tim == NULL ) EXRETURN ;
13964
13965 /** make the image square? **/
13966
13967 /* INFO_message("AFNI_IMAGE_SAVESQUARE = %s",getenv("AFNI_IMAGE_SAVESQUARE")); */
13968 if( AFNI_yesenv("AFNI_IMAGE_SAVESQUARE") ){
13969 tim->dx = seq->last_dx ; tim->dy = seq->last_dy ;
13970 flim = mri_squareaspect( tim ) ;
13971 if( flim != NULL ){ mri_free(tim); tim = flim; }
13972 }
13973
13974 /** zoom? **/
13975
13976 if( DO_BLOWUP(seq) ){
13977 int zf = MAX(seq->zoom_fac,seq->saver_blowup) ;
13978 // [PT: Dec 19, 2018] Change default behavior to be NN interp
13979 if( AFNI_noenv("AFNI_IMAGE_ZOOM_NN") ) mri_dup2D_mode(-7) ;
13980 flim = mri_dup2D(zf,tim) ;
13981 mri_dup2D_mode(7) ;
13982 if( flim != NULL ){ mri_free(tim); tim = flim; }
13983 }
13984
13985 /** line drawing overlay? **/
13986
13987 if( seq->mplot != NULL ){
13988 /* mri_draw_force_opaque(1) ; */
13989 memplot_to_mri_set_dothick(1) ;
13990 memplot_to_RGB_sef( tim, seq->mplot, 0,0,MEMPLOT_FREE_ASPECT ) ;
13991 memplot_to_mri_set_dothick(0) ;
13992 /* mri_draw_force_opaque(0) ; */
13993 }
13994
13995 /** cut up zoomed image? **/
13996
13997 if( seq->zoom_fac > 1 &&
13998 seq->saver_blowup == 1 &&
13999 seq->mont_nx == 1 &&
14000 seq->mont_ny == 1 &&
14001 AFNI_yesenv("AFNI_CROP_ZOOMSAVE") ) {
14002
14003 int xa,ya , iw=tim->nx/seq->zoom_fac , ih=tim->ny/seq->zoom_fac ;
14004
14005 xa = seq->zoom_hor_off * tim->nx ;
14006 if( xa+iw > tim->nx ) xa = tim->nx-iw ;
14007 ya = seq->zoom_ver_off * tim->nx ;
14008 if( ya+ih > tim->ny ) ya = tim->ny-ih ;
14009 flim = mri_cut_2D( tim , xa,xa+iw-1 , ya,ya+ih-1 ) ;
14010 if( flim != NULL ){ mri_free(tim); tim = flim; }
14011 }
14012
14013 /** open a pipe to the filter function **/
14014
14015 if( fname != NULL ){
14016 strcpy(fn,fname) ;
14017 if( suffix != NULL && *suffix != '\0' &&
14018 !STRING_HAS_SUFFIX_CASE(fname,suffix) ){
14019 if( *suffix != '.' ) strcat(fn,".") ;
14020 strcat(fn,suffix) ;
14021 }
14022 sprintf( filt , filtername , fn ) ;
14023 } else {
14024 strcpy( filt , filtername ) ;
14025 }
14026 INFO_message("Writing one %dx%d image to filter '%s'",tim->nx,tim->ny,filt) ;
14027
14028 #ifndef CYGWIN
14029 signal( SIGPIPE , SIG_IGN ) ;
14030 #endif
14031 errno = 0 ; fp = popen( filt , "w" ) ;
14032 if( fp == NULL ){
14033 ERROR_message("Can't open output filter: %s",filt) ;
14034 if( errno != 0 ) perror("** Unix error message") ;
14035 mri_free(tim) ; EXRETURN ;
14036 }
14037
14038 /** write a PPM file to the filter pipe **/
14039
14040 fprintf(fp,"P6\n%d %d\n255\n" , tim->nx,tim->ny ) ;
14041 fwrite( MRI_RGB_PTR(tim), sizeof(byte), 3*tim->nvox, fp ) ; fflush(fp) ;
14042 errno = 0 ; sll = pclose(fp) ;
14043 if( sll == -1 ){
14044 ERROR_message("Image save filter command was %s\n",filt) ;
14045 if( errno != 0 ) perror("** Unix error in image output pipe") ;
14046 }
14047
14048 mri_free(tim) ; EXRETURN ;
14049 }
14050
14051 /*--------------------------------------------------------------------------*/
14052
ISQ_save_jpeg(MCW_imseq * seq,char * fname)14053 void ISQ_save_jpeg( MCW_imseq *seq , char *fname )
14054 {
14055 ISQ_save_image( seq , fname , ppmto_jpg95_filter , ".jpg" ) ;
14056 return ;
14057 }
14058
ISQ_save_png(MCW_imseq * seq,char * fname)14059 void ISQ_save_png( MCW_imseq *seq , char *fname ) /* 11 Dec 2006 */
14060 {
14061 ISQ_save_image( seq , fname , ppmto_png_filter , ".png" ) ;
14062 return ;
14063 }
14064
14065 /*--------------------------------------------------------------------------*/
14066
ISQ_save_raw(MCW_imseq * seq,char * fname)14067 void ISQ_save_raw( MCW_imseq *seq , char *fname ) /* 13 Nov 2007 */
14068 {
14069 MRI_IMAGE *im ;
14070
14071 ENTRY("ISQ_save_raw") ;
14072 if( !ISQ_REALZ(seq) ) EXRETURN ;
14073 if( fname == NULL || *fname == '\0' ) fname = "image.raw" ;
14074
14075 im = ISQ_getimage( seq->im_nr , seq ) ;
14076
14077 if( im != NULL ){
14078 INFO_message("Writing one %dx%d raw image (type=%s bytes=%d) to file '%s'",
14079 im->nx,im->ny,MRI_TYPE_name[im->kind],im->nvox*im->pixel_size,fname ) ;
14080 mri_write_raw(fname,im); mri_free(im);
14081 }
14082 EXRETURN ;
14083 }
14084
14085 /*--------------------------------------------------------------------------*/
14086
ISQ_save_rawmont(MCW_imseq * seq,char * fname)14087 void ISQ_save_rawmont( MCW_imseq *seq , char *fname ) /* 13 Nov 2007 */
14088 {
14089 MRI_IMAGE *im ;
14090 MRI_IMARR *mar ;
14091 int nmont=seq->mont_nx * seq->mont_ny ,ij,nim,ijcen,nxyim ;
14092
14093 ENTRY("ISQ_save_raw_montage") ;
14094 if( !ISQ_REALZ(seq) ) EXRETURN ;
14095
14096 if( nmont < 2 ){
14097 INFO_message("save_rawmont: montage not turned on") ;
14098 ISQ_save_raw(seq,fname); EXRETURN;
14099 }
14100
14101 if( fname == NULL || *fname == '\0' ) fname = "image_montage.raw" ;
14102
14103 /* the following code is mostly from ISQ_make_montage() */
14104
14105 INIT_IMARR(mar) ;
14106
14107 ijcen = (seq->mont_nx)/2 + (seq->mont_ny/2) * seq->mont_nx ;
14108 for( nxyim=ij=0 ; ij < nmont ; ij++ ){
14109 nim = seq->im_nr + (seq->mont_skip + 1) * (ij - ijcen) ;
14110 im = ISQ_getimage( nim , seq ) ; if( im != NULL ) nxyim++ ;
14111 ADDTO_IMARR(mar,im) ;
14112 }
14113 if( nxyim == 0 ){
14114 ERROR_message("Raw montage error: no images found!") ;
14115 DESTROY_IMARR(mar) ; EXRETURN ;
14116 }
14117
14118 im = mri_cat2D( seq->mont_nx , seq->mont_ny , 0 , NULL , mar ) ;
14119 DESTROY_IMARR(mar) ;
14120
14121 if( im != NULL ){
14122 INFO_message("Writing one %dx%d raw image (type=%s bytes=%d) to file '%s'",
14123 im->nx,im->ny,MRI_TYPE_name[im->kind],im->nvox*im->pixel_size,fname ) ;
14124 mri_write_raw(fname,im); mri_free(im);
14125 } else {
14126 ERROR_message("Can't make raw montage for some reason!") ;
14127 }
14128
14129 EXRETURN ;
14130 }
14131
14132 /*--------------------------------------------------------------------------*/
14133 /*! Save the current images to an MPEG or AGIF file. [06 Dec 2006]
14134 Say the recorder has N images ZSS Jan 07
14135 if top < 0 then top = N +top
14136 top ==0 then top = N -1
14137 else top = min(top, N)
14138 if bot < 0 then bot = N +bot
14139 else bot = max(bot, 0)
14140
14141 use bot = 0 and top = 0 to save everything.
14142 */
14143
ISQ_save_anim(MCW_imseq * seq,char * prefin,int bot,int top,int mode)14144 void ISQ_save_anim( MCW_imseq *seq, char *prefin, int bot, int top, int mode )
14145 {
14146 int ii , kf , ll ;
14147 MRI_IMAGE *tim , *flim ;
14148 char *fnamep=NULL, *prefix ;
14149 THD_string_array *agif_list=NULL ;
14150 char tsuf[8] ;
14151 float dx,dy ;
14152 #ifndef USE_GIFF
14153 char *togif = ppmto_gif_filter ;
14154 #else
14155 char *togif = ppmto_giff_filter ;
14156 #endif
14157 int doanim=0 ;
14158 char filt[512], *ppo = NULL; FILE *fp ; MRI_IMAGE *ovim ;
14159 int nx , ny , npix , pc ;
14160 int adup=1 , akk,aa ; /* 10 Feb 2009 */
14161
14162 ENTRY("ISQ_save_anim") ;
14163
14164 if( !ISQ_REALZ(seq) ) EXRETURN ; /* bad input */
14165 switch( mode ){
14166 default: EXRETURN ; /* bad input */
14167
14168 case AGIF_MODE:
14169 if( ppmto_agif_filter == NULL || togif == NULL ){
14170 ERROR_message("Can't save AGIF - missing filter!\a") ; EXRETURN ;
14171 }
14172 doanim = 1 ;
14173 break ;
14174
14175 case MPEG_MODE:
14176 if( ppmto_mpeg_filter == NULL || ppmto_ppm_filter == NULL ){
14177 ERROR_message("Can't save MPEG - missing filter!\a") ; EXRETURN ;
14178 }
14179 doanim = 1 ;
14180 break ;
14181
14182 case JPEG_MODE:
14183 if( ppmto_jpg95_filter == NULL ){
14184 ERROR_message("Can't save JPEG - missing filter!\a") ; EXRETURN ;
14185 }
14186 doanim = 0 ;
14187 break ;
14188
14189 case PNG_MODE:
14190 if( ppmto_png_filter == NULL ){
14191 ERROR_message("Can't save PNG - missing filter!\a") ; EXRETURN ;
14192 }
14193 doanim = 0 ;
14194 break ;
14195 }
14196
14197 if (bot < 0) { /* special case */
14198 bot = seq->status->num_total+bot ;
14199 if (bot < 0) bot = 0;
14200 } else {
14201 bot = MAX(bot,0) ;
14202 }
14203 if( top < 0 ) {
14204 top = seq->status->num_total+top ;
14205 if (top > seq->status->num_total-1) top = seq->status->num_total-1;
14206 } else if (top == 0) {
14207 top = seq->status->num_total -1;
14208 } else {
14209 top = MIN(top,seq->status->num_total-1) ;
14210 }
14211 if( bot > top || (bot==top && doanim) ){
14212 ERROR_message("Can't save image range %d..%d!\a",bot,top) ; EXRETURN ;
14213 }
14214
14215 /*
14216 fprintf(stderr,
14217 "+++ Will save from %d to %d with %d images total in recorder.\n",
14218 bot, top, seq->status->num_total);
14219 */
14220 /*--- setup prefix for animation filename to save ---*/
14221
14222 if( prefin == NULL || *prefin == '\0' ) prefin = "Anim" ;
14223 if( !THD_filename_ok(prefin) ){
14224 ERROR_message("Bad image save filename '%s'\a",prefin) ; EXRETURN ;
14225 }
14226 ll = strlen(prefin) ;
14227 prefix = (char*)calloc( ll+16, sizeof(char)) ;
14228 strcpy( prefix , prefin ) ;
14229 fnamep = (char*)calloc( ll+32, sizeof(char)) ;
14230
14231 ppo = THD_trailname(prefix,0) ; /* strip directory */
14232
14233 if( prefix[ll-1] != '.' ){ /* add a . at the end */
14234 prefix[ll++] = '.' ; /* if one isn't there */
14235 prefix[ll] = '\0' ;
14236 }
14237
14238 tsuf[0] = (lrand48()>>5)%26 + 'A' ; /* random suffix */
14239 tsuf[1] = (lrand48()>>5)%26 + 'A' ; /* for animation */
14240 tsuf[2] = (lrand48()>>5)%26 + 'A' ; /* temp files */
14241 tsuf[3] = '\0' ;
14242
14243 #ifdef USE_GIFF /* create the fixed GIF colormap for animations */
14244 if( mode == AGIF_MODE ){
14245 MRI_IMAGE *im = mri_colorsetup( 76 , 6,6,5 ); /* 76 grays + */
14246 remove( GIFF_MAPFILE ) ; /* 6*red X 6*green X 5*blue */
14247 mri_write_pnm( GIFF_MAPFILE , im ) ;
14248 mri_free( im ) ;
14249 }
14250 #endif
14251
14252 if( mode == AGIF_MODE || mode == MPEG_MODE ){
14253 adup = (ISQ_anim_dup > 0) ? ISQ_anim_dup : AFNI_numenv("AFNI_ANIM_DUP") ;
14254 if( adup <= 0 ) adup = 1 ; else if( adup > 99 ) adup = 99 ;
14255 }
14256
14257 /*---- loop thru, get images, save them ----*/
14258
14259 if( doanim )
14260 INFO_message("Starting to save images to temp files") ;
14261 else
14262 INFO_message("Starting to save images") ;
14263
14264 for( akk=0,kf=bot ; kf <= top ; kf++ ){
14265
14266 /* get the underlay image */
14267
14268 tim = ISQ_getimage( kf , seq ) ;
14269
14270 /* if we failed to get the image? */
14271
14272 if( tim == NULL ) continue ; /* skip to next one? */
14273
14274 /* image to save will be in flim */
14275
14276 flim = tim ;
14277
14278 /* process image to make the grayscale index */
14279
14280 seq->set_orim = 0 ;
14281 tim = flim ;
14282 flim = ISQ_process_mri( kf , seq , tim , 0 ) ;
14283 if( tim != flim ) KILL_1MRI( tim ) ;
14284
14285 /* get overlay and flip it */
14286
14287 ovim = NULL ;
14288 if( !ISQ_SKIP_OVERLAY(seq) ){
14289 tim = ISQ_getoverlay( kf , seq ) ;
14290 if( tim != NULL && !ISQ_GOOD_OVERLAY_TYPE(tim->kind) ){
14291 KILL_1MRI(tim) ;
14292 }
14293 if( tim != NULL )
14294 ovim = mri_flippo( ISQ_TO_MRI_ROT(seq->opt.rot), seq->opt.mirror, tim );
14295 if( tim != ovim ) KILL_1MRI(tim) ;
14296 ISQ_apply_mask( seq->last_automask , ovim ) ;
14297 }
14298
14299 /* and perform overlay onto flim */
14300
14301 if( ovim != NULL ){
14302 tim = flim ;
14303 flim = ISQ_overlay( seq->dc , tim , ovim , seq->ov_opacity ) ;
14304 if( flim == NULL ){ flim = tim ; } /* shouldn't happen */
14305 else { KILL_1MRI(tim) ; }
14306 mri_free( ovim ) ;
14307 }
14308
14309 /* INFO_message("AFNI_IMAGE_SAVESQUARE = %s",getenv("AFNI_IMAGE_SAVESQUARE")); */
14310 if( AFNI_yesenv("AFNI_IMAGE_SAVESQUARE") ){ /* 08 Jun 2004 */
14311 flim->dx = seq->last_dx ; flim->dy = seq->last_dy ;
14312 tim = mri_squareaspect( flim ) ;
14313 if( tim != NULL ){ mri_free(flim); flim = tim; }
14314 }
14315
14316 /* if needed, convert from indices to RGB */
14317
14318 if( flim->kind == MRI_short ){
14319 tim = ISQ_index_to_rgb( seq->dc , 0 , flim ) ;
14320 mri_free(flim) ; flim = tim ;
14321 }
14322
14323 /* 26 Mar 2002: zoom out, and geometry overlay, maybe */
14324
14325 if( DO_BLOWUP(seq) ){
14326 int zf = MAX(seq->zoom_fac,seq->saver_blowup) ;
14327 // [PT: Dec 19, 2018] Change default behavior to be NN interp
14328 if( AFNI_noenv("AFNI_IMAGE_ZOOM_NN") ) mri_dup2D_mode(-7) ;
14329 tim = mri_dup2D(zf,flim) ;
14330 mri_dup2D_mode(7) ;
14331 mri_free(flim) ; flim = tim ;
14332 }
14333
14334 if( MCW_val_bbox(seq->wbar_plots_bbox) != 0 ){ /* draw geometry overlay */
14335 MEM_plotdata *mp ;
14336 mp = ISQ_getmemplot( kf , seq ) ;
14337 if( mp != NULL ){
14338 flip_memplot( ISQ_TO_MRI_ROT(seq->opt.rot),seq->opt.mirror,mp );
14339 /* mri_draw_force_opaque(1) ; */
14340 memplot_to_RGB_sef( flim, mp, 0,0,MEMPLOT_FREE_ASPECT ) ;
14341 /* mri_draw_force_opaque(0) ; */
14342 delete_memplot(mp) ;
14343 }
14344 }
14345
14346 if( seq->wbar_label_av->ival != 0 ){ /* 17 Jun 2005 */
14347 char *lab = ISQ_getlabel( kf , seq ) ;
14348 if( lab != NULL ){
14349 MEM_plotdata *mp = ISQ_plot_label( seq , lab ) ;
14350 if( mp != NULL ){
14351 /* mri_draw_force_opaque(1) ; */
14352 memplot_to_mri_set_dothick(1) ;
14353 memplot_to_RGB_sef( flim, mp, 0,0,MEMPLOT_FREE_ASPECT ) ;
14354 memplot_to_mri_set_dothick(0) ;
14355 /* mri_draw_force_opaque(0) ; */
14356 delete_memplot(mp) ;
14357 }
14358 free(lab) ;
14359 }
14360 }
14361
14362 if( seq->zoom_fac > 1 && /* crop zoomed image */
14363 seq->mont_nx == 1 && /* to displayed part? */
14364 seq->mont_ny == 1 &&
14365 AFNI_yesenv("AFNI_CROP_ZOOMSAVE") ) {
14366
14367 int xa,ya , iw=flim->nx/seq->zoom_fac , ih=flim->ny/seq->zoom_fac ;
14368
14369 xa = seq->zoom_hor_off * flim->nx ;
14370 if( xa+iw > flim->nx ) xa = flim->nx-iw ;
14371 ya = seq->zoom_ver_off * flim->nx ;
14372 if( ya+ih > flim->ny ) ya = flim->ny-ih ;
14373 tim = mri_cut_2D( flim , xa,xa+iw-1 , ya,ya+ih-1 ) ;
14374 if( tim != NULL ){ mri_free(flim); flim = tim; }
14375 }
14376
14377 /* image dimensions we are saving */
14378
14379 nx = flim->nx ; ny = flim->ny ; npix = nx*ny ;
14380
14381 /* create the filter command into string 'filt' */
14382
14383 for( aa=0 ; aa < adup ; aa++,akk++ ){ /* adup==1 if no animation */
14384
14385 switch( mode ){
14386 case AGIF_MODE:
14387 sprintf( fnamep, "%s%s.%05d.gif" , prefix,tsuf, akk) ;
14388 sprintf( filt , togif , fnamep ) ; /* free colormap */
14389 if( agif_list == NULL ) INIT_SARR(agif_list) ;
14390 ADDTO_SARR(agif_list,fnamep) ;
14391 break ;
14392
14393 case MPEG_MODE:
14394 sprintf( fnamep, "%s%s.%06d.ppm" , ppo,tsuf, akk) ;
14395 sprintf( filt , ppmto_ppm_filter , fnamep ) ;
14396 if( agif_list == NULL ) INIT_SARR(agif_list) ;
14397 ADDTO_SARR(agif_list,fnamep) ;
14398 break ;
14399
14400 case JPEG_MODE:
14401 sprintf( fnamep, "%s%05d.jpg" , prefix, kf) ;
14402 sprintf( filt , ppmto_jpg95_filter , fnamep ) ;
14403 if( agif_list == NULL ) INIT_SARR(agif_list) ;
14404 ADDTO_SARR(agif_list,fnamep) ;
14405 break ;
14406
14407 case PNG_MODE:
14408 sprintf( fnamep, "%s%05d.png" , prefix, kf) ;
14409 sprintf( filt , ppmto_png_filter , fnamep ) ;
14410 if( agif_list == NULL ) INIT_SARR(agif_list) ;
14411 ADDTO_SARR(agif_list,fnamep) ;
14412 break ;
14413 }
14414 #ifndef CYGWIN
14415 signal( SIGPIPE , SIG_IGN ) ; /* ignore broken pipe */
14416 #endif
14417 fp = popen( filt , "w" ) ; /* open pipe to filter */
14418 if( fp == NULL ){
14419 ERROR_message("Can't open output filter %s\a",filt) ;
14420 break ; /* out of loop over aa */
14421 }
14422
14423 /* write RGB image to pipe as a PPM file */
14424
14425 fprintf(fp,"P6\n%d %d\n255\n" , nx,ny ) ;
14426 fwrite( MRI_RGB_PTR(flim), sizeof(byte), 3*npix, fp ) ;
14427 pc = pclose(fp) ;
14428 if( pc == -1 ) perror("Error in image output pipe") ;
14429
14430 } /* end of loop over aa = image duplicates for animation */
14431
14432 /* done with this image */
14433
14434 mri_free(flim) ; flim = NULL ;
14435
14436 } /* end of loop over image sequence to save */
14437
14438 /** post-process saved images into animation? **/
14439
14440 if( agif_list != NULL && agif_list->num > 0 && doanim ){
14441
14442 int af ;
14443
14444 switch( mode ){
14445 /* animated GIF */
14446
14447 case AGIF_MODE:{
14448 int alen ; char *alc , *alf , *oof ;
14449 #ifdef USE_GIFF
14450 remove( GIFF_MAPFILE ) ; /* don't need this any longer */
14451 #endif
14452 for( alen=af=0 ; af < agif_list->num ; af++ ) /* size of all */
14453 alen += strlen( agif_list->ar[af] ) ; /* filenames */
14454
14455 alen += 3*agif_list->num + 32 ; /* all filenames */
14456 alc = AFMALL ( char, alen) ; alc[0] = '\0' ; /* in one string */
14457 for( alen=af=0 ; af < agif_list->num ; af++ ){
14458 strcat(alc," ") ; strcat(alc,agif_list->ar[af]) ;
14459 }
14460
14461 oof = AFMALL( char, strlen(prefix)+32 ) ; /* output fname */
14462 sprintf(oof,"%sgif",prefix) ;
14463
14464 alen = strlen(alc)+strlen(ppmto_agif_filter)+strlen(oof)+32 ;
14465 alf = AFMALL( char, alen) ;
14466 sprintf(alf , ppmto_agif_filter, alc, oof ) ; /* command to run */
14467 INFO_message("Running '%s'",alf) ;
14468 if( THD_is_ondisk(oof) ) WARNING_message("Over-writing '%s'",oof);
14469 system(alf) ; /* so run it! */
14470 free(alf) ; free(oof) ; free(alc) ; /* free trash */
14471 }
14472 break ;
14473
14474 /* MPEG-1 */
14475
14476 case MPEG_MODE:{
14477 int alen ; char *alf , *oof , *frate ;
14478 char *qscale , *pattrn ;
14479
14480 /* compose ffmpeg parameters */
14481 oof = AFMALL( char, strlen(prefix)+32 ) ; /* output fname */
14482 sprintf(oof,"%smpg",prefix) ;
14483 qscale=getenv("AFNI_MPEG_QSCALE") ; if(qscale==NULL) qscale="11";
14484 frate =getenv("AFNI_MPEG_FRAMERATE"); if(frate ==NULL) frate ="24";
14485 pattrn=getenv("AFNI_MPEG_PATTERN") ;
14486 if( pattrn == NULL ){
14487 /* by default use only I-frames */
14488 if( adup <= 1 ) pattrn="-intra";
14489 /* otherwise go with ffmpegs default */
14490 else pattrn="";
14491 }
14492 /* make command to run */
14493 alen = strlen(seq->saver_prefix) + strlen(ppmto_mpeg_filter)
14494 +1000 ;
14495 alf = AFMALL( char, alen) ;
14496 sprintf(alf,
14497 "%s -r %s -f image2 -i %s%s.%%06d.ppm -b 400k -qscale %s %s %s",
14498 ppmto_mpeg_filter, frate, seq->saver_prefix, tsuf, qscale,
14499 pattrn, oof) ; /* command to run */
14500 INFO_message("Running '%s' to produce %s",alf,oof) ;
14501 if( THD_is_ondisk(oof) ) WARNING_message("Over-writing '%s'",oof);
14502 system(alf) ; /* so run it! */
14503 free(alf); free(oof); /* free trash */
14504 }
14505 break ;
14506 }
14507
14508 /* animation is done, for good or for ill */
14509
14510 for( af=0 ; af < agif_list->num ; af++ ) /* erase temp files */
14511 remove( agif_list->ar[af] ) ;
14512 INFO_message("Done saving images") ;
14513
14514 } else if( agif_list != NULL && agif_list->num > 0 ){
14515 if( agif_list->num > 1 )
14516 INFO_message("%d images saved in files %s .. %s",
14517 agif_list->num ,
14518 agif_list->ar[0] , agif_list->ar[agif_list->num-1] ) ;
14519 else
14520 INFO_message("1 image saved in file %s",agif_list->ar[0]) ;
14521 }
14522
14523 /*--- go home ---*/
14524
14525 DESTROY_SARR(agif_list) ; free(prefix) ; free(fnamep); EXRETURN ;
14526 }
14527
14528 /*----------------------------------------------------------------------------*/
14529 /**** Stuff for the fun fun fun VG effect [RWC Feb 2017] ****/
14530
mri_streakize(MRI_IMAGE * im,MRI_IMAGE * sxim,MRI_IMAGE * syim)14531 static MRI_IMAGE * mri_streakize( MRI_IMAGE *im , MRI_IMAGE *sxim , MRI_IMAGE *syim )
14532 {
14533 MRI_IMAGE *qim ; byte *qar , *iar ;
14534 float *sxar , *syar ;
14535 int nx,ny,nxy , kk,dk , ii,jj,sk, dd,di,dj , ei,ej , ns ;
14536 float strk , sx,sy , rr,gg,bb , bsig,slo,shi ;
14537
14538 nx = im->nx ; ny = im->ny ; nxy = nx*ny ;
14539 bsig = sqrtf(nx*(float)ny) ;
14540
14541 /* min and max streak sizes */
14542 slo = 0.004f*bsig ; if( slo < 2.0f ) slo = 2.0f ;
14543 shi = 0.024f*bsig ; if( shi < 6.0f*slo ) shi = 6.0f*slo ;
14544
14545 qim = mri_copy(im) ; qar = MRI_RGB_PTR(qim) ; iar = MRI_RGB_PTR(im) ;
14546 sxar = MRI_FLOAT_PTR(sxim) ; syar = MRI_FLOAT_PTR(syim) ;
14547
14548 /* ININFO_message("mri_streakize") ; */
14549
14550 for( kk=0 ; kk < nxy ; kk++ ){
14551 /* get streak vector */
14552 sx = sxar[kk] ; sy = syar[kk] ;
14553 strk = sqrtf(sx*sx+sy*sy) ;
14554 if( strk == 0.0f ){
14555 sx = (2.0f*drand48()-1.0f)*slo ;
14556 sy = (2.0f*drand48()-1.0f)*slo ; strk = sqrtf(sx*sx+sy*sy);
14557 } else if( strk < slo ){
14558 sx *= (slo/strk) ; sy *= (slo/strk) ; strk = slo ;
14559 }
14560 sx /= strk ; sy /= strk ; /* unit vector */
14561 if( strk < slo ) strk = slo; else if( strk > shi ) strk = shi ;
14562 sk = (int)(strk+0.499f) ;
14563 /* color at start pixel */
14564 rr = iar[3*kk+0]; gg = iar[3*kk+1]; bb = iar[3*kk+2]; ns = 1;
14565 ii = kk % nx ; jj = kk / nx ;
14566 for( dd=1 ; dd <= sk ; dd++ ){ /* streaking */
14567 di = (int)(dd*sx+0.499f) ; dj = (int)(dd*sy+0.499f) ;
14568 /* if( di == 0.0f && dj == 0.0f ) continue ; */
14569 ei = ii+di ; ej = jj+dj ; /* the plus step */
14570 if( ei >= 0 && ei < nx && ej >= 0 && ej < ny ){
14571 dk = ei + ej*nx ;
14572 rr += iar[3*dk+0] ; gg += iar[3*dk+1] ; bb += iar[3*dk+2] ; ns++ ;
14573 }
14574 ei = ii-di ; ej = jj-dj ; /* the minus step */
14575 if( ei >= 0 && ei < nx && ej >= 0 && ej < ny ){
14576 dk = ei + ej*nx ;
14577 rr += iar[3*dk+0] ; gg += iar[3*dk+1] ; bb += iar[3*dk+2] ; ns++ ;
14578 }
14579 }
14580 if( ns > 1 ){ /* if we summed in any other pixels */
14581 rr /= ns ; gg /= ns ; bb /= ns ;
14582 qar[3*kk+0] = BYTEIZE(rr) ; qar[3*kk+1] = BYTEIZE(gg) ; qar[3*kk+2] = BYTEIZE(bb) ;
14583 }
14584 }
14585
14586 return qim ;
14587 }
14588
14589 /*----------------------------------------------------------------------------*/
14590
mri_vgize(MRI_IMAGE * iim)14591 static MRI_IMAGE * mri_vgize( MRI_IMAGE *iim )
14592 {
14593 MRI_IMAGE *blim , *gxim,*gyim , *bxim,*byim , *im ;
14594 float *bar , *gxar,*gyar , *bxar,*byar ;
14595 int nx,ny,nxy , ii,jj,kk,joff ;
14596 float bsig , bmax , gsiz , blen , bx,by , slen , cc,ss ;
14597 byte *iar ;
14598
14599 if( iim == NULL ) return NULL ;
14600
14601 im = mri_to_rgb(iim) ; iar = MRI_RGB_PTR(im) ;
14602
14603 nx = im->nx ; ny = im->ny ; nxy = nx*ny ;
14604
14605 bsig = sqrtf(nx*(float)ny) * vgize_sigfac ;
14606 if( bsig < 1.9f ) bsig = 1.9f ;
14607 /* INFO_message("mri_vgize: nx=%d ny=%d bsig=%.3f",nx,ny,bsig) ; */
14608
14609 #define NOIS_SIZ 27.0f
14610
14611 /* add colored noise to the image */
14612 #ifdef NOIS_SIZ
14613 if( ! AFNI_noenv("AFNI_VG_RANCOLOR") ){
14614 MRI_IMAGE *rrim , *ggim , *bbim , *qqim ;
14615 float *rrar , *ggar , *bbar , rmax,gmax,bmax , rr,gg,bb,qq , nois ;
14616 rrim = mri_new_conforming(im,MRI_float) ; rrar = MRI_FLOAT_PTR(rrim) ;
14617 ggim = mri_new_conforming(im,MRI_float) ; ggar = MRI_FLOAT_PTR(ggim) ;
14618 bbim = mri_new_conforming(im,MRI_float) ; bbar = MRI_FLOAT_PTR(bbim) ;
14619 nois = NOIS_SIZ + 222.2f*vgize_sigfac ;
14620 for( kk=0 ; kk < nxy ; kk++ ){
14621 rrar[kk] = (float)(11.0*drand48()-5.0) ;
14622 ggar[kk] = (float)(10.0*drand48()-5.0) ;
14623 bbar[kk] = (float)(11.0*drand48()-5.0) ;
14624 }
14625 qqim = mri_float_blur2D(0.4f*bsig,rrim); mri_free(rrim); rrim = qqim; rrar = MRI_FLOAT_PTR(rrim);
14626 qqim = mri_float_blur2D(0.4f*bsig,ggim); mri_free(ggim); ggim = qqim; ggar = MRI_FLOAT_PTR(ggim);
14627 qqim = mri_float_blur2D(0.4f*bsig,bbim); mri_free(bbim); bbim = qqim; bbar = MRI_FLOAT_PTR(bbim);
14628 rmax = gmax = bmax = 0.0f ;
14629 for( kk=0 ; kk < nxy ; kk++ ){
14630 qq = fabsf(rrar[kk]) ; if( qq > rmax ) rmax = qq ;
14631 qq = fabsf(ggar[kk]) ; if( qq > gmax ) gmax = qq ;
14632 qq = fabsf(bbar[kk]) ; if( qq > bmax ) bmax = qq ;
14633 }
14634 rmax = NOIS_SIZ/rmax ; gmax = NOIS_SIZ/gmax ; bmax = NOIS_SIZ/bmax ;
14635
14636 for( kk=0 ; kk < nxy ; kk++ ){
14637 rr = (float)iar[3*kk+0] + rrar[kk]*rmax; iar[3*kk+0] = BYTEIZE(rr);
14638 gg = (float)iar[3*kk+1] + ggar[kk]*gmax; iar[3*kk+1] = BYTEIZE(gg);
14639 bb = (float)iar[3*kk+2] + bbar[kk]*bmax; iar[3*kk+2] = BYTEIZE(bb);
14640 }
14641 mri_free(rrim); mri_free(ggim); mri_free(bbim);
14642 }
14643 #endif
14644
14645 bxim = mri_to_float(im) ;
14646 blim = mri_float_blur2D( bsig , bxim ) ; mri_free(bxim) ;
14647 bar = MRI_FLOAT_PTR(blim) ;
14648
14649 gxim = mri_new_conforming(blim,MRI_float) ; gxar = MRI_FLOAT_PTR(gxim) ;
14650 gyim = mri_new_conforming(blim,MRI_float) ; gyar = MRI_FLOAT_PTR(gyim) ;
14651
14652 /* ININFO_message("compute gradients") ; */
14653 for( jj=0 ; jj < ny ; jj++ ){
14654 joff = jj*nx ;
14655 for( ii=0 ; ii < nx ; ii++ ){
14656 if( jj==0 || jj==ny-1 || ii==0 || ii==nx-1 ){
14657 gxar[ii+joff] = gyar[ii+joff] = 0.0f ;
14658 } else {
14659 gxar[ii+joff] = bar[ii+joff+1 ] - bar[ii+joff-1 ] ;
14660 gyar[ii+joff] = bar[ii+joff+nx] - bar[ii+joff-nx] ;
14661 }
14662 }}
14663
14664 /* ININFO_message("blur gradients") ; */
14665 bxim = mri_float_blur2D(0.5f*bsig,gxim); mri_free(gxim); bxar = MRI_FLOAT_PTR(bxim);
14666 byim = mri_float_blur2D(0.5f*bsig,gyim); mri_free(gyim); byar = MRI_FLOAT_PTR(byim);
14667
14668 /* ININFO_message("find gradient max") ; */
14669 bmax = 0.0f ;
14670 for( kk=0 ; kk < nxy ; kk++ ){
14671 gsiz = bxar[kk]*bxar[kk] + byar[kk]*byar[kk] ;
14672 if( gsiz > bmax ) bmax = gsiz ;
14673 }
14674 bmax = sqrtf(bmax) ;
14675 /* ININFO_message("bmax=%g",bmax) ; */
14676 if( bmax == 0.0f ){ mri_free(bxim); mri_free(byim); mri_free(im); return NULL; }
14677
14678 /* scale gradients by largest one */
14679
14680 bmax = 1.0f / bmax ;
14681 slen = 1.3f * bsig ;
14682 for( kk=0 ; kk < nxy ; kk++ ){
14683 bx = bxar[kk]*bmax ; by = byar[kk]*bmax ; gsiz = sqrtf(bx*bx+by*by) ;
14684 if( gsiz > 0.0f ){
14685 cc = 0.111f + 2.69f*gsiz ; if( cc > 1.0f ) cc = 1.0f ;
14686 bx *= (cc*slen/gsiz) ; by *= (cc*slen/gsiz) ;
14687 }
14688 bxar[kk] = by ; byar[kk] = -bx ; /* streak direction */
14689 bar[kk] = (float)(30.0*drand48()-15.0) ; /* random angle for streak */
14690 }
14691
14692 /* ININFO_message("blur angles") ; */
14693 gxim = mri_float_blur2D(0.5f*bsig,blim); mri_free(blim); gxar = MRI_FLOAT_PTR(gxim);
14694 bmax = 0.0f ;
14695 for( kk=0 ; kk < nxy ; kk++ ){
14696 gsiz = fabsf(gxar[kk]) ; if( gsiz > bmax ) bmax = gsiz ;
14697 }
14698 /* ININFO_message("max angle=%g",bmax) ; */
14699
14700 /* rotate streak directions randomly */
14701 if( bmax > 0.0f && vgize_sigfac > 0.0111f ){
14702 bmax = (22.2f * PI/180.0f) / bmax ; /* max angle is 22.2 degrees */
14703 for( kk=0 ; kk < nxy ; kk++ ){
14704 bx = bxar[kk] ; by = byar[kk] ;
14705 gsiz = sqrtf(bx*bx+by*by) ;
14706 cc = cosf(bmax*gxar[kk]) ;
14707 ss = sinf(bmax*gxar[kk]) ;
14708 if( gsiz < 2.0f ){
14709 bxar[kk] = 2.2f*cc ; byar[kk] = 2.2f*ss ;
14710 } else {
14711 bxar[kk] = cc*bx + ss*by ;
14712 byar[kk] = -ss*bx + cc*by ;
14713 }
14714 }
14715 }
14716 mri_free(gxim) ;
14717
14718 blim = mri_streakize( im , bxim , byim ) ; /* do the streaking */
14719
14720 mri_free(bxim) ; mri_free(byim) ; mri_free(im) ;
14721
14722 im = mri_sharpen_rgb(0.666f,blim) ; mri_free(blim) ; /* 26 Sep 2017 */
14723 return im ;
14724 }
14725