Skip to content

Commit

Permalink
Added support of localized strings and custom tool to select localize…
Browse files Browse the repository at this point in the history
…d strings
  • Loading branch information
DronCode committed Jun 9, 2024
1 parent f815aee commit 9445d65
Show file tree
Hide file tree
Showing 6 changed files with 377 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Assets/g1/ZAction.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"parent": "ZEventBase",
"kind": "TypeKind.COMPLEX",
"properties": [
{ "name": "ActionName", "typename": "PRPOpCode.String" },
{ "name": "ActionName", "typename": "ZLocalizedString" },
{ "name": "IsVisible", "typename": "PRPOpCode.Bool" },
{ "name": "ActionType", "typename": "ZAction.EActionType", "offset": 44 },
{ "name": "MessageID", "typename": "ZMsg", "offset": 48 },
Expand Down
6 changes: 6 additions & 0 deletions Assets/g1/ZLocalizedString.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"typename": "ZLocalizedString",
"kind": "TypeKind.ALIAS",
"alias": "PRPOpCode.String",
"editor": "SelectLocalizationKey"
}
6 changes: 6 additions & 0 deletions BMEdit/Editor/Source/Widgets/EditorToolFactory.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <Widgets/EditorToolFactory.h>

// Widgets
#include <SelectLocalizationTool.h>
#include <SelectSceneObjectTool.h>
#include <SelectScriptTool.h>
#include <QDebug>
Expand All @@ -22,6 +23,11 @@ namespace widgets
pResult = SelectScriptTool::Create(parent);
}

if (hintId == "SelectLocalizationKey")
{
pResult = SelectLocalizationTool::Create(parent);
}

if (!pResult)
{
qWarning() << "For hint '" << QString::fromStdString(hintId) << "' no editor created. Check name please";
Expand Down
66 changes: 66 additions & 0 deletions BMEdit/Editor/UI/Include/SelectLocalizationTool.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#pragma once

#include <Widgets/TypePropertyWidget.h>
#include <QItemSelection>
#include <QCloseEvent>
#include <QLabel>


class Frontend_SelectLocalizationTool final : public widgets::TypePropertyWidget
{
Q_OBJECT
public:
Frontend_SelectLocalizationTool(QWidget* parent, widgets::TypePropertyWidget* pTarget);
~Frontend_SelectLocalizationTool() override;

void setValue(const types::QGlacierValue &value) override;
[[nodiscard]] const types::QGlacierValue &getValue() const override;

bool canHookFocus() const override;

private slots:
void onTargetValueChanged();
void onTargetEditFinished();

private:
void commitValue(const types::QGlacierValue &value);

private:
widgets::TypePropertyWidget* m_pTarget { nullptr };
QLabel* m_pLabel { nullptr };
};


namespace Ui {
class SelectLocalizationTool;
}

class SelectLocalizationTool : public widgets::TypePropertyWidget
{
Q_OBJECT

public:
explicit SelectLocalizationTool(QWidget *parent = nullptr);
~SelectLocalizationTool();

static Frontend_SelectLocalizationTool* Create(QWidget* parent);

void setValue(const types::QGlacierValue &value) override;

protected:
// buildLayout and updateLayout not implemented because no dynamic layout here. I'm just handling setValue
void closeEvent(QCloseEvent* pEvent) override;

private:
void disableAcceptButton();
void enableAcceptButton();
void selectByPath(const QString& path);

private slots:
void onAccepted();
void onRejected();
void onLocaleSelected(const QItemSelection &selected, const QItemSelection &deselected);

private:
Ui::SelectLocalizationTool *m_ui;
};
267 changes: 267 additions & 0 deletions BMEdit/Editor/UI/Source/SelectLocalizationTool.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
#include "ui_SelectLocalizationTool.h"
#include <SelectLocalizationTool.h>
#include <Models/ModelsLocator.h>
#include <QStandardItemModel>
#include <QHBoxLayout>
#include <QStringList>
#include <QPushButton>
#include <QString>


Frontend_SelectLocalizationTool::Frontend_SelectLocalizationTool(QWidget *parent, widgets::TypePropertyWidget* pTarget)
: widgets::TypePropertyWidget(parent)
, m_pTarget(pTarget)
{
if (m_pTarget)
{
connect(m_pTarget, &widgets::TypePropertyWidget::valueChanged, this, &Frontend_SelectLocalizationTool::onTargetEditFinished);
connect(m_pTarget, &widgets::TypePropertyWidget::editFinished, this, &Frontend_SelectLocalizationTool::onTargetValueChanged);

m_pTarget->setWindowModality(Qt::WindowModality::ApplicationModal);
m_pTarget->show();
}

// And build layout
auto* pLayout = new QHBoxLayout(this);
m_pLabel = new QLabel(this);
m_pLabel->setText("MAYBE");
pLayout->addWidget(m_pLabel);
setLayout(pLayout);
}

Frontend_SelectLocalizationTool::~Frontend_SelectLocalizationTool()
{
m_pTarget = nullptr;
}

void Frontend_SelectLocalizationTool::setValue(const types::QGlacierValue &value)
{
if (m_pLabel && !value.instructions.empty() && value.instructions[0].isString())
{
m_pLabel->setText(QString::fromStdString(value.instructions[0].getOperand().str));
}

if (m_pTarget)
{
m_pTarget->setValue(value);
}

commitValue(value);
}

const types::QGlacierValue &Frontend_SelectLocalizationTool::getValue() const
{
static const types::QGlacierValue s_Invalid {};
if (!m_pTarget) return s_Invalid;
return m_pTarget->getValue();
}

bool Frontend_SelectLocalizationTool::canHookFocus() const
{
// Yep it can in this case
return true;
}

void Frontend_SelectLocalizationTool::commitValue(const types::QGlacierValue &value)
{
widgets::TypePropertyWidget::setValue(value);
}

void Frontend_SelectLocalizationTool::onTargetValueChanged()
{
if (m_pTarget)
{
commitValue(m_pTarget->getValue());
emit editFinished();
}
}

void Frontend_SelectLocalizationTool::onTargetEditFinished()
{
if (m_pTarget)
{
commitValue(m_pTarget->getValue());
emit valueChanged();
}
}

SelectLocalizationTool::SelectLocalizationTool(QWidget* parent) : widgets::TypePropertyWidget(parent), m_ui(new Ui::SelectLocalizationTool)
{
m_ui->setupUi(this);

// Set model
m_ui->localizedStrings->setModel(models::ModelsLocator::s_LocalizationTreeModel.get());
m_ui->localizedStrings->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);

// Connect signals
connect(m_ui->buttonBox, &QDialogButtonBox::rejected, [this]() {
emit editFinished();
close();
});

connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &SelectLocalizationTool::onAccepted);
}

SelectLocalizationTool::~SelectLocalizationTool()
{
delete m_ui;
}

Frontend_SelectLocalizationTool *SelectLocalizationTool::Create(QWidget *parent)
{
auto* pEditor = new SelectLocalizationTool(nullptr);
auto* pFrontend = new Frontend_SelectLocalizationTool(parent, pEditor);
return pFrontend;
}

void SelectLocalizationTool::setValue(const types::QGlacierValue &value)
{
// call for base
widgets::TypePropertyWidget::setValue(value);

if (value.instructions.size() == 1 && value.instructions[0].isString())
{
// Need to parse path
selectByPath(QString::fromStdString(value.instructions[0].getOperand().str));
}
}

void SelectLocalizationTool::disableAcceptButton()
{
if (QPushButton* pOkButton = m_ui->buttonBox->button(QDialogButtonBox::StandardButton::Ok))
{
pOkButton->setEnabled(false);
}
}

void SelectLocalizationTool::enableAcceptButton()
{
if (QPushButton* pOkButton = m_ui->buttonBox->button(QDialogButtonBox::StandardButton::Ok))
{
pOkButton->setEnabled(true);
}
}

void SelectLocalizationTool::selectByPath(const QString &path)
{
QStringList pathParts = path.split('/');
if (pathParts.empty()) return;

if (pathParts[0] == "ROOT")
{
// remove ROOT because it literally does not exists :)
pathParts.removeFirst();
}

auto* model = qobject_cast<models::LocalizationTreeModel*>(m_ui->localizedStrings->model());
if (!model)
{
return;
}

QModelIndex currentIndex = QModelIndex();

foreach (const QString& part, pathParts)
{
bool found = false;
int rows = model->rowCount(currentIndex);

for (int i = 0; i < rows; ++i)
{
QModelIndex childIndex = model->index(i, 0, currentIndex);
QString entryName = model->data(childIndex, Qt::DisplayRole).toString();

if (entryName == part)
{
currentIndex = childIndex;
found = true;
m_ui->localizedStrings->expand(currentIndex);
m_ui->localizedStrings->scrollTo(currentIndex);
break;
}
}

if (!found)
{
return;
}
}

m_ui->localizedStrings->selectionModel()->select(currentIndex, QItemSelectionModel::Select | QItemSelectionModel::Rows);
}

void SelectLocalizationTool::onAccepted()
{
// need to set value
const QModelIndexList selectedIndexes = m_ui->localizedStrings->selectionModel()->selectedIndexes();
if (selectedIndexes.isEmpty())
{
// just do nothing
emit editFinished();
return;
}

QModelIndex currentIndex = selectedIndexes.first();
QStringList pathParts {};
while (currentIndex.isValid())
{
pathParts.prepend(currentIndex.data().toString());
currentIndex = currentIndex.parent();
}

const auto fullPath = pathParts.join('/').toStdString();
auto newVal = getValue();
if (!newVal.instructions.empty())
{
// weird but ok
newVal.instructions[0] = gamelib::prp::PRPInstruction(newVal.instructions[0].getOpCode(), gamelib::prp::PRPOperandVal(fullPath));

// use base to avoid of extra selector iteration
widgets::TypePropertyWidget::setValue(newVal);
emit editFinished();
}

// and close us
close();
}

void SelectLocalizationTool::onRejected()
{
emit editFinished();
close();
}

void SelectLocalizationTool::onLocaleSelected(const QItemSelection &selected, const QItemSelection &deselected)
{
if (selected.empty())
{
disableAcceptButton();
return;
}

QModelIndex index = selected.first().indexes()[0];
auto* node = reinterpret_cast<gamelib::loc::LOCTreeNode*>(index.internalPointer());

if (!node)
{
disableAcceptButton();
}
else
{
types::QGlacierValue temp = getValue();
if (temp.instructions.empty())
{
disableAcceptButton();
}
else
{
enableAcceptButton();
}
}
}

void SelectLocalizationTool::closeEvent(QCloseEvent *pEvent)
{
emit editFinished();
QWidget::closeEvent(pEvent);
}
Loading

0 comments on commit 9445d65

Please sign in to comment.