txtwin: support 1G command
[cnoor.git] / txtwin.c
blob25f456a3fc6205ee1e321e5568f543740aac35af
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 /* a GtkTextView */
12 GtkWidget *main;
13 GtkAdjustment *adjst;
14 /* a GtkEntry */
15 GtkWidget *bar;
16 /* command arg */
17 int arg;
20 static void on_window_destroy(GtkWidget *widget, gpointer data)
22 gtk_main_quit();
25 enum location {
26 LOC_PAGE,
27 LOC_STEP,
28 LOC_LINE,
29 LOC_BEG,
30 LOC_END
33 static void update_bar(struct txtwin *tw)
35 int val = gtk_adjustment_get_value(tw->adjst) +
36 gtk_adjustment_get_page_size(tw->adjst);
37 int max = gtk_adjustment_get_upper(tw->adjst);
38 char msg[128];
39 sprintf(msg, "%d%%", val * 100 / max);
40 gtk_entry_set_text(GTK_ENTRY(tw->bar), msg);
43 static int get_arg(struct txtwin *tw, int def)
45 return tw->arg == 0 ? def : tw->arg;
48 static void scroll(struct txtwin *tw, enum location loc, int n)
50 int val = gtk_adjustment_get_value(tw->adjst);
51 int max = gtk_adjustment_get_upper(tw->adjst) -
52 gtk_adjustment_get_page_size(tw->adjst);
53 n *= get_arg(tw, 1);
54 switch(loc) {
55 case LOC_PAGE:
56 val += n * gtk_adjustment_get_page_increment(tw->adjst);
57 break;
58 case LOC_STEP:
59 val += n * gtk_adjustment_get_step_increment(tw->adjst);
60 break;
61 case LOC_LINE:
62 val = get_arg(tw, 0) ? 0 : max;
63 break;
64 case LOC_BEG:
65 val = 0;
66 break;
67 case LOC_END:
68 val = max;
69 break;
71 if (val > max)
72 val = max;
73 if (val < 0)
74 val = 0;
75 tw->arg = 0;
76 gtk_adjustment_set_value(tw->adjst, val);
77 update_bar(tw);
80 static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event,
81 gpointer data)
83 struct txtwin *tw = data;
84 int mod = event->state & gtk_accelerator_get_default_mod_mask();
85 if (mod == GDK_CONTROL_MASK) {
86 switch(event->keyval) {
87 case GDK_f:
88 scroll(tw, LOC_PAGE, 1);
89 break;
90 case GDK_b:
91 scroll(tw, LOC_PAGE, -1);
92 break;
93 case GDK_l:
94 gtk_widget_queue_draw(tw->main);
95 break;
96 case GDK_n:
97 scroll(tw, LOC_STEP, 1);
98 break;
99 case GDK_p:
100 scroll(tw, LOC_STEP, -1);
101 break;
102 default:
103 break;
105 return 1;
107 switch(event->keyval) {
108 case GDK_Down:
109 case GDK_j:
110 scroll(tw, LOC_STEP, 1);
111 break;
112 case GDK_Up:
113 case GDK_k:
114 scroll(tw, LOC_STEP, -1);
115 break;
116 case GDK_G:
117 scroll(tw, LOC_LINE, 1);
118 break;
119 case GDK_End:
120 scroll(tw, LOC_END, 1);
121 break;
122 case GDK_Home:
123 scroll(tw, LOC_BEG, 1);
124 break;
125 case GDK_Next:
126 case GDK_space:
127 scroll(tw, LOC_PAGE, 1);
128 break;
129 case GDK_Prior:
130 case GDK_BackSpace:
131 scroll(tw, LOC_PAGE, -1);
132 break;
133 case GDK_q:
134 gtk_main_quit();
135 break;
136 case GDK_Escape:
137 tw->arg = 0;
138 default:
139 if (isdigit(event->keyval))
140 tw->arg = tw->arg * 10 + event->keyval - '0';
141 break;
143 return 1;
146 static void on_size_allocate(GtkWidget *w, GtkAllocation *a, gpointer tw)
148 update_bar(tw);
151 struct txtwin *txtwin_alloc()
153 GtkWidget *window;
154 GtkWidget *vbox;
155 struct txtwin *tw = xmalloc(sizeof(struct txtwin));
156 memset(tw, 0, sizeof(*tw));
157 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
158 gtk_window_set_title(GTK_WINDOW(window), "CNOOR");
159 g_signal_connect(G_OBJECT(window), "destroy",
160 G_CALLBACK(on_window_destroy), NULL);
162 vbox = gtk_vbox_new(FALSE, 2);
163 gtk_container_add(GTK_CONTAINER(window), vbox);
165 /* create the textview */
166 tw->main = gtk_text_view_new();
167 gtk_box_pack_start(GTK_BOX(vbox), tw->main, 1, 1, 0);
168 gtk_signal_connect(GTK_OBJECT(tw->main), "key_press_event",
169 GTK_SIGNAL_FUNC(on_key_press), tw);
170 gtk_signal_connect(GTK_OBJECT(window), "size_allocate",
171 GTK_SIGNAL_FUNC(on_size_allocate), tw);
172 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tw->main),
173 GTK_WRAP_WORD);
174 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(tw->main), FALSE);
176 /* add the adjustment */
177 tw->adjst = GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, 100, 1, 9, 10));
178 gtk_widget_set_scroll_adjustments(tw->main, NULL, tw->adjst);
180 /* create the minibuffer */
181 tw->bar = gtk_entry_new();
182 gtk_box_pack_start(GTK_BOX(vbox), tw->bar, 0, 0, 0);
183 gtk_signal_connect(GTK_OBJECT(tw->bar), "key_press_event",
184 GTK_SIGNAL_FUNC(on_key_press), tw);
185 update_bar(tw);
187 gtk_widget_set_size_request(window, 800, 600);
188 gtk_window_set_default_size(GTK_WINDOW(window), 1024, 768);
189 gtk_widget_show_all(window);
190 return tw;
193 void txtwin_free(struct txtwin *tw)
195 free(tw);
198 void txtwin_loop(struct txtwin *tw)
200 gtk_main();
203 void txtwin_gtk_init(int argc, char **argv)
205 gtk_init(&argc, &argv);
208 static GtkTextBuffer *txtwin_buffer(struct txtwin *tw)
210 return gtk_text_view_get_buffer(GTK_TEXT_VIEW(tw->main));
213 void txtwin_append(struct txtwin *tw, char *s, char *tag)
215 GtkTextIter iter;
216 GtkTextBuffer *buf = txtwin_buffer(tw);
217 gtk_text_buffer_get_end_iter(buf, &iter);
218 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, s, strlen(s),
219 tag, NULL);
222 void txtwin_tag(struct txtwin *tw, char *name, char *fg, char *bg, char *font)
224 GtkTextBuffer *buf = txtwin_buffer(tw);
225 gtk_text_buffer_create_tag(buf, name,
226 "foreground", fg,
227 "background", bg,
228 "font", font,
229 NULL);