]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/minifram.cpp
fix wxStringOutputStream::Write() in Unicode build when the output overlaps a boundar...
[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
83624f79 23#include "wx/gtk/win_gtk.h"
fab591c5 24#include "wx/gtk/private.h"
83624f79 25
32a95f9f
RR
26//-----------------------------------------------------------------------------
27// data
28//-----------------------------------------------------------------------------
29
8480b297
RR
30extern bool g_blockEventsOnDrag;
31extern bool g_blockEventsOnScroll;
c2fa61e8 32extern GtkWidget *wxGetRootWindow();
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{
6d727f6c
PC
63 if (!win->m_hasVMT || gdk_event->count > 0)
64 return false;
c2fa61e8 65
da048e3d 66 GtkPizza *pizza = GTK_PIZZA(widget);
c2fa61e8 67
67b73b9a
MR
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);
b9a535f5 75
00e4ffbc 76 int style = win->GetWindowStyle();
b41b2a05 77
85a0a12a
RR
78 wxClientDC dc(win);
79 // Hack alert
80 dc.m_window = pizza->bin_window;
b41b2a05 81
85a0a12a
RR
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
340bfb43 89 if (!win->GetTitle().empty() &&
00e4ffbc
RR
90 ((style & wxCAPTION) ||
91 (style & wxTINY_CAPTION_HORIZ) ||
92 (style & wxTINY_CAPTION_VERT)))
b9a535f5 93 {
ba718523
RR
94 dc.SetFont( *wxSMALL_FONT );
95 int height = dc.GetCharHeight();
340bfb43 96
6d976005
RR
97 wxBrush brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT) ) );
98 dc.SetBrush( brush );
99 dc.SetPen( *wxTRANSPARENT_PEN );
1ed6bbc2 100 dc.DrawRectangle( 3, 3, win->m_width - 7, height );
ba718523 101
ba718523
RR
102 dc.SetTextForeground( *wxWHITE );
103 dc.DrawText( win->GetTitle(), 6, 3 );
00e4ffbc
RR
104
105 if (style & wxCLOSE_BOX)
ba6ce5fb 106 dc.DrawBitmap( win->m_closeButton, win->m_width-19, 2, true );
b9a535f5 107 }
6d727f6c 108 return false;
32a95f9f 109}
865bb325 110}
32a95f9f 111
32a95f9f
RR
112//-----------------------------------------------------------------------------
113// "button_press_event" of m_mainWidget
114//-----------------------------------------------------------------------------
115
865bb325 116extern "C" {
32a95f9f
RR
117static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
118{
a2053b27 119 if (!win->m_hasVMT) return FALSE;
32a95f9f
RR
120 if (g_blockEventsOnDrag) return TRUE;
121 if (g_blockEventsOnScroll) return TRUE;
122
123 if (win->m_isDragging) return TRUE;
124
2c990ec0
RR
125 GtkPizza *pizza = GTK_PIZZA(widget);
126 if (gdk_event->window != pizza->bin_window) return TRUE;
ba718523 127
85a0a12a
RR
128 int style = win->GetWindowStyle();
129
00e4ffbc
RR
130 int y = (int)gdk_event->y;
131 int x = (int)gdk_event->x;
b41b2a05 132
85a0a12a
RR
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);
b41b2a05 150
85a0a12a
RR
151 return TRUE;
152 }
00e4ffbc 153
00e4ffbc
RR
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 }
b41b2a05 163
ba718523
RR
164 wxClientDC dc(win);
165 dc.SetFont( *wxSMALL_FONT );
166 int height = dc.GetCharHeight() + 1;
340bfb43 167
00e4ffbc
RR
168
169 if (y > height) return TRUE;
340bfb43 170
4dcaf11a 171 gdk_window_raise( win->m_widget->window );
c2fa61e8 172
32a95f9f
RR
173 gdk_pointer_grab( widget->window, FALSE,
174 (GdkEventMask)
175 (GDK_BUTTON_PRESS_MASK |
176 GDK_BUTTON_RELEASE_MASK |
f03fc89f 177 GDK_POINTER_MOTION_MASK |
32a95f9f 178 GDK_POINTER_MOTION_HINT_MASK |
f03fc89f 179 GDK_BUTTON_MOTION_MASK |
32a95f9f
RR
180 GDK_BUTTON1_MOTION_MASK),
181 (GdkWindow *) NULL,
182 (GdkCursor *) NULL,
7941ba11 183 (unsigned int) GDK_CURRENT_TIME );
c2fa61e8 184
00e4ffbc
RR
185 win->m_diffX = x;
186 win->m_diffY = y;
32a95f9f
RR
187 win->m_oldX = 0;
188 win->m_oldY = 0;
c2fa61e8 189
340bfb43 190 win->m_isDragging = true;
32a95f9f
RR
191
192 return TRUE;
193}
865bb325 194}
32a95f9f
RR
195
196//-----------------------------------------------------------------------------
197// "button_release_event" of m_mainWidget
198//-----------------------------------------------------------------------------
199
865bb325 200extern "C" {
32a95f9f
RR
201static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
202{
a2053b27 203 if (!win->m_hasVMT) return FALSE;
32a95f9f
RR
204 if (g_blockEventsOnDrag) return TRUE;
205 if (g_blockEventsOnScroll) return TRUE;
206
207 if (!win->m_isDragging) return TRUE;
c2fa61e8 208
11dbb4bf 209 win->m_isDragging = false;
c2fa61e8 210
32a95f9f
RR
211 int x = (int)gdk_event->x;
212 int y = (int)gdk_event->y;
c2fa61e8 213
13111b2a 214 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
c2fa61e8 215 int org_x = 0;
32a95f9f
RR
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;
121a3581
RR
220 win->m_x = x;
221 win->m_y = y;
9adb9063 222 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
32a95f9f
RR
223
224 return TRUE;
225}
865bb325 226}
32a95f9f 227
85a0a12a
RR
228//-----------------------------------------------------------------------------
229// "leave_notify_event" of m_mainWidget
230//-----------------------------------------------------------------------------
231
232extern "C" {
233static gboolean
234gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxMiniFrame *win )
235{
85a0a12a
RR
236 if (!win->m_hasVMT) return FALSE;
237 if (g_blockEventsOnDrag) return FALSE;
238
239 gdk_window_set_cursor( widget->window, NULL );
b41b2a05 240
85a0a12a
RR
241 return FALSE;
242}
243}
244
32a95f9f
RR
245//-----------------------------------------------------------------------------
246// "motion_notify_event" of m_mainWidget
247//-----------------------------------------------------------------------------
248
865bb325 249extern "C" {
b41b2a05 250static gint
85a0a12a 251gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxMiniFrame *win )
32a95f9f 252{
a2053b27 253 if (!win->m_hasVMT) return FALSE;
32a95f9f
RR
254 if (g_blockEventsOnDrag) return TRUE;
255 if (g_blockEventsOnScroll) return TRUE;
256
32a95f9f
RR
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
85a0a12a 268 int style = win->GetWindowStyle();
b41b2a05 269
d02d8b4c
RR
270 int x = (int)gdk_event->x;
271 int y = (int)gdk_event->y;
b41b2a05 272
85a0a12a
RR
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 }
b41b2a05 284
85a0a12a
RR
285 win->m_oldX = x - win->m_diffX;
286 win->m_oldY = y - win->m_diffY;
287
d02d8b4c
RR
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
c2fa61e8 297
32a95f9f
RR
298 return TRUE;
299}
865bb325 300}
32a95f9f 301
b2b3ccc5
RR
302//-----------------------------------------------------------------------------
303// wxMiniFrame
304//-----------------------------------------------------------------------------
305
00e4ffbc
RR
306static 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
5d5b3a40 311
b2b3ccc5
RR
312IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame,wxFrame)
313
314bool wxMiniFrame::Create( wxWindow *parent, wxWindowID id, const wxString &title,
315 const wxPoint &pos, const wxSize &size,
316 long style, const wxString &name )
317{
2c990ec0 318 style = style | wxCAPTION;
b9a535f5
RR
319
320 if ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT))
00e4ffbc 321 m_miniTitle = 16;
c2fa61e8 322
6d976005 323 if (style & wxRESIZE_BORDER)
85a0a12a 324 m_miniEdge = 4;
6d976005
RR
325 else
326 m_miniEdge = 3;
340bfb43 327 m_isDragging = false;
b2b3ccc5
RR
328 m_oldX = -1;
329 m_oldY = -1;
330 m_diffX = 0;
331 m_diffY = 0;
c2fa61e8 332
b2b3ccc5
RR
333 wxFrame::Create( parent, id, title, pos, size, style, name );
334
2c990ec0
RR
335 if (m_parent && (GTK_IS_WINDOW(m_parent->m_widget)))
336 {
337 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
338 }
340bfb43 339
00e4ffbc 340 if ((style & wxCLOSE_BOX) &&
b9a535f5
RR
341 ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT)))
342 {
00e4ffbc 343 wxImage img = wxBitmap((const char*)close_bits, 16, 16).ConvertToImage();
c4d39711 344 img.Replace(0,0,0,123,123,123);
00e4ffbc
RR
345 img.SetMaskColour(123,123,123);
346 m_closeButton = wxBitmap( img );
b9a535f5 347 }
c2fa61e8 348
32a95f9f 349 /* these are called when the borders are drawn */
9fa72bd2
MR
350 g_signal_connect (m_mainWidget, "expose_event",
351 G_CALLBACK (gtk_window_own_expose_callback), this );
b2b3ccc5 352
32a95f9f 353 /* these are required for dragging the mini frame around */
9fa72bd2
MR
354 g_signal_connect (m_mainWidget, "button_press_event",
355 G_CALLBACK (gtk_window_button_press_callback), this);
356 g_signal_connect (m_mainWidget, "button_release_event",
357 G_CALLBACK (gtk_window_button_release_callback), this);
358 g_signal_connect (m_mainWidget, "motion_notify_event",
359 G_CALLBACK (gtk_window_motion_notify_callback), this);
85a0a12a
RR
360 g_signal_connect (m_mainWidget, "leave_notify_event",
361 G_CALLBACK (gtk_window_leave_callback), this);
340bfb43 362 return true;
b2b3ccc5 363}
dcf924a3 364
400be137
RR
365void wxMiniFrame::SetTitle( const wxString &title )
366{
367 wxFrame::SetTitle( title );
340bfb43 368
c67e060d
RR
369 if (GTK_PIZZA(m_mainWidget)->bin_window)
370 gdk_window_invalidate_rect( GTK_PIZZA(m_mainWidget)->bin_window, NULL, true );
400be137
RR
371}
372
11dbb4bf 373#endif // wxUSE_MINIFRAME