mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-25 10:58:52 +00:00
Make input methods support great again
This unbreaks input methods by splitting the part of the code that does the actual drawing to a separate paintPreeditText() method which is called from paintEvent(). The proper solution would have been to introduce the preedit string in the Row object, like is done for completion, but this is too complex to do at this point. The only change in behavior is that now the commit string is inserted in one fell swoop, intead of emulating a number of key events.
This commit is contained in:
parent
1a7e342652
commit
14320e5b9a
@ -39,6 +39,7 @@
|
||||
#include "LyXVC.h"
|
||||
#include "Text.h"
|
||||
#include "TextMetrics.h"
|
||||
#include "Undo.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "graphics/GraphicsImage.h"
|
||||
@ -1144,105 +1145,31 @@ void GuiWorkArea::resizeEvent(QResizeEvent * ev)
|
||||
}
|
||||
|
||||
|
||||
void GuiWorkArea::paintEvent(QPaintEvent * ev)
|
||||
void GuiWorkArea::Private::paintPreeditText(GuiPainter & pain)
|
||||
{
|
||||
// LYXERR(Debug::PAINTING, "paintEvent begin: x: " << rc.x()
|
||||
// << " y: " << rc.y() << " w: " << rc.width() << " h: " << rc.height());
|
||||
|
||||
if (d->needResize()) {
|
||||
d->resizeBufferView();
|
||||
if (d->caret_visible_) {
|
||||
d->hideCaret();
|
||||
d->showCaret();
|
||||
}
|
||||
}
|
||||
|
||||
GuiPainter pain(viewport(), pixelRatio());
|
||||
d->buffer_view_->draw(pain, d->caret_visible_);
|
||||
|
||||
if (d->caret_visible_)
|
||||
d->caret_->draw(pain);
|
||||
ev->accept();
|
||||
}
|
||||
|
||||
|
||||
void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e)
|
||||
{
|
||||
//FIXME Broken Feature !!
|
||||
// I do not think that we are supposed to paint inside this event. Shall we
|
||||
// just let TextMetrics::breakRow add this to the relevant Row object?
|
||||
#if 0
|
||||
QString const & commit_string = e->commitString();
|
||||
docstring const & preedit_string
|
||||
= qstring_to_ucs4(e->preeditString());
|
||||
|
||||
if (!commit_string.isEmpty()) {
|
||||
|
||||
LYXERR(Debug::KEY, "preeditString: " << e->preeditString()
|
||||
<< " commitString: " << e->commitString());
|
||||
|
||||
int key = 0;
|
||||
|
||||
// FIXME Iwami 04/01/07: we should take care also of UTF16 surrogates here.
|
||||
for (int i = 0; i != commit_string.size(); ++i) {
|
||||
QKeyEvent ev(QEvent::KeyPress, key, Qt::NoModifier, commit_string[i]);
|
||||
keyPressEvent(&ev);
|
||||
}
|
||||
}
|
||||
|
||||
// Hide the cursor during the kana-kanji transformation.
|
||||
if (preedit_string.empty())
|
||||
startBlinkingCaret();
|
||||
else
|
||||
stopBlinkingCaret();
|
||||
|
||||
// last_width : for checking if last preedit string was/wasn't empty.
|
||||
// FIXME THREAD && FIXME
|
||||
// We could have more than one work area, right?
|
||||
static bool last_width = false;
|
||||
if (!last_width && preedit_string.empty()) {
|
||||
// if last_width is last length of preedit string.
|
||||
e->accept();
|
||||
if (preedit_string_.empty())
|
||||
return;
|
||||
}
|
||||
|
||||
d->buffer_view_->updateMetrics();
|
||||
viewport()->update();
|
||||
// FIXME: shall we use real_current_font here? (see #10478)
|
||||
FontInfo font = d->buffer_view_->cursor().getFont().fontInfo();
|
||||
FontInfo const font = buffer_view_->cursor().getFont().fontInfo();
|
||||
FontMetrics const & fm = theFontMetrics(font);
|
||||
int height = fm.maxHeight();
|
||||
int cur_x = d->caret_->rect().left();
|
||||
int cur_y = d->caret_->rect().bottom();
|
||||
|
||||
// redraw area of preedit string.
|
||||
viewport()->update(0, cur_y - height, viewport()->width(),
|
||||
(height + 1) * d->preedit_lines_);
|
||||
|
||||
if (preedit_string.empty()) {
|
||||
last_width = false;
|
||||
d->preedit_lines_ = 1;
|
||||
e->accept();
|
||||
return;
|
||||
}
|
||||
last_width = true;
|
||||
|
||||
// att : stores an IM attribute.
|
||||
QList<QInputMethodEvent::Attribute> const & att = e->attributes();
|
||||
int const height = fm.maxHeight();
|
||||
int cur_x = caret_->rect().left();
|
||||
int cur_y = caret_->rect().bottom();
|
||||
|
||||
// get attributes of input method cursor.
|
||||
// cursor_pos : cursor position in preedit string.
|
||||
size_t cursor_pos = 0;
|
||||
bool caret_is_visible = false;
|
||||
for (int i = 0; i != att.size(); ++i) {
|
||||
if (att.at(i).type == QInputMethodEvent::Cursor) {
|
||||
cursor_pos = att.at(i).start;
|
||||
cursor_is_visible = att.at(i).length != 0;
|
||||
bool cursor_is_visible = false;
|
||||
for (auto const & attr : preedit_attr_) {
|
||||
if (attr.type == QInputMethodEvent::Cursor) {
|
||||
cursor_pos = attr.start;
|
||||
cursor_is_visible = attr.length != 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t preedit_length = preedit_string.length();
|
||||
size_t const preedit_length = preedit_string_.length();
|
||||
|
||||
// get position of selection in input method.
|
||||
// FIXME: isn't there a way to do this simplier?
|
||||
@ -1251,12 +1178,12 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e)
|
||||
// rLength : selected string length in IM.
|
||||
size_t rLength = 0;
|
||||
if (cursor_pos < preedit_length) {
|
||||
for (int i = 0; i != att.size(); ++i) {
|
||||
if (att.at(i).type == QInputMethodEvent::TextFormat) {
|
||||
if (att.at(i).start <= int(cursor_pos)
|
||||
&& int(cursor_pos) < att.at(i).start + att.at(i).length) {
|
||||
rStart = att.at(i).start;
|
||||
rLength = att.at(i).length;
|
||||
for (auto const & attr : preedit_attr_) {
|
||||
if (attr.type == QInputMethodEvent::TextFormat) {
|
||||
if (attr.start <= int(cursor_pos)
|
||||
&& int(cursor_pos) < attr.start + attr.length) {
|
||||
rStart = attr.start;
|
||||
rLength = attr.length;
|
||||
if (!cursor_is_visible)
|
||||
cursor_pos += rLength;
|
||||
break;
|
||||
@ -1269,20 +1196,20 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e)
|
||||
rLength = 0;
|
||||
}
|
||||
|
||||
int const right_margin = d->buffer_view_->rightMargin();
|
||||
int const right_margin = buffer_view_->rightMargin();
|
||||
Painter::preedit_style ps;
|
||||
// Most often there would be only one line:
|
||||
d->preedit_lines_ = 1;
|
||||
preedit_lines_ = 1;
|
||||
for (size_t pos = 0; pos != preedit_length; ++pos) {
|
||||
char_type const typed_char = preedit_string[pos];
|
||||
char_type const typed_char = preedit_string_[pos];
|
||||
// reset preedit string style
|
||||
ps = Painter::preedit_default;
|
||||
|
||||
// if we reached the right extremity of the screen, go to next line.
|
||||
if (cur_x + fm.width(typed_char) > viewport()->width() - right_margin) {
|
||||
if (cur_x + fm.width(typed_char) > p->viewport()->width() - right_margin) {
|
||||
cur_x = right_margin;
|
||||
cur_y += height + 1;
|
||||
++d->preedit_lines_;
|
||||
++preedit_lines_;
|
||||
}
|
||||
// preedit strings are displayed with dashed underline
|
||||
// and partial strings are displayed white on black indicating
|
||||
@ -1299,14 +1226,79 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e)
|
||||
ps = Painter::preedit_cursor;
|
||||
|
||||
// draw one character and update cur_x.
|
||||
GuiPainter pain(d->screen_, pixelRatio());
|
||||
cur_x += pain.preeditText(cur_x, cur_y, typed_char, font, ps);
|
||||
}
|
||||
}
|
||||
|
||||
// update the preedit string screen area.
|
||||
viewport()->update(0, cur_y - d->preedit_lines_*height, viewport()->width(),
|
||||
|
||||
void GuiWorkArea::paintEvent(QPaintEvent * ev)
|
||||
{
|
||||
// LYXERR(Debug::PAINTING, "paintEvent begin: x: " << rc.x()
|
||||
// << " y: " << rc.y() << " w: " << rc.width() << " h: " << rc.height());
|
||||
|
||||
if (d->needResize()) {
|
||||
d->resizeBufferView();
|
||||
if (d->caret_visible_) {
|
||||
d->hideCaret();
|
||||
d->showCaret();
|
||||
}
|
||||
}
|
||||
|
||||
GuiPainter pain(viewport(), pixelRatio());
|
||||
d->buffer_view_->draw(pain, d->caret_visible_);
|
||||
|
||||
// The preedit text, if needed
|
||||
d->paintPreeditText(pain);
|
||||
|
||||
// and the caret
|
||||
if (d->caret_visible_)
|
||||
d->caret_->draw(pain);
|
||||
ev->accept();
|
||||
}
|
||||
|
||||
|
||||
void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e)
|
||||
{
|
||||
LYXERR(Debug::KEY, "preeditString: " << e->preeditString()
|
||||
<< " commitString: " << e->commitString());
|
||||
|
||||
// insert the processed text in the document (handles undo)
|
||||
if (!e->commitString().isEmpty()) {
|
||||
d->buffer_view_->cursor().beginUndoGroup();
|
||||
d->buffer_view_->cursor().insert(qstring_to_ucs4(e->commitString()));
|
||||
d->buffer_view_->updateMetrics();
|
||||
d->buffer_view_->cursor().endUndoGroup();
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
// Hide the cursor during the test transformation.
|
||||
if (e->preeditString().isEmpty())
|
||||
startBlinkingCaret();
|
||||
else
|
||||
stopBlinkingCaret();
|
||||
|
||||
if (d->preedit_string_.empty() && e->preeditString().isEmpty()) {
|
||||
// Nothing to do
|
||||
e->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
// The preedit text and its attributes will be used in paintPreeditText
|
||||
d->preedit_string_ = qstring_to_ucs4(e->preeditString());
|
||||
d->preedit_attr_ = e->attributes();
|
||||
|
||||
|
||||
// redraw area of preedit string.
|
||||
int height = d->caret_->rect().height();
|
||||
int cur_y = d->caret_->rect().bottom();
|
||||
viewport()->update(0, cur_y - height, viewport()->width(),
|
||||
(height + 1) * d->preedit_lines_);
|
||||
#endif
|
||||
|
||||
if (d->preedit_string_.empty()) {
|
||||
d->preedit_lines_ = 1;
|
||||
e->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't forget to accept the event!
|
||||
e->accept();
|
||||
|
@ -27,6 +27,7 @@ class Buffer;
|
||||
namespace frontend {
|
||||
|
||||
class GuiCompleter;
|
||||
class GuiPainter;
|
||||
class GuiView;
|
||||
class GuiWorkArea;
|
||||
|
||||
@ -94,6 +95,8 @@ struct GuiWorkArea::Private
|
||||
/// Change the cursor when the mouse hovers over a clickable inset
|
||||
void updateCursorShape();
|
||||
|
||||
void paintPreeditText(GuiPainter & pain);
|
||||
|
||||
bool needResize() const {
|
||||
return need_resize_ || p->pixelRatio() != pixel_ratio_;
|
||||
}
|
||||
@ -121,8 +124,14 @@ struct GuiWorkArea::Private
|
||||
bool need_resize_;
|
||||
///
|
||||
bool schedule_redraw_;
|
||||
///
|
||||
|
||||
/// the current preedit text of the input method
|
||||
docstring preedit_string_;
|
||||
/// Number of lines used by preedit text
|
||||
int preedit_lines_;
|
||||
/// the attributes of the preedit text
|
||||
QList<QInputMethodEvent::Attribute> preedit_attr_;
|
||||
|
||||
/// Ratio between physical pixels and device-independent pixels
|
||||
/// We save the last used value to detect changes of the
|
||||
/// current pixel_ratio of the viewport.
|
||||
|
Loading…
Reference in New Issue
Block a user