diff --git a/src/control/LatexController.cpp b/src/control/LatexController.cpp index 945a0f7b..abbdb639 100644 --- a/src/control/LatexController.cpp +++ b/src/control/LatexController.cpp @@ -11,26 +11,26 @@ #include #include +#include "pixbuf-utils.h" #include using std::cout; using std::endl; - -LatexController::LatexController(Control* control) - : control(control), - texArea(0), - posx(0), - posy(0), - imgwidth(0), - imgheight(0), - doc(control->getDocument()), - view(NULL), - layer(NULL), - // .png will be appended automatically => tex.png - texImage(Util::getConfigFile("tex").string()), - selectedTexImage(NULL), - selectedText(NULL) +LatexController::LatexController(Control *control) + : control(control), + texArea(0), + posx(0), + posy(0), + imgwidth(0), + imgheight(0), + doc(control->getDocument()), + view(NULL), + layer(NULL), + // .png will be appended automatically => tex.png + texImage(Util::getConfigFile("tex").string()), + selectedTexImage(NULL), + selectedText(NULL) { XOJ_INIT_TYPE(LatexController); } @@ -60,7 +60,7 @@ bool LatexController::findTexExecutable() return true; } - gchar* mathtex = g_find_program_in_path("mathtex-xournalpp.cgi"); + gchar *mathtex = g_find_program_in_path("mathtex-xournalpp.cgi"); if (!mathtex) { return false; @@ -72,7 +72,6 @@ bool LatexController::findTexExecutable() return true; } - /** * Run LaTeX Command */ @@ -108,13 +107,10 @@ bool LatexController::runCommand() { texres = "1000"; } - - string command = FS(bl::format("{1} -m 0 \"\\png\\usepackage{{color}}\\color{{{2}}}\\dpi{{{3}}}\\normalsize {4}\" -o {5}") - % binTex % "black" % texres - % g_strescape(currentTex.c_str(), NULL) % texImage); + string command = FS(bl::format("{1} -m 0 \"\\png\\usepackage{{color}}\\color{{{2}}}\\dpi{{{3}}}\\normalsize {4}\" -o {5}") % binTex % fontcolour % texres % g_strescape(currentTex.c_str(), NULL) % texImage); gint rt = 0; - void(*texhandler)(int) = signal(SIGCHLD, SIG_DFL); + void (*texhandler)(int) = signal(SIGCHLD, SIG_DFL); gboolean success = g_spawn_command_line_sync(command.c_str(), NULL, NULL, &rt, NULL); signal(SIGCHLD, texhandler); @@ -152,7 +148,7 @@ void LatexController::findSelectedTexElement() if (selectedTexImage || selectedText) { // this will get the position of the Latex properly - EditSelection* theSelection = control->getWindow()->getXournal()->getSelection(); + EditSelection *theSelection = control->getWindow()->getXournal()->getSelection(); posx = theSelection->getXOnView(); posy = theSelection->getYOnView(); @@ -173,7 +169,11 @@ void LatexController::findSelectedTexElement() texArea = imgwidth * imgheight; } - + if (initalTex.empty()) + { + initalTex = "x^2"; + } + currentTex = initalTex; doc->unlock(); // need to do this otherwise we can't remove the image for its replacement @@ -184,44 +184,87 @@ void LatexController::showTexEditDialog() { XOJ_CHECK_TYPE(LatexController); - LatexDialog* dlg = new LatexDialog(control->getGladeSearchPath()); + dlg = new LatexDialog(control->getGladeSearchPath()); + //For 'real time' LaTex rendering in the dialog + g_signal_connect(dlg->getTexBox(), "changed", G_CALLBACK(this->handleTexChanged), gpointer(this)); dlg->setTex(initalTex); + //The controller owns the tempRender because, on signal changed, he has to handle the old/new renders + insertTexImage(true); + dlg->setTempRender(temporaryRender->getImage()); dlg->show(GTK_WINDOW(control->getWindow()->getWindow())); + deletePreviousRender(); currentTex = dlg->getTex(); currentTex += " "; delete dlg; } +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Text-changed handler: when the Entry in the dialog changes, + * this handler updates currentTex, removes the previous existing render and creates + * a new one. We need to do it through 'thisContr' because signal handlers + * cannot directly access non-static methods and non-static fields such as + * 'dlg' so we need to wrap all the dlg method inside small methods in 'thisContr' + * + */ +void LatexController::handleTexChanged(GtkWidget *widget, gpointer data) +{ + LatexController *thisContr = ((LatexController *)data); + + thisContr->setCurrentTex(gtk_entry_get_text(GTK_ENTRY(widget))); + thisContr->deletePreviousRender(); + thisContr->runCommand(); + thisContr->insertTexImage(true); + thisContr->setImageInDialog(thisContr->getTemporaryRender()->getImage()); +} + +TexImage* LatexController::getTemporaryRender(){ + return this->temporaryRender; +} + +void LatexController::setImageInDialog(cairo_surface_t *image) +{ + dlg->setTempRender(image); +} + +void LatexController::deletePreviousRender() +{ + delete temporaryRender; +} + +void LatexController::setCurrentTex(string currentTex) +{ + this->currentTex = currentTex; +} + void LatexController::deleteOldImage() { XOJ_CHECK_TYPE(LatexController); if (selectedTexImage) { - EditSelection* selection = new EditSelection(control->getUndoRedoHandler(), selectedTexImage, view, page); + EditSelection *selection = new EditSelection(control->getUndoRedoHandler(), selectedTexImage, view, page); view->getXournal()->deleteSelection(selection); delete selection; selectedTexImage = NULL; } else if (selectedText) { - EditSelection* selection = new EditSelection(control->getUndoRedoHandler(), selectedText, view, page); + EditSelection *selection = new EditSelection(control->getUndoRedoHandler(), selectedText, view, page); view->getXournal()->deleteSelection(selection); delete selection; selectedText = NULL; } } -void LatexController::insertTexImage() +void LatexController::insertTexImage(bool forTemporaryRender) { XOJ_CHECK_TYPE(LatexController); string imgPath = texImage + ".png"; - - GFile* mygfile = g_file_new_for_path(imgPath.c_str()); - GError* err = NULL; - GFileInputStream* in = g_file_read(mygfile, NULL, &err); + GFile *mygfile = g_file_new_for_path(imgPath.c_str()); + GError *err = NULL; + GFileInputStream *in = g_file_read(mygfile, NULL, &err); g_object_unref(mygfile); if (err) @@ -231,12 +274,12 @@ void LatexController::insertTexImage() return; } - GdkPixbuf* pixbuf = gdk_pixbuf_new_from_stream(G_INPUT_STREAM(in), NULL, &err); + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_stream(G_INPUT_STREAM(in), NULL, &err); g_input_stream_close(G_INPUT_STREAM(in), NULL, NULL); deleteOldImage(); - TexImage* img = new TexImage(); + TexImage *img = new TexImage(); img->setX(posx); img->setY(posy); img->setImage(pixbuf); @@ -244,7 +287,7 @@ void LatexController::insertTexImage() if (imgheight) { - double ratio = (gdouble) gdk_pixbuf_get_width(pixbuf) / gdk_pixbuf_get_height(pixbuf); + double ratio = (gdouble)gdk_pixbuf_get_width(pixbuf) / gdk_pixbuf_get_height(pixbuf); if (ratio == 0) { if (imgwidth == 0) @@ -268,6 +311,14 @@ void LatexController::insertTexImage() img->setHeight(gdk_pixbuf_get_height(pixbuf)); } + //Calling this function for 'on-the-go' LaTex render too, so + //if this is that case, return to the caller at this point + if (forTemporaryRender) + { + this->temporaryRender = img; + return; + } + doc->lock(); layer->addElement(img); view->rerenderElement(img); @@ -276,8 +327,10 @@ void LatexController::insertTexImage() control->getUndoRedoHandler()->addUndoAction(new InsertUndoAction(page, layer, img)); // Select element - EditSelection* selection = new EditSelection(control->getUndoRedoHandler(), img, view, page); + EditSelection *selection = new EditSelection(control->getUndoRedoHandler(), img, view, page); view->getXournal()->setSelection(selection); + + return; } void LatexController::run() @@ -310,6 +363,7 @@ void LatexController::run() return; } - insertTexImage(); + //False, because it's not for temporary render but this time + //we add it to the document + insertTexImage(false); } - diff --git a/src/control/LatexController.h b/src/control/LatexController.h index a47db0c7..4f13adc8 100644 --- a/src/control/LatexController.h +++ b/src/control/LatexController.h @@ -18,7 +18,7 @@ #include "model/Text.h" #include - +#include "gui/dialog/LatexDialog.h" #include using std::string; @@ -49,14 +49,45 @@ private: */ void findSelectedTexElement(); + /** + * If a previous image/text is selected, delete it + */ + void deleteOldImage(); + /** * Run LaTeX Command */ bool runCommand(); + /** + * Show the LaTex Editor dialog + */ void showTexEditDialog(); - void insertTexImage(); - void deleteOldImage(); + + /** + * Signal handler, updates the rendered image when the text in the editor changes + */ + static void handleTexChanged(GtkWidget* widget, gpointer data); + + /*******/ + //Wrappers for signal handler who can't access non-static fields + //(see implementation for further explanation) + TexImage* getTemporaryRender(); + void setImageInDialog(cairo_surface_t* image); + void deletePreviousRender(); + void setCurrentTex(string currentTex); + /*******/ + + /** + * Actual image creation, if 'forTemporaryRender' is true, it does not + * add the image to the doc because it means that it has been called + * during the render in the Editor dialog + */ + void insertTexImage(bool forTemporaryRender); + + + + private: XOJ_TYPE_ATTRIB; @@ -128,6 +159,21 @@ private: */ string texImage; + /** + * Previously existin TexImage + */ TexImage* selectedTexImage; + Text* selectedText; + + /** + * LaTex editor dialog + */ + LatexDialog* dlg; + + /** + * The controller holds the 'on-the-go' render in order + * to be able to delete it when a new render is created + */ + TexImage* temporaryRender; }; diff --git a/src/gui/dialog/LatexDialog.cpp b/src/gui/dialog/LatexDialog.cpp index a84d9342..57eb4d20 100644 --- a/src/gui/dialog/LatexDialog.cpp +++ b/src/gui/dialog/LatexDialog.cpp @@ -1,16 +1,21 @@ #include "LatexDialog.h" -LatexDialog::LatexDialog(GladeSearchpath* gladeSearchPath) - : GladeGui(gladeSearchPath, "texdialog.glade", "texDialog") +LatexDialog::LatexDialog(GladeSearchpath *gladeSearchPath) + : GladeGui(gladeSearchPath, "texdialog.glade", "texDialog") { XOJ_INIT_TYPE(LatexDialog); this->texBox = get("texEntry"); + this->texTempRender = get("texImage"); // increase the maximum length to something reasonable. gtk_entry_set_max_length(GTK_ENTRY(this->texBox), 500); - gtk_widget_show(this->texBox); + //Background color for the temporary render, default is white because + //on dark themed DE the LaTex is hard to read + GtkCssProvider* cssProvider = gtk_css_provider_new(); + gtk_css_provider_load_from_data(cssProvider, "*{background-color:white;padding:10px;}", -1, NULL); + gtk_style_context_add_provider(gtk_widget_get_style_context(this->texTempRender), GTK_STYLE_PROVIDER(cssProvider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); } LatexDialog::~LatexDialog() @@ -30,6 +35,27 @@ string LatexDialog::getTex() return this->theLatex; } +void LatexDialog::setTempRender(cairo_surface_t *cairoTexTempRender) +{ + XOJ_CHECK_TYPE(LatexDialog); + this->cairoTexTempRender = cairoTexTempRender; + //Every time the controller updates the temporary render, we update + //our corresponding GtkWidget + gtk_image_set_from_surface(GTK_IMAGE(this->texTempRender), this->cairoTexTempRender); +} + +cairo_surface_t *LatexDialog::getTempRender() +{ + XOJ_CHECK_TYPE(LatexDialog); + return this->cairoTexTempRender; +} + +GtkWidget *LatexDialog::getTexBox() +{ + XOJ_CHECK_TYPE(LatexDialog); + return this->texBox; +} + void LatexDialog::save() { XOJ_CHECK_TYPE(LatexDialog); @@ -48,10 +74,9 @@ void LatexDialog::load() gtk_entry_set_text(GTK_ENTRY(this->texBox), this->theLatex.c_str()); } -void LatexDialog::show(GtkWindow* parent) +void LatexDialog::show(GtkWindow *parent) { XOJ_CHECK_TYPE(LatexDialog); - this->load(); gtk_window_set_transient_for(GTK_WINDOW(this->window), parent); int res = gtk_dialog_run(GTK_DIALOG(this->window)); diff --git a/src/gui/dialog/LatexDialog.h b/src/gui/dialog/LatexDialog.h index c566accf..b29f6be7 100644 --- a/src/gui/dialog/LatexDialog.h +++ b/src/gui/dialog/LatexDialog.h @@ -15,24 +15,41 @@ #include "gui/GladeGui.h" +#include "model/TexImage.h" + #include class LatexDialog : public GladeGui { -public: - LatexDialog(GladeSearchpath* gladeSearchPath); + public: + LatexDialog(GladeSearchpath *gladeSearchPath); virtual ~LatexDialog(); -public: - virtual void show(GtkWindow* parent); + public: + virtual void show(GtkWindow *parent); void save(); void load(); + + //Set and retrieve text from text box void setTex(string texString); string getTex(); + + //Set and retrieve temporary Tex render + void setTempRender(cairo_surface_t *cairoTexTempRender); + cairo_surface_t *getTempRender(); + //Necessary for the controller in order to connect the 'text-changed' + //signal handler + GtkWidget* getTexBox(); -private: + private: XOJ_TYPE_ATTRIB; - GtkWidget* texBox; + + //Temporary render + GtkWidget *texTempRender; + cairo_surface_t *cairoTexTempRender; + + //Text field + GtkWidget *texBox; string theLatex; }; diff --git a/ui/texdialog.glade b/ui/texdialog.glade index 22cd055e..4dd8ab42 100644 --- a/ui/texdialog.glade +++ b/ui/texdialog.glade @@ -83,6 +83,19 @@ False True 3 + + + + + + True + False + + + True + True + 12 + 2