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
|
//!## An object to multiplex the callbacks of multiple attributes.
#ifndef _ATTRHANDLER_H
#define _ATTRHANDLER_H
// This class is meant to be subclassed. The methods you must provide
// are given as pure virtuals. See ExampleAttrib for more details, and
// an example subclass that you can copy for your own use.
#include "attrcb.h"
#include "attribs.h"
#include <bfc/map.h>
//
// Forward References
class WAComponentClient;
class Attribute;
//
// Class Definition
template <class TCallback>
class AttrHandler {
protected:
// Heh, oops. Can't have one AttrCallback handle lots of different attribs, anymore. I fix.
class AttrHandlerChild : public AttrCallback {
public:
AttrHandlerChild(AttrHandler *_parent) : AttrCallback() {
ASSERT(_parent != NULL);
recursion = 0;
callback = NULL;
parent = _parent;
}
// Here is where we split out the different value types
virtual void onValueChange(Attribute *attr) {
if (!recursion) {
// protect our programmers from stack overflow, please.
recursion = 1;
if ((callback != NULL) && (parent != NULL)) {
int id;
// find the id from the map (friendly)
int success = parent->attribmap.getItem(attr,&id);
if (success) {
// and send it to the proper handling function (poorman's RTTI)
switch (attr->getAttributeType()) {
case AttributeType::INT:
callback->onIntChange(id,*static_cast<_int *>(attr));
break;
case AttributeType::BOOL:
callback->onBoolChange(id, *static_cast<_bool *>(attr));
break;
case AttributeType::FLOAT:
callback->onFloatChange(id, *static_cast<_float *>(attr));
break;
case AttributeType::STRING:
callback->onStringChange(id, *static_cast<_string *>(attr));
break;
}
}
}
recursion = 0;
}
}
virtual void bindCallbackObj(TCallback *callbackobj) {
// Be advised, this may be null. That's okay, we test for it above.
callback = callbackobj;
}
private:
int recursion;
TCallback *callback;
AttrHandler *parent;
};
public:
AttrHandler() {
component = NULL;
callback = NULL;
}
// Call this method to bind your component (in your component's constructor)
virtual void bindComponent(WAComponentClient *parentcomponent) {
component = parentcomponent;
}
// Call this method to bind your callback object (usually your window in its constructor)
virtual void bindCallbackObj(TCallback *callbackobj) {
// Bind ourselves.
callback = callbackobj;
// Then go through and rebind any children.
int i, num = attrchildren.getNumItems();
for (i = 0; i < num; i++) {
AttrHandlerChild *child = attrchildren.enumItem(i);
child->bindCallbackObj(callback);
}
}
// Call this method to register each attribute.
virtual void registerAttribute(Attribute *attr, int id) {
ASSERTPR(component != NULL, "BIND YOUR COMPONENT before registering Attributes to a Handler.");
// register the attrib with a child object as its callback
AttrHandlerChild *child = new AttrHandlerChild(this);
attrchildren.addItem(child);
component->registerAttribute(attr, child);
// and save its id mapping
attribmap.addItem(attr, id);
}
#if 0
// Your callback object (probably your primary window class) must implement
// its own versions of these methods here. They will be called by the
// switch statement below.
virtual void onIntChange(int id, int *attr);
virtual void onBoolChange(int id, bool *attr);
virtual void onFloatChange(int id, double *attr);
virtual void onStringChange(int id, const char *attr);
#endif
private:
friend AttrHandlerChild;
TCallback *callback;
WAComponentClient *component;
Map< Attribute *, int > attribmap;
PtrList<AttrHandlerChild> attrchildren;
};
#endif // _ATTRHANDLER_H
|