don't always add wxCAPTION to wxMiniFrame style unconditionally
[wxWidgets.git] / src / gtk / minifram.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/minifram.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #if wxUSE_MINIFRAME
14
15 #include "wx/minifram.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/settings.h"
19 #include "wx/dcclient.h"
20 #include "wx/image.h"
21 #endif
22
23 #include "wx/gtk/win_gtk.h"
24 #include "wx/gtk/private.h"
25
26 //-----------------------------------------------------------------------------
27 // data
28 //-----------------------------------------------------------------------------
29
30 extern bool g_blockEventsOnDrag;
31 extern bool g_blockEventsOnScroll;
32 extern GtkWidget *wxGetRootWindow();
33
34 //-----------------------------------------------------------------------------
35 // "expose_event" of m_mainWidget
36 //-----------------------------------------------------------------------------
37
38 // StepColour() it a utility function that simply darkens
39 // or lightens a color, based on the specified percentage
40 static 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
48 static 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
60 extern "C" {
61 static gboolean gtk_window_own_expose_callback(GtkWidget* widget, GdkEventExpose* gdk_event, wxMiniFrame* win)
62 {
63 if (!win->m_hasVMT || gdk_event->count > 0)
64 return false;
65
66 GtkPizza *pizza = GTK_PIZZA(widget);
67
68 gtk_paint_shadow (widget->style,
69 pizza->bin_window,
70 GTK_STATE_NORMAL,
71 GTK_SHADOW_OUT,
72 NULL, NULL, NULL, // FIXME: No clipping?
73 0, 0,
74 win->m_width, win->m_height);
75
76 int style = win->GetWindowStyle();
77
78 wxClientDC dc(win);
79 // Hack alert
80 dc.m_window = pizza->bin_window;
81
82 if (style & wxRESIZE_BORDER)
83 {
84 dc.SetBrush( *wxGREY_BRUSH );
85 dc.SetPen( *wxTRANSPARENT_PEN );
86 dc.DrawRectangle( win->m_width - 14, win->m_height-14, 14, 14 );
87 }
88
89 if (!win->GetTitle().empty() &&
90 ((style & wxCAPTION) ||
91 (style & wxTINY_CAPTION_HORIZ) ||
92 (style & wxTINY_CAPTION_VERT)))
93 {
94 dc.SetFont( *wxSMALL_FONT );
95 int height = dc.GetCharHeight();
96
97 wxBrush brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT) ) );
98 dc.SetBrush( brush );
99 dc.SetPen( *wxTRANSPARENT_PEN );
100 dc.DrawRectangle( 3, 3, win->m_width - 7, height );
101
102 dc.SetTextForeground( *wxWHITE );
103 dc.DrawText( win->GetTitle(), 6, 3 );
104
105 if (style & wxCLOSE_BOX)
106 dc.DrawBitmap( win->m_closeButton, win->m_width-19, 2, true );
107 }
108 return false;
109 }
110 }
111
112 //-----------------------------------------------------------------------------
113 // "button_press_event" of m_mainWidget
114 //-----------------------------------------------------------------------------
115
116 extern "C" {
117 static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
118 {
119 if (!win->m_hasVMT) return FALSE;
120 if (g_blockEventsOnDrag) return TRUE;
121 if (g_blockEventsOnScroll) return TRUE;
122
123 if (win->m_isDragging) return TRUE;
124
125 GtkPizza *pizza = GTK_PIZZA(widget);
126 if (gdk_event->window != pizza->bin_window) return TRUE;
127
128 int style = win->GetWindowStyle();
129
130 int y = (int)gdk_event->y;
131 int x = (int)gdk_event->x;
132
133 if ((style & wxRESIZE_BORDER) &&
134 (x > win->m_width-14) && (y > win->m_height-14))
135 {
136 GtkWidget *ancestor = gtk_widget_get_toplevel( widget );
137
138 GdkWindow *source = GTK_PIZZA(widget)->bin_window;
139
140 int org_x = 0;
141 int org_y = 0;
142 gdk_window_get_origin( source, &org_x, &org_y );
143
144 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
145 GDK_WINDOW_EDGE_SOUTH_EAST,
146 1,
147 org_x + x,
148 org_y + y,
149 0);
150
151 return TRUE;
152 }
153
154 if ((style & wxCLOSE_BOX) &&
155 ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT)))
156 {
157 if ((y > 3) && (y < 19) && (x > win->m_width-19) && (x < win->m_width-3))
158 {
159 win->Close();
160 return TRUE;
161 }
162 }
163
164 wxClientDC dc(win);
165 dc.SetFont( *wxSMALL_FONT );
166 int height = dc.GetCharHeight() + 1;
167
168
169 if (y > height) return TRUE;
170
171 gdk_window_raise( win->m_widget->window );
172
173 gdk_pointer_grab( widget->window, FALSE,
174 (GdkEventMask)
175 (GDK_BUTTON_PRESS_MASK |
176 GDK_BUTTON_RELEASE_MASK |
177 GDK_POINTER_MOTION_MASK |
178 GDK_POINTER_MOTION_HINT_MASK |
179 GDK_BUTTON_MOTION_MASK |
180 GDK_BUTTON1_MOTION_MASK),
181 (GdkWindow *) NULL,
182 (GdkCursor *) NULL,
183 (unsigned int) GDK_CURRENT_TIME );
184
185 win->m_diffX = x;
186 win->m_diffY = y;
187 win->m_oldX = 0;
188 win->m_oldY = 0;
189
190 win->m_isDragging = true;
191
192 return TRUE;
193 }
194 }
195
196 //-----------------------------------------------------------------------------
197 // "button_release_event" of m_mainWidget
198 //-----------------------------------------------------------------------------
199
200 extern "C" {
201 static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
202 {
203 if (!win->m_hasVMT) return FALSE;
204 if (g_blockEventsOnDrag) return TRUE;
205 if (g_blockEventsOnScroll) return TRUE;
206
207 if (!win->m_isDragging) return TRUE;
208
209 win->m_isDragging = false;
210
211 int x = (int)gdk_event->x;
212 int y = (int)gdk_event->y;
213
214 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
215 int org_x = 0;
216 int org_y = 0;
217 gdk_window_get_origin( widget->window, &org_x, &org_y );
218 x += org_x - win->m_diffX;
219 y += org_y - win->m_diffY;
220 win->m_x = x;
221 win->m_y = y;
222 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
223
224 return TRUE;
225 }
226 }
227
228 //-----------------------------------------------------------------------------
229 // "leave_notify_event" of m_mainWidget
230 //-----------------------------------------------------------------------------
231
232 extern "C" {
233 static gboolean
234 gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxMiniFrame *win )
235 {
236 if (!win->m_hasVMT) return FALSE;
237 if (g_blockEventsOnDrag) return FALSE;
238
239 gdk_window_set_cursor( widget->window, NULL );
240
241 return FALSE;
242 }
243 }
244
245 //-----------------------------------------------------------------------------
246 // "motion_notify_event" of m_mainWidget
247 //-----------------------------------------------------------------------------
248
249 extern "C" {
250 static gint
251 gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxMiniFrame *win )
252 {
253 if (!win->m_hasVMT) return FALSE;
254 if (g_blockEventsOnDrag) return TRUE;
255 if (g_blockEventsOnScroll) return TRUE;
256
257 if (gdk_event->is_hint)
258 {
259 int x = 0;
260 int y = 0;
261 GdkModifierType state;
262 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
263 gdk_event->x = x;
264 gdk_event->y = y;
265 gdk_event->state = state;
266 }
267
268 int style = win->GetWindowStyle();
269
270 int x = (int)gdk_event->x;
271 int y = (int)gdk_event->y;
272
273 if (!win->m_isDragging)
274 {
275 if (style & wxRESIZE_BORDER)
276 {
277 if ((x > win->m_width-14) && (y > win->m_height-14))
278 gdk_window_set_cursor( widget->window, gdk_cursor_new( GDK_BOTTOM_RIGHT_CORNER ) );
279 else
280 gdk_window_set_cursor( widget->window, NULL );
281 }
282 return TRUE;
283 }
284
285 win->m_oldX = x - win->m_diffX;
286 win->m_oldY = y - win->m_diffY;
287
288 int org_x = 0;
289 int org_y = 0;
290 gdk_window_get_origin( widget->window, &org_x, &org_y );
291 x += org_x - win->m_diffX;
292 y += org_y - win->m_diffY;
293 win->m_x = x;
294 win->m_y = y;
295 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
296
297
298 return TRUE;
299 }
300 }
301
302 //-----------------------------------------------------------------------------
303 // wxMiniFrame
304 //-----------------------------------------------------------------------------
305
306 static unsigned char close_bits[]={
307 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
308 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
309 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
310
311
312 IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame,wxFrame)
313
314 bool wxMiniFrame::Create( wxWindow *parent, wxWindowID id, const wxString &title,
315 const wxPoint &pos, const wxSize &size,
316 long style, const wxString &name )
317 {
318 if ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT))
319 m_miniTitle = 16;
320
321 if (style & wxRESIZE_BORDER)
322 m_miniEdge = 4;
323 else
324 m_miniEdge = 3;
325 m_isDragging = false;
326 m_oldX = -1;
327 m_oldY = -1;
328 m_diffX = 0;
329 m_diffY = 0;
330
331 wxFrame::Create( parent, id, title, pos, size, style, name );
332
333 if (m_parent && (GTK_IS_WINDOW(m_parent->m_widget)))
334 {
335 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
336 }
337
338 if ((style & wxCLOSE_BOX) &&
339 ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT)))
340 {
341 wxImage img = wxBitmap((const char*)close_bits, 16, 16).ConvertToImage();
342 img.Replace(0,0,0,123,123,123);
343 img.SetMaskColour(123,123,123);
344 m_closeButton = wxBitmap( img );
345 }
346
347 /* these are called when the borders are drawn */
348 g_signal_connect (m_mainWidget, "expose_event",
349 G_CALLBACK (gtk_window_own_expose_callback), this );
350
351 /* these are required for dragging the mini frame around */
352 g_signal_connect (m_mainWidget, "button_press_event",
353 G_CALLBACK (gtk_window_button_press_callback), this);
354 g_signal_connect (m_mainWidget, "button_release_event",
355 G_CALLBACK (gtk_window_button_release_callback), this);
356 g_signal_connect (m_mainWidget, "motion_notify_event",
357 G_CALLBACK (gtk_window_motion_notify_callback), this);
358 g_signal_connect (m_mainWidget, "leave_notify_event",
359 G_CALLBACK (gtk_window_leave_callback), this);
360 return true;
361 }
362
363 void wxMiniFrame::SetTitle( const wxString &title )
364 {
365 wxFrame::SetTitle( title );
366
367 if (GTK_PIZZA(m_mainWidget)->bin_window)
368 gdk_window_invalidate_rect( GTK_PIZZA(m_mainWidget)->bin_window, NULL, true );
369 }
370
371 #endif // wxUSE_MINIFRAME