498 lines
9.0 KiB
C++
498 lines
9.0 KiB
C++
|
|
enum NodeType
|
|
{
|
|
DataNode = 0,
|
|
AndNode = 1,
|
|
OrNode = 2,
|
|
XorNode = 3
|
|
};
|
|
|
|
// shape flags for temporary editing
|
|
#define ShapeDisabled 0x00000001
|
|
|
|
template <class Data> class TreeNode
|
|
{
|
|
public:
|
|
friend class TestShapeRegion;
|
|
|
|
TreeNode(NodeType type = DataNode, Data* data = NULL, BOOL notNode = FALSE)
|
|
{
|
|
this->type = type;
|
|
this->data = data;
|
|
this->notNode = notNode;
|
|
nodeName = NULL;
|
|
|
|
if (data)
|
|
{
|
|
// !! violates we are a template class.. Yipes!! hacky!!
|
|
path = new GraphicsPath();
|
|
data->AddToPath(path);
|
|
}
|
|
else
|
|
path = NULL;
|
|
|
|
nextSibling = NULL;
|
|
prevSibling = NULL;
|
|
parent = NULL;
|
|
firstChild = NULL;
|
|
|
|
hItem = (HTREEITEM)-1;
|
|
}
|
|
|
|
~TreeNode()
|
|
{
|
|
if (nodeName)
|
|
free(nodeName);
|
|
|
|
TreeNode* next = firstChild;
|
|
while (next)
|
|
{
|
|
TreeNode* nextnext = next->nextSibling;
|
|
delete next;
|
|
next = nextnext;
|
|
}
|
|
|
|
if (nextSibling)
|
|
nextSibling->prevSibling = prevSibling;
|
|
|
|
if (prevSibling)
|
|
prevSibling->nextSibling = nextSibling;
|
|
|
|
if (parent && parent->firstChild == this)
|
|
parent->firstChild = nextSibling;
|
|
|
|
if (path)
|
|
delete path;
|
|
};
|
|
|
|
TreeNode* GetRoot()
|
|
{
|
|
TreeNode* next = parent;
|
|
|
|
while (next && next->parent)
|
|
next = next->parent;
|
|
|
|
return next ? next : this;
|
|
}
|
|
|
|
BOOL HasChildren()
|
|
{
|
|
return (firstChild) ? TRUE : FALSE;
|
|
}
|
|
|
|
TreeNode* GetParent()
|
|
{
|
|
return parent;
|
|
}
|
|
|
|
TreeNode* GetNextSibling()
|
|
{
|
|
return nextSibling;
|
|
}
|
|
|
|
TreeNode* GetPrevSibling()
|
|
{
|
|
return prevSibling;
|
|
}
|
|
|
|
TreeNode* GetFirstChild()
|
|
{
|
|
return firstChild;
|
|
}
|
|
|
|
VOID MoveChildrenToParent()
|
|
{
|
|
ASSERT(parent);
|
|
|
|
TreeNode* lastSibling = parent->firstChild;
|
|
while (lastSibling->nextSibling)
|
|
lastSibling = lastSibling->nextSibling;
|
|
|
|
lastSibling->nextSibling = firstChild;
|
|
if (firstChild)
|
|
firstChild->prevSibling = lastSibling;
|
|
|
|
lastSibling = firstChild;
|
|
while (lastSibling)
|
|
{
|
|
lastSibling->parent = parent;
|
|
lastSibling = lastSibling->nextSibling;
|
|
}
|
|
|
|
firstChild = NULL;
|
|
}
|
|
|
|
HTREEITEM CreateTreeView(HWND hwndTV)
|
|
{
|
|
HTREEITEM hTreeItem = AddToTreeView(hwndTV);
|
|
|
|
if (nextSibling)
|
|
nextSibling->CreateTreeView(hwndTV);
|
|
|
|
if (firstChild)
|
|
firstChild->CreateTreeView(hwndTV);
|
|
|
|
return hTreeItem;
|
|
}
|
|
|
|
HTREEITEM AddToTreeView(HWND hwndTV)
|
|
{
|
|
nodeName = GetNodeName(type, notNode, data);
|
|
|
|
TVINSERTSTRUCT insertStruct =
|
|
{
|
|
parent ? (HTREEITEM)parent->GetHTREEITEM() : TVI_ROOT,
|
|
prevSibling ? (HTREEITEM)prevSibling->GetHTREEITEM() : TVI_FIRST,
|
|
};
|
|
|
|
TVITEMEX itemex =
|
|
{
|
|
TVIF_CHILDREN|
|
|
TVIF_PARAM|
|
|
TVIF_STATE|
|
|
TVIF_TEXT, // mask
|
|
(HTREEITEM)(NULL), // identifies TV item
|
|
0, // state
|
|
0, // stateMask
|
|
nodeName, // text to display
|
|
0, // cchTextMax
|
|
0, // iImage
|
|
0, // iSelectedImage
|
|
(firstChild ? 1 : 0), // cChildren
|
|
(LPARAM)(this), // lParam
|
|
1 // iIntegral
|
|
};
|
|
|
|
// !! wasn't able to compile into one assignment !?!?
|
|
insertStruct.itemex = itemex;
|
|
|
|
hItem = TreeView_InsertItem(hwndTV, &insertStruct);
|
|
|
|
return hItem;
|
|
};
|
|
|
|
VOID AddChild(TreeNode* node)
|
|
{
|
|
if (!firstChild)
|
|
{
|
|
firstChild = node;
|
|
|
|
node->parent = this;
|
|
node->prevSibling = NULL;
|
|
|
|
node->nextSibling = NULL;
|
|
node->firstChild = NULL;
|
|
}
|
|
else
|
|
{
|
|
TreeNode* next = firstChild;
|
|
|
|
while (next->nextSibling)
|
|
next = next->nextSibling;
|
|
|
|
next->nextSibling = node;
|
|
node->parent = this;
|
|
node->prevSibling = next;
|
|
|
|
node->nextSibling = NULL;
|
|
node->firstChild = NULL;
|
|
}
|
|
};
|
|
|
|
VOID AddSibling(TreeNode* node)
|
|
{
|
|
TreeNode* next = this;
|
|
|
|
while (next->nextSibling)
|
|
next = next->nextSibling;
|
|
|
|
if (next)
|
|
{
|
|
next->nextSibling = node;
|
|
node->parent = this->parent;
|
|
node->prevSibling = next;
|
|
|
|
node->nextSibling = NULL;
|
|
node->firstChild = NULL;
|
|
}
|
|
else
|
|
ASSERT(FALSE);
|
|
};
|
|
|
|
VOID AddAsParent(TreeNode* newParent)
|
|
{
|
|
newParent->parent = parent;
|
|
newParent->prevSibling = prevSibling;
|
|
newParent->nextSibling = nextSibling;
|
|
newParent->firstChild = this;
|
|
|
|
if (parent && parent->firstChild == this)
|
|
parent->firstChild = newParent;
|
|
|
|
if (prevSibling)
|
|
prevSibling->nextSibling = newParent;
|
|
|
|
if (nextSibling)
|
|
nextSibling->prevSibling = newParent;
|
|
|
|
nextSibling = NULL;
|
|
prevSibling = NULL;
|
|
parent = newParent;
|
|
}
|
|
|
|
BOOL IsEmpty()
|
|
{
|
|
return (type == DataNode) && (notNode) && (data == NULL);
|
|
}
|
|
|
|
BOOL IsInfinite()
|
|
{
|
|
return (type == DataNode) && (!notNode) && (data == NULL);
|
|
}
|
|
|
|
HTREEITEM GetHTREEITEM()
|
|
{
|
|
return hItem;
|
|
}
|
|
|
|
static LPTSTR GetNodeName(NodeType type,
|
|
BOOL notNode,
|
|
Data* data)
|
|
{
|
|
TCHAR tmpName[MAX_PATH];
|
|
LPTSTR name;
|
|
|
|
switch(type)
|
|
{
|
|
case DataNode:
|
|
// !! won't work on other template class types.
|
|
if (data)
|
|
{
|
|
if (notNode)
|
|
{
|
|
name = &tmpName[0];
|
|
|
|
_stprintf(&tmpName[0],
|
|
_T("NOT %s"),
|
|
data->GetShapeName());
|
|
|
|
}
|
|
else
|
|
name = data->GetShapeName();
|
|
}
|
|
else
|
|
{
|
|
if (notNode)
|
|
name = _T("Empty");
|
|
else
|
|
name = _T("Infinite");
|
|
}
|
|
break;
|
|
|
|
case AndNode:
|
|
if (notNode)
|
|
name = _T("NAND");
|
|
else
|
|
name = _T("AND");
|
|
break;
|
|
|
|
case OrNode:
|
|
if (notNode)
|
|
name = _T("NOR");
|
|
else
|
|
name = _T("OR");
|
|
break;
|
|
|
|
case XorNode:
|
|
if (notNode)
|
|
name = _T("NXOR");
|
|
else
|
|
name = _T("XOR");
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
return _T("Unknown!?!");
|
|
};
|
|
|
|
return _tcsdup(name);
|
|
}
|
|
|
|
Region* GetRegion()
|
|
{
|
|
Region* newRegion = NULL;
|
|
|
|
switch(type)
|
|
{
|
|
case DataNode:
|
|
{
|
|
if (path)
|
|
newRegion = new Region(path);
|
|
else
|
|
{
|
|
newRegion = new Region();
|
|
newRegion->SetInfinite();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case AndNode:
|
|
case OrNode:
|
|
case XorNode:
|
|
{
|
|
Region* curRegion;
|
|
TreeNode* curNode = firstChild;
|
|
|
|
newRegion = new Region();
|
|
if (type == AndNode)
|
|
newRegion->SetInfinite();
|
|
else
|
|
newRegion->SetEmpty();
|
|
|
|
while (curNode)
|
|
{
|
|
curRegion = curNode->GetRegion();
|
|
|
|
if (type == AndNode)
|
|
newRegion->And(curRegion);
|
|
else if (type == OrNode)
|
|
newRegion->Or(curRegion);
|
|
else
|
|
{
|
|
ASSERT(type == XorNode);
|
|
newRegion->Xor(curRegion);
|
|
}
|
|
|
|
curNode = curNode->nextSibling;
|
|
delete curRegion;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
// complement the current region
|
|
if (notNode)
|
|
{
|
|
Region *tmpRegion = new Region();
|
|
tmpRegion->SetInfinite();
|
|
newRegion->Complement(tmpRegion);
|
|
delete tmpRegion;
|
|
}
|
|
|
|
return newRegion;
|
|
}
|
|
|
|
TreeNode* Clone()
|
|
{
|
|
TreeNode* newNode = new TreeNode(type, data, notNode);
|
|
TreeNode* curNode = firstChild;
|
|
TreeNode* newSibling = NULL;
|
|
|
|
// loop through all children, clone and add to 'newNode'
|
|
while (curNode)
|
|
{
|
|
TreeNode *newChild = curNode->Clone();
|
|
|
|
newChild->nodeName = GetNodeName(type, notNode, data);
|
|
|
|
if (!newSibling)
|
|
newSibling = newNode->firstChild = newChild;
|
|
else
|
|
{
|
|
newSibling->nextSibling = newChild;
|
|
newChild->prevSibling = newSibling;
|
|
newSibling = newChild;
|
|
}
|
|
|
|
newChild->parent = newNode;
|
|
curNode = curNode->nextSibling;
|
|
}
|
|
|
|
return newNode;
|
|
}
|
|
|
|
private:
|
|
NodeType type;
|
|
BOOL notNode;
|
|
|
|
LPTSTR nodeName;
|
|
|
|
TreeNode* nextSibling;
|
|
TreeNode* prevSibling;
|
|
TreeNode* firstChild;
|
|
TreeNode* parent;
|
|
|
|
HTREEITEM hItem;
|
|
|
|
GraphicsPath* path; // GDI+ path for shape
|
|
|
|
Data* data;
|
|
};
|
|
|
|
typedef TreeNode<TestShape> ClipTree;
|
|
|
|
class TestShapeRegion : public TestConfigureInterface,
|
|
public TestDialogInterface
|
|
{
|
|
public:
|
|
TestShapeRegion()
|
|
{
|
|
clipTree = new ClipTree(AndNode, NULL, FALSE);
|
|
origTree = NULL;
|
|
|
|
shapeStack = new ShapeStack();
|
|
origStack = NULL;
|
|
}
|
|
|
|
~TestShapeRegion()
|
|
{
|
|
delete clipTree;
|
|
delete shapeStack;
|
|
|
|
// do not delete 'origTree' or 'origStack'
|
|
// these are temporary references for saving under 'OK'
|
|
}
|
|
|
|
// configuration management
|
|
virtual BOOL ChangeSettings(HWND hwnd);
|
|
virtual VOID Initialize();
|
|
virtual VOID Initialize(ShapeStack* stack, TestShape* current, BOOL useClip);
|
|
|
|
// dialog control interface methods
|
|
virtual VOID InitDialog(HWND hwnd);
|
|
virtual BOOL SaveValues(HWND hwnd);
|
|
virtual BOOL ProcessDialog(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
|
|
Region* GetClipRegion();
|
|
BOOL GetClipBool()
|
|
{
|
|
return origUseClip;
|
|
}
|
|
|
|
protected:
|
|
VOID AddClipNode(HWND hwnd, NodeType type = DataNode);
|
|
VOID RemoveClipNode(HWND hwnd);
|
|
VOID ToggleNotNode(HWND hwnd);
|
|
|
|
VOID ShiftCurrentShape(HWND hwnd, INT dir);
|
|
VOID ToggleDisableShape(HWND hwnd);
|
|
|
|
VOID UpdateShapePicture(HWND hwnd);
|
|
VOID CleanUpPictures(HWND hwnd);
|
|
|
|
private:
|
|
// currently modified parameters
|
|
ShapeStack* shapeStack;
|
|
ClipTree* clipTree;
|
|
|
|
// original saved parameters
|
|
ShapeStack* origStack;
|
|
ClipTree* origTree;
|
|
BOOL origUseClip;
|
|
};
|