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
);
99 int height
= dc
.GetCharHeight();
101 wxBrush
brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
) ) );
102 dc
.SetBrush( brush
);
103 dc
.SetPen( *wxTRANSPARENT_PEN
);
104 dc
.DrawRectangle( 3, 3, win
->m_width
- 7, height
);
106 dc
.SetTextForeground( *wxWHITE
);
107 dc
.DrawText( win
->GetTitle(), 6, 3 );
109 if (style
& wxCLOSE_BOX
)
110 dc
.DrawBitmap( win
->m_closeButton
, win
->m_width
-19, 2, true );
116 //-----------------------------------------------------------------------------
117 // "button_press_event" of m_mainWidget
118 //-----------------------------------------------------------------------------
121 static gint
gtk_window_button_press_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxMiniFrame
*win
)
123 if (!win
->m_hasVMT
) return FALSE
;
124 if (g_blockEventsOnDrag
) return TRUE
;
125 if (g_blockEventsOnScroll
) return TRUE
;
127 if (win
->m_isDragging
) return TRUE
;
129 int style
= win
->GetWindowStyle();
131 int y
= (int)gdk_event
->y
;
132 int x
= (int)gdk_event
->x
;
134 if ((style
& wxRESIZE_BORDER
) &&
135 (x
> win
->m_width
-14) && (y
> win
->m_height
-14))
137 GtkWidget
*ancestor
= gtk_widget_get_toplevel( widget
);
139 GdkWindow
*source
= widget
->window
;
143 gdk_window_get_origin( source
, &org_x
, &org_y
);
145 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor
),
146 GDK_WINDOW_EDGE_SOUTH_EAST
,
155 if ((style
& wxCLOSE_BOX
) &&
156 ((style
& wxCAPTION
) || (style
& wxTINY_CAPTION_HORIZ
) || (style
& wxTINY_CAPTION_VERT
)))
158 if ((y
> 3) && (y
< 19) && (x
> win
->m_width
-19) && (x
< win
->m_width
-3))
166 dc
.SetFont( *wxSMALL_FONT
);
167 int height
= dc
.GetCharHeight() + 1;
170 if (y
> height
) return TRUE
;
172 gdk_window_raise( win
->m_widget
->window
);
174 gdk_pointer_grab( widget
->window
, FALSE
,
176 (GDK_BUTTON_PRESS_MASK
|
177 GDK_BUTTON_RELEASE_MASK
|
178 GDK_POINTER_MOTION_MASK
|
179 GDK_POINTER_MOTION_HINT_MASK
|
180 GDK_BUTTON_MOTION_MASK
|
181 GDK_BUTTON1_MOTION_MASK
),
184 (unsigned int) GDK_CURRENT_TIME
);
191 win
->m_isDragging
= true;
197 //-----------------------------------------------------------------------------
198 // "button_release_event" of m_mainWidget
199 //-----------------------------------------------------------------------------
202 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxMiniFrame
*win
)
204 if (!win
->m_hasVMT
) return FALSE
;
205 if (g_blockEventsOnDrag
) return TRUE
;
206 if (g_blockEventsOnScroll
) return TRUE
;
208 if (!win
->m_isDragging
) return TRUE
;
210 win
->m_isDragging
= false;
212 int x
= (int)gdk_event
->x
;
213 int y
= (int)gdk_event
->y
;
215 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
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
;
223 gtk_window_move( GTK_WINDOW(win
->m_widget
), x
, y
);
229 //-----------------------------------------------------------------------------
230 // "leave_notify_event" of m_mainWidget
231 //-----------------------------------------------------------------------------
235 gtk_window_leave_callback(GtkWidget
*widget
,
236 GdkEventCrossing
* WXUNUSED(gdk_event
),
239 if (!win
->m_hasVMT
) return FALSE
;
240 if (g_blockEventsOnDrag
) return FALSE
;
242 gdk_window_set_cursor( widget
->window
, NULL
);
248 //-----------------------------------------------------------------------------
249 // "motion_notify_event" of m_mainWidget
250 //-----------------------------------------------------------------------------
254 gtk_window_motion_notify_callback( GtkWidget
*widget
, GdkEventMotion
*gdk_event
, wxMiniFrame
*win
)
256 if (!win
->m_hasVMT
) return FALSE
;
257 if (g_blockEventsOnDrag
) return TRUE
;
258 if (g_blockEventsOnScroll
) return TRUE
;
260 if (gdk_event
->is_hint
)
264 GdkModifierType state
;
265 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
268 gdk_event
->state
= state
;
271 int style
= win
->GetWindowStyle();
273 int x
= (int)gdk_event
->x
;
274 int y
= (int)gdk_event
->y
;
276 if (!win
->m_isDragging
)
278 if (style
& wxRESIZE_BORDER
)
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
) );
283 gdk_window_set_cursor( widget
->window
, NULL
);
288 win
->m_oldX
= x
- win
->m_diffX
;
289 win
->m_oldY
= y
- win
->m_diffY
;
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
;
298 gtk_window_move( GTK_WINDOW(win
->m_widget
), x
, y
);
304 //-----------------------------------------------------------------------------
305 // "size_allocate" from GtkFixed, parent of m_mainWidget
306 //-----------------------------------------------------------------------------
309 static void size_allocate(GtkWidget
*, GtkAllocation
* alloc
, wxMiniFrame
* win
)
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
);
319 //-----------------------------------------------------------------------------
321 //-----------------------------------------------------------------------------
323 static 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 };
329 IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame
,wxFrame
)
331 bool wxMiniFrame::Create( wxWindow
*parent
, wxWindowID id
, const wxString
&title
,
332 const wxPoint
&pos
, const wxSize
&size
,
333 long style
, const wxString
&name
)
335 if ((style
& wxCAPTION
) || (style
& wxTINY_CAPTION_HORIZ
) || (style
& wxTINY_CAPTION_VERT
))
338 if (style
& wxRESIZE_BORDER
)
342 m_isDragging
= false;
348 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
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);
368 if (style
& wxRESIZE_BORDER
)
369 m_gdkFunc
= GDK_FUNC_RESIZE
;
371 if (m_parent
&& (GTK_IS_WINDOW(m_parent
->m_widget
)))
373 gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) );
376 if ((style
& wxCLOSE_BOX
) &&
377 ((style
& wxCAPTION
) || (style
& wxTINY_CAPTION_HORIZ
) || (style
& wxTINY_CAPTION_VERT
)))
379 wxImage img
= wxBitmap((const char*)close_bits
, 16, 16).ConvertToImage();
380 img
.Replace(0,0,0,123,123,123);
381 img
.SetMaskColour(123,123,123);
382 m_closeButton
= wxBitmap( img
);
385 /* these are called when the borders are drawn */
386 g_signal_connect_after(fixed
, "expose_event",
387 G_CALLBACK (gtk_window_own_expose_callback
), this );
389 /* these are required for dragging the mini frame around */
390 g_signal_connect (fixed
, "button_press_event",
391 G_CALLBACK (gtk_window_button_press_callback
), this);
392 g_signal_connect (fixed
, "button_release_event",
393 G_CALLBACK (gtk_window_button_release_callback
), this);
394 g_signal_connect (fixed
, "motion_notify_event",
395 G_CALLBACK (gtk_window_motion_notify_callback
), this);
396 g_signal_connect (fixed
, "leave_notify_event",
397 G_CALLBACK (gtk_window_leave_callback
), this);
401 void wxMiniFrame::DoGetClientSize(int* width
, int* height
) const
403 wxFrame::DoGetClientSize(width
, height
);
406 *width
-= 2 * m_miniEdge
;
407 if (*width
< 0) *width
= 0;
411 *height
-= m_miniTitle
+ 2 * m_miniEdge
;
412 if (*height
< 0) *height
= 0;
416 void wxMiniFrame::SetTitle( const wxString
&title
)
418 wxFrame::SetTitle( title
);
420 GtkWidget
* fixed
= GTK_BIN(m_widget
)->child
;
422 gdk_window_invalidate_rect(fixed
->window
, NULL
, false);
425 #endif // wxUSE_MINIFRAME