From be2577e4e650993fe49f18955972e5360840dad2 Mon Sep 17 00:00:00 2001
From: Robin Dunn <robin@alldunn.com>
Date: Tue, 9 Nov 1999 23:02:41 +0000
Subject: [PATCH] wxSizer patches by Alexander Smishlajev <als@turnhere.com>

    Adds some wxALIGN_* flags to increase ability to position item
    within its allotted space.

    Adds wxSHAPED flag that enforces proportional resizing on growable
    items.

    Adds a sample and updated documentation.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4461 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/latex/wx/boxsizer.tex    |  35 ++---
 docs/latex/wx/sizer.tex       |  11 +-
 include/wx/defs.h             |  14 +-
 include/wx/sizer.h            |  13 ++
 samples/propsize/Makefile.in  |  20 +++
 samples/propsize/makefile.g95 |  16 +++
 samples/propsize/makefile.vc  |  17 +++
 samples/propsize/mondrian.ico | Bin 0 -> 766 bytes
 samples/propsize/mondrian.xpm |  44 ++++++
 samples/propsize/propsize.cpp | 249 ++++++++++++++++++++++++++++++++++
 samples/propsize/propsize.rc  |   5 +
 src/common/sizer.cpp          |  54 ++++++--
 utils/wxPython/demo/Sizers.py |  94 ++++++++++++-
 utils/wxPython/lib/grids.py   |  26 ++--
 utils/wxPython/src/_defs.i    |   9 +-
 15 files changed, 554 insertions(+), 53 deletions(-)
 create mode 100644 samples/propsize/Makefile.in
 create mode 100644 samples/propsize/makefile.g95
 create mode 100644 samples/propsize/makefile.vc
 create mode 100644 samples/propsize/mondrian.ico
 create mode 100644 samples/propsize/mondrian.xpm
 create mode 100644 samples/propsize/propsize.cpp
 create mode 100644 samples/propsize/propsize.rc

diff --git a/docs/latex/wx/boxsizer.tex b/docs/latex/wx/boxsizer.tex
index f00db53148..42a0cf1104 100644
--- a/docs/latex/wx/boxsizer.tex
+++ b/docs/latex/wx/boxsizer.tex
@@ -1,6 +1,6 @@
 \section{\class{wxBoxSizer}}\label{wxboxsizer}
 
-The basic idea behind a box sizer is that windows will most often be laid out in rather 
+The basic idea behind a box sizer is that windows will most often be laid out in rather
 simple basic geomerty, typically in a row or a column or several hierachies of either.
 
 As an exmaple, we will construct a dialog that will contain a text field at the top and
@@ -21,13 +21,16 @@ when adding a window (or another sizer) to a sizer. It is interpreted
 as a weight factor, i.e. it can be zero, indicating that the window may not be resized
 at all, or above zero. If several windows have a value above zero, the value is interpreted
 relative to the sum of all weight factors of the sizer, so when adding two windows with
-a value of 1, they will both get resized equally much and each half as much as the sizer 
+a value of 1, they will both get resized equally much and each half as much as the sizer
 owning them. Then what do we do when a column sizer changes its width? This behaviour is
-controlled by {\it flags} (the second parameter of the Add() function): Zero or no flag indicates that
-the window will get aligned at the left (in a column sizer) and the top (row sizer), whereas
-wxALIGN\_RIGHT and wxALIGN\_BOTTOM will do what they say. The item can also be centered
-using the wxCENTRE flag (same as wxCENTER) or it can be forced to grow with the sizer (using
-the wxGROW flag (same as wxEXPAND)).
+controlled by {\it flags} (the second parameter of the Add() function): Zero or no flag
+indicates that the window will preserve it's original size, wxGROW flag (same as wxEXPAND)
+forces the window to grow with the sizer, and wxSHAPED flag tells the window to change it's
+size proportionally, preserving original aspect ratio.  When wxGROW flag is not used,
+the item can be aligned within available space.  wxALIGN\_LEFT, wxALIGN\_TOP, wxALIGN\_RIGHT,
+wxALIGN\_BOTTOM, wxALIGN\_CENTER\_HORIZONTAL and wxALIGN\_CENTER\_VERTICAL do what they say.
+wxALIGN\_CENTRE (same as wxALIGN\_CENTER) is defined as (wxALIGN\_CENTER\_HORIZONTAL |
+wxALIGN\_CENTER\_VERTICAL).  Default alignment is wxALIGN\_LEFT | wxALIGN\_TOP.
 
 As mentioned above, any window belonging to a sizer may have border, and it can be specified
 which of the four sides may have this border, using the wxTOP, wxLEFT, wxRIGHT and wxBOTTOM
@@ -45,9 +48,9 @@ MyDialog::MyDialog(wxFrame *parent, wxWindowID id, const wxString &title ) :
   wxDialog( parent, id, title, wxDefaultPosition, wxDefaultSize, wxDIALOG_STYLE | wxRESIZE_BORDER )
 {
   wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
-  
+
   // create text ctrl with minimal size 100x60
-  topsizer->Add( 
+  topsizer->Add(
     new wxTextCtrl( this, -1, "My text.", wxDefaultPosition, wxSize(100,60), wxTE_MULTILINE),
     1,            // make vertically stretchable
     wxEXPAND |    // make horizontally stretchable
@@ -57,20 +60,20 @@ MyDialog::MyDialog(wxFrame *parent, wxWindowID id, const wxString &title ) :
 
   wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
   button_sizer->Add(
-     new wxButton( this, wxID_OK, "OK" ), 
+     new wxButton( this, wxID_OK, "OK" ),
      0,           // make horizontally unstretchable
      wxALL,       // make border all around (implicit top alignment)
      10 );        // set border width to 10
   button_sizer->Add(
-     new wxButton( this, wxID_CANCEL, "Cancel" ), 
+     new wxButton( this, wxID_CANCEL, "Cancel" ),
      0,           // make horizontally unstretchable
      wxALL,       // make border all around (implicit top alignment)
      10 );        // set border width to 10
-  
-  topsizer->Add( 
+
+  topsizer->Add(
      button_sizer,
-     0,          // make vertically unstretchable
-     wxCENTER ); // no border and centre horizontally
+     0,                // make vertically unstretchable
+     wxALIGN_CENTER ); // no border and centre horizontally
 
   SetAutoLayout( TRUE );     // tell dialog to use sizer
   SetSizer( topsizer );      // actually set the sizer
@@ -98,7 +101,7 @@ or wxHORIZONTAL for creating either a column sizer or a row sizer.
 
 Implements the calculation of a box sizer's dimensions and then sets
 the size of its its children (calling \helpref{wxWindow::SetSize}{wxwindowsetsize}
-if the child is a window). It is used internally only and must not be called 
+if the child is a window). It is used internally only and must not be called
 by the users. Documented for information.
 
 \membersection{wxBoxSizer::CalcMin}\label{wxboxsizercalcmin}
diff --git a/docs/latex/wx/sizer.tex b/docs/latex/wx/sizer.tex
index 47e9cf0302..802c70d17d 100644
--- a/docs/latex/wx/sizer.tex
+++ b/docs/latex/wx/sizer.tex
@@ -1,7 +1,7 @@
 \section{\class{wxSizer}}\label{wxsizer}
 
 wxSizer is the abstract base class used for laying out subwindows in a window. You
-cannot use wxSizer directly; instead, you'll have to use \helpref{wxBoxSizer}{wxboxsizer} 
+cannot use wxSizer directly; instead, you'll have to use \helpref{wxBoxSizer}{wxboxsizer}
 or \helpref{wxStaticBoxSizer}{wxstaticboxsizer}.
 
 The layout algorithm used by sizers in wxWindows closely related to layout
@@ -87,9 +87,12 @@ determine the child window's behaviour if the size of the sizer changes, but - i
 the {\it option} flag - not in the main orientation, but the respectively other orientation. So
 if you created a wxBoxSizer with the wxVERTICAL option, these flags will be relevant if the
 sizer changes its horizontal size. A child may get resized to completely fill out the new size (using
-either wxGROW or wxEXPAND), may get centered (wxCENTER or wxCENTRE) or may get aligned to either
-side (wxALIGN\_LEFT and wxALIGN\_TOP are set to 0 and thus represent the default, wxALIGN\_RIGHT and
-wxALIGN\_BOTTOM have their obvious meaning).}
+either wxGROW or wxEXPAND), may get proportionally resized (wxSHAPED), may get centered (wxALIGN\_CENTER
+or wxALIGN\_CENTRE) or may get aligned to either side (wxALIGN\_LEFT and wxALIGN\_TOP are set to 0
+and thus represent the default, wxALIGN\_RIGHT and wxALIGN\_BOTTOM have their obvious meaning).
+With proportional resize, a child may also be centered in the main orientation using
+wxALIGN\_CENTER\_VERTICAL (same as wxALIGN\_CENTRE\_VERTICAL) and wxALIGN\_CENTER\_HORIZONTAL
+(same as wxALIGN\_CENTRE\_HORIZONTAL) flags.}
 
 \docparam{border}{Determines the border width, if the {\it flag} parameter is set to any border.}
 
diff --git a/include/wx/defs.h b/include/wx/defs.h
index 1cf504cb50..8a546d325d 100644
--- a/include/wx/defs.h
+++ b/include/wx/defs.h
@@ -695,12 +695,17 @@ enum wxDirection
 enum wxAlignment
 {
     wxALIGN_NOT               = 0x0000,
-    wxALIGN_CENTER            = 0x0100,
-    wxALIGN_CENTRE            = wxALIGN_CENTER,
+    wxALIGN_CENTER_HORIZONTAL = 0x0100,
+    wxALIGN_CENTRE_HORIZONTAL = wxALIGN_CENTER_HORIZONTAL,
     wxALIGN_LEFT              = wxALIGN_NOT,
     wxALIGN_TOP               = wxALIGN_NOT,
     wxALIGN_RIGHT             = 0x0200,
-    wxALIGN_BOTTOM            = 0x0400
+    wxALIGN_BOTTOM            = 0x0400,
+    wxALIGN_CENTER_VERTICAL   = 0x0800,
+    wxALIGN_CENTRE_VERTICAL   = wxALIGN_CENTER_VERTICAL,
+
+    wxALIGN_CENTER            = (wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL),
+    wxALIGN_CENTRE            = wxALIGN_CENTER
 };
 
 enum wxStretch
@@ -708,7 +713,8 @@ enum wxStretch
     wxSTRETCH_NOT             = 0x0000,
     wxSHRINK                  = 0x1000,
     wxGROW                    = 0x2000,
-    wxEXPAND                  = wxGROW
+    wxEXPAND                  = wxGROW,
+    wxSHAPED                  = 0x4000
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/wx/sizer.h b/include/wx/sizer.h
index c94ebfee71..c8e4503f51 100644
--- a/include/wx/sizer.h
+++ b/include/wx/sizer.h
@@ -56,6 +56,15 @@ public:
   virtual wxSize CalcMin();
   virtual void SetDimension( wxPoint pos, wxSize size );
 
+  void SetRatio( int width, int height )
+    // if either of dimensions is zero, ratio is assumed to be 1
+    // to avoid "divide by zero" errors
+    { m_ratio = (width && height) ? ((float) width / (float) height) : 1; }
+  void SetRatio( wxSize size )
+    { m_ratio = (size.x && size.y) ? ((float) size.x / (float) size.y) : 1; }
+  void SetRatio( float ratio ) { m_ratio = ratio; }
+  float GetRatio() const { return m_ratio; }
+
   bool IsWindow();
   bool IsSizer();
   bool IsSpacer();
@@ -81,6 +90,10 @@ protected:
   int          m_option;
   int          m_border;
   int          m_flag;
+  // als: aspect ratio can always be calculated from m_size,
+  //      but this would cause precision loss when the window
+  //      is shrinked.  it is safer to preserve initial value.
+  float        m_ratio;
   wxObject    *m_userData;
 };
 
diff --git a/samples/propsize/Makefile.in b/samples/propsize/Makefile.in
new file mode 100644
index 0000000000..f889d2842c
--- /dev/null
+++ b/samples/propsize/Makefile.in
@@ -0,0 +1,20 @@
+#
+# File:		makefile.unx
+# Author:	Julian Smart
+# Created:	1998
+# Updated:
+# Copyright:	(c) 1998 Julian Smart
+#
+# "%W% %G%"
+#
+# Makefile for wxWindows sample (UNIX).
+
+top_srcdir = @top_srcdir@
+top_builddir = ../..
+program_dir = samples/propsize
+
+PROGRAM=propsize
+
+OBJECTS=$(PROGRAM).o
+
+include ../../src/makeprog.env
diff --git a/samples/propsize/makefile.g95 b/samples/propsize/makefile.g95
new file mode 100644
index 0000000000..7a2bd64b3d
--- /dev/null
+++ b/samples/propsize/makefile.g95
@@ -0,0 +1,16 @@
+#
+# File:         makefile.g95
+# Author:       Julian Smart
+# Created:      1999
+# Updated:
+# Copyright:    (c) Julian Smart, 1999
+#
+# Makefile for wxWindows sample (Cygwin/Mingw32).
+
+WXDIR = ../..
+
+TARGET=propsize
+OBJECTS = $(TARGET).o
+
+include $(WXDIR)\src\makeprog.g95
+
diff --git a/samples/propsize/makefile.vc b/samples/propsize/makefile.vc
new file mode 100644
index 0000000000..c356f69b6f
--- /dev/null
+++ b/samples/propsize/makefile.vc
@@ -0,0 +1,17 @@
+#
+# File:		makefile.vc
+# Author:	Julian Smart
+# Created:	1999
+# Updated:
+# Copyright:	(c) Julian Smart
+#
+# Makefile : Builds sample (VC++, WIN32)
+# Use FINAL=1 argument to nmake to build final version with no debug info.
+
+# Set WXDIR for your system
+WXDIR = $(WXWIN)
+
+PROGRAM=propsize
+OBJECTS = $(PROGRAM).obj
+
+!include $(WXDIR)\src\makeprog.vc
diff --git a/samples/propsize/mondrian.ico b/samples/propsize/mondrian.ico
new file mode 100644
index 0000000000000000000000000000000000000000..2310c5d275a87af295d5ea8dc79ea417a5e74c53
GIT binary patch
literal 766
zcmZQzU<5)11px*Sc)`TLAO@s0fLH;D9e|jTfdxnc0Z<M**w4TKL=5})Lnt5#WHKB$
zaDbtqp#doIAB-6O{|B*v7zjZ^AOa2W|NsACHyAJ}De?dRKnp(HN~rljcR;{k;{zQE
i@;}UZ|9Q?Fpp*~yJCwmWbLIrN`9Qm9%}2L?p!oo$cZ4ed

literal 0
HcmV?d00001

diff --git a/samples/propsize/mondrian.xpm b/samples/propsize/mondrian.xpm
new file mode 100644
index 0000000000..0d72d6803f
--- /dev/null
+++ b/samples/propsize/mondrian.xpm
@@ -0,0 +1,44 @@
+/* XPM */
+static char *mondrian_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"32 32 6 1",
+"  c Black",
+". c Blue",
+"X c #00bf00",
+"o c Red",
+"O c Yellow",
+"+ c Gray100",
+/* pixels */
+"                                ",
+" oooooo +++++++++++++++++++++++ ",
+" oooooo +++++++++++++++++++++++ ",
+" oooooo +++++++++++++++++++++++ ",
+" oooooo +++++++++++++++++++++++ ",
+" oooooo +++++++++++++++++++++++ ",
+" oooooo +++++++++++++++++++++++ ",
+" oooooo +++++++++++++++++++++++ ",
+"                                ",
+" ++++++ ++++++++++++++++++ .... ",
+" ++++++ ++++++++++++++++++ .... ",
+" ++++++ ++++++++++++++++++ .... ",
+" ++++++ ++++++++++++++++++ .... ",
+" ++++++ ++++++++++++++++++ .... ",
+" ++++++ ++++++++++++++++++      ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++                    ++++ ",
+" ++++++ OOOOOOOOOOOO XXXXX ++++ ",
+" ++++++ OOOOOOOOOOOO XXXXX ++++ ",
+" ++++++ OOOOOOOOOOOO XXXXX ++++ ",
+" ++++++ OOOOOOOOOOOO XXXXX ++++ ",
+" ++++++ OOOOOOOOOOOO XXXXX ++++ ",
+" ++++++ OOOOOOOOOOOO XXXXX ++++ ",
+"                                "
+};
\ No newline at end of file
diff --git a/samples/propsize/propsize.cpp b/samples/propsize/propsize.cpp
new file mode 100644
index 0000000000..2189f89910
--- /dev/null
+++ b/samples/propsize/propsize.cpp
@@ -0,0 +1,249 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        propsize.cpp
+// Purpose:     Minimal wxWindows sample
+// Author:      Julian Smart
+// Modified by:
+// Created:     04/01/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+#ifdef __GNUG__
+    #pragma implementation "propsize.cpp"
+    #pragma interface "propsize.cpp"
+#endif
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+// for all others, include the necessary headers (this file is usually all you
+// need because it includes almost all "standard" wxWindows headers
+#ifndef WX_PRECOMP
+    #include "wx/wx.h"
+#endif
+
+#include "wx/statline.h"
+
+// ----------------------------------------------------------------------------
+// ressources
+// ----------------------------------------------------------------------------
+// the application icon
+#if defined(__WXGTK__) || defined(__WXMOTIF__)
+    #include "mondrian.xpm"
+#endif
+
+// ----------------------------------------------------------------------------
+// private classes
+// ----------------------------------------------------------------------------
+
+// Define a new application type, each program should derive a class from wxApp
+class MyApp : public wxApp
+{
+public:
+    // override base class virtuals
+    // ----------------------------
+
+    // this one is called on application startup and is a good place for the app
+    // initialization (doing it here and not in the ctor allows to have an error
+    // return: if OnInit() returns false, the application terminates)
+    virtual bool OnInit();
+};
+
+// Define a new frame type: this is going to be our main frame
+class MyFrame : public wxFrame
+{
+public:
+    // ctor(s)
+    MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
+
+    // event handlers (these functions should _not_ be virtual)
+    void OnQuit(wxCommandEvent& event);
+    void OnAbout(wxCommandEvent& event);
+
+private:
+    // any class wishing to process wxWindows events must use this macro
+    DECLARE_EVENT_TABLE()
+};
+
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
+
+// IDs for the controls and the menu commands
+enum
+{
+    // menu items
+    Minimal_Quit = 1,
+    Minimal_About
+};
+
+// ----------------------------------------------------------------------------
+// event tables and other macros for wxWindows
+// ----------------------------------------------------------------------------
+
+// the event tables connect the wxWindows events with the functions (event
+// handlers) which process them. It can be also done at run-time, but for the
+// simple menu events like this the static method is much simpler.
+BEGIN_EVENT_TABLE(MyFrame, wxFrame)
+    EVT_MENU(Minimal_Quit,  MyFrame::OnQuit)
+    EVT_MENU(Minimal_About, MyFrame::OnAbout)
+END_EVENT_TABLE()
+
+// Create a new application object: this macro will allow wxWindows to create
+// the application object during program execution (it's better than using a
+// static object for many reasons) and also declares the accessor function
+// wxGetApp() which will return the reference of the right type (i.e. MyApp and
+// not wxApp)
+IMPLEMENT_APP(MyApp)
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// the application class
+// ----------------------------------------------------------------------------
+
+// `Main program' equivalent: the program execution "starts" here
+bool MyApp::OnInit()
+{
+    // Create the main application window
+    MyFrame *frame = new MyFrame("Proportional resize",
+                                 wxPoint(50, 50), wxSize(450, 340));
+
+    // Show it and tell the application that it's our main window
+    // @@@ what does it do exactly, in fact? is it necessary here?
+    frame->Show(TRUE);
+    SetTopWindow(frame);
+
+    // success: wxApp::OnRun() will be called which will enter the main message
+    // loop and the application will run. If we returned FALSE here, the
+    // application would exit immediately.
+    return TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// main frame
+// ----------------------------------------------------------------------------
+
+// frame constructor
+MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
+       : wxFrame((wxFrame *)NULL, -1, title, pos, size)
+{
+    // set the frame icon
+    SetIcon(wxICON(mondrian));
+
+    // create a menu bar
+    wxMenu *menuFile = new wxMenu("", wxMENU_TEAROFF);
+
+    menuFile->Append(Minimal_About, "&About...\tCtrl-A", "Show about dialog");
+    menuFile->AppendSeparator();
+    menuFile->Append(Minimal_Quit, "E&xit\tAlt-X", "Quit this program");
+
+    // now append the freshly created menu to the menu bar...
+    wxMenuBar *menuBar = new wxMenuBar();
+    menuBar->Append(menuFile, "&File");
+
+    // ... and attach this menu bar to the frame
+    SetMenuBar(menuBar);
+
+#if wxUSE_STATUSBAR
+    // create a status bar just for fun (by default with 1 pane only)
+    CreateStatusBar(1);
+    SetStatusText("Resize the frame to see how controls react");
+#endif // wxUSE_STATUSBAR
+
+#define AddLine(orient) \
+     Add( new wxStaticLine( this, -1, wxDefaultPosition, wxSize(2,2), orient), \
+     0, wxEXPAND)
+#define AddButton(label,align) Add( \
+     new wxButton( this, -1, label, wxDefaultPosition, wxSize(100,50)), \
+     1, wxSHAPED | align)
+
+  wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
+  // top row -- top-aligned
+  wxBoxSizer *hsizer1 = new wxBoxSizer( wxHORIZONTAL );
+  hsizer1->AddButton( "one", wxALIGN_LEFT | wxALIGN_TOP);
+  hsizer1->AddLine(wxVERTICAL);
+  hsizer1->AddButton( "two", wxALIGN_CENTER_HORIZONTAL | wxALIGN_TOP);
+  hsizer1->AddLine(wxVERTICAL);
+  hsizer1->AddButton( "three", wxALIGN_RIGHT | wxALIGN_TOP);
+
+  topsizer->Add(hsizer1, 1, wxEXPAND);
+  topsizer->AddLine(wxHORIZONTAL);
+
+  wxBoxSizer *hsizer2 = new wxBoxSizer( wxHORIZONTAL );
+  hsizer2->AddButton( "four", wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
+  hsizer2->AddLine(wxVERTICAL);
+  // sizer that preserves it's shape
+  wxBoxSizer *vsizer = new wxBoxSizer( wxVERTICAL );
+  vsizer->Add(
+     new wxButton( this, -1, "up", wxDefaultPosition, wxSize(100,25)), \
+     1, wxEXPAND);
+  vsizer->Add(
+     new wxButton( this, -1, "down", wxDefaultPosition, wxSize(100,25)), \
+     1, wxEXPAND);
+  hsizer2->Add(vsizer, 1, wxSHAPED | wxALIGN_CENTER);
+  hsizer2->AddLine(wxVERTICAL);
+  hsizer2->AddButton( "six", wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
+
+  topsizer->Add(hsizer2, 1, wxEXPAND);
+  topsizer->AddLine(wxHORIZONTAL);
+
+  wxBoxSizer *hsizer3 = new wxBoxSizer( wxHORIZONTAL );
+  hsizer3->AddButton( "seven", wxALIGN_LEFT | wxALIGN_BOTTOM);
+  hsizer3->AddLine(wxVERTICAL);
+  hsizer3->AddButton( "eight", wxALIGN_CENTER_HORIZONTAL | wxALIGN_BOTTOM);
+  hsizer3->AddLine(wxVERTICAL);
+  // wxEXPAND should have no effect
+  hsizer3->AddButton( "nine", wxEXPAND | wxALIGN_RIGHT | wxALIGN_BOTTOM);
+
+  topsizer->Add(hsizer3, 1, wxEXPAND);
+
+  // set frame to minimum size
+  topsizer->Fit( this );
+
+  // don't allow frame to get smaller than what the sizers tell ye
+  // topsizer->SetSizeHints( this );
+
+  SetSizer( topsizer );
+  SetAutoLayout( TRUE );
+}
+
+
+// event handlers
+
+void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
+{
+    // TRUE is to force the frame to close
+    Close(TRUE);
+}
+
+void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
+{
+    wxString msg;
+    msg.Printf( _T("This is the about dialog of proportional sizer test.\n")
+                _T("Welcome to %s")
+#ifdef wxBETA_NUMBER
+               _T(" (beta %d)!")
+#endif // wxBETA_NUMBER
+               , wxVERSION_STRING
+#ifdef wxBETA_NUMBER
+               , wxBETA_NUMBER
+#endif // wxBETA_NUMBER
+              );
+
+    wxMessageBox(msg, "About Shaped Sizer", wxOK | wxICON_INFORMATION, this);
+}
diff --git a/samples/propsize/propsize.rc b/samples/propsize/propsize.rc
new file mode 100644
index 0000000000..4e062315d2
--- /dev/null
+++ b/samples/propsize/propsize.rc
@@ -0,0 +1,5 @@
+mondrian ICON "mondrian.ico"
+#include "wx/msw/wx.rc"
+
+#define MINIMAL_QUIT 	1
+#define MINIMAL_ABOUT 	102
diff --git a/src/common/sizer.cpp b/src/common/sizer.cpp
index e412f5a70c..ea20ee7168 100644
--- a/src/common/sizer.cpp
+++ b/src/common/sizer.cpp
@@ -48,6 +48,8 @@ wxSizerItem::wxSizerItem( int width, int height, int option, int flag, int borde
     m_minSize.x = width;
     m_minSize.y = height;
 
+    SetRatio(width, height);
+
     // size is set directly
     m_size = m_minSize;
 }
@@ -64,6 +66,9 @@ wxSizerItem::wxSizerItem( wxWindow *window, int option, int flag, int border, wx
     // minimal size is the initial size
     m_minSize = window->GetSize();
 
+    // aspect ratio calculated from initial size
+    SetRatio(m_minSize);
+
     // size is calculated later
     // m_size = ...
 }
@@ -79,6 +84,7 @@ wxSizerItem::wxSizerItem( wxSizer *sizer, int option, int flag, int border, wxOb
 
     // minimal size is calculated later
     // m_minSize = ...
+    m_ratio = 0;
 
     // size is calculated later
     // m_size = ...
@@ -119,7 +125,13 @@ wxSize wxSizerItem::CalcMin()
 {
     wxSize ret;
     if (IsSizer())
+    {
         ret = m_sizer->CalcMin();
+        // if we have to preserve aspect ratio _AND_ this is
+        // the first-time calculation, consider ret to be initial size
+        if ((m_flag & wxSHAPED) && !m_ratio) SetRatio(ret);
+    }
+
 /*
     The minimum size of a window should be the
     initial size, as saved in m_minSize, not the
@@ -163,6 +175,28 @@ void wxSizerItem::SetDimension( wxPoint pos, wxSize size )
     {
         size.y -= m_border;
     }
+    if (m_flag & wxSHAPED) {
+        // adjust aspect ratio
+        int rwidth = (int) (size.y * m_ratio);
+        if (rwidth > size.x) {
+            // fit horizontally
+            int rheight = (int) (size.x / m_ratio);
+            // add vertical space
+            if (m_flag & wxALIGN_CENTER_VERTICAL)
+                pos.y += (size.y - rheight) / 2;
+            else if (m_flag & wxALIGN_BOTTOM)
+                pos.y += (size.y - rheight);
+            // use reduced dimensions
+            size.y =rheight;
+        } else if (rwidth < size.x) {
+            // add horizontal space
+            if (m_flag & wxALIGN_CENTER_HORIZONTAL)
+                pos.x += (size.x - rwidth) / 2;
+            else if (m_flag & wxALIGN_RIGHT)
+                pos.x += (size.x - rwidth);
+            size.x = rwidth;
+        }
+    }
 
     if (IsSizer())
         m_sizer->SetDimension( pos.x, pos.y, size.x, size.y );
@@ -370,12 +404,14 @@ void wxBoxSizer::RecalcSizes()
 	    wxPoint child_pos( pt );
 	    wxSize  child_size( wxSize( size.x, height) );
 
-	    if (item->GetFlag() & wxALIGN_RIGHT)
+	    if (item->GetFlag() & (wxEXPAND | wxSHAPED))
+	      child_size.x = m_size.x;
+	    else if (item->GetFlag() & wxALIGN_RIGHT)
 	      child_pos.x += m_size.x - size.x;
-	    else if (item->GetFlag() & wxCENTER)
+	    else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
+	      // XXX wxCENTER is added for backward compatibility;
+	      //     wxALIGN_CENTER should be used in new code
 	      child_pos.x += (m_size.x - size.x) / 2;
-	    else if (item->GetFlag() & wxEXPAND)
-	      child_size.x = m_size.x;
 
 	    item->SetDimension( child_pos, child_size );
 
@@ -393,12 +429,14 @@ void wxBoxSizer::RecalcSizes()
 	    wxPoint child_pos( pt );
 	    wxSize  child_size( wxSize(width, size.y) );
 
-	    if (item->GetFlag() & wxALIGN_BOTTOM)
+	    if (item->GetFlag() & (wxEXPAND | wxSHAPED))
+	      child_size.y = m_size.y;
+	    else if (item->GetFlag() & wxALIGN_BOTTOM)
 	      child_pos.y += m_size.y - size.y;
-	    else if (item->GetFlag() & wxCENTER)
+	    else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
+	      // XXX wxCENTER is added for backward compatibility;
+	      //     wxALIGN_CENTER should be used in new code
 	      child_pos.y += (m_size.y - size.y) / 2;
-	    else if (item->GetFlag() & wxEXPAND)
-	      child_size.y = m_size.y;
 
 	    item->SetDimension( child_pos, child_size );
 
diff --git a/utils/wxPython/demo/Sizers.py b/utils/wxPython/demo/Sizers.py
index 0ea2df7807..24545c108d 100644
--- a/utils/wxPython/demo/Sizers.py
+++ b/utils/wxPython/demo/Sizers.py
@@ -69,7 +69,7 @@ def makeSimpleBox6(win):
     box = wxBoxSizer(wxHORIZONTAL)
     box.Add(wxButton(win, 1010, "one"), 1, wxALIGN_TOP)
     box.Add(wxButton(win, 1010, "two"), 1, wxEXPAND)
-    box.Add(wxButton(win, 1010, "three"), 1, wxCENTER)
+    box.Add(wxButton(win, 1010, "three"), 1, wxALIGN_CENTER)
     box.Add(wxButton(win, 1010, "four"), 1, wxEXPAND)
     box.Add(wxButton(win, 1010, "five"), 1, wxALIGN_BOTTOM)
 
@@ -93,7 +93,7 @@ def makeSimpleBox8(win):
     box = wxBoxSizer(wxVERTICAL)
     box.Add(wxButton(win, 1010, "one"), 0, wxEXPAND)
     box.Add(0,0, 1)
-    box.Add(wxButton(win, 1010, "two"), 0, wxCENTER)
+    box.Add(wxButton(win, 1010, "two"), 0, wxALIGN_CENTER)
     box.Add(0,0, 1)
     box.Add(wxButton(win, 1010, "three"), 0, wxEXPAND)
     box.Add(wxButton(win, 1010, "four"), 0, wxEXPAND)
@@ -243,7 +243,7 @@ def makeGrid2(win):
                  (wxButton(win, 1010, 'two'),   0, wxEXPAND),
                  (wxButton(win, 1010, 'three'), 0, wxALIGN_LEFT | wxALIGN_BOTTOM),
                  (wxButton(win, 1010, 'four'),  0, wxEXPAND),
-                 (wxButton(win, 1010, 'five'),  0, wxCENTER),
+                 (wxButton(win, 1010, 'five'),  0, wxALIGN_CENTER),
                  (wxButton(win, 1010, 'six'),   0, wxEXPAND),
                  (box,                          0, wxEXPAND | wxALL, 10),
                  (wxButton(win, 1010, 'eight'), 0, wxEXPAND),
@@ -276,6 +276,76 @@ def makeGrid3(win):
 
 #----------------------------------------------------------------------
 
+def makeGrid4(win):
+    bpos = wxDefaultPosition
+    bsize = wxSize(100, 50)
+    gs = wxGridSizer(3, 3, 2, 2)  # rows, cols, hgap, vgap
+
+    gs.AddMany([ (wxButton(win, 1010, 'one', bpos, bsize),
+                  0, wxALIGN_TOP | wxALIGN_LEFT ),
+                 (wxButton(win, 1010, 'two', bpos, bsize),
+                  0, wxALIGN_TOP | wxALIGN_CENTER_HORIZONTAL ),
+                 (wxButton(win, 1010, 'three', bpos, bsize),
+                  0, wxALIGN_TOP | wxALIGN_RIGHT ),
+                 (wxButton(win, 1010, 'four', bpos, bsize),
+                  0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT ),
+                 (wxButton(win, 1010, 'five', bpos, bsize),
+                  0, wxALIGN_CENTER ),
+                 (wxButton(win, 1010, 'six', bpos, bsize),
+                  0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT ),
+                 (wxButton(win, 1010, 'seven', bpos, bsize),
+                  0, wxALIGN_BOTTOM | wxALIGN_LEFT ),
+                 (wxButton(win, 1010, 'eight', bpos, bsize),
+                  0, wxALIGN_BOTTOM | wxALIGN_CENTER_HORIZONTAL ),
+                 (wxButton(win, 1010, 'nine', bpos, bsize),
+                  0, wxALIGN_BOTTOM | wxALIGN_RIGHT ),
+                 ])
+
+    return gs
+
+#----------------------------------------------------------------------
+
+def makeShapes(win):
+    bpos = wxDefaultPosition
+    bsize = wxSize(100, 50)
+    gs = wxGridSizer(3, 3, 2, 2)  # rows, cols, hgap, vgap
+
+    gs.AddMany([ (wxButton(win, 1010, 'one', bpos, bsize),
+                  0, wxSHAPED | wxALIGN_TOP | wxALIGN_LEFT ),
+                 (wxButton(win, 1010, 'two', bpos, bsize),
+                  0, wxSHAPED | wxALIGN_TOP | wxALIGN_CENTER_HORIZONTAL ),
+                 (wxButton(win, 1010, 'three', bpos, bsize),
+                  0, wxSHAPED | wxALIGN_TOP | wxALIGN_RIGHT ),
+                 (wxButton(win, 1010, 'four', bpos, bsize),
+                  0, wxSHAPED | wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT ),
+                 (wxButton(win, 1010, 'five', bpos, bsize),
+                  0, wxSHAPED | wxALIGN_CENTER ),
+                 (wxButton(win, 1010, 'six', bpos, bsize),
+                  0, wxSHAPED | wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT ),
+                 (wxButton(win, 1010, 'seven', bpos, bsize),
+                  0, wxSHAPED |  wxALIGN_BOTTOM | wxALIGN_LEFT ),
+                 (wxButton(win, 1010, 'eight', bpos, bsize),
+                  0, wxSHAPED | wxALIGN_BOTTOM | wxALIGN_CENTER_HORIZONTAL ),
+                 (wxButton(win, 1010, 'nine', bpos, bsize),
+                  0, wxSHAPED | wxALIGN_BOTTOM | wxALIGN_RIGHT ),
+                 ])
+
+    return gs
+
+#----------------------------------------------------------------------
+
+def makeSimpleBoxShaped(win):
+    box = wxBoxSizer(wxHORIZONTAL)
+    box.Add(wxButton(win, 1010, "one"), 0, wxEXPAND)
+    box.Add(wxButton(win, 1010, "two"), 0, wxEXPAND)
+    box.Add(wxButton(win, 1010, "three"), 0, wxEXPAND)
+    box.Add(wxButton(win, 1010, "four"), 0, wxEXPAND)
+    box.Add(wxButton(win, 1010, "five"), 1, wxSHAPED)
+
+    return box
+
+#----------------------------------------------------------------------
+
 theTests = [
     ("Simple horizontal boxes", makeSimpleBox1,
      "This is a HORIZONTAL box sizer with four non-stretchable buttons held "
@@ -328,7 +398,7 @@ theTests = [
     ("", None, ""),
 
     ("Simple border sizer", makeSimpleBorder1,
-     "The wxBorderSizer leaves empty space around its contents.  This one "
+     "The wxBoxSizer can leave empty space around its contents.  This one "
      "gives a border all the way around."
      ),
 
@@ -380,6 +450,22 @@ theTests = [
      "\nThere is also a spacer in the middle cell instead of an actual window."
      ),
 
+    ("Grid with Alignment", makeGrid4,
+     "New alignment flags allow for the positioning of items in any corner or centered "
+     "position."
+     ),
+
+    ("", None, ""),
+
+    ("Proportional resize", makeSimpleBoxShaped,
+     "Managed items can preserve their original aspect ratio.  The last item has the "
+     "wxSHAPED flag set and will resize proportional to its origingal size."
+     ),
+
+    ("Proportional resize with Alignments", makeShapes,
+     "This one shows various alignments as well as proportional resizing for all items."
+     ),
+
     ]
 #----------------------------------------------------------------------
 
diff --git a/utils/wxPython/lib/grids.py b/utils/wxPython/lib/grids.py
index d67443e07b..df4d7c9969 100644
--- a/utils/wxPython/lib/grids.py
+++ b/utils/wxPython/lib/grids.py
@@ -132,22 +132,18 @@ class wxGridSizer(wxPySizer):
         isz = item.CalcMin()
         flag = item.GetFlag()
 
-        if flag & wxEXPAND:
+        if flag & wxEXPAND or flag & wxSHAPED:
             isz = wxSize(w, h)
-
-        elif flag & wxCENTER:
-            ipt.x = x + (w - isz.width) / 2
-            ipt.y = y + (h - isz.height) / 2
-
-        if flag & wxALIGN_LEFT:
-            ipt.x = x
-        elif flag & wxALIGN_RIGHT:
-            ipt.x = x + (w - isz.width)
-
-        if flag & wxALIGN_TOP:
-            ipt.y = y
-        elif flag & wxALIGN_BOTTOM:
-            ipt.y = y + (h - isz.height)
+        else:
+            if flag & wxALIGN_CENTER_HORIZONTAL:
+                ipt.x = x + (w - isz.width) / 2
+            elif flag & wxALIGN_RIGHT:
+                ipt.x = x + (w - isz.width)
+
+            if flag & wxALIGN_CENTER_VERTICAL:
+                ipt.y = y + (h - isz.height) / 2
+            elif flag & wxALIGN_BOTTOM:
+                ipt.y = y + (h - isz.height)
 
         item.SetDimension(ipt, isz)
 
diff --git a/utils/wxPython/src/_defs.i b/utils/wxPython/src/_defs.i
index 98c6124f09..fbed419f63 100644
--- a/utils/wxPython/src/_defs.i
+++ b/utils/wxPython/src/_defs.i
@@ -232,11 +232,16 @@ enum {
     wxCOLOURED,
     wxFIXED_LENGTH,
     wxALIGN_LEFT,
-    wxALIGN_CENTER,
-    wxALIGN_CENTRE,
+    wxALIGN_CENTER_HORIZONTAL,
+    wxALIGN_CENTRE_HORIZONTAL,
     wxALIGN_RIGHT,
     wxALIGN_BOTTOM,
+    wxALIGN_CENTER_VERTICAL,
+    wxALIGN_CENTRE_VERTICAL,
     wxALIGN_TOP,
+    wxALIGN_CENTER,
+    wxALIGN_CENTRE,
+    wxSHAPED,
     wxLB_NEEDED_SB,
     wxLB_ALWAYS_SB,
     wxLB_SORT,
-- 
2.50.0

