text: /* memory.c: the GTK+ memory browser
     Copyright (c) 2004-2005 Philip Kendall
     Copyright (c) 2015 Stuart Brady
  
     $Id: memory.c 804 2016-06-01 10:46:07Z fredm $
  
     This program 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 of the License, or
     (at your option) any later version.
  
     This program 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 this program; if not, write to the Free Software Foundation, Inc.,
     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  
     Author contact information:
  
     E-mail: philip-fuse@shadowmagic.org.uk
  
  */
  
  #include <config.h>
  
  #include <stdio.h>
  #include <string.h>
  
  #include <gdk/gdkkeysyms.h>
  #include <gtk/gtk.h>
  
  #include "compat.h"
  #include "fuse.h"
  #include "gtkcompat.h"
  #include "gtkinternals.h"
  #include "memory.h"
  #include "menu.h"
  
  static libspectrum_word memaddr = 0x0000;
  
  /* List columns */
  enum
  {
    COL_ADDRESS = 0,
    COL_HEX,
    COL_DATA,
    NUM_COLS
  };
  
  static void
  update_display( GtkTreeModel *model, libspectrum_word base )
  {
    size_t i, j;
    GtkTreeIter iter;
  
    gchar buffer[ 8 + 64 + 20 ];
    gchar *text[] = { &buffer[0], &buffer[ 8 ], &buffer[ 8 + 64 ] };
    char buffer2[ 8 ];
  
    memaddr = base;
    gtk_list_store_clear( GTK_LIST_STORE( model ) );
  
    for( i = 0; i < 20; i++ ) {
      snprintf( text[0], 8, "%04X", base );
  
      text[1][0] = '\0';
      for( j = 0; j < 0x10; j++, base++ ) {
  
        libspectrum_byte b = readbyte_internal( base );
  
        snprintf( buffer2, 4, "%02X ", b );
        strncat( text[1], buffer2, 4 );
  
        text[2][j] = ( b >= 32 && b < 127 ) ? b : '.';
      }
      text[2][ 0x10 ] = '\0';
  
      /* Append a new row and fill data */
      gtk_list_store_append( GTK_LIST_STORE( model ), &iter );
      gtk_list_store_set( GTK_LIST_STORE( model ), &iter,
                          COL_ADDRESS, text[0],
                          COL_HEX,     text[1],
                          COL_DATA,    text[2],
                          -1 );
    }
  
  }
  
  static void
  scroller( GtkAdjustment *adjustment, gpointer user_data )
  {
    libspectrum_word base;
    GtkTreeModel *model = user_data;
  
    /* Drop the low bits before displaying anything */
    base = gtk_adjustment_get_value( adjustment );
    base &= 0xfff0;
  
    update_display( model, base );
  }
  
  static GtkWidget *
  create_mem_list( void )
  {
    GtkWidget *view;
    GtkCellRenderer *renderer;
    GtkTreeModel *model;
    GtkListStore *store;
  
    view = gtk_tree_view_new();
  
    /* Add columns */
    renderer = gtk_cell_renderer_text_new();
    gtk_tree_view_insert_column_with_attributes( GTK_TREE_VIEW( view ),
                                                 -1,
                                                 "Address",
                                                 renderer,
                                                 "text", COL_ADDRESS,
                                                 NULL );
  
    renderer = gtk_cell_renderer_text_new();
    gtk_tree_view_insert_column_with_attributes( GTK_TREE_VIEW( view ),
                                                 -1,
                                                 "Hex",
                                                 renderer,
                                                 "text", COL_HEX,
                                                 NULL );
  
    renderer = gtk_cell_renderer_text_new();
    gtk_tree_view_insert_column_with_attributes( GTK_TREE_VIEW( view ),
                                                 -1,
                                                 "Data",
                                                 renderer,
                                                 "text", COL_DATA,
                                                 NULL );
  
    /* Create data model */
    store = gtk_list_store_new( NUM_COLS, G_TYPE_STRING, G_TYPE_STRING,
                                G_TYPE_STRING );
  
    model = GTK_TREE_MODEL( store );
    gtk_tree_view_set_model( GTK_TREE_VIEW( view ), model );
    g_object_unref( model );
  
    return view;
  }
  
  void
  menu_machine_memorybrowser( GtkAction *gtk_action GCC_UNUSED,
                              gpointer data GCC_UNUSED )
  {
    GtkWidget *dialog, *box, *content_area, *list, *scrollbar;
    GtkAdjustment *adjustment;
    GtkTreeModel *model;
    int error;
    gtkui_font font;
  
    fuse_emulation_pause();
  
    error = gtkui_get_monospaced_font( &font ); if( error ) return;
  
    dialog = gtkstock_dialog_new( "Fuse - Memory Browser", NULL );
  
    gtkstock_create_close( dialog, NULL, NULL, FALSE );
  
    box = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 );
    content_area = gtk_dialog_get_content_area( GTK_DIALOG( dialog ) );
    gtk_box_pack_start( GTK_BOX( content_area ), box, TRUE, TRUE, 0 );
  
    /* The list itself */
    list = create_mem_list();
    gtkui_set_font( list, font );
    model = gtk_tree_view_get_model( GTK_TREE_VIEW( list ) );
    update_display( GTK_TREE_MODEL( model ), memaddr );
    gtk_box_pack_start( GTK_BOX( box ), list, TRUE, TRUE, 0 );
  
    adjustment = GTK_ADJUSTMENT(
      gtk_adjustment_new( memaddr, 0x0000, 0xffff, 0x10, 0xa0, 0x13f ) );
    g_signal_connect( adjustment, "value-changed", G_CALLBACK( scroller ),
                      model );
  
    gtkui_scroll_connect( GTK_TREE_VIEW( list ), adjustment );
  
    scrollbar = gtk_scrollbar_new( GTK_ORIENTATION_VERTICAL, adjustment );
    gtk_box_pack_start( GTK_BOX( box ), scrollbar, FALSE, FALSE, 0 );
  
    gtk_widget_show_all( dialog );
    gtk_main();
  
    gtkui_free_font( font );
    fuse_emulation_unpause();
  
    return;
  }
  