Added real-time LaTex rendering in LatexDialog

presentation
Luca Errani 7 years ago
parent 849e2be030
commit 255e1e3c9a
  1. 130
      src/control/LatexController.cpp
  2. 52
      src/control/LatexController.h
  3. 35
      src/gui/dialog/LatexDialog.cpp
  4. 29
      src/gui/dialog/LatexDialog.h
  5. 13
      ui/texdialog.glade

@ -11,26 +11,26 @@
#include <Stacktrace.h>
#include <boost/filesystem.hpp>
#include "pixbuf-utils.h"
#include <iostream>
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);
}

@ -18,7 +18,7 @@
#include "model/Text.h"
#include <XournalType.h>
#include "gui/dialog/LatexDialog.h"
#include <string>
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;
};

@ -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));

@ -15,24 +15,41 @@
#include "gui/GladeGui.h"
#include "model/TexImage.h"
#include <XournalType.h>
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;
};

@ -83,6 +83,19 @@
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkImage" id="texImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="padding">12</property>
<property name="position">2</property>
</packing>
</child>
</object>

Loading…
Cancel
Save