81ffd7311dea4273e4557fae687acc945dec746e
[pspp-builds.git] / src / ui / gui / widget-io.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2007  Free Software Foundation
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "widget-io.h"
20
21 #include <string.h>
22 #include <stdlib.h>
23 #include <gl/printf-parse.h>
24 #include <stdarg.h>
25 #include <gtk/gtk.h>
26
27 #include <gl/gettext.h>
28
29
30
31 static void
32 ship_label (GtkBox *box, const char **s, const char_directive *dir)
33 {
34   GtkWidget *label ;
35   gchar *text = g_strdup (*s);
36
37   if ( dir )
38     {
39       text [ dir->dir_start - *s ] = '\0';
40       *s = dir->dir_end;
41     }
42
43   label = gtk_label_new (text);
44   g_free (text);
45
46   gtk_box_pack_start (box, label, FALSE, FALSE, 0);
47   gtk_widget_show (label);
48 }
49
50 /* Returns a string generated from FMT and a list of GtkEntry widgets.
51    Each conversion in FMT will be replaced with the text from the
52    corresponding GtkEntry.  The normal printf semantics will be ignored.
53    Note that the GtkEntry widgets may be GtkSpinbuttons or any other widget
54    derived from GtkEntry.
55    The returned string should be freed when no longer required.
56  */
57 gchar *
58 widget_printf (const gchar *fmt, ...)
59 {
60   gint i;
61   char_directives d;
62   arguments a;
63   GString *output;
64   GtkWidget **widgets;
65   gchar *text;
66   va_list ap;
67   const char *s = fmt;
68
69   if ( 0 !=  printf_parse (fmt, &d, &a) )
70     return NULL;
71
72   widgets = calloc (sizeof (*widgets), d.count);
73   va_start (ap, fmt);
74   for (i = 0 ; i < d.count ; ++i )
75     {
76       if ( d.dir[i].conversion != '%')
77         widgets[i] = va_arg (ap, GtkWidget *);
78     }
79   va_end (ap);
80
81   g_free (a.arg);
82
83   output = g_string_sized_new (strlen (fmt));
84
85   for (i = 0 ; i < d.count ; ++i )
86     {
87       char_directive dir = d.dir[i];
88       GtkWidget *w ;
89       const gchar *entry_text;
90
91       if ( dir.conversion == '%')
92         {
93           s++;
94           continue;
95         }
96
97       w = widgets [dir.arg_index];
98       entry_text = gtk_entry_get_text (GTK_ENTRY (w));
99
100       if ( dir.dir_start > s )
101         g_string_append_len (output, s, dir.dir_start - s);
102
103       s = dir.dir_end;
104
105       g_string_append (output, entry_text);
106     }
107
108   free (widgets);
109   free (d.dir);
110
111   if (*s)
112     g_string_append_len (output, s, -1);
113
114   text = output->str;
115   g_string_free (output, FALSE);
116   return text;
117 }
118
119 /*
120    Returns a GtkHBox populated with an GtkLabel and GtkEntry widgets.
121    Each conversion in FMT will cause a GtkEntry (possibly a GtkSpinButton) to
122    be created.  Any text between conversions produces a GtkLabel.
123    There should be N arguments following FMT should be of type GtkEntry **,
124    where N is the number of conversions.
125    These arguments will be filled with a pointer to the corresponding widgets.
126    Their properties may be changed, but they should not be unrefed.
127  */
128 GtkWidget *
129 widget_scanf (const gchar *fmt, ...)
130 {
131   char_directives d;
132   arguments a;
133   int i;
134   va_list ap;
135   GtkWidget ***widgets = NULL;
136   GtkWidget *hbox = NULL;
137   GtkWidget **w;
138   const char *s = fmt;
139
140   if ( 0 !=  printf_parse (fmt, &d, &a) )
141     return NULL;
142
143   g_free (a.arg);
144
145   va_start (ap, fmt);
146
147   if ( d.count > 0 )
148     {
149       hbox = gtk_hbox_new (FALSE, 0);
150       widgets = calloc (sizeof (*widgets), d.count);
151     }
152
153   for (i = 0 ; i < d.count ; ++i )
154     {
155       if ( d.dir[i].conversion != '%')
156         widgets[i] = va_arg (ap, GtkWidget **);
157     }
158   va_end (ap);
159
160
161   for (i = 0 ; i < d.count ; ++i )
162     {
163       char_directive dir = d.dir[i];
164       int precision = 0;
165       int width = 0;
166
167
168       if ( dir.precision_start && dir.precision_end)
169         precision = strtol (dir.precision_start + 1,
170                             (char **) &dir.precision_end, 10);
171
172       if ( dir.width_start && dir.width_end )
173         width = strtol (dir.width_start, (char **) &dir.width_end, 10);
174
175       if ( dir.dir_start > s )
176         ship_label (GTK_BOX (hbox), &s, &dir);
177
178       if ( dir.conversion == '%')
179         {
180           s++;
181           continue;
182         }
183
184       w = widgets [dir.arg_index];
185       switch (dir.conversion)
186         {
187         case 'd':
188         case 'i':
189         case 'f':
190           {
191             *w = gtk_spin_button_new_with_range (0, 100.0, 1.0);
192             g_object_set (*w, "digits", precision, NULL);
193           }
194           break;
195         case 's':
196           *w = gtk_entry_new ();
197           break;
198         };
199
200       g_object_set (*w, "width-chars", width, NULL);
201       gtk_box_pack_start (GTK_BOX (hbox), *w, FALSE, FALSE, 0);
202       gtk_widget_show (*w);
203     }
204
205   if ( *s )
206     ship_label (GTK_BOX (hbox), &s, NULL);
207
208
209   g_free (widgets);
210
211   free (d.dir);
212
213   return hbox;
214 }