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"
16 #include "wx/gtk/dcclient.h"
19 #include "wx/settings.h"
20 #include "wx/dcclient.h"
26 //-----------------------------------------------------------------------------
28 //-----------------------------------------------------------------------------
30 extern bool g_blockEventsOnDrag
;
31 extern bool g_blockEventsOnScroll
;
33 //-----------------------------------------------------------------------------
34 // "expose_event" of m_mainWidget
35 //-----------------------------------------------------------------------------
37 // StepColour() it a utility function that simply darkens
38 // or lightens a color, based on the specified percentage
39 static wxColor
StepColour(const wxColor
& c
, int percent
)
41 int r
= c
.Red(), g
= c
.Green(), b
= c
.Blue();
42 return wxColour((unsigned char)wxMin((r
*percent
)/100,255),
43 (unsigned char)wxMin((g
*percent
)/100,255),
44 (unsigned char)wxMin((b
*percent
)/100,255));
47 static wxColor
LightContrastColour(const wxColour
& c
)
51 // if the color is especially dark, then
52 // make the contrast even lighter
53 if (c
.Red() < 128 && c
.Green() < 128 && c
.Blue() < 128)
56 return StepColour(c
, amount
);
60 static gboolean
gtk_window_own_expose_callback(GtkWidget
* widget
, GdkEventExpose
* gdk_event
, wxMiniFrame
* win
)
62 if (!win
->m_hasVMT
|| gdk_event
->count
> 0)
65 gtk_paint_shadow (widget
->style
,
69 NULL
, NULL
, NULL
, // FIXME: No clipping?
71 win
->m_width
, win
->m_height
);
73 int style
= win
->GetWindowStyle();
77 wxDCImpl
*impl
= dc
.GetImpl();
78 wxClientDCImpl
*gtk_impl
= wxDynamicCast( impl
, wxClientDCImpl
);
79 gtk_impl
->m_gdkwindow
= widget
->window
; // Hack alert
81 if (style
& wxRESIZE_BORDER
)
83 dc
.SetBrush( *wxGREY_BRUSH
);
84 dc
.SetPen( *wxTRANSPARENT_PEN
);
85 dc
.DrawRectangle( win
->m_width
- 14, win
->m_height
-14, 14, 14 );
88 if (!win
->GetTitle().empty() &&
89 ((style
& wxCAPTION
) ||
90 (style
& wxTINY_CAPTION_HORIZ
) ||
91 (style
& wxTINY_CAPTION_VERT
)))
93 dc
.SetFont( *wxSMALL_FONT
);
95 wxBrush
brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
) ) );
97 dc
.SetPen( *wxTRANSPARENT_PEN
);
98 dc
.DrawRectangle( win
->m_miniEdge
-1,
100 win
->m_width
- (2*(win
->m_miniEdge
-1)),
103 dc
.SetTextForeground( *wxWHITE
);
104 dc
.DrawText( win
->GetTitle(), 6, 4 );
106 if (style
& wxCLOSE_BOX
)
107 dc
.DrawBitmap( win
->m_closeButton
, win
->m_width
-18, 3, true );
114 //-----------------------------------------------------------------------------
115 // "button_press_event" of m_mainWidget
116 //-----------------------------------------------------------------------------
119 static gint
gtk_window_button_press_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxMiniFrame
*win
)
121 if (!win
->m_hasVMT
) return FALSE
;
122 if (g_blockEventsOnDrag
) return TRUE
;
123 if (g_blockEventsOnScroll
) return TRUE
;
125 if (win
->m_isDragging
) return TRUE
;
127 int style
= win
->GetWindowStyle();
129 int y
= (int)gdk_event
->y
;
130 int x
= (int)gdk_event
->x
;
132 if ((style
& wxRESIZE_BORDER
) &&
133 (x
> win
->m_width
-14) && (y
> win
->m_height
-14))
135 GtkWidget
*ancestor
= gtk_widget_get_toplevel( widget
);
137 GdkWindow
*source
= widget
->window
;
141 gdk_window_get_origin( source
, &org_x
, &org_y
);
143 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor
),
144 GDK_WINDOW_EDGE_SOUTH_EAST
,
153 if ((style
& wxCLOSE_BOX
) &&
154 ((style
& wxCAPTION
) || (style
& wxTINY_CAPTION_HORIZ
) || (style
& wxTINY_CAPTION_VERT
)))
156 if ((y
> 3) && (y
< 19) && (x
> win
->m_width
-19) && (x
< win
->m_width
-3))
163 if (y
> win
->m_miniEdge
-1 + 15) return TRUE
;
165 gdk_window_raise( win
->m_widget
->window
);
167 gdk_pointer_grab( widget
->window
, FALSE
,
169 (GDK_BUTTON_PRESS_MASK
|
170 GDK_BUTTON_RELEASE_MASK
|
171 GDK_POINTER_MOTION_MASK
|
172 GDK_POINTER_MOTION_HINT_MASK
|
173 GDK_BUTTON_MOTION_MASK
|
174 GDK_BUTTON1_MOTION_MASK
),
177 (unsigned int) GDK_CURRENT_TIME
);
184 win
->m_isDragging
= true;
190 //-----------------------------------------------------------------------------
191 // "button_release_event" of m_mainWidget
192 //-----------------------------------------------------------------------------
195 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxMiniFrame
*win
)
197 if (!win
->m_hasVMT
) return FALSE
;
198 if (g_blockEventsOnDrag
) return TRUE
;
199 if (g_blockEventsOnScroll
) return TRUE
;
201 if (!win
->m_isDragging
) return TRUE
;
203 win
->m_isDragging
= false;
205 int x
= (int)gdk_event
->x
;
206 int y
= (int)gdk_event
->y
;
208 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
211 gdk_window_get_origin( widget
->window
, &org_x
, &org_y
);
212 x
+= org_x
- win
->m_diffX
;
213 y
+= org_y
- win
->m_diffY
;
216 gtk_window_move( GTK_WINDOW(win
->m_widget
), x
, y
);
222 //-----------------------------------------------------------------------------
223 // "leave_notify_event" of m_mainWidget
224 //-----------------------------------------------------------------------------
228 gtk_window_leave_callback(GtkWidget
*widget
,
229 GdkEventCrossing
* WXUNUSED(gdk_event
),
232 if (!win
->m_hasVMT
) return FALSE
;
233 if (g_blockEventsOnDrag
) return FALSE
;
235 gdk_window_set_cursor( widget
->window
, NULL
);
241 //-----------------------------------------------------------------------------
242 // "motion_notify_event" of m_mainWidget
243 //-----------------------------------------------------------------------------
247 gtk_window_motion_notify_callback( GtkWidget
*widget
, GdkEventMotion
*gdk_event
, wxMiniFrame
*win
)
249 if (!win
->m_hasVMT
) return FALSE
;
250 if (g_blockEventsOnDrag
) return TRUE
;
251 if (g_blockEventsOnScroll
) return TRUE
;
253 if (gdk_event
->is_hint
)
257 GdkModifierType state
;
258 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
261 gdk_event
->state
= state
;
264 int style
= win
->GetWindowStyle();
266 int x
= (int)gdk_event
->x
;
267 int y
= (int)gdk_event
->y
;
269 if (!win
->m_isDragging
)
271 if (style
& wxRESIZE_BORDER
)
273 if ((x
> win
->m_width
-14) && (y
> win
->m_height
-14))
274 gdk_window_set_cursor( widget
->window
, gdk_cursor_new( GDK_BOTTOM_RIGHT_CORNER
) );
276 gdk_window_set_cursor( widget
->window
, NULL
);
281 win
->m_oldX
= x
- win
->m_diffX
;
282 win
->m_oldY
= y
- win
->m_diffY
;
286 gdk_window_get_origin( widget
->window
, &org_x
, &org_y
);
287 x
+= org_x
- win
->m_diffX
;
288 y
+= org_y
- win
->m_diffY
;
291 gtk_window_move( GTK_WINDOW(win
->m_widget
), x
, y
);
297 //-----------------------------------------------------------------------------
299 //-----------------------------------------------------------------------------
301 static unsigned char close_bits
[]={
302 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
303 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
304 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
307 IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame
,wxFrame
)
309 bool wxMiniFrame::Create( wxWindow
*parent
, wxWindowID id
, const wxString
&title
,
310 const wxPoint
&pos
, const wxSize
&size
,
311 long style
, const wxString
&name
)
313 if ((style
& wxCAPTION
) || (style
& wxTINY_CAPTION_HORIZ
) || (style
& wxTINY_CAPTION_VERT
))
316 if (style
& wxRESIZE_BORDER
)
320 m_isDragging
= false;
326 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
328 // Use a GtkEventBox for the title and borders. Using m_widget for this
329 // almost works, except that setting the resize cursor has no effect.
330 GtkWidget
* eventbox
= gtk_event_box_new();
331 gtk_widget_add_events(eventbox
,
332 GDK_POINTER_MOTION_MASK
|
333 GDK_POINTER_MOTION_HINT_MASK
);
334 gtk_widget_show(eventbox
);
335 // Use a GtkAlignment to position m_mainWidget inside the decorations
336 GtkWidget
* alignment
= gtk_alignment_new(0, 0, 1, 1);
337 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment
),
338 m_miniTitle
+ m_miniEdge
, m_miniEdge
, m_miniEdge
, m_miniEdge
);
339 gtk_widget_show(alignment
);
340 // The GtkEventBox and GtkAlignment go between m_widget and m_mainWidget
341 gtk_widget_reparent(m_mainWidget
, alignment
);
342 gtk_container_add(GTK_CONTAINER(eventbox
), alignment
);
343 gtk_container_add(GTK_CONTAINER(m_widget
), eventbox
);
347 if (style
& wxRESIZE_BORDER
)
348 m_gdkFunc
= GDK_FUNC_RESIZE
;
350 // need to reset default size after changing m_gdkDecor
351 gtk_window_set_default_size(GTK_WINDOW(m_widget
), m_width
, m_height
);
352 m_decorSize
.Set(0, 0);
354 // don't allow sizing smaller than decorations
356 geom
.min_width
= 2 * m_miniEdge
;
357 geom
.min_height
= 2 * m_miniEdge
+ m_miniTitle
;
358 gtk_window_set_geometry_hints(GTK_WINDOW(m_widget
), NULL
, &geom
, GDK_HINT_MIN_SIZE
);
360 if (m_parent
&& (GTK_IS_WINDOW(m_parent
->m_widget
)))
362 gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) );
365 if ((style
& wxCLOSE_BOX
) &&
366 ((style
& wxCAPTION
) || (style
& wxTINY_CAPTION_HORIZ
) || (style
& wxTINY_CAPTION_VERT
)))
368 wxImage img
= wxBitmap((const char*)close_bits
, 16, 16).ConvertToImage();
369 img
.Replace(0,0,0,123,123,123);
370 img
.SetMaskColour(123,123,123);
371 m_closeButton
= wxBitmap( img
);
374 /* these are called when the borders are drawn */
375 g_signal_connect_after(eventbox
, "expose_event",
376 G_CALLBACK (gtk_window_own_expose_callback
), this );
378 /* these are required for dragging the mini frame around */
379 g_signal_connect (eventbox
, "button_press_event",
380 G_CALLBACK (gtk_window_button_press_callback
), this);
381 g_signal_connect (eventbox
, "button_release_event",
382 G_CALLBACK (gtk_window_button_release_callback
), this);
383 g_signal_connect (eventbox
, "motion_notify_event",
384 G_CALLBACK (gtk_window_motion_notify_callback
), this);
385 g_signal_connect (eventbox
, "leave_notify_event",
386 G_CALLBACK (gtk_window_leave_callback
), this);
390 void wxMiniFrame::DoGetClientSize(int* width
, int* height
) const
392 wxFrame::DoGetClientSize(width
, height
);
395 *width
-= 2 * m_miniEdge
;
396 if (*width
< 0) *width
= 0;
400 *height
-= m_miniTitle
+ 2 * m_miniEdge
;
401 if (*height
< 0) *height
= 0;
405 // Keep min size at least as large as decorations
406 void wxMiniFrame::DoSetSizeHints(int minW
, int minH
, int maxW
, int maxH
, int incW
, int incH
)
408 const int w
= 2 * m_miniEdge
;
409 const int h
= 2 * m_miniEdge
+ m_miniTitle
;
410 if (minW
< w
) minW
= w
;
411 if (minH
< h
) minH
= h
;
412 wxFrame::DoSetSizeHints(minW
, minH
, maxW
, maxH
, incW
, incH
);
415 void wxMiniFrame::SetTitle( const wxString
&title
)
417 wxFrame::SetTitle( title
);
419 GtkWidget
* widget
= GTK_BIN(m_widget
)->child
;
421 gdk_window_invalidate_rect(widget
->window
, NULL
, false);
424 #endif // wxUSE_MINIFRAME