/*
   Copyright (C) 1998,1999,2000,2001
   T. Scott Dattalo and Ralf Forsberg

This file is part of gpsim.

gpsim is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

gpsim is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with gpsim; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#include "../config.h"
#ifdef HAVE_GUI

#include <unistd.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
#include <glib.h>
#include <string.h>

#include <gtkextra/gtkbordercombo.h>
#include <gtkextra/gtkcolorcombo.h>
#include <gtkextra/gtksheet.h>

extern int gui_question(char *question, char *a, char *b);

#include "gui.h"
#include "gui_src.h"

#include <assert.h>

#define PROGRAM_MEMORY_WINDOW_COLUMNS 4   //yuk
#define DEFAULT_ROWS  256
#define OPCODES_PER_ROW 16

#define PROFILE_COLUMN  0
#define ADDRESS_COLUMN  1
#define OPCODE_COLUMN   2
#define MNEMONIC_COLUMN 3

typedef enum {
    MENU_BREAK_CLEAR,
    MENU_BREAK_READ,
    MENU_BREAK_WRITE,
    MENU_BREAK_EXECUTE,
    MENU_ADD_WATCH,
    MENU_ASCII_1BYTE,
    MENU_ASCII_2BYTELSB,
    MENU_ASCII_2BYTEMSB,
    MENU_SETTINGS,
} menu_id;




typedef struct _menu_item {
    char *name;
    menu_id id;
} menu_item;

static menu_item sheet_menu_items[] = {
    {"Clear breakpoints", MENU_BREAK_CLEAR},
    {"Set break on read", MENU_BREAK_READ},
    {"Set break on write", MENU_BREAK_WRITE},
    {"Set break on execute", MENU_BREAK_EXECUTE},
    {"Add watch", MENU_ADD_WATCH},
    {"Settings...",MENU_SETTINGS}
};

static menu_item sheet_submenu_items[] = {
    {"One byte per cell",             MENU_ASCII_1BYTE},
    {"Two bytes per cell, MSB first", MENU_ASCII_2BYTEMSB},
    {"Two bytes per cell, LSB first", MENU_ASCII_2BYTELSB},
};

static menu_item clist_menu_items[] = {
    {"Settings...",MENU_SETTINGS}
};

// Used only in popup menus
SourceBrowserOpcode_Window *popup_sbow;

static char profile_buffer[128];
static char address_buffer[128];
static char opcode_buffer[128];
static char mnemonic_buffer[128];
static char *row_text[PROGRAM_MEMORY_WINDOW_COLUMNS]={
    profile_buffer,address_buffer,opcode_buffer,mnemonic_buffer
};

static int dlg_x=200, dlg_y=200;

static int settings_dialog(SourceBrowserOpcode_Window *sbow);
extern int font_dialog_browse(GtkWidget *w, gpointer user_data);


//========================================================================

class SourceOpcodeXREF : public CrossReferenceToGUI
{
public:

  void Update(int new_value)
  {

    SourceBrowserOpcode_Window *sbow;

    sbow = (SourceBrowserOpcode_Window*)(parent_window);
    
    sbow->SetPC(new_value);

  }

  void Remove()
  {
  }

};

//========================================================================

// update ascii column in sheet
static void update_ascii( SourceBrowserOpcode_Window *sbow, gint row)
{
    gint i;
    gchar name[45];
    unsigned char byte;

    if(sbow == 0 || row<0 || row > GTK_SHEET(sbow->sheet)->maxrow)
    {
	printf("Warning update_ascii(%p,%x)\n",sbow,row);
	return;
    }

    if(row<0 || row>GTK_SHEET(sbow->sheet)->maxrow)
	return;

    switch(sbow->ascii_mode)
    {
    case 0:
	for(i=0; i<16; i++)
	{
	    byte = sbow->memory[row*16 + i]&0xff;

	    name[i] = byte;
	    
	    if( (name[i] < ' ') || (name[i]>'z'))
		name[i] = '.';
	}
	name[i] = 0;
	break;
    case 1: // two bytes, MSB first
	for(i=0; i<32; i++)
	{
	    if(i%2)
		byte = sbow->memory[row*16 + i/2]&0xff;
	    else
		byte = (sbow->memory[row*16 + i/2]&0xff00) >>8;

	    name[i] = byte;
	    
	    if( (name[i] < ' ') || (name[i]>'z'))
		name[i] = '.';
	}
	name[i] = 0;
	break;
    case 2: // two bytes, LSB first
	for(i=0; i<32; i++)
	{

	    if(i%2)
		byte = (sbow->memory[row*16 + i/2]&0xff00) >>8;
	    else
		byte = sbow->memory[row*16 + i/2]&0xff;

	    name[i] = byte;
	    
	    if( (name[i] < ' ') || (name[i]>'z'))
		name[i] = '.';
	}
	name[i] = 0;
	break;
    }
    gtk_sheet_set_cell(GTK_SHEET(sbow->sheet), row,OPCODES_PER_ROW, GTK_JUSTIFY_RIGHT,name);

}

// called when user has selected a menu item
static void
popup_activated(GtkWidget *widget, gpointer data)
{
  GtkSheet *sheet;

  menu_item *item;
  int i,j;
  GtkSheetRange range;
  int pm_size;
  gint char_width;

  if(!widget || !data)
    return;
    
  if(!popup_sbow || !popup_sbow->gp || !popup_sbow->gp->cpu) {
    printf("%s:%d - 0 pointer \n",__FILE__,__LINE__);
    return;
  }
  item = (menu_item *)data;
  sheet=GTK_SHEET(popup_sbow->sheet);
  range = sheet->range;
    
  pm_size = popup_sbow->gp->cpu->program_memory_size();
#if GTK_MAJOR_VERSION >= 2
  char_width = gdk_string_width(gtk_style_get_font(popup_sbow->normal_style), "9");
#else
  char_width = gdk_string_width (popup_sbow->normal_style->font,"9");
#endif

  switch(item->id)
    {
    case MENU_BREAK_WRITE:
    case MENU_BREAK_READ:
      printf("This function is not implemented\n");

      for(j=range.row0;j<=range.rowi;j++)
	for(i=range.col0;i<=range.coli;i++) {
	  unsigned address = popup_sbow->gp->cpu->map_pm_index2address(j*16+i);
	  popup_sbow->gp->cpu->pma->toggle_break_at_address(address);
	}
      break;

    case MENU_BREAK_EXECUTE:

      for(j=range.row0;j<=range.rowi;j++)
	for(i=range.col0;i<=range.coli;i++) {
	  unsigned address = popup_sbow->gp->cpu->map_pm_index2address(j*16+i);
	  popup_sbow->gp->cpu->pma->set_break_at_address(address);
	}
      break;
    case MENU_BREAK_CLEAR:
      for(j=range.row0;j<=range.rowi;j++)
	for(i=range.col0;i<=range.coli;i++) {
	  unsigned address = popup_sbow->gp->cpu->map_pm_index2address(j*16+i);
	  popup_sbow->gp->cpu->pma->set_break_at_address(address);
	}
      break;
    case MENU_ADD_WATCH:
      puts("not implemented");
      /*
      for(j=range.row0;j<=range.rowi;j++)
	for(i=range.col0;i<=range.coli;i++) {
	  unsigned address = popup_sbow->gp->cpu->map_pm_index2address(j*16+i);
	  WatchWindow_add(popup_sbow->gui_obj.gp->watch_window,pic_id, popup_sbow->type, address);
	}
      */
      break;
    case MENU_ASCII_1BYTE:
      popup_sbow->ascii_mode=0;
      config_set_variable(popup_sbow->name(),"ascii_mode",popup_sbow->ascii_mode);
      gtk_sheet_set_column_width (GTK_SHEET(popup_sbow->sheet), 16, 16*char_width + 6);
      for(i=0;i<pm_size/16;i++)
	update_ascii(popup_sbow,i);
      break;
    case MENU_ASCII_2BYTEMSB:
      popup_sbow->ascii_mode=1;
      config_set_variable(popup_sbow->name(),"ascii_mode",popup_sbow->ascii_mode);
      gtk_sheet_set_column_width (GTK_SHEET(popup_sbow->sheet), 16, 32*char_width + 6);
      for(i=0;i<pm_size/16;i++)
	update_ascii(popup_sbow,i);
      break;
    case MENU_ASCII_2BYTELSB:
      popup_sbow->ascii_mode=2;
      config_set_variable(popup_sbow->name(),"ascii_mode",popup_sbow->ascii_mode);
      gtk_sheet_set_column_width (GTK_SHEET(popup_sbow->sheet), 16, 32*char_width + 6);
      for(i=0;i<pm_size/16;i++)
	update_ascii(popup_sbow,i);
      break;
    case MENU_SETTINGS:
      settings_dialog(popup_sbow);
      break;
    default:
      puts("Unhandled menuitem?");
      break;
    }
}


static GtkWidget *
build_menu_for_sheet(SourceBrowserOpcode_Window *sbow)
{
    GtkWidget *menu;
    GtkWidget *item;

    GSList *group=0;
    
    GtkWidget *submenu;

  unsigned int i;

  if(sbow==0)
  {
      printf("Warning build_menu_for_sheet(%p)\n",sbow);
      return 0;
  }

  popup_sbow=sbow;
  
  menu=gtk_menu_new();

  item = gtk_tearoff_menu_item_new ();
  gtk_menu_append (GTK_MENU (menu), item);
  gtk_widget_show (item);
  
  
  for (i=0; i < (sizeof(sheet_menu_items)/sizeof(sheet_menu_items[0])) ; i++){
      item=gtk_menu_item_new_with_label(sheet_menu_items[i].name);

      gtk_signal_connect(GTK_OBJECT(item),"activate",
			 (GtkSignalFunc) popup_activated,
			 &sheet_menu_items[i]);
      GTK_WIDGET_SET_FLAGS (item, GTK_SENSITIVE | GTK_CAN_FOCUS);

      if(sheet_menu_items[i].id==MENU_ADD_WATCH)
      {
	  GTK_WIDGET_UNSET_FLAGS (item,
				  GTK_SENSITIVE | GTK_CAN_FOCUS);
      }
      gtk_widget_show(item);
      gtk_menu_append(GTK_MENU(menu),item);
  }
  
    submenu=gtk_menu_new();
    for (i=0; i < (sizeof(sheet_submenu_items)/sizeof(sheet_submenu_items[0])) ; i++){
	item=gtk_radio_menu_item_new_with_label(group, sheet_submenu_items[i].name);

	group=gtk_radio_menu_item_group(GTK_RADIO_MENU_ITEM(item));
	gtk_signal_connect(GTK_OBJECT(item),"activate",
			   (GtkSignalFunc) popup_activated,
			   &sheet_submenu_items[i]);
	
	GTK_WIDGET_SET_FLAGS (item, GTK_SENSITIVE | GTK_CAN_FOCUS);

	gtk_widget_show(item);
	
	if(i==sbow->ascii_mode)
	    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item),1);
	
	gtk_menu_append(GTK_MENU(submenu),item);
    }
    item = gtk_menu_item_new_with_label ("ASCII mode");
    gtk_menu_append (GTK_MENU (menu), item);
    gtk_widget_show (item);
    gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);

  
  return menu;
}

static GtkWidget *
build_menu_for_clist(SourceBrowserOpcode_Window *sbow)
{
    GtkWidget *menu;
    GtkWidget *item;

  unsigned int i;

  if(sbow==0)
  {
      printf("Warning build_menu_for_sheet(%p)\n",sbow);
      return 0;
  }

  popup_sbow=sbow;
  
  menu=gtk_menu_new();

  item = gtk_tearoff_menu_item_new ();
  gtk_menu_append (GTK_MENU (menu), item);
  gtk_widget_show (item);
  
  
  for (i=0; i < (sizeof(clist_menu_items)/sizeof(clist_menu_items[0])) ; i++){
      item=gtk_menu_item_new_with_label(clist_menu_items[i].name);

      gtk_signal_connect(GTK_OBJECT(item),"activate",
			 (GtkSignalFunc) popup_activated,
			 &clist_menu_items[i]);
      GTK_WIDGET_SET_FLAGS (item, GTK_SENSITIVE | GTK_CAN_FOCUS);

      if(clist_menu_items[i].id==MENU_ADD_WATCH)
      {
	  GTK_WIDGET_UNSET_FLAGS (item,
				  GTK_SENSITIVE | GTK_CAN_FOCUS);
      }
      gtk_widget_show(item);
      gtk_menu_append(GTK_MENU(menu),item);
  }
  
  return menu;
}

// button press handler
static gint
button_press(GtkWidget *widget, GdkEventButton *event, SourceBrowserOpcode_Window *sbow)
{
    GtkWidget *popup;
    int break_row;

    if(!sbow || !sbow->gp || !sbow->gp->cpu)
      return 0;

    if(widget==0 || event==0)
    {
	printf("Warning button_press(%p,%p,%p)\n",widget,event,sbow);
	return 0;
    }
  
    if( (event->type == GDK_BUTTON_PRESS) &&  (event->button == 3) )
    {
	popup_sbow = sbow;

	if(GTK_IS_CLIST(GTK_OBJECT(widget)))
	{
	    popup=sbow->clist_popup_menu;
    	    gtk_menu_popup(GTK_MENU(popup), 0, 0, 0, 0,
			   3, event->time);
	}
	else
	{
	    popup=sbow->sheet_popup_menu;
    	    gtk_menu_popup(GTK_MENU(popup), 0, 0, 0, 0,
			   3, event->time);
	}
    }

    if ((event->type == GDK_2BUTTON_PRESS) &&
	(event->button == 1))

    {
	if(GTK_IS_CLIST(GTK_OBJECT(widget)))
	{
	    break_row =  GTK_CLIST (sbow->clist)->focus_row;

	    unsigned address = sbow->gp->cpu->map_pm_index2address(break_row);
	    sbow->gp->cpu->pma->toggle_break_at_address(address);
	    return TRUE;
	}
    }
    return FALSE;
}


static void filter(char *clean, char *dirty, int max)
{

  int i=0,j;

  if(dirty!=0) {

    do {


      if(*dirty == '\t')
	for(j=0,dirty++; j<8 && i%8; j++,i++)
	  *clean++ = ' ';
      else if (*dirty <' ')
	dirty++;
      else
	*clean++ = *dirty++;



    } while(*dirty && ++i < max);
  }

  *clean = 0;

}

static void update_styles(SourceBrowserOpcode_Window *sbow, int address)
{
  GtkSheetRange range;

  int index = address;

  if(sbow->gp->cpu)
    index = sbow->gp->cpu->map_pm_address2index(address);

  int row=index/16;
  int column=index%16;


  range.row0=row;
  range.rowi=row;
  range.col0=column;
  range.coli=column;
    
  if(!sbow->gp->cpu) {
    gtk_sheet_range_set_background(GTK_SHEET(sbow->sheet), &range, &sbow->normal_pm_bg_color);
    return;
  }

  if(sbow->gp->cpu && sbow->gp->cpu->pma->address_has_break(address)) {

    gtk_clist_set_row_style (GTK_CLIST (sbow->clist), index, sbow->breakpoint_line_number_style);
    gtk_sheet_range_set_background(GTK_SHEET(sbow->sheet), &range, &sbow->breakpoint_color);

  } else {

    gtk_clist_set_row_style (GTK_CLIST (sbow->clist), index, sbow->normal_style);

    if(sbow->gp->cpu->pma->isModified(address))
      gtk_sheet_range_set_background(GTK_SHEET(sbow->sheet), &range, &sbow->pm_has_changed_color);
    else
      gtk_sheet_range_set_background(GTK_SHEET(sbow->sheet), &range, &sbow->normal_pm_bg_color);
  }

}


static void update_label(SourceBrowserOpcode_Window *sbow, int address)
{
  char labeltext[128];
  char entrytext[128];
  GtkEntry *sheet_entry;
  unsigned int oc;

  if(!sbow || !sbow->gp || !sbow->gp->cpu)
    return;

  if(address<0) {
    entrytext[0]=0;
    strcpy(labeltext,"ASCII");
  } else {

    oc = sbow->gp->cpu->pma->get_opcode(address);
	
    filter(labeltext,
	   sbow->gp->cpu->pma->get_opcode_name(address,entrytext,sizeof(entrytext)),
	   sizeof(labeltext));

    sprintf(entrytext, "0x%04X", oc);
  }
    
  sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(GTK_SHEET(sbow->sheet)));
  gtk_label_set(GTK_LABEL(sbow->label), labeltext);
  gtk_entry_set_max_length(GTK_ENTRY(sbow->entry),
			   GTK_ENTRY(sheet_entry)->text_max_length);
  gtk_entry_set_text(GTK_ENTRY(sbow->entry), entrytext);

}

static void update_values(SourceBrowserOpcode_Window *sbow, int address)
{
  if(!sbow || !sbow->gp || !sbow->gp->cpu)
    return;

  unsigned uMemoryIndex = sbow->gp->cpu->map_pm_address2index(address);
  int row=uMemoryIndex/16;
  int column=uMemoryIndex%16;
  char buf[128];
  unsigned int oc;

  oc = sbow->gp->cpu->pma->get_opcode(address);
  if(oc != sbow->memory[uMemoryIndex]) {
    
    sbow->memory[address]=oc;
    // Put new values, in case they changed
    sprintf (row_text[ADDRESS_COLUMN], "0x%04X", address);
    sprintf(row_text[OPCODE_COLUMN], "0x%04X", oc);
    filter(row_text[MNEMONIC_COLUMN], 
	   sbow->gp->cpu->pma->get_opcode_name(address,buf,sizeof(buf)),
	   sizeof(buf));

    gtk_clist_set_text (GTK_CLIST (sbow->clist), address, OPCODE_COLUMN, row_text[OPCODE_COLUMN]);
    gtk_clist_set_text (GTK_CLIST (sbow->clist), address, MNEMONIC_COLUMN, row_text[MNEMONIC_COLUMN]);

    gtk_sheet_set_cell(GTK_SHEET(sbow->sheet),
		       row,column,
		       GTK_JUSTIFY_RIGHT,row_text[OPCODE_COLUMN]+2);
  }
}

static void update(SourceBrowserOpcode_Window *sbow, int address)
{

  if(!sbow->gp->cpu)
    return;

  update_values(sbow,address);
  update_styles(sbow,address);
}

static gint configure_event(GtkWidget *widget, GdkEventConfigure *e, gpointer data)
{
    if(widget->window==0)
	return 0;
    
    gdk_window_get_root_origin(widget->window,&dlg_x,&dlg_y);
    return 0; // what should be returned?, FIXME
}

static int load_styles(SourceBrowserOpcode_Window *sbow)
{
    GdkColor text_fg;
    GdkColor text_bg;
    GdkColormap *colormap = gdk_colormap_get_system();

    gdk_color_parse("black", &text_fg);
    gdk_color_parse("light cyan", &text_bg);
    gdk_colormap_alloc_color(colormap, &text_fg,FALSE,TRUE );
    gdk_colormap_alloc_color(colormap, &text_bg,FALSE,TRUE );

    sbow->normal_style = gtk_style_new ();
    sbow->normal_style->fg[GTK_STATE_NORMAL] = text_fg;
    sbow->normal_style->base[GTK_STATE_NORMAL] = text_bg;
#if GTK_MAJOR_VERSION >= 2
    gtk_style_set_font(sbow->normal_style,
      gdk_fontset_load(sbow->normalfont_string));
#else
    gdk_font_unref (sbow->normal_style->font);
    sbow->normal_style->font =
	gdk_fontset_load (sbow->normalfont_string);
#endif

    text_bg.red   = 30000;
    text_bg.green = 30000;
    text_bg.blue  = 30000;
    gdk_colormap_alloc_color(colormap, &text_bg,FALSE,TRUE );
    sbow->current_line_number_style = gtk_style_new ();
    sbow->current_line_number_style->fg[GTK_STATE_NORMAL] = text_fg;
    sbow->current_line_number_style->base[GTK_STATE_NORMAL] = text_bg;
#if GTK_MAJOR_VERSION >= 2
    gtk_style_set_font(sbow->current_line_number_style,
      gdk_fontset_load(sbow->pcfont_string));
#else
    gdk_font_unref (sbow->current_line_number_style->font);
    sbow->current_line_number_style->font =
	gdk_fontset_load (sbow->pcfont_string);
#endif

    gdk_color_parse("red", &text_bg);
    sbow->breakpoint_color=text_bg;
    gdk_colormap_alloc_color(colormap, &sbow->breakpoint_color,FALSE,TRUE );
    sbow->breakpoint_line_number_style = gtk_style_new ();
    sbow->breakpoint_line_number_style->fg[GTK_STATE_NORMAL] = text_fg;
    sbow->breakpoint_line_number_style->base[GTK_STATE_NORMAL] = text_bg;
#if GTK_MAJOR_VERSION >= 2
    gtk_style_set_font(sbow->breakpoint_line_number_style,
      gdk_fontset_load(sbow->breakpointfont_string));
#else
    gdk_font_unref (sbow->breakpoint_line_number_style->font);
    sbow->breakpoint_line_number_style->font =
	gdk_fontset_load (sbow->breakpointfont_string);
#endif

    gdk_color_parse("white",&sbow->normal_pm_bg_color);
    gdk_colormap_alloc_color(colormap, &sbow->normal_pm_bg_color,FALSE,TRUE);
    gdk_color_parse("light gray",&sbow->pm_has_changed_color);
    gdk_colormap_alloc_color(colormap, &sbow->pm_has_changed_color,FALSE,TRUE);

#if GTK_MAJOR_VERSION >= 2
    if (gtk_style_get_font(sbow->breakpoint_line_number_style) == 0 ||
      gtk_style_get_font(sbow->current_line_number_style) == 0 ||
      gtk_style_get_font(sbow->normal_style) == 0)
      return 0;
#else
    if(sbow->breakpoint_line_number_style->font==0)
	return 0;
    if(sbow->current_line_number_style->font==0)
	return 0;
    if(sbow->normal_style->font==0)
	return 0;
#endif

    return 1;
}

/********************** Settings dialog ***************************/
static int settings_active;
static void settingsok_cb(GtkWidget *w, gpointer user_data)
{
    if(settings_active)
    {
        settings_active=0;
    }
}
static int settings_dialog(SourceBrowserOpcode_Window *sbow)
{
    static GtkWidget *dialog=0;
    GtkWidget *button;
    static int retval;
    GtkWidget *hbox;
    static GtkWidget *normalfontstringentry;
    static GtkWidget *breakpointfontstringentry;
    static GtkWidget *pcfontstringentry;
    GtkWidget *label;
    int fonts_ok=0;
    
    if(dialog==0)
    {
	dialog = gtk_dialog_new();
	gtk_window_set_title (GTK_WINDOW (dialog), "Opcode browser settings");
	gtk_signal_connect(GTK_OBJECT(dialog),
			   "configure_event",GTK_SIGNAL_FUNC(configure_event),0);
	gtk_signal_connect_object(GTK_OBJECT(dialog),
				  "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide),GTK_OBJECT(dialog));


	// Normal font
	hbox = gtk_hbox_new(0,0);
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox,FALSE,FALSE,20);
	gtk_widget_show(hbox);
	label=gtk_label_new("Normal font:");
	gtk_box_pack_start(GTK_BOX(hbox), label,
			   FALSE,FALSE, 20);
	gtk_widget_show(label);
	normalfontstringentry=gtk_entry_new();
	gtk_box_pack_start(GTK_BOX(hbox), normalfontstringentry,
			   TRUE, TRUE, 0);
	gtk_widget_show(normalfontstringentry);
	button = gtk_button_new_with_label("Browse...");
	gtk_widget_show(button);
	gtk_box_pack_start(GTK_BOX(hbox), button,
			   FALSE,FALSE,10);
	gtk_signal_connect(GTK_OBJECT(button),"clicked",
			   GTK_SIGNAL_FUNC(font_dialog_browse),(gpointer)normalfontstringentry);


	// Breakpoint font
	hbox = gtk_hbox_new(0,0);
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox,FALSE,FALSE,20);
	gtk_widget_show(hbox);
	label=gtk_label_new("Breakpoint font:");
	gtk_box_pack_start(GTK_BOX(hbox), label,
			   FALSE,FALSE, 20);
	gtk_widget_show(label);
	breakpointfontstringentry=gtk_entry_new();
	gtk_box_pack_start(GTK_BOX(hbox), breakpointfontstringentry,
			   TRUE, TRUE, 0);
	gtk_widget_show(breakpointfontstringentry);
	button = gtk_button_new_with_label("Browse...");
	gtk_widget_show(button);
	gtk_box_pack_start(GTK_BOX(hbox), button,
			   FALSE,FALSE,10);
	gtk_signal_connect(GTK_OBJECT(button),"clicked",
			   GTK_SIGNAL_FUNC(font_dialog_browse),(gpointer)breakpointfontstringentry);


	// PC font
	hbox = gtk_hbox_new(0,0);
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox,FALSE,FALSE,20);
	gtk_widget_show(hbox);
	label=gtk_label_new("PC font:");
	gtk_box_pack_start(GTK_BOX(hbox), label,
			   FALSE,FALSE, 20);
	gtk_widget_show(label);
	pcfontstringentry=gtk_entry_new();
	gtk_box_pack_start(GTK_BOX(hbox), pcfontstringentry,
			   TRUE, TRUE, 0);
	gtk_widget_show(pcfontstringentry);
	button = gtk_button_new_with_label("Browse...");
	gtk_widget_show(button);
	gtk_box_pack_start(GTK_BOX(hbox), button,
			   FALSE,FALSE,10);
	gtk_signal_connect(GTK_OBJECT(button),"clicked",
			   GTK_SIGNAL_FUNC(font_dialog_browse),(gpointer)pcfontstringentry);


	// OK button
	button = gtk_button_new_with_label("OK");
	gtk_widget_show(button);
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button,
			   FALSE,FALSE,10);
	gtk_signal_connect(GTK_OBJECT(button),"clicked",
			   GTK_SIGNAL_FUNC(settingsok_cb),(gpointer)dialog);
    }
    
    gtk_entry_set_text(GTK_ENTRY(normalfontstringentry), sbow->normalfont_string);
    gtk_entry_set_text(GTK_ENTRY(breakpointfontstringentry), sbow->breakpointfont_string);
    gtk_entry_set_text(GTK_ENTRY(pcfontstringentry), sbow->pcfont_string);

    gtk_widget_set_uposition(GTK_WIDGET(dialog),dlg_x,dlg_y);
    gtk_widget_show_now(dialog);



    while(fonts_ok!=3)
    {
	char fontname[256];
#if GTK_MAJOR_VERSION >= 2
        PangoFontDescription *font;
#else
	GdkFont *font;
#endif

        settings_active=1;
	while(settings_active)
	    gtk_main_iteration();

	fonts_ok=0;

	strcpy(fontname,gtk_entry_get_text(GTK_ENTRY(normalfontstringentry)));
#if GTK_MAJOR_VERSION >= 2
	if((font=pango_font_description_from_string(fontname))==0)
#else
	if((font=gdk_fontset_load(fontname))==0)
#endif
	{
	    if(gui_question("Normalfont did not load!","Try again","Ignore/Cancel")==FALSE)
		break;
	}
	else
	{
#if GTK_MAJOR_VERSION >= 2
#else
            gdk_font_unref(font);
#endif
	    strcpy(sbow->normalfont_string,gtk_entry_get_text(GTK_ENTRY(normalfontstringentry)));
	    config_set_string(sbow->name(),"normalfont",sbow->normalfont_string);
            fonts_ok++;
	}

	strcpy(fontname,gtk_entry_get_text(GTK_ENTRY(breakpointfontstringentry)));
#if GTK_MAJOR_VERSION >= 2
	if((font=pango_font_description_from_string(fontname))==0)
#else
        if((font=gdk_fontset_load(fontname))==0)
#endif
	{
	    if(gui_question("Breakpointfont did not load!","Try again","Ignore/Cancel")==FALSE)
		break;
	}
        else
	{
#if GTK_MAJOR_VERSION >= 2
#else
            gdk_font_unref(font);
#endif
	    strcpy(sbow->breakpointfont_string,gtk_entry_get_text(GTK_ENTRY(breakpointfontstringentry)));
	    config_set_string(sbow->name(),"breakpointfont",sbow->breakpointfont_string);
            fonts_ok++;
	}

	strcpy(fontname,gtk_entry_get_text(GTK_ENTRY(pcfontstringentry)));
#if GTK_MAJOR_VERSION >= 2
	if((font=pango_font_description_from_string(fontname))==0)
#else
        if((font=gdk_fontset_load(fontname))==0)
#endif
	{
	    if(gui_question("PCfont did not load!","Try again","Ignore/Cancel")==FALSE)
		break;
	}
        else
	{
#if GTK_MAJOR_VERSION >= 2
#else
            gdk_font_unref(font);
#endif
	    strcpy(sbow->pcfont_string,gtk_entry_get_text(GTK_ENTRY(pcfontstringentry)));
	    config_set_string(sbow->name(),"pcfont",sbow->pcfont_string);
            fonts_ok++;
	}
    }


    sbow->Build();

    gtk_widget_hide(dialog);

    return retval;
}


static unsigned long get_number_in_string(const char *number_string)
{
  unsigned long retval = 0;
  char *bad_position;
  int current_base = 16;
  
  if(number_string==0)
  {
      printf("Warning get_number_in_string(%p)\n",number_string);
      errno = EINVAL;
      return (unsigned long)-1;
  }


  errno = 0;

  retval = strtoul(number_string, &bad_position, current_base);

  if( strlen(bad_position) ) 
    errno = EINVAL;  /* string contains an invalid number */

  /*
  if(retval > 255)
    errno = ERANGE;
  */

  return(retval);
}


// when a new cell is selected, we write changes in
// previously selected cell to gpsim
static void
parse_numbers(GtkWidget *widget, int row, int col, SourceBrowserOpcode_Window *sbow)
{

  if(!sbow || !sbow->gp || !sbow->gp->cpu || !widget)
    return;

  GtkSheet *sheet;
  const gchar *text;
  int justification;

  sheet=GTK_SHEET(widget);
  
  if(row>sheet->maxrow || row<0 ||
     col>sheet->maxcol || col<0)
  {
      printf("Warning parse_numbers(%p,%x,%x,%p)\n",widget,row,col,sbow);
      return;
  }

  if(sbow->memory==0)
      return;

  
  justification=GTK_JUSTIFY_RIGHT;

  if(col < OPCODES_PER_ROW)
    {

      int reg = row*16+col;
      unsigned int n=0;

      text = gtk_entry_get_text(GTK_ENTRY(sheet->sheet_entry));

      errno = 0;
      if(strlen(text)>0)
	n = get_number_in_string(text);
      else
	errno = ERANGE;

      if(errno != 0)
      {
	  n = sbow->gp->cpu->pma->get_opcode(reg);
	  sbow->memory[reg] = INVALID_VALUE;
      }

      if(n != sbow->memory[reg])
      {
	  printf("Writing new value, new %d, last %d\n",n,sbow->memory[reg]);
	  sbow->memory[reg]=n;
	  sbow->gp->cpu->pma->put_opcode(reg, n);
	  update_ascii(sbow,row);
      }
    }
  else
      ; // ignore user changes in ascii column for right now
}

/* when the entry above the sheet is changed (typed a digit), we
   copy it to the cell entry */
static void
show_sheet_entry(GtkWidget *widget, SourceBrowserOpcode_Window *sbow)
{
 const char *text;
 GtkSheet *sheet;
 GtkEntry *sheet_entry;

 int row,col;
 
 if(widget==0|| sbow==0)
  {
      printf("Warning show_sheet_entry(%p,%p)\n",widget,sbow);
      return;
  }

 if(!GTK_WIDGET_HAS_FOCUS(widget)) return;
 
 sheet=GTK_SHEET(sbow->sheet);
 sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));

 row=sheet->active_cell.row; col=sheet->active_cell.col;

 if((text=gtk_entry_get_text (GTK_ENTRY(sbow->entry))))
     gtk_entry_set_text(sheet_entry, text);

}

/* when we have new data in the entry above the sheet, we
 copy the data to the cells/registers

 this doesn't get called when it is clicked
 in, only when we hit return
 */
static void
activate_sheet_entry(GtkWidget *widget, SourceBrowserOpcode_Window *sbow)
{
  GtkSheet *sheet;
  gint row, col;

  if(widget==0|| sbow==0)
  {
      printf("Warning activate_sheet_entry(%p,%p)\n",widget,sbow);
      return;
  }

  sheet=GTK_SHEET(sbow->sheet);
  row=sheet->active_cell.row;
  col=sheet->active_cell.col;

  parse_numbers(GTK_WIDGET(sheet),sheet->active_cell.row,sheet->active_cell.col,sbow);
  
  update_label(sbow,row*16+col);
}

/*
 we get here when the entry in a cell is changed (typed a digit), we
 copy it to the entry above the sheet.
 */
static void
show_entry(GtkWidget *widget, SourceBrowserOpcode_Window *sbow)
{
 const char *text; 
 GtkSheet *sheet;
 GtkWidget * sheet_entry;
  gint row, col;

  if(widget==0|| sbow==0)
  {
      printf("Warning show_entry(%p,%p)\n",widget,sbow);
      return;
  }
  
 if(!GTK_WIDGET_HAS_FOCUS(widget)) return;

 sheet=GTK_SHEET(sbow->sheet);
 sheet_entry = gtk_sheet_get_entry(sheet);

 row=sheet->active_cell.row; col=sheet->active_cell.col;
 
 if((text=gtk_entry_get_text (GTK_ENTRY(sheet_entry))))
     gtk_entry_set_text(GTK_ENTRY(sbow->entry), text);
}

/* when a cell is activated, we set the label and entry above the sheet
 */
static gint
activate_sheet_cell(GtkWidget *widget, gint row, gint column, SourceBrowserOpcode_Window *sbow)
{
    GtkSheet *sheet;
    GtkSheetCellAttr attributes;
  
    sheet=GTK_SHEET(sbow->sheet);

    if(widget==0 || row>sheet->maxrow || row<0||
       column>sheet->maxcol || column<0 || sbow==0)
    {
	printf("Warning activate_sheet_cell(%p,%x,%x,%p)\n",widget,row,column,sbow);
	return 0;
    }

    if(column<16)
	update_label(sbow,row*16+column);
    else
	update_label(sbow,-1);
    
    gtk_sheet_get_attributes(sheet,sheet->active_cell.row,
			     sheet->active_cell.col, &attributes);
    gtk_entry_set_editable(GTK_ENTRY(sbow->entry), attributes.is_editable);
    gtk_sheet_range_set_justification(sheet, &sheet->range, GTK_JUSTIFY_RIGHT);


    return TRUE;
}


void SourceBrowserOpcode_Window::SelectAddress(int address)
{
  if(!enabled)
    return;
  unsigned int row = address;
  if(gp->cpu)
    row = gp->cpu->map_pm_address2index(address);

  gtk_clist_unselect_all(GTK_CLIST(clist));
  gtk_clist_select_row(GTK_CLIST(clist),row,0);
  if(GTK_VISIBILITY_FULL != gtk_clist_row_is_visible (GTK_CLIST (clist),row))
    gtk_clist_moveto (GTK_CLIST (clist), row, 0, .5, 0.0);

}

void SourceBrowserOpcode_Window::UpdateLine(int address)
{

    
  if(!enabled)
    return;

  if(address >= 0)
    update(this,address);
}

void SourceBrowserOpcode_Window::SetPC(int address)
{
  gint last_address;

  if(!enabled)
    return;

  last_address = current_address;
  current_address = address;

  if(address != last_address)
    {
      UpdateLine(last_address);
      gtk_clist_set_row_style (GTK_CLIST (clist),
			       gp->cpu->map_pm_address2index(last_address),
			       normal_style);

      UpdateLine(address);
      gtk_clist_set_row_style (GTK_CLIST (clist), 
			       gp->cpu->map_pm_address2index(address),
			       current_line_number_style);
    }

  unsigned int current_row = gp->cpu->map_pm_address2index(current_address);
  if(GTK_VISIBILITY_FULL != gtk_clist_row_is_visible (GTK_CLIST (clist),
						      current_row))
    {
      gtk_clist_moveto (GTK_CLIST (clist), 
			current_row, 
			0, .5, 0.0);
    }
}

//========================================================================
// Fill()
//
// copy the processor's program memory contents to the both the disassembly
// and opcode windows.

void SourceBrowserOpcode_Window::Fill()
{
  if(!bIsBuilt)
    Build();

  if(!gp || !gp->cpu)
    return;

  char buf[128];
  unsigned int opcode;
  gint i;
  int pm_size;
  int pc;

  // Clearing and appending is faster than changing
  gtk_clist_clear(GTK_CLIST(clist));

  pm_size = gp->cpu->program_memory_size();

  if(memory!=0)
    free(memory);
  memory=(unsigned int*)malloc(pm_size*sizeof(*memory));


  for(i=0; i < pm_size; i++) {
    int address = gp->cpu->map_pm_index2address(i);
    opcode = gp->cpu->pma->get_opcode(address);
    memory[i]=opcode;
    sprintf (row_text[ADDRESS_COLUMN], "0x%04X", address);
    sprintf(row_text[OPCODE_COLUMN], "0x%04X", opcode);
    filter(row_text[MNEMONIC_COLUMN],
	   gp->cpu->pma->get_opcode_name(address,buf,sizeof(buf)),
	   128);

    if(GTK_SHEET(sheet)->maxrow<i/16)
      gtk_sheet_add_row(GTK_SHEET(sheet),1);

    gtk_sheet_set_cell(GTK_SHEET(sheet),
		       i/16,
		       i%16,
		       GTK_JUSTIFY_RIGHT,row_text[OPCODE_COLUMN]+2);

    gtk_clist_append (GTK_CLIST (clist), row_text);
    update_styles(this,i);
  }

  for(i=0;i<pm_size/16;i++)
    update_ascii(this,i);
    
  gtk_clist_set_row_style (GTK_CLIST (clist), 0, current_line_number_style);

  pc=gp->cpu->pma->get_PC();
  SetPC(pc);
  update_label(this,pc);


}
void SourceBrowserOpcode_Window::NewSource(GUI_Processor *_gp)
{
  if(!gp)
    return;

  current_address=0;

  if(!enabled)
    return;
  if(!bIsBuilt)
    Build();

  assert(wt==WT_opcode_source_window);

  /* Now create a cross-reference link that the
   * simulator can use to send information back to the gui
   */
  if(gp->cpu && gp->cpu->pc) {
    SourceOpcodeXREF *cross_reference;

    cross_reference = new SourceOpcodeXREF();
    cross_reference->parent_window_type =   WT_status_bar;
    cross_reference->parent_window = (gpointer) this;
    cross_reference->data = (gpointer) this;
  
    gp->cpu->pc->add_xref((gpointer) cross_reference);

  }

  Fill();

}

void SourceBrowserOpcode_Window::NewProcessor(GUI_Processor *_gp)
{

  GtkSheetRange range;

  if(!gp || !gp->cpu)
    return;

  current_address=0;
    
  if(!enabled)
    return;

  if(!bIsBuilt)
    Build();

  assert(wt==WT_opcode_source_window);

  pma = gp->cpu->pma;

  Fill();

  range.row0=0;range.col0=0;
  range.rowi=GTK_SHEET(sheet)->maxrow;
  range.coli=GTK_SHEET(sheet)->maxcol;
  gtk_sheet_range_set_background(GTK_SHEET(sheet), &range, &normal_pm_bg_color);
#if GTK_MAJOR_VERSION >= 2
  // --tsd - commented this out when the new gtkextra package was released.
  //gtk_sheet_range_set_font(GTK_SHEET(sheet), &range, normal_style->font_desc);
#else
  gtk_sheet_range_set_font(GTK_SHEET(sheet), &range, normal_style->font);
#endif


  range.row0=range.rowi=0;
  range.col0=range.coli=0;
  gtk_sheet_select_range(GTK_SHEET(sheet),&range);
    
  update_label(this,0);
    
}

void SourceBrowserOpcode_Window::Build(void)
{
  if(bIsBuilt)
    return;

  GtkWidget *hbox;
  GtkWidget *scrolled_win;
  GtkRequisition request;
  
  gchar _name[10];
  gint column_width,char_width;
  gint i;

  static GtkStyle *style=0;
  char *fontstring;

  if(window!=0)
    gtk_widget_destroy(window);
  
  SourceBrowser_Window::Create();


  gtk_window_set_title (GTK_WINDOW (window), "Program memory");

  notebook = gtk_notebook_new();
  gtk_widget_show(notebook);

  gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);

  gtk_window_set_default_size(GTK_WINDOW(window), width,height);
  gtk_widget_set_uposition(GTK_WIDGET(window),x,y);


  /**************************** load fonts *********************************/
#if GTK_MAJOR_VERSION >= 2
#define DEFAULT_NORMALFONT "Courier Roman 14"
#define DEFAULT_BREAKPOINTFONT "Courier Bold 14"
#define DEFAULT_PCFONT "Courier Bold 14"
#else
#define DEFAULT_NORMALFONT "-adobe-courier-*-r-*-*-*-140-*-*-*-*-*-*"
#define DEFAULT_BREAKPOINTFONT "-adobe-courier-bold-r-*-*-*-140-*-*-*-*-*-*"
#define DEFAULT_PCFONT "-adobe-courier-bold-r-*-*-*-140-*-*-*-*-*-*"
#endif

  strcpy(normalfont_string,DEFAULT_NORMALFONT);
  if(config_get_string(name(),"normalfont",&fontstring))
      strcpy(normalfont_string,fontstring);

  strcpy(breakpointfont_string,DEFAULT_BREAKPOINTFONT);
  if(config_get_string(name(),"breakpointfont",&fontstring))
    strcpy(breakpointfont_string,fontstring);

  strcpy(pcfont_string,DEFAULT_PCFONT);
  if(config_get_string(name(),"pcfont",&fontstring))
      strcpy(pcfont_string,fontstring);

  while(!load_styles(this))
  {
      if(gui_question("Some fonts did not load.","Open font dialog","Try defaults")==FALSE)
      {
	  strcpy(normalfont_string,DEFAULT_NORMALFONT);
	  strcpy(breakpointfont_string,DEFAULT_BREAKPOINTFONT);
	  strcpy(pcfont_string,DEFAULT_PCFONT);
	  config_set_string(name(),"normalfont",normalfont_string);
	  config_set_string(name(),"breakpointfont",breakpointfont_string);
	  config_set_string(name(),"pcfont",pcfont_string);
      }
      else
      {
	  settings_dialog(this);
      }
  }


  /////////////////////////////////////////////////////////////////
  // create clist
  /////////////////////////////////////////////////////////////////
  scrolled_win = gtk_scrolled_window_new (0, 0);
  gtk_widget_show(scrolled_win);
  gtk_container_set_border_width (GTK_CONTAINER (scrolled_win), 5);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
				  GTK_POLICY_AUTOMATIC, 
				  GTK_POLICY_AUTOMATIC);

  /* create GtkCList here so we have a pointer to throw at the 
   * button callbacks -- more is done with it later */
  clist = gtk_clist_new_with_titles (columns, column_titles);
  gtk_widget_show(clist);

  gtk_container_add (GTK_CONTAINER (scrolled_win), clist);

  /* Add a signal handler for button press events. This will capture
   * commands for setting and/or clearing break points
   */
  gtk_signal_connect(GTK_OBJECT(clist),"button_press_event",
		     (GtkSignalFunc) button_press,
		     (gpointer) this);


  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
			   scrolled_win,
			   gtk_label_new("Assembly"));

  gtk_clist_set_row_height (GTK_CLIST (clist), 18);
  gtk_widget_set_usize (clist, 300, 100);
  gtk_clist_set_selection_mode (GTK_CLIST (clist), GTK_SELECTION_EXTENDED);

  for (i = 0; i < columns; i++)
    {
      gtk_clist_set_column_width (GTK_CLIST (clist), i, 80);

      gtk_clist_set_column_auto_resize (GTK_CLIST (clist), i, FALSE);
      gtk_clist_set_column_justification (GTK_CLIST (clist), i,
					  GTK_JUSTIFY_LEFT);
      // %%% FIX ME
      //   Hide the profile column for now...
      if(i == 0)
	gtk_clist_set_column_visibility (GTK_CLIST (clist), i, FALSE);
    }


  for (i = 0; i < DEFAULT_ROWS; i++)
    {
      sprintf (row_text[ADDRESS_COLUMN], "0x%04X", i);
      gtk_clist_append (GTK_CLIST (clist), row_text);
      gtk_clist_set_row_style (GTK_CLIST (clist), i, normal_style);

    }



  /////////////////////////////////////////////////////////////////
  // create sheet
  /////////////////////////////////////////////////////////////////
  vbox=gtk_vbox_new(FALSE,1);
  gtk_widget_show(vbox);

  // Create entry bar
  hbox=gtk_hbox_new(FALSE,1);
  gtk_widget_show(hbox);
  gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
  
  label=gtk_label_new("");
  style=gtk_style_new();
#if GTK_MAJOR_VERSION >= 2
  gtk_style_set_font(style, gtk_style_get_font(normal_style));
#else
  style->font=normal_style->font;
#endif
  gtk_widget_set_style(label,style);
  gtk_widget_size_request(label, &request);
  gtk_widget_set_usize(label, 160, request.height);
  gtk_widget_show(label);
  gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);

  entry=gtk_entry_new();
  style=gtk_style_new();
#if GTK_MAJOR_VERSION >= 2
  gtk_style_set_font(style, gtk_style_get_font(normal_style));
#else
  style->font=normal_style->font;
#endif
  gtk_widget_set_style(entry,style);
  gtk_widget_show(entry);
  gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
  
  // Create sheet
  scrolled_win=gtk_scrolled_window_new(0, 0);
  gtk_widget_show(scrolled_win);
  gtk_box_pack_start(GTK_BOX(vbox), scrolled_win, TRUE, TRUE, 0);
  
  sheet=gtk_sheet_new(1,17,"where does this string go?");
  gtk_widget_show(sheet);
  gtk_container_add(GTK_CONTAINER(scrolled_win), sheet);
  
  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
			   vbox,
			   gtk_label_new("Opcodes"));

#if GTK_MAJOR_VERSION >= 2
  char_width = gdk_string_width(gtk_style_get_font(normal_style), "9");
#else
  char_width = gdk_string_width (normal_style->font,"9");
#endif
  column_width = 5 * char_width + 6;

  for(i=0; i<GTK_SHEET(sheet)->maxcol; i++){

    sprintf(_name,"%02x",i);
    gtk_sheet_column_button_add_label(GTK_SHEET(sheet), i, _name);
    gtk_sheet_set_column_title(GTK_SHEET(sheet), i, _name);
    gtk_sheet_set_column_width (GTK_SHEET(sheet), i, column_width);
  }
  sprintf(_name,"ASCII");
  gtk_sheet_column_button_add_label(GTK_SHEET(sheet), i, _name);
  gtk_sheet_set_column_title(GTK_SHEET(sheet), i, _name);
  gtk_sheet_set_row_titles_width(GTK_SHEET(sheet), column_width);

  
  gtk_signal_connect(GTK_OBJECT(sheet),
		     "button_press_event",
		     (GtkSignalFunc) button_press,
		     this);

  gtk_signal_connect(GTK_OBJECT(gtk_sheet_get_entry(GTK_SHEET(sheet))),
		     "changed", (GtkSignalFunc)show_entry, this);

  gtk_signal_connect(GTK_OBJECT(sheet),
		     "activate", (GtkSignalFunc)activate_sheet_cell,
		     (gpointer) this);

  gtk_signal_connect(GTK_OBJECT(entry),
		     "changed", (GtkSignalFunc)show_sheet_entry, this);

  gtk_signal_connect(GTK_OBJECT(entry),
		     "activate", (GtkSignalFunc)activate_sheet_entry,
		     this);
  gtk_signal_connect(GTK_OBJECT(sheet),
		     "set_cell",
		     (GtkSignalFunc) parse_numbers,
		     this);
  /////////////////////////////////////////////////////////////////



  
  gtk_widget_show(scrolled_win);
  gtk_widget_show(sheet);
  
  gtk_signal_connect_after(GTK_OBJECT(window), "configure_event",
			   GTK_SIGNAL_FUNC(gui_object_configure_event),this);
  
  gtk_widget_show(window);

  bIsBuilt = true;

  //GTKWAIT;

  NewProcessor(gp);
  NewSource(gp);

  /* create popupmenu for sheet */
  sheet_popup_menu=build_menu_for_sheet(this);

  /* create popupmenu for clist */
  clist_popup_menu=build_menu_for_clist(this);

  UpdateMenuItem();
}

SourceBrowserOpcode_Window::SourceBrowserOpcode_Window(GUI_Processor *_gp)
{
  static char *titles[] =
    {
      "profile", "address", "opcode", "instruction"
    };

  menu = "<main>/Windows/Program memory";

  window = 0;
  pma =0;
  status_bar = 0;

  column_titles = titles;
  columns = 4;


  gp = _gp;
  set_name("program_memory");
  wc = WC_source;
  wt = WT_opcode_source_window;

  memory=0;
  current_address=0;

  ascii_mode=1; /// default, two bytes/cell, MSB first
  int tmp=0;
  config_get_variable(name(),"ascii_mode",&tmp);
  ascii_mode = tmp;

  get_config();

  if(enabled)
    Build();

}

#endif // HAVE_GUI


syntax highlighted by Code2HTML, v. 0.9.1