]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/minifram.cpp
Minimum is now GTK+ 2.4
[wxWidgets.git] / src / gtk / minifram.cpp
CommitLineData
b2b3ccc5 1/////////////////////////////////////////////////////////////////////////////
340bfb43 2// Name: src/gtk/minifram.cpp
b2b3ccc5
RR
3// Purpose:
4// Author: Robert Roebling
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling
65571936 7// Licence: wxWindows licence
b2b3ccc5
RR
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
dcf924a3
RR
13#if wxUSE_MINIFRAME
14
11dbb4bf
WS
15#include "wx/minifram.h"
16
17#ifndef WX_PRECOMP
b41b2a05 18 #include "wx/settings.h"
0416c418
PC
19 #include "wx/dcclient.h"
20 #include "wx/image.h"
11dbb4bf 21#endif
b2b3ccc5 22
cca410b3 23#include <gtk/gtk.h>
83624f79 24
32a95f9f
RR
25//-----------------------------------------------------------------------------
26// data
27//-----------------------------------------------------------------------------
28
8480b297
RR
29extern bool g_blockEventsOnDrag;
30extern bool g_blockEventsOnScroll;
32a95f9f 31
32a95f9f
RR
32//-----------------------------------------------------------------------------
33// "expose_event" of m_mainWidget
34//-----------------------------------------------------------------------------
35
6d976005
RR
36// StepColour() it a utility function that simply darkens
37// or lightens a color, based on the specified percentage
38static wxColor StepColour(const wxColor& c, int percent)
39{
40 int r = c.Red(), g = c.Green(), b = c.Blue();
41 return wxColour((unsigned char)wxMin((r*percent)/100,255),
42 (unsigned char)wxMin((g*percent)/100,255),
43 (unsigned char)wxMin((b*percent)/100,255));
44}
45
46static wxColor LightContrastColour(const wxColour& c)
47{
48 int amount = 120;
49
50 // if the color is especially dark, then
51 // make the contrast even lighter
52 if (c.Red() < 128 && c.Green() < 128 && c.Blue() < 128)
53 amount = 160;
54
55 return StepColour(c, amount);
56}
57
865bb325 58extern "C" {
6d727f6c 59static gboolean gtk_window_own_expose_callback(GtkWidget* widget, GdkEventExpose* gdk_event, wxMiniFrame* win)
32a95f9f 60{
6d727f6c
PC
61 if (!win->m_hasVMT || gdk_event->count > 0)
62 return false;
c2fa61e8 63
67b73b9a 64 gtk_paint_shadow (widget->style,
cca410b3 65 widget->window,
67b73b9a
MR
66 GTK_STATE_NORMAL,
67 GTK_SHADOW_OUT,
68 NULL, NULL, NULL, // FIXME: No clipping?
69 0, 0,
70 win->m_width, win->m_height);
b9a535f5 71
00e4ffbc 72 int style = win->GetWindowStyle();
b41b2a05 73
85a0a12a 74 wxClientDC dc(win);
cca410b3 75
ab171e95
RR
76#if wxUSE_NEW_DC
77 wxImplDC *impl = dc.GetImpl();
78 wxGTKClientImplDC *client_impl = wxDynamicCast( impl, wxGTKClientImplDC );
79 // Hack alert
cca410b3 80 client_impl->m_window = widget->window;
ab171e95 81#else
85a0a12a 82 // Hack alert
cca410b3 83 dc.m_window = widget->window;
ab171e95 84#endif
b41b2a05 85
85a0a12a
RR
86 if (style & wxRESIZE_BORDER)
87 {
88 dc.SetBrush( *wxGREY_BRUSH );
89 dc.SetPen( *wxTRANSPARENT_PEN );
90 dc.DrawRectangle( win->m_width - 14, win->m_height-14, 14, 14 );
91 }
92
340bfb43 93 if (!win->GetTitle().empty() &&
00e4ffbc
RR
94 ((style & wxCAPTION) ||
95 (style & wxTINY_CAPTION_HORIZ) ||
96 (style & wxTINY_CAPTION_VERT)))
b9a535f5 97 {
ba718523
RR
98 dc.SetFont( *wxSMALL_FONT );
99 int height = dc.GetCharHeight();
340bfb43 100
6d976005
RR
101 wxBrush brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT) ) );
102 dc.SetBrush( brush );
103 dc.SetPen( *wxTRANSPARENT_PEN );
1ed6bbc2 104 dc.DrawRectangle( 3, 3, win->m_width - 7, height );
ba718523 105
ba718523
RR
106 dc.SetTextForeground( *wxWHITE );
107 dc.DrawText( win->GetTitle(), 6, 3 );
00e4ffbc
RR
108
109 if (style & wxCLOSE_BOX)
ba6ce5fb 110 dc.DrawBitmap( win->m_closeButton, win->m_width-19, 2, true );
b9a535f5 111 }
6d727f6c 112 return false;
32a95f9f 113}
865bb325 114}
32a95f9f 115
32a95f9f
RR
116//-----------------------------------------------------------------------------
117// "button_press_event" of m_mainWidget
118//-----------------------------------------------------------------------------
119
865bb325 120extern "C" {
32a95f9f
RR
121static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
122{
a2053b27 123 if (!win->m_hasVMT) return FALSE;
32a95f9f
RR
124 if (g_blockEventsOnDrag) return TRUE;
125 if (g_blockEventsOnScroll) return TRUE;
126
127 if (win->m_isDragging) return TRUE;
128
85a0a12a
RR
129 int style = win->GetWindowStyle();
130
00e4ffbc
RR
131 int y = (int)gdk_event->y;
132 int x = (int)gdk_event->x;
b41b2a05 133
85a0a12a
RR
134 if ((style & wxRESIZE_BORDER) &&
135 (x > win->m_width-14) && (y > win->m_height-14))
136 {
137 GtkWidget *ancestor = gtk_widget_get_toplevel( widget );
138
cca410b3 139 GdkWindow *source = widget->window;
85a0a12a
RR
140
141 int org_x = 0;
142 int org_y = 0;
143 gdk_window_get_origin( source, &org_x, &org_y );
144
145 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
146 GDK_WINDOW_EDGE_SOUTH_EAST,
147 1,
148 org_x + x,
149 org_y + y,
150 0);
b41b2a05 151
85a0a12a
RR
152 return TRUE;
153 }
00e4ffbc 154
00e4ffbc
RR
155 if ((style & wxCLOSE_BOX) &&
156 ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT)))
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 }
b41b2a05 164
ba718523
RR
165 wxClientDC dc(win);
166 dc.SetFont( *wxSMALL_FONT );
167 int height = dc.GetCharHeight() + 1;
340bfb43 168
00e4ffbc
RR
169
170 if (y > height) return TRUE;
340bfb43 171
4dcaf11a 172 gdk_window_raise( win->m_widget->window );
c2fa61e8 173
32a95f9f
RR
174 gdk_pointer_grab( widget->window, FALSE,
175 (GdkEventMask)
176 (GDK_BUTTON_PRESS_MASK |
177 GDK_BUTTON_RELEASE_MASK |
f03fc89f 178 GDK_POINTER_MOTION_MASK |
32a95f9f 179 GDK_POINTER_MOTION_HINT_MASK |
f03fc89f 180 GDK_BUTTON_MOTION_MASK |
32a95f9f
RR
181 GDK_BUTTON1_MOTION_MASK),
182 (GdkWindow *) NULL,
183 (GdkCursor *) NULL,
7941ba11 184 (unsigned int) GDK_CURRENT_TIME );
c2fa61e8 185
00e4ffbc
RR
186 win->m_diffX = x;
187 win->m_diffY = y;
32a95f9f
RR
188 win->m_oldX = 0;
189 win->m_oldY = 0;
c2fa61e8 190
340bfb43 191 win->m_isDragging = true;
32a95f9f
RR
192
193 return TRUE;
194}
865bb325 195}
32a95f9f
RR
196
197//-----------------------------------------------------------------------------
198// "button_release_event" of m_mainWidget
199//-----------------------------------------------------------------------------
200
865bb325 201extern "C" {
32a95f9f
RR
202static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
203{
a2053b27 204 if (!win->m_hasVMT) return FALSE;
32a95f9f
RR
205 if (g_blockEventsOnDrag) return TRUE;
206 if (g_blockEventsOnScroll) return TRUE;
207
208 if (!win->m_isDragging) return TRUE;
c2fa61e8 209
11dbb4bf 210 win->m_isDragging = false;
c2fa61e8 211
32a95f9f
RR
212 int x = (int)gdk_event->x;
213 int y = (int)gdk_event->y;
c2fa61e8 214
13111b2a 215 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
c2fa61e8 216 int org_x = 0;
32a95f9f
RR
217 int org_y = 0;
218 gdk_window_get_origin( widget->window, &org_x, &org_y );
219 x += org_x - win->m_diffX;
220 y += org_y - win->m_diffY;
121a3581
RR
221 win->m_x = x;
222 win->m_y = y;
9adb9063 223 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
32a95f9f
RR
224
225 return TRUE;
226}
865bb325 227}
32a95f9f 228
85a0a12a
RR
229//-----------------------------------------------------------------------------
230// "leave_notify_event" of m_mainWidget
231//-----------------------------------------------------------------------------
232
233extern "C" {
234static gboolean
e4161a2a
VZ
235gtk_window_leave_callback(GtkWidget *widget,
236 GdkEventCrossing * WXUNUSED(gdk_event),
237 wxMiniFrame *win)
85a0a12a 238{
85a0a12a
RR
239 if (!win->m_hasVMT) return FALSE;
240 if (g_blockEventsOnDrag) return FALSE;
241
242 gdk_window_set_cursor( widget->window, NULL );
b41b2a05 243
85a0a12a
RR
244 return FALSE;
245}
246}
247
32a95f9f
RR
248//-----------------------------------------------------------------------------
249// "motion_notify_event" of m_mainWidget
250//-----------------------------------------------------------------------------
251
865bb325 252extern "C" {
b41b2a05 253static gint
85a0a12a 254gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxMiniFrame *win )
32a95f9f 255{
a2053b27 256 if (!win->m_hasVMT) return FALSE;
32a95f9f
RR
257 if (g_blockEventsOnDrag) return TRUE;
258 if (g_blockEventsOnScroll) return TRUE;
259
32a95f9f
RR
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
85a0a12a 271 int style = win->GetWindowStyle();
b41b2a05 272
d02d8b4c
RR
273 int x = (int)gdk_event->x;
274 int y = (int)gdk_event->y;
b41b2a05 275
85a0a12a
RR
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 }
b41b2a05 287
85a0a12a
RR
288 win->m_oldX = x - win->m_diffX;
289 win->m_oldY = y - win->m_diffY;
290
d02d8b4c
RR
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
32a95f9f
RR
300 return TRUE;
301}
865bb325 302}
32a95f9f 303
cca410b3
PC
304//-----------------------------------------------------------------------------
305// "size_allocate" from GtkFixed, parent of m_mainWidget
306//-----------------------------------------------------------------------------
307
308extern "C" {
309static void size_allocate(GtkWidget*, GtkAllocation* alloc, wxMiniFrame* win)
310{
311 // place m_mainWidget inside of decorations drawn on the GtkFixed
312 GtkAllocation alloc2 = win->m_mainWidget->allocation;
313 alloc2.width = alloc->width - 2 * win->m_miniEdge;
314 alloc2.height = alloc->height - win->m_miniTitle - 2 * win->m_miniEdge;
315 gtk_widget_size_allocate(win->m_mainWidget, &alloc2);
316}
317}
318
b2b3ccc5
RR
319//-----------------------------------------------------------------------------
320// wxMiniFrame
321//-----------------------------------------------------------------------------
322
00e4ffbc
RR
323static unsigned char close_bits[]={
324 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
325 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
326 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
327
5d5b3a40 328
b2b3ccc5
RR
329IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame,wxFrame)
330
331bool wxMiniFrame::Create( wxWindow *parent, wxWindowID id, const wxString &title,
332 const wxPoint &pos, const wxSize &size,
333 long style, const wxString &name )
334{
b9a535f5 335 if ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT))
00e4ffbc 336 m_miniTitle = 16;
c2fa61e8 337
6d976005 338 if (style & wxRESIZE_BORDER)
85a0a12a 339 m_miniEdge = 4;
6d976005
RR
340 else
341 m_miniEdge = 3;
340bfb43 342 m_isDragging = false;
b2b3ccc5
RR
343 m_oldX = -1;
344 m_oldY = -1;
345 m_diffX = 0;
346 m_diffY = 0;
c2fa61e8 347
b2b3ccc5
RR
348 wxFrame::Create( parent, id, title, pos, size, style, name );
349
cca410b3
PC
350 // borders and title are on a GtkFixed between m_widget and m_mainWidget
351 GtkWidget* fixed = gtk_fixed_new();
352 gtk_fixed_set_has_window((GtkFixed*)fixed, true);
353 gtk_widget_add_events(fixed,
354 GDK_POINTER_MOTION_MASK |
355 GDK_POINTER_MOTION_HINT_MASK |
356 GDK_BUTTON_MOTION_MASK |
357 GDK_BUTTON_PRESS_MASK |
358 GDK_BUTTON_RELEASE_MASK |
359 GDK_LEAVE_NOTIFY_MASK);
360 gtk_widget_show(fixed);
361 gtk_widget_reparent(m_mainWidget, fixed);
362 gtk_container_add((GtkContainer*)m_widget, fixed);
363 gtk_fixed_move((GtkFixed*)fixed, m_mainWidget, m_miniEdge, m_miniTitle + m_miniEdge);
364 g_signal_connect(fixed, "size_allocate", G_CALLBACK(size_allocate), this);
365
366 m_gdkDecor = 0;
367 m_gdkFunc = 0;
368 if (style & wxRESIZE_BORDER)
369 m_gdkFunc = GDK_FUNC_RESIZE;
370
2c990ec0
RR
371 if (m_parent && (GTK_IS_WINDOW(m_parent->m_widget)))
372 {
373 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
374 }
340bfb43 375
00e4ffbc 376 if ((style & wxCLOSE_BOX) &&
b9a535f5
RR
377 ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT)))
378 {
00e4ffbc 379 wxImage img = wxBitmap((const char*)close_bits, 16, 16).ConvertToImage();
c4d39711 380 img.Replace(0,0,0,123,123,123);
00e4ffbc
RR
381 img.SetMaskColour(123,123,123);
382 m_closeButton = wxBitmap( img );
b9a535f5 383 }
c2fa61e8 384
32a95f9f 385 /* these are called when the borders are drawn */
cca410b3 386 g_signal_connect_after(fixed, "expose_event",
9fa72bd2 387 G_CALLBACK (gtk_window_own_expose_callback), this );
b2b3ccc5 388
32a95f9f 389 /* these are required for dragging the mini frame around */
cca410b3 390 g_signal_connect (fixed, "button_press_event",
9fa72bd2 391 G_CALLBACK (gtk_window_button_press_callback), this);
cca410b3 392 g_signal_connect (fixed, "button_release_event",
9fa72bd2 393 G_CALLBACK (gtk_window_button_release_callback), this);
cca410b3 394 g_signal_connect (fixed, "motion_notify_event",
9fa72bd2 395 G_CALLBACK (gtk_window_motion_notify_callback), this);
cca410b3 396 g_signal_connect (fixed, "leave_notify_event",
85a0a12a 397 G_CALLBACK (gtk_window_leave_callback), this);
340bfb43 398 return true;
b2b3ccc5 399}
dcf924a3 400
cca410b3
PC
401void wxMiniFrame::DoGetClientSize(int* width, int* height) const
402{
403 wxFrame::DoGetClientSize(width, height);
404 if (width)
405 {
406 *width -= 2 * m_miniEdge;
407 if (*width < 0) *width = 0;
408 }
409 if (height)
410 {
411 *height -= m_miniTitle + 2 * m_miniEdge;
412 if (*height < 0) *height = 0;
413 }
414}
415
400be137
RR
416void wxMiniFrame::SetTitle( const wxString &title )
417{
418 wxFrame::SetTitle( title );
340bfb43 419
cca410b3
PC
420 GtkWidget* fixed = GTK_BIN(m_widget)->child;
421 if (fixed->window)
422 gdk_window_invalidate_rect(fixed->window, NULL, false);
400be137
RR
423}
424
11dbb4bf 425#endif // wxUSE_MINIFRAME