]> git.lyx.org Git - lyx.git/commitdiff
Improved input method support by M. Iwami. I fixed some typo, and simplified the...
authorAbdelrazak Younes <younes@lyx.org>
Sun, 1 Apr 2007 09:14:08 +0000 (09:14 +0000)
committerAbdelrazak Younes <younes@lyx.org>
Sun, 1 Apr 2007 09:14:08 +0000 (09:14 +0000)
* 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
src/frontends/Painter.h
src/frontends/qt4/GuiWorkArea.C
src/frontends/qt4/GuiWorkArea.h

index e893aafdbb5bf0c6004ef3cf692e147fb1d25140..845106188a1c99dce21788b115833725a9db67f0 100644 (file)
@@ -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
index 2b3de17435f5b050708a212dee00e297ecce3e72..0ac00c4715a5c5296f8f79ee3c4b12ff885417d4 100644 (file)
@@ -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);
 
index 0d28ddac1a432bf178194a2a91c5a3995f110368..5f194ffaac402e5cc07f4181e50160a1e4df866e 100644 (file)
@@ -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 @@ 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<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
 } // namespace lyx
 
index 6f2832a5d89c6be7235a0c75bfdd408e154abf6c..73ca1426971de0d4818865045abe7919339b3790 100644 (file)
@@ -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