📄 vcp_widgets.c
字号:
/** This file, 'vcp_widgets.c', implements most of the GUI widgets that halvcp uses to build a Virtual Control Panel.*//** Copyright (C) 2005 John Kasunich <jmkasunich AT users DOT sourceforge DOT net>*//** This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. 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 USA THE AUTHORS OF THIS PROGRAM ACCEPT ABSOLUTELY NO LIABILITY FOR ANY HARM OR LOSS RESULTING FROM ITS USE. IT IS _EXTREMELY_ UNWISE TO RELY ON SOFTWARE ALONE FOR SAFETY. Any machinery capable of harming persons must have provisions for completely removing power from all motors, etc, before persons enter any danger area. All machinery must be designed to comply with local and national safety codes, and the authors of this software can not, and do not, take any responsibility for such compliance. This code was written as part of the EMC HAL project. For more information, go to www.linuxcnc.org.*/#include <stdio.h>#include <stddef.h>#include <ctype.h>#include <string.h>#include <hal.h>#include "vcp.h"#include "hal/utils/miscgtk.h"/*************** Local Function Prototypes *********************/static gboolean alloc_color_rgb(GdkColor * color, GdkColormap * map, unsigned char red, unsigned char green, unsigned char blue);static gboolean alloc_color(GdkColor * color, GdkColormap * map);static void add_to_parent ( vcp_widget_t *parent, GtkWidget *child, int expand, int padding );/*********** Widget Definitions (structs and code) *************//** General notes: Every widget must declare a vcp_widget_def_t structure, and initialize it with the appropriate values. Fields are as follows: 'name' The name of the widget, as a string. 'w_class' The class of the widget. 'w_class_mask' A bitmask identifying legal child widgets. 'attribs' A pointer to an array of vcp_attrib_def_t structs that identify the widget's attributes. Can be NULL if there are no attributes. 'priv_data_size' The number of bytes of RAM needed for the widget's private data, including attribute values (but not HAL data). Can be zero if there are no no attributes and no other internal data. 'init_funct' Pointer to a function that initializes the widget. Can be NULL, but just about any usefull widget will require some init code. When the init_funct is called, it is passed a pointer to a new vcp_widget structure. The 'type' pointer in the structure points to the definition above, so the init function can get any data it needs from the definition, or indirectly from the attribute definitions. The 'parent', 'child', and 'sibling' pointers in the widget structure will already be set, as will the linenum field. The 'priv_data' pointer will point to a block of the desired size. The 'hal_data' field will be NULL, if the widget needs HAL data, the init function must allocate it. The 'poll_funct' field will also be NULL, the init function should set it if needed. If specified, the 'poll_funct' will be called about ten times per second (this may wind up configurable). It is passed a pointer to the widget structure.*//* Widgets start here *//** VCP WIDGET: This is the top level widget in the file. It isn't a real widget, it simply provides a wrapper for everything else. In theory the "main-window" widget could serve this role, but someday I might want to allow for pop-ups or other widgets that are siblings of the main window rather than its children.*/vcp_widget_def_t vcp_def = { "vcp", CL_TOP_LEVEL, CH_ONE | CL_MAIN_WINDOW, NULL, 0, NULL};/** MAIN WINDOW WIDGET: The application must have one and only one of these widgets. It is the main GUI window of the program.*/static int init_main_window(vcp_widget_t *widget);typedef struct { char *title; int height; int width;} main_win_data_t;vcp_attrib_def_t main_win_attribs[] = { { "title", "VCP", ATTRIB_STRING, offsetof(main_win_data_t, title) }, { "height", "-2", ATTRIB_INT, offsetof(main_win_data_t, height) }, { "width", "-2", ATTRIB_INT, offsetof(main_win_data_t, width) }, { NULL, NULL, 0, 0 }};vcp_widget_def_t main_window_def = { "main-window", CL_MAIN_WINDOW, CH_ONE | CL_CONTROL | CL_LAYOUT | CL_DISPLAY, main_win_attribs, sizeof(main_win_data_t), init_main_window};static void main_window_closed(GtkWidget * widget, gpointer * gdata){ gtk_main_quit();}static int init_main_window ( vcp_widget_t *wp ){ static int have_one = 0; main_win_data_t *pd; GtkWidget *gwp; if ( have_one != 0 ) { printf ( "line %d: can't have two main windows\n", wp->linenum ); return -1; } /* get pointer to private data */ pd = (main_win_data_t *)(wp->priv_data); /* create main window, set it's size */ gwp = gtk_window_new(GTK_WINDOW_TOPLEVEL); wp->gtk_widget = gwp; wp->gtk_type = BIN; /* set the minimum size */ gtk_widget_set_usize(GTK_WIDGET(gwp), pd->width, pd->height); /* allow the user to expand it */ gtk_window_set_policy(GTK_WINDOW(gwp), FALSE, TRUE, FALSE); /* set main window title */ gtk_window_set_title(GTK_WINDOW(gwp), pd->title); /* this makes the application exit when the window is closed */ gtk_signal_connect(GTK_OBJECT(gwp), "destroy", GTK_SIGNAL_FUNC(main_window_closed), NULL); have_one = 1; return 0;}/** BOX: The box widget is used to place more than one child widget inside a parent widget that normally holds only one child. It can also draw an optional frame and title around the group of widgets it contains.*/static int init_box(vcp_widget_t *widget);typedef struct { char *layout; int expand; int padding; int uniform; int space; int frame; char *title; int border;} box_data_t;vcp_attrib_def_t box_attribs[] = { { "layout", "vert", ATTRIB_STRING, offsetof(box_data_t, layout) }, { "expand", "0", ATTRIB_BOOL, offsetof(box_data_t, expand) }, { "padding", "0", ATTRIB_INT, offsetof(box_data_t, padding) }, { "uniform", "0", ATTRIB_BOOL, offsetof(box_data_t, uniform) }, { "space", "0", ATTRIB_INT, offsetof(box_data_t, space) }, { "frame", "0", ATTRIB_BOOL, offsetof(box_data_t, frame) }, { "title", "", ATTRIB_STRING, offsetof(box_data_t, title) }, { "border", "0", ATTRIB_INT, offsetof(box_data_t, border) }, { NULL, NULL, 0, 0 }};vcp_widget_def_t box_def = { "box", CL_LAYOUT, CH_MANY | CL_CONTROL | CL_LAYOUT | CL_LABEL | CL_DISPLAY, box_attribs, sizeof(box_data_t), init_box};static int init_box ( vcp_widget_t *wp ){ box_data_t *pd; GtkWidget *gwp, *gwp2; /* get pointer to private data */ pd = (box_data_t *)(wp->priv_data); /* create the box */ if ( strncasecmp(pd->layout, "hor", 3) == 0 ) { gwp = gtk_hbox_new(pd->uniform, pd->space); } else if ( strncasecmp(pd->layout, "ver", 3) == 0 ) { gwp = gtk_vbox_new(pd->uniform, pd->space); } else { printf ( "line %d:box layout must be either horizontal or vertical\n", wp->linenum ); return -1; } wp->gtk_widget = gwp; wp->gtk_type = BOX; gtk_container_set_border_width(GTK_CONTAINER(gwp), pd->border); /* see if we need a frame */ if (( pd->frame != 0 ) || ( pd->title[0] != '\0' )) { /* create a frame */ if ( pd->title[0] == '\0' ) { /* no title */ gwp2 = gtk_frame_new(NULL); } else { gwp2 = gtk_frame_new(pd->title); } gtk_container_add(GTK_CONTAINER(gwp2), gwp); gtk_widget_show(gwp); gwp = gwp2; } /* add to the parent widget */ add_to_parent(wp->parent, gwp, pd->expand, pd->padding); gtk_widget_show(gwp); return 0;}/** LABEL: The label widget provides a simple, static label.*/static int init_label(vcp_widget_t *widget);typedef struct { int expand; int padding; char *text;} label_data_t;vcp_attrib_def_t label_attribs[] = { { "expand", "0", ATTRIB_BOOL, offsetof(label_data_t, expand) }, { "padding", "0", ATTRIB_INT, offsetof(label_data_t, padding) }, { "text", NULL, ATTRIB_STRING, offsetof(label_data_t, text) }, { NULL, NULL, 0, 0 }};vcp_widget_def_t label_def = { "label", CL_LABEL, CH_NONE, label_attribs, sizeof(label_data_t), init_label};static int init_label ( vcp_widget_t *wp ){ label_data_t *pd; GtkWidget *gwp; pd = (label_data_t *)(wp->priv_data); /* create a label */ gwp = gtk_label_new(pd->text); wp->gtk_widget = gwp; wp->gtk_type = NONE; /* add the label to the parent widget */ add_to_parent(wp->parent, gwp, pd->expand, pd->padding); gtk_widget_show(gwp); return 0;}/** SPIN_BUTTON: a numerical input field which can be hooked to a float for input */static int init_spin_button(vcp_widget_t * widget);typedef struct { int expand; int padding; char *halpin; int dec_points; double rate; double lower; double upper; double value; hal_float_t pin_state;} spin_button_data_t;typedef struct { hal_float_t *pin;} spin_button_hal_t;vcp_attrib_def_t spin_button_attribs[] = { { "expand", "0", ATTRIB_BOOL, offsetof(spin_button_data_t, expand) }, { "padding", "0", ATTRIB_INT, offsetof(spin_button_data_t, padding) }, { "halpin", NULL, ATTRIB_STRING, offsetof(spin_button_data_t, halpin) }, { "rate", "1.0", ATTRIB_FLOAT, offsetof(spin_button_data_t, rate) }, { "upper", "10.0", ATTRIB_FLOAT, offsetof(spin_button_data_t, upper) }, { "lower", "0.0", ATTRIB_FLOAT, offsetof(spin_button_data_t, lower) }, { "value", "0.0", ATTRIB_FLOAT, offsetof(spin_button_data_t, value) }, { "dec_points", "0", ATTRIB_INT, offsetof(spin_button_data_t, dec_points) }, { NULL, NULL, 0, 0 }};vcp_widget_def_t spin_button_def = { "spin_button", CL_CONTROL, CH_NONE, spin_button_attribs, sizeof(spin_button_data_t), init_spin_button};static void spin_button_changed(GtkWidget * widget, gpointer gdata){ vcp_widget_t *wp; spin_button_data_t *dp; spin_button_hal_t *hp; wp = (vcp_widget_t *)gdata; dp = (spin_button_data_t *)wp->priv_data; hp = (spin_button_hal_t *)wp->hal_data; dp->pin_state = gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON(widget)); *(hp->pin) = dp->pin_state;}static void spin_button_refresh (vcp_widget_t *wp){ spin_button_data_t *dp; spin_button_hal_t *hp; dp = (spin_button_data_t *)wp->priv_data; hp = (spin_button_hal_t *)wp->hal_data; *(hp->pin) = dp->pin_state;}static int init_spin_button ( vcp_widget_t *wp ){ spin_button_data_t *pd; spin_button_hal_t *hd; int retval; GtkWidget *gwp; GtkAdjustment *spinner_adj; pd = (spin_button_data_t *) (wp->priv_data); /* allocate HAL memory for pin */ hd = hal_malloc(sizeof(spin_button_hal_t)); if (hd == NULL) { printf( "init_spin_button(): unable to allocate HAL memory\n" ); return -1; } wp->hal_data = hd; /* export pin */ retval = hal_pin_float_new(pd->halpin, HAL_OUT, &(hd->pin), comp_id); if (retval != 0) { printf( "init_spin_button(): unable to export HAL pin '%s'\n", pd->halpin ); return -1; } /* create a new spin button, without any childs (children are not allowed for spin buttons) */ spinner_adj = (GtkAdjustment *) gtk_adjustment_new( pd->value, pd->lower, pd->upper, pd->rate, pd->rate, pd->rate); gwp = gtk_spin_button_new(spinner_adj,pd->rate,pd->dec_points); /* connect handler function to grab changes and update pin */ gtk_signal_connect(GTK_OBJECT(gwp), "changed", GTK_SIGNAL_FUNC(spin_button_changed), wp); /* put it in its parent */ add_to_parent(wp->parent, gwp, pd->expand, pd->padding); /* use a poll function for periodic refresh */ wp->poll_funct = spin_button_refresh; gtk_widget_show(gwp); /* If the hal pin is below the lower limit or above the upper limit, set to the value displayed (closer limit)*/ /* or if the hal pin is set to 0 it means that it is not updated from any other source and should be set to the initial */ /* value of the spin button */ if ( *(hd->pin) < pd->lower || *(hd->pin) > pd->upper || *(hd->pin) == 0 ) { pd->pin_state = gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON(gwp)); *(hd->pin) = pd->pin_state; } return 0; }/** BUTTON: The button widget sets a bit HAL pin TRUE while it is pressed, and FALSE when it is released. The button is not labeled, but it can accept any child widget (or widgets, if they are in a box). Normally, a label widget would be specified as a child.*/static int init_button(vcp_widget_t *widget);typedef struct { int expand; int padding; char *halpin; hal_bit_t pin_state;} button_data_t;typedef struct { hal_bit_t *pin;} button_hal_t;vcp_attrib_def_t button_attribs[] = { { "expand", "0", ATTRIB_BOOL, offsetof(button_data_t, expand) }, { "padding", "0", ATTRIB_INT, offsetof(button_data_t, padding) }, { "halpin", NULL, ATTRIB_STRING, offsetof(button_data_t, halpin) }, { NULL, NULL, 0, 0 }};vcp_widget_def_t button_def = { "button",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -