Reorganize idle system code.
[wxWidgets.git] / src / gtk / minifram.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/minifram.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #if wxUSE_MINIFRAME
14
15 #include "wx/minifram.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/settings.h"
19 #include "wx/dcclient.h"
20 #include "wx/image.h"
21 #endif
22
23 #include "wx/gtk/win_gtk.h"
24 #include "wx/gtk/private.h"
25
26 //-----------------------------------------------------------------------------
27 // data
28 //-----------------------------------------------------------------------------
29
30 extern bool g_blockEventsOnDrag;
31 extern bool g_blockEventsOnScroll;
32 extern GtkWidget *wxGetRootWindow();
33
34 //-----------------------------------------------------------------------------
35 // "expose_event" of m_mainWidget
36 //-----------------------------------------------------------------------------
37
38 // StepColour() it a utility function that simply darkens
39 // or lightens a color, based on the specified percentage
40 static wxColor StepColour(const wxColor& c, int percent)
41 {
42 int r = c.Red(), g = c.Green(), b = c.Blue();
43 return wxColour((unsigned char)wxMin((r*percent)/100,255),
44 (unsigned char)wxMin((g*percent)/100,255),
45 (unsigned char)wxMin((b*percent)/100,255));
46 }
47
48 static wxColor LightContrastColour(const wxColour& c)
49 {
50 int amount = 120;
51
52 // if the color is especially dark, then
53 // make the contrast even lighter
54 if (c.Red() < 128 && c.Green() < 128 && c.Blue() < 128)
55 amount = 160;
56
57 return StepColour(c, amount);
58 }
59
60 extern "C" {
61 static gboolean gtk_window_own_expose_callback(GtkWidget* widget, GdkEventExpose* gdk_event, wxMiniFrame* win)
62 {
63 if (!win->m_hasVMT || gdk_event->count > 0)
64 return false;
65
66 GtkPizza *pizza = GTK_PIZZA(widget);
67
68 gtk_paint_shadow (widget->style,
69 pizza->bin_window,
70 GTK_STATE_NORMAL,
71 GTK_SHADOW_OUT,
72 NULL, NULL, NULL, // FIXME: No clipping?
73 0, 0,
74 win->m_width, win->m_height);
75
76 int style = win->GetWindowStyle();
77
78 wxClientDC dc(win);
79 // Hack alert
80 dc.m_window = pizza->bin_window;
81
82 if (style & wxRESIZE_BORDER)
83 {
84 dc.SetBrush( *wxGREY_BRUSH );
85 dc.SetPen( *wxTRANSPARENT_PEN );
86 dc.DrawRectangle( win->m_width - 14, win->m_height-14, 14, 14 );
87 }
88
89 if (!win->GetTitle().empty() &&
90 ((style & wxCAPTION) ||
91 (style & wxTINY_CAPTION_HORIZ) ||
92 (style & wxTINY_CAPTION_VERT)))
93 {
94 dc.SetFont( *wxSMALL_FONT );
95 int height = dc.GetCharHeight();
96
97 wxBrush brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT) ) );
98 dc.SetBrush( brush );
99 dc.SetPen( *wxTRANSPARENT_PEN );
100 dc.DrawRectangle( 3, 3, win->m_width - 7, height );
101
102 dc.SetTextForeground( *wxWHITE );
103 dc.DrawText( win->GetTitle(), 6, 3 );
104
105 if (style & wxCLOSE_BOX)
106 dc.DrawBitmap( win->m_closeButton, win->m_width-19, 2, true );
107 }
108 return false;
109 }
110 }
111
112 //-----------------------------------------------------------------------------
113 // "button_press_event" of m_mainWidget
114 //-----------------------------------------------------------------------------
115
116 extern "C" {
117 static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
118 {
119 if (!win->m_hasVMT) return FALSE;
120 if (g_blockEventsOnDrag) return TRUE;
121 if (g_blockEventsOnScroll) return TRUE;
122
123 if (win->m_isDragging) return TRUE;
124
125 GtkPizza *pizza = GTK_PIZZA(widget);
126 if (gdk_event->window != pizza->bin_window) return TRUE;
127
128 int style = win->GetWindowStyle();
129
130 int y = (int)gdk_event->y;
131 int x = (int)gdk_event->x;
132
133 if ((style & wxRESIZE_BORDER) &&
134 (x > win->m_width-14) && (y > win->m_height-14))
135 {
136 GtkWidget *ancestor = gtk_widget_get_toplevel( widget );
137
138 GdkWindow *source = GTK_PIZZA(widget)->bin_window;
139
140 int org_x = 0;
141 int org_y = 0;
142 gdk_window_get_origin( source, &org_x, &org_y );
143
144 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
145 GDK_WINDOW_EDGE_SOUTH_EAST,
146 1,
147 org_x + x,
148 org_y + y,
149 0);
150
151 return TRUE;
152 }
153
154 if ((style & wxCLOSE_BOX) &&
155 ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT)))
156 {
157 if ((y > 3) && (y < 19) && (x > win->m_width-19) && (x < win->m_width-3))
158 {
159 win->Close();
160 return TRUE;
161 }
162 }
163
164 wxClientDC dc(win);
165 dc.SetFont( *wxSMALL_FONT );
166 int height = dc.GetCharHeight() + 1;
167
168
169 if (y > height) return TRUE;
170
171 gdk_window_raise( win->m_widget->window );
172
173 gdk_pointer_grab( widget->window, FALSE,
174 (GdkEventMask)
175 (GDK_BUTTON_PRESS_MASK |
176 GDK_BUTTON_RELEASE_MASK |
177 GDK_POINTER_MOTION_MASK |
178 GDK_POINTER_MOTION_HINT_MASK |
179 GDK_BUTTON_MOTION_MASK |
180 GDK_BUTTON1_MOTION_MASK),
181 (GdkWindow *) NULL,
182 (GdkCursor *) NULL,
183 (unsigned int) GDK_CURRENT_TIME );
184
185 win->m_diffX = x;
186 win->m_diffY = y;
187 win->m_oldX = 0;
188 win->m_oldY = 0;
189
190 win->m_isDragging = true;
191
192 return TRUE;
193 }
194 }
195
196 //-----------------------------------------------------------------------------
197 // "button_release_event" of m_mainWidget
198 //-----------------------------------------------------------------------------
199
200 extern "C" {
201 static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
202 {
203 if (!win->m_hasVMT) return FALSE;
204 if (g_blockEventsOnDrag) return TRUE;
205 if (g_blockEventsOnScroll) return TRUE;
206
207 if (!win->m_isDragging) return TRUE;
208
209 win->m_isDragging = false;
210
211 int x = (int)gdk_event->x;
212 int y = (int)gdk_event->y;
213
214 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
215 int org_x = 0;
216 int org_y = 0;
217 gdk_window_get_origin( widget->window, &org_x, &org_y );
218 x += org_x - win->m_diffX;
219 y += org_y - win->m_diffY;
220 win->m_x = x;
221 win->m_y = y;
222 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
223
224 return TRUE;
225 }
226 }
227
228 //-----------------------------------------------------------------------------
229 // "leave_notify_event" of m_mainWidget
230 //-----------------------------------------------------------------------------
231
232 extern "C" {
233 static gboolean
234 gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxMiniFrame *win )
235 {
236 if (!win->m_hasVMT) return FALSE;
237 if (g_blockEventsOnDrag) return FALSE;
238
239 gdk_window_set_cursor( widget->window, NULL );
240
241 return FALSE;
242 }
243 }
244
245 //-----------------------------------------------------------------------------
246 // "motion_notify_event" of m_mainWidget
247 //-----------------------------------------------------------------------------
248
249 extern "C" {
250 static gint
251 gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxMiniFrame *win )
252 {
253 if (!win->m_hasVMT) return FALSE;
254 if (g_blockEventsOnDrag) return TRUE;
255 if (g_blockEventsOnScroll) return TRUE;
256
257 if (gdk_event->is_hint)
258 {
259 int x = 0;
260 int y = 0;
261 GdkModifierType state;
262 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
263 gdk_event->x = x;
264 gdk_event->y = y;
265 gdk_event->state = state;
266 }
267
268 int style = win->GetWindowStyle();
269
270 int x = (int)gdk_event->x;
271 int y = (int)gdk_event->y;
272
273 if (!win->m_isDragging)
274 {
275 if (style & wxRESIZE_BORDER)
276 {
277 if ((x > win->m_width-14) && (y > win->m_height-14))
278 gdk_window_set_cursor( widget->window, gdk_cursor_new( GDK_BOTTOM_RIGHT_CORNER ) );
279 else
280 gdk_window_set_cursor( widget->window, NULL );
281 }
282 return TRUE;
283 }
284
285 win->m_oldX = x - win->m_diffX;
286 win->m_oldY = y - win->m_diffY;
287
288 int org_x = 0;
289 int org_y = 0;
290 gdk_window_get_origin( widget->window, &org_x, &org_y );
291 x += org_x - win->m_diffX;
292 y += org_y - win->m_diffY;
293 win->m_x = x;
294 win->m_y = y;
295 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
296
297
298 return TRUE;
299 }
300 }
301
302 //-----------------------------------------------------------------------------
303 // wxMiniFrame
304 //-----------------------------------------------------------------------------
305
306 static unsigned char close_bits[]={
307 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
308 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
309 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
310
311
312 IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame,wxFrame)
313
314 bool wxMiniFrame::Create( wxWindow *parent, wxWindowID id, const wxString &title,
315 const wxPoint &pos, const wxSize &size,
316 long style, const wxString &name )
317 {
318 style = style | wxCAPTION;
319
320 if ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT))
321 m_miniTitle = 16;
322
323 if (style & wxRESIZE_BORDER)
324 m_miniEdge = 4;
325 else
326 m_miniEdge = 3;
327 m_isDragging = false;
328 m_oldX = -1;
329 m_oldY = -1;
330 m_diffX = 0;
331 m_diffY = 0;
332
333 wxFrame::Create( parent, id, title, pos, size, style, name );
334
335 if (m_parent && (GTK_IS_WINDOW(m_parent->m_widget)))
336 {
337 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
338 }
339
340 if ((style & wxCLOSE_BOX) &&
341 ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT)))
342 {
343 wxImage img = wxBitmap((const char*)close_bits, 16, 16).ConvertToImage();
344 img.Replace(0,0,0,123,123,123);
345 img.SetMaskColour(123,123,123);
346 m_closeButton = wxBitmap( img );
347 }
348
349 /* these are called when the borders are drawn */
350 g_signal_connect (m_mainWidget, "expose_event",
351 G_CALLBACK (gtk_window_own_expose_callback), this );
352
353 /* these are required for dragging the mini frame around */
354 g_signal_connect (m_mainWidget, "button_press_event",
355 G_CALLBACK (gtk_window_button_press_callback), this);
356 g_signal_connect (m_mainWidget, "button_release_event",
357 G_CALLBACK (gtk_window_button_release_callback), this);
358 g_signal_connect (m_mainWidget, "motion_notify_event",
359 G_CALLBACK (gtk_window_motion_notify_callback), this);
360 g_signal_connect (m_mainWidget, "leave_notify_event",
361 G_CALLBACK (gtk_window_leave_callback), this);
362 return true;
363 }
364
365 void wxMiniFrame::SetTitle( const wxString &title )
366 {
367 wxFrame::SetTitle( title );
368
369 if (GTK_PIZZA(m_mainWidget)->bin_window)
370 gdk_window_invalidate_rect( GTK_PIZZA(m_mainWidget)->bin_window, NULL, true );
371 }
372
373 #endif // wxUSE_MINIFRAME