Back to index

texmacs  1.0.7.15
qt_menu.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : qt_menu.cpp
00004 * DESCRIPTION: QT menu proxies
00005 * COPYRIGHT  : (C) 2007  Massimiliano Gubinelli
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 "qt_menu.hpp"
00013 #include "qt_utilities.hpp"
00014 #include "qt_renderer.hpp"
00015 #include "qt_simple_widget.hpp"
00016 #include "qt_basic_widgets.hpp"
00017 #include "QTMMenuHelper.hpp"
00018 #include "QTMStyle.hpp"
00019 #include "analyze.hpp"
00020 #include "widget.hpp"
00021 #include "message.hpp"
00022 #include "promise.hpp"
00023 //#import "TMView.h"
00024 #include <QtGui>
00025 
00026 
00027 #include "QTMGuiHelper.hpp"
00028 #include "qt_gui.hpp"
00029 
00030 // REMARK on memory management.
00031 // the hierarchy of a QMenu has parents correctly set to the proper supermenu
00032 // this guarantees that deletion of the root menu correclty deletes all the tree below it.
00033 // the root menu itself (without parent QObject) is "owned" by the associate qt_menu_rep instance
00034 // and it is deallocated by it. This ensures correct memory management between TeXmacs and Qt
00035 // since qt_menu_rep is sometimes cached at TeXmacs level.
00036 // this also means that when we install some menu in the GUI (in the main menu or in the toolbar)
00037 // we should just add actions and not reroot the qt parent hierarchy since even if the menu will
00038 // be eventually removed from the GUI it has some chance to still be cached in the TeXmacs side
00039 // conventions are as follows:
00040 // - the method as_qaction passes the ownership of the action and the eventual submenu to the caller 
00041 //   responsibility. When creating menu hierachies (eg. via the scheme interface) you should use this method
00042 //   to retrieve the relevant Qt objects.
00043 // - the method qt_menu_rep::get_menu preserves the onwership of the menu to the called qt_menu_rep
00044 //   (to guarantee correct caching). when installing menus in the gui you should use this method.
00045 // Submenus belongs implicitly to the parent QTMAction since it controls if the menu has an explicit parent
00046 // and in negative case delete the submenu. All submenus in the menu hierarchy should have an empty parent widget
00047 // and be attached to some QTMAction. This guarantees correct memory management.
00048 
00049 
00050 
00051 QTMAction::QTMAction(QObject *parent) : QAction(parent) { 
00052   QObject::connect(the_gui->gui_helper, SIGNAL(refresh()), this, SLOT(doRefresh()));
00053   _timer = new QTimer(this);
00054   QObject::connect(_timer, SIGNAL(timeout()), this, SLOT(doShowToolTip()));
00055   
00056 }
00057 
00058 QTMAction::~QTMAction() { 
00059   if (menu() && !(menu()->parent())) delete menu(); 
00060 }
00061 
00062 
00063 void 
00064 QTMAction::doRefresh() {
00065   if (N(str)) {
00066     string t= tm_var_encode (str);
00067     if (t == "Help") t= "Help ";
00068     setText(to_qstring (t));
00069   }
00070 }
00071 
00072 void
00073 QTMAction::showToolTip()
00074 {
00075   _timer->start(500);   // Restarts the timer if already running
00076   _pos = QCursor::pos();
00077 }
00078 
00079 /*
00080  * This is the best I could come up with: under MacOSX menu items receive no
00081  * mouse events, nor are they QWidgets whose geometry we can query. As far as I
00082  * know, it is not possible to know whether the menu item currently under the
00083  * cursor is this particular one, so in order to avoid displaying outdated
00084  * toolTips (because the user moved fast over items) we compute distances.
00085  * This is obviously wrong, and will behave weirdly under certain resolutions,
00086  * for given menu item sizes, etc. Also, one typically moves for a while 
00087  * horizontally over the first item in an extensible menu, so once the user
00088  * stops, the distance is bigger than the given constant and no tooltip is
00089  * displayed.
00090  */
00091 void
00092 QTMAction::doShowToolTip() {
00093   static int step = QApplication::font().pointSize();
00094   _timer->stop();
00095   if((QCursor::pos() - _pos).manhattanLength() < step)  // Hideous HACK
00096     QToolTip::showText(QCursor::pos(), toolTip());
00097   else
00098     QToolTip::hideText();
00099 }
00100 
00101 
00102 /*******************************************************************************
00103 * Default action is empty.
00104 *******************************************************************************/
00105 
00106 QAction *qt_widget_rep::as_qaction() {
00107   QAction *a = new QTMAction (NULL); 
00108   //  a->setSeparator(true);
00109   a->setEnabled(false);
00110   return a;
00111 };
00112 
00113 
00114 /******************************************************************************/
00115 
00116 
00117 qt_menu_rep::qt_menu_rep (QAction* _item) 
00118  : item (_item ? _item : new QTMAction (NULL)) {  }
00119 
00120 
00121 QAction*
00122 qt_menu_rep::as_qaction() {
00123   // FIXME: the convention is that as_qaction give ownership of
00124   // the action to the caller. However in this case we do not want
00125   // to replicate the action so we must be sure to be called only once.
00126   if (!item) cout << "THIS MUST NOT HAPPEN TWICE" << LF;
00127   QAction *ret = item;
00128   item = NULL;
00129   return ret;
00130 }
00131 
00132 widget
00133 qt_menu_rep::make_popup_widget () {
00134   return this;
00135 }
00136 
00137 widget
00138 qt_menu_rep::popup_window_widget (string s) {
00139   item->menu()->setWindowTitle (to_qstring (s));
00140   return this;
00141 }
00142 
00143 widget
00144 qt_menu_rep::plain_window_widget (string s, command q) {
00145   item->menu()->setWindowTitle (to_qstring (s));
00146   (void) q; // FIXME: to be ignored?
00147   return this;
00148 }
00149 
00150 void
00151 qt_menu_rep::send (slot s, blackbox val) {
00152   if (DEBUG_QT)
00153     cout << "qt_menu_rep::send " << slot_name(s) << LF;
00154   switch (s) {
00155   case SLOT_POSITION:
00156     ASSERT (type_box (val) == type_helper<coord2>::id, "type mismatch");
00157     break;
00158   case SLOT_VISIBILITY:
00159     {   
00160       check_type<bool> (val, "SLOT_VISIBILITY");
00161       bool flag = open_box<bool> (val);
00162       if (flag)
00163         item->menu()->show();
00164       (void) flag;
00165     }   
00166     break;
00167   case SLOT_MOUSE_GRAB:
00168     {   
00169       check_type<bool> (val, "SLOT_MOUSE_GRAB");
00170       bool flag = open_box<bool> (val);
00171       (void) flag;
00172       // [NSMenu popUpContextMenu:[item submenu] withEvent:[NSApp currentEvent] forView:( (qt_view_widget_rep*)(the_keyboard_focus.rep))->view ];
00173       if (item->menu ())
00174         item->menu()->exec (QCursor::pos ());
00175     }   
00176     break;
00177   default:
00178     FAILED ("cannot handle slot type");
00179   }
00180 }
00181 
00182 
00183 
00184 QPixmap
00185 impress (simple_widget_rep* wid) {
00186   if (wid) {
00187     int width, height;
00188     wid->handle_get_size_hint (width, height);
00189     QSize s = QSize (width/PIXEL, height/PIXEL);
00190     QPixmap pxm(s);
00191     //cout << "impress (" << s.width() << "," << s.height() << ")\n";
00192     pxm.fill (Qt::transparent);
00193     {
00194       qt_renderer_rep *ren = the_qt_renderer();
00195       ren->begin (static_cast<QPaintDevice*>(&pxm));
00196       wid->set_current_renderer(the_qt_renderer());
00197       rectangle r = rectangle (0, 0, s.width(), s.height());
00198       ren->set_origin(0,0);
00199       ren->encode (r->x1, r->y1);
00200       ren->encode (r->x2, r->y2);
00201       ren->set_clipping (r->x1, r->y2, r->x2, r->y1);
00202       {
00203         // we do not want to be interrupted here...
00204         extern bool disable_check_event;
00205         bool cache = disable_check_event;
00206         disable_check_event= true;
00207         wid->handle_repaint (r->x1, r->y2, r->x2, r->y1);
00208         disable_check_event= cache;
00209       }
00210       ren->end();
00211       wid->set_current_renderer(NULL);
00212     }
00213     return pxm;
00214   }
00215   else {
00216     // return arbitrary image...
00217     QPixmap pxm (10, 10);
00218     return pxm;
00219   }
00220 }
00221 
00222 QAction*
00223 simple_widget_rep::as_qaction () {
00224   QAction* a= new QTMAction (NULL);
00225   QPixmap pxm (impress (this));
00226   QIcon icon (pxm);
00227   a->setIcon (icon);
00228   return a;
00229 }
00230