1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Merge pull request #3046 from Nordsoft91/editor-improvements-1.4

Add map editor zoom and objects lock functionality
This commit is contained in:
Nordsoft91 2023-10-16 01:22:18 +02:00 committed by GitHub
commit 02c1425939
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1110 additions and 449 deletions

View File

@ -1067,8 +1067,7 @@ std::string CGHeroInstance::getBiographyTextID() const
if (type)
return type->getBiographyTextID();
assert(0);
return "";
return ""; //for random hero
}
CGHeroInstance::ArtPlacementMap CGHeroInstance::putArtifact(ArtifactPosition pos, CArtifactInstance * art)

View File

@ -14,6 +14,7 @@
#include "Animation.h"
#include "BitmapHandler.h"
#include "graphics.h"
#include "../lib/vcmi_endian.h"
#include "../lib/filesystem/Filesystem.h"
@ -585,8 +586,8 @@ void Animation::init()
JsonPath resID = JsonPath::builtin("SPRITES/" + name);
//if(vstd::contains(graphics->imageLists, resID.getName()))
//initFromJson(graphics->imageLists[resID.getName()]);
if(vstd::contains(graphics->imageLists, resID.getName()))
initFromJson(graphics->imageLists[resID.getName()]);
auto configList = CResourceHandler::get()->getResourcesWithName(resID);

View File

@ -35,6 +35,7 @@ set(editor_SRCS
inspector/questwidget.cpp
inspector/heroskillswidget.cpp
inspector/PickObjectDelegate.cpp
inspector/portraitwidget.cpp
resourceExtractor/ResourceConverter.cpp
)
@ -74,6 +75,7 @@ set(editor_HEADERS
inspector/questwidget.h
inspector/heroskillswidget.h
inspector/PickObjectDelegate.h
inspector/portraitwidget.h
resourceExtractor/ResourceConverter.h
)
@ -99,6 +101,7 @@ set(editor_FORMS
inspector/rewardswidget.ui
inspector/questwidget.ui
inspector/heroskillswidget.ui
inspector/portraitwidget.ui
)
set(editor_TS

View File

@ -11,6 +11,7 @@
//code is copied from vcmiclient/Graphics.h with minimal changes
#include "../lib/GameConstants.h"
#include "../lib/filesystem/ResourcePath.h"
#include <QImage>
VCMI_LIB_NAMESPACE_BEGIN

BIN
mapeditor/icons/brush-0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
mapeditor/icons/brush-6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
mapeditor/icons/brush-7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -26,6 +26,7 @@
#include "rewardswidget.h"
#include "questwidget.h"
#include "heroskillswidget.h"
#include "portraitwidget.h"
#include "PickObjectDelegate.h"
#include "../mapcontroller.h"
@ -272,7 +273,7 @@ void Inspector::updateProperties(CGHeroInstance * o)
}
addProperty("Name", o->getNameTranslated(), false);
addProperty("Biography", o->getBiographyTranslated(), new MessageDelegate, false);
addProperty("Portrait", o->customPortraitSource, false);
addProperty("Portrait", PropertyEditorPlaceholder(), new PortraitDelegate(*o), false);
auto * delegate = new HeroSkillsDelegate(*o);
addProperty("Skills", PropertyEditorPlaceholder(), delegate, false);

View File

@ -0,0 +1,135 @@
/*
* portraitwidget.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 "portraitwidget.h"
#include "ui_portraitwidget.h"
#include "../../lib/CHeroHandler.h"
#include "../Animation.h"
PortraitWidget::PortraitWidget(CGHeroInstance & h, QWidget *parent):
QDialog(parent),
ui(new Ui::PortraitWidget),
hero(h),
portraitIndex(0)
{
ui->setupUi(this);
ui->portraitView->setScene(&scene);
ui->portraitView->fitInView(scene.itemsBoundingRect(), Qt::KeepAspectRatio);
}
PortraitWidget::~PortraitWidget()
{
delete ui;
}
void PortraitWidget::obtainData()
{
portraitIndex = VLC->heroh->getById(hero.getPortraitSource())->getIndex();
if(hero.customPortraitSource.isValid())
{
ui->isDefault->setChecked(true);
}
drawPortrait();
}
void PortraitWidget::commitChanges()
{
if(portraitIndex == VLC->heroh->getById(HeroTypeID(hero.subID))->getIndex())
hero.customPortraitSource = HeroTypeID::NONE;
else
hero.customPortraitSource = VLC->heroh->getByIndex(portraitIndex)->getId();
}
void PortraitWidget::drawPortrait()
{
static Animation portraitAnimation(AnimationPath::builtin("PortraitsLarge").getOriginalName());
portraitAnimation.preload();
auto icon = VLC->heroTypes()->getByIndex(portraitIndex)->getIconIndex();
pixmap = QPixmap::fromImage(*portraitAnimation.getImage(icon));
scene.addPixmap(pixmap);
ui->portraitView->fitInView(scene.itemsBoundingRect(), Qt::KeepAspectRatio);
}
void PortraitWidget::resizeEvent(QResizeEvent *)
{
ui->portraitView->fitInView(scene.itemsBoundingRect(), Qt::KeepAspectRatio);
}
void PortraitWidget::on_isDefault_toggled(bool checked)
{
if(checked)
{
ui->buttonNext->setEnabled(false);
ui->buttonPrev->setEnabled(false);
portraitIndex = VLC->heroh->getById(HeroTypeID(hero.subID))->getIndex();
}
else
{
ui->buttonNext->setEnabled(true);
ui->buttonPrev->setEnabled(true);
}
drawPortrait();
}
void PortraitWidget::on_buttonNext_clicked()
{
if(portraitIndex < VLC->heroh->size() - 1)
++portraitIndex;
else
portraitIndex = 0;
drawPortrait();
}
void PortraitWidget::on_buttonPrev_clicked()
{
if(portraitIndex > 0)
--portraitIndex;
else
portraitIndex = VLC->heroh->size() - 1;
drawPortrait();
}
PortraitDelegate::PortraitDelegate(CGHeroInstance & h): hero(h), QStyledItemDelegate()
{
}
QWidget * PortraitDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
return new PortraitWidget(hero, parent);
}
void PortraitDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
if(auto * ed = qobject_cast<PortraitWidget *>(editor))
{
ed->obtainData();
}
else
{
QStyledItemDelegate::setEditorData(editor, index);
}
}
void PortraitDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
if(auto * ed = qobject_cast<PortraitWidget *>(editor))
{
ed->commitChanges();
}
else
{
QStyledItemDelegate::setModelData(editor, model, index);
}
}

View File

@ -0,0 +1,64 @@
/*
* portraitwidget.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
#include <QDialog>
#include "../../lib/mapObjects/CGHeroInstance.h"
namespace Ui {
class PortraitWidget;
}
class PortraitWidget : public QDialog
{
Q_OBJECT
public:
explicit PortraitWidget(CGHeroInstance &, QWidget *parent = nullptr);
~PortraitWidget();
void obtainData();
void commitChanges();
void resizeEvent(QResizeEvent *) override;
private slots:
void on_isDefault_toggled(bool checked);
void on_buttonNext_clicked();
void on_buttonPrev_clicked();
private:
void drawPortrait();
Ui::PortraitWidget *ui;
QGraphicsScene scene;
QPixmap pixmap;
CGHeroInstance & hero;
int portraitIndex;
};
class PortraitDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
using QStyledItemDelegate::QStyledItemDelegate;
PortraitDelegate(CGHeroInstance &);
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:
CGHeroInstance & hero;
};

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PortraitWidget</class>
<widget class="QDialog" name="PortraitWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>286</width>
<height>305</height>
</rect>
</property>
<property name="windowTitle">
<string>Portrait</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QGraphicsView" name="portraitView">
<property name="minimumSize">
<size>
<width>116</width>
<height>128</height>
</size>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<item>
<widget class="QToolButton" name="buttonNext">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>...</string>
</property>
<property name="arrowType">
<enum>Qt::UpArrow</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="buttonPrev">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>...</string>
</property>
<property name="arrowType">
<enum>Qt::DownArrow</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="isDefault">
<property name="text">
<string>Default</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -222,6 +222,8 @@ MainWindow::MainWindow(QWidget* parent) :
scenePreview = new QGraphicsScene(this);
ui->objectPreview->setScene(scenePreview);
initialScale = ui->mapView->viewport()->geometry();
//loading objects
loadObjectsTree();
@ -296,6 +298,7 @@ void MainWindow::initializeMap(bool isNew)
ui->mapView->setScene(controller.scene(mapLevel));
ui->minimapView->setScene(controller.miniScene(mapLevel));
ui->minimapView->dimensions();
initialScale = ui->mapView->mapToScene(ui->mapView->viewport()->geometry()).boundingRect();
//enable settings
ui->actionMapSettings->setEnabled(true);
@ -537,18 +540,20 @@ void MainWindow::addGroupIntoCatalog(const std::string & groupName, bool useCust
painter.drawImage(QPoint(0, 0), *picture);
}
//create object to extract name
std::unique_ptr<CGObjectInstance> temporaryObj(factory->create(templ));
QString translated = useCustomName ? QString::fromStdString(temporaryObj->getObjectName().c_str()) : subGroupName;
itemType->setText(translated);
//add parameters
QJsonObject data{{"id", QJsonValue(ID)},
{"subid", QJsonValue(secondaryID)},
{"template", QJsonValue(templateId)},
{"animationEditor", QString::fromStdString(templ->editorAnimationFile.getOriginalName())},
{"animation", QString::fromStdString(templ->animationFile.getOriginalName())},
{"preview", jsonFromPixmap(preview)}};
//create object to extract name
std::unique_ptr<CGObjectInstance> temporaryObj(factory->create(templ));
QString translated = useCustomName ? tr(temporaryObj->getObjectName().c_str()) : subGroupName;
itemType->setText(translated);
{"preview", jsonFromPixmap(preview)},
{"typeName", QString::fromStdString(factory->getJsonKey())}
};
//do not have extra level
if(singleTemplate)
@ -830,99 +835,12 @@ void MainWindow::changeBrushState(int idx)
}
void MainWindow::on_toolBrush_clicked(bool checked)
{
//ui->toolBrush->setChecked(false);
ui->toolBrush2->setChecked(false);
ui->toolBrush4->setChecked(false);
ui->toolArea->setChecked(false);
ui->toolLasso->setChecked(false);
if(checked)
ui->mapView->selectionTool = MapView::SelectionTool::Brush;
else
ui->mapView->selectionTool = MapView::SelectionTool::None;
ui->tabWidget->setCurrentIndex(0);
}
void MainWindow::on_toolBrush2_clicked(bool checked)
{
ui->toolBrush->setChecked(false);
//ui->toolBrush2->setChecked(false);
ui->toolBrush4->setChecked(false);
ui->toolArea->setChecked(false);
ui->toolLasso->setChecked(false);
if(checked)
ui->mapView->selectionTool = MapView::SelectionTool::Brush2;
else
ui->mapView->selectionTool = MapView::SelectionTool::None;
ui->tabWidget->setCurrentIndex(0);
}
void MainWindow::on_toolBrush4_clicked(bool checked)
{
ui->toolBrush->setChecked(false);
ui->toolBrush2->setChecked(false);
//ui->toolBrush4->setChecked(false);
ui->toolArea->setChecked(false);
ui->toolLasso->setChecked(false);
if(checked)
ui->mapView->selectionTool = MapView::SelectionTool::Brush4;
else
ui->mapView->selectionTool = MapView::SelectionTool::None;
ui->tabWidget->setCurrentIndex(0);
}
void MainWindow::on_toolArea_clicked(bool checked)
{
ui->toolBrush->setChecked(false);
ui->toolBrush2->setChecked(false);
ui->toolBrush4->setChecked(false);
//ui->toolArea->setChecked(false);
ui->toolLasso->setChecked(false);
if(checked)
ui->mapView->selectionTool = MapView::SelectionTool::Area;
else
ui->mapView->selectionTool = MapView::SelectionTool::None;
ui->tabWidget->setCurrentIndex(0);
}
void MainWindow::on_toolLasso_clicked(bool checked)
{
ui->toolBrush->setChecked(false);
ui->toolBrush2->setChecked(false);
ui->toolBrush4->setChecked(false);
ui->toolArea->setChecked(false);
//ui->toolLasso->setChecked(false);
if(checked)
ui->mapView->selectionTool = MapView::SelectionTool::Lasso;
else
ui->mapView->selectionTool = MapView::SelectionTool::None;
ui->tabWidget->setCurrentIndex(0);
}
void MainWindow::on_actionErase_triggered()
{
on_toolErase_clicked();
}
void MainWindow::on_toolErase_clicked()
{
if(controller.map())
{
controller.commitObjectErase(mapLevel);
}
ui->tabWidget->setCurrentIndex(0);
}
void MainWindow::preparePreview(const QModelIndex &index)
@ -939,16 +857,14 @@ void MainWindow::preparePreview(const QModelIndex &index)
scenePreview->addPixmap(objPreview);
}
}
ui->objectPreview->fitInView(scenePreview->itemsBoundingRect(), Qt::KeepAspectRatio);
}
void MainWindow::treeViewSelected(const QModelIndex & index, const QModelIndex & deselected)
{
ui->toolBrush->setChecked(false);
ui->toolBrush2->setChecked(false);
ui->toolBrush4->setChecked(false);
ui->toolArea->setChecked(false);
ui->toolLasso->setChecked(false);
ui->toolSelect->setChecked(true);
ui->mapView->selectionTool = MapView::SelectionTool::None;
preparePreview(index);
@ -1109,7 +1025,6 @@ void MainWindow::onSelectionMade(int level, bool anythingSelected)
if (level == mapLevel)
{
ui->actionErase->setEnabled(anythingSelected);
ui->toolErase->setEnabled(anythingSelected);
}
}
void MainWindow::displayStatus(const QString& message, int timeout /* = 2000 */)
@ -1279,3 +1194,145 @@ void MainWindow::on_actionh3m_converter_triggered()
}
}
void MainWindow::on_actionLock_triggered()
{
if(controller.map())
{
if(controller.scene(mapLevel)->selectionObjectsView.getSelection().empty())
{
for(auto obj : controller.map()->objects)
{
controller.scene(mapLevel)->selectionObjectsView.setLockObject(obj, true);
controller.scene(mapLevel)->objectsView.setLockObject(obj, true);
}
}
else
{
for(auto * obj : controller.scene(mapLevel)->selectionObjectsView.getSelection())
{
controller.scene(mapLevel)->selectionObjectsView.setLockObject(obj, true);
controller.scene(mapLevel)->objectsView.setLockObject(obj, true);
}
controller.scene(mapLevel)->selectionObjectsView.clear();
}
controller.scene(mapLevel)->objectsView.update();
controller.scene(mapLevel)->selectionObjectsView.update();
}
}
void MainWindow::on_actionUnlock_triggered()
{
if(controller.map())
{
controller.scene(mapLevel)->selectionObjectsView.unlockAll();
controller.scene(mapLevel)->objectsView.unlockAll();
}
controller.scene(mapLevel)->objectsView.update();
}
void MainWindow::on_actionZoom_in_triggered()
{
auto rect = ui->mapView->mapToScene(ui->mapView->viewport()->geometry()).boundingRect();
rect -= QMargins{32 + 1, 32 + 1, 32 + 2, 32 + 2}; //compensate bounding box
ui->mapView->fitInView(rect, Qt::KeepAspectRatioByExpanding);
}
void MainWindow::on_actionZoom_out_triggered()
{
auto rect = ui->mapView->mapToScene(ui->mapView->viewport()->geometry()).boundingRect();
rect += QMargins{32 - 1, 32 - 1, 32 - 2, 32 - 2}; //compensate bounding box
ui->mapView->fitInView(rect, Qt::KeepAspectRatioByExpanding);
}
void MainWindow::on_actionZoom_reset_triggered()
{
auto center = ui->mapView->mapToScene(ui->mapView->viewport()->geometry().center());
ui->mapView->fitInView(initialScale, Qt::KeepAspectRatioByExpanding);
ui->mapView->centerOn(center);
}
void MainWindow::on_toolLine_toggled(bool checked)
{
if(checked)
{
ui->mapView->selectionTool = MapView::SelectionTool::Line;
ui->tabWidget->setCurrentIndex(0);
}
}
void MainWindow::on_toolBrush2_toggled(bool checked)
{
if(checked)
{
ui->mapView->selectionTool = MapView::SelectionTool::Brush2;
ui->tabWidget->setCurrentIndex(0);
}
}
void MainWindow::on_toolBrush_toggled(bool checked)
{
if(checked)
{
ui->mapView->selectionTool = MapView::SelectionTool::Brush;
ui->tabWidget->setCurrentIndex(0);
}
}
void MainWindow::on_toolBrush4_toggled(bool checked)
{
if(checked)
{
ui->mapView->selectionTool = MapView::SelectionTool::Brush4;
ui->tabWidget->setCurrentIndex(0);
}
}
void MainWindow::on_toolLasso_toggled(bool checked)
{
if(checked)
{
ui->mapView->selectionTool = MapView::SelectionTool::Lasso;
ui->tabWidget->setCurrentIndex(0);
}
}
void MainWindow::on_toolArea_toggled(bool checked)
{
if(checked)
{
ui->mapView->selectionTool = MapView::SelectionTool::Area;
ui->tabWidget->setCurrentIndex(0);
}
}
void MainWindow::on_toolFill_toggled(bool checked)
{
if(checked)
{
ui->mapView->selectionTool = MapView::SelectionTool::Fill;
ui->tabWidget->setCurrentIndex(0);
}
}
void MainWindow::on_toolSelect_toggled(bool checked)
{
if(checked)
{
ui->mapView->selectionTool = MapView::SelectionTool::None;
ui->tabWidget->setCurrentIndex(0);
}
}

View File

@ -76,28 +76,16 @@ private slots:
void on_actionGrid_triggered(bool checked);
void on_toolBrush_clicked(bool checked);
void on_toolArea_clicked(bool checked);
void terrainButtonClicked(TerrainId terrain);
void roadOrRiverButtonClicked(ui8 type, bool isRoad);
void currentCoordinatesChanged(int x, int y);
void on_toolErase_clicked();
void on_terrainFilterCombo_currentIndexChanged(int index);
void on_filter_textChanged(const QString &arg1);
void on_actionFill_triggered();
void on_toolBrush2_clicked(bool checked);
void on_toolBrush4_clicked(bool checked);
void on_toolLasso_clicked(bool checked);
void on_inspectorWidget_itemChanged(QTableWidgetItem *item);
void on_actionMapSettings_triggered();
@ -124,6 +112,32 @@ private slots:
void on_actionh3m_converter_triggered();
void on_actionLock_triggered();
void on_actionUnlock_triggered();
void on_actionZoom_in_triggered();
void on_actionZoom_out_triggered();
void on_actionZoom_reset_triggered();
void on_toolLine_toggled(bool checked);
void on_toolBrush2_toggled(bool checked);
void on_toolBrush_toggled(bool checked);
void on_toolBrush4_toggled(bool checked);
void on_toolLasso_toggled(bool checked);
void on_toolArea_toggled(bool checked);
void on_toolFill_toggled(bool checked);
void on_toolSelect_toggled(bool checked);
public slots:
void treeViewSelected(const QModelIndex &selected, const QModelIndex &deselected);
@ -166,6 +180,7 @@ private:
QStandardItemModel objectsModel;
int mapLevel = 0;
QRectF initialScale;
std::set<int> catalog;

View File

@ -86,6 +86,8 @@
<addaction name="actionCopy"/>
<addaction name="actionPaste"/>
<addaction name="actionErase"/>
<addaction name="actionLock"/>
<addaction name="actionUnlock"/>
</widget>
<widget class="QMenu" name="menuView">
<property name="title">
@ -94,6 +96,10 @@
<addaction name="actionLevel"/>
<addaction name="actionGrid"/>
<addaction name="actionPass"/>
<addaction name="separator"/>
<addaction name="actionZoom_in"/>
<addaction name="actionZoom_out"/>
<addaction name="actionZoom_reset"/>
</widget>
<widget class="QMenu" name="menuPlayer">
<property name="title">
@ -143,6 +149,13 @@
<addaction name="separator"/>
<addaction name="actionFill"/>
<addaction name="actionTranslations"/>
<addaction name="separator"/>
<addaction name="actionLock"/>
<addaction name="actionUnlock"/>
<addaction name="separator"/>
<addaction name="actionZoom_in"/>
<addaction name="actionZoom_out"/>
<addaction name="actionZoom_reset"/>
</widget>
<widget class="QDockWidget" name="dockWidget_2">
<property name="sizePolicy">
@ -163,6 +176,9 @@
<height>214</height>
</size>
</property>
<property name="features">
<set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
</property>
<property name="windowTitle">
<string>Minimap</string>
</property>
@ -203,12 +219,6 @@
<height>192</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>192</width>
<height>192</height>
</size>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
@ -239,6 +249,9 @@
<height>524287</height>
</size>
</property>
<property name="features">
<set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
</property>
<property name="windowTitle">
<string>Map Objects View</string>
</property>
@ -429,17 +442,8 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>128</width>
<height>192</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>524287</width>
<height>192</height>
</size>
<property name="features">
<set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
</property>
<property name="windowTitle">
<string>Tools</string>
@ -468,48 +472,23 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_8">
<property name="leftMargin">
<number>0</number>
<number>3</number>
</property>
<property name="topMargin">
<number>0</number>
<number>3</number>
</property>
<property name="rightMargin">
<number>0</number>
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>Brush</string>
</property>
<layout class="QFormLayout" name="formLayout">
<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 row="0" column="0">
<widget class="QPushButton" name="toolBrush">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
@ -545,12 +524,15 @@
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoExclusive">
<bool>true</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<item>
<widget class="QPushButton" name="toolBrush2">
<property name="enabled">
<bool>true</bool>
@ -589,12 +571,15 @@
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoExclusive">
<bool>true</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<item>
<widget class="QPushButton" name="toolBrush4">
<property name="enabled">
<bool>true</bool>
@ -633,39 +618,7 @@
<property name="checkable">
<bool>true</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="toolArea">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>icons:brush-5.png</normaloff>icons:brush-5.png</iconset>
</property>
<property name="checkable">
<property name="autoExclusive">
<bool>true</bool>
</property>
<property name="flat">
@ -673,7 +626,7 @@
</property>
</widget>
</item>
<item row="2" column="0">
<item>
<widget class="QPushButton" name="toolLasso">
<property name="enabled">
<bool>true</bool>
@ -706,16 +659,134 @@
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoExclusive">
<bool>true</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="toolErase">
<property name="enabled">
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="toolLine">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>icons:brush-7.png</normaloff>icons:brush-7.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoExclusive">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="toolArea">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>icons:brush-5.png</normaloff>icons:brush-5.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoExclusive">
<bool>true</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="toolFill">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>icons:brush-6.png</normaloff>icons:brush-6.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoExclusive">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="toolSelect">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -739,10 +810,16 @@
</property>
<property name="icon">
<iconset>
<normaloff>icons:edit-clear.png</normaloff>icons:edit-clear.png</iconset>
<normaloff>icons:brush-0.png</normaloff>icons:brush-0.png</iconset>
</property>
<property name="checkable">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="autoExclusive">
<bool>true</bool>
</property>
<property name="flat">
<bool>false</bool>
@ -750,7 +827,6 @@
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
@ -762,6 +838,9 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="features">
<set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
</property>
<property name="windowTitle">
<string>Painting</string>
</property>
@ -804,8 +883,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>128</width>
<height>192</height>
<width>256</width>
<height>120</height>
</rect>
</property>
<property name="sizePolicy">
@ -847,8 +926,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>128</width>
<height>192</height>
<width>256</width>
<height>120</height>
</rect>
</property>
<property name="sizePolicy">
@ -883,8 +962,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>128</width>
<height>192</height>
<width>256</width>
<height>120</height>
</rect>
</property>
<property name="sizePolicy">
@ -920,11 +999,8 @@
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_5">
<property name="maximumSize">
<size>
<width>524287</width>
<height>150</height>
</size>
<property name="features">
<set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
</property>
<property name="windowTitle">
<string>Preview</string>
@ -954,12 +1030,6 @@
<height>128</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>128</width>
<height>128</height>
</size>
</property>
</widget>
</item>
</layout>
@ -1341,6 +1411,72 @@
<string>h3m converter</string>
</property>
</action>
<action name="actionLock">
<property name="icon">
<iconset>
<normaloff>icons:lock-closed.png</normaloff>icons:lock-closed.png</iconset>
</property>
<property name="text">
<string>Lock</string>
</property>
<property name="toolTip">
<string>Lock objects on map to avoid unnecessary changes</string>
</property>
<property name="shortcut">
<string>Ctrl+L</string>
</property>
</action>
<action name="actionUnlock">
<property name="icon">
<iconset>
<normaloff>icons:lock-open.png</normaloff>icons:lock-open.png</iconset>
</property>
<property name="text">
<string>Unlock</string>
</property>
<property name="toolTip">
<string>Unlock all objects on the map</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+L</string>
</property>
</action>
<action name="actionZoom_in">
<property name="icon">
<iconset>
<normaloff>icons:zoom_plus.png</normaloff>icons:zoom_plus.png</iconset>
</property>
<property name="text">
<string>Zoom in</string>
</property>
<property name="shortcut">
<string>Ctrl+=</string>
</property>
</action>
<action name="actionZoom_out">
<property name="icon">
<iconset>
<normaloff>icons:zoom_minus.png</normaloff>icons:zoom_minus.png</iconset>
</property>
<property name="text">
<string>Zoom out</string>
</property>
<property name="shortcut">
<string>Ctrl+-</string>
</property>
</action>
<action name="actionZoom_reset">
<property name="icon">
<iconset>
<normaloff>icons:zoom_zero.png</normaloff>icons:zoom_zero.png</iconset>
</property>
<property name="text">
<string>Zoom reset</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+=</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View File

@ -322,8 +322,11 @@ std::vector<TileObject> & MapHandler::getObjects(int x, int y, int z)
return ttiles[index(x, y, z)];
}
void MapHandler::drawObjects(QPainter & painter, int x, int y, int z)
void MapHandler::drawObjects(QPainter & painter, int x, int y, int z, const std::set<const CGObjectInstance *> & locked)
{
painter.setRenderHint(QPainter::Antialiasing, false);
painter.setRenderHint(QPainter::SmoothPixmapTransform, false);
for(auto & object : getObjects(x, y, z))
{
const CGObjectInstance * obj = object.obj;
@ -343,7 +346,14 @@ void MapHandler::drawObjects(QPainter & painter, int x, int y, int z)
{
auto pos = obj->getPosition();
painter.drawImage(QPoint(x * tileSize, y * tileSize), *objData.objBitmap, object.rect);
painter.drawImage(QPoint(x * tileSize, y * tileSize), *objData.objBitmap, object.rect, Qt::AutoColor | Qt::NoOpaqueDetection);
if(locked.count(obj))
{
painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
painter.fillRect(x * tileSize, y * tileSize, object.rect.width(), object.rect.height(), Qt::Dense4Pattern);
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
}
if(objData.flagBitmap)
{

View File

@ -89,6 +89,8 @@ private:
void initTerrainGraphics();
QRgb getTileColor(int x, int y, int z);
QPolygon lockBitMask;
public:
MapHandler();
~MapHandler() = default;
@ -110,7 +112,7 @@ public:
std::vector<int3> getTilesUnderObject(CGObjectInstance *) const;
/// draws all objects on current tile (higher-level logic, unlike other draw*** methods)
void drawObjects(QPainter & painter, int x, int y, int z);
void drawObjects(QPainter & painter, int x, int y, int z, const std::set<const CGObjectInstance *> & locked);
void drawObject(QPainter & painter, const TileObject & object);
void drawObjectAt(QPainter & painter, const CGObjectInstance * object, int x, int y);
std::vector<TileObject> & getObjects(int x, int y, int z);

View File

@ -44,15 +44,9 @@ void MinimapView::mouseMoveEvent(QMouseEvent *mouseEvent)
if(!sc)
return;
int w = sc->viewport.viewportWidth();
int h = sc->viewport.viewportHeight();
auto pos = mapToScene(mouseEvent->pos());
pos.setX(pos.x() - w / 2);
pos.setY(pos.y() - h / 2);
QPointF point = pos * 32;
emit cameraPositionChanged(point);
pos *= 32;
emit cameraPositionChanged(pos);
}
void MinimapView::mousePressEvent(QMouseEvent* event)
@ -68,8 +62,7 @@ MapView::MapView(QWidget * parent):
void MapView::cameraChanged(const QPointF & pos)
{
horizontalScrollBar()->setValue(pos.x());
verticalScrollBar()->setValue(pos.y());
centerOn(pos);
}
void MapView::setController(MapController * ctrl)
@ -158,6 +151,60 @@ void MapView::mouseMoveEvent(QMouseEvent *mouseEvent)
sc->selectionTerrainView.draw();
break;
case MapView::SelectionTool::Line:
{
assert(tile.z == tileStart.z);
const auto diff = tile - tileStart;
if(diff == int3{})
break;
const int edge = std::max(abs(diff.x), abs(diff.y));
int distMin = std::numeric_limits<int>::max();
int3 dir;
for(auto & d : int3::getDirs())
{
if(tile.dist2d(d * edge + tileStart) < distMin)
{
distMin = tile.dist2d(d * edge + tileStart);
dir = d;
}
}
assert(dir != int3{});
if(mouseEvent->buttons() == Qt::LeftButton)
{
for(auto & ts : temporaryTiles)
sc->selectionTerrainView.erase(ts);
for(auto ts = tileStart; ts.dist2d(tileStart) < edge; ts += dir)
{
if(!controller->map()->isInTheMap(ts))
break;
if(!sc->selectionTerrainView.selection().count(ts))
temporaryTiles.insert(ts);
sc->selectionTerrainView.select(ts);
}
}
if(mouseEvent->buttons() == Qt::RightButton)
{
for(auto & ts : temporaryTiles)
sc->selectionTerrainView.select(ts);
for(auto ts = tileStart; ts.dist2d(tileStart) < edge; ts += dir)
{
if(!controller->map()->isInTheMap(ts))
break;
if(sc->selectionTerrainView.selection().count(ts))
temporaryTiles.insert(ts);
sc->selectionTerrainView.erase(ts);
}
}
sc->selectionTerrainView.draw();
break;
}
case MapView::SelectionTool::Lasso:
if(mouseEvent->buttons() == Qt::LeftButton)
{
@ -212,6 +259,7 @@ void MapView::mousePressEvent(QMouseEvent *event)
switch(selectionTool)
{
case MapView::SelectionTool::Brush:
case MapView::SelectionTool::Line:
sc->selectionObjectsView.clear();
sc->selectionObjectsView.draw();
@ -270,6 +318,55 @@ void MapView::mousePressEvent(QMouseEvent *event)
sc->selectionObjectsView.draw();
break;
case MapView::SelectionTool::Fill:
{
if(event->button() != Qt::RightButton && event->button() != Qt::LeftButton)
break;
std::vector<int3> queue;
queue.push_back(tileStart);
const std::array<int3, 4> dirs{ int3{1, 0, 0}, int3{-1, 0, 0}, int3{0, 1, 0}, int3{0, -1, 0} };
while(!queue.empty())
{
auto tile = queue.back();
queue.pop_back();
if(event->button() == Qt::LeftButton)
sc->selectionTerrainView.select(tile);
else
sc->selectionTerrainView.erase(tile);
for(auto & d : dirs)
{
auto tilen = tile + d;
if(!controller->map()->isInTheMap(tilen))
continue;
if(event->button() == Qt::LeftButton)
{
if(controller->map()->getTile(tile).roadType
&& controller->map()->getTile(tile).roadType != controller->map()->getTile(tilen).roadType)
continue;
else if(controller->map()->getTile(tile).riverType
&& controller->map()->getTile(tile).riverType != controller->map()->getTile(tilen).riverType)
continue;
else if(controller->map()->getTile(tile).terType != controller->map()->getTile(tilen).terType)
continue;
}
if(event->button() == Qt::LeftButton && sc->selectionTerrainView.selection().count(tilen))
continue;
if(event->button() == Qt::RightButton && !sc->selectionTerrainView.selection().count(tilen))
continue;
queue.push_back(tilen);
}
}
sc->selectionTerrainView.draw();
sc->selectionObjectsView.clear();
sc->selectionObjectsView.draw();
break;
}
case MapView::SelectionTool::None:
sc->selectionTerrainView.clear();
sc->selectionTerrainView.draw();
@ -408,6 +505,10 @@ void MapView::mouseReleaseEvent(QMouseEvent *event)
break;
}
case MapView::SelectionTool::Line:
temporaryTiles.clear();
break;
case MapView::SelectionTool::None:
if(event->button() == Qt::RightButton)
break;

View File

@ -89,7 +89,7 @@ class MapView : public QGraphicsView
public:
enum class SelectionTool
{
None, Brush, Brush2, Brush4, Area, Lasso
None, Brush, Brush2, Brush4, Area, Lasso, Line, Fill
};
public:
@ -124,6 +124,8 @@ private:
int3 tileStart;
int3 tilePrev;
bool pressedOnSelected;
std::set<int3> temporaryTiles;
};
class MinimapView : public QGraphicsView

View File

@ -77,7 +77,11 @@ bool ObjectBrowserProxyModel::filterAcceptsRowText(int source_row, const QModelI
if(!item)
return false;
return (filter.isNull() || filter.isEmpty() || item->text().contains(filter, Qt::CaseInsensitive));
auto data = item->data().toJsonObject();
return (filter.isNull() || filter.isEmpty()
|| item->text().contains(filter, Qt::CaseInsensitive)
|| data["typeName"].toString().contains(filter, Qt::CaseInsensitive));
}
Qt::ItemFlags ObjectBrowserProxyModel::flags(const QModelIndex & index) const

View File

@ -377,7 +377,6 @@ void ObjectsLayer::draw(bool onlyDirty)
return;
QPainter painter(pixmap.get());
std::set<const CGObjectInstance *> drawen;
if(onlyDirty)
{
@ -392,7 +391,7 @@ void ObjectsLayer::draw(bool onlyDirty)
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
for(auto & p : dirty)
handler->drawObjects(painter, p.x, p.y, p.z);
handler->drawObjects(painter, p.x, p.y, p.z, lockedObjects);
}
else
{
@ -401,7 +400,7 @@ void ObjectsLayer::draw(bool onlyDirty)
{
for(int i = 0; i < map->width; ++i)
{
handler->drawObjects(painter, i, j, scene->level);
handler->drawObjects(painter, i, j, scene->level, lockedObjects);
}
}
}
@ -430,6 +429,19 @@ void ObjectsLayer::setDirty(const CGObjectInstance * object)
}
}
void ObjectsLayer::setLockObject(const CGObjectInstance * object, bool lock)
{
if(lock)
lockedObjects.insert(object);
else
lockedObjects.erase(object);
}
void ObjectsLayer::unlockAll()
{
lockedObjects.clear();
}
SelectionObjectsLayer::SelectionObjectsLayer(MapSceneBase * s): AbstractLayer(s), newObject(nullptr)
{
}
@ -501,7 +513,7 @@ CGObjectInstance * SelectionObjectsLayer::selectObjectAt(int x, int y, const CGO
//visitable is most important
for(auto & object : objects)
{
if(!object.obj || object.obj == ignore)
if(!object.obj || object.obj == ignore || lockedObjects.count(object.obj))
continue;
if(object.obj->visitableAt(x, y))
@ -513,7 +525,7 @@ CGObjectInstance * SelectionObjectsLayer::selectObjectAt(int x, int y, const CGO
//if not visitable tile - try to get blocked
for(auto & object : objects)
{
if(!object.obj || object.obj == ignore)
if(!object.obj || object.obj == ignore || lockedObjects.count(object.obj))
continue;
if(object.obj->blockingAt(x, y))
@ -525,7 +537,7 @@ CGObjectInstance * SelectionObjectsLayer::selectObjectAt(int x, int y, const CGO
//finally, we can take any object
for(auto & object : objects)
{
if(!object.obj || object.obj == ignore)
if(!object.obj || object.obj == ignore || lockedObjects.count(object.obj))
continue;
if(object.obj->coveringAt(x, y))
@ -555,6 +567,7 @@ void SelectionObjectsLayer::selectObjects(int x1, int y1, int x2, int y2)
if(map->isInTheMap(int3(i, j, scene->level)))
{
for(auto & o : handler->getObjects(i, j, scene->level))
if(!lockedObjects.count(o.obj))
selectObject(o.obj, false); //do not inform about each object added
}
}
@ -599,6 +612,19 @@ void SelectionObjectsLayer::onSelection()
emit selectionMade(!selectedObjects.empty());
}
void SelectionObjectsLayer::setLockObject(const CGObjectInstance * object, bool lock)
{
if(lock)
lockedObjects.insert(object);
else
lockedObjects.erase(object);
}
void SelectionObjectsLayer::unlockAll()
{
lockedObjects.clear();
}
MinimapLayer::MinimapLayer(MapSceneBase * s): AbstractLayer(s)
{

View File

@ -121,8 +121,12 @@ public:
void setDirty(int x, int y);
void setDirty(const CGObjectInstance * object);
void setLockObject(const CGObjectInstance * object, bool lock);
void unlockAll();
private:
std::set<const CGObjectInstance *> objDirty;
std::set<const CGObjectInstance *> lockedObjects;
std::set<int3> dirty;
};
@ -181,6 +185,9 @@ public:
std::set<CGObjectInstance*> getSelection() const;
void clear();
void setLockObject(const CGObjectInstance * object, bool lock);
void unlockAll();
QPoint shift;
CGObjectInstance * newObject;
//FIXME: magic number
@ -191,6 +198,7 @@ signals:
private:
std::set<CGObjectInstance *> selectedObjects;
std::set<const CGObjectInstance *> lockedObjects;
void onSelection();
};