Back to index

texmacs  1.0.7.15
QTMWidget.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : QTMWidget.cpp
00004 * DESCRIPTION: QT Texmacs widget class
00005 * COPYRIGHT  : (C) 2008 Massimiliano Gubinelli and Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include <QtGui>
00013 
00014 #include "QTMWidget.hpp"
00015 #include "qt_renderer.hpp"
00016 #include "qt_gui.hpp"
00017 #include "qt_utilities.hpp"
00018 #include "qt_simple_widget.hpp"
00019 #include "converter.hpp"
00020 
00021 #include "config.h"
00022 #include "message.hpp" 
00023 
00024 #ifdef USE_CAIRO
00025 #include "Cairo/cairo_renderer.hpp"
00026 #include "Cairo/tm_cairo.hpp"
00027 
00028 #if defined(Q_WS_X11)
00029 #include <QX11Info>
00030 extern Drawable qt_x11Handle(const QPaintDevice *pd);
00031 extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
00032 #undef KeyPress  // conflict between QEvent::KeyPrees and X11 defintion
00033 #endif // Q_WS_X11
00034 
00035 #endif // USE_CAIRO
00036 
00037 #include <QEvent>
00038 
00039 #define PIXEL 256
00040 
00041 QSet<QTMWidget*> QTMWidget::all_widgets;
00042 
00043 
00044 hashmap<int,string> qtkeymap (0);
00045 hashmap<int,string> qtdeadmap (0);
00046 
00047 inline void
00048 scale (QPoint& point) {
00049   point.rx() *= PIXEL; point.ry() *= -PIXEL;
00050 }
00051 
00052 inline void
00053 map (int code, string name) {
00054   qtkeymap(code) = name;
00055 }
00056 inline void
00057 deadmap (int code, string name) {
00058   qtdeadmap(code) = name;
00059 }
00060 
00061 void
00062 initkeymap () {
00063   map (Qt::Key_Space     , "space");
00064   map (Qt::Key_Return    , "return");
00065   map (Qt::Key_Tab       , "tab");
00066   map (Qt::Key_Backspace , "backspace");
00067   map (Qt::Key_Enter     , "enter");
00068   map (Qt::Key_Escape    , "escape");
00069   map (Qt::Key_Backspace , "backspace");
00070   map (Qt::Key_Up        , "up" );
00071   map (Qt::Key_Down      , "down" );
00072   map (Qt::Key_Left      , "left" );
00073   map (Qt::Key_Right     , "right" );
00074   map (Qt::Key_F1        , "F1" );
00075   map (Qt::Key_F2        , "F2" );
00076   map (Qt::Key_F3        , "F3" );
00077   map (Qt::Key_F4        , "F4" );
00078   map (Qt::Key_F5        , "F5" );
00079   map (Qt::Key_F6        , "F6" );
00080   map (Qt::Key_F7        , "F7" );
00081   map (Qt::Key_F8        , "F8" );
00082   map (Qt::Key_F9        , "F9" );
00083   map (Qt::Key_F10       , "F10" );
00084   map (Qt::Key_F11       , "F11" );
00085   map (Qt::Key_F12       , "F12" );
00086   map (Qt::Key_F13       , "F13" );
00087   map (Qt::Key_F14       , "F14" );
00088   map (Qt::Key_F15       , "F15" );
00089   map (Qt::Key_F16       , "F16" );
00090   map (Qt::Key_F17       , "F17" );
00091   map (Qt::Key_F18       , "F18" );
00092   map (Qt::Key_F19       , "F19" );
00093   map (Qt::Key_F20       , "F20" );
00094   map (Qt::Key_F21       , "F21" );
00095   map (Qt::Key_F22       , "F22" );
00096   map (Qt::Key_F23       , "F23" );
00097   map (Qt::Key_F24       , "F24" );
00098   map (Qt::Key_F25       , "F25" );
00099   map (Qt::Key_F26       , "F26" );
00100   map (Qt::Key_F27       , "F27" );
00101   map (Qt::Key_F28       , "F28" );
00102   map (Qt::Key_F29       , "F29" );
00103   map (Qt::Key_F30       , "F30" );
00104   map (Qt::Key_F31       , "F31" );
00105   map (Qt::Key_F32       , "F32" );
00106   map (Qt::Key_F33       , "F33" );
00107   map (Qt::Key_F34       , "F34" );
00108   map (Qt::Key_F35       , "F35" );
00109   map (Qt::Key_Insert    , "insert" );
00110   map (Qt::Key_Delete    , "delete" );
00111   map (Qt::Key_Home      , "home" );
00112   map (Qt::Key_End       , "end" );
00113   map (Qt::Key_PageUp    , "pageup" );
00114   map (Qt::Key_PageDown  , "pagedown" );
00115   map (Qt::Key_ScrollLock, "scrolllock" );
00116   map (Qt::Key_Pause     , "pause" );
00117   map (Qt::Key_SysReq    , "sysreq" );
00118   map (Qt::Key_Stop      , "stop" );
00119   map (Qt::Key_Menu      , "menu" );
00120   map (Qt::Key_Print     , "print" );
00121   map (Qt::Key_Select    , "select" );
00122   map (Qt::Key_Execute   , "execute" );
00123   map (Qt::Key_Help      , "help" );
00124 
00125   deadmap (Qt::Key_Dead_Acute     , "acute");
00126   deadmap (Qt::Key_Dead_Grave     , "grave");
00127   deadmap (Qt::Key_Dead_Diaeresis , "umlaut");
00128   deadmap (Qt::Key_Dead_Circumflex, "hat");
00129   deadmap (Qt::Key_Dead_Tilde     , "tilde");
00130 
00131   // map (0x0003              , "K-enter");
00132   // map (Qt::Key_Begin       , "begin" );
00133   // map (Qt::Key_PrintScreen , "printscreen" );
00134   // map (Qt::Key_Break       , "break" );
00135   // map (Qt::Key_User        , "user" );
00136   // map (Qt::Key_System      , "system" );
00137   // map (Qt::Key_Reset       , "reset" );
00138   // map (Qt::Key_ClearLine   , "clear" );
00139   // map (Qt::Key_ClearDisplay, "cleardisplay" );
00140   // map (Qt::Key_InsertLine  , "insertline" );
00141   // map (Qt::Key_DeleteLine  , "deleteline" );
00142   // map (Qt::Key_InsertChar  , "insert" );
00143   // map (Qt::Key_DeleteChar  , "delete" );
00144   // map (Qt::Key_Prev        , "prev" );
00145   // map (Qt::Key_Next        , "next" );
00146   // map (Qt::Key_Undo        , "undo" );
00147   // map (Qt::Key_Redo        , "redo" );
00148   // map (Qt::Key_Find        , "find" );
00149   // map (Qt::Key_ModeSwitchFunctionKey, "modeswitch" );
00150 }
00151 
00152 
00153 
00154 QTMWidget::QTMWidget (simple_widget_rep *_wid) 
00155   : QTMScrollView (), backingPixmap(), imwidget(NULL) {
00156   setObjectName("A QTMWidget");
00157   setProperty ("texmacs_widget", QVariant::fromValue ((void*) _wid));
00158   surface()->setMouseTracking (true);
00159   setFocusPolicy (Qt::StrongFocus);
00160   backing_pos = origin();
00161   setAttribute(Qt::WA_InputMethodEnabled);
00162 }
00163 
00164 
00165 QTMWidget::~QTMWidget () {
00166   if (DEBUG_QT) cout << "destroying " << this << LF;
00167 }
00168 
00169 void 
00170 QTMWidget::invalidate_rect (int x1, int y1, int x2, int y2) {
00171 #ifdef Q_WS_MAC
00172   //HACK: for unknown reasons we need to enlarge the invalid rect to prevent
00173   //artifacts while moving the cursor (for example at the end of a formula like
00174   // $a+f$. These artifacts seems present only on 64 bit Macs. 
00175   rectangle r = rectangle (x1-10, y1-10, x2+10, y2+10);
00176 #else
00177   rectangle r = rectangle (x1, y1, x2, y2);
00178 #endif
00179   // cout << "invalidating " << r << LF;
00180   invalid_regions = invalid_regions | rectangles (r);
00181 }
00182 
00183 void 
00184 QTMWidget::invalidate_all () {
00185   QSize sz = surface()->size();
00186  // QPoint pt = QAbstractScrollArea::viewport()->pos();
00187    //cout << "invalidate all " << LF;
00188   invalid_regions = rectangles();
00189   invalidate_rect (0, 0, sz.width(), sz.height());
00190 }
00191 
00192 
00193 basic_renderer_rep* 
00194 QTMWidget::getRenderer() {
00195 #ifdef USE_CAIRO
00196   cairo_renderer_rep *ren = the_cairo_renderer ();
00197   cairo_surface_t *surf;
00198 #ifdef Q_WS_X11
00199   //const QX11Info & info = x11Info();//qt_x11Info(this);
00200   //    Display *dpy = x11Info().display();
00201   //backingPixmap = QPixmap(width(),height());
00202   //cout << backingPixmap.width() << LF;
00203   Display *dpy = QX11Info::display();
00204   Drawable drawable = backingPixmap.handle();
00205   Visual *visual = (Visual*)(backingPixmap.x11Info().visual());
00206   surf = tm_cairo_xlib_surface_create (dpy, drawable, visual, 
00207                             backingPixmap.width (), backingPixmap.height ());
00208 #elif defined(Q_WS_MAC)
00209   surf = tm_cairo_quartz_surface_create_for_cg_context (
00210                     (CGContextRef)(this->macCGHandle()), width(), height());
00211 #endif
00212   cairo_t *ct = tm_cairo_create (surf);
00213   ren->begin (ct);
00214   tm_cairo_surface_destroy (surf);
00215   tm_cairo_destroy (ct);
00216 #else
00217   qt_renderer_rep * ren = the_qt_renderer();
00218   ren->begin(&backingPixmap);
00219 #endif
00220   return ren;
00221 }
00222 
00223 void
00224 QTMWidget::repaint_invalid_regions () {
00225 
00226   // this function is called by the qt_gui::update method to keep the backing
00227   // store in sync and propagate the changes to the surface on screen.
00228   // first we check that the backing store geometry is right and then we
00229   // request to the texmacs canvas widget to repaint the regions which were
00230   // marked invalid. Subsequently, for each succesfully repainted region, we
00231   // propagate its contents from the backing store to the onscreen surface.
00232   // If repaint has been interrupted we do not propagate the changes and proceed
00233   // to mark the region invalid again.
00234 
00235   QRegion qrgn; 
00236   // qrgn is to keep track of the area on the sceen which needs to be updated 
00237 
00238   // update backing store origin wrt. TeXmacs document
00239   if ( backing_pos != origin() ) {
00240 
00241     int dx =  origin().x() - backing_pos.x();
00242     int dy =  origin().y() - backing_pos.y();
00243     backing_pos = origin();
00244     
00245     QPixmap newBackingPixmap (backingPixmap.size());
00246     QPainter p (&newBackingPixmap);
00247     //newBackingPixmap.fill(Qt::black);
00248     p.drawPixmap(-dx,-dy,backingPixmap);
00249     p.end();
00250     backingPixmap = newBackingPixmap;
00251     //cout << "SCROLL CONTENTS BY " << dx << " " << dy << LF;
00252     
00253     QSize sz = backingPixmap.size();
00254     
00255     rectangles invalid;
00256     while (!is_nil(invalid_regions)) {
00257       rectangle r = invalid_regions->item ;
00258       //      rectangle q = rectangle(r->x1+dx,r->y1-dy,r->x2+dx,r->y2-dy);
00259       rectangle q = rectangle(r->x1-dx,r->y1-dy,r->x2-dx,r->y2-dy);
00260       invalid = rectangles (q, invalid);
00261       //cout << r << " ---> " << q << LF;
00262       invalid_regions = invalid_regions->next;
00263     }
00264     invalid_regions= invalid & 
00265     rectangles(rectangle(0,0,
00266                          sz.width(),sz.height())) ;
00267     
00268     if (dy<0) 
00269       invalidate_rect(0,0,sz.width(),min(sz.height(),-dy));
00270     else if (dy>0)
00271       invalidate_rect(0,max(0,sz.height()-dy),sz.width(),sz.height());
00272     
00273     if (dx<0) 
00274       invalidate_rect(0,0,min(-dx,sz.width()),sz.height());
00275     else if (dx>0)
00276       invalidate_rect(max(0,sz.width()-dx),0,sz.width(),sz.height());
00277     
00278     // we cal update now to allow repainint of invalid regions
00279     // this cannot be done directly since interpose handler needs
00280     // to be run at least once in some situations
00281     // (for example when scrolling is initiated by TeXmacs itself)
00282     //the_gui->update();
00283     //  QAbstractScrollArea::viewport()->scroll(-dx,-dy);
00284    // QAbstractScrollArea::viewport()->update();
00285     qrgn += QRect(QPoint(0,0),sz);
00286   }
00287   
00288   
00289   // update backing store size
00290   {
00291     QSize _oldSize = backingPixmap.size();
00292     QSize _newSize = surface()->size();
00293     if (_newSize != _oldSize) {
00294       // cout << "RESIZING BITMAP"<< LF;
00295       QPixmap newBackingPixmap (_newSize);
00296       QPainter p (&newBackingPixmap);
00297       p.drawPixmap(0,0,backingPixmap);
00298       //p.fillRect(0, 0, _newSize.width(), _newSize.height(), Qt::red);
00299       if (_newSize.width() >= _oldSize.width()) {
00300         invalidate_rect(_oldSize.width(), 0, _newSize.width(), _newSize.height());
00301         p.fillRect(QRect(_oldSize.width(), 0, _newSize.width()-_oldSize.width(), _newSize.height()), Qt::gray);
00302       }
00303       if (_newSize.height() >= _oldSize.height()) {
00304         invalidate_rect(0,_oldSize.height(), _newSize.width(), _newSize.height());
00305         p.fillRect(QRect(0,_oldSize.height(), _newSize.width(), _newSize.height()-_oldSize.height()), Qt::gray);
00306       }
00307       p.end();
00308       backingPixmap = newBackingPixmap;
00309     }
00310   }
00311   
00312   // repaint invalid rectangles
00313   {
00314     rectangles new_regions;
00315     if (!is_nil (invalid_regions)) {
00316       rectangle lub= least_upper_bound (invalid_regions);
00317       if (area (lub) < 1.2 * area (invalid_regions))
00318         invalid_regions= rectangles (lub);
00319       
00320       basic_renderer_rep* ren = getRenderer();
00321       tm_widget()->set_current_renderer(ren);
00322       
00323       SI ox = -backing_pos.x()*PIXEL;
00324       SI oy = backing_pos.y()*PIXEL;
00325       
00326       rectangles rects = invalid_regions;
00327       invalid_regions = rectangles();
00328       
00329       while (!is_nil (rects)) {
00330         rectangle r = copy (rects->item);
00331         rectangle r0 = rects->item;
00332         QRect qr = QRect(r0->x1, r0->y1, r0->x2 - r0->x1, r0->y2 - r0->y1);
00333         //cout << "repainting " << r0 << "\n";
00334         ren->set_origin(ox,oy); 
00335         ren->encode (r->x1, r->y1);
00336         ren->encode (r->x2, r->y2);
00337         ren->set_clipping (r->x1, r->y2, r->x2, r->y1);
00338         tm_widget()->handle_repaint (r->x1, r->y2, r->x2, r->y1);
00339         if (ren->interrupted ()) {
00340           //cout << "interrupted repainting of  " << r0 << "\n";
00341           //ren->set_color(green);
00342           //ren->line(r->x1, r->y1, r->x2, r->y2);
00343           //ren->line(r->x1, r->y2, r->x2, r->y1);
00344           invalidate_rect (r0->x1, r0->y1, r0->x2, r0->y2);
00345         } 
00346         qrgn += qr;
00347         rects = rects->next;
00348       }
00349       
00350       tm_widget()->set_current_renderer(NULL);
00351       ren->end();
00352     } // !is_nil(invalid_regions)
00353     
00354   }
00355 
00356   // propagate immediatly the changes to the screen  
00357   surface()->repaint(qrgn);
00358   
00359 }
00360 
00361 void 
00362 QTMWidget::scrollContentsBy ( int dx, int dy ) {
00363   QTMScrollView::scrollContentsBy (dx,dy);
00364 
00365   force_update();
00366   // we force an update of the internal state to be in sync with the moving
00367   // scrollbars
00368 }
00369 
00370 void 
00371 QTMWidget::resizeEvent( QResizeEvent* event ) {
00372   (void) event;
00373   
00374   // cout << "QTMWidget::resizeEvent (" << event->size().width()
00375   //      << "," << event->size().height() << ")" << LF;
00376   
00377   the_gui -> process_resize(tm_widget(), 0, 0); // FIXME
00378 
00379   // force_update();
00380 
00381   //FIXME: I would like to have a force_update here but this cause a failed
00382   //assertion in TeXmacs since the at the boot not every internal structure is
00383   //initialized at this point. It seems not too difficult to fix but I
00384   //postpone this to discuss with Joris. 
00385   //
00386   //Not having a force_update results in some lack of sync of the surface
00387   //while the user is actively resizing with the mouse.
00388 }
00389 
00390 
00391 
00392 
00393 void
00394 QTMWidget::paintEvent (QPaintEvent* event) {
00395   // In the current implementation repainting take place during the call to
00396   // the widget's repaint_invalid_regions method in the_gui::update. All
00397   // we have to do is to take the backing store and put it on screen according
00398   // to the QRegion marked invalid. 
00399   // CHECK: Maybe just put onscreen all the region bounding rectangle could not 
00400   // be so expensive.
00401   
00402   
00403   if (DEBUG_QT) 
00404   {
00405     QRect rect = event->rect ();
00406     cout << "paintEvent ("<< rect.x() << "," <<  rect.y()
00407     << "," <<  rect.width() << "," <<  rect.height() << ")" << LF ;
00408   }
00409     
00410   {    
00411     QPainter p (surface());
00412     QVector<QRect> rects = event->region().rects();
00413     for (int i=0; i< rects.count(); i++) {
00414       QRect qr = rects.at(i);
00415       p.drawPixmap(qr,backingPixmap,qr);
00416     }
00417   } 
00418   
00419 }
00420 
00421 
00422 void
00423 QTMWidget::keyPressEvent (QKeyEvent* event) {
00424   static bool fInit = false;
00425   if (!fInit) {
00426     if (DEBUG_QT)
00427       cout << "Initializing keymap\n";
00428     initkeymap();
00429     fInit= true;
00430   }
00431 
00432   if (DEBUG_QT)
00433     cout << "keypressed\n";
00434   simple_widget_rep *wid =  tm_widget();
00435   if (!wid) return;
00436 
00437   {
00438     int key = event->key();
00439     Qt::KeyboardModifiers mods = event->modifiers();
00440 
00441     if (DEBUG_QT) {
00442       cout << "key  : " << key << LF;
00443       cout << "text : " << event->text().toAscii().data() << LF;
00444       cout << "count: " << event->text().count() << LF;
00445       if (mods & Qt::ShiftModifier) cout << "shift\n";
00446       if (mods & Qt::MetaModifier) cout << "meta\n";
00447       if (mods & Qt::ControlModifier) cout << "control\n";
00448       if (mods & Qt::KeypadModifier) cout << "keypad\n";
00449       if (mods & Qt::AltModifier) cout << "alt\n";
00450     }
00451 
00452     string r;
00453 #ifdef __MINGW32__
00454     // denis begin
00455     if (event->text().count() == 1) {
00456       QChar c= event->text()[0];
00457       if (c.isPrint() && event->modifiers() != Qt::MetaModifier) {
00458        // not a control character or dead key or modifier
00459        char ac=c.toAscii();
00460        if (ac && ac != ' ') { // a true ascii printable
00461          r= ac;
00462          if (DEBUG_QT) cout << "ascii key= " <<r << "\n";      
00463          the_gui->process_keypress(wid, r, texmacs_time());
00464          return;
00465        }
00466       }
00467     }
00468     // denis end
00469 #endif
00470     if (qtkeymap->contains (key)) {
00471       r = qtkeymap[key];
00472     }
00473     else if (qtdeadmap->contains (key)) {
00474       mods &=~ Qt::ShiftModifier;
00475       r = qtdeadmap[key];
00476     }
00477     else {
00478       QString nss = event->text();
00479       unsigned short unic= nss.data()[0].unicode();
00480       if (unic < 32 && key < 128 && key > 0) {
00481         if (((char) key) >= 'A' && ((char) key) <= 'Z') {
00482           if ((mods & Qt::ShiftModifier) == 0)
00483             key= (int) (key + ((int) 'a') - ((int) 'A'));
00484         }
00485         mods &=~ Qt::ShiftModifier;
00486         r= string ((char) key);
00487       } else {
00488         switch(unic) {
00489         case 96:   r= "`"; 
00490             // unicode to cork conversion not appropriate for this case...
00491 #ifdef Q_WS_MAC
00492           // CHECKME: are these two MAC exceptions really needed?
00493                    if (mods & Qt::AltModifier) r= "grave";
00494 #endif
00495                    break;
00496         case 168:  r= "umlaut"; break;
00497         case 180:  r= "acute"; break;
00498         // the following combining characters should be caught by qtdeadmap
00499         case 0x300: r= "grave"; break;
00500         case 0x301: r= "acute"; break;
00501         case 0x302: r= "hat"; break;
00502         case 0x308: r= "umlaut"; break;
00503         case 0x33e: r= "tilde"; break;
00504         default:
00505           QByteArray buf= nss.toUtf8();
00506           string rr (buf.constData(), buf.count());
00507           r= utf8_to_cork (rr);
00508           if (r == "<less>") r= "<";
00509           if (r == "<gtr>") r= ">";
00510         }
00511 #ifdef Q_WS_MAC
00512         // CHECKME: are these two MAC exceptions really needed?
00513         mods &=~ Qt::AltModifier;
00514 #endif
00515         mods &=~ Qt::ShiftModifier;
00516       }
00517     }
00518 
00519     if (r == "") return;
00520 
00521 #ifdef Q_WS_MAC
00522     if (mods & Qt::ShiftModifier) r= "S-" * r;
00523     if (mods & Qt::MetaModifier) r= "C-" * r;        // The "Control" key
00524     if (mods & Qt::AltModifier) r= "A-" * r;
00525     if (mods & Qt::ControlModifier) r= "M-" * r;  // The "Command" key
00526     //if (mods & Qt::KeypadModifier) r= "K-" * r;
00527 #else
00528     if (mods & Qt::ShiftModifier) r= "S-" * r;
00529     if (mods & Qt::ControlModifier) r= "C-" * r;
00530     if (mods & Qt::AltModifier) r= "A-" * r;
00531     if (mods & Qt::MetaModifier) r= "M-" * r;     // The "Windows" key
00532     //if (mods & Qt::KeypadModifier) r= "K-" * r;
00533 #endif
00534 
00535     if (DEBUG_QT)
00536       cout << "key press: " << r << LF;
00537     //int start= texmacs_time ();
00538     //wid -> handle_keypress (r, texmacs_time());
00539     the_gui -> process_keypress (wid, r, texmacs_time());
00540     //int end= texmacs_time ();
00541     //if (end > start) cout << "Keypress " << end - start << "\n";
00542   //  the_gui->update (); // FIXME: remove this line when
00543                         // edit_typeset_rep::get_env_value will be faster
00544     
00545 //    needs_update();
00546   }
00547 }
00548 
00549 static unsigned int
00550 mouse_state (QMouseEvent* event, bool flag) {
00551   unsigned int i= 0;
00552   Qt::MouseButtons bstate= event->buttons ();
00553   Qt::MouseButton  tstate= event->button ();
00554   Qt::KeyboardModifiers kstate= event->modifiers ();
00555   if (flag) bstate= bstate | tstate;
00556   if ((bstate & Qt::LeftButton     ) != 0) i += 1;
00557   if ((bstate & Qt::MidButton      ) != 0) i += 2;
00558   if ((bstate & Qt::RightButton    ) != 0) i += 4;
00559   if ((bstate & Qt::XButton1       ) != 0) i += 8;
00560   if ((bstate & Qt::XButton2       ) != 0) i += 16;
00561 #ifdef Q_WS_MAC
00562   if ((kstate & Qt::AltModifier    ) != 0) i = 2;
00563   if ((kstate & Qt::MetaModifier   ) != 0) i = 4;
00564   if ((kstate & Qt::ShiftModifier  ) != 0) i += 256;
00565   if ((kstate & Qt::ControlModifier) != 0) i += 2048;
00566 #else
00567   if ((kstate & Qt::ShiftModifier  ) != 0) i += 256;
00568   if ((kstate & Qt::ControlModifier) != 0) i += 512;
00569   if ((kstate & Qt::AltModifier    ) != 0) i += 2048;
00570   if ((kstate & Qt::MetaModifier   ) != 0) i += 16384;
00571 #endif
00572   return i;
00573 }
00574 
00575 static string
00576 mouse_decode (unsigned int mstate) {
00577   if      (mstate & 1 ) return "left";
00578   else if (mstate & 2 ) return "middle";
00579   else if (mstate & 4 ) return "right";
00580   else if (mstate & 8 ) return "up";
00581   else if (mstate & 16) return "down";
00582   return "unknown";
00583 }
00584 
00585 #if 0 // NOT USED
00586 static void setRoundedMask(QWidget *widget)
00587 {
00588   QPixmap pixmap(widget->size());
00589   QPainter painter(&pixmap);
00590   painter.fillRect(pixmap.rect(), Qt::white);
00591   painter.setBrush(Qt::black);
00592 #if (QT_VERSION >= 0x040400)
00593   painter.drawRoundedRect(pixmap.rect(),8,8, Qt::AbsoluteSize);
00594 #else
00595   painter.drawRect(pixmap.rect());
00596 #endif
00597   widget->setMask(pixmap.createMaskFromColor(Qt::white));
00598 }
00599 #endif
00600 
00601 
00602 #if 0 
00603 // OLD INPUT METHOD PREVIEW
00604 void
00605 QTMWidget::inputMethodEvent (QInputMethodEvent* event) {
00606   if (! imwidget) {   
00607     imwidget = new QLabel(this);
00608     imwidget->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
00609   //  imwidget->setAttribute(Qt::WA_TranslucentBackground);
00610 //    imwidget->setAutoFillBackground(false);
00611        imwidget->setAutoFillBackground(true);
00612     imwidget->setWindowOpacity(0.5);
00613     imwidget->setFocusPolicy(Qt::NoFocus);
00614     QPalette pal = imwidget->palette();
00615 //    pal.setColor(QPalette::Window, QColor(0,0,255,80));
00616     pal.setColor(QPalette::Window, QColor(0,0,255,255));
00617     pal.setColor(QPalette::WindowText, Qt::white);
00618     imwidget->setPalette(pal);
00619     QFont f = imwidget->font();
00620     f.setPointSize(30);
00621     imwidget->setFont(f);
00622     imwidget->setMargin(5);
00623   }
00624 
00625   QString const & preedit_string = event->preeditString();
00626   QString const & commit_string = event->commitString();
00627 
00628   if (preedit_string.isEmpty()) {
00629     imwidget->hide();
00630   } else {
00631     if (DEBUG_QT)
00632       cout << "IM preediting :" << preedit_string.toUtf8().data() << LF;
00633     imwidget->setText(preedit_string);
00634     imwidget->adjustSize();
00635     QSize sz = size();
00636     QRect g = imwidget->geometry();
00637     QPoint c = mapToGlobal(cursor_pos);
00638     c += QPoint(5,5);
00639     // g.moveCenter(QPoint(sz.width()/2,sz.height()/2));
00640     g.moveTopLeft(c);
00641     if (DEBUG_QT)
00642       cout << "IM hotspot: " << cursor_pos.x() << "," << cursor_pos.y() << LF;
00643     imwidget->setGeometry(g);
00644     // setRoundedMask(imwidget);
00645     imwidget->show();
00646 #ifdef QT_MAC_USE_COCOA
00647     // HACK: we unexplicably loose the focus even when showing the small window,
00648     // so we need to restore it manually.....
00649     // The following fixes the problem (but I do not really understand why it 
00650     // happens)
00651     // Maybe this is a Qt/Cocoa bug.
00652     this->window()->activateWindow();
00653 #endif    
00654   }
00655   
00656   if (!commit_string.isEmpty()) {
00657     if (DEBUG_QT)
00658       cout << "IM committing :" << commit_string.toUtf8().data() << LF;
00659 
00660     int key = 0;
00661 #if 1
00662     for (int i = 0; i < commit_string.size(); ++i) {
00663       QKeyEvent ev(QEvent::KeyPress, key, Qt::NoModifier, commit_string[i]);
00664       keyPressEvent(&ev);
00665     }
00666 #else
00667     QKeyEvent ev(QEvent::KeyPress, key, Qt::NoModifier, commit_string);
00668     keyPressEvent(&ev);
00669 #endif
00670   }
00671   
00672   event->accept();
00673 
00674 }  
00675 
00676 QVariant 
00677 QTMWidget::inputMethodQuery ( Qt::InputMethodQuery query ) const {
00678   switch (query) {
00679     case Qt::ImMicroFocus :
00680       return QVariant(QRect(cursor_pos + QPoint(10,10),QSize(20,40)));
00681     default:
00682       return QVariant();
00683   }
00684 }
00685 
00686 #else
00687 
00688 // NEW INPUT METHOD PREVIEW
00689 void
00690 QTMWidget::inputMethodEvent (QInputMethodEvent* event) {
00691   
00692   QString const & preedit_string = event->preeditString();
00693   QString const & commit_string = event->commitString();
00694   
00695   if (!commit_string.isEmpty()) {
00696     if (DEBUG_QT)
00697       cout << "IM committing :" << commit_string.toUtf8().data() << LF;
00698     
00699     int key = 0;
00700 #if 1
00701     for (int i = 0; i < commit_string.size(); ++i) {
00702       QKeyEvent ev(QEvent::KeyPress, key, Qt::NoModifier, commit_string[i]);
00703       keyPressEvent(&ev);
00704     }
00705 #else
00706     QKeyEvent ev(QEvent::KeyPress, key, Qt::NoModifier, commit_string);
00707     keyPressEvent(&ev);
00708 #endif
00709   }
00710   
00711   if (DEBUG_QT)
00712     cout << "IM preediting :" << preedit_string.toUtf8().data() << LF;
00713   
00714   string r = "pre-edit:";
00715   if (!preedit_string.isEmpty())
00716   {
00717     
00718     // find cursor position in the preedit string
00719     QList<QInputMethodEvent::Attribute>  const & attrs = event->attributes();
00720     //    int pos = preedit_string.count();
00721     int pos = 0;
00722     bool visible_cur = false;
00723     for(int i=0; i< attrs.count(); i++) 
00724       if (attrs[i].type == QInputMethodEvent::Cursor) {
00725         pos = attrs[i].start;
00726         visible_cur = (attrs[i].length != 0);
00727       }
00728     
00729     // find selection in the preedit string
00730     int sel_start = 0;
00731     int sel_length = 0;
00732     if (pos <  preedit_string.count()) {
00733       for(int i=0; i< attrs.count(); i++) 
00734         if ((attrs[i].type == QInputMethodEvent::TextFormat) &&
00735             (attrs[i].start <= pos) &&
00736             (pos < attrs[i].start + attrs[i].length)) {
00737           sel_start = attrs[i].start;
00738           sel_length =  attrs[i].length;
00739           if (!visible_cur) pos += attrs[i].length;
00740         }
00741     } else {
00742       sel_start = pos;
00743       sel_length = 0;
00744     }
00745     (void) sel_start; (void) sel_length;
00746     
00747     r = r * as_string(pos) * ":" * from_qstring(preedit_string);
00748   }
00749   simple_widget_rep *wid =  tm_widget();
00750   if (wid)
00751     the_gui -> process_keypress (wid, r, texmacs_time());
00752   event->accept();
00753 }  
00754 
00755 QVariant 
00756 QTMWidget::inputMethodQuery ( Qt::InputMethodQuery query ) const {
00757   switch (query) {
00758     case Qt::ImMicroFocus :
00759       return QVariant (QRect (cursor_pos, QSize (5,5)));
00760     default:
00761       return QWidget::inputMethodQuery (query);
00762   }
00763 }
00764 
00765 
00766 #endif // input method variants
00767 
00768 
00769 
00770 void
00771 QTMWidget::mousePressEvent (QMouseEvent* event) {
00772   simple_widget_rep *wid= tm_widget ();
00773   if (!wid) return;
00774   QPoint point = event->pos() + origin();
00775   scale (point);
00776   unsigned int mstate= mouse_state (event, false);
00777   string s= "press-" * mouse_decode (mstate);
00778   the_gui -> process_mouse (wid, s, point.x (), point.y (), 
00779                             mstate, texmacs_time ());
00780  // wid -> handle_mouse (s, point.x (), point.y (), mstate, texmacs_time ());
00781   if (DEBUG_QT)
00782     cout << "mouse event: " << s << " at "
00783          << point.x () << ", " << point.y () << LF;
00784 }
00785 
00786 void
00787 QTMWidget::mouseReleaseEvent (QMouseEvent* event) {
00788   simple_widget_rep *wid = tm_widget();
00789   if (!wid) return;
00790   QPoint point = event->pos() + origin();
00791   scale (point);
00792   unsigned int mstate= mouse_state (event, true);
00793   string s= "release-" * mouse_decode (mstate);
00794   the_gui -> process_mouse (wid, s, point.x (), point.y (), 
00795                             mstate, texmacs_time ());
00796 //  wid -> handle_mouse (s, point.x (), point.y (), mstate, texmacs_time ());
00797   if (DEBUG_QT)
00798     cout << "mouse event: " << s << " at "
00799          << point.x () << ", " << point.y () << LF;
00800 }
00801 
00802 void
00803 QTMWidget::mouseMoveEvent (QMouseEvent* event) {
00804   simple_widget_rep *wid = tm_widget();
00805   if (!wid) return;
00806   QPoint point = event->pos() + origin();
00807   scale (point);
00808   unsigned int mstate= mouse_state (event, false);
00809   string s= "move";
00810   the_gui -> process_mouse (wid, s, point.x (), point.y (), 
00811                             mstate, texmacs_time ());
00812 //  wid -> handle_mouse (s, point.x (), point.y (), mstate, texmacs_time ());
00813   if (DEBUG_QT)
00814     cout << "mouse event: " << s << " at "
00815          << point.x () << ", " << point.y () << LF;
00816 }
00817 
00818 
00819 bool
00820 QTMWidget::event (QEvent* event) {
00821   if (event->type() == QEvent::KeyPress) {
00822     QKeyEvent *ke = static_cast<QKeyEvent*> (event);
00823     keyPressEvent (ke);
00824     return true;
00825   } 
00826   return QTMScrollView::event (event);
00827 }
00828 
00829 
00830 void
00831 QTMWidget::focusInEvent ( QFocusEvent * event ) {
00832   if (DEBUG_QT) cout << "FOCUSIN" << LF;
00833   simple_widget_rep *wid = tm_widget ();
00834   if (wid) {
00835     the_gui -> process_keyboard_focus (wid, true, texmacs_time());
00836     //wid -> handle_keyboard_focus (true, texmacs_time ());
00837   }
00838   QTMScrollView::focusInEvent (event);
00839 }
00840 
00841 void
00842 QTMWidget::focusOutEvent ( QFocusEvent * event ) {
00843   if (DEBUG_QT)   cout << "FOCUSOUT" << LF;
00844   simple_widget_rep *wid = tm_widget ();
00845   if (wid) {
00846     the_gui -> process_keyboard_focus (wid, false, texmacs_time());
00847 //    wid -> handle_keyboard_focus (false, texmacs_time ());
00848   }
00849   QTMScrollView::focusOutEvent (event);
00850 }