1 /*
2  * Xiphos Bible Study Tool
3  * navbar_book.c - navigation bar for genbook modules
4  *
5  * Copyright (C) 2000-2020 Xiphos Developer Team
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include <gtk/gtk.h>
27 
28 #include "gui/navbar_book.h"
29 #include "gui/utilities.h"
30 
31 #include "main/navbar_book.h"
32 #include "main/settings.h"
33 #include "main/sword.h"
34 #include "main/url.hh"
35 
36 NAVBAR_BOOK navbar_book;
37 
38 /******************************************************************************
39  * Name
40  *   menu_deactivate_callback
41  *
42  * Synopsis
43  *   #include "gui/navbar_book.h"
44  *
45  *   void menu_deactivate_callback (GtkWidget *widget, gpointer user_data)
46  *
47  * Description
48  *   return toogle button to normal
49  *
50  * Return value
51  *   void
52  */
53 
menu_deactivate_callback(GtkWidget * widget,gpointer user_data)54 static void menu_deactivate_callback(GtkWidget *widget,
55 				     gpointer user_data)
56 {
57 	GtkWidget *menu_button;
58 
59 	menu_button = GTK_WIDGET(user_data);
60 
61 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(menu_button),
62 				     FALSE);
63 }
64 
65 /******************************************************************************
66  * Name
67  *   menu_position_under
68  *
69  * Synopsis
70  *   #include "gui/navbar_book.h"
71  *
72  *   void menu_position_under(GtkMenu * menu, int * x, int * y,
73  *				gboolean * push_in, gpointer user_data)
74  *
75  * Description
76  *   position drop down menu under toogle button
77  *
78  *
79  * Return value
80  *   void
81  */
82 
menu_position_under(GtkMenu * menu,int * x,int * y,gboolean * push_in,gpointer user_data)83 static void menu_position_under(GtkMenu *menu, int *x, int *y,
84 				gboolean *push_in, gpointer user_data)
85 {
86 	GtkWidget *widget;
87 	GtkAllocation allocation;
88 	g_return_if_fail(GTK_IS_BUTTON(user_data));
89 #if GTK_CHECK_VERSION(2, 20, 0)
90 	g_return_if_fail(gtk_widget_get_window(user_data));
91 #else
92 	g_return_if_fail(GTK_WIDGET_NO_WINDOW(user_data));
93 #endif
94 
95 	widget = GTK_WIDGET(user_data);
96 
97 	gdk_window_get_origin(gtk_widget_get_window(widget), x, y);
98 	gtk_widget_get_allocation(widget, &allocation);
99 	*x += allocation.x;
100 	*y += allocation.y + allocation.height;
101 
102 	*push_in = FALSE;
103 }
104 
lookup_entry_press_callback(GtkWidget * widget,GdkEventKey * event,gpointer user_data)105 static gboolean lookup_entry_press_callback(GtkWidget *widget,
106 					    GdkEventKey *event,
107 					    gpointer user_data)
108 {
109 	if (!settings.havebook)
110 		return FALSE;
111 	/* this does not work on my system - hope I'm not messing things up
112 	   for others - 104 is the enter key on the number pad
113 	   switch (event->hardware_keycode) {
114 	   case 98:
115 	   gtk_button_clicked(GTK_BUTTON(navbar_book.button_up));
116 	   return TRUE;
117 	   break;
118 	   case 104:
119 	   gtk_button_clicked(GTK_BUTTON(navbar_book.button_down));
120 	   return TRUE;
121 	   break;
122 	   case 100:
123 	   gtk_button_clicked(GTK_BUTTON(navbar_book.button_left));
124 	   return TRUE;
125 	   break;
126 	   case 102:
127 	   gtk_button_clicked(GTK_BUTTON(navbar_book.button_right));
128 	   return TRUE;
129 	   break;
130 	   }
131 	 */
132 	XI_message(("lookup_entry_press_callback\nkeycode: %d",
133 		    event->hardware_keycode));
134 	return FALSE;
135 }
136 
137 /******************************************************************************
138  * Name
139  *   select_button_press_callback
140  *
141  * Synopsis
142  *   #include "gui/navbar_book.h"
143  *
144  *   gboolean select_button_press_callback (GtkWidget *widget,
145  *			      GdkEventButton *event,
146  *			      gpointer user_data)
147  *
148  * Description
149  *    make the tooglebutton act like a gtk optionmenu by dropping a popup
150  *    under the button
151  *
152  * Return value
153  *   gboolean
154  */
155 
select_button_press_callback(GtkWidget * widget,GdkEventButton * event,gpointer user_data)156 static gboolean select_button_press_callback(GtkWidget *widget,
157 					     GdkEventButton *event,
158 					     gpointer user_data)
159 {
160 	GtkWidget *menu;
161 
162 	if (!settings.havebook)
163 		return FALSE;
164 	menu = main_book_drop_down_new();
165 	g_signal_connect(menu, "deactivate",
166 			 G_CALLBACK(menu_deactivate_callback), widget);
167 	if ((event->type == GDK_BUTTON_PRESS) && event->button == 1) {
168 		gtk_widget_grab_focus(widget);
169 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
170 					     TRUE);
171 #if GTK_CHECK_VERSION(3, 22, 0)
172 		gtk_menu_popup_at_widget(GTK_MENU(menu), widget, GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, NULL);
173 #else
174 		gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
175 			       menu_position_under, widget, event->button,
176 			       event->time);
177 #endif
178 		return TRUE;
179 	}
180 	return FALSE;
181 }
182 
183 /******************************************************************************
184  * Name
185  *  on_button_parent_clicked
186  *
187  * Synopsis
188  *   #include "gui/navbar_book.h"
189  *
190  *  void on_button_parent_clicked(GtkButton * button, gpointer user_data)
191  *
192  * Description
193  *   call main_navbar_book_parent() in main/navbar_book.cc
194  *
195  * Return value
196  *   void
197  */
198 
on_button_parent_clicked(GtkButton * button,gpointer user_data)199 static void on_button_parent_clicked(GtkButton *button, gpointer user_data)
200 {
201 	if (!settings.havebook)
202 		return;
203 	main_navbar_book_parent();
204 }
205 
206 /******************************************************************************
207  * Name
208  *  on_button_child_clicked
209  *
210  * Synopsis
211  *   #include "gui/navbar_book.h"
212  *
213  *  void on_button_child_clicked(GtkButton * button, gpointer user_data)
214  *
215  * Description
216  *   call main_navbar_book_first_child() in main/navbar_book.cc
217  *
218  * Return value
219  *   void
220  */
221 
on_button_child_clicked(GtkButton * button,gpointer user_data)222 static void on_button_child_clicked(GtkButton *button, gpointer user_data)
223 {
224 	if (!settings.havebook)
225 		return;
226 	main_navbar_book_first_child();
227 }
228 
229 /******************************************************************************
230  * Name
231  *  on_button_prev_clicked
232  *
233  * Synopsis
234  *   #include "gui/navbar_book.h"
235  *
236  *  void on_button_prev_clicked(GtkButton * button, gpointer user_data)
237  *
238  * Description
239  *   call main_navbar_book_prev() in main/navbar_book.cc
240  *
241  * Return value
242  *   void
243  */
244 
on_button_prev_clicked(GtkButton * button,gpointer user_data)245 static void on_button_prev_clicked(GtkButton *button, gpointer user_data)
246 {
247 	if (!settings.havebook)
248 		return;
249 	main_navbar_book_prev();
250 }
251 
252 /******************************************************************************
253  * Name
254  *  on_button_next_clicked
255  *
256  * Synopsis
257  *   #include "gui/navbar_book.h"
258  *
259  *  void on_button_next_clicked(GtkButton * button, gpointer user_data)
260  *
261  * Description
262  *   call main_navbar_book_next(); in main/navbar_book.cc
263  *
264  * Return value
265  *   void
266  */
267 
on_button_next_clicked(GtkButton * button,gpointer user_data)268 static void on_button_next_clicked(GtkButton *button, gpointer user_data)
269 {
270 	if (!settings.havebook)
271 		return;
272 	main_navbar_book_next();
273 }
274 
275 /******************************************************************************
276  * Name
277  *    on_entry_activate
278  *
279  * Synopsis
280  *   #include "gui/navbar_book.h"
281  *
282  *  void on_entry_activate (GtkEntry *entry, gpointer  user_data)
283  *
284  * Description
285  *    get entry text and call main_navbar_book_entry_activate();
286  *    in main/navbar_book.cc
287  *
288  * Return value
289  *   void
290  */
291 
on_entry_activate(GtkEntry * entry,gpointer user_data)292 void on_entry_activate(GtkEntry *entry, gpointer user_data)
293 {
294 	const gchar *entry_buf = NULL;
295 
296 	entry_buf = gtk_entry_get_text(entry);
297 	main_navbar_book_entry_activate(entry_buf);
298 }
299 
300 /******************************************************************************
301  * Name
302  *  gui_navbar_book_new
303  *
304  * Synopsis
305  *   #include "gui/navbar_book.h"
306  *
307  *  GtkWidget *gui_navbar_book_new(void)
308  *
309  * Description
310  *   create a new gen book navigation toolbar and return it
311  *
312  * Return value
313  *   GtkWidget *
314  */
315 
gui_navbar_book_new(void)316 GtkWidget *gui_navbar_book_new(void)
317 {
318 	GtkWidget *vbox1;
319 	GtkWidget *hbox1;
320 	GtkWidget *image1;
321 	GtkWidget *arrow1;
322 	GtkWidget *image2;
323 
324 	UI_VBOX(vbox1, FALSE, 0);
325 	gtk_widget_show(vbox1);
326 
327 	UI_HBOX(hbox1, FALSE, 0);
328 	gtk_widget_show(hbox1);
329 	gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, TRUE, 0);
330 
331 	navbar_book.lookup_entry = gtk_entry_new();
332 	gtk_widget_show(navbar_book.lookup_entry);
333 	gtk_box_pack_start(GTK_BOX(hbox1), navbar_book.lookup_entry, TRUE,
334 			   TRUE, 0);
335 	gtk_editable_set_editable(GTK_EDITABLE(navbar_book.lookup_entry),
336 				  TRUE);
337 	gtk_entry_set_invisible_char(GTK_ENTRY(navbar_book.lookup_entry),
338 				     9679);
339 
340 	navbar_book.button_list = gtk_toggle_button_new();
341 	gtk_widget_show(navbar_book.button_list);
342 	gtk_box_pack_start(GTK_BOX(hbox1), navbar_book.button_list, FALSE,
343 			   FALSE, 0);
344 
345 #if GTK_CHECK_VERSION(3, 14, 0)
346 	arrow1 =
347 	    gtk_image_new_from_icon_name("open-menu-symbolic",
348 					 GTK_ICON_SIZE_BUTTON);
349 #else
350 	arrow1 = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
351 #endif
352 	gtk_widget_show(arrow1);
353 	gtk_container_add(GTK_CONTAINER(navbar_book.button_list), arrow1);
354 
355 	navbar_book.button_left = gtk_button_new();
356 	gtk_widget_show(navbar_book.button_left);
357 	gtk_box_pack_start(GTK_BOX(hbox1), navbar_book.button_left, FALSE,
358 			   FALSE, 0);
359 	gtk_widget_set_tooltip_text(navbar_book.button_left,
360 				    _("Go outward, to the section containing this one"));
361 
362 	gtk_button_set_relief(GTK_BUTTON(navbar_book.button_left),
363 			      GTK_RELIEF_NONE);
364 #if GTK_CHECK_VERSION(3, 20, 0)
365 	gtk_widget_set_focus_on_click(GTK_WIDGET(navbar_book.button_left), FALSE);
366 #else
367 	gtk_button_set_focus_on_click(GTK_BUTTON(navbar_book.button_left), FALSE);
368 #endif
369 
370 	image1 =
371 #if GTK_CHECK_VERSION(3, 10, 0)
372 	    gtk_image_new_from_icon_name("go-previous-symbolic", GTK_ICON_SIZE_BUTTON);
373 #else
374 	    gtk_image_new_from_stock(GTK_STOCK_GO_BACK, GTK_ICON_SIZE_BUTTON);
375 #endif
376 	gtk_widget_show(image1);
377 	gtk_container_add(GTK_CONTAINER(navbar_book.button_left), image1);
378 
379 	navbar_book.button_up = gtk_button_new();
380 	gtk_widget_show(navbar_book.button_up);
381 	gtk_box_pack_start(GTK_BOX(hbox1), navbar_book.button_up, FALSE,
382 			   FALSE, 0);
383 	gtk_widget_set_tooltip_text(navbar_book.button_up,
384 				    _("Go to previous item"));
385 	gtk_button_set_relief(GTK_BUTTON(navbar_book.button_up),
386 			      GTK_RELIEF_NONE);
387 #if GTK_CHECK_VERSION(3, 20, 0)
388 	gtk_widget_set_focus_on_click(GTK_WIDGET(navbar_book.button_up), FALSE);
389 #else
390 	gtk_button_set_focus_on_click(GTK_BUTTON(navbar_book.button_up), FALSE);
391 #endif
392 
393 	image1 =
394 #if GTK_CHECK_VERSION(3, 10, 0)
395 	    gtk_image_new_from_icon_name("go-up-symbolic", GTK_ICON_SIZE_BUTTON);
396 #else
397 	    gtk_image_new_from_stock(GTK_STOCK_GO_UP, GTK_ICON_SIZE_BUTTON);
398 #endif
399 	gtk_widget_show(image1);
400 	gtk_container_add(GTK_CONTAINER(navbar_book.button_up), image1);
401 
402 	navbar_book.button_down = gtk_button_new();
403 	gtk_widget_show(navbar_book.button_down);
404 	gtk_box_pack_start(GTK_BOX(hbox1), navbar_book.button_down, FALSE,
405 			   FALSE, 0);
406 	gtk_widget_set_tooltip_text(navbar_book.button_down,
407 				    _("Go to next item"));
408 	gtk_button_set_relief(GTK_BUTTON(navbar_book.button_down),
409 			      GTK_RELIEF_NONE);
410 #if GTK_CHECK_VERSION(3, 20, 0)
411 	gtk_widget_set_focus_on_click(GTK_WIDGET(navbar_book.button_down), FALSE);
412 #else
413 	gtk_button_set_focus_on_click(GTK_BUTTON(navbar_book.button_down), FALSE);
414 #endif
415 
416 	image2 =
417 #if GTK_CHECK_VERSION(3, 10, 0)
418 	    gtk_image_new_from_icon_name("go-down-symbolic", GTK_ICON_SIZE_BUTTON);
419 #else
420 	    gtk_image_new_from_stock(GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_BUTTON);
421 #endif
422 
423 	gtk_widget_show(image2);
424 	gtk_container_add(GTK_CONTAINER(navbar_book.button_down), image2);
425 
426 	navbar_book.button_right = gtk_button_new();
427 	gtk_widget_show(navbar_book.button_right);
428 	gtk_box_pack_start(GTK_BOX(hbox1), navbar_book.button_right, FALSE,
429 			   FALSE, 0);
430 	gtk_widget_set_tooltip_text(navbar_book.button_right,
431 				    _("Go inward, to the first subsection"));
432 
433 	gtk_button_set_relief(GTK_BUTTON(navbar_book.button_right),
434 			      GTK_RELIEF_NONE);
435 #if GTK_CHECK_VERSION(3, 20, 0)
436 	gtk_widget_set_focus_on_click(GTK_WIDGET(navbar_book.button_right), FALSE);
437 #else
438 	gtk_button_set_focus_on_click(GTK_BUTTON(navbar_book.button_right), FALSE);
439 #endif
440 
441 	image1 =
442 #if GTK_CHECK_VERSION(3, 10, 0)
443 	    gtk_image_new_from_icon_name("go-next-symbolic", GTK_ICON_SIZE_BUTTON);
444 #else
445 	    gtk_image_new_from_stock(GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON);
446 #endif
447 	gtk_widget_show(image1);
448 	gtk_container_add(GTK_CONTAINER(navbar_book.button_right), image1);
449 
450 	g_signal_connect((gpointer)navbar_book.lookup_entry,
451 			 "activate", G_CALLBACK(on_entry_activate), NULL);
452 	g_signal_connect((gpointer)navbar_book.button_up, "clicked",
453 			 G_CALLBACK(on_button_prev_clicked), NULL);
454 	g_signal_connect((gpointer)navbar_book.button_down, "clicked",
455 			 G_CALLBACK(on_button_next_clicked), NULL);
456 	g_signal_connect((gpointer)navbar_book.button_left, "clicked",
457 			 G_CALLBACK(on_button_parent_clicked), NULL);
458 	g_signal_connect((gpointer)navbar_book.button_right, "clicked",
459 			 G_CALLBACK(on_button_child_clicked), NULL);
460 	g_signal_connect((gpointer)navbar_book.button_list,
461 			 "button_press_event",
462 			 G_CALLBACK(select_button_press_callback), NULL);
463 	g_signal_connect((gpointer)navbar_book.lookup_entry,
464 			 "key_press_event",
465 			 G_CALLBACK(lookup_entry_press_callback), NULL);
466 	return vbox1;
467 }
468