# HG changeset patch # User vitiv # Date 1356948743 -7200 # Node ID 14b938faec692a9ecd3ced9ac269d1e8c7d6362b # Parent 9d9b498cfb032318b914837e2622e96f33e87f94# Parent c039ac6f33e01a33986270ee06686e8d9dfbc17d merged changes diff -r 9d9b498cfb03 -r 14b938faec69 CMakeLists.txt --- a/CMakeLists.txt Sun Dec 30 16:04:28 2012 +0200 +++ b/CMakeLists.txt Mon Dec 31 12:12:23 2012 +0200 @@ -130,8 +130,8 @@ find_package(SDL_mixer REQUIRED) set(DYLIB_SMPEG "-dylib_file @loader_path/Frameworks/smpeg.framework/Versions/A/smpeg:${SDLMIXER_LIBRARY}/Versions/A/Frameworks/smpeg.framework/Versions/A/smpeg") set(DYLIB_MIKMOD "-dylib_file @loader_path/Frameworks/mikmod.framework/Versions/A/mikmod:${SDLMIXER_LIBRARY}/Versions/A/Frameworks/mikmod.framework/Versions/A/mikmod") - set(pascal_flags "-k${DYLIB_SMPEG}" "-k${DYLIB_MIKMOD}" ${pascal_flags}) - set(CMAKE_C_FLAGS "${DYLIB_SMPEG}" "${DYLIB_MIKMOD}" ${CMAKE_C_FLAGS}) + set(CMAKE_C_FLAGS "${DYLIB_SMPEG} ${DYLIB_MIKMOD}") + list(APPEND pascal_flags "-k${DYLIB_SMPEG}" "-k${DYLIB_MIKMOD}") endif() #CMAKE_OSX_ARCHITECTURES and CMAKE_OSX_SYSROOT need to be set for universal binary and correct linking @@ -161,9 +161,9 @@ endif() #add user framework directory, other paths can be passed via FPFLAGS - set(pascal_flags "-Ff~/Library/Frameworks" ${pascal_flags}) + list(APPEND pascal_flags "-Ff~/Library/Frameworks") #set deployment target - set(pascal_flags "-k-macosx_version_min" "-k${minimum_macosx_version}" "-XR${CMAKE_OSX_SYSROOT}" ${pascal_flags}) + list(APPEND pascal_flags "-k-macosx_version_min" "-k${minimum_macosx_version}" "-XR${CMAKE_OSX_SYSROOT}") #silly libav that always brings in VideoDecoderAcceleration, avaible only from 10.6.3 if(NOT NOVIDEOREC AND ${minimum_macosx_version} VERSION_LESS "10.6") @@ -184,10 +184,10 @@ endif (CMAKE_BUILD_TYPE) #set default flags values for all projects (unless MINIMAL_FLAGS is true) -if(NOT MINIMAL_FLAGS) - set(CMAKE_C_FLAGS "-pipe") - set(CMAKE_C_FLAGS_RELEASE "-w -Os -fomit-frame-pointer") - set(CMAKE_C_FLAGS_DEBUG "-Wall -O0 -g -DDEBUG") +if(NOT ${MINIMAL_FLAGS}) + set(CMAKE_C_FLAGS "-pipe ${CMAKE_C_FLAGS}") + set(CMAKE_C_FLAGS_RELEASE "-w -Os -fomit-frame-pointer ${CMAKE_C_FLAGS_RELEASE}") + set(CMAKE_C_FLAGS_DEBUG "-Wall -O0 -g -DDEBUG ${CMAKE_C_FLAGS_DEBUG}") set(CMAKE_CXX_FLAGS ${CMAKE_C_FLAGS}) set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE}) set(CMAKE_CXX_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG}) @@ -210,7 +210,7 @@ endif() endif() -set(pascal_flags ${fpflags_parsed} # user flags +list(APPEND pascal_flags ${fpflags_parsed} # user flags "-vm4079,4080,4081" # fpc output format "-B" # compile all units "-FE${PROJECT_BINARY_DIR}/bin" # fpc output directory @@ -218,19 +218,18 @@ "-Cs2000000" # stack size "-vewnq" # fpc output verbosity "-dDEBUGFILE" # macro for engine output - ${pascal_flags} # adding to list ) -set(haskell_flags "-O2" ${ghflags_parsed} ${haskell_flags}) +list(APPEND haskell_flags "-O2" ${ghflags_parsed}) #get BUILD_TYPE and enable/disable optimisation message(STATUS "Using ${CMAKE_BUILD_TYPE} configuration") if(CMAKE_BUILD_TYPE MATCHES "DEBUG") - set(pascal_flags "-O-" "-g" "-gl" "-gv" ${pascal_flags}) - set(haskell_flags "-Wall" "-debug" "-dcore-lint" "-fno-warn-unused-do-bind" ${haskell_flags}) + list(APPEND pascal_flags "-O-" "-g" "-gl" "-gv") + list(APPEND haskell_flags "-Wall" "-debug" "-dcore-lint" "-fno-warn-unused-do-bind") else() # set(pascal_flags "-O3" "-OpPENTIUM4" "-CfSSE3" "-Xs" "-Si" ${pascal_flags}) - set(pascal_flags "-Os" "-Xs" "-Si" ${pascal_flags}) - set(haskell_flags "-w" "-fno-warn-unused-do-bind" ${haskell_flags}) + list(APPEND pascal_flags "-Os" "-Xs" "-Si") + list(APPEND haskell_flags "-w" "-fno-warn-unused-do-bind") endif() @@ -264,14 +263,14 @@ message(STATUS "LUA will be provided by the bundled sources") add_subdirectory(misc/liblua) #linking with liblua.a requires system readline - set(pascal_flags "-k${EXECUTABLE_OUTPUT_PATH}/lib${LUA_LIBRARY}.a" "-k-lreadline" ${pascal_flags}) + list(APPEND pascal_flags "-k${EXECUTABLE_OUTPUT_PATH}/lib${LUA_LIBRARY}.a" "-k-lreadline") endif() #physfs library (static on unix, dll on win32) add_subdirectory(misc/physfs) if(NOT WIN32) - set(pascal_flags "-k${LIBRARY_OUTPUT_PATH}/libphysfs.a" ${pascal_flags}) + list(APPEND pascal_flags "-k${LIBRARY_OUTPUT_PATH}/libphysfs.a") endif() diff -r 9d9b498cfb03 -r 14b938faec69 QTfrontend/CMakeLists.txt --- a/QTfrontend/CMakeLists.txt Sun Dec 30 16:04:28 2012 +0200 +++ b/QTfrontend/CMakeLists.txt Mon Dec 31 12:12:23 2012 +0200 @@ -62,7 +62,7 @@ file(GLOB_RECURSE UIcpp ui/*.cpp) file(GLOB UtilCpp util/*.cpp) -set(hwfr_src +list(APPEND hwfr_src ${ModelCpp} ${NetCpp} ${UIcpp} @@ -83,7 +83,7 @@ #xfire integration if(WIN32) - set(hwfr_src ${hwfr_src} xfire.cpp ../misc/xfire/xfiregameclient.cpp) + list(APPEND hwfr_src xfire.cpp ../misc/xfire/xfiregameclient.cpp) endif(WIN32) if(MINGW) @@ -92,9 +92,9 @@ COMMAND windres -I ${CMAKE_CURRENT_SOURCE_DIR} -i ${CMAKE_CURRENT_SOURCE_DIR}/hedgewars.rc -o ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o) - set(hwfr_src ${hwfr_src} ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o) + list(APPEND hwfr_src ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o) else(MINGW) - set(hwfr_src ${hwfr_src} hedgewars.rc) + list(APPEND hwfr_src hedgewars.rc) endif(MINGW) file(GLOB ModelHdr model/*.h) @@ -133,7 +133,7 @@ if(${BUILD_ENGINE_LIBRARY}) add_definitions(-DHWLIBRARY=1) set(hwlibname "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}hwengine${CMAKE_SHARED_LIBRARY_SUFFIX}") - set(HW_LINK_LIBS ${hwlibname} ${HW_LINK_LIBS}) + list(APPEND HW_LINK_LIBS ${hwlibname}) endif() qt4_add_resources(hwfr_rez_src ${hwfr_rez}) @@ -143,8 +143,8 @@ if(APPLE) find_library(iokit_framework NAMES IOKit) - set(HW_LINK_LIBS ${iokit_framework} ${HW_LINK_LIBS}) - set(hwfr_src ${hwfr_src} CocoaInitializer.mm + list(APPEND HW_LINK_LIBS ${iokit_framework}) + list(APPEND hwfr_src CocoaInitializer.mm InstallController.cpp M3Panel.mm M3InstallController.m @@ -154,8 +154,8 @@ find_package(Sparkle) if(SPARKLE_FOUND) add_definitions(-DSPARKLE_ENABLED) - set(hwfr_src ${hwfr_src} AutoUpdater.cpp SparkleAutoUpdater.mm) - set(HW_LINK_LIBS ${SPARKLE_LIBRARY} ${HW_LINK_LIBS}) + list(APPEND hwfr_src AutoUpdater.cpp SparkleAutoUpdater.mm) + list(APPEND HW_LINK_LIBS ${SPARKLE_LIBRARY}) endif() endif() endif() @@ -177,22 +177,20 @@ set_target_properties(hedgewars PROPERTIES LINK_FLAGS "-Wl,-rpath,${CMAKE_INSTALL_PREFIX}/${target_library_install_dir}") endif() -set(HW_LINK_LIBS +list(APPEND HW_LINK_LIBS physfs ${QT_LIBRARIES} ${SDL_LIBRARY} ${SDLMIXER_LIBRARY} ${FFMPEG_LIBRARIES} - ${HW_LINK_LIBS} ) if(WIN32 AND NOT UNIX) if(NOT SDL_LIBRARY) - set(HW_LINK_LIBS ${HW_LINK_LIBS} SDL) + list(APPEND HW_LINK_LIBS SDL) endif() - set(HW_LINK_LIBS - ${HW_LINK_LIBS} + list(APPEND HW_LINK_LIBS ole32 oleaut32 winspool diff -r 9d9b498cfb03 -r 14b938faec69 QTfrontend/binds.cpp --- a/QTfrontend/binds.cpp Sun Dec 30 16:04:28 2012 +0200 +++ b/QTfrontend/binds.cpp Mon Dec 31 12:12:23 2012 +0200 @@ -20,17 +20,15 @@ const BindAction cbinds[BINDS_NUMBER] = { - {"+up", "up", QT_TRANSLATE_NOOP("binds", "up"), QT_TRANSLATE_NOOP("binds (categories)", "Basic controls"), QT_TRANSLATE_NOOP("binds (descriptions)", "Move your hogs and aim:")}, + {"+up", "up", QT_TRANSLATE_NOOP("binds", "up"), QT_TRANSLATE_NOOP("binds (categories)", "Movement"), QT_TRANSLATE_NOOP("binds (descriptions)", "Hedgehog movement")}, {"+left", "left", QT_TRANSLATE_NOOP("binds", "left"), NULL, NULL}, {"+right", "right", QT_TRANSLATE_NOOP("binds", "right"), NULL, NULL}, {"+down", "down", QT_TRANSLATE_NOOP("binds", "down"), NULL, NULL}, {"+precise", "left_shift", QT_TRANSLATE_NOOP("binds", "precise aim"), NULL, NULL}, {"ljump", "return", QT_TRANSLATE_NOOP("binds", "long jump"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Traverse gaps and obstacles by jumping:")}, {"hjump", "backspace", QT_TRANSLATE_NOOP("binds", "high jump"), NULL, NULL}, - {"+attack", "space", QT_TRANSLATE_NOOP("binds", "attack"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Fire your selected weapon or trigger an utility item:")}, - {"put", "mousel", QT_TRANSLATE_NOOP("binds", "put"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Pick a weapon or a target location under the cursor:")}, {"switch", "tab", QT_TRANSLATE_NOOP("binds", "switch"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Switch your currently active hog (if possible):")}, - {"ammomenu", "mouser", QT_TRANSLATE_NOOP("binds", "ammo menu"), QT_TRANSLATE_NOOP("binds (categories)", "Weapon controls"), QT_TRANSLATE_NOOP("binds (descriptions)", "Pick a weapon or utility item:")}, + {"ammomenu", "mouser", QT_TRANSLATE_NOOP("binds", "ammo menu"), QT_TRANSLATE_NOOP("binds (categories)", "Weapons"), QT_TRANSLATE_NOOP("binds (descriptions)", "Pick a weapon or utility item:")}, {"slot 1", "f1", QT_TRANSLATE_NOOP("binds", "slot 1"), NULL, NULL}, {"slot 2", "f2", QT_TRANSLATE_NOOP("binds", "slot 2"), NULL, NULL}, {"slot 3", "f3", QT_TRANSLATE_NOOP("binds", "slot 3"), NULL, NULL}, @@ -46,7 +44,9 @@ {"timer 3", "3", QT_TRANSLATE_NOOP("binds", "timer 3 sec"), NULL, NULL}, {"timer 4", "4", QT_TRANSLATE_NOOP("binds", "timer 4 sec"), NULL, NULL}, {"timer 5", "5", QT_TRANSLATE_NOOP("binds", "timer 5 sec"), NULL, NULL}, - {"findhh", "h", QT_TRANSLATE_NOOP("binds", "find hedgehog"), QT_TRANSLATE_NOOP("binds (categories)", "Camera and cursor controls"), QT_TRANSLATE_NOOP("binds (descriptions)", "Move the camera to the active hog:")}, + {"+attack", "space", QT_TRANSLATE_NOOP("binds", "attack"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Fire your selected weapon or trigger an utility item:")}, + {"put", "mousel", QT_TRANSLATE_NOOP("binds", "put"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Pick a weapon or a target location under the cursor:")}, + {"findhh", "h", QT_TRANSLATE_NOOP("binds", "find hedgehog"), QT_TRANSLATE_NOOP("binds (categories)", "Camera"), QT_TRANSLATE_NOOP("binds (descriptions)", "Move the camera to the active hog:")}, {"+cur_u", "[8]", QT_TRANSLATE_NOOP("binds", "up"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Move the cursor or camera without using the mouse:")}, {"+cur_l", "[4]", QT_TRANSLATE_NOOP("binds", "left"), NULL, NULL}, {"+cur_r", "[6]", QT_TRANSLATE_NOOP("binds", "right"), NULL, NULL}, @@ -55,7 +55,7 @@ {"zoomin", "wheelup", QT_TRANSLATE_NOOP("binds", "zoom in"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Modify the camera's zoom level:")}, {"zoomout", "wheeldown", QT_TRANSLATE_NOOP("binds", "zoom out"), NULL, NULL}, {"zoomreset", "mousem", QT_TRANSLATE_NOOP("binds", "reset zoom"), NULL, NULL}, - {"chat", "t", QT_TRANSLATE_NOOP("binds", "chat"), QT_TRANSLATE_NOOP("binds (categories)", "Other"), QT_TRANSLATE_NOOP("binds (descriptions)", "Talk to your team or all participants:")}, + {"chat", "t", QT_TRANSLATE_NOOP("binds", "chat"), QT_TRANSLATE_NOOP("binds (categories)", "Miscellaneous"), QT_TRANSLATE_NOOP("binds (descriptions)", "Talk to your team or all participants:")}, {"history", "`", QT_TRANSLATE_NOOP("binds", "chat history"), NULL, NULL}, {"pause", "p", QT_TRANSLATE_NOOP("binds", "pause"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Pause, continue or leave your game:")}, {"quit", "escape", QT_TRANSLATE_NOOP("binds", "quit"), NULL, NULL}, @@ -65,7 +65,7 @@ {"mute", "8", QT_TRANSLATE_NOOP("binds", "mute audio"), NULL, NULL}, {"fullscr", "f12", QT_TRANSLATE_NOOP("binds", "change mode"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Toggle fullscreen mode:")}, {"capture", "c", QT_TRANSLATE_NOOP("binds", "capture"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Take a screenshot:")}, - {"rotmask", "delete", QT_TRANSLATE_NOOP("binds", "hedgehogs\ninfo"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Toggle labels above hedgehogs:")}, + {"rotmask", "delete", QT_TRANSLATE_NOOP("binds", "hedgehog info"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Toggle labels above hedgehogs:")}, #ifdef VIDEOREC {"record", "r", QT_TRANSLATE_NOOP("binds", "record"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Record video:")} #endif diff -r 9d9b498cfb03 -r 14b938faec69 QTfrontend/game.cpp --- a/QTfrontend/game.cpp Sun Dec 30 16:04:28 2012 +0200 +++ b/QTfrontend/game.cpp Mon Dec 31 12:12:23 2012 +0200 @@ -31,6 +31,7 @@ #include "gamecfgwidget.h" #include "teamselect.h" #include "proto.h" +#include "binds.h" #include "campaign.h" #include @@ -75,6 +76,18 @@ SetGameState(gsStopped); } +void HWGame::addKeyBindings(QByteArray * buf) +{ + for(int i = 0; i < BINDS_NUMBER; i++) + { + QString value = config->value(QString("Binds/%1").arg(cbinds[i].action), cbinds[i].strbind).toString(); + if (value.isEmpty() || value == "default") continue; + + QString bind = QString("edbind " + value + " " + cbinds[i].action); + HWProto::addStringToBuffer(*buf, bind); + } +} + void HWGame::commonConfig() { QByteArray buf; @@ -92,6 +105,8 @@ } HWProto::addStringToBuffer(buf, gt); + addKeyBindings(&buf); + buf += gamecfg->getFullConfig(); if (m_pTeamSelWidget) @@ -104,10 +119,11 @@ HWProto::addStringToBuffer(buf, QString("eammreinf %1").arg(ammostr.mid(3 * cAmmoNumber, cAmmoNumber))); if(gamecfg->schemeData(15).toBool() || !gamecfg->schemeData(21).toBool()) HWProto::addStringToBuffer(buf, QString("eammstore")); HWProto::addStringListToBuffer(buf, - team.teamGameConfig(gamecfg->getInitHealth())); + team.teamGameConfig(gamecfg->getInitHealth(), config)); ; } } + RawSendIPC(buf); } @@ -121,6 +137,8 @@ QByteArray teamscfg; ThemeModel * themeModel = DataManager::instance().themeModel(); + addKeyBindings(&teamscfg); + HWProto::addStringToBuffer(teamscfg, "TL"); HWProto::addStringToBuffer(teamscfg, QString("etheme %1") .arg((themeModel->rowCount() > 0) ? themeModel->index(rand() % themeModel->rowCount()).data().toString() : "steel")); @@ -134,7 +152,7 @@ team1.setNumHedgehogs(4); HWNamegen::teamRandomNames(team1,true); HWProto::addStringListToBuffer(teamscfg, - team1.teamGameConfig(100)); + team1.teamGameConfig(100, config)); HWTeam team2; team2.setDifficulty(4); @@ -144,7 +162,7 @@ HWNamegen::teamRandomNames(team2,true); while(!team2.name().compare(team1.name()) || !team2.hedgehog(0).Hat.compare(team1.hedgehog(0).Hat)); HWProto::addStringListToBuffer(teamscfg, - team2.teamGameConfig(100)); + team2.teamGameConfig(100, config)); HWProto::addStringToBuffer(teamscfg, QString("eammloadt %1").arg(cDefaultAmmoStore->mid(0, cAmmoNumber))); HWProto::addStringToBuffer(teamscfg, QString("eammprob %1").arg(cDefaultAmmoStore->mid(cAmmoNumber, cAmmoNumber))); @@ -152,6 +170,7 @@ HWProto::addStringToBuffer(teamscfg, QString("eammreinf %1").arg(cDefaultAmmoStore->mid(3 * cAmmoNumber, cAmmoNumber))); HWProto::addStringToBuffer(teamscfg, QString("eammstore")); HWProto::addStringToBuffer(teamscfg, QString("eammstore")); + RawSendIPC(teamscfg); } @@ -162,6 +181,8 @@ HWProto::addStringToBuffer(traincfg, "eseed " + QUuid::createUuid().toString()); HWProto::addStringToBuffer(traincfg, "escript " + training); + addKeyBindings(&traincfg); + RawSendIPC(traincfg); } @@ -173,6 +194,8 @@ HWProto::addStringToBuffer(campaigncfg, "escript " + campaignScript); + addKeyBindings(&campaigncfg); + RawSendIPC(campaigncfg); } diff -r 9d9b498cfb03 -r 14b938faec69 QTfrontend/game.h --- a/QTfrontend/game.h Sun Dec 30 16:04:28 2012 +0200 +++ b/QTfrontend/game.h Mon Dec 31 12:12:23 2012 +0200 @@ -103,6 +103,7 @@ TeamSelWidget* m_pTeamSelWidget; GameType gameType; + void addKeyBindings(QByteArray * buf); void commonConfig(); void SendConfig(); void SendQuickConfig(); diff -r 9d9b498cfb03 -r 14b938faec69 QTfrontend/gameuiconfig.cpp --- a/QTfrontend/gameuiconfig.cpp Sun Dec 30 16:04:28 2012 +0200 +++ b/QTfrontend/gameuiconfig.cpp Mon Dec 31 12:12:23 2012 +0200 @@ -53,6 +53,13 @@ connect(Form->ui.pageOptions->CBFrontendMusic, SIGNAL(toggled(bool)), Form, SLOT(Music(bool))); + for(int i = 0; i < BINDS_NUMBER; i++) + { + m_binds.append(BindAction()); + m_binds[i].action = cbinds[i].action; + m_binds[i].strbind = cbinds[i].strbind; + } + //Form->resize(value("frontend/width", 640).toUInt(), value("frontend/height", 450).toUInt()); resizeToConfigValues(); @@ -150,6 +157,15 @@ for(int i = model->rowCount() - 1; i >= 0; --i) model->item(i)->setData(QColor(value(QString("colors/color%1").arg(i), model->item(i)->data().value()).value())); } + + { // load binds + QStandardItemModel * binds = DataManager::instance().bindsModel(); + for(int i = 0; i < BINDS_NUMBER; i++) + { + m_binds[i].strbind = value(QString("Binds/%1").arg(m_binds[i].action), cbinds[i].strbind).toString(); + if (m_binds[i].strbind.isEmpty() || m_binds[i].strbind == "default") m_binds[i].strbind = cbinds[i].strbind; + } + } } void GameUIConfig::reloadVideosValues(void) @@ -604,3 +620,16 @@ { return Form->ui.pageOptions->checkRecordAudio->isChecked(); } + +// Gets a bind for a bindID +QString GameUIConfig::bind(int bindID) +{ + return m_binds[bindID].strbind; +} + +// Sets a bind for a bindID and saves it +void GameUIConfig::setBind(int bindID, QString & strbind) +{ + m_binds[bindID].strbind = strbind; + setValue(QString("Binds/%1").arg(m_binds[bindID].action), strbind); +} diff -r 9d9b498cfb03 -r 14b938faec69 QTfrontend/gameuiconfig.h --- a/QTfrontend/gameuiconfig.h Sun Dec 30 16:04:28 2012 +0200 +++ b/QTfrontend/gameuiconfig.h Mon Dec 31 12:12:23 2012 +0200 @@ -23,6 +23,8 @@ #include #include #include +#include +#include "binds.h" class HWForm; class QSettings; @@ -64,6 +66,8 @@ void resizeToConfigValues(); quint32 stereoMode() const; void setValue(const QString & key, const QVariant & value); + QString bind(int bindID); + void setBind(int bindID, QString & strbind); QString AVFormat(); QString videoCodec(); @@ -91,7 +95,8 @@ private: bool netPasswordIsValid(); bool eventFilter(QObject *object, QEvent *event); - QString temphash; + QString temphash; + QList m_binds; }; #endif diff -r 9d9b498cfb03 -r 14b938faec69 QTfrontend/hwform.cpp --- a/QTfrontend/hwform.cpp Sun Dec 30 16:04:28 2012 +0200 +++ b/QTfrontend/hwform.cpp Mon Dec 31 12:12:23 2012 +0200 @@ -155,9 +155,9 @@ ui.pageRoomsList->setSettings(config); ui.pageNetGame->chatWidget->setSettings(config); ui.pageRoomsList->chatWidget->setSettings(config); + ui.pageOptions->setConfig(config); #ifdef VIDEOREC ui.pageVideos->init(config); - ui.pageOptions->setConfig(config); #endif #ifdef __APPLE__ @@ -975,18 +975,8 @@ void HWForm::DeleteTeam(const QString & teamName) { - QMessageBox reallyDeleteMsg(this); - reallyDeleteMsg.setIcon(QMessageBox::Question); - reallyDeleteMsg.setWindowTitle(QMessageBox::tr("Teams - Are you sure?")); - reallyDeleteMsg.setText(QMessageBox::tr("Do you really want to delete the team '%1'?").arg(teamName)); - reallyDeleteMsg.setWindowModality(Qt::WindowModal); - reallyDeleteMsg.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - - if (reallyDeleteMsg.exec() == QMessageBox::Ok) - { - ui.pageEditTeam->deleteTeam(teamName); - UpdateTeamsLists(); - } + ui.pageEditTeam->deleteTeam(teamName); + UpdateTeamsLists(); } void HWForm::DeleteScheme() diff -r 9d9b498cfb03 -r 14b938faec69 QTfrontend/main.cpp --- a/QTfrontend/main.cpp Sun Dec 30 16:04:28 2012 +0200 +++ b/QTfrontend/main.cpp Mon Dec 31 12:12:23 2012 +0200 @@ -139,8 +139,7 @@ HWApplication app(argc, argv); QLabel *splash = NULL; - //enabled on win and osx, disable if it doesn't look good -#if defined Q_WS_WIN || defined Q_WS_MAC +#if defined Q_WS_WIN QPixmap pixmap(":res/splash.png"); splash = new QLabel(0, Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint); splash->setAttribute(Qt::WA_TranslucentBackground); diff -r 9d9b498cfb03 -r 14b938faec69 QTfrontend/team.cpp --- a/QTfrontend/team.cpp Sun Dec 30 16:04:28 2012 +0200 +++ b/QTfrontend/team.cpp Mon Dec 31 12:12:23 2012 +0200 @@ -23,10 +23,12 @@ #include #include #include +#include #include "team.h" #include "hwform.h" #include "DataManager.h" +#include "gameuiconfig.h" HWTeam::HWTeam(const QString & teamname) : QObject(0) @@ -50,7 +52,7 @@ { m_binds.append(BindAction()); m_binds[i].action = cbinds[i].action; - m_binds[i].strbind = cbinds[i].strbind; + m_binds[i].strbind = QString(); } m_rounds = 0; m_wins = 0; @@ -110,7 +112,7 @@ { m_binds.append(BindAction()); m_binds[i].action = cbinds[i].action; - m_binds[i].strbind = cbinds[i].strbind; + m_binds[i].strbind = QString(); } m_rounds = 0; m_wins = 0; @@ -191,7 +193,7 @@ m_hedgehogs[i].Suicides = teamfile.value(hh + "Suicides", 0).toInt(); } for(int i = 0; i < BINDS_NUMBER; i++) - m_binds[i].strbind = teamfile.value(QString("Binds/%1").arg(m_binds[i].action), cbinds[i].strbind).toString(); + m_binds[i].strbind = teamfile.value(QString("Binds/%1").arg(m_binds[i].action), QString()).toString(); for(int i = 0; i < MAX_ACHIEVEMENTS; i++) if(achievements[i][0][0]) AchievementProgress[i] = teamfile.value(QString("Achievements/%1").arg(achievements[i][0]), 0).toUInt(); @@ -257,7 +259,7 @@ return true; } -QStringList HWTeam::teamGameConfig(quint32 InitHealth) const +QStringList HWTeam::teamGameConfig(quint32 InitHealth, GameUIConfig * config) const { QStringList sl; if (m_isNetTeam) @@ -273,9 +275,15 @@ sl.push_back(QString("eflag " + m_flag)); if (!m_isNetTeam) + { for(int i = 0; i < BINDS_NUMBER; i++) - if(!m_binds[i].strbind.isEmpty()) + { + if(m_binds[i].strbind.isEmpty() || m_binds[i].strbind == "default") + sl.push_back(QString("ebind " + config->bind(i) + " " + m_binds[i].action)); + else sl.push_back(QString("ebind " + m_binds[i].strbind + " " + m_binds[i].action)); + } + } for (int t = 0; t < m_numHedgehogs; t++) { diff -r 9d9b498cfb03 -r 14b938faec69 QTfrontend/team.h --- a/QTfrontend/team.h Sun Dec 30 16:04:28 2012 +0200 +++ b/QTfrontend/team.h Mon Dec 31 12:12:23 2012 +0200 @@ -93,7 +93,7 @@ void incWins(); // convert team info into strings for further computation - QStringList teamGameConfig(quint32 InitHealth) const; + QStringList teamGameConfig(quint32 InitHealth, GameUIConfig * config) const; // comparison operators bool operator == (const HWTeam& t1) const; diff -r 9d9b498cfb03 -r 14b938faec69 QTfrontend/ui/page/pageeditteam.cpp --- a/QTfrontend/ui/page/pageeditteam.cpp Sun Dec 30 16:04:28 2012 +0200 +++ b/QTfrontend/ui/page/pageeditteam.cpp Mon Dec 31 12:12:23 2012 +0200 @@ -30,6 +30,7 @@ #include #include "SquareLabel.h" #include "HWApplication.h" +#include "keybinder.h" #include "DataManager.h" #include "HatModel.h" @@ -39,16 +40,16 @@ QLayout * PageEditTeam::bodyLayoutDefinition() { QGridLayout * pageLayout = new QGridLayout(); - QTabWidget * tbw = new QTabWidget(); + tbw = new QTabWidget(); QWidget * page1 = new QWidget(this); - QWidget * page2 = new QWidget(this); + binder = new KeyBinder(this, tr("Select an action to choose a custom key bind for this team"), tr("Use my default"), tr("Reset all binds")); + connect(binder, SIGNAL(resetAllBinds()), this, SLOT(resetAllBinds())); tbw->addTab(page1, tr("General")); - tbw->addTab(page2, tr("Advanced")); + tbw->addTab(binder, tr("Custom Controls")); pageLayout->addWidget(tbw, 0, 0, 1, 3); QHBoxLayout * page1Layout = new QHBoxLayout(page1); page1Layout->setAlignment(Qt::AlignTop); - QGridLayout * page2Layout = new QGridLayout(page2); // ====== Page 1 ====== QVBoxLayout * vbox1 = new QVBoxLayout(); @@ -157,52 +158,6 @@ vbox1->addStretch(); vbox2->addStretch(); -// ====== Page 2 ====== - GBoxBinds = new QGroupBox(this); - GBoxBinds->setTitle(QGroupBox::tr("Key binds")); - QGridLayout * GBBLayout = new QGridLayout(GBoxBinds); - BindsBox = new QToolBox(GBoxBinds); - BindsBox->setLineWidth(0); - GBBLayout->addWidget(BindsBox); - page2Layout->addWidget(GBoxBinds, 0, 0); - - quint16 i = 0; - quint16 num = 0; - QWidget * curW = NULL; - QGridLayout * pagelayout = NULL; - QLabel* l = NULL; - while (i < BINDS_NUMBER) - { - if(cbinds[i].category != NULL) - { - if(curW != NULL) - { - l = new QLabel(curW); - l->setText(""); - pagelayout->addWidget(l, num++, 0, 1, 2); - } - curW = new QWidget(this); - BindsBox->addItem(curW, HWApplication::translate("binds (categories)", cbinds[i].category)); - pagelayout = new QGridLayout(curW); - num = 0; - } - if(cbinds[i].description != NULL) - { - l = new QLabel(curW); - l->setText((num > 0 ? QString("\n") : QString("")) + HWApplication::translate("binds (descriptions)", cbinds[i].description)); - pagelayout->addWidget(l, num++, 0, 1, 2); - } - - l = new QLabel(curW); - l->setText(HWApplication::translate("binds", cbinds[i].name)); - l->setAlignment(Qt::AlignRight); - pagelayout->addWidget(l, num, 0); - - CBBind[i] = new QComboBox(curW); - CBBind[i]->setModel(DataManager::instance().bindsModel()); - pagelayout->addWidget(CBBind[i++], num++, 1); - } - return pageLayout; } @@ -407,6 +362,9 @@ void PageEditTeam::loadTeam(const HWTeam & team) { + tbw->setCurrentIndex(0); + binder->resetInterface(); + TeamNameEdit->setText(team.name()); CBTeamLvl->setCurrentIndex(team.difficulty()); @@ -431,10 +389,12 @@ QStandardItemModel * binds = DataManager::instance().bindsModel(); for(int i = 0; i < BINDS_NUMBER; i++) { + if (team.keyBind(i).isEmpty()) continue; + QModelIndexList mdl = binds->match(binds->index(0, 0), Qt::UserRole + 1, team.keyBind(i), 1, Qt::MatchExactly); if(mdl.size() == 1) - CBBind[i]->setCurrentIndex(mdl[0].row()); + binder->setBindIndex(i, mdl[0].row()); else qDebug() << "Binds: cannot find" << team.keyBind(i); } @@ -465,7 +425,7 @@ QStandardItemModel * binds = DataManager::instance().bindsModel(); for(int i = 0; i < BINDS_NUMBER; i++) { - team.bindKey(i, binds->index(CBBind[i]->currentIndex(), 0).data(Qt::UserRole + 1).toString()); + team.bindKey(i, binds->index(binder->bindIndex(i), 0).data(Qt::UserRole + 1).toString()); } return team; @@ -475,3 +435,10 @@ { data().saveToFile(); } + +// When the "Use default for all binds" is pressed... +void PageEditTeam::resetAllBinds() +{ + for (int i = 0; i < BINDS_NUMBER; i++) + binder->setBindIndex(i, 0); +} diff -r 9d9b498cfb03 -r 14b938faec69 QTfrontend/ui/page/pageeditteam.h --- a/QTfrontend/ui/page/pageeditteam.h Sun Dec 30 16:04:28 2012 +0200 +++ b/QTfrontend/ui/page/pageeditteam.h Mon Dec 31 12:12:23 2012 +0200 @@ -28,6 +28,7 @@ #include "team.h" class SquareLabel; +class KeyBinder; class PageEditTeam : public AbstractPage { @@ -44,6 +45,7 @@ void CBFort_activated(const QString & gravename); private: + QTabWidget * tbw; QSignalMapper* signalMapper1; QSignalMapper* signalMapper2; QGroupBox *GBoxHedgehogs; @@ -60,9 +62,9 @@ QLineEdit * TeamNameEdit; QLineEdit * HHNameEdit[HEDGEHOGS_PER_TEAM]; QComboBox * HHHats[HEDGEHOGS_PER_TEAM]; - QComboBox * CBBind[BINDS_NUMBER]; HWTeam data(); QString m_playerHash; + KeyBinder * binder; QLayout * bodyLayoutDefinition(); QLayout * footerLayoutDefinition(); @@ -85,6 +87,7 @@ void testSound(); void fixHHname(int idx); + void resetAllBinds(); }; #endif diff -r 9d9b498cfb03 -r 14b938faec69 QTfrontend/ui/page/pageoptions.cpp --- a/QTfrontend/ui/page/pageoptions.cpp Sun Dec 30 16:04:28 2012 +0200 +++ b/QTfrontend/ui/page/pageoptions.cpp Mon Dec 31 12:12:23 2012 +0200 @@ -23,14 +23,17 @@ #include #include #include +#include #include #include #include -#include +#include +#include #include #include #include #include +#include #include "pageoptions.h" #include "gameuiconfig.h" @@ -40,6 +43,8 @@ #include "DataManager.h" #include "LibavInteraction.h" #include "AutoUpdater.h" +#include "HWApplication.h" +#include "keybinder.h" #ifdef __APPLE__ #ifdef SPARKLE_ENABLED @@ -56,9 +61,15 @@ pageLayout->addWidget(tabs); QWidget * page1 = new QWidget(this); QWidget * page2 = new QWidget(this); + binder = new KeyBinder(this, tr("Select an action to change what key controls it"), tr("Reset to default"), tr("Reset all binds")); + connect(binder, SIGNAL(bindUpdate(int)), this, SLOT(bindUpdated(int))); + connect(binder, SIGNAL(resetAllBinds()), this, SLOT(resetAllBinds())); tabs->addTab(page1, tr("General")); + binderTab = tabs->addTab(binder, tr("Controls")); tabs->addTab(page2, tr("Advanced")); + connect(tabs, SIGNAL(currentChanged(int)), this, SLOT(tabIndexChanged(int))); + #ifdef VIDEOREC QWidget * page3 = new QWidget(this); tabs->addTab(page3, tr("Video Recording")); @@ -946,3 +957,57 @@ return true; } + +// When the current tab is switched +void PageOptions::tabIndexChanged(int index) +{ + if (index == binderTab) // Switched to bind tab + { + binder->resetInterface(); + + if (!config) return; + + QStandardItemModel * binds = DataManager::instance().bindsModel(); + for(int i = 0; i < BINDS_NUMBER; i++) + { + QString value = config->bind(i); + QModelIndexList mdl = binds->match(binds->index(0, 0), Qt::UserRole + 1, value, 1, Qt::MatchExactly); + if(mdl.size() == 1) binder->setBindIndex(i, mdl[0].row()); + } + } + + currentTab = index; +} + +// When a key bind combobox is changed +void PageOptions::bindUpdated(int bindID) +{ + int bindIndex = binder->bindIndex(bindID); + + if (bindIndex == 0) bindIndex = resetBindToDefault(bindID); + + // Save bind + QStandardItemModel * binds = DataManager::instance().bindsModel(); + QString strbind = binds->index(binder->bindIndex(bindID), 0).data(Qt::UserRole + 1).toString(); + config->setBind(bindID, strbind); +} + +// Changes a key bind (bindID) to its default value. This updates the bind's combo-box in the UI. +// Returns: The bind model index of the default. +int PageOptions::resetBindToDefault(int bindID) +{ + QStandardItemModel * binds = DataManager::instance().bindsModel(); + QModelIndexList mdl = binds->match(binds->index(0, 0), Qt::UserRole + 1, cbinds[bindID].strbind, 1, Qt::MatchExactly); + if(mdl.size() == 1) binder->setBindIndex(bindID, mdl[0].row()); + return mdl[0].row(); +} + +// Called when "reset all binds" button is pressed +void PageOptions::resetAllBinds() +{ + for (int i = 0; i < BINDS_NUMBER; i++) + { + resetBindToDefault(i); + bindUpdated(i); + } +} diff -r 9d9b498cfb03 -r 14b938faec69 QTfrontend/ui/page/pageoptions.h --- a/QTfrontend/ui/page/pageoptions.h Sun Dec 30 16:04:28 2012 +0200 +++ b/QTfrontend/ui/page/pageoptions.h Mon Dec 31 12:12:23 2012 +0200 @@ -25,6 +25,7 @@ class FPSEdit; class IconedGroupBox; class QSignalMapper; +class KeyBinder; class PageOptions : public AbstractPage { @@ -120,6 +121,7 @@ QLayout * bodyLayoutDefinition(); QLayout * footerLayoutDefinition(); void connectSignals(); + int resetBindToDefault(int bindID); bool previousFullscreenValue; int previousResolutionIndex; @@ -136,6 +138,9 @@ QPushButton *btnDefaults; QPushButton *btnUpdateNow; GameUIConfig * config; + KeyBinder * binder; + int currentTab; + int binderTab; private slots: void forceFullscreen(int index); @@ -153,6 +158,9 @@ void changeUseGameRes(int state); void changeRecordAudio(int state); void checkForUpdates(); + void tabIndexChanged(int); + void bindUpdated(int bindID); + void resetAllBinds(); public slots: void setDefaultOptions(); diff -r 9d9b498cfb03 -r 14b938faec69 QTfrontend/ui/widget/keybinder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/ui/widget/keybinder.cpp Mon Dec 31 12:12:23 2012 +0200 @@ -0,0 +1,301 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "keybinder.h" +#include "HWApplication.h" +#include "DataManager.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +KeyBinder::KeyBinder(QWidget * parent, const QString & helpText, const QString & defaultText, const QString & resetButtonText) : QWidget(parent) +{ + this->defaultText = defaultText; + enableSignal = false; + + // Two-column tab layout + QHBoxLayout * pageKeysLayout = new QHBoxLayout(this); + pageKeysLayout->setSpacing(0); + pageKeysLayout->setContentsMargins(0, 0, 0, 0); + + // Table for category list + QVBoxLayout * catListContainer = new QVBoxLayout(); + catListContainer->setContentsMargins(10, 10, 10, 10); + catList = new QListWidget(); + catList->setFixedWidth(180); + catList->setStyleSheet("QListWidget::item { font-size: 14px; } QListWidget:hover { border-color: #F6CB1C; } QListWidget::item:selected { background: #150A61; color: yellow; }"); + catList->setFocusPolicy(Qt::NoFocus); + connect(catList, SIGNAL(currentRowChanged(int)), this, SLOT(changeBindingsPage(int))); + catListContainer->addWidget(catList); + pageKeysLayout->addLayout(catListContainer); + + // Reset all binds button + if (!resetButtonText.isEmpty()) + { + QPushButton * btnResetAll = new QPushButton(resetButtonText); + catListContainer->addWidget(btnResetAll); + btnResetAll->setFixedHeight(40); + catListContainer->setStretch(1, 0); + catListContainer->setSpacing(10); + connect(btnResetAll, SIGNAL(clicked()), this, SIGNAL(resetAllBinds())); + } + + // Container for pages of key bindings + QWidget * bindingsPagesContainer = new QWidget(); + QVBoxLayout * rightLayout = new QVBoxLayout(bindingsPagesContainer); + + // Scroll area for key bindings + QScrollArea * scrollArea = new QScrollArea(); + scrollArea->setContentsMargins(0, 0, 0, 0); + scrollArea->setWidget(bindingsPagesContainer); + scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + scrollArea->setWidgetResizable(true); + scrollArea->setFrameShape(QFrame::NoFrame); + scrollArea->setStyleSheet("background: #130F2A;"); + + // Add key binding pages to bindings tab + pageKeysLayout->addWidget(scrollArea); + pageKeysLayout->setStretch(1, 1); + + // Custom help text + QLabel * helpLabel = new QLabel(); + helpLabel->setText(helpText); + helpLabel->setStyleSheet("color: #130F2A; background: #F6CB1C; border: solid 4px #F6CB1C; border-radius: 10px; padding: auto 20px;"); + helpLabel->setFixedHeight(24); + rightLayout->addWidget(helpLabel, 0, Qt::AlignCenter); + + // Category list and bind table row heights + const int rowHeight = 20; + QSize catSize, headerSize; + catSize.setHeight(36); + headerSize.setHeight(24); + + // Category list header + QListWidgetItem * catListHeader = new QListWidgetItem(tr("Category")); + catListHeader->setSizeHint(headerSize); + catListHeader->setFlags(Qt::NoItemFlags); + catListHeader->setForeground(QBrush(QColor("#130F2A"))); + catListHeader->setBackground(QBrush(QColor("#F6CB1C"))); + catListHeader->setTextAlignment(Qt::AlignCenter); + catList->addItem(catListHeader); + + // Populate + bindingsPages = new QHBoxLayout(); + bindingsPages->setContentsMargins(0, 0, 0, 0); + rightLayout->addLayout(bindingsPages); + QWidget * curPage = NULL; + QVBoxLayout * curLayout = NULL; + QTableWidget * curTable = NULL; + bool bFirstPage = true; + selectedBindTable = NULL; + bindComboBoxCellMappings = new QHash(); + bindCellComboBoxMappings = new QHash(); + for (int i = 0; i < BINDS_NUMBER; i++) + { + if (cbinds[i].category != NULL) + { + // Add stretch at end of previous layout + if (curLayout != NULL) curLayout->insertStretch(-1, 1); + + // Category list item + QListWidgetItem * catItem = new QListWidgetItem(HWApplication::translate("binds (categories)", cbinds[i].category)); + catItem->setSizeHint(catSize); + catList->addItem(catItem); + + // Create new page + curPage = new QWidget(); + curLayout = new QVBoxLayout(curPage); + curLayout->setSpacing(2); + bindingsPages->addWidget(curPage); + if (!bFirstPage) curPage->setVisible(false); + } + + // Description + if (cbinds[i].description != NULL) + { + QLabel * desc = new QLabel(HWApplication::translate("binds (descriptions)", cbinds[i].description)); + curLayout->addWidget(desc, 0); + QFrame * divider = new QFrame(); + divider->setFrameShape(QFrame::HLine); + divider->setFrameShadow(QFrame::Plain); + curLayout->addWidget(divider, 0); + } + + // New table + if (cbinds[i].category != NULL || cbinds[i].description != NULL) + { + curTable = new QTableWidget(0, 2); + curTable->verticalHeader()->setVisible(false); + curTable->horizontalHeader()->setVisible(false); + curTable->horizontalHeader()->setResizeMode(QHeaderView::Stretch); + curTable->verticalHeader()->setDefaultSectionSize(rowHeight); + curTable->setShowGrid(false); + curTable->setStyleSheet("QTableWidget { border: none; } "); + curTable->setSelectionBehavior(QAbstractItemView::SelectRows); + curTable->setSelectionMode(QAbstractItemView::SingleSelection); + curTable->setFocusPolicy(Qt::NoFocus); + connect(curTable, SIGNAL(itemSelectionChanged()), this, SLOT(bindSelectionChanged())); + connect(curTable, SIGNAL(itemClicked(QTableWidgetItem *)), this, SLOT(bindCellClicked(QTableWidgetItem *))); + curLayout->addWidget(curTable, 0); + } + + // Hidden combo box + QComboBox * comboBox = CBBind[i] = new QComboBox(curTable); + comboBox->setModel((QAbstractItemModel*)DataManager::instance().bindsModel()); + comboBox->setVisible(false); + comboBox->setFixedWidth(200); + + // Table row + int row = curTable->rowCount(); + QTableWidgetItem * nameCell = new QTableWidgetItem(HWApplication::translate("binds", cbinds[i].name)); + nameCell->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + curTable->insertRow(row); + curTable->setItem(row, 0, nameCell); + QTableWidgetItem * bindCell = new QTableWidgetItem(comboBox->currentText()); + bindCell->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + curTable->setItem(row, 1, bindCell); + curTable->resizeColumnsToContents(); + curTable->setFixedHeight(curTable->verticalHeader()->length() + 10); + + // Updates the text in the table cell + connect(comboBox, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(bindChanged(const QString &))); + + // Map combo box and that row's cells to each other + bindComboBoxCellMappings->insert(comboBox, bindCell); + bindCellComboBoxMappings->insert(nameCell, comboBox); + bindCellComboBoxMappings->insert(bindCell, comboBox); + } + + // Add stretch at end of last layout + if (curLayout != NULL) curLayout->insertStretch(-1, 1); + + // Go to first page + catList->setCurrentItem(catList->item(1)); + + enableSignal = true; +} + +KeyBinder::~KeyBinder() +{ + delete bindComboBoxCellMappings; + delete bindCellComboBoxMappings; +} + +// Switches between different pages of key binds +void KeyBinder::changeBindingsPage(int page) +{ + page--; // Disregard first item (the list header) + int pages = bindingsPages->count(); + for (int i = 0; i < pages; i++) + bindingsPages->itemAt(i)->widget()->setVisible(false); + bindingsPages->itemAt(page)->widget()->setVisible(true); +} + +// When a key bind combobox value is changed, updates the table cell text +void KeyBinder::bindChanged(const QString & text) +{ + bindComboBoxCellMappings->value(sender())->setText(text); + + if (enableSignal) + { + for (int i = 0; i < BINDS_NUMBER; i++) + { + if (CBBind[i] == sender()) + { + emit bindUpdate(i); + break; + } + } + } +} + +// When a row in a key bind table is clicked, this shows the popup +void KeyBinder::bindCellClicked(QTableWidgetItem * item) +{ + QComboBox * box = bindCellComboBoxMappings->value(item); + QTableWidget * table = item->tableWidget(); + QFrame * frame = box->findChild(); + + box->showPopup(); + frame->move( + frame->x() + table->horizontalHeader()->sectionSize(0), + frame->y() + (table->verticalHeader()->defaultSectionSize() * item->row()) + ); +} + +// When a new row in a bind table is *selected*, this clears selection in any other table +void KeyBinder::bindSelectionChanged() +{ + QTableWidget * theSender = (QTableWidget*)sender(); + if (theSender != selectedBindTable) + { + if (selectedBindTable != NULL) + selectedBindTable->clearSelection(); + selectedBindTable = theSender; + } +} + +// Set a combobox's index +void KeyBinder::setBindIndex(int keyIndex, int bindIndex) +{ + enableSignal = false; + CBBind[keyIndex]->setCurrentIndex(bindIndex); + enableSignal = true; +} + +// Return a combobox's selected index +int KeyBinder::bindIndex(int keyIndex) +{ + return CBBind[keyIndex]->currentIndex(); +} + +// Clears selection and goes to first category +void KeyBinder::resetInterface() +{ + enableSignal = false; + + catList->setCurrentItem(catList->item(1)); + changeBindingsPage(1); + if (selectedBindTable != NULL) + { + selectedBindTable->clearSelection(); + selectedBindTable = NULL; + } + + // Default bind text + DataManager::instance().bindsModel()->item(0)->setData(defaultText, Qt::DisplayRole); + for (int i = 0; i < BINDS_NUMBER; i++) + { + CBBind[i]->setModel(DataManager::instance().bindsModel()); + CBBind[i]->setCurrentIndex(0); + bindComboBoxCellMappings->value(CBBind[i])->setText(defaultText); + } + + enableSignal = true; +} diff -r 9d9b498cfb03 -r 14b938faec69 QTfrontend/ui/widget/keybinder.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/ui/widget/keybinder.h Mon Dec 31 12:12:23 2012 +0200 @@ -0,0 +1,68 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef _KEY_BINDER_H +#define _KEY_BINDER_H + +#include +#include + +#include "binds.h" + +class QListWidget; +class QTableWidgetItem; +class QTableWidget; +class QBoxLayout; +class QComboBox; + +// USAGE NOTE: Every time the widget comes into view, you must call resetInterface() + +class KeyBinder : public QWidget +{ + Q_OBJECT + + public: + KeyBinder(QWidget * parent = NULL, const QString & helpText = QString(), const QString & defaultText = QString(), const QString & resetButtonText = QString()); + ~KeyBinder(); + + void setBindIndex(int keyIndex, int bindIndex); + int bindIndex(int keyIndex); + void resetInterface(); + + private: + QHash * bindComboBoxCellMappings; + QHash * bindCellComboBoxMappings; + QTableWidget * selectedBindTable; + QListWidget * catList; + QBoxLayout *bindingsPages; + QComboBox * CBBind[BINDS_NUMBER]; + QString defaultText; + bool enableSignal; + + signals: + void bindUpdate(int bindID); + void resetAllBinds(); + + private slots: + void changeBindingsPage(int page); + void bindChanged(const QString &); + void bindCellClicked(QTableWidgetItem * item); + void bindSelectionChanged(); +}; + +#endif // _KEY_BINDER_H diff -r 9d9b498cfb03 -r 14b938faec69 QTfrontend/util/DataManager.cpp --- a/QTfrontend/util/DataManager.cpp Sun Dec 30 16:04:28 2012 +0200 +++ b/QTfrontend/util/DataManager.cpp Mon Dec 31 12:12:23 2012 +0200 @@ -135,6 +135,11 @@ { m_bindsModel = new QStandardItemModel(); + QStandardItem * firstItem = new QStandardItem(); + firstItem->setData(tr("Use Default"), Qt::DisplayRole); + firstItem->setData("default", Qt::UserRole + 1); + m_bindsModel->appendRow(firstItem); + for(int j = 0; sdlkeys[j][1][0] != '\0'; j++) { QStandardItem * item = new QStandardItem(); diff -r 9d9b498cfb03 -r 14b938faec69 cmake_modules/FindSDL_Extras.cmake --- a/cmake_modules/FindSDL_Extras.cmake Sun Dec 30 16:04:28 2012 +0200 +++ b/cmake_modules/FindSDL_Extras.cmake Mon Dec 31 12:12:23 2012 +0200 @@ -13,7 +13,7 @@ if(sdlmixer_version GREATER "10209") message(STATUS "Mix_Init() is present") - set(pascal_flags "-dSDL_MIXER_NEWER" ${pascal_flags}) + list(APPEND pascal_flags "-dSDL_MIXER_NEWER") endif() endif() @@ -30,7 +30,7 @@ if(sdlimage_version GREATER "010207") message(STATUS "IMG_Init() is present") - set(pascal_flags "-dSDL_IMAGE_NEWER" ${pascal_flags}) + list(APPEND pascal_flags "-dSDL_IMAGE_NEWER") endif() endif() diff -r 9d9b498cfb03 -r 14b938faec69 hedgewars/CMakeLists.txt --- a/hedgewars/CMakeLists.txt Sun Dec 30 16:04:28 2012 +0200 +++ b/hedgewars/CMakeLists.txt Mon Dec 31 12:12:23 2012 +0200 @@ -92,16 +92,16 @@ if(${BUILD_ENGINE_LIBRARY}) message(WARNING "Engine will be built as library (experimental)") - set(pascal_flags "-dHWLIBRARY" ${pascal_flags}) + list(APPEND pascal_flags "-dHWLIBRARY") # create position independent code, only required for x68_64 builds, similar to -fPIC if(CMAKE_SIZEOF_VOID_P MATCHES "8") - set(pascal_flags "-Cg" ${pascal_flags}) + list(APPEND pascal_flags "-Cg") endif(CMAKE_SIZEOF_VOID_P MATCHES "8") # due to compiler/linker issues on Max OS X 10.6 -k-no_order_inits is needed to avoid linking fail if(APPLE AND current_macosx_version VERSION_GREATER "10.5") - set(pascal_flags "-k-no_order_inits" ${pascal_flags}) + list(APPEND pascal_flags "-k-no_order_inits") endif() set(destination_dir ${target_library_install_dir}) else(${BUILD_ENGINE_LIBRARY}) @@ -140,20 +140,20 @@ include_directories(${SDL_INCLUDE_DIR}) add_library (SDLmain STATIC SDLMain.m) #add a dependency to the hwengine target - set(engine_sources ${engine_sources} SDLmain) + list(APPEND engine_sources SDLmain) set(SDLMAIN_LIB "${LIBRARY_OUTPUT_PATH}/libSDLmain.a") endif() - set(pascal_flags "-k${SDLMAIN_LIB}" ${pascal_flags}) + list(APPEND pascal_flags "-k${SDLMAIN_LIB}") endif() endif(APPLE) if(NOT NOPNG) find_package(PNG) if(${PNG_FOUND}) - set(pascal_flags "-dPNG_SCREENSHOTS" ${pascal_flags}) + list(APPEND pascal_flags "-dPNG_SCREENSHOTS") if(APPLE) # fpc png unit doesn't pull the library (see bug 21833) - set(pascal_flags "-k${PNG_LIBRARY}" ${pascal_flags}) + list(APPEND pascal_flags "-k${PNG_LIBRARY}") endif() else() message(WARNING "Screenshots will be in BMP format because libpng was not found") @@ -185,7 +185,7 @@ #TODO: convert avwrapper to .pas unit so we can skip this step include_directories(${FFMPEG_INCLUDE_DIR}) - set(pascal_flags "-dUSE_VIDEO_RECORDING" ${pascal_flags}) + list(APPEND pascal_flags "-dUSE_VIDEO_RECORDING") IF (WIN32) # there are some problems with linking our avwrapper as static lib, so link it as shared add_library(avwrapper SHARED avwrapper.c) @@ -193,7 +193,7 @@ install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}avwrapper${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION ${target_library_install_dir}) ELSE() add_library(avwrapper STATIC avwrapper.c) - set(pascal_flags "-k${FFMPEG_LIBAVCODEC}" "-k${FFMPEG_LIBAVFORMAT}" "-k${FFMPEG_LIBAVUTIL}" ${pascal_flags}) + list(APPEND pascal_flags "-k${FFMPEG_LIBAVCODEC}" "-k${FFMPEG_LIBAVFORMAT}" "-k${FFMPEG_LIBAVUTIL}") ENDIF() else() message(WARNING "Could NOT find FFMPEG/LibAV, video recording will be disabled") @@ -216,7 +216,7 @@ else() #these are the dependencies for building a universal binary on Mac OS X foreach (build_arch ${powerpc_build} ${i386_build} ${x86_64_build}) - set(lipo_args_list "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}" ${lipo_args_list}) + list(APPEND lipo_args_list "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}") add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}" COMMAND "${FPC_EXECUTABLE}" ARGS ${fpc_flags} -ohwengine.${build_arch} -P${build_arch} diff -r 9d9b498cfb03 -r 14b938faec69 hedgewars/hwengine.pas --- a/hedgewars/hwengine.pas Sun Dec 30 16:04:28 2012 +0200 +++ b/hedgewars/hwengine.pas Mon Dec 31 12:12:23 2012 +0200 @@ -264,6 +264,9 @@ end; //end case event.type_ of end; //end while SDL_PollEvent(@event) <> 0 do + if (CursorMovementX <> 0) or (CursorMovementY <> 0) then + handlePositionUpdate(CursorMovementX * cameraKeyboardSpeed, CursorMovementY * cameraKeyboardSpeed); + if (cScreenResizeDelay <> 0) and (cScreenResizeDelay < RealTicks) and ((cNewScreenWidth <> cScreenWidth) or (cNewScreenHeight <> cScreenHeight)) then begin diff -r 9d9b498cfb03 -r 14b938faec69 hedgewars/uConsts.pas --- a/hedgewars/uConsts.pas Sun Dec 30 16:04:28 2012 +0200 +++ b/hedgewars/uConsts.pas Mon Dec 31 12:12:23 2012 +0200 @@ -43,6 +43,9 @@ msgFailedSize = 'failed due to size'; msgGettingConfig = 'Getting game config...'; + // camera movement multipliers + cameraKeyboardSpeed : ShortInt = 10; + // color constants cWhiteColorChannels : TSDL_Color = (r:$FF; g:$FF; b:$FF; unused:$FF); cNearBlackColorChannels : TSDL_Color = (r:$00; g:$00; b:$10; unused:$FF); diff -r 9d9b498cfb03 -r 14b938faec69 hedgewars/uCursor.pas --- a/hedgewars/uCursor.pas Sun Dec 30 16:04:28 2012 +0200 +++ b/hedgewars/uCursor.pas Mon Dec 31 12:12:23 2012 +0200 @@ -5,6 +5,7 @@ procedure init; procedure resetPosition; procedure updatePosition; +procedure handlePositionUpdate(x, y: LongInt); implementation @@ -24,15 +25,20 @@ var x, y: LongInt; begin SDL_GetMouseState(@x, @y); - + if(x <> cScreenWidth div 2) or (y <> cScreenHeight div 2) then - begin - CursorPoint.X:= CursorPoint.X + x - cScreenWidth div 2; - CursorPoint.Y:= CursorPoint.Y - y + cScreenHeight div 2; + begin + handlePositionUpdate(x - cScreenWidth div 2, y - cScreenHeight div 2); if cHasFocus then SDL_WarpMouse(cScreenWidth div 2, cScreenHeight div 2); - end + end +end; + +procedure handlePositionUpdate(x, y: LongInt); +begin + CursorPoint.X:= CursorPoint.X + x; + CursorPoint.Y:= CursorPoint.Y - y; end; end. diff -r 9d9b498cfb03 -r 14b938faec69 hedgewars/uInputHandler.pas --- a/hedgewars/uInputHandler.pas Sun Dec 30 16:04:28 2012 +0200 +++ b/hedgewars/uInputHandler.pas Mon Dec 31 12:12:23 2012 +0200 @@ -39,6 +39,7 @@ procedure SetBinds(var binds: TBinds); procedure SetDefaultBinds; +procedure chDefaultBind(var id: shortstring); procedure ControllerInit; procedure ControllerAxisEvent(joy, axis: Byte; value: Integer); @@ -70,6 +71,7 @@ //ControllerBalls: array[0..5] of array[0..19] of array[0..1] of Integer; ControllerHats: array[0..5] of array[0..19] of Byte; ControllerButtons: array[0..5] of array[0..19] of Byte; + usingDBinds: boolean; function KeyNameToCode(name: shortstring): LongInt; inline; begin @@ -329,9 +331,9 @@ binds:= binds; // avoid hint CurrentBinds:= DefaultBinds; {$ELSE} -for t:= 0 to cKbdMaxIndex do - if (CurrentBinds[t] <> binds[t]) and tkbd[t] then - ProcessKey(t, False); + for t:= 0 to cKbdMaxIndex do + if (CurrentBinds[t] <> binds[t]) and tkbd[t] then + ProcessKey(t, False); CurrentBinds:= binds; {$ENDIF} @@ -450,8 +452,45 @@ ProcessKey(k + ControllerNumAxes[joy]*2 + ControllerNumHats[joy]*4 + button, pressed); end; +// Bind that isn't a team bind, but overrides defaultbinds. +// When first called, DefaultBinds is cleared, because we assume we are getting a full list of dbinds. +procedure chDefaultBind(var id: shortstring); +var KeyName, Modifier, tmp: shortstring; + b: LongInt; +begin +KeyName:= ''; +Modifier:= ''; + +if (not usingDBinds) then + begin + usingDBinds:= true; + FillByte(DefaultBinds, SizeOf(DefaultBinds), 0); + end; + +if (Pos('mod:', id) <> 0) then + begin + tmp:= ''; + SplitBySpace(id, tmp); + Modifier:= id; + id:= tmp; + end; + +SplitBySpace(id, KeyName); +if KeyName[1]='"' then + Delete(KeyName, 1, 1); +if KeyName[byte(KeyName[0])]='"' then + Delete(KeyName, byte(KeyName[0]), 1); +b:= KeyNameToCode(id, Modifier); +if b = 0 then + OutError(errmsgUnknownVariable + ' "' + id + '"', false) +else + DefaultBinds[b]:= KeyName; +end; + procedure initModule; begin + usingDBinds:= false; + RegisterVariable('dbind', @chDefaultBind, true ); end; procedure freeModule; diff -r 9d9b498cfb03 -r 14b938faec69 hedgewars/uTeams.pas --- a/hedgewars/uTeams.pas Sun Dec 30 16:04:28 2012 +0200 +++ b/hedgewars/uTeams.pas Mon Dec 31 12:12:23 2012 +0200 @@ -330,7 +330,7 @@ function AddTeam(TeamColor: Longword): PTeam; var team: PTeam; - c: LongInt; + c, t: LongInt; begin TryDo(TeamsCount < cMaxTeams, 'Too many teams', true); New(team); @@ -343,6 +343,9 @@ TeamsArray[TeamsCount]:= team; inc(TeamsCount); +for t:= 0 to cKbdMaxIndex do + team^.Binds[t]:= ''; + c:= Pred(ClansCount); while (c >= 0) and (ClansArray[c]^.Color <> TeamColor) do dec(c); if c < 0 then