diff --git a/src/control/xml/XmlAudioNode.cpp b/src/control/xml/XmlAudioNode.cpp new file mode 100644 index 00000000..02fdc4cf --- /dev/null +++ b/src/control/xml/XmlAudioNode.cpp @@ -0,0 +1,25 @@ +#include "XmlAudioNode.h" + +XmlAudioNode::XmlAudioNode(const char* tag) + : XmlNode(tag), + audioFilename("") +{ + XOJ_INIT_TYPE(XmlAudioNode); +} + +XmlAudioNode::~XmlAudioNode() +{ + XOJ_CHECK_TYPE(XmlAudioNode); + + XOJ_RELEASE_TYPE(XmlAudioNode); +} + +string XmlAudioNode::getAudioFilename() +{ + return this->audioFilename; +} + +void XmlAudioNode::setAudioFilename(string filename) +{ + this->audioFilename = filename; +} \ No newline at end of file diff --git a/src/control/xml/XmlAudioNode.h b/src/control/xml/XmlAudioNode.h new file mode 100644 index 00000000..b3654dfc --- /dev/null +++ b/src/control/xml/XmlAudioNode.h @@ -0,0 +1,37 @@ +/* + * Xournal++ + * + * [Header description] + * + * @author Xournal++ Team + * https://github.com/xournalpp/xournalpp + * + * @license GNU GPLv2 or later + */ + +#pragma once + + +#include "XmlNode.h" + +class XmlAudioNode : public XmlNode +{ +public: + XmlAudioNode(const char* tag); + virtual ~XmlAudioNode(); + +private: + XmlAudioNode(const XmlAudioNode& node); + void operator=(const XmlAudioNode& node); + +public: + string getAudioFilename(); + void setAudioFilename(string filename); + +private: + XOJ_TYPE_ATTRIB; + + string audioFilename; +}; + + diff --git a/src/control/xml/XmlPointNode.cpp b/src/control/xml/XmlPointNode.cpp index fb9c0e19..13afd490 100644 --- a/src/control/xml/XmlPointNode.cpp +++ b/src/control/xml/XmlPointNode.cpp @@ -1,7 +1,7 @@ #include "XmlPointNode.h" XmlPointNode::XmlPointNode(const char* tag) - : XmlNode(tag), + : XmlAudioNode(tag), points(NULL) { XOJ_INIT_TYPE(XmlPointNode); @@ -22,16 +22,6 @@ XmlPointNode::~XmlPointNode() XOJ_RELEASE_TYPE(XmlPointNode); } -string XmlPointNode::getAudioFilename() -{ - return this->audioFilename; -} - -void XmlPointNode::setAudioFilename(string filename) -{ - this->audioFilename = filename; -} - void XmlPointNode::addPoint(const Point* point) { XOJ_CHECK_TYPE(XmlPointNode); diff --git a/src/control/xml/XmlPointNode.h b/src/control/xml/XmlPointNode.h index 297c78c2..ea3e8b93 100644 --- a/src/control/xml/XmlPointNode.h +++ b/src/control/xml/XmlPointNode.h @@ -11,10 +11,10 @@ #pragma once -#include "XmlNode.h" #include "model/Point.h" +#include "XmlAudioNode.h" -class XmlPointNode : public XmlNode +class XmlPointNode : public XmlAudioNode { public: XmlPointNode(const char* tag); @@ -26,13 +26,10 @@ private: public: void addPoint(const Point* point); - string getAudioFilename(); - void setAudioFilename(string filename); virtual void writeOut(OutputStream* out); private: XOJ_TYPE_ATTRIB; GList* points; - string audioFilename; }; diff --git a/src/control/xml/XmlTextNode.cpp b/src/control/xml/XmlTextNode.cpp index a5fa289d..211b2439 100644 --- a/src/control/xml/XmlTextNode.cpp +++ b/src/control/xml/XmlTextNode.cpp @@ -2,14 +2,14 @@ #include -XmlTextNode::XmlTextNode(const char* tag, const char* text) : XmlNode(tag) +XmlTextNode::XmlTextNode(const char* tag, const char* text) : XmlAudioNode(tag) { XOJ_INIT_TYPE(XmlTextNode); this->text = g_strdup(text); } -XmlTextNode::XmlTextNode(const char* tag) : XmlNode(tag) +XmlTextNode::XmlTextNode(const char* tag) : XmlAudioNode(tag) { XOJ_INIT_TYPE(XmlTextNode); diff --git a/src/control/xml/XmlTextNode.h b/src/control/xml/XmlTextNode.h index 030ebcb2..a2d88b4d 100644 --- a/src/control/xml/XmlTextNode.h +++ b/src/control/xml/XmlTextNode.h @@ -12,8 +12,9 @@ #pragma once #include "XmlNode.h" +#include "XmlAudioNode.h" -class XmlTextNode : public XmlNode +class XmlTextNode : public XmlAudioNode { public: XmlTextNode(const char* tag, const char* text); diff --git a/src/control/xojfile/LoadHandler.cpp b/src/control/xojfile/LoadHandler.cpp index e3f17fe7..b3c7ab97 100644 --- a/src/control/xojfile/LoadHandler.cpp +++ b/src/control/xojfile/LoadHandler.cpp @@ -639,6 +639,18 @@ void LoadHandler::parseText() int color = 0; LoadHandlerHelper::parseColor(sColor, color, this); text->setColor(color); + + const char* fn = LoadHandlerHelper::getAttrib("fn", true, this); + if (fn != NULL) + { + text->setAudioFilename(fn); + } + + size_t ts = 0; + if (LoadHandlerHelper::getAttribSizeT("ts", true, this, ts)) + { + text->setTimestamp(ts); + } } void LoadHandler::parseImage() diff --git a/src/control/xojfile/SaveHandler.cpp b/src/control/xojfile/SaveHandler.cpp index c0181224..e4d8a2f2 100644 --- a/src/control/xojfile/SaveHandler.cpp +++ b/src/control/xojfile/SaveHandler.cpp @@ -105,7 +105,7 @@ string SaveHandler::getColorStr(int c, unsigned char alpha) return color; } -void SaveHandler::writeTimestamp(Stroke* s, XmlPointNode* stroke) +void SaveHandler::writeTimestamp(AudioElement* s, XmlAudioNode* stroke) { XOJ_CHECK_TYPE(SaveHandler); @@ -217,6 +217,8 @@ void SaveHandler::visitLayer(XmlNode* page, Layer* l) text->setAttrib("x", t->getX()); text->setAttrib("y", t->getY()); text->setAttrib("color", getColorStr(t->getColor()).c_str()); + + writeTimestamp(t, text); } else if (e->getType() == ELEMENT_IMAGE) { diff --git a/src/control/xojfile/SaveHandler.h b/src/control/xojfile/SaveHandler.h index 4dbe72ec..a43de610 100644 --- a/src/control/xojfile/SaveHandler.h +++ b/src/control/xojfile/SaveHandler.h @@ -17,6 +17,7 @@ #include #include +#include class XmlNode; class XmlPointNode; @@ -48,7 +49,7 @@ protected: virtual void writeHeader(); virtual void writeSolidBackground(XmlNode* background, PageRef p); - virtual void writeTimestamp(Stroke* s, XmlPointNode* stroke); + virtual void writeTimestamp(AudioElement* s, XmlAudioNode* stroke); protected: XOJ_TYPE_ATTRIB; diff --git a/src/gui/PageView.cpp b/src/gui/PageView.cpp index f0fdc568..cbb1f66a 100644 --- a/src/gui/PageView.cpp +++ b/src/gui/PageView.cpp @@ -287,6 +287,15 @@ void XojPageView::startText(double x, double y) text->setY(y); text->setColor(h->getColor()); text->setFont(settings->getFont()); + + if (xournal->getControl()->getAudioController()->getAudioRecorder()->isRecording()) + { + string audioFilename = xournal->getControl()->getAudioController()->getAudioFilename(); + size_t sttime = xournal->getControl()->getAudioController()->getStartTime(); + size_t milliseconds = ((g_get_monotonic_time() / 1000) - sttime); + text->setTimestamp(milliseconds); + text->setAudioFilename(audioFilename); + } } else { @@ -303,6 +312,8 @@ void XojPageView::startText(double x, double y) text->setColor(oldtext->getColor()); text->setFont(oldtext->getFont()); text->setText(oldtext->getText()); + text->setTimestamp(oldtext->getTimestamp()); + text->setAudioFilename(oldtext->getAudioFilename()); Layer* layer = this->page->getSelectedLayer(); layer->removeElement(this->oldtext, false); diff --git a/src/gui/PageViewFindObjectHelper.h b/src/gui/PageViewFindObjectHelper.h index daa8cb9c..6b3cabe0 100644 --- a/src/gui/PageViewFindObjectHelper.h +++ b/src/gui/PageViewFindObjectHelper.h @@ -147,12 +147,12 @@ public: protected: virtual void checkElement(Element* e) { - if (e->getType() != ELEMENT_STROKE) + if (e->getType() != ELEMENT_STROKE && e->getType() != ELEMENT_TEXT) { return; } - Stroke* s = (Stroke*) e; + AudioElement* s = (AudioElement*) e; double tmpGap = 0; if ((s->intersects(x, y, 15, &tmpGap))) { diff --git a/src/model/AudioElement.cpp b/src/model/AudioElement.cpp new file mode 100644 index 00000000..38e08873 --- /dev/null +++ b/src/model/AudioElement.cpp @@ -0,0 +1,80 @@ +#include "AudioElement.h" + +AudioElement::AudioElement(ElementType type) : Element(type) +{ + XOJ_INIT_TYPE(AudioElement); + + this->timestamp = 0; +} + +AudioElement::~AudioElement() +{ + + XOJ_CHECK_TYPE(AudioElement); + + this->timestamp = 0; + + XOJ_RELEASE_TYPE(AudioElement); +} + +void AudioElement::setAudioFilename(string fn) +{ + XOJ_CHECK_TYPE(AudioElement); + + this->audioFilename = fn; +} + +string AudioElement::getAudioFilename() const +{ + XOJ_CHECK_TYPE(AudioElement); + + return this->audioFilename; +} + +void AudioElement::setTimestamp(size_t timestamp) +{ + XOJ_CHECK_TYPE(AudioElement); + + this->timestamp = timestamp; +} + +size_t AudioElement::getTimestamp() const +{ + XOJ_CHECK_TYPE(AudioElement); + + return this->timestamp; +} + +void AudioElement::serializeAudioElement(ObjectOutputStream& out) +{ + XOJ_CHECK_TYPE(AudioElement); + + out.writeObject("AudioElement"); + + serializeElement(out); + + out.writeString(this->audioFilename); + out.writeSizeT(this->timestamp); + + out.endObject(); +} + +void AudioElement::readSerializedAudioElement(ObjectInputStream& in) +{ + XOJ_CHECK_TYPE(AudioElement); + + in.readObject("AudioElement"); + + readSerializedElement(in); + + this->audioFilename = in.readString(); + this->timestamp = in.readSizeT(); + + in.endObject(); +} + +void AudioElement::cloneAudioData(const AudioElement* other) +{ + setAudioFilename(other->getAudioFilename()); + setTimestamp(other->getTimestamp()); +} diff --git a/src/model/AudioElement.h b/src/model/AudioElement.h new file mode 100644 index 00000000..39032c30 --- /dev/null +++ b/src/model/AudioElement.h @@ -0,0 +1,50 @@ +/* + * Xournal++ + * + * Element that is audio enabled + * + * @author Xournal++ Team + * https://github.com/xournalpp/xournalpp + * + * @license GNU GPLv2 or later + */ + +#pragma once + +#include "Element.h" +#include +#include +#include + +class AudioElement : public Element +{ +protected: + AudioElement(ElementType type); + +public: + ~AudioElement() override; + + void setTimestamp(size_t timestamp); + size_t getTimestamp() const; + + void setAudioFilename(string fn); + string getAudioFilename() const; + + virtual bool intersects(double x, double y, double halfSize) = 0; + virtual bool intersects(double x, double y, double halfSize, double* gap) = 0; + +protected: + void serializeAudioElement(ObjectOutputStream& out); + void readSerializedAudioElement(ObjectInputStream& in); + + void cloneAudioData(const AudioElement *other); + +private: + XOJ_TYPE_ATTRIB; + + // Stroke timestamp, to match it to the audio stream + size_t timestamp = 0; + string audioFilename = ""; +}; + + diff --git a/src/model/Stroke.cpp b/src/model/Stroke.cpp index 303f2a1f..49e380eb 100644 --- a/src/model/Stroke.cpp +++ b/src/model/Stroke.cpp @@ -8,7 +8,7 @@ #include Stroke::Stroke() - : Element(ELEMENT_STROKE) + : AudioElement(ELEMENT_STROKE) { XOJ_INIT_TYPE(Stroke); @@ -19,8 +19,6 @@ Stroke::Stroke() this->points = NULL; this->toolType = STROKE_TOOL_PEN; - this->timestamp = 0; - this->eraseable = NULL; this->fill = -1; } @@ -34,8 +32,6 @@ Stroke::~Stroke() this->pointCount = 0; this->pointAllocCount = 0; - this->timestamp = 0; - XOJ_RELEASE_TYPE(Stroke); } @@ -47,10 +43,10 @@ void Stroke::applyStyleFrom(const Stroke* other) setColor(other->getColor()); setToolType(other->getToolType()); setWidth(other->getWidth()); - setAudioFilename(other->getAudioFilename()); - setTimestamp(other->getTimestamp()); setFill(other->getFill()); setLineStyle(other->getLineStyle()); + + cloneAudioData(other); } Stroke* Stroke::cloneStroke() const @@ -80,16 +76,12 @@ void Stroke::serialize(ObjectOutputStream& out) out.writeObject("Stroke"); - serializeElement(out); + serializeAudioElement(out); out.writeDouble(this->width); out.writeInt(this->toolType); - out.writeString(this->audioFilename); - - out.writeSizeT(this->timestamp); - out.writeInt(fill); out.writeData(this->points, this->pointCount, sizeof(Point)); @@ -105,16 +97,12 @@ void Stroke::readSerialized(ObjectInputStream& in) in.readObject("Stroke"); - readSerializedElement(in); + readSerializedAudioElement(in); this->width = in.readDouble(); this->toolType = (StrokeTool) in.readInt(); - this->audioFilename = in.readString(); - - this->timestamp = in.readSizeT(); - this->fill = in.readInt(); g_free(this->points); @@ -127,30 +115,6 @@ void Stroke::readSerialized(ObjectInputStream& in) in.endObject(); } -void Stroke::setAudioFilename(string fn) -{ - this->audioFilename = fn; -} - -string Stroke::getAudioFilename() const -{ - return this->audioFilename; -} - -void Stroke::setTimestamp(size_t seconds) -{ - XOJ_CHECK_TYPE(Stroke); - - this->timestamp = seconds; -} - -size_t Stroke::getTimestamp() const -{ - XOJ_CHECK_TYPE(Stroke); - - return this->timestamp; -} - /** * Option to fill the shape: * -1: The shape is not filled @@ -508,6 +472,16 @@ void Stroke::setPressure(const vector& pressure) } } +/** + * split index is the split point, minimimum is 1 NOT 0 + */ +bool Stroke::intersects(double x, double y, double halfEraserSize) +{ + XOJ_CHECK_TYPE(Stroke); + + return intersects(x, y, halfEraserSize, nullptr); +} + /** * split index is the split point, minimimum is 1 NOT 0 */ diff --git a/src/model/Stroke.h b/src/model/Stroke.h index 42b168bc..479ca55e 100644 --- a/src/model/Stroke.h +++ b/src/model/Stroke.h @@ -11,9 +11,10 @@ #pragma once -#include "Element.h" +#include "AudioElement.h" #include "Point.h" #include "LineStyle.h" +#include "Element.h" #include @@ -24,7 +25,7 @@ enum StrokeTool class EraseableStroke; -class Stroke : public Element +class Stroke : public AudioElement { public: Stroke(); @@ -42,12 +43,6 @@ public: void setWidth(double width); double getWidth() const; - void setTimestamp(size_t seconds); - size_t getTimestamp() const; - - void setAudioFilename(string fn); - string getAudioFilename() const; - /** * Option to fill the shape: * -1: The shape is not filled @@ -85,7 +80,8 @@ public: const LineStyle& getLineStyle() const; void setLineStyle(const LineStyle& style); - bool intersects(double x, double y, double halfSize, double* gap = NULL); + bool intersects(double x, double y, double halfSize) override; + bool intersects(double x, double y, double halfSize, double* gap) override; void setPressure(const vector& pressure); void setLastPressure(double pressure); @@ -133,10 +129,6 @@ private: */ LineStyle lineStyle; - // Stroke timestamp, to match it to the audio stream - size_t timestamp = 0; - string audioFilename; - EraseableStroke* eraseable; /** diff --git a/src/model/Text.cpp b/src/model/Text.cpp index 17d5ffc1..b87233fb 100644 --- a/src/model/Text.cpp +++ b/src/model/Text.cpp @@ -7,7 +7,7 @@ #include Text::Text() - : Element(ELEMENT_TEXT) + : AudioElement(ELEMENT_TEXT) { XOJ_INIT_TYPE(Text); @@ -31,6 +31,7 @@ Element* Text::clone() text->setColor(this->getColor()); text->x = this->x; text->y = this->y; + text->cloneAudioData(this); return text; } @@ -136,13 +137,32 @@ bool Text::rescaleOnlyAspectRatio() return true; } +bool Text::intersects(double x, double y, double halfEraserSize) +{ + XOJ_CHECK_TYPE(Text); + + return intersects(x, y, halfEraserSize, nullptr); +} + +bool Text::intersects(double x, double y, double halfEraserSize, double* gap) +{ + XOJ_CHECK_TYPE(Text); + + double x1 = this->x - halfEraserSize; + double x2 = this->x + this->getElementWidth() + halfEraserSize; + double y1 = this->y - halfEraserSize; + double y2 = this->y + this->getElementHeight() + halfEraserSize; + + return x >= x1 && x <= x2 && y >= y1 && y <= y2; +} + void Text::serialize(ObjectOutputStream& out) { XOJ_CHECK_TYPE(Text); out.writeObject("Text"); - serializeElement(out); + serializeAudioElement(out); out.writeString(this->text); @@ -157,7 +177,7 @@ void Text::readSerialized(ObjectInputStream& in) in.readObject("Text"); - readSerializedElement(in); + readSerializedAudioElement(in); this->text = in.readString(); diff --git a/src/model/Text.h b/src/model/Text.h index 8bfaff47..e41842e2 100644 --- a/src/model/Text.h +++ b/src/model/Text.h @@ -13,10 +13,11 @@ #include "Element.h" #include "Font.h" +#include "AudioElement.h" #include -class Text : public Element +class Text : public AudioElement { public: Text(); @@ -45,6 +46,9 @@ public: */ virtual Element* clone(); + bool intersects(double x, double y, double halfSize) override; + bool intersects(double x, double y, double halfSize, double* gap) override; + public: // Serialize interface void serialize(ObjectOutputStream& out); diff --git a/src/util/XournalTypeList.h b/src/util/XournalTypeList.h index 33e3db0b..50ba2500 100644 --- a/src/util/XournalTypeList.h +++ b/src/util/XournalTypeList.h @@ -277,4 +277,5 @@ XOJ_DECLARE_TYPE(AudioPlayer, 267); XOJ_DECLARE_TYPE(VorbisConsumer, 268); XOJ_DECLARE_TYPE(VorbisProducer, 269); XOJ_DECLARE_TYPE(FullscreenHandler, 270); - +XOJ_DECLARE_TYPE(AudioElement, 271); +XOJ_DECLARE_TYPE(XmlAudioNode, 272);