linuxdcpp-team team mailing list archive
-
linuxdcpp-team team
-
Mailing list archive
-
Message #06690
[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 3220: dwt: add a table-tree control
------------------------------------------------------------
revno: 3220
committer: poy <poy@xxxxxxxxxx>
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();