def mouseReleased(self, evt):
		"""Tear selected instances and set selection tool as cursor"""
		self.log.debug("TearingTool: mouseReleased")
		if evt.getButton() == fife.MouseEvent.LEFT:
			coords = self.get_world_location(evt).to_tuple()
			if self.coords is None:
				self.coords = coords
			self._mark(self.coords, coords)
			selection_list_copy = [building for building in self.selected]
			for building in selection_list_copy:
				self.session.view.renderer['InstanceRenderer'].removeColored(building._instance)
				if (not building.id in BUILDINGS.EXPAND_RANGE) or self.confirm_ranged_delete(building):
					Tear(building).execute(self.session)
			else:
				if self._hovering_over:
					# we're hovering over a building, but none is selected, so this tear action isn't allowed
					warehouses = [ b for b in self._hovering_over if
					               b.id == BUILDINGS.WAREHOUSE and b.owner.is_local_player]
					if warehouses:
						# tried to tear a warehouse, this is especially non-tearable
						pos = warehouses[0].position.origin
						self.session.ingame_gui.message_widget.add(point=pos, string_id="WAREHOUSE_NOT_TEARABLE" )

			self.selected = WeakList()
			self._hovering_over = WeakList()
			if not evt.isShiftPressed() and not horizons.globals.fife.get_uh_setting('UninterruptedBuilding'):
				self.tear_tool_active = False
				self.on_escape()
			evt.consume()
	def _mark(self, *edges):
		"""Highights building instances and keeps self.selected up to date."""
		self._restore_transparent_instances()
		self.log.debug("TearingTool: mark")
		if len(edges) == 1:
			edges = (edges[0], edges[0])
		elif len(edges) == 2:
			edges = ((min(edges[0][0], edges[1][0]), min(edges[0][1], edges[1][1])),
					 (max(edges[0][0], edges[1][0]), max(edges[0][1], edges[1][1])))
		else:
			edges = None
		if self.oldedges != edges or edges is None:
			for i in self.selected:
				self.session.view.renderer['InstanceRenderer'].removeColored(i._instance)
			self.selected = WeakList()
			self.oldedges = edges
		if edges is not None:
			self._hovering_over = WeakList()
			for x in xrange(edges[0][0], edges[1][0] + 1):
				for y in xrange(edges[0][1], edges[1][1] + 1):
					b = self.session.world.get_building(Point(x, y))
					if b is not None:
						if b not in self._hovering_over:
							self._hovering_over.append(b)
							self._make_surrounding_transparent(b)
							self._remove_object_transparency(Point(x,y))
						if b.tearable and b.owner is not None and b.owner.is_local_player:
							if b not in self.selected:
								self._make_surrounding_transparent(b)
								self.selected.append(b)
								self._remove_object_transparency(Point(x,y))
			for i in self.selected:
				self.session.view.renderer['InstanceRenderer'].addColored(i._instance,
				                                                          *self.tear_selection_color)
		self.log.debug("TearingTool: mark done")
Esempio n. 3
0
	def mouseReleased(self, evt):
		"""Tear selected instances and set selection tool as cursor"""
		self.log.debug("TearingTool: mouseReleased")
		if evt.getButton() == fife.MouseEvent.LEFT:
			coords = self.get_world_location(evt).to_tuple()
			if self.coords is None:
				self.coords = coords
			self._mark(self.coords, coords)
			selection_list_copy = [building for building in self.selected]
			if self.selected:
				for building in selection_list_copy:
					self.session.view.renderer['InstanceRenderer'].removeColored(building._instance)
					if (building.id not in BUILDINGS.EXPAND_RANGE) or self.confirm_ranged_delete(building):
						Tear(building).execute(self.session)
			elif self._hovering_over:
				# we're hovering over a building, but none is selected, so this tear action isn't allowed
				warehouses = [ b for b in self._hovering_over if
					       b.id == BUILDINGS.WAREHOUSE and b.owner.is_local_player]
				if warehouses:
					# tried to tear a warehouse, this is especially non-tearable
					pos = warehouses[0].position.origin
					self.session.ingame_gui.message_widget.add(point=pos, string_id="WAREHOUSE_NOT_TEARABLE" )

			self.selected = WeakList()
			self._hovering_over = WeakList()
			if not evt.isShiftPressed() and not horizons.globals.fife.get_uh_setting('UninterruptedBuilding'):
				self.tear_tool_active = False
				self.on_escape()
			evt.consume()
Esempio n. 4
0
	def _mark(self, *edges):
		"""Highights building instances and keeps self.selected up to date."""
		self._restore_transparent_instances()
		self.log.debug("TearingTool: mark")
		if len(edges) == 1:
			edges = (edges[0], edges[0])
		elif len(edges) == 2:
			edges = ((min(edges[0][0], edges[1][0]), min(edges[0][1], edges[1][1])),
					 (max(edges[0][0], edges[1][0]), max(edges[0][1], edges[1][1])))
		else:
			edges = None
		if self.oldedges != edges or edges is None:
			for i in self.selected:
				self.session.view.renderer['InstanceRenderer'].removeColored(i._instance)
			self.selected = WeakList()
			self.oldedges = edges
		if edges is not None:
			self._hovering_over = WeakList()
			for x in xrange(edges[0][0], edges[1][0] + 1):
				for y in xrange(edges[0][1], edges[1][1] + 1):
					b = self.session.world.get_building(Point(x, y))
					if b is not None:
						if b not in self._hovering_over:
							self._hovering_over.append(b)
							self._make_surrounding_transparent(b)
							self._remove_object_transparency(Point(x,y))
						if b.tearable and b.owner is not None and b.owner.is_local_player:
							if b not in self.selected:
								self._make_surrounding_transparent(b)
								self.selected.append(b)
								self._remove_object_transparency(Point(x,y))
			for i in self.selected:
				self.session.view.renderer['InstanceRenderer'].addColored(i._instance,
				                                                          *self.tear_selection_color)
		self.log.debug("TearingTool: mark done")
	def __init__(self, session):
		super(TearingTool, self).__init__(session)
		self.coords = None
		self.selected = WeakList()
		self.oldedges = None
		self.tear_tool_active = True
		self.session.ingame_gui.hide_menu()
		self.session.selected_instances.clear()
		horizons.globals.fife.set_cursor_image("tearing")
		self._hovering_over = WeakList()
		WorldObjectDeleted.subscribe(self._on_object_deleted)
Esempio n. 6
0
	def __init__(self, session):
		super(TearingTool, self).__init__(session)
		self._transparent_instances = set() # fife instances modified for transparency
		self.coords = None
		self.selected = WeakList()
		self.oldedges = None
		self.tear_tool_active = True
		self.session.ingame_gui.hide_menu()
		self.session.selected_instances.clear()
		horizons.globals.fife.set_cursor_image("tearing")
		self._hovering_over = WeakList()
		WorldObjectDeleted.subscribe(self._on_object_deleted)
    def __init__(self, session):
        super(NavigationTool, self).__init__(session)
        self._last_mmb_scroll_point = [0, 0]
        # coordinates of last mouse positions
        self.last_exact_world_location = fife.ExactModelCoordinate()
        self._hover_instances_update_scheduled = False
        self.middle_scroll_active = False

        class CmdListener(fife.ICommandListener):
            pass

        self.cmdlist = CmdListener()
        horizons.globals.fife.eventmanager.addCommandListener(self.cmdlist)
        self.cmdlist.onCommand = self.onCommand

        if not self.__class__.send_hover_instances_update:
            # clear
            HoverInstancesChanged.broadcast(self, set())
            self.__class__.last_hover_instances = WeakList()
        else:
            # need updates about scrolling here
            self.session.view.add_change_listener(
                self._schedule_hover_instance_update)
            self._schedule_hover_instance_update()

        class CoordsTooltip(object):
            @classmethod
            def get_instance(cls, cursor_tool):
                if cursor_tool.session.ingame_gui.coordinates_tooltip is not None:
                    inst = cursor_tool.session.ingame_gui.coordinates_tooltip
                    inst.cursor_tool = cursor_tool
                    return inst
                else:
                    return CoordsTooltip(cursor_tool)

            def __init__(self, cursor_tool, **kwargs):
                super(CoordsTooltip, self).__init__(**kwargs)
                cursor_tool.session.ingame_gui.coordinates_tooltip = self
                self.cursor_tool = cursor_tool
                self.enabled = False

                self.icon = Icon(position=(
                    1, 1))  # 0, 0 is currently not supported by tooltips

            def toggle(self):
                self.enabled = not self.enabled
                if not self.enabled and self.icon.tooltip_shown:
                    self.icon.hide_tooltip()

            def show_evt(self, evt):
                if self.enabled:
                    x, y = self.cursor_tool.get_world_location(evt).to_tuple()
                    self.icon.helptext = u'%d, %d ' % (x, y) + _(
                        "Press H to remove this hint")
                    self.icon.position_tooltip(evt)
                    self.icon.show_tooltip()

        self.tooltip = CoordsTooltip.get_instance(self)
	def _send_hover_instance_upate(self):
		"""Broadcast update with new instances below mouse (hovered).
		At most called in a certain interval, not after every mouse move in
		order to prevent delays."""
		self._hover_instances_update_scheduled = False
		where = fife.Point(self.__class__.last_event_pos.x, self.__class__.last_event_pos.y)

		instances = set(self.get_hover_instances(where))
		# only send when there were actual changes
		if instances != set(self.__class__.last_hover_instances):
			self.__class__.last_hover_instances = WeakList(instances)
			HoverInstancesChanged.broadcast(self, instances)
class NavigationTool(CursorTool):
    """Navigation Class to process mouse actions ingame"""

    last_event_pos = fife.ScreenPoint(
        0, 0)  # last received mouse event position, fife.ScreenPoint

    send_hover_instances_update = True
    HOVER_INSTANCES_UPDATE_DELAY = 1  # sec
    last_hover_instances = WeakList()

    def __init__(self, session):
        super(NavigationTool, self).__init__(session)
        self._last_mmb_scroll_point = [0, 0]
        # coordinates of last mouse positions
        self.last_exact_world_location = fife.ExactModelCoordinate()
        self._hover_instances_update_scheduled = False
        self.middle_scroll_active = False

        class CmdListener(fife.ICommandListener):
            pass

        self.cmdlist = CmdListener()
        horizons.globals.fife.eventmanager.addCommandListener(self.cmdlist)
        self.cmdlist.onCommand = self.onCommand

        if not self.__class__.send_hover_instances_update:
            # clear
            HoverInstancesChanged.broadcast(self, set())
            self.__class__.last_hover_instances = WeakList()
        else:
            # need updates about scrolling here
            self.session.view.add_change_listener(
                self._schedule_hover_instance_update)
            self._schedule_hover_instance_update()

        class CoordsTooltip(object):
            @classmethod
            def get_instance(cls, cursor_tool):
                if cursor_tool.session.ingame_gui.coordinates_tooltip is not None:
                    inst = cursor_tool.session.ingame_gui.coordinates_tooltip
                    inst.cursor_tool = cursor_tool
                    return inst
                else:
                    return CoordsTooltip(cursor_tool)

            def __init__(self, cursor_tool, **kwargs):
                super(CoordsTooltip, self).__init__(**kwargs)
                cursor_tool.session.ingame_gui.coordinates_tooltip = self
                self.cursor_tool = cursor_tool
                self.enabled = False

                self.icon = Icon(position=(
                    1, 1))  # 0, 0 is currently not supported by tooltips

            def toggle(self):
                self.enabled = not self.enabled
                if not self.enabled and self.icon.tooltip_shown:
                    self.icon.hide_tooltip()

            def show_evt(self, evt):
                if self.enabled:
                    x, y = self.cursor_tool.get_world_location(evt).to_tuple()
                    self.icon.helptext = u'%d, %d ' % (x, y) + _(
                        "Press H to remove this hint")
                    self.icon.position_tooltip(evt)
                    self.icon.show_tooltip()

        self.tooltip = CoordsTooltip.get_instance(self)

    def remove(self):
        if self.__class__.send_hover_instances_update:
            self.session.view.remove_change_listener(
                self._schedule_hover_instance_update)
        horizons.globals.fife.eventmanager.removeCommandListener(self.cmdlist)
        super(NavigationTool, self).remove()

    def mousePressed(self, evt):
        if evt.getButton() == fife.MouseEvent.MIDDLE:
            if horizons.globals.fife.get_uh_setting("MiddleMousePan"):
                self._last_mmb_scroll_point = (evt.getX(), evt.getY())
                self.middle_scroll_active = True

    def mouseReleased(self, evt):
        if evt.getButton() == fife.MouseEvent.MIDDLE:
            if horizons.globals.fife.get_uh_setting("MiddleMousePan"):
                self.middle_scroll_active = False

    def mouseDragged(self, evt):
        if evt.getButton() == fife.MouseEvent.MIDDLE:
            if horizons.globals.fife.get_uh_setting("MiddleMousePan"):
                if self.middle_scroll_active:
                    scroll_by = (self._last_mmb_scroll_point[0] - evt.getX(),
                                 self._last_mmb_scroll_point[1] - evt.getY())
                    self.session.view.scroll(*scroll_by)
                    self._last_mmb_scroll_point = (evt.getX(), evt.getY())
        else:
            # Else the event will mistakenly be delegated if the left mouse button is hit while
            # scrolling using the middle mouse button
            if not self.middle_scroll_active:
                NavigationTool.mouseMoved(self, evt)

    # return new mouse position after moving
    def mouseMoved(self, evt):
        if not self.session.world.inited:
            return

        self.tooltip.show_evt(evt)
        # don't overwrite this last_event_pos instance. Due to class
        # hierarchy, it would write to the lowest class (e.g. SelectionTool)
        # and the attribute in NavigationTool would be left unchanged.
        self.__class__.last_event_pos.set(evt.getX(), evt.getY(), 0)
        mousepoint = self.__class__.last_event_pos

        # Status menu update
        current = self.get_exact_world_location(evt)

        distance_ge = lambda a, b, epsilon: abs((a.x - b.x)**2 +
                                                (a.y - b.y)**2) >= epsilon**2

        if distance_ge(current, self.last_exact_world_location,
                       4):  # update every 4 tiles for settlement info
            self.last_exact_world_location = current
            # update res bar with settlement-related info
            LastActivePlayerSettlementManager().update(current)

        # check if instance update is scheduled
        if self.__class__.send_hover_instances_update:
            self._schedule_hover_instance_update()

        # Mouse scrolling
        x, y = 0, 0
        if mousepoint.x < VIEW.AUTOSCROLL_WIDTH:
            x -= VIEW.AUTOSCROLL_WIDTH - mousepoint.x
        elif mousepoint.x > (self.session.view.cam.getViewPort().right() -
                             VIEW.AUTOSCROLL_WIDTH):
            x += VIEW.AUTOSCROLL_WIDTH + mousepoint.x - self.session.view.cam.getViewPort(
            ).right()
        if mousepoint.y < VIEW.AUTOSCROLL_WIDTH:
            y -= VIEW.AUTOSCROLL_WIDTH - mousepoint.y
        elif mousepoint.y > (self.session.view.cam.getViewPort().bottom() -
                             VIEW.AUTOSCROLL_WIDTH):
            y += VIEW.AUTOSCROLL_WIDTH + mousepoint.y - self.session.view.cam.getViewPort(
            ).bottom()
        x *= 10
        y *= 10
        self.session.view.autoscroll(x, y)

    # move up mouse wheel = zoom in
    def mouseWheelMovedUp(self, evt):
        track_cursor = horizons.globals.fife.get_uh_setting(
            "CursorCenteredZoom")
        self.session.view.zoom_in(track_cursor)
        evt.consume()

    # move down mouse wheel = zoom out
    def mouseWheelMovedDown(self, evt):
        track_cursor = horizons.globals.fife.get_uh_setting(
            "CursorCenteredZoom")
        self.session.view.zoom_out(track_cursor)
        evt.consume()

    def onCommand(self, command):
        """Called when some kind of command-event happens.
		For "documentation", see:
		engine/core/eventchannel/command/ec_commandids.h
		engine/core/eventchannel/eventmanager.cpp
		in fife.
		It's usually about mouse/keyboard focus or window being iconified/restored.
		"""
        stop_scrolling_on = (fife.CMD_APP_ICONIFIED, fife.CMD_MOUSE_FOCUS_LOST,
                             fife.CMD_INPUT_FOCUS_LOST)
        if command.getCommandType() in stop_scrolling_on:
            # it has been randomly observed twice that this code is reached with session being None or
            # partly deinitialized. Since it is unknown how fife handles this and why
            # removeCommandListener in remove() doesn't prevent further calls, we have to catch and ignore the error
            try:
                self.session.view.autoscroll(0, 0)  # stop autoscroll
            except AttributeError:
                pass

    def get_hover_instances(self, where, layers=None):
        """
		Utility method, returns the instances under the cursor
		@param where: anything supporting getX/getY
		@param layers: list of layer ids to search for. Default to OBJECTS
		"""
        if layers is None:
            layers = [LAYERS.OBJECTS]

        all_instances = []
        for layer in layers:
            x = where.getX()
            y = where.getY()
            instances = self.session.view.cam.getMatchingInstances(
                fife.ScreenPoint(x, y), self.session.view.layers[layer],
                False)  # False for accurate

            # if no instances found, try again and search within a 8px radius
            if not instances:
                selection_radius = 8
                radius = fife.Rect(x - selection_radius, y - selection_radius,
                                   selection_radius * 2, selection_radius * 2)

                instances = self.session.view.cam.getMatchingInstances(
                    radius, self.session.view.layers[layer])

            all_instances.extend(instances)

        hover_instances = []
        for i in all_instances:
            id = i.getId()
            # Check id, can be '' if instance is created and clicked on before
            # actual game representation class is created (network play)
            if id == '':
                continue
            instance = WorldObject.get_object_by_id(int(id))
            hover_instances.append(instance)
        return hover_instances

    def end(self):
        super(NavigationTool, self).end()
        if self._hover_instances_update_scheduled:
            ExtScheduler().rem_all_classinst_calls(self)
        self.helptext = None

    def _schedule_hover_instance_update(self):
        """Hover instances have potentially changed, do an update in a timely fashion (but not right away)"""
        if not self._hover_instances_update_scheduled:
            self._hover_instances_update_scheduled = True
            ExtScheduler().add_new_object(
                self._send_hover_instance_upate,
                self,
                run_in=self.__class__.HOVER_INSTANCES_UPDATE_DELAY)

    def _send_hover_instance_upate(self):
        """Broadcast update with new instances below mouse (hovered).
		At most called in a certain interval, not after every mouse move in
		order to prevent delays."""
        self._hover_instances_update_scheduled = False
        where = fife.Point(self.__class__.last_event_pos.x,
                           self.__class__.last_event_pos.y)

        instances = set(self.get_hover_instances(where))
        # only send when there were actual changes
        if instances != set(self.__class__.last_hover_instances):
            self.__class__.last_hover_instances = WeakList(instances)
            HoverInstancesChanged.broadcast(self, instances)
Esempio n. 10
0
class TearingTool(NavigationTool):
	"""
	Represents a dangling tool to remove (tear) buildings.
	"""
	tear_selection_color = (255, 255, 255)
	nearby_objects_radius = 4

	def __init__(self, session):
		super(TearingTool, self).__init__(session)
		self._transparent_instances = set() # fife instances modified for transparency
		self.coords = None
		self.selected = WeakList()
		self.oldedges = None
		self.tear_tool_active = True
		self.session.ingame_gui.hide_menu()
		self.session.selected_instances.clear()
		horizons.globals.fife.set_cursor_image("tearing")
		self._hovering_over = WeakList()
		WorldObjectDeleted.subscribe(self._on_object_deleted)

	def remove(self):
		self._mark()
		self.tear_tool_active = False
		horizons.globals.fife.set_cursor_image("default")
		WorldObjectDeleted.unsubscribe(self._on_object_deleted)
		super(TearingTool, self).remove()

	def mouseDragged(self, evt):
		coords = self.get_world_location(evt).to_tuple()
		if self.coords is None:
			self.coords = coords
		self._mark(self.coords, coords)
		evt.consume()

	def mouseMoved(self, evt):
		super(TearingTool, self).mouseMoved(evt)
		coords = self.get_world_location(evt).to_tuple()
		self._mark(coords)
		evt.consume()

	def on_escape(self):
		self.session.ingame_gui.set_cursor()

	def mouseReleased(self, evt):
		"""Tear selected instances and set selection tool as cursor"""
		self.log.debug("TearingTool: mouseReleased")
		if evt.getButton() == fife.MouseEvent.LEFT:
			coords = self.get_world_location(evt).to_tuple()
			if self.coords is None:
				self.coords = coords
			self._mark(self.coords, coords)
			selection_list_copy = [building for building in self.selected]
			for building in selection_list_copy:
				self.session.view.renderer['InstanceRenderer'].removeColored(building._instance)
				if (not building.id in BUILDINGS.EXPAND_RANGE) or self.confirm_ranged_delete(building):
					Tear(building).execute(self.session)
			else:
				if self._hovering_over:
					# we're hovering over a building, but none is selected, so this tear action isn't allowed
					warehouses = [ b for b in self._hovering_over if
					               b.id == BUILDINGS.WAREHOUSE and b.owner.is_local_player]
					if warehouses:
						# tried to tear a warehouse, this is especially non-tearable
						pos = warehouses[0].position.origin
						self.session.ingame_gui.message_widget.add(point=pos, string_id="WAREHOUSE_NOT_TEARABLE" )

			self.selected = WeakList()
			self._hovering_over = WeakList()
			if not evt.isShiftPressed() and not horizons.globals.fife.get_uh_setting('UninterruptedBuilding'):
				self.tear_tool_active = False
				self.on_escape()
			evt.consume()
			
	def confirm_ranged_delete(self, building):
			buildings_to_destroy = len(Tear.additional_removals_after_tear(building)[0])
			if buildings_to_destroy == 0:
				return True
			
			title = _("Destroy all buildings")
			msg = _("This will destroy all the buildings that fall outside of"
		            " the settlement range.")
			msg += u"\n\n"
			msg += N_("%s additional building will be destroyed.",
		              "%s additional buildings will be destroyed",
		              buildings_to_destroy) % buildings_to_destroy
			return building.session.ingame_gui.show_popup(title, msg, show_cancel_button=True)

	def mousePressed(self, evt):
		if evt.getButton() == fife.MouseEvent.RIGHT:
			self.on_escape()
		elif evt.getButton() == fife.MouseEvent.LEFT:
			self.coords = self.get_world_location(evt).to_tuple()
			self._mark(self.coords)
		else:
			return
		self.tear_tool_active = False
		evt.consume()

	def _mark(self, *edges):
		"""Highights building instances and keeps self.selected up to date."""
		self._restore_transparent_instances()
		self.log.debug("TearingTool: mark")
		if len(edges) == 1:
			edges = (edges[0], edges[0])
		elif len(edges) == 2:
			edges = ((min(edges[0][0], edges[1][0]), min(edges[0][1], edges[1][1])),
					 (max(edges[0][0], edges[1][0]), max(edges[0][1], edges[1][1])))
		else:
			edges = None
		if self.oldedges != edges or edges is None:
			for i in self.selected:
				self.session.view.renderer['InstanceRenderer'].removeColored(i._instance)
			self.selected = WeakList()
			self.oldedges = edges
		if edges is not None:
			self._hovering_over = WeakList()
			for x in xrange(edges[0][0], edges[1][0] + 1):
				for y in xrange(edges[0][1], edges[1][1] + 1):
					b = self.session.world.get_building(Point(x, y))
					if b is not None:
						if b not in self._hovering_over:
							self._hovering_over.append(b)
							self._make_surrounding_transparent(b)
							self._remove_object_transparency(Point(x,y))
						if b.tearable and b.owner is not None and b.owner.is_local_player:
							if b not in self.selected:
								self._make_surrounding_transparent(b)
								self.selected.append(b)
								self._remove_object_transparency(Point(x,y))
			for i in self.selected:
				self.session.view.renderer['InstanceRenderer'].addColored(i._instance,
				                                                          *self.tear_selection_color)
		self.log.debug("TearingTool: mark done")

	def _remove_object_transparency(self, coords):
		"""helper function, used to remove transparency from object hovered upon,
		identified through its coordinates"""
		tile = self.session.world.get_tile(coords)
		if tile.object is not None and tile.object.buildable_upon:
			inst = tile.object.fife_instance
			inst.get2dGfxVisual().setTransparency(0)

	def _make_surrounding_transparent(self, building):
		"""Makes the surrounding of building_position transparent"""
		world_contains = self.session.world.map_dimensions.contains_without_border
		for coord in building.position.get_radius_coordinates(self.nearby_objects_radius, include_self=True):
			p = Point(*coord)
			if not world_contains(p):
				continue
			tile = self.session.world.get_tile(p)
			if tile.object is not None and tile.object.buildable_upon:
				inst = tile.object.fife_instance
				inst.get2dGfxVisual().setTransparency(BUILDINGS.TRANSPARENCY_VALUE)
				self._transparent_instances.add(weakref.ref(inst))

	def _restore_transparent_instances(self):
		"""Removes transparency"""
		for inst_weakref in self._transparent_instances:
			fife_instance = inst_weakref()
			if fife_instance:
				# remove transparency only if trees aren't supposed to be transparent as default
				if not hasattr(fife_instance, "keep_translucency") or not fife_instance.keep_translucency:
					fife_instance.get2dGfxVisual().setTransparency(0)
				else:
					# restore regular translucency value, can also be different
					fife_instance.get2dGfxVisual().setTransparency( BUILDINGS.TRANSPARENCY_VALUE )
		self._transparent_instances.clear()

	def _on_object_deleted(self, message):
		self.log.debug("TearingTool: on deletion notification %s", message.worldid)
		if message.sender in self.selected:
			self.log.debug("TearingTool: deleted obj present")
			self.selected.remove(message.sender)
class TearingTool(NavigationTool):
	"""
	Represents a dangling tool to remove (tear) buildings.
	"""
	tear_selection_color = (255, 255, 255)

	def __init__(self, session):
		super(TearingTool, self).__init__(session)
		self.coords = None
		self.selected = WeakList()
		self.oldedges = None
		self.tear_tool_active = True
		self.session.ingame_gui.hide_menu()
		self.session.selected_instances.clear()
		horizons.globals.fife.set_cursor_image("tearing")
		self._hovering_over = WeakList()
		WorldObjectDeleted.subscribe(self._on_object_deleted)

	def remove(self):
		self._mark()
		self.tear_tool_active = False
		horizons.globals.fife.set_cursor_image("default")
		WorldObjectDeleted.unsubscribe(self._on_object_deleted)
		super(TearingTool, self).remove()

	def mouseDragged(self, evt):
		coords = self.get_world_location(evt).to_tuple()
		if self.coords is None:
			self.coords = coords
		self._mark(self.coords, coords)
		evt.consume()

	def mouseMoved(self, evt):
		super(TearingTool, self).mouseMoved(evt)
		coords = self.get_world_location(evt).to_tuple()
		self._mark(coords)
		evt.consume()

	def on_escape(self):
		self.session.ingame_gui.set_cursor()

	def mouseReleased(self, evt):
		"""Tear selected instances and set selection tool as cursor"""
		self.log.debug("TearingTool: mouseReleased")
		if evt.getButton() == fife.MouseEvent.LEFT:
			coords = self.get_world_location(evt).to_tuple()
			if self.coords is None:
				self.coords = coords
			self._mark(self.coords, coords)
			for i in [i for i in self.selected]:
				self.session.view.renderer['InstanceRenderer'].removeColored(i._instance)
				Tear(i).execute(self.session)
			else:
				if self._hovering_over:
					# we're hovering over a building, but none is selected, so this tear action isn't allowed
					warehouses = [ b for b in self._hovering_over if
					               b.id == BUILDINGS.WAREHOUSE ]
					if warehouses:
						# tried to tear a warehouse, this is especially non-tearable
						pos = warehouses[0].position.origin
						self.session.ingame_gui.message_widget.add(point=pos, string_id="WAREHOUSE_NOT_TEARABLE" )

			self.selected = WeakList()
			self._hovering_over = WeakList()

			if not evt.isShiftPressed() and not horizons.globals.fife.get_uh_setting('UninterruptedBuilding'):
				self.tear_tool_active = False
				self.on_escape()
			evt.consume()

	def mousePressed(self, evt):
		if evt.getButton() == fife.MouseEvent.RIGHT:
			self.on_escape()
		elif evt.getButton() == fife.MouseEvent.LEFT:
			self.coords = self.get_world_location(evt).to_tuple()
			self._mark(self.coords)
		else:
			return
		self.tear_tool_active = False
		evt.consume()

	def _mark(self, *edges):
		"""Highights building instances and keeps self.selected up to date."""
		self.log.debug("TearingTool: mark")
		if len(edges) == 1:
			edges = (edges[0], edges[0])
		elif len(edges) == 2:
			edges = ((min(edges[0][0], edges[1][0]), min(edges[0][1], edges[1][1])),
					 (max(edges[0][0], edges[1][0]), max(edges[0][1], edges[1][1])))
		else:
			edges = None
		if self.oldedges != edges or edges is None:
			for i in self.selected:
				self.session.view.renderer['InstanceRenderer'].removeColored(i._instance)
			self.selected = WeakList()
			self.oldedges = edges
		if edges is not None:
			self._hovering_over = WeakList()
			for x in xrange(edges[0][0], edges[1][0] + 1):
				for y in xrange(edges[0][1], edges[1][1] + 1):
					b = self.session.world.get_building(Point(x, y))
					if b is not None:
						if b not in self._hovering_over:
							self._hovering_over.append(b)
						if b.tearable and b.owner is not None and b.owner.is_local_player:
							if b not in self.selected:
								self.selected.append(b)
			for i in self.selected:
				self.session.view.renderer['InstanceRenderer'].addColored(i._instance,
				                                                          *self.tear_selection_color)
		self.log.debug("TearingTool: mark done")


	def _on_object_deleted(self, message):
		self.log.debug("TearingTool: on deletion notification %s", message.worldid)
		if message.sender in self.selected:
			self.log.debug("TearingTool: deleted obj present")
			self.selected.remove(message.sender)
Esempio n. 12
0
class TearingTool(NavigationTool):
	"""
	Represents a dangling tool to remove (tear) buildings.
	"""
	tear_selection_color = (255, 255, 255)
	nearby_objects_radius = 4

	def __init__(self, session):
		super(TearingTool, self).__init__(session)
		self._transparent_instances = set() # fife instances modified for transparency
		self.coords = None
		self.selected = WeakList()
		self.oldedges = None
		self.tear_tool_active = True
		self.session.ingame_gui.hide_menu()
		self.session.selected_instances.clear()
		horizons.globals.fife.set_cursor_image("tearing")
		self._hovering_over = WeakList()
		WorldObjectDeleted.subscribe(self._on_object_deleted)

	def remove(self):
		self._mark()
		self.tear_tool_active = False
		horizons.globals.fife.set_cursor_image("default")
		WorldObjectDeleted.unsubscribe(self._on_object_deleted)
		super(TearingTool, self).remove()

	def mouseDragged(self, evt):
		coords = self.get_world_location(evt).to_tuple()
		if self.coords is None:
			self.coords = coords
		self._mark(self.coords, coords)
		evt.consume()

	def mouseMoved(self, evt):
		super(TearingTool, self).mouseMoved(evt)
		coords = self.get_world_location(evt).to_tuple()
		self._mark(coords)
		evt.consume()

	def on_escape(self):
		self.session.ingame_gui.set_cursor()

	def mouseReleased(self, evt):
		"""Tear selected instances and set selection tool as cursor"""
		self.log.debug("TearingTool: mouseReleased")
		if evt.getButton() == fife.MouseEvent.LEFT:
			coords = self.get_world_location(evt).to_tuple()
			if self.coords is None:
				self.coords = coords
			self._mark(self.coords, coords)
			selection_list_copy = [building for building in self.selected]
			if self.selected:
				for building in selection_list_copy:
					self.session.view.renderer['InstanceRenderer'].removeColored(building._instance)
					if (building.id not in BUILDINGS.EXPAND_RANGE) or self.confirm_ranged_delete(building):
						Tear(building).execute(self.session)
			elif self._hovering_over:
				# we're hovering over a building, but none is selected, so this tear action isn't allowed
				warehouses = [ b for b in self._hovering_over if
					       b.id == BUILDINGS.WAREHOUSE and b.owner.is_local_player]
				if warehouses:
					# tried to tear a warehouse, this is especially non-tearable
					pos = warehouses[0].position.origin
					self.session.ingame_gui.message_widget.add(point=pos, string_id="WAREHOUSE_NOT_TEARABLE" )

			self.selected = WeakList()
			self._hovering_over = WeakList()
			if not evt.isShiftPressed() and not horizons.globals.fife.get_uh_setting('UninterruptedBuilding'):
				self.tear_tool_active = False
				self.on_escape()
			evt.consume()

	def confirm_ranged_delete(self, building):
			buildings_to_destroy = len(Tear.additional_removals_after_tear(building)[0])
			if buildings_to_destroy == 0:
				return True

			title = T("Destroy all buildings")
			msg = T("This will destroy all the buildings that fall outside of"
		            " the settlement range.")
			msg += u"\n\n"
			msg += NT("%s additional building will be destroyed.",
		              "%s additional buildings will be destroyed",
		              buildings_to_destroy) % buildings_to_destroy
			return building.session.ingame_gui.open_popup(title, msg, show_cancel_button=True)

	def mousePressed(self, evt):
		if evt.getButton() == fife.MouseEvent.RIGHT:
			self.on_escape()
		elif evt.getButton() == fife.MouseEvent.LEFT:
			self.coords = self.get_world_location(evt).to_tuple()
			self._mark(self.coords)
		else:
			return
		self.tear_tool_active = False
		evt.consume()

	def _mark(self, *edges):
		"""Highights building instances and keeps self.selected up to date."""
		self._restore_transparent_instances()
		self.log.debug("TearingTool: mark")
		if len(edges) == 1:
			edges = (edges[0], edges[0])
		elif len(edges) == 2:
			edges = ((min(edges[0][0], edges[1][0]), min(edges[0][1], edges[1][1])),
					 (max(edges[0][0], edges[1][0]), max(edges[0][1], edges[1][1])))
		else:
			edges = None
		if self.oldedges != edges or edges is None:
			for i in self.selected:
				self.session.view.renderer['InstanceRenderer'].removeColored(i._instance)
			self.selected = WeakList()
			self.oldedges = edges
		if edges is not None:
			self._hovering_over = WeakList()
			for x in xrange(edges[0][0], edges[1][0] + 1):
				for y in xrange(edges[0][1], edges[1][1] + 1):
					b = self.session.world.get_building(Point(x, y))
					if b is not None:
						if b not in self._hovering_over:
							self._hovering_over.append(b)
							self._make_surrounding_transparent(b)
							self._remove_object_transparency(Point(x,y))
						if b.tearable and b.owner is not None and b.owner.is_local_player:
							if b not in self.selected:
								self._make_surrounding_transparent(b)
								self.selected.append(b)
								self._remove_object_transparency(Point(x,y))
			for i in self.selected:
				self.session.view.renderer['InstanceRenderer'].addColored(i._instance,
				                                                          *self.tear_selection_color)
		self.log.debug("TearingTool: mark done")

	def _remove_object_transparency(self, coords):
		"""helper function, used to remove transparency from object hovered upon,
		identified through its coordinates"""
		tile = self.session.world.get_tile(coords)
		if tile.object is not None and tile.object.buildable_upon:
			inst = tile.object.fife_instance
			inst.get2dGfxVisual().setTransparency(0)

	def _make_surrounding_transparent(self, building):
		"""Makes the surrounding of building_position transparent"""
		world_contains = self.session.world.map_dimensions.contains_without_border
		for coord in building.position.get_radius_coordinates(self.nearby_objects_radius, include_self=True):
			p = Point(*coord)
			if not world_contains(p):
				continue
			tile = self.session.world.get_tile(p)
			if tile.object is not None and tile.object.buildable_upon:
				inst = tile.object.fife_instance
				inst.get2dGfxVisual().setTransparency(BUILDINGS.TRANSPARENCY_VALUE)
				self._transparent_instances.add(weakref.ref(inst))

	def _restore_transparent_instances(self):
		"""Removes transparency"""
		for inst_weakref in self._transparent_instances:
			fife_instance = inst_weakref()
			if fife_instance:
				# remove transparency only if trees aren't supposed to be transparent as default
				if not hasattr(fife_instance, "keep_translucency") or not fife_instance.keep_translucency:
					fife_instance.get2dGfxVisual().setTransparency(0)
				else:
					# restore regular translucency value, can also be different
					fife_instance.get2dGfxVisual().setTransparency( BUILDINGS.TRANSPARENCY_VALUE )
		self._transparent_instances.clear()

	def _on_object_deleted(self, message):
		self.log.debug("TearingTool: on deletion notification %s", message.worldid)
		if message.sender in self.selected:
			self.log.debug("TearingTool: deleted obj present")
			self.selected.remove(message.sender)