#! /usr/bin/perl -w


##########################################################
#
#  Display data from Standard Data Aquisition Log files
#
# (C) 2012 Doug Coulter, GPL v2 license -- share and enjoy,
# but if you improve it, be sure and share it back, to
# clab@swva.net, or www.coultersmithing.com/forums
#
#
# See use section below for any modules you'll need to install first
##########################################################
# It's probably obvious I'm coding this like I was a C programmer
# (because I am), and squishing fancy expressions into single liners
# would just make the inevitable changes this is going to need harder
# to figure out later -- for a C programmer (me).
#
# Anything I thought was dodgy is marked with an @@@ for searching
#
# If you're a perl purist or stylist, sorry 'bout that.  
# TMTOWTDI and, TANSTAAFL for good measure.
# lots of steal-me code here for beginning perl people
##########################################################
#
# Note, I'm using a goodly number of globals here to avoid tons of typing
# parameters into subroutines.  Most assume you'll call them in the right
# order and they're valid.  This only works for well disciplined programmers
# and not even for them if things get too big and confusing. It's not stylin,
# don't do this at home.  It does make things faster to run and to write if
# you keep it all in your head well enough. Flame me if you want.  This works.

use strict; # make perl tell me about typos and how dumb I am - built in

# Bring in a pile of library modules, this code is already written and tested by 
# someone else (mostly).  Most of these aren't standard, but have to be gotten from
# CPAN and installed via the standard way for your platform
#
# If you're running ubuntu the software center can search for these.
# run this from a terminal then use Software center to get anything mentioned in the printed
# errors this program gives -- you'll need the gnuplot program of course too.

use Gtk2 -init; # sets up GUI basics
use Glib qw(TRUE FALSE); # ah, teach it truth and falsity - the apple in eden
use Gtk2::GladeXML; # lets GUI come from a glade file
#use Graphics::GnuplotIF qw(GnuplotIF); # gnuplot for plots
# I rolled my own instead


# these were built-ins in my distro
use File::Spec::Functions qw/:ALL/; # changes things like ./ to a real path
use File::Basename; # to get path to program for config files and logs
use Storable; # for (re) storing hash of hashes preset


##################################################################
######################  Global Variables #########################
##################################################################

# gui pointers
my $gui; # main window
my ($filechooser,$filepath); # button to look for a file

my ($xedit,$xcode); # widget pointer, then its data variable
my ($yedit,$ycode);
my ($zedit,$zcode);
my ($cedit,$ccode);

my ($xlabel,$xtext); # axes labels and text
my ($ylabel,$ytext);
my ($zlabel,$ztext);
my ($clabel,$ctext);

my ($logxc,$logxb); # log buttons and boolean
my ($logyc,$logyb);
my ($logzc,$logzb);
my ($logcc,$logcb);

my ($presetcombo,$presettext);
my ($statusbar,$statustext);

my $makeplot;

# plain globals

my %presets; # saved/restored from disk file .plotdatpre in current dir
my $prepath; # file path for presets file

# data series from file
my @T;
my @c0;
my @c1;
my @a0;
my @a1;
my @a2;
my $cal;
# plot series to gnuplot
my @x;
my @y;
my @z;
my @c;

my $gplot; # handle to gnuplot object

##################################################################
######################  Subroutines ##############################
##################################################################

####################
#@@@ - remember, this is stupid, so when copying for a new program read below

# to hook this up, in glade use gtk_main_quit as the handler in the mainwin/GtkWidget/destory-event
# also needed Gtkobject destroy event and check "after"?  Did both, now it works.

sub gtk_main_quit  { Gtk2->main_quit; } # fall out of main event loop

####################
# get pathname to program directory for use in config and log files
# we need this insane dance as the program path in $0 might be ./name
# which is kind of hard to use right.  We want an absolute path where
# the script lives, and this gets it (with two modules needed!)

sub getmypath()
{
 my $path = rel2abs($0); # fix up any relative path we got
# print ("\nmunged path is: $path\n"); # debug
 $path = dirname($path); # now get just the dir without progname on it
#print ("\nfinally, path to program is: $path\n"); # debug 
 return $path;
}
####################
sub creategui()
{# create a local scope
 my $guidata; # packed the xml internally, goes here
 local $/; # which makes this undefined for this sub
 $guidata = <main::DATA>; # which in turn makes this slurp the entire file
 $gui = Gtk2::GladeXML->new_from_buffer($guidata); # create gui from in-program data, cool.
 $gui->signal_autoconnect_from_package('main'); # hooks subs to signals if things are named right
# not so program-specific you couldn't use it again
}

####################
sub getwidgetpointers()
{ # get pointers to all the gui elements
  # VERY program-specific
 $filechooser = $gui->get_widget('filechooser');
 $xedit = $gui->get_widget('xeq');
 $yedit = $gui->get_widget('yeq');
 $zedit = $gui->get_widget('zeq');
 $cedit = $gui->get_widget('ceq');
 $xlabel = $gui->get_widget('XLabel');
 $ylabel = $gui->get_widget('YLabel');
 $zlabel = $gui->get_widget('ZLabel');
 $clabel = $gui->get_widget('CLabel');
 $logxc = $gui->get_widget('logx');
 $logyc = $gui->get_widget('logy');
 $logzc = $gui->get_widget('logz');
 $logcc = $gui->get_widget('logc');
 $presetcombo = $gui->get_widget('preset');
 $makeplot = $gui->get_widget('doplot'); # so we can enable/disable button
 $makeplot->set_sensitive(FALSE); # no file open yet
 $statusbar = $gui->get_widget('statusbar');  
}
####################
sub resetdata
{ # clear out various arrays before a new file
 @T = (); # stuff from file
 @c0 = ();
 @c1 = ();
 @a0 = ();
 @a1 = ();
 @a2 = ();
 $cal = 0;
# plot series to gnuplot
 @x = ();
 @y = ();
 @z = ();
 @c = ();
}
####################
sub clearcombo()
{ # a little hard to discover how to do this
 $presetcombo->get_model->clear(); # seems to work
}
####################
sub setupcombo()
{ # pull in presets etc
# my $hashref;
 
 unless (-e $prepath) # test for preset file existance
 {
  print "\nno file at:$prepath\n";
  $presetcombo->append_text("no presets!");
  $presetcombo->set_active(0); # show the status
  return; # can't do squat else
 }
 # ok, file exists, read it into hash-of-hashes
 %presets = %{ retrieve($prepath) }; # cool rebuild from file
 clearcombo(); # remove any existing junk
 # now fill combobox
 foreach (sort keys %presets) { $presetcombo->append_text($_); } # put into combo box list
# 
 $presetcombo->set_active(0); # select something, create event
}

####################
####################


####################
sub printpresets()
{ #@@@ gnarly dereferencing syntax in this
 my $href;
 my ($okey,$ikey);
 foreach $okey (sort keys %presets)
 {
  print "\n\nPreset Name: $okey\n\n";
  $href = $presets{$okey};
  
  foreach $ikey (sort keys %$href )
  {
   print "key:$ikey, value:$$href{$ikey}\n";
  }
  print "\n\n";
 }
}

####################
sub map_plot()
{ # this is the tricky bit.  We will map from log file data
  # onto the plottable data using code from entry boxes
  # we'll evaluate here in a loop.
  my ($x,$y,$z,$c); # scalar loop variables for output
  my ($t,$c0,$c1,$a0,$a1,$a2); # scalar inputs from log file
  my ($xeq,$yeq,$zeq,$ceq); # equations texts
  my ($i,$scr1,$scr2,$scr3); # looping var and temps
  
  $#x = $#y = $#z = $#c = $#T; # preset result array lengths
  
  $xeq =  $xedit->get_text(); # get the equations
  $yeq =  $yedit->get_text();
  $zeq =  $zedit->get_text();
  $ceq =  $cedit->get_text();

  
  for ($i=0;$i<scalar(@T);$i++) # a subscripted loop over all times
  { # fill result arrays by eval'ing code from text boxes
   $t = $T[$i]; # fill scalars for equations to work on
   $c0 = $c0[$i];
   $c1 = $c1[$i];
   $a0 = $a0[$i];
   $a1 = $a1[$i];
   $a2 = $a2[$i];
  
   eval $xeq;
   if ($@) {die "Syntax error in x code: $@\n";}
   $x[$i] = $x; # build the array
#   print "xeq:$xeq, x:$x\n"; # debug

   eval $yeq;
   if ($@) {die "Syntax error in y code: $@\n";}
   $y[$i] = $y; # build the array

   eval $zeq;
   if ($@) {die "Syntax error in z code: $@\n";}
   $z[$i] = $z; # build the array

   eval $ceq;
   if ($@) {die "Syntax error in c code: $@\n";}
   $c[$i] = $c; # build the array

  } # for-loop eval - not as slow as warned by book

 # print "X array: @x\n"; # debug
}

####################
####################


############################################################
####################  Event Handlers #######################
############################################################

# we get here when a file has been chosen to open
sub on_filechooser_file_set
{ # slurp up the file, parse it into plot arrays
 my $diodecal = (2.46/5.0) * 65535; #@@@ should come from a config file?
 my $curindex = 0;
 my @cfields; # place to hold a split line 
 my $h; # for breaking up time
 my $m;
 my $s;
 my $csec; # current second after conversion
 
 $filepath = $filechooser->get_filename(); # file to open
 print "file chosen:$filepath\n";
 resetdata(); # clear out file and plot arrays, cal
 #@@@ clear status bar here?
 open (LOG, "< $filepath") or die "couldn't open datafile:$filepath: $!"; # debug
# now, slurp up the file and fill the arrays with the content
 while (<LOG>) # for each line in file
 {
  if ($_ =~ m/#/)
  {
   #print ("comment:$_");
#   $statusbar->set_text("in-file comment:$_"); # show in status bar
   chop;
   $statusbar->push(1," in-file comment:$_"); # show in status bar

   next; # just grab the comment, then look for real data
  } # end if comment line
 # now, assume valid line and do our thing on it
  @cfields = split(/\s+/); # break on whitespace

  # figure out total seconds
  ($h,$m,$s) = split(/:/,$cfields[0]); # break up time and calculate total seconds
  $csec = $s + 60 * $m + 3600 * $h; # assuming 60 sec/min and so on

  #@cfields = @cfields[2,6,10,12,14,16]; # strip off all labels via array slice
  $c0[$curindex] = $cfields[2]; # counter 0
  $c1[$curindex] = $cfields[6]; # counter 1
  $a0[$curindex] = $cfields[10]; # a/d ch 0
  $a1[$curindex] = $cfields[12]; # a/d ch 1
  $a2[$curindex] = $cfields[14]; # a/d ch 2
  $cal += $cfields[16]; # build up calibration sum for average
  $T[$curindex++] = $csec; # elapsed seconds
 
 } # end while LOG 
 $cal /= $curindex; # now have average a/d for cal diode
 $cal = $diodecal / $cal; # make into a multiplier for a/d channel counts
 print "cal:$cal\n"; # debug
 close (LOG) or die "Couldn't close log file $!";
 
 $makeplot->set_sensitive(TRUE); # we've opened a file to plot
}
####################
sub on_savepre_clicked
{
 my $hashref;
 my $name = $presetcombo->get_active_text(); # preset name
 #@@@ add test here for valid name
 
 print "\nsavepre clicked\n";
 # add stuff to hash and store it on disk for later
 $hashref = { # get the junk out of the text boxes etc
 name => "$name",
 xeq =>  $xedit->get_text(),
 yeq =>  $yedit->get_text(),
 zeq =>  $zedit->get_text(),
 ceq =>  $cedit->get_text(),
 xlabel => $xlabel->get_text(),
 ylabel => $ylabel->get_text(),
 zlabel => $zlabel->get_text(),
 clabel => $clabel->get_text(),
 logx =>  $logxc->get_active() ? TRUE:FALSE,
 logy => $logyc->get_active() ? TRUE:FALSE,
 logz => $logzc->get_active() ? TRUE:FALSE,
 logc => $logcc->get_active() ? TRUE:FALSE
 }; # end anon hash build
 $presets {$name} = $hashref; # add it to the presets
 store (\%presets,$prepath); # save it to disk
 
 printpresets();
 setupcombo(); # re-sync combo box with presets data
 
}
####################
sub on_delpre_clicked
{
 my $name = $presetcombo->get_active_text(); # preset name
 print "\nremoving preset:$name\n";
 delete($presets{$name}); # do the deed
 store (\%presets,$prepath); # save it to disk
# $presetcombo->set_active(0); # select something, create event
 printpresets();
 setupcombo();
}

####################
sub on_preset_changed
{
my $index;
my $itext;
my $href;

 $index = $presetcombo->get_active(); # returns -1 for typing in box, handy
 $itext = $presetcombo->get_active_text();
 print "\npreset changed:$index, text:$itext\n";
 if (-1 < $index) # then it's a real selection, not just typing in the box
 {# get values into other controls from the hash entry
 
 print "\nThere was a real selection in on_preset_changed:$itext\n";
 $href = $presets{$itext};
# so, do something about that - load up the gui 

 $xedit->set_text($href->{xeq});
 $yedit->set_text($href->{yeq});
 $zedit->set_text($href->{zeq});
 $cedit->set_text($href->{ceq});
 $xlabel->set_text($href->{xlabel});
 $ylabel->set_text($href->{ylabel});
 $zlabel->set_text($href->{zlabel});
 $clabel->set_text($href->{clabel});
 $logxc->set_active($href->{logx} ? TRUE:FALSE);
 $logyc->set_active($href->{logy} ? TRUE:FALSE);
 $logzc->set_active($href->{logz} ? TRUE:FALSE);
 $logcc->set_active($href->{logc} ? TRUE:FALSE);
 
 
 } # end if real selection
 
}
####################

####################
sub gnuplot_cmd {  #swiped from gnuplotif and modified
    my  (@commands)  = @_;
    @commands = map {$_."\n"} @commands;
    print $gplot @commands
        or die "Couldn't write to pipe: $!";
#        print @commands; # debug

} # ----------  end of subroutine gnuplot_cmd  ----------
####################
sub on_doplot_clicked
{
 my ($xlab,$ylab,$zlab,$clab,$style);
 my ($logx,$logy,$logz,$logc);
 my $i;
 
# print "\non doplot clicked\n";
 
 $xlab = $xlabel->get_text();
 $ylab = $ylabel->get_text();
 $zlab = $zlabel->get_text();
 $clab = $clabel->get_text();

 $logx = $logxc->get_active();
 $logy = $logyc->get_active();
 $logz = $logzc->get_active();
 $logc = $logzc->get_active();


#print ("xlab:$xlab\n");

 $style = 'points'; #@@@ make dynamic later
 
 map_plot(); # map raw data onto plot desired via eval
 print "\n mapping done \n";
 
 #now, lets try some stuff and see if we can get a plot going

 open ($gplot, '|- ', "gnuplot 2> /dev/null") # plot_err_log.txt
                or die "\n$0 : failed to open pipe to \"gnuplot\" : $!\n";
 $gplot->autoflush(1); # duh, required!
                
                # various experiments that don't work yet, commented out
# gnuplot_cmd ("plot '-' with lines\n"); # try sending a command
# gnuplot_cmd( join( "\n", @z), 'e' );
# gnuplot_cmd("set dgrid3d 50,50");
# gnuplot_cmd("set hidden3d");
# gnuplot_cmd("set style fill transparent solid 0.2 noborder");

 gnuplot_cmd("set xlabel \"$xlab\""); # gnuplot requires quotes on the label
 gnuplot_cmd("set ylabel \"$ylab\"");  # hence the strange escapes here
 gnuplot_cmd("set zlabel \"$zlab\"");
 gnuplot_cmd("set title \"$clab\"");
 gnuplot_cmd ("set grid"); # show a grid
 
 if ($logx){gnuplot_cmd("set log x");}
 if ($logy){gnuplot_cmd("set log y");}
 if ($logz){gnuplot_cmd("set log z");}

 gnuplot_cmd("set pm3d"); # add palette mapping for 4th dimension
 gnuplot_cmd("splot '-' u 1:2:3:4 title '4D' lc palette z with points\n"); #4-d
 # null title avoids spurious "- + + +" on screen
 # tell gnuplot some stuff, and tell it input is coming in as STDIN, then
 # shove data to gnuplot on it's STDIN
 foreach $i (0..$#x)  # assumes X axis' number of points total 
 { # most of the rest of this program was written to make this line this simple
  gnuplot_cmd ("$x[$i] $y[$i] $z[$i] $c[$i]"); # So, hard to change, eh?
 }
 gnuplot_cmd('e'); # say we're done; take it away, gnuplot!
} # go look at the plot and have some fun



##################################################################
#################################  Main Code  ####################
##################################################################

creategui(); # use the embedded xml to create the gui and hook up subs
getwidgetpointers(); # get pointers to the program's UI stuff
$filepath = getmypath(); # where we are - abs path - base dir for all other files
$prepath = catfile($filepath,'.plotdpresets'); # put together opsys-independent
# and oh yes, assume we're in this dir for the file picker - might be handy
chdir ("$filepath") or die "Can't change work dir to $filepath $!";
#print "running from: $filepath \n";  # debug
setupcombo(); # setup combo box for presets


# Enter the event loop
Gtk2->main; # make events work
# we die when the above exits
# do any cleanup or saving of presets here
close ($gplot) if ($gplot); # might as well...
store (\%presets,$prepath); # save presets to disk
#print "\nGui exit\n"; # debug

##################################################################
################################# End Main Code  #################
##################################################################



__END__  # we've put the glade xml file data here and read it from within - so if you change the glade...change this
<?xml version="1.0"?>
<glade-interface>
  <!-- interface-requires gtk+ 2.16 -->
  <!-- interface-naming-policy project-wide -->
  <widget class="GtkWindow" id="MainWin">
    <property name="visible">True</property>
    <property name="tooltip" translatable="yes">Data plotter for sdaq data logs</property>
    <property name="title" translatable="yes">sdaq data plotter</property>
    <property name="default_width">440</property>
    <property name="default_height">250</property>
    <signal name="destroy" handler="gtk_main_quit"/>
    <signal name="destroy_event" handler="gtk_main_quit" after="yes"/>
    <child>
      <widget class="GtkVBox" id="vbox1">
        <property name="visible">True</property>
        <child>
          <widget class="GtkHBox" id="hbox1">
            <property name="visible">True</property>
            <child>
              <widget class="GtkLabel" id="filelabel">
                <property name="visible">True</property>
                <property name="label" translatable="yes">Choose a file to plot --&gt;</property>
              </widget>
              <packing>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <widget class="GtkFileChooserButton" id="filechooser">
                <property name="visible">True</property>
                <property name="has_tooltip">True</property>
                <property name="tooltip" translatable="yes">Choose a file to plot</property>
                <property name="border_width">3</property>
                <property name="create_folders">False</property>
                <signal name="file_set" handler="on_filechooser_file_set"/>
              </widget>
              <packing>
                <property name="padding">1</property>
                <property name="position">1</property>
              </packing>
            </child>
          </widget>
          <packing>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <widget class="GtkLabel" id="eqhelp">
            <property name="visible">True</property>
            <property name="label" translatable="yes">Equations to map data to plot axes, Perl syntax
Sources $T (seconds), $c0, $c1, $a0, $a1, $a2,$cal.
Destinations $x, $y, $z, $c (color)
$i (loop index) and $scr1-3 are also available.
Loop over dataset is implied.</property>
          </widget>
          <packing>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <widget class="GtkHBox" id="hbox3">
            <property name="visible">True</property>
            <child>
              <widget class="GtkLabel" id="label2">
                <property name="visible">True</property>
                <property name="label" translatable="yes">X Axis</property>
              </widget>
              <packing>
                <property name="expand">False</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <widget class="GtkEntry" id="xeq">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="tooltip" translatable="yes">Perl code to eval for X axis</property>
                <property name="invisible_char">&#x25CF;</property>
                <property name="text" translatable="yes">@x = @a0;</property>
              </widget>
              <packing>
                <property name="position">1</property>
              </packing>
            </child>
          </widget>
          <packing>
            <property name="position">2</property>
          </packing>
        </child>
        <child>
          <widget class="GtkHBox" id="hbox4">
            <property name="visible">True</property>
            <child>
              <widget class="GtkLabel" id="label3">
                <property name="visible">True</property>
                <property name="label" translatable="yes">Y Axis</property>
              </widget>
              <packing>
                <property name="expand">False</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <widget class="GtkEntry" id="yeq">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="tooltip" translatable="yes">Y axis equation</property>
                <property name="invisible_char">&#x25CF;</property>
                <property name="text" translatable="yes">@y = @a1;</property>
              </widget>
              <packing>
                <property name="position">1</property>
              </packing>
            </child>
          </widget>
          <packing>
            <property name="position">3</property>
          </packing>
        </child>
        <child>
          <widget class="GtkHBox" id="hbox5">
            <property name="visible">True</property>
            <child>
              <widget class="GtkLabel" id="label4">
                <property name="visible">True</property>
                <property name="label" translatable="yes">Z Axis</property>
              </widget>
              <packing>
                <property name="expand">False</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <widget class="GtkEntry" id="zeq">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="tooltip" translatable="yes">Z axis equation</property>
                <property name="invisible_char">&#x25CF;</property>
                <property name="text" translatable="yes">@z = @c1;</property>
              </widget>
              <packing>
                <property name="position">1</property>
              </packing>
            </child>
          </widget>
          <packing>
            <property name="position">4</property>
          </packing>
        </child>
        <child>
          <widget class="GtkHBox" id="hbox7">
            <property name="visible">True</property>
            <child>
              <widget class="GtkLabel" id="label5">
                <property name="visible">True</property>
                <property name="label" translatable="yes">C axis</property>
              </widget>
              <packing>
                <property name="expand">False</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <widget class="GtkEntry" id="ceq">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="tooltip" translatable="yes">Color axis equation</property>
                <property name="invisible_char">&#x25CF;</property>
                <property name="text" translatable="yes">@c = @a2;</property>
              </widget>
              <packing>
                <property name="position">1</property>
              </packing>
            </child>
          </widget>
          <packing>
            <property name="position">5</property>
          </packing>
        </child>
        <child>
          <widget class="GtkTable" id="table1">
            <property name="visible">True</property>
            <property name="border_width">3</property>
            <property name="n_rows">3</property>
            <property name="n_columns">5</property>
            <child>
              <widget class="GtkLabel" id="label8">
                <property name="visible">True</property>
                <property name="label" translatable="yes">Axis -&gt;</property>
              </widget>
            </child>
            <child>
              <widget class="GtkLabel" id="label9">
                <property name="visible">True</property>
                <property name="label" translatable="yes">X</property>
              </widget>
              <packing>
                <property name="left_attach">1</property>
                <property name="right_attach">2</property>
              </packing>
            </child>
            <child>
              <widget class="GtkLabel" id="label10">
                <property name="visible">True</property>
                <property name="label" translatable="yes">Y</property>
              </widget>
              <packing>
                <property name="left_attach">2</property>
                <property name="right_attach">3</property>
              </packing>
            </child>
            <child>
              <widget class="GtkLabel" id="label11">
                <property name="visible">True</property>
                <property name="label" translatable="yes">Z</property>
              </widget>
              <packing>
                <property name="left_attach">3</property>
                <property name="right_attach">4</property>
              </packing>
            </child>
            <child>
              <widget class="GtkLabel" id="label12">
                <property name="visible">True</property>
                <property name="label" translatable="yes">C</property>
              </widget>
              <packing>
                <property name="left_attach">4</property>
                <property name="right_attach">5</property>
              </packing>
            </child>
            <child>
              <widget class="GtkLabel" id="label13">
                <property name="visible">True</property>
                <property name="label" translatable="yes">Label</property>
              </widget>
              <packing>
                <property name="top_attach">1</property>
                <property name="bottom_attach">2</property>
              </packing>
            </child>
            <child>
              <widget class="GtkEntry" id="XLabel">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="tooltip" translatable="yes">X axis plot label</property>
                <property name="invisible_char">&#x25CF;</property>
              </widget>
              <packing>
                <property name="left_attach">1</property>
                <property name="right_attach">2</property>
                <property name="top_attach">1</property>
                <property name="bottom_attach">2</property>
              </packing>
            </child>
            <child>
              <widget class="GtkEntry" id="YLabel">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="tooltip" translatable="yes">Y axis plot label</property>
                <property name="invisible_char">&#x25CF;</property>
              </widget>
              <packing>
                <property name="left_attach">2</property>
                <property name="right_attach">3</property>
                <property name="top_attach">1</property>
                <property name="bottom_attach">2</property>
              </packing>
            </child>
            <child>
              <widget class="GtkEntry" id="ZLabel">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="tooltip" translatable="yes">Z axis plot label</property>
                <property name="invisible_char">&#x25CF;</property>
              </widget>
              <packing>
                <property name="left_attach">3</property>
                <property name="right_attach">4</property>
                <property name="top_attach">1</property>
                <property name="bottom_attach">2</property>
              </packing>
            </child>
            <child>
              <widget class="GtkEntry" id="CLabel">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="tooltip" translatable="yes">C axis plot label</property>
                <property name="invisible_char">&#x25CF;</property>
              </widget>
              <packing>
                <property name="left_attach">4</property>
                <property name="right_attach">5</property>
                <property name="top_attach">1</property>
                <property name="bottom_attach">2</property>
              </packing>
            </child>
            <child>
              <widget class="GtkLabel" id="label14">
                <property name="visible">True</property>
                <property name="label" translatable="yes">Log?</property>
              </widget>
              <packing>
                <property name="top_attach">2</property>
                <property name="bottom_attach">3</property>
              </packing>
            </child>
            <child>
              <widget class="GtkCheckButton" id="logx">
                <property name="label" translatable="yes">Log X?</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">False</property>
                <property name="tooltip" translatable="yes">Log X axis?</property>
                <property name="xalign">0.56999999284744263</property>
                <property name="draw_indicator">True</property>
              </widget>
              <packing>
                <property name="left_attach">1</property>
                <property name="right_attach">2</property>
                <property name="top_attach">2</property>
                <property name="bottom_attach">3</property>
              </packing>
            </child>
            <child>
              <widget class="GtkCheckButton" id="logy">
                <property name="label" translatable="yes">Log Y?</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">False</property>
                <property name="tooltip" translatable="yes">Log Y axis?</property>
                <property name="draw_indicator">True</property>
              </widget>
              <packing>
                <property name="left_attach">2</property>
                <property name="right_attach">3</property>
                <property name="top_attach">2</property>
                <property name="bottom_attach">3</property>
              </packing>
            </child>
            <child>
              <widget class="GtkCheckButton" id="logz">
                <property name="label" translatable="yes">Log Z?</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">False</property>
                <property name="tooltip" translatable="yes">Log Z axis?</property>
                <property name="draw_indicator">True</property>
              </widget>
              <packing>
                <property name="left_attach">3</property>
                <property name="right_attach">4</property>
                <property name="top_attach">2</property>
                <property name="bottom_attach">3</property>
              </packing>
            </child>
            <child>
              <widget class="GtkCheckButton" id="logc">
                <property name="label" translatable="yes">Log C?</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">False</property>
                <property name="tooltip" translatable="yes">Log C axis?</property>
                <property name="draw_indicator">True</property>
              </widget>
              <packing>
                <property name="left_attach">4</property>
                <property name="right_attach">5</property>
                <property name="top_attach">2</property>
                <property name="bottom_attach">3</property>
              </packing>
            </child>
          </widget>
          <packing>
            <property name="position">6</property>
          </packing>
        </child>
        <child>
          <widget class="GtkHSeparator" id="hseparator1">
            <property name="visible">True</property>
          </widget>
          <packing>
            <property name="expand">False</property>
            <property name="position">7</property>
          </packing>
        </child>
        <child>
          <widget class="GtkHBox" id="hbox2">
            <property name="visible">True</property>
            <child>
              <widget class="GtkLabel" id="presetlabel">
                <property name="visible">True</property>
                <property name="tooltip" translatable="yes">Select existing or name new preset</property>
                <property name="label" translatable="yes">Select preset:</property>
              </widget>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <widget class="GtkComboBoxEntry" id="preset">
                <property name="visible">True</property>
                <property name="tooltip" translatable="yes">Select a preset or name a new one.</property>
                <property name="items" translatable="yes"></property>
                <signal name="changed" handler="on_preset_changed"/>
              </widget>
              <packing>
                <property name="position">1</property>
              </packing>
            </child>
            <child>
              <widget class="GtkButton" id="savepre">
                <property name="label" translatable="yes">Save Preset</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="tooltip" translatable="yes">Save a new preset</property>
                <signal name="clicked" handler="on_savepre_clicked"/>
              </widget>
              <packing>
                <property name="expand">False</property>
                <property name="position">2</property>
              </packing>
            </child>
            <child>
              <widget class="GtkButton" id="delpre">
                <property name="label" translatable="yes">Delete Preset</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <signal name="clicked" handler="on_delpre_clicked"/>
              </widget>
              <packing>
                <property name="expand">False</property>
                <property name="position">3</property>
              </packing>
            </child>
          </widget>
          <packing>
            <property name="position">8</property>
          </packing>
        </child>
        <child>
          <widget class="GtkHSeparator" id="hseparator2">
            <property name="visible">True</property>
          </widget>
          <packing>
            <property name="expand">False</property>
            <property name="position">9</property>
          </packing>
        </child>
        <child>
          <widget class="GtkLabel" id="space">
            <property name="visible">True</property>
            <property name="label" translatable="yes"> </property>
          </widget>
          <packing>
            <property name="position">10</property>
          </packing>
        </child>
        <child>
          <placeholder/>
        </child>
        <child>
          <placeholder/>
        </child>
        <child>
          <placeholder/>
        </child>
        <child>
          <widget class="GtkHBox" id="hbox6">
            <property name="visible">True</property>
            <child>
              <widget class="GtkLabel" id="botlabel">
                <property name="visible">True</property>
                <property name="label" translatable="yes">The bottom line:</property>
              </widget>
              <packing>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
              <widget class="GtkButton" id="doplot">
                <property name="label" translatable="yes">Make Plot</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="has_tooltip">True</property>
                <property name="tooltip" translatable="yes">Create a new plot</property>
                <property name="xalign">0.52999997138977051</property>
                <signal name="clicked" handler="on_doplot_clicked"/>
              </widget>
              <packing>
                <property name="expand">False</property>
                <property name="position">3</property>
              </packing>
            </child>
          </widget>
          <packing>
            <property name="position">14</property>
          </packing>
        </child>
        <child>
          <widget class="GtkStatusbar" id="statusbar">
            <property name="visible">True</property>
            <property name="has_tooltip">True</property>
            <property name="tooltip" translatable="yes">Log File comments</property>
            <property name="spacing">2</property>
          </widget>
          <packing>
            <property name="expand">False</property>
            <property name="position">15</property>
          </packing>
        </child>
      </widget>
    </child>
  </widget>
</glade-interface>
