mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-05-28 18:21:20 +00:00
Support for reordering strings with drag & drop
This commit is contained in:
parent
cb262504af
commit
4714c6ccf5
@ -1,4 +1,5 @@
|
||||
#include "CStringTable.h"
|
||||
#include <Common/Math/MathUtil.h>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
@ -88,6 +89,10 @@ void CStringTable::SetStringName(uint StringIndex, const TString& kNewName)
|
||||
}
|
||||
|
||||
mStringNames[StringIndex] = kNewName;
|
||||
|
||||
// Strip empty string names
|
||||
while (mStringNames.back().IsEmpty())
|
||||
mStringNames.pop_back();
|
||||
}
|
||||
|
||||
/** Move string to another position in the table */
|
||||
@ -100,7 +105,7 @@ void CStringTable::MoveString(uint StringIndex, uint NewIndex)
|
||||
return;
|
||||
|
||||
// Update string data
|
||||
for (uint LanguageIdx = 0; LanguageIdx < StringIndex; LanguageIdx++)
|
||||
for (uint LanguageIdx = 0; LanguageIdx < mLanguages.size(); LanguageIdx++)
|
||||
{
|
||||
SLanguageData& Language = mLanguages[LanguageIdx];
|
||||
TString String = Language.Strings[StringIndex];
|
||||
@ -120,19 +125,34 @@ void CStringTable::MoveString(uint StringIndex, uint NewIndex)
|
||||
}
|
||||
|
||||
// Update string name
|
||||
TString Name = mStringNames[StringIndex];
|
||||
uint MinIndex = Math::Min(StringIndex, NewIndex);
|
||||
uint MaxIndex = Math::Max(StringIndex, NewIndex);
|
||||
|
||||
if (NewIndex > StringIndex)
|
||||
if (MinIndex < mStringNames.size())
|
||||
{
|
||||
for (uint i=StringIndex; i<NewIndex; i++)
|
||||
mStringNames[i] = mStringNames[i+1];
|
||||
if (MaxIndex >= mStringNames.size())
|
||||
{
|
||||
mStringNames.resize(MaxIndex + 1);
|
||||
}
|
||||
|
||||
TString Name = mStringNames[StringIndex];
|
||||
|
||||
if (NewIndex > StringIndex)
|
||||
{
|
||||
for (uint i=StringIndex; i<NewIndex; i++)
|
||||
mStringNames[i] = mStringNames[i+1];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint i=StringIndex; i>NewIndex; i--)
|
||||
mStringNames[i] = mStringNames[i-1];
|
||||
}
|
||||
mStringNames[NewIndex] = Name;
|
||||
|
||||
// Strip empty string names
|
||||
while (mStringNames.back().IsEmpty())
|
||||
mStringNames.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint i=StringIndex; i>NewIndex; i--)
|
||||
mStringNames[i] = mStringNames[i-1];
|
||||
}
|
||||
mStringNames[NewIndex] = Name;
|
||||
}
|
||||
|
||||
/** Add a new string to the table */
|
||||
|
@ -206,7 +206,8 @@ HEADERS += \
|
||||
CCustomDelegate.h \
|
||||
CTweakEditor.h \
|
||||
Undo/CEditIntrinsicPropertyCommand.h \
|
||||
Undo/TSerializeUndoCommand.h
|
||||
Undo/TSerializeUndoCommand.h \
|
||||
StringEditor/CStringMimeData.h
|
||||
|
||||
# Source Files
|
||||
SOURCES += \
|
||||
|
@ -18,7 +18,7 @@ class CSetStringIndexCommand : public IUndoCommand
|
||||
int mOldIndex, mNewIndex;
|
||||
public:
|
||||
CSetStringIndexCommand(CStringEditor* pEditor, int OldIndex, int NewIndex)
|
||||
: mpEditor(pEditor), mOldIndex(OldIndex), mNewIndex(NewIndex)
|
||||
: IUndoCommand("Select String"), mpEditor(pEditor), mOldIndex(OldIndex), mNewIndex(NewIndex)
|
||||
{}
|
||||
|
||||
virtual void undo() override { mpEditor->SetActiveString(mOldIndex); }
|
||||
@ -32,7 +32,7 @@ class CSetLanguageCommand : public IUndoCommand
|
||||
ELanguage mOldLanguage, mNewLanguage;
|
||||
public:
|
||||
CSetLanguageCommand(CStringEditor* pEditor, ELanguage OldLanguage, ELanguage NewLanguage)
|
||||
: mpEditor(pEditor), mOldLanguage(OldLanguage), mNewLanguage(NewLanguage)
|
||||
: IUndoCommand("Select Language"), mpEditor(pEditor), mOldLanguage(OldLanguage), mNewLanguage(NewLanguage)
|
||||
{}
|
||||
|
||||
virtual void undo() override { mpEditor->SetActiveLanguage(mOldLanguage); }
|
||||
@ -85,7 +85,7 @@ bool CStringEditor::eventFilter(QObject* pWatched, QEvent* pEvent)
|
||||
void CStringEditor::InitUI()
|
||||
{
|
||||
mpUI->setupUi(this);
|
||||
mpListModel = new CStringListModel(mpStringTable, this);
|
||||
mpListModel = new CStringListModel(this);
|
||||
mpUI->StringNameListView->setModel(mpListModel);
|
||||
mpUI->StringNameListView->setItemDelegate( new CStringDelegate(this) );
|
||||
mpUI->AddStringButton->setShortcut( QKeySequence("Alt+=") );
|
||||
@ -117,6 +117,9 @@ void CStringEditor::InitUI()
|
||||
connect( mpUI->AddStringButton, SIGNAL(pressed()), this, SLOT(OnAddString()) );
|
||||
connect( mpUI->RemoveStringButton, SIGNAL(pressed()), this, SLOT(OnRemoveString()) );
|
||||
|
||||
connect( mpListModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
|
||||
this, SLOT(OnRowsMoved(QModelIndex,int,int,QModelIndex,int)) );
|
||||
|
||||
connect( &UndoStack(), SIGNAL(indexChanged(int)), this, SLOT(UpdateUI()) );
|
||||
|
||||
mpUI->ToolBar->addSeparator();
|
||||
@ -209,20 +212,22 @@ void CStringEditor::UpdateUI()
|
||||
}
|
||||
|
||||
// Update selection in string list
|
||||
QModelIndex OldStringIndex = mpUI->StringNameListView->selectionModel()->hasSelection() ?
|
||||
mpUI->StringNameListView->currentIndex() : QModelIndex();
|
||||
QItemSelectionModel* pSelectionModel = mpUI->StringNameListView->selectionModel();
|
||||
|
||||
QModelIndex OldStringIndex = pSelectionModel->hasSelection() ?
|
||||
pSelectionModel->currentIndex() : QModelIndex();
|
||||
|
||||
QModelIndex NewStringIndex = mpUI->StringNameListView->model()->index(mCurrentStringIndex,0);
|
||||
|
||||
if (OldStringIndex != NewStringIndex)
|
||||
{
|
||||
QItemSelectionModel* pSelectionModel = mpUI->StringNameListView->selectionModel();
|
||||
pSelectionModel->blockSignals(true);
|
||||
pSelectionModel->setCurrentIndex(NewStringIndex, QItemSelectionModel::ClearAndSelect);
|
||||
pSelectionModel->blockSignals(false);
|
||||
mpUI->StringNameListView->update(OldStringIndex);
|
||||
}
|
||||
mpUI->StringNameListView->update(NewStringIndex);
|
||||
mpUI->RemoveStringButton->setEnabled( pSelectionModel->hasSelection() );
|
||||
|
||||
// Update language tabs
|
||||
uint LanguageIndex = mpUI->EditLanguageTabBar->currentIndex();
|
||||
@ -352,6 +357,26 @@ void CStringEditor::OnRemoveString()
|
||||
}
|
||||
}
|
||||
|
||||
void CStringEditor::OnMoveString(int StringIndex, int NewIndex)
|
||||
{
|
||||
if (StringIndex != NewIndex)
|
||||
{
|
||||
ASSERT( StringIndex >= 0 && StringIndex < (int) mpStringTable->NumStrings() );
|
||||
ASSERT( NewIndex >= 0 && NewIndex < (int) mpStringTable->NumStrings() );
|
||||
UndoStack().beginMacro("Move String");
|
||||
|
||||
// Move string
|
||||
IUndoCommand* pCommand = new TSerializeUndoCommand<CStringTable>("Move String", mpStringTable, true);
|
||||
mpStringTable->MoveString(StringIndex, NewIndex);
|
||||
UndoStack().push(pCommand);
|
||||
|
||||
// Select new string index
|
||||
pCommand = new CSetStringIndexCommand(this, StringIndex, NewIndex);
|
||||
UndoStack().push(pCommand);
|
||||
UndoStack().endMacro();
|
||||
}
|
||||
}
|
||||
|
||||
void CStringEditor::IncrementStringIndex()
|
||||
{
|
||||
uint NewIndex = mCurrentStringIndex + 1;
|
||||
|
@ -64,6 +64,7 @@ public slots:
|
||||
void OnStringTextEdited();
|
||||
void OnAddString();
|
||||
void OnRemoveString();
|
||||
void OnMoveString(int StringIndex, int NewIndex);
|
||||
|
||||
void IncrementStringIndex();
|
||||
void DecrementStringIndex();
|
||||
|
@ -57,7 +57,7 @@
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
|
@ -1,9 +1,14 @@
|
||||
#include "CStringListModel.h"
|
||||
#include "CStringEditor.h"
|
||||
#include "CStringMimeData.h"
|
||||
#include "Editor/UICommon.h"
|
||||
|
||||
CStringListModel::CStringListModel(CStringTable* pInStrings, QObject* pParent /*= 0*/)
|
||||
: QAbstractListModel(pParent)
|
||||
, mpStringTable(pInStrings)
|
||||
#include <QMimeData>
|
||||
|
||||
CStringListModel::CStringListModel(CStringEditor* pInEditor)
|
||||
: QAbstractListModel(pInEditor)
|
||||
, mpEditor(pInEditor)
|
||||
, mpStringTable(pInEditor->StringTable())
|
||||
, mStringPreviewLanguage(ELanguage::English)
|
||||
{
|
||||
}
|
||||
@ -67,3 +72,79 @@ QVariant CStringListModel::data(const QModelIndex& kIndex, int Role) const
|
||||
return QVariant::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
Qt::ItemFlags CStringListModel::flags(const QModelIndex& kIndex) const
|
||||
{
|
||||
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
|
||||
}
|
||||
|
||||
/** Drag & Drop support */
|
||||
Qt::DropActions CStringListModel::supportedDragActions() const
|
||||
{
|
||||
return Qt::MoveAction;
|
||||
}
|
||||
|
||||
Qt::DropActions CStringListModel::supportedDropActions() const
|
||||
{
|
||||
return Qt::MoveAction;
|
||||
}
|
||||
|
||||
QMimeData* CStringListModel::mimeData(const QModelIndexList& kIndexes) const
|
||||
{
|
||||
// We don't support drag&drop on multiple strings at once
|
||||
ASSERT( kIndexes.size() == 1 );
|
||||
QModelIndex Index = kIndexes.front();
|
||||
return new CStringMimeData(mpStringTable->ID(), Index.row());
|
||||
}
|
||||
|
||||
bool CStringListModel::canDropMimeData(const QMimeData* pkData, Qt::DropAction Action, int Row, int Column, const QModelIndex& kParent) const
|
||||
{
|
||||
// Only allow dropping string mime data that originated from our string table
|
||||
const CStringMimeData* pkStringMimeData = qobject_cast<const CStringMimeData*>(pkData);
|
||||
return Action == Qt::MoveAction && pkStringMimeData != nullptr && pkStringMimeData->AssetID() == mpStringTable->ID();
|
||||
}
|
||||
|
||||
bool CStringListModel::dropMimeData(const QMimeData* pkData, Qt::DropAction Action, int Row, int Column, const QModelIndex& kParent)
|
||||
{
|
||||
debugf("Dropped onto row %d column %d", Row, Column);
|
||||
|
||||
if (Action == Qt::MoveAction)
|
||||
{
|
||||
const CStringMimeData* pkStringMimeData = qobject_cast<const CStringMimeData*>(pkData);
|
||||
|
||||
if (pkStringMimeData && pkStringMimeData->AssetID() == mpStringTable->ID())
|
||||
{
|
||||
// Determine new row index. If the string was dropped in between items, we can place
|
||||
// it in between those two items. Otherwise, if it was dropped on top of an item, we
|
||||
// want to bump it in place of that item (so use the item's index).
|
||||
if (Row == -1)
|
||||
{
|
||||
Row = kParent.row();
|
||||
|
||||
// In some cases Row can still be -1 at this point if the parent is invalid
|
||||
// It seems like this can happen when trying to place at the top of the list
|
||||
// So to account for it, in this case, reset Row back to 0
|
||||
if (Row == -1)
|
||||
{
|
||||
Row = 0;
|
||||
}
|
||||
}
|
||||
// If the user placed the string at the end of the list, then the index we receive
|
||||
// will be out of range, so cap it to a valid index.
|
||||
else if (Row >= (int) mpStringTable->NumStrings())
|
||||
{
|
||||
Row = mpStringTable->NumStrings() - 1;
|
||||
}
|
||||
// If the string is being moved further down the list, then account for the fact that
|
||||
// the rest of the strings below it will be bumped up.
|
||||
else if (Row > (int) pkStringMimeData->StringIndex())
|
||||
{
|
||||
Row--;
|
||||
}
|
||||
|
||||
mpEditor->OnMoveString(pkStringMimeData->StringIndex(), Row);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -5,9 +5,14 @@
|
||||
#include <Core/Resource/TResPtr.h>
|
||||
#include <Core/Resource/StringTable/CStringTable.h>
|
||||
|
||||
class CStringEditor;
|
||||
|
||||
/** Model for listing available strings in a string table */
|
||||
class CStringListModel : public QAbstractListModel
|
||||
{
|
||||
/** String editor that owns the model */
|
||||
CStringEditor* mpEditor;
|
||||
|
||||
/** Asset to pull the strings from */
|
||||
TResPtr<CStringTable> mpStringTable;
|
||||
|
||||
@ -15,7 +20,7 @@ class CStringListModel : public QAbstractListModel
|
||||
ELanguage mStringPreviewLanguage;
|
||||
|
||||
public:
|
||||
CStringListModel(CStringTable* pInStrings, QObject* pParent = 0);
|
||||
CStringListModel(CStringEditor* pInEditor);
|
||||
|
||||
/** Change the preview language display */
|
||||
void SetPreviewLanguage(ELanguage InLanguage);
|
||||
@ -23,6 +28,14 @@ public:
|
||||
/** QAbstractListModel interface */
|
||||
virtual int rowCount(const QModelIndex& kParent) const override;
|
||||
virtual QVariant data(const QModelIndex& kIndex, int Role) const override;
|
||||
virtual Qt::ItemFlags flags(const QModelIndex& kIndex) const override;
|
||||
|
||||
/** Drag & Drop support */
|
||||
virtual Qt::DropActions supportedDragActions() const override;
|
||||
virtual Qt::DropActions supportedDropActions() const override;
|
||||
virtual QMimeData* mimeData(const QModelIndexList& kIndexes) const override;
|
||||
virtual bool canDropMimeData(const QMimeData* pkData, Qt::DropAction Action, int Row, int Column, const QModelIndex& kParent) const override;
|
||||
virtual bool dropMimeData(const QMimeData* pkData, Qt::DropAction Action, int Row, int Column, const QModelIndex& kParent) override;
|
||||
};
|
||||
|
||||
#endif // CSTRINGLISTMODEL_H
|
||||
|
25
src/Editor/StringEditor/CStringMimeData.h
Normal file
25
src/Editor/StringEditor/CStringMimeData.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef CSTRINGMIMEDATA_H
|
||||
#define CSTRINGMIMEDATA_H
|
||||
|
||||
#include <QMimeData>
|
||||
#include <Common/Common.h>
|
||||
|
||||
/** Mime data encoding a reference to a string for drag&drop support in string editor */
|
||||
class CStringMimeData : public QMimeData
|
||||
{
|
||||
Q_OBJECT
|
||||
CAssetID mAssetID;
|
||||
uint mStringIndex;
|
||||
|
||||
public:
|
||||
CStringMimeData(CAssetID AssetID, uint StringIndex)
|
||||
: mAssetID(AssetID), mStringIndex(StringIndex)
|
||||
{}
|
||||
|
||||
virtual bool hasFormat(const QString& kMimeType) const override { return true; }
|
||||
|
||||
inline CAssetID AssetID() const { return mAssetID; }
|
||||
inline uint StringIndex() const { return mStringIndex; }
|
||||
};
|
||||
|
||||
#endif // CSTRINGMIMEDATA_H
|
Loading…
x
Reference in New Issue
Block a user