From 099a4adc92be2b735dc66d6e6a2eb689d5531fd5 Mon Sep 17 00:00:00 2001 From: Abdelrazak Younes Date: Sun, 1 Apr 2007 09:14:08 +0000 Subject: [PATCH] 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. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@17671 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/frontends/Painter.C | 48 +++++++++ src/frontends/Painter.h | 16 +++ src/frontends/qt4/GuiWorkArea.C | 166 ++++++++++++++++++++++++++++---- src/frontends/qt4/GuiWorkArea.h | 4 + 4 files changed, 217 insertions(+), 17 deletions(-) diff --git a/src/frontends/Painter.C b/src/frontends/Painter.C index e893aafdbb..845106188a 100644 --- a/src/frontends/Painter.C +++ b/src/frontends/Painter.C @@ -84,6 +84,39 @@ void Painter::buttonText(int x, int y, docstring const & str, } +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 @@ void Painter::underline(LyXFont const & f, int x, int y, int width) 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 diff --git a/src/frontends/Painter.h b/src/frontends/Painter.h index 2b3de17435..0ac00c4715 100644 --- a/src/frontends/Painter.h +++ b/src/frontends/Painter.h @@ -66,6 +66,14 @@ public: 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() {} /// draw a line from point to point @@ -157,11 +165,19 @@ public: 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 void buttonFrame(int x, int y, int w, int h); diff --git a/src/frontends/qt4/GuiWorkArea.C b/src/frontends/qt4/GuiWorkArea.C index 0d28ddac1a..5f194ffaac 100644 --- a/src/frontends/qt4/GuiWorkArea.C +++ b/src/frontends/qt4/GuiWorkArea.C @@ -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 #include #include +#include #include #include @@ -160,7 +162,8 @@ SyntheticMouseEvent::SyntheticMouseEvent() 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(); @@ -299,6 +302,8 @@ void GuiWorkArea::mousePressEvent(QMouseEvent * e) return; } + inputContext()->reset(); + FuncRequest const cmd(LFUN_MOUSE_PRESS, e->x(), e->y(), q_button_state(e->button())); dispatch(cmd, q_key_state(e->modifiers())); @@ -573,8 +578,16 @@ void GuiWorkArea::removeCursor() 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,26 +596,145 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) 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 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 } // namespace lyx diff --git a/src/frontends/qt4/GuiWorkArea.h b/src/frontends/qt4/GuiWorkArea.h index 6f2832a5d8..73ca142697 100644 --- a/src/frontends/qt4/GuiWorkArea.h +++ b/src/frontends/qt4/GuiWorkArea.h @@ -142,6 +142,8 @@ private: 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 @@ private: bool need_resize_; /// bool schedule_redraw_; + /// + int preedit_lines_; }; } // namespace frontend -- 2.39.2