class EditorTool(object):
    surfaceBuild = False
    panel = None
    optionsPanel = None
    toolIconName = None
    worldTooltipText = None
    previewRenderer = None

    tooltipText = "???"

    def levelChanged(self):
        """ called after a level change """
        pass

    @property
    def statusText(self):
        return ""

    @property
    def cameraDistance(self):
        return self.editor.cameraToolDistance

    def toolEnabled(self):
        return True

    def __init__(self, editor):
        self.editor = editor

    def toolReselected(self):
        pass

    def toolSelected(self):
        pass

    def drawTerrainReticle(self):
        pass

    def drawTerrainMarkers(self):
        pass

    def drawTerrainPreview(self, origin):
        if self.previewRenderer is None:
            return
        self.previewRenderer.origin = map(lambda a, b: a - b, origin, self.level.bounds.origin)

        GL.glPolygonOffset(DepthOffset.ClonePreview, DepthOffset.ClonePreview)
        GL.glEnable(GL.GL_POLYGON_OFFSET_FILL)
        self.previewRenderer.draw()
        GL.glDisable(GL.GL_POLYGON_OFFSET_FILL)

    def rotate(self, amount=1):
        pass

    def roll(self, amount=1):
        pass

    def flip(self, amount=1):
        pass

    def mirror(self, amount=1):
        pass

    def swap(self, amount=1):
        pass

    def mouseDown(self, evt, pos, direction):
        '''pos is the coordinates of the block under the cursor,
        direction indicates which face is under it.  the tool performs
        its action on the specified block'''

        pass

    def mouseUp(self, evt, pos, direction):
        pass

    def mouseDrag(self, evt, pos, direction):
        pass

    def increaseToolReach(self):
        "Return True if the tool handles its own reach"
        return False

    def decreaseToolReach(self):
        "Return True if the tool handles its own reach"
        return False

    def resetToolReach(self):
        "Return True if the tool handles its own reach"
        return False

    def confirm(self):
        ''' called when user presses enter '''
        pass

    def cancel(self):
        '''cancel the current operation.  called when a different tool
        is picked, escape is pressed, or etc etc'''
        self.hidePanel()

    #        pass

    def findBestTrackingPlane(self, face):
        cv = list(self.editor.mainViewport.cameraVector)
        cv[face >> 1] = 0
        cv = map(abs, cv)

        return cv.index(max(cv))

    def drawToolReticle(self):

        '''get self.editor.blockFaceUnderCursor for pos and direction.
        pos is the coordinates of the block under the cursor,
        direction indicates which face is under it. draw something to
        let the user know where the tool is going to act.  e.g. a
        transparent block for the block placing tool.'''

        pass

    def drawToolMarkers(self):
        ''' draw any markers the tool wants to leave in the field
        while another tool is out.  e.g. the current selection for
        SelectionTool'''

        pass

    def selectionChanged(self):
        """ called when the selection changes due to nudge. other tools can be active. """
        pass

    edge_factor = 0.1

    def boxFaceUnderCursor(self, box):
        if self.editor.mainViewport.mouseMovesCamera:
            return None, None

        p0 = self.editor.mainViewport.cameraPosition
        normal = self.editor.mainViewport.mouseVector
        if normal is None:
            return None, None

        points = {}

#        glPointSize(5.0)
#        glColor(1.0, 1.0, 0.0, 1.0)
#        glBegin(GL_POINTS)

        for dim in range(3):
            dim1 = dim + 1
            dim2 = dim + 2
            dim1 %= 3
            dim2 %= 3

            def pointInBounds(point, x):
                return box.origin[x] <= point[x] <= box.maximum[x]

            neg = normal[dim] < 0

            for side in 0, 1:

                d = (box.maximum, box.origin)[side][dim] - p0[dim]

                if d >= 0 or (neg and d <= 0):
                    if normal[dim]:
                        scale = d / normal[dim]

                        point = map(lambda a, p: (a * scale + p), normal, p0)
    #                    glVertex3f(*point)

                        if pointInBounds(point, dim1) and pointInBounds(point, dim2):
                            points[dim * 2 + side] = point

#        glEnd()

        if not len(points):
            return None, None

        cp = self.editor.mainViewport.cameraPosition
        distances = dict((numpy.sum(map(lambda a, b: (b - a) ** 2, cp, point)), (face, point)) for face, point in points.iteritems())
        if not len(distances):
            return None, None

        # When holding alt, pick the face opposite the camera
        # if key.get_mods() & KMOD_ALT:
        #    minmax = max
        # else:

        face, point = distances[min(distances.iterkeys())]

        # if the point is near the edge of the face, and the edge is facing away,
        # return the away-facing face

        dim = face // 2
        side = face & 1

        dim1, dim2 = dim + 1, dim + 2
        dim1, dim2 = dim1 % 3, dim2 % 3
        cv = self.editor.mainViewport.cameraVector

        # determine if a click was within self.edge_factor of the edge of a selection box side. if so, click through
        # to the opposite side
        for d in dim1, dim2:
            edge_width = box.size[d] * self.edge_factor
            facenormal = [0, 0, 0]
            cameraBehind = False

            if point[d] - box.origin[d] < edge_width:
                facenormal[d] = -1
                cameraBehind = cp[d] - box.origin[d] > 0
            if point[d] - box.maximum[d] > -edge_width:
                facenormal[d] = 1
                cameraBehind = cp[d] - box.maximum[d] < 0

            if numpy.dot(facenormal, cv) > 0 or cameraBehind:
                # the face adjacent to the clicked edge faces away from the cam
                return distances[max(distances.iterkeys())]

        return face, point

    def selectionCorners(self):
        """ returns the positions of the two selection corners as a pair of 3-tuples, each ordered x,y,z """

        if(None != self.editor.selectionTool.bottomLeftPoint and
           None != self.editor.selectionTool.topRightPoint):

            return (self.editor.selectionTool.bottomLeftPoint,
                    self.editor.selectionTool.topRightPoint)

        return None

    def selectionBoxForCorners(self, p1, p2):
        ''' considers p1,p2 as the marked corners of a selection.
        returns a BoundingBox containing all the blocks within.'''

        if self.editor.level is None:
            return None

        p1, p2 = list(p1), list(p2)
        # d = [(a-b) for a,b in zip(p1,p2)]
        for i in range(3):
            if p1[i] > p2[i]:
                t = p2[i]
                p2[i] = p1[i]
                p1[i] = t

            p2[i] += 1

        size = map(lambda a, b: a - b, p2, p1)

        if p1[1] < 0:
            size[1] += p1[1]
            p1[1] = 0

        h = self.editor.level.Height
        if p1[1] >= h:
            p1[1] = h - 1
            size[1] = 1

        if p1[1] + size[1] >= h:
            size[1] = h - p1[1]

        return BoundingBox(p1, size)

    def selectionBox(self):
        ''' selection corners, ordered, with the greater point moved up one block for use as the ending value of an array slice '''
        c = self.selectionCorners()
        if c:
            return self.selectionBoxForCorners(*c)

        return None

    def selectionSize(self):
        ''' returns a tuple containing the size of the selection (x,y,z)'''
        c = self.selectionBox()
        if c is None:
            return None
        return c.size

    @property
    def maxBlocks(self):
        from leveleditor import Settings
        return Settings.blockBuffer.get() / 2  # assume block buffer in bytes

    def showPanel(self):
        pass

    def hidePanel(self):
        if self.panel and self.panel.parent:
            self.panel.parent.remove(self.panel)
            self.panel = None class NudgeButton(GLBackground):
    """ A button that captures movement keys while pressed and sends them to a listener as nudge events.
    Poorly planned. """

    is_gl_container = True

    def __init__(self):
        GLBackground.__init__(self)
        nudgeLabel = Label("Nudge", margin=8)

        self.add(nudgeLabel)
        self.shrink_wrap()

        # tooltipBacking = Panel()
        # tooltipBacking.bg_color = (0, 0, 0, 0.6)
        keys = [config.config.get("Keys", k).upper() for k in ("Forward", "Back", "Left", "Right", "Up", "Down")]

        nudgeLabel.tooltipText = "Click and hold.  While holding, use the movement keys ({0}{1}{2}{3}{4}{5}) to nudge. Hold SHIFT to nudge faster.".format(*keys)
        # tooltipBacking.shrink_wrap()

    def mouse_down(self, event):
        self.focus()

    def mouse_up(self, event):
        self.get_root().mcedit.editor.focus_switch = None  # xxxx restore focus to editor better

    def key_down(self, evt):
        keyname = key.name(evt.key)
        if keyname == config.config.get("Keys", "Up"):
            self.nudge(Vector(0, 1, 0))
        if keyname == config.config.get("Keys", "Down"):
            self.nudge(Vector(0, -1, 0))

        Z = self.get_root().mcedit.editor.mainViewport.cameraVector  # xxx mouthful
        absZ = map(abs, Z)
        if absZ[0] < absZ[2]:
            forward = (0, 0, (-1 if Z[2] < 0 else 1))
        else:
            forward = ((-1 if Z[0] < 0 else 1), 0, 0)

        back = map(int.__neg__, forward)
        left = forward[2], forward[1], -forward[0]
        right = map(int.__neg__, left)

        if keyname == config.config.get("Keys", "Forward"):
            self.nudge(Vector(*forward))
        if keyname == config.config.get("Keys", "Back"):
            self.nudge(Vector(*back))
        if keyname == config.config.get("Keys", "Left"):
            self.nudge(Vector(*left))
        if keyname == config.config.get("Keys", "Right"):
            self.nudge(Vector(*right)) class ToolOptions(Panel):
    @property
    def editor(self):
        return self.tool.editor class Panel(GLBackground):
    pass class ChoiceButton(ValueButton):
    align = "c"
    choose = None

    def __init__(self, choices, scrolling=True, scroll_items=30, **kw):
        # passing an empty list of choices is ill-advised

        if 'choose' in kw:
            self.choose = kw.pop('choose')

        ValueButton.__init__(self, action=self.showMenu, **kw)

        self.scrolling = scrolling
        self.scroll_items = scroll_items
        self.choices = choices or ["[UNDEFINED]"]

        widths = [self.font.size(c)[0] for c in choices] + [self.width]
        if len(widths):
            self.width = max(widths) + self.margin * 2

        self.choiceIndex = 0

    def showMenu(self):
        choiceIndex = self.menu.present(self, (0, 0))
        if choiceIndex != -1:
            self.choiceIndex = choiceIndex
            if self.choose:
                self.choose()

    def get_value(self):
        return self.selectedChoice

    @property
    def selectedChoice(self):
        if self.choiceIndex >= len(self.choices) or self.choiceIndex < 0:
            return ""
        return self.choices[self.choiceIndex]

    @selectedChoice.setter
    def selectedChoice(self, val):
        idx = self.choices.index(val)
        if idx != -1:
            self.choiceIndex = idx

    @property
    def choices(self):
        return self._choices

    @choices.setter
    def choices(self, ch):
        self._choices = ch
        self.menu = Menu("", ((name, "pickMenu") for name in self._choices),
                         self.scrolling, self.scroll_items) def CheckBoxLabel(title, *args, **kw):
    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 def IntInputRow(title, *args, **kw):
    return Row((Label(title, tooltipText=kw.get('tooltipText')), IntField(*args, **kw))) 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:")
            if ask("Error during {0}: {1!r}".format(func, e)[:1000], ["Report Error", "Okay"], default=1, cancel=0) == "Report Error":
                try:
                    import squash_python
                    squash_python.get_client().recordException(*sys.exc_info())
                except ImportError:
                    pass
                except Exception:
                    logging.exception("Error while recording exception data:")

    return _alertException 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 == 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 != 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 != None:
        GL.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY)
        GL.glDisable(GL.GL_TEXTURE_2D) 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) 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) def setWindowCaption(prefix):
    caption = display.get_caption()[0]

    class ctx:
        def __enter__(self):
            display.set_caption(prefix + caption)

        def __exit__(self, *args):
            display.set_caption(caption)
    return ctx() 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"""
    class ProgressWidget(Dialog):
        progressFraction = 0.0
        firstDraw = False

        def draw(self, surface):
            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))
            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()

    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"
import os
import traceback
import numpy
import pygame
import config
import mcplatform
import pymclevel
import tempfile
from OpenGL import GL
from collections import defaultdict
from albow import Row, Label, Button, AttrRef, Column, ask
from depths import DepthOffset
from editortools.editortool import EditorTool
from editortools.nudgebutton import NudgeButton
from editortools.tooloptions import ToolOptions
from glbackground import Panel
from mceutils import ChoiceButton, CheckBoxLabel, IntInputRow, alertException, drawCube, drawFace, drawTerrainCuttingWire, setWindowCaption, showProgress
from operation import Operation
from pymclevel.box import Vector, BoundingBox, FloatBox
from fill import  BlockFillOperation
from pymclevel import nbt
        from albow import theme
        self.editor.toolbar.toolTextureChanged()

    def selectOtherCorner(self):
        self.currentCorner = 1 - self.currentCorner

    showPreviousSelection = SelectSettings.showPreviousSelection.configProperty()
    alpha = 0.25

    def drawToolMarkers(self):

        selectionBox = self.selectionBox()
        if(selectionBox):
            widg = self.editor.find_widget(pygame.mouse.get_pos())

            # these corners stay even while using the chunk tool.
            GL.glPolygonOffset(DepthOffset.SelectionCorners, DepthOffset.SelectionCorners)
            lineWidth = 3
            for t, c, n in ((self.bottomLeftPoint, self.bottomLeftColor, self.bottomLeftNudge), (self.topRightPoint, self.topRightColor, self.topRightNudge)):
                if t != None:
                    (sx, sy, sz) = t
                    if self.selectionInProgress:
                        if t == self.getSelectionPoint(self.currentCorner):
                            blockFace = self.editor.blockFaceUnderCursor
                            if blockFace:
                                p, d = blockFace
                                (sx, sy, sz) = p
                        else:
                            sx, sy, sz = self.dragStartPoint

                    # draw a blue or yellow wireframe box at the selection corner
                    r, g, b = c
                    alpha = 0.4
                    try:
                        bt = self.editor.level.blockAt(sx, sy, sz)
                        if(bt):
                            alpha = 0.2
                    except (EnvironmentError, pymclevel.ChunkNotPresent):
                        pass

                    GL.glLineWidth(lineWidth)
                    lineWidth += 1

                    # draw highlighted block faces when nudging
                    if (widg.parent == n or widg == n):
                        GL.glEnable(GL.GL_BLEND)
                        # drawCube(BoundingBox((sx, sy, sz), (1,1,1)))
                        nudgefaces = numpy.array([
                               selectionBox.minx, selectionBox.miny, selectionBox.minz,
                               selectionBox.minx, selectionBox.maxy, selectionBox.minz,
                               selectionBox.minx, selectionBox.maxy, selectionBox.maxz,
                               selectionBox.minx, selectionBox.miny, selectionBox.maxz,
                               selectionBox.minx, selectionBox.miny, selectionBox.minz,
                               selectionBox.maxx, selectionBox.miny, selectionBox.minz,
                               selectionBox.maxx, selectionBox.miny, selectionBox.maxz,
                               selectionBox.minx, selectionBox.miny, selectionBox.maxz,
                               selectionBox.minx, selectionBox.miny, selectionBox.minz,
                               selectionBox.minx, selectionBox.maxy, selectionBox.minz,
                               selectionBox.maxx, selectionBox.maxy, selectionBox.minz,
                               selectionBox.maxx, selectionBox.miny, selectionBox.minz,
                               ], dtype='float32')

                        if sx != selectionBox.minx:
                            nudgefaces[0:12:3] = selectionBox.maxx
                        if sy != selectionBox.miny:
                            nudgefaces[13:24:3] = selectionBox.maxy
                        if sz != selectionBox.minz:
                            nudgefaces[26:36:3] = selectionBox.maxz

                        GL.glColor(r, g, b, 0.3)
                        GL.glVertexPointer(3, GL.GL_FLOAT, 0, nudgefaces)
                        GL.glEnable(GL.GL_DEPTH_TEST)
                        GL.glDrawArrays(GL.GL_QUADS, 0, 12)
                        GL.glDisable(GL.GL_DEPTH_TEST)

                        GL.glDisable(GL.GL_BLEND)

                    GL.glColor(r, g, b, alpha)
                    drawCube(BoundingBox((sx, sy, sz), (1, 1, 1)), GL.GL_LINE_STRIP)

            if not (not self.showPreviousSelection and self.selectionInProgress):
                # draw the current selection as a white box.  hangs around when you use other tools.
                GL.glPolygonOffset(DepthOffset.Selection, DepthOffset.Selection)
                color = self.selectionColor + (self.alpha,)
                if self.dragResizeFace is not None:
                    box = self.draggingSelectionBox()
                else:
                    box = selectionBox

                if self.panel and (widg is self.panel.nudgeBlocksButton or widg.parent is self.panel.nudgeBlocksButton):
                    color = (0.3, 1.0, 0.3, self.alpha)
                self.editor.drawConstructionCube(box, color)

                # highlight the face under the cursor, or the face being dragged
                if self.dragResizeFace is None:
                    if self.selectionInProgress or self.clickSelectionInProgress:
                        pass
                    else:
                        face, point = self.boxFaceUnderCursor(box)

                        if face is not None:
                            GL.glEnable(GL.GL_BLEND)
                            GL.glColor(*color)

                            # Shrink the highlighted face to show the click-through edges

                            offs = [s * self.edge_factor for s in box.size]
                            offs[face >> 1] = 0
                            origin = [o + off for o, off in zip(box.origin, offs)]
                            size = [s - off * 2 for s, off in zip(box.size, offs)]

                            cv = self.editor.mainViewport.cameraVector
                            for i in range(3):
                                if cv[i] > 0:
                                    origin[i] -= offs[i]
                                    size[i] += offs[i]
                                else:
                                    size[i] += offs[i]

                            smallbox = FloatBox(origin, size)


                            drawFace(smallbox, face)