fbpan: add % command
[cnoor.git] / txtwin.c
blobdd439fb5448a9d267b1313839bae24d453cb0810
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <gtk/gtk.h>
6 #include <gdk/gdkkeysyms.h>
7 #include "txtwin.h"
8 #include "util.h"
10 struct txtwin {
11 GtkWidget *main; /* a GtkTextView */
12 GtkAdjustment *adjst;
13 GtkWidget *bar; /* a GtkEntry */
14 int arg; /* command arg */
17 static void on_window_destroy(GtkWidget *widget, gpointer data)
19 gtk_main_quit();
22 enum location {
23 LOC_PAGE,
24 LOC_STEP,
25 LOC_LINE,
26 LOC_PERCENT,
27 LOC_BEG,
28 LOC_END
31 static void update_bar(struct txtwin *tw)
33 int val = gtk_adjustment_get_value(tw->adjst) +
34 gtk_adjustment_get_page_size(tw->adjst);
35 int max = gtk_adjustment_get_upper(tw->adjst);
36 char msg[128];
37 sprintf(msg, "%d%%", val * 100 / max);
38 gtk_entry_set_text(GTK_ENTRY(tw->bar), msg);
41 static int get_arg(struct txtwin *tw, int def)
43 return tw->arg == 0 ? def : tw->arg;
46 static void scroll(struct txtwin *tw, enum location loc, int n)
48 int val = gtk_adjustment_get_value(tw->adjst);
49 int page = gtk_adjustment_get_page_size(tw->adjst);
50 int end = gtk_adjustment_get_upper(tw->adjst);
51 int max = end - page;
52 n *= get_arg(tw, 1);
53 switch(loc) {
54 case LOC_PAGE:
55 val += n * gtk_adjustment_get_page_increment(tw->adjst);
56 break;
57 case LOC_STEP:
58 val += n * gtk_adjustment_get_step_increment(tw->adjst);
59 break;
60 case LOC_LINE:
61 val = get_arg(tw, 0) ? 0 : max;
62 break;
63 case LOC_PERCENT:
64 val = get_arg(tw, 0) * end / 100 - page;
65 break;
66 case LOC_BEG:
67 val = 0;
68 break;
69 case LOC_END:
70 val = max;
71 break;
73 if (val > max)
74 val = max;
75 if (val < 0)
76 val = 0;
77 tw->arg = 0;
78 gtk_adjustment_set_value(tw->adjst, val);
79 update_bar(tw);
82 static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event,
83 gpointer data)
85 struct txtwin *tw = data;
86 int mod = event->state & gtk_accelerator_get_default_mod_mask();
87 if (mod == GDK_CONTROL_MASK) {
88 switch(event->keyval) {
89 case GDK_f:
90 scroll(tw, LOC_PAGE, 1);
91 break;
92 case GDK_b:
93 scroll(tw, LOC_PAGE, -1);
94 break;
95 case GDK_l:
96 gtk_widget_queue_draw(tw->main);
97 break;
98 case GDK_n:
99 scroll(tw, LOC_STEP, 1);
100 break;
101 case GDK_p:
102 scroll(tw, LOC_STEP, -1);
103 break;
104 default:
105 break;
107 return 1;
109 switch(event->keyval) {
110 case GDK_Down:
111 case GDK_j:
112 scroll(tw, LOC_STEP, 1);
113 break;
114 case GDK_Up:
115 case GDK_k:
116 scroll(tw, LOC_STEP, -1);
117 break;
118 case GDK_G:
119 scroll(tw, LOC_LINE, 1);
120 break;
121 case GDK_End:
122 scroll(tw, LOC_END, 1);
123 break;
124 case GDK_Home:
125 scroll(tw, LOC_BEG, 1);
126 break;
127 case GDK_Next:
128 case GDK_space:
129 scroll(tw, LOC_PAGE, 1);
130 break;
131 case GDK_Prior:
132 case GDK_BackSpace:
133 scroll(tw, LOC_PAGE, -1);
134 break;
135 case GDK_q:
136 gtk_main_quit();
137 break;
138 case GDK_percent:
139 scroll(tw, LOC_PERCENT, 1);
140 break;
141 case GDK_Escape:
142 tw->arg = 0;
143 break;
144 default:
145 if (isdigit(event->keyval))
146 tw->arg = tw->arg * 10 + event->keyval - '0';
147 break;
149 return 1;
152 static void on_size_allocate(GtkWidget *w, GtkAllocation *a, gpointer tw)
154 update_bar(tw);
157 struct txtwin *txtwin_alloc()
159 GtkWidget *window;
160 GtkWidget *vbox;
161 struct txtwin *tw = xmalloc(sizeof(struct txtwin));
162 memset(tw, 0, sizeof(*tw));
163 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
164 gtk_window_set_title(GTK_WINDOW(window), "CNOOR");
165 g_signal_connect(G_OBJECT(window), "destroy",
166 G_CALLBACK(on_window_destroy), NULL);
168 vbox = gtk_vbox_new(FALSE, 2);
169 gtk_container_add(GTK_CONTAINER(window), vbox);
171 /* create the textview */
172 tw->main = gtk_text_view_new();
173 gtk_box_pack_start(GTK_BOX(vbox), tw->main, 1, 1, 0);
174 gtk_signal_connect(GTK_OBJECT(tw->main), "key_press_event",
175 GTK_SIGNAL_FUNC(on_key_press), tw);
176 gtk_signal_connect(GTK_OBJECT(window), "size_allocate",
177 GTK_SIGNAL_FUNC(on_size_allocate), tw);
178 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tw->main),
179 GTK_WRAP_WORD);
180 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(tw->main), FALSE);
182 /* add the adjustment */
183 tw->adjst = GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, 100, 1, 9, 10));
184 gtk_widget_set_scroll_adjustments(tw->main, NULL, tw->adjst);
186 /* create the minibuffer */
187 tw->bar = gtk_entry_new();
188 gtk_box_pack_start(GTK_BOX(vbox), tw->bar, 0, 0, 0);
189 gtk_signal_connect(GTK_OBJECT(tw->bar), "key_press_event",
190 GTK_SIGNAL_FUNC(on_key_press), tw);
191 update_bar(tw);
193 gtk_widget_set_size_request(window, 800, 600);
194 gtk_window_set_default_size(GTK_WINDOW(window), 1024, 768);
195 gtk_widget_show_all(window);
196 return tw;
199 void txtwin_free(struct txtwin *tw)
201 free(tw);
204 void txtwin_loop(struct txtwin *tw)
206 gtk_main();
209 void txtwin_gtk_init(int argc, char **argv)
211 gtk_init(&argc, &argv);
214 static GtkTextBuffer *txtwin_buffer(struct txtwin *tw)
216 return gtk_text_view_get_buffer(GTK_TEXT_VIEW(tw->main));
219 void txtwin_append(struct txtwin *tw, char *s, char *tag)
221 GtkTextIter iter;
222 GtkTextBuffer *buf = txtwin_buffer(tw);
223 gtk_text_buffer_get_end_iter(buf, &iter);
224 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, s, strlen(s),
225 tag, NULL);
228 void txtwin_tag(struct txtwin *tw, char *name, char *fg, char *bg, char *font)
230 GtkTextBuffer *buf = txtwin_buffer(tw);
231 gtk_text_buffer_create_tag(buf, name,
232 "foreground", fg,
233 "background", bg,
234 "font", font,
235 NULL);