mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-23 05:25:26 +00:00
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
This commit is contained in:
parent
44c4c02c5d
commit
099a4adc92
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user