1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/gtk/statbox.cpp
3 // Purpose:
4 // Author:      Robert Roebling
5 // Copyright:   (c) 1998 Robert Roebling
6 // Licence:     wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
8 
9 // For compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
11 
12 #if wxUSE_STATBOX
13 
14 #include "wx/statbox.h"
15 
16 #include "wx/gtk/private/wrapgtk.h"
17 #include "wx/gtk/private/win_gtk.h"
18 
19 // constants taken from GTK sources
20 #define LABEL_PAD 1
21 #define LABEL_SIDE_PAD 2
22 
23 //-----------------------------------------------------------------------------
24 // "size_allocate" from m_widget
25 //-----------------------------------------------------------------------------
26 
27 #ifndef __WXGTK3__
28 extern "C" {
size_allocate(GtkWidget * widget,GtkAllocation * alloc,void *)29 static void size_allocate(GtkWidget* widget, GtkAllocation* alloc, void*)
30 {
31     // clip label as GTK >= 2.12 does
32     GtkWidget* label_widget = gtk_frame_get_label_widget(GTK_FRAME(widget));
33     int w = alloc->width -
34         2 * gtk_widget_get_style(widget)->xthickness - 2 * LABEL_PAD - 2 * LABEL_SIDE_PAD;
35     if (w < 0)
36         w = 0;
37 
38     GtkAllocation a;
39     gtk_widget_get_allocation(label_widget, &a);
40     if (a.width > w)
41     {
42         a.width = w;
43         gtk_widget_size_allocate(label_widget, &a);
44     }
45 }
46 
expose_event(GtkWidget * widget,GdkEventExpose *,wxWindow *)47 static gboolean expose_event(GtkWidget* widget, GdkEventExpose*, wxWindow*)
48 {
49     const GtkAllocation& a = widget->allocation;
50     gtk_paint_flat_box(gtk_widget_get_style(widget), gtk_widget_get_window(widget),
51         GTK_STATE_NORMAL, GTK_SHADOW_NONE, NULL, widget, "", a.x, a.y, a.width, a.height);
52     return false;
53 }
54 }
55 #endif
56 
57 //-----------------------------------------------------------------------------
58 // wxStaticBox
59 //-----------------------------------------------------------------------------
60 
DoCreate(wxWindow * parent,wxWindowID id,const wxString * labelStr,wxWindow * labelWin,const wxPoint & pos,const wxSize & size,long style,const wxString & name)61 bool wxStaticBox::DoCreate(wxWindow *parent,
62                            wxWindowID id,
63                            const wxString* labelStr,
64                            wxWindow* labelWin,
65                            const wxPoint& pos,
66                            const wxSize& size,
67                            long style,
68                            const wxString& name)
69 {
70     if (!PreCreation( parent, pos, size ) ||
71         !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
72     {
73         wxFAIL_MSG( wxT("wxStaticBox creation failed") );
74         return false;
75     }
76 
77     if ( labelStr )
78     {
79         m_widget = GTKCreateFrame(*labelStr);
80 
81         // only base SetLabel needs to be called after GTKCreateFrame
82         wxControl::SetLabel(*labelStr);
83     }
84     else // Use the given window as the label.
85     {
86         wxCHECK_MSG( labelWin, false, wxS("Label window can't be null") );
87 
88         GtkWidget* const labelWidget = labelWin->m_widget;
89         wxCHECK_MSG( labelWidget, false, wxS("Label window must be created") );
90 
91         // The widget must not have any parent at GTK+ level or setting it as
92         // label widget would fail.
93         GtkWidget* const oldParent = gtk_widget_get_parent(labelWidget);
94         gtk_container_remove(GTK_CONTAINER(oldParent), labelWidget);
95         gtk_widget_unparent(labelWidget);
96 
97         // It also should be our child at wx API level, but without being our
98         // child in wxGTK, i.e. it must not be added to the GtkFrame container,
99         // so we can't call Reparent() here (not even wxWindowBase version, as
100         // it still would end up in our overridden AddChild()), nor the normal
101         // AddChild() for the same reason.
102         labelWin->GetParent()->RemoveChild(labelWin);
103         wxWindowBase::AddChild(labelWin);
104 
105         m_labelWin = labelWin;
106 
107         m_widget = gtk_frame_new(NULL);
108         gtk_frame_set_label_widget(GTK_FRAME(m_widget), labelWidget);
109     }
110 
111     g_object_ref(m_widget);
112 
113     m_parent->DoAddChild( this );
114 
115     PostCreation(size);
116 
117     // need to set non default alignment?
118     gfloat xalign = 0;
119     if ( style & wxALIGN_CENTER )
120         xalign = 0.5;
121     else if ( style & wxALIGN_RIGHT )
122         xalign = 1.0;
123 
124     gtk_frame_set_label_align(GTK_FRAME(m_widget), xalign, 0.5);
125 
126 #ifndef __WXGTK3__
127     if (!wx_is_at_least_gtk2(12))
128     {
129         // we connect this signal to perform label-clipping as GTK >= 2.12 does
130         g_signal_connect(m_widget, "size_allocate", G_CALLBACK(size_allocate), NULL);
131     }
132 #endif
133 
134     m_container.DisableSelfFocus();
135 
136     return true;
137 }
138 
AddChild(wxWindowBase * child)139 void wxStaticBox::AddChild( wxWindowBase *child )
140 {
141     if (!m_wxwindow)
142     {
143         // make this window a container of other wxWindows by instancing a wxPizza
144         // and packing it into the GtkFrame:
145         m_wxwindow = wxPizza::New();
146         gtk_widget_show( m_wxwindow );
147         gtk_container_add( GTK_CONTAINER (m_widget), m_wxwindow );
148         GTKApplyWidgetStyle();
149     }
150 
151     wxStaticBoxBase::AddChild(child);
152 }
153 
SetLabel(const wxString & label)154 void wxStaticBox::SetLabel( const wxString& label )
155 {
156     wxCHECK_RET( m_widget != NULL, wxT("invalid staticbox") );
157 
158     wxCHECK_RET( !m_labelWin, wxS("Doesn't make sense when using label window") );
159 
160     GTKSetLabelForFrame(GTK_FRAME(m_widget), label);
161 }
162 
DoApplyWidgetStyle(GtkRcStyle * style)163 void wxStaticBox::DoApplyWidgetStyle(GtkRcStyle *style)
164 {
165     GTKFrameApplyWidgetStyle(GTK_FRAME(m_widget), style);
166     if ( m_labelWin )
167         GTKDoApplyWidgetStyle(m_labelWin, style);
168     if (m_wxwindow)
169         GTKApplyStyle(m_wxwindow, style);
170 
171 #ifndef __WXGTK3__
172     g_signal_handlers_disconnect_by_func(m_widget, (void*)expose_event, this);
173     if (m_backgroundColour.IsOk())
174         g_signal_connect(m_widget, "expose-event", G_CALLBACK(expose_event), this);
175 #endif
176 }
177 
GTKWidgetNeedsMnemonic() const178 bool wxStaticBox::GTKWidgetNeedsMnemonic() const
179 {
180     return true;
181 }
182 
GTKWidgetDoSetMnemonic(GtkWidget * w)183 void wxStaticBox::GTKWidgetDoSetMnemonic(GtkWidget* w)
184 {
185     GTKFrameSetMnemonicWidget(GTK_FRAME(m_widget), w);
186 }
187 
188 // static
189 wxVisualAttributes
GetClassDefaultAttributes(wxWindowVariant WXUNUSED (variant))190 wxStaticBox::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
191 {
192     return GetDefaultAttributesFromGTKWidget(gtk_frame_new(""));
193 }
194 
GetBordersForSizer(int * borderTop,int * borderOther) const195 void wxStaticBox::GetBordersForSizer(int *borderTop, int *borderOther) const
196 {
197     GtkWidget* label = gtk_frame_get_label_widget(GTK_FRAME(m_widget));
198 #ifdef __WXGTK3__
199     *borderOther = 0;
200     *borderTop = 0;
201     if (label)
202     {
203         int nat_width;
204         gtk_widget_get_preferred_width(label, NULL, &nat_width);
205         gtk_widget_get_preferred_height_for_width(label, nat_width, borderTop, NULL);
206     }
207 #else
208     gtk_widget_ensure_style(m_widget);
209     const int border_width = GTK_CONTAINER(m_widget)->border_width;
210     *borderOther = border_width + m_widget->style->xthickness;
211     *borderTop = border_width;
212     if (label)
213     {
214         GtkRequisition req;
215         gtk_widget_size_request(label, &req);
216         *borderTop += req.height;
217     }
218     else
219         *borderTop += m_widget->style->ythickness;
220 #endif
221 }
222 
223 #endif // wxUSE_STATBOX
224