mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 02:17:11 +02:00
Merge branch 'master' into hazeZone
This commit is contained in:
commit
afa93f46e5
9 changed files with 164 additions and 30 deletions
|
@ -13,6 +13,7 @@ import "."
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: keyboardBase
|
id: keyboardBase
|
||||||
|
objectName: "keyboard"
|
||||||
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
@ -27,6 +28,8 @@ Rectangle {
|
||||||
|
|
||||||
readonly property int mirrorTextHeight: keyboardRowHeight
|
readonly property int mirrorTextHeight: keyboardRowHeight
|
||||||
|
|
||||||
|
property bool password: false
|
||||||
|
property alias mirroredText: mirrorText.text
|
||||||
property bool showMirrorText: true
|
property bool showMirrorText: true
|
||||||
readonly property int raisedHeight: 200
|
readonly property int raisedHeight: 200
|
||||||
|
|
||||||
|
@ -112,16 +115,20 @@ Rectangle {
|
||||||
color: "#252525"
|
color: "#252525"
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
TextEdit {
|
TextInput {
|
||||||
id: mirrorText
|
id: mirrorText
|
||||||
visible: showMirrorText
|
visible: showMirrorText
|
||||||
size: 13.5
|
FontLoader { id: ralewaySemiBold; source: "../../fonts/Raleway-SemiBold.ttf"; }
|
||||||
|
font.family: ralewaySemiBold.name
|
||||||
|
font.pointSize: 13.5
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
color: "#FFFFFF";
|
color: "#FFFFFF";
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
readOnly: false // we need to leave this property read-only to allow control to accept QKeyEvent
|
readOnly: false // we need this to allow control to accept QKeyEvent
|
||||||
selectByMouse: false
|
selectByMouse: false
|
||||||
|
echoMode: password ? TextInput.Password : TextInput.Normal
|
||||||
|
|
||||||
Keys.onPressed: {
|
Keys.onPressed: {
|
||||||
if (event.key == Qt.Key_Return || event.key == Qt.Key_Space) {
|
if (event.key == Qt.Key_Return || event.key == Qt.Key_Space) {
|
||||||
|
|
|
@ -207,6 +207,17 @@
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
#include <VersionHelpers.h>
|
#include <VersionHelpers.h>
|
||||||
|
|
||||||
|
#ifdef DEBUG_EVENT_QUEUE
|
||||||
|
// This is a HACK that uses private headers included with the qt source distrubution.
|
||||||
|
// To use this feature you need to add these directores to your include path:
|
||||||
|
// E:/Qt/5.9.1/Src/qtbase/include/QtCore/5.9.1/QtCore
|
||||||
|
// E:/Qt/5.9.1/Src/qtbase/include/QtCore/5.9.1
|
||||||
|
#define QT_BOOTSTRAPPED
|
||||||
|
#include <private/qthread_p.h>
|
||||||
|
#include <private/qobject_p.h>
|
||||||
|
#undef QT_BOOTSTRAPPED
|
||||||
|
#endif
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
||||||
}
|
}
|
||||||
|
@ -264,9 +275,7 @@ private:
|
||||||
switch ((int)event->type()) {
|
switch ((int)event->type()) {
|
||||||
case ApplicationEvent::Render:
|
case ApplicationEvent::Render:
|
||||||
render();
|
render();
|
||||||
// Ensure we never back up the render events. Each render should be triggered only in response
|
qApp->_pendingRenderEvent.store(false);
|
||||||
// to the NEXT render event after the last render occured
|
|
||||||
QCoreApplication::removePostedEvents(this, ApplicationEvent::Render);
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -2712,9 +2721,14 @@ bool Application::importFromZIP(const QString& filePath) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// thread-safe
|
||||||
void Application::onPresent(quint32 frameCount) {
|
void Application::onPresent(quint32 frameCount) {
|
||||||
postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority);
|
bool expected = false;
|
||||||
if (_renderEventHandler && !isAboutToQuit()) {
|
if (_pendingIdleEvent.compare_exchange_strong(expected, true)) {
|
||||||
|
postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority);
|
||||||
|
}
|
||||||
|
expected = false;
|
||||||
|
if (_renderEventHandler && !isAboutToQuit() && _pendingRenderEvent.compare_exchange_strong(expected, true)) {
|
||||||
postEvent(_renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render));
|
postEvent(_renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2781,7 +2795,26 @@ bool Application::handleFileOpenEvent(QFileOpenEvent* fileEvent) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_EVENT_QUEUE
|
||||||
|
static int getEventQueueSize(QThread* thread) {
|
||||||
|
auto threadData = QThreadData::get2(thread);
|
||||||
|
QMutexLocker locker(&threadData->postEventList.mutex);
|
||||||
|
return threadData->postEventList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dumpEventQueue(QThread* thread) {
|
||||||
|
auto threadData = QThreadData::get2(thread);
|
||||||
|
QMutexLocker locker(&threadData->postEventList.mutex);
|
||||||
|
qDebug() << "AJT: event list, size =" << threadData->postEventList.size();
|
||||||
|
for (auto& postEvent : threadData->postEventList) {
|
||||||
|
QEvent::Type type = (postEvent.event ? postEvent.event->type() : QEvent::None);
|
||||||
|
qDebug() << "AJT: " << type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // DEBUG_EVENT_QUEUE
|
||||||
|
|
||||||
bool Application::event(QEvent* event) {
|
bool Application::event(QEvent* event) {
|
||||||
|
|
||||||
if (!Menu::getInstance()) {
|
if (!Menu::getInstance()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2801,8 +2834,18 @@ bool Application::event(QEvent* event) {
|
||||||
// see (windowMinimizedChanged)
|
// see (windowMinimizedChanged)
|
||||||
case ApplicationEvent::Idle:
|
case ApplicationEvent::Idle:
|
||||||
idle();
|
idle();
|
||||||
// Don't process extra idle events that arrived in the event queue while we were doing this idle
|
|
||||||
QCoreApplication::removePostedEvents(this, ApplicationEvent::Idle);
|
#ifdef DEBUG_EVENT_QUEUE
|
||||||
|
{
|
||||||
|
int count = getEventQueueSize(QThread::currentThread());
|
||||||
|
if (count > 400) {
|
||||||
|
dumpEventQueue(QThread::currentThread());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // DEBUG_EVENT_QUEUE
|
||||||
|
|
||||||
|
_pendingIdleEvent.store(false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case QEvent::MouseMove:
|
case QEvent::MouseMove:
|
||||||
|
@ -7203,7 +7246,7 @@ void Application::updateDisplayMode() {
|
||||||
_offscreenContext->makeCurrent();
|
_offscreenContext->makeCurrent();
|
||||||
getApplicationCompositor().setDisplayPlugin(newDisplayPlugin);
|
getApplicationCompositor().setDisplayPlugin(newDisplayPlugin);
|
||||||
_displayPlugin = newDisplayPlugin;
|
_displayPlugin = newDisplayPlugin;
|
||||||
connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent);
|
connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent, Qt::DirectConnection);
|
||||||
auto desktop = offscreenUi->getDesktop();
|
auto desktop = offscreenUi->getDesktop();
|
||||||
if (desktop) {
|
if (desktop) {
|
||||||
desktop->setProperty("repositionLocked", wasRepositionLocked);
|
desktop->setProperty("repositionLocked", wasRepositionLocked);
|
||||||
|
|
|
@ -717,5 +717,8 @@ private:
|
||||||
LaserPointerManager _laserPointerManager;
|
LaserPointerManager _laserPointerManager;
|
||||||
|
|
||||||
friend class RenderEventHandler;
|
friend class RenderEventHandler;
|
||||||
|
|
||||||
|
std::atomic<bool> _pendingIdleEvent { false };
|
||||||
|
std::atomic<bool> _pendingRenderEvent { false };
|
||||||
};
|
};
|
||||||
#endif // hifi_Application_h
|
#endif // hifi_Application_h
|
||||||
|
|
|
@ -72,6 +72,12 @@ void Application::paintGL() {
|
||||||
{
|
{
|
||||||
QMutexLocker viewLocker(&_renderArgsMutex);
|
QMutexLocker viewLocker(&_renderArgsMutex);
|
||||||
renderArgs = _appRenderArgs._renderArgs;
|
renderArgs = _appRenderArgs._renderArgs;
|
||||||
|
|
||||||
|
// don't render if there is no context.
|
||||||
|
if (!_appRenderArgs._renderArgs._context) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
HMDSensorPose = _appRenderArgs._headPose;
|
HMDSensorPose = _appRenderArgs._headPose;
|
||||||
eyeToWorld = _appRenderArgs._eyeToWorld;
|
eyeToWorld = _appRenderArgs._eyeToWorld;
|
||||||
sensorToWorld = _appRenderArgs._sensorToWorld;
|
sensorToWorld = _appRenderArgs._sensorToWorld;
|
||||||
|
|
|
@ -46,6 +46,10 @@ static const int STATS_FOR_STATS_PACKET_WINDOW_SECONDS = 30;
|
||||||
// _currentJitterBufferFrames is updated with the time-weighted avg and the running time-weighted avg is reset.
|
// _currentJitterBufferFrames is updated with the time-weighted avg and the running time-weighted avg is reset.
|
||||||
static const quint64 FRAMES_AVAILABLE_STAT_WINDOW_USECS = 10 * USECS_PER_SECOND;
|
static const quint64 FRAMES_AVAILABLE_STAT_WINDOW_USECS = 10 * USECS_PER_SECOND;
|
||||||
|
|
||||||
|
// When the audio codec is switched, temporary codec mismatch is expected due to packets in-flight.
|
||||||
|
// A SelectedAudioFormat packet is not sent until this threshold is exceeded.
|
||||||
|
static const int MAX_MISMATCHED_AUDIO_CODEC_COUNT = 10;
|
||||||
|
|
||||||
InboundAudioStream::InboundAudioStream(int numChannels, int numFrames, int numBlocks, int numStaticJitterBlocks) :
|
InboundAudioStream::InboundAudioStream(int numChannels, int numFrames, int numBlocks, int numStaticJitterBlocks) :
|
||||||
_ringBuffer(numChannels * numFrames, numBlocks),
|
_ringBuffer(numChannels * numFrames, numBlocks),
|
||||||
_numChannels(numChannels),
|
_numChannels(numChannels),
|
||||||
|
@ -153,6 +157,7 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
|
||||||
// If we recieved a SilentAudioFrame from our sender, we might want to drop
|
// If we recieved a SilentAudioFrame from our sender, we might want to drop
|
||||||
// some of the samples in order to catch up to our desired jitter buffer size.
|
// some of the samples in order to catch up to our desired jitter buffer size.
|
||||||
writeDroppableSilentFrames(networkFrames);
|
writeDroppableSilentFrames(networkFrames);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// note: PCM and no codec are identical
|
// note: PCM and no codec are identical
|
||||||
bool selectedPCM = _selectedCodecName == "pcm" || _selectedCodecName == "";
|
bool selectedPCM = _selectedCodecName == "pcm" || _selectedCodecName == "";
|
||||||
|
@ -160,20 +165,33 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
|
||||||
if (codecInPacket == _selectedCodecName || (packetPCM && selectedPCM)) {
|
if (codecInPacket == _selectedCodecName || (packetPCM && selectedPCM)) {
|
||||||
auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead());
|
auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead());
|
||||||
parseAudioData(message.getType(), afterProperties);
|
parseAudioData(message.getType(), afterProperties);
|
||||||
|
_mismatchedAudioCodecCount = 0;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qDebug(audio) << "Codec mismatch: expected" << _selectedCodecName << "got" << codecInPacket << "writing silence";
|
_mismatchedAudioCodecCount++;
|
||||||
|
qDebug(audio) << "Codec mismatch: expected" << _selectedCodecName << "got" << codecInPacket;
|
||||||
|
|
||||||
// Since the data in the stream is using a codec that we aren't prepared for,
|
if (packetPCM) {
|
||||||
// we need to let the codec know that we don't have data for it, this will
|
// If there are PCM packets in-flight after the codec is changed, use them.
|
||||||
// allow the codec to interpolate missing data and produce a fade to silence.
|
auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead());
|
||||||
lostAudioData(1);
|
_ringBuffer.writeData(afterProperties.data(), afterProperties.size());
|
||||||
|
} else {
|
||||||
// inform others of the mismatch
|
// Since the data in the stream is using a codec that we aren't prepared for,
|
||||||
auto sendingNode = DependencyManager::get<NodeList>()->nodeWithUUID(message.getSourceID());
|
// we need to let the codec know that we don't have data for it, this will
|
||||||
if (sendingNode) {
|
// allow the codec to interpolate missing data and produce a fade to silence.
|
||||||
emit mismatchedAudioCodec(sendingNode, _selectedCodecName, codecInPacket);
|
lostAudioData(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_mismatchedAudioCodecCount > MAX_MISMATCHED_AUDIO_CODEC_COUNT) {
|
||||||
|
_mismatchedAudioCodecCount = 0;
|
||||||
|
|
||||||
|
// inform others of the mismatch
|
||||||
|
auto sendingNode = DependencyManager::get<NodeList>()->nodeWithUUID(message.getSourceID());
|
||||||
|
if (sendingNode) {
|
||||||
|
emit mismatchedAudioCodec(sendingNode, _selectedCodecName, codecInPacket);
|
||||||
|
qDebug(audio) << "Codec mismatch threshold exceeded, SelectedAudioFormat(" << _selectedCodecName << " ) sent";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -186,6 +186,7 @@ protected:
|
||||||
CodecPluginPointer _codec;
|
CodecPluginPointer _codec;
|
||||||
QString _selectedCodecName;
|
QString _selectedCodecName;
|
||||||
Decoder* _decoder { nullptr };
|
Decoder* _decoder { nullptr };
|
||||||
|
int _mismatchedAudioCodecCount { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
float calculateRepeatedFrameFadeFactor(int indexOfRepeat);
|
float calculateRepeatedFrameFadeFactor(int indexOfRepeat);
|
||||||
|
|
|
@ -983,6 +983,9 @@ public:
|
||||||
glm::vec2 dstCoord;
|
glm::vec2 dstCoord;
|
||||||
glm::ivec2 srcPixel;
|
glm::ivec2 srcPixel;
|
||||||
for (int y = 0; y < faceWidth; ++y) {
|
for (int y = 0; y < faceWidth; ++y) {
|
||||||
|
QRgb* destScanLineBegin = reinterpret_cast<QRgb*>( image.scanLine(y) );
|
||||||
|
QRgb* destPixelIterator = destScanLineBegin;
|
||||||
|
|
||||||
dstCoord.y = 1.0f - (y + 0.5f) * dstInvSize.y; // Fill cube face images from top to bottom
|
dstCoord.y = 1.0f - (y + 0.5f) * dstInvSize.y; // Fill cube face images from top to bottom
|
||||||
for (int x = 0; x < faceWidth; ++x) {
|
for (int x = 0; x < faceWidth; ++x) {
|
||||||
dstCoord.x = (x + 0.5f) * dstInvSize.x;
|
dstCoord.x = (x + 0.5f) * dstInvSize.x;
|
||||||
|
@ -995,13 +998,19 @@ public:
|
||||||
srcPixel.y = floor((1.0f - srcCoord.y) * srcFaceHeight);
|
srcPixel.y = floor((1.0f - srcCoord.y) * srcFaceHeight);
|
||||||
|
|
||||||
if (((uint32)srcPixel.x < (uint32)source.width()) && ((uint32)srcPixel.y < (uint32)source.height())) {
|
if (((uint32)srcPixel.x < (uint32)source.width()) && ((uint32)srcPixel.y < (uint32)source.height())) {
|
||||||
image.setPixel(x, y, source.pixel(QPoint(srcPixel.x, srcPixel.y)));
|
// We can't directly use the pixel() method because that launches a pixel color conversion to output
|
||||||
|
// a correct RGBA8 color. But in our case we may have stored HDR values encoded in a RGB30 format which
|
||||||
|
// are not convertible by Qt. The same goes with the setPixel method, by the way.
|
||||||
|
const QRgb* sourcePixelIterator = reinterpret_cast<const QRgb*>(source.scanLine(srcPixel.y));
|
||||||
|
sourcePixelIterator += srcPixel.x;
|
||||||
|
*destPixelIterator = *sourcePixelIterator;
|
||||||
|
|
||||||
// Keep for debug, this is showing the dir as a color
|
// Keep for debug, this is showing the dir as a color
|
||||||
// glm::u8vec4 rgba((xyzDir.x + 1.0)*0.5 * 256, (xyzDir.y + 1.0)*0.5 * 256, (xyzDir.z + 1.0)*0.5 * 256, 256);
|
// glm::u8vec4 rgba((xyzDir.x + 1.0)*0.5 * 256, (xyzDir.y + 1.0)*0.5 * 256, (xyzDir.z + 1.0)*0.5 * 256, 256);
|
||||||
// unsigned int val = 0xff000000 | (rgba.r) | (rgba.g << 8) | (rgba.b << 16);
|
// unsigned int val = 0xff000000 | (rgba.r) | (rgba.g << 8) | (rgba.b << 16);
|
||||||
// image.setPixel(x, y, val);
|
// *destPixelIterator = val;
|
||||||
}
|
}
|
||||||
|
++destPixelIterator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return image;
|
return image;
|
||||||
|
@ -1192,6 +1201,10 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(const QImage&
|
||||||
if ((srcImage.width() > 0) && (srcImage.height() > 0)) {
|
if ((srcImage.width() > 0) && (srcImage.height() > 0)) {
|
||||||
QImage image = processSourceImage(srcImage, true);
|
QImage image = processSourceImage(srcImage, true);
|
||||||
|
|
||||||
|
if (image.format() != QIMAGE_HDR_FORMAT) {
|
||||||
|
image = convertToHDRFormat(image, HDR_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
gpu::Element formatMip;
|
gpu::Element formatMip;
|
||||||
gpu::Element formatGPU;
|
gpu::Element formatGPU;
|
||||||
if (isCubeTexturesCompressionEnabled()) {
|
if (isCubeTexturesCompressionEnabled()) {
|
||||||
|
@ -1229,13 +1242,6 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(const QImage&
|
||||||
faces.push_back(faceImage);
|
faces.push_back(faceImage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (image.format() != QIMAGE_HDR_FORMAT) {
|
|
||||||
for (auto& face : faces) {
|
|
||||||
face = convertToHDRFormat(face, HDR_FORMAT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qCDebug(imagelogging) << "Failed to find a known cube map layout from this image:" << QString(srcImageName.c_str());
|
qCDebug(imagelogging) << "Failed to find a known cube map layout from this image:" << QString(srcImageName.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -1018,6 +1018,32 @@ void OffscreenQmlSurface::synthesizeKeyPress(QString key, QObject* targetOverrid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void forEachKeyboard(QQuickItem* item, std::function<void(QQuickItem*)> function) {
|
||||||
|
QObject* itemObject = item;
|
||||||
|
while (itemObject) {
|
||||||
|
if (itemObject->parent()) {
|
||||||
|
itemObject = itemObject->parent();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto keyboards = itemObject->findChildren<QObject*>("keyboard");
|
||||||
|
|
||||||
|
for (auto keyboardObject : keyboards) {
|
||||||
|
auto keyboard = qobject_cast<QQuickItem*>(keyboardObject);
|
||||||
|
if (keyboard == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function) {
|
||||||
|
function(keyboard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int TEXTINPUT_PASSWORD = 2;
|
||||||
|
|
||||||
void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool numeric) {
|
void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool numeric) {
|
||||||
#if Q_OS_ANDROID
|
#if Q_OS_ANDROID
|
||||||
return;
|
return;
|
||||||
|
@ -1030,6 +1056,26 @@ void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool n
|
||||||
// if HMD is being worn, allow keyboard to open. allow it to close, HMD or not.
|
// if HMD is being worn, allow keyboard to open. allow it to close, HMD or not.
|
||||||
if (!raised || qApp->property(hifi::properties::HMD).toBool()) {
|
if (!raised || qApp->property(hifi::properties::HMD).toBool()) {
|
||||||
QQuickItem* item = dynamic_cast<QQuickItem*>(object);
|
QQuickItem* item = dynamic_cast<QQuickItem*>(object);
|
||||||
|
if (!item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto echoMode = item->property("echoMode");
|
||||||
|
bool isPasswordField = echoMode.isValid() && echoMode.toInt() == TEXTINPUT_PASSWORD;
|
||||||
|
|
||||||
|
// we need to somehow pass 'isPasswordField' to visible keyboard so it will change its 'mirror text' to asterixes
|
||||||
|
// the issue in some cases there might be more than one keyboard in object tree and it is hard to understand which one is being used at the moment
|
||||||
|
// unfortunately attempts to check for visibility failed becuase visibility is not updated yet. So... I don't see other way than just update properties for all the keyboards
|
||||||
|
forEachKeyboard(item, [&](QQuickItem* keyboard) {
|
||||||
|
keyboard->setProperty("mirroredText", QVariant::fromValue(QString("")));
|
||||||
|
keyboard->setProperty("password", isPasswordField);
|
||||||
|
});
|
||||||
|
|
||||||
|
// for future probably makes sense to consider one of the following:
|
||||||
|
// 1. make keyboard a singleton, which will be dynamically re-parented before showing
|
||||||
|
// 2. track currently visible keyboard somewhere, allow to subscribe for this signal
|
||||||
|
// any of above should also eliminate need in duplicated properties and code below
|
||||||
|
|
||||||
while (item) {
|
while (item) {
|
||||||
// Numeric value may be set in parameter from HTML UI; for QML UI, detect numeric fields here.
|
// Numeric value may be set in parameter from HTML UI; for QML UI, detect numeric fields here.
|
||||||
numeric = numeric || QString(item->metaObject()->className()).left(7) == "SpinBox";
|
numeric = numeric || QString(item->metaObject()->className()).left(7) == "SpinBox";
|
||||||
|
|
|
@ -53,4 +53,8 @@ ScriptDiscoveryService.clearDebugWindow.connect(function() {
|
||||||
window.clearDebugWindow();
|
window.clearDebugWindow();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(function () {
|
||||||
|
window.close();
|
||||||
|
})
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
|
Loading…
Reference in a new issue