[dasher] Assign default group colours better and properly handle invisible groups
- From: Patrick Welche <pwelche src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dasher] Assign default group colours better and properly handle invisible groups
- Date: Thu, 12 May 2011 11:58:03 +0000 (UTC)
commit fdd2dfa6629f478d08c340e395b616869daf87b3
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date: Wed Apr 13 10:46:18 2011 +0100
Assign default group colours better and properly handle invisible groups
AlphIO: assign colour to group only if none (or -1) specified, ensuring
the chosen colour is different to both parent and previous sibling.
Also tidy group setup code and remove m_bFirstGroup (redundant)
DasherNode: add NF_VISIBLE flag, set by default in c'tor; AlphMgr clears for
invisible groups.
DasherViewSquare: fill and outline node iff NF_VISIBLE set, rather than
comparing to parent colour. Rm parent_colour param of recursive render methods.
Src/DasherCore/Alphabet/AlphIO.cpp | 61 ++++++++++++++++-------------------
Src/DasherCore/Alphabet/AlphIO.h | 1 -
Src/DasherCore/AlphabetManager.cpp | 1 +
Src/DasherCore/DasherNode.cpp | 10 +----
Src/DasherCore/DasherNode.h | 57 +++++++++++++++++++-------------
Src/DasherCore/DasherViewSquare.cpp | 41 +++++++++++------------
Src/DasherCore/DasherViewSquare.h | 6 ++--
7 files changed, 88 insertions(+), 89 deletions(-)
---
diff --git a/Src/DasherCore/Alphabet/AlphIO.cpp b/Src/DasherCore/Alphabet/AlphIO.cpp
index 9f360d4..4e41ebc 100644
--- a/Src/DasherCore/Alphabet/AlphIO.cpp
+++ b/Src/DasherCore/Alphabet/AlphIO.cpp
@@ -430,7 +430,6 @@ void CAlphIO::XML_StartElement(void *userData, const XML_Char *name, const XML_C
Me->InputInfo->Mutable = Me->LoadMutable;
Me->ParagraphCharacter = NULL;
Me->SpaceCharacter = NULL;
- Me->bFirstGroup = true;
Me->iGroupIdx = 0;
while(*atts != 0) {
if(strcmp(*atts, "name") == 0) {
@@ -506,17 +505,11 @@ void CAlphIO::XML_StartElement(void *userData, const XML_Char *name, const XML_C
if(strcmp(name, "group") == 0) {
SGroupInfo *pNewGroup(new SGroupInfo);
pNewGroup->iNumChildNodes=0;
- pNewGroup->iColour = (Me->iGroupIdx % 3) + 110;
- ++Me->iGroupIdx;
+ pNewGroup->iColour = -1; //marker for "none specified"; if so, will compute later
if (Me->m_vGroups.empty()) Me->InputInfo->iNumChildNodes++; else Me->m_vGroups.back()->iNumChildNodes++;
- if(Me->bFirstGroup) {
- pNewGroup->bVisible = false;
- Me->bFirstGroup = false;
- }
- else {
- pNewGroup->bVisible = true;
- }
+ //by default, the first group in the alphabet is invisible
+ pNewGroup->bVisible = (Me->InputInfo->m_pBaseGroup!=NULL);
while(*atts != 0) {
if(strcmp(*atts, "name") == 0) {
@@ -527,39 +520,41 @@ void CAlphIO::XML_StartElement(void *userData, const XML_Char *name, const XML_C
// atts--;
}
if(strcmp(*atts, "b") == 0) {
+ pNewGroup->iColour = atoi(*(atts+1));
+ } else if(strcmp(*atts, "visible") == 0) {
atts++;
- pNewGroup->iColour = atoi(*atts);
- atts--;
- }
- if(strcmp(*atts, "visible") == 0) {
- atts++;
- if(!strcmp(*atts, "yes") || !strcmp(*atts, "on"))
- pNewGroup->bVisible = true;
- else if(!strcmp(*atts, "no") || !strcmp(*atts, "off"))
- pNewGroup->bVisible = false;
- atts--;
- }
- if(strcmp(*atts, "label") == 0) {
- atts++;
- pNewGroup->strLabel = *atts;
+ if(!strcmp(*atts, "yes") || !strcmp(*atts, "on"))
+ pNewGroup->bVisible = true;
+ else if(!strcmp(*atts, "no") || !strcmp(*atts, "off"))
+ pNewGroup->bVisible = false;
atts--;
+ } else if(strcmp(*atts, "label") == 0) {
+ pNewGroup->strLabel = *(atts+1);
}
atts += 2;
}
+ SGroupInfo *&prevSibling(Me->m_vGroups.empty() ? Me->InputInfo->m_pBaseGroup : Me->m_vGroups.back()->pChild);
+
+ if (pNewGroup->iColour==-1 && pNewGroup->bVisible) {
+ //no colour specified. Try to colour cycle, but make sure we choose
+ // a different colour from both its parent and any previous sibling
+ for (;;) {
+ pNewGroup->iColour=(Me->iGroupIdx++ % 3) + 110;
+ if (!Me->m_vGroups.empty() && Me->m_vGroups.back()->iColour == pNewGroup->iColour)
+ continue; //same colour as parent -> try again
+ if (prevSibling && prevSibling->iColour == pNewGroup->iColour)
+ continue; //same colour as previous sibling -> try again
+ break; //different from parent and previous sibling (if any!), so ok
+ }
+ }
+
pNewGroup->iStart = Me->InputInfo->m_vCharacters.size()+1;
pNewGroup->pChild = NULL;
- if(Me->m_vGroups.size() > 0) {
- pNewGroup->pNext = Me->m_vGroups.back()->pChild;
- Me->m_vGroups.back()->pChild = pNewGroup;
- }
- else {
- pNewGroup->pNext = Me->InputInfo->m_pBaseGroup;
- Me->InputInfo->m_pBaseGroup = pNewGroup;
- }
-
+ pNewGroup->pNext = prevSibling;
+ prevSibling = pNewGroup;
Me->m_vGroups.push_back(pNewGroup);
diff --git a/Src/DasherCore/Alphabet/AlphIO.h b/Src/DasherCore/Alphabet/AlphIO.h
index ac01426..d501ffa 100644
--- a/Src/DasherCore/Alphabet/AlphIO.h
+++ b/Src/DasherCore/Alphabet/AlphIO.h
@@ -91,7 +91,6 @@ private:
// Data gathered
std::string CData; // Text gathered from when an elemnt starts to when it ends
CAlphInfo *InputInfo;
- bool bFirstGroup;
int iGroupIdx;
// Callback functions. These involve the normal dodgy casting to a pointer
diff --git a/Src/DasherCore/AlphabetManager.cpp b/Src/DasherCore/AlphabetManager.cpp
index dc1c72e..f123879 100644
--- a/Src/DasherCore/AlphabetManager.cpp
+++ b/Src/DasherCore/AlphabetManager.cpp
@@ -176,6 +176,7 @@ CAlphabetManager::CGroupNode::CGroupNode(CDasherNode *pParent, int iOffset, unsi
pGroup ? (pGroup->bVisible ? pGroup->iColour : iBkgCol)
: (iOffset&1) ? 7 : 137, //special case for root nodes
pGroup ? strEnc+pGroup->strLabel : strEnc, pMgr), m_pGroup(pGroup) {
+ if (m_pGroup && !m_pGroup->bVisible) SetFlag(NF_VISIBLE, false);
}
CAlphabetManager::CAlphNode *CAlphabetManager::GetRoot(CDasherNode *pParent, unsigned int iLower, unsigned int iUpper, bool bEnteredLast, int iOffset) {
diff --git a/Src/DasherCore/DasherNode.cpp b/Src/DasherCore/DasherNode.cpp
index ef247fe..5f918fe 100644
--- a/Src/DasherCore/DasherNode.cpp
+++ b/Src/DasherCore/DasherNode.cpp
@@ -43,20 +43,14 @@ int Dasher::currentNumNodeObjects() {return iNumNodes;}
//TODO this used to be inline - should we make it so again?
CDasherNode::CDasherNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const string &strDisplayText)
-: m_pParent(pParent), m_iOffset(iOffset), m_iLbnd(iLbnd), m_iHbnd(iHbnd), m_iColour(iColour), m_strDisplayText(strDisplayText) {
+: m_pParent(pParent), m_iFlags(DEFAULT_FLAGS), onlyChildRendered(NULL), m_iLbnd(iLbnd), m_iHbnd(iHbnd), m_iOffset(iOffset), m_iColour(iColour), m_strDisplayText(strDisplayText) {
DASHER_ASSERT(iHbnd >= iLbnd);
if (pParent) {
DASHER_ASSERT(!pParent->GetFlag(NF_ALLCHILDREN));
pParent->Children().push_back(this);
}
-
- onlyChildRendered = NULL;
-
- // Default flags (make a definition somewhere, pass flags to constructor?)
- m_iFlags = 0;
-
- m_iRefCount = 0;
+
iNumNodes++;
}
diff --git a/Src/DasherCore/DasherNode.h b/Src/DasherCore/DasherNode.h
index f503208..3c2767c 100644
--- a/Src/DasherCore/DasherNode.h
+++ b/Src/DasherCore/DasherNode.h
@@ -37,14 +37,40 @@ namespace Dasher {
#include <vector>
// Node flag constants
+/// NF_COMMITTED: The node is 'above' the root, i.e. all onscreen parts of it
+/// are covered by the root; this is when we train the language model etc
#define NF_COMMITTED 1
+
+/// NF_SEEN - Node is under the crosshair and has (already) been output
#define NF_SEEN 2
+
+/// NF_CONVERTED - Node has been converted (eg Japanese mode)
#define NF_CONVERTED 4
+
+/// NF_GAME - Node is on the path in game mode
#define NF_GAME 8
+
+/// NF_ALLCHILDREN - Node has all children. TODO Since nodes only
+/// ever have all their children, or none of them, can we not
+/// just check it has children, and get rid of this flag?
#define NF_ALLCHILDREN 16
+
+/// NF_SUPER - Node covers entire visible area (and so is eligible
+/// to be made the new root)
#define NF_SUPER 32
+
+/// NF_END_GAME - Node is the last one of the phrase in game mode
#define NF_END_GAME 64
+/// NF_VISIBLE - an invisible node is one which lets its parent's
+/// colour show through, and has no outline drawn round it (it may
+/// still have a label). Note that this flag is set (i.e. the node
+/// is drawn and outlined) by default in the constructor.
+#define NF_VISIBLE 128
+
+///Flags to assign to a newly created node:
+#define DEFAULT_FLAGS NF_VISIBLE
+
/// \ingroup Model
/// @{
@@ -80,11 +106,14 @@ class Dasher::CDasherNode:private NoClones {
/// @brief Constructor
///
- /// @param pParent Parent of the new node
+ /// Note the flags of the new node are initialized to DEFAULT_FLAGS.
+ ///
+ /// @param pParent Parent of the new node; automatically adds self to children
+ /// @param iOffset index into text box of character being/last entered
/// @param iLbnd Lower bound of node within parent
/// @param iHbnd Upper bound of node within parent
- /// @param pDisplayInfo Struct containing information on how to display the node
- ///
+ /// @param iColour colour to render node; for invisible nodes, should be same as parent.
+ /// @param strDisplayText label to render upon node
CDasherNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const std::string &strDisplayText);
/// @brief Destructor
@@ -98,24 +127,8 @@ class Dasher::CDasherNode:private NoClones {
/// @brief Set a node flag
///
- /// Set various flags corresponding to the state of the node. The following flags are defined:
- ///
- /// NF_COMMITTED - Node is 'above' the root, so corresponding symbol
- /// has been added to text box, language model trained etc
- ///
- /// NF_SEEN - Node has already been output
- ///
- /// NF_CONVERTED - Node has been converted (eg Japanese mode)
- ///
- /// NF_GAME - Node is on the path in game mode
- ///
- /// NF_ALLCHILDREN - Node has all children (TODO: obsolete?)
- ///
- /// NF_SUPER - Node covers entire visible area
- ///
- /// NF_END_GAME - Node is the last one of the phrase in game mode
- ///
- ///
+ /// Set various flags corresponding to the state of the node.
+ ///
/// @param iFlag The flag to set
/// @param bValue The new value of the flag
///
@@ -269,8 +282,6 @@ class Dasher::CDasherNode:private NoClones {
unsigned int m_iLbnd;
unsigned int m_iHbnd; // the cumulative lower and upper bound prob relative to parent
- int m_iRefCount; // reference count if ancestor of (or equal to) root node
-
ChildMap m_mChildren; // pointer to array of children
CDasherNode *m_pParent; // pointer to parent
diff --git a/Src/DasherCore/DasherViewSquare.cpp b/Src/DasherCore/DasherViewSquare.cpp
index f2e4004..a08c9bd 100644
--- a/Src/DasherCore/DasherViewSquare.cpp
+++ b/Src/DasherCore/DasherViewSquare.cpp
@@ -99,14 +99,6 @@ CDasherNode *CDasherViewSquare::Render(CDasherNode *pRoot, myint iRootMin, myint
VisibleRegion(iDasherMinX, iDasherMinY, iDasherMaxX, iDasherMaxY);
//
- screenint iScreenLeft;
- screenint iScreenTop;
- screenint iScreenRight;
- screenint iScreenBottom;
-
- Dasher2Screen(iRootMax-iRootMin, iRootMin, iScreenLeft, iScreenTop);
- Dasher2Screen(0, iRootMax, iScreenRight, iScreenBottom);
-
m_iRenderCount = 0;
CDasherNode *pOutput = pRoot->Parent();
@@ -127,11 +119,19 @@ CDasherNode *CDasherViewSquare::Render(CDasherNode *pRoot, myint iRootMin, myint
DasherDrawRectangle(0, iDasherMinY, iDasherMinX, iDasherMaxY, 0, -1, 0);
//and render root.
- DisjointRender(pRoot, iRootMin, iRootMax, NULL, policy, std::numeric_limits<double>::infinity(), 0, pOutput);
+ DisjointRender(pRoot, iRootMin, iRootMax, NULL, policy, std::numeric_limits<double>::infinity(), pOutput);
} else {
//overlapping rects/shapes
- Screen()->DrawRectangle(0, 0, Screen()->GetWidth(), Screen()->GetHeight(), 0, -1, 0);
- NewRender(pRoot, iRootMin, iRootMax, NULL, policy, std::numeric_limits<double>::infinity(), 0, pOutput);
+ if (pOutput) {
+ //LEFT of Y axis, would be entirely covered by the root node parent (before we render root)
+ // (getColour() gives the right colour, even if pOutput is invisible - in that case it gives
+ // the colour of its parent)
+ DasherDrawRectangle(iDasherMaxX, iDasherMinY, 0, iDasherMaxY, pOutput->getColour(), -1, 0);
+ //RIGHT of Y axis, should be white.
+ DasherDrawRectangle(0, iDasherMinY, iDasherMinX, iDasherMaxY, 0, -1, 0);
+ } else //easy case, whole screen is white (outside root node, e.g. when starting)
+ Screen()->DrawRectangle(0, 0, Screen()->GetWidth(), Screen()->GetHeight(), 0, -1, 0);
+ NewRender(pRoot, iRootMin, iRootMax, NULL, policy, std::numeric_limits<double>::infinity(), pOutput);
}
// Labels are drawn in a second parse to get the overlapping right
@@ -465,7 +465,7 @@ bool CDasherViewSquare::IsSpaceAroundNode(myint y1, myint y2) {
void CDasherViewSquare::DisjointRender(CDasherNode *pRender, myint y1, myint y2,
CTextString *pPrevText, CExpansionPolicy &policy, double dMaxCost,
- int parent_color, CDasherNode *&pOutput)
+ CDasherNode *&pOutput)
{
DASHER_ASSERT_VALIDPTR_RW(pRender);
@@ -534,8 +534,8 @@ void CDasherViewSquare::DisjointRender(CDasherNode *pRender, myint y1, myint y2,
if (newy2-newy1 < iDasherMaxX) //fill in to it's left...
DasherDrawRectangle(std::min(Range,iDasherMaxX), std::max(y1,iDasherMinY), newy2-newy1, std::min(y2,iDasherMaxY), myColor, -1, 0);
- DisjointRender(pChild, newy1, newy2, pPrevText,
- policy, dMaxCost, myColor, pOutput);
+ DisjointRender(pChild, newy1, newy2, pPrevText,
+ policy, dMaxCost, pOutput);
//leave pRender->onlyChildRendered set, so remaining children are skipped
}
else
@@ -557,7 +557,7 @@ void CDasherViewSquare::DisjointRender(CDasherNode *pRender, myint y1, myint y2,
pRender->onlyChildRendered = pChild;
if (newy2-newy1 < iDasherMaxX)
DasherDrawRectangle(std::min(Range,iDasherMaxX), std::max(y1,iDasherMinY), newy2-newy1, std::min(y2,iDasherMaxY), myColor, -1, 0);
- DisjointRender(pChild, newy1, newy2, pPrevText, policy, dMaxCost, myColor, pOutput);
+ DisjointRender(pChild, newy1, newy2, pPrevText, policy, dMaxCost, pOutput);
//ensure we don't blank over this child in "finishing off" the parent (!)
lasty=newy2;
//all remaining children are offscreen. quickly delete, avoid recomputing ranges...
@@ -574,7 +574,7 @@ void CDasherViewSquare::DisjointRender(CDasherNode *pRender, myint y1, myint y2,
if (std::max(lasty,iDasherMinY)<newy1) //fill in interval above child up to the last drawn child
DasherDrawRectangle(std::min(Range,iDasherMaxX), std::max(lasty,iDasherMinY),0, std::min(newy1,iDasherMaxY), myColor, -1, 0);
lasty = newy2;
- DisjointRender(pChild, newy1, newy2, pPrevText, policy, dMaxCost, myColor, pOutput);
+ DisjointRender(pChild, newy1, newy2, pPrevText, policy, dMaxCost, pOutput);
} else {
// We get here if the node is too small to render or is off-screen.
// So, collapse it immediately.
@@ -594,7 +594,7 @@ void CDasherViewSquare::DisjointRender(CDasherNode *pRender, myint y1, myint y2,
//end rendering children, fall through to outline
}
// Lastly, draw the outline
- if(GetLongParameter(LP_OUTLINE_WIDTH) && (!pRender->Parent() || pRender->getColour()!=pRender->Parent()->getColour())) {
+ if(GetLongParameter(LP_OUTLINE_WIDTH) && pRender->GetFlag(NF_VISIBLE)) {
DasherDrawRectangle(std::min(Range,iDasherMaxX), std::max(y1,iDasherMinY),0, std::min(y2,iDasherMaxY), -1, -1, abs(GetLongParameter(LP_OUTLINE_WIDTH)));
}
}
@@ -635,7 +635,7 @@ bool CDasherViewSquare::CoversCrosshair(myint Range, myint y1, myint y2) {
void CDasherViewSquare::NewRender(CDasherNode *pRender, myint y1, myint y2,
CTextString *pPrevText, CExpansionPolicy &policy, double dMaxCost,
- int parent_color, CDasherNode *&pOutput)
+ CDasherNode *&pOutput)
{
//when we have only one child node to render, which'll be the last thing we
// do before returning, we make a tail call by jumping here, rather than
@@ -679,7 +679,7 @@ beginning:
// _supposed_ to be the same colour as their parent, will have no outlines...
// (thankfully having 2 "phases" means this doesn't happen in standard
// colour schemes)
- if (myColor!=parent_color) {
+ if (pRender->GetFlag(NF_VISIBLE)) {
//outline width 0 = fill only; >0 = fill + outline; <0 = outline only
int fillColour = GetLongParameter(LP_OUTLINE_WIDTH)>=0 ? myColor : -1;
int lineWidth = abs(GetLongParameter(LP_OUTLINE_WIDTH));
@@ -737,7 +737,6 @@ beginning:
(newy1 < iDasherMinY && newy2 > iDasherMaxY)) { //covers entire y-axis!
//render just that child; nothing more to do for this node => tail call to beginning
pRender = pChild; y1=newy1; y2=newy2;
- parent_color = myColor;
goto beginning;
}
pRender->onlyChildRendered = NULL;
@@ -753,7 +752,7 @@ beginning:
if (newy1<=iDasherMaxY && newy2 >= iDasherMinY) { //onscreen
if (newy2-newy1 > GetLongParameter(LP_MIN_NODE_SIZE)) {
//definitely big enough to render.
- NewRender(pChild, newy1, newy2, pPrevText, policy, dMaxCost, myColor, pOutput);
+ NewRender(pChild, newy1, newy2, pPrevText, policy, dMaxCost, pOutput);
if (newy2 > iDasherMaxY) {
//remaining children offscreen.
if (newy1 < iDasherMinY) pRender->onlyChildRendered = pChild; //...and previous were too!
diff --git a/Src/DasherCore/DasherViewSquare.h b/Src/DasherCore/DasherViewSquare.h
index f514a02..bfb4319 100644
--- a/Src/DasherCore/DasherViewSquare.h
+++ b/Src/DasherCore/DasherViewSquare.h
@@ -147,14 +147,14 @@ private:
/// (i.e. appropriate for LP_SHAPE_TYPE==0). Each call responsible for rendering
/// exactly the area contained within the node.
/// @param pOutput The innermost node covering the crosshair (if any)
- void DisjointRender(CDasherNode * Render, myint y1, myint y2, CTextString *prevText, CExpansionPolicy &policy, double dMaxCost,int parent_color, CDasherNode *&pOutput);
-
+ void DisjointRender(CDasherNode * Render, myint y1, myint y2, CTextString *prevText, CExpansionPolicy &policy, double dMaxCost, CDasherNode *&pOutput);
+
/// (Recursively) render a node and all contained subnodes, in overlapping shapes
/// (according to LP_SHAPE_TYPE: 1=rects, 2=triangles, 3=truncated triangles,
/// 4=quadrics, 5=semicircles)
/// Each call responsible for rendering exactly the area contained within the node.
/// @param pOutput The innermost node covering the crosshair (if any)
- void NewRender(CDasherNode * Render, myint y1, myint y2, CTextString *prevText, CExpansionPolicy &policy, double dMaxCost,int parent_color, CDasherNode *&pOutput);
+ void NewRender(CDasherNode * Render, myint y1, myint y2, CTextString *prevText, CExpansionPolicy &policy, double dMaxCost, CDasherNode *&pOutput);
#ifdef _WIN32
///
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]