// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
-#ifdef __WXGTK24__
+#if wxUSE_COLLPANE && defined(__WXGTK24__) && !defined(__WXUNIVERSAL__)
#include "wx/collpane.h"
+#include "wx/toplevel.h"
+#include "wx/sizer.h"
+#include "wx/panel.h"
-#include <gtk/gtkexpander.h>
-#include <gtk/gtk.h>
+#include "wx/gtk/private.h"
+#include "wx/gtk/win_gtk.h"
-const wxChar wxCollapsiblePaneNameStr[] = wxT("CollapsiblePane");
+#include <gtk/gtkexpander.h>
// ============================================================================
// implementation
wxSize sz;
if ( p->IsExpanded() )
{
- // unfortunately there's no clean way to retrieve the minimal size of
- // the expanded pane in this handler or in other handlers for the
- // signals generated by user clicks on the GtkExpander button:
- // p->GetBestSize() or p->GetMinSize() would still return the size for
- // the collapsed expander even if the collapsed->expanded transition
- // has already been completed (this because GTK+ queues some resize
- // calls which still must be processed). So, the only solution to
- // correctly set the size hints for this window is to calculate the
- // expanded size ourselves, without relying on p->Get[Best|Min]Size:
- sz = p->GetMinSize();
- sz.SetWidth(wxMax(sz.x, p->GetPane()->GetMinSize().x));
- sz.SetHeight(sz.y + p->GetPane()->GetMinSize().y + 10);
+ // NB: we cannot use the p->GetBestSize() or p->GetMinSize() functions
+ // here as they would return the size for the collapsed expander
+ // even if the collapsed->expanded transition has already been
+ // completed; we solve this problem doing:
+
+ sz = p->m_szCollapsed;
+
+ wxSize panesz = p->GetPane()->GetBestSize();
+ sz.x = wxMax(sz.x, panesz.x);
+ sz.y += gtk_expander_get_spacing(GTK_EXPANDER(p->m_widget)) + panesz.y;
}
else // collapsed
{
sz = p->m_szCollapsed;
}
- // minimal size has priority over the best size so set here our min size
+ // VERY IMPORTANT:
+ // just calling
+ // p->OnStateChange(sz);
+ // here would work work BUT:
+ // 1) in the expanded->collapsed transition it provokes a lot of flickering
+ // 2) in the collapsed->expanded transition using the "Change status" wxButton
+ // in samples/collpane application some strange warnings would be generated
+ // by the "clearlooks" theme, if that's your theme.
+ //
+ // So we prefer to use some GTK+ native optimized calls, which prevent too many resize
+ // calculations to happen. Note that the following code has been very carefully designed
+ // and tested - be VERY careful when changing it!
+
+ // 1) need to update our size hints
+ // NB: this function call won't actually do any long operation
+ // (redraw/relayouting/resizing) so that it's flicker-free
p->SetMinSize(sz);
- p->SetSize(sz);
- wxWindow *top = p->GetTopLevelParent();
- if (top)
+ if (p->HasFlag(wxCP_NO_TLW_RESIZE))
+ {
+ // fire an event
+ wxCollapsiblePaneEvent ev(p, p->GetId(), p->IsCollapsed());
+ p->GetEventHandler()->ProcessEvent(ev);
+
+ // the user asked to explicitely handle the resizing itself...
+ return;
+ }
+
+ wxTopLevelWindow *
+ top = wxDynamicCast(wxGetTopLevelParent(p), wxTopLevelWindow);
+ if ( top && top->GetSizer() )
{
- // we've changed our size, thus our top level parent needs to relayout
- // itself
- top->Layout();
+ // 2) recalculate minimal size of the top window
+ wxSize sz = top->GetSizer()->CalcMin();
- if (p->IsExpanded())
- {
- // force our parent to "fit", i.e. expand so that it can honour
- // our minimal size
- top->Fit();
- }
- else // correctly
+ if (top->m_mainWidget)
{
- if (top->GetSizer())
- top->GetSizer()->SetSizeHints(top);
+ // 3) MAGIC HACK: if you ever used GtkExpander in a GTK+ program you know
+ // that this magic call is required to make it possible to shrink the
+ // top level window in the expanded->collapsed transition.
+ // This may be sometimes undesired but *is* necessary and if you look
+ // carefully, all GTK+ programs using GtkExpander perform this trick
+ // (e.g. the standard "open file" dialog of GTK+>=2.4 is not resizeable
+ // when the expander is collapsed!)
+ gtk_window_set_resizable (GTK_WINDOW (top->m_widget), p->IsExpanded());
+
+ // 4) set size hints: note that this code has been taken and adapted
+ // from src/gtk/toplevel.cpp
+ GdkGeometry geom;
+
+ geom.min_width = sz.x;
+ geom.min_height = sz.y;
+
+ gtk_window_set_geometry_hints( GTK_WINDOW(top->m_widget),
+ (GtkWidget*) NULL,
+ &geom,
+ GDK_HINT_MIN_SIZE );
+
+ // 5) set size: also this code has been adapted from src/gtk/toplevel.cpp
+ // to do the size changes immediately and not delaying them in the idle
+ // time
+ top->m_width = sz.x;
+ top->m_height = sz.y;
+
+ int client_x = top->m_miniEdge;
+ int client_y = top->m_miniEdge + top->m_miniTitle;
+ int client_w = top->m_width - 2*top->m_miniEdge;
+ int client_h = top->m_height - 2*top->m_miniEdge - top->m_miniTitle;
+ if (client_w < 0)
+ client_w = 0;
+ if (client_h < 0)
+ client_h = 0;
+
+ gtk_pizza_set_size( GTK_PIZZA(top->m_mainWidget),
+ top->m_wxwindow,
+ client_x, client_y, client_w, client_h );
+
+ gtk_widget_set_size_request( top->m_wxwindow, sz.x, sz.y );
- // use SetClientSize() and not SetSize() otherwise the size for
- // e.g. a wxFrame with a menubar wouldn't be correctly set
- top->SetClientSize(sz);
}
}
return wxGenericCollapsiblePane::Create(parent, id, label,
pos, size, style, val, name);
- m_needParent = true;
- m_acceptsFocus = true;
m_bIgnoreNextChange = false;
if ( !PreCreation( parent, pos, size ) ||
m_insertCallback = gtk_collapsiblepane_insert_callback;
// this the real "pane"
- m_pPane = new wxWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
- wxNO_BORDER);
+ m_pPane = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
+ wxTAB_TRAVERSAL|wxNO_BORDER);
- gtk_widget_show( GTK_WIDGET(m_widget) );
+ gtk_widget_show(m_widget);
m_parent->DoAddChild( this );
PostCreation(size);
(m_widget, &req );
// notice that we do not cache our best size here as it changes
+ // all times the user expands/hide our pane
return wxSize(req.width, req.height);
}
void wxCollapsiblePane::SetLabel(const wxString &str)
{
if (!gtk_check_version(2,4,0))
- gtk_expander_set_label(GTK_EXPANDER(m_widget), str.c_str());
+ {
+ gtk_expander_set_label(GTK_EXPANDER(m_widget), wxGTK_CONV(str));
+
+ // FIXME: we need to update our collapsed width in some way but using GetBestSize()
+ // we may get the size of the control with the pane size summed up if we are expanded!
+ //m_szCollapsed.x = GetBestSize().x;
+ }
else
wxGenericCollapsiblePane::SetLabel(str);
}
// here we need to resize the pane window otherwise, even if the GtkExpander container
// is expanded or shrinked, the pane window won't be updated!
- m_pPane->SetSize(ev.GetSize());
+ m_pPane->SetSize(ev.GetSize().x, ev.GetSize().y - m_szCollapsed.y);
// we need to explicitely call m_pPane->Layout() or else it won't correctly relayout
// (even if SetAutoLayout(true) has been called on it!)
m_pPane->Layout();
}
-#endif // __WXGTK24__
+#endif // wxUSE_COLLPANE && defined(__WXGTK24__) && !defined(__WXUNIVERSAL__)