1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* chartable.c - a window with a character table
3
4 Copyright (C) 1998 - 2004 Free Software Foundation
5
6 GHex is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 GHex is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GHex; see the file COPYING.
18 If not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21 Author: Jaka Mocnik <jaka@gnu.org>
22 */
23
24 #ifdef HAVE_CONFIG_H
25 # include <config.h>
26 #endif /* HAVE_CONFIG_H */
27
28 #include <stdlib.h>
29
30 #include <gtk/gtk.h>
31 #include <gdk/gdkkeysyms.h>
32 #include <glib/gi18n.h>
33
34 #include "chartable.h"
35 #include "ghex-window.h"
36 #include "ui.h"
37
38 GtkWidget *char_table = NULL;
39 static GtkTreeSelection *sel_row = NULL;
40
41 static char *ascii_non_printable_label[] = {
42 "NUL",
43 "SOH",
44 "STX",
45 "ETX",
46 "EOT",
47 "ENQ",
48 "ACK",
49 "BEL",
50 "BS",
51 "TAB",
52 "LF",
53 "VT",
54 "FF",
55 "CR",
56 "SO",
57 "SI",
58 "DLE",
59 "DC1",
60 "DC2",
61 "DC3",
62 "DC4",
63 "NAK",
64 "SYN",
65 "ETB",
66 "CAN",
67 "EM",
68 "SUB",
69 "ESC",
70 "FS",
71 "GS",
72 "RS",
73 "US"
74 };
75
76 static void
insert_char(GtkTreeView * treeview,GtkTreeModel * model)77 insert_char(GtkTreeView *treeview, GtkTreeModel *model)
78 {
79 GHexWindow *win;
80 GtkTreeIter iter;
81 GtkTreeSelection *selection;
82 GValue value = { 0 };
83
84 selection = gtk_tree_view_get_selection(treeview);
85 if(!gtk_tree_selection_get_selected(selection, &model, &iter))
86 return;
87 gtk_tree_model_get_value(model, &iter, 2, &value);
88 if(selection == sel_row) {
89 win = ghex_window_get_active();
90 if(win->gh) {
91 hex_document_set_byte(win->gh->document, (guchar)atoi(g_value_get_string(&value)), win->gh->cursor_pos,
92 win->gh->insert, TRUE);
93 gtk_hex_set_cursor(win->gh, win->gh->cursor_pos + 1);
94 }
95 }
96 g_value_unset(&value);
97 sel_row = selection;
98 }
99
select_chartable_row_cb(GtkTreeView * treeview,GdkEventButton * event,gpointer data)100 static gboolean select_chartable_row_cb(GtkTreeView *treeview, GdkEventButton *event, gpointer data)
101 {
102 GtkTreeModel *model = GTK_TREE_MODEL(data);
103
104 if(event->type == GDK_2BUTTON_PRESS)
105 insert_char(treeview, model);
106 return FALSE;
107 }
108
hide_chartable_cb(GtkWidget * widget,GtkWidget * win)109 static void hide_chartable_cb (GtkWidget *widget, GtkWidget *win)
110 {
111 /* widget may be NULL if called from keypress cb! */
112 ghex_window_sync_char_table_item(NULL, FALSE);
113 gtk_widget_hide(win);
114 }
115
char_table_key_press_cb(GtkWindow * w,GdkEventKey * e,gpointer data)116 static gint char_table_key_press_cb (GtkWindow *w, GdkEventKey *e, gpointer data)
117 {
118 if (e->keyval == GDK_KEY_Escape) {
119 hide_chartable_cb(NULL, GTK_WIDGET(w));
120 return TRUE;
121 }
122 return FALSE;
123 }
124
key_press_cb(GtkTreeView * treeview,GdkEventKey * e,gpointer data)125 static gint key_press_cb (GtkTreeView *treeview, GdkEventKey *e, gpointer data)
126 {
127 GtkTreeModel *model = GTK_TREE_MODEL(data);
128
129 if (e->keyval == GDK_KEY_Return) {
130 insert_char(treeview, model);
131 return TRUE;
132 }
133 return FALSE;
134 }
135
136 static gboolean
char_table_delete_event_cb(GtkWidget * widget,GdkEventAny * e,gpointer user_data)137 char_table_delete_event_cb(GtkWidget *widget, GdkEventAny *e, gpointer user_data)
138 {
139 ghex_window_sync_char_table_item(NULL, FALSE);
140 gtk_widget_hide(widget);
141 return TRUE;
142 }
143
create_char_table()144 GtkWidget *create_char_table()
145 {
146 static gchar *fmt[] = { NULL, "%02X", "%03d", "%03o" };
147 static gchar *titles[] = { N_("ASCII"), N_("Hex"), N_("Decimal"),
148 N_("Octal"), N_("Binary") };
149 gchar *real_titles[5];
150 GtkWidget *ct, *sw, *ctv, *cbtn, *vbox, *hbox, *lbl;
151 GtkListStore *store;
152 GtkCellRenderer *cell_renderer;
153 GtkTreeViewColumn *column;
154 GtkTreeIter iter;
155 GtkTreeSelection *selection;
156 int i, col;
157 gchar *label, ascii_printable_label[2], bin_label[9], *row[5];
158
159 ct = gtk_window_new(GTK_WINDOW_TOPLEVEL);
160 g_signal_connect(G_OBJECT(ct), "delete_event",
161 G_CALLBACK(char_table_delete_event_cb), NULL);
162 g_signal_connect(G_OBJECT(ct), "key_press_event",
163 G_CALLBACK(char_table_key_press_cb), NULL);
164 gtk_window_set_title(GTK_WINDOW(ct), _("Character table"));
165 sw = gtk_scrolled_window_new(NULL, NULL);
166 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
167 for(i = 0; i < 5; i++)
168 real_titles[i] = _(titles[i]);
169 store = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
170 cell_renderer = gtk_cell_renderer_text_new();
171 ctv = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
172 for (i = 0; i < 5; i++) {
173 column = gtk_tree_view_column_new_with_attributes (real_titles[i], cell_renderer, "text", i, NULL);
174 gtk_tree_view_append_column(GTK_TREE_VIEW(ctv), column);
175 }
176
177 bin_label[8] = 0;
178 ascii_printable_label[1] = 0;
179 for(i = 0; i < 256; i++) {
180 if(i < 0x20)
181 row[0] = ascii_non_printable_label[i];
182 else if(i < 0x7f) {
183 ascii_printable_label[0] = i;
184 row[0] = ascii_printable_label;
185 }
186 else
187 row[0] = "";
188 for(col = 1; col < 4; col++) {
189 #if defined(__GNUC__) && (__GNUC__ > 4)
190 #pragma GCC diagnostic push
191 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
192 #endif
193 label = g_strdup_printf(fmt[col], i);
194 #if defined(__GNUC__) && (__GNUC__ > 4)
195 #pragma GCC diagnostic pop
196 #endif
197 row[col] = label;
198 }
199 for(col = 0; col < 8; col++) {
200 bin_label[7-col] = (i & (1L << col))?'1':'0';
201 row[4] = bin_label;
202 }
203
204 gtk_list_store_append(GTK_LIST_STORE(store), &iter);
205 gtk_list_store_set(GTK_LIST_STORE(store), &iter,
206 0, row[0],
207 1, row[1],
208 2, row[2],
209 3, row[3],
210 4, row[4],
211 -1);
212
213 for(col = 1; col < 4; col++)
214 g_free(row[col]);
215 }
216
217 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW (ctv));
218 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
219
220 g_signal_connect(G_OBJECT(ct), "delete-event",
221 G_CALLBACK(delete_event_cb), ct);
222 g_signal_connect(G_OBJECT(ctv), "button_press_event",
223 G_CALLBACK(select_chartable_row_cb), GTK_TREE_MODEL(store));
224 g_signal_connect(G_OBJECT(ctv), "key_press_event",
225 G_CALLBACK(key_press_cb), GTK_TREE_MODEL(store));
226 gtk_widget_grab_focus(ctv);
227
228 cbtn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
229 gtk_widget_show(cbtn);
230 g_signal_connect(G_OBJECT (cbtn), "clicked",
231 G_CALLBACK(hide_chartable_cb), ct);
232
233 lbl = gtk_label_new ("");
234 gtk_widget_show(lbl);
235
236 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4);
237 gtk_widget_show(vbox);
238
239 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
240 gtk_widget_show(hbox);
241
242 gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
243 gtk_box_pack_start(GTK_BOX(hbox), lbl, TRUE, TRUE, 4);
244 gtk_box_pack_start(GTK_BOX(hbox), cbtn, FALSE, TRUE, 12);
245 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
246
247 gtk_container_add(GTK_CONTAINER(sw), ctv);
248 gtk_container_add(GTK_CONTAINER(ct), vbox);
249 gtk_widget_show(ctv);
250 gtk_widget_show(sw);
251
252 gtk_widget_set_size_request(ct, 320, 256);
253
254 return ct;
255 }
256