mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 22:02:49 -06:00
1469 lines
31 KiB
C++
1469 lines
31 KiB
C++
//////////////////////////////////////////////////////////////////////
|
|
// OldTreeCtrl: tree control.
|
|
|
|
#include "TCtrlLib.h"
|
|
#pragma hdrstop
|
|
|
|
#include "OldTreeCtrl.h"
|
|
|
|
namespace Upp {
|
|
|
|
#define IMAGECLASS OldTreeCtrlImg
|
|
#define IMAGEFILE <TCtrlLib/OldTreeCtrl.iml>
|
|
#include <Draw/iml_header.h>
|
|
|
|
enum { SCREEN_ZOOM = 140 };
|
|
|
|
#ifdef _DEBUG
|
|
//#define DBG_PAINT(co, dbgco) dbgco // debug version
|
|
#define DBG_PAINT(co, dbgco) co // release version
|
|
#else
|
|
#define DBG_PAINT(co, dbgco) co // release version
|
|
#endif
|
|
|
|
#define IMAGECLASS OldTreeCtrlImg
|
|
#define IMAGEFILE <TCtrlLib/OldTreeCtrl.iml>
|
|
#include <Draw/iml_source.h>
|
|
|
|
enum
|
|
{
|
|
ICONGAP = 6,
|
|
TEXTGAP = 5,
|
|
TSGAP = 3,
|
|
BUTTON_SIZE = 9,
|
|
BUTTON_HALF = BUTTON_SIZE >> 1,
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// OldTreeCursor::
|
|
|
|
OldTreeCursor::OldTreeCursor()
|
|
: root(0)
|
|
{
|
|
}
|
|
|
|
OldTreeCursor::OldTreeCursor(const OldTreeItem& item)
|
|
: root(0)
|
|
{
|
|
Find(item);
|
|
}
|
|
|
|
OldTreeCursor::OldTreeCursor(const OldTreeCursor& another, int)
|
|
: root(another.root)
|
|
, cursor(another.cursor, 0)
|
|
{
|
|
}
|
|
|
|
OldTreeCursor& OldTreeCursor::Adjust()
|
|
{
|
|
if(cursor.IsEmpty() || !root)
|
|
return *this;
|
|
const OldTreeItem *ptr = root;
|
|
int *b = cursor.Begin(), *e = cursor.End(), *p;
|
|
for(p = b; p < e; p++)
|
|
if(ptr->IsEmpty())
|
|
break;
|
|
else {
|
|
*p = minmax(*p, 0, ptr->GetCount() - 1);
|
|
ptr = &ptr->children[*p];
|
|
}
|
|
cursor.SetCount(p - b);
|
|
return *this;
|
|
}
|
|
|
|
OldTreeCursor& OldTreeCursor::WeakAdjust()
|
|
{
|
|
if(cursor.IsEmpty() || !root)
|
|
return *this;
|
|
const OldTreeItem *ptr = root;
|
|
int *b = cursor.Begin(), *e = cursor.End(), *p;
|
|
for(p = b; p < e; p++) {
|
|
*p = minmax(*p, 0, ptr->GetCount());
|
|
if(*p == ptr->GetCount()) {
|
|
p++;
|
|
break;
|
|
}
|
|
ptr = &ptr->children[*p];
|
|
}
|
|
cursor.SetCount(p - b);
|
|
return *this;
|
|
}
|
|
|
|
OldTreeCursor& OldTreeCursor::AddAfter(const OldTreeCursor& c, int count)
|
|
{
|
|
int top = c.cursor.GetCount() - 1;
|
|
if(!root || root != c.root || top < 0 || cursor.GetCount() <= top
|
|
|| memcmp(cursor.Begin(), c.cursor.Begin(), sizeof(int) * top))
|
|
return *this;
|
|
int d = cursor[top] - c.cursor[top];
|
|
if(d >= 0)
|
|
cursor[top] += max(count, -d);
|
|
return *this;
|
|
}
|
|
|
|
OldTreeCursor& OldTreeCursor::AdjustAfter(const OldTreeCursor& c, int count)
|
|
{
|
|
return AddAfter(c, count).Adjust();
|
|
}
|
|
|
|
OldTreeCursor& OldTreeCursor::WeakAdjustAfter(const OldTreeCursor& c, int count)
|
|
{
|
|
return AddAfter(c, count).WeakAdjust();
|
|
}
|
|
|
|
OldTreeItem *OldTreeCursor::Get() const
|
|
{
|
|
OldTreeItem *ptr = root;
|
|
for(const int *p = cursor.Begin(), *e = cursor.End(); ptr && p < e; p++)
|
|
ptr = (*p >= 0 && *p < ptr->children.GetCount() ? &ptr->children[*p] : NULL);
|
|
return ptr;
|
|
}
|
|
|
|
OldTreeItem *OldTreeCursor::GetParent() const
|
|
{
|
|
if(!root || cursor.IsEmpty())
|
|
return NULL;
|
|
OldTreeItem *ptr = root;
|
|
for(const int *p = cursor.Begin(), *e = cursor.End() - 1; ptr && p < e; p++)
|
|
ptr = (*p >= 0 && *p < ptr->children.GetCount() ? &ptr->children[*p] : NULL);
|
|
return ptr;
|
|
}
|
|
|
|
const OldTreeCursor& OldTreeCursor::Open() const
|
|
{
|
|
if(!root)
|
|
return *this;
|
|
OldTreeItem *i = root;
|
|
for(const int *p = cursor.Begin(), *e = cursor.End(); p < e; p++) {
|
|
if(!i->IsOpenItem())
|
|
i->Open().TouchLayout();
|
|
if(*p < 0 || *p >= i->GetCount())
|
|
break;
|
|
i = &(*i)[*p];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
OldTreeCursor& OldTreeCursor::BeginAll()
|
|
{
|
|
cursor.Clear();
|
|
return *this;
|
|
}
|
|
|
|
OldTreeCursor& OldTreeCursor::EndAll()
|
|
{
|
|
cursor.Clear();
|
|
ASSERT(root);
|
|
cursor.Add(root->GetCount());
|
|
return *this;
|
|
}
|
|
|
|
bool OldTreeCursor::IsBeginAll() const
|
|
{
|
|
return cursor.IsEmpty();
|
|
}
|
|
|
|
bool OldTreeCursor::IsEndAll() const
|
|
{
|
|
ASSERT(root);
|
|
return !cursor.IsEmpty() && cursor[0] >= root->GetCount();
|
|
}
|
|
|
|
bool OldTreeCursor::IsBegin() const
|
|
{
|
|
return cursor.IsEmpty() || cursor.Top() == 0;
|
|
}
|
|
|
|
const OldTreeCursor& OldTreeCursor::Select(bool select, bool subtree) const
|
|
{
|
|
OldTreeItem *ptr = Get();
|
|
if(ptr)
|
|
if(subtree)
|
|
ptr->SelectTree(select);
|
|
else
|
|
ptr->Select(select);
|
|
return *this;
|
|
}
|
|
|
|
OldTreeCursor& OldTreeCursor::Find(const OldTreeItem& item)
|
|
{
|
|
cursor.Clear();
|
|
if(root = item.owner) {
|
|
for(OldTreeItem *i = const_cast<OldTreeItem *>(&item); i->parent; i = i->parent) {
|
|
int pos = i->parent->children.GetIndex(*i);
|
|
ASSERT(pos >= 0);
|
|
cursor.Insert(0, pos);
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
OldTreeItem *OldTreeCursor::Find(int clss, int flags)
|
|
{
|
|
for(OldTreeItem *i; i = Get(); Down(flags))
|
|
if(i->GetClass() == clss)
|
|
return i;
|
|
return NULL;
|
|
}
|
|
|
|
bool OldTreeCursor::Up(int flags)
|
|
{
|
|
OldTreeItem *parent = GetParent();
|
|
if(!parent)
|
|
return false;
|
|
int pos = min(cursor.Top(), parent->GetCount());
|
|
if(pos <= 0) { // drop out of child into parent
|
|
if(flags & LEFT)
|
|
cursor.Drop();
|
|
return true;
|
|
}
|
|
cursor.Top() = (pos -= 1);
|
|
if(flags & (RIGHT | RIGHT_CLOSED))
|
|
for(OldTreeItem *temp; temp = &parent->children[pos],
|
|
!temp->IsEmpty() && (temp->IsOpenItem() || flags & RIGHT_CLOSED);
|
|
cursor.Add(pos = temp->GetCount() - 1), parent = temp)
|
|
;
|
|
return true;
|
|
}
|
|
|
|
bool OldTreeCursor::Down(int flags)
|
|
{
|
|
if(cursor.IsEmpty()) { // step into 1st item
|
|
if(flags & (RIGHT | RIGHT_CLOSED) && root && !root->IsEmpty()
|
|
&& (root->IsOpenItem() || flags & RIGHT_CLOSED)) {
|
|
cursor.Add(0);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
OldTreeItem *parent = GetParent();
|
|
if(!parent)
|
|
return false;
|
|
int pos = cursor.Top();
|
|
if(pos < parent->GetCount() && flags & (RIGHT | RIGHT_CLOSED)) {
|
|
OldTreeItem *ptr = &parent->children[pos];
|
|
if(!ptr->IsEmpty() && (ptr->IsOpenItem() || flags & RIGHT_CLOSED)) { // descend into child
|
|
cursor.Add(0);
|
|
return true;
|
|
}
|
|
}
|
|
do {
|
|
if(++cursor.Top() < parent->GetCount()) // move to next item in current row
|
|
return true;
|
|
if(!(flags & LEFT) || cursor.GetCount() <= 1) { // not moving out or global last item encountered - move to end item
|
|
cursor.Top() = parent->GetCount();
|
|
return true;
|
|
}
|
|
cursor.Drop();
|
|
}
|
|
while(parent = parent->parent);
|
|
return true;
|
|
}
|
|
|
|
OldTreeCursor& OldTreeCursor::Right()
|
|
{
|
|
if(!IsEnd())
|
|
cursor.Add(0);
|
|
return *this;
|
|
}
|
|
|
|
OldTreeCursor& OldTreeCursor::Left()
|
|
{
|
|
if(!cursor.IsEmpty())
|
|
cursor.Drop();
|
|
return *this;
|
|
}
|
|
|
|
OldTreeCursor& OldTreeCursor::Begin()
|
|
{
|
|
cursor.Top() = 0;
|
|
return *this;
|
|
}
|
|
|
|
OldTreeCursor& OldTreeCursor::End()
|
|
{
|
|
OldTreeItem *parent = GetParent();
|
|
if(parent)
|
|
cursor.Top() = parent->GetCount();
|
|
return *this;
|
|
}
|
|
|
|
int TreeCursor_Compare(const OldTreeCursor& a, const OldTreeCursor& b)
|
|
{
|
|
return OldTreeCursor::Compare(a, b);
|
|
}
|
|
|
|
int OldTreeCursor::Compare(const OldTreeCursor& a, const OldTreeCursor& b)
|
|
{
|
|
if(a.root != b.root)
|
|
return cmp(a.root, b.root);
|
|
const int *pa = a.cursor.Begin(), *ea = pa + min(a.cursor.GetCount(), b.cursor.GetCount());
|
|
const int *pb = b.cursor.Begin();
|
|
for(; pa < ea; pa++, pb++)
|
|
if(*pa != *pb)
|
|
return cmp(*pa, *pb);
|
|
return cmp(a.cursor.GetCount(), b.cursor.GetCount());
|
|
}
|
|
|
|
String OldTreeCursor::ToString() const
|
|
{
|
|
String out;
|
|
out << '[';
|
|
for(int i = 0; i < cursor.GetCount(); i++) {
|
|
if(i)
|
|
out << ", ";
|
|
out << cursor[i];
|
|
}
|
|
out << ']';
|
|
return out;
|
|
}
|
|
|
|
bool OldTreeCursor::IsSubtreeOf(const OldTreeCursor& top) const
|
|
{
|
|
return top.root == root
|
|
&& top.cursor.GetCount() <= cursor.GetCount()
|
|
&& !memcmp(top.cursor.Begin(), cursor.Begin(), top.cursor.GetCount() * sizeof(int));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// SimpleTreeItem::
|
|
|
|
SimpleTreeItem::SimpleTreeItem()
|
|
{
|
|
Zero(*this);
|
|
indent = 0;
|
|
type = TEXT;
|
|
layout = false;
|
|
enabled = true;
|
|
branch = true;
|
|
leaf = true;
|
|
auto_size = true;
|
|
auto_indent = true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// OldTreeItem::
|
|
|
|
OldTreeItem::OldTreeItem()
|
|
: text(String::GetVoid())
|
|
{
|
|
}
|
|
|
|
OldTreeItem::OldTreeItem(const OldTreeItem& item, int)
|
|
: SimpleTreeItem(item)
|
|
, text(item.text)
|
|
, value(item.value)
|
|
, subtree(item.subtree)
|
|
, children(item.children, 0)
|
|
{
|
|
}
|
|
|
|
OldTreeItem& OldTreeItem::Open(bool _open)
|
|
{
|
|
if((open = _open) && !up_to_date && subtree) { // expand subtree as necessary
|
|
subtree(*this);
|
|
if(is_static)
|
|
up_to_date = true;
|
|
TouchLayout();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void OldTreeItem::SetCursor()
|
|
{
|
|
if(this) {
|
|
ASSERT(owner);
|
|
owner->SetCursor(this);
|
|
}
|
|
}
|
|
|
|
bool OldTreeItem::IsSubtree() const
|
|
{
|
|
return !IsEmpty() || (subtree && !up_to_date);
|
|
}
|
|
|
|
bool OldTreeItem::IsOpenFull() const
|
|
{
|
|
return IsOpenItem() && !IsEmpty();
|
|
}
|
|
|
|
String OldTreeItem::GetTextOrValue() const
|
|
{
|
|
if(!text.IsVoid())
|
|
return text;
|
|
return StdFormat(value);
|
|
}
|
|
|
|
OldTreeItem& OldTreeItem::Select(bool _sel)
|
|
{
|
|
if(this && selected != _sel) {
|
|
selected = _sel;
|
|
Touch();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
OldTreeItem& OldTreeItem::SelectTree(bool _sel)
|
|
{
|
|
if(this) {
|
|
Select(_sel);
|
|
for(int i = 0; i < GetCount(); i++)
|
|
children[i].SelectTree(_sel);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
int OldTreeItem::GetCount(int clss) const
|
|
{
|
|
int count = (item_class == clss ? 1 : 0);
|
|
for(int i = 0; i < children.GetCount(); i++)
|
|
count += children[i].GetCount(clss);
|
|
return count;
|
|
}
|
|
|
|
int OldTreeItem::GetCountDeep() const
|
|
{
|
|
if(this == 0)
|
|
return 0;
|
|
int count = 1;
|
|
for(int i = 0; i < children.GetCount(); i++)
|
|
count += children[i].GetCountDeep();
|
|
return count;
|
|
}
|
|
|
|
const OldTreeItem *OldTreeItem::FindValue(Value _value) const
|
|
{
|
|
if(value == _value)
|
|
return this;
|
|
for(int i = 0; i < children.GetCount(); i++) {
|
|
const OldTreeItem *p = children[i].FindValue(_value);
|
|
if(p)
|
|
return p;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
OldTreeItem *OldTreeItem::FindValue(Value _value)
|
|
{
|
|
if(value == _value)
|
|
return this;
|
|
for(int i = 0; i < children.GetCount(); i++) {
|
|
OldTreeItem *p = children[i].FindValue(_value);
|
|
if(p)
|
|
return p;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void OldTreeItem::Touch()
|
|
{
|
|
if(this && !owner->updating && !owner->IsFullRefresh())
|
|
owner->Refresh(GetClientRect());
|
|
}
|
|
|
|
void OldTreeItem::TouchLayout()
|
|
{
|
|
if(this && !layout) {
|
|
OldTreeItem *p = this;
|
|
while(p && !p->layout) {
|
|
p->layout = true;
|
|
p = p->parent;
|
|
}
|
|
if(!p && owner)
|
|
owner->Refresh();
|
|
}
|
|
}
|
|
|
|
Rect OldTreeItem::GetRect(int hittest) const
|
|
{
|
|
Rect sum = Null;
|
|
if(item_size.cy <= 0)
|
|
return sum;
|
|
|
|
if((hittest & HBUTTON) && IsLeaf() && IsSubtree())
|
|
sum = RectC(-BUTTON_HALF, (item_size.cy >> 1) - BUTTON_HALF, BUTTON_SIZE, BUTTON_SIZE);
|
|
|
|
Size iconsize(0, 0);
|
|
if(type == TEXT && image)
|
|
iconsize = image.GetSize();
|
|
int left = 0;
|
|
if(leaf)
|
|
left += BUTTON_HALF + 1 + ICONGAP;
|
|
if(type == TEXT && image) {
|
|
if(hittest & HICON)
|
|
sum |= RectC(left, 0, iconsize.cx, item_size.cy);
|
|
left += iconsize.cx + TEXTGAP;
|
|
}
|
|
if(hittest & (HTEXT | HPICT | HCTRL))
|
|
sum |= Rect(left, 0, item_size.cx ? item_size.cx : tree_size.cx, item_size.cy);
|
|
|
|
return sum;
|
|
}
|
|
|
|
OldTreeItem& OldTreeItem::Clear()
|
|
{
|
|
children.Clear();
|
|
TouchLayout();
|
|
return *this;
|
|
}
|
|
|
|
OldTreeItem& OldTreeItem::SetCount(int n)
|
|
{
|
|
if(children.GetCount() == n)
|
|
return *this;
|
|
|
|
while(children.GetCount() < n)
|
|
Add();
|
|
children.SetCount(n);
|
|
TouchLayout();
|
|
return *this;
|
|
}
|
|
|
|
OldTreeItem *OldTreeItem::Detach(int pos)
|
|
{
|
|
children[pos].TouchLayout();
|
|
return children.Detach(pos);
|
|
}
|
|
|
|
OldTreeItem& OldTreeItem::Add()
|
|
{
|
|
return Insert(GetCount(), new OldTreeItem);
|
|
}
|
|
|
|
OldTreeItem& OldTreeItem::Insert(int pos)
|
|
{
|
|
return Insert(pos, new OldTreeItem);
|
|
}
|
|
|
|
OldTreeItem& OldTreeItem::Add(OldTreeItem *item)
|
|
{
|
|
return Insert(GetCount(), item);
|
|
}
|
|
|
|
static void SetOwner(OldTreeItem& item)
|
|
{
|
|
for(int i = 0; i < item.GetCount(); i++)
|
|
SetOwner(item[i].SetOwner(item.GetOwner()));
|
|
}
|
|
|
|
OldTreeItem& OldTreeItem::Insert(int pos, OldTreeItem *item)
|
|
{
|
|
ASSERT(owner && item);
|
|
children.Insert(pos, item);
|
|
item->parent = this;
|
|
item->owner = owner;
|
|
UPP::SetOwner(*item);
|
|
item->TouchLayout();
|
|
return *item;
|
|
}
|
|
|
|
void OldTreeItem::Remove(int pos, int count)
|
|
{
|
|
ASSERT(owner);
|
|
ASSERT(pos >= 0 && pos < GetCount());
|
|
if(pos >= 0 && pos < GetCount()) {
|
|
children.Remove(pos, count);
|
|
TouchLayout();
|
|
}
|
|
}
|
|
|
|
void OldTreeItem::LayoutItem()
|
|
{
|
|
ASSERT(owner);
|
|
if(!layout)
|
|
return;
|
|
Size iconsize = image.GetSize();
|
|
int leafgap = (leaf ? BUTTON_HALF + 1 + ICONGAP : 0);
|
|
if(auto_indent)
|
|
indent = leafgap + (iconsize.cx >> 1);
|
|
if(auto_size) {
|
|
Size textsize(0, 0);
|
|
item_size = Size(0, 0);
|
|
|
|
switch(type) {
|
|
case TEXT: {
|
|
String display = GetTextOrValue();
|
|
if(!IsNull(display)) {
|
|
/* if(*display == '\xFF') {
|
|
Document doc(display.Begin() + 1);
|
|
Size size;
|
|
textsize.cx = doc.GetWidth(DOC_SCREEN_ZOOM, ScreenInfo());
|
|
textsize.cy = doc.GetHeight(DOC_SCREEN_ZOOM, ScreenInfo(), textsize.cx);
|
|
}
|
|
else*/
|
|
textsize = GetSmartTextSize(display, owner->font);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PICT:
|
|
textsize = picture->GetStdSize(value);
|
|
break;
|
|
|
|
case CTRL:
|
|
textsize = ctrl->GetRect().Size();
|
|
break;
|
|
}
|
|
item_size.cx = iconsize.cx + textsize.cx + leafgap + TSGAP;
|
|
item_size.cy = max(iconsize.cy, textsize.cy);
|
|
if(iconsize.cx && textsize.cx)
|
|
item_size.cx += TEXTGAP;
|
|
}
|
|
|
|
tree_size = item_size;
|
|
|
|
/* if(subtree && open) { // expand subtree as necessary
|
|
if(!up_to_date) {
|
|
subtree(*this);
|
|
if(is_static)
|
|
up_to_date = true;
|
|
}
|
|
}
|
|
*/
|
|
if(open) { // include children in raw size
|
|
for(int i = 0; i < children.GetCount(); i++) {
|
|
OldTreeItem& child = children[i];
|
|
child.LayoutItem();
|
|
tree_size.cx = max(tree_size.cx, child.tree_size.cx + indent);
|
|
tree_size.cy += child.tree_size.cy;
|
|
}
|
|
}
|
|
|
|
layout = false;
|
|
}
|
|
|
|
void OldTreeItem::PaintItem(Draw& draw, Point pos) const
|
|
{
|
|
Rect clip(0, 0, 9999, 9999);
|
|
Rect rc = Rect(pos.x - BUTTON_HALF, pos.y, clip.right, pos.y + tree_size.cy) & clip;
|
|
if(rc.IsEmpty())
|
|
return;
|
|
int daddy = pos.x;
|
|
|
|
Color bg = (owner->IsShowEnabled() ? SWhite : SLtGray);
|
|
{ // clear branch area
|
|
int lb = pos.x + (leaf ? BUTTON_HALF + 1 : 0);
|
|
int rb = pos.x + indent + BUTTON_HALF + 1;
|
|
draw.DrawRect(lb, pos.y, clip.right - lb, item_size.cy, DBG_PAINT(bg, LtRed));
|
|
draw.DrawRect(lb, pos.y, rb - lb, tree_size.cy, DBG_PAINT(bg, LtMagenta));
|
|
/*
|
|
int left = parent ? prev + 1 : clip.left;
|
|
int right = pos.x + branch_indent + 1;
|
|
if(right - left)
|
|
draw.DrawRect(left, rc.top, right - left, rc.Height(), bg);
|
|
*/
|
|
}
|
|
|
|
if(IsBranch() && IsOpenFull()) { // generate branch
|
|
int top = pos.y + item_size.cy;
|
|
int bot = Null, bbot = Null;
|
|
int tmp = top;
|
|
for(int i = 0; i < children.GetCount(); i++) {
|
|
const OldTreeItem& child = children[i];
|
|
if(child.item_size.cy > 0 && child.leaf) {
|
|
bot = tmp + (child.item_size.cy >> 1) + 1;
|
|
bbot = tmp + child.item_size.cy;
|
|
}
|
|
tmp += child.tree_size.cy;
|
|
}
|
|
if(!IsNull(bot) && item_size.cy > 0) { // vertical joint
|
|
int x = pos.x + indent;
|
|
DrawRect(draw, Rect(x, top, x + 1, bot), OldTreeCtrlImg::dither());
|
|
}
|
|
}
|
|
|
|
if(item_size.cy > 0) {
|
|
Rect item(pos, GetItemSize());
|
|
// if(prev + 1 < clip.right)
|
|
// draw.DrawRect(prev + 1, item.top, clip.right - prev - 1, item.Height(), bg);
|
|
if(item.Width() == 0)
|
|
item.right = item.left + tree_size.cx;
|
|
if(item.bottom > rc.top && item.top < rc.bottom) {
|
|
if(leaf) { // draw leaf
|
|
int mid = (item.top + item.bottom) >> 1;
|
|
DrawRect(draw, pos.x, mid, BUTTON_SIZE + ICONGAP, 1, OldTreeCtrlImg::dither());
|
|
if(IsSubtree()) { // draw expand/collapse button
|
|
draw.DrawImage(pos.x - BUTTON_HALF, mid - BUTTON_HALF, IsOpenItem() ? OldTreeCtrlImg::minus() : OldTreeCtrlImg::plus());
|
|
}
|
|
item.left += BUTTON_HALF + 1 + ICONGAP;
|
|
}
|
|
|
|
Color ink = SBlack;
|
|
Color bgnd = bg;
|
|
if(IsSelected())
|
|
if(owner->HasFocus()) {
|
|
bgnd = SBlue;
|
|
ink = SWhite;
|
|
}
|
|
else {
|
|
bgnd = SLtGray;
|
|
ink = SBlack;
|
|
}
|
|
|
|
if(image) {
|
|
Size iconsize = image.GetSize();
|
|
Point iconpos(item.left, (item.top + item.bottom - iconsize.cy) >> 1);
|
|
#ifdef NEWIMAGE
|
|
draw.DrawImage(iconpos.x, iconpos.y, enabled ? image : MakeImage(image, Etched));
|
|
#else
|
|
draw.DrawImage(iconpos.x, iconpos.y, image, enabled ? 0 : image.ETCHED);
|
|
#endif
|
|
item.left += iconsize.cx + TEXTGAP;
|
|
}
|
|
|
|
switch(type) {
|
|
case TEXT: {
|
|
String display = GetTextOrValue();
|
|
WString wdisplay;
|
|
if(!IsNull(display)) {
|
|
Size size;
|
|
if(*display == '\xFF') {
|
|
Document doc;
|
|
doc.Qtf(display.Begin() + 1);
|
|
size.cx = doc.GetWidth(SCREEN_ZOOM);
|
|
size.cy = doc.GetHeight(SCREEN_ZOOM, size.cx);
|
|
}
|
|
else
|
|
size = GetTLTextSize(wdisplay = display.ToWString(), owner->font);
|
|
|
|
Rect trc = item;
|
|
trc.left -= TSGAP;
|
|
// trc.top = (item.top + item.bottom - size.cy) >> 1;
|
|
// trc.bottom = trc.top + size.cy;
|
|
draw.DrawRect(trc, bgnd);
|
|
trc.left += TSGAP;
|
|
trc.top = (item.top + item.bottom - size.cy) >> 1;
|
|
if(*display == '\xFF') {
|
|
Document doc;
|
|
String s;
|
|
s << "[@(" << ink.GetR() << "." << ink.GetG() << "." << ink.GetB() << ") "
|
|
<< display.Begin() + 1;
|
|
doc.Qtf(s);
|
|
doc.Paint(SCREEN_ZOOM, draw, trc.left, trc.top, trc.Width());
|
|
}
|
|
else
|
|
DrawTLText(draw, trc.left, trc.top, trc.Width(), wdisplay, owner->font, ink);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PICT:
|
|
picture->Paint(draw, item, value, ink, bgnd, 0);
|
|
break;
|
|
|
|
case CTRL:
|
|
if(item != ctrl->GetRect())
|
|
ctrl->SetRect(item);
|
|
break;
|
|
}
|
|
}
|
|
pos.y += item_size.cy;
|
|
}
|
|
if(IsOpenFull()) {
|
|
pos.x += indent;
|
|
int i = 0;
|
|
for(; i < children.GetCount() && pos.y + children[i].tree_size.cy <= rc.top; i++)
|
|
pos.y += children[i].tree_size.cy;
|
|
for(; i < children.GetCount() && pos.y < rc.bottom; i++) {
|
|
children[i].PaintItem(draw, pos);
|
|
pos.y += children[i].tree_size.cy;
|
|
}
|
|
}
|
|
}
|
|
|
|
OldTreeItem::HITTEST OldTreeItem::FindItem(Point pt, OldTreeItem *& item) const
|
|
{
|
|
if(pt.y < 0 || pt.y >= tree_size.cy) {
|
|
item = NULL;
|
|
return HNIL;
|
|
}
|
|
if(item_size.cy > 0 && pt.y < item_size.cy) { // check this item
|
|
item = (OldTreeItem*)this;
|
|
if(GetRect(HBUTTON).Contains(pt))
|
|
return HBUTTON;
|
|
|
|
switch(type) {
|
|
case TEXT:
|
|
if(GetRect(HICON).Contains(pt))
|
|
return HICON;
|
|
if(GetRect(HTEXT).Contains(pt))
|
|
return HTEXT;
|
|
break;
|
|
|
|
case PICT:
|
|
if(GetRect(HPICT).Contains(pt))
|
|
return HPICT;
|
|
break;
|
|
|
|
case CTRL:
|
|
if(GetRect(HCTRL).Contains(pt))
|
|
return HCTRL;
|
|
break;
|
|
}
|
|
return HOTHER;
|
|
}
|
|
|
|
|
|
if(IsOpenFull() && (pt.y -= item_size.cy) >= 0) {
|
|
pt.x -= indent;
|
|
for(int i = 0; i < children.GetCount() && pt.y >= 0; pt.y -= children[i++].tree_size.cy) {
|
|
HITTEST result;
|
|
if((result = children[i].FindItem(pt, item)) != HNIL)
|
|
return result;
|
|
}
|
|
}
|
|
|
|
item = NULL;
|
|
return HNIL;
|
|
}
|
|
|
|
int OldTreeItem::GetOpenCount() const
|
|
{
|
|
int count = 0;
|
|
if(item_size.cy > 0)
|
|
count++;
|
|
if(IsOpenFull())
|
|
for(List::ConstIterator p = children.Begin(), e = children.End(); p < e; p++)
|
|
count += p->GetOpenCount();
|
|
return count;
|
|
}
|
|
|
|
Rect OldTreeItem::GetItemRect(int hittest) const
|
|
{
|
|
Rect rc = GetRect(hittest);
|
|
for(const OldTreeItem *c = this, *p; p = c->parent; c = p) {
|
|
int i;
|
|
if(!p->IsOpenFull() || (i = p->children.GetIndex(*c)) < 0)
|
|
return Null; // error
|
|
int y = p->item_size.cy;
|
|
for(int t = 0; t < i; t++)
|
|
y += p->children[t].tree_size.cy;
|
|
rc.Offset(p->indent, y);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
Rect OldTreeItem::GetClientRect(int hittest) const
|
|
{
|
|
return GetItemRect(hittest) + (owner->offset - owner->old_scroll);
|
|
}
|
|
|
|
Rect OldTreeItem::GetTreeRect() const
|
|
{
|
|
Rect rc(0, 0, tree_size.cx, tree_size.cy);
|
|
for(const OldTreeItem *c = this, *p; p = c->parent; c = p) {
|
|
int i;
|
|
if(!p->IsOpenFull() || (i = p->children.GetIndex(*c)) < 0)
|
|
return Null; // error
|
|
int y = p->item_size.cy;
|
|
for(int t = 0; t < i; t++)
|
|
y += p->children[t].tree_size.cy;
|
|
rc.Offset(p->indent, y);
|
|
}
|
|
return rc;
|
|
|
|
}
|
|
|
|
Rect OldTreeItem::GetClientTreeRect() const
|
|
{
|
|
return GetTreeRect() + (owner->offset - owner->old_scroll);
|
|
}
|
|
|
|
OldTreeItem& OldTreeItem::Set(Proc proc)
|
|
{
|
|
subtree.Clear();
|
|
proc(*this);
|
|
return *this;
|
|
}
|
|
|
|
Bar::Item& OldTreeItem::BarOpenClose(Bar& bar)
|
|
{
|
|
return bar.Add(enabled && IsSubtree(),
|
|
IsOpenItem() ? t_("Close") : t_("Open"), callback(this, &OldTreeItem::OnOpenClose))
|
|
.Help(IsOpenItem() ? t_("Close child items") : t_("Open child items"));
|
|
}
|
|
|
|
Bar::Item& OldTreeItem::BarOpenSubtree(Bar& bar)
|
|
{
|
|
return bar.Add(enabled && IsSubtree(),
|
|
t_("Open all"), callback(this, &OldTreeItem::OnOpenSubtree))
|
|
.Help(t_("Open the whole subtree"));
|
|
}
|
|
|
|
Bar::Item& OldTreeItem::BarCloseSubtree(Bar& bar)
|
|
{
|
|
return bar.Add(enabled && IsSubtree(),
|
|
t_("Close all"), callback(this, &OldTreeItem::OnCloseSubtree))
|
|
.Help(t_("Close the whole subtree"));
|
|
}
|
|
|
|
void OldTreeItem::OnOpenClose()
|
|
{
|
|
if(enabled && IsSubtree()) {
|
|
Open(!IsOpenItem());
|
|
TouchLayout();
|
|
LayoutItem();
|
|
ScrollInto();
|
|
}
|
|
}
|
|
|
|
void OldTreeItem::OnOpenSubtreeRaw()
|
|
{
|
|
if(enabled) {
|
|
Open();
|
|
TouchLayout();
|
|
for(int i = 0; i < GetCount(); i++)
|
|
children[i].OnOpenSubtree();
|
|
}
|
|
}
|
|
|
|
void OldTreeItem::OnOpenSubtree()
|
|
{
|
|
OnOpenSubtreeRaw();
|
|
ScrollInto();
|
|
}
|
|
|
|
void OldTreeItem::OnCloseSubtree()
|
|
{
|
|
for(int i = 0; i < GetCount(); i++)
|
|
children[i].OnCloseSubtree();
|
|
Close();
|
|
TouchLayout();
|
|
}
|
|
|
|
void OldTreeItem::ScrollInto()
|
|
{
|
|
if(this && owner/* && owner->IsOpen()*/) {
|
|
owner->Layout();
|
|
Rect rc = owner->GetOffset() + GetItemRect();
|
|
rc.Inflate(4);
|
|
owner->ScrollInto(rc);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// OldTreeEdit::
|
|
|
|
OldTreeEdit& OldTreeEdit::Perform()
|
|
{
|
|
if(!cursor)
|
|
return *this;
|
|
item.TouchLayout();
|
|
OldTreeItem *pos;
|
|
switch(op & ~DEEP) {
|
|
case INS:
|
|
if(pos = cursor.GetParent()) {
|
|
int index = minmax(cursor.cursor.Top(), 0, pos->GetCount());
|
|
if(op & DEEP)
|
|
pos->Insert(index) <<= item;
|
|
else
|
|
pos->Insert(index) = item;
|
|
pos->TouchLayout();
|
|
}
|
|
else
|
|
NEVER();
|
|
break;
|
|
case INS | KIDS:
|
|
if(pos = cursor.Get()) {
|
|
if(!item.IsEmpty()) {
|
|
if(!pos->IsEmpty()) {
|
|
int count = pos->GetCount();
|
|
pos->children.SetCount(count + item.GetCount());
|
|
OldTreeItem::List::Iterator d = pos->children.GetIter(count);
|
|
for(OldTreeItem::List::Iterator p = item.children.Begin(), e = item.children.End(); p != e;)
|
|
if(op & DEEP)
|
|
*d++ <<= *p++;
|
|
else
|
|
*d++ = *p++;
|
|
}
|
|
else {
|
|
if(op & DEEP)
|
|
pos->children <<= item.children;
|
|
else
|
|
pos->children = item.children;
|
|
}
|
|
pos->TouchLayout();
|
|
}
|
|
}
|
|
else
|
|
NEVER();
|
|
break;
|
|
case UPD:
|
|
if(pos = cursor.Get()) {
|
|
if(op & DEEP)
|
|
*pos <<= item;
|
|
else
|
|
*pos = item;
|
|
pos->TouchLayout();
|
|
}
|
|
else
|
|
NEVER();
|
|
break;
|
|
case UPD | KIDS:
|
|
if(pos = cursor.Get()) {
|
|
if(op & DEEP)
|
|
pos->children <<= item.children;
|
|
else
|
|
pos->children = item.children;
|
|
pos->TouchLayout();
|
|
}
|
|
else
|
|
NEVER();
|
|
break;
|
|
case DEL:
|
|
if(pos = cursor.GetParent()) {
|
|
int index = cursor.cursor.Top();
|
|
if(index >= 0 && index < pos->GetCount()) {
|
|
pos->children.Remove(index);
|
|
pos->TouchLayout();
|
|
cursor.Adjust();
|
|
}
|
|
else
|
|
NEVER();
|
|
}
|
|
else
|
|
NEVER();
|
|
break;
|
|
case DEL | KIDS:
|
|
if(pos = cursor.Get()) {
|
|
pos->Clear();
|
|
pos->TouchLayout();
|
|
}
|
|
else
|
|
NEVER();
|
|
break;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
OldTreeEdit& OldTreeEdit::Adjust(OldTreeCursor& pos)
|
|
{
|
|
switch(op & ~DEEP) {
|
|
case INS: pos.AdjustAfter(cursor, 1); break;
|
|
case INS | KIDS: break;
|
|
case UPD: break;
|
|
case UPD | KIDS: pos.Adjust(); break;
|
|
case DEL:
|
|
if(pos.IsSubtreeOf(cursor))
|
|
pos <<= cursor;
|
|
pos.AdjustAfter(cursor, -1);
|
|
break;
|
|
|
|
case DEL | KIDS:
|
|
if(pos.IsSubtreeOf(cursor))
|
|
pos <<= cursor;
|
|
pos.Adjust();
|
|
break;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
OldTreeEdit& OldTreeEdit::Adjust(const Vector<OldTreeCursor *>& list)
|
|
{
|
|
for(OldTreeCursor *const *p = list.Begin(), *const *e = list.End(); p < e; p++)
|
|
Adjust(**p);
|
|
return *this;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// OldTreeCtrl::
|
|
|
|
OldTreeCtrl::OldTreeCtrl()
|
|
: updating(false)
|
|
, font(StdFont())
|
|
, offset(3 + BUTTON_HALF, 3)
|
|
, old_scroll(Null)
|
|
, open_menu(true)
|
|
, hide_top(false)
|
|
, hittest(0)
|
|
, multiselect(false)
|
|
{
|
|
// WheelScroll(scroll);
|
|
drag_state = 0;
|
|
|
|
owner = this;
|
|
AddFrame(scroll);
|
|
scroll.AutoHide();
|
|
// scroll/*.AutoHide()*/.AddTo(*this);
|
|
scroll.WhenScroll = THISBACK(OnScroll);
|
|
|
|
WhenOpenClose = THISBACK(OnOpenClose);
|
|
WhenPush = THISBACK(OnPush);
|
|
WhenRight = THISBACK(OnRight);
|
|
WhenKey = THISBACK(OnKey);
|
|
WhenBar = THISBACK(StdBar);
|
|
WhenLeftDouble = THISBACK(OnOpenClose);
|
|
|
|
SetFrame(InsetFrame());
|
|
}
|
|
|
|
OldTreeCtrl::~OldTreeCtrl()
|
|
{
|
|
}
|
|
|
|
Value OldTreeCtrl::GetData() const
|
|
{
|
|
const OldTreeItem *item = GetCursorItem();
|
|
if(item)
|
|
return item->GetData();
|
|
return Value();
|
|
}
|
|
|
|
void OldTreeCtrl::SetData(const Value& value)
|
|
{
|
|
SetCursor(FindValue(value));
|
|
}
|
|
|
|
OldTreeItem::HITTEST OldTreeCtrl::Find(Point pt, const OldTreeItem *& item) const
|
|
{
|
|
return FindItem(pt - offset + old_scroll, (OldTreeItem*&)item);
|
|
}
|
|
|
|
OldTreeItem::HITTEST OldTreeCtrl::Find(Point pt, OldTreeItem *& item)
|
|
{
|
|
return FindItem(pt - offset + old_scroll, item);
|
|
}
|
|
|
|
OldTreeCursor OldTreeCtrl::Find(int y) const
|
|
{
|
|
OldTreeItem *item;
|
|
y += old_scroll.y - offset.cy;
|
|
HITTEST ht = FindItem(Point(0, y), item);
|
|
if(ht != HNIL && item)
|
|
return OldTreeCursor(*item);
|
|
OldTreeCursor c(*this);
|
|
if(y >= tree_size.cy)
|
|
c.EndAll();
|
|
return c;
|
|
}
|
|
|
|
OldTreeCtrl& OldTreeCtrl::HideTop()
|
|
{
|
|
hide_top = true;
|
|
Indent(4);
|
|
Open();
|
|
EnableItem();
|
|
return *this;
|
|
}
|
|
|
|
void OldTreeCtrl::Layout()
|
|
{
|
|
// if(!IsOpen())
|
|
// return;
|
|
/*
|
|
if(IsDesignMode() && IsEmpty()) {
|
|
Text("OldTreeCtrl", CtrlImg::new_doc()).Open();
|
|
Add().Text("Child1", CtrlImg::save());
|
|
OldTreeItem& item = Add().Text("Child2", CtrlImg::save_as()).Open();
|
|
item.Add().Text("Child3", CtrlImg::open());
|
|
}
|
|
*/
|
|
LayoutItem();
|
|
old_scroll = scroll;
|
|
rowht = tree_size.cy / max(GetOpenCount(), 1);
|
|
Size total = GetTreeSize() + 2 * offset;
|
|
scroll.Set(old_scroll, scroll.GetReducedViewSize(), total);
|
|
scroll.SetLine((scroll.GetReducedViewSize().cx >> 3) + 1, rowht);
|
|
}
|
|
|
|
void OldTreeCtrl::Paint(Draw& draw)
|
|
{
|
|
if(layout) {
|
|
Layout();
|
|
Refresh();
|
|
}
|
|
Size size = GetSize();
|
|
Rect rc = GetClientTreeRect();
|
|
Rect rc_butt = rc;
|
|
rc_butt.left += BUTTON_HALF + 1 + ICONGAP;
|
|
Color bg = (IsShowEnabled() ? SWhite : SLtGray);
|
|
DrawRectMinusRect(draw, GetSize(), rc_butt, DBG_PAINT(bg, LtGreen));
|
|
PaintItem(draw, rc.TopLeft());
|
|
}
|
|
|
|
void OldTreeCtrl::OnScroll()
|
|
{
|
|
if((Point)scroll != old_scroll) {
|
|
Size delta = old_scroll - (Point)scroll;
|
|
Size view = GetSize();
|
|
old_scroll = scroll;
|
|
if(IsNull(old_scroll.x) || 2 * tabs(delta.cx) >= view.cx || 2 * tabs(delta.cy) >= view.cy || IsFullRefresh())
|
|
Refresh();
|
|
else
|
|
ScrollView(delta);
|
|
}
|
|
}
|
|
|
|
void OldTreeCtrl::LeftDown(Point pt, dword keyflags)
|
|
{
|
|
SetFocus();
|
|
SetCapture();
|
|
OldTreeItem *item;
|
|
hittest = Find(pt, item);
|
|
|
|
if(multiselect && hittest == HNIL && !(keyflags & (K_CTRL | K_SHIFT)))
|
|
UnselectTree();
|
|
else if(item && item->IsEnabledItem()) {
|
|
OldTreeCursor new_cursor(*item);
|
|
|
|
switch(hittest) {
|
|
case HBUTTON:
|
|
item->Open(!item->IsOpenItem());
|
|
item->TouchLayout();
|
|
break;
|
|
|
|
case HNIL:
|
|
break;
|
|
|
|
default:
|
|
if(multiselect && (keyflags & K_CTRL))
|
|
PickCursor(new_cursor, XOR_SEL);
|
|
else if(multiselect && (keyflags & K_SHIFT) && anchor) // anchor selection
|
|
PickCursor(new_cursor, DRAG_SEL);
|
|
else if(!item->IsSelected())
|
|
PickCursor(new_cursor, SET_SEL);
|
|
else
|
|
PickCursor(new_cursor, KEEP_SEL);
|
|
break;
|
|
}
|
|
}
|
|
|
|
drag_start = pt;
|
|
drag_state = 2;
|
|
|
|
WhenPush();
|
|
}
|
|
|
|
void OldTreeCtrl::LeftUp(Point pt, dword keyflags)
|
|
{
|
|
ReleaseCapture();
|
|
if(drag_state == 1)
|
|
WhenDrag(pt + GetScreenView().TopLeft(), keyflags, 3);
|
|
else {
|
|
}
|
|
// OldTreeItem *item;
|
|
// hittest = Find(pt, item);
|
|
// SetCursor(item);
|
|
Action();
|
|
drag_state = 0;
|
|
}
|
|
|
|
void OldTreeCtrl::LeftDouble(Point pt, dword keyflags)
|
|
{
|
|
IgnoreMouseUp();
|
|
OldTreeItem *item;
|
|
int hit = Find(pt, item);
|
|
if(item == GetCursor().Get() && hit == hittest)
|
|
WhenLeftDouble();
|
|
}
|
|
|
|
void OldTreeCtrl::RightDown(Point pt, dword keyflags)
|
|
{
|
|
if(drag_state == 1) {
|
|
WhenDrag(pt + GetScreenView().TopLeft(), keyflags, 2);
|
|
drag_state = 0;
|
|
}
|
|
SetFocus();
|
|
OldTreeItem *item;
|
|
hittest = Find(pt, item);
|
|
SetCursor(item);
|
|
Action();
|
|
WhenRight();
|
|
}
|
|
|
|
void OldTreeCtrl::MouseMove(Point pt, dword keyflags)
|
|
{
|
|
Point scrn = pt + GetScreenView().TopLeft();
|
|
if(drag_state == 2 && abs2(pt - drag_start) >= 50) { // start d&d
|
|
WhenDrag(scrn, keyflags, 0);
|
|
drag_state = 1;
|
|
}
|
|
if(drag_state == 1)
|
|
WhenDrag(scrn, keyflags, 1);
|
|
}
|
|
|
|
void OldTreeCtrl::MouseWheel(Point p, int zdelta, dword keyflags)
|
|
{
|
|
scroll.WheelY(zdelta);
|
|
}
|
|
|
|
Image OldTreeCtrl::CursorImage(Point pt, dword keyflags)
|
|
{
|
|
Image image = Image::Arrow();
|
|
if(drag_state == 1)
|
|
WhenDragImage(image);
|
|
return image;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// default handlers
|
|
|
|
void OldTreeCtrl::OnOpenClose()
|
|
{
|
|
const OldTreeCursor& cursor = GetCursor();
|
|
if(cursor) {
|
|
cursor->Open(!cursor->IsOpenItem());
|
|
cursor.TouchLayout();
|
|
}
|
|
}
|
|
|
|
void OldTreeCtrl::OnPush()
|
|
{
|
|
}
|
|
|
|
void OldTreeCtrl::OnRight()
|
|
{
|
|
MenuBar menu;
|
|
WhenBar(menu);
|
|
menu.Execute();
|
|
}
|
|
|
|
void OldTreeCtrl::StdBar(Bar& bar)
|
|
{
|
|
const OldTreeCursor& cursor = GetCursor();
|
|
if(cursor && cursor->IsSubtree()) {
|
|
cursor->BarOpenClose(bar);
|
|
cursor->BarOpenSubtree(bar);
|
|
cursor->BarCloseSubtree(bar);
|
|
}
|
|
}
|
|
|
|
bool OldTreeCtrl::Key(dword key, int repcnt)
|
|
{
|
|
if(WhenKey(key))
|
|
return true;
|
|
if(key == K_INSERT)
|
|
if(OldTreeItem *item = GetCursorItem()) {
|
|
item->OnOpenClose();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool OldTreeCtrl::OnKey(dword key)
|
|
{
|
|
OldTreeCursor move = cursor.Copy();
|
|
Rect rc(0, 0, 0, 0);
|
|
const OldTreeItem *item = move.Get();
|
|
if(item)
|
|
rc = item->GetClientRect();
|
|
|
|
int ops = SET_SEL;
|
|
if(key & K_CTRL)
|
|
ops = XOR_SEL;
|
|
else if(key & K_SHIFT)
|
|
ops = DRAG_SEL;
|
|
|
|
switch(key & ~(K_SHIFT | K_CTRL)) {
|
|
default:
|
|
return Bar::Scan(WhenBar, key);
|
|
|
|
case K_UP:
|
|
if(move)
|
|
move.Up(OldTreeCursor::HIERARCHY);
|
|
else
|
|
move = OldTreeCursor(*this);
|
|
break;
|
|
|
|
case K_DOWN:
|
|
if(move)
|
|
move.Down(OldTreeCursor::HIERARCHY);
|
|
else
|
|
move = OldTreeCursor(*this);
|
|
break;
|
|
|
|
case K_PAGEUP:
|
|
move = Find(rc.bottom - GetSize().cy);
|
|
break;
|
|
|
|
case K_PAGEDOWN:
|
|
move = Find(rc.top + GetSize().cy);
|
|
break;
|
|
|
|
case K_CTRL_PAGEUP:
|
|
case K_HOME:
|
|
move = OldTreeCursor(*this);
|
|
break;
|
|
|
|
case K_CTRL_PAGEDOWN:
|
|
case K_END:
|
|
move = OldTreeCursor(*this).EndAll();
|
|
break;
|
|
}
|
|
|
|
if(move.IsEnd())
|
|
move.Up(OldTreeCursor::HIERARCHY);
|
|
if(move.IsBegin() && move && hide_top)
|
|
move.Down(OldTreeCursor::HIERARCHY);
|
|
if(move != cursor) {
|
|
PickCursor(move, ops);
|
|
Action();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
OldTreeCtrl& OldTreeCtrl::PickCursor(pick_ OldTreeCursor& nc, int selection_op)
|
|
{
|
|
OldTreeCursor new_cursor = nc;
|
|
new_cursor.Adjust();
|
|
cursor.Touch();
|
|
if(selection_op == DRAG_SEL && anchor) {
|
|
UnselectTree();
|
|
bool anchorup = anchor >= new_cursor;
|
|
const OldTreeCursor& b = (anchorup ? new_cursor : anchor);
|
|
const OldTreeCursor& l = (anchorup ? anchor : new_cursor);
|
|
for(OldTreeCursor p(b, 0); p <= l; p.Down(p.HIERARCHY))
|
|
if(p->IsEnabledItem())
|
|
p->Select();
|
|
}
|
|
else if(selection_op != KEEP_SEL) {
|
|
anchor <<= new_cursor;
|
|
if(selection_op == SET_SEL)
|
|
UnselectTree();
|
|
if(new_cursor)
|
|
new_cursor->Select(selection_op == SET_SEL ? true : !new_cursor->IsSelected());
|
|
}
|
|
cursor = new_cursor;
|
|
cursor.Touch().Open().ScrollInto();
|
|
WhenSetCursor();
|
|
return *this;
|
|
}
|
|
|
|
OldTreeCtrl& OldTreeCtrl::SetCursor(const OldTreeItem *item)
|
|
{
|
|
if(!item)
|
|
return PickCursor(OldTreeCursor());
|
|
ASSERT(item->owner == this);
|
|
return PickCursor(OldTreeCursor(*item));
|
|
}
|
|
|
|
void OldTreeCtrl::GotFocus()
|
|
{
|
|
Refresh();
|
|
}
|
|
|
|
void OldTreeCtrl::LostFocus()
|
|
{
|
|
Refresh();
|
|
}
|
|
|
|
Point OldTreeCtrl::GetCursorSc() const
|
|
{
|
|
Point pt = scroll;
|
|
OldTreeItem *i = GetCursorItem();
|
|
if(i)
|
|
pt -= i->GetTreeRect().TopLeft();
|
|
return pt;
|
|
}
|
|
|
|
void OldTreeCtrl::ScCursor(Point pt)
|
|
{
|
|
OldTreeItem *i = GetCursorItem();
|
|
if(i)
|
|
pt += i->GetTreeRect().TopLeft();
|
|
scroll = pt;
|
|
}
|
|
|
|
}
|