/*! \internal \fn void SelectedItem::keyPressEvent(QKeyEvent *event) Calls \l{function}{moveRequested(Direction)} in response to Qt::Key_Right, Qt::Key_Left, Qt::Key_Up or Qt::Key_Down. Calls triggerItemSelected() in response to Qt::Key_Select or Qt::Key_Return. For all other keys, the default functionality applies. If there is no current item, does nothing. */ void SelectedItem::keyPressEvent(QKeyEvent *event) { if ( !currentItem ) { qWarning("SelectedItem::keyPressEvent(...): No current item."); QGraphicsRectItem::keyPressEvent(event); return; } switch( event->key() ) { case Qt::Key_Right: if ( Qtopia::mousePreferred() || event->isAutoRepeat() && destItem ) return; moveRequested(Right); break; case Qt::Key_Left: if ( Qtopia::mousePreferred() || event->isAutoRepeat() && destItem ) return; moveRequested(Left); break; case Qt::Key_Up: if ( Qtopia::mousePreferred() || event->isAutoRepeat() && destItem ) return; moveRequested(Up); break; case Qt::Key_Down: if ( Qtopia::mousePreferred() || event->isAutoRepeat() && destItem ) return; moveRequested(Down); break; case Qt::Key_Select: // Qtopia pad case Qt::Key_Return: // otherwise if ( event->isAutoRepeat()) return; setActive(true); pressed = true; if ( destItem ) { // User has chosen to move to a new destination already, so they want to select // that one. triggerItemPressed(destItem); } else { triggerItemPressed(currentItem); } break; default: if ( event->isAutoRepeat()) return; QGraphicsRectItem::keyPressEvent(event); return; } }
void packetAdmin::createPacket() { QThread* newThread = new QThread(); packet *newPacket = new packet(); newPacket->moveToThread(newThread); connect(newPacket, SIGNAL(moveRequested()), newThread, SLOT(start())); connect(newThread, SIGNAL(started()), newPacket, SLOT(move())); connect(newPacket, SIGNAL(finished()), newThread, SLOT(quit()), Qt::DirectConnection); // (1) connect(newPacket, SIGNAL(deletePacket(packet*)), this, SLOT(deletePacketFromList(packet*))); connect(newPacket, SIGNAL(loosePacket()), this, SLOT(increaseLostPackets())); newPacket->requestMoving(); _packets.append(newPacket); _threads.append(newThread); }
// Set top-level layout to show cards. // Entry conditions: // - mCardWidgetsList contains CardWidgets from previous layout (any // widgets not reused should be cleaned up) // Exit requirements: // - mCardsList must be set to the list of cards // - mCardWidgetsList must contain all CardWidgets in the layout void GridCardViewerWidget::setCards( const QList<CardDataSharedPtr>& cards ) { // No need to lay everything out again if nothing changed. if( mCardsList == cards ) return; mCardsList = cards; // // Performance gets bad if creating all new widgets from scratch, // especially when images are scaled. Instead need to extract the // widgets from the layout, then only create new stuff as needed. // // Liberate the widgets we want to retain before clearing out the layout. for( auto w : mCardWidgetsList ) { w->setParent( 0 ); } for( int col = 0; col < 3; ++col ) { mTopColButtons[col]->setParent( 0 ); mBottomColButtons[col]->setParent( 0 ); } for( int row = 0; row < 3; ++row ) { mLeftRowButtons[row]->setParent( 0 ); mRightRowButtons[row]->setParent( 0 ); } // Our grid layout will be actually deleted below by clearLayout, but // need to null out our pointer. mGridCardsLayout = nullptr; // Remove any previously created widget from the alertable set. clearAlertableSubwidgets(); // Clear out the top-level layout - we're rebuilding it here. qtutils::clearLayout( mLayout ); // Function to clean up cardwidgets in the tracking list. auto cleanupCardWidgetsListFn = [this]() { for( auto w : mCardWidgetsList ) { w->deleteLater(); } mCardWidgetsList.clear(); }; // At this point everything is cleared. Finish cleanup and exit if // there aren't exactly 9 cards in the list. if( mCardsList.size() != 9 ) { // Zero is normal, but non-zero is not. if( mCardsList.size() > 0 ) { mLogger->warn( "card list size ({}) != 9, cannot perform grid layout!", cards.size() ); } // Clean up any cardwidgets remaining in the original list. cleanupCardWidgetsListFn(); return; } // This will contain all widgets once they're created/reused. QList<CardWidget*> newCardWidgetsList; // This local function picks a matching already-created CardWidget from // our tracking list to speed up the overall "setCards" operation which happens // on every sort, categorize, etc. auto takeWidgetFromCardWidgetsList = [this]( const CardDataSharedPtr& cardDataSharedPtr ) -> CardWidget* { for( int i = 0; i < mCardWidgetsList.count(); ++i ) { CardWidget* w = mCardWidgetsList[i]; if( w->getCardData() == cardDataSharedPtr ) { mLogger->debug( "reusing CardWidget for name={} muid={}", cardDataSharedPtr->getName(), cardDataSharedPtr->getMultiverseId() ); mCardWidgetsList.takeAt( i ); w->resetTraits(); updateCardWidgetSelectedAppearance( w ); return w; } } return nullptr; }; // This local function creates and connects a CardWidget. auto createCardWidget = [this]( const CardDataSharedPtr& cardDataSharedPtr ) -> CardWidget* { mLogger->debug( "creating CardWidget name={} muid={}", cardDataSharedPtr->getName(), cardDataSharedPtr->getMultiverseId() ); QString card = QString::fromStdString( cardDataSharedPtr->getName() ); CardWidget* cardWidget = new CardWidget( cardDataSharedPtr, mImageLoaderFactory, QSize( 223, 310 ), mLoggingConfig.createChildConfig( "cardwidget" ) ); cardWidget->setZoomFactor( mZoomFactor ); updateCardWidgetSelectedAppearance( cardWidget ); cardWidget->loadImage(); connect(cardWidget, SIGNAL(preselectRequested()), this, SLOT(handleCardPreselectRequested())); connect(cardWidget, SIGNAL(selectRequested()), this, SLOT(handleCardSelectRequested())); connect(cardWidget, SIGNAL(moveRequested()), this, SLOT(handleCardMoveRequested())); cardWidget->setContextMenuPolicy( Qt::CustomContextMenu ); connect(cardWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(handleCardContextMenu(const QPoint&))); return cardWidget; }; // // Lay out the cards and buttons in a grid. // // This widget shouldn't be needed but Qt gets confused when the // layout is added directly. Having a widget own it seems to help. QWidget* gridCardsLayoutWidget = new QWidget(); // The widget needs to turn red when the alert is active. addAlertableSubwidget( gridCardsLayoutWidget ); mGridCardsLayout = new QGridLayout( gridCardsLayoutWidget ); // Center the gridlayout using a QHBoxLayout and add to parent layout // before adding widgets as mentioned in Qt docs. QHBoxLayout* alignmentLayout = new QHBoxLayout(); alignmentLayout->addStretch(); alignmentLayout->addWidget( gridCardsLayoutWidget ); alignmentLayout->addStretch(); mLayout->addLayout( alignmentLayout ); // Lay out column buttons. for( int col = 0; col < 3; ++col ) { mGridCardsLayout->addWidget( mTopColButtons[col], 0, 1 + col, Qt::AlignCenter ); mGridCardsLayout->addWidget( mBottomColButtons[col], 4, 1 + col, Qt::AlignCenter ); } // Lay out row buttons. for( int row = 0; row < 3; ++row ) { mGridCardsLayout->addWidget( mLeftRowButtons[row], 1 + row, 0, Qt::AlignCenter ); mGridCardsLayout->addWidget( mRightRowButtons[row], 1 + row, 4, Qt::AlignCenter ); } updateButtonVisibility(); // Create card widgets and add to layout. for( int i = 0; i < 9; ++i ) { auto cardDataSharedPtr = mCardsList[i]; // Look for an existing card widget that matches our card data, // and extract it from the list if found. CardWidget* cardWidget = nullptr; cardWidget = takeWidgetFromCardWidgetsList( cardDataSharedPtr ); if( !cardWidget ) { // The widget doesn't exist. Create it. cardWidget = createCardWidget( cardDataSharedPtr ); } mGridCardsLayout->addWidget( cardWidget, 1+ i/3, 1 + i%3 ); newCardWidgetsList.push_back( cardWidget ); } if( mFooterSpacing > 0 ) mLayout->addSpacing( mFooterSpacing ); // This keeps everything pushed nicely to the top of the main area. mLayout->addStretch(); // Clean up any cardwidgets remaining in the original list. cleanupCardWidgetsListFn(); // Old is new. mCardWidgetsList = newCardWidgetsList; }