/**************************************************************
 * Structured Markov Chains Solver       [  SMCSolver  ]      *
 * Dario Bini, Beatrice Meini, Sergio Steffe'                 *
 * bini@dm.unipi.it, meini@dm.unipi.it, steffe@dm.unipi.it    *
 * Dipartimento di Matematica "Leonida Tonelli"               *
 * Largo Pontecorvo 5                                         *
 * 56127 Pisa                                                 *
 * Italy                                                      *
 * Version 1.1 - Oct 2006                                     *
 **************************************************************
 *
 *  edit-b.c - view and edit B0, BN1, B  - both callbacks and interfaces
 *
 */

#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <libgen.h>
#include <gtk/gtk.h>
#include <errno.h>
#include <ctype.h> /* character functions */
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <gdk-pixbuf/gdk-pixbuf.h>

#include "structures.h"
#include "edit_b.h"

#define  PIX 500   /* drawing area side */

/* Edit B Window  **** Interface */
void
create_edit_b_window()
{
/* GtkWidget *window_edit_b; global */
GtkWidget *vboxm_editb;
GtkWidget *hbox1,*hbox2;
GtkWidget *vbox1,*vbox2;
GtkWidget *vbox11,*vbox14;
/* GtkWidget *edit_vbox12b,*edit_vbox13b; globale */
GtkWidget *hsep11,*hsep12,*hsep13; /* separators */
GtkWidget *label_v11,*label_v12,*label_v13; /* titles for button groups */
GtkWidget *button_pos_neg;
GtkWidget *button_color;
GtkWidget *button_user;
GtkWidget *hbox_contrast;
GtkWidget *label_contrast;
GtkWidget *button_contrast;
GtkWidget *button_range_normal; 
GtkWidget *button_range_adaptive;
GtkWidget *button_range_block;  
GSList *range_list = NULL;
GtkWidget *hsep1,*hsep2,*vsep0,*vsep1,*vsep2; /* separators */
GtkWidget *vbox21,*vbox22, *vbox23;
GtkWidget *label_211,*label_212; /* labels with matrix results */
GtkWidget *label_221; /* labels with matrix results */
/* GtkWidget *label_222b, *label_231b, *label_232b; globals */
GtkWidget *button_truncate;
/* GtkWidget  *matareab; global */
GtkWidget *hbox_matlabels;
GtkWidget *label_mat;
GtkWidget *toolbar_ed;
GtkWidget *tmp_toolbar_icon;
GtkWidget *button_quit_ed;
GtkWidget *hbox_block;
GtkWidget *button_up,*button_down;
GtkWidget *label1_block,*label2_block;
/* GtkWidget *entry_blockb; global */
/* int b_selected_block; global */
GtkWidget *hbox_aij;
GtkWidget *label_aij;
/* GtkWidget *label_spaceb; global */
/* GtkWidget   *entryb_ij; global */
/* GtkWidget   *entryb_aij; global */
/* GtkWidget *statusb_editb; global */
/* unsigned char *matvalueb; globals */
char buf[256];
/* double *bs, bsmax;  globals   allocated in create_edit_b_window, sum of rows of block and maximum value of bock */
int nblk;

/* window_edit_b */
window_edit_b=gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window_edit_b), "View and Edit  Matrix B");
gtk_window_set_default_size (GTK_WINDOW (window_edit_b), 720, 700);
b_selected_block = peb.block; /* we need this value here */
gdk_rgb_init();

/* vboxm_editb - main vertical box*/
vboxm_editb = gtk_vbox_new (FALSE, 5);
gtk_widget_show (vboxm_editb);
gtk_container_add (GTK_CONTAINER (window_edit_b), vboxm_editb);
/* divided in four hbox */
hbox1=gtk_hbox_new(FALSE,5);
gtk_widget_show(hbox1);
gtk_box_pack_start (GTK_BOX (vboxm_editb), hbox1, FALSE, FALSE, 5);
/* first hbox divided in 2 vbox */
/* first vbox in first hbox  for buttons and hboxes */
vbox1=gtk_vbox_new(FALSE,5);
gtk_box_pack_start (GTK_BOX (hbox1), vbox1, FALSE, FALSE, 5);
gtk_widget_show(vbox1);
/* first vbox on the left contains buttons and hboxes in 3 vboxes */
vbox11 = gtk_vbox_new(FALSE,5);
gtk_box_pack_start (GTK_BOX (vbox1), vbox11, FALSE, FALSE, 0);
gtk_widget_show(vbox11);
label_v11 = gtk_label_new("DISPLAY CONTROL\n     change to: ");
gtk_widget_show(label_v11);
gtk_box_pack_start (GTK_BOX (vbox11), label_v11, TRUE, FALSE, 0);
/* button positive / negative s_positive=0 default is positive i.e. black is 1 white is 0*/
button_pos_neg = gtk_button_new();
if (peb.is_positive==1)  gtk_button_set_label (GTK_BUTTON(button_pos_neg)," Positive ");
          else           gtk_button_set_label (GTK_BUTTON(button_pos_neg)," Negative ");
gtk_widget_show (button_pos_neg);
gtk_box_pack_start (GTK_BOX (vbox11), button_pos_neg, TRUE, FALSE, 0);
/* button b/n - color default is_color=0 is black&white */ 
button_color = gtk_button_new();
if (peb.is_color==1)  gtk_button_set_label (GTK_BUTTON(button_color),"  B & W  ");
          else        gtk_button_set_label (GTK_BUTTON(button_color),"  Color  ");
gtk_widget_show (button_color);
gtk_box_pack_start (GTK_BOX (vbox11), button_color, TRUE, FALSE, 0);
/* button enhance = no enhance*/
button_user = gtk_button_new();
/* set labels depending on previous setup choices */
if (peb.is_user==1)  gtk_button_set_label (GTK_BUTTON(button_user),"  STANDARD   ");
          else       gtk_button_set_label (GTK_BUTTON(button_user),"    USER     ");
gtk_widget_show (button_user);
gtk_box_pack_start (GTK_BOX (vbox11), button_user, TRUE, FALSE, 0);

/* horizontal separator */
hsep11 = gtk_hseparator_new();
gtk_widget_show(hsep11);
gtk_box_pack_start (GTK_BOX (vbox1), hsep11, FALSE, FALSE, 0);
edit_vbox12b = gtk_vbox_new(TRUE,5);
gtk_box_pack_start (GTK_BOX (vbox1), edit_vbox12b, FALSE, FALSE, 0);
gtk_widget_show(edit_vbox12b);
label_v12 = gtk_label_new("USER CONTRAST");
gtk_widget_show(label_v12);
gtk_box_pack_start (GTK_BOX (edit_vbox12b), label_v12, TRUE, FALSE, 0);
/* contrast spin button */
hbox_contrast = gtk_hbox_new(FALSE,0);
gtk_widget_show (hbox_contrast);
gtk_box_pack_start (GTK_BOX (edit_vbox12b), hbox_contrast, TRUE, FALSE, 0);
label_contrast = gtk_label_new(" contrast");
gtk_widget_show (label_contrast);
gtk_box_pack_start (GTK_BOX (hbox_contrast),label_contrast, TRUE, FALSE, 0);
button_contrast = gtk_spin_button_new_with_range(-20,20,1);
gtk_widget_show (button_contrast);
gtk_box_pack_start (GTK_BOX (hbox_contrast), button_contrast, TRUE, FALSE, 0);
gtk_spin_button_set_digits (GTK_SPIN_BUTTON(button_contrast),0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON(button_contrast),peb.contrast_value);
gtk_entry_set_editable(GTK_ENTRY(button_contrast),FALSE);
/* horizontal separator */
hsep12 = gtk_hseparator_new();
gtk_widget_show(hsep12);
gtk_box_pack_start (GTK_BOX (vbox1), hsep12, FALSE, FALSE, 0);
edit_vbox13b = gtk_vbox_new(TRUE,5);
gtk_box_pack_start (GTK_BOX (vbox1), edit_vbox13b, FALSE, FALSE, 0);
gtk_widget_show(edit_vbox13b);
label_v13 = gtk_label_new("USER    RANGE");
gtk_widget_show(label_v13);
gtk_box_pack_start (GTK_BOX (edit_vbox13b), label_v13, TRUE, FALSE, 0);
/* button normal range*/
button_range_normal = gtk_radio_button_new_with_label(NULL,"  [0,1]  ");
range_list = gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_range_normal));
gtk_widget_show (button_range_normal);
gtk_box_pack_start (GTK_BOX (edit_vbox13b), button_range_normal, TRUE, FALSE, 0);
/* button range block */
button_range_block = gtk_radio_button_new_with_label(range_list," [min,max] ");
range_list = gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_range_normal));
gtk_widget_show (button_range_block);
gtk_box_pack_start (GTK_BOX (edit_vbox13b), button_range_block, TRUE, FALSE, 0);
/* button range adaptive */
button_range_adaptive = gtk_radio_button_new_with_label(range_list," adaptive ");
gtk_widget_show (button_range_adaptive);
gtk_box_pack_start (GTK_BOX (edit_vbox13b), button_range_adaptive, TRUE, FALSE, 0);
switch (peb.is_range_type) {
        case 0:
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button_range_normal),TRUE);
                break;
        case 1:
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button_range_block),TRUE);
                break;
        case 2:
                gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_range_adaptive),TRUE);
                break;
        }

/* horizontal separator */
hsep13 = gtk_hseparator_new();
gtk_widget_show(hsep13);
gtk_box_pack_start (GTK_BOX (vbox1), hsep13, FALSE, FALSE, 0);

vbox14 = gtk_vbox_new(FALSE,5);
gtk_box_pack_start (GTK_BOX (vbox1), vbox14, FALSE, FALSE, 0);
gtk_widget_show(vbox14);
label_v13 = gtk_label_new("MATRIX MODIFY");
gtk_widget_show(label_v13);
gtk_box_pack_start (GTK_BOX (vbox14), label_v13, TRUE, FALSE, 0);

/* truncate button */
button_truncate = gtk_button_new_with_label("Truncate\n outside [0,1] ");
gtk_widget_show (button_truncate);
gtk_box_pack_start (GTK_BOX (vbox14), button_truncate, TRUE, FALSE, 0);
/* vertical separator */
vsep0 = gtk_vseparator_new();
gtk_widget_show(vsep0);
gtk_box_pack_start (GTK_BOX (hbox1), vsep0, FALSE, FALSE, 0);

/* second vbox in first hbox for matrix display */
vbox2=gtk_vbox_new(FALSE,5);
gtk_widget_show(vbox2);
gtk_box_pack_end (GTK_BOX (hbox1), vbox2, FALSE, FALSE, 0);
gtk_container_set_border_width (GTK_CONTAINER (vbox2), 10);
/* matrix drawable area */
gtk_widget_push_visual(gdk_rgb_get_visual());
gtk_widget_push_colormap(gdk_rgb_get_cmap());
matareab =  gtk_drawing_area_new();
gtk_widget_pop_visual();
gtk_widget_pop_colormap();
gtk_widget_show(matareab);
gtk_drawing_area_size  (GTK_DRAWING_AREA(matareab),PIX,PIX);
gtk_box_pack_start (GTK_BOX (vbox2), matareab, FALSE, FALSE, 0);
/* add mouse positioning events to matareab */
gtk_widget_add_events (GTK_WIDGET(matareab),GDK_POINTER_MOTION_MASK);
gtk_widget_add_events (GTK_WIDGET(matareab),GDK_BUTTON_PRESS_MASK);
hbox_matlabels = gtk_hbox_new(FALSE,0);
gtk_widget_show(hbox_matlabels);
gtk_box_pack_start (GTK_BOX (vbox2), hbox_matlabels, FALSE, FALSE, 0);
label_mat = gtk_label_new(" Block of Matrix B Graphic Display ");
gtk_widget_show(label_mat);
gtk_box_pack_start (GTK_BOX (hbox_matlabels), label_mat, FALSE, FALSE, 0);
edit_labelb_user = gtk_label_new("                             USER LEVELS");
if (peb.is_user==0) gtk_label_set_text(GTK_LABEL(edit_labelb_user),"                          STANDARD LEVELS");
else gtk_label_set_text(GTK_LABEL(edit_labelb_user),"                             USER LEVELS");
gtk_widget_show(edit_labelb_user);
gtk_box_pack_start (GTK_BOX (hbox_matlabels), edit_labelb_user, FALSE, FALSE, 0);

/* horizontal separator */
hsep1 = gtk_hseparator_new();
gtk_widget_show(hsep1);
gtk_box_pack_start (GTK_BOX (vboxm_editb), hsep1, FALSE, FALSE, 0);

/* second hbox contains various data show boxes */
hbox2=gtk_hbox_new(FALSE,5);
gtk_widget_show(hbox2);
gtk_box_pack_start (GTK_BOX (vboxm_editb), hbox2, FALSE, FALSE, 0);
/* matrix #blocks and dimensions */
vbox21 = gtk_vbox_new(TRUE,5);
gtk_box_pack_start (GTK_BOX (hbox2), vbox21, TRUE, TRUE, 0);
gtk_widget_show(vbox21);
/*
 * B consist of B0 matrix, committed.dimension_n x committed.dimension_n,           b_selected_block=0
 *              BN1 matrix                                                          b_selected_block=-1
 *              B committed.matrix_b_num matrices                                   b_selected_block=1...committed.matrix_b_num
 * BN1 and B can be optional and have different possibly non square dimensioning
 * depending on the committed.type problem QBD, MG1, GIM1 
 * for optional blocks no editing is possible (A blocks are used instead) and a fallback is used
 * for rectangular blocks  dimensions are globals b_dim_m,b_dim_n b_d is the max of the two 
 */
if (committed.dimension_m >=committed.dimension_n) b_d=committed.dimension_m; else b_d=committed.dimension_n;
nblk=1; /* B0 is one - we do not count the optional blocks derived from A */
if(committed.is_bn1) nblk++;
if(committed.is_b) nblk=nblk+committed.matrix_b_num;

if(committed.is_b) {
    if(committed.is_bn1) sprintf(buf," %d Blocks B (-1,0,..%d) ",nblk,nblk-2);
       else sprintf(buf," %d Blocks B (0,..%d) ",nblk,nblk-1);
	} else {
    if(committed.is_bn1) sprintf(buf," %d Blocks B (-1,0) ",nblk);
       else sprintf(buf," Something wrong !");
	}
label_211 = gtk_label_new(buf);
gtk_widget_show(label_211); 
gtk_box_pack_start (GTK_BOX (vbox21), label_211, TRUE, TRUE, 0);

sprintf(buf," [ dimensions  %d and %d  ",committed.dimension_m, committed.dimension_n);
label_212 = gtk_label_new(buf);
gtk_widget_show(label_212);
gtk_box_pack_start (GTK_BOX (vbox21), label_212, FALSE, FALSE, 0);
/* vertical separator */
vsep1 = gtk_vseparator_new();
gtk_widget_show(vsep1);
gtk_box_pack_start (GTK_BOX (hbox2), vsep1, FALSE, FALSE, 0);
vbox22 = gtk_vbox_new(TRUE,0);
gtk_box_pack_start (GTK_BOX (hbox2), vbox22, TRUE, TRUE, 0);
gtk_widget_show(vbox22);
sprintf(buf,"Global Stochasticity Defect");
label_221 = gtk_label_new(buf);
gtk_widget_show(label_221);
gtk_box_pack_start (GTK_BOX (vbox22), label_221, TRUE, TRUE, 0);
sprintf(buf,"  %lg  ",st_def_b(committed.type)); 
label_222b = gtk_label_new(buf);
gtk_widget_show(label_222b);
gtk_box_pack_start (GTK_BOX (vbox22), label_222b, TRUE, TRUE, 0);
/* vertical separator */
vsep2 = gtk_vseparator_new();
gtk_widget_show(vsep2);
gtk_box_pack_start (GTK_BOX (hbox2), vsep2, FALSE, FALSE, 0);
vbox23 = gtk_vbox_new(TRUE,0);
gtk_box_pack_start (GTK_BOX (hbox2), vbox23, TRUE, TRUE, 0);
gtk_widget_show(vbox23);
label_231b = gtk_label_new(" ");
gtk_widget_show(label_231b);
gtk_box_pack_start (GTK_BOX (vbox23), label_231b, TRUE, TRUE, 0);
label_232b = gtk_label_new(" ");
gtk_widget_show(label_232b);
gtk_box_pack_start (GTK_BOX (vbox23), label_232b, TRUE, TRUE, 0);

/* horizontal separator */
hsep2 = gtk_hseparator_new();
gtk_widget_show(hsep2);
gtk_box_pack_start (GTK_BOX (vboxm_editb), hsep2, FALSE, FALSE, 0);

/* third hbox consists in toolbox  */
/* toolbar begins */
toolbar_ed = gtk_toolbar_new ();
gtk_widget_show (toolbar_ed);
gtk_box_pack_start (GTK_BOX (vboxm_editb), toolbar_ed, FALSE, FALSE, 0);
gtk_container_set_border_width (GTK_CONTAINER (toolbar_ed), 10);
gtk_toolbar_set_style (GTK_TOOLBAR (toolbar_ed), GTK_TOOLBAR_BOTH);
/* cancel button  first position */
tmp_toolbar_icon = gtk_image_new_from_stock ("gtk-quit", gtk_toolbar_get_icon_size (GTK_TOOLBAR (toolbar_ed)));
button_quit_ed = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar_ed),
                                GTK_TOOLBAR_CHILD_BUTTON,
                                NULL,
                                "Close",
                                NULL, NULL,
                                tmp_toolbar_icon, NULL, NULL);
gtk_widget_show(button_quit_ed);
/* blocks choice hbox */
hbox_block =gtk_hbox_new(TRUE,0);
gtk_box_set_homogeneous (GTK_BOX(hbox_block),FALSE);
label1_block = gtk_label_new("               Block : ");
gtk_widget_show (label1_block);
gtk_box_pack_start (GTK_BOX (hbox_block), label1_block, FALSE, FALSE, 0);
button_down= gtk_button_new_from_stock ("gtk-go-down");
gtk_widget_show(button_down);
gtk_box_pack_start (GTK_BOX (hbox_block), button_down, FALSE, FALSE, 0);
entry_blockb = gtk_entry_new_with_max_length (4);
gtk_entry_set_width_chars (GTK_ENTRY(entry_blockb),5);
gtk_widget_show(entry_blockb);
gtk_box_pack_start (GTK_BOX (hbox_block), entry_blockb, FALSE, FALSE, 0);
sprintf(buf,"%d",b_selected_block);
gtk_entry_set_text(GTK_ENTRY(entry_blockb), buf);
button_up= gtk_button_new_from_stock ("gtk-go-up");
gtk_widget_show(button_up);
gtk_box_pack_start (GTK_BOX (hbox_block), button_up, FALSE, FALSE, 0);
label2_block = gtk_label_new("  ");
gtk_widget_show (label2_block);
gtk_box_pack_start (GTK_BOX (hbox_block), label2_block, FALSE, FALSE, 0);
gtk_widget_show(gtk_toolbar_append_element (GTK_TOOLBAR (toolbar_ed),
                                GTK_TOOLBAR_CHILD_WIDGET,
                                hbox_block,
                                "",
                                NULL, NULL,
                                NULL, NULL, NULL));
/* A(i,j)= x hbox */
hbox_aij = gtk_hbox_new(TRUE,0);
gtk_box_set_homogeneous (GTK_BOX(hbox_aij),FALSE);
label_aij=gtk_label_new("   Value : ");
gtk_box_pack_start (GTK_BOX (hbox_aij), label_aij, FALSE, FALSE, 0);
gtk_widget_show (label_aij);
entryb_ij = gtk_entry_new_with_max_length (14);
gtk_entry_set_width_chars (GTK_ENTRY(entryb_ij),15);
gtk_entry_set_editable (GTK_ENTRY(entryb_ij),FALSE);
gtk_widget_show(entryb_ij);
gtk_box_pack_start (GTK_BOX (hbox_aij),entryb_ij,FALSE, FALSE, 0);
entryb_aij = gtk_entry_new_with_max_length (16);
gtk_entry_set_width_chars (GTK_ENTRY(entryb_aij),20);
gtk_entry_set_editable(GTK_ENTRY(entryb_aij),FALSE);
gtk_widget_show(entryb_aij);
gtk_box_pack_start (GTK_BOX (hbox_aij),entryb_aij,FALSE, FALSE, 0);
gtk_widget_show(gtk_toolbar_append_element (GTK_TOOLBAR (toolbar_ed),
                                GTK_TOOLBAR_CHILD_WIDGET,
                                hbox_aij,
                                "",
                                NULL, NULL,
                                NULL, NULL, NULL));
/* label space with editing/view only message */
labelb_space = gtk_label_new("(view only)   ");
gtk_widget_show (labelb_space);
gtk_widget_show(gtk_toolbar_append_element (GTK_TOOLBAR (toolbar_ed),
                                GTK_TOOLBAR_CHILD_WIDGET,
                                labelb_space,
                                "",
                                NULL, NULL,
                                NULL, NULL, NULL));

/* fourth hbox consists in statusbar  */
/**************** statusbar  begins        */
statusb_editb = gtk_statusbar_new();
gtk_widget_show (statusb_editb);
gtk_box_pack_end (GTK_BOX (vboxm_editb), statusb_editb, FALSE, FALSE, 0);
/**************** statusbar ends           */

/* initialize */
if (peb.is_user==0) {
         gtk_widget_set_sensitive(edit_vbox12b,FALSE);
         gtk_widget_set_sensitive(edit_vbox13b,FALSE);
         }

is_freezeb_aij=0;
/* allocate space for graphic buffers and block computations */
matvalueb=calloc((PIX)*PIX,sizeof(char));
rgb_matvalueb=calloc(3*(PIX)*PIX,sizeof(guchar));
bs=malloc((committed.dimension_m+1)*sizeof(double)); /* remember that index goes from 1 to committed.dimension_m .. Fortran style */

if ((matvalueb==NULL)||(rgb_matvalueb==NULL)) {
        gtk_statusbar_push(GTK_STATUSBAR(statusb_editb),0,"   Sorry, there is NOT enougth memory left for graphic window");
        } else { 
	max_min_bb_compute(); /*compute dimensions and min and max values for the b_selected_block block  */
	gray_levelsb_setup(peb.contrast_value);  /*compute gray levels */
        image_computeb(b_selected_block);  /*compute matvalueb */
        /* no need to draw the image: an expose event will be produced drawing window !*/ 
	if((peb.is_range_type==2)&&(peb.is_user==1)) {recompute_levelsb(peb.contrast_value);image_computeb(b_selected_block);} 
        }
g_idle_add((GtkFunction) b_labels_update,NULL);
if (committed.dimension_m > 250) 
    gtk_statusbar_push(GTK_STATUSBAR(statusb_editb),0,"  Warning: Matrix Display is not accurate for dimensions larger then 250 x 250");

/**************** connect signals  begin   */
g_signal_connect ((gpointer) window_edit_b, "destroy", G_CALLBACK (on_edit_b_menu_destroy_activate),NULL);
g_signal_connect ((gpointer) button_quit_ed, "clicked", G_CALLBACK(on_edit_b_menu_quit_activate),NULL);
if (matvalueb!=NULL) { /* do not activate drawings calls if no memory for buffers */
                g_signal_connect (G_OBJECT (matareab), "expose_event",  G_CALLBACK (draw_matareab_callback), NULL);
		g_signal_connect ((gpointer) button_pos_neg, "clicked", G_CALLBACK(on_edit_b_pos_neg_activate),NULL);
                g_signal_connect ((gpointer) button_color, "clicked", G_CALLBACK(on_edit_b_color_activate),NULL);
		g_signal_connect ((gpointer) button_contrast, "changed", G_CALLBACK (on_edit_b_contrast_changed), NULL);
                g_signal_connect ((gpointer) button_user, "clicked", G_CALLBACK(on_edit_b_user_activate),NULL);
                g_signal_connect ((gpointer) button_range_normal, "toggled", G_CALLBACK(on_edit_b_range_normal_activate),NULL);
                g_signal_connect ((gpointer) button_range_block, "toggled", G_CALLBACK(on_edit_b_range_block_activate),NULL);
                g_signal_connect ((gpointer) button_range_adaptive, "toggled", G_CALLBACK(on_edit_b_range_adaptive_activate),NULL);
                g_signal_connect ((gpointer) button_up, "clicked", G_CALLBACK(on_edit_b_button_up_activate),NULL);
                g_signal_connect ((gpointer) button_down, "clicked", G_CALLBACK(on_edit_b_button_down_activate),NULL);
                g_signal_connect ((gpointer) entry_blockb, "changed", G_CALLBACK(on_edit_b_block_entry_changed),NULL); 
                g_signal_connect ((gpointer) entry_blockb, "activate", G_CALLBACK(on_edit_b_block_entry_activated),NULL);
  
g_signal_connect (G_OBJECT (matareab), "motion_notify_event",  G_CALLBACK (xy_matareab), NULL);
gtk_signal_connect (GTK_OBJECT (matareab), "button_press_event", (GtkSignalFunc) button_press_matareab, NULL);
g_signal_connect ((gpointer) entryb_aij, "activate", G_CALLBACK(on_edit_b_float_entry_activate),NULL);
                  }
g_signal_connect ((gpointer) button_truncate, "clicked", G_CALLBACK(on_edit_b_truncate_activate),NULL);

/**************** connect signals  end     */

gtk_widget_show_all(window_edit_b);
}
/*********************************/

/******************* Callbacks:  Buttons and  widgets on the toolbar ***********************/

/* Edit A Window: Quit  **** Callback */
void
on_edit_b_menu_quit_activate   (GtkMenuItem  *menuitem, gpointer  user_data)
{
if(is_debug==1) printf("on_edit_b_menu_quit_activate: quit\n");
gtk_widget_destroy(GTK_WIDGET(window_edit_b));
if(is_debug==1) printf("on_edit_b_menu_quit_activate: exiting \n");   
}
/*********************************/

/* response to destroy window event */
void
on_edit_b_menu_destroy_activate   (GtkWidget  *ww, gpointer  user_data)
{
if(is_debug==1) printf("on_edit_b_menu_destroy_activate: \n");

/* save block number */
peb.block=b_displayed_block;
/* free space of the graphic buffers */
free(matvalueb);
free(rgb_matvalueb);
free(bs);
is_edit_b_open=0;  /* 0=not open  1=open */
gtk_widget_destroy(GTK_WIDGET(window_edit_b));
if(is_debug==1) printf("on_edit_b_menu_destroy_activate: exiting Edit B; preferences: %d %d %d %d %g %d\n",peb.block,peb.is_positive,peb.is_color,peb.is_user,peb.contrast_value,peb.is_range_type);

}
/*********************************/


/* B block max */
double
bbmax(int q)
{
double max,r;
int i,j;
max=-1.0E100;
for(i=1;i<=committed.dimension_m;i++)  for(j=1;j<=committed.dimension_m;j++) {
/*  read_mata_(&i,&j,&q,&r);*/
  if (max < r) max=r;
  }
return(max);
}
/*********************************/

/* B block min */
double
bbmin(int q)
{
double min,r;
int i,j;
min=1.0E100;
for(i=1;i<=committed.dimension_m;i++)  for(j=1;j<=committed.dimension_m;j++) {
/*  read_mata_(&i,&j,&q,&r);*/
  if (min > r) min=r;
  }
return(min);
}
/*********************************/

/* B  max */
double
bamax()
{
double max,r;
int k;
max=bbmax(1);
for(k=2;k<=committed.matrix_a_num;k++)   {
  r=bbmax(k);
  if (max < r) max=r;
  }
return(max);
}
/*********************************/

/* B  min */
double
bamin()
{
double min,r;
int k;
min=bbmin(1);
for(k=2;k<=committed.matrix_a_num;k++)   {
  r=bbmin(k);
  if (min > r) min=r;
  }

return(min);
}
/*********************************/

/* compute max min every time block is changed */
/* more: this routine computes b_dim_m,b_dim_n */
/* the block is b_selected_block  */
void
max_min_bb_compute()
{
int i,j,q;
double r;

/* first step, compute bdim_m and b_dim_n for the block */
q=b_selected_block;
if (q==0) { /* Block B0 */
	b_dim_m=committed.dimension_n;
        b_dim_n=committed.dimension_n;
	}
if (q==-1) { /* Block BN1 */
	if (committed.type==3) { /* GIM1 have exchanged dimensions */
           b_dim_n=committed.dimension_m;
           b_dim_m=committed.dimension_n;
           } else {
           b_dim_n=committed.dimension_n;
           b_dim_m=committed.dimension_m;
          }
	}
if (q>0) { /* Blocks B  exchanged respect BN1 */
        if (committed.type==3) { /* GIM1 have exchanged dimensions */
           b_dim_n=committed.dimension_n;
           b_dim_m=committed.dimension_m;
           } else {
           b_dim_n=committed.dimension_m;
           b_dim_m=committed.dimension_n;
          }
        }

i=1;
j=1;
if (q==0) read_matb0_(&i,&j,&r);
else if (q==-1) read_matbn1_(&i,&j,&r);
else read_matb_(&i,&j,&q,&r);
matbbmax=r;
matbbmin=r;
matbbqmin=r;


for(i=1;i<=b_dim_m;i++) {
                for(j=1;j<=b_dim_n;j++) {
			if (q==0) read_matb0_(&i,&j,&r);
			else if (q==-1) read_matbn1_(&i,&j,&r);
			else read_matb_(&i,&j,&q,&r);
			if(matbbmin>r)matbbmin=r;
			if(matbbmax<r)matbbmax=r;
			if((matbbqmin>r)&&(r>1.0E-30))matbbqmin=r;						
                        }
                }

if(is_debug==1) printf("max_min_bb_compute: block=%d, n=%d m=%d, max=%g, min=%g qmin=%g\n",b_selected_block,b_dim_n,b_dim_m,matbbmax,matbbmin,matbbqmin);
}
/*********************************/

/* linear or nonlinear setup of gray_levels 
 * parameter a affects the shape of nonlinear curve 
 * in the case of user selected range type 0 1 2 and
 * in such cases tha max and min values computed by 
 * max_min_ab_compute() are needed !
 */
void
gray_levelsb_setup(double a)
{
/* double  matbbmax, matbbmin,matbbqmin;    globals */
int i;
double min,max;
if (peb.is_user==0) {
        gray_levelsb[0]=0; /* not used ... */
        for (i=1;i<256;i++) gray_levelsb[i]= ((double)1.0 *(i-1))/254.0; /* L[1]=0.0  L[255]=1.0 */
        if(is_debug==1) printf("gray_levelsb_setup: (user=0) a=%g, L[0]=%g,L[1]=%g,L[2]=%g,...L[254]=%g,L[255]=%g\n",a,gray_levelsb[0],gray_levelsb[1],gray_levelsb[2],gray_levelsb[254],gray_levelsb[255]);
        return;
        } else {
        switch(peb.is_range_type) {
           case 2:
                min=matbbqmin; /* first non zero minimum if possible */
                max=matbbmax;
                break;
           case 1: /* [matabqmin,asmax] */
                min=matbbqmin;
                max=matbbmax;
                break;
           case 0: /* [0,1] full range */
                min=0;
                max=1;
                break;
           default:
                min=0;
                max=1;
           }
       if(min==max) {min=0;max=1;} /* is needed ??? */
       gray_levelsb[0]=0;
       gray_levelsb[1]=0; /* hard minimum is fixed to 0.0 */
       if(a==0) for (i=2;i<256;i++) gray_levelsb[i]= (max-min)*((double)1.0 *(i-1))/254.0 + min;
       if(a>0) for (i=2;i<256;i++) gray_levelsb[i]= (max-min)*pow(((double)1.0 *(i-1))/254.0,a)+min;
       if(a<0) for (i=2;i<256;i++) gray_levelsb[i]= (max-min)*pow(((double)1.0 *(i-1))/254.0,-1/(a-1))+min;
       }
if(is_debug==1) printf("gray_levelsb_setup: (user=1) a=%g, max=%g min=%g L[0]=%g,L[1]=%g,L[2]=%g,...L[254]=%g,L[255]=%g\n",a,max,min,gray_levelsb[0],gray_levelsb[1],gray_levelsb[2],gray_levelsb[254],gray_levelsb[255]);
}
/*********************************/

/* calculating image from B block data */
void
image_computeb(int q)
{
/* int b_selected_block,b_computed_block,b_displayed_block; globals */
/* int * matvalueb; global */
int i,j,h,k,m,n,v;
double r;
if(is_debug==1) printf("image_computeb: block %d\n",q);
/* b_d is the maximum between b_dim_m and b_dim_n */
/* we draw the matrices as immersed in b_d x b_d, leaving blank the unused area */
m=b_dim_m;
n=b_dim_n;
if (peb.is_range_type==2) for(i=0;i<256;i++) numlevb[i]=0; /* adaptive range type */

if (peb.is_color==0) {
   /* compute matvalueb   for gray  */
   for(i=0;i<PIX;i++) for(j=0;j<PIX;j++) {
        h=(i*b_d)/PIX+1;
        k=(j*b_d)/PIX+1;
        if (j<PIX) { /* block values */
			if((h>b_dim_m)||(k>b_dim_n)) {r=0.0;} else {
			  if (q==0) read_matb0_(&h,&k,&r);
                          else if (q==-1) read_matbn1_(&h,&k,&r);
                          else read_matb_(&h,&k,&q,&r);
			}
                  v=get_gray_levelb(r);
                  if ((peb.is_range_type==2)&&(peb.is_user==1)) numlevb[v]++;
                 if (peb.is_positive==1) v=255-v;
                  matvalueb[i*(PIX)+j]=  (char)v;
                }
        }
   /* matvalueb computed */
   } else {
   /* compute rgb_matvalue for colors */
   for(i=0;i<PIX;i++) for(j=0;j<PIX;j++) {
        h=(i*b_d)/PIX+1;
        k=(j*b_d)/PIX+1;
        if (j<PIX) { /* block values */
			if((h>b_dim_m)||(k>b_dim_n)) {r=0.0;} else {
		          if (q==0) read_matb0_(&h,&k,&r);
                          else if (q==-1) read_matbn1_(&h,&k,&r);
                          else read_matb_(&h,&k,&q,&r);
			}
                  v=get_gray_levelb(r);
                  if ((peb.is_range_type==2)&&(peb.is_user==1)) numlevb[v]++;
                  if (peb.is_positive==1) v=255-v;
                  rgb_matvalueb[3*(i*(PIX)+j)]=  (char)v;
                  rgb_matvalueb[3*(i*(PIX)+j)+1]=  (char)(35);
                  rgb_matvalueb[3*(i*(PIX)+j)+2]= (char)(255-v);
                }
        }
   /* rgb_matvalue computed */
   }
b_computed_block=q;
if(is_debug==1) printf("image_computeb: b_computed_block=%d \n",b_computed_block);
}
/*********************************/

/* the levels gray_levels[256] are number ordered increasing  */
/* we get the index i such that gray_levels[i]<=x<gray_levels[i+1] */
/* precisely:
 * 0   x (-inf,L[1])  L[1]=0 typical   L[0] not used !!!
 * 1   x [L[1], L[2])
 * .....
 * 254 x [L[254],L[255]) 
 * 255 x [L255], +inf) L[255]=1 typical
 */
int
get_gray_levelb(double x)
{
int i;
i=0;
if (x > gray_levelsb[128])  i=128;
if (x > gray_levelsb[i+64]) i+=64;
if (x > gray_levelsb[i+32]) i+=32;
if (x > gray_levelsb[i+16]) i+=16;
if (x > gray_levelsb[i+8]) i+=8;
if (x > gray_levelsb[i+4]) i+=4;
if (x > gray_levelsb[i+2]) i+=2;
if (x > gray_levelsb[i+1]) i+=1;
return(i);
}
/*********************************/

/* draw matarea uses matvalue or rgb_matvalue to redraw into matarea drawable and sets a_displayed_block */
void
draw_matareab()
{
if (peb.is_color==0) gdk_draw_gray_image (matareab->window,
                matareab->style->fg_gc[GTK_WIDGET_STATE (matareab)],
                0, 0, PIX,PIX,GDK_RGB_DITHER_NORMAL,matvalueb,PIX);
                else
                gdk_draw_rgb_image(matareab->window,
                matareab->style->fg_gc[GTK_WIDGET_STATE (matareab)],
                0, 0, PIX,PIX,GDK_RGB_DITHER_NORMAL,rgb_matvalueb,3*(PIX));
b_displayed_block=b_computed_block;
}
/*********************************/

/* Draw Matrix Block from buffer matvalueib   ****** Callback "expose" event */
gboolean
draw_matareab_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
GdkCursor  *crosshair;
/* int a_selected_block,a_computed_block,a_displayed_block; globals */

/* gdk_draw_rectangle (widget->window,
                widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
                TRUE,
                0,0,30,30);*/
if (b_selected_block!=b_computed_block) {
                image_computeb(b_selected_block);
                if((peb.is_range_type==2)&&(peb.is_user==1)) {recompute_levelsb(peb.contrast_value);image_computeb(b_selected_block);}
                }
crosshair = gdk_cursor_new(GDK_TCROSS);
gdk_window_set_cursor(widget->window, crosshair);
gdk_cursor_destroy(crosshair);
draw_matareab();
b_displayed_block=b_computed_block;
if (is_debug==1) printf("draw_matareab_callback: b_displayed_block=%d\n",b_displayed_block);
return TRUE;
}
/*********************************/

/* adaptive case: recompute levels 
 * using old levels and numerosity of levels numlev 
 * must be called after computing once gray levels and image
 */
void
recompute_levelsb(double a)
{ 
/* double gray_levels[256]; global */
double newlev[256];
double max,min,v;
int quota[256], interval[256],interval_num[256];
int i,j,k,h;
int s,usl,unusl,spacers;
int cont;
/* memo:
 * the levels gray_levels[256] are number ordered increasing  
 * we get the index i such that gray_levels[i]<=x<gray_levels[i+1] 
 * precisely:
 * 0   x (-inf,L[1])  L[1]=0 typical   L[0] not used !!! numlevel[0] refers to <= L[1]
 * 1   x [L[1], L[2])                                    numlevel[1] refers to  <=L[2]
 * .....
 * 254 x [L[254],L[255]) 
 * 255 x [L255], +inf) L[255]=1 typical                  numlevel[255] refers to >=L[255] 
 */
/* memo:
 * in the step prior to this, we did call max_min_ab_compute and  gray_levels_setup with
 * min=matabqmin; max=asmax; and the choosen contrast, L[0]=L[1]=0,
 * and L[2]...L[255] were assigned with
 * (max-min)*pow(((double)1.0 *(i-1))/254.0,a)+min or similar, depending on 
 * the contrast a.
 */
/* memo:
 * PIX*(PIX+PIV) is the total number of pixels, the sum of numlev.
 */

/* count unused levels  */
usl=0;
unusl=0;
for(i=0;i<256;i++) if( numlevb[i] ==0) unusl++; else usl++;
if(is_debug==1) {
                printf("recompute_levels:  entering we count on 256 levels %d assigned levels,   %d unassigned levels\n",usl,unusl);
                }
/* clean all */
for(i=0;i<256;i++){
                interval[i]=0;
                interval_num[i]=0;
                newlev[i]=-1.0;
                quota[i]=0;
                }
/* compute interval[i], reporting the number of nonvoid levels starting on i-th level */
for(i=0;i<256;i++){
    if(numlevb[i]!=0) {
        j=i;
        cont=0;
        while (cont==0){
                j++;
                if((numlevb[j]==0)||(j==256)) cont=1;
                }
        interval[i]=j-i; /* if j==i 1 */
        i=j;
       }/* else increment i */
    }
/* compute numerosity of intervals */
for (i=0;i<256;i++) if (interval[i]!=0) {
        s=0;
        for (j=i;j<i+interval[i];j++) s=s+numlevb[j];
        interval_num[i]=s;
        }
if(is_debug==1) for(i=0;i<256;i++) if(interval_num[i]!=0) printf("recompute_levels:  pre reassign interval[%d]=%d, interval_num=%d bounds [%g,%g]\n",i,interval[i],interval_num[i],gray_levelsb[i],gray_levelsb[i+interval[i]]);
/* reassign levels */
k=0;
for(i=0;i<256;i++) if (interval[i]!=0) k=k+interval_num[i]; /* well k should be PIX*PIX, but we check for debugging errors ... */
if(is_debug==1) printf("recompute_levels:  pre reassign interval numerosity %d - PIX=%d\n",k,PIX*PIX);
/* we now reassign the free levels giving a quota[i] to each non void interval i */
/* k is the total number of pixels involved in reassign , interval_num[i] in every interval */
for(i=0;i<256;i++) if (interval[i]!=0) { /* these are the intervals to reassign */
        v=interval_num[i] *unusl;
        quota[i]= interval[i]+floor(v/k) ;
    }
/* better count totals ... */
j=0;
for(i=0;i<256;i++) if (interval[i]!=0) j=j+quota[i];
spacers=256-j; /* these levels can be used to separate leves with void levels */
if (is_debug==1)    printf("recompute_levels:  now we count on 256 levels %d assigned levels,   %d unassigned levels, reassigning total %d, spacers=%d\n",usl,unusl,j,spacers);
/* now reassign spacers to biggest  quota  */
k=0;
for(i=0;i<256;i++) if(interval[i]!=0) if(quota[i]>k) {h=i; k=quota[i];}
quota[h]=quota[h]+spacers;
/* better recount totals ... */
j=0;
for(i=0;i<256;i++) if (interval[i]!=0) j=j+quota[i];
spacers=256-j; /* these levels can be used to separate leves with void levels */
if (is_debug==1)    printf("recompute_levels:  now we recount on 256 levels %d assigned levels,   %d unassigned levels, reassigning total %d, spacers=%d\n",usl,unusl,j,spacers);

newlev[0]=0.0;
j=1;  /*first level to reassign */
for(i=0;i<256;i++) if (interval[i]!=0) {
        min=gray_levelsb[i];
        if(i+1+interval[i] <256) max=gray_levelsb[i+1+interval[i]]; else max=1.1;
        if (is_debug==1) printf("recompute_levels: interval %d [%g,%g] : reassigning %d levels (old %d) \n",i, min,max,quota[i],interval[i]);
          if(a==0) for (k=j;k<j+quota[i];k++) newlev[k]= (max-min)*((double)1.0 *(k-j))/quota[i] + min;
          if(a>0)  for (k=j;k<j+quota[i];k++) newlev[k]= (max-min)*pow(((double)1.0 *(k-j))/quota[i],a)+min;
          if(a<0)  for (k=j;k<j+quota[i];k++) newlev[k]= (max-min)*pow(((double)1.0 *(k-j))/quota[i],-1/(a-1))+min;
          j=j+quota[i];
          }

/* at this point there should be no newlev with value -1 ! */
for(i=0;i<256;i++) if (newlev[i]==-1.0) printf("nelwv = -1 !!! %d\n",i);

/* now copy and sort the levels */
gray_levelsb[0]=newlev[0];
for(i=0;i<256;i++) { /* get the minimum for the first gray level */
        if (newlev[i]<gray_levelsb[0]) gray_levelsb[0]=newlev[i];
        }
gray_levelsb[255]=gray_levelsb[0];
for(i=0;i<256;i++) { /* get the maximum for the last gray level */
        if (newlev[i]>gray_levelsb[255]) gray_levelsb[255]=newlev[i];
        }
for(i=1;i<255;i++) { /* for others levels go growing */
     gray_levelsb[i]=gray_levelsb[255];
     for (j=0;j<256;j++) if ((newlev[j]<gray_levelsb[i])&&(newlev[j]>gray_levelsb[i-1])) gray_levelsb[i]=newlev[j];
   }

/* now insert spacers if any */
}
/*********************************/
/******************* Callbacks:  Buttons and  widgets on the left side  ***********************/

/* positive / negative choice button  */
void
on_edit_b_pos_neg_activate(GtkButton *button, gpointer my_data)
{
if( is_debug==1) printf("on_edit_b_pos_neg_activate:\n");
if (peb.is_positive==0) {
         peb.is_positive=1;
         gtk_button_set_label (button," Positive ");
         } else {
        peb.is_positive=0;
         gtk_button_set_label (button," Negative ");
        }
gray_levelsb_setup(peb.contrast_value);
image_computeb(b_selected_block);
if((peb.is_range_type==2)&&(peb.is_user==1)) {recompute_levelsb(peb.contrast_value);image_computeb(b_selected_block);}
draw_matareab();
}
/*********************************/

/* color / black % white */
void
on_edit_b_color_activate(GtkButton *button, gpointer my_data)
{
if( is_debug==1) printf("on_edit_b_color_activate:\n");
if (peb.is_color==0) {
         peb.is_color=1;
         gtk_button_set_label (button,"  B & W  ");
         } else {
        peb.is_color=0;
         gtk_button_set_label (button,"  Color  ");
        }
gray_levelsb_setup(peb.contrast_value);
image_computeb(b_selected_block);
if((peb.is_range_type==2)&&(peb.is_user==1)) {recompute_levelsb(peb.contrast_value);image_computeb(b_selected_block);}
draw_matareab();
}
/*********************************/

/* (toggle button) user:  activate user contrast settings  and redraw */
void
on_edit_b_user_activate(GtkButton *button, gpointer my_data)
{
if( is_debug==1) printf("on_edit_b_user_activate:\n");
if (peb.is_user==0) {
         peb.is_user=1;
         gtk_widget_set_sensitive(edit_vbox12b,TRUE);
         gtk_widget_set_sensitive(edit_vbox13b,TRUE);
         gtk_label_set_text(GTK_LABEL(edit_labelb_user),"                             USER LEVELS");
         gtk_button_set_label (button,"  STANDARD   ");
         } else {
         peb.is_user=0;
         gtk_widget_set_sensitive(edit_vbox12b,FALSE);
         gtk_widget_set_sensitive(edit_vbox13b,FALSE);
         gtk_label_set_text(GTK_LABEL(edit_labelb_user),"                          STANDARD LEVELS");
         gtk_button_set_label (button,"    USER     ");
        }


if(is_debug==1) printf("on_edit_b_user_activate:  contrast_value=%g, b_selected_block=%d\n",peb.contrast_value,b_selected_block);
gray_levelsb_setup(peb.contrast_value);
image_computeb(b_selected_block);
if((peb.is_range_type==2)&&(peb.is_user==1)) {recompute_levelsb(peb.contrast_value);image_computeb(b_selected_block);}
draw_matareab();
}
/*********************************/

/* read contrast and redraw */
void
on_edit_b_contrast_changed(GtkEntry *entry, gpointer my_data)
{
if( is_debug==1) printf("on_edit_b_contrast_changed:\n");
peb.contrast_value = gtk_spin_button_get_value (GTK_SPIN_BUTTON(entry));
if(peb.is_user==1) {/* the change is valid but to see result must be user mode */
                gray_levelsb_setup(peb.contrast_value);
                image_computeb(b_selected_block);
                if((peb.is_range_type==2)&&(peb.is_user==1)) {recompute_levelsb(peb.contrast_value);image_computeb(b_selected_block);}
                draw_matareab();
                }
}
/*********************************/

/* range normal and redraw (toggle) */
void
on_edit_b_range_normal_activate(GtkButton *button, gpointer my_data)
{
if( is_debug==1) printf("on_edit_b_range_normal_activate\n");
peb.is_range_type=0;
if(peb.is_user==1) {/* the change is valid but to see result must be user mode */
                gray_levelsb_setup(peb.contrast_value);
                image_computeb(b_selected_block);
                if((peb.is_range_type==2)&&(peb.is_user==1)) {recompute_levelsb(peb.contrast_value);image_computeb(b_selected_block);}
                draw_matareab();
                }
}
/*********************************/
/* range for the block  and redraw (toggle) */
void
on_edit_b_range_block_activate(GtkButton *button, gpointer my_data)
{
if( is_debug==1) printf("on_edit_b_range_block_activate:\n");
peb.is_range_type=1;
if(peb.is_user==1) {/* the change is valid but to see result must be user mode */
                gray_levelsb_setup(peb.contrast_value);
                image_computeb(b_selected_block);
                draw_matareab();
                }
}
/*********************************/

/* range for the adaptive  and redraw (toggle) */
void
on_edit_b_range_adaptive_activate(GtkButton *button, gpointer my_data)
{
if( is_debug==1) printf("on_edit_b_range_adaptive_activate:\n");
peb.is_range_type=2;
if(peb.is_user==1) {/* the change is valid but to see result must be user mode */
                gray_levelsb_setup(peb.contrast_value);
                image_computeb(b_selected_block);
                if((peb.is_range_type==2)&&(peb.is_user==1)) {recompute_levelsb(peb.contrast_value);image_computeb(b_selected_block);}
                draw_matareab();
                }
}
/*********************************/

/* truncate B block to the range [0,1] */
void on_edit_b_truncate_activate(GtkButton *button, gpointer my_data)
{
bbtrunc(b_selected_block);
max_min_bb_compute();
gray_levelsb_setup(peb.contrast_value);
image_computeb(b_selected_block);
if((peb.is_range_type==2)&&(peb.is_user==1)) {recompute_levelsb(peb.contrast_value);image_computeb(b_selected_block);}
draw_matareab();
g_idle_add((GtkFunction) b_labels_update,NULL);
sprintf(SBUFB,"    Now all the terms of all the Blocks are in the range [0,1]");
g_idle_add((GtkFunction) b_edit_status_update,NULL);
}
/*********************************/

/* B block truncate in [0,1] */
void
bbtrunc(int q)
{
int h,k;
double r;
for(h=1;h<=b_dim_m;h++)  for(k=1;k<=b_dim_n;k++) {
   if (q==0) read_matb0_(&h,&k,&r);
   else if (q==-1) read_matbn1_(&h,&k,&r);
   else read_matb_(&h,&k,&q,&r);
  if (r<(double)0.0) r=(double)0.0;
  if (r>(double)1.0) r=(double)1.0;
   if (q==0) write_matb0_(&h,&k,&r);
   else if (q==-1) write_matbn1_(&h,&k,&r);
   else write_matb_(&h,&k,&q,&r);
  }
}
/*********************************/

/* update of the statusbar - to be called after each matrix change */
int
b_edit_status_update()
{
gtk_statusbar_push(GTK_STATUSBAR(statusb_editb),0,SBUFB);
return(0);
}
/*********************************/

/* update of the labels - to be called after each matrix change and after max_min_ab_compute()*/
int
b_labels_update()
{
/* double matbbmax, matbbqmin; globals */
char buf[256];
sprintf(buf,"  %lg  ",st_def_b(committed.type));
gtk_label_set_text (GTK_LABEL(label_222b),buf);
sprintf(buf,"This Block:  %d  x  %d   ",b_dim_m,b_dim_n);
gtk_label_set_text (GTK_LABEL(label_231b),buf);
sprintf(buf," max=%g  min=%g ",matbbmax,matbbqmin);
gtk_label_set_text (GTK_LABEL(label_232b) ,buf);
return(0);
}
/*********************************/

/* increase block number and redraw *****  Callback button_up */
void 
on_edit_b_button_up_activate (GtkButton   *button, gpointer my_data )
{
/* int b_selected_block,b_displayed_block; global */
char buf[8];
if(is_debug==1) printf("on_edit_b_button_up_activate: b_selected_block(before up)=%d committed.matrix_b_num=%d\n",b_selected_block,committed.matrix_b_num);
if (((b_selected_block ==-1)||((b_selected_block>0)&&(b_selected_block<committed.matrix_b_num)))||((b_selected_block ==0)&&(committed.is_b==1))) {
/* we are at BN1 and we pass to use B0 or */
/* we are using a B block less than maximum or */
/* we are at B0, B is present and we go at a B block */
     b_selected_block++;
     max_min_bb_compute();
     sprintf(buf,"%d",b_selected_block);
     gtk_entry_set_text(GTK_ENTRY(entry_blockb), buf);
     gray_levelsb_setup(peb.contrast_value);
     image_computeb(b_selected_block);
     if((peb.is_range_type==2)&&(peb.is_user==1)) {recompute_levelsb(peb.contrast_value);image_computeb(b_selected_block);}
     draw_matareab(); 
     g_idle_add((GtkFunction) b_labels_update,NULL);
     }
}
/*********************************/

/* decrease block number and redraw *****  Callback button_down */
void 
on_edit_b_button_down_activate (GtkButton   *button, gpointer my_data )
{
/* int b_selected_block; global */
char buf[8];
if(is_debug==1) printf("on_edit_b_button_up_activate: b_selected_block(before down)=%d \n",b_selected_block);
if ((b_selected_block >=1)||((b_selected_block==0)&&(committed.is_bn1==1)) ) {
/* we are using a B block and we decrease to a B block >1  or  */
/* we are at B Block 1 and we pass at B0 or */
/* we are at B0 and BN1 is present and we pass at BN1 */
     b_selected_block--;
     max_min_bb_compute();
     sprintf(buf,"%d",b_selected_block);
     gtk_entry_set_text(GTK_ENTRY(entry_blockb), buf);
     gray_levelsb_setup(peb.contrast_value);
     image_computeb(b_selected_block);
     if((peb.is_range_type==2)&&(peb.is_user==1)) {recompute_levelsb(peb.contrast_value);image_computeb(b_selected_block);}
     draw_matareab();
     g_idle_add((GtkFunction) b_labels_update,NULL);
     }
}
/*********************************/


/* edit B Window: reads block number from entry *****  Callback "change" event */
/* simply throw away any non digit, throw away first 0, and and check range  */
void on_edit_b_block_entry_changed  (GtkEntry *entry, gpointer user_data )
{
/* GtkWidget *statusb_edita; global    */
gchar *blocks_in = NULL;
gchar blocks_out[256];
gchar  this_char = '\0';
int blocks_int;
int i=0;
int j=0;
int last=0;
if(is_debug==1) printf("on_edit_b_block_entry_changed: \n");
blocks_in = gtk_editable_get_chars(GTK_EDITABLE(entry_blockb), 0, -1);
this_char = blocks_in[0];
if (!this_char) {
    b_no_block_selected=1;
    g_free (blocks_in);
    return ;
    }
   /* 45 is "-"  */
if((this_char==45)&&(committed.is_bn1==1)) { /* put -1 as output */
    if(is_debug==1) printf("on_edit_b_block_entry_changed:  set it to -1 !\n");
    blocks_int=-1;	
    } else {
    while (last==0) { 
     if (isdigit(this_char)!=0) {
         blocks_out[i]=this_char;
         i++;
         }
         j++;
         this_char=blocks_in[j];
         if(this_char=='\0') {
               last=1;
               blocks_out[i]=this_char;
               }
    }
    if(blocks_out[0]==0) {
                g_free (blocks_in);
                gtk_entry_set_text(GTK_ENTRY(entry_blockb), blocks_out);
                return;
                }
    blocks_int=atoi(blocks_out);
    }
if(is_debug==1) printf("on_edit_b_block_entry_changed: blocks_out string = %s, blocks_int=%d\n",blocks_out,blocks_int);
/* Blocks can be -1 if bn1 is present, 0, from 1 to committed.matrix_b_num if b is present */
if (blocks_int <-1) {
                     blocks_int=-1;
                     sprintf(SBUFB,"   Blocks number must be greater than -1 !");
                     g_idle_add((GtkFunction) b_edit_status_update,NULL);
                      }
if ((blocks_int ==-1)&&(committed.is_bn1==0)) {
		     blocks_int=0;
		     sprintf(SBUFB,"   Blocks number must be at least 0 !"); 
		     g_idle_add((GtkFunction) b_edit_status_update,NULL);
		      }
if ((blocks_int >=1)&&(committed.is_b==0)) {
                     blocks_int=0;
                     sprintf(SBUFB,"   Blocks number must be at maximum 0 !");    
                     g_idle_add((GtkFunction) b_edit_status_update,NULL);
                      } 

if ((committed.is_b==1)&&(blocks_int >committed.matrix_b_num)) {
                    blocks_int=committed.matrix_b_num;
                    sprintf(SBUFB,"    Blocks maximum number is %d !",committed.matrix_b_num);
                    g_idle_add((GtkFunction) b_edit_status_update,NULL);
                      }
if ((blocks_int >= -1)&&(blocks_int <= committed.matrix_b_num)) {
                b_selected_block=blocks_int;
                sprintf(blocks_out,"%d",blocks_int);}
g_free (blocks_in);
b_no_block_selected=0;
gtk_entry_set_text(GTK_ENTRY(entry_blockb), blocks_out);
}
/*********************************/

/* edit B Window: reads block number from entry , calculates image and refresh screen ***** Callback "activate" event */
/* the entry is always correct at this stage  */
void on_edit_b_block_entry_activated  (GtkEntry *entry, gpointer user_data )
{
/* GtkWidget *statusb_edita; global    */
gchar *blocks_in = NULL;

blocks_in = gtk_editable_get_chars(GTK_EDITABLE(entry_blockb), 0, -1);
if( is_debug==1) printf("on_edit_b_block_entry_activated: %s\n",blocks_in);
sscanf(blocks_in,"%d",&b_selected_block);
max_min_bb_compute();
gray_levelsb_setup(peb.contrast_value);
image_computeb(b_selected_block);
if((peb.is_range_type==2)&&(peb.is_user==1)) {recompute_levelsb(peb.contrast_value);image_computeb(b_selected_block);}
draw_matareab();
}
/*********************************/

/* print x y position on matareab ***** Callback  from mouse moving in matarea "motion_notify" event */
gboolean
xy_matareab (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
int x,y,i,j,m,q;
GdkModifierType state;
double r;
char buf[256];
if (b_no_block_selected==1) {
                if (is_debug==1) printf("xy_matareab: no block selection\n");
                b_selected_block=b_computed_block;
                sprintf(buf,"%d",b_selected_block);
                gtk_entry_set_text(GTK_ENTRY(entry_blockb), buf);
                        }
if (b_selected_block!=b_computed_block) {
                if (is_debug==1) printf("xy_matareab: b_selected_block=%d, b_computed_block=%d, recomputing\n",b_selected_block,b_computed_block);
                image_computeb(b_selected_block);
                if((peb.is_range_type==2)&&(peb.is_user==1)) {recompute_levelsb(peb.contrast_value);image_computeb(b_selected_block);}
                g_idle_add((GtkFunction) b_labels_update,NULL);
                }
if (b_selected_block!=b_displayed_block) {
                if (is_debug==1) printf("xy_matareab: b_selected_block=%d, b_displayed_block=%d, redrawing\n",b_selected_block,b_displayed_block);
                draw_matareab();
                }
m=b_d;
q=b_selected_block;
gdk_window_get_pointer(widget->window,&x,&y,&state);
i=y*m/PIX+1;
j=x*m/PIX+1;

if(is_freezeb_aij==0) {
   if ((i <= b_dim_m)&&(j<=b_dim_n)) {
        is_frozenb_i=i;
        is_frozenb_j=j;
		if (q==0) read_matb0_(&i,&j,&r);
                          else if (q==-1) read_matbn1_(&i,&j,&r);
                          else read_matb_(&i,&j,&q,&r);
        is_frozenb=r;
        sprintf(buf,"B(%02d,%02d)=",i,j);
        gtk_entry_set_text(GTK_ENTRY(entryb_ij), buf);
        sprintf(buf,"%.8E",r);
        gtk_entry_set_text(GTK_ENTRY(entryb_aij), buf);
        } else {
                buf[0]=0;
                gtk_entry_set_text(GTK_ENTRY(entryb_ij), buf);
                gtk_entry_set_text(GTK_ENTRY(entryb_aij), buf);
        }
   }
return TRUE;
}
/*********************************/

/* click mouse button in matarea to edit value of matrix ***** Callback  "mouse_press" event */
gboolean
button_press_matareab (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
int x,y,i,j;
GdkModifierType state;

/* if we are in the correct part of the matrix */
gdk_window_get_pointer(widget->window,&x,&y,&state);
i=y*b_d/PIX+1;
j=x*b_d/PIX+1;
if ((i > b_dim_m)||(j > b_dim_n))  return FALSE;
if(is_freezeb_aij==0) { /* toggle to permit editing */
        gtk_entry_set_editable(GTK_ENTRY(entryb_aij),TRUE);
        is_freezeb_aij=1;
        gtk_label_set_text (GTK_LABEL(labelb_space),"(editable)    ");
        sprintf(SBUFB,"   To return to viewing values, click a mouse button in the drawing area  -  to finalize change, type the ENTER key on kbd");
        g_idle_add((GtkFunction) b_edit_status_update,NULL);
        }
else {
        gtk_entry_set_editable(GTK_ENTRY(entryb_aij),FALSE);
        is_freezeb_aij=0;
        gtk_label_set_text (GTK_LABEL(labelb_space),"(view only)   ");
        SBUFB[0]=0;
        g_idle_add((GtkFunction) b_edit_status_update,NULL);
        }
return TRUE;
}
/*********************************/

/* edit B Window: reads float number from entry */
/* uses watch_for_number to read string and detect valid floats - the last one is the good  */
/* watch_for_number: initialize with watch_for_number(0, 0,num_str); and fill num_str with 0 before using; add watch_for_number('\n', 1,num_str) at last.
 * return value: 0=other ASCII <128   1=considering a number    2=comment line and new line    3=new line    4=new line following a new line
 *                5=int   6=int and new line   7=floatFP   8=floatEX   9=floatFP and new line   10 floatEX and new line  11 ASCII > 127 not in comment line 
 */
void on_edit_b_float_entry_activate  (GtkEntry *entry, gpointer user_data )
{
/* GtkWidget *statusb_edita; global    */
gchar *float_in = NULL;
gchar float_out[256];
int  this_char = '\0';
double float_num;
int i=0;
int last=0;
int v; /* retrun value */
int valid;
int q; /* block number */
char num_str[1024];
if( is_debug==1) printf("on_edit_b_float_entry_activate:\n");
q=b_selected_block;
valid=0; /* non valid */
float_num=-1.0;
for(i=0;i<1024;i++)num_str[i]=0; /* clean input string */
watch_for_number(0, 0,num_str);  /* initialization     */

float_in = gtk_editable_get_chars(GTK_EDITABLE(entryb_aij), 0, -1);
last=0;
i=0;
while (last==0) {
        this_char=float_in[i];
        if(this_char!=0) {
                        v=watch_for_number(this_char,1,num_str);
                        /*if ((v==7)||(v==8)||(v==9)||(v=10)) {if(1==sscanf(num_str,"%lg",&float_num)) valid=1;}*/
                        i++;
                        } else {
                        v=watch_for_number('\n', 1,num_str);
                        /*if ((v==7)||(v==8)||(v==9)||(v=10)) {if(1==sscanf(num_str,"%lg",&float_num)) valid=1;}*/
                        last=1;
                        };
        }
if ((v==7)||(v==8)||(v==9)||(v=10)) {if(1==sscanf(num_str,"%lg",&float_num)) valid=1;}
if (is_debug==1) printf("on_edit_a_float_entry_activate: old A(%d,%d)=%g new valid=%d  %g\n",is_frozenb_i,is_frozenb_j,is_frozenb,valid,float_num);
if (valid==0) {
                sprintf(float_out,"%.8E",is_frozenb);
                gtk_entry_set_text(GTK_ENTRY(entryb_aij), float_out);
                sprintf(SBUFB,"    Entry not accepted: not a floating number !");
                g_idle_add((GtkFunction) b_edit_status_update,NULL);
                return;
                }
if ((valid==1)&& (float_num < 0.0)) {
                sprintf(float_out,"%.8E",is_frozenb);
                gtk_entry_set_text(GTK_ENTRY(entryb_aij), float_out);
                sprintf(SBUFB,"    Negative values not allowed !");
                g_idle_add((GtkFunction) b_edit_status_update,NULL);
                return;
                }
sprintf(float_out,"%.8E",float_num);
gtk_entry_set_text(GTK_ENTRY(entryb_aij), float_out);
if (q==0) write_matb0_(&is_frozenb_i,&is_frozenb_j,&float_num);
   else if (q==-1) write_matbn1_(&is_frozenb_i,&is_frozenb_j,&float_num);
   else write_matb_(&is_frozenb_i,&is_frozenb_j,&b_displayed_block,&float_num);
/* recompute row sum */
max_min_bb_compute();
gray_levelsb_setup(peb.contrast_value);
image_computeb(b_selected_block);
if((peb.is_range_type==2)&&(peb.is_user==1)) {recompute_levelsb(peb.contrast_value);image_computeb(b_selected_block);}
draw_matareab();
gtk_entry_set_editable(GTK_ENTRY(entryb_aij),FALSE);
is_freezeb_aij=0;
g_idle_add((GtkFunction) b_labels_update,NULL);
gtk_label_set_text (GTK_LABEL(labelb_space),"(view only)   ");
SBUFB[0]=0;
g_idle_add((GtkFunction) b_edit_status_update,NULL);
sprintf(SBUFB,"    Value changed. Remember to Normalize the matrix before using it !");
g_idle_add((GtkFunction) b_edit_status_update,NULL);
return;
}
/*********************************/

