#include #include #include "UIListView.h" using namespace tb; namespace Atomic { class ListViewItemSource; class ListViewItemWidget; class ListViewItem : public TBGenericStringItem { bool expanded_; public: ListViewItem(const char *str, const TBID &id, const char* icon, ListViewItemSource* source) : TBGenericStringItem(str, id), source_(source), parent_(0), depth_(0), widget_(0), expanded_(false), icon_(icon) { } ListViewItem* AddChild(const char* text, const char* icon, const TBID &id); bool GetExpanded() { return expanded_; } void GetChildren(PODVector& children, bool recursive = false) { children += children_; if (recursive) { for (unsigned i = 0; i < children_.Size(); i++) { children_[i]->GetChildren(children, recursive); } } } void SetExpanded(bool expanded) { expanded_ = expanded; if (!expanded_) { for (unsigned i = 0; i < children_.Size(); i ++) children_[i]->SetExpanded(expanded); } else { ListViewItem* p = parent_; while (p) { p->expanded_ = true; p = p->parent_; } } } void UpdateText(const String& text); ListViewItemSource* source_; ListViewItem* parent_; int depth_; PODVector children_; ListViewItemWidget* widget_; String icon_; }; class ListViewItemWidget : public TBLayout { public: ListViewItemWidget(ListViewItem *item, ListViewItemSource *source, TBSelectItemViewer *sourceviewer, int index); virtual bool OnEvent(const TBWidgetEvent &ev); void UpdateText(const String& text) { if (textField_) textField_->SetText(text.CString()); } private: TBTextField* textField_; ListViewItemSource *source_; TBSelectItemViewer *sourceviewer_; int index_; ListViewItem* item_; }; class ListViewItemSource : public TBSelectItemSourceList { public: TBSelectList* list_; ListViewItemSource(TBSelectList* list) : list_(list) {} virtual ~ListViewItemSource() {} virtual bool Filter(int index, const char *filter); virtual TBWidget *CreateItemWidget(int index, TBSelectItemViewer *viewer); }; // implementation void ListViewItem::UpdateText(const String& text) { str = text.CString(); if (widget_) widget_->UpdateText(text); } ListViewItem* ListViewItem::AddChild(const char *text, const char* icon, const TBID &id) { ListViewItem* child = new ListViewItem(text, id, icon, source_); child->parent_ = this; child->depth_ = depth_ + 1; // filter, alphabetically into source ListViewItem* insert = this; int parentIndex = -1; for (int i = 0; i < source_->GetNumItems(); i++) { if (source_->GetItem(i) == this) { parentIndex = i; break; } } for (int i = parentIndex + 1; i < source_->GetNumItems(); i++) { ListViewItem* item = source_->GetItem(i); if (item->depth_ <= depth_) break; if (item->depth_ != depth_ + 1) { insert = item; continue; } if (strcmp(item->str.CStr(), text) >= 0) break; insert = item; } for (int i = 0; i < source_->GetNumItems(); i++) { if (source_->GetItem(i) == insert) { source_->AddItem(child, i + 1); break; } } children_.Push(child); return child; } ListViewItemWidget::ListViewItemWidget(ListViewItem *item, ListViewItemSource *source, TBSelectItemViewer *sourceviewer, int index) : source_(source) , sourceviewer_(sourceviewer) , index_(index) , item_(item) , textField_(0) { SetLayoutDistribution(LAYOUT_DISTRIBUTION_GRAVITY); SetLayoutDistributionPosition(LAYOUT_DISTRIBUTION_POSITION_LEFT_TOP); SetPaintOverflowFadeout(false); item_->widget_ = this; for (int i = 0; i < item->depth_; i++) { LayoutParams lp; lp.SetWidth(6); lp.SetHeight(4); TBWidget* spacer = new TBWidget(); spacer->SetLayoutParams(lp); GetContentRoot()->AddChild(spacer); } if (item->icon_.Length()) { TBSkinImage* skinImage = new TBSkinImage(TBIDC(item->icon_.CString())); skinImage->SetIgnoreInput(true); GetContentRoot()->AddChild(skinImage); } TBFontDescription fd; fd.SetID(TBIDC("Vera")); fd.SetSize(11); TBTextField* tfield = textField_ = new TBTextField(); tfield->SetIgnoreInput(true); tfield->SetSkinBg(TBIDC("Folder")); tfield->SetText(item->str); tfield->SetFontDescription(fd); SetSkinBg(TBIDC("TBSelectItem")); GetContentRoot()->AddChild(tfield); SetID(item->id); } bool ListViewItemWidget::OnEvent(const TBWidgetEvent &ev) { if (ev.type == EVENT_TYPE_WHEEL) { return false; } // get clicks this way, not sure we want to if (ev.type == EVENT_TYPE_CLICK && ev.target->GetID() == item_->id) { item_->SetExpanded(!item_->GetExpanded()); source_->list_->InvalidateList(); // want to bubble return false; } return TBLayout::OnEvent(ev); } bool ListViewItemSource::Filter(int index, const char *filter) { ListViewItem* item = GetItem(index); if (!item->parent_) return true; if (item->parent_->GetExpanded()) return true; return false; } TBWidget *ListViewItemSource::CreateItemWidget(int index, TBSelectItemViewer *viewer) { ListViewItem* item = GetItem(index); if (TBLayout *layout = new ListViewItemWidget(item, this, viewer, index)) return layout; return nullptr; } /* static int select_list_sort_cb(TBSelectItemSource *_source, const int *a, const int *b) { ListViewItemSource* source = (ListViewItemSource*) _source; ListViewItem* itemA = source->GetItem(*a); ListViewItem* itemB = source->GetItem(*b); int value; if (itemA->depth_ == itemB->depth_) { value = strcmp(source->GetItemString(*a), source->GetItemString(*b)); } else { value = itemA->depth_ > itemB->depth_ ? 1 : -1; } return source->GetSort() == TB_SORT_DESCENDING ? -value : value; } */ UIListView::UIListView(Context* context, bool createWidget) : UIWidget(context, createWidget), source_(0), itemLookupId_(0) { rootList_ = new UISelectList(context); // dummy filter so filter is called rootList_->SetFilter(" "); widget_->SetGravity(WIDGET_GRAVITY_ALL); rootList_->SetGravity(UI_GRAVITY_ALL); source_ = new ListViewItemSource(rootList_->GetTBSelectList()); rootList_->GetTBSelectList()->SetSource(source_); AddChild(rootList_); } UIListView::~UIListView() { } unsigned UIListView::AddRootItem(const String& text, const String& icon, const String& id) { ListViewItem* item = new ListViewItem(text.CString(), TBID(id.CString()), icon.CString(), source_); source_->AddItem(item); itemLookup_[itemLookupId_++] = item; return itemLookupId_ - 1; } void UIListView::SetItemText(const String& id, const String& text) { TBID tbid(id.CString()); for (int i = 0; i < source_->GetNumItems(); i++) { if (source_->GetItemID(i) == tbid) { ListViewItem* item = source_->GetItem(i); item->UpdateText(text); return; } } } void UIListView::DeleteItemByID(const String& id) { TBID tbid(id.CString()); for (int i = 0; i < source_->GetNumItems(); i++) { if (source_->GetItemID(i) == tbid) { ListViewItem* item = source_->GetItem(i); if (item->parent_) item->parent_->children_.Remove(item); PODVector children; item->GetChildren(children, true); for (unsigned j = 0; j < children.Size(); j++) { for (int k = 0; k < source_->GetNumItems(); k++) { if (children[j] == source_->GetItem(k)) { source_->DeleteItem(k); break; } } } source_->DeleteItem(i); return; } } } unsigned UIListView::AddChildItem(unsigned parentItemID, const String& text, const String& icon, const String& id) { if (!itemLookup_.Contains(parentItemID)) return -1; ListViewItem* item = itemLookup_[parentItemID]; ListViewItem* child = item->AddChild(text.CString(), icon.CString(), TBID(id.CString())); itemLookup_[itemLookupId_++] = child; return itemLookupId_ - 1; } void UIListView::SetExpanded(unsigned itemID, bool value) { if (!itemLookup_.Contains(itemID)) return; itemLookup_[itemID]->SetExpanded(value); } void UIListView::DeleteAllItems() { itemLookup_.Clear(); source_->DeleteAllItems(); } void UIListView::SelectItemByID(const String& id) { TBID tid = TBIDC(id.CString()); for (int i = 0; i < source_->GetNumItems(); i++) { ListViewItem* item = source_->GetItem(i); if (tid == item->id) { item->SetExpanded(true); rootList_->SetValue(i); rootList_->InvalidateList(); return; } } } }