commit
669d4d3d7e
@ -0,0 +1,542 @@
|
|||||||
|
#include "terraintexturemode.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QDropEvent>
|
||||||
|
#include <QDragEnterEvent>
|
||||||
|
#include <QDrag>
|
||||||
|
|
||||||
|
#include <components/esm/loadland.hpp>
|
||||||
|
|
||||||
|
#include "../widget/modebutton.hpp"
|
||||||
|
#include "../widget/scenetoolbar.hpp"
|
||||||
|
#include "../widget/scenetooltexturebrush.hpp"
|
||||||
|
|
||||||
|
#include "../../model/doc/document.hpp"
|
||||||
|
#include "../../model/prefs/state.hpp"
|
||||||
|
#include "../../model/world/columnbase.hpp"
|
||||||
|
#include "../../model/world/commandmacro.hpp"
|
||||||
|
#include "../../model/world/commands.hpp"
|
||||||
|
#include "../../model/world/data.hpp"
|
||||||
|
#include "../../model/world/idtable.hpp"
|
||||||
|
#include "../../model/world/idtree.hpp"
|
||||||
|
#include "../../model/world/land.hpp"
|
||||||
|
#include "../../model/world/landtexture.hpp"
|
||||||
|
#include "../../model/world/resourcetable.hpp"
|
||||||
|
#include "../../model/world/tablemimedata.hpp"
|
||||||
|
#include "../../model/world/universalid.hpp"
|
||||||
|
|
||||||
|
#include "editmode.hpp"
|
||||||
|
#include "pagedworldspacewidget.hpp"
|
||||||
|
#include "mask.hpp"
|
||||||
|
#include "object.hpp" // Something small needed regarding pointers from here ()
|
||||||
|
#include "worldspacewidget.hpp"
|
||||||
|
|
||||||
|
CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, QWidget *parent)
|
||||||
|
: EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, Mask_Terrain | Mask_Reference, "Terrain texture editing", parent),
|
||||||
|
mBrushTexture("L0#0"),
|
||||||
|
mBrushSize(0),
|
||||||
|
mBrushShape(0),
|
||||||
|
mTextureBrushScenetool(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::TerrainTextureMode::activate(CSVWidget::SceneToolbar* toolbar)
|
||||||
|
{
|
||||||
|
if(!mTextureBrushScenetool)
|
||||||
|
{
|
||||||
|
mTextureBrushScenetool = new CSVWidget::SceneToolTextureBrush (toolbar, "scenetooltexturebrush", getWorldspaceWidget().getDocument());
|
||||||
|
connect(mTextureBrushScenetool, SIGNAL (clicked()), mTextureBrushScenetool, SLOT (activate()));
|
||||||
|
connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passBrushSize(int)), this, SLOT(setBrushSize(int)));
|
||||||
|
connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passBrushShape(int)), this, SLOT(setBrushShape(int)));
|
||||||
|
connect(mTextureBrushScenetool->mTextureBrushWindow->mSizeSliders->mBrushSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(setBrushSize(int)));
|
||||||
|
connect(mTextureBrushScenetool, SIGNAL(passTextureId(std::string)), this, SLOT(setBrushTexture(std::string)));
|
||||||
|
connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passTextureId(std::string)), this, SLOT(setBrushTexture(std::string)));
|
||||||
|
|
||||||
|
connect(mTextureBrushScenetool, SIGNAL(passEvent(QDropEvent*)), this, SLOT(handleDropEvent(QDropEvent*)));
|
||||||
|
connect(this, SIGNAL(passBrushTexture(std::string)), mTextureBrushScenetool->mTextureBrushWindow, SLOT(setBrushTexture(std::string)));
|
||||||
|
connect(this, SIGNAL(passBrushTexture(std::string)), mTextureBrushScenetool, SLOT(updateBrushHistory(std::string)));
|
||||||
|
}
|
||||||
|
|
||||||
|
EditMode::activate(toolbar);
|
||||||
|
toolbar->addTool (mTextureBrushScenetool);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::TerrainTextureMode::deactivate(CSVWidget::SceneToolbar* toolbar)
|
||||||
|
{
|
||||||
|
if(mTextureBrushScenetool)
|
||||||
|
{
|
||||||
|
toolbar->removeTool (mTextureBrushScenetool);
|
||||||
|
delete mTextureBrushScenetool;
|
||||||
|
mTextureBrushScenetool = 0;
|
||||||
|
}
|
||||||
|
EditMode::deactivate(toolbar);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult& hit) // Apply changes here
|
||||||
|
{
|
||||||
|
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
|
||||||
|
CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||||
|
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Land));
|
||||||
|
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||||
|
*document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures));
|
||||||
|
|
||||||
|
mCellId = getWorldspaceWidget().getCellId (hit.worldPos);
|
||||||
|
|
||||||
|
QUndoStack& undoStack = document.getUndoStack();
|
||||||
|
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures();
|
||||||
|
int index = landtexturesCollection.searchId(mBrushTexture);
|
||||||
|
|
||||||
|
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit == true)
|
||||||
|
{
|
||||||
|
undoStack.beginMacro ("Edit texture records");
|
||||||
|
if(allowLandTextureEditing(mCellId)==true)
|
||||||
|
{
|
||||||
|
undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId));
|
||||||
|
editTerrainTextureGrid(hit);
|
||||||
|
}
|
||||||
|
undoStack.endMacro();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::TerrainTextureMode::primarySelectPressed(const WorldspaceHitResult& hit)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::TerrainTextureMode::secondarySelectPressed(const WorldspaceHitResult& hit)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSVRender::TerrainTextureMode::primaryEditStartDrag (const QPoint& pos)
|
||||||
|
{
|
||||||
|
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||||
|
|
||||||
|
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
|
||||||
|
CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||||
|
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Land));
|
||||||
|
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||||
|
*document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures));
|
||||||
|
|
||||||
|
mCellId = getWorldspaceWidget().getCellId (hit.worldPos);
|
||||||
|
|
||||||
|
QUndoStack& undoStack = document.getUndoStack();
|
||||||
|
|
||||||
|
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures();
|
||||||
|
int index = landtexturesCollection.searchId(mBrushTexture);
|
||||||
|
|
||||||
|
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
|
||||||
|
{
|
||||||
|
undoStack.beginMacro ("Edit texture records");
|
||||||
|
if(allowLandTextureEditing(mCellId)==true && hit.hit == true)
|
||||||
|
{
|
||||||
|
undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId));
|
||||||
|
editTerrainTextureGrid(hit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSVRender::TerrainTextureMode::secondaryEditStartDrag (const QPoint& pos)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSVRender::TerrainTextureMode::primarySelectStartDrag (const QPoint& pos)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSVRender::TerrainTextureMode::secondarySelectStartDrag (const QPoint& pos)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::TerrainTextureMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor)
|
||||||
|
{
|
||||||
|
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||||
|
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
|
||||||
|
|
||||||
|
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures();
|
||||||
|
int index = landtexturesCollection.searchId(mBrushTexture);
|
||||||
|
|
||||||
|
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit == true)
|
||||||
|
{
|
||||||
|
editTerrainTextureGrid(hit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::TerrainTextureMode::dragCompleted(const QPoint& pos) {
|
||||||
|
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
|
||||||
|
QUndoStack& undoStack = document.getUndoStack();
|
||||||
|
|
||||||
|
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures();
|
||||||
|
int index = landtexturesCollection.searchId(mBrushTexture);
|
||||||
|
|
||||||
|
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
|
||||||
|
{
|
||||||
|
undoStack.endMacro();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::TerrainTextureMode::dragAborted() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::TerrainTextureMode::dragWheel (int diff, double speedFactor) {}
|
||||||
|
|
||||||
|
void CSVRender::TerrainTextureMode::handleDropEvent (QDropEvent *event) {
|
||||||
|
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
|
||||||
|
|
||||||
|
if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mime->holdsType (CSMWorld::UniversalId::Type_LandTexture))
|
||||||
|
{
|
||||||
|
const std::vector<CSMWorld::UniversalId> ids = mime->getData();
|
||||||
|
|
||||||
|
for (const CSMWorld::UniversalId& uid : ids)
|
||||||
|
{
|
||||||
|
mBrushTexture = uid.getId();
|
||||||
|
emit passBrushTexture(mBrushTexture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mime->holdsType (CSMWorld::UniversalId::Type_Texture))
|
||||||
|
{
|
||||||
|
const std::vector<CSMWorld::UniversalId> ids = mime->getData();
|
||||||
|
|
||||||
|
for (const CSMWorld::UniversalId& uid : ids)
|
||||||
|
{
|
||||||
|
std::string textureFileName = uid.toString();
|
||||||
|
createTexture(textureFileName);
|
||||||
|
emit passBrushTexture(mBrushTexture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitResult& hit)
|
||||||
|
{
|
||||||
|
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
|
||||||
|
CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||||
|
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Land));
|
||||||
|
|
||||||
|
mCellId = getWorldspaceWidget().getCellId (hit.worldPos);
|
||||||
|
if(allowLandTextureEditing(mCellId)==true) {}
|
||||||
|
|
||||||
|
std::pair<CSMWorld::CellCoordinates, bool> cellCoordinates_pair = CSMWorld::CellCoordinates::fromId (mCellId);
|
||||||
|
|
||||||
|
int cellX = cellCoordinates_pair.first.getX();
|
||||||
|
int cellY = cellCoordinates_pair.first.getY();
|
||||||
|
|
||||||
|
// The coordinates of hit in mCellId
|
||||||
|
int xHitInCell (float(((hit.worldPos.x() - (cellX* cellSize)) * landTextureSize / cellSize) - 0.5));
|
||||||
|
int yHitInCell (float(((hit.worldPos.y() - (cellY* cellSize)) * landTextureSize / cellSize) + 0.5));
|
||||||
|
if (xHitInCell < 0)
|
||||||
|
{
|
||||||
|
xHitInCell = xHitInCell + landTextureSize;
|
||||||
|
cellX = cellX - 1;
|
||||||
|
}
|
||||||
|
if (yHitInCell > 15)
|
||||||
|
{
|
||||||
|
yHitInCell = yHitInCell - landTextureSize;
|
||||||
|
cellY = cellY + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCellId = "#" + std::to_string(cellX) + " " + std::to_string(cellY);
|
||||||
|
if(allowLandTextureEditing(mCellId)==true) {}
|
||||||
|
|
||||||
|
std::string iteratedCellId;
|
||||||
|
|
||||||
|
int textureColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandTexturesIndex);
|
||||||
|
|
||||||
|
std::size_t hashlocation = mBrushTexture.find("#");
|
||||||
|
std::string mBrushTextureInt = mBrushTexture.substr (hashlocation+1);
|
||||||
|
int brushInt = stoi(mBrushTexture.substr (hashlocation+1))+1; // All indices are offset by +1
|
||||||
|
|
||||||
|
float rf = mBrushSize/2;
|
||||||
|
int r = (mBrushSize/2)+1;
|
||||||
|
float distance = 0;
|
||||||
|
|
||||||
|
if (mBrushShape == 0)
|
||||||
|
{
|
||||||
|
CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>();
|
||||||
|
CSMWorld::LandTexturesColumn::DataType mNew(mPointer);
|
||||||
|
|
||||||
|
if(allowLandTextureEditing(mCellId)==true)
|
||||||
|
{
|
||||||
|
mNew[yHitInCell*landTextureSize+xHitInCell] = brushInt;
|
||||||
|
pushEditToCommand(mNew, document, landTable, mCellId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBrushShape == 1)
|
||||||
|
{
|
||||||
|
int upperLeftCellX = cellX - std::floor(r / landTextureSize);
|
||||||
|
int upperLeftCellY = cellY - std::floor(r / landTextureSize);
|
||||||
|
if (xHitInCell - (r % landTextureSize) < 0) upperLeftCellX--;
|
||||||
|
if (yHitInCell - (r % landTextureSize) < 0) upperLeftCellY--;
|
||||||
|
|
||||||
|
int lowerrightCellX = cellX + std::floor(r / landTextureSize);
|
||||||
|
int lowerrightCellY = cellY + std::floor(r / landTextureSize);
|
||||||
|
if (xHitInCell + (r % landTextureSize) > landTextureSize - 1) lowerrightCellX++;
|
||||||
|
if (yHitInCell + (r % landTextureSize) > landTextureSize - 1) lowerrightCellY++;
|
||||||
|
|
||||||
|
for(int i_cell = upperLeftCellX; i_cell <= lowerrightCellX; i_cell++)
|
||||||
|
{
|
||||||
|
for(int j_cell = upperLeftCellY; j_cell <= lowerrightCellY; j_cell++)
|
||||||
|
{
|
||||||
|
iteratedCellId = "#" + std::to_string(i_cell) + " " + std::to_string(j_cell);
|
||||||
|
if(allowLandTextureEditing(iteratedCellId)==true)
|
||||||
|
{
|
||||||
|
CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>();
|
||||||
|
CSMWorld::LandTexturesColumn::DataType mNew(mPointer);
|
||||||
|
for(int i = 0; i < landTextureSize; i++)
|
||||||
|
{
|
||||||
|
for(int j = 0; j < landTextureSize; j++)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (i_cell == cellX && j_cell == cellY && abs(i-xHitInCell) < r && abs(j-yHitInCell) < r)
|
||||||
|
{
|
||||||
|
mNew[j*landTextureSize+i] = brushInt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int distanceX(0);
|
||||||
|
int distanceY(0);
|
||||||
|
if (i_cell < cellX) distanceX = xHitInCell + landTextureSize * abs(i_cell-cellX) - i;
|
||||||
|
if (j_cell < cellY) distanceY = yHitInCell + landTextureSize * abs(j_cell-cellY) - j;
|
||||||
|
if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize * abs(i_cell-cellX) + i;
|
||||||
|
if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j;
|
||||||
|
if (i_cell == cellX) distanceX = abs(i-xHitInCell);
|
||||||
|
if (j_cell == cellY) distanceY = abs(j-yHitInCell);
|
||||||
|
if (distanceX < r && distanceY < r) mNew[j*landTextureSize+i] = brushInt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pushEditToCommand(mNew, document, landTable, iteratedCellId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBrushShape == 2)
|
||||||
|
{
|
||||||
|
int upperLeftCellX = cellX - std::floor(r / landTextureSize);
|
||||||
|
int upperLeftCellY = cellY - std::floor(r / landTextureSize);
|
||||||
|
if (xHitInCell - (r % landTextureSize) < 0) upperLeftCellX--;
|
||||||
|
if (yHitInCell - (r % landTextureSize) < 0) upperLeftCellY--;
|
||||||
|
|
||||||
|
int lowerrightCellX = cellX + std::floor(r / landTextureSize);
|
||||||
|
int lowerrightCellY = cellY + std::floor(r / landTextureSize);
|
||||||
|
if (xHitInCell + (r % landTextureSize) > landTextureSize - 1) lowerrightCellX++;
|
||||||
|
if (yHitInCell + (r % landTextureSize) > landTextureSize - 1) lowerrightCellY++;
|
||||||
|
|
||||||
|
for(int i_cell = upperLeftCellX; i_cell <= lowerrightCellX; i_cell++)
|
||||||
|
{
|
||||||
|
for(int j_cell = upperLeftCellY; j_cell <= lowerrightCellY; j_cell++)
|
||||||
|
{
|
||||||
|
iteratedCellId = "#" + std::to_string(i_cell) + " " + std::to_string(j_cell);
|
||||||
|
if(allowLandTextureEditing(iteratedCellId)==true)
|
||||||
|
{
|
||||||
|
CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>();
|
||||||
|
CSMWorld::LandTexturesColumn::DataType mNew(mPointer);
|
||||||
|
for(int i = 0; i < landTextureSize; i++)
|
||||||
|
{
|
||||||
|
for(int j = 0; j < landTextureSize; j++)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (i_cell == cellX && j_cell == cellY && abs(i-xHitInCell) < r && abs(j-yHitInCell) < r)
|
||||||
|
{
|
||||||
|
int distanceX(0);
|
||||||
|
int distanceY(0);
|
||||||
|
if (i_cell < cellX) distanceX = xHitInCell + landTextureSize * abs(i_cell-cellX) - i;
|
||||||
|
if (j_cell < cellY) distanceY = yHitInCell + landTextureSize * abs(j_cell-cellY) - j;
|
||||||
|
if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize* abs(i_cell-cellX) + i;
|
||||||
|
if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j;
|
||||||
|
if (i_cell == cellX) distanceX = abs(i-xHitInCell);
|
||||||
|
if (j_cell == cellY) distanceY = abs(j-yHitInCell);
|
||||||
|
distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2)));
|
||||||
|
if (distance < rf) mNew[j*landTextureSize+i] = brushInt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int distanceX(0);
|
||||||
|
int distanceY(0);
|
||||||
|
if (i_cell < cellX) distanceX = xHitInCell + landTextureSize * abs(i_cell-cellX) - i;
|
||||||
|
if (j_cell < cellY) distanceY = yHitInCell + landTextureSize * abs(j_cell-cellY) - j;
|
||||||
|
if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize * abs(i_cell-cellX) + i;
|
||||||
|
if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j;
|
||||||
|
if (i_cell == cellX) distanceX = abs(i-xHitInCell);
|
||||||
|
if (j_cell == cellY) distanceY = abs(j-yHitInCell);
|
||||||
|
distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2)));
|
||||||
|
if (distance < rf) mNew[j*landTextureSize+i] = brushInt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pushEditToCommand(mNew, document, landTable, iteratedCellId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBrushShape == 3)
|
||||||
|
{
|
||||||
|
// Not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::TerrainTextureMode::pushEditToCommand(CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document,
|
||||||
|
CSMWorld::IdTable& landTable, std::string cellId)
|
||||||
|
{
|
||||||
|
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||||
|
*document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures));
|
||||||
|
|
||||||
|
QVariant changedLand;
|
||||||
|
changedLand.setValue(newLandGrid);
|
||||||
|
|
||||||
|
QModelIndex index(landTable.getModelIndex (cellId, landTable.findColumnIndex (CSMWorld::Columns::ColumnId_LandTexturesIndex)));
|
||||||
|
|
||||||
|
QUndoStack& undoStack = document.getUndoStack();
|
||||||
|
undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, cellId));
|
||||||
|
undoStack.push (new CSMWorld::ModifyCommand(landTable, index, changedLand));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::TerrainTextureMode::createTexture(std::string textureFileName)
|
||||||
|
{
|
||||||
|
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
|
||||||
|
|
||||||
|
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||||
|
*document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures));
|
||||||
|
|
||||||
|
QUndoStack& undoStack = document.getUndoStack();
|
||||||
|
|
||||||
|
std::string newId;
|
||||||
|
|
||||||
|
int counter=0;
|
||||||
|
bool freeIndexFound = false;
|
||||||
|
do {
|
||||||
|
const size_t maxCounter = std::numeric_limits<uint16_t>::max() - 1;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
|
||||||
|
if (ltexTable.getRecord(newId).isDeleted() == 0) counter = (counter + 1) % maxCounter;
|
||||||
|
} catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
|
||||||
|
freeIndexFound = true;
|
||||||
|
}
|
||||||
|
} while (freeIndexFound == false);
|
||||||
|
|
||||||
|
std::size_t idlocation = textureFileName.find("Texture: ");
|
||||||
|
textureFileName = textureFileName.substr (idlocation + 9);
|
||||||
|
|
||||||
|
QVariant textureNameVariant;
|
||||||
|
|
||||||
|
QVariant textureFileNameVariant;
|
||||||
|
textureFileNameVariant.setValue(QString::fromStdString(textureFileName));
|
||||||
|
|
||||||
|
undoStack.beginMacro ("Add land texture record");
|
||||||
|
|
||||||
|
undoStack.push (new CSMWorld::CreateCommand (ltexTable, newId));
|
||||||
|
QModelIndex index(ltexTable.getModelIndex (newId, ltexTable.findColumnIndex (CSMWorld::Columns::ColumnId_Texture)));
|
||||||
|
undoStack.push (new CSMWorld::ModifyCommand(ltexTable, index, textureFileNameVariant));
|
||||||
|
undoStack.endMacro();
|
||||||
|
mBrushTexture = newId;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSVRender::TerrainTextureMode::allowLandTextureEditing(std::string cellId)
|
||||||
|
{
|
||||||
|
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
|
||||||
|
CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||||
|
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Land));
|
||||||
|
CSMWorld::IdTree& cellTable = dynamic_cast<CSMWorld::IdTree&> (
|
||||||
|
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells));
|
||||||
|
|
||||||
|
bool noCell = document.getData().getCells().searchId (cellId)==-1;
|
||||||
|
bool noLand = document.getData().getLand().searchId (cellId)==-1;
|
||||||
|
|
||||||
|
if (noCell)
|
||||||
|
{
|
||||||
|
std::string mode = CSMPrefs::get()["3D Scene Editing"]["outside-landedit"].toString();
|
||||||
|
|
||||||
|
// target cell does not exist
|
||||||
|
if (mode=="Discard")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (mode=="Create cell and land, then edit")
|
||||||
|
{
|
||||||
|
std::unique_ptr<CSMWorld::CreateCommand> createCommand (
|
||||||
|
new CSMWorld::CreateCommand (cellTable, cellId));
|
||||||
|
int parentIndex = cellTable.findColumnIndex (CSMWorld::Columns::ColumnId_Cell);
|
||||||
|
int index = cellTable.findNestedColumnIndex (parentIndex, CSMWorld::Columns::ColumnId_Interior);
|
||||||
|
createCommand->addNestedValue (parentIndex, index, false);
|
||||||
|
document.getUndoStack().push (createCommand.release());
|
||||||
|
|
||||||
|
if (CSVRender::PagedWorldspaceWidget *paged =
|
||||||
|
dynamic_cast<CSVRender::PagedWorldspaceWidget *> (&getWorldspaceWidget()))
|
||||||
|
{
|
||||||
|
CSMWorld::CellSelection selection = paged->getCellSelection();
|
||||||
|
selection.add (CSMWorld::CellCoordinates::fromId (cellId).first);
|
||||||
|
paged->setCellSelection (selection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (CSVRender::PagedWorldspaceWidget *paged =
|
||||||
|
dynamic_cast<CSVRender::PagedWorldspaceWidget *> (&getWorldspaceWidget()))
|
||||||
|
{
|
||||||
|
CSMWorld::CellSelection selection = paged->getCellSelection();
|
||||||
|
if (!selection.has (CSMWorld::CellCoordinates::fromId (cellId).first))
|
||||||
|
{
|
||||||
|
// target cell exists, but is not shown
|
||||||
|
std::string mode =
|
||||||
|
CSMPrefs::get()["3D Scene Editing"]["outside-visible-landedit"].toString();
|
||||||
|
|
||||||
|
if (mode=="Discard")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (mode=="Show cell and edit")
|
||||||
|
{
|
||||||
|
selection.add (CSMWorld::CellCoordinates::fromId (cellId).first);
|
||||||
|
paged->setCellSelection (selection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noLand)
|
||||||
|
{
|
||||||
|
std::string mode = CSMPrefs::get()["3D Scene Editing"]["outside-landedit"].toString();
|
||||||
|
|
||||||
|
// target cell does not exist
|
||||||
|
if (mode=="Discard")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (mode=="Create cell and land, then edit")
|
||||||
|
{
|
||||||
|
document.getUndoStack().push (new CSMWorld::CreateCommand (landTable, cellId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::TerrainTextureMode::dragMoveEvent (QDragMoveEvent *event) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::TerrainTextureMode::setBrushSize(int brushSize)
|
||||||
|
{
|
||||||
|
mBrushSize = brushSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::TerrainTextureMode::setBrushShape(int brushShape)
|
||||||
|
{
|
||||||
|
mBrushShape = brushShape;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::TerrainTextureMode::setBrushTexture(std::string brushTexture)
|
||||||
|
{
|
||||||
|
mBrushTexture = brushTexture;
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
#ifndef CSV_RENDER_TERRAINTEXTUREMODE_H
|
||||||
|
#define CSV_RENDER_TERRAINTEXTUREMODE_H
|
||||||
|
|
||||||
|
#include "editmode.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QEvent>
|
||||||
|
|
||||||
|
#include "../../model/world/data.hpp"
|
||||||
|
#include "../../model/world/land.hpp"
|
||||||
|
|
||||||
|
#include "../../model/doc/document.hpp"
|
||||||
|
#include "../../model/world/commands.hpp"
|
||||||
|
#include "../../model/world/idtable.hpp"
|
||||||
|
#include "../../model/world/landtexture.hpp"
|
||||||
|
|
||||||
|
namespace CSVWidget
|
||||||
|
{
|
||||||
|
class SceneToolTextureBrush;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
|
||||||
|
class TerrainTextureMode : public EditMode
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// \brief Editmode for terrain texture grid
|
||||||
|
TerrainTextureMode(WorldspaceWidget*, QWidget* parent = nullptr);
|
||||||
|
|
||||||
|
/// \brief Create single command for one-click texture editing
|
||||||
|
void primaryEditPressed (const WorldspaceHitResult& hit);
|
||||||
|
|
||||||
|
/// \brief Open brush settings window
|
||||||
|
void primarySelectPressed(const WorldspaceHitResult&);
|
||||||
|
|
||||||
|
void secondarySelectPressed(const WorldspaceHitResult&);
|
||||||
|
|
||||||
|
void activate(CSVWidget::SceneToolbar*);
|
||||||
|
void deactivate(CSVWidget::SceneToolbar*);
|
||||||
|
|
||||||
|
/// \brief Start texture editing command macro
|
||||||
|
virtual bool primaryEditStartDrag (const QPoint& pos);
|
||||||
|
|
||||||
|
virtual bool secondaryEditStartDrag (const QPoint& pos);
|
||||||
|
virtual bool primarySelectStartDrag (const QPoint& pos);
|
||||||
|
virtual bool secondarySelectStartDrag (const QPoint& pos);
|
||||||
|
|
||||||
|
/// \brief Handle texture edit behavior during dragging
|
||||||
|
virtual void drag (const QPoint& pos, int diffX, int diffY, double speedFactor);
|
||||||
|
|
||||||
|
/// \brief End texture editing command macro
|
||||||
|
virtual void dragCompleted(const QPoint& pos);
|
||||||
|
|
||||||
|
virtual void dragAborted();
|
||||||
|
virtual void dragWheel (int diff, double speedFactor);
|
||||||
|
virtual void dragMoveEvent (QDragMoveEvent *event);
|
||||||
|
|
||||||
|
/// \brief Handle brush mechanics, maths regarding worldspace hit etc.
|
||||||
|
void editTerrainTextureGrid (const WorldspaceHitResult& hit);
|
||||||
|
|
||||||
|
/// \brief Push texture edits to command macro
|
||||||
|
void pushEditToCommand (CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document,
|
||||||
|
CSMWorld::IdTable& landTable, std::string cellId);
|
||||||
|
|
||||||
|
/// \brief Create new land texture record from texture asset
|
||||||
|
void createTexture(std::string textureFileName);
|
||||||
|
|
||||||
|
/// \brief Create new cell and land if needed
|
||||||
|
bool allowLandTextureEditing(std::string textureFileName);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mCellId;
|
||||||
|
std::string mBrushTexture;
|
||||||
|
int mBrushSize;
|
||||||
|
int mBrushShape;
|
||||||
|
CSVWidget::SceneToolTextureBrush *mTextureBrushScenetool;
|
||||||
|
|
||||||
|
const int cellSize {ESM::Land::REAL_SIZE};
|
||||||
|
const int landSize {ESM::Land::LAND_SIZE};
|
||||||
|
const int landTextureSize {ESM::Land::LAND_TEXTURE_SIZE};
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void passBrushTexture(std::string brushTexture);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void handleDropEvent(QDropEvent *event);
|
||||||
|
void setBrushSize(int brushSize);
|
||||||
|
void setBrushShape(int brushShape);
|
||||||
|
void setBrushTexture(std::string brushShape);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,379 @@
|
|||||||
|
#include "scenetooltexturebrush.hpp"
|
||||||
|
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QTableWidget>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QSlider>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QDropEvent>
|
||||||
|
#include <QButtonGroup>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QDragEnterEvent>
|
||||||
|
#include <QDrag>
|
||||||
|
#include <QTableWidget>
|
||||||
|
#include <QHeaderView>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QSizePolicy>
|
||||||
|
|
||||||
|
#include "scenetool.hpp"
|
||||||
|
|
||||||
|
#include "../../model/doc/document.hpp"
|
||||||
|
#include "../../model/prefs/state.hpp"
|
||||||
|
#include "../../model/world/commands.hpp"
|
||||||
|
#include "../../model/world/data.hpp"
|
||||||
|
#include "../../model/world/idcollection.hpp"
|
||||||
|
#include "../../model/world/idtable.hpp"
|
||||||
|
#include "../../model/world/landtexture.hpp"
|
||||||
|
#include "../../model/world/universalid.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
CSVWidget::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *parent)
|
||||||
|
: QGroupBox(title, parent)
|
||||||
|
{
|
||||||
|
mBrushSizeSlider = new QSlider(Qt::Horizontal);
|
||||||
|
mBrushSizeSlider->setTickPosition(QSlider::TicksBothSides);
|
||||||
|
mBrushSizeSlider->setTickInterval(10);
|
||||||
|
mBrushSizeSlider->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt());
|
||||||
|
mBrushSizeSlider->setSingleStep(1);
|
||||||
|
|
||||||
|
mBrushSizeSpinBox = new QSpinBox;
|
||||||
|
mBrushSizeSpinBox->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt());
|
||||||
|
mBrushSizeSpinBox->setSingleStep(1);
|
||||||
|
|
||||||
|
mLayoutSliderSize = new QHBoxLayout;
|
||||||
|
mLayoutSliderSize->addWidget(mBrushSizeSlider);
|
||||||
|
mLayoutSliderSize->addWidget(mBrushSizeSpinBox);
|
||||||
|
|
||||||
|
connect(mBrushSizeSlider, SIGNAL(valueChanged(int)), mBrushSizeSpinBox, SLOT(setValue(int)));
|
||||||
|
connect(mBrushSizeSpinBox, SIGNAL(valueChanged(int)), mBrushSizeSlider, SLOT(setValue(int)));
|
||||||
|
|
||||||
|
setLayout(mLayoutSliderSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSVWidget::TextureBrushWindow::TextureBrushWindow(CSMDoc::Document& document, QWidget *parent)
|
||||||
|
: QFrame(parent, Qt::Popup),
|
||||||
|
mBrushShape(0),
|
||||||
|
mBrushSize(0),
|
||||||
|
mBrushTexture("L0#0"),
|
||||||
|
mDocument(document)
|
||||||
|
{
|
||||||
|
mBrushTextureLabel = "Selected texture: " + mBrushTexture + " ";
|
||||||
|
|
||||||
|
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures();
|
||||||
|
|
||||||
|
int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture);
|
||||||
|
int index = landtexturesCollection.searchId(mBrushTexture);
|
||||||
|
|
||||||
|
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
|
||||||
|
{
|
||||||
|
mSelectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel) + landtexturesCollection.getData(index, landTextureFilename).value<QString>());
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
mBrushTextureLabel = "No selected texture or invalid texture";
|
||||||
|
mSelectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel));
|
||||||
|
}
|
||||||
|
|
||||||
|
mButtonPoint = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-point")), "", this);
|
||||||
|
mButtonSquare = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-square")), "", this);
|
||||||
|
mButtonCircle = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-circle")), "", this);
|
||||||
|
mButtonCustom = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-custom")), "", this);
|
||||||
|
|
||||||
|
mSizeSliders = new BrushSizeControls("Brush size", this);
|
||||||
|
|
||||||
|
QVBoxLayout *layoutMain = new QVBoxLayout;
|
||||||
|
layoutMain->setSpacing(0);
|
||||||
|
layoutMain->setContentsMargins(4,0,4,4);
|
||||||
|
|
||||||
|
QHBoxLayout *layoutHorizontal = new QHBoxLayout;
|
||||||
|
layoutHorizontal->setSpacing(0);
|
||||||
|
layoutHorizontal->setContentsMargins (QMargins (0, 0, 0, 0));
|
||||||
|
|
||||||
|
configureButtonInitialSettings(mButtonPoint);
|
||||||
|
configureButtonInitialSettings(mButtonSquare);
|
||||||
|
configureButtonInitialSettings(mButtonCircle);
|
||||||
|
configureButtonInitialSettings(mButtonCustom);
|
||||||
|
|
||||||
|
mButtonPoint->setToolTip (toolTipPoint);
|
||||||
|
mButtonSquare->setToolTip (toolTipSquare);
|
||||||
|
mButtonCircle->setToolTip (toolTipCircle);
|
||||||
|
mButtonCustom->setToolTip (toolTipCustom);
|
||||||
|
|
||||||
|
QButtonGroup* brushButtonGroup = new QButtonGroup(this);
|
||||||
|
brushButtonGroup->addButton(mButtonPoint);
|
||||||
|
brushButtonGroup->addButton(mButtonSquare);
|
||||||
|
brushButtonGroup->addButton(mButtonCircle);
|
||||||
|
brushButtonGroup->addButton(mButtonCustom);
|
||||||
|
|
||||||
|
brushButtonGroup->setExclusive(true);
|
||||||
|
|
||||||
|
layoutHorizontal->addWidget(mButtonPoint, 0, Qt::AlignTop);
|
||||||
|
layoutHorizontal->addWidget(mButtonSquare, 0, Qt::AlignTop);
|
||||||
|
layoutHorizontal->addWidget(mButtonCircle, 0, Qt::AlignTop);
|
||||||
|
layoutHorizontal->addWidget(mButtonCustom, 0, Qt::AlignTop);
|
||||||
|
|
||||||
|
mHorizontalGroupBox = new QGroupBox(tr(""));
|
||||||
|
mHorizontalGroupBox->setLayout(layoutHorizontal);
|
||||||
|
|
||||||
|
layoutMain->addWidget(mHorizontalGroupBox);
|
||||||
|
layoutMain->addWidget(mSizeSliders);
|
||||||
|
layoutMain->addWidget(mSelectedBrush);
|
||||||
|
|
||||||
|
setLayout(layoutMain);
|
||||||
|
|
||||||
|
connect(mButtonPoint, SIGNAL(clicked()), this, SLOT(setBrushShape()));
|
||||||
|
connect(mButtonSquare, SIGNAL(clicked()), this, SLOT(setBrushShape()));
|
||||||
|
connect(mButtonCircle, SIGNAL(clicked()), this, SLOT(setBrushShape()));
|
||||||
|
connect(mButtonCustom, SIGNAL(clicked()), this, SLOT(setBrushShape()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::TextureBrushWindow::configureButtonInitialSettings(QPushButton *button)
|
||||||
|
{
|
||||||
|
button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed));
|
||||||
|
button->setContentsMargins (QMargins (0, 0, 0, 0));
|
||||||
|
button->setIconSize (QSize (48-6, 48-6));
|
||||||
|
button->setFixedSize (48, 48);
|
||||||
|
button->setCheckable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::TextureBrushWindow::setBrushTexture(std::string brushTexture)
|
||||||
|
{
|
||||||
|
mBrushTexture = brushTexture;
|
||||||
|
|
||||||
|
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures();
|
||||||
|
|
||||||
|
int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture);
|
||||||
|
int columnModification = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Modification);
|
||||||
|
int index = landtexturesCollection.searchId(mBrushTexture);
|
||||||
|
|
||||||
|
// Check if texture exists in current plugin
|
||||||
|
if(landtexturesCollection.getData(index, columnModification).value<int>() == 0)
|
||||||
|
{
|
||||||
|
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||||
|
*mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures));
|
||||||
|
|
||||||
|
QUndoStack& undoStack = mDocument.getUndoStack();
|
||||||
|
|
||||||
|
QVariant textureFileNameVariant;
|
||||||
|
textureFileNameVariant.setValue(landtexturesCollection.getData(index, landTextureFilename).value<QString>());
|
||||||
|
|
||||||
|
std::size_t hashlocation = mBrushTexture.find("#");
|
||||||
|
std::string mBrushTexturePlugin = "L0#" + mBrushTexture.substr (hashlocation+1);
|
||||||
|
int indexPlugin = landtexturesCollection.searchId(mBrushTexturePlugin);
|
||||||
|
|
||||||
|
// Reindex texture if needed
|
||||||
|
if (indexPlugin != -1 && !landtexturesCollection.getRecord(indexPlugin).isDeleted())
|
||||||
|
{
|
||||||
|
int counter=0;
|
||||||
|
bool freeIndexFound = false;
|
||||||
|
do {
|
||||||
|
const size_t maxCounter = std::numeric_limits<uint16_t>::max() - 1;
|
||||||
|
mBrushTexturePlugin = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
|
||||||
|
if (landtexturesCollection.searchId(mBrushTexturePlugin) != -1 && landtexturesCollection.getRecord(mBrushTexturePlugin).isDeleted() == 0) counter = (counter + 1) % maxCounter;
|
||||||
|
else freeIndexFound = true;
|
||||||
|
} while (freeIndexFound == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
undoStack.beginMacro ("Add land texture record");
|
||||||
|
undoStack.push (new CSMWorld::CloneCommand (ltexTable, mBrushTexture, mBrushTexturePlugin, CSMWorld::UniversalId::Type_LandTexture));
|
||||||
|
undoStack.endMacro();
|
||||||
|
mBrushTexture = mBrushTexturePlugin;
|
||||||
|
emit passTextureId(mBrushTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
|
||||||
|
{
|
||||||
|
mBrushTextureLabel = "Selected texture: " + mBrushTexture + " ";
|
||||||
|
mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel) + landtexturesCollection.getData(index, landTextureFilename).value<QString>());
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
mBrushTextureLabel = "No selected texture or invalid texture";
|
||||||
|
mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel));
|
||||||
|
}
|
||||||
|
|
||||||
|
emit passBrushShape(mBrushShape); // update icon
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::TextureBrushWindow::setBrushSize(int brushSize)
|
||||||
|
{
|
||||||
|
mBrushSize = brushSize;
|
||||||
|
emit passBrushSize(mBrushSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::TextureBrushWindow::setBrushShape()
|
||||||
|
{
|
||||||
|
if(mButtonPoint->isChecked()) mBrushShape = 0;
|
||||||
|
if(mButtonSquare->isChecked()) mBrushShape = 1;
|
||||||
|
if(mButtonCircle->isChecked()) mBrushShape = 2;
|
||||||
|
if(mButtonCustom->isChecked()) mBrushShape = 3;
|
||||||
|
emit passBrushShape(mBrushShape);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::SceneToolTextureBrush::adjustToolTips()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CSVWidget::SceneToolTextureBrush::SceneToolTextureBrush (SceneToolbar *parent, const QString& toolTip, CSMDoc::Document& document)
|
||||||
|
: SceneTool (parent, Type_TopAction),
|
||||||
|
mToolTip (toolTip),
|
||||||
|
mDocument (document),
|
||||||
|
mTextureBrushWindow(new TextureBrushWindow(document, this))
|
||||||
|
{
|
||||||
|
mBrushHistory.resize(1);
|
||||||
|
mBrushHistory[0] = "L0#0";
|
||||||
|
|
||||||
|
setAcceptDrops(true);
|
||||||
|
connect(mTextureBrushWindow, SIGNAL(passBrushShape(int)), this, SLOT(setButtonIcon(int)));
|
||||||
|
setButtonIcon(mTextureBrushWindow->mBrushShape);
|
||||||
|
|
||||||
|
mPanel = new QFrame (this, Qt::Popup);
|
||||||
|
|
||||||
|
QHBoxLayout *layout = new QHBoxLayout (mPanel);
|
||||||
|
|
||||||
|
layout->setContentsMargins (QMargins (0, 0, 0, 0));
|
||||||
|
|
||||||
|
mTable = new QTableWidget (0, 2, this);
|
||||||
|
|
||||||
|
mTable->setShowGrid (true);
|
||||||
|
mTable->verticalHeader()->hide();
|
||||||
|
mTable->horizontalHeader()->hide();
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||||
|
mTable->horizontalHeader()->setSectionResizeMode (0, QHeaderView::Stretch);
|
||||||
|
mTable->horizontalHeader()->setSectionResizeMode (1, QHeaderView::Stretch);
|
||||||
|
#else
|
||||||
|
mTable->horizontalHeader()->setResizeMode (0, QHeaderView::Stretch);
|
||||||
|
mTable->horizontalHeader()->setResizeMode (1, QHeaderView::Stretch);
|
||||||
|
#endif
|
||||||
|
mTable->setSelectionMode (QAbstractItemView::NoSelection);
|
||||||
|
|
||||||
|
layout->addWidget (mTable);
|
||||||
|
|
||||||
|
connect (mTable, SIGNAL (clicked (const QModelIndex&)),
|
||||||
|
this, SLOT (clicked (const QModelIndex&)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::SceneToolTextureBrush::setButtonIcon (int brushShape)
|
||||||
|
{
|
||||||
|
QString tooltip = "Change brush settings <p>Currently selected: ";
|
||||||
|
|
||||||
|
switch (brushShape)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
|
||||||
|
setIcon (QIcon (QPixmap (":scenetoolbar/brush-point")));
|
||||||
|
tooltip += mTextureBrushWindow->toolTipPoint;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
|
||||||
|
setIcon (QIcon (QPixmap (":scenetoolbar/brush-square")));
|
||||||
|
tooltip += mTextureBrushWindow->toolTipSquare;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
|
||||||
|
setIcon (QIcon (QPixmap (":scenetoolbar/brush-circle")));
|
||||||
|
tooltip += mTextureBrushWindow->toolTipCircle;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
|
||||||
|
setIcon (QIcon (QPixmap (":scenetoolbar/brush-custom")));
|
||||||
|
tooltip += mTextureBrushWindow->toolTipCustom;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tooltip += "<p>(right click to access of previously used brush settings)";
|
||||||
|
|
||||||
|
|
||||||
|
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures();
|
||||||
|
|
||||||
|
int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture);
|
||||||
|
int index = landtexturesCollection.searchId(mTextureBrushWindow->mBrushTexture);
|
||||||
|
|
||||||
|
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
|
||||||
|
{
|
||||||
|
tooltip += "<p>Selected texture: " + QString::fromStdString(mTextureBrushWindow->mBrushTexture) + " ";
|
||||||
|
|
||||||
|
tooltip += landtexturesCollection.getData(index, landTextureFilename).value<QString>();
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
tooltip += "<p>No selected texture or invalid texture";
|
||||||
|
}
|
||||||
|
|
||||||
|
tooltip += "<br>(drop texture here to change)";
|
||||||
|
setToolTip (tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::SceneToolTextureBrush::showPanel (const QPoint& position)
|
||||||
|
{
|
||||||
|
updatePanel();
|
||||||
|
mPanel->move (position);
|
||||||
|
mPanel->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::SceneToolTextureBrush::updatePanel()
|
||||||
|
{
|
||||||
|
mTable->setRowCount (mBrushHistory.size());
|
||||||
|
|
||||||
|
for (int i = mBrushHistory.size()-1; i >= 0; --i)
|
||||||
|
{
|
||||||
|
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures();
|
||||||
|
int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture);
|
||||||
|
int index = landtexturesCollection.searchId(mBrushHistory[i]);
|
||||||
|
|
||||||
|
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
|
||||||
|
{
|
||||||
|
mTable->setItem (i, 1, new QTableWidgetItem (landtexturesCollection.getData(index, landTextureFilename).value<QString>()));
|
||||||
|
mTable->setItem (i, 0, new QTableWidgetItem (QString::fromStdString(mBrushHistory[i])));
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
mTable->setItem (i, 1, new QTableWidgetItem ("Invalid/deleted texture"));
|
||||||
|
mTable->setItem (i, 0, new QTableWidgetItem (QString::fromStdString(mBrushHistory[i])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::SceneToolTextureBrush::updateBrushHistory (const std::string& brushTexture)
|
||||||
|
{
|
||||||
|
mBrushHistory.insert(mBrushHistory.begin(), brushTexture);
|
||||||
|
if(mBrushHistory.size() > 5) mBrushHistory.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::SceneToolTextureBrush::clicked (const QModelIndex& index)
|
||||||
|
{
|
||||||
|
if (index.column()==0 || index.column()==1)
|
||||||
|
{
|
||||||
|
std::string brushTexture = mBrushHistory[index.row()];
|
||||||
|
std::swap(mBrushHistory[index.row()], mBrushHistory[0]);
|
||||||
|
mTextureBrushWindow->setBrushTexture(brushTexture);
|
||||||
|
emit passTextureId(brushTexture);
|
||||||
|
updatePanel();
|
||||||
|
mPanel->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::SceneToolTextureBrush::activate ()
|
||||||
|
{
|
||||||
|
QPoint position = QCursor::pos();
|
||||||
|
mTextureBrushWindow->mSizeSliders->mBrushSizeSlider->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt());
|
||||||
|
mTextureBrushWindow->mSizeSliders->mBrushSizeSpinBox->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt());
|
||||||
|
mTextureBrushWindow->move (position);
|
||||||
|
mTextureBrushWindow->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::SceneToolTextureBrush::dragEnterEvent (QDragEnterEvent *event)
|
||||||
|
{
|
||||||
|
emit passEvent(event);
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
void CSVWidget::SceneToolTextureBrush::dropEvent (QDropEvent *event)
|
||||||
|
{
|
||||||
|
emit passEvent(event);
|
||||||
|
event->accept();
|
||||||
|
}
|
@ -0,0 +1,133 @@
|
|||||||
|
#ifndef CSV_WIDGET_SCENETOOLTEXTUREBRUSH_H
|
||||||
|
#define CSV_WIDGET_SCENETOOLTEXTUREBRUSH_H
|
||||||
|
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QModelIndex>
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QSlider>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
#include "scenetool.hpp"
|
||||||
|
|
||||||
|
#include "../../model/doc/document.hpp"
|
||||||
|
|
||||||
|
class QTableWidget;
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
class TerrainTextureMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CSVWidget
|
||||||
|
{
|
||||||
|
class SceneToolTextureBrush;
|
||||||
|
|
||||||
|
/// \brief Layout-box for some brush button settings
|
||||||
|
class BrushSizeControls : public QGroupBox
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
BrushSizeControls(const QString &title, QWidget *parent);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHBoxLayout *mLayoutSliderSize;
|
||||||
|
QSlider *mBrushSizeSlider;
|
||||||
|
QSpinBox *mBrushSizeSpinBox;
|
||||||
|
|
||||||
|
friend class SceneToolTextureBrush;
|
||||||
|
friend class CSVRender::TerrainTextureMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SceneToolTextureBrush;
|
||||||
|
|
||||||
|
/// \brief Brush settings window
|
||||||
|
class TextureBrushWindow : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
TextureBrushWindow(CSMDoc::Document& document, QWidget *parent = 0);
|
||||||
|
void configureButtonInitialSettings(QPushButton *button);
|
||||||
|
|
||||||
|
const QString toolTipPoint = "Paint single point";
|
||||||
|
const QString toolTipSquare = "Paint with square brush";
|
||||||
|
const QString toolTipCircle = "Paint with circle brush";
|
||||||
|
const QString toolTipCustom = "Paint custom selection (not implemented yet)";
|
||||||
|
|
||||||
|
private:
|
||||||
|
int mBrushShape;
|
||||||
|
int mBrushSize;
|
||||||
|
std::string mBrushTexture;
|
||||||
|
CSMDoc::Document& mDocument;
|
||||||
|
QLabel *mSelectedBrush;
|
||||||
|
QGroupBox *mHorizontalGroupBox;
|
||||||
|
std::string mBrushTextureLabel;
|
||||||
|
QPushButton *mButtonPoint;
|
||||||
|
QPushButton *mButtonSquare;
|
||||||
|
QPushButton *mButtonCircle;
|
||||||
|
QPushButton *mButtonCustom;
|
||||||
|
BrushSizeControls* mSizeSliders;
|
||||||
|
|
||||||
|
friend class SceneToolTextureBrush;
|
||||||
|
friend class CSVRender::TerrainTextureMode;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setBrushTexture(std::string brushTexture);
|
||||||
|
void setBrushShape();
|
||||||
|
void setBrushSize(int brushSize);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void passBrushSize (int brushSize);
|
||||||
|
void passBrushShape(int brushShape);
|
||||||
|
void passTextureId(std::string brushTexture);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SceneToolTextureBrush : public SceneTool
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
QString mToolTip;
|
||||||
|
CSMDoc::Document& mDocument;
|
||||||
|
QFrame *mPanel;
|
||||||
|
QTableWidget *mTable;
|
||||||
|
std::vector<std::string> mBrushHistory;
|
||||||
|
TextureBrushWindow *mTextureBrushWindow;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void adjustToolTips();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
SceneToolTextureBrush (SceneToolbar *parent, const QString& toolTip, CSMDoc::Document& document);
|
||||||
|
|
||||||
|
virtual void showPanel (const QPoint& position);
|
||||||
|
void updatePanel ();
|
||||||
|
|
||||||
|
void dropEvent (QDropEvent *event);
|
||||||
|
void dragEnterEvent (QDragEnterEvent *event);
|
||||||
|
|
||||||
|
friend class CSVRender::TerrainTextureMode;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setButtonIcon(int brushShape);
|
||||||
|
void updateBrushHistory (const std::string& mBrushTexture);
|
||||||
|
void clicked (const QModelIndex& index);
|
||||||
|
virtual void activate();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void passEvent(QDropEvent *event);
|
||||||
|
void passEvent(QDragEnterEvent *event);
|
||||||
|
void passTextureId(std::string brushTexture);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue