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

graph.c

/* dc_gui2 - a GTK+2 GUI for DCTC
 * Copyright (C) 2002 Eric Prevoteau
 *
 * graph.c: Copyright (C) Eric Prevoteau <www@a2pb.gotdns.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
/*
$Id: graph.c,v 1.6 2004/01/10 16:16:34 ericprev Exp $
*/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pango/pango.h>
#include <gnome.h>

#include "graph.h"
#include "misc_gtk.h"
#include "misc.h"
#include "main.h"

/***********************/
/* values for DL graph */
/***********************/
GdkPixmap *graph_dl_image=NULL;
GRAPH_TYPE graph_dl_type=GRAPH_BY_WEEKDAY;
GRAPH_DISPLAY_TYPE graph_dl_display_type=GRAPH_BY_TRANSFER;

/***********************/
/* values for UL graph */
/***********************/
GdkPixmap *graph_ul_image=NULL;
GRAPH_TYPE graph_ul_type=GRAPH_BY_WEEKDAY;
GRAPH_DISPLAY_TYPE graph_ul_display_type=GRAPH_BY_TRANSFER;

/*******************************/
/* values shared between graph */
/*******************************/
gint graph_image_w=-1;
gint graph_image_h=-1;
gint graph_depth=-1;          /* set by main.c on start */

static GdkGC *graph_gc=NULL;
static GdkColormap *graph_cmap=NULL;
static PangoLayout *graph_layout=NULL;
static PangoFontDescription *font_desc=NULL;

gint today_monthday=0;

GdkColor light_red, white, black, light_grey, green, light_orange;
 
GdkColor greyDD,greyEE; 
 
static struct
{
   unsigned int r,v,b;
   GdkColor *ptr;
}alloc_color[]={
                  {0xffff,0x0,0x0,&light_red},
                  {0xffff,0xffff,0xffff,&white},
                  {0,0,0,&black},
                  {0xacac,0xacac,0xacac,&light_grey},
                  {0x0,0xffff,0x0,&green},
                  {0xffff,0xe7e7,0x8080,&light_orange},
                  {0xdddd,0xdddd,0xdddd,&greyDD},
                  {0xeeee,0xeeee,0xeeee,&greyEE},
                  {0,0,0,NULL}
               };

typedef struct 
{
      guint32 julian_day;                 /* for day display */
      GDateWeekday week_day;        /* for week day display */
      GDateDay month_day;           /* for month day display */
      XFER_TYPE xfer_type;
      double xfer_size;
} XFER_ENTRY;

GArray *xfers=NULL; /* array of XFER_ENTRY */

/******************************************************************/
/* some values need to be initialized (only after image creation) */
/******************************************************************/
static void init_values(void)
{
      int i;
      GtkWidget *widget;

      widget=get_widget_by_widget_name(main_window,"root_notebook");
      graph_gc=gdk_gc_new(widget->window);
      graph_cmap=gdk_colormap_new(gdk_visual_get_best(),FALSE);

   i=0;
   while(alloc_color[i].ptr!=NULL)
   {
      alloc_color[i].ptr->red=(guint16)alloc_color[i].r;
      alloc_color[i].ptr->green=(guint16)alloc_color[i].v;
      alloc_color[i].ptr->blue=(guint16)alloc_color[i].b;

      /* Allocate color */
      gdk_colormap_alloc_color (graph_cmap, alloc_color[i].ptr,FALSE,TRUE);
      i++;
   }

      graph_layout=gtk_widget_create_pango_layout(widget,"");
      font_desc=pango_font_description_from_string("Luxi Mono 9");
      pango_layout_set_font_description(graph_layout,font_desc);
      pango_layout_set_justify(graph_layout,PANGO_ALIGN_CENTER);        /* only required for multi-line text */
}

/*************************************************************/
/* graph some bars with title (bar size is given in guint32) */
/*************************************************************/
static void graph_guint32_bars(GdkPixmap *graph_image,int nb_bars, guint32 *bars_size, const char **bar_name, const char *unit, double scale, gint today_bar)
{
      guint32 max_bar_size;
      guint32 i;
      guint bar_height;
      guint bar_width;
      guint32 bar_step=1;
      guint32 bar_step_count;
      guint bar_bottom;
      guint bar_left;
      guint bar_step_pix_size;

      max_bar_size=0;
      for(i=0;i<nb_bars;i++)
      {
            if(bars_size[i]>max_bar_size)
                  max_bar_size=bars_size[i];
      }

      /* compute the size of a step and the number of step */
      while((max_bar_size/bar_step)>9)
      {
            bar_step*=10;
      }

      bar_step_count=(max_bar_size+bar_step-1)/bar_step;
      if(bar_step_count==0)
            bar_step_count=1;

      bar_left=64;
      bar_width=(graph_image_w-bar_left-10)/nb_bars;

      bar_bottom=(graph_image_h-20);
      bar_height=bar_bottom-10;

      bar_step_pix_size=bar_height/bar_step_count;

      /* draw the left and the bottom line */
      gdk_gc_set_foreground(graph_gc,&black);
      
      gdk_draw_line(graph_image,graph_gc,bar_left,10,bar_left,bar_bottom);
      gdk_draw_line(graph_image,graph_gc,bar_left,bar_bottom,bar_left+nb_bars*bar_width,bar_bottom);
      for(i=0;i<bar_step_count+1;i++)
      {
            GString *level;
            int w, h;

            gdk_draw_line(graph_image,graph_gc,
                                                            bar_left-3,bar_bottom-i*bar_step_pix_size,
                                                            bar_left,bar_bottom-i*bar_step_pix_size);

            level=value_to_readable(i*bar_step,scale);
            if(unit)
                  g_string_append(level,unit);

            pango_layout_set_text(graph_layout,level->str,level->len);
            pango_layout_get_pixel_size(graph_layout,&w,&h);
            g_string_free(level,TRUE);

            gdk_draw_layout(graph_image,graph_gc,bar_left-6-w,bar_bottom-i*bar_step_pix_size-h/2,graph_layout);
      }

      for(i=0;i<(nb_bars+1);i++)
      {
            gdk_draw_line(graph_image,graph_gc,
                                                            bar_left+i*bar_width,bar_bottom,
                                                            bar_left+i*bar_width,bar_bottom+3);
            if((i<nb_bars)&&(bar_name[i]))
            {
                  int ln=strlen(bar_name[i]);
                  int w, h;

                  /* adjust the number of bytes in the column name to avoid column title overlapping */
                  pango_layout_set_text(graph_layout,bar_name[i],ln);
                  pango_layout_get_pixel_size(graph_layout,&w,&h);

                  while((w>bar_width)&&(ln>0))
                  {
                        pango_layout_set_text(graph_layout,bar_name[i],ln);
                        pango_layout_get_pixel_size(graph_layout,&w,&h);
                        ln--;
                  }
                  
                  if(w>bar_width)         /* if even 1 character is too much, force width to avoid computation error */
                        w=bar_width;
                  gdk_draw_layout(graph_image,graph_gc,bar_left+i*bar_width+((bar_width-w)/2), bar_bottom+4,graph_layout);
            }
      }

      /* horizontal line to separate each level */
      gdk_gc_set_foreground(graph_gc,&light_grey);
      for(i=0;i<bar_step_count+1;i++)
      {
            gdk_draw_line(graph_image,graph_gc,
                                                            bar_left+1,bar_bottom-i*bar_step_pix_size,
                                                            bar_left+nb_bars*bar_width,bar_bottom-i*bar_step_pix_size);
      }

      /* draw all bars */
      gdk_gc_set_foreground(graph_gc,&light_orange);
      for(i=0;i<nb_bars;i++)
      {
            double h;
            guint ih;

            h=bar_height;
            h*=bars_size[i];
            h/=(bar_step*bar_step_count);
            ih=h;
            gdk_draw_rectangle(graph_image,graph_gc,TRUE,
                                                      bar_left+1+i*bar_width, bar_bottom-ih,
                                                      bar_width-2, ih
                                                      );
      }

      if(today_bar>=0)
      {
            int w, h;

            gdk_gc_set_foreground(graph_gc,&light_red);

            gdk_draw_line(graph_image,graph_gc,
                                                            bar_left+(today_bar+1)*bar_width,10,
                                                            bar_left+(today_bar+1)*bar_width,bar_bottom-1);

            pango_layout_set_text(graph_layout,_("T\no\nd\na\ny"),-1);
            pango_layout_get_pixel_size(graph_layout,&w,&h);
            gdk_draw_layout(graph_image,graph_gc,bar_left+(today_bar+1)*bar_width-w-2, 10,graph_layout);
      }
}

/* ================================================================ */
/*************************************************************/
/* graph some bars with title (bar size is given in guint32) */
/*************************************************************/
static void graph_double_bars(GdkPixmap *graph_image,int nb_bars, double *bars_size, const char **bar_name, const char *unit, double scale, gint today_bar)
{
      double max_bar_size;
      guint32 i;
      guint bar_height;
      guint bar_width;
      double bar_step=1;
      guint32 bar_step_count;
      guint bar_bottom;
      guint bar_left;
      guint bar_step_pix_size;
      
      max_bar_size=0;
      for(i=0;i<nb_bars;i++)
      {
            if(bars_size[i]>max_bar_size)
                  max_bar_size=bars_size[i];
      }

      /* compute the size of a step and the number of step */
      while((max_bar_size/bar_step)>9)
      {
            bar_step*=10;
      }
      bar_step_count=(max_bar_size+bar_step-1)/bar_step;
      if(bar_step_count==0)
            bar_step_count=1;

      bar_left=64;
      bar_width=(graph_image_w-bar_left-10)/nb_bars;

      bar_bottom=(graph_image_h-20);
      bar_height=bar_bottom-10;

      bar_step_pix_size=bar_height/bar_step_count;

      /* draw the left and the bottom line */
      gdk_gc_set_foreground(graph_gc,&black);
      
      gdk_draw_line(graph_image,graph_gc,bar_left,10,bar_left,bar_bottom);
      gdk_draw_line(graph_image,graph_gc,bar_left,bar_bottom,bar_left+nb_bars*bar_width,bar_bottom);
      for(i=0;i<bar_step_count+1;i++)
      {
            GString *level;
            int w, h;

            gdk_draw_line(graph_image,graph_gc,
                                                            bar_left-3,bar_bottom-i*bar_step_pix_size,
                                                            bar_left,bar_bottom-i*bar_step_pix_size);

            level=value_to_readable(i*bar_step,scale);
            if(unit)
                  g_string_append(level,unit);

            pango_layout_set_text(graph_layout,level->str,level->len);
            pango_layout_get_pixel_size(graph_layout,&w,&h);
            g_string_free(level,TRUE);

            gdk_draw_layout(graph_image,graph_gc,bar_left-6-w,bar_bottom-i*bar_step_pix_size-h/2,graph_layout);
      }

      for(i=0;i<(nb_bars+1);i++)
      {
            gdk_draw_line(graph_image,graph_gc,
                                                            bar_left+i*bar_width,bar_bottom,
                                                            bar_left+i*bar_width,bar_bottom+3);
            if((i<nb_bars)&&(bar_name[i]))
            {
                  int ln=strlen(bar_name[i]);
                  int w, h;

                  /* adjust the number of bytes in the column name to avoid column title overlapping */
                  pango_layout_set_text(graph_layout,bar_name[i],ln);
                  pango_layout_get_pixel_size(graph_layout,&w,&h);

                  while((w>bar_width)&&(ln>0))
                  {
                        pango_layout_set_text(graph_layout,bar_name[i],ln);
                        pango_layout_get_pixel_size(graph_layout,&w,&h);
                        ln--;
                  }
                  
                  if(w>bar_width)         /* if even 1 character is too much, force width to avoid computation error */
                        w=bar_width;
                  gdk_draw_layout(graph_image,graph_gc,bar_left+i*bar_width+((bar_width-w)/2), bar_bottom+4,graph_layout);
            }
      }

      /* horizontal line to separate each level */
      gdk_gc_set_foreground(graph_gc,&light_grey);
      for(i=0;i<bar_step_count+1;i++)
      {
            gdk_draw_line(graph_image,graph_gc,
                                                            bar_left+1,bar_bottom-i*bar_step_pix_size,
                                                            bar_left+nb_bars*bar_width,bar_bottom-i*bar_step_pix_size);
      }

      /* draw all bars */
      gdk_gc_set_foreground(graph_gc,&light_orange);
      for(i=0;i<nb_bars;i++)
      {
            double h;
            guint ih;

            h=bar_height;
            h*=bars_size[i];
            h/=(bar_step*bar_step_count);
            ih=h;
            gdk_draw_rectangle(graph_image,graph_gc,TRUE,
                                                      bar_left+1+i*bar_width, bar_bottom-ih,
                                                      bar_width-2, ih
                                                      );
      }

      if(today_bar>=0)
      {
            int w, h;

            gdk_gc_set_foreground(graph_gc,&light_red);

            gdk_draw_line(graph_image,graph_gc,
                                                            bar_left+(today_bar+1)*bar_width,10,
                                                            bar_left+(today_bar+1)*bar_width,bar_bottom-1);

            pango_layout_set_text(graph_layout,_("T\no\nd\na\ny"),-1);
            pango_layout_get_pixel_size(graph_layout,&w,&h);
            gdk_draw_layout(graph_image,graph_gc,bar_left+(today_bar+1)*bar_width-w-2, 10,graph_layout);
      }
}

/* ================================================================ */
static void graph_by_weekday_xfer(GdkPixmap *graph_image, XFER_TYPE direction)
{
      guint32 stat_day[8];          /* 8 for 7 days (1-7) + 1 bad day */
      const char *stat_name[8]={_("Unknown"),_("Monday"),_("Tuesday"),_("Wednesday"),_("Thursday"),_("Friday"),_("Saturday"),_("Sunday")};
      int i;

      for(i=0;i<8;i++)
            stat_day[i]=0;

      for(i=0;i<xfers->len;i++)
      {
            if(g_array_index(xfers,XFER_ENTRY,i).xfer_type==direction)
                  stat_day[g_array_index(xfers,XFER_ENTRY,i).week_day]++;
      }

      graph_guint32_bars(graph_image,8,stat_day,stat_name,NULL,1000,-1);
}

/* ================================================================ */
static void graph_by_monthday_xfer(GdkPixmap *graph_image, XFER_TYPE direction)
{
      guint32 stat_day[32];         /* 31 for 31 days (1-31) + 1 (the 0) */
      int i;
      const char *stat_name[32]={"?","1",NULL,NULL,NULL,"5",NULL,NULL,NULL,NULL,"10",
                        NULL,NULL,NULL,NULL,"15",NULL,NULL,NULL,NULL,"20",NULL,NULL,NULL,NULL,"25",NULL,NULL,NULL,NULL,"30",NULL};

      for(i=0;i<32;i++)
            stat_day[i]=0;

      for(i=0;i<xfers->len;i++)
      {
            if(g_array_index(xfers,XFER_ENTRY,i).xfer_type==direction)
                  stat_day[g_array_index(xfers,XFER_ENTRY,i).month_day]++;
      }

      graph_guint32_bars(graph_image,32,stat_day,stat_name,NULL,1000,today_monthday);
}

/* ================================================================ */
static void graph_by_weekday_size(GdkPixmap *graph_image, XFER_TYPE direction)
{
      double stat_day[8];           /* 8 for 7 days (1-7) + 1 bad day */
      const char *stat_name[8]={_("Unknown"),_("Monday"),_("Tuesday"),_("Wednesday"),_("Thursday"),_("Friday"),_("Saturday"),_("Sunday")};
      int i;

      for(i=0;i<8;i++)
            stat_day[i]=0;

      for(i=0;i<xfers->len;i++)
      {
            if(g_array_index(xfers,XFER_ENTRY,i).xfer_type==direction)
                  stat_day[g_array_index(xfers,XFER_ENTRY,i).week_day]+=g_array_index(xfers,XFER_ENTRY,i).xfer_size;
      }

      graph_double_bars(graph_image,8,stat_day,stat_name,_("B"),1024,-1);
}

/* ================================================================ */
static void graph_by_monthday_size(GdkPixmap *graph_image, XFER_TYPE direction)
{
      double stat_day[32];          /* 31 for 31 days (1-31) + 1 (the 0) */
      int i;
      const char *stat_name[32]={"?","1",NULL,NULL,NULL,"5",NULL,NULL,NULL,NULL,"10",
                        NULL,NULL,NULL,NULL,"15",NULL,NULL,NULL,NULL,"20",NULL,NULL,NULL,NULL,"25",NULL,NULL,NULL,NULL,"30",NULL};

      for(i=0;i<32;i++)
            stat_day[i]=0;

      for(i=0;i<xfers->len;i++)
      {
            if(g_array_index(xfers,XFER_ENTRY,i).xfer_type==direction)
                  stat_day[g_array_index(xfers,XFER_ENTRY,i).month_day]+=g_array_index(xfers,XFER_ENTRY,i).xfer_size;
      }

      graph_double_bars(graph_image,32,stat_day,stat_name,_("B"),1024,today_monthday);
}

/* ================================================================ */
static void graph_by_weekday(GdkPixmap *graph_image, XFER_TYPE direction, int graph_display_type)
{
      switch(graph_display_type)
      {
            case GRAPH_BY_TRANSFER: graph_by_weekday_xfer(graph_image,direction);
                                                            break;
            case GRAPH_BY_SIZE:           graph_by_weekday_size(graph_image,direction);
                                                            break;
      }
}

static void graph_by_monthday(GdkPixmap *graph_image, XFER_TYPE direction, int graph_display_type)
{
      switch(graph_display_type)
      {
            case GRAPH_BY_TRANSFER: graph_by_monthday_xfer(graph_image,direction);
                                                            break;
            case GRAPH_BY_SIZE:           graph_by_monthday_size(graph_image,direction);
                                                            break;
      }
}

/* ================================================================ */
/*****************************************************/
/* build a GdkImage containing the requested graphic */
/*****************************************************/
/* if w or h == -1, its value is left unchanged */
/************************************************/
void build_graph_image(gint w, gint h)
{
      struct tm *stm;
      time_t now;
      static gboolean init_val=FALSE;

      now=time(NULL);
      stm=localtime(&now);
      today_monthday=stm->tm_mday;

      if(graph_dl_image!=NULL)
      {
            gdk_pixmap_unref(graph_dl_image);
            graph_dl_image=NULL;
      }

      if(graph_ul_image!=NULL)
      {
            gdk_pixmap_unref(graph_ul_image);
            graph_ul_image=NULL;
      }

      if(w!=-1)
            graph_image_w=w;
      if(h!=-1)
            graph_image_h=h;

      if((graph_image_w==-1)||(graph_image_h==-1))
            return;

      graph_dl_image=gdk_pixmap_new(NULL,graph_image_w,graph_image_h,graph_depth);
      graph_ul_image=gdk_pixmap_new(NULL,graph_image_w,graph_image_h,graph_depth);

      if(graph_dl_image)
      {
            if(!init_val)
            {
                  init_values();
                  init_val=TRUE;
            }
      
            gdk_gc_set_foreground(graph_gc,&white);
            gdk_draw_rectangle(graph_dl_image,graph_gc,TRUE,0,0,graph_image_w, graph_image_h);

            switch(graph_dl_type)
            {
                  case GRAPH_BY_WEEKDAY:  graph_by_weekday(graph_dl_image,XFER_IS_DL,graph_dl_display_type);
                                                                  break;
                  case GRAPH_BY_MONTHDAY: graph_by_monthday(graph_dl_image,XFER_IS_DL,graph_dl_display_type);
                                                                  break;
            }
      }

      if(graph_ul_image)
      {
            if(!init_val)
            {
                  init_values();
                  init_val=TRUE;
            }
      
            gdk_gc_set_foreground(graph_gc,&white);
            gdk_draw_rectangle(graph_ul_image,graph_gc,TRUE,0,0,graph_image_w, graph_image_h);

            switch(graph_ul_type)
            {
                  case GRAPH_BY_WEEKDAY:  graph_by_weekday(graph_ul_image,XFER_IS_UL,graph_ul_display_type);
                                                                  break;
                  case GRAPH_BY_MONTHDAY: graph_by_monthday(graph_ul_image,XFER_IS_UL,graph_ul_display_type);
                                                                  break;
            }
      }
}

/* ========================================================================== */
/* ========================================================================== */
/* ========================================================================== */
/*************************************/
/* clear the list of registered XFER */
/*************************************/
void graph_stat_clear(void)
{
      if(xfers!=NULL)
            g_array_free(xfers,TRUE);
      xfers=g_array_new(FALSE,FALSE,sizeof(XFER_ENTRY));
}

/*************************************/
/* register a new XFER for the graph */
/*************************************/
void graph_stat_add(time_t end_time, guint64 size, XFER_TYPE xfer_type)
{
      XFER_ENTRY xe;
      struct tm stm;
      GDate gd;
      GDate gd_now;
      time_t now;

      localtime_r(&end_time,&stm);
      g_date_set_dmy(&gd, stm.tm_mday, stm.tm_mon+1, stm.tm_year);

      now=time(NULL);
      localtime_r(&now,&stm);
      g_date_set_dmy(&gd_now, stm.tm_mday, stm.tm_mon+1, stm.tm_year);

      if(g_date_days_between(&gd,&gd_now)>30)
            return;

      xe.julian_day=g_date_get_julian(&gd);
      xe.week_day=g_date_get_weekday(&gd);
      xe.month_day=g_date_get_day(&gd);
      xe.xfer_size=size;
      xe.xfer_type=xfer_type;

      g_array_append_val(xfers,xe);
}


Generated by  Doxygen 1.6.0   Back to index