Merge pull request #1179 from Technius/feature/text-multiclick

Multiple clicks in text editor
presentation
Bryan Tan 7 years ago committed by GitHub
commit 3d6094b29e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 85
      src/gui/PageView.cpp
  2. 2
      src/gui/PageView.h
  3. 70
      src/gui/TextEditor.cpp
  4. 5
      src/gui/TextEditor.h
  5. 2
      src/gui/TextEditorWidget.h
  6. 2
      src/gui/inputdevices/MouseInputHandler.cpp
  7. 53
      src/gui/inputdevices/PenInputHandler.cpp
  8. 2
      src/gui/inputdevices/StylusInputHandler.cpp

@ -45,6 +45,7 @@
#include <gdk/gdk.h>
#include <stdlib.h>
#include <algorithm>
XojPageView::XojPageView(XournalView* xournal, PageRef page)
{
@ -443,6 +444,90 @@ bool XojPageView::onButtonPressEvent(const PositionInputData& pos)
return true;
}
bool XojPageView::onButtonDoublePressEvent(const PositionInputData& pos)
{
// This method assumes that it is called after onButtonPressEvent but before
// onButtonReleaseEvent
double zoom = this->xournal->getZoom();
double x = pos.x / zoom;
double y = pos.y / zoom;
if (x < 0 || y < 0)
{
return false;
}
ToolHandler* toolHandler = this->xournal->getControl()->getToolHandler();
ToolType toolType = toolHandler->getToolType();
bool isSelectTool = toolType == TOOL_SELECT_OBJECT || TOOL_SELECT_RECT || TOOL_SELECT_REGION;
EditSelection* selection = xournal->getSelection();
bool hasNoModifiers = !pos.isShiftDown() && !pos.isControlDown();
if (hasNoModifiers && isSelectTool && selection != nullptr)
{
// Find a selected object under the cursor, if possible. The selection doesn't change the
// element coordinates until it is finalized, so we need to use position relative to the
// original coordinates of the selection.
double origx = x - (selection->getXOnView() - selection->getOriginalXOnView());
double origy = y - (selection->getYOnView() - selection->getOriginalYOnView());
std::vector<Element*>* elems = selection->getElements();
auto it = std::find_if(elems->begin(), elems->end(), [&](Element*& elem) {
return elem->intersectsArea(origx - 5, origy - 5, 5, 5);
});
if (it != elems->end())
{
// Enter editing mode on the selected object
Element* object = *it;
ElementType elemType = object->getType();
if (elemType == ELEMENT_TEXT)
{
this->xournal->clearSelection();
toolHandler->selectTool(TOOL_TEXT);
// Simulate a button press; there's too many things that we
// could forget to do if we manually call startText
this->onButtonPressEvent(pos);
}
else if (elemType == ELEMENT_TEXIMAGE)
{
Control* control = this->xournal->getControl();
this->xournal->clearSelection();
EditSelection* sel = new EditSelection(control->getUndoRedoHandler(), object, this, this->getPage());
this->xournal->setSelection(sel);
control->runLatex();
}
}
}
else if (toolType == TOOL_TEXT)
{
this->startText(x, y);
this->textEditor->selectAtCursor(TextEditor::SelectType::word);
}
return true;
}
bool XojPageView::onButtonTriplePressEvent(const PositionInputData& pos)
{
// This method assumes that it is called after onButtonDoubleEvent but before
// onButtonReleaseEvent
double zoom = this->xournal->getZoom();
double x = pos.x / zoom;
double y = pos.y / zoom;
if (x < 0 || y < 0)
{
return false;
}
ToolHandler* toolHandler = this->xournal->getControl()->getToolHandler();
if (toolHandler->getToolType() == TOOL_TEXT)
{
this->startText(x, y);
this->textEditor->selectAtCursor(TextEditor::SelectType::paragraph);
}
return true;
}
void XojPageView::resetShapeRecognizer()
{
XOJ_CHECK_TYPE(XojPageView);

@ -149,6 +149,8 @@ public:
public: // event handler
bool onButtonPressEvent(const PositionInputData& pos);
bool onButtonReleaseEvent(const PositionInputData& pos);
bool onButtonDoublePressEvent(const PositionInputData& pos);
bool onButtonTriplePressEvent(const PositionInputData& pos);
bool onMotionNotifyEvent(const PositionInputData& pos);
/**

@ -449,14 +449,76 @@ void TextEditor::toggleBold()
//this->repaintEditor();
}
void TextEditor::selectAll()
void TextEditor::selectAtCursor(TextEditor::SelectType ty)
{
XOJ_CHECK_TYPE(TextEditor);
GtkTextIter start_iter, end_iter;
GtkTextMark* mark = gtk_text_buffer_get_insert(this->buffer);
GtkTextIter startPos;
GtkTextIter endPos;
gtk_text_buffer_get_selection_bounds(this->buffer, &startPos, &endPos);
const auto searchFlag = GTK_TEXT_SEARCH_TEXT_ONLY; // To be used to find double newlines
switch(ty) {
case TextEditor::SelectType::word:
// Do nothing if cursor is over whitespace
GtkTextIter currentPos;
gtk_text_buffer_get_iter_at_mark(this->buffer, &currentPos, mark);
if (!gtk_text_iter_inside_word(&currentPos))
{
return;
}
if (!gtk_text_iter_starts_word(&currentPos))
{
gtk_text_iter_backward_word_start(&startPos);
}
if (!gtk_text_iter_ends_word(&currentPos))
{
gtk_text_iter_forward_word_end(&endPos);
}
break;
case TextEditor::SelectType::paragraph:
// Note that a GTK "paragraph" is a line, so there's no nice one-liner.
// We define a paragraph as text separated by double newlines.
while (!gtk_text_iter_is_start(&startPos))
{
// There's no GTK function to go to line start, so do it manually.
while (!gtk_text_iter_starts_line(&startPos))
{
if (!gtk_text_iter_backward_word_start(&startPos))
{
break;
}
}
// Check for paragraph start
GtkTextIter searchPos = startPos;
gtk_text_iter_backward_chars(&searchPos, 2);
if (gtk_text_iter_backward_search(&startPos, "\n\n", searchFlag, nullptr, nullptr, &searchPos))
{
break;
}
gtk_text_iter_backward_line(&startPos);
}
while (!gtk_text_iter_ends_line(&endPos))
{
gtk_text_iter_forward_to_line_end(&endPos);
// Check for paragraph end
GtkTextIter searchPos = endPos;
gtk_text_iter_forward_chars(&searchPos, 2);
if (gtk_text_iter_forward_search(&endPos, "\n\n", searchFlag, nullptr, nullptr, &searchPos))
{
break;
}
gtk_text_iter_forward_line(&endPos);
}
break;
case TextEditor::SelectType::all:
gtk_text_buffer_get_bounds(this->buffer, &startPos, &endPos);
break;
}
gtk_text_buffer_get_bounds(buffer, &start_iter, &end_iter);
gtk_text_buffer_select_range(buffer, &start_iter, &end_iter);
gtk_text_buffer_select_range(this->buffer, &startPos, &endPos);
this->repaintEditor();
}

@ -26,13 +26,16 @@ public:
TextEditor(XojPageView* gui, GtkWidget* widget, Text* text, bool ownText);
virtual ~TextEditor();
/** Represents the different kinds of text selection */
enum class SelectType { word, paragraph, all };
void paint(cairo_t* cr, GdkRectangle* rect, double zoom);
bool onKeyPressEvent(GdkEventKey* event);
bool onKeyReleaseEvent(GdkEventKey* event);
void toggleOverwrite();
void selectAll();
void selectAtCursor(TextEditor::SelectType ty);
void toggleBold();
void incSize();
void decSize();

@ -65,7 +65,7 @@ static guint signals[LAST_SIGNAL] = {0};
static void gtk_xoj_int_txt_select_all(GtkWidget* widget)
{
GtkXojIntTxt* txt = GTK_XOJ_INT_TXT(widget);
txt->te->selectAll();
txt->te->selectAtCursor(TextEditor::SelectType::all);
}
static void gtk_xoj_int_txt_move_cursor(GtkWidget* widget, gint step, gint bitmask)

@ -47,7 +47,7 @@ bool MouseInputHandler::handleImpl(GdkEvent* event)
return true;
}
if (event->type == GDK_DOUBLE_BUTTON_PRESS)
if (event->type == GDK_DOUBLE_BUTTON_PRESS || event->type == GDK_TRIPLE_BUTTON_PRESS)
{
this->actionPerform(event);
return true;

@ -13,7 +13,6 @@
#include "gui/XournalView.h"
#include <control/settings/ButtonConfig.h>
#include <algorithm>
#include <cmath>
#define WIDGET_SCROLL_BORDER 25
@ -385,57 +384,21 @@ bool PenInputHandler::actionEnd(GdkEvent* event)
void PenInputHandler::actionPerform(GdkEvent* event)
{
XOJ_CHECK_TYPE(PenInputHandler);
GtkXournal* xournal = this->inputContext->getXournal();
EditSelection* selection = xournal->selection;
ToolHandler* toolHandler = this->inputContext->getToolHandler();
ToolType toolType = toolHandler->getToolType();
bool isSelectTool = toolType == TOOL_SELECT_OBJECT || TOOL_SELECT_RECT || TOOL_SELECT_REGION;
#ifdef DEBUG_INPUT
g_message("Discrete input action; modifier1=%s, modifier2=%2",
this->modifier2 ? "true" : "false", this->modifier3 ? "true" : "false");
#endif
// Double click selection to edit;
// Only applies to double left clicks / taps
if (!this->modifier2 && !this->modifier3 && isSelectTool && selection != nullptr)
XojPageView* currentPage = this->getPageAtCurrentPosition(event);
PositionInputData pos = this->getInputDataRelativeToCurrentPage(currentPage, event);
if (event->type == GDK_DOUBLE_BUTTON_PRESS)
{
XojPageView* currentPage = this->getPageAtCurrentPosition(event);
PositionInputData pos = getInputDataRelativeToCurrentPage(currentPage, event);
// Find a selected object under the cursor, if possible. The selection doesn't change the
// element coordinates until it is finalized, so we need to use position relative to the
// original coordinates of the selection.
double zoom = xournal->view->getZoom();
double x = (pos.x - selection->getXOnView() + selection->getOriginalXOnView()) / zoom;
double y = (pos.y - selection->getYOnView() + selection->getOriginalYOnView()) / zoom;
std::vector<Element*>* elems = selection->getElements();
auto it = std::find_if(elems->begin(), elems->end(), [&](Element*& elem) {
return elem->intersectsArea(x - 5, y - 5, 5, 5);
});
if (it != elems->end())
{
// Enter editing mode on the selected object
Element* object = *it;
ElementType elemType = object->getType();
if (elemType == ELEMENT_TEXT)
{
xournal->view->clearSelection();
toolHandler->selectTool(TOOL_TEXT);
// Simulate a button press; there's too many things that we
// could forget to do if we manually call XojPageView::startText
currentPage->onButtonPressEvent(pos);
}
else if (elemType == ELEMENT_TEXIMAGE)
{
Control* control = xournal->view->getControl();
xournal->view->clearSelection();
EditSelection* sel = new EditSelection(control->getUndoRedoHandler(), object, currentPage, currentPage->getPage());
xournal->view->setSelection(sel);
control->runLatex();
}
}
currentPage->onButtonDoublePressEvent(pos);
}
else if (event->type == GDK_TRIPLE_BUTTON_PRESS)
{
currentPage->onButtonTriplePressEvent(pos);
}
}

@ -55,7 +55,7 @@ bool StylusInputHandler::handleImpl(GdkEvent* event)
}
// Trigger discrete action on double tap
if (event->type == GDK_DOUBLE_BUTTON_PRESS)
if (event->type == GDK_DOUBLE_BUTTON_PRESS || event->type == GDK_TRIPLE_BUTTON_PRESS)
{
this->actionPerform(event);
return true;

Loading…
Cancel
Save