#include "Application.h"
#include "Window.h"
#include "Painter.h"
#include "SignalSlot.h"
#include "Widget.h"
#include "CommonWidgets.h"
#include <iostream>
#include <iomanip>
#include <climits>
#include <fstream>
#include <cctype>
#include <cstdarg>
USING_NAMESPACE
void drawGrid(Painter& p, const int x1, const int y1, const int gridSize, const int gridDim, const uint32_t* buf)
{
if (buf)
for (int i = 0; i < gridDim; i++)
for (int j = 0; j < gridDim; j++)
if (buf[j*gridDim+i])
{
p.setBrush(~buf[j*gridDim+i] | 0xFF000000);
p.drawRectangle(x1 + i * gridSize, y1 + j * gridSize, gridSize, gridSize);
}
for (int i = 0; i <= gridDim; i++)
p.drawLine(x1 + i * gridSize, y1, x1 + i * gridSize, y1 + gridSize * gridDim);
for (int i = 0; i <= gridDim; i++)
p.drawLine(x1, y1 + i * gridSize, x1 + gridSize * gridDim, y1 + gridSize * i);
}
// Internal font rendering APIs
//extern "C"
BEGIN_NAMESPACE
extern bool drawAAText;
extern bool g_enableKerning;
END_NAMESPACE
class NamedCombo : public VBox
{
Property<String> m_label;
public:
NamedCombo(Widget* parent, const char* name)
: VBox(parent)
{
new Label(this, m_label);
m_label = name;
m_combo = new ComboBox(this, m_value);
}
void addItem(const char* name)
{
m_combo->addItem(name);
}
ComboBox* m_combo;
Property<int> m_value;
};
template <typename T>
class PropertyDelegate : public Property<T>
{
Property<T> m_value;
T& m_backingValue;
public:
PropertyDelegate(T& a_backingValue)
: m_backingValue(a_backingValue)
{
m_value = a_backingValue;
connect(m_value.valueChanged, this, &PropertyDelegate<T>::replicate);
}
void replicate(T newValue)
{
m_backingValue = newValue;
}
};
template <class T>
class PropertyWrapper : public AbstractProperty<T>
{
public:
//PropertyWrapper() {}
PropertyWrapper(T& val) : m_value(val) {}
PropertyWrapper(const PropertyWrapper<T>& other) : m_value(other.m_value) {}
Property<T>& operator=(T const & a_newValue)
{
AbstractProperty<T>::setValue(a_newValue);
return *this;
}
protected:
T const & get() const { return m_value; }
void set(T a_newValue) { m_value = a_newValue; }
private:
T& m_value;
};
class TestWindow : public Widget
{
//Property<bool> m_drawAA;
PropertyWrapper<bool> m_drawAA;
PropertyWrapper<bool> m_enableKerning;
Property<bool> m_drawFill;
Property<bool> m_drawDebugOutline;
Property<int> m_sliderValue;
Property<String> m_testText;
NamedCombo* m_drawMode;
public:
TestWindow(Widget* a_parent, const char* a_name)
: Widget(a_parent, a_name)
, m_drawAA(drawAAText)
, m_enableKerning(g_enableKerning)
{
Widget* vbox = new VBox(this);
new CheckBox(vbox, m_drawFill, "fill");
new CheckBox(vbox, m_drawDebugOutline, "debug-outline");
new CheckBox(vbox, m_drawAA, "Draw anti-alias");
new CheckBox(vbox, m_enableKerning, "Enable kerning");
m_drawMode = new NamedCombo(vbox, "Draw mode:");
m_drawMode->addItem("Filled");
m_drawMode->addItem("Outline");
m_drawMode->addItem("OutlineBlend");
m_drawMode->addItem("Stage0");
m_drawMode->addItem("Stage1");
m_drawMode->addItem("Stage2");
m_drawMode->addItem("Stage3");
m_drawMode->addItem("Stage4");
m_drawMode->addItem("Stage5");
NamedCombo *fontFamily = new NamedCombo(vbox, "Font family:");
fontFamily->addItem("Filled");
fontFamily->addItem("Outline");
fontFamily->addItem("OutlineBlend");
fontFamily->addItem("Stage0");
fontFamily->addItem("Stage1");
fontFamily->addItem("Stage2");
fontFamily->addItem("Stage3");
new LineEdit(vbox, m_testText);
new Slider(vbox, m_sliderValue);
m_sliderValue = 32000;
connect(m_drawAA.valueChanged, this, &TestWindow::toggleAA);
connect(m_enableKerning.valueChanged, this, &TestWindow::redraw);
connect(m_drawFill.valueChanged, this, &TestWindow::redraw);
connect(m_drawMode->m_value.valueChanged, this, &TestWindow::redraw);
// m_drawAA = drawAAText;
}
void redraw(bool)
{
repaint();
}
void toggleAA(bool a_on)
{
// drawAAText = a_on;
repaint();
}
void paintEvent(PaintEvent& a_event)
{
const int w = 80;
const int h = 80;
uint32_t *buf = new uint32_t[w*h];
memset(buf, 0, w*h*sizeof(uint32_t));
Pixmap pix((unsigned char*)buf, w, h, sizeof(uint32_t));
Painter p1(&pix);
//p1.setFontFamily("Segoe UI");// "Arial Unicode");
int fontSize = m_sliderValue() * 24 / 32000;
//p1.setPen(0x000000);
p1.setFontSize(fontSize);
int yoff = 20;//fontSize / 2;
p1.drawText(0, yoff/2, m_testText(), m_drawMode->m_value());
const int x1 = 150;
const int y1 = 150;
const int gridSize = 5;
const int gridDim = w;
int scale = (fontSize) ? 1024 / (2 * fontSize) : 1;
Painter p(this);
FontMetrics fm = p.fontMetrics();
GlyphMetrics gm = p.glyphMetrics(m_testText()[0]);
int boundsY1 = fontSize * 2 + yoff + 9 - gm.m_minY / scale;
int boundsY2 = fontSize * 2 + yoff + 9 - gm.m_maxY / scale;
int boundsX1 = (gm.m_leftSideBearing + gm.m_minX) / scale;
int boundsX2 = (gm.m_leftSideBearing + gm.m_maxX) / scale;
//printf("ascent: %i\n", fm.m_ascent);
//printf("descent: %i\n", fm.m_descent);
//printf("lineGap: %i\n", fm.m_lineGap);
// draw font baseline
p.setPen(0xF01010);
int baseLine = yoff + 9 + fontSize * 2;
p.drawLine(x1, y1+2+gridSize*baseLine, x1+gridSize*w-1, y1+2+gridSize*baseLine);
p.setPen(0x10F010);
int descentLine = baseLine - (fm.m_descent / scale);
p.drawLine(x1, y1+2+gridSize*descentLine, x1+gridSize*w-1, y1+2+gridSize*descentLine);
int bottomLine = descentLine + (fm.m_lineGap / scale);
p.drawLine(x1, y1+2+gridSize*bottomLine, x1+gridSize*w-1, y1+2+gridSize*bottomLine);
int ascentLine = baseLine - (fm.m_ascent / scale);
p.drawLine(x1, y1+2+gridSize*ascentLine, x1+gridSize*w-1, y1+2+gridSize*ascentLine);
p.setPen(0x1010F0);
int xHeightLine = baseLine - (fm.m_xHeight / scale);
p.drawLine(x1, y1+2+gridSize*xHeightLine, x1+gridSize*w-1, y1+2+gridSize*xHeightLine);
int capHeightLine = baseLine - (fm.m_capHeight / scale);
p.drawLine(x1, y1+2+gridSize*capHeightLine, x1+gridSize*w-1, y1+2+gridSize*capHeightLine);
p.setPen(0x000000);
// p.drawText(0, 0, "Blah");
// p.drawLine(0, 0, 1000, 1000);
drawGrid(p, x1, y1, gridSize, gridDim, buf);
p.setPen(0xFF00FF);
p.drawLine(x1 + boundsX1*gridSize+2, y1+2+boundsY1*gridSize, x1 + boundsX1*gridSize+2, y1+2+boundsY2*gridSize);
p.drawLine(x1 + boundsX2*gridSize+2, y1+2+boundsY1*gridSize, x1 + boundsX2*gridSize+2, y1+2+boundsY2*gridSize);
p.drawLine(x1 + boundsX1*gridSize, y1+2+boundsY1*gridSize, x1 + boundsX2*gridSize, y1+2+boundsY1*gridSize);
p.drawLine(x1 + boundsX1*gridSize, y1+2+boundsY2*gridSize, x1 + boundsX2*gridSize, y1+2+boundsY2*gridSize);
delete[] buf;
}
};
int main(int argc, char* argv[])
{
Application app;
TestWindow testWin(0, "Test Window");
testWin.setNewSize(800, 600);
return app.exec();
}