]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/minifram.cpp
reorganized wxBitmap/wxBitmapHandler classes to use wxBitmapType instead of "long...
[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/dcclient.h"
24
25 #include <gtk/gtk.h>
26
27 //-----------------------------------------------------------------------------
28 // data
29 //-----------------------------------------------------------------------------
30
31 extern bool g_blockEventsOnDrag;
32 extern bool g_blockEventsOnScroll;
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 gdk_event->window != widget->window)
65 {
66 return false;
67 }
68
69 gtk_paint_shadow (widget->style,
70 widget->window,
71 GTK_STATE_NORMAL,
72 GTK_SHADOW_OUT,
73 NULL, NULL, NULL, // FIXME: No clipping?
74 0, 0,
75 win->m_width, win->m_height);
76
77 int style = win->GetWindowStyle();
78
79 wxClientDC dc(win);
80
81 wxDCImpl *impl = dc.GetImpl();
82 wxClientDCImpl *gtk_impl = wxDynamicCast( impl, wxClientDCImpl );
83 gtk_impl->m_gdkwindow = widget->window; // Hack alert
84
85 if (style & wxRESIZE_BORDER)
86 {
87 dc.SetBrush( *wxGREY_BRUSH );
88 dc.SetPen( *wxTRANSPARENT_PEN );
89 dc.DrawRectangle( win->m_width - 14, win->m_height-14, 14, 14 );
90 }
91
92 if (win->m_miniTitle && !win->GetTitle().empty())
93 {
94 dc.SetFont( *wxSMALL_FONT );
95
96 wxBrush brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT) ) );
97 dc.SetBrush( brush );
98 dc.SetPen( *wxTRANSPARENT_PEN );
99 dc.DrawRectangle( win->m_miniEdge-1,
100 win->m_miniEdge-1,
101 win->m_width - (2*(win->m_miniEdge-1)),
102 15 );
103
104 dc.SetTextForeground( *wxWHITE );
105 dc.DrawText( win->GetTitle(), 6, 4 );
106
107 if (style & wxCLOSE_BOX)
108 dc.DrawBitmap( win->m_closeButton, win->m_width-18, 3, true );
109 }
110
111 return false;
112 }
113 }
114
115 //-----------------------------------------------------------------------------
116 // "button_press_event" of m_mainWidget
117 //-----------------------------------------------------------------------------
118
119 extern "C" {
120 static gboolean
121 gtk_window_button_press_callback(GtkWidget* widget, GdkEventButton* gdk_event, wxMiniFrame* win)
122 {
123 if (!win->m_hasVMT || gdk_event->window != widget->window)
124 return false;
125 if (g_blockEventsOnDrag) return TRUE;
126 if (g_blockEventsOnScroll) return TRUE;
127
128 if (win->m_isDragging) return TRUE;
129
130 int style = win->GetWindowStyle();
131
132 int y = (int)gdk_event->y;
133 int x = (int)gdk_event->x;
134
135 if ((style & wxRESIZE_BORDER) &&
136 (x > win->m_width-14) && (y > win->m_height-14))
137 {
138 GtkWidget *ancestor = gtk_widget_get_toplevel( widget );
139
140 GdkWindow *source = widget->window;
141
142 int org_x = 0;
143 int org_y = 0;
144 gdk_window_get_origin( source, &org_x, &org_y );
145
146 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
147 GDK_WINDOW_EDGE_SOUTH_EAST,
148 1,
149 org_x + x,
150 org_y + y,
151 0);
152
153 return TRUE;
154 }
155
156 if (win->m_miniTitle && (style & wxCLOSE_BOX))
157 {
158 if ((y > 3) && (y < 19) && (x > win->m_width-19) && (x < win->m_width-3))
159 {
160 win->Close();
161 return TRUE;
162 }
163 }
164
165 if (y >= win->m_miniEdge + win->m_miniTitle)
166 return true;
167
168 gdk_window_raise( win->m_widget->window );
169
170 gdk_pointer_grab( widget->window, FALSE,
171 (GdkEventMask)
172 (GDK_BUTTON_PRESS_MASK |
173 GDK_BUTTON_RELEASE_MASK |
174 GDK_POINTER_MOTION_MASK |
175 GDK_POINTER_MOTION_HINT_MASK |
176 GDK_BUTTON_MOTION_MASK |
177 GDK_BUTTON1_MOTION_MASK),
178 (GdkWindow *) NULL,
179 (GdkCursor *) NULL,
180 (unsigned int) GDK_CURRENT_TIME );
181
182 win->m_diffX = x;
183 win->m_diffY = y;
184 win->m_oldX = 0;
185 win->m_oldY = 0;
186
187 win->m_isDragging = true;
188
189 return TRUE;
190 }
191 }
192
193 //-----------------------------------------------------------------------------
194 // "button_release_event" of m_mainWidget
195 //-----------------------------------------------------------------------------
196
197 extern "C" {
198 static gboolean
199 gtk_window_button_release_callback(GtkWidget* widget, GdkEventButton* gdk_event, wxMiniFrame* win)
200 {
201 if (!win->m_hasVMT || gdk_event->window != widget->window)
202 return false;
203 if (g_blockEventsOnDrag) return TRUE;
204 if (g_blockEventsOnScroll) return TRUE;
205 if (!win->m_isDragging) return TRUE;
206
207 win->m_isDragging = false;
208
209 int x = (int)gdk_event->x;
210 int y = (int)gdk_event->y;
211
212 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
213 int org_x = 0;
214 int org_y = 0;
215 gdk_window_get_origin( widget->window, &org_x, &org_y );
216 x += org_x - win->m_diffX;
217 y += org_y - win->m_diffY;
218 win->m_x = x;
219 win->m_y = y;
220 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
221
222 return TRUE;
223 }
224 }
225
226 //-----------------------------------------------------------------------------
227 // "leave_notify_event" of m_mainWidget
228 //-----------------------------------------------------------------------------
229
230 extern "C" {
231 static gboolean
232 gtk_window_leave_callback(GtkWidget *widget,
233 GdkEventCrossing* gdk_event,
234 wxMiniFrame *win)
235 {
236 if (!win->m_hasVMT) return FALSE;
237 if (g_blockEventsOnDrag) return FALSE;
238 if (gdk_event->window != widget->window)
239 return false;
240
241 gdk_window_set_cursor( widget->window, NULL );
242
243 return FALSE;
244 }
245 }
246
247 //-----------------------------------------------------------------------------
248 // "motion_notify_event" of m_mainWidget
249 //-----------------------------------------------------------------------------
250
251 extern "C" {
252 static gboolean
253 gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxMiniFrame *win )
254 {
255 if (!win->m_hasVMT || gdk_event->window != widget->window)
256 return false;
257 if (g_blockEventsOnDrag) return TRUE;
258 if (g_blockEventsOnScroll) return TRUE;
259
260 if (gdk_event->is_hint)
261 {
262 int x = 0;
263 int y = 0;
264 GdkModifierType state;
265 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
266 gdk_event->x = x;
267 gdk_event->y = y;
268 gdk_event->state = state;
269 }
270
271 int style = win->GetWindowStyle();
272
273 int x = (int)gdk_event->x;
274 int y = (int)gdk_event->y;
275
276 if (!win->m_isDragging)
277 {
278 if (style & wxRESIZE_BORDER)
279 {
280 if ((x > win->m_width-14) && (y > win->m_height-14))
281 gdk_window_set_cursor( widget->window, gdk_cursor_new( GDK_BOTTOM_RIGHT_CORNER ) );
282 else
283 gdk_window_set_cursor( widget->window, NULL );
284 }
285 return TRUE;
286 }
287
288 win->m_oldX = x - win->m_diffX;
289 win->m_oldY = y - win->m_diffY;
290
291 int org_x = 0;
292 int org_y = 0;
293 gdk_window_get_origin( widget->window, &org_x, &org_y );
294 x += org_x - win->m_diffX;
295 y += org_y - win->m_diffY;
296 win->m_x = x;
297 win->m_y = y;
298 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
299
300 return TRUE;
301 }
302 }
303
304 //-----------------------------------------------------------------------------
305 // wxMiniFrame
306 //-----------------------------------------------------------------------------
307
308 static unsigned char close_bits[]={
309 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
310 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
311 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
312
313
314 IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame,wxFrame)
315
316 bool wxMiniFrame::Create( wxWindow *parent, wxWindowID id, const wxString &title,
317 const wxPoint &pos, const wxSize &size,
318 long style, const wxString &name )
319 {
320 m_miniTitle = 0;
321 if (style & wxCAPTION)
322 m_miniTitle = 16;
323
324 if (style & wxRESIZE_BORDER)
325 m_miniEdge = 4;
326 else
327 m_miniEdge = 3;
328 m_isDragging = false;
329 m_oldX = -1;
330 m_oldY = -1;
331 m_diffX = 0;
332 m_diffY = 0;
333
334 wxFrame::Create( parent, id, title, pos, size, style, name );
335
336 // Use a GtkEventBox for the title and borders. Using m_widget for this
337 // almost works, except that setting the resize cursor has no effect.
338 GtkWidget* eventbox = gtk_event_box_new();
339 gtk_widget_add_events(eventbox,
340 GDK_POINTER_MOTION_MASK |
341 GDK_POINTER_MOTION_HINT_MASK);
342 gtk_widget_show(eventbox);
343 // Use a GtkAlignment to position m_mainWidget inside the decorations
344 GtkWidget* alignment = gtk_alignment_new(0, 0, 1, 1);
345 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment),
346 m_miniTitle + m_miniEdge, m_miniEdge, m_miniEdge, m_miniEdge);
347 gtk_widget_show(alignment);
348 // The GtkEventBox and GtkAlignment go between m_widget and m_mainWidget
349 gtk_widget_reparent(m_mainWidget, alignment);
350 gtk_container_add(GTK_CONTAINER(eventbox), alignment);
351 gtk_container_add(GTK_CONTAINER(m_widget), eventbox);
352
353 m_gdkDecor = 0;
354 m_gdkFunc = 0;
355 if (style & wxRESIZE_BORDER)
356 m_gdkFunc = GDK_FUNC_RESIZE;
357
358 // don't allow sizing smaller than decorations
359 GdkGeometry geom;
360 geom.min_width = 2 * m_miniEdge;
361 geom.min_height = 2 * m_miniEdge + m_miniTitle;
362 gtk_window_set_geometry_hints(GTK_WINDOW(m_widget), NULL, &geom, GDK_HINT_MIN_SIZE);
363
364 if (m_parent && (GTK_IS_WINDOW(m_parent->m_widget)))
365 {
366 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
367 }
368
369 if (m_miniTitle && (style & wxCLOSE_BOX))
370 {
371 wxImage img = wxBitmap((const char*)close_bits, 16, 16).ConvertToImage();
372 img.Replace(0,0,0,123,123,123);
373 img.SetMaskColour(123,123,123);
374 m_closeButton = wxBitmap( img );
375 }
376
377 /* these are called when the borders are drawn */
378 g_signal_connect_after(eventbox, "expose_event",
379 G_CALLBACK (gtk_window_own_expose_callback), this );
380
381 /* these are required for dragging the mini frame around */
382 g_signal_connect (eventbox, "button_press_event",
383 G_CALLBACK (gtk_window_button_press_callback), this);
384 g_signal_connect (eventbox, "button_release_event",
385 G_CALLBACK (gtk_window_button_release_callback), this);
386 g_signal_connect (eventbox, "motion_notify_event",
387 G_CALLBACK (gtk_window_motion_notify_callback), this);
388 g_signal_connect (eventbox, "leave_notify_event",
389 G_CALLBACK (gtk_window_leave_callback), this);
390 return true;
391 }
392
393 void wxMiniFrame::DoGetClientSize(int* width, int* height) const
394 {
395 wxFrame::DoGetClientSize(width, height);
396 if (width)
397 {
398 *width -= 2 * m_miniEdge;
399 if (*width < 0) *width = 0;
400 }
401 if (height)
402 {
403 *height -= m_miniTitle + 2 * m_miniEdge;
404 if (*height < 0) *height = 0;
405 }
406 }
407
408 // Keep min size at least as large as decorations
409 void wxMiniFrame::DoSetSizeHints(int minW, int minH, int maxW, int maxH, int incW, int incH)
410 {
411 const int w = 2 * m_miniEdge;
412 const int h = 2 * m_miniEdge + m_miniTitle;
413 if (minW < w) minW = w;
414 if (minH < h) minH = h;
415 wxFrame::DoSetSizeHints(minW, minH, maxW, maxH, incW, incH);
416 }
417
418 void wxMiniFrame::SetTitle( const wxString &title )
419 {
420 wxFrame::SetTitle( title );
421
422 GtkWidget* widget = GTK_BIN(m_widget)->child;
423 if (widget->window)
424 gdk_window_invalidate_rect(widget->window, NULL, false);
425 }
426
427 #endif // wxUSE_MINIFRAME