+ if ( GetExtraStyle() & wxPG_EX_MULTIPLE_SELECTION )
+ {
+ if ( mouseEvent )
+ {
+ if ( mouseEvent->GetEventType() == wxEVT_RIGHT_DOWN ||
+ mouseEvent->GetEventType() == wxEVT_RIGHT_UP )
+ {
+ // Allow right-click for context menu without
+ // disturbing the selection.
+ if ( GetSelectedProperties().size() <= 1 ||
+ !alreadySelected )
+ return DoSelectAndEdit(prop, colIndex, selFlags);
+ return true;
+ }
+ else
+ {
+ addToExistingSelection = mouseEvent->ShiftDown();
+ }
+ }
+ else
+ {
+ addToExistingSelection = false;
+ }
+ }
+ else
+ {
+ addToExistingSelection = false;
+ }
+
+ if ( addToExistingSelection )
+ {
+ if ( !alreadySelected )
+ {
+ res = DoAddToSelection(prop, selFlags);
+ }
+ else if ( GetSelectedProperties().size() > 1 )
+ {
+ res = DoRemoveFromSelection(prop, selFlags);
+ }
+ }
+ else
+ {
+ res = DoSelectAndEdit(prop, colIndex, selFlags);
+ }
+
+ return res;
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::DoSetSelection( const wxArrayPGProperty& newSelection,
+ int selFlags )
+{
+ if ( newSelection.size() > 0 )
+ {
+ if ( !DoSelectProperty(newSelection[0], selFlags) )
+ return;
+ }
+ else
+ {
+ DoClearSelection(false, selFlags);
+ }
+
+ for ( unsigned int i = 1; i < newSelection.size(); i++ )
+ {
+ DoAddToSelection(newSelection[i], selFlags);
+ }
+
+ Refresh();
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::MakeColumnEditable( unsigned int column,
+ bool editable )
+{
+ wxASSERT( column != 1 );
+
+ wxArrayInt& cols = m_pState->m_editableColumns;
+
+ if ( editable )
+ {
+ cols.push_back(column);
+ }
+ else
+ {
+ for ( int i = cols.size() - 1; i > 0; i-- )
+ {
+ if ( cols[i] == (int)column )
+ cols.erase( cols.begin() + i );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::DoBeginLabelEdit( unsigned int colIndex,
+ int selFlags )
+{
+ wxPGProperty* selected = GetSelection();
+ wxCHECK_RET(selected, wxT("No property selected"));
+ wxCHECK_RET(colIndex != 1, wxT("Do not use this for column 1"));
+
+ if ( !(selFlags & wxPG_SEL_DONT_SEND_EVENT) )
+ {
+ if ( SendEvent( wxEVT_PG_LABEL_EDIT_BEGIN,
+ selected, NULL, 0,
+ colIndex ) )
+ return;
+ }
+
+ wxString text;
+ const wxPGCell* cell = NULL;
+ if ( selected->HasCell(colIndex) )
+ {
+ cell = &selected->GetCell(colIndex);
+ if ( !cell->HasText() && colIndex == 0 )
+ text = selected->GetLabel();
+ }
+
+ if ( !cell )
+ {
+ if ( colIndex == 0 )
+ text = selected->GetLabel();
+ else
+ cell = &selected->GetOrCreateCell(colIndex);
+ }
+
+ if ( cell && cell->HasText() )
+ text = cell->GetText();
+
+ DoEndLabelEdit(true, wxPG_SEL_NOVALIDATE); // send event
+
+ m_selColumn = colIndex;
+
+ wxRect r = GetEditorWidgetRect(selected, m_selColumn);
+
+ wxWindow* tc = GenerateEditorTextCtrl(r.GetPosition(),
+ r.GetSize(),
+ text,
+ NULL,
+ wxTE_PROCESS_ENTER,
+ 0,
+ colIndex);
+
+ wxWindowID id = tc->GetId();
+ tc->Connect(id, wxEVT_COMMAND_TEXT_ENTER,
+ wxCommandEventHandler(wxPropertyGrid::OnLabelEditorEnterPress),
+ NULL, this);
+ tc->Connect(id, wxEVT_KEY_DOWN,
+ wxKeyEventHandler(wxPropertyGrid::OnLabelEditorKeyPress),
+ NULL, this);
+
+ tc->SetFocus();
+
+ m_labelEditor = wxStaticCast(tc, wxTextCtrl);
+ m_labelEditorProperty = selected;
+}
+
+// -----------------------------------------------------------------------
+
+void
+wxPropertyGrid::OnLabelEditorEnterPress( wxCommandEvent& WXUNUSED(event) )
+{
+ DoEndLabelEdit(true);
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::OnLabelEditorKeyPress( wxKeyEvent& event )
+{
+ int keycode = event.GetKeyCode();
+
+ if ( keycode == WXK_ESCAPE )
+ {
+ DoEndLabelEdit(false);
+ }
+ else
+ {
+ event.Skip();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::DoEndLabelEdit( bool commit, int selFlags )
+{
+ if ( !m_labelEditor )
+ return;
+
+ wxPGProperty* prop = m_labelEditorProperty;
+ wxASSERT(prop);
+
+ if ( commit )
+ {
+ if ( !(selFlags & wxPG_SEL_DONT_SEND_EVENT) )
+ {
+ // wxPG_SEL_NOVALIDATE is passed correctly in selFlags
+ if ( SendEvent( wxEVT_PG_LABEL_EDIT_ENDING,
+ prop, NULL, selFlags,
+ m_selColumn ) )
+ return;
+ }
+
+ wxString text = m_labelEditor->GetValue();
+ wxPGCell* cell = NULL;
+ if ( prop->HasCell(m_selColumn) )
+ {
+ cell = &prop->GetCell(m_selColumn);
+ }
+ else
+ {
+ if ( m_selColumn == 0 )
+ prop->SetLabel(text);
+ else
+ cell = &prop->GetOrCreateCell(m_selColumn);
+ }
+
+ if ( cell )
+ cell->SetText(text);
+ }
+
+ m_selColumn = 1;
+
+ DestroyEditorWnd(m_labelEditor);
+ m_labelEditor = NULL;
+ m_labelEditorProperty = NULL;
+
+ DrawItem(prop);
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::SetExtraStyle( long exStyle )
+{
+ if ( exStyle & wxPG_EX_ENABLE_TLP_TRACKING )
+ OnTLPChanging(::wxGetTopLevelParent(this));
+ else
+ OnTLPChanging(NULL);
+
+ if ( exStyle & wxPG_EX_NATIVE_DOUBLE_BUFFERING )
+ {
+#if defined(__WXMSW__)
+
+ /*
+ // Don't use WS_EX_COMPOSITED just now.
+ HWND hWnd;
+
+ if ( m_iFlags & wxPG_FL_IN_MANAGER )
+ hWnd = (HWND)GetParent()->GetHWND();
+ else
+ hWnd = (HWND)GetHWND();
+
+ ::SetWindowLong( hWnd, GWL_EXSTYLE,
+ ::GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_COMPOSITED );
+ */
+
+//#elif defined(__WXGTK20__)
+#endif
+ // Only apply wxPG_EX_NATIVE_DOUBLE_BUFFERING if the window
+ // truly was double-buffered.
+ if ( !this->IsDoubleBuffered() )
+ {
+ exStyle &= ~(wxPG_EX_NATIVE_DOUBLE_BUFFERING);
+ }
+ else
+ {
+ #if wxPG_DOUBLE_BUFFER
+ delete m_doubleBuffer;
+ m_doubleBuffer = NULL;
+ #endif
+ }
+ }
+
+ wxScrolledWindow::SetExtraStyle( exStyle );
+
+ if ( exStyle & wxPG_EX_INIT_NOCAT )
+ m_pState->InitNonCatMode();
+
+ if ( exStyle & wxPG_EX_HELP_AS_TOOLTIPS )
+ m_windowStyle |= wxPG_TOOLTIPS;
+
+ // Set global style
+ wxPGGlobalVars->m_extraStyle = exStyle;
+}
+
+// -----------------------------------------------------------------------
+
+// returns the best acceptable minimal size
+wxSize wxPropertyGrid::DoGetBestSize() const
+{
+ int lineHeight = wxMax(15, m_lineHeight);
+
+ // don't make the grid too tall (limit height to 10 items) but don't
+ // make it too small neither
+ int numLines = wxMin
+ (
+ wxMax(m_pState->m_properties->GetChildCount(), 3),
+ 10
+ );
+
+ wxClientDC dc(const_cast<wxPropertyGrid *>(this));
+ int width = m_marginWidth;
+ for ( unsigned int i = 0; i < m_pState->m_colWidths.size(); i++ )
+ {
+ width += m_pState->GetColumnFitWidth(dc, m_pState->DoGetRoot(), i, true);
+ }
+
+ const wxSize sz = wxSize(width, lineHeight*numLines + 40);
+
+ CacheBestSize(sz);
+ return sz;
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::OnTLPChanging( wxWindow* newTLP )
+{
+ if ( newTLP == m_tlp )
+ return;
+
+ wxLongLong currentTime = ::wxGetLocalTimeMillis();
+
+ //
+ // Parent changed so let's redetermine and re-hook the
+ // correct top-level window.
+ if ( m_tlp )
+ {
+ m_tlp->Disconnect( wxEVT_CLOSE_WINDOW,
+ wxCloseEventHandler(wxPropertyGrid::OnTLPClose),
+ NULL, this );
+ m_tlpClosed = m_tlp;
+ m_tlpClosedTime = currentTime;
+ }
+
+ if ( newTLP )
+ {
+ // Only accept new tlp if same one was not just dismissed.
+ if ( newTLP != m_tlpClosed ||
+ m_tlpClosedTime+250 < currentTime )
+ {
+ newTLP->Connect( wxEVT_CLOSE_WINDOW,
+ wxCloseEventHandler(wxPropertyGrid::OnTLPClose),
+ NULL, this );
+ m_tlpClosed = NULL;
+ }
+ else
+ {
+ newTLP = NULL;
+ }
+ }
+
+ m_tlp = newTLP;
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::OnTLPClose( wxCloseEvent& event )
+{
+ // ClearSelection forces value validation/commit.
+ if ( event.CanVeto() && !DoClearSelection() )
+ {
+ event.Veto();
+ return;
+ }
+
+ // Ok, it can close, set tlp pointer to NULL. Some other event
+ // handler can of course veto the close, but our OnIdle() should
+ // then be able to regain the tlp pointer.
+ OnTLPChanging(NULL);
+
+ event.Skip();
+}
+
+// -----------------------------------------------------------------------
+
+bool wxPropertyGrid::Reparent( wxWindowBase *newParent )
+{
+ OnTLPChanging((wxWindow*)newParent);
+
+ bool res = wxScrolledWindow::Reparent(newParent);
+
+ return res;
+}
+
+// -----------------------------------------------------------------------
+// wxPropertyGrid Font and Colour Methods
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::CalculateFontAndBitmapStuff( int vspacing )
+{
+ int x = 0, y = 0;
+
+ m_captionFont = wxScrolledWindow::GetFont();
+
+ GetTextExtent(wxS("jG"), &x, &y, 0, 0, &m_captionFont);
+ m_subgroup_extramargin = x + (x/2);
+ m_fontHeight = y;
+
+#if wxPG_USE_RENDERER_NATIVE
+ m_iconWidth = wxPG_ICON_WIDTH;
+#elif wxPG_ICON_WIDTH
+ // scale icon
+ m_iconWidth = (m_fontHeight * wxPG_ICON_WIDTH) / 13;
+ if ( m_iconWidth < 5 ) m_iconWidth = 5;
+ else if ( !(m_iconWidth & 0x01) ) m_iconWidth++; // must be odd
+
+#endif
+
+ m_gutterWidth = m_iconWidth / wxPG_GUTTER_DIV;
+ if ( m_gutterWidth < wxPG_GUTTER_MIN )
+ m_gutterWidth = wxPG_GUTTER_MIN;
+
+ int vdiv = 6;
+ if ( vspacing <= 1 ) vdiv = 12;
+ else if ( vspacing >= 3 ) vdiv = 3;
+
+ m_spacingy = m_fontHeight / vdiv;
+ if ( m_spacingy < wxPG_YSPACING_MIN )
+ m_spacingy = wxPG_YSPACING_MIN;
+
+ m_marginWidth = 0;
+ if ( !(m_windowStyle & wxPG_HIDE_MARGIN) )
+ m_marginWidth = m_gutterWidth*2 + m_iconWidth;
+
+ m_captionFont.SetWeight(wxBOLD);
+ GetTextExtent(wxS("jG"), &x, &y, 0, 0, &m_captionFont);
+
+ m_lineHeight = m_fontHeight+(2*m_spacingy)+1;
+
+ // button spacing
+ m_buttonSpacingY = (m_lineHeight - m_iconHeight) / 2;
+ if ( m_buttonSpacingY < 0 ) m_buttonSpacingY = 0;
+
+ if ( m_pState )
+ m_pState->CalculateFontAndBitmapStuff(vspacing);
+
+ if ( m_iFlags & wxPG_FL_INITIALIZED )
+ RecalculateVirtualSize();
+
+ InvalidateBestSize();
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::OnSysColourChanged( wxSysColourChangedEvent &WXUNUSED(event) )
+{
+ RegainColours();
+ Refresh();
+}
+
+// -----------------------------------------------------------------------
+
+static wxColour wxPGAdjustColour(const wxColour& src, int ra,
+ int ga = 1000, int ba = 1000,
+ bool forceDifferent = false)
+{
+ if ( ga >= 1000 )
+ ga = ra;
+ if ( ba >= 1000 )
+ ba = ra;