]> icculus.org git repositories - divverent/netradiant.git/blob - libs/gtkutil/nonmodal.h
initial
[divverent/netradiant.git] / libs / gtkutil / nonmodal.h
1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant 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 GtkRadiant 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 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 #if !defined(INCLUDED_GTKUTIL_NONMODAL_H)
23 #define INCLUDED_GTKUTIL_NONMODAL_H
24
25 #include <gtk/gtkwindow.h>
26 #include <gtk/gtkspinbutton.h>
27 #include <gtk/gtkradiobutton.h>
28 #include <gdk/gdkkeysyms.h>
29
30 #include "generic/callback.h"
31
32 #include "pointer.h"
33 #include "button.h"
34
35 typedef struct _GtkEntry GtkEntry;
36
37
38 inline gboolean escape_clear_focus_widget(GtkWidget* widget, GdkEventKey* event, gpointer data)
39 {
40   if(event->keyval == GDK_Escape)
41   {
42     gtk_window_set_focus(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(widget))), NULL);
43     return TRUE;
44   }
45   return FALSE;
46 }
47
48 inline void widget_connect_escape_clear_focus_widget(GtkWidget* widget)
49 {
50   g_signal_connect(G_OBJECT(widget), "key_press_event", G_CALLBACK(escape_clear_focus_widget), 0);
51 }
52
53
54 class NonModalEntry
55 {
56   bool m_editing;
57   Callback m_apply;
58   Callback m_cancel;
59
60   static gboolean focus_in(GtkEntry* entry, GdkEventFocus *event, NonModalEntry* self)
61   {
62     self->m_editing = false;
63     return FALSE;
64   }
65
66   static gboolean focus_out(GtkEntry* entry, GdkEventFocus *event, NonModalEntry* self)
67   {
68     if(self->m_editing && GTK_WIDGET_VISIBLE(entry))
69     {
70       self->m_apply();
71     }
72     self->m_editing = false;
73     return FALSE;
74   }
75
76   static gboolean changed(GtkEntry* entry, NonModalEntry* self)
77   {
78     self->m_editing = true;
79     return FALSE;
80   }
81
82   static gboolean enter(GtkEntry* entry, GdkEventKey* event, NonModalEntry* self)
83   {
84     if(event->keyval == GDK_Return)
85     {
86       self->m_apply();
87       self->m_editing = false;
88       gtk_window_set_focus(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(entry))), NULL);
89       return TRUE;
90     }
91     return FALSE;
92   }
93
94   static gboolean escape(GtkEntry* entry, GdkEventKey* event, NonModalEntry* self)
95   {
96     if(event->keyval == GDK_Escape)
97     {
98       self->m_cancel();
99       self->m_editing = false;
100       gtk_window_set_focus(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(entry))), NULL);
101       return TRUE;
102     }
103     return FALSE;
104   }
105
106 public:
107   NonModalEntry(const Callback& apply, const Callback& cancel) : m_editing(false), m_apply(apply), m_cancel(cancel)
108   {
109   }
110   void connect(GtkEntry* entry)
111   {
112     g_signal_connect(G_OBJECT(entry), "focus_in_event", G_CALLBACK(focus_in), this);
113     g_signal_connect(G_OBJECT(entry), "focus_out_event", G_CALLBACK(focus_out), this);
114     g_signal_connect(G_OBJECT(entry), "key_press_event", G_CALLBACK(enter), this);
115     g_signal_connect(G_OBJECT(entry), "key_press_event", G_CALLBACK(escape), this);
116     g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(changed), this);
117   }
118 };
119
120
121 class NonModalSpinner
122 {
123   Callback m_apply;
124   Callback m_cancel;
125
126   static gboolean changed(GtkSpinButton* spin, NonModalSpinner* self)
127   {
128     self->m_apply();
129     return FALSE;
130   }
131
132   static gboolean enter(GtkSpinButton* spin, GdkEventKey* event, NonModalSpinner* self)
133   {
134     if(event->keyval == GDK_Return)
135     {
136       gtk_window_set_focus(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(spin))), NULL);
137       return TRUE;
138     }
139     return FALSE;
140   }
141
142   static gboolean escape(GtkSpinButton* spin, GdkEventKey* event, NonModalSpinner* self)
143   {
144     if(event->keyval == GDK_Escape)
145     {
146       self->m_cancel();
147       gtk_window_set_focus(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(spin))), NULL);
148       return TRUE;
149     }
150     return FALSE;
151   }
152
153 public:
154   NonModalSpinner(const Callback& apply, const Callback& cancel) : m_apply(apply), m_cancel(cancel)
155   {
156   }
157   void connect(GtkSpinButton* spin)
158   {
159     guint handler = g_signal_connect(G_OBJECT(gtk_spin_button_get_adjustment(spin)), "value_changed", G_CALLBACK(changed), this);
160     g_object_set_data(G_OBJECT(spin), "handler", gint_to_pointer(handler));
161     g_signal_connect(G_OBJECT(spin), "key_press_event", G_CALLBACK(enter), this);
162     g_signal_connect(G_OBJECT(spin), "key_press_event", G_CALLBACK(escape), this);
163   }
164 };
165
166  
167 class NonModalRadio
168 {
169   Callback m_changed;
170
171 public:
172   NonModalRadio(const Callback& changed) : m_changed(changed)
173   {
174   }
175   void connect(GtkRadioButton* radio)
176   {
177     GSList* group = gtk_radio_button_group(radio);
178     for(; group != 0; group = g_slist_next(group))
179     {
180       toggle_button_connect_callback(GTK_TOGGLE_BUTTON(group->data), m_changed);
181     }
182   }
183 };
184
185
186 #endif