/TeXmacs-1.0.7.11-src/src/Plugins/Qt/QTMWidget.cpp
C++ | 830 lines | 602 code | 108 blank | 120 comment | 133 complexity | 0e016c92abefb8303e941fbf1025b450 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0, MPL-2.0-no-copyleft-exception
1
2/******************************************************************************
3* MODULE : QTMWidget.cpp
4* DESCRIPTION: QT Texmacs widget class
5* COPYRIGHT : (C) 2008 Massimiliano Gubinelli and Joris van der Hoeven
6*******************************************************************************
7* This software falls under the GNU general public license version 3 or later.
8* It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9* in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10******************************************************************************/
11
12#include <QtGui>
13
14#include "QTMWidget.hpp"
15#include "qt_renderer.hpp"
16#include "qt_gui.hpp"
17#include "qt_utilities.hpp"
18#include "qt_simple_widget.hpp"
19#include "converter.hpp"
20
21#include "config.h"
22#include "message.hpp"
23
24#ifdef USE_CAIRO
25#include "Cairo/cairo_renderer.hpp"
26#include "Cairo/tm_cairo.hpp"
27
28#if defined(Q_WS_X11)
29#include <QX11Info>
30extern Drawable qt_x11Handle(const QPaintDevice *pd);
31extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
32#undef KeyPress // conflict between QEvent::KeyPrees and X11 defintion
33#endif // Q_WS_X11
34
35#endif // USE_CAIRO
36
37#include <QEvent>
38
39#define PIXEL 256
40
41QSet<QTMWidget*> QTMWidget::all_widgets;
42
43
44hashmap<int,string> qtkeymap (0);
45hashmap<int,string> qtdeadmap (0);
46
47inline void
48scale (QPoint& point) {
49 point.rx() *= PIXEL; point.ry() *= -PIXEL;
50}
51
52inline void
53map (int code, string name) {
54 qtkeymap(code) = name;
55}
56inline void
57deadmap (int code, string name) {
58 qtdeadmap(code) = name;
59}
60
61void
62initkeymap () {
63 map (Qt::Key_Space , "space");
64 map (Qt::Key_Return , "return");
65 map (Qt::Key_Tab , "tab");
66 map (Qt::Key_Backspace , "backspace");
67 map (Qt::Key_Enter , "enter");
68 map (Qt::Key_Escape , "escape");
69 map (Qt::Key_Backspace , "backspace");
70 map (Qt::Key_Up , "up" );
71 map (Qt::Key_Down , "down" );
72 map (Qt::Key_Left , "left" );
73 map (Qt::Key_Right , "right" );
74 map (Qt::Key_F1 , "F1" );
75 map (Qt::Key_F2 , "F2" );
76 map (Qt::Key_F3 , "F3" );
77 map (Qt::Key_F4 , "F4" );
78 map (Qt::Key_F5 , "F5" );
79 map (Qt::Key_F6 , "F6" );
80 map (Qt::Key_F7 , "F7" );
81 map (Qt::Key_F8 , "F8" );
82 map (Qt::Key_F9 , "F9" );
83 map (Qt::Key_F10 , "F10" );
84 map (Qt::Key_F11 , "F11" );
85 map (Qt::Key_F12 , "F12" );
86 map (Qt::Key_F13 , "F13" );
87 map (Qt::Key_F14 , "F14" );
88 map (Qt::Key_F15 , "F15" );
89 map (Qt::Key_F16 , "F16" );
90 map (Qt::Key_F17 , "F17" );
91 map (Qt::Key_F18 , "F18" );
92 map (Qt::Key_F19 , "F19" );
93 map (Qt::Key_F20 , "F20" );
94 map (Qt::Key_F21 , "F21" );
95 map (Qt::Key_F22 , "F22" );
96 map (Qt::Key_F23 , "F23" );
97 map (Qt::Key_F24 , "F24" );
98 map (Qt::Key_F25 , "F25" );
99 map (Qt::Key_F26 , "F26" );
100 map (Qt::Key_F27 , "F27" );
101 map (Qt::Key_F28 , "F28" );
102 map (Qt::Key_F29 , "F29" );
103 map (Qt::Key_F30 , "F30" );
104 map (Qt::Key_F31 , "F31" );
105 map (Qt::Key_F32 , "F32" );
106 map (Qt::Key_F33 , "F33" );
107 map (Qt::Key_F34 , "F34" );
108 map (Qt::Key_F35 , "F35" );
109 map (Qt::Key_Insert , "insert" );
110 map (Qt::Key_Delete , "delete" );
111 map (Qt::Key_Home , "home" );
112 map (Qt::Key_End , "end" );
113 map (Qt::Key_PageUp , "pageup" );
114 map (Qt::Key_PageDown , "pagedown" );
115 map (Qt::Key_ScrollLock, "scrolllock" );
116 map (Qt::Key_Pause , "pause" );
117 map (Qt::Key_SysReq , "sysreq" );
118 map (Qt::Key_Stop , "stop" );
119 map (Qt::Key_Menu , "menu" );
120 map (Qt::Key_Print , "print" );
121 map (Qt::Key_Select , "select" );
122 map (Qt::Key_Execute , "execute" );
123 map (Qt::Key_Help , "help" );
124
125 deadmap (Qt::Key_Dead_Acute , "acute");
126 deadmap (Qt::Key_Dead_Grave , "grave");
127 deadmap (Qt::Key_Dead_Diaeresis , "umlaut");
128 deadmap (Qt::Key_Dead_Circumflex, "hat");
129 deadmap (Qt::Key_Dead_Tilde , "tilde");
130
131 // map (0x0003 , "K-enter");
132 // map (Qt::Key_Begin , "begin" );
133 // map (Qt::Key_PrintScreen , "printscreen" );
134 // map (Qt::Key_Break , "break" );
135 // map (Qt::Key_User , "user" );
136 // map (Qt::Key_System , "system" );
137 // map (Qt::Key_Reset , "reset" );
138 // map (Qt::Key_ClearLine , "clear" );
139 // map (Qt::Key_ClearDisplay, "cleardisplay" );
140 // map (Qt::Key_InsertLine , "insertline" );
141 // map (Qt::Key_DeleteLine , "deleteline" );
142 // map (Qt::Key_InsertChar , "insert" );
143 // map (Qt::Key_DeleteChar , "delete" );
144 // map (Qt::Key_Prev , "prev" );
145 // map (Qt::Key_Next , "next" );
146 // map (Qt::Key_Undo , "undo" );
147 // map (Qt::Key_Redo , "redo" );
148 // map (Qt::Key_Find , "find" );
149 // map (Qt::Key_ModeSwitchFunctionKey, "modeswitch" );
150}
151
152
153
154QTMWidget::QTMWidget (simple_widget_rep *_wid)
155 : QTMScrollView (), backingPixmap(), imwidget(NULL) {
156 setObjectName("A QTMWidget");
157 setProperty ("texmacs_widget", QVariant::fromValue ((void*) _wid));
158 surface()->setMouseTracking (true);
159 setFocusPolicy (Qt::StrongFocus);
160 backing_pos = origin();
161 setAttribute(Qt::WA_InputMethodEnabled);
162}
163
164
165QTMWidget::~QTMWidget () {
166 if (DEBUG_QT) cout << "destroying " << this << LF;
167}
168
169void
170QTMWidget::invalidate_rect (int x1, int y1, int x2, int y2) {
171#ifdef Q_WS_MAC
172 //HACK: for unknown reasons we need to enlarge the invalid rect to prevent
173 //artifacts while moving the cursor (for example at the end of a formula like
174 // $a+f$. These artifacts seems present only on 64 bit Macs.
175 rectangle r = rectangle (x1-10, y1-10, x2+10, y2+10);
176#else
177 rectangle r = rectangle (x1, y1, x2, y2);
178#endif
179 // cout << "invalidating " << r << LF;
180 invalid_regions = invalid_regions | rectangles (r);
181}
182
183void
184QTMWidget::invalidate_all () {
185 QSize sz = surface()->size();
186 // QPoint pt = QAbstractScrollArea::viewport()->pos();
187 //cout << "invalidate all " << LF;
188 invalid_regions = rectangles();
189 invalidate_rect (0, 0, sz.width(), sz.height());
190}
191
192
193basic_renderer_rep*
194QTMWidget::getRenderer() {
195#ifdef USE_CAIRO
196 cairo_renderer_rep *ren = the_cairo_renderer ();
197 cairo_surface_t *surf;
198#ifdef Q_WS_X11
199 //const QX11Info & info = x11Info();//qt_x11Info(this);
200 // Display *dpy = x11Info().display();
201 //backingPixmap = QPixmap(width(),height());
202 //cout << backingPixmap.width() << LF;
203 Display *dpy = QX11Info::display();
204 Drawable drawable = backingPixmap.handle();
205 Visual *visual = (Visual*)(backingPixmap.x11Info().visual());
206 surf = tm_cairo_xlib_surface_create (dpy, drawable, visual,
207 backingPixmap.width (), backingPixmap.height ());
208#elif defined(Q_WS_MAC)
209 surf = tm_cairo_quartz_surface_create_for_cg_context (
210 (CGContextRef)(this->macCGHandle()), width(), height());
211#endif
212 cairo_t *ct = tm_cairo_create (surf);
213 ren->begin (ct);
214 tm_cairo_surface_destroy (surf);
215 tm_cairo_destroy (ct);
216#else
217 qt_renderer_rep * ren = the_qt_renderer();
218 ren->begin(&backingPixmap);
219#endif
220 return ren;
221}
222
223void
224QTMWidget::repaint_invalid_regions () {
225
226 // this function is called by the qt_gui::update method to keep the backing
227 // store in sync and propagate the changes to the surface on screen.
228 // first we check that the backing store geometry is right and then we
229 // request to the texmacs canvas widget to repaint the regions which were
230 // marked invalid. Subsequently, for each succesfully repainted region, we
231 // propagate its contents from the backing store to the onscreen surface.
232 // If repaint has been interrupted we do not propagate the changes and proceed
233 // to mark the region invalid again.
234
235 QRegion qrgn;
236 // qrgn is to keep track of the area on the sceen which needs to be updated
237
238 // update backing store origin wrt. TeXmacs document
239 if ( backing_pos != origin() ) {
240
241 int dx = origin().x() - backing_pos.x();
242 int dy = origin().y() - backing_pos.y();
243 backing_pos = origin();
244
245 QPixmap newBackingPixmap (backingPixmap.size());
246 QPainter p (&newBackingPixmap);
247 //newBackingPixmap.fill(Qt::black);
248 p.drawPixmap(-dx,-dy,backingPixmap);
249 p.end();
250 backingPixmap = newBackingPixmap;
251 //cout << "SCROLL CONTENTS BY " << dx << " " << dy << LF;
252
253 QSize sz = backingPixmap.size();
254
255 rectangles invalid;
256 while (!is_nil(invalid_regions)) {
257 rectangle r = invalid_regions->item ;
258 // rectangle q = rectangle(r->x1+dx,r->y1-dy,r->x2+dx,r->y2-dy);
259 rectangle q = rectangle(r->x1-dx,r->y1-dy,r->x2-dx,r->y2-dy);
260 invalid = rectangles (q, invalid);
261 //cout << r << " ---> " << q << LF;
262 invalid_regions = invalid_regions->next;
263 }
264 invalid_regions= invalid &
265 rectangles(rectangle(0,0,
266 sz.width(),sz.height())) ;
267
268 if (dy<0)
269 invalidate_rect(0,0,sz.width(),min(sz.height(),-dy));
270 else if (dy>0)
271 invalidate_rect(0,max(0,sz.height()-dy),sz.width(),sz.height());
272
273 if (dx<0)
274 invalidate_rect(0,0,min(-dx,sz.width()),sz.height());
275 else if (dx>0)
276 invalidate_rect(max(0,sz.width()-dx),0,sz.width(),sz.height());
277
278 // we cal update now to allow repainint of invalid regions
279 // this cannot be done directly since interpose handler needs
280 // to be run at least once in some situations
281 // (for example when scrolling is initiated by TeXmacs itself)
282 //the_gui->update();
283 // QAbstractScrollArea::viewport()->scroll(-dx,-dy);
284 // QAbstractScrollArea::viewport()->update();
285 qrgn += QRect(QPoint(0,0),sz);
286 }
287
288
289 // update backing store size
290 {
291 QSize _oldSize = backingPixmap.size();
292 QSize _newSize = surface()->size();
293 if (_newSize != _oldSize) {
294 // cout << "RESIZING BITMAP"<< LF;
295 QPixmap newBackingPixmap (_newSize);
296 QPainter p (&newBackingPixmap);
297 p.drawPixmap(0,0,backingPixmap);
298 //p.fillRect(0, 0, _newSize.width(), _newSize.height(), Qt::red);
299 if (_newSize.width() >= _oldSize.width()) {
300 invalidate_rect(_oldSize.width(), 0, _newSize.width(), _newSize.height());
301 p.fillRect(QRect(_oldSize.width(), 0, _newSize.width()-_oldSize.width(), _newSize.height()), Qt::gray);
302 }
303 if (_newSize.height() >= _oldSize.height()) {
304 invalidate_rect(0,_oldSize.height(), _newSize.width(), _newSize.height());
305 p.fillRect(QRect(0,_oldSize.height(), _newSize.width(), _newSize.height()-_oldSize.height()), Qt::gray);
306 }
307 p.end();
308 backingPixmap = newBackingPixmap;
309 }
310 }
311
312 // repaint invalid rectangles
313 {
314 rectangles new_regions;
315 if (!is_nil (invalid_regions)) {
316 rectangle lub= least_upper_bound (invalid_regions);
317 if (area (lub) < 1.2 * area (invalid_regions))
318 invalid_regions= rectangles (lub);
319
320 basic_renderer_rep* ren = getRenderer();
321 tm_widget()->set_current_renderer(ren);
322
323 SI ox = -backing_pos.x()*PIXEL;
324 SI oy = backing_pos.y()*PIXEL;
325
326 rectangles rects = invalid_regions;
327 invalid_regions = rectangles();
328
329 while (!is_nil (rects)) {
330 rectangle r = copy (rects->item);
331 rectangle r0 = rects->item;
332 QRect qr = QRect(r0->x1, r0->y1, r0->x2 - r0->x1, r0->y2 - r0->y1);
333 //cout << "repainting " << r0 << "\n";
334 ren->set_origin(ox,oy);
335 ren->encode (r->x1, r->y1);
336 ren->encode (r->x2, r->y2);
337 ren->set_clipping (r->x1, r->y2, r->x2, r->y1);
338 tm_widget()->handle_repaint (r->x1, r->y2, r->x2, r->y1);
339 if (ren->interrupted ()) {
340 //cout << "interrupted repainting of " << r0 << "\n";
341 //ren->set_color(green);
342 //ren->line(r->x1, r->y1, r->x2, r->y2);
343 //ren->line(r->x1, r->y2, r->x2, r->y1);
344 invalidate_rect (r0->x1, r0->y1, r0->x2, r0->y2);
345 }
346 qrgn += qr;
347 rects = rects->next;
348 }
349
350 tm_widget()->set_current_renderer(NULL);
351 ren->end();
352 } // !is_nil(invalid_regions)
353
354 }
355
356 // propagate immediatly the changes to the screen
357 surface()->repaint(qrgn);
358
359}
360
361void
362QTMWidget::scrollContentsBy ( int dx, int dy ) {
363 QTMScrollView::scrollContentsBy (dx,dy);
364
365 force_update();
366 // we force an update of the internal state to be in sync with the moving
367 // scrollbars
368}
369
370void
371QTMWidget::resizeEvent( QResizeEvent* event ) {
372 (void) event;
373
374 // cout << "QTMWidget::resizeEvent (" << event->size().width()
375 // << "," << event->size().height() << ")" << LF;
376
377 the_gui -> process_resize(tm_widget(), 0, 0); // FIXME
378
379 // force_update();
380
381 //FIXME: I would like to have a force_update here but this cause a failed
382 //assertion in TeXmacs since the at the boot not every internal structure is
383 //initialized at this point. It seems not too difficult to fix but I
384 //postpone this to discuss with Joris.
385 //
386 //Not having a force_update results in some lack of sync of the surface
387 //while the user is actively resizing with the mouse.
388}
389
390
391
392
393void
394QTMWidget::paintEvent (QPaintEvent* event) {
395 // In the current implementation repainting take place during the call to
396 // the widget's repaint_invalid_regions method in the_gui::update. All
397 // we have to do is to take the backing store and put it on screen according
398 // to the QRegion marked invalid.
399 // CHECK: Maybe just put onscreen all the region bounding rectangle could not
400 // be so expensive.
401
402
403 if (DEBUG_QT)
404 {
405 QRect rect = event->rect ();
406 cout << "paintEvent ("<< rect.x() << "," << rect.y()
407 << "," << rect.width() << "," << rect.height() << ")" << LF ;
408 }
409
410 {
411 QPainter p (surface());
412 QVector<QRect> rects = event->region().rects();
413 for (int i=0; i< rects.count(); i++) {
414 QRect qr = rects.at(i);
415 p.drawPixmap(qr,backingPixmap,qr);
416 }
417 }
418
419}
420
421
422void
423QTMWidget::keyPressEvent (QKeyEvent* event) {
424 static bool fInit = false;
425 if (!fInit) {
426 if (DEBUG_QT)
427 cout << "Initializing keymap\n";
428 initkeymap();
429 fInit= true;
430 }
431
432 if (DEBUG_QT)
433 cout << "keypressed\n";
434 simple_widget_rep *wid = tm_widget();
435 if (!wid) return;
436
437 {
438 int key = event->key();
439 Qt::KeyboardModifiers mods = event->modifiers();
440
441 if (DEBUG_QT) {
442 cout << "key : " << key << LF;
443 cout << "text : " << event->text().toAscii().data() << LF;
444 cout << "count: " << event->text().count() << LF;
445 if (mods & Qt::ShiftModifier) cout << "shift\n";
446 if (mods & Qt::MetaModifier) cout << "meta\n";
447 if (mods & Qt::ControlModifier) cout << "control\n";
448 if (mods & Qt::KeypadModifier) cout << "keypad\n";
449 if (mods & Qt::AltModifier) cout << "alt\n";
450 }
451
452 string r;
453 if (qtkeymap->contains (key)) {
454 r = qtkeymap[key];
455 } else if (qtdeadmap->contains (key)) {
456 mods &=~ Qt::ShiftModifier;
457 r = qtdeadmap[key];
458 } else {
459 QString nss = event->text();
460 unsigned short unic= nss.data()[0].unicode();
461 if (unic < 32 && key < 128 && key > 0) {
462 if (((char) key) >= 'A' && ((char) key) <= 'Z') {
463 if ((mods & Qt::ShiftModifier) == 0)
464 key= (int) (key + ((int) 'a') - ((int) 'A'));
465 }
466 mods &=~ Qt::ShiftModifier;
467 r= string ((char) key);
468 } else {
469 switch(unic) {
470 case 96: r= "`";
471 // unicode to cork conversion not appropriate for this case...
472#ifdef Q_WS_MAC
473 // CHECKME: are these two MAC exceptions really needed?
474 if (mods & Qt::AltModifier) r= "grave";
475#endif
476 break;
477 case 168: r= "umlaut"; break;
478 case 180: r= "acute"; break;
479 // the following combining characters should be caught by qtdeadmap
480 case 0x300: r= "grave"; break;
481 case 0x301: r= "acute"; break;
482 case 0x302: r= "hat"; break;
483 case 0x308: r= "umlaut"; break;
484 case 0x33e: r= "tilde"; break;
485 default:
486 QByteArray buf= nss.toUtf8();
487 string rr (buf.constData(), buf.count());
488 r= utf8_to_cork (rr);
489 if (r == "<less>") r= "<";
490 if (r == "<gtr>") r= ">";
491 }
492#ifdef Q_WS_MAC
493 // CHECKME: are these two MAC exceptions really needed?
494 mods &=~ Qt::AltModifier;
495#endif
496 mods &=~ Qt::ShiftModifier;
497 }
498 }
499
500 if (r == "") return;
501
502#ifdef Q_WS_MAC
503 if (mods & Qt::ShiftModifier) r= "S-" * r;
504 if (mods & Qt::MetaModifier) r= "C-" * r; // The "Control" key
505 if (mods & Qt::AltModifier) r= "A-" * r;
506 if (mods & Qt::ControlModifier) r= "M-" * r; // The "Command" key
507 //if (mods & Qt::KeypadModifier) r= "K-" * r;
508#else
509 if (mods & Qt::ShiftModifier) r= "S-" * r;
510 if (mods & Qt::ControlModifier) r= "C-" * r;
511 if (mods & Qt::AltModifier) r= "A-" * r;
512 if (mods & Qt::MetaModifier) r= "M-" * r; // The "Windows" key
513 //if (mods & Qt::KeypadModifier) r= "K-" * r;
514#endif
515
516 if (DEBUG_QT)
517 cout << "key press: " << r << LF;
518 //int start= texmacs_time ();
519 //wid -> handle_keypress (r, texmacs_time());
520 the_gui -> process_keypress (wid, r, texmacs_time());
521 //int end= texmacs_time ();
522 //if (end > start) cout << "Keypress " << end - start << "\n";
523 // the_gui->update (); // FIXME: remove this line when
524 // edit_typeset_rep::get_env_value will be faster
525
526// needs_update();
527 }
528}
529
530static unsigned int
531mouse_state (QMouseEvent* event, bool flag) {
532 unsigned int i= 0;
533 Qt::MouseButtons bstate= event->buttons ();
534 Qt::MouseButton tstate= event->button ();
535 Qt::KeyboardModifiers kstate= event->modifiers ();
536 if (flag) bstate= bstate | tstate;
537 if ((bstate & Qt::LeftButton ) != 0) i += 1;
538 if ((bstate & Qt::MidButton ) != 0) i += 2;
539 if ((bstate & Qt::RightButton ) != 0) i += 4;
540 if ((bstate & Qt::XButton1 ) != 0) i += 8;
541 if ((bstate & Qt::XButton2 ) != 0) i += 16;
542#ifdef Q_WS_MAC
543 if ((kstate & Qt::AltModifier ) != 0) i = 2;
544 if ((kstate & Qt::MetaModifier ) != 0) i = 4;
545 if ((kstate & Qt::ShiftModifier ) != 0) i += 256;
546 if ((kstate & Qt::ControlModifier) != 0) i += 2048;
547#else
548 if ((kstate & Qt::ShiftModifier ) != 0) i += 256;
549 if ((kstate & Qt::ControlModifier) != 0) i += 512;
550 if ((kstate & Qt::AltModifier ) != 0) i += 2048;
551 if ((kstate & Qt::MetaModifier ) != 0) i += 16384;
552#endif
553 return i;
554}
555
556static string
557mouse_decode (unsigned int mstate) {
558 if (mstate & 1 ) return "left";
559 else if (mstate & 2 ) return "middle";
560 else if (mstate & 4 ) return "right";
561 else if (mstate & 8 ) return "up";
562 else if (mstate & 16) return "down";
563 return "unknown";
564}
565
566#if 0 // NOT USED
567static void setRoundedMask(QWidget *widget)
568{
569 QPixmap pixmap(widget->size());
570 QPainter painter(&pixmap);
571 painter.fillRect(pixmap.rect(), Qt::white);
572 painter.setBrush(Qt::black);
573#if (QT_VERSION >= 0x040400)
574 painter.drawRoundedRect(pixmap.rect(),8,8, Qt::AbsoluteSize);
575#else
576 painter.drawRect(pixmap.rect());
577#endif
578 widget->setMask(pixmap.createMaskFromColor(Qt::white));
579}
580#endif
581
582
583#if 0
584// OLD INPUT METHOD PREVIEW
585void
586QTMWidget::inputMethodEvent (QInputMethodEvent* event) {
587 if (! imwidget) {
588 imwidget = new QLabel(this);
589 imwidget->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
590 // imwidget->setAttribute(Qt::WA_TranslucentBackground);
591// imwidget->setAutoFillBackground(false);
592 imwidget->setAutoFillBackground(true);
593 imwidget->setWindowOpacity(0.5);
594 imwidget->setFocusPolicy(Qt::NoFocus);
595 QPalette pal = imwidget->palette();
596// pal.setColor(QPalette::Window, QColor(0,0,255,80));
597 pal.setColor(QPalette::Window, QColor(0,0,255,255));
598 pal.setColor(QPalette::WindowText, Qt::white);
599 imwidget->setPalette(pal);
600 QFont f = imwidget->font();
601 f.setPointSize(30);
602 imwidget->setFont(f);
603 imwidget->setMargin(5);
604 }
605
606 QString const & preedit_string = event->preeditString();
607 QString const & commit_string = event->commitString();
608
609 if (preedit_string.isEmpty()) {
610 imwidget->hide();
611 } else {
612 if (DEBUG_QT)
613 cout << "IM preediting :" << preedit_string.toUtf8().data() << LF;
614 imwidget->setText(preedit_string);
615 imwidget->adjustSize();
616 QSize sz = size();
617 QRect g = imwidget->geometry();
618 QPoint c = mapToGlobal(cursor_pos);
619 c += QPoint(5,5);
620 // g.moveCenter(QPoint(sz.width()/2,sz.height()/2));
621 g.moveTopLeft(c);
622 if (DEBUG_QT)
623 cout << "IM hotspot: " << cursor_pos.x() << "," << cursor_pos.y() << LF;
624 imwidget->setGeometry(g);
625 // setRoundedMask(imwidget);
626 imwidget->show();
627#ifdef QT_MAC_USE_COCOA
628 // HACK: we unexplicably loose the focus even when showing the small window,
629 // so we need to restore it manually.....
630 // The following fixes the problem (but I do not really understand why it
631 // happens)
632 // Maybe this is a Qt/Cocoa bug.
633 this->window()->activateWindow();
634#endif
635 }
636
637 if (!commit_string.isEmpty()) {
638 if (DEBUG_QT)
639 cout << "IM committing :" << commit_string.toUtf8().data() << LF;
640
641 int key = 0;
642#if 1
643 for (int i = 0; i < commit_string.size(); ++i) {
644 QKeyEvent ev(QEvent::KeyPress, key, Qt::NoModifier, commit_string[i]);
645 keyPressEvent(&ev);
646 }
647#else
648 QKeyEvent ev(QEvent::KeyPress, key, Qt::NoModifier, commit_string);
649 keyPressEvent(&ev);
650#endif
651 }
652
653 event->accept();
654
655}
656
657QVariant
658QTMWidget::inputMethodQuery ( Qt::InputMethodQuery query ) const {
659 switch (query) {
660 case Qt::ImMicroFocus :
661 return QVariant(QRect(cursor_pos + QPoint(10,10),QSize(20,40)));
662 default:
663 return QVariant();
664 }
665}
666
667#else
668
669// NEW INPUT METHOD PREVIEW
670void
671QTMWidget::inputMethodEvent (QInputMethodEvent* event) {
672
673 QString const & preedit_string = event->preeditString();
674 QString const & commit_string = event->commitString();
675
676 if (!commit_string.isEmpty()) {
677 if (DEBUG_QT)
678 cout << "IM committing :" << commit_string.toUtf8().data() << LF;
679
680 int key = 0;
681#if 1
682 for (int i = 0; i < commit_string.size(); ++i) {
683 QKeyEvent ev(QEvent::KeyPress, key, Qt::NoModifier, commit_string[i]);
684 keyPressEvent(&ev);
685 }
686#else
687 QKeyEvent ev(QEvent::KeyPress, key, Qt::NoModifier, commit_string);
688 keyPressEvent(&ev);
689#endif
690 }
691
692 if (DEBUG_QT)
693 cout << "IM preediting :" << preedit_string.toUtf8().data() << LF;
694
695 string r = "pre-edit:";
696 if (!preedit_string.isEmpty())
697 {
698
699 // find cursor position in the preedit string
700 QList<QInputMethodEvent::Attribute> const & attrs = event->attributes();
701 // int pos = preedit_string.count();
702 int pos = 0;
703 bool visible_cur = false;
704 for(int i=0; i< attrs.count(); i++)
705 if (attrs[i].type == QInputMethodEvent::Cursor) {
706 pos = attrs[i].start;
707 visible_cur = (attrs[i].length != 0);
708 }
709
710 // find selection in the preedit string
711 int sel_start = 0;
712 int sel_length = 0;
713 if (pos < preedit_string.count()) {
714 for(int i=0; i< attrs.count(); i++)
715 if ((attrs[i].type == QInputMethodEvent::TextFormat) &&
716 (attrs[i].start <= pos) && (pos < attrs[i].start + attrs[i].length)) {
717 sel_start = attrs[i].start;
718 sel_length = attrs[i].length;
719 if (!visible_cur) pos += attrs[i].length;
720 }
721 } else {
722 sel_start = pos;
723 sel_length = 0;
724 }
725
726 r = r * as_string(pos) * ":"
727 * from_qstring(preedit_string);
728 }
729 simple_widget_rep *wid = tm_widget();
730 if (wid)
731 the_gui -> process_keypress (wid, r, texmacs_time());
732 event->accept();
733}
734
735QVariant
736QTMWidget::inputMethodQuery ( Qt::InputMethodQuery query ) const {
737 switch (query) {
738 case Qt::ImMicroFocus :
739 return QVariant (QRect (cursor_pos, QSize (5,5)));
740 default:
741 return QWidget::inputMethodQuery (query);
742 }
743}
744
745
746#endif // input method variants
747
748
749
750void
751QTMWidget::mousePressEvent (QMouseEvent* event) {
752 simple_widget_rep *wid= tm_widget ();
753 if (!wid) return;
754 QPoint point = event->pos() + origin();
755 scale (point);
756 unsigned int mstate= mouse_state (event, false);
757 string s= "press-" * mouse_decode (mstate);
758 the_gui -> process_mouse (wid, s, point.x (), point.y (),
759 mstate, texmacs_time ());
760 // wid -> handle_mouse (s, point.x (), point.y (), mstate, texmacs_time ());
761 if (DEBUG_QT)
762 cout << "mouse event: " << s << " at "
763 << point.x () << ", " << point.y () << LF;
764}
765
766void
767QTMWidget::mouseReleaseEvent (QMouseEvent* event) {
768 simple_widget_rep *wid = tm_widget();
769 if (!wid) return;
770 QPoint point = event->pos() + origin();
771 scale (point);
772 unsigned int mstate= mouse_state (event, true);
773 string s= "release-" * mouse_decode (mstate);
774 the_gui -> process_mouse (wid, s, point.x (), point.y (),
775 mstate, texmacs_time ());
776// wid -> handle_mouse (s, point.x (), point.y (), mstate, texmacs_time ());
777 if (DEBUG_QT)
778 cout << "mouse event: " << s << " at "
779 << point.x () << ", " << point.y () << LF;
780}
781
782void
783QTMWidget::mouseMoveEvent (QMouseEvent* event) {
784 simple_widget_rep *wid = tm_widget();
785 if (!wid) return;
786 QPoint point = event->pos() + origin();
787 scale (point);
788 unsigned int mstate= mouse_state (event, false);
789 string s= "move";
790 the_gui -> process_mouse (wid, s, point.x (), point.y (),
791 mstate, texmacs_time ());
792// wid -> handle_mouse (s, point.x (), point.y (), mstate, texmacs_time ());
793 if (DEBUG_QT)
794 cout << "mouse event: " << s << " at "
795 << point.x () << ", " << point.y () << LF;
796}
797
798
799bool
800QTMWidget::event (QEvent* event) {
801 if (event->type() == QEvent::KeyPress) {
802 QKeyEvent *ke = static_cast<QKeyEvent*> (event);
803 keyPressEvent (ke);
804 return true;
805 }
806 return QTMScrollView::event (event);
807}
808
809
810void
811QTMWidget::focusInEvent ( QFocusEvent * event ) {
812 if (DEBUG_QT) cout << "FOCUSIN" << LF;
813 simple_widget_rep *wid = tm_widget ();
814 if (wid) {
815 the_gui -> process_keyboard_focus (wid, true, texmacs_time());
816 //wid -> handle_keyboard_focus (true, texmacs_time ());
817 }
818 QTMScrollView::focusInEvent (event);
819}
820
821void
822QTMWidget::focusOutEvent ( QFocusEvent * event ) {
823 if (DEBUG_QT) cout << "FOCUSOUT" << LF;
824 simple_widget_rep *wid = tm_widget ();
825 if (wid) {
826 the_gui -> process_keyboard_focus (wid, false, texmacs_time());
827// wid -> handle_keyboard_focus (false, texmacs_time ());
828 }
829 QTMScrollView::focusOutEvent (event);
830}