1 //
2 // Copyright 1996-2018 by Manolo Gouy.
3 //
4 // This program, except where indicated, is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public
6 // License as published by the Free Software Foundation;
7 // either version 3 of the License, or (at your option) any later version.
8 //
9 // Three files (dnapars.c, protpars.c and seq.c) have a distinct license
10 // which authorizes distribution. They are Copyright Joseph Felsenstein
11 //
12 // Three files (bionj.c, phyml_util.c and phyml_util.h) are also covered by the
13 // GNU General Public License but are copyright Stephane Guindon.
14 //
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 // General Public License for more details.
19 //
20 // Additional permission under GNU GPL version 3 section 7
21 //
22 // If you modify this Program, or any covered work, by linking or combining it with PHYLIP
23 // (or a modified version of that library), containing parts covered by the terms of
24 // the University of Washington license, the licensor of this Program grants you additional
25 // permission to convey the resulting work.
26 //
27 // A copy of the GNU General Public License is available
28 // from http://www.gnu.org/licenses/gpl.txt .
29 //
30 // Please report all bugs and problems to "manolo.gouy@univ-lyon1.fr".
31 
32 /*
33  Version 4.2    10_OCT_2009
34   Added cladogram tree display and copy fasta-seqs to clipboard.
35  Version 4.1    27_JUN_2009
36   Added nucleotide ambiguity symbols in consensus DNA sequences
37  Version 4.0    27_MAY_2009
38   Added tree computing and drawing
39  Version 3.2    22_OCT_2008
40 	Import from databases: can use keyword
41                 15_OCT_2008
42 	WIN32: correct display of UTF8 filenames in window and messages
43  Version 3.1    08_OCT_2008
44 	now use Fl_Native_File_Chooser (with slightly changed macOS version)
45 	MacOS: correct display of UTF8 filenames in windows and menu and in messages for
46 		left-to-right scripts
47  Version 3.0    11_SEP_2008
48 	added File:Import from DB
49  Version 2.4    04_MAR_2008
50                 phylip format allows to customize max name length
51  Version 2.3    22_FEB_2008
52 		corrected bug if deleting/adding/moving seqs when in 'view as proteins' mode
53  Version 2.2    6_OCT_2007
54 		added support for multiple alignment windows
55  Version 2.1    19_SEP_2007
56 		added interface to external multiple alignment programs
57  Version 2.0	22_AUG_2007
58 		added Props:View as proteins
59 		added Edit:Set genetic code
60 		added Edit:Align all sequences
61 		added File:Save prot alignmnt
62 */
63 #if !defined(WIN32)
64 #include <unistd.h>
65 #endif
66 
67 #include "seaview.h"
68 #include "treedraw.h"
69 #include <string.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <ctype.h>
73 #include <FL/Fl_Double_Window.H>
74 #include <FL/Fl_Pack.H>
75 #include <FL/Fl_Hold_Browser.H>
76 #include <FL/Fl_Round_Button.H>
77 #include <FL/Fl_Check_Button.H>
78 #include <FL/Fl_Help_Dialog.H>
79 #include <FL/Fl_Menu_Bar.H>
80 #include <FL/Fl_Paged_Device.H>
81 
82 #include "seaview.xpm"
83 
84 /* allongement maximal prevu pour les seqs suite a edition */
85 #define MAX_SEQ_ALLONG 5000
86 #define CLIPBOARDMARK "seaview_alignment_clipboard:"
87 /*
88 Purpose
89 resource	argument	type		default			exemple
90 
91 Default file format for saving operations
92 save		-save		{mase, phylip,	mase			phylip
93 			    clustal, msf, fasta, nexus}
94 
95 Control of printout options
96 printoutblock	N/A		integer		10			3
97 printoutcpl	N/A		integer		80			90
98 	[this is the paper width, not the # of residues desired on each line]
99 printoutlpp	N/A		integer		66			90
100 Name of help file
101 helpfile	N/A		string		"seaview.help"
102 
103 Standard coloring of protein sequences (<= 10 colors + white for gaps)
104 (colors are red, green, yellow, blue, cyan, magenta, salmon, purple, aquamarine,
105 and dark-gray)
106 stdcolorgroups	N/A		string		EDQNHRKBZ,ILMV,APSGT,FY,WC
107 						      BZDE,ACWY,FGHIK,LMNPQRSTV
108 Alternate coloring of protein sequences
109 altcolorgroups	N/A		string		\0	AC,DEFGHIK,LMNPQRS,WY,TV
110 
111 Faster but less smooth writing
112 fast		-fast		no-value	False
113 
114 Residues colored on background
115 inverted	-inverted	no-value	False
116 
117 N/A		filename
118 */
119 
120 Fl_Group *create_dna_scroller(SEA_VIEW *view, int x, int y, int w, int h,
121 	int dbl_buff);
122 SEA_VIEW *create_the_form(int double_buffer);
123 int prep_custom_colors(int *colors, char *customcolors,
124 	int max_colors);
125 color_choice prep_aa_color_code(char *list_std, char *list_alt,
126 	int maxprotcolors, int *numb_stdprotcolors, int *numb_altprotcolors);
127 void deplacer_grp_seqs(SEA_VIEW *view, int target);
128 void del_gap_only_sites(SEA_VIEW *view);
129 void reference_toggle(SEA_VIEW *view, int on);
130 void help_callback(Fl_Widget *ob, void *unused);
131 void help_items_callback(Fl_Widget *ob, void *data);
132 void direct_help_callback(Fl_Widget *wgt, void *data);
133 void handle_paste(SEA_VIEW *view, char *clipboard, int doing_dnd);
134 void handle_mouse(SEA_VIEW *view, int mx, int my,
135 	int *p_selecting_seqs, int *p_sel_seq_move, int *p_modifying_segment);
136 void handle_keyboard(SEA_VIEW *view, unsigned int key, int istext);
137 void handle_push(SEA_VIEW *view, int mx, int my, int key,
138 	int *p_modifying_segment, int *p_selecting_seqs, int *p_sel_seq_move);
139 int delete_gaps_before(SEA_VIEW *view, int numseq, int numsite, int total);
140 void set_save_format(SEA_VIEW *view, int val);
141 Fl_Window *use_initial_file(SEA_VIEW *view, char *masename, int doing_dnd);
142 Fl_Window* pdfps_options_dialog(SEA_VIEW *view, bool autonomous);
143 void mainwin_close_callback(Fl_Widget *form, void *data);
144 void to_do_at_exit(void);
145 SEA_VIEW *newwindow_callback(SEA_VIEW *old_view);
146 //void fix_paste_timeout(void *);
147 void hide_window_callback(Fl_Widget *ob, void *data);
148 void free_colranks_by_difference(char **alt_col_rank, int total);
149 char *create_tmp_filename(void);
150 void delete_tmp_filename(const char *base_fname);
151 void draw_seq_names(Fl_Widget *ob, SEA_VIEW *view);
152 
153 /* external functions */
154 void draw_comment_lines(Fl_Widget *ob, SEA_VIEW *view);
155 char* seaview_file_chooser_save_as(const char* message,
156 	const char* fname, SEA_VIEW *view, known_format* new_format);
157 void load_resources(const char *progname);
158 char *get_res_value(const char *name, const char *def_value);
159 int int_res_value(const char *name, int def_value);
160 int bool_res_value(const char *name, int def_value);
161 void minuscules(char *);
162 known_format what_format(const char *filename);
163 extern void custom_callback(Fl_Widget *obj, void *data);
164 extern void stats_callback(Fl_Widget *obj, void *data);
165 void adjust_menu_edit_modes(SEA_VIEW *view);
166 extern void *set_viewasprots(SEA_VIEW * view, int onoff);
167 extern void racnuc_dialog(SEA_VIEW *view);
168 extern void disconnect_tree_windows(SEA_VIEW *view);
169 extern void concatenate_dialog(SEA_VIEW *view);
170 extern int get_ncbi_gc_from_comment(char *comment);
171 extern "C" {
172   char codaa(char *codon, int code);
173   int get_acnuc_gc_number(int ncbi_gc);
174   void compact(char *chaine);
175   }
176 #ifdef __APPLE__
177 extern char *mac_GetOutputFName_Plus(const char *dfault, const char *message, int use_only_button,
178 									 const char *dirname);
179 #if 100*FL_MAJOR_VERSION + FL_MINOR_VERSION < 104
180   extern int find_windowmenuitem(Fl_Window *w);
181   extern int add_windowmenuitem(const char *name, Fl_Window *w);
182   extern void rename_windowmenuitem(const char *name, int rank);
183   extern void delete_windowmenuitem(int rank);
184 #endif
185 extern int set_res_value(const char *name, const char *value);
186 extern void fl_mac_set_about( Fl_Callback *cb, void *user_data, int shortcut );
187 extern void MG_apple_inits(void);
188 extern void mac_tmp_dir_name(char *buffer, int l);
189 #elif defined(WIN32)
190 extern char **getutf8args(int *pargc);
191 #else
192 extern void inform_prog_dir(const char *arg0);
193 #endif
194 extern int printout(SEA_VIEW *view, const char *filename,
195 	int fontsize, int block_size, Fl_Paged_Device::Page_Format pageformat, int vary_only, int ref0,
196 	int pdfkindvalue, Fl_Paged_Device::Page_Layout layout, int svg_width = 0);
197 extern void set_ncbi_genetic_code(SEA_VIEW *view);
198 extern void cre_align_menu(SEA_VIEW *view);
199 extern void init_msa_algos(void);
200 extern void parse_trees_from_header(char *header, SEA_VIEW *view);
201 extern void decode_codon_colors(int *colors);
202 extern void select_deselect_in_tree(SEA_VIEW *view);
203 extern void format_conversion(int argc, char **argv);
204 extern void command_line_phylogeny(int argc, char **argv);
205 extern int command_line_align(int argc, char **argv);
206 extern void concatenate_no_gui(int argc, char *argv[]);
207 extern void save_bootstrap_replicates(const char *fname, int replicates, SEA_VIEW *view);
208 
209 /* global variables */
210 /* to control parameters of option printout */
211 Fl_Paged_Device::Page_Format printout_pageformat;
212 Fl_Paged_Device::Page_Layout printout_layout = Fl_Paged_Device::PORTRAIT;
213 int printout_block, printout_fontsize, printout_black = PDF_COLOR, print;
214 int printout_vary = FALSE;
215 const char *f_format_names[] = {"Mase", "Phylip", "Clustal", "MSF", "Fasta", "NEXUS"};
216 const char *f_format_exts[] = {"mase", "phy", "aln", "msf", "fst", "nxs"};
217 int nbr_formats = sizeof(f_format_names)/sizeof(char *);
218 //char def_stdcolorgroups[] = "EDQNHRKBZ,ILMV,APSGT,FY,WC";
219 char def_stdcolorgroups[] = "KR,AFILMVW,NQST,HY,C,DE,P,G";
220 //int def_protcolors[] =
221 //	{ FL_WHITE, FL_RED, FL_GREEN, FL_YELLOW, FL_BLUE, FL_CYAN,
222 //	FL_MAGENTA, 9/*salmon*/, 13/*purple*/, 14/*aquamarine*/, 8/*darkgray*/};
223 int def_protcolors_rgb[] =
224 	{255,255,255, /* white */
225 	230,51,25,   25,128,230,   25,204,25,   25,179,179,   230,128,128,
226 	204,77,204,   204,204,0,   230,153,77,
227 	128,128,128,    100,100,100 };
228 int numb_stdprotcolors, numb_altprotcolors;
229 color_choice curr_color_choice;
230 int max_protcolors = sizeof(def_protcolors_rgb) / sizeof(int) / 3;
231 int *def_protcolors;
232 const char *progname = "seaview";
233 char *clipboardfname = NULL; // name of temporary file used to hold copied data
234 extern char aminoacids[]; // from misc_acnuc.c
235 static int defaultfontsize =
236 #ifdef WIN32
237 	12;
238 #else
239 	14;
240 #endif
241 
242 #ifdef WIN32
243 #define LINE_HEIGHT_FACTOR  0.85
244 #else
245 #define LINE_HEIGHT_FACTOR  1.
246 #endif
247 static int pasted_from_what_source; // gives what source was used for paste: 0=selection, 1=clipboard
248 
249 extern void plotonly(int argc, char *argv[]);
250 extern void printout_cmdline(int argc, char **argv);
251 extern bool isarg(int argc, char *argv[], const char *arg);
252 extern char *argname(int argc, char *argv[], const char *arg);
253 
254 
main(int argc,char * argv[])255 int main(int argc, char *argv[])
256 {
257 #if defined(WIN32)
258   argv = getutf8args(&argc);
259 #endif
260   if (isarg(argc, argv, "-h")) {
261     fputs("Usage:\nseaview [options] [alignment-or-tree-file]\n"
262 	    "where alignment-or-tree-file is an optional sequence alignment or tree file to be read (always the last argument) and options are:\n"
263 	    "-h            display all program options and exit\n"
264 	    "-fontsize n   font size used for the tree plot or alignment windows\n"
265 	    "-fast         sequences will be displayed faster but less smoothly\n"
266 	    "     Options for non-interactive usage driven by command-line arguments\n"
267 	    "(Use exactly one for a non-interactive seaview run. Add any sub-option described below)\n"
268 	    "-convert      convert an input alignment to another format (no window creation)\n"
269 	    "-concatenate  concatenate alignment(s) to the end of an input alignment (no window creation)\n"
270 	    "-align        align an input sequence file (no window creation)\n"
271 	    "-build_tree   compute a phylogenetic tree from an input alignment file (no window creation)\n"
272 #ifndef NO_PDF
273 	    "-printout     draws a multiple sequence alignment to PDF/SVG (no window creation)\n"
274 	    "-reroot       modify the rooting of, or process otherwise, an input tree (no window creation)\n"
275 	    "-plotonly     draw an input tree in a pdf or svg file (no window creation)\n"
276 #endif
277 
278 	    "\n"
279 	    "           Sub-options for -convert\n"
280 	    "           Use '-' as last argument to read alignment from standard input\n"
281 	    "-output_format fmt    format of the converted alignment file (mase, phylip, clustal, msf, fasta, or nexus)\n"
282 	    "-o fname      use fname as name of the converted alignment (default is built from input filename)\n"
283 	    "-o -          write the output alignment to standard output\n"
284 	    "-translate    translate input sequences to protein before outputting them (don't use -sites)\n"
285 	    "-no_terminal_stop   translate terminal stop codons as a gap (with -translate option)\n"
286 	    "-del_gap_only_sites  remove all gap-only sites from alignment (don't use the -sites option)\n"
287 	    "-def_species_group group_name,group_member_ranks   create a species group of given name and members\n"
288 	    "                  (species group members are expressed with their ranks as in this example: 3-8,12,19)\n"
289 	    "-def_site_selection name,endpoints   create a selection of sites of given name and endpoints\n"
290 	    "                  (site selection endpoints are expressed as in this example: 10-200,305,310-342)\n"
291 	    "-gblocks      create under the name 'Gblocks' a set of blocks of conserved sites with the Gblocks program\n"
292       "                  (requires the nexus or mase output formats)\n"
293 	    "      -gblocks-specific options:\n"
294 	    "              -b4 allow smaller final blocks\n"
295 	    "              -b5 allow gaps within final blocks \n"
296 	    "              -b2 less strict flanking positions \n"
297 	    "              -b3 don't allow many contiguous nonconserved positions\n"
298 	    "-sites selection_name    use the named selection of sites from the input alignment \n"
299 	    "-species species_group_name    use the named group of species from the input alignment \n"
300       "-bootstrap n    writes n bootstrap replicates of the input alignment to the output file \n"
301 
302 	    "\n"
303 	    "           Sub-options for -concatenate \n"
304 	    "           Use '-' as last argument to read alignment from standard input\n"
305 	    "-concatenate align1,...    name(s) of alignment files to add at the end of the input alignment\n"
306 	    "-by_rank      identify sequences by their rank in alignments (rather than by their name)\n"
307       "-record_partition record the locations of the concatenated pieces in the final concatenate\n"
308 	    "-output_format fmt    format of the concatenated alignment (mase, phylip, clustal, msf, fasta, or nexus)\n"
309 	    "-o fname      use fname as name of the concatenated alignment (default is built from input filename)\n"
310 	    "-o -          write the concatenated alignment to standard output\n"
311 
312 	    "\n"
313 	    "           Sub-options for -align \n"
314 	    "           Use '-' as last argument to read sequence file from standard input\n"
315 	    "-align_algo n  rank (in seaview from 0) of alignment algorithm, otherwise use seaview's default alignment algorithm\n"
316 	    "-align_extra_opts \"option1 ...\"  additional options to use when running the alignment algorithm\n"
317 	    "-align_at_protein_level  translate and align input sequences and reproduce alignment at DNA level.\n"
318 	    "-output_format fmt    format of the output alignment (mase, phylip, clustal, msf, fasta, or nexus)\n"
319 	    "-o fname      use fname as name of the output alignment (default is built from input filename)\n"
320 	    "-o -          write the output alignment to standard output\n"
321 
322 	    "\n"
323 	    "           Sub-options for -build_tree (either -distance or -parsimony is required)\n"
324 	    "           Use '-' as last argument to read alignment from standard input\n"
325 	    "-o fname      use fname as name of the output tree\n"
326 	    "-o -          write the output tree to standard output\n"
327 	    "-distance dist_name   computes the tree with a distance method using dist_name (observed, JC, K2P, logdet, Ka, Ks, Poisson or Kimura)\n"
328 	    "-distance_matrix fname  don't compute the tree, but write to fname the matrix of pairwise distances\n"
329 	    "-NJ           compute the distance tree by the Neighbor-Joining method (default is BioNJ)\n"
330 	    "-parsimony    compute the tree by the parsimony method \n"
331 	    "-search more|less|one  controls how much rearrangement is done to find better trees (DNA parsimony only)\n"
332 	    "-nogaps       remove all gap-containing sites before computations\n"
333 	    "-replicates n use n bootstrap replicates to compute tree branch support\n"
334 	    "-jumbles n    jumble sequence order n times (parsimony only)\n"
335 	    "-gaps_as_unknown  encode gaps as unknown character state (parsimony only)\n"
336 	    "-sites selection_name    use the named selection of sites from the input alignment \n"
337 	    "-species species_group_name    use the named group of species from the input alignment \n"
338 
339 #ifndef NO_PDF
340 	  "\n"
341 	  "           Sub-options for -printout (-o fname is required)\n"
342 	  "           Use '-' as last argument to read alignment from standard input\n"
343 	  "-o fname     use fname as name of the output PDF/SVG file\n"
344 	  "-o -         write the printout to standard output\n"
345 	  "-fontsize n  font size used for the alignment printout (10 by default)\n"
346 	  "-blocksize n divide sequences in blocks of size n (10 by default) separated by one space\n"
347 	  "-svg  w      produce a file in SVG format of width w pixels\n"
348 	  "               (without this option, the output is in PDF format)\n"
349 	  "-landscape   write the alignment in landscape orientation (PDF output only)\n"
350 	  "-letter      write the alignment using Letter-sized pages (A4 by default, PDF output only)\n"
351 
352 	    "\n"
353 	    "           Sub-options for -reroot\n"
354 	    "           Use '-' as last argument to read input tree from standard input\n"
355 	    "-outnewick filename   write the resulting tree to named file in Newick format\n"
356 	    "-outgroup name   use tree leaf labelled 'name' as tree outgroup\n"
357 	    "-outgroup \"name1,name2,name3\" use node at center of the 3 names as tree center\n"
358 	    "               and name3-containing clade as outgroup\n"
359 	    "-ingroup \"name1,name2,name3\" use node at center of the 3 names as tree center\n"
360 	    "               and name1-containing clade as ingroup\n"
361 	    "-root_at_center   reroot the tree at its center\n"
362 	    "-unroot       remove the root from the input tree, if any\n"
363             "-trim r       rule to trim long tree leaf names in output tree file (def=no trimming)\n"
364 	    "-patristic_distances fname    write to named file patristic distances for leaves of input tree\n"
365 	    "-remove_bootstrap    remove branch support values present in input tree\n"
366 
367 	    "\n"
368 	    "           Sub-options for -plotonly\n"
369 	    "options -outgroup, -ingroup, -outnewick above plus the following:\n"
370 	    "           Use '-' as last argument to read tree from standard input\n"
371 	    "-o fname      use fname as name of the output plot (.pdf or .svg)\n"
372 	    "-o -          write the output plot to standard output (svg only)\n"
373 	    "-svg          draw the input tree in a .svg file (default is .pdf file)\n"
374 	    "-unrooted     draw the input tree in unrooted (circular) form\n"
375 	    "-pagecount n  number of pages used for the tree plot (pdf only)\n"
376 	    "-letter       use letter-sized paper for the tree plot\n"
377 	    "-fontsize n   font size used in the tree plot\n"
378 	    "-lengths      display branch lengths in the tree plot\n"
379 	    "-bootstrap    display branch support values in the tree plot\n"
380 	    "-bootstrap_threshold x    display branch supports if >= x\n"
381 	    "-size WxH     pixel Width and Height of tree plot (svg only) (default is 595x842)\n"
382 	    "-match text   display in color (red by default) tree labels containing this text (case is not significant)\n"
383 	    "-color RRGGBB hexadecimal color used for matching labels (example: 00FF00 means green)\n"
384 	    "-branch_width_as_support  draw plot with branches of increasing widths with increasing support\n"
385 	    "-support_threshold_high f support above which a branch is drawn with maximal width (def=.95)\n"
386 	    "-support_threshold_low f support below which a branch is drawn with minimal width (def=.8)\n"
387             "-trim r       rule to trim long tree leaf names (def=no trimming)\n"
388 #endif
389 	    , stdout);
390     fputs("\nSee http://doua.prabi.fr/software/seaview_data/seaview#Program%20arguments for more details\n", stdout);
391     return 0;
392     }
393 #if !(defined(WIN32) || defined(__APPLE__))
394   inform_prog_dir(argv[0]);
395 #endif
396 
397 
398 #ifndef NO_PDF
399   if ( isarg(argc, argv, "-remove_bootstrap") && !isarg(argc, argv, "-reroot")) {
400     fprintf(stderr, "Must use also -reroot when -remove_bootstrap is used\n");
401     exit(1);
402   }
403   if (isarg(argc, argv, "-plotonly") || isarg(argc, argv, "-reroot")) {
404     plotonly(argc, argv);
405     return 0;
406     }
407   if (isarg(argc, argv, "-printout")) {
408     printout_cmdline(argc, argv);
409     return 0;
410   }
411 #endif
412   if (isarg(argc, argv, "-convert")) {
413     format_conversion(argc, argv);
414     return 0;
415   }
416   if (isarg(argc, argv, "-build_tree")) {
417     command_line_phylogeny(argc, argv);
418     return 0;
419   }
420   if (isarg(argc, argv, "-concatenate")) {
421     concatenate_no_gui(argc, argv);
422     return 0;
423   }
424   if (isarg(argc, argv, "-align")) {
425     return command_line_align(argc, argv);
426   }
427 #ifdef __APPLE__
428   MG_apple_inits();
429 #endif
430 #ifdef WIN32
431     update_treerecs_prog_path(get_full_path("treerecs.exe"));
432 #else
433     update_treerecs_prog_path(get_full_path("treerecs"));
434 #endif
435 
436 Fl_Pixmap* px = new Fl_Pixmap(seaview_xpm);
437 const Fl_RGB_Image* icon = new Fl_RGB_Image(px);
438 delete px;
439 Fl_Window::default_icon(icon);
440 delete icon;
441 Fl_Window::default_xclass("FLTK");
442 char *masename;
443 int i;
444 
445 static int quick_and_dirty;
446 
447 load_resources(progname);
448 init_msa_algos();
449 
450 // access to resources
451 #ifdef __APPLE__
452 quick_and_dirty = TRUE;
453 #else
454 quick_and_dirty = bool_res_value("fast", FALSE);
455 #endif
456 printout_block = int_res_value("printoutblock", 10);
457 printout_fontsize = int_res_value("printoutfontsize", 10);
458 if(strcmp( get_res_value("printoutpageformat", "A4") , "A4") == 0)
459   printout_pageformat = Fl_Paged_Device::A4;
460 else printout_pageformat = Fl_Paged_Device::LETTER;
461   defaultfontsize = int_res_value("sequencefontsize", defaultfontsize);
462 fl_message_font(FL_HELVETICA_BOLD, FL_NORMAL_SIZE );
463 
464 // argument processing
465 masename = NULL;
466 i = 1;
467 while(i < argc) {
468 	if(argv[i][0] != '-') masename = argv[i];
469 	if(strcmp(argv[i], "-fast") == 0) quick_and_dirty = TRUE;
470 	if(strcmp(argv[i], "-fontsize") == 0) {
471 		if(++i < argc) sscanf(argv[i], "%d", &defaultfontsize);
472 		}
473 	i++;
474 	}
475   clipboardfname = strdup( create_tmp_filename() );
476   atexit(to_do_at_exit);
477 #ifdef __APPLE__
478   SEA_VIEW *view = NULL;
479   Fl::wait(0); // creates the windows related to files dropped at launch
480   if (Fl::first_window() == 0) {
481     // if there is no window already, create an empty one
482     view = create_the_form(!quick_and_dirty);
483   } else { // a window is created, do not process file in argument list
484     masename = 0;
485   }
486 #else
487 SEA_VIEW *view = create_the_form(!quick_and_dirty);
488 #endif
489 //Fl::add_timeout(0.5, fix_paste_timeout);
490 if (masename != NULL) use_initial_file(view, masename, FALSE);
491 Fl::lock();
492 Fl::run();
493 return 0;
494 }
495 
496 
use_initial_file(SEA_VIEW * view,char * masename,int doing_dnd)497 Fl_Window *use_initial_file(SEA_VIEW *view, char *masename, int doing_dnd)
498 /* returns the window containing the loaded data (alignment or tree) or NULL
499  */
500 {
501 known_format defaultformat;
502 Fl_Window *w = NULL;
503 
504 defaultformat = what_format(masename);
505 if ((int)defaultformat >= 0) {
506 	w = load_alignment_file(view, masename, NULL, defaultformat, doing_dnd);
507 	}
508 else if((int)defaultformat == -2) {// a Newick tree
509 	FILE *in = fopen(masename, "r");
510 	fseek(in, 0, SEEK_END);
511 	long l = ftell(in);
512 	fseek(in, 0, SEEK_SET);
513 	char *tree = (char *)malloc(l + 1);
514 	char *p = tree;
515 	while(l-- > 0) {
516 		char c = fgetc(in);
517 		if(c != '\n' && c != '\r') *(p++) = c;
518 		}
519 	*p = 0;
520 	fclose(in);
521 	w = treedraw(tree, view, extract_filename(masename), FALSE);
522 	if (view != NULL && view->tot_seqs == 0) { // closes an empty alignment window that opened the tree
523     view->dnawin->do_callback();
524 	}
525 }
526 else
527 		fl_alert("File %s\nis not of a format readable by seaview", masename);
528 return w;
529 }
530 
531 
532 #ifdef _AIX
533 /* sur IBM RISC __filbuf est en fait _filbuf utilise a l'interieur de xforms */
__filbuf(FILE * fich)534 int __filbuf(FILE *fich)
535 {
536 return _filbuf(fich);
537 }
538 #endif
539 
540 
541 class DNA_obj : public Fl_Widget {
542     FL_EXPORT void draw(void);
543     FL_EXPORT int handle(int);
544 public:
DNA_obj(int x,int y,int w,int h,void * view)545     FL_EXPORT DNA_obj(int x,int y,int w,int h, void *view) :
546 		Fl_Widget(x,y,w,h,NULL) {
547 	this->user_data(view);
548 	}
549 };
550 
551 
out_of_memory(void)552 void out_of_memory(void)
553 {
554 Fl_Window *w;
555 while((w = Fl::first_window()) != NULL) w->hide();
556 fl_alert("Seaview error: Not enough memory!");
557 exit(1);
558 }
559 
560 
minuscules(char * p)561 void minuscules(char *p)
562 {
563 if(p == NULL) return;
564 while(*p) {
565 	*p = tolower(*p);
566 	p++;
567 	}
568 return;
569 }
570 
571 
extract_filename(const char * fname)572 const char *extract_filename(const char *fname)
573 {
574 static const char *p, *q;
575 q = fname;
576 if(q == NULL) return (char *)"";
577 do	{
578 #ifdef __VMS
579 	p = strchr(q,']');
580 	if(p == NULL) p = strchr(q,':');
581 #elif defined(WIN32)
582 	p = strchr(q,'\\');
583 #else
584 	p = strchr(q,'/');
585 #endif
586 	if(p != NULL) q = p+1;
587 	}
588 while 	(p != NULL);
589 return q;
590 }
591 
592 
create_tmp_filename()593 char *create_tmp_filename()
594 // returns a temporary file name in private memory or NULL
595 // need to call delete_tmp_filename() after all temporary files usage
596 {
597 #if defined(WIN32)
598   static char *buff = NULL;
599   static int lbuff = 0;
600   wchar_t *wc = _wtempnam(NULL, L"seaview_tmp");
601   if (wc != NULL) {
602     FILE *in = _wfopen(wc, L"w");
603     if (in != NULL) fclose(in);
604     int l = wcslen(wc);
605     unsigned l2 = fl_utf8fromwc(NULL, 0, wc, l);
606     if (l2+1 > lbuff) {
607       lbuff = l2+1;
608       buff = (char*)realloc(buff, lbuff);
609       }
610     fl_utf8fromwc(buff, l2+1, wc, l);
611   }
612   return buff;
613 #else
614   char *retval;
615   int fd;
616   static char buffer[PATH_MAX];
617 #ifdef __APPLE__
618   mac_tmp_dir_name(buffer, PATH_MAX);
619 #else
620   strcpy(buffer, "/tmp/");
621 #endif
622 	strcat(buffer, "seaview.XXXXXX");
623 	if ((fd = mkstemp(buffer)) == -1) return NULL;
624 	close(fd);
625 	retval = buffer;
626   return retval;
627 #endif // WIN32
628 }
629 
630 
631 #ifndef WIN32
delete_tmp_filename(const char * base_fname)632 void delete_tmp_filename(const char *base_fname)
633 {
634   char fname[PATH_MAX];
635   sprintf(fname, "PATH=/bin:/usr/bin rm \"%s\"*", base_fname);
636   system(fname);
637 }
638 #endif
639 
640 
allonge_seqs(char ** seq,int totseqs,int maxlen,int * eachlength,int tot_comment_lines,char ** comment_line,char ** pregion_line)641 void allonge_seqs(char **seq, int totseqs, int maxlen, int *eachlength,
642 	int tot_comment_lines, char **comment_line, char **pregion_line)
643 {
644 int num, l;
645 char *newseq;
646 
647 for(num = 0; num < totseqs; num++) {
648 	l = eachlength[num];
649 	newseq = (char *)malloc(maxlen+1);
650 	if(newseq==NULL) out_of_memory();
651 	memcpy(newseq,seq[num],l+1);
652 	free(seq[num]);
653 	seq[num] = newseq;
654 	}
655 for(num = 0; num < tot_comment_lines; num++) {
656 	l = strlen(comment_line[num]);
657 	newseq = (char *)malloc(maxlen+1);
658 	if(newseq == NULL) out_of_memory();
659 	memcpy(newseq, comment_line[num], l+1);
660 	free(comment_line[num]);
661 	comment_line[num] = newseq;
662 	}
663   if (pregion_line) *pregion_line = (char*)realloc(*pregion_line, maxlen + 1);
664 }
665 
666 
667 /* memoire pour contenir coloriage standard */
668 static int color_for_aa_gaps;
669 static char std_aminoacids[30];
670 static int std_aa_color[30];
671 /* memoire pour contenir coloriage alternatif */
672 static char alt_aminoacids[30] = "";
673 static int alt_aa_color[30];
674 /* pointeurs vers coloriage courant */
675 static char *current_aminoacids;
676 static int *current_aa_color;
677 
678 
decode_color_scheme(char * vlist,char * aas,int * aa_color,int maxprotcolors)679 int decode_color_scheme(char *vlist,  char *aas, int *aa_color,
680 	int maxprotcolors)
681 {
682 int nbr_colors = 1, current = 0, i;
683 char *p, *list;
684 list = strdup(vlist);
685 if(list == NULL) return 1;
686 aas[0] = 0;
687 p=strtok(list,",");
688 while( p!= NULL && nbr_colors < maxprotcolors) {
689 	strcat(aas,p);
690 	for(i=0; i < (int) strlen(p); i++)
691 		aa_color[current++] = nbr_colors;
692 	nbr_colors++;
693 	p=strtok(NULL,",");
694 	}
695 free(list);
696 return nbr_colors;
697 }
698 
699 
prep_custom_colors(int * colors,char * customcolors,int max_colors)700 int prep_custom_colors(int *colors, char *customcolors, int max_colors)
701 {
702 char *nom;
703 int rank = 0, r, g, b;
704 Fl_Color col;
705 
706 if(*customcolors == 0) return max_colors;
707 nom = strtok(customcolors, ",");
708 while(nom != NULL && rank < max_colors - 1) {
709 	r = g = b = -1;
710 	sscanf(nom, "%d%d%d", &r, &g, &b);
711 	if( r>=0 && g>=0 && b>=0 )
712 		col = fl_rgb_color(r, g, b);
713 	else col = FL_BLACK;
714 	colors[++rank] = (int)col;
715 	nom = strtok(NULL, ",");
716 	}
717 return rank + 1;
718 }
719 
720 
prep_aa_color_code(char * list_std,char * list_alt,int maxprotcolors,int * numb_stdprotcolors,int * numb_altprotcolors)721 color_choice prep_aa_color_code(char *list_std, char *list_alt,
722 	int maxprotcolors, int *numb_stdprotcolors, int *numb_altprotcolors)
723 {
724 /* couleur pour gaps = 1ere couleur connue (comptee a partir de 0) */
725 color_for_aa_gaps = 0;
726 current_aminoacids = std_aminoacids;
727 current_aa_color = std_aa_color;
728 /* decodage du coloriage standard des proteines */
729 *numb_stdprotcolors =
730 	decode_color_scheme(list_std, std_aminoacids, std_aa_color,
731 		maxprotcolors);
732 *numb_altprotcolors = 0;
733 if(*list_alt == 0) return NO_ALT_COLORS;
734 /* decodage du coloriage alternatif des proteines */
735 *numb_altprotcolors =
736 	decode_color_scheme(list_alt, alt_aminoacids, alt_aa_color,
737 		maxprotcolors);
738 return USING_STANDARD_COLORS;
739 }
740 
741 
set_aa_color_mode(color_choice choice)742 void set_aa_color_mode(color_choice choice)
743 {
744 if(choice == USING_ALT_COLORS) {
745 	current_aminoacids = alt_aminoacids;
746 	current_aa_color = alt_aa_color;
747 	}
748 else	{
749 	current_aminoacids = std_aminoacids;
750 	current_aa_color = std_aa_color;
751 	}
752 }
753 
754 
get_color_for_aa(int key)755 int get_color_for_aa( int key )
756 /* returns the color # used to display character key in protein */
757 {
758 char *pos;
759 pos = strchr(current_aminoacids, toupper(key) );
760 return ( pos == NULL ?
761 	color_for_aa_gaps : current_aa_color[pos - current_aminoacids] );
762 }
763 
764 
get_color_for_base(int key)765 int get_color_for_base( int key )
766 /* returns the color # used to display character key in DNA */
767 {
768 	int retval;
769 	if(key=='A' || key == 'a') retval = 1;
770 	else if(key=='C' || key == 'c') retval = 2;
771 	else if(key=='G' || key == 'g') retval = 3;
772 	else if(key=='T' || key == 't' || key=='U' || key == 'u') retval = 4;
773 	else retval = 0;
774 	return retval;
775 }
776 
777 
prepcolranks(char ** seq,int totseqs,int maxlen,int * eachlength,int (* calc_color_function)(int),int numb_gc,int allow_lower)778 char **prepcolranks(char **seq, int totseqs, int maxlen, int *eachlength,
779 					int (*calc_color_function)( int ), int numb_gc, int allow_lower)
780 {
781 	int num, l, i;
782 	char **colrank;
783 	if(totseqs == 0 || numb_gc == 1) return NULL;
784 	colrank=(char **)malloc(totseqs*sizeof(char *));
785 	if(colrank == NULL) return NULL;
786 	for(num=0; num<totseqs; num++) {
787 		l = eachlength[num];
788 		colrank[num]=(char *)malloc(maxlen + 1);
789 		if(colrank[num] == NULL) return NULL;
790 		for(i=0; i<l; i++) {
791 			colrank[num][i] = (char)calc_color_function( seq[num][i] );
792 		}
793 	}
794 	return colrank;
795 }
796 
prepcolranks_by_codon(char ** seq,int totseqs,int maxlen,int * eachlength,char ** comments)797 char **prepcolranks_by_codon(char **seq, int totseqs, int maxlen, int *eachlength, char **comments)
798 {
799 	int num, l, i, c, gc;
800 	char **colrank, *p, aa;
801 	if(totseqs == 0) return NULL;
802 	colrank = (char **)malloc(totseqs*sizeof(char *));
803 	if(colrank == NULL) return NULL;
804 	for(num=0; num<totseqs; num++) { /* allocation memoire */
805 		l = eachlength[num];
806 		colrank[num]=(char *)malloc(maxlen + 1);
807 		if(colrank[num] == NULL) return NULL;
808 		gc = get_acnuc_gc_number(get_ncbi_gc_from_comment(comments[num]));
809 		for(i = 0; i < l; i += 3) {
810 			if(i+2 < l) aa = codaa(seq[num] + i, gc);
811 			else aa = 'X';
812 			p = strchr(aminoacids, aa);
813 			c = (p != NULL ? p - aminoacids : 21);
814 			if(c == 21) c = 0;
815 			else c++;
816 			colrank[num][i] = c;
817 			if(i + 1 < l) colrank[num][i + 1] = c;
818 			if(i + 2 < l) colrank[num][i + 2] = c;
819 			}
820 	}
821 	return colrank;
822 }
823 
824 
prepcolranks_by_difference(char ** seq,int totseqs,int ref_seq0,int maxlen,int * eachlength,int (* calc_color_function)(int),int numb_gc,int allow_lower)825 char **prepcolranks_by_difference(char **seq, int totseqs, int ref_seq0,
826 	int maxlen, int *eachlength,
827 	int (*calc_color_function)( int ), int numb_gc, int allow_lower)
828 {
829 int num, l, i, res;
830 char **colrank;
831 if(totseqs == 0) return NULL;
832 colrank = (char **)malloc(totseqs*sizeof(char *));
833 if(colrank == NULL) return NULL;
834 for(num=0; num<totseqs; num++) { /* allocation memoire */
835 	l = eachlength[num];
836 	colrank[num]=(char *)malloc(maxlen + 1);
837 	if(colrank[num] == NULL) return NULL;
838 	}
839 for(i=0; i<eachlength[ref_seq0]; i++) { /* coloration seq de reference */
840 	res = seq[ref_seq0][i];
841 	colrank[ref_seq0][i] = (char)calc_color_function( res );
842 	}
843 for(num=0; num<totseqs; num++) { /* coloration des autres sequences */
844 	if(num == ref_seq0) continue;
845 	l = eachlength[num];
846 	for(i=0; i<l; i++) {
847 		res = seq[num][i];
848 		if(toupper(res) != toupper(seq[ref_seq0][i])) {
849 			colrank[num][i] = (char)calc_color_function( res );
850 			}
851 		else	{
852 			colrank[num][i] = 0;
853 			}
854 		}
855 	}
856 return colrank;
857 }
858 
859 
draw_cursor(Fl_Widget * ob,int on_off,int site,int seq,int cursor_in_comment)860 void draw_cursor(Fl_Widget *ob, int on_off, int site, int seq,
861 	int cursor_in_comment)
862 {
863 SEA_VIEW *view = (SEA_VIEW *)ob->user_data() ;
864 int  x, y, cursor_x, cursor_y, c, max_curs_coord;
865 char *debut, *fin;
866 int background, foreground;
867 static char lettre[]="A";
868 static char cursor_coord[200];
869 Fl_Menu_Item *menu_props = (Fl_Menu_Item *)view->menu_props;
870 props_menu_parts *props_parts = (props_menu_parts *)menu_props->user_data();
871 int byreference = (menu_props + props_parts->reference)->value();
872 
873 if( (!cursor_in_comment) && (seq == 0 || site > view->each_length[seq-1] + 1) )
874 	return;
875 cursor_x = site - view->first_site;
876 if(cursor_in_comment) {
877 	if(view->tot_comment_lines == 0 || !view->show_comment_lines) return;
878 	if(cursor_x < 0 || cursor_x >= view->tot_sites ) return;
879 	if(seq <= 0 || seq > view->tot_comment_lines ) return;
880 	y = view->y_seq + (seq + view->pos_first_comment_line - 2) *
881 		view->line_height;
882 	x = view->x_seq + cursor_x * view->char_width;
883 	lettre[0] = view->comment_line[seq-1][site-1];
884 	}
885 else	{
886 	if(view->tot_seqs == 0) return;
887 	if (view->old_cursor_seq != seq) {
888 	  view->draw_names = view->old_cursor_seq; // ecrire en noir nom ancien curseur
889 	  draw_seq_names(view->DNA_obj, view);
890 	  }
891 	view->draw_names = seq; // ecrire en jaune nom nouveau curseur
892 	draw_seq_names(view->DNA_obj, view);
893 	view->draw_names = -1;
894 	cursor_y = seq - view->first_seq;
895 	if(cursor_x < 0 || cursor_x >= view->tot_sites || cursor_y < 0 || cursor_y >= view->tot_lines ) {
896 	  return;
897 	  }
898 	y = view->y_seq + cursor_y * view->line_height;
899 	x = view->x_seq + cursor_x * view->char_width;
900 	lettre[0] = view->sequence[seq-1][site-1];
901 	if(!view->allow_lower) lettre[0] = toupper(lettre[0]);
902 	if(byreference && (!on_off) && seq >= 2) {
903 		if(toupper(lettre[0]) == toupper(view->sequence[0][site-1])) lettre[0] = '.';
904 		}
905 	}
906 if(view->numb_gc == 1) { /* cas noir et blanc */
907 	if(on_off) {
908 		foreground = FL_WHITE;
909 		background = FL_BLACK;
910 		}
911 	else	{
912 		foreground = FL_BLACK;
913 		background = FL_WHITE;
914 		}
915 	}
916 else if( (!cursor_in_comment) && view->inverted_colors) {
917 	/* cas inverted colors */
918 	if(site <= view->each_length[seq - 1]) {
919 		if( (c = (int)view->col_rank[seq-1][site-1]) == 0) background = ob->color();
920 		else background = view->curr_colors[c];
921 		}
922 	else
923 		background = ob->color();
924 	if(on_off) {
925 		foreground = background;
926 		background = FL_BLACK;
927 		}
928 	else	{
929 		if(view->active_region == NULL ||
930 				view->region_line[site - 1] == 'X')
931 			foreground = FL_BLACK;
932 		else
933 			foreground = ob->selection_color();
934 		}
935 	}
936 else if(cursor_in_comment) { /* dans les lignes comment sur ecran couleur */
937 	if(on_off) {
938 		foreground = FL_WHITE; background = FL_BLACK;
939 		}
940 	else	{
941 		foreground = FL_BLACK; background = ob->color();
942 		}
943 	}
944 else	{ /* cas colored letters */
945 	if( site <= view->each_length[seq - 1]) {
946 		foreground = view->curr_colors[(unsigned)view->col_rank[seq-1][site-1]];
947 		}
948 	else	{
949 		lettre[0] = ' ';
950 		foreground = FL_BLACK;
951 		}
952 	if(on_off) {
953 		background = FL_BLACK;
954 		}
955 	else	{
956 		if( (!cursor_in_comment) && view->active_region != NULL &&
957 				view->region_line[site - 1] == 'X')
958 			background = ob->selection_color();
959 		else
960 			background = ob->color();
961 		}
962 	}
963 fl_font(ob->labelfont(), ob->labelsize());
964 fl_color(background);
965 fl_rectf( x, y - view->line_height + fl_descent(),
966 	view->char_width +1,
967 	view->line_height);
968 fl_color(foreground);
969 fl_draw(lettre, 1, x, y);
970 if(on_off) {
971 /* ecriture des coordonnees du curseur */
972 	max_curs_coord = view->tot_sites - 14;
973 	x = view->x_seq + 7 * view->char_width;
974 	y = view->y_seq - view->line_height;
975 	fl_font(FL_COURIER, ob->labelsize());
976 	fl_color(ob->color());
977 	fl_rectf( x, y - view->line_height,
978 		(max_curs_coord ) * view->char_width,
979 		view->line_height + fl_descent());
980 	if(!cursor_in_comment) {
981 		debut = view->sequence[seq-1] - 1; fin = debut + site; c = 0;
982 		if(*fin == 0) fin--;
983 		while(++debut <= fin) if( *debut != '-' ) c++;
984 		sprintf(cursor_coord, "Seq:%d", seq);
985 		if(view->curr_colors == view->codoncolors) {//codon mode: write amino acid name
986 			int aanum;
987 			static char aa3[] = "ArgLeuSerThrProAlaGlyValLysAsnGlnHisGluAspTyrCysPheIleMetTrpTER???   ";
988 			char *codonstart = view->sequence[seq - 1] + ((site - 1)/3) * 3;
989 			if(codonstart+2 - view->sequence[seq - 1] < view->each_length[seq-1] && memchr(codonstart, '-', 3) == NULL) {//gap-less codon
990 				char aa = codaa(codonstart,
991 							get_acnuc_gc_number(get_ncbi_gc_from_comment(view->comments[seq - 1])));
992 				aanum = strchr(aminoacids, aa) - aminoacids;
993 				}
994 			else aanum = 22;//write spaces for gap-with codon
995 			sprintf(cursor_coord + strlen(cursor_coord), " %.3s", aa3 + 3 * aanum);
996 			}
997 		sprintf(cursor_coord + strlen(cursor_coord), " Pos:%d|%d [%.150s]", site, c, view->seqname[seq - 1]);
998 		}
999 	else
1000 		sprintf(cursor_coord, "Pos:%d", site);
1001 	fl_color(view->namecolor);
1002 	if (max_curs_coord >= 0 && (unsigned)max_curs_coord < sizeof(cursor_coord)) cursor_coord[max_curs_coord] = 0;
1003 	fl_draw(cursor_coord, x, y);
1004 	}
1005 }
1006 
1007 
draw_seq_names(Fl_Widget * ob,SEA_VIEW * view)1008 void draw_seq_names(Fl_Widget *ob, SEA_VIEW *view)
1009 {
1010 int x, y, num, debut, fin;
1011 int couleur;
1012 static char trunc_name[20];
1013 
1014 x = view->x_name; y = view->y_name;
1015 fl_font(FL_COURIER, ob->labelsize() );
1016 fl_push_clip(ob->x(), ob->y(), view->x_seq - ob->x(), ob->h() - 4);
1017 debut = view->first_seq - 1;
1018 fin = view->first_seq - 2 + view->tot_lines;
1019 if(fin >= view->tot_seqs) fin = view->tot_seqs - 1;
1020 if(view->draw_names == -1) { /* ecrire tous les noms */
1021 	fl_color(ob->color());
1022 	fl_rectf( ob->x(), ob->y(),  /* fond pour les noms */
1023 		view->x_seq - ob->x(),
1024 		ob->h() - 4 /* 2 * BORDER_WIDTH */);
1025 /* write region name */
1026 	if(view->active_region != NULL) {
1027 		fl_color(view->region_color);
1028 		fl_font(ob->labelfont(), ob->labelsize());
1029 		fl_draw(view->active_region->name,
1030 		   FL_min((unsigned)view->wid_names, strlen(view->active_region->name)),
1031 			view->x_name,
1032 			view->y_name + FL_min(view->tot_lines, view->tot_seqs) *
1033 			view->line_height );
1034 		fl_font(FL_COURIER, ob->labelsize() );
1035 		}
1036 	}
1037 else if(view->draw_names == -2) { /* ecrire tous les noms mais rien qu'eux */
1038 	fl_color(ob->color());
1039 	fl_rectf( ob->x(),   /* fond pour les noms */
1040 		y - view->line_height + fl_descent(),
1041 		view->x_seq - ob->x(),
1042 		(fin - debut + 1) * view->line_height);
1043 	}
1044 else	{ /* ecrire un seul nom */
1045 	debut = fin = view->draw_names - 1;
1046   if (debut < view->first_seq - 1) {
1047     fl_pop_clip();
1048     return;
1049   }
1050 	y += view->line_height * (view->draw_names - view->first_seq);
1051 	if( !view->sel_seqs[view->draw_names - 1] ) {
1052 		fl_color(ob->color());
1053 		fl_rectf( x, y - view->line_height + fl_descent(),
1054 			(view->wid_names+1) * view->char_width,
1055 			view->line_height);
1056 		}
1057 	}
1058 if(view->tot_seqs > 0) { /* nbre de seqs selectionnees */
1059 	fl_color(ob->color());
1060 	fl_rectf( x, view->y_name - 2 * view->line_height,
1061 		(view->wid_names+1) * view->char_width, view->line_height);
1062 	sprintf(trunc_name, "sel=%d", view->tot_sel_seqs);
1063 	fl_color(view->namecolor);
1064 	fl_draw(trunc_name, x, view->y_name - view->line_height );
1065 	}
1066 /* le(s) nom(s) a ecrire */
1067 for(num = debut; num <= fin; num++) {
1068 	if(view->sel_seqs[num]) {
1069 		fl_color(FL_BLACK);
1070 		fl_rectf( x, y - view->line_height + fl_descent(),
1071 			(view->wid_names+1) * view->char_width,
1072 			view->line_height);
1073 		couleur = FL_WHITE;
1074 		}
1075 	else
1076 		couleur = view->namecolor;
1077 	if (num == view->cursor_seq - 1) { // set name of cursor-containing seq in bold
1078 	  if (view->sel_seqs[num]) couleur = FL_DARK2;
1079 	  fl_font(fl_font()|FL_BOLD, fl_size());
1080 	  }
1081 	fl_color(couleur);
1082     int lbytes = strlen(view->seqname[num]); // length in bytes
1083     int lc = fl_utf_nb_char((uchar*)view->seqname[num], lbytes); // length in UTF characters
1084     int draw_bytes; // # of bytes of the name string to draw
1085     if (lc == lbytes) draw_bytes = FL_min(view->wid_names, lbytes);
1086     else if (lc <= view->wid_names) draw_bytes = lbytes;
1087     else { // name contains non ASCII: count characters not bytes
1088         lc = 0;
1089         char *p = view->seqname[num], *last = view->seqname[num] + lbytes;
1090         while (p < last && lc < view->wid_names) {
1091             int len;
1092             fl_utf8decode(p, last, &len);
1093             lc++;
1094             p += len;
1095         }
1096         draw_bytes = p - view->seqname[num];
1097     }
1098 	fl_draw(view->seqname[num], draw_bytes, x, y );
1099 	if (num == view->cursor_seq - 1) {
1100 	  fl_font(fl_font()&~FL_BOLD, fl_size());
1101 	  }
1102 	y += view->line_height;
1103 	}
1104     fl_pop_clip();
1105 }
1106 
1107 
draw_header(Fl_Widget * ob,SEA_VIEW * view)1108 void draw_header(Fl_Widget *ob, SEA_VIEW *view)
1109 {
1110 static char site_line[10];
1111 
1112 if(view->mod_seq) return;
1113 if(view->tot_seqs == 0) return;
1114 if(view->active_region != NULL) draw_region_line(ob, view);
1115 /* write site numbers */
1116 if (view->tot_sites < 7) return;
1117 fl_color(ob->color());
1118 fl_rectf( view->x_seq,
1119 	view->y_seq - 2 * view->line_height + fl_descent(),
1120 	view->tot_sites * view->char_width, view->line_height);
1121 fl_color(view->namecolor); fl_font(FL_COURIER, ob->labelsize() );
1122   sprintf(site_line, "%d", view->first_site);
1123   fl_draw(site_line, view->x_seq, view->y_seq - view->line_height);
1124   sprintf(site_line, "%7d", view->first_site + view->tot_sites - 1);
1125   fl_draw(site_line, view->x_seq + (view->tot_sites - 7)*view->char_width, view->y_seq - view->line_height);
1126 }
1127 
1128 
draw_dna_seqs(Fl_Widget * ob,SEA_VIEW * view)1129 void draw_dna_seqs(Fl_Widget *ob, SEA_VIEW *view)
1130 {
1131 int nline, offset, x, y, i, l_line, y_back, need_back, isreference;
1132 char *pos;
1133 int debut, fin, use_region;
1134 list_segments *segment, *first_segment;
1135   Fl_Menu_Item *menu_props = (Fl_Menu_Item *)view->menu_props;
1136 props_menu_parts *props_parts = (props_menu_parts *)menu_props->user_data();
1137 int byreference = (menu_props + props_parts->reference)->value();
1138 static int first = TRUE;
1139 static char **clines;//holds color-specific lines
1140 if(first) {
1141 	first = FALSE;
1142 	clines = new char*[22];
1143 	for(i=0; i < 22; i++) clines[i] = new char[1000];
1144 	}
1145 
1146 if(view->mod_seq == 0) { /* draw all lines */
1147 	debut = view->first_seq - 1;
1148 	fin = FL_min(view->first_seq + view->tot_lines - 1, view->tot_seqs) - 1;
1149 	}
1150 else if(view->mod_seq == -1) { /* draw only selected lines */
1151 	debut = view->first_seq - 1;
1152 	fin = FL_min(view->first_seq + view->tot_lines - 1, view->tot_seqs) - 1;
1153 	while(fin >= debut && !view->sel_seqs[fin]) fin--;
1154 	if(debut > fin) return;
1155 	while(!view->sel_seqs[debut]) debut++;
1156 	}
1157 else	{ /* draw just line # view->mod_seq */
1158 	debut = fin = view->mod_seq - 1;
1159 	if(debut < view->first_seq - 1) fin = debut - 1;
1160 	}
1161 // prepare for drawing region background
1162 use_region = (view->active_region != NULL && view->numb_gc > 1 &&
1163 		(first_segment = view->active_region->list) != NULL);
1164 if(use_region) {
1165 	do	{
1166 		if(first_segment->debut >
1167 			view->first_site + view->tot_sites - 1) {
1168 				use_region = FALSE;
1169 				break;
1170 			}
1171 		if(first_segment->fin >= view->first_site) break;
1172 		first_segment = first_segment->next;
1173 		}
1174 	while(first_segment != NULL);
1175 	if(first_segment == NULL) use_region = FALSE;
1176 	}
1177 need_back = TRUE;
1178 if(use_region) {
1179 	if(first_segment->debut <= view->first_site &&
1180 		first_segment->fin >= view->first_site + view->tot_sites - 1)
1181 		need_back = FALSE;
1182 	}
1183 
1184 /* write sequences */
1185 fl_font( ob->labelfont(), ob->labelsize() );
1186 x = view->x_seq;
1187 y = view->y_seq + (debut - (view->first_seq - 1)) * view->line_height;
1188 y_back = y - view->line_height + fl_descent();
1189 offset = view->first_site - 1;
1190 for(nline = debut; nline <= fin; nline++) {
1191 	isreference = (byreference && (nline > 0));
1192 	if( view->mod_seq != -1 || view->sel_seqs[nline] ) {
1193 		if(need_back) { /* write seq background */
1194 			fl_color(ob->color());
1195 			fl_rectf( x, y_back,
1196 				view->tot_sites * view->char_width,
1197 				view->line_height);
1198 			}
1199 		if(use_region) { /* write regions background */
1200 			int deb_block, fin_block;
1201 			fl_color(ob->selection_color());
1202 			segment = first_segment;
1203 			do	{
1204 				deb_block = FL_max(
1205 					segment->debut, view->first_site);
1206 				fin_block = FL_min(segment->fin,
1207 					view->first_site + view->tot_sites - 1);
1208 				fl_rectf(x+(deb_block - view->first_site)*
1209 						view->char_width,
1210 					y_back,
1211 					(fin_block - deb_block + 1) *
1212 						view->char_width,
1213 					view->line_height);
1214 				segment = segment->next;
1215 				}
1216 			while(segment != NULL && segment->debut <=
1217 				view->first_site + view->tot_sites - 1);
1218 			}
1219 		if(view->each_length[nline] > offset) {
1220 			l_line = FL_min( view->tot_sites, view->each_length[nline] - offset );
1221 			// write DNA seqs
1222 			if(view->numb_gc > 1) {
1223 				char residue;
1224 				pos = view->sequence[nline] + offset;
1225 				char *pos0 = view->sequence[0] + offset;
1226 				for(i=0; i < view->numb_gc; i++) {
1227 					memset(clines[i], ' ', l_line);
1228 					clines[i][l_line] = 0;
1229 					}
1230 				for( i = 0; i < l_line; i++) {//fill color-specific lines
1231 					if(isreference && toupper(*pos) == toupper(*pos0)) residue = '.';
1232 					else residue = *pos;
1233 					if(!view->allow_lower) residue = toupper(residue);
1234 					clines[ (unsigned)view->col_rank[nline][offset + i] ][i] = residue;
1235 					pos++; pos0++;
1236 					}
1237 				for(i=0; i < view->numb_gc; i++) {//draw color-specific lines
1238 					fl_color(view->curr_colors[i]);
1239 					fl_draw(clines[i], l_line, x, y);
1240 					}
1241 				}
1242 			else {
1243 				pos = view->sequence[nline];
1244 				fl_color(view->curr_colors[0]);
1245 				fl_draw(pos + offset, l_line, x, y );
1246 				}
1247 			}
1248 		}
1249 	y += view->line_height;
1250 	y_back += view->line_height;
1251 	}
1252 draw_header(ob, view);
1253 }
1254 
1255 
draw_dna_seqs_inverted(Fl_Widget * ob,SEA_VIEW * view)1256 void draw_dna_seqs_inverted(Fl_Widget *ob, SEA_VIEW *view)
1257 {
1258 int nline, c, offset, x, y, l_line, yy, firstline, lastline, use_region,
1259 	debut, fin, der_site;
1260   float xx;
1261 int pos;
1262 list_segments *segment, *first_segment;
1263 int save_col0;
1264 static char up_line[1000]; char *p, *q, *r; int i;
1265   Fl_Menu_Item *menu_props = (Fl_Menu_Item *)view->menu_props;
1266 props_menu_parts *props_parts = (props_menu_parts *)menu_props->user_data();
1267 int byreference = (menu_props + props_parts->reference)->value();
1268 
1269 if(view->tot_seqs == 0) {
1270 	return;
1271 	}
1272 fl_font(ob->labelfont(), ob->labelsize() );
1273 save_col0 = view->curr_colors[0];
1274 view->curr_colors[0] = ob->color();
1275 /* write sequences */
1276 x = view->x_seq;
1277 offset= view->first_site - 1;
1278 if(view->mod_seq <= 0) {
1279 	firstline = view->first_seq-1;
1280 	lastline = FL_min(view->first_seq + view->tot_lines -1, view->tot_seqs);
1281 	}
1282 else	{
1283 	firstline = view->mod_seq - 1;
1284 	lastline = firstline + 1;
1285 	if(firstline < view->first_seq - 1) lastline = firstline - 1;
1286 	}
1287 	use_region = (view->active_region != NULL &&
1288 		(first_segment = view->active_region->list) != NULL);
1289 if(use_region) {
1290 	do	{
1291 		if(first_segment->fin >= view->first_site) break;
1292 		first_segment = first_segment->next;
1293 		}
1294 	while(first_segment != NULL);
1295 	}
1296 y = view->y_seq + (firstline - view->first_seq + 1) * view->line_height;
1297 yy = y - view->line_height + fl_descent();
1298 //ecriture du fond gris
1299 fl_color(ob->color());
1300 fl_rectf( x, yy, view->tot_sites * view->char_width, (lastline - firstline) * view->line_height);
1301 //
1302 for(nline=firstline; nline < lastline; /* ecriture des fonds de couleur */
1303 		nline++, y += view->line_height, yy += view->line_height ) {
1304 	l_line = ( offset + view->tot_sites < view->each_length[nline] ?
1305 		view->tot_sites : view->each_length[nline] - offset);
1306 	l_line = FL_max(l_line, 0); /* nbre de caract a ecrire */
1307 	if(l_line > 0) {
1308 			xx = x;
1309 			for(pos = offset; pos < offset + l_line; pos++) {
1310 				if( (c = (int)view->col_rank[nline][pos]) != 0 ) {
1311 					fl_color(view->curr_colors[c]);
1312 					fl_rectf( xx, yy,
1313 						view->char_width+1,
1314 						view->line_height);
1315 						}
1316 				xx += view->char_width;
1317 				}
1318 
1319 		}
1320 	if(l_line < view->tot_sites) { /* au dela de la fin de la seq */
1321 		fl_color(ob->color());
1322 	 	fl_rectf( x + l_line * view->char_width, yy,
1323 			view->char_width * (view->tot_sites - l_line),
1324 			view->line_height);
1325 		}
1326 	if(l_line == 0) continue;
1327 
1328 /*ecriture des seqs: regions en noir et autres en col2 */
1329 	fl_color( use_region ? ob->selection_color() : FL_BLACK );
1330 	p = view->sequence[nline] + offset;
1331 	memcpy(up_line, p, l_line); up_line[l_line] = 0;
1332 	p = up_line;
1333 	if(!view->allow_lower) majuscules(up_line);
1334 	if(byreference && nline != 0) {
1335 		q = p + l_line; i = 0;
1336 		r= view->sequence[0] + offset;
1337 		while( p < q) {
1338 			up_line[i++] = (toupper(*p) == toupper(*r) ? '.' : *p);
1339 			p++; r++;
1340 			}
1341 		p = up_line;
1342 		}
1343 	fl_draw(p, l_line, x, y);
1344 	if(use_region) { /* re-ecrire les regions en noir */
1345 		der_site = view->first_site + l_line - 1;
1346 		segment = first_segment;
1347 		fl_color( FL_BLACK );
1348 		while( segment  != NULL ) {
1349 			if(segment->debut > der_site) break;
1350 			debut = FL_max(segment->debut, view->first_site);
1351 			fin = FL_min(segment->fin, der_site);
1352 			p = up_line + debut - offset - 1;
1353 			fl_draw(p,
1354 				fin - debut + 1,
1355 				x + (debut - offset - 1)*view->char_width, y);
1356 			segment = segment->next;
1357 			}
1358 		}
1359 	}
1360 view->curr_colors[0] = save_col0;
1361 draw_header(ob, view);
1362 }
1363 
1364 
set_tot_lines(SEA_VIEW * view,int new_val)1365 void set_tot_lines(SEA_VIEW *view, int new_val)
1366 {
1367 int l;
1368 double x;
1369 view->tot_lines = new_val;
1370 l = view->tot_seqs - view->tot_lines + 1;
1371 if(l<1) l=1;
1372 if(view->first_seq > l) {
1373 	view->first_seq = l;
1374 	}
1375 if(view->tot_seqs > 0) {
1376 	x = view->tot_lines / ( (double) view->tot_seqs );
1377 	if(x>1) x=1;
1378 	}
1379 else	x = 1;
1380 view->vertsli->slider_size(x);
1381 view->vertsli->bounds(1, l);
1382 view->vertsli->Fl_Slider::value(view->first_seq);
1383 }
1384 
1385 
compute_size_params(SEA_VIEW * view,int force_recompute)1386 int compute_size_params(SEA_VIEW *view, int force_recompute)
1387 {
1388 static int old_w = 0;
1389 static int old_h = 0;
1390 static Fl_Widget *old_dna_obj = NULL;
1391 Fl_Widget *ob = view->DNA_obj;
1392 double x;
1393 int l, tot_lines, possible_lines;
1394 
1395 if( !force_recompute && old_dna_obj == ob && ob->w() == old_w && ob->h() == old_h) return FALSE;
1396 old_w = ob->w(); old_h = ob->h(); old_dna_obj = ob;
1397 view->x_name = view->char_width/2 + ob->x();
1398 view->y_name =  2 * view->line_height + ob->y();
1399 view->x_seq = (view->wid_names +2) * view->char_width + ob->x();
1400 view->y_seq = view->y_name;
1401 view->tot_sites = ( ob->w() - view->x_seq - ob->x() ) / view->char_width;
1402 possible_lines = ( ob->h() - 4 ) / view->line_height  - 1;
1403 tot_lines = possible_lines;
1404 if(view->active_region != NULL) tot_lines--;
1405 if(view->show_comment_lines) {
1406 	tot_lines -= view->tot_comment_lines;
1407 	view->pos_first_comment_line =
1408 		FL_min(tot_lines, view->tot_seqs) + 1;
1409 	if(view->active_region != NULL) ++(view->pos_first_comment_line);
1410 	}
1411 /* init sliders bounds and size */
1412 if(view->tot_seqs > 0) {
1413 	x = ( (double) view->tot_sites ) / ( view->seq_length + 3 );
1414 	if(x>1) x=1;
1415 	}
1416 else	x = 1;
1417 view->horsli->slider_size(x);
1418 l = view->seq_length - view->tot_sites+3;
1419 if(l<1) l=1;
1420 view->horsli->bounds(1,l);
1421 if(view->first_site > l) {
1422 	view->first_site = l;
1423 	}
1424 view->horsli->Fl_Slider::value(view->first_site);
1425 set_tot_lines(view, tot_lines);
1426 if(view->tot_seqs +
1427 	(view->show_comment_lines ? view->tot_comment_lines : 0) +
1428 	(view->active_region != NULL ? 1 : 0) < possible_lines) {
1429 /* forcer effacement de tout l'alignement pour ne pas garder
1430 de mauvaises lignes regions ou footers en bas */
1431 	ob->parent()->redraw();
1432 	}
1433 return TRUE;
1434 }
1435 
compute_wid_names(SEA_VIEW * view,int totseqs)1436 int compute_wid_names(SEA_VIEW *view, int totseqs)
1437 {
1438   int i, l, maxnamewidth, wid_names = 0;
1439   for(i=0; i<totseqs; i++) {
1440     l=strlen(view->seqname[i]);
1441     while(l > 0 && view->seqname[i][l-1] == ' ') l--;
1442     view->seqname[i][l] = 0;
1443     if(l > wid_names) wid_names = l;
1444   }
1445   if(totseqs > 0 && wid_names < 10) wid_names = 10;
1446   maxnamewidth = int_res_value("maxnamewidth", 20);
1447   if(wid_names > maxnamewidth) wid_names = maxnamewidth;
1448   return wid_names;
1449 }
1450 
calc_max_seq_length(int seq_length,int tot_seqs)1451 int calc_max_seq_length(int seq_length, int tot_seqs)
1452 {
1453   int max_seq_length = (int)(1.3 * seq_length);
1454   if(tot_seqs <= 5000) {
1455     max_seq_length = FL_max(max_seq_length, seq_length + MAX_SEQ_ALLONG);
1456   }
1457   else {
1458     max_seq_length = FL_max(max_seq_length, seq_length + 500);
1459   }
1460   return max_seq_length;
1461 }
1462 
init_dna_scroller(SEA_VIEW * view,int totseqs,const char * masename,int protein,char * header)1463 void init_dna_scroller(SEA_VIEW *view, int totseqs, const char *masename,
1464 	int protein, char *header)
1465 {
1466 int i, l;
1467 list_regions *mylregion;
1468   Fl_Menu_Item *menu_props = (Fl_Menu_Item *)view->menu_props;
1469 props_menu_parts *props_parts = (props_menu_parts *)menu_props->user_data();
1470 Fl_Menu_Item *item;
1471 
1472 view->header = header;
1473 view->tot_seqs = totseqs;
1474 view->seq_length = 0;
1475 view->protein = protein;
1476 view->allow_seq_edit = FALSE;
1477 view->viewasprots = NULL;
1478 item = menu_props + props_parts->viewasprots;
1479 item->clear();
1480 if(protein) item->deactivate(); else item->activate();
1481 item = menu_props + props_parts->edit;
1482 item->activate(); item->clear();
1483 item = menu_props + props_parts->keys;
1484 item->clear(); (item + 1)->clear(); (item + 2)->clear();
1485 item = menu_props + props_parts->keys - 1;
1486 if(protein) item->deactivate();
1487 else item->activate();
1488 item = menu_props + props_parts->reference;
1489 item->clear();
1490 item->deactivate();
1491 view->hjkl = FALSE;
1492 set_seaview_modified(view, FALSE);
1493 if(masename != NULL) {
1494 	view->masename = (char *)malloc(strlen(masename)+1);
1495 	if(view->masename == NULL) out_of_memory();
1496 	strcpy(view->masename, masename);
1497 	view->dnawin->label(extract_filename(view->masename));
1498 #if defined(__APPLE__) && 100*FL_MAJOR_VERSION + FL_MINOR_VERSION < 104
1499 	rename_windowmenuitem(view->dnawin->label(), find_windowmenuitem(view->dnawin));
1500 #endif
1501 	}
1502 else	view->masename = NULL;
1503 if(totseqs > 0) {
1504 	view->each_length = (int *)malloc(totseqs * sizeof(int));
1505 	if(view->each_length == NULL) out_of_memory();
1506 	}
1507 for(i = 0; i < totseqs; i++) {
1508 	l = strlen(view->sequence[i]);
1509 	view->each_length[i] = l;
1510 	if(l > view->seq_length) view->seq_length = l;
1511 	}
1512 for(i = 0; i < view->tot_comment_lines; i++) {
1513 	l = strlen(view->comment_line[i]);
1514 	if(l > view->seq_length) view->seq_length = l;
1515 	}
1516   view->max_seq_length = calc_max_seq_length(view->seq_length, view->tot_seqs);
1517 view->wid_names = compute_wid_names(view, totseqs);
1518 allonge_seqs(view->sequence, totseqs, view->max_seq_length,
1519 	view->each_length, view->tot_comment_lines, view->comment_line, NULL);
1520 if(view->numb_dnacolors > 1 && view->menu_props != NULL) {
1521 	/* DNA/prot modes useful only with colors */
1522 	item = menu_props + props_parts->colors;
1523 	if(view->alt_colors != NO_ALT_COLORS) (item+2)->activate();
1524 	if(protein) {
1525 		if(view->alt_colors == USING_ALT_COLORS) {
1526 			(item+2)->setonly();
1527 			set_aa_color_mode(USING_ALT_COLORS);
1528 			view->numb_gc = view->numb_altprotcolors;
1529 			view->curr_colors = view->altprotcolors;
1530 			}
1531 		else	{
1532 			(item+1)->setonly();
1533 			set_aa_color_mode(USING_STANDARD_COLORS);
1534 			view->numb_gc = view->numb_stdprotcolors;
1535 			view->curr_colors = view->stdprotcolors;
1536 			}
1537 		}
1538 	else	{
1539 		item->setonly();
1540 		view->numb_gc = view->numb_dnacolors;
1541 		view->curr_colors = view->dnacolors;
1542 		}
1543 	}
1544 if(view->numb_gc > 1) {
1545 	view->col_rank = prepcolranks(view->sequence, totseqs,
1546 		view->max_seq_length, view->each_length,
1547 		( view->protein ? get_color_for_aa : get_color_for_base ),
1548 		view->numb_gc, view->allow_lower);
1549 	if(view->col_rank == NULL) out_of_memory();
1550 	view->alt_col_rank = NULL;
1551 	}
1552 view->first_seq = view->first_site = 1;
1553 #ifdef WIN32
1554 	Fl::flush();//necessary against bug with "Edit/Create seq" with FLTK 1.3
1555 #endif
1556 fl_font(view->DNA_obj->labelfont(), view->DNA_obj->labelsize());
1557 view->line_height = (int)( LINE_HEIGHT_FACTOR * fl_height() );
1558 view->char_width = fl_width("W");
1559 view->draw_names = -1;
1560 view->mod_cursor = FALSE;
1561 view->mod_seq = 0;
1562 view->multipl->argument(0);
1563 if(view->tot_seqs == 0)
1564 	view->cursor_seq = view->cursor_site = 0;
1565 else
1566 	view->cursor_seq = view->cursor_site = 1;
1567 view->old_cursor_seq = view->cursor_seq;
1568 view->old_cursor_site = view->cursor_site;
1569 view->cursor_in_comment = view->old_cursor_in_comment = FALSE;
1570 view->tot_sel_seqs = 0;
1571 if(view->menu_edit != NULL) {
1572 	Fl_Menu_Item *items = (Fl_Menu_Item *)view->menu_edit;
1573 	items[RENAME_SEQ].deactivate();
1574 	items[EDIT_COMMENTS].deactivate();
1575 	items[EDIT_SEQ].deactivate();
1576 	items[DUPLICATE_SEQ].deactivate();
1577 	items[DELETE_SEQ].deactivate();
1578 	items[COMPLEMENT_SEQ].deactivate();
1579 	items[REVERSE_SEQ].deactivate();
1580 	items[EXCHANGE_UT].deactivate();
1581 	items[DOT_PLOT].deactivate();
1582 	items[CONSENSUS_SEQ].deactivate();
1583 	items[DELETE_GAP_ONLY_SITES].activate();
1584 	items[SET_GCODE].deactivate();
1585 	items[COPY_SEQS].deactivate();
1586 	}
1587 	if(view->menu_align != NULL) {
1588 		Fl_Menu_Item *items = (Fl_Menu_Item *)view->menu_align;
1589 		items[ALIGN_SELECTED_SEQS].deactivate();
1590 		items[ALIGN_SITES].deactivate();
1591 		items[PROFILE].deactivate();
1592 		items[UNALIGN].deactivate();
1593 		}
1594 if(view->tot_seqs > 0) {
1595 	view->sel_seqs = (int *)calloc(view->tot_seqs, sizeof(int));
1596 	if(view->sel_seqs == NULL) out_of_memory();
1597 	}
1598 /* initialiser les regions et leur menu avec pas de region active */
1599 view->mod_region_line = FALSE;
1600 if(view->tot_seqs > 0) {
1601 	view->region_line = (char *)malloc(view->max_seq_length + 1);
1602 	if(view->region_line == NULL) out_of_memory();
1603 	}
1604 view->region_length = 0;
1605 view->active_region = NULL;
1606 if(view->menu_sites != NULL) {
1607 	if(view->tot_seqs > 0) (view->menu_sites->get_menu())->activate();
1608 	mylregion = view->regions;
1609   view->menu_sites->vclear();
1610 	while(mylregion != NULL) {
1611 	  view->menu_sites->add(mylregion->element->name, regions_menu_callback, NULL, FL_MENU_RADIO);
1612 		mylregion = mylregion->next;
1613 		}
1614 	}
1615 if(view->menu_species != NULL) {
1616   view->menu_species->vclear();
1617 	for (i=0; i < view->numb_species_sets; i++) {
1618 	  view->menu_species->add(view->name_species_sets[i], species_menu_callback, NULL, FL_MENU_RADIO);
1619 	  }
1620 	}
1621 view->show_comment_lines = (view->tot_comment_lines > 0);
1622 view->active_comment_line = 0;
1623 update_menu_footers(view);
1624 compute_size_params(view, TRUE);
1625 view->DNA_obj->take_focus();
1626 }
1627 
1628 
mod_multipl(SEA_VIEW * view,int newval)1629 void mod_multipl(SEA_VIEW *view, int newval)
1630 {
1631 Fl_Widget *obj = view->multipl;
1632 static char label[16];
1633 int old = obj->argument();
1634 
1635 if(newval == 0) sprintf(label, "%s-+_", view->movekeys);
1636 else	sprintf(label, "mult=%d", newval);
1637 obj->argument(newval);
1638 obj->label(label);
1639 if(newval != old) obj->redraw();
1640 }
1641 
1642 
rename_sequence(SEA_VIEW * view)1643 void rename_sequence(SEA_VIEW *view)
1644 {
1645 char *new_name;
1646 const char *rep;
1647 int num;
1648 if(view->tot_sel_seqs != 1) return; /* only by security, should not happen */
1649 num = 0;
1650 while( ! view->sel_seqs[num] ) num++;
1651 rep = fl_input("Rename:",view->seqname[num]);
1652 if(rep == NULL) return;
1653 new_name = (char *)malloc(strlen(rep)+1);
1654 if(new_name == NULL) return;
1655 free(view->seqname[num]);
1656 strcpy(new_name, rep);
1657 view->seqname[num] = new_name;
1658 if(num+1 >= view->first_seq && num+1 <= view->first_seq+view->tot_lines-1) {
1659   view->wid_names = compute_wid_names(view, view->tot_seqs);
1660   compute_size_params(view, TRUE);
1661   view->DNA_obj->redraw();
1662   }
1663 set_seaview_modified(view, TRUE);
1664 }
1665 
1666 
del_gap_only_sites(SEA_VIEW * view)1667 void del_gap_only_sites(SEA_VIEW *view)
1668 {
1669 int position, numseq, allgaps, inrun, debut, count;
1670 
1671 view->seq_length = 0;
1672 for(numseq = 0; numseq < view->tot_seqs; numseq++)
1673 	if(view->each_length[numseq] > view->seq_length)
1674 		view->seq_length = view->each_length[numseq];
1675 inrun = FALSE;
1676 position = -1;
1677 while( ++position <= view->seq_length) {
1678 	for(numseq = 0; numseq < view->tot_seqs; numseq++)
1679 		if(position < view->each_length[numseq] &&
1680 			view->sequence[numseq][position] != '-') break;
1681 	allgaps = (numseq >= view->tot_seqs);
1682 	if(position >= view->seq_length) allgaps = FALSE;
1683 	if(inrun == allgaps) continue;
1684 	if(allgaps && !inrun) {
1685 		inrun = TRUE;
1686 		debut = position;
1687 		}
1688 	else	{
1689 		inrun = FALSE;
1690 		count = position - debut;
1691 		for(numseq = 1; numseq <= view->tot_seqs; numseq++)
1692 			delete_gaps_before(view, numseq, debut + count + 1,
1693 				count);
1694 		view->seq_length -= count;
1695 		if(view->cursor_site > position) view->cursor_site -= count;
1696 		if(view->regions != NULL) delete_region_part(view,
1697 			debut + count + 1, count);
1698 		if(view->tot_comment_lines > 0)	delete_in_all_comments(count,
1699 			debut + count + 1, view);
1700 		position -= count;
1701 		}
1702 	}
1703 view->seq_length = 0;
1704 for(numseq = 0; numseq < view->tot_seqs; numseq++)
1705 	if(view->each_length[numseq] > view->seq_length)
1706 		view->seq_length = view->each_length[numseq];
1707 }
1708 
1709 
delete_selected_seqs(SEA_VIEW * view)1710 int delete_selected_seqs(SEA_VIEW *view)
1711 {
1712 void **temp_data;
1713 char **viewasprots = (char **)view->viewasprots;
1714 int new_tot_seqs, i, j, *temp_int, numset;
1715 new_tot_seqs = view->tot_seqs - view->tot_sel_seqs;
1716 if(new_tot_seqs > 0) {
1717 	temp_data = (void **)malloc(new_tot_seqs * sizeof(void *));
1718 	if(temp_data == NULL) return TRUE;
1719 	temp_int = (int *)malloc(new_tot_seqs * sizeof(int));
1720 	if(temp_int == NULL) return TRUE;
1721 	}
1722 
1723 for(i = 0, j = 0; i<  view->tot_seqs; i++) /* process sequences */
1724 	if( ! view->sel_seqs[i] ) temp_data[j++] = (void *) view->sequence[i];
1725 	else free(view->sequence[i]);
1726 memcpy(view->sequence , temp_data, new_tot_seqs * sizeof(char *) );
1727 
1728 if(viewasprots != NULL) {
1729 	for(i = 0, j = 0; i<  view->tot_seqs; i++) /* process sequences */
1730 		if( ! view->sel_seqs[i] ) temp_data[j++] = (void *) viewasprots[i];
1731 		else free(viewasprots[i]);
1732 	memcpy(viewasprots, temp_data, new_tot_seqs * sizeof(char *) );
1733 	}
1734 
1735 if(view->comments != NULL) {
1736 	for(i = 0, j = 0; i<  view->tot_seqs; i++) /* process comments */
1737 		if( ! view->sel_seqs[i] ) temp_data[j++] =
1738 						(void *) view->comments[i];
1739 		else if( view->comments[i]!= NULL) free(view->comments[i]);
1740 	memcpy(view->comments , temp_data, new_tot_seqs * sizeof(char *) );
1741 	}
1742 
1743 for(i = 0, j = 0; i<  view->tot_seqs; i++) /* process seq names */
1744 	if( ! view->sel_seqs[i] ) temp_data[j++] = (void *) view->seqname[i];
1745 	else free(view->seqname[i]);
1746 memcpy(view->seqname , temp_data, new_tot_seqs * sizeof(char *) );
1747 
1748 for(i = 0, j = 0; i<  view->tot_seqs; i++) /* process seq lengths */
1749 	if( ! view->sel_seqs[i] ) temp_int[j++]= view->each_length[i];
1750 memcpy(view->each_length , temp_int, new_tot_seqs * sizeof(int) );
1751 
1752 if(view->numb_gc > 1) { /* process color-coded sequences */
1753 	for(i = 0, j = 0; i<  view->tot_seqs; i++)
1754 		if( ! view->sel_seqs[i] ) temp_data[j++] = (void *) view->col_rank[i];
1755 		else free(view->col_rank[i]);
1756 		memcpy(view->col_rank , temp_data, new_tot_seqs * sizeof(char *) );
1757    	}
1758 for(numset = 0; numset < view->numb_species_sets; numset++) {
1759 /* process species sets */
1760 	for(i = 0, j = 0; i < view->tot_seqs; i++) {
1761 		if( ! view->sel_seqs[i] )
1762 			temp_int[j++]= view->list_species_sets[numset][i];
1763 		}
1764 	memcpy(view->list_species_sets[numset], temp_int,
1765 		new_tot_seqs * sizeof(int) );
1766 	}
1767 
1768 if (! view->cursor_in_comment) view->cursor_seq = view->old_cursor_seq = 1;
1769 memset(view->sel_seqs, 0, view->tot_seqs * sizeof(int));
1770 view->tot_seqs = new_tot_seqs;
1771 select_deselect_seq(view, 0);
1772 if(view->menu_species != NULL) {
1773 	numset = 0;
1774 	while(numset < view->numb_species_sets) { /* check for empty sets */
1775 		for(i = 0, j = 0; i < view->tot_seqs; i++)
1776 			if( view->list_species_sets[numset][i] ) j++;
1777 		if( j == 0 ) { /* set became empty => remove it */
1778 			free(view->list_species_sets[numset]);
1779 			free(view->name_species_sets[numset]);
1780 			memcpy(view->list_species_sets + numset,
1781 			view->list_species_sets + numset + 1,
1782 			(view->numb_species_sets - numset - 1)*sizeof(int *) );
1783 			memcpy(view->name_species_sets + numset,
1784 			view->name_species_sets + numset + 1,
1785 			(view->numb_species_sets - numset - 1)*sizeof(char *) );
1786 		  view->menu_species->remove(numset);
1787 		  view->menu_species->value(0);
1788 			(view->numb_species_sets)--;
1789 			}
1790 		else	numset++;
1791 		}
1792 	}
1793 set_seaview_modified(view, TRUE);
1794 return FALSE;
1795 }
1796 
1797 
vh_sliders_callback(Fl_Widget * ob,void * data)1798 void vh_sliders_callback(Fl_Widget *ob, void *data)
1799 {
1800 int old, new_val, page;
1801 int which = ((user_data_plus *)data)->value;
1802 SEA_VIEW *view = (SEA_VIEW *)((user_data_plus *)data)->p;
1803 Fl_Scrollbar *sli = (Fl_Scrollbar *)ob;
1804 
1805 new_val = sli->value();
1806 if (which == 0) { /* vertical */
1807       	old = view->first_seq;
1808 	if( Fl::event_is_click() ) {
1809 		page = view->tot_lines - 2;
1810 		if(page < 1) page = 1;
1811 		if(new_val > old + sli->linesize() ) new_val = old + page;
1812 		else if(new_val < old - sli->linesize() ) new_val = old - page;
1813 		new_val = (int) sli->clamp(new_val);
1814 		((Fl_Valuator *)sli)->value(new_val);
1815 		}
1816       	view->first_seq = new_val;
1817 	if(old != new_val) view->DNA_obj->redraw();
1818 	}
1819 else	{ /* horizontal */
1820       	old = view->first_site;
1821 	if( Fl::event_is_click() ) {
1822 		page = view->tot_sites - 20;
1823 		if(page < 10) page = 10;
1824 		if(new_val > old + sli->linesize() ) new_val = old + page;
1825 		else if(new_val < old - sli->linesize() ) new_val = old - page;
1826 		new_val = (int)sli->clamp(new_val);
1827 		((Fl_Valuator *)sli)->value(new_val);
1828 		}
1829       	view->first_site = new_val;
1830 	view->draw_names = 0;
1831 	if(old != new_val) view->DNA_obj->damage(1);
1832 	}
1833 view->DNA_obj->take_focus();
1834 }
1835 
1836 
lrdu_button_callback(Fl_Widget * ob,void * data)1837 void lrdu_button_callback(Fl_Widget *ob, void *data)
1838 {
1839 Fl_Slider *sli;
1840 int *pval, newval=0;
1841 int mini, maxi;
1842 
1843 int which = ((user_data_plus *)data)->value;
1844 SEA_VIEW *view = (SEA_VIEW *)((user_data_plus *)data)->p;
1845 if(which <= 3) { /* mouvement horizontal */
1846 	sli = view->horsli;
1847 	pval = &view->first_site;
1848 	}
1849 else	{ /* mouvement vertical */
1850 	sli = view->vertsli;
1851 	pval = &view->first_seq;
1852 	}
1853 mini = (int)(sli->minimum());
1854 maxi = (int)(sli->maximum());
1855 
1856 if(which == 1 || which == 5) newval = mini;
1857 else if(which == 3 || which == 7) newval = maxi;
1858 
1859 if(newval < mini) newval = mini;
1860 if(newval > maxi) newval = maxi;
1861 if(newval != *pval) {
1862 	*pval = newval;
1863 	sli->value(*pval);
1864 	if(which <= 3)  view->draw_names = 0;
1865 	view->DNA_obj->damage(view->draw_names ? FL_DAMAGE_ALL : 1);
1866 	}
1867 view->DNA_obj->take_focus();
1868 }
1869 
1870 
font_callback(Fl_Widget * ob,void * data)1871 void font_callback(Fl_Widget *ob, void *data)
1872 {
1873 int taille;
1874   SEA_VIEW *view = (SEA_VIEW*)ob->user_data();
1875 sscanf( ((Fl_Menu_ *)ob)->text(), "%d", &taille);
1876 if(view->DNA_obj->labelsize() == taille ) return;
1877 my_watch_cursor(view->dnawin);
1878 view->DNA_obj->labelsize(taille);
1879 fl_font( view->DNA_obj->labelfont(), view->DNA_obj->labelsize() );
1880 view->line_height = (int)( LINE_HEIGHT_FACTOR * fl_height() );
1881 view->char_width = fl_width("W");
1882 compute_size_params(view, TRUE);
1883 view->DNA_obj->parent()->redraw();
1884 fl_reset_cursor(view->dnawin);
1885 view->DNA_obj->take_focus();
1886 }
1887 
1888 
set_save_format(SEA_VIEW * view,int val)1889 void set_save_format(SEA_VIEW *view, int val)
1890 {
1891 if(val >= nbr_formats) return;
1892 if( view->format_for_save == (known_format)val) return;
1893 view->format_for_save = (known_format)val;
1894   Fl_Menu_Item *items = (Fl_Menu_Item*)view->menu_file;
1895 if(view->masename != NULL) {
1896 	 items[SAVE].activate();
1897 	}
1898 }
1899 
1900 
colors_callback(Fl_Widget * ob,void * data)1901 void colors_callback(Fl_Widget *ob, void *data)
1902 {
1903   SEA_VIEW *view = (SEA_VIEW*)ob->user_data();
1904   Fl_Menu_Item *menu_props = (Fl_Menu_Item *)view->menu_props;
1905   props_menu_parts *parts = (props_menu_parts *)view->menu_props->user_data();
1906 int reponse =  ((Fl_Menu_*)ob)->mvalue() - menu_props;
1907 Fl_Menu_Item *item;
1908 
1909 /* processing inverted colors */
1910 if(reponse == parts->inverted) {
1911 	int style;
1912 	my_watch_cursor(view->dnawin);
1913 	view->inverted_colors = !view->inverted_colors;
1914 	if(view->inverted_colors) {
1915 		style = FL_COURIER;
1916 		}
1917 	else	{
1918 		style = FL_COURIER_BOLD;
1919 		}
1920 	view->DNA_obj->labelfont(style);
1921 	view->DNA_obj->redraw();
1922 	fl_reset_cursor(view->dnawin);
1923 	return;
1924 	}
1925 
1926 /* changing DNA / protein / Alternate protein / Codon mode */
1927 enum {DNARNA, Protein, Alt, Codon };
1928 int debut = parts->colors;
1929 reponse -= debut;
1930 if(reponse == Protein && view->protein &&
1931 	( view->alt_colors == USING_STANDARD_COLORS ||
1932 	view->alt_colors == NO_ALT_COLORS) ) return;
1933 if(reponse == Alt && view->alt_colors == USING_ALT_COLORS) return;
1934 view->protein = (reponse == Protein || reponse == Alt);
1935 my_watch_cursor(view->dnawin);
1936 if(view->numb_gc > 1) { /* free col_rank */
1937 	int num;
1938 	for(num = 0; num < view->tot_seqs; num++) {
1939 		free(view->col_rank[num]);
1940 		}
1941 	free(view->col_rank);
1942 	}
1943 if(reponse == DNARNA) {
1944 	view->numb_gc = view->numb_dnacolors;
1945 	view->curr_colors = view->dnacolors;
1946 	}
1947 else if(reponse == Protein) {
1948 	set_aa_color_mode(USING_STANDARD_COLORS);
1949 	view->numb_gc = view->numb_stdprotcolors;
1950 	view->curr_colors = view->stdprotcolors;
1951 	}
1952 else if(reponse == Alt) {
1953 	set_aa_color_mode(USING_ALT_COLORS);
1954 	view->numb_gc = view->numb_altprotcolors;
1955 	view->curr_colors = view->altprotcolors;
1956 	}
1957 else if(reponse == Codon) {
1958 	view->numb_gc = 22;
1959 	view->curr_colors = view->codoncolors;
1960 	}
1961 item = menu_props + parts->edit;
1962 adjust_menu_edit_modes(view);
1963 if(reponse != Codon) {
1964 	view->col_rank = prepcolranks(view->sequence, view->tot_seqs,
1965 								  view->max_seq_length, view->each_length,
1966 								  (view->protein ? get_color_for_aa : get_color_for_base),
1967 								  view->numb_gc, view->allow_lower);
1968 	}
1969 else view->col_rank = prepcolranks_by_codon(view->sequence, view->tot_seqs, view->max_seq_length,
1970 										   view->each_length, view->comments);
1971 
1972 if(view->col_rank == NULL) out_of_memory();
1973   if (reponse == Protein)  view->alt_colors = NO_ALT_COLORS;
1974   if (reponse == Alt)  view->alt_colors = USING_ALT_COLORS;
1975 view->DNA_obj->redraw();
1976 view->DNA_obj->take_focus();
1977 fl_reset_cursor(view->dnawin);
1978 }
1979 
1980 
allow_edit_callback(Fl_Widget * ob,void * data)1981 void allow_edit_callback(Fl_Widget *ob, void *data)
1982 {
1983   SEA_VIEW *view = (SEA_VIEW*)ob->user_data();
1984 Fl_Menu_Item *item = (Fl_Menu_Item*)((Fl_Menu_*)ob)->mvalue();
1985 
1986 view->allow_seq_edit = !view->allow_seq_edit;
1987 if(view->allow_seq_edit)
1988 	item->set();
1989 else
1990 	item->clear();
1991 view->DNA_obj->take_focus();
1992 }
1993 
1994 
viewasprots_callback(Fl_Widget * ob,void * data)1995 void viewasprots_callback(Fl_Widget *ob, void *data)
1996 {
1997   SEA_VIEW *view = (SEA_VIEW*)ob->user_data();
1998   props_menu_parts *parts = (props_menu_parts *)view->menu_props->user_data();
1999 int oldedit, num;
2000 Fl_Menu_Item *menu_props = (Fl_Menu_Item *)view->menu_props;
2001 Fl_Menu_Item *item = (Fl_Menu_Item*)((Fl_Menu_*)ob)->mvalue();
2002 Fl_Menu_Item *item2 = menu_props + parts->edit;
2003 Fl_Menu_Item *fileitems = (Fl_Menu_Item *)view->menu_file;
2004   Fl_Menu_Item *edititems = (Fl_Menu_Item *)view->menu_edit;
2005 
2006 if(view->tot_seqs == 0) return;
2007 oldedit = item2->value();
2008 if(view->viewasprots != NULL) {
2009 	view->viewasprots = set_viewasprots(view, FALSE);
2010 	if(parts->usingcodoncolors) {
2011 		for(num = 0; num < view->tot_seqs; num++) free(view->col_rank[num]);
2012 		free(view->col_rank);
2013 		Fl_Menu_Item *codoncolor = menu_props + parts->colors + 3;
2014 		codoncolor->setonly();
2015 		view->numb_gc = 22;
2016 		view->curr_colors = view->codoncolors;
2017 		view->col_rank = prepcolranks_by_codon(view->sequence, view->tot_seqs, view->max_seq_length,
2018 											   view->each_length, view->comments);
2019 		}
2020 	}
2021 else {
2022 	parts->usingcodoncolors = (view->curr_colors == view->codoncolors);
2023 	view->viewasprots = set_viewasprots(view, TRUE);
2024 	}
2025 if(oldedit) item2->set();
2026 if(view->viewasprots != NULL) {
2027 	item->set();
2028 	item->activate();
2029 	item2->deactivate();
2030 	view->allow_seq_edit = FALSE;
2031 	fileitems[ACNUC_IMPORT].deactivate();
2032 	fileitems[SAVE_PROT_ALIGN].activate();
2033 	fileitems[SAVE].deactivate();
2034 	fileitems[SAVE_AS].deactivate();
2035 	fileitems[SAVE_REGIONS].deactivate();
2036 	edititems[PASTE_SEQS].deactivate();
2037 	edititems[CREATE_SEQ].deactivate();
2038 	edititems[LOAD_SEQ].deactivate();
2039 	edititems[EDIT_SEQ].deactivate();
2040 	edititems[DUPLICATE_SEQ].deactivate();
2041 	edititems[COMPLEMENT_SEQ].deactivate();
2042 	edititems[REVERSE_SEQ].deactivate();
2043 	edititems[CONSENSUS_SEQ].deactivate();
2044 	}
2045 else	{
2046 	item->clear();
2047 	item2->activate();
2048 	view->allow_seq_edit = item2->value();
2049 	fileitems[ACNUC_IMPORT].activate();
2050 	fileitems[SAVE_PROT_ALIGN].deactivate();
2051 	fileitems[SAVE].activate();
2052 	fileitems[SAVE_AS].activate();
2053 	if (view->active_region) fileitems[SAVE_REGIONS].activate();
2054 	edititems[PASTE_SEQS].activate();
2055         edititems[CREATE_SEQ].activate();
2056 	edititems[LOAD_SEQ].activate();
2057 	}
2058 view->DNA_obj->take_focus();
2059 }
2060 
2061 
consensus_allowgaps_callback(Fl_Widget * ob,void * data)2062 void consensus_allowgaps_callback(Fl_Widget *ob, void *data)
2063 {
2064 SEA_VIEW *view = (SEA_VIEW*)ob->user_data();
2065 int *poption = &(view->consensus_allowgaps);
2066 *poption = !(*poption);
2067 }
2068 
consensus_iupac_callback(Fl_Widget * ob,void * data)2069 void consensus_iupac_callback(Fl_Widget *ob, void *data)
2070 {
2071   SEA_VIEW *view = (SEA_VIEW*)ob->user_data();
2072   int *poption = &(view->consensus_allowiupac);
2073   *poption = !(*poption);
2074 }
2075 
2076 
slow_fast_callback(Fl_Widget * ob,void * data)2077 void slow_fast_callback(Fl_Widget *ob, void *data)
2078 {
2079   SEA_VIEW *view = (SEA_VIEW*)ob->user_data();
2080   Fl_Menu_Item *item = (Fl_Menu_Item*)((Fl_Menu_*)ob)->mvalue();
2081 view->double_buffer = !view->double_buffer;
2082 if(!view->double_buffer)
2083 	item->set();
2084 else
2085 	item->clear();
2086 Fl_Window *win = (Fl_Window *)view->DNA_obj->parent();
2087 Fl_Group *win_parent = (Fl_Group *)win->parent();
2088 int x,y,w,h;
2089 x = win->x(); y = win->y(); w = win->w(); h = win->h();
2090 int size = view->DNA_obj->labelsize();
2091 int font = view->DNA_obj->labelfont();
2092 Fl_Color col = view->DNA_obj->color();
2093 Fl_Color sel_col = view->DNA_obj->selection_color();
2094 win->hide();
2095 win_parent->remove(*win);
2096 delete win;
2097 Fl_Group::current(win_parent);
2098 if(view->double_buffer)
2099 	win = new Fl_Double_Window(x, y, w, h );
2100 else 	win = new Fl_Window(x,y,w,h);
2101 win->box(FL_DOWN_BOX);
2102 win->resizable(win);
2103 view->DNA_obj = (Fl_Widget*)new DNA_obj(3, 3, w - 6, h - 6, view);
2104 view->DNA_obj->labelfont(font);
2105 view->DNA_obj->labelsize(size);
2106 view->DNA_obj->color(col, sel_col);
2107 win->color(col);
2108 win->end();
2109 win->show();
2110 view->DNA_obj->take_focus();
2111 }
2112 
2113 
allow_lower_callback(Fl_Widget * ob,void * data)2114 void allow_lower_callback(Fl_Widget *ob, void *data)
2115 {
2116 SEA_VIEW *view = (SEA_VIEW*)ob->user_data();
2117 Fl_Menu_Item *item = (Fl_Menu_Item *)((Fl_Menu_*)ob)->mvalue();
2118 
2119 view->allow_lower = !view->allow_lower;
2120 if(view->allow_lower)
2121 	item->set();
2122 else
2123 	item->clear();
2124 view->DNA_obj->parent()->redraw();
2125 view->DNA_obj->take_focus();
2126 }
2127 
2128 
toggle_reference_callback(Fl_Widget * ob,void * data)2129 void toggle_reference_callback(Fl_Widget *ob, void *data)
2130 {
2131 int on;
2132   SEA_VIEW *view = (SEA_VIEW*)ob->user_data();
2133   props_menu_parts *parts = (props_menu_parts *)view->menu_props->user_data();
2134 Fl_Menu_Item *item = (Fl_Menu_Item *)view->menu_props + parts->edit;
2135 on = (view->menu_props + parts->reference)->value();
2136 reference_toggle(view, on);
2137 if(on) 	{
2138 	item->deactivate();
2139 	}
2140 else	{
2141 	item->activate();
2142 	if(view->allow_seq_edit) item->set();
2143 	else item->clear();
2144 	}
2145 }
2146 
2147 
dnakeys_callback(Fl_Widget * ob,void * data)2148 void dnakeys_callback(Fl_Widget *ob, void *data)
2149 {
2150   SEA_VIEW *view = (SEA_VIEW*)ob->user_data();
2151   props_menu_parts *parts = (props_menu_parts *)view->menu_props->user_data();
2152 int reponse =  (((Fl_Menu_*)ob)->mvalue() - view->menu_props) - parts->keys;
2153 if( ! view->hjkl ) { /* activer un choix */
2154 	view->hjkl = reponse + 1;
2155 	}
2156 else if(view->hjkl == reponse + 1) { /* desactiver choix courant */
2157 	((Fl_Menu_Item*)((Fl_Menu_*)ob)->mvalue())->clear();
2158 	view->hjkl = 0;
2159 	}
2160 else	{ /* changer de choix */
2161 	view->hjkl = reponse + 1;
2162 	}
2163 }
2164 
2165 
consensus_opt_callback(Fl_Widget * ob,void * data)2166 void consensus_opt_callback(Fl_Widget *ob, void *data)
2167 {
2168 props_menu_parts *parts = (props_menu_parts *)data;
2169   SEA_VIEW *view = (SEA_VIEW*)ob->user_data();
2170 Fl_Menu_Item *menu_props = (Fl_Menu_Item *)view->menu_props;
2171 const char *rep;
2172 char tmp[100];
2173 int value;
2174 sprintf(tmp, "%d %%", view->consensus_threshold);
2175 rep = fl_input("Set consensus threshold value in %%", tmp );
2176 if(rep == NULL) return;
2177 value = -1;
2178 sscanf(rep, "%d", &value);
2179 if(value <= 0 || value > 100) return;
2180 view->consensus_threshold = value;
2181 sprintf(tmp, "%d %%", view->consensus_threshold);
2182   (menu_props + parts->consensusopt)->label(strdup(tmp));
2183 }
2184 
2185 
create_props_menu(SEA_VIEW * view,int my_color_choice,int inverted,int black_and_white,int def_fontsize)2186 void create_props_menu(SEA_VIEW *view,
2187 	int my_color_choice, int inverted, int black_and_white,
2188 	int def_fontsize)
2189 {
2190 #define NBER_FONTSIZES 10
2191   int defaut;
2192   static int first = TRUE;
2193   static props_menu_parts *parts;
2194 
2195   if (first) {
2196     first = FALSE;
2197     parts = (props_menu_parts *)malloc(sizeof(props_menu_parts));
2198 
2199     parts->colors = 1 + NBER_FONTSIZES + 3;
2200     parts->viewasprots = parts->colors - 2;
2201     parts->inverted = parts->colors + 4;
2202     parts->reference = parts->inverted + 3;
2203     parts->edit = parts->reference - 1;
2204     parts->keys = parts->reference + 2;
2205     parts->consensusopt = parts->keys + 5;
2206     parts->slow_fast = parts->consensusopt + 5;
2207     parts->allow_lower = parts->slow_fast + 1;
2208     }
2209 
2210   static const Fl_Menu_Item propsitems_static[] = {
2211     {"Fontsize", 0, 0, 0, FL_SUBMENU},
2212     {"8", 0, font_callback, 0, FL_MENU_RADIO},
2213     {"10", 0, font_callback, 0, FL_MENU_RADIO},
2214     {"12", 0, font_callback, 0, FL_MENU_RADIO},
2215     {"14", 0, font_callback, 0, FL_MENU_RADIO},
2216     {"16", 0, font_callback, 0, FL_MENU_RADIO},
2217     {"18", 0, font_callback, 0, FL_MENU_RADIO},
2218     {"24", 0, font_callback, 0, FL_MENU_RADIO},
2219     {"28", 0, font_callback, 0, FL_MENU_RADIO},
2220     {"32", 0, font_callback, 0, FL_MENU_RADIO},
2221     {"36", 0, font_callback, 0, FL_MENU_RADIO},
2222     {0},
2223     {"View as proteins", 0, viewasprots_callback, 0, FL_MENU_TOGGLE | FL_MENU_INACTIVE},
2224     {"Colors", 0, 0, 0, FL_SUBMENU},
2225     {"DNA-RNA colors", 0, colors_callback, 0, FL_MENU_RADIO},
2226     {"Protein colors", 0, colors_callback, 0, FL_MENU_RADIO},
2227     {"Alt. colors", 0, colors_callback, 0, FL_MENU_RADIO},
2228     {"Codon colors", 0, colors_callback, 0, FL_MENU_RADIO | FL_MENU_DIVIDER},
2229     {"Inverted colors", 0, colors_callback, 0, FL_MENU_TOGGLE},
2230     {0},
2231     {"Allow seq. editing", 0, allow_edit_callback, 0, FL_MENU_TOGGLE},
2232     {"by Reference", FL_COMMAND | 'r', toggle_reference_callback, 0, FL_MENU_TOGGLE},
2233     {"DNA keys", 0, 0, 0, FL_SUBMENU},
2234     {"hjkl<space> => GATCN", 0, dnakeys_callback, 0, FL_MENU_RADIO},
2235     {"hjkl<space> => TCGAN", 0, dnakeys_callback, 0, FL_MENU_RADIO},
2236     {"hjkl<space> => ACGTN", 0, dnakeys_callback, 0, FL_MENU_RADIO},
2237     {0},
2238     {"Consensus options", 0, 0, 0, FL_SUBMENU},
2239     {"%", 0, NULL, 0, FL_MENU_DIVIDER},
2240     {"allow gaps", 0, consensus_allowgaps_callback, 0, FL_MENU_TOGGLE},
2241     {"use IUPAC symbols", 0, consensus_iupac_callback, 0, FL_MENU_TOGGLE},
2242     {"Edit threshold", 0, consensus_opt_callback, parts, 0},
2243     {0},
2244     {"Fast-Rough", 0, slow_fast_callback, 0, FL_MENU_TOGGLE},
2245     {"Allow lowercase", 0, allow_lower_callback, 0, FL_MENU_TOGGLE},
2246     {"Customize", 0, custom_callback, NULL, 0},
2247     {"Statistics", 0, stats_callback, NULL, 0},
2248     {0}
2249   };
2250 
2251   Fl_Menu_Item *propsitems = new Fl_Menu_Item[sizeof(propsitems_static)/sizeof(Fl_Menu_Item)];
2252   memcpy(propsitems, propsitems_static, sizeof(propsitems_static));
2253   view->menu_props = propsitems;
2254   view->menubar->add("Props", 0, NULL, (void*)view->menu_props, FL_SUBMENU_POINTER);
2255   propsitems->user_data(parts);
2256 
2257 /* partie Fontsize */
2258 for(defaut = 1; defaut <= NBER_FONTSIZES; defaut++) {
2259 	int taille;
2260 	sscanf( propsitems[defaut].label(), "%d", &taille);
2261 	if(taille >= def_fontsize) break;
2262 	}
2263 if(defaut > NBER_FONTSIZES) defaut = 4;
2264 (propsitems + defaut)->set();
2265 
2266 /* partie View as proteins */
2267 
2268 /* partie Colors */
2269 if(black_and_white) {
2270 	(propsitems + parts->colors - 1)->deactivate();
2271 	}
2272 else	{
2273 	defaut = parts->colors; if(view->protein) defaut++;
2274 	(propsitems + defaut)->set();
2275 	if(my_color_choice == NO_ALT_COLORS)
2276 		(propsitems + parts->colors + 2)->deactivate();
2277 	if(inverted) (propsitems + parts->inverted)->set();
2278 	}
2279 
2280 /* partie Edit */
2281 
2282 /* partie by reference */
2283 
2284 /* partie keys */
2285 
2286 /* partie consensus options */
2287 char tmp[50];
2288 sprintf(tmp, "%d %%", view->consensus_threshold);
2289   (propsitems + parts->consensusopt)->label(strdup(tmp));
2290 
2291 /* partie Fast/Slow */
2292   (propsitems + parts->slow_fast)->flags =
2293 #ifdef __APPLE__
2294 	FL_MENU_INVISIBLE;
2295 #else
2296 	(view->double_buffer ? FL_MENU_TOGGLE : FL_MENU_TOGGLE | FL_MENU_VALUE);
2297 #endif
2298 
2299 /* partie allow lower case */
2300   if (view->allow_lower) (propsitems + parts->allow_lower)->set();
2301   if (black_and_white) (propsitems + parts->allow_lower)->deactivate();
2302 
2303 /* partie customize */
2304 /* partie statistiques */
2305 }
2306 
2307 
2308 /*int clipboard_contains_alignment(const char *clip)
2309 {
2310 extern char *fl_selection_buffer[];
2311 if(clip == NULL) clip = fl_selection_buffer[0];
2312 return (clip != NULL && memcmp(clip, CLIPBOARDMARK, strlen(CLIPBOARDMARK)) == 0);
2313 }
2314 
2315 void fix_all_paste_items(const char *p)
2316 {
2317 Fl_Window *w;
2318 SEA_VIEW *view;
2319 int mode;
2320 
2321 if(clipboard_contains_alignment(p) ) mode = 0;
2322 else mode = FL_MENU_INACTIVE;
2323 #ifdef WIN32
2324   Fl::check(); // calls Fl::do_widget_deletion(), crashes without this when closing window
2325 #endif
2326 w = Fl::first_window();
2327 while(w != NULL) {
2328 	if(w->callback() == mainwin_close_callback) {
2329 		view = (SEA_VIEW *)w->user_data();
2330 		if (view) {
2331 		  Fl_Menu_Item* items = (Fl_Menu_Item*)view->menu_edit;
2332 		  if (view->viewasprots || mode == FL_MENU_INACTIVE) items[PASTE_SEQS].deactivate();
2333 		  else items[PASTE_SEQS].activate();
2334 		  }
2335 		}
2336 	w = Fl::next_window(w);
2337 	}
2338 }
2339 
2340 void fix_paste_timeout(void *u)
2341 {
2342 fix_all_paste_items(NULL);
2343 Fl::repeat_timeout(0.5, fix_paste_timeout);
2344 }*/
2345 
2346 
edit_menu_callback(Fl_Widget * ob,void * data)2347 void edit_menu_callback(Fl_Widget *ob, void* data)
2348 {
2349 SEA_VIEW *view = (SEA_VIEW *)ob->user_data();
2350   int reponse = ((Fl_Menu_*)ob)->mvalue() - view->menu_edit;
2351 
2352 if(reponse == COPY_SEQS) { /* copy selected sequences */
2353 	region *myregion;
2354 	myregion = view->active_region;
2355 	if(myregion == NULL) {
2356 		myregion = (region *)malloc(sizeof(region));
2357 		if(myregion == NULL) return;
2358 		myregion->list = (list_segments *)malloc(sizeof(list_segments));
2359 		if(myregion->list == NULL) return;
2360 		myregion->list->debut = 1;
2361 		myregion->list->fin = view->seq_length;
2362 		myregion->list->next = NULL;
2363 		myregion->name = (char *)"all";
2364 		}
2365 	char *err = save_alignment_or_region(clipboardfname, view->sequence, view->comments,
2366 		NULL, view->seqname, view->tot_seqs, view->each_length,
2367 		NULL, myregion, MASE_FORMAT,
2368 		0, NULL, NULL, view->sel_seqs, view->tot_sel_seqs,
2369 		view->protein, 0, NULL, NULL, view->phylipwidnames,
2370 		0, NULL, NULL, FALSE);
2371 	if(view->active_region == NULL) { free(myregion->list); free(myregion); }
2372 	if(err == NULL) {
2373 	  //put filename on the selection clipboard (0)
2374 		char tmp[200];
2375 		sprintf(tmp, CLIPBOARDMARK"%s", clipboardfname);
2376 		Fl::copy(tmp, strlen(tmp), 0);
2377 	  //put Fasta sequences on the primary clipboard (1)
2378 		char *buf, *p;
2379 		int i, l = 0;
2380 		for( i = 0; i < view->tot_seqs; i++) {
2381 		  if(!view->sel_seqs[i]) continue;
2382 		  l += strlen(view->seqname[i]) + view->each_length[i] + 3;
2383 		  }
2384 		buf = (char *)malloc(l + 10);
2385 		if(buf != NULL) {
2386 			p = buf;
2387 			for( i = 0; i < view->tot_seqs; i++) {
2388 			  if(!view->sel_seqs[i]) continue;
2389 			  sprintf(p, ">%s\n", view->seqname[i]);
2390 			  p += strlen(p);
2391 			  strcpy(p, view->sequence[i]);
2392 			  p += strlen(p);
2393 			  *(p++) = '\n';
2394 			  }
2395 			Fl::copy(buf, p - buf, 1);
2396 			free(buf);
2397 		  }
2398 		}
2399 	else {
2400 		FILE *tmpf = fopen(clipboardfname, "w");
2401 		if (tmpf) fclose(tmpf);
2402 		Fl::copy("", 0, 0);
2403 		Fl::copy("", 0, 1);
2404 		}
2405 	}
2406 else if(reponse == PASTE_SEQS) {
2407 #ifdef WIN32
2408   pasted_from_what_source = 1;
2409 #else
2410   pasted_from_what_source = 0; /* paste first from the selection buffer */
2411 #endif
2412   Fl::paste(*(view->DNA_obj), pasted_from_what_source);
2413 	}
2414 else if(reponse == SELECT_ALL) { /* select all sequences */
2415   if(view->multipl->argument() > 0) mod_multipl(view,0);
2416   select_deselect_seq(view, -1);
2417   view->draw_names = -2;
2418   // ceci signifie redraw partiel commande' par draw_names, mod_cursor, ...
2419   view->DNA_obj->damage(1);
2420 }
2421 else if(reponse == RENAME_SEQ) { /* rename the selected sequence */
2422 	rename_sequence(view);
2423 	}
2424 else if(reponse == EDIT_COMMENTS) {
2425 	edit_comments_dialog(view);
2426 	}
2427 else if(reponse == EDIT_SEQ) {
2428 	edit_sequence_dialog(view);
2429 	}
2430 else if(reponse == DELETE_SEQ) { /* delete selected sequences from alignment */
2431 	if( fl_choice("Confirm request of deletion of %d sequence(s)", "Cancel", "Delete", NULL, view->tot_sel_seqs) ) {
2432 		if( delete_selected_seqs(view) )
2433 			fl_alert("Not enough memory for this operation");
2434 		else	{
2435 			compute_size_params(view, TRUE);
2436 			update_menu_footers(view);
2437 			view->DNA_obj->redraw();
2438 			view->vertsli->redraw();
2439 			}
2440 		}
2441 	}
2442 else if(reponse == CREATE_SEQ) { /* create a new sequence */
2443 	char *newname;
2444 	newname = (char *) fl_input("Name of the new sequence?", "");
2445 	if(newname == NULL || strlen(newname) == 0) return;
2446 	add_seq_to_align(view, newname, (char *)"-", 1);
2447 	}
2448 else if(reponse == LOAD_SEQ) { /* load a new sequence */
2449 	load_seq_dialog(view);
2450 	}
2451 else if(reponse == DUPLICATE_SEQ || reponse == COMPLEMENT_SEQ ||
2452 		 reponse == REVERSE_SEQ) {
2453 	int num, lenseq, old_first_seq;
2454 	char *newseq, *p, *q, *newname;
2455 	if(view->tot_sel_seqs != 1 ) return; /* par securite */
2456 	if(reponse != DUPLICATE_SEQ && view->protein) return; /* par securite */
2457 	for(num = 0; num < view->tot_seqs; num++)
2458 		if(view->sel_seqs[num]) break;
2459 	lenseq = view->each_length[num];
2460 	newseq = (char *)malloc(lenseq + 1);
2461 	if(newseq == NULL) {
2462 		fl_alert("Not enough memory\nto create a new sequence");
2463 	  Fl_Menu_Item *items = (Fl_Menu_Item *)view->menu_edit;
2464 		items[reponse].deactivate();
2465 		return;
2466 		}
2467 	if(reponse == DUPLICATE_SEQ) {
2468 		strcpy(newseq, view->sequence[num]);
2469 		}
2470 	else	{
2471 		p = view->sequence[num]; q = newseq + lenseq - 1;
2472 		while( *p != 0) {
2473 			if(reponse == COMPLEMENT_SEQ) *q = complement_base(*p);
2474 			else *q = *p;
2475 			p++; q--;
2476 			}
2477  		newseq[lenseq] = 0;
2478 		}
2479 	newname = (char*)malloc(strlen(view->seqname[num]) + 3);
2480 	if(reponse == COMPLEMENT_SEQ) strcpy(newname,"C_");
2481 	else if(reponse == REVERSE_SEQ) strcpy(newname,"R_");
2482 	else	strcpy(newname,"D_");
2483 	strcat(newname,view->seqname[num]);
2484 	old_first_seq = view->first_seq;
2485 	add_seq_to_align(view, newname , newseq, lenseq);
2486 	free(newseq);
2487 	free(newname);
2488 /* placer la nouvelle seq apres celle de depart */
2489 	view->sel_seqs[num] = FALSE;
2490 	view->sel_seqs[view->tot_seqs - 1] = TRUE;
2491 	deplacer_grp_seqs( view, FL_min(num + 2, view->tot_seqs) );
2492 /* montrer les 2 seqs concernees */
2493 	if(old_first_seq > num + 1) view->first_seq =
2494 		FL_min(num + 1, view->tot_seqs - view->tot_lines + 1);
2495 	else if(old_first_seq + view->tot_lines - 1 < num + 2)
2496 		view->first_seq = FL_min(num + 2,
2497 			view->tot_seqs - view->tot_lines + 1);
2498 	else
2499 		view->first_seq = old_first_seq;
2500 	view->vertsli->Fl_Slider::value(view->first_seq);
2501 	}
2502 else if(reponse == EXCHANGE_UT) { /* exchange Us and Ts */
2503 	int num; char *p;
2504 	if(view->tot_sel_seqs == 0 || view->protein) return; /* par securite */
2505 	my_watch_cursor(view->dnawin);
2506 	for(num = 0; num < view->tot_seqs; num++) {
2507 		if( ! view->sel_seqs[num] ) continue;
2508 		p = view->sequence[num] - 1;
2509 		while( *(++p) != 0 ) {
2510 			if( *p == 'U' ) {
2511 			   	*p = 'T';
2512 			   	}
2513 			else if( *p == 'T' ) {
2514 			   	*p = 'U';
2515 			   	}
2516 			else if( *p == 't' ) {
2517 			   	*p = 'u';
2518 				}
2519 			else if( *p == 'u' ) {
2520 			   	*p = 't';
2521 			   	}
2522 			}
2523 		}
2524 	set_seaview_modified(view, TRUE);
2525 	view->draw_names = 0;
2526 	view->DNA_obj->damage(1);
2527 	fl_reset_cursor(view->dnawin);
2528 	}
2529 else if(reponse == DOT_PLOT) { /* dot plot */
2530 	int num1, num2;
2531 	extern void show_dot_plot(char *seq1, char *seq2, char *seqname1,
2532 		char *seqname2, int l1, int l2, int maxseqlength,
2533 		void *seaview_data);
2534 
2535 	if(view->tot_sel_seqs != 2) return;
2536 	for(num1 = 0; num1 < view->tot_seqs; num1++)
2537 		if(view->sel_seqs[num1]) break;
2538 	for(num2 = num1 + 1; num2 < view->tot_seqs; num2++)
2539 		if(view->sel_seqs[num2]) break;
2540 	show_dot_plot(view->sequence[num1], view->sequence[num2],
2541 		view->seqname[num1], view->seqname[num2],
2542 		view->each_length[num1], view->each_length[num2],
2543 		view->max_seq_length, (void *)view);
2544 	}
2545 else if (reponse == CONSENSUS_SEQ) {
2546 	char *newseq, newname[100];
2547 	int old_total, *tmp, new_pos, i, old_first_seq;
2548 
2549 	if(view->tot_sel_seqs <= 1 ) return; /* par securite */
2550 	newseq = cre_consensus(view, newname);
2551 	if(newseq == NULL) {
2552 		fl_alert("Not enough memory\nto create a new sequence");
2553 		Fl_Menu_Item *items = (Fl_Menu_Item *)view->menu_edit;
2554 		items[reponse].deactivate();
2555 		return;
2556 		}
2557 	old_first_seq = view->first_seq;
2558 	old_total = view->tot_seqs;
2559 	add_seq_to_align(view, newname , newseq, strlen(newseq));
2560 	free(newseq);
2561 	for(i=0; i < view->tot_seqs; i++)
2562 		if(view->sel_seqs[i]) new_pos = i;
2563 	new_pos += 2;
2564 	if(view->tot_seqs == old_total || new_pos == view->tot_seqs) {
2565 		return;
2566 		}
2567 /* placer la nouvelle seq apres la derniere des selectionnees */
2568 	tmp = (int *)calloc(view->tot_seqs, sizeof(int));
2569 	if(tmp == NULL) {
2570 		return;
2571 		}
2572 	memcpy(tmp, view->sel_seqs, view->tot_seqs * sizeof(int) );
2573 	memset(view->sel_seqs, 0, view->tot_seqs * sizeof(int) );
2574 	view->sel_seqs[view->tot_seqs - 1] = TRUE;
2575 	old_total = view->tot_sel_seqs;
2576 	view->tot_sel_seqs = 1;
2577 	deplacer_grp_seqs( view, new_pos );
2578 	memcpy(view->sel_seqs, tmp, view->tot_seqs * sizeof(int) );
2579 	view->tot_sel_seqs = old_total;
2580 	free(tmp);
2581 /* montrer la seq concernee */
2582 	if(old_first_seq > new_pos ) view->first_seq =
2583 		FL_min(new_pos - 2,  1);
2584 	else if(old_first_seq + view->tot_lines - 1 < new_pos)
2585 		view->first_seq = FL_min(new_pos - 2,
2586 			view->tot_seqs - view->tot_lines + 1);
2587 	else
2588 		view->first_seq = old_first_seq;
2589 	view->vertsli->Fl_Slider::value(view->first_seq);
2590 	}
2591 else if(reponse == DELETE_GAP_ONLY_SITES) {
2592 	if( !fl_choice("Confirm remove all gap_containing sites?", "Cancel", "Remove", NULL) )
2593 		return;
2594 	my_watch_cursor(view->dnawin);
2595 	del_gap_only_sites(view);
2596 	compute_size_params(view, TRUE);
2597 	view->DNA_obj->redraw();
2598 	view->horsli->redraw();
2599 	fl_reset_cursor(view->dnawin);
2600 	}
2601 else if(reponse == SET_GCODE) {
2602 	if( (!view->protein) && view->tot_sel_seqs != 0 ) set_ncbi_genetic_code(view);
2603 	}
2604 }
2605 
2606 
set_and_show_new_cursor_site(SEA_VIEW * view,int new_pos,int center,int force_redraw)2607 void set_and_show_new_cursor_site(SEA_VIEW *view, int new_pos, int center,
2608 	int force_redraw)
2609 {
2610 int old_pos;
2611 old_pos = view->cursor_site;
2612 if(new_pos != old_pos)
2613 	view->cursor_site = new_pos;
2614 if(new_pos >= view->first_site && new_pos < view->first_site +
2615 	view->tot_sites - 1) {
2616 	if( !force_redraw &&
2617 		( (view->cursor_in_comment && view->mod_comment_line == 0) ||
2618 		(!view->cursor_in_comment && view->mod_seq == 0) ) )
2619 		view->mod_cursor = TRUE;
2620 	}
2621 else	{
2622 	if(center)
2623 		view->first_site =
2624 			view->cursor_site - view->tot_sites/2;
2625 	else	{
2626 		if(new_pos >= old_pos)
2627 			view->first_site = view->cursor_site + 10 -
2628 				view->tot_sites;
2629 		else
2630 			view->first_site = view->cursor_site - 10;
2631 		}
2632 	if(view->first_site + view->tot_sites - 1 >
2633 		view->seq_length + 1 )
2634 		view->first_site = view->seq_length - view->tot_sites + 2;
2635 	if(view->first_site <=0 )
2636 		view->first_site = 1;
2637 	view->horsli->Fl_Slider::value(view->first_site);
2638 	view->mod_seq = 0;
2639 	view->mod_comment_line = 0;
2640 	}
2641 view->draw_names = 0;
2642 view->DNA_obj->damage(1);
2643 }
2644 
2645 
set_and_show_new_cursor_seq(SEA_VIEW * view,int new_pos)2646 void set_and_show_new_cursor_seq(SEA_VIEW *view, int new_pos)
2647 {
2648 if(view->cursor_in_comment) {
2649 	if(view->comment_length[new_pos - 1] + 1 < view->cursor_site) {
2650 		fl_beep(FL_BEEP_DEFAULT);
2651 		return;
2652 		}
2653 	if(new_pos == view->cursor_seq) return;
2654 	view->cursor_seq = new_pos;
2655 	view->mod_cursor = TRUE;
2656 	view->draw_names = 0;
2657 	view->DNA_obj->damage(1);
2658 	return;
2659 	}
2660 if(view->each_length[new_pos - 1] + 1 < view->cursor_site) {
2661 	fl_beep(FL_BEEP_DEFAULT); return;
2662 	}
2663 if(new_pos != view->cursor_seq || new_pos < view->first_seq ||
2664 	view->cursor_site != view->old_cursor_site ||
2665 	new_pos >= view->first_seq + view->tot_lines) {
2666 	view->cursor_seq = new_pos;
2667 	if(new_pos >= view->first_seq && new_pos < view->first_seq +
2668 		view->tot_lines) {
2669 		view->mod_cursor = TRUE;
2670 		view->draw_names = 0;
2671 		view->DNA_obj->damage(1);
2672 		}
2673 	else	{
2674 		view->first_seq = view->cursor_seq - view->tot_lines/2;
2675 		if(view->first_seq + view->tot_lines >=
2676 			view->tot_seqs )
2677 			view->first_seq = view->tot_seqs - view->tot_lines + 1;
2678 		if(view->first_seq <=0 )
2679 			view->first_seq = 1;
2680 		view->vertsli->Fl_Slider::value(view->first_seq);
2681 		view->draw_names = -1;
2682 		view->DNA_obj->redraw();
2683 		}
2684 	}
2685 }
2686 
2687 
goto_callback(Fl_Widget * ob,void * data)2688 void goto_callback(Fl_Widget *ob, void *data)
2689 {
2690 Fl_Input *input;
2691 SEA_VIEW *view;
2692 int maxi, num, new_pos = -1, numerique = TRUE;
2693   unsigned l;
2694 char *p, *q, target[50];
2695 static char *upname;
2696 static int l_upname = 0;
2697 
2698 user_data_plus *data_plus = (user_data_plus *)data;
2699 int which = data_plus->value;
2700 if(which == 0) { /* appele par bouton goto */
2701 	input = (Fl_Input *)data_plus->p;
2702 	data_plus = (user_data_plus *)input->user_data();
2703 	}
2704 else	input = (Fl_Input*)ob;
2705 view = (SEA_VIEW *)data_plus->p;
2706 if(view->tot_seqs == 0) return;
2707 p = (char *)input->value();
2708 q = p - 1; while(*(++q) != 0) {
2709 	if(!isdigit(*q)) numerique = FALSE;
2710 	}
2711 if(numerique) { /* aller a une position de l'alignement */
2712 	sscanf(p,"%d",&new_pos);
2713 	if(view->cursor_in_comment)
2714 		maxi = view->comment_length[view->cursor_seq - 1];
2715 	else
2716 		maxi = view->each_length[view->cursor_seq - 1];
2717 	if( new_pos <= 0 || new_pos > maxi ) {
2718 		input->value("");
2719 		fl_beep(FL_BEEP_DEFAULT);
2720 		}
2721 	else	{
2722 		set_and_show_new_cursor_site(view, new_pos, TRUE, FALSE);
2723 		}
2724 	}
2725 else	{ /* recherche d'une seq par son nom */
2726 	l = strlen(p);
2727 	if (l > sizeof(target) - 1) l = sizeof(target) - 1;
2728 	strncpy(target, p, l); target[l] = 0; majuscules(target);
2729 	if(view->wid_names > l_upname) {
2730 		if(l_upname > 0) free(upname);
2731 		upname = (char *)malloc(view->wid_names + 1);
2732 		l_upname = view->wid_names;
2733 		}
2734 	for(num = 0; num < view->tot_seqs; num++) {
2735 		strncpy(upname, view->seqname[num], l_upname);
2736 		upname[l_upname] = 0; majuscules(upname);
2737 		if(strstr(upname, target) != NULL) break;
2738 		}
2739 	if(num >= view->tot_seqs) {
2740 		fl_beep(FL_BEEP_DEFAULT);
2741 		return;
2742 		}
2743 	if(view->cursor_site < view->first_site ||
2744 		view->cursor_site >= view->first_site + view->tot_sites)
2745 		view->cursor_site = view->first_site;
2746 	set_and_show_new_cursor_seq(view, num + 1);
2747 	}
2748 view->DNA_obj->take_focus();
2749 }
2750 
2751 
search_with_gaps(char * target,char * debut)2752 char *search_with_gaps(char *target, char *debut)
2753 {
2754 char *cherche, *trouve = debut - 1;
2755 do	{
2756 	debut = trouve + 1;
2757 	trouve = NULL;
2758 	cherche = target;
2759 	do	{
2760 		while( *debut == '-' ) debut++;
2761 		if(trouve == NULL) trouve = debut;
2762 		if ( toupper(*debut) != *cherche ) break;
2763 		cherche++; debut++;
2764 		}
2765 	while( *cherche != 0 );
2766 	}
2767 while( *trouve != 0  && *cherche != 0);
2768 return ( *cherche == 0 ? trouve : (char*)NULL );
2769 }
2770 
2771 
search_callback(Fl_Widget * ob,void * data)2772 void search_callback(Fl_Widget *ob, void *data)
2773 {
2774   SEA_VIEW *view;
2775   char *target, *pos, *debut;
2776   int new_pos;
2777 
2778   user_data_plus *data_plus = (user_data_plus *)data;
2779   int which = data_plus->value;
2780   if(which == 1) { /* appele par champ input */
2781 	  pos = (char *)((Fl_Input*)ob)->value();
2782 	  }
2783   else	{ /* appele par bouton search */
2784 	  Fl_Input *champ = (Fl_Input *)data_plus->p;
2785 	  pos = (char *)champ->value();
2786 	  data_plus = (user_data_plus *) champ->user_data();
2787 	  }
2788   view = (SEA_VIEW *)data_plus->p;
2789   if(view->tot_seqs == 0) return;
2790   target = strdup(pos);
2791   while((pos = strchr(target, '\n')) != NULL) *pos = ' ';
2792   while((pos = strchr(target, '\r')) != NULL) *pos = ' ';
2793   compact(target);
2794   if( strlen(target) == 0 ) {free(target); return; }
2795   majuscules(target);
2796   if(view->cursor_in_comment)
2797 	  debut = view->comment_line[view->cursor_seq - 1] + view->cursor_site;
2798   else
2799 	  debut = view->sequence[view->cursor_seq - 1] + view->cursor_site;
2800   pos = search_with_gaps(target, debut);
2801   free(target);
2802   if(pos == NULL) fl_beep(FL_BEEP_DEFAULT);
2803   else	{
2804 	  if(view->cursor_in_comment)
2805 		  new_pos = pos - view->comment_line[view->cursor_seq - 1] + 1;
2806 	  else
2807 		  new_pos = pos - view->sequence[view->cursor_seq - 1] + 1;
2808 	  set_and_show_new_cursor_site(view, new_pos, TRUE, FALSE);
2809 	  }
2810   view->DNA_obj->take_focus();
2811 }
2812 
2813 
free_alignment(SEA_VIEW * view)2814 void free_alignment(SEA_VIEW *view)
2815 {
2816 int num;
2817 if(view->header!=NULL) { free(view->header); view->header = NULL; }
2818 if(view->alt_col_rank != NULL) free_colranks_by_difference(view->alt_col_rank, view->tot_seqs);
2819 for(num = 0; num < view->tot_seqs; num++) {
2820 	free(view->sequence[num]);
2821 	free(view->seqname[num]);
2822 	if(view->comments != NULL && view->comments[num] != NULL) {
2823 		free(view->comments[num]);
2824 		view->comments[num] = NULL;
2825 		}
2826 	if(view->numb_gc > 1) {
2827 		free(view->col_rank[num]);
2828 		}
2829 	}
2830 if( view->tot_seqs > 0 ) {
2831 	free(view->sequence);
2832 	free(view->seqname);
2833 	if(view->comments != NULL) free(view->comments);
2834 	}
2835 if( view->numb_gc > 1 && view->tot_seqs > 0 ) free(view->col_rank);
2836 if(view->masename != NULL) {
2837 	free(view->masename);
2838 	view->masename = NULL;
2839 	}
2840 if( view->tot_seqs >= 1 ) {
2841 	free(view->each_length);
2842 	free(view->sel_seqs);
2843 	free(view->region_line);
2844 	}
2845 if(view->viewasprots != NULL) {
2846 	char **seqs = (char **)view->viewasprots;
2847 	for(num = 0; num < view->tot_seqs; num++) {
2848 		free(seqs[num]);
2849 		}
2850 	free(seqs);
2851 	}
2852 view->tot_seqs = 0;
2853 while (view->regions != NULL) delete_region(view, 1);
2854 for(num = 0; num < view->numb_species_sets; num++) {
2855 	free(view->list_species_sets[num]);
2856 	free(view->name_species_sets[num]);
2857 	}
2858 view->numb_species_sets = 0;
2859 view->tot_sel_seqs = 0;
2860 view->cursor_seq = 0;
2861 if(view->active_region != NULL) {
2862 	free_region(view->active_region);
2863 	view->active_region = NULL;
2864 	}
2865 if(view->menu_file != NULL) {
2866 	Fl_Menu_Item *items = (Fl_Menu_Item *)view->menu_file;
2867 	items[SAVE].deactivate();
2868 	items[SAVE_AS].deactivate();
2869 	items[SAVE_REGIONS].deactivate();
2870   items[SAVE_BOOTSTRAPS].deactivate();
2871 	}
2872 if(view->tot_comment_lines > 0) {
2873 	for(num = 0; num < view->tot_comment_lines; num++) {
2874 		free(view->comment_name[num]);
2875 		free(view->comment_line[num]);
2876 		}
2877 	free(view->comment_name);
2878 	free(view->comment_line);
2879 	free(view->comment_length);
2880 	view->tot_comment_lines = 0;
2881 	view->show_comment_lines = FALSE;
2882 	}
2883 for(num = 0; num < view->tot_trees; num++) free(view->trees[num]);
2884 if(view->tot_trees > 0) free(view->trees);
2885 view->tot_trees = 0;
2886 }
2887 
2888 
run_and_close_native_file_chooser(Fl_Native_File_Chooser * chooser,int keepalive)2889 char *run_and_close_native_file_chooser(Fl_Native_File_Chooser *chooser, int keepalive)
2890 //returns chosen file in static memory or NULL if user cancelled
2891 {
2892 	static char filename[PATH_MAX];
2893 	char *retval = NULL;
2894 #ifndef MICRO
2895 	static char last_visited_directory[PATH_MAX] = "";
2896 	char *p;
2897 	if ( chooser->directory() == NULL &&
2898 	  (chooser->preset_file() == NULL || *chooser->preset_file() != '/') ) {
2899 	  if( *last_visited_directory )chdir(last_visited_directory);
2900 	  chooser->directory(last_visited_directory);
2901 	  p = (char *)chooser->preset_file();
2902 	  if(p != NULL && *p != 0) {
2903 		  p = strdup(extract_filename(p));
2904 		  if(p != NULL) {
2905 			  chooser->preset_file(p);
2906 			  free(p);
2907 			  }
2908 		  }
2909 	}
2910 #endif
2911 	if ( chooser->show() == 0 ) {
2912 		strcpy(filename, chooser->filename());
2913 #ifndef MICRO
2914 		strcpy(last_visited_directory, filename);
2915 		p = strrchr(last_visited_directory, '/');
2916 		if(p != NULL) *p = 0;
2917 #endif
2918 		retval = filename;
2919 		}
2920 	if(!keepalive) delete chooser;
2921 	return retval;
2922 }
2923 
2924 
load_alignment_file(SEA_VIEW * view,char * filename,const char * message,known_format file_format,int doing_dnd)2925 Fl_Window *load_alignment_file(SEA_VIEW *view, char *filename, const char *message,
2926 	known_format file_format, int doing_dnd)
2927 /* returns the window containing the new alignment or NULL
2928  */
2929 {
2930 char *err_message;
2931 int protein;
2932 
2933 if(filename == NULL) {
2934 	Fl_Native_File_Chooser *chooser = new Fl_Native_File_Chooser();
2935 	chooser->title(message);
2936 	chooser->type(Fl_Native_File_Chooser::BROWSE_FILE);   // let user browse a single file
2937 	if ((int)file_format != -1) {
2938 		char wpattern[100];
2939                 const char *exts = (file_format == FASTA_FORMAT ?
2940                                     "{fa,fst,fasta}" : f_format_exts[file_format]);
2941 		sprintf(wpattern, "%s \t*.%s", f_format_names[file_format], exts);
2942 		chooser->filter(wpattern);
2943 		}
2944 	filename = run_and_close_native_file_chooser(chooser);
2945 	if(filename == NULL) return NULL;
2946 	}
2947 if ((int)file_format == -1) {
2948 	file_format = what_format(filename);
2949 	if(file_format < 0) {
2950 		fl_alert("File %s\nis not of a format readable by seaview", filename);
2951 		return NULL;
2952 		}
2953 	}
2954 if(view != NULL && view->alt_col_rank != NULL) {
2955 	reference_toggle(view, FALSE);
2956 	}
2957 // search for empty alignment window; if none, create a new one
2958 Fl_Window *w = Fl::first_window();
2959 while(w != NULL) {
2960 	if(w->callback() == mainwin_close_callback) {
2961 		view = (SEA_VIEW *)w->user_data();
2962 		if(view && view->tot_seqs == 0) break;
2963 		}
2964 	w = Fl::next_window(w);
2965 	}
2966 if(w == NULL) {
2967 	view = newwindow_callback(view);
2968 	}
2969 #ifdef WIN32
2970 	Fl::check();//to redraw window after file dialog box closes (FLTK bug fixed in FLTK 1.3.4)
2971 #endif
2972 my_watch_cursor(view->dnawin);
2973 if(file_format == MASE_FORMAT) {
2974 	view->tot_seqs = read_mase_seqs_header(filename, &view->sequence,
2975 		&view->seqname, &view->comments, &view->header,
2976 		&err_message);
2977 /* interpreter les regions du header du fichier mase */
2978 	view->regions = parse_regions_from_header(view->header);
2979 /* interpreter les species sets du fichier mase */
2980 	view->numb_species_sets = parse_species_sets_from_header(view->header,
2981 	view->list_species_sets, view->name_species_sets, view->tot_seqs);
2982 /* interpreter les trees du fichier mase */
2983 	parse_trees_from_header(view->header, view);
2984 /* interpreter les comment lines du header */
2985 view->tot_comment_lines = parse_comment_lines_from_header(view->header,
2986 	&(view->comment_line), &(view->comment_name),
2987 	&(view->comment_length) , &(view->max_seq_length));
2988 	}
2989 else if(file_format == FASTA_FORMAT)
2990 	view->tot_seqs = read_fasta_align(filename, &view->sequence,
2991 		&view->seqname, &view->comments, &view->header, &err_message, view->spaces_in_fasta_names);
2992 else if(file_format == PHYLIP_FORMAT)
2993 	view->tot_seqs = read_phylip_align(filename, &view->sequence,
2994 		&view->seqname, &view->comments, &view->header, &err_message);
2995 else if(file_format == CLUSTAL_FORMAT)
2996 	view->tot_seqs = read_clustal_align(filename, &view->sequence,
2997 		&view->seqname, &view->comments, &view->header, &err_message);
2998 else if(file_format == MSF_FORMAT)
2999 	view->tot_seqs = read_msf_align(filename, &view->sequence,
3000 		&view->seqname, &view->comments, &view->header, &err_message);
3001 else if(file_format == NEXUS_FORMAT) {
3002 	int **list_sp = NULL; char **name_sp = NULL; int i;
3003 	view->tot_seqs = read_nexus_align(filename, &view->sequence,
3004 		&view->seqname, &view->comments, &view->header,
3005 		&err_message, &view->regions, &view->numb_species_sets,
3006 		&list_sp, &name_sp, &view->tot_comment_lines,
3007 		&view->comment_name, &view->comment_line,
3008 		&view->comment_length, &protein, view);
3009 	for(i= 0; i < view->numb_species_sets; i++) {
3010 		view->list_species_sets[i] = list_sp[i];
3011 		view->name_species_sets[i] = name_sp[i];
3012 		}
3013 	if(list_sp != NULL) free(list_sp);
3014 	if(name_sp != NULL) free(name_sp);
3015 	}
3016 if(view->tot_seqs == 0 && view->tot_trees == 0) {
3017 	fl_reset_cursor(view->dnawin);
3018 	fl_alert("Error while reading file %s\n%s", filename,
3019 		err_message);
3020 	view->DNA_obj->parent()->redraw();
3021 	return NULL;
3022 	}
3023 if(file_format != NEXUS_FORMAT) protein = is_a_protein_alignment(view);
3024 if(view->menu_file != NULL) {
3025 	Fl_Menu_Item *items = (Fl_Menu_Item *)view->menu_file;
3026 	if(file_format == view->format_for_save) {
3027 		items[SAVE].activate();
3028 		items[SAVE_AS].activate();
3029 		}
3030 	else	{
3031 		items[SAVE_AS].activate();
3032 		if(view->masename != NULL) {
3033 			free(view->masename);
3034 			view->masename = filename = NULL;
3035 			}
3036 		}
3037 		items[SAVE_BOOTSTRAPS].activate();
3038 	}
3039 int keep_dnawin = TRUE;
3040 if(view->tot_seqs > 0) {
3041   extern char *position_mask_names[];
3042   extern int position_mask_count;
3043   list_regions *mylist = view->regions;
3044   while(mylist) { // hide each region named as in position_mask_names array
3045     for(int l = 0; l < position_mask_count; l++) {
3046       if(strcmp(mylist->element->name, position_mask_names[l]) == 0) {
3047 	mylist->element->hide_when_viewasprots = TRUE;
3048 	}
3049       }
3050     mylist = mylist->next;
3051     }
3052   init_dna_scroller(view, view->tot_seqs, filename, protein, view->header);
3053 	set_save_format(view, file_format);
3054 	view->DNA_obj->parent()->redraw();
3055 	w = view->dnawin;
3056 	}
3057 else 	{//there was only a tree in the file read
3058 	const char *p = view->menu_trees->vitem(0)->label();
3059 	keep_dnawin = doing_dnd || view->tot_trees > 1;
3060 	w = treedraw(strdup(view->trees[0]), view, p, keep_dnawin);
3061 	if(keep_dnawin) w = view->dnawin;
3062 	else view->dnawin->do_callback();//closes an empty alignment window that opened the tree
3063 	}
3064 if( keep_dnawin) fl_reset_cursor(view->dnawin);
3065 return w;
3066 }
3067 
3068 
mainwin_close_callback(Fl_Widget * form,void * data)3069 void mainwin_close_callback(Fl_Widget *form, void *data)
3070 {
3071 	SEA_VIEW *view = (SEA_VIEW *)data;
3072 	Fl_Window *w , *w2;
3073 	if(view->modif_but_not_saved) {
3074 		if( fl_choice("Alignment %s was modified but not saved\n"
3075 			"Do you want to close it anyway?", "Cancel", "Close", NULL, extract_filename(view->masename)) == 0) return;
3076 		}
3077 	free_alignment(view);
3078 #if defined(__APPLE__)
3079 	char value[50];
3080 	sprintf(value, "%dx%d", view->dnawin->w(),  view->dnawin->h() );
3081 # if 100*FL_MAJOR_VERSION + FL_MINOR_VERSION < 104
3082     delete_windowmenuitem(find_windowmenuitem(view->dnawin));
3083 # endif
3084 #endif
3085 	//disconnect all tree windows pointing to the deleted seaview window
3086 	disconnect_tree_windows(view);
3087 	//when a callback destroys its own widget delete is bad; Fl::delete_widget is to be called
3088 	Fl::delete_widget(form);
3089 	//search for last alignment window and not the one scheduled for deletion
3090 	w = Fl::first_window();
3091 	w2 = NULL;
3092 	while(w != NULL) {
3093           if(w != form && w->callback() == mainwin_close_callback) {w2 = w; break; }
3094 		w = Fl::next_window(w);
3095 		}
3096 	if(w2 != NULL) {
3097 		// set focus to last open alignment window
3098 		((SEA_VIEW *)w2->user_data())->DNA_obj->take_focus();
3099 		}
3100 	else {
3101 		// this was the last alignment window
3102 #ifdef __APPLE__
3103 		set_res_value("window", value);
3104 #endif
3105 		}
3106 	view->DNA_obj->user_data(NULL);
3107   delete[] view->menu_file;
3108   delete[] view->menu_edit;
3109   delete[] view->menu_align;
3110   delete[] view->menu_props;
3111   delete view->menu_sites;
3112   delete view->menu_species;
3113   delete[] view->menu_footers;
3114   delete view->menu_trees;
3115 	free(view);
3116 	form->user_data(NULL);
3117 }
3118 
to_do_at_exit(void)3119 void to_do_at_exit(void)
3120 {
3121   delete_tmp_filename(clipboardfname);
3122 }
3123 
close_all_saved_wins(Fl_Widget * ob)3124 void close_all_saved_wins(Fl_Widget *ob)
3125 {
3126 //this rather complicated stuff seems necessary for WIN32
3127 	Fl_Window *w, *mine;
3128 	int count = 0, i = 0;
3129 	mine = ob->window();
3130 	//count and memorize all top-level windows except that containing the calling menu
3131 	w = Fl::first_window();
3132 	while( w != NULL) {
3133 		if(w->window() == NULL && w != mine) count++;
3134 		w = Fl::next_window(w);
3135 	}
3136 	Fl_Window **tabwins = (Fl_Window **)malloc(count * sizeof(Fl_Window *));
3137 	w = Fl::first_window();
3138 	while( w != NULL) {
3139 		if(w->window() == NULL && w != mine) tabwins[i++] = w;
3140 		w = Fl::next_window(w);
3141 	}
3142 	//attempt closing all these windows
3143 	for(i = 0; i < count; i++) {
3144 		Fl::handle(FL_CLOSE, tabwins[i]);
3145 		Fl::wait(0);//this does close operation for good if needed
3146 	}
3147 	free(tabwins);
3148 	//finally attempt closing the calling menu-containing window
3149 	Fl::handle(FL_CLOSE, mine);
3150 	return;
3151 }
3152 
3153 
newwindow_callback(SEA_VIEW * old_view)3154 SEA_VIEW *newwindow_callback(SEA_VIEW *old_view)
3155 {
3156 SEA_VIEW *view = create_the_form( old_view != NULL ? old_view->double_buffer : TRUE );
3157 return view;
3158 }
3159 
3160 
file_menu_callback(Fl_Widget * ob,void * data)3161 void file_menu_callback(Fl_Widget *ob, void *data)
3162 {
3163 SEA_VIEW *view;
3164 char pattern[20];
3165 static char fsel_message[] = "seaview: choose file and format";
3166 char *filename;
3167   view = (SEA_VIEW *)ob->user_data();
3168 int reponse = ((Fl_Menu_*)ob)->mvalue() - view->menu_file;
3169 
3170 sprintf(pattern, "*.%s", f_format_exts[view->format_for_save]);
3171 if(reponse == CLOSE_WINDOW) {
3172 	ob->window()->do_callback();
3173 	}
3174 else if(reponse == QUIT) {
3175 	close_all_saved_wins(ob);
3176 	}
3177 else if(reponse == NEW_WINDOW) {
3178 	newwindow_callback(view);
3179 }
3180 else if(reponse == CONCATENATE) {
3181 	concatenate_dialog(view);
3182 }
3183 else if(reponse == OPEN_ANY) {
3184 #ifdef WIN32
3185   Fl::e_state = 0; // fix bug where CTRL remains ON if Ctrl-O shortcut was used
3186 #endif
3187   Fl_Native_File_Chooser *chooser = new Fl_Native_File_Chooser();
3188   chooser->title("Choose an alignment/tree file");
3189   chooser->type(Fl_Native_File_Chooser::BROWSE_FILE);   // let user browse a single file
3190   filename = run_and_close_native_file_chooser(chooser);
3191   if(filename == NULL) return;
3192   use_initial_file(view, filename, FALSE);
3193   }
3194 else if(reponse == OPEN_MASE) {
3195 	load_alignment_file(view, NULL, "Choose a .mase file",  MASE_FORMAT, FALSE);
3196 	}
3197 else if(reponse == OPEN_PHYLIP )	{
3198 	load_alignment_file(view, NULL, "Choose a Phylip file" ,  PHYLIP_FORMAT, FALSE);
3199 	}
3200 else if(reponse == OPEN_CLUSTAL )	{
3201 	load_alignment_file(view, NULL, "Choose a Clustal file" ,  CLUSTAL_FORMAT, FALSE);
3202 	}
3203 else if(reponse == OPEN_MSF )	{
3204 	load_alignment_file(view, NULL, "Choose an MSF file",  MSF_FORMAT, FALSE);
3205 	}
3206 else if(reponse == OPEN_FASTA )	{
3207 	load_alignment_file(view, NULL, "Choose a Fasta file",  FASTA_FORMAT, FALSE);
3208 	}
3209 else if(reponse == OPEN_NEXUS )	{
3210 	load_alignment_file(view, NULL, "Choose a NEXUS file",  NEXUS_FORMAT, FALSE);
3211 	}
3212 else if(reponse == ACNUC_IMPORT ) {
3213 	racnuc_dialog(view);
3214 	}
3215 else if(reponse == SAVE || reponse == SAVE_AS) 	{
3216 	char *err;
3217 	if(reponse == SAVE_AS) { /* Save as */
3218 		known_format new_format;
3219 		filename = seaview_file_chooser_save_as(fsel_message, view->masename, view, &new_format);
3220 		if(filename==NULL) return;
3221 		set_save_format(view, new_format);
3222 		}
3223 	else {
3224 		filename = view->masename;
3225 		}
3226 	my_watch_cursor(view->dnawin);
3227 	save_active_region(view);
3228 	err = save_alignment_or_region(filename, view->sequence, view->comments,
3229 		view->header, view->seqname, view->tot_seqs, view->each_length,
3230 		view->regions, NULL, view->format_for_save,
3231 		view->numb_species_sets, view->list_species_sets,
3232 		view->name_species_sets, NULL, 0, view->protein,
3233 		view->tot_comment_lines, view->comment_name,
3234 		view->comment_line, view->phylipwidnames,
3235 		view->tot_trees, view->trees,
3236 		view->menu_trees->vitem(0), view->spaces_in_fasta_names);
3237 	fl_reset_cursor(view->dnawin);
3238 	if(err != NULL) fl_alert("%s", err);
3239 	else 	{
3240 		if(reponse == SAVE_AS) {
3241 			if(view->masename != NULL) free(view->masename);
3242 			view->masename=(char *)malloc(strlen(filename)+1);
3243 			if(view->masename == NULL) out_of_memory();
3244 			strcpy(view->masename,filename);
3245 			view->dnawin->label(extract_filename(filename));
3246 #if defined(__APPLE__) && 100*FL_MAJOR_VERSION + FL_MINOR_VERSION < 104
3247 			rename_windowmenuitem(view->dnawin->label(), find_windowmenuitem(view->dnawin));
3248 #endif
3249 		  Fl_Menu_Item *items = (Fl_Menu_Item *)view->menu_file;
3250 			items[SAVE].activate();
3251 			}
3252 		set_seaview_modified(view, FALSE);
3253 		}
3254 	}
3255 else if(reponse == SAVE_REGIONS) {  /* save current regions choice */
3256 	char *err;
3257 	region *myregion;
3258 	known_format region_format;
3259 	static char regions_only_filename[200];
3260 	static int first = TRUE;
3261 	if(first) {
3262 	 	strcpy(regions_only_filename, "regions");
3263 		if( strchr(pattern,'.') != NULL)
3264 			strcat(regions_only_filename,
3265 				pattern+1);
3266 		first = FALSE;
3267 		}
3268 	filename = seaview_file_chooser_save_as(fsel_message, regions_only_filename, view, &region_format);
3269 	if(filename==NULL) return;
3270 	my_watch_cursor(view->dnawin);
3271 	myregion = view->active_region;
3272 	if(myregion == NULL) {
3273 		myregion = (region *)malloc(sizeof(region));
3274 		if(myregion == NULL) return;
3275 		myregion->list = (list_segments *)malloc(sizeof(list_segments));
3276 		if(myregion->list == NULL) return;
3277 		myregion->list->debut = 1;
3278 		myregion->list->fin = view->seq_length;
3279 		myregion->list->next = NULL;
3280 		myregion->name = (char *)"all";
3281 		}
3282 	err = save_alignment_or_region(filename, view->sequence, view->comments,
3283 		view->header, view->seqname, view->tot_seqs, view->each_length,
3284 		NULL, myregion, region_format,
3285 		0, NULL, NULL, view->sel_seqs, view->tot_sel_seqs,
3286 		view->protein, 0, NULL, NULL, view->phylipwidnames,
3287 		view->tot_trees, view->trees,
3288 		view->menu_trees->vitem(0), view->spaces_in_fasta_names);
3289 	if(view->active_region == NULL) { free(myregion->list); free(myregion); }
3290 	fl_reset_cursor(view->dnawin);
3291 	if(err != NULL) fl_alert("%s", err);
3292 	else strcpy(regions_only_filename, extract_filename(filename));
3293 	}
3294 else if(reponse == SAVE_PROT_ALIGN) {  /* save alignmt at protein level */
3295 	char *err;
3296 	known_format new_format;
3297 	filename = seaview_file_chooser_save_as(fsel_message, view->masename, view, &new_format);
3298 	if(filename==NULL) return;
3299 	my_watch_cursor(view->dnawin);
3300 	err = save_alignment_or_region(filename, view->sequence, view->comments,
3301 								   view->header, view->seqname, view->tot_seqs, view->each_length,
3302 								   view->regions, NULL, new_format,
3303 								   view->numb_species_sets, view->list_species_sets,
3304 								   view->name_species_sets, NULL, 0, TRUE,
3305 								   0, NULL, NULL, view->phylipwidnames,
3306 								   view->tot_trees, view->trees,
3307 								   view->menu_trees->vitem(0),
3308 								   view->spaces_in_fasta_names);
3309 	fl_reset_cursor(view->dnawin);
3310 	if(err != NULL) fl_alert("%s", err);
3311 	}
3312 else if(reponse == SAVE_BOOTSTRAPS && view->tot_seqs > 0) {  /* save bootstrap replicates */
3313   char suggested[300], *p;
3314   int replicates = -1;
3315   strcpy(suggested, view->masename);
3316   p = strrchr(suggested, '.');
3317   if (p != NULL) *p = 0;
3318   strcat(suggested, "_bootstraps.phy");
3319   Fl_Native_File_Chooser *chooser = new Fl_Native_File_Chooser();
3320   chooser->type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
3321   chooser->options(Fl_Native_File_Chooser::SAVEAS_CONFIRM | chooser->options());
3322   chooser->title("Enter output bootstrap Phylip filename");
3323   chooser->directory(extract_dirname(suggested));
3324   chooser->preset_file(extract_filename(suggested));
3325   filename = run_and_close_native_file_chooser(chooser);
3326   if (filename == NULL) return;
3327   const char *rep = fl_input("Desired number of bootstrap replicates:", "100");
3328   if (!rep) return;
3329   sscanf(rep, "%d", &replicates);
3330   if (replicates == -1) return;
3331   my_watch_cursor(view->dnawin);
3332   save_bootstrap_replicates(filename, replicates, view);
3333   fl_reset_cursor(view->dnawin);
3334   }
3335 else if(reponse == PRINTOUT && view->tot_seqs > 0) {
3336 	int anerr;
3337 	char suggested[200], *p;
3338 
3339 	strcpy(suggested, view->masename);
3340 	p = strrchr(suggested, '.');
3341 	if(p != NULL) *p = 0;
3342 	if(printout_black == TEXT_ONLY) strcat(suggested, ".txt");
3343 	else {
3344 		strcat(suggested, "." PDF_OR_PS_EXT);
3345 		}
3346 if( view->alt_col_rank != NULL ) {
3347 		for(anerr = 0; anerr < view->tot_seqs; anerr++)
3348 			if(view->sel_seqs[anerr]) break;
3349 		}
3350 	else	anerr = -1;
3351 #if defined(__APPLE__)
3352 	filename = mac_GetOutputFName_Plus(extract_filename(suggested), "Enter an output file name",
3353 									   (anerr >= 0 ? TRUE : FALSE), extract_dirname(view->masename) );
3354 #else
3355 	Fl_Native_File_Chooser *chooser = new Fl_Native_File_Chooser();
3356 	chooser->type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
3357   chooser->options(Fl_Native_File_Chooser::SAVEAS_CONFIRM | chooser->options());
3358 	chooser->title("Enter an output file name");
3359 	chooser->directory(extract_dirname(suggested));
3360 	chooser->preset_file(extract_filename(suggested));
3361 	if(printout_black == TEXT_ONLY)
3362 		chooser->filter("Text Files\t*.txt");
3363 	else {
3364 #ifdef NO_PDF
3365 		chooser->filter("PostScript Files\t*.ps");
3366 #else
3367 		chooser->filter("PDF Files\t*.pdf");
3368 #endif
3369 	}
3370 	filename = run_and_close_native_file_chooser(chooser);
3371 #endif
3372 	if(filename == NULL) return;
3373 	my_watch_cursor(view->dnawin);
3374   anerr = printout(view, filename, printout_fontsize,
3375 	       printout_block, printout_pageformat, printout_vary, anerr, printout_black, printout_layout);
3376 
3377 	fl_reset_cursor(view->dnawin);
3378 	if( anerr ) fl_alert("Error while writing to file %s", filename);
3379 	}
3380 #if !defined(__APPLE__)
3381 else if(reponse == PDFOPTIONS ) {
3382 	pdfps_options_dialog(view, true);
3383 	}
3384 #endif
3385 }
3386 
3387 
3388 
3389 #if !defined( __APPLE__)
3390 
printout_callback(Fl_Widget * obj,void * data)3391 static void printout_callback(Fl_Widget *obj, void *data)
3392 {
3393 const char *p;
3394 
3395 p = ((Fl_Input *)obj)->value();
3396 sscanf(p, "%d", (int *)data);
3397 }
3398 
3399 
ok_callback(Fl_Widget * obj)3400 static void ok_callback(Fl_Widget *obj)
3401 {
3402 if(obj->window() == NULL) obj->hide();
3403 else obj->window()->hide();
3404 }
3405 
3406 
paper_callback(Fl_Widget * obj)3407 static void paper_callback(Fl_Widget *obj)
3408 {
3409   printout_pageformat = ((Fl_Choice *)obj)->value() == 0 ? Fl_Paged_Device::A4 : Fl_Paged_Device::LETTER;
3410 }
3411 
layout_callback(Fl_Widget * obj)3412 static void layout_callback(Fl_Widget *obj)
3413 {
3414   printout_layout = ((Fl_Check_Button *)obj)->value() == 0 ? Fl_Paged_Device::PORTRAIT : Fl_Paged_Device::LANDSCAPE;
3415 }
3416 
variable_callback(Fl_Widget * obj)3417 static void variable_callback(Fl_Widget *obj)
3418 {
3419 printout_vary = ! printout_vary;
3420 }
3421 
3422 
radio_callback(Fl_Widget * obj)3423 static void radio_callback(Fl_Widget *obj)
3424 {
3425 Fl_Group *group;
3426 
3427 if( ! ((Fl_Round_Button *)obj)->value() ) {
3428 	((Fl_Round_Button *)obj)->setonly();
3429 	return;
3430 	}
3431 group = obj->parent();
3432 if ( ((Fl_Round_Button *)group->child(0))->value() ) printout_black = PDF_COLOR;
3433 if ( ((Fl_Round_Button *)group->child(1))->value() )printout_black = PDF_BW;
3434 if ( ((Fl_Round_Button *)group->child(2))->value() ) printout_black = TEXT_ONLY;
3435 }
3436 
pdfps_options_dialog(SEA_VIEW * view,bool autonomous)3437 Fl_Window* pdfps_options_dialog(SEA_VIEW *view, bool autonomous)
3438 {
3439 static Fl_Window *pdf_form = NULL;
3440 static Fl_Input *sizeinput, *blockinput;
3441 static Fl_Choice *paper;
3442 static Fl_Round_Button *colorb, *blackb, *tob;
3443 static Fl_Check_Button *variable, *landscape;
3444 Fl_Button *ok;
3445 Fl_Group *radiog;
3446 int x, y, w, h;
3447 char txt[20];
3448 
3449 if(pdf_form == NULL) {
3450 fl_font(FL_HELVETICA, FL_NORMAL_SIZE);
3451 
3452 pdf_form = new Fl_Window(415, 90);
3453 pdf_form->box(FL_FLAT_BOX);
3454 pdf_form->label("Set " PDF_OR_PS " output options");
3455 
3456 x = 5 + (int)fl_width("block size:"); y = 5; w = 50; h = 25;
3457 sizeinput = new Fl_Input(x, y, w, h, "font size:");
3458 sizeinput->callback(printout_callback, &printout_fontsize);
3459 blockinput = new Fl_Input(x, y + sizeinput->h() + 5 , w, h, "block size:");
3460 blockinput->callback(printout_callback, &printout_block);
3461 paper = new Fl_Choice(x + sizeinput->w() + (int)fl_width("paper size:") + 15, y,
3462 	(int)fl_width("LETTER") + 30, h, "paper size:");
3463 paper->add("A4|LETTER");
3464 paper->callback(paper_callback);
3465 
3466   landscape = new Fl_Check_Button(paper->x(), paper->y() + 30, 20, 20, "landscape");
3467   landscape->callback(layout_callback);
3468   landscape->align(FL_ALIGN_LEFT);
3469 
3470 x = paper->x() + paper->w() + 5;
3471 radiog = new Fl_Group(x, y, (int)fl_width(PDF_OR_PS " color") + 25, 3 * h + 3);
3472 radiog->box(FL_DOWN_FRAME);
3473 colorb = new Fl_Round_Button(x, y, radiog->w(), h, PDF_OR_PS " color");
3474 blackb = new Fl_Round_Button(x, y + colorb->h() + 5, radiog->w(), h, PDF_OR_PS " B&&W");
3475 tob = new Fl_Round_Button(x, y + colorb->h() + blackb->h() + 5, radiog->w(), h, "Text File");
3476 colorb->callback(radio_callback);
3477 colorb->type(FL_RADIO_BUTTON);
3478 blackb->callback(radio_callback);
3479 blackb->type(FL_RADIO_BUTTON);
3480 tob->callback(radio_callback);
3481 tob->type(FL_RADIO_BUTTON);
3482 radiog->end();
3483 
3484 x = blockinput->x() + blockinput->w() + 5;
3485 variable = new Fl_Check_Button(x, blockinput->y() + blockinput->h(), (int)fl_width("Variable sites only") + 25, h, "Variable sites only");
3486 variable->box(FL_DOWN_FRAME);
3487 variable->callback(variable_callback);
3488 
3489 ok = new Fl_Button(radiog->x() + radiog->w() + 5, variable->y(), 25, h, "OK");
3490 ok->callback(ok_callback);
3491 
3492 pdf_form->end();
3493 pdf_form->size(ok->x() + ok->w() + 5 , pdf_form->h() );
3494 pdf_form->resizable(NULL);
3495 if (autonomous) pdf_form->set_modal();
3496 else {
3497   ok->hide();
3498   pdf_form->box(FL_DOWN_BOX);
3499   pdf_form->set_visible();
3500   }
3501 }
3502 
3503 sprintf(txt, "%d", printout_fontsize);
3504 sizeinput->value(txt);
3505 sprintf(txt, "%d", printout_block);
3506 blockinput->value(txt);
3507 paper->value(printout_pageformat == Fl_Paged_Device::A4 ? 0 : 1);
3508   landscape->value(printout_layout == Fl_Paged_Device::LANDSCAPE ? 1 : 0);
3509 if(printout_black == PDF_COLOR) colorb->setonly() ;
3510 else if(printout_black == PDF_BW) blackb->setonly() ;
3511 else  tob->setonly() ;
3512 variable->value(printout_vary);
3513 if(view->alt_col_rank != NULL && view->tot_sel_seqs == 1) variable->activate();
3514 else variable->deactivate();
3515 if (autonomous) pdf_form->show();
3516 return pdf_form;
3517 }
3518 #endif
3519 
3520 
3521 
3522 
hide_window_callback(Fl_Widget * ob,void * data)3523 void hide_window_callback(Fl_Widget *ob, void *data)
3524 {
3525 ob->window()->hide();
3526 }
3527 
3528 
free_colranks_by_difference(char ** alt_col_rank,int total)3529 void free_colranks_by_difference(char **alt_col_rank, int total)
3530 {
3531 int num;
3532 
3533 if(alt_col_rank == NULL) return;
3534 for(num = 0; num < total; num++) {
3535 	free(alt_col_rank[num]);
3536 	}
3537 if( total > 0 ) free(alt_col_rank);
3538 }
3539 
3540 
reference_toggle(SEA_VIEW * view,int on)3541 void reference_toggle(SEA_VIEW *view, int on)
3542 {
3543 char **tmp;
3544 static int old_pos;
3545 
3546 if(view->numb_gc == 1) return;
3547   Fl_Menu_Item *menu_props = (Fl_Menu_Item *)view->menu_props;
3548 props_menu_parts *props_parts = (props_menu_parts *)menu_props->user_data();
3549 if(on) { /* tenter de passer en mode par reference */
3550 	if( view->tot_sel_seqs != 1 || view->numb_gc == 1) {
3551 		(menu_props + props_parts->reference)->clear();
3552 		return;
3553 		}
3554 	my_watch_cursor(view->dnawin);
3555 	for(old_pos = 0; old_pos < view->tot_seqs; old_pos++)
3556 		if(view->sel_seqs[old_pos]) break;
3557 	deplacer_grp_seqs(view, 1);
3558 	set_seaview_modified(view, FALSE);
3559 	view->first_seq = 1;
3560 	view->vertsli->Fl_Slider::value(1);
3561 	view->alt_col_rank = prepcolranks_by_difference(view->sequence,
3562 		view->tot_seqs, 0,
3563 		view->max_seq_length,
3564 		view->each_length,
3565 		( view->protein ? get_color_for_aa : get_color_for_base ),
3566 		view->numb_gc, view->allow_lower);
3567 	fl_reset_cursor(view->dnawin);
3568 	if(view->alt_col_rank == NULL) {
3569 		view->DNA_obj->redraw();
3570 		(menu_props + props_parts->reference)->clear();
3571 		return;
3572 		}
3573 	tmp = view->alt_col_rank;
3574 	view->alt_col_rank = view->col_rank;
3575 	view->col_rank = tmp;
3576 	view->DNA_obj->redraw();
3577 	(menu_props + props_parts->colors - 1)->deactivate();
3578 	(menu_props + props_parts->reference)->set();
3579   ((Fl_Menu_Item*)view->menubar->find_item("Edit"))->deactivate();
3580   view->menu_species->bar_item()->deactivate();
3581   view->menubar->redraw();
3582 	}
3583 else	{ /* retour mode normal */
3584 	my_watch_cursor(view->dnawin);
3585 	tmp = view->alt_col_rank;
3586 	view->alt_col_rank = view->col_rank;
3587 	view->col_rank = tmp;
3588 	free_colranks_by_difference(view->alt_col_rank, view->tot_seqs);
3589 	view->alt_col_rank = NULL;
3590 	deplacer_grp_seqs(view, old_pos + 1);
3591 	set_seaview_modified(view, FALSE);
3592 	view->DNA_obj->redraw();
3593 	(menu_props + props_parts->colors - 1)->activate();
3594 	(menu_props + props_parts->reference)->clear();
3595   ((Fl_Menu_Item*)view->menubar->find_item("Edit"))->activate();
3596   view->menu_species->bar_item()->activate();
3597   view->menubar->redraw();
3598 	fl_reset_cursor(view->dnawin);
3599 	}
3600 }
3601 
3602 
3603 static Fl_Help_Dialog *help_viewer = NULL;
help_callback(Fl_Widget * ob,void * unused)3604 void help_callback(Fl_Widget *ob, void *unused)
3605 {
3606 	if(help_viewer == NULL) {
3607 		char *help_file;
3608 #ifndef DEFAULT_HELPFILE   /* to ease FreeBSD port */
3609 #define DEFAULT_HELPFILE "seaview.html"
3610 #endif
3611 		help_file = get_res_value("helpfile", DEFAULT_HELPFILE);
3612 		help_file = get_full_path(help_file);
3613 		if(help_file == NULL) {
3614 			fl_alert(
3615 #ifdef __APPLE__
3616 					 "No help information in program resources"
3617 #else
3618 					 "Help file %s\nnot found in PATH directories nor in current directory", help_file
3619 #endif
3620 					 );
3621 			return;
3622 		}
3623 		my_watch_cursor(ob->window());
3624 		help_viewer = new Fl_Help_Dialog();
3625 		if(help_viewer == NULL) return;
3626 #ifdef MICRO
3627 		help_viewer->resize(help_viewer->x(), help_viewer->y(), 700, 600);
3628 		help_viewer->textsize(14);
3629 #else
3630 		help_viewer->resize(help_viewer->x(), help_viewer->y(), 740, 500);
3631 		help_viewer->textsize(12);
3632 #endif
3633 		help_viewer->load(help_file);
3634 		help_viewer->show();
3635 		fl_reset_cursor(ob->window());
3636 #ifndef MICRO
3637 		//for X11 control where the window appears, useful if multiple screens
3638 		Fl_Window *w = Fl::first_window();// gives the help_viewer window
3639 		if(w) w->hotspot(w);//so the window is close to the mouse
3640 #endif
3641 		}
3642 	else help_viewer->show();
3643 }
3644 
3645 
direct_help_callback(Fl_Widget * wgt,void * data)3646 void direct_help_callback(Fl_Widget *wgt, void *data)
3647 {
3648 	help_callback(wgt, NULL);
3649 	if(help_viewer != NULL) help_viewer->topline((char *)data);
3650 }
3651 
3652 
insert_gaps_at(SEA_VIEW * view,int seq,int site,int total)3653 int insert_gaps_at(SEA_VIEW *view, int seq, int site, int total)
3654 {
3655 char *pos, **psequence;
3656 int l, gapcolor, *plength;
3657 if(view->cursor_in_comment) {
3658 	psequence = view->comment_line;
3659 	plength = view->comment_length;
3660 	}
3661 else {
3662 	psequence = view->sequence;
3663 	plength = view->each_length;
3664 	if (view->col_rank) gapcolor = ( view->protein ?
3665 		get_color_for_aa('-') : get_color_for_base('-') );
3666 	}
3667 l = plength[seq-1];
3668 if(site > l + 1) return total;
3669 if( l + total > view->max_seq_length) total = view->max_seq_length - l;
3670 pos = psequence[seq-1] + site - 1;
3671 memmove(pos+total, pos, l - site + 2);
3672 memset(pos, '-', total);
3673 if( (!view->cursor_in_comment) && view->col_rank) {
3674 	pos = view->col_rank[seq-1] + site - 1;
3675 	memmove(pos+total, pos, l - site + 1);
3676 	memset(pos, gapcolor, total);
3677 	}
3678 plength[seq-1] += total;
3679 if( (!view->cursor_in_comment) && view->curr_colors == view->codoncolors && view->col_rank) {
3680 	char **tmp = prepcolranks_by_codon(&view->sequence[seq-1], 1, view->max_seq_length, &view->each_length[seq-1],
3681 									   &view->comments[seq-1]);
3682 	free(view->col_rank[seq-1]);
3683 	view->col_rank[seq-1] = tmp[0];
3684 	free(tmp);
3685 	}
3686 if (view->col_rank) set_seaview_modified(view, TRUE);
3687 return total;
3688 }
3689 
3690 
delete_gaps_before(SEA_VIEW * view,int numseq,int numsite,int total)3691 int delete_gaps_before(SEA_VIEW *view, int numseq, int numsite, int total)
3692 {
3693 char *site, *finseq, **psequence;
3694 int count = -1, l, retval, *plength;
3695 
3696 psequence = view->sequence;
3697 plength = view->each_length;
3698 site = psequence[numseq-1] + numsite - 1;
3699 finseq = psequence[numseq-1] + plength[numseq-1] - 1;
3700 do	{ site--; count++; }
3701 while ( count < total && site >= psequence[numseq-1] &&
3702 	( view->allow_seq_edit || *site == '-' || site > finseq) );
3703 if(count == 0) return 0;
3704 /* ne rien faire si on efface au dela de la fin de la seq */
3705 if(numsite - count > plength[numseq-1]) return count;
3706 l = plength[numseq-1];
3707 retval = count;
3708 if(numsite > l) { /* effacer depuis au dela fin jusqu'a interieur seq */
3709 	count -= (numsite - l - 1);
3710 	numsite = l + 1;
3711 	}
3712 site = psequence[numseq-1] + numsite - 1;
3713 memmove(site-count, site, l - numsite + 2);
3714 if( view->numb_gc > 1) {
3715 		site= view->col_rank[numseq-1] + numsite - 1;
3716 		memmove(site - count, site, l - numsite + 1);
3717 	}
3718 plength[numseq-1] -= count;
3719 if ( view->curr_colors == view->codoncolors && view->col_rank) {
3720 	char **tmp = prepcolranks_by_codon(&view->sequence[numseq-1], 1, view->max_seq_length,
3721 									   &view->each_length[numseq-1], &view->comments[numseq-1]);
3722 	free(view->col_rank[numseq-1]);
3723 	view->col_rank[numseq-1] = tmp[0];
3724 	free(tmp);
3725 	}
3726 if (view->col_rank) set_seaview_modified(view, TRUE);
3727 return retval;
3728 }
3729 
3730 
adjust_menu_edit_modes(SEA_VIEW * view)3731 void adjust_menu_edit_modes(SEA_VIEW *view)
3732 {
3733 if(view->menu_edit != NULL) {
3734 	Fl_Menu_Item *items = (Fl_Menu_Item *)view->menu_edit;
3735   Fl_Menu_Item *align_items = (Fl_Menu_Item *)view->menu_align;
3736 	if(view->tot_sel_seqs != 0) {
3737 		items[DELETE_SEQ].activate();
3738 		items[COPY_SEQS].activate();
3739 		align_items[PROFILE].activate();
3740 		align_items[UNALIGN].activate();
3741 	  ((Fl_Menu_Item*)view->menu_file)[SAVE_REGIONS].activate();
3742 		if(view->protein) items[EXCHANGE_UT].deactivate();
3743 		else items[EXCHANGE_UT].activate();
3744 		}
3745 	else	{
3746 		items[DELETE_SEQ].deactivate();
3747 		items[EXCHANGE_UT].deactivate();
3748 		items[COPY_SEQS].deactivate();
3749 		align_items[PROFILE].deactivate();
3750 		align_items[UNALIGN].deactivate();
3751 	  if (view->active_region == NULL) ((Fl_Menu_Item*)view->menu_file)[SAVE_REGIONS].deactivate();
3752 		}
3753 	if(view->tot_sel_seqs != 0 && ! view->protein) items[SET_GCODE].activate();
3754 	else items[SET_GCODE].deactivate();
3755   Fl_Menu_Item *menu_props = (Fl_Menu_Item *)view->menu_props;
3756 	props_menu_parts *props_parts = (props_menu_parts *)menu_props->user_data();
3757 	Fl_Menu_Item *byref = menu_props + props_parts->reference;
3758 	if(view->tot_sel_seqs == 1 && view->curr_colors != view->codoncolors) byref->activate();
3759 	else byref->deactivate();
3760 	if(view->tot_sel_seqs == 1) {
3761 		items[RENAME_SEQ].activate();
3762 		if(view->viewasprots == NULL) items[DUPLICATE_SEQ].activate();
3763 		items[EDIT_COMMENTS].activate();
3764 		if(view->viewasprots == NULL) items[EDIT_SEQ].activate();
3765 		if(view->protein) {
3766 			items[COMPLEMENT_SEQ].deactivate();
3767 			items[REVERSE_SEQ].deactivate();
3768 			}
3769 		else if(view->viewasprots == NULL) {
3770 			items[COMPLEMENT_SEQ].activate();
3771 			items[REVERSE_SEQ].activate();
3772 			}
3773 		}
3774 	else	{
3775 		items[RENAME_SEQ].deactivate();
3776 		items[DUPLICATE_SEQ].deactivate();
3777 		items[EDIT_COMMENTS].deactivate();
3778 		items[EDIT_SEQ].deactivate();
3779 		items[COMPLEMENT_SEQ].deactivate();
3780 		items[REVERSE_SEQ].deactivate();
3781 		}
3782 	if(view->tot_sel_seqs == 2)
3783 		items[DOT_PLOT].activate();
3784 	else
3785 		items[DOT_PLOT].deactivate();
3786 	if(view->tot_sel_seqs >= 2) {
3787 		align_items[ALIGN_SELECTED_SEQS].activate();
3788 		align_items[ALIGN_SITES].activate();
3789 		if(view->viewasprots == NULL) items[CONSENSUS_SEQ].activate();
3790 		}
3791 	else	{
3792 		align_items[ALIGN_SELECTED_SEQS].deactivate();
3793 		align_items[ALIGN_SITES].deactivate();
3794 		items[CONSENSUS_SEQ].deactivate();
3795 		}
3796 	}
3797 }
3798 
3799 
select_deselect_seq(SEA_VIEW * view,int new_seq,int from_tree)3800 void select_deselect_seq(SEA_VIEW *view, int new_seq, int from_tree)
3801 {
3802 /* new_seq = # seq a select/deselect; si 0: tout deselectionner;
3803    si -1: tout selectionner
3804    si -2: ne pas changer la selection mais ajuster l'interface selon son etat
3805 */
3806 if(new_seq > 0) { /* traiter une sequence */
3807 	view->sel_seqs[new_seq-1] = !view->sel_seqs[new_seq-1];
3808 	if(view->sel_seqs[new_seq-1])
3809 		++view->tot_sel_seqs;
3810 	else
3811 		--view->tot_sel_seqs;
3812 	}
3813 else if(new_seq == 0)	{ /* tout deselectionner */
3814 	view->tot_sel_seqs = 0;
3815 	memset(view->sel_seqs, 0, view->tot_seqs * sizeof(int));
3816 	}
3817 else if(new_seq == -1)	{ /* tout selectionner */
3818 	int i;
3819 	view->tot_sel_seqs = view->tot_seqs;
3820 	for(i=0; i < view->tot_seqs; i++) view->sel_seqs[i] = TRUE;
3821 	}
3822 adjust_menu_edit_modes(view);
3823 if(view->menu_species != NULL) {
3824 	Fl_Menu_Item *items = (Fl_Menu_Item *)view->menu_species->get_menu();
3825 	if(items != NULL) {
3826 		if(view->tot_sel_seqs == 0)
3827 			items[0].deactivate();
3828 		else
3829 			items[0].activate();
3830 		items[1].deactivate();
3831 		view->menu_species->value(0);
3832 		}
3833 	}
3834   if (!from_tree) {
3835     select_deselect_in_tree(view);
3836     }
3837 }
3838 
3839 
deplacer_grp_seqs(SEA_VIEW * view,int target)3840 void deplacer_grp_seqs(SEA_VIEW *view, int target)
3841 {
3842 /* deplacer toutes les seqs selectionnees pour positionner la premiere
3843 d'entre elles en position target */
3844 int *new_rank, *old_rank, old, new_val, numset;
3845 char **aux;
3846 -- target;
3847 new_rank = (int *)malloc(view->tot_seqs * sizeof(int));
3848 old_rank = (int *)malloc(view->tot_seqs * sizeof(int));
3849 aux = (char **)malloc( view->tot_seqs * sizeof(char *) );
3850 if(new_rank == NULL || old_rank == NULL || aux == NULL) out_of_memory();
3851 /* compute old_rank[new_val] = old */
3852 new_val = -1;
3853 /* place first all non selected seqs */
3854 for(old = 0; old < view->tot_seqs; old++) {
3855 	if(!view->sel_seqs[old]) old_rank[++new_val] = old;
3856 	}
3857 /* allocate room for selected seqs */
3858 if(target + view->tot_sel_seqs > view->tot_seqs)
3859 	target = view->tot_seqs - view->tot_sel_seqs;
3860 old = view->tot_seqs - view->tot_sel_seqs - target;
3861 if(old != 0)
3862 	memmove(old_rank + target + view->tot_sel_seqs, old_rank + target,
3863 		old * sizeof(int));
3864 /* insert selected seqs */
3865 for(old = 0; old < view->tot_seqs; old++)
3866 	if(view->sel_seqs[old]) old_rank[target++] = old;
3867 /* compute new_rank[old] = new_val */
3868 for(new_val = 0; new_val < view->tot_seqs; new_val++)
3869 	new_rank[old_rank[new_val]] = new_val;
3870 /* displace all sequence order-dependent ingredients */
3871 /* deplacer la position du curseur */
3872 if(!view->cursor_in_comment) {
3873 	view->cursor_seq = new_rank[view->cursor_seq - 1] + 1;
3874 	view->old_cursor_seq = view->cursor_seq;
3875 	}
3876 /* deplacer les seqs */
3877 for(old = 0; old < view->tot_seqs; old++)
3878 	aux[new_rank[old]] = view->sequence[old];
3879 memcpy(view->sequence, aux, view->tot_seqs * sizeof(char *) );
3880 /* deplacer les noms */
3881 for(old = 0; old < view->tot_seqs; old++)
3882 	aux[new_rank[old]] = view->seqname[old];
3883 memcpy(view->seqname, aux, view->tot_seqs * sizeof(char *) );
3884 if(view->comments != NULL) {
3885 	/* deplacer les commentaires */
3886 	for(old = 0; old < view->tot_seqs; old++)
3887 		aux[new_rank[old]] = view->comments[old];
3888 	memcpy(view->comments, aux, view->tot_seqs * sizeof(char *) );
3889 	}
3890 if(view->viewasprots != NULL) {
3891 	/* deplacer les DNA seqs conservees pour mode vision traduction */
3892 	char **viewasprots = (char **)view->viewasprots;
3893 	for(old = 0; old < view->tot_seqs; old++)
3894 		aux[new_rank[old]] = viewasprots[old];
3895 	memcpy(viewasprots, aux, view->tot_seqs * sizeof(char *) );
3896 	}
3897 /* deplacer les seqs en couleurs */
3898 if(view->numb_gc > 1) {
3899 	for(old = 0; old < view->tot_seqs; old++) aux[new_rank[old]] = view->col_rank[old];
3900 	memcpy(view->col_rank, aux, view->tot_seqs * sizeof(char *) );
3901 	}
3902 /* deplacer les sequences selectionnees */
3903 for(old = 0; old < view->tot_seqs; old++)
3904 	old_rank[new_rank[old]] = view->sel_seqs[old];
3905 memcpy(view->sel_seqs, old_rank, view->tot_seqs * sizeof(int) );
3906 /* deplacer les longueurs de sequences */
3907 for(old = 0; old < view->tot_seqs; old++)
3908 	old_rank[new_rank[old]] = view->each_length[old];
3909 memcpy(view->each_length, old_rank, view->tot_seqs * sizeof(int) );
3910 /* process species sets */
3911 for(numset = 0; numset < view->numb_species_sets; numset++) {
3912 	for(old = 0; old < view->tot_seqs; old++)
3913 		old_rank[new_rank[old]] = view->list_species_sets[numset][old];
3914 	memcpy(view->list_species_sets[numset], old_rank,
3915 		view->tot_seqs * sizeof(int) );
3916 	}
3917 free(aux); free(old_rank); free(new_rank);
3918 set_seaview_modified(view, TRUE);
3919 }
3920 
3921 
update_current_seq_length(int newlength,SEA_VIEW * view)3922 void update_current_seq_length(int newlength, SEA_VIEW *view)
3923 {
3924 double x; int l;
3925 if(newlength > view->seq_length) {
3926 	view->seq_length =
3927 		( newlength+20 < view->max_seq_length ?
3928 		newlength+20 : view->max_seq_length );
3929 	l = view->seq_length - view->tot_sites+3;
3930 	if(l<1) l=1;
3931 	view->horsli->bounds(1,l);
3932 	x = ( (double) view->tot_sites ) /
3933 		( view->seq_length + 3 ) ;
3934 	if(x>1) x=1;
3935 	view->horsli->slider_size(x);
3936 	}
3937 }
3938 
3939 
insert_char_in_seq(int key,int total,SEA_VIEW * view)3940 int insert_char_in_seq( int key, int total, SEA_VIEW *view)
3941 /* to insert the typed key in the sequence at cursor location if it is visible
3942 returns # of inserted chars if ok, 0 if error (= cursor not visible or
3943 max seq size is reached)
3944 */
3945 {
3946 char *pos;
3947 int l, c, *plength;
3948 if(view->cursor_in_comment) {
3949 	if( view->cursor_seq < 1 ||
3950 	   view->cursor_seq >= view->tot_comment_lines ||
3951 	   view->cursor_site < view->first_site ||
3952 	   view->cursor_site >= view->first_site + view->tot_sites ) return 0;
3953 	l = view->comment_length[view->cursor_seq - 1];
3954 	}
3955 else	{
3956 	if( view->cursor_seq < view->first_seq ||
3957 	   view->cursor_seq >=view->first_seq+view->tot_lines ||
3958 	   view->cursor_site < view->first_site ||
3959 	   view->cursor_site >= view->first_site + view->tot_sites ) return 0;
3960 	l = view->each_length[view->cursor_seq-1];
3961 	}
3962 if(view->cursor_site > l + 1) return 0;
3963 if( l + total > view->max_seq_length) total = view->max_seq_length - l;
3964 if(total <= 0) return 0;
3965 if(view->cursor_in_comment)
3966 	pos = view->comment_line[view->cursor_seq - 1] + view->cursor_site - 1;
3967 else
3968 	pos = view->sequence[view->cursor_seq - 1] + view->cursor_site - 1;
3969 memmove(pos+total, pos, l - view->cursor_site + 2);
3970 memset(pos, view->cursor_in_comment || view->allow_lower ? key : toupper(key) ,
3971 	 total);
3972 if( (!view->cursor_in_comment) && view->numb_gc > 1) {
3973 	   pos= &view->col_rank[view->cursor_seq-1][view->cursor_site-1];
3974 	   memmove(pos+total, pos, l - view->cursor_site + 1);
3975 	c = (view->protein ? get_color_for_aa(key) : get_color_for_base(key) );
3976 	memset(view->col_rank[view->cursor_seq-1] + view->cursor_site - 1,
3977 		c, total);
3978 	}
3979 if(view->cursor_in_comment)
3980 	plength = &(view->comment_length[view->cursor_seq-1]);
3981 else
3982 	plength = &(view->each_length[view->cursor_seq-1]);
3983 (*plength) += total;
3984 update_current_seq_length(*plength, view);
3985 if( (!view->cursor_in_comment) && view->curr_colors == view->codoncolors) {
3986 	char **tmp = prepcolranks_by_codon(&view->sequence[view->cursor_seq-1], 1, view->max_seq_length,
3987 								&view->each_length[view->cursor_seq-1], &view->comments[view->cursor_seq-1]);
3988 	free(view->col_rank[view->cursor_seq-1]);
3989 	view->col_rank[view->cursor_seq-1] = tmp[0];
3990 	free(tmp);
3991 	}
3992 set_seaview_modified(view, TRUE);
3993 return total;
3994 }
3995 
3996 /*  The routine that does drawing */
draw(void)3997 void DNA_obj::draw(void)
3998 {
3999 SEA_VIEW *view = (SEA_VIEW *)this->user_data();
4000 if(view == NULL) return; //this is necessary after deletion of an alignment window
4001 
4002 #if (100*FL_MAJOR_VERSION + FL_MINOR_VERSION >= 104) && !defined(__APPLE__)
4003   if (view->scale != fl_graphics_driver->scale()) {
4004     view->scale = fl_graphics_driver->scale();
4005     fl_font(view->DNA_obj->labelfont(), view->DNA_obj->labelsize());
4006     view->char_width = fl_width('W');
4007   }
4008 #endif
4009 
4010 /* returns TRUE if window size was changed by user */
4011 if( compute_size_params( view, FALSE) ) {
4012 	view->horsli->redraw();
4013 	view->vertsli->redraw();
4014 	}
4015 if( ( this->damage() & FL_DAMAGE_ALL ) != 0 ) {
4016 // appel autre que uniquement par damage partiel
4017 	view->draw_names = -1;
4018 	view->mod_cursor = view->mod_region_line = view->mod_comment_line =
4019 		FALSE;
4020 	view->mod_seq = 0;
4021 	}
4022 if(view->draw_names) { /* soit tous (<= -1) soit un seul ( >= 1) */
4023 	draw_seq_names(view->DNA_obj, view);
4024 	if(view->draw_names > 0 || view->draw_names == -2){
4025 		/* si > 0 ou -2, ne pas ecrire les seqs*/
4026 		view->draw_names = -1;
4027 		return;
4028 		}
4029 	}
4030 if(view->mod_cursor) {
4031 	/* effacer old_cursor en ecrivant dessus */
4032 	draw_cursor(view->DNA_obj, FALSE, view->old_cursor_site,
4033 		view->old_cursor_seq, view->old_cursor_in_comment);
4034 	view->mod_cursor = FALSE;
4035 	}
4036 else if(view->mod_region_line) {
4037 	draw_region_line(view->DNA_obj, view);
4038 	view->mod_region_line = FALSE;
4039 	}
4040 else if(view->mod_comment_line) {
4041 	draw_comment_lines(view->DNA_obj, view);
4042 	view->mod_comment_line = FALSE;
4043 	}
4044 else	{
4045 	if(view->tot_seqs == 0) {
4046 #define DRAG_MESS "alignment/tree file drop zone"
4047 		fl_color(FL_WHITE);
4048 		fl_font(FL_TIMES_BOLD_ITALIC, 28 );
4049 		fl_draw(DRAG_MESS, (int)(this->x()+this->w()/2-fl_width(DRAG_MESS)/2 + 0.5), this->y()+this->h()/2);
4050 		}
4051 	if(view->inverted_colors)
4052 		    draw_dna_seqs_inverted(view->DNA_obj, view);
4053 	else
4054 		    draw_dna_seqs(view->DNA_obj, view);
4055 	draw_comment_lines(view->DNA_obj, view);
4056 	}
4057 view->mod_seq = 0;
4058 view->draw_names = -1;
4059 draw_cursor(view->DNA_obj, TRUE , view->cursor_site, view->cursor_seq,
4060 	view->cursor_in_comment);
4061 view->old_cursor_seq = view->cursor_seq;
4062 view->old_cursor_site = view->cursor_site;
4063 view->old_cursor_in_comment = view->cursor_in_comment;
4064 }
4065 
4066 
my_event_button(void)4067 int my_event_button(void)
4068 /* returns mouse button number 1=left, 2=centre, 3=right.
4069 on Mac or Win32, extra buttons can also be emulated by modifier keys (shift for right, ctrl for middle)
4070 Also returns 4 for cmd-Click (Mac) alt-Click (win32) meta-Click (X11)
4071 */
4072 {
4073 #ifdef __APPLE__
4074 #define EXTRA_MODIF_KEY FL_META
4075 #elif defined(WIN32)
4076 #define EXTRA_MODIF_KEY FL_ALT
4077 #else
4078 #define EXTRA_MODIF_KEY FL_META
4079 #endif
4080 int key;
4081 
4082 key = Fl::event_button();  /* key: 1=gauche, 2=centre, 3=droit souris */
4083 if(key == 1) {//emulate mouse buttons by modifiers
4084 	if(Fl::event_state(FL_CTRL)) key = 2;// bouton du milieu par Ctrl-Click
4085 	else if(Fl::event_state(FL_SHIFT)) key = 3;// bouton  droit par Shift-Click
4086 	}
4087 if(Fl::event_state(EXTRA_MODIF_KEY)) key = 4;// cmd-Click (Mac) alt-Click (win32) meta-Click (X11)
4088 return key;
4089 }
4090 
4091 
4092 
handle(int event)4093 int DNA_obj::handle(int event)
4094 {
4095   SEA_VIEW *view;
4096   /* numero courant de la derniere seq selectionnee pendant selection de seqs
4097    par glissement de la souris
4098    */
4099   static int selecting_seqs = 0, sel_seq_move = 0;
4100   static int modifying_segment = 0;
4101   int mx = Fl::event_x();
4102   int my = Fl::event_y();
4103   static int doing_dnd = FALSE;
4104 
4105   view = (SEA_VIEW *) ( this->user_data() );
4106   if(view == NULL) return 1;
4107   switch (event)
4108   {
4109     case FL_DND_ENTER:
4110       return view->tot_seqs == 0;
4111     case FL_DND_DRAG:
4112       return view->tot_seqs == 0;
4113     case FL_DND_RELEASE:
4114    	 	if(view->tot_seqs == 0) {
4115         doing_dnd = TRUE;
4116         return 1;
4117       }
4118       else return 0;
4119     case FL_PASTE:
4120       char *p;
4121       p = (char*)Fl::event_text();
4122 #if ! ( defined(__APPLE__) || defined(WIN32) )
4123       if(doing_dnd) {
4124         char *q;
4125         if(strncmp(p, "file://", 7) == 0) p += 7;
4126         if((q = strchr(p, '\r')) != NULL) *q = 0;
4127         if((q = strchr(p, '\n')) != NULL) *q = 0;
4128         fl_decode_uri(p);
4129       }
4130 #endif
4131       handle_paste(view, p, doing_dnd);
4132       doing_dnd = FALSE;
4133       Fl::focus(this);
4134       return 1;
4135     case FL_FOCUS:
4136     case FL_UNFOCUS:
4137       return 1;
4138     case FL_PUSH:
4139       int key;
4140       key = my_event_button();
4141       if( key == 1 && Fl::event_clicks() ) { /* left double click */
4142         int new_seq;
4143         Fl::event_clicks(0);
4144         new_seq = (my + view->line_height/2 -
4145                    view->y_seq)/view->line_height + view->first_seq;
4146         if( new_seq < view->first_seq || new_seq > view->tot_seqs ||
4147            new_seq >= view->first_seq + view->tot_lines ) break;
4148         if(mx < view->x_name || mx >= view->x_seq - view->char_width ||
4149            key != 1) break;
4150         /* double click sur nom de seq: selection de toutes les seqs */
4151         /*		if(view->alt_col_rank != NULL) break;
4152          if(view->multipl->argument() > 0) mod_multipl(view,0);
4153          select_deselect_seq(view, -1);
4154          selecting_seqs = 0;
4155          view->draw_names = -2;
4156          // ceci signifie redraw partiel commande' par draw_names, mod_cursor, ...
4157          this->damage(1); */
4158       }
4159       else	{ /* simple click */
4160         Fl::focus(this);
4161         handle_push(view, mx, my, key, &modifying_segment,
4162                     &selecting_seqs, &sel_seq_move);
4163       }
4164       break;
4165     case FL_DRAG: /* mouvement avec souris enfoncee */
4166       handle_mouse(view, mx, my, &selecting_seqs, &sel_seq_move,
4167                    &modifying_segment);
4168       break;
4169     case FL_RELEASE:
4170       //     case FL_LEAVE:
4171       if(selecting_seqs) {
4172         if(sel_seq_move) {
4173           select_deselect_seq(view, sel_seq_move);
4174           view->draw_names = sel_seq_move;
4175           this->damage(1);
4176         }
4177         else
4178           select_deselect_seq(view, -2);
4179         selecting_seqs = 0;
4180       }
4181       else if(modifying_segment) {
4182         end_change_segment(view);
4183         view->draw_names = 0;
4184         this->damage(1);
4185         modifying_segment = 0;
4186       }
4187       break;
4188     case FL_KEYBOARD:
4189       if( Fl::event_state(FL_CTRL) || Fl::event_state(FL_META)) {
4190         return 0; /* ne pas traiter ici car shortcut d'autres widgets */
4191       }
4192       key = Fl::event_key();
4193       if(key == FL_Delete || key == FL_BackSpace ||
4194          key == FL_Right || key == FL_Left || key == FL_Up || key == FL_Down  ||
4195          key == FL_Page_Up || key == FL_Page_Down) {
4196         handle_keyboard(view, key, FALSE );
4197         return 1;
4198       }
4199       if(Fl::event_length() > 0) { // du vrai texte
4200         handle_keyboard(view, Fl::event_text()[0], TRUE );
4201       }
4202       break;
4203     default :
4204       return 0;
4205   }
4206   return 1;
4207 }
4208 
4209 
handle_paste(SEA_VIEW * view,char * clipboard,int doing_dnd)4210 void handle_paste(SEA_VIEW *view, char *clipboard, int doing_dnd)
4211 {
4212   if (doing_dnd) {
4213     use_initial_file(view, clipboard, doing_dnd);
4214     return;
4215   }
4216 
4217   char **seqs, **seqnames, **comments, *p, *message;
4218   int count, i, num, changedwname = FALSE;
4219   if (pasted_from_what_source == 1 || memcmp(clipboard, CLIPBOARDMARK, strlen(CLIPBOARDMARK)) ) {
4220     if (pasted_from_what_source == 0) {
4221       pasted_from_what_source = 1; // try to paste from clipboard that may contain fasta data
4222       Fl::paste(*(view->DNA_obj), 1);
4223       return;
4224     }
4225     if (*clipboard != '>') return;
4226     char *header, *err_message;
4227     char *fname = create_tmp_filename();
4228     FILE *out = fopen(fname, "w");
4229     fputs(clipboard, out);
4230     fclose(out);
4231     count = read_fasta_align(fname, &seqs, &seqnames, &comments, &header, &err_message, false);
4232     delete_tmp_filename(fname);
4233     if (count) { // caution here: fl_choice may change Fl::e_text which may be reused after return
4234       char *save = Fl::e_text;
4235       int savel = Fl::e_length;
4236       Fl::e_text = NULL;
4237       i = fl_choice("You are about to add to this alignment %d sequence%s (%s) \n"
4238 		    "present in the clipboard.", "Cancel", "Confirm",
4239 		    NULL, count, (count > 1 ? "s" : ""), seqnames[0]);
4240       Fl::e_text = save;
4241       Fl::e_length = savel;
4242       if (!i) return;
4243     }
4244   }
4245   else {
4246     p = (char*)strchr(clipboard, ':') + 1;
4247     count = read_mase_seqs_header(p, &seqs, &seqnames, &comments, NULL, &message);
4248   }
4249   if (count == 0) return;
4250   if (view->tot_seqs == 0 && view->masename == NULL) {
4251 	  view->masename = strdup("newfile");
4252 	  changedwname = TRUE;
4253 	  }
4254   for (i = 0; i < count; i++) {
4255 	  num = add_seq_to_align(view, seqnames[i], seqs[i], strlen(seqs[i]));
4256 	  if(num != 0) view->comments[view->tot_seqs - 1] = comments[i];
4257 	  }
4258   if (changedwname) {
4259 #if defined(__APPLE__) && 100*FL_MAJOR_VERSION + FL_MINOR_VERSION < 104
4260     rename_windowmenuitem(view->dnawin->label(), find_windowmenuitem(view->dnawin));
4261 #endif
4262     ((Fl_Menu_Item*)view->menu_file)[SAVE].deactivate();
4263   }
4264 }
4265 
4266 
handle_mouse(SEA_VIEW * view,int mx,int my,int * p_selecting_seqs,int * p_sel_seq_move,int * p_modifying_segment)4267 void handle_mouse(SEA_VIEW *view, int mx, int my,
4268 	int *p_selecting_seqs, int *p_sel_seq_move, int *p_modifying_segment)
4269 { /* mouvement avec souris enfoncee */
4270 int debut, fin, step, num, new_seq, new_site;
4271 
4272 if(*p_selecting_seqs != 0) {
4273 	new_seq = (my + view->line_height/2 -
4274 		view->y_seq)/view->line_height + view->first_seq;
4275 	if(new_seq == *p_selecting_seqs) return;
4276 	if( new_seq < view->first_seq || new_seq > view->tot_seqs ||
4277 		new_seq >= view->first_seq + view->tot_lines ) return;
4278 	if(!view->sel_seqs[new_seq - 1])
4279 		{ debut= new_seq; fin = *p_selecting_seqs; }
4280 	else
4281 		{ debut= *p_selecting_seqs; fin = new_seq; }
4282 	if(debut < fin) step = 1;
4283 	else	step = -1;
4284 	*p_selecting_seqs = new_seq;
4285 	for(num = debut; num != fin; num += step) {
4286 		new_seq = debut + fin - step - num - 1;
4287 		if(view->sel_seqs[new_seq]) {
4288 			view->sel_seqs[new_seq] = FALSE;
4289 			--(view->tot_sel_seqs);
4290 			}
4291 		else	{
4292 			view->sel_seqs[new_seq] = TRUE;
4293 			++(view->tot_sel_seqs);
4294 			}
4295 		if(*p_sel_seq_move == new_seq + 1) *p_sel_seq_move = 0;
4296 		}
4297 	if(*p_sel_seq_move) {
4298 		if( view->sel_seqs[*p_sel_seq_move - 1] ) {
4299 			view->sel_seqs[*p_sel_seq_move - 1] = FALSE;
4300 			--(view->tot_sel_seqs);
4301 			}
4302 		else	{
4303 			view->sel_seqs[*p_sel_seq_move - 1] = TRUE;
4304 			++(view->tot_sel_seqs);
4305 			}
4306 		*p_sel_seq_move = 0;
4307 		}
4308 	view->draw_names = -2;
4309 	view->DNA_obj->damage(1);
4310 	}
4311 else if(*p_modifying_segment != 0) {
4312 	new_site = (mx - view->x_seq )/view->char_width +
4313 		view->first_site;
4314 	if(new_site == *p_modifying_segment) return;
4315 	if( new_site < view->first_site ||
4316 		new_site > view->first_site + view->tot_sites ||
4317 		new_site > view->region_length ) return;
4318 	if( continue_change_segment(view, new_site) ) {
4319 		*p_modifying_segment = new_site;
4320 		view->draw_names = 0;
4321 		view->mod_region_line = TRUE;
4322 		view->DNA_obj->damage(1);
4323 		}
4324 	}
4325 }
4326 
4327 
handle_push(SEA_VIEW * view,int mx,int my,int key,int * p_modifying_segment,int * p_selecting_seqs,int * p_sel_seq_move)4328 void handle_push(SEA_VIEW *view, int mx, int my, int key,
4329 	int *p_modifying_segment, int *p_selecting_seqs, int *p_sel_seq_move)
4330 /* key: 1=bouton gauche, 2=centre, 3=droit de la souris */
4331 {
4332 int new_site, new_seq, new_line;
4333 
4334 if(view->multipl->argument() > 0) mod_multipl(view,0);
4335 new_seq = (my + view->line_height/2 - view->y_seq)/view->line_height +
4336 	view->first_seq;
4337 new_line = new_seq - view->first_seq + 1;
4338 new_site = (mx - view->x_seq )/view->char_width +
4339 	view->first_site;
4340 if(view->active_region != NULL &&
4341   new_seq == view->first_seq + FL_min(view->tot_lines,view->tot_seqs) &&
4342 	new_site >= view->first_site &&
4343 	new_site < view->first_site + view->tot_sites &&
4344 	new_site <= view->region_length ) {
4345 /* work with segments: extend, or create, or delete */
4346 	if(key == 2) { /* middle button:extend left neighbor segment */
4347 		new_seq = extend_segment_at_left(view, new_site);
4348 		if(new_seq) fl_beep(FL_BEEP_DEFAULT);
4349 		else	{
4350 			view->draw_names = 0;
4351 			}
4352 		}
4353 	else if(key == 3) { /* right button=>delete segment */
4354 		new_seq = suppr_segment(view->active_region, new_site,
4355 			view->region_line);
4356 		if(new_seq) fl_beep(FL_BEEP_DEFAULT);
4357 		else	{
4358 			view->draw_names = 0;
4359 			}
4360 		}
4361 	else	{ /* left button=>extend or create segment */
4362 		new_seq = begin_change_segment(view, new_site);
4363 		if(new_seq) {
4364 			view->mod_region_line = TRUE;
4365 			*p_modifying_segment = new_site;
4366 			}
4367 		view->draw_names = 0;
4368 		}
4369 	if(view->draw_names == 0) {
4370 		view->DNA_obj->damage(1);
4371 		}
4372 	return;
4373 	}
4374 if( view->show_comment_lines && new_line >= view->pos_first_comment_line &&
4375 	new_line < view->pos_first_comment_line + view->tot_comment_lines ) {
4376 /* dans les comment lines */
4377 	int num, old;
4378 	if(key != 1) return;
4379 	num = new_line - view->pos_first_comment_line + 1;
4380 	if(mx >= view->x_name && mx < view->x_seq - view->char_width) {
4381 	/* click sur nom de comment line: selection/deselection */
4382 		old = view->active_comment_line;
4383 		if(old == num)
4384 			view->active_comment_line = 0;
4385 		else
4386 			view->active_comment_line = num;
4387 		if(old == num || old == 0)
4388 			view->mod_comment_line = num;
4389 		else	{
4390 			view->mod_comment_line = 0;
4391 			view->mod_seq = 1; // astuce
4392 			}
4393 		view->draw_names = 0;
4394 		update_menu_footers(view);
4395 		view->DNA_obj->damage(1);
4396 		}
4397 	else if( new_site >= view->first_site &&
4398 		new_site < view->first_site + view->tot_sites &&
4399 		new_site <= view->comment_length[num - 1] + 1 ) {
4400 		/* click sur comment: positionnement du curseur */
4401 		view->cursor_site = new_site;
4402 		view->cursor_seq = num;
4403 		view->draw_names = 0;
4404 		view->mod_cursor = TRUE;
4405 		view->cursor_in_comment = TRUE;
4406 		view->DNA_obj->damage(1);
4407 		}
4408 	return;
4409 	}
4410 
4411 if( new_seq < view->first_seq || new_seq > view->tot_seqs ||
4412 	new_seq >= view->first_seq + view->tot_lines ) return;
4413 if(mx >= view->x_name && mx < view->x_seq - view->char_width) {
4414 /* click sur nom de seq: selection/deselection */
4415 	if(view->alt_col_rank != NULL) return;
4416 	if(key == 1) {
4417 		*p_selecting_seqs = new_seq;
4418 		*p_sel_seq_move = new_seq;
4419 		return;
4420 		}
4421 	else if(key == 3) {
4422 		select_deselect_seq(view, 0);
4423 		view->draw_names = -2;
4424 		view->DNA_obj->damage(1);
4425 		return;
4426 		}
4427 	else if(key == 4) { //cmd-Click select from last selected to here
4428 		int i;
4429 		for(i = new_seq; i > 0; i--) {
4430 			if(view->sel_seqs[i - 1]) break;
4431 			}
4432 		if(i == 0) return;
4433 		while(++i <= new_seq) {
4434 			if(!view->sel_seqs[i - 1]) {
4435 				view->sel_seqs[i - 1] = TRUE;
4436 				view->tot_sel_seqs++;
4437 				}
4438 			}
4439 		select_deselect_seq(view, -2);
4440 		view->draw_names = -2;
4441 		view->DNA_obj->damage(1);
4442 		return;
4443 		}
4444 	else	{ /* milieu: depl des seqs selectionnees */
4445 		if(view->tot_sel_seqs == 0 ||
4446 			view->sel_seqs[new_seq - 1])
4447 			{ fl_beep(FL_BEEP_DEFAULT); return; }
4448 		deplacer_grp_seqs(view, new_seq);
4449 		view->DNA_obj->redraw();
4450 		}
4451 	return;
4452 	}
4453 if(key != 1)  return;
4454 /* click sur seq: positionnement du curseur */
4455 if( new_site >= view->first_site &&
4456 	new_site < view->first_site + view->tot_sites &&
4457 	new_site <= view->each_length[new_seq-1] + 1 ) {
4458 	view->cursor_site = new_site;
4459 	view->cursor_seq = new_seq;
4460 	view->cursor_in_comment = FALSE;
4461 	view->draw_names = 0;
4462 	view->mod_cursor = TRUE;
4463 	view->DNA_obj->damage(1);
4464 	}
4465 return;
4466 }
4467 
4468 
handle_keyboard(SEA_VIEW * view,unsigned int key,int istext)4469 void handle_keyboard(SEA_VIEW *view, unsigned int key, int istext)
4470 {
4471 int new_pos, multipl, num;
4472 
4473 multipl = view->multipl->argument();
4474 if(multipl == 0) multipl = 1;
4475 if(key == FL_Right) { /* right arrow */
4476 	new_pos = view->cursor_site + multipl;
4477     if(view->cursor_in_comment) {
4478 	if(new_pos > view->comment_length[view->cursor_seq-1]+1)
4479 	   new_pos = view->comment_length[view->cursor_seq-1]+1;
4480 	}
4481     else {
4482 	if(new_pos > view->each_length[view->cursor_seq-1] + 1)
4483 	   new_pos = view->each_length[view->cursor_seq-1] + 1;
4484 	}
4485     set_and_show_new_cursor_site(view, new_pos,FALSE,FALSE);
4486     }
4487 else if(key == FL_Left) { /* left arrow */
4488 	new_pos = FL_max(1, view->cursor_site - multipl);
4489 	set_and_show_new_cursor_site(view, new_pos,FALSE,FALSE);
4490 	}
4491 else if(key == FL_Up) { /* up arrow */
4492 	new_pos = FL_max(1, view->cursor_seq - multipl);
4493 	set_and_show_new_cursor_seq(view, new_pos);
4494 	}
4495 else if(key == FL_Down){ /* down arrow */
4496 	new_pos = view->cursor_seq + multipl;
4497 	if(view->cursor_in_comment) {
4498 		if(new_pos > view->tot_comment_lines)
4499 			new_pos = view->tot_comment_lines;
4500 		}
4501 	else	{
4502 		if(new_pos > view->tot_seqs)
4503 			new_pos = view->tot_seqs;
4504 		}
4505 	set_and_show_new_cursor_seq(view, new_pos);
4506 	}
4507 else if(key == FL_Page_Up) { /* page up key */
4508   new_pos = FL_max(1, view->cursor_seq - view->tot_lines + 1);
4509   set_and_show_new_cursor_seq(view, new_pos);
4510   }
4511 else if(key == FL_Page_Down) { /* page down key */
4512   new_pos = FL_min(view->tot_seqs, view->cursor_seq + view->tot_lines - 1);
4513   set_and_show_new_cursor_seq(view, new_pos);
4514 }
4515 else if(view->cursor_in_comment &&
4516 	view->active_comment_line == view->cursor_seq) {
4517 	unsigned char c_key = (unsigned)key;
4518 	if(view->alt_col_rank != NULL) return;
4519 	if( key == 0x7f || key == 0x8 || key == FL_Delete || key == FL_BackSpace ) /* del or BS */
4520 		delete_char_in_comment(view, 1,
4521 			view->active_comment_line,
4522 			view->cursor_site, FALSE);
4523 	else if( istext && ( ( c_key >= 32 && c_key <= 126 ) ||
4524 		( c_key >= 160 /* && c_key <= 255 */ )  ) )
4525 		insert_char_in_comment(c_key, 1, view);
4526 	else
4527 		return;
4528 	}
4529 else if(strchr(view->movekeys, key) != NULL) {
4530 					/* ][>< touches depl droite/gauche */
4531 	int oldpos;
4532 	int upper_step=50, bracket_step=5 ;
4533 	int max_w;
4534 	max_w = (int)(view->horsli->maximum());
4535 	oldpos = (int)( view->horsli->value() );
4536 	new_pos = oldpos;
4537 	upper_step *= multipl;
4538 	bracket_step *= multipl;
4539 	if ((int)key == view->movekeys[2] /* > */ ) {
4540 		new_pos=oldpos+upper_step;
4541 		if(new_pos>max_w) new_pos=max_w;
4542 		}
4543 	else if((int)key == view->movekeys[3] /* < */ ) {
4544 		new_pos=oldpos-upper_step;
4545 		if(new_pos<1) new_pos=1;
4546 		}
4547 	else if((int)key == view->movekeys[0] /* ] */ ) {
4548 		new_pos=oldpos+bracket_step;
4549 		if(new_pos>max_w) new_pos=max_w;
4550 		}
4551 	else if((int)key == view->movekeys[1] /* [ */ ) {
4552 		new_pos=oldpos-bracket_step;
4553 		if(new_pos<1) new_pos=1;
4554 		}
4555 	if(new_pos!=oldpos) {
4556 		view->horsli->Fl_Slider::value(new_pos);
4557 		view->draw_names = 0;
4558 		view->first_site = new_pos;
4559 		view->DNA_obj->damage(1);
4560 		}
4561 	}
4562 else if(key == 0x7f || key == 0x8 || key == FL_Delete || key == FL_BackSpace ) { /* delete or backspace */
4563 	int count, count_each, debut, fin, test;
4564 	    if(view->multipl->argument() > 0)
4565 		mod_multipl(view,0);
4566 	if(view->cursor_in_comment)
4567 		test = view->cursor_seq < 1 ||
4568 	   		view->cursor_seq > view->tot_comment_lines;
4569 	else
4570 		test = view->cursor_seq < view->first_seq ||
4571 	   		view->cursor_seq >= view->first_seq+view->tot_lines;
4572 	if( test ||
4573 	   view->cursor_site < view->first_site ||
4574 	   view->cursor_site >=view->first_site+view->tot_sites)
4575 		{ fl_beep(FL_BEEP_DEFAULT); return; }
4576 	if(view->cursor_in_comment) {
4577 		if( delete_char_in_comment(view, multipl,
4578 			view->cursor_seq, view->cursor_site,
4579 			TRUE) != multipl) fl_beep(FL_BEEP_DEFAULT);
4580 		return;
4581 		}
4582 	if(view->alt_col_rank != NULL) return;
4583 	if(view->tot_sel_seqs > 1 &&
4584 		view->sel_seqs[view->cursor_seq - 1])
4585 		{ debut = 1; fin = view->tot_seqs; test = TRUE;}
4586 	else
4587 		{ debut = fin = view->cursor_seq; test = FALSE;}
4588 	if(multipl > view->cursor_site - 1) multipl = view->cursor_site - 1;
4589 	for(num = debut; num<=fin; num++)
4590 		{
4591 		if(test && !view->sel_seqs[num-1]) continue;
4592 		count_each = delete_gaps_before(view,
4593 			num,
4594 			view->cursor_site, multipl);
4595 		if(count_each < multipl) fl_beep(FL_BEEP_DEFAULT);
4596 		if(num == view->cursor_seq) count = count_each;
4597 		}
4598 	/* si ttes seqs selectionnees, traiter aussi regions et comments */
4599 	if(count_each == multipl &&
4600 		(!view->cursor_in_comment) &&
4601 		view->tot_sel_seqs == view->tot_seqs ) {
4602 		if(view->regions != NULL)
4603 			delete_region_part(view,
4604 				view->cursor_site,multipl);
4605 		if(view->tot_comment_lines > 0)
4606 			delete_in_all_comments(multipl,
4607 				view->cursor_site, view);
4608 		}
4609 	new_pos = view->cursor_site - count;
4610 	if(new_pos <= 0) new_pos = 1;
4611 	if(view->cursor_in_comment) {
4612 		view->mod_comment_line = view->cursor_seq;
4613 		}
4614 	else	{
4615 		if(view->tot_sel_seqs > 1 &&
4616 			view->tot_sel_seqs != view->tot_seqs &&
4617 			view->sel_seqs[view->cursor_seq - 1])
4618 			view->mod_seq = -1;
4619 		else if(view->tot_sel_seqs <= 1 ||
4620 			!view->sel_seqs[view->cursor_seq - 1])
4621 			view->mod_seq = view->cursor_seq;
4622 		}
4623 	set_and_show_new_cursor_site(view, new_pos,
4624 		FALSE,TRUE);
4625 	}
4626 else if(key == '_' ) { /* del gap in all but current seq(s) */
4627 	int count_each;
4628 	    if(view->multipl->argument() > 0)
4629 		mod_multipl(view,0);
4630 	if(view->cursor_in_comment) return;
4631 	if( view->cursor_seq < view->first_seq ||
4632 	   	view->cursor_seq >=view->first_seq+view->tot_lines ||
4633 	  	view->cursor_site < view->first_site ||
4634 	   	view->cursor_site >=
4635 	   	view->first_site + view->tot_sites ||
4636 	   	view->tot_sel_seqs == view->tot_seqs )
4637 		 { fl_beep(FL_BEEP_DEFAULT); return; }
4638 	if(view->alt_col_rank != NULL) return;
4639 	for( num = 1; num <= view->tot_seqs; num++) {
4640 		if(num == view->cursor_seq ||
4641 			(view->sel_seqs[view->cursor_seq-1] &&
4642 			view->sel_seqs[num-1] ) ) continue;
4643 		count_each = delete_gaps_before(view,
4644 		    	num, view->cursor_site, multipl);
4645 		if(count_each < multipl) {
4646 			fl_beep(FL_BEEP_DEFAULT);
4647 			return;
4648 			}
4649 		}
4650 	if(count_each == multipl && view->regions != NULL)
4651 		delete_region_part(view, view->cursor_site, multipl);
4652 	if(count_each == multipl && view->tot_comment_lines > 0)
4653 		delete_in_all_comments(multipl, view->cursor_site, view);
4654 	new_pos = view->cursor_site - multipl;
4655 	if(new_pos <= 0) new_pos = 1;
4656 	set_and_show_new_cursor_site(view, new_pos, FALSE, TRUE);
4657 	}
4658 else if( key == '-' || (key == ' ' && !view->hjkl)
4659 			  /* gap key = - or space */
4660 	|| key == '+' ) { /* insert gap in other seqs key */
4661 	int newlength = 0, count = 0, count_each, debut, fin, test;
4662 	    if(view->multipl->argument() > 0)
4663 		mod_multipl(view,0);
4664 	if(view->cursor_in_comment && key == '+') return;
4665 	if(view->cursor_in_comment)
4666 		test = FALSE;
4667 	else
4668 		test = view->cursor_seq < view->first_seq ||
4669 	   		view->cursor_seq >=view->first_seq+view->tot_lines;
4670 	if( test || view->cursor_site < view->first_site ||
4671 	   	view->cursor_site >=
4672 		view->first_site + view->tot_sites )
4673 		 { fl_beep(FL_BEEP_DEFAULT); return; }
4674 	if(view->alt_col_rank != NULL) return;
4675 	if(key != '+') { /* gap key */
4676 	    if(view->tot_sel_seqs > 1 &&
4677 		(!view->cursor_in_comment) &&
4678 		view->sel_seqs[view->cursor_seq - 1])
4679 		{ debut = 1; fin = view->tot_seqs; test = TRUE;}
4680 	    else
4681 		{ debut = fin = view->cursor_seq; test = FALSE;}
4682 	    for(num = debut; num<=fin; num++)
4683 		{
4684 		if(test && !view->sel_seqs[num-1]) continue;
4685 		count_each = insert_gaps_at(view, num,
4686 			view->cursor_site, multipl);
4687 		if(count_each < multipl) fl_beep(FL_BEEP_DEFAULT);
4688 		if(num == view->cursor_seq) count = count_each;
4689 		if(view->cursor_in_comment) {
4690 		   if(newlength < view->comment_length[num-1])
4691 			newlength = view->comment_length[num-1];
4692 		     }
4693 		else {
4694 		   if(newlength < view->each_length[num-1])
4695 			   newlength = view->each_length[num-1];
4696 		     }
4697 		}
4698 /* si ttes seqs selectionnees, traiter aussi regions et comments */
4699 	    if(count_each == multipl &&
4700 		(!view->cursor_in_comment) &&
4701 		view->tot_sel_seqs == view->tot_seqs) {
4702 		if(view->regions != NULL)
4703 			insert_region_part(view, view->cursor_site, multipl);
4704 		if(view->tot_comment_lines > 0)
4705 			insert_gap_all_comments(multipl,view->cursor_site,
4706 				view);
4707 		}
4708 	    }
4709 	else	{ /* + ==> gap in other sequences */
4710 		if(view->tot_sel_seqs == view->tot_seqs) {
4711 			fl_beep(FL_BEEP_DEFAULT); return;
4712 			}
4713 		for( num = 1; num <= view->tot_seqs; num++) {
4714 			if(num == view->cursor_seq ||
4715 			     (view->sel_seqs[view->cursor_seq-1] &&
4716 			      view->sel_seqs[num-1] ) ) continue;
4717 			count_each = insert_gaps_at(view,
4718 			    num, view->cursor_site, multipl);
4719 			if(count_each < multipl) {
4720 				fl_beep(FL_BEEP_DEFAULT); return;
4721 				}
4722 			if(newlength < view->each_length[num-1])
4723 			   	newlength = view->each_length[num-1];
4724 			}
4725 		count = multipl;
4726 		if(count_each == multipl &&
4727 			view->regions != NULL)
4728 			insert_region_part(view, view->cursor_site, multipl);
4729 		if(count_each == multipl &&
4730 			view->tot_comment_lines > 0) {
4731 			insert_gap_all_comments(multipl,view->cursor_site,
4732 				view);
4733 			   }
4734 		}
4735 	new_pos = view->cursor_site + count;
4736 	if(view->cursor_in_comment) {
4737 	 	if(new_pos> view->comment_length[view->cursor_seq-1]+1)
4738 	    		new_pos= view->comment_length[view->cursor_seq-1]+1;
4739 	 	}
4740 	else 	{
4741 	 	if(new_pos > view->each_length[view->cursor_seq-1] + 1)
4742 	   		 new_pos = view->each_length[view->cursor_seq-1] + 1;
4743 	 	}
4744 	if(view->cursor_in_comment)
4745 		view->mod_comment_line = view->cursor_seq;
4746 	else if(key != '+' ) {
4747 		if(view->tot_sel_seqs > 1 &&
4748 			view->tot_sel_seqs != view->tot_seqs &&
4749 			view->sel_seqs[view->cursor_seq - 1])
4750 			view->mod_seq = -1;
4751 		else if(view->tot_sel_seqs <= 1 ||
4752 			!view->sel_seqs[view->cursor_seq - 1] )
4753 			view->mod_seq = view->cursor_seq;
4754 		}
4755 	update_current_seq_length(newlength, view);
4756 	set_and_show_new_cursor_site(view, new_pos, FALSE,TRUE);
4757 	}
4758 else if( key >= '0' && key <= '9' ) { /* multiplicateur */
4759 	multipl = view->multipl->argument() * 10;
4760 	multipl += (key - '0');
4761 	mod_multipl(view, multipl);
4762 	return;
4763 	}
4764 else if( view->allow_seq_edit && (view->alt_col_rank == NULL) &&
4765 	(!view->cursor_in_comment) &&
4766 	isprint(key) /* a user asked for inserting special characters in sequences */
4767 	) {
4768 	if(view->hjkl) {
4769 		static char typedkey[]= "hjklHJKL ";
4770 		static char dnaequivs[3][10]={
4771 			"gatcGATCN", "tcgaTCAGN", "acgtACGTN"};
4772 		char *p;
4773 		p = strchr(typedkey, key);
4774 		if(p != NULL)
4775 			key = *( dnaequivs[view->hjkl - 1] + (p - typedkey) );
4776 		}
4777 	if(key == ' ') num = 0;
4778 	else	num = insert_char_in_seq(key, multipl, view);
4779 	if( num == 0 ) fl_beep(FL_BEEP_DEFAULT);
4780 	else 	{
4781 		view->mod_seq = view->cursor_seq;
4782 		set_and_show_new_cursor_site(view,
4783 			view->cursor_site + num, FALSE, TRUE);
4784 		}
4785 	}
4786 else	return;
4787 if(view->multipl->argument() > 0) mod_multipl(view, 0);
4788 }
4789 
4790 
create_dna_scroller(SEA_VIEW * view,int x,int y,int w,int h,int double_buffer)4791 Fl_Group *create_dna_scroller(SEA_VIEW *view, int x, int y, int w, int h,
4792 	int double_buffer)
4793 {
4794   Fl_Group *dna_group;
4795   Fl_Widget *obj;
4796   int wmultipl, x_pos;
4797   user_data_plus *data;
4798 dna_group = new Fl_Group(x,y,w,h);
4799 int scroll_w = 15;
4800 #ifdef __APPLE__
4801 #define DELTA_G  13 // laisser place pour poignée de dimensionnement de fenetre
4802 #else
4803 #define DELTA_G  0
4804 #endif
4805 /* screen move haut */
4806 view->up_screen_move = obj =
4807 (Fl_Widget*)new Fl_Repeat_Button(x+3, y,scroll_w,scroll_w,"@8>>");
4808 obj->labeltype(FL_SYMBOL_LABEL);
4809 data = new user_data_plus;
4810 data->p = view;
4811 data->value = 5;
4812 obj->callback(lrdu_button_callback, data);
4813 /* ascenc. vertical */
4814 view->vertsli =  new Fl_Scrollbar(x+3, y + scroll_w + 2, scroll_w,
4815 		h - 3*scroll_w - 12, "");
4816 view->vertsli->box(FL_DOWN_BOX);
4817 data = new user_data_plus;
4818 data->p = view;
4819 data->value = 0;
4820 ((Fl_Scrollbar *)view->vertsli)->linesize(1);
4821 view->vertsli->callback(vh_sliders_callback, data);
4822   view->vertsli->bounds(1,1);
4823   view->vertsli->slider_size(1);
4824   view->vertsli->Fl_Slider::value(1);
4825   view->vertsli->step(1);
4826 view->vertsli->when(FL_WHEN_CHANGED);
4827 /* screen move bas */
4828 view->down_screen_move = obj =
4829 (Fl_Widget*)new Fl_Repeat_Button(x+3,
4830 	y + h - 2 * scroll_w - 8, scroll_w, scroll_w, "@2>>");
4831 obj->labeltype(FL_SYMBOL_LABEL);
4832 data = new user_data_plus;
4833 data->p = view;
4834 data->value = 7;
4835 obj->callback(lrdu_button_callback, data);
4836 
4837 int y_scroll = y + h - scroll_w - 3;
4838 /* valeur du multiplicateur */
4839 fl_font(FL_HELVETICA, FL_NORMAL_SIZE);
4840   wmultipl = (int)fl_width("mult=9999");
4841   x_pos = 5;
4842   view->multipl = obj = (Fl_Widget*)new Fl_Box(FL_FLAT_BOX,
4843 	x+x_pos, y_scroll - 2, wmultipl, FL_NORMAL_SIZE + 4, "");
4844   x_pos += wmultipl + 5;
4845   obj->labelfont(FL_HELVETICA);
4846   obj->labelsize(FL_NORMAL_SIZE);
4847   obj->align(FL_ALIGN_CENTER);
4848 
4849 
4850 /* screen move gauche */
4851   view->left_screen_move = obj =
4852 (Fl_Widget*)new Fl_Repeat_Button(x+x_pos,y_scroll,scroll_w,scroll_w,"@<<");
4853 obj->labeltype(FL_SYMBOL_LABEL);
4854   x_pos += scroll_w + 2;
4855 data = new user_data_plus;
4856 data->p = view;
4857 data->value = 1;
4858 obj->callback(lrdu_button_callback, data);
4859 /* ascens. horizontal */
4860 view->horsli =
4861 new Fl_Scrollbar(x + x_pos, y_scroll, w - x_pos - scroll_w - 2 - DELTA_G, scroll_w,"");
4862 view->horsli->type(FL_HORIZONTAL);
4863 view->horsli->box(FL_DOWN_BOX);
4864 ((Fl_Scrollbar *)view->horsli)->linesize(1);
4865 data = new user_data_plus;
4866 data->p = view;
4867 data->value = 1;
4868 view->horsli->callback(vh_sliders_callback, data);
4869 view->horsli->bounds(1,1);
4870 view->horsli->slider_size(1);
4871 view->horsli->Fl_Slider::value(1);
4872 view->horsli->step(1);
4873 view->horsli->when(FL_WHEN_CHANGED);
4874 /* screen move a droite */
4875   view->right_screen_move = obj =
4876 (Fl_Widget*)new Fl_Repeat_Button(x+w - scroll_w - DELTA_G, y_scroll, scroll_w, scroll_w,"@>>");
4877 obj->labeltype(FL_SYMBOL_LABEL);
4878 data = new user_data_plus;
4879 data->p = view;
4880 data->value = 3;
4881 obj->callback(lrdu_button_callback, data);
4882 
4883 /* noms + sequences */
4884 Fl_Window *viewer;
4885 if(double_buffer)
4886 	  viewer = (Fl_Window *)new Fl_Double_Window(
4887 					x+25-3, y, w - 25 - 1 + 6, h - 30 + 6);
4888 else
4889 	  viewer = new Fl_Window(x+25, y+3, w - 25 - 1, h - 30);
4890 viewer->box(FL_DOWN_BOX);
4891 viewer->resizable(viewer);
4892 view->double_buffer = double_buffer;
4893 view->DNA_obj = (Fl_Widget*)new DNA_obj(3, 3, w - 25 - 1, h - 30, view);
4894 view->DNA_obj->labelfont(FL_COURIER_BOLD);
4895 viewer->end();
4896 
4897 dna_group->end();
4898 Fl_Box *resizable_box =	new Fl_Box(x + x_pos, y + scroll_w + 2, w - x_pos - scroll_w - 2 - DELTA_G,
4899 		h - 3*scroll_w - 12);
4900 dna_group->add_resizable(*resizable_box);
4901 resizable_box->hide();
4902 return dna_group;
4903 }
4904 
4905 
create_the_form(int double_buffer)4906 SEA_VIEW *create_the_form(int double_buffer)
4907 {
4908 Fl_Group *dna_group;
4909 Fl_Window *my_form;
4910 Fl_Widget *obj, *bouton_search, *champ_search, *bouton_goto, *champ_goto, *bouton_help;
4911 int black_and_white, inverted;
4912 SEA_VIEW *view;
4913 user_data_plus *data;
4914 int labelSize = 12;
4915 int borderWidth = 2;
4916 int i, w_w, w_h, back_color, region_back_color, defaultformat;
4917 char *win_size, *save_format;
4918 static int first = TRUE;
4919 static int dnacolors[] = { FL_WHITE, FL_RED, FL_GREEN, FL_YELLOW, FL_BLUE };
4920 static int numb_dnacolors = sizeof(dnacolors) / sizeof(int);
4921 static char *customdnacolors;
4922 static int *protcolors;
4923 static int *codoncolors = NULL;
4924 static char **possible_formats;
4925 
4926 if(first) {
4927 	first = FALSE;
4928 	//DNA colors
4929 	customdnacolors = get_res_value("dnacolors", "");
4930 	prep_custom_colors(dnacolors, customdnacolors, numb_dnacolors);
4931 	//protein colors
4932 	static char stdcolorgroups[50], altcolorgroups[50], customprotcolors[300];
4933 	strcpy(stdcolorgroups, get_res_value("stdcolorgroups", def_stdcolorgroups));
4934 	strcpy(altcolorgroups, get_res_value("altcolorgroups", ""));
4935 	strcpy(customprotcolors, get_res_value("protcolors", ""));
4936 	protcolors = (int *)malloc(max_protcolors * sizeof(int));
4937 	def_protcolors = (int *)malloc(max_protcolors * sizeof(int));
4938 	for(i=0; i<max_protcolors; i++) def_protcolors[i] =
4939 		fl_rgb_color(def_protcolors_rgb[3*i], def_protcolors_rgb[3*i+1], def_protcolors_rgb[3*i+2]);
4940 
4941 	memcpy(protcolors, def_protcolors, max_protcolors * sizeof(int) );
4942 	int cur_protcolors = prep_custom_colors(protcolors, customprotcolors, max_protcolors);
4943 	/* process resource-read stdcolorgroups and altcolorgroups */
4944 	curr_color_choice = prep_aa_color_code(stdcolorgroups, altcolorgroups,
4945 					       cur_protcolors, &numb_stdprotcolors, &numb_altprotcolors);
4946 	codoncolors = (int *)malloc(22 * sizeof(int));
4947 //codoncolors[1..21] correspond to aas RLSTPAGVKNQHEDYCFIMW*
4948 	decode_codon_colors(codoncolors);
4949 	possible_formats = (char **)malloc(nbr_formats * sizeof(char *));
4950 	for(i= 0; i < nbr_formats; i++) {
4951 		possible_formats[i] = (char  *)malloc( strlen(f_format_names[i]) + 1 );
4952 		strcpy(possible_formats[i], f_format_names[i]);
4953 		minuscules(possible_formats[i]);
4954 		}
4955 	}
4956 save_format = get_res_value("save", possible_formats[NEXUS_FORMAT]);
4957 for(i = 0; i < nbr_formats; i++)
4958 	if(strcmp(save_format, possible_formats[i]) == 0) break;
4959 if( i >= nbr_formats )
4960 	defaultformat = NEXUS_FORMAT;
4961 else
4962 	defaultformat = i;
4963 #ifdef MICRO
4964   black_and_white = FALSE;
4965 #else
4966   black_and_white = (fl_xpixel(FL_BLACK) == fl_xpixel(FL_RED));
4967 #endif
4968   if (black_and_white) inverted = FALSE;
4969   else inverted = bool_res_value("inverted", TRUE);
4970 #ifdef WIN32
4971 	back_color = FL_DARK1; region_back_color = 43;
4972 #else
4973 	back_color = FL_GRAY; region_back_color = FL_DARK2;
4974 #endif
4975 back_color = int_res_value("background", back_color);
4976 region_back_color = int_res_value("sites_background", region_back_color);
4977 win_size = get_res_value("window", "790x500");
4978 sscanf(win_size, "%dx%d", &w_w, &w_h);
4979 my_form = new Fl_Window( FL_min(w_w, Fl::w()), FL_min(w_h, Fl::h()-22) );
4980 my_form->xclass(SEAVIEW_WINDOW);
4981 #ifdef MICRO
4982 int w_x = (Fl::w() - my_form->w())/2;
4983 int w_y =  (Fl::h() - my_form->h())/2;
4984 	{static int count = 0;
4985 	w_x += count * 30;
4986 	w_y += (count++) * 30;
4987 	count = count % 5;
4988 	}
4989 my_form->position(w_x, w_y);
4990 #endif
4991 my_form->color(FL_LIGHT1);
4992 my_form->label(progname);
4993 my_form->box(FL_FLAT_BOX);
4994 
4995   view = (SEA_VIEW *)calloc(1, sizeof(SEA_VIEW));
4996   if(view == NULL) out_of_memory();
4997 
4998 Fl_Pack *menus = new Fl_Pack(1,5,10,25); /* groupe fixe des menus */
4999 menus->type(FL_HORIZONTAL);
5000 menus->spacing(2);
5001 
5002 #ifdef MICRO
5003   const int mbw = 415;
5004 #else
5005   const int mbw = 438;
5006 #endif
5007   Fl_Menu_Bar *menubar = new Fl_Menu_Bar(0,0, mbw, 30);
5008   menubar->user_data(view);
5009   menubar->box(FL_UP_BOX);
5010   view->menubar = menubar;
5011   /* menu File */
5012   static const Fl_Menu_Item fileitems_static[] = {
5013     {"Open", FL_COMMAND | 'o',file_menu_callback, 0, FL_MENU_DIVIDER},
5014     {"Open Mase", 0,file_menu_callback, 0, 0},
5015     {"Open Phylip", 0,file_menu_callback, 0, 0},
5016     {"Open Clustal", 0,file_menu_callback, 0, 0},
5017     {"Open MSF", 0,file_menu_callback, 0, 0},
5018     {"Open Fasta", 0,file_menu_callback, 0, 0},
5019     {"Open NEXUS", 0,file_menu_callback, 0, FL_MENU_DIVIDER},
5020     {"Import from DBs", 0,file_menu_callback, 0, FL_MENU_DIVIDER},
5021     {"Save", FL_COMMAND | 's',file_menu_callback, 0, FL_MENU_INACTIVE},
5022     {"Save as...", 0,file_menu_callback, 0, FL_MENU_INACTIVE},
5023     {"Save selection", 0,file_menu_callback, 0, FL_MENU_INACTIVE},
5024     {"Save prot alignmt", 0,file_menu_callback, 0, FL_MENU_INACTIVE},
5025     {"Save bootstrap replicates", 0,file_menu_callback, 0, FL_MENU_INACTIVE | FL_MENU_DIVIDER},
5026 #if !defined(__APPLE__)
5027     {"Prepare " PDF_OR_PS, 0, file_menu_callback, 0, 0},
5028     {PDF_OR_PS " options...", 0, file_menu_callback, 0, FL_MENU_DIVIDER},
5029 #else
5030     {"Prepare " PDF_OR_PS, 0, file_menu_callback, 0, FL_MENU_DIVIDER},
5031 #endif
5032     {"Concatenate", 0,file_menu_callback, 0, FL_MENU_DIVIDER},
5033     {"New window", FL_COMMAND | 'n', file_menu_callback, 0, 0},
5034     {"Close window", FL_COMMAND | 'w', file_menu_callback, 0, 0},
5035 #if ! defined( __APPLE__)
5036     {"Quit", FL_COMMAND | 'q', file_menu_callback, 0, 0 },
5037 #endif
5038     {0}
5039   };
5040   Fl_Menu_Item *fileitems = new Fl_Menu_Item[sizeof(fileitems_static)/sizeof(Fl_Menu_Item)];
5041   memcpy(fileitems, fileitems_static, sizeof(fileitems_static));
5042   menubar->add("File", 0, 0, fileitems, FL_SUBMENU_POINTER);
5043   view->menu_file = fileitems; // to delete[] at window close
5044 
5045 /* menu Edit */
5046   static const Fl_Menu_Item edititems_static [] = {
5047     {"Copy selected seqs", FL_COMMAND | 'c', edit_menu_callback, 0, FL_MENU_INACTIVE},
5048     {"Paste alignment data", FL_COMMAND | 'v', edit_menu_callback, 0, 0},
5049     {"Select All", FL_COMMAND | 'a', edit_menu_callback, 0, 0},
5050     {"Rename sequence", 0, edit_menu_callback, 0, 0},
5051     {"Edit comments", 0, edit_menu_callback, 0, 0},
5052     {"Edit sequence", 0, edit_menu_callback, 0, 0},
5053     {"Delete sequence(s)", 0, edit_menu_callback, 0, 0},
5054     {"Create sequence", 0, edit_menu_callback, 0, 0},
5055     {"Load sequence", 0, edit_menu_callback, 0, 0},
5056     {"Duplicate sequence", 0, edit_menu_callback, 0, 0},
5057     {"Complement sequence", 0, edit_menu_callback, 0, 0},
5058     {"Reverse sequence", 0, edit_menu_callback, 0, 0},
5059     {"Exchange Us and Ts", 0, edit_menu_callback, 0, 0},
5060     {"Dot plot", 0, edit_menu_callback, 0, 0},
5061     {"Consensus sequence", 0, edit_menu_callback, 0, 0},
5062     {"Del. gap-only sites", 0, edit_menu_callback, 0, 0},
5063     {"Set genetic code", 0, edit_menu_callback, 0, 0},
5064     {0}
5065   };
5066   Fl_Menu_Item *edititems = new Fl_Menu_Item[sizeof(edititems_static)/sizeof(Fl_Menu_Item)];
5067   memcpy(edititems, edititems_static, sizeof(edititems_static));
5068   menubar->add("Edit", 0, 0, edititems, FL_SUBMENU_POINTER);
5069   view->menu_edit = edititems; // to delete[] at window close
5070 
5071 /* menu align */
5072   cre_align_menu(view);
5073 
5074 /* menu Props */
5075   view->inverted_colors = inverted;
5076   view->consensus_threshold = 60;
5077   view->double_buffer = double_buffer;
5078   create_props_menu(view, curr_color_choice, view->inverted_colors, black_and_white, defaultfontsize);
5079 
5080 /* menu regions */
5081   static const Fl_Menu_Item siteitems_static[] = {
5082     {"Create set", 0, regions_menu_callback, 0, FL_MENU_INACTIVE},
5083     {"Duplicate set", 0, regions_menu_callback, 0,FL_MENU_INACTIVE},
5084     {"Hide set", 0, regions_menu_callback, 0, FL_MENU_INACTIVE},
5085     {"Delete set", 0, regions_menu_callback, 0, FL_MENU_INACTIVE | FL_MENU_DIVIDER},
5086   };
5087   view->menu_sites = new vlength_menu(view->menubar, "Sites", siteitems_static, 4);
5088 
5089 /* menu species */
5090   static const Fl_Menu_Item speciesitems_static[] = {
5091     {"Create group", 0, species_menu_callback, 0, FL_MENU_INACTIVE},
5092     {"Delete group", 0, species_menu_callback, 0, FL_MENU_INACTIVE | FL_MENU_DIVIDER},
5093   };
5094   view->menu_species = new vlength_menu(view->menubar, "Species", speciesitems_static, 2);
5095 
5096 /* menu footers */
5097   const static Fl_Menu_Item footeritems_static[] = {
5098     {"Show footers", 0, footers_menu_callback, NULL, FL_MENU_INACTIVE},
5099     {"Create footer", 0, footers_menu_callback, NULL, 0},
5100     {"Delete footer", 0, footers_menu_callback, NULL, FL_MENU_INACTIVE},
5101     {0}
5102   };
5103   Fl_Menu_Item *footeritems = new Fl_Menu_Item[4];
5104   memcpy(footeritems, footeritems_static, sizeof(footeritems_static));
5105   menubar->add("Footers", 0, 0, footeritems, FL_SUBMENU_POINTER);
5106   view->menu_footers = footeritems;
5107 
5108   /* menu trees */
5109   const static Fl_Menu_Item treeitems_static[] = {
5110     {"Parsimony", 0, trees_callback, 0, 0},
5111     {"Distance methods", 0, trees_callback, 0, 0},
5112     {"PhyML", 0, trees_callback, 0, FL_MENU_DIVIDER},
5113     {"Import tree", 0, trees_callback, 0, 0},
5114     {"New tree window", 0, trees_callback, 0, FL_MENU_DIVIDER},
5115   };
5116   view->menu_trees = new vlength_menu(view->menubar, "Trees", treeitems_static, 5);
5117 
5118 #define calc_width(nom) \
5119 (fl_font(FL_HELVETICA, labelSize), (int)fl_width(nom) + 4 * borderWidth)
5120 #define add_button(nom) new Fl_Button(0,0,calc_width(nom),25,nom)
5121 
5122   /* bouton search + champ Search */
5123 bouton_search = obj = add_button("Search:");
5124 obj->labelsize(labelSize);
5125 data = new user_data_plus;
5126 data->value = 0;
5127 obj->callback(search_callback, data);
5128 champ_search = obj = (Fl_Widget*)new Fl_Input(0,0, 80, 25, "");
5129 ((Fl_Input*)obj)->type(FL_NORMAL_INPUT);
5130 ((Fl_Input*)obj)->when(FL_WHEN_ENTER_KEY);
5131 data = new user_data_plus;
5132 data->value = 1;
5133 champ_search->callback(search_callback, data);
5134 data = (user_data_plus *)bouton_search->user_data();
5135 data->p = champ_search;
5136 
5137 /*  bouton + champ Goto */
5138 bouton_goto = obj = add_button("Goto:");
5139 obj->labelsize(labelSize);
5140 data = new user_data_plus;
5141 data->value = 0;
5142 obj->callback(goto_callback, data);
5143 champ_goto = obj = (Fl_Widget*)new Fl_Input(0, 0, 80, 25, "");
5144 ((Fl_Input*)obj)->type(FL_NORMAL_INPUT);
5145 data = new user_data_plus;
5146 data->value = 1;
5147 champ_goto->callback(goto_callback, data);
5148 data = (user_data_plus *)bouton_goto->user_data();
5149 data->p = champ_goto;
5150 ((Fl_Input*)obj)->when(FL_WHEN_ENTER_KEY);
5151 
5152 /* bouton help */
5153 bouton_help = add_button("Help");
5154 bouton_help->labelsize(labelSize);
5155 bouton_help->callback(help_callback);
5156 
5157 #undef add_button
5158 #undef calc_width
5159 
5160 menus->end();
5161 menus->resizable(NULL);
5162 
5163 /* tout le groupe scroller */
5164 dna_group = create_dna_scroller(view, 0, 35, my_form->w() - 5, my_form->h() - 35, double_buffer);
5165 my_form->resizable( dna_group );
5166 my_form->end();
5167 my_form->callback(mainwin_close_callback, view);
5168 /* initialisation independantes des sequences */
5169 static char movekeys[5];
5170 strcpy(movekeys, get_res_value("movekeys", MOVEKEYS_DEFAULT));
5171 view->movekeys = movekeys;
5172 data = (user_data_plus *)champ_search->user_data();
5173 data->p = view;
5174 data = (user_data_plus *)champ_goto->user_data();
5175 data->p = view;
5176 view->format_for_save = (known_format)defaultformat; /* default format for saving */
5177 view->tot_seqs = 0;
5178 view->first_seq = 1; view->tot_sites = 1;
5179 view->numb_gc = 1;
5180 view->line_height = 1;
5181 view->char_width = 1;
5182 view->draw_names = -1;
5183 view->mod_seq = 0;
5184 view->mod_comment_line = 0;
5185 view->consensus_allowgaps = FALSE;
5186 view->consensus_allowiupac = FALSE;
5187 view->dnawin = my_form;
5188 view->max_seq_length = 0;
5189 mod_multipl(view, 0);
5190 view->spaces_in_fasta_names = bool_res_value("spacesinfastanames", FALSE);
5191 
5192 if ( ! black_and_white) {
5193 	/* couleurs du fond pour seqs */
5194   	view->DNA_obj->color(back_color, region_back_color);
5195 	view->region_color = FL_WHITE;
5196 	if(view->inverted_colors) {
5197 		view->DNA_obj->labelfont( FL_COURIER);
5198 		}
5199 	view->allow_lower = bool_res_value("lowercase", 0);
5200 	}
5201 else	{ /* the Black and White case */
5202 	numb_dnacolors = numb_stdprotcolors = numb_altprotcolors = 1;
5203 	dnacolors[0] = FL_BLACK;
5204 	/* couleur du fond pour seqs */
5205   	view->DNA_obj->color(FL_WHITE, FL_WHITE);
5206 	view->region_color = FL_BLACK;
5207 	view->numb_gc = 1;
5208 	view->curr_colors = dnacolors;
5209 	view->allow_lower = TRUE;
5210 	}
5211 view->DNA_obj->parent()->color( view->DNA_obj->color() );
5212 /* taille par defaut des lettres des sequences */
5213 view->DNA_obj->labelsize(defaultfontsize);
5214   view->dnacolors = dnacolors;
5215 view->numb_dnacolors = numb_dnacolors;
5216 view->stdprotcolors = protcolors;
5217 view->numb_stdprotcolors = numb_stdprotcolors;
5218 view->altprotcolors = protcolors;
5219 view->numb_altprotcolors = numb_altprotcolors;
5220 view->codoncolors = codoncolors;
5221 view->namecolor = FL_BLACK;
5222 view->alt_colors = curr_color_choice;
5223 view->clustal_options = NULL;
5224 view->show_comment_lines = FALSE;
5225 view->tot_comment_lines = 0;
5226 view->phylipwidnames = int_res_value("phylipwidnames", 30);
5227 #if defined(__APPLE__) && 100*FL_MAJOR_VERSION + FL_MINOR_VERSION < 104
5228   add_windowmenuitem(NULL, my_form);
5229 #endif
5230 my_form->show();
5231 #ifndef MICRO
5232 my_form->hotspot(my_form);
5233 #endif
5234 #if !(defined(__APPLE__) && !defined(WIN32)) //for X11 only
5235   my_form->make_current(); // 3 lines so the Fl_Pack gets its true width
5236   menus->damage(FL_DAMAGE_ALL);
5237   ((Fl_Widget*)menus)->draw();
5238   int min_w = menus->x() + menus->w() + 5; //min_w = width of the menu bar
5239   if (min_w > my_form->w()) {//make sure window is as wide as menu bar
5240     my_form->size(min_w, my_form->h());
5241   }
5242 #endif
5243 view->DNA_obj->take_focus();
5244 return view;
5245 }
5246 
5247 
5248 
5249