]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/minifram.cpp
minimize overlay area to avoid eg scrolling artifacts when using a caret
[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" {
00e4ffbc 61static void gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxMiniFrame *win )
32a95f9f 62{
14819684 63 // don't need to install idle handler, its done from "event" signal
acfd422a 64
a2053b27 65 if (!win->m_hasVMT) return;
32a95f9f 66 if (gdk_event->count > 0) return;
c2fa61e8 67
da048e3d 68 GtkPizza *pizza = GTK_PIZZA(widget);
c2fa61e8 69
67b73b9a
MR
70 gtk_paint_shadow (widget->style,
71 pizza->bin_window,
72 GTK_STATE_NORMAL,
73 GTK_SHADOW_OUT,
74 NULL, NULL, NULL, // FIXME: No clipping?
75 0, 0,
76 win->m_width, win->m_height);
b9a535f5 77
00e4ffbc 78 int style = win->GetWindowStyle();
b41b2a05 79
85a0a12a
RR
80 wxClientDC dc(win);
81 // Hack alert
82 dc.m_window = pizza->bin_window;
b41b2a05 83
85a0a12a
RR
84 if (style & wxRESIZE_BORDER)
85 {
86 dc.SetBrush( *wxGREY_BRUSH );
87 dc.SetPen( *wxTRANSPARENT_PEN );
88 dc.DrawRectangle( win->m_width - 14, win->m_height-14, 14, 14 );
89 }
90
340bfb43 91 if (!win->GetTitle().empty() &&
00e4ffbc
RR
92 ((style & wxCAPTION) ||
93 (style & wxTINY_CAPTION_HORIZ) ||
94 (style & wxTINY_CAPTION_VERT)))
b9a535f5 95 {
ba718523
RR
96 dc.SetFont( *wxSMALL_FONT );
97 int height = dc.GetCharHeight();
340bfb43 98
6d976005
RR
99 wxBrush brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT) ) );
100 dc.SetBrush( brush );
101 dc.SetPen( *wxTRANSPARENT_PEN );
1ed6bbc2 102 dc.DrawRectangle( 3, 3, win->m_width - 7, height );
ba718523 103
ba718523
RR
104 dc.SetTextForeground( *wxWHITE );
105 dc.DrawText( win->GetTitle(), 6, 3 );
00e4ffbc
RR
106
107 if (style & wxCLOSE_BOX)
108 dc.DrawBitmap( win->m_closeButton, win->m_width-19, 3, true );
b9a535f5 109 }
32a95f9f 110}
865bb325 111}
32a95f9f 112
32a95f9f
RR
113//-----------------------------------------------------------------------------
114// "button_press_event" of m_mainWidget
115//-----------------------------------------------------------------------------
116
865bb325 117extern "C" {
32a95f9f
RR
118static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
119{
14819684 120 // don't need to install idle handler, its done from "event" signal
acfd422a 121
a2053b27 122 if (!win->m_hasVMT) return FALSE;
32a95f9f
RR
123 if (g_blockEventsOnDrag) return TRUE;
124 if (g_blockEventsOnScroll) return TRUE;
125
126 if (win->m_isDragging) return TRUE;
127
2c990ec0
RR
128 GtkPizza *pizza = GTK_PIZZA(widget);
129 if (gdk_event->window != pizza->bin_window) return TRUE;
ba718523 130
85a0a12a
RR
131 int style = win->GetWindowStyle();
132
00e4ffbc
RR
133 int y = (int)gdk_event->y;
134 int x = (int)gdk_event->x;
b41b2a05 135
85a0a12a
RR
136 if ((style & wxRESIZE_BORDER) &&
137 (x > win->m_width-14) && (y > win->m_height-14))
138 {
139 GtkWidget *ancestor = gtk_widget_get_toplevel( widget );
140
141 GdkWindow *source = GTK_PIZZA(widget)->bin_window;
142
143 int org_x = 0;
144 int org_y = 0;
145 gdk_window_get_origin( source, &org_x, &org_y );
146
147 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
148 GDK_WINDOW_EDGE_SOUTH_EAST,
149 1,
150 org_x + x,
151 org_y + y,
152 0);
b41b2a05 153
85a0a12a
RR
154 return TRUE;
155 }
00e4ffbc 156
00e4ffbc
RR
157 if ((style & wxCLOSE_BOX) &&
158 ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT)))
159 {
160 if ((y > 3) && (y < 19) && (x > win->m_width-19) && (x < win->m_width-3))
161 {
162 win->Close();
163 return TRUE;
164 }
165 }
b41b2a05 166
ba718523
RR
167 wxClientDC dc(win);
168 dc.SetFont( *wxSMALL_FONT );
169 int height = dc.GetCharHeight() + 1;
340bfb43 170
00e4ffbc
RR
171
172 if (y > height) return TRUE;
340bfb43 173
4dcaf11a 174 gdk_window_raise( win->m_widget->window );
c2fa61e8 175
32a95f9f
RR
176 gdk_pointer_grab( widget->window, FALSE,
177 (GdkEventMask)
178 (GDK_BUTTON_PRESS_MASK |
179 GDK_BUTTON_RELEASE_MASK |
f03fc89f 180 GDK_POINTER_MOTION_MASK |
32a95f9f 181 GDK_POINTER_MOTION_HINT_MASK |
f03fc89f 182 GDK_BUTTON_MOTION_MASK |
32a95f9f
RR
183 GDK_BUTTON1_MOTION_MASK),
184 (GdkWindow *) NULL,
185 (GdkCursor *) NULL,
7941ba11 186 (unsigned int) GDK_CURRENT_TIME );
c2fa61e8 187
00e4ffbc
RR
188 win->m_diffX = x;
189 win->m_diffY = y;
32a95f9f
RR
190 win->m_oldX = 0;
191 win->m_oldY = 0;
c2fa61e8 192
340bfb43 193 win->m_isDragging = true;
32a95f9f
RR
194
195 return TRUE;
196}
865bb325 197}
32a95f9f
RR
198
199//-----------------------------------------------------------------------------
200// "button_release_event" of m_mainWidget
201//-----------------------------------------------------------------------------
202
865bb325 203extern "C" {
32a95f9f
RR
204static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
205{
14819684 206 // don't need to install idle handler, its done from "event" signal
acfd422a 207
a2053b27 208 if (!win->m_hasVMT) return FALSE;
32a95f9f
RR
209 if (g_blockEventsOnDrag) return TRUE;
210 if (g_blockEventsOnScroll) return TRUE;
211
212 if (!win->m_isDragging) return TRUE;
c2fa61e8 213
11dbb4bf 214 win->m_isDragging = false;
c2fa61e8 215
32a95f9f
RR
216 int x = (int)gdk_event->x;
217 int y = (int)gdk_event->y;
c2fa61e8 218
13111b2a 219 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
c2fa61e8 220 int org_x = 0;
32a95f9f
RR
221 int org_y = 0;
222 gdk_window_get_origin( widget->window, &org_x, &org_y );
223 x += org_x - win->m_diffX;
224 y += org_y - win->m_diffY;
121a3581
RR
225 win->m_x = x;
226 win->m_y = y;
9adb9063 227 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
32a95f9f
RR
228
229 return TRUE;
230}
865bb325 231}
32a95f9f 232
85a0a12a
RR
233//-----------------------------------------------------------------------------
234// "leave_notify_event" of m_mainWidget
235//-----------------------------------------------------------------------------
236
237extern "C" {
238static gboolean
239gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxMiniFrame *win )
240{
14819684 241 // don't need to install idle handler, its done from "event" signal
85a0a12a
RR
242
243 if (!win->m_hasVMT) return FALSE;
244 if (g_blockEventsOnDrag) return FALSE;
245
246 gdk_window_set_cursor( widget->window, NULL );
b41b2a05 247
85a0a12a
RR
248 return FALSE;
249}
250}
251
32a95f9f
RR
252//-----------------------------------------------------------------------------
253// "motion_notify_event" of m_mainWidget
254//-----------------------------------------------------------------------------
255
865bb325 256extern "C" {
b41b2a05 257static gint
85a0a12a 258gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxMiniFrame *win )
32a95f9f 259{
14819684 260 // don't need to install idle handler, its done from "event" signal
acfd422a 261
a2053b27 262 if (!win->m_hasVMT) return FALSE;
32a95f9f
RR
263 if (g_blockEventsOnDrag) return TRUE;
264 if (g_blockEventsOnScroll) return TRUE;
265
32a95f9f
RR
266 if (gdk_event->is_hint)
267 {
268 int x = 0;
269 int y = 0;
270 GdkModifierType state;
271 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
272 gdk_event->x = x;
273 gdk_event->y = y;
274 gdk_event->state = state;
275 }
276
85a0a12a 277 int style = win->GetWindowStyle();
b41b2a05 278
d02d8b4c
RR
279 int x = (int)gdk_event->x;
280 int y = (int)gdk_event->y;
b41b2a05 281
85a0a12a
RR
282 if (!win->m_isDragging)
283 {
284 if (style & wxRESIZE_BORDER)
285 {
286 if ((x > win->m_width-14) && (y > win->m_height-14))
287 gdk_window_set_cursor( widget->window, gdk_cursor_new( GDK_BOTTOM_RIGHT_CORNER ) );
288 else
289 gdk_window_set_cursor( widget->window, NULL );
290 }
291 return TRUE;
292 }
b41b2a05 293
85a0a12a
RR
294 win->m_oldX = x - win->m_diffX;
295 win->m_oldY = y - win->m_diffY;
296
d02d8b4c
RR
297 int org_x = 0;
298 int org_y = 0;
299 gdk_window_get_origin( widget->window, &org_x, &org_y );
300 x += org_x - win->m_diffX;
301 y += org_y - win->m_diffY;
302 win->m_x = x;
303 win->m_y = y;
304 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
305
c2fa61e8 306
32a95f9f
RR
307 return TRUE;
308}
865bb325 309}
32a95f9f 310
b2b3ccc5
RR
311//-----------------------------------------------------------------------------
312// wxMiniFrame
313//-----------------------------------------------------------------------------
314
00e4ffbc
RR
315static unsigned char close_bits[]={
316 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
317 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
318 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
319
5d5b3a40 320
b2b3ccc5
RR
321IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame,wxFrame)
322
323bool wxMiniFrame::Create( wxWindow *parent, wxWindowID id, const wxString &title,
324 const wxPoint &pos, const wxSize &size,
325 long style, const wxString &name )
326{
2c990ec0 327 style = style | wxCAPTION;
b9a535f5
RR
328
329 if ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT))
00e4ffbc 330 m_miniTitle = 16;
c2fa61e8 331
6d976005 332 if (style & wxRESIZE_BORDER)
85a0a12a 333 m_miniEdge = 4;
6d976005
RR
334 else
335 m_miniEdge = 3;
340bfb43 336 m_isDragging = false;
b2b3ccc5
RR
337 m_oldX = -1;
338 m_oldY = -1;
339 m_diffX = 0;
340 m_diffY = 0;
c2fa61e8 341
b2b3ccc5
RR
342 wxFrame::Create( parent, id, title, pos, size, style, name );
343
2c990ec0
RR
344 if (m_parent && (GTK_IS_WINDOW(m_parent->m_widget)))
345 {
346 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
347 }
340bfb43 348
00e4ffbc 349 if ((style & wxCLOSE_BOX) &&
b9a535f5
RR
350 ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT)))
351 {
00e4ffbc 352 wxImage img = wxBitmap((const char*)close_bits, 16, 16).ConvertToImage();
c4d39711 353 img.Replace(0,0,0,123,123,123);
00e4ffbc
RR
354 img.SetMaskColour(123,123,123);
355 m_closeButton = wxBitmap( img );
b9a535f5 356 }
c2fa61e8 357
32a95f9f 358 /* these are called when the borders are drawn */
9fa72bd2
MR
359 g_signal_connect (m_mainWidget, "expose_event",
360 G_CALLBACK (gtk_window_own_expose_callback), this );
b2b3ccc5 361
32a95f9f 362 /* these are required for dragging the mini frame around */
9fa72bd2
MR
363 g_signal_connect (m_mainWidget, "button_press_event",
364 G_CALLBACK (gtk_window_button_press_callback), this);
365 g_signal_connect (m_mainWidget, "button_release_event",
366 G_CALLBACK (gtk_window_button_release_callback), this);
367 g_signal_connect (m_mainWidget, "motion_notify_event",
368 G_CALLBACK (gtk_window_motion_notify_callback), this);
85a0a12a
RR
369 g_signal_connect (m_mainWidget, "leave_notify_event",
370 G_CALLBACK (gtk_window_leave_callback), this);
340bfb43 371 return true;
b2b3ccc5 372}
dcf924a3 373
400be137
RR
374void wxMiniFrame::SetTitle( const wxString &title )
375{
376 wxFrame::SetTitle( title );
340bfb43 377
c67e060d
RR
378 if (GTK_PIZZA(m_mainWidget)->bin_window)
379 gdk_window_invalidate_rect( GTK_PIZZA(m_mainWidget)->bin_window, NULL, true );
400be137
RR
380}
381
11dbb4bf 382#endif // wxUSE_MINIFRAME