diff --git a/include/wx/qt/frame.h b/include/wx/qt/frame.h index 4905911d79..f640911a46 100644 --- a/include/wx/qt/frame.h +++ b/include/wx/qt/frame.h @@ -56,6 +56,9 @@ public: protected: virtual void DoGetClientSize(int *width, int *height) const wxOVERRIDE; + virtual void DoSetClientSize(int width, int height) wxOVERRIDE; + + virtual QWidget* QtGetParentWidget() const wxOVERRIDE; private: // Common part of all ctors. diff --git a/include/wx/qt/listbox.h b/include/wx/qt/listbox.h index 9ebaf91a66..3108bb62f8 100644 --- a/include/wx/qt/listbox.h +++ b/include/wx/qt/listbox.h @@ -60,7 +60,7 @@ public: virtual QWidget *GetHandle() const wxOVERRIDE; - void QtSendEvent(wxEventType evtType, const QModelIndex &index, bool selected); + void QtSendEvent(wxEventType evtType, int rowIndex, bool selected); protected: virtual void DoSetFirstItem(int n) wxOVERRIDE; diff --git a/include/wx/qt/menuitem.h b/include/wx/qt/menuitem.h index c91a16a4e1..24e5e27003 100644 --- a/include/wx/qt/menuitem.h +++ b/include/wx/qt/menuitem.h @@ -12,6 +12,7 @@ #include "wx/bitmap.h" class QAction; +class wxQtAction; class WXDLLIMPEXP_FWD_CORE wxMenu; @@ -41,7 +42,7 @@ public: private: // Qt is using an action instead of a menu item. - QAction *m_qtAction; + wxQtAction *m_qtAction; wxBitmap m_bitmap; wxDECLARE_DYNAMIC_CLASS( wxMenuItem ); diff --git a/include/wx/qt/private/treeitemdelegate.h b/include/wx/qt/private/treeitemdelegate.h index 65025de442..632172f6ec 100644 --- a/include/wx/qt/private/treeitemdelegate.h +++ b/include/wx/qt/private/treeitemdelegate.h @@ -11,6 +11,7 @@ #define _WX_QT_PRIVATE_TREEITEM_DELEGATE_H #include +#include #include "wx/app.h" #include "wx/textctrl.h" @@ -67,6 +68,28 @@ public: QStyledItemDelegate::setModelData(editor, model, index); } + bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) + { + if ( event->type() == QEvent::ToolTip ) + { + const QRect &itemRect = view->visualRect(index); + const QSize &bestSize = sizeHint(option, index); + if ( itemRect.width() < bestSize.width() ) + { + const QString &value = index.data(Qt::DisplayRole).toString(); + QToolTip::showText(event->globalPos(), value, view); + } + else + { + QToolTip::hideText(); + } + + return true; + } + + return QStyledItemDelegate::helpEvent(event, view, option, index); + } + private: wxWindow* m_parent; mutable wxTextCtrl* m_textCtrl; diff --git a/include/wx/qt/private/winevent.h b/include/wx/qt/private/winevent.h index 5137f6d00e..87623cf605 100644 --- a/include/wx/qt/private/winevent.h +++ b/include/wx/qt/private/winevent.h @@ -61,6 +61,7 @@ public: QObject::connect( this, &QObject::destroyed, this, &wxQtEventSignalHandler::HandleDestroyedSignal ); + Widget::setMouseTracking(true); } void HandleDestroyedSignal() @@ -104,7 +105,7 @@ protected: if ( !this->GetHandler()->QtHandleCloseEvent(this, event) ) Widget::closeEvent(event); else - event->accept(); + event->ignore(); } //wxContextMenuEvent diff --git a/include/wx/qt/window.h b/include/wx/qt/window.h index 98608b1fa2..a4d49516d8 100644 --- a/include/wx/qt/window.h +++ b/include/wx/qt/window.h @@ -168,6 +168,7 @@ public: static void QtStoreWindowPointer( QWidget *widget, const wxWindowQt *window ); static wxWindowQt *QtRetrieveWindowPointer( const QWidget *widget ); + static void QtSendSetCursorEvent(wxWindowQt* win, wxPoint posClient); #if wxUSE_ACCEL virtual void QtHandleShortcut ( int command ); @@ -215,6 +216,12 @@ protected: virtual bool DoPopupMenu(wxMenu *menu, int x, int y) wxOVERRIDE; #endif // wxUSE_MENUS + // Return the parent to use for children being reparented to us: this is + // overridden in wxFrame to use its central widget rather than the frame + // itself. + virtual QWidget* QtGetParentWidget() const { return GetHandle(); } + + QWidget *m_qtWindow; private: @@ -224,6 +231,11 @@ private: QScrollBar *m_horzScrollBar; // owned by m_qtWindow when allocated QScrollBar *m_vertScrollBar; // owned by m_qtWindow when allocated + // Return the viewport of m_qtContainer, if it's used, or just m_qtWindow. + // + // Always returns non-null pointer if the window has been already created. + QWidget *QtGetClientWidget() const; + QScrollBar *QtGetScrollBar( int orientation ) const; QScrollBar *QtSetScrollBar( int orientation, QScrollBar *scrollBar=NULL ); diff --git a/src/aui/framemanager.cpp b/src/aui/framemanager.cpp index 540cccb6e7..47a7e035e2 100644 --- a/src/aui/framemanager.cpp +++ b/src/aui/framemanager.cpp @@ -848,7 +848,7 @@ void wxAuiManager::UpdateHintWindowConfig() if ((m_flags & wxAUI_MGR_TRANSPARENT_HINT) && can_do_transparent) { // Make a window to use for a transparent hint - #if defined(__WXMSW__) || defined(__WXGTK__) + #if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXQT__) m_hintWnd = new wxFrame(m_frame, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(1,1), wxFRAME_TOOL_WINDOW | diff --git a/src/qt/anybutton.cpp b/src/qt/anybutton.cpp index 1bf235bd46..5c6f880c6b 100644 --- a/src/qt/anybutton.cpp +++ b/src/qt/anybutton.cpp @@ -85,8 +85,9 @@ wxAnyButton::wxAnyButton() : void wxAnyButton::QtCreate(wxWindow *parent) { - // create the default push button (used in button and bmp button) - m_qtPushButton = new wxQtPushButton( parent, this ); + // create the basic push button (used in button and bmp button) + m_qtPushButton = new wxQtPushButton(parent, this); + m_qtPushButton->setAutoDefault(false); } void wxAnyButton::QtSetBitmap( const wxBitmap &bitmap ) diff --git a/src/qt/dnd.cpp b/src/qt/dnd.cpp index ed8ca9e898..b7655f56d5 100644 --- a/src/qt/dnd.cpp +++ b/src/qt/dnd.cpp @@ -16,10 +16,10 @@ #include "wx/qt/private/converter.h" -#include -#include -#include -#include +#include +#include +#include +#include namespace { diff --git a/src/qt/font.cpp b/src/qt/font.cpp index f9e5b1fd9b..6cfebf895e 100644 --- a/src/qt/font.cpp +++ b/src/qt/font.cpp @@ -563,7 +563,7 @@ void wxNativeFontInfo::SetFamily(wxFontFamily family) { m_qtFont.setStyleHint(ConvertFontFamily(family)); // reset the face name to force qt to choose a new font - m_qtFont.setFamily(""); + m_qtFont.setFamily(m_qtFont.defaultFamily()); } void wxNativeFontInfo::SetEncoding(wxFontEncoding WXUNUSED(encoding)) diff --git a/src/qt/frame.cpp b/src/qt/frame.cpp index be927ce2cd..08f1c43f98 100644 --- a/src/qt/frame.cpp +++ b/src/qt/frame.cpp @@ -134,15 +134,16 @@ void wxFrame::SetWindowStyleFlag( long style ) { wxWindow::SetWindowStyleFlag( style ); - QMainWindow *qtFrame = GetQMainWindow(); - Qt::WindowFlags qtFlags = qtFrame->windowFlags(); - qtFlags |= Qt::CustomizeWindowHint; + Qt::WindowFlags qtFlags = Qt::CustomizeWindowHint; if ( HasFlag( wxFRAME_TOOL_WINDOW ) ) { - qtFlags &= ~Qt::WindowType_Mask; qtFlags |= Qt::Tool; } + else + { + qtFlags |= Qt::Window; + } if ( HasFlag(wxCAPTION) ) { @@ -183,15 +184,19 @@ void wxFrame::SetWindowStyleFlag( long style ) qtFlags |= Qt::FramelessWindowHint; } - qtFrame->setWindowFlags(qtFlags); + GetQMainWindow()->setWindowFlags(qtFlags); +} +QWidget* wxFrame::QtGetParentWidget() const +{ + return GetQMainWindow()->centralWidget(); } void wxFrame::AddChild( wxWindowBase *child ) { // Make sure all children are children of the central widget: - QtReparent( child->GetHandle(), GetQMainWindow()->centralWidget() ); + QtReparent( child->GetHandle(), QtGetParentWidget() ); wxFrameBase::AddChild( child ); } @@ -226,6 +231,19 @@ void wxFrame::DoGetClientSize(int *width, int *height) const } } +void wxFrame::DoSetClientSize(int width, int height) +{ + wxWindow::DoSetClientSize(width, height); + + int adjustedWidth, adjustedHeight; + DoGetClientSize(&adjustedWidth, &adjustedHeight); + + QWidget *centralWidget = GetQMainWindow()->centralWidget(); + QRect geometry = centralWidget->geometry(); + geometry.setSize(QSize(adjustedWidth, adjustedHeight)); + centralWidget->setGeometry(geometry); +} + QMainWindow *wxFrame::GetQMainWindow() const { return static_cast(m_qtWindow); diff --git a/src/qt/listbox.cpp b/src/qt/listbox.cpp index 0e395c4744..1408f6f9d2 100644 --- a/src/qt/listbox.cpp +++ b/src/qt/listbox.cpp @@ -19,31 +19,51 @@ public: wxQtListWidget( wxWindow *parent, wxListBox *handler ); private: - void clicked( const QModelIndex &index ); + void OnCurrentItemChange(QListWidgetItem *current, QListWidgetItem *previous); void doubleClicked( const QModelIndex &index ); + void itemChanged(QListWidgetItem *item); }; wxQtListWidget::wxQtListWidget( wxWindow *parent, wxListBox *handler ) : wxQtEventSignalHandler< QListWidget, wxListBox >( parent, handler ) { - connect(this, &QListWidget::clicked, this, &wxQtListWidget::clicked); + connect(this, &QListWidget::currentItemChanged, this, &wxQtListWidget::OnCurrentItemChange); connect(this, &QListWidget::doubleClicked, this, &wxQtListWidget::doubleClicked); + connect(this, &QListWidget::itemChanged, this, &wxQtListWidget::itemChanged); } -void wxQtListWidget::clicked(const QModelIndex &index ) +void wxQtListWidget::OnCurrentItemChange(QListWidgetItem *current, QListWidgetItem *) { + if ( !current ) + return; + wxListBox *handler = GetHandler(); if ( handler ) - handler->QtSendEvent(wxEVT_LISTBOX, index, true); + { + const QModelIndex &index = indexFromItem(current); + handler->QtSendEvent(wxEVT_LISTBOX, index.row(), true); + } } void wxQtListWidget::doubleClicked( const QModelIndex &index ) { wxListBox *handler = GetHandler(); if ( handler ) - handler->QtSendEvent(wxEVT_LISTBOX_DCLICK, index, true); + handler->QtSendEvent(wxEVT_LISTBOX_DCLICK, index.row(), true); } +void wxQtListWidget::itemChanged(QListWidgetItem *item) +{ + if ( item->flags() & Qt::ItemIsUserCheckable ) + { + wxListBox *handler = GetHandler(); + if ( handler ) + { + int rowIndex = this->row(item); + handler->QtSendEvent(wxEVT_CHECKLISTBOX, rowIndex, true); + } + } +} wxListBox::wxListBox() : m_qtListWidget(NULL) @@ -282,9 +302,9 @@ QWidget *wxListBox::GetHandle() const return m_qtListWidget; } -void wxListBox::QtSendEvent(wxEventType evtType, const QModelIndex &index, bool selected) +void wxListBox::QtSendEvent(wxEventType evtType, int rowIndex, bool selected) { - SendEvent(evtType, index.row(), selected); + SendEvent(evtType, rowIndex, selected); } QScrollArea *wxListBox::QtGetScrollBarsContainer() const diff --git a/src/qt/menuitem.cpp b/src/qt/menuitem.cpp index 1889702327..a2f84822d6 100644 --- a/src/qt/menuitem.cpp +++ b/src/qt/menuitem.cpp @@ -25,6 +25,10 @@ public: wxQtAction( wxMenu *parent, int id, const wxString &text, const wxString &help, wxItemKind kind, wxMenu *subMenu, wxMenuItem *handler ); + // Set the action shortcut to correspond to the accelerator specified by + // the given label. + void UpdateShortcutsFromLabel(const wxString& text); + private: void onActionTriggered( bool checked ); }; @@ -51,6 +55,8 @@ void wxMenuItem::SetItemLabel( const wxString &label ) { wxMenuItemBase::SetItemLabel( label ); + m_qtAction->UpdateShortcutsFromLabel( label ); + m_qtAction->setText( wxQtConvertString( label )); } @@ -161,8 +167,20 @@ wxQtAction::wxQtAction( wxMenu *parent, int id, const wxString &text, const wxSt } connect( this, &QAction::triggered, this, &wxQtAction::onActionTriggered ); + + UpdateShortcutsFromLabel( text ); } +void wxQtAction::UpdateShortcutsFromLabel(const wxString& text) +{ +#if wxUSE_ACCEL + const wxString accelStr = text.AfterFirst('\t'); + if ( !accelStr.empty() ) + { + setShortcut( QKeySequence( wxQtConvertString(accelStr) ) ); + } +#endif // wxUSE_ACCEL +} void wxQtAction::onActionTriggered( bool checked ) { diff --git a/src/qt/notebook.cpp b/src/qt/notebook.cpp index 0f4c2ae062..06c5439436 100644 --- a/src/qt/notebook.cpp +++ b/src/qt/notebook.cpp @@ -14,6 +14,7 @@ #include "wx/qt/private/winevent.h" #include +#include class wxQtTabWidget : public wxQtEventSignalHandler< QTabWidget, wxNotebook > { @@ -162,7 +163,10 @@ bool wxNotebook::InsertPage(size_t n, wxWindow *page, const wxString& text, wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const { - return sizePage; + QTabBar *tabBar = m_qtTabWidget->tabBar(); + const QSize &tabBarSize = tabBar->size(); + return wxSize(sizePage.GetWidth(), + sizePage.GetHeight() + tabBarSize.height()); } bool wxNotebook::DeleteAllPages() @@ -192,8 +196,8 @@ int wxNotebook::SetSelection(size_t page) int selOld = GetSelection(); // change the QTabWidget selected page: - m_selection = page; m_qtTabWidget->setCurrentIndex( page ); + m_selection = page; return selOld; } diff --git a/src/qt/slider.cpp b/src/qt/slider.cpp index 1b8e1f96a7..a97f78db60 100644 --- a/src/qt/slider.cpp +++ b/src/qt/slider.cpp @@ -80,6 +80,7 @@ bool wxSlider::Create(wxWindow *parent, m_qtSlider->blockSignals(true); SetRange( minValue, maxValue ); m_qtSlider->blockSignals(false); + SetPageSize(wxMax(1, (maxValue - minValue) / 10)); #if 0 // there are not normally ticks for a wxSlider // draw ticks marks (default bellow if horizontal, right if vertical): diff --git a/src/qt/stattext.cpp b/src/qt/stattext.cpp index 369d15f7e2..1aaa885277 100644 --- a/src/qt/stattext.cpp +++ b/src/qt/stattext.cpp @@ -47,7 +47,6 @@ bool wxStaticText::Create(wxWindow *parent, const wxString &name) { m_qtLabel = new wxQtStaticText( parent, this ); - m_qtLabel->setText( wxQtConvertString( label ) ); // Set the buddy to itself to get the mnemonic key but ensure that we don't have // any unwanted side effects, so disable the interaction: @@ -64,7 +63,12 @@ bool wxStaticText::Create(wxWindow *parent, else m_qtLabel->setAlignment(Qt::AlignLeft); - return QtCreateControl( parent, id, pos, size, style, wxDefaultValidator, name ); + if ( !QtCreateControl(parent, id, pos, size, style, wxDefaultValidator, name) ) + return false; + + SetLabel(label); + + return true; } void wxStaticText::SetLabel(const wxString& label) diff --git a/src/qt/treectrl.cpp b/src/qt/treectrl.cpp index 89325fba02..ef478911bb 100644 --- a/src/qt/treectrl.cpp +++ b/src/qt/treectrl.cpp @@ -23,6 +23,7 @@ #include #include +#include #include namespace @@ -142,6 +143,8 @@ public: this, &wxQTreeWidget::OnItemCollapsed); connect(this, &QTreeWidget::itemExpanded, this, &wxQTreeWidget::OnItemExpanded); + connect(verticalScrollBar(), &QScrollBar::valueChanged, + this, &wxQTreeWidget::OnTreeScrolled); setItemDelegate(&m_item_delegate); setDragEnabled(true); @@ -244,6 +247,12 @@ public: return m_placeHolderImage; } + void select(QTreeWidgetItem* item, QItemSelectionModel::SelectionFlag selectionFlag) + { + const QModelIndex &index = indexFromItem(item); + selectionModel()->select(index, selectionFlag); + } + protected: virtual void drawRow( QPainter *painter, @@ -432,6 +441,12 @@ private: EmitEvent(expandedEvent); } + void OnTreeScrolled(int) + { + if ( GetEditControl() != NULL ) + closeEditor(GetEditControl()->GetHandle(), QAbstractItemDelegate::RevertModelCache); + } + void tryStartDrag(const QMouseEvent *event) { wxEventType command = event->buttons() & Qt::RightButton @@ -448,14 +463,14 @@ private: tree_event.SetPoint(wxQtConvertPoint(event->pos())); - // Vetoed unless explicitly accepted. + // Client must explicitly accept drag and drop. Vetoed by default. tree_event.Veto(); EmitEvent(tree_event); if ( !tree_event.IsAllowed() ) { - setState(DragSelectingState); + setState(NoState); } } @@ -1158,25 +1173,19 @@ void wxTreeCtrl::Toggle(const wxTreeItemId& item) wxCHECK_RET(item.IsOk(), "invalid tree item"); QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); - qTreeItem->setSelected(!qTreeItem->isSelected()); + qTreeItem->setExpanded(!qTreeItem->isExpanded()); } void wxTreeCtrl::Unselect() { QTreeWidgetItem *current = m_qtTreeWidget->currentItem(); - if ( current != NULL ) - current->setSelected(false); + m_qtTreeWidget->select(current, QItemSelectionModel::Deselect); } void wxTreeCtrl::UnselectAll() { - QList selections = m_qtTreeWidget->selectedItems(); - const size_t selectedCount = selections.size(); - for ( size_t i = 0; i < selectedCount; ++i) - { - selections[i]->setSelected(false); - } + m_qtTreeWidget->selectionModel()->clearSelection(); } void wxTreeCtrl::SelectItem(const wxTreeItemId& item, bool select) @@ -1189,7 +1198,15 @@ void wxTreeCtrl::SelectItem(const wxTreeItemId& item, bool select) } QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); - qTreeItem->setSelected(select); + + if ( qTreeItem ) + { + m_qtTreeWidget->select(qTreeItem, select ? QItemSelectionModel::Select : QItemSelectionModel::Deselect); + if ( select && m_qtTreeWidget->selectionMode() == QTreeWidget::SingleSelection ) + { + m_qtTreeWidget->setCurrentItem(qTreeItem); + } + } } void wxTreeCtrl::SelectChildren(const wxTreeItemId& parent) @@ -1201,7 +1218,7 @@ void wxTreeCtrl::SelectChildren(const wxTreeItemId& parent) for ( int i = 0; i < childCount; ++i ) { - qTreeItem->child(i)->setSelected(true); + m_qtTreeWidget->select(qTreeItem->child(i), QItemSelectionModel::Select); } } diff --git a/src/qt/window.cpp b/src/qt/window.cpp index 7ccb774ab5..7a31b7a928 100644 --- a/src/qt/window.cpp +++ b/src/qt/window.cpp @@ -59,9 +59,10 @@ wxQtWidget::wxQtWidget( wxWindowQt *parent, wxWindowQt *handler ) class wxQtScrollArea : public wxQtEventSignalHandler< QScrollArea, wxWindowQt > { +public: + wxQtScrollArea(wxWindowQt *parent, wxWindowQt *handler); - public: - wxQtScrollArea( wxWindowQt *parent, wxWindowQt *handler ); + bool event(QEvent *e) wxOVERRIDE; }; wxQtScrollArea::wxQtScrollArea( wxWindowQt *parent, wxWindowQt *handler ) @@ -69,6 +70,27 @@ wxQtScrollArea::wxQtScrollArea( wxWindowQt *parent, wxWindowQt *handler ) { } +bool wxQtScrollArea::event(QEvent *e) +{ + wxWindowQt* handler = GetHandler(); + if ( handler && handler->HasCapture() ) + { + switch ( e->type() ) + { + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + case QEvent::Wheel: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + return viewportEvent(e); + default: + break; + } + } + return QScrollArea::event(e); +} + class wxQtInternalScrollBar : public wxQtEventSignalHandler< QScrollBar, wxWindowQt > { public: @@ -193,6 +215,30 @@ static const char WINDOW_POINTER_PROPERTY_NAME[] = "wxWindowPointer"; return const_cast< wxWindowQt * >( ( variant.value< const wxWindow * >() )); } +/* static */ +void wxWindowQt::QtSendSetCursorEvent(wxWindowQt* win, wxPoint posScreen) +{ + wxWindowQt* w = win; + for ( ;; ) + { + const wxPoint posClient = w->ScreenToClient(posScreen); + wxSetCursorEvent event(posClient.x, posClient.y); + event.SetEventObject(w); + + const bool processedEvtSetCursor = w->ProcessWindowEvent(event); + if ( processedEvtSetCursor && event.HasCursor() ) + { + win->SetCursor(event.GetCursor()); + return; + } + + w = w->GetParent(); + if ( w == NULL ) + break; + } + win->SetCursor(wxCursor(wxCURSOR_ARROW)); +} + static wxWindowQt *s_capturedWindow = NULL; /* static */ wxWindowQt *wxWindowBase::DoFindFocus() @@ -297,8 +343,6 @@ bool wxWindowQt::Create( wxWindowQt * parent, wxWindowID id, const wxPoint & pos m_qtWindow = new wxQtWidget( parent, this ); } - - GetHandle()->setMouseTracking(true); if ( !wxWindowBase::CreateBase( parent, id, pos, size, style, wxDefaultValidator, name )) return false; @@ -437,7 +481,7 @@ bool wxWindowQt::Reparent( wxWindowBase *parent ) if ( !wxWindowBase::Reparent( parent )) return false; - QtReparent( GetHandle(), parent->GetHandle() ); + QtReparent( GetHandle(), static_cast(parent)->QtGetParentWidget() ); return true; } @@ -560,6 +604,23 @@ void wxWindowQt::DoGetTextExtent(const wxString& string, int *x, int *y, int *de *externalLeading = fontMetrics.lineSpacing(); } +QWidget *wxWindowQt::QtGetClientWidget() const +{ + QWidget *qtWidget = NULL; + if ( m_qtContainer != NULL ) + { + qtWidget = m_qtContainer->viewport(); + } + + if ( qtWidget == NULL ) + { + // We don't have scrollbars or the QScrollArea has no children + qtWidget = GetHandle(); + } + + return qtWidget; +} + /* Returns a scrollbar for the given orientation, or NULL if the scrollbar * has not been previously created and create is false */ QScrollBar *wxWindowQt::QtGetScrollBar( int orientation ) const @@ -935,7 +996,10 @@ void wxWindowQt::DoSetSize(int x, int y, int width, int height, int sizeFlags ) void wxWindowQt::DoGetClientSize(int *width, int *height) const { - QRect geometry = GetHandle()->geometry(); + QWidget *qtWidget = QtGetClientWidget(); + wxCHECK_RET( qtWidget, "window must be created" ); + + const QRect geometry = qtWidget->geometry(); if (width) *width = geometry.width(); if (height) *height = geometry.height(); } @@ -943,7 +1007,9 @@ void wxWindowQt::DoGetClientSize(int *width, int *height) const void wxWindowQt::DoSetClientSize(int width, int height) { - QWidget *qtWidget = GetHandle(); + QWidget *qtWidget = QtGetClientWidget(); + wxCHECK_RET( qtWidget, "window must be created" ); + QRect geometry = qtWidget->geometry(); geometry.setWidth( width ); geometry.setHeight( height ); @@ -955,9 +1021,19 @@ void wxWindowQt::DoMoveWindow(int x, int y, int width, int height) QWidget *qtWidget = GetHandle(); qtWidget->move( x, y ); - qtWidget->resize( width, height ); -} + // There doesn't seem to be any way to change Qt frame size directly, so + // change the widget size, but take into account the extra margins + // corresponding to the frame decorations. + const QSize frameSize = qtWidget->frameSize(); + const QSize innerSize = qtWidget->geometry().size(); + const QSize frameSizeDiff = frameSize - innerSize; + + const int clientWidth = std::max(width - frameSizeDiff.width(), 0); + const int clientHeight = std::max(height - frameSizeDiff.height(), 0); + + qtWidget->resize(clientWidth, clientHeight); +} #if wxUSE_TOOLTIPS void wxWindowQt::QtApplyToolTip(const wxString& text) @@ -983,9 +1059,10 @@ void wxWindowQt::DoSetToolTip( wxToolTip *tip ) #if wxUSE_MENUS bool wxWindowQt::DoPopupMenu(wxMenu *menu, int x, int y) { + menu->UpdateUI(); menu->GetHandle()->exec( GetHandle()->mapToGlobal( QPoint( x, y ) ) ); - return ( true ); + return true; } #endif // wxUSE_MENUS @@ -1424,11 +1501,15 @@ bool wxWindowQt::QtHandleMouseEvent ( QWidget *handler, QMouseEvent *event ) } // Fill the event - QPoint mousePos = event->pos(); + + // Use screen position as the event might originate from a different + // Qt window than this one. + wxPoint mousePos = ScreenToClient(wxQtConvertPoint(event->globalPos())); + wxMouseEvent e( wxType ); e.SetEventObject(this); e.m_clickCount = -1; - e.SetPosition( wxQtConvertPoint( mousePos ) ); + e.SetPosition(mousePos); // Mouse buttons wxQtFillMouseButtons( event->buttons(), &e ); @@ -1440,8 +1521,8 @@ bool wxWindowQt::QtHandleMouseEvent ( QWidget *handler, QMouseEvent *event ) // Determine if mouse is inside the widget bool mouseInside = true; - if ( mousePos.x() < 0 || mousePos.x() > handler->width() || - mousePos.y() < 0 || mousePos.y() > handler->height() ) + if ( mousePos.x < 0 || mousePos.x > handler->width() || + mousePos.y < 0 || mousePos.y > handler->height() ) mouseInside = false; if ( e.GetEventType() == wxEVT_MOTION ) @@ -1460,6 +1541,8 @@ bool wxWindowQt::QtHandleMouseEvent ( QWidget *handler, QMouseEvent *event ) ProcessWindowEvent( e ); } + + QtSendSetCursorEvent(this, wxQtConvertPoint( event->globalPos())); } m_mouseInside = mouseInside; @@ -1521,18 +1604,27 @@ bool wxWindowQt::QtHandleChangeEvent ( QWidget *handler, QEvent *event ) return false; } +// Returns true if the closing should be vetoed and false if the window should be closed. bool wxWindowQt::QtHandleCloseEvent ( QWidget *handler, QCloseEvent *WXUNUSED( event ) ) { if ( GetHandle() != handler ) return false; - return Close(); + // This is required as Qt will still send out close events when the window is disabled. + if ( !IsEnabled() ) + return true; + + return !Close(); } bool wxWindowQt::QtHandleContextMenuEvent ( QWidget *WXUNUSED( handler ), QContextMenuEvent *event ) { wxContextMenuEvent e( wxEVT_CONTEXT_MENU, GetId() ); - e.SetPosition( wxQtConvertPoint( event->globalPos() ) ); + e.SetPosition( + event->reason() == QContextMenuEvent::Keyboard + ? wxDefaultPosition + : wxQtConvertPoint( event->globalPos() ) + ); e.SetEventObject(this); return ProcessWindowEvent( e ); diff --git a/tests/window/clientsize.cpp b/tests/window/clientsize.cpp index 27e13b4459..48d9ec8da3 100644 --- a/tests/window/clientsize.cpp +++ b/tests/window/clientsize.cpp @@ -21,78 +21,36 @@ #include "wx/window.h" #endif // WX_PRECOMP -// ---------------------------------------------------------------------------- -// test class -// ---------------------------------------------------------------------------- +#include "wx/scopedptr.h" -class ClientSizeTestCase : public CppUnit::TestCase -{ -public: - ClientSizeTestCase() { } - - virtual void setUp() wxOVERRIDE; - virtual void tearDown() wxOVERRIDE; - -private: - CPPUNIT_TEST_SUITE( ClientSizeTestCase ); - CPPUNIT_TEST( ClientToWindow ); - CPPUNIT_TEST( ClientSizeNotNegative ); - CPPUNIT_TEST( WindowToClient ); - CPPUNIT_TEST_SUITE_END(); - - void ClientToWindow(); - void ClientSizeNotNegative(); - void WindowToClient(); - - wxWindow *m_win; - - wxDECLARE_NO_COPY_CLASS(ClientSizeTestCase); -}; - -// register in the unnamed registry so that these tests are run by default -CPPUNIT_TEST_SUITE_REGISTRATION( ClientSizeTestCase ); - -// also include in its own registry so that these tests can be run alone -CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ClientSizeTestCase, "ClientSizeTestCase" ); - -// ---------------------------------------------------------------------------- -// test initialization -// ---------------------------------------------------------------------------- - -void ClientSizeTestCase::setUp() -{ - m_win = wxTheApp->GetTopWindow(); -} - -void ClientSizeTestCase::tearDown() -{ - m_win = NULL; -} +#include "asserthelper.h" // ---------------------------------------------------------------------------- // tests themselves // ---------------------------------------------------------------------------- -void ClientSizeTestCase::ClientToWindow() +TEST_CASE("wxWindow::ClientWindowSizeRoundTrip", "[window][client-size]") { - CPPUNIT_ASSERT(m_win->GetSize() == - m_win->ClientToWindowSize(m_win->GetClientSize())); + wxWindow* const w = wxTheApp->GetTopWindow(); + REQUIRE( w ); + + const wxSize sizeWindow = w->GetSize(); + const wxSize sizeClient = w->GetClientSize(); + + INFO("client size: " << sizeClient); + CHECK( sizeWindow == w->ClientToWindowSize(sizeClient) ); + + INFO("window size: " << sizeWindow); + CHECK( sizeClient == w->WindowToClientSize(sizeWindow) ); } -void ClientSizeTestCase::ClientSizeNotNegative() +TEST_CASE("wxWindow::MinClientSize", "[window][client-size]") { - wxWindow* w = new wxWindow(wxTheApp->GetTopWindow(), -1, - wxDefaultPosition, wxDefaultSize, - wxBORDER_THEME); + wxScopedPtr w(new wxWindow(wxTheApp->GetTopWindow(), wxID_ANY, + wxDefaultPosition, wxDefaultSize, + wxBORDER_THEME)); w->SetSize(wxSize(1,1)); const wxSize szw = w->GetClientSize(); - CPPUNIT_ASSERT(szw.GetWidth() >= 0); - CPPUNIT_ASSERT(szw.GetHeight() >= 0); - w->Destroy(); -} - -void ClientSizeTestCase::WindowToClient() -{ - CPPUNIT_ASSERT(m_win->GetClientSize() == - m_win->WindowToClientSize(m_win->GetSize())); + CHECK(szw.GetWidth() >= 0); + CHECK(szw.GetHeight() >= 0); } diff --git a/tests/window/setsize.cpp b/tests/window/setsize.cpp index d99200ac52..81b3eeb8d5 100644 --- a/tests/window/setsize.cpp +++ b/tests/window/setsize.cpp @@ -18,100 +18,136 @@ #ifndef WX_PRECOMP #include "wx/app.h" + #include "wx/frame.h" #include "wx/window.h" #endif // WX_PRECOMP +#include "wx/scopedptr.h" +#include "wx/stopwatch.h" + #include "asserthelper.h" // ---------------------------------------------------------------------------- -// test class +// tests helpers // ---------------------------------------------------------------------------- -class SetSizeTestCase : public CppUnit::TestCase +namespace +{ + +// Helper class overriding DoGetBestSize() for testing purposes. +class MyWindow : public wxWindow { public: - SetSizeTestCase() { } - - virtual void setUp() wxOVERRIDE; - virtual void tearDown() wxOVERRIDE; - -private: - CPPUNIT_TEST_SUITE( SetSizeTestCase ); - CPPUNIT_TEST( SetSize ); - CPPUNIT_TEST( SetSizeLessThanMinSize ); - CPPUNIT_TEST( BestSize ); - CPPUNIT_TEST_SUITE_END(); - - void SetSize(); - void SetSizeLessThanMinSize(); - void BestSize(); - - // Helper class overriding DoGetBestSize() for testing purposes. - class MyWindow : public wxWindow + MyWindow(wxWindow* parent) + : wxWindow(parent, wxID_ANY) { - public: - MyWindow(wxWindow* parent) - : wxWindow(parent, wxID_ANY) - { - } + } - protected: - virtual wxSize DoGetBestSize() const wxOVERRIDE { return wxSize(50, 250); } - }; - - wxWindow *m_win; - - wxDECLARE_NO_COPY_CLASS(SetSizeTestCase); +protected: + virtual wxSize DoGetBestSize() const wxOVERRIDE { return wxSize(50, 250); } }; -// register in the unnamed registry so that these tests are run by default -CPPUNIT_TEST_SUITE_REGISTRATION( SetSizeTestCase ); - -// also include in its own registry so that these tests can be run alone -CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( SetSizeTestCase, "SetSizeTestCase" ); - -// ---------------------------------------------------------------------------- -// test initialization -// ---------------------------------------------------------------------------- - -void SetSizeTestCase::setUp() +// Class used to check if we received the (first) paint event. +class WaitForPaint { - m_win = new MyWindow(wxTheApp->GetTopWindow()); +public: + // Note that we have to use a pointer here, i.e. we can't just store the + // flag inside the class itself because it's going to be cloned inside wx + // and querying the flag of the original copy is not going to work. + explicit WaitForPaint(bool* painted) + : m_painted(*painted) + { + m_painted = false; + } + + void operator()(wxPaintEvent& event) + { + event.Skip(); + m_painted = true; + } + +private: + bool& m_painted; +}; + +// This function should be used to show the window and wait until we can get +// its real geometry. +void ShowAndWaitForPaint(wxWindow* w) +{ + // Unfortunately showing the window is asynchronous, at least when using + // X11, so we have to wait for some time before retrieving its true + // geometry. And it's not clear how long should we wait, so we do it until + // we get the first paint event -- by then the window really should have + // its final size. + bool painted; + WaitForPaint waitForPaint(&painted); + w->Bind(wxEVT_PAINT, waitForPaint); + + w->Show(); + + wxStopWatch sw; + while ( !painted ) + { + wxYield(); + + if ( sw.Time() > 250 ) + { + WARN("Didn't get a paint event until timeout expiration"); + break; + } + } } -void SetSizeTestCase::tearDown() -{ - delete m_win; - m_win = NULL; -} +} // anonymous namespace // ---------------------------------------------------------------------------- // tests themselves // ---------------------------------------------------------------------------- -void SetSizeTestCase::SetSize() +TEST_CASE("wxWindow::SetSize", "[window][size]") { - const wxSize size(127, 35); - m_win->SetSize(size); - CPPUNIT_ASSERT_EQUAL( size, m_win->GetSize() ); + wxScopedPtr w(new MyWindow(wxTheApp->GetTopWindow())); + + SECTION("Simple") + { + const wxSize size(127, 35); + w->SetSize(size); + CHECK( size == w->GetSize() ); + } + + SECTION("With min size") + { + w->SetMinSize(wxSize(100, 100)); + + const wxSize size(200, 50); + w->SetSize(size); + CHECK( size == w->GetSize() ); + } } -void SetSizeTestCase::SetSizeLessThanMinSize() +TEST_CASE("wxWindow::GetBestSize", "[window][size][best-size]") { - m_win->SetMinSize(wxSize(100, 100)); + wxScopedPtr w(new MyWindow(wxTheApp->GetTopWindow())); - const wxSize size(200, 50); - m_win->SetSize(size); - CPPUNIT_ASSERT_EQUAL( size, m_win->GetSize() ); + CHECK( wxSize(50, 250) == w->GetBestSize() ); + + w->SetMinSize(wxSize(100, 100)); + CHECK( wxSize(100, 250) == w->GetBestSize() ); + + w->SetMaxSize(wxSize(200, 200)); + CHECK( wxSize(100, 200) == w->GetBestSize() ); } -void SetSizeTestCase::BestSize() +TEST_CASE("wxWindow::MovePreservesSize", "[window][size][move]") { - CPPUNIT_ASSERT_EQUAL( wxSize(50, 250), m_win->GetBestSize() ); + wxScopedPtr + w(new wxFrame(wxTheApp->GetTopWindow(), wxID_ANY, "Test child frame")); - m_win->SetMinSize(wxSize(100, 100)); - CPPUNIT_ASSERT_EQUAL( wxSize(100, 250), m_win->GetBestSize() ); + ShowAndWaitForPaint(w.get()); - m_win->SetMaxSize(wxSize(200, 200)); - CPPUNIT_ASSERT_EQUAL( wxSize(100, 200), m_win->GetBestSize() ); + const wxRect rectOrig = w->GetRect(); + + // Check that moving the window doesn't change its size. + w->Move(rectOrig.GetPosition() + wxPoint(100, 100)); + CHECK( w->GetSize() == rectOrig.GetSize() ); }