岩見昌範 wrote:
Hi, every LyX developpers.
It is a long time. I'm Iwami.
This is the patch for supporting an input method.
It refers to an opinion the other day and only
Painter and GuiWorkArea were changed.
It comes to be able to perform the input of CJK now.
OK Iwami, I've checked in a modified verion of your patch. Basically,
I've fixed some typo, add some more comments following my understanding
(please verify), simplify the code where I could (I think nested if/loop
are hard to follow, so I've simplified that).
I don't think I've introduced errors but please verify.
So Georg, what's next on this front?
Thanks,
Abdel.
Author: younes
Date: Sun Apr 1 11:14:08 2007
New Revision: 17671
URL: http://www.lyx.org/trac/changeset/17671
Log:
Improved input method support by M. Iwami. I fixed some typo, and
simplified the code a bit.
* Painter:
- preeditText(), dashedUnderline(): new methods for CJK support.
* GuiWorkArea:
- inputMethodQuery(): new Qt inherited method for proper CJK support.
- inputMethodEvent(): now properly take care of input methods.
Modified:
lyx-devel/trunk/src/frontends/Painter.C
lyx-devel/trunk/src/frontends/Painter.h
lyx-devel/trunk/src/frontends/qt4/GuiWorkArea.C
lyx-devel/trunk/src/frontends/qt4/GuiWorkArea.h
Modified: lyx-devel/trunk/src/frontends/Painter.C
URL:
http://www.lyx.org/trac/file/lyx-devel/trunk/src/frontends/Painter.C?rev=17671
==============================================================================
--- lyx-devel/trunk/src/frontends/Painter.C (original)
+++ lyx-devel/trunk/src/frontends/Painter.C Sun Apr 1 11:14:08 2007
@@ -84,6 +84,39 @@
}
+int Painter::preeditText(int x, int y, char_type c,
+ LyXFont const & font, preedit_style style)
+{
+ LyXFont temp_font = font;
+ FontMetrics const & fm = theFontMetrics(font);
+ int ascent = fm.maxAscent();
+ int descent = fm.maxDescent();
+ int height = ascent + descent;
+ int width = fm.width(c);
+
+ switch (style) {
+ case preedit_default:
+ // default unselecting mode.
+ fillRectangle(x, y - height + 1, width, height,
LColor::background);
+ dashedUnderline(font, x, y - descent + 1, width);
+ break;
+ case preedit_selecting:
+ // We are in selecting mode: white text on black
background.
+ fillRectangle(x, y - height + 1, width, height,
LColor::black);
+ temp_font.setColor(LColor::white);
+ break;
+ case preedit_cursor:
+ // The character comes with a cursor.
+ fillRectangle(x, y - height + 1, width, height,
LColor::background);
+ underline(font, x, y - descent + 1, width);
+ break;
+ }
+ text(x, y - descent + 1, c, temp_font);
+
+ return width;
+}
+
+
void Painter::underline(LyXFont const & f, int x, int y, int width)
{
FontMetrics const & fm = theFontMetrics(f);
@@ -97,5 +130,20 @@
fillRectangle(x, y + below, width, below + height, f.color());
}
+
+void Painter::dashedUnderline(LyXFont const & f, int x, int y, int width)
+{
+ FontMetrics const & fm = theFontMetrics(f);
+
+ int const below = max(fm.maxDescent() / 2, 2);
+ int height = max((fm.maxDescent() / 4) - 1, 1);
+
+ if (height >= 2)
+ height += below;
+
+ for (int n = 0; n < height; ++n)
+ line(x, y + below + n, x + width, y + below + n, f.color(),
line_onoffdash);
+}
+
} // namespace frontend
} // namespace lyx
Modified: lyx-devel/trunk/src/frontends/Painter.h
URL:
http://www.lyx.org/trac/file/lyx-devel/trunk/src/frontends/Painter.h?rev=17671
==============================================================================
--- lyx-devel/trunk/src/frontends/Painter.h (original)
+++ lyx-devel/trunk/src/frontends/Painter.h Sun Apr 1 11:14:08 2007
@@ -64,6 +64,14 @@
enum line_style {
line_solid, //< solid line
line_onoffdash //< dashes with spaces
+ };
+
+ /// possible character styles of preedit string.
+ /// This is used for CJK input method support.
+ enum preedit_style {
+ preedit_default, //< when unselecting, no cursor and dashed
underline.
+ preedit_selecting, //< when selecting.
+ preedit_cursor //< with cursor.
};
virtual ~Painter() {}
@@ -157,9 +165,17 @@
void buttonText(int x, int baseline, docstring const & s,
LyXFont const & font, bool mouseHover);
+ /// draw a character of a preedit string for cjk support.
+ int preeditText(int x, int y,
+ char_type c, LyXFont const & f, preedit_style style);
+
protected:
/// check the font, and if set, draw an underline
void underline(LyXFont const & f,
+ int x, int y, int width);
+
+ /// check the font, and if set, draw an dashed underline
+ void dashedUnderline(LyXFont const & f,
int x, int y, int width);
/// draw a bevelled button border
Modified: lyx-devel/trunk/src/frontends/qt4/GuiWorkArea.C
URL:
http://www.lyx.org/trac/file/lyx-devel/trunk/src/frontends/qt4/GuiWorkArea.C?rev=17671
==============================================================================
--- lyx-devel/trunk/src/frontends/qt4/GuiWorkArea.C (original)
+++ lyx-devel/trunk/src/frontends/qt4/GuiWorkArea.C Sun Apr 1 11:14:08 2007
@@ -28,6 +28,7 @@
#include "LColor.h"
#include "version.h"
#include "lyxrc.h"
+#include "lyxtext.h"
#include "support/filetools.h" // LibFileSearch
#include "support/os.h"
@@ -44,6 +45,7 @@
#include <QPainter>
#include <QScrollBar>
#include <QTimer>
+#include <QInputContext>
#include <boost/bind.hpp>
#include <boost/current_function.hpp>
@@ -160,7 +162,8 @@
GuiWorkArea::GuiWorkArea(int w, int h, int id, LyXView & lyx_view)
- : WorkArea(id, lyx_view), need_resize_(false), schedule_redraw_(false)
+ : WorkArea(id, lyx_view), need_resize_(false), schedule_redraw_(false),
+ preedit_lines_(1)
{
screen_ = QPixmap(viewport()->width(), viewport()->height());
cursor_ = new frontend::CursorWidget();
@@ -298,6 +301,8 @@
dispatch(cmd);
return;
}
+
+ inputContext()->reset();
FuncRequest const cmd(LFUN_MOUSE_PRESS, e->x(), e->y(),
q_button_state(e->button()));
@@ -573,8 +578,16 @@
void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e)
{
- QString const & text = e->commitString();
- if (!text.isEmpty()) {
+ QString const & commit_string = e->commitString();
+ docstring const & preedit_string
+ = qstring_to_ucs4(e->preeditString());
+
+ if(greyed_out_) {
+ e->ignore();
+ return;
+ }
+
+ if (!commit_string.isEmpty()) {
lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
<< " preeditString =" << fromqstr(e->preeditString())
@@ -583,24 +596,143 @@
int key = 0;
- // FIXME Abdel 10/02/07: Remove?
- // needed to make math superscript work on some systems
- // ideally, such special coding should not be necessary
- if (text == "^")
- key = Qt::Key_AsciiCircum;
-
- // FIXME Abdel 10/02/07: Minimal support for CJK, aka systems
- // with input methods. What should we do with
e->preeditString()?
- // Do we need an inputMethodQuery() method?
- // FIXME 2: we should take care also of UTF16 surrogates here.
- for (int i = 0; i < text.size(); ++i) {
- // FIXME: Needs for investigation, this key is not
really used,
- // the ctor below just check if key is different from 0.
- QKeyEvent ev(QEvent::KeyPress, key, Qt::NoModifier,
text[i]);
+ // 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())
+ startBlinkingCursor();
+ else
+ stopBlinkingCursor();
+
+ // if last_width is last length of preedit string.
+ static int last_width = 0;
+ if (!last_width && preedit_string.empty()) {
+ e->accept();
+ return;
+ }
+
+ QLPainter pain(&screen_);
+ buffer_view_->updateMetrics(false);
+ paintText(*buffer_view_, pain);
+ LyXFont font = buffer_view_->cursor().getFont();
+ FontMetrics const & fm = theFontMetrics(font);
+ int height = fm.maxHeight();
+ int cur_x = cursor_->rect().left();
+ int cur_y = cursor_->rect().bottom();
+
+ // redraw area of preedit string.
+ update(0, cur_y - height, GuiWorkArea::width(),
+ (height + 1) * preedit_lines_);
+
+ if (preedit_string.empty()) {
+ last_width = 0;
+ preedit_lines_ = 1;
+ e->accept();
+ return;
+ }
+
+ // FIXME: Describe these variables.
+ last_width = 1;
+ size_t cur_pos = 0;
+ size_t rStart = 0;
+ size_t rLength = 0;
+ int cur_visible = 0;
+ QList<QInputMethodEvent::Attribute> const & att(e->attributes());
+
+ // get attributes of input method cursor.
+ for (int i = 0; i < att.size(); ++i) {
+ if (att.at(i).type == QInputMethodEvent::Cursor) {
+ cur_pos = att.at(i).start;
+ cur_visible = att.at(i).length;
+ break;
+ }
+ }
+
+ size_t preedit_length = preedit_string.length();
+
+ // get position of selection in input method.
+ // FIXME: isn't there a way to do this simplier?
+ if (cur_pos < preedit_length) {
+ for (int i = 0; i < att.size(); ++i) {
+ if (att.at(i).type == QInputMethodEvent::TextFormat) {
+ if (att.at(i).start <= int(cur_pos)
+ && int(cur_pos) < att.at(i).start +
att.at(i).length) {
+ rStart = att.at(i).start;
+ rLength = att.at(i).length;
+ if (cur_visible == 0)
+ cur_pos += rLength;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ rStart = cur_pos;
+ rLength = 0;
+ }
+
+ int const right_margin = lyx::rightMargin();
+ Painter::preedit_style ps;
+ // Most often there would be only one line:
+ preedit_lines_ = 1;
+ for (size_t pos = 0; pos != preedit_length; ++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) > GuiWorkArea::width() -
right_margin) {
+ cur_x = right_margin;
+ cur_y += height + 1;
+ ++preedit_lines_;
+ }
+ // preedit strings are displayed with dashed underline
+ // and partial strings are displayed white on black indicating
+ // that we are in selecting mode in the input method.
+ // FIXME: rLength == preedit_length is not a changing condition
+ // FIXME: should be put out of the loop.
+ if (pos >= rStart
+ && pos < rStart + rLength
+ && !(cur_pos < rLength && rLength == preedit_length))
+ ps = Painter::preedit_selecting;
+
+ if (pos == cur_pos
+ && (cur_pos < rLength && rLength == preedit_length))
+ ps = Painter::preedit_cursor;
+
+ // draw one character and update cur_x.
+ cur_x += pain.preeditText(cur_x, cur_y, typed_char, font, ps);
+ }
+
+ // update the preedit string screen area.
+ update(0, cur_y - preedit_lines_*height, GuiWorkArea::width(),
+ (height + 1) * preedit_lines_);
+
+ // Don't forget to accept the event!
e->accept();
+}
+
+
+QVariant GuiWorkArea::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ QRect cur_r(0,0,0,0);
+ switch (query) {
+ // this is the CJK-specific composition window position.
+ case Qt::ImMicroFocus:
+ cur_r = cursor_->rect();
+ if (preedit_lines_ != 1)
+ cur_r.moveLeft(10);
+ cur_r.moveBottom(cur_r.bottom() + cur_r.height() *
preedit_lines_);
+ // return lower right of cursor in LyX.
+ return cur_r;
+ default:
+ return QWidget::inputMethodQuery(query);
+ }
}
} // namespace frontend
Modified: lyx-devel/trunk/src/frontends/qt4/GuiWorkArea.h
URL:
http://www.lyx.org/trac/file/lyx-devel/trunk/src/frontends/qt4/GuiWorkArea.h?rev=17671
==============================================================================
--- lyx-devel/trunk/src/frontends/qt4/GuiWorkArea.h (original)
+++ lyx-devel/trunk/src/frontends/qt4/GuiWorkArea.h Sun Apr 1 11:14:08 2007
@@ -142,6 +142,8 @@
void keyPressEvent(QKeyEvent * ev);
/// IM events
void inputMethodEvent(QInputMethodEvent * ev);
+ /// IM query
+ QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
public Q_SLOTS:
/// Adjust the LyX buffer view with the position of the scrollbar.
@@ -173,6 +175,8 @@
bool need_resize_;
///
bool schedule_redraw_;
+ ///
+ int preedit_lines_;
};
} // namespace frontend