//njplot coords = pdf coords: bottom to top
//QuickDraw coords: top to bottom
#include <math.h>
#include <time.h>
#include <ctype.h>

#include <FL/Enumerations.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Check_Button.H>
#include <FL/Fl_Round_Button.H>
#include <FL/Fl_Scrollbar.H>
#include <FL/Fl_Counter.H>
#include <FL/Fl_Printer.H>
#include "unrooted.h"
#include "treedraw.h"
#include "pdf_or_ps.h"
#include <FL/Fl_PostScript.H>

#define MAX_FRAC 0.95
#ifndef FALSE
#define FALSE 0
#define TRUE (!FALSE)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* typedefs */

typedef enum { helvetica, courier, times} font_name;

	
typedef struct branche { /* une branche definie par ses deux extremites */
	struct noeud *bouta;
	struct noeud *boutb;
	char *br_label;
	} branche;

#define s_noeud sizeof(struct noeud)

typedef struct _moments {
	int N; /* nbre de fils */
	double somme, carres; /* somme des longueurs jusqu'aux feuilles, et somme des carres */
} moments;



/* prototypes of included functions */
static void copy(Fl_Widget *wgt, void *data);
static void paste(Fl_Widget *wgt, void *data);
void toggle_br_lengths(Fl_Widget *wgt, void *data);
void toggle_bootstrap(Fl_Widget *wgt, void *data);
void change_ffam(Fl_Widget *wgt, void *data);
char *prepare_ps_or_pdf_font(int font_num);
void subtreeup_callback(Fl_Widget *wgt, void *data);
void operation_callback(Fl_Widget *wgt, void *data);
void do_plot(FD_nj_plot *fd_nj_plot, int doing_print);
int calc_text_size(char *text, int *pheight, int *pascent);
void plotstring(const char *nom);
void dir_moveto(double x,double y);
void dir_lineto(double x,double y);
void dir_plotsquare(double x, double y, int edge, int use_color);
void scale_window(double lxmin, double lxmax, double lymin, double lymax,
 	double pxmin, double pxmax, double pymin, double pymax);
void ch_echelle(double lx, double ly, double *px, double *py);
void init_tree(char *fname, char *displayname);
const char *preptree(FD_nj_plot *fd_nj_plot);
char *check_alloc(int nbrelt, int sizelt);
const char *loadphylip(FD_nj_plot *fd_nj_plot, char *arbre, char *last_bootstrap);
struct noeud *unrootedset(FD_nj_plot *fd_nj_plot, char *deb, char *fin, branche **p_int_br);
char *nextpar(char *pospar);
const char *make_binary_or_unrooted(char *arbre);
int make_binary(char *arbre, char *debut, char *fin, int go_down);
void mydrawstring(double x, double y, char *nom, char option, int height);
void moveto(double x,double y);
void lineto(double x,double y);
int calc_brl_for_lengthless(struct noeud *centre, struct noeud *pere);
void add_value_downstream(struct noeud *centre, int value);
double place_midpoint_root(struct noeud *from, struct noeud *racine);
void parcourir_branches(struct noeud *centre, struct noeud *origine);
void process_branche(struct noeud *cote1, struct noeud *cote2, double length);
double get_length_down(struct noeud *, struct noeud *);
moments stat_from_node(struct noeud *pere, struct noeud *racine);
void runtree(FD_nj_plot *fd_nj_plot);
void mem_plot(FD_nj_plot *fd_nj_plot, struct noeud *pere, struct noeud *centre, double currx,
	double *curry);
void mem_point(FD_nj_plot *fd_nj_plot, double x, double y, int number);
void mem_nom(FD_nj_plot *fd_nj_plot, double x, double y, char *nom, char option);
void mem_trait(FD_nj_plot *fd_nj_plot, double xd, double yd, double xf, double yf);
char *get_br_label(FD_nj_plot *fd_nj_plot, struct noeud *a, struct noeud *b);
char *get_br_label_with_threshold(FD_nj_plot *fd_nj_plot, struct noeud *a, struct noeud *b);
int get_br_from_bouts(FD_nj_plot *fd_nj_plot, struct noeud *a, struct noeud *b);
void free_tree(FD_nj_plot *fd_nj_plot);
char *ecrit_arbre_parenth_unrooted(FD_nj_plot *fd_nj_plot, struct noeud *root);
char *ecrit_arbre_parenth(FD_nj_plot *fd_nj_plot, struct noeud *root);
char *recur_ecrit_arbre(FD_nj_plot *fd_nj_plot, struct noeud *centre, char *arbre, char *finarbre);
void removeroot(FD_nj_plot *fd_nj_plot);
double length_log_phys(double p);
double length_phys_log(double p);
double arrondi_echelle(double x);
double calc_echelle(double larg);
void draw_scale(FD_nj_plot *fd_nj_plot);
int calc_n_desc(struct noeud *pere);
void majuscules(char *p);
void treeplotw_callback(Fl_Widget *wgt, void *data);
void scrollnotu(FD_nj_plot *fd_nj_plot);
void zoom_callback(Fl_Widget *wgt, void *data);
void scroller_callback(Fl_Widget *wgt, void *data);
static void file_callback(Fl_Widget *wgt, void *data);
void remove_from_tree_menu(FD_nj_plot *fd_nj_plot, const char *name);
void add_to_tree_menu(FD_nj_plot *fd_nj_plot);
void physic_to_logic(double px, double py, double *lx, double *ly);
void tree_click_proc(tree_panel *panel, int mx, int my);
void disconnect_tree_windows(SEA_VIEW *view);
void reorder_following_tree(struct noeud *root, int notu, SEA_VIEW *view);
static void search_callback(Fl_Widget *wgt, void *data);
void bt_threshold_callback(Fl_Widget *wgt, void *data);
void midpoint_callback(Fl_Widget *wgt, void *data);
void edit_tree_header(Fl_Widget *wgt, void *data);
void set_win_size_callback(Fl_Widget *wgt, void *data);
int compare_newick_with_names(const char *tree, char **names, int notu, char **pname);
void edit_shape_callback(Fl_Widget *obj, void *data);
void select_clade_callback(Fl_Widget *obj, void *data);
void delete_clade_callback(Fl_Widget *obj, void *data);
void complete_edit_callback(Fl_Widget *obj, void *data);
void select_in_alignment(FD_nj_plot *fd_nj_plot);
void print_plot(FD_nj_plot *fd_nj_plot, bool to_ps_file, const char *directname = NULL);

//extern variables & functions
extern void help_callback(Fl_Widget *ob, void *data);
extern Fl_Window *use_initial_file(SEA_VIEW *view, char *masename, int doing_dnd);
extern void direct_help_callback(Fl_Widget *wgt, void *data);
extern void rooted_unrooted_callback(Fl_Widget *o, void *data);
extern void free_unrooted(FD_unrooted *data);
extern void unrooted_search(FD_unrooted *fd_unrooted, const char *select);
#ifdef __APPLE__
extern int add_windowmenuitem(const char *name, Fl_Window *w);
extern void rename_windowmenuitem(const char *name, int rank);
extern void delete_windowmenuitem(int rank);
extern int find_windowmenuitem(Fl_Window *w);
#endif


/* globals */
static int page_x_offset = 0;// +/- quantity to add to all horizontal drawing coordinates
static int page_y_offset = 0;// +/- quantity to add to all vertical drawing coordinates
char *end_br_length;
double	physx,physy,physx_min,physy_min,physx_corr,physy_corr;
/* window scaling variables */
double tek_xmin,tek_ymin,tek_dx,tek_dy;
double maxx, maxy, nexty;
int num_noeud, nextotu;
char list_ps_font_name[3][15] = { "Helvetica", "Courier", "Times"};
extern Fl_Paged_Device::Page_Format printout_pageformat;
/* variables globales pour memoriser la meilleure branche:
celle qui partage l'arbre en 2 parties les plus egales possibles en prof moyenne
*/
double current_best_diff, current_br_length, current_balance;
struct noeud *current_cote1=NULL, *current_cote2=NULL;
#define VERY_BIG 9.e99
static const char bad_tree[] = "Incorrect tree data.";


Fl_Window *treedraw(char *tree, SEA_VIEW *view, const char *name, int from_tree_menu)
/* returns the created window or NULL if none created
 */
{
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)calloc(1, sizeof(FD_nj_plot));
	fd_nj_plot->current_tree = tree;
	fd_nj_plot->view = view;
#ifdef unix
	putenv((char *)"LC_NUMERIC=C");
#endif
	fd_nj_plot->swap = 0;
	fd_nj_plot->tree_name = NULL;
	fd_nj_plot->show_bootstrap = 0;
	fd_nj_plot->plot_br_l = 0;
	fd_nj_plot->choix = show_tree;
	fd_nj_plot->need_runtree = FALSE;
	
	Fl_Window *w = new Fl_Window(530, 530);
	w->xclass(TREE_WINDOW);
	Fl_Group *g = new Fl_Group(0, 0, 528, 50);
  
  Fl_Menu_Bar* menubar = new Fl_Menu_Bar(3, 3, 130, 20);
  menubar->user_data(fd_nj_plot);
  int left = menubar->x() + menubar->w() + 5;
  
  static const Fl_Menu_Item fileitems[] = {
    {"Save to Trees menu", 0, file_callback, NULL, 0},
    {"Remove from Trees menu", 0, file_callback, NULL, 0},
    {"Save rooted tree", 0, file_callback, NULL, 0},
    {"Save unrooted tree", 0, file_callback, NULL, FL_MENU_DIVIDER},
    {"Print", FL_COMMAND | 'p', file_callback, NULL, 0},
    {"Save as "PDF_OR_PS"", 0, file_callback, NULL, 0},
    {"Save as SVG", 0, file_callback, NULL, 0},
    {"A4", 0, file_callback, NULL, FL_MENU_RADIO | 0},
    {"Letter", 0, file_callback, NULL, FL_MENU_RADIO | 0},
    {"Page count", 0, NULL, NULL, FL_SUBMENU | FL_MENU_DIVIDER},
    {"1", 0, file_callback, NULL, FL_MENU_RADIO | FL_MENU_VALUE},
    {"2", 0, file_callback, NULL, FL_MENU_RADIO},
    {"3", 0, file_callback, NULL, FL_MENU_RADIO},
    {"4", 0, file_callback, NULL, FL_MENU_RADIO},
    {"5", 0, file_callback, NULL, FL_MENU_RADIO},
    {"6", 0, file_callback, NULL, FL_MENU_RADIO},
    {"7", 0, file_callback, NULL, FL_MENU_RADIO},
    {"8", 0, file_callback, NULL, FL_MENU_RADIO},
    {"9", 0, file_callback, NULL, FL_MENU_RADIO},
    {"10", 0, file_callback, NULL, FL_MENU_RADIO},
    {"11", 0, file_callback, NULL, FL_MENU_RADIO},
    {"other value", 0, file_callback, NULL, 0},
    {0},
    {"Reorder following tree", 0, file_callback, NULL, 0},
    {"Select in alignment", 0, file_callback, NULL, FL_MENU_INACTIVE | FL_MENU_DIVIDER},
    {"Open tree or alignment", FL_COMMAND | 'o', file_callback, NULL, 0},
    {"New window", FL_COMMAND | 'n', file_callback, NULL, 0},
    {"Close window", FL_COMMAND | 'w', file_callback, NULL, 0}
  };
  fd_nj_plot->menu_file = new vlength_menu(menubar, "File", fileitems, sizeof(fileitems)/sizeof(Fl_Menu_Item));
  (fd_nj_plot->menu_file->get_menu() + (printout_pageformat == Fl_Paged_Device::A4 ? 7 : 8))->setonly();
    if(view == NULL || view->tot_seqs == 0) {
      (fd_nj_plot->menu_file->get_menu() + 23)->deactivate();
      fd_nj_plot->menu_file->get_menu()->deactivate();
    }
    if(!from_tree_menu) (fd_nj_plot->menu_file->get_menu() + 1)->deactivate();
    fd_nj_plot->page_count = 1;
  
  static const Fl_Menu_Item edititems[] = {
#ifdef MICRO
    {"Copy", FL_COMMAND | 'c', copy, NULL, 0},
#else
    {"Copy", 0, NULL, NULL, FL_MENU_INVISIBLE},
#endif
    {"Paste tree", FL_COMMAND | 'v', paste, NULL, 0},
    {"Find", FL_COMMAND | 'f', search_callback, NULL, 0},
    {"Again", FL_COMMAND | 'a', search_callback, NULL, 0},
    {"Edit tree header", 0, edit_tree_header, NULL, 0},
    {"Bootstrap threshold", 0, 0, NULL, FL_SUBMENU},
    {"0", 0, NULL, NULL, FL_MENU_DIVIDER},
    {"Edit threshold", 0, bt_threshold_callback, NULL, 0},
    {0},
    {"Root at tree center", 0, midpoint_callback, NULL, 0},
    {"Get or Set Window size", 0, set_win_size_callback, NULL, FL_MENU_DIVIDER},
    {"Edit tree shape", 0, edit_shape_callback, NULL, 0},
  };
  fd_nj_plot->center_rank = 9;
  fd_nj_plot->edit_shape_rank = 11;
  fd_nj_plot->menu_edit = new vlength_menu(menubar, "Edit", edititems, sizeof(edititems)/sizeof(Fl_Menu_Item));
  fd_nj_plot->bootstrap_threshold = 0;
  
  static const Fl_Menu_Item fontitems[] = {
    {"Helvetica", 0, change_ffam, NULL, FL_MENU_RADIO},
    {"Courier", 0, change_ffam, NULL, FL_MENU_RADIO},
    {"Times", 0, change_ffam, NULL, FL_MENU_RADIO | FL_MENU_DIVIDER | FL_MENU_VALUE},
    {"Bold", 0, change_ffam, NULL, FL_MENU_TOGGLE},
    {"Italic", 0, change_ffam, NULL, FL_MENU_TOGGLE | FL_MENU_DIVIDER},
    {"8", 0, change_ffam, NULL, FL_MENU_RADIO},
    {"10", 0, change_ffam, NULL, FL_MENU_RADIO},
    {"12", 0, change_ffam, NULL, FL_MENU_RADIO | FL_MENU_VALUE},
    {"14", 0, change_ffam, NULL, FL_MENU_RADIO},
    {"16", 0, change_ffam, NULL, FL_MENU_RADIO},
    {"18", 0, change_ffam, NULL, FL_MENU_RADIO},
    {"24", 0, change_ffam, NULL, FL_MENU_RADIO},
  };
  fd_nj_plot->menu_font = new vlength_menu(menubar, "Font", fontitems, sizeof(fontitems)/sizeof(Fl_Menu_Item));
  
	fd_nj_plot->l_button = new Fl_Check_Button(left,3,90, 20, "Br lengths");
	fd_nj_plot->l_button->value(fd_nj_plot->plot_br_l);
	fd_nj_plot->bt_button = new Fl_Check_Button(fd_nj_plot->l_button->x() + fd_nj_plot->l_button->w() + 5,3,85, 20, 
												"Bootstrap");
	fd_nj_plot->bt_button->value(fd_nj_plot->show_bootstrap);
	fd_nj_plot->root_unroot = new Fl_Choice(fd_nj_plot->bt_button->x() + fd_nj_plot->bt_button->w() + 2, 
										   fd_nj_plot->bt_button->y(), 98, 20, "");
	fd_nj_plot->root_unroot->add("squared");
	fd_nj_plot->root_unroot->add("circular");
	fd_nj_plot->root_unroot->add("cladogram");
	fd_nj_plot->root_unroot->value(0);
	fd_nj_plot->root_unroot->clear_visible_focus();
	Fl_Button *help_button = new Fl_Button(g->w() - 55,3,50, 20, "Help");
	help_button->callback(direct_help_callback, (void *)"Tree windows");

	fd_nj_plot->full = new Fl_Round_Button(3,26,47, 20, "Full");
	fd_nj_plot->full->type(FL_RADIO_BUTTON);
	fd_nj_plot->swap_button = new Fl_Round_Button(52,26,60, 20, "Swap");
	fd_nj_plot->swap_button->type(FL_RADIO_BUTTON);
	fd_nj_plot->new_outgroup = new Fl_Round_Button(110,26,73, 20, "Re-root");
	fd_nj_plot->new_outgroup->type(FL_RADIO_BUTTON);
  fd_nj_plot->select = new Fl_Round_Button(183,26,65, 20, "Select");
  fd_nj_plot->select->type(FL_RADIO_BUTTON);
	fd_nj_plot->subtree = new Fl_Round_Button(248,26,75, 20, "Subtree");
	fd_nj_plot->subtree->type(FL_RADIO_BUTTON);
	fd_nj_plot->full->setonly();
	fd_nj_plot->up = new Fl_Button(323, 26, 90, 20, "Subtree Up");
	fd_nj_plot->up->deactivate();
	fd_nj_plot->zoom = new Fl_Counter(fd_nj_plot->up->x() + fd_nj_plot->up->w() + 45, fd_nj_plot->up->y(), 70, 20, "Zoom");
	fd_nj_plot->zoom->callback(zoom_callback, fd_nj_plot);
	fd_nj_plot->zoom->type(FL_SIMPLE_COUNTER);
	fd_nj_plot->zoom->align(FL_ALIGN_LEFT);
	fd_nj_plot->zoom->value(1.);
	fd_nj_plot->zoom->bounds(1., 100.);
	fd_nj_plot->zoom->step(0.4);
	fd_nj_plot->zoom->clear_visible_focus();
	fd_nj_plot->zoomvalue = 1;
	g->end();
	g->resizable(NULL);
	
	Fl_Box *down = new Fl_Box(FL_DOWN_FRAME, 4, 50, w->w()-8, w->h()-54, NULL); 
	Fl_Window *w2 = (Fl_Window*)new Fl_Window(down->x()+3, down->y()+3, down->w()-6, down->h()-6);
	w->resizable(w2);
	w2->box(FL_FLAT_BOX);
	w2->color(FL_WHITE);
	fd_nj_plot->panel = new tree_panel(0, 0, w2->w(), w2->h());
	fd_nj_plot->panel->user_data(fd_nj_plot);
	fd_nj_plot->root_unroot->callback(rooted_unrooted_callback, fd_nj_plot);
	fd_nj_plot->scroller = new Fl_Scrollbar(w2->w() - 15, fd_nj_plot->panel->y(), 15, fd_nj_plot->panel->h()
#ifdef __APPLE__
						- 5
#endif
	);
	Fl_Box *b = new Fl_Box(0, 0, w2->w() - fd_nj_plot->scroller->w(), w2->h());
	b->hide();
	w2->resizable(b);
	fd_nj_plot->scroller->hide();
	fd_nj_plot->scroller->callback(scroller_callback, fd_nj_plot);
	fd_nj_plot->scroller->bounds(0, 1);
	fd_nj_plot->scroller->linesize(1);
	fd_nj_plot->scroller->slider_size(1);
	((Fl_Slider *)fd_nj_plot->scroller)->value(0);
	w2->end();
	fd_nj_plot->l_button->callback(toggle_br_lengths, fd_nj_plot->panel);
	fd_nj_plot->bt_button->callback(toggle_bootstrap, fd_nj_plot->panel);
	fd_nj_plot->font_family = FL_TIMES;
	fd_nj_plot->font_size = 12;
	fd_nj_plot->full->callback(operation_callback, fd_nj_plot->panel);
	fd_nj_plot->swap_button->callback(operation_callback, fd_nj_plot->panel);
	fd_nj_plot->new_outgroup->callback(operation_callback, fd_nj_plot->panel);
  fd_nj_plot->select->callback(operation_callback, fd_nj_plot->panel);
	fd_nj_plot->subtree->callback(operation_callback, fd_nj_plot->panel);
	fd_nj_plot->up->callback(subtreeup_callback, fd_nj_plot->panel);
	w->end();
	w->callback(treeplotw_callback, fd_nj_plot);
	if(name != NULL) {
		const char *mess;
		if( (mess = preptree(fd_nj_plot)) != NULL ) {
			fl_alert("%s", mess);
			fd_nj_plot->notu = 0;
			w->do_callback();
			return NULL;
			}
		else {
			fd_nj_plot->need_runtree = TRUE;
			if(!fd_nj_plot->has_br_length) {
				fd_nj_plot->l_button->deactivate();
				(fd_nj_plot->menu_edit->get_menu() + fd_nj_plot->center_rank)->hide();
				((Fl_Menu_Item *)fd_nj_plot->root_unroot->menu() + 2)->hide();
				}
			if(!fd_nj_plot->has_internal)fd_nj_plot->bt_button->deactivate();
		  (fd_nj_plot->menu_edit->get_menu() + 1)->deactivate();
			fd_nj_plot->tree_name = strdup(name);
			}
		}
	else fd_nj_plot->tree_name = strdup("no tree");
	w->label(fd_nj_plot->tree_name);
#if defined(WIN32)
	w->icon((char *)LoadIcon(fl_display, MAKEINTRESOURCE(100)));
#endif
	w->show();
#ifndef MICRO
	w->hotspot(w);
#endif
#ifdef __APPLE__
	add_windowmenuitem(w->label(), w);
#endif
	return w;
}


void tree_panel::draw(void)
{
	static int old_w = 0;
	static int old_h = 0;
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)this->user_data();
	if(fd_nj_plot->notu == 0) return;
	fl_font(fd_nj_plot->font_family, fd_nj_plot->font_size);
	fl_color(FL_BLACK);
	if(fd_nj_plot->need_runtree || this->w() != old_w || this->h() != old_h) {
		old_w = this->w();
		old_h = this->h();
		physx = this->w();
		physy = this->h();
		maxy = 1000.;
		runtree(fd_nj_plot);
		fd_nj_plot->need_runtree = FALSE;
		fd_nj_plot->swap = 0;
	}
	do_plot(fd_nj_plot, FALSE);
}

#ifdef MICRO
extern void frame_and_draw_unrooted(FD_unrooted *fd_unrooted);
static void copy(Fl_Widget *wgt, void *data)
{
  FD_nj_plot *fd_nj_plot = (FD_nj_plot *)wgt->user_data();
  Fl_Widget *g;
  if(fd_nj_plot->fd_unrooted != NULL) 
    g = ((FD_unrooted*)(fd_nj_plot->fd_unrooted))->unrooted_plot;
  else
    g = fd_nj_plot->panel;
  Fl_Surface_Device *current = Fl_Surface_Device::surface();
  Fl_Copy_Surface *copy_surf = new Fl_Copy_Surface(
#ifdef __APPLE__
						   fd_nj_plot->fd_unrooted == NULL, 
#endif
						   g->w(), g->h());
  copy_surf->set_current();
  if(fd_nj_plot->fd_unrooted != NULL) {
    frame_and_draw_unrooted((FD_unrooted *)fd_nj_plot->fd_unrooted);
    }
  else {
    g->draw();
    }
  delete copy_surf;
  current->set_current();
}
#endif // MICRO

static void paste(Fl_Widget *wgt, void *data)
{
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)wgt->user_data();
	Fl::paste(*fd_nj_plot->panel, 1);
}


char *prepare_ps_or_pdf_font(int font_num)
{
	/* prepare PDF name of font */
	static char current_ps_font[80];
	int modulo = font_num % 4;
	int use_bold = modulo == 1 || modulo == 3;
	int use_italic = modulo >= 2;
	int fam_num = font_num/4;
	strcpy(current_ps_font, list_ps_font_name[fam_num]);
	if( use_bold && use_italic ) {
		if(fam_num == times) strcat(current_ps_font,"-BoldItalic");
		else strcat(current_ps_font,"-BoldOblique");
		}
	else if( use_bold ) strcat(current_ps_font,"-Bold");
	else if( use_italic )  {
			if(fam_num == times) strcat(current_ps_font,"-Italic");
			else strcat(current_ps_font,"-Oblique");
		}
	else if(fam_num == times) strcat(current_ps_font,"-Roman");
	return current_ps_font;
}


void toggle_br_lengths(Fl_Widget *wgt, void *data)
{
	tree_panel *g = (tree_panel *)data;
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)g->user_data();
	fd_nj_plot->plot_br_l = ((Fl_Check_Button *)wgt)->value();
	fd_nj_plot->need_runtree = TRUE;
	g->window()->redraw();	
}

void toggle_bootstrap(Fl_Widget *wgt, void *data)
{
	tree_panel *g = (tree_panel *)data;
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)g->user_data();
	fd_nj_plot->show_bootstrap = ((Fl_Check_Button *)wgt)->value();
	fd_nj_plot->need_runtree = TRUE;
	g->window()->redraw();	
}

void change_ffam(Fl_Widget *wgt, void *data)
{
  FD_nj_plot *fd_nj_plot = (FD_nj_plot *)wgt->user_data();
  int val = ((Fl_Menu_*)wgt)->mvalue() - fd_nj_plot->menu_font->get_menu();
	if(val < 3) fd_nj_plot->font_family = FL_HELVETICA + 4 * val;
	else if (val >= 5) sscanf( ((Fl_Menu_ *)wgt)->text(), "%d", &fd_nj_plot->font_size);
	fd_nj_plot->font_family = 4*(fd_nj_plot->font_family/4);
	const Fl_Menu_Item* menu = fd_nj_plot->menu_font->get_menu();
	int bold = (menu[3].flags & FL_MENU_VALUE);
	int italic = (menu[4].flags & FL_MENU_VALUE);
	if(bold && italic) fd_nj_plot->font_family += 3;
	else if (bold)  fd_nj_plot->font_family += 1;
	else if (italic)  fd_nj_plot->font_family += 2;
	if( fd_nj_plot->fd_unrooted != NULL) {
		FD_unrooted *fd_unrooted = (FD_unrooted *)fd_nj_plot->fd_unrooted;
		fd_unrooted->current_font = fd_nj_plot->font_family;
		fd_unrooted->font_size = fd_nj_plot->font_size;
		fd_unrooted->comp_phys_bounds = TRUE;
		fd_unrooted->unrooted_plot->window()->redraw();
		}
	else {
		fd_nj_plot->need_runtree = TRUE;
		fd_nj_plot->panel->window()->redraw();
		}
}

int tree_panel::handle(int event)
{
FD_nj_plot *fd_nj_plot = (FD_nj_plot *)this->user_data();
const char *p;
char *q;
Fl_Window *w;
int my = Fl::event_y();
static int start_y;
static int start_sy;
static int changed_cursor = FALSE;
			
switch (event)
    {
	case FL_PUSH:
		tree_click_proc(this, Fl::event_x(), Fl::event_y());
		start_y = my;
		start_sy = fd_nj_plot->scroller->value();
		break;
	case FL_DRAG:
			if(fd_nj_plot->zoomvalue > 1) {
				if(!changed_cursor) this->window()->cursor(FL_CURSOR_NS); 
				changed_cursor = TRUE;
				int val = (int)fd_nj_plot->scroller->clamp(start_sy - 
						(my - start_y) * fd_nj_plot->scroller->maximum() / (fd_nj_plot->zoomvalue - 1) / 
						(this->h()-2.6*fd_nj_plot->char_height) );
				((Fl_Slider *)fd_nj_plot->scroller)->value(val);
				fd_nj_plot->scroller->do_callback();
			}
			break;
	case FL_RELEASE:
			if(fd_nj_plot->zoomvalue > 1) {
				fl_reset_cursor(this->window());
				changed_cursor = FALSE;
			}
			break;
	case FL_PASTE:
		p = Fl::event_text();
		fd_nj_plot->current_tree = (char *)malloc(strlen(p) + 1);
		q = fd_nj_plot->current_tree;
		while(*p != 0) {
			if(*p != '\n' && *p != '\n') *q++ = *p;
			p++;
			}
		*q = 0;
		if(preptree(fd_nj_plot) != NULL) {
			fl_alert("Clipboard does not contain Newick-formatted tree");
			break;
			}
		fd_nj_plot->need_runtree = TRUE;
		if(!fd_nj_plot->has_br_length) {
			fd_nj_plot->l_button->deactivate();
			(fd_nj_plot->menu_edit->get_menu() + fd_nj_plot->center_rank)->hide();
			((Fl_Menu_Item *)fd_nj_plot->root_unroot->menu() + 2)->hide();
			} 
		if(!fd_nj_plot->has_internal)fd_nj_plot->bt_button->deactivate();
	(fd_nj_plot->menu_edit->get_menu() + 1)->deactivate();
		fd_nj_plot->tree_name = strdup("pasted tree");
		w = fd_nj_plot->full->window();
		w->label(fd_nj_plot->tree_name);
#ifdef __APPLE__
		rename_windowmenuitem(w->label(), find_windowmenuitem(w));
#endif
		fd_nj_plot->panel->window()->redraw();
		break;
	default :
		return 0; // other events are not processed here
	}
	return 1; // from processed events
}


void scrollnotu(FD_nj_plot *fd_nj_plot)
{
	int lines;
	float old;
	int count = fd_nj_plot->subtree_notu;
	
	old = fd_nj_plot->scroller->value() / (float)fd_nj_plot->scroller->maximum();
	lines = (int)((count + 1) * (1 - 1/fd_nj_plot->zoomvalue) + 0.5); 
	if(lines < 3) lines = 3;
	fd_nj_plot->scroller->maximum(lines);
	((Fl_Slider *)fd_nj_plot->scroller)->value(old * lines);
	fd_nj_plot->scroller->slider_size(1/fd_nj_plot->zoomvalue);
}


void zoom_callback(Fl_Widget *wgt, void *data)
{
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)data;
	if(((Fl_Counter *)wgt)->value() > fd_nj_plot->zoomvalue) fd_nj_plot->zoomvalue *= 1.4;
	else fd_nj_plot->zoomvalue /= 1.4;
	fd_nj_plot->zoomvalue = ((Fl_Counter *)wgt)->clamp(fd_nj_plot->zoomvalue);
	((Fl_Counter *)wgt)->value(fd_nj_plot->zoomvalue);
	if(fd_nj_plot->zoomvalue <= 1.1) {
		fd_nj_plot->panel->size(fd_nj_plot->panel->parent()->w(), 
										 fd_nj_plot->panel->h());
		fd_nj_plot->scroller->hide();
	}
	else {
		fd_nj_plot->panel->size(fd_nj_plot->panel->parent()->w() - 15, 
										 fd_nj_plot->panel->h());
		fd_nj_plot->scroller->show();
	}
	scrollnotu(fd_nj_plot);
	fd_nj_plot->panel->parent()->redraw();
}

void scroller_callback(Fl_Widget *wgt, void *data)
{
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)data;
	fd_nj_plot->panel->parent()->redraw();
}

static void file_callback(Fl_Widget *wgt, void *data)
{
  FD_nj_plot *fd_nj_plot = (FD_nj_plot *)wgt->user_data();
	Fl_Menu_Item *item = fd_nj_plot->menu_file->get_menu();
	int reponse =  ((Fl_Menu_*)wgt)->mvalue() - item;
	if(reponse == 0) {//save to tree menu
		add_to_tree_menu(fd_nj_plot);
	}
	else if(reponse == 1) {//remove from tree menu
		remove_from_tree_menu(fd_nj_plot, wgt->window()->label());
	}
	else if(reponse == 2 /*rooted*/ || reponse == 3 /*unrooted*/) {//save to file
        int saved_notu = fd_nj_plot->subtree_center != NULL ? fd_nj_plot->subtree_notu : fd_nj_plot->notu;
		if( (reponse == 2 && saved_notu < 2) || (reponse == 3 && saved_notu < 3) ) return;
		Fl_Native_File_Chooser *chooser = new Fl_Native_File_Chooser();
		chooser->type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
	  chooser->options(Fl_Native_File_Chooser::SAVEAS_CONFIRM | chooser->options());
		chooser->title("Set tree filename");   
	  chooser->preset_file(fd_nj_plot->tree_name);
		char *filename = run_and_close_native_file_chooser(chooser);
		if(filename == NULL) return;
        struct noeud *center = fd_nj_plot->subtree_center != NULL ? fd_nj_plot->subtree_center : fd_nj_plot->racine;
	  char *tree;
	  if(reponse == 2) tree = ecrit_arbre_parenth(fd_nj_plot, center);
	  else tree = ecrit_arbre_parenth_unrooted(fd_nj_plot, center);
	  FILE *out = fopen(filename, "w");
          if(out) {
	    fputs(tree, out);
	    fputs("\n", out);
	    fclose(out);
	    free(tree);
	    }
	  else fl_alert("Incorrect output filename: %s", filename);
	  }
	else if(reponse == 4) {//print
		print_plot(fd_nj_plot, false);
	}
	else if(reponse == 5) {//save to PDF/PS
	  print_plot(fd_nj_plot, true);
	  }
	else if(reponse == 6) {// SVG
	  extern void svg_tree_save(FD_nj_plot *fd_nj_plot);
	  svg_tree_save(fd_nj_plot);
	}
	else if(reponse == 7) {// A4
	  printout_pageformat = Fl_Paged_Device::A4;
	}
	else if(reponse == 8) {// Letter
	  printout_pageformat = Fl_Paged_Device::LETTER;
	}
	else if(reponse >= 10 && reponse <= 21) {// page counts
		if(reponse >= 10 && reponse <= 19) {// fixed page counts
			fd_nj_plot->page_count = reponse - 9;
		}
		else if(reponse == 20) {// variable page count
			sscanf((item + 20)->label(), "%d", &fd_nj_plot->page_count);
		}
		else if(reponse == 21) {
			int newval;
			const char *reply = fl_input("Enter page count (>= 11)", "11");
			if(reply == NULL) return;
			sscanf(reply, "%d", &newval);
			if(newval >= 1) fd_nj_plot->page_count = newval;
			if(newval >= 11) {
				//menu_file->replace(20, reply);
			  if (strcmp((item + 20)->label(), "11") != 0) free((void*)(item + 20)->label());
			  (item + 20)->label(strdup(reply));
				(item + 20)->setonly();
				}
			else if(newval >= 1) {
				(item + 9 + fd_nj_plot->page_count)->setonly();
				}
			}
		char tmp[20];
		sprintf(tmp, "Page count (%d)", fd_nj_plot->page_count);
		//menu_file->replace(9, tmp);
	  if (strcmp((item + 9)->label(), "Page count") != 0) free((void*)(item + 9)->label());
	  (item + 9)->label(strdup(tmp));
	}
	else if(reponse == 23) {
		reorder_following_tree(fd_nj_plot->racine, fd_nj_plot->notu, fd_nj_plot->view);
	}
	else if(reponse == 24) {
		select_in_alignment(fd_nj_plot);
	}
	else if(reponse == 25) {//open tree/alignment
		Fl_Native_File_Chooser *chooser = new Fl_Native_File_Chooser();
		chooser->type(Fl_Native_File_Chooser::BROWSE_FILE);
		chooser->title("Choose a Newick tree or alignment file");                        
		char *filename = run_and_close_native_file_chooser(chooser);
		if(filename == NULL) return;
		Fl_Window *w = use_initial_file(fd_nj_plot->view, filename, FALSE);
		//close the opening window if it was empty and a new tree window was successfully created
		const char *c;
		if(w != NULL && fd_nj_plot->notu == 0 && (c = w->xclass()) != NULL && strcmp(c, TREE_WINDOW) == 0) 
			fd_nj_plot->full->window()->do_callback();
	}
	else if(reponse == 26) {//new tree window
		treedraw(NULL, fd_nj_plot->view, NULL, FALSE);
	}
	else if(reponse == 27) {//close
	  wgt->window()->do_callback();
	}
}

void remove_from_tree_menu(FD_nj_plot *fd_nj_plot, const char *name)
{
  SEA_VIEW *view = fd_nj_plot->view;
	if(view == NULL) return;
	vlength_menu *menu_trees = view->menu_trees;
	Fl_Menu_Item *item;
	Fl_Menu_Item *items = menu_trees->vitem(0);
	if( (item = menu_trees->find_item(name)) == NULL) return;
	int rank = item - items;
	menu_trees->remove(rank);
	items = fd_nj_plot->menu_file->get_menu();
	items->activate();
	(items + 1)->deactivate();
	free(view->trees[rank]);
	(view->tot_trees)--;
	for(int i = rank; i < view->tot_trees; i++)  view->trees[i] = view->trees[i + 1];
	if(view->tot_trees == 0) free(view->trees);
}

void add_to_tree_menu(FD_nj_plot *fd_nj_plot)
{
	SEA_VIEW *view = fd_nj_plot->view;
	char *p, *fulltree;
	if(view == NULL) return;
	char *name = fd_nj_plot->tree_name;
	vlength_menu *menu_trees = view->menu_trees;
	name = (char *)fl_input("Enter tree name:", name);
	if(name == NULL) return;
	free(fd_nj_plot->tree_name);
	char *newname = NULL;
	int count=2;
	if( menu_trees->find_item(name) != NULL) {//check if same name already exists
		newname = new char[strlen(name) + 5];
		do sprintf(newname, "%s_%d", name, count++);
		while( menu_trees->find_item(newname) != NULL);
		name = newname;
	}
  fd_nj_plot->tree_name = strdup(name);
  fd_nj_plot->full->window()->label( fd_nj_plot->tree_name);
  menu_trees->add(name, trees_callback, NULL, 0);
  int rank = menu_trees->vlength();
  menu_trees->vitem(rank - 1)->labelfont(FL_HELVETICA_ITALIC);
	if(newname != NULL) delete newname;
	if(view->tot_trees == 0) view->trees = (char **)malloc(sizeof(char *));
	else view->trees = (char **)realloc(view->trees, (view->tot_trees + 1) * sizeof(char *));
	p = ecrit_arbre_parenth(fd_nj_plot, fd_nj_plot->racine);
	if(fd_nj_plot->tree_label != NULL) {
		fulltree = (char *)malloc(strlen(p) + strlen(fd_nj_plot->tree_label) + 3);
		sprintf(fulltree, "[%s]%s", fd_nj_plot->tree_label, p);
		free(p);
		}
	else fulltree = p;
	view->trees[view->tot_trees] = fulltree;
	view->tot_trees++;
  (fd_nj_plot->menu_file->get_menu() + 1)->activate();
}

void treeplotw_callback(Fl_Widget *wgt, void *data)
{
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)data;
	if(fd_nj_plot->fd_unrooted != NULL) {
		FD_unrooted *fd_unrooted = (FD_unrooted *)fd_nj_plot->fd_unrooted;
		free_unrooted(fd_unrooted);
		}
	if(fd_nj_plot != NULL) {
		free_tree(fd_nj_plot);
	  delete fd_nj_plot->menu_file;
	  delete fd_nj_plot->menu_edit;
	  delete fd_nj_plot->menu_font;
		free(fd_nj_plot);
		}
#ifdef __APPLE__
	int rank = find_windowmenuitem((Fl_Window *)wgt);
	if(rank > 0) delete_windowmenuitem(rank);
#endif
//when a callback destroys its own widget delete is bad; hide()+Fl::delete_widget is to be called instead
	wgt->hide();
	Fl::delete_widget(wgt);
}

void subtreeup_callback(Fl_Widget *wgt, void *data)
{
	tree_panel *g = (tree_panel *)data;
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)g->user_data();
	fd_nj_plot->subtree_center = fd_nj_plot->subtree_ascend;
	fd_nj_plot->subtree_ascend = fd_nj_plot->subtree_center->v3;
	if(fd_nj_plot->subtree_ascend == NULL) {
		fd_nj_plot->subtree_center = NULL;
		wgt->deactivate();
		fd_nj_plot->new_outgroup->activate();
		((Fl_Menu_Item *)fd_nj_plot->menu_edit->get_menu() + fd_nj_plot->center_rank)->activate();
		fd_nj_plot->full->setonly();
	  (fd_nj_plot->menu_file->get_menu()+23)->activate();
	  (fd_nj_plot->menu_file->get_menu()+24)->deactivate();
		fd_nj_plot->subtree_notu = fd_nj_plot->notu;
		if(fd_nj_plot->root_unroot != NULL) fd_nj_plot->root_unroot->activate();
	  (fd_nj_plot->menu_file->get_menu()+2)->label("Save rooted tree");
	  (fd_nj_plot->menu_file->get_menu()+3)->label("Save unrooted tree");
	}
	else fd_nj_plot->subtree_notu = calc_n_desc(fd_nj_plot->subtree_center);
	fd_nj_plot->need_runtree = TRUE;
	fd_nj_plot->swap_button->value(0);
	fd_nj_plot->subtree->value(0);
  fd_nj_plot->select->value(0);
	fd_nj_plot->choix = show_tree;
	if(fd_nj_plot->has_internal) fd_nj_plot->bt_button->activate();
	if(fd_nj_plot->has_br_length) fd_nj_plot->l_button->activate();
	if(fd_nj_plot->select_clade_button != NULL) fd_nj_plot->select_clade_button->activate();
	g->window()->redraw();
}

void operation_callback(Fl_Widget *wgt, void *data)
{
	tree_panel *g = (tree_panel *)data;
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)g->user_data();
	((Fl_Button *)wgt)->setonly();
	if(wgt == fd_nj_plot->swap_button) {
		fd_nj_plot->choix = permutation;
		fd_nj_plot->show_bootstrap = FALSE;
		fd_nj_plot->plot_br_l = FALSE;
		fd_nj_plot->l_button->deactivate();
		fd_nj_plot->l_button->value(0);
		fd_nj_plot->bt_button->deactivate();
		fd_nj_plot->bt_button->value(0);
		if(fd_nj_plot->select_clade_button != NULL) fd_nj_plot->select_clade_button->activate();
		}
	else if(wgt == fd_nj_plot->new_outgroup) {
		fd_nj_plot->choix = depl_racine;
		fd_nj_plot->show_bootstrap = FALSE;
		fd_nj_plot->plot_br_l = FALSE;
		fd_nj_plot->l_button->deactivate();
		fd_nj_plot->l_button->value(0);
		fd_nj_plot->bt_button->deactivate();
		fd_nj_plot->bt_button->value(0);
	  (fd_nj_plot->menu_file->get_menu()+23)->deactivate(); // Re-order following tree
	}
	else if(wgt == fd_nj_plot->subtree) {
		fd_nj_plot->choix = subtree;
		fd_nj_plot->show_bootstrap = FALSE;
		fd_nj_plot->plot_br_l = FALSE;
		((Fl_Menu_Item *)fd_nj_plot->menu_edit->get_menu() + fd_nj_plot->center_rank)->deactivate();
		fd_nj_plot->new_outgroup->deactivate();
		fd_nj_plot->l_button->deactivate();
		fd_nj_plot->l_button->value(0);
		fd_nj_plot->bt_button->deactivate();
		fd_nj_plot->bt_button->value(0);
		if(fd_nj_plot->root_unroot != NULL) fd_nj_plot->root_unroot->deactivate();
	}
	else if(wgt == fd_nj_plot->select) {
	  fd_nj_plot->choix = selection;
	  fd_nj_plot->l_button->deactivate();
	  fd_nj_plot->l_button->value(0);
	  fd_nj_plot->bt_button->deactivate();
	  fd_nj_plot->bt_button->value(0);
	  fd_nj_plot->show_bootstrap = FALSE;
	  fd_nj_plot->plot_br_l = FALSE;
	  (fd_nj_plot->menu_file->get_menu()+23)->deactivate(); // Re-order following tree
	  }
	else {//full
		fd_nj_plot->choix = show_tree;
		fd_nj_plot->subtree_notu = fd_nj_plot->notu;
		if(fd_nj_plot->subtree_center != NULL) scrollnotu(fd_nj_plot);
		fd_nj_plot->subtree_center = NULL;
		fd_nj_plot->new_outgroup->activate();
		((Fl_Menu_Item *)fd_nj_plot->menu_edit->get_menu() + fd_nj_plot->center_rank)->activate();
		fd_nj_plot->up->deactivate();
	  if(fd_nj_plot->view != NULL) (fd_nj_plot->menu_file->get_menu()+23)->activate();
	  (fd_nj_plot->menu_file->get_menu()+24)->deactivate();
		if(fd_nj_plot->has_internal) fd_nj_plot->bt_button->activate();
		if(fd_nj_plot->has_br_length) fd_nj_plot->l_button->activate();
		if(fd_nj_plot->root_unroot != NULL) fd_nj_plot->root_unroot->activate();
	  (fd_nj_plot->menu_file->get_menu()+2)->label("Save rooted tree");
	  (fd_nj_plot->menu_file->get_menu()+3)->label("Save unrooted tree");
	}
	fd_nj_plot->need_runtree = TRUE;
	g->window()->redraw();
}

void select_clade(struct noeud *n, SEA_VIEW *view, int on)
/* select (on is true) or deselect (on is false) all seqs in alignment placed below node n in tree
 */
{
  if (n == NULL) return;
  select_clade(n->v1, view, on);
  select_clade(n->v2, view, on);
  char *p = n->nom;
  if (n->v1 == NULL) { // a leaf
    int num;
    for ( num = 0; num < view->tot_seqs; num++) { // find what sequence it is in alignment
      if (strcmp(p + 1, view->seqname[num]) == 0) {
	if ((view->sel_seqs[num] && !on) || (!view->sel_seqs[num] && on)) select_deselect_seq(view, num+1, TRUE);
	break;
	}
      }
    }
  if (*p) *p = (on ? '(' : ')');
}

void tree_click_proc(tree_panel *panel, int mx, int my)
{
	double eps, x, y, epsx, epsy, px, py;
	int i, found=0, node_num;
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *) panel->user_data();
	if(fd_nj_plot->notu == 0) return;
	if(fd_nj_plot->choix != permutation && fd_nj_plot->choix != depl_racine && fd_nj_plot->choix != subtree && 
		fd_nj_plot->choix != selection &&fd_nj_plot->choix != prune_clade && fd_nj_plot->choix != prune_clade_found) 
		return;
	eps = fd_nj_plot->char_height/2.;
	x = mx - panel->x();
	my -= panel->y();
	y = panel->h() - my;
	//next 5 statements so that physic_to_logic apply to the clicked window
	tek_dx = fd_nj_plot->tek_dx;
	tek_dy = fd_nj_plot->tek_dy;
	tek_ymin = fd_nj_plot->tek_ymin;
	physx_min = fd_nj_plot->ascent;
	physy_min = 0.6 * fd_nj_plot->char_height;
	physic_to_logic(x, y, &x, &y); 
	epsx = eps / tek_dx;
	epsy = eps / tek_dy;
	for(i=0; i<=fd_nj_plot->totpoints; i++ ) {
		px = (fd_nj_plot->points+i)->x; py = (fd_nj_plot->points+i)->y;
		if(x < px || x > px + epsx) continue;
		if(y < py - epsy/2 || y > py + epsy/2) continue;
		found=1;
		break;
	}
	if(!found)return;
	node_num=(fd_nj_plot->points+i)->number;
	if(fd_nj_plot->choix==depl_racine) {
		if(node_num >= 0 && node_num <= 2*fd_nj_plot->notu - 3 && 
		   node_num != fd_nj_plot->root_num) {
			fd_nj_plot->root_num = node_num;
			removeroot(fd_nj_plot);
		} 
	}
	else if(fd_nj_plot->choix==permutation) {
		if(node_num >= fd_nj_plot->notu && node_num <= 2*fd_nj_plot->notu - 2) 
			fd_nj_plot->swap = node_num;
		else
			fd_nj_plot->swap = 0;
	}
	else if(fd_nj_plot->choix==subtree) {
		if(node_num < fd_nj_plot->notu || node_num > 2*fd_nj_plot->notu - 2) return;
		fd_nj_plot->subtree_center = fd_nj_plot->tabtax[node_num];
		fd_nj_plot->subtree_ascend = fd_nj_plot->subtree_center->v3;
		fd_nj_plot->subtree_notu = calc_n_desc(fd_nj_plot->subtree_center);
		scrollnotu(fd_nj_plot);
		fd_nj_plot->choix = show_tree;
		fd_nj_plot->subtree->value(0);
		fd_nj_plot->up->activate();
		if(fd_nj_plot->select_clade_button != NULL) fd_nj_plot->select_clade_button->activate();
		if(fd_nj_plot->has_br_length) {
			fd_nj_plot->l_button->activate();
		}
		if(fd_nj_plot->has_internal) {
			fd_nj_plot->bt_button->activate();
		} 
	  (fd_nj_plot->menu_file->get_menu()+23)->deactivate();
	  (fd_nj_plot->menu_file->get_menu()+24)->activate();
	  (fd_nj_plot->menu_file->get_menu()+2)->label("Save rooted subtree");
	  (fd_nj_plot->menu_file->get_menu()+3)->label("Save unrooted subtree");
	}
	else if(fd_nj_plot->choix == selection) {
	  SEA_VIEW *view = fd_nj_plot->view;
	  if (!view) return;
	  if(node_num >= fd_nj_plot->notu && node_num <= 2*fd_nj_plot->notu - 2) {
	    int on = fd_nj_plot->tabtax[node_num]->nom[0] == ')';
	    select_clade(fd_nj_plot->tabtax[node_num], view, on);
	    view->DNA_obj->redraw();
	    panel->window()->redraw();
	    return;
	    }
	  for (int num = 0; num < view->tot_seqs; num++) {
	    if (strcmp(fd_nj_plot->tabtax[node_num]->nom + 1, view->seqname[num]) == 0) {
	      select_deselect_seq(view, num+1, TRUE);
	      fd_nj_plot->tabtax[node_num]->nom[0] = (view->sel_seqs[num] ? '(' : ')');
	      extern void set_and_show_new_cursor_seq(SEA_VIEW *view, int new_pos);
	      if (num+1 < view->first_seq || num+1 >= view->first_seq + view->tot_lines)
		set_and_show_new_cursor_seq(view, num+1);
	      view->DNA_obj->redraw();
	      panel->window()->redraw();
	      break;
	      }
	    }
	  return;
	  }
	else if(fd_nj_plot->choix==prune_clade) {
		fd_nj_plot->prune_clade_node = fd_nj_plot->tabtax[node_num];
		fd_nj_plot->choix = prune_clade_found;
		fd_nj_plot->select_clade_button->activate();
		fd_nj_plot->delete_clade_button->activate();
		}
	else if(fd_nj_plot->choix==prune_clade_found) {
		struct noeud *sister, *parent, *gparent;//move selected clade to its target branch
		parent = fd_nj_plot->prune_clade_node->v3;
		sister = parent->v1 == fd_nj_plot->prune_clade_node ? parent->v2 : parent->v1;
		gparent = parent->v3;
		if(gparent != NULL) {
			if(gparent->v1 == parent) { gparent->v1 = sister; gparent->l1 = 1; }
			else { gparent->v2 = sister; gparent->l2 = 1; }
			sister->v3 = gparent;
			sister->l3 = 1;
			gparent = fd_nj_plot->tabtax[node_num]->v3;
			parent->v1 = fd_nj_plot->prune_clade_node;
			parent->l1 = 1;
			fd_nj_plot->prune_clade_node->v3 = parent;
			fd_nj_plot->prune_clade_node->l3 = 1;
			parent->v2 = fd_nj_plot->tabtax[node_num];
			parent->l2 = 1;
			fd_nj_plot->tabtax[node_num]->v3 = parent;
			fd_nj_plot->tabtax[node_num]->l3 = 1;
			parent->v3 = gparent;
			parent->l3 = 1;
			if(gparent->v1 == fd_nj_plot->tabtax[node_num]) { gparent->v1 = parent; gparent->l1 = 1; }
			else { gparent->v2 = parent; gparent->l2 = 1; }
			}
		else {
			parent->v1 = sister->v1; parent->l1 = 1;
			parent->v2 = sister->v2; parent->l2 = 1;
			parent->v1->v3 = parent; parent->v1->l3 = 1;
			parent->v2->v3 = parent; parent->v2->l3 = 1;
			gparent = fd_nj_plot->tabtax[node_num]->v3;
			if(gparent->v1 == fd_nj_plot->tabtax[node_num]) { gparent->v1 = sister; gparent->l1 = 1;}
			else { gparent->v2 = sister; gparent->l2 = 1;}
			sister->v3 = gparent; sister->l3 = 1;
			sister->v1 = fd_nj_plot->prune_clade_node; sister->l1 = 1;
			sister->v2 = fd_nj_plot->tabtax[node_num]; sister->l2 = 1;
			fd_nj_plot->prune_clade_node->v3 = sister; fd_nj_plot->prune_clade_node->l3 = 1;
			fd_nj_plot->tabtax[node_num]->v3 = sister; fd_nj_plot->tabtax[node_num]->l3 = 1;
			}
		calc_brl_for_lengthless(fd_nj_plot->racine, NULL);
		}
	fd_nj_plot->need_runtree = TRUE;
	panel->window()->redraw();
}


double length_log_phys(double p)
{
return p * tek_dx;
}

double length_phys_log(double p)
{
return  p / tek_dx;
}


double arrondi_echelle(double x)
{ /* arrondi x a une valeur 1, 2, 5 pour echelle */
double l, n;
int r;
static int corresp[] = {1,1,2,2,5,5,5,10,10,10,10,10};
                     /* 0,1,2,3,4,5,6, 7, 8, 9,10,11 */
l = log10(x);
n = floor(l);
l = x * pow(10., -n);  /* 10. plutot que 10 necessaire pour alpha! */
r = myrint(l); r = corresp[r];
return r * pow(10., n);  /* 10. plutot que 10 necessaire pour alpha! */
}


void scale_window(double lxmin, double lxmax, double lymin, double lymax,
 double pxmin, double pxmax, double pymin, double pymax)
/* to scale the plot window for logical coords l... in physical coords p... */
{
tek_xmin=lxmin; tek_ymin=lymin; 
tek_dx = (pxmax-pxmin)/(lxmax-tek_xmin < 1e-4 ? 1e-4 : lxmax-tek_xmin);
tek_dy = (pymax-pymin)/(lymax-tek_ymin);
}


void ch_echelle(double lx, double ly, double *px, double *py)
/* conversion coord logique lx,ly en coord physique px,py */
{
*px = (lx-tek_xmin)*tek_dx + physx_min;
*py = (ly-tek_ymin)*tek_dy + physy_min;
}

void physic_to_logic(double px, double py, double *lx, double *ly)
/* conversion coord physique px,py en coord logique lx,ly */
{
	*lx = (px - physx_min)/tek_dx + tek_xmin;
	*ly = (py - physy_min)/tek_dy + tek_ymin;
}


double calc_echelle(double larg)
{ /* rend taille logique pour echelle optimale */
double log_val, phys_val;
phys_val = larg/10;
log_val = length_phys_log(phys_val);
log_val = arrondi_echelle(log_val);
return log_val;
}


void draw_scale(FD_nj_plot *fd_nj_plot)
{
	char ech_name[20];
	double phys_w, y, xd, xf, lc;
	double log_val;

	y = physy - 1.1 * fd_nj_plot->char_height;
	if(fd_nj_plot->choix == prune_clade) {
		fl_color(FL_RED);
		dir_moveto( physx * 0.01, y ); //sd be placed here to avoid pdf error
		plotstring("Click on a square to select sequence group or \"End edit\".");
		fl_color(FL_BLACK);
	}
	else if(fd_nj_plot->choix == prune_clade_found) {
		fl_color(FL_BLUE);
		dir_moveto( physx * 0.01, y ); 
		plotstring("Click on a square to move selection or \"Select group|Delete group|End edit\".");
		fl_color(FL_BLACK);
	}
	else if(fd_nj_plot->tree_label != NULL) {
		dir_moveto( physx * 0.01, y ); 
		plotstring(fd_nj_plot->tree_label);
	}
	
	log_val = calc_echelle(physx);	
	phys_w = myrint(length_log_phys(log_val));
	fl_font(FL_TIMES, 12);
	y = physy - 1.1 * 12;
	xf = physx * 0.95;
	xd = xf - phys_w;
	sprintf(ech_name, "%.1g", log_val);
	lc = calc_text_size(ech_name, NULL, NULL);
	if(fd_nj_plot->has_br_length) {
		dir_moveto(xd, y);
		dir_lineto(xf, y);
		dir_moveto(xd, y - 4);
		dir_lineto(xd, y + 4);
		dir_moveto(xf, y - 4);
		dir_lineto(xf, y + 4);
		dir_moveto( (xd + xf)/2 - lc/2, y + 2 ); 
		plotstring(ech_name);
		}
}

void do_plot(FD_nj_plot *fd_nj_plot, int doing_print)
{
struct trait *p;
int num;
double factor, value, m = 1, v = 0, zoom = 1;

if(! doing_print) {
	/* size of the tree plot window  */
	v = fd_nj_plot->scroller->value();
	m = fd_nj_plot->scroller->maximum();
	zoom = fd_nj_plot->zoomvalue;
	}

factor = 1e99;
for(num=0; num<fd_nj_plot->notu; num++) {
	if(fd_nj_plot->profs[num] <= 0) continue; 
	value = (physx - fd_nj_plot->widnames[num] - 2 * fd_nj_plot->ascent) / fd_nj_plot->profs[num];
	if(value < factor) factor = value;
	}

physx_min  = fd_nj_plot->ascent;
physx_corr = maxx * factor + physx_min;
if(physx_corr <= physx_min + 1) {
	physx_corr = physx_min + 1;
	}
physy_corr = physy - 2 * fd_nj_plot->char_height;
physy_min  = 0.6 * fd_nj_plot->char_height;
scale_window(0, maxx, 
	((m-v)/m) * (maxy - maxy/zoom), 
	((m-v)/m) * (maxy - maxy/zoom) + maxy/zoom, 
	physx_min, physx_corr, physy_min, physy_corr);
fd_nj_plot->tek_dx = tek_dx;
fd_nj_plot->tek_dy = tek_dy;
fd_nj_plot->tek_ymin = tek_ymin;

for(num=0; num<=fd_nj_plot->totnoms; num++) {
	mydrawstring( (fd_nj_plot->noms+num)->x, (fd_nj_plot->noms+num)->y , (fd_nj_plot->noms+num)->nom,
			(fd_nj_plot->noms+num)->disp_option, fd_nj_plot->char_height );
	}
for(num=0; num<=fd_nj_plot->tottraits; num++) {
	p= fd_nj_plot->traits+num;
	moveto(p->xd,p->yd);
	lineto(p->xf,p->yf);
	}

if(fd_nj_plot->choix == prune_clade_found) {//redraw in color the prune clade subtree
	fl_color(FL_RED);
	for(num=fd_nj_plot->colored_names_1; num<=fd_nj_plot->colored_names_2; num++) {
		mydrawstring( (fd_nj_plot->noms+num)->x, (fd_nj_plot->noms+num)->y , (fd_nj_plot->noms+num)->nom,
					 (fd_nj_plot->noms+num)->disp_option, fd_nj_plot->char_height );
	}
	for(num=fd_nj_plot->colored_traits_1; num<=fd_nj_plot->colored_traits_2; num++) {
		p= fd_nj_plot->traits+num;
		moveto(p->xd,p->yd);
		lineto(p->xf,p->yf);
	}
	fl_color(FL_BLACK);
}
/* echelle */
draw_scale(fd_nj_plot);
} /* end of do_plot */



int calc_text_size(char *text, int *pheight, int *pascent)
{
	int width, height, ascent;

	width = (int)fl_width(text);
	height = fl_height();
	ascent = fl_height() - fl_descent();
	if(pheight != NULL) *pheight = height;
	if(pascent != NULL) *pascent = ascent;
	return width;
}


static int moveto_x, moveto_y;
void plotstring(const char *nom)
{
  fl_draw(nom, moveto_x, moveto_y);
}

void dir_moveto(double x,double y)
/* move to physical coord x,y */
{
	moveto_x = myrint(x);
//	moveto_y = myrint(y);
	moveto_x += page_x_offset;
	moveto_y = myrint(page_y_offset + physy - y);
}


void dir_lineto(double x,double y)
/* draw line from current pos to physical coord x,y */
{
  int yi = myrint(page_y_offset + physy - y);
  fl_line(moveto_x, moveto_y, myrint(page_x_offset + x), yi);
}

void dir_plotsquare(double x, double y, int edge, int use_color)
{
  y += edge/2;
  int xi = (int)(page_x_offset + x + 0.5);
  int yi = (int)(page_y_offset + physy - (y + 0.5));
  if (use_color) fl_color(FL_RED);
  fl_rectf(xi, yi, edge, edge);
  if (use_color) fl_color(FL_BLACK);
}

const char *preptree(FD_nj_plot *fd_nj_plot)
{
int i, c, maxlname, v;
char *arbre, *finarbre;
char *last_bootstrap, *p, *q;

arbre = strdup(fd_nj_plot->current_tree);
/* lecture de l'arbre et de son label entre [] */
p = arbre; while(isspace(*p)) p++;
if(*p == '[') { 
	q = p;
	do q++; while(*q != ']');
	if(q > p + 1) {
		*q = 0;
		fd_nj_plot->tree_label = (char *)malloc(q - p);
		strcpy(fd_nj_plot->tree_label, p + 1);
		}
	p = q + 1;
	while(isspace(*p)) p++;
	}
fd_nj_plot->notu = 2; i = 3; v = 0;
if(*p == '(') {
	if(p > arbre) memmove(arbre, p, strlen(p) + 1);
	p = arbre + 1;
	while( (c=*(p++)) != 0 && c != ';') {
		if(c == ')') fd_nj_plot->notu++;
		if(c == '(') i++;
		if(c == ',') v++;
		}
	}
if(i != fd_nj_plot->notu) {
	free(arbre);
	fd_nj_plot->notu = 0;
	return bad_tree;
}
finarbre = nextpar(arbre);
if(finarbre == NULL) {
	fd_nj_plot->notu = 0;
	return ("Unbalanced parentheses in tree.");
	}
finarbre++;
/* memorize bootstrap value after last ) */
while(isspace(*finarbre)) finarbre++;
if(*finarbre != ';' && *finarbre != 0) {
	last_bootstrap = strdup(finarbre);
	p = strchr(last_bootstrap, ';');
	if(p != NULL) *p = 0;
	}
else last_bootstrap = NULL;

arbre = (char *)realloc(arbre, strlen(arbre) + 4 * v + 5 ); /* worst case add 4 chars for each , */
p = (char *)make_binary_or_unrooted(arbre);
if(p != NULL) {
	fd_nj_plot->notu = 0;
	free(arbre);
	return p;
	}
fd_nj_plot->long_arbre_parenth = strlen(arbre);
fd_nj_plot->notu = v + 1 ; /* after this fd_nj_plot->notu = number of OTUs  */
fd_nj_plot->totbranches= -1;
/* allocate all memory */
fd_nj_plot->tabtax = (struct noeud **)check_alloc(2*fd_nj_plot->notu - 1,sizeof(struct noeud *));
fd_nj_plot->branches = (branche *)check_alloc(fd_nj_plot->notu - 1, sizeof(branche));
for(i=0; i<2*fd_nj_plot->notu - 1; i++) *(fd_nj_plot->tabtax+i)=
			(struct noeud *)check_alloc(1,s_noeud);
fd_nj_plot->noms = (struct nom *)check_alloc(5*(fd_nj_plot->notu-1)+1,sizeof(struct nom));
fd_nj_plot->points = (struct mon_point *)check_alloc(2*(fd_nj_plot->notu-1)+1,sizeof(struct mon_point));
fd_nj_plot->traits = (struct trait *)check_alloc(3*(fd_nj_plot->notu-1),sizeof(struct trait));
fd_nj_plot->labels = (char **)check_alloc(fd_nj_plot->notu, sizeof(char *));
fd_nj_plot->widnames = (int *)check_alloc(fd_nj_plot->notu, sizeof(int));
fd_nj_plot->profs = (double *)check_alloc(fd_nj_plot->notu, sizeof(double));
fd_nj_plot->br_length_txt = (char *)check_alloc(2*(fd_nj_plot->notu - 1),10);
p = (char *)loadphylip(fd_nj_plot, arbre, last_bootstrap);
free(arbre);
if(p != NULL) return p;
maxlname = 0; /* largeur max des noms des feuilles */

if(nextotu != fd_nj_plot->notu - 1) return bad_tree;

for(i = 0; i <= nextotu; i++) {
	c = strlen(fd_nj_plot->labels[i]);
	if(c > maxlname) maxlname = c;
	}
for(i = 0; i < 2*fd_nj_plot->notu - 1; i++) {
	fd_nj_plot->tabtax[i]->nom = (char *)check_alloc(maxlname + 2 + 1, 1); /*2=place pour ) */
	fd_nj_plot->tabtax[i]->rank = i;
	}
	
if(!fd_nj_plot->rooted) {
	fd_nj_plot->racine = *(fd_nj_plot->tabtax+(++num_noeud));
	if(num_noeud >= 2*fd_nj_plot->notu - 1) return bad_tree;
	if(fd_nj_plot->has_br_length) {
		fd_nj_plot->root_br_l = place_midpoint_root(fd_nj_plot->tabtax[0], fd_nj_plot->racine);
		fd_nj_plot->rooted = TRUE;
		fd_nj_plot->root_num = -1;//means the tree is rooted at fd_nj_plot->racine
		}
	else	{
/* ancienne version: derniere espece est groupe externe
*/
		fd_nj_plot->racine->v3 = NULL;
		fd_nj_plot->root_num = fd_nj_plot->notu - 1; 
		}
	}
else	{
	fd_nj_plot->racine = *(fd_nj_plot->tabtax+num_noeud);
	fd_nj_plot->root_br_l= fd_nj_plot->racine->l1 + fd_nj_plot->racine->l2;
	fd_nj_plot->root_num = num_noeud;
	if(!fd_nj_plot->has_br_length) calc_brl_for_lengthless(fd_nj_plot->racine, NULL);

/* y a-t-il un bootstrap sur l'une des branches racine ? */
	i = get_br_from_bouts(fd_nj_plot, fd_nj_plot->racine, fd_nj_plot->racine->v1); 
	if(i == -1) i = get_br_from_bouts(fd_nj_plot, fd_nj_plot->racine, fd_nj_plot->racine->v2);
  // build the exclusive OR of 2 conditions
	int cond1 = (i != -1 ? 1 : 0);
	int cond2 = 0;
	int j = get_br_from_bouts(fd_nj_plot, fd_nj_plot->racine, NULL);
	if (j != -1) { cond2 = 1; if (!cond1) i = j; }
	if (cond1 ^ cond2) {
		fd_nj_plot->branches[i].bouta = fd_nj_plot->racine->v1;
		fd_nj_plot->branches[i].boutb = fd_nj_plot->racine->v2;
		}
	} 
if(fd_nj_plot->notu < 2) return ("Tree should contain at least 2 elements.");
fd_nj_plot->subtree_notu = fd_nj_plot->notu;
fd_nj_plot->subtree_center = NULL;
if (fd_nj_plot->up) fd_nj_plot->up->deactivate();
if (fd_nj_plot->full) fd_nj_plot->full->value(1);
  if(fd_nj_plot->view == NULL && fd_nj_plot->menu_file) (fd_nj_plot->menu_file->get_menu() + 23)->deactivate();
if (fd_nj_plot->new_outgroup) fd_nj_plot->new_outgroup->activate();
return NULL;
} /* end of preptree */


char *check_alloc(int nbrelt, int sizelt)
{
char *retval;
if( (retval=(char *)calloc(nbrelt,sizelt)) != NULL ) return retval;
fl_alert("ERROR: Not enough memory.");
exit(1);
}


const char *loadphylip(FD_nj_plot *fd_nj_plot, char *arbre, char *last_bootstrap)
//returns NULL iff OK
{
char *deba,*debb,*debc, *finarbre;
struct noeud *p1, *p2, *p3, *p;
branche *int_br_g, *int_br_d;

fd_nj_plot->has_br_length = 2;
fd_nj_plot->has_internal = FALSE;
/* ignore all stuff after last closing parenthesis 
(needed for fastDNAml output)
*/
finarbre= nextpar(arbre);
fd_nj_plot->rooted=0;
deba=arbre+1;
debb=deba;
while(*debb != ',') {
	if(*debb == 0) return bad_tree;
	if(*debb == '(')debb=nextpar(debb);
	debb++;
	}
debb++;
debc=debb;
while(*debc != ',' && debc<finarbre) {
	if(*debc == '(')debc=nextpar(debc);
	debc++;
	}
if(*debc==',') {
/* the tree is unrooted <==> it has 3 subtrees at its bottommost level */
	debc++;
	}
else	{
/* the tree is rooted */
	debc=finarbre+1;
	fd_nj_plot->rooted=1;
	}

num_noeud = fd_nj_plot->notu - 1;
nextotu = -1;
p1=unrootedset(fd_nj_plot, deba,debb-2,&int_br_g);
if(p1 != NULL) p2=unrootedset(fd_nj_plot, debb,debc-2,&int_br_d);
p = *(fd_nj_plot->tabtax+(++num_noeud));
if(p1==NULL || p2==NULL || num_noeud >= 2*fd_nj_plot->notu - 1) return bad_tree;
p->v1=p1; p1->v3=p; p->l1=p1->l3;
if(int_br_g!=NULL) { int_br_g->bouta=p; int_br_g->boutb=p1; }
p->v2=p2; p2->v3=p; p->l2=p2->l3;
if(int_br_d!=NULL) { int_br_d->bouta=p; int_br_d->boutb=p2; }
if(!fd_nj_plot->rooted) {
	p3=unrootedset(fd_nj_plot, debc,finarbre-1,&int_br_g);
	if(p3==NULL) return bad_tree;
	if(int_br_g!=NULL) { int_br_g->bouta=p; int_br_g->boutb=p3; }
	p->v3=p3; p3->v3=p; p->l3=p3->l3;
	}
else	{
	p->v3=NULL;
/* recherche d'un dernier label interne */
	debc=finarbre+1;
	while(*debc!=0 && *debc!=':' && *debc!='[') debc++;
	if(debc-finarbre>1) {
		int l=debc-finarbre-1;
		fd_nj_plot->has_internal = TRUE;
		fd_nj_plot->totbranches++;
		fd_nj_plot->branches[fd_nj_plot->totbranches].br_label=check_alloc(l+1,1);
		memcpy(fd_nj_plot->branches[fd_nj_plot->totbranches].br_label,finarbre+1,l);
		fd_nj_plot->branches[fd_nj_plot->totbranches].br_label[l]=0;
		fd_nj_plot->branches[fd_nj_plot->totbranches].bouta=p1;
		fd_nj_plot->branches[fd_nj_plot->totbranches].boutb=p2;
		}
	}
if(fd_nj_plot->rooted && last_bootstrap != NULL) {
/* attach last_bootstrap to branch racine <--> NULL */
		fd_nj_plot->totbranches++;
		fd_nj_plot->branches[fd_nj_plot->totbranches].br_label = strdup(last_bootstrap);
		fd_nj_plot->branches[fd_nj_plot->totbranches].bouta=p;
		fd_nj_plot->branches[fd_nj_plot->totbranches].boutb=NULL;
	}
if(last_bootstrap != NULL) free(last_bootstrap);
return NULL;
}


struct noeud *unrootedset(FD_nj_plot *fd_nj_plot, char *deb, char *fin, branche **p_int_br)
//returns NULL iff error
{
struct noeud *p, *pp;
char *virg, *ferme;
branche *int_br;
static int l;
static double brlength;

*p_int_br=NULL;
while(*deb==' ')deb++;
while(*fin==' ')fin--;
if(*deb != '(') { /* une feuille */
	virg = strchr(deb, ':');
	if(virg != NULL && virg < fin) {
		sscanf(virg+1, "%le", &brlength);
		fd_nj_plot->has_br_length=1;
		}
	else	{
		brlength = 1;
		fd_nj_plot->has_br_length=0;
		virg = fin + 1;
		}
	virg--;
	while(*deb==' ')deb++;
	l = virg-deb+1;
	fd_nj_plot->labels[ ++nextotu] = (char *)check_alloc(l + 1, 1);
	memcpy(fd_nj_plot->labels[nextotu], deb, l);
	fd_nj_plot->labels[nextotu][l] = 0;
	p = *(fd_nj_plot->tabtax + nextotu);
	p->l3 = brlength;
	p->v1 = p->v2 = p->v3 = NULL;
	return p;
	}
/* un noeud */
num_noeud++;
if(num_noeud >= 2*fd_nj_plot->notu - 1) return NULL;
p = *(fd_nj_plot->tabtax + num_noeud);
ferme =  nextpar(deb);
virg=deb + 1;
while(*virg != ',' && virg < fin) {
	if(*virg == '(') virg=nextpar(virg);
	virg++;
	}
if(virg>=ferme) return NULL;
pp = unrootedset(fd_nj_plot, deb + 1, virg - 1, &int_br);
if(pp == NULL) return NULL;
p->v1 = pp; pp->v3 = p; p->l1 = pp->l3;
if(int_br != NULL) { int_br->bouta = p; int_br->boutb = pp; }
pp = unrootedset(fd_nj_plot, virg + 1, ferme - 1, &int_br);
if(pp == NULL) return NULL;
p->v2 = pp; pp->v3 = p; p->l2 = pp->l3;
if(int_br != NULL) { int_br->bouta = p; int_br->boutb = pp; }
virg = strchr(ferme, ':');
if(virg != NULL && virg < fin) { /* traitement longueur */
//	if(fd_nj_plot->has_br_length == 0) return NULL;
	sscanf(virg+1, "%le", &brlength);
	fd_nj_plot->has_br_length=1;
	if(*fin == ']') { /* bootstrap entre [] apres longueurs */
		static char *q;
		q = fin - 1;
		while(q > virg && *q != '[') q--;
		if(*q == '[' && fin - q >= 2) {
			fd_nj_plot->has_internal = TRUE;
			fd_nj_plot->totbranches++;
			l = fin - q - 1;
			fd_nj_plot->branches[fd_nj_plot->totbranches].br_label =
				check_alloc(l+1,1);
			memcpy(fd_nj_plot->branches[fd_nj_plot->totbranches].br_label,q+1,l);
			fd_nj_plot->branches[fd_nj_plot->totbranches].br_label[l]=0;
			*p_int_br= &fd_nj_plot->branches[fd_nj_plot->totbranches];
			}
		}
	}
else	{
//	if(fd_nj_plot->has_br_length == 1) return NULL;
	brlength = 1;
	fd_nj_plot->has_br_length=0;
	virg = fin + 1;
	}
/* recherche bootstrap (internal label) */
l=virg-ferme-1;
if(l>0) {
	fd_nj_plot->has_internal = TRUE;
	fd_nj_plot->totbranches++;
	fd_nj_plot->branches[fd_nj_plot->totbranches].br_label=
		check_alloc(l+1,1);
	memcpy(fd_nj_plot->branches[fd_nj_plot->totbranches].br_label,ferme+1,l);
	fd_nj_plot->branches[fd_nj_plot->totbranches].br_label[l]=0;
	*p_int_br= &fd_nj_plot->branches[fd_nj_plot->totbranches];
	}
p->l3 = brlength;
return p;
}


char *nextpar(char *pospar)
//returns NULL iff error
{
char *pos;
pos=pospar+1;
while(*pos != ')') {
	if(*pos == 0) return NULL;
	if(*pos == '(') pos=nextpar(pos);
	pos++;
	}
return pos;
}


const char *make_binary_or_unrooted(char *arbre)
//returns NULL iff OK
{
char *finarbre, *deba, *debb, *debc;
int retval;

finarbre= nextpar(arbre);
*(finarbre + 1) = 0;
deba=arbre+1;
debb=deba;
while(*debb != ',') {
	if(*debb == 0) return("Incorrect tree file");
	if(*debb == '(')debb=nextpar(debb);
	debb++;
	}
debb++;
debc=debb;
while(*debc != ',' && debc<finarbre) {
	if(*debc == '(')debc=nextpar(debc);
	debc++;
	}
if(*debc == ',') {
/* the tree is unrooted <==> it has 3 subtrees or more at its bottommost level */
	retval = make_binary(arbre , debb, finarbre - 1, TRUE);
	if(retval != -1) retval = make_binary(arbre , deba, debb - 2, TRUE);
	}
else retval = make_binary(arbre , deba, finarbre - 1, TRUE);
	return (retval >= 0 ? NULL : "Cannot process multibranched tree without branch lengths");
}


int make_binary(char *arbre, char *debut, char *fin, int go_down)
//returns -1 iff error
{
int virg, l, retval;
char *p, *q;

p = debut; virg = 0; retval = 0;
while(p < fin) {
	if(*p == ',') virg++;
	else if(*p == '(')	{
		q = nextpar(p);
		if(go_down) {
			l = make_binary(arbre, p+1, q-1, TRUE);
			fin += l;
			retval += l;
			p = q + l;
			}
		else p = q;
		}
	p++;
	}
if(virg > 1) { /* multifurcation */
	/* recherche de la 2eme virgule */
	p = debut; l = 0;
	while(TRUE) {
		if(*p == ',') {
			l++;
			if(l == 2) break;
			}
		else if(*p == '(')	{
			p = nextpar(p);
			}
		p++;
		}
	l = strlen(p);
	memmove(p + 4, p, l + 1);
	memmove(debut + 1, debut, p - debut);
	*debut = '(';
	memcpy(p + 1, "):0", 3);
	fin += 4;
	retval += 4;
	if(virg > 2) retval += make_binary(arbre, debut, fin, FALSE);  
	}
return retval;
}


void mydrawstring(double x, double y, char *nom, char option, int height)
{
static double px,py;

ch_echelle(x,y,&px,&py);
if(option == '1') {
/* ecrire une chaine en la montant d'un chouia */
	py += height/6.;
	}
else if(option == 'c' || option == 'r')	{
/* ecrire une chaine en la centrant vert. sur cette position*/
	if (*nom == ')' || *nom == '(') {//indicates we want to draw a square before the name
		int edge = height/2;
		dir_plotsquare(px, py, edge, *nom == '(');
		nom++;
		while(*nom==' ')nom++;
		if(*nom == 0) return;
		px += edge;
		}
	py -= height/3.;
	px += height/6.;
	}
else if(option == 't')	{
	py -=  (5./6.) * height;
	}
else if(option == 'b')	{
	py += height/6.;
	}
dir_moveto(px,py);
if(option == 'r') fl_color(FL_RED);
plotstring(nom);
if(option == 'r') fl_color(FL_BLACK);
}


void moveto(double x,double y)
/* move from current pos to logical coord x,y */
{
static double px,py;
ch_echelle(x,y,&px,&py);
dir_moveto(px,py);
}


void lineto(double x,double y)
/* draw line from current pos to logical coord x,y */
{
static double px,py;
ch_echelle(x,y,&px,&py);
dir_lineto(px,py);
}


int calc_brl_for_lengthless(struct noeud *centre, struct noeud *pere)
/* Recursively computes branch lengths of a lengthless tree having some branches fixed to 0 to allow
 multifurcations so that all tips align to the right of the plot.
 */
{
	int n1 = 0, n2, depth;
	volatile double l;
	if(centre->v1 == NULL && centre->v2 == NULL) {
	  if(centre->l3 == 0) {//no terminal branch of 0 length
		centre->l3 = 1E-6;
		if(centre->v3->v1 == centre) centre->v3->l1 = centre->l3;
		else centre->v3->l2 = centre->l3;
		}
	  return 0;//a leaf
	  }
	//rearrange with centre->v3 towards root
	if(centre->v1 == pere) {
		centre->v1 = centre->v3;
		centre->v3 = pere;
		l = centre->l3;
		centre->l3 = centre->l1;
		centre->l1 = l;
	}
	else if(centre->v2 == pere) {
		centre->v2 = centre->v3;
		centre->v3 = pere;
		l = centre->l3;
		centre->l3 = centre->l2;
		centre->l2 = l;
	}
	n1 = calc_brl_for_lengthless(centre->v1, centre);
	n2 = calc_brl_for_lengthless(centre->v2, centre);
	depth = n1;
	if(centre->l1 != 0) depth++;
	if(depth < n2) depth = n2;
	if(centre->l2 != 0 && n2 + 1 > depth) depth++;
	if(centre->l1 != 0) {
		centre->l1 = depth - n1; 
		centre->v1->l3 = depth - n1;
		}
	else if(depth - n1 > 0) add_value_downstream(centre->v1, depth - n1);
	if(centre->l2 != 0) {
		centre->l2 = depth - n2; 
		centre->v2->l3 = depth - n2;
		}
	else if(depth - n2 > 0) add_value_downstream(centre->v2, depth - n2);
	return depth;
}

void add_value_downstream(struct noeud *centre, int value)
{
  if(centre->l1 != 0) {
	  centre->l1 += value;
	  centre->v1->l3 = centre->l1;
  }
  else add_value_downstream(centre->v1, value);
  if(centre->l2 != 0) {
	  centre->l2 += value;
	  centre->v2->l3 = centre->l1;
  }
  else add_value_downstream(centre->v2, value);
}


double place_midpoint_root(struct noeud *from, struct noeud *racine)
/* enraciner l'arbre sans racine en cherchant son centre 
*/
{
struct noeud *aux;
double laux;

current_best_diff = VERY_BIG;
current_cote1=current_cote2=NULL;
parcourir_branches(from, NULL);
/* il faut toujours que la racine soit telle que racine->v1->v3=racine */
if (current_cote1->v1 == current_cote2 ) {
/* echanger les voisins v1 et v3 de cote1 */
	aux=current_cote1->v1;
	current_cote1->v1=current_cote1->v3;
	current_cote1->v3=aux;
	laux=current_cote1->l1;
	current_cote1->l1=current_cote1->l3;
	current_cote1->l3=laux;
	}
else if (current_cote1->v2 == current_cote2) {
/* echanger les voisins v2 et v3 de cote1 */
	aux=current_cote1->v2;
	current_cote1->v2=current_cote1->v3;
	current_cote1->v3=aux;
	laux=current_cote1->l2;
	current_cote1->l2=current_cote1->l3;
	current_cote1->l3=laux;
	}
current_cote1->v3 = racine;

if (current_cote2->v1 == current_cote1 )
	current_cote2->v1 = racine;
else if (current_cote2->v2 == current_cote1)
	current_cote2->v2 = racine;
else
	current_cote2->v3 = racine;
racine->v1=current_cote1;
racine->v2=current_cote2;
racine->v3=NULL;
racine->l3=0;
/* avoid very unbalanced division of root branch */
if(current_balance > MAX_FRAC) current_balance = MAX_FRAC;
else if(current_balance < 1 - MAX_FRAC) current_balance = 1 - MAX_FRAC;
racine->l1 = current_br_length * current_balance;
racine->l2 = current_br_length - racine->l1;
return current_br_length;
}


void parcourir_branches(struct noeud *centre, struct noeud *origine)
/* parcourir recursivement toutes les branches de l'arbre sans racine
a partir de centre et dans la direction opposee a son voisin origine
*/
{
if(centre==NULL) return;
if(centre->v1!=origine) {
	process_branche(centre,centre->v1,centre->l1);
	parcourir_branches(centre->v1,centre);
	}
if(centre->v2!=origine) {
	process_branche(centre,centre->v2,centre->l2);
	parcourir_branches(centre->v2,centre);
	}
if(centre->v3!=origine) {
	process_branche(centre,centre->v3,centre->l3);
	parcourir_branches(centre->v3,centre);
	}
}


void process_branche(struct noeud *cote1, struct noeud *cote2, double length)
/* calculer la variance des distances racine - feuilles si racine est sur branche cote1 - cote2
et memoriser la meilleure branche dans les variables globales
*/
{
double x ; /* partage de branche par facteur x */
moments m1, m2;
double A, B, C; /* variance(x) = A x x + B x + C */
double mini_val; /* meilleure variance pour toutes valeurs de x entre 0 et 1 */

if(cote1 == NULL || cote2 == NULL) return;
if( length < 0 ) length = 0;

m1 = stat_from_node(cote2, cote1);
m2 = stat_from_node(cote1, cote2);
A = 4 * m1.N * ( m2.N * length ) * length;
B = 4 * length * ( m2.N * m1.somme - m1.N * m2.somme - length * m1.N * m2.N);
C = (m1.N + m2.N) * (m1.carres + m2.carres) + m1.N * length * m2.N * length +
	2 * m1.N * length * m2.somme - 2 * m2.N * length * m1.somme -
	(m1. somme + m2.somme) * (m1. somme + m2.somme);
if(A < 1e-20) {
	x = 0.5;
	mini_val = VERY_BIG * 0.99 ;
	}
else {
	x = - B / (2 * A);
	mini_val = C - (B * B) / 4 / A;
	}
if( x < 0 ) {
	x = 0; mini_val = C;
	}
else if( x > 1) {
	x = 1; mini_val = A + B + C;
	}

if(mini_val < current_best_diff ) {
	current_best_diff = mini_val;
	current_cote1 = cote1;
	current_cote2 = cote2;
	current_br_length = length;
	current_balance = x;
	}
}


/* no longer useful */
double get_length_down(struct noeud *pere, struct noeud *racine)
/* compute the average length of the tree down a node */
{
if(racine == NULL) return 0.0;
else	{
	struct noeud *gauche, *droite;
	double bg,bd,lg,ld;
	if( racine->v1 == pere ) {
		gauche =racine->v2; droite = racine->v3;
		bg = (racine->l2); bd = (racine->l3);
		}
	else if( racine->v2 == pere ) {
		gauche =racine->v1; droite = racine->v3;
		bg = (racine->l1); bd = (racine->l3);
		}
	else	{
		gauche =racine->v1; droite = racine->v2;
		bg = (racine->l1); bd = (racine->l2);
		}
 	/* conserver cette ecriture sinon plante sur PC */
 	lg = ld = 0;
 	if(gauche != NULL) lg = get_length_down(racine,gauche);
 	lg += bg;
 	if(droite != NULL) ld = get_length_down(racine,droite);
 	ld += bd;
	return ((lg+ld)/2);
	}
}


moments stat_from_node(struct noeud *pere, struct noeud *racine)
/* compute the moments down a node to all descending tips */
{
struct noeud *gauche, *droite;
moments m;
 static  moments mtmp;
double bg, bd;

	if( racine->v1 == pere ) {
		gauche =racine->v2; droite = racine->v3;
		bg = (racine->l2); bd = (racine->l3);
		}
	else if( racine->v2 == pere ) {
		gauche =racine->v1; droite = racine->v3;
		bg = (racine->l1); bd = (racine->l3);
		}
	else	{
		gauche =racine->v1; droite = racine->v2;
		bg = (racine->l1); bd = (racine->l2);
		}
 	if(gauche != NULL) {
		mtmp = stat_from_node(racine, gauche);
		m.N = mtmp.N; /* nbre de fils */
		m.somme = mtmp.somme + bg * mtmp.N;
		m.carres = mtmp.carres + 2 * bg * mtmp.somme + mtmp.N * bg * bg;

		mtmp = stat_from_node(racine, droite);
		m.N += mtmp.N; /* nbre de fils */
		m.somme += mtmp.somme + bd * mtmp.N;
		m.carres += mtmp.carres + 2 * bd * mtmp.somme + mtmp.N * bd * bd;
 		}
 	else {
 		m.N = 1;
 		m.somme = 0;
 		m.carres = 0;
 		}

return m;
}


void clear_squares_below(struct noeud *n)
{
	if(n == NULL) return;
	clear_squares_below(n->v1);
	clear_squares_below(n->v2);
	char *p = n->nom;
	if(p != NULL && *p == ')') memmove(p, p+1, strlen(p));
}


void runtree(FD_nj_plot *fd_nj_plot)
{
double currx, curry;
int i;
struct noeud *p1, *p2;
double b1,b2,frac_gauche;
if(!fd_nj_plot->rooted) {
	/* place root at user-chosen place: node # fd_nj_plot->root_num */
	fd_nj_plot->rooted = TRUE;
	p1 = fd_nj_plot->tabtax[fd_nj_plot->root_num];
	p2 = p1->v3;
	fd_nj_plot->root_br_l = p1->l3;
	if(fd_nj_plot->has_br_length) {
		current_best_diff = VERY_BIG;
		process_branche(p1, p2, fd_nj_plot->root_br_l);
		}
	p1->v3 = fd_nj_plot->racine;
	if (p2->v1 == p1 )
		p2->v1 = fd_nj_plot->racine;
	else if (p2->v2 == p1)
		p2->v2 = fd_nj_plot->racine;
	else
		p2->v3 = fd_nj_plot->racine;
	fd_nj_plot->racine->v1=p1;
	fd_nj_plot->racine->v2=p2;
	fd_nj_plot->racine->v3=NULL;
	if(fd_nj_plot->has_br_length) {
		frac_gauche = current_balance;
		if(frac_gauche>MAX_FRAC) frac_gauche=MAX_FRAC;
		else if(frac_gauche<1-MAX_FRAC) frac_gauche=1-MAX_FRAC;
		b1 = frac_gauche*fd_nj_plot->root_br_l;  b2 = fd_nj_plot->root_br_l - b1;
		fd_nj_plot->racine->l1=b1; fd_nj_plot->racine->l2=b2;
		}
	else	{
		fd_nj_plot->racine->l1 = p1->l3;
		if (p2->v1 == fd_nj_plot->racine )
			fd_nj_plot->racine->l2 = p2->l1;
		else if (p2->v2 == fd_nj_plot->racine)
			fd_nj_plot->racine->l2 = p2->l2;
		else
			fd_nj_plot->racine->l2 = p2->l3;
		calc_brl_for_lengthless(fd_nj_plot->racine, NULL);
		}
	}
/* initialize leave and node names */
for(i = 0; i <= 2*(fd_nj_plot->notu - 1); i++) fd_nj_plot->tabtax[i]->nom[0] = 0;
if (fd_nj_plot->choix == depl_racine) {
	for(i=0; i <= 2*(fd_nj_plot->notu - 1) - 1; i++) {
		if(i == fd_nj_plot->root_num) continue;//skip current root
		if( !fd_nj_plot->has_br_length) {
		   if(fd_nj_plot->tabtax[i]->l3 == 0) continue;//skip internal multifurcation nodes that can't be broken by root
			}
		sprintf(fd_nj_plot->tabtax[i]->nom,")");
		}
	}
else if(fd_nj_plot->choix == permutation)
	for(i=fd_nj_plot->notu; i <= 2*(fd_nj_plot->notu - 1); i++) sprintf(fd_nj_plot->tabtax[i]->nom,")");
else if(fd_nj_plot->choix == subtree)
	for(i=fd_nj_plot->notu; i <= 2*(fd_nj_plot->notu - 1) - 1; i++) sprintf(fd_nj_plot->tabtax[i]->nom,")");
else if(fd_nj_plot->choix == selection) {
  int j;
  SEA_VIEW *view = fd_nj_plot->view;
  if (view) {
    for(i=fd_nj_plot->notu; i <= 2*(fd_nj_plot->notu - 1); i++) sprintf(fd_nj_plot->tabtax[i]->nom,")");
    for (i=0; i < fd_nj_plot->notu; i++) {
      for (j=0; j < view->tot_seqs; j++) {
	if (view->sel_seqs[j] && strcmp(fd_nj_plot->labels[i], view->seqname[j]) == 0) break;
	}
      // ) means draw black square, ( means draw red square
      sprintf(fd_nj_plot->tabtax[i]->nom, j >= view->tot_seqs ? ")" : "(");
      }
    }
  }
else if(fd_nj_plot->choix == prune_clade)
	for(i=0; i <= 2*(fd_nj_plot->notu - 1) - 1; i++) sprintf(fd_nj_plot->tabtax[i]->nom,")");
else if(fd_nj_plot->choix == prune_clade_found) {
	char *p;
	struct noeud *parent;
	for(i=0; i <= 2*(fd_nj_plot->notu - 1) - 1; i++) sprintf(fd_nj_plot->tabtax[i]->nom,")");
	parent = fd_nj_plot->prune_clade_node->v3;
	parent->nom[0] = 0;//no square on clade's parent
	if(parent->v1 == fd_nj_plot->prune_clade_node) p = parent->v2->nom;//nor on clade's sister
	else p = parent->v1->nom;
	if(*p != 0) memmove(p, p + 1, strlen(p));
	clear_squares_below(fd_nj_plot->prune_clade_node);//nor in clade
	}

for(i=0; i<fd_nj_plot->notu; i++) {
	int j;
	j = strlen(fd_nj_plot->tabtax[i]->nom);
	strcpy(fd_nj_plot->tabtax[i]->nom + j, fd_nj_plot->labels[i]);
	}
fd_nj_plot->totnoms = fd_nj_plot->tottraits = fd_nj_plot->totpoints = -1;
end_br_length = fd_nj_plot->br_length_txt;
currx = 0.;
maxx = 0.;
memset(fd_nj_plot->profs, 0, (fd_nj_plot->notu)*sizeof(double));
if(fd_nj_plot->subtree_center != NULL)
	fd_nj_plot->deltay = maxy / (fd_nj_plot->subtree_notu - 1);
else {
	fd_nj_plot->deltay = maxy / (fd_nj_plot->notu - 1);
	fd_nj_plot->subtree_notu = fd_nj_plot->notu;
	}
nexty = -fd_nj_plot->deltay;
calc_text_size((char *)"Mq", &fd_nj_plot->char_height, &fd_nj_plot->ascent);
if(fd_nj_plot->subtree_center == NULL)
	mem_plot(fd_nj_plot, NULL, fd_nj_plot->racine, currx, &curry);
else
	mem_plot(fd_nj_plot, fd_nj_plot->subtree_ascend, fd_nj_plot->subtree_center, currx, &curry);
} /* end of runtree */


void mem_plot(FD_nj_plot *fd_nj_plot, struct noeud *pere, struct noeud *centre, double currx,
double *curry)
/* prepare tree by memorizing all graphic requests */
{
int num=0;
char *p;
struct noeud *gauche, *droite;
double bg, bd, bpere;

if(fd_nj_plot->choix == prune_clade_found && centre == fd_nj_plot->prune_clade_node) {
	fd_nj_plot->colored_names_1 = fd_nj_plot->totnoms + 1;
	fd_nj_plot->colored_traits_1 = fd_nj_plot->tottraits + 1;
	}

while( *(fd_nj_plot->tabtax+num) != centre) num++;
if(pere != NULL && 
	(centre->v1 == NULL || centre->v2 == NULL || centre->v3 == NULL) ) {
	/* orienter le noeud centre de maniere standard: centre->v3=pere */
	if( centre->v1 == pere ) {
		gauche =centre->v2; droite = centre->v3;
		bg = centre->l2; bd = centre->l3; bpere = centre->l1;
		}
	else if( centre->v2 == pere ) {
		gauche =centre->v1; droite = centre->v3;
		bg = centre->l1; bd = centre->l3; bpere = centre->l2;
		}
	else	{
		gauche =centre->v1; droite = centre->v2;
		bg = centre->l1; bd = centre->l2; bpere = centre->l3;
		}
	centre->v3=pere; centre->v1=gauche; centre->v2=droite;
	centre->l3=bpere; centre->l1=bg; centre->l2=bd;
	/* write taxon name */
	nexty += fd_nj_plot->deltay;
	mem_nom(fd_nj_plot, currx,nexty,fd_nj_plot->tabtax[num]->nom,'c');
	fd_nj_plot->profs[num] = currx;
	fd_nj_plot->widnames[num] = calc_text_size(fd_nj_plot->tabtax[num]->nom, NULL, NULL);
	if(fd_nj_plot->choix==depl_racine || fd_nj_plot->choix== selection || fd_nj_plot->choix == prune_clade || fd_nj_plot->choix == prune_clade_found) 
		mem_point(fd_nj_plot, currx, nexty, num);
	*curry = nexty;
	}
else 	{
	double yg, yd, xg, xd;

	static int doswap;
	static struct noeud *tmp;
	/* doswap vrai ssi permutation de 2 descendants necessaire ici */
	doswap = (fd_nj_plot->swap != 0 && *(fd_nj_plot->tabtax+fd_nj_plot->swap) == centre);
	if( centre->v1 == pere ) {
		if(doswap) {
			tmp= centre->v2;centre->v2= centre->v3;centre->v3= tmp;
			bg= centre->l2; centre->l2= centre->l3; centre->l3= bg;
			}
		gauche =centre->v2; droite = centre->v3;
		bg = centre->l2; bd = centre->l3; bpere = centre->l1;
		}
	else if( centre->v2 == pere ) {
		if(doswap) {
			tmp= centre->v1;centre->v1= centre->v3;centre->v3= tmp;
			bg= centre->l1; centre->l1= centre->l3; centre->l3= bg;
			}
		gauche =centre->v1; droite = centre->v3;
		bg = centre->l1; bd = centre->l3; bpere = centre->l2;
		}
	else	{
		if(doswap) {
			tmp= centre->v1;centre->v1= centre->v2;centre->v2= tmp;
			bg= centre->l1; centre->l1= centre->l2; centre->l2= bg;
			}
		gauche =centre->v1; droite = centre->v2;
		bg = centre->l1; bd = centre->l2; bpere = centre->l3;
		}
	/* orienter le noeud centre de maniere standard: centre->v3=pere */
	centre->v3=pere; centre->v1=gauche; centre->v2=droite;
	centre->l3=bpere; centre->l1=bg; centre->l2=bd;
	xg=currx+bg; xd=currx+bd;

	mem_plot(fd_nj_plot, centre, gauche, xg, &yg);
	mem_plot(fd_nj_plot, centre, droite, xd, &yd);

	mem_trait(fd_nj_plot, currx,yg,xg,yg);
	mem_trait(fd_nj_plot, currx,yd,xd,yd);
	mem_trait(fd_nj_plot, currx,yg,currx,yd);
	*curry = (yg+yd)/2;

/* write internal fd_nj_plot->labels */
	if(fd_nj_plot->choix==show_tree && fd_nj_plot->show_bootstrap) {
		if(pere != NULL) { /* for all but root node */
			if( (p=get_br_label_with_threshold(fd_nj_plot, centre, gauche)) != NULL ) mem_nom(fd_nj_plot, currx,yg,p,'t');
			if( (p=get_br_label_with_threshold(fd_nj_plot, centre, droite)) != NULL ) mem_nom(fd_nj_plot, currx,yd,p,'b');
			}
		else {/* for root node */
			if( (p=get_br_label_with_threshold(fd_nj_plot, centre, NULL)) != NULL ) { /* if root bootstrap exists */
				mem_nom(fd_nj_plot, currx,*curry,p,'c');
				if( (p=get_br_label_with_threshold(fd_nj_plot, centre, gauche)) != NULL ) mem_nom(fd_nj_plot, currx,yg,p,'t');
				if( (p=get_br_label_with_threshold(fd_nj_plot, centre, droite)) != NULL ) mem_nom(fd_nj_plot, currx,yd,p,'b');
				}
			else {/* if no root bootstrap any bootstrap is to be centered */
				if( (p=get_br_label_with_threshold(fd_nj_plot, centre, gauche)) != NULL ) mem_nom(fd_nj_plot, currx,*curry,p,'c');
				if( (p=get_br_label_with_threshold(fd_nj_plot, centre, droite)) != NULL ) mem_nom(fd_nj_plot, currx,*curry,p,'c');
				if( (p=get_br_label_with_threshold(fd_nj_plot, gauche, droite)) != NULL ) mem_nom(fd_nj_plot, currx,*curry,p,'c');
				}
			}
		}

/* write node number */
	mem_nom(fd_nj_plot, currx,*curry,fd_nj_plot->tabtax[num]->nom,'c');
	mem_point(fd_nj_plot, currx, *curry, num);
	if(fd_nj_plot->plot_br_l && fd_nj_plot->has_br_length) {
/* write branch length */
		double min_br_l = 0.008; /* minimum branch length displayed */
		if(bg>min_br_l) {
			sprintf(end_br_length,"%.3f",bg);
			mem_nom(fd_nj_plot, currx+bg/10,yg,end_br_length,'1');
			end_br_length += (strlen(end_br_length)+1);
			}
		if(bd>min_br_l) {
			sprintf(end_br_length,"%.3f",bd);
			mem_nom(fd_nj_plot, currx+bd/10,yd,end_br_length,'1');
			end_br_length += (strlen(end_br_length)+1);
			}
		}
	}
if(fd_nj_plot->choix == prune_clade_found && centre == fd_nj_plot->prune_clade_node) {
	fd_nj_plot->colored_names_2 = fd_nj_plot->totnoms;
	fd_nj_plot->colored_traits_2 = fd_nj_plot->tottraits;
	}
}  /* end of mem_plot */

void mem_point(FD_nj_plot *fd_nj_plot, double x, double y, int number)
{
if( *(fd_nj_plot->tabtax[number]->nom) != ')' &&  *(fd_nj_plot->tabtax[number]->nom) != '(') return;
++fd_nj_plot->totpoints;
(fd_nj_plot->points+fd_nj_plot->totpoints)->x = x;
(fd_nj_plot->points+fd_nj_plot->totpoints)->y = y;
(fd_nj_plot->points+fd_nj_plot->totpoints)->number = number;
}

void mem_nom(FD_nj_plot *fd_nj_plot, double x, double y, char *nom, char option)
/* x,y: logical coordinates of beginning of string 
   nom: address of string to be displayed later
   option: 'c' use for position of center of character height
           '1' put bottom of characters at y+1 pixel
	   't' use for position of top of character
	   'b' use for position of bottom of character
*/
{
if(strlen(nom) != 0) {
	fd_nj_plot->totnoms++;
	if(x > maxx) maxx = x;
	(fd_nj_plot->noms+fd_nj_plot->totnoms)->x = x;
	(fd_nj_plot->noms+fd_nj_plot->totnoms)->y = y;
	(fd_nj_plot->noms+fd_nj_plot->totnoms)->nom = nom;
	(fd_nj_plot->noms+fd_nj_plot->totnoms)->disp_option = option;
	}
}


void mem_trait(FD_nj_plot *fd_nj_plot, double xd, double yd, double xf, double yf)
{
fd_nj_plot->tottraits++;
if(xd>maxx) maxx=xd;
if(xf>maxx) maxx=xf;
(fd_nj_plot->traits+fd_nj_plot->tottraits)->xd = xd;
(fd_nj_plot->traits+fd_nj_plot->tottraits)->yd = yd;
(fd_nj_plot->traits+fd_nj_plot->tottraits)->xf = xf;
(fd_nj_plot->traits+fd_nj_plot->tottraits)->yf = yf;
}


char *get_br_label(FD_nj_plot *fd_nj_plot, struct noeud *a, struct noeud *b)
{
int i;
for(i=0; i<=fd_nj_plot->totbranches; i++) {
	if(fd_nj_plot->branches[i].bouta==a && fd_nj_plot->branches[i].boutb==b) {
		return fd_nj_plot->branches[i].br_label;
		}
	else if(fd_nj_plot->branches[i].boutb==a && fd_nj_plot->branches[i].bouta==b) {
		return fd_nj_plot->branches[i].br_label;
		}
	}
return NULL;
}

char *get_br_label_with_threshold(FD_nj_plot *fd_nj_plot, struct noeud *a, struct noeud *b)
{
	float value;
	char *label = get_br_label(fd_nj_plot, a, b);
	if(label != NULL && fd_nj_plot->bootstrap_threshold > 0.01) {
		sscanf(label, "%f", &value);
		if(value < fd_nj_plot->bootstrap_threshold) label = NULL;
	}
	return label;
}


int get_br_from_bouts(FD_nj_plot *fd_nj_plot, struct noeud *a, struct noeud *b)
{
int i;
for(i=0; i<=fd_nj_plot->totbranches; i++) {
	if(fd_nj_plot->branches[i].bouta==a && fd_nj_plot->branches[i].boutb==b) 
		return i;
	if(fd_nj_plot->branches[i].boutb==a && fd_nj_plot->branches[i].bouta==b) 
		return i;
	}
return -1;
}


void free_tree(FD_nj_plot *fd_nj_plot)
{
	int i;
	if(fd_nj_plot->notu == 0) return;
	/* de-allocate all memory */
	for(i=0; i<2*fd_nj_plot->notu - 1; i++) {
		free(fd_nj_plot->tabtax[i]->nom);
		free(fd_nj_plot->tabtax[i]);
		}
	free(fd_nj_plot->tabtax);
	for(i=0; i<fd_nj_plot->notu - 1; i++)
		if(fd_nj_plot->branches[i].br_label != NULL) free(fd_nj_plot->branches[i].br_label);
	free(fd_nj_plot->branches);
	free(fd_nj_plot->widnames);
	free(fd_nj_plot->noms);
	free(fd_nj_plot->points);
	free(fd_nj_plot->traits);
	free(fd_nj_plot->profs);
	for(i = 0; i < fd_nj_plot->notu; i++) free(fd_nj_plot->labels[i]);
	free(fd_nj_plot->labels);
	free(fd_nj_plot->br_length_txt);
	if(fd_nj_plot->tree_name != NULL) {
	  free(fd_nj_plot->tree_name);
	  fd_nj_plot->tree_name = NULL;
	  }
	if(fd_nj_plot->current_tree != NULL) {
	  free(fd_nj_plot->current_tree);
	  fd_nj_plot->current_tree = NULL;
	  }
	if(fd_nj_plot->tree_label != NULL) {
	  free(fd_nj_plot->tree_label);
	  fd_nj_plot->tree_label = NULL;
	  }
}


/* ecriture d'un arbre non racine au format phylip, multifurcations allowed */
char *ecrit_arbre_parenth_unrooted(FD_nj_plot *fd_nj_plot, struct noeud *root)
{
struct noeud *t1, *t2, *t3;
char *p1, *p2, *p3, *p, *bootstrap;
int l;
float l1, l2, l3;	

if(root == NULL) return NULL;
t1 = root->v1->v1; t2 = root->v1->v2; t3 = root->v2;
l1 = root->v1->l1; l2 = root->v1->l2; 
if(t1 == NULL) {
	t1 = root->v2->v1; t2 = root->v2->v2; t3 = root->v1;
	l1 = root->v2->l1; l2 = root->v2->l2; 
	}
l3 = root->l1 + root->l2;
bootstrap = get_br_label(fd_nj_plot, root->v1, root->v2);
if(bootstrap == NULL) bootstrap = (char *)"";

p1 = ecrit_arbre_parenth(fd_nj_plot, t1);  *(p1 + strlen(p1) - 1) = 0;
p2 = ecrit_arbre_parenth(fd_nj_plot, t2);  *(p2 + strlen(p2) - 1) = 0;
p3 = ecrit_arbre_parenth(fd_nj_plot, t3);  *(p3 + strlen(p3) - 1) = 0;
l = strlen(p1) + strlen(p2)+ strlen(p3) + 150;
p = (char *)check_alloc(l, 1);
if(fd_nj_plot->has_br_length) sprintf(p, "(%s:%.5f,%s:%.5f,%s%s:%.5f);", p1, l1, p2, l2, p3, bootstrap, l3);
else sprintf(p, "(%s,%s,%s%s);", p1, p2, p3, bootstrap);
free(p1); free(p2); free(p3);
return p;
}


/* ecriture d'un arbre racine au format phylip, multifurcations allowed */
char *ecrit_arbre_parenth(FD_nj_plot *fd_nj_plot, struct noeud *root)
{
char *arbre, *fin, *p;
int l, maxarbre = 2 * fd_nj_plot->long_arbre_parenth + 1000;

arbre=check_alloc( maxarbre+20,1);
fin=recur_ecrit_arbre(fd_nj_plot, root,arbre,arbre+maxarbre-1);
/* ecriture du dernier label interne */
if( fin != NULL && (p=get_br_label(fd_nj_plot, root->v1,root->v2)) != NULL ) {
	l=strlen(p);
	if(fin+l>=arbre+maxarbre) fin= NULL;
	else	{
		memcpy(fin+1,p,l);
		fin+=l;
		}
	}
if(fin == NULL) {
	free(arbre);
	return NULL;
	}
strcpy(fin+1,";");
arbre = (char *)realloc(arbre, strlen(arbre) + 1);
return arbre;
}


char *recur_ecrit_arbre(FD_nj_plot *fd_nj_plot, struct noeud *centre, char *arbre, char *finarbre)
{
int l;
char *p, *q;

if(centre->v1==NULL && centre->v2==NULL) {
	p = centre->nom;
	if(*p == ')' || *p == '(') p++;//skip square mark
	l = strlen(p);
	if(arbre+l>=finarbre) return NULL;	
	memcpy(arbre,p,l);
	arbre += l-1;
	}
else	{
	*arbre='(';
	p = arbre;
	arbre=recur_ecrit_arbre(fd_nj_plot, centre->v1,arbre+1,finarbre);
	if(arbre==NULL) return NULL;
	if(fd_nj_plot->has_br_length) {
		if(arbre+10>=finarbre) return NULL;
		sprintf(++arbre,":%.5f",centre->l1);
		while(*arbre!=0) arbre++;
		}
	else arbre++;
	*arbre=',';
	arbre=recur_ecrit_arbre(fd_nj_plot, centre->v2,arbre+1,finarbre);
	if(arbre==NULL) return NULL;
	if(fd_nj_plot->has_br_length) {
		if(arbre+10>=finarbre) return NULL;
		sprintf(++arbre,":%.5f",centre->l2);
		while(*arbre!=0) arbre++;
		}
	else arbre++;
	*arbre=')';
	/* ecriture des fd_nj_plot->labels internes */
	if( (q=get_br_label(fd_nj_plot, centre,centre->v3) ) != NULL  && (fd_nj_plot->has_br_length || (centre->l3 != 0) ) ) {
		l=strlen(q);
		if(arbre+l>=finarbre) return NULL;
		memcpy(arbre+1,q,l);
		arbre+=l;
		}
	else if(centre->v3 != NULL && (!fd_nj_plot->has_br_length) && (centre->l3 == 0) ) {//multibranches processed here
		memmove(p, p + 1, arbre - p);
		arbre -= 2;
	}
}
return arbre;
}


void removeroot(FD_nj_plot *fd_nj_plot)
{
struct noeud *p1, *p2;
p1=fd_nj_plot->racine->v1;
p2=fd_nj_plot->racine->v2;
if(p1->v1 == fd_nj_plot->racine )
	{p1->v1 = p2; p1->l1 = fd_nj_plot->root_br_l;}
else if (p1->v2 == fd_nj_plot->racine)
	{p1->v2 = p2; p1->l2 = fd_nj_plot->root_br_l;}
else
	{p1->v3 = p2; p1->l3 = fd_nj_plot->root_br_l;}
if(p2->v1 == fd_nj_plot->racine )
	{p2->v1 = p1; p2->l1 = fd_nj_plot->root_br_l;}
else if (p2->v2 == fd_nj_plot->racine)
	{p2->v2 = p1; p2->l2 = fd_nj_plot->root_br_l;}
else
	{p2->v3 = p1; p2->l3 = fd_nj_plot->root_br_l;}
fd_nj_plot->rooted = 0;
}


int calc_n_desc(struct noeud *pere)
{
if(pere->v1 == NULL) return 1;
else return calc_n_desc(pere->v1) + calc_n_desc(pere->v2);
}


void disconnect_tree_windows(SEA_VIEW *view)
//disconnect all tree windows pointing to view
{
	Fl_Window *w = Fl::first_window();
	while(w != NULL) {
		const char *c = w->xclass();
		if(c != NULL && strcmp(c, TREE_WINDOW) == 0) {
			FD_nj_plot *fd_nj_plot = (FD_nj_plot *)(w->user_data());
			if(fd_nj_plot->view == view) fd_nj_plot->view = NULL;
			}
		w = Fl::next_window(w);
	}
}


int calc_new_order(int *intree, struct noeud *from, char **names, int tot_seqs, int found, char **pmissing)
//computes tree-based order of names
//upon return, intree[old] = new
//returns # of names found in array names, or 0 if any was not found
{
	if(from->v1 == NULL && from->v2 == NULL) {
		int i;
		for(i = 0; i < tot_seqs; i++) if(intree[i] == -1 && strcmp(names[i], from->nom) == 0) break;
		if(i < tot_seqs) {
			intree[i] = found++;
			return found;
			}
		else {
			*pmissing = from->nom;
			return 0;
			}
		}
	found = calc_new_order(intree, from->v2, names, tot_seqs, found, pmissing);
	if(found != 0) 	found = calc_new_order(intree, from->v1, names, tot_seqs, found, pmissing);
	return found;
}


void reorder_following_tree(struct noeud *root, int notu, SEA_VIEW *view)
{
	int i, j;
	char *missing_name;
	if(view == NULL || view->alt_col_rank != NULL) return;
	
	int *intree = (int *)malloc(view->tot_seqs * sizeof(int));
	for( i = 0; i < view->tot_seqs; i++) intree[i] = -1;
	int found = calc_new_order(intree, root, view->seqname, view->tot_seqs, 0, &missing_name);
	if(found != notu) { 
		fl_alert("Missing tree sequence from alignment: [%s]", missing_name);
		free(intree); 
		return; 
		}
	int *order = (int *)malloc(view->tot_seqs * sizeof(int));
	int *fromtree = (int *)malloc(notu * sizeof(int));
	for( j = 0, i = 0; i < view->tot_seqs; i++) {
		if(intree[i] != -1) fromtree[j++] = i;
		}
	for( i = 0; i < view->tot_seqs; i++) {
		if(intree[i] == -1) order[i] = i;
		else order[i] = fromtree[intree[i]];
		}
	free(fromtree); free(intree);
	char **tmp = (char **)malloc(view->tot_seqs * sizeof(char *));
	memcpy(tmp, view->sequence, view->tot_seqs * sizeof(char *));
	for( i = 0; i < view->tot_seqs; i++) view->sequence[order[i]] = tmp[i];
	if(view->comments != NULL) {
		memcpy(tmp, view->comments, view->tot_seqs * sizeof(char *));
		for( i = 0; i < view->tot_seqs; i++) view->comments[order[i]] = tmp[i];
		}
	memcpy(tmp, view->seqname, view->tot_seqs * sizeof(char *));
	for( i = 0; i < view->tot_seqs; i++) view->seqname[order[i]] = tmp[i];
	memcpy(tmp, view->col_rank, view->tot_seqs * sizeof(char *));
	for( i = 0; i < view->tot_seqs; i++) view->col_rank[order[i]] = tmp[i];
	if(view->viewasprots != NULL) {
		memcpy(tmp, view->viewasprots, view->tot_seqs * sizeof(char *));
		for( i = 0; i < view->tot_seqs; i++) ((char **)(view->viewasprots))[order[i]] = tmp[i];
		}
	free(tmp);
	int *tmpint = (int *)malloc(view->tot_seqs * sizeof(int));
	memcpy(tmpint, view->each_length, view->tot_seqs * sizeof(int));
	for( i = 0; i < view->tot_seqs; i++) view->each_length[order[i]] = tmpint[i];
	if(view->tot_sel_seqs != 0) {
		memcpy(tmpint, view->sel_seqs, view->tot_seqs * sizeof(int));
		for( i = 0; i < view->tot_seqs; i++) view->sel_seqs[order[i]] = tmpint[i];
		}
	for(int numset = 0; numset < view->numb_species_sets; numset++) {
		for(i = 0; i < view->tot_seqs; i++)
			tmpint[order[i]] = view->list_species_sets[numset][i];
		memcpy(view->list_species_sets[numset], tmpint, view->tot_seqs * sizeof(int) );
	}
	free(tmpint);
	if(!view->cursor_in_comment) {
		view->cursor_seq = order[view->cursor_seq - 1] + 1;
		view->old_cursor_seq = view->cursor_seq;
		}
	free(order);
	set_seaview_modified(view, TRUE);
	view->DNA_obj->redraw();
	view->DNA_obj->take_focus();
}

static void search_callback(Fl_Widget *wgt, void *data)
{
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)wgt->user_data();
	static char select[500] = "";
	char aux[500];
	int num, trouve;
	
	if(fd_nj_plot->notu == 0) return;
	if(strcmp(((Fl_Menu_ *)wgt)->text(), "Find") == 0) {
		const char *p = fl_input("Enter searched name:", select);
		if(p == NULL) return;
		strcpy(select, p);
		majuscules(select);
	}
	if(strlen(select) == 0) return;
	if(fd_nj_plot->fd_unrooted != NULL) {
		unrooted_search((FD_unrooted *)fd_nj_plot->fd_unrooted, select);
		return;
		}
	trouve = FALSE;
	for(num = 0; num <= fd_nj_plot->totnoms; num++) {
		strcpy(aux, (fd_nj_plot->noms+num)->nom);
		majuscules(aux);
		if(strstr( aux, select) != NULL) {
			(fd_nj_plot->noms+num)->disp_option = 'r';
			trouve = TRUE;
		}
	}
	if(trouve) {
		fd_nj_plot->panel->window()->redraw();
	}
}

void bt_threshold_callback(Fl_Widget *wgt, void *data)
{
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)wgt->user_data();
  Fl_Menu_Item *item = fd_nj_plot->menu_edit->get_menu();
	const char *reply = fl_input("Enter bootstrap threshold value", NULL);
	if(reply == NULL) return;
  char *p = (char *)(item + 6)->label();
	if (strcmp(p, "0") != 0) free(p);
	(item + 6)->label(strdup(reply));
	sscanf(reply, "%f", &fd_nj_plot->bootstrap_threshold);
	fd_nj_plot->need_runtree = TRUE;
	fd_nj_plot->panel->window()->redraw();
}


void midpoint_callback(Fl_Widget *wgt, void *data)
{
	struct noeud *v1, *v2;
	double l, l1, l2;
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)wgt->user_data();
	if(fd_nj_plot->notu == 0) return;
	v1 = fd_nj_plot->racine->v1; v2 = fd_nj_plot->racine->v2;
	l1 = fd_nj_plot->racine->l1; l2 = fd_nj_plot->racine->l2;
	removeroot(fd_nj_plot);
	l = place_midpoint_root(fd_nj_plot->tabtax[0], fd_nj_plot->racine);
	if(fd_nj_plot->racine->v1 != v2 || fd_nj_plot->racine->v2 != v1) {//accept new root
		fd_nj_plot->root_br_l = l;
		fd_nj_plot->root_num = -1;
		}
	else {//don't accept to only exchange v1 & v2 of previous root
		fd_nj_plot->racine->v1 = v1; fd_nj_plot->racine->v2 = v2;
		fd_nj_plot->racine->l1 = l1; fd_nj_plot->racine->l2 = l2;
		}
	fd_nj_plot->rooted = TRUE;
	fd_nj_plot->need_runtree = TRUE;
	fd_nj_plot->panel->window()->redraw();	
}

void edit_tree_header(Fl_Widget *wgt, void *data)
{
	char *p, *newtree;
	int i;
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)wgt->user_data();
	if(fd_nj_plot->notu == 0) return;
	SEA_VIEW *view = fd_nj_plot->view;
	const char *reply = fl_input("Set tree header:", fd_nj_plot->tree_label);
	if(reply == NULL) return;
	if(fd_nj_plot->tree_label != NULL) free(fd_nj_plot->tree_label);
	fd_nj_plot->tree_label = strdup(reply);
	fd_nj_plot->panel->window()->redraw();
	if(view == NULL) return;
	p = fd_nj_plot->current_tree;
	for(i = 0; i < view->tot_trees; i++) {//search for current tree among known trees
		if(strcmp(view->trees[i], p) == 0) break;
		}
	if(i >= view->tot_trees) return;
	while(*p == ' ') p++;
	if(*p == '[') {
		p = strchr(p, ']');
		if(p == NULL) return;
		p++;
		}
	while(*p == ' ') p++;
	newtree = (char *)malloc(strlen(reply) + strlen(p) + 3);
	sprintf(newtree, "[%s]%s", reply, p);
	free(fd_nj_plot->current_tree);
	fd_nj_plot->current_tree = newtree;
	free(view->trees[i]);
	view->trees[i] = strdup(newtree);
}


void set_win_size_callback(Fl_Widget *wgt, void *data)
{
	int w = 300, h = 100;
	char current[30];
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)wgt->user_data();
	sprintf(current, "%dx%d", fd_nj_plot->full->window()->w(), fd_nj_plot->full->window()->h() );
	const char *reply = fl_input("Enter desired window size", current);
	if(reply == NULL) return;
	sscanf(reply, "%dx%d", &w, &h);
	fd_nj_plot->full->window()->size(w, h);
	fd_nj_plot->full->window()->size_range(300, 100);
}


int compare_newick_with_names(const char *tree, char **names, int notu, char **pname)
/* returns 0 iff names in tree are the same as in names[0::notu[
           1 when name from tree absent from names and puts differing name in *pname
		  -1 when elements in names absent from tree and puts one absent name in *pname
 */
{
	char *p = (char *)tree - 1;
	int found = 0, i, l, *seen, retval;
	char *start = NULL;
	static char name[200];
	seen = (int *)calloc(notu, sizeof(int));
	while(*(++p) != 0) {
		if(*p == '(' ) start = p + 1;
		else if(start == NULL && *p == ',') start = p + 1;
		else if(start != NULL && (*p == ')' || *p == ':' || *p == ',') ) {
			found++;
			while(*start == ' ') start++;
			memcpy(name, start, p - start); name[p - start] = 0;
			l = strlen(name) - 1; while( l >= 0 && name[l] == ' ')  name[l--] = 0;
			for(i = 0; i < notu; i++) if(strcmp(name, names[i]) == 0) break;
			if(i == notu) {
				if(pname != NULL) *pname = name;
				free(seen);
				return 1;
				}
			else seen[i] = 1;
			if(*p != ',') start = NULL; else start = p + 1;
			}
		}
	for(i = 0; i < notu; i++) if(!seen[i]) break;
	if(i < notu) {
		strcpy(name, names[i]);
		if(pname != NULL) *pname = name;
		retval = -1;
	}
	else retval = 0;
	free(seen);
	return retval;
}


void edit_shape_callback(Fl_Widget *obj, void *data)
{
FD_nj_plot *fd_nj_plot = (FD_nj_plot *)obj->user_data();
Fl_Menu_Item *item = (Fl_Menu_Item*)((Fl_Menu_ *)obj)->mvalue();
if( fd_nj_plot->notu == 0) return;
if( fd_nj_plot->select_clade_button == NULL || item->value() ) {
	char *p, *q, *oldtree, *newtree, *label;
	int in_name = FALSE;
	oldtree = ecrit_arbre_parenth( fd_nj_plot, fd_nj_plot->racine);
	label = fd_nj_plot->tree_label;
	newtree = (char *)malloc(strlen(oldtree) + 1);//rewrite tree without lengths nor bootstrap
	q = newtree;
	p = oldtree - 1;
	while(*(++p) != 0) {
		if( *p != '(' && (*(p-1) == ',' || *(p-1) == '(')) {
			in_name = TRUE;
			*q++ = *p;
			continue;
			}
		else if(in_name) {
			if(strchr(":,()", *p) != NULL) in_name = FALSE;
			}
		if(in_name || *p == ',' || *p == ')' || *p == '(') *q++ = *p;
		}
	*(q++) = ';'; *q = 0;
	free(oldtree);
	if(fd_nj_plot->select_clade_button == NULL) {
		Fl_Window *w = treedraw(newtree, fd_nj_plot->view, "edited_tree", FALSE);
		fd_nj_plot = (FD_nj_plot *)w->user_data();
		int x = fd_nj_plot->l_button->x();
		int y = fd_nj_plot->l_button->y();
		Fl_Group::current(fd_nj_plot->l_button->parent());
		fd_nj_plot->select_clade_button = new Fl_Button(x, y, 90, 20, "Select group");
		fd_nj_plot->delete_clade_button = new Fl_Button(fd_nj_plot->select_clade_button->x() + fd_nj_plot->select_clade_button->w() 
														+ 5, y, 90, 20, "Delete group");
		fd_nj_plot->complete_edit_button = new Fl_Button(fd_nj_plot->delete_clade_button->x() + fd_nj_plot->delete_clade_button->w() 
														 + 5, y, 65, 20, "End edit");
		fd_nj_plot->select_clade_button->callback(select_clade_callback, fd_nj_plot);
		fd_nj_plot->delete_clade_button->callback(delete_clade_callback, fd_nj_plot);
		fd_nj_plot->complete_edit_button->callback(complete_edit_callback, fd_nj_plot);
	  (fd_nj_plot->menu_edit->get_menu() + fd_nj_plot->edit_shape_rank)->flags = FL_MENU_TOGGLE;
		if(label != NULL) fd_nj_plot->tree_label = strdup(label);
		}
	else {
		fd_nj_plot->select_clade_button->show();
		fd_nj_plot->delete_clade_button->show();
		fd_nj_plot->complete_edit_button->show();
		}
	fd_nj_plot->l_button->hide();
	fd_nj_plot->bt_button->hide();
	if(fd_nj_plot->root_unroot != NULL) fd_nj_plot->root_unroot->hide();
	(fd_nj_plot->menu_edit->get_menu() + fd_nj_plot->edit_shape_rank)->set();
	fd_nj_plot->menu_file->bar_item()->deactivate();
	select_clade_callback(NULL, fd_nj_plot);
	}
else {
	complete_edit_callback(NULL, fd_nj_plot);
	}
}


void select_clade_callback(Fl_Widget *obj, void *data)
{
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)data;
	fd_nj_plot->choix = prune_clade;
	fd_nj_plot->select_clade_button->deactivate();
	fd_nj_plot->delete_clade_button->deactivate();
	fd_nj_plot->swap_button->value(0);
	fd_nj_plot->need_runtree = TRUE;
	fd_nj_plot->panel->window()->redraw();
}


void delete_clade_callback(Fl_Widget *obj, void *data)
{
	struct noeud *parent, *gparent, *sister;
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)data;
	parent = fd_nj_plot->prune_clade_node->v3;
	if(parent->v1 == fd_nj_plot->prune_clade_node) sister = parent->v2;
	else sister = parent->v1;
	gparent = parent->v3;
	if(gparent != NULL) {
		if(gparent->v1 == parent) { gparent->v1 = sister; gparent->l1 += sister->l3; sister->l3 = gparent->l1; }
		else { gparent->v2 = sister; gparent->l2 += sister->l3; sister->l3 = gparent->l2; }
		sister->v3 = gparent; 
		}
	else {
		struct noeud *X, *Y;
		X = sister->v1; Y = sister->v2;
		if(X == NULL || Y == NULL) return;
		parent->v1 = X; parent->l1 = sister->l3 + X->l3;
		X->v3 = parent; X->l3 = parent->l1;
		parent->v2 = Y; parent->l2 = sister->l3 + Y->l3;
		Y->v3 = parent; Y->l3 = parent->l2;
		}
	clear_squares_below(fd_nj_plot->racine);
	char *newtree = ecrit_arbre_parenth(fd_nj_plot, fd_nj_plot->racine);
	char *p = strdup(fd_nj_plot->tree_name);
	char *q;
	if(fd_nj_plot->tree_label != NULL) q = strdup(fd_nj_plot->tree_label);
	else q = NULL;
	free_tree(fd_nj_plot);
	fd_nj_plot->tree_name = p;
  fd_nj_plot->full->window()->label(p);
	fd_nj_plot->tree_label = q;
	fd_nj_plot->current_tree = newtree;
	if(preptree(fd_nj_plot) == NULL) {
		select_clade_callback(NULL, data);
		}
	else {
		fd_nj_plot->notu = 0;
		fd_nj_plot->panel->window()->redraw();
		}
}

	
void complete_edit_callback(Fl_Widget *obj, void *data)
{
	FD_nj_plot *fd_nj_plot = (FD_nj_plot *)data;
	fd_nj_plot->l_button->show();
	fd_nj_plot->bt_button->show();
	if(fd_nj_plot->root_unroot != NULL) fd_nj_plot->root_unroot->show();
	((Fl_Menu_Item *)fd_nj_plot->menu_edit->get_menu() + fd_nj_plot->edit_shape_rank)->clear();
	fd_nj_plot->select_clade_button->hide();
	fd_nj_plot->delete_clade_button->hide();
	fd_nj_plot->complete_edit_button->hide();
	fd_nj_plot->choix = show_tree;
	fd_nj_plot->need_runtree = TRUE;
	fd_nj_plot->panel->window()->redraw();
	fd_nj_plot->menu_file->bar_item()->activate();
}


void sel_next_in_subtree(struct noeud *center, SEA_VIEW *view, char **missing)
{
	if(center == NULL) return;
	if(center->v1 == NULL || center->v2 == NULL || center->v3 == NULL) {//a leaf
		int i;
		for(i = 0; i < view->tot_seqs; i++)
			if(view->sel_seqs[i] == 0 && strcmp(center->nom, view->seqname[i]) == 0) break;
		if(i < view->tot_seqs) {
			view->sel_seqs[i] = 1;
			}
		else if(*missing == NULL) *missing = center->nom;
		}
	sel_next_in_subtree(center->v1, view, missing);
	sel_next_in_subtree(center->v2, view, missing);
}


void select_in_alignment(FD_nj_plot *fd_nj_plot)
//selects in alignment all members of subtree
{
	char *missing = NULL;
	SEA_VIEW *view = fd_nj_plot->view;
	if(view == NULL || fd_nj_plot->subtree_center == NULL) return;
	view->tot_sel_seqs = 0;
	memset(view->sel_seqs, 0, view->tot_seqs * sizeof(int));
	sel_next_in_subtree(fd_nj_plot->subtree_center, view, &missing);
	for(int i = 0; i < view->tot_seqs; i++) if(view->sel_seqs[i]) view->tot_sel_seqs++;
	select_deselect_seq(view, -2);
	view->DNA_obj->redraw();
	if(view->tot_sel_seqs != fd_nj_plot->subtree_notu) 
		fl_alert("At least one subtree leave not found in alignment: %s", missing);
}


static FD_nj_plot *find_matching_tree_window(SEA_VIEW *view)
{ // returns the FD_nj_plot of the first tree window found that refers to view
  // and that is in selection mode
  Fl_Window *win = Fl::first_window();
  while (win) {
    const char *c;
    if (!win->parent() && (c = win->xclass()) != NULL && strcmp(c, TREE_WINDOW) == 0) {
      FD_nj_plot *fd_nj_plot = (FD_nj_plot *)(win->user_data());
      if (fd_nj_plot->select->value() && fd_nj_plot->view == view) {
	return fd_nj_plot;
      }
    }
    win = Fl::next_window(win);
  }
  return NULL;
}


void select_deselect_in_tree(SEA_VIEW *view)
{ // select/deselect seqs in tree following selection in view
  FD_nj_plot* tree_plot = find_matching_tree_window(view);
  if (tree_plot) {
    tree_plot->need_runtree = TRUE;
    tree_plot->panel->window()->redraw();
  }
}


void print_title(int x, int y, char *text, int family, int size, int p, int totp)
{
	static char ligne[200];
	time_t heure;
	int h;
	
	time (&heure);
	sprintf(ligne, "Seaview    %s    %s", text, ctime(&heure) );
	h = strlen(ligne) - 1; ligne[h] = 0;
	if(totp > 1) sprintf(ligne + h, " Page %d of %d", p, totp);
	fl_color(FL_BLACK);
	fl_font(family, size);
	fl_draw(ligne, x, y);
}

extern void print_unrooted(FD_unrooted *fd_unrooted, const char *name, bool to_ps_file, const char *directname = NULL);
void print_plot(FD_nj_plot *fd_nj_plot, bool to_ps_file, const char *directname)
{
  if(fd_nj_plot->fd_unrooted != NULL) {
    print_unrooted((FD_unrooted *)fd_nj_plot->fd_unrooted, fd_nj_plot->tree_name, to_ps_file, directname);
    return;
    }
  double currx, curry;
  int h, page, superpos, frompage, topage, error, title_height, title_ascent;
  int true_print_rect_x, true_print_rect_y, true_print_rect_w, true_print_rect_h;
  int title_rect_x, title_rect_y, title_rect_w, title_rect_h;
  
  if(fd_nj_plot->notu == 0) return;
  if (fd_nj_plot->full) my_watch_cursor(fd_nj_plot->full->window());
  Fl_Printer* myprinter;
  if (to_ps_file) {
    myprinter = (Fl_Printer*)new Fl_PDF_or_PS_File_Device();
    if (directname) {
      error = ((Fl_PDF_or_PS_File_Device*)myprinter)->begin_document(directname, printout_pageformat);
      }
    else error = ((Fl_PDF_or_PS_File_Device*)myprinter)->start_job(fd_nj_plot->tree_name, printout_pageformat);
    frompage = 1;
    topage = fd_nj_plot->page_count;
    }
  else {
    myprinter = new Fl_Printer();
    error = myprinter->start_job(fd_nj_plot->page_count, &frompage, &topage);
    }
  if (error) {
    fl_reset_cursor(fd_nj_plot->full->window());
    return;
  }
#ifndef NO_PDF
  jmp_buf *jbuf;
  if (to_ps_file) ((Fl_PDF_File_Device*)myprinter)->surface_try(&jbuf);
  if ( (!to_ps_file) || setjmp(*jbuf) == 0) { // replaces PDF_TRY
#endif
  myprinter->printable_rect(&true_print_rect_w, &true_print_rect_h);
  true_print_rect_x = true_print_rect_y = 0;
  fl_font(FL_TIMES, 11);
  calc_text_size((char*)"Mq", &title_height, &title_ascent);
  title_rect_x = true_print_rect_x; 
  title_rect_y = true_print_rect_y;
  title_rect_w = true_print_rect_w; 
  title_rect_h = title_ascent;
  true_print_rect_y += title_height;
  true_print_rect_h -= title_height;
    fl_font(fd_nj_plot->font_family, fd_nj_plot->font_size);
    calc_text_size((char*)"Mq", &fd_nj_plot->char_height, &fd_nj_plot->ascent);

  h = true_print_rect_h;
  superpos = h / 30;	
  fd_nj_plot->totnoms = fd_nj_plot->tottraits = fd_nj_plot->totpoints = -1;
  end_br_length = fd_nj_plot->br_length_txt;
  currx = 0.;
  maxx = 0.;
  nexty = -fd_nj_plot->deltay;
  if(fd_nj_plot->subtree_center == NULL)
	  mem_plot(fd_nj_plot, NULL, fd_nj_plot->racine, currx, &curry);
  else
	  mem_plot(fd_nj_plot, fd_nj_plot->subtree_ascend, fd_nj_plot->subtree_center, currx, &curry);
  physx = true_print_rect_w;
  physy = (fd_nj_plot->page_count - 1) * (h - superpos) + h - 1;
  page_x_offset = true_print_rect_x;
  page_y_offset = true_print_rect_y;
  page_y_offset -= (frompage - 1) * (h - superpos);
  for(page = frompage; page <= topage; page++) {
    myprinter->start_page();
    fl_push_clip(title_rect_x, title_rect_y, title_rect_w, title_height);
    print_title(title_rect_x, title_rect_y + title_rect_h - 1, fd_nj_plot->tree_name, 
				  FL_TIMES, 10, page, fd_nj_plot->page_count);
    fl_pop_clip();
    fl_push_clip(true_print_rect_x, true_print_rect_y, true_print_rect_w, true_print_rect_h );
    fl_font(fd_nj_plot->font_family, fd_nj_plot->font_size);
    fl_color(FL_GRAY);
    fl_rect(true_print_rect_x, true_print_rect_y, true_print_rect_w, true_print_rect_h);
    fl_color(FL_BLACK);
    do_plot(fd_nj_plot, TRUE);
    fl_pop_clip();
    myprinter->end_page();
    page_y_offset -= h - superpos;
  }
  myprinter->end_job();
#ifndef NO_PDF
  } // end of PDF_TRY
  if (to_ps_file && ((Fl_PDF_File_Device*)myprinter)->surface_catch()) { // replaces PDF_CATCH
    ((Fl_PDF_File_Device*)myprinter)->error_catch();
  }
#endif
  delete myprinter;
  fd_nj_plot->need_runtree = TRUE;
  if (fd_nj_plot->panel) fd_nj_plot->panel->redraw();	
  page_x_offset = 0;
  page_y_offset = 0;
  if (fd_nj_plot->full) fl_reset_cursor(fd_nj_plot->full->window());
}

#ifndef NO_PDF
float argval(int argc, char *argv[], const char *arg, float defval)
{
  for (int i = 1; i < argc - 1; i++) {
    if (strcmp(argv[i], arg) == 0) {
      sscanf(argv[i+1], "%f", &defval);
      break;
      }
    }
  return defval;
}

char *argname(int argc, char *argv[], const char *arg)
{
  for (int i = 1; i < argc - 1; i++) {
    if (strcmp(argv[i], arg) == 0) {
      return argv[i+1];
    }
  }
  return NULL;
}


bool isarg(int argc, char *argv[], const char *arg)
{
  for (int i = 1; i < argc; i++) {
    if (strcmp(argv[i], arg) == 0) return true;
  }
  return false;
}

extern int debut_arbre(const char *tree, FD_unrooted *fd_unrooted);
void plotonly(int argc, char *argv[])
{
  const char *fname = argv[argc-1];
  FILE *in = fopen(fname, "r");
  if (!in) return;
  fseek(in, 0, SEEK_END);
  long l = ftell(in);
  fseek(in, 0, SEEK_SET);
  char *tree = (char *)malloc(l + 1);
  char *p = tree;
  while(l-- > 0) {
    char c = fgetc(in);
    if(c != '\n' && c != '\r') *(p++) = c;
  }
  *p = 0;
  fclose(in);
  FD_nj_plot *fd_nj_plot = (FD_nj_plot *)calloc(1, sizeof(FD_nj_plot));
  fd_nj_plot->current_tree = tree;
  fd_nj_plot->font_size = argval(argc, argv, "-fontsize", 12);
  fd_nj_plot->page_count = argval(argc, argv, "-pagecount", 1);
  fd_nj_plot->plot_br_l = isarg(argc, argv, "-lengths");
  fd_nj_plot->show_bootstrap = 
      isarg(argc, argv, "-bootstrap") || isarg(argc, argv, "-bootstrap_threshold");
  fd_nj_plot->bootstrap_threshold = argval(argc, argv, "-bootstrap_threshold", 0);
  fd_nj_plot->choix = show_tree;
  printout_pageformat = isarg(argc, argv, "-letter") ? Fl_Paged_Device::LETTER : Fl_Paged_Device::A4;
  if (preptree(fd_nj_plot)) {
    free(fd_nj_plot);
    return;
    }
  fd_nj_plot->tree_name = strdup(fname);
  maxy = 1000.;
  runtree(fd_nj_plot);
  
  if (isarg(argc, argv, "-unrooted")) {
    char *tree = ecrit_arbre_parenth_unrooted(fd_nj_plot, fd_nj_plot->racine);
    if (tree == NULL) { return; }
    FD_unrooted *fd_unrooted = (FD_unrooted *) calloc(1, sizeof(FD_unrooted));
    fd_nj_plot->fd_unrooted = fd_unrooted;
    if ( debut_arbre(tree, fd_unrooted) ) return;
    free(tree);
    fd_unrooted->font_size = fd_nj_plot->font_size;
    }

  char *pdfname;
  if ((pdfname = argname(argc, argv, "-o")) == NULL)  {
    pdfname = (char*)malloc(strlen(fname) + 5);
    strcpy(pdfname, fname);
    if ((p = strrchr(pdfname, '.')) == NULL) p = pdfname + strlen(pdfname);
    strcpy(p, ".pdf");
    }
  print_plot(fd_nj_plot, true, pdfname);
  if (argname(argc, argv, "-o") == NULL) free(pdfname);
}
#endif // NO_PDF

#if !(defined(__APPLE__) || defined(WIN32)) && 100*FL_MAJOR_VERSION + 10*FL_MINOR_VERSION  + FL_PATCH_VERSION == 130
// for X11 under 1.3.0 only
#undef Fl_Printer
#undef Fl_PostScript_File_Device
corr_Fl_Printer::corr_Fl_Printer() : Fl_Printer() {
  count = 0;
}

corr_Fl_PostScript_File_Device::corr_Fl_PostScript_File_Device() : Fl_PostScript_File_Device() {
  count = 0;
}


// bypass FLTK 1.3.0 bug where printable_rect() not usable before start_page() on X11
int corr_Fl_Printer::start_job(int pagecount, int *frompage, int *topage) {
  int retval = Fl_Printer::start_job(pagecount, frompage, topage);
  if (retval) return retval;
  start_page();
  return 0;
}

int corr_Fl_PostScript_File_Device::start_job(int pagecount, enum Fl_Paged_Device::Page_Format format, 
						     enum Fl_Paged_Device::Page_Layout layout)
 {
  int retval = Fl_PostScript_File_Device::start_job(pagecount, format, layout);
  if (retval) return retval;
  start_page();
  return 0;
}

int corr_Fl_PostScript_File_Device::start_job(FILE *file, int pagecount, enum Fl_Paged_Device::Page_Format format, 
					      enum Fl_Paged_Device::Page_Layout layout)
{
  int retval = Fl_PostScript_File_Device::start_job(file, pagecount, format, layout);
  if (retval) return retval;
  start_page();
  return 0;
}

// correct FLTK 1.3.0 Fl_PostScript_Printer bug where %%PageBoundingBox is missing.
int corr_Fl_Printer::start_page() {
  if (count++ == 1) return 0;
  int retval = Fl_Printer::start_page();
  Fl_PostScript_Graphics_Driver *d = (Fl_PostScript_Graphics_Driver*)driver();
  if (count == 1) {
    m = (int)d->pw_;
    M = (int)d->ph_;
    if(m > M) {
      int x;
      x = m; m = M; M = x;
    }
  }
  fprintf(d->output, "%%%%PageBoundingBox: 0 0 %d %d\n", m, M);
  return retval;
}

int corr_Fl_PostScript_File_Device::start_page()
{
  if (count++ == 1) return 0;
  int retval = Fl_PostScript_File_Device::start_page();
  Fl_PostScript_Graphics_Driver *d = (Fl_PostScript_Graphics_Driver*)driver();
  if (count == 1) {
    m = (int)d->pw_;
    M = (int)d->ph_;
    if(m > M) {
      int x;
      x = m; m = M; M = x;
    }
  }
  fprintf(d->output, "%%%%PageBoundingBox: 0 0 %d %d\n", m, M);
  return retval;
}
#endif // for X11 under 1.3.0 only
