~brian-sidebotham/wxwidgets-cmake/wxpython-2.9.4

« back to all changes in this revision

Viewing changes to src/gtk/minifram.cpp

  • Committer: Brian Sidebotham
  • Date: 2013-08-03 14:30:08 UTC
  • Revision ID: brian.sidebotham@gmail.com-20130803143008-c7806tkych1tp6fc
Initial import into Bazaar

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/////////////////////////////////////////////////////////////////////////////
 
2
// Name:        src/gtk/minifram.cpp
 
3
// Purpose:
 
4
// Author:      Robert Roebling
 
5
// Id:          $Id: minifram.cpp 71894 2012-06-30 20:39:06Z PC $
 
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
#ifdef __WXGTK3__
 
24
#include "wx/gtk/dc.h"
 
25
#else
 
26
#include "wx/gtk/dcclient.h"
 
27
#endif
 
28
 
 
29
#include <gtk/gtk.h>
 
30
#include "wx/gtk/private/gtk2-compat.h"
 
31
 
 
32
//-----------------------------------------------------------------------------
 
33
// data
 
34
//-----------------------------------------------------------------------------
 
35
 
 
36
extern bool        g_blockEventsOnDrag;
 
37
extern bool        g_blockEventsOnScroll;
 
38
 
 
39
//-----------------------------------------------------------------------------
 
40
// "expose_event" of m_mainWidget
 
41
//-----------------------------------------------------------------------------
 
42
 
 
43
// StepColour() it a utility function that simply darkens
 
44
// or lightens a color, based on the specified percentage
 
45
static wxColor StepColour(const wxColor& c, int percent)
 
46
{
 
47
    int r = c.Red(), g = c.Green(), b = c.Blue();
 
48
    return wxColour((unsigned char)wxMin((r*percent)/100,255),
 
49
                    (unsigned char)wxMin((g*percent)/100,255),
 
50
                    (unsigned char)wxMin((b*percent)/100,255));
 
51
}
 
52
 
 
53
static wxColor LightContrastColour(const wxColour& c)
 
54
{
 
55
    int amount = 120;
 
56
 
 
57
    // if the color is especially dark, then
 
58
    // make the contrast even lighter
 
59
    if (c.Red() < 128 && c.Green() < 128 && c.Blue() < 128)
 
60
        amount = 160;
 
61
 
 
62
    return StepColour(c, amount);
 
63
}
 
64
 
 
65
extern "C" {
 
66
#ifdef __WXGTK3__
 
67
static gboolean draw(GtkWidget* widget, cairo_t* cr, wxMiniFrame* win)
 
68
#else
 
69
static gboolean expose_event(GtkWidget* widget, GdkEventExpose* gdk_event, wxMiniFrame* win)
 
70
#endif
 
71
{
 
72
#ifdef __WXGTK3__
 
73
    if (!gtk_cairo_should_draw_window(cr, gtk_widget_get_window(widget)))
 
74
        return false;
 
75
 
 
76
    GtkStyleContext* sc = gtk_widget_get_style_context(widget);
 
77
    gtk_style_context_save(sc);
 
78
    gtk_style_context_add_class(sc, GTK_STYLE_CLASS_BUTTON);
 
79
    gtk_render_frame(sc, cr, 0, 0, win->m_width, win->m_height);
 
80
    gtk_style_context_restore(sc);
 
81
 
 
82
    wxGTKCairoDC dc(cr);
 
83
#else
 
84
    if (!win->m_hasVMT || gdk_event->count > 0 ||
 
85
        gdk_event->window != gtk_widget_get_window(widget))
 
86
    {
 
87
        return false;
 
88
    }
 
89
 
 
90
    gtk_paint_shadow (gtk_widget_get_style(widget),
 
91
                      gtk_widget_get_window(widget),
 
92
                      GTK_STATE_NORMAL,
 
93
                      GTK_SHADOW_OUT,
 
94
                      NULL, NULL, NULL, // FIXME: No clipping?
 
95
                      0, 0,
 
96
                      win->m_width, win->m_height);
 
97
 
 
98
    wxClientDC dc(win);
 
99
 
 
100
    wxDCImpl *impl = dc.GetImpl();
 
101
    wxClientDCImpl *gtk_impl = wxDynamicCast( impl, wxClientDCImpl );
 
102
    gtk_impl->m_gdkwindow = gtk_widget_get_window(widget); // Hack alert
 
103
#endif
 
104
 
 
105
    int style = win->GetWindowStyle();
 
106
 
 
107
#ifndef __WXGTK3__
 
108
    if (style & wxRESIZE_BORDER)
 
109
    {
 
110
        dc.SetBrush( *wxGREY_BRUSH );
 
111
        dc.SetPen( *wxTRANSPARENT_PEN );
 
112
        dc.DrawRectangle( win->m_width - 14, win->m_height-14, 14, 14 );
 
113
    }
 
114
#endif
 
115
 
 
116
    if (win->m_miniTitle && !win->GetTitle().empty())
 
117
    {
 
118
        dc.SetFont( *wxSMALL_FONT );
 
119
 
 
120
        wxBrush brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT) ) );
 
121
        dc.SetBrush( brush );
 
122
        dc.SetPen( *wxTRANSPARENT_PEN );
 
123
        dc.DrawRectangle( win->m_miniEdge-1,
 
124
                          win->m_miniEdge-1,
 
125
                          win->m_width - (2*(win->m_miniEdge-1)),
 
126
                          15  );
 
127
 
 
128
        dc.SetTextForeground( *wxWHITE );
 
129
        dc.DrawText( win->GetTitle(), 6, 4 );
 
130
 
 
131
        if (style & wxCLOSE_BOX)
 
132
            dc.DrawBitmap( win->m_closeButton, win->m_width-18, 3, true );
 
133
    }
 
134
 
 
135
    return false;
 
136
}
 
137
}
 
138
 
 
139
//-----------------------------------------------------------------------------
 
140
// "button_press_event" of m_mainWidget
 
141
//-----------------------------------------------------------------------------
 
142
 
 
143
extern "C" {
 
144
static gboolean
 
145
gtk_window_button_press_callback(GtkWidget* widget, GdkEventButton* gdk_event, wxMiniFrame* win)
 
146
{
 
147
    if (!win->m_hasVMT || gdk_event->window != gtk_widget_get_window(widget))
 
148
        return false;
 
149
    if (g_blockEventsOnDrag) return TRUE;
 
150
    if (g_blockEventsOnScroll) return TRUE;
 
151
 
 
152
    if (win->m_isDragging) return TRUE;
 
153
 
 
154
    int style = win->GetWindowStyle();
 
155
 
 
156
    int y = (int)gdk_event->y;
 
157
    int x = (int)gdk_event->x;
 
158
 
 
159
#ifndef __WXGTK3__
 
160
    if ((style & wxRESIZE_BORDER) &&
 
161
        (x > win->m_width-14) && (y > win->m_height-14))
 
162
    {
 
163
        GtkWidget *ancestor = gtk_widget_get_toplevel( widget );
 
164
 
 
165
        GdkWindow *source = gtk_widget_get_window(widget);
 
166
 
 
167
        int org_x = 0;
 
168
        int org_y = 0;
 
169
        gdk_window_get_origin( source, &org_x, &org_y );
 
170
 
 
171
        gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
 
172
                                  GDK_WINDOW_EDGE_SOUTH_EAST,
 
173
                                  1,
 
174
                                  org_x + x,
 
175
                                  org_y + y,
 
176
                                  0);
 
177
 
 
178
        return TRUE;
 
179
    }
 
180
#endif
 
181
 
 
182
    if (win->m_miniTitle && (style & wxCLOSE_BOX))
 
183
    {
 
184
        if ((y > 3) && (y < 19) && (x > win->m_width-19) && (x < win->m_width-3))
 
185
        {
 
186
            win->Close();
 
187
            return TRUE;
 
188
        }
 
189
    }
 
190
 
 
191
    if (y >= win->m_miniEdge + win->m_miniTitle)
 
192
        return true;
 
193
 
 
194
    gdk_window_raise(gtk_widget_get_window(win->m_widget));
 
195
 
 
196
    gdk_pointer_grab( gtk_widget_get_window(widget), false,
 
197
                      (GdkEventMask)
 
198
                         (GDK_BUTTON_PRESS_MASK |
 
199
                          GDK_BUTTON_RELEASE_MASK |
 
200
                          GDK_POINTER_MOTION_MASK        |
 
201
                          GDK_POINTER_MOTION_HINT_MASK  |
 
202
                          GDK_BUTTON_MOTION_MASK        |
 
203
                          GDK_BUTTON1_MOTION_MASK),
 
204
                      NULL,
 
205
                      NULL,
 
206
                      (unsigned int) GDK_CURRENT_TIME );
 
207
 
 
208
    win->m_diffX = x;
 
209
    win->m_diffY = y;
 
210
    win->m_oldX = 0;
 
211
    win->m_oldY = 0;
 
212
 
 
213
    win->m_isDragging = true;
 
214
 
 
215
    return TRUE;
 
216
}
 
217
}
 
218
 
 
219
//-----------------------------------------------------------------------------
 
220
// "button_release_event" of m_mainWidget
 
221
//-----------------------------------------------------------------------------
 
222
 
 
223
extern "C" {
 
224
static gboolean
 
225
gtk_window_button_release_callback(GtkWidget* widget, GdkEventButton* gdk_event, wxMiniFrame* win)
 
226
{
 
227
    if (!win->m_hasVMT || gdk_event->window != gtk_widget_get_window(widget))
 
228
        return false;
 
229
    if (g_blockEventsOnDrag) return TRUE;
 
230
    if (g_blockEventsOnScroll) return TRUE;
 
231
    if (!win->m_isDragging) return TRUE;
 
232
 
 
233
    win->m_isDragging = false;
 
234
 
 
235
    int x = (int)gdk_event->x;
 
236
    int y = (int)gdk_event->y;
 
237
 
 
238
    gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
 
239
    int org_x = 0;
 
240
    int org_y = 0;
 
241
    gdk_window_get_origin(gtk_widget_get_window(widget), &org_x, &org_y);
 
242
    x += org_x - win->m_diffX;
 
243
    y += org_y - win->m_diffY;
 
244
    win->m_x = x;
 
245
    win->m_y = y;
 
246
    gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
 
247
 
 
248
    return TRUE;
 
249
}
 
250
}
 
251
 
 
252
//-----------------------------------------------------------------------------
 
253
// "leave_notify_event" of m_mainWidget
 
254
//-----------------------------------------------------------------------------
 
255
 
 
256
extern "C" {
 
257
static gboolean
 
258
gtk_window_leave_callback(GtkWidget *widget,
 
259
                          GdkEventCrossing* gdk_event,
 
260
                          wxMiniFrame *win)
 
261
{
 
262
    if (!win->m_hasVMT) return FALSE;
 
263
    if (g_blockEventsOnDrag) return FALSE;
 
264
    if (gdk_event->window != gtk_widget_get_window(widget))
 
265
        return false;
 
266
 
 
267
    gdk_window_set_cursor(gtk_widget_get_window(widget), NULL);
 
268
 
 
269
    return FALSE;
 
270
}
 
271
}
 
272
 
 
273
//-----------------------------------------------------------------------------
 
274
// "motion_notify_event" of m_mainWidget
 
275
//-----------------------------------------------------------------------------
 
276
 
 
277
extern "C" {
 
278
static gboolean
 
279
gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxMiniFrame *win )
 
280
{
 
281
    if (!win->m_hasVMT || gdk_event->window != gtk_widget_get_window(widget))
 
282
        return false;
 
283
    if (g_blockEventsOnDrag) return TRUE;
 
284
    if (g_blockEventsOnScroll) return TRUE;
 
285
 
 
286
    if (gdk_event->is_hint)
 
287
    {
 
288
       int x = 0;
 
289
       int y = 0;
 
290
       GdkModifierType state;
 
291
       gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
 
292
       gdk_event->x = x;
 
293
       gdk_event->y = y;
 
294
       gdk_event->state = state;
 
295
    }
 
296
 
 
297
    int x = (int)gdk_event->x;
 
298
    int y = (int)gdk_event->y;
 
299
 
 
300
    if (!win->m_isDragging)
 
301
    {
 
302
#ifndef __WXGTK3__
 
303
        if (win->GetWindowStyle() & wxRESIZE_BORDER)
 
304
        {
 
305
            if ((x > win->m_width-14) && (y > win->m_height-14))
 
306
               gdk_window_set_cursor(gtk_widget_get_window(widget), gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER));
 
307
            else
 
308
               gdk_window_set_cursor(gtk_widget_get_window(widget), NULL);
 
309
            win->GTKUpdateCursor(false);
 
310
        }
 
311
#endif
 
312
        return TRUE;
 
313
    }
 
314
 
 
315
    win->m_oldX = x - win->m_diffX;
 
316
    win->m_oldY = y - win->m_diffY;
 
317
 
 
318
    int org_x = 0;
 
319
    int org_y = 0;
 
320
    gdk_window_get_origin(gtk_widget_get_window(widget), &org_x, &org_y);
 
321
    x += org_x - win->m_diffX;
 
322
    y += org_y - win->m_diffY;
 
323
    win->m_x = x;
 
324
    win->m_y = y;
 
325
    gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
 
326
 
 
327
    return TRUE;
 
328
}
 
329
}
 
330
 
 
331
//-----------------------------------------------------------------------------
 
332
// wxMiniFrame
 
333
//-----------------------------------------------------------------------------
 
334
 
 
335
static unsigned char close_bits[]={
 
336
    0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
 
337
    0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
 
338
    0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
339
 
 
340
 
 
341
IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame,wxFrame)
 
342
 
 
343
bool wxMiniFrame::Create( wxWindow *parent, wxWindowID id, const wxString &title,
 
344
      const wxPoint &pos, const wxSize &size,
 
345
      long style, const wxString &name )
 
346
{
 
347
    m_miniTitle = 0;
 
348
    if (style & wxCAPTION)
 
349
        m_miniTitle = 16;
 
350
 
 
351
    if (style & wxRESIZE_BORDER)
 
352
        m_miniEdge = 4;
 
353
    else
 
354
        m_miniEdge = 3;
 
355
    m_isDragging = false;
 
356
    m_oldX = -1;
 
357
    m_oldY = -1;
 
358
    m_diffX = 0;
 
359
    m_diffY = 0;
 
360
 
 
361
    // don't allow sizing smaller than decorations
 
362
    int minWidth = 2 * m_miniEdge;
 
363
    int minHeight = 2 * m_miniEdge + m_miniTitle;
 
364
    if (m_minWidth < minWidth)
 
365
        m_minWidth = minWidth;
 
366
    if (m_minHeight < minHeight)
 
367
        m_minHeight = minHeight;
 
368
 
 
369
    wxFrame::Create( parent, id, title, pos, size, style, name );
 
370
 
 
371
    // Use a GtkEventBox for the title and borders. Using m_widget for this
 
372
    // almost works, except that setting the resize cursor has no effect.
 
373
    GtkWidget* eventbox = gtk_event_box_new();
 
374
    gtk_widget_add_events(eventbox,
 
375
        GDK_POINTER_MOTION_MASK |
 
376
        GDK_POINTER_MOTION_HINT_MASK);
 
377
    gtk_widget_show(eventbox);
 
378
    // Use a GtkAlignment to position m_mainWidget inside the decorations
 
379
    GtkWidget* alignment = gtk_alignment_new(0, 0, 1, 1);
 
380
    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment),
 
381
        m_miniTitle + m_miniEdge, m_miniEdge, m_miniEdge, m_miniEdge);
 
382
    gtk_widget_show(alignment);
 
383
    // The GtkEventBox and GtkAlignment go between m_widget and m_mainWidget
 
384
    gtk_widget_reparent(m_mainWidget, alignment);
 
385
    gtk_container_add(GTK_CONTAINER(eventbox), alignment);
 
386
    gtk_container_add(GTK_CONTAINER(m_widget), eventbox);
 
387
 
 
388
    m_gdkDecor = 0;
 
389
    m_gdkFunc = 0;
 
390
    if (style & wxRESIZE_BORDER)
 
391
       m_gdkFunc = GDK_FUNC_RESIZE;
 
392
    gtk_window_set_default_size(GTK_WINDOW(m_widget), m_width, m_height);
 
393
    m_decorSize.Set(0, 0);
 
394
    m_deferShow = false;
 
395
 
 
396
    if (m_parent && (GTK_IS_WINDOW(m_parent->m_widget)))
 
397
    {
 
398
        gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
 
399
    }
 
400
 
 
401
    if (m_miniTitle && (style & wxCLOSE_BOX))
 
402
    {
 
403
        wxImage img = wxBitmap((const char*)close_bits, 16, 16).ConvertToImage();
 
404
        img.Replace(0,0,0,123,123,123);
 
405
        img.SetMaskColour(123,123,123);
 
406
        m_closeButton = wxBitmap( img );
 
407
    }
 
408
 
 
409
    /* these are called when the borders are drawn */
 
410
#ifdef __WXGTK3__
 
411
    g_signal_connect_after(eventbox, "draw", G_CALLBACK(draw), this);
 
412
#else
 
413
    g_signal_connect_after(eventbox, "expose_event", G_CALLBACK(expose_event), this);
 
414
#endif
 
415
 
 
416
    /* these are required for dragging the mini frame around */
 
417
    g_signal_connect (eventbox, "button_press_event",
 
418
                      G_CALLBACK (gtk_window_button_press_callback), this);
 
419
    g_signal_connect (eventbox, "button_release_event",
 
420
                      G_CALLBACK (gtk_window_button_release_callback), this);
 
421
    g_signal_connect (eventbox, "motion_notify_event",
 
422
                      G_CALLBACK (gtk_window_motion_notify_callback), this);
 
423
    g_signal_connect (eventbox, "leave_notify_event",
 
424
                      G_CALLBACK (gtk_window_leave_callback), this);
 
425
    return true;
 
426
}
 
427
 
 
428
void wxMiniFrame::DoGetClientSize(int* width, int* height) const
 
429
{
 
430
    wxFrame::DoGetClientSize(width, height);
 
431
    if (width)
 
432
    {
 
433
        *width -= 2 * m_miniEdge;
 
434
        if (*width < 0) *width = 0;
 
435
    }
 
436
    if (height)
 
437
    {
 
438
        *height -= m_miniTitle + 2 * m_miniEdge;
 
439
        if (*height < 0) *height = 0;
 
440
    }
 
441
}
 
442
 
 
443
// Keep min size at least as large as decorations
 
444
void wxMiniFrame::DoSetSizeHints(int minW, int minH, int maxW, int maxH, int incW, int incH)
 
445
{
 
446
    const int w = 2 * m_miniEdge;
 
447
    const int h = 2 * m_miniEdge + m_miniTitle;
 
448
    if (minW < w) minW = w;
 
449
    if (minH < h) minH = h;
 
450
    wxFrame::DoSetSizeHints(minW, minH, maxW, maxH, incW, incH);
 
451
}
 
452
 
 
453
void wxMiniFrame::SetTitle( const wxString &title )
 
454
{
 
455
    wxFrame::SetTitle( title );
 
456
 
 
457
    GdkWindow* window = gtk_widget_get_window(gtk_bin_get_child(GTK_BIN(m_widget)));
 
458
    if (window)
 
459
        gdk_window_invalidate_rect(window, NULL, false);
 
460
}
 
461
 
 
462
#endif // wxUSE_MINIFRAME