Last active
December 20, 2015 07:59
-
-
Save FrankHB/6097283 to your computer and use it in GitHub Desktop.
YFramework base test.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define YB_T_NO_MATH 1 | |
//#define YB_T_NO_IOSTREAM 1 | |
//#define YB_T_NO_TIMING 1 | |
#define YTEST_B 4 | |
#include "../../Temp/test.h" | |
#include <ysbuild.h> | |
#include <Helper/HostWindow.h> | |
#include <windows.h> | |
#include "../HelperEx/Shells.h" | |
#include <NPL/SContext.h> | |
#include <YSLib/Core/ValueNode.h> | |
#include <sstream> | |
#define TEST_GUI 1 | |
#define TEST_IMAGE 0 | |
#include <iostream> | |
#include <stdexcept> | |
#include <YCLib/COM.h> | |
#include <shlobj.h> | |
#include <shlwapi.h> | |
//#include <Windows.Foundation.h> | |
#include <vector> | |
#include <string> | |
#include <algorithm> | |
#include <ystdex/functional.hpp> | |
#include <ystdex/iterator.hpp> | |
#if TEST_IMAGE | |
# include <YSLib/Adaptor/Image.h> | |
#endif | |
using namespace std; | |
using namespace placeholders; | |
using namespace ystdex; | |
using namespace ytest::timing; | |
using namespace NPL; | |
using namespace YSLib; | |
using namespace Drawing; | |
#if 0 | |
using YSLib::Timers::HighResolutionClock; | |
#endif | |
typedef std::chrono::steady_clock HighResolutionClock; | |
using UI::Widget; | |
using UI::Button; | |
using Host::Window; | |
using Host::NativeWindowHandle; | |
using Host::HostRenderer; | |
#if TEST_GUI == 1 | |
class TestWnd : public UI::Window | |
{ | |
public: | |
Button b1, b2; | |
Host::Window* p_wnd; | |
Widget w1; | |
#if TEST_IMAGE | |
HBitmap pixmap; | |
#endif | |
TestWnd(const Rect& r) | |
: UI::Window(r), | |
b1({5, 5, 80, 32}), b2({90, 5, 80, 32}), p_wnd(), | |
w1({40, 40, 640, 480}) | |
#if TEST_IMAGE | |
, pixmap(u8R"(T:\a.png)") | |
#endif | |
{ | |
using namespace UI; | |
#if TEST_IMAGE | |
auto buf(ImageCodec::Convert(pixmap)); | |
auto p_img(ystdex::make_shared<Image>(buf.GetBufferPtr(), | |
buf.GetWidth(), buf.GetHeight())); | |
printf("bmp size:%s\n", to_string(buf.GetSize()).c_str()); | |
SetSizeOf(w1, buf.GetSize()); | |
printf("wgt size:%s\n", to_string(GetSizeOf(w1)).c_str()); | |
#endif | |
*this += b1, | |
*this += b2, | |
*this += w1, | |
yunseq( | |
Background = SolidBrush(ColorSpace::Red), | |
b1.Text = "改变大小", | |
b2.Text = "还原大小", | |
FetchEvent<Click>(b1) += std::bind(&TestWnd::AdjustClient, | |
this, Size(640, 480), std::placeholders::_1), | |
FetchEvent<Click>(b2) += std::bind(&TestWnd::AdjustClient, | |
this, Size(480, 320), std::placeholders::_1), | |
#if TEST_IMAGE | |
FetchEvent<Paint>(w1) += ImageBrush(std::move(p_img)), | |
#endif | |
w1.Background = SolidBrush(ColorSpace::Green) | |
); | |
} | |
private: | |
void | |
AdjustClient(const Size& s, UI::CursorEventArgs&&) | |
{ | |
if(p_wnd) | |
p_wnd->ResizeClient(s); | |
} | |
}; | |
#endif | |
#if TEST_GUI == 2 | |
namespace platform_ex | |
{ | |
inline std::string | |
ToANSI(const std::wstring& str, int cp = 936) | |
{ | |
return WCSToMBCS(str.c_str(), str.length(), cp); | |
} | |
string | |
SToMBCS(String str, int cp) | |
{ | |
return platform_ex::WCSToMBCS(reinterpret_cast<const wchar_t*>(str.c_str()), | |
str.length(), cp); | |
} | |
string | |
UTF8ToGBK(string str) | |
{ | |
return SToMBCS(str, 936); | |
} | |
using ystdex::indirect_input_iterator; | |
typedef ::IShellFolder IShellFolder; | |
typedef ::IEnumIDList IEnumIDList; | |
typedef COMPtr<IShellFolder> ShellFolderPtr; | |
typedef COMPtr<IEnumIDList> EnumIDListPtr; | |
// 关于内存管理和 OLE32 库的链接: | |
// http://blogs.msdn.com/b/oldnewthing/archive/2004/07/05/173226.aspx | |
class YF_API ShellPathFailure : public YSLib::LoggedEvent | |
{ | |
public: | |
ShellPathFailure(const std::string& msg) ynothrow | |
: LoggedEvent(msg) | |
{} | |
}; | |
class ShellPath | |
{ | |
private: | |
::LPITEMIDLIST p_idl; | |
public: | |
ShellPath(::LPITEMIDLIST p = nullptr) ynothrow | |
: p_idl(p) | |
{} | |
ShellPath(const ShellPath& pth) | |
: p_idl(::ILClone(pth.p_idl)) | |
{ | |
if(pth.p_idl && !p_idl) | |
throw std::bad_alloc(); | |
} | |
ShellPath(ShellPath&& pth) ynothrow | |
: p_idl(pth.p_idl) | |
{ | |
pth.p_idl = nullptr; | |
} | |
~ShellPath() ynothrow | |
{ | |
::CoTaskMemFree(p_idl); | |
} | |
ShellPath& | |
operator=(ShellPath&& pth) ynothrow | |
{ | |
std::swap(p_idl, pth.p_idl); | |
return *this; | |
} | |
ShellPath& | |
operator+=(const ::SHITEMID& id) ynothrow | |
{ | |
if(!::ILAppendID(p_idl, &id, TRUE)) | |
throw ShellPathFailure("Appending ID failed."); | |
return *this; | |
} | |
::ITEMIDLIST& | |
operator*() const ynothrow | |
{ | |
yconstraint(p_idl); | |
return *p_idl; | |
} | |
explicit DefCvt(const ynothrow, bool, bool(p_idl)) | |
DefGetter(const ynothrow, ::LPITEMIDLIST, , p_idl) | |
DefGetter(const, ::ITEMIDLIST&, Object, EnsureNonNull(p_idl), *p_idl) | |
DefGetter(ynothrow, ::LPITEMIDLIST&, Ref, p_idl) | |
}; | |
ShellPath | |
LocateFolder(int csidl, ::HANDLE token = nullptr) | |
ythrow(COMException) | |
{ | |
::LPITEMIDLIST p{}; | |
CheckHResult(::SHGetFolderLocation(nullptr, csidl, token, 0, &p)); | |
return p; | |
} | |
template<typename... _tParams> | |
ShellPath | |
GetNext(IEnumIDList& lst, _tParams&&...) ythrow(COMException) | |
{ | |
::LPITEMIDLIST p{}; | |
CheckHResult(lst.Next(1, &p, nullptr)); | |
return p; | |
} | |
ShellFolderPtr | |
GetDesktopFolder() ythrow(COMException) | |
{ | |
IShellFolder* p{}; | |
CheckHResult(::SHGetDesktopFolder(&p)); | |
return p; | |
} | |
template<typename... _tParams> | |
ShellFolderPtr | |
BindToObject(IShellFolder& folder, _tParams&&... args) ythrow(COMException) | |
{ | |
IShellFolder* p{}; | |
CheckHResult(folder.BindToObject(yforward(args)..., | |
reinterpret_cast<void**>(&p))); | |
return p; | |
} | |
ShellFolderPtr | |
BindPath(IShellFolder& folder, const ShellPath& p_pth, | |
::IBindCtx* p_ctx = nullptr) | |
ythrow(COMException) | |
{ | |
return BindToObject(folder, p_pth.Get(), p_ctx, ::IID_IShellFolder); | |
} | |
EnumIDListPtr | |
EnumObjects(IShellFolder& folder, ::SHCONTF flags = SHCONTF_FOLDERS | |
| SHCONTF_NONFOLDERS, ::HWND h_own = nullptr) | |
ythrow(COMException) | |
{ | |
IEnumIDList* p{}; | |
CheckHResult(folder.EnumObjects(h_own, flags, &p)); | |
return p; | |
} | |
std::wstring | |
GetDisplayName(IShellFolder& folder, const ShellPath& p_pth) | |
{ | |
::STRRET strret; | |
wchar_t buf[MAX_PATH]; | |
CheckHResult(folder.GetDisplayNameOf(p_pth.Get(), SHGDN_INFOLDER, &strret)); | |
::StrRetToBufW(&strret, p_pth.Get(), buf, MAX_PATH); | |
return buf; | |
} | |
ShellPath | |
ParseDisplayName(IShellFolder& folder, const wchar_t* name, | |
::ULONG* p_attr = nullptr) | |
{ | |
::LPITEMIDLIST p{}; | |
std::wstring str(name); | |
CheckHResult(folder.ParseDisplayName(nullptr, nullptr, &str[0], nullptr, | |
&p, p_attr)); | |
return p; | |
} | |
class YF_API DirectorySession | |
{ | |
public: | |
typedef ShellFolderPtr NativeHandle; | |
private: | |
NativeHandle dir; | |
protected: | |
EnumIDListPtr pList; | |
public: | |
// explicit | |
// DirectorySession(const wchar_t* name) | |
// {} | |
explicit | |
DirectorySession(NativeHandle p_folder = {}, | |
::SHCONTF flags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS) | |
: dir(std::move(p_folder)), | |
pList(dir ? EnumObjects(*dir, flags) : nullptr) | |
{} | |
DirectorySession(DirectorySession&& h) | |
: dir(std::move(h.dir)), pList(std::move(h.pList)) | |
{ | |
yunseq(h.dir = nullptr, pList = nullptr); | |
} | |
~DirectorySession() ynothrow = default; | |
NativeHandle | |
GetNativeHandle() const ynothrow | |
{ | |
return dir; | |
} | |
void | |
Rewind() ythrow(COMException) | |
{ | |
if(pList) | |
CheckHResult(pList->Reset()); | |
} | |
}; | |
class YF_API HDirectory final : private DirectorySession | |
{ | |
private: | |
mutable ShellPath p_path; | |
mutable std::string utf8_name; | |
public: | |
template<typename... _tParams> | |
explicit | |
HDirectory(_tParams&&... args) | |
: DirectorySession(yforward(args)...), p_path(), utf8_name() | |
{} | |
HDirectory& | |
operator*() ynothrow | |
{ | |
return *this; | |
} | |
const HDirectory& | |
operator*() const ynothrow | |
{ | |
return *this; | |
} | |
operator string() const ynothrow | |
{ | |
return GetName(); | |
} | |
HDirectory& | |
operator++() | |
{ | |
p_path = GetNext(pList.GetObject()); | |
return *this; | |
} | |
explicit | |
operator bool() const ynothrow | |
{ | |
return bool(p_path); | |
} | |
bool | |
IsDirectory() const ynothrow | |
{ | |
::ULONG uAttr(SFGAO_FOLDER); | |
GetNativeHandle()->GetAttributesOf(1, const_cast< ::LPCITEMIDLIST*>( | |
&p_path.GetRef()), &uAttr); | |
return uAttr & SFGAO_FOLDER; | |
} | |
const char* | |
GetName() const ynothrow | |
{ | |
if(p_path) | |
{ | |
try | |
{ | |
const auto h(GetNativeHandle()); | |
yassume(h); | |
utf8_name = ToANSI(GetDisplayName(*h, p_path)); | |
return &utf8_name[0]; | |
} | |
catch(...) | |
{} | |
} | |
return "."; | |
} | |
using DirectorySession::GetNativeHandle; | |
const ShellPath& | |
GetPathPtr() const ynothrow | |
{ | |
return p_path; | |
} | |
ShellPath& | |
GetPathPtrRef() ynothrow | |
{ | |
return p_path; | |
} | |
using DirectorySession::Rewind; | |
}; | |
typedef indirect_input_iterator<HDirectory*> FileIterator; | |
} | |
#endif | |
namespace YSLib | |
{ | |
using namespace UI; | |
template<typename _fCreator> | |
using GWidgetCreatorMap = unordered_map<string, _fCreator>; | |
template<typename _fCreator> | |
GWidgetCreatorMap<_fCreator>& | |
FetchWidgetMapping() | |
{ | |
static GWidgetCreatorMap<_fCreator> widget_map; | |
return widget_map; | |
} | |
template<class _tWidget> | |
class GWidgetFactory | |
{ | |
private: | |
template<typename... _tParams> | |
static unique_ptr<IWidget> | |
CreateWidget(_tParams&&... args) | |
{ | |
return make_unique<_tWidget>(yforward(args)...); | |
} | |
template<typename... _tParams> | |
static int | |
Register(const string& key) | |
{ | |
FetchWidgetMapping<unique_ptr<IWidget>(*)(_tParams...)>().emplace( | |
key, &CreateWidget<_tParams...>); | |
return 0; | |
} | |
public: | |
GWidgetFactory(const string& key) | |
{ | |
static int create_def(Register<>(key)); | |
static int create_bounds(Register<const Rect&>(key)); | |
static_cast<void>(create_def); | |
static_cast<void>(create_bounds); | |
} | |
}; | |
const Size def_size(80, 24); | |
const Size def_size2(120, 36); | |
const Size def_size3(160, 48); | |
template<typename... _tParams> | |
unique_ptr<IWidget> | |
CreateWidget(const string& type_str, _tParams&&... args) | |
{ | |
if(const auto f = FetchWidgetMapping<unique_ptr<IWidget>(*)(_tParams...)>()[ | |
type_str]) | |
{ | |
YTraceDe(Notice, "Found widget creator: %s.\n", type_str.c_str()); | |
auto p(f(yforward(args)...)); | |
auto p1 = dynamic_cast<Widget*>(p.get()); | |
if(type_str == "Widget") | |
p1->Background = SolidBrush(ColorSpace::Yellow); | |
else if(type_str == "Control") | |
p1->Background = SolidBrush(ColorSpace::Aqua); | |
else if(type_str == "Panel") | |
p1->Background = SolidBrush(ColorSpace::Blue); | |
return std::move(p); | |
} | |
return {}; | |
} | |
Rect | |
ParseRect(const string& str) | |
{ | |
std::istringstream iss(str); | |
int buf[4]; | |
for(size_t i(0); i < 4; ++i) | |
if(iss) | |
iss >> buf[i]; | |
else | |
throw std::invalid_argument("Parse 'Rect' failed: bad state."); | |
// FIXME: Complete max value checking. | |
if(buf[2] < 0 || buf[3] < 0) | |
throw std::invalid_argument("Parse 'Rect' failed: underflow."); | |
Rect res(buf[0], buf[1], buf[2], buf[3]); | |
YTraceDe(Informative, "ParseRect: %s.\n", to_string(res).c_str()); | |
return res; | |
} | |
unique_ptr<IWidget> | |
DetectWidgetNode(const ValueNode& node) | |
{ | |
try | |
{ | |
const auto& type_str(AccessChild<string>(node, "$type")); | |
if(const auto* p_bounds_str = AccessChildPtr<string>(node, "$bounds")) | |
try | |
{ | |
const Rect& bounds(ParseRect(*p_bounds_str)); | |
return CreateWidget(type_str, bounds); | |
} | |
catch(std::invalid_argument&) | |
{} | |
return CreateWidget(type_str); | |
} | |
catch(ystdex::bad_any_cast&) | |
{} | |
return {}; | |
} | |
bool | |
CheckChildName(const string& str) | |
{ | |
return str.size() != 0 && str[0] != '$'; | |
} | |
ValueNode | |
TransformUILayout(const ValueNode& node) | |
{ | |
if(unique_ptr<IWidget> p_new_widget{DetectWidgetNode(node)}) | |
{ | |
ValueNode res(0, node.GetName()); | |
if(auto p_pnl = dynamic_cast<Panel*>(p_new_widget.get())) | |
{ | |
auto p_cont(make_unique<ValueNode::Container>()); | |
for(const auto& vn : node) | |
if(CheckChildName(vn.GetName())) | |
try | |
{ | |
if(ValueNode res_child{TransformUILayout(vn)}) | |
{ | |
auto& p_wgt(*AccessChild<shared_ptr<IWidget>>( | |
res_child, "$pointer")); | |
if(p_cont->insert(std::move(res_child)).second) | |
*p_pnl += p_wgt; | |
} | |
} | |
catch(ystdex::bad_any_cast&) | |
{} | |
res += ValueNode{0, "$children", p_cont.release(), PointerTag()}; | |
} | |
res += ValueNode{0, "$pointer", | |
shared_ptr<IWidget>(std::move(p_new_widget))}; | |
return std::move(res); | |
} | |
return {}; | |
} | |
ValueNode | |
ConvertUILayout(const string& str) | |
{ | |
ValueNode root; | |
try | |
{ | |
root = TransformConfiguration(SContext::Analyze(Session(str))); | |
} | |
catch(ystdex::bad_any_cast& e) | |
{ | |
// TODO: Avoid memory allocation. | |
throw LoggedEvent(ystdex::sfmt( | |
"Bad configuration found: cast failed from [%s] to [%s] .", | |
e.from(), e.to()), Warning); | |
} | |
// return std::move(root); | |
return TransformUILayout(std::move(root)); | |
} | |
const char tu_test[] = u8R"NPL( | |
node_a | |
($type "Panel") | |
($bounds "128 64 160 48") | |
( | |
node_c | |
($type "Control") | |
($bounds "4 4 120 36") | |
) | |
( | |
node_b | |
($type "Widget") | |
($bounds "0 0 80 24") | |
) | |
)NPL"; | |
void | |
NPLUITest(Panel& pnl) | |
{ | |
GWidgetFactory<Widget>("Widget"); | |
GWidgetFactory<Control>("Control"); | |
GWidgetFactory<Panel>("Panel"); | |
static auto node(ConvertUILayout(tu_test)); | |
YTraceDe(Notice, "Size of children nodes: %u\n", unsigned(node.GetSize())); | |
#if 0 | |
{ | |
TextFile tf("node.txt", ios::out | ios::trunc); | |
tf << NPL::Configuration(node); | |
} | |
std::system("notepad node.txt"); | |
#endif | |
pnl += *AccessChild<shared_ptr<IWidget>>(node, "$pointer"); | |
} | |
} | |
int | |
main() | |
{ | |
using namespace YSLib; | |
using namespace platform_ex; | |
#if TEST_GUI == 2 | |
// YSLib::InitializeInstalled(); | |
COM com; | |
while(wcin) | |
{ | |
wstring ws; | |
getline(wcin, ws); | |
try | |
{ | |
auto p_dsk = GetDesktopFolder(); | |
auto& dsk(p_dsk.GetObject()); | |
auto path = ParseDisplayName(dsk, ws.c_str()); | |
// auto path = ParseDisplayName(dsk, reinterpret_cast<const wchar_t*>( | |
// String(in, Text::CharSet::GBK).c_str())); | |
cout << ToANSI(GetDisplayName(dsk, path)) << endl | |
<< "====" << endl; | |
ShellFolderPtr psfFirstFolder; | |
{ | |
// HDirectory h_dir(BindPath(GetDesktopFolder().GetObject(), | |
// LocateFolder(CSIDL_PROGRAM_FILES))); | |
// HDirectory h_dir(GetDesktopFolder().GetObject()); | |
HDirectory h_dir(BindPath(dsk, path)); | |
for(FileIterator i(&h_dir); i != FileIterator(); ++i) | |
#if 0 | |
for(auto i(ystdex::make_transform(FileIterator(&h_dir), | |
[](const FileIterator& i){ | |
return i.get()->GetName(); | |
})); i != FileIterator(); ++i) | |
#endif | |
{ | |
cout << string(*i) << '\n'; | |
const auto& h(i.get()); | |
if(!psfFirstFolder && h->IsDirectory()) | |
psfFirstFolder = BindPath(*h->GetNativeHandle(), | |
h->GetPathPtr()); | |
} | |
} | |
#if 0 | |
cout << "\n\n"; | |
if(psfFirstFolder) | |
{ | |
HDirectory h_dir(std::move(psfFirstFolder)); | |
#if 0 | |
vector<string> vec; | |
// vector<size_t> vec; | |
copy(FileIterator(&h_dir), FileIterator(), back_inserter(vec)); | |
for(const auto& x : vec) | |
cout << x << endl; | |
#endif | |
for(FileIterator i(&h_dir); i != FileIterator(); ++i) | |
cout << string(*i) << endl; | |
} | |
#endif | |
} | |
catch(COMException&) | |
{} | |
} | |
cin.get(); | |
#endif | |
#if TEST_GUI == 1 | |
GUIApplication app; | |
#if TEST_IMAGE | |
ImageCodec codec; | |
#endif | |
#if 1 | |
TestWnd wgt(Rect(0, 0, 800, 600)); | |
NPLUITest(wgt); | |
Host::ShowTopLevel(wgt, WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, 0); | |
wgt.p_wnd = &Host::WaitForHostWindow(wgt); | |
#else | |
UI::Label wgt(Drawing::Size(120, 24)); | |
wgt.Text = "Hello world!"; | |
Host::Show(wgt, WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX); | |
#endif | |
Execute(app); | |
#endif | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//#undef NDEBUG | |
#include <cassert> | |
#include <cstddef> | |
#include <cstdint> | |
#include <cstdlib> | |
#include <memory> | |
#if !YB_T_NO_MATH | |
#include <cmath> | |
#include <ccomplex> | |
#include <complex> | |
#endif | |
#if !_MSC_VER | |
#include <type_traits> | |
#include <cstdio> | |
#include <ctime> | |
#include <tuple> | |
#include <iterator> | |
#include <functional> | |
#include <algorithm> | |
#include <bitset> | |
#include <chrono> | |
#include <random> | |
#endif | |
#if !YB_T_NO_IOSTREAM | |
#include <iostream> | |
#include <iomanip> | |
#endif | |
#if !YB_T_NO_CONT | |
#include <array> | |
#include <vector> | |
#include <list> | |
#include <forward_list> | |
#include <map> | |
#include <set> | |
#include <unordered_map> | |
#include <unordered_set> | |
#include <stack> | |
#include <queue> | |
#endif | |
#if YTEST_B == 1 | |
#include <ydef.h> | |
#include <YSLib/Core/ybasemac.h> | |
typedef std::int16_t s16; | |
typedef std::uint16_t u16; | |
typedef std::uint32_t u32; | |
typedef s16 SPos; | |
typedef u16 SDst; | |
#elif YTEST_B == 2 | |
#include <ystdex/any.h> | |
#include <YSLib/Core/YObject.h> | |
#elif YTEST_B == 3 | |
#include <YSLib/Core/ValueNode.h> | |
#elif YTEST_B == 4 | |
#include <ysbuild.h> | |
#endif | |
#if !YB_T_NO_TIMING | |
#include <ytest/timing.hpp> | |
#endif | |
#include <typeinfo> | |
#include <string> | |
#include <cxxabi.h> | |
namespace ytest | |
{ | |
char* | |
demangle_c(const std::type_info& ti) | |
{ | |
int status; | |
return abi::__cxa_demangle(ti.name(), {}, {}, &status); | |
// Warning: don't forget free! | |
// See http://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html . | |
} | |
std::string | |
demangle(const std::type_info& ti) | |
{ | |
const auto p(demangle_c(ti)); | |
std::string str(p); | |
std::free(p); | |
return std::move(str); | |
} | |
} | |
using namespace ytest; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment