1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-10 22:31:40 +02:00

Merge pull request #5543 from kambala-decapitator/ios-portrait-mode

[iOS] enable portrait mode
This commit is contained in:
Ivan Savenko
2025-03-19 10:09:47 +02:00
committed by GitHub
8 changed files with 142 additions and 69 deletions

View File

@@ -237,7 +237,7 @@ void InputHandler::preprocessEvent(const SDL_Event & ev)
#endif
break;
case SDL_WINDOWEVENT_SIZE_CHANGED:
#ifdef VCMI_ANDROID
#ifdef VCMI_MOBILE
{
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
GH.onScreenResize(true);

View File

@@ -53,10 +53,5 @@
<true/>
<key>UIStatusBarHidden</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@@ -31,6 +31,11 @@ if(APPLE_IOS)
ios/revealdirectoryinfiles.mm
ios/selectdirectory.h
ios/selectdirectory.mm
prepare_ios.mm
)
elseif(ANDROID)
list(APPEND launcher_SRCS
prepare_android.cpp
)
endif()
@@ -55,6 +60,7 @@ set(launcher_HEADERS
helper.h
innoextract.h
prepare.h
prepare_p.h
)
set(launcher_FORMS

View File

@@ -9,75 +9,17 @@
*/
#include "StdInc.h"
#include "prepare.h"
#include "prepare_p.h"
#include "../vcmiqt/launcherdirs.h"
#include <QDir>
#include <QFile>
#include <QFileInfo>
#ifdef VCMI_ANDROID
#include "../lib/CAndroidVMHelper.h"
#include <QAndroidJniEnvironment>
#include <QAndroidJniObject>
#include <QtAndroid>
namespace
{
// https://gist.github.com/ssendeavour/7324701
bool copyRecursively(const QString &srcFilePath, const QString &tgtFilePath)
{
QFileInfo srcFileInfo{srcFilePath};
if(srcFileInfo.isDir()) {
QDir targetDir{tgtFilePath};
targetDir.cdUp();
if(!targetDir.mkpath(QFileInfo{tgtFilePath}.fileName()))
return false;
targetDir.setPath(tgtFilePath);
QDir sourceDir{srcFilePath};
const auto fileNames = sourceDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System);
for(const auto & fileName : fileNames) {
const auto newSrcFilePath = sourceDir.filePath(fileName);
const auto newTgtFilePath = targetDir.filePath(fileName);
if(!copyRecursively(newSrcFilePath, newTgtFilePath))
return false;
}
} else {
if(!QFile::copy(srcFilePath, tgtFilePath))
return false;
}
return true;
}
void prepareAndroid()
{
QAndroidJniEnvironment jniEnv;
CAndroidVMHelper::initClassloader(static_cast<JNIEnv *>(jniEnv));
const bool justLaunched = QtAndroid::androidActivity().getField<jboolean>("justLaunched") == JNI_TRUE;
if(!justLaunched)
return;
// copy core data to internal directory
const auto vcmiDir = QAndroidJniObject::callStaticObjectMethod<jstring>("eu/vcmi/vcmi/NativeMethods", "internalDataRoot").toString();
for(auto vcmiFilesResource : {QLatin1String{"config"}, QLatin1String{"Mods"}})
{
QDir destDir = QString{"%1/%2"}.arg(vcmiDir, vcmiFilesResource);
destDir.removeRecursively();
copyRecursively(QString{":/%1"}.arg(vcmiFilesResource), destDir.absolutePath());
}
}
}
#endif
namespace launcher
{
void prepare()
{
#ifdef VCMI_ANDROID
prepareAndroid();
#elif defined(VCMI_IOS)
prepareIos();
#endif
CLauncherDirs::prepare();

View File

@@ -0,0 +1,71 @@
/*
* prepare_android.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "prepare_p.h"
#include "../lib/CAndroidVMHelper.h"
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QAndroidJniEnvironment>
#include <QAndroidJniObject>
#include <QtAndroid>
namespace
{
// https://gist.github.com/ssendeavour/7324701
bool copyRecursively(const QString & srcFilePath, const QString & tgtFilePath)
{
QFileInfo srcFileInfo{srcFilePath};
if(srcFileInfo.isDir()) {
QDir targetDir{tgtFilePath};
targetDir.cdUp();
if(!targetDir.mkpath(QFileInfo{tgtFilePath}.fileName()))
return false;
targetDir.setPath(tgtFilePath);
QDir sourceDir{srcFilePath};
const auto fileNames = sourceDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System);
for(const auto & fileName : fileNames) {
const auto newSrcFilePath = sourceDir.filePath(fileName);
const auto newTgtFilePath = targetDir.filePath(fileName);
if(!copyRecursively(newSrcFilePath, newTgtFilePath))
return false;
}
} else {
if(!QFile::copy(srcFilePath, tgtFilePath))
return false;
}
return true;
}
}
namespace launcher
{
void prepareAndroid()
{
QAndroidJniEnvironment jniEnv;
CAndroidVMHelper::initClassloader(static_cast<JNIEnv *>(jniEnv));
const bool justLaunched = QtAndroid::androidActivity().getField<jboolean>("justLaunched") == JNI_TRUE;
if(!justLaunched)
return;
// copy core data to internal directory
const auto vcmiDir = QAndroidJniObject::callStaticObjectMethod<jstring>("eu/vcmi/vcmi/NativeMethods", "internalDataRoot").toString();
for(auto vcmiFilesResource : {QLatin1String{"config"}, QLatin1String{"Mods"}})
{
QDir destDir = QString{"%1/%2"}.arg(vcmiDir, vcmiFilesResource);
destDir.removeRecursively();
copyRecursively(QString{":/%1"}.arg(vcmiFilesResource), destDir.absolutePath());
}
}
}

40
launcher/prepare_ios.mm Normal file
View File

@@ -0,0 +1,40 @@
/*
* prepare_ios.mm, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "prepare_p.h"
#import <UIKit/UIKit.h>
#include <objc/runtime.h>
namespace
{
UIInterfaceOrientationMask swizzled_supportedInterfaceOrientationsForWindow
(id __unused self, SEL __unused _cmd, UIApplication * __unused application, UIWindow * __unused _Nullable window)
{
if(UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad)
return UIInterfaceOrientationMaskAll;
return UIInterfaceOrientationMaskLandscape;
}
}
namespace launcher
{
void prepareIos()
{
auto sel = @selector(application:supportedInterfaceOrientationsForWindow:);
auto methodDesc = protocol_getMethodDescription(@protocol(UIApplicationDelegate), sel, NO, YES);
auto appDelegateClass = object_getClass(UIApplication.sharedApplication.delegate);
[[maybe_unused]] auto existingImp = class_replaceMethod(
appDelegateClass, sel, (IMP)swizzled_supportedInterfaceOrientationsForWindow, methodDesc.types);
// also check implementation in qtbase - src/plugins/platforms/ios/qiosapplicationdelegate.mm
NSCAssert(existingImp == nullptr, @"original app delegate has this method, don't ignore it");
}
}

19
launcher/prepare_p.h Normal file
View File

@@ -0,0 +1,19 @@
/*
* prepare_p.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
namespace launcher
{
#ifdef VCMI_ANDROID
void prepareAndroid();
#elif defined(VCMI_IOS)
void prepareIos();
#endif
}

View File

@@ -120,6 +120,8 @@ void CSettingsView::loadSettings()
ui->labelHapticFeedback->hide();
ui->labelResetTutorialTouchscreen->hide();
ui->pushButtonResetTutorialTouchscreen->hide();
ui->labelAllowPortrait->hide();
ui->buttonAllowPortrait->hide();
if (settings["video"]["realFullscreen"].Bool())
ui->comboBoxFullScreen->setCurrentIndex(2);
else
@@ -128,8 +130,6 @@ void CSettingsView::loadSettings()
#ifndef VCMI_ANDROID
ui->buttonHandleBackRightMouseButton->hide();
ui->labelHandleBackRightMouseButton->hide();
ui->buttonAllowPortrait->hide();
ui->labelAllowPortrait->hide();
#endif
fillValidScalingRange();