1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-18 17:40:48 +02:00

Review and modifying object properties

This commit is contained in:
nordsoft 2022-09-04 04:12:33 +04:00
parent 2572744f00
commit 5a78703abc
12 changed files with 587 additions and 22 deletions

View File

@ -15,6 +15,8 @@ set(editor_SRCS
mapview.cpp
radiopushbutton.cpp
objectbrowser.cpp
inspector.cpp
mapsettings.cpp
)
set(editor_HEADERS
@ -33,12 +35,15 @@ set(editor_HEADERS
mapview.h
radiopushbutton.h
objectbrowser.h
inspector.h
mapsettings.h
)
set(editor_FORMS
mainwindow.ui
windownewmap.ui
generatorprogress.ui
mapsettings.ui
)
assign_source_group(${editor_SRCS} ${editor_HEADERS} VCMI_launcher.rc)

185
mapeditor/inspector.cpp Normal file
View File

@ -0,0 +1,185 @@
#include "StdInc.h"
#include "inspector.h"
#include "../lib/mapObjects/CObjectHandler.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
#include "../lib/mapObjects/CGTownInstance.h"
#include "../lib/spells/CSpellHandler.h"
void Inspector::setProperty(const QString & key, const QVariant & value)
{
if(!obj)
return;
setProperty(dynamic_cast<CGTownInstance*>(obj), key, value);
//updateProperties();
}
void Inspector::setProperty(CGTownInstance * object, const QString & key, const QVariant & value)
{
if(!object)
return;
if(key == "Owner")
{
PlayerColor owner(value.toString().toInt());
if(value == "NEUTRAL")
owner = PlayerColor::NEUTRAL;
if(value == "UNFLAGGABLE")
owner = PlayerColor::UNFLAGGABLE;
object->tempOwner = owner;
return;
}
}
CGTownInstance * initialize(CGTownInstance * o)
{
if(!o)
return nullptr;
o->tempOwner = PlayerColor::NEUTRAL;
o->builtBuildings.insert(BuildingID::FORT);
o->builtBuildings.insert(BuildingID::DEFAULT);
for(auto spell : VLC->spellh->objects) //add all regular spells to town
{
if(!spell->isSpecial() && !spell->isCreatureAbility())
o->possibleSpells.push_back(spell->id);
}
}
Initializer::Initializer(CGObjectInstance * o)
{
initialize(dynamic_cast<CGTownInstance*>(o));
}
Inspector::Inspector(CGObjectInstance * o, QTableWidget * t): obj(o), table(t)
{
/*
/// Position of bottom-right corner of object on map
int3 pos;
/// Type of object, e.g. town, hero, creature.
Obj ID;
/// Subtype of object, depends on type
si32 subID;
/// Current owner of an object (when below PLAYER_LIMIT)
PlayerColor tempOwner;
/// Index of object in map's list of objects
ObjectInstanceID id;
/// Defines appearance of object on map (animation, blocked tiles, blit order, etc)
ObjectTemplate appearance;
/// If true hero can visit this object only from neighbouring tiles and can't stand on this object
bool blockVisit;
std::string instanceName;
std::string typeName;
std::string subTypeName;*/
}
void Inspector::updateProperties()
{
if(!obj)
return;
addProperty("Indentifier", obj);
addProperty("ID", obj->ID.getNum());
addProperty("SubID", obj->subID);
addProperty("InstanceName", obj->instanceName);
addProperty("TypeName", obj->typeName);
addProperty("SubTypeName", obj->subTypeName);
addProperty("Owner", obj->tempOwner, false);
auto factory = VLC->objtypeh->getHandlerFor(obj->ID, obj->subID);
addProperty("IsStatic", factory->isStaticObject());
table->show();
}
QTableWidgetItem * Inspector::addProperty(CGObjectInstance * value)
{
using NumericPointer = unsigned long long;
static_assert(sizeof(CGObjectInstance *) == sizeof(NumericPointer),
"Compilied for 64 bit arcitecture. Use NumericPointer = unsigned int");
return new QTableWidgetItem(QString::number(reinterpret_cast<NumericPointer>(value)));
}
QTableWidgetItem * Inspector::addProperty(int value)
{
return new QTableWidgetItem(QString::number(value));
}
QTableWidgetItem * Inspector::addProperty(bool value)
{
return new QTableWidgetItem(value ? "TRUE" : "FALSE");
}
QTableWidgetItem * Inspector::addProperty(const std::string & value)
{
return addProperty(QString::fromStdString(value));
}
QTableWidgetItem * Inspector::addProperty(const QString & value)
{
return new QTableWidgetItem(value);
}
QTableWidgetItem * Inspector::addProperty(const int3 & value)
{
return new QTableWidgetItem(QString("(%1, %2, %3)").arg(value.x, value.y, value.z));
}
QTableWidgetItem * Inspector::addProperty(const PlayerColor & value)
{
//auto str = QString("PLAYER %1").arg(value.getNum());
auto str = QString::number(value.getNum());
if(value == PlayerColor::NEUTRAL)
str = "NEUTRAL";
if(value == PlayerColor::UNFLAGGABLE)
str = "UNFLAGGABLE";
return new QTableWidgetItem(str);
}
QWidget * PlayerColorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (index.data().canConvert<int>())
{
auto *editor = new QComboBox(parent);
connect(editor, SIGNAL(activated(int)), this, SLOT(commitAndCloseEditor(int)));
return editor;
}
return QStyledItemDelegate::createEditor(parent, option, index);
}
void PlayerColorDelegate::commitAndCloseEditor(int id)
{
QComboBox *editor = qobject_cast<QComboBox *>(sender());
emit commitData(editor);
emit closeEditor(editor);
}
void PlayerColorDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
if (index.data().canConvert<int>())
{
PlayerColor player(qvariant_cast<int>(index.data()));
QComboBox *editor = qobject_cast<QComboBox *>(editor);
editor->addItem(QString::number(player.getNum()));
}
else
{
QStyledItemDelegate::setEditorData(editor, index);
}
}
void PlayerColorDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
if (index.data().canConvert<int>())
{
QComboBox *editor = qobject_cast<QComboBox *>(editor);
model->setData(index, QVariant::fromValue(editor->currentText()));
}
else
{
QStyledItemDelegate::setModelData(editor, model, index);
}
}

77
mapeditor/inspector.h Normal file
View File

@ -0,0 +1,77 @@
#ifndef INSPECTOR_H
#define INSPECTOR_H
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QStyledItemDelegate>
#include "../lib/int3.h"
#include "../lib/GameConstants.h"
class CGObjectInstance;
class CGTownInstance;
class Initializer
{
public:
Initializer(CGObjectInstance *);
};
class Inspector
{
public:
Inspector(CGObjectInstance *, QTableWidget *);
void setProperty(const QString & key, const QVariant & value);
void updateProperties();
protected:
QTableWidgetItem * addProperty(int value);
QTableWidgetItem * addProperty(const std::string & value);
QTableWidgetItem * addProperty(const QString & value);
QTableWidgetItem * addProperty(const int3 & value);
QTableWidgetItem * addProperty(const PlayerColor & value);
QTableWidgetItem * addProperty(bool value);
QTableWidgetItem * addProperty(CGObjectInstance * value);
void setProperty(CGTownInstance * obj, const QString & key, const QVariant & value);
template<class T>
void addProperty(const QString & key, const T & value, bool restricted = true)
{
auto * itemKey = new QTableWidgetItem(key);
auto * itemValue = addProperty(value);
itemKey->setFlags(Qt::NoItemFlags);
if(restricted)
itemValue->setFlags(Qt::NoItemFlags);
if(table->rowCount() < row + 1)
table->setRowCount(row + 1);
table->setItem(row, 0, itemKey);
table->setItem(row, 1, itemValue);
++row;
}
protected:
int row = 0;
QTableWidget * table;
CGObjectInstance * obj;
};
class PlayerColorDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
using QStyledItemDelegate::QStyledItemDelegate;
//void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
//QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
private slots:
void commitAndCloseEditor(int);
};
#endif // INSPECTOR_H

View File

@ -27,6 +27,7 @@
#include "graphics.h"
#include "windownewmap.h"
#include "objectbrowser.h"
#include "inspector.h"
static CBasicLogConfigurator * logConfig;
@ -61,6 +62,10 @@ MainWindow::MainWindow(QWidget *parent) :
ui->setupUi(this);
ui->mapView->setMain(this);
// Set current working dir to executable folder.
// This is important on Mac for relative paths to work inside DMG.
QDir::setCurrent(QApplication::applicationDirPath());
//configure logging
const boost::filesystem::path logPath = VCMIDirs::get().userCachePath() / "VCMI_Editor_log.txt";
@ -172,6 +177,9 @@ MapHandler * MainWindow::getMapHandler()
void MainWindow::resetMapHandler()
{
mapHandler.reset(new MapHandler(map.get()));
unsaved = true;
setWindowTitle(filename + "* - VCMI Map Editor");
}
void MainWindow::setMapRaw(std::unique_ptr<CMap> cmap)
@ -701,6 +709,7 @@ void MainWindow::preparePreview(const QModelIndex &index, bool createNew)
auto factory = VLC->objtypeh->getHandlerFor(objId, objSubId);
auto templ = factory->getTemplates()[templateId];
scenes[mapLevel]->selectionObjectsView.newObject = factory->create(templ);
scenes[mapLevel]->selectionObjectsView.selectionMode = 2;
scenes[mapLevel]->selectionObjectsView.draw();
}
}
@ -780,3 +789,36 @@ void MainWindow::on_actionFill_triggered()
scenes[mapLevel]->updateViews();
}
void MainWindow::loadInspector(CGObjectInstance * obj)
{
Inspector inspector(obj, ui->inspectorWidget);
inspector.updateProperties();
}
void MainWindow::on_inspectorWidget_itemChanged(QTableWidgetItem *item)
{
if(!item->isSelected())
return;
int r = item->row();
int c = item->column();
if(c < 1)
return;
auto * tableWidget = item->tableWidget();
//get identifier
auto identifier = tableWidget->item(0, 1)->text();
static_assert(sizeof(CGObjectInstance *) == sizeof(decltype(identifier.toLongLong())),
"Compilied for 64 bit arcitecture. Use .toInt() method");
CGObjectInstance * obj = reinterpret_cast<CGObjectInstance *>(identifier.toLongLong());
//get parameter name
auto param = tableWidget->item(r, c - 1)->text();
//set parameter
Inspector inspector(obj, tableWidget);
inspector.setProperty(param, item->text());
}

View File

@ -11,6 +11,7 @@
class CMap;
class ObjectBrowser;
class CGObjectInstance;
namespace Ui {
class MainWindow;
@ -37,6 +38,8 @@ public:
void setStatusMessage(const QString & status);
void loadInspector(CGObjectInstance * obj);
MapView * getMapView();
int getMapLevel() const {return mapLevel;}
@ -76,6 +79,8 @@ private slots:
void on_toolBrush4_clicked(bool checked);
void on_inspectorWidget_itemChanged(QTableWidgetItem *item);
public slots:
void treeViewSelected(const QModelIndex &selected, const QModelIndex &deselected);

View File

@ -213,7 +213,7 @@
</sizepolicy>
</property>
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="tab_2">
<property name="sizePolicy">
@ -223,7 +223,7 @@
</sizepolicy>
</property>
<attribute name="title">
<string>Objects</string>
<string>Browser</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
@ -293,6 +293,59 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Inspector</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTableWidget" name="inspectorWidget">
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="editTriggers">
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="columnCount">
<number>2</number>
</property>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>20</number>
</attribute>
<column>
<property name="text">
<string>Property</string>
</property>
</column>
<column>
<property name="text">
<string>Value</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>

14
mapeditor/mapsettings.cpp Normal file
View File

@ -0,0 +1,14 @@
#include "mapsettings.h"
#include "ui_mapsettings.h"
MapSettings::MapSettings(QWidget *parent) :
QDialog(parent),
ui(new Ui::MapSettings)
{
ui->setupUi(this);
}
MapSettings::~MapSettings()
{
delete ui;
}

22
mapeditor/mapsettings.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef MAPSETTINGS_H
#define MAPSETTINGS_H
#include <QDialog>
namespace Ui {
class MapSettings;
}
class MapSettings : public QDialog
{
Q_OBJECT
public:
explicit MapSettings(QWidget *parent = nullptr);
~MapSettings();
private:
Ui::MapSettings *ui;
};
#endif // MAPSETTINGS_H

102
mapeditor/mapsettings.ui Normal file
View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MapSettings</class>
<widget class="QDialog" name="MapSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>308</width>
<height>251</height>
</rect>
</property>
<property name="windowTitle">
<string>Map settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Map description</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QPlainTextEdit" name="plainTextEdit"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Map name</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Players amount</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="locale">
<locale language="English" country="UnitedStates"/>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLineEdit" name="lineEdit"/>
</item>
<item row="5" column="0">
<widget class="QComboBox" name="comboBox">
<item>
<property name="text">
<string>1</string>
</property>
</item>
<item>
<property name="text">
<string>2</string>
</property>
</item>
<item>
<property name="text">
<string>3</string>
</property>
</item>
<item>
<property name="text">
<string>4</string>
</property>
</item>
<item>
<property name="text">
<string>5</string>
</property>
</item>
<item>
<property name="text">
<string>6</string>
</property>
</item>
<item>
<property name="text">
<string>7</string>
</property>
</item>
<item>
<property name="text">
<string>8</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -1,6 +1,7 @@
#include "StdInc.h"
#include "mapview.h"
#include "mainwindow.h"
#include "inspector.h"
#include <QGraphicsSceneMouseEvent>
#include "../lib/mapping/CMapEditManager.h"
@ -99,10 +100,22 @@ void MapView::mouseMoveEvent(QMouseEvent *mouseEvent)
auto sh = tile - tileStart;
sc->selectionObjectsView.shift = QPoint(sh.x, sh.y);
if((sh.x || sh.y) && sc->selectionObjectsView.newObject)
if(sh.x || sh.y)
{
sc->selectionObjectsView.shift = QPoint(tile.x, tile.y);
sc->selectionObjectsView.selectObject(sc->selectionObjectsView.newObject);
if(sc->selectionObjectsView.newObject)
{
sc->selectionObjectsView.shift = QPoint(tile.x, tile.y);
sc->selectionObjectsView.selectObject(sc->selectionObjectsView.newObject);
sc->selectionObjectsView.selectionMode = 2;
}
else if(mouseEvent->buttons() & Qt::LeftButton)
{
if(sc->selectionObjectsView.selectionMode == 1)
{
sc->selectionObjectsView.clear();
sc->selectionObjectsView.selectObjects(tileStart.x, tileStart.y, tile.x, tile.y);
}
}
}
sc->selectionObjectsView.draw();
@ -196,9 +209,29 @@ void MapView::mousePressEvent(QMouseEvent *event)
}
else
{
sc->selectionObjectsView.clear();
if(event->button() == Qt::LeftButton)
sc->selectionObjectsView.selectObjectAt(tileStart.x, tileStart.y);
{
auto * obj = sc->selectionObjectsView.selectObjectAt(tileStart.x, tileStart.y);
if(obj)
{
if(sc->selectionObjectsView.isSelected(obj))
{
sc->selectionObjectsView.selectionMode = 2;
}
else
{
sc->selectionObjectsView.clear();
sc->selectionObjectsView.selectionMode = 2;
sc->selectionObjectsView.selectObject(obj);
}
}
else
{
sc->selectionObjectsView.clear();
sc->selectionObjectsView.selectionMode = 1;
}
}
sc->selectionObjectsView.shift = QPoint(0, 0);
sc->selectionObjectsView.draw();
}
break;
@ -230,16 +263,23 @@ void MapView::mouseReleaseEvent(QMouseEvent *event)
if(event->button() == Qt::RightButton)
break;
//switch position
if(sc->selectionObjectsView.applyShift())
if(sc->selectionObjectsView.selectionMode == 2 && sc->selectionObjectsView.applyShift())
{
sc->selectionObjectsView.newObject = nullptr;
sc->selectionObjectsView.selectionMode = 0;
sc->selectionObjectsView.shift = QPoint(0, 0);
main->resetMapHandler();
sc->updateViews();
}
else
{
sc->selectionObjectsView.selectionMode = 0;
sc->selectionObjectsView.shift = QPoint(0, 0);
sc->selectionObjectsView.draw();
//check if we have only one object
auto selection = sc->selectionObjectsView.getSelection();
if(selection.size() == 1)
main->loadInspector(*selection.begin());
}
break;
}
@ -664,7 +704,7 @@ void SelectionObjectsView::draw()
}
//show translation
if(shift.x() || shift.y())
if(selectionMode == 2 && (shift.x() || shift.y()))
{
painter.setOpacity(0.5);
auto newPos = QPoint(obj->getPosition().x, obj->getPosition().y) + shift;
@ -675,7 +715,7 @@ void SelectionObjectsView::draw()
redraw();
}
CGObjectInstance * SelectionObjectsView::selectObjectAt(int x, int y)
CGObjectInstance * SelectionObjectsView::selectObjectAt(int x, int y) const
{
if(!main->getMap() || !main->getMapHandler() || !main->getMap()->isInTheMap(int3(x, y, scene->level)))
return nullptr;
@ -685,12 +725,11 @@ CGObjectInstance * SelectionObjectsView::selectObjectAt(int x, int y)
//visitable is most important
for(auto & object : objects)
{
if(!object.obj || selectedObjects.count(object.obj))
if(!object.obj)
continue;
if(object.obj->visitableAt(x, y))
{
selectedObjects.insert(object.obj);
return object.obj;
}
}
@ -698,12 +737,11 @@ CGObjectInstance * SelectionObjectsView::selectObjectAt(int x, int y)
//if not visitable tile - try to get blocked
for(auto & object : objects)
{
if(!object.obj || selectedObjects.count(object.obj))
if(!object.obj)
continue;
if(object.obj->blockingAt(x, y))
{
selectedObjects.insert(object.obj);
return object.obj;
}
}
@ -711,12 +749,11 @@ CGObjectInstance * SelectionObjectsView::selectObjectAt(int x, int y)
//finally, we can take any object
for(auto & object : objects)
{
if(!object.obj || selectedObjects.count(object.obj))
if(!object.obj)
continue;
if(object.obj->coveringAt(x, y))
{
selectedObjects.insert(object.obj);
return object.obj;
}
}
@ -738,6 +775,7 @@ bool SelectionObjectsView::applyShift()
{
newObject->pos = pos;
main->getMap()->getEditManager()->insertObject(newObject);
Initializer init(newObject);
}
else
{
@ -759,11 +797,25 @@ void SelectionObjectsView::deleteSelection()
clear();
}
std::set<CGObjectInstance *> SelectionObjectsView::selectObjects(int x1, int y1, int x2, int y2)
void SelectionObjectsView::selectObjects(int x1, int y1, int x2, int y2)
{
std::set<CGObjectInstance *> result;
//TBD
return result;
if(!main->getMap() || !main->getMapHandler())
return;
if(x1 > x2)
std::swap(x1, x2);
if(y1 > y2)
std::swap(y1, y2);
for(int j = y1; j < y2; ++j)
{
for(int i = x1; i < x2; ++i)
{
for(auto & o : main->getMapHandler()->getObjects(i, j, scene->level))
selectObject(o.obj);
}
}
}
void SelectionObjectsView::selectObject(CGObjectInstance * obj)
@ -776,6 +828,11 @@ bool SelectionObjectsView::isSelected(const CGObjectInstance * obj) const
return selectedObjects.count(const_cast<CGObjectInstance*>(obj));
}
std::set<CGObjectInstance*> SelectionObjectsView::getSelection() const
{
return selectedObjects;
}
void SelectionObjectsView::clear()
{
selectedObjects.clear();

View File

@ -134,10 +134,11 @@ public:
void draw();
CGObjectInstance * selectObjectAt(int x, int y);
std::set<CGObjectInstance *> selectObjects(int x1, int y1, int x2, int y2);
CGObjectInstance * selectObjectAt(int x, int y) const;
void selectObjects(int x1, int y1, int x2, int y2);
void selectObject(CGObjectInstance *);
bool isSelected(const CGObjectInstance *) const;
std::set<CGObjectInstance*> getSelection() const;
void moveSelection(int x, int y);
void clear();
@ -146,6 +147,7 @@ public:
QPoint shift;
CGObjectInstance * newObject;
int selectionMode = 0; //0 - nothing, 1 - selection, 2 - movement
private:
std::set<CGObjectInstance *> selectedObjects;

View File

@ -68,6 +68,7 @@ void WindowNewMap::on_okButtong_clicked()
mapGenOptions.setWaterContent(water);
mapGenOptions.setMonsterStrength(monster);
CMapGenerator generator(mapGenOptions);
//TODO: fix water and roads