From eacb91fc20ed0079a699ba7f3f2f624958caf482 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 22 Aug 2001 15:02:40 +0000 Subject: [PATCH] added wxDynamicSashWindow (patch 441518) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@11437 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- contrib/configure | 6 + contrib/configure.in | 2 + contrib/include/wx/gizmos/dynamicsash.h | 148 ++ contrib/samples/gizmos/Makefile.in | 2 +- contrib/samples/gizmos/dynsash/Makefile.in | 23 + contrib/samples/gizmos/dynsash/dynsash.cpp | 86 ++ .../samples/gizmos/dynsash_switch/Makefile.in | 23 + .../gizmos/dynsash_switch/dynsash_switch.cpp | 219 +++ contrib/src/gizmos/GizmosVC.dsp | 8 + contrib/src/gizmos/Makefile.in | 4 +- contrib/src/gizmos/dynamicsash.cpp | 1242 +++++++++++++++++ contrib/src/gizmos/makefile.b32 | 2 +- contrib/src/gizmos/makefile.bcc | 2 +- contrib/src/gizmos/makefile.g95 | 2 +- contrib/src/gizmos/makefile.unx | 3 +- contrib/src/gizmos/makefile.vc | 7 +- contrib/src/gizmos/makefile.wat | 2 +- 17 files changed, 1772 insertions(+), 9 deletions(-) create mode 100644 contrib/include/wx/gizmos/dynamicsash.h create mode 100644 contrib/samples/gizmos/dynsash/Makefile.in create mode 100644 contrib/samples/gizmos/dynsash/dynsash.cpp create mode 100644 contrib/samples/gizmos/dynsash_switch/Makefile.in create mode 100644 contrib/samples/gizmos/dynsash_switch/dynsash_switch.cpp create mode 100644 contrib/src/gizmos/dynamicsash.cpp diff --git a/contrib/configure b/contrib/configure index 27de393508..054e0c7389 100755 --- a/contrib/configure +++ b/contrib/configure @@ -822,6 +822,7 @@ trap 'rm -fr `echo " src/plot/Makefile src/applet/Makefile src/fl/Makefile + src/net/Makefile samples/Makefile samples/mmedia/Makefile samples/ogl/Makefile @@ -835,6 +836,8 @@ trap 'rm -fr `echo " samples/gizmos/multicell/Makefile samples/gizmos/splittree/Makefile samples/gizmos/editlbox/Makefile + samples/gizmos/dynsash/Makefile + samples/gizmos/dynsash_switch/Makefile samples/xrc/Makefile samples/plot/Makefile samples/applet/Makefile @@ -936,6 +939,7 @@ CONFIG_FILES=\${CONFIG_FILES-"src/Makefile src/plot/Makefile src/applet/Makefile src/fl/Makefile + src/net/Makefile samples/Makefile samples/mmedia/Makefile samples/ogl/Makefile @@ -949,6 +953,8 @@ CONFIG_FILES=\${CONFIG_FILES-"src/Makefile samples/gizmos/multicell/Makefile samples/gizmos/splittree/Makefile samples/gizmos/editlbox/Makefile + samples/gizmos/dynsash/Makefile + samples/gizmos/dynsash_switch/Makefile samples/xrc/Makefile samples/plot/Makefile samples/applet/Makefile diff --git a/contrib/configure.in b/contrib/configure.in index 8a245132fb..c35f135d47 100644 --- a/contrib/configure.in +++ b/contrib/configure.in @@ -61,6 +61,8 @@ AC_OUTPUT([ samples/gizmos/multicell/Makefile samples/gizmos/splittree/Makefile samples/gizmos/editlbox/Makefile + samples/gizmos/dynsash/Makefile + samples/gizmos/dynsash_switch/Makefile samples/xrc/Makefile samples/plot/Makefile samples/applet/Makefile diff --git a/contrib/include/wx/gizmos/dynamicsash.h b/contrib/include/wx/gizmos/dynamicsash.h new file mode 100644 index 0000000000..10b6b94c80 --- /dev/null +++ b/contrib/include/wx/gizmos/dynamicsash.h @@ -0,0 +1,148 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: dynamicsash.h +// Purpose: A window which can be dynamically split to an arbitrary depth +// and later reunified through the user interface +// Author: Matt Kimball +// Modified by: +// Created: 7/15/2001 +// RCS-ID: $Id$ +// Copyright: (c) 2001 Matt Kimball +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_DYNAMICSASH_H_ +#define _WX_DYNAMICSASH_H_ + +/* + + wxDynamicSashWindow + + wxDynamicSashWindow widgets manages the way other widgets are viewed. + When a wxDynamicSashWindow is first shown, it will contain one child + view, a viewport for that child, and a pair of scrollbars to allow the + user to navigate the child view area. Next to each scrollbar is a small + tab. By clicking on either tab and dragging to the appropriate spot, a + user can split the view area into two smaller views separated by a + draggable sash. Later, when the user wishes to reunify the two subviews, + the user simply drags the sash to the side of the window. + wxDynamicSashWindow will automatically reparent the appropriate child + view back up the window hierarchy, and the wxDynamicSashWindow will have + only one child view once again. + + As an application developer, you will simply create a wxDynamicSashWindow + using either the Create() function or the more complex constructor + provided below, and then create a view window whose parent is the + wxDynamicSashWindow. The child should respond to + wxDynamicSashSplitEvents -- perhaps with an OnSplit() event handler -- by + constructing a new view window whose parent is also the + wxDynamicSashWindow. That's it! Now your users can dynamically split + and reunify the view you provided. + + If you wish to handle the scrollbar events for your view, rather than + allowing wxDynamicSashWindow to do it for you, things are a bit more + complex. (You might want to handle scrollbar events yourself, if, + for instance, you wish to scroll a subwindow of the view you add to + your wxDynamicSashWindow object, rather than scrolling the whole view.) + In this case, you will need to construct your wxDynamicSashWindow without + the wxMANAGE_SCROLLBARS style and you will need to use the + GetHScrollBar() and GetVScrollBar() methods to retrieve the scrollbar + controls and call SetEventHanler() on them to redirect the scrolling + events whenever your window is reparented by wxDyanmicSashWindow. + You will need to set the scrollbars' event handler at three times: + + * When your view is created + * When your view receives a wxDynamicSashSplitEvent + * When your view receives a wxDynamicSashUnifyEvent + + See the dynsash_switch sample application for an example which does this. + +*/ + + +#include +#include +class wxScrollBar; + + +#define wxEVT_DYNAMIC_SASH_BASE (((int)('d' - 'a') << 11) | ((int)('s' - 'a') << 6) | ((int)('h' - 'a') << 1)) +#define wxEVT_DYNAMIC_SASH_SPLIT (wxEVT_DYNAMIC_SASH_BASE + 1) +#define wxEVT_DYNAMIC_SASH_UNIFY (wxEVT_DYNAMIC_SASH_BASE + 2) + +#define EVT_DYNAMIC_SASH_SPLIT(id, func) EVT_CUSTOM(wxEVT_DYNAMIC_SASH_SPLIT, (id), (func)) +#define EVT_DYNAMIC_SASH_UNIFY(id, func) EVT_CUSTOM(wxEVT_DYNAMIC_SASH_UNIFY, (id), (func)) + + +/* + wxMANAGE_SCROLLBARS is a default style of wxDynamicSashWindow which + will cause it to respond to scrollbar events for your application by + automatically scrolling the child view. +*/ +#define wxMANAGE_SCROLLBARS 0x00800000 + + +/* + wxDynamicSashSplitEvents are sent to your view by wxDynamicSashWindow + whenever your view is being split by the user. It is your + responsibility to handle this event by creating a new view window as + a child of the wxDynamicSashWindow. wxDynamicSashWindow will + automatically reparent it to the proper place in its window hierarchy. +*/ +class wxDynamicSashSplitEvent : public wxCommandEvent { +public: + wxDynamicSashSplitEvent(); + wxDynamicSashSplitEvent(wxObject *target); + +private: + DECLARE_DYNAMIC_CLASS(wxDynamicSashSplitEvent) +}; + +/* + wxDynamicSashUnifyEvents are sent to your view by wxDynamicSashWindow + whenever the sash which splits your view and its sibling is being + reunified such that your view is expanding to replace its sibling. + You needn't do anything with this event if you are allowing + wxDynamicSashWindow to manage your view's scrollbars, but it is useful + if you are managing the scrollbars yourself so that you can keep + the scrollbars' event handlers connected to your view's event handler + class. +*/ +class wxDynamicSashUnifyEvent : public wxCommandEvent { +public: + wxDynamicSashUnifyEvent(); + wxDynamicSashUnifyEvent(wxObject *target); + +private: + DECLARE_DYNAMIC_CLASS(wxDynamicSashUnifyEvent); +}; + +/* + wxDynamicSashWindow. See above. +*/ +class wxDynamicSashWindow : public wxWindow { +public: + wxDynamicSashWindow(); + wxDynamicSashWindow(wxWindow *parent, wxWindowID id, + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + long style = wxCLIP_CHILDREN | wxMANAGE_SCROLLBARS, + const wxString& name = "dynamicSashWindow"); + virtual ~wxDynamicSashWindow(); + + virtual bool Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + long style = wxCLIP_CHILDREN | wxMANAGE_SCROLLBARS, + const wxString& name = "dynamicSashWindow"); + virtual wxScrollBar *GetHScrollBar(const wxWindow *child) const; + virtual wxScrollBar *GetVScrollBar(const wxWindow *child) const; + + /* This is overloaded from wxWindowBase. It's not here for you to + call directly. */ + virtual void AddChild(wxWindowBase *child); + +private: + class wxDynamicSashWindowImpl *m_impl; + + DECLARE_DYNAMIC_CLASS(wxDynamicSashWindow) +}; + + +#endif diff --git a/contrib/samples/gizmos/Makefile.in b/contrib/samples/gizmos/Makefile.in index b8ea713e3b..223d5330fe 100644 --- a/contrib/samples/gizmos/Makefile.in +++ b/contrib/samples/gizmos/Makefile.in @@ -1,6 +1,6 @@ # $Id$ -CONTRIB_SAMPLES=multicell splittree editlbox +CONTRIB_SAMPLES=multicell splittree editlbox dynsash dynsash_switch all: @for d in $(CONTRIB_SAMPLES); do (cd $$d && $(MAKE)); done diff --git a/contrib/samples/gizmos/dynsash/Makefile.in b/contrib/samples/gizmos/dynsash/Makefile.in new file mode 100644 index 0000000000..5e5fd58b72 --- /dev/null +++ b/contrib/samples/gizmos/dynsash/Makefile.in @@ -0,0 +1,23 @@ +# +# File: Makefile.in +# Author: Matt Kimball +# Created: 2001 +# Updated: +# Copyright: (c) 2001 Matt Kimball +# +# "%W% %G%" +# +# Makefile for the dynsash example (UNIX). + +top_srcdir = @top_srcdir@/.. +top_builddir = ../../../.. +program_dir = contrib/samples/gizmos/dynsash + +PROGRAM=dynsash +OBJECTS=dynsash.o + +APPEXTRALIBS=$(top_builddir)/lib/libgizmos.@WX_TARGET_LIBRARY_TYPE@ +APPEXTRADEFS=-I$(top_srcdir)/contrib/include + +include $(top_builddir)/src/makeprog.env + diff --git a/contrib/samples/gizmos/dynsash/dynsash.cpp b/contrib/samples/gizmos/dynsash/dynsash.cpp new file mode 100644 index 0000000000..8e7bbb4efe --- /dev/null +++ b/contrib/samples/gizmos/dynsash/dynsash.cpp @@ -0,0 +1,86 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: dynsash.cpp +// Purpose: Test the wxDynamicSash class by creating a dynamic sash which +// contains an HTML view +// Author: Matt Kimball +// Modified by: +// Created: 7/15/2001 +// RCS-ID: $Id$ +// Copyright: (c) 2001 Matt Kimball +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +class Demo : public wxApp { +public: + bool OnInit(); +}; + +class SashHtmlWindow : public wxHtmlWindow { +public: + SashHtmlWindow(wxWindow *parent, wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + long style = wxHW_SCROLLBAR_NEVER, const wxString& name = "sashHtmlWindow"); + + wxSize DoGetBestSize() const; + +private: + void OnSplit(wxDynamicSashSplitEvent& event); + + wxWindow *m_dyn_sash; +}; + +IMPLEMENT_APP(Demo) + +char *HTML_content = +"

wxDynamicSashWindow demo

" +"

Here is an example of how you can use wxDynamicSashWindow to allow your users to " +"dynamically split and unify the views of your windows. Try dragging out a few splits " +"and then reunifying the window." +"

Also, see the dynsash_switch sample for an example of an application which " +"manages the scrollbars provided by wxDynamicSashWindow itself." +; + +bool Demo::OnInit() { + wxInitAllImageHandlers(); + + wxFrame *frame = new wxFrame(NULL, -1, "Dynamic Sash Demo"); + frame->SetSize(480, 480); + + wxDynamicSashWindow *sash = new wxDynamicSashWindow(frame, -1); + wxHtmlWindow *html = new SashHtmlWindow(sash, -1); + html->SetPage(HTML_content); + + frame->Show(); + + return TRUE; +} + + +SashHtmlWindow::SashHtmlWindow(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, long style, const wxString& name) : + wxHtmlWindow(parent, id, pos, size, style, name) { + Connect(-1, wxEVT_DYNAMIC_SASH_SPLIT, (wxObjectEventFunction)&SashHtmlWindow::OnSplit); + + m_dyn_sash = parent; +} + +wxSize SashHtmlWindow::DoGetBestSize() const { + wxHtmlContainerCell *cell = GetInternalRepresentation(); + wxSize size = GetSize(); + + if (cell) { + cell->Layout(size.GetWidth()); + return wxSize(cell->GetWidth(), cell->GetHeight()); + } else + return wxHtmlWindow::GetBestSize(); +} + +void SashHtmlWindow::OnSplit(wxDynamicSashSplitEvent& event) { + wxHtmlWindow *html = new SashHtmlWindow(m_dyn_sash, -1); + html->SetPage(HTML_content); +} diff --git a/contrib/samples/gizmos/dynsash_switch/Makefile.in b/contrib/samples/gizmos/dynsash_switch/Makefile.in new file mode 100644 index 0000000000..b9796bb40e --- /dev/null +++ b/contrib/samples/gizmos/dynsash_switch/Makefile.in @@ -0,0 +1,23 @@ +# +# File: Makefile.in +# Author: Matt Kimball +# Created: 2001 +# Updated: +# Copyright: (c) 2001 Matt Kimball +# +# "%W% %G%" +# +# Makefile for the dynsash_switch example (UNIX). + +top_srcdir = @top_srcdir@/.. +top_builddir = ../../../.. +program_dir = contrib/samples/gizmos/dynsash_switch + +PROGRAM=dynsash_switch +OBJECTS=dynsash_switch.o + +APPEXTRALIBS=$(top_builddir)/lib/libgizmos.@WX_TARGET_LIBRARY_TYPE@ +APPEXTRADEFS=-I$(top_srcdir)/contrib/include + +include $(top_builddir)/src/makeprog.env + diff --git a/contrib/samples/gizmos/dynsash_switch/dynsash_switch.cpp b/contrib/samples/gizmos/dynsash_switch/dynsash_switch.cpp new file mode 100644 index 0000000000..208745d8fb --- /dev/null +++ b/contrib/samples/gizmos/dynsash_switch/dynsash_switch.cpp @@ -0,0 +1,219 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: dynsash_switch.cpp +// Purpose: Test custom scrollbar handling of wxDynamicSashWindow by +// creating a dynamic sash window where the client scrolls a +// a subwindow of the client window by responding to scroll +// events itself +// Author: Matt Kimball +// Modified by: +// Created: 7/15/2001 +// RCS-ID: $Id$ +// Copyright: (c) 2001 Matt Kimball +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +class SwitchDemo : public wxApp { +public: + bool OnInit(); +}; + + +class SwitchView : public wxWindow { +public: + SwitchView(wxDynamicSashWindow *parent); + + wxSize DoGetBestSize() const; + +private: + void OnSize(wxSizeEvent& event); + void OnPaint(wxPaintEvent& event); + void OnChoice(wxCommandEvent& event); + void OnScroll(wxScrollEvent& event); + void OnFocus(wxFocusEvent& event); + void OnErase(wxEraseEvent& event); + void OnSplit(wxDynamicSashSplitEvent& event); + void OnUnify(wxDynamicSashUnifyEvent& event); + + wxDynamicSashWindow *m_dyn_sash; + wxWindow *m_bar; + wxChoice *m_choice; + wxWindow *m_view; +}; + +IMPLEMENT_APP(SwitchDemo) + + +SwitchView::SwitchView(wxDynamicSashWindow *win) { + Create(win, -1); + + m_dyn_sash = win; + + m_bar = new wxWindow(this, -1, wxDefaultPosition, wxDefaultSize, wxRAISED_BORDER, "bar"); + m_choice = new wxChoice(m_bar, -1); + m_choice->SetEventHandler(this); + m_view = new wxWindow(this, -1, wxDefaultPosition, wxDefaultSize, 0, "view"); + m_view->SetBackgroundColour(*wxWHITE); + m_view->SetEventHandler(this); + + m_choice->Append("Triangle"); + m_choice->Append("Square"); + m_choice->SetSelection(0); + + wxLayoutConstraints *layout; + + layout = new wxLayoutConstraints(); + layout->left.Absolute(0); + layout->top.Absolute(0); + layout->height.Absolute(36); + layout->width.SameAs(this, wxWidth); + m_bar->SetConstraints(layout); + + layout = new wxLayoutConstraints(); + layout->left.Absolute(3); + layout->width.AsIs(); + layout->height.AsIs(); + layout->top.Absolute(3); + m_choice->SetConstraints(layout); + + layout = new wxLayoutConstraints(); + layout->left.Absolute(0); + layout->width.SameAs(this, wxWidth); + layout->top.Below(m_bar); + layout->bottom.SameAs(this, wxBottom); + m_view->SetConstraints(layout); + + wxScrollBar *hscroll = m_dyn_sash->GetHScrollBar(this); + wxScrollBar *vscroll = m_dyn_sash->GetVScrollBar(this); + + hscroll->SetEventHandler(this); + vscroll->SetEventHandler(this); + + Connect(GetId(), wxEVT_SIZE, (wxObjectEventFunction)&SwitchView::OnSize); + Connect(m_choice->GetId(), wxEVT_COMMAND_CHOICE_SELECTED, (wxObjectEventFunction)&SwitchView::OnChoice); + Connect(m_view->GetId(), wxEVT_PAINT, (wxObjectEventFunction)&SwitchView::OnPaint); + + Connect(-1, wxEVT_SET_FOCUS, (wxObjectEventFunction)&SwitchView::OnFocus); + Connect(-1, wxEVT_SCROLL_TOP, (wxObjectEventFunction)&SwitchView::OnScroll); + Connect(-1, wxEVT_SCROLL_BOTTOM, (wxObjectEventFunction)&SwitchView::OnScroll); + Connect(-1, wxEVT_SCROLL_LINEUP, (wxObjectEventFunction)&SwitchView::OnScroll); + Connect(-1, wxEVT_SCROLL_LINEDOWN, (wxObjectEventFunction)&SwitchView::OnScroll); + Connect(-1, wxEVT_SCROLL_PAGEUP, (wxObjectEventFunction)&SwitchView::OnScroll); + Connect(-1, wxEVT_SCROLL_PAGEDOWN, (wxObjectEventFunction)&SwitchView::OnScroll); + Connect(-1, wxEVT_SCROLL_THUMBTRACK, (wxObjectEventFunction)&SwitchView::OnScroll); + Connect(-1, wxEVT_SCROLL_THUMBRELEASE, (wxObjectEventFunction)&SwitchView::OnScroll); + Connect(-1, wxEVT_ERASE_BACKGROUND, (wxObjectEventFunction)&SwitchView::OnErase); + + Connect(-1, wxEVT_DYNAMIC_SASH_SPLIT, (wxObjectEventFunction)&SwitchView::OnSplit); + Connect(-1, wxEVT_DYNAMIC_SASH_UNIFY, (wxObjectEventFunction)&SwitchView::OnUnify); +} + +wxSize SwitchView::DoGetBestSize() const { + return wxSize(64, 64); +} + +void SwitchView::OnSize(wxSizeEvent& event) { + Layout(); + + wxScrollBar *hscroll = m_dyn_sash->GetHScrollBar(this); + wxScrollBar *vscroll = m_dyn_sash->GetVScrollBar(this); + + if (hscroll && vscroll) { + int hpos = hscroll->GetThumbPosition(); + int vpos = vscroll->GetThumbPosition(); + + wxSize size = m_view->GetSize(); + if (hpos + size.GetWidth() > 300) + hpos = 300 - size.GetWidth(); + if (vpos + size.GetHeight() > 300) + vpos = 300 - size.GetHeight(); + + hscroll->SetScrollbar(hpos, size.GetWidth(), 300, size.GetWidth()); + vscroll->SetScrollbar(vpos, size.GetHeight(), 300, size.GetHeight()); + } +} + +void SwitchView::OnPaint(wxPaintEvent& event) { + wxPaintDC dc(m_view); + + wxScrollBar *hscroll = m_dyn_sash->GetHScrollBar(this); + wxScrollBar *vscroll = m_dyn_sash->GetVScrollBar(this); + + dc.Clear(); + dc.SetDeviceOrigin(-hscroll->GetThumbPosition(), -vscroll->GetThumbPosition()); + + if (m_choice->GetSelection()) { + dc.DrawLine(20, 20, 280, 20); + dc.DrawLine(280, 20, 280, 280); + dc.DrawLine(280, 280, 20, 280); + dc.DrawLine(20, 280, 20, 20); + } else { + dc.DrawLine(150, 20, 280, 280); + dc.DrawLine(280, 280, 20, 280); + dc.DrawLine(20, 280, 150, 20); + } +} + +void SwitchView::OnErase(wxEraseEvent& event) { + // Do nothing +} + +void SwitchView::OnSplit(wxDynamicSashSplitEvent& event) { + SwitchView *view = new SwitchView(m_dyn_sash); + view->m_choice->SetSelection(m_choice->GetSelection()); + + wxScrollBar *hscroll = m_dyn_sash->GetHScrollBar(this); + wxScrollBar *vscroll = m_dyn_sash->GetVScrollBar(this); + + hscroll->SetEventHandler(this); + vscroll->SetEventHandler(this); +} + +void SwitchView::OnUnify(wxDynamicSashUnifyEvent& event) { + wxScrollBar *hscroll = m_dyn_sash->GetHScrollBar(this); + wxScrollBar *vscroll = m_dyn_sash->GetVScrollBar(this); + + hscroll->SetEventHandler(this); + vscroll->SetEventHandler(this); +} + +void SwitchView::OnChoice(wxCommandEvent& event) { + m_view->Refresh(); +} + +void SwitchView::OnScroll(wxScrollEvent& event) { + m_view->Refresh(); +} + +void SwitchView::OnFocus(wxFocusEvent& event) { + wxScrollBar *hscroll = m_dyn_sash->GetHScrollBar(this); + wxScrollBar *vscroll = m_dyn_sash->GetVScrollBar(this); + + if (event.m_eventObject == hscroll || event.m_eventObject == vscroll) { + m_view->SetFocus(); + } else { + event.Skip(); + } +} + + + +bool SwitchDemo::OnInit() { + wxFrame *frame; + wxDynamicSashWindow *dyn; + + frame = new wxFrame(NULL, -1, "Dynamic Sash Window Switch Demo"); + dyn = new wxDynamicSashWindow(frame, -1, wxDefaultPosition, wxDefaultSize, wxCLIP_CHILDREN); + new SwitchView(dyn); + + frame->SetSize(480, 480); + frame->Show(); + + return TRUE; +} diff --git a/contrib/src/gizmos/GizmosVC.dsp b/contrib/src/gizmos/GizmosVC.dsp index cacdb63d7b..2b60bbe078 100644 --- a/contrib/src/gizmos/GizmosVC.dsp +++ b/contrib/src/gizmos/GizmosVC.dsp @@ -97,6 +97,10 @@ SOURCE=..\..\include\wx\gizmos\editlbox.h SOURCE=..\..\include\wx\gizmos\splittree.h # End Source File +# Begin Source File + +SOURCE=..\..\include\wx\gizmos\dynamicsash.h +# End Source File # End Group # Begin Source File @@ -110,5 +114,9 @@ SOURCE=.\editlbox.cpp SOURCE=.\splittree.cpp # End Source File +# Begin Source File + +SOURCE=.\dynamicsash.cpp +# End Source File # End Target # End Project diff --git a/contrib/src/gizmos/Makefile.in b/contrib/src/gizmos/Makefile.in index b015c7d15f..a307c53576 100644 --- a/contrib/src/gizmos/Makefile.in +++ b/contrib/src/gizmos/Makefile.in @@ -13,9 +13,9 @@ LIBVERSION_AGE=0 HEADER_PATH=$(top_srcdir)/contrib/include/wx HEADER_SUBDIR=gizmos -HEADERS=multicell.h splittree.h editlbox.h +HEADERS=multicell.h splittree.h editlbox.h dynamicsash.h -OBJECTS=multicell.o splittree.o editlbox.o +OBJECTS=multicell.o splittree.o editlbox.o dynamicsash.o APPEXTRADEFS=-I$(top_srcdir)/contrib/include diff --git a/contrib/src/gizmos/dynamicsash.cpp b/contrib/src/gizmos/dynamicsash.cpp new file mode 100644 index 0000000000..3787b4df05 --- /dev/null +++ b/contrib/src/gizmos/dynamicsash.cpp @@ -0,0 +1,1242 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: dynamicsash.cpp +// Purpose: A window which can be dynamically split to an arbitrary depth +// and later reunified through the user interface +// Author: Matt Kimball +// Modified by: +// Created: 7/15/2001 +// RCS-ID: $Id$ +// Copyright: (c) 2001 Matt Kimball +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/gizmos/dynamicsash.h" + +/* + wxDynamicSashWindow works by internally storing a tree of Implementation + objects (wxDynamicSsahWindowImpl) and Leaf objects + (wxDynamicSashWindowLeaf). The wxDynamicSashWindow has a pointer to one + implementation, and each implementation either has a pointer to a one + leaf (m_leaf) or a pointer to two children implementation objects + (m_child). The leaves each are responsible for drawing the frame and + decorations around one user-provided views and for responding to mouse + and scrollbar events. + + A resulting tree might look something like this: + + wxDynamicSashWindow + | + +- wxDynamicSashWindowImpl + | + +- wxDynamicSashWindowLeaf + | | + | +- user view window + | + +- wxDynamicSashWindowImpl + | + +- wxDynamicSashWindowLeaf + | | + | +- user view window + | + +- wxDynamicSashWindowLeaf + | + +- user view window + + Each time a split occurs, one of the implementation objects removes its + leaf, generates two new implementation object children, each with a new + leaf, and reparents the user view which was connected to its old leaf + to be one of the new leaf's user view, and sends a Split event to the + user view in the hopes that it will generate a new user view for the + other new leaf. + + When a unification ocurrs, an implementation object is replaced by one + of its children, and the tree of its other child is pruned. + + One quirk is that the top-level implementation object (m_top) always + keeps a pointer to the implementation object where a new child is needed. + (m_add_child_target). This is so that when a new uesr view is added + to the hierarchy, AddChild() is able to reparent the new user view to + the correct implementation object's leaf. + +*/ + +#include +#include +#include +#include +#include + + +#define wxEVT_DYNAMIC_SASH_PRIVATE (wxEVT_DYNAMIC_SASH_BASE + 8) +#define wxEVT_DYNAMIC_SASH_REPARENT (wxEVT_DYNAMIC_SASH_PRIVATE + 1) + + +/* + wxDynamicSashReparentEvent is generated by the AddChild() method of + wxDynamicSashWindow when it wants a Leaf to reparent a user view window + to its viewport at some time in the future. We can't reparent the window + immediately, because switching parents in AddChild() confuses the wxWindow + class. Instead, we queue up this event, and the window is actually + reparented the next time we process events in the idle loop. +*/ +class wxDynamicSashReparentEvent : public wxEvent { +public: + wxDynamicSashReparentEvent(); + wxDynamicSashReparentEvent(wxObject *object); + + DECLARE_DYNAMIC_CLASS(wxDynamicSashReparentEvent); +}; + + +enum DynamicSashRegion { + DSR_NONE, + DSR_VERTICAL_TAB, + DSR_HORIZONTAL_TAB, + DSR_CORNER, + DSR_LEFT_EDGE, + DSR_TOP_EDGE, + DSR_RIGHT_EDGE, + DSR_BOTTOM_EDGE +}; + + +class wxDynamicSashWindowImpl : public wxEvtHandler { +public: + wxDynamicSashWindowImpl(wxDynamicSashWindow *window); + ~wxDynamicSashWindowImpl(); + + bool Create(); + void AddChild(wxWindow *window); + void DrawSash(int x, int y) const; + void ConstrainChildren(int px, int py); + void Split(int x, int y); + void Unify(int panel); + void Resize(int x, int y); + wxDynamicSashWindowImpl *FindParent(DynamicSashRegion side) const; + wxDynamicSashWindowImpl *FindUpperParent(wxDynamicSashWindowImpl *sash_a, + wxDynamicSashWindowImpl *sash_b) const; + wxWindow *FindFrame() const; + wxScrollBar *FindScrollBar(const wxWindow *child, int vert) const; + + void OnSize(wxSizeEvent &event); + void OnPaint(wxPaintEvent &event); + void OnMouseMove(wxMouseEvent &event); + void OnLeave(wxMouseEvent &event); + void OnPress(wxMouseEvent &event); + void OnRelease(wxMouseEvent &event); + + wxDynamicSashWindow *m_window; + wxDynamicSashWindowImpl *m_add_child_target; + + /* This is the window we are responsible for managing. Either of + leaf or our children are in this window. For the top level + implementation object, this is the same as m_window. + Otherwise it is a window we've created an will destroy when we + are deleted. */ + wxWindow *m_container; + + wxDynamicSashWindowImpl *m_parent; + wxDynamicSashWindowImpl *m_top; + wxDynamicSashWindowImpl *m_child[2]; + + class wxDynamicSashWindowLeaf *m_leaf; + + /* If the implementation is split horizontally or vertically, m_split + is set to DSR_HORIZONTAL_TAB or DSR_VERTICAL_TAB, respectively. + Otherwise it is set to DSR_NONE. */ + DynamicSashRegion m_split; + + /* These are used to keep track of a sash as it is being dragged, for + drawing the user interface correctly. */ + DynamicSashRegion m_dragging; + int m_drag_x, m_drag_y; +}; + +class wxDynamicSashWindowLeaf : public wxEvtHandler { +public: + wxDynamicSashWindowLeaf(wxDynamicSashWindowImpl *impl); + ~wxDynamicSashWindowLeaf(); + + bool Create(); + void AddChild(wxWindow *window); + DynamicSashRegion GetRegion(int x, int y); + void ResizeChild(wxSize size); + wxScrollBar *FindScrollBar(const wxWindow *child, int vert) const; + + void OnSize(wxSizeEvent &event); + void OnPaint(wxPaintEvent &event); + void OnScroll(wxScrollEvent &event); + void OnFocus(wxFocusEvent &event); + void OnMouseMove(wxMouseEvent &event); + void OnLeave(wxMouseEvent &event); + void OnPress(wxMouseEvent &event); + void OnRelease(wxMouseEvent &event); + void OnReparent(wxEvent &event); + + wxDynamicSashWindowImpl *m_impl; + + wxScrollBar *m_vscroll, *m_hscroll; + + /* m_child is the window provided to us by the application developer. + m_viewport is a window we've created, and it is the immediately + parent of m_child. We scroll m_child by moving it around within + m_viewport. */ + wxWindow *m_viewport, *m_child; +}; + +// wxDynamicSashWindow ////////////////////////////////////////////////////// + +wxDynamicSashWindow::wxDynamicSashWindow() { + m_impl = NULL; +} + +wxDynamicSashWindow::wxDynamicSashWindow(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, + long style, const wxString& name) { + m_impl = NULL; + Create(parent, id, pos, size, style, name); +} + +wxDynamicSashWindow::~wxDynamicSashWindow() { + SetEventHandler(this); + delete m_impl; +} + +bool wxDynamicSashWindow::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, + long style, const wxString& name) { + if (m_impl) + return FALSE; + + if (!wxWindow::Create(parent, id, pos, size, style, name)) + return FALSE; + + m_impl = new wxDynamicSashWindowImpl(this); + if (!m_impl) + return FALSE; + + if (!m_impl->Create()) { + delete m_impl; + m_impl = NULL; + return FALSE; + } + + return TRUE; +} + +void wxDynamicSashWindow::AddChild(wxWindowBase *child) { + wxWindow::AddChild(child); + + m_impl->AddChild(wxDynamicCast(child, wxWindow)); +} + +wxScrollBar *wxDynamicSashWindow::GetHScrollBar(const wxWindow *child) const { + return m_impl->FindScrollBar(child, 0); +} + +wxScrollBar *wxDynamicSashWindow::GetVScrollBar(const wxWindow *child) const { + return m_impl->FindScrollBar(child, 1); +} + +IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashWindow, wxWindow) + +// wxDynamicSashWindowImpl ////////////////////////////////////////////////// + +wxDynamicSashWindowImpl::wxDynamicSashWindowImpl(wxDynamicSashWindow *window) { + m_window = window; + m_add_child_target = this; + + m_container = NULL; + m_parent = NULL; + m_top = this; + m_child[0] = m_child[1] = NULL; + m_leaf = NULL; + m_dragging = DSR_NONE; + m_split = DSR_NONE; +} + +wxDynamicSashWindowImpl::~wxDynamicSashWindowImpl() { + delete m_leaf; + delete m_child[0]; + m_child[0] = NULL; + delete m_child[1]; + m_child[1] = NULL; + m_leaf = NULL; + + if (m_container != m_window && m_container) { + m_container->SetEventHandler(m_container); + m_container->Destroy(); + } +} + +bool wxDynamicSashWindowImpl::Create() { + if (!m_container) { + m_container = m_window; + } + + wxCursor cursor(wxCURSOR_ARROW); + m_container->SetCursor(cursor); + + m_leaf = new wxDynamicSashWindowLeaf(this); + if (!m_leaf) + return FALSE; + + if (!m_leaf->Create()) { + delete m_leaf; + m_leaf = NULL; + return FALSE; + } + + m_container->SetEventHandler(this); + + Connect(-1, wxEVT_SIZE, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnSize); + Connect(-1, wxEVT_PAINT, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnPaint); + Connect(-1, wxEVT_MOTION, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnMouseMove); + Connect(-1, wxEVT_ENTER_WINDOW, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnMouseMove); + Connect(-1, wxEVT_LEAVE_WINDOW, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnLeave); + Connect(-1, wxEVT_LEFT_DOWN, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnPress); + Connect(-1, wxEVT_LEFT_UP, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnRelease); + + return TRUE; +} + +void wxDynamicSashWindowImpl::AddChild(wxWindow *window) { + if (m_add_child_target && m_add_child_target->m_leaf) { + m_add_child_target->m_leaf->AddChild(window); + } +} + +void wxDynamicSashWindowImpl::DrawSash(int x, int y) const { + int i, j; + + wxScreenDC dc; + dc.StartDrawingOnTop(m_container); + + wxBitmap bmp(8, 8); + wxMemoryDC bdc; + bdc.SelectObject(bmp); + bdc.DrawRectangle(-1, -1, 10, 10); + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++) { + if ((i + j) & 1) { + bdc.DrawPoint(i, j); + } + } + } + + wxBrush brush(bmp); + dc.SetBrush(brush); + dc.SetLogicalFunction(wxXOR); + + if (m_dragging == DSR_CORNER) { + int cx = 0; + int cy = 0; + + m_container->ClientToScreen(&cx, &cy); + m_container->ClientToScreen(&x, &y); + + if (cx < x && cy < y) { + dc.DrawRectangle(cx - 2, cy - 2, x - cx + 4, 4); + dc.DrawRectangle(x - 2, cy + 2, 4, y - cy); + dc.DrawRectangle(cx - 2, cy + 2, 4, y - cy); + dc.DrawRectangle(cx + 2, y - 2, x - cx - 4, 4); + } + } else { + int body_w, body_h; + m_container->GetClientSize(&body_w, &body_h); + + if (y < 0) + y = 0; + if (y > body_h) + y = body_h; + if (x < 0) + x = 0; + if (x > body_w) + x = body_w; + + if (m_dragging == DSR_HORIZONTAL_TAB) + x = 0; + else + y = 0; + + m_container->ClientToScreen(&x, &y); + + int w, h; + w = body_w; h = body_h; + + if (m_dragging == DSR_HORIZONTAL_TAB) + dc.DrawRectangle(x, y - 2, w, 4); + else + dc.DrawRectangle(x - 2, y, 4, h); + } + + dc.EndDrawingOnTop(); +} + +wxDynamicSashWindowImpl *wxDynamicSashWindowImpl::FindParent(DynamicSashRegion side) const { + if (m_parent == NULL) { + return NULL; + } + + if (m_parent->m_split == DSR_HORIZONTAL_TAB) { + if (side == DSR_TOP_EDGE && m_parent->m_child[1] == this) + return m_parent; + if (side == DSR_BOTTOM_EDGE && m_parent->m_child[0] == this) + return m_parent; + } else if (m_parent->m_split == DSR_VERTICAL_TAB) { + if (side == DSR_LEFT_EDGE && m_parent->m_child[1] == this) + return m_parent; + if (side == DSR_RIGHT_EDGE && m_parent->m_child[0] == this) + return m_parent; + } + + return m_parent->FindParent(side); +} + +wxDynamicSashWindowImpl *wxDynamicSashWindowImpl::FindUpperParent(wxDynamicSashWindowImpl *sash_a, + wxDynamicSashWindowImpl *sash_b) const { + wxWindow *win; + win = sash_a->m_container->GetParent(); + while (win && !win->IsTopLevel()) { + if (win == sash_b->m_container) { + return sash_b; + } + + win = win->GetParent(); + } + + return sash_a; +} + + +wxWindow *wxDynamicSashWindowImpl::FindFrame() const { + wxWindow *win; + + win = m_window->GetParent(); + while (win && !win->IsTopLevel()) { + win = win->GetParent(); + } + + return win; +} + +wxScrollBar *wxDynamicSashWindowImpl::FindScrollBar(const wxWindow *child, int vert) const { + if (m_child[0] == NULL && m_leaf == NULL) { + return NULL; + } + + if (!m_child[0]) { + return m_leaf->FindScrollBar(child, vert); + } else { + wxScrollBar *ret = m_child[0]->FindScrollBar(child, vert); + if (!ret) { + ret = m_child[1]->FindScrollBar(child, vert); + } + + return ret; + } +} + +void wxDynamicSashWindowImpl::ConstrainChildren(int px, int py) { + wxLayoutConstraints *layout = new wxLayoutConstraints(); + layout->left.SameAs(m_container, wxLeft); + layout->top.SameAs(m_container, wxTop); + if (m_split == DSR_HORIZONTAL_TAB) { + layout->right.SameAs(m_container, wxRight); + layout->height.PercentOf(m_container, wxHeight, py); + } else { + layout->bottom.SameAs(m_container, wxBottom); + layout->width.PercentOf(m_container, wxWidth, px); + } + m_child[0]->m_container->SetConstraints(layout); + + layout = new wxLayoutConstraints(); + layout->right.SameAs(m_container, wxRight); + layout->bottom.SameAs(m_container, wxBottom); + if (m_split == DSR_HORIZONTAL_TAB) { + layout->top.Below(m_child[0]->m_container, 1); + layout->left.SameAs(m_container, wxLeft); + } else { + layout->left.RightOf(m_child[0]->m_container, 1); + layout->top.SameAs(m_container, wxTop); + } + m_child[1]->m_container->SetConstraints(layout); +} + +void wxDynamicSashWindowImpl::Unify(int panel) { + int other = 0; + if (panel == 0) { + other = 1; + } + + if (m_child[panel]->m_leaf) { + wxDynamicSashWindowImpl *child[2]; + + child[0] = m_child[0]; + child[1] = m_child[1]; + + m_child[0] = m_child[1] = NULL; + + m_leaf = new wxDynamicSashWindowLeaf(this); + m_leaf->Create(); + m_leaf->m_child = child[panel]->m_leaf->m_child; + + m_leaf->m_vscroll->SetScrollbar(child[panel]->m_leaf->m_vscroll->GetThumbPosition(), + child[panel]->m_leaf->m_vscroll->GetThumbSize(), + child[panel]->m_leaf->m_vscroll->GetRange(), + child[panel]->m_leaf->m_vscroll->GetPageSize()); + m_leaf->m_hscroll->SetScrollbar(child[panel]->m_leaf->m_hscroll->GetThumbPosition(), + child[panel]->m_leaf->m_hscroll->GetThumbSize(), + child[panel]->m_leaf->m_hscroll->GetRange(), + child[panel]->m_leaf->m_hscroll->GetPageSize()); + m_add_child_target = NULL; + wxDynamicSashReparentEvent event(m_leaf); + m_leaf->ProcessEvent(event); + + delete child[0]; + delete child[1]; + + m_split = DSR_NONE; + + wxDynamicSashUnifyEvent unify(m_leaf->m_child); + m_leaf->m_child->ProcessEvent(unify); + } else { + m_split = m_child[panel]->m_split; + + delete m_child[other]; + + wxDynamicSashWindowImpl *child_panel = m_child[panel]; + m_child[0] = child_panel->m_child[0]; + m_child[1] = child_panel->m_child[1]; + + m_child[0]->m_parent = this; + m_child[1]->m_parent = this; + + m_add_child_target = NULL; + m_child[0]->m_container->Reparent(m_container); + m_child[1]->m_container->Reparent(m_container); + + child_panel->m_child[0] = child_panel->m_child[1] = NULL; + delete child_panel; + + wxSize size = m_container->GetSize(); + wxSize child_size = m_child[0]->m_container->GetSize(); + + ConstrainChildren(child_size.GetWidth() * 100 / size.GetWidth(), + child_size.GetHeight() * 100 / size.GetHeight()); + + m_container->Layout(); + } +} + +void wxDynamicSashWindowImpl::Split(int px, int py) { + m_window->Hide(); + + m_add_child_target = NULL; + + m_child[0] = new wxDynamicSashWindowImpl(m_window); + m_child[0]->m_container = new wxWindow(m_container, -1); + m_child[0]->m_parent = this; + m_child[0]->m_top = m_top; + m_child[0]->Create(); + if (m_leaf->m_child) { + m_leaf->m_child->Reparent(m_container); + m_child[0]->AddChild(m_leaf->m_child); + } + + m_child[1] = new wxDynamicSashWindowImpl(m_window); + m_child[1]->m_container = new wxWindow(m_container, -1); + m_child[1]->m_parent = this; + m_child[1]->m_top = m_top; + m_child[1]->Create(); + + m_split = m_dragging; + ConstrainChildren(px, py); + + m_top->m_add_child_target = m_child[1]; + wxDynamicSashSplitEvent split(m_child[0]->m_leaf->m_child); + m_child[0]->m_leaf->m_child->ProcessEvent(split); + + m_child[0]->m_leaf->m_vscroll->SetScrollbar(m_leaf->m_vscroll->GetThumbPosition(), + m_leaf->m_vscroll->GetThumbSize(), + m_leaf->m_vscroll->GetRange(), + m_leaf->m_vscroll->GetPageSize()); + m_child[0]->m_leaf->m_hscroll->SetScrollbar(m_leaf->m_hscroll->GetThumbPosition(), + m_leaf->m_hscroll->GetThumbSize(), + m_leaf->m_hscroll->GetRange(), + m_leaf->m_hscroll->GetPageSize()); + m_child[1]->m_leaf->m_vscroll->SetScrollbar(m_leaf->m_vscroll->GetThumbPosition(), + m_leaf->m_vscroll->GetThumbSize(), + m_leaf->m_vscroll->GetRange(), + m_leaf->m_vscroll->GetPageSize()); + m_child[1]->m_leaf->m_hscroll->SetScrollbar(m_leaf->m_hscroll->GetThumbPosition(), + m_leaf->m_hscroll->GetThumbSize(), + m_leaf->m_hscroll->GetRange(), + m_leaf->m_hscroll->GetPageSize()); + delete m_leaf; + m_leaf = NULL; + + m_container->Layout(); + + m_window->Show(); +} + +/* This code is called when you finish resizing a view by dragging the + corner tab, but I think this implementation is lousy and will surprise + the user more often than it will do what they are trying to do. What + I really need to be doing here is do a rewrite such that *no* sashes + move except the ones immediately to the bottom and right of this window, + and handle the case where you resize a window larger than it's neighbors + by destroying the neighbors. + + But this will do for now. */ +void wxDynamicSashWindowImpl::Resize(int x, int y) { + wxDynamicSashWindowImpl *h_parent = FindParent(DSR_BOTTOM_EDGE); + wxDynamicSashWindowImpl *v_parent = FindParent(DSR_RIGHT_EDGE); + int h_unify = -1; + int v_unify = -1; + wxWindow *frame = FindFrame(); + + if (x < 0) { + x = 0; + } + if (y < 0) { + y = 0; + } + + if (h_parent) { + m_container->ClientToScreen(NULL, &y); + h_parent->m_container->ScreenToClient(NULL, &y); + + int py = (int)((y * 100) / h_parent->m_container->GetSize().GetHeight() + 0.5); + + if (py < 10) { + wxDynamicSashWindowImpl *ho_parent = FindParent(DSR_TOP_EDGE); + + if (ho_parent) { + if (FindUpperParent(h_parent, ho_parent) == ho_parent) { + h_unify = 1; + } else { + py = (int)((ho_parent->m_child[0]->m_container->GetSize().GetHeight() * 100) + / h_parent->m_container->GetSize().GetHeight() + 0.5); + h_parent->m_child[0]->m_container->GetConstraints()->height.PercentOf( + h_parent->m_container, wxHeight, py); + + h_parent = ho_parent; + h_unify = 0; + } + } else { + h_unify = 1; + } + } else if (py > 90) { + h_unify = 0; + } else { + h_parent->m_child[0]->m_container->GetConstraints()->height.PercentOf( + h_parent->m_container, wxHeight, py); + h_parent->m_container->Layout(); + } + } else { + int do_resize = 1; + h_parent = FindParent(DSR_TOP_EDGE); + + if (h_parent) { + int py = (int)((y * 100) / + (h_parent->m_container->GetSize().GetHeight() + + y - m_container->GetSize().GetHeight()) + 0.5); + + if (py < 10) { + h_unify = 0; + } + } else if (y < 64) { + do_resize = 0; + } + + if (do_resize) { + wxSize size = frame->GetSize(); + frame->SetSize(size.GetWidth(), size.GetHeight() + y - m_container->GetSize().GetHeight()); + } + } + + if (v_parent) { + m_container->ClientToScreen(&x, NULL); + v_parent->m_container->ScreenToClient(&x, NULL); + + int px = (int)((x * 100) / v_parent->m_container->GetSize().GetWidth() + 0.5); + + if (px < 10) { + wxDynamicSashWindowImpl *vo_parent = FindParent(DSR_LEFT_EDGE); + + if (vo_parent) { + if (FindUpperParent(v_parent, vo_parent) == vo_parent) { + v_unify = 1; + } else { + px = (int)((vo_parent->m_child[0]->m_container->GetSize().GetWidth() * 100) + / v_parent->m_container->GetSize().GetWidth() + 0.5); + v_parent->m_child[0]->m_container->GetConstraints()->width.PercentOf( + v_parent->m_container, wxWidth, px); + + v_parent = vo_parent; + v_unify = 0; + } + } else { + v_unify = 1; + } + } else if (px > 90) { + v_unify = 0; + } else { + v_parent->m_child[0]->m_container->GetConstraints()->width.PercentOf( + v_parent->m_container, wxWidth, px); + v_parent->m_container->Layout(); + } + } else { + int do_resize = 1; + v_parent = FindParent(DSR_LEFT_EDGE); + + if (v_parent) { + int px = (int)((x * 100) / + (v_parent->m_container->GetSize().GetWidth() + + x - m_container->GetSize().GetWidth()) + 0.5); + + if (px < 10) { + v_unify = 0; + } + } else if (x < 64) { + do_resize = 0; + } + + if (do_resize) { + wxSize size = frame->GetSize(); + frame->SetSize(size.GetWidth() + x - m_container->GetSize().GetWidth(), size.GetHeight()); + } + } + + if (h_unify != -1 && v_unify != -1) { + wxDynamicSashWindowImpl *parent = FindUpperParent(h_parent, v_parent); + + if (parent == h_parent) { + h_parent->Unify(h_unify); + } else { + v_parent->Unify(v_unify); + } + } else if (h_unify != -1) { + h_parent->Unify(h_unify); + } else if (v_unify != -1) { + v_parent->Unify(v_unify); + } +} + + +void wxDynamicSashWindowImpl::OnSize(wxSizeEvent &event) { + m_container->Layout(); + + if (m_leaf) + m_leaf->OnSize(event); +} + +void wxDynamicSashWindowImpl::OnPaint(wxPaintEvent &event) { + if (m_leaf) + m_leaf->OnPaint(event); + else { + wxPaintDC dc(m_container); + dc.SetBackground(wxBrush(m_container->GetBackgroundColour(), wxSOLID)); + dc.Clear(); + } +} + +void wxDynamicSashWindowImpl::OnMouseMove(wxMouseEvent &event) { + if (m_dragging) { + DrawSash(m_drag_x, m_drag_y); + m_drag_x = event.m_x; m_drag_y = event.m_y; + DrawSash(m_drag_x, m_drag_y); + } else if (m_leaf) { + m_leaf->OnMouseMove(event); + } +} + +void wxDynamicSashWindowImpl::OnLeave(wxMouseEvent &event) { + if (m_leaf) { + m_leaf->OnLeave(event); + } +} + +void wxDynamicSashWindowImpl::OnPress(wxMouseEvent &event) { + if (m_leaf) { + m_leaf->OnPress(event); + } else { + m_dragging = m_split; + m_drag_x = event.m_x; + m_drag_y = event.m_y; + DrawSash(m_drag_x, m_drag_y); + m_container->CaptureMouse(); + } +} + +void wxDynamicSashWindowImpl::OnRelease(wxMouseEvent &event) { + if (m_dragging == DSR_CORNER) { + DrawSash(m_drag_x, m_drag_y); + m_container->ReleaseMouse(); + + Resize(event.m_x, event.m_y); + + m_dragging = DSR_NONE; + } else if (m_dragging) { + DrawSash(m_drag_x, m_drag_y); + m_container->ReleaseMouse(); + + wxSize size = m_container->GetSize(); + int px = (int)((event.m_x * 100) / size.GetWidth() + 0.5); + int py = (int)((event.m_y * 100) / size.GetHeight() + 0.5); + + if ((m_dragging == DSR_HORIZONTAL_TAB && py >= 10 && py <= 90) + || (m_dragging == DSR_VERTICAL_TAB && px >= 10 && px <= 90)) { + if (m_child[0] == NULL) { + Split(px, py); + } else { + /* It would be nice if moving *this* sash didn't implicitly move + the sashes of our children (if any). But this will do. */ + wxLayoutConstraints *layout = m_child[0]->m_container->GetConstraints(); + if (m_split == DSR_HORIZONTAL_TAB) { + layout->height.PercentOf(m_container, wxHeight, py); + } else { + layout->width.PercentOf(m_container, wxWidth, px); + } + m_container->Layout(); + } + } else { + if (m_child[0] != NULL) { + if ((m_dragging == DSR_HORIZONTAL_TAB && py <= 10) + || (m_dragging == DSR_VERTICAL_TAB && px <= 10)) { + Unify(1); + } else { + Unify(0); + } + } + } + + wxCursor cursor(wxCURSOR_ARROW); + if (m_split == DSR_HORIZONTAL_TAB) { + cursor = wxCursor(wxCURSOR_SIZENS); + } else if (m_split == DSR_VERTICAL_TAB) { + cursor = wxCursor(wxCURSOR_SIZEWE); + } + m_container->SetCursor(cursor); + + m_dragging = DSR_NONE; + } else if (m_leaf) { + m_leaf->OnRelease(event); + } +} + +// wxDynamicSashWindowLeaf ////////////////////////////////////////////////// + +wxDynamicSashWindowLeaf::wxDynamicSashWindowLeaf(wxDynamicSashWindowImpl *impl) { + m_impl = impl; + + m_hscroll = m_vscroll = NULL; + m_child = NULL; +} + +wxDynamicSashWindowLeaf::~wxDynamicSashWindowLeaf() { + m_hscroll->SetEventHandler(m_hscroll); + m_vscroll->SetEventHandler(m_vscroll); + m_viewport->SetEventHandler(m_viewport); + + m_hscroll->Destroy(); + m_vscroll->Destroy(); + m_viewport->Destroy(); +} + +bool wxDynamicSashWindowLeaf::Create() { + bool success; + + m_hscroll = new wxScrollBar(); + m_vscroll = new wxScrollBar(); + m_viewport = new wxWindow(); + + if (!m_hscroll || !m_vscroll || !m_viewport) { + return FALSE; + } + + wxDynamicSashWindowImpl *add_child_target = m_impl->m_add_child_target; + m_impl->m_add_child_target = NULL; + success = m_hscroll->Create(m_impl->m_container, -1, wxDefaultPosition, wxDefaultSize, + wxSB_HORIZONTAL); + success = success && m_vscroll->Create(m_impl->m_container, -1, wxDefaultPosition, wxDefaultSize, + wxSB_VERTICAL); + success = success && m_viewport->Create(m_impl->m_container, -1); + m_impl->m_add_child_target = add_child_target; + + wxCursor cursor(wxCURSOR_ARROW); + m_hscroll->SetCursor(cursor); + m_vscroll->SetCursor(cursor); + m_viewport->SetCursor(cursor); + + m_viewport->SetEventHandler(this); + Connect(-1, wxEVT_DYNAMIC_SASH_REPARENT, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnReparent); + + if (m_impl->m_window->GetWindowStyle() & wxMANAGE_SCROLLBARS) { + m_hscroll->SetEventHandler(this); + m_vscroll->SetEventHandler(this); + + Connect(-1, wxEVT_SET_FOCUS, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnFocus); + Connect(-1, wxEVT_SCROLL_TOP, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll); + Connect(-1, wxEVT_SCROLL_BOTTOM, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll); + Connect(-1, wxEVT_SCROLL_LINEUP, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll); + Connect(-1, wxEVT_SCROLL_LINEDOWN, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll); + Connect(-1, wxEVT_SCROLL_PAGEUP, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll); + Connect(-1, wxEVT_SCROLL_PAGEDOWN, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll); + Connect(-1, wxEVT_SCROLL_THUMBTRACK, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll); + Connect(-1, wxEVT_SCROLL_THUMBRELEASE, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll); + } + + wxLayoutConstraints *layout = new wxLayoutConstraints(); + if (!layout) + return FALSE; + wxSize size = m_hscroll->GetBestSize(); +#ifdef __WXMSW__ + size = m_hscroll->GetSize(); +#endif + + layout->left.SameAs(m_impl->m_container, wxLeft, 10); + layout->right.LeftOf(m_vscroll); + layout->bottom.SameAs(m_impl->m_container, wxBottom, 3); + layout->height.Absolute(size.GetHeight()); + m_hscroll->SetConstraints(layout); + + layout = new wxLayoutConstraints(); + if (!layout) + return FALSE; + size = size = m_vscroll->GetBestSize(); +#ifdef __WXMSW__ + size = m_vscroll->GetSize(); +#endif + + layout->top.SameAs(m_impl->m_container, wxTop, 10); + layout->bottom.Above(m_hscroll); + layout->right.SameAs(m_impl->m_container, wxRight, 3); + layout->width.Absolute(size.GetWidth()); + m_vscroll->SetConstraints(layout); + + layout = new wxLayoutConstraints(); + if (!layout) + return FALSE; + layout->left.SameAs(m_impl->m_container, wxLeft, 3); + layout->right.LeftOf(m_vscroll); + layout->top.SameAs(m_impl->m_container, wxTop, 3); + layout->bottom.Above(m_hscroll); + m_viewport->SetConstraints(layout); + + m_impl->m_container->Layout(); + + return success; +} + +void wxDynamicSashWindowLeaf::AddChild(wxWindow *window) { + if (m_child) { + m_child->Destroy(); + } + + m_child = window; + + wxDynamicSashReparentEvent event(this); + AddPendingEvent(event); +} + +DynamicSashRegion wxDynamicSashWindowLeaf::GetRegion(int x, int y) { + wxSize size = m_impl->m_container->GetSize(); + int w = size.GetWidth(); + int h = size.GetHeight(); + size = m_hscroll->GetSize(); + int sh = size.GetHeight(); + size = m_vscroll->GetSize(); + int sw = size.GetWidth(); + + if (x >= w - sw - 3 && x < w && y >= h - sh - 3 && y < h) + return DSR_CORNER; + if (x >= 3 && x < 10 && y >= h - sh - 3 && y < h - 2) + return DSR_VERTICAL_TAB; + if (x >= w - sw - 3 && x < w - 2 && y >= 3 && y < 10) + return DSR_HORIZONTAL_TAB; + if (x < 3) + return DSR_LEFT_EDGE; + if (y < 3) + return DSR_TOP_EDGE; + if (x >= w - 2) + return DSR_RIGHT_EDGE; + if (y >= h - 2) + return DSR_BOTTOM_EDGE; + + return DSR_NONE; +} + +void wxDynamicSashWindowLeaf::ResizeChild(wxSize size) { + if (m_child) { + if (m_impl->m_window->GetWindowStyle() & wxMANAGE_SCROLLBARS) { + m_child->SetSize(size); + wxSize best_size = m_child->GetBestSize(); + if (best_size.GetWidth() < size.GetWidth()) { + best_size.SetWidth(size.GetWidth()); + } + if (best_size.GetHeight() < size.GetHeight()) { + best_size.SetHeight(size.GetHeight()); + } + m_child->SetSize(best_size); + + int hpos = m_hscroll->GetThumbPosition(); + int vpos = m_vscroll->GetThumbPosition(); + + if (hpos < 0) { + hpos = 0; + } + if (vpos < 0) { + vpos = 0; + } + if (hpos > best_size.GetWidth() - size.GetWidth()) { + hpos = best_size.GetWidth() - size.GetWidth(); + } + if (vpos > best_size.GetHeight() - size.GetHeight()) { + vpos = best_size.GetHeight() - size.GetHeight(); + } + + m_hscroll->SetScrollbar(hpos, size.GetWidth(), + best_size.GetWidth(), size.GetWidth()); + m_vscroll->SetScrollbar(vpos, size.GetHeight(), + best_size.GetHeight(), size.GetHeight()); + + // Umm, the scrollbars are doing something insane under GTK+ and subtracting + // one from the position I pass in. This works around that. + m_hscroll->SetThumbPosition(hpos + hpos - m_hscroll->GetThumbPosition()); + m_vscroll->SetThumbPosition(vpos + vpos - m_vscroll->GetThumbPosition()); + + wxPoint pos = m_child->GetPosition(); + m_viewport->ScrollWindow(-hpos - pos.x, -vpos - pos.y); + } else { + m_child->SetSize(size); + } + } +} + +wxScrollBar *wxDynamicSashWindowLeaf::FindScrollBar(const wxWindow *child, int vert) const { + if (m_child == child) { + if (vert) { + return m_vscroll; + } else { + return m_hscroll; + } + } + + return NULL; +} + +void wxDynamicSashWindowLeaf::OnSize(wxSizeEvent &event) { + m_impl->m_container->Refresh(); + ResizeChild(m_viewport->GetSize()); +} + +void wxDynamicSashWindowLeaf::OnPaint(wxPaintEvent &event) { + wxPaintDC dc(m_impl->m_container); + dc.SetBackground(wxBrush(m_impl->m_container->GetBackgroundColour(), wxSOLID)); + dc.Clear(); + + wxPen highlight(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNHIGHLIGHT), 1, wxSOLID); + wxPen shadow(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNSHADOW), 1, wxSOLID); + wxPen black(*wxBLACK, 1, wxSOLID); + + wxSize size = m_impl->m_container->GetSize(); + int w = size.GetWidth(); + int h = size.GetHeight(); + size = m_hscroll->GetSize(); + int sh = size.GetHeight(); + size = m_vscroll->GetSize(); + int sw = size.GetWidth(); + + dc.SetPen(shadow); + dc.DrawLine(1, 1, 1, h - 2); + dc.DrawLine(1, 1, w - 2, 1); + dc.SetPen(black); + dc.DrawLine(2, 2, 2, h - 3); + dc.DrawLine(2, 2, w - 3, 2); + dc.SetPen(highlight); + dc.DrawLine(w - 2, 2, w - 2, h - sh - 2); + dc.DrawLine(w - 2, h - sh - 2, w - sw - 2, h - sh - 2); + dc.DrawLine(w - sw - 2, h - sh - 2, w - sw - 2, h - 2); + dc.DrawLine(w - sw - 2, h - 2, 2, h - 2); + + dc.SetPen(highlight); + dc.DrawLine(w - sw - 2, 8, w - sw - 2, 4); + dc.DrawLine(w - sw - 2, 4, w - 5, 4); + dc.SetPen(shadow); + dc.DrawLine(w - 5, 4, w - 5, 8); + dc.DrawLine(w - 5, 8, w - sw - 2, 8); + dc.SetPen(black); + dc.DrawLine(w - 4, 3, w - 4, 9); + dc.DrawLine(w - 4, 9, w - sw - 3, 9); + + dc.SetPen(highlight); + dc.DrawLine(4, h - 5, 4, h - sh - 2); + dc.DrawLine(4, h - sh - 2, 8, h - sh - 2); + dc.SetPen(shadow); + dc.DrawLine(8, h - sh - 2, 8, h - 5); + dc.DrawLine(8, h - 5, 4, h - 5); + dc.SetPen(black); + dc.DrawLine(9, h - sh - 3, 9, h - 4); + dc.DrawLine(9, h - 4, 3, h - 4); + + + int cy = (h - sh + h - 6) / 2 + 1; + int cx = (w - sw + w - 6) / 2 + 1; + int sy = cy; + while (sy > h - sh) + sy -= 4; + int sx = cx; + while (sx > w - sw) + sx -= 4; + + int x, y; + for (y = sy; y < h - 2; y += 4) { + for (x = sx; x < w - 2; x += 4) { + if (x - cx >= -(y - cy)) { + dc.SetPen(highlight); + dc.DrawPoint(x, y); + dc.SetPen(shadow); + dc.DrawPoint(x + 1, y + 1); + } + } + } +} + +void wxDynamicSashWindowLeaf::OnScroll(wxScrollEvent &event) { + int nx = -m_hscroll->GetThumbPosition(); + int ny = -m_vscroll->GetThumbPosition(); + + if (m_child) { + wxPoint pos = m_child->GetPosition(); + + m_viewport->ScrollWindow(nx - pos.x, ny - pos.y); + } +} + +void wxDynamicSashWindowLeaf::OnFocus(wxFocusEvent &event) { + if (event.m_eventObject == m_hscroll || event.m_eventObject == m_vscroll) { + m_child->SetFocus(); + } +} + + +void wxDynamicSashWindowLeaf::OnMouseMove(wxMouseEvent &event) { + if (m_impl->m_dragging) { + return; + } + + DynamicSashRegion region = GetRegion(event.m_x, event.m_y); + + wxCursor cursor(wxCURSOR_ARROW); + if (region == DSR_HORIZONTAL_TAB) { + cursor = wxCursor(wxCURSOR_SIZENS); + } else if (region == DSR_VERTICAL_TAB) { + cursor = wxCursor(wxCURSOR_SIZEWE); + } else if (region == DSR_CORNER) { + cursor = wxCursor(wxCURSOR_SIZENWSE); + } else if (region == DSR_LEFT_EDGE || region == DSR_TOP_EDGE + || region == DSR_RIGHT_EDGE || region == DSR_BOTTOM_EDGE) { + if (m_impl->FindParent(region)) { + if (region == DSR_LEFT_EDGE || region == DSR_RIGHT_EDGE) { + cursor = wxCursor(wxCURSOR_SIZEWE); + } else { + cursor = wxCursor(wxCURSOR_SIZENS); + } + } + } + + m_impl->m_container->SetCursor(cursor); +} + +void wxDynamicSashWindowLeaf::OnLeave(wxMouseEvent &event) { + wxCursor cursor(wxCURSOR_ARROW); + m_impl->m_container->SetCursor(cursor); +} + + +void wxDynamicSashWindowLeaf::OnPress(wxMouseEvent &event) { + DynamicSashRegion region = GetRegion(event.m_x, event.m_y); + + if (region == DSR_HORIZONTAL_TAB || region == DSR_VERTICAL_TAB || region == DSR_CORNER) { + m_impl->m_dragging = region; + m_impl->m_drag_x = event.m_x; + m_impl->m_drag_y = event.m_y; + m_impl->DrawSash(event.m_x, event.m_y); + m_impl->m_container->CaptureMouse(); + } else if (region == DSR_LEFT_EDGE || region == DSR_TOP_EDGE + || region == DSR_RIGHT_EDGE || region == DSR_BOTTOM_EDGE) { + wxDynamicSashWindowImpl *parent = m_impl->FindParent(region); + + if (parent) { + int x = event.m_x; + int y = event.m_y; + + m_impl->m_container->ClientToScreen(&x, &y); + parent->m_container->ScreenToClient(&x, &y); + + parent->m_dragging = parent->m_split; + parent->m_drag_x = x; + parent->m_drag_y = y; + parent->DrawSash(x, y); + parent->m_container->CaptureMouse(); + } + } +} + +void wxDynamicSashWindowLeaf::OnRelease(wxMouseEvent &event) { +} + +void wxDynamicSashWindowLeaf::OnReparent(wxEvent &event) { + if (m_child) { + m_child->Reparent(m_viewport); + } + + ResizeChild(m_viewport->GetSize()); +} + +// wxDynamicSashSplitEvent ////////////////////////////////////////////////// + +wxDynamicSashSplitEvent::wxDynamicSashSplitEvent() { + m_eventObject = NULL; + m_eventType = wxEVT_DYNAMIC_SASH_SPLIT; +} + +wxDynamicSashSplitEvent::wxDynamicSashSplitEvent(wxObject *object) { + m_eventObject = object; + m_eventType = wxEVT_DYNAMIC_SASH_SPLIT; +} + +IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashSplitEvent, wxCommandEvent) + +// wxDynamicSashUnifyEvent ////////////////////////////////////////////////// + +wxDynamicSashUnifyEvent::wxDynamicSashUnifyEvent() { + m_eventObject = NULL; + m_eventType = wxEVT_DYNAMIC_SASH_UNIFY; +} + +wxDynamicSashUnifyEvent::wxDynamicSashUnifyEvent(wxObject *object) { + m_eventObject = object; + m_eventType = wxEVT_DYNAMIC_SASH_UNIFY; +} + +IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashUnifyEvent, wxCommandEvent) + +// wxDynamicSsahReparentEvent /////////////////////////////////////////////// + +wxDynamicSashReparentEvent::wxDynamicSashReparentEvent() { + m_eventObject = NULL; + m_eventType = wxEVT_DYNAMIC_SASH_REPARENT; +} + +wxDynamicSashReparentEvent::wxDynamicSashReparentEvent(wxObject *object) { + m_eventObject = object; + m_eventType = wxEVT_DYNAMIC_SASH_REPARENT; +} + +IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashReparentEvent, wxEvent) + +///////////////////////////////////////////////////////////////////////////// diff --git a/contrib/src/gizmos/makefile.b32 b/contrib/src/gizmos/makefile.b32 index b50cd162da..75f719eb1e 100644 --- a/contrib/src/gizmos/makefile.b32 +++ b/contrib/src/gizmos/makefile.b32 @@ -11,7 +11,7 @@ WXDIR = $(WXWIN) LIBTARGET=$(WXDIR)\lib\gizmos.lib -OBJECTS = multicell.obj splittree.obj editlbox.obj +OBJECTS = multicell.obj splittree.obj editlbox.obj dynamicsash.obj !include $(WXDIR)\src\makelib.b32 diff --git a/contrib/src/gizmos/makefile.bcc b/contrib/src/gizmos/makefile.bcc index 052c8b09c0..a9cbb5a799 100644 --- a/contrib/src/gizmos/makefile.bcc +++ b/contrib/src/gizmos/makefile.bcc @@ -14,7 +14,7 @@ WXDIR = $(WXWIN) LIBTARGET=$(WXDIR)\lib\gizmos.lib -OBJECTS = multicell.obj splittree.obj editlbox.obj +OBJECTS = multicell.obj splittree.obj editlbox.obj dynamicsash.obj !include $(WXDIR)\src\makelib.bcc diff --git a/contrib/src/gizmos/makefile.g95 b/contrib/src/gizmos/makefile.g95 index e289454288..5b5237e9fc 100644 --- a/contrib/src/gizmos/makefile.g95 +++ b/contrib/src/gizmos/makefile.g95 @@ -10,7 +10,7 @@ WXDIR = ../../.. LIBTARGET=$(WXDIR)/lib/libgizmos.a -OBJECTS = multicell.o splittree.o editlbox.o +OBJECTS = multicell.o splittree.o editlbox.o dynamicsash.o include $(WXDIR)/src/makelib.g95 diff --git a/contrib/src/gizmos/makefile.unx b/contrib/src/gizmos/makefile.unx index c1fae75d2a..b070bc96af 100644 --- a/contrib/src/gizmos/makefile.unx +++ b/contrib/src/gizmos/makefile.unx @@ -16,7 +16,8 @@ LIB_CPP_SRC=\ \ multicell.o\ editlbox.o\ - splittree.o + splittree.o\ + dynamicsash.o all: $(GIZMOSLIB) diff --git a/contrib/src/gizmos/makefile.vc b/contrib/src/gizmos/makefile.vc index 7aef83ead2..a7d0f925f4 100644 --- a/contrib/src/gizmos/makefile.vc +++ b/contrib/src/gizmos/makefile.vc @@ -23,7 +23,7 @@ LOCALDOCDIR=$(WXDIR)\contrib\docs\latex\gizmos !include $(WXDIR)\src\makevc.env -OBJECTS = $(D)\multicell.obj $(D)\splittree.obj $(D)\editlbox.obj +OBJECTS = $(D)\multicell.obj $(D)\splittree.obj $(D)\editlbox.obj $(D)\dynamicsash.obj LIBTARGET=$(WXDIR)\lib\gizmos$(LIBEXT).lib @@ -65,6 +65,11 @@ $(D)\editlbox.obj: editlbox.$(SRCSUFF) $(CPPFLAGS) /c /Fo$@ /Tp $(*B).$(SRCSUFF) << +$(D)\dynamicsash.obj: dynamicsash.$(SRCSUFF) + cl @<< +$(CPPFLAGS) /c /Fo$@ /Tp $(*B).$(SRCSUFF) +<< + clean: -erase $(D)\*.obj -erase *.sbr diff --git a/contrib/src/gizmos/makefile.wat b/contrib/src/gizmos/makefile.wat index 0d01935c1f..3d3a85f6a4 100644 --- a/contrib/src/gizmos/makefile.wat +++ b/contrib/src/gizmos/makefile.wat @@ -10,7 +10,7 @@ THISDIR = $(WXDIR)\contrib\src\gizmos NAME = gizmos LNK = $(name).lnk -OBJECTS = multicell.obj splittree.obj editlbox.obj +OBJECTS = multicell.obj splittree.obj editlbox.obj dynamicsash.obj all: $(GIZMOSLIB) -- 2.45.2