File: LayerTool.py

package info (click to toggle)
fife 0.3.3%2Br3-3
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 16,312 kB
  • sloc: cpp: 83,234; python: 16,261; sh: 10,134; xml: 3,435; makefile: 265; objc: 245; ansic: 229
file content (392 lines) | stat: -rw-r--r-- 12,534 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
# -*- coding: utf-8 -*-

# ####################################################################
#  Copyright (C) 2005-2009 by the FIFE team
#  http://www.fifengine.de
#  This file is part of FIFE.
#
#  FIFE is free software; you can redistribute it and/or
#  modify it under the terms of the GNU Lesser General Public
#  License as published by the Free Software Foundation; either
#  version 2.1 of the License, or (at your option) any later version.
#
#  This library is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#  Lesser General Public License for more details.
#
#  You should have received a copy of the GNU Lesser General Public
#  License along with this library; if not, write to the
#  Free Software Foundation, Inc.,
#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
# ####################################################################

""" A layer tool for FIFedit """

from fife import fife
from fife.extensions import pychan
import fife.extensions.pychan.widgets as widgets
from fife.extensions.pychan.tools import callbackWithArguments as cbwa

import scripts.plugin as plugin
import scripts.editor

from scripts.events import *
from scripts.gui.action import Action
from scripts.gui.layerdialog import LayerDialog

# plugin default settings
_PLUGIN_SETTINGS = {
	'module' : "LayerToolSettings",
	'items' : {
		'dockarea' : 'left',
		'docked' : True,
		
	},
}

class LayerTool(plugin.Plugin):
	""" The B{LayerTool} allows to select and show / hide layers of a loaded
		map as well as creating new layers or edit layer properties
	"""
	
	# default should be pychan default, highlight can be choosen (format: r,g,b)
	DEFAULT_BACKGROUND_COLOR = pychan.internal.DEFAULT_STYLE['default']['base_color']
	HIGHLIGHT_BACKGROUND_COLOR = pychan.internal.DEFAULT_STYLE['default']['selection_color']

	# the dynamicly created widgets have the name scheme prefix + layerid
	LABEL_NAME_PREFIX = "select_"

	def __init__(self):	
		super(LayerTool, self).__init__()
		# Editor instance
		self._editor = scripts.editor.getEditor()
		
		# Plugin variables
		self._enabled = False
		
		# Current mapview
		self._mapview = None
		
		# Toolbar button to display LayerTool
		self._action_show = None
		
		# GUI
		self._layer_wizard = None
		self.container = None
		self.wrapper = None
		self.remove_layer_button = None
		self.create_layer_button = None
		self.edit_layer_button = None
		
		self.default_settings = _PLUGIN_SETTINGS
		self.eds = self._editor._settings
		self.update_settings()
			
	#--- Plugin functions ---#
	def enable(self):
		""" Enable plugin """
		if self._enabled: return
			
		# Fifedit plugin data
		self._action_show = Action(u"LayerTool", checkable=True)
		scripts.gui.action.activated.connect(self.toggle, sender=self._action_show)
		self._editor._tools_menu.addAction(self._action_show)

		self.create()
		self.toggle()
		
		events.postMapShown.connect(self.update)
		events.preMapClosed.connect(self._mapClosed)
		
		if self.settings['docked']:
			self._editor.dockWidgetTo(self.container, self.settings['dockarea'])

	def disable(self):
		""" Disable plugin """
		if not self._enabled: return
		
		self.container.setDocked(False)
		self.container.hide()
		
		events.postMapShown.disconnect(self.update)
		events.preMapClosed.disconnect(self._mapClosed)
		
		self._editor._tools_menu.removeAction(self._action_show)

	def isEnabled(self):
		""" Returns True if plugin is enabled """
		return self._enabled;

	def getName(self):
		""" Return plugin name """
		return u"Layertool"
	
	#--- End plugin functions ---#
	def _mapClosed(self):
		self.update(mapview=None)
		
	
	def showLayerWizard(self):
		""" Show layer wizard """
		if not self._mapview: return
		
		if self._layer_wizard: self._layer_wizard._widget.hide()
		self._layer_wizard = LayerDialog(self._editor.getEngine(), self._mapview.getMap(), callback=self._layerCreated)
		
	def showEditDialog(self):
		""" Show layerdialog for active layer """
		if not self._mapview: return
		layer = self.getActiveLayer()
		if not layer: return
		
		if self._layer_wizard: self._layer_wizard._widget.hide()
		self._layer_wizard = LayerDialog(self._editor.getEngine(), self._mapview.getMap(), layer=layer, callback=cbwa(self.update, self._mapview))
		
	def clear(self):
		""" Remove all subwrappers """
		self.wrapper.removeAllChildren()
		
	def update(self, mapview):
		""" Update layertool with information from mapview
		
		We group one ToggleButton and one Label into a HBox, the main wrapper
		itself is a VBox and we also capture both the Button and the Label to listen
		for mouse actions
		
		@type	event:	object
		@param	event:	pychan mouse event
		"""
		layers = []
		self._mapview = mapview
		if self._mapview is not None:
			layers = self._mapview.getMap().getLayers()
		
		self.clear()
		
		if len(layers) <= 0:
			if not self._mapview:
				layerid = "No map is open"
			else:
				layerid = "No layers"
			subwrapper = pychan.widgets.HBox()

			layerLabel = pychan.widgets.Label()
			layerLabel.text = unicode(layerid)
			layerLabel.name = LayerTool.LABEL_NAME_PREFIX + layerid
			subwrapper.addChild(layerLabel)
			
			self.wrapper.addChild(subwrapper)
		
		active_layer = self.getActiveLayer()
		if active_layer:
			active_layer = active_layer.getId()
		for layer in reversed(layers):
			layerid = layer.getId()
			subwrapper = pychan.widgets.HBox()

			toggleVisibleButton = pychan.widgets.ToggleButton(hexpand=0, up_image="gui/icons/is_visible.png", down_image="gui/icons/is_visible.png", hover_image="gui/icons/is_visible.png")
			toggleVisibleButton.name = "toggle_" + layerid
			if layer.areInstancesVisible():
				toggleVisibleButton.toggled = True
			toggleVisibleButton.capture(self.toggleLayerVisibility)
			
			layerLabel = pychan.widgets.Label()
			layerLabel.text = unicode(layerid)
			layerLabel.name = LayerTool.LABEL_NAME_PREFIX + layerid
			layerLabel.capture(self.selectLayer,"mousePressed")
			
			if active_layer == layerid:
				layerLabel.background_color	= LayerTool.HIGHLIGHT_BACKGROUND_COLOR
				layerLabel.foreground_color	= LayerTool.HIGHLIGHT_BACKGROUND_COLOR
				layerLabel.base_color		= LayerTool.HIGHLIGHT_BACKGROUND_COLOR
			
			subwrapper.addChild(toggleVisibleButton)
			subwrapper.addChild(layerLabel)
			
			self.wrapper.addChild(subwrapper)
		
		self.container.adaptLayout()		
			
	def toggleLayerVisibility(self, event, widget):
		""" Callback for ToggleButtons 
		
		Toggle the chosen layer visible / invisible. If the active layer is hidden,
		it will be deselected.
		
		@type	event:	object
		@param	event:	pychan mouse event
		@type	widget:	object
		@param	widget:	the pychan widget where the event occurs, transports the layer id in it's name
		"""

		layerid = widget.name[len(LayerTool.LABEL_NAME_PREFIX):]
		
		layer = self._mapview.getMap().getLayer(layerid)
		active_layer = self.getActiveLayer()
		if active_layer:
			active_layer = active_layer.getId()
		
		if layer.areInstancesVisible():
			layer.setInstancesVisible(False)
		else:
			layer.setInstancesVisible(True)
			
		if active_layer == layerid:
			self.resetSelection()
			
	def getActiveLayer(self):
		""" Returns the active layer """
		if self._mapview:
			return self._mapview.getController()._layer
		
	def selectLayer(self, event, widget=None, layerid=None):
		""" Callback for Labels 
		
		We hand the layerid over to the mapeditor module to select a 
		new active layer
		
		Additionally, we mark the active layer widget (changing base color) and reseting the previous one

		@type	event:	object
		@param	event:	pychan mouse event
		@type	widget:	object
		@param	widget:	the pychan widget where the event occurs, transports the layer id in it's name
		@type	layerid: string
		@param	layerid: the layer id
		"""
		
		if not widget and not layerid:
			print "No layer ID or widget passed to LayerTool.selectLayer"
			return
		
		if widget is not None:
			layerid = widget.name[len(LayerTool.LABEL_NAME_PREFIX):]	
		
		self.resetSelection()
		
		widget.background_color = LayerTool.HIGHLIGHT_BACKGROUND_COLOR
		widget.foreground_color = LayerTool.HIGHLIGHT_BACKGROUND_COLOR
		widget.base_color = LayerTool.HIGHLIGHT_BACKGROUND_COLOR
		
		self._mapview.getController().selectLayer(layerid)
		
	def resetSelection(self):
		""" Deselects selected layer """
		previous_active_layer = self.getActiveLayer()
		if previous_active_layer is not None:
			previous_layer_id = previous_active_layer.getId()
			previous_active_widget = self.container.findChild(name=LayerTool.LABEL_NAME_PREFIX + previous_layer_id)
			previous_active_widget.background_color = LayerTool.DEFAULT_BACKGROUND_COLOR
			previous_active_widget.foreground_color = LayerTool.DEFAULT_BACKGROUND_COLOR
			previous_active_widget.base_color = LayerTool.DEFAULT_BACKGROUND_COLOR
			previous_active_widget.text = unicode(previous_layer_id)
			
		self._mapview.getController().selectLayer(None)
		
		
	def removeSelectedLayer(self):
		""" Deletes the selected layer """
		if not self._mapview: return
		
		if self._mapview.getMap().getLayerCount() <= 1:
			print "Can't remove the last layer"
			return
		
		layer = self.getActiveLayer()
		if not layer: return
		
		self.resetSelection()
		
		map = self._mapview.getMap()		
		
		# FIFE will crash if we try to delete the layer which is in use by a camera
		# so we will set the camera to another layer instead
		for cam in map.getCameras():
			if cam.getLocationRef().getMap().getId() != map.getId():
				continue
				
			if cam.getLocation().getLayer().getId() != layer.getId():
				continue
				
			for l in map.getLayers():
				if l.getId() == layer.getId(): 
					continue
				
				cam.getLocationRef().setLayer(l)
				break
		
		map.deleteLayer(layer)
		self.update(self._mapview)

	def toggle(self):
		"""	Toggles the layertool visible / invisible and sets
			dock status 
		"""
		if self.container.isVisible() or self.container.isDocked():
			self.container.setDocked(False)
			self.container.hide()

			self._action_show.setChecked(False)
		else:
			self.container.show()
			self._action_show.setChecked(True)
			self._adjustPosition()
			
	def create(self):
		""" Create the basic gui container """
		self.container =  pychan.loadXML('gui/layertool.xml')
		self.wrapper = self.container.findChild(name="layers_wrapper")
		self.remove_layer_button = self.container.findChild(name="remove_layer_button")
		self.create_layer_button = self.container.findChild(name="add_layer_button")
		self.edit_layer_button = self.container.findChild(name="edit_layer_button")
		
		self.remove_layer_button.capture(self.removeSelectedLayer)
		self.remove_layer_button.capture(cbwa(self._editor.getStatusBar().showTooltip, self.remove_layer_button.helptext), 'mouseEntered')
		self.remove_layer_button.capture(self._editor.getStatusBar().hideTooltip, 'mouseExited')
		
		self.create_layer_button.capture(self.showLayerWizard)
		self.create_layer_button.capture(cbwa(self._editor.getStatusBar().showTooltip, self.create_layer_button.helptext), 'mouseEntered')
		self.create_layer_button.capture(self._editor.getStatusBar().hideTooltip, 'mouseExited')
		
		self.edit_layer_button.capture(self.showEditDialog)
		self.edit_layer_button.capture(cbwa(self._editor.getStatusBar().showTooltip, self.edit_layer_button.helptext), 'mouseEntered')
		self.edit_layer_button.capture(self._editor.getStatusBar().hideTooltip, 'mouseExited')
		
		self.update(None)
		
		# overwrite Panel.afterUndock
		self.container.afterUndock = self.on_undock
		self.container.afterDock = self.on_dock
		
	def on_dock(self):
		""" callback for dock event of B{Panel}	widget """
		side = self.container.dockarea.side
		if not side: return

		module = self.default_settings['module']
		self.eds.set(module, 'dockarea', side)
		self.eds.set(module, 'docked', True)
	
	def on_undock(self):
		""" callback for undock event of B{Panel} widget """
		self.container.hide()
		self.toggle()

		module = self.default_settings['module']
		self.eds.set(module, 'dockarea', '')
		self.eds.set(module, 'docked', False)				

	def _adjustPosition(self):
		"""	Adjusts the position of the container - we don't want to
		let the window appear at the center of the screen.
		(new default position: left, beneath the tools window)
		"""
		self.container.position = (50, 200)

	def _layerCreated(self, layer):
		self.update(self._mapview)
		self.selectLayer(None, self.wrapper.findChild(name=LayerTool.LABEL_NAME_PREFIX + layer.getId()))