1 /*
2
3 Copyright (c) 2010-2013 uim Project https://github.com/uim/uim
4
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. Neither the name of authors nor the names of its contributors
17 may be used to endorse or promote products derived from this software
18 without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 SUCH DAMAGE.
31 */
32 #include "caretstateindicator.h"
33
34 #include <QtCore/QRect>
35 #include <QtCore/QStringList>
36 #include <QtCore/QTimer>
37 #include <QtCore/QVariant>
38 #include <QtGui/QMoveEvent>
39 #if QT_VERSION < 0x050000
40 # include <QtGui/QApplication>
41 # include <QtGui/QHBoxLayout>
42 # include <QtGui/QLabel>
43 #else
44 # include <QtWidgets/QApplication>
45 # include <QtWidgets/QHBoxLayout>
46 # include <QtWidgets/QLabel>
47 #endif
48
49 #include <uim/uim-scm.h>
50
51 const int CaretStateIndicator::SPACING = 3;
52 static const int DEFAULT_WINDOW_WIDTH = 20;
53 static const int DEFAULT_WINDOW_HEIGHT = 20;
54
55 // caret state indicator is a state indicator nearby the caret.
CaretStateIndicator(QWidget * parent)56 CaretStateIndicator::CaretStateIndicator(QWidget *parent):
57 QWidget(parent, Qt::ToolTip), m_window(0)
58 {
59 QHBoxLayout *layout = new QHBoxLayout;
60 layout->setMargin(0);
61 layout->setSpacing(0);
62 setLayout(layout);
63
64 m_timer = new QTimer(this);
65 connect(m_timer, SIGNAL(timeout()), this, SLOT(hide()));
66 }
67
~CaretStateIndicator()68 CaretStateIndicator::~CaretStateIndicator()
69 {
70 while (!m_labelList.isEmpty())
71 delete m_labelList.takeFirst();
72 }
73
update(const QString & str)74 void CaretStateIndicator::update(const QString &str)
75 {
76 bool isEnabled = uim_scm_symbol_value_bool("bridge-show-input-state?");
77 char *type = uim_scm_c_symbol(uim_scm_symbol_value("bridge-show-with?"));
78 bool isMode = (qstrcmp(type, "mode") == 0);
79 free(type);
80 bool isModeOn
81 = uim_scm_symbol_value_bool("bridge-show-input-state-mode-on?");
82 if (isEnabled && !(isMode && !isModeOn)) {
83 updateLabels(str);
84 if (!isMode) {
85 int time = uim_scm_symbol_value_int(
86 "bridge-show-input-state-time-length");
87 if (time != 0)
88 setTimeout(time);
89 }
90 setVisible(true);
91 } else if (isMode && !isModeOn) {
92 setVisible(false);
93 }
94 }
95
updateLabels(const QString & str)96 void CaretStateIndicator::updateLabels(const QString &str)
97 {
98 if (!str.isEmpty()) {
99 QStringList lines = str.split('\n', QString::SkipEmptyParts);
100 QStringList cols;
101 for (int i = 0; i < lines.count(); i++) {
102 if (lines.at(i).startsWith(QLatin1String("branch\t"))) {
103 QStringList branchLines = lines.at(i).split('\t');
104 if (branchLines.count() > 2)
105 cols.append(branchLines.at(2));
106 }
107 }
108 int colsCount = cols.count();
109 int labelCount = m_labelList.count();
110 for (int i = labelCount; i < colsCount; i++) {
111 QLabel *label = new QLabel;
112 label->setFrameStyle(QFrame::Box | QFrame::Plain);
113 label->setMinimumSize(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
114 label->setAlignment(Qt::AlignCenter);
115 m_labelList.append(label);
116 layout()->addWidget(label);
117 }
118 for (int i = colsCount; i < labelCount; i++) {
119 QLabel *label = m_labelList.takeAt(colsCount);
120 layout()->removeWidget(label);
121 delete label;
122 }
123 for (int i = 0; i < colsCount; i++)
124 m_labelList[i]->setText(cols[i]);
125 }
126 QWidget *widget = QApplication::focusWidget();
127 if (widget) {
128 QRect rect = widget->inputMethodQuery(Qt::ImMicroFocus).toRect();
129 move(widget->mapToGlobal(rect.bottomLeft())
130 + QPoint(0, CaretStateIndicator::SPACING));
131 m_window = widget->window();
132 m_window->installEventFilter(this);
133 }
134 }
135
setTimeout(int second)136 void CaretStateIndicator::setTimeout(int second)
137 {
138 if (m_timer->isActive())
139 m_timer->stop();
140 m_timer->start(1000 * second);
141 }
142
eventFilter(QObject * obj,QEvent * event)143 bool CaretStateIndicator::eventFilter(QObject *obj, QEvent *event)
144 {
145 if (obj == m_window) {
146 if (event->type() == QEvent::Move) {
147 QMoveEvent *moveEvent = static_cast<QMoveEvent *>(event);
148 move(pos() + moveEvent->pos() - moveEvent->oldPos());
149 }
150 return false;
151 }
152 return QWidget::eventFilter(obj, event);
153 }
154