// 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"
#ifndef _WIN32
# include <unistd.h>
# define __cdecl
int fopen_s(FILE** a_file, const char* a_fileName, const char* a_mode);
#else
# include <Windows.h>
#endif
#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)
{
#ifdef _WIN32
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);
#else
unlink(fileName);
#endif
}
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);
mainWindow.menuBar()->setNativeMenuBar(false);
about.setupUi(&aboutDialog);
aboutDialog.setFixedSize(430, 300);
QObject::connect(appWindow.actionAbout, SIGNAL(triggered(bool)), &aboutDialog, SLOT(exec()));
mainWindow.show();
}
};
#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));
}
}
};
#endif
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
}