From 3b84e35e38150b302bd237d2cd34b5461aee3d6c Mon Sep 17 00:00:00 2001 From: John Peterson Date: Tue, 25 Aug 2009 02:13:59 +0000 Subject: [PATCH] GUI: Added the wx_aui files git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4054 8ced0084-cf51-0410-be5f-012b33b47a6e --- Externals/wxWidgets/include/wx/aui/auibar.h | 684 +++ Externals/wxWidgets/src/aui/auibar.cpp | 2630 ++++++++++ Externals/wxWidgets/src/aui/auibook.cpp | 4602 ++++++++++++++++++ Externals/wxWidgets/src/aui/dockart.cpp | 771 +++ Externals/wxWidgets/src/aui/floatpane.cpp | 323 ++ Externals/wxWidgets/src/aui/framemanager.cpp | 4593 +++++++++++++++++ Externals/wxWidgets/src/aui/tabmdi.cpp | 837 ++++ 7 files changed, 14440 insertions(+) create mode 100644 Externals/wxWidgets/include/wx/aui/auibar.h create mode 100644 Externals/wxWidgets/src/aui/auibar.cpp create mode 100644 Externals/wxWidgets/src/aui/auibook.cpp create mode 100644 Externals/wxWidgets/src/aui/dockart.cpp create mode 100644 Externals/wxWidgets/src/aui/floatpane.cpp create mode 100644 Externals/wxWidgets/src/aui/framemanager.cpp create mode 100644 Externals/wxWidgets/src/aui/tabmdi.cpp diff --git a/Externals/wxWidgets/include/wx/aui/auibar.h b/Externals/wxWidgets/include/wx/aui/auibar.h new file mode 100644 index 0000000000..5ca0e23803 --- /dev/null +++ b/Externals/wxWidgets/include/wx/aui/auibar.h @@ -0,0 +1,684 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/aui/toolbar.h +// Purpose: wxaui: wx advanced user interface - docking window manager +// Author: Benjamin I. Williams +// Modified by: +// Created: 2008-08-04 +// RCS-ID: $Id: auibar.h 55522 2008-09-08 09:54:28Z BIW $ +// Copyright: (C) Copyright 2005, Kirix Corporation, All Rights Reserved. +// Licence: wxWindows Library Licence, Version 3.1 +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_AUIBAR_H_ +#define _WX_AUIBAR_H_ + +#include "wx/defs.h" + +#if wxUSE_AUI + +#if wxABI_VERSION >= 20809 + +#include "wx/control.h" + +enum wxAuiToolBarStyle +{ + wxAUI_TB_TEXT = 1 << 0, + wxAUI_TB_NO_TOOLTIPS = 1 << 1, + wxAUI_TB_NO_AUTORESIZE = 1 << 2, + wxAUI_TB_GRIPPER = 1 << 3, + wxAUI_TB_OVERFLOW = 1 << 4, + wxAUI_TB_VERTICAL = 1 << 5, + wxAUI_TB_HORZ_LAYOUT = 1 << 6, + wxAUI_TB_HORZ_TEXT = (wxAUI_TB_HORZ_LAYOUT | wxAUI_TB_TEXT), + wxAUI_TB_DEFAULT_STYLE = 0 +}; + +enum wxAuiToolBarArtSetting +{ + wxAUI_TBART_SEPARATOR_SIZE = 0, + wxAUI_TBART_GRIPPER_SIZE = 1, + wxAUI_TBART_OVERFLOW_SIZE = 2 +}; + +enum wxAuiToolBarToolTextOrientation +{ + wxAUI_TBTOOL_TEXT_LEFT = 0, // unused/unimplemented + wxAUI_TBTOOL_TEXT_RIGHT = 1, + wxAUI_TBTOOL_TEXT_TOP = 2, // unused/unimplemented + wxAUI_TBTOOL_TEXT_BOTTOM = 3 +}; + + +// aui toolbar event class + +class WXDLLIMPEXP_AUI wxAuiToolBarEvent : public wxNotifyEvent +{ +public: + wxAuiToolBarEvent(wxEventType command_type = wxEVT_NULL, + int win_id = 0) + : wxNotifyEvent(command_type, win_id) + { + is_dropdown_clicked = false; + click_pt = wxPoint(-1, -1); + rect = wxRect(-1,-1, 0, 0); + tool_id = -1; + } +#ifndef SWIG + wxAuiToolBarEvent(const wxAuiToolBarEvent& c) : wxNotifyEvent(c) + { + is_dropdown_clicked = c.is_dropdown_clicked; + click_pt = c.click_pt; + rect = c.rect; + tool_id = c.tool_id; + } +#endif + wxEvent *Clone() const { return new wxAuiToolBarEvent(*this); } + + bool IsDropDownClicked() const { return is_dropdown_clicked; } + void SetDropDownClicked(bool c) { is_dropdown_clicked = c; } + + wxPoint GetClickPoint() const { return click_pt; } + void SetClickPoint(const wxPoint& p) { click_pt = p; } + + wxRect GetItemRect() const { return rect; } + void SetItemRect(const wxRect& r) { rect = r; } + + int GetToolId() const { return tool_id; } + void SetToolId(int id) { tool_id = id; } + +private: + + bool is_dropdown_clicked; + wxPoint click_pt; + wxRect rect; + int tool_id; + +#ifndef SWIG +private: + DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxAuiToolBarEvent) +#endif +}; + + +class WXDLLIMPEXP_AUI wxAuiToolBarItem +{ + friend class wxAuiToolBar; + +public: + + wxAuiToolBarItem() + { + window = NULL; + sizer_item = NULL; + spacer_pixels = 0; + id = 0; + kind = wxITEM_NORMAL; + state = 0; // normal, enabled + proportion = 0; + active = true; + dropdown = true; + sticky = true; + user_data = 0; + } + + wxAuiToolBarItem(const wxAuiToolBarItem& c) + { + Assign(c); + } + + wxAuiToolBarItem& operator=(const wxAuiToolBarItem& c) + { + Assign(c); + return *this; + } + + void Assign(const wxAuiToolBarItem& c) + { + window = c.window; + label = c.label; + bitmap = c.bitmap; + disabled_bitmap = c.disabled_bitmap; + hover_bitmap = c.hover_bitmap; + short_help = c.short_help; + long_help = c.long_help; + sizer_item = c.sizer_item; + min_size = c.min_size; + spacer_pixels = c.spacer_pixels; + id = c.id; + kind = c.kind; + state = c.state; + proportion = c.proportion; + active = c.active; + dropdown = c.dropdown; + sticky = c.sticky; + user_data = c.user_data; + } + + + void SetWindow(wxWindow* w) { window = w; } + wxWindow* GetWindow() { return window; } + + void SetId(int new_id) { id = new_id; } + int GetId() const { return id; } + + void SetKind(int new_kind) { kind = new_kind; } + int GetKind() const { return kind; } + + void SetState(int new_state) { state = new_state; } + int GetState() const { return state; } + + void SetSizerItem(wxSizerItem* s) { sizer_item = s; } + wxSizerItem* GetSizerItem() const { return sizer_item; } + + void SetLabel(const wxString& s) { label = s; } + const wxString& GetLabel() const { return label; } + + void SetBitmap(const wxBitmap& bmp) { bitmap = bmp; } + const wxBitmap& GetBitmap() const { return bitmap; } + + void SetDisabledBitmap(const wxBitmap& bmp) { disabled_bitmap = bmp; } + const wxBitmap& GetDisabledBitmap() const { return disabled_bitmap; } + + void SetHoverBitmap(const wxBitmap& bmp) { hover_bitmap = bmp; } + const wxBitmap& GetHoverBitmap() const { return hover_bitmap; } + + void SetShortHelp(const wxString& s) { short_help = s; } + const wxString& GetShortHelp() const { return short_help; } + + void SetLongHelp(const wxString& s) { long_help = s; } + const wxString& GetLongHelp() const { return long_help; } + + void SetMinSize(const wxSize& s) { min_size = s; } + const wxSize& GetMinSize() const { return min_size; } + + void SetSpacerPixels(int s) { spacer_pixels = s; } + int GetSpacerPixels() const { return spacer_pixels; } + + void SetProportion(int p) { proportion = p; } + int GetProportion() const { return proportion; } + + void SetActive(bool b) { active = b; } + bool IsActive() const { return active; } + + void SetHasDropDown(bool b) { dropdown = b; } + bool HasDropDown() const { return dropdown; } + + void SetSticky(bool b) { sticky = b; } + bool IsSticky() const { return sticky; } + + void SetUserData(long l) { user_data = l; } + long GetUserData() const { return user_data; } + +private: + + wxWindow* window; // item's associated window + wxString label; // label displayed on the item + wxBitmap bitmap; // item's bitmap + wxBitmap disabled_bitmap; // item's disabled bitmap + wxBitmap hover_bitmap; // item's hover bitmap + wxString short_help; // short help (for tooltip) + wxString long_help; // long help (for status bar) + wxSizerItem* sizer_item; // sizer item + wxSize min_size; // item's minimum size + int spacer_pixels; // size of a spacer + int id; // item's id + int kind; // item's kind + int state; // state + int proportion; // proportion + bool active; // true if the item is currently active + bool dropdown; // true if the item has a dropdown button + bool sticky; // overrides button states if true (always active) + long user_data; // user-specified data +}; + +#ifndef SWIG +WX_DECLARE_USER_EXPORTED_OBJARRAY(wxAuiToolBarItem, wxAuiToolBarItemArray, WXDLLIMPEXP_AUI); +#endif + + + + +// tab art class + +class WXDLLIMPEXP_AUI wxAuiToolBarArt +{ +public: + + wxAuiToolBarArt() { } + virtual ~wxAuiToolBarArt() { } + + virtual wxAuiToolBarArt* Clone() = 0; + virtual void SetFlags(unsigned int flags) = 0; + virtual void SetFont(const wxFont& font) = 0; + virtual void SetTextOrientation(int orientation) = 0; + + virtual void DrawBackground( + wxDC& dc, + wxWindow* wnd, + const wxRect& rect) = 0; + + virtual void DrawLabel( + wxDC& dc, + wxWindow* wnd, + const wxAuiToolBarItem& item, + const wxRect& rect) = 0; + + virtual void DrawButton( + wxDC& dc, + wxWindow* wnd, + const wxAuiToolBarItem& item, + const wxRect& rect) = 0; + + virtual void DrawDropDownButton( + wxDC& dc, + wxWindow* wnd, + const wxAuiToolBarItem& item, + const wxRect& rect) = 0; + + virtual void DrawControlLabel( + wxDC& dc, + wxWindow* wnd, + const wxAuiToolBarItem& item, + const wxRect& rect) = 0; + + virtual void DrawSeparator( + wxDC& dc, + wxWindow* wnd, + const wxRect& rect) = 0; + + virtual void DrawGripper( + wxDC& dc, + wxWindow* wnd, + const wxRect& rect) = 0; + + virtual void DrawOverflowButton( + wxDC& dc, + wxWindow* wnd, + const wxRect& rect, + int state) = 0; + + virtual wxSize GetLabelSize( + wxDC& dc, + wxWindow* wnd, + const wxAuiToolBarItem& item) = 0; + + virtual wxSize GetToolSize( + wxDC& dc, + wxWindow* wnd, + const wxAuiToolBarItem& item) = 0; + + virtual int GetElementSize(int element_id) = 0; + virtual void SetElementSize(int element_id, int size) = 0; + + virtual int ShowDropDown( + wxWindow* wnd, + const wxAuiToolBarItemArray& items) = 0; +}; + + + +class WXDLLIMPEXP_AUI wxAuiDefaultToolBarArt : public wxAuiToolBarArt +{ + +public: + + wxAuiDefaultToolBarArt(); + virtual ~wxAuiDefaultToolBarArt(); + + virtual wxAuiToolBarArt* Clone(); + virtual void SetFlags(unsigned int flags); + virtual void SetFont(const wxFont& font); + virtual void SetTextOrientation(int orientation); + + virtual void DrawBackground( + wxDC& dc, + wxWindow* wnd, + const wxRect& rect); + + virtual void DrawLabel( + wxDC& dc, + wxWindow* wnd, + const wxAuiToolBarItem& item, + const wxRect& rect); + + virtual void DrawButton( + wxDC& dc, + wxWindow* wnd, + const wxAuiToolBarItem& item, + const wxRect& rect); + + virtual void DrawDropDownButton( + wxDC& dc, + wxWindow* wnd, + const wxAuiToolBarItem& item, + const wxRect& rect); + + virtual void DrawControlLabel( + wxDC& dc, + wxWindow* wnd, + const wxAuiToolBarItem& item, + const wxRect& rect); + + virtual void DrawSeparator( + wxDC& dc, + wxWindow* wnd, + const wxRect& rect); + + virtual void DrawGripper( + wxDC& dc, + wxWindow* wnd, + const wxRect& rect); + + virtual void DrawOverflowButton( + wxDC& dc, + wxWindow* wnd, + const wxRect& rect, + int state); + + virtual wxSize GetLabelSize( + wxDC& dc, + wxWindow* wnd, + const wxAuiToolBarItem& item); + + virtual wxSize GetToolSize( + wxDC& dc, + wxWindow* wnd, + const wxAuiToolBarItem& item); + + virtual int GetElementSize(int element); + virtual void SetElementSize(int element_id, int size); + + virtual int ShowDropDown(wxWindow* wnd, + const wxAuiToolBarItemArray& items); + +protected: + + wxBitmap m_button_dropdown_bmp; + wxBitmap m_disabled_button_dropdown_bmp; + wxBitmap m_overflow_bmp; + wxBitmap m_disabled_overflow_bmp; + wxColour m_base_colour; + wxColour m_highlight_colour; + wxFont m_font; + unsigned int m_flags; + int m_text_orientation; + + wxPen m_gripper_pen1; + wxPen m_gripper_pen2; + wxPen m_gripper_pen3; + + int m_separator_size; + int m_gripper_size; + int m_overflow_size; +}; + + + + +class WXDLLIMPEXP_AUI wxAuiToolBar : public wxControl +{ +public: + + wxAuiToolBar(wxWindow* parent, + wxWindowID id = -1, + const wxPoint& position = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxAUI_TB_DEFAULT_STYLE); + ~wxAuiToolBar(); + + void SetWindowStyleFlag(long style); + + void SetArtProvider(wxAuiToolBarArt* art); + wxAuiToolBarArt* GetArtProvider() const; + + bool SetFont(const wxFont& font); + + + void AddTool(int tool_id, + const wxString& label, + const wxBitmap& bitmap, + const wxString& short_help_string = wxEmptyString, + wxItemKind kind = wxITEM_NORMAL); + + void AddTool(int tool_id, + const wxString& label, + const wxBitmap& bitmap, + const wxBitmap& disabled_bitmap, + wxItemKind kind, + const wxString& short_help_string, + const wxString& long_help_string, + wxObject* client_data); + + void AddTool(int tool_id, + const wxBitmap& bitmap, + const wxBitmap& disabled_bitmap, + bool toggle = false, + wxObject* client_data = NULL, + const wxString& short_help_string = wxEmptyString, + const wxString& long_help_string = wxEmptyString) + { + AddTool(tool_id, + wxEmptyString, + bitmap, + disabled_bitmap, + toggle ? wxITEM_CHECK : wxITEM_NORMAL, + short_help_string, + long_help_string, + client_data); + } + + void AddLabel(int tool_id, + const wxString& label = wxEmptyString, + const int width = -1); + void AddControl(wxControl* control, + const wxString& label = wxEmptyString); + void AddSeparator(); + void AddSpacer(int pixels); + void AddStretchSpacer(int proportion = 1); + + bool Realize(); + + wxControl* FindControl(int window_id); + wxAuiToolBarItem* FindToolByPosition(wxCoord x, wxCoord y) const; + wxAuiToolBarItem* FindToolByIndex(int idx) const; + wxAuiToolBarItem* FindTool(int tool_id) const; + + void ClearTools() { Clear() ; } + void Clear(); + bool DeleteTool(int tool_id); + bool DeleteByIndex(int tool_id); + + size_t GetToolCount() const; + int GetToolPos(int tool_id) const { return GetToolIndex(tool_id); } + int GetToolIndex(int tool_id) const; + bool GetToolFits(int tool_id) const; + wxRect GetToolRect(int tool_id) const; + bool GetToolFitsByIndex(int tool_id) const; + bool GetToolBarFits() const; + + void SetMargins(const wxSize& size) { SetMargins(size.x, size.x, size.y, size.y); } + void SetMargins(int x, int y) { SetMargins(x, x, y, y); } + void SetMargins(int left, int right, int top, int bottom); + + void SetToolBitmapSize(const wxSize& size); + wxSize GetToolBitmapSize() const; + + bool GetOverflowVisible() const; + void SetOverflowVisible(bool visible); + + bool GetGripperVisible() const; + void SetGripperVisible(bool visible); + + void ToggleTool(int tool_id, bool state); + bool GetToolToggled(int tool_id) const; + + void EnableTool(int tool_id, bool state); + bool GetToolEnabled(int tool_id) const; + + void SetToolDropDown(int tool_id, bool dropdown); + bool GetToolDropDown(int tool_id) const; + + void SetToolBorderPadding(int padding); + int GetToolBorderPadding() const; + + void SetToolTextOrientation(int orientation); + int GetToolTextOrientation() const; + + void SetToolPacking(int packing); + int GetToolPacking() const; + + void SetToolProportion(int tool_id, int proportion); + int GetToolProportion(int tool_id) const; + + void SetToolSeparation(int separation); + int GetToolSeparation() const; + + void SetToolSticky(int tool_id, bool sticky); + bool GetToolSticky(int tool_id) const; + + wxString GetToolLabel(int tool_id) const; + void SetToolLabel(int tool_id, const wxString& label); + + wxBitmap GetToolBitmap(int tool_id) const; + void SetToolBitmap(int tool_id, const wxBitmap& bitmap); + + wxString GetToolShortHelp(int tool_id) const; + void SetToolShortHelp(int tool_id, const wxString& help_string); + + wxString GetToolLongHelp(int tool_id) const; + void SetToolLongHelp(int tool_id, const wxString& help_string); + + void SetCustomOverflowItems(const wxAuiToolBarItemArray& prepend, + const wxAuiToolBarItemArray& append); + +protected: + + virtual void OnCustomRender(wxDC& WXUNUSED(dc), + const wxAuiToolBarItem& WXUNUSED(item), + const wxRect& WXUNUSED(rect)) { } + +protected: + + void DoIdleUpdate(); + void SetOrientation(int orientation); + void SetHoverItem(wxAuiToolBarItem* item); + void SetPressedItem(wxAuiToolBarItem* item); + void RefreshOverflowState(); + + int GetOverflowState() const; + wxRect GetOverflowRect() const; + wxSize GetLabelSize(const wxString& label); + wxAuiToolBarItem* FindToolByPositionWithPacking(wxCoord x, wxCoord y) const; + + void DoSetSize(int x, + int y, + int width, + int height, + int sizeFlags = wxSIZE_AUTO); + +protected: // handlers + + void OnSize(wxSizeEvent& evt); + void OnIdle(wxIdleEvent& evt); + void OnPaint(wxPaintEvent& evt); + void OnEraseBackground(wxEraseEvent& evt); + void OnLeftDown(wxMouseEvent& evt); + void OnLeftUp(wxMouseEvent& evt); + void OnRightDown(wxMouseEvent& evt); + void OnRightUp(wxMouseEvent& evt); + void OnMiddleDown(wxMouseEvent& evt); + void OnMiddleUp(wxMouseEvent& evt); + void OnMotion(wxMouseEvent& evt); + void OnLeaveWindow(wxMouseEvent& evt); + void OnSetCursor(wxSetCursorEvent& evt); + +protected: + + wxAuiToolBarItemArray m_items; // array of toolbar items + wxAuiToolBarArt* m_art; // art provider + wxBoxSizer* m_sizer; // main sizer for toolbar + wxAuiToolBarItem* m_action_item; // item that's being acted upon (pressed) + wxAuiToolBarItem* m_tip_item; // item that has its tooltip shown + wxBitmap m_bitmap; // double-buffer bitmap + wxSizerItem* m_gripper_sizer_item; + wxSizerItem* m_overflow_sizer_item; + wxSize m_absolute_min_size; + wxPoint m_action_pos; // position of left-mouse down + wxAuiToolBarItemArray m_custom_overflow_prepend; + wxAuiToolBarItemArray m_custom_overflow_append; + + int m_button_width; + int m_button_height; + int m_sizer_element_count; + int m_left_padding; + int m_right_padding; + int m_top_padding; + int m_bottom_padding; + int m_tool_packing; + int m_tool_border_padding; + int m_tool_text_orientation; + int m_overflow_state; + bool m_dragging; + bool m_gripper_visible; + bool m_overflow_visible; + long m_style; + + DECLARE_EVENT_TABLE() + DECLARE_CLASS(wxAuiToolBar) +}; + + + + +// wx event machinery + +#ifndef SWIG + +BEGIN_DECLARE_EVENT_TYPES() + DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_AUI, wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, 0) + DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_AUI, wxEVT_COMMAND_AUITOOLBAR_OVERFLOW_CLICK, 0) + DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_AUI, wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK, 0) + DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_AUI, wxEVT_COMMAND_AUITOOLBAR_MIDDLE_CLICK, 0) + DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_AUI, wxEVT_COMMAND_AUITOOLBAR_BEGIN_DRAG, 0) +END_DECLARE_EVENT_TYPES() + +typedef void (wxEvtHandler::*wxAuiToolBarEventFunction)(wxAuiToolBarEvent&); + +#define wxAuiToolBarEventHandler(func) \ + (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxAuiToolBarEventFunction, &func) + +#define EVT_AUITOOLBAR_TOOL_DROPDOWN(winid, fn) \ + wx__DECLARE_EVT1(wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, winid, wxAuiToolBarEventHandler(fn)) +#define EVT_AUITOOLBAR_OVERFLOW_CLICK(winid, fn) \ + wx__DECLARE_EVT1(wxEVT_COMMAND_AUITOOLBAR_OVERFLOW_CLICK, winid, wxAuiToolBarEventHandler(fn)) +#define EVT_AUITOOLBAR_RIGHT_CLICK(winid, fn) \ + wx__DECLARE_EVT1(wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK, winid, wxAuiToolBarEventHandler(fn)) +#define EVT_AUITOOLBAR_MIDDLE_CLICK(winid, fn) \ + wx__DECLARE_EVT1(wxEVT_COMMAND_AUITOOLBAR_MIDDLE_CLICK, winid, wxAuiToolBarEventHandler(fn)) +#define EVT_AUITOOLBAR_BEGIN_DRAG(winid, fn) \ + wx__DECLARE_EVT1(wxEVT_COMMAND_AUITOOLBAR_BEGIN_DRAG, winid, wxAuiToolBarEventHandler(fn)) + +#else + +// wxpython/swig event work +%constant wxEventType wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN; +%constant wxEventType wxEVT_COMMAND_AUITOOLBAR_OVERFLOW_CLICK; +%constant wxEventType wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK; +%constant wxEventType wxEVT_COMMAND_AUITOOLBAR_MIDDLE_CLICK; +%constant wxEventType wxEVT_COMMAND_AUITOOLBAR_BEGIN_DRAG; + +%pythoncode { + EVT_AUITOOLBAR_TOOL_DROPDOWN = wx.PyEventBinder( wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, 1 ) + EVT_AUITOOLBAR_OVERFLOW_CLICK = wx.PyEventBinder( wxEVT_COMMAND_AUITOOLBAR_OVERFLOW_CLICK, 1 ) + EVT_AUITOOLBAR_RIGHT_CLICK = wx.PyEventBinder( wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK, 1 ) + EVT_AUITOOLBAR_MIDDLE_CLICK = wx.PyEventBinder( wxEVT_COMMAND_AUITOOLBAR_MIDDLE_CLICK, 1 ) + EVT_AUITOOLBAR_BEGIN_DRAG = wx.PyEventBinder( wxEVT_COMMAND_AUITOOLBAR_BEGIN_DRAG, 1 ) +} +#endif // SWIG + +#endif // wxABI_VERSION >= 20809 + +#endif // wxUSE_AUI + +#endif // _WX_AUIBAR_H_ + diff --git a/Externals/wxWidgets/src/aui/auibar.cpp b/Externals/wxWidgets/src/aui/auibar.cpp new file mode 100644 index 0000000000..fc6a547b50 --- /dev/null +++ b/Externals/wxWidgets/src/aui/auibar.cpp @@ -0,0 +1,2630 @@ +/////////////////////////////////////////////////////////////////////////////// + +// Name: src/aui/dockart.cpp +// Purpose: wxaui: wx advanced user interface - docking window manager +// Author: Benjamin I. Williams +// Modified by: +// Created: 2005-05-17 +// RCS-ID: $Id: auibar.cpp 55515 2008-09-07 18:38:38Z VZ $ +// Copyright: (C) Copyright 2005-2006, Kirix Corporation, All Rights Reserved +// Licence: wxWindows Library Licence, Version 3.1 +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_AUI + +#include "wx/statline.h" +#include "wx/dcbuffer.h" +#include "wx/sizer.h" +#include "wx/image.h" +#include "wx/settings.h" +#include "wx/menu.h" + +#include "wx/aui/auibar.h" +#include "wx/aui/framemanager.h" + +#ifdef __WXMAC__ +#include "wx/mac/carbon/private.h" +// for themeing support +#include +#endif + +#include "wx/arrimpl.cpp" +WX_DEFINE_OBJARRAY(wxAuiToolBarItemArray) + + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUITOOLBAR_OVERFLOW_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUITOOLBAR_MIDDLE_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUITOOLBAR_BEGIN_DRAG) + + +IMPLEMENT_CLASS(wxAuiToolBar, wxControl) +IMPLEMENT_DYNAMIC_CLASS(wxAuiToolBarEvent, wxEvent) + + +// missing wxITEM_* items +enum +{ + wxITEM_CONTROL = wxITEM_MAX, + wxITEM_LABEL, + wxITEM_SPACER +}; + +const int BUTTON_DROPDOWN_WIDTH = 10; + + +wxBitmap wxAuiBitmapFromBits(const unsigned char bits[], int w, int h, + const wxColour& color); + +unsigned char wxAuiBlendColour(unsigned char fg, unsigned char bg, double alpha); +wxColor wxAuiStepColour(const wxColor& c, int percent); + +static wxBitmap MakeDisabledBitmap(wxBitmap& bmp) +{ + wxImage image = bmp.ConvertToImage(); + + int mr, mg, mb; + mr = image.GetMaskRed(); + mg = image.GetMaskGreen(); + mb = image.GetMaskBlue(); + + unsigned char* data = image.GetData(); + int width = image.GetWidth(); + int height = image.GetHeight(); + bool has_mask = image.HasMask(); + + for (int y = height-1; y >= 0; --y) + { + for (int x = width-1; x >= 0; --x) + { + data = image.GetData() + (y*(width*3))+(x*3); + unsigned char* r = data; + unsigned char* g = data+1; + unsigned char* b = data+2; + + if (has_mask && *r == mr && *g == mg && *b == mb) + continue; + + *r = wxAuiBlendColour(*r, 255, 0.4); + *g = wxAuiBlendColour(*g, 255, 0.4); + *b = wxAuiBlendColour(*b, 255, 0.4); + } + } + + return wxBitmap(image); +} + +static wxColor GetBaseColor() +{ + +#if defined( __WXMAC__ ) && wxOSX_USE_COCOA_OR_CARBON + wxColor base_colour = wxColour( wxMacCreateCGColorFromHITheme(kThemeBrushToolbarBackground)); +#else + wxColor base_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE); +#endif + + // the base_colour is too pale to use as our base colour, + // so darken it a bit -- + if ((255-base_colour.Red()) + + (255-base_colour.Green()) + + (255-base_colour.Blue()) < 60) + { + base_colour = wxAuiStepColour(base_colour, 92); + } + + return base_colour; +} + + + +class ToolbarCommandCapture : public wxEvtHandler +{ +public: + + ToolbarCommandCapture() { m_last_id = 0; } + int GetCommandId() const { return m_last_id; } + + bool ProcessEvent(wxEvent& evt) + { + if (evt.GetEventType() == wxEVT_COMMAND_MENU_SELECTED) + { + m_last_id = evt.GetId(); + return true; + } + + if (GetNextHandler()) + return GetNextHandler()->ProcessEvent(evt); + + return false; + } + +private: + int m_last_id; +}; + + + +static const unsigned char + DISABLED_TEXT_GREY_HUE = wxAuiBlendColour(0, 255, 0.4); +const wxColour DISABLED_TEXT_COLOR(DISABLED_TEXT_GREY_HUE, + DISABLED_TEXT_GREY_HUE, + DISABLED_TEXT_GREY_HUE); + +wxAuiDefaultToolBarArt::wxAuiDefaultToolBarArt() +{ + m_base_colour = GetBaseColor(); + + m_flags = 0; + m_text_orientation = wxAUI_TBTOOL_TEXT_BOTTOM; + m_highlight_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); + + m_separator_size = 7; + m_gripper_size = 7; + m_overflow_size = 16; + + wxColor darker1_colour = wxAuiStepColour(m_base_colour, 85); + wxColor darker2_colour = wxAuiStepColour(m_base_colour, 75); + wxColor darker3_colour = wxAuiStepColour(m_base_colour, 60); + wxColor darker4_colour = wxAuiStepColour(m_base_colour, 50); + wxColor darker5_colour = wxAuiStepColour(m_base_colour, 40); + + m_gripper_pen1 = wxPen(darker5_colour); + m_gripper_pen2 = wxPen(darker3_colour); + m_gripper_pen3 = *wxWHITE_PEN; + + static unsigned char button_dropdown_bits[] = { 0xe0, 0xf1, 0xfb }; + static unsigned char overflow_bits[] = { 0x80, 0xff, 0x80, 0xc1, 0xe3, 0xf7 }; + + m_button_dropdown_bmp = wxAuiBitmapFromBits(button_dropdown_bits, 5, 3, + *wxBLACK); + m_disabled_button_dropdown_bmp = wxAuiBitmapFromBits( + button_dropdown_bits, 5, 3, + wxColor(128,128,128)); + m_overflow_bmp = wxAuiBitmapFromBits(overflow_bits, 7, 6, *wxBLACK); + m_disabled_overflow_bmp = wxAuiBitmapFromBits(overflow_bits, 7, 6, wxColor(128,128,128)); + + m_font = *wxNORMAL_FONT; +} + +wxAuiDefaultToolBarArt::~wxAuiDefaultToolBarArt() +{ + m_font = *wxNORMAL_FONT; +} + + +wxAuiToolBarArt* wxAuiDefaultToolBarArt::Clone() +{ + return static_cast(new wxAuiDefaultToolBarArt); +} + +void wxAuiDefaultToolBarArt::SetFlags(unsigned int flags) +{ + m_flags = flags; +} + +void wxAuiDefaultToolBarArt::SetFont(const wxFont& font) +{ + m_font = font; +} + +void wxAuiDefaultToolBarArt::SetTextOrientation(int orientation) +{ + m_text_orientation = orientation; +} + +void wxAuiDefaultToolBarArt::DrawBackground( + wxDC& dc, + wxWindow* WXUNUSED(wnd), + const wxRect& _rect) +{ + wxRect rect = _rect; + rect.height++; + wxColour start_colour = wxAuiStepColour(m_base_colour, 150); + wxColour end_colour = wxAuiStepColour(m_base_colour, 90); + dc.GradientFillLinear(rect, start_colour, end_colour, wxSOUTH); +} + +void wxAuiDefaultToolBarArt::DrawLabel( + wxDC& dc, + wxWindow* WXUNUSED(wnd), + const wxAuiToolBarItem& item, + const wxRect& rect) +{ + dc.SetFont(m_font); + dc.SetTextForeground(*wxBLACK); + + // we only care about the text height here since the text + // will get cropped based on the width of the item + int text_width = 0, text_height = 0; + dc.GetTextExtent(wxT("ABCDHgj"), &text_width, &text_height); + + // set the clipping region + wxRect clip_rect = rect; + clip_rect.width -= 1; + dc.SetClippingRegion(clip_rect); + + int text_x, text_y; + text_x = rect.x + 1; + text_y = rect.y + (rect.height-text_height)/2; + dc.DrawText(item.GetLabel(), text_x, text_y); + dc.DestroyClippingRegion(); +} + + +void wxAuiDefaultToolBarArt::DrawButton( + wxDC& dc, + wxWindow* WXUNUSED(wnd), + const wxAuiToolBarItem& item, + const wxRect& rect) +{ + int text_width = 0, text_height = 0; + + if (m_flags & wxAUI_TB_TEXT) + { + dc.SetFont(m_font); + + int tx, ty; + + dc.GetTextExtent(wxT("ABCDHgj"), &tx, &text_height); + text_width = 0; + dc.GetTextExtent(item.GetLabel(), &text_width, &ty); + } + + int bmp_x = 0, bmp_y = 0; + int text_x = 0, text_y = 0; + + if (m_text_orientation == wxAUI_TBTOOL_TEXT_BOTTOM) + { + bmp_x = rect.x + + (rect.width/2) - + (item.GetBitmap().GetWidth()/2); + + bmp_y = rect.y + + ((rect.height-text_height)/2) - + (item.GetBitmap().GetHeight()/2); + + text_x = rect.x + (rect.width/2) - (text_width/2) + 1; + text_y = rect.y + rect.height - text_height - 1; + } + else if (m_text_orientation == wxAUI_TBTOOL_TEXT_RIGHT) + { + bmp_x = rect.x + 3; + + bmp_y = rect.y + + (rect.height/2) - + (item.GetBitmap().GetHeight()/2); + + text_x = bmp_x + 3 + item.GetBitmap().GetWidth(); + text_y = rect.y + + (rect.height/2) - + (text_height/2); + } + + + if (!(item.GetState() & wxAUI_BUTTON_STATE_DISABLED)) + { + if (item.GetState() & wxAUI_BUTTON_STATE_PRESSED) + { + dc.SetPen(wxPen(m_highlight_colour)); + dc.SetBrush(wxBrush(wxAuiStepColour(m_highlight_colour, 150))); + dc.DrawRectangle(rect); + } + else if ((item.GetState() & wxAUI_BUTTON_STATE_HOVER) || item.IsSticky()) + { + dc.SetPen(wxPen(m_highlight_colour)); + dc.SetBrush(wxBrush(wxAuiStepColour(m_highlight_colour, 170))); + + // draw an even lighter background for checked item hovers (since + // the hover background is the same color as the check background) + if (item.GetState() & wxAUI_BUTTON_STATE_CHECKED) + dc.SetBrush(wxBrush(wxAuiStepColour(m_highlight_colour, 180))); + + dc.DrawRectangle(rect); + } + else if (item.GetState() & wxAUI_BUTTON_STATE_CHECKED) + { + // it's important to put this code in an else statment after the + // hover, otherwise hovers won't draw properly for checked items + dc.SetPen(wxPen(m_highlight_colour)); + dc.SetBrush(wxBrush(wxAuiStepColour(m_highlight_colour, 170))); + dc.DrawRectangle(rect); + } + } + + wxBitmap bmp; + if (item.GetState() & wxAUI_BUTTON_STATE_DISABLED) + bmp = item.GetDisabledBitmap(); + else + bmp = item.GetBitmap(); + + if (!bmp.IsOk()) + return; + + dc.DrawBitmap(bmp, bmp_x, bmp_y, true); + + // set the item's text color based on if it is disabled + dc.SetTextForeground(*wxBLACK); + if (item.GetState() & wxAUI_BUTTON_STATE_DISABLED) + dc.SetTextForeground(DISABLED_TEXT_COLOR); + + if ( (m_flags & wxAUI_TB_TEXT) && !item.GetLabel().empty() ) + { + dc.DrawText(item.GetLabel(), text_x, text_y); + } +} + + +void wxAuiDefaultToolBarArt::DrawDropDownButton( + wxDC& dc, + wxWindow* WXUNUSED(wnd), + const wxAuiToolBarItem& item, + const wxRect& rect) +{ + int text_width = 0, text_height = 0, text_x = 0, text_y = 0; + int bmp_x = 0, bmp_y = 0, dropbmp_x = 0, dropbmp_y = 0; + + wxRect button_rect = wxRect(rect.x, + rect.y, + rect.width-BUTTON_DROPDOWN_WIDTH, + rect.height); + wxRect dropdown_rect = wxRect(rect.x+rect.width-BUTTON_DROPDOWN_WIDTH-1, + rect.y, + BUTTON_DROPDOWN_WIDTH+1, + rect.height); + + if (m_flags & wxAUI_TB_TEXT) + { + dc.SetFont(m_font); + + int tx, ty; + if (m_flags & wxAUI_TB_TEXT) + { + dc.GetTextExtent(wxT("ABCDHgj"), &tx, &text_height); + text_width = 0; + } + + dc.GetTextExtent(item.GetLabel(), &text_width, &ty); + } + + + + dropbmp_x = dropdown_rect.x + + (dropdown_rect.width/2) - + (m_button_dropdown_bmp.GetWidth()/2); + dropbmp_y = dropdown_rect.y + + (dropdown_rect.height/2) - + (m_button_dropdown_bmp.GetHeight()/2); + + + if (m_text_orientation == wxAUI_TBTOOL_TEXT_BOTTOM) + { + bmp_x = button_rect.x + + (button_rect.width/2) - + (item.GetBitmap().GetWidth()/2); + bmp_y = button_rect.y + + ((button_rect.height-text_height)/2) - + (item.GetBitmap().GetHeight()/2); + + text_x = rect.x + (rect.width/2) - (text_width/2) + 1; + text_y = rect.y + rect.height - text_height - 1; + } + else if (m_text_orientation == wxAUI_TBTOOL_TEXT_RIGHT) + { + bmp_x = rect.x + 3; + + bmp_y = rect.y + + (rect.height/2) - + (item.GetBitmap().GetHeight()/2); + + text_x = bmp_x + 3 + item.GetBitmap().GetWidth(); + text_y = rect.y + + (rect.height/2) - + (text_height/2); + } + + + if (item.GetState() & wxAUI_BUTTON_STATE_PRESSED) + { + dc.SetPen(wxPen(m_highlight_colour)); + dc.SetBrush(wxBrush(wxAuiStepColour(m_highlight_colour, 140))); + dc.DrawRectangle(button_rect); + dc.DrawRectangle(dropdown_rect); + } + else if (item.GetState() & wxAUI_BUTTON_STATE_HOVER || + item.IsSticky()) + { + dc.SetPen(wxPen(m_highlight_colour)); + dc.SetBrush(wxBrush(wxAuiStepColour(m_highlight_colour, 170))); + dc.DrawRectangle(button_rect); + dc.DrawRectangle(dropdown_rect); + } + + wxBitmap bmp; + wxBitmap dropbmp; + if (item.GetState() & wxAUI_BUTTON_STATE_DISABLED) + { + bmp = item.GetDisabledBitmap(); + dropbmp = m_disabled_button_dropdown_bmp; + } + else + { + bmp = item.GetBitmap(); + dropbmp = m_button_dropdown_bmp; + } + + if (!bmp.IsOk()) + return; + + dc.DrawBitmap(bmp, bmp_x, bmp_y, true); + dc.DrawBitmap(dropbmp, dropbmp_x, dropbmp_y, true); + + // set the item's text color based on if it is disabled + dc.SetTextForeground(*wxBLACK); + if (item.GetState() & wxAUI_BUTTON_STATE_DISABLED) + dc.SetTextForeground(DISABLED_TEXT_COLOR); + + if ( (m_flags & wxAUI_TB_TEXT) && !item.GetLabel().empty() ) + { + dc.DrawText(item.GetLabel(), text_x, text_y); + } +} + +void wxAuiDefaultToolBarArt::DrawControlLabel( + wxDC& dc, + wxWindow* WXUNUSED(wnd), + const wxAuiToolBarItem& item, + const wxRect& rect) +{ + if (!(m_flags & wxAUI_TB_TEXT)) + return; + + if (m_text_orientation != wxAUI_TBTOOL_TEXT_BOTTOM) + return; + + int text_x = 0, text_y = 0; + int text_width = 0, text_height = 0; + + dc.SetFont(m_font); + + int tx, ty; + if (m_flags & wxAUI_TB_TEXT) + { + dc.GetTextExtent(wxT("ABCDHgj"), &tx, &text_height); + text_width = 0; + } + + dc.GetTextExtent(item.GetLabel(), &text_width, &ty); + + // don't draw the label if it is wider than the item width + if (text_width > rect.width) + return; + + // set the label's text color + dc.SetTextForeground(*wxBLACK); + + text_x = rect.x + (rect.width/2) - (text_width/2) + 1; + text_y = rect.y + rect.height - text_height - 1; + + if ( (m_flags & wxAUI_TB_TEXT) && !item.GetLabel().empty() ) + { + dc.DrawText(item.GetLabel(), text_x, text_y); + } +} + +wxSize wxAuiDefaultToolBarArt::GetLabelSize( + wxDC& dc, + wxWindow* WXUNUSED(wnd), + const wxAuiToolBarItem& item) +{ + dc.SetFont(m_font); + + // get label's height + int width = 0, height = 0; + dc.GetTextExtent(wxT("ABCDHgj"), &width, &height); + + // get item's width + width = item.GetMinSize().GetWidth(); + + return wxSize(width, height); +} + +wxSize wxAuiDefaultToolBarArt::GetToolSize( + wxDC& dc, + wxWindow* WXUNUSED(wnd), + const wxAuiToolBarItem& item) +{ + if (!item.GetBitmap().IsOk() && !(m_flags & wxAUI_TB_TEXT)) + return wxSize(16,16); + + int width = item.GetBitmap().GetWidth(); + int height = item.GetBitmap().GetHeight(); + + if (m_flags & wxAUI_TB_TEXT) + { + dc.SetFont(m_font); + int tx, ty; + + if (m_text_orientation == wxAUI_TBTOOL_TEXT_BOTTOM) + { + dc.GetTextExtent(wxT("ABCDHgj"), &tx, &ty); + height += ty; + + if ( !item.GetLabel().empty() ) + { + dc.GetTextExtent(item.GetLabel(), &tx, &ty); + width = wxMax(width, tx+6); + } + } + else if ( m_text_orientation == wxAUI_TBTOOL_TEXT_RIGHT && + !item.GetLabel().empty() ) + { + width += 3; // space between left border and bitmap + width += 3; // space between bitmap and text + + if ( !item.GetLabel().empty() ) + { + dc.GetTextExtent(item.GetLabel(), &tx, &ty); + width += tx; + height = wxMax(height, ty); + } + } + } + + // if the tool has a dropdown button, add it to the width + if (item.HasDropDown()) + width += (BUTTON_DROPDOWN_WIDTH+4); + + return wxSize(width, height); +} + +void wxAuiDefaultToolBarArt::DrawSeparator( + wxDC& dc, + wxWindow* WXUNUSED(wnd), + const wxRect& _rect) +{ + bool horizontal = true; + if (m_flags & wxAUI_TB_VERTICAL) + horizontal = false; + + wxRect rect = _rect; + + if (horizontal) + { + rect.x += (rect.width/2); + rect.width = 1; + int new_height = (rect.height*3)/4; + rect.y += (rect.height/2) - (new_height/2); + rect.height = new_height; + } + else + { + rect.y += (rect.height/2); + rect.height = 1; + int new_width = (rect.width*3)/4; + rect.x += (rect.width/2) - (new_width/2); + rect.width = new_width; + } + + wxColour start_colour = wxAuiStepColour(m_base_colour, 80); + wxColour end_colour = wxAuiStepColour(m_base_colour, 80); + dc.GradientFillLinear(rect, start_colour, end_colour, horizontal ? wxSOUTH : wxEAST); +} + +void wxAuiDefaultToolBarArt::DrawGripper(wxDC& dc, + wxWindow* WXUNUSED(wnd), + const wxRect& rect) +{ + int i = 0; + while (1) + { + int x, y; + + if (m_flags & wxAUI_TB_VERTICAL) + { + x = rect.x + (i*4) + 5; + y = rect.y + 3; + if (x > rect.GetWidth()-5) + break; + } + else + { + x = rect.x + 3; + y = rect.y + (i*4) + 5; + if (y > rect.GetHeight()-5) + break; + } + + dc.SetPen(m_gripper_pen1); + dc.DrawPoint(x, y); + dc.SetPen(m_gripper_pen2); + dc.DrawPoint(x, y+1); + dc.DrawPoint(x+1, y); + dc.SetPen(m_gripper_pen3); + dc.DrawPoint(x+2, y+1); + dc.DrawPoint(x+2, y+2); + dc.DrawPoint(x+1, y+2); + + i++; + } + +} + +void wxAuiDefaultToolBarArt::DrawOverflowButton(wxDC& dc, + wxWindow* wnd, + const wxRect& rect, + int state) +{ + if (state & wxAUI_BUTTON_STATE_HOVER || + state & wxAUI_BUTTON_STATE_PRESSED) + { + wxRect cli_rect = wnd->GetClientRect(); + wxColor light_gray_bg = wxAuiStepColour(m_highlight_colour, 170); + + if (m_flags & wxAUI_TB_VERTICAL) + { + dc.SetPen(wxPen(m_highlight_colour)); + dc.DrawLine(rect.x, rect.y, rect.x+rect.width, rect.y); + dc.SetPen(wxPen(light_gray_bg)); + dc.SetBrush(wxBrush(light_gray_bg)); + dc.DrawRectangle(rect.x, rect.y+1, rect.width, rect.height); + } + else + { + dc.SetPen(wxPen(m_highlight_colour)); + dc.DrawLine(rect.x, rect.y, rect.x, rect.y+rect.height); + dc.SetPen(wxPen(light_gray_bg)); + dc.SetBrush(wxBrush(light_gray_bg)); + dc.DrawRectangle(rect.x+1, rect.y, rect.width, rect.height); + } + } + + int x = rect.x+1+(rect.width-m_overflow_bmp.GetWidth())/2; + int y = rect.y+1+(rect.height-m_overflow_bmp.GetHeight())/2; + dc.DrawBitmap(m_overflow_bmp, x, y, true); +} + +int wxAuiDefaultToolBarArt::GetElementSize(int element_id) +{ + switch (element_id) + { + case wxAUI_TBART_SEPARATOR_SIZE: return m_separator_size; + case wxAUI_TBART_GRIPPER_SIZE: return m_gripper_size; + case wxAUI_TBART_OVERFLOW_SIZE: return m_overflow_size; + default: return 0; + } +} + +void wxAuiDefaultToolBarArt::SetElementSize(int element_id, int size) +{ + switch (element_id) + { + case wxAUI_TBART_SEPARATOR_SIZE: m_separator_size = size; + case wxAUI_TBART_GRIPPER_SIZE: m_gripper_size = size; + case wxAUI_TBART_OVERFLOW_SIZE: m_overflow_size = size; + } +} + +int wxAuiDefaultToolBarArt::ShowDropDown(wxWindow* wnd, + const wxAuiToolBarItemArray& items) +{ + wxMenu menuPopup; + + size_t items_added = 0; + + size_t i, count = items.GetCount(); + for (i = 0; i < count; ++i) + { + wxAuiToolBarItem& item = items.Item(i); + + if (item.GetKind() == wxITEM_NORMAL) + { + wxString text = item.GetShortHelp(); + if (text.empty()) + text = item.GetLabel(); + + if (text.empty()) + text = wxT(" "); + + wxMenuItem* m = new wxMenuItem(&menuPopup, item.GetId(), text, item.GetShortHelp()); + + m->SetBitmap(item.GetBitmap()); + menuPopup.Append(m); + items_added++; + } + else if (item.GetKind() == wxITEM_SEPARATOR) + { + if (items_added > 0) + menuPopup.AppendSeparator(); + } + } + + // find out where to put the popup menu of window items + wxPoint pt = ::wxGetMousePosition(); + pt = wnd->ScreenToClient(pt); + + // find out the screen coordinate at the bottom of the tab ctrl + wxRect cli_rect = wnd->GetClientRect(); + pt.y = cli_rect.y + cli_rect.height; + + ToolbarCommandCapture* cc = new ToolbarCommandCapture; + wnd->PushEventHandler(cc); + wnd->PopupMenu(&menuPopup, pt); + int command = cc->GetCommandId(); + wnd->PopEventHandler(true); + + return command; +} + + + + +BEGIN_EVENT_TABLE(wxAuiToolBar, wxControl) + EVT_SIZE(wxAuiToolBar::OnSize) + EVT_IDLE(wxAuiToolBar::OnIdle) + EVT_ERASE_BACKGROUND(wxAuiToolBar::OnEraseBackground) + EVT_PAINT(wxAuiToolBar::OnPaint) + EVT_LEFT_DOWN(wxAuiToolBar::OnLeftDown) + EVT_LEFT_DCLICK(wxAuiToolBar::OnLeftDown) + EVT_LEFT_UP(wxAuiToolBar::OnLeftUp) + EVT_RIGHT_DOWN(wxAuiToolBar::OnRightDown) + EVT_RIGHT_DCLICK(wxAuiToolBar::OnRightDown) + EVT_RIGHT_UP(wxAuiToolBar::OnRightUp) + EVT_MIDDLE_DOWN(wxAuiToolBar::OnMiddleDown) + EVT_MIDDLE_DCLICK(wxAuiToolBar::OnMiddleDown) + EVT_MIDDLE_UP(wxAuiToolBar::OnMiddleUp) + EVT_MOTION(wxAuiToolBar::OnMotion) + EVT_LEAVE_WINDOW(wxAuiToolBar::OnLeaveWindow) + EVT_SET_CURSOR(wxAuiToolBar::OnSetCursor) +END_EVENT_TABLE() + + +wxAuiToolBar::wxAuiToolBar(wxWindow* parent, + wxWindowID id, + const wxPoint& position, + const wxSize& size, + long style) + : wxControl(parent, + id, + position, + size, + style | wxBORDER_NONE) +{ + m_sizer = new wxBoxSizer(wxHORIZONTAL); + m_button_width = -1; + m_button_height = -1; + m_sizer_element_count = 0; + m_action_pos = wxPoint(-1,-1); + m_action_item = NULL; + m_tip_item = NULL; + m_art = new wxAuiDefaultToolBarArt; + m_tool_packing = 2; + m_tool_border_padding = 3; + m_tool_text_orientation = wxAUI_TBTOOL_TEXT_BOTTOM; + m_gripper_sizer_item = NULL; + m_overflow_sizer_item = NULL; + m_dragging = false; + m_style = style; + m_gripper_visible = (m_style & wxAUI_TB_GRIPPER) ? true : false; + m_overflow_visible = (m_style & wxAUI_TB_OVERFLOW) ? true : false; + m_overflow_state = 0; + SetMargins(5, 5, 2, 2); + SetFont(*wxNORMAL_FONT); + m_art->SetFlags((unsigned int)m_style); + SetExtraStyle(wxWS_EX_PROCESS_IDLE); + if (style & wxAUI_TB_HORZ_LAYOUT) + SetToolTextOrientation(wxAUI_TBTOOL_TEXT_RIGHT); +} + + +wxAuiToolBar::~wxAuiToolBar() +{ + delete m_art; + delete m_sizer; +} + +void wxAuiToolBar::SetWindowStyleFlag(long style) +{ + wxControl::SetWindowStyleFlag(style); + + m_style = style; + + if (m_art) + { + m_art->SetFlags((unsigned int)m_style); + } + + if (m_style & wxAUI_TB_GRIPPER) + m_gripper_visible = true; + else + m_gripper_visible = false; + + + if (m_style & wxAUI_TB_OVERFLOW) + m_overflow_visible = true; + else + m_overflow_visible = false; + + if (style & wxAUI_TB_HORZ_LAYOUT) + SetToolTextOrientation(wxAUI_TBTOOL_TEXT_RIGHT); + else + SetToolTextOrientation(wxAUI_TBTOOL_TEXT_BOTTOM); +} + + +void wxAuiToolBar::SetArtProvider(wxAuiToolBarArt* art) +{ + delete m_art; + + m_art = art; + + if (m_art) + { + m_art->SetFlags((unsigned int)m_style); + m_art->SetTextOrientation(m_tool_text_orientation); + } +} + +wxAuiToolBarArt* wxAuiToolBar::GetArtProvider() const +{ + return m_art; +} + + + + +void wxAuiToolBar::AddTool(int tool_id, + const wxString& label, + const wxBitmap& bitmap, + const wxString& short_help_string, + wxItemKind kind) +{ + AddTool(tool_id, + label, + bitmap, + wxNullBitmap, + kind, + short_help_string, + wxEmptyString, + NULL); +} + + +void wxAuiToolBar::AddTool(int tool_id, + const wxString& label, + const wxBitmap& bitmap, + const wxBitmap& disabled_bitmap, + wxItemKind kind, + const wxString& short_help_string, + const wxString& long_help_string, + wxObject* WXUNUSED(client_data)) +{ + wxAuiToolBarItem item; + item.window = NULL; + item.label = label; + item.bitmap = bitmap; + item.disabled_bitmap = disabled_bitmap; + item.short_help = short_help_string; + item.long_help = long_help_string; + item.active = true; + item.dropdown = false; + item.spacer_pixels = 0; + item.id = tool_id; + item.state = 0; + item.proportion = 0; + item.kind = kind; + item.sizer_item = NULL; + item.min_size = wxDefaultSize; + item.user_data = 0; + item.sticky = false; + + if (!item.disabled_bitmap.IsOk()) + { + // no disabled bitmap specified, we need to make one + if (item.bitmap.IsOk()) + { + //wxImage img = item.bitmap.ConvertToImage(); + //wxImage grey_version = img.ConvertToGreyscale(); + //item.disabled_bitmap = wxBitmap(grey_version); + item.disabled_bitmap = MakeDisabledBitmap(item.bitmap); + } + } + + m_items.Add(item); +} + +void wxAuiToolBar::AddControl(wxControl* control, + const wxString& label) +{ + wxAuiToolBarItem item; + item.window = (wxWindow*)control; + item.label = label; + item.bitmap = wxNullBitmap; + item.disabled_bitmap = wxNullBitmap; + item.active = true; + item.dropdown = false; + item.spacer_pixels = 0; + item.id = control->GetId(); + item.state = 0; + item.proportion = 0; + item.kind = wxITEM_CONTROL; + item.sizer_item = NULL; + item.min_size = control->GetEffectiveMinSize(); + item.user_data = 0; + item.sticky = false; + + m_items.Add(item); +} + +void wxAuiToolBar::AddLabel(int tool_id, + const wxString& label, + const int width) +{ + wxSize min_size = wxDefaultSize; + if (width != -1) + min_size.x = width; + + wxAuiToolBarItem item; + item.window = NULL; + item.label = label; + item.bitmap = wxNullBitmap; + item.disabled_bitmap = wxNullBitmap; + item.active = true; + item.dropdown = false; + item.spacer_pixels = 0; + item.id = tool_id; + item.state = 0; + item.proportion = 0; + item.kind = wxITEM_LABEL; + item.sizer_item = NULL; + item.min_size = min_size; + item.user_data = 0; + item.sticky = false; + + m_items.Add(item); +} + +void wxAuiToolBar::AddSeparator() +{ + wxAuiToolBarItem item; + item.window = NULL; + item.label = wxEmptyString; + item.bitmap = wxNullBitmap; + item.disabled_bitmap = wxNullBitmap; + item.active = true; + item.dropdown = false; + item.id = -1; + item.state = 0; + item.proportion = 0; + item.kind = wxITEM_SEPARATOR; + item.sizer_item = NULL; + item.min_size = wxDefaultSize; + item.user_data = 0; + item.sticky = false; + + m_items.Add(item); +} + +void wxAuiToolBar::AddSpacer(int pixels) +{ + wxAuiToolBarItem item; + item.window = NULL; + item.label = wxEmptyString; + item.bitmap = wxNullBitmap; + item.disabled_bitmap = wxNullBitmap; + item.active = true; + item.dropdown = false; + item.spacer_pixels = pixels; + item.id = -1; + item.state = 0; + item.proportion = 0; + item.kind = wxITEM_SPACER; + item.sizer_item = NULL; + item.min_size = wxDefaultSize; + item.user_data = 0; + item.sticky = false; + + m_items.Add(item); +} + +void wxAuiToolBar::AddStretchSpacer(int proportion) +{ + wxAuiToolBarItem item; + item.window = NULL; + item.label = wxEmptyString; + item.bitmap = wxNullBitmap; + item.disabled_bitmap = wxNullBitmap; + item.active = true; + item.dropdown = false; + item.spacer_pixels = 0; + item.id = -1; + item.state = 0; + item.proportion = proportion; + item.kind = wxITEM_SPACER; + item.sizer_item = NULL; + item.min_size = wxDefaultSize; + item.user_data = 0; + item.sticky = false; + + m_items.Add(item); +} + +void wxAuiToolBar::Clear() +{ + m_items.Clear(); + m_sizer_element_count = 0; +} + +bool wxAuiToolBar::DeleteTool(int tool_id) +{ + int idx = GetToolIndex(tool_id); + if (idx >= 0 && idx < (int)m_items.GetCount()) + { + m_items.RemoveAt(idx); + Realize(); + return true; + } + + return false; +} + +bool wxAuiToolBar::DeleteByIndex(int idx) +{ + if (idx >= 0 && idx < (int)m_items.GetCount()) + { + m_items.RemoveAt(idx); + Realize(); + return true; + } + + return false; +} + + +wxControl* wxAuiToolBar::FindControl(int id) +{ + wxWindow* wnd = FindWindow(id); + return (wxControl*)wnd; +} + +wxAuiToolBarItem* wxAuiToolBar::FindTool(int tool_id) const +{ + size_t i, count; + for (i = 0, count = m_items.GetCount(); i < count; ++i) + { + wxAuiToolBarItem& item = m_items.Item(i); + if (item.id == tool_id) + return &item; + } + + return NULL; +} + +wxAuiToolBarItem* wxAuiToolBar::FindToolByPosition(wxCoord x, wxCoord y) const +{ + size_t i, count; + for (i = 0, count = m_items.GetCount(); i < count; ++i) + { + wxAuiToolBarItem& item = m_items.Item(i); + + if (!item.sizer_item) + continue; + + wxRect rect = item.sizer_item->GetRect(); + if (rect.Contains(x,y)) + { + // if the item doesn't fit on the toolbar, return NULL + if (!GetToolFitsByIndex(i)) + return NULL; + + return &item; + } + } + + return NULL; +} + +wxAuiToolBarItem* wxAuiToolBar::FindToolByPositionWithPacking(wxCoord x, wxCoord y) const +{ + size_t i, count; + for (i = 0, count = m_items.GetCount(); i < count; ++i) + { + wxAuiToolBarItem& item = m_items.Item(i); + + if (!item.sizer_item) + continue; + + wxRect rect = item.sizer_item->GetRect(); + + // apply tool packing + if (i+1 < count) + rect.width += m_tool_packing; + + if (rect.Contains(x,y)) + { + // if the item doesn't fit on the toolbar, return NULL + if (!GetToolFitsByIndex(i)) + return NULL; + + return &item; + } + } + + return NULL; +} + +wxAuiToolBarItem* wxAuiToolBar::FindToolByIndex(int idx) const +{ + if (idx < 0) + return NULL; + + if (idx >= (int)m_items.size()) + return NULL; + + return &(m_items[idx]); +} + +void wxAuiToolBar::SetToolBitmapSize(const wxSize& WXUNUSED(size)) +{ + // TODO: wxToolBar compatibility +} + +wxSize wxAuiToolBar::GetToolBitmapSize() const +{ + // TODO: wxToolBar compatibility + return wxSize(16,15); +} + +void wxAuiToolBar::SetToolProportion(int tool_id, int proportion) +{ + wxAuiToolBarItem* item = FindTool(tool_id); + if (!item) + return; + + item->proportion = proportion; +} + +int wxAuiToolBar::GetToolProportion(int tool_id) const +{ + wxAuiToolBarItem* item = FindTool(tool_id); + if (!item) + return 0; + + return item->proportion; +} + +void wxAuiToolBar::SetToolSeparation(int separation) +{ + if (m_art) + m_art->SetElementSize(wxAUI_TBART_SEPARATOR_SIZE, separation); +} + +int wxAuiToolBar::GetToolSeparation() const +{ + if (m_art) + return m_art->GetElementSize(wxAUI_TBART_SEPARATOR_SIZE); + else + return 5; +} + + +void wxAuiToolBar::SetToolDropDown(int tool_id, bool dropdown) +{ + wxAuiToolBarItem* item = FindTool(tool_id); + if (!item) + return; + + item->dropdown = dropdown; +} + +bool wxAuiToolBar::GetToolDropDown(int tool_id) const +{ + wxAuiToolBarItem* item = FindTool(tool_id); + if (!item) + return 0; + + return item->dropdown; +} + +void wxAuiToolBar::SetToolSticky(int tool_id, bool sticky) +{ + // ignore separators + if (tool_id == -1) + return; + + wxAuiToolBarItem* item = FindTool(tool_id); + if (!item) + return; + + if (item->sticky == sticky) + return; + + item->sticky = sticky; + + Refresh(false); + Update(); +} + +bool wxAuiToolBar::GetToolSticky(int tool_id) const +{ + wxAuiToolBarItem* item = FindTool(tool_id); + if (!item) + return 0; + + return item->sticky; +} + + + + +void wxAuiToolBar::SetToolBorderPadding(int padding) +{ + m_tool_border_padding = padding; +} + +int wxAuiToolBar::GetToolBorderPadding() const +{ + return m_tool_border_padding; +} + +void wxAuiToolBar::SetToolTextOrientation(int orientation) +{ + m_tool_text_orientation = orientation; + + if (m_art) + { + m_art->SetTextOrientation(orientation); + } +} + +int wxAuiToolBar::GetToolTextOrientation() const +{ + return m_tool_text_orientation; +} + +void wxAuiToolBar::SetToolPacking(int packing) +{ + m_tool_packing = packing; +} + +int wxAuiToolBar::GetToolPacking() const +{ + return m_tool_packing; +} + + +void wxAuiToolBar::SetOrientation(int WXUNUSED(orientation)) +{ +} + +void wxAuiToolBar::SetMargins(int left, int right, int top, int bottom) +{ + if (left != -1) + m_left_padding = left; + if (right != -1) + m_right_padding = right; + if (top != -1) + m_top_padding = top; + if (bottom != -1) + m_bottom_padding = bottom; +} + +bool wxAuiToolBar::GetGripperVisible() const +{ + return m_gripper_visible; +} + +void wxAuiToolBar::SetGripperVisible(bool visible) +{ + m_gripper_visible = visible; + if (visible) + m_style |= wxAUI_TB_GRIPPER; + Realize(); + Refresh(false); +} + + +bool wxAuiToolBar::GetOverflowVisible() const +{ + return m_overflow_visible; +} + +void wxAuiToolBar::SetOverflowVisible(bool visible) +{ + m_overflow_visible = visible; + if (visible) + m_style |= wxAUI_TB_OVERFLOW; + Refresh(false); +} + +bool wxAuiToolBar::SetFont(const wxFont& font) +{ + bool res = wxWindow::SetFont(font); + + if (m_art) + { + m_art->SetFont(font); + } + + return res; +} + + +void wxAuiToolBar::SetHoverItem(wxAuiToolBarItem* pitem) +{ + wxAuiToolBarItem* former_hover = NULL; + + size_t i, count; + for (i = 0, count = m_items.GetCount(); i < count; ++i) + { + wxAuiToolBarItem& item = m_items.Item(i); + if (item.state & wxAUI_BUTTON_STATE_HOVER) + former_hover = &item; + item.state &= ~wxAUI_BUTTON_STATE_HOVER; + } + + if (pitem) + { + pitem->state |= wxAUI_BUTTON_STATE_HOVER; + } + + if (former_hover != pitem) + { + Refresh(false); + Update(); + } +} + +void wxAuiToolBar::SetPressedItem(wxAuiToolBarItem* pitem) +{ + wxAuiToolBarItem* former_item = NULL; + + size_t i, count; + for (i = 0, count = m_items.GetCount(); i < count; ++i) + { + wxAuiToolBarItem& item = m_items.Item(i); + if (item.state & wxAUI_BUTTON_STATE_PRESSED) + former_item = &item; + item.state &= ~wxAUI_BUTTON_STATE_PRESSED; + } + + if (pitem) + { + pitem->state &= ~wxAUI_BUTTON_STATE_HOVER; + pitem->state |= wxAUI_BUTTON_STATE_PRESSED; + } + + if (former_item != pitem) + { + Refresh(false); + Update(); + } +} + +void wxAuiToolBar::RefreshOverflowState() +{ + if (!m_overflow_sizer_item) + { + m_overflow_state = 0; + return; + } + + int overflow_state = 0; + + wxRect overflow_rect = GetOverflowRect(); + + + // find out the mouse's current position + wxPoint pt = ::wxGetMousePosition(); + pt = this->ScreenToClient(pt); + + // find out if the mouse cursor is inside the dropdown rectangle + if (overflow_rect.Contains(pt.x, pt.y)) + { + if (::wxGetMouseState().LeftDown()) + overflow_state = wxAUI_BUTTON_STATE_PRESSED; + else + overflow_state = wxAUI_BUTTON_STATE_HOVER; + } + + if (overflow_state != m_overflow_state) + { + m_overflow_state = overflow_state; + Refresh(false); + Update(); + } + + m_overflow_state = overflow_state; +} + +void wxAuiToolBar::ToggleTool(int tool_id, bool state) +{ + wxAuiToolBarItem* tool = FindTool(tool_id); + + if (tool) + { + if (tool->kind != wxITEM_CHECK) + return; + + if (state == true) + tool->state |= wxAUI_BUTTON_STATE_CHECKED; + else + tool->state &= ~wxAUI_BUTTON_STATE_CHECKED; + } +} + +bool wxAuiToolBar::GetToolToggled(int tool_id) const +{ + wxAuiToolBarItem* tool = FindTool(tool_id); + + if (tool) + { + if (tool->kind != wxITEM_CHECK) + return false; + + return (tool->state & wxAUI_BUTTON_STATE_CHECKED) ? true : false; + } + + return false; +} + +void wxAuiToolBar::EnableTool(int tool_id, bool state) +{ + wxAuiToolBarItem* tool = FindTool(tool_id); + + if (tool) + { + if (state == true) + tool->state &= ~wxAUI_BUTTON_STATE_DISABLED; + else + tool->state |= wxAUI_BUTTON_STATE_DISABLED; + } +} + +bool wxAuiToolBar::GetToolEnabled(int tool_id) const +{ + wxAuiToolBarItem* tool = FindTool(tool_id); + + if (tool) + return (tool->state & wxAUI_BUTTON_STATE_DISABLED) ? false : true; + + return false; +} + +wxString wxAuiToolBar::GetToolLabel(int tool_id) const +{ + wxAuiToolBarItem* tool = FindTool(tool_id); + wxASSERT_MSG(tool, wxT("can't find tool in toolbar item array")); + if (!tool) + return wxEmptyString; + + return tool->label; +} + +void wxAuiToolBar::SetToolLabel(int tool_id, const wxString& label) +{ + wxAuiToolBarItem* tool = FindTool(tool_id); + if (tool) + { + tool->label = label; + } +} + +wxBitmap wxAuiToolBar::GetToolBitmap(int tool_id) const +{ + wxAuiToolBarItem* tool = FindTool(tool_id); + wxASSERT_MSG(tool, wxT("can't find tool in toolbar item array")); + if (!tool) + return wxNullBitmap; + + return tool->bitmap; +} + +void wxAuiToolBar::SetToolBitmap(int tool_id, const wxBitmap& bitmap) +{ + wxAuiToolBarItem* tool = FindTool(tool_id); + if (tool) + { + tool->bitmap = bitmap; + } +} + +wxString wxAuiToolBar::GetToolShortHelp(int tool_id) const +{ + wxAuiToolBarItem* tool = FindTool(tool_id); + wxASSERT_MSG(tool, wxT("can't find tool in toolbar item array")); + if (!tool) + return wxEmptyString; + + return tool->short_help; +} + +void wxAuiToolBar::SetToolShortHelp(int tool_id, const wxString& help_string) +{ + wxAuiToolBarItem* tool = FindTool(tool_id); + if (tool) + { + tool->short_help = help_string; + } +} + +wxString wxAuiToolBar::GetToolLongHelp(int tool_id) const +{ + wxAuiToolBarItem* tool = FindTool(tool_id); + wxASSERT_MSG(tool, wxT("can't find tool in toolbar item array")); + if (!tool) + return wxEmptyString; + + return tool->long_help; +} + +void wxAuiToolBar::SetToolLongHelp(int tool_id, const wxString& help_string) +{ + wxAuiToolBarItem* tool = FindTool(tool_id); + if (tool) + { + tool->long_help = help_string; + } +} + +void wxAuiToolBar::SetCustomOverflowItems(const wxAuiToolBarItemArray& prepend, + const wxAuiToolBarItemArray& append) +{ + m_custom_overflow_prepend = prepend; + m_custom_overflow_append = append; +} + + +size_t wxAuiToolBar::GetToolCount() const +{ + return m_items.size(); +} + +int wxAuiToolBar::GetToolIndex(int tool_id) const +{ + // this will prevent us from returning the index of the + // first separator in the toolbar since its id is equal to -1 + if (tool_id == -1) + return wxNOT_FOUND; + + size_t i, count = m_items.GetCount(); + for (i = 0; i < count; ++i) + { + wxAuiToolBarItem& item = m_items.Item(i); + if (item.id == tool_id) + return i; + } + + return wxNOT_FOUND; +} + +bool wxAuiToolBar::GetToolFitsByIndex(int tool_idx) const +{ + if (tool_idx < 0 || tool_idx >= (int)m_items.GetCount()) + return false; + + if (!m_items[tool_idx].sizer_item) + return false; + + int cli_w, cli_h; + GetClientSize(&cli_w, &cli_h); + + wxRect rect = m_items[tool_idx].sizer_item->GetRect(); + + if (m_style & wxAUI_TB_VERTICAL) + { + // take the dropdown size into account + if (m_overflow_visible) + cli_h -= m_overflow_sizer_item->GetSize().y; + + if (rect.y+rect.height < cli_h) + return true; + } + else + { + // take the dropdown size into account + if (m_overflow_visible) + cli_w -= m_overflow_sizer_item->GetSize().x; + + if (rect.x+rect.width < cli_w) + return true; + } + + return false; +} + + +bool wxAuiToolBar::GetToolFits(int tool_id) const +{ + return GetToolFitsByIndex(GetToolIndex(tool_id)); +} + +wxRect wxAuiToolBar::GetToolRect(int tool_id) const +{ + wxAuiToolBarItem* tool = FindTool(tool_id); + if (tool && tool->sizer_item) + { + return tool->sizer_item->GetRect(); + } + + return wxRect(); +} + +bool wxAuiToolBar::GetToolBarFits() const +{ + if (m_items.GetCount() == 0) + { + // empty toolbar always 'fits' + return true; + } + + // entire toolbar content fits if the last tool fits + return GetToolFitsByIndex(m_items.GetCount() - 1); +} + +bool wxAuiToolBar::Realize() +{ + wxClientDC dc(this); + if (!dc.IsOk()) + return false; + + bool horizontal = true; + if (m_style & wxAUI_TB_VERTICAL) + horizontal = false; + + + // create the new sizer to add toolbar elements to + wxBoxSizer* sizer = new wxBoxSizer(horizontal ? wxHORIZONTAL : wxVERTICAL); + + // add gripper area + int separator_size = m_art->GetElementSize(wxAUI_TBART_SEPARATOR_SIZE); + int gripper_size = m_art->GetElementSize(wxAUI_TBART_GRIPPER_SIZE); + if (gripper_size > 0 && m_gripper_visible) + { + if (horizontal) + m_gripper_sizer_item = sizer->Add(gripper_size, 1, 0, wxEXPAND); + else + m_gripper_sizer_item = sizer->Add(1, gripper_size, 0, wxEXPAND); + } + else + { + m_gripper_sizer_item = NULL; + } + + // add "left" padding + if (m_left_padding > 0) + { + if (horizontal) + sizer->Add(m_left_padding, 1); + else + sizer->Add(1, m_left_padding); + } + + size_t i, count; + for (i = 0, count = m_items.GetCount(); i < count; ++i) + { + wxAuiToolBarItem& item = m_items.Item(i); + wxSizerItem* sizer_item = NULL; + + switch (item.kind) + { + case wxITEM_LABEL: + { + wxSize size = m_art->GetLabelSize(dc, this, item); + sizer_item = sizer->Add(size.x + (m_tool_border_padding*2), + size.y + (m_tool_border_padding*2), + item.proportion, + wxALIGN_CENTER); + if (i+1 < count) + { + sizer->AddSpacer(m_tool_packing); + } + + break; + } + + case wxITEM_CHECK: + case wxITEM_NORMAL: + { + wxSize size = m_art->GetToolSize(dc, this, item); + sizer_item = sizer->Add(size.x + (m_tool_border_padding*2), + size.y + (m_tool_border_padding*2), + 0, + wxALIGN_CENTER); + // add tool packing + if (i+1 < count) + { + sizer->AddSpacer(m_tool_packing); + } + + break; + } + + case wxITEM_SEPARATOR: + { + if (horizontal) + sizer_item = sizer->Add(separator_size, 1, 0, wxEXPAND); + else + sizer_item = sizer->Add(1, separator_size, 0, wxEXPAND); + + // add tool packing + if (i+1 < count) + { + sizer->AddSpacer(m_tool_packing); + } + + break; + } + + case wxITEM_SPACER: + if (item.proportion > 0) + sizer_item = sizer->AddStretchSpacer(item.proportion); + else + sizer_item = sizer->Add(item.spacer_pixels, 1); + break; + + case wxITEM_CONTROL: + { + //sizer_item = sizer->Add(item.window, item.proportion, wxEXPAND); + wxSizerItem* ctrl_sizer_item; + + wxBoxSizer* vert_sizer = new wxBoxSizer(wxVERTICAL); + vert_sizer->AddStretchSpacer(1); + ctrl_sizer_item = vert_sizer->Add(item.window, 0, wxEXPAND); + vert_sizer->AddStretchSpacer(1); + if ( (m_style & wxAUI_TB_TEXT) && + m_tool_text_orientation == wxAUI_TBTOOL_TEXT_BOTTOM && + !item.GetLabel().empty() ) + { + wxSize s = GetLabelSize(item.GetLabel()); + vert_sizer->Add(1, s.y); + } + + + sizer_item = sizer->Add(vert_sizer, item.proportion, wxEXPAND); + + wxSize min_size = item.min_size; + + + // proportional items will disappear from the toolbar if + // their min width is not set to something really small + if (item.proportion != 0) + { + min_size.x = 1; + } + + if (min_size.IsFullySpecified()) + { + sizer_item->SetMinSize(min_size); + ctrl_sizer_item->SetMinSize(min_size); + } + + // add tool packing + if (i+1 < count) + { + sizer->AddSpacer(m_tool_packing); + } + } + } + + item.sizer_item = sizer_item; + } + + // add "right" padding + if (m_right_padding > 0) + { + if (horizontal) + sizer->Add(m_right_padding, 1); + else + sizer->Add(1, m_right_padding); + } + + // add drop down area + m_overflow_sizer_item = NULL; + + if (m_style & wxAUI_TB_OVERFLOW) + { + int overflow_size = m_art->GetElementSize(wxAUI_TBART_OVERFLOW_SIZE); + if (overflow_size > 0 && m_overflow_visible) + { + if (horizontal) + m_overflow_sizer_item = sizer->Add(overflow_size, 1, 0, wxEXPAND); + else + m_overflow_sizer_item = sizer->Add(1, overflow_size, 0, wxEXPAND); + } + else + { + m_overflow_sizer_item = NULL; + } + } + + + // the outside sizer helps us apply the "top" and "bottom" padding + wxBoxSizer* outside_sizer = new wxBoxSizer(horizontal ? wxVERTICAL : wxHORIZONTAL); + + // add "top" padding + if (m_top_padding > 0) + { + if (horizontal) + outside_sizer->Add(1, m_top_padding); + else + outside_sizer->Add(m_top_padding, 1); + } + + // add the sizer that contains all of the toolbar elements + outside_sizer->Add(sizer, 1, wxEXPAND); + + // add "bottom" padding + if (m_bottom_padding > 0) + { + if (horizontal) + outside_sizer->Add(1, m_bottom_padding); + else + outside_sizer->Add(m_bottom_padding, 1); + } + + delete m_sizer; // remove old sizer + m_sizer = outside_sizer; + + // calculate the rock-bottom minimum size + for (i = 0, count = m_items.GetCount(); i < count; ++i) + { + wxAuiToolBarItem& item = m_items.Item(i); + if (item.sizer_item && item.proportion > 0 && item.min_size.IsFullySpecified()) + item.sizer_item->SetMinSize(0,0); + } + + m_absolute_min_size = m_sizer->GetMinSize(); + + // reset the min sizes to what they were + for (i = 0, count = m_items.GetCount(); i < count; ++i) + { + wxAuiToolBarItem& item = m_items.Item(i); + if (item.sizer_item && item.proportion > 0 && item.min_size.IsFullySpecified()) + item.sizer_item->SetMinSize(item.min_size); + } + + // set control size + wxSize size = m_sizer->GetMinSize(); + m_minWidth = size.x; + m_minHeight = size.y; + + if ((m_style & wxAUI_TB_NO_AUTORESIZE) == 0) + { + wxSize cur_size = GetClientSize(); + wxSize new_size = GetMinSize(); + if (new_size != cur_size) + { + SetClientSize(new_size); + } + else + { + m_sizer->SetDimension(0, 0, cur_size.x, cur_size.y); + } + } + else + { + wxSize cur_size = GetClientSize(); + m_sizer->SetDimension(0, 0, cur_size.x, cur_size.y); + } + + Refresh(false); + return true; +} + +int wxAuiToolBar::GetOverflowState() const +{ + return m_overflow_state; +} + +wxRect wxAuiToolBar::GetOverflowRect() const +{ + wxRect cli_rect(wxPoint(0,0), GetClientSize()); + wxRect overflow_rect = m_overflow_sizer_item->GetRect(); + int overflow_size = m_art->GetElementSize(wxAUI_TBART_OVERFLOW_SIZE); + + if (m_style & wxAUI_TB_VERTICAL) + { + overflow_rect.y = cli_rect.height - overflow_size; + overflow_rect.x = 0; + overflow_rect.width = cli_rect.width; + overflow_rect.height = overflow_size; + } + else + { + overflow_rect.x = cli_rect.width - overflow_size; + overflow_rect.y = 0; + overflow_rect.width = overflow_size; + overflow_rect.height = cli_rect.height; + } + + return overflow_rect; +} + +wxSize wxAuiToolBar::GetLabelSize(const wxString& label) +{ + wxClientDC dc(this); + + int tx, ty; + int text_width = 0, text_height = 0; + + dc.SetFont(m_font); + + // get the text height + dc.GetTextExtent(wxT("ABCDHgj"), &tx, &text_height); + + // get the text width + dc.GetTextExtent(label, &text_width, &ty); + + return wxSize(text_width, text_height); +} + + +void wxAuiToolBar::DoIdleUpdate() +{ + wxEvtHandler* handler = GetEventHandler(); + + bool need_refresh = false; + + size_t i, count; + for (i = 0, count = m_items.GetCount(); i < count; ++i) + { + wxAuiToolBarItem& item = m_items.Item(i); + + if (item.id == -1) + continue; + + wxUpdateUIEvent evt(item.id); + evt.SetEventObject(this); + + if (handler->ProcessEvent(evt)) + { + if (evt.GetSetEnabled()) + { + bool is_enabled; + if (item.window) + is_enabled = item.window->IsEnabled(); + else + is_enabled = (item.state & wxAUI_BUTTON_STATE_DISABLED) ? false : true; + + bool new_enabled = evt.GetEnabled(); + if (new_enabled != is_enabled) + { + if (item.window) + { + item.window->Enable(new_enabled); + } + else + { + if (new_enabled) + item.state &= ~wxAUI_BUTTON_STATE_DISABLED; + else + item.state |= wxAUI_BUTTON_STATE_DISABLED; + } + need_refresh = true; + } + } + + if (evt.GetSetChecked()) + { + // make sure we aren't checking an item that can't be + if (item.kind != wxITEM_CHECK && item.kind != wxITEM_RADIO) + continue; + + bool is_checked = (item.state & wxAUI_BUTTON_STATE_CHECKED) ? true : false; + bool new_checked = evt.GetChecked(); + + if (new_checked != is_checked) + { + if (new_checked) + item.state |= wxAUI_BUTTON_STATE_CHECKED; + else + item.state &= ~wxAUI_BUTTON_STATE_CHECKED; + + need_refresh = true; + } + } + + } + } + + + if (need_refresh) + { + Refresh(false); + } +} + + +void wxAuiToolBar::OnSize(wxSizeEvent& WXUNUSED(evt)) +{ + int x, y; + GetClientSize(&x, &y); + + if (x > y) + SetOrientation(wxHORIZONTAL); + else + SetOrientation(wxVERTICAL); + + if (((x >= y) && m_absolute_min_size.x > x) || + ((y > x) && m_absolute_min_size.y > y)) + { + // hide all flexible items + size_t i, count; + for (i = 0, count = m_items.GetCount(); i < count; ++i) + { + wxAuiToolBarItem& item = m_items.Item(i); + if (item.sizer_item && item.proportion > 0 && item.sizer_item->IsShown()) + { + item.sizer_item->Show(false); + item.sizer_item->SetProportion(0); + } + } + } + else + { + // show all flexible items + size_t i, count; + for (i = 0, count = m_items.GetCount(); i < count; ++i) + { + wxAuiToolBarItem& item = m_items.Item(i); + if (item.sizer_item && item.proportion > 0 && !item.sizer_item->IsShown()) + { + item.sizer_item->Show(true); + item.sizer_item->SetProportion(item.proportion); + } + } + } + + m_sizer->SetDimension(0, 0, x, y); + + Refresh(false); + Update(); +} + + + +void wxAuiToolBar::DoSetSize(int x, + int y, + int width, + int height, + int sizeFlags) +{ + wxSize parent_size = GetParent()->GetClientSize(); + if (x + width > parent_size.x) + width = wxMax(0, parent_size.x - x); + if (y + height > parent_size.y) + height = wxMax(0, parent_size.y - y); + + wxWindow::DoSetSize(x, y, width, height, sizeFlags); +} + + +void wxAuiToolBar::OnIdle(wxIdleEvent& evt) +{ + DoIdleUpdate(); + evt.Skip(); +} + +void wxAuiToolBar::OnPaint(wxPaintEvent& WXUNUSED(evt)) +{ + wxBufferedPaintDC dc(this); + wxRect cli_rect(wxPoint(0,0), GetClientSize()); + + + bool horizontal = true; + if (m_style & wxAUI_TB_VERTICAL) + horizontal = false; + + + m_art->DrawBackground(dc, this, cli_rect); + + int gripper_size = m_art->GetElementSize(wxAUI_TBART_GRIPPER_SIZE); + int dropdown_size = m_art->GetElementSize(wxAUI_TBART_OVERFLOW_SIZE); + + // paint the gripper + if (gripper_size > 0 && m_gripper_sizer_item) + { + wxRect gripper_rect = m_gripper_sizer_item->GetRect(); + if (horizontal) + gripper_rect.width = gripper_size; + else + gripper_rect.height = gripper_size; + m_art->DrawGripper(dc, this, gripper_rect); + } + + // calculated how far we can draw items + int last_extent; + if (horizontal) + last_extent = cli_rect.width; + else + last_extent = cli_rect.height; + if (m_overflow_visible) + last_extent -= dropdown_size; + + // paint each individual tool + size_t i, count = m_items.GetCount(); + for (i = 0; i < count; ++i) + { + wxAuiToolBarItem& item = m_items.Item(i); + + if (!item.sizer_item) + continue; + + wxRect item_rect = item.sizer_item->GetRect(); + + + if ((horizontal && item_rect.x + item_rect.width >= last_extent) || + (!horizontal && item_rect.y + item_rect.height >= last_extent)) + { + break; + } + + if (item.kind == wxITEM_SEPARATOR) + { + // draw a separator + m_art->DrawSeparator(dc, this, item_rect); + } + else if (item.kind == wxITEM_LABEL) + { + // draw a text label only + m_art->DrawLabel(dc, this, item, item_rect); + } + else if (item.kind == wxITEM_NORMAL) + { + // draw a regular button or dropdown button + if (!item.dropdown) + m_art->DrawButton(dc, this, item, item_rect); + else + m_art->DrawDropDownButton(dc, this, item, item_rect); + } + else if (item.kind == wxITEM_CHECK) + { + // draw a toggle button + m_art->DrawButton(dc, this, item, item_rect); + } + else if (item.kind == wxITEM_CONTROL) + { + // draw the control's label + m_art->DrawControlLabel(dc, this, item, item_rect); + } + + // fire a signal to see if the item wants to be custom-rendered + OnCustomRender(dc, item, item_rect); + } + + // paint the overflow button + if (dropdown_size > 0 && m_overflow_sizer_item) + { + wxRect dropdown_rect = GetOverflowRect(); + m_art->DrawOverflowButton(dc, this, dropdown_rect, m_overflow_state); + } +} + +void wxAuiToolBar::OnEraseBackground(wxEraseEvent& WXUNUSED(evt)) +{ + // empty +} + +void wxAuiToolBar::OnLeftDown(wxMouseEvent& evt) +{ + wxRect cli_rect(wxPoint(0,0), GetClientSize()); + + if (m_gripper_sizer_item) + { + wxRect gripper_rect = m_gripper_sizer_item->GetRect(); + if (gripper_rect.Contains(evt.GetX(), evt.GetY())) + { + // find aui manager + wxAuiManager* manager = wxAuiManager::GetManager(this); + if (!manager) + return; + + int x_drag_offset = evt.GetX() - gripper_rect.GetX(); + int y_drag_offset = evt.GetY() - gripper_rect.GetY(); + + // gripper was clicked + manager->StartPaneDrag(this, wxPoint(x_drag_offset, y_drag_offset)); + return; + } + } + + if (m_overflow_sizer_item) + { + wxRect overflow_rect = GetOverflowRect(); + + if (m_art && + m_overflow_visible && + overflow_rect.Contains(evt.m_x, evt.m_y)) + { + wxAuiToolBarEvent e(wxEVT_COMMAND_AUITOOLBAR_OVERFLOW_CLICK, -1); + e.SetEventObject(this); + e.SetToolId(-1); + e.SetClickPoint(wxPoint(evt.GetX(), evt.GetY())); + bool processed = ProcessEvent(e); + + if (processed) + { + DoIdleUpdate(); + } + else + { + size_t i, count; + wxAuiToolBarItemArray overflow_items; + + + // add custom overflow prepend items, if any + count = m_custom_overflow_prepend.GetCount(); + for (i = 0; i < count; ++i) + overflow_items.Add(m_custom_overflow_prepend[i]); + + // only show items that don't fit in the dropdown + count = m_items.GetCount(); + for (i = 0; i < count; ++i) + { + if (!GetToolFitsByIndex(i)) + overflow_items.Add(m_items[i]); + } + + // add custom overflow append items, if any + count = m_custom_overflow_append.GetCount(); + for (i = 0; i < count; ++i) + overflow_items.Add(m_custom_overflow_append[i]); + + int res = m_art->ShowDropDown(this, overflow_items); + m_overflow_state = 0; + Refresh(false); + if (res != -1) + { + wxCommandEvent e(wxEVT_COMMAND_MENU_SELECTED, res); + e.SetEventObject(this); + GetParent()->ProcessEvent(e); + } + } + + return; + } + } + + m_dragging = false; + m_action_pos = wxPoint(evt.GetX(), evt.GetY()); + m_action_item = FindToolByPosition(evt.GetX(), evt.GetY()); + + if (m_action_item) + { + if (m_action_item->state & wxAUI_BUTTON_STATE_DISABLED) + { + m_action_pos = wxPoint(-1,-1); + m_action_item = NULL; + return; + } + + SetPressedItem(m_action_item); + + // fire the tool dropdown event + wxAuiToolBarEvent e(wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, m_action_item->id); + e.SetEventObject(this); + e.SetToolId(m_action_item->id); + e.SetDropDownClicked(false); + + int mouse_x = evt.GetX(); + wxRect rect = m_action_item->sizer_item->GetRect(); + + if (m_action_item->dropdown && + mouse_x >= (rect.x+rect.width-BUTTON_DROPDOWN_WIDTH-1) && + mouse_x < (rect.x+rect.width)) + { + e.SetDropDownClicked(true); + } + + e.SetClickPoint(evt.GetPosition()); + e.SetItemRect(rect); + ProcessEvent(e); + DoIdleUpdate(); + } +} + +void wxAuiToolBar::OnLeftUp(wxMouseEvent& evt) +{ + SetPressedItem(NULL); + + wxAuiToolBarItem* hit_item = FindToolByPosition(evt.GetX(), evt.GetY()); + if (hit_item && !(hit_item->state & wxAUI_BUTTON_STATE_DISABLED)) + { + SetHoverItem(hit_item); + } + + + if (m_dragging) + { + // reset drag and drop member variables + m_dragging = false; + m_action_pos = wxPoint(-1,-1); + m_action_item = NULL; + return; + } + else + { + wxAuiToolBarItem* hit_item; + hit_item = FindToolByPosition(evt.GetX(), evt.GetY()); + + if (m_action_item && hit_item == m_action_item) + { + UnsetToolTip(); + + if (hit_item->kind == wxITEM_CHECK) + { + bool toggle = false; + + if (m_action_item->state & wxAUI_BUTTON_STATE_CHECKED) + toggle = false; + else + toggle = true; + + ToggleTool(m_action_item->id, toggle); + + wxCommandEvent e(wxEVT_COMMAND_MENU_SELECTED, m_action_item->id); + e.SetEventObject(this); + ProcessEvent(e); + DoIdleUpdate(); + } + else + { + wxCommandEvent e(wxEVT_COMMAND_MENU_SELECTED, m_action_item->id); + e.SetEventObject(this); + ProcessEvent(e); + DoIdleUpdate(); + } + } + } + + // reset drag and drop member variables + m_dragging = false; + m_action_pos = wxPoint(-1,-1); + m_action_item = NULL; +} + +void wxAuiToolBar::OnRightDown(wxMouseEvent& evt) +{ + wxRect cli_rect(wxPoint(0,0), GetClientSize()); + + if (m_gripper_sizer_item) + { + wxRect gripper_rect = m_gripper_sizer_item->GetRect(); + if (gripper_rect.Contains(evt.GetX(), evt.GetY())) + return; + } + + if (m_overflow_sizer_item) + { + int dropdown_size = m_art->GetElementSize(wxAUI_TBART_OVERFLOW_SIZE); + if (dropdown_size > 0 && + evt.m_x > cli_rect.width - dropdown_size && + evt.m_y >= 0 && + evt.m_y < cli_rect.height && + m_art) + { + return; + } + } + + m_action_pos = wxPoint(evt.GetX(), evt.GetY()); + m_action_item = FindToolByPosition(evt.GetX(), evt.GetY()); + + if (m_action_item) + { + if (m_action_item->state & wxAUI_BUTTON_STATE_DISABLED) + { + m_action_pos = wxPoint(-1,-1); + m_action_item = NULL; + return; + } + } +} + +void wxAuiToolBar::OnRightUp(wxMouseEvent& evt) +{ + wxAuiToolBarItem* hit_item; + hit_item = FindToolByPosition(evt.GetX(), evt.GetY()); + + if (m_action_item && hit_item == m_action_item) + { + if (hit_item->kind == wxITEM_NORMAL) + { + wxAuiToolBarEvent e(wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK, m_action_item->id); + e.SetEventObject(this); + e.SetToolId(m_action_item->id); + e.SetClickPoint(m_action_pos); + ProcessEvent(e); + DoIdleUpdate(); + } + } + else + { + // right-clicked on the invalid area of the toolbar + wxAuiToolBarEvent e(wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK, -1); + e.SetEventObject(this); + e.SetToolId(-1); + e.SetClickPoint(m_action_pos); + ProcessEvent(e); + DoIdleUpdate(); + } + + // reset member variables + m_action_pos = wxPoint(-1,-1); + m_action_item = NULL; +} + +void wxAuiToolBar::OnMiddleDown(wxMouseEvent& evt) +{ + wxRect cli_rect(wxPoint(0,0), GetClientSize()); + + if (m_gripper_sizer_item) + { + wxRect gripper_rect = m_gripper_sizer_item->GetRect(); + if (gripper_rect.Contains(evt.GetX(), evt.GetY())) + return; + } + + if (m_overflow_sizer_item) + { + int dropdown_size = m_art->GetElementSize(wxAUI_TBART_OVERFLOW_SIZE); + if (dropdown_size > 0 && + evt.m_x > cli_rect.width - dropdown_size && + evt.m_y >= 0 && + evt.m_y < cli_rect.height && + m_art) + { + return; + } + } + + m_action_pos = wxPoint(evt.GetX(), evt.GetY()); + m_action_item = FindToolByPosition(evt.GetX(), evt.GetY()); + + if (m_action_item) + { + if (m_action_item->state & wxAUI_BUTTON_STATE_DISABLED) + { + m_action_pos = wxPoint(-1,-1); + m_action_item = NULL; + return; + } + } +} + +void wxAuiToolBar::OnMiddleUp(wxMouseEvent& evt) +{ + wxAuiToolBarItem* hit_item; + hit_item = FindToolByPosition(evt.GetX(), evt.GetY()); + + if (m_action_item && hit_item == m_action_item) + { + if (hit_item->kind == wxITEM_NORMAL) + { + wxAuiToolBarEvent e(wxEVT_COMMAND_AUITOOLBAR_MIDDLE_CLICK, m_action_item->id); + e.SetEventObject(this); + e.SetToolId(m_action_item->id); + e.SetClickPoint(m_action_pos); + ProcessEvent(e); + DoIdleUpdate(); + } + } + + // reset member variables + m_action_pos = wxPoint(-1,-1); + m_action_item = NULL; +} + +void wxAuiToolBar::OnMotion(wxMouseEvent& evt) +{ + // start a drag event + if (!m_dragging && + m_action_item != NULL && + m_action_pos != wxPoint(-1,-1) && + abs(evt.m_x - m_action_pos.x) + abs(evt.m_y - m_action_pos.y) > 5) + { + UnsetToolTip(); + + m_dragging = true; + + wxAuiToolBarEvent e(wxEVT_COMMAND_AUITOOLBAR_BEGIN_DRAG, GetId()); + e.SetEventObject(this); + e.SetToolId(m_action_item->id); + ProcessEvent(e); + DoIdleUpdate(); + return; + } + + wxAuiToolBarItem* hit_item = FindToolByPosition(evt.GetX(), evt.GetY()); + if (hit_item) + { + if (!(hit_item->state & wxAUI_BUTTON_STATE_DISABLED)) + SetHoverItem(hit_item); + else + SetHoverItem(NULL); + } + else + { + // no hit item, remove any hit item + SetHoverItem(hit_item); + } + + // figure out tooltips + wxAuiToolBarItem* packing_hit_item; + packing_hit_item = FindToolByPositionWithPacking(evt.GetX(), evt.GetY()); + if (packing_hit_item) + { + if (packing_hit_item != m_tip_item) + { + m_tip_item = packing_hit_item; + + if ( !packing_hit_item->short_help.empty() ) + SetToolTip(packing_hit_item->short_help); + else + UnsetToolTip(); + } + } + else + { + UnsetToolTip(); + m_tip_item = NULL; + } + + // if we've pressed down an item and we're hovering + // over it, make sure it's state is set to pressed + if (m_action_item) + { + if (m_action_item == hit_item) + SetPressedItem(m_action_item); + else + SetPressedItem(NULL); + } + + // figure out the dropdown button state (are we hovering or pressing it?) + RefreshOverflowState(); +} + +void wxAuiToolBar::OnLeaveWindow(wxMouseEvent& WXUNUSED(evt)) +{ + RefreshOverflowState(); + SetHoverItem(NULL); + SetPressedItem(NULL); + + m_tip_item = NULL; +} + + +void wxAuiToolBar::OnSetCursor(wxSetCursorEvent& evt) +{ + wxCursor cursor = wxNullCursor; + + if (m_gripper_sizer_item) + { + wxRect gripper_rect = m_gripper_sizer_item->GetRect(); + if (gripper_rect.Contains(evt.GetX(), evt.GetY())) + { + cursor = wxCursor(wxCURSOR_SIZING); + } + } + + evt.SetCursor(cursor); +} + + +#endif // wxUSE_AUI + diff --git a/Externals/wxWidgets/src/aui/auibook.cpp b/Externals/wxWidgets/src/aui/auibook.cpp new file mode 100644 index 0000000000..1d58fc29b1 --- /dev/null +++ b/Externals/wxWidgets/src/aui/auibook.cpp @@ -0,0 +1,4602 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/aui/auibook.cpp +// Purpose: wxaui: wx advanced user interface - notebook +// Author: Benjamin I. Williams +// Modified by: +// Created: 2006-06-28 +// Copyright: (C) Copyright 2006, Kirix Corporation, All Rights Reserved +// Licence: wxWindows Library Licence, Version 3.1 +/////////////////////////////////////////////////////////////////////////////// + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_AUI + +#include "wx/aui/auibook.h" + +#ifndef WX_PRECOMP + #include "wx/settings.h" + #include "wx/image.h" + #include "wx/menu.h" +#endif + +#include "wx/aui/tabmdi.h" +#include "wx/dcbuffer.h" +#include "wx/log.h" + +#ifdef __WXMSW__ +#include "wx/msw/private.h" +#endif + +#ifdef __WXMAC__ +#include "wx/mac/carbon/private.h" +#endif + +#ifdef __WXGTK__ +#include +#include "wx/gtk/win_gtk.h" +#endif + +#include "wx/arrimpl.cpp" +WX_DEFINE_OBJARRAY(wxAuiNotebookPageArray) +WX_DEFINE_OBJARRAY(wxAuiTabContainerButtonArray) + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BUTTON) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN) + + +IMPLEMENT_CLASS(wxAuiNotebook, wxControl) +IMPLEMENT_CLASS(wxAuiTabCtrl, wxControl) +IMPLEMENT_DYNAMIC_CLASS(wxAuiNotebookEvent, wxEvent) + + + + +// these functions live in dockart.cpp -- they'll eventually +// be moved to a new utility cpp file + +wxColor wxAuiStepColour(const wxColor& c, int percent); + +wxBitmap wxAuiBitmapFromBits(const unsigned char bits[], int w, int h, + const wxColour& color); + +wxString wxAuiChopText(wxDC& dc, const wxString& text, int max_size); + +static void DrawButtons(wxDC& dc, + const wxRect& _rect, + const wxBitmap& bmp, + const wxColour& bkcolour, + int button_state) +{ + wxRect rect = _rect; + + if (button_state == wxAUI_BUTTON_STATE_PRESSED) + { + rect.x++; + rect.y++; + } + + if (button_state == wxAUI_BUTTON_STATE_HOVER || + button_state == wxAUI_BUTTON_STATE_PRESSED) + { + dc.SetBrush(wxBrush(wxAuiStepColour(bkcolour, 120))); + dc.SetPen(wxPen(wxAuiStepColour(bkcolour, 75))); + + // draw the background behind the button + dc.DrawRectangle(rect.x, rect.y, 15, 15); + } + + // draw the button itself + dc.DrawBitmap(bmp, rect.x, rect.y, true); +} + +static void IndentPressedBitmap(wxRect* rect, int button_state) +{ + if (button_state == wxAUI_BUTTON_STATE_PRESSED) + { + rect->x++; + rect->y++; + } +} + +static void DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags) +{ +#ifdef __WXMSW__ + wxUnusedVar(win); + wxUnusedVar(flags); + + RECT rc; + wxCopyRectToRECT(rect, rc); + + ::DrawFocusRect(GetHdcOf(dc), &rc); + +#elif defined(__WXGTK20__) + GdkWindow* gdk_window = dc.GetGDKWindow(); + wxASSERT_MSG( gdk_window, + wxT("cannot draw focus rectangle on wxDC of this type") ); + + GtkStateType state; + //if (flags & wxCONTROL_SELECTED) + // state = GTK_STATE_SELECTED; + //else + state = GTK_STATE_NORMAL; + + gtk_paint_focus( win->m_widget->style, + gdk_window, + state, + NULL, + win->m_wxwindow, + NULL, + dc.LogicalToDeviceX(rect.x), + dc.LogicalToDeviceY(rect.y), + rect.width, + rect.height ); +#elif (defined(__WXMAC__)) + +#if wxMAC_USE_CORE_GRAPHICS + { + CGRect cgrect = CGRectMake( rect.x , rect.y , rect.width, rect.height ) ; + +#if 0 + Rect bounds ; + win->GetPeer()->GetRect( &bounds ) ; + + wxLogDebug(wxT("Focus rect %d, %d, %d, %d"), rect.x, rect.y, rect.width, rect.height); + wxLogDebug(wxT("Peer rect %d, %d, %d, %d"), bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top); +#endif + + HIThemeFrameDrawInfo info ; + memset( &info, 0 , sizeof(info) ) ; + + info.version = 0 ; + info.kind = 0 ; + info.state = kThemeStateActive; + info.isFocused = true ; + + CGContextRef cgContext = (CGContextRef) win->MacGetCGContextRef() ; + wxASSERT( cgContext ) ; + + HIThemeDrawFocusRect( &cgrect , true , cgContext , kHIThemeOrientationNormal ) ; + } + #else + { + Rect r; + r.left = rect.x; r.top = rect.y; r.right = rect.GetRight(); r.bottom = rect.GetBottom(); + wxTopLevelWindowMac* top = win->MacGetTopLevelWindow(); + if ( top ) + { + wxPoint pt(0, 0) ; + wxMacControl::Convert( &pt , win->GetPeer() , top->GetPeer() ) ; + OffsetRect( &r , pt.x , pt.y ) ; + } + + DrawThemeFocusRect( &r , true ) ; + } +#endif +#else + wxUnusedVar(win); + wxUnusedVar(flags); + + // draw the pixels manually because the "dots" in wxPen with wxDOT style + // may be short traits and not really dots + // + // note that to behave in the same manner as DrawRect(), we must exclude + // the bottom and right borders from the rectangle + wxCoord x1 = rect.GetLeft(), + y1 = rect.GetTop(), + x2 = rect.GetRight(), + y2 = rect.GetBottom(); + + dc.SetPen(*wxBLACK_PEN); + +#ifdef __WXMAC__ + dc.SetLogicalFunction(wxCOPY); +#else + // this seems to be closer than what Windows does than wxINVERT although + // I'm still not sure if it's correct + dc.SetLogicalFunction(wxAND_REVERSE); +#endif + + wxCoord z; + for ( z = x1 + 1; z < x2; z += 2 ) + dc.DrawPoint(z, rect.GetTop()); + + wxCoord shift = z == x2 ? 0 : 1; + for ( z = y1 + shift; z < y2; z += 2 ) + dc.DrawPoint(x2, z); + + shift = z == y2 ? 0 : 1; + for ( z = x2 - shift; z > x1; z -= 2 ) + dc.DrawPoint(z, y2); + + shift = z == x1 ? 0 : 1; + for ( z = y2 - shift; z > y1; z -= 2 ) + dc.DrawPoint(x1, z); + + dc.SetLogicalFunction(wxCOPY); +#endif +} + + +// -- GUI helper classes and functions -- + +class wxAuiCommandCapture : public wxEvtHandler +{ +public: + + wxAuiCommandCapture() { m_last_id = 0; } + int GetCommandId() const { return m_last_id; } + + bool ProcessEvent(wxEvent& evt) + { + if (evt.GetEventType() == wxEVT_COMMAND_MENU_SELECTED) + { + m_last_id = evt.GetId(); + return true; + } + + if (GetNextHandler()) + return GetNextHandler()->ProcessEvent(evt); + + return false; + } + +private: + int m_last_id; +}; + + +// -- bitmaps -- + +#if defined( __WXMAC__ ) + static unsigned char close_bits[]={ + 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x03, 0xF8, 0x01, 0xF0, 0x19, 0xF3, + 0xB8, 0xE3, 0xF0, 0xE1, 0xE0, 0xE0, 0xF0, 0xE1, 0xB8, 0xE3, 0x19, 0xF3, + 0x01, 0xF0, 0x03, 0xF8, 0x0F, 0xFE, 0xFF, 0xFF }; +#elif defined( __WXGTK__) + static unsigned char close_bits[]={ + 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8, + 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef, + 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +#else + static unsigned char close_bits[]={ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xf3, 0xcf, 0xf9, + 0x9f, 0xfc, 0x3f, 0xfe, 0x3f, 0xfe, 0x9f, 0xfc, 0xcf, 0xf9, 0xe7, 0xf3, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +#endif + +static unsigned char left_bits[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0xfe, + 0x1f, 0xfe, 0x0f, 0xfe, 0x1f, 0xfe, 0x3f, 0xfe, 0x7f, 0xfe, 0xff, 0xfe, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + +static unsigned char right_bits[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x9f, 0xff, 0x1f, 0xff, + 0x1f, 0xfe, 0x1f, 0xfc, 0x1f, 0xfe, 0x1f, 0xff, 0x9f, 0xff, 0xdf, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + +static unsigned char list_bits[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + + + + + +// -- wxAuiDefaultTabArt class implementation -- + +wxAuiDefaultTabArt::wxAuiDefaultTabArt() +{ + m_normal_font = *wxNORMAL_FONT; + m_selected_font = *wxNORMAL_FONT; + m_selected_font.SetWeight(wxBOLD); + m_measuring_font = m_selected_font; + + m_fixed_tab_width = 100; + m_tab_ctrl_height = 0; + +#ifdef __WXMAC__ + wxBrush toolbarbrush; + toolbarbrush.MacSetTheme( kThemeBrushToolbarBackground ); + wxColor base_colour = toolbarbrush.GetColour(); +#else + wxColor base_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE); +#endif + + // the base_colour is too pale to use as our base colour, + // so darken it a bit -- + if ((255-base_colour.Red()) + + (255-base_colour.Green()) + + (255-base_colour.Blue()) < 60) + { + base_colour = wxAuiStepColour(base_colour, 92); + } + + m_base_colour = base_colour; + wxColor border_colour = wxAuiStepColour(base_colour, 75); + + m_border_pen = wxPen(border_colour); + m_base_colour_pen = wxPen(m_base_colour); + m_base_colour_brush = wxBrush(m_base_colour); + + m_active_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, *wxBLACK); + m_disabled_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, wxColour(128,128,128)); + + m_active_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, *wxBLACK); + m_disabled_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, wxColour(128,128,128)); + + m_active_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, *wxBLACK); + m_disabled_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, wxColour(128,128,128)); + + m_active_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, *wxBLACK); + m_disabled_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, wxColour(128,128,128)); + + m_flags = 0; +} + +wxAuiDefaultTabArt::~wxAuiDefaultTabArt() +{ +} + +wxAuiTabArt* wxAuiDefaultTabArt::Clone() +{ + wxAuiDefaultTabArt* art = new wxAuiDefaultTabArt; + art->SetNormalFont(m_normal_font); + art->SetSelectedFont(m_selected_font); + art->SetMeasuringFont(m_measuring_font); + + return art; +} + +void wxAuiDefaultTabArt::SetFlags(unsigned int flags) +{ + m_flags = flags; +} + +void wxAuiDefaultTabArt::SetSizingInfo(const wxSize& tab_ctrl_size, + size_t tab_count) +{ + m_fixed_tab_width = 100; + + int tot_width = (int)tab_ctrl_size.x - GetIndentSize() - 4; + + if (m_flags & wxAUI_NB_CLOSE_BUTTON) + tot_width -= m_active_close_bmp.GetWidth(); + if (m_flags & wxAUI_NB_WINDOWLIST_BUTTON) + tot_width -= m_active_windowlist_bmp.GetWidth(); + + if (tab_count > 0) + { + m_fixed_tab_width = tot_width/(int)tab_count; + } + + + if (m_fixed_tab_width < 100) + m_fixed_tab_width = 100; + + if (m_fixed_tab_width > tot_width/2) + m_fixed_tab_width = tot_width/2; + + if (m_fixed_tab_width > 220) + m_fixed_tab_width = 220; + + m_tab_ctrl_height = tab_ctrl_size.y; +} + + +void wxAuiDefaultTabArt::DrawBackground(wxDC& dc, + wxWindow* WXUNUSED(wnd), + const wxRect& rect) +{ + // draw background + wxColor top_color = wxAuiStepColour(m_base_colour, 90); + wxColor bottom_color = wxAuiStepColour(m_base_colour, 170); + wxRect r; + + if (m_flags &wxAUI_NB_BOTTOM) + r = wxRect(rect.x, rect.y, rect.width+2, rect.height); + // TODO: else if (m_flags &wxAUI_NB_LEFT) {} + // TODO: else if (m_flags &wxAUI_NB_RIGHT) {} + else //for wxAUI_NB_TOP + r = wxRect(rect.x, rect.y, rect.width+2, rect.height-3); + dc.GradientFillLinear(r, top_color, bottom_color, wxSOUTH); + + // draw base lines + dc.SetPen(m_border_pen); + int y = rect.GetHeight(); + int w = rect.GetWidth(); + + if (m_flags &wxAUI_NB_BOTTOM) + { + dc.SetBrush(wxBrush(bottom_color)); + dc.DrawRectangle(-1, 0, w+2, 4); + } + // TODO: else if (m_flags &wxAUI_NB_LEFT) {} + // TODO: else if (m_flags &wxAUI_NB_RIGHT) {} + else //for wxAUI_NB_TOP + { + dc.SetBrush(m_base_colour_brush); + dc.DrawRectangle(-1, y-4, w+2, 4); + } +} + + +// DrawTab() draws an individual tab. +// +// dc - output dc +// in_rect - rectangle the tab should be confined to +// caption - tab's caption +// active - whether or not the tab is active +// out_rect - actual output rectangle +// x_extent - the advance x; where the next tab should start + +void wxAuiDefaultTabArt::DrawTab(wxDC& dc, + wxWindow* wnd, + const wxAuiNotebookPage& page, + const wxRect& in_rect, + int close_button_state, + wxRect* out_tab_rect, + wxRect* out_button_rect, + int* x_extent) +{ + wxCoord normal_textx, normal_texty; + wxCoord selected_textx, selected_texty; + wxCoord texty; + + // if the caption is empty, measure some temporary text + wxString caption = page.caption; + if (caption.empty()) + caption = wxT("Xj"); + + dc.SetFont(m_selected_font); + dc.GetTextExtent(caption, &selected_textx, &selected_texty); + + dc.SetFont(m_normal_font); + dc.GetTextExtent(caption, &normal_textx, &normal_texty); + + // figure out the size of the tab + wxSize tab_size = GetTabSize(dc, + wnd, + page.caption, + page.bitmap, + page.active, + close_button_state, + x_extent); + + wxCoord tab_height = m_tab_ctrl_height - 3; + wxCoord tab_width = tab_size.x; + wxCoord tab_x = in_rect.x; + wxCoord tab_y = in_rect.y + in_rect.height - tab_height; + + + caption = page.caption; + + + // select pen, brush and font for the tab to be drawn + + if (page.active) + { + dc.SetFont(m_selected_font); + texty = selected_texty; + } + else + { + dc.SetFont(m_normal_font); + texty = normal_texty; + } + + + // create points that will make the tab outline + + int clip_width = tab_width; + if (tab_x + clip_width > in_rect.x + in_rect.width) + clip_width = (in_rect.x + in_rect.width) - tab_x; + +/* + wxPoint clip_points[6]; + clip_points[0] = wxPoint(tab_x, tab_y+tab_height-3); + clip_points[1] = wxPoint(tab_x, tab_y+2); + clip_points[2] = wxPoint(tab_x+2, tab_y); + clip_points[3] = wxPoint(tab_x+clip_width-1, tab_y); + clip_points[4] = wxPoint(tab_x+clip_width+1, tab_y+2); + clip_points[5] = wxPoint(tab_x+clip_width+1, tab_y+tab_height-3); + + // FIXME: these ports don't provide wxRegion ctor from array of points +#if !defined(__WXDFB__) && !defined(__WXCOCOA__) + // set the clipping region for the tab -- + wxRegion clipping_region(WXSIZEOF(clip_points), clip_points); + dc.SetClippingRegion(clipping_region); +#endif // !wxDFB && !wxCocoa +*/ + // since the above code above doesn't play well with WXDFB or WXCOCOA, + // we'll just use a rectangle for the clipping region for now -- + dc.SetClippingRegion(tab_x, tab_y, clip_width+1, tab_height-3); + + + wxPoint border_points[6]; + if (m_flags &wxAUI_NB_BOTTOM) + { + border_points[0] = wxPoint(tab_x, tab_y); + border_points[1] = wxPoint(tab_x, tab_y+tab_height-6); + border_points[2] = wxPoint(tab_x+2, tab_y+tab_height-4); + border_points[3] = wxPoint(tab_x+tab_width-2, tab_y+tab_height-4); + border_points[4] = wxPoint(tab_x+tab_width, tab_y+tab_height-6); + border_points[5] = wxPoint(tab_x+tab_width, tab_y); + } + else //if (m_flags & wxAUI_NB_TOP) {} + { + border_points[0] = wxPoint(tab_x, tab_y+tab_height-4); + border_points[1] = wxPoint(tab_x, tab_y+2); + border_points[2] = wxPoint(tab_x+2, tab_y); + border_points[3] = wxPoint(tab_x+tab_width-2, tab_y); + border_points[4] = wxPoint(tab_x+tab_width, tab_y+2); + border_points[5] = wxPoint(tab_x+tab_width, tab_y+tab_height-4); + } + // TODO: else if (m_flags &wxAUI_NB_LEFT) {} + // TODO: else if (m_flags &wxAUI_NB_RIGHT) {} + + int drawn_tab_yoff = border_points[1].y; + int drawn_tab_height = border_points[0].y - border_points[1].y; + + + if (page.active) + { + // draw active tab + + // draw base background color + wxRect r(tab_x, tab_y, tab_width, tab_height); + dc.SetPen(m_base_colour_pen); + dc.SetBrush(m_base_colour_brush); + dc.DrawRectangle(r.x+1, r.y+1, r.width-1, r.height-4); + + // this white helps fill out the gradient at the top of the tab + dc.SetPen(*wxWHITE_PEN); + dc.SetBrush(*wxWHITE_BRUSH); + dc.DrawRectangle(r.x+2, r.y+1, r.width-3, r.height-4); + + // these two points help the rounded corners appear more antialiased + dc.SetPen(m_base_colour_pen); + dc.DrawPoint(r.x+2, r.y+1); + dc.DrawPoint(r.x+r.width-2, r.y+1); + + // set rectangle down a bit for gradient drawing + r.SetHeight(r.GetHeight()/2); + r.x += 2; + r.width -= 2; + r.y += r.height; + r.y -= 2; + + // draw gradient background + wxColor top_color = *wxWHITE; + wxColor bottom_color = m_base_colour; + dc.GradientFillLinear(r, bottom_color, top_color, wxNORTH); + } + else + { + // draw inactive tab + + wxRect r(tab_x, tab_y+1, tab_width, tab_height-3); + + // start the gradent up a bit and leave the inside border inset + // by a pixel for a 3D look. Only the top half of the inactive + // tab will have a slight gradient + r.x += 3; + r.y++; + r.width -= 4; + r.height /= 2; + r.height--; + + // -- draw top gradient fill for glossy look + wxColor top_color = m_base_colour; + wxColor bottom_color = wxAuiStepColour(top_color, 160); + dc.GradientFillLinear(r, bottom_color, top_color, wxNORTH); + + r.y += r.height; + r.y--; + + // -- draw bottom fill for glossy look + top_color = m_base_colour; + bottom_color = m_base_colour; + dc.GradientFillLinear(r, top_color, bottom_color, wxSOUTH); + } + + // draw tab outline + dc.SetPen(m_border_pen); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawPolygon(WXSIZEOF(border_points), border_points); + + // there are two horizontal grey lines at the bottom of the tab control, + // this gets rid of the top one of those lines in the tab control + if (page.active) + { + if (m_flags &wxAUI_NB_BOTTOM) + dc.SetPen(wxPen(wxColour(wxAuiStepColour(m_base_colour, 170)))); + // TODO: else if (m_flags &wxAUI_NB_LEFT) {} + // TODO: else if (m_flags &wxAUI_NB_RIGHT) {} + else //for wxAUI_NB_TOP + dc.SetPen(m_base_colour_pen); + dc.DrawLine(border_points[0].x+1, + border_points[0].y, + border_points[5].x, + border_points[5].y); + } + + + int text_offset = tab_x + 8; + int close_button_width = 0; + if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN) + { + close_button_width = m_active_close_bmp.GetWidth(); + } + + + int bitmap_offset = 0; + if (page.bitmap.IsOk()) + { + bitmap_offset = tab_x + 8; + + // draw bitmap + dc.DrawBitmap(page.bitmap, + bitmap_offset, + drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2), + true); + + text_offset = bitmap_offset + page.bitmap.GetWidth(); + text_offset += 3; // bitmap padding + } + else + { + text_offset = tab_x + 8; + } + + + wxString draw_text = wxAuiChopText(dc, + caption, + tab_width - (text_offset-tab_x) - close_button_width); + + // draw tab text + dc.DrawText(draw_text, + text_offset, + drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1); + + // draw close button if necessary + if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN) + { + wxBitmap bmp = m_disabled_close_bmp; + + if (close_button_state == wxAUI_BUTTON_STATE_HOVER || + close_button_state == wxAUI_BUTTON_STATE_PRESSED) + { + bmp = m_active_close_bmp; + } + + wxRect rect(tab_x + tab_width - close_button_width - 1, + tab_y + (tab_height/2) - (bmp.GetHeight()/2), + close_button_width, + tab_height); + IndentPressedBitmap(&rect, close_button_state); + dc.DrawBitmap(bmp, rect.x, rect.y, true); + + *out_button_rect = rect; + } + + *out_tab_rect = wxRect(tab_x, tab_y, tab_width, tab_height); + +#ifndef __WXMAC__ + // draw focus rectangle + if (page.active && (wnd->FindFocus() == wnd)) + { + wxRect focusRectText(text_offset, (drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1), + selected_textx, selected_texty); + + wxRect focusRect; + wxRect focusRectBitmap; + + if (page.bitmap.IsOk()) + focusRectBitmap = wxRect(bitmap_offset, drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2), + page.bitmap.GetWidth(), page.bitmap.GetHeight()); + + if (page.bitmap.IsOk() && draw_text.IsEmpty()) + focusRect = focusRectBitmap; + else if (!page.bitmap.IsOk() && !draw_text.IsEmpty()) + focusRect = focusRectText; + else if (page.bitmap.IsOk() && !draw_text.IsEmpty()) + focusRect = focusRectText.Union(focusRectBitmap); + + focusRect.Inflate(2, 2); + + DrawFocusRect(wnd, dc, focusRect, 0); + } +#endif + + dc.DestroyClippingRegion(); +} + +int wxAuiDefaultTabArt::GetIndentSize() +{ + return 5; +} + +wxSize wxAuiDefaultTabArt::GetTabSize(wxDC& dc, + wxWindow* WXUNUSED(wnd), + const wxString& caption, + const wxBitmap& bitmap, + bool WXUNUSED(active), + int close_button_state, + int* x_extent) +{ + wxCoord measured_textx, measured_texty, tmp; + + dc.SetFont(m_measuring_font); + dc.GetTextExtent(caption, &measured_textx, &measured_texty); + + dc.GetTextExtent(wxT("ABCDEFXj"), &tmp, &measured_texty); + + // add padding around the text + wxCoord tab_width = measured_textx; + wxCoord tab_height = measured_texty; + + // if the close button is showing, add space for it + if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN) + tab_width += m_active_close_bmp.GetWidth() + 3; + + // if there's a bitmap, add space for it + if (bitmap.IsOk()) + { + tab_width += bitmap.GetWidth(); + tab_width += 3; // right side bitmap padding + tab_height = wxMax(tab_height, bitmap.GetHeight()); + } + + // add padding + tab_width += 16; + tab_height += 10; + + if (m_flags & wxAUI_NB_TAB_FIXED_WIDTH) + { + tab_width = m_fixed_tab_width; + } + + *x_extent = tab_width; + + return wxSize(tab_width, tab_height); +} + + +void wxAuiDefaultTabArt::DrawButton(wxDC& dc, + wxWindow* WXUNUSED(wnd), + const wxRect& in_rect, + int bitmap_id, + int button_state, + int orientation, + wxRect* out_rect) +{ + wxBitmap bmp; + wxRect rect; + + switch (bitmap_id) + { + case wxAUI_BUTTON_CLOSE: + if (button_state & wxAUI_BUTTON_STATE_DISABLED) + bmp = m_disabled_close_bmp; + else + bmp = m_active_close_bmp; + break; + case wxAUI_BUTTON_LEFT: + if (button_state & wxAUI_BUTTON_STATE_DISABLED) + bmp = m_disabled_left_bmp; + else + bmp = m_active_left_bmp; + break; + case wxAUI_BUTTON_RIGHT: + if (button_state & wxAUI_BUTTON_STATE_DISABLED) + bmp = m_disabled_right_bmp; + else + bmp = m_active_right_bmp; + break; + case wxAUI_BUTTON_WINDOWLIST: + if (button_state & wxAUI_BUTTON_STATE_DISABLED) + bmp = m_disabled_windowlist_bmp; + else + bmp = m_active_windowlist_bmp; + break; + } + + + if (!bmp.IsOk()) + return; + + rect = in_rect; + + if (orientation == wxLEFT) + { + rect.SetX(in_rect.x); + rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2)); + rect.SetWidth(bmp.GetWidth()); + rect.SetHeight(bmp.GetHeight()); + } + else + { + rect = wxRect(in_rect.x + in_rect.width - bmp.GetWidth(), + ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2), + bmp.GetWidth(), bmp.GetHeight()); + } + + IndentPressedBitmap(&rect, button_state); + dc.DrawBitmap(bmp, rect.x, rect.y, true); + + *out_rect = rect; +} + + +int wxAuiDefaultTabArt::ShowDropDown(wxWindow* wnd, + const wxAuiNotebookPageArray& pages, + int active_idx) +{ + wxMenu menuPopup; + + size_t i, count = pages.GetCount(); + for (i = 0; i < count; ++i) + { + const wxAuiNotebookPage& page = pages.Item(i); + wxString caption = page.caption; + + // if there is no caption, make it a space. This will prevent + // an assert in the menu code. + if (caption.IsEmpty()) + caption = wxT(" "); + + menuPopup.AppendCheckItem(1000+i, caption); + } + + if (active_idx != -1) + { + menuPopup.Check(1000+active_idx, true); + } + + // find out where to put the popup menu of window items + wxPoint pt = ::wxGetMousePosition(); + pt = wnd->ScreenToClient(pt); + + // find out the screen coordinate at the bottom of the tab ctrl + wxRect cli_rect = wnd->GetClientRect(); + pt.y = cli_rect.y + cli_rect.height; + + wxAuiCommandCapture* cc = new wxAuiCommandCapture; + wnd->PushEventHandler(cc); + wnd->PopupMenu(&menuPopup, pt); + int command = cc->GetCommandId(); + wnd->PopEventHandler(true); + + if (command >= 1000) + return command-1000; + + return -1; +} + +int wxAuiDefaultTabArt::GetBestTabCtrlSize(wxWindow* wnd, + const wxAuiNotebookPageArray& pages, + const wxSize& required_bmp_size) +{ + wxClientDC dc(wnd); + dc.SetFont(m_measuring_font); + + // sometimes a standard bitmap size needs to be enforced, especially + // if some tabs have bitmaps and others don't. This is important because + // it prevents the tab control from resizing when tabs are added. + wxBitmap measure_bmp; + if (required_bmp_size.IsFullySpecified()) + { + measure_bmp.Create(required_bmp_size.x, + required_bmp_size.y); + } + + + int max_y = 0; + size_t i, page_count = pages.GetCount(); + for (i = 0; i < page_count; ++i) + { + wxAuiNotebookPage& page = pages.Item(i); + + wxBitmap bmp; + if (measure_bmp.IsOk()) + bmp = measure_bmp; + else + bmp = page.bitmap; + + // we don't use the caption text because we don't + // want tab heights to be different in the case + // of a very short piece of text on one tab and a very + // tall piece of text on another tab + int x_ext = 0; + wxSize s = GetTabSize(dc, + wnd, + wxT("ABCDEFGHIj"), + bmp, + true, + wxAUI_BUTTON_STATE_HIDDEN, + &x_ext); + + max_y = wxMax(max_y, s.y); + } + + return max_y+2; +} + +void wxAuiDefaultTabArt::SetNormalFont(const wxFont& font) +{ + m_normal_font = font; +} + +void wxAuiDefaultTabArt::SetSelectedFont(const wxFont& font) +{ + m_selected_font = font; +} + +void wxAuiDefaultTabArt::SetMeasuringFont(const wxFont& font) +{ + m_measuring_font = font; +} + + +// -- wxAuiSimpleTabArt class implementation -- + +wxAuiSimpleTabArt::wxAuiSimpleTabArt() +{ + m_normal_font = *wxNORMAL_FONT; + m_selected_font = *wxNORMAL_FONT; + m_selected_font.SetWeight(wxBOLD); + m_measuring_font = m_selected_font; + + m_flags = 0; + m_fixed_tab_width = 100; + + wxColour base_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE); + + wxColour background_colour = base_colour; + wxColour normaltab_colour = base_colour; + wxColour selectedtab_colour = *wxWHITE; + + m_bkbrush = wxBrush(background_colour); + m_normal_bkbrush = wxBrush(normaltab_colour); + m_normal_bkpen = wxPen(normaltab_colour); + m_selected_bkbrush = wxBrush(selectedtab_colour); + m_selected_bkpen = wxPen(selectedtab_colour); + + m_active_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, *wxBLACK); + m_disabled_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, wxColour(128,128,128)); + + m_active_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, *wxBLACK); + m_disabled_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, wxColour(128,128,128)); + + m_active_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, *wxBLACK); + m_disabled_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, wxColour(128,128,128)); + + m_active_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, *wxBLACK); + m_disabled_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, wxColour(128,128,128)); + +} + +wxAuiSimpleTabArt::~wxAuiSimpleTabArt() +{ +} + +wxAuiTabArt* wxAuiSimpleTabArt::Clone() +{ + return wx_static_cast(wxAuiTabArt*, new wxAuiSimpleTabArt); +} + + +void wxAuiSimpleTabArt::SetFlags(unsigned int flags) +{ + m_flags = flags; +} + +void wxAuiSimpleTabArt::SetSizingInfo(const wxSize& tab_ctrl_size, + size_t tab_count) +{ + m_fixed_tab_width = 100; + + int tot_width = (int)tab_ctrl_size.x - GetIndentSize() - 4; + + if (m_flags & wxAUI_NB_CLOSE_BUTTON) + tot_width -= m_active_close_bmp.GetWidth(); + if (m_flags & wxAUI_NB_WINDOWLIST_BUTTON) + tot_width -= m_active_windowlist_bmp.GetWidth(); + + if (tab_count > 0) + { + m_fixed_tab_width = tot_width/(int)tab_count; + } + + + if (m_fixed_tab_width < 100) + m_fixed_tab_width = 100; + + if (m_fixed_tab_width > tot_width/2) + m_fixed_tab_width = tot_width/2; + + if (m_fixed_tab_width > 220) + m_fixed_tab_width = 220; +} + +void wxAuiSimpleTabArt::DrawBackground(wxDC& dc, + wxWindow* WXUNUSED(wnd), + const wxRect& rect) +{ + // draw background + dc.SetBrush(m_bkbrush); + dc.SetPen(*wxTRANSPARENT_PEN); + dc.DrawRectangle(-1, -1, rect.GetWidth()+2, rect.GetHeight()+2); + + // draw base line + dc.SetPen(*wxGREY_PEN); + dc.DrawLine(0, rect.GetHeight()-1, rect.GetWidth(), rect.GetHeight()-1); +} + + +// DrawTab() draws an individual tab. +// +// dc - output dc +// in_rect - rectangle the tab should be confined to +// caption - tab's caption +// active - whether or not the tab is active +// out_rect - actual output rectangle +// x_extent - the advance x; where the next tab should start + +void wxAuiSimpleTabArt::DrawTab(wxDC& dc, + wxWindow* wnd, + const wxAuiNotebookPage& page, + const wxRect& in_rect, + int close_button_state, + wxRect* out_tab_rect, + wxRect* out_button_rect, + int* x_extent) +{ + wxCoord normal_textx, normal_texty; + wxCoord selected_textx, selected_texty; + wxCoord textx, texty; + + // if the caption is empty, measure some temporary text + wxString caption = page.caption; + if (caption.empty()) + caption = wxT("Xj"); + + dc.SetFont(m_selected_font); + dc.GetTextExtent(caption, &selected_textx, &selected_texty); + + dc.SetFont(m_normal_font); + dc.GetTextExtent(caption, &normal_textx, &normal_texty); + + // figure out the size of the tab + wxSize tab_size = GetTabSize(dc, + wnd, + page.caption, + page.bitmap, + page.active, + close_button_state, + x_extent); + + wxCoord tab_height = tab_size.y; + wxCoord tab_width = tab_size.x; + wxCoord tab_x = in_rect.x; + wxCoord tab_y = in_rect.y + in_rect.height - tab_height; + + caption = page.caption; + + // select pen, brush and font for the tab to be drawn + + if (page.active) + { + dc.SetPen(m_selected_bkpen); + dc.SetBrush(m_selected_bkbrush); + dc.SetFont(m_selected_font); + textx = selected_textx; + texty = selected_texty; + } + else + { + dc.SetPen(m_normal_bkpen); + dc.SetBrush(m_normal_bkbrush); + dc.SetFont(m_normal_font); + textx = normal_textx; + texty = normal_texty; + } + + + // -- draw line -- + + wxPoint points[7]; + points[0].x = tab_x; + points[0].y = tab_y + tab_height - 1; + points[1].x = tab_x + tab_height - 3; + points[1].y = tab_y + 2; + points[2].x = tab_x + tab_height + 3; + points[2].y = tab_y; + points[3].x = tab_x + tab_width - 2; + points[3].y = tab_y; + points[4].x = tab_x + tab_width; + points[4].y = tab_y + 2; + points[5].x = tab_x + tab_width; + points[5].y = tab_y + tab_height - 1; + points[6] = points[0]; + + dc.SetClippingRegion(in_rect); + + dc.DrawPolygon(WXSIZEOF(points) - 1, points); + + dc.SetPen(*wxGREY_PEN); + + //dc.DrawLines(active ? WXSIZEOF(points) - 1 : WXSIZEOF(points), points); + dc.DrawLines(WXSIZEOF(points), points); + + + int text_offset; + + int close_button_width = 0; + if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN) + { + close_button_width = m_active_close_bmp.GetWidth(); + text_offset = tab_x + (tab_height/2) + ((tab_width-close_button_width)/2) - (textx/2); + } + else + { + text_offset = tab_x + (tab_height/3) + (tab_width/2) - (textx/2); + } + + // set minimum text offset + if (text_offset < tab_x + tab_height) + text_offset = tab_x + tab_height; + + // chop text if necessary + wxString draw_text = wxAuiChopText(dc, + caption, + tab_width - (text_offset-tab_x) - close_button_width); + + // draw tab text + dc.DrawText(draw_text, + text_offset, + (tab_y + tab_height)/2 - (texty/2) + 1); + + +#ifndef __WXMAC__ + // draw focus rectangle + if (page.active && (wnd->FindFocus() == wnd)) + { + wxRect focusRect(text_offset, ((tab_y + tab_height)/2 - (texty/2) + 1), + selected_textx, selected_texty); + + focusRect.Inflate(2, 2); + + DrawFocusRect(wnd, dc, focusRect, 0); + } +#endif + + // draw close button if necessary + if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN) + { + wxBitmap bmp; + if (page.active) + bmp = m_active_close_bmp; + else + bmp = m_disabled_close_bmp; + + wxRect rect(tab_x + tab_width - close_button_width - 1, + tab_y + (tab_height/2) - (bmp.GetHeight()/2) + 1, + close_button_width, + tab_height - 1); + DrawButtons(dc, rect, bmp, *wxWHITE, close_button_state); + + *out_button_rect = rect; + } + + + *out_tab_rect = wxRect(tab_x, tab_y, tab_width, tab_height); + + dc.DestroyClippingRegion(); +} + +int wxAuiSimpleTabArt::GetIndentSize() +{ + return 0; +} + +wxSize wxAuiSimpleTabArt::GetTabSize(wxDC& dc, + wxWindow* WXUNUSED(wnd), + const wxString& caption, + const wxBitmap& WXUNUSED(bitmap), + bool WXUNUSED(active), + int close_button_state, + int* x_extent) +{ + wxCoord measured_textx, measured_texty; + + dc.SetFont(m_measuring_font); + dc.GetTextExtent(caption, &measured_textx, &measured_texty); + + wxCoord tab_height = measured_texty + 4; + wxCoord tab_width = measured_textx + tab_height + 5; + + if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN) + tab_width += m_active_close_bmp.GetWidth(); + + if (m_flags & wxAUI_NB_TAB_FIXED_WIDTH) + { + tab_width = m_fixed_tab_width; + } + + *x_extent = tab_width - (tab_height/2) - 1; + + return wxSize(tab_width, tab_height); +} + + +void wxAuiSimpleTabArt::DrawButton(wxDC& dc, + wxWindow* WXUNUSED(wnd), + const wxRect& in_rect, + int bitmap_id, + int button_state, + int orientation, + wxRect* out_rect) +{ + wxBitmap bmp; + wxRect rect; + + switch (bitmap_id) + { + case wxAUI_BUTTON_CLOSE: + if (button_state & wxAUI_BUTTON_STATE_DISABLED) + bmp = m_disabled_close_bmp; + else + bmp = m_active_close_bmp; + break; + case wxAUI_BUTTON_LEFT: + if (button_state & wxAUI_BUTTON_STATE_DISABLED) + bmp = m_disabled_left_bmp; + else + bmp = m_active_left_bmp; + break; + case wxAUI_BUTTON_RIGHT: + if (button_state & wxAUI_BUTTON_STATE_DISABLED) + bmp = m_disabled_right_bmp; + else + bmp = m_active_right_bmp; + break; + case wxAUI_BUTTON_WINDOWLIST: + if (button_state & wxAUI_BUTTON_STATE_DISABLED) + bmp = m_disabled_windowlist_bmp; + else + bmp = m_active_windowlist_bmp; + break; + } + + if (!bmp.IsOk()) + return; + + rect = in_rect; + + if (orientation == wxLEFT) + { + rect.SetX(in_rect.x); + rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2)); + rect.SetWidth(bmp.GetWidth()); + rect.SetHeight(bmp.GetHeight()); + } + else + { + rect = wxRect(in_rect.x + in_rect.width - bmp.GetWidth(), + ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2), + bmp.GetWidth(), bmp.GetHeight()); + } + + + DrawButtons(dc, rect, bmp, *wxWHITE, button_state); + + *out_rect = rect; +} + + +int wxAuiSimpleTabArt::ShowDropDown(wxWindow* wnd, + const wxAuiNotebookPageArray& pages, + int active_idx) +{ + wxMenu menuPopup; + + size_t i, count = pages.GetCount(); + for (i = 0; i < count; ++i) + { + const wxAuiNotebookPage& page = pages.Item(i); + menuPopup.AppendCheckItem(1000+i, page.caption); + } + + if (active_idx != -1) + { + menuPopup.Check(1000+active_idx, true); + } + + // find out where to put the popup menu of window + // items. Subtract 100 for now to center the menu + // a bit, until a better mechanism can be implemented + wxPoint pt = ::wxGetMousePosition(); + pt = wnd->ScreenToClient(pt); + if (pt.x < 100) + pt.x = 0; + else + pt.x -= 100; + + // find out the screen coordinate at the bottom of the tab ctrl + wxRect cli_rect = wnd->GetClientRect(); + pt.y = cli_rect.y + cli_rect.height; + + wxAuiCommandCapture* cc = new wxAuiCommandCapture; + wnd->PushEventHandler(cc); + wnd->PopupMenu(&menuPopup, pt); + int command = cc->GetCommandId(); + wnd->PopEventHandler(true); + + if (command >= 1000) + return command-1000; + + return -1; +} + +int wxAuiSimpleTabArt::GetBestTabCtrlSize(wxWindow* wnd, + const wxAuiNotebookPageArray& WXUNUSED(pages), + const wxSize& WXUNUSED(required_bmp_size)) +{ + wxClientDC dc(wnd); + dc.SetFont(m_measuring_font); + int x_ext = 0; + wxSize s = GetTabSize(dc, + wnd, + wxT("ABCDEFGHIj"), + wxNullBitmap, + true, + wxAUI_BUTTON_STATE_HIDDEN, + &x_ext); + return s.y+3; +} + +void wxAuiSimpleTabArt::SetNormalFont(const wxFont& font) +{ + m_normal_font = font; +} + +void wxAuiSimpleTabArt::SetSelectedFont(const wxFont& font) +{ + m_selected_font = font; +} + +void wxAuiSimpleTabArt::SetMeasuringFont(const wxFont& font) +{ + m_measuring_font = font; +} + + + + +// -- wxAuiTabContainer class implementation -- + + +// wxAuiTabContainer is a class which contains information about each +// tab. It also can render an entire tab control to a specified DC. +// It's not a window class itself, because this code will be used by +// the wxFrameMananger, where it is disadvantageous to have separate +// windows for each tab control in the case of "docked tabs" + +// A derived class, wxAuiTabCtrl, is an actual wxWindow-derived window +// which can be used as a tab control in the normal sense. + + +wxAuiTabContainer::wxAuiTabContainer() +{ + m_tab_offset = 0; + m_flags = 0; + m_art = new wxAuiDefaultTabArt; + + AddButton(wxAUI_BUTTON_LEFT, wxLEFT); + AddButton(wxAUI_BUTTON_RIGHT, wxRIGHT); + AddButton(wxAUI_BUTTON_WINDOWLIST, wxRIGHT); + AddButton(wxAUI_BUTTON_CLOSE, wxRIGHT); +} + +wxAuiTabContainer::~wxAuiTabContainer() +{ + delete m_art; +} + +void wxAuiTabContainer::SetArtProvider(wxAuiTabArt* art) +{ + delete m_art; + m_art = art; + + if (m_art) + { + m_art->SetFlags(m_flags); + } +} + +wxAuiTabArt* wxAuiTabContainer::GetArtProvider() const +{ + return m_art; +} + +void wxAuiTabContainer::SetFlags(unsigned int flags) +{ + m_flags = flags; + + // check for new close button settings + RemoveButton(wxAUI_BUTTON_LEFT); + RemoveButton(wxAUI_BUTTON_RIGHT); + RemoveButton(wxAUI_BUTTON_WINDOWLIST); + RemoveButton(wxAUI_BUTTON_CLOSE); + + + if (flags & wxAUI_NB_SCROLL_BUTTONS) + { + AddButton(wxAUI_BUTTON_LEFT, wxLEFT); + AddButton(wxAUI_BUTTON_RIGHT, wxRIGHT); + } + + if (flags & wxAUI_NB_WINDOWLIST_BUTTON) + { + AddButton(wxAUI_BUTTON_WINDOWLIST, wxRIGHT); + } + + if (flags & wxAUI_NB_CLOSE_BUTTON) + { + AddButton(wxAUI_BUTTON_CLOSE, wxRIGHT); + } + + if (m_art) + { + m_art->SetFlags(m_flags); + } +} + +unsigned int wxAuiTabContainer::GetFlags() const +{ + return m_flags; +} + + +void wxAuiTabContainer::SetNormalFont(const wxFont& font) +{ + m_art->SetNormalFont(font); +} + +void wxAuiTabContainer::SetSelectedFont(const wxFont& font) +{ + m_art->SetSelectedFont(font); +} + +void wxAuiTabContainer::SetMeasuringFont(const wxFont& font) +{ + m_art->SetMeasuringFont(font); +} + +void wxAuiTabContainer::SetRect(const wxRect& rect) +{ + m_rect = rect; + + if (m_art) + { + m_art->SetSizingInfo(rect.GetSize(), m_pages.GetCount()); + } +} + +bool wxAuiTabContainer::AddPage(wxWindow* page, + const wxAuiNotebookPage& info) +{ + wxAuiNotebookPage page_info; + page_info = info; + page_info.window = page; + + m_pages.Add(page_info); + + // let the art provider know how many pages we have + if (m_art) + { + m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount()); + } + + return true; +} + +bool wxAuiTabContainer::InsertPage(wxWindow* page, + const wxAuiNotebookPage& info, + size_t idx) +{ + wxAuiNotebookPage page_info; + page_info = info; + page_info.window = page; + + if (idx >= m_pages.GetCount()) + m_pages.Add(page_info); + else + m_pages.Insert(page_info, idx); + + // let the art provider know how many pages we have + if (m_art) + { + m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount()); + } + + return true; +} + +bool wxAuiTabContainer::MovePage(wxWindow* page, + size_t new_idx) +{ + int idx = GetIdxFromWindow(page); + if (idx == -1) + return false; + + // get page entry, make a copy of it + wxAuiNotebookPage p = GetPage(idx); + + // remove old page entry + RemovePage(page); + + // insert page where it should be + InsertPage(page, p, new_idx); + + return true; +} + +bool wxAuiTabContainer::RemovePage(wxWindow* wnd) +{ + size_t i, page_count = m_pages.GetCount(); + for (i = 0; i < page_count; ++i) + { + wxAuiNotebookPage& page = m_pages.Item(i); + if (page.window == wnd) + { + m_pages.RemoveAt(i); + + // let the art provider know how many pages we have + if (m_art) + { + m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount()); + } + + return true; + } + } + + return false; +} + +bool wxAuiTabContainer::SetActivePage(wxWindow* wnd) +{ + bool found = false; + + size_t i, page_count = m_pages.GetCount(); + for (i = 0; i < page_count; ++i) + { + wxAuiNotebookPage& page = m_pages.Item(i); + if (page.window == wnd) + { + page.active = true; + found = true; + } + else + { + page.active = false; + } + } + + return found; +} + +void wxAuiTabContainer::SetNoneActive() +{ + size_t i, page_count = m_pages.GetCount(); + for (i = 0; i < page_count; ++i) + { + wxAuiNotebookPage& page = m_pages.Item(i); + page.active = false; + } +} + +bool wxAuiTabContainer::SetActivePage(size_t page) +{ + if (page >= m_pages.GetCount()) + return false; + + return SetActivePage(m_pages.Item(page).window); +} + +int wxAuiTabContainer::GetActivePage() const +{ + size_t i, page_count = m_pages.GetCount(); + for (i = 0; i < page_count; ++i) + { + wxAuiNotebookPage& page = m_pages.Item(i); + if (page.active) + return i; + } + + return -1; +} + +wxWindow* wxAuiTabContainer::GetWindowFromIdx(size_t idx) const +{ + if (idx >= m_pages.GetCount()) + return NULL; + + return m_pages[idx].window; +} + +int wxAuiTabContainer::GetIdxFromWindow(wxWindow* wnd) const +{ + size_t i, page_count = m_pages.GetCount(); + for (i = 0; i < page_count; ++i) + { + wxAuiNotebookPage& page = m_pages.Item(i); + if (page.window == wnd) + return i; + } + return -1; +} + +wxAuiNotebookPage& wxAuiTabContainer::GetPage(size_t idx) +{ + wxASSERT_MSG(idx < m_pages.GetCount(), wxT("Invalid Page index")); + + return m_pages[idx]; +} + +const wxAuiNotebookPage& wxAuiTabContainer::GetPage(size_t idx) const +{ + wxASSERT_MSG(idx < m_pages.GetCount(), wxT("Invalid Page index")); + + return m_pages[idx]; +} + +wxAuiNotebookPageArray& wxAuiTabContainer::GetPages() +{ + return m_pages; +} + +size_t wxAuiTabContainer::GetPageCount() const +{ + return m_pages.GetCount(); +} + +void wxAuiTabContainer::AddButton(int id, + int location, + const wxBitmap& normal_bitmap, + const wxBitmap& disabled_bitmap) +{ + wxAuiTabContainerButton button; + button.id = id; + button.bitmap = normal_bitmap; + button.dis_bitmap = disabled_bitmap; + button.location = location; + button.cur_state = wxAUI_BUTTON_STATE_NORMAL; + + m_buttons.Add(button); +} + +void wxAuiTabContainer::RemoveButton(int id) +{ + size_t i, button_count = m_buttons.GetCount(); + + for (i = 0; i < button_count; ++i) + { + if (m_buttons.Item(i).id == id) + { + m_buttons.RemoveAt(i); + return; + } + } +} + + + +size_t wxAuiTabContainer::GetTabOffset() const +{ + return m_tab_offset; +} + +void wxAuiTabContainer::SetTabOffset(size_t offset) +{ + m_tab_offset = offset; +} + + + + +// Render() renders the tab catalog to the specified DC +// It is a virtual function and can be overridden to +// provide custom drawing capabilities +void wxAuiTabContainer::Render(wxDC* raw_dc, wxWindow* wnd) +{ + if (!raw_dc || !raw_dc->IsOk()) + return; + + wxMemoryDC dc; + + // use the same layout direction as the window DC uses to ensure that the + // text is rendered correctly + dc.SetLayoutDirection(raw_dc->GetLayoutDirection()); + + wxBitmap bmp; + size_t i; + size_t page_count = m_pages.GetCount(); + size_t button_count = m_buttons.GetCount(); + + // create off-screen bitmap + bmp.Create(m_rect.GetWidth(), m_rect.GetHeight()); + dc.SelectObject(bmp); + + if (!dc.IsOk()) + return; + + // find out if size of tabs is larger than can be + // afforded on screen + int total_width = 0; + int visible_width = 0; + + for (i = 0; i < page_count; ++i) + { + wxAuiNotebookPage& page = m_pages.Item(i); + + // determine if a close button is on this tab + bool close_button = false; + if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 || + ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active)) + { + close_button = true; + } + + + int x_extent = 0; + wxSize size = m_art->GetTabSize(dc, + wnd, + page.caption, + page.bitmap, + page.active, + close_button ? + wxAUI_BUTTON_STATE_NORMAL : + wxAUI_BUTTON_STATE_HIDDEN, + &x_extent); + + if (i+1 < page_count) + total_width += x_extent; + else + total_width += size.x; + + if (i >= m_tab_offset) + { + if (i+1 < page_count) + visible_width += x_extent; + else + visible_width += size.x; + } + } + + if (total_width > m_rect.GetWidth() || m_tab_offset != 0) + { + // show left/right buttons + for (i = 0; i < button_count; ++i) + { + wxAuiTabContainerButton& button = m_buttons.Item(i); + if (button.id == wxAUI_BUTTON_LEFT || + button.id == wxAUI_BUTTON_RIGHT) + { + button.cur_state &= ~wxAUI_BUTTON_STATE_HIDDEN; + } + } + } + else + { + // hide left/right buttons + for (i = 0; i < button_count; ++i) + { + wxAuiTabContainerButton& button = m_buttons.Item(i); + if (button.id == wxAUI_BUTTON_LEFT || + button.id == wxAUI_BUTTON_RIGHT) + { + button.cur_state |= wxAUI_BUTTON_STATE_HIDDEN; + } + } + } + + // determine whether left button should be enabled + for (i = 0; i < button_count; ++i) + { + wxAuiTabContainerButton& button = m_buttons.Item(i); + if (button.id == wxAUI_BUTTON_LEFT) + { + if (m_tab_offset == 0) + button.cur_state |= wxAUI_BUTTON_STATE_DISABLED; + else + button.cur_state &= ~wxAUI_BUTTON_STATE_DISABLED; + } + if (button.id == wxAUI_BUTTON_RIGHT) + { + if (visible_width < m_rect.GetWidth() - ((int)button_count*16)) + button.cur_state |= wxAUI_BUTTON_STATE_DISABLED; + else + button.cur_state &= ~wxAUI_BUTTON_STATE_DISABLED; + } + } + + + + // draw background + m_art->DrawBackground(dc, wnd, m_rect); + + // draw buttons + int left_buttons_width = 0; + int right_buttons_width = 0; + + int offset = 0; + + // draw the buttons on the right side + offset = m_rect.x + m_rect.width; + for (i = 0; i < button_count; ++i) + { + wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1); + + if (button.location != wxRIGHT) + continue; + if (button.cur_state & wxAUI_BUTTON_STATE_HIDDEN) + continue; + + wxRect button_rect = m_rect; + button_rect.SetY(1); + button_rect.SetWidth(offset); + + m_art->DrawButton(dc, + wnd, + button_rect, + button.id, + button.cur_state, + wxRIGHT, + &button.rect); + + offset -= button.rect.GetWidth(); + right_buttons_width += button.rect.GetWidth(); + } + + + + offset = 0; + + // draw the buttons on the left side + + for (i = 0; i < button_count; ++i) + { + wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1); + + if (button.location != wxLEFT) + continue; + if (button.cur_state & wxAUI_BUTTON_STATE_HIDDEN) + continue; + + wxRect button_rect(offset, 1, 1000, m_rect.height); + + m_art->DrawButton(dc, + wnd, + button_rect, + button.id, + button.cur_state, + wxLEFT, + &button.rect); + + offset += button.rect.GetWidth(); + left_buttons_width += button.rect.GetWidth(); + } + + offset = left_buttons_width; + + if (offset == 0) + offset += m_art->GetIndentSize(); + + + // prepare the tab-close-button array + // make sure tab button entries which aren't used are marked as hidden + for (i = page_count; i < m_tab_close_buttons.GetCount(); ++i) + m_tab_close_buttons.Item(i).cur_state = wxAUI_BUTTON_STATE_HIDDEN; + + // make sure there are enough tab button entries to accommodate all tabs + while (m_tab_close_buttons.GetCount() < page_count) + { + wxAuiTabContainerButton tempbtn; + tempbtn.id = wxAUI_BUTTON_CLOSE; + tempbtn.location = wxCENTER; + tempbtn.cur_state = wxAUI_BUTTON_STATE_HIDDEN; + m_tab_close_buttons.Add(tempbtn); + } + + + // buttons before the tab offset must be set to hidden + for (i = 0; i < m_tab_offset; ++i) + { + m_tab_close_buttons.Item(i).cur_state = wxAUI_BUTTON_STATE_HIDDEN; + } + + + // draw the tabs + + size_t active = 999; + int active_offset = 0; + wxRect active_rect; + wxRect active_focus_rect; + + int x_extent = 0; + wxRect rect = m_rect; + rect.y = 0; + rect.height = m_rect.height; + + for (i = m_tab_offset; i < page_count; ++i) + { + wxAuiNotebookPage& page = m_pages.Item(i); + wxAuiTabContainerButton& tab_button = m_tab_close_buttons.Item(i); + + // determine if a close button is on this tab + if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 || + ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active)) + { + if (tab_button.cur_state == wxAUI_BUTTON_STATE_HIDDEN) + { + tab_button.id = wxAUI_BUTTON_CLOSE; + tab_button.cur_state = wxAUI_BUTTON_STATE_NORMAL; + tab_button.location = wxCENTER; + } + } + else + { + tab_button.cur_state = wxAUI_BUTTON_STATE_HIDDEN; + } + + rect.x = offset; + rect.width = m_rect.width - right_buttons_width - offset - 2; + + if (rect.width <= 0) + break; + + m_art->DrawTab(dc, + wnd, + page, + rect, + tab_button.cur_state, + &page.rect, + &tab_button.rect, + &x_extent); + + if (page.active) + { + active = i; + active_offset = offset; + active_rect = rect; + active_focus_rect = rect; + active_focus_rect.width = x_extent; + } + + offset += x_extent; + } + + + // make sure to deactivate buttons which are off the screen to the right + for (++i; i < m_tab_close_buttons.GetCount(); ++i) + { + m_tab_close_buttons.Item(i).cur_state = wxAUI_BUTTON_STATE_HIDDEN; + } + + + // draw the active tab again so it stands in the foreground + if (active >= m_tab_offset && active < m_pages.GetCount()) + { + wxAuiNotebookPage& page = m_pages.Item(active); + + wxAuiTabContainerButton& tab_button = m_tab_close_buttons.Item(active); + + rect.x = active_offset; + m_art->DrawTab(dc, + wnd, + page, + active_rect, + tab_button.cur_state, + &page.rect, + &tab_button.rect, + &x_extent); + } + + + raw_dc->Blit(m_rect.x, m_rect.y, + m_rect.GetWidth(), m_rect.GetHeight(), + &dc, 0, 0); + +#ifdef __WXMAC__ + // On Mac, need to draw the focus rect directly to the window + if (wnd && (wnd->FindFocus() == wnd) && (active >= m_tab_offset && active < m_pages.GetCount())) + { + wxRect focusRect(active_focus_rect); + focusRect.Inflate(-6, -6); + DrawFocusRect(wnd, * raw_dc, focusRect, 0); + } +#endif +} + +// Is the tab visible? +bool wxAuiTabContainer::IsTabVisible(int tabPage, int tabOffset, wxDC* dc, wxWindow* wnd) +{ + if (!dc || !dc->IsOk()) + return false; + + size_t i; + size_t page_count = m_pages.GetCount(); + size_t button_count = m_buttons.GetCount(); + + // Hasn't been rendered yet; assume it's visible + if (m_tab_close_buttons.GetCount() < page_count) + return true; + + // First check if both buttons are disabled - if so, there's no need to + // check further for visibility. + int arrowButtonVisibleCount = 0; + for (i = 0; i < button_count; ++i) + { + wxAuiTabContainerButton& button = m_buttons.Item(i); + if (button.id == wxAUI_BUTTON_LEFT || + button.id == wxAUI_BUTTON_RIGHT) + { + if ((button.cur_state & wxAUI_BUTTON_STATE_HIDDEN) == 0) + arrowButtonVisibleCount ++; + } + } + + // Tab must be visible + if (arrowButtonVisibleCount == 0) + return true; + + // If tab is less than the given offset, it must be invisible by definition + if (tabPage < tabOffset) + return false; + + // draw buttons + int left_buttons_width = 0; + int right_buttons_width = 0; + + int offset = 0; + + // calculate size of the buttons on the right side + offset = m_rect.x + m_rect.width; + for (i = 0; i < button_count; ++i) + { + wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1); + + if (button.location != wxRIGHT) + continue; + if (button.cur_state & wxAUI_BUTTON_STATE_HIDDEN) + continue; + + offset -= button.rect.GetWidth(); + right_buttons_width += button.rect.GetWidth(); + } + + offset = 0; + + // calculate size of the buttons on the left side + for (i = 0; i < button_count; ++i) + { + wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1); + + if (button.location != wxLEFT) + continue; + if (button.cur_state & wxAUI_BUTTON_STATE_HIDDEN) + continue; + + offset += button.rect.GetWidth(); + left_buttons_width += button.rect.GetWidth(); + } + + offset = left_buttons_width; + + if (offset == 0) + offset += m_art->GetIndentSize(); + + wxRect active_rect; + + wxRect rect = m_rect; + rect.y = 0; + rect.height = m_rect.height; + + // See if the given page is visible at the given tab offset (effectively scroll position) + for (i = tabOffset; i < page_count; ++i) + { + wxAuiNotebookPage& page = m_pages.Item(i); + wxAuiTabContainerButton& tab_button = m_tab_close_buttons.Item(i); + + rect.x = offset; + rect.width = m_rect.width - right_buttons_width - offset - 2; + + if (rect.width <= 0) + return false; // haven't found the tab, and we've run out of space, so return false + + int x_extent = 0; + wxSize size = m_art->GetTabSize(*dc, + wnd, + page.caption, + page.bitmap, + page.active, + tab_button.cur_state, + &x_extent); + + offset += x_extent; + + if (i == (size_t) tabPage) + { + // If not all of the tab is visible, and supposing there's space to display it all, + // we could do better so we return false. + if (((m_rect.width - right_buttons_width - offset - 2) <= 0) && ((m_rect.width - right_buttons_width - left_buttons_width) > x_extent)) + return false; + else + return true; + } + } + + // Shouldn't really get here, but if it does, assume the tab is visible to prevent + // further looping in calling code. + return true; +} + +// Make the tab visible if it wasn't already +void wxAuiTabContainer::MakeTabVisible(int tabPage, wxWindow* win) +{ + wxClientDC dc(win); + if (!IsTabVisible(tabPage, GetTabOffset(), & dc, win)) + { + int i; + for (i = 0; i < (int) m_pages.GetCount(); i++) + { + if (IsTabVisible(tabPage, i, & dc, win)) + { + SetTabOffset(i); + win->Refresh(); + return; + } + } + } +} + +// TabHitTest() tests if a tab was hit, passing the window pointer +// back if that condition was fulfilled. The function returns +// true if a tab was hit, otherwise false +bool wxAuiTabContainer::TabHitTest(int x, int y, wxWindow** hit) const +{ + if (!m_rect.Contains(x,y)) + return false; + + wxAuiTabContainerButton* btn = NULL; + if (ButtonHitTest(x, y, &btn)) + { + if (m_buttons.Index(*btn) != wxNOT_FOUND) + return false; + } + + size_t i, page_count = m_pages.GetCount(); + + for (i = m_tab_offset; i < page_count; ++i) + { + wxAuiNotebookPage& page = m_pages.Item(i); + if (page.rect.Contains(x,y)) + { + if (hit) + *hit = page.window; + return true; + } + } + + return false; +} + +// ButtonHitTest() tests if a button was hit. The function returns +// true if a button was hit, otherwise false +bool wxAuiTabContainer::ButtonHitTest(int x, int y, + wxAuiTabContainerButton** hit) const +{ + if (!m_rect.Contains(x,y)) + return false; + + size_t i, button_count; + + + button_count = m_buttons.GetCount(); + for (i = 0; i < button_count; ++i) + { + wxAuiTabContainerButton& button = m_buttons.Item(i); + if (button.rect.Contains(x,y) && + !(button.cur_state & (wxAUI_BUTTON_STATE_HIDDEN | + wxAUI_BUTTON_STATE_DISABLED))) + { + if (hit) + *hit = &button; + return true; + } + } + + button_count = m_tab_close_buttons.GetCount(); + for (i = 0; i < button_count; ++i) + { + wxAuiTabContainerButton& button = m_tab_close_buttons.Item(i); + if (button.rect.Contains(x,y) && + !(button.cur_state & (wxAUI_BUTTON_STATE_HIDDEN | + wxAUI_BUTTON_STATE_DISABLED))) + { + if (hit) + *hit = &button; + return true; + } + } + + return false; +} + + + +// the utility function ShowWnd() is the same as show, +// except it handles wxAuiMDIChildFrame windows as well, +// as the Show() method on this class is "unplugged" +static void ShowWnd(wxWindow* wnd, bool show) +{ +#if wxUSE_MDI + if (wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame))) + { + wxAuiMDIChildFrame* cf = (wxAuiMDIChildFrame*)wnd; + cf->DoShow(show); + } + else +#endif + { + wnd->Show(show); + } +} + + +// DoShowHide() this function shows the active window, then +// hides all of the other windows (in that order) +void wxAuiTabContainer::DoShowHide() +{ + wxAuiNotebookPageArray& pages = GetPages(); + size_t i, page_count = pages.GetCount(); + + // show new active page first + for (i = 0; i < page_count; ++i) + { + wxAuiNotebookPage& page = pages.Item(i); + if (page.active) + { + ShowWnd(page.window, true); + break; + } + } + + // hide all other pages + for (i = 0; i < page_count; ++i) + { + wxAuiNotebookPage& page = pages.Item(i); + if (!page.active) + ShowWnd(page.window, false); + } +} + + + + + + +// -- wxAuiTabCtrl class implementation -- + + + +BEGIN_EVENT_TABLE(wxAuiTabCtrl, wxControl) + EVT_PAINT(wxAuiTabCtrl::OnPaint) + EVT_ERASE_BACKGROUND(wxAuiTabCtrl::OnEraseBackground) + EVT_SIZE(wxAuiTabCtrl::OnSize) + EVT_LEFT_DOWN(wxAuiTabCtrl::OnLeftDown) + EVT_LEFT_DCLICK(wxAuiTabCtrl::OnLeftDClick) + EVT_LEFT_UP(wxAuiTabCtrl::OnLeftUp) + EVT_MIDDLE_DOWN(wxAuiTabCtrl::OnMiddleDown) + EVT_MIDDLE_UP(wxAuiTabCtrl::OnMiddleUp) + EVT_RIGHT_DOWN(wxAuiTabCtrl::OnRightDown) + EVT_RIGHT_UP(wxAuiTabCtrl::OnRightUp) + EVT_MOTION(wxAuiTabCtrl::OnMotion) + EVT_LEAVE_WINDOW(wxAuiTabCtrl::OnLeaveWindow) + EVT_AUINOTEBOOK_BUTTON(wxID_ANY, wxAuiTabCtrl::OnButton) + EVT_SET_FOCUS(wxAuiTabCtrl::OnSetFocus) + EVT_KILL_FOCUS(wxAuiTabCtrl::OnKillFocus) + EVT_CHAR(wxAuiTabCtrl::OnChar) + EVT_MOUSE_CAPTURE_LOST(wxAuiTabCtrl::OnCaptureLost) +END_EVENT_TABLE() + + +wxAuiTabCtrl::wxAuiTabCtrl(wxWindow* parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style) : wxControl(parent, id, pos, size, style) +{ + m_click_pt = wxDefaultPosition; + m_is_dragging = false; + m_hover_button = NULL; + m_pressed_button = NULL; +} + +wxAuiTabCtrl::~wxAuiTabCtrl() +{ +} + +void wxAuiTabCtrl::OnPaint(wxPaintEvent&) +{ + wxPaintDC dc(this); + + dc.SetFont(GetFont()); + + if (GetPageCount() > 0) + Render(&dc, this); +} + +void wxAuiTabCtrl::OnEraseBackground(wxEraseEvent& WXUNUSED(evt)) +{ +} + +void wxAuiTabCtrl::OnSize(wxSizeEvent& evt) +{ + wxSize s = evt.GetSize(); + wxRect r(0, 0, s.GetWidth(), s.GetHeight()); + SetRect(r); +} + +void wxAuiTabCtrl::OnLeftDown(wxMouseEvent& evt) +{ + CaptureMouse(); + m_click_pt = wxDefaultPosition; + m_is_dragging = false; + m_click_tab = NULL; + m_pressed_button = NULL; + + + wxWindow* wnd; + if (TabHitTest(evt.m_x, evt.m_y, &wnd)) + { + int new_selection = GetIdxFromWindow(wnd); + + // wxAuiNotebooks always want to receive this event + // even if the tab is already active, because they may + // have multiple tab controls + if (new_selection != GetActivePage() || + GetParent()->IsKindOf(CLASSINFO(wxAuiNotebook))) + { + wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId); + e.SetSelection(new_selection); + e.SetOldSelection(GetActivePage()); + e.SetEventObject(this); + GetEventHandler()->ProcessEvent(e); + } + + m_click_pt.x = evt.m_x; + m_click_pt.y = evt.m_y; + m_click_tab = wnd; + } + + if (m_hover_button) + { + m_pressed_button = m_hover_button; + m_pressed_button->cur_state = wxAUI_BUTTON_STATE_PRESSED; + Refresh(); + Update(); + } +} + +void wxAuiTabCtrl::OnCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event)) +{ +} + +void wxAuiTabCtrl::OnLeftUp(wxMouseEvent& evt) +{ + if (GetCapture() == this) + ReleaseMouse(); + + if (m_is_dragging) + { + m_is_dragging = false; + + wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, m_windowId); + evt.SetSelection(GetIdxFromWindow(m_click_tab)); + evt.SetOldSelection(evt.GetSelection()); + evt.SetEventObject(this); + GetEventHandler()->ProcessEvent(evt); + + return; + } + + if (m_pressed_button) + { + // make sure we're still clicking the button + wxAuiTabContainerButton* button = NULL; + if (!ButtonHitTest(evt.m_x, evt.m_y, &button)) + return; + + if (button != m_pressed_button) + { + m_pressed_button = NULL; + return; + } + + Refresh(); + Update(); + + if (!(m_pressed_button->cur_state & wxAUI_BUTTON_STATE_DISABLED)) + { + wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BUTTON, m_windowId); + evt.SetSelection(GetIdxFromWindow(m_click_tab)); + evt.SetInt(m_pressed_button->id); + evt.SetEventObject(this); + GetEventHandler()->ProcessEvent(evt); + } + + m_pressed_button = NULL; + } + + m_click_pt = wxDefaultPosition; + m_is_dragging = false; + m_click_tab = NULL; +} + +void wxAuiTabCtrl::OnMiddleUp(wxMouseEvent& evt) +{ + wxWindow* wnd = NULL; + if (!TabHitTest(evt.m_x, evt.m_y, &wnd)) + return; + + wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, m_windowId); + e.SetEventObject(this); + e.SetSelection(GetIdxFromWindow(wnd)); + GetEventHandler()->ProcessEvent(e); +} + +void wxAuiTabCtrl::OnMiddleDown(wxMouseEvent& evt) +{ + wxWindow* wnd = NULL; + if (!TabHitTest(evt.m_x, evt.m_y, &wnd)) + return; + + wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, m_windowId); + e.SetEventObject(this); + e.SetSelection(GetIdxFromWindow(wnd)); + GetEventHandler()->ProcessEvent(e); +} + +void wxAuiTabCtrl::OnRightUp(wxMouseEvent& evt) +{ + wxWindow* wnd = NULL; + if (!TabHitTest(evt.m_x, evt.m_y, &wnd)) + return; + + wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, m_windowId); + e.SetEventObject(this); + e.SetSelection(GetIdxFromWindow(wnd)); + GetEventHandler()->ProcessEvent(e); +} + +void wxAuiTabCtrl::OnRightDown(wxMouseEvent& evt) +{ + wxWindow* wnd = NULL; + if (!TabHitTest(evt.m_x, evt.m_y, &wnd)) + return; + + wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, m_windowId); + e.SetEventObject(this); + e.SetSelection(GetIdxFromWindow(wnd)); + GetEventHandler()->ProcessEvent(e); +} + +void wxAuiTabCtrl::OnLeftDClick(wxMouseEvent& evt) +{ + wxWindow* wnd; + wxAuiTabContainerButton* button; + if (!TabHitTest(evt.m_x, evt.m_y, &wnd) && !ButtonHitTest(evt.m_x, evt.m_y, &button)) + { + wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, m_windowId); + e.SetEventObject(this); + GetEventHandler()->ProcessEvent(e); + } +} + +void wxAuiTabCtrl::OnMotion(wxMouseEvent& evt) +{ + wxPoint pos = evt.GetPosition(); + + // check if the mouse is hovering above a button + wxAuiTabContainerButton* button; + if (ButtonHitTest(pos.x, pos.y, &button)) + { + if (m_hover_button && button != m_hover_button) + { + m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL; + m_hover_button = NULL; + Refresh(); + Update(); + } + + if (button->cur_state != wxAUI_BUTTON_STATE_HOVER) + { + button->cur_state = wxAUI_BUTTON_STATE_HOVER; + Refresh(); + Update(); + m_hover_button = button; + return; + } + } + else + { + if (m_hover_button) + { + m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL; + m_hover_button = NULL; + Refresh(); + Update(); + } + } + + + if (!evt.LeftIsDown() || m_click_pt == wxDefaultPosition) + return; + + if (m_is_dragging) + { + wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, m_windowId); + evt.SetSelection(GetIdxFromWindow(m_click_tab)); + evt.SetOldSelection(evt.GetSelection()); + evt.SetEventObject(this); + GetEventHandler()->ProcessEvent(evt); + return; + } + + + int drag_x_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_X); + int drag_y_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_Y); + + if (abs(pos.x - m_click_pt.x) > drag_x_threshold || + abs(pos.y - m_click_pt.y) > drag_y_threshold) + { + wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, m_windowId); + evt.SetSelection(GetIdxFromWindow(m_click_tab)); + evt.SetOldSelection(evt.GetSelection()); + evt.SetEventObject(this); + GetEventHandler()->ProcessEvent(evt); + + m_is_dragging = true; + } +} + +void wxAuiTabCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event)) +{ + if (m_hover_button) + { + m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL; + m_hover_button = NULL; + Refresh(); + Update(); + } +} + +void wxAuiTabCtrl::OnButton(wxAuiNotebookEvent& event) +{ + int button = event.GetInt(); + + if (button == wxAUI_BUTTON_LEFT || button == wxAUI_BUTTON_RIGHT) + { + if (button == wxAUI_BUTTON_LEFT) + { + if (GetTabOffset() > 0) + { + SetTabOffset(GetTabOffset()-1); + Refresh(); + Update(); + } + } + else + { + SetTabOffset(GetTabOffset()+1); + Refresh(); + Update(); + } + } + else if (button == wxAUI_BUTTON_WINDOWLIST) + { + int idx = GetArtProvider()->ShowDropDown(this, m_pages, GetActivePage()); + + if (idx != -1) + { + wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId); + e.SetSelection(idx); + e.SetOldSelection(GetActivePage()); + e.SetEventObject(this); + GetEventHandler()->ProcessEvent(e); + } + } + else + { + event.Skip(); + } +} + +void wxAuiTabCtrl::OnSetFocus(wxFocusEvent& WXUNUSED(event)) +{ + Refresh(); +} + +void wxAuiTabCtrl::OnKillFocus(wxFocusEvent& WXUNUSED(event)) +{ + Refresh(); +} + +void wxAuiTabCtrl::OnChar(wxKeyEvent& event) +{ + if (GetActivePage() == -1) + { + event.Skip(); + return; + } + + // We can't leave tab processing to the system; on Windows, tabs and keys + // get eaten by the system and not processed properly if we specify both + // wxTAB_TRAVERSAL and wxWANTS_CHARS. And if we specify just wxTAB_TRAVERSAL, + // we don't key arrow key events. + + int key = event.GetKeyCode(); + + if (key == WXK_NUMPAD_PAGEUP) + key = WXK_PAGEUP; + if (key == WXK_NUMPAD_PAGEDOWN) + key = WXK_PAGEDOWN; + if (key == WXK_NUMPAD_HOME) + key = WXK_HOME; + if (key == WXK_NUMPAD_END) + key = WXK_END; + if (key == WXK_NUMPAD_LEFT) + key = WXK_LEFT; + if (key == WXK_NUMPAD_RIGHT) + key = WXK_RIGHT; + + if (key == WXK_TAB || key == WXK_PAGEUP || key == WXK_PAGEDOWN) + { + bool bCtrlDown = event.ControlDown(); + bool bShiftDown = event.ShiftDown(); + + bool bForward = (key == WXK_TAB && !bShiftDown) || (key == WXK_PAGEDOWN); + bool bWindowChange = (key == WXK_PAGEUP) || (key == WXK_PAGEDOWN) || bCtrlDown; + bool bFromTab = (key == WXK_TAB); + + wxAuiNotebook* nb = wxDynamicCast(GetParent(), wxAuiNotebook); + if (!nb) + { + event.Skip(); + return; + } + + wxNavigationKeyEvent keyEvent; + keyEvent.SetDirection(bForward); + keyEvent.SetWindowChange(bWindowChange); + keyEvent.SetFromTab(bFromTab); + keyEvent.SetEventObject(nb); + + if (!nb->GetEventHandler()->ProcessEvent(keyEvent)) + { + // Not processed? Do an explicit tab into the page. + wxWindow* win = GetWindowFromIdx(GetActivePage()); + if (win) + win->SetFocus(); + } + return; + } + + if (m_pages.GetCount() < 2) + { + event.Skip(); + return; + } + + int newPage = -1; + + int forwardKey, backwardKey; + if (GetLayoutDirection() == wxLayout_RightToLeft) + { + forwardKey = WXK_LEFT; + backwardKey = WXK_RIGHT; + } + else + { + forwardKey = WXK_RIGHT; + backwardKey = WXK_LEFT; + } + + if (key == forwardKey) + { + if (m_pages.GetCount() > 1) + { + if (GetActivePage() == -1) + newPage = 0; + else if (GetActivePage() < (int) (m_pages.GetCount() - 1)) + newPage = GetActivePage() + 1; + } + } + else if (key == backwardKey) + { + if (m_pages.GetCount() > 1) + { + if (GetActivePage() == -1) + newPage = (int) (m_pages.GetCount() - 1); + else if (GetActivePage() > 0) + newPage = GetActivePage() - 1; + } + } + else if (key == WXK_HOME) + { + newPage = 0; + } + else if (key == WXK_END) + { + newPage = (int) (m_pages.GetCount() - 1); + } + else + event.Skip(); + + if (newPage != -1) + { + wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId); + e.SetSelection(newPage); + e.SetOldSelection(newPage); + e.SetEventObject(this); + this->GetEventHandler()->ProcessEvent(e); + } + else + event.Skip(); +} + +// wxTabFrame is an interesting case. It's important that all child pages +// of the multi-notebook control are all actually children of that control +// (and not grandchildren). wxTabFrame facilitates this. There is one +// instance of wxTabFrame for each tab control inside the multi-notebook. +// It's important to know that wxTabFrame is not a real window, but it merely +// used to capture the dimensions/positioning of the internal tab control and +// it's managed page windows + +class wxTabFrame : public wxWindow +{ +public: + + wxTabFrame() + { + m_tabs = NULL; + m_rect = wxRect(0,0,200,200); + m_tab_ctrl_height = 20; + } + + ~wxTabFrame() + { + wxDELETE(m_tabs); + } + + void SetTabCtrlHeight(int h) + { + m_tab_ctrl_height = h; + } + + void DoSetSize(int x, int y, + int width, int height, + int WXUNUSED(sizeFlags = wxSIZE_AUTO)) + { + m_rect = wxRect(x, y, width, height); + DoSizing(); + } + + void DoGetClientSize(int* x, int* y) const + { + *x = m_rect.width; + *y = m_rect.height; + } + + bool Show( bool WXUNUSED(show = true) ) { return false; } + + void DoSizing() + { + if (!m_tabs) + return; + + if (m_tabs->GetFlags() & wxAUI_NB_BOTTOM) + { + m_tab_rect = wxRect (m_rect.x, m_rect.y + m_rect.height - m_tab_ctrl_height, m_rect.width, m_tab_ctrl_height); + m_tabs->SetSize (m_rect.x, m_rect.y + m_rect.height - m_tab_ctrl_height, m_rect.width, m_tab_ctrl_height); + m_tabs->SetRect (wxRect(0, 0, m_rect.width, m_tab_ctrl_height)); + } + else //TODO: if (GetFlags() & wxAUI_NB_TOP) + { + m_tab_rect = wxRect (m_rect.x, m_rect.y, m_rect.width, m_tab_ctrl_height); + m_tabs->SetSize (m_rect.x, m_rect.y, m_rect.width, m_tab_ctrl_height); + m_tabs->SetRect (wxRect(0, 0, m_rect.width, m_tab_ctrl_height)); + } + // TODO: else if (GetFlags() & wxAUI_NB_LEFT){} + // TODO: else if (GetFlags() & wxAUI_NB_RIGHT){} + + m_tabs->Refresh(); + m_tabs->Update(); + + wxAuiNotebookPageArray& pages = m_tabs->GetPages(); + size_t i, page_count = pages.GetCount(); + + for (i = 0; i < page_count; ++i) + { + wxAuiNotebookPage& page = pages.Item(i); + if (m_tabs->GetFlags() & wxAUI_NB_BOTTOM) + { + page.window->SetSize(m_rect.x, m_rect.y, + m_rect.width, m_rect.height - m_tab_ctrl_height); + } + else //TODO: if (GetFlags() & wxAUI_NB_TOP) + { + page.window->SetSize(m_rect.x, m_rect.y + m_tab_ctrl_height, + m_rect.width, m_rect.height - m_tab_ctrl_height); + } + // TODO: else if (GetFlags() & wxAUI_NB_LEFT){} + // TODO: else if (GetFlags() & wxAUI_NB_RIGHT){} + +#if wxUSE_MDI + if (page.window->IsKindOf(CLASSINFO(wxAuiMDIChildFrame))) + { + wxAuiMDIChildFrame* wnd = (wxAuiMDIChildFrame*)page.window; + wnd->ApplyMDIChildFrameRect(); + } +#endif + } + } + + void DoGetSize(int* x, int* y) const + { + if (x) + *x = m_rect.GetWidth(); + if (y) + *y = m_rect.GetHeight(); + } + + void Update() + { + // does nothing + } + +public: + + wxRect m_rect; + wxRect m_tab_rect; + wxAuiTabCtrl* m_tabs; + int m_tab_ctrl_height; +}; + + +const int wxAuiBaseTabCtrlId = 5380; + + +// -- wxAuiNotebook class implementation -- + +BEGIN_EVENT_TABLE(wxAuiNotebook, wxControl) + EVT_SIZE(wxAuiNotebook::OnSize) + EVT_CHILD_FOCUS(wxAuiNotebook::OnChildFocus) + EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500, + wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, + wxAuiNotebook::OnTabClicked) + EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500, + wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, + wxAuiNotebook::OnTabBeginDrag) + EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500, + wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, + wxAuiNotebook::OnTabEndDrag) + EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500, + wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, + wxAuiNotebook::OnTabDragMotion) + EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500, + wxEVT_COMMAND_AUINOTEBOOK_BUTTON, + wxAuiNotebook::OnTabButton) + EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500, + wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, + wxAuiNotebook::OnTabMiddleDown) + EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500, + wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, + wxAuiNotebook::OnTabMiddleUp) + EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500, + wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, + wxAuiNotebook::OnTabRightDown) + EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500, + wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, + wxAuiNotebook::OnTabRightUp) + EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500, + wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, + wxAuiNotebook::OnTabBgDClick) + EVT_NAVIGATION_KEY(wxAuiNotebook::OnNavigationKey) +END_EVENT_TABLE() + +wxAuiNotebook::wxAuiNotebook() +{ + m_curpage = -1; + m_tab_id_counter = wxAuiBaseTabCtrlId; + m_dummy_wnd = NULL; + m_tab_ctrl_height = 20; + m_requested_bmp_size = wxDefaultSize; + m_requested_tabctrl_height = -1; +} + +wxAuiNotebook::wxAuiNotebook(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style) : wxControl(parent, id, pos, size, style) +{ + m_dummy_wnd = NULL; + m_requested_bmp_size = wxDefaultSize; + m_requested_tabctrl_height = -1; + InitNotebook(style); +} + +bool wxAuiNotebook::Create(wxWindow* parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style) +{ + if (!wxControl::Create(parent, id, pos, size, style)) + return false; + + InitNotebook(style); + + return true; +} + +// InitNotebook() contains common initialization +// code called by all constructors +void wxAuiNotebook::InitNotebook(long style) +{ + m_curpage = -1; + m_tab_id_counter = wxAuiBaseTabCtrlId; + m_dummy_wnd = NULL; + m_flags = (unsigned int)style; + m_tab_ctrl_height = 20; + + m_normal_font = *wxNORMAL_FONT; + m_selected_font = *wxNORMAL_FONT; + m_selected_font.SetWeight(wxBOLD); + + SetArtProvider(new wxAuiDefaultTabArt); + + m_dummy_wnd = new wxWindow(this, wxID_ANY, wxPoint(0,0), wxSize(0,0)); + m_dummy_wnd->SetSize(200, 200); + m_dummy_wnd->Show(false); + + m_mgr.SetManagedWindow(this); + m_mgr.SetFlags(wxAUI_MGR_DEFAULT); + m_mgr.SetDockSizeConstraint(1.0, 1.0); // no dock size constraint + + m_mgr.AddPane(m_dummy_wnd, + wxAuiPaneInfo().Name(wxT("dummy")).Bottom().CaptionVisible(false).Show(false)); + + m_mgr.Update(); +} + +wxAuiNotebook::~wxAuiNotebook() +{ + // Indicate we're deleting pages + m_isBeingDeleted = true; + + while ( GetPageCount() > 0 ) + DeletePage(0); + + m_mgr.UnInit(); +} + +void wxAuiNotebook::SetArtProvider(wxAuiTabArt* art) +{ + m_tabs.SetArtProvider(art); + + UpdateTabCtrlHeight(); +} + +// SetTabCtrlHeight() is the highest-level override of the +// tab height. A call to this function effectively enforces a +// specified tab ctrl height, overriding all other considerations, +// such as text or bitmap height. It overrides any call to +// SetUniformBitmapSize(). Specifying a height of -1 reverts +// any previous call and returns to the default behavior + +void wxAuiNotebook::SetTabCtrlHeight(int height) +{ + m_requested_tabctrl_height = height; + + // if window is already initialized, recalculate the tab height + if (m_dummy_wnd) + { + UpdateTabCtrlHeight(); + } +} + + +// SetUniformBitmapSize() ensures that all tabs will have +// the same height, even if some tabs don't have bitmaps +// Passing wxDefaultSize to this function will instruct +// the control to use dynamic tab height-- so when a tab +// with a large bitmap is added, the tab ctrl's height will +// automatically increase to accommodate the bitmap + +void wxAuiNotebook::SetUniformBitmapSize(const wxSize& size) +{ + m_requested_bmp_size = size; + + // if window is already initialized, recalculate the tab height + if (m_dummy_wnd) + { + UpdateTabCtrlHeight(); + } +} + +// UpdateTabCtrlHeight() does the actual tab resizing. It's meant +// to be used interally +void wxAuiNotebook::UpdateTabCtrlHeight() +{ + // get the tab ctrl height we will use + int height = CalculateTabCtrlHeight(); + + // if the tab control height needs to change, update + // all of our tab controls with the new height + if (m_tab_ctrl_height != height) + { + wxAuiTabArt* art = m_tabs.GetArtProvider(); + + m_tab_ctrl_height = height; + + wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes(); + size_t i, pane_count = all_panes.GetCount(); + for (i = 0; i < pane_count; ++i) + { + wxAuiPaneInfo& pane = all_panes.Item(i); + if (pane.name == wxT("dummy")) + continue; + wxTabFrame* tab_frame = (wxTabFrame*)pane.window; + wxAuiTabCtrl* tabctrl = tab_frame->m_tabs; + tab_frame->SetTabCtrlHeight(m_tab_ctrl_height); + tabctrl->SetArtProvider(art->Clone()); + tab_frame->DoSizing(); + } + } +} + +void wxAuiNotebook::UpdateHintWindowSize() +{ + wxSize size = CalculateNewSplitSize(); + + // the placeholder hint window should be set to this size + wxAuiPaneInfo& info = m_mgr.GetPane(wxT("dummy")); + if (info.IsOk()) + { + info.MinSize(size); + info.BestSize(size); + m_dummy_wnd->SetSize(size); + } +} + + +// calculates the size of the new split +wxSize wxAuiNotebook::CalculateNewSplitSize() +{ + // count number of tab controls + int tab_ctrl_count = 0; + wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes(); + size_t i, pane_count = all_panes.GetCount(); + for (i = 0; i < pane_count; ++i) + { + wxAuiPaneInfo& pane = all_panes.Item(i); + if (pane.name == wxT("dummy")) + continue; + tab_ctrl_count++; + } + + wxSize new_split_size; + + // if there is only one tab control, the first split + // should happen around the middle + if (tab_ctrl_count < 2) + { + new_split_size = GetClientSize(); + new_split_size.x /= 2; + new_split_size.y /= 2; + } + else + { + // this is in place of a more complicated calculation + // that needs to be implemented + new_split_size = wxSize(180,180); + } + + return new_split_size; +} + +int wxAuiNotebook::CalculateTabCtrlHeight() +{ + // if a fixed tab ctrl height is specified, + // just return that instead of calculating a + // tab height + if (m_requested_tabctrl_height != -1) + return m_requested_tabctrl_height; + + // find out new best tab height + wxAuiTabArt* art = m_tabs.GetArtProvider(); + + return art->GetBestTabCtrlSize(this, + m_tabs.GetPages(), + m_requested_bmp_size); +} + + +wxAuiTabArt* wxAuiNotebook::GetArtProvider() const +{ + return m_tabs.GetArtProvider(); +} + +void wxAuiNotebook::SetWindowStyleFlag(long style) +{ + wxControl::SetWindowStyleFlag(style); + + m_flags = (unsigned int)style; + + // if the control is already initialized + if (m_mgr.GetManagedWindow() == (wxWindow*)this) + { + // let all of the tab children know about the new style + + wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes(); + size_t i, pane_count = all_panes.GetCount(); + for (i = 0; i < pane_count; ++i) + { + wxAuiPaneInfo& pane = all_panes.Item(i); + if (pane.name == wxT("dummy")) + continue; + wxTabFrame* tabframe = (wxTabFrame*)pane.window; + wxAuiTabCtrl* tabctrl = tabframe->m_tabs; + tabctrl->SetFlags(m_flags); + tabframe->DoSizing(); + tabctrl->Refresh(); + tabctrl->Update(); + } + } +} + + +bool wxAuiNotebook::AddPage(wxWindow* page, + const wxString& caption, + bool select, + const wxBitmap& bitmap) +{ + return InsertPage(GetPageCount(), page, caption, select, bitmap); +} + +bool wxAuiNotebook::InsertPage(size_t page_idx, + wxWindow* page, + const wxString& caption, + bool select, + const wxBitmap& bitmap) +{ + wxASSERT_MSG(page, wxT("page pointer must be non-NULL")); + if (!page) + return false; + + page->Reparent(this); + + wxAuiNotebookPage info; + info.window = page; + info.caption = caption; + info.bitmap = bitmap; + info.active = false; + + // if there are currently no tabs, the first added + // tab must be active + if (m_tabs.GetPageCount() == 0) + info.active = true; + + m_tabs.InsertPage(page, info, page_idx); + + // if that was the first page added, even if + // select is false, it must become the "current page" + // (though no select events will be fired) + if (!select && m_tabs.GetPageCount() == 1) + select = true; + //m_curpage = GetPageIndex(page); + + wxAuiTabCtrl* active_tabctrl = GetActiveTabCtrl(); + if (page_idx >= active_tabctrl->GetPageCount()) + active_tabctrl->AddPage(page, info); + else + active_tabctrl->InsertPage(page, info, page_idx); + + UpdateTabCtrlHeight(); + DoSizing(); + active_tabctrl->DoShowHide(); + + // adjust selected index + if(m_curpage >= (int) page_idx) + m_curpage++; + + if (select) + { + int idx = m_tabs.GetIdxFromWindow(page); + wxASSERT_MSG(idx != -1, wxT("Invalid Page index returned on wxAuiNotebook::InsertPage()")); + + SetSelection(idx); + } + + return true; +} + + +// DeletePage() removes a tab from the multi-notebook, +// and destroys the window as well +bool wxAuiNotebook::DeletePage(size_t page_idx) +{ + if (page_idx >= m_tabs.GetPageCount()) + return false; + + wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx); + + // hide the window in advance, as this will + // prevent flicker + if ( !IsBeingDeleted() ) + ShowWnd(wnd, false); + + if (!RemovePage(page_idx)) + return false; + + // actually destroy the window now +#if wxUSE_MDI + if (wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame))) + { + // delete the child frame with pending delete, as is + // customary with frame windows + if (!wxPendingDelete.Member(wnd)) + wxPendingDelete.Append(wnd); + } + else +#endif + { + wnd->Destroy(); + } + + return true; +} + + + +// RemovePage() removes a tab from the multi-notebook, +// but does not destroy the window +bool wxAuiNotebook::RemovePage(size_t page_idx) +{ + // save active window pointer + wxWindow* active_wnd = NULL; + if (m_curpage >= 0) + active_wnd = m_tabs.GetWindowFromIdx(m_curpage); + + // save pointer of window being deleted + wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx); + wxWindow* new_active = NULL; + + // make sure we found the page + if (!wnd) + return false; + + // find out which onscreen tab ctrl owns this tab + wxAuiTabCtrl* ctrl; + int ctrl_idx; + if (!FindTab(wnd, &ctrl, &ctrl_idx)) + return false; + + bool is_curpage = (m_curpage == (int)page_idx); + bool is_active_in_split = ctrl->GetPage(ctrl_idx).active; + + + // remove the tab from main catalog + if (!m_tabs.RemovePage(wnd)) + return false; + + // remove the tab from the onscreen tab ctrl + ctrl->RemovePage(wnd); + + if (is_active_in_split) + { + int ctrl_new_page_count = (int)ctrl->GetPageCount(); + + if (ctrl_idx >= ctrl_new_page_count) + ctrl_idx = ctrl_new_page_count-1; + + if (ctrl_idx >= 0 && ctrl_idx < (int)ctrl->GetPageCount()) + { + // set new page as active in the tab split + ctrl->SetActivePage(ctrl_idx); + + // if the page deleted was the current page for the + // entire tab control, then record the window + // pointer of the new active page for activation + if (is_curpage) + { + new_active = ctrl->GetWindowFromIdx(ctrl_idx); + } + } + } + else + { + // we are not deleting the active page, so keep it the same + new_active = active_wnd; + } + + + if (!new_active) + { + // we haven't yet found a new page to active, + // so select the next page from the main tab + // catalogue + + if (page_idx < m_tabs.GetPageCount()) + { + new_active = m_tabs.GetPage(page_idx).window; + } + + if (!new_active && m_tabs.GetPageCount() > 0) + { + new_active = m_tabs.GetPage(0).window; + } + } + + + RemoveEmptyTabFrames(); + + // set new active pane + m_curpage = -1; + if (new_active && !m_isBeingDeleted) + { + SetSelection(m_tabs.GetIdxFromWindow(new_active)); + } + + return true; +} + +// GetPageIndex() returns the index of the page, or -1 if the +// page could not be located in the notebook +int wxAuiNotebook::GetPageIndex(wxWindow* page_wnd) const +{ + return m_tabs.GetIdxFromWindow(page_wnd); +} + + + +// SetPageText() changes the tab caption of the specified page +bool wxAuiNotebook::SetPageText(size_t page_idx, const wxString& text) +{ + if (page_idx >= m_tabs.GetPageCount()) + return false; + + // update our own tab catalog + wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx); + page_info.caption = text; + + // update what's on screen + wxAuiTabCtrl* ctrl; + int ctrl_idx; + if (FindTab(page_info.window, &ctrl, &ctrl_idx)) + { + wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx); + info.caption = text; + ctrl->Refresh(); + ctrl->Update(); + } + + return true; +} + +// returns the page caption +wxString wxAuiNotebook::GetPageText(size_t page_idx) const +{ + if (page_idx >= m_tabs.GetPageCount()) + return wxEmptyString; + + // update our own tab catalog + const wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx); + return page_info.caption; +} + +bool wxAuiNotebook::SetPageBitmap(size_t page_idx, const wxBitmap& bitmap) +{ + if (page_idx >= m_tabs.GetPageCount()) + return false; + + // update our own tab catalog + wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx); + page_info.bitmap = bitmap; + + // tab height might have changed + UpdateTabCtrlHeight(); + + // update what's on screen + wxAuiTabCtrl* ctrl; + int ctrl_idx; + if (FindTab(page_info.window, &ctrl, &ctrl_idx)) + { + wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx); + info.bitmap = bitmap; + ctrl->Refresh(); + ctrl->Update(); + } + + return true; +} + +// returns the page bitmap +wxBitmap wxAuiNotebook::GetPageBitmap(size_t page_idx) const +{ + if (page_idx >= m_tabs.GetPageCount()) + return wxBitmap(); + + // update our own tab catalog + const wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx); + return page_info.bitmap; +} + +// GetSelection() returns the index of the currently active page +int wxAuiNotebook::GetSelection() const +{ + return m_curpage; +} + +// SetSelection() sets the currently active page +size_t wxAuiNotebook::SetSelection(size_t new_page) +{ + wxWindow* wnd = m_tabs.GetWindowFromIdx(new_page); + if (!wnd) + return m_curpage; + + // don't change the page unless necessary; + // however, clicking again on a tab should give it the focus. + if ((int)new_page == m_curpage) + { + wxAuiTabCtrl* ctrl; + int ctrl_idx; + if (FindTab(wnd, &ctrl, &ctrl_idx)) + { + if (FindFocus() != ctrl) + ctrl->SetFocus(); + } + return m_curpage; + } + + wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId); + evt.SetSelection(new_page); + evt.SetOldSelection(m_curpage); + evt.SetEventObject(this); + if (!GetEventHandler()->ProcessEvent(evt) || evt.IsAllowed()) + { + int old_curpage = m_curpage; + m_curpage = new_page; + + // program allows the page change + evt.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED); + (void)GetEventHandler()->ProcessEvent(evt); + + + wxAuiTabCtrl* ctrl; + int ctrl_idx; + if (FindTab(wnd, &ctrl, &ctrl_idx)) + { + m_tabs.SetActivePage(wnd); + + ctrl->SetActivePage(ctrl_idx); + DoSizing(); + ctrl->DoShowHide(); + + ctrl->MakeTabVisible(ctrl_idx, ctrl); + + // set fonts + wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes(); + size_t i, pane_count = all_panes.GetCount(); + for (i = 0; i < pane_count; ++i) + { + wxAuiPaneInfo& pane = all_panes.Item(i); + if (pane.name == wxT("dummy")) + continue; + wxAuiTabCtrl* tabctrl = ((wxTabFrame*)pane.window)->m_tabs; + if (tabctrl != ctrl) + tabctrl->SetSelectedFont(m_normal_font); + else + tabctrl->SetSelectedFont(m_selected_font); + tabctrl->Refresh(); + } + + // Set the focus to the page if we're not currently focused on the tab. + // This is Firefox-like behaviour. + if (wnd->IsShownOnScreen() && FindFocus() != ctrl) + wnd->SetFocus(); + + return old_curpage; + } + } + + return m_curpage; +} + +// GetPageCount() returns the total number of +// pages managed by the multi-notebook +size_t wxAuiNotebook::GetPageCount() const +{ + return m_tabs.GetPageCount(); +} + +// GetPage() returns the wxWindow pointer of the +// specified page +wxWindow* wxAuiNotebook::GetPage(size_t page_idx) const +{ + wxASSERT(page_idx < m_tabs.GetPageCount()); + + return m_tabs.GetWindowFromIdx(page_idx); +} + +// DoSizing() performs all sizing operations in each tab control +void wxAuiNotebook::DoSizing() +{ + wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes(); + size_t i, pane_count = all_panes.GetCount(); + for (i = 0; i < pane_count; ++i) + { + if (all_panes.Item(i).name == wxT("dummy")) + continue; + + wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window; + tabframe->DoSizing(); + } +} + +// GetActiveTabCtrl() returns the active tab control. It is +// called to determine which control gets new windows being added +wxAuiTabCtrl* wxAuiNotebook::GetActiveTabCtrl() +{ + if (m_curpage >= 0 && m_curpage < (int)m_tabs.GetPageCount()) + { + wxAuiTabCtrl* ctrl; + int idx; + + // find the tab ctrl with the current page + if (FindTab(m_tabs.GetPage(m_curpage).window, + &ctrl, &idx)) + { + return ctrl; + } + } + + // no current page, just find the first tab ctrl + wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes(); + size_t i, pane_count = all_panes.GetCount(); + for (i = 0; i < pane_count; ++i) + { + if (all_panes.Item(i).name == wxT("dummy")) + continue; + + wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window; + return tabframe->m_tabs; + } + + // If there is no tabframe at all, create one + wxTabFrame* tabframe = new wxTabFrame; + tabframe->SetTabCtrlHeight(m_tab_ctrl_height); + tabframe->m_tabs = new wxAuiTabCtrl(this, + m_tab_id_counter++, + wxDefaultPosition, + wxDefaultSize, + wxNO_BORDER|wxWANTS_CHARS); + tabframe->m_tabs->SetFlags(m_flags); + tabframe->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone()); + m_mgr.AddPane(tabframe, + wxAuiPaneInfo().Center().CaptionVisible(false)); + + m_mgr.Update(); + + return tabframe->m_tabs; +} + +// FindTab() finds the tab control that currently contains the window as well +// as the index of the window in the tab control. It returns true if the +// window was found, otherwise false. +bool wxAuiNotebook::FindTab(wxWindow* page, wxAuiTabCtrl** ctrl, int* idx) +{ + wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes(); + size_t i, pane_count = all_panes.GetCount(); + for (i = 0; i < pane_count; ++i) + { + if (all_panes.Item(i).name == wxT("dummy")) + continue; + + wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window; + + int page_idx = tabframe->m_tabs->GetIdxFromWindow(page); + if (page_idx != -1) + { + *ctrl = tabframe->m_tabs; + *idx = page_idx; + return true; + } + } + + return false; +} + +void wxAuiNotebook::Split(size_t page, int direction) +{ + wxSize cli_size = GetClientSize(); + + // get the page's window pointer + wxWindow* wnd = GetPage(page); + if (!wnd) + return; + + // notebooks with 1 or less pages can't be split + if (GetPageCount() < 2) + return; + + // find out which tab control the page currently belongs to + wxAuiTabCtrl *src_tabs, *dest_tabs; + int src_idx = -1; + src_tabs = NULL; + if (!FindTab(wnd, &src_tabs, &src_idx)) + return; + if (!src_tabs || src_idx == -1) + return; + + // choose a split size + wxSize split_size; + if (GetPageCount() > 2) + { + split_size = CalculateNewSplitSize(); + } + else + { + // because there are two panes, always split them + // equally + split_size = GetClientSize(); + split_size.x /= 2; + split_size.y /= 2; + } + + + // create a new tab frame + wxTabFrame* new_tabs = new wxTabFrame; + new_tabs->m_rect = wxRect(wxPoint(0,0), split_size); + new_tabs->SetTabCtrlHeight(m_tab_ctrl_height); + new_tabs->m_tabs = new wxAuiTabCtrl(this, + m_tab_id_counter++, + wxDefaultPosition, + wxDefaultSize, + wxNO_BORDER|wxWANTS_CHARS); + new_tabs->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone()); + new_tabs->m_tabs->SetFlags(m_flags); + dest_tabs = new_tabs->m_tabs; + + // create a pane info structure with the information + // about where the pane should be added + wxAuiPaneInfo pane_info = wxAuiPaneInfo().Bottom().CaptionVisible(false); + wxPoint mouse_pt; + + if (direction == wxLEFT) + { + pane_info.Left(); + mouse_pt = wxPoint(0, cli_size.y/2); + } + else if (direction == wxRIGHT) + { + pane_info.Right(); + mouse_pt = wxPoint(cli_size.x, cli_size.y/2); + } + else if (direction == wxTOP) + { + pane_info.Top(); + mouse_pt = wxPoint(cli_size.x/2, 0); + } + else if (direction == wxBOTTOM) + { + pane_info.Bottom(); + mouse_pt = wxPoint(cli_size.x/2, cli_size.y); + } + + m_mgr.AddPane(new_tabs, pane_info, mouse_pt); + m_mgr.Update(); + + // remove the page from the source tabs + wxAuiNotebookPage page_info = src_tabs->GetPage(src_idx); + page_info.active = false; + src_tabs->RemovePage(page_info.window); + if (src_tabs->GetPageCount() > 0) + { + src_tabs->SetActivePage((size_t)0); + src_tabs->DoShowHide(); + src_tabs->Refresh(); + } + + + // add the page to the destination tabs + dest_tabs->InsertPage(page_info.window, page_info, 0); + + if (src_tabs->GetPageCount() == 0) + { + RemoveEmptyTabFrames(); + } + + DoSizing(); + dest_tabs->DoShowHide(); + dest_tabs->Refresh(); + + // force the set selection function reset the selection + m_curpage = -1; + + // set the active page to the one we just split off + SetSelection(m_tabs.GetIdxFromWindow(page_info.window)); + + UpdateHintWindowSize(); +} + + +void wxAuiNotebook::OnSize(wxSizeEvent& evt) +{ + UpdateHintWindowSize(); + + evt.Skip(); +} + +void wxAuiNotebook::OnTabClicked(wxCommandEvent& command_evt) +{ + wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt; + + wxAuiTabCtrl* ctrl = (wxAuiTabCtrl*)evt.GetEventObject(); + wxASSERT(ctrl != NULL); + + wxWindow* wnd = ctrl->GetWindowFromIdx(evt.GetSelection()); + wxASSERT(wnd != NULL); + + int idx = m_tabs.GetIdxFromWindow(wnd); + wxASSERT(idx != -1); + + + // since a tab was clicked, let the parent know that we received + // the focus, even if we will assign that focus immediately + // to the child tab in the SetSelection call below + // (the child focus event will also let wxAuiManager, if any, + // know that the notebook control has been activated) + + wxWindow* parent = GetParent(); + if (parent) + { + wxChildFocusEvent eventFocus(this); + parent->GetEventHandler()->ProcessEvent(eventFocus); + } + + + SetSelection(idx); +} + +void wxAuiNotebook::OnTabBgDClick(wxCommandEvent& WXUNUSED(evt)) +{ + // notify owner that the tabbar background has been double-clicked + wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, m_windowId); + e.SetEventObject(this); + GetEventHandler()->ProcessEvent(e); +} + +void wxAuiNotebook::OnTabBeginDrag(wxCommandEvent&) +{ + m_last_drag_x = 0; +} + +void wxAuiNotebook::OnTabDragMotion(wxCommandEvent& evt) +{ + wxPoint screen_pt = ::wxGetMousePosition(); + wxPoint client_pt = ScreenToClient(screen_pt); + wxPoint zero(0,0); + + wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject(); + wxAuiTabCtrl* dest_tabs = GetTabCtrlFromPoint(client_pt); + + if (dest_tabs == src_tabs) + { + if (src_tabs) + { + src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW)); + } + + // always hide the hint for inner-tabctrl drag + m_mgr.HideHint(); + + // if tab moving is not allowed, leave + if (!(m_flags & wxAUI_NB_TAB_MOVE)) + { + return; + } + + wxPoint pt = dest_tabs->ScreenToClient(screen_pt); + wxWindow* dest_location_tab; + + // this is an inner-tab drag/reposition + if (dest_tabs->TabHitTest(pt.x, pt.y, &dest_location_tab)) + { + int src_idx = evt.GetSelection(); + int dest_idx = dest_tabs->GetIdxFromWindow(dest_location_tab); + + // prevent jumpy drag + if ((src_idx == dest_idx) || dest_idx == -1 || + (src_idx > dest_idx && m_last_drag_x <= pt.x) || + (src_idx < dest_idx && m_last_drag_x >= pt.x)) + { + m_last_drag_x = pt.x; + return; + } + + + wxWindow* src_tab = dest_tabs->GetWindowFromIdx(src_idx); + dest_tabs->MovePage(src_tab, dest_idx); + dest_tabs->SetActivePage((size_t)dest_idx); + dest_tabs->DoShowHide(); + dest_tabs->Refresh(); + m_last_drag_x = pt.x; + + } + + return; + } + + + // if external drag is allowed, check if the tab is being dragged + // over a different wxAuiNotebook control + if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE) + { + wxWindow* tab_ctrl = ::wxFindWindowAtPoint(screen_pt); + + // if we aren't over any window, stop here + if (!tab_ctrl) + return; + + // make sure we are not over the hint window + if (!tab_ctrl->IsKindOf(CLASSINFO(wxFrame))) + { + while (tab_ctrl) + { + if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl))) + break; + tab_ctrl = tab_ctrl->GetParent(); + } + + if (tab_ctrl) + { + wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent(); + + if (nb != this) + { + wxRect hint_rect = tab_ctrl->GetClientRect(); + tab_ctrl->ClientToScreen(&hint_rect.x, &hint_rect.y); + m_mgr.ShowHint(hint_rect); + return; + } + } + } + else + { + if (!dest_tabs) + { + // we are either over a hint window, or not over a tab + // window, and there is no where to drag to, so exit + return; + } + } + } + + + // if there are less than two panes, split can't happen, so leave + if (m_tabs.GetPageCount() < 2) + return; + + // if tab moving is not allowed, leave + if (!(m_flags & wxAUI_NB_TAB_SPLIT)) + return; + + + if (src_tabs) + { + src_tabs->SetCursor(wxCursor(wxCURSOR_SIZING)); + } + + + if (dest_tabs) + { + wxRect hint_rect = dest_tabs->GetRect(); + ClientToScreen(&hint_rect.x, &hint_rect.y); + m_mgr.ShowHint(hint_rect); + } + else + { + m_mgr.DrawHintRect(m_dummy_wnd, client_pt, zero); + } +} + + + +void wxAuiNotebook::OnTabEndDrag(wxCommandEvent& command_evt) +{ + wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt; + + m_mgr.HideHint(); + + + wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject(); + wxAuiTabCtrl* dest_tabs = NULL; + if (src_tabs) + { + // set cursor back to an arrow + src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW)); + } + + // get the mouse position, which will be used to determine the drop point + wxPoint mouse_screen_pt = ::wxGetMousePosition(); + wxPoint mouse_client_pt = ScreenToClient(mouse_screen_pt); + + + + // check for an external move + if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE) + { + wxWindow* tab_ctrl = ::wxFindWindowAtPoint(mouse_screen_pt); + + while (tab_ctrl) + { + if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl))) + break; + tab_ctrl = tab_ctrl->GetParent(); + } + + if (tab_ctrl) + { + wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent(); + + if (nb != this) + { + // find out from the destination control + // if it's ok to drop this tab here + wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, m_windowId); + e.SetSelection(evt.GetSelection()); + e.SetOldSelection(evt.GetSelection()); + e.SetEventObject(this); + e.SetDragSource(this); + e.Veto(); // dropping must be explicitly approved by control owner + + nb->GetEventHandler()->ProcessEvent(e); + + if (!e.IsAllowed()) + { + // no answer or negative answer + m_mgr.HideHint(); + return; + } + + // drop was allowed + int src_idx = evt.GetSelection(); + wxWindow* src_page = src_tabs->GetWindowFromIdx(src_idx); + + // Check that it's not an impossible parent relationship + wxWindow* p = nb; + while (p && !p->IsTopLevel()) + { + if (p == src_page) + { + return; + } + p = p->GetParent(); + } + + // get main index of the page + int main_idx = m_tabs.GetIdxFromWindow(src_page); + + // make a copy of the page info + wxAuiNotebookPage page_info = m_tabs.GetPage((size_t)main_idx); + + // remove the page from the source notebook + RemovePage(main_idx); + + // reparent the page + src_page->Reparent(nb); + + + // found out the insert idx + wxAuiTabCtrl* dest_tabs = (wxAuiTabCtrl*)tab_ctrl; + wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt); + + wxWindow* target = NULL; + int insert_idx = -1; + dest_tabs->TabHitTest(pt.x, pt.y, &target); + if (target) + { + insert_idx = dest_tabs->GetIdxFromWindow(target); + } + + + // add the page to the new notebook + if (insert_idx == -1) + insert_idx = dest_tabs->GetPageCount(); + dest_tabs->InsertPage(page_info.window, page_info, insert_idx); + nb->m_tabs.AddPage(page_info.window, page_info); + + nb->DoSizing(); + dest_tabs->DoShowHide(); + dest_tabs->Refresh(); + + // set the selection in the destination tab control + nb->SetSelection(nb->m_tabs.GetIdxFromWindow(page_info.window)); + + // notify owner that the tab has been dragged + wxAuiNotebookEvent e2(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, m_windowId); + e2.SetSelection(evt.GetSelection()); + e2.SetOldSelection(evt.GetSelection()); + e2.SetEventObject(this); + GetEventHandler()->ProcessEvent(e2); + + return; + } + } + } + + + + + // only perform a tab split if it's allowed + if ((m_flags & wxAUI_NB_TAB_SPLIT) && m_tabs.GetPageCount() >= 2) + { + // If the pointer is in an existing tab frame, do a tab insert + wxWindow* hit_wnd = ::wxFindWindowAtPoint(mouse_screen_pt); + wxTabFrame* tab_frame = (wxTabFrame*)GetTabFrameFromTabCtrl(hit_wnd); + int insert_idx = -1; + if (tab_frame) + { + dest_tabs = tab_frame->m_tabs; + + if (dest_tabs == src_tabs) + return; + + + wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt); + wxWindow* target = NULL; + dest_tabs->TabHitTest(pt.x, pt.y, &target); + if (target) + { + insert_idx = dest_tabs->GetIdxFromWindow(target); + } + } + else + { + wxPoint zero(0,0); + wxRect rect = m_mgr.CalculateHintRect(m_dummy_wnd, + mouse_client_pt, + zero); + if (rect.IsEmpty()) + { + // there is no suitable drop location here, exit out + return; + } + + // If there is no tabframe at all, create one + wxTabFrame* new_tabs = new wxTabFrame; + new_tabs->m_rect = wxRect(wxPoint(0,0), CalculateNewSplitSize()); + new_tabs->SetTabCtrlHeight(m_tab_ctrl_height); + new_tabs->m_tabs = new wxAuiTabCtrl(this, + m_tab_id_counter++, + wxDefaultPosition, + wxDefaultSize, + wxNO_BORDER|wxWANTS_CHARS); + new_tabs->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone()); + new_tabs->m_tabs->SetFlags(m_flags); + + m_mgr.AddPane(new_tabs, + wxAuiPaneInfo().Bottom().CaptionVisible(false), + mouse_client_pt); + m_mgr.Update(); + dest_tabs = new_tabs->m_tabs; + } + + + + // remove the page from the source tabs + wxAuiNotebookPage page_info = src_tabs->GetPage(evt.GetSelection()); + page_info.active = false; + src_tabs->RemovePage(page_info.window); + if (src_tabs->GetPageCount() > 0) + { + src_tabs->SetActivePage((size_t)0); + src_tabs->DoShowHide(); + src_tabs->Refresh(); + } + + + + // add the page to the destination tabs + if (insert_idx == -1) + insert_idx = dest_tabs->GetPageCount(); + dest_tabs->InsertPage(page_info.window, page_info, insert_idx); + + if (src_tabs->GetPageCount() == 0) + { + RemoveEmptyTabFrames(); + } + + DoSizing(); + dest_tabs->DoShowHide(); + dest_tabs->Refresh(); + + // force the set selection function reset the selection + m_curpage = -1; + + // set the active page to the one we just split off + SetSelection(m_tabs.GetIdxFromWindow(page_info.window)); + + UpdateHintWindowSize(); + } + + // notify owner that the tab has been dragged + wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, m_windowId); + e.SetSelection(evt.GetSelection()); + e.SetOldSelection(evt.GetSelection()); + e.SetEventObject(this); + GetEventHandler()->ProcessEvent(e); +} + + + +wxAuiTabCtrl* wxAuiNotebook::GetTabCtrlFromPoint(const wxPoint& pt) +{ + // if we've just removed the last tab from the source + // tab set, the remove the tab control completely + wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes(); + size_t i, pane_count = all_panes.GetCount(); + for (i = 0; i < pane_count; ++i) + { + if (all_panes.Item(i).name == wxT("dummy")) + continue; + + wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window; + if (tabframe->m_tab_rect.Contains(pt)) + return tabframe->m_tabs; + } + + return NULL; +} + +wxWindow* wxAuiNotebook::GetTabFrameFromTabCtrl(wxWindow* tab_ctrl) +{ + // if we've just removed the last tab from the source + // tab set, the remove the tab control completely + wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes(); + size_t i, pane_count = all_panes.GetCount(); + for (i = 0; i < pane_count; ++i) + { + if (all_panes.Item(i).name == wxT("dummy")) + continue; + + wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window; + if (tabframe->m_tabs == tab_ctrl) + { + return tabframe; + } + } + + return NULL; +} + +void wxAuiNotebook::RemoveEmptyTabFrames() +{ + // if we've just removed the last tab from the source + // tab set, the remove the tab control completely + wxAuiPaneInfoArray all_panes = m_mgr.GetAllPanes(); + size_t i, pane_count = all_panes.GetCount(); + for (i = 0; i < pane_count; ++i) + { + if (all_panes.Item(i).name == wxT("dummy")) + continue; + + wxTabFrame* tab_frame = (wxTabFrame*)all_panes.Item(i).window; + if (tab_frame->m_tabs->GetPageCount() == 0) + { + m_mgr.DetachPane(tab_frame); + + // use pending delete because sometimes during + // window closing, refreshs are pending + if (!wxPendingDelete.Member(tab_frame->m_tabs)) + wxPendingDelete.Append(tab_frame->m_tabs); + + tab_frame->m_tabs = NULL; + + delete tab_frame; + } + } + + + // check to see if there is still a center pane; + // if there isn't, make a frame the center pane + wxAuiPaneInfoArray panes = m_mgr.GetAllPanes(); + pane_count = panes.GetCount(); + wxWindow* first_good = NULL; + bool center_found = false; + for (i = 0; i < pane_count; ++i) + { + if (panes.Item(i).name == wxT("dummy")) + continue; + if (panes.Item(i).dock_direction == wxAUI_DOCK_CENTRE) + center_found = true; + if (!first_good) + first_good = panes.Item(i).window; + } + + if (!center_found && first_good) + { + m_mgr.GetPane(first_good).Centre(); + } + + if (!m_isBeingDeleted) + m_mgr.Update(); +} + +void wxAuiNotebook::OnChildFocus(wxChildFocusEvent& evt) +{ + // if we're dragging a tab, don't change the current selection. + // This code prevents a bug that used to happen when the hint window + // was hidden. In the bug, the focus would return to the notebook + // child, which would then enter this handler and call + // SetSelection, which is not desired turn tab dragging. + + wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes(); + size_t i, pane_count = all_panes.GetCount(); + for (i = 0; i < pane_count; ++i) + { + wxAuiPaneInfo& pane = all_panes.Item(i); + if (pane.name == wxT("dummy")) + continue; + wxTabFrame* tabframe = (wxTabFrame*)pane.window; + if (tabframe->m_tabs->IsDragging()) + return; + } + + + // change the tab selection to the child + // which was focused + int idx = m_tabs.GetIdxFromWindow(evt.GetWindow()); + if (idx != -1 && idx != m_curpage) + { + SetSelection(idx); + } +} + +void wxAuiNotebook::OnNavigationKey(wxNavigationKeyEvent& event) +{ + if ( event.IsWindowChange() ) { + // change pages + // FIXME: the problem with this is that if we have a split notebook, + // we selection may go all over the place. + AdvanceSelection(event.GetDirection()); + } + else { + // we get this event in 3 cases + // + // a) one of our pages might have generated it because the user TABbed + // out from it in which case we should propagate the event upwards and + // our parent will take care of setting the focus to prev/next sibling + // + // or + // + // b) the parent panel wants to give the focus to us so that we + // forward it to our selected page. We can't deal with this in + // OnSetFocus() because we don't know which direction the focus came + // from in this case and so can't choose between setting the focus to + // first or last panel child + // + // or + // + // c) we ourselves (see MSWTranslateMessage) generated the event + // + wxWindow * const parent = GetParent(); + + // the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE + const bool isFromParent = event.GetEventObject() == (wxObject*) parent; + const bool isFromSelf = event.GetEventObject() == (wxObject*) this; + + if ( isFromParent || isFromSelf ) + { + // no, it doesn't come from child, case (b) or (c): forward to a + // page but only if direction is backwards (TAB) or from ourselves, + if ( GetSelection() != wxNOT_FOUND && + (!event.GetDirection() || isFromSelf) ) + { + // so that the page knows that the event comes from it's parent + // and is being propagated downwards + event.SetEventObject(this); + + wxWindow *page = GetPage(GetSelection()); + if ( !page->GetEventHandler()->ProcessEvent(event) ) + { + page->SetFocus(); + } + //else: page manages focus inside it itself + } + else // otherwise set the focus to the notebook itself + { + SetFocus(); + } + } + else + { + // it comes from our child, case (a), pass to the parent, but only + // if the direction is forwards. Otherwise set the focus to the + // notebook itself. The notebook is always the 'first' control of a + // page. + if ( !event.GetDirection() ) + { + SetFocus(); + } + else if ( parent ) + { + event.SetCurrentFocus(this); + parent->GetEventHandler()->ProcessEvent(event); + } + } + } +} + +void wxAuiNotebook::OnTabButton(wxCommandEvent& command_evt) +{ + wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt; + wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject(); + + int button_id = evt.GetInt(); + + if (button_id == wxAUI_BUTTON_CLOSE) + { + int selection = evt.GetSelection(); + + if (selection == -1) + { + // if the close button is to the right, use the active + // page selection to determine which page to close + selection = tabs->GetActivePage(); + } + + if (selection != -1) + { + wxWindow* close_wnd = tabs->GetWindowFromIdx(selection); + + // ask owner if it's ok to close the tab + wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, m_windowId); + const int idx = m_tabs.GetIdxFromWindow(close_wnd); + e.SetSelection(idx); + e.SetOldSelection(evt.GetSelection()); + e.SetEventObject(this); + GetEventHandler()->ProcessEvent(e); + if (!e.IsAllowed()) + return; + + +#if wxUSE_MDI + if (close_wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame))) + { + close_wnd->Close(); + } + else +#endif + { + int main_idx = m_tabs.GetIdxFromWindow(close_wnd); + DeletePage(main_idx); + } + + // notify owner that the tab has been closed + wxAuiNotebookEvent e2(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, m_windowId); + e2.SetSelection(idx); + e2.SetEventObject(this); + GetEventHandler()->ProcessEvent(e2); + } + } +} + +void wxAuiNotebook::OnTabMiddleDown(wxCommandEvent& evt) +{ + // patch event through to owner + wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject(); + wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection()); + + wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, m_windowId); + e.SetSelection(m_tabs.GetIdxFromWindow(wnd)); + e.SetEventObject(this); + GetEventHandler()->ProcessEvent(e); +} + +void wxAuiNotebook::OnTabMiddleUp(wxCommandEvent& evt) +{ + // if the wxAUI_NB_MIDDLE_CLICK_CLOSE is specified, middle + // click should act like a tab close action. However, first + // give the owner an opportunity to handle the middle up event + // for custom action + + wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject(); + wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection()); + + wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, m_windowId); + e.SetSelection(m_tabs.GetIdxFromWindow(wnd)); + e.SetEventObject(this); + if (GetEventHandler()->ProcessEvent(e)) + return; + if (!e.IsAllowed()) + return; + + // check if we are supposed to close on middle-up + if ((m_flags & wxAUI_NB_MIDDLE_CLICK_CLOSE) == 0) + return; + + // simulate the user pressing the close button on the tab + evt.SetInt(wxAUI_BUTTON_CLOSE); + OnTabButton(evt); +} + +void wxAuiNotebook::OnTabRightDown(wxCommandEvent& evt) +{ + // patch event through to owner + wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject(); + wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection()); + + wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, m_windowId); + e.SetSelection(m_tabs.GetIdxFromWindow(wnd)); + e.SetEventObject(this); + GetEventHandler()->ProcessEvent(e); +} + +void wxAuiNotebook::OnTabRightUp(wxCommandEvent& evt) +{ + // patch event through to owner + wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject(); + wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection()); + + wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, m_windowId); + e.SetSelection(m_tabs.GetIdxFromWindow(wnd)); + e.SetEventObject(this); + GetEventHandler()->ProcessEvent(e); +} + + + +// Sets the normal font +void wxAuiNotebook::SetNormalFont(const wxFont& font) +{ + m_normal_font = font; + GetArtProvider()->SetNormalFont(font); +} + +// Sets the selected tab font +void wxAuiNotebook::SetSelectedFont(const wxFont& font) +{ + m_selected_font = font; + GetArtProvider()->SetSelectedFont(font); +} + +// Sets the measuring font +void wxAuiNotebook::SetMeasuringFont(const wxFont& font) +{ + GetArtProvider()->SetMeasuringFont(font); +} + +// Sets the tab font +bool wxAuiNotebook::SetFont(const wxFont& font) +{ + wxControl::SetFont(font); + + wxFont normalFont(font); + wxFont selectedFont(normalFont); + selectedFont.SetWeight(wxBOLD); + + SetNormalFont(normalFont); + SetSelectedFont(selectedFont); + SetMeasuringFont(selectedFont); + + return true; +} + +// Gets the tab control height +int wxAuiNotebook::GetTabCtrlHeight() const +{ + return m_tab_ctrl_height; +} + +// Gets the height of the notebook for a given page height +int wxAuiNotebook::GetHeightForPageHeight(int pageHeight) +{ + UpdateTabCtrlHeight(); + + int tabCtrlHeight = GetTabCtrlHeight(); + int decorHeight = 2; + return tabCtrlHeight + pageHeight + decorHeight; +} + +// Advances the selection, generation page selection events +void wxAuiNotebook::AdvanceSelection(bool forward) +{ + if (GetPageCount() <= 1) + return; + + int currentSelection = GetSelection(); + + if (forward) + { + if (currentSelection == (int) (GetPageCount() - 1)) + return; + else if (currentSelection == -1) + currentSelection = 0; + else + currentSelection ++; + } + else + { + if (currentSelection <= 0) + return; + else + currentSelection --; + } + + SetSelection(currentSelection); +} + +// Shows the window menu +bool wxAuiNotebook::ShowWindowMenu() +{ + wxAuiTabCtrl* tabCtrl = GetActiveTabCtrl(); + + int idx = tabCtrl->GetArtProvider()->ShowDropDown(tabCtrl, tabCtrl->GetPages(), tabCtrl->GetActivePage()); + + if (idx != -1) + { + wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, tabCtrl->GetId()); + e.SetSelection(idx); + e.SetOldSelection(tabCtrl->GetActivePage()); + e.SetEventObject(tabCtrl); + GetEventHandler()->ProcessEvent(e); + + return true; + } + else + return false; +} + +#endif // wxUSE_AUI diff --git a/Externals/wxWidgets/src/aui/dockart.cpp b/Externals/wxWidgets/src/aui/dockart.cpp new file mode 100644 index 0000000000..b0989200d8 --- /dev/null +++ b/Externals/wxWidgets/src/aui/dockart.cpp @@ -0,0 +1,771 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/aui/dockart.cpp +// Purpose: wxaui: wx advanced user interface - docking window manager +// Author: Benjamin I. Williams +// Modified by: +// Created: 2005-05-17 +// RCS-ID: $Id: dockart.cpp 55210 2008-08-23 18:17:49Z VZ $ +// Copyright: (C) Copyright 2005-2006, Kirix Corporation, All Rights Reserved +// Licence: wxWindows Library Licence, Version 3.1 +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_AUI + +#include "wx/aui/framemanager.h" +#include "wx/aui/dockart.h" + +#ifndef WX_PRECOMP + #include "wx/settings.h" + #include "wx/dcclient.h" + #include "wx/image.h" +#endif + +#ifdef __WXMAC__ +#include "wx/mac/private.h" +#include "wx/graphics.h" +#endif + +#ifdef __WXGTK__ +#include +#include "wx/gtk/win_gtk.h" +#include "wx/renderer.h" +#endif + + +// -- wxAuiDefaultDockArt class implementation -- + +// wxAuiDefaultDockArt is an art provider class which does all of the drawing for +// wxAuiManager. This allows the library caller to customize the dock art +// (probably by deriving from this class), or to completely replace all drawing +// with custom dock art (probably by writing a new stand-alone class derived +// from the wxAuiDockArt base class). The active dock art class can be set via +// wxAuiManager::SetDockArt() + + +// wxAuiBlendColour is used by wxAuiStepColour +unsigned char wxAuiBlendColour(unsigned char fg, unsigned char bg, double alpha) +{ + double result = bg + (alpha * (fg - bg)); + if (result < 0.0) + result = 0.0; + if (result > 255) + result = 255; + return (unsigned char)result; +} + +// wxAuiStepColour() it a utility function that simply darkens +// or lightens a color, based on the specified percentage +// ialpha of 0 would be completely black, 100 completely white +// an ialpha of 100 returns the same colour +wxColor wxAuiStepColour(const wxColor& c, int ialpha) +{ + if (ialpha == 100) + return c; + + unsigned char r = c.Red(), + g = c.Green(), + b = c.Blue(); + unsigned char bg; + + // ialpha is 0..200 where 0 is completely black + // and 200 is completely white and 100 is the same + // convert that to normal alpha 0.0 - 1.0 + ialpha = wxMin(ialpha, 200); + ialpha = wxMax(ialpha, 0); + double alpha = ((double)(ialpha - 100.0))/100.0; + + if (ialpha > 100) + { + // blend with white + bg = 255; + alpha = 1.0 - alpha; // 0 = transparent fg; 1 = opaque fg + } + else + { + // blend with black + bg = 0; + alpha += 1.0; // 0 = transparent fg; 1 = opaque fg + } + + r = wxAuiBlendColour(r, bg, alpha); + g = wxAuiBlendColour(g, bg, alpha); + b = wxAuiBlendColour(b, bg, alpha); + + return wxColour(r, g, b); +} + + +wxColor wxAuiLightContrastColour(const wxColour& c) +{ + int amount = 120; + + // if the color is especially dark, then + // make the contrast even lighter + if (c.Red() < 128 && c.Green() < 128 && c.Blue() < 128) + amount = 160; + + return wxAuiStepColour(c, amount); +} + +// wxAuiBitmapFromBits() is a utility function that creates a +// masked bitmap from raw bits (XBM format) +wxBitmap wxAuiBitmapFromBits(const unsigned char bits[], int w, int h, + const wxColour& color) +{ + wxImage img = wxBitmap((const char*)bits, w, h).ConvertToImage(); + img.Replace(0,0,0,123,123,123); + img.Replace(255,255,255,color.Red(),color.Green(),color.Blue()); + img.SetMaskColour(123,123,123); + return wxBitmap(img); +} + + +static void DrawGradientRectangle(wxDC& dc, + const wxRect& rect, + const wxColour& start_color, + const wxColour& end_color, + int direction) +{ + int rd, gd, bd, high = 0; + rd = end_color.Red() - start_color.Red(); + gd = end_color.Green() - start_color.Green(); + bd = end_color.Blue() - start_color.Blue(); + + if (direction == wxAUI_GRADIENT_VERTICAL) + high = rect.GetHeight()-1; + else + high = rect.GetWidth()-1; + + for (int i = 0; i <= high; ++i) + { + int r,g,b; + + + r = start_color.Red() + (high <= 0 ? 0 : (((i*rd*100)/high)/100)); + g = start_color.Green() + (high <= 0 ? 0 : (((i*gd*100)/high)/100)); + b = start_color.Blue() + (high <= 0 ? 0 : (((i*bd*100)/high)/100)); + + wxPen p(wxColor((unsigned char)r, + (unsigned char)g, + (unsigned char)b)); + dc.SetPen(p); + + if (direction == wxAUI_GRADIENT_VERTICAL) + dc.DrawLine(rect.x, rect.y+i, rect.x+rect.width, rect.y+i); + else + dc.DrawLine(rect.x+i, rect.y, rect.x+i, rect.y+rect.height); + } +} + +wxString wxAuiChopText(wxDC& dc, const wxString& text, int max_size) +{ + wxCoord x,y; + + // first check if the text fits with no problems + dc.GetTextExtent(text, &x, &y); + if (x <= max_size) + return text; + + size_t i, len = text.Length(); + size_t last_good_length = 0; + for (i = 0; i < len; ++i) + { + wxString s = text.Left(i); + s += wxT("..."); + + dc.GetTextExtent(s, &x, &y); + if (x > max_size) + break; + + last_good_length = i; + } + + wxString ret = text.Left(last_good_length); + ret += wxT("..."); + return ret; +} + +wxAuiDefaultDockArt::wxAuiDefaultDockArt() +{ +#ifdef __WXMAC__ + wxBrush toolbarbrush; + toolbarbrush.MacSetTheme( kThemeBrushToolbarBackground ); + wxColor base_colour = toolbarbrush.GetColour(); +#else + wxColor base_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE); +#endif + + // the base_colour is too pale to use as our base colour, + // so darken it a bit -- + if ((255-base_colour.Red()) + + (255-base_colour.Green()) + + (255-base_colour.Blue()) < 60) + { + base_colour = wxAuiStepColour(base_colour, 92); + } + + m_base_colour = base_colour; + wxColor darker1_colour = wxAuiStepColour(base_colour, 85); + wxColor darker2_colour = wxAuiStepColour(base_colour, 75); + wxColor darker3_colour = wxAuiStepColour(base_colour, 60); + wxColor darker4_colour = wxAuiStepColour(base_colour, 50); + wxColor darker5_colour = wxAuiStepColour(base_colour, 40); + + m_active_caption_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); + m_active_caption_gradient_colour = wxAuiLightContrastColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT)); + m_active_caption_text_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + m_inactive_caption_colour = darker1_colour; + m_inactive_caption_gradient_colour = wxAuiStepColour(base_colour, 97); + m_inactive_caption_text_colour = *wxBLACK; + +#ifdef __WXMAC__ + m_sash_brush = toolbarbrush; + m_background_brush = toolbarbrush; + m_gripper_brush = toolbarbrush; +#else + m_sash_brush = wxBrush(base_colour); + m_background_brush = wxBrush(base_colour); + m_gripper_brush = wxBrush(base_colour); +#endif + m_border_pen = wxPen(darker2_colour); + m_gripper_pen1 = wxPen(darker5_colour); + m_gripper_pen2 = wxPen(darker3_colour); + m_gripper_pen3 = *wxWHITE_PEN; + +#ifdef __WXMAC__ + m_caption_font = *wxSMALL_FONT; +#else + m_caption_font = wxFont(8, wxDEFAULT, wxNORMAL, wxNORMAL, FALSE); +#endif + + // some built in bitmaps +#if defined( __WXMAC__ ) + static unsigned char close_bits[]={ + 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x03, 0xF8, 0x01, 0xF0, 0x19, 0xF3, + 0xB8, 0xE3, 0xF0, 0xE1, 0xE0, 0xE0, 0xF0, 0xE1, 0xB8, 0xE3, 0x19, 0xF3, + 0x01, 0xF0, 0x03, 0xF8, 0x0F, 0xFE, 0xFF, 0xFF }; +#elif defined( __WXGTK__) + static unsigned char close_bits[]={ + 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8, + 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef, + 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +#else + static unsigned char close_bits[]={ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xf3, 0xcf, 0xf9, + 0x9f, 0xfc, 0x3f, 0xfe, 0x3f, 0xfe, 0x9f, 0xfc, 0xcf, 0xf9, 0xe7, 0xf3, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +#endif + + static unsigned char maximize_bits[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xf7, 0xf7, 0x07, 0xf0, + 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0x07, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + static unsigned char restore_bits[]={ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xf0, 0x1f, 0xf0, 0xdf, 0xf7, + 0x07, 0xf4, 0x07, 0xf4, 0xf7, 0xf5, 0xf7, 0xf1, 0xf7, 0xfd, 0xf7, 0xfd, + 0x07, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + static unsigned char pin_bits[]={ + 0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0xfc,0xdf,0xfc,0xdf,0xfc, + 0xdf,0xfc,0xdf,0xfc,0xdf,0xfc,0x0f,0xf8,0x7f,0xff,0x7f,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; + +#ifdef __WXMAC__ + m_inactive_close_bitmap = wxAuiBitmapFromBits(close_bits, 16, 16, *wxWHITE); + m_active_close_bitmap = wxAuiBitmapFromBits(close_bits, 16, 16, *wxWHITE ); +#else + m_inactive_close_bitmap = wxAuiBitmapFromBits(close_bits, 16, 16, m_inactive_caption_text_colour); + m_active_close_bitmap = wxAuiBitmapFromBits(close_bits, 16, 16, m_active_caption_text_colour); +#endif + +#ifdef __WXMAC__ + m_inactive_maximize_bitmap = wxAuiBitmapFromBits(maximize_bits, 16, 16, *wxWHITE); + m_active_maximize_bitmap = wxAuiBitmapFromBits(maximize_bits, 16, 16, *wxWHITE ); +#else + m_inactive_maximize_bitmap = wxAuiBitmapFromBits(maximize_bits, 16, 16, m_inactive_caption_text_colour); + m_active_maximize_bitmap = wxAuiBitmapFromBits(maximize_bits, 16, 16, m_active_caption_text_colour); +#endif + +#ifdef __WXMAC__ + m_inactive_restore_bitmap = wxAuiBitmapFromBits(restore_bits, 16, 16, *wxWHITE); + m_active_restore_bitmap = wxAuiBitmapFromBits(restore_bits, 16, 16, *wxWHITE ); +#else + m_inactive_restore_bitmap = wxAuiBitmapFromBits(restore_bits, 16, 16, m_inactive_caption_text_colour); + m_active_restore_bitmap = wxAuiBitmapFromBits(restore_bits, 16, 16, m_active_caption_text_colour); +#endif + + m_inactive_pin_bitmap = wxAuiBitmapFromBits(pin_bits, 16, 16, m_inactive_caption_text_colour); + m_active_pin_bitmap = wxAuiBitmapFromBits(pin_bits, 16, 16, m_active_caption_text_colour); + + // default metric values +#if defined(__WXMAC__) + SInt32 height; + GetThemeMetric( kThemeMetricSmallPaneSplitterHeight , &height ); + m_sash_size = height; +#elif defined(__WXGTK__) + m_sash_size = wxRendererNative::Get().GetSplitterParams(NULL).widthSash; +#else + m_sash_size = 4; +#endif + m_caption_size = 17; + m_border_size = 1; + m_button_size = 14; + m_gripper_size = 9; + m_gradient_type = wxAUI_GRADIENT_VERTICAL; +} + +int wxAuiDefaultDockArt::GetMetric(int id) +{ + switch (id) + { + case wxAUI_DOCKART_SASH_SIZE: return m_sash_size; + case wxAUI_DOCKART_CAPTION_SIZE: return m_caption_size; + case wxAUI_DOCKART_GRIPPER_SIZE: return m_gripper_size; + case wxAUI_DOCKART_PANE_BORDER_SIZE: return m_border_size; + case wxAUI_DOCKART_PANE_BUTTON_SIZE: return m_button_size; + case wxAUI_DOCKART_GRADIENT_TYPE: return m_gradient_type; + default: wxFAIL_MSG(wxT("Invalid Metric Ordinal")); break; + } + + return 0; +} + +void wxAuiDefaultDockArt::SetMetric(int id, int new_val) +{ + switch (id) + { + case wxAUI_DOCKART_SASH_SIZE: m_sash_size = new_val; break; + case wxAUI_DOCKART_CAPTION_SIZE: m_caption_size = new_val; break; + case wxAUI_DOCKART_GRIPPER_SIZE: m_gripper_size = new_val; break; + case wxAUI_DOCKART_PANE_BORDER_SIZE: m_border_size = new_val; break; + case wxAUI_DOCKART_PANE_BUTTON_SIZE: m_button_size = new_val; break; + case wxAUI_DOCKART_GRADIENT_TYPE: m_gradient_type = new_val; break; + default: wxFAIL_MSG(wxT("Invalid Metric Ordinal")); break; + } +} + +wxColour wxAuiDefaultDockArt::GetColour(int id) +{ + switch (id) + { + case wxAUI_DOCKART_BACKGROUND_COLOUR: return m_background_brush.GetColour(); + case wxAUI_DOCKART_SASH_COLOUR: return m_sash_brush.GetColour(); + case wxAUI_DOCKART_INACTIVE_CAPTION_COLOUR: return m_inactive_caption_colour; + case wxAUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR: return m_inactive_caption_gradient_colour; + case wxAUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR: return m_inactive_caption_text_colour; + case wxAUI_DOCKART_ACTIVE_CAPTION_COLOUR: return m_active_caption_colour; + case wxAUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR: return m_active_caption_gradient_colour; + case wxAUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR: return m_active_caption_text_colour; + case wxAUI_DOCKART_BORDER_COLOUR: return m_border_pen.GetColour(); + case wxAUI_DOCKART_GRIPPER_COLOUR: return m_gripper_brush.GetColour(); + default: wxFAIL_MSG(wxT("Invalid Metric Ordinal")); break; + } + + return wxColour(); +} + +void wxAuiDefaultDockArt::SetColour(int id, const wxColor& colour) +{ + switch (id) + { + case wxAUI_DOCKART_BACKGROUND_COLOUR: m_background_brush.SetColour(colour); break; + case wxAUI_DOCKART_SASH_COLOUR: m_sash_brush.SetColour(colour); break; + case wxAUI_DOCKART_INACTIVE_CAPTION_COLOUR: m_inactive_caption_colour = colour; break; + case wxAUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR: m_inactive_caption_gradient_colour = colour; break; + case wxAUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR: m_inactive_caption_text_colour = colour; break; + case wxAUI_DOCKART_ACTIVE_CAPTION_COLOUR: m_active_caption_colour = colour; break; + case wxAUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR: m_active_caption_gradient_colour = colour; break; + case wxAUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR: m_active_caption_text_colour = colour; break; + case wxAUI_DOCKART_BORDER_COLOUR: m_border_pen.SetColour(colour); break; + case wxAUI_DOCKART_GRIPPER_COLOUR: + m_gripper_brush.SetColour(colour); + m_gripper_pen1.SetColour(wxAuiStepColour(colour, 40)); + m_gripper_pen2.SetColour(wxAuiStepColour(colour, 60)); + break; + default: wxFAIL_MSG(wxT("Invalid Metric Ordinal")); break; + } +} + +void wxAuiDefaultDockArt::SetFont(int id, const wxFont& font) +{ + if (id == wxAUI_DOCKART_CAPTION_FONT) + m_caption_font = font; +} + +wxFont wxAuiDefaultDockArt::GetFont(int id) +{ + if (id == wxAUI_DOCKART_CAPTION_FONT) + return m_caption_font; + return wxNullFont; +} + +void wxAuiDefaultDockArt::DrawSash(wxDC& dc, wxWindow *window, int orientation, const wxRect& rect) +{ +#if defined(__WXMAC__) + HIRect splitterRect = CGRectMake( rect.x , rect.y , rect.width , rect.height ); + CGContextRef cgContext ; +#if wxMAC_USE_CORE_GRAPHICS + cgContext = (CGContextRef) dc.GetGraphicsContext()->GetNativeContext() ; +#else + Rect bounds ; + GetPortBounds( (CGrafPtr) dc.m_macPort , &bounds ) ; + QDBeginCGContext( (CGrafPtr) dc.m_macPort , &cgContext ) ; + CGContextTranslateCTM( cgContext , 0 , bounds.bottom - bounds.top ) ; + CGContextScaleCTM( cgContext , 1 , -1 ) ; + + if ( window ) + { + wxPoint origin = window->GetClientAreaOrigin(); + int x, y; + x = origin.x; + y = origin.y; + window->MacWindowToRootWindow( &x , &y ); + CGContextTranslateCTM( cgContext, x, y); + } +#endif + + HIThemeSplitterDrawInfo drawInfo ; + drawInfo.version = 0 ; + drawInfo.state = kThemeStateActive ; + drawInfo.adornment = kHIThemeSplitterAdornmentNone ; + HIThemeDrawPaneSplitter( &splitterRect , &drawInfo , cgContext , kHIThemeOrientationNormal ) ; + +#if wxMAC_USE_CORE_GRAPHICS +#else + QDEndCGContext( (CGrafPtr) dc.m_macPort , &cgContext ) ; +#endif + +#elif defined(__WXGTK__) + // clear out the rectangle first + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush(m_sash_brush); + dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height); + + GdkRectangle gdk_rect; + if (orientation == wxVERTICAL ) + { + gdk_rect.x = rect.x; + gdk_rect.y = rect.y; + gdk_rect.width = m_sash_size; + gdk_rect.height = rect.height; + } + else + { + gdk_rect.x = rect.x; + gdk_rect.y = rect.y; + gdk_rect.width = rect.width; + gdk_rect.height = m_sash_size; + } + + if (!window) return; + if (!window->m_wxwindow) return; + if (!GTK_PIZZA(window->m_wxwindow)->bin_window) return; + + gtk_paint_handle + ( + window->m_wxwindow->style, + GTK_PIZZA(window->m_wxwindow)->bin_window, + // flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL, + GTK_STATE_NORMAL, + GTK_SHADOW_NONE, + NULL /* no clipping */, + window->m_wxwindow, + "paned", + rect.x, + rect.y, + rect.width, + rect.height, + (orientation == wxVERTICAL) ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL + ); + +#else + wxUnusedVar(window); + wxUnusedVar(orientation); + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush(m_sash_brush); + dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height); +#endif +} + + +void wxAuiDefaultDockArt::DrawBackground(wxDC& dc, wxWindow *WXUNUSED(window), int, const wxRect& rect) +{ + dc.SetPen(*wxTRANSPARENT_PEN); +#ifdef __WXMAC__ + // we have to clear first, otherwise we are drawing a light striped pattern + // over an already darker striped background + dc.SetBrush(*wxWHITE_BRUSH) ; + dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height); +#endif + dc.SetBrush(m_background_brush); + dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height); +} + +void wxAuiDefaultDockArt::DrawBorder(wxDC& dc, wxWindow *WXUNUSED(window), const wxRect& _rect, + wxAuiPaneInfo& pane) +{ + dc.SetPen(m_border_pen); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + + wxRect rect = _rect; + int i, border_width = GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE); + + if (pane.IsToolbar()) + { + for (i = 0; i < border_width; ++i) + { + dc.SetPen(*wxWHITE_PEN); + dc.DrawLine(rect.x, rect.y, rect.x+rect.width, rect.y); + dc.DrawLine(rect.x, rect.y, rect.x, rect.y+rect.height); + dc.SetPen(m_border_pen); + dc.DrawLine(rect.x, rect.y+rect.height-1, + rect.x+rect.width, rect.y+rect.height-1); + dc.DrawLine(rect.x+rect.width-1, rect.y, + rect.x+rect.width-1, rect.y+rect.height); + rect.Deflate(1); + } + } + else + { + for (i = 0; i < border_width; ++i) + { + dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height); + rect.Deflate(1); + } + } +} + + +void wxAuiDefaultDockArt::DrawCaptionBackground(wxDC& dc, const wxRect& rect, bool active) +{ + if (m_gradient_type == wxAUI_GRADIENT_NONE) + { + if (active) + dc.SetBrush(wxBrush(m_active_caption_colour)); + else + dc.SetBrush(wxBrush(m_inactive_caption_colour)); + + dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height); + } + else + { + if (active) + { + // on mac the gradients are expected to become darker from the top +#ifdef __WXMAC__ + DrawGradientRectangle(dc, rect, + m_active_caption_colour, + m_active_caption_gradient_colour, + m_gradient_type); +#else + // on other platforms, active gradients become lighter at the top + DrawGradientRectangle(dc, rect, + m_active_caption_gradient_colour, + m_active_caption_colour, + m_gradient_type); +#endif + } + else + { +#ifdef __WXMAC__ + // on mac the gradients are expected to become darker from the top + DrawGradientRectangle(dc, rect, + m_inactive_caption_gradient_colour, + m_inactive_caption_colour, + m_gradient_type); +#else + // on other platforms, inactive gradients become lighter at the bottom + DrawGradientRectangle(dc, rect, + m_inactive_caption_colour, + m_inactive_caption_gradient_colour, + m_gradient_type); +#endif + } + } +} + + +void wxAuiDefaultDockArt::DrawCaption(wxDC& dc, wxWindow *WXUNUSED(window), + const wxString& text, + const wxRect& rect, + wxAuiPaneInfo& pane) +{ + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetFont(m_caption_font); + + DrawCaptionBackground(dc, rect, + (pane.state & wxAuiPaneInfo::optionActive)?true:false); + + if (pane.state & wxAuiPaneInfo::optionActive) + dc.SetTextForeground(m_active_caption_text_colour); + else + dc.SetTextForeground(m_inactive_caption_text_colour); + + + wxCoord w,h; + dc.GetTextExtent(wxT("ABCDEFHXfgkj"), &w, &h); + + wxRect clip_rect = rect; + clip_rect.width -= 3; // text offset + clip_rect.width -= 2; // button padding + if (pane.HasCloseButton()) + clip_rect.width -= m_button_size; + if (pane.HasPinButton()) + clip_rect.width -= m_button_size; + if (pane.HasMaximizeButton()) + clip_rect.width -= m_button_size; + + wxString draw_text = wxAuiChopText(dc, text, clip_rect.width); + + dc.SetClippingRegion(clip_rect); + dc.DrawText(draw_text, rect.x+3, rect.y+(rect.height/2)-(h/2)-1); + dc.DestroyClippingRegion(); +} + +void wxAuiDefaultDockArt::DrawGripper(wxDC& dc, wxWindow *WXUNUSED(window), + const wxRect& rect, + wxAuiPaneInfo& pane) +{ + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush(m_gripper_brush); + + dc.DrawRectangle(rect.x, rect.y, rect.width,rect.height); + + if (!pane.HasGripperTop()) + { + int y = 5; + while (1) + { + dc.SetPen(m_gripper_pen1); + dc.DrawPoint(rect.x+3, rect.y+y); + dc.SetPen(m_gripper_pen2); + dc.DrawPoint(rect.x+3, rect.y+y+1); + dc.DrawPoint(rect.x+4, rect.y+y); + dc.SetPen(m_gripper_pen3); + dc.DrawPoint(rect.x+5, rect.y+y+1); + dc.DrawPoint(rect.x+5, rect.y+y+2); + dc.DrawPoint(rect.x+4, rect.y+y+2); + + y += 4; + if (y > rect.GetHeight()-5) + break; + } + } + else + { + int x = 5; + while (1) + { + dc.SetPen(m_gripper_pen1); + dc.DrawPoint(rect.x+x, rect.y+3); + dc.SetPen(m_gripper_pen2); + dc.DrawPoint(rect.x+x+1, rect.y+3); + dc.DrawPoint(rect.x+x, rect.y+4); + dc.SetPen(m_gripper_pen3); + dc.DrawPoint(rect.x+x+1, rect.y+5); + dc.DrawPoint(rect.x+x+2, rect.y+5); + dc.DrawPoint(rect.x+x+2, rect.y+4); + + x += 4; + if (x > rect.GetWidth()-5) + break; + } + } +} + +void wxAuiDefaultDockArt::DrawPaneButton(wxDC& dc, wxWindow *WXUNUSED(window), + int button, + int button_state, + const wxRect& _rect, + wxAuiPaneInfo& pane) +{ + wxBitmap bmp; + if (!(&pane)) + return; + switch (button) + { + default: + case wxAUI_BUTTON_CLOSE: + if (pane.state & wxAuiPaneInfo::optionActive) + bmp = m_active_close_bitmap; + else + bmp = m_inactive_close_bitmap; + break; + case wxAUI_BUTTON_PIN: + if (pane.state & wxAuiPaneInfo::optionActive) + bmp = m_active_pin_bitmap; + else + bmp = m_inactive_pin_bitmap; + break; + case wxAUI_BUTTON_MAXIMIZE_RESTORE: + if (pane.IsMaximized()) + { + if (pane.state & wxAuiPaneInfo::optionActive) + bmp = m_active_restore_bitmap; + else + bmp = m_inactive_restore_bitmap; + } + else + { + if (pane.state & wxAuiPaneInfo::optionActive) + bmp = m_active_maximize_bitmap; + else + bmp = m_inactive_maximize_bitmap; + } + break; + } + + + wxRect rect = _rect; + + int old_y = rect.y; + rect.y = rect.y + (rect.height/2) - (bmp.GetHeight()/2); + rect.height = old_y + rect.height - rect.y - 1; + + + if (button_state == wxAUI_BUTTON_STATE_PRESSED) + { + rect.x++; + rect.y++; + } + + if (button_state == wxAUI_BUTTON_STATE_HOVER || + button_state == wxAUI_BUTTON_STATE_PRESSED) + { + if (pane.state & wxAuiPaneInfo::optionActive) + { + dc.SetBrush(wxBrush(wxAuiStepColour(m_active_caption_colour, 120))); + dc.SetPen(wxPen(wxAuiStepColour(m_active_caption_colour, 70))); + } + else + { + dc.SetBrush(wxBrush(wxAuiStepColour(m_inactive_caption_colour, 120))); + dc.SetPen(wxPen(wxAuiStepColour(m_inactive_caption_colour, 70))); + } + + // draw the background behind the button + dc.DrawRectangle(rect.x, rect.y, 15, 15); + } + + + // draw the button itself + dc.DrawBitmap(bmp, rect.x, rect.y, true); +} + + +#endif // wxUSE_AUI diff --git a/Externals/wxWidgets/src/aui/floatpane.cpp b/Externals/wxWidgets/src/aui/floatpane.cpp new file mode 100644 index 0000000000..f8827e2a01 --- /dev/null +++ b/Externals/wxWidgets/src/aui/floatpane.cpp @@ -0,0 +1,323 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/aui/floatpane.cpp +// Purpose: wxaui: wx advanced user interface - docking window manager +// Author: Benjamin I. Williams +// Modified by: +// Created: 2005-05-17 +// RCS-ID: $Id: floatpane.cpp 54904 2008-08-01 16:07:46Z BIW $ +// Copyright: (C) Copyright 2005-2006, Kirix Corporation, All Rights Reserved +// Licence: wxWindows Library Licence, Version 3.1 +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_AUI + +#include "wx/aui/framemanager.h" +#include "wx/aui/floatpane.h" +#include "wx/aui/dockart.h" + +#ifndef WX_PRECOMP +#endif + +#ifdef __WXMSW__ +#include "wx/msw/private.h" +#endif + +IMPLEMENT_CLASS(wxAuiFloatingFrame, wxAuiFloatingFrameBaseClass) + +wxAuiFloatingFrame::wxAuiFloatingFrame(wxWindow* parent, + wxAuiManager* owner_mgr, + const wxAuiPaneInfo& pane, + wxWindowID id /*= wxID_ANY*/, + long style /*=wxRESIZE_BORDER | wxSYSTEM_MENU | wxCAPTION | + wxFRAME_NO_TASKBAR | wxFRAME_FLOAT_ON_PARENT | + wxCLIP_CHILDREN + */) + : wxAuiFloatingFrameBaseClass(parent, id, wxEmptyString, + pane.floating_pos, pane.floating_size, + style | + (pane.HasCloseButton()?wxCLOSE_BOX:0) | + (pane.HasMaximizeButton()?wxMAXIMIZE_BOX:0) | + (pane.IsFixed()?0:wxRESIZE_BORDER) + ) +{ + m_owner_mgr = owner_mgr; + m_moving = false; + m_mgr.SetManagedWindow(this); + m_solid_drag = true; + + // find out if the system supports solid window drag. + // on non-msw systems, this is assumed to be the case +#ifdef __WXMSW__ + BOOL b = TRUE; + SystemParametersInfo(38 /*SPI_GETDRAGFULLWINDOWS*/, 0, &b, 0); + m_solid_drag = b ? true : false; +#endif + + SetExtraStyle(wxWS_EX_PROCESS_IDLE); +} + +wxAuiFloatingFrame::~wxAuiFloatingFrame() +{ + // if we do not do this, then we can crash... + if(m_owner_mgr && m_owner_mgr->m_action_window == this) + { + m_owner_mgr->m_action_window = NULL; + } + m_mgr.UnInit(); +} + +void wxAuiFloatingFrame::SetPaneWindow(const wxAuiPaneInfo& pane) +{ + m_pane_window = pane.window; + m_pane_window->Reparent(this); + + wxAuiPaneInfo contained_pane = pane; + contained_pane.Dock().Center().Show(). + CaptionVisible(false). + PaneBorder(false). + Layer(0).Row(0).Position(0); + + // Carry over the minimum size + wxSize pane_min_size = pane.window->GetMinSize(); + + // if the frame window's max size is greater than the min size + // then set the max size to the min size as well + wxSize cur_max_size = GetMaxSize(); + if (cur_max_size.IsFullySpecified() && + (cur_max_size.x < pane.min_size.x || + cur_max_size.y < pane.min_size.y) + ) + { + SetMaxSize(pane_min_size); + } + + SetMinSize(pane.window->GetMinSize()); + + m_mgr.AddPane(m_pane_window, contained_pane); + m_mgr.Update(); + + if (pane.min_size.IsFullySpecified()) + { + // because SetSizeHints() calls Fit() too (which sets the window + // size to its minimum allowed), we keep the size before calling + // SetSizeHints() and reset it afterwards... + wxSize tmp = GetSize(); + GetSizer()->SetSizeHints(this); + SetSize(tmp); + } + + SetTitle(pane.caption); + + if (pane.floating_size != wxDefaultSize) + { + SetSize(pane.floating_size); + } + else + { + wxSize size = pane.best_size; + if (size == wxDefaultSize) + size = pane.min_size; + if (size == wxDefaultSize) + size = m_pane_window->GetSize(); + if (pane.HasGripper()) + { + if (pane.HasGripperTop()) + size.y += m_owner_mgr->m_art->GetMetric(wxAUI_DOCKART_GRIPPER_SIZE); + else + size.x += m_owner_mgr->m_art->GetMetric(wxAUI_DOCKART_GRIPPER_SIZE); + } + + SetClientSize(size); + } + + if (pane.IsFixed()) + { + SetWindowStyleFlag(GetWindowStyleFlag() & ~wxRESIZE_BORDER); + } +} + +wxAuiManager* wxAuiFloatingFrame::GetOwnerManager() const +{ + return m_owner_mgr; +} + + +void wxAuiFloatingFrame::OnSize(wxSizeEvent& event) +{ + m_owner_mgr->OnFloatingPaneResized(m_pane_window, event.GetSize()); +} + +void wxAuiFloatingFrame::OnClose(wxCloseEvent& evt) +{ + m_owner_mgr->OnFloatingPaneClosed(m_pane_window, evt); + if (!evt.GetVeto()) { + m_mgr.DetachPane(m_pane_window); + Destroy(); + } +} + +void wxAuiFloatingFrame::OnMoveEvent(wxMoveEvent& event) +{ + if (!m_solid_drag) + { + // systems without solid window dragging need to be + // handled slightly differently, due to the lack of + // the constant stream of EVT_MOVING events + if (!isMouseDown()) + return; + OnMoveStart(); + OnMoving(event.GetRect(), wxNORTH); + m_moving = true; + return; + } + + + wxRect win_rect = GetRect(); + + if (win_rect == m_last_rect) + return; + + // skip the first move event + if (m_last_rect.IsEmpty()) + { + m_last_rect = win_rect; + return; + } + + // skip if moving too fast to avoid massive redraws and + // jumping hint windows + if ((abs(win_rect.x - m_last_rect.x) > 3) || + (abs(win_rect.y - m_last_rect.y) > 3)) + { + m_last3_rect = m_last2_rect; + m_last2_rect = m_last_rect; + m_last_rect = win_rect; + return; + } + + // prevent frame redocking during resize + if (m_last_rect.GetSize() != win_rect.GetSize()) + { + m_last3_rect = m_last2_rect; + m_last2_rect = m_last_rect; + m_last_rect = win_rect; + return; + } + + wxDirection dir = wxALL; + + int horiz_dist = abs(win_rect.x - m_last3_rect.x); + int vert_dist = abs(win_rect.y - m_last3_rect.y); + + if (vert_dist >= horiz_dist) + { + if (win_rect.y < m_last3_rect.y) + dir = wxNORTH; + else + dir = wxSOUTH; + } + else + { + if (win_rect.x < m_last3_rect.x) + dir = wxWEST; + else + dir = wxEAST; + } + + m_last3_rect = m_last2_rect; + m_last2_rect = m_last_rect; + m_last_rect = win_rect; + + if (!isMouseDown()) + return; + + if (!m_moving) + { + OnMoveStart(); + m_moving = true; + } + + if (m_last3_rect.IsEmpty()) + return; + + OnMoving(event.GetRect(), dir); +} + +void wxAuiFloatingFrame::OnIdle(wxIdleEvent& event) +{ + if (m_moving) + { + if (!isMouseDown()) + { + m_moving = false; + OnMoveFinished(); + } + else + { + event.RequestMore(); + } + } +} + +void wxAuiFloatingFrame::OnMoveStart() +{ + // notify the owner manager that the pane has started to move + m_owner_mgr->OnFloatingPaneMoveStart(m_pane_window); +} + +void wxAuiFloatingFrame::OnMoving(const wxRect& WXUNUSED(window_rect), wxDirection dir) +{ + // notify the owner manager that the pane is moving + m_owner_mgr->OnFloatingPaneMoving(m_pane_window, dir); + m_lastDirection = dir; +} + +void wxAuiFloatingFrame::OnMoveFinished() +{ + // notify the owner manager that the pane has finished moving + m_owner_mgr->OnFloatingPaneMoved(m_pane_window, m_lastDirection); +} + +void wxAuiFloatingFrame::OnActivate(wxActivateEvent& event) +{ + if (event.GetActive()) + { + m_owner_mgr->OnFloatingPaneActivated(m_pane_window); + } +} + +// utility function which determines the state of the mouse button +// (independant of having a wxMouseEvent handy) - utimately a better +// mechanism for this should be found (possibly by adding the +// functionality to wxWidgets itself) +bool wxAuiFloatingFrame::isMouseDown() +{ + return wxGetMouseState().LeftDown(); +} + + +BEGIN_EVENT_TABLE(wxAuiFloatingFrame, wxAuiFloatingFrameBaseClass) + EVT_SIZE(wxAuiFloatingFrame::OnSize) + EVT_MOVE(wxAuiFloatingFrame::OnMoveEvent) + EVT_MOVING(wxAuiFloatingFrame::OnMoveEvent) + EVT_CLOSE(wxAuiFloatingFrame::OnClose) + EVT_IDLE(wxAuiFloatingFrame::OnIdle) + EVT_ACTIVATE(wxAuiFloatingFrame::OnActivate) +END_EVENT_TABLE() + + +#endif // wxUSE_AUI diff --git a/Externals/wxWidgets/src/aui/framemanager.cpp b/Externals/wxWidgets/src/aui/framemanager.cpp new file mode 100644 index 0000000000..c85215f157 --- /dev/null +++ b/Externals/wxWidgets/src/aui/framemanager.cpp @@ -0,0 +1,4593 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/aui/framemanager.cpp +// Purpose: wxaui: wx advanced user interface - docking window manager +// Author: Benjamin I. Williams +// Modified by: +// Created: 2005-05-17 +// RCS-ID: $Id: framemanager.cpp 59107 2009-02-23 18:28:05Z BP $ +// Copyright: (C) Copyright 2005-2006, Kirix Corporation, All Rights Reserved +// Licence: wxWindows Library Licence, Version 3.1 +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_AUI + +#include "wx/aui/framemanager.h" +#include "wx/aui/dockart.h" +#include "wx/aui/floatpane.h" +#include "wx/aui/tabmdi.h" +#include "wx/aui/auibar.h" + +#ifndef WX_PRECOMP + #include "wx/panel.h" + #include "wx/settings.h" + #include "wx/app.h" + #include "wx/dcclient.h" + #include "wx/dcscreen.h" + #include "wx/toolbar.h" + #include "wx/mdi.h" + #include "wx/image.h" +#endif + +WX_CHECK_BUILD_OPTIONS("wxAUI") + +#include "wx/arrimpl.cpp" +WX_DECLARE_OBJARRAY(wxRect, wxAuiRectArray); +WX_DEFINE_OBJARRAY(wxAuiRectArray) +WX_DEFINE_OBJARRAY(wxAuiDockUIPartArray) +WX_DEFINE_OBJARRAY(wxAuiDockInfoArray) +WX_DEFINE_OBJARRAY(wxAuiPaneButtonArray) +WX_DEFINE_OBJARRAY(wxAuiPaneInfoArray) + +wxAuiPaneInfo wxAuiNullPaneInfo; +wxAuiDockInfo wxAuiNullDockInfo; +DEFINE_EVENT_TYPE(wxEVT_AUI_PANE_BUTTON) +DEFINE_EVENT_TYPE(wxEVT_AUI_PANE_CLOSE) +DEFINE_EVENT_TYPE(wxEVT_AUI_PANE_MAXIMIZE) +DEFINE_EVENT_TYPE(wxEVT_AUI_PANE_RESTORE) +DEFINE_EVENT_TYPE(wxEVT_AUI_RENDER) +DEFINE_EVENT_TYPE(wxEVT_AUI_FIND_MANAGER) + +#ifdef __WXMAC__ + // a few defines to avoid nameclashes + #define __MAC_OS_X_MEMORY_MANAGER_CLEAN__ 1 + #define __AIFF__ + #include "wx/mac/private.h" +#endif + +#ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" + #include "wx/msw/private.h" +#endif + +IMPLEMENT_DYNAMIC_CLASS(wxAuiManagerEvent, wxEvent) +IMPLEMENT_CLASS(wxAuiManager, wxEvtHandler) + + +const int auiToolBarLayer = 10; + +#ifndef __WXGTK20__ + +class wxPseudoTransparentFrame : public wxFrame +{ +public: + wxPseudoTransparentFrame(wxWindow* parent = NULL, + wxWindowID id = wxID_ANY, + const wxString& title = wxEmptyString, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxDEFAULT_FRAME_STYLE, + const wxString &name = wxT("frame")) + : wxFrame(parent, id, title, pos, size, style | wxFRAME_SHAPED, name) + { + SetBackgroundStyle(wxBG_STYLE_CUSTOM); + m_Amount=0; + m_MaxWidth=0; + m_MaxHeight=0; + m_lastWidth=0; + m_lastHeight=0; +#ifdef __WXGTK__ + m_CanSetShape = false; // have to wait for window create event on GTK +#else + m_CanSetShape = true; +#endif + m_Region = wxRegion(0, 0, 0, 0); + SetTransparent(0); + } + + virtual bool SetTransparent(wxByte alpha) + { + if (m_CanSetShape) + { + int w=100; // some defaults + int h=100; + GetClientSize(&w, &h); + + m_MaxWidth = w; + m_MaxHeight = h; + m_Amount = alpha; + m_Region.Clear(); +// m_Region.Union(0, 0, 1, m_MaxWidth); + if (m_Amount) + { + for (int y=0; ywindow, region.GetRegion(), 0, 0); +} + + +class wxPseudoTransparentFrame: public wxFrame +{ +public: + wxPseudoTransparentFrame(wxWindow* parent = NULL, + wxWindowID id = wxID_ANY, + const wxString& title = wxEmptyString, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxDEFAULT_FRAME_STYLE, + const wxString &name = wxT("frame")) + { + if (!CreateBase( parent, id, pos, size, style, wxDefaultValidator, name )) + return; + + m_title = title; + + m_widget = gtk_window_new( GTK_WINDOW_POPUP ); + + g_signal_connect( m_widget, "realize", + G_CALLBACK (gtk_pseudo_window_realized_callback), this ); + + GdkColor col; + col.red = 128 * 256; + col.green = 192 * 256; + col.blue = 255 * 256; + gtk_widget_modify_bg( m_widget, GTK_STATE_NORMAL, &col ); + } + + bool SetTransparent(wxByte alpha) + { + return true; + } + +private: + DECLARE_DYNAMIC_CLASS(wxPseudoTransparentFrame) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxPseudoTransparentFrame, wxFrame) + +#endif + // __WXGTK20__ + + +// -- static utility functions -- + +static wxBitmap wxPaneCreateStippleBitmap() +{ + unsigned char data[] = { 0,0,0,192,192,192, 192,192,192,0,0,0 }; + wxImage img(2,2,data,true); + return wxBitmap(img); +} + +static void DrawResizeHint(wxDC& dc, const wxRect& rect) +{ + wxBitmap stipple = wxPaneCreateStippleBitmap(); + wxBrush brush(stipple); + dc.SetBrush(brush); + +#ifdef __WXMSW__ + PatBlt(GetHdcOf(dc), rect.GetX(), rect.GetY(), rect.GetWidth(), rect.GetHeight(), PATINVERT); +#else + dc.SetPen(*wxTRANSPARENT_PEN); + + dc.SetLogicalFunction(wxXOR); + dc.DrawRectangle(rect); +#endif +} + + + +// CopyDocksAndPanes() - this utility function creates copies of +// the dock and pane info. wxAuiDockInfo's usually contain pointers +// to wxAuiPaneInfo classes, thus this function is necessary to reliably +// reconstruct that relationship in the new dock info and pane info arrays + +static void CopyDocksAndPanes(wxAuiDockInfoArray& dest_docks, + wxAuiPaneInfoArray& dest_panes, + const wxAuiDockInfoArray& src_docks, + const wxAuiPaneInfoArray& src_panes) +{ + dest_docks = src_docks; + dest_panes = src_panes; + int i, j, k, dock_count, pc1, pc2; + for (i = 0, dock_count = dest_docks.GetCount(); i < dock_count; ++i) + { + wxAuiDockInfo& dock = dest_docks.Item(i); + for (j = 0, pc1 = dock.panes.GetCount(); j < pc1; ++j) + for (k = 0, pc2 = src_panes.GetCount(); k < pc2; ++k) + if (dock.panes.Item(j) == &src_panes.Item(k)) + dock.panes.Item(j) = &dest_panes.Item(k); + } +} + +// GetMaxLayer() is an internal function which returns +// the highest layer inside the specified dock +static int GetMaxLayer(const wxAuiDockInfoArray& docks, + int dock_direction) +{ + int i, dock_count, max_layer = 0; + for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i) + { + wxAuiDockInfo& dock = docks.Item(i); + if (dock.dock_direction == dock_direction && + dock.dock_layer > max_layer && !dock.fixed) + max_layer = dock.dock_layer; + } + return max_layer; +} + + +// GetMaxRow() is an internal function which returns +// the highest layer inside the specified dock +static int GetMaxRow(const wxAuiPaneInfoArray& panes, int direction, int layer) +{ + int i, pane_count, max_row = 0; + for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i) + { + wxAuiPaneInfo& pane = panes.Item(i); + if (pane.dock_direction == direction && + pane.dock_layer == layer && + pane.dock_row > max_row) + max_row = pane.dock_row; + } + return max_row; +} + + + +// DoInsertDockLayer() is an internal function that inserts a new dock +// layer by incrementing all existing dock layer values by one +static void DoInsertDockLayer(wxAuiPaneInfoArray& panes, + int dock_direction, + int dock_layer) +{ + int i, pane_count; + for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i) + { + wxAuiPaneInfo& pane = panes.Item(i); + if (!pane.IsFloating() && + pane.dock_direction == dock_direction && + pane.dock_layer >= dock_layer) + pane.dock_layer++; + } +} + +// DoInsertDockLayer() is an internal function that inserts a new dock +// row by incrementing all existing dock row values by one +static void DoInsertDockRow(wxAuiPaneInfoArray& panes, + int dock_direction, + int dock_layer, + int dock_row) +{ + int i, pane_count; + for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i) + { + wxAuiPaneInfo& pane = panes.Item(i); + if (!pane.IsFloating() && + pane.dock_direction == dock_direction && + pane.dock_layer == dock_layer && + pane.dock_row >= dock_row) + pane.dock_row++; + } +} + +// DoInsertDockLayer() is an internal function that inserts a space for +// another dock pane by incrementing all existing dock row values by one +static void DoInsertPane(wxAuiPaneInfoArray& panes, + int dock_direction, + int dock_layer, + int dock_row, + int dock_pos) +{ + int i, pane_count; + for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i) + { + wxAuiPaneInfo& pane = panes.Item(i); + if (!pane.IsFloating() && + pane.dock_direction == dock_direction && + pane.dock_layer == dock_layer && + pane.dock_row == dock_row && + pane.dock_pos >= dock_pos) + pane.dock_pos++; + } +} + +// FindDocks() is an internal function that returns a list of docks which meet +// the specified conditions in the parameters and returns a sorted array +// (sorted by layer and then row) +static void FindDocks(wxAuiDockInfoArray& docks, + int dock_direction, + int dock_layer, + int dock_row, + wxAuiDockInfoPtrArray& arr) +{ + int begin_layer = dock_layer; + int end_layer = dock_layer; + int begin_row = dock_row; + int end_row = dock_row; + int dock_count = docks.GetCount(); + int layer, row, i, max_row = 0, max_layer = 0; + + // discover the maximum dock layer and the max row + for (i = 0; i < dock_count; ++i) + { + max_row = wxMax(max_row, docks.Item(i).dock_row); + max_layer = wxMax(max_layer, docks.Item(i).dock_layer); + } + + // if no dock layer was specified, search all dock layers + if (dock_layer == -1) + { + begin_layer = 0; + end_layer = max_layer; + } + + // if no dock row was specified, search all dock row + if (dock_row == -1) + { + begin_row = 0; + end_row = max_row; + } + + arr.Clear(); + + for (layer = begin_layer; layer <= end_layer; ++layer) + for (row = begin_row; row <= end_row; ++row) + for (i = 0; i < dock_count; ++i) + { + wxAuiDockInfo& d = docks.Item(i); + if (dock_direction == -1 || dock_direction == d.dock_direction) + { + if (d.dock_layer == layer && d.dock_row == row) + arr.Add(&d); + } + } +} + +// FindPaneInDock() looks up a specified window pointer inside a dock. +// If found, the corresponding wxAuiPaneInfo pointer is returned, otherwise NULL. +static wxAuiPaneInfo* FindPaneInDock(const wxAuiDockInfo& dock, wxWindow* window) +{ + int i, count = dock.panes.GetCount(); + for (i = 0; i < count; ++i) + { + wxAuiPaneInfo* p = dock.panes.Item(i); + if (p->window == window) + return p; + } + return NULL; +} + +// RemovePaneFromDocks() removes a pane window from all docks +// with a possible exception specified by parameter "ex_cept" +static void RemovePaneFromDocks(wxAuiDockInfoArray& docks, + wxAuiPaneInfo& pane, + wxAuiDockInfo* ex_cept = NULL ) +{ + int i, dock_count; + for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i) + { + wxAuiDockInfo& d = docks.Item(i); + if (&d == ex_cept) + continue; + wxAuiPaneInfo* pi = FindPaneInDock(d, pane.window); + if (pi) + d.panes.Remove(pi); + } +} + +/* +// This function works fine, and may be used in the future + +// RenumberDockRows() takes a dock and assigns sequential numbers +// to existing rows. Basically it takes out the gaps; so if a +// dock has rows with numbers 0,2,5, they will become 0,1,2 +static void RenumberDockRows(wxAuiDockInfoPtrArray& docks) +{ + int i, dock_count; + for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i) + { + wxAuiDockInfo& dock = *docks.Item(i); + dock.dock_row = i; + + int j, pane_count; + for (j = 0, pane_count = dock.panes.GetCount(); j < pane_count; ++j) + dock.panes.Item(j)->dock_row = i; + } +} +*/ + + +// SetActivePane() sets the active pane, as well as cycles through +// every other pane and makes sure that all others' active flags +// are turned off +static void SetActivePane(wxAuiPaneInfoArray& panes, wxWindow* active_pane) +{ + int i, pane_count; + for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i) + { + wxAuiPaneInfo& pane = panes.Item(i); + pane.state &= ~wxAuiPaneInfo::optionActive; + if (pane.window == active_pane) + pane.state |= wxAuiPaneInfo::optionActive; + } +} + + +// this function is used to sort panes by dock position +static int PaneSortFunc(wxAuiPaneInfo** p1, wxAuiPaneInfo** p2) +{ + return ((*p1)->dock_pos < (*p2)->dock_pos) ? -1 : 1; +} + + +// -- wxAuiManager class implementation -- + + +BEGIN_EVENT_TABLE(wxAuiManager, wxEvtHandler) + EVT_AUI_PANE_BUTTON(wxAuiManager::OnPaneButton) + EVT_AUI_RENDER(wxAuiManager::OnRender) + EVT_PAINT(wxAuiManager::OnPaint) + EVT_ERASE_BACKGROUND(wxAuiManager::OnEraseBackground) + EVT_SIZE(wxAuiManager::OnSize) + EVT_SET_CURSOR(wxAuiManager::OnSetCursor) + EVT_LEFT_DOWN(wxAuiManager::OnLeftDown) + EVT_LEFT_UP(wxAuiManager::OnLeftUp) + EVT_MOTION(wxAuiManager::OnMotion) + EVT_LEAVE_WINDOW(wxAuiManager::OnLeaveWindow) + EVT_CHILD_FOCUS(wxAuiManager::OnChildFocus) + EVT_AUI_FIND_MANAGER(wxAuiManager::OnFindManager) + EVT_TIMER(101, wxAuiManager::OnHintFadeTimer) +END_EVENT_TABLE() + + +wxAuiManager::wxAuiManager(wxWindow* managed_wnd, unsigned int flags) +{ + m_action = actionNone; + m_action_window = NULL; + m_last_mouse_move = wxPoint(); + m_hover_button = NULL; + m_art = new wxAuiDefaultDockArt; + m_hint_wnd = NULL; + m_flags = flags; + m_skipping = false; + m_has_maximized = false; + m_frame = NULL; + m_dock_constraint_x = 0.3; + m_dock_constraint_y = 0.3; + m_reserved = NULL; + + if (managed_wnd) + { + SetManagedWindow(managed_wnd); + } +} + +wxAuiManager::~wxAuiManager() +{ + // NOTE: It's possible that the windows have already been destroyed by the + // time this dtor is called, so this loop can result in memory access via + // invalid pointers, resulting in a crash. So it will be disabled while + // waiting for a better solution. +#if 0 + for(size_t i = 0; i < m_panes.size(); i++ ) + { + wxAuiPaneInfo& pinfo = m_panes[i]; + if( pinfo.window && !pinfo.window->GetParent() ) + delete pinfo.window; + } +#endif + + delete m_art; +} + +// creates a floating frame for the windows +wxAuiFloatingFrame* wxAuiManager::CreateFloatingFrame(wxWindow* parent, + const wxAuiPaneInfo& pane_info) +{ + return new wxAuiFloatingFrame(parent, this, pane_info); +} + +// GetPane() looks up a wxAuiPaneInfo structure based +// on the supplied window pointer. Upon failure, GetPane() +// returns an empty wxAuiPaneInfo, a condition which can be checked +// by calling wxAuiPaneInfo::IsOk(). +// +// The pane info's structure may then be modified. Once a pane's +// info is modified, wxAuiManager::Update() must be called to +// realize the changes in the UI. + +wxAuiPaneInfo& wxAuiManager::GetPane(wxWindow* window) +{ + int i, pane_count; + for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i) + { + wxAuiPaneInfo& p = m_panes.Item(i); + if (p.window == window) + return p; + } + return wxAuiNullPaneInfo; +} + +// this version of GetPane() looks up a pane based on a +// 'pane name', see above comment for more info +wxAuiPaneInfo& wxAuiManager::GetPane(const wxString& name) +{ + int i, pane_count; + for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i) + { + wxAuiPaneInfo& p = m_panes.Item(i); + if (p.name == name) + return p; + } + return wxAuiNullPaneInfo; +} + +// GetAllPanes() returns a reference to all the pane info structures +wxAuiPaneInfoArray& wxAuiManager::GetAllPanes() +{ + return m_panes; +} + +// HitTest() is an internal function which determines +// which UI item the specified coordinates are over +// (x,y) specify a position in client coordinates +wxAuiDockUIPart* wxAuiManager::HitTest(int x, int y) +{ + wxAuiDockUIPart* result = NULL; + + int i, part_count; + for (i = 0, part_count = m_uiparts.GetCount(); i < part_count; ++i) + { + wxAuiDockUIPart* item = &m_uiparts.Item(i); + + // we are not interested in typeDock, because this space + // isn't used to draw anything, just for measurements; + // besides, the entire dock area is covered with other + // rectangles, which we are interested in. + if (item->type == wxAuiDockUIPart::typeDock) + continue; + + // if we already have a hit on a more specific item, we are not + // interested in a pane hit. If, however, we don't already have + // a hit, returning a pane hit is necessary for some operations + if ((item->type == wxAuiDockUIPart::typePane || + item->type == wxAuiDockUIPart::typePaneBorder) && result) + continue; + + // if the point is inside the rectangle, we have a hit + if (item->rect.Contains(x,y)) + result = item; + } + + return result; +} + + +// SetFlags() and GetFlags() allow the owner to set various +// options which are global to wxAuiManager +void wxAuiManager::SetFlags(unsigned int flags) +{ + // find out if we have to call UpdateHintWindowConfig() + bool update_hint_wnd = false; + unsigned int hint_mask = wxAUI_MGR_TRANSPARENT_HINT | + wxAUI_MGR_VENETIAN_BLINDS_HINT | + wxAUI_MGR_RECTANGLE_HINT; + if ((flags & hint_mask) != (m_flags & hint_mask)) + update_hint_wnd = true; + + + // set the new flags + m_flags = flags; + + if (update_hint_wnd) + { + UpdateHintWindowConfig(); + } +} + +unsigned int wxAuiManager::GetFlags() const +{ + return m_flags; +} + +// Convenience function +bool wxAuiManager_HasLiveResize(wxAuiManager& manager) +{ + // With Core Graphics on Mac, it's not possible to show sash feedback, + // so we'll always use live update instead. +#if defined(__WXMAC__) && wxMAC_USE_CORE_GRAPHICS + return true; +#else + return (manager.GetFlags() & wxAUI_MGR_LIVE_RESIZE) == wxAUI_MGR_LIVE_RESIZE; +#endif +} + +// don't use these anymore as they are deprecated +// use Set/GetManagedFrame() instead +void wxAuiManager::SetFrame(wxFrame* frame) +{ + SetManagedWindow((wxWindow*)frame); +} + +wxFrame* wxAuiManager::GetFrame() const +{ + return (wxFrame*)m_frame; +} + + +// this function will return the aui manager for a given +// window. The |window| parameter should be any child window +// or grand-child window (and so on) of the frame/window +// managed by wxAuiManager. The |window| parameter does not +// need to be managed by the manager itself. +wxAuiManager* wxAuiManager::GetManager(wxWindow* window) +{ + wxAuiManagerEvent evt(wxEVT_AUI_FIND_MANAGER); + evt.SetManager(NULL); + evt.ResumePropagation(wxEVENT_PROPAGATE_MAX); + if (!window->ProcessEvent(evt)) + return NULL; + + return evt.GetManager(); +} + + +void wxAuiManager::UpdateHintWindowConfig() +{ + // find out if the the system can do transparent frames + bool can_do_transparent = false; + + wxWindow* w = m_frame; + while (w) + { + if (w->IsKindOf(CLASSINFO(wxFrame))) + { + wxFrame* f = wx_static_cast(wxFrame*, w); + can_do_transparent = f->CanSetTransparent(); + break; + } + + w = w->GetParent(); + } + + // if there is an existing hint window, delete it + if (m_hint_wnd) + { + m_hint_wnd->Destroy(); + m_hint_wnd = NULL; + } + + m_hint_fademax = 50; + m_hint_wnd = NULL; + + if ((m_flags & wxAUI_MGR_TRANSPARENT_HINT) && can_do_transparent) + { + // Make a window to use for a transparent hint + #if defined(__WXMSW__) || defined(__WXGTK__) + m_hint_wnd = new wxFrame(m_frame, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxSize(1,1), + wxFRAME_TOOL_WINDOW | + wxFRAME_FLOAT_ON_PARENT | + wxFRAME_NO_TASKBAR | + wxNO_BORDER); + + m_hint_wnd->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVECAPTION)); + #elif defined(__WXMAC__) + // Using a miniframe with float and tool styles keeps the parent + // frame activated and highlighted as such... + m_hint_wnd = new wxMiniFrame(m_frame, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxSize(1,1), + wxFRAME_FLOAT_ON_PARENT + | wxFRAME_TOOL_WINDOW ); + + // Can't set the bg colour of a Frame in wxMac + wxPanel* p = new wxPanel(m_hint_wnd); + + // The default wxSYS_COLOUR_ACTIVECAPTION colour is a light silver + // color that is really hard to see, especially transparent. + // Until a better system color is decided upon we'll just use + // blue. + p->SetBackgroundColour(*wxBLUE); + #endif + + } + else + { + if ((m_flags & wxAUI_MGR_TRANSPARENT_HINT) != 0 || + (m_flags & wxAUI_MGR_VENETIAN_BLINDS_HINT) != 0) + { + // system can't support transparent fade, or the venetian + // blinds effect was explicitly requested + m_hint_wnd = new wxPseudoTransparentFrame(m_frame, + wxID_ANY, + wxEmptyString, + wxDefaultPosition, + wxSize(1,1), + wxFRAME_TOOL_WINDOW | + wxFRAME_FLOAT_ON_PARENT | + wxFRAME_NO_TASKBAR | + wxNO_BORDER); + m_hint_fademax = 128; + } + } +} + + +// SetManagedWindow() is usually called once when the frame +// manager class is being initialized. "frame" specifies +// the frame which should be managed by the frame mananger +void wxAuiManager::SetManagedWindow(wxWindow* wnd) +{ + wxASSERT_MSG(wnd, wxT("specified window must be non-NULL")); + + m_frame = wnd; + m_frame->PushEventHandler(this); + +#if wxUSE_MDI + // if the owner is going to manage an MDI parent frame, + // we need to add the MDI client window as the default + // center pane + + if (m_frame->IsKindOf(CLASSINFO(wxMDIParentFrame))) + { + wxMDIParentFrame* mdi_frame = (wxMDIParentFrame*)m_frame; + wxWindow* client_window = mdi_frame->GetClientWindow(); + + wxASSERT_MSG(client_window, wxT("Client window is NULL!")); + + AddPane(client_window, + wxAuiPaneInfo().Name(wxT("mdiclient")). + CenterPane().PaneBorder(false)); + } + else if (m_frame->IsKindOf(CLASSINFO(wxAuiMDIParentFrame))) + { + wxAuiMDIParentFrame* mdi_frame = (wxAuiMDIParentFrame*)m_frame; + wxAuiMDIClientWindow* client_window = mdi_frame->GetClientWindow(); + wxASSERT_MSG(client_window, wxT("Client window is NULL!")); + + AddPane(client_window, + wxAuiPaneInfo().Name(wxT("mdiclient")). + CenterPane().PaneBorder(false)); + } + +#endif + + UpdateHintWindowConfig(); +} + + +// UnInit() must be called, usually in the destructor +// of the frame class. If it is not called, usually this +// will result in a crash upon program exit +void wxAuiManager::UnInit() +{ + if (m_frame) + { + m_frame->RemoveEventHandler(this); + } +} + +// GetManagedWindow() returns the window pointer being managed +wxWindow* wxAuiManager::GetManagedWindow() const +{ + return m_frame; +} + +wxAuiDockArt* wxAuiManager::GetArtProvider() const +{ + return m_art; +} + +void wxAuiManager::ProcessMgrEvent(wxAuiManagerEvent& event) +{ + // first, give the owner frame a chance to override + if (m_frame) + { + if (m_frame->ProcessEvent(event)) + return; + } + + ProcessEvent(event); +} + +// SetArtProvider() instructs wxAuiManager to use the +// specified art provider for all drawing calls. This allows +// plugable look-and-feel features. The pointer that is +// passed to this method subsequently belongs to wxAuiManager, +// and is deleted in the frame manager destructor +void wxAuiManager::SetArtProvider(wxAuiDockArt* art_provider) +{ + // delete the last art provider, if any + delete m_art; + + // assign the new art provider + m_art = art_provider; +} + + +bool wxAuiManager::AddPane(wxWindow* window, const wxAuiPaneInfo& pane_info) +{ + wxASSERT_MSG(window, wxT("NULL window ptrs are not allowed")); + + // check if the pane has a valid window + if (!window) + return false; + + // check if the window is already managed by us + if (GetPane(pane_info.window).IsOk()) + return false; + + // check if the pane name already exists, this could reveal a + // bug in the library user's application + bool already_exists = false; + if (!pane_info.name.empty() && GetPane(pane_info.name).IsOk()) + { + wxFAIL_MSG(wxT("A pane with that name already exists in the manager!")); + already_exists = true; + } + + // if the new pane is docked then we should undo maximize + if (pane_info.IsDocked()) + RestoreMaximizedPane(); + + m_panes.Add(pane_info); + + wxAuiPaneInfo& pinfo = m_panes.Last(); + + // set the pane window + pinfo.window = window; + + + // if the pane's name identifier is blank, create a random string + if (pinfo.name.empty() || already_exists) + { + pinfo.name.Printf(wxT("%08lx%08x%08x%08lx"), + ((unsigned long)pinfo.window) & 0xffffffff, + (unsigned int)time(NULL), +#ifdef __WXWINCE__ + (unsigned int)GetTickCount(), +#else + (unsigned int)clock(), +#endif + (unsigned long)m_panes.GetCount()); + } + + // set initial proportion (if not already set) + if (pinfo.dock_proportion == 0) + pinfo.dock_proportion = 100000; + + if (pinfo.HasMaximizeButton()) + { + wxAuiPaneButton button; + button.button_id = wxAUI_BUTTON_MAXIMIZE_RESTORE; + pinfo.buttons.Add(button); + } + + if (pinfo.HasPinButton()) + { + wxAuiPaneButton button; + button.button_id = wxAUI_BUTTON_PIN; + pinfo.buttons.Add(button); + } + + if (pinfo.HasCloseButton()) + { + wxAuiPaneButton button; + button.button_id = wxAUI_BUTTON_CLOSE; + pinfo.buttons.Add(button); + } + + if (pinfo.HasGripper()) + { + if (pinfo.window->IsKindOf(CLASSINFO(wxAuiToolBar))) + { + // prevent duplicate gripper -- both wxAuiManager and wxAuiToolBar + // have a gripper control. The toolbar's built-in gripper + // meshes better with the look and feel of the control than ours, + // so turn wxAuiManager's gripper off, and the toolbar's on. + + wxAuiToolBar* tb = wx_static_cast(wxAuiToolBar*, pinfo.window); + pinfo.SetFlag(wxAuiPaneInfo::optionGripper, false); + tb->SetGripperVisible(true); + } + } + + + if (pinfo.best_size == wxDefaultSize && + pinfo.window) + { + pinfo.best_size = pinfo.window->GetClientSize(); + + if (pinfo.window->IsKindOf(CLASSINFO(wxToolBar))) + { + // GetClientSize() doesn't get the best size for + // a toolbar under some newer versions of wxWidgets, + // so use GetBestSize() + pinfo.best_size = pinfo.window->GetBestSize(); + + // for some reason, wxToolBar::GetBestSize() is returning + // a size that is a pixel shy of the correct amount. + // I believe this to be the correct action, until + // wxToolBar::GetBestSize() is fixed. Is this assumption + // correct? + // commented out by JACS 2007-9-08 after having added a pixel in wxMSW's wxToolBar::DoGetBestSize() + // pinfo.best_size.y++; + } + + if (pinfo.min_size != wxDefaultSize) + { + if (pinfo.best_size.x < pinfo.min_size.x) + pinfo.best_size.x = pinfo.min_size.x; + if (pinfo.best_size.y < pinfo.min_size.y) + pinfo.best_size.y = pinfo.min_size.y; + } + } + + + + return true; +} + +bool wxAuiManager::AddPane(wxWindow* window, + int direction, + const wxString& caption) +{ + wxAuiPaneInfo pinfo; + pinfo.Caption(caption); + switch (direction) + { + case wxTOP: pinfo.Top(); break; + case wxBOTTOM: pinfo.Bottom(); break; + case wxLEFT: pinfo.Left(); break; + case wxRIGHT: pinfo.Right(); break; + case wxCENTER: pinfo.CenterPane(); break; + } + return AddPane(window, pinfo); +} + +bool wxAuiManager::AddPane(wxWindow* window, + const wxAuiPaneInfo& pane_info, + const wxPoint& drop_pos) +{ + if (!AddPane(window, pane_info)) + return false; + + wxAuiPaneInfo& pane = GetPane(window); + + DoDrop(m_docks, m_panes, pane, drop_pos, wxPoint(0,0)); + + return true; +} + +bool wxAuiManager::InsertPane(wxWindow* window, const wxAuiPaneInfo& pane_info, + int insert_level) +{ + wxASSERT_MSG(window, wxT("NULL window ptrs are not allowed")); + + // shift the panes around, depending on the insert level + switch (insert_level) + { + case wxAUI_INSERT_PANE: + DoInsertPane(m_panes, + pane_info.dock_direction, + pane_info.dock_layer, + pane_info.dock_row, + pane_info.dock_pos); + break; + case wxAUI_INSERT_ROW: + DoInsertDockRow(m_panes, + pane_info.dock_direction, + pane_info.dock_layer, + pane_info.dock_row); + break; + case wxAUI_INSERT_DOCK: + DoInsertDockLayer(m_panes, + pane_info.dock_direction, + pane_info.dock_layer); + break; + } + + // if the window already exists, we are basically just moving/inserting the + // existing window. If it doesn't exist, we need to add it and insert it + wxAuiPaneInfo& existing_pane = GetPane(window); + if (!existing_pane.IsOk()) + { + return AddPane(window, pane_info); + } + else + { + if (pane_info.IsFloating()) + { + existing_pane.Float(); + if (pane_info.floating_pos != wxDefaultPosition) + existing_pane.FloatingPosition(pane_info.floating_pos); + if (pane_info.floating_size != wxDefaultSize) + existing_pane.FloatingSize(pane_info.floating_size); + } + else + { + // if the new pane is docked then we should undo maximize + RestoreMaximizedPane(); + + existing_pane.Direction(pane_info.dock_direction); + existing_pane.Layer(pane_info.dock_layer); + existing_pane.Row(pane_info.dock_row); + existing_pane.Position(pane_info.dock_pos); + } + } + + return true; +} + + +// DetachPane() removes a pane from the frame manager. This +// method will not destroy the window that is removed. +bool wxAuiManager::DetachPane(wxWindow* window) +{ + wxASSERT_MSG(window, wxT("NULL window ptrs are not allowed")); + + int i, count; + for (i = 0, count = m_panes.GetCount(); i < count; ++i) + { + wxAuiPaneInfo& p = m_panes.Item(i); + if (p.window == window) + { + if (p.frame) + { + // we have a floating frame which is being detached. We need to + // reparent it to m_frame and destroy the floating frame + + // reduce flicker + p.window->SetSize(1,1); + + if (p.frame->IsShown()) + p.frame->Show(false); + + // reparent to m_frame and destroy the pane + if (m_action_window == p.frame) + { + m_action_window = NULL; + } + + p.window->Reparent(m_frame); + p.frame->SetSizer(NULL); + p.frame->Destroy(); + p.frame = NULL; + } + + // make sure there are no references to this pane in our uiparts, + // just in case the caller doesn't call Update() immediately after + // the DetachPane() call. This prevets obscure crashes which would + // happen at window repaint if the caller forgets to call Update() + int pi, part_count; + for (pi = 0, part_count = (int)m_uiparts.GetCount(); pi < part_count; ++pi) + { + wxAuiDockUIPart& part = m_uiparts.Item(pi); + if (part.pane == &p) + { + m_uiparts.RemoveAt(pi); + part_count--; + pi--; + continue; + } + } + + m_panes.RemoveAt(i); + return true; + } + } + return false; +} + +// ClosePane() destroys or hides the pane depending on its flags +void wxAuiManager::ClosePane(wxAuiPaneInfo& pane_info) +{ + // if we were maximized, restore + if (pane_info.IsMaximized()) + { + RestorePane(pane_info); + } + + // first, hide the window + if (pane_info.window && pane_info.window->IsShown()) + { + pane_info.window->Show(false); + } + + // make sure that we are the parent of this window + if (pane_info.window && pane_info.window->GetParent() != m_frame) + { + pane_info.window->Reparent(m_frame); + } + + // if we have a frame, destroy it + if (pane_info.frame) + { + pane_info.frame->Destroy(); + pane_info.frame = NULL; + } + + // now we need to either destroy or hide the pane + if (pane_info.IsDestroyOnClose()) + { + wxWindow * window = pane_info.window; + DetachPane(window); + if (window) + { + window->Destroy(); + } + } + else + { + pane_info.Hide(); + } +} + +void wxAuiManager::MaximizePane(wxAuiPaneInfo& pane_info) +{ + int i, pane_count; + + // un-maximize and hide all other panes + for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i) + { + wxAuiPaneInfo& p = m_panes.Item(i); + if (!p.IsToolbar() && !p.IsFloating()) + { + p.Restore(); + + // save hidden state + p.SetFlag(wxAuiPaneInfo::savedHiddenState, + p.HasFlag(wxAuiPaneInfo::optionHidden)); + + // hide the pane, because only the newly + // maximized pane should show + p.Hide(); + } + } + + // mark ourselves maximized + pane_info.Maximize(); + pane_info.Show(); + m_has_maximized = true; + + // last, show the window + if (pane_info.window && !pane_info.window->IsShown()) + { + pane_info.window->Show(true); + } +} + +void wxAuiManager::RestorePane(wxAuiPaneInfo& pane_info) +{ + int i, pane_count; + + // restore all the panes + for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i) + { + wxAuiPaneInfo& p = m_panes.Item(i); + if (!p.IsToolbar()) + { + p.SetFlag(wxAuiPaneInfo::optionHidden, + p.HasFlag(wxAuiPaneInfo::savedHiddenState)); + } + } + + // mark ourselves non-maximized + pane_info.Restore(); + m_has_maximized = false; + + // last, show the window + if (pane_info.window && !pane_info.window->IsShown()) + { + pane_info.window->Show(true); + } +} + +void wxAuiManager::RestoreMaximizedPane() +{ + int i, pane_count; + + // restore all the panes + for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i) + { + wxAuiPaneInfo& p = m_panes.Item(i); + if (p.IsMaximized()) + { + RestorePane(p); + break; + } + } +} + +// EscapeDelimiters() changes ";" into "\;" and "|" into "\|" +// in the input string. This is an internal functions which is +// used for saving perspectives +static wxString EscapeDelimiters(const wxString& s) +{ + wxString result; + result.Alloc(s.length()); + const wxChar* ch = s.c_str(); + while (*ch) + { + if (*ch == wxT(';') || *ch == wxT('|')) + result += wxT('\\'); + result += *ch; + ++ch; + } + return result; +} + +wxString wxAuiManager::SavePaneInfo(wxAuiPaneInfo& pane) +{ + wxString result = wxT("name="); + result += EscapeDelimiters(pane.name); + result += wxT(";"); + + result += wxT("caption="); + result += EscapeDelimiters(pane.caption); + result += wxT(";"); + + result += wxString::Format(wxT("state=%u;"), pane.state); + result += wxString::Format(wxT("dir=%d;"), pane.dock_direction); + result += wxString::Format(wxT("layer=%d;"), pane.dock_layer); + result += wxString::Format(wxT("row=%d;"), pane.dock_row); + result += wxString::Format(wxT("pos=%d;"), pane.dock_pos); + result += wxString::Format(wxT("prop=%d;"), pane.dock_proportion); + result += wxString::Format(wxT("bestw=%d;"), pane.best_size.x); + result += wxString::Format(wxT("besth=%d;"), pane.best_size.y); + result += wxString::Format(wxT("minw=%d;"), pane.min_size.x); + result += wxString::Format(wxT("minh=%d;"), pane.min_size.y); + result += wxString::Format(wxT("maxw=%d;"), pane.max_size.x); + result += wxString::Format(wxT("maxh=%d;"), pane.max_size.y); + result += wxString::Format(wxT("floatx=%d;"), pane.floating_pos.x); + result += wxString::Format(wxT("floaty=%d;"), pane.floating_pos.y); + result += wxString::Format(wxT("floatw=%d;"), pane.floating_size.x); + result += wxString::Format(wxT("floath=%d"), pane.floating_size.y); + + return result; +} + +// Load a "pane" with the pane infor settings in pane_part +void wxAuiManager::LoadPaneInfo(wxString pane_part, wxAuiPaneInfo &pane) +{ + // replace escaped characters so we can + // split up the string easily + pane_part.Replace(wxT("\\|"), wxT("\a")); + pane_part.Replace(wxT("\\;"), wxT("\b")); + + while(1) + { + wxString val_part = pane_part.BeforeFirst(wxT(';')); + pane_part = pane_part.AfterFirst(wxT(';')); + wxString val_name = val_part.BeforeFirst(wxT('=')); + wxString value = val_part.AfterFirst(wxT('=')); + val_name.MakeLower(); + val_name.Trim(true); + val_name.Trim(false); + value.Trim(true); + value.Trim(false); + + if (val_name.empty()) + break; + + if (val_name == wxT("name")) + pane.name = value; + else if (val_name == wxT("caption")) + pane.caption = value; + else if (val_name == wxT("state")) + pane.state = (unsigned int)wxAtoi(value.c_str()); + else if (val_name == wxT("dir")) + pane.dock_direction = wxAtoi(value.c_str()); + else if (val_name == wxT("layer")) + pane.dock_layer = wxAtoi(value.c_str()); + else if (val_name == wxT("row")) + pane.dock_row = wxAtoi(value.c_str()); + else if (val_name == wxT("pos")) + pane.dock_pos = wxAtoi(value.c_str()); + else if (val_name == wxT("prop")) + pane.dock_proportion = wxAtoi(value.c_str()); + else if (val_name == wxT("bestw")) + pane.best_size.x = wxAtoi(value.c_str()); + else if (val_name == wxT("besth")) + pane.best_size.y = wxAtoi(value.c_str()); + else if (val_name == wxT("minw")) + pane.min_size.x = wxAtoi(value.c_str()); + else if (val_name == wxT("minh")) + pane.min_size.y = wxAtoi(value.c_str()); + else if (val_name == wxT("maxw")) + pane.max_size.x = wxAtoi(value.c_str()); + else if (val_name == wxT("maxh")) + pane.max_size.y = wxAtoi(value.c_str()); + else if (val_name == wxT("floatx")) + pane.floating_pos.x = wxAtoi(value.c_str()); + else if (val_name == wxT("floaty")) + pane.floating_pos.y = wxAtoi(value.c_str()); + else if (val_name == wxT("floatw")) + pane.floating_size.x = wxAtoi(value.c_str()); + else if (val_name == wxT("floath")) + pane.floating_size.y = wxAtoi(value.c_str()); + else { + wxFAIL_MSG(wxT("Bad Perspective String")); + } + } + + // replace escaped characters so we can + // split up the string easily + pane.name.Replace(wxT("\a"), wxT("|")); + pane.name.Replace(wxT("\b"), wxT(";")); + pane.caption.Replace(wxT("\a"), wxT("|")); + pane.caption.Replace(wxT("\b"), wxT(";")); + pane_part.Replace(wxT("\a"), wxT("|")); + pane_part.Replace(wxT("\b"), wxT(";")); + + return; +} + + +// SavePerspective() saves all pane information as a single string. +// This string may later be fed into LoadPerspective() to restore +// all pane settings. This save and load mechanism allows an +// exact pane configuration to be saved and restored at a later time + +wxString wxAuiManager::SavePerspective() +{ + wxString result; + result.Alloc(500); + result = wxT("layout2|"); + + int pane_i, pane_count = m_panes.GetCount(); + for (pane_i = 0; pane_i < pane_count; ++pane_i) + { + wxAuiPaneInfo& pane = m_panes.Item(pane_i); + result += SavePaneInfo(pane)+wxT("|"); + } + + int dock_i, dock_count = m_docks.GetCount(); + for (dock_i = 0; dock_i < dock_count; ++dock_i) + { + wxAuiDockInfo& dock = m_docks.Item(dock_i); + + result += wxString::Format(wxT("dock_size(%d,%d,%d)=%d|"), + dock.dock_direction, dock.dock_layer, + dock.dock_row, dock.size); + } + + return result; +} + +// LoadPerspective() loads a layout which was saved with SavePerspective() +// If the "update" flag parameter is true, the GUI will immediately be updated + +bool wxAuiManager::LoadPerspective(const wxString& layout, bool update) +{ + wxString input = layout; + wxString part; + + // check layout string version + // 'layout1' = wxAUI 0.9.0 - wxAUI 0.9.2 + // 'layout2' = wxAUI 0.9.2 (wxWidgets 2.8) + part = input.BeforeFirst(wxT('|')); + input = input.AfterFirst(wxT('|')); + part.Trim(true); + part.Trim(false); + if (part != wxT("layout2")) + return false; + + // mark all panes currently managed as docked and hidden + int pane_i, pane_count = m_panes.GetCount(); + for (pane_i = 0; pane_i < pane_count; ++pane_i) + m_panes.Item(pane_i).Dock().Hide(); + + // clear out the dock array; this will be reconstructed + m_docks.Clear(); + + // replace escaped characters so we can + // split up the string easily + input.Replace(wxT("\\|"), wxT("\a")); + input.Replace(wxT("\\;"), wxT("\b")); + + while (1) + { + wxAuiPaneInfo pane; + + wxString pane_part = input.BeforeFirst(wxT('|')); + input = input.AfterFirst(wxT('|')); + pane_part.Trim(true); + + // if the string is empty, we're done parsing + if (pane_part.empty()) + break; + + if (pane_part.Left(9) == wxT("dock_size")) + { + wxString val_name = pane_part.BeforeFirst(wxT('=')); + wxString value = pane_part.AfterFirst(wxT('=')); + + long dir, layer, row, size; + wxString piece = val_name.AfterFirst(wxT('(')); + piece = piece.BeforeLast(wxT(')')); + piece.BeforeFirst(wxT(',')).ToLong(&dir); + piece = piece.AfterFirst(wxT(',')); + piece.BeforeFirst(wxT(',')).ToLong(&layer); + piece.AfterFirst(wxT(',')).ToLong(&row); + value.ToLong(&size); + + wxAuiDockInfo dock; + dock.dock_direction = dir; + dock.dock_layer = layer; + dock.dock_row = row; + dock.size = size; + m_docks.Add(dock); + continue; + } + + // Undo our escaping as LoadPaneInfo needs to take an unescaped + // name so it can be called by external callers + pane_part.Replace(wxT("\a"), wxT("|")); + pane_part.Replace(wxT("\b"), wxT(";")); + + LoadPaneInfo(pane_part, pane); + + wxAuiPaneInfo& p = GetPane(pane.name); + if (!p.IsOk()) + { + // the pane window couldn't be found + // in the existing layout -- skip it + continue; + } + + p.SafeSet(pane); + } + + if (update) + Update(); + + return true; +} + +void wxAuiManager::GetPanePositionsAndSizes(wxAuiDockInfo& dock, + wxArrayInt& positions, + wxArrayInt& sizes) +{ + int caption_size = m_art->GetMetric(wxAUI_DOCKART_CAPTION_SIZE); + int pane_border_size = m_art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE); + int gripper_size = m_art->GetMetric(wxAUI_DOCKART_GRIPPER_SIZE); + + positions.Empty(); + sizes.Empty(); + + int offset, action_pane = -1; + int pane_i, pane_count = dock.panes.GetCount(); + + // find the pane marked as our action pane + for (pane_i = 0; pane_i < pane_count; ++pane_i) + { + wxAuiPaneInfo& pane = *(dock.panes.Item(pane_i)); + + if (pane.state & wxAuiPaneInfo::actionPane) + { + wxASSERT_MSG(action_pane==-1, wxT("Too many fixed action panes")); + action_pane = pane_i; + } + } + + // set up each panes default position, and + // determine the size (width or height, depending + // on the dock's orientation) of each pane + for (pane_i = 0; pane_i < pane_count; ++pane_i) + { + wxAuiPaneInfo& pane = *(dock.panes.Item(pane_i)); + positions.Add(pane.dock_pos); + int size = 0; + + if (pane.HasBorder()) + size += (pane_border_size*2); + + if (dock.IsHorizontal()) + { + if (pane.HasGripper() && !pane.HasGripperTop()) + size += gripper_size; + size += pane.best_size.x; + } + else + { + if (pane.HasGripper() && pane.HasGripperTop()) + size += gripper_size; + + if (pane.HasCaption()) + size += caption_size; + size += pane.best_size.y; + } + + sizes.Add(size); + } + + // if there is no action pane, just return the default + // positions (as specified in pane.pane_pos) + if (action_pane == -1) + return; + + offset = 0; + for (pane_i = action_pane-1; pane_i >= 0; --pane_i) + { + int amount = positions[pane_i+1] - (positions[pane_i] + sizes[pane_i]); + + if (amount >= 0) + offset += amount; + else + positions[pane_i] -= -amount; + + offset += sizes[pane_i]; + } + + // if the dock mode is fixed, make sure none of the panes + // overlap; we will bump panes that overlap + offset = 0; + for (pane_i = action_pane; pane_i < pane_count; ++pane_i) + { + int amount = positions[pane_i] - offset; + if (amount >= 0) + offset += amount; + else + positions[pane_i] += -amount; + + offset += sizes[pane_i]; + } +} + + +void wxAuiManager::LayoutAddPane(wxSizer* cont, + wxAuiDockInfo& dock, + wxAuiPaneInfo& pane, + wxAuiDockUIPartArray& uiparts, + bool spacer_only) +{ + wxAuiDockUIPart part; + wxSizerItem* sizer_item; + + int caption_size = m_art->GetMetric(wxAUI_DOCKART_CAPTION_SIZE); + int gripper_size = m_art->GetMetric(wxAUI_DOCKART_GRIPPER_SIZE); + int pane_border_size = m_art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE); + int pane_button_size = m_art->GetMetric(wxAUI_DOCKART_PANE_BUTTON_SIZE); + + // find out the orientation of the item (orientation for panes + // is the same as the dock's orientation) + int orientation; + if (dock.IsHorizontal()) + orientation = wxHORIZONTAL; + else + orientation = wxVERTICAL; + + // this variable will store the proportion + // value that the pane will receive + int pane_proportion = pane.dock_proportion; + + wxBoxSizer* horz_pane_sizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* vert_pane_sizer = new wxBoxSizer(wxVERTICAL); + + if (pane.HasGripper()) + { + if (pane.HasGripperTop()) + sizer_item = vert_pane_sizer ->Add(1, gripper_size, 0, wxEXPAND); + else + sizer_item = horz_pane_sizer ->Add(gripper_size, 1, 0, wxEXPAND); + + part.type = wxAuiDockUIPart::typeGripper; + part.dock = &dock; + part.pane = &pane; + part.button = NULL; + part.orientation = orientation; + part.cont_sizer = horz_pane_sizer; + part.sizer_item = sizer_item; + uiparts.Add(part); + } + + if (pane.HasCaption()) + { + // create the caption sizer + wxBoxSizer* caption_sizer = new wxBoxSizer(wxHORIZONTAL); + + sizer_item = caption_sizer->Add(1, caption_size, 1, wxEXPAND); + + part.type = wxAuiDockUIPart::typeCaption; + part.dock = &dock; + part.pane = &pane; + part.button = NULL; + part.orientation = orientation; + part.cont_sizer = vert_pane_sizer; + part.sizer_item = sizer_item; + int caption_part_idx = uiparts.GetCount(); + uiparts.Add(part); + + // add pane buttons to the caption + int i, button_count; + for (i = 0, button_count = pane.buttons.GetCount(); + i < button_count; ++i) + { + wxAuiPaneButton& button = pane.buttons.Item(i); + + sizer_item = caption_sizer->Add(pane_button_size, + caption_size, + 0, wxEXPAND); + + part.type = wxAuiDockUIPart::typePaneButton; + part.dock = &dock; + part.pane = &pane; + part.button = &button; + part.orientation = orientation; + part.cont_sizer = caption_sizer; + part.sizer_item = sizer_item; + uiparts.Add(part); + } + + // if we have buttons, add a little space to the right + // of them to ease visual crowding + if (button_count >= 1) + { + caption_sizer->Add(3,1); + } + + // add the caption sizer + sizer_item = vert_pane_sizer->Add(caption_sizer, 0, wxEXPAND); + + uiparts.Item(caption_part_idx).sizer_item = sizer_item; + } + + // add the pane window itself + if (spacer_only) + { + sizer_item = vert_pane_sizer->Add(1, 1, 1, wxEXPAND); + } + else + { + sizer_item = vert_pane_sizer->Add(pane.window, 1, wxEXPAND); + // Don't do this because it breaks the pane size in floating windows + // BIW: Right now commenting this out is causing problems with + // an mdi client window as the center pane. + vert_pane_sizer->SetItemMinSize(pane.window, 1, 1); + } + + part.type = wxAuiDockUIPart::typePane; + part.dock = &dock; + part.pane = &pane; + part.button = NULL; + part.orientation = orientation; + part.cont_sizer = vert_pane_sizer; + part.sizer_item = sizer_item; + uiparts.Add(part); + + + // determine if the pane should have a minimum size; if the pane is + // non-resizable (fixed) then we must set a minimum size. Alternatively, + // if the pane.min_size is set, we must use that value as well + + wxSize min_size = pane.min_size; + if (pane.IsFixed()) + { + if (min_size == wxDefaultSize) + { + min_size = pane.best_size; + pane_proportion = 0; + } + } + + if (min_size != wxDefaultSize) + { + vert_pane_sizer->SetItemMinSize( + vert_pane_sizer->GetChildren().GetCount()-1, + min_size.x, min_size.y); + } + + + // add the verticle sizer (caption, pane window) to the + // horizontal sizer (gripper, verticle sizer) + horz_pane_sizer->Add(vert_pane_sizer, 1, wxEXPAND); + + // finally, add the pane sizer to the dock sizer + + if (pane.HasBorder()) + { + // allowing space for the pane's border + sizer_item = cont->Add(horz_pane_sizer, pane_proportion, + wxEXPAND | wxALL, pane_border_size); + + part.type = wxAuiDockUIPart::typePaneBorder; + part.dock = &dock; + part.pane = &pane; + part.button = NULL; + part.orientation = orientation; + part.cont_sizer = cont; + part.sizer_item = sizer_item; + uiparts.Add(part); + } + else + { + sizer_item = cont->Add(horz_pane_sizer, pane_proportion, wxEXPAND); + } +} + +void wxAuiManager::LayoutAddDock(wxSizer* cont, + wxAuiDockInfo& dock, + wxAuiDockUIPartArray& uiparts, + bool spacer_only) +{ + wxSizerItem* sizer_item; + wxAuiDockUIPart part; + + int sash_size = m_art->GetMetric(wxAUI_DOCKART_SASH_SIZE); + int orientation = dock.IsHorizontal() ? wxHORIZONTAL : wxVERTICAL; + + // resizable bottom and right docks have a sash before them + if (!m_has_maximized && !dock.fixed && (dock.dock_direction == wxAUI_DOCK_BOTTOM || + dock.dock_direction == wxAUI_DOCK_RIGHT)) + { + sizer_item = cont->Add(sash_size, sash_size, 0, wxEXPAND); + + part.type = wxAuiDockUIPart::typeDockSizer; + part.orientation = orientation; + part.dock = &dock; + part.pane = NULL; + part.button = NULL; + part.cont_sizer = cont; + part.sizer_item = sizer_item; + uiparts.Add(part); + } + + // create the sizer for the dock + wxSizer* dock_sizer = new wxBoxSizer(orientation); + + // add each pane to the dock + bool has_maximized_pane = false; + int pane_i, pane_count = dock.panes.GetCount(); + + if (dock.fixed) + { + wxArrayInt pane_positions, pane_sizes; + + // figure out the real pane positions we will + // use, without modifying the each pane's pane_pos member + GetPanePositionsAndSizes(dock, pane_positions, pane_sizes); + + int offset = 0; + for (pane_i = 0; pane_i < pane_count; ++pane_i) + { + wxAuiPaneInfo& pane = *(dock.panes.Item(pane_i)); + int pane_pos = pane_positions.Item(pane_i); + + if (pane.IsMaximized()) + has_maximized_pane = true; + + + int amount = pane_pos - offset; + if (amount > 0) + { + if (dock.IsVertical()) + sizer_item = dock_sizer->Add(1, amount, 0, wxEXPAND); + else + sizer_item = dock_sizer->Add(amount, 1, 0, wxEXPAND); + + part.type = wxAuiDockUIPart::typeBackground; + part.dock = &dock; + part.pane = NULL; + part.button = NULL; + part.orientation = (orientation==wxHORIZONTAL) ? wxVERTICAL:wxHORIZONTAL; + part.cont_sizer = dock_sizer; + part.sizer_item = sizer_item; + uiparts.Add(part); + + offset += amount; + } + + LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only); + + offset += pane_sizes.Item(pane_i); + } + + // at the end add a very small stretchable background area + sizer_item = dock_sizer->Add(0,0, 1, wxEXPAND); + + part.type = wxAuiDockUIPart::typeBackground; + part.dock = &dock; + part.pane = NULL; + part.button = NULL; + part.orientation = orientation; + part.cont_sizer = dock_sizer; + part.sizer_item = sizer_item; + uiparts.Add(part); + } + else + { + for (pane_i = 0; pane_i < pane_count; ++pane_i) + { + wxAuiPaneInfo& pane = *(dock.panes.Item(pane_i)); + + if (pane.IsMaximized()) + has_maximized_pane = true; + + // if this is not the first pane being added, + // we need to add a pane sizer + if (!m_has_maximized && pane_i > 0) + { + sizer_item = dock_sizer->Add(sash_size, sash_size, 0, wxEXPAND); + + part.type = wxAuiDockUIPart::typePaneSizer; + part.dock = &dock; + part.pane = dock.panes.Item(pane_i-1); + part.button = NULL; + part.orientation = (orientation==wxHORIZONTAL) ? wxVERTICAL:wxHORIZONTAL; + part.cont_sizer = dock_sizer; + part.sizer_item = sizer_item; + uiparts.Add(part); + } + + LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only); + } + } + + if (dock.dock_direction == wxAUI_DOCK_CENTER || has_maximized_pane) + sizer_item = cont->Add(dock_sizer, 1, wxEXPAND); + else + sizer_item = cont->Add(dock_sizer, 0, wxEXPAND); + + part.type = wxAuiDockUIPart::typeDock; + part.dock = &dock; + part.pane = NULL; + part.button = NULL; + part.orientation = orientation; + part.cont_sizer = cont; + part.sizer_item = sizer_item; + uiparts.Add(part); + + if (dock.IsHorizontal()) + cont->SetItemMinSize(dock_sizer, 0, dock.size); + else + cont->SetItemMinSize(dock_sizer, dock.size, 0); + + // top and left docks have a sash after them + if (!m_has_maximized && + !dock.fixed && + (dock.dock_direction == wxAUI_DOCK_TOP || + dock.dock_direction == wxAUI_DOCK_LEFT)) + { + sizer_item = cont->Add(sash_size, sash_size, 0, wxEXPAND); + + part.type = wxAuiDockUIPart::typeDockSizer; + part.dock = &dock; + part.pane = NULL; + part.button = NULL; + part.orientation = orientation; + part.cont_sizer = cont; + part.sizer_item = sizer_item; + uiparts.Add(part); + } +} + +wxSizer* wxAuiManager::LayoutAll(wxAuiPaneInfoArray& panes, + wxAuiDockInfoArray& docks, + wxAuiDockUIPartArray& uiparts, + bool spacer_only) +{ + wxBoxSizer* container = new wxBoxSizer(wxVERTICAL); + + int pane_border_size = m_art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE); + int caption_size = m_art->GetMetric(wxAUI_DOCKART_CAPTION_SIZE); + wxSize cli_size = m_frame->GetClientSize(); + int i, dock_count, pane_count; + + + // empty all docks out + for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i) + { + wxAuiDockInfo& dock = docks.Item(i); + + // empty out all panes, as they will be readded below + dock.panes.Empty(); + + if (dock.fixed) + { + // always reset fixed docks' sizes, because + // the contained windows may have been resized + dock.size = 0; + } + } + + + // iterate through all known panes, filing each + // of them into the appropriate dock. If the + // pane does not exist in the dock, add it + for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i) + { + wxAuiPaneInfo& p = panes.Item(i); + + // find any docks with the same dock direction, dock layer, and + // dock row as the pane we are working on + wxAuiDockInfo* dock; + wxAuiDockInfoPtrArray arr; + FindDocks(docks, p.dock_direction, p.dock_layer, p.dock_row, arr); + + if (arr.GetCount() > 0) + { + // found the right dock + dock = arr.Item(0); + } + else + { + // dock was not found, so we need to create a new one + wxAuiDockInfo d; + d.dock_direction = p.dock_direction; + d.dock_layer = p.dock_layer; + d.dock_row = p.dock_row; + docks.Add(d); + dock = &docks.Last(); + } + + + if (p.IsDocked() && p.IsShown()) + { + // remove the pane from any existing docks except this one + RemovePaneFromDocks(docks, p, dock); + + // pane needs to be added to the dock, + // if it doesn't already exist + if (!FindPaneInDock(*dock, p.window)) + dock->panes.Add(&p); + } + else + { + // remove the pane from any existing docks + RemovePaneFromDocks(docks, p); + } + + } + + // remove any empty docks + for (i = docks.GetCount()-1; i >= 0; --i) + { + if (docks.Item(i).panes.GetCount() == 0) + docks.RemoveAt(i); + } + + // configure the docks further + for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i) + { + wxAuiDockInfo& dock = docks.Item(i); + int j, dock_pane_count = dock.panes.GetCount(); + + // sort the dock pane array by the pane's + // dock position (dock_pos), in ascending order + dock.panes.Sort(PaneSortFunc); + + // for newly created docks, set up their initial size + if (dock.size == 0) + { + int size = 0; + + for (j = 0; j < dock_pane_count; ++j) + { + wxAuiPaneInfo& pane = *dock.panes.Item(j); + wxSize pane_size = pane.best_size; + if (pane_size == wxDefaultSize) + pane_size = pane.min_size; + if (pane_size == wxDefaultSize) + pane_size = pane.window->GetSize(); + + if (dock.IsHorizontal()) + size = wxMax(pane_size.y, size); + else + size = wxMax(pane_size.x, size); + } + + // add space for the border (two times), but only + // if at least one pane inside the dock has a pane border + for (j = 0; j < dock_pane_count; ++j) + { + if (dock.panes.Item(j)->HasBorder()) + { + size += (pane_border_size*2); + break; + } + } + + // if pane is on the top or bottom, add the caption height, + // but only if at least one pane inside the dock has a caption + if (dock.IsHorizontal()) + { + for (j = 0; j < dock_pane_count; ++j) + { + if (dock.panes.Item(j)->HasCaption()) + { + size += caption_size; + break; + } + } + } + + + // new dock's size may not be more than the dock constraint + // parameter specifies. See SetDockSizeConstraint() + + int max_dock_x_size = (int)(m_dock_constraint_x * ((double)cli_size.x)); + int max_dock_y_size = (int)(m_dock_constraint_y * ((double)cli_size.y)); + + if (dock.IsHorizontal()) + size = wxMin(size, max_dock_y_size); + else + size = wxMin(size, max_dock_x_size); + + // absolute minimum size for a dock is 10 pixels + if (size < 10) + size = 10; + + dock.size = size; + } + + + // determine the dock's minimum size + bool plus_border = false; + bool plus_caption = false; + int dock_min_size = 0; + for (j = 0; j < dock_pane_count; ++j) + { + wxAuiPaneInfo& pane = *dock.panes.Item(j); + if (pane.min_size != wxDefaultSize) + { + if (pane.HasBorder()) + plus_border = true; + if (pane.HasCaption()) + plus_caption = true; + if (dock.IsHorizontal()) + { + if (pane.min_size.y > dock_min_size) + dock_min_size = pane.min_size.y; + } + else + { + if (pane.min_size.x > dock_min_size) + dock_min_size = pane.min_size.x; + } + } + } + + if (plus_border) + dock_min_size += (pane_border_size*2); + if (plus_caption && dock.IsHorizontal()) + dock_min_size += (caption_size); + + dock.min_size = dock_min_size; + + + // if the pane's current size is less than it's + // minimum, increase the dock's size to it's minimum + if (dock.size < dock.min_size) + dock.size = dock.min_size; + + + // determine the dock's mode (fixed or proportional); + // determine whether the dock has only toolbars + bool action_pane_marked = false; + dock.fixed = true; + dock.toolbar = true; + for (j = 0; j < dock_pane_count; ++j) + { + wxAuiPaneInfo& pane = *dock.panes.Item(j); + if (!pane.IsFixed()) + dock.fixed = false; + if (!pane.IsToolbar()) + dock.toolbar = false; + if (pane.HasFlag(wxAuiPaneInfo::optionDockFixed)) + dock.fixed = true; + if (pane.state & wxAuiPaneInfo::actionPane) + action_pane_marked = true; + } + + + // if the dock mode is proportional and not fixed-pixel, + // reassign the dock_pos to the sequential 0, 1, 2, 3; + // e.g. remove gaps like 1, 2, 30, 500 + if (!dock.fixed) + { + for (j = 0; j < dock_pane_count; ++j) + { + wxAuiPaneInfo& pane = *dock.panes.Item(j); + pane.dock_pos = j; + } + } + + // if the dock mode is fixed, and none of the panes + // are being moved right now, make sure the panes + // do not overlap each other. If they do, we will + // adjust the positions of the panes + if (dock.fixed && !action_pane_marked) + { + wxArrayInt pane_positions, pane_sizes; + GetPanePositionsAndSizes(dock, pane_positions, pane_sizes); + + int offset = 0; + for (j = 0; j < dock_pane_count; ++j) + { + wxAuiPaneInfo& pane = *(dock.panes.Item(j)); + pane.dock_pos = pane_positions[j]; + + int amount = pane.dock_pos - offset; + if (amount >= 0) + offset += amount; + else + pane.dock_pos += -amount; + + offset += pane_sizes[j]; + } + } + } + + // discover the maximum dock layer + int max_layer = 0; + for (i = 0; i < dock_count; ++i) + max_layer = wxMax(max_layer, docks.Item(i).dock_layer); + + + // clear out uiparts + uiparts.Empty(); + + // create a bunch of box sizers, + // from the innermost level outwards. + wxSizer* cont = NULL; + wxSizer* middle = NULL; + int layer = 0; + int row, row_count; + + for (layer = 0; layer <= max_layer; ++layer) + { + wxAuiDockInfoPtrArray arr; + + // find any docks in this layer + FindDocks(docks, -1, layer, -1, arr); + + // if there aren't any, skip to the next layer + if (arr.IsEmpty()) + continue; + + wxSizer* old_cont = cont; + + // create a container which will hold this layer's + // docks (top, bottom, left, right) + cont = new wxBoxSizer(wxVERTICAL); + + + // find any top docks in this layer + FindDocks(docks, wxAUI_DOCK_TOP, layer, -1, arr); + if (!arr.IsEmpty()) + { + for (row = 0, row_count = arr.GetCount(); row < row_count; ++row) + LayoutAddDock(cont, *arr.Item(row), uiparts, spacer_only); + } + + + // fill out the middle layer (which consists + // of left docks, content area and right docks) + + middle = new wxBoxSizer(wxHORIZONTAL); + + // find any left docks in this layer + FindDocks(docks, wxAUI_DOCK_LEFT, layer, -1, arr); + if (!arr.IsEmpty()) + { + for (row = 0, row_count = arr.GetCount(); row < row_count; ++row) + LayoutAddDock(middle, *arr.Item(row), uiparts, spacer_only); + } + + // add content dock (or previous layer's sizer + // to the middle + if (!old_cont) + { + // find any center docks + FindDocks(docks, wxAUI_DOCK_CENTER, -1, -1, arr); + if (!arr.IsEmpty()) + { + for (row = 0,row_count = arr.GetCount(); rowAdd(1,1, 1, wxEXPAND); + wxAuiDockUIPart part; + part.type = wxAuiDockUIPart::typeBackground; + part.pane = NULL; + part.dock = NULL; + part.button = NULL; + part.cont_sizer = middle; + part.sizer_item = sizer_item; + uiparts.Add(part); + } + } + else + { + middle->Add(old_cont, 1, wxEXPAND); + } + + // find any right docks in this layer + FindDocks(docks, wxAUI_DOCK_RIGHT, layer, -1, arr); + if (!arr.IsEmpty()) + { + for (row = arr.GetCount()-1; row >= 0; --row) + LayoutAddDock(middle, *arr.Item(row), uiparts, spacer_only); + } + + if (middle->GetChildren().GetCount() > 0) + cont->Add(middle, 1, wxEXPAND); + else + delete middle; + + + + // find any bottom docks in this layer + FindDocks(docks, wxAUI_DOCK_BOTTOM, layer, -1, arr); + if (!arr.IsEmpty()) + { + for (row = arr.GetCount()-1; row >= 0; --row) + LayoutAddDock(cont, *arr.Item(row), uiparts, spacer_only); + } + + } + + if (!cont) + { + // no sizer available, because there are no docks, + // therefore we will create a simple background area + cont = new wxBoxSizer(wxVERTICAL); + wxSizerItem* sizer_item = cont->Add(1,1, 1, wxEXPAND); + wxAuiDockUIPart part; + part.type = wxAuiDockUIPart::typeBackground; + part.pane = NULL; + part.dock = NULL; + part.button = NULL; + part.cont_sizer = middle; + part.sizer_item = sizer_item; + uiparts.Add(part); + } + + container->Add(cont, 1, wxEXPAND); + return container; +} + + +// SetDockSizeConstraint() allows the dock constraints to be set. For example, +// specifying values of 0.5, 0.5 will mean that upon dock creation, a dock may +// not be larger than half of the window's size + +void wxAuiManager::SetDockSizeConstraint(double width_pct, double height_pct) +{ + m_dock_constraint_x = wxMax(0.0, wxMin(1.0, width_pct)); + m_dock_constraint_y = wxMax(0.0, wxMin(1.0, height_pct)); +} + +void wxAuiManager::GetDockSizeConstraint(double* width_pct, double* height_pct) const +{ + if (width_pct) + *width_pct = m_dock_constraint_x; + + if (height_pct) + *height_pct = m_dock_constraint_y; +} + + + +// Update() updates the layout. Whenever changes are made to +// one or more panes, this function should be called. It is the +// external entry point for running the layout engine. + +void wxAuiManager::Update() +{ + m_hover_button = NULL; + m_action_part = NULL; + + wxSizer* sizer; + int i, pane_count = m_panes.GetCount(); + + + // destroy floating panes which have been + // redocked or are becoming non-floating + for (i = 0; i < pane_count; ++i) + { + wxAuiPaneInfo& p = m_panes.Item(i); + + if (!p.IsFloating() && p.frame) + { + // because the pane is no longer in a floating, we need to + // reparent it to m_frame and destroy the floating frame + + // reduce flicker + p.window->SetSize(1,1); + + + // the following block is a workaround for bug #1531361 + // (see wxWidgets sourceforge page). On wxGTK (only), when + // a frame is shown/hidden, a move event unfortunately + // also gets fired. Because we may be dragging around + // a pane, we need to cancel that action here to prevent + // a spurious crash. + if (m_action_window == p.frame) + { + if (wxWindow::GetCapture() == m_frame) + m_frame->ReleaseMouse(); + m_action = actionNone; + m_action_window = NULL; + } + + // hide the frame + if (p.frame->IsShown()) + p.frame->Show(false); + + // reparent to m_frame and destroy the pane + if (m_action_window == p.frame) + { + m_action_window = NULL; + } + + p.window->Reparent(m_frame); + p.frame->SetSizer(NULL); + p.frame->Destroy(); + p.frame = NULL; + } + } + + + // delete old sizer first + m_frame->SetSizer(NULL); + + // create a layout for all of the panes + sizer = LayoutAll(m_panes, m_docks, m_uiparts, false); + + // hide or show panes as necessary, + // and float panes as necessary + for (i = 0; i < pane_count; ++i) + { + wxAuiPaneInfo& p = m_panes.Item(i); + + if (p.IsFloating()) + { + if (p.frame == NULL) + { + // we need to create a frame for this + // pane, which has recently been floated + wxAuiFloatingFrame* frame = CreateFloatingFrame(m_frame, p); + + // on MSW and Mac, if the owner desires transparent dragging, and + // the dragging is happening right now, then the floating + // window should have this style by default + if (m_action == actionDragFloatingPane && + (m_flags & wxAUI_MGR_TRANSPARENT_DRAG)) + frame->SetTransparent(150); + + frame->SetPaneWindow(p); + p.frame = frame; + + if (p.IsShown() && !frame->IsShown()) + frame->Show(); + } + else + { + // frame already exists, make sure it's position + // and size reflect the information in wxAuiPaneInfo + if ((p.frame->GetPosition() != p.floating_pos) || (p.frame->GetSize() != p.floating_size)) + { + p.frame->SetSize(p.floating_pos.x, p.floating_pos.y, + p.floating_size.x, p.floating_size.y, + wxSIZE_USE_EXISTING); + /* + p.frame->SetSize(p.floating_pos.x, p.floating_pos.y, + wxDefaultCoord, wxDefaultCoord, + wxSIZE_USE_EXISTING); + //p.frame->Move(p.floating_pos.x, p.floating_pos.y); + */ + } + + if (p.frame->IsShown() != p.IsShown()) + p.frame->Show(p.IsShown()); + } + } + else + { + if (p.window->IsShown() != p.IsShown()) + p.window->Show(p.IsShown()); + } + + // if "active panes" are no longer allowed, clear + // any optionActive values from the pane states + if ((m_flags & wxAUI_MGR_ALLOW_ACTIVE_PANE) == 0) + { + p.state &= ~wxAuiPaneInfo::optionActive; + } + } + + + // keep track of the old window rectangles so we can + // refresh those windows whose rect has changed + wxAuiRectArray old_pane_rects; + for (i = 0; i < pane_count; ++i) + { + wxRect r; + wxAuiPaneInfo& p = m_panes.Item(i); + + if (p.window && p.IsShown() && p.IsDocked()) + r = p.rect; + + old_pane_rects.Add(r); + } + + + + + // apply the new sizer + m_frame->SetSizer(sizer); + m_frame->SetAutoLayout(false); + DoFrameLayout(); + + + + // now that the frame layout is done, we need to check + // the new pane rectangles against the old rectangles that + // we saved a few lines above here. If the rectangles have + // changed, the corresponding panes must also be updated + for (i = 0; i < pane_count; ++i) + { + wxAuiPaneInfo& p = m_panes.Item(i); + if (p.window && p.window->IsShown() && p.IsDocked()) + { + if (p.rect != old_pane_rects[i]) + { + p.window->Refresh(); + p.window->Update(); + } + } + } + + + Repaint(); + + // set frame's minimum size + +/* + // N.B. More work needs to be done on frame minimum sizes; + // this is some intresting code that imposes the minimum size, + // but we may want to include a more flexible mechanism or + // options for multiple minimum-size modes, e.g. strict or lax + wxSize min_size = sizer->GetMinSize(); + wxSize frame_size = m_frame->GetSize(); + wxSize client_size = m_frame->GetClientSize(); + + wxSize minframe_size(min_size.x+frame_size.x-client_size.x, + min_size.y+frame_size.y-client_size.y ); + + m_frame->SetMinSize(minframe_size); + + if (frame_size.x < minframe_size.x || + frame_size.y < minframe_size.y) + sizer->Fit(m_frame); +*/ +} + + +// DoFrameLayout() is an internal function which invokes wxSizer::Layout +// on the frame's main sizer, then measures all the various UI items +// and updates their internal rectangles. This should always be called +// instead of calling m_frame->Layout() directly + +void wxAuiManager::DoFrameLayout() +{ + m_frame->Layout(); + + int i, part_count; + for (i = 0, part_count = m_uiparts.GetCount(); i < part_count; ++i) + { + wxAuiDockUIPart& part = m_uiparts.Item(i); + + // get the rectangle of the UI part + // originally, this code looked like this: + // part.rect = wxRect(part.sizer_item->GetPosition(), + // part.sizer_item->GetSize()); + // this worked quite well, with one exception: the mdi + // client window had a "deferred" size variable + // that returned the wrong size. It looks like + // a bug in wx, because the former size of the window + // was being returned. So, we will retrieve the part's + // rectangle via other means + + + part.rect = part.sizer_item->GetRect(); + int flag = part.sizer_item->GetFlag(); + int border = part.sizer_item->GetBorder(); + if (flag & wxTOP) + { + part.rect.y -= border; + part.rect.height += border; + } + if (flag & wxLEFT) + { + part.rect.x -= border; + part.rect.width += border; + } + if (flag & wxBOTTOM) + part.rect.height += border; + if (flag & wxRIGHT) + part.rect.width += border; + + + if (part.type == wxAuiDockUIPart::typeDock) + part.dock->rect = part.rect; + if (part.type == wxAuiDockUIPart::typePane) + part.pane->rect = part.rect; + } +} + +// GetPanePart() looks up the pane the pane border UI part (or the regular +// pane part if there is no border). This allows the caller to get the exact +// rectangle of the pane in question, including decorations like +// caption and border (if any). + +wxAuiDockUIPart* wxAuiManager::GetPanePart(wxWindow* wnd) +{ + int i, part_count; + for (i = 0, part_count = m_uiparts.GetCount(); i < part_count; ++i) + { + wxAuiDockUIPart& part = m_uiparts.Item(i); + if (part.type == wxAuiDockUIPart::typePaneBorder && + part.pane && part.pane->window == wnd) + return ∂ + } + for (i = 0, part_count = m_uiparts.GetCount(); i < part_count; ++i) + { + wxAuiDockUIPart& part = m_uiparts.Item(i); + if (part.type == wxAuiDockUIPart::typePane && + part.pane && part.pane->window == wnd) + return ∂ + } + return NULL; +} + + + +// GetDockPixelOffset() is an internal function which returns +// a dock's offset in pixels from the left side of the window +// (for horizontal docks) or from the top of the window (for +// vertical docks). This value is necessary for calculating +// fixel-pane/toolbar offsets when they are dragged. + +int wxAuiManager::GetDockPixelOffset(wxAuiPaneInfo& test) +{ + // the only way to accurately calculate the dock's + // offset is to actually run a theoretical layout + + int i, part_count, dock_count; + wxAuiDockInfoArray docks; + wxAuiPaneInfoArray panes; + wxAuiDockUIPartArray uiparts; + CopyDocksAndPanes(docks, panes, m_docks, m_panes); + panes.Add(test); + + wxSizer* sizer = LayoutAll(panes, docks, uiparts, true); + wxSize client_size = m_frame->GetClientSize(); + sizer->SetDimension(0, 0, client_size.x, client_size.y); + sizer->Layout(); + + for (i = 0, part_count = uiparts.GetCount(); i < part_count; ++i) + { + wxAuiDockUIPart& part = uiparts.Item(i); + part.rect = wxRect(part.sizer_item->GetPosition(), + part.sizer_item->GetSize()); + if (part.type == wxAuiDockUIPart::typeDock) + part.dock->rect = part.rect; + } + + delete sizer; + + for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i) + { + wxAuiDockInfo& dock = docks.Item(i); + if (test.dock_direction == dock.dock_direction && + test.dock_layer==dock.dock_layer && test.dock_row==dock.dock_row) + { + if (dock.IsVertical()) + return dock.rect.y; + else + return dock.rect.x; + } + } + + return 0; +} + + + +// ProcessDockResult() is a utility function used by DoDrop() - it checks +// if a dock operation is allowed, the new dock position is copied into +// the target info. If the operation was allowed, the function returns true. + +bool wxAuiManager::ProcessDockResult(wxAuiPaneInfo& target, + const wxAuiPaneInfo& new_pos) +{ + bool allowed = false; + switch (new_pos.dock_direction) + { + case wxAUI_DOCK_TOP: allowed = target.IsTopDockable(); break; + case wxAUI_DOCK_BOTTOM: allowed = target.IsBottomDockable(); break; + case wxAUI_DOCK_LEFT: allowed = target.IsLeftDockable(); break; + case wxAUI_DOCK_RIGHT: allowed = target.IsRightDockable(); break; + } + + if (allowed) + target = new_pos; + + return allowed; +} + + +// DoDrop() is an important function. It basically takes a mouse position, +// and determines where the pane's new position would be. If the pane is to be +// dropped, it performs the drop operation using the specified dock and pane +// arrays. By specifying copied dock and pane arrays when calling, a "what-if" +// scenario can be performed, giving precise coordinates for drop hints. +// If, however, wxAuiManager:m_docks and wxAuiManager::m_panes are specified +// as parameters, the changes will be made to the main state arrays + +const int auiInsertRowPixels = 10; +const int auiNewRowPixels = 40; +const int auiLayerInsertPixels = 40; +const int auiLayerInsertOffset = 5; + +bool wxAuiManager::DoDrop(wxAuiDockInfoArray& docks, + wxAuiPaneInfoArray& panes, + wxAuiPaneInfo& target, + const wxPoint& pt, + const wxPoint& offset) +{ + wxSize cli_size = m_frame->GetClientSize(); + + wxAuiPaneInfo drop = target; + + + // The result should always be shown + drop.Show(); + + + // Check to see if the pane has been dragged outside of the window + // (or near to the outside of the window), if so, dock it along the edge + + + int layer_insert_offset = auiLayerInsertOffset; + if (drop.IsToolbar()) + layer_insert_offset = 0; + + + if (pt.x < layer_insert_offset && + pt.x > layer_insert_offset-auiLayerInsertPixels) + { + int new_layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_LEFT), + GetMaxLayer(docks, wxAUI_DOCK_BOTTOM)), + GetMaxLayer(docks, wxAUI_DOCK_TOP)) + 1; + + if (drop.IsToolbar()) + new_layer = auiToolBarLayer; + + drop.Dock().Left(). + Layer(new_layer). + Row(0). + Position(pt.y - GetDockPixelOffset(drop) - offset.y); + return ProcessDockResult(target, drop); + } + else if (pt.y < layer_insert_offset && + pt.y > layer_insert_offset-auiLayerInsertPixels) + { + int new_layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_TOP), + GetMaxLayer(docks, wxAUI_DOCK_LEFT)), + GetMaxLayer(docks, wxAUI_DOCK_RIGHT)) + 1; + + if (drop.IsToolbar()) + new_layer = auiToolBarLayer; + + drop.Dock().Top(). + Layer(new_layer). + Row(0). + Position(pt.x - GetDockPixelOffset(drop) - offset.x); + return ProcessDockResult(target, drop); + } + else if (pt.x >= cli_size.x - layer_insert_offset && + pt.x < cli_size.x - layer_insert_offset + auiLayerInsertPixels) + { + int new_layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_RIGHT), + GetMaxLayer(docks, wxAUI_DOCK_TOP)), + GetMaxLayer(docks, wxAUI_DOCK_BOTTOM)) + 1; + + if (drop.IsToolbar()) + new_layer = auiToolBarLayer; + + drop.Dock().Right(). + Layer(new_layer). + Row(0). + Position(pt.y - GetDockPixelOffset(drop) - offset.y); + return ProcessDockResult(target, drop); + } + else if (pt.y >= cli_size.y - layer_insert_offset && + pt.y < cli_size.y - layer_insert_offset + auiLayerInsertPixels) + { + int new_layer = wxMax( wxMax( GetMaxLayer(docks, wxAUI_DOCK_BOTTOM), + GetMaxLayer(docks, wxAUI_DOCK_LEFT)), + GetMaxLayer(docks, wxAUI_DOCK_RIGHT)) + 1; + + if (drop.IsToolbar()) + new_layer = auiToolBarLayer; + + drop.Dock().Bottom(). + Layer(new_layer). + Row(0). + Position(pt.x - GetDockPixelOffset(drop) - offset.x); + return ProcessDockResult(target, drop); + } + + + wxAuiDockUIPart* part = HitTest(pt.x, pt.y); + + + if (drop.IsToolbar()) + { + if (!part || !part->dock) + return false; + + // calculate the offset from where the dock begins + // to the point where the user dropped the pane + int dock_drop_offset = 0; + if (part->dock->IsHorizontal()) + dock_drop_offset = pt.x - part->dock->rect.x - offset.x; + else + dock_drop_offset = pt.y - part->dock->rect.y - offset.y; + + + // toolbars may only be moved in and to fixed-pane docks, + // otherwise we will try to float the pane. Also, the pane + // should float if being dragged over center pane windows + if (!part->dock->fixed || part->dock->dock_direction == wxAUI_DOCK_CENTER) + { + if (m_last_rect.IsEmpty() || m_last_rect.Contains(pt.x, pt.y )) + { + m_skipping = true; + } + else + { + if ((m_flags & wxAUI_MGR_ALLOW_FLOATING) && + (drop.IsFloatable() || + (part->dock->dock_direction != wxAUI_DOCK_CENTER && + part->dock->dock_direction != wxAUI_DOCK_NONE))) + { + if (drop.IsFloatable()) + drop.Float(); + } + + m_skipping = false; + + return ProcessDockResult(target, drop); + } + + drop.Position(pt.x - GetDockPixelOffset(drop) - offset.x); + + return ProcessDockResult(target, drop); + } + else + { + m_skipping = false; + } + + if (!m_skipping) + { + m_last_rect = part->dock->rect; + m_last_rect.Inflate( 15, 15 ); + } + + drop.Dock(). + Direction(part->dock->dock_direction). + Layer(part->dock->dock_layer). + Row(part->dock->dock_row). + Position(dock_drop_offset); + + if (( + ((pt.y < part->dock->rect.y + 1) && part->dock->IsHorizontal()) || + ((pt.x < part->dock->rect.x + 1) && part->dock->IsVertical()) + ) && part->dock->panes.GetCount() > 1) + { + if ((part->dock->dock_direction == wxAUI_DOCK_TOP) || + (part->dock->dock_direction == wxAUI_DOCK_LEFT)) + { + int row = drop.dock_row; + DoInsertDockRow(panes, part->dock->dock_direction, + part->dock->dock_layer, + part->dock->dock_row); + drop.dock_row = row; + } + else + { + DoInsertDockRow(panes, part->dock->dock_direction, + part->dock->dock_layer, + part->dock->dock_row+1); + drop.dock_row = part->dock->dock_row+1; + } + } + + if (( + ((pt.y > part->dock->rect.y + part->dock->rect.height - 2 ) && part->dock->IsHorizontal()) || + ((pt.x > part->dock->rect.x + part->dock->rect.width - 2 ) && part->dock->IsVertical()) + ) && part->dock->panes.GetCount() > 1) + { + if ((part->dock->dock_direction == wxAUI_DOCK_TOP) || + (part->dock->dock_direction == wxAUI_DOCK_LEFT)) + { + DoInsertDockRow(panes, part->dock->dock_direction, + part->dock->dock_layer, + part->dock->dock_row+1); + drop.dock_row = part->dock->dock_row+1; + } + else + { + int row = drop.dock_row; + DoInsertDockRow(panes, part->dock->dock_direction, + part->dock->dock_layer, + part->dock->dock_row); + drop.dock_row = row; + } + } + + return ProcessDockResult(target, drop); + } + + + + + if (!part) + return false; + + if (part->type == wxAuiDockUIPart::typePaneBorder || + part->type == wxAuiDockUIPart::typeCaption || + part->type == wxAuiDockUIPart::typeGripper || + part->type == wxAuiDockUIPart::typePaneButton || + part->type == wxAuiDockUIPart::typePane || + part->type == wxAuiDockUIPart::typePaneSizer || + part->type == wxAuiDockUIPart::typeDockSizer || + part->type == wxAuiDockUIPart::typeBackground) + { + if (part->type == wxAuiDockUIPart::typeDockSizer) + { + if (part->dock->panes.GetCount() != 1) + return false; + part = GetPanePart(part->dock->panes.Item(0)->window); + if (!part) + return false; + } + + + + // If a normal frame is being dragged over a toolbar, insert it + // along the edge under the toolbar, but over all other panes. + // (this could be done much better, but somehow factoring this + // calculation with the one at the beginning of this function) + if (part->dock && part->dock->toolbar) + { + int layer = 0; + + switch (part->dock->dock_direction) + { + case wxAUI_DOCK_LEFT: + layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_LEFT), + GetMaxLayer(docks, wxAUI_DOCK_BOTTOM)), + GetMaxLayer(docks, wxAUI_DOCK_TOP)); + break; + case wxAUI_DOCK_TOP: + layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_TOP), + GetMaxLayer(docks, wxAUI_DOCK_LEFT)), + GetMaxLayer(docks, wxAUI_DOCK_RIGHT)); + break; + case wxAUI_DOCK_RIGHT: + layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_RIGHT), + GetMaxLayer(docks, wxAUI_DOCK_TOP)), + GetMaxLayer(docks, wxAUI_DOCK_BOTTOM)); + break; + case wxAUI_DOCK_BOTTOM: + layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_BOTTOM), + GetMaxLayer(docks, wxAUI_DOCK_LEFT)), + GetMaxLayer(docks, wxAUI_DOCK_RIGHT)); + break; + } + + DoInsertDockRow(panes, part->dock->dock_direction, + layer, 0); + drop.Dock(). + Direction(part->dock->dock_direction). + Layer(layer).Row(0).Position(0); + return ProcessDockResult(target, drop); + } + + + if (!part->pane) + return false; + + part = GetPanePart(part->pane->window); + if (!part) + return false; + + bool insert_dock_row = false; + int insert_row = part->pane->dock_row; + int insert_dir = part->pane->dock_direction; + int insert_layer = part->pane->dock_layer; + + switch (part->pane->dock_direction) + { + case wxAUI_DOCK_TOP: + if (pt.y >= part->rect.y && + pt.y < part->rect.y+auiInsertRowPixels) + insert_dock_row = true; + break; + case wxAUI_DOCK_BOTTOM: + if (pt.y > part->rect.y+part->rect.height-auiInsertRowPixels && + pt.y <= part->rect.y + part->rect.height) + insert_dock_row = true; + break; + case wxAUI_DOCK_LEFT: + if (pt.x >= part->rect.x && + pt.x < part->rect.x+auiInsertRowPixels) + insert_dock_row = true; + break; + case wxAUI_DOCK_RIGHT: + if (pt.x > part->rect.x+part->rect.width-auiInsertRowPixels && + pt.x <= part->rect.x+part->rect.width) + insert_dock_row = true; + break; + case wxAUI_DOCK_CENTER: + { + // "new row pixels" will be set to the default, but + // must never exceed 20% of the window size + int new_row_pixels_x = auiNewRowPixels; + int new_row_pixels_y = auiNewRowPixels; + + if (new_row_pixels_x > (part->rect.width*20)/100) + new_row_pixels_x = (part->rect.width*20)/100; + + if (new_row_pixels_y > (part->rect.height*20)/100) + new_row_pixels_y = (part->rect.height*20)/100; + + + // determine if the mouse pointer is in a location that + // will cause a new row to be inserted. The hot spot positions + // are along the borders of the center pane + + insert_layer = 0; + insert_dock_row = true; + if (pt.x >= part->rect.x && + pt.x < part->rect.x+new_row_pixels_x) + insert_dir = wxAUI_DOCK_LEFT; + else + if (pt.y >= part->rect.y && + pt.y < part->rect.y+new_row_pixels_y) + insert_dir = wxAUI_DOCK_TOP; + else + if (pt.x >= part->rect.x + part->rect.width-new_row_pixels_x && + pt.x < part->rect.x + part->rect.width) + insert_dir = wxAUI_DOCK_RIGHT; + else + if (pt.y >= part->rect.y+ part->rect.height-new_row_pixels_y && + pt.y < part->rect.y + part->rect.height) + insert_dir = wxAUI_DOCK_BOTTOM; + else + return false; + + insert_row = GetMaxRow(panes, insert_dir, insert_layer) + 1; + } + } + + if (insert_dock_row) + { + DoInsertDockRow(panes, insert_dir, insert_layer, insert_row); + drop.Dock().Direction(insert_dir). + Layer(insert_layer). + Row(insert_row). + Position(0); + return ProcessDockResult(target, drop); + } + + // determine the mouse offset and the pane size, both in the + // direction of the dock itself, and perpendicular to the dock + + int offset, size; + + if (part->orientation == wxVERTICAL) + { + offset = pt.y - part->rect.y; + size = part->rect.GetHeight(); + } + else + { + offset = pt.x - part->rect.x; + size = part->rect.GetWidth(); + } + + int drop_position = part->pane->dock_pos; + + // if we are in the top/left part of the pane, + // insert the pane before the pane being hovered over + if (offset <= size/2) + { + drop_position = part->pane->dock_pos; + DoInsertPane(panes, + part->pane->dock_direction, + part->pane->dock_layer, + part->pane->dock_row, + part->pane->dock_pos); + } + + // if we are in the bottom/right part of the pane, + // insert the pane before the pane being hovered over + if (offset > size/2) + { + drop_position = part->pane->dock_pos+1; + DoInsertPane(panes, + part->pane->dock_direction, + part->pane->dock_layer, + part->pane->dock_row, + part->pane->dock_pos+1); + } + + drop.Dock(). + Direction(part->dock->dock_direction). + Layer(part->dock->dock_layer). + Row(part->dock->dock_row). + Position(drop_position); + return ProcessDockResult(target, drop); + } + + return false; +} + + +void wxAuiManager::OnHintFadeTimer(wxTimerEvent& WXUNUSED(event)) +{ + if (!m_hint_wnd || m_hint_fadeamt >= m_hint_fademax) + { + m_hint_fadetimer.Stop(); + return; + } + + m_hint_fadeamt += 4; + m_hint_wnd->SetTransparent(m_hint_fadeamt); +} + +void wxAuiManager::ShowHint(const wxRect& rect) +{ + if (m_hint_wnd) + { + // if the hint rect is the same as last time, don't do anything + if (m_last_hint == rect) + return; + m_last_hint = rect; + + m_hint_fadeamt = m_hint_fademax; + + if ((m_flags & wxAUI_MGR_HINT_FADE) + && !((m_hint_wnd->IsKindOf(CLASSINFO(wxPseudoTransparentFrame))) && + (m_flags & wxAUI_MGR_NO_VENETIAN_BLINDS_FADE)) + ) + m_hint_fadeamt = 0; + + m_hint_wnd->SetSize(rect); + m_hint_wnd->SetTransparent(m_hint_fadeamt); + + if (!m_hint_wnd->IsShown()) + m_hint_wnd->Show(); + + // if we are dragging a floating pane, set the focus + // back to that floating pane (otherwise it becomes unfocused) + if (m_action == actionDragFloatingPane && m_action_window) + m_action_window->SetFocus(); + + m_hint_wnd->Raise(); + + + if (m_hint_fadeamt != m_hint_fademax) // Only fade if we need to + { + // start fade in timer + m_hint_fadetimer.SetOwner(this, 101); + m_hint_fadetimer.Start(5); + } + } + else // Not using a transparent hint window... + { + if (!(m_flags & wxAUI_MGR_RECTANGLE_HINT)) + return; + + if (m_last_hint != rect) + { + // remove the last hint rectangle + m_last_hint = rect; + m_frame->Refresh(); + m_frame->Update(); + } + + wxScreenDC screendc; + wxRegion clip(1, 1, 10000, 10000); + + // clip all floating windows, so we don't draw over them + int i, pane_count; + for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i) + { + wxAuiPaneInfo& pane = m_panes.Item(i); + + if (pane.IsFloating() && + pane.frame->IsShown()) + { + wxRect rect = pane.frame->GetRect(); +#ifdef __WXGTK__ + // wxGTK returns the client size, not the whole frame size + rect.width += 15; + rect.height += 35; + rect.Inflate(5); +#endif + + clip.Subtract(rect); + } + } + + // As we can only hide the hint by redrawing the managed window, we + // need to clip the region to the managed window too or we get + // nasty redrawn problems. + clip.Intersect(m_frame->GetRect()); + + screendc.SetClippingRegion(clip); + + wxBitmap stipple = wxPaneCreateStippleBitmap(); + wxBrush brush(stipple); + screendc.SetBrush(brush); + screendc.SetPen(*wxTRANSPARENT_PEN); + + screendc.DrawRectangle(rect.x, rect.y, 5, rect.height); + screendc.DrawRectangle(rect.x+5, rect.y, rect.width-10, 5); + screendc.DrawRectangle(rect.x+rect.width-5, rect.y, 5, rect.height); + screendc.DrawRectangle(rect.x+5, rect.y+rect.height-5, rect.width-10, 5); + } +} + +void wxAuiManager::HideHint() +{ + // hides a transparent window hint, if there is one + if (m_hint_wnd) + { + if (m_hint_wnd->IsShown()) + m_hint_wnd->Show(false); + m_hint_wnd->SetTransparent(0); + m_hint_fadetimer.Stop(); + m_last_hint = wxRect(); + return; + } + + // hides a painted hint by redrawing the frame window + if (!m_last_hint.IsEmpty()) + { + m_frame->Refresh(); + m_frame->Update(); + m_last_hint = wxRect(); + } +} + + + +void wxAuiManager::StartPaneDrag(wxWindow* pane_window, + const wxPoint& offset) +{ + wxAuiPaneInfo& pane = GetPane(pane_window); + if (!pane.IsOk()) + return; + + if (pane.IsToolbar()) + { + m_action = actionDragToolbarPane; + } + else + { + m_action = actionDragFloatingPane; + } + + m_action_window = pane_window; + m_action_offset = offset; + m_frame->CaptureMouse(); +} + + +// CalculateHintRect() calculates the drop hint rectangle. The method +// first calls DoDrop() to determine the exact position the pane would +// be at were if dropped. If the pane would indeed become docked at the +// specified drop point, the the rectangle hint will be returned in +// screen coordinates. Otherwise, an empty rectangle is returned. +// |pane_window| is the window pointer of the pane being dragged, |pt| is +// the mouse position, in client coordinates. |offset| describes the offset +// that the mouse is from the upper-left corner of the item being dragged + +wxRect wxAuiManager::CalculateHintRect(wxWindow* pane_window, + const wxPoint& pt, + const wxPoint& offset) +{ + wxRect rect; + + // we need to paint a hint rectangle; to find out the exact hint rectangle, + // we will create a new temporary layout and then measure the resulting + // rectangle; we will create a copy of the docking structures (m_dock) + // so that we don't modify the real thing on screen + + int i, pane_count, part_count; + wxAuiDockInfoArray docks; + wxAuiPaneInfoArray panes; + wxAuiDockUIPartArray uiparts; + wxAuiPaneInfo hint = GetPane(pane_window); + hint.name = wxT("__HINT__"); + hint.PaneBorder(true); + hint.Show(); + + if (!hint.IsOk()) + return rect; + + CopyDocksAndPanes(docks, panes, m_docks, m_panes); + + // remove any pane already there which bears the same window; + // this happens when you are moving a pane around in a dock + for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i) + { + if (panes.Item(i).window == pane_window) + { + RemovePaneFromDocks(docks, panes.Item(i)); + panes.RemoveAt(i); + break; + } + } + + // find out where the new pane would be + if (!DoDrop(docks, panes, hint, pt, offset)) + { + return rect; + } + + panes.Add(hint); + + wxSizer* sizer = LayoutAll(panes, docks, uiparts, true); + wxSize client_size = m_frame->GetClientSize(); + sizer->SetDimension(0, 0, client_size.x, client_size.y); + sizer->Layout(); + + for (i = 0, part_count = uiparts.GetCount(); + i < part_count; ++i) + { + wxAuiDockUIPart& part = uiparts.Item(i); + + if (part.type == wxAuiDockUIPart::typePaneBorder && + part.pane && part.pane->name == wxT("__HINT__")) + { + rect = wxRect(part.sizer_item->GetPosition(), + part.sizer_item->GetSize()); + break; + } + } + + delete sizer; + + if (rect.IsEmpty()) + { + return rect; + } + + // actually show the hint rectangle on the screen + m_frame->ClientToScreen(&rect.x, &rect.y); + + if ( m_frame->GetLayoutDirection() == wxLayout_RightToLeft ) + { + // Mirror rectangle in RTL mode + rect.x -= rect.GetWidth(); + } + + return rect; +} + +// DrawHintRect() calculates the hint rectangle by calling +// CalculateHintRect(). If there is a rectangle, it shows it +// by calling ShowHint(), otherwise it hides any hint +// rectangle currently shown +void wxAuiManager::DrawHintRect(wxWindow* pane_window, + const wxPoint& pt, + const wxPoint& offset) +{ + wxRect rect = CalculateHintRect(pane_window, pt, offset); + + if (rect.IsEmpty()) + { + HideHint(); + } + else + { + ShowHint(rect); + } +} + +void wxAuiManager::OnFloatingPaneMoveStart(wxWindow* wnd) +{ + // try to find the pane + wxAuiPaneInfo& pane = GetPane(wnd); + wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found")); + + if (m_flags & wxAUI_MGR_TRANSPARENT_DRAG) + pane.frame->SetTransparent(150); +} + +void wxAuiManager::OnFloatingPaneMoving(wxWindow* wnd, wxDirection dir) +{ + // try to find the pane + wxAuiPaneInfo& pane = GetPane(wnd); + wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found")); + + if(!pane.frame) + return; + + wxPoint pt = ::wxGetMousePosition(); + +#if 0 + // Adapt pt to direction + if (dir == wxNORTH) + { + // move to pane's upper border + wxPoint pos( 0,0 ); + pos = wnd->ClientToScreen( pos ); + pt.y = pos.y; + // and some more pixels for the title bar + pt.y -= 5; + } else + if (dir == wxWEST) + { + // move to pane's left border + wxPoint pos( 0,0 ); + pos = wnd->ClientToScreen( pos ); + pt.x = pos.x; + } else + if (dir == wxEAST) + { + // move to pane's right border + wxPoint pos( wnd->GetSize().x, 0 ); + pos = wnd->ClientToScreen( pos ); + pt.x = pos.x; + } else + if (dir == wxSOUTH) + { + // move to pane's bottom border + wxPoint pos( 0, wnd->GetSize().y ); + pos = wnd->ClientToScreen( pos ); + pt.y = pos.y; + } +#else + wxUnusedVar(dir); +#endif + + wxPoint client_pt = m_frame->ScreenToClient(pt); + + // calculate the offset from the upper left-hand corner + // of the frame to the mouse pointer + wxPoint frame_pos = pane.frame->GetPosition(); + wxPoint action_offset(pt.x-frame_pos.x, pt.y-frame_pos.y); + + // no hint for toolbar floating windows + if (pane.IsToolbar() && m_action == actionDragFloatingPane) + { + if (m_action == actionDragFloatingPane) + { + wxAuiDockInfoArray docks; + wxAuiPaneInfoArray panes; + wxAuiDockUIPartArray uiparts; + wxAuiPaneInfo hint = pane; + + CopyDocksAndPanes(docks, panes, m_docks, m_panes); + + // find out where the new pane would be + if (!DoDrop(docks, panes, hint, client_pt)) + return; + if (hint.IsFloating()) + return; + + pane = hint; + m_action = actionDragToolbarPane; + m_action_window = pane.window; + + Update(); + } + + return; + } + + + // if a key modifier is pressed while dragging the frame, + // don't dock the window + if (wxGetKeyState(WXK_CONTROL) || wxGetKeyState(WXK_ALT)) + { + HideHint(); + return; + } + + + DrawHintRect(wnd, client_pt, action_offset); + +#ifdef __WXGTK__ + // this cleans up some screen artifacts that are caused on GTK because + // we aren't getting the exact size of the window (see comment + // in DrawHintRect) + //Refresh(); +#endif + + + // reduces flicker + m_frame->Update(); +} + +void wxAuiManager::OnFloatingPaneMoved(wxWindow* wnd, wxDirection dir) +{ + // try to find the pane + wxAuiPaneInfo& pane = GetPane(wnd); + wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found")); + + if(!pane.frame) + return; + + wxPoint pt = ::wxGetMousePosition(); + +#if 0 + // Adapt pt to direction + if (dir == wxNORTH) + { + // move to pane's upper border + wxPoint pos( 0,0 ); + pos = wnd->ClientToScreen( pos ); + pt.y = pos.y; + // and some more pixels for the title bar + pt.y -= 10; + } else + if (dir == wxWEST) + { + // move to pane's left border + wxPoint pos( 0,0 ); + pos = wnd->ClientToScreen( pos ); + pt.x = pos.x; + } else + if (dir == wxEAST) + { + // move to pane's right border + wxPoint pos( wnd->GetSize().x, 0 ); + pos = wnd->ClientToScreen( pos ); + pt.x = pos.x; + } else + if (dir == wxSOUTH) + { + // move to pane's bottom border + wxPoint pos( 0, wnd->GetSize().y ); + pos = wnd->ClientToScreen( pos ); + pt.y = pos.y; + } +#else + wxUnusedVar(dir); +#endif + + wxPoint client_pt = m_frame->ScreenToClient(pt); + + // calculate the offset from the upper left-hand corner + // of the frame to the mouse pointer + wxPoint frame_pos = pane.frame->GetPosition(); + wxPoint action_offset(pt.x-frame_pos.x, pt.y-frame_pos.y); + + // if a key modifier is pressed while dragging the frame, + // don't dock the window + if (!wxGetKeyState(WXK_CONTROL) && !wxGetKeyState(WXK_ALT)) + { + // do the drop calculation + DoDrop(m_docks, m_panes, pane, client_pt, action_offset); + } + + // if the pane is still floating, update it's floating + // position (that we store) + if (pane.IsFloating()) + { + pane.floating_pos = pane.frame->GetPosition(); + + if (m_flags & wxAUI_MGR_TRANSPARENT_DRAG) + pane.frame->SetTransparent(255); + } + else if (m_has_maximized) + { + RestoreMaximizedPane(); + } + + Update(); + + HideHint(); +} + +void wxAuiManager::OnFloatingPaneResized(wxWindow* wnd, const wxSize& size) +{ + // try to find the pane + wxAuiPaneInfo& pane = GetPane(wnd); + wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found")); + + pane.floating_size = size; +} + + +void wxAuiManager::OnFloatingPaneClosed(wxWindow* wnd, wxCloseEvent& evt) +{ + // try to find the pane + wxAuiPaneInfo& pane = GetPane(wnd); + wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found")); + + + // fire pane close event + wxAuiManagerEvent e(wxEVT_AUI_PANE_CLOSE); + e.SetPane(&pane); + e.SetCanVeto(evt.CanVeto()); + ProcessMgrEvent(e); + + if (e.GetVeto()) + { + evt.Veto(); + return; + } + else + { + // close the pane, but check that it + // still exists in our pane array first + // (the event handler above might have removed it) + + wxAuiPaneInfo& check = GetPane(wnd); + if (check.IsOk()) + { + ClosePane(pane); + } + } +} + + + +void wxAuiManager::OnFloatingPaneActivated(wxWindow* wnd) +{ + if ((GetFlags() & wxAUI_MGR_ALLOW_ACTIVE_PANE) && GetPane(wnd).IsOk()) + { + SetActivePane(m_panes, wnd); + Repaint(); + } +} + +// OnRender() draws all of the pane captions, sashes, +// backgrounds, captions, grippers, pane borders and buttons. +// It renders the entire user interface. + +void wxAuiManager::OnRender(wxAuiManagerEvent& evt) +{ + // if the frame is about to be deleted, don't bother + if (!m_frame || wxPendingDelete.Member(m_frame)) + return; + + wxDC* dc = evt.GetDC(); + +#ifdef __WXMAC__ + dc->Clear() ; +#endif + int i, part_count; + for (i = 0, part_count = m_uiparts.GetCount(); + i < part_count; ++i) + { + wxAuiDockUIPart& part = m_uiparts.Item(i); + + // don't draw hidden pane items or items that aren't windows + if (part.sizer_item && ((!part.sizer_item->IsWindow() && !part.sizer_item->IsSpacer() && !part.sizer_item->IsSizer()) || !part.sizer_item->IsShown())) + continue; + + switch (part.type) + { + case wxAuiDockUIPart::typeDockSizer: + case wxAuiDockUIPart::typePaneSizer: + m_art->DrawSash(*dc, m_frame, part.orientation, part.rect); + break; + case wxAuiDockUIPart::typeBackground: + m_art->DrawBackground(*dc, m_frame, part.orientation, part.rect); + break; + case wxAuiDockUIPart::typeCaption: + m_art->DrawCaption(*dc, m_frame, part.pane->caption, part.rect, *part.pane); + break; + case wxAuiDockUIPart::typeGripper: + m_art->DrawGripper(*dc, m_frame, part.rect, *part.pane); + break; + case wxAuiDockUIPart::typePaneBorder: + m_art->DrawBorder(*dc, m_frame, part.rect, *part.pane); + break; + case wxAuiDockUIPart::typePaneButton: + m_art->DrawPaneButton(*dc, m_frame, part.button->button_id, + wxAUI_BUTTON_STATE_NORMAL, part.rect, *part.pane); + break; + } + } +} + + +// Render() fire a render event, which is normally handled by +// wxAuiManager::OnRender(). This allows the render function to +// be overridden via the render event. This can be useful for paintin +// custom graphics in the main window. Default behavior can be +// invoked in the overridden function by calling OnRender() + +void wxAuiManager::Render(wxDC* dc) +{ + wxAuiManagerEvent e(wxEVT_AUI_RENDER); + e.SetManager(this); + e.SetDC(dc); + ProcessMgrEvent(e); +} + +void wxAuiManager::Repaint(wxDC* dc) +{ +#ifdef __WXMAC__ + if ( dc == NULL ) + { + m_frame->Refresh() ; + m_frame->Update() ; + return ; + } +#endif + int w, h; + m_frame->GetClientSize(&w, &h); + + // figure out which dc to use; if one + // has been specified, use it, otherwise + // make a client dc + wxClientDC* client_dc = NULL; + if (!dc) + { + client_dc = new wxClientDC(m_frame); + dc = client_dc; + } + + // if the frame has a toolbar, the client area + // origin will not be (0,0). + wxPoint pt = m_frame->GetClientAreaOrigin(); + if (pt.x != 0 || pt.y != 0) + dc->SetDeviceOrigin(pt.x, pt.y); + + // render all the items + Render(dc); + + // if we created a client_dc, delete it + if (client_dc) + delete client_dc; +} + +void wxAuiManager::OnPaint(wxPaintEvent& WXUNUSED(event)) +{ + wxPaintDC dc(m_frame); + Repaint(&dc); +} + +void wxAuiManager::OnEraseBackground(wxEraseEvent& event) +{ +#ifdef __WXMAC__ + event.Skip() ; +#else + wxUnusedVar(event); +#endif +} + +void wxAuiManager::OnSize(wxSizeEvent& event) +{ + if (m_frame) + { + DoFrameLayout(); + Repaint(); + +#if wxUSE_MDI + if (m_frame->IsKindOf(CLASSINFO(wxMDIParentFrame))) + { + // for MDI parent frames, this event must not + // be "skipped". In other words, the parent frame + // must not be allowed to resize the client window + // after we are finished processing sizing changes + return; + } +#endif + } + event.Skip(); +} + +void wxAuiManager::OnFindManager(wxAuiManagerEvent& evt) +{ + // get the window we are managing, if none, return NULL + wxWindow* window = GetManagedWindow(); + if (!window) + { + evt.SetManager(NULL); + return; + } + + // if we are managing a child frame, get the 'real' manager + if (window->IsKindOf(CLASSINFO(wxAuiFloatingFrame))) + { + wxAuiFloatingFrame* float_frame = wx_static_cast(wxAuiFloatingFrame*, window); + evt.SetManager(float_frame->GetOwnerManager()); + return; + } + + // return pointer to ourself + evt.SetManager(this); +} + +void wxAuiManager::OnSetCursor(wxSetCursorEvent& event) +{ + // determine cursor + wxAuiDockUIPart* part = HitTest(event.GetX(), event.GetY()); + wxCursor cursor = wxNullCursor; + + if (part) + { + if (part->type == wxAuiDockUIPart::typeDockSizer || + part->type == wxAuiDockUIPart::typePaneSizer) + { + // a dock may not be resized if it has a single + // pane which is not resizable + if (part->type == wxAuiDockUIPart::typeDockSizer && part->dock && + part->dock->panes.GetCount() == 1 && + part->dock->panes.Item(0)->IsFixed()) + return; + + // panes that may not be resized do not get a sizing cursor + if (part->pane && part->pane->IsFixed()) + return; + + if (part->orientation == wxVERTICAL) + cursor = wxCursor(wxCURSOR_SIZEWE); + else + cursor = wxCursor(wxCURSOR_SIZENS); + } + else if (part->type == wxAuiDockUIPart::typeGripper) + { + cursor = wxCursor(wxCURSOR_SIZING); + } + } + + event.SetCursor(cursor); +} + + + +void wxAuiManager::UpdateButtonOnScreen(wxAuiDockUIPart* button_ui_part, + const wxMouseEvent& event) +{ + wxAuiDockUIPart* hit_test = HitTest(event.GetX(), event.GetY()); + if (!hit_test || !button_ui_part) + return; + + int state = wxAUI_BUTTON_STATE_NORMAL; + + if (hit_test == button_ui_part) + { + if (event.LeftDown()) + state = wxAUI_BUTTON_STATE_PRESSED; + else + state = wxAUI_BUTTON_STATE_HOVER; + } + else + { + if (event.LeftDown()) + state = wxAUI_BUTTON_STATE_HOVER; + } + + // now repaint the button with hover state + wxClientDC cdc(m_frame); + + // if the frame has a toolbar, the client area + // origin will not be (0,0). + wxPoint pt = m_frame->GetClientAreaOrigin(); + if (pt.x != 0 || pt.y != 0) + cdc.SetDeviceOrigin(pt.x, pt.y); + + if (hit_test->pane) + { + m_art->DrawPaneButton(cdc, m_frame, + button_ui_part->button->button_id, + state, + button_ui_part->rect, + *hit_test->pane); + } +} + +static int gs_CurrentDragItem = -1; + +void wxAuiManager::OnLeftDown(wxMouseEvent& event) +{ + gs_CurrentDragItem = -1; + wxAuiDockUIPart* part = HitTest(event.GetX(), event.GetY()); + if (part) + { + if (part->type == wxAuiDockUIPart::typeDockSizer || + part->type == wxAuiDockUIPart::typePaneSizer) + { + // Removing this restriction so that a centre pane can be resized + //if (part->dock && part->dock->dock_direction == wxAUI_DOCK_CENTER) + // return; + + // a dock may not be resized if it has a single + // pane which is not resizable + if (part->type == wxAuiDockUIPart::typeDockSizer && part->dock && + part->dock->panes.GetCount() == 1 && + part->dock->panes.Item(0)->IsFixed()) + return; + + // panes that may not be resized should be ignored here + if (part->pane && part->pane->IsFixed()) + return; + + m_action = actionResize; + m_action_part = part; + m_action_hintrect = wxRect(); + m_action_start = wxPoint(event.m_x, event.m_y); + m_action_offset = wxPoint(event.m_x - part->rect.x, + event.m_y - part->rect.y); + m_frame->CaptureMouse(); + } + else if (part->type == wxAuiDockUIPart::typePaneButton) + { + m_action = actionClickButton; + m_action_part = part; + m_action_start = wxPoint(event.m_x, event.m_y); + m_frame->CaptureMouse(); + + UpdateButtonOnScreen(part, event); + } + else if (part->type == wxAuiDockUIPart::typeCaption || + part->type == wxAuiDockUIPart::typeGripper) + { + // if we are managing a wxAuiFloatingFrame window, then + // we are an embedded wxAuiManager inside the wxAuiFloatingFrame. + // We want to initiate a toolbar drag in our owner manager + wxWindow* managed_wnd = GetManagedWindow(); + + if (part->pane && + part->pane->window && + managed_wnd && + managed_wnd->IsKindOf(CLASSINFO(wxAuiFloatingFrame))) + { + wxAuiFloatingFrame* floating_frame = (wxAuiFloatingFrame*)managed_wnd; + wxAuiManager* owner_mgr = floating_frame->GetOwnerManager(); + owner_mgr->StartPaneDrag(part->pane->window, + wxPoint(event.m_x - part->rect.x, + event.m_y - part->rect.y)); + return; + } + + if (GetFlags() & wxAUI_MGR_ALLOW_ACTIVE_PANE) + { + // set the caption as active + SetActivePane(m_panes, part->pane->window); + Repaint(); + } + + if (part->dock && part->dock->dock_direction == wxAUI_DOCK_CENTER) + return; + + m_action = actionClickCaption; + m_action_part = part; + m_action_start = wxPoint(event.m_x, event.m_y); + m_action_offset = wxPoint(event.m_x - part->rect.x, + event.m_y - part->rect.y); + m_frame->CaptureMouse(); + } +#ifdef __WXMAC__ + else + { + event.Skip(); + } +#endif + } +#ifdef __WXMAC__ + else + { + event.Skip(); + } +#else + event.Skip(); +#endif +} + +/// Ends a resize action, or for live update, resizes the sash +bool wxAuiManager::DoEndResizeAction(wxMouseEvent& event) +{ + // resize the dock or the pane + if (m_action_part && m_action_part->type==wxAuiDockUIPart::typeDockSizer) + { + wxRect& rect = m_action_part->dock->rect; + + wxPoint new_pos(event.m_x - m_action_offset.x, + event.m_y - m_action_offset.y); + + switch (m_action_part->dock->dock_direction) + { + case wxAUI_DOCK_LEFT: + m_action_part->dock->size = new_pos.x - rect.x; + break; + case wxAUI_DOCK_TOP: + m_action_part->dock->size = new_pos.y - rect.y; + break; + case wxAUI_DOCK_RIGHT: + m_action_part->dock->size = rect.x + rect.width - + new_pos.x - m_action_part->rect.GetWidth(); + break; + case wxAUI_DOCK_BOTTOM: + m_action_part->dock->size = rect.y + rect.height - + new_pos.y - m_action_part->rect.GetHeight(); + break; + } + + Update(); + Repaint(NULL); + } + else if (m_action_part && + m_action_part->type == wxAuiDockUIPart::typePaneSizer) + { + wxAuiDockInfo& dock = *m_action_part->dock; + wxAuiPaneInfo& pane = *m_action_part->pane; + + int total_proportion = 0; + int dock_pixels = 0; + int new_pixsize = 0; + + int caption_size = m_art->GetMetric(wxAUI_DOCKART_CAPTION_SIZE); + int pane_border_size = m_art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE); + int sash_size = m_art->GetMetric(wxAUI_DOCKART_SASH_SIZE); + + wxPoint new_pos(event.m_x - m_action_offset.x, + event.m_y - m_action_offset.y); + + // determine the pane rectangle by getting the pane part + wxAuiDockUIPart* pane_part = GetPanePart(pane.window); + wxASSERT_MSG(pane_part, + wxT("Pane border part not found -- shouldn't happen")); + + // determine the new pixel size that the user wants; + // this will help us recalculate the pane's proportion + if (dock.IsHorizontal()) + new_pixsize = new_pos.x - pane_part->rect.x; + else + new_pixsize = new_pos.y - pane_part->rect.y; + + // determine the size of the dock, based on orientation + if (dock.IsHorizontal()) + dock_pixels = dock.rect.GetWidth(); + else + dock_pixels = dock.rect.GetHeight(); + + // determine the total proportion of all resizable panes, + // and the total size of the dock minus the size of all + // the fixed panes + int i, dock_pane_count = dock.panes.GetCount(); + int pane_position = -1; + for (i = 0; i < dock_pane_count; ++i) + { + wxAuiPaneInfo& p = *dock.panes.Item(i); + if (p.window == pane.window) + pane_position = i; + + // while we're at it, subtract the pane sash + // width from the dock width, because this would + // skew our proportion calculations + if (i > 0) + dock_pixels -= sash_size; + + // also, the whole size (including decorations) of + // all fixed panes must also be subtracted, because they + // are not part of the proportion calculation + if (p.IsFixed()) + { + if (dock.IsHorizontal()) + dock_pixels -= p.best_size.x; + else + dock_pixels -= p.best_size.y; + } + else + { + total_proportion += p.dock_proportion; + } + } + + // find a pane in our dock to 'steal' space from or to 'give' + // space to -- this is essentially what is done when a pane is + // resized; the pane should usually be the first non-fixed pane + // to the right of the action pane + int borrow_pane = -1; + for (i = pane_position+1; i < dock_pane_count; ++i) + { + wxAuiPaneInfo& p = *dock.panes.Item(i); + if (!p.IsFixed()) + { + borrow_pane = i; + break; + } + } + + + // demand that the pane being resized is found in this dock + // (this assert really never should be raised) + wxASSERT_MSG(pane_position != -1, wxT("Pane not found in dock")); + + // prevent division by zero + if (dock_pixels == 0 || total_proportion == 0 || borrow_pane == -1) + { + m_action = actionNone; + return false; + } + + // calculate the new proportion of the pane + int new_proportion = (new_pixsize*total_proportion)/dock_pixels; + + // default minimum size + int min_size = 0; + + // check against the pane's minimum size, if specified. please note + // that this is not enough to ensure that the minimum size will + // not be violated, because the whole frame might later be shrunk, + // causing the size of the pane to violate it's minimum size + if (pane.min_size.IsFullySpecified()) + { + min_size = 0; + + if (pane.HasBorder()) + min_size += (pane_border_size*2); + + // calculate minimum size with decorations (border,caption) + if (pane_part->orientation == wxVERTICAL) + { + min_size += pane.min_size.y; + if (pane.HasCaption()) + min_size += caption_size; + } + else + { + min_size += pane.min_size.x; + } + } + + + // for some reason, an arithmatic error somewhere is causing + // the proportion calculations to always be off by 1 pixel; + // for now we will add the 1 pixel on, but we really should + // determine what's causing this. + min_size++; + + int min_proportion = (min_size*total_proportion)/dock_pixels; + + if (new_proportion < min_proportion) + new_proportion = min_proportion; + + + + int prop_diff = new_proportion - pane.dock_proportion; + + // borrow the space from our neighbor pane to the + // right or bottom (depending on orientation) + dock.panes.Item(borrow_pane)->dock_proportion -= prop_diff; + pane.dock_proportion = new_proportion; + + // repaint + Update(); + Repaint(NULL); + } + + return true; +} + +void wxAuiManager::OnLeftUp(wxMouseEvent& event) +{ + if (m_action == actionResize) + { + m_frame->ReleaseMouse(); + + // get rid of the hint rectangle + + // On non-CG Mac we use a wxClientDC since when compiling and running on Leopard, + // we can get the dreaded _SetDstBlits32BGRA crash (but not in the AUI sample). + // In CG mode we always use live resize since DrawResizeHint doesn't work. + if (!wxAuiManager_HasLiveResize(*this)) + { + // get rid of the hint rectangle +#if defined(__WXMAC__) && !wxMAC_USE_CORE_GRAPHICS + wxClientDC dc(m_frame); +#else + wxScreenDC dc; +#endif + DrawResizeHint(dc, m_action_hintrect); + } + if (gs_CurrentDragItem != -1 && wxAuiManager_HasLiveResize(*this)) + m_action_part = & (m_uiparts.Item(gs_CurrentDragItem)); + + DoEndResizeAction(event); + + gs_CurrentDragItem = -1; + } + else if (m_action == actionClickButton) + { + m_hover_button = NULL; + m_frame->ReleaseMouse(); + + if (m_action_part) + { + UpdateButtonOnScreen(m_action_part, event); + + // make sure we're still over the item that was originally clicked + if (m_action_part == HitTest(event.GetX(), event.GetY())) + { + // fire button-click event + wxAuiManagerEvent e(wxEVT_AUI_PANE_BUTTON); + e.SetManager(this); + e.SetPane(m_action_part->pane); + e.SetButton(m_action_part->button->button_id); + ProcessMgrEvent(e); + } + } + } + else if (m_action == actionClickCaption) + { + m_frame->ReleaseMouse(); + } + else if (m_action == actionDragFloatingPane) + { + m_frame->ReleaseMouse(); + } + else if (m_action == actionDragToolbarPane) + { + m_frame->ReleaseMouse(); + + wxAuiPaneInfo& pane = GetPane(m_action_window); + wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found")); + + // save the new positions + wxAuiDockInfoPtrArray docks; + FindDocks(m_docks, pane.dock_direction, + pane.dock_layer, pane.dock_row, docks); + if (docks.GetCount() == 1) + { + wxAuiDockInfo& dock = *docks.Item(0); + + wxArrayInt pane_positions, pane_sizes; + GetPanePositionsAndSizes(dock, pane_positions, pane_sizes); + + int i, dock_pane_count = dock.panes.GetCount(); + for (i = 0; i < dock_pane_count; ++i) + dock.panes.Item(i)->dock_pos = pane_positions[i]; + } + + pane.state &= ~wxAuiPaneInfo::actionPane; + Update(); + } + else + { + event.Skip(); + } + + m_action = actionNone; + m_last_mouse_move = wxPoint(); // see comment in OnMotion() +} + + +void wxAuiManager::OnMotion(wxMouseEvent& event) +{ + // sometimes when Update() is called from inside this method, + // a spurious mouse move event is generated; this check will make + // sure that only real mouse moves will get anywhere in this method; + // this appears to be a bug somewhere, and I don't know where the + // mouse move event is being generated. only verified on MSW + + wxPoint mouse_pos = event.GetPosition(); + if (m_last_mouse_move == mouse_pos) + return; + m_last_mouse_move = mouse_pos; + + + if (m_action == actionResize) + { + // It's necessary to reset m_action_part since it destroyed + // by the Update within DoEndResizeAction. + if (gs_CurrentDragItem != -1) + m_action_part = & (m_uiparts.Item(gs_CurrentDragItem)); + else + gs_CurrentDragItem = m_uiparts.Index(* m_action_part); + + if (m_action_part) + { + wxPoint pos = m_action_part->rect.GetPosition(); + if (m_action_part->orientation == wxHORIZONTAL) + pos.y = wxMax(0, event.m_y - m_action_offset.y); + else + pos.x = wxMax(0, event.m_x - m_action_offset.x); + + if (wxAuiManager_HasLiveResize(*this)) + { + + m_frame->ReleaseMouse(); + DoEndResizeAction(event); + m_frame->CaptureMouse(); + } + else + { +#if defined(__WXMAC__) && !wxMAC_USE_CORE_GRAPHICS + wxRect rect(pos, + m_action_part->rect.GetSize()); + + wxClientDC dc(m_frame); +#else + wxRect rect(m_frame->ClientToScreen(pos), + m_action_part->rect.GetSize()); + wxScreenDC dc; +#endif + if (!m_action_hintrect.IsEmpty()) + DrawResizeHint(dc, m_action_hintrect); + DrawResizeHint(dc, rect); + m_action_hintrect = rect; + } + } + } + else if (m_action == actionClickCaption) + { + int drag_x_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_X); + int drag_y_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_Y); + + // caption has been clicked. we need to check if the mouse + // is now being dragged. if it is, we need to change the + // mouse action to 'drag' + if (m_action_part && + (abs(event.m_x - m_action_start.x) > drag_x_threshold || + abs(event.m_y - m_action_start.y) > drag_y_threshold)) + { + wxAuiPaneInfo* pane_info = m_action_part->pane; + + if (!pane_info->IsToolbar()) + { + if ((m_flags & wxAUI_MGR_ALLOW_FLOATING) && + pane_info->IsFloatable()) + { + m_action = actionDragFloatingPane; + + // set initial float position + wxPoint pt = m_frame->ClientToScreen(event.GetPosition()); + pane_info->floating_pos = wxPoint(pt.x - m_action_offset.x, + pt.y - m_action_offset.y); + + // float the window + if (pane_info->IsMaximized()) + RestorePane(*pane_info); + pane_info->Float(); + Update(); + + m_action_window = pane_info->frame; + + // action offset is used here to make it feel "natural" to the user + // to drag a docked pane and suddenly have it become a floating frame. + // Sometimes, however, the offset where the user clicked on the docked + // caption is bigger than the width of the floating frame itself, so + // in that case we need to set the action offset to a sensible value + wxSize frame_size = m_action_window->GetSize(); + if (frame_size.x <= m_action_offset.x) + m_action_offset.x = 30; + } + } + else + { + m_action = actionDragToolbarPane; + m_action_window = pane_info->window; + } + } + } + else if (m_action == actionDragFloatingPane) + { + if (m_action_window) + { + wxPoint pt = m_frame->ClientToScreen(event.GetPosition()); + m_action_window->Move(pt.x - m_action_offset.x, + pt.y - m_action_offset.y); + } + } + else if (m_action == actionDragToolbarPane) + { + wxAuiPaneInfo& pane = GetPane(m_action_window); + wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found")); + + pane.state |= wxAuiPaneInfo::actionPane; + + wxPoint pt = event.GetPosition(); + DoDrop(m_docks, m_panes, pane, pt, m_action_offset); + + // if DoDrop() decided to float the pane, set up + // the floating pane's initial position + if (pane.IsFloating()) + { + wxPoint pt = m_frame->ClientToScreen(event.GetPosition()); + pane.floating_pos = wxPoint(pt.x - m_action_offset.x, + pt.y - m_action_offset.y); + } + + // this will do the actiual move operation; + // in the case that the pane has been floated, + // this call will create the floating pane + // and do the reparenting + Update(); + + // if the pane has been floated, change the mouse + // action actionDragFloatingPane so that subsequent + // EVT_MOTION() events will move the floating pane + if (pane.IsFloating()) + { + pane.state &= ~wxAuiPaneInfo::actionPane; + m_action = actionDragFloatingPane; + m_action_window = pane.frame; + } + } + else + { + wxAuiDockUIPart* part = HitTest(event.GetX(), event.GetY()); + if (part && part->type == wxAuiDockUIPart::typePaneButton) + { + if (part != m_hover_button) + { + // make the old button normal + if (m_hover_button) + { + UpdateButtonOnScreen(m_hover_button, event); + Repaint(); + } + + // mouse is over a button, so repaint the + // button in hover mode + UpdateButtonOnScreen(part, event); + m_hover_button = part; + + } + } + else + { + if (m_hover_button) + { + m_hover_button = NULL; + Repaint(); + } + else + { + event.Skip(); + } + } + } +} + +void wxAuiManager::OnLeaveWindow(wxMouseEvent& WXUNUSED(event)) +{ + if (m_hover_button) + { + m_hover_button = NULL; + Repaint(); + } +} + +void wxAuiManager::OnChildFocus(wxChildFocusEvent& event) +{ + // when a child pane has it's focus set, we should change the + // pane's active state to reflect this. (this is only true if + // active panes are allowed by the owner) + if (GetFlags() & wxAUI_MGR_ALLOW_ACTIVE_PANE) + { + wxAuiPaneInfo& pane = GetPane(event.GetWindow()); + if (pane.IsOk() && (pane.state & wxAuiPaneInfo::optionActive) == 0) + { + SetActivePane(m_panes, event.GetWindow()); + m_frame->Refresh(); + } + } + + event.Skip(); +} + + +// OnPaneButton() is an event handler that is called +// when a pane button has been pressed. +void wxAuiManager::OnPaneButton(wxAuiManagerEvent& evt) +{ + wxASSERT_MSG(evt.pane, wxT("Pane Info passed to wxAuiManager::OnPaneButton must be non-null")); + + wxAuiPaneInfo& pane = *(evt.pane); + + if (evt.button == wxAUI_BUTTON_CLOSE) + { + // fire pane close event + wxAuiManagerEvent e(wxEVT_AUI_PANE_CLOSE); + e.SetManager(this); + e.SetPane(evt.pane); + ProcessMgrEvent(e); + + if (!e.GetVeto()) + { + // close the pane, but check that it + // still exists in our pane array first + // (the event handler above might have removed it) + + wxAuiPaneInfo& check = GetPane(pane.window); + if (check.IsOk()) + { + ClosePane(pane); + } + + Update(); + } + } + else if (evt.button == wxAUI_BUTTON_MAXIMIZE_RESTORE && !pane.IsMaximized()) + { + // fire pane close event + wxAuiManagerEvent e(wxEVT_AUI_PANE_MAXIMIZE); + e.SetManager(this); + e.SetPane(evt.pane); + ProcessMgrEvent(e); + + if (!e.GetVeto()) + { + MaximizePane(pane); + Update(); + } + } + else if (evt.button == wxAUI_BUTTON_MAXIMIZE_RESTORE && pane.IsMaximized()) + { + // fire pane close event + wxAuiManagerEvent e(wxEVT_AUI_PANE_RESTORE); + e.SetManager(this); + e.SetPane(evt.pane); + ProcessMgrEvent(e); + + if (!e.GetVeto()) + { + RestorePane(pane); + Update(); + } + } + else if (evt.button == wxAUI_BUTTON_PIN) + { + if ((m_flags & wxAUI_MGR_ALLOW_FLOATING) && + pane.IsFloatable()) + pane.Float(); + Update(); + } +} + +#endif // wxUSE_AUI diff --git a/Externals/wxWidgets/src/aui/tabmdi.cpp b/Externals/wxWidgets/src/aui/tabmdi.cpp new file mode 100644 index 0000000000..43490948b3 --- /dev/null +++ b/Externals/wxWidgets/src/aui/tabmdi.cpp @@ -0,0 +1,837 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/aui/tabmdi.cpp +// Purpose: Generic MDI (Multiple Document Interface) classes +// Author: Hans Van Leemputten +// Modified by: Benjamin I. Williams / Kirix Corporation +// Created: 29/07/2002 +// RCS-ID: $Id: tabmdi.cpp 55206 2008-08-23 16:19:16Z VZ $ +// Copyright: (c) Hans Van Leemputten +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// =========================================================================== +// declarations +// =========================================================================== + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_AUI +#if wxUSE_MDI + +#include "wx/aui/tabmdi.h" + +#ifndef WX_PRECOMP + #include "wx/panel.h" + #include "wx/menu.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/settings.h" +#endif //WX_PRECOMP + +#include "wx/stockitem.h" + +enum MDI_MENU_ID +{ + wxWINDOWCLOSE = 4001, + wxWINDOWCLOSEALL, + wxWINDOWNEXT, + wxWINDOWPREV +}; + +//----------------------------------------------------------------------------- +// wxAuiMDIParentFrame +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxAuiMDIParentFrame, wxFrame) + +BEGIN_EVENT_TABLE(wxAuiMDIParentFrame, wxFrame) +#if wxUSE_MENUS + EVT_MENU (wxID_ANY, wxAuiMDIParentFrame::DoHandleMenu) +#endif +END_EVENT_TABLE() + +wxAuiMDIParentFrame::wxAuiMDIParentFrame() +{ + Init(); +} + +wxAuiMDIParentFrame::wxAuiMDIParentFrame(wxWindow *parent, + wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + Init(); + (void)Create(parent, id, title, pos, size, style, name); +} + +wxAuiMDIParentFrame::~wxAuiMDIParentFrame() +{ + // Make sure the client window is destructed before the menu bars are! + wxDELETE(m_pClientWindow); + +#if wxUSE_MENUS + wxDELETE(m_pMyMenuBar); + RemoveWindowMenu(GetMenuBar()); + wxDELETE(m_pWindowMenu); +#endif // wxUSE_MENUS +} + +bool wxAuiMDIParentFrame::Create(wxWindow *parent, + wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ +#if wxUSE_MENUS + // this style can be used to prevent a window from having the standard MDI + // "Window" menu + if (!(style & wxFRAME_NO_WINDOW_MENU)) + { + m_pWindowMenu = new wxMenu; + m_pWindowMenu->Append(wxWINDOWCLOSE, _("Cl&ose")); + m_pWindowMenu->Append(wxWINDOWCLOSEALL, _("Close All")); + m_pWindowMenu->AppendSeparator(); + m_pWindowMenu->Append(wxWINDOWNEXT, _("&Next")); + m_pWindowMenu->Append(wxWINDOWPREV, _("&Previous")); + } +#endif // wxUSE_MENUS + + wxFrame::Create(parent, id, title, pos, size, style, name); + OnCreateClient(); + return true; +} + + +void wxAuiMDIParentFrame::SetArtProvider(wxAuiTabArt* provider) +{ + if (m_pClientWindow) + { + m_pClientWindow->SetArtProvider(provider); + } +} + +wxAuiTabArt* wxAuiMDIParentFrame::GetArtProvider() +{ + if (!m_pClientWindow) + return NULL; + + return m_pClientWindow->GetArtProvider(); +} + +wxAuiNotebook* wxAuiMDIParentFrame::GetNotebook() const +{ + return wx_static_cast(wxAuiNotebook*, m_pClientWindow); +} + + + +#if wxUSE_MENUS +void wxAuiMDIParentFrame::SetWindowMenu(wxMenu* pMenu) +{ + // Replace the window menu from the currently loaded menu bar. + wxMenuBar *pMenuBar = GetMenuBar(); + + if (m_pWindowMenu) + { + RemoveWindowMenu(pMenuBar); + wxDELETE(m_pWindowMenu); + } + + if (pMenu) + { + m_pWindowMenu = pMenu; + AddWindowMenu(pMenuBar); + } +} + +void wxAuiMDIParentFrame::SetMenuBar(wxMenuBar* pMenuBar) +{ + // Remove the Window menu from the old menu bar + RemoveWindowMenu(GetMenuBar()); + + // Add the Window menu to the new menu bar. + AddWindowMenu(pMenuBar); + + wxFrame::SetMenuBar(pMenuBar); + //m_pMyMenuBar = GetMenuBar(); +} +#endif // wxUSE_MENUS + +void wxAuiMDIParentFrame::SetChildMenuBar(wxAuiMDIChildFrame* pChild) +{ +#if wxUSE_MENUS + if (!pChild) + { + // No Child, set Our menu bar back. + if (m_pMyMenuBar) + SetMenuBar(m_pMyMenuBar); + else + SetMenuBar(GetMenuBar()); + + // Make sure we know our menu bar is in use + m_pMyMenuBar = NULL; + } + else + { + if (pChild->GetMenuBar() == NULL) + return; + + // Do we need to save the current bar? + if (m_pMyMenuBar == NULL) + m_pMyMenuBar = GetMenuBar(); + + SetMenuBar(pChild->GetMenuBar()); + } +#endif // wxUSE_MENUS +} + +bool wxAuiMDIParentFrame::ProcessEvent(wxEvent& event) +{ + // stops the same event being processed repeatedly + if (m_pLastEvt == &event) + return false; + m_pLastEvt = &event; + + // let the active child (if any) process the event first. + bool res = false; + if (m_pActiveChild && + event.IsCommandEvent() && + event.GetEventObject() != m_pClientWindow && + !(event.GetEventType() == wxEVT_ACTIVATE || + event.GetEventType() == wxEVT_SET_FOCUS || + event.GetEventType() == wxEVT_KILL_FOCUS || + event.GetEventType() == wxEVT_CHILD_FOCUS || + event.GetEventType() == wxEVT_COMMAND_SET_FOCUS || + event.GetEventType() == wxEVT_COMMAND_KILL_FOCUS ) + ) + { + res = m_pActiveChild->GetEventHandler()->ProcessEvent(event); + } + + if (!res) + { + // if the event was not handled this frame will handle it, + // which is why we need the protection code at the beginning + // of this method + res = wxEvtHandler::ProcessEvent(event); + } + + m_pLastEvt = NULL; + + return res; +} + +wxAuiMDIChildFrame *wxAuiMDIParentFrame::GetActiveChild() const +{ + return m_pActiveChild; +} + +void wxAuiMDIParentFrame::SetActiveChild(wxAuiMDIChildFrame* pChildFrame) +{ + m_pActiveChild = pChildFrame; +} + +wxAuiMDIClientWindow *wxAuiMDIParentFrame::GetClientWindow() const +{ + return m_pClientWindow; +} + +wxAuiMDIClientWindow *wxAuiMDIParentFrame::OnCreateClient() +{ + m_pClientWindow = new wxAuiMDIClientWindow( this ); + return m_pClientWindow; +} + +void wxAuiMDIParentFrame::ActivateNext() +{ + if (m_pClientWindow && m_pClientWindow->GetSelection() != wxNOT_FOUND) + { + size_t active = m_pClientWindow->GetSelection() + 1; + if (active >= m_pClientWindow->GetPageCount()) + active = 0; + + m_pClientWindow->SetSelection(active); + } +} + +void wxAuiMDIParentFrame::ActivatePrevious() +{ + if (m_pClientWindow && m_pClientWindow->GetSelection() != wxNOT_FOUND) + { + int active = m_pClientWindow->GetSelection() - 1; + if (active < 0) + active = m_pClientWindow->GetPageCount() - 1; + + m_pClientWindow->SetSelection(active); + } +} + +void wxAuiMDIParentFrame::Init() +{ + m_pLastEvt = NULL; + m_pClientWindow = NULL; + m_pActiveChild = NULL; +#if wxUSE_MENUS + m_pWindowMenu = NULL; + m_pMyMenuBar = NULL; +#endif // wxUSE_MENUS +} + +#if wxUSE_MENUS +void wxAuiMDIParentFrame::RemoveWindowMenu(wxMenuBar* pMenuBar) +{ + if (pMenuBar && m_pWindowMenu) + { + // Remove old window menu + int pos = pMenuBar->FindMenu(_("&Window")); + if (pos != wxNOT_FOUND) + { + // DBG:: We're going to delete the wrong menu!!! + wxASSERT(m_pWindowMenu == pMenuBar->GetMenu(pos)); + pMenuBar->Remove(pos); + } + } +} + +void wxAuiMDIParentFrame::AddWindowMenu(wxMenuBar *pMenuBar) +{ + if (pMenuBar && m_pWindowMenu) + { + int pos = pMenuBar->FindMenu(wxGetStockLabel(wxID_HELP,wxSTOCK_NOFLAGS)); + if (pos == wxNOT_FOUND) + pMenuBar->Append(m_pWindowMenu, _("&Window")); + else + pMenuBar->Insert(pos, m_pWindowMenu, _("&Window")); + } +} + +void wxAuiMDIParentFrame::DoHandleMenu(wxCommandEvent& event) +{ + switch (event.GetId()) + { + case wxWINDOWCLOSE: + if (m_pActiveChild) + m_pActiveChild->Close(); + break; + case wxWINDOWCLOSEALL: + while (m_pActiveChild) + { + if (!m_pActiveChild->Close()) + { + return; // failure + } + } + break; + case wxWINDOWNEXT: + ActivateNext(); + break; + case wxWINDOWPREV: + ActivatePrevious(); + break; + default: + event.Skip(); + } +} +#endif // wxUSE_MENUS + +void wxAuiMDIParentFrame::DoGetClientSize(int* width, int* height) const +{ + wxFrame::DoGetClientSize(width, height); +} + +void wxAuiMDIParentFrame::Tile(wxOrientation orient) +{ + wxAuiMDIClientWindow* client_window = GetClientWindow(); + wxASSERT_MSG(client_window, wxT("Missing MDI Client Window")); + + int cur_idx = client_window->GetSelection(); + if (cur_idx == -1) + return; + + if (orient == wxVERTICAL) + { + client_window->Split(cur_idx, wxLEFT); + } + else if (orient == wxHORIZONTAL) + { + client_window->Split(cur_idx, wxTOP); + } +} + + +//----------------------------------------------------------------------------- +// wxAuiMDIChildFrame +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxAuiMDIChildFrame, wxPanel) + +BEGIN_EVENT_TABLE(wxAuiMDIChildFrame, wxPanel) + EVT_MENU_HIGHLIGHT_ALL(wxAuiMDIChildFrame::OnMenuHighlight) + EVT_ACTIVATE(wxAuiMDIChildFrame::OnActivate) + EVT_CLOSE(wxAuiMDIChildFrame::OnCloseWindow) +END_EVENT_TABLE() + +wxAuiMDIChildFrame::wxAuiMDIChildFrame() +{ + Init(); +} + +wxAuiMDIChildFrame::wxAuiMDIChildFrame(wxAuiMDIParentFrame *parent, + wxWindowID id, + const wxString& title, + const wxPoint& WXUNUSED(pos), + const wxSize& size, + long style, + const wxString& name) +{ + Init(); + + // There are two ways to create an tabbed mdi child fram without + // making it the active document. Either Show(false) can be called + // before Create() (as is customary on some ports with wxFrame-type + // windows), or wxMINIMIZE can be passed in the style flags. Note that + // wxAuiMDIChildFrame is not really derived from wxFrame, as wxMDIChildFrame + // is, but those are the expected symantics. No style flag is passed + // onto the panel underneath. + if (style & wxMINIMIZE) + m_activate_on_create = false; + + Create(parent, id, title, wxDefaultPosition, size, 0, name); +} + +wxAuiMDIChildFrame::~wxAuiMDIChildFrame() +{ + wxAuiMDIParentFrame* pParentFrame = GetMDIParentFrame(); + if (pParentFrame) + { + if (pParentFrame->GetActiveChild() == this) + { + pParentFrame->SetActiveChild(NULL); + pParentFrame->SetChildMenuBar(NULL); + } + wxAuiMDIClientWindow* pClientWindow = pParentFrame->GetClientWindow(); + wxASSERT(pClientWindow); + int idx = pClientWindow->GetPageIndex(this); + if (idx != wxNOT_FOUND) + { + pClientWindow->RemovePage(idx); + } + } + +#if wxUSE_MENUS + wxDELETE(m_pMenuBar); +#endif // wxUSE_MENUS +} + +bool wxAuiMDIChildFrame::Create(wxAuiMDIParentFrame* parent, + wxWindowID id, + const wxString& title, + const wxPoint& WXUNUSED(pos), + const wxSize& size, + long style, + const wxString& name) +{ + wxAuiMDIClientWindow* pClientWindow = parent->GetClientWindow(); + wxASSERT_MSG((pClientWindow != (wxWindow*) NULL), wxT("Missing MDI client window.")); + + // see comment in constructor + if (style & wxMINIMIZE) + m_activate_on_create = false; + + wxSize cli_size = pClientWindow->GetClientSize(); + + // create the window off-screen to prevent flicker + wxPanel::Create(pClientWindow, + id, + wxPoint(cli_size.x+1, cli_size.y+1), + size, + wxNO_BORDER, name); + + DoShow(false); + + SetMDIParentFrame(parent); + + // this is the currently active child + parent->SetActiveChild(this); + + m_title = title; + + pClientWindow->AddPage(this, title, m_activate_on_create); + pClientWindow->Refresh(); + + return true; +} + +bool wxAuiMDIChildFrame::Destroy() +{ + wxAuiMDIParentFrame* pParentFrame = GetMDIParentFrame(); + wxASSERT_MSG(pParentFrame, wxT("Missing MDI Parent Frame")); + + wxAuiMDIClientWindow* pClientWindow = pParentFrame->GetClientWindow(); + wxASSERT_MSG(pClientWindow, wxT("Missing MDI Client Window")); + + if (pParentFrame->GetActiveChild() == this) + { + // deactivate ourself + wxActivateEvent event(wxEVT_ACTIVATE, false, GetId()); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); + + pParentFrame->SetActiveChild(NULL); + pParentFrame->SetChildMenuBar(NULL); + } + + size_t page_count = pClientWindow->GetPageCount(); + for (size_t pos = 0; pos < page_count; pos++) + { + if (pClientWindow->GetPage(pos) == this) + return pClientWindow->DeletePage(pos); + } + + return false; +} + +#if wxUSE_MENUS +void wxAuiMDIChildFrame::SetMenuBar(wxMenuBar *menu_bar) +{ + wxMenuBar *pOldMenuBar = m_pMenuBar; + m_pMenuBar = menu_bar; + + if (m_pMenuBar) + { + wxAuiMDIParentFrame* pParentFrame = GetMDIParentFrame(); + wxASSERT_MSG(pParentFrame, wxT("Missing MDI Parent Frame")); + + m_pMenuBar->SetParent(pParentFrame); + if (pParentFrame->GetActiveChild() == this) + { + // replace current menu bars + if (pOldMenuBar) + pParentFrame->SetChildMenuBar(NULL); + pParentFrame->SetChildMenuBar(this); + } + } +} + +wxMenuBar *wxAuiMDIChildFrame::GetMenuBar() const +{ + return m_pMenuBar; +} +#endif // wxUSE_MENUS + +void wxAuiMDIChildFrame::SetTitle(const wxString& title) +{ + m_title = title; + + wxAuiMDIParentFrame* pParentFrame = GetMDIParentFrame(); + wxASSERT_MSG(pParentFrame, wxT("Missing MDI Parent Frame")); + + wxAuiMDIClientWindow* pClientWindow = pParentFrame->GetClientWindow(); + if (pClientWindow != NULL) + { + size_t pos; + for (pos = 0; pos < pClientWindow->GetPageCount(); pos++) + { + if (pClientWindow->GetPage(pos) == this) + { + pClientWindow->SetPageText(pos, m_title); + break; + } + } + } +} + +wxString wxAuiMDIChildFrame::GetTitle() const +{ + return m_title; +} + +void wxAuiMDIChildFrame::SetIcons(const wxIconBundle& icons) +{ + // get icon with the system icon size + SetIcon(icons.GetIcon(-1)); + m_icon_bundle = icons; +} + +const wxIconBundle& wxAuiMDIChildFrame::GetIcons() const +{ + return m_icon_bundle; +} + +void wxAuiMDIChildFrame::SetIcon(const wxIcon& icon) +{ + wxAuiMDIParentFrame* pParentFrame = GetMDIParentFrame(); + wxASSERT_MSG(pParentFrame, wxT("Missing MDI Parent Frame")); + + m_icon = icon; + + wxBitmap bmp; + bmp.CopyFromIcon(m_icon); + + wxAuiMDIClientWindow* pClientWindow = pParentFrame->GetClientWindow(); + if (pClientWindow != NULL) + { + int idx = pClientWindow->GetPageIndex(this); + + if (idx != -1) + { + pClientWindow->SetPageBitmap((size_t)idx, bmp); + } + } +} + +const wxIcon& wxAuiMDIChildFrame::GetIcon() const +{ + return m_icon; +} + + +void wxAuiMDIChildFrame::Activate() +{ + wxAuiMDIParentFrame* pParentFrame = GetMDIParentFrame(); + wxASSERT_MSG(pParentFrame, wxT("Missing MDI Parent Frame")); + + wxAuiMDIClientWindow* pClientWindow = pParentFrame->GetClientWindow(); + + if (pClientWindow != NULL) + { + size_t pos; + for (pos = 0; pos < pClientWindow->GetPageCount(); pos++) + { + if (pClientWindow->GetPage(pos) == this) + { + pClientWindow->SetSelection(pos); + break; + } + } + } +} + +void wxAuiMDIChildFrame::OnMenuHighlight(wxMenuEvent& event) +{ +#if wxUSE_STATUSBAR + if (m_pMDIParentFrame) + { + // we don't have any help text for this item, + // but may be the MDI frame does? + m_pMDIParentFrame->OnMenuHighlight(event); + } +#else + wxUnusedVar(event); +#endif // wxUSE_STATUSBAR +} + +void wxAuiMDIChildFrame::OnActivate(wxActivateEvent& WXUNUSED(event)) +{ + // do nothing +} + +void wxAuiMDIChildFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) +{ + Destroy(); +} + +void wxAuiMDIChildFrame::SetMDIParentFrame(wxAuiMDIParentFrame* parentFrame) +{ + m_pMDIParentFrame = parentFrame; +} + +wxAuiMDIParentFrame* wxAuiMDIChildFrame::GetMDIParentFrame() const +{ + return m_pMDIParentFrame; +} + +void wxAuiMDIChildFrame::Init() +{ + m_activate_on_create = true; + m_pMDIParentFrame = NULL; +#if wxUSE_MENUS + m_pMenuBar = NULL; +#endif // wxUSE_MENUS +} + +bool wxAuiMDIChildFrame::Show(bool show) +{ + m_activate_on_create = show; + + // do nothing + return true; +} + +void wxAuiMDIChildFrame::DoShow(bool show) +{ + wxWindow::Show(show); +} + +void wxAuiMDIChildFrame::DoSetSize(int x, int y, int width, int height, int sizeFlags) +{ + m_mdi_newrect = wxRect(x, y, width, height); +#ifdef __WXGTK__ + wxPanel::DoSetSize(x,y,width, height, sizeFlags); +#else + wxUnusedVar(sizeFlags); +#endif +} + +void wxAuiMDIChildFrame::DoMoveWindow(int x, int y, int width, int height) +{ + m_mdi_newrect = wxRect(x, y, width, height); +} + +void wxAuiMDIChildFrame::ApplyMDIChildFrameRect() +{ + if (m_mdi_currect != m_mdi_newrect) + { + wxPanel::DoMoveWindow(m_mdi_newrect.x, m_mdi_newrect.y, + m_mdi_newrect.width, m_mdi_newrect.height); + m_mdi_currect = m_mdi_newrect; + } +} + + +//----------------------------------------------------------------------------- +// wxAuiMDIClientWindow +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxAuiMDIClientWindow, wxAuiNotebook) + +BEGIN_EVENT_TABLE(wxAuiMDIClientWindow, wxAuiNotebook) + EVT_AUINOTEBOOK_PAGE_CHANGED(wxID_ANY, wxAuiMDIClientWindow::OnPageChanged) + EVT_AUINOTEBOOK_PAGE_CLOSE(wxID_ANY, wxAuiMDIClientWindow::OnPageClose) + EVT_SIZE(wxAuiMDIClientWindow::OnSize) +END_EVENT_TABLE() + +wxAuiMDIClientWindow::wxAuiMDIClientWindow() +{ +} + +wxAuiMDIClientWindow::wxAuiMDIClientWindow(wxAuiMDIParentFrame* parent, long style) +{ + CreateClient(parent, style); +} + +wxAuiMDIClientWindow::~wxAuiMDIClientWindow() +{ +} + +bool wxAuiMDIClientWindow::CreateClient(wxAuiMDIParentFrame* parent, long style) +{ + SetWindowStyleFlag(style); + + wxSize caption_icon_size = + wxSize(wxSystemSettings::GetMetric(wxSYS_SMALLICON_X), + wxSystemSettings::GetMetric(wxSYS_SMALLICON_Y)); + SetUniformBitmapSize(caption_icon_size); + + if (!wxAuiNotebook::Create(parent, + wxID_ANY, + wxPoint(0,0), + wxSize(100, 100), + wxAUI_NB_DEFAULT_STYLE | wxNO_BORDER)) + { + return false; + } + + wxColour bkcolour = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE); + SetOwnBackgroundColour(bkcolour); + + m_mgr.GetArtProvider()->SetColour(wxAUI_DOCKART_BACKGROUND_COLOUR, bkcolour); + + return true; +} + +int wxAuiMDIClientWindow::SetSelection(size_t nPage) +{ + return wxAuiNotebook::SetSelection(nPage); +} + +void wxAuiMDIClientWindow::PageChanged(int old_selection, int new_selection) +{ + // don't do anything if the page doesn't actually change + if (old_selection == new_selection) + return; + + /* + // don't do anything if the new page is already active + if (new_selection != -1) + { + wxAuiMDIChildFrame* child = (wxAuiMDIChildFrame*)GetPage(new_selection); + if (child->GetMDIParentFrame()->GetActiveChild() == child) + return; + }*/ + + + // notify old active child that it has been deactivated + if ((old_selection != -1) && (old_selection < (int)GetPageCount())) + { + wxAuiMDIChildFrame* old_child = (wxAuiMDIChildFrame*)GetPage(old_selection); + wxASSERT_MSG(old_child, wxT("wxAuiMDIClientWindow::PageChanged - null page pointer")); + + wxActivateEvent event(wxEVT_ACTIVATE, false, old_child->GetId()); + event.SetEventObject(old_child); + old_child->GetEventHandler()->ProcessEvent(event); + } + + // notify new active child that it has been activated + if (new_selection != -1) + { + wxAuiMDIChildFrame* active_child = (wxAuiMDIChildFrame*)GetPage(new_selection); + wxASSERT_MSG(active_child, wxT("wxAuiMDIClientWindow::PageChanged - null page pointer")); + + wxActivateEvent event(wxEVT_ACTIVATE, true, active_child->GetId()); + event.SetEventObject(active_child); + active_child->GetEventHandler()->ProcessEvent(event); + + if (active_child->GetMDIParentFrame()) + { + active_child->GetMDIParentFrame()->SetActiveChild(active_child); + active_child->GetMDIParentFrame()->SetChildMenuBar(active_child); + } + } + + +} + +void wxAuiMDIClientWindow::OnPageClose(wxAuiNotebookEvent& evt) +{ + wxAuiMDIChildFrame* + wnd = wx_static_cast(wxAuiMDIChildFrame*, GetPage(evt.GetSelection())); + + wnd->Close(); + + // regardless of the result of wnd->Close(), we've + // already taken care of the close operations, so + // suppress further processing + evt.Veto(); +} + +void wxAuiMDIClientWindow::OnPageChanged(wxAuiNotebookEvent& evt) +{ + PageChanged(evt.GetOldSelection(), evt.GetSelection()); +} + +void wxAuiMDIClientWindow::OnSize(wxSizeEvent& evt) +{ + wxAuiNotebook::OnSize(evt); + + for (size_t pos = 0; pos < GetPageCount(); pos++) + ((wxAuiMDIChildFrame *)GetPage(pos))->ApplyMDIChildFrameRect(); +} + +#endif // wxUSE_MDI + +#endif // wxUSE_AUI