
The supported platforms of v1.0 will be Windows desktop and Android.
Initial design goals will be:
1) to be as fast as possible (after all this is C++);
2) to embrace modern C++ paradigms (which includes templates and
exceptions);
3) for compiled binaries to be as small as possible with no huge
redistributables (after all this is
not Qt);
4) to not use signals and slots as an event mechanism (after all this is
not Qt).
The major unknown at this point is the quality of C++ support provided by the Android (NDK) platform; currently third party libraries/patches seem to be required to enable C++ exception support and to provide for a C++ Standard Library (STL): come on Google, get with the program! :)
Watch this space for further updates.
Sample application:

Try the sample application for yourself
(requires Windows 7, Vista or XP):
Sample application source code:
<?xml version="1.0" encoding="utf-8"?>
<neogfx>
<resources name="test" language="en-gb">
<main_window title="ClicksAndWhistles 3.0" layout_type="horizontal" layout_margin="0.5em" layout_gap="0.5em" x="2in" y="2in" width="7in" height="8in">
<menu mnemonics="auto">
<menu name="File">
<command text="Connect..." shortcut="Ctrl+N" id="connect" />
<command text="Join Channel..." shortcut="Ctrl+J" id="join_channel" />
<command text="Disconnect" shortcut="Ctrl+Q" id="disconnect" />
<command text="New Console" id="new" />
<separator />
<command text="Manage Identities..." id="manage_identities" />
<command text="Manage Servers..." id="manage_servers" />
<separator />
<command text="View Log..." id="view_log" />
<separator />
<command text="Recent Server" id="recent_server" disabled="true" />
<separator />
<command text="Exit" id="exit" />
</menu>
<menu name="View">
<command text="Toolbar" id="view_toolbar" />
<command text="Status Bar" id="view_status_bar" />
</menu>
<menu name="Favourites">
<command text="Add to Favourites..." id="add_to_favourites" />
<command text="Organize Favourites..." id="organize_favourites" />
<separator />
<command text="עִבְרִית العربية" />
<command text="one" />
<command text="two" />
<command text="three" />
<menu name="folder 1">
<command text="apples" />
<command text="oranges" />
<command text="bananas" />
<menu name="folder">
<command text="circles" />
<command text="squares" />
<command text="triangles" />
<command text="hexagons" />
<command text="pentagons" />
<command text="octagons" />
</menu>
<command text="grapes" />
<command text="peaches" />
<command text="lemons" />
</menu>
<menu name="folder 2">
<command text="a" />
<command text="b" />
<command text="c" />
<menu name="folder">
<command text="aa" />
<command text="bb" />
<command text="cc" />
<command text="dd" />
<command text="ee" />
<command text="ff" />
</menu>
<command text="d" />
<command text="e" />
<command text="f" />
</menu>
<command text="four" />
<command text="five" />
<command text="six" />
</menu>
<menu name="Tools">
<command text="Options..." id="options" />
<command text="Macros..." id="macros" />
<command text="Keywords and Emoticons..." id="keywords" />
<command text="Plugins..." id="plugins" />
<separator />
<command text="Install Program Updates..." id="update_program" />
</menu>
<menu name="Help">
<command text="User Guide..." id="user_guide" />
<command text="ClicksAndWhistles Channel" id="help_channel" />
<separator />
<command text="About ClicksAndWhistles..." id="about" />
</menu>
</menu>
<layout id ="dialog" gap="0.25em" margin="0.5em" valign="centre">
<list_box id="items" height="240px">
<column name="Entry" />
<column name="Some Text" />
<column name="Some More Text" />
</list_box>
<tree_box id ="tree_items" height="240px" show_buttons="true">
<column name="Entry" />
<column name="Some Text" />
<column name="Some More Text" />
</tree_box>
<button id="one" text="Button One" />
<button id="two" text="Button Two" />
<edit_box id="edit" text="abc123" label="Text:" width="1.5in"/>
<button id="three" text="Button Three" />
<layout type="grid" gap="0.25em" columns="3" rows="4">
<button id="keypad1" text="1" />
<button id="keypad2" text="2" />
<button id="keypad3" text="3" />
<button id="keypad4" text="4" />
<button id="keypad5" text="5" />
<button id="keypad6" text="6" />
<button id="keypad7" text="7" />
<button id="keypad8" text="8" />
<button id="keypad9" text="9" />
<spacer />
<button id="keypad0" text="0" />
<spacer />
</layout>
<button id="big" text="This is a fixed width multiline button." multiline="true" width="2in" />
<button id="rtl" text="Another multiline button with some RTL text.\nעִבְרִית\nالعربية" multiline="true" />
</layout>
<separator type="vertical" />
<layout type="vertical" gap="0.5em" margin="0.5em" align="fill">
<button id="red" text="Red" colour="#802020" />
<button id="green" text="Green" colour="#208020" />
<button id="blue" text="Blue" colour="#202080" />
<spacer />
<spacer />
<button id="goldenrod" text="Goldenrod" colour="goldenrod"/>
<button id="khaki" text="Khaki" colour="khaki"/>
<spacer />
<button id="hotpink" text="Hot Pink" colour="hotpink"/>
</layout>
</main_window>
</resources>
</neogfx>
#include <neolib/string.h>
#include <neolib/random.h>
#include <neogfx/neogfx.h>
#include <neogfx/app.h>
#include <neogfx/command.h>
#include <neogfx/window.h>
#include <neogfx/button.h>
#include <neogfx/edit_box.h>
#include <neogfx/spacer.h>
#include <neogfx/separator.h>
#include <neogfx/list_box.h>
#include <neogfx/tree_box.h>
#include "resources.h"
typedef neogfx::three_column_list_box test_list_box;
typedef neogfx::three_column_tree_box test_tree_box;
class example_event_handler :
public neogfx::command_event_sink,
public neogfx::window_event_sink,
public neogfx::button_event_sink,
public neogfx::list_box_event_sink,
public neogfx::tree_box_event_sink
{
public:
example_event_handler(neogfx::app& aApp) : iApp(aApp)
{
on_command(iApp, test::id_exit, &example_event_handler::on_exit);
on_button_press_event(iApp.window_from_id<neogfx::button>(test::id_one), &example_event_handler::change_theme_colour_and_other_stuff);
on_button_press_event(iApp.window_from_id<neogfx::button>(test::id_two), &example_event_handler::no_layout);
on_button_press_event(iApp.window_from_id<neogfx::button>(test::id_three), &example_event_handler::flow_layout);
on_button_press_event(iApp.window_from_id<neogfx::button>(test::id_keypad1), &example_event_handler::disable_list_box_full_row_select);
on_button_press_event(iApp.window_from_id<neogfx::button>(test::id_keypad2), &example_event_handler::enable_list_box_full_row_select);
on_button_press_event(iApp.window_from_id<neogfx::button>(test::id_keypad3), &example_event_handler::disable_tree_box_full_row_select);
on_button_press_event(iApp.window_from_id<neogfx::button>(test::id_keypad4), &example_event_handler::enable_tree_box_full_row_select);
on_button_press_event(iApp.window_from_id<neogfx::button>(test::id_keypad0), &example_event_handler::black_theme);
neogfx::list_box& itemsListBox = iApp.window_from_id<neogfx::list_box>(test::id_items);
on_list_box_event(itemsListBox, neogfx::list_box_event::ItemSelected, &example_event_handler::list_box_item_selected);
on_list_box_event(itemsListBox, neogfx::list_box_event::ItemDraw, &example_event_handler::list_box_draw_item);
on_list_box_event(itemsListBox, neogfx::list_box_event::ItemMenu, &example_event_handler::list_box_delete_item);
on_list_box_event(itemsListBox, neogfx::list_box_event::HeaderAction, &example_event_handler::list_box_header_action);
neogfx::tree_box& itemsTreeBox = iApp.window_from_id<neogfx::tree_box>(test::id_tree_items);
on_tree_box_event(itemsTreeBox, neogfx::tree_box_event::ItemSelected, &example_event_handler::tree_box_item_selected);
on_tree_box_event(itemsTreeBox, neogfx::tree_box_event::ItemDraw, &example_event_handler::tree_box_draw_item);
on_tree_box_event(itemsTreeBox, neogfx::tree_box_event::ItemMenu, &example_event_handler::tree_box_delete_item);
on_tree_box_event(itemsTreeBox, neogfx::tree_box_event::HeaderAction, &example_event_handler::tree_box_header_action);
}
void on_exit()
{
iApp.exit(0);
}
void change_theme_colour_and_other_stuff()
{
iApp.current_theme() = neogfx::theme(iApp, neogfx::colour(iRandom.get(0xFF), iRandom.get(0xFF), iRandom.get(0xFF)));
iApp.window_from_id(test::id_one).set_window_text(neogfx::text(L"Button One ") + neogfx::text(iRandom.get(31), L'.'));
}
void black_theme()
{
iApp.current_theme() = neogfx::theme(iApp, neogfx::colour::Black);
}
void no_layout()
{
iApp.window_from_id<neogfx::layout>(test::id_dialog).set_layout_type(neogfx::LayoutNone);
}
void flow_layout()
{
iApp.window_from_id<neogfx::layout>(test::id_dialog).set_layout_type(neogfx::LayoutFlow);
}
void disable_list_box_full_row_select()
{
iApp.window_from_id<test_list_box>(test::id_items).disable_full_row_select();
}
void enable_list_box_full_row_select()
{
iApp.window_from_id<test_list_box>(test::id_items).enable_full_row_select();
}
void disable_tree_box_full_row_select()
{
iApp.window_from_id<test_tree_box>(test::id_tree_items).disable_full_row_select();
}
void enable_tree_box_full_row_select()
{
iApp.window_from_id<test_tree_box>(test::id_tree_items).enable_full_row_select();
}
void list_box_item_selected(const neogfx::list_box_event& aEvent)
{
}
void list_box_draw_item(const neogfx::list_box_event& aEvent)
{
test_list_box& itemsListBox = iApp.window_from_id<test_list_box>(test::id_items);
const neogfx::list_box_event::draw_item_info& drawItemInfo = aEvent.data();
if (!itemsListBox.has_selection() || !itemsListBox.has_focus() || itemsListBox.selection() != aEvent.item_index() || (!itemsListBox.full_row_select() &&
drawItemInfo.column_index() != 0))
{ // if list box item is not selected then make the item text a random colour (seed = item data)
neolib::random random(reinterpret_cast<int>(itemsListBox[aEvent.item_index()]));
neogfx::colour randomColour = neogfx::colour(random.get(0xFF), random.get(0xFF), random.get(0xFF));
while(randomColour.similar_intensity(itemsListBox.window_colour(), 0x20))
randomColour = neogfx::colour(random.get(0xFF), random.get(0xFF), random.get(0xFF));
drawItemInfo.set_text_colour(randomColour);
}
}
void list_box_delete_item(const neogfx::list_box_event& aEvent)
{
test_list_box& itemsListBox = iApp.window_from_id<test_list_box>(test::id_items);
itemsListBox.erase(aEvent.item_index());
}
struct list_box_sorter
{
bool operator()(const test_list_box::item& aLeft, const test_list_box::item& aRight) const
{
return reinterpret_cast<int>(aLeft.data()) < reinterpret_cast<int>(aRight.data());
}
};
void list_box_header_action(const neogfx::list_box_event& aEvent)
{
test_list_box& itemsListBox = iApp.window_from_id<test_list_box>(test::id_items);
if (aEvent.column_index() != 0)
itemsListBox.sort_by_cell_text(aEvent.column_index(), true, true);
else
itemsListBox.sort(0, list_box_sorter());
}
void tree_box_item_selected(const neogfx::tree_box_event& aEvent)
{
}
void tree_box_draw_item(const neogfx::tree_box_event& aEvent)
{
test_tree_box& itemsTreeBox = iApp.window_from_id<test_tree_box>(test::id_tree_items);
const neogfx::tree_box_event::draw_item_info& drawItemInfo = aEvent.data();
if (!itemsTreeBox.has_selection() || !itemsTreeBox.has_focus() || itemsTreeBox.selection() != aEvent.location() || (!itemsTreeBox.full_row_select() &&
drawItemInfo.column_index() != 0))
{ // if tree box item is not selected then make the item text a random colour (seed = item data)
neolib::random random(reinterpret_cast<int>(static_cast<const test_tree_box::item&>(aEvent.item()).data()));
neogfx::colour randomColour = neogfx::colour(random.get(0xFF), random.get(0xFF), random.get(0xFF));
while(randomColour.similar_intensity(itemsTreeBox.window_colour(), 0x20))
randomColour = neogfx::colour(random.get(0xFF), random.get(0xFF), random.get(0xFF));
drawItemInfo.set_text_colour(randomColour);
}
}
void tree_box_delete_item(const neogfx::tree_box_event& aEvent)
{
test_tree_box& itemsTreeBox = iApp.window_from_id<test_tree_box>(test::id_tree_items);
itemsTreeBox.erase(aEvent.location());
}
struct tree_box_sorter
{
bool operator()(const test_tree_box::item& aLeft, const test_tree_box::item& aRight) const
{
return reinterpret_cast<int>(aLeft.data()) < reinterpret_cast<int>(aRight.data());
}
};
void tree_box_header_action(const neogfx::tree_box_event& aEvent)
{
test_tree_box& itemsTreeBox = iApp.window_from_id<test_tree_box>(test::id_tree_items);
if (aEvent.column_index() != 0)
itemsTreeBox.sort_by_cell_text(aEvent.column_index(), true, true);
else
itemsTreeBox.sort(0, tree_box_sorter());
}
private:
neogfx::app& iApp;
neolib::random iRandom;
};
void populate_tree(test_tree_box& aTree, test_tree_box::const_iterator aParentNode)
{
if (aTree.depth(aParentNode) == 4)
return;
static neolib::random random;
for (int i = random.get(0, 10); i != 0; --i)
{
test_tree_box::const_iterator newNode = aTree.append(aParentNode, reinterpret_cast<void*>(aTree.size() + 1),
neogfx::text(L"Tree box entry #") + neolib::integer_to_string<wchar_t>(aTree.size() + 1));
for (int j = 1; j != 3; ++j)
{
const neogfx::text& letters = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
neogfx::text testText;
for (int k = random.get(1, 32); k != 0; --k)
testText += letters[random.get(letters.size() - 1)];
aTree.set_text(newNode, j, testText);
}
populate_tree(aTree, newNode);
}
}
int main()
{
neogfx::app myApp(test::resource_data);
test_list_box& itemsListBox = myApp.window_from_id<test_list_box>(test::id_items);
neolib::random random;
for (int i = 1; i <= 10000; ++i)
{
test_list_box::const_iterator item = itemsListBox.append(reinterpret_cast<void*>(i),
neogfx::text(L"List box entry #") + neolib::integer_to_string<wchar_t>(i));
for (int j = 1; j != 3; ++j)
{
const neogfx::text& letters = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
neogfx::text testText;
for (int k = random.get(1, 32); k != 0; --k)
testText += letters[random.get(letters.size() - 1)];
itemsListBox.set_text(item, j, testText);
}
}
itemsListBox.sort_by_cell_text(1, true, true);
test_tree_box& itemsTreeBox = myApp.window_from_id<test_tree_box>(test::id_tree_items);
populate_tree(itemsTreeBox, itemsTreeBox.begin());
itemsTreeBox.sort_by_cell_text(1, true, true);
example_event_handler myExampleEventHandler(myApp);
return myApp.run();
}
The neogfx C++ Coding Style Guide is here.

Windows is a registered trademark of Microsoft Corporation.
Android is a trademark of Google Inc.
Qt is a trademark of Nokia Corporation.