]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/minifram.cpp
replace usage of objective-c keyword 'id'
[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
8d788b83
PC
23#include "wx/gtk/dcclient.h"
24
cca410b3 25#include <gtk/gtk.h>
83624f79 26
32a95f9f
RR
27//-----------------------------------------------------------------------------
28// data
29//-----------------------------------------------------------------------------
30
8480b297
RR
31extern bool g_blockEventsOnDrag;
32extern bool g_blockEventsOnScroll;
32a95f9f 33
32a95f9f
RR
34//-----------------------------------------------------------------------------
35// "expose_event" of m_mainWidget
36//-----------------------------------------------------------------------------
37
6d976005
RR
38// StepColour() it a utility function that simply darkens
39// or lightens a color, based on the specified percentage
40static 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
48static 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
865bb325 60extern "C" {
6d727f6c 61static gboolean gtk_window_own_expose_callback(GtkWidget* widget, GdkEventExpose* gdk_event, wxMiniFrame* win)
32a95f9f 62{
8d788b83
PC
63 if (!win->m_hasVMT || gdk_event->count > 0 ||
64 gdk_event->window != widget->window)
65 {
6d727f6c 66 return false;
8d788b83 67 }
c2fa61e8 68
67b73b9a 69 gtk_paint_shadow (widget->style,
cca410b3 70 widget->window,
67b73b9a
MR
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);
b9a535f5 76
00e4ffbc 77 int style = win->GetWindowStyle();
b41b2a05 78
85a0a12a 79 wxClientDC dc(win);
cca410b3 80
888dde65
RR
81 wxDCImpl *impl = dc.GetImpl();
82 wxClientDCImpl *gtk_impl = wxDynamicCast( impl, wxClientDCImpl );
83 gtk_impl->m_gdkwindow = widget->window; // Hack alert
b41b2a05 84
85a0a12a
RR
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
8d788b83 92 if (win->m_miniTitle && !win->GetTitle().empty())
b9a535f5 93 {
ba718523 94 dc.SetFont( *wxSMALL_FONT );
340bfb43 95
6d976005
RR
96 wxBrush brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT) ) );
97 dc.SetBrush( brush );
98 dc.SetPen( *wxTRANSPARENT_PEN );
03647350
VZ
99 dc.DrawRectangle( win->m_miniEdge-1,
100 win->m_miniEdge-1,
39db4477
RR
101 win->m_width - (2*(win->m_miniEdge-1)),
102 15 );
ba718523 103
ba718523 104 dc.SetTextForeground( *wxWHITE );
39db4477 105 dc.DrawText( win->GetTitle(), 6, 4 );
00e4ffbc
RR
106
107 if (style & wxCLOSE_BOX)
39db4477 108 dc.DrawBitmap( win->m_closeButton, win->m_width-18, 3, true );
b9a535f5 109 }
03647350 110
6d727f6c 111 return false;
32a95f9f 112}
865bb325 113}
32a95f9f 114
32a95f9f
RR
115//-----------------------------------------------------------------------------
116// "button_press_event" of m_mainWidget
117//-----------------------------------------------------------------------------
118
865bb325 119extern "C" {
8d788b83
PC
120static gboolean
121gtk_window_button_press_callback(GtkWidget* widget, GdkEventButton* gdk_event, wxMiniFrame* win)
32a95f9f 122{
8d788b83
PC
123 if (!win->m_hasVMT || gdk_event->window != widget->window)
124 return false;
32a95f9f
RR
125 if (g_blockEventsOnDrag) return TRUE;
126 if (g_blockEventsOnScroll) return TRUE;
127
128 if (win->m_isDragging) return TRUE;
129
85a0a12a
RR
130 int style = win->GetWindowStyle();
131
00e4ffbc
RR
132 int y = (int)gdk_event->y;
133 int x = (int)gdk_event->x;
b41b2a05 134
85a0a12a
RR
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
cca410b3 140 GdkWindow *source = widget->window;
85a0a12a
RR
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);
b41b2a05 152
85a0a12a
RR
153 return TRUE;
154 }
00e4ffbc 155
8d788b83 156 if (win->m_miniTitle && (style & wxCLOSE_BOX))
00e4ffbc
RR
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
8d788b83
PC
165 if (y >= win->m_miniEdge + win->m_miniTitle)
166 return true;
340bfb43 167
4dcaf11a 168 gdk_window_raise( win->m_widget->window );
c2fa61e8 169
32a95f9f
RR
170 gdk_pointer_grab( widget->window, FALSE,
171 (GdkEventMask)
172 (GDK_BUTTON_PRESS_MASK |
173 GDK_BUTTON_RELEASE_MASK |
f03fc89f 174 GDK_POINTER_MOTION_MASK |
32a95f9f 175 GDK_POINTER_MOTION_HINT_MASK |
f03fc89f 176 GDK_BUTTON_MOTION_MASK |
32a95f9f 177 GDK_BUTTON1_MOTION_MASK),
d3b9f782
VZ
178 NULL,
179 NULL,
7941ba11 180 (unsigned int) GDK_CURRENT_TIME );
c2fa61e8 181
00e4ffbc
RR
182 win->m_diffX = x;
183 win->m_diffY = y;
32a95f9f
RR
184 win->m_oldX = 0;
185 win->m_oldY = 0;
c2fa61e8 186
340bfb43 187 win->m_isDragging = true;
32a95f9f
RR
188
189 return TRUE;
190}
865bb325 191}
32a95f9f
RR
192
193//-----------------------------------------------------------------------------
194// "button_release_event" of m_mainWidget
195//-----------------------------------------------------------------------------
196
865bb325 197extern "C" {
8d788b83
PC
198static gboolean
199gtk_window_button_release_callback(GtkWidget* widget, GdkEventButton* gdk_event, wxMiniFrame* win)
32a95f9f 200{
8d788b83
PC
201 if (!win->m_hasVMT || gdk_event->window != widget->window)
202 return false;
32a95f9f
RR
203 if (g_blockEventsOnDrag) return TRUE;
204 if (g_blockEventsOnScroll) return TRUE;
32a95f9f 205 if (!win->m_isDragging) return TRUE;
c2fa61e8 206
11dbb4bf 207 win->m_isDragging = false;
c2fa61e8 208
32a95f9f
RR
209 int x = (int)gdk_event->x;
210 int y = (int)gdk_event->y;
c2fa61e8 211
13111b2a 212 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
c2fa61e8 213 int org_x = 0;
32a95f9f
RR
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;
121a3581
RR
218 win->m_x = x;
219 win->m_y = y;
9adb9063 220 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
32a95f9f
RR
221
222 return TRUE;
223}
865bb325 224}
32a95f9f 225
85a0a12a
RR
226//-----------------------------------------------------------------------------
227// "leave_notify_event" of m_mainWidget
228//-----------------------------------------------------------------------------
229
230extern "C" {
231static gboolean
e4161a2a 232gtk_window_leave_callback(GtkWidget *widget,
8d788b83 233 GdkEventCrossing* gdk_event,
e4161a2a 234 wxMiniFrame *win)
85a0a12a 235{
85a0a12a
RR
236 if (!win->m_hasVMT) return FALSE;
237 if (g_blockEventsOnDrag) return FALSE;
8d788b83
PC
238 if (gdk_event->window != widget->window)
239 return false;
85a0a12a
RR
240
241 gdk_window_set_cursor( widget->window, NULL );
b41b2a05 242
85a0a12a
RR
243 return FALSE;
244}
245}
246
32a95f9f
RR
247//-----------------------------------------------------------------------------
248// "motion_notify_event" of m_mainWidget
249//-----------------------------------------------------------------------------
250
865bb325 251extern "C" {
8d788b83 252static gboolean
85a0a12a 253gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxMiniFrame *win )
32a95f9f 254{
8d788b83
PC
255 if (!win->m_hasVMT || gdk_event->window != widget->window)
256 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 );
c2246a38 284 win->GTKUpdateCursor(false);
85a0a12a
RR
285 }
286 return TRUE;
287 }
b41b2a05 288
85a0a12a
RR
289 win->m_oldX = x - win->m_diffX;
290 win->m_oldY = y - win->m_diffY;
291
d02d8b4c
RR
292 int org_x = 0;
293 int org_y = 0;
294 gdk_window_get_origin( widget->window, &org_x, &org_y );
295 x += org_x - win->m_diffX;
296 y += org_y - win->m_diffY;
297 win->m_x = x;
298 win->m_y = y;
299 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
300
32a95f9f
RR
301 return TRUE;
302}
865bb325 303}
32a95f9f 304
b2b3ccc5
RR
305//-----------------------------------------------------------------------------
306// wxMiniFrame
307//-----------------------------------------------------------------------------
308
00e4ffbc
RR
309static unsigned char close_bits[]={
310 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
311 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
312 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
313
5d5b3a40 314
b2b3ccc5
RR
315IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame,wxFrame)
316
317bool wxMiniFrame::Create( wxWindow *parent, wxWindowID id, const wxString &title,
318 const wxPoint &pos, const wxSize &size,
319 long style, const wxString &name )
320{
8d788b83
PC
321 m_miniTitle = 0;
322 if (style & wxCAPTION)
00e4ffbc 323 m_miniTitle = 16;
c2fa61e8 324
6d976005 325 if (style & wxRESIZE_BORDER)
85a0a12a 326 m_miniEdge = 4;
6d976005
RR
327 else
328 m_miniEdge = 3;
340bfb43 329 m_isDragging = false;
b2b3ccc5
RR
330 m_oldX = -1;
331 m_oldY = -1;
332 m_diffX = 0;
333 m_diffY = 0;
c2fa61e8 334
b2b3ccc5
RR
335 wxFrame::Create( parent, id, title, pos, size, style, name );
336
3f4049ff
PC
337 // Use a GtkEventBox for the title and borders. Using m_widget for this
338 // almost works, except that setting the resize cursor has no effect.
339 GtkWidget* eventbox = gtk_event_box_new();
340 gtk_widget_add_events(eventbox,
cca410b3 341 GDK_POINTER_MOTION_MASK |
3f4049ff
PC
342 GDK_POINTER_MOTION_HINT_MASK);
343 gtk_widget_show(eventbox);
344 // Use a GtkAlignment to position m_mainWidget inside the decorations
345 GtkWidget* alignment = gtk_alignment_new(0, 0, 1, 1);
346 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment),
347 m_miniTitle + m_miniEdge, m_miniEdge, m_miniEdge, m_miniEdge);
348 gtk_widget_show(alignment);
349 // The GtkEventBox and GtkAlignment go between m_widget and m_mainWidget
350 gtk_widget_reparent(m_mainWidget, alignment);
351 gtk_container_add(GTK_CONTAINER(eventbox), alignment);
352 gtk_container_add(GTK_CONTAINER(m_widget), eventbox);
cca410b3
PC
353
354 m_gdkDecor = 0;
355 m_gdkFunc = 0;
356 if (style & wxRESIZE_BORDER)
357 m_gdkFunc = GDK_FUNC_RESIZE;
fce611e4
PC
358 gtk_window_set_default_size(GTK_WINDOW(m_widget), m_width, m_height);
359 m_decorSize.Set(0, 0);
360 m_deferShow = false;
cca410b3 361
3f4049ff
PC
362 // don't allow sizing smaller than decorations
363 GdkGeometry geom;
364 geom.min_width = 2 * m_miniEdge;
365 geom.min_height = 2 * m_miniEdge + m_miniTitle;
366 gtk_window_set_geometry_hints(GTK_WINDOW(m_widget), NULL, &geom, GDK_HINT_MIN_SIZE);
367
2c990ec0
RR
368 if (m_parent && (GTK_IS_WINDOW(m_parent->m_widget)))
369 {
370 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
371 }
340bfb43 372
8d788b83 373 if (m_miniTitle && (style & wxCLOSE_BOX))
b9a535f5 374 {
00e4ffbc 375 wxImage img = wxBitmap((const char*)close_bits, 16, 16).ConvertToImage();
c4d39711 376 img.Replace(0,0,0,123,123,123);
00e4ffbc
RR
377 img.SetMaskColour(123,123,123);
378 m_closeButton = wxBitmap( img );
b9a535f5 379 }
c2fa61e8 380
32a95f9f 381 /* these are called when the borders are drawn */
3f4049ff 382 g_signal_connect_after(eventbox, "expose_event",
9fa72bd2 383 G_CALLBACK (gtk_window_own_expose_callback), this );
b2b3ccc5 384
32a95f9f 385 /* these are required for dragging the mini frame around */
3f4049ff 386 g_signal_connect (eventbox, "button_press_event",
9fa72bd2 387 G_CALLBACK (gtk_window_button_press_callback), this);
3f4049ff 388 g_signal_connect (eventbox, "button_release_event",
9fa72bd2 389 G_CALLBACK (gtk_window_button_release_callback), this);
3f4049ff 390 g_signal_connect (eventbox, "motion_notify_event",
9fa72bd2 391 G_CALLBACK (gtk_window_motion_notify_callback), this);
3f4049ff 392 g_signal_connect (eventbox, "leave_notify_event",
85a0a12a 393 G_CALLBACK (gtk_window_leave_callback), this);
340bfb43 394 return true;
b2b3ccc5 395}
dcf924a3 396
cca410b3
PC
397void wxMiniFrame::DoGetClientSize(int* width, int* height) const
398{
399 wxFrame::DoGetClientSize(width, height);
400 if (width)
401 {
402 *width -= 2 * m_miniEdge;
403 if (*width < 0) *width = 0;
404 }
405 if (height)
406 {
407 *height -= m_miniTitle + 2 * m_miniEdge;
408 if (*height < 0) *height = 0;
409 }
410}
411
3f4049ff
PC
412// Keep min size at least as large as decorations
413void wxMiniFrame::DoSetSizeHints(int minW, int minH, int maxW, int maxH, int incW, int incH)
414{
415 const int w = 2 * m_miniEdge;
416 const int h = 2 * m_miniEdge + m_miniTitle;
417 if (minW < w) minW = w;
418 if (minH < h) minH = h;
419 wxFrame::DoSetSizeHints(minW, minH, maxW, maxH, incW, incH);
420}
421
400be137
RR
422void wxMiniFrame::SetTitle( const wxString &title )
423{
424 wxFrame::SetTitle( title );
340bfb43 425
3f4049ff
PC
426 GtkWidget* widget = GTK_BIN(m_widget)->child;
427 if (widget->window)
428 gdk_window_invalidate_rect(widget->window, NULL, false);
400be137
RR
429}
430
11dbb4bf 431#endif // wxUSE_MINIFRAME