Logo Search packages:      
Sourcecode: ygraph version File versions  Download package

axis.c

Go to the documentation of this file.
/**
 * @file    axis.c
 * @brief   Routines for generating and manipulating plot axes.
 *
 * @author  Denis Pollney
 * @date    1 Oct 2001
 *
 * @par Copyright (C) 2001-2002 Denis Pollney
 *
 *  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, or (at your option)
 *  any later version.
 * @par
 *  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.
 * @par
 *  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include<math.h>
#include<string.h>

#include "ygraph.h"

GtkWidget* entry_xmin = NULL;
GtkWidget* entry_xmax = NULL;
GtkWidget* entry_ymin = NULL;
GtkWidget* entry_ymax = NULL;
GtkWidget* radio_xtype_linear = NULL;
GtkWidget* radio_ytype_linear = NULL;
GtkWidget* radio_xtype_log = NULL;
GtkWidget* radio_ytype_log = NULL;

inline gdouble
linear2log(const gdouble value)
{
  return ((value<=0.0)?(-G_MAXDOUBLE/10.):(log10(value)));
}
inline gdouble
log2linear(const gdouble value)
{
  return pow(10.0, value);
}

inline gdouble
axis_transformation(const gdouble value, const Axis* axis)
{
  switch (axis->type)
    {
      case AXIS_LINEAR: return value;
      case AXIS_LOG   : return linear2log(value);
      default         : printf("axis_transformation(): unknown axis type %d\n",
                               axis->type);
                        return value;
    }
}
inline gdouble
axis_transformation_back(const gdouble value, const Axis* axis)
{
  switch (axis->type)
    {
      case AXIS_LINEAR: return value;
      case AXIS_LOG   : return log2linear(value);
      default         : printf("axis_transformation(): unknown axis type %d\n",
                               axis->type);
                        return value;
    }
}

/**
 * @brief    Calculate the maximum and minimum values of a collection of
 *           datasets to be displayed in a single window.
 *
 * @param    plot  The Plot.
 * @param    mode  Either APPEND_DATA, INIT_DATA or RESCALE_DATA, depending
 *                 on whether data is being appended to an existing plot or
 *                 a new plot is being initialised.
 */
void
00085 plot_range_set(Plot* plot, gint mode)
{
  DataSet* data_set;
  guint i;

  if (plot->data == NULL)
    return;

  if (mode != RESCALE_DATA)
    {
      if (plot->data->len == 0)
        {
          /*
           * If there's no data, draw a plot of default size.
           */
          plot->x_range[0] = 0;
          plot->x_range[1] = 1;
          plot->y_range[0] = 0;
          plot->y_range[1] = 1;
        }
      else if (plot->data->len == 1)
        {
          /*
           * If there's only one dataset, then the ranges of the plot window are
           * the ranges of that set.
           */
          data_set = plot_get_data_index(plot, 0);

          plot->x_range[0] = data_set->x_range[0];
          plot->x_range[1] = data_set->x_range[1];
          plot->y_range[0] = data_set->y_range[0];
          plot->y_range[1] = data_set->y_range[1];
        }
      else if (mode == APPEND_DATA)
        {
          /*
           * If we're just appending a set, then compare the range of the new
           * set to the existing values.
           */
          data_set = plot_get_data_index(plot, plot->data->len-1);

          plot->x_range[0] = MIN(plot->x_range[0], data_set->x_range[0]);
          plot->x_range[1] = MAX(plot->x_range[1], data_set->x_range[1]);
          plot->y_range[0] = MIN(plot->y_range[0], data_set->y_range[0]);
          plot->y_range[1] = MAX(plot->y_range[1], data_set->y_range[1]);
        }
      else
        {
          plot->x_range[0] = G_MAXDOUBLE;
          plot->x_range[1] = -G_MAXDOUBLE;
          plot->y_range[0] = G_MAXDOUBLE;
          plot->y_range[1] = -G_MAXDOUBLE;

          for (i=0; i<plot->data->len; ++i)
            {
              data_set = plot_get_data_index(plot, i);
              
              plot->x_range[0] = MIN(plot->x_range[0], data_set->x_range[0]);
              plot->x_range[1] = MAX(plot->x_range[1], data_set->x_range[1]);
              plot->y_range[0] = MIN(plot->y_range[0], data_set->y_range[0]);
              plot->y_range[1] = MAX(plot->y_range[1], data_set->y_range[1]);
            }
        }

      if (mode == INIT_DATA)
        {
          if (global_x_range != NULL)
            {
              plot->x_range[0] = global_x_range[0];
              plot->x_range[1] = global_x_range[1];
            }
          if (global_y_range != NULL)
            {
              plot->y_range[0] = global_y_range[0];
              plot->y_range[1] = global_y_range[1];
            }
        }
    }
  /* Check if the range is 0.0 (or even less, which should not happen) */
  if (plot->x_range[1] <= plot->x_range[0])
    plot->x_range[1] = plot->x_range[0] + AXIS_EPSILON;
  if (plot->y_range[1] <= plot->y_range[0])
    plot->y_range[1] = plot->y_range[0] + AXIS_EPSILON;
}

/**
 * @brief    Add a Tick to an array.
 *
 * @param    ticks        Array of *Ticks.
 * @param    val          The value of the tick mark along the axis.
 * @param    exp_notation TRUE if the value should be expressed in
 *                        exponential notation.
 * @returns  The original array with the new tick mark appended.
 * @note     The tick should be freed when the axis is destroyed.
 */
GArray*
00181 axis_tick_append(GArray* ticks, gdouble val, Axis* axis, gboolean exp_notation)
{
  Tick* tick;
  tick = g_malloc(sizeof(Tick));
  tick->val = axis_transformation_back(val, axis);
  tick->str = double_to_str(tick->val, exp_notation);
  return g_array_append_val(ticks, tick);
}

/**
 * @brief    Determine the location of tickmarks along an axis, given its
 *           range.
 *
 *           This is not an easy thing to do generally. The following
 *           algorithm tries to divide the range into intervals specified
 *           by the largest log10 division that will fit in the range.
 *           It tries to fit the number of ticks into an optimum range
 *           so that the numbers don't run together. The method is not
 *           always great, and will sometimes fail to put tickmarks on the
 *           axis where intuitively one would expect them. Maybe this could
 *           be generalised by allowing for log2 divisions if the number
 *           of ticks falls below an optimum number.
 *
 * @param    range A pointer to a pair of doubles specifying min and max
 *                 values for the range.
 * @returns  An array of *Ticks where tick-marks should be drawn.
 */
GArray*
00209 axis_calc_ticks(gdouble min, gdouble max, Axis* axis)
{
  GArray* ticks;
  gdouble d;
  gdouble e;
  gdouble div;
  gint n_ticks;
  gdouble a_min;
  gdouble a;
  gint i;
  gboolean exp_notation;

  ticks = g_array_new(FALSE, FALSE, sizeof(Tick*));

  min = axis_transformation(min, axis);
  max = axis_transformation(max, axis);
  if (max == min)
    {
      max += AXIS_EPSILON;
      min -= AXIS_EPSILON;
    }

  d = max - min;
  max += d/1000000;                         /* a*(b/a) !=(always) b */
  e = floor(log10(d));                      /* exponent of the range */
  
  div = pow(10,e);                          /* size of divisions */
  n_ticks = d/div;                          /* number of divisions */

  while (n_ticks < OPTIMUM_TICK_MARK_NUMBER)
    {
      div = 0.1*div;
      n_ticks = ceil(d/div);
    }

  if (n_ticks > 2*OPTIMUM_TICK_MARK_NUMBER)
    {
      while (n_ticks > OPTIMUM_TICK_MARK_NUMBER)
        {
          div = 5*div;
          n_ticks = (gint) d/div;
        }
    }

  /*
   * Very large and very small numbers are display with exponential notation,
   * but intermediate numbers not.
   */
  exp_notation = ( (fabs(max) > 1000) || (fabs(max) < 0.001) );

  i=0;
  a_min = ceil(min/div)*div;          /* leftmost axis label */
  for (a=a_min; a<=max; a+=div)
    {
      /* 
       * If any labels are sufficiently close to zero relative to the
       * extent of the axis (d) then display them as `0'. (Eg. This prevents
       * numbers such as 10-17 showing up when the range is -1...1)
       */
      if (fabs(a/d) < AXIS_EPSILON)
        a = 0;

      axis_tick_append(ticks, a, axis, exp_notation);
    }

  return ticks;
}

/**
 * @brief    Return the width of an axis label entry, including padding.
 *
 * @param    font      The font in which the text is to be displayed.
 * @param    label     The text to be displayed.
 * @param    axis_type The type of axis (0=x-axis).
 * @returns  The width (in pixels) of the text to be displayed.
 */
gint
00286 axis_get_text_width(GdkFont* font, gchar* label, gboolean axis_type)
{
  gint padding[] = {TEXT_X_WIDTH_PADDING, TEXT_Y_WIDTH_PADDING};
  return gdk_text_width(font, label, strlen(label)) + 2*padding[axis_type];
}

/**
 * @brief    Return the height of an axis label entry, including padding.
 *
 * @param    font       The font in which the text is to be displayed.
 * @param    label      The text to be displayed.
 * @param    axis_type  The type of axis (0=x-axis).
 * @returns  The height (in pixels) of the text to be displayed, with padding.
 */
gint
00301 axis_get_text_height(GdkFont* font, gchar* label, gboolean axis_type)
{
  gint padding[] = {TEXT_X_HEIGHT_PADDING, TEXT_Y_HEIGHT_PADDING};
  return gdk_text_height(font, label, strlen(label)) + 2*padding[axis_type];
}

/**
 * @brief    Calculate the amount of space needed by an axis according to the
 *           text in its labels.
 *
 * @param    axis The axis to be measured.
 * @returns  The width (in pixels) of the axis.
 */
gint
00315 axis_calc_width (Axis* axis)
{
  GArray* ticks;
  Tick *tick;
  gint width;
  gint nticks;
  gint i;

  ticks = axis->ticks;
  nticks = ticks->len;

  width = 0;
  for (i=0; i<nticks; ++i)
    {
      tick = g_array_index(ticks, Tick*, i);
      width = MAX(width, axis_get_text_width(axis->font, tick->str, 
                                             axis->orientation));
    }
  return width;
}

/**
 * @brief    Calculate the amount of space needed by an axis according to the
 *           text in its labels.
 *
 * @param    axis The axis to be measured.
 * @returns  The height (in pixels) of the axis.
 */
gint
00344 axis_calc_height (Axis* axis)
{
  GArray* ticks;
  Tick *tick;
  gint height;
  gint nticks;
  gint i;

  ticks = axis->ticks;
  nticks = ticks->len;

  height = 0;
  for (i=0; i<nticks; ++i)
    {
      tick = g_array_index(ticks, Tick*, i);
      height = MAX(height, axis_get_text_height(axis->font, tick->str, 
                                                axis->orientation));
    }
  return height;
}

/**
 * @brief    Determine a measure of inter-tick spacing.
 *
 *           This function calculate the separation between the first
 *           and second tick marks as a measure of the inter-tick
 *           spacing.
 *           The result of this calculation is used to estimate whether
 *           any pair of labels along an axis will have their text write
 *           over one another. Seems to work well enough.
 *
 * @param    plot  The Plot on which the axis is to be displayed.
 * @param    axis  The axis in question.
 * @param    i     The index of an tick, measured is the spacing between this
 *                 and the next tick
 * @returns  The estimate of tick spacing.
 */
gint
00382 axis_calc_tick_sep (Plot* plot, Axis* axis, guint i)
{
  gdouble x0;
  gdouble x1;

  /* prevent values out of range */
  if (i >= axis->ticks->len-1)
    i = axis->ticks->len-2;

  if (axis->ticks->len > 1)
    {
      x0 = g_array_index(axis->ticks, Tick*, i  )->val;
      x1 = g_array_index(axis->ticks, Tick*, i+1)->val;
    }
  else
    {
      if (axis->orientation == X_AXIS)
        {
          x0 = plot->x_range[0];
          x1 = plot->x_range[1];
        }
      else
        {
          x0 = plot->y_range[0];
          x1 = plot->y_range[1];
        }
    }

  x0=axis_transformation(x0, axis);
  x1=axis_transformation(x1, axis);

  if (axis->orientation == X_AXIS)
    return (2*plot->i_origin + x_to_i(plot, x1) - x_to_i(plot, x0)) || 1 ;
  else
    return (2*plot->j_origin + y_to_j(plot, x0) - y_to_j(plot, x1)) || 1;
}

/**
 * @brief    Draw the labels on the x-axis.
 *
 * @param    plot  The Plot on which the axis is to be displayed.
 */
void
00425 axis_draw_x_text(Plot* plot)
{
  Axis* axis;
  GArray* ticks;
  Tick* tick;
  guint i;
  gint len;
  gint text_height;
  gint text_width;
  gint text_ip;
  gint text_jp;
  gint tick_ip;
  gint tick_jp;
  gchar* str;
  
  axis = plot->x_axis;
  ticks = axis->ticks;

  /*
   * Determine the number of pixels between two ticks (assuming uniform grid),
   * and the number of ticks that need to be skipped in order to display the
   * label text without overlap.
   */

  tick_jp = plot->j_origin + 1;

  for (i=0; i<ticks->len; i++)
    {
      tick = g_array_index(ticks, Tick*, i);
      str = tick->str;
      len = strlen(str);

      /*
       * Center the text under a tick mark and draw a long tick at points for
       * which there is a text label.
       */
      text_height = axis_get_text_height(axis->font, str, axis->orientation);
      text_width = axis_get_text_width(axis->font, str, axis->orientation);

      tick_ip = plot->i_origin + x_to_i(plot, tick->val);
      text_ip = tick_ip - 0.5*text_width;
      text_jp = tick_jp + LONG_TICK_LENGTH + text_height;

      g_assert(axis->gc != NULL);
      gdk_draw_text(plot->pixmap, axis->font, axis->gc, text_ip, text_jp, str,
                    len);
      gdk_draw_line(plot->pixmap, axis->gc, tick_ip, tick_jp+LONG_TICK_LENGTH,
                    tick_ip, tick_jp);
    }

  /*
   * At points for which there is no text label, draw a short tick.
   */
  for (i=1; i<ticks->len; ++i)
    {
      if (i)
        {
          tick = g_array_index(ticks, Tick*, i);
          tick_ip = plot->i_origin + x_to_i(plot, tick->val);
          g_assert(axis->gc != NULL);
          gdk_draw_line(plot->pixmap, axis->gc, tick_ip,
                        tick_jp+SHORT_TICK_LENGTH, tick_ip, tick_jp);
        }
    }
}

/**
 * @brief    Draw the y-axis labels.
 *
 * @param    plot  The Plot on which the axis is to be displayed.
 */
void
00497 axis_draw_y_text(Plot* plot)
{
  Axis* axis;
  GArray* ticks;
  Tick* tick;
  guint i;
  gint len;
  gint text_height;
  gint text_width;
  gint text_ip;
  gint text_jp;
  gint tick_ip;
  gint tick_jp;
  gchar* str;
  gint di;
  gint step;
  
  axis = plot->y_axis;
  ticks = axis->ticks;

  /*
   * Determine the number of pixels between two ticks (assuming uniform grid),
   * and the number of ticks that need to be skipped in order to display the
   * label text without overlap.
   */
  di = axis_calc_tick_sep(plot, axis, 0);
  step = 1;

  tick_ip = plot->i_origin - 1;

  for (i=0; i<ticks->len; i++)
    {
      tick = g_array_index(ticks, Tick*, i);
      str = tick->str;
      len = strlen(str);
      if (i < ticks->len)
        {

          /*
           * Center the text next to a tick mark and draw a long tick at points
           * for which there is a text label.
           */
           text_height = axis_get_text_height(axis->font, str,
                                              axis->orientation);
           text_width = axis_get_text_width(axis->font, str,
                                            axis->orientation);

           tick_jp = plot->j_origin + y_to_j(plot, tick->val);
           text_jp = tick_jp + 0.3*text_height;
           text_ip = tick_ip - LONG_TICK_LENGTH - text_width;

           g_assert(axis->gc != NULL);
           gdk_draw_text(plot->pixmap, axis->font, axis->gc, text_ip, text_jp,
                         str, len);
           gdk_draw_line(plot->pixmap, axis->gc, tick_ip-LONG_TICK_LENGTH,
                         tick_jp, tick_ip, tick_jp);
        }
    }

  /*
   * At points for which there is no text label, draw a short tick.
   * need to be fixed
   */
  for (i=1; i<ticks->len; i+=step)
    {
      tick = g_array_index(ticks, Tick*, i);
      tick_jp = plot->j_origin + y_to_j(plot, tick->val);
      g_assert(axis->gc != NULL);
      gdk_draw_line(plot->pixmap, axis->gc, tick_ip-SHORT_TICK_LENGTH, tick_jp,
                    tick_ip, tick_jp);
    }
}

/**
 * @brief    Create an axis, including labels and locations of tick-marks.
 *
 * @param    plot         The Plot for which the axis is being created.
 * @param    orientation  Either X_AXIS or Y_AXIS.
 * @returns  A completed axis structure.
 */
Axis*
00578 axis_create(Plot* plot, gint orientation, AXIS_TYPE type)
{
  Axis* axis;

  YDEB("axis_create\n");
  axis = g_malloc(sizeof(Axis));
  axis->font=NULL;
  axis->gc=NULL;
  axis->ticks=NULL;
  axis->orientation = orientation;
  axis->type = type;
  axis->font = gdk_font_load(DEFAULT_AXIS_FONT);

  if (orientation == X_AXIS)
    axis->ticks = axis_calc_ticks(plot->x_range[0], plot->x_range[1], axis);
  else
    axis->ticks = axis_calc_ticks(plot->y_range[0], plot->y_range[1], axis);

  axis->width = axis_calc_width(axis);
  axis->height = axis_calc_height(axis);
  
  return axis;
}

/**
 * @brief    Free the space allocated to an Axis structure.
 *
 * @param    axis The axis to be freed.
 * @todo     Need to check whether all of the components of the axis are
 *           being freed properly.
 */
void
00610 axis_free (Axis* axis)
{
  int i;
  for (i=axis->ticks->len-1; i>=0; i--)
  {
    g_free(g_array_index(axis->ticks, Tick*, i)->str);
    g_free(g_array_index(axis->ticks, Tick*, i));
  }
  g_array_free(axis->ticks, TRUE);
  if (axis->gc != NULL)
  {
    gdk_gc_unref(axis->gc);
    axis->gc=NULL;
  }
  g_free(axis);
  axis=NULL;
}

/**
 * @brief    Render lines for the x and y axes.
 *
 * @param    plot  The Plot on which the axis lines are to be drawn.
 */
void
00634 axis_draw_lines(Plot* plot)
{
  gdk_draw_line(plot->pixmap, plot->x_axis->gc,
                plot->i_origin-1, plot->j_origin+1,
                plot->i_origin + plot->i_size, plot->j_origin+1);
  gdk_draw_line(plot->pixmap, plot->y_axis->gc,
                plot->i_origin-1, plot->j_origin,
                plot->i_origin-1, plot->j_origin-plot->j_size);
}

/**
 * @brief    Write "log" at the end of a log axis.
 *
 * @param    plot  The Plot on which the axes are to be drawn.
 * @param    axis  The Axis to be labelled.
 */
void
00651 axis_draw_log_indicator(Plot* plot, Axis* axis)
{
  gint text_height;
  gint text_width;
  gint text_ip;
  gint text_jp;
  
  text_height = axis_get_text_height(axis->font, AXIS_LOG_TYPE_LABEL,
                                     axis->orientation);
  text_width = axis_get_text_width(axis->font, AXIS_LOG_TYPE_LABEL,
                                   axis->orientation);

  if (axis->orientation == X_AXIS)
    {
      text_ip = plot->i_origin + plot->i_size - text_width;
      text_jp = plot->j_origin;
    }
  else
    {
      text_ip = plot->i_origin - text_width;
      text_jp = plot->j_origin - plot->j_size;
    }

  if (axis->type == AXIS_LOG)
    gdk_draw_text(plot->pixmap, axis->font, axis->gc,
                  text_ip, text_jp+text_height,
                  AXIS_LOG_TYPE_LABEL, strlen(AXIS_LOG_TYPE_LABEL));
}

/**
 * @brief    Write "log" at the end of log each axis.
 *
 * @param    plot  The Plot on which the axes are to be drawn.
 */
void
00686 axis_draw_log_indicator_xy(Plot* plot)
{
  axis_draw_log_indicator(plot, plot->x_axis);
  axis_draw_log_indicator(plot, plot->y_axis);
}

/**
 * @brief    Draw the plot axes, including tick-marks and labels.
 *
 * @param    plot  The Plot on which the axes are to be drawn.
 */
void
00698 axis_draw(Plot* plot)
{
  if (plot->x_axis->gc == NULL)
    plot->x_axis->gc = gdk_gc_new(plot->plot_area->window);
  if (plot->y_axis->gc == NULL)
    plot->y_axis->gc = gdk_gc_new(plot->plot_area->window);

  axis_draw_x_text(plot);
  axis_draw_y_text(plot);
  axis_draw_lines(plot);
  axis_draw_log_indicator_xy(plot);
}

/**
 * @brief    Create both x and y axes for a plot window.
 * 
 * @param    plot  The Plot for which the axes are to be created.
 */
void
00717 plot_axes_create(Plot* plot)
{
  AXIS_TYPE x_type = AXIS_LINEAR;
  AXIS_TYPE y_type = AXIS_LINEAR;

  if (plot->x_axis != NULL)
    {
      x_type = plot->x_axis->type;
      axis_free(plot->x_axis);
    }

  if (plot->y_axis != NULL)
    {
      y_type = plot->y_axis->type;
      axis_free(plot->y_axis);
    }

  plot->x_axis = axis_create(plot, X_AXIS, x_type);
  plot->y_axis = axis_create(plot, Y_AXIS, y_type);
}

/**
 * @brief    Set the state of an axis-type toggle button (linear or log axis).
 *
 * @param    axis              The Axis whose state is being checked.
 * @param    toggle_linear     The toggle button indicating a linear axis.
 * @param    toggle_log        The toggle button indicating a log axis.
 */
void
00746 axis_type_set_toggle(Axis* axis, GtkToggleButton* toggle_linear,
                     GtkToggleButton* toggle_log)
{
  if ((axis->type == AXIS_LINEAR) && (toggle_linear != NULL))
    gtk_toggle_button_set_active(toggle_linear, TRUE);
  else if ((axis->type == AXIS_LOG) && (toggle_log != NULL))
    gtk_toggle_button_set_active(toggle_log, TRUE);
}

/**
 * @brief    Put values in the range dialog entry boxes.
 *
 * @param    plot              The Plot for which the ranges are to be set.
 */
void
00761 range_entry_value_set(Plot* plot)
{
  gchar xmin_str[RANGE_VAL_SIZE];
  gchar xmax_str[RANGE_VAL_SIZE];
  gchar ymin_str[RANGE_VAL_SIZE];
  gchar ymax_str[RANGE_VAL_SIZE];

  g_snprintf(xmin_str, RANGE_VAL_SIZE, "%f", plot->x_range[0]);
  gtk_entry_set_text(GTK_ENTRY(entry_xmin), xmin_str);

  g_snprintf(xmax_str, RANGE_VAL_SIZE, "%f", plot->x_range[1]);
  gtk_entry_set_text(GTK_ENTRY(entry_xmax), xmax_str);

  g_snprintf(ymin_str, RANGE_VAL_SIZE, "%f", plot->y_range[0]);
  gtk_entry_set_text(GTK_ENTRY(entry_ymin), ymin_str);

  g_snprintf(ymax_str, RANGE_VAL_SIZE, "%f", plot->y_range[1]);
  gtk_entry_set_text(GTK_ENTRY(entry_ymax), ymax_str);

  axis_type_set_toggle(plot->x_axis, GTK_TOGGLE_BUTTON(radio_xtype_linear),
                       GTK_TOGGLE_BUTTON(radio_xtype_log));
  axis_type_set_toggle(plot->y_axis, GTK_TOGGLE_BUTTON(radio_ytype_linear),
                       GTK_TOGGLE_BUTTON(radio_ytype_log));
}

/**
 * @brief    Create a dialog which prompts the user to enter (x,y) range
 *           values.
 *
 * @param    plot              The Plot for which the ranges are to be set.
 * @param    action            The action initiating the call (unused).
 * @param    range_set_button  The button initiating the call.
 */
void
00795 range_dialog_create(Plot* plot, gint action, GtkItem* range_set_button)
{
  GtkWidget* dialog;
  GtkWidget* range_table;
  GtkWidget* label_xmin;
  GtkWidget* label_xmax;
  GtkWidget* label_ymin;
  GtkWidget* label_ymax;
  GtkWidget* okay_button;
  GtkWidget* apply_button;
  GtkWidget* cancel_button;
  GtkWidget* label_xtype;
  GtkWidget* radio_xtype_hbox;
  GSList* radio_group_xtype;
  GtkWidget* label_ytype;
  GtkWidget* radio_ytype_hbox;
  GSList* radio_group_ytype;

  UNUSED(action);
  UNUSED(range_set_button);
  dialog = gtk_dialog_new();
  gtk_window_set_title(GTK_WINDOW(dialog), RANGE_DIALOG_TITLE);
  gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, TRUE);

  range_table = gtk_table_new(4, 2, TRUE);

  /*
   * Entry labels.
   */
  label_xmin = gtk_label_new(XMIN_LABEL);
  gtk_widget_show(label_xmin);
  gtk_table_attach_defaults(GTK_TABLE(range_table), label_xmin, 0, 1, 0, 1);

  entry_xmin = gtk_entry_new();
  gtk_entry_set_max_length(GTK_ENTRY(entry_xmin), RANGE_VAL_SIZE);
  gtk_signal_connect(GTK_OBJECT(entry_xmin), "activate",
                     GTK_SIGNAL_FUNC(axis_set_from_dialog), plot);
  gtk_widget_show(entry_xmin);
  gtk_table_attach_defaults(GTK_TABLE(range_table), entry_xmin, 1, 2, 0, 1);
  gtk_widget_set_usize(entry_xmin, RANGE_VAL_SIZE, -2);

  label_xmax = gtk_label_new(XMAX_LABEL);
  gtk_widget_show(label_xmax);
  gtk_table_attach_defaults(GTK_TABLE(range_table), label_xmax, 0, 1, 1, 2);

  entry_xmax = gtk_entry_new();
  gtk_entry_set_max_length(GTK_ENTRY(entry_xmax), RANGE_VAL_SIZE);
  gtk_signal_connect(GTK_OBJECT(entry_xmax), "activate",
                     GTK_SIGNAL_FUNC(axis_set_from_dialog), plot);
  gtk_widget_show(entry_xmax);
  gtk_table_attach_defaults(GTK_TABLE(range_table), entry_xmax, 1, 2, 1, 2);
  gtk_widget_set_usize(entry_xmax, RANGE_VAL_SIZE, -2);

  label_xtype = gtk_label_new(X_AXIS_TYPE_LABEL);
  gtk_widget_show(label_xtype);
  gtk_table_attach_defaults(GTK_TABLE(range_table), label_xtype, 0, 1, 2, 3);
  
  radio_xtype_hbox = gtk_hbox_new(TRUE, 2);
  radio_xtype_linear = gtk_radio_button_new_with_label
    (NULL, AXIS_LINEAR_TYPE_LABEL);
  radio_group_xtype = gtk_radio_button_group
    (GTK_RADIO_BUTTON(radio_xtype_linear));
  radio_xtype_log = gtk_radio_button_new_with_label
    (radio_group_xtype, AXIS_LOG_TYPE_LABEL);
  gtk_box_pack_start(GTK_BOX(radio_xtype_hbox), radio_xtype_linear,
                     TRUE, TRUE, 2);
  gtk_box_pack_start(GTK_BOX(radio_xtype_hbox), radio_xtype_log,
                     TRUE, TRUE, 2);
  gtk_widget_show(radio_xtype_hbox);
  gtk_table_attach_defaults(GTK_TABLE(range_table), radio_xtype_hbox,
                            1, 2, 2, 3);
  axis_type_set_toggle(plot->x_axis, GTK_TOGGLE_BUTTON(radio_xtype_linear),
                       GTK_TOGGLE_BUTTON(radio_xtype_log));

  label_ymin = gtk_label_new(YMIN_LABEL);
  gtk_widget_show(label_ymin);
  gtk_table_attach_defaults(GTK_TABLE(range_table), label_ymin, 0, 1, 3, 4);

  entry_ymin = gtk_entry_new();
  gtk_entry_set_max_length(GTK_ENTRY(entry_ymin), RANGE_VAL_SIZE);
  gtk_signal_connect(GTK_OBJECT(entry_ymin), "activate",
                     GTK_SIGNAL_FUNC(axis_set_from_dialog), plot);
  gtk_widget_show(entry_ymin);
  gtk_table_attach_defaults(GTK_TABLE(range_table), entry_ymin, 1, 2, 3, 4);
  gtk_widget_set_usize(entry_ymin, RANGE_VAL_SIZE, -2);

  label_ymax = gtk_label_new(YMAX_LABEL);
  gtk_widget_show(label_ymax);
  gtk_table_attach_defaults(GTK_TABLE(range_table), label_ymax, 0, 1, 4, 5);

  entry_ymax = gtk_entry_new();
  gtk_entry_set_max_length(GTK_ENTRY(entry_ymax), RANGE_VAL_SIZE);
  gtk_signal_connect(GTK_OBJECT(entry_ymax), "activate",
                     GTK_SIGNAL_FUNC(axis_set_from_dialog), plot);
  gtk_widget_show(entry_ymax);
  gtk_table_attach_defaults(GTK_TABLE(range_table), entry_ymax, 1, 2, 4, 5);
  gtk_widget_set_usize(entry_ymax, RANGE_VAL_SIZE, -2);

  gtk_widget_show(range_table);
  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), range_table, FALSE,
                     FALSE, 0);

  label_ytype = gtk_label_new(Y_AXIS_TYPE_LABEL);
  gtk_widget_show(label_ytype);
  gtk_table_attach_defaults(GTK_TABLE(range_table), label_ytype, 0, 1, 5, 6);
  
  radio_ytype_hbox = gtk_hbox_new(TRUE, 2);
  radio_ytype_linear = gtk_radio_button_new_with_label(NULL, 
                                                       AXIS_LINEAR_TYPE_LABEL);
  radio_group_ytype = gtk_radio_button_group
    (GTK_RADIO_BUTTON(radio_ytype_linear));
  radio_ytype_log = gtk_radio_button_new_with_label(radio_group_ytype,
                                                    AXIS_LOG_TYPE_LABEL);
  gtk_box_pack_start(GTK_BOX(radio_ytype_hbox), radio_ytype_linear,
                     TRUE, TRUE, 2);
  gtk_box_pack_start(GTK_BOX(radio_ytype_hbox), radio_ytype_log,
                     TRUE, TRUE, 2);
  gtk_widget_show(radio_ytype_hbox);
  gtk_table_attach_defaults(GTK_TABLE(range_table), radio_ytype_hbox,
                            1, 2, 5, 6);
  axis_type_set_toggle(plot->y_axis, GTK_TOGGLE_BUTTON(radio_ytype_linear),
                       GTK_TOGGLE_BUTTON(radio_ytype_log));

  range_entry_value_set(plot);

  /*
   * Okay button.
   */
  okay_button = gtk_button_new_with_label(OKAY_BUTTON_LABEL);
  gtk_signal_connect(GTK_OBJECT(okay_button),
                     "clicked", GTK_SIGNAL_FUNC(axis_set_from_dialog), plot);
  gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked",
                             GTK_SIGNAL_FUNC (gtk_widget_destroy),
                             GTK_OBJECT(dialog));
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
                     okay_button);
  gtk_widget_show(okay_button);

  /*
   * Apply button.
   */
  apply_button = gtk_button_new_with_label(APPLY_BUTTON_LABEL);
  gtk_signal_connect(GTK_OBJECT(apply_button),
                     "clicked", GTK_SIGNAL_FUNC(axis_set_from_dialog), plot);
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
                     apply_button);
  gtk_widget_show(apply_button);

  /*
   * Cancel button.
   */
  cancel_button = gtk_button_new_with_label(CANCEL_BUTTON_LABEL);
  gtk_signal_connect_object (GTK_OBJECT (cancel_button), "clicked",
                             GTK_SIGNAL_FUNC (gtk_widget_destroy),
                             GTK_OBJECT(dialog));
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
                     cancel_button);
  gtk_widget_show(cancel_button);

  gtk_widget_show_all (dialog);
}

/**
 * @brief    Sets the plot range based on values returned from the plot dialog.
 *
 * @param    plot    The Plot whose range should be set.
 */
gboolean
00963 range_reset(Plot* plot)
{
  gchar* new_xmin_str;
  gchar* new_xmax_str;
  gchar* new_ymin_str;
  gchar* new_ymax_str;
  gdouble new_xmin;
  gdouble new_xmax;
  gdouble new_ymin;
  gdouble new_ymax;

  if ((entry_xmin == NULL) || (entry_xmax == NULL) || (entry_ymin == NULL)
      || (entry_ymax == NULL))
    return;
    
  new_xmin_str = gtk_entry_get_text(GTK_ENTRY(entry_xmin));
  new_xmax_str = gtk_entry_get_text(GTK_ENTRY(entry_xmax));
  new_ymin_str = gtk_entry_get_text(GTK_ENTRY(entry_ymin));
  new_ymax_str = gtk_entry_get_text(GTK_ENTRY(entry_ymax));

  new_xmin = g_strtod(new_xmin_str, NULL);
  new_xmax = g_strtod(new_xmax_str, NULL);
  new_ymin = g_strtod(new_ymin_str, NULL);
  new_ymax = g_strtod(new_ymax_str, NULL);

  if (new_xmin >= new_xmax)
      message_dialog("Invalid x range");
  else
    {
      plot->x_range[0] = new_xmin;
      plot->x_range[1] = new_xmax;
    }

  if (new_ymin >= new_ymax)
      message_dialog("Invalid y range");
  else
    {
      plot->y_range[0] = new_ymin;
      plot->y_range[1] = new_ymax;
    }
  
  plot->fixed_range = TRUE;

  return TRUE;
}

/**
 * @brief    Sets the plot range based on values returned from the plot dialog.
 *
 * @param    plot    The Plot whose range should be set.
 */
gboolean
01015 axis_type_reset(Plot* plot)
{
  if ((gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_xtype_linear))
       == TRUE) && (plot->x_axis->type == AXIS_LOG))
    plot->x_axis->type = AXIS_LINEAR;
  else if ((gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_xtype_log))
           == TRUE) && (plot->x_axis->type == AXIS_LINEAR))
    plot->x_axis->type = AXIS_LOG;

  if ((gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_ytype_linear))
      == TRUE) && (plot->y_axis->type == AXIS_LOG))
    plot->y_axis->type = AXIS_LINEAR;
  else if ((gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_ytype_log))
           == TRUE) && (plot->y_axis->type == AXIS_LINEAR))
    plot->y_axis->type = AXIS_LOG;
  return TRUE;
}

/**
 * @brief    Sets the plot range based on values returned from the plot dialog.
 *
 * @param    plot    The Plot whose range should be set.
 */
gboolean
01039 axis_set_from_dialog(GtkObject* button, Plot* plot)
{
  UNUSED(button);
  axis_type_reset(plot);

  range_reset(plot);
  plot_range_set(plot, RESCALE_DATA);
  range_entry_value_set(plot);

  plot_axes_create(plot);
  plot_window_reconfigure(plot);
  plot_window_display_all(plot);

  return TRUE;
}


/**
 * @brief    Switch between axis states log<->linear.
 *
 * @param    plot    The Plot whose axes are to be toggled.
 */
void
01062 axis_toggle_log_state(Plot* plot)
{
  if (plot == NULL)
    return;

  if (plot->x_axis->type == AXIS_LINEAR)
    {
     if (plot->y_axis->type == AXIS_LINEAR)
       plot->y_axis->type = AXIS_LOG;
     else
       plot->x_axis->type = AXIS_LOG;
    }
  else
    {
      if (plot->y_axis->type == AXIS_LOG)
        plot->y_axis->type = AXIS_LINEAR;
      else
        plot->x_axis->type = AXIS_LINEAR;
    }

  plot_range_set(plot, RESCALE_DATA);

  plot_axes_create(plot);
  plot_window_reconfigure(plot);
  plot_window_display_all(plot);
}

Generated by  Doxygen 1.6.0   Back to index