Mercurial > parpg-source
view bGrease/component/general.py @ 124:ef24560eb920
Fixed bug that dropping an item onto another would not set the drag_data to the replaced item, which caused this to be lost.
author | KarstenBock@gmx.net |
---|---|
date | Thu, 06 Oct 2011 16:08:00 +0200 |
parents | e856b604b650 |
children |
line wrap: on
line source
############################################################################# # # Copyright (c) 2010 by Casey Duncan and contributors # All Rights Reserved. # # This software is subject to the provisions of the MIT License # A copy of the license should accompany this distribution. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # ############################################################################# __version__ = '$Id$' from parpg.bGrease.component import base from parpg.bGrease.component import field from parpg.bGrease.entity import ComponentEntitySet class Component(dict): """General component with a configurable schema The field schema is defined via keyword args where the arg name is the field name and the value is the type object. The following types are supported for fields: - :class:`int` - :class:`float` - :class:`bool` - :class:`str` - :class:`object` - |Vec2d| - |Vec2dArray| - |RGBA| - |Rect| """ deleted_entities = () """List of entities deleted from the component since the last time step""" new_entities = () """List of entities added to the component since the last time step""" def __init__(self, **fields): self.fields = {} for fname, ftype in fields.items(): assert ftype in field.types, fname + " has an illegal field type" self.fields[fname] = field.Field(self, fname, ftype) self.entities = ComponentEntitySet(self) self._added = [] self._deleted = [] def set_world(self, world): self.world = world def step(self, dt): """Update the component for the next timestep""" delitem = super(Component, self).__delitem__ for entity in self._deleted: delitem(entity) self.new_entities = self._added self.deleted_entities = self._deleted self._added = [] self._deleted = [] def set(self, entity, data=None, **data_kw): """Set the component data for an entity, adding it to the component if it is not already a member. If data is specified, its data for the new entity's fields are copied from its attributes, making it easy to copy another entity's data. Keyword arguments are also matched to fields. If both a data attribute and keyword argument are supplied for a single field, the keyword arg is used. """ if data is not None: for fname, field in self.fields.items(): if fname not in data_kw and hasattr(data, fname): data_kw[fname] = getattr(data, fname) data = self[entity] = Data(self.fields, entity, **data_kw) return data def __setitem__(self, entity, data): assert entity.world is self.world, "Entity not in component's world" if entity not in self.entities: self._added.append(entity) self.entities.add(entity) super(Component, self).__setitem__(entity, data) def remove(self, entity): if entity in self.entities: self._deleted.append(entity) self.entities.remove(entity) return True return False __delitem__ = remove def __repr__(self): return '<%s %x of %r>' % ( self.__class__.__name__, id(self), getattr(self, 'world', None)) class Singleton(Component): """Component that may contain only a single entity""" def add(self, entity_id, data=None, **data_kw): if entity_id not in self._data: self.entity_id_set.clear() self._data.clear() Component.add(self, entity_id, data, **data_kw) @property def entity(self): """Return the entity in the component, or None if empty""" if self._data: return self.manager[self._data.keys()[0]] class Data(object): def __init__(self, fields, entity, **data): self.__dict__['_Data__fields'] = fields self.__dict__['entity'] = entity for field in fields.values(): if field.name in data: setattr(self, field.name, data[field.name]) else: setattr(self, field.name, field.default()) def __setattr__(self, name, value): if name in self.__fields: self.__dict__[name] = self.__fields[name].cast(value) else: raise AttributeError("Invalid data field: " + name) def __repr__(self): return '<%s(%r)>' % (self.__class__.__name__, self.__dict__)