// Project Headers
#include "Application.h"
#include "Window.h"
#include "Painter.h"
#include "SignalSlot.h"
#include "Widget.h"
#include "MemoryMapping.h"
#include "CommonWidgets.h"
#include "Test.h"
#include "XmlParser.h"
#include "UiBuilder.h"
#include "Reflection.h"
#include <iostream>
#include <iomanip>
#include <climits>
#include <fstream>
#include <cctype>
#include <cstdarg>
#include <type_traits>
#define typeof(...) std::remove_reference<decltype(__VA_ARGS__)>::type
extern bool c_useRetina;
extern float c_retinaScale;
// TODO: doxygen style documentation everywhere
USING_NAMESPACE
class CludgeBoolProperty : public AbstractProperty<bool>
{
public:
void cludgeSet(bool) { set(false); } // set the value without invoking valueChanged
};
// Useful for radio button groups
// pass in a list of Propery<bool> pointers, and terminate the argument list with NULL
void makeExclusiveBoolPropertySet(AbstractProperty<bool>* a_value1, ...)
{
va_list list;
std::vector<int> v;
std::string str;
va_start(list, a_value1);
Vector<CludgeBoolProperty*> radioButtonGroup;
CludgeBoolProperty* nextVal = (CludgeBoolProperty*)a_value1;
while (nextVal) {
radioButtonGroup.push_back(nextVal);
nextVal = va_arg(list, CludgeBoolProperty*);
}
va_end(list);
for (unsigned i = 0; i < radioButtonGroup.size(); i++)
for (unsigned j = 0; j < radioButtonGroup.size(); j++)
if (i != j)
connect(radioButtonGroup[i]->valueChanged, radioButtonGroup[j], &CludgeBoolProperty::cludgeSet);
}
class TestWindow : public Inherit<Widget, TestWindow>
{
public:
Property<String> m_labelText;
Property<String> m_groupBoxTitle;
Property<bool> m_checkBoxChecked1;
Property<bool> m_radioButtonChecked1;
Property<bool> m_checkBoxChecked2;
Property<bool> m_radioButtonChecked2;
Property<bool> m_checkBoxChecked3;
Property<bool> m_radioButtonChecked3;
Property<bool> m_checkBoxChecked4;
Property<bool> m_radioButtonChecked4;
Property<int> m_sliderValue;
Property<int> m_comboValue;
VBox* m_vbox1 = nullptr;
void buttonPressed(int)
{
printf("button pressed\n");
}
TestWindow(Widget* parent, const char* name)
: BaseT(parent, name)
{
XmlParser parser;
XmlDomTreeBuilder domTree;
UiBuilder uiBuilder(this);
uiBuilder.registerProperty("m_labelText" , m_labelText);
uiBuilder.registerProperty("m_groupBoxTitle" , m_groupBoxTitle);
uiBuilder.registerProperty("m_checkBoxChecked1" , m_checkBoxChecked1);
uiBuilder.registerProperty("m_radioButtonChecked1", m_radioButtonChecked1);
uiBuilder.registerProperty("m_checkBoxChecked2" , m_checkBoxChecked2);
uiBuilder.registerProperty("m_radioButtonChecked2", m_radioButtonChecked2);
uiBuilder.registerProperty("m_checkBoxChecked3" , m_checkBoxChecked3);
uiBuilder.registerProperty("m_radioButtonChecked3", m_radioButtonChecked3);
uiBuilder.registerProperty("m_checkBoxChecked4" , m_checkBoxChecked4);
uiBuilder.registerProperty("m_radioButtonChecked4", m_radioButtonChecked4);
uiBuilder.registerProperty("m_sliderValue" , m_sliderValue);
uiBuilder.registerProperty("m_comboValue" , m_comboValue);
parser.parseXmlFile("../data/TestUI.xml", domTree);
parser.parseXmlFile("../data/TestUI.xml", uiBuilder);
domTree.printDomTree();
Button* button = (Button*)uiBuilder.findWidget("but1").m_widget;
RadioButton* rb1 = (RadioButton*)uiBuilder.findWidget("rb1").m_widget;
RadioButton* rb2 = (RadioButton*)uiBuilder.findWidget("rb2").m_widget;
RadioButton* rb3 = (RadioButton*)uiBuilder.findWidget("rb3").m_widget;
RadioButton* rb4 = (RadioButton*)uiBuilder.findWidget("rb4").m_widget;
if (button)
connect(button->activated, this, &TestWindow::buttonPressed);
if (rb1 && rb2 && rb3 && rb4)
makeExclusiveBoolPropertySet(&rb1->checked, &rb2->checked, &rb3->checked, &rb4->checked, nullptr);
/*
m_labelText = "testing";
VBox *vbox1 = new VBox(this);
HBox *hbox = new HBox(vbox1);
VBox *vbox = new VBox(hbox);
RadioButton *rb1 = new RadioButton(vbox, m_radioButtonChecked1, "Hello World");
RadioButton *rb2 = new RadioButton(vbox, m_radioButtonChecked2, "Hello World");
RadioButton *rb3 = new RadioButton(vbox, m_radioButtonChecked3, "Hello World");
RadioButton *rb4 = new RadioButton(vbox, m_radioButtonChecked4, "Hello World");
Button *but1 = new Button(vbox, "Hello World");
connect(but1->activated, this, &TestWindow::buttonPressed);
Button *but2 = new Button(vbox, "Hello World");
Button *but3 = new Button(vbox, "Hello World");
Button *but4 = new Button(vbox, "Hello World");
new VSpace(vbox);
vbox = new VBox(hbox);
CheckBox *cb1 = new CheckBox(vbox, m_checkBoxChecked1, "Hello World");
CheckBox *cb2 = new CheckBox(vbox, m_checkBoxChecked2, "Hello World");
CheckBox *cb3 = new CheckBox(vbox, m_checkBoxChecked3, "Hello World");
CheckBox *cb4 = new CheckBox(vbox, m_checkBoxChecked4, "Hello World");
Label *l1 = new Label(vbox, m_labelText);
Label *l2 = new Label(vbox, m_labelText);
Label *l3 = new Label(vbox, m_labelText);
Label *l4 = new Label(vbox, m_labelText);
LineEdit *le1 = new LineEdit(vbox, m_labelText);
new VSpace(vbox);
new VSpace(vbox);
vbox = new VBox(hbox);
Slider *sl = new Slider(vbox, m_sliderValue);
ComboBox *cb = new ComboBox(vbox, m_comboValue);
GroupBox *gb = new GroupBox(vbox, m_labelText);
new VSpace(vbox);
CheckBox *cb5 = new CheckBox(gb, m_checkBoxChecked1, "Test");
CheckBox *cb6 = new CheckBox(gb, m_checkBoxChecked2, "Test");
new Label(gb, m_labelText);
new LineEdit(gb, m_labelText);
new Slider(gb, m_sliderValue);
new VSpace(vbox);
ProgressBar *pb = new ProgressBar(vbox1, m_sliderValue);
new VSpace(vbox1);
cb->addItem("blah item 1");
cb->addItem("foo item 2");
cb->addItem("bar item 3");
rb2->disabled = true;
but2->disabled = true;
cb2->disabled = true;
l2->disabled = true;
rb3->isDefault = true;
but3->isDefault = true;
cb3->isDefault = true;
rb4->hasFocus = true;
but4->hasFocus = true;
cb4->hasFocus = true;
connect(m_checkBoxChecked1.valueChanged, &but1->isDefault, &Property<bool>::setValue);
makeExclusiveBoolPropertySet(&m_radioButtonChecked1, &m_radioButtonChecked2,
&m_radioButtonChecked3, &m_radioButtonChecked4, NULL);
*/
//connect(m_checkBoxChecked1.valueChanged, this, & typeof(*this)::refresh );
//connect(m_checkBoxChecked1.valueChanged, this, & TestWindow::refresh );
m_vbox1 = (VBox*)uiBuilder.findWidget("vbox1").m_widget;
connect(m_sliderValue.valueChanged, this, &ThisT::sliderMoved);
connect(m_checkBoxChecked1.valueChanged, this, &ThisT::toggleRetina);
}
void toggleRetina(bool val)
{
refresh(val);
// c_useRetina = val;
// updateLayout();
}
void sliderMoved(int val)
{
fprintf(stderr, "slider val: %i\n", val);
//c_retinaScale = (4.0f * val) / 100.0f;
//scale = (2.0f * val) / 100.0f;
if (m_vbox1)
m_vbox1->scale = (2.0f * val) / 100.0f;
updateLayout();
}
void refresh(bool use)
{
int w = width();
int h = height();
/*
if (c_useRetina)
{
w /= c_retinaScale;
h /= c_retinaScale;
}
*/
c_useRetina = use;
updateLayout();
//repaint();
setNewSize(w+1, h+0);
//setNewSize(width()-1, height());
}
};
BEGIN_NAMESPACE
extern bool drawAAText;
//extern bool drawFill;
//extern bool drawOutline;
extern bool drawWholeOutline;
//extern bool drawControlPoints;
extern std::string fontOpt;
//extern int fixedFontSize;
END_NAMESPACE
class FontTestWindow : public Widget // Window
{
Property<bool> m_useRetina;
Property<bool> m_drawFill;
Property<bool> m_drawControlPoints;
Property<bool> m_drawDebugOutline;
Property<bool> m_drawWholeOutline;
Property<bool> m_drawAA;
Property<bool> m_fontOpt;
Property<int> m_sliderValue;
public:
FontTestWindow(Widget* a_parent, const char* a_name)
: Widget(a_parent, a_name)
{
//Widget* vbox = this;//new VBox(this);
Widget* vbox = new VBox(this);
new CheckBox(vbox, m_useRetina, "retina");
new CheckBox(vbox, m_drawFill, "fill");
new CheckBox(vbox, m_drawWholeOutline, "outline");
new CheckBox(vbox, m_drawDebugOutline, "debug-outline");
new CheckBox(vbox, m_drawControlPoints, "control points");
new CheckBox(vbox, m_drawAA, "anti-alias");
new CheckBox(vbox, m_fontOpt, "font");
new Slider(vbox, m_sliderValue);
m_sliderValue = 40;
m_drawFill = true;
connect(m_drawFill.valueChanged, this, &FontTestWindow::redraw);
connect(m_useRetina.valueChanged, this, &FontTestWindow::refresh);
}
void refresh(bool use)
{
int w = width();
int h = height();
if (c_useRetina)
{
w /= c_retinaScale;
h /= c_retinaScale;
}
c_useRetina = use;
//updateLayout();
//repaint();
setNewSize(w+8, h+0);
//setNewSize(width()-1, height());
}
void redraw(bool)
{
repaint();
}
void paintEvent(PaintEvent& a_event)
{
Painter p(this);
p.setFontSize(m_sliderValue.value() * 3);
p.setPen(0x000000);
//NAMESPACE::fixedFontSize = 100;
NAMESPACE::drawAAText = m_drawAA.value();
//NAMESPACE::drawFill = m_drawFill.value();
//NAMESPACE::drawOutline = m_drawDebugOutline.value();
NAMESPACE::drawWholeOutline = m_drawWholeOutline.value();
//NAMESPACE::drawControlPoints = m_drawControlPoints.value();
NAMESPACE::fontOpt = m_fontOpt.value() ? "Arial" : "Tahoma";
NAMESPACE::fontOpt = m_fontOpt.value() ? "Verdana" : "Tahoma";
//NAMESPACE::fontOpt = "Andale Mono";
//p.drawText(120, 150, "$@filHeoWrld");
p.drawText(120, 150, "fill Hello World");
p.drawText(120, 300, "$@AGQRXY");
//NAMESPACE::fixedFontSize = m_sliderValue.value();
//printf("font size: %i\n", NAMESPACE::fixedFontSize);
NAMESPACE::drawAAText = true;
//NAMESPACE::drawFill = true;
//NAMESPACE::drawOutline = false;
NAMESPACE::drawWholeOutline = false;
//NAMESPACE::drawControlPoints = false;
//NAMESPACE::fontOpt = "Arial";
NAMESPACE::fontOpt = "Apple Chancery";
NAMESPACE::fontOpt = "Andale Mono";
NAMESPACE::fontOpt = "Nadeem";
NAMESPACE::fontOpt = "Verdana";
NAMESPACE::fontOpt = "Tahoma";
NAMESPACE::fontOpt = "Trebuchet MS";
//NAMESPACE::fontOpt = "Segoe UI";
}
};
std::string getMethodName(const std::string& prettyFunction)
{
size_t end = prettyFunction.find("(") - 1;
size_t begin = prettyFunction.substr(0, end).rfind(" ") + 1;
return prettyFunction.substr(begin, end - begin + 1);
}
// Some crude introspection of current class and function
#define DEBUG_FUNC \
/*fprintf(stderr, "Class: -%s- ", typeid(*this).name()); */ \
fprintf(stderr, "Function: -%s-\n", getMethodName(__PRETTY_FUNCTION__).c_str());
class LineTestWindow : public Widget
{
public:
LineTestWindow(Widget* a_parent, const char* a_name)
: Widget(a_parent, a_name)
{
DEBUG_FUNC
}
void paintEvent(PaintEvent& a_event)
{
DEBUG_FUNC
Painter p(this);
p.setPen(0x000000);
//p.setPen(0xFFC0C0C0);
int w = 400;//width();
int h = 500;//height();
int cx = w / 2;
int cy = h / 2;
int radius = ((w > h) ? w : h) * 2;
const int lines = 100;
for (int i = 0; i < lines; i++)
{
int x2 = cx + radius * cos((2.0 * M_PI * i) / lines);
int y2 = cy + radius * sin((2.0 * M_PI * i) / lines);
p.drawLine(cx, cy, x2, y2);
//p.drawLine(x2, y2, cx, cy);
}
}
};
// Different ways to express lambdas
#define L1(var, ret, args, body) struct { ret operator() args const body } var // Pre C++11 compatible
#define L2(var, ret, args, body) std::function<ret args> var = [] args body // Explicit C++11 way
#define L3(var, ret, args, body) auto var = [] args body // Implicit C++11
// This is building up towards a generic RPC kind of mechanism
// Main problem will be pointers in argument lists - you can send the value of a pointer
// via RPC, but when the remote side de-references it, it will be meaningless. Perhaps
// need to prevent them. But also means can't pass in structs which contain them too.
// So a general struct which contains pointers in it can't be passed to the RPC function
// even if those pointers aren't used. Perhaps needs to just pass what is marked as
// reflectable through the interface.
// With the Lua bindings I did before, it is similar to RPC in that it built up an
// argument list from a function signature and captured the values to pass to something.
// Probably should refer to what I did there while doing this.
enum BasicValueType
{
Null,
Void,
Bool,
Int8,
UInt8,
Int16,
UInt16,
Int32,
UInt32,
Int64,
UInt64,
Float32,
Float64,
Pointer
};
enum ValueType
{
Basic,
Complex
};
struct BasicValue
{
BasicValueType m_type;
union {
int64_t m_null;
int64_t m_void;
bool m_bool;
int8_t m_int8;
uint8_t m_uint8;
int16_t m_int16;
uint16_t m_uint16;
int32_t m_int32;
uint32_t m_uint32;
int64_t m_int64;
uint64_t m_uint64;
float m_float32;
double m_float64;
void* m_pointer;
} m_value;
};
struct ComplexValue
{
struct Value {
ValueType m_type;
union {
BasicValue m_basic;
//ComplexValue& m_complex;
} m_value;
};
std::vector<Value> m_members;
};
struct CallableInterface : public InterfaceBase
{
virtual ComplexValue operator() (const ComplexValue& args) = 0;
};
/*
template <typename Sig>
struct L
{
ret operator() args const
{
std::function<void(int)> f = p[](int) { };
}
};
*/
void lambdaTests()
{
L1(f1, void, (int a, int b), { printf("f1 args: %i %i\n", a, b); });
L2(f2, void, (int a, int b), { printf("f2 args: %i %i\n", a, b); });
L3(f3, void, (int a, int b), { printf("f3 args: %i %i\n", a, b); });
auto f4 = [] (int a, int b) { printf("f4 args: %i %i\n", a, b); }; // Implicit vs Macros for comparison (2 characters less)
// If macro name was simply 'L' then only 1 less character to type using the implicit C++11 way vs using the macro which
// could be made to work with pre C++11 compilers
f1(1, 2);
f2(3, 4);
f3(5, 6);
f4(7, 8);
}
void nullableTests()
{
struct NullTest { int x; };
Nullable2<NullTest> nullTest;
auto n1 = nullTest;
n1 = n1;
// int x = n1.value().x; // Is meant to assert or static_assert
NullTest newNullTest = NullTest{ 1 };
// Unfortunately need to assign it to a new variable - kind of defeats the point
auto n2 = nullTest = newNullTest;
n2 = nullTest = newNullTest;
int y = n2.value().x;
// then want to call something:
// foo(n1); // and the passed in argument will be of type Nullable<T,true> or Nullable<T,false>
int x = y; y = x;
}
extern void fontEditTest();
extern void formFactorTest();
int main(int argc, char* argv[])
{
// fontEditTest();
formFactorTest();
nullableTests();
lambdaTests();
runUnitTests(0);
Application app;
Reflection::registerObjectTypes();
Object::dumpReflectionInformation();
Object object;
VBox vbox(0);
Object& obj = object;
Object& vb = vbox;
printf("Object type id: %i\n", Object::staticTypeId());
printf("Widget type id: %i\n", Widget::staticTypeId());
printf("VBox type id: %i\n", VBox::staticTypeId());
printf("HBox type id: %i\n", HBox::staticTypeId());
printf("--------------------------\n");
printf("Object inherits Object: %i, Widget: %i, HBox: %i VBox: %i\n",
obj.inherits<Object>(), obj.inherits<Widget>(), obj.inherits<HBox>(), obj.inherits<VBox>());
printf("VBox inherits Object: %i, Widget: %i, HBox: %i VBox: %i\n",
vb.inherits<Object>(), vb.inherits<Widget>(), vb.inherits<HBox>(), vb.inherits<VBox>());
printf("Object is Object: %i, Widget: %i, HBox: %i VBox: %i\n",
obj.is<Object>(), obj.is<Widget>(), obj.is<HBox>(), obj.is<VBox>());
printf("VBox is Object: %i, Widget: %i, HBox: %i VBox: %i\n",
vb.is<Object>(), vb.is<Widget>(), vb.is<HBox>(), vb.is<VBox>());
printf("--------------------------\n");
printf("Object inherits Object: %i, Widget: %i, HBox: %i VBox: %i\n",
Object::staticInherits<Object>(), Object::staticInherits<Widget>(), Object::staticInherits<HBox>(), Object::staticInherits<VBox>());
printf("VBox inherits Object: %i, Widget: %i, HBox: %i VBox: %i\n",
VBox::staticInherits<Object>(), VBox::staticInherits<Widget>(), VBox::staticInherits<HBox>(), VBox::staticInherits<VBox>());
printf("Object is Object: %i, Widget: %i, HBox: %i VBox: %i\n",
Object::staticIs<Object>(), Object::staticIs<Widget>(), Object::staticIs<HBox>(), Object::staticIs<VBox>());
printf("VBox is Object: %i, Widget: %i, HBox: %i VBox: %i\n",
VBox::staticIs<Object>(), VBox::staticIs<Widget>(), VBox::staticIs<HBox>(), VBox::staticIs<VBox>());
printf("--------------------------\n");
printf("Object inherits Object: %i, Widget: %i, HBox: %i VBox: %i\n",
object.inherits<Object>(), object.inherits<Widget>(), object.inherits<HBox>(), object.inherits<VBox>());
printf("VBox inherits Object: %i, Widget: %i, HBox: %i VBox: %i\n",
vbox.inherits<Object>(), vbox.inherits<Widget>(), vbox.inherits<HBox>(), vbox.inherits<VBox>());
printf("Object is Object: %i, Widget: %i, HBox: %i VBox: %i\n",
object.is<Object>(), object.is<Widget>(), object.is<HBox>(), object.is<VBox>());
printf("VBox is Object: %i, Widget: %i, HBox: %i VBox: %i\n",
vbox.is<Object>(), vbox.is<Widget>(), vbox.is<HBox>(), vbox.is<VBox>());
printf("--------------------------\n");
/*
GenericFactory<ReflectionDataFactory> reflectionFactory;
for (ReflectionDataFactory f : reflectionFactory)
{
const ReflectionDataInterface* i = f();
if (i) {
printf("Type: %i Name: %s Size: %i\n", i->GetTypeId(), i->GetType().c_str(), i->GetSize());
} else {
printf("Invalid reflection factory\n");
}
}
*/
printf("sizeof(Object): %lu sizeof(VBox): %lu\n", sizeof(Object), sizeof(VBox));
#if 1
HBox b(0);
Widget* p = &b;
TestWindow testWin(p, "Test Window");
Property<int> scrollValue;
ScrollBar sb(p, scrollValue);
b.setNewSize(800, 600);
#else
//FontTestWindow testWin(0, "Test Window");
//testWin.setNewSize(1200, 600);
LineTestWindow testWin(0, "Test Window");
testWin.setNewSize(400, 500);
#endif
app.exec();
}
/*
#include <link.h>
#include <string>
#include <vector>
using namespace std;
int retrieve_symbolnames(struct dl_phdr_info* info, size_t info_size, void* symbol_names_vector)
{
ElfW(Dyn*) dyn;
ElfW(Sym*) sym;
ElfW(Word*) hash;
char* strtab = 0;
char* sym_name = 0;
ElfW(Word) sym_cnt = 0;
vector<string>* symbol_names = reinterpret_cast<vector<string>*>(symbol_names_vector);
for (size_t header_index = 0; header_index < info->dlpi_phnum; header_index++)
{
if (info->dlpi_phdr[header_index].p_type == PT_DYNAMIC)
{
dyn = (ElfW(Dyn)*)(info->dlpi_addr + info->dlpi_phdr[header_index].p_vaddr);
while(dyn->d_tag != DT_NULL)
{
if (dyn->d_tag == DT_HASH)
{
hash = (ElfW(Word*))dyn->d_un.d_ptr;
sym_cnt = hash[1];
}
else if (dyn->d_tag == DT_STRTAB)
{
strtab = (char*)dyn->d_un.d_ptr;
}
else if (dyn->d_tag == DT_SYMTAB)
{
sym = (ElfW(Sym*))dyn->d_un.d_ptr;
for (ElfW(Word) sym_index = 0; sym_index < sym_cnt; sym_index++)
{
sym_name = &strtab[sym[sym_index].st_name];
symbol_names->push_back(string(sym_name));
}
}
dyn++;
}
}
}
return 1;
}
int main()
{
vector<string> symbolNames;
dl_iterate_phdr(retrieve_symbolnames, &symbolNames);
return 0;
}
*/