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