Newer
Older
WickedDocs / main.cpp
// MakePDF.cpp : Defines the entry point for the console application.
//

#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include "DocVisitor.h"
#include "DocTemplate.h"
#include "DocOutput.h"

//#include "document.h"
#include "html.h"
#include "tinyxml.h"
#include <Windows.h>


#define DEF_IUNIT        1024
#define DEF_OUNIT        64
#define DEF_MAX_NESTING  16


extern void runTests();


struct Context
{
	const char* title;
	const char* inFileName;
	const char* outFileName_PDF;
	const char* outFileName_HTML;
	DocOutputDevice* doc;
	hoedown_buffer *inputBuffer;
	hoedown_buffer *outputBuffer;
};


static void RemoveFile(const char* fileName)
{
	FILE* tmpF = 0;
	bool first = true;
	do
	{
		fopen_s(&tmpF, fileName, "rb");
		if (tmpF)
		{
			fclose(tmpF);
			_unlink(fileName);
			::Sleep(100);
			if (first)
				printf("waiting for output file to be removed.");
			else
				printf(".");
			first = false;
			fflush(stdout);
		}
	} while (tmpF != 0);
}


hoedown_buffer *ReadInWholeFile(const char* inputFileName)
{
	// Read in the markdown file
	FILE* f = 0;
	fopen_s(&f, inputFileName, "rt"); // text or binary? Can it be utf8, and if so, do I need to read in binary mode?
	if (!f)
		return 0;
	/*
	fseek(f, 0L, SEEK_END);
	long fileSize = ftell(f);
	fseek(f, 0L, SEEK_SET);
	uint8_t* inputBuffer = (uint8_t*)malloc(fileSize);
	size_t inputBufferSize = fread(inputBuffer, 1, fileSize, f);
	*/
	hoedown_buffer *ib = hoedown_buffer_new(DEF_IUNIT);
	if (hoedown_buffer_putf(ib, f))
		fprintf(stderr, "I/O errors found while reading input.\n");

	fclose(f);
	return ib;
}


hoedown_buffer *ConvertMarkdownToHTML(uint8_t* inputBuffer, size_t inputBufferSize)
{
	hoedown_html_flags flags = (hoedown_html_flags)(HOEDOWN_HTML_ESCAPE | HOEDOWN_HTML_HARD_WRAP | HOEDOWN_HTML_USE_XHTML);
	hoedown_renderer *renderer = hoedown_html_renderer_new(flags, 0);
	hoedown_buffer *ob = hoedown_buffer_new(DEF_OUNIT);
	hoedown_document *document = hoedown_document_new(renderer, HOEDOWN_EXT_SPACE_HEADERS, DEF_MAX_NESTING);
	hoedown_document_render(document, ob, inputBuffer, inputBufferSize);
	hoedown_document_free(document);
	hoedown_html_renderer_free(renderer);
	return ob;
}


void ConvertHTMLToPDF(uint8_t* inputBuffer, DocOutputDevice* outputDoc)
{
	// xml parse
	DocStyle style;
	DocTemplate templ;
	TiXmlDocument parser;

	templ.ReadTemplateFile("test.tmpl");
	parser.Parse((char*)inputBuffer);
	DocVisitor visitor(outputDoc, &style, &templ);
	parser.Accept(&visitor);
}


void SaveHTML(const char* fileName, const uint8_t* data, size_t dataSize)
{
	RemoveFile(fileName);
	FILE* f = 0;
	fopen_s(&f, fileName, "wb");
	if (!f)
		return;
	const char *CSSText = "<!DOCTYPE html><html><head><title>test</title><link rel=\"stylesheet\" type=\"text/css\" href=\"base.css\"></head><body>";
	fwrite(CSSText, 1, strlen(CSSText), f);
	fwrite(data, 1, dataSize, f);
	fclose(f);
}


int ProcessConversionContext(Context* context)
{
	context->inputBuffer = ReadInWholeFile(context->inFileName);
	if (!context->inputBuffer)
		return -1;
	context->outputBuffer = ConvertMarkdownToHTML(context->inputBuffer->data, context->inputBuffer->size);
	//free(inputBuffer);
	hoedown_buffer_free(context->inputBuffer);
	ConvertHTMLToPDF(context->outputBuffer->data, context->doc);
	SaveHTML(context->outFileName_HTML, context->outputBuffer->data, context->outputBuffer->size);
	hoedown_buffer_free(context->outputBuffer);
	RemoveFile(context->outFileName_PDF);
	context->doc->finalize(context->outFileName_PDF);
	return 0;
}


#ifdef GUI_APP

#include "ui_About.h"
#include "ui_ExtensibleObjectModelUI.h"
#include "EventLog.h"
#include "GenericTableUI.h"


class UiLogger : public Logger
{
public:
	EventLog* m_log;
	void logMessage(yqLogLevel a_logLevel, const char *a_location, const char *a_message)
	{
		m_log->LogMessage(a_location, a_message);
	}
};


struct UiContext
{
	Ui_MainWindow appWindow;
	QMainWindow mainWindow;

	Ui_About about;
	QDialog aboutDialog;

	EventLog log;
	UiLogger logger;

	void setupUi()
	{
		logger.m_log = &log;
		g_currentModule.m_messageLogger = &logger;

		appWindow.setupUi(&mainWindow);

		about.setupUi(&aboutDialog);
		aboutDialog.setFixedSize(430, 300);

		QObject::connect(appWindow.actionAbout, SIGNAL(triggered(bool)), &aboutDialog, SLOT(exec()));

		mainWindow.show();
	}
};

#endif


#include <QPainter>


// Values from this come up the same as doing:   QColor::fromHsvF(hue, sat, 1.0).rgba()
uint32_t rgbFromHsvF(qreal h1, qreal s, qreal v, qreal a)
{
	uint16_t hue = h1 == qreal(-1.0) ? USHRT_MAX : qRound(h1 * 36000);
	h1 = hue == 36000 ? 0 : hue / qreal(6000.);
	s = uint16_t(qRound(s * USHRT_MAX)) / qreal(USHRT_MAX);
	v = uint16_t(qRound(v * USHRT_MAX)) / qreal(USHRT_MAX);
	const qreal h = h1;
	const int i = int(h);
	const qreal f = h - i;
	const qreal v2 = v * USHRT_MAX;
	uint8_t components[4] = {
		qRound(v2 * (qreal(1.0) - s)) >> 8,
		qRound(v2) >> 8,
		qRound(v2 * (qreal(1.0) - (s * f))) >> 8,
		qRound(v2 * (qreal(1.0) - (s * (qreal(1.0) - f)))) >> 8
	};
	const int indexTable[10] = { 1, 2, 0, 0, 3, 1, 1, 2, 0, 0 };
	return 0xff000000 | (components[indexTable[i]] << 16) | (components[indexTable[i + 4]] << 8) | components[indexTable[i + 2]];
}

bool m_wheelCached = false;
QImage colorWheelCache;

void makeColorWheel(int siz)
{
	const float twoPi = 2 * 3.142;
	const int cen = (siz / 2);
	const int rad = cen - 20;
	const int iter = siz * 10;

	QImage img(siz, siz, QImage::Format_ARGB32);
	img.fill(0xFF444444);
	uint32_t* bits = (uint32_t*)img.bits();
	int pitch = img.bytesPerLine() / sizeof(uint32_t);
	double dSat = 1.0 / rad;
	for (int i = 0; i < iter; i++)
	{
		double hue = double(i) / iter;
		double c = ::cos(hue * twoPi);
		double s = ::sin(hue * twoPi);
		double x = cen + rad * c;
		double y = cen + rad * s;
		double sat = 1.0;
		for (int w = rad-30; w < rad; w++)
		{
			bits[int(y)*pitch + int(x)] = rgbFromHsvF(hue, sat, 1.0, 1.0);
			x -= c;
			y -= s;
			//sat -= dSat;
		}
	}
	// Smoothing technique where we scale it up a fraction and then back down again
	img = img.scaled(img.size() + QSize(6, 6), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
	colorWheelCache = img.scaled(img.size() - QSize(6, 6), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
	m_wheelCached = true;
}


const int modeHands[8] = { 1, 2, 3, 4, 4, 4, 4, 4 };
const int modeHandAngles[6][4] = { { 0 }, { 0, 180 }, { 0, 180 - 30, 180 + 30 },
	{ 0, 360 - 30, 30, 180 },  /* { 0, 180 - 30, 180, 180 + 30 }, */ { 360 - 45, 45, 180 - 45, 180 + 45 } };
const char* modeNames[6] = {
	"Monochromatic", "Complementary", "Analogous", "Accented Analogous", "Tetradic"
};


struct ColorScheme
{
	//   mode (3-bits), primary hue (8-bits), angle / hue-delta (8-bits)
	//   saturation (8-bits), stretch (5-bits)
	unsigned    m_primaryHue : 8;
	unsigned    m_secondaryHueDelta : 8;
	unsigned    m_saturation : 8;
	unsigned    m_stretch : 5;
	unsigned    m_mode : 3;

	const char* modeName()
	{
		if (m_mode == 2 && m_secondaryHueDelta > 64 && m_secondaryHueDelta < (255 - 64))
			return "Triadic";
		if (m_mode == 3 && m_secondaryHueDelta > 64 && m_secondaryHueDelta < (255-64))
			return "Split-Complementary";
		return modeNames[m_mode];
	}
	int hueCount()
	{
		return modeHands[m_mode];
	}
	void setHue(int a_index, float a_val)
	{
		if (a_index == 0)
			m_primaryHue = unsigned(a_val * 255.0) & 0xff;
		else if (a_index == 1 && m_mode != 2)
			m_primaryHue = unsigned((a_val - 0.5) * 255.0) & 0xff;
		else if ((a_index == 2 && m_mode != 2) || (m_mode == 2 && a_index == 1))
			m_secondaryHueDelta = (unsigned(a_val * 255.0) - m_primaryHue) & 0xff;
		else if (m_mode == 3 || (m_mode == 2 && a_index == 2))
			m_secondaryHueDelta = (m_primaryHue - unsigned(a_val * 255.0)) & 0xff;
		else
			m_secondaryHueDelta = (unsigned((a_val - 0.5) * 255.0) - m_primaryHue) & 0xff;
	}
	float denormalizedHue(int a_index)
	{
		if (a_index == 0)
			return float(m_primaryHue) / 255.0;
		if (a_index == 1 && m_mode != 2)
			return 0.5 + float(m_primaryHue) / 255.0;
		if ((a_index == 2 && m_mode != 2) || (m_mode == 2 && a_index == 1))
			return float((int)m_primaryHue + m_secondaryHueDelta) / 255.0;
		if (m_mode == 3 || (m_mode == 2 && a_index == 2))
			return float((int)m_primaryHue - (int)m_secondaryHueDelta) / 255.0;
		return 0.5 + float((int)m_primaryHue + (int)m_secondaryHueDelta) / 255.0;
	}
	float hue(int a_index)
	{
		float h = denormalizedHue(a_index);
		while (h < 0.0) h += 1.0;
		while (h > 1.0) h -= 1.0;
		return h;
	}
};


static_assert(sizeof(ColorScheme) == 4, "bad size");


class SchemeSelection : public QWidget
{
public:
	const int titleHeight = 20;
	const int modes = 5;

	ColorScheme* scheme;
	SchemeSelection(QWidget* a_parent, ColorScheme* a_scheme) : QWidget(a_parent), scheme(a_scheme) {}

	void mousePressEvent(QMouseEvent* me)
	{
		for (int i = 0; i < modes; i++)
		{
			QRect r(16, titleHeight + 10 + i * 55, 50, 50);
			if (r.contains(me->pos()))
			{
				scheme->m_mode = i;
				parentWidget()->update();
				return;
			}
		}
	}

	void paintEvent(QPaintEvent*)
	{
		QPainter p(this);
		p.fillRect(0, 0, width(), titleHeight, QColor(0x444444));

		QFont f("Segoe UI", 13, 200);
		p.setFont(f);
		p.setPen(Qt::white);
		p.drawText(3 + 0, 15, "Scheme");

		QPixmap pix1("../color-dial-deselect.png");
		QPixmap pix2("../color-dial-select.png");
		QPixmap pixHand1("../color-pointer-deselect.png");
		QPixmap pixHand2("../color-pointer-select.png");
		p.fillRect(0, titleHeight, width(), height() - titleHeight, QColor(0x333333));
		for (int i = 0; i < modes; i++)
		{
			p.drawPixmap(16, titleHeight + 10 + i * 55, (i == scheme->m_mode) ? pix2 : pix1);
			QPixmap hands = (i == scheme->m_mode) ? pixHand2 : pixHand1;

			for (int j = 0; j < modeHands[i]; j++)
			{
				QMatrix m;
				m = m.scale(0.5, 0.5);
				m = m.rotate(modeHandAngles[i][j]);
				QPixmap newPix = hands.transformed(m, Qt::SmoothTransformation);
				QSize s = newPix.size() - hands.size() / 2;
				s = s / 2;
				p.drawPixmap(16 - s.width(), titleHeight + 10 - s.height() + i * 55, newPix);
				//pix.transformed(m, Qt::SmoothTransformation);
			}
		}
	}
};



#include "c:\Users\John\Desktop\Euclideon\model-iterator.cpp"



// lineedit to name the scheme
// okay/cancel buttons
// styled titlebar

class ColorPicker : public QWidget
{
public:
	const float twoPi = 2 * acos(-1);
	const int siz = 250;
	const int cen = (siz / 2);
	const int rad = (siz / 2) - 20;
	const int iter = siz * 10;
	const int dotSiz = 18;// 16;
	const int dotAlpha = 96;// 64;

	const int titleHeight = 20;

	const int schemeWidth = 80;
	const int wheelWidth = siz * 2;// 600;

	const int paletteWidth = 150;
	const int paletteHeight = 350;

	const int xOff = schemeWidth;
	const int yOff = titleHeight;
	//const int modes = 6;

	int m_hueMovingIdx;

	
	ColorScheme palette;
	SchemeSelection scheme;


	// Properties of a scheme:
	//   mode (3-bits), primary hue (8-bits), angle / hue-delta (8-bits)
	//   saturation (8-bits), stretch (5-bits)

	ColorPicker(QWidget* parent = 0) : QWidget(parent), scheme(this, &palette)
	{
		palette.m_mode = 0;
		palette.m_primaryHue = 0;
		palette.m_secondaryHueDelta = 10;
		palette.m_saturation = 0;
		palette.m_stretch = 0;
		scheme.setGeometry(0, 0, schemeWidth, paletteHeight + titleHeight);

		setFixedSize(schemeWidth + wheelWidth + paletteWidth, paletteHeight + titleHeight);
		m_hueMovingIdx = -1;
	}
	~ColorPicker()
	{
	}

	void mousePressEvent(QMouseEvent* me)
	{
		for (int h = palette.hueCount() - 1; h >= 0; h--)
		{
			int x = xOff + cen + (rad - dotSiz - 5) * ::cos(palette.hue(h) * twoPi);
			int y = yOff + cen + (rad - dotSiz - 5) * ::sin(palette.hue(h) * twoPi);
			QRect r(x - dotSiz / 2, y - dotSiz / 2, x + dotSiz / 2, y + dotSiz / 2);
			if (r.contains(me->pos()))
			{
				m_hueMovingIdx = h;
				return;
			}
		}
	}

	void mouseReleaseEvent(QMouseEvent*)
	{
		m_hueMovingIdx = -1;
	}

	void mouseMoveEvent(QMouseEvent* me)
	{
		if (m_hueMovingIdx != -1)
		{
			int x = me->pos().x() - (cen + xOff);
			int y = me->pos().y() - (cen + yOff);
			palette.setHue(m_hueMovingIdx, ::atan2(y, x) / twoPi);
update();
		}
	}

	void paintEvent(QPaintEvent*)
	{
		QPainter p(this);

		p.fillRect(0, 0, width(), titleHeight, QColor(0x444444));
		p.fillRect(schemeWidth, 0, wheelWidth, titleHeight, QColor(0x333333));

		QFont f("Segoe UI", 13, 200);
		p.setFont(f);
		p.setPen(Qt::white);
		//p.drawText(3 + schemeWidth, 15, "Color Wheel");
		p.drawText(3 + schemeWidth + wheelWidth, 15, "Palette Preview");


		if (!m_wheelCached)
			makeColorWheel(siz);
		p.drawImage(xOff, yOff, colorWheelCache);
		//p.drawText(3 + schemeWidth, titleHeight + 15, QString(modeNames[m_mode]) + " Colors");
		p.drawText(3 + schemeWidth, 15, QString(palette.modeName()) + " Colors");

		for (int h = 0; h < palette.hueCount(); h++)
		{
			int x = xOff + cen + (rad /*- dotSiz */ - 15 - 5) * ::cos(palette.hue(h) * twoPi);
			int y = yOff + cen + (rad /*- dotSiz */ - 15 - 5) * ::sin(palette.hue(h) * twoPi);
			if (h == 0) {
				p.setPen(QPen(QColor(255, 255, 255, dotAlpha + 20), 2));
				p.setBrush(QColor(192, 192, 192, dotAlpha + 20));
			}
			else {
				p.setPen(QPen(QColor(0, 0, 0, dotAlpha - 10), 2));
				p.setBrush(QColor(0, 0, 0, dotAlpha - 10));
			}
			p.drawEllipse(x - dotSiz / 2, y - dotSiz / 2, dotSiz, dotSiz);
		}


		//p.fillRect(schemeWidth + siz, titleHeight, siz, paletteHeight, QColor(0x533333));
		QImage img(siz, siz, QImage::Format_ARGB32);
		img.fill(0xFF444444);
		uint32_t* bits = (uint32_t*)img.bits();
		int pitch = img.bytesPerLine() / sizeof(uint32_t);
		float hue = palette.hue(0); // Get the primary color
		for (int j = 0; j < (siz - 120); j++)
		{
			for (int i = 0; i < (siz - 40); i++)
			{
				bits[int(j + 20)*pitch + int(i + 20)] = rgbFromHsvF(hue, j / float(siz - 120), i / float(siz - 40), 1.0);
			}
		}

		for (int j = 0; j < 16; j++)
		{
			for (int i = 0; i < 10; i++)
			{
				float t = i / float(9);
				for (int x = 0; x < 16; x++)
				{
					// shades, tones and tints   (black,grey,white)
					bits[int(j + siz - 80 + 10)*pitch + int(i * 20 + x + 25)] = rgbFromHsvF(hue, 1.0, 1.0 - t, 1.0); // shades
					bits[int(j + siz - 80 + 30)*pitch + int(i * 20 + x + 25)] = rgbFromHsvF(hue, 1.0 - t, 1.0 - (t*0.6), 1.0); // tones
					bits[int(j + siz - 80 + 50)*pitch + int(i * 20 + x + 25)] = rgbFromHsvF(hue, 1.0 - t, 1.0, 1.0); // tints
				}
			}
		}
		p.drawImage(schemeWidth + siz, titleHeight, img);


		p.fillRect(schemeWidth + wheelWidth, titleHeight, paletteWidth, paletteHeight, QColor(0x333333));
		for (int h = 0; h < palette.hueCount(); h++)
		{
			QColor c = QColor::fromHsvF(palette.hue(h), 1.0, 1.0);
			p.setPen(QPen(Qt::white));
			p.setBrush(c);
			// p.drawRect(schemeWidth + siz + 20 + 60 * (h % 2), titleHeight + 20 + 60 * (h / 2), 50, 50);
			p.drawRect(schemeWidth + wheelWidth + 20, titleHeight + 20 + 60 * h, 50, 50);

			QFont f("Segoe UI", 12, 175);
			p.setFont(f);
			QString x = QVariant(c.toRgb()).toString();
			//QString y = QString("%1,%2,%3,%4").arg(c.cyan()).arg(c.magenta()).arg(c.yellow()).arg(c.black());
			p.drawText(schemeWidth + wheelWidth + 20 + 60, titleHeight + 20 + 60 * h + 16, x);// "#FF123456");
			//p.drawText(schemeWidth + siz + 20 + 60, titleHeight + 20 + 60 * h + 16 + 25, y);// "10,20,40,10");
		}

		int colIdxForMode[5][5] = { { 0, 0, 0, 0, -1 }, { 0, 0, 0, 1, -1 }, { 0, 0, 1, 2, -1 }, { 0, 2, 3, 1, -1 }, { 0, 2, 3, 1, -1 } };
		for (int i = 0; i < 4; i++)
		{
			int idx = colIdxForMode[palette.m_mode][i];
			float sats[4] = { 1.0 - 0.65, 1.0 - 0.35, 1.0, 1.0 };
			float vals[4] = { 1.0, 1.0, 1.0 - 0.35, 1.0 - 0.65 };
			float baseTone = 0.15;
			float hue = palette.hue(idx);
			QColor c = QColor::fromHsvF(hue, 1.0 - baseTone, 1.0 - (baseTone*0.6));

			int unitSiz = (((siz*2) - 30) / 16) * 4;
			int unitW = unitSiz - 4;
			int x1 = schemeWidth + 20 + unitSiz * i;
			int x2 = x1 + unitW;

			while (idx == colIdxForMode[palette.m_mode][i + 1]) {
				x2 += unitSiz;
				i++;
			}

			int w = x2 - x1;
			p.fillRect(x1, titleHeight + siz + 10, w, 50, c);
			for (int s = 0; s < 4; s++)
				p.fillRect(x1 + (w / 4) * s, titleHeight + siz + 10 + 50, w / 4, 25, rgbFromHsvF(hue, sats[s], vals[s], 1.0));

		}

	}
};




int main(int argc, char* argv[])
{
#ifdef GUI_APP
	QApplication app(argc, argv);
	UiContext ui;
	ui.setupUi();

	ColorPicker picker;
	picker.show();


	runTests();

	YQ_LOG_DEBUG("This is a test message");
	ui.log.LogMessage("blah", "hooking up ui");

	GenericTableUI table(&ui.log, ui.appWindow.eventLog);

	ui.log.LogMessage("blah", "starting");
	ui.log.LogMessage("blah", "starting1");
	ui.log.LogMessage("blah", "starting2");
	ui.log.LogMessage("blah", "starting3");
	ui.log.LogMessage("blah", "starting4");
	ui.log.LogMessage("blah", "starting");
	ui.log.LogMessage("blah", "true");
	ui.log.LogMessage("false", "starting");

	return app.exec();
#else
	DocOutputDevice outputDoc;
	Context context = {
		"Test Markdown to PDF",
		"test/test.md",
		"test/test.pdf",
		"test/test.html",
		&outputDoc
	};
	ProcessConversionContext(&context);
	return 0;
#endif
}