1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/minifram.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
15 #include "wx/minifram.h"
18 #include "wx/settings.h"
19 #include "wx/dcclient.h"
25 //-----------------------------------------------------------------------------
27 //-----------------------------------------------------------------------------
29 extern bool g_blockEventsOnDrag
;
30 extern bool g_blockEventsOnScroll
;
32 //-----------------------------------------------------------------------------
33 // "expose_event" of m_mainWidget
34 //-----------------------------------------------------------------------------
36 // StepColour() it a utility function that simply darkens
37 // or lightens a color, based on the specified percentage
38 static wxColor
StepColour(const wxColor
& c
, int percent
)
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));
46 static wxColor
LightContrastColour(const wxColour
& c
)
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)
55 return StepColour(c
, amount
);
59 static gboolean
gtk_window_own_expose_callback(GtkWidget
* widget
, GdkEventExpose
* gdk_event
, wxMiniFrame
* win
)
61 if (!win
->m_hasVMT
|| gdk_event
->count
> 0)
64 gtk_paint_shadow (widget
->style
,
68 NULL
, NULL
, NULL
, // FIXME: No clipping?
70 win
->m_width
, win
->m_height
);
72 int style
= win
->GetWindowStyle();
77 wxImplDC
*impl
= dc
.GetImpl();
78 wxGTKClientImplDC
*client_impl
= wxDynamicCast( impl
, wxGTKClientImplDC
);
80 client_impl
->m_window
= widget
->window
;
83 dc
.m_window
= widget
->window
;
86 if (style
& wxRESIZE_BORDER
)
88 dc
.SetBrush( *wxGREY_BRUSH
);
89 dc
.SetPen( *wxTRANSPARENT_PEN
);
90 dc
.DrawRectangle( win
->m_width
- 14, win
->m_height
-14, 14, 14 );
93 if (!win
->GetTitle().empty() &&
94 ((style
& wxCAPTION
) ||
95 (style
& wxTINY_CAPTION_HORIZ
) ||
96 (style
& wxTINY_CAPTION_VERT
)))
98 dc
.SetFont( *wxSMALL_FONT
);
100 wxBrush
brush( LightContrastColour( wxSystemSettings
::GetColour(wxSYS_COLOUR_HIGHLIGHT
) ) );
101 dc
.SetBrush( brush
);
102 dc
.SetPen( *wxTRANSPARENT_PEN
);
103 dc
.DrawRectangle( win
->m_miniEdge
-1,
105 win
->m_width
- (2*(win
->m_miniEdge
-1)),
108 dc
.SetTextForeground( *wxWHITE
);
109 dc
.DrawText( win
->GetTitle(), 6, 4 );
111 if (style
& wxCLOSE_BOX
)
112 dc
.DrawBitmap( win
->m_closeButton
, win
->m_width
-18, 3, true );
119 //-----------------------------------------------------------------------------
120 // "button_press_event" of m_mainWidget
121 //-----------------------------------------------------------------------------
124 static gint
gtk_window_button_press_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxMiniFrame
*win
)
126 if (!win
->m_hasVMT
) return FALSE
;
127 if (g_blockEventsOnDrag
) return TRUE
;
128 if (g_blockEventsOnScroll
) return TRUE
;
130 if (win
->m_isDragging
) return TRUE
;
132 int style
= win
->GetWindowStyle();
134 int y
= (int)gdk_event
->y
;
135 int x
= (int)gdk_event
->x
;
137 if ((style
& wxRESIZE_BORDER
) &&
138 (x
> win
->m_width
-14) && (y
> win
->m_height
-14))
140 GtkWidget
*ancestor
= gtk_widget_get_toplevel( widget
);
142 GdkWindow
*source
= widget
->window
;
146 gdk_window_get_origin( source
, &org_x
, &org_y
);
148 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor
),
149 GDK_WINDOW_EDGE_SOUTH_EAST
,
158 if ((style
& wxCLOSE_BOX
) &&
159 ((style
& wxCAPTION
) || (style
& wxTINY_CAPTION_HORIZ
) || (style
& wxTINY_CAPTION_VERT
)))
161 if ((y
> 3) && (y
< 19) && (x
> win
->m_width
-19) && (x
< win
->m_width
-3))
168 if (y
> win
->m_miniEdge
-1 + 15) return TRUE
;
170 gdk_window_raise( win
->m_widget
->window
);
172 gdk_pointer_grab( widget
->window
, FALSE
,
174 (GDK_BUTTON_PRESS_MASK
|
175 GDK_BUTTON_RELEASE_MASK
|
176 GDK_POINTER_MOTION_MASK
|
177 GDK_POINTER_MOTION_HINT_MASK
|
178 GDK_BUTTON_MOTION_MASK
|
179 GDK_BUTTON1_MOTION_MASK
),
182 (unsigned int) GDK_CURRENT_TIME
);
189 win
->m_isDragging
= true;
195 //-----------------------------------------------------------------------------
196 // "button_release_event" of m_mainWidget
197 //-----------------------------------------------------------------------------
200 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxMiniFrame
*win
)
202 if (!win
->m_hasVMT
) return FALSE
;
203 if (g_blockEventsOnDrag
) return TRUE
;
204 if (g_blockEventsOnScroll
) return TRUE
;
206 if (!win
->m_isDragging
) return TRUE
;
208 win
->m_isDragging
= false;
210 int x
= (int)gdk_event
->x
;
211 int y
= (int)gdk_event
->y
;
213 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
216 gdk_window_get_origin( widget
->window
, &org_x
, &org_y
);
217 x
+= org_x
- win
->m_diffX
;
218 y
+= org_y
- win
->m_diffY
;
221 gtk_window_move( GTK_WINDOW(win
->m_widget
), x
, y
);
227 //-----------------------------------------------------------------------------
228 // "leave_notify_event" of m_mainWidget
229 //-----------------------------------------------------------------------------
233 gtk_window_leave_callback(GtkWidget
*widget
,
234 GdkEventCrossing
* WXUNUSED(gdk_event
),
237 if (!win
->m_hasVMT
) return FALSE
;
238 if (g_blockEventsOnDrag
) return FALSE
;
240 gdk_window_set_cursor( widget
->window
, NULL
);
246 //-----------------------------------------------------------------------------
247 // "motion_notify_event" of m_mainWidget
248 //-----------------------------------------------------------------------------
252 gtk_window_motion_notify_callback( GtkWidget
*widget
, GdkEventMotion
*gdk_event
, wxMiniFrame
*win
)
254 if (!win
->m_hasVMT
) return FALSE
;
255 if (g_blockEventsOnDrag
) return TRUE
;
256 if (g_blockEventsOnScroll
) return TRUE
;
258 if (gdk_event
->is_hint
)
262 GdkModifierType state
;
263 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
266 gdk_event
->state
= state
;
269 int style
= win
->GetWindowStyle();
271 int x
= (int)gdk_event
->x
;
272 int y
= (int)gdk_event
->y
;
274 if (!win
->m_isDragging
)
276 if (style
& wxRESIZE_BORDER
)
278 if ((x
> win
->m_width
-14) && (y
> win
->m_height
-14))
279 gdk_window_set_cursor( widget
->window
, gdk_cursor_new( GDK_BOTTOM_RIGHT_CORNER
) );
281 gdk_window_set_cursor( widget
->window
, NULL
);
286 win
->m_oldX
= x
- win
->m_diffX
;
287 win
->m_oldY
= y
- win
->m_diffY
;
291 gdk_window_get_origin( widget
->window
, &org_x
, &org_y
);
292 x
+= org_x
- win
->m_diffX
;
293 y
+= org_y
- win
->m_diffY
;
296 gtk_window_move( GTK_WINDOW(win
->m_widget
), x
, y
);
302 //-----------------------------------------------------------------------------
303 // "size_allocate" from GtkFixed, parent of m_mainWidget
304 //-----------------------------------------------------------------------------
307 static void size_allocate(GtkWidget
*, GtkAllocation
* alloc
, wxMiniFrame
* win
)
309 // place m_mainWidget inside of decorations drawn on the GtkFixed
310 GtkAllocation alloc2
= win
->m_mainWidget
->allocation
;
311 alloc2
.width
= alloc
->width
- 2 * win
->m_miniEdge
;
312 alloc2
.height
= alloc
->height
- win
->m_miniTitle
- 2 * win
->m_miniEdge
;
313 gtk_widget_size_allocate(win
->m_mainWidget
, &alloc2
);
317 //-----------------------------------------------------------------------------
319 //-----------------------------------------------------------------------------
321 static unsigned char close_bits
[]={
322 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
323 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
324 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
327 IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame
,wxFrame
)
329 bool wxMiniFrame
::Create( wxWindow
*parent
, wxWindowID id
, const wxString
&title
,
330 const wxPoint
&pos
, const wxSize
&size
,
331 long style
, const wxString
&name
)
333 if ((style
& wxCAPTION
) || (style
& wxTINY_CAPTION_HORIZ
) || (style
& wxTINY_CAPTION_VERT
))
336 if (style
& wxRESIZE_BORDER
)
340 m_isDragging
= false;
346 wxFrame
::Create( parent
, id
, title
, pos
, size
, style
, name
);
348 // borders and title are on a GtkFixed between m_widget and m_mainWidget
349 GtkWidget
* fixed
= gtk_fixed_new();
350 gtk_fixed_set_has_window((GtkFixed
*)fixed
, true);
351 gtk_widget_add_events(fixed
,
352 GDK_POINTER_MOTION_MASK
|
353 GDK_POINTER_MOTION_HINT_MASK
|
354 GDK_BUTTON_MOTION_MASK
|
355 GDK_BUTTON_PRESS_MASK
|
356 GDK_BUTTON_RELEASE_MASK
|
357 GDK_LEAVE_NOTIFY_MASK
);
358 gtk_widget_show(fixed
);
359 gtk_widget_reparent(m_mainWidget
, fixed
);
360 gtk_container_add((GtkContainer
*)m_widget
, fixed
);
361 gtk_fixed_move((GtkFixed
*)fixed
, m_mainWidget
, m_miniEdge
, m_miniTitle
+ m_miniEdge
);
362 g_signal_connect(fixed
, "size_allocate", G_CALLBACK(size_allocate
), this);
366 if (style
& wxRESIZE_BORDER
)
367 m_gdkFunc
= GDK_FUNC_RESIZE
;
369 // need to reset default size after changing m_gdkDecor
370 gtk_window_set_default_size(GTK_WINDOW(m_widget
), m_width
, m_height
);
372 if (m_parent
&& (GTK_IS_WINDOW(m_parent
->m_widget
)))
374 gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) );
377 if ((style
& wxCLOSE_BOX
) &&
378 ((style
& wxCAPTION
) || (style
& wxTINY_CAPTION_HORIZ
) || (style
& wxTINY_CAPTION_VERT
)))
380 wxImage img
= wxBitmap((const char*)close_bits
, 16, 16).ConvertToImage();
381 img
.Replace(0,0,0,123,123,123);
382 img
.SetMaskColour(123,123,123);
383 m_closeButton
= wxBitmap( img
);
386 /* these are called when the borders are drawn */
387 g_signal_connect_after(fixed
, "expose_event",
388 G_CALLBACK (gtk_window_own_expose_callback
), this );
390 /* these are required for dragging the mini frame around */
391 g_signal_connect (fixed
, "button_press_event",
392 G_CALLBACK (gtk_window_button_press_callback
), this);
393 g_signal_connect (fixed
, "button_release_event",
394 G_CALLBACK (gtk_window_button_release_callback
), this);
395 g_signal_connect (fixed
, "motion_notify_event",
396 G_CALLBACK (gtk_window_motion_notify_callback
), this);
397 g_signal_connect (fixed
, "leave_notify_event",
398 G_CALLBACK (gtk_window_leave_callback
), this);
402 void wxMiniFrame
::DoGetClientSize(int* width
, int* height
) const
404 wxFrame
::DoGetClientSize(width
, height
);
407 *width
-= 2 * m_miniEdge
;
408 if (*width
< 0) *width
= 0;
412 *height
-= m_miniTitle
+ 2 * m_miniEdge
;
413 if (*height
< 0) *height
= 0;
417 void wxMiniFrame
::SetTitle( const wxString
&title
)
419 wxFrame
::SetTitle( title
);
421 GtkWidget
* fixed
= GTK_BIN(m_widget
)->child
;
423 gdk_window_invalidate_rect(fixed
->window
, NULL
, false);
426 #endif // wxUSE_MINIFRAME