gtkhistory.g - The History program in GTK

Cogent Tools Demo and Tutorials: Version 4.0
Prev | Chapter 3. View the Code | Next

# 3.10. `gtkhistory.g` - The History program in GTK

    /*--------------------------------------------------------------------
     * File:         gtkhistory.g
     *
     * Description:  Demonstrates the Cascade Historian
     *
     * Functions and methods by category
     *
     * Interpolator: InterpolatorSettings.change_int
     *               InterpolatorSettings.assign_values
     *               InterpolatorSettings.get_data
     * Query:        allow_entry_values
     *               countdown
     *               record_data
     *               reset_deadbands
     *               plot_prep
     *               send_query
     *               write_minmax
     *               file_add
     *               show_data
     * Deadbanding:  db_options
     *               db_labels
     *               create_dbtype_win
     * Window:       make_toggle_button
     *               qry_radio_but
     *               qry_entry
     *               create_history
     * Main:         main
     *------------------------------------------------------------------*/

    /********************************************************
     *               GENERAL UTILITY Code                   *
     ********************************************************/

    /* Get access to the library of common functions. */
    require("lib/common.g");

    /* Keep track of all child processes that this process has started. */
    Children := nil;

    /********************************************************
     *                  INTERPOLATOR Code                   *
     ********************************************************/

    /*--------------------------------------------------------------------
     * Method:      InterpolatorSettings.change_int
     * Returns:     t or nil
     * Description: Responding to a click on a "Choose an Interpolator"
     *              radio button, this method calls the allow_entry_values()
     *              function on the active button.  The callback is set up
     *              in qry_radio_but().
     *------------------------------------------------------------------*/
    method InterpolatorSettings.change_int(button, str, w1, w2, w3, e1, e2, e3)
    {
      if (button.switched_on())
        {
          .fn = str;
          allow_entry_values(w1, w2, w3, e1, e2, e3);
        }
    }

    /*--------------------------------------------------------------------
     * Method:      InterpolatorSettings.assign_values
     * Returns:     t or nil
     * Description: Assigns the values from the interpolator entry widgets
     *              to the appropriate instance variables of the class.
     *              Called by send_query().
     *------------------------------------------------------------------*/
    method InterpolatorSettings.assign_values(e1, e2, e3, e4, e5, e6)
    {
      .y_history = assign_history(.dbflag, .y_history, e1.get_text());
      .start = number(e2.get_text());
      .duration = number(e3.get_text());
      .x_history =  assign_history(.dbflag, .x_history, e4.get_text());
      .interval = number(e5.get_text());
      .max_gap = number(e6.get_text());
    }

    /*--------------------------------------------------------------------
     * Method:      InterpolatorSettings.get_data
     * Returns:     a list of two lists
     * Description: Sends the query and retrieves the data.  Activated by
     *              the send_query() function.
     *------------------------------------------------------------------*/
    method InterpolatorSettings.get_data(e1, e2, e3, e4, e5, e6, e7)
    {
      local tsk, intpl, buf_length, alldata, count, dur, data, outfile;
      local xdata = list();
      local ydata = list();
      local midnite = find_midnite();

      /* Make sure there are valid values in the entry widgets.*/
      if (undefined_p(.start) || (!number_p(.start)))
        {
          .start = 0;
          e2.set_text("0");
        }
      if (undefined_p(.duration) || (!number_p(.duration))
          || (.duration <= 0))
        {
          .duration = 10;
          e3.set_text("10");
        }
      if (undefined_p(.interval) || (!number_p(.interval))
          || (.interval < .01))
        {
          .interval = .01;
          e5.set_text("0.01");
        }

      if ((tsk = locate_task("demohistdb", nil)) != nil)
        {
          alldata = list();
          count = 0;
          intpl = self.set_interpolator(tsk);
          buf_length = caddr(send(tsk, `bufferIdLength(intpl)));
          if(!((.fn == "TimeSetup") || (.fn == "RelSetup")))
            e7.set_text(string(buf_length));

          while (count < buf_length)
            {
              if((buf_length - count) > 100)
                dur = 100;
              else
                dur = buf_length - count;
              data = send(tsk, `bufferIdDataAscii(intpl, @count, @dur));
              data = cddr(cdr(data));
              alldata = append(alldata, data);
              count = count + 100;
            }

          if(.dbflag == "NONE")
            outfile = open("/tmp/cogentdemo/hsoutput.dat", "w");
          if(.dbflag == "DB")
            outfile = open("/tmp/cogentdemo/hsoutput2.dat", "w");
          if(.dbflag == "DBP")
            outfile = open("/tmp/cogentdemo/hsoutput3.dat", "w");
          if (outfile)
            if (buf_length == 0)
              {
                writec(outfile, "# Sorry, no data matched your query.");
                writec(outfile, string("\n", midnite, " 0",
                                       "\n", (midnite + 1), " 0"));
                close(outfile);
              }
            else
              {
                with d in alldata do
                  writec(outfile, string(car(d), " ", cadr(d), "\n"));
                close(outfile);
              }

          while (alldata != nil)
            {
              if(.fn == "TimeSetup" ||
                 .fn == "NoInterpolator" || .fn == "Periodic")
                xdata = cons(caar(alldata) - midnite, xdata);
              else
                xdata = cons(caar(alldata), xdata);
              ydata = cons(cadar(alldata), ydata);
              alldata = cdr(alldata);
            }
          xdata = reverse(xdata);
          ydata = reverse(ydata);
          send(tsk, #bufferIdDestroy(intpl));
        }
      list(xdata, ydata);
    }

    /********************************************************
     *                      QUERY Code                      *
     ********************************************************/

    /*--------------------------------------------------------------------
     * Function:    allow_entry_values
     * Returns:     t or nil
     * Description: Sets the three optional parameter entry widgets
     *              (X history, Time Interval, and Max. gap) sensitive or
     *              non-sensitive.  Called by qry_radio_but() and
     *              InterpolatorSettings.change_int().  The possible values
     *              for e1 - e3 are 0 (FALSE) or 1 (TRUE).
     *------------------------------------------------------------------*/
    function allow_entry_values(w1, w2, w3, e1, e2, e3)
    {
      w1.set_sensitive(e1);
      w2.set_sensitive(e2);
      w3.set_sensitive(e3);
    }

    /*--------------------------------------------------------------------
     * Function:    countdown
     * Returns:     t or nil
     * Description: Called by record_data() to do the time count-down.
     *------------------------------------------------------------------*/
    function countdown(txt_wgt, time)
    {
      txt_wgt.set_point(42);
      txt_wgt.forward_delete(txt_wgt.get_length() - 42);
      txt_wgt.insert(FONT, nil, nil, string(time - clock()), -1);
    }

    /* Assign a global variable for recording time, and a font. */
    RECORD_TIME = 5;
    FONT = gdk_font_load ("-adobe-courier-medium-r-normal--*-120-*-*-*-*-*-*");

    /*--------------------------------------------------------------------
     * Function:    record_data
     * Returns:     t or nil
     * Description: Records data for the specified time, then sends a query.
     * Arguments:   button:       The Record button
     *              iset:         An InterpolatorSettings instance
     *              e1 - e6:      The six Interpolator options entry widgets
     *              e7:           The "Number of points from last query" display
     *              but_db1 - 3:  The three Deadband options buttons
     *              b1 - b4:      The four Interpolator options buttons
     *              b6:           The Update display button
     *------------------------------------------------------------------*/
    function record_data(button, iset, but_db1, but_db2, but_db3, text,
                         e1, e2, e3, e4, e5, e6, e7, b1, b2, b3, b4, b6)
    {
      if (button.switched_on())
        {
          local time = clock() + RECORD_TIME;
          text.backward_delete(text.get_length());
          text.insert(FONT, nil, nil,
                      (string("Recording,please wait.\nSeconds remaining: ", RECORD_TIME)),
                      -1);
          numtimer = every (1, `countdown(@text, @time));

          e3.set_text(string(RECORD_TIME + 1));
          iset.set_defaults(button, e2);
          send_hs_command(button, "enable", e1.get_text(), nil);

          after(RECORD_TIME, `(@button).set_active(FALSE));
          after((RECORD_TIME + .1), `(send_hs_command(@button, "enable",
                                                      (@e1).get_text(), nil)));
          after((RECORD_TIME + .1), `(cancel(numtimer)));
          after((RECORD_TIME + .15),
                `(reset_deadbands(nil, @iset, @but_db1, @but_db2, @but_db3, @text,
                                  @e1, @e2, @e3, @e4, @e5, @e6, @e7, @b1,
                                  @b2, @b3, @b4, @button, @b6)));
        }
    }

    /*--------------------------------------------------------------------
     * Function:    reset_deadbands
     * Returns:     t or nil
     * Description: Clears all traces and sets the Full data set (no deadband)
     *              option.  Called when non-deadband buttons are activated.
     *------------------------------------------------------------------*/
    function reset_deadbands(button, iset, but1, but2, but3, text, e1, e2,
                             e3, e4, e5, e6, e7, b1, b2, b3, b4, b5, b6)
    {
      but2.set_active(FALSE);
      but3.set_active(FALSE);
      but1.set_active(TRUE);
      if(is_file("/tmp/cogentdemo/hsoutput2.dat"))
          unlink("/tmp/cogentdemo/hsoutput2.dat");
      if(is_file("/tmp/cogentdemo/hsoutput3.dat"))
          unlink("/tmp/cogentdemo/hsoutput3.dat");
      plot_prep(but1, iset, but1, but2, but3, text, e1, e2,
                e3, e4, e5, e6, e7, b1, b2, b3, b4, b5, b6);
    }

    /*--------------------------------------------------------------------
     * Function:    plot_prep
     * Returns:     t or nil
     * Description: Writes to the plhistsetup.dat file the relevant values
     *              for the time of midnight, x-axis label, and deadband
     *              status.
     *------------------------------------------------------------------*/
    function plot_prep (button, iset, but_db1, but_db2, but_db3, text,
                        e1, e2, e3, e4, e5, e6, e7, b1, b2, b3, b4, b5, b6)
    {
      local fp, histtime, line;

      /* Write the time. */
      fp = open("/tmp/cogentdemo/plhistsetup.dat", "w", nil);
      histtime = find_midnite();
      line = string("histtime = ", histtime, "\n");
      writec(fp, line);

      /* Set up the X-axis label. */
      if ((iset.fn == "NoInterpolator") || (iset.fn == "Periodic"))
        line = "xlab = 1\n";
      else line = "xlab = 2\n";
      writec(fp, line);

      /* Set the deadband flag in the InterpolatorSettings instance. */
      if(button.switched_on() && button == but_db1)
        iset.dbflag = "NONE";
      if(button.switched_on() && button == but_db2)
        iset.dbflag = "DB";
      if(button.switched_on() && button == but_db3)
        iset.dbflag = "DBP";

      /* Write the on or off value for each deadband. */
      if (but_db1.switched_on())
        line = "db1 = 1\n";
      else line = "db1 = 0\n";
      writec(fp, line);

      if (but_db2.switched_on())
        line = "db2 = 1\n";
      else line = "db2 = 0\n";
      writec(fp, line);

      if (but_db3.switched_on())
        line = "db3 = 1\n";
      else line = "db3 = 0\n";
      writec(fp, line);

      close(fp);

      send_query(button, iset, text, e1, e2, e3, e4,
                 e5, e6, e7, b1, b2, b3, b4, b5, b6);
    }

    /*--------------------------------------------------------------------
     * Function:    send_query
     * Returns:     t or nil
     * Description: Calls the necessary functions to send a query to the
     *              Historian, and handle the data returned.  It is activated
     *              by the "Record" button popping out, or any radio button.
     *              It sends two queries, the first to calculate the minimum
     *              and maximum values for use in creating plots, and the
     *              second to get the actual data.
     * Arguments:   button:       The button that activated the function
     *              iset:         An InterpolatorSettings instance
     *              e1 - e6:      The six Interpolator options entry widgets
     *              e7:           The "Number of points from last query" display
     *              b1 - b4:      The four Interpolator options buttons
     *              b5:           The Record button
     *              b6:           The Update display button
     *------------------------------------------------------------------*/
    function send_query(button, iset, text, e1, e2, e3, e4,
                        e5, e6, e7, b1, b2, b3, b4, b5, b6)
    {
      local fnholder, datalist, minmaxlist;
      if ((button == nil) || (button == b6) || (button.switched_on()))
        {
          if ((button == b1 || button == b2 ||
               button == b3 || button == b4 ||
               button == b5 || button == b6))
            iset.dbflag = "NONE";

          iset.assign_values(e1, e2, e3, e4, e5, e6);

          datalist = list();
          fnholder = iset.fn;

          /* Assign a name for the setup query. */
          if ((iset.fn == "NoInterpolator") || (iset.fn == "Periodic"))
            iset.fn = "TimeSetup";
          else
            iset.fn = "RelSetup";

          /* Make the setup query and assign minimum and maximum values. */
          datalist = iset.get_data(e1, e2, e3, e4, e5, e6, e7);
          if (car(datalist) && cadr(datalist))
            minmaxlist = list(min_max(car(datalist)), min_max(cadr(datalist)));
          else
            minmaxlist = nil;

          /* Make the actual query. */
          iset.fn = fnholder;
          datalist = iset.get_data(e1, e2, e3, e4, e5, e6, e7);
          show_data(text, iset, button, datalist, minmaxlist);
        }
      else
        {
          write_minmax(iset.misc_info);
        }
    }

    /*--------------------------------------------------------------------
     * Function:    write_minmax
     * Returns:     t or nil
     * Description: Writes a string to the plhistsetup.dat file containing
     *              four lines, each line assigning a value for an X or Y axis
     *              minimum or maximum variable, which are used by gnuplot.
     *------------------------------------------------------------------*/
    function write_minmax(minmax_string)
    {
      local fp = open("/tmp/cogentdemo/plhistsetup.dat", "a", nil);
      writec(fp, minmax_string);
      close(fp);
    }

    /*--------------------------------------------------------------------
     * Function:    file_add
     * Returns:     t or nil
     * Description: Adds content from a file previously opened for reading
     *              (inptr) to a file previously opened for writing (outptr).
     *              Adds extra newlines, which gnuplot uses to mark the beginning
     *              of a new index file.  Called only by show_data().
     *------------------------------------------------------------------*/
    function file_add(inptr, outptr)
    {
      local line;
      while(line != _eof_)
        {
          line = read_line(inptr);
          if (line != "Unexpected end of file")
            writec(outptr, string(line, "\n"));
        }
      writec(outptr, "\n\n");
      close(inptr);
    }

    /*--------------------------------------------------------------------
     * Function:    show_data
     * Returns:     t or nil
     * Description: Shows interpolated query results from the Cascade Historian
     *              in the text widget.  Sets up a single file (hsoutputpl.dat)
     *              that contains the content of all existing hsoutput files.
     *              This is necessary because gnuplot must read from a single file.
     *              Uses file_add() to do the actual reading and writing of the files.
     *------------------------------------------------------------------*/
    function show_data(txt_wgt, int_set, button, datalist, minmaxlist)
    {
      local start_time, tsk, infile, line, string_list, line_ret;
      local title_string, x_list, y_list;
      local f1, f2, f3, f4;

      x_list = car(datalist);
      y_list = cadr(datalist);
      midnite = find_midnite();

      if (int_set.fn == "NoInterpolator"  || int_set.fn == "Periodic")
        {
          x_is_time = t;
          title_string = "Query results: \n     Time             Y History\n";
        }
      else
        {
          x_is_time = nil;
          title_string = "Query results: \nX-hist / Y-hist\n";
        }

      midnite = find_midnite();
      txt_wgt.freeze();
      txt_wgt.backward_delete(txt_wgt.get_length());
      txt_wgt.insert(FONT, nil, nil, title_string, -1);

      if(int_set.dbflag == "NONE")
        infile = open("/tmp/cogentdemo/hsoutput.dat", "r");
      if(int_set.dbflag == "DB")
        infile = open("/tmp/cogentdemo/hsoutput2.dat", "r");
      if(int_set.dbflag == "DBP")
        infile = open("/tmp/cogentdemo/hsoutput3.dat", "r");
      if (infile)
        {
          line = nil;
          while(line != _eof_)
            {
              line = read_line(infile);
              if (line != "Unexpected end of file")
                {
                  if ((strstr(line,"#") != -1))
                    {
                      txt_wgt.insert(FONT, nil, nil, line, -1);
                      read_line(infile);
                      read_line(infile);
                    }
                  else
                    {
                      string_list = string_split(line, " ", 2);
                      if (int_set.fn == "NoInterpolator"
                          || int_set.fn == "Periodic")
                        line_ret = string(number(car(string_list)) - midnite,
                                          " ", cadr(string_list),"\n");
                      else
                        line_ret = string(number(car(string_list)),
                                          " ", cadr(string_list),"\n");
                      txt_wgt.insert(FONT, nil, nil, line_ret, -1);
                    }
                }
            }
          close(infile);

          if(x_list && y_list && minmaxlist != nil)
            {
              if (x_is_time)
                {
                  x_min = caar(minmaxlist);
                  x_max = cadar(minmaxlist);
                }
              else
                {
                  x_min = floor(caar(minmaxlist));
                  x_max = ceil(cadar(minmaxlist));
                }
              y_min = floor(caadr(minmaxlist));
              y_max = ceil(car(cdadr(minmaxlist))) + 1;
              int_set.misc_info = string("x_min = ", x_min, "\n",
                                         "x_max = ", x_max, "\n",
                                         "y_min = ", y_min, "\n",
                                         "y_max = ", y_max, "\n");
              write_minmax(int_set.misc_info);
            }
        }
      txt_wgt.thaw();

      if(is_file("/tmp/cogentdemo/hsoutput.dat"))
        f1 = open("/tmp/cogentdemo/hsoutput.dat", "r");
      if(is_file("/tmp/cogentdemo/hsoutput2.dat"))
        f2 = open("/tmp/cogentdemo/hsoutput2.dat", "r");
      if(is_file("/tmp/cogentdemo/hsoutput3.dat"))
        f3 = open("/tmp/cogentdemo/hsoutput3.dat", "r");
      f4 = open("/tmp/cogentdemo/hsoutputpl.dat", "w");

      if(f1)
        {
          file_add(f1, f4);
          if(f2)
            file_add(f2, f4);
          else
            /* Put in a spacer line so gnuplot starts a new plot. */
            writec(f4, "999 999\n\n\n");
          if(f3)
            file_add(f3, f4);
        }

      close(f4);
    }

    /********************************************************
     *               DEADBANDING Code                       *
     ********************************************************/

    /*--------------------------------------------------------------------
     * Function:    db_options
     * Returns:     t or nil
     * Description: Creates a GtkEntry widget and puts it into a table.
     *              The widget calls the update_value() function when it
     *              gets changed.
     *------------------------------------------------------------------*/
    function db_options(tbl, p_array, left, right)
    {
      local entry;

      for (i=0; i<=3; i++)
        {
          entry = new(GtkEntry);
          entry.width = 40;
          entry.set_text(string(p_array[i]));
          entry.signal("changed", `(@p_array)[@i] = number((@entry).get_text()));
          tbl.attach_defaults(entry, left, right, i + 2, i + 3);
        }
    }

    /*--------------------------------------------------------------------
     * Function:    db_labels
     * Returns:     t or nil
     * Description: Creates labels and puts them in a table.
     *------------------------------------------------------------------*/
    function db_labels(tbl, title, left, right, top, bottom)
    {
      local label;

      label = new(GtkLabel);
      label.set_text(title);
      tbl.attach_defaults(label, left, right, top, bottom);
    }

    /*--------------------------------------------------------------------
     * Function:    create_dbtype_win
     * Returns:     A GtkWindow, or a destroyed instance
     * Description: Creates the Deadband Type window.
     *------------------------------------------------------------------*/
    function create_dbtype_win (!point_list, button)
    {
      local db1, db2, db3, vbox, table, pa1, pa2, pa3;
      local label, separator, box2, abut, cbut, okbut;

      if (((undefined_p(win_db) || (win_db == nil))
           && (button.get_active() == TRUE)))
        {
          db1 = car(point_list);
          db2 = cadr(point_list);

          win_db = new (GtkWindow);
          send_message("6.50");
          win_db.signal ("destroy", #win_db = nil);
          win_db.title = "Deadband Type";
          win_db.set_uposition(20, 440);
          win_db.set_color(1, GTK_STATE_NORMAL, 0xdddddd);
          win_db.width = 500;

          table = gtk_table_new(7, 4, FALSE);
          table.border_width = 15;
          table.set_col_spacings(15);
          table.set_row_spacings(3);
          table.set_row_spacing(0, 10);
          table.set_row_spacing(3, 10);
          table.set_row_spacing(5, 10);

          db_labels(table, "Set up deadband types", 0, 4, 0, 1);
          db_labels(table, "MV", 1, 2, 1, 2);
          db_labels(table, "PV", 2, 3, 1, 2);

          db_labels(table, "Absolute:", 0, 1, 2, 3);
          db_labels(table, "Percent:", 0, 1, 3, 4);
          db_labels(table, "Time Limit:", 0, 1, 4, 5);
          db_labels(table, "Count Limit:", 0, 1, 5, 6);

          db_labels(table, string("Deadband range is set to this ",
                                  "value.                  "), 3, 4, 2, 3);
          db_labels(table, string("Range set to percent of last logged ",
                                  "value.          "), 3, 4, 3, 4);
          db_labels(table, string("The maximum time period to deadband.",
                                  "               "), 3, 4, 4, 5);
          db_labels(table, string("The max number of received values to",
                                  " deadband."), 3, 4, 5, 6);
          db_labels(table, string("Note: These settings don't take effect",
                                  " until the next record session."), 0, 4, 6, 7);

          pa1 = array(db1.absolute, db1.percent,
                      db1.timelimit, db1.countlimit);

          pa2 = array(db2.absolute, db2.percent,
                      db2.timelimit, db2.countlimit);

          db_options(table, pa1, 1, 2);
          db_options(table, pa2, 2, 3);

          vbox = new(GtkVBox);
          win_db.add(vbox);
          vbox.pack_start(table, TRUE, TRUE, 0);

          separator = new(GtkHSeparator);
          vbox.pack_start(separator, TRUE, TRUE, 0);

          box2 = new(GtkHButtonBox);
          box2.border_width = 10;
          box2.set_layout(GTK_BUTTONBOX_SPREAD);
          vbox.pack_start(box2, TRUE, TRUE, 0);

          cbut = new(GtkButton);
          cbut.label = "Cancel";
          cbut.signal("clicked", `(@button).set_active(FALSE));
          cbut.signal("clicked", `(@win_db).destroy());
          button_messages (cbut, "6.55", "6.50");
          box2.pack_start(cbut, TRUE, TRUE, 0);
          cbut.show();

          okbut = new(GtkButton);
          okbut.label = "OK";
          okbut.signal("clicked", `(@db1).set_parms(@okbut, @pa1));
          okbut.signal("clicked", `(@db2).set_parms(@okbut, @pa2));
          okbut.signal("clicked", `(@button).set_active(FALSE));
          okbut.signal("clicked", `(@win_db).destroy());
          button_messages (okbut, "6.56", "6.50");
          box2.pack_start(okbut, TRUE, TRUE, 0);
          okbut.show();

          win_db.signal("destroy", `(@button).set_active(FALSE));
          win_db.show_all();
          win_db;
        }
      else
          if(instance_p(win_db))
            win_db.destroy();
    }

    /********************************************************
     *               HISTORY WINDOW Code                    *
     ********************************************************/

    /*--------------------------------------------------------------------
     * Function:    make_toggle_button
     * Returns:     A GtkToggleButton
     * Description: Creates toggle buttons.
     *------------------------------------------------------------------*/
    function make_toggle_button(lbl, color)
    {
      local button;

      button = new(GtkToggleButton);
      button.label = lbl;
      button.set_color(1, GTK_STATE_NORMAL, color);
      button.set_color(1, GTK_STATE_PRELIGHT, (color + 0x111111));
      button.set_color(1, GTK_STATE_ACTIVE, (color - 0x111111));
      button;
    }

    /*--------------------------------------------------------------------
     * Function:    qry_radio_but
     * Returns:     A GtkRadioButton
     * Description: Creates the "Choose an Interpolator" radio buttons and
     *              puts them into a table.  The last 6 parameters simply
     *              get passed along to the allow_entry_values() function
     *              and the .change_int() method.
     *------------------------------------------------------------------*/
    function qry_radio_but(tbl, txt, butlist, int_set, msg,
                           top, bottom, w1, w2, w3, e1, e2, e3)
    {
      local button;
      button = gtk_radio_button_new_with_label(butlist, txt);
      if (txt == "NoInterpolator")
        {
          button.set_active(TRUE);
          allow_entry_values(w1, w2, w3, e1, e2, e3);
        }
      button.signal("clicked", `((@int_set).change_int(@button, @txt, @w1, @w2,
                                                        @w3, @e1, @e2, @e3)));
      button_messages (button, msg, "6");
      tbl.attach_defaults(button, 0, 1, top, bottom);
      button;
    }

    /*--------------------------------------------------------------------
     * Function:    qry_entry
     * Returns:     A GtkEntry or GtkCombo widget, as specified
     * Description: Creates a GtkEntry or GtkCombo widget, sets defaut values,
     *              and puts it into a table.
     *------------------------------------------------------------------*/
    function qry_entry(tbl, txt, value, top, bottom)
    {
      local box, label, entry, cbitems, cmb, ent_but = nil;

      box = new(GtkHBox);
      label = new(GtkLabel);
      label.set_text(txt);
      label.width = 80;
      box.pack_start(label, TRUE, TRUE, 0);

      if ((strstr(txt, "history")) == -1)
        {
          entry = new(GtkEntry);
          entry.width = 75;
          if (value == nil)
            entry.set_text("");
          else
            entry.set_text(string(value));
          box.pack_start(entry, TRUE, TRUE, 0);
        }
      else
        {
          cbitems = list("MV_001", "PV_001");
          cmb = new(GtkCombo);
          cmb.width = 75;
          cmb.use_arrows = 0;
          cmb.set_popdown_strings(cbitems);
          entry = car(cmb.children());
          ent_but = cadr(cmb.children());
          entry.set_editable(FALSE);
          if (value == nil)
            entry.set_text("");
          else
            entry.set_text(string(value));
          box.pack_start(cmb, TRUE, TRUE, 0);
        }
      tbl.attach_defaults(box, 1, 2, top, bottom);
      entry;
    }

    /*--------------------------------------------------------------------
     * Function:    create_history
     * Returns:     A GtkWindow
     * Description: Creates the History window.
     *------------------------------------------------------------------*/
    function create_history ()
    {
      local history_win, title, frame, box1, box2, box3, table;
      local label, label1, label2, but_int1, but_int2, but_int3, but_int4;
      local recbut, entry, qubut, dbsbut, text, but_db1, but_db2, but_db3;
      local spinner, adj, xbut, iset, ent_yhs, ent_str, ent_dur;
      local ent_xhs, ent_int, ent_max, ent_res, dbmv_set, dbpv_set, db_list;
      local dbsbut, plbut, swin, buttons;

      history_win = new (GtkWindow);
      send_message("6");
      history_win.signal ("destroy", #history_win = nil);
      history_win.title = "Cogent Tools Demo: History";
      history_win.set_color(1, GTK_STATE_NORMAL, 0xdddddd);
      history_win.border_width = 10;
      history_win.width = 380;

      /* Title frame. */

      box1 = new(GtkVBox);
      title = new (GtkLabel);
      title.set_text("Cogent Tools Demo - History");
      title.set_color(1, GTK_STATE_NORMAL, 0xff0000);
      title.height = 25;

      frame = new(GtkFrame);
      frame.set_color(1, GTK_STATE_NORMAL, 0xff0000);
      frame.add(title);
      frame.border_width = 5;
      box1.pack_start(frame, TRUE, TRUE, 0);
      history_win.add (box1);

      /* Record Values and Exit buttons. */

      table = gtk_table_new(5, 1, FALSE);
      table.border_width = 5;
      table.set_homogeneous(FALSE);

      recbut = make_toggle_button("Record", 0xddccee);
      recbut.signal("clicked", `send_hs_command(@recbut, "enable", nil, nil));
      button_messages (recbut, "6.2", "6");

      label1 = new(GtkLabel);
      label1.set_text("data for");

      adj = gtk_adjustment_new (0, 1, 200, 1, 5, 0.0);
      spinner = new(GtkSpinButton);
      spinner.set_adjustment(adj);
      spinner.set_value(RECORD_TIME);
      adj.signal("value_changed", `(RECORD_TIME = (@adj).value));

      label2 = new(GtkLabel);
      label2.set_text("seconds.           ");

      xbut = new(GtkButton);
      xbut.label = "Exit";
      xbut.signal("clicked", `(@history_win).destroy());

      iset = new(InterpolatorSettings);

      table.attach_defaults(recbut, 0, 1, 0, 1);
      table.attach_defaults(label1, 1, 2, 0, 1);
      table.attach_defaults(spinner, 2, 3, 0, 1);
      table.attach_defaults(label2, 3, 4, 0, 1);
      table.attach_defaults(xbut, 4, 5, 0, 1);
      box1.pack_start(table, TRUE, TRUE, 5);

      text = new(GtkText);
      text.set_editable(FALSE);

      /* Interpolator options. */

      frame = new(GtkFrame);
      frame.border_width = 5;
      frame.set_color(1, GTK_STATE_NORMAL, 0xddccee);
      frame.set_label(" Interpolator options: ");
      frame.set_label_align(.05, 1);
      frame.set_shadow_type(GTK_SHADOW_IN);
      box1.pack_start(frame, TRUE, TRUE, 0);

      table = gtk_table_new(2, 6, FALSE);
      table.border_width = 10;
      table.set_col_spacing(0, 20);
      table.set_row_spacings(3);
      frame.add(table);

      ent_yhs = qry_entry(table, "Y history:", iset.y_history, 0, 1);
      ent_str = qry_entry(table, "Start:", iset.start, 1, 2);
      ent_dur = qry_entry(table, "Duration:", iset.duration, 2, 3);
      ent_xhs = qry_entry(table, "X history:", iset.x_history, 3, 4);
      ent_int = qry_entry(table, "Time Interval:", iset.interval, 4, 5);
      ent_max = qry_entry(table, "Max. gap:", iset.max_gap, 5, 6);

      but_int1 = qry_radio_but(table, "NoInterpolator", nil, iset,
                               "6.31", 0, 1, ent_xhs, ent_int, ent_max,
                               0, 0, 0);
      but_int2 = qry_radio_but(table, "Periodic", list(but_int1), iset,
                               "6.32", 1, 2, ent_xhs, ent_int, ent_max,
                               0, 1, 1);
      but_int3 = qry_radio_but(table, "Relative", list(but_int1, but_int2),
                               iset, "6.33", 2, 3, ent_xhs, ent_int,
                               ent_max, 1, 0, 0);
      but_int4 = qry_radio_but(table, "FixedRelative",
                               list(but_int1, but_int2, but_int3), iset, "6.34",
                               3, 4, ent_xhs, ent_int, ent_max, 1, 1, 0);

      ent_res = new(GtkEntry);
      ent_res.width = 45;

      qubut = new(GtkButton);
      qubut.label = "Update display";
      qubut.set_color(1, GTK_STATE_NORMAL, 0xddccee);
      qubut.set_color(1, GTK_STATE_PRELIGHT, 0xeeddff);
      button_messages (qubut, "6.3", "6");
      table.attach_defaults(qubut, 0, 1, 5, 6);

      /* Deadband options. */
      dbmv_set = new(DeadbandSettings);
      dbmv_set.history = "MV_001";

      dbpv_set = new(DeadbandSettings);
      dbpv_set.history = "PV_001";

      db_list = list(dbmv_set, dbpv_set);

      box2 = new(GtkHBox);
      box1.pack_start(box2, TRUE, TRUE, 0);

      frame = new(GtkFrame);
      frame.border_width = 5;
      frame.set_color(1, GTK_STATE_NORMAL, 0xddccee);
      frame.set_label(" Deadband options: ");
      frame.set_label_align(.05, 1);
      frame.set_shadow_type(GTK_SHADOW_IN);
      box2.pack_start(frame, TRUE, TRUE, 0);

      table = gtk_table_new(1, 4, FALSE);
      table.border_width = 10;
      table.set_row_spacings(3);
      frame.add(table);

      but_db1 = gtk_check_button_new_with_label ("Full data set (no deadband)");
      but_db2 = gtk_check_button_new_with_label ("Deadband on, prior value off");
      but_db3 = gtk_check_button_new_with_label ("Deadband on, prior value on");
      but_db1.signal("enter", `send_message("6.51"));
      but_db2.signal("enter", `send_message("6.52"));
      but_db3.signal("enter", `send_message("6.53"));

      dbsbut = make_toggle_button("Set up deadband types", 0xddccee);
      dbsbut.signal("toggled", `create_dbtype_win(@db_list, @dbsbut));
      dbsbut.signal("enter", `send_message("6.5"));

      table.attach_defaults(but_db1,  0, 1, 0, 1);
      table.attach_defaults(but_db2,  0, 1, 1, 2);
      table.attach_defaults(but_db3,  0, 1, 2, 3);
      table.attach_defaults(dbsbut,  0, 1, 3, 4);

      /* Plot and text display. */
      box3 = new(GtkVBox);
      box2.pack_start(box3, TRUE, TRUE, 30);

      local button;
      plbut = new(GtkToggleButton);
      plbut.height = 20;
      plbut.label = "Plot Data";
      plbut.set_color(1, GTK_STATE_NORMAL, 0xccccb0);
      plbut.set_color(1, GTK_STATE_PRELIGHT, 0xddddbb);
      plbut.set_color(1, GTK_STATE_ACTIVE, 0xbbbb99);
      plbut.signal("toggled", `start_stop(@plbut, "gnuplot", "plothist1",
                                          "-background", "gray", "-geometry",
                                          "500x400-10-30", "plhist.cfg", nil, nil, nil));
      plbut.signal("toggled", `anygui_move_window(@plbut, @history_win,
                                                  380, 45, 100, 45));
      button_messages (plbut, "6.4", "6");

      label = new(GtkLabel);
      label.set_text("Number\nof points\nfrom last\nquery:");

      box3.pack_end(ent_res, FALSE, FALSE, 5);
      box3.pack_end(label, TRUE, TRUE, 5);
      box3.pack_end(plbut, TRUE, TRUE, 5);

      swin = new(GtkScrolledWindow);
      swin.set_policy(GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
      swin.border_width = 5;
      swin.height = 200;
      swin.width = 400;
      swin.add(text);
      box1.pack_start(swin, TRUE, TRUE, 0);

      recbut.signal("clicked",
                    `record_data(@recbut, @iset, @but_db1, @but_db2, @but_db3, @text,
                                 @ent_yhs, @ent_str, @ent_dur, @ent_xhs,
                                 @ent_int, @ent_max, @ent_res,
                                  @but_int1, @but_int2,
                                  @but_int3, @but_int4, @qubut));

      /* Callbacks for non-deadband buttons to send a query. */
      buttons = list(but_int1, but_int2, but_int3, but_int4, qubut);
      with b in buttons do
      {
        b.signal("clicked",
                 `reset_deadbands(@b, @iset, @but_db1, @but_db2, @but_db3, @text,
                                  @ent_yhs, @ent_str, @ent_dur, @ent_xhs,
                                  @ent_int, @ent_max, @ent_res,
                                  @but_int1, @but_int2, @but_int3,
                                  @but_int4, @recbut, @qubut));
      }

      /* Callbacks for deadband buttons to prepare for and send a query. */
      buttons = list(but_db1, but_db2, but_db3);
      with b in buttons do
      {
        b.signal("clicked",
                 `plot_prep(@b, @iset, @but_db1, @but_db2, @but_db3, @text,
                            @ent_yhs, @ent_str, @ent_dur, @ent_xhs,
                            @ent_int, @ent_max, @ent_res,
                            @but_int1, @but_int2, @but_int3,
                            @but_int4, @recbut, @qubut));
      }

      /* Display version info and start-up message.*/
      ret = display_hs_info(text);

      history_win.show_all();
      history_win.reposition(380, 45);
      history_win;
    }

    /********************************************************
     *                 MAIN FUNCTION Code                   *
     ********************************************************/

    /*--------------------------------------------------------------------
     * Function:    main
     * Returns:     doesn't return
     * Description: Calls the common.g program_startup() function and loops.
     *------------------------------------------------------------------*/
    function main()
    {
      program_startup("history", "historyq", #create_history(), "6");

      atexit(#stop_processes());

      /* Loop forever handling events. */
      gtk_main ();
    }

Prev | Home | Next
`phlog.g` - The Log program in Photon | Up | `phhistory.g` - The History program in Photon

Copyright 1995-2002 by Cogent Real-Time Systems, Inc.