/* * (c) 2001 Juan Carlos Orozco * * PLC point type conversions taken from /mmi/curses/vitrine.c from * Jiri Baum and Mario de Sousa * * Offered to the public 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. * * This code is made available on the understanding that it will not be * used in safety-critical situations without a full and competent review. */ /* * TODO * * Add new widgets: * Add more widgets for analog or digital input and output. (Button, Scroller, etc) * An image widget that will display one of two images depending on the digital value. * Gauge widget. * * Write errors to the plc log. * * When trying to open an already oppened window send it to the foreground * * Pre-assign the widget types to variables to optimize execution time. */ /* * Functions that need to be edited or created to add support for a new widget: * * x_widget - Where x is the type of the new widget. Update the value * from the plc or variable to the widget. * parse_connection - Add a case for the new type and call xWidget * * In case the widget is for data entry also edit: * * x_widget_update - Add the variable update from the new entered value. * updateValue - Add a case for the new type and call xWidgetUpdate * * Note: the new widget should be supported by glade and libglade, otherwise * more changes should be made (to glade, libglade). */ /* DEBUGING */ #define DEBUG_gnome_pixmap_widget #undef DEBUG_gnome_pixmap_widget #define DEBUG_hmi_GnomePixmap_read_matplc_conf #undef DEBUG_hmi_GnomePixmap_read_matplc_conf #define DEBUG_hmi_GtkLabel_read_matplc_conf #undef DEBUG_hmi_GtkLabel_read_matplc_conf #define DEBUG_init_widget_data #undef DEBUG_init_widget_data #define GTKEXTRA #undef GTKEXTRA #define GTKSOCKET #undef GTKSOCKET #include #include #include #include #include /* includes for GtkSocket */ #ifdef GTKSOCKET #include #endif /* includes for GtkPlotCanvas */ #ifdef GTKEXTRA #include #include #include #include #include #define DEFAULT_XMIN 0 #define DEFAULT_XMAX 20 #define DEFAULT_YMIN 0 #define DEFAULT_YMAX 20 #define DEFAULT_SAMPLETIME 0.5 #define DEFAULT_WIDGET_HEIGHT 600 #define DEFAULT_WIDGET_WIDTH 600 #define DEFAULT_SYMBOLSIZE 2 #define DEFAULT_LINEWIDTH 1 #define AXIS_TICKS_MAJOR 0.1 #define AXIS_TICKS_MINOR 1 #endif /* define version ourselves, really this should be defined by the build process if we use autoconf/automake */ #define VERSION "1.0" /* The strings in the config file used to define what format the data is in */ #define f32_TYPE "f32" #define i32_TYPE "i32" #define u32_TYPE "u32" #define i16_TYPE "i16" #define u16_TYPE "u16" #define i8_TYPE "i8" #define u8_TYPE "u8" #define bool_TYPE "bool" typedef enum {bool_dt, i32_dt, u32_dt, i16_dt, u16_dt, i8_dt, u8_dt, f32_dt} data_type_t; /* Variables for GtKPlotCanvas */ typedef enum {false=0,true=1} t_boolean ; #ifdef GTKEXTRA typedef enum {timermode=0,plotxymode=1} mode ; typedef enum {notconfigured=0,configured=1} configuration ; typedef struct{ GtkPlotData *dataset; gdouble *px; gdouble *py; gchar *ylegend; gchar *ycolor; plc_pt_t xval; plc_pt_t yval; GtkPlotSymbolType symboltype; GtkPlotSymbolType symbolstyle; unsigned int symbolsize; GtkPlotSymbolType linestyle; unsigned int linewidth; GtkPlotSymbolType pointconnect; } channel_t; typedef struct{ GtkWidget *plotfield; gint plotcount; plc_timer_t timer; t_boolean plotstart; GList * channellist; gchar *title; gchar *x_title; gchar *y_title; gchar *plot_bg_color; gchar *legend_bg_color; plc_pt_t startplot; plc_pt_t stopplot; plc_pt_t resetplot; mode plotmode; double sampletime; double timer_wait; double xmin; double xmax; double ymin; double ymax; double pos_draw_x; double pos_draw_y; double size_plot_x; double size_plot_y; double widget_width; double widget_height; configuration conf_title; configuration conf_widget; configuration conf_axis; configuration conf_color; configuration conf_timer; configuration conf_plotctrl; configuration conf_plotx; configuration conf_channel; configuration conf_channelcolor; configuration conf_mode; configuration conf_symboltype; configuration conf_symbolstyle; configuration conf_symbolsize; configuration conf_linestyle; configuration conf_linewidth; configuration conf_pointconnect; } plot_t; #endif /* data type to store GnomePixmap config data */ typedef struct{ int nbPixmap; char *widgetpattern; char **Pixmap; } hmi_GnomePixmap_tab_t; typedef struct{ int nbPixmapTab; hmi_GnomePixmap_tab_t *PixmapTab; } hmi_GnomePixmap_t; /* data type to store GtkLabel config data */ typedef struct{ char *widgetpattern; char *formatstring; } hmi_GtkLabel_tab_t; typedef struct{ int nbLabelTab; hmi_GtkLabel_tab_t *LabelTab; } hmi_GtkLabel_t; /* data type to store variables */ typedef struct{ data_type_t type; u32 value; } variable_t; /* data required to relate a widget with a plc point to form a connection */ typedef struct { GtkWidget *widget; plc_pt_t pt; variable_t *variable; /* Only data entry fields will use this field */ data_type_t data_type; /* Used by GnomePixmap */ char *on; /* for ON state */ char *off; /* for OFF state */ hmi_GnomePixmap_tab_t *PixmapTab; /* reference to pixmap table */ hmi_GtkLabel_tab_t *LabelTab; /* reference to label table */ GList *OptionMenuTab; /* reference to the OptionMenu table */ /* only for GtkPlotCanvas-Widget */ #ifdef GTKEXTRA plot_t * plot; #endif } connection_t; /* data required to relate a window with a list of connections to the plc */ typedef struct { gboolean first_scan; char *name; GList *connections; GtkWidget *widget; } window_node_t; /* this structure is used to search a window in a DList */ typedef struct{ gboolean found_it; char *name; } search_window_t; typedef struct{ int pv; plc_pt_t pt; }optionmenu_t; /* The window list pointer */ GList *windows; /* The variable list to allow several input widgets for the same PLC point * this table will point to u32 values which will represent the values to * update the PLC */ GHashTable *variables; /* a global pointer to the main window */ static GtkWidget *app; /* Global Config Data for GnomePixmap */ static hmi_GnomePixmap_t hmi_GnomePixmap; /* Global Config Data for GtkLabel*/ static hmi_GtkLabel_t hmi_GtkLabel; /* prototypes to avoid warnings */ void do_nothing(GtkWidget *w); void add_number(GtkWidget *w, gpointer data); void run_window(GtkWidget *w, gpointer data); void update_value(GtkWidget *w, gpointer data); void update_optionmenu(GtkWidget *w, gpointer data); /* Function to get a plc point variable */ /* -------------------- get_pt -------------------- */ plc_pt_t get_pt(const char *pt_name) { plc_pt_t pt_handle; pt_handle = plc_pt_by_name(pt_name); if (!pt_handle.valid) { plc_log_errmsg(0,"get_pt(): Could not get valid handle to %s.",pt_name); pt_handle = plc_pt_null(); } return pt_handle; } /* Just a spaceholder kind of a handler */ void do_nothing(GtkWidget *w) { gnome_app_message(GNOME_APP(app), "Doesn't do anything!"); } /* Print digital value in a label widget */ void label_digital_out(GtkWidget *w, gboolean state, char *on, char *off) { char s[10]; if(state) { if(on) sprintf(s, "%s", on); else sprintf(s, "X"); } else { if(off) sprintf(s, "%s", off); else sprintf(s, "-"); } gtk_label_set_text(GTK_LABEL(w), s); } /* Load a GnomePixmap widget image and resize it */ void load_gnome_pixmap(GtkWidget *widget, char *name){ gint width, height; GtkArg *gtk_arg; gtk_arg = malloc(sizeof(GtkArg)); gtk_arg->name = g_strdup("width"); gtk_widget_get(widget, gtk_arg); width = GTK_VALUE_INT(*gtk_arg); g_free(gtk_arg->name); gtk_arg->name = g_strdup("height"); gtk_widget_get(widget, gtk_arg); height = GTK_VALUE_INT(*gtk_arg); if((width > 0) && (height > 0)){ gnome_pixmap_load_file_at_size(GNOME_PIXMAP(widget), name, width, height); } else { gnome_pixmap_load_file(GNOME_PIXMAP(widget), name); } g_free(gtk_arg->name); free(gtk_arg); } #define BUFF_SIZE 128 /* Connect the different widget types */ void label_widget(connection_t *connection){ union { u32 u; f32 f; } tmp; #define u32_tmp (tmp.u) char str_buff[BUFF_SIZE]; char *sFormat=NULL; if(connection->data_type == bool_dt) label_digital_out(connection->widget, plc_get(connection->pt), connection->on, connection->off); else{ u32_tmp = plc_get(connection->pt); if ( connection->LabelTab != NULL ) { sFormat=connection->LabelTab->formatstring; } else { sFormat=NULL; } if (sFormat==NULL) { switch (connection->data_type) { case f32_dt: snprintf(str_buff, BUFF_SIZE, "%f", *((f32 *)&u32_tmp)); break; case i8_dt: snprintf(str_buff, BUFF_SIZE, "%d", *(( i8 *)&u32_tmp)); break; case u8_dt: snprintf(str_buff, BUFF_SIZE, "%d", *(( u8 *)&u32_tmp)); break; case i16_dt: snprintf(str_buff, BUFF_SIZE, "%d", *((i16 *)&u32_tmp)); break; case u16_dt: snprintf(str_buff, BUFF_SIZE, "%d", *((u16 *)&u32_tmp)); break; case i32_dt: snprintf(str_buff, BUFF_SIZE, "%d", *((i32 *)&u32_tmp)); break; case u32_dt: snprintf(str_buff, BUFF_SIZE, "%d", *((u32 *)&u32_tmp)); break; default : break; }; /* switch() */ } else { switch (connection->data_type) { case f32_dt: snprintf(str_buff, BUFF_SIZE, sFormat, *((f32 *)&u32_tmp)); break; case i8_dt: snprintf(str_buff, BUFF_SIZE, sFormat, *(( i8 *)&u32_tmp)); break; case u8_dt: snprintf(str_buff, BUFF_SIZE, sFormat, *(( u8 *)&u32_tmp)); break; case i16_dt: snprintf(str_buff, BUFF_SIZE, sFormat, *((i16 *)&u32_tmp)); break; case u16_dt: snprintf(str_buff, BUFF_SIZE, sFormat, *((u16 *)&u32_tmp)); break; case i32_dt: snprintf(str_buff, BUFF_SIZE, sFormat, *((i32 *)&u32_tmp)); break; case u32_dt: snprintf(str_buff, BUFF_SIZE, sFormat, *((u32 *)&u32_tmp)); break; default : break; }; } gtk_label_set_text(GTK_LABEL(connection->widget), str_buff); } #undef u32_tmp } /* This widget only takes float with 0.0 to 100.0 value range. * We could add the other types and convert them to 0.0 to 100.0 float values * using their min and max. * * 13.03.2003: Staedtler * Range is now limited by the widget settings. This is more * flexible and the widget does the job in a better way. */ void progress_widget(connection_t *connection){ f32 f32_tmp; f32_tmp = 0.0; switch (connection->data_type) { case f32_dt: f32_tmp = plc_get_f32(connection->pt); break; case i8_dt: break; case u8_dt: break; case i16_dt: break; case u16_dt: break; case i32_dt: break; case u32_dt: break; default : break; }; /* switch() */ gtk_progress_set_value(GTK_PROGRESS(connection->widget), f32_tmp); } void gnome_pixmap_widget(connection_t *connection){ char *image_name; char *image; int iPtab=0; union { u32 u; f32 f; } tmp; #define u32_tmp (tmp.u) /* Check previous state before doing */ if(plc_get(connection->pt) == connection->variable->value) return; #ifdef DEBUG_gnome_pixmap_widget printf("Widget=%s\n", gtk_widget_get_name(connection->widget)); #endif /* Save new value */ connection->variable->value = plc_get(connection->pt); u32_tmp = plc_get(connection->pt); switch (connection->data_type) { case bool_dt: if (u32_tmp) iPtab=1; else iPtab=0; break; case f32_dt: iPtab=*(( f32 *)&u32_tmp); break; case i8_dt: iPtab=*(( i8 *)&u32_tmp); break; case u8_dt: iPtab=*(( u8 *)&u32_tmp); break; case i16_dt: iPtab=*(( i16 *)&u32_tmp); break; case u16_dt: iPtab=*(( u16 *)&u32_tmp); break; case i32_dt: iPtab=*(( i32 *)&u32_tmp); break; case u32_dt: iPtab=*(( u32 *)&u32_tmp); break; default : break; }; /* switch() */ #ifdef DEBUG_gnome_pixmap_widget printf("gnome_pixmap_widget: iPtab=%d\n",iPtab); #endif image=NULL; if (connection->PixmapTab != NULL) { if ((connection->PixmapTab->nbPixmap)>0) { iPtab=iPtab % connection->PixmapTab->nbPixmap; image=connection->PixmapTab->Pixmap[iPtab]; } } else { if (iPtab) image=connection->on; else image=connection->off; } if (image!=NULL) { image_name = g_strdup_printf("%s.xpm",image); #ifdef DEBUG_gnome_pixmap_widget printf("gnome_pixmap_widget: image_name=%s\n",image_name); #endif load_gnome_pixmap(connection->widget, image_name); g_free(image_name); } #undef u32_tmp } /* Data entry widgets */ void toggle_button_widget(connection_t *connection){ if(connection->data_type == bool_dt){ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(connection->widget), (gboolean)connection->variable->value); plc_set(connection->pt, connection->variable->value); } } void button_widget(connection_t *connection){ if(connection->data_type == bool_dt){ plc_set(connection->pt, connection->variable->value); } } void entry_widget(connection_t *connection){ /* Copy the Value from Widget to plc */ plc_set(connection->pt, connection->variable->value); } /* Initialize the entry widget text with init value from plc This Function is called only once by parse connection, when window->first_scan=1 */ void entry_widget_init(connection_t *connection){ union { u32 u; f32 f; } tmp; #define u32_tmp (tmp.u) char str_buff[BUFF_SIZE]; u32_tmp = connection->variable->value; switch (connection->data_type) { case f32_dt: snprintf(str_buff, BUFF_SIZE, "%f", *((f32 *)&u32_tmp)); break; case i8_dt: snprintf(str_buff, BUFF_SIZE, "%d", *(( i8 *)&u32_tmp)); break; case u8_dt: snprintf(str_buff, BUFF_SIZE, "%d", *(( u8 *)&u32_tmp)); break; case i16_dt: snprintf(str_buff, BUFF_SIZE, "%d", *((i16 *)&u32_tmp)); break; case u16_dt: snprintf(str_buff, BUFF_SIZE, "%d", *((u16 *)&u32_tmp)); break; case i32_dt: snprintf(str_buff, BUFF_SIZE, "%d", *((i32 *)&u32_tmp)); break; case u32_dt: snprintf(str_buff, BUFF_SIZE, "%d", *((u32 *)&u32_tmp)); break; case bool_dt: snprintf(str_buff, BUFF_SIZE, "%01d", *((i8 *)&u32_tmp)); break; default : break; }; /* switch() */ gtk_entry_set_text(GTK_ENTRY(connection->widget), str_buff); #undef u32_tmp } void scale_widget(connection_t *connection){ switch (connection->data_type) { case f32_dt: case u32_dt: case u16_dt: case u8_dt: case i32_dt: case i16_dt: case i8_dt: plc_set(connection->pt, connection->variable->value); break; default: break; } } /* Initialize the scale widget with init value from plc This Function is called only once by parse connection, when window->first_scan=1 */ void scale_widget_init(connection_t *connection){ u32 u32_tmp; u16 u16_tmp; u8 u8_tmp; i32 i32_tmp; i16 i16_tmp; i8 i8_tmp; f32 f32_tmp=0; GtkAdjustment *adjustment; adjustment=gtk_range_get_adjustment(GTK_RANGE(connection->widget)); switch (connection->variable->type) { case f32_dt: f32_tmp = *((f32 *)&(connection->variable->value)); break; case u32_dt: u32_tmp = *((u32 *)&(connection->variable->value)); f32_tmp=u32_tmp; break; case u16_dt: u16_tmp = *((u16 *)&(connection->variable->value)); f32_tmp=u16_tmp; break; case u8_dt: u8_tmp = *((u8 *)&(connection->variable->value)); f32_tmp=u8_tmp; break; case i32_dt: i32_tmp = *((i32 *)&(connection->variable->value)); f32_tmp=i32_tmp; break; case i16_dt: i16_tmp = *((i16 *)&(connection->variable->value)); f32_tmp=i16_tmp; break; case i8_dt: i8_tmp = *((i8 *)&(connection->variable->value)); f32_tmp=i8_tmp; break; default: break; } adjustment->value = f32_tmp; gtk_adjustment_value_changed(adjustment); } void spin_button_widget(connection_t *connection){ switch (connection->data_type) { case f32_dt: case u32_dt: case u16_dt: case u8_dt: case i32_dt: case i16_dt: case i8_dt: plc_set(connection->pt, connection->variable->value); break; default: break; } } /* Initialize the spinbutton widget with init value from plc This Function is called only once by parse connection, when window->first_scan=1 */ void spin_button_widget_init(connection_t *connection){ u32 u32_tmp; u16 u16_tmp; u8 u8_tmp; i32 i32_tmp; i16 i16_tmp; i8 i8_tmp; f32 f32_tmp=0; switch (connection->variable->type) { case f32_dt: f32_tmp = *((f32 *)&(connection->variable->value)); break; case u32_dt: u32_tmp = *((u32 *)&(connection->variable->value)); f32_tmp=u32_tmp; break; case u16_dt: u16_tmp = *((u16 *)&(connection->variable->value)); f32_tmp=u16_tmp; break; case u8_dt: u8_tmp = *((u8 *)&(connection->variable->value)); f32_tmp=u8_tmp; break; case i32_dt: i32_tmp = *((i32 *)&(connection->variable->value)); f32_tmp=i32_tmp; break; case i16_dt: i16_tmp = *((i16 *)&(connection->variable->value)); f32_tmp=i16_tmp; break; case i8_dt: i8_tmp = *((i8 *)&(connection->variable->value)); f32_tmp=i8_tmp; break; default: break; } gtk_spin_button_set_value(GTK_SPIN_BUTTON(connection->widget),f32_tmp); } #ifdef GTKEXTRA /* hmi_GtkPlotCanvas_check_sections() Check for necessary definitions in matplc.conf */ void hmi_GtkPlotCanvas_check_sections(connection_t *connection){ char *widgetname; int nbofrows=0; int i=0,j; int found; const char * section_tab[] = { "mode", "plotctrl", "channel", "-" }; #define DEBUG_CHECK_SECTIONS #undef DEBUG_CHECK_SECTIONS #ifdef DEBUG_CHECK_SECTIONS printf("hmi_GtkPlotCanvas_check_sections()\n"); #endif widgetname=gtk_widget_get_name(connection->widget); if( widgetname[0] == '_' ){ widgetname++; while (section_tab[i][0] != '-'){ #ifdef DEBUG_CHECK_SECTIONS printf("Searching for SECTION [%s] in matplc.conf ...",section_tab[i]); #endif nbofrows=conffile_get_table_rows(widgetname); found=0; for(j=0;jplot->plotstart=false; connection->plot->plotcount=0; connection->plot->conf_title = notconfigured; connection->plot->conf_widget = notconfigured; connection->plot->conf_axis = notconfigured; connection->plot->conf_color = notconfigured; connection->plot->conf_timer = notconfigured; connection->plot->conf_plotctrl = notconfigured; connection->plot->conf_plotx = notconfigured; connection->plot->conf_channel = notconfigured; connection->plot->conf_channelcolor = notconfigured; connection->plot->conf_mode = notconfigured; connection->plot->conf_symboltype = notconfigured; connection->plot->conf_symbolstyle = notconfigured; connection->plot->conf_linestyle = notconfigured; connection->plot->conf_linewidth = notconfigured; connection->plot->conf_pointconnect = notconfigured; character=(char *)"lightyellow"; connection->plot->plot_bg_color = (char *)g_malloc(strlen(character)); strcpy(connection->plot->plot_bg_color,character); character=(char *)"white"; connection->plot->legend_bg_color = (char *)g_malloc(strlen(character)); strcpy(connection->plot->legend_bg_color,character); /* Title */ character=(char *)"Title"; connection->plot->title = (char *)g_malloc(strlen(character)); strcpy(connection->plot->title,character); /* x_title */ character=(char *)"x"; connection->plot->x_title = (char *)g_malloc(strlen(character)); strcpy(connection->plot->x_title,character); /* y_title */ character=(char *)"y"; connection->plot->y_title = (char *)g_malloc(strlen(character)); strcpy(connection->plot->y_title,character); /* size_plot_x */ connection->plot->size_plot_x = 0.80; /* size_plot_y */ connection->plot->size_plot_y = 0.80; /* pos_draw_x */ connection->plot->pos_draw_x = 0.10; /* pos_draw_y */ connection->plot->pos_draw_y = 0.1; /* xmin */ connection->plot->xmin = DEFAULT_XMIN; /* xmax */ connection->plot->xmax = DEFAULT_XMAX; /* ymin */ connection->plot->ymin = DEFAULT_YMIN; /* ymax */ connection->plot->ymax = DEFAULT_YMAX; /* sampletime */ connection->plot->sampletime = DEFAULT_SAMPLETIME; } /* hmi_GtkPlotCanvas_check_dependence() check, if all variables are defined */ void hmi_GtkPlotCanvas_check_dependence(connection_t *connection){ int j; channel_t *channelPtr; #define DEBUG_CHECK_DEPENDENCE #undef DEBUG_CHECK_DEPENDENCE #ifdef DEBUG_CHECK_DEPENDENCE printf("hmi_GtkPlotCanvas_check_dependence()\n"); #endif if(connection->plot->plotmode==plotxymode){ if((connection->plot->conf_plotx)==notconfigured){ printf("ERROR: In mode you have to set plotx-points in matplc.conf\n"); exit(1); } } if((connection->plot->conf_channelcolor)==notconfigured){ for(j=0;jplot->plotcount;j++){ channelPtr=g_list_nth_data(connection->plot->channellist,j); channelPtr->ycolor = g_strdup("red"); } } } /* hmi_GtkPlotCanvas_read_matplc_conf() Read configuration from matplc.conf */ void hmi_GtkPlotCanvas_read_matplc_conf(connection_t *connection){ char *retval; char *widgetname; int i,j,k; int nbofrows=0; int nbofcols=0; int ret; f32 f32_tmp; i32 i32_tmp; channel_t *channel; channel_t *channelPtr; const char * symboltype_tab[] = { "none", "square", "circle", "up_triangle", "down_triangle", "right_triangle", "left_triangle", "diamond", "plus", "cross", "star", "dot","impulse", "-" }; const char * symbolstyle_tab[] = { "empty", "filled", "opaque", "-" }; const char * linestyle_tab[] = { "none", "solid", "dotted", "dashed", "dot_dash", "dot_dot_dash", "dot_dash_dash", "-" }; const char * pointconnect_tab[] = { "none", "straight", "spline", "hv_step", "vh_step", "middle_step", "-" }; #define DEBUG_READ_MATPLC_CONF #undef DEBUG_READ_MATPLC_CONF #ifdef DEBUG_READ_MATPLC_CONF printf("hmi_GtkPlotCanvas_read_matplc_conf()\n"); #endif widgetname=gtk_widget_get_name(connection->widget); if( widgetname[0] == '_' ){ widgetname++; nbofrows=conffile_get_table_rows(widgetname); for(i=0;iplot->plotcount=nbofcols-1; for(j=0;jplot->plotcount;j++){ channel = (channel_t *)g_malloc(sizeof(channel_t)); channel->dataset=NULL; channel->px=NULL; channel->py=NULL; channel->ylegend=NULL; channel->ycolor=NULL; channel->symboltype=GTK_PLOT_SYMBOL_STAR; channel->symbolstyle=GTK_PLOT_SYMBOL_OPAQUE; channel->symbolsize=DEFAULT_SYMBOLSIZE; channel->linestyle=GTK_PLOT_LINE_SOLID; channel->linewidth=DEFAULT_LINEWIDTH; channel->pointconnect=GTK_PLOT_CONNECT_STRAIGHT; connection->plot->channellist=g_list_append(connection->plot->channellist,channel); } } } for(i=0;iplot->conf_title = configured; /* Title */ retval=conffile_get_table(widgetname,i,1); connection->plot->title = (char *)g_malloc(strlen(retval)); strcpy(connection->plot->title,retval); #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->title = %s\n",connection->plot->title); #endif /* x_title */ retval=conffile_get_table(widgetname,i,2); connection->plot->x_title = (char *)g_malloc(strlen(retval)); strcpy(connection->plot->x_title,retval); #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->title = %s\n",connection->plot->x_title); #endif /* y_title */ retval=conffile_get_table(widgetname,i,3); connection->plot->y_title = (char *)g_malloc(strlen(retval)); strcpy(connection->plot->y_title,retval); #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->title = %s\n",connection->plot->y_title); #endif } /* [SECTION: timer] */ if(g_strcasecmp(conffile_get_table(widgetname,i,0),"timer")==0){ connection->plot->conf_timer = configured; /* sampletime */ ret=conffile_get_table_f32(widgetname,i,1,&(f32_tmp), 1E-12, 1E12, DEFAULT_SAMPLETIME); if(ret!=0){ connection->plot->sampletime = DEFAULT_SAMPLETIME; }else{ connection->plot->sampletime = f32_tmp; } #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->sampletime = %f\n",connection->plot->sampletime); #endif } /* [SECTION: plotctrl] */ if(g_strcasecmp(conffile_get_table(widgetname,i,0),"plotctrl")==0){ connection->plot->conf_plotctrl = configured; /* startplot */ retval=conffile_get_table(widgetname,i,1); if(retval==NULL){ printf("ERROR:Startplot not set in plotctrl (matplc.conf)\n"); exit(1); } connection->plot->startplot=get_pt(retval); #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->startplot made\n"); #endif /* stopplot */ retval=conffile_get_table(widgetname,i,2); if(retval==NULL){ printf("ERROR:Stopplot not set in plotctrl (matplc.conf)\n"); exit(1); } connection->plot->stopplot=get_pt(retval); #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->stopplot made\n"); #endif /* resetplot */ retval=conffile_get_table(widgetname,i,3); if(retval==NULL){ printf("ERROR:Resetplot not set in plotctrl (matplc.conf)\n"); exit(1); } connection->plot->resetplot=get_pt(retval); #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->resetplot made\n"); #endif } /* [SECTION: channel] */ if(g_strcasecmp(conffile_get_table(widgetname,i,0),"channel")==0){ connection->plot->conf_channel = configured; #ifdef DEBUG_READ_MATPLC_CONF printf("\tNumber of Curves: %d\n",connection->plot->plotcount); #endif /* yval */ for(j=0;jplot->plotcount;j++){ channelPtr=g_list_nth_data(connection->plot->channellist,j); retval=conffile_get_table(widgetname,i,j+1); channelPtr->ylegend = g_strdup(retval); channelPtr->yval=get_pt(retval); #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->yval[%d] made\n",j+1); printf("\tconnection->plot->ylegend[%d] = %s\n",j+1,channelPtr->ylegend); #endif } } /* [SECTION: mode] */ if(g_strcasecmp(conffile_get_table(widgetname,i,0),"mode")==0){ connection->plot->conf_mode = configured; /* plotmode */ retval=conffile_get_table(widgetname,i,1); if(g_strcasecmp(retval,"timer")==0){ connection->plot->plotmode = timermode; #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->mode = timer\n"); #endif }else if (g_strcasecmp(retval,"plotxy")==0) { connection->plot->plotmode = plotxymode; #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->mode = plotxy\n"); #endif }else{ printf("ERROR: PlotMode not set\n"); exit(1); } } /* [SECTION: plotx] */ if(g_strcasecmp(conffile_get_table(widgetname,i,0),"plotx")==0){ connection->plot->conf_plotx = configured; /* xval */ nbofcols=conffile_get_table_rowlen(widgetname, i); for(j=0;jplot->plotcount;j++){ channelPtr=g_list_nth_data(connection->plot->channellist,j); if( j < (nbofcols-1) ){ channelPtr->xval=get_pt(conffile_get_table(widgetname,i,j+1)); }else{ channelPtr->xval=get_pt(conffile_get_table(widgetname,i,1)); } #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->xval[%d] made\n",j+1); #endif } } /* [SECTION: channelcolor] */ if(g_strcasecmp(conffile_get_table(widgetname,i,0),"channelcolor")==0){ connection->plot->conf_channelcolor= configured; /* ycolor */ for(j=0;jplot->plotcount;j++){ channelPtr=g_list_nth_data(connection->plot->channellist,j); retval=conffile_get_table(widgetname,i,j+1); if(retval==NULL) retval=(char *)"red"; channelPtr->ycolor = g_strdup(retval); #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->ycolor[%d] = %s\n",j+1,channelPtr->ycolor); #endif } } /* [SECTION: axis] */ if(g_strcasecmp(conffile_get_table(widgetname,i,0),"axis")==0){ connection->plot->conf_axis = configured; /* xmin */ ret=conffile_get_table_f32(widgetname,i,1,&(f32_tmp), -1E12, 1E12, DEFAULT_XMIN); if(ret!=0){ connection->plot->xmin = DEFAULT_XMIN; }else{ connection->plot->xmin = f32_tmp; } #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->xmin = %f\n",connection->plot->xmin); #endif /* xmax */ ret=conffile_get_table_f32(widgetname,i,2,&(f32_tmp), -1E12, 1E12, DEFAULT_XMAX); if(ret!=0){ connection->plot->xmax = DEFAULT_XMAX; }else{ connection->plot->xmax = f32_tmp; } #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->xmax = %f\n",connection->plot->xmax); #endif /* ymin */ ret=conffile_get_table_f32(widgetname,i,3,&(f32_tmp), -1E12, 1E12, DEFAULT_YMIN); if(ret!=0){ connection->plot->ymin = DEFAULT_YMIN; }else{ connection->plot->ymin = f32_tmp; } #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->ymin = %f\n",connection->plot->ymin); #endif /* ymax */ ret=conffile_get_table_f32(widgetname,i,4,&(f32_tmp), -1E12, 1E12, DEFAULT_YMAX); if(ret!=0){ connection->plot->ymax = DEFAULT_YMAX; }else{ connection->plot->ymax = f32_tmp; } #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->ymax = %f\n",connection->plot->ymax); #endif } /* [SECTION: color] */ if(g_strcasecmp(conffile_get_table(widgetname,i,0),"color")==0){ connection->plot->conf_color = configured; /* plot_bg_color */ retval=conffile_get_table(widgetname,i,2); if(retval!=NULL) { connection->plot->plot_bg_color = (char *)g_malloc(strlen(retval)); strcpy(connection->plot->plot_bg_color,retval); } #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->plot_bg_color = %s\n",connection->plot->plot_bg_color); #endif /* legend_bg_color */ retval=conffile_get_table(widgetname,i,3); if(retval!=NULL) { connection->plot->legend_bg_color = (char *)g_malloc(strlen(retval)); strcpy(connection->plot->legend_bg_color,retval); } #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->legend_bg_color = %s\n",connection->plot->legend_bg_color); #endif } /* [SECTION: symboltype] */ if(g_strcasecmp(conffile_get_table(widgetname,i,0),"symboltype")==0){ connection->plot->conf_symboltype= configured; for(j=0;jplot->plotcount;j++){ channelPtr=g_list_nth_data(connection->plot->channellist,j); channelPtr->symboltype = GTK_PLOT_SYMBOL_STAR; retval=conffile_get_table(widgetname,i,j+1); if(retval!=NULL){ k=0; while( symboltype_tab[k][0] != '-' ){ if((g_strcasecmp(retval,symboltype_tab[k]))==0){ channelPtr->symboltype=k; #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->symboltype[%d] = %d\n",j+1,channelPtr->symboltype); #endif break; } k++; } } } } /* [SECTION: symbolstyle] */ if(g_strcasecmp(conffile_get_table(widgetname,i,0),"symbolstyle")==0){ connection->plot->conf_symbolstyle= configured; for(j=0;jplot->plotcount;j++){ channelPtr=g_list_nth_data(connection->plot->channellist,j); channelPtr->symbolstyle = GTK_PLOT_SYMBOL_OPAQUE; retval=conffile_get_table(widgetname,i,j+1); if(retval!=NULL){ k=0; while( symbolstyle_tab[k][0] != '-' ){ if((g_strcasecmp(retval,symbolstyle_tab[k]))==0){ channelPtr->symbolstyle=k; #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->symbolstyle[%d] = %d\n",j+1,channelPtr->symbolstyle); #endif break; } k++; } } } } /* [SECTION: linestyle] */ if(g_strcasecmp(conffile_get_table(widgetname,i,0),"linestyle")==0){ connection->plot->conf_linestyle= configured; for(j=0;jplot->plotcount;j++){ channelPtr=g_list_nth_data(connection->plot->channellist,j); channelPtr->linestyle = GTK_PLOT_LINE_SOLID; retval=conffile_get_table(widgetname,i,j+1); if(retval!=NULL){ k=0; while( linestyle_tab[k][0] != '-' ){ if((g_strcasecmp(retval,linestyle_tab[k]))==0){ channelPtr->linestyle=k; #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->linestyle[%d] = %d\n",j+1,channelPtr->linestyle); #endif break; } k++; } } } } /* [SECTION: pointconnect] */ if(g_strcasecmp(conffile_get_table(widgetname,i,0),"pointconnect")==0){ connection->plot->conf_pointconnect= configured; for(j=0;jplot->plotcount;j++){ channelPtr=g_list_nth_data(connection->plot->channellist,j); channelPtr->pointconnect = GTK_PLOT_CONNECT_STRAIGHT; retval=conffile_get_table(widgetname,i,j+1); if(retval!=NULL){ k=0; while( pointconnect_tab[k][0] != '-' ){ if((g_strcasecmp(retval,pointconnect_tab[k]))==0){ channelPtr->pointconnect=k; #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->pointconnect[%d] = %d\n",j+1,channelPtr->pointconnect); #endif break; } k++; } } } } /* [SECTION: linewidth] */ if(g_strcasecmp(conffile_get_table(widgetname,i,0),"linewidth")==0){ connection->plot->conf_linewidth= configured; for(j=0;jplot->plotcount;j++){ channelPtr=g_list_nth_data(connection->plot->channellist,j); ret=conffile_get_table_i32(widgetname,i,j+1,&(i32_tmp), 1, 100, DEFAULT_LINEWIDTH); if(ret!=0){ channelPtr->linewidth = DEFAULT_LINEWIDTH; }else{ channelPtr->linewidth = i32_tmp; } #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->linewidth[%d] = %d\n",j+1,channelPtr->linewidth); #endif } } /* [SECTION: symbolsize] */ if(g_strcasecmp(conffile_get_table(widgetname,i,0),"symbolsize")==0){ connection->plot->conf_symbolsize= configured; for(j=0;jplot->plotcount;j++){ channelPtr=g_list_nth_data(connection->plot->channellist,j); ret=conffile_get_table_i32(widgetname,i,j+1,&(i32_tmp), 1, 100, DEFAULT_SYMBOLSIZE); if(ret!=0){ channelPtr->symbolsize = DEFAULT_SYMBOLSIZE; }else{ channelPtr->symbolsize = i32_tmp; } #ifdef DEBUG_READ_MATPLC_CONF printf("\tconnection->plot->symbolsize[%d] = %d\n",j+1,channelPtr->symbolsize); #endif } } } } } /* hmi_GtkPlotCanvas_widget() Update function for GtkPlotCanvas Two modes: configuration through matplc.conf (1) timermode (2) plotxymode */ void hmi_GtkPlotCanvas_widget(connection_t *connection){ GtkPlot *gtkplot=NULL; gdouble x=0, y=0; gdouble xmin, xmax; gdouble xnewmin, xnewmax; int i,j; int newpoints=0; int startvalue=0; int stopvalue=0; gdouble *oldpxPtr; gdouble *oldpyPtr; t_boolean newpoint_timer=false; t_boolean newpoint_xy=false; channel_t *channelPtr; #define DEBUG_GTKPLOTCANVAS_WIDGET #undef DEBUG_GTKPLOTCANVAS_WIDGET /* Detect plotstart in timer-mode -> start timer */ if((connection->plot->plotstart==false)&&(plc_get(connection->plot->startplot))){ connection->plot->plotstart=true; if(connection->plot->plotmode==timermode) plc_timer_enable(connection->plot->timer); #ifdef DEBUG_GTKPLOTCANVAS_WIDGET printf("Plotstart=yes\n"); #endif } /* Detect plotstop in timer-mode -> stop timer */ if((connection->plot->plotstart==true)&&(plc_get(connection->plot->stopplot))){ if(connection->plot->plotmode==timermode){ plc_timer_disable(connection->plot->timer); } connection->plot->plotstart=false; #ifdef DEBUG_GTKPLOTCANVAS_WIDGET printf("Plotstart=false\n"); #endif } /* Detect resetplot --> clear points, set new range, etc. in timer-mode -> restart timer */ if(plc_get(connection->plot->resetplot)){ if(connection->plot->plotmode==timermode){ plc_timer_clear(connection->plot->timer); connection->plot->timer_wait=(connection->plot->sampletime); plc_timer_disable(connection->plot->timer); } connection->plot->plotstart=false; #ifdef DEBUG_GTKPLOTCANVAS_WIDGET printf("Resetting Plot: Plotstart=false\n"); #endif /* Clear all points */ for(i=0;iplot->plotcount;i++){ channelPtr=g_list_nth_data(connection->plot->channellist,i); #ifdef DEBUG_GTKPLOTCANVAS_WIDGET printf("Clearing Points: Plotcount=%d\n",connection->plot->plotcount); #endif channelPtr->px = (gdouble *)g_realloc(channelPtr->px, (1)*sizeof(gdouble)); channelPtr->py = (gdouble *)g_realloc(channelPtr->py, (1)*sizeof(gdouble)); /* void gtk_plot_data_set_x (GtkPlotData *data,gdouble *x); */ gtk_plot_data_set_x(channelPtr->dataset, channelPtr->px); /* void gtk_plot_data_set_y (GtkPlotData *data,gdouble *y); */ gtk_plot_data_set_y(channelPtr->dataset, channelPtr->py); /* void gtk_plot_data_set_numpoints (GtkPlotData *data,gint num_points); */ gtk_plot_data_set_numpoints(channelPtr->dataset, 0); } gtkplot = GTK_PLOT(connection->plot->plotfield); gtk_plot_set_xrange(gtkplot, connection->plot->xmin , connection->plot->xmax); gtk_plot_canvas_paint(GTK_PLOT_CANVAS(connection->widget)); gtk_plot_canvas_refresh(GTK_PLOT_CANVAS(connection->widget)); } /* Timer-Mode */ if ( (connection->plot->plotmode==timermode) && (plc_timer_done(connection->plot->timer, connection->plot->timer_wait)) ){ #ifdef DEBUG_GTKPLOTCANVAS_WIDGET printf("Timer-Mode: Getting new Point\n"); #endif newpoint_timer=true; }else{ newpoint_timer=false; } /* xyplot-Mode */ if (connection->plot->plotmode==plotxymode){ newpoint_xy=false; for(i=0;iplot->plotcount;i++){ channelPtr=g_list_nth_data(connection->plot->channellist,i); if (connection->plot->plotstart==true){ x=plc_get_f32(channelPtr->xval); y=plc_get_f32(channelPtr->yval); if(channelPtr->dataset->num_points>0){ if( (fabs( (channelPtr->px[(channelPtr->dataset->num_points)-1]) - x )) > 1.0E-8 ){ newpoint_xy=true; #ifdef DEBUG_GTKPLOTCANVAS_WIDGET printf("XY-Mode: Getting new x Point for channel %s\n",channelPtr->ylegend); #endif break; }else if( (fabs( (channelPtr->py[(channelPtr->dataset->num_points)-1]) - y )) > 1.0E-8 ){ newpoint_xy=true; #ifdef DEBUG_GTKPLOTCANVAS_WIDGET printf("XY-Mode: Getting new y Point for channel %s\n",channelPtr->ylegend); #endif break; } }else{ newpoint_xy=true; #ifdef DEBUG_GTKPLOTCANVAS_WIDGET printf("XY-Mode: Getting first Point for channel %s\n",channelPtr->ylegend); #endif break; } } } } if( newpoint_timer || newpoint_xy ) { #ifdef DEBUG_GTKPLOTCANVAS_WIDGET printf("Plotting new Point\n"); #endif /* #define GTK_PLOT(obj) GTK_CHECK_CAST (obj, gtk_plot_get_type (), GtkPlot) #define GTK_CHECK_CAST(tobj, cast_type, cast) ((cast*) gtk_type_check_object_cast ((GtkTypeObject*) (tobj), (cast_type))) */ gtkplot = GTK_PLOT(connection->plot->plotfield); #ifdef DEBUG_GTKPLOTCANVAS_WIDGET printf("Plotcount = %d\n",connection->plot->plotcount); #endif /* void gtk_plot_get_xrange (GtkPlot *plot,gdouble *xmin, gdouble *xmax); */ gtk_plot_get_xrange(gtkplot, &xmin , &xmax); xnewmin=xmin; xnewmax=xmax; for(i=0;iplot->plotcount;i++){ channelPtr=g_list_nth_data(connection->plot->channellist,i); channelPtr->px = (gdouble *)g_realloc(channelPtr->px, (channelPtr->dataset->num_points+1)*sizeof(gdouble)); channelPtr->py = (gdouble *)g_realloc(channelPtr->py, (channelPtr->dataset->num_points+1)*sizeof(gdouble)); y=plc_get_f32(channelPtr->yval); if(newpoint_timer){ x = connection->plot->timer_wait; xnewmin=x; xnewmax=x; }else if(newpoint_xy){ x=plc_get_f32(channelPtr->xval); if(x>xnewmax) xnewmax=x; if(xpx[channelPtr->dataset->num_points] = x; channelPtr->py[channelPtr->dataset->num_points] = y; /* void gtk_plot_data_set_x (GtkPlotData *data,gdouble *x); */ gtk_plot_data_set_x(channelPtr->dataset, channelPtr->px); /* void gtk_plot_data_set_y (GtkPlotData *data,gdouble *y); */ gtk_plot_data_set_y(channelPtr->dataset, channelPtr->py); /* void gtk_plot_data_set_numpoints (GtkPlotData *data,gint num_points); */ gtk_plot_data_set_numpoints(channelPtr->dataset, channelPtr->dataset->num_points+1); } if( (xnewmax > xmax) || (xnewmin < xmin) ){ channelPtr=g_list_nth_data(connection->plot->channellist,0); startvalue=0; stopvalue=(channelPtr->dataset->num_points); newpoints=(channelPtr->dataset->num_points); if( xnewmax > xmax ){ xmax=xnewmax+0.9*(connection->plot->xmax-connection->plot->xmin); xmin=xnewmax-0.1*(connection->plot->xmax-connection->plot->xmin); /* get startvalue for next plot */ for(j=startvalue;jpx[j]) >= xmin ){ newpoints=(channelPtr->dataset->num_points)-j; startvalue=j; break; } } }else{ xmax=xnewmin+0.1*(connection->plot->xmax-connection->plot->xmin); xmin=xnewmin-0.9*(connection->plot->xmax-connection->plot->xmin);; /* get startvalue for next plot */ for(j=startvalue;jpx[j]) <= xmax ){ newpoints=(channelPtr->dataset->num_points)-j; startvalue=j; break; } } } for(i=0;iplot->plotcount;i++){ channelPtr=g_list_nth_data(connection->plot->channellist,i); oldpxPtr=channelPtr->px; channelPtr->px = (gdouble *) g_memdup(&(channelPtr->px[startvalue]), newpoints*sizeof(gdouble)); g_free(oldpxPtr); oldpxPtr=NULL; oldpyPtr=channelPtr->py; channelPtr->py = (gdouble *) g_memdup(&(channelPtr->py[startvalue]), newpoints*sizeof(gdouble)); g_free(oldpyPtr); oldpyPtr=NULL; /* void gtk_plot_data_set_x (GtkPlotData *data,gdouble *x); */ gtk_plot_data_set_x(channelPtr->dataset, channelPtr->px); /* void gtk_plot_data_set_y (GtkPlotData *data,gdouble *y); */ gtk_plot_data_set_y(channelPtr->dataset, channelPtr->py); gtk_plot_data_set_numpoints(channelPtr->dataset, newpoints); } /* void gtk_plot_set_range (GtkPlot *plot,gdouble xmin, gdouble xmax,gdouble ymin, gdouble ymax); */ gtk_plot_set_xrange(gtkplot, xmin , xmax); /* void gtk_plot_canvas_paint (GtkPlotCanvas *canvas); Paint the canvas(update the changes) */ gtk_plot_canvas_paint(GTK_PLOT_CANVAS(connection->widget)); /* void gtk_plot_canvas_refresh (GtkPlotCanvas *canvas); Refresh the canvas */ gtk_plot_canvas_refresh(GTK_PLOT_CANVAS(connection->widget)); }else { for(i=0;iplot->plotcount;i++){ channelPtr=g_list_nth_data(connection->plot->channellist,i); /* void gtk_plot_data_draw_points (GtkPlotData *data,gint n); */ gtk_plot_data_draw_points(channelPtr->dataset, 1); } /* void gtk_plot_refresh (GtkPlot *plot,GdkRectangle *area); ------------------------------------------------------------------------------------------ Refresh a certain area of the plot-> plot -> a GtkPlot widget area -> area to be refreshed */ gtk_plot_refresh(gtkplot, NULL); } if(newpoint_timer) connection->plot->timer_wait+=(connection->plot->sampletime); } } /* hmi_GtkPlotCanvas_widget_init() Initialize widget */ void hmi_GtkPlotCanvas_widget_init(connection_t *connection){ GdkColor color; channel_t *channelPtr; int i; #define DEBUG_GTKPLOTCANVAS_WIDGET_INIT #undef DEBUG_GTKPLOTCANVAS_WIDGET_INIT #ifdef DEBUG_GTKPLOTCANVAS_WIDGET_INIT printf("hmi_GtkPlotCanvas_widget_init()\n"); #endif hmi_GtkPlotCanvas_set_defaults(connection); hmi_GtkPlotCanvas_check_sections(connection); hmi_GtkPlotCanvas_read_matplc_conf(connection); hmi_GtkPlotCanvas_check_dependence(connection); /* Init timer */ plc_timer_start(connection->plot->timer); plc_timer_disable(connection->plot->timer); /* Create new plotfield */ connection->plot->plotfield = (GtkWidget *)g_malloc(sizeof(GtkWidget *)); /* GtkWidget* gtk_plot_new_with_size (GdkDrawable *drawable,gdouble width, gdouble height); ------------------------------------------------------------------------------------------ Create a new GtkPlot widget with specified dimensions drawable -> A drawable Gdk widget width,height -> Width,height of the new GtkPlot widget in percentage of widget size Returns a new GtkPlot widget */ connection->plot->plotfield = gtk_plot_new_with_size(NULL,connection->plot->size_plot_x,connection->plot->size_plot_y); gdk_color_parse(connection->plot->plot_bg_color, &color); gdk_color_alloc(gtk_widget_get_colormap(connection->plot->plotfield), &color); /* void gtk_plot_set_background (GtkPlot *plot,const GdkColor *background); */ gtk_plot_set_background(GTK_PLOT(connection->plot->plotfield), &color); gdk_color_parse(connection->plot->legend_bg_color, &color); gdk_color_alloc(gtk_widget_get_colormap(connection->widget), &color); /* void gtk_plot_legends_set_attributes (GtkPlot *plot,const gchar *font,gint height, const GdkColor *foreground,const GdkColor *background); font -> font name; height -> height of the font; foreground,background -> colors of the text */ gtk_plot_legends_set_attributes(GTK_PLOT(connection->plot->plotfield),NULL, 0,NULL,&color); /* void gtk_plot_set_range (GtkPlot *plot,gdouble xmin, gdouble xmax,gdouble ymin, gdouble ymax); */ gtk_plot_set_range(GTK_PLOT(connection->plot->plotfield), connection->plot->xmin ,connection->plot->xmax, connection->plot->ymin, connection->plot->ymax); /* void gtk_plot_axis_set_ticks (GtkPlot *plot,GtkPlotOrientation orientation,gdouble major_step,gint nminor); ------------------------------------------------------------------------------------------ typedef enum{GTK_PLOT_AXIS_X,GTK_PLOT_AXIS_Y,GTK_PLOT_AXIS_Z} GtkPlotOrientation; */ gtk_plot_axis_set_ticks(GTK_PLOT(connection->plot->plotfield), GTK_PLOT_AXIS_X, (connection->plot->xmax-connection->plot->xmin)*AXIS_TICKS_MAJOR, AXIS_TICKS_MINOR); gtk_plot_axis_set_ticks(GTK_PLOT(connection->plot->plotfield), GTK_PLOT_AXIS_Y, (connection->plot->ymax-connection->plot->ymin)*AXIS_TICKS_MAJOR, AXIS_TICKS_MINOR); /* void gtk_plot_axis_set_labels_numbers (GtkPlot *plot,GtkPlotAxisPos axis,gint style,gint precision); ------------------------------------------------------------------------------------------ typedef enum{GTK_PLOT_AXIS_LEFT,GTK_PLOT_AXIS_RIGHT,GTK_PLOT_AXIS_TOP,GTK_PLOT_AXIS_BOTTOM} GtkPlotAxisPos; typedef enum{GTK_PLOT_LABEL_FLOAT,GTK_PLOT_LABEL_EXP,GTK_PLOT_LABEL_POW} GtkPlotLabelStyle; */ i=(int)(ceil(log10(1.0/((connection->plot->xmax-connection->plot->xmin)*AXIS_TICKS_MAJOR)))); if(i<0)i=0; gtk_plot_axis_set_labels_numbers(GTK_PLOT(connection->plot->plotfield), GTK_PLOT_AXIS_TOP,GTK_PLOT_LABEL_FLOAT,i); gtk_plot_axis_set_labels_numbers(GTK_PLOT(connection->plot->plotfield), GTK_PLOT_AXIS_BOTTOM, GTK_PLOT_LABEL_FLOAT,i); i=(int)(ceil(log10(1.0/((connection->plot->ymax-connection->plot->ymin)*AXIS_TICKS_MAJOR)))); if(i<0)i=0; gtk_plot_axis_set_labels_numbers(GTK_PLOT(connection->plot->plotfield), GTK_PLOT_AXIS_LEFT,GTK_PLOT_LABEL_FLOAT,i); gtk_plot_axis_set_labels_numbers(GTK_PLOT(connection->plot->plotfield), GTK_PLOT_AXIS_RIGHT, GTK_PLOT_LABEL_FLOAT,i); /* void gtk_plot_axis_set_visible (GtkPlot *plot,GtkPlotAxisPos axis,gboolean visible); */ gtk_plot_axis_set_visible(GTK_PLOT(connection->plot->plotfield), GTK_PLOT_AXIS_TOP, TRUE); gtk_plot_axis_set_visible(GTK_PLOT(connection->plot->plotfield), GTK_PLOT_AXIS_RIGHT, TRUE); /* void gtk_plot_grids_set_visible (GtkPlot *plot,gboolean vmajor,gboolean vminor,gboolean hmajor,gboolean hminor); */ gtk_plot_grids_set_visible(GTK_PLOT(connection->plot->plotfield), TRUE, TRUE, TRUE, TRUE); /* void gtk_plot_canvas_add_plot (GtkPlotCanvas *plot_canvas,GtkPlot *plot,gdouble x, gdouble y); ------------------------------------------------------------------------------------------ x,y -> the coordinates of the plot in percentage of widget size */ gtk_plot_canvas_add_plot(GTK_PLOT_CANVAS(connection->widget), GTK_PLOT(connection->plot->plotfield),connection->plot->pos_draw_x,connection->plot->pos_draw_y); /* void gtk_plot_axis_hide_title (GtkPlot *plot,GtkPlotAxisPos axis); */ gtk_plot_axis_hide_title(GTK_PLOT(connection->plot->plotfield), GTK_PLOT_AXIS_TOP); gtk_plot_axis_hide_title(GTK_PLOT(connection->plot->plotfield), GTK_PLOT_AXIS_RIGHT); /* void gtk_plot_axis_set_title (GtkPlot *plot,GtkPlotAxisPos axis, const gchar *title); */ gtk_plot_axis_set_title(GTK_PLOT(connection->plot->plotfield), GTK_PLOT_AXIS_LEFT, connection->plot->y_title); gtk_plot_axis_set_title(GTK_PLOT(connection->plot->plotfield), GTK_PLOT_AXIS_BOTTOM, connection->plot->x_title); /* void gtk_plot_axis_move_title (GtkPlot *plot, GtkPlotAxisPos axis, gint angle, gdouble x, gdouble y); */ gtk_plot_axis_move_title(GTK_PLOT(connection->plot->plotfield), GTK_PLOT_AXIS_LEFT, 90, 0.03, 0.5); gtk_plot_axis_move_title(GTK_PLOT(connection->plot->plotfield), GTK_PLOT_AXIS_BOTTOM, 0, 0.5 , 0.98); /* void gtk_plot_set_legends_border (GtkPlot *plot,GtkPlotBorderStyle border,gint shadow_width); ------------------------------------------------------------------------------------------ typedef enum{GTK_PLOT_BORDER_NONE,GTK_PLOT_BORDER_LINE,GTK_PLOT_BORDER_SHADOW,} GtkPlotBorderStyle; */ gtk_plot_set_legends_border(GTK_PLOT(connection->plot->plotfield), GTK_PLOT_BORDER_SHADOW, 3); /* void gtk_plot_legends_move (GtkPlot *plot,gdouble x, gdouble y); ------------------------------------------------------------------------------------------ x,y -> new coordinates of the legend */ gtk_plot_legends_move(GTK_PLOT(connection->plot->plotfield), .70, .05); gtk_widget_show(connection->plot->plotfield); /* GtkPlotCanvasChild * gtk_plot_canvas_put_text (GtkPlotCanvas *canvas,gdouble x,gdouble y,const gchar *font, gint height,gint angle,const GdkColor *fg,const GdkColor *bg,gboolean transparent, GtkJustification justification,const gchar *text); ------------------------------------------------------------------------------------------ Insert text in the canvas canvas -> a GtkPlotCanvas widget x,y -> coordinates where text is inserted (in percentage of the widget) font -> text font height -> font height angle -> font angle fg,bg -> foregound(text),background color transparent -> TRUE or FALSE justification -> GTK_JUSTIFY_LEFT, RIGHT, CENTER text -> text string */ gtk_plot_canvas_put_text(GTK_PLOT_CANVAS(connection->widget), .45, .05, "Times-BoldItalic", 20, 0, NULL, NULL, TRUE,GTK_JUSTIFY_CENTER,connection->plot->title); for(i=0;iplot->plotcount;i++) { channelPtr=g_list_nth_data(connection->plot->channellist,i); channelPtr->dataset = GTK_PLOT_DATA(gtk_plot_data_new()); /* void gtk_plot_add_data (GtkPlot *plot,GtkPlotData *data); ------------------------------------------------------------------------------------------ Add data to the plot widget: plot -> A GtkPlot widget; data -> data pointer */ gtk_plot_add_data(GTK_PLOT(connection->plot->plotfield), channelPtr->dataset); gtk_widget_show(GTK_WIDGET(channelPtr->dataset)); gdk_color_parse(channelPtr->ycolor, &color); gdk_color_alloc(gdk_colormap_get_system(), &color); /* void gtk_plot_data_set_legend (GtkPlotData *dataset,const gchar *legend); */ gtk_plot_data_set_legend(channelPtr->dataset, channelPtr->ylegend); /* void gtk_plot_data_set_symbol (GtkPlotData *data,GtkPlotSymbolType type, GtkPlotSymbolStyle style,gint size,gfloat line_width,const GdkColor *color, const GdkColor *border_color); ---------------------------------------------------------------------------------- typedef enum{ GTK_PLOT_SYMBOL_NONE,GTK_PLOT_SYMBOL_SQUARE,GTK_PLOT_SYMBOL_CIRCLE, GTK_PLOT_SYMBOL_UP_TRIANGLE,GTK_PLOT_SYMBOL_DOWN_TRIANGLE, GTK_PLOT_SYMBOL_RIGHT_TRIANGLE,GTK_PLOT_SYMBOL_LEFT_TRIANGLE, GTK_PLOT_SYMBOL_DIAMOND,GTK_PLOT_SYMBOL_PLUS,GTK_PLOT_SYMBOL_CROSS, GTK_PLOT_SYMBOL_STAR,GTK_PLOT_SYMBOL_DOT,GTK_PLOT_SYMBOL_IMPULSE, } GtkPlotSymbolType; typedef enum{ GTK_PLOT_SYMBOL_EMPTY,GTK_PLOT_SYMBOL_FILLED,GTK_PLOT_SYMBOL_OPAQUE } GtkPlotSymbolStyle; */ gtk_plot_data_set_symbol(channelPtr->dataset, channelPtr->symboltype, channelPtr->symbolstyle, channelPtr->symbolsize, channelPtr->linewidth, &color, &color); /* void gtk_plot_data_set_line_attributes (GtkPlotData *data, GtkPlotLineStyle style, gfloat width, const GdkColor *color); ---------------------------------------------------------------------------------- typedef enum{ GTK_PLOT_LINE_NONE, GTK_PLOT_LINE_SOLID,GTK_PLOT_LINE_DOTTED, GTK_PLOT_LINE_DASHED,GTK_PLOT_LINE_DOT_DASH,GTK_PLOT_LINE_DOT_DOT_DASH, GTK_PLOT_LINE_DOT_DASH_DASH } GtkPlotLineStyle; */ gtk_plot_data_set_line_attributes(channelPtr->dataset, channelPtr->linestyle, channelPtr->linewidth, &color); /* void gtk_plot_data_set_connector (GtkPlotData *data,GtkPlotConnector connector); ---------------------------------------------------------------------------------- typedef enum{ GTK_PLOT_CONNECT_NONE,GTK_PLOT_CONNECT_STRAIGHT,GTK_PLOT_CONNECT_SPLINE, GTK_PLOT_CONNECT_HV_STEP,GTK_PLOT_CONNECT_VH_STEP,GTK_PLOT_CONNECT_MIDDLE_STEP } GtkPlotConnector; */ gtk_plot_data_set_connector (channelPtr->dataset,channelPtr->pointconnect); } /* Paint the canvas(update the changes) */ gtk_plot_canvas_paint(GTK_PLOT_CANVAS(connection->widget)); /* Refresh the canvas */ gtk_plot_canvas_refresh(GTK_PLOT_CANVAS(connection->widget)); gtk_plot_clip_data(GTK_PLOT(connection->plot->plotfield), TRUE); } GtkWidget * hmi_GtkPlotCanvas(gchar *widgetname){ GtkWidget *canvas; GdkColor color; gint widget_height=DEFAULT_WIDGET_HEIGHT; gint widget_width=DEFAULT_WIDGET_WIDTH; char *bgcolor=(char*)"light blue"; int i; int nbofrows=0; int nbofcols=0; int ret; f32 f32_tmp; #define DEBUG_GTKPLOTCANVAS #undef DEBUG_GTKPLOTCANVAS #ifdef DEBUG_GTKPLOTCANVAS printf("hmi_GtkPlotCanvas()\n"); #endif if( widgetname[0] == '_' ){ widgetname++; nbofrows=conffile_get_table_rows(widgetname); for(i=0;i width, height of the new canvas magnification -> magnification of the canvas Returns the canvas widget */ canvas = gtk_plot_canvas_new(widget_width, widget_height, 1.); /* #define GTK_PLOT_CANVAS_UNSET_FLAGS(canvas, flags) (GTK_PLOT_CANVAS_FLAGS(canvas) &= ~(flags)) #define GTK_PLOT_CANVAS_FLAGS(canvas) (GTK_PLOT_CANVAS(canvas)->flags) #define GTK_PLOT_CANVAS(obj) GTK_CHECK_CAST (obj, gtk_plot_canvas_get_type (), GtkPlotCanvas) #define GTK_CHECK_CAST(tobj, cast_type, cast) ((cast*) gtk_type_check_object_cast ((GtkTypeObject*) (tobj), (cast_type))) */ GTK_PLOT_CANVAS_UNSET_FLAGS(GTK_PLOT_CANVAS(canvas), GTK_PLOT_CANVAS_DND_FLAGS); gdk_color_parse(bgcolor, &color); gdk_color_alloc(gtk_widget_get_colormap(canvas), &color); /* void gtk_plot_canvas_set_background (GtkPlotCanvas *canvas,const GdkColor *background); */ gtk_plot_canvas_set_background(GTK_PLOT_CANVAS(canvas), &color); gtk_widget_show(canvas); return(canvas); } #endif /* hmi_GnomePixmap_read_matplc_conf() Read configuration from matplc.conf [hmi_gtk] GnomePixmap widgetname pixmap1 ... pixmapn */ void hmi_GnomePixmap_read_matplc_conf(void) { int nbofrows=0; int nbofcols=0; int iCol,iRow,iWtab,iPtab,found; char tablename[]="GnomePixmap"; char *widgetpattern; char *sPixmap=NULL; char *image_name; FILE *fPixmap; #ifdef DEBUG_hmi_GnomePixmap_read_matplc_conf printf("hmi_GnomePixmap_read_matplc_conf()\n"); #endif hmi_GnomePixmap.nbPixmapTab=0; hmi_GnomePixmap.PixmapTab=NULL; nbofrows=conffile_get_table_rows(tablename); //printf("GnomePixmap:: nbofrows %d\n",nbofrows); for(iRow=0;iRowfirst_scan=1 */ void option_menu_widget_init(connection_t *connection){ int nbofrows=0; int nbofcols=0; int iRow,iCol; char *tablename; GtkWidget *menu_item; GtkMenuShell *menu_shell; //int index; optionmenu_t *om; GList *glist; plc_pt_t pt; menu_shell=GTK_MENU_SHELL(GTK_MENU(GTK_OPTION_MENU(connection->widget)->menu)); //printf("-->g_list_length=%d\n",g_list_length(menu_shell->children)); tablename=gtk_widget_get_name(connection->widget); if(tablename[0]=='_') tablename++; nbofrows=conffile_get_table_rows(tablename); /* OptionMenuTab mit Dummy-Element (index=0) starten */ om = (optionmenu_t *)g_malloc(sizeof(optionmenu_t)); if(om==NULL) printf("(Z %d) Could not allocate memory for structure optionmenu_t",__LINE__); om->pv = 0; om->pt = plc_pt_null(); connection->OptionMenuTab = g_list_append(connection->OptionMenuTab, om); /* Tabelle in matplc.conf durcharbeiten */ for(iRow=0;iRowpv = iCol; om->pt = pt; connection->OptionMenuTab = g_list_append(connection->OptionMenuTab, om); } } gtk_signal_connect (GTK_OBJECT (GTK_OPTION_MENU (connection->widget)->menu), "selection-done", GTK_SIGNAL_FUNC (update_optionmenu), connection); gtk_option_menu_set_history(GTK_OPTION_MENU(connection->widget),1); gtk_widget_show_all(connection->widget); /* Set Point for the first item (which is now selected) */ glist=g_list_nth(connection->OptionMenuTab,1); om=(optionmenu_t*)glist->data; plc_set(om->pt,om->pv); connection->variable->value=1; } #ifdef GTKSOCKET #define DEBUG_GTKSOCKET #undef DEBUG_GTKSOCKET /* Init function for GtkSocket Set point with window-ID */ void socket_widget_init(connection_t *connection){ gtk_widget_realize(connection->widget); plc_set(connection->pt,(u32)(GDK_WINDOW_XWINDOW(connection->widget->window))); #ifdef DEBUG_GTKSOCKET printf("socket_widget_init: ID=%d\n", (guint32)(GDK_WINDOW_XWINDOW(connection->widget->window)));fflush(stdout); #endif } /* Create socket window in creation function */ GtkWidget * hmi_GtkSocket(gchar *widgetname){ GtkWidget *socket; #ifdef DEBUG_GTKSOCKET printf("hmi_GtkSocket(): Name=%s\n",widgetname);fflush(stdout); #endif socket = gtk_socket_new(); gtk_widget_show_all(socket); return(socket); } #endif /* Parse the windows data structure and update the values in the connections */ void parse_connection(gpointer a_connection, gpointer data){ connection_t *connection = a_connection; window_node_t *window = data; guint type; /* If the widget is not there do nothing (Gtk_Socket will be destroyed, when the plugged window was destroyed) */ if(!(GTK_IS_WIDGET(connection->widget)))return; /* An obvious opportunity for speed optimisation is to calculate the type * values one time and store them in variables */ type = GTK_OBJECT(connection->widget)->klass->type; if(type == gtk_type_from_name("GtkLabel")){ label_widget(connection); } else if(type == gtk_type_from_name("GtkProgressBar")){ progress_widget(connection); } else if(type == gtk_type_from_name("GnomePixmap")){ /* Force first draw of the widget using the current state */ if(window->first_scan){ connection->variable->value = !plc_get(connection->pt); } gnome_pixmap_widget(connection); } else{ /* From here enter the data entry widgets */ if(window->first_scan){ if(connection->variable){ connection->variable->value = plc_get(connection->pt); } } if(type == gtk_type_from_name("GtkToggleButton")){ toggle_button_widget(connection); } else if(type == gtk_type_from_name("GtkRadioButton")){ toggle_button_widget(connection); } else if(type == gtk_type_from_name("GtkCheckButton")){ toggle_button_widget(connection); } else if(type == gtk_type_from_name("GtkButton")){ button_widget(connection); } else if(type == gtk_type_from_name("GtkEntry")){ if(window->first_scan) { entry_widget_init(connection); } entry_widget(connection); } else if(type == gtk_type_from_name("GtkHScale")){ if(window->first_scan) { scale_widget_init(connection); } scale_widget(connection); } else if(type == gtk_type_from_name("GtkVScale")){ if(window->first_scan) { scale_widget_init(connection); } scale_widget(connection); } else if(type == gtk_type_from_name("GtkSpinButton")){ if(window->first_scan) { spin_button_widget_init(connection); } spin_button_widget(connection); } else if(type == gtk_type_from_name("GtkOptionMenu")){ if(window->first_scan) { option_menu_widget_init(connection); } } #ifdef GTKSOCKET else if(type == gtk_type_from_name("GtkSocket")){ if(window->first_scan) { socket_widget_init(connection); } } #endif #ifdef GTKEXTRA else if(type == gtk_type_from_name("GtkPlotCanvas")){ if(window->first_scan) { hmi_GtkPlotCanvas_widget_init(connection); } hmi_GtkPlotCanvas_widget(connection); } #endif } } void parse_window(gpointer window, gpointer data){ window_node_t *window_node = window; g_list_foreach (window_node->connections, (GFunc)parse_connection, window); window_node->first_scan = 0; } /* This function is called when gtk is idle (free of events) */ gboolean idle(gpointer data) { plc_scan_beg(); plc_update(); g_list_foreach (windows, (GFunc)parse_window, NULL); plc_update(); plc_scan_end(); return TRUE; } /* add the variable name to the variables hash table for input fields */ variable_t *add_variable(char *name, data_type_t type){ variable_t *variable, *exist; #define DEBUG_ADD_VARIABLE #undef DEBUG_ADD_VARIABLE variable = g_malloc0(sizeof(variable_t)); variable->type = type; exist = g_hash_table_lookup(variables, name); if(exist){ /* Already created check that the type matches */ if(exist->type != type){ printf("Type inconsistency in variable %s\n", name); } return exist; } else{ #ifdef DEBUG_ADD_VARIABLE printf("Adding %s to hash table\n",name); #endif g_hash_table_insert(variables, name, variable); } return variable; } /* init window data to comunicate with plc points */ void init_widget_data(gpointer widget, gpointer user_data) { window_node_t *main_window = user_data; connection_t *connection; char *widget_name; char *s; gchar **split_str; gchar *PixmapName; int i; gboolean notype; guint type; #define DEBUG_INIT_WIDGET_DATA #undef DEBUG_INIT_WIDGET_DATA #ifdef DEBUG_INIT_WIDGET_DATA printf("init_widget_data()\n"); #endif if(widget){ widget_name = g_strdup(glade_get_widget_name(GTK_WIDGET(widget))); //sprintf("init_widget_data() %s \n",widget_name); /* Interim code to automaticaly adjust GnomePixmap to the widget size * Glade and libglade are currently not handling GnomePixmap image scaling */ type = GTK_OBJECT(widget)->klass->type; if(type == gtk_type_from_name("GnomePixmap")){ if(widget_name[0] == '.'){ split_str = g_strsplit(widget_name+1, "_", 2); if(split_str[0]){ load_gnome_pixmap(GTK_WIDGET(widget), split_str[0]); } g_free(split_str); } /* Load a transparent pixmap to avoid painting a large * non scaled pixmap when using Pixmap as display. */ else if(widget_name[0] == '_'){ PixmapName = g_strdup("Transparent.xpm"); load_gnome_pixmap(GTK_WIDGET(widget), PixmapName); g_free(PixmapName); } } #ifdef DEBUG_INIT_WIDGET_DATA printf("Name: %s\n", widget_name); #endif /* printf("Name: %s\n", widget_name); */ /* if the name starts with '_' then create a connection */ if(widget_name[0] == '_'){ /* format for point name widgets * _pointname[.id][.type][.parameter1[.parameter2]] * The parameters is used for example in boolean variables * for the text for on and off states */ split_str = g_strsplit(widget_name+1, ".", 5); i = 0; while(split_str[i]){ #ifdef DEBUG_INIT_WIDGET_DATA printf("%s \n", split_str[i]); #endif i++; } if(i>0){ /* create a connection to a plc point for this widget */ connection = (connection_t *)g_malloc(sizeof(connection_t)); connection->data_type = bool_dt; connection->on = NULL; connection->off = NULL; connection->widget = widget; connection->pt = get_pt(split_str[0]); connection->PixmapTab = NULL; connection->LabelTab = NULL; #ifdef GTKEXTRA connection->plot = NULL; #endif connection->OptionMenuTab = NULL; if(i>2){ notype = 0; s = split_str[2]; if (strcmp(s, f32_TYPE) == 0) connection->data_type = f32_dt; else if (strcmp(s, i32_TYPE) == 0) connection->data_type = i32_dt; else if (strcmp(s, u32_TYPE) == 0) connection->data_type = u32_dt; else if (strcmp(s, i16_TYPE) == 0) connection->data_type = i16_dt; else if (strcmp(s, u16_TYPE) == 0) connection->data_type = u16_dt; else if (strcmp(s, i8_TYPE) == 0) connection->data_type = i8_dt; else if (strcmp(s, u8_TYPE) == 0) connection->data_type = u8_dt; else if (strcmp(s, bool_TYPE) == 0) connection->data_type = bool_dt; else notype = 1; if(notype){ connection->on = g_strdup(split_str[2]); if(i>2){ connection->off = g_strdup(split_str[3]); } } else{ if(i>2){ connection->on = g_strdup(split_str[3]); if(i>3){ connection->off = g_strdup(split_str[4]); } } } } /* for GnomePixmap find the corresponding PixmapTab Entry */ if(type == gtk_type_from_name("GnomePixmap")){ for (i=0;iPixmapTab=&hmi_GnomePixmap.PixmapTab[i]; } } } /* for GtkLabel find the corresponding LabelTab Entry */ if(type == gtk_type_from_name("GtkLabel")){ for (i=0;iLabelTab=&hmi_GtkLabel.LabelTab[i]; } } } #ifdef GTKEXTRA if(type == gtk_type_from_name("GtkPlotCanvas")){ connection->plot = (plot_t *)g_malloc(sizeof(plot_t)); connection->plot->channellist=NULL; } #endif /* add the widget name to the variable table */ connection->variable = add_variable(split_str[0], connection->data_type); main_window->connections = g_list_append(main_window->connections, connection); g_free(split_str); } } g_free(widget_name); } } /* Data entry widgets update functions */ void toggle_button_widget_update(GtkWidget *w, variable_t *variable){ /* printf("ToggleButton %d\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))); */ if(variable->type == bool_dt){ variable->value = (u32)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)); } } void button_widget_update(GtkWidget *w, variable_t *variable){ if(variable->type == bool_dt){ variable->value = 1; } } void entry_widget_update(GtkWidget *w, variable_t *variable){ u32 u32_tmp; union { u32 u; f32 f; } f32_tmp; char *str_buff; str_buff = gtk_editable_get_chars (GTK_EDITABLE(w), 0, -1); if(variable->type == bool_dt){ /* No digital type allowed for this widget */ } else{ switch (variable->type) { case f32_dt: f32_tmp.f = atof(str_buff); variable->value = f32_tmp.u; break; case i8_dt: case u8_dt: case i16_dt: case u16_dt: case i32_dt: case u32_dt: /* Check if this does not have any type conversion implications */ u32_tmp = (u32)atoi(str_buff); variable->value = u32_tmp; break; default : break; }; /* switch() */ } g_free(str_buff); } void scale_widget_update(GtkWidget *w, variable_t *variable){ u32 u32_tmp; u16 u16_tmp; u8 u8_tmp; i32 i32_tmp; i16 i16_tmp; i8 i8_tmp; union {u32 u; f32 f;} f32_tmp; GtkAdjustment *adjustment; adjustment=gtk_range_get_adjustment(GTK_RANGE(w)); u32_tmp = adjustment->value; switch (variable->type) { case f32_dt: f32_tmp.f=adjustment->value; variable->value = f32_tmp.u; //printf("scale_widget_update.f32: value=%f\n",f32_tmp); break; case u32_dt: variable->value = u32_tmp; //printf("scale_widget_update.u32: value=%d\n",u32_tmp); break; case u16_dt: u16_tmp=u32_tmp; u32_tmp=u16_tmp; variable->value = u32_tmp; //printf("scale_widget_update.u16: value=%d\n",u16_tmp); break; case u8_dt: u8_tmp=u32_tmp; variable->value = *((u32 *)&u8_tmp); //printf("scale_widget_update.u8: value=%d\n",u8_tmp); break; case i32_dt: i32_tmp=u32_tmp; variable->value = *((u32 *)&i32_tmp); //printf("scale_widget_update.i32: value=%d\n",i32_tmp); break; case i16_dt: i16_tmp=u32_tmp; i32_tmp=i16_tmp; variable->value = *((u32 *)&i32_tmp); //printf("scale_widget_update.i16: value=%d\n",i16_tmp); break; case i8_dt: i8_tmp=u32_tmp; variable->value = *((u32 *)&i8_tmp); //printf("scale_widget_update.i8: value=%d\n",i8_tmp); break; default: break; } } void spin_button_widget_update(GtkWidget *w, variable_t *variable){ u32 u32_tmp; u16 u16_tmp; u8 u8_tmp; i32 i32_tmp; i16 i16_tmp; i8 i8_tmp; union {u32 u; f32 f;} tmp; #define f32_tmp (tmp.f) f32_tmp = gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(w)); switch (variable->type) { case f32_dt: variable->value = tmp.u; //printf("spin_button_widget_update.f32: value=%f\n",f32_tmp); break; case u32_dt: u32_tmp=f32_tmp; variable->value = u32_tmp; //printf("spin_button_widget_update.u32: value=%d\n",u32_tmp); break; case u16_dt: u16_tmp=f32_tmp; u32_tmp=u16_tmp; variable->value = u32_tmp; //printf("spin_button_widget_update.u16: value=%d\n",u16_tmp); break; case u8_dt: u8_tmp=f32_tmp; variable->value = *((u32 *)&u8_tmp); //printf("spin_button_widget_update.u8: value=%d\n",u8_tmp); break; case i32_dt: i32_tmp=f32_tmp; variable->value = *((u32 *)&i32_tmp); //printf("spin_button_widget_update.i32: value=%d\n",i32_tmp); break; case i16_dt: i16_tmp=f32_tmp; i32_tmp=i16_tmp; variable->value = i32_tmp; //printf("spin_button_widget_update.i16: value=%d\n",i16_tmp); break; case i8_dt: i8_tmp=f32_tmp; variable->value = *((u32 *)&i8_tmp); //printf("spin_button_widget_update.i8: value=%d\n",i8_tmp); break; default: break; } #undef f32_tmp } /* Function to update an entry value */ void update_value(GtkWidget *w, gpointer data){ variable_t *variable; data_type_t type; char *name; char **point_name; #define DEBUG_UPDATE_VALUE #undef DEBUG_UPDATE_VALUE #ifdef DEBUG_UPDATE_VALUE printf("update_value()\n"); #endif name = (char *)glade_get_widget_name(GTK_WIDGET(w)); if(name[0] == '_'){ point_name = g_strsplit(name+1, ".", 2); /* get variable from hash table */ variable = g_hash_table_lookup(variables, point_name[0]); #ifdef DEBUG_UPDATE_VALUE printf("Point Name: %s\n", point_name[0]); #endif /* An obvious opportunity for speed optimisation is to calculate the type * values one time and store them in variables */ type = GTK_OBJECT(w)->klass->type; if(type == gtk_type_from_name("GtkToggleButton")){ toggle_button_widget_update(w, variable); } else if(type == gtk_type_from_name("GtkRadioButton")){ toggle_button_widget_update(w, variable); } else if(type == gtk_type_from_name("GtkCheckButton")){ toggle_button_widget_update(w, variable); } else if(type == gtk_type_from_name("GtkButton")){ button_widget_update(w, variable); } else if(type == gtk_type_from_name("GtkEntry")){ entry_widget_update(w, variable); } else if(type == gtk_type_from_name("GtkHScale")){ scale_widget_update(w, variable); } else if(type == gtk_type_from_name("GtkVScale")){ scale_widget_update(w, variable); } else if(type == gtk_type_from_name("GtkSpinButton")){ spin_button_widget_update(w, variable); } } } /* Function to update an entry value */ void update_optionmenu(GtkWidget *w, gpointer data){ int index; GtkMenuShell *menushell; optionmenu_t *om; GList *glist; #define DEBUG_UPDATE_OPTIONMENU #undef DEBUG_UPDATE_OPTIONMENU #ifdef DEBUG_UPDATE_OPTIONMENU printf("update_optionmenu()\n"); #endif menushell=GTK_MENU_SHELL(w); index = g_list_index(menushell->children,gtk_menu_get_active(GTK_MENU(w))); /* Reset last selected Point */ glist=g_list_nth(((connection_t *)data)->OptionMenuTab,((connection_t *)data)->variable->value); if (glist!=NULL) { om=(optionmenu_t*)glist->data; plc_set(om->pt,0); } /* Get Value from GList */ glist=g_list_nth(((connection_t *)data)->OptionMenuTab,index); if (glist!=NULL) { om=(optionmenu_t*)glist->data; plc_set(om->pt,om->pv); ((connection_t *)data)->variable->value=index; } } /* Function to reset an entry value mainly for implementing push buttons*/ void reset_value(GtkWidget *w, gpointer data){ variable_t *variable; data_type_t type; char *name; char **point_name; #define DEBUG_RESET_VALUE #undef DEBUG_RESET_VALUE #ifdef DEBUG_RESET_VALUE printf("reset_value()\n"); #endif name = (char *)glade_get_widget_name(GTK_WIDGET(w)); if(name[0] == '_'){ point_name = g_strsplit(name+1, ".", 2); /* get variable from hash table */ variable = g_hash_table_lookup(variables, point_name[0]); type = GTK_OBJECT(w)->klass->type; if(type == gtk_type_from_name("GtkButton")){ if(variable->type == bool_dt){ variable->value = 0; } } } } /* Generate data tree for a window */ void new_window(GladeXML *xml, char *name, GtkWidget *widget){ window_node_t *window; GList *widgetList; #define DEBUG_NEW_WINDOW #undef DEBUG_NEW_WINDOW #ifdef DEBUG_NEW_WINDOW printf("new_window() %s \n",name); #endif window = (window_node_t *)g_malloc(sizeof(window_node_t)); /* Never forget to assign NULL to a before starting to popullate a GList */ window->connections = NULL; window->first_scan = 1; window->name = name; window->widget = widget; windows = g_list_append(windows, window); widgetList = glade_xml_get_widget_prefix(xml, ""); #ifdef DEBUG_NEW_WINDOW printf("Length : %d\n", g_list_length(widgetList)); #endif g_list_foreach (widgetList, (GFunc)init_widget_data, window); } /* Run the about dialog */ void on_about1_activate(GtkWidget *w) { /* GladeXML *xml; */ const gchar *authors[] = { "Juan Carlos Orozco", NULL }; gtk_widget_show (gnome_about_new ("HMI Interpreter", VERSION, "Copyright 2001 Juan Carlos Orozco", (const gchar **) authors, ("Credits: " "MatPLC:" " Jiri Baum, Mario de Sousa - creators of gmm; " " Court Wollet - project leader; " "Glade:" " Damon Chaplin, Martijn van Beers; "), NULL)); } /* Function to compare the window name in the windows DList */ gint comp_window_name(gconstpointer window1, gconstpointer name1){ #define DEBUG_COMP_WINDOW_NAME #undef DEBUG_COMP_WINDOW_NAME window_node_t *window = (window_node_t *)window1; char *name = (char *)name1; #ifdef DEBUG_COMP_WINDOW_NAME printf("comp_window_name() \n"); #endif return strcmp(window->name, name); } /* Function to erase the variables in each connection */ void free_connection(gpointer connection1, gpointer userdata){ connection_t *connection = (connection_t *)connection1; variable_t *exist; #ifdef GTKEXTRA channel_t *channelPtr; #endif optionmenu_t *om; GList *glist; #define DEBUG_FREE_CONNECTION #undef DEBUG_FREE_CONNECTION #ifdef GTKEXTRA int i; #endif #ifdef DEBUG_FREE_CONNECTION printf("free_connection(%s) ***** START *****\n",(connection->widget->name)+1); #endif if(connection->OptionMenuTab){ glist=g_list_first(connection->OptionMenuTab); while (glist!=NULL) { om=(optionmenu_t*)glist->data; if (om!=NULL) { g_free(om); glist->data=NULL; } glist=g_list_next(glist); } g_list_free(connection->OptionMenuTab); connection->OptionMenuTab=NULL; } if(connection->variable){ exist = g_hash_table_lookup(variables, (connection->widget->name)+1); if(exist){ #ifdef DEBUG_FREE_CONNECTION printf("\tRemoving variable %s from hash table\n",(connection->widget->name)+1); #endif g_hash_table_remove(variables, (connection->widget->name)+1); g_free(connection->variable); connection->variable=NULL; } } if(connection->on){ #ifdef DEBUG_FREE_CONNECTION printf("\tDeleting on\n");fflush(stdout); #endif g_free(connection->on); connection->on=NULL; } if(connection->off){ #ifdef DEBUG_FREE_CONNECTION printf("\tDeleting off\n");fflush(stdout); #endif g_free(connection->off); connection->off=NULL; } if(connection->widget){ #ifdef DEBUG_FREE_CONNECTION printf("\tSetting widget to Nullpointer\n");fflush(stdout); #endif connection->widget=NULL; } #ifdef GTKEXTRA if(connection->plot){ for(i=0;iplot->plotcount;i++){ channelPtr=((GList *)g_list_last(connection->plot->channellist))->data; if(channelPtr->dataset){ #ifdef DEBUG_FREE_CONNECTION printf("\tChannel %s: Deleting plot->dataset[%d]\n",channelPtr->dataset,i);fflush(stdout); #endif gtk_plot_remove_data (GTK_PLOT(connection->plot->plotfield), channelPtr->dataset); gtk_widget_destroy(GTK_WIDGET(channelPtr->dataset)); g_free(channelPtr->dataset); channelPtr->dataset=NULL; } if(channelPtr->px){ #ifdef DEBUG_FREE_CONNECTION printf("\tChannel %s: Deleting plot->px[%d]\n",channelPtr->px,i);fflush(stdout); #endif g_free(channelPtr->px); channelPtr->px=NULL; } if(channelPtr->py){ #ifdef DEBUG_FREE_CONNECTION printf("\tChannel %s: Deleting plot->py[%d]\n",channelPtr->py,i);fflush(stdout); #endif g_free(channelPtr->py); channelPtr->py=NULL; } if(channelPtr->ycolor){ #ifdef DEBUG_FREE_CONNECTION printf("\tChannel %s: Deleting plot->ycolor[%d]\n",channelPtr->ycolor,i);fflush(stdout); #endif g_free(channelPtr->ycolor); channelPtr->ycolor=NULL; } if(channelPtr->ylegend){ #ifdef DEBUG_FREE_CONNECTION printf("\tChannel %s: Deleting plot->ylegend[%d]\n",channelPtr->ylegend,i);fflush(stdout); #endif g_free(channelPtr->ylegend); channelPtr->ylegend=NULL; } connection->plot->channellist=g_list_remove(connection->plot->channellist,channelPtr); } if(connection->plot->channellist){ #ifdef DEBUG_FREE_CONNECTION printf("\tDeleting channellist\n");fflush(stdout); #endif g_list_free(connection->plot->channellist); } if(connection->plot->channellist){ #ifdef DEBUG_FREE_CONNECTION printf("\tDeleting plot->channellist\n");fflush(stdout); #endif g_free(connection->plot->channellist); } if(connection->plot->plotfield){ #ifdef DEBUG_FREE_CONNECTION printf("\tDestroying plot->plotfield\n");fflush(stdout); #endif gtk_widget_destroy(connection->plot->plotfield); //g_free(connection->plot->plotfield); connection->plot->plotfield=NULL; } if(connection->plot->title){ #ifdef DEBUG_FREE_CONNECTION printf("\tDeleting plot->title\n");fflush(stdout); #endif g_free(connection->plot->title); } if(connection->plot->x_title){ #ifdef DEBUG_FREE_CONNECTION printf("\tDeleting plot->x_title\n");fflush(stdout); #endif g_free(connection->plot->x_title); } if(connection->plot->y_title){ #ifdef DEBUG_FREE_CONNECTION printf("\tDeleting plot->y_title\n");fflush(stdout); #endif g_free(connection->plot->y_title); } if(connection->plot->plot_bg_color){ #ifdef DEBUG_FREE_CONNECTION printf("\tDeleting plot->plot_bg_color\n");fflush(stdout); #endif g_free(connection->plot->plot_bg_color); } if(connection->plot->legend_bg_color){ #ifdef DEBUG_FREE_CONNECTION printf("\tDeleting plot->legend_bg_color\n");fflush(stdout); #endif g_free(connection->plot->legend_bg_color); } g_free(connection->plot); connection->plot=NULL; } #endif g_free(connection); connection=NULL; #ifdef DEBUG_FREE_CONNECTION printf("free_connection() ***** END *****\n"); #endif } /* Exit window (== destroy_handler) * This handler only release the focus. */ void exit_window(GtkWidget *w, gpointer data1, gpointer data2) { if(w){ // gtk_grab_remove(w); gtk_widget_hide(w); } } /* handler for "delete_events" (from window-manager, e.g. X-Button) * This handler free the structures contained in the node * and finally destroy the window. * The destroy-handler then calls exit_window(). */ gint delete_event( GtkWidget *w, GdkEvent *event, gpointer data ) { GList *found_it; window_node_t *free_this_window; char *name; #define DEBUG_DELETE_EVENT #undef DEBUG_DELETE_EVENT #ifdef DEBUG_DELETE_EVENT printf("delete event()\n"); #endif if(w){ name = (char *)glade_get_widget_name(GTK_WIDGET(w)); #ifdef DEBUG_DELETE_EVENT printf("delete event....%s\n",name); #endif //gtk_grab_remove(w); found_it = g_list_find_custom(windows, name,(GCompareFunc)comp_window_name); if(found_it){ #ifdef DEBUG_DELETE_EVENT printf("we found it\n"); #endif // Hide the window instead of destroying it. gtk_widget_hide(w); //windows = g_list_remove_link(windows, found_it); //free_this_window = (window_node_t *)(found_it->data); //g_free(free_this_window->name); //g_list_foreach(free_this_window->connections, (GFunc)free_connection, NULL); //g_list_free(free_this_window->connections); } //gtk_widget_destroy(w); } return(TRUE); } /* quit-Handler only for window "app1" * * Window "app1" must connect the signal delete_event with quit_handler. * In matplc.conf you have to create the point "quit_app1" and assign it to * plcshutdown. * * The quit-handler sets the point quit_app1 and free the structures * contained in the node. */ void quit_handler(GtkWidget *w, gpointer data){ char *name; plc_pt_t pt_quitapp1; GList *found_it; window_node_t *free_this_window; #define DEBUG_QUIT_HANDLER #undef DEBUG_QUIT_HANDLER #ifdef DEBUG_QUIT_HANDLER printf("quit_handler()\n"); #endif pt_quitapp1 = get_pt("quit_app1"); #ifdef DEBUG_QUIT_HANDLER printf(" --> setting quit_app1\n"); #endif plc_set(pt_quitapp1,1); plc_update(); if(w){ name = (char *)glade_get_widget_name(GTK_WIDGET(w)); #ifdef DEBUG_QUIT_HANDLER printf("quit_handler()....%s\n",name); #endif gtk_grab_remove(w); found_it = g_list_find_custom(windows, name,(GCompareFunc)comp_window_name); if(found_it){ #ifdef DEBUG_QUIT_HANDLER printf("we found it\n"); #endif windows = g_list_remove_link(windows, found_it); free_this_window = (window_node_t *)(found_it->data); g_free(free_this_window->name); g_list_foreach(free_this_window->connections, (GFunc)free_connection, NULL); g_list_free(free_this_window->connections); } gtk_widget_destroy(w); } } /* Run a new window dialog using the name in the data field */ void run_window(GtkWidget *w, gpointer data) { GladeXML *xml; GtkWidget *window; gchar *name; GList *found_it; window_node_t *wn; GtkWidget *widget; #define DEBUG_RUN_WINDOW #undef DEBUG_RUN_WINDOW #ifdef DEBUG_RUN_WINDOW printf("run_window()\n"); #endif /* Search for if this window already exists */ found_it = g_list_find_custom(windows, data,(GCompareFunc)comp_window_name); if(found_it){ wn = found_it->data; widget = wn->widget; gtk_widget_show(widget); } else{ /* We will use the name string for the window name in the window_node * structure, so we will free it when the window is closed. */ name = g_strdup((char *)data); #ifdef DEBUG_RUN_WINDOW printf("Data %s\n", name); #endif /* load the about1 dialog */ xml = glade_xml_new("hmi_gtk.glade", name); /* in case we can't load the interface, bail */ if(!xml) { g_warning("We could not load the interface!"); return; } /* Set the event to dispose the window from the DList when the * window is closed */ window = glade_xml_get_widget(xml, name); /* set the parent of the dialog to be the main window */ /* gnome_dialog_set_parent(GNOME_DIALOG(dialog), GTK_WINDOW(app)); */ if(window){ new_window(xml, name, window); /* unref the xml file as it's not needed anymore */ /* gtk_object_unref(GTK_OBJECT(xml)); */ // Try hiding the window instead of destroying it. To avoid segfault. gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(delete_event), NULL); /* unref the xml file as it's not needed anymore */ /* gtk_object_unref(GTK_OBJECT(xml)); */ // GTK2 Complains about this way of destroying the xml data. //g_signal_connect_data(G_OBJECT(window), "destroy", // G_CALLBACK(exit_window), // xml, (GClosureNotify)g_object_unref, // FALSE); gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(exit_window), NULL); /* autoconnect any signals */ glade_xml_signal_autoconnect(xml); } } } /* Fuctions to call 10 predefined windows from the menus */ void run_window1(GtkWidget *parent){ char str[] = "window1"; run_window(parent, str); } void run_window2(GtkWidget *parent){ char str[] = "window2"; run_window(parent, str); } void run_window3(GtkWidget *parent){ char str[] = "window3"; run_window(parent, str); } void run_window4(GtkWidget *parent){ char str[] = "window4"; run_window(parent, str); } void run_window5(GtkWidget *parent){ char str[] = "window5"; run_window(parent, str); } void run_window6(GtkWidget *parent){ char str[] = "window6"; run_window(parent, str); } void run_window7(GtkWidget *parent){ char str[] = "window7"; run_window(parent, str); } void run_window8(GtkWidget *parent){ char str[] = "window8"; run_window(parent, str); } void run_window9(GtkWidget *parent){ char str[] = "window9"; run_window(parent, str); } void run_window10(GtkWidget *parent){ char str[] = "window10"; run_window(parent, str); } /* Main program: initialize the plc, create the main window * and connect the gtk signals */ int main(int argc, char *argv[]) { GladeXML *xml; GtkWidget *window; const char *module_name = "hmi_gtk"; char *name; #define DEBUG_MAIN #undef DEBUG_MAIN #ifdef DEBUG_MAIN printf("main()\n"); #endif /* We will use the name string for the window name in the window_node * structure, so we will free it when the window is closed. */ name = g_strdup("app1"); if (plc_init(module_name, argc, argv) < 0) { printf("Error initializing PLC\n"); return -1; } /* initialize the variables hash table */ variables = g_hash_table_new ((GHashFunc)g_str_hash, (GCompareFunc)g_str_equal); /* initialize gnome */ gnome_init("hmi_gtk", VERSION, argc, argv); /* initialize glade for gnome */ glade_gnome_init(); /* Read from matplc.conf */ hmi_GnomePixmap_read_matplc_conf(); /* Read from matplc.conf */ hmi_GtkLabel_read_matplc_conf(); /* load the main window (which is named app1) */ /* run_window(NULL, "app1"); */ xml = glade_xml_new("hmi_gtk.glade", name); /* in case we can't load the interface, bail */ if(!xml) { g_warning("We could not load the interface!"); return -1; } app = glade_xml_get_widget(xml, name); /* Set the event to dispose the window from the DList when the * window is closed */ window = glade_xml_get_widget(xml, name); windows = NULL; new_window(xml, name, window); gtk_signal_connect_full(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(exit_window), NULL, xml, (GtkDestroyNotify)gtk_object_unref, FALSE, FALSE); /* autoconnect any signals */ glade_xml_signal_autoconnect(xml); /* run the main loop */ if(!g_idle_add((GSourceFunc)idle, NULL)){ printf("Error cannot add idle function\n"); return -1; } /* printf("Before gtk_main()\n"); */ gtk_main(); /* printf("After gtk_main()\n"); */ return 0; }