/*
   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 "../config.h"
#ifdef HAVE_GUI

#ifdef DOING_GNOME
#include <gnome.h>
#endif

#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>


#include "gui.h"
#include "preferences.h"
#include "gui_callbacks.h"
#include "gui_breadboard.h"
#include "gui_processor.h"
#include "gui_profile.h"
#include "gui_register.h"
#include "gui_regwin.h"
#include "gui_scope.h"
#include "gui_src.h"
#include "gui_stack.h"
#include "gui_stopwatch.h"
#include "gui_symbols.h"
#include "gui_trace.h"
#include "gui_watch.h"

#include "../cli/input.h"  // for gpsim_open()
#include "../src/gpsim_interface.h"

typedef struct _note_book_item
{
  gchar        *name;
  GtkSignalFunc func;
} NotebookItem;

GtkItemFactory *item_factory=0;

extern GUI_Processor *gpGuiProcessor;

static void 
do_quit_app(GtkWidget *widget) 
{
	exit_gpsim();
}


static void
show_message (char *title, char *message)
{
  GtkWidget *window;
  GtkWidget *label;
  GtkWidget *button;

  window = gtk_dialog_new ();

  gtk_window_set_title (GTK_WINDOW (window), title);
  gtk_container_set_border_width (GTK_CONTAINER (window), 0);


  button = gtk_button_new_with_label ("close");
  gtk_container_set_border_width (GTK_CONTAINER (button), 10);
  gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
			     GTK_SIGNAL_FUNC(gtk_widget_destroy),
			     GTK_OBJECT (window));
  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
  gtk_widget_grab_default(button);
  gtk_widget_show(button);


  label = gtk_label_new (message);
  gtk_misc_set_padding (GTK_MISC (label), 10, 10);
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), label, TRUE, TRUE, 0);

  gtk_widget_show (label);
  gtk_widget_show (window);

  gtk_grab_add (window);

}
//========================================================================
static void 
about_cb (gpointer             callback_data,
	  guint                callback_action,
	  GtkWidget           *widget)
{

  show_message(  "The GNUPIC Simulator - " VERSION, "A simulator for Microchip PIC microcontrollers.\n"
		 "by T. Scott Dattalo - mailto:scott@dattalo.com\n"
		 "   Ralf Forsberg - mailto:rfg@home.se\n"
		 "   Borut Ra" "\xc5\xbe" "em - mailto:borut.razem@siol.net\n\n"
		 "gpsim homepage: http://www.dattalo.com/gnupic/gpsim.html\n"
		 "gpsimWin32: http://gpsim.sourceforge.net/gpsimWin32/gpsimWin32.html\n");

}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#if defined(NEW_SOURCE_BROWSER)

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


//========================================================================
//
// class ColorButton
//
// Creates a GtkColorButton and places it into a parent widget.
// When the color button is clicked and changed, the signal will
// call back into this class and keep track of the selected 
// color state.
class SourceBrowserPreferences;
class ColorButton
{
public:
  ColorButton (GtkWidget *pParent, 
	       TextStyle *pStyle,
	       const char *label,
	       SourceBrowserPreferences *
	       );
  static void setColor_cb(GtkColorButton *widget,
			  ColorButton    *This);
  void apply();
  void cancel();
  TextStyle *m_pStyle;
private:
  SourceBrowserPreferences *m_prefs;
  const char *m_label;
};

//========================================================================
//
// class MarginButton
//
// Creates a GtkCheckButton that is used to select whether line numbers,
// addresses or opcodes will be displayed in the source browser margin.

class MarginButton
{
public:
  enum eMarginType {
    eLineNumbers,
    eAddresses,
    eOpcodes
  };
  MarginButton (GtkWidget *pParent,
		const char *pName,
		eMarginType id,
		SourceBrowserPreferences *
	       );
  static void toggle_cb(GtkToggleButton *widget,
			MarginButton    *This);
  void set_active();
private:
  GtkWidget *m_button;
  SourceBrowserPreferences *m_prefs;
  eMarginType m_id;
};

//========================================================================
//
// class TabButton
//
// Creates a GtkCheckButton that is used to select whether line numbers,
// addresses or opcodes will be displayed in the source browser margin.

class TabButton
{
public:
  TabButton (GtkWidget *pParent, GtkWidget *pButton,
	     int id,
	     SourceBrowserPreferences *
	     );
  static void toggle_cb(GtkToggleButton *widget,
			TabButton    *This);
  void set_active();
private:
  GtkWidget *m_button;
  SourceBrowserPreferences *m_prefs;
  int m_id;
};

//========================================================================
//
// class FontSelection
//

class FontSelection
{
public:
  FontSelection (GtkWidget *pParent, 
		 SourceBrowserPreferences *
		 );
  static void setFont_cb(GtkFontButton *widget,
			FontSelection  *This);
  void setFont();
private:
  SourceBrowserPreferences *m_prefs;
  GtkWidget *m_fontButton;
};

//========================================================================
//
class SourceBrowserPreferences : public SourceWindow
{
public:
  SourceBrowserPreferences(GtkWidget *pParent);

  void apply();
  void cancel();
  void update();
  void toggleBreak(int line);
  void movePC(int line);

  virtual int getPCLine(int page);
  virtual int getAddress(NSourcePage *pPage, int line);
  virtual bool bAddressHasBreak(int address);
  virtual int getOpcode(int address);
  void setTabPosition(int);
  void setFont(const char *);
  const char *getFont();
private:

  ColorButton *m_LabelColor;
  ColorButton *m_MnemonicColor;
  ColorButton *m_SymbolColor;
  ColorButton *m_CommentColor;
  ColorButton *m_ConstantColor;

  MarginButton *m_LineNumbers;
  MarginButton *m_Addresses;
  MarginButton *m_Opcodes;

  int m_currentTabPosition;
  int m_originalTabPosition;
  TabButton    *m_Up;
  TabButton    *m_Left;
  TabButton    *m_Down;
  TabButton    *m_Right;
  TabButton    *m_None;

  FontSelection *m_FontSelector;
};

//------------------------------------------------------------------------
class gpsimGuiPreferences
{
public:
  gpsimGuiPreferences();
  ~gpsimGuiPreferences();

  static void setup (gpointer             callback_data,
		     guint                callback_action,
		     GtkWidget           *widget);


private:
  SourceBrowserPreferences *m_SourceBrowser;

  static gint cancel_cb (gpsimGuiPreferences *Self);
  static gint apply_cb  (gpsimGuiPreferences *Self);
  void apply() { m_SourceBrowser->apply();}
  void cancel() { m_SourceBrowser->cancel();}
  GtkWidget *window;
};
static GtkWidget *LocalWindow=0;


void gpsimGuiPreferences::setup (gpointer             callback_data,
				 guint                callback_action,
				 GtkWidget           *widget)
{
  new gpsimGuiPreferences();
}


gint gpsimGuiPreferences::cancel_cb (gpsimGuiPreferences  *Self)
{

  Self->cancel();
  delete Self;
  return TRUE;
}
gint gpsimGuiPreferences::apply_cb  (gpsimGuiPreferences *Self)
{

  Self->apply();
  delete Self;
  return TRUE;
}

//------------------------------------------------------------------------
// ColorButton Constructor
ColorButton::ColorButton(GtkWidget *pParent, TextStyle *pStyle,
			 const char *colorName,SourceBrowserPreferences *prefs)
  : m_pStyle(pStyle),m_prefs(prefs), m_label(colorName)
{
  GtkWidget *hbox        = gtk_hbox_new(0,0);
  gtk_box_pack_start (GTK_BOX (pParent), hbox, FALSE, TRUE, 0);

  GtkWidget *colorButton = gtk_color_button_new_with_color (pStyle->mFG.CurrentColor());
  gtk_color_button_set_title (GTK_COLOR_BUTTON(colorButton), colorName);
  gtk_box_pack_start (GTK_BOX(hbox),colorButton,FALSE, FALSE, 0);
  gtk_widget_show(colorButton);

  gtk_signal_connect (GTK_OBJECT(colorButton), 
		      "color-set", 
		      GTK_SIGNAL_FUNC(setColor_cb),
		      this);
  const int cBORDER = 10; // pixels
  GtkWidget *label       = gtk_label_new(colorName);
  gtk_box_pack_start (GTK_BOX(hbox),label,FALSE,FALSE, cBORDER);
  gtk_widget_show (label);

  gtk_widget_show (hbox);
}

//------------------------------------------------------------------------
void ColorButton::setColor_cb(GtkColorButton *widget,
			      ColorButton    *This)
{
  GdkColor newColor;
  gtk_color_button_get_color (widget, &newColor);
  This->m_pStyle->setFG(&newColor);
}

void ColorButton::apply()
{
  m_pStyle->apply();
}
void ColorButton::cancel()
{
  m_pStyle->revert();
}

//------------------------------------------------------------------------
MarginButton::MarginButton(GtkWidget *pParent, const char *pName,
			   eMarginType id,
			   SourceBrowserPreferences *prefs)
  : m_prefs(prefs), m_id(id)
{
  m_button = gtk_check_button_new_with_label (pName);
  bool bState = false;
  switch (m_id) {
  case eLineNumbers:
    bState = m_prefs->margin().bLineNumbers();
    break;
  case eAddresses:
    bState = m_prefs->margin().bAddresses();
    break;
  case eOpcodes:
    bState = m_prefs->margin().bOpcodes();
    break;
  }
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(m_button),
				bState);
  gtk_box_pack_start (GTK_BOX (pParent), m_button, FALSE, TRUE, 10);

  gtk_signal_connect (GTK_OBJECT(m_button),
		      "toggled", 
		      GTK_SIGNAL_FUNC(toggle_cb),
		      this);
}
//------------------------------------------------------------------------
void MarginButton::toggle_cb(GtkToggleButton *widget,
			     MarginButton    *This)
{
  //  This->m_pStyle->setFG(&newColor);
  This->set_active();
}
void MarginButton::set_active()
{
  bool bNewState = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m_button)) ? true : false;
  switch (m_id) {
  case eLineNumbers:
    m_prefs->margin().enableLineNumbers(bNewState);
    break;
  case eAddresses:
    m_prefs->margin().enableAddresses(bNewState);
    break;
  case eOpcodes:
    m_prefs->margin().enableOpcodes(bNewState);
    break;
  }

}

//------------------------------------------------------------------------
TabButton::TabButton(GtkWidget *pParent, GtkWidget *pButton,
		     int id,
		     SourceBrowserPreferences *prefs)
  : m_button(pButton), m_prefs(prefs), m_id(id)
{
  gtk_box_pack_start (GTK_BOX (pParent), m_button, FALSE, TRUE, 5);

  gtk_signal_connect (GTK_OBJECT(m_button),
		      "toggled", 
		      GTK_SIGNAL_FUNC(toggle_cb),
		      this);
}
//------------------------------------------------------------------------
void TabButton::toggle_cb(GtkToggleButton *widget,
			  TabButton    *This)
{
  //  This->m_pStyle->setFG(&newColor);
  This->set_active();
}
void TabButton::set_active()
{
  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m_button)))
    m_prefs->setTabPosition(m_id);
}

//------------------------------------------------------------------------
FontSelection::FontSelection (GtkWidget *pParent,
			      SourceBrowserPreferences *pPrefs)
  : m_prefs(pPrefs)
{
  GtkWidget *frame = gtk_frame_new ("Font");

  gtk_box_pack_start (GTK_BOX (pParent), frame, FALSE, TRUE, 0);
  GtkWidget *hbox        = gtk_hbox_new(0,0);
  gtk_container_add (GTK_CONTAINER (frame), hbox);

  m_fontButton = gtk_font_button_new_with_font (m_prefs->getFont());
  const char *fontDescription = "Font Selector";
  gtk_font_button_set_title (GTK_FONT_BUTTON(m_fontButton), fontDescription);
  gtk_box_pack_start (GTK_BOX(hbox),m_fontButton,FALSE, FALSE, 0);
  gtk_widget_show(m_fontButton);

  gtk_signal_connect (GTK_OBJECT(m_fontButton), 
		      "font-set", 
		      GTK_SIGNAL_FUNC(setFont_cb),
		      this);

  const char *fontName = "font";
  const int cBORDER = 10; // pixels
  GtkWidget *label       = gtk_label_new(fontName);
  gtk_box_pack_start (GTK_BOX(hbox),label,TRUE, TRUE, cBORDER);
  gtk_widget_show (label);

  gtk_widget_show (hbox);
}
//------------------------------------------------------------------------
void FontSelection::setFont_cb (GtkFontButton *pFontButton,
				FontSelection *This)
{
  This->setFont();
}
void FontSelection::setFont()
{
  m_prefs->setFont(gtk_font_button_get_font_name (GTK_FONT_BUTTON(m_fontButton)));
}

//------------------------------------------------------------------------
#if 0 // defined but not used
static bool isButtonEvent (GdkEventType type)
{
  return 
    type == GDK_BUTTON_PRESS ||
    type == GDK_2BUTTON_PRESS ||
    type == GDK_3BUTTON_PRESS ||
    type == GDK_BUTTON_RELEASE;

}

static gboolean    TagEvent  (GtkTextTag *texttag,
		       GObject *arg1,
		       GdkEvent *event,
		       GtkTextIter *arg2,
		       gpointer user_data)
{
  printf("Received tag event signal Tag:%p arg1:%p Event:%p iter:%p user:%p %08X Line:%d\n",
	 texttag, arg1,event,arg2, user_data, event->type, gtk_text_iter_get_line(arg2));

  if (isButtonEvent(event->type)) {
    GdkEventButton *evtButton = (GdkEventButton *) event;

    printf("Button Event: button:%d  modifier:%d coords(%g,%g)\n",
	   evtButton->button, evtButton->state, evtButton->x,evtButton->y);
    // If the right mouse button is pressed then suppress the GTK pop up menu.
    if (evtButton->button == 3)
      return TRUE;
  }
  return FALSE;
}
//------------------------------------------------------------------------

static void preferences_AddFontSelect(GtkWidget *pParent, const char *fontDescription,
				      const char *fontName  )
{
}
#endif


void SourceBrowserPreferences::toggleBreak(int line)
{

}


void SourceBrowserPreferences::movePC(int line)
{
}


//========================================================================
SourceBrowserPreferences::SourceBrowserPreferences(GtkWidget *pParent)
  : SourceWindow(0,0,false,0)
{

  if (!gpGuiProcessor && !gpGuiProcessor->source_browser)
    return;

  GtkWidget *notebook = gtk_notebook_new();
  gtk_notebook_set_tab_pos((GtkNotebook*)notebook,GTK_POS_TOP);
  gtk_box_pack_start (GTK_BOX (pParent), notebook, TRUE, TRUE, 0);
  gtk_widget_show(notebook);

  m_pParent = gpGuiProcessor->source_browser;
  GtkWidget *label;

  {
    // Color Frame for Source Browser configuration

    GtkWidget *vbox = gtk_vbox_new(0,0);

    GtkWidget *colorFrame = gtk_frame_new ("Colors");
    gtk_box_pack_start (GTK_BOX (vbox), colorFrame, FALSE, TRUE, 0);

    GtkWidget *colorVbox = gtk_vbox_new(0,0);
    gtk_container_add (GTK_CONTAINER (colorFrame), colorVbox);

    m_LabelColor    = new ColorButton(colorVbox, 
				      m_pParent->mLabel,
				      "Label", this);
    m_MnemonicColor = new ColorButton(colorVbox, 
				      m_pParent->mMnemonic,
				      "Mnemonic", this);
    m_SymbolColor   = new ColorButton(colorVbox, 
				      m_pParent->mSymbol,
				      "Symbols", this);
    m_ConstantColor = new ColorButton(colorVbox,
				      m_pParent->mConstant,
				      "Constants", this);
    m_CommentColor  = new ColorButton(colorVbox,
				      m_pParent->mComment,
				      "Comments", this);

    // Font selector
    //preferences_AddFontSelect(GTK_WIDGET(vbox), "Font Selector", "font");
    m_FontSelector = new FontSelection(vbox,this);

    label = gtk_label_new("Font");
    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),vbox,label);



  }

  {
    // Tab Frame for the Source browser
    m_currentTabPosition = m_pParent->getTabPosition();
    m_originalTabPosition = m_currentTabPosition;

    GtkWidget *hbox = gtk_hbox_new(0,0);
    GtkWidget *tabFrame = gtk_frame_new ("Notebook Tabs");
    gtk_box_pack_start (GTK_BOX (hbox), tabFrame, FALSE, TRUE, 0);

    GtkWidget *radioUp  = gtk_radio_button_new_with_label (NULL,"up");
    GtkRadioButton *rb  = GTK_RADIO_BUTTON(radioUp);

    GtkWidget *tabVbox = gtk_vbox_new(0,0);
    gtk_container_add (GTK_CONTAINER (tabFrame), tabVbox);

    m_Up    = new TabButton(tabVbox, radioUp, GTK_POS_TOP, this);
    m_Left  = new TabButton(tabVbox, gtk_radio_button_new_with_label_from_widget (rb,"left"),
			   GTK_POS_LEFT, this);
    m_Down  = new TabButton(tabVbox, gtk_radio_button_new_with_label_from_widget (rb,"down"),
			   GTK_POS_BOTTOM, this);
    m_Right = new TabButton(tabVbox, gtk_radio_button_new_with_label_from_widget (rb,"right"),
			   GTK_POS_RIGHT, this);
    m_None  = new TabButton(tabVbox, gtk_radio_button_new_with_label_from_widget (rb,"none"),
			   -1, this);


    // Source browser margin 
    GtkWidget *marginFrame = gtk_frame_new ("Margin");
    gtk_box_pack_start (GTK_BOX (hbox), marginFrame, FALSE, TRUE, 0);
    GtkWidget *marginVbox = gtk_vbox_new(0,0);
    gtk_container_add (GTK_CONTAINER (marginFrame), marginVbox);

    m_LineNumbers = new MarginButton(marginVbox, "Line Numbers", 
				     MarginButton::eLineNumbers, this);
    m_Addresses   = new MarginButton(marginVbox, "Addresses", 
				     MarginButton::eAddresses, this);
    m_Opcodes     = new MarginButton(marginVbox, "Opcodes", 
				     MarginButton::eOpcodes, this);

    label = gtk_label_new("Margins");
    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),hbox,label);

  }

  {
    SourceBuffer *pBuffer = new SourceBuffer (m_pParent->getTagTable(),0,m_pParent);


    GtkWidget *frame = gtk_frame_new ("Sample");
    gtk_box_pack_start (GTK_BOX (pParent), frame, FALSE, TRUE, 0);
    
    m_Notebook = gtk_notebook_new();
    //m_currentTabPosition = m_pParent->getTabPosition();
    //gtk_notebook_set_tab_pos((GtkNotebook*)m_Notebook,m_TabPosition);
    setTabPosition(m_pParent->getTabPosition());

    gtk_container_add (GTK_CONTAINER (frame), m_Notebook);

    bIsBuilt = true;

    int id = AddPage (pBuffer, "file1.asm");

    pages[id]->m_pBuffer->parseLine( "        MOVLW   0x34       ; Comment",1);
    pages[id]->m_pBuffer->parseLine( "; Comment only",1);
    pages[id]->m_pBuffer->parseLine( "Label:  ADDWF  Variable,F  ; Comment",1);

#if 0
    label = gtk_label_new("file2.asm");
    GtkWidget *emptyBox = gtk_hbox_new(0,0);
    gtk_notebook_append_page(GTK_NOTEBOOK(m_Notebook),emptyBox,label);

#endif



  }

  gtk_widget_show_all(notebook);

}

void SourceBrowserPreferences::setTabPosition(int tabPosition)
{
  m_currentTabPosition = tabPosition;
  m_pParent->setTabPosition(tabPosition);
  if (tabPosition >= 0) {
    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(m_Notebook),TRUE);
    gtk_notebook_set_tab_pos(GTK_NOTEBOOK(m_Notebook), (GtkPositionType) m_currentTabPosition);
  } else {
    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(m_Notebook),FALSE);
  }
  Update();
}

void SourceBrowserPreferences::setFont(const char *cpFont)
{
  m_pParent->setFont(cpFont);
}

const char *SourceBrowserPreferences::getFont()
{
  return m_pParent->getFont();
}

void SourceBrowserPreferences::apply()
{
  m_LabelColor->apply();
  m_MnemonicColor->apply();
  m_SymbolColor->apply();
  m_ConstantColor->apply();
  m_CommentColor->apply();

  m_pParent->setTabPosition(m_currentTabPosition);
}

void SourceBrowserPreferences::cancel()
{

  m_LabelColor->cancel();
  m_MnemonicColor->cancel();
  m_SymbolColor->cancel();
  m_ConstantColor->cancel();
  m_CommentColor->cancel();

  m_pParent->setTabPosition(m_originalTabPosition);
}

int SourceBrowserPreferences::getPCLine(int page)
{
  return 1;
}
int SourceBrowserPreferences::getAddress(NSourcePage *pPage, int line)
{
  return 0x1234;
}
bool SourceBrowserPreferences::bAddressHasBreak(int address)
{
  return false;
}
int SourceBrowserPreferences::getOpcode(int address)
{
  return 0xABCD;
}

//========================================================================
gpsimGuiPreferences::gpsimGuiPreferences()
{
  GtkWidget *button;

  LocalWindow = gtk_dialog_new ();
  window = LocalWindow;
  gtk_widget_show (window);

  gtk_window_set_title (GTK_WINDOW (window), "Source Browser configuration");
  gtk_container_set_border_width (GTK_CONTAINER (window), 0);

  GtkWidget *vbox = GTK_DIALOG (window)->vbox;

  m_SourceBrowser = new SourceBrowserPreferences(vbox);
  gtk_widget_show_all(vbox);


  // Cancel and Apply buttons

  GtkWidget *buttonBox = gtk_hbutton_box_new();
  gtk_box_pack_start (GTK_BOX (vbox), buttonBox, TRUE, TRUE, 0);

  button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
  gtk_container_set_border_width (GTK_CONTAINER (button), 10);
  gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
			     GTK_SIGNAL_FUNC(gpsimGuiPreferences::cancel_cb),
			     this);
  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);

  gtk_box_pack_start (GTK_BOX (buttonBox), button, TRUE, TRUE, 0);
  gtk_widget_grab_default(button);

  button = gtk_button_new_from_stock (GTK_STOCK_APPLY);
  gtk_container_set_border_width (GTK_CONTAINER (button), 10);
  gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
			     GTK_SIGNAL_FUNC(gpsimGuiPreferences::apply_cb),
			     this);

  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  gtk_box_pack_start (GTK_BOX (buttonBox), button, TRUE, TRUE, 0);
  gtk_widget_show_all(buttonBox);


  gtk_widget_show (window);
  gtk_grab_add (window);

}

gpsimGuiPreferences::~gpsimGuiPreferences()
{


  gtk_widget_destroy (window);

  //delete m_SourceBrowser;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#endif //if defined(NEW_SOURCE_BROWSER)

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

//========================================================================
void
file_selection_hide_fileops (GtkWidget *widget,
			     GtkFileSelection *fs)
{
  gtk_file_selection_hide_fileop_buttons (fs);
}

extern int gui_message(char *message);

void
file_selection_ok (GtkWidget        *w,
		   GtkFileSelection *fs)
{

  const char *file;
  char msg[200];

  if(gpGuiProcessor)
  {
    file=gtk_file_selection_get_filename (fs);
    if(!gpsim_open(gpGuiProcessor->cpu, file, 0, 0))
    {
      sprintf(msg, "Open failedCould not open \"%s\"", (char *)file);
      gui_message(msg);
    }
  }
  gtk_widget_hide (GTK_WIDGET (fs));
}

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

static GtkItemFactoryCallback 
fileopen_dialog(gpointer             callback_data,
	      guint                callback_action,
	      GtkWidget           *widget)
{
  static GtkWidget *window = 0;
  GtkWidget *button;

  if (!window)
  {

    window = gtk_file_selection_new ("file selection dialog");

    gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (window));

    gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);

    gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (window)->ok_button),
			"clicked", GTK_SIGNAL_FUNC(file_selection_ok),
			window);
    gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (window)->cancel_button),
			       "clicked", GTK_SIGNAL_FUNC(gtk_widget_hide),
			       GTK_OBJECT (window));
      
    button = gtk_button_new_with_label ("Hide Fileops");
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
			(GtkSignalFunc) file_selection_hide_fileops, 
			(gpointer) window);
    gtk_box_pack_start (GTK_BOX (GTK_FILE_SELECTION (window)->action_area), 
			button, FALSE, FALSE, 0);
    gtk_widget_show (button);

    button = gtk_button_new_with_label ("Show Fileops");
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
			(GtkSignalFunc) gtk_file_selection_show_fileop_buttons,
			(gpointer) window);
    gtk_box_pack_start (GTK_BOX (GTK_FILE_SELECTION (window)->action_area), 
			button, FALSE, FALSE, 0);
    gtk_widget_show (button);
  }
    gtk_widget_show (window);
    return 0;
}




// Menuhandler for Windows menu buttons
static GtkItemFactoryCallback 
toggle_window (gpointer             callback_data,
	      guint                callback_action,
	      GtkWidget           *widget)
{
  GtkWidget *menu_item = 0;

  menu_item = gtk_item_factory_get_item (item_factory,
					 gtk_item_factory_path_from_widget (widget));
  if(gpGuiProcessor && menu_item) {
    
    int view_state =  GTK_CHECK_MENU_ITEM(menu_item)->active ? VIEW_SHOW : VIEW_HIDE;
			
    switch(callback_action) {
    case WT_opcode_source_window:
      gpGuiProcessor->program_memory->ChangeView(view_state);
      break;
    case WT_asm_source_window:
      gpGuiProcessor->source_browser->ChangeView(view_state);
      break;
    case WT_register_window:
      gpGuiProcessor->regwin_ram->ChangeView(view_state);
      break;
    case WT_eeprom_window:
      gpGuiProcessor->regwin_eeprom->ChangeView(view_state);
      break;
    case WT_watch_window:
      gpGuiProcessor->watch_window->ChangeView(view_state);
      break;
    case WT_symbol_window:
      gpGuiProcessor->symbol_window->ChangeView(view_state);
      break;
    case WT_breadboard_window:
      gpGuiProcessor->breadboard_window->ChangeView(view_state);
      break;
    case WT_stack_window:
      gpGuiProcessor->stack_window->ChangeView(view_state);
      break;
    case WT_trace_window:
      gpGuiProcessor->trace_window->ChangeView(view_state);
      break;
    case WT_profile_window:
      gpGuiProcessor->profile_window->ChangeView(view_state);
      break;
    case WT_stopwatch_window:
      gpGuiProcessor->stopwatch_window->ChangeView(view_state);
      break;
    case WT_scope_window:
      gpGuiProcessor->scope_window->ChangeView(view_state);
      //cout << " The Scope is disabled right now\n";
      break;
    default:
      puts("unknown menu action");
    }

  }
  return 0;
}

//========================================================================
// Button callbacks
static void 
runbutton_cb(GtkWidget *widget)
{
  if(gpGuiProcessor && gpGuiProcessor->cpu)
    gpGuiProcessor->cpu->pma->run();
}

static void 
stopbutton_cb(GtkWidget *widget)
{
  if(gpGuiProcessor && gpGuiProcessor->cpu)
    gpGuiProcessor->cpu->pma->stop();
}
    
static void 
stepbutton_cb(GtkWidget *widget)
{
  if(gpGuiProcessor && gpGuiProcessor->cpu) 
    gpGuiProcessor->cpu->pma->step(1);
}
    
static void 
overbutton_cb(GtkWidget *widget)
{
  if(gpGuiProcessor && gpGuiProcessor->cpu) 
    gpGuiProcessor->cpu->pma->step_over();

}
    
static void 
finishbutton_cb(GtkWidget *widget)
{
  if(gpGuiProcessor && gpGuiProcessor->cpu) 
    gpGuiProcessor->cpu->pma->finish();
}

static void 
resetbutton_cb(GtkWidget *widget)
{
  if(gpGuiProcessor && gpGuiProcessor->cpu)
    gpGuiProcessor->cpu->reset(POR_RESET);
}


int gui_animate_delay; // in milliseconds


//========================================================================
//========================================================================
//
// UpdateRateMenuItem

//========================================================================
//
// Class declaration -- probaby should move to a .h file.

class UpdateRateMenuItem {
public:

  char id;
  int menu_index;
  bool bRealTime;
  bool bWithGui;
  bool bAnimate;

  int update_rate;

  UpdateRateMenuItem(GtkWidget *,char, const char *, int update_rate=0, bool _bRealTime=false, bool _bWithGui=false);

  void Select();
  static GtkWidget *menu;
  static int seq_no;
};
//========================================================================
// UpdateRateMenuItem members

GtkWidget * UpdateRateMenuItem::menu = 0;
int UpdateRateMenuItem::seq_no=0;

map<guint, UpdateRateMenuItem*> UpdateRateMenuItemMap;
map<guint, UpdateRateMenuItem*> UpdateRateMenuItemIndexed;


static void
gui_update_cb(GtkWidget *widget, gpointer data)
{
  GtkComboBox *combo_box = GTK_COMBO_BOX(widget);
  gint index = combo_box ? gtk_combo_box_get_active(combo_box) : 0;

  UpdateRateMenuItem *umi = UpdateRateMenuItemIndexed[index];
  if (umi)
    umi->Select();
  else 
    cout << "Error UpdateRateMenuItem bad index:" << index << endl;
}

UpdateRateMenuItem::UpdateRateMenuItem(GtkWidget *parent,
				       char _id, 
				       const char *label,
				       int _update_rate,
				       bool _bRealTime,
				       bool _bWithGui)
  : id(_id), bRealTime(_bRealTime), bWithGui(_bWithGui), update_rate(_update_rate)
{

  if(update_rate <0) {
    bAnimate = true;
    update_rate = -update_rate;
  } else
    bAnimate = false;

  if(!menu)
    menu = gtk_menu_new();

  gtk_combo_box_append_text (GTK_COMBO_BOX(parent), label);

  menu_index = seq_no;
  seq_no++;

  UpdateRateMenuItemMap[id] = this;
  UpdateRateMenuItemIndexed[menu_index] = this;

}

void UpdateRateMenuItem::Select()
{
  EnableRealTimeMode(bRealTime);
  EnableRealTimeModeWithGui(bWithGui);

  if(bAnimate) {
    gui_animate_delay = update_rate;
    get_interface().set_update_rate(1);
  } else {
    gui_animate_delay = 0;
    get_interface().set_update_rate(update_rate);
  }

  if(gpGuiProcessor && gpGuiProcessor->cpu)
    gpGuiProcessor->cpu->pma->stop();

  config_set_variable("dispatcher", "SimulationMode", id);

  if (0)
    cout << "Update gui refresh: " << hex << update_rate 
	 << " ID:" << id << "Seq no:" << menu_index
	 << endl;
}


//========================================================================
//========================================================================
class TimeWidget;
class TimeFormatter
{
public:

  enum eMenuID {
    eCyclesHex=0,
    eCyclesDec,
    eMicroSeconds,
    eMilliSeconds,
    eSeconds,
    eHHMMSS
  } time_format;
  TimeFormatter(TimeWidget *_tw,GtkWidget *menu, const char*menu_text)
   : tw(_tw)
  {
    AddToMenu(menu,menu_text);
  }

  void ChangeFormat();
  void AddToMenu(GtkWidget *menu, const char*menu_text);
  virtual void Format(char *, int)=0;
  TimeWidget *tw;
};

class TimeWidget : public EntryWidget
{
public:
  TimeWidget();
  void Create(GtkWidget *);
  virtual void Update();
  void NewFormat(TimeFormatter *tf);
  TimeFormatter *current_format;

  GtkWidget *menu;
};


class TimeMicroSeconds : public TimeFormatter
{
public:
  TimeMicroSeconds(TimeWidget *tw, GtkWidget *menu) 
    : TimeFormatter(tw,menu,"MicroSeconds") {}
  void Format(char *buf, int size)
  {
    double time_db = gpGuiProcessor->cpu->get_InstPeriod() * get_cycles().value * 1e6;
    snprintf(buf,size, "%19.2f us",time_db);
  }
};

class TimeMilliSeconds : public TimeFormatter
{
public:
  TimeMilliSeconds(TimeWidget *tw, GtkWidget *menu) 
    : TimeFormatter(tw,menu,"MilliSeconds") {}
  void Format(char *buf, int size)
  {
    double time_db = gpGuiProcessor->cpu->get_InstPeriod() * get_cycles().value * 1e3;
    snprintf(buf,size, "%19.3f ms",time_db);
  }
};

class TimeSeconds : public TimeFormatter
{
public:
  TimeSeconds(TimeWidget *tw, GtkWidget *menu) 
    : TimeFormatter(tw,menu,"Seconds") {}
  void Format(char *buf, int size)
  {
    double time_db = gpGuiProcessor->cpu->get_InstPeriod() * get_cycles().value;
    snprintf(buf,size, "%19.3f Sec",time_db);
  }
};

class TimeHHMMSS : public TimeFormatter
{
public:
  TimeHHMMSS(TimeWidget *tw, GtkWidget *menu) 
    : TimeFormatter(tw,menu,"HH:MM:SS.mmm") {}
  void Format(char *buf, int size)
  {
    double time_db = gpGuiProcessor->cpu->get_InstPeriod() * get_cycles().value;
    double v=time_db;
    int hh=(int)(v/3600),mm,ss,cc;
    v-=hh*3600.0;
    mm=(int)(v/60);
    v-=mm*60.0;
    ss=(int)v;
    cc=(int)(v*100.0+0.5);
    snprintf(buf,size,"    %02d:%02d:%02d.%02d",hh,mm,ss,cc);
  }
};

class TimeCyclesHex : public TimeFormatter
{
public:
  TimeCyclesHex(TimeWidget *tw, GtkWidget *menu) 
    : TimeFormatter(tw,menu,"Cycles (Hex)") {}
  void Format(char *buf, int size)
  {
    snprintf(buf,size,"0x%016" PRINTF_INT64_MODIFIER "x",get_cycles().value);
  }
};

class TimeCyclesDec : public TimeFormatter
{
public:
  TimeCyclesDec(TimeWidget *tw, GtkWidget *menu) 
    : TimeFormatter(tw,menu,"Cycles (Dec)") {}
  void Format(char *buf, int size)
  {
    snprintf(buf,size,"%016" PRINTF_INT64_MODIFIER "d",get_cycles().value);
  }
};

//========================================================================
// called when user has selected a menu item from the time format menu
static void
cbTimeFormatActivated(GtkWidget *widget, gpointer data)
{
  if(!widget || !data)
    return;
    
  TimeFormatter *tf = static_cast<TimeFormatter *>(data);
  tf->ChangeFormat();
}
// button press handler
static gint
cbTimeFormatPopup(GtkWidget *widget, GdkEventButton *event, TimeWidget *tw)
{
  if(!widget || !event || !tw)
    return 0;
  
  if( (event->type == GDK_BUTTON_PRESS) ) {// &&  (event->button == 3) ) {

    gtk_menu_popup(GTK_MENU(tw->menu), 0, 0, 0, 0,
		   3, event->time);
    // It looks like we need it to avoid a selection in the entry.
    // For this we tell the entry to stop reporting this event.
    gtk_signal_emit_stop_by_name(GTK_OBJECT(tw->entry),"button_press_event");
  }
  return FALSE;
}


void TimeFormatter::ChangeFormat()
{
  if(tw)
    tw->NewFormat(this);
}

void TimeFormatter::AddToMenu(GtkWidget *menu, 
			      const char*menu_text)
{
  GtkWidget *item = gtk_menu_item_new_with_label(menu_text);
  gtk_signal_connect(GTK_OBJECT(item),"activate",
		     (GtkSignalFunc) cbTimeFormatActivated,
		     this);
  gtk_widget_show(item);
  gtk_menu_append(GTK_MENU(menu),item);
}

void TimeWidget::Create(GtkWidget *container)
{
  EntryWidget::Create(false);

  gtk_container_add(GTK_CONTAINER(container),entry);

  SetEntryWidth(18);

  menu = gtk_menu_new();
  GtkWidget *item = gtk_tearoff_menu_item_new ();
  gtk_menu_append (GTK_MENU (menu), item);
  gtk_widget_show (item);


  // Create an entry for each item in the formatter pop up window.

  new TimeMicroSeconds(this,menu);
  new TimeMilliSeconds(this,menu);
  new TimeSeconds(this,menu);
  new TimeHHMMSS(this,menu);
  NewFormat(new TimeCyclesHex(this,menu));
  new TimeCyclesDec(this,menu);

  // Associate a callback with the user button-click actions
  gtk_signal_connect(GTK_OBJECT(entry),
		     "button_press_event",
		     (GtkSignalFunc) cbTimeFormatPopup,
		     this);
}


void TimeWidget::NewFormat(TimeFormatter *tf)
{
  if(tf && tf != current_format) {
    current_format = tf;
    Update();
  }
}

void TimeWidget::Update()
{
  if(!current_format)
    return;

  char buffer[32];

  current_format->Format(buffer, sizeof(buffer));
  gtk_entry_set_text (GTK_ENTRY (entry), buffer);

}

TimeWidget::TimeWidget()
{
  menu = 0;
  current_format =0;
}


//========================================================================
static int dispatcher_delete_event(GtkWidget *widget,
				   GdkEvent  *event,
				   gpointer data)
{
    do_quit_app(0);

    return 0;
}

static GtkItemFactoryCallback
gtk_ifactory_cb (gpointer             callback_data,
		 guint                callback_action,
		 GtkWidget           *widget)
{
  g_message ("\"%s\" is not supported yet.", gtk_item_factory_path_from_widget (widget));
    return 0;
}

#define TOGGLE_WINDOW (GtkItemFactoryCallback)toggle_window

static GtkItemFactoryEntry menu_items[] =
{
  { "/_File",            0,         0,                     0, "<Branch>" },
  { "/File/tearoff1",    0,         (GtkItemFactoryCallback)gtk_ifactory_cb,       0, "<Tearoff>" },
  //{ "/File/_New",        "<control>N", (GtkItemFactoryCallback)gtk_ifactory_cb,       0 },
  { "/File/_Open",       "<control>O", (GtkItemFactoryCallback)fileopen_dialog,       0 },
  //{ "/File/_Save",       "<control>S", (GtkItemFactoryCallback)gtk_ifactory_cb,       0 },
  //{ "/File/Save _As...", 0,         (GtkItemFactoryCallback)gtk_ifactory_cb,       0 },
  { "/File/sep1",        0,         (GtkItemFactoryCallback)gtk_ifactory_cb,       0, "<Separator>" },
  { "/File/_Quit",       "<control>Q", (GtkItemFactoryCallback)do_quit_app,         0 },

  //  { "/_Processor",     	 0,       0,               0, "<Branch>" },
  //  { "/_Processor/New",   0,       (GtkItemFactoryCallback)new_processor_dialog,       0 },
  //  { "/_Processor/Delete",0,       (GtkItemFactoryCallback)gtk_ifactory_cb,       0 },
  //  { "/_Processor/Switch",0,       (GtkItemFactoryCallback)gtk_ifactory_cb,       0 },


  //  { "/_Break",     	 0, 0,               0, "<Branch>" },
  //  { "/_Break/Set",       0, (GtkItemFactoryCallback)gtk_ifactory_cb,       0 },
  //  { "/_Break/Clear",     0, (GtkItemFactoryCallback)gtk_ifactory_cb,       0 },

  { "/_Windows",     0, 0,       0, "<Branch>" },
  { "/Windows/Program _memory", 0, TOGGLE_WINDOW,WT_opcode_source_window,"<ToggleItem>" },
  { "/Windows/_Source",         0, TOGGLE_WINDOW,WT_asm_source_window,"<ToggleItem>" },
  { "/Windows/sep1",            0, (GtkItemFactoryCallback)gtk_ifactory_cb,0,"<Separator>"  },
  { "/Windows/_Ram",            0, TOGGLE_WINDOW,WT_register_window,"<ToggleItem>" },
  { "/Windows/_EEPROM",         0, TOGGLE_WINDOW,WT_eeprom_window,"<ToggleItem>" },
  { "/Windows/_Watch",          0, TOGGLE_WINDOW,WT_watch_window,"<ToggleItem>" },
  { "/Windows/Sta_ck",          0, TOGGLE_WINDOW,WT_stack_window,"<ToggleItem>" },
  { "/Windows/sep2",            0, (GtkItemFactoryCallback)gtk_ifactory_cb,0,"<Separator>"  },
  { "/Windows/Symbo_ls",        0, TOGGLE_WINDOW,WT_symbol_window,"<ToggleItem>" },
  { "/Windows/_Breadboard",     0, TOGGLE_WINDOW,WT_breadboard_window,"<ToggleItem>" },
  { "/Windows/sep3",            0, (GtkItemFactoryCallback)gtk_ifactory_cb,0,"<Separator>"  },
  { "/Windows/_Trace",          0, TOGGLE_WINDOW,WT_trace_window,"<ToggleItem>" },
  { "/Windows/Pro_file",        0, TOGGLE_WINDOW,WT_profile_window,"<ToggleItem>" },
  { "/Windows/St_opwatch",      0, TOGGLE_WINDOW,WT_stopwatch_window,"<ToggleItem>" },
  { "/Windows/Sco_pe",          0, TOGGLE_WINDOW,WT_scope_window,"<ToggleItem>" },

#if defined(NEW_SOURCE_BROWSER)
  { "/_Edit",     0, 0,       0, "<Branch>" },
  { "/Edit/Preferences",        0, (GtkItemFactoryCallback)gpsimGuiPreferences::setup, 0 },
#endif

  { "/_Help",            0,         0,                     0, "<LastBranch>" },
  { "/Help/_About",      0,         (GtkItemFactoryCallback)about_cb,       0 },

};

static int nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);


GtkWidget *dispatcher_window = 0;
//========================================================================
//========================================================================

class MainWindow 
{
public:

  TimeWidget   *timeW;

  void Update();
  void Create();

  MainWindow();
};

MainWindow TheWindow;

MainWindow::MainWindow()
{
  timeW=0;
}

void MainWindow::Update()
{
  if(timeW)
   timeW->Update();
}


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

void dispatch_Update()
{
  if(!dispatcher_window)
    return;

  if(gpGuiProcessor && gpGuiProcessor->cpu) {

    TheWindow.Update();

  }
}

void MainWindow::Create ()
{

  if (dispatcher_window)
    return;

  GtkWidget *box1;

  GtkWidget *buttonbox;
  GtkWidget *separator;
  GtkWidget *button;
  GtkWidget *frame;
  GtkAccelGroup *accel_group;
      
  int x,y,width,height;

  GtkWidget *update_rate_menu;

  int SimulationMode;
      
  dispatcher_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

  if(!config_get_variable("dispatcher", "x", &x))
    x=10;
  if(!config_get_variable("dispatcher", "y", &y))
    y=10;
  if(!config_get_variable("dispatcher", "width", &width))
    width=1;
  if(!config_get_variable("dispatcher", "height", &height))
    height=1;
  gtk_window_set_default_size(GTK_WINDOW(dispatcher_window), width,height);
  gtk_widget_set_uposition(GTK_WIDGET(dispatcher_window),x,y);
      
      
  gtk_signal_connect (GTK_OBJECT (dispatcher_window), "delete-event",
		      GTK_SIGNAL_FUNC (dispatcher_delete_event),
		      0);
      
#if GTK_MAJOR_VERSION >= 2
  accel_group = gtk_accel_group_new();
#else
  accel_group = gtk_accel_group_get_default ();
#endif
  item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", accel_group);
  gtk_object_set_data_full (GTK_OBJECT (dispatcher_window),
			    "<main>",
			    item_factory,
			    (GtkDestroyNotify) gtk_object_unref);
  //      gtk_accel_group_attach (accel_group, GTK_OBJECT (dispatcher_window));
  gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, 0);
  gtk_window_set_title (GTK_WINDOW (dispatcher_window), 
			VERSION);
  gtk_container_set_border_width (GTK_CONTAINER (dispatcher_window), 0);
      
  box1 = gtk_vbox_new (FALSE, 0);
  gtk_container_add (GTK_CONTAINER (dispatcher_window), box1);
      
  gtk_box_pack_start (GTK_BOX (box1),
		      gtk_item_factory_get_widget (item_factory, "<main>"),
		      FALSE, FALSE, 0);


      
  buttonbox = gtk_hbox_new(FALSE,0);
  gtk_container_set_border_width (GTK_CONTAINER (buttonbox), 1);
  gtk_box_pack_start (GTK_BOX (box1), buttonbox, TRUE, TRUE, 0);

      
      
  // Buttons
  button = gtk_button_new_with_label ("step");
  gtk_signal_connect(GTK_OBJECT(button), "clicked",
		     (GtkSignalFunc) stepbutton_cb, 0);
  gtk_box_pack_start (GTK_BOX (buttonbox), button, TRUE, TRUE, 0);
      
  button = gtk_button_new_with_label ("over");
  gtk_signal_connect(GTK_OBJECT(button), "clicked",
		     (GtkSignalFunc) overbutton_cb, 0);
  gtk_box_pack_start (GTK_BOX (buttonbox), button, TRUE, TRUE, 0);

  button = gtk_button_new_with_label ("finish");
  gtk_signal_connect(GTK_OBJECT(button), "clicked",
		     (GtkSignalFunc) finishbutton_cb, 0);
  gtk_box_pack_start (GTK_BOX (buttonbox), button, TRUE, TRUE, 0);

  button = gtk_button_new_with_label ("run");
  gtk_signal_connect(GTK_OBJECT(button), "clicked",
		     (GtkSignalFunc) runbutton_cb, 0);
  gtk_box_pack_start (GTK_BOX (buttonbox), button, TRUE, TRUE, 0);

  button = gtk_button_new_with_label ("stop");
  gtk_signal_connect(GTK_OBJECT(button), "clicked",
		     (GtkSignalFunc) stopbutton_cb, 0);
  gtk_box_pack_start (GTK_BOX (buttonbox), button, TRUE, TRUE, 0);

  button = gtk_button_new_with_label ("reset");
  gtk_signal_connect(GTK_OBJECT(button), "clicked",
		     (GtkSignalFunc) resetbutton_cb, 0);
  gtk_box_pack_start (GTK_BOX (buttonbox), button, TRUE, TRUE, 0);


  //
  // Simulation Mode Frame
  //

  frame = gtk_frame_new("Simulation mode");
  if(!config_get_variable("dispatcher", "SimulationMode", &SimulationMode))
    {
      SimulationMode='4';
    }
  //  set_simulation_mode(SimulationMode);

  //
  // Gui Update Rate
  //
  cout << "SimulationMode:"<<SimulationMode<<endl;

  update_rate_menu = gtk_combo_box_new_text();
  gtk_container_add(GTK_CONTAINER(frame),update_rate_menu);

  new UpdateRateMenuItem(update_rate_menu,'5',"Without gui (fastest simulation)",0);
  new UpdateRateMenuItem(update_rate_menu,'4',"2000000 cycles/gui update",2000000);
  new UpdateRateMenuItem(update_rate_menu,'3',"100000 cycles/gui update",100000);
  new UpdateRateMenuItem(update_rate_menu,'2',"1000 cycles/gui update",1000);
  new UpdateRateMenuItem(update_rate_menu,'1',"Update gui every cycle",1);
  new UpdateRateMenuItem(update_rate_menu,'b',"100ms animate",-100);
  new UpdateRateMenuItem(update_rate_menu,'c',"300ms animate",-300);
  new UpdateRateMenuItem(update_rate_menu,'d',"700ms animate",-700);
  new UpdateRateMenuItem(update_rate_menu,'r',"Realtime without gui",0,true);
  new UpdateRateMenuItem(update_rate_menu,'R',"Realtime with gui",0,true,true);

  UpdateRateMenuItem *umi = UpdateRateMenuItemMap[SimulationMode];

  if(!umi)
    cout << "error selecting update rate menu\n";
  umi->Select();

  gtk_combo_box_set_active(GTK_COMBO_BOX(update_rate_menu), umi->menu_index);

  gtk_signal_connect(GTK_OBJECT(update_rate_menu),"changed",
		     (GtkSignalFunc) gui_update_cb,
		     (gpointer)update_rate_menu);

  gtk_box_pack_start (GTK_BOX (buttonbox), frame, FALSE, FALSE, 5);

  //
  // Simulation Time Frame
  //

  frame = gtk_frame_new("Simulation Time");
  gtk_box_pack_start (GTK_BOX (buttonbox), frame, FALSE, FALSE, 5);

  timeW = new TimeWidget();
  timeW->Create(frame);
  timeW->Update();

  //gtk_box_pack_start (GTK_BOX (buttonbox), frame, TRUE, TRUE, 5);

  separator = gtk_hseparator_new ();
  gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
  button = gtk_button_new_with_label ("Quit gpsim");
  gtk_signal_connect(GTK_OBJECT(button), "clicked",
		     (GtkSignalFunc) do_quit_app, 0);

  gtk_box_pack_start (GTK_BOX (box1), button, FALSE, TRUE, 5);
  gtk_widget_show_all (dispatcher_window);
      

}

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

void create_dispatcher ()
{
  TheWindow.Create();
}

#endif // HAVE_GUI


syntax highlighted by Code2HTML, v. 0.9.1