示例#1
0
class TileSelector(wx.Panel):

    SelectEvent, EVT_SELECT_EVENT = wx.lib.newevent.NewEvent()

    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.NO_BORDER):
        wx.Panel.__init__(self, parent, id=id, pos=pos, size=size, style=style)

        self.Viewport = wx.Panel(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER)
        self.Scrollbar = wx.ScrollBar(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.SB_VERTICAL)

        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(self.Viewport, 1, wx.EXPAND, 0)
        sizer.Add(self.Scrollbar, 0, wx.EXPAND, 0)

        self.SetSizer(sizer)
        self.Layout()
        sizer.Fit(self)

        self.Scrollbar.SetScrollbar(0, 0, 0, 0)

        self._presenter = Presenter.from_window(self.Viewport.GetHandle(), config.SCALE)
        self._camera = Camera(0, 0, 0, 0)

        self._tilemap = None
        self._tileset = None
        self._select_start = None
        self._select_end = None

        self._show_collision = False

        self.Viewport.Bind(wx.EVT_PAINT, self.paint)
        self.Viewport.Bind(wx.EVT_SIZE, self.resize)
        self.Viewport.Bind(wx.EVT_MOUSEWHEEL, self.mouse_wheel)
        self.Viewport.Bind(wx.EVT_LEFT_DOWN, self.mouse_left_down)
        self.Viewport.Bind(wx.EVT_LEFT_UP, self.mouse_left_up)
        self.Viewport.Bind(wx.EVT_MOTION, self.mouse_move)
        self.Scrollbar.Bind(wx.EVT_SCROLL, self.scroll)

    def set_tileset(self, tileset):
        self._tileset = tileset
        self.populate_tiles()

        self.Viewport.Refresh(False)

    def populate_tiles(self):
        if not self._tileset:
            self._tilemap.clear()

        surface = self._presenter.surface

        tiles_width = int(math.floor(surface.width / float(Tilemap.TILE_SIZE)))
        tiles_height = int(math.ceil(len(self._tileset.tiles) / float(tiles_width)))

        tiles = range(0, len(self._tileset.tiles))
        self._tilemap = Tilemap(tiles, tiles_width, tiles_height)

        self._camera.set_max(tiles_width * Tilemap.TILE_SIZE, tiles_height * Tilemap.TILE_SIZE)
        self.Scrollbar.SetScrollbar(wx.VERTICAL, 0, surface.height, tiles_height, True)

        self.Scrollbar.SetThumbPosition(0)

    def resize(self, event):
        self._presenter.resize()
        surface = self._presenter.surface

        self._camera.set_size(surface.width, surface.height)

        if self._tileset:
            tiles_width = int(math.floor(surface.width / float(Tilemap.TILE_SIZE)))
            tiles_height = int(math.ceil((len(self._tileset.tiles) / tiles_width) * Tilemap.TILE_SIZE))

            diff = int(tiles_height - surface.height)
            if diff:
                position = self.Scrollbar.GetThumbPosition()
                self.Scrollbar.SetScrollbar(position, surface.height, tiles_height, Tilemap.TILE_SIZE)
            else:
                self.Scrollbar.SetScrollbar(0, 0, 0, 0)

    def paint(self, event):
        if not self._tileset:
            return

        surface = self._presenter.surface
        surface.clear()

        self._camera.move_absolute(0, self.Scrollbar.GetThumbPosition())
        self._tilemap.render(surface, self._camera, self._tileset, self._show_collision)

        if self._select_start:
            x1 = self._select_start[0] * Tilemap.TILE_SIZE
            y1 = self._select_start[1] * Tilemap.TILE_SIZE

            x2 = self._select_end[0] * Tilemap.TILE_SIZE
            y2 = self._select_end[1] * Tilemap.TILE_SIZE

            x1, y1 = self._camera.world_to_camera(x1, y1)
            x2, y2 = self._camera.world_to_camera(x2, y2)

            if x2 < x1:
                x2, x1 = x1, x2
            if y2 < y1:
                y2, y1 = y1, y2

            width = x2 - x1 + Tilemap.TILE_SIZE
            height = y2 - y1 + Tilemap.TILE_SIZE

            surface.box_fill(x1, y1, width, height, 0xFFFFFFFF, BlendOp.ALPHA50)

        self._presenter.present()

    def mouse_wheel(self, event):
        if not self._tileset:
            return

        position = self.Scrollbar.GetThumbPosition()
        position -= (event.GetWheelRotation() / 20) * Tilemap.TILE_SIZE
        self.Scrollbar.SetThumbPosition(position)

        self.Viewport.Refresh(False)

    def mouse_left_down(self, event):
        if not self._tileset:
            return

        if self._select_start:
            return

        pos = event.GetPosition()
        x, y = self.get_tile_position(pos)

        self._select_start = (x, y)
        self._select_end = self._select_start

        self.Viewport.Refresh(False)

    def mouse_left_up(self, event):
        if not self._tilemap:
            return

        if not self._select_end:
            return

        x1, y1 = self._select_start
        x2, y2 = self._select_end

        if x2 < x1:
            x2, x1 = x1, x2
        if y2 < y1:
            y2, y1 = y1, y2

        width = x2 - x1 + 1
        height = y2 - y1 + 1

        self._select_start = None
        self._select_end = None

        self.Viewport.Refresh(False)

        if width and height:
            selection = Tilemap.from_tilemap(self._tilemap, x1, y1, x2 + 1, y2 + 1)
        else:
            selection = None

        event = TileSelector.SelectEvent(selection=selection)
        wx.PostEvent(self.GetEventHandler(), event)

    def mouse_move(self, event):
        if not self._select_start:
            return

        pos = event.GetPosition()
        x, y = self.get_tile_position(pos)

        self._select_end = (x, y)
        self.Viewport.Refresh(False)

    def scroll(self, event):
        self.Viewport.Refresh(False)

    def get_tile_position(self, pos):
        x = pos[0] / self._presenter.scale
        y = pos[1] / self._presenter.scale
        x, y = self._camera.camera_to_world(x, y)
        x /= Tilemap.TILE_SIZE
        y /= Tilemap.TILE_SIZE

        return x, y

    def show_collision(self, show):
        self._show_collision = show
        self.Viewport.Refresh(False)