windows-nt/Source/XPSP1/NT/public/internal/windows/inc/duser/duielement.h

1231 lines
53 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*
* Element
*/
#ifndef DUI_CORE_ELEMENT_H_INCLUDED
#define DUI_CORE_ELEMENT_H_INCLUDED
#pragma once
#include "duivalue.h"
#include "duievent.h"
#include "duisheet.h"
#include "duilayout.h"
struct IAccessible;
namespace DirectUI
{
#if DBG
extern UINT g_cGetDep;
extern UINT g_cGetVal;
extern UINT g_cOnPropChg;
#endif
class DuiAccessible;
// TODO: Switch DUI listeners to use DirectUser MessageHandlers
/*
* Element Properties
*
* Element provides default behavior for Get/SetValue based on the flags used in PropertyInfo.
* The Flags also define what indicies are available during property operations.
*
* Get/SetValue cannot be overridden. Rather, a default implemention is supplied for GetValue's
* on all properties. By default, Get's on the Specified and Computed index are handled by a
* built-in Value Expression (VE) while Get's on Local query a local store (see below for exact
* default behavior). However, various system properties override this default behavior with
* different unchangable Value Expressions (implicit VEs) in the Local and Computed indicies.
*
* End users will use Normal properties and may occasionally use LocalOnly properties. Although
* available to derived classes, TriLevel property functionaly is only useful by the system.
*
* All property value must be available generically through GetValue.
*
* Flags supported (default behavior):
*
* "LocalOnly"
* Indicies: Local
* Get: Retrieve local value from Element. If none is set, 'Unset' returned.
* Set: Stores value locally on the Element.
* Dependents: None
* Modifiers: Readonly: Disallow Set
*
* "Normal"
* Indicies: Local, Specified (implicit VE)
* Get: Local: Retrieve local value from Element. If none is set, 'Unset' returned.
* Specified: Does a Get on the Local value. If 'Unset', return Property Sheet value
* if Cascade modifier is set. If 'Unset', return parent's value if Inherit
* modifier is set. If 'Unset' return property's Default value.
* Automatically evaulate value expressions before return.
* Set: Local: Stores value locally on the Element.
* Specified: Unsupported.
* Dependents: Specified is dependent on Local.
* Modifiers: Readonly: Disallow Set for Local.
* Cascade: Used with Specified Get (see Get description).
* Inherit: Used with Specified Get (see Get description).
*
* "TriLevel"
* Indicies: Local, Specified (implicit VE), Computed (implicit VE)
* Get: Local: Retrieve local value from Element. If none is set, 'Unset' returned.
* Specified: Does a Get on the Local value. If 'Unset', return Property Sheet value
* if Cascade modifier is set. If 'Unset', return parent's value if Inherit
* modifier is set. If 'Unset' return property's Default value.
* Automatically evaulate value expressions before return.
* Computed: Does a get of the Specified value.
* Set: Local: Stores value locally on the Element.
* Specified: Unsupported.
* Computed: Unsupported.
* Dependents: Computed is dependent on Specified. Specified is dependent on Local.
* Modifiers: Readonly: Disallow Set for Local.
* Cascade: Used with Specified Get (see Get description).
* Inherit: Used with Specified Get (see Get description).
*
* SetValue must always be used by derived classes. However, SetValue is sometimes bypassed and
* Pre/PostSourceChange is called directly in the case of LocalOnly properties that are ReadOnly
* and are cached directly on the Element (optimization). All other ReadOnly sets use
* _SetValue since generic storage (of Values) is used. SetValue is used in all other cases.
*
* For ReadOnly values, if storing the value is cheap (i.e. bools) and interit and style sheet
* functionality is not required, it is best to not use generic storage (_SetValue). Rather,
* write the value directly and call Pre/PostSourceChange directly ("LocalOnly property).
* Otherwise, if a ReadOnly value requires inheritance and/or sheet lookups, or the value is
* seldom different than a default value, use _SetValue (generic storage, "Normal" property).
*
* For Normal/ReadOnly, use SetValue, For LocalOnly/ReadOnly, use _SetValue,
* For internal LocalOnly/ReadOnly, set and store manually (no generic storage)
*
* All property values must be settable generically via SetValue except ReadOnly properties.
* Any "LocalOnly" property that doesn't use generic storage must initialize their members
* at construction to the property's default value. "Normal" properties will choose the
* default value automatically when queried. All derived classes (external) will use "Normal"
* properties.
*
* SetValue only accepts the PI_Local index. ReadOnly sets do not fire OnPropertyChanging.
* All value sets must result in a PreSourceChange, followed by the store update (in which GetValue
* will retrieve values from), followed by a PostSourceChange. OnPropertyChange and old value
* compare are optional.
*
* Set values are updated immediately (i.e. an immediate GetValue after will produce the updated
* result). Location and Extent are updated after the defer cycle ends (EndDefer, SetValues are internal).
*/
/*
* Element Multithreading
*
* Elements have context affinity. A single thread is allowed per context. This thread
* is owned by the context. Only that thread may be allowed to access objects in its
* context. This requirement is not enforced in this library. The caller application
* must ensure access to objects in a context happens via the owned thread.
*
* A Proxy class is provided to invoke methods on objects from an out-of-context thread.
*
* The library supports multiple instances in the same process. This would happen by
* linking the library to multiple process modules. The only restriction is a thread
* must access a set of objects consistantly with the same instance of the library code.
*
*/
/*
* Error Reporting
*
* Conditions that would affect the stability of DirectUI are reported. Some conditions are
* only reported in Debug builds, and other in both Release and Debug
*
* Debug time reporting:
* Erroneous states are reported in Debug (checked) builds. An erroneous state arises
* when a programming error is found or when invalid arguments are passed to a method.
* Erroneous states cause raising of asserts
*
* Release time reporting:
* Abnormal states (such as out of memory or resources) that result in a serious condition
* (crash or very irregular state) are reported via HRESULTs. Any DUI API that can fail due to
* these types of abnormal states returns an HRESULT. If a method fails, it will recover.
* Some methods (such as object creation methods) will recover by freeing any memory or
* resources allocated within that method (resulting of a complete undo of all the work it
* accomplished up to the point of the failure). Other methods (such as rendering and the defer
* cycle) will do as much work as possible. Upon a failure, they will return an 'incomplete'
* error, however, they would have not completed. Failures do not result in crashes or irregular
* state. Failures are ignored in callbacks
*/
typedef int (__cdecl *CompareCallback)(const void*, const void*);
// Property indicies
#define PI_Local 1
#define PI_Specified 2
#define PI_Computed 3
// Property flags
#define PF_LocalOnly 0x01
#define PF_Normal 0x02
#define PF_TriLevel 0x03
#define PF_Cascade 0x04
#define PF_Inherit 0x08
#define PF_ReadOnly 0x10
#define PF_TypeBits 0x03 // Map out for LocalOnly, Normal, or Trilevel
// For use in OnPropertyChanged, mask out non-retrieval index property changes
#define IsProp(p) ((p##Prop == ppi) && ((ppi->fFlags&PF_TypeBits) == iIndex))
#define RetIdx(p) (p->fFlags&PF_TypeBits)
// Property groups
#define PG_AffectsDesiredSize 0x00000001 // Normal priority
#define PG_AffectsParentDesiredSize 0x00000002
#define PG_AffectsLayout 0x00000004
#define PG_AffectsParentLayout 0x00000008
#define PG_AffectsBounds 0x00010000 // Low priority
#define PG_AffectsDisplay 0x00020000
#define PG_NormalPriMask 0x0000FFFF
#define PG_LowPriMask 0xFFFF0000
// Layout cycle queue modes
#define LC_Pass 0
#define LC_Normal 1
#define LC_Optimize 2
// todo: get these from accessibility
#define GA_NOTHANDLED ((Element*) -1)
// to be internal
#define NAV_LOGICAL 0x00000001 // unset == directional
#define NAV_FORWARD 0x00000002 // unset == backward
#define NAV_VERTICAL 0x00000004 // unset == horizontal
#define NAV_RELATIVE 0x00000008 // unset == absolute
// to be exposed
#define NAV_FIRST (NAV_FORWARD | NAV_LOGICAL)
#define NAV_LAST (NAV_LOGICAL)
#define NAV_UP (NAV_RELATIVE | NAV_VERTICAL)
#define NAV_DOWN (NAV_RELATIVE | NAV_VERTICAL | NAV_FORWARD)
#define NAV_LEFT (NAV_RELATIVE)
#define NAV_RIGHT (NAV_RELATIVE | NAV_FORWARD)
#define NAV_NEXT (NAV_RELATIVE | NAV_FORWARD | NAV_LOGICAL)
#define NAV_PREV (NAV_RELATIVE | NAV_LOGICAL)
// to be exposed
#define DIRECTION_LTR 0
#define DIRECTION_RTL 1
// Asynchronous destroy message (must be async to ensure outstanding
// defer pointers are cleared)
#define GM_DUIASYNCDESTROY GM_USER - 1
////////////////////////////////////////////////////////
// PropertyInfo
struct IClassInfo;
struct EnumMap
{
LPCWSTR pszEnum;
int nEnum;
};
struct PropertyInfo
{
WCHAR szName[81];
int fFlags;
int fGroups;
int* pValidValues;
EnumMap* pEnumMaps;
Value* pvDefault;
int _iIndex; // Class-wide unique id (zero-based consecutive, set by ClassInfo)
int _iGlobalIndex; // Process-wide unique id (zero-based consecutive, set by ClassInfo (manually set for Element))
IClassInfo* _pciOwner; // Class that this property is defined on (direct owner, not inherited-by)
};
class Element;
////////////////////////////////////////////////////////
// UpdateCache
struct UpdateCache
{
Element* peSrc;
PropertyInfo* ppiSrc;
int iIndexSrc;
Value* pvOldSrc;
Value* pvNewSrc;
};
////////////////////////////////////////////////////////
// Dependencies
struct Dependency
{
Element* pe;
PropertyInfo* ppi;
int iIndex;
};
// Track dependency records in PC list
struct DepRecs
{
int iDepPos;
int cDepCnt;
};
struct NavReference
{
void Init(Element* pe, RECT* prc);
UINT cbSize;
Element* pe;
RECT* prc;
};
////////////////////////////////////////////////////////
// Class information interface
// Used so that a class will not be linked out if a class is not referred to
// (and is only referred by the parser)
#define UsingDUIClass(classn) static IClassInfo* _DUI__pCI##classn = ##classn::Class
struct IClassInfo
{
virtual HRESULT CreateInstance(OUT Element** ppElement) = 0;
virtual PropertyInfo* EnumPropertyInfo(UINT nEnum) = 0; // Includes base classes
virtual UINT GetPICount() = 0; // Includes base classes
virtual UINT GetGlobalIndex() = 0;
virtual IClassInfo* GetBaseClass() = 0;
virtual LPCWSTR GetName() = 0;
virtual bool IsValidProperty(PropertyInfo* ppi) = 0;
virtual bool IsSubclassOf(IClassInfo* pci) = 0;
virtual void Destroy() = 0;
};
////////////////////////////////////////////////////////
// Element Listener interface
struct IElementListener
{
virtual void OnListenerAttach(Element* peFrom) = 0;
virtual void OnListenerDetach(Element* peFrom) = 0;
virtual bool OnListenedPropertyChanging(Element* peFrom, PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew) = 0;
virtual void OnListenedPropertyChanged(Element* peFrom, PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew) = 0;
virtual void OnListenedInput(Element* peFrom, InputEvent* pInput) = 0;
virtual void OnListenedEvent(Element* peFrom, Event* pEvent) = 0;
};
#if DBG
////////////////////////////////////////////////////////
// Track "owner" context of this instance to validation that threads that don't
// belong to the context don't access the object.
//
// For side-by-side library support, also store the TLS slot of the instance
// of the library in the process that created this object. This will ensure the
// thread is using the correct library instance to access the object.
struct Owner
{
HDCONTEXT hCtx;
DWORD dwTLSSlot;
};
#endif
////////////////////////////////////////////////////////
// Element
typedef DynamicArray<Element*> ElementList;
class DeferCycle;
struct PCRecord;
#define EC_NoGadgetCreate 0x1 // Do not create DisplayNode, must be created within constructor override
#define EC_SelfLayout 0x2 // Element will lay out children (via self layout callbacks)
class Element
{
public:
////////////////////////////////////////////////////////
// Construction / destruction
static HRESULT Create(UINT nCreate, OUT Element** ppe);
HRESULT Destroy(bool fDelayed = true); // Destroy self
HRESULT DestroyAll(); // Destroy all children
Element() { }
virtual ~Element();
HRESULT Initialize(UINT nCreate);
////////////////////////////////////////////////////////
// Properties (impl in property.cpp)
// Accessors
Value* GetValue(PropertyInfo* ppi, int iIndex, UpdateCache* puc = NULL);
HRESULT SetValue(PropertyInfo* ppi, int iIndex, Value* pv);
// Additional property methods
HRESULT RemoveLocalValue(PropertyInfo* ppi);
// Deferring
static void StartDefer();
static void EndDefer();
// Checks
inline bool IsValidAccessor(PropertyInfo* ppi, int iIndex, bool bSetting);
static bool IsValidValue(PropertyInfo* ppi, Value* pv);
bool IsRTL() { return (GetDirection() == DIRECTION_RTL);}
// System event callbacks
virtual bool OnPropertyChanging(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew); // Direct
virtual void OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew); // Direct
virtual void OnGroupChanged(int fGroups, bool bLowPri); // Direct
virtual void OnInput(InputEvent* pInput); // Direct and bubbled
virtual void OnKeyFocusMoved(Element* peFrom, Element* peTo); // Direct and bubbled
virtual void OnMouseFocusMoved(Element* peFrom, Element* peTo); // Direct and bubbled
virtual void OnDestroy(); // Direct
// ContainerCleanup: OnLoadedFromResource(dictionary)
// Generic eventing and callback (pointer is only guaranteed good for the lifetime of the call)
void FireEvent(Event* pEvent, bool fFull = true);
virtual void OnEvent(Event* pEvent);
// Rendering callbacks
virtual void Paint(HDC hDC, const RECT* prcBounds, const RECT* prcInvalid, RECT* prcSkipBorder, RECT* prcSkipContent);
#ifdef GADGET_ENABLE_GDIPLUS
virtual void Paint(Gdiplus::Graphics* pgpgr, const Gdiplus::RectF* prcBounds, const Gdiplus::RectF* prcInvalid, Gdiplus::RectF* prSkipBorder, Gdiplus::RectF* prSkipContent);
#endif
virtual SIZE GetContentSize(int dConstW, int dConstH, Surface* psrf);
float GetTreeAlphaLevel();
// Hierarchy
HRESULT Add(Element* pe);
virtual HRESULT Add(Element** ppe, UINT cCount);
HRESULT Insert(Element* pe, UINT iInsertIdx);
virtual HRESULT Insert(Element** ppe, UINT cCount, UINT iInsertIdx);
HRESULT Add(Element* pe, CompareCallback lpfnCompare);
HRESULT SortChildren(CompareCallback lpfnCompare);
HRESULT Remove(Element* peFrom);
HRESULT RemoveAll();
virtual HRESULT Remove(Element** ppe, UINT cCount);
// Mapping and navigation
Element* FindDescendent(ATOM atomID);
void MapElementPoint(Element* peFrom, const POINT* pptFrom, POINT* pptTo);
Element* GetImmediateChild(Element* peFrom);
bool IsDescendent(Element* pe);
virtual Element* GetAdjacent(Element* peFrom, int iNavDir, NavReference const* pnr, bool bKeyable);
Element* GetKeyWithinChild();
Element* GetMouseWithinChild();
bool EnsureVisible();
bool EnsureVisible(UINT uChild);
virtual bool EnsureVisible(int x, int y, int cx, int cy);
virtual void SetKeyFocus();
// Element Listeners
HRESULT AddListener(IElementListener* pel);
void RemoveListener(IElementListener* pel);
// Effects, animate display node to match current Element state
void InvokeAnimation(int dAni, UINT nTypeMask);
void InvokeAnimation(UINT nTypes, UINT nInterpol, float flDuration, float flDelay, bool fPushToChildren = false);
void StopAnimation(UINT nTypes);
// Display node callback extension
virtual UINT MessageCallback(GMSG* pGMsg);
// Internal defer cycle and Layout-only callbacks
SIZE _UpdateDesiredSize(int dConstW, int dConstH, Surface* psrf);
void _UpdateLayoutPosition(int dX, int dY);
void _UpdateLayoutSize(int dWidth, int dHeight);
// Use in DoLayout on children where one or more properties will be changed which will
// cause a Layout GPC to be queued. This will cancel the layout GPCs and force the child
// to be included in the current layout cycle
void _StartOptimizedLayoutQ() { DUIAssertNoMsg(_fBit.fNeedsLayout != LC_Optimize); _fBit.fNeedsLayout = LC_Optimize; }
void _EndOptimizedLayoutQ() { _fBit.fNeedsLayout = LC_Normal; }
// Internal defer cycle and PropertySheet-only callbacks
static void _AddDependency(Element* pe, PropertyInfo* ppi, int iIndex, DepRecs* pdr, DeferCycle* pdc, HRESULT* phr);
// Internal DirectUser interop
static HRESULT CALLBACK _DisplayNodeCallback(HGADGET hgadCur, void * pvCur, EventMsg * pGMsg);
// Internal IUnknown interface impl
long __stdcall QueryInterface(REFIID iid, void** pvObj) { UNREFERENCED_PARAMETER(iid); UNREFERENCED_PARAMETER(pvObj); return E_NOTIMPL; }
ULONG __stdcall AddRef() { return 1; }
ULONG __stdcall Release() { return 1; }
private:
// Value update
HRESULT _GetDependencies(PropertyInfo* ppi, int iIndex, DepRecs* pdr, int iPCSrcRoot, DeferCycle* pdc);
static void _VoidPCNotifyTree(int iPCPos, DeferCycle* pdc);
// Defer cycle
static void _FlushDS(Element* pe, DeferCycle* pdc);
static void _FlushLayout(Element* pe, DeferCycle* pdc);
// Value Update
HRESULT _PreSourceChange(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew);
HRESULT _PostSourceChange();
protected:
// EC_SelfLayout flag at creation activates these methods. No external layouts are used for layout,
// rather, Element is responsible for layout (use when layout is specific and hierarchy is known)
virtual void _SelfLayoutDoLayout(int dWidth, int dHeight);
virtual SIZE _SelfLayoutUpdateDesiredSize(int dConstW, int dConstH, Surface* psrf);
// Internal Set and Remove
HRESULT _SetValue(PropertyInfo* ppi, int iIndex, Value* pv, bool fInternalCall = true);
HRESULT _RemoveLocalValue(PropertyInfo* ppi, bool fInternalCall = true);
// Natvie hosting system event callbacks and retrieval
virtual void OnHosted(Element* peNewHost); // Direct
virtual void OnUnHosted(Element* peOldHost); // Direct
void MarkHosted() { _fBit.bHosted = true; }
public:
inline void DoubleBuffered(bool fEnabled = true)
{
if (_hgDisplayNode)
SetGadgetStyle(_hgDisplayNode, (fEnabled) ? GS_BUFFERED : 0, GS_BUFFERED);
}
inline BOOL IsRoot()
{
return IsHosted() && (GetParent() == NULL);
}
// Return if being hosted by a native root
inline Element* GetRoot()
{
if (!IsHosted())
return NULL;
Element * peCur = this;
while (peCur->GetParent() != NULL)
{
peCur = peCur->GetParent();
}
return peCur;
}
static BTreeLookup<IClassInfo*>* pciMap;
// Event types
static UID KeyboardNavigate;
// Property definitions
static PropertyInfo* ParentProp; // 00
static PropertyInfo* ChildrenProp; // 01
static PropertyInfo* VisibleProp; // 02
static PropertyInfo* WidthProp; // 03
static PropertyInfo* HeightProp; // 04
static PropertyInfo* LocationProp; // 05
static PropertyInfo* ExtentProp; // 06
static PropertyInfo* XProp; // 07
static PropertyInfo* YProp; // 08
static PropertyInfo* PosInLayoutProp; // 09
static PropertyInfo* SizeInLayoutProp; // 10
static PropertyInfo* DesiredSizeProp; // 11
static PropertyInfo* LastDSConstProp; // 12
static PropertyInfo* LayoutProp; // 13
static PropertyInfo* LayoutPosProp; // 14
static PropertyInfo* BorderThicknessProp; // 15
static PropertyInfo* BorderStyleProp; // 16
static PropertyInfo* BorderColorProp; // 17
static PropertyInfo* PaddingProp; // 18
static PropertyInfo* MarginProp; // 19
static PropertyInfo* ForegroundProp; // 20
static PropertyInfo* BackgroundProp; // 21
static PropertyInfo* ContentProp; // 22
static PropertyInfo* FontFaceProp; // 23
static PropertyInfo* FontSizeProp; // 24
static PropertyInfo* FontWeightProp; // 25
static PropertyInfo* FontStyleProp; // 26
static PropertyInfo* ActiveProp; // 27
static PropertyInfo* ContentAlignProp; // 28
static PropertyInfo* KeyFocusedProp; // 29
static PropertyInfo* KeyWithinProp; // 30
static PropertyInfo* MouseFocusedProp; // 31
static PropertyInfo* MouseWithinProp; // 32
static PropertyInfo* ClassProp; // 33
static PropertyInfo* IDProp; // 34
static PropertyInfo* SheetProp; // 35
static PropertyInfo* SelectedProp; // 36
static PropertyInfo* AlphaProp; // 37
static PropertyInfo* AnimationProp; // 38
static PropertyInfo* CursorProp; // 39
static PropertyInfo* DirectionProp; // 40
static PropertyInfo* AccessibleProp; // 41
static PropertyInfo* AccRoleProp; // 42
static PropertyInfo* AccStateProp; // 43
static PropertyInfo* AccNameProp; // 44
static PropertyInfo* AccDescProp; // 45
static PropertyInfo* AccValueProp; // 46
static PropertyInfo* AccDefActionProp; // 47
static PropertyInfo* ShortcutProp; // 48
static PropertyInfo* EnabledProp; // 49
#if DBG
Owner owner;
#endif
protected:
HGADGET _hgDisplayNode;
private:
int _iIndex;
BTreeLookup<Value*>* _pvmLocal;
int _iGCSlot;
int _iGCLPSlot;
int _iPCTail;
IElementListener** _ppel;
// All "cached" values are caching resulting values from the Specified and Computed IVEs.
// All local (loc) values are for ReadOnly properties. These values are updated directly
// since it is not required to go generically through SetValue because they are ReadOnly.
// They are used often or are cheap to store (bools), so they do not use generic
// storage (via _SetValue).
// Cached and local values
Element* _peLocParent; // Parent local
POINT _ptLocPosInLayt; // Position in layout local
SIZE _sizeLocSizeInLayt; // Size in layout local
SIZE _sizeLocLastDSConst; // Last desired size constraint local
SIZE _sizeLocDesiredSize; // Desired size local
int _dSpecLayoutPos; // Cached layout position
Value* _pvSpecSheet; // Cached property sheet specified (Value cached due to destruction)
ATOM _atomSpecID; // Cached id specified
int _dSpecAlpha; // Cached alpha value
struct _BitMap
{
// Local values
bool bLocKeyWithin : 1; // 0 Keyboard within local
bool bLocMouseWithin : 1; // 1 Mouse within local
// Direct VE cache
bool bCmpVisible : 1; // 2 Cached visible computed
bool bSpecVisible : 1; // 3 Cached visible specified
UINT fSpecActive : 2; // 4 Cached active state specified
bool bSpecSelected : 1; // 5 Cached selected state specified
bool bSpecKeyFocused : 1; // 6 Cached keyboard focused state specified
bool bSpecMouseFocused : 1; // 7 Cached mouse focused state specified
UINT nSpecDirection : 1; // 8 Cached direction specified
bool bSpecAccessible : 1; // 9 Cached accessible specified
bool bSpecEnabled : 1; // 10 Cached enabled specified
// Indirect VE cache (cache if default value)
bool bHasChildren : 1; // 11 Cached children state (likely to be default value, no full cache)
bool bHasLayout : 1; // 12 Cached layout state (likely to be default value, no full cache)
bool bHasBorder : 1; // 13 Cached border state (likely to be default value, no full cache)
bool bHasPadding : 1; // 14 Cached padding state (likely to be default value, no full cache)
bool bHasMargin : 1; // 15 Cached margin state (likely to be default value, no full cache)
bool bHasContent : 1; // 16 Cached content state (likely to be default value, no full cache)
bool bDefaultCAlign : 1; // 17 Cached content align state (likely to be default value, no full cache)
bool bWordWrap : 1; // 18 Cached content align state (likely to be default value, no full cache)
bool bHasAnimation : 1; // 19 Cached animation state (likely to be default value, no full cache)
bool bDefaultCursor : 1; // 20 Cached cursor state (likely to be default value, no full cache)
bool bDefaultBorderColor : 1; // 21 Cached border color state (likely to be default value, no full cache)
bool bDefaultForeground : 1; // 22 Cached foreground state (likely to be default value, no full cache)
bool bDefaultFontWeight : 1; // 23 Cached font weight state (likely to be default value, no full cache)
bool bDefaultFontStyle : 1; // 24 Cached font style state (likely to be default value, no full cache)
// Layout and UDS flags
bool bSelfLayout : 1; // 25 Element is laying out itself (callbacks active, external layout set is undefined)
bool bNeedsDSUpdate : 1; // 26
UINT fNeedsLayout : 2; // 27
// Lifetime flags
bool bDestroyed : 1; // 28
// Hosting flags
bool bHosted : 1; // 29 Initially set by host Element directly
} _fBit;
public:
// Element DisplayNode and Index access
HGADGET GetDisplayNode() { return _hgDisplayNode; }
int GetIndex() { return _iIndex; }
bool IsDestroyed() { return _fBit.bDestroyed; }
bool IsHosted() { return _fBit.bHosted; }
// Cache state for faster property value lookup
bool IsSelfLayout() { return _fBit.bSelfLayout; }
bool HasChildren() { return _fBit.bHasChildren; } // Quick check before doing lookup
bool HasLayout() { return _fBit.bHasLayout; } // Quick check before doing lookup
bool HasBorder() { return _fBit.bHasBorder; } // Quick check before doing lookup
bool HasPadding() { return _fBit.bHasPadding; } // Quick check before doing lookup
bool HasMargin() { return _fBit.bHasMargin; } // Quick check before doing lookup
bool HasContent() { return _fBit.bHasContent; } // Quick check before doing lookup
bool IsDefaultCAlign() { return _fBit.bDefaultCAlign; } // Quick check before doing lookup
bool IsWordWrap() { return _fBit.bWordWrap; } // Quick check before doing lookup
bool HasAnimation() { return _fBit.bHasAnimation; } // Quick check before doing lookup
bool IsDefaultCursor() { return _fBit.bDefaultCursor; } // Quick check before doing lookup
// Quick property accessors (since system has knowledge of its unchangable value expressions, use cached values
// directly were possible to bypass GetValue value lookup). Quick accessors are only used during non-cache
// gets. (PostSourceChange requires GetValue directly (with update-cache flag) for cache updates.)
// All derived classes do accessors normally (no direct cache lookups)
#define DUIQuickGetter(t, gv, p, i) { Value* pv; t v = (pv = GetValue(p##Prop, PI_##i))->gv; pv->Release(); return v; }
#define DUIQuickGetterInd(gv, p, i) { return (*ppv = GetValue(p##Prop, PI_##i))->gv; }
#define DUIQuickSetter(cv, p) { Value* pv = Value::cv; if (!pv) return E_OUTOFMEMORY; HRESULT hr = SetValue(p##Prop, PI_Local, pv); pv->Release(); return hr; }
Element* GetParent() { return _peLocParent; }
bool GetVisible() { return _fBit.bCmpVisible; }
int GetWidth() DUIQuickGetter(int, GetInt(), Width, Specified)
int GetHeight() DUIQuickGetter(int, GetInt(), Height, Specified)
ElementList* GetChildren(Value** ppv) { return (*ppv = (HasChildren() ? GetValue(ChildrenProp, PI_Specified) : ChildrenProp->pvDefault))->GetElementList(); }
int GetX() DUIQuickGetter(int, GetInt(), X, Specified)
int GetY() DUIQuickGetter(int, GetInt(), Y, Specified)
Layout* GetLayout(Value** ppv) { return (*ppv = (HasLayout() ? GetValue(LayoutProp, PI_Specified) : LayoutProp->pvDefault))->GetLayout(); }
int GetLayoutPos() { return _dSpecLayoutPos; }
const RECT* GetBorderThickness(Value** ppv) { return (*ppv = (HasBorder() ? GetValue(BorderThicknessProp, PI_Specified) : BorderThicknessProp->pvDefault))->GetRect(); }
int GetBorderStyle() DUIQuickGetter(int, GetInt(), BorderStyle, Specified)
int GetBorderStdColor() DUIQuickGetter(int, GetInt(), BorderColor, Specified)
const Fill* GetBorderColor(Value** ppv) DUIQuickGetterInd(GetFill(), BorderColor, Specified)
const RECT* GetPadding(Value** ppv) { return (*ppv = (HasPadding() ? GetValue(PaddingProp, PI_Specified) : PaddingProp->pvDefault))->GetRect(); }
const RECT* GetMargin(Value** ppv) { return (*ppv = (HasMargin() ? GetValue(MarginProp, PI_Specified) : MarginProp->pvDefault))->GetRect(); }
const POINT* GetLocation(Value** ppv) DUIQuickGetterInd(GetPoint(), Location, Local)
const SIZE* GetExtent(Value** ppv) DUIQuickGetterInd(GetSize(), Extent, Local)
const SIZE* GetDesiredSize() { return &_sizeLocDesiredSize; }
int GetForegroundStdColor() DUIQuickGetter(int, GetInt(), Foreground, Specified)
const Fill* GetForegroundColor(Value** ppv) DUIQuickGetterInd(GetFill(), Foreground, Specified)
int GetBackgroundStdColor() DUIQuickGetter(int, GetInt(), Background, Specified)
const LPWSTR GetContentString(Value** ppv) { return (*ppv = (HasContent() ? GetValue(ContentProp, PI_Specified) : Value::pvStringNull))->GetString(); }
const LPWSTR GetFontFace(Value** ppv) DUIQuickGetterInd(GetString(), FontFace, Specified)
int GetFontSize() DUIQuickGetter(int, GetInt(), FontSize, Specified)
int GetFontWeight() DUIQuickGetter(int, GetInt(), FontWeight, Specified)
int GetFontStyle() DUIQuickGetter(int, GetInt(), FontStyle, Specified)
int GetActive() { return _fBit.fSpecActive; }
int GetContentAlign() { Value* pv; int v = (pv = (!IsDefaultCAlign() ? GetValue(ContentAlignProp, PI_Specified) : Value::pvIntZero))->GetInt(); pv->Release(); return v; }
bool GetKeyFocused() { return _fBit.bSpecKeyFocused; }
bool GetKeyWithin() { return _fBit.bLocKeyWithin; }
bool GetMouseFocused() { return _fBit.bSpecMouseFocused; }
bool GetMouseWithin() { return _fBit.bLocMouseWithin; }
const LPWSTR GetClass(Value** ppv) DUIQuickGetterInd(GetString(), Class, Specified)
ATOM GetID() { return _atomSpecID; }
PropertySheet* GetSheet() { return _pvSpecSheet->GetPropertySheet(); }
bool GetSelected() { return _fBit.bSpecSelected; }
int GetAlpha() { return _dSpecAlpha; }
int GetAnimation() DUIQuickGetter(int, GetInt(), Animation, Specified)
int GetDirection() DUIQuickGetter(int, GetInt(), Direction, Specified)
bool GetAccessible() { return _fBit.bSpecAccessible; }
int GetAccRole() DUIQuickGetter(int, GetInt(), AccRole, Specified)
int GetAccState() DUIQuickGetter(int, GetInt(), AccState, Specified)
const LPWSTR GetAccName(Value** ppv) DUIQuickGetterInd(GetString(), AccName, Specified)
const LPWSTR GetAccDesc(Value** ppv) DUIQuickGetterInd(GetString(), AccDesc, Specified)
const LPWSTR GetAccValue(Value** ppv) DUIQuickGetterInd(GetString(), AccValue, Specified)
const LPWSTR GetAccDefAction(Value** ppv) DUIQuickGetterInd(GetString(), AccDefAction, Specified)
int GetShortcut() DUIQuickGetter(int, GetInt(), Shortcut, Specified)
bool GetEnabled() { return _fBit.bSpecEnabled; }
HRESULT SetVisible(bool v) DUIQuickSetter(CreateBool(v), Visible)
HRESULT SetWidth(int v) DUIQuickSetter(CreateInt(v), Width)
HRESULT SetHeight(int v) DUIQuickSetter(CreateInt(v), Height)
HRESULT SetX(int v) DUIQuickSetter(CreateInt(v), X)
HRESULT SetY(int v) DUIQuickSetter(CreateInt(v), Y)
HRESULT SetLayout(Layout* v) DUIQuickSetter(CreateLayout(v), Layout)
HRESULT SetLayoutPos(int v) DUIQuickSetter(CreateInt(v), LayoutPos)
HRESULT SetBorderThickness(int l, int t, int r, int b) DUIQuickSetter(CreateRect(l, t, r, b), BorderThickness)
HRESULT SetBorderStyle(int v) DUIQuickSetter(CreateInt(v), BorderStyle)
HRESULT SetBorderStdColor(int v) DUIQuickSetter(CreateInt(v), BorderColor)
HRESULT SetBorderColor(COLORREF cr) DUIQuickSetter(CreateColor(cr), BorderColor)
HRESULT SetBorderGradientColor(COLORREF cr0,
COLORREF cr1, BYTE dType = FILLTYPE_HGradient) DUIQuickSetter(CreateColor(cr0, cr1, dType), BorderColor)
HRESULT SetPadding(int l, int t, int r, int b) DUIQuickSetter(CreateRect(l, t, r, b), Padding)
HRESULT SetMargin(int l, int t, int r, int b) DUIQuickSetter(CreateRect(l, t, r, b), Margin)
HRESULT SetForegroundStdColor(int v) DUIQuickSetter(CreateInt(v), Foreground)
HRESULT SetForegroundColor(COLORREF cr) DUIQuickSetter(CreateColor(cr), Foreground)
HRESULT SetForegroundColor(COLORREF cr0, COLORREF cr1,
BYTE dType = FILLTYPE_HGradient) DUIQuickSetter(CreateColor(cr0, cr1, dType), Foreground)
HRESULT SetForegroundColor(COLORREF cr0, COLORREF cr1, COLORREF cr2,
BYTE dType = FILLTYPE_TriHGradient) DUIQuickSetter(CreateColor(cr0, cr1, cr2, dType), Foreground)
HRESULT SetBackgroundStdColor(int v) DUIQuickSetter(CreateInt(v), Background)
HRESULT SetBackgroundColor(COLORREF cr) DUIQuickSetter(CreateColor(cr), Background)
HRESULT SetBackgroundColor(COLORREF cr0, COLORREF cr1,
BYTE dType = FILLTYPE_HGradient) DUIQuickSetter(CreateColor(cr0, cr1, dType), Background)
HRESULT SetBackgroundColor(COLORREF cr0, COLORREF cr1, COLORREF cr2,
BYTE dType = FILLTYPE_TriHGradient) DUIQuickSetter(CreateColor(cr0, cr1, cr2, dType), Background)
HRESULT SetContentString(LPCWSTR v) DUIQuickSetter(CreateString(v), Content)
HRESULT SetContentGraphic(LPCWSTR v,
BYTE dBlendMode = GRAPHIC_NoBlend,
UINT dBlendValue = 0) DUIQuickSetter(CreateGraphic(v, dBlendMode, dBlendValue), Content)
HRESULT SetContentGraphic(LPCWSTR v, USHORT cxDesired,
USHORT cyDesired) DUIQuickSetter(CreateGraphic(v, cxDesired, cyDesired), Content)
HRESULT SetFontFace(LPCWSTR v) DUIQuickSetter(CreateString(v), FontFace)
HRESULT SetFontSize(int v) DUIQuickSetter(CreateInt(v), FontSize)
HRESULT SetFontWeight(int v) DUIQuickSetter(CreateInt(v), FontWeight)
HRESULT SetFontStyle(int v) DUIQuickSetter(CreateInt(v), FontStyle)
HRESULT SetActive(int v) DUIQuickSetter(CreateInt(v), Active)
HRESULT SetContentAlign(int v) DUIQuickSetter(CreateInt(v), ContentAlign)
HRESULT SetClass(LPCWSTR v) DUIQuickSetter(CreateString(v), Class)
HRESULT SetID(LPCWSTR v) DUIQuickSetter(CreateAtom(v), ID)
HRESULT SetSheet(PropertySheet* v) DUIQuickSetter(CreatePropertySheet(v), Sheet)
HRESULT SetSelected(bool v) DUIQuickSetter(CreateBool(v), Selected)
HRESULT SetAlpha(int v) DUIQuickSetter(CreateInt(v), Alpha)
HRESULT SetAnimation(int v) DUIQuickSetter(CreateInt(v), Animation)
HRESULT SetStdCursor(int v) DUIQuickSetter(CreateInt(v), Cursor)
HRESULT SetCursor(LPCWSTR v) DUIQuickSetter(CreateCursor(v), Cursor)
HRESULT SetDirection(int v) DUIQuickSetter(CreateInt(v), Direction)
HRESULT SetAccessible(bool v) DUIQuickSetter(CreateBool(v), Accessible)
HRESULT SetAccRole(int v) DUIQuickSetter(CreateInt(v), AccRole)
HRESULT SetAccState(int v) DUIQuickSetter(CreateInt(v), AccState)
HRESULT SetAccName(LPCWSTR v) DUIQuickSetter(CreateString(v), AccName)
HRESULT SetAccDesc(LPCWSTR v) DUIQuickSetter(CreateString(v), AccDesc)
HRESULT SetAccValue(LPCWSTR v) DUIQuickSetter(CreateString(v), AccValue)
HRESULT SetAccDefAction(LPCWSTR v) DUIQuickSetter(CreateString(v), AccDefAction)
HRESULT SetShortcut(int v) DUIQuickSetter(CreateInt(v), Shortcut)
HRESULT SetEnabled(bool v) DUIQuickSetter(CreateBool(v), Enabled)
////////////////////////////////////////////////////////
// ClassInfo accessors (static and virtual instance-based)
static IClassInfo* Class;
virtual IClassInfo* GetClassInfo() { return Class; }
static HRESULT Register();
///////////////////////////////////////////////////////
// Accessibility support
DuiAccessible * _pDuiAccessible;
virtual HRESULT GetAccessibleImpl(IAccessible ** ppAccessible);
HRESULT QueueDefaultAction();
virtual HRESULT DefaultAction();
};
////////////////////////////////////////////////////////
// Element helpers
Element* ElementFromGadget(HGADGET hGadget);
void QueryDetails(Element* pe, HWND hParent);
////////////////////////////////////////////////////////
// DeferCycle: Per-thread deferring information
// Group notifications: deferred until EndDefer and coalesced
struct GCRecord
{
Element* pe;
int fGroups;
};
// Property notifications: deferred until source's dependency
// graph is searched (within SetValue call), not coalesced
struct PCRecord
{
bool fVoid;
Element* pe;
PropertyInfo* ppi;
int iIndex;
Value* pvOld;
Value* pvNew;
DepRecs dr;
int iPrevElRec;
};
class DeferCycle
{
public:
static HRESULT Create(DeferCycle** ppDC);
void Destroy() { HDelete<DeferCycle>(this); }
void Reset();
DynamicArray<GCRecord>* pdaGC; // Group changed database
DynamicArray<GCRecord>* pdaGCLP; // Low priority group changed database
DynamicArray<PCRecord>* pdaPC; // Property changed database
ValueMap<Element*,BYTE>* pvmLayoutRoot; // Layout trees pending
ValueMap<Element*,BYTE>* pvmUpdateDSRoot; // Update desired size trees pending
int cEnter;
bool fFiring;
int iGCPtr;
int iGCLPPtr;
int iPCPtr;
int iPCSSUpdate;
int cPCEnter;
DeferCycle() { }
HRESULT Initialize();
virtual ~DeferCycle();
};
#if DBG
// Process-wide element count
extern LONG g_cElement;
#endif
// Per-thread Element slot
extern DWORD g_dwElSlot;
struct ElTls
{
HDCONTEXT hCtx; // DirectUser thread context
int cRef;
SBAlloc* psba;
DeferCycle* pdc;
FontCache* pfc;
bool fCoInitialized;
int dEnableAnimations;
#if DBG
int cDNCBEnter; // Track when _DisplayNodeCallback is entered
#endif
};
/////////////////////////////////////////////////////////////////////////////
// Per-Context object access
inline bool IsAnimationsEnabled()
{
ElTls* petls = (ElTls*)TlsGetValue(g_dwElSlot);
if (!petls)
return false;
return (petls->dEnableAnimations == 0);
}
inline void EnableAnimations()
{
ElTls* petls = (ElTls*)TlsGetValue(g_dwElSlot);
if (!petls)
return;
petls->dEnableAnimations++;
}
inline void DisableAnimations()
{
ElTls* petls = (ElTls*)TlsGetValue(g_dwElSlot);
if (!petls)
return;
petls->dEnableAnimations--;
}
inline HDCONTEXT GetContext()
{
ElTls* petls = (ElTls*)TlsGetValue(g_dwElSlot);
if (!petls)
return NULL;
return petls->hCtx;
}
inline DeferCycle* GetDeferObject()
{
ElTls* petls = (ElTls*)TlsGetValue(g_dwElSlot);
if (!petls)
return NULL;
return petls->pdc;
}
inline FontCache* GetFontCache()
{
ElTls* petls = (ElTls*)TlsGetValue(g_dwElSlot);
if (!petls)
return NULL;
return petls->pfc;
}
inline SBAlloc* GetSBAllocator()
{
#if 0
ElTls* petls = (ElTls*)TlsGetValue(g_dwElSlot);
if (!petls)
return NULL;
return petls->psba;
#else
ElTls* petls = (ElTls*)TlsGetValue(g_dwElSlot);
DUIAssert(petls != NULL, "Must have valid SBAllocator");
return petls->psba;
#endif
}
// Use to check if Element may be accessed via the current thread
#if DBG
inline void ContextCheck(Element* pe)
{
DUIAssert(pe->owner.dwTLSSlot == g_dwElSlot, "Element being accessed out of side-by-side instance");
DUIAssert(pe->owner.hCtx == GetContext(), "Element being accessed out of context");
}
#define DUIContextAssert(pe) ContextCheck(pe)
#else
#define DUIContextAssert(pe)
#endif
////////////////////////////////////////////////////////
// Property enumerations
// ActiveProp
#define AE_Inactive 0x00000000
#define AE_Mouse 0x00000001
#define AE_Keyboard 0x00000002
#define AE_MouseAndKeyboard (AE_Mouse | AE_Keyboard)
// BorderStyleProp
#define BDS_Solid 0
#define BDS_Raised 1
#define BDS_Sunken 2
#define BDS_Rounded 3
// FontStyleProp
#define FS_None 0x00000000
#define FS_Italic 0x00000001
#define FS_Underline 0x00000002
#define FS_StrikeOut 0x00000004
#define FS_Shadow 0x00000008
// FontWeightProp
#define FW_DontCare 0
#define FW_Thin 100
#define FW_ExtraLight 200
#define FW_Light 300
#define FW_Normal 400
#define FW_Medium 500
#define FW_SemiBold 600
#define FW_Bold 700
#define FW_ExtraBold 800
#define FW_Heavy 900
// ContentAlignProp (CAE_XY, Y=bits 0-1, X=bits 2-3)
#define CA_TopLeft 0x00000000 // (0,0)
#define CA_TopCenter 0x00000001 // (0,1)
#define CA_TopRight 0x00000002 // (0,2)
#define CA_MiddleLeft 0x00000004 // (1,0)
#define CA_MiddleCenter 0x00000005 // (1,1)
#define CA_MiddleRight 0x00000006 // (1,2)
#define CA_BottomLeft 0x00000008 // (2,0)
#define CA_BottomCenter 0x00000009 // (2,1)
#define CA_BottomRight 0x0000000A // (2,2)
#define CA_WrapLeft 0x0000000C // (3,0)
#define CA_WrapCenter 0x0000000D // (3,1)
#define CA_WrapRight 0x0000000E // (3,2)
#define CA_EndEllipsis 0x00000010
#define CA_FocusRect 0x00000020
// AnimationProp (Interpolation | CatType [ | CatType | ... ] | Speed)
#define ANI_InterpolMask 0x0000000F
#define ANI_DelayMask 0x000000F0
#define ANI_TypeMask 0x0FFFFF00
#define ANI_SpeedMask 0xF0000000
#define ANI_DefaultInterpol 0x00000000
#define ANI_Linear 0x00000001 // INTERPOLATION_LINEAR
#define ANI_Log 0x00000002 // INTERPOLATION_LOG
#define ANI_Exp 0x00000003 // INTERPOLATION_EXP
#define ANI_S 0x00000004 // INTERPOLATION_S
#define ANI_DelayNone 0x00000000
#define ANI_DelayShort 0x00000010
#define ANI_DelayMedium 0x00000020
#define ANI_DelayLong 0x00000030
#define ANI_AlphaType 0x00000F00
#define ANI_BoundsType 0x0000F000
#define ANI_XFormType 0x000F0000
#define ANI_None 0x00000000
#define ANI_Alpha 0x00000100
#define ANI_Position 0x00001000
#define ANI_Size 0x00002000
#define ANI_SizeH 0x00003000
#define ANI_SizeV 0x00004000
#define ANI_Rect 0x00005000
#define ANI_RectH 0x00006000
#define ANI_RectV 0x00007000
#define ANI_Scale 0x00010000
#define ANI_DefaultSpeed 0x00000000
#define ANI_VeryFast 0x10000000
#define ANI_Fast 0x20000000
#define ANI_MediumFast 0x30000000
#define ANI_Medium 0x40000000
#define ANI_MediumSlow 0x50000000
#define ANI_Slow 0x60000000
#define ANI_VerySlow 0x70000000
// CursorProp
#define CUR_Arrow 0
#define CUR_Hand 1
#define CUR_Help 2
#define CUR_No 3
#define CUR_Wait 4
#define CUR_SizeAll 5
#define CUR_SizeNESW 6
#define CUR_SizeNS 7
#define CUR_SizeNWSE 8
#define CUR_SizeWE 9
#define CUR_Total 10
// Internal property indicies for property compares. Must match up one to one
// with Element property definitions
#define _PIDX_Parent 0
#define _PIDX_PosInLayout 1
#define _PIDX_SizeInLayout 2
#define _PIDX_DesiredSize 3
#define _PIDX_LastDSConst 4
#define _PIDX_Location 5
#define _PIDX_Extent 6
#define _PIDX_LayoutPos 7
#define _PIDX_Active 8
#define _PIDX_Children 9
#define _PIDX_Layout 10
#define _PIDX_BorderThickness 11
#define _PIDX_Padding 12
#define _PIDX_Margin 13
#define _PIDX_Visible 14
#define _PIDX_X 15
#define _PIDX_Y 16
#define _PIDX_ContentAlign 17
#define _PIDX_KeyFocused 18
#define _PIDX_KeyWithin 19
#define _PIDX_MouseFocused 20
#define _PIDX_MouseWithin 21
#define _PIDX_Content 22
#define _PIDX_Sheet 23
#define _PIDX_Width 24
#define _PIDX_Height 25
#define _PIDX_BorderStyle 26
#define _PIDX_BorderColor 27
#define _PIDX_Foreground 28
#define _PIDX_Background 29
#define _PIDX_FontFace 30
#define _PIDX_FontSize 31
#define _PIDX_FontWeight 32
#define _PIDX_FontStyle 33
#define _PIDX_Class 34
#define _PIDX_ID 35
#define _PIDX_Selected 36
#define _PIDX_Alpha 37
#define _PIDX_Animation 38
#define _PIDX_Cursor 39
#define _PIDX_Direction 40
#define _PIDX_Accessible 41
#define _PIDX_AccRole 42
#define _PIDX_AccState 43
#define _PIDX_AccName 44
#define _PIDX_AccDesc 45
#define _PIDX_AccValue 46
#define _PIDX_AccDefAction 47
#define _PIDX_Shortcut 48
#define _PIDX_Enabled 49
#define _PIDX_TOTAL 50
////////////////////////////////////////////////////////
// Class information template
// All classes that derive from Element must create a global instance of this class.
// It maintains a list of the class properties (provides enumeration) and creation method
// C = Class, B = Base class
// Defined in Element.cpp
extern UINT g_iGlobalCI;
extern UINT g_iGlobalPI;
template <typename C, typename B> class ClassInfo : public IClassInfo
{
public:
// Registration (cannot unregister -- will be registered until UnInitProcess is called)
static HRESULT Register(LPCWSTR pszName, PropertyInfo** ppPI, UINT cPI)
{
HRESULT hr;
// If class mapping doesn't exist, registration fails
if (!Element::pciMap)
return E_FAIL;
// Check for entry in mapping, if exists, ignore registration
if (!Element::pciMap->GetItem((void*)pszName))
{
// Never been registered, create class info entry
hr = Create(pszName, ppPI, cPI, &C::Class);
if (FAILED(hr))
return hr;
hr = Element::pciMap->SetItem((void*)pszName, C::Class);
if (FAILED(hr))
return hr;
}
return S_OK;
}
// Construction
static HRESULT Create(LPCWSTR pszName, PropertyInfo** ppPI, UINT cPI, IClassInfo** ppCI)
{
*ppCI = NULL;
// Element map must already exist
if (!Element::pciMap)
return E_FAIL;
ClassInfo* pci = HNew<ClassInfo>();
if (!pci)
return E_OUTOFMEMORY;
// Setup state
pci->_ppPI = ppPI;
pci->_cPI = cPI;
pci->_pszName = pszName;
// Set global index
pci->_iGlobalIndex = g_iGlobalCI++;
// Setup property ownership
for (UINT i = 0; i < cPI; i++)
{
ppPI[i]->_iIndex = i;
ppPI[i]->_iGlobalIndex = g_iGlobalPI++;
ppPI[i]->_pciOwner = pci;
}
#if DBG
// Call string conversion method directly since can't assume Util library is available for header
CHAR szNameA[101];
ZeroMemory(szNameA, sizeof(szNameA));
WideCharToMultiByte(CP_ACP, 0, pszName, -1, szNameA, (sizeof(szNameA) / sizeof(CHAR)) - 1, NULL, NULL);
//DUITrace("RegDUIClass[%d]: '%s', %d ClassProps\n", pci->_iGlobalIndex, szNameA, cPI);
#endif
*ppCI = pci;
return S_OK;
}
void Destroy() { HDelete<ClassInfo>(this); }
public:
HRESULT CreateInstance(OUT Element** ppElement) { return C::Create(ppElement); }
PropertyInfo* EnumPropertyInfo(UINT nEnum) { return (nEnum < _cPI) ? _ppPI[nEnum] : B::Class->EnumPropertyInfo(nEnum - _cPI); }
UINT GetPICount() { return _cPI + B::Class->GetPICount(); }
UINT GetGlobalIndex() { return _iGlobalIndex; }
IClassInfo* GetBaseClass() { return B::Class; }
LPCWSTR GetName() { return _pszName; }
bool IsValidProperty(PropertyInfo* ppi) { return (ppi->_pciOwner == this) ? true : B::Class->IsValidProperty(ppi); }
bool IsSubclassOf(IClassInfo* pci) { return (pci == this) ? true : B::Class->IsSubclassOf(pci); }
ClassInfo() { }
virtual ~ClassInfo() { }
private:
PropertyInfo** _ppPI; // Array of properties for this class (C)
UINT _cPI; // Count of properties for this class (C)
UINT _iGlobalIndex; // Zero-based unique contiguous class id
LPCWSTR _pszName; // Class name
};
} // namespace DirectUI
#endif // DUI_CORE_ELEMENT_H_INCLUDED