Merge branch 'qt-fixes'

A multitude of miscellaneous Qt fixes and improvements.

See https://github.com/wxWidgets/wxWidgets/pull/1552
This commit is contained in:
Vadim Zeitlin
2019-09-27 19:18:11 +02:00
20 changed files with 392 additions and 183 deletions

View File

@@ -56,6 +56,9 @@ public:
protected: protected:
virtual void DoGetClientSize(int *width, int *height) const wxOVERRIDE; virtual void DoGetClientSize(int *width, int *height) const wxOVERRIDE;
virtual void DoSetClientSize(int width, int height) wxOVERRIDE;
virtual QWidget* QtGetParentWidget() const wxOVERRIDE;
private: private:
// Common part of all ctors. // Common part of all ctors.

View File

@@ -60,7 +60,7 @@ public:
virtual QWidget *GetHandle() const wxOVERRIDE; virtual QWidget *GetHandle() const wxOVERRIDE;
void QtSendEvent(wxEventType evtType, const QModelIndex &index, bool selected); void QtSendEvent(wxEventType evtType, int rowIndex, bool selected);
protected: protected:
virtual void DoSetFirstItem(int n) wxOVERRIDE; virtual void DoSetFirstItem(int n) wxOVERRIDE;

View File

@@ -12,6 +12,7 @@
#include "wx/bitmap.h" #include "wx/bitmap.h"
class QAction; class QAction;
class wxQtAction;
class WXDLLIMPEXP_FWD_CORE wxMenu; class WXDLLIMPEXP_FWD_CORE wxMenu;
@@ -41,7 +42,7 @@ public:
private: private:
// Qt is using an action instead of a menu item. // Qt is using an action instead of a menu item.
QAction *m_qtAction; wxQtAction *m_qtAction;
wxBitmap m_bitmap; wxBitmap m_bitmap;
wxDECLARE_DYNAMIC_CLASS( wxMenuItem ); wxDECLARE_DYNAMIC_CLASS( wxMenuItem );

View File

@@ -11,6 +11,7 @@
#define _WX_QT_PRIVATE_TREEITEM_DELEGATE_H #define _WX_QT_PRIVATE_TREEITEM_DELEGATE_H
#include <QtWidgets/QStyledItemDelegate> #include <QtWidgets/QStyledItemDelegate>
#include <QtWidgets/QToolTip>
#include "wx/app.h" #include "wx/app.h"
#include "wx/textctrl.h" #include "wx/textctrl.h"
@@ -67,6 +68,28 @@ public:
QStyledItemDelegate::setModelData(editor, model, index); 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: private:
wxWindow* m_parent; wxWindow* m_parent;
mutable wxTextCtrl* m_textCtrl; mutable wxTextCtrl* m_textCtrl;

View File

@@ -61,6 +61,7 @@ public:
QObject::connect( this, &QObject::destroyed, this, QObject::connect( this, &QObject::destroyed, this,
&wxQtEventSignalHandler::HandleDestroyedSignal ); &wxQtEventSignalHandler::HandleDestroyedSignal );
Widget::setMouseTracking(true);
} }
void HandleDestroyedSignal() void HandleDestroyedSignal()
@@ -104,7 +105,7 @@ protected:
if ( !this->GetHandler()->QtHandleCloseEvent(this, event) ) if ( !this->GetHandler()->QtHandleCloseEvent(this, event) )
Widget::closeEvent(event); Widget::closeEvent(event);
else else
event->accept(); event->ignore();
} }
//wxContextMenuEvent //wxContextMenuEvent

View File

@@ -168,6 +168,7 @@ public:
static void QtStoreWindowPointer( QWidget *widget, const wxWindowQt *window ); static void QtStoreWindowPointer( QWidget *widget, const wxWindowQt *window );
static wxWindowQt *QtRetrieveWindowPointer( const QWidget *widget ); static wxWindowQt *QtRetrieveWindowPointer( const QWidget *widget );
static void QtSendSetCursorEvent(wxWindowQt* win, wxPoint posClient);
#if wxUSE_ACCEL #if wxUSE_ACCEL
virtual void QtHandleShortcut ( int command ); virtual void QtHandleShortcut ( int command );
@@ -215,6 +216,12 @@ protected:
virtual bool DoPopupMenu(wxMenu *menu, int x, int y) wxOVERRIDE; virtual bool DoPopupMenu(wxMenu *menu, int x, int y) wxOVERRIDE;
#endif // wxUSE_MENUS #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; QWidget *m_qtWindow;
private: private:
@@ -224,6 +231,11 @@ private:
QScrollBar *m_horzScrollBar; // owned by m_qtWindow when allocated QScrollBar *m_horzScrollBar; // owned by m_qtWindow when allocated
QScrollBar *m_vertScrollBar; // 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 *QtGetScrollBar( int orientation ) const;
QScrollBar *QtSetScrollBar( int orientation, QScrollBar *scrollBar=NULL ); QScrollBar *QtSetScrollBar( int orientation, QScrollBar *scrollBar=NULL );

View File

@@ -848,7 +848,7 @@ void wxAuiManager::UpdateHintWindowConfig()
if ((m_flags & wxAUI_MGR_TRANSPARENT_HINT) && can_do_transparent) if ((m_flags & wxAUI_MGR_TRANSPARENT_HINT) && can_do_transparent)
{ {
// Make a window to use for a transparent hint // 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, m_hintWnd = new wxFrame(m_frame, wxID_ANY, wxEmptyString,
wxDefaultPosition, wxSize(1,1), wxDefaultPosition, wxSize(1,1),
wxFRAME_TOOL_WINDOW | wxFRAME_TOOL_WINDOW |

View File

@@ -85,8 +85,9 @@ wxAnyButton::wxAnyButton() :
void wxAnyButton::QtCreate(wxWindow *parent) void wxAnyButton::QtCreate(wxWindow *parent)
{ {
// create the default push button (used in button and bmp button) // create the basic push button (used in button and bmp button)
m_qtPushButton = new wxQtPushButton( parent, this ); m_qtPushButton = new wxQtPushButton(parent, this);
m_qtPushButton->setAutoDefault(false);
} }
void wxAnyButton::QtSetBitmap( const wxBitmap &bitmap ) void wxAnyButton::QtSetBitmap( const wxBitmap &bitmap )

View File

@@ -16,10 +16,10 @@
#include "wx/qt/private/converter.h" #include "wx/qt/private/converter.h"
#include <QDrag> #include <QtGui/QDrag>
#include <QWidget> #include <QtWidgets/QWidget>
#include <QMimeData> #include <QtCore/QMimeData>
#include <QCloseEvent> #include <QtGui/QCloseEvent>
namespace namespace
{ {

View File

@@ -563,7 +563,7 @@ void wxNativeFontInfo::SetFamily(wxFontFamily family)
{ {
m_qtFont.setStyleHint(ConvertFontFamily(family)); m_qtFont.setStyleHint(ConvertFontFamily(family));
// reset the face name to force qt to choose a new font // 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)) void wxNativeFontInfo::SetEncoding(wxFontEncoding WXUNUSED(encoding))

View File

@@ -134,15 +134,16 @@ void wxFrame::SetWindowStyleFlag( long style )
{ {
wxWindow::SetWindowStyleFlag( style ); wxWindow::SetWindowStyleFlag( style );
QMainWindow *qtFrame = GetQMainWindow(); Qt::WindowFlags qtFlags = Qt::CustomizeWindowHint;
Qt::WindowFlags qtFlags = qtFrame->windowFlags();
qtFlags |= Qt::CustomizeWindowHint;
if ( HasFlag( wxFRAME_TOOL_WINDOW ) ) if ( HasFlag( wxFRAME_TOOL_WINDOW ) )
{ {
qtFlags &= ~Qt::WindowType_Mask;
qtFlags |= Qt::Tool; qtFlags |= Qt::Tool;
} }
else
{
qtFlags |= Qt::Window;
}
if ( HasFlag(wxCAPTION) ) if ( HasFlag(wxCAPTION) )
{ {
@@ -183,15 +184,19 @@ void wxFrame::SetWindowStyleFlag( long style )
qtFlags |= Qt::FramelessWindowHint; qtFlags |= Qt::FramelessWindowHint;
} }
qtFrame->setWindowFlags(qtFlags); GetQMainWindow()->setWindowFlags(qtFlags);
}
QWidget* wxFrame::QtGetParentWidget() const
{
return GetQMainWindow()->centralWidget();
} }
void wxFrame::AddChild( wxWindowBase *child ) void wxFrame::AddChild( wxWindowBase *child )
{ {
// Make sure all children are children of the central widget: // Make sure all children are children of the central widget:
QtReparent( child->GetHandle(), GetQMainWindow()->centralWidget() ); QtReparent( child->GetHandle(), QtGetParentWidget() );
wxFrameBase::AddChild( child ); 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 QMainWindow *wxFrame::GetQMainWindow() const
{ {
return static_cast<QMainWindow*>(m_qtWindow); return static_cast<QMainWindow*>(m_qtWindow);

View File

@@ -19,31 +19,51 @@ public:
wxQtListWidget( wxWindow *parent, wxListBox *handler ); wxQtListWidget( wxWindow *parent, wxListBox *handler );
private: private:
void clicked( const QModelIndex &index ); void OnCurrentItemChange(QListWidgetItem *current, QListWidgetItem *previous);
void doubleClicked( const QModelIndex &index ); void doubleClicked( const QModelIndex &index );
void itemChanged(QListWidgetItem *item);
}; };
wxQtListWidget::wxQtListWidget( wxWindow *parent, wxListBox *handler ) wxQtListWidget::wxQtListWidget( wxWindow *parent, wxListBox *handler )
: wxQtEventSignalHandler< QListWidget, wxListBox >( parent, 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::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(); wxListBox *handler = GetHandler();
if ( handler ) 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 ) void wxQtListWidget::doubleClicked( const QModelIndex &index )
{ {
wxListBox *handler = GetHandler(); wxListBox *handler = GetHandler();
if ( handler ) 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() : wxListBox::wxListBox() :
m_qtListWidget(NULL) m_qtListWidget(NULL)
@@ -282,9 +302,9 @@ QWidget *wxListBox::GetHandle() const
return m_qtListWidget; 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 QScrollArea *wxListBox::QtGetScrollBarsContainer() const

View File

@@ -25,6 +25,10 @@ public:
wxQtAction( wxMenu *parent, int id, const wxString &text, const wxString &help, wxQtAction( wxMenu *parent, int id, const wxString &text, const wxString &help,
wxItemKind kind, wxMenu *subMenu, wxMenuItem *handler ); 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: private:
void onActionTriggered( bool checked ); void onActionTriggered( bool checked );
}; };
@@ -51,6 +55,8 @@ void wxMenuItem::SetItemLabel( const wxString &label )
{ {
wxMenuItemBase::SetItemLabel( label ); wxMenuItemBase::SetItemLabel( label );
m_qtAction->UpdateShortcutsFromLabel( label );
m_qtAction->setText( wxQtConvertString( 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 ); 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 ) void wxQtAction::onActionTriggered( bool checked )
{ {

View File

@@ -14,6 +14,7 @@
#include "wx/qt/private/winevent.h" #include "wx/qt/private/winevent.h"
#include <QtWidgets/QTabWidget> #include <QtWidgets/QTabWidget>
#include <QtWidgets/QTabBar>
class wxQtTabWidget : public wxQtEventSignalHandler< QTabWidget, wxNotebook > 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 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() bool wxNotebook::DeleteAllPages()
@@ -192,8 +196,8 @@ int wxNotebook::SetSelection(size_t page)
int selOld = GetSelection(); int selOld = GetSelection();
// change the QTabWidget selected page: // change the QTabWidget selected page:
m_selection = page;
m_qtTabWidget->setCurrentIndex( page ); m_qtTabWidget->setCurrentIndex( page );
m_selection = page;
return selOld; return selOld;
} }

View File

@@ -80,6 +80,7 @@ bool wxSlider::Create(wxWindow *parent,
m_qtSlider->blockSignals(true); m_qtSlider->blockSignals(true);
SetRange( minValue, maxValue ); SetRange( minValue, maxValue );
m_qtSlider->blockSignals(false); m_qtSlider->blockSignals(false);
SetPageSize(wxMax(1, (maxValue - minValue) / 10));
#if 0 // there are not normally ticks for a wxSlider #if 0 // there are not normally ticks for a wxSlider
// draw ticks marks (default bellow if horizontal, right if vertical): // draw ticks marks (default bellow if horizontal, right if vertical):

View File

@@ -47,7 +47,6 @@ bool wxStaticText::Create(wxWindow *parent,
const wxString &name) const wxString &name)
{ {
m_qtLabel = new wxQtStaticText( parent, this ); 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 // 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: // any unwanted side effects, so disable the interaction:
@@ -64,7 +63,12 @@ bool wxStaticText::Create(wxWindow *parent,
else else
m_qtLabel->setAlignment(Qt::AlignLeft); 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) void wxStaticText::SetLabel(const wxString& label)

View File

@@ -23,6 +23,7 @@
#include <QtWidgets/QTreeWidget> #include <QtWidgets/QTreeWidget>
#include <QtWidgets/QHeaderView> #include <QtWidgets/QHeaderView>
#include <QtWidgets/QScrollBar>
#include <QtGui/QPainter> #include <QtGui/QPainter>
namespace namespace
@@ -142,6 +143,8 @@ public:
this, &wxQTreeWidget::OnItemCollapsed); this, &wxQTreeWidget::OnItemCollapsed);
connect(this, &QTreeWidget::itemExpanded, connect(this, &QTreeWidget::itemExpanded,
this, &wxQTreeWidget::OnItemExpanded); this, &wxQTreeWidget::OnItemExpanded);
connect(verticalScrollBar(), &QScrollBar::valueChanged,
this, &wxQTreeWidget::OnTreeScrolled);
setItemDelegate(&m_item_delegate); setItemDelegate(&m_item_delegate);
setDragEnabled(true); setDragEnabled(true);
@@ -244,6 +247,12 @@ public:
return m_placeHolderImage; return m_placeHolderImage;
} }
void select(QTreeWidgetItem* item, QItemSelectionModel::SelectionFlag selectionFlag)
{
const QModelIndex &index = indexFromItem(item);
selectionModel()->select(index, selectionFlag);
}
protected: protected:
virtual void drawRow( virtual void drawRow(
QPainter *painter, QPainter *painter,
@@ -432,6 +441,12 @@ private:
EmitEvent(expandedEvent); EmitEvent(expandedEvent);
} }
void OnTreeScrolled(int)
{
if ( GetEditControl() != NULL )
closeEditor(GetEditControl()->GetHandle(), QAbstractItemDelegate::RevertModelCache);
}
void tryStartDrag(const QMouseEvent *event) void tryStartDrag(const QMouseEvent *event)
{ {
wxEventType command = event->buttons() & Qt::RightButton wxEventType command = event->buttons() & Qt::RightButton
@@ -448,14 +463,14 @@ private:
tree_event.SetPoint(wxQtConvertPoint(event->pos())); tree_event.SetPoint(wxQtConvertPoint(event->pos()));
// Vetoed unless explicitly accepted. // Client must explicitly accept drag and drop. Vetoed by default.
tree_event.Veto(); tree_event.Veto();
EmitEvent(tree_event); EmitEvent(tree_event);
if ( !tree_event.IsAllowed() ) 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"); wxCHECK_RET(item.IsOk(), "invalid tree item");
QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item);
qTreeItem->setSelected(!qTreeItem->isSelected()); qTreeItem->setExpanded(!qTreeItem->isExpanded());
} }
void wxTreeCtrl::Unselect() void wxTreeCtrl::Unselect()
{ {
QTreeWidgetItem *current = m_qtTreeWidget->currentItem(); QTreeWidgetItem *current = m_qtTreeWidget->currentItem();
if ( current != NULL ) if ( current != NULL )
current->setSelected(false); m_qtTreeWidget->select(current, QItemSelectionModel::Deselect);
} }
void wxTreeCtrl::UnselectAll() void wxTreeCtrl::UnselectAll()
{ {
QList<QTreeWidgetItem *> selections = m_qtTreeWidget->selectedItems(); m_qtTreeWidget->selectionModel()->clearSelection();
const size_t selectedCount = selections.size();
for ( size_t i = 0; i < selectedCount; ++i)
{
selections[i]->setSelected(false);
}
} }
void wxTreeCtrl::SelectItem(const wxTreeItemId& item, bool select) void wxTreeCtrl::SelectItem(const wxTreeItemId& item, bool select)
@@ -1189,7 +1198,15 @@ void wxTreeCtrl::SelectItem(const wxTreeItemId& item, bool select)
} }
QTreeWidgetItem *qTreeItem = wxQtConvertTreeItem(item); 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) void wxTreeCtrl::SelectChildren(const wxTreeItemId& parent)
@@ -1201,7 +1218,7 @@ void wxTreeCtrl::SelectChildren(const wxTreeItemId& parent)
for ( int i = 0; i < childCount; ++i ) for ( int i = 0; i < childCount; ++i )
{ {
qTreeItem->child(i)->setSelected(true); m_qtTreeWidget->select(qTreeItem->child(i), QItemSelectionModel::Select);
} }
} }

View File

@@ -59,9 +59,10 @@ wxQtWidget::wxQtWidget( wxWindowQt *parent, wxWindowQt *handler )
class wxQtScrollArea : public wxQtEventSignalHandler< QScrollArea, wxWindowQt > class wxQtScrollArea : public wxQtEventSignalHandler< QScrollArea, wxWindowQt >
{ {
public:
wxQtScrollArea(wxWindowQt *parent, wxWindowQt *handler);
public: bool event(QEvent *e) wxOVERRIDE;
wxQtScrollArea( wxWindowQt *parent, wxWindowQt *handler );
}; };
wxQtScrollArea::wxQtScrollArea( wxWindowQt *parent, wxWindowQt *handler ) 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 > class wxQtInternalScrollBar : public wxQtEventSignalHandler< QScrollBar, wxWindowQt >
{ {
public: public:
@@ -193,6 +215,30 @@ static const char WINDOW_POINTER_PROPERTY_NAME[] = "wxWindowPointer";
return const_cast< wxWindowQt * >( ( variant.value< const wxWindow * >() )); 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 *s_capturedWindow = NULL;
/* static */ wxWindowQt *wxWindowBase::DoFindFocus() /* static */ wxWindowQt *wxWindowBase::DoFindFocus()
@@ -297,8 +343,6 @@ bool wxWindowQt::Create( wxWindowQt * parent, wxWindowID id, const wxPoint & pos
m_qtWindow = new wxQtWidget( parent, this ); m_qtWindow = new wxQtWidget( parent, this );
} }
GetHandle()->setMouseTracking(true);
if ( !wxWindowBase::CreateBase( parent, id, pos, size, style, wxDefaultValidator, name )) if ( !wxWindowBase::CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
return false; return false;
@@ -437,7 +481,7 @@ bool wxWindowQt::Reparent( wxWindowBase *parent )
if ( !wxWindowBase::Reparent( parent )) if ( !wxWindowBase::Reparent( parent ))
return false; return false;
QtReparent( GetHandle(), parent->GetHandle() ); QtReparent( GetHandle(), static_cast<wxWindow*>(parent)->QtGetParentWidget() );
return true; return true;
} }
@@ -560,6 +604,23 @@ void wxWindowQt::DoGetTextExtent(const wxString& string, int *x, int *y, int *de
*externalLeading = fontMetrics.lineSpacing(); *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 /* Returns a scrollbar for the given orientation, or NULL if the scrollbar
* has not been previously created and create is false */ * has not been previously created and create is false */
QScrollBar *wxWindowQt::QtGetScrollBar( int orientation ) const 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 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 (width) *width = geometry.width();
if (height) *height = geometry.height(); if (height) *height = geometry.height();
} }
@@ -943,7 +1007,9 @@ void wxWindowQt::DoGetClientSize(int *width, int *height) const
void wxWindowQt::DoSetClientSize(int width, int height) void wxWindowQt::DoSetClientSize(int width, int height)
{ {
QWidget *qtWidget = GetHandle(); QWidget *qtWidget = QtGetClientWidget();
wxCHECK_RET( qtWidget, "window must be created" );
QRect geometry = qtWidget->geometry(); QRect geometry = qtWidget->geometry();
geometry.setWidth( width ); geometry.setWidth( width );
geometry.setHeight( height ); geometry.setHeight( height );
@@ -955,9 +1021,19 @@ void wxWindowQt::DoMoveWindow(int x, int y, int width, int height)
QWidget *qtWidget = GetHandle(); QWidget *qtWidget = GetHandle();
qtWidget->move( x, y ); 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 #if wxUSE_TOOLTIPS
void wxWindowQt::QtApplyToolTip(const wxString& text) void wxWindowQt::QtApplyToolTip(const wxString& text)
@@ -983,9 +1059,10 @@ void wxWindowQt::DoSetToolTip( wxToolTip *tip )
#if wxUSE_MENUS #if wxUSE_MENUS
bool wxWindowQt::DoPopupMenu(wxMenu *menu, int x, int y) bool wxWindowQt::DoPopupMenu(wxMenu *menu, int x, int y)
{ {
menu->UpdateUI();
menu->GetHandle()->exec( GetHandle()->mapToGlobal( QPoint( x, y ) ) ); menu->GetHandle()->exec( GetHandle()->mapToGlobal( QPoint( x, y ) ) );
return ( true ); return true;
} }
#endif // wxUSE_MENUS #endif // wxUSE_MENUS
@@ -1424,11 +1501,15 @@ bool wxWindowQt::QtHandleMouseEvent ( QWidget *handler, QMouseEvent *event )
} }
// Fill the 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 ); wxMouseEvent e( wxType );
e.SetEventObject(this); e.SetEventObject(this);
e.m_clickCount = -1; e.m_clickCount = -1;
e.SetPosition( wxQtConvertPoint( mousePos ) ); e.SetPosition(mousePos);
// Mouse buttons // Mouse buttons
wxQtFillMouseButtons( event->buttons(), &e ); wxQtFillMouseButtons( event->buttons(), &e );
@@ -1440,8 +1521,8 @@ bool wxWindowQt::QtHandleMouseEvent ( QWidget *handler, QMouseEvent *event )
// Determine if mouse is inside the widget // Determine if mouse is inside the widget
bool mouseInside = true; bool mouseInside = true;
if ( mousePos.x() < 0 || mousePos.x() > handler->width() || if ( mousePos.x < 0 || mousePos.x > handler->width() ||
mousePos.y() < 0 || mousePos.y() > handler->height() ) mousePos.y < 0 || mousePos.y > handler->height() )
mouseInside = false; mouseInside = false;
if ( e.GetEventType() == wxEVT_MOTION ) if ( e.GetEventType() == wxEVT_MOTION )
@@ -1460,6 +1541,8 @@ bool wxWindowQt::QtHandleMouseEvent ( QWidget *handler, QMouseEvent *event )
ProcessWindowEvent( e ); ProcessWindowEvent( e );
} }
QtSendSetCursorEvent(this, wxQtConvertPoint( event->globalPos()));
} }
m_mouseInside = mouseInside; m_mouseInside = mouseInside;
@@ -1521,18 +1604,27 @@ bool wxWindowQt::QtHandleChangeEvent ( QWidget *handler, QEvent *event )
return false; 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 ) ) bool wxWindowQt::QtHandleCloseEvent ( QWidget *handler, QCloseEvent *WXUNUSED( event ) )
{ {
if ( GetHandle() != handler ) if ( GetHandle() != handler )
return false; 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 ) bool wxWindowQt::QtHandleContextMenuEvent ( QWidget *WXUNUSED( handler ), QContextMenuEvent *event )
{ {
wxContextMenuEvent e( wxEVT_CONTEXT_MENU, GetId() ); wxContextMenuEvent e( wxEVT_CONTEXT_MENU, GetId() );
e.SetPosition( wxQtConvertPoint( event->globalPos() ) ); e.SetPosition(
event->reason() == QContextMenuEvent::Keyboard
? wxDefaultPosition
: wxQtConvertPoint( event->globalPos() )
);
e.SetEventObject(this); e.SetEventObject(this);
return ProcessWindowEvent( e ); return ProcessWindowEvent( e );

View File

@@ -21,78 +21,36 @@
#include "wx/window.h" #include "wx/window.h"
#endif // WX_PRECOMP #endif // WX_PRECOMP
// ---------------------------------------------------------------------------- #include "wx/scopedptr.h"
// test class
// ----------------------------------------------------------------------------
class ClientSizeTestCase : public CppUnit::TestCase #include "asserthelper.h"
{
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;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// tests themselves // tests themselves
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void ClientSizeTestCase::ClientToWindow() TEST_CASE("wxWindow::ClientWindowSizeRoundTrip", "[window][client-size]")
{ {
CPPUNIT_ASSERT(m_win->GetSize() == wxWindow* const w = wxTheApp->GetTopWindow();
m_win->ClientToWindowSize(m_win->GetClientSize())); 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, wxScopedPtr<wxWindow> w(new wxWindow(wxTheApp->GetTopWindow(), wxID_ANY,
wxDefaultPosition, wxDefaultSize, wxDefaultPosition, wxDefaultSize,
wxBORDER_THEME); wxBORDER_THEME));
w->SetSize(wxSize(1,1)); w->SetSize(wxSize(1,1));
const wxSize szw = w->GetClientSize(); const wxSize szw = w->GetClientSize();
CPPUNIT_ASSERT(szw.GetWidth() >= 0); CHECK(szw.GetWidth() >= 0);
CPPUNIT_ASSERT(szw.GetHeight() >= 0); CHECK(szw.GetHeight() >= 0);
w->Destroy();
}
void ClientSizeTestCase::WindowToClient()
{
CPPUNIT_ASSERT(m_win->GetClientSize() ==
m_win->WindowToClientSize(m_win->GetSize()));
} }

View File

@@ -18,100 +18,136 @@
#ifndef WX_PRECOMP #ifndef WX_PRECOMP
#include "wx/app.h" #include "wx/app.h"
#include "wx/frame.h"
#include "wx/window.h" #include "wx/window.h"
#endif // WX_PRECOMP #endif // WX_PRECOMP
#include "wx/scopedptr.h"
#include "wx/stopwatch.h"
#include "asserthelper.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: public:
SetSizeTestCase() { } MyWindow(wxWindow* parent)
: wxWindow(parent, wxID_ANY)
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
{ {
public: }
MyWindow(wxWindow* parent)
: wxWindow(parent, wxID_ANY)
{
}
protected: protected:
virtual wxSize DoGetBestSize() const wxOVERRIDE { return wxSize(50, 250); } virtual wxSize DoGetBestSize() const wxOVERRIDE { return wxSize(50, 250); }
};
wxWindow *m_win;
wxDECLARE_NO_COPY_CLASS(SetSizeTestCase);
}; };
// register in the unnamed registry so that these tests are run by default // Class used to check if we received the (first) paint event.
CPPUNIT_TEST_SUITE_REGISTRATION( SetSizeTestCase ); class WaitForPaint
// 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()
{ {
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() } // anonymous namespace
{
delete m_win;
m_win = NULL;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// tests themselves // tests themselves
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void SetSizeTestCase::SetSize() TEST_CASE("wxWindow::SetSize", "[window][size]")
{ {
const wxSize size(127, 35); wxScopedPtr<wxWindow> w(new MyWindow(wxTheApp->GetTopWindow()));
m_win->SetSize(size);
CPPUNIT_ASSERT_EQUAL( size, m_win->GetSize() ); 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<wxWindow> w(new MyWindow(wxTheApp->GetTopWindow()));
const wxSize size(200, 50); CHECK( wxSize(50, 250) == w->GetBestSize() );
m_win->SetSize(size);
CPPUNIT_ASSERT_EQUAL( size, m_win->GetSize() ); 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<wxWindow>
w(new wxFrame(wxTheApp->GetTopWindow(), wxID_ANY, "Test child frame"));
m_win->SetMinSize(wxSize(100, 100)); ShowAndWaitForPaint(w.get());
CPPUNIT_ASSERT_EQUAL( wxSize(100, 250), m_win->GetBestSize() );
m_win->SetMaxSize(wxSize(200, 200)); const wxRect rectOrig = w->GetRect();
CPPUNIT_ASSERT_EQUAL( wxSize(100, 200), m_win->GetBestSize() );
// Check that moving the window doesn't change its size.
w->Move(rectOrig.GetPosition() + wxPoint(100, 100));
CHECK( w->GetSize() == rectOrig.GetSize() );
} }