Skip to content

Commit

Permalink
Merge branch 'release-1.1' into pr/merge-release
Browse files Browse the repository at this point in the history
  • Loading branch information
bhennion committed Jul 31, 2022
2 parents d3dbf42 + b3a8184 commit 038daf3
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 60 deletions.
19 changes: 10 additions & 9 deletions src/core/control/ToolHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -552,17 +552,18 @@ auto ToolHandler::isSinglePageTool() -> bool {
ToolType toolType = this->getToolType();
DrawingType drawingType = this->getDrawingType();

return toolType == (TOOL_PEN && (drawingType == DRAWING_TYPE_ARROW || drawingType == DRAWING_TYPE_ELLIPSE ||
drawingType == DRAWING_TYPE_COORDINATE_SYSTEM ||
drawingType == DRAWING_TYPE_LINE || drawingType == DRAWING_TYPE_RECTANGLE)) ||
drawingType == DRAWING_TYPE_SPLINE || toolType == TOOL_SELECT_REGION || toolType == TOOL_SELECT_RECT ||
toolType == TOOL_SELECT_OBJECT || toolType == TOOL_DRAW_RECT || toolType == TOOL_DRAW_ELLIPSE ||
toolType == TOOL_DRAW_COORDINATE_SYSTEM || toolType == TOOL_DRAW_ARROW ||
toolType == TOOL_DRAW_DOUBLE_ARROW || toolType == TOOL_FLOATING_TOOLBOX || toolType == TOOL_DRAW_SPLINE ||
toolType == TOOL_SELECT_PDF_TEXT_LINEAR || toolType == TOOL_SELECT_PDF_TEXT_RECT;
return ((toolType == TOOL_PEN || toolType == TOOL_HIGHLIGHTER) &&
(drawingType == DRAWING_TYPE_ARROW || drawingType == DRAWING_TYPE_DOUBLE_ARROW ||
drawingType == DRAWING_TYPE_ELLIPSE || drawingType == DRAWING_TYPE_COORDINATE_SYSTEM ||
drawingType == DRAWING_TYPE_LINE || drawingType == DRAWING_TYPE_RECTANGLE ||
drawingType == DRAWING_TYPE_SPLINE)) ||
toolType == TOOL_SELECT_REGION || toolType == TOOL_SELECT_RECT || toolType == TOOL_SELECT_OBJECT ||
toolType == TOOL_DRAW_RECT || toolType == TOOL_DRAW_ELLIPSE || toolType == TOOL_DRAW_COORDINATE_SYSTEM ||
toolType == TOOL_DRAW_ARROW || toolType == TOOL_DRAW_DOUBLE_ARROW || toolType == TOOL_FLOATING_TOOLBOX ||
toolType == TOOL_DRAW_SPLINE || toolType == TOOL_SELECT_PDF_TEXT_LINEAR ||
toolType == TOOL_SELECT_PDF_TEXT_RECT;
}


auto ToolHandler::getSelectedTool(SelectedTool selectedTool) -> Tool* {
switch (selectedTool) {
case SelectedTool::active:
Expand Down
2 changes: 1 addition & 1 deletion src/core/gui/PageView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ void XojPageView::startText(double x, double y) {
this->textEditor->mousePressed(x - text->getX(), y - text->getY());
}

this->rerenderPage();
this->rerenderElement(text);
}
}

Expand Down
134 changes: 92 additions & 42 deletions src/core/gui/TextEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ TextEditor::TextEditor(XojPageView* gui, GtkWidget* widget, Text* text, bool own
this->textWidget = gtk_xoj_int_txt_new(this);
this->lastText = text->getText();

this->previousBoundingBox = text->boundingRect();

this->buffer = gtk_text_buffer_new(nullptr);
string txt = this->text->getText();
gtk_text_buffer_set_text(this->buffer, txt.c_str(), -1);
Expand Down Expand Up @@ -180,8 +182,8 @@ void TextEditor::iMCommitCallback(GtkIMContext* context, const gchar* str, TextE
}

gtk_text_buffer_end_user_action(te->buffer);
te->repaintEditor();
te->contentsChanged();
te->repaintEditor();
}

void TextEditor::iMPreeditChangedCallback(GtkIMContext* context, TextEditor* te) {
Expand Down Expand Up @@ -218,8 +220,8 @@ void TextEditor::iMPreeditChangedCallback(GtkIMContext* context, TextEditor* te)
te->preeditString = "";
}
te->preeditCursor = cursor_pos;
te->repaintEditor();
te->contentsChanged();
te->repaintEditor();

out:

Expand All @@ -241,8 +243,8 @@ auto TextEditor::iMRetrieveSurroundingCallback(GtkIMContext* context, TextEditor
gtk_im_context_set_surrounding(context, text, -1, pos);
g_free(text);

te->repaintEditor();
te->contentsChanged();
te->repaintEditor();
return true;
}

Expand All @@ -258,8 +260,8 @@ auto TextEditor::imDeleteSurroundingCallback(GtkIMContext* context, gint offset,

gtk_text_buffer_delete_interactive(te->buffer, &start, &end, true);

te->repaintEditor();
te->contentsChanged();
te->repaintEditor();

return true;
}
Expand Down Expand Up @@ -829,16 +831,16 @@ void TextEditor::backspace() {

// Backspace deletes the selection, if one exists
if (gtk_text_buffer_delete_selection(this->buffer, true, true)) {
this->repaintEditor();
this->contentsChanged();
this->repaintEditor();
return;
}

gtk_text_buffer_get_iter_at_mark(this->buffer, &insert, gtk_text_buffer_get_insert(this->buffer));

if (gtk_text_buffer_backspace(this->buffer, &insert, true, true)) {
this->repaintEditor();
this->contentsChanged();
this->repaintEditor();
} else {
gtk_widget_error_bell(this->widget);
}
Expand Down Expand Up @@ -866,8 +868,8 @@ void TextEditor::cutToClipboard() {
GtkClipboard* clipboard = gtk_widget_get_clipboard(this->widget, GDK_SELECTION_CLIPBOARD);
gtk_text_buffer_cut_clipboard(this->buffer, clipboard, true);

this->repaintEditor();
this->contentsChanged(true);
this->repaintEditor();
}

void TextEditor::pasteFromClipboard() {
Expand All @@ -876,8 +878,8 @@ void TextEditor::pasteFromClipboard() {
}

void TextEditor::bufferPasteDoneCallback(GtkTextBuffer* buffer, GtkClipboard* clipboard, TextEditor* te) {
te->repaintEditor();
te->contentsChanged(true);
te->repaintEditor();
}

void TextEditor::resetImContext() {
Expand All @@ -887,11 +889,7 @@ void TextEditor::resetImContext() {
}
}

void TextEditor::repaintCursor() {
double x = this->text->getX();
double y = this->text->getY();
this->gui->repaintArea(x, y, x + this->text->getElementWidth(), y + this->text->getElementHeight());
}
void TextEditor::repaintCursor() { this->gui->repaintElement(this->text); }

#define CURSOR_ON_MULTIPLIER 2
#define CURSOR_OFF_MULTIPLIER 1
Expand All @@ -918,9 +916,78 @@ auto TextEditor::blinkCallback(TextEditor* te) -> gint {
return false;
}

void TextEditor::setTextToPangoLayout(PangoLayout* pl) const {
std::string txt = this->text->getText();

if (!this->preeditString.empty()) {
// When using an Input Method, we need to insert the preeditString into the text at the cursor location

// Get the byte position of the cursor in the string, so we can insert at the right place
int pos = 0;
{
// Get an iterator at the cursor location
GtkTextIter it = {nullptr};
GtkTextMark* cursor = gtk_text_buffer_get_insert(this->buffer);
gtk_text_buffer_get_iter_at_mark(this->buffer, &it, cursor);
// Bytes from beginning of line to iterator
pos = gtk_text_iter_get_line_index(&it);
gtk_text_iter_set_line_index(&it, 0);
// Count bytes of previous lines
while (gtk_text_iter_backward_line(&it)) {
pos += gtk_text_iter_get_bytes_in_line(&it);
}
}
txt.insert(static_cast<size_t>(pos), this->preeditString);

PangoAttrList* attrlist = pango_attr_list_new();
PangoAttrList* preedit_attrlist = this->preeditAttrList;
pango_attr_list_splice(attrlist, preedit_attrlist, pos, static_cast<int>(preeditString.length()));
pango_layout_set_attributes(pl, attrlist);
pango_attr_list_unref(attrlist);
attrlist = nullptr;
}
pango_layout_set_text(pl, txt.c_str(), static_cast<int>(txt.length()));
}

auto TextEditor::computeBoundingRect() -> xoj::util::Rectangle<double> {
/*
* We draw on a fake surface to get the size of the printed text
* See also TextView::calcSize
*
* NB: we cannot rely on TextView::calcSize directly, since it would not take the size changes due to the IM
* preeditString into account.
*/
cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1);
cairo_t* cr = cairo_create(surface);
auto* textElement = this->getText();

PangoLayout* pl = xoj::view::TextView::initPango(cr, textElement);

setTextToPangoLayout(pl);

int w = 0;
int h = 0;
pango_layout_get_size(pl, &w, &h);
double width = (static_cast<double>(w)) / PANGO_SCALE;
double height = (static_cast<double>(h)) / PANGO_SCALE;
g_object_unref(pl);

cairo_destroy(cr);
cairo_surface_destroy(surface);

return xoj::util::Rectangle<double>(textElement->getX(), textElement->getY(), width, height);
}


void TextEditor::repaintEditor() {
auto rect = text->boundingRect();
this->gui->rerenderRect(rect.x, rect.y, rect.width, rect.height);
auto rect = this->computeBoundingRect();
this->previousBoundingBox.unite(rect);
const double zoom = this->gui->getXournal()->getZoom();
const double padding = (BORDER_WIDTH_IN_PIXELS + PADDING_IN_PIXELS) / zoom;
this->gui->repaintRect(this->previousBoundingBox.x - padding, this->previousBoundingBox.y - padding,
this->previousBoundingBox.width + 2.0 * padding,
this->previousBoundingBox.height + 2.0 * padding);
this->previousBoundingBox = rect;
}

/**
Expand Down Expand Up @@ -971,10 +1038,6 @@ void TextEditor::paint(cairo_t* cr, double zoom) {

Util::cairo_set_source_rgbi(cr, this->text->getColor());

GtkTextIter cursorIter = {nullptr};
GtkTextMark* cursor = gtk_text_buffer_get_insert(this->buffer);
gtk_text_buffer_get_iter_at_mark(this->buffer, &cursorIter, cursor);

double x0 = this->text->getX();
double y0 = this->text->getY();
cairo_translate(cr, x0, y0);
Expand All @@ -985,28 +1048,9 @@ void TextEditor::paint(cairo_t* cr, double zoom) {
this->layout = xoj::view::TextView::initPango(cr, this->text);
}

if (!this->preeditString.empty()) {
string text = this->text->getText();
int offset = gtk_text_iter_get_offset(&cursorIter);
int pos = gtk_text_iter_get_line_index(&cursorIter);

for (gtk_text_iter_set_line_index(&cursorIter, 0); gtk_text_iter_backward_line(&cursorIter);) {
pos += gtk_text_iter_get_bytes_in_line(&cursorIter);
}
gtk_text_iter_set_offset(&cursorIter, offset);
string txt = text.substr(0, pos) + preeditString + text.substr(pos);

PangoAttrList* attrlist = pango_attr_list_new();
PangoAttrList* preedit_attrlist = this->preeditAttrList;
pango_attr_list_splice(attrlist, preedit_attrlist, pos, preeditString.length());
pango_layout_set_attributes(this->layout, attrlist);
pango_attr_list_unref(attrlist);
attrlist = nullptr;
pango_layout_set_text(this->layout, txt.c_str(), txt.length());
} else {
string txt = this->text->getText();
pango_layout_set_text(this->layout, txt.c_str(), txt.length());
this->setTextToPangoLayout(this->layout);

if (this->preeditString.empty()) {
GtkTextIter start;
GtkTextIter end;
bool hasSelection = gtk_text_buffer_get_selection_bounds(this->buffer, &start, &end);
Expand Down Expand Up @@ -1039,6 +1083,11 @@ void TextEditor::paint(cairo_t* cr, double zoom) {
double width = (static_cast<double>(w)) / PANGO_SCALE;
double height = (static_cast<double>(h)) / PANGO_SCALE;


GtkTextIter cursorIter = {nullptr};
GtkTextMark* cursor = gtk_text_buffer_get_insert(this->buffer);
gtk_text_buffer_get_iter_at_mark(this->buffer, &cursorIter, cursor);

int offset = gtk_text_iter_get_offset(&cursorIter);
PangoRectangle rect = {0};
int pcursInd = 0;
Expand All @@ -1057,10 +1106,11 @@ void TextEditor::paint(cairo_t* cr, double zoom) {
cairo_restore(cr);

// set the line always the same size on display
cairo_set_line_width(cr, 1 / zoom);
cairo_set_line_width(cr, BORDER_WIDTH_IN_PIXELS / zoom);
gdk_cairo_set_source_rgba(cr, &selectionColor);

cairo_rectangle(cr, x0 - 5 / zoom, y0 - 5 / zoom, width + 10 / zoom, height + 10 / zoom);
cairo_rectangle(cr, x0 - PADDING_IN_PIXELS / zoom, y0 - PADDING_IN_PIXELS / zoom,
width + 2 * PADDING_IN_PIXELS / zoom, height + 2 * PADDING_IN_PIXELS / zoom);
cairo_stroke(cr);

// Notify the IM of the app's window and cursor position.
Expand Down
22 changes: 22 additions & 0 deletions src/core/gui/TextEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <pango/pangocairo.h> // for cairo_t, PangoAttrList, PangoLayout

#include "util/Color.h" // for Color
#include "util/Rectangle.h"

class XojPageView;
class Text;
Expand Down Expand Up @@ -68,6 +69,14 @@ class TextEditor {
UndoAction* setColor(Color color);

private:
/**
* @brief Add the text to the providedd Pango layout.
* The added text contains both this->text, and the preedit string of the Input Method (this->preeditstring)
* This function also sets up the attributes of the preedit string (typically underlined)
*/
void setTextToPangoLayout(PangoLayout* pl) const;

xoj::util::Rectangle<double> computeBoundingRect();
void repaintEditor();
void drawCursor(cairo_t* cr, double x, double y, double height, double zoom);
void repaintCursor();
Expand Down Expand Up @@ -115,6 +124,14 @@ class TextEditor {
double markPosX = 0;
double markPosY = 0;

/**
* Tracks the bounding box of the editor from the last render.
*
* Because adding or deleting lines may cause the size of the bounding box to change,
* we need to rerender the union of the current and previous bboxes.
*/
xoj::util::Rectangle<double> previousBoundingBox;

bool cursorBlink = true;
int cursorBlinkTime = 0;
int cursorBlinkTimeout = 0;
Expand All @@ -127,4 +144,9 @@ class TextEditor {
bool mouseDown = false;
bool cursorOverwrite = false;
bool cursorVisible = false;

// Padding between the text logical box and the frame
static constexpr int PADDING_IN_PIXELS = 5;
// Width of the lines making the frame
static constexpr int BORDER_WIDTH_IN_PIXELS = 1;
};
17 changes: 9 additions & 8 deletions src/core/gui/inputdevices/PenInputHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,6 @@ auto PenInputHandler::actionMotion(InputEvent const& event) -> bool {
}
}

bool result = false;

// Update the cursor
xournal->view->getCursor()->setInsidePage(currentPage != nullptr);

Expand All @@ -309,21 +307,24 @@ auto PenInputHandler::actionMotion(InputEvent const& event) -> bool {

pos.pressure = this->filterPressure(pos, sequenceStartPage);

result = sequenceStartPage->onMotionNotifyEvent(pos);
bool result = sequenceStartPage->onMotionNotifyEvent(pos);

this->updateLastEvent(event); // Update the last position of the input device
return result;
}

if (currentPage && this->penInWidget) {
// Relay the event to the page
PositionInputData pos = getInputDataRelativeToCurrentPage(currentPage, event);
pos.pressure = this->filterPressure(pos, currentPage);

result = currentPage->onMotionNotifyEvent(pos);
}
bool result = currentPage->onMotionNotifyEvent(pos);

// Update the last position of the input device
this->updateLastEvent(event);
this->updateLastEvent(event); // Update the last position of the input device
return result;
}

return result;
return false;
}

auto PenInputHandler::actionEnd(InputEvent const& event) -> bool {
Expand Down

0 comments on commit 038daf3

Please sign in to comment.