//////////////////////////////////////////////////////////////////////////////////////////////////// // NoesisGUI - http://www.noesisengine.com // Copyright (c) Noesis Technologies S.L. All Rights Reserved. //////////////////////////////////////////////////////////////////////////////////////////////////// #ifndef __GUI_ITEMCONTAINERGENERATOR_H__ #define __GUI_ITEMCONTAINERGENERATOR_H__ #include #include #include #include #include #include namespace Noesis { class DependencyObject; class DependencyProperty; class ItemsControl; class Panel; class ItemContainerGeneratorTest; struct NotifyCollectionChangedEventArgs; enum NotifyCollectionChangedAction: int32_t; //////////////////////////////////////////////////////////////////////////////////////////////////// /// The ItemsChanged event is raised by an ItemContainerGenerator to inform layouts that the items /// collection has changed. //////////////////////////////////////////////////////////////////////////////////////////////////// struct ItemsChangedEventArgs: public EventArgs { NotifyCollectionChangedAction action; GeneratorPosition position; GeneratorPosition oldPosition; int itemCount; int itemUICount; ItemsChangedEventArgs(NotifyCollectionChangedAction action, const GeneratorPosition& position, const GeneratorPosition& oldPosition, int itemCount, int itemUICount); ItemsChangedEventArgs(NotifyCollectionChangedAction action, const GeneratorPosition& position, int itemCount, int itemUICount); }; typedef Delegate ItemsChangedEventHandler; NS_WARNING_PUSH NS_MSVC_WARNING_DISABLE(4251 4275) //////////////////////////////////////////////////////////////////////////////////////////////////// /// Generates the user interface on behalf of its host, such as an ItemsControl. /// /// http://msdn.microsoft.com/en-us/library/system.windows.controls.itemcontainergenerator.aspx //////////////////////////////////////////////////////////////////////////////////////////////////// class NS_GUI_CORE_API ItemContainerGenerator: public BaseComponent, public IRecyclingItemContainerGenerator { public: // TODO: Expose Items as a ReadOnlyCollection /// Gets the status of the generator GeneratorStatus GetStatus() const; /// Raised to inform controls that ItemContainerGenerator status has changed DelegateEvent_ StatusChanged(); /// Raised by a ItemContainerGenerator to inform layouts that the items collection has changed DelegateEvent_ ItemsChanged(); /// Returns the container corresponding to the item at the given index within the Items DependencyObject* ContainerFromIndex(int index) const; /// Returns the container corresponding to the given item. Returns null if the item does not /// belong to the item collection, or if no container has been generated for it DependencyObject* ContainerFromItem(BaseComponent* item) const; /// Given a generated container, returns the index of the corresponding item within the Items int IndexFromContainer(DependencyObject* container) const; /// Returns the item corresponding to the given container. If the element was not generated as /// a container for this generator's host, the method returns DependencyProperty.UnsetValue BaseComponent* ItemFromContainer(DependencyObject* container) const; /// Starts a container generation batch void StartBatch(); /// Stops current container generation batch void StopBatch(); /// From IItemContainerGenerator //@{ ItemContainerGenerator* GetItemContainerGeneratorForPanel(Panel* panel) const override; GeneratorPosition GeneratorPositionFromIndex(int itemIndex) const override; int IndexFromGeneratorPosition(const GeneratorPosition& position) const override; void StartAt(const GeneratorPosition& position, GeneratorDirection direction) override; void StartAt(const GeneratorPosition& position, GeneratorDirection direction, bool allowStartAtRealizedItem) override; Ptr GenerateNext() override; Ptr GenerateNext(bool& isNewlyRealized) override; void Stop() override; void PrepareItemContainer(DependencyObject* container) const override; void Remove(const GeneratorPosition& position, uint32_t count) override; void RemoveAll() override; //@} /// From IRecyclingItemContainerGenerator //@{ void Recycle(const GeneratorPosition& position, uint32_t count) override; //@} NS_IMPLEMENT_INTERFACE_FIXUP private: friend class ItemsControl; friend class VirtualizingStackPanelTestHelper; ItemContainerGenerator(); ItemContainerGenerator(ItemsControl* host); void Refresh(); void ResetLastNodeIndex() const; void SetStatus(GeneratorStatus status); Ptr GenerateNext(bool stopAtRealized, bool& isNewlyRealized); static BaseComponent* GetContainerItem(DependencyObject* container); static void SetContainerItem(DependencyObject* container, BaseComponent* item); void OnItemsChanged(BaseComponent* sender, const NotifyCollectionChangedEventArgs& e); void OnItemAdded(BaseComponent* item, int index); void OnItemRemoved(BaseComponent* item, int index); void OnItemReplaced(BaseComponent* oldItem, BaseComponent* newItem, int index); void OnItemMoved(BaseComponent* item, int oldIndex, int newIndex); void OnReset(); void AttachContainerItem(DependencyObject* container, BaseComponent* item); void DetachContainerItem(DependencyObject* container, BaseComponent* item, bool setDisconnected); void UpdateAlternationCount(int oldValue, int newValue); private: friend class ItemContainerGeneratorHelperTest; friend class ItemContainerGeneratorTest; // Host for generator items ItemsControl* mHost; // Stores info about one (realized) or several (unrealized) items struct ItemNode { enum Type { Unrealized, Realized }; Type type; union { struct { uint32_t numItems; } unrealized; struct { BaseComponent* item; DependencyObject* container; } realized; }; ItemNode(uint32_t n = 0); ItemNode(BaseComponent* i, DependencyObject* c); ItemNode(const ItemNode& node); ItemNode(ItemNode&& node); ~ItemNode(); ItemNode& operator=(const ItemNode& node); ItemNode& operator=(ItemNode&& node); uint32_t NumItems() const; uint32_t NumContainers() const; BaseComponent* Item() const; DependencyObject* Container() const; bool MoveAllowed(bool allowMove) const; bool IsRealized() const; void Unrealize(uint32_t n); void Realize(BaseComponent* i, DependencyObject* c); private: void CopyFrom(const ItemNode& node); void MoveFrom(ItemNode& node); void UnrealizeInternal(uint32_t n); void RealizeInternal(BaseComponent* i, DependencyObject* c); void Release(); }; // Holds correspondence between Items and their Containers. Usually a group of unrealized // (virtualized) items, followed by some realized (visible) items, and a final group of // unrealized items: // // ------------ -------------- -------------- ------------ // | n | | 1 item* | | 1 item* | | n | // | unrealized | -> | 1 container* | -> ... -> | 1 container* | -> | unrealized | // ------------ -------------- -------------- ------------ // typedef Vector ItemNodes; ItemNodes mItemNodes; uint32_t mNumItems; void Remove(const GeneratorPosition& position, uint32_t count, bool recycleContainers, const char* actionName); void Remove(uint32_t startIt, int startIndex, uint32_t count, bool allowUnrealizedItems, bool recycleContainers, const char* actionName); int RemoveItem(uint32_t it); void CoalesceNodes(uint32_t prevIt, uint32_t nextIt); uint32_t FindNodeFromIndex(int index, int& itemIndex, int& offset); void MoveForward(); void MoveForward(int offset, bool allowStartAtRealizedItem); void MoveBackward(); void MoveBackward(int offset, bool allowStartAtRealizedItem); // Stores recycled containers to be used in future generations typedef Vector> RecycledContainers; RecycledContainers mRecycledContainers; // Generator status GeneratorStatus mStatus; bool mBatching; // Generation state GeneratorDirection mDirection; uint32_t mNode; // node where next generation should occur int mOffset; // offset inside the current node where next generation should occur int mItemIndex; // index of next generated item // Events EventHandler mStatusChanged; ItemsChangedEventHandler mItemsChanged; // Stores a reference to the item in the container to speed up some searches static const DependencyProperty* ContainerItemProperty; // Optimization for ContainerFromIndex look-ups mutable uint32_t mLastNode; mutable int mLastIndex; NS_DECLARE_REFLECTION(ItemContainerGenerator, BaseComponent) }; NS_WARNING_POP } #include #endif