Set up current working directory on File->Open
[gscope.git] / notebook.c
blob17726bd98fbd2e1b95b7689521ff82405c3c036d
1 /*
2 * (c) 2010 Cyrill Gorcunov, gorcunov@gmail.com
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 2 of the License, or (at
7 * your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 #include <unistd.h>
21 #include <stdio.h>
22 #include <stddef.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <limits.h>
28 #include <sys/param.h>
29 #include <sys/types.h>
31 #include <gtk/gtk.h>
33 #include "notebook.h"
35 #include "util.h"
36 #include "list.h"
38 #include "sourceview.h"
40 #include "backend-proto.h"
42 #define NB_PAGE_LOCKED_IMG GTK_STOCK_NO
43 #define NB_PAGE_UNLOCKED_IMG GTK_STOCK_YES
45 #define NB_CLOSE_PAGE_RC_NAME "nb_page_close-button"
46 static const char nb_page_close_rc[] =
47 "style \"nb_page_close-style\"\n"
48 "{\n"
49 " GtkWidget::focus-padding = 0\n"
50 " GtkWidget::focus-line-width = 0\n"
51 " xthickness = 0\n"
52 " ythickness = 0\n"
53 "}\n"
54 "widget \"*.nb_page_close-button\" style \"nb_page_close-style\"";
56 #define NB_LOCK_PAGE_RC_NAME "nb_page_lock-button"
57 static const char nb_page_lock_rc[] =
58 "style \"nb_page_lock-style\"\n"
59 "{\n"
60 " GtkWidget::focus-padding = 0\n"
61 " GtkWidget::focus-line-width = 0\n"
62 " xthickness = 0\n"
63 " ythickness = 0\n"
64 "}\n"
65 "widget \"*.nb_page_lock-button\" style \"nb_page_lock-style\"";
67 void notebook_init(void)
69 gtk_rc_parse_string(nb_page_close_rc);
70 gtk_rc_parse_string(nb_page_lock_rc);
73 void notebook_fini(void)
75 /* FIXME: Something there? */
78 static void notebook_delete_title(struct notebook_title *title)
80 gtk_widget_destroy(title->label);
81 gtk_widget_destroy(title->lock_image);
82 gtk_widget_destroy(title->lock_button);
83 gtk_widget_destroy(title->close_image);
84 gtk_widget_destroy(title->close_button);
86 memset(title, 0, sizeof(*title));
89 static void notebook_delete_page(struct notebook_page *page)
91 GtkNotebook *nb = GTK_NOTEBOOK(page->notebook->me);
92 int pos;
94 /* title composite */
95 notebook_delete_title(&page->title);
97 /* child widget (text view and friends) */
98 if (page->child) {
100 * NOTE: If child widget embedded into notebook
101 * deletes itself we should not call gtk_notebook_remove_page
102 * the GTK will delete the page by self
104 if (page->child_delete_hook) {
105 page->child_delete_hook(page->child, page->private);
106 } else {
107 pos = gtk_notebook_page_num(nb, page->child);
108 if (pos != NB_ENOPAGE)
109 gtk_notebook_remove_page(GTK_NOTEBOOK(page->notebook->me), pos);
113 list_del(&page->siblings);
114 free(page);
117 static void cb_page_switched(GtkNotebook *nb, GtkWidget *pg,
118 guint page_num, gpointer user_data)
120 struct notebook *notebook = (struct notebook *)user_data;
121 struct notebook_page *page;
122 unsigned int num;
124 list_for_each_entry(page, &notebook->pages, siblings) {
125 num = gtk_notebook_page_num(GTK_NOTEBOOK(notebook->me), page->child);
126 if (num == page_num) {
127 if (page->page_changed_hook)
128 page->page_changed_hook(page);
129 else
130 break;
135 struct notebook *notebook_create(void)
137 struct notebook *notebook = xzalloc(sizeof(*notebook));
139 notebook->me = GTK_WIDGET(gtk_notebook_new());
140 INIT_LIST_HEAD(&notebook->pages);
142 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook->me), TRUE);
144 /* signals */
145 g_signal_connect(G_OBJECT(notebook->me), "switch-page",
146 G_CALLBACK(cb_page_switched), (gpointer)notebook);
148 return notebook;
151 void notebook_delete(struct notebook *notebook)
153 if (!notebook)
154 return;
156 if (!list_empty(&notebook->pages)) {
157 struct notebook_page *page, *n;
158 list_for_each_entry_safe(page, n, &notebook->pages, siblings)
159 notebook_delete_page(page);
162 gtk_widget_destroy(notebook->me);
163 free(notebook);
166 static void cb_lock_page(GtkButton *widget, gpointer data)
168 struct notebook_page *page = data;
169 GtkImage *image = GTK_IMAGE(page->title.lock_image);
171 gtk_image_clear(image);
173 if (page->status & NB_STATUS_LOCKED) {
174 gtk_image_set_from_stock(image, NB_PAGE_UNLOCKED_IMG, GTK_ICON_SIZE_MENU);
175 page->status &= ~NB_STATUS_LOCKED;
176 } else {
177 gtk_image_set_from_stock(image, GTK_STOCK_NO, GTK_ICON_SIZE_MENU);
178 page->status |= NB_STATUS_LOCKED;
181 gtk_widget_show_all(GTK_WIDGET(image));
184 static void cb_close_page(GtkButton *widget, gpointer data)
186 struct notebook_page *notebook_page = data;
187 if (!(notebook_page->status & NB_STATUS_LOCKED))
188 notebook_delete_page((struct notebook_page *)data);
191 /* create new empty page */
192 struct notebook_page *notebook_create_page(struct notebook *notebook, char *title, int title_nchars, int status)
194 struct notebook_page *page;
196 page = xzalloc(sizeof(*page));
197 page->status = status;
198 page->title.container = gtk_hbox_new(FALSE, 3);
199 page->title.label = gtk_label_new(title);
200 page->title.close_button = gtk_button_new();
201 page->title.lock_button = gtk_button_new();
202 page->title.close_image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
203 page->title.lock_image = gtk_image_new_from_stock(NB_PAGE_UNLOCKED_IMG, GTK_ICON_SIZE_MENU);
205 gtk_label_set_max_width_chars(GTK_LABEL(page->title.label), title_nchars);
207 gtk_widget_set_name(page->title.close_button, NB_CLOSE_PAGE_RC_NAME);
208 gtk_widget_set_name(page->title.close_button, NB_LOCK_PAGE_RC_NAME);
210 gtk_button_set_relief(GTK_BUTTON(page->title.close_button), GTK_RELIEF_NONE);
211 gtk_button_set_relief(GTK_BUTTON(page->title.lock_button), GTK_RELIEF_NONE);
213 gtk_box_pack_start(GTK_BOX(page->title.container), page->title.lock_button, TRUE, TRUE, 0);
214 gtk_box_pack_start(GTK_BOX(page->title.container), page->title.label, TRUE, TRUE, 0);
215 gtk_box_pack_start(GTK_BOX(page->title.container), page->title.close_button, FALSE, FALSE, 0);
217 gtk_container_add(GTK_CONTAINER(page->title.lock_button), page->title.lock_image);
218 gtk_container_add(GTK_CONTAINER(page->title.close_button), page->title.close_image);
220 /* buttons signals */
221 g_signal_connect(page->title.lock_button, "clicked", G_CALLBACK(cb_lock_page), page);
222 g_signal_connect(page->title.close_button, "clicked", G_CALLBACK(cb_close_page), page);
224 gtk_widget_show_all(page->title.container);
226 /* link to notebook */
227 page->notebook = notebook;
228 list_add(&page->siblings, &notebook->pages);
230 return page;
233 void notebook_page_child_attach(struct notebook_page *page, GtkWidget *widget, void *private,
234 void (*page_changed_hook)(struct notebook_page *page),
235 void (*child_delete_hook)(GtkWidget *child, void *private))
237 page->child = widget;
238 page->page_changed_hook = page_changed_hook;
239 page->child_delete_hook = child_delete_hook;
240 page->private = private;
242 gtk_notebook_append_page(GTK_NOTEBOOK(page->notebook->me), widget, page->title.container);
243 gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(page->notebook->me), widget, TRUE);
246 void notebook_page_child_dettach(struct notebook_page *page)
248 page->child = NULL;
249 page->child_delete_hook = NULL;
250 page->private = NULL;
253 void notebook_activate_page(struct notebook *notebook, struct notebook_page *page)
255 int num;
256 gtk_widget_show(page->child);
257 num = gtk_notebook_page_num(GTK_NOTEBOOK(notebook->me), page->child);
258 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook->me), num);
261 struct notebook_page *notebook_page_find(struct notebook *notebook, GtkWidget *child)
263 struct notebook_page *page;
265 list_for_each_entry(page, &notebook->pages, siblings) {
266 if (page->child == child)
267 return page;
270 return NULL;