------------------------------------------------------------ revno: 3220 committer: poy <p...@123gen.com> branch nick: trunk timestamp: Sat 2013-03-16 14:25:11 +0100 message: dwt: add a table-tree control added: dwt/include/dwt/widgets/TableTree.h dwt/src/widgets/TableTree.cpp dwt/test/TableTreeTest.cpp modified: dwt/include/dwt/Rectangle.h dwt/include/dwt/forward.h dwt/include/dwt/widgets/Table.h dwt/src/Rectangle.cpp dwt/src/widgets/TabView.cpp dwt/src/widgets/Table.cpp dwt/test/SplitTest.cpp dwt/test/TableTest.cpp dwt/test/TreeTest.cpp
-- lp:dcplusplus https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk Your team Dcplusplus-team is subscribed to branch lp:dcplusplus. To unsubscribe from this branch go to https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk/+edit-subscription
=== modified file 'dwt/include/dwt/Rectangle.h' --- dwt/include/dwt/Rectangle.h 2013-01-18 21:28:38 +0000 +++ dwt/include/dwt/Rectangle.h 2013-03-16 13:25:11 +0000 @@ -85,6 +85,8 @@ long height() const { return size.y; } + bool contains(const Point& pt) const; + const Point& upperLeft() const { return pos; } /// Return the lower right point of the rectangle. === modified file 'dwt/include/dwt/forward.h' --- dwt/include/dwt/forward.h 2013-01-18 21:28:38 +0000 +++ dwt/include/dwt/forward.h 2013-03-16 13:25:11 +0000 @@ -170,6 +170,9 @@ class Table; typedef Table* TablePtr; +class TableTree; +typedef TableTree* TableTreePtr; + class TabView; typedef TabView* TabViewPtr; === modified file 'dwt/include/dwt/widgets/Table.h' --- dwt/include/dwt/widgets/Table.h 2013-01-21 18:43:48 +0000 +++ dwt/include/dwt/widgets/Table.h 2013-03-16 13:25:11 +0000 @@ -383,10 +383,10 @@ std::pair<int, int> hitTest(const ScreenCoordinate& pt); /// Returns the rect for the item per code (wraps ListView_GetItemRect) - Rectangle getRect(int item, int code); + Rectangle getRect(int row, int code); /// Returns the rect for the subitem item per code (wraps ListView_GetSubItemRect) - Rectangle getRect(int item, int subitem, int code); + Rectangle getRect(int row, int col, int code); /// Actually creates the Data Grid Control /** You should call WidgetFactory::createTable if you instantiate class @@ -587,22 +587,6 @@ return ListView_GetItemCount( handle() ); } -// Calculates the adjustment from the columns of an item. - -inline Rectangle Table::getRect( int item, int code ) -{ - RECT r; - ListView_GetItemRect( handle(), item, &r, code ); - return Rectangle(r); -} - -inline Rectangle Table::getRect( int item, int subitem, int code ) -{ - RECT r; - ListView_GetSubItemRect( handle(), item, subitem, code, &r ); - return Rectangle(r); -} - inline bool Table::isAscending() const { return ascending; } === added file 'dwt/include/dwt/widgets/TableTree.h' --- dwt/include/dwt/widgets/TableTree.h 1970-01-01 00:00:00 +0000 +++ dwt/include/dwt/widgets/TableTree.h 2013-03-16 13:25:11 +0000 @@ -0,0 +1,106 @@ +/* + DC++ Widget Toolkit + + Copyright (c) 2007-2013, Jacek Sieka + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the DWT nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef DWT_TABLETREE_H +#define DWT_TABLETREE_H + +#include <unordered_map> +#include <vector> + +#include "Table.h" +#include <dwt/Theme.h> + +namespace dwt { + +/** This table control provides a hierarchical organization of its items. Parency is represented by +glyphs similar to those drawn by tree controls. */ +class TableTree : + public Table +{ + typedef Table BaseType; + friend class WidgetCreator<TableTree>; + +public: + typedef TableTree ThisType; + typedef ThisType* ObjectType; + + struct Seed : public BaseType::Seed { + typedef ThisType WidgetType; + + Seed(const BaseType::Seed& seed); + }; + + void create(const Seed& seed); + + virtual bool handleMessage(const MSG& msg, LRESULT& retVal); + + void insertChild(LPARAM parent, LPARAM child); + void collapse(LPARAM parent); + void expand(LPARAM parent); + + template<typename SortFunction> void onSortItems(SortFunction f) { + BaseType::onSortItems([this, f](LPARAM lhs, LPARAM rhs) -> int { + auto res = handleSort(lhs, rhs); + return res ? res : f(lhs, rhs); + }); + } + +protected: + explicit TableTree(Widget* parent); + virtual ~TableTree() { } + +private: + struct Item { + std::vector<LPARAM> children; + bool expanded; + Rectangle glyphRect; + Item(); + void switchExp(TableTree& w); + }; + std::unordered_map<LPARAM, Item> items; + std::unordered_map<LPARAM, LPARAM> children; // child -> parent cache + + Theme theme; + long indent; + + LRESULT handleCustomDraw(NMLVCUSTOMDRAW& data); + bool handleKeyDown(int c); + bool handleLeftMouseDown(const MouseEvent& me); + void handleDelete(int pos); + void handleInsert(LVITEM& lv); + int handleSort(LPARAM& lhs, LPARAM& rhs); + + LRESULT sendMsg(UINT msg, WPARAM wParam, LPARAM lParam); +}; + +} + +#endif === modified file 'dwt/src/Rectangle.cpp' --- dwt/src/Rectangle.cpp 2013-01-18 21:28:38 +0000 +++ dwt/src/Rectangle.cpp 2013-03-16 13:25:11 +0000 @@ -49,6 +49,11 @@ return toRECT(); } +bool Rectangle::contains(const Point& pt) const { + auto rect = toRECT(); + return ::PtInRect(&rect, pt); +} + Rectangle Rectangle::subRect( double xFraction, double yFraction, double widthFraction, double heightFraction ) const { === modified file 'dwt/src/widgets/TabView.cpp' --- dwt/src/widgets/TabView.cpp 2013-01-18 21:28:38 +0000 +++ dwt/src/widgets/TabView.cpp 2013-03-16 13:25:11 +0000 @@ -901,8 +901,7 @@ bool TabView::inCloseRect(const ScreenCoordinate& pos) const { if(closeRect.width() > 0 && closeRect.height() > 0) { - ::RECT rc(closeRect); - return ::PtInRect(&rc, pos.getPoint()); + return closeRect.contains(pos.getPoint()); } return false; } === modified file 'dwt/src/widgets/Table.cpp' --- dwt/src/widgets/Table.cpp 2013-01-21 18:43:48 +0000 +++ dwt/src/widgets/Table.cpp 2013-03-16 13:25:11 +0000 @@ -642,4 +642,25 @@ }); } +Rectangle Table::getRect(int row, int code) { + ::RECT r; + ListView_GetItemRect(handle(), row, &r, code); + return Rectangle(r); +} + +Rectangle Table::getRect(int row, int col, int code) { + ::RECT r; + ListView_GetSubItemRect(handle(), row, col, code, &r); + + // when asked for the column 0, Windows returns a rect for the whole item. + if(col == 0) { + ::RECT colRect; + Header_GetItemRect(ListView_GetHeader(handle()), col, &colRect); + r.left = colRect.left; + r.right = colRect.right; + } + + return Rectangle(r); +} + } === added file 'dwt/src/widgets/TableTree.cpp' --- dwt/src/widgets/TableTree.cpp 1970-01-01 00:00:00 +0000 +++ dwt/src/widgets/TableTree.cpp 2013-03-16 13:25:11 +0000 @@ -0,0 +1,343 @@ +/* + DC++ Widget Toolkit + + Copyright (c) 2007-2013, Jacek Sieka + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the DWT nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <dwt/widgets/TableTree.h> + +#include <dwt/CanvasClasses.h> +#include <dwt/dwt_vsstyle.h> +#include <dwt/resources/ImageList.h> +#include <dwt/resources/Pen.h> +#include <dwt/util/check.h> +#include <dwt/util/HoldRedraw.h> + +namespace dwt { + +TableTree::Seed::Seed(const BaseType::Seed& seed) : + BaseType::Seed(seed) +{ +} + +TableTree::TableTree(Widget* parent) : + BaseType(parent), + indent(0) +{ +} + +void TableTree::create(const Seed& seed) { + dwtassert((seed.style & LVS_REPORT) == LVS_REPORT, "TableTree requires LVS_REPORT"); + + BaseType::create(seed); + + theme.load(VSCLASS_TREEVIEW, this); + + onCustomDraw([this](NMLVCUSTOMDRAW& data) { return handleCustomDraw(data); }); + onKeyDown([this](int c) { return handleKeyDown(c); }); + onLeftMouseDown([this](const MouseEvent& me) { return handleLeftMouseDown(me); }); +} + +bool TableTree::handleMessage(const MSG& msg, LRESULT& retVal) { + switch(msg.message) { + case LVM_DELETEITEM: + { + handleDelete(msg.wParam); + break; + } + case LVM_DELETEALLITEMS: + { + items.clear(); + children.clear(); + break; + } + case LVM_INSERTITEM: + { + handleInsert(*reinterpret_cast<LVITEM*>(msg.lParam)); + break; + } + case LVM_SETIMAGELIST: + { + if(msg.wParam == LVSIL_SMALL && msg.lParam) { + indent = ImageList(reinterpret_cast<HIMAGELIST>(msg.lParam), false).getImageSize().x; + } + break; + } + case LVM_SETITEM: + { + dwtDebugFail("TableTree LVM_SETITEM not implemented"); + break; + } + } + return BaseType::handleMessage(msg, retVal); +} + +void TableTree::insertChild(LPARAM parent, LPARAM child) { + items[parent].children.push_back(child); + children[child] = parent; +} + +void TableTree::collapse(LPARAM parent) { + util::HoldRedraw hold { this }; + auto pos = findData(parent) + 1; + for(size_t i = 0, n = items[parent].children.size(); i < n; ++i) { + sendMsg(LVM_DELETEITEM, pos, 0); + } + items[parent].switchExp(*this); +} + +void TableTree::expand(LPARAM parent) { + util::HoldRedraw hold { this }; + LVITEM item = { LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_INDENT, findData(parent) }; + item.pszText = LPSTR_TEXTCALLBACK; + item.iImage = I_IMAGECALLBACK; + item.iIndent = 2; + for(auto child: items[parent].children) { + ++item.iItem; + item.lParam = child; + sendMsg(LVM_INSERTITEM, 0, reinterpret_cast<LPARAM>(&item)); + } + items[parent].switchExp(*this); +} + +TableTree::Item::Item() : expanded(false) +{ +} + +void TableTree::Item::switchExp(TableTree& w) { + expanded = !expanded; + + ::RECT rect = glyphRect; + ::InvalidateRect(w.handle(), &rect, FALSE); +} + +LRESULT TableTree::handleCustomDraw(NMLVCUSTOMDRAW& data) { + if(data.nmcd.dwDrawStage == CDDS_PREPAINT) { + return CDRF_NOTIFYITEMDRAW; + } + + if(data.nmcd.dwDrawStage == CDDS_ITEMPREPAINT && data.dwItemType == LVCDI_ITEM) { + return CDRF_NOTIFYSUBITEMDRAW | CDRF_NOTIFYPOSTPAINT; + } + + if(data.nmcd.dwDrawStage == (CDDS_ITEMPREPAINT | CDDS_SUBITEM) && data.dwItemType == LVCDI_ITEM && data.iSubItem == 0) { + return CDRF_NOTIFYPOSTPAINT; + } + + if(data.nmcd.dwDrawStage == (CDDS_ITEMPOSTPAINT | CDDS_SUBITEM) && data.dwItemType == LVCDI_ITEM && data.iSubItem == 0) { + FreeCanvas canvas { data.nmcd.hdc }; + + auto rect = getRect(data.nmcd.dwItemSpec, 0, LVIR_BOUNDS); + + { + // draw tree lines. + auto first = data.nmcd.dwItemSpec == 0, last = data.nmcd.dwItemSpec + 1 == size(); + + LOGBRUSH lb { BS_SOLID, Color::predefined(COLOR_GRAYTEXT) }; + Pen pen { ::ExtCreatePen(PS_COSMETIC | PS_ALTERNATE, 1, &lb, 0, nullptr) }; + auto selectPen(canvas.select(pen)); + + Point mid { rect.left() + indent / 2, rect.top() + indent / 2 }; + + if(children.find(data.nmcd.lItemlParam) != children.end()) { + // this is a child item; draw a second vertical line to link surrounding parents. + canvas.line(mid.x, rect.top(), mid.x, last ? mid.y : rect.bottom()); // vertical + rect.pos.x += indent; + mid.x += indent; + if(!last) { last = children.find(getData(data.nmcd.dwItemSpec + 1)) == children.end(); } + } + + canvas.line(mid, Point(rect.left() + indent, mid.y)); // horizontal + canvas.line(mid.x, first ? mid.y : rect.top(), mid.x, last ? mid.y : rect.bottom()); // vertical + } + + auto parent = items.find(data.nmcd.lItemlParam); + if(parent != items.end()) { + // this is a parent item; draw the +/- glyph. + + if(theme) { + int part = TVP_GLYPH, state = parent->second.expanded ? GLPS_OPENED : GLPS_CLOSED; + theme.getPartSize(canvas, part, state, rect.size); + rect.pos.x += std::max(indent - rect.size.x, 0L) / 2; + rect.pos.y += std::max(indent - rect.size.y, 0L) / 2; + theme.drawBackground(canvas, part, state, rect); + parent->second.glyphRect = rect; + + } else { + const long glyphSize = 9, padding = 2; + rect.pos.x += std::max(indent - glyphSize, 0L) / 2; + rect.pos.y += std::max(indent - glyphSize, 0L) / 2; + rect.size.x = rect.size.y = glyphSize; + + ::RECT rc = rect; + ::DrawEdge(canvas.handle(), &rc, EDGE_BUMP, BF_RECT | BF_MIDDLE | BF_FLAT); + + Point mid { rect.left() + glyphSize / 2, rect.top() + glyphSize / 2 }; + + Pen pen { Color::predefined(COLOR_GRAYTEXT), Pen::Solid }; + auto selectPen(canvas.select(pen)); + + canvas.line(rect.left() + padding, mid.y, rect.right() - padding, mid.y); // horizontal + if(parent->second.expanded) { + canvas.line(mid.x, rect.top() + padding, mid.x, rect.bottom() - padding); // vertical + } + + parent->second.glyphRect = rect; + } + } + } + + return CDRF_DODEFAULT; +} + +bool TableTree::handleKeyDown(int c) { + bool handled = false; + switch(c) { + case VK_LEFT: + { + for(auto sel: getSelection()) { + auto item = items.find(getData(sel)); + if(item != items.end()) { + // a parent is selected; collapse it. + handled = true; + if(item->second.expanded) { + collapse(item->first); + continue; + } + } + auto child = children.find(getData(sel)); + if(child != children.end()) { + // a child is selected; select its parent. + handled = true; + ListView_SetItemState(handle(), sel, 0, LVIS_SELECTED | LVIS_FOCUSED); + setSelected(findData(child->second)); + } + } + break; + } + case VK_RIGHT: + { + for(auto sel: getSelection()) { + auto item = items.find(getData(sel)); + if(item != items.end()) { + // a parent is selected; either expand it or select its first child. + handled = true; + if(item->second.expanded) { + if(!item->second.children.empty()) { + ListView_SetItemState(handle(), sel, 0, LVIS_SELECTED | LVIS_FOCUSED); + setSelected(sel + 1); + } + } else { + expand(item->first); + } + } + } + break; + } + } + return handled; +} + +bool TableTree::handleLeftMouseDown(const MouseEvent& me) { + auto hit = hitTest(me.pos); + if(hit.second == 0) { + auto it = items.find(getData(hit.first)); + if(it != items.end() && it->second.glyphRect.contains(ClientCoordinate(me.pos, this).getPoint())) { + it->second.expanded ? collapse(it->first) : expand(it->first); + } + } + return false; +} + +void TableTree::handleDelete(int pos) { + auto param = getData(pos); + + auto parent = items.find(param); + if(parent != items.end()) { + for(auto child: parent->second.children) { + children.erase(child); + } + items.erase(parent); + } + + auto child = children.find(param); + if(child != children.end()) { + auto& cont = items[child->second].children; + cont.erase(std::remove(cont.begin(), cont.end(), param), cont.end()); + children.erase(child); + } +} + +void TableTree::handleInsert(LVITEM& lv) { + if((lv.mask & LVIF_TEXT) == LVIF_TEXT && lv.pszText != LPSTR_TEXTCALLBACK) { + dwtDebugFail("TableTree non-callback texts not implemented"); + } + if((lv.mask & LVIF_IMAGE) == LVIF_IMAGE && lv.iImage != I_IMAGECALLBACK) { + dwtDebugFail("TableTree non-callback images not implemented"); + } + if((lv.mask & LVIF_PARAM) != LVIF_PARAM || !lv.lParam) { + dwtDebugFail("TableTree null LPARAM not implemented"); + } + + // add indentation to draw tree lines. + if((lv.mask & LVIF_INDENT) != LVIF_INDENT) { + lv.mask |= LVIF_INDENT; + } + ++lv.iIndent; +} + +int TableTree::handleSort(LPARAM& lhs, LPARAM& rhs) { + /* return 1 or -1 when the 2 items have a direct parency relationship; otherwise, return 0 and + let the host proceed with comparing. */ + + auto c1 = children.find(lhs), c2 = children.find(rhs); + + if(c1 != children.end() && c2 != children.end() && c1->second == c2->second) { + return 0; // rhs & lhs have the same parent + } + + if(c1 != children.end()) { + if(c1->second == rhs) { return isAscending() ? 1 : -1; } // rhs is lhs' parent + lhs = c1->second; // lhs now points to its parent + } + + if(c2 != children.end()) { + if(c2->second == lhs) { return isAscending() ? -1 : 1; } // lhs is rhs' parent + rhs = c2->second; // rhs now points to its parent + } + + return 0; +} + +LRESULT TableTree::sendMsg(UINT msg, WPARAM wParam, LPARAM lParam) { + // send with a direct dispatcher call to avoid loops (since we catch messages in handleMessage). + MSG directMsg { handle(), msg, wParam, lParam }; + return getDispatcher().chain(directMsg); +} + +} === modified file 'dwt/test/SplitTest.cpp' --- dwt/test/SplitTest.cpp 2012-12-08 17:44:30 +0000 +++ dwt/test/SplitTest.cpp 2013-03-16 13:25:11 +0000 @@ -14,7 +14,8 @@ split->addChild(dwt::Label::Seed(_T("Second row"))); split->addChild(dwt::Label::Seed(_T("Third row"))); - split->resize(dwt::Rectangle(window->getClientSize())); + split->resize(window->getClientSize()); + window->onSized([=](const dwt::SizedEvent&) { split->resize(window->getClientSize()); }); app.run(); === modified file 'dwt/test/TableTest.cpp' --- dwt/test/TableTest.cpp 2013-01-18 21:28:38 +0000 +++ dwt/test/TableTest.cpp 2013-03-16 13:25:11 +0000 @@ -30,7 +30,8 @@ table->insert(rows); - table->resize(dwt::Rectangle(window->getClientSize())); + table->resize(window->getClientSize()); + window->onSized([=](const dwt::SizedEvent&) { table->resize(window->getClientSize()); }); app.run(); === added file 'dwt/test/TableTreeTest.cpp' --- dwt/test/TableTreeTest.cpp 1970-01-01 00:00:00 +0000 +++ dwt/test/TableTreeTest.cpp 2013-03-16 13:25:11 +0000 @@ -0,0 +1,102 @@ +#include <dwt/widgets/Window.h> +#include <dwt/widgets/TableTree.h> +#include <dwt/resources/ImageList.h> + +#include <boost/format.hpp> + +using dwt::tstring; + +const size_t COLUMNS = 3; +const size_t ROWS = 100; + +const size_t PARENT = 0; +const size_t CHILDREN = 10; + +const auto IMAGE_SIZE = 32; + +struct Item { + tstring texts[COLUMNS]; +}; + +int dwtMain(dwt::Application& app) +{ + auto window = new dwt::Window(); + window->create(); + window->onClosing([] { return ::PostQuitMessage(0), true; }); + + auto seed = dwt::TableTree::Seed(dwt::Table::Seed()); + seed.style |= WS_HSCROLL | WS_VSCROLL | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS; + seed.lvStyle |= LVS_EX_HEADERDRAGDROP | LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP; + auto table = window->addChild(seed); + + table->onSortItems([table](LPARAM lhs, LPARAM rhs) -> int { + auto col = table->getSortColumn(); + return wcscoll(reinterpret_cast<Item*>(lhs)->texts[col].c_str(), reinterpret_cast<Item*>(rhs)->texts[col].c_str()); + }); + table->onColumnClick([table](int column) { + if(column != table->getSortColumn()) { + table->setSort(column, dwt::Table::SORT_CALLBACK, true); + } else if(table->isAscending()) { + table->setSort(table->getSortColumn(), dwt::Table::SORT_CALLBACK, false); + } else { + table->setSort(-1, dwt::Table::SORT_CALLBACK, true); + } + }); + table->setSort(0, dwt::Table::SORT_CALLBACK); + + dwt::ImageListPtr images(new dwt::ImageList(dwt::Point(IMAGE_SIZE, IMAGE_SIZE))); + images->add(dwt::Icon(L"../../../../res/File.ico", dwt::Point(IMAGE_SIZE, IMAGE_SIZE))); + table->setSmallImageList(images); + + for(size_t i = 0; i < COLUMNS; ++i) { + table->addColumn(dwt::Column((boost::wformat(L"Column %d") % i).str())); + table->setColumnWidth(i, 200); + } + + std::vector<Item> items(ROWS); + + for(size_t i = 0; i < items.size(); ++i) { + for(size_t j = 0; j < COLUMNS; ++j) { + items[i].texts[j] = (boost::wformat(L"Item %d in col %d") % i % j).str(); + } + } + + table->onRaw([](WPARAM, LPARAM lParam) -> LRESULT { + auto& data = *reinterpret_cast<NMLVDISPINFO*>(lParam); + if(data.item.mask & LVIF_TEXT) { + const auto& text = reinterpret_cast<Item*>(data.item.lParam)->texts[data.item.iSubItem]; + _tcsncpy(data.item.pszText, text.data(), text.size()); + data.item.pszText[text.size()] = 0; + } + if(data.item.mask & LVIF_IMAGE) { + data.item.iImage = 0; + } + return 0; + }, dwt::Message(WM_NOTIFY, LVN_GETDISPINFO)); + + for(auto& item: items) { + table->insert(LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE, table->size(), + LPSTR_TEXTCALLBACK, 0, 0, I_IMAGECALLBACK, reinterpret_cast<LPARAM>(&item)); + } + + std::vector<Item> children(CHILDREN); + + for(size_t i = 0; i < children.size(); ++i) { + for(size_t j = 0; j < COLUMNS; ++j) { + children[i].texts[j] = (boost::wformat(L"Child %d in col %d") % i % j).str(); + } + } + + auto parent = reinterpret_cast<LPARAM>(&items[PARENT]); + for(auto& child: children) { + table->insertChild(parent, reinterpret_cast<LPARAM>(&child)); + } + table->expand(parent); + + table->resize(window->getClientSize()); + window->onSized([=](const dwt::SizedEvent&) { table->resize(window->getClientSize()); }); + + app.run(); + + return 0; +} === modified file 'dwt/test/TreeTest.cpp' --- dwt/test/TreeTest.cpp 2013-03-10 12:52:24 +0000 +++ dwt/test/TreeTest.cpp 2013-03-16 13:25:11 +0000 @@ -35,7 +35,8 @@ } } - tree->resize(dwt::Rectangle(window->getClientSize())); + tree->resize(window->getClientSize()); + window->onSized([=](const dwt::SizedEvent&) { tree->resize(window->getClientSize()); }); app.run();
_______________________________________________ Mailing list: https://launchpad.net/~linuxdcpp-team Post to : linuxdcpp-team@lists.launchpad.net Unsubscribe : https://launchpad.net/~linuxdcpp-team More help : https://help.launchpad.net/ListHelp