QGroupBox *CardEditor::createTextItemBox(const QString &text, const QFont &font, int skip, BlackEdgeTextItem *item){ QGroupBox *box = new QGroupBox; QLineEdit *edit = new QLineEdit; QPushButton *font_button = new QPushButton(font.family()); QSpinBox *size_spinbox = new QSpinBox; size_spinbox->setRange(1, 96); QSpinBox *space_spinbox = new QSpinBox; space_spinbox->setRange(0, 100); edit->setObjectName("name"); size_spinbox->setObjectName("font"); space_spinbox->setObjectName("space"); QFormLayout *layout = new QFormLayout; layout->addRow(tr("Text"), edit); layout->addRow(tr("Font"), font_button); layout->addRow(tr("Line spacing"), space_spinbox); QFontDialog *font_dialog = new QFontDialog(this); setMapping(font_dialog, font_button); connect(edit, SIGNAL(textChanged(QString)), item, SLOT(setText(QString))); connect(font_dialog, SIGNAL(currentFontChanged(QFont)), item, SLOT(setFont(QFont))); connect(space_spinbox, SIGNAL(valueChanged(int)), item, SLOT(setSkip(int))); edit->setText(text); font_dialog->setCurrentFont(font); space_spinbox->setValue(skip); box->setLayout(layout); return box; }
void contact_list_dialog::update_contacts() { INVARIANT(_list); INVARIANT(_service); _list->clear(); _ui.clear(); for(auto u : _service->user().contacts().list()) { auto rm = make_x_button(); std::stringstream ss; ss << "Remove `" << u->name() << "'"; rm->setToolTip(ss.str().c_str()); auto mapper = new QSignalMapper{this}; mapper->setMapping(rm, QString(u->id().c_str())); connect(rm, SIGNAL(clicked()), mapper, SLOT(map())); connect(mapper, SIGNAL(mapped(QString)), this, SLOT(remove(QString))); auto ui = new user_info{u, _service, rm, false}; _list->add(ui); _ui.push_back(ui); } _prev_contacts = _service->user().contacts().size(); }
void Dialog::AttachComboBox(int Row, int Col) { if (m_Table->rowCount() <= 0) { return; } auto Mapper(new QSignalMapper(this)); auto Combo(CreateCombo()); m_Table->setCellWidget(Row, Col, Combo); connect(Combo, SIGNAL(currentIndexChanged(int)), Mapper, SLOT(map())); Mapper->setMapping(Combo, QString("%1-%2").arg(Row).arg(Col)); }
MappingParameters::MappingParameters( mapping::Interface* _mapping, QWidget* _parent) : ParameterWidget(_parent) { QLayout *_layout = new QVBoxLayout; _layout->setSpacing(2); _layout->setContentsMargins(0, 0, 0, 0); setLayout(_layout); setMapping(_mapping); }
void Remapper::beginRemapping( QString GUID, QString button ) { // TODO: Let the user know about this situation // FIXME: Wouldn't muting problem buttons fix this? Is this even necessary? Should we detect conflicts and offer to mute? if( ignoreMode ) { Key key = mappingStringToKey( button ); Val value = gameControllerToJoystick[ GUID ][ key ]; qInfo().noquote() << "Release" << valToFriendlyString( ignoreModeVal ) << "first before trying to remap" << button; emit setMapping( GUID, button, valToFriendlyString( value ) ); emit remappingEnded(); return; } remapMode = true; remapModeGUID = GUID; remapModeKey = mappingStringToKey( button ); }
void MidiInterface::loadMapping() { if(!_mapping.isEmpty()) { MidiMapping * mm = MidiMapping::loadFromFile(_mapping); if(mm) { Minotor::minotor()->midiMapper()->loadMidiMapping(this, mm); delete mm; } else { qDebug() << Q_FUNC_INFO << "Invalid file" << _mapping; // Do not keep invalid mapping filename setMapping(""); } } }
void ATPClientApp::uploadAsset() { auto path = _url.path(); if (path == "/") { qDebug() << "cannot upload to path of /"; QCoreApplication::exit(1); } auto upload = DependencyManager::get<AssetClient>()->createUpload(_localUploadFile); QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { if (upload->getError() != AssetUpload::NoError) { qDebug() << "upload failed: " << upload->getErrorString(); } else { setMapping(hash); } upload->deleteLater(); }); upload->start(); }
void InputDeviceMapping::remapMapping(QString previousEvent, QVariant event, QString retroId, unsigned port) { // Remove the previous mapping auto prevEv = eventFromString(previousEvent); if (prevEv != nullptr) mapping.erase(prevEv); InputDeviceEvent *ev = event.value<InputDeviceEvent *>(); if (ev) { for (auto m=mapping.begin(); m != mapping.end(); ++m) { qDebug() << QString(*(m->first)); QString prev_event = QString(*(m->first)); if (prev_event == QString(*ev)) { qDebug() << "Value is already mapped"; return; } } setMapping(ev, retroId.toUInt(), port); } }
bool InputDeviceMapping::populateFromSettings(QSettings &s) { // retro device type QString device_type = s.value("device_type").toString(); if (device_type != "joypad") { // TODO: only supported type for now return false; } setDeviceType(RETRO_DEVICE_JOYPAD); auto *mapping = settings_mappings.value(device_type); for (auto i = mapping->constBegin(); i != mapping->constEnd(); i++) { QVariant val = s.value(i.key()); if (!val.isValid()) continue; QString eventstr = val.toString(); InputDeviceEvent *ev = eventFromString(eventstr); if (ev != nullptr) setMapping(ev, i.value()); } return true; }
void Remapper::dataIn( Node::DataType type, QMutex *mutex, void *data, size_t bytes, qint64 timeStamp ) { switch( type ) { case DataType::Input: { // Copy incoming data to our own buffer GamepadState gamepad; { mutex->lock(); gamepad = *reinterpret_cast<GamepadState *>( data ); mutex->unlock(); } int instanceID = gamepad.instanceID; int joystickID = gamepad.joystickID; QString GUID( QByteArray( reinterpret_cast<const char *>( gamepad.GUID.data ), 16 ).toHex() ); // Do initial calibration if not done yet { if( deadzoneFlag[ GUID ] ) { deadzoneFlag[ GUID ] = false; // Apply default value for( int i = 0; i < gamepad.joystickNumAxes; i++ ) { deadzones[ GUID ][ i ] = 10000; // Check analog value at this moment. If its magnitude is less than 30000 then it's most likely // an analog stick. Otherwise, it might be a trigger (with a centered value of -32768) deadzoneModes[ GUID ][ i ] = ( qAbs( static_cast<int>( gamepad.joystickAxis[ i ] ) ) < 30000 ); } // TODO: Replace with stored value from disk } } // Inject deadzone settings into gamepad { for( int i = 0; i < gamepad.joystickNumAxes; i++ ) { gamepad.deadzone[ i ] = deadzones[ GUID ][ i ]; gamepad.deadzoneMode[ i ] = deadzoneModes[ GUID ][ i ]; } } // Send raw joystick data to the model // Do this before we apply joystick deadzones so the user sees completely unprocessed data { // Copy current gamepad into buffer this->mutex.lock(); gamepadBuffer[ gamepadBufferIndex ] = gamepad; this->mutex.unlock(); // Send buffer on its way emit rawJoystickData( &( this->mutex ), reinterpret_cast<void *>( &gamepadBuffer[ gamepadBufferIndex ] ) ); // Increment the index gamepadBufferIndex = ( gamepadBufferIndex + 1 ) % 100; } // Apply deadzones to each stick and both triggers independently { qreal deadzone = 0.0; bool deadzoneMode = false; for( int i = 0; i < 4; i++ ) { int xAxis; int yAxis; // For the analog sticks, average the underlying joystick axes together to get the final deadzone value // If either axis has deadzone mode set to true, it'll apply to both // FIXME: If users complain about this, expand the code to handle this case (one axis true and one axis false) and treat axes indepenently switch( i ) { case 0: { xAxis = SDL_CONTROLLER_AXIS_LEFTX; yAxis = SDL_CONTROLLER_AXIS_LEFTY; Val val = gameControllerToJoystick[ GUID ][ Key( AXIS, SDL_CONTROLLER_AXIS_LEFTX ) ]; int axisID = val.second.first; if( val.first == AXIS ) { deadzone = deadzones[ GUID ][ axisID ]; deadzoneMode = deadzoneModes[ GUID ][ axisID ]; } Val val2 = gameControllerToJoystick[ GUID ][ Key( AXIS, SDL_CONTROLLER_AXIS_LEFTY ) ]; axisID = val2.second.first; if( val2.first == AXIS ) { deadzone += deadzones[ GUID ][ axisID ]; deadzone /= 2.0; deadzoneMode = deadzoneMode || deadzoneModes[ GUID ][ axisID ]; } break; } case 1: { xAxis = SDL_CONTROLLER_AXIS_RIGHTX; yAxis = SDL_CONTROLLER_AXIS_RIGHTY; Val val = gameControllerToJoystick[ GUID ][ Key( AXIS, SDL_CONTROLLER_AXIS_RIGHTX ) ]; int axisID = val.second.first; if( val.first == AXIS ) { deadzone = deadzones[ GUID ][ axisID ]; deadzoneMode = deadzoneModes[ GUID ][ axisID ]; } Val val2 = gameControllerToJoystick[ GUID ][ Key( AXIS, SDL_CONTROLLER_AXIS_RIGHTY ) ]; axisID = val2.second.first; if( val2.first == AXIS ) { deadzone += deadzones[ GUID ][ axisID ]; deadzone /= 2.0; deadzoneMode = deadzoneMode || deadzoneModes[ GUID ][ axisID ]; } break; } // For simplicity, just map the triggers to the line y = x case 2: { xAxis = SDL_CONTROLLER_AXIS_TRIGGERLEFT; yAxis = SDL_CONTROLLER_AXIS_TRIGGERLEFT; Val val = gameControllerToJoystick[ GUID ][ Key( AXIS, SDL_CONTROLLER_AXIS_TRIGGERLEFT ) ]; int axisID = val.second.first; if( val.first == AXIS ) { deadzone = deadzones[ GUID ][ axisID ]; deadzoneMode = deadzoneModes[ GUID ][ axisID ]; } break; } case 3: { xAxis = SDL_CONTROLLER_AXIS_TRIGGERRIGHT; yAxis = SDL_CONTROLLER_AXIS_TRIGGERRIGHT; Val val = gameControllerToJoystick[ GUID ][ Key( AXIS, SDL_CONTROLLER_AXIS_TRIGGERRIGHT ) ]; int axisID = val.second.first; if( val.first == AXIS ) { deadzone = deadzones[ GUID ][ axisID ]; deadzoneMode = deadzoneModes[ GUID ][ axisID ]; } break; } } // Map from [-32768, 32767] to [0, 32767] if( !deadzoneMode ) { gamepad.axis[ xAxis ] /= 2; gamepad.axis[ yAxis ] /= 2; gamepad.axis[ xAxis ] += 16384; gamepad.axis[ yAxis ] += 16384; } // Get axis coords in cartesian coords // Bottom right is positive -> top right is positive qreal xCoord = gamepad.axis[ xAxis ]; qreal yCoord = -gamepad.axis[ yAxis ]; // Get radius from center QVector2D position( static_cast<float>( xCoord ), static_cast<float>( yCoord ) ); qreal radius = static_cast<qreal>( position.length() ); if( !( radius > deadzone ) ) { gamepad.axis[ xAxis ] = 0; gamepad.axis[ yAxis ] = 0; if( xAxis == SDL_CONTROLLER_AXIS_TRIGGERLEFT ) { gamepad.digitalL2 = false; } if( xAxis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT ) { gamepad.digitalR2 = false; } } else { if( xAxis == SDL_CONTROLLER_AXIS_TRIGGERLEFT ) { gamepad.digitalL2 = true; } if( xAxis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT ) { gamepad.digitalR2 = true; } } } } // Apply deadzones to all joystick axes // Used only when detecting input for remapping { for( int i = 0; i < 16; i++ ) { qreal deadzoneRadius = deadzones[ GUID ][ i ]; qreal coord = gamepad.joystickAxis[ i ]; if( !deadzoneModes[ GUID ][ i ] ) { coord += 32768; } if( !( qAbs( coord ) > deadzoneRadius ) ) { gamepad.joystickAxis[ i ] = 0; } } } // If ignoreMode is set, the user hasn't let go of the button they were remapping to // Do not let the button go through until they let go { if( ignoreMode && ignoreModeGUID == GUID && ignoreModeInstanceID == gamepad.instanceID ) { if( ignoreModeVal.first == BUTTON ) { if( gamepad.joystickButton[ ignoreModeVal.second.first ] == SDL_PRESSED ) { gamepad.joystickButton[ ignoreModeVal.second.first ] = SDL_RELEASED; } else { ignoreMode = false; } } else if( ignoreModeVal.first == HAT ) { if( gamepad.joystickHat[ ignoreModeVal.second.first ] != SDL_HAT_CENTERED ) { gamepad.joystickHat[ ignoreModeVal.second.first ] = SDL_HAT_CENTERED; } else { ignoreMode = false; } } else if( ignoreModeVal.first == AXIS ) { if( gamepad.joystickAxis[ ignoreModeVal.second.first ] != 0 ) { gamepad.joystickAxis[ ignoreModeVal.second.first ] = 0; } else { ignoreMode = false; } } } } // If we opened an SDL2 Game controller handle from this class, keep it and inject it into all gamepads we send out { if( gameControllerHandles[ instanceID ] ) { gamepad.gamecontrollerHandle = gameControllerHandles[ instanceID ]; } } // If we are in remap mode, check for a button press from the stored GUID, and remap the stored button to that button // All game controller states are cleared past this point if in remap mode { if( remapMode && GUID == remapModeGUID ) { // Find a button press, the first one we encounter will be the new remapping bool foundInput = false; Key key = remapModeKey; Val value = Val( INVALID, VHat( -1, -1 ) ); // Prioritize buttons and hats over analog sticks for( int joystickButton = 0; joystickButton < 256; joystickButton++ ) { if( gamepad.joystickButton[ joystickButton ] == SDL_PRESSED ) { qCDebug( phxInput ).nospace() << "Button b" << joystickButton << " from GUID " << GUID << " now activates " << keyToMappingString( key ); foundInput = true; value.first = BUTTON; value.second = VHat( joystickButton, -1 ); break; } } for( int joystickHat = 0; joystickHat < 16; joystickHat++ ) { if( gamepad.joystickHat[ joystickHat ] != SDL_HAT_CENTERED ) { qCDebug( phxInput ).nospace() << "Hat h" << joystickHat << "." << gamepad.joystickHat[ joystickHat ] << " from GUID " << GUID << " now activates " << keyToMappingString( key ); foundInput = true; value.first = HAT; value.second = VHat( joystickHat, gamepad.joystickHat[ joystickHat ] ); break; } } for( int joystickAxis = 0; joystickAxis < 16; joystickAxis++ ) { if( gamepad.joystickAxis[ joystickAxis ] != 0 ) { qCDebug( phxInput ).nospace() << "Axis a" << joystickAxis << " from GUID " << GUID << " now activates " << keyToMappingString( key ); foundInput = true; value.first = AXIS; value.second = VHat( joystickAxis, -1 ); break; } } if( foundInput ) { // Store the new remapping internally gameControllerToJoystick[ GUID ][ remapModeKey ] = value; // Tell SDL2 about it QString mappingString; QString platform( SDL_GetPlatform() ); { QString friendlyName = QString( SDL_JoystickName( gamepad.joystickHandle ) ); mappingString.append( GUID ).append( "," ).append( friendlyName ).append( "," ); for( Key key : gameControllerToJoystick[ GUID ].keys() ) { if( gameControllerToJoystick[ GUID ][ key ].first != INVALID ) { mappingString.append( keyToMappingString( key ) ).append( ':' ) .append( valToMappingString( gameControllerToJoystick[ GUID ][ key ] ) ).append( ',' ); } } mappingString.append( "platform:" ).append( platform ).append( "," ); qDebug().nospace() << mappingString; // Give SDL the new mapping string SDL_GameControllerAddMapping( mappingString.toUtf8().constData() ); // If this is not a game controller, reopen as one SDL_GameController *gamecontrollerHandle = nullptr; if( !gameControllerHandles[ instanceID ] ) { gamecontrollerHandle = SDL_GameControllerOpen( joystickID ); gamepad.gamecontrollerHandle = gamecontrollerHandle; // Store internally so we can inject it into all future events from this instanceID gameControllerHandles[ instanceID ] = gamecontrollerHandle; qDebug() << "Opened newly remapped joystick as a game controller:" << gamecontrollerHandle; } } // Store this mapping to disk { if( !userDataPath.isEmpty() ) { QFile mappingFile( userDataPath + "/gamecontrollerdb.txt" ); mappingFile.open( QIODevice::ReadWrite | QIODevice::Text ); QByteArray mappingFileData = mappingFile.readAll(); if( !mappingFile.isOpen() ) { qWarning() << "Unable to open mapping file for reading" << mappingFile.errorString(); } mappingFile.close(); QTextStream mappingFileStreamIn( &mappingFileData ); mappingFileStreamIn.setCodec( "UTF-8" ); mappingFile.open( QIODevice::WriteOnly | QIODevice::Text ); if( !mappingFile.isOpen() ) { qWarning() << "Unable to open mapping file for writing" << mappingFile.errorString(); } QTextStream mappingFileStreamOut( &mappingFile ); mappingFileStreamOut.setCodec( "UTF-8" ); QString line = ""; while( !line.isNull() ) { line = mappingFileStreamIn.readLine(); // We want to replace the line (any line) for our platform that contains our GUID // We'll also filter out empty lines if( line.isEmpty() || ( line.contains( GUID ) && line.contains( platform ) ) ) { continue; } mappingFileStreamOut << line << endl; } mappingFileStreamOut << mappingString << endl; mappingFile.close(); } else { qWarning() << "Unable to open controller mapping file, user data path not set"; } } // End remap mode, start ignore mode { remapMode = false; ignoreMode = true; ignoreModeGUID = GUID; ignoreModeVal = value; ignoreModeInstanceID = gamepad.instanceID; } // Tell the model we're done { emit setMapping( GUID, keyToMappingString( key ), valToFriendlyString( value ) ); emit remappingEnded(); } } // Clear all game controller states (joystick states are untouched) for( int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++ ) { gamepad.button[ i ] = 0; } for( int i = 0; i < SDL_CONTROLLER_AXIS_MAX; i++ ) { gamepad.axis[ i ] = 0; } } else if( remapMode ) { // Clear all gamepad states for( int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++ ) { gamepad.button[ i ] = 0; } for( int i = 0; i < SDL_CONTROLLER_AXIS_MAX; i++ ) { gamepad.axis[ i ] = 0; } } } // OR all joystick button, hat and analog states together by GUID for RemapperModel to indicate presses { for( int i = 0; i < 256; i++ ) { pressed[ GUID ] |= gamepad.joystickButton[ i ]; } for( int i = 0; i < 16; i++ ) { pressed[ GUID ] |= ( gamepad.joystickHat[ i ] != SDL_HAT_CENTERED ); } for( int i = 0; i < 16; i++ ) { pressed[ GUID ] |= ( gamepad.joystickAxis[ i ] != 0 ); } } // Apply axis to d-pad, if enabled // This will always be enabled if we're not currently playing so GlobalGamepad can use the analog stick { if( analogToDpad[ GUID ] || !playing ) { // TODO: Support other axes? int xAxis = SDL_CONTROLLER_AXIS_LEFTX; int yAxis = SDL_CONTROLLER_AXIS_LEFTY; // TODO: Let user configure these qreal threshold = 16384.0; // Size in degrees of the arc covering and centered around each cardinal direction // If <90, there will be gaps in the diagonals // If >180, this code will always produce diagonal inputs qreal rangeDegrees = 180.0 - 45.0; // Get axis coords in cartesian coords // Bottom right is positive -> top right is positive qreal xCoord = gamepad.axis[ xAxis ]; qreal yCoord = -gamepad.axis[ yAxis ]; // Get radius from center QVector2D position( static_cast<float>( xCoord ), static_cast<float>( yCoord ) ); qreal radius = static_cast<qreal>( position.length() ); // Get angle in degrees qreal angle = qRadiansToDegrees( qAtan2( yCoord, xCoord ) ); if( angle < 0.0 ) { angle += 360.0; } if( radius > threshold ) { qreal halfRange = rangeDegrees / 2.0; if( angle > 90.0 - halfRange && angle < 90.0 + halfRange ) { gamepad.button[ SDL_CONTROLLER_BUTTON_DPAD_UP ] = true; } if( angle > 270.0 - halfRange && angle < 270.0 + halfRange ) { gamepad.button[ SDL_CONTROLLER_BUTTON_DPAD_DOWN ] = true; } if( angle > 180.0 - halfRange && angle < 180.0 + halfRange ) { gamepad.button[ SDL_CONTROLLER_BUTTON_DPAD_LEFT ] = true; } if( angle > 360.0 - halfRange || angle < 0.0 + halfRange ) { gamepad.button[ SDL_CONTROLLER_BUTTON_DPAD_RIGHT ] = true; } } } } // Apply d-pad to axis, if enabled { if( dpadToAnalog[ GUID ] ) { gamepad = mapDpadToAnalog( gamepad ); } } // Send updated data out { // Copy current gamepad into buffer this->mutex.lock(); gamepadBuffer[ gamepadBufferIndex ] = gamepad; this->mutex.unlock(); // Send buffer on its way emit dataOut( DataType::Input, &( this->mutex ), reinterpret_cast<void *>( &gamepadBuffer[ gamepadBufferIndex ] ), 0, nodeCurrentTime() ); // Increment the index gamepadBufferIndex = ( gamepadBufferIndex + 1 ) % 100; } break; } case DataType::KeyboardInput: { // Unpack keyboard states and write to gamepad according to remap data { mutex->lock(); KeyboardState keyboard = *reinterpret_cast<KeyboardState *>( data ); for( int i = keyboard.head; i < keyboard.tail; i = ( i + 1 ) % 128 ) { int key = keyboard.key[ i ]; bool pressed = keyboard.pressed[ i ]; if( keyboardKeyToSDLButton.contains( key ) ) { keyboardGamepad.button[ keyboardKeyToSDLButton[ key ] ] = pressed ? SDL_PRESSED : SDL_RELEASED; } } mutex->unlock(); } // OR all key states together and store that value for( int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++ ) { keyboardKeyPressed |= keyboardGamepad.button[ i ]; } // Apply d-pad to axis, if enabled if( dpadToAnalogKeyboard ) { keyboardGamepad = mapDpadToAnalog( keyboardGamepad, true ); } // Send gamepad on its way { // Copy current gamepad into buffer this->mutex.lock(); gamepadBuffer[ gamepadBufferIndex ] = keyboardGamepad; this->mutex.unlock(); // Send buffer on its way emit dataOut( DataType::Input, &( this->mutex ), reinterpret_cast< void * >( &gamepadBuffer[ gamepadBufferIndex ] ), 0, nodeCurrentTime() ); // Increment the index gamepadBufferIndex = ( gamepadBufferIndex + 1 ) % 100; } break; } default: { emit dataOut( type, mutex, data, bytes, timeStamp ); break; } } }
void Remapper::commandIn( Command command, QVariant data, qint64 timeStamp ) { switch( command ) { case Command::Stop: case Command::Load: case Command::Pause: case Command::Unload: case Command::Reset: { emit commandOut( command, data, timeStamp ); playing = false; break; } case Command::Play: { emit commandOut( command, data, timeStamp ); playing = true; break; } case Command::HandleGlobalPipelineReady: { emit commandOut( command, data, timeStamp ); emit controllerAdded( "", "Keyboard", 0, 0, 0 ); // TODO: Read keyboard setting from disk too dpadToAnalogKeyboard = true; // Give the model friendly names for all the keys set for( int physicalKey : keyboardKeyToSDLButton.keys() ) { int virtualButton = keyboardKeyToSDLButton[ physicalKey ]; // This prints garbage as-is, so change it to something that doesn't // Confirmed on Windows but looks okay in OS X? // https://bugreports.qt.io/browse/QTBUG-40030 if( physicalKey == Qt::Key_Shift ) { physicalKey = Qt::ShiftModifier; } if( physicalKey == Qt::Key_Control ) { physicalKey = Qt::ControlModifier; } if( physicalKey == Qt::Key_Meta ) { physicalKey = Qt::MetaModifier; } if( physicalKey == Qt::Key_Alt ) { physicalKey = Qt::AltModifier; } if( physicalKey == Qt::Key_AltGr ) { physicalKey = Qt::AltModifier; } QString keyString = QKeySequence( physicalKey ).toString( QKeySequence::NativeText ); // Strip out trailing + in the corrected keys if( keyString.length() > 1 ) { keyString = keyString.section( '+', 0, 0 ); } emit setMapping( "", keyString, gameControllerIDToMappingString( virtualButton ) ); } break; } case Command::SetUserDataPath: { userDataPath = data.toString(); qDebug() << "Using path" << userDataPath; break; } case Command::Heartbeat: { emit commandOut( command, data, timeStamp ); // Tell the model to clear its stored states emit heartbeat(); // Send out per-GUID OR'd states to RemapperModel then clear stored pressed states for( QString GUID : pressed.keys() ) { emit buttonUpdate( GUID, pressed[ GUID ] ); pressed[ GUID ] = false; } // Do the same for the keyboard emit buttonUpdate( "", keyboardKeyPressed ); keyboardKeyPressed = false; // If in remap mode, make sure the GUID in question still exists, exit remap mode if not if( remapMode && !GUIDCount.contains( remapModeGUID ) ) { qCWarning( phxInput ) << "No controllers with GUID" << remapModeGUID << "remaining, exiting remap mode!"; remapMode = false; emit remappingEnded(); } break; } case Command::AddController: { emit commandOut( command, data, timeStamp ); GamepadState gamepad = data.value<GamepadState>(); int instanceID = gamepad.instanceID; QString GUID( QByteArray( reinterpret_cast<const char *>( gamepad.GUID.data ), 16 ).toHex() ); // Add to map if it hasn't been encountered yet // Otherwise, just increment the count if( !GUIDCount.contains( GUID ) ) { GUIDCount[ GUID ] = 1; emit controllerAdded( GUID, gamepad.friendlyName, gamepad.joystickNumButtons, gamepad.joystickNumHats, gamepad.joystickNumAxes ); } else { GUIDCount[ GUID ]++; } // Initialize mappings with invalid values for( int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++ ) { Key key = Key( BUTTON, i ); Val val = Val( INVALID, VHat( -1, -1 ) ); gameControllerToJoystick[ GUID ][ key ] = val; emit setMapping( GUID, keyToMappingString( key ), valToFriendlyString( val ) ); } // Grab gamepad handle gameControllerHandles[ instanceID ] = gamepad.gamecontrollerHandle; for( int i = 0; i < SDL_CONTROLLER_AXIS_MAX; i++ ) { Key key = Key( AXIS, i ); Val val = Val( INVALID, VHat( -1, -1 ) ); gameControllerToJoystick[ GUID ][ key ] = val; emit setMapping( GUID, keyToMappingString( key ), valToFriendlyString( val ) ); } // TODO: Read value from disk analogToDpad[ GUID ] = false; dpadToAnalog[ GUID ] = false; // Set calibration flag, analog values will be read and deadzone values will be calculated the first time // we get data deadzoneFlag[ GUID ] = true; QString mappingString = gamepad.mappingString; if( mappingString.isEmpty() ) { return; } // Parse mapping string { QStringList mappings = mappingString.split( ',', QString::SkipEmptyParts ); // No one likes QList asserts failing if( mappings.isEmpty() ) { return; } /*QString gamepadGUID =*/ mappings.takeFirst(); if( mappings.isEmpty() ) { return; } QString friendlyName = mappings.takeFirst(); if( mappings.isEmpty() ) { return; } QString platform; // Parse the main part of the remapping string for( QString mapping : mappings ) { if( mapping.contains( "platform" ) ) { platform = mapping; continue; } QString keyString = mapping.section( ':', 0, 0 ); QString valueString = mapping.section( ':', 1, 1 ); // Give up if there's nothing parsed if( keyString.isEmpty() || valueString.isEmpty() ) { continue; } Type valueType; // Parse the key Key key = Key( BUTTON, SDL_CONTROLLER_BUTTON_INVALID ); { bool okay; key = mappingStringToKey( keyString, &okay ); if( !okay ) { continue; } } // Parse the value int value = -1; int hatValue = -1; { // Button, format: bX if( valueString.startsWith( "b" ) ) { valueType = BUTTON; bool okay; value = valueString.right( valueString.size() - 1 ).toInt( &okay ); if( !okay ) { continue; } } // Hat, format: hX.Y else if( valueString.startsWith( "h" ) ) { valueType = HAT; bool okay; value = valueString.right( valueString.size() - 1 ).split( '.' )[ 0 ].toInt( &okay ); if( !okay ) { continue; } hatValue = valueString.split( '.' )[ 1 ].toInt( &okay ); if( !okay ) { continue; } } // Axis, format aX else if( valueString.startsWith( "a" ) ) { valueType = AXIS; bool okay; value = valueString.right( valueString.size() - 1 ).toInt( &okay ); if( !okay ) { continue; } } else { continue; } } //qDebug() << keyString << valueString << key << keyType << value << hatValue << valueType; gameControllerToJoystick[ GUID ][ key ] = Val( valueType, VHat( value, hatValue ) ); emit setMapping( GUID, keyToMappingString( key ), valToFriendlyString( Val( valueType, VHat( value, hatValue ) ) ) ); } } break; } case Command::RemoveController: { GamepadState gamepad = data.value<GamepadState>(); int instanceID = gamepad.instanceID; QString GUID( QByteArray( reinterpret_cast<const char *>( gamepad.GUID.data ), 16 ).toHex() ); GUIDCount[ GUID ]--; // Remove from map if no longer there if( GUIDCount[ GUID ] == 0 ) { GUIDCount.remove( GUID ); emit controllerRemoved( GUID ); } // If we opened an SDL2 Game controller handle from this class, keep it and inject it into all gamepads we send out if( gameControllerHandles[ instanceID ] ) { gamepad.gamecontrollerHandle = gameControllerHandles[ instanceID ]; } gameControllerHandles.remove( instanceID ); emit commandOut( Command::RemoveController, QVariant::fromValue( gamepad ), nodeCurrentTime() ); break; } default: { emit commandOut( command, data, timeStamp ); break; } } }
void DataBase::copyAttributes(Object::const_ptr src, bool replace) { Base::copyAttributes(src, replace); if (auto d = DataBase::as(src)) { setMapping(d->mapping()); } }
void VertexWelder::update(NxMeshData meshData) { assert(mWriteVerticesPtr != NULL); bool updateVertices = (*(meshData.dirtyBufferFlagsPtr) & (NX_MDF_VERTICES_POS_DIRTY | NX_MDF_VERTICES_NORMAL_DIRTY)) > 0; bool updateIndices = (*(meshData.dirtyBufferFlagsPtr) & (NX_MDF_INDICES_DIRTY | NX_MDF_PARENT_INDICES_DIRTY)) > 0; NxU32 numNewVertices = *meshData.numVerticesPtr; NxU32 numTriangles = *meshData.numIndicesPtr / 3; NxU32 oldMappingDomain = mMappingDomain; NxArray<NewVertex> newVertices; NxArray<DifficultVertex> difficultVertices; mMappingDomainAddition = 0; if (updateVertices) { if (mMappingDomain < numNewVertices) { #ifdef DEBUG_WELDER printf("------------------------------------\n"); #endif for (NxU32 i = mMappingDomain; i < numNewVertices; i++) { NewVertex v; v.index = i; v.parent = *(NxU32*)(((char*)meshData.parentIndicesBegin) + meshData.parentIndicesByteStride * i); while (v.parent >= (NxI32)mMappingDomain) { v.parent = *(NxU32*)(((char*)meshData.parentIndicesBegin) + meshData.parentIndicesByteStride * v.parent); } #ifdef DEBUG_WELDER printf("New Vertex: %d %d\n", v.index, v.parent); #endif newVertices.push_back(v); } std::sort(newVertices.begin(), newVertices.end(), sortParent); } for (NxU32 i = 0; i < mMappingSize; i++) { NxU32 mappedIndex = getMapping(i); NewVertex newV; newV.parent = mappedIndex; // Find all vertices that are a parent for a newly created vertex NxArray<NewVertex>::iterator found = std::lower_bound(newVertices.begin(), newVertices.end(), newV, sortParent); while (found != NULL && found->parent == mappedIndex) { found->mappedVertices ++; if (found->mappedVertices == 1) { found->unMapParent = i; #ifdef DEBUG_WELDER printf("New Vertex Update, %d %d %d\n", found->index, found->parent, found->unMapParent); #endif } else { // several unmapped parents DifficultVertex v; v.mappedIndex = found->index; v.unMappedIndex = i; difficultVertices.push_back(v); #ifdef DEBUG_WELDER printf("Difficult Vertex %d %d\n", v.unMappedIndex, v.mappedIndex); #endif if (found->mappedVertices == 2) { v.unMappedIndex = found->unMapParent; difficultVertices.push_back(v); #ifdef DEBUG_WELDER printf("Difficult Vertex %d %d\n", v.unMappedIndex, v.mappedIndex); #endif } found->unMapParent = -2; } found++; } NxVec3& vertex = *(NxVec3*)(((char*)mWriteVerticesPtr) + mWriteVerticesStride * i); NxVec3& normal = *(NxVec3*)(((char*)mWriteNormalsPtr) + mWriteNormalsStride* i); //float* texCoord = (float*)(((char*)texCoords) + texStride * i); const NxVec3& oldVertex = *(NxVec3*)(((char*)meshData.verticesPosBegin) + meshData.verticesPosByteStride * mappedIndex); const NxVec3& oldNormal = *(NxVec3*)(((char*)meshData.verticesNormalBegin) + meshData.verticesNormalByteStride * mappedIndex); vertex = oldVertex; normal = oldNormal; } // Adapt the mapping table std::sort(newVertices.begin(), newVertices.end(), sortIndex); std::sort(difficultVertices.begin(), difficultVertices.end(), sortDifficultExt); } if (updateIndices) { std::vector<bool> bitVector(mMappingSpace, false); #ifdef DEBUG_WELDER printf("updateIndices: Vertices: %d, Indices %d, gfx Vertices: %d\n", *meshData.numVerticesPtr, *meshData.numIndicesPtr, mMappingSize); #endif if (difficultVertices.size() > 0) { #ifdef DEBUG_WELDER printf(" Difficult Vertices:\n"); #endif for (NxU32 i = 0; i < difficultVertices.size(); i++) { DifficultVertex& v = difficultVertices[i]; #ifdef DEBUG_WELDER printf(" V %d %d\n", v.unMappedIndex, v.mappedIndex); #endif } } assert((meshData.flags & NX_MF_16_BIT_INDICES) == 0); assert(meshData.indicesByteStride == 4); for (NxU32 i = 0; i < numTriangles; i++) { const NxU32* simTriangle = (NxU32*)(((char*)meshData.indicesBegin) + meshData.indicesByteStride * (i*3)); NxU32* gfxTriangle = (NxU32*)(((char*)mWriteIndicesPtr) + mWriteIndicesStride* i); if (simTriangle[0] == simTriangle[1] && simTriangle[1] == simTriangle[2]) { // Face was deleted (outside valid bounds probably) gfxTriangle[0] = gfxTriangle[1] = gfxTriangle[2] = 0; continue; } for (NxU32 j = 0; j < 3; j++) { DifficultVertex v; v.mappedIndex = simTriangle[j]; v.unMappedIndex = gfxTriangle[j]; if (std::binary_search(difficultVertices.begin(), difficultVertices.end(), v, sortDifficult)) { NxArray<DifficultVertex>::iterator it = std::lower_bound(difficultVertices.begin(), difficultVertices.end(), v, sortDifficultExt); #ifdef DEBUG_WELDER printf("-- Triangle %d (%d) (%d %d %d) (%d %d %d)", i, j, simTriangle[0], simTriangle[1], simTriangle[2], gfxTriangle[0], gfxTriangle[1], gfxTriangle[2]); printf(" %d %d\n", v.unMappedIndex, v.mappedIndex); #endif if (it == NULL || it->mappedIndex != simTriangle[j]) { // element hasn't been found //insert element #ifdef DEBUG_WELDER printf("Adding Diff %d %d\n", v.unMappedIndex, v.mappedIndex); #endif difficultVertices.push_back(v); // sort now, don't know whether this could be done less often, so far the list is extremely small std::sort(difficultVertices.begin(), difficultVertices.end(), sortDifficultExt); // get the freshly created item it = std::lower_bound(difficultVertices.begin(), difficultVertices.end(), v, sortDifficultExt); // element has to exist assert(it != NULL); } if (it->newUnMappedIndex >= 0) { gfxTriangle[j] = it->newUnMappedIndex; } else if (bitVector[it->unMappedIndex]) { #ifdef DEBUG_WELDER printf("Bit %d is true\n", it->unMappedIndex); #endif // create a new gfx vertex it->newUnMappedIndex = mMappingSize; addNewVertex(gfxTriangle[j]); setMapping(it->newUnMappedIndex, simTriangle[j]); gfxTriangle[j] = it->newUnMappedIndex; bitVector[it->newUnMappedIndex] = true; } else { #ifdef DEBUG_WELDER printf("Set Bit %d to true\n", it->unMappedIndex); #endif bitVector[it->unMappedIndex] = true; it->newUnMappedIndex = it->unMappedIndex; setMapping(it->newUnMappedIndex, simTriangle[j]); } } else if (simTriangle[j] >= oldMappingDomain) // only used when not a difficult vertex { // unamp index and update for (NxU32 k = 0; k < newVertices.size(); k++) { NewVertex& v = newVertices[k]; if (v.index == simTriangle[j] && v.mappedVertices == 1) { #ifdef DEBUG_WELDER printf("- Triangle %d (%d %d %d) (%d %d %d)", i, simTriangle[0], simTriangle[1], simTriangle[2], gfxTriangle[0], gfxTriangle[1], gfxTriangle[2]); printf(" %d %d\n", v.unMapIndex, v.index); #endif if (v.unMapIndex == -1) { #ifdef DEBUG_WELDER printf("Add Simple\n"); #endif v.unMapIndex = mMappingSize; //addNewVertex(vertices, vertexStride, normals, normalStride, texCoords, texStride, v.unMapParent); addNewVertex(gfxTriangle[j]); gfxTriangle[j] = v.unMapIndex; setMapping(v.unMapIndex, v.index); } else { #ifdef DEBUG_WELDER printf("Use Simple\n"); #endif gfxTriangle[j] = v.unMapIndex; } break; // for (k) } } } } } } if (updateVertices) { mMappingDomain = *meshData.numVerticesPtr; #ifdef DEBUG_WELDER static bool sanityCheck = true; if (sanityCheck) { // sanity check NxU32 temp = 0; for (NxU32 i = 0; i < mMappingSize; i++) { temp = NxMath::max(getMapping(i), temp); } if (temp != mMappingDomain - 1) { printf("Mapping Domain not right, is %d, should be %d\n", temp, mMappingDomain-1); assert(0); } for (NxU32 i = 0; i < numTriangles; i++) { const NxU32* simTriangle = (NxU32*)(((char*)meshData.indicesBegin) + meshData.indicesByteStride * (i*3)); NxU32* gfxTriangle = (NxU32*)(((char*)mWriteIndicesPtr) + mWriteIndicesStride * i); for (NxU32 j = 0; j < 3; j++) { if (simTriangle[j] != getMapping(gfxTriangle[j])) { printf("Triangle %d (%d) not correct (%d %d %d) -> (%d %d %d) != (%d %d %d)\n", i, 3*i+j, gfxTriangle[0], gfxTriangle[1], gfxTriangle[2], getMapping(gfxTriangle[0]), getMapping(gfxTriangle[1]), getMapping(gfxTriangle[2]), simTriangle[0], simTriangle[1], simTriangle[2]); assert(0); } } } } #endif } return; }
void processPacket (MWEvent *eventPacket) { MW244BPacket *p = new MW244BPacket ; p = eventPacket->eventDetail; /*cout << p->ID<< endl; cout << p->sequence_number<< endl; cout << p->score<< endl; cout << p->x_pos<< endl; cout << p->y_pos<< endl; cout << p->dir<< endl; cout << p->tagged_rat<< endl; cout << p->globalID<< endl; ConvertIncoming(p); cout << p->ID<< endl; cout << p->sequence_number<< endl; cout << p->score<< endl; cout << p->x_pos<< endl; cout << p->y_pos<< endl; cout << p->dir<< endl; cout << p->tagged_rat<< endl; cout << p->globalID<< endl; exit(0);*/ cout << "PP " << p->ID << endl; if (myPacket(p, &eventPacket->eventSource) && join)// BECAUSE WHILE YOU ARE STILL 0, you will get packets with ID 0 { return; } else { if (!join && expected_seqno[p->ID] <= p->sequence_number){ if (p->globalID == 7) // What if there is only player with global ID 7? :/ { cout << "You are one player too many :(" << endl; cout << "Please try again later." << endl; exit(0); } else { for (int i = 0; i < 100; i++) cout << "Incrementing for no reason" << endl; join = true; GLOBAL_ID = p->globalID+1; M->myRatIdIs(GLOBAL_ID); setMapping(); UpdateScoreCard(0); MW244BPacket q; makePacket(&q,'h',-1, updateSeqNo); sendPacketToPlayers(q); participants[p->ID]++; Rat r; r.playing = 1; cout << "NEW " << p->ID << endl; r.x=p->x_pos; r.y=p->y_pos; r.dir=(p->dir); M->mazeRats_[Mapping_idToIndex.find(p->ID)->second] = r; rat_array[p-> ID]=new MW244BPacket; rat_array[Mapping_idToIndex.find(p->ID)->second]=p; Loc x(p->x_pos); Loc y(p->y_pos); Direction dir(p-> dir); RatIndexType ratId(Mapping_idToIndex.find(p->ID)->second); SetRatPosition(ratId, x, y, dir); UpdateScoreCard(Mapping_idToIndex.find(p-> ID)->second); expected_seqno[p->ID] = p->sequence_number + 1; return; } } if (GLOBAL_ID < p->globalID && expected_seqno[p->ID] <= p->sequence_number ) GLOBAL_ID = p->globalID; if (p->status == 'a' && p->tagged_rat == M->myRatId().value()) { // cannot discard expected_seqno[p->ID] <= p->sequence_number // because we're getting this packet because the other side didn't get b :( // MUST send b MW244BPacket q; makePacket(&q,'b',-1, updateSeqNo); sendPacketToPlayers(q); cout<<p->sequence_number<<"Seq number"<<endl; cout<<prevseq_a[p->ID]<<"Previous Seq number"<<endl; if (p->sequence_number > prevseq_a[p->ID]) { // dealing with duplicates DrawString("You have been tagged!",21,200,250); M->scoreIs( M->score().value()-5 ); UpdateScoreCard(0); NewPosition(M); } prevseq_a[p->ID] = p->sequence_number; } else if (p->status == 'a' && expected_seqno[p->ID] <= p->sequence_number){ //RatIndexType ratId(p-> ID); //ClearRatPosition(ratId); RatIndexType ratId( Mapping_idToIndex.find(p->ID)->second); ClearRatPosition(ratId); } if (p->status == 'b' && expected_seqno[p->ID] <= p->sequence_number) { checkingzero = 1; updateSeqNo = true; } if (p->status == 'f' && expected_seqno[p->ID] <= p->sequence_number) { //player has left cout << "Player has gone :(" << endl; participants[p->ID] = -1;// in next section, will be incremented to 0 // automatically dealt with in ratstates RatIndexType ratId( Mapping_idToIndex.find(p->ID)->second); ClearRatPosition(ratId); // WHY IS THIS NOT WORKING? :/ clearSquare(p->x_pos, p->y_pos); cout << p->x_pos << "," << p->y_pos << endl; cout << M->mazeRats_[Mapping_idToIndex.find(p->ID)->second].x.value() << "," << M->mazeRats_[Mapping_idToIndex.find(p->ID)->second].y.value() << endl; } if (expected_seqno[p->ID] <= p->sequence_number) { // if this condition is false, then we are discarding the packet. Rat r; r.playing = 1; cout << "IF " << p->ID << endl; r.x=p->x_pos; r.y=p->y_pos; r.dir=(p->dir); M->mazeRats_[Mapping_idToIndex.find(p->ID)->second] = r; rat_array[p-> ID]=new MW244BPacket; rat_array[Mapping_idToIndex.find(p->ID)->second]=p; Loc x(p->x_pos); Loc y(p->y_pos); Direction dir(p-> dir); RatIndexType ratId(Mapping_idToIndex.find(p->ID)->second); SetRatPosition(ratId, x, y, dir); UpdateScoreCard(Mapping_idToIndex.find(p-> ID)->second); expected_seqno[p->ID] = p->sequence_number + 1; participants[p->ID]++; } } }
/* ----------------------------------------------------------------------- */ void play(void) { // initialisation cout << "Starting Play" << endl; //SetRatPosition(7,1,5,0); proj.present = false; proj.prev_x = proj.prev_y = proj.x = proj.y = 1; int turn = 0; updateSeqNo = true; join = false; for (int k = 0; k < 8; k++) participants[k] = prevseq_a[k] = 0; for (int k = 0; k < 8; k++) expected_seqno[k] = k+1; GLOBAL_ID = 0; checking = 1; checkingzero=1; MWEvent event; MW244BPacket incoming; event.eventDetail = &incoming; while (TRUE) { turn ++; NextEvent(&event, M->theSocket()); if (!M->peeking()) switch(event.eventType) { case EVENT_A: aboutFace(); break; case EVENT_S: leftTurn(); break; case EVENT_D: forward(); break; case EVENT_F: rightTurn(); break; case EVENT_LEFT_D: peekLeft(); break; case EVENT_BAR: shoot(); break; case EVENT_RIGHT_D: peekRight(); break; case EVENT_NETWORK: processPacket(&event); break; case EVENT_TIMEOUT: checking = (++checking) % 25; if (checking == 0 && !join){ cout << "Setting ID to zero" << endl; join = true; setMapping(); } else {cout << "TIMEOUT" << endl; participation = (++participation) % 30; manageMissiles(); if (participation == 29) { ratStates(); /* clean house */ for (int i = 0 ; i < 8 ; i++) participants[i] = 0; } } break; case EVENT_INT: quit(0); break; } else switch (event.eventType) { case EVENT_RIGHT_U: case EVENT_LEFT_U: peekStop(); break; case EVENT_NETWORK: processPacket(&event); break; } DoViewUpdate(); checking ++; manageMissiles(); if (join && checkingzero == 0) { MW244BPacket p; makePacket(&p,'a',kills, updateSeqNo); sendPacketToPlayers(p); } else if (join && turn % 2 == 0) { MW244BPacket p; makePacket(&p,'t',-1, updateSeqNo); sendPacketToPlayers(p); } } }
ViewerWindow::ViewerWindow(QWidget* parent, Qt::WindowFlags flags) : QMainWindow(parent, flags) , gameData(nullptr) , gameWorld(nullptr) , renderer(nullptr) { setMinimumSize(640, 480); QMenuBar* mb = this->menuBar(); QMenu* file = mb->addMenu("&File"); file->addAction("Open &Game", this, SLOT(loadGame())); file->addSeparator(); for(int i = 0; i < MaxRecentGames; ++i) { QAction* r = file->addAction(""); recentGames.append(r); connect(r, SIGNAL(triggered()), SLOT(openRecent())); } recentSep = file->addSeparator(); auto ex = file->addAction("E&xit"); ex->setShortcut(QKeySequence::Quit); connect(ex, SIGNAL(triggered()), QApplication::instance(), SLOT(closeAllWindows())); //----------------------- View Mode setup viewerWidget = new ViewerWidget; viewerWidget->context()->makeCurrent(); connect(this, SIGNAL(loadedData(GameWorld*)), viewerWidget, SLOT(dataLoaded(GameWorld*))); //------------- Object Viewer m_views[ViewMode::Object] = new ObjectViewer(viewerWidget); m_viewNames[ViewMode::Object] = "Objects"; //------------- Model Viewer m_views[ViewMode::Model] = new ModelViewer(viewerWidget); m_viewNames[ViewMode::Model] = "Model"; //------------- World Viewer m_views[ViewMode::World] = new WorldViewer(viewerWidget); m_viewNames[ViewMode::World] = "World"; //------------- display mode switching viewSwitcher = new QStackedWidget; auto signalMapper = new QSignalMapper(this); auto switchPanel = new QVBoxLayout(); int i = 0; for(auto viewer : m_views) { viewSwitcher->addWidget(viewer); connect(this, SIGNAL(loadedData(GameWorld*)), viewer, SLOT(showData(GameWorld*))); auto viewerButton = new QPushButton(m_viewNames[i].c_str()); signalMapper->setMapping(m_views[i], i); signalMapper->setMapping(viewerButton, i); connect(viewerButton, SIGNAL(clicked()), signalMapper, SLOT(map())); switchPanel->addWidget(viewerButton); i++; } // Map world viewer loading placements to switch to the world viewer connect(m_views[ViewMode::World], SIGNAL(placementsLoaded(QString)), signalMapper, SLOT(map())); switchView(ViewMode::Object); connect(m_views[ViewMode::Object], SIGNAL(showObjectModel(uint16_t)), this, SLOT(showObjectModel(uint16_t))); connect(m_views[ViewMode::Object], SIGNAL(showObjectModel(uint16_t)), m_views[ViewMode::Model], SLOT(showObject(uint16_t))); connect(this, SIGNAL(loadAnimations(QString)), m_views[ViewMode::Model], SLOT(loadAnimations(QString))); connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(switchView(int))); connect(signalMapper, SIGNAL(mapped(int)), viewSwitcher, SLOT(setCurrentIndex(int))); switchPanel->addStretch(); auto mainlayout = new QHBoxLayout(); mainlayout->addLayout(switchPanel); mainlayout->addWidget(viewSwitcher); auto mainwidget = new QWidget(); mainwidget->setLayout(mainlayout); QMenu* data = mb->addMenu("&Data"); //data->addAction("Export &Model", objectViewer, SLOT(exportModel())); QMenu* anim = mb->addMenu("&Animation"); anim->addAction("Load &Animations", this, SLOT(openAnimations())); QMenu* map = mb->addMenu("&Map"); map->addAction("Load IPL", m_views[ViewMode::World], SLOT(loadPlacements())); this->setCentralWidget(mainwidget); updateRecentGames(); }