"""Copyright (c) 2010-2012 David Rio Vierra
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE."""
# import resource_packs # not the right place, moving it a bit furtehr
"""
mceutils.py
Exception catching, some basic box drawing, texture pack loading, oddball UI elements
"""
# Modified by D.C.-G. for translation purpose
#.# Marks the layout modifications. -- D.C.-G.
#!#
#!# The stuff in there related to albow should be in albow module.
#!# This stuff will then be available for components base classes in this GUI module.
#!# And make albow/widgets more coherent to use.
#!#
from resource_packs import ResourcePackHandler
from albow.controls import ValueDisplay
from albow import alert, ask, Button, Column, Label, root, Row, ValueButton, Widget
from albow.translate import _
from datetime import datetime
import directories
import numpy
from OpenGL import GL
import os
import png
from pygame import display
import pymclevel
import json
import hashlib
import shutil
import logging
#!# Used to track the ALBOW stuff imported from here
[docs]def warn(obj):
name = getattr(obj, '__name__', getattr(getattr(obj, '__class__', obj), '__name__', obj))
logging.getLogger().warn('%s.%s is deprecated and will be removed. Use albow.%s instead.'%(obj.__module__, name, name))
#!#
[docs]def alertException(func):
def _alertException(*args, **kw):
try:
return func(*args, **kw)
except root.Cancel:
alert("Canceled.")
except pymclevel.infiniteworld.SessionLockLost as e:
alert(_(e.message) + _("\n\nYour changes cannot be saved."))
except Exception, e:
logging.exception("Exception:")
ask(_("Error during {0}: {1!r}").format(func, e)[:1000], ["OK"], cancel=0)
return _alertException
[docs]def drawFace(box, face, type=GL.GL_QUADS):
x, y, z, = box.origin
x2, y2, z2 = box.maximum
if face == pymclevel.faces.FaceXDecreasing:
faceVertices = numpy.array(
(x, y2, z2,
x, y2, z,
x, y, z,
x, y, z2,
), dtype='f4')
elif face == pymclevel.faces.FaceXIncreasing:
faceVertices = numpy.array(
(x2, y, z2,
x2, y, z,
x2, y2, z,
x2, y2, z2,
), dtype='f4')
elif face == pymclevel.faces.FaceYDecreasing:
faceVertices = numpy.array(
(x2, y, z2,
x, y, z2,
x, y, z,
x2, y, z,
), dtype='f4')
elif face == pymclevel.faces.FaceYIncreasing:
faceVertices = numpy.array(
(x2, y2, z,
x, y2, z,
x, y2, z2,
x2, y2, z2,
), dtype='f4')
elif face == pymclevel.faces.FaceZDecreasing:
faceVertices = numpy.array(
(x, y, z,
x, y2, z,
x2, y2, z,
x2, y, z,
), dtype='f4')
elif face == pymclevel.faces.FaceZIncreasing:
faceVertices = numpy.array(
(x2, y, z2,
x2, y2, z2,
x, y2, z2,
x, y, z2,
), dtype='f4')
faceVertices.shape = (4, 3)
dim = face >> 1
dims = [0, 1, 2]
dims.remove(dim)
texVertices = numpy.array(
faceVertices[:, dims],
dtype='f4'
).flatten()
faceVertices.shape = (12,)
texVertices *= 16
GL.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY)
GL.glVertexPointer(3, GL.GL_FLOAT, 0, faceVertices)
GL.glTexCoordPointer(2, GL.GL_FLOAT, 0, texVertices)
GL.glEnable(GL.GL_POLYGON_OFFSET_FILL)
GL.glEnable(GL.GL_POLYGON_OFFSET_LINE)
if type is GL.GL_LINE_STRIP:
indexes = numpy.array((0, 1, 2, 3, 0), dtype='uint32')
GL.glDrawElements(type, 5, GL.GL_UNSIGNED_INT, indexes)
else:
GL.glDrawArrays(type, 0, 4)
GL.glDisable(GL.GL_POLYGON_OFFSET_FILL)
GL.glDisable(GL.GL_POLYGON_OFFSET_LINE)
GL.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY)
[docs]def drawCube(box, cubeType=GL.GL_QUADS, blockType=0, texture=None, textureVertices=None, selectionBox=False):
""" pass a different cubeType e.g. GL_LINE_STRIP for wireframes """
x, y, z, = box.origin
x2, y2, z2 = box.maximum
dx, dy, dz = x2 - x, y2 - y, z2 - z
cubeVertices = numpy.array(
(
x, y, z,
x, y2, z,
x2, y2, z,
x2, y, z,
x2, y, z2,
x2, y2, z2,
x, y2, z2,
x, y, z2,
x2, y, z2,
x, y, z2,
x, y, z,
x2, y, z,
x2, y2, z,
x, y2, z,
x, y2, z2,
x2, y2, z2,
x, y2, z2,
x, y2, z,
x, y, z,
x, y, z2,
x2, y, z2,
x2, y, z,
x2, y2, z,
x2, y2, z2,
), dtype='f4')
if textureVertices is None:
textureVertices = numpy.array(
(
0, -dy * 16,
0, 0,
dx * 16, 0,
dx * 16, -dy * 16,
dx * 16, -dy * 16,
dx * 16, 0,
0, 0,
0, -dy * 16,
dx * 16, -dz * 16,
0, -dz * 16,
0, 0,
dx * 16, 0,
dx * 16, 0,
0, 0,
0, -dz * 16,
dx * 16, -dz * 16,
dz * 16, 0,
0, 0,
0, -dy * 16,
dz * 16, -dy * 16,
dz * 16, -dy * 16,
0, -dy * 16,
0, 0,
dz * 16, 0,
), dtype='f4')
textureVertices.shape = (6, 4, 2)
if selectionBox:
textureVertices[0:2] += (16 * (x & 15), 16 * (y2 & 15))
textureVertices[2:4] += (16 * (x & 15), -16 * (z & 15))
textureVertices[4:6] += (16 * (z & 15), 16 * (y2 & 15))
textureVertices[:] += 0.5
GL.glVertexPointer(3, GL.GL_FLOAT, 0, cubeVertices)
if texture is not None:
GL.glEnable(GL.GL_TEXTURE_2D)
GL.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY)
texture.bind()
GL.glTexCoordPointer(2, GL.GL_FLOAT, 0, textureVertices),
GL.glEnable(GL.GL_POLYGON_OFFSET_FILL)
GL.glEnable(GL.GL_POLYGON_OFFSET_LINE)
GL.glDrawArrays(cubeType, 0, 24)
GL.glDisable(GL.GL_POLYGON_OFFSET_FILL)
GL.glDisable(GL.GL_POLYGON_OFFSET_LINE)
if texture is not None:
GL.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY)
GL.glDisable(GL.GL_TEXTURE_2D)
[docs]def drawTerrainCuttingWire(box,
c0=(0.75, 0.75, 0.75, 0.4),
c1=(1.0, 1.0, 1.0, 1.0)):
# glDepthMask(False)
GL.glEnable(GL.GL_DEPTH_TEST)
GL.glDepthFunc(GL.GL_LEQUAL)
GL.glColor(*c1)
GL.glLineWidth(2.0)
drawCube(box, cubeType=GL.GL_LINE_STRIP)
GL.glDepthFunc(GL.GL_GREATER)
GL.glColor(*c0)
GL.glLineWidth(1.0)
drawCube(box, cubeType=GL.GL_LINE_STRIP)
GL.glDepthFunc(GL.GL_LEQUAL)
GL.glDisable(GL.GL_DEPTH_TEST)
# glDepthMask(True)
[docs]def loadAlphaTerrainTexture():
texW, texH, terraindata = loadPNGFile(os.path.join(directories.getDataDir(), ResourcePackHandler.Instance().get_selected_resource_pack().terrain_path()))
def _loadFunc():
loadTextureFunc(texW, texH, terraindata)
tex = glutils.Texture(_loadFunc)
tex.data = terraindata
return tex
[docs]def loadPNGData(filename_or_data):
reader = png.Reader(filename_or_data)
(w, h, data, metadata) = reader.read_flat()
data = numpy.array(data, dtype='uint8')
data.shape = (h, w, metadata['planes'])
if data.shape[2] == 1:
# indexed color. remarkably straightforward.
data.shape = data.shape[:2]
data = numpy.array(reader.palette(), dtype='uint8')[data]
if data.shape[2] < 4:
data = numpy.insert(data, 3, 255, 2)
return w, h, data
[docs]def loadPNGFile(filename):
(w, h, data) = loadPNGData(filename)
powers = (16, 32, 64, 128, 256, 512, 1024, 2048, 4096)
assert (w in powers) and (h in powers) # how crude
return w, h, data
[docs]def loadTextureFunc(w, h, ndata):
GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, w, h, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, ndata)
return w, h
[docs]def loadPNGTexture(filename, *a, **kw):
filename = os.path.join(directories.getDataDir(), filename)
try:
w, h, ndata = loadPNGFile(filename)
tex = glutils.Texture(functools.partial(loadTextureFunc, w, h, ndata), *a, **kw)
tex.data = ndata
return tex
except Exception, e:
print "Exception loading ", filename, ": ", repr(e)
return glutils.Texture()
import glutils
[docs]def normalize(x):
l = x[0] * x[0] + x[1] * x[1] + x[2] * x[2]
if l <= 0.0:
return [0, 0, 0]
size = numpy.sqrt(l)
if size <= 0.0:
return [0, 0, 0]
return map(lambda a: a / size, x)
[docs]def normalize_size(x):
l = x[0] * x[0] + x[1] * x[1] + x[2] * x[2]
if l <= 0.0:
return [0., 0., 0.], 0.
size = numpy.sqrt(l)
if size <= 0.0:
return [0, 0, 0], 0
return (x / size), size
# Label = GLLabel
[docs]class HotkeyColumn(Widget):
is_gl_container = True
def __init__(self, items, keysColumn=None, buttonsColumn=None, item_spacing=None):
warn(self)
if keysColumn is None:
keysColumn = []
if buttonsColumn is None:
buttonsColumn = []
labels = []
Widget.__init__(self)
for t in items:
if len(t) == 3:
(hotkey, title, action) = t
tooltipText = None
else:
(hotkey, title, action, tooltipText) = t
if isinstance(title, (str, unicode)):
button = Button(title, action=action)
else:
button = ValueButton(ref=title, action=action, width=200)
button.anchor = self.anchor
label = Label(hotkey, width=100, margin=button.margin)
label.anchor = "wh"
label.height = button.height
labels.append(label)
if tooltipText:
button.tooltipText = tooltipText
keysColumn.append(label)
buttonsColumn.append(button)
self.buttons = list(buttonsColumn)
#.#
if item_spacing == None:
buttonsColumn = Column(buttonsColumn)
else:
buttonsColumn = Column(buttonsColumn, spacing=item_spacing)
#.#
buttonsColumn.anchor = self.anchor
#.#
if item_spacing == None:
keysColumn = Column(keysColumn)
else:
keysColumn = Column(keysColumn, spacing=item_spacing)
commandRow = Row((keysColumn, buttonsColumn))
self.labels = labels
self.add(commandRow)
self.shrink_wrap()
from albow import CheckBox, AttrRef, Menu
[docs]def CheckBoxLabel(title, *args, **kw):
warn(CheckBoxLabel)
tooltipText = kw.pop('tooltipText', None)
cb = CheckBox(*args, **kw)
lab = Label(title, fg_color=cb.fg_color)
lab.mouse_down = cb.mouse_down
if tooltipText:
cb.tooltipText = tooltipText
lab.tooltipText = tooltipText
class CBRow(Row):
margin = 0
@property
def value(self):
return self.checkbox.value
@value.setter
def value(self, val):
self.checkbox.value = val
row = CBRow((lab, cb))
row.checkbox = cb
return row
from albow import FloatField, IntField, TextFieldWrapped
from albow.dialogs import Dialog
from datetime import timedelta
[docs]def TextInputRow(title, *args, **kw):
warn(TextInputRow)
return Row((Label(title, tooltipText=kw.get('tooltipText')), TextFieldWrapped(*args, **kw)))
[docs]def setWindowCaption(prefix):
caption = display.get_caption()[0]
prefix = _(prefix)
if type(prefix) == unicode:
prefix = prefix.encode("utf8")
class ctx:
def __enter__(self):
display.set_caption(prefix + caption)
def __exit__(self, *args):
display.set_caption(caption)
return ctx()
[docs]def showProgress(progressText, progressIterator, cancel=False):
"""Show the progress for a long-running synchronous operation.
progressIterator should be a generator-like object that can return
either None, for an indeterminate indicator,
A float value between 0.0 and 1.0 for a determinate indicator,
A string, to update the progress info label
or a tuple of (float value, string) to set the progress and update the label"""
warn(ShowProgress)
class ProgressWidget(Dialog):
progressFraction = 0.0
firstDraw = False
root = None
def draw(self, surface):
if self.root is None:
self.root = self.get_root()
Widget.draw(self, surface)
frameStart = datetime.now()
frameInterval = timedelta(0, 1, 0) / 2
amount = None
try:
while datetime.now() < frameStart + frameInterval:
amount = progressIterator.next()
if self.firstDraw is False:
self.firstDraw = True
break
except StopIteration:
self.dismiss()
infoText = ""
if amount is not None:
if isinstance(amount, tuple):
if len(amount) > 2:
infoText = ": " + amount[2]
amount, max = amount[:2]
else:
max = amount
maxwidth = (self.width - self.margin * 2)
if amount is None:
self.progressBar.width = maxwidth
self.progressBar.bg_color = (255, 255, 25, 255)
elif isinstance(amount, basestring):
self.statusText = amount
else:
self.progressAmount = amount
if isinstance(amount, (int, float)):
self.progressFraction = float(amount) / (float(max) or 1)
self.progressBar.width = maxwidth * self.progressFraction
self.statusText = str("{0} / {1}".format(amount, max))
else:
self.statusText = str(amount)
if infoText:
self.statusText += infoText
@property
def estimateText(self):
delta = (datetime.now() - self.startTime)
progressPercent = (int(self.progressFraction * 10000))
if progressPercent > 10000:
progressPercent = 10000
left = delta * (10000 - progressPercent) / (progressPercent or 1)
return _("Time left: {0}").format(left)
def cancel(self):
if cancel:
self.dismiss(False)
def idleevent(self, evt):
self.invalidate()
def key_down(self, event):
pass
def key_up(self, event):
pass
def mouse_up(self, event):
try:
if "SelectionTool" in str(self.root.editor.currentTool):
if self.root.get_nudge_block().count > 0:
self.root.get_nudge_block().mouse_up(event)
except:
pass
widget = ProgressWidget()
widget.progressText = _(progressText)
widget.statusText = ""
widget.progressAmount = 0.0
progressLabel = ValueDisplay(ref=AttrRef(widget, 'progressText'), width=550)
statusLabel = ValueDisplay(ref=AttrRef(widget, 'statusText'), width=550)
estimateLabel = ValueDisplay(ref=AttrRef(widget, 'estimateText'), width=550)
progressBar = Widget(size=(550, 20), bg_color=(150, 150, 150, 255))
widget.progressBar = progressBar
col = (progressLabel, statusLabel, estimateLabel, progressBar)
if cancel:
cancelButton = Button("Cancel", action=widget.cancel, fg_color=(255, 0, 0, 255))
col += (Column((cancelButton,), align="r"),)
widget.add(Column(col))
widget.shrink_wrap()
widget.startTime = datetime.now()
if widget.present():
return widget.progressAmount
else:
return "Canceled"
from glutils import DisplayList
import functools