Add Biome brush
BrushModes create their options widgets BrushModes return additional options that are added to brushTool's common options BrushModes return their own bounding boxes instead of BrushTool BrushModes create the level to be used for the brush cursor Current BrushMode is saved in settings
This commit is contained in:
parent
de6a39c865
commit
1673b7f48c
@ -15,7 +15,9 @@ from mcedit2.util.load_ui import load_ui, registerCustomWidget
|
||||
from mcedit2.util.settings import Settings
|
||||
from mcedit2.util.showprogress import showProgress
|
||||
from mcedit2.util.worldloader import WorldLoader
|
||||
from mcedit2.widgets.layout import Row
|
||||
from mcedit2.widgets.blockpicker import BlockTypeButton
|
||||
from mcedit2.widgets.layout import Row, Column
|
||||
from mceditlib.anvil.biome_types import BiomeTypes
|
||||
from mceditlib.geometry import Vector
|
||||
from mceditlib.selection import ShapedSelection, BoundingBox
|
||||
from mceditlib.util import exhaust
|
||||
@ -23,7 +25,7 @@ from mceditlib.util import exhaust
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
BrushModeSetting = Settings().getOption("editortools/brush/mode")
|
||||
BrushModeSetting = Settings().getOption("editortools/brush/mode", default="fill")
|
||||
BrushShapeSetting = Settings().getOption("editortools/brush/shape")
|
||||
BrushSizeSetting = Settings().getOption("editortools/brush/size")
|
||||
|
||||
@ -45,7 +47,6 @@ class BrushCommand(SimplePerformCommand):
|
||||
self.points = points
|
||||
|
||||
self.brushSize = options['brushSize']
|
||||
self.blockInfo = options['blockInfo']
|
||||
self.brushStyle = options['brushStyle']
|
||||
self.brushMode = options['brushMode']
|
||||
self.setText("%s %s Brush" % (self.brushMode.name, self.brushStyle.ID))
|
||||
@ -63,9 +64,6 @@ class BrushCommand(SimplePerformCommand):
|
||||
def hollow(self):
|
||||
return self.options.get('brushHollow', False)
|
||||
|
||||
def brushBoxForPoint(self, point):
|
||||
return self.brushMode.brushBoundingBox(point, self.options)
|
||||
|
||||
def perform(self):
|
||||
if len(self.points) > 10:
|
||||
showProgress("Performing brush...", self._perform(), cancel=True)
|
||||
@ -76,7 +74,7 @@ class BrushCommand(SimplePerformCommand):
|
||||
yield 0, len(self.points), "Applying {0} brush...".format(self.brushMode.name)
|
||||
try:
|
||||
#xxx combine selections
|
||||
selections = [ShapedSelection(self.brushBoxForPoint(point), self.brushStyle.shapeFunc) for point in self.points]
|
||||
selections = [ShapedSelection(self.brushMode.brushBoxForPoint(point, self.options), self.brushStyle.shapeFunc) for point in self.points]
|
||||
self.brushMode.applyToSelections(self, selections)
|
||||
except NotImplementedError:
|
||||
for i, point in enumerate(self.points):
|
||||
@ -90,8 +88,8 @@ class BrushCommand(SimplePerformCommand):
|
||||
self.performed = True
|
||||
|
||||
|
||||
class BrushMode(object):
|
||||
options = []
|
||||
class BrushMode(QtCore.QObject):
|
||||
optionsWidget = None
|
||||
|
||||
def brushBoundingBox(self, center, options={}):
|
||||
# Return a box of size options['brushSize'] centered around point.
|
||||
@ -109,7 +107,6 @@ class BrushMode(object):
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def applyToSelections(self, command, selections):
|
||||
"""
|
||||
Called by BrushCommand to apply this brush mode to the given selection. Selection is generated
|
||||
@ -117,35 +114,114 @@ class BrushMode(object):
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def createOptionsPanel(self, tool):
|
||||
pass
|
||||
def createOptionsWidget(self, brushTool):
|
||||
return None
|
||||
|
||||
def createCursorLevel(self, brushTool):
|
||||
return None
|
||||
|
||||
class Fill(BrushMode):
|
||||
name = "Fill"
|
||||
#
|
||||
#def createOptions(self, panel, tool):
|
||||
# col = [
|
||||
# panel.modeStyleGrid,
|
||||
# panel.hollowRow,
|
||||
# panel.noiseInput,
|
||||
# panel.brushSizeRows,
|
||||
# panel.blockButton,
|
||||
# ]
|
||||
# return col
|
||||
name = "fill"
|
||||
|
||||
def __init__(self):
|
||||
super(Fill, self).__init__()
|
||||
self.displayName = self.tr("Fill")
|
||||
|
||||
def createOptionsWidget(self, brushTool):
|
||||
if self.optionsWidget:
|
||||
return self.optionsWidget
|
||||
|
||||
self.optionsWidget = QtGui.QWidget()
|
||||
label = QtGui.QLabel(self.tr("Fill Block:"))
|
||||
self.blockTypeButton = BlockTypeButton()
|
||||
self.blockTypeButton.textureAtlas = brushTool.editorSession.textureAtlas
|
||||
self.blockTypeButton.block = brushTool.editorSession.worldEditor.blocktypes['minecraft:stone']
|
||||
self.blockTypeButton.blocksChanged.connect(brushTool.updateCursor)
|
||||
|
||||
self.optionsWidget.setLayout(Column(
|
||||
Row(label, self.blockTypeButton, margin=0),
|
||||
None, margin=0))
|
||||
return self.optionsWidget
|
||||
|
||||
def getOptions(self):
|
||||
return {'blockInfo': self.blockTypeButton.block}
|
||||
|
||||
def applyToSelections(self, command, selections):
|
||||
"""
|
||||
|
||||
:type command: BrushCommand
|
||||
"""
|
||||
fill = command.editorSession.currentDimension.fillBlocksIter(selections[0], command.blockInfo)
|
||||
fill = command.editorSession.currentDimension.fillBlocksIter(selections[0], command.options['blockInfo'])
|
||||
showProgress("Applying brush...", fill)
|
||||
|
||||
def brushBoxForPoint(self, point, options):
|
||||
return self.brushBoundingBox(point, options)
|
||||
|
||||
def createCursorLevel(self, brushTool):
|
||||
selection = ShapedSelection(self.brushBoxForPoint((0, 0, 0), brushTool.options), brushTool.brushStyle.shapeFunc)
|
||||
cursorLevel = MaskLevel(selection,
|
||||
self.blockTypeButton.block,
|
||||
brushTool.editorSession.worldEditor.blocktypes)
|
||||
return cursorLevel
|
||||
|
||||
class Biome(BrushMode):
|
||||
name = "biome"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Biome, self).__init__(*args, **kwargs)
|
||||
self.displayName = self.tr("Biome")
|
||||
|
||||
def getOptions(self):
|
||||
return {'biomeID': self.biomeTypeBox.itemData(self.biomeTypeBox.currentIndex())}
|
||||
|
||||
def createOptionsWidget(self, brushTool):
|
||||
if self.optionsWidget:
|
||||
return self.optionsWidget
|
||||
|
||||
self.optionsWidget = QtGui.QWidget()
|
||||
label = QtGui.QLabel(self.tr("Fill Biome:"))
|
||||
self.biomeTypeBox = QtGui.QComboBox()
|
||||
self.biomeTypes = BiomeTypes()
|
||||
for biome in self.biomeTypes.types.values():
|
||||
self.biomeTypeBox.addItem(biome.name, biome.ID)
|
||||
|
||||
self.biomeTypeBox.activated.connect(brushTool.updateCursor)
|
||||
self.optionsWidget.setLayout(Column(Row(label, self.biomeTypeBox, margin=0), None, margin=0))
|
||||
return self.optionsWidget
|
||||
|
||||
def applyToSelections(self, command, selections):
|
||||
"""
|
||||
|
||||
:type command: BrushCommand
|
||||
"""
|
||||
#task = command.editorSession.currentDimension.fillBlocksIter(selections[0], command.blockInfo)
|
||||
#showProgress("Applying brush...", task)
|
||||
selection = selections[0]
|
||||
biomeID = command.options['biomeID']
|
||||
for x, _, z in selection.positions:
|
||||
command.editorSession.currentDimension.setBiomeID(x, z, biomeID)
|
||||
|
||||
def brushBoxForPoint(self, point, options):
|
||||
x, y, z = options['brushSize']
|
||||
options['brushSize'] = x, 1, z
|
||||
|
||||
return self.brushBoundingBox(point, options)
|
||||
|
||||
def createCursorLevel(self, brushTool):
|
||||
box = self.brushBoxForPoint((0, 0, 0), brushTool.options)
|
||||
|
||||
selection = ShapedSelection(box, brushTool.brushStyle.shapeFunc)
|
||||
cursorLevel = MaskLevel(selection,
|
||||
brushTool.editorSession.worldEditor.blocktypes["minecraft:grass"],
|
||||
brushTool.editorSession.worldEditor.blocktypes)
|
||||
return cursorLevel
|
||||
|
||||
class BrushModes(object):
|
||||
# load from plugins here
|
||||
allModes = (Fill(),)
|
||||
fill = Fill()
|
||||
biome = Biome()
|
||||
allModes = [fill, biome]
|
||||
modesByName = {mode.name: mode for mode in allModes}
|
||||
|
||||
|
||||
class Style(object):
|
||||
@ -257,6 +333,8 @@ class BrushTool(EditorTool):
|
||||
super(BrushTool, self).__init__(editorSession, *args, **kwargs)
|
||||
self.toolWidget = load_ui("editortools/brush.ui")
|
||||
|
||||
BrushModeSetting.connectAndCall(self.modeSettingChanged)
|
||||
|
||||
self.cursorWorldScene = None
|
||||
self.cursorNode = scenegraph.TranslateNode()
|
||||
|
||||
@ -268,10 +346,6 @@ class BrushTool(EditorTool):
|
||||
self.toolWidget.ySpinSlider.valueChanged.connect(self.setY)
|
||||
self.toolWidget.zSpinSlider.valueChanged.connect(self.setZ)
|
||||
|
||||
self.toolWidget.blockTypeInput.textureAtlas = editorSession.textureAtlas
|
||||
self.toolWidget.blockTypeInput.block = editorSession.worldEditor.blocktypes["minecraft:stone"]
|
||||
self.toolWidget.blockTypeInput.blocksChanged.connect(self.setBlocktypes)
|
||||
|
||||
self.toolWidget.brushShapeInput.shapeChanged.connect(self.updateCursor)
|
||||
|
||||
self.fillBlock = editorSession.worldEditor.blocktypes["stone"]
|
||||
@ -322,41 +396,38 @@ class BrushTool(EditorTool):
|
||||
self.editorSession.pushCommand(command)
|
||||
|
||||
def mouseMove(self, event):
|
||||
#box = self.brushBoxForPoint(event.blockPosition)
|
||||
if event.blockPosition:
|
||||
self.cursorNode.translateOffset = event.blockPosition + event.blockFace.vector
|
||||
|
||||
|
||||
@property
|
||||
def options(self):
|
||||
return {'brushSize': self.brushSize,
|
||||
'blockInfo': self.fillBlock,
|
||||
'brushStyle': self.brushStyle,
|
||||
'brushMode': self.brushMode}
|
||||
options = {'brushSize': self.brushSize,
|
||||
'brushStyle': self.brushStyle,
|
||||
'brushMode': self.brushMode}
|
||||
options.update(self.brushMode.getOptions())
|
||||
return options
|
||||
|
||||
def modeSettingChanged(self, value):
|
||||
self.brushMode = BrushModes.modesByName[value]
|
||||
stack = self.toolWidget.modeOptionsStack
|
||||
while stack.count():
|
||||
stack.removeWidget(stack.widget(0))
|
||||
widget = self.brushMode.createOptionsWidget(self)
|
||||
if widget:
|
||||
stack.addWidget(widget)
|
||||
|
||||
@property
|
||||
def brushMode(self):
|
||||
return self.toolWidget.brushModeInput.currentMode()
|
||||
|
||||
@property
|
||||
def brushStyle(self):
|
||||
return self.toolWidget.brushShapeInput.currentShape
|
||||
|
||||
def brushBoxForPoint(self, point):
|
||||
return self.brushMode.brushBoundingBox(point, self.options)
|
||||
|
||||
def brushSelectionForCursor(self):
|
||||
return ShapedSelection(self.brushBoxForPoint((0, 0, 0)), self.brushStyle.shapeFunc)
|
||||
|
||||
def updateCursor(self):
|
||||
log.info("Updating brush cursor: %s %s", self.brushStyle, self.brushSelectionForCursor())
|
||||
log.info("Updating brush cursor")
|
||||
if self.cursorWorldScene:
|
||||
self.brushLoader.timer.stop()
|
||||
self.cursorNode.removeChild(self.cursorWorldScene)
|
||||
|
||||
cursorLevel = MaskLevel(self.brushSelectionForCursor(),
|
||||
self.fillBlock,
|
||||
self.editorSession.worldEditor.blocktypes)
|
||||
cursorLevel = self.brushMode.createCursorLevel(self)
|
||||
|
||||
self.cursorWorldScene = worldscene.WorldScene(cursorLevel, self.editorSession.textureAtlas)
|
||||
self.cursorWorldScene.depthOffsetNode.depthOffset = DepthOffset.PreviewRenderer
|
||||
@ -372,16 +443,14 @@ class BrushModeWidget(QtGui.QComboBox):
|
||||
super(BrushModeWidget, self).__init__(*args, **kwargs)
|
||||
|
||||
for mode in BrushModes.allModes:
|
||||
self.addItem(mode.name, mode)
|
||||
self.addItem(mode.displayName, mode.name)
|
||||
|
||||
currentID = BrushModeSetting.value(BrushModes.allModes[0].name)
|
||||
indexesByID = {s.name: i for (i, s) in enumerate(BrushModes.allModes)}
|
||||
idx = indexesByID.get(currentID, 0)
|
||||
self.setCurrentIndex(idx)
|
||||
currentID = BrushModeSetting.value()
|
||||
currentIndex = self.findData(currentID)
|
||||
if currentIndex == -1:
|
||||
currentIndex = 0
|
||||
self.setCurrentIndex(currentIndex)
|
||||
self.currentIndexChanged.connect(self.indexDidChange)
|
||||
|
||||
def currentMode(self):
|
||||
return self.itemData(self.currentIndex())
|
||||
|
||||
def indexDidChange(self):
|
||||
BrushModeSetting.setValue(self.currentMode().name)
|
||||
BrushModeSetting.setValue(self.itemData(self.currentIndex()))
|
||||
|
@ -15,7 +15,17 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0,0,0,0,0,0">
|
||||
<layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0,0,0,0,0">
|
||||
<item row="7" column="1" colspan="2">
|
||||
<widget class="SpinSlider" name="hoverSpinSlider" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="SpinSlider" name="xSpinSlider" native="true">
|
||||
<property name="sizePolicy">
|
||||
@ -26,6 +36,37 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Shape:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Length:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Hover:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="BrushModeWidget" name="brushModeInput" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
@ -33,23 +74,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="BrushModeWidget" name="brushModeInput" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Width:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
@ -57,51 +81,10 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Length:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1" colspan="2">
|
||||
<widget class="SpinSlider" name="hoverSpinSlider" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Hover:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Block:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1" colspan="2">
|
||||
<widget class="BlockTypeButton" name="blockTypeInput" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Shape:</string>
|
||||
<string>Width:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -181,17 +164,20 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<widget class="QStackedWidget" name="modeOptionsStack">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</spacer>
|
||||
<property name="currentIndex">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@ -208,12 +194,6 @@
|
||||
<header>shapewidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>BlockTypeButton</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>blocktypebutton.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>SpinSlider</class>
|
||||
<extends>QWidget</extends>
|
||||
|
Reference in New Issue
Block a user