From: Sam Moore Date: Mon, 18 Aug 2014 14:47:00 +0000 (+0800) Subject: Go nuts with Qt X-Git-Url: https://git.ucc.asn.au/?p=ipdf%2Fcode.git;a=commitdiff_plain;h=d9c0c3792133f87cd224dc22be428be8ddc016d8 Go nuts with Qt We can do all the things I promised!* And we can do it without having to implement a vim style stdio based interface! Or adding 16 extra mouse buttons! Qt can parse XML or even SVG all by itself though... I'm going to ignore that and just keep treating it as a menu system. * Commit --amend Well, the set of things we can do is neither a subset nor a superset of the things I promised. --- diff --git a/src/DejaVuSansMono.ttf b/src/DejaVuSansMono.ttf deleted file mode 100644 index 1376228..0000000 Binary files a/src/DejaVuSansMono.ttf and /dev/null differ diff --git a/src/bezier.cpp b/src/bezier.cpp index da65336..b3129e4 100644 --- a/src/bezier.cpp +++ b/src/bezier.cpp @@ -71,10 +71,10 @@ static pair BezierTurningPoints(const Real & p0, const Real & p1, co if (t < 0) t = 0; return pair(t, t); } - Debug("a, b, c are %f, %f, %f", Float(a), Float(b), Float(c)); + //Debug("a, b, c are %f, %f, %f", Float(a), Float(b), Float(c)); if (b*b - 4*a*c < 0) { - Debug("No real roots"); + //Debug("No real roots"); return pair(0,1); } pair tsols = SolveQuadratic(a, b, c); @@ -102,7 +102,7 @@ Rect Bezier::SolveBounds() const Evaluate(tp0, o, tsols.first); Evaluate(tp1, o, tsols.second); - Debug("x: tp0 is %f tp1 is %f", Float(tp0), Float(tp1)); + //Debug("x: tp0 is %f tp1 is %f", Float(tp0), Float(tp1)); vector v(4); v[0] = &x0; @@ -122,7 +122,7 @@ Rect Bezier::SolveBounds() const Evaluate(o, tp1, tsols.second); - Debug("y: tp0 is %f tp1 is %f", Float(tp0), Float(tp1)); + //Debug("y: tp0 is %f tp1 is %f", Float(tp0), Float(tp1)); v[0] = &y0; v[1] = &y3; @@ -133,7 +133,7 @@ Rect Bezier::SolveBounds() const result.y = *(v[0]); result.h = *(v[3]) - result.y; - Debug("Solved Bezier %s bounds as %s", Str().c_str(), result.Str().c_str()); + //Debug("Solved Bezier %s bounds as %s", Str().c_str(), result.Str().c_str()); return result; } diff --git a/src/controlpanel.cpp b/src/controlpanel.cpp index 984a459..41013d0 100644 --- a/src/controlpanel.cpp +++ b/src/controlpanel.cpp @@ -3,25 +3,28 @@ */ #include "controlpanel.h" + +#ifndef CONTROLPANEL_DISABLED + #include "view.h" #include "screen.h" #include "document.h" +#include +#include -#ifndef CONTROLPANEL_DISABLED +using namespace std; namespace IPDF { ControlPanel::ControlPanel(RunArgs & args, QWidget * p) : QMainWindow(p), - m_view(args.view), m_doc(args.doc), m_screen(args.screen) + m_view(args.view), m_doc(args.doc), m_screen(args.screen), m_width(300), m_height(300), + m_state(ControlPanel::ABOUT), m_on_ok(NULL) { // Size - resize(300,300); - // Title - setWindowTitle("IPDF Control Panel"); - // Tooltip - setToolTip("This is the IPDF Control Panel.\nDo you feel in control?"); + resize(m_width,m_height); + // Main menues CreateMainMenu(); @@ -29,14 +32,30 @@ ControlPanel::ControlPanel(RunArgs & args, QWidget * p) : QMainWindow(p), CreateDocumentMenu(); CreateScreenMenu(); + CreateLayout(); + UpdateAll(); +} +void ControlPanel::CreateLayout() +{ + m_text_edit = new QTextEdit(this); + m_text_edit->setGeometry(10,35,m_width-20,m_height-100); + + m_ok_button = new QPushButton("OK", this); + m_ok_button->setGeometry(10,35+m_height-90, m_width-20, 50); + connect(m_ok_button, SIGNAL(clicked()), this, SLOT(PressOK())); } QMenu * ControlPanel::CreateMainMenu() { QMenu * main = menuBar()->addMenu("&Main"); + QAction * about = new QAction("&About", this); + main->addAction(about); + connect(about, SIGNAL(triggered()), this, SLOT(StateAbout())); + + // Quit entry QAction * quit = new QAction("&Quit", this); main->addAction(quit); @@ -47,6 +66,24 @@ QMenu * ControlPanel::CreateMainMenu() QMenu * ControlPanel::CreateDocumentMenu() { QMenu * document = menuBar()->addMenu("&Document"); + + m_document_set_font = new QAction("&Set Insertion Font", this); + document->addAction(m_document_set_font); + connect(m_document_set_font, SIGNAL(triggered()), this, SLOT(SetDocumentFont())); + + m_document_insert_text = new QAction("&Insert Text", this); + document->addAction(m_document_insert_text); + connect(m_document_insert_text, SIGNAL(triggered()), this, SLOT(StateInsertText())); + + m_document_load_svg = new QAction("&Load SVG From File", this); + document->addAction(m_document_load_svg); + connect(m_document_load_svg, SIGNAL(triggered()), this, SLOT(LoadSVGIntoDocument())); + + m_document_parse_svg = new QAction("&Input SVG Manually", this); + document->addAction(m_document_parse_svg); + connect(m_document_parse_svg, SIGNAL(triggered()), this, SLOT(StateParseSVG())); + + return document; } @@ -54,7 +91,9 @@ QMenu * ControlPanel::CreateViewMenu() { QMenu * view = menuBar()->addMenu("&View"); - + m_view_set_bounds = new QAction("&Set bounds", this); + view->addAction(m_view_set_bounds); + connect(m_view_set_bounds, SIGNAL(triggered()), this, SLOT(SetViewBounds())); return view; } @@ -67,9 +106,11 @@ QMenu * ControlPanel::CreateScreenMenu() m_screen_gpu_rendering = new QAction("&GPU Rendering", this); m_screen_gpu_rendering->setCheckable(true); + m_screen_gpu_rendering->setToolTip("Uses the GPU for Rendering"); m_screen_cpu_rendering = new QAction("&CPU Rendering", this); m_screen_cpu_rendering->setCheckable(true); + m_screen_gpu_rendering->setToolTip("Uses the CPU for Rendering"); screen->addAction(m_screen_gpu_rendering); screen->addAction(m_screen_cpu_rendering); @@ -77,14 +118,73 @@ QMenu * ControlPanel::CreateScreenMenu() connect(m_screen_gpu_rendering, SIGNAL(triggered()), this, SLOT(SetGPURendering())); connect(m_screen_cpu_rendering, SIGNAL(triggered()), this, SLOT(SetCPURendering())); + m_screen_show_debug = new QAction("&Print Debug Info", this); + m_screen_show_debug->setCheckable(true); + + screen->addAction(m_screen_show_debug); + connect(m_screen_show_debug, SIGNAL(triggered()), this, SLOT(ToggleScreenDebugFont())); + return screen; } +void ControlPanel::paintEvent(QPaintEvent * e) +{ +// Debug("Called"); + +} + +void ControlPanel::ChangeState(State next_state) +{ + m_state = next_state; + UpdateAll(); +} + + void ControlPanel::UpdateAll() { bool using_gpu_rendering = m_view.UsingGPURendering(); m_screen_gpu_rendering->setChecked(using_gpu_rendering); m_screen_cpu_rendering->setChecked(!using_gpu_rendering); + m_screen_show_debug->setChecked(m_screen.DebugFontShown()); + + // update things based on state + const char * title; + const char * tooltip; + switch (m_state) + { + case INSERT_TEXT: + title = "Insert Text"; + tooltip = "Type text to insert, press OK, simple."; + m_text_edit->show(); + m_ok_button->show(); + m_on_ok = &ControlPanel::InsertTextIntoDocument; + if (m_text_edit->toPlainText() == "") + m_text_edit->setText("The quick brown\nfox jumps over\nthe lazy dog."); + break; + case PARSE_SVG: + title = "Parse SVG"; + tooltip = "Enter valid SVG and press OK to insert."; + m_text_edit->show(); + m_ok_button->show(); + m_on_ok = &ControlPanel::InsertSVGIntoDocument; + if (m_text_edit->toPlainText() == "") + m_text_edit->setText("\n\n"); + + break; + case ABOUT: + default: + title = "IPDF Control Panel"; + tooltip = "This is the IPDF Control Panel\nDo you feel in control?"; + m_text_edit->hide(); + m_ok_button->hide(); + m_on_ok = NULL; + break; + } + + // Title + setWindowTitle(title); + // Tooltip + setToolTip(tooltip); } void ControlPanel::SetGPURendering() @@ -99,6 +199,79 @@ void ControlPanel::SetCPURendering() UpdateAll(); } +void ControlPanel::ToggleScreenDebugFont() +{ + bool state = m_screen.DebugFontShown(); + m_screen.ShowDebugFont(!state); + UpdateAll(); + +} + +void ControlPanel::SetViewBounds() +{ + bool ok; + Real xx = QInputDialog::getDouble(this, "View X Coordinate", "Enter X coordinate:", 0, -2e-30, 2e30,30,&ok); + + Real yy = QInputDialog::getDouble(this, "View Y Coordinate", "Enter Y coordinate:", 0, -2e-30, 2e30,30,&ok); + + Real w = QInputDialog::getDouble(this, "View Width", "Enter Width:", 1, -2e-30, 2e30,30,&ok); + + Real h = QInputDialog::getDouble(this, "View Height", "Enter Height:", 1, -2e-30, 2e30,30,&ok); + m_view.SetBounds(Rect(xx,yy,w,h)); + +} + +void ControlPanel::InsertTextIntoDocument() +{ + const Rect & bounds = m_view.GetBounds(); + Real xx = bounds.x + bounds.w/Real(2); + Real yy = bounds.y + bounds.h/Real(2); + + string msg = m_text_edit->toPlainText().toStdString(); + Real scale = bounds.w / Real(2); + Debug("Insert \"%s\" at %f, %f, scale %f", msg.c_str(), Float(xx), Float(yy), Float(scale)); + //m_doc.Add(RECT_OUTLINE, bounds, 0); // debugging; text needs to go in the boujnds + m_doc.AddText(msg, xx, yy, scale); + m_view.ForceRenderDirty(); + m_view.ForceBufferDirty(); + m_view.ForceBoundsDirty(); +} +void ControlPanel::InsertSVGIntoDocument() +{ + Rect bounds(m_view.GetBounds()); + bounds.w /= Real(m_screen.ViewportWidth()); + bounds.h /= Real(m_screen.ViewportHeight()); + + m_doc.ParseSVG(m_text_edit->toPlainText().toStdString(), bounds); + m_view.ForceRenderDirty(); + m_view.ForceBufferDirty(); + m_view.ForceBoundsDirty(); +} + +void ControlPanel::LoadSVGIntoDocument() +{ + + QString filename = QFileDialog::getOpenFileName(this, "Open SVG", "svg-tests", "Image Files (*.svg)"); + if (filename == "") + return; + + Rect bounds(m_view.GetBounds()); + bounds.w /= Real(m_screen.ViewportWidth()); + bounds.h /= Real(m_screen.ViewportHeight()); + + m_doc.LoadSVG(filename.toStdString(), bounds); + m_view.ForceRenderDirty(); + m_view.ForceBufferDirty(); + m_view.ForceBoundsDirty(); +} + +void ControlPanel::SetDocumentFont() +{ + QString filename = QFileDialog::getOpenFileName(this, "Set Font", "fonts", "True Type Fonts (*.ttf)"); + if (filename != "") + m_doc.SetFont(filename.toStdString()); +} + ControlPanel * ControlPanel::g_panel = NULL; int ControlPanel::Run(void * args) diff --git a/src/controlpanel.h b/src/controlpanel.h index f799375..90394f8 100644 --- a/src/controlpanel.h +++ b/src/controlpanel.h @@ -16,7 +16,9 @@ #include #include #include - +#include +#include +#include namespace IPDF @@ -47,34 +49,69 @@ namespace IPDF }; static int Run(void * args); - static void Update() {if (g_panel != NULL) g_panel->UpdateAll();}; - - ControlPanel(RunArgs & a, QWidget * p = NULL); - virtual ~ControlPanel() {} + static void Update() {if (g_panel != NULL) g_panel->UpdateAll();} + + private: + typedef enum { + ABOUT, + INSERT_TEXT, + PARSE_SVG + } State; private slots: void SetGPURendering(); void SetCPURendering(); - + void ToggleScreenDebugFont(); + void SetViewBounds(); + void LoadSVGIntoDocument(); + void SetDocumentFont(); + void StateInsertText() {ChangeState(INSERT_TEXT);} + void StateAbout() {ChangeState(ABOUT);} + void StateParseSVG() {ChangeState(PARSE_SVG);} + void PressOK() {if (m_on_ok != NULL) (this->*m_on_ok)();} private: static ControlPanel * g_panel; - - + void paintEvent(QPaintEvent * e); + ControlPanel(RunArgs & a, QWidget * p = NULL); + virtual ~ControlPanel() {} void UpdateAll(); - + void ChangeState(State next_state); View & m_view; Document & m_doc; Screen & m_screen; + int m_width; + int m_height; + + + State m_state; + QMenu * CreateMainMenu(); QMenu * CreateViewMenu(); QMenu * CreateDocumentMenu(); QMenu * CreateScreenMenu(); + void CreateLayout(); + + void InsertTextIntoDocument(); + void InsertSVGIntoDocument(); QAction * m_screen_gpu_rendering; QAction * m_screen_cpu_rendering; + QAction * m_screen_show_debug; + + QAction * m_document_set_font; + QAction * m_document_insert_text; + QAction * m_document_parse_svg; + QAction * m_document_load_svg; + QAction * m_view_set_bounds; + + QTextEdit * m_text_edit; + QPushButton * m_ok_button; + + void (ControlPanel::* m_on_ok)(); + }; diff --git a/src/document.cpp b/src/document.cpp index 57b8925..e0dd70b 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -545,6 +545,24 @@ void Document::ParseSVGNode(pugi::xml_node & root, SVGMatrix & parent_transform) } } +/** + * Parse an SVG string into a rectangle + */ +void Document::ParseSVG(const string & input, const Rect & bounds) +{ + using namespace pugi; + + xml_document doc_xml; + xml_parse_result result = doc_xml.load(input.c_str()); + + if (!result) + Error("Couldn't parse SVG input - %s", result.description()); + + Debug("Loaded XML - %s", result.description()); + SVGMatrix transform = {bounds.w, 0,bounds.x, 0,bounds.h,bounds.y}; + ParseSVGNode(doc_xml, transform); +} + /** * Load an SVG into a rectangle */ @@ -557,7 +575,7 @@ void Document::LoadSVG(const string & filename, const Rect & bounds) xml_parse_result result = doc_xml.load(input); if (!result) - Fatal("Couldn't load \"%s\" - %s", filename.c_str(), result.description()); + Error("Couldn't load \"%s\" - %s", filename.c_str(), result.description()); Debug("Loaded XML - %s", result.description()); @@ -758,7 +776,7 @@ void Document::SetFont(const string & font_filename) free(m_font_data); } - FILE *font_file = fopen("DejaVuSansMono.ttf", "rb"); + FILE *font_file = fopen(font_filename.c_str(), "rb"); fseek(font_file, 0, SEEK_END); size_t font_file_size = ftell(font_file); fseek(font_file, 0, SEEK_SET); @@ -863,6 +881,7 @@ void Document::AddFontGlyphAtPoint(stbtt_fontinfo *font, int character, Real sca { AddGroup(start_index, end_index); } + Debug("Added Glyph \"%c\" at %f %f, scale %f", (char)character, Float(x), Float(y), Float(scale)); stbtt_FreeShape(font, instructions); } diff --git a/src/document.h b/src/document.h index 6592f4b..3ff607b 100644 --- a/src/document.h +++ b/src/document.h @@ -27,7 +27,7 @@ namespace IPDF class Document { public: - Document(const std::string & filename = "", const std::string & font_filename = "DejaVuSansMono.ttf") : m_objects(), m_count(0), m_font_data(NULL), m_font() + Document(const std::string & filename = "", const std::string & font_filename = "fonts/DejaVuSansMono.ttf") : m_objects(), m_count(0), m_font_data(NULL), m_font() { Load(filename); if (font_filename != "") @@ -65,6 +65,7 @@ namespace IPDF /** Load an SVG text file and add to the document **/ void LoadSVG(const std::string & filename, const Rect & bounds = Rect(0,0,1,1)); + void ParseSVG(const std::string & svg, const Rect & bounds = Rect(0,0,1,1)); /** Parse an SVG node or SVG-group node, adding children to the document **/ void ParseSVGNode(pugi::xml_node & root, SVGMatrix & transform); diff --git a/src/fonts/BleedingCowboys.ttf b/src/fonts/BleedingCowboys.ttf new file mode 100644 index 0000000..9aeda00 Binary files /dev/null and b/src/fonts/BleedingCowboys.ttf differ diff --git a/src/fonts/ComicSans.ttf b/src/fonts/ComicSans.ttf new file mode 100644 index 0000000..d17e1be Binary files /dev/null and b/src/fonts/ComicSans.ttf differ diff --git a/src/fonts/DejaVuSansMono.ttf b/src/fonts/DejaVuSansMono.ttf new file mode 100644 index 0000000..1376228 Binary files /dev/null and b/src/fonts/DejaVuSansMono.ttf differ diff --git a/src/main.cpp b/src/main.cpp index 2612afc..848debc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,7 +14,7 @@ int main(int argc, char ** argv) Debug("Compiled with REAL = %d => \"%s\" sizeof(Real) == %d bytes", REAL, g_real_name[REAL], sizeof(Real)); - Document doc; + Document doc("","fonts/ComicSans.ttf"); srand(time(NULL)); enum {OUTPUT_TO_BMP, LOOP} mode = LOOP; @@ -86,9 +86,7 @@ int main(int argc, char ** argv) } else { - //doc.AddBezier(Bezier(0,0, 1,0.5, 0.5,1, 1,1)); - doc.AddText("The quick brown\nfox jumps over\nthe lazy dog",0.1,0,0.5); - //doc.AddBezier(Bezier(0,0,0,0.1,0,0.1,0,0.1)); + doc.Add(RECT_OUTLINE, Rect(0,0,0,0),0); // hack to stop segfault if document is empty (:S) } Debug("Start!"); Rect bounds(b[0],b[1],b[2],b[3]); diff --git a/src/main.h b/src/main.h index 9e48967..5ca71ef 100644 --- a/src/main.h +++ b/src/main.h @@ -82,7 +82,7 @@ inline void MainLoop(Document & doc, Screen & scr, View & view) { // order is important... segfaults occur when screen (which inits GL) is not constructed first -_- - scr.DebugFontInit("DejaVuSansMono.ttf"); + scr.DebugFontInit("fonts/DejaVuSansMono.ttf"); scr.SetMouseHandler(RatCatcher); double total_cpu_time = 0; diff --git a/src/screen.cpp b/src/screen.cpp index 223f4a3..a32b1e2 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -93,9 +93,12 @@ Screen::Screen() m_debug_font_atlas = 0; m_no_quit_requested = true; + m_show_debug_font = true; m_view = NULL; ResizeViewport(800, 600); + + Clear(); Present(); @@ -454,7 +457,7 @@ struct fontvertex void Screen::DebugFontPrint(const char* str) { - if (!m_debug_font_atlas) return; + if (!m_debug_font_atlas || !m_show_debug_font) return; glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 41, -1, "Screen::DebugFontPrint()"); diff --git a/src/screen.h b/src/screen.h index 6b52a09..aed042d 100644 --- a/src/screen.h +++ b/src/screen.h @@ -72,6 +72,9 @@ namespace IPDF void RequestQuit() {m_no_quit_requested = false;} bool QuitRequested() const {return !m_no_quit_requested;} + + void ShowDebugFont(bool show = true) {m_show_debug_font = show;} + bool DebugFontShown() const {return m_show_debug_font;} private: void ResizeViewport(int width, int height); void DebugFontFlush(); @@ -104,6 +107,7 @@ namespace IPDF int m_debug_font_index_head; View * m_view; bool m_no_quit_requested; + bool m_show_debug_font; }; } diff --git a/src/view.cpp b/src/view.cpp index a953579..d7d1e34 100644 --- a/src/view.cpp +++ b/src/view.cpp @@ -77,6 +77,21 @@ void View::Translate(Real x, Real y) m_bounds_dirty = true; } +/** + * Set View bounds + * @param bounds - New bounds + */ +void View::SetBounds(const Rect & bounds) +{ + m_bounds.x = bounds.x; + m_bounds.y = bounds.y; + m_bounds.w = bounds.w; + m_bounds.h = bounds.h; + if (!m_use_gpu_transform) + m_buffer_dirty = true; + m_bounds_dirty = true; +} + /** * Scale the View at a point * @param x, y - Coordinates to scale at (eg: Mouse cursor position) diff --git a/src/view.h b/src/view.h index ff34415..fe93e6c 100644 --- a/src/view.h +++ b/src/view.h @@ -27,11 +27,13 @@ namespace IPDF void Translate(Real x, Real y); void ScaleAroundPoint(Real x, Real y, Real scale_amount); + void SetBounds(const Rect & new_bounds); Rect TransformToViewCoords(const Rect& inp) const; const Rect& GetBounds() const { return m_bounds; } + const bool UsingGPUTransform() const { return m_use_gpu_transform; } // whether view transform calculated on CPU or GPU const bool UsingGPURendering() const { return m_use_gpu_rendering; } // whether GPU shaders are used or CPU rendering void ToggleGPUTransform() { m_use_gpu_transform = (!m_use_gpu_transform); m_bounds_dirty = true; m_buffer_dirty = true; }