Back to index

texmacs  1.0.7.15
QTMStyle.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003  * MODULE     : QTMStyle.hpp
00004  * DESCRIPTION: QT Texmacs custom style (for some elements)
00005  * COPYRIGHT  : (C) 2008 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 "QTMStyle.hpp"
00013 #include <QApplication>
00014 #include <QStyleOptionMenuItem>
00015 #include "tm_ostream.hpp"
00016 #include <qdrawutil.h>
00017 #include <QPainter>
00018 #include <QMainWindow>
00019 
00020 #ifdef Q_WS_MAC
00021 #define UNIFIED_TOOLBAR
00022 // enable the unified toolbar style on the mac. To work properly this requires
00023 // a modification of the widget hierarchy of the main window.
00024 #endif
00025 
00026 // custom style to override some Qt "features" like
00027 // frame around widgets in the status bar
00028 
00029 class QTMProxyStyle: public QStyle {
00030   
00031 protected:
00032   QStyle* base;
00033   
00034 public:
00035   explicit QTMProxyStyle (QStyle* _base = NULL);
00036   ~QTMProxyStyle ();
00037   
00038   QStyle *baseStyle() const;
00039   
00040 #if (QT_VERSION < 0x046000)
00041   const QStyle * proxy () const { return this; }
00042 #endif  
00043   
00044   void drawComplexControl (ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget = 0) const;
00045   void drawControl (ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = 0)  const;
00046   void drawItemPixmap (QPainter* painter, const QRect& rect, int alignment, const QPixmap& pixmap) const;
00047   void drawItemText (QPainter* painter, const QRect& rect, int alignment, const QPalette& pal, bool enabled, const QString& text, QPalette::ColorRole textRole = QPalette::NoRole) const;
00048   void drawPrimitive (PrimitiveElement elem, const QStyleOption* option, QPainter* painter, const QWidget* widget = 0) const;
00049   QPixmap generatedIconPixmap (QIcon::Mode iconMode, const QPixmap& pixmap, const QStyleOption* option) const;
00050   SubControl hitTestComplexControl (ComplexControl control, const QStyleOptionComplex* option, const QPoint& pos, const QWidget* widget = 0) const;
00051   QRect itemPixmapRect (const QRect& rect, int alignment, const QPixmap& pixmap) const;
00052   QRect itemTextRect (const QFontMetrics& metrics, const QRect& rect, int alignment, bool enabled, const QString& text) const;
00053   int pixelMetric (PixelMetric metric, const QStyleOption* option = 0, const QWidget* widget = 0) const;
00054   void polish (QWidget* widget);
00055   void polish (QApplication* app);
00056   void polish (QPalette& pal);
00057   QSize sizeFromContents (ContentsType type, const QStyleOption* option, const QSize& contentsSize, const QWidget* widget = 0) const;
00058   QIcon standardIcon (StandardPixmap standardIcon, const QStyleOption* option = 0, const QWidget* widget = 0) const;
00059   QPalette standardPalette () const;
00060   QPixmap standardPixmap (StandardPixmap standardPixmap, const QStyleOption* option = 0, const QWidget* widget = 0) const;
00061   int styleHint (StyleHint hint, const QStyleOption* option = 0, const QWidget* widget = 0, QStyleHintReturn* returnData = 0) const;
00062   QRect subControlRect (ComplexControl control, const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget = 0) const;
00063   QRect subElementRect (SubElement element, const QStyleOption* option, const QWidget* widget = 0) const;
00064   void unpolish (QWidget* widget);
00065   void unpolish (QApplication* app);
00066 };
00067 
00068 class QTMStyle: public QTMProxyStyle {
00069   
00070   
00071 public:
00072   inline QTMStyle (QStyle* _style = NULL): QTMProxyStyle (_style) {}
00073   inline ~QTMStyle () {}
00074   
00075   void drawComplexControl (ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget = 0) const;
00076   void drawPrimitive (PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const;
00077   int pixelMetric (PixelMetric metric, const QStyleOption *opt, const QWidget *widget) const;
00078   QSize sizeFromContents (ContentsType type, const QStyleOption* option, const QSize& contentsSize, const QWidget* widget = 0) const;
00079    void drawControl (ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = 0)  const;
00080   int styleHint (StyleHint hint, const QStyleOption* option = 0, const QWidget* widget = 0, QStyleHintReturn* returnData = 0) const;
00081 };
00082 
00083 /******************************************************************************
00084  * QTMProxyStyle (does not own *style)
00085  ******************************************************************************/
00086 
00087 QTMProxyStyle::QTMProxyStyle (QStyle* _base):
00088 QStyle (), base (_base) {}
00089 
00090 QTMProxyStyle::~QTMProxyStyle() {
00091   // delete style;
00092 }
00093 
00094 inline  QStyle *QTMProxyStyle::baseStyle() const {
00095   return ( base ? base : qApp->style() );
00096 }
00097 
00098 
00099 void
00100 QTMProxyStyle::drawComplexControl (ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget) const {
00101   baseStyle()->drawComplexControl (control, option, painter, widget);
00102 }
00103 
00104 void
00105 QTMProxyStyle::drawControl (ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const {
00106   baseStyle()->drawControl (element, option, painter, widget);
00107 }
00108 
00109 void
00110 QTMProxyStyle::drawItemPixmap (QPainter* painter, const QRect& rect, int alignment, const QPixmap& pixmap) const {
00111   baseStyle()->drawItemPixmap (painter, rect, alignment, pixmap);
00112 }
00113 
00114 void
00115 QTMProxyStyle::drawItemText (QPainter* painter, const QRect& rect, int alignment, const QPalette& pal, bool enabled, const QString& text, QPalette::ColorRole textRole) const {
00116   baseStyle()->drawItemText (painter, rect, alignment, pal, enabled, text, textRole);
00117 }
00118 
00119 void
00120 QTMProxyStyle::drawPrimitive (PrimitiveElement elem, const QStyleOption* option, QPainter* painter, const QWidget* widget) const {
00121   baseStyle()->drawPrimitive (elem, option, painter, widget);
00122 }
00123 
00124 QPixmap
00125 QTMProxyStyle::generatedIconPixmap (QIcon::Mode iconMode, const QPixmap& pixmap, const QStyleOption* option) const {
00126   return baseStyle()->generatedIconPixmap (iconMode, pixmap, option);
00127 }
00128 
00129 QStyle::SubControl
00130 QTMProxyStyle::hitTestComplexControl (ComplexControl control, const QStyleOptionComplex* option, const QPoint& pos, const QWidget* widget) const {
00131   return baseStyle()->hitTestComplexControl (control, option, pos, widget);
00132 }
00133 
00134 QRect
00135 QTMProxyStyle::itemPixmapRect (const QRect& rect, int alignment, const QPixmap& pixmap) const {
00136   return baseStyle()->itemPixmapRect (rect, alignment, pixmap);
00137 }
00138 
00139 QRect
00140 QTMProxyStyle::itemTextRect (const QFontMetrics& metrics, const QRect& rect, int alignment, bool enabled, const QString& text) const {
00141   return baseStyle()->itemTextRect (metrics, rect, alignment, enabled, text);
00142 }
00143 
00144 int
00145 QTMProxyStyle::pixelMetric (PixelMetric metric, const QStyleOption* option, const QWidget* widget) const {
00146   return baseStyle()->pixelMetric (metric, option, widget);
00147 }
00148 
00149 void
00150 QTMProxyStyle::polish (QWidget* widget) {
00151   baseStyle()->polish (widget);
00152 }
00153 
00154 void
00155 QTMProxyStyle::polish (QApplication* app) {
00156   baseStyle()->polish (app);
00157 }
00158 
00159 void
00160 QTMProxyStyle::polish (QPalette& pal) {
00161   baseStyle()->polish (pal);
00162 }
00163 
00164 QSize
00165 QTMProxyStyle::sizeFromContents (ContentsType type, const QStyleOption* option, const QSize& contentsSize, const QWidget* widget) const {
00166   return baseStyle()->sizeFromContents (type, option, contentsSize, widget);
00167 }
00168 
00169 QIcon
00170 QTMProxyStyle::standardIcon (StandardPixmap standardIcon, const QStyleOption* option, const QWidget* widget) const {
00171   return baseStyle()->standardIcon (standardIcon, option, widget);
00172 }
00173 
00174 QPalette
00175 QTMProxyStyle::standardPalette () const {
00176   return baseStyle()->standardPalette ();
00177 }
00178 
00179 QPixmap
00180 QTMProxyStyle::standardPixmap (StandardPixmap standardPixmap, const QStyleOption* option, const QWidget* widget) const {
00181   return baseStyle()->standardPixmap (standardPixmap, option, widget);
00182 }
00183 
00184 int
00185 QTMProxyStyle::styleHint (StyleHint hint, const QStyleOption* option, const QWidget* widget, QStyleHintReturn* returnData) const {
00186   return baseStyle()->styleHint (hint, option, widget, returnData);
00187 }
00188 
00189 QRect
00190 QTMProxyStyle::subControlRect (ComplexControl control, const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget) const {
00191   return baseStyle()->subControlRect (control, option, subControl, widget);
00192 }
00193 
00194 QRect
00195 QTMProxyStyle::subElementRect (SubElement element, const QStyleOption* option, const QWidget* widget) const {
00196   return baseStyle()->subElementRect (element, option, widget);
00197 }
00198 
00199 void
00200 QTMProxyStyle::unpolish (QWidget* widget) {
00201   baseStyle()->unpolish (widget);
00202 }
00203 
00204 void
00205 QTMProxyStyle::unpolish (QApplication* app) {
00206   baseStyle()->unpolish (app);
00207 }
00208 
00209 /******************************************************************************
00210  * QTMStyle
00211  ******************************************************************************/
00212 
00213 
00214 static void qtmDrawRoundedRect(QPainter *p, const QRectF &rect, qreal xRadius, qreal yRadius,
00215                                Qt::SizeMode mode)
00216 {
00217   QRectF r = rect.normalized();
00218   
00219   if (r.isNull())
00220     return;
00221   
00222   if (mode == Qt::AbsoluteSize) {
00223     qreal w = r.width() / 2;
00224     qreal h = r.height() / 2;
00225     
00226     xRadius = 100 * qMin(xRadius, w) / w;
00227     yRadius = 100 * qMin(yRadius, h) / h;
00228   } else {
00229     if (xRadius > 100)                          // fix ranges
00230       xRadius = 100;
00231     
00232     if (yRadius > 100)
00233       yRadius = 100;
00234   }
00235   
00236   QPainterPath path;
00237   
00238   if (xRadius <= 0 || yRadius <= 0) {             // add normal rectangle
00239     path.addRect(r);
00240   } else {
00241     qreal x = r.x();
00242     qreal y = r.y();
00243     qreal w = r.width();
00244     qreal h = r.height();
00245     qreal rxx2 = w*xRadius/100;
00246     qreal ryy2 = h*yRadius/100;
00247     
00248 #ifdef Q_WS_X11
00249     // There is a bug (probably in arcTo) for small sizes.
00250     // We use a rough linear approx.
00251     rxx2 /= 4;
00252     ryy2 /= 4;
00253     path.moveTo(x+rxx2,y);
00254     path.lineTo(x+w-rxx2, y);
00255     path.lineTo(x+w, y+ryy2);
00256     path.lineTo(x+w, y+h-ryy2);    
00257     path.lineTo(x+w-rxx2, y+h);    
00258     path.lineTo(x+rxx2, y+h);    
00259     path.lineTo(x, y+h-ryy2);    
00260     path.lineTo(x, y+ryy2);    
00261     path.closeSubpath();
00262 #else
00263     path.moveTo(x+rxx2,y);
00264     path.arcMoveTo(x, y, rxx2, ryy2, 90);
00265     path.arcTo(x, y, rxx2, ryy2, 90, 90);
00266     path.arcTo(x, y+h-ryy2, rxx2, ryy2, 2*90, 90);
00267     path.arcTo(x+w-rxx2, y+h-ryy2, rxx2, ryy2, 3*90, 90);
00268     path.arcTo(x+w-rxx2, y, rxx2, ryy2, 0, 90);
00269     path.closeSubpath();
00270 #endif
00271   }
00272   
00273   p->drawPath(path);
00274 }
00275 
00276 static void qtmDrawShadeRoundPanel(QPainter *p, const QRect &r,
00277                                    const QPalette &pal, bool sunken,
00278                                    int lineWidth, const QBrush *fill)
00279 {
00280   if (r.width() == 0 || r.height() == 0)
00281     return;
00282   if (!(r.width() > 0 && r.height() > 0 && lineWidth >= 0)) {
00283     qWarning("qtmDrawShadeRoundPanel: Invalid parameters");
00284   }
00285   
00286   QColor shade = pal.dark().color();
00287   QColor light = pal.light().color();
00288   if (fill) {
00289     if (fill->color() == shade)
00290       shade = pal.shadow().color();
00291     if (fill->color() == light)
00292       light = pal.midlight().color();
00293   }
00294   
00295   QPen oldPen = p->pen();                        // save pen
00296   QBrush oldBrush = p->brush();                  // save brush  
00297   QRect rect(r);
00298   int border = 8;
00299   
00300   p->setPen(Qt::NoPen);
00301   
00302   if (sunken) {
00303     p->setBrush(light);
00304     qtmDrawRoundedRect(p,rect,border,border, Qt::AbsoluteSize);
00305     //    p->drawRoundedRect(rect,border,border, Qt::AbsoluteSize);
00306     rect.adjust(0,0,-1,-1);
00307     p->setBrush(shade);
00308     qtmDrawRoundedRect(p,rect,border,border, Qt::AbsoluteSize);
00309     //    p->drawRoundedRect(rect,border,border, Qt::AbsoluteSize);
00310     rect.adjust(1,1,0,0);
00311   }
00312   
00313   p->setBrush(fill ? *fill : shade);
00314   qtmDrawRoundedRect(p,rect,border,border, Qt::AbsoluteSize);
00315   //  p->drawRoundedRect(rect,border,border, Qt::AbsoluteSize);
00316   
00317   p->setPen(oldPen);                        // restore pen
00318   p->setBrush(oldBrush);                        // restore brush
00319 }
00320 
00321 
00322 
00323 void
00324 QTMStyle::drawPrimitive (PrimitiveElement element, const QStyleOption *opt, QPainter *p, const QWidget *widget) const {
00325   //  if (element == QStyle::PE_FrameStatusBarItem) return;
00326   switch (element) {
00327     case PE_FrameStatusBar : 
00328       return;
00329     case PE_PanelButtonTool:
00330       if ((opt->state & (State_Sunken | State_On))) {
00331         qtmDrawShadeRoundPanel(p, opt->rect,  QPalette(opt->palette.color(QPalette::Mid)),//opt->palette,
00332                         (opt->state & (State_Sunken | State_On)), 2,
00333                         &opt->palette.brush(QPalette::Mid));
00334       } else {
00335         qtmDrawShadeRoundPanel(p, opt->rect, opt->palette, //QPalette(opt->palette.color(QPalette::Mid)),//opt->palette,
00336                         (opt->state & (State_Sunken | State_On)), 0,
00337                         &opt->palette.brush(QPalette::Mid));
00338       }
00339       return;
00340     default:
00341       ;
00342   }
00343   baseStyle()->drawPrimitive(element,opt,p,widget);  
00344 }
00345 
00346 
00347 void 
00348 QTMStyle::drawComplexControl (ComplexControl cc, const QStyleOptionComplex* opt, QPainter* p, const QWidget* widget) const {
00349   switch (cc) {
00350     case CC_ToolButton:
00351       if (const QStyleOptionToolButton *toolbutton
00352           = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
00353         QRect button, menuarea;
00354         button = proxy()->subControlRect(cc, toolbutton, SC_ToolButton, widget);
00355         menuarea = proxy()->subControlRect(cc, toolbutton, SC_ToolButtonMenu, widget);
00356         
00357         State bflags = toolbutton->state & ~State_Sunken;
00358         
00359         if (bflags & State_AutoRaise) {
00360           if (!(bflags & State_MouseOver) || !(bflags & State_Enabled)) {
00361             bflags &= ~State_Raised;
00362           }
00363         }
00364         State mflags = bflags;
00365         if (toolbutton->state & State_Sunken) {
00366           if (toolbutton->activeSubControls & SC_ToolButton)
00367             bflags |= State_Sunken;
00368           mflags |= State_Sunken;
00369         }
00370         
00371         QStyleOption tool(0);
00372         tool.palette = toolbutton->palette;
00373         if (toolbutton->subControls & SC_ToolButton) {
00374           if (bflags & (State_Sunken | State_On | State_Raised)) {
00375             tool.rect = button;
00376             tool.state = bflags;
00377             proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p, widget);
00378           }
00379         }
00380         
00381         if (toolbutton->state & State_HasFocus) {
00382           QStyleOptionFocusRect fr;
00383           fr.QStyleOption::operator=(*toolbutton);
00384           fr.rect.adjust(3, 3, -3, -3);
00385           if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup)
00386             fr.rect.adjust(0, 0, -proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator,
00387                                                        toolbutton, widget), 0);
00388           proxy()->drawPrimitive(PE_FrameFocusRect, &fr, p, widget);
00389         }
00390         QStyleOptionToolButton label = *toolbutton;
00391         label.state = bflags;
00392         int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt, widget);
00393         label.rect = button.adjusted(fw, fw, -fw, -fw);
00394         proxy()->drawControl(CE_ToolButtonLabel, &label, p, widget);
00395         
00396         if (toolbutton->subControls & SC_ToolButtonMenu) {
00397           tool.rect = menuarea;
00398           tool.state = mflags;
00399           if (mflags & (State_Sunken | State_On | State_Raised))
00400             proxy()->drawPrimitive(PE_IndicatorButtonDropDown, &tool, p, widget);
00401           proxy()->drawPrimitive(PE_IndicatorArrowDown, &tool, p, widget);
00402         } else if ((toolbutton->features & QStyleOptionToolButton::HasMenu) 
00403                    && (mflags & State_MouseOver))
00404         {
00405           int mbi = proxy()->pixelMetric(PM_MenuButtonIndicator, toolbutton, widget);
00406           QRect ir = toolbutton->rect;
00407           QStyleOptionToolButton newBtn = *toolbutton;
00408           newBtn.rect = QRect(ir.right() + 5 - mbi, ir.y() + ir.height() - mbi + 4, mbi - 6, mbi - 6);
00409           proxy()->drawPrimitive(PE_IndicatorArrowDown, &newBtn, p, widget);
00410         }
00411       }
00412       break;
00413     default:
00414       baseStyle()->drawComplexControl (cc, opt, p, widget);
00415   }
00416 }
00417 
00418 
00419 
00420 
00421 QSize 
00422 QTMStyle::sizeFromContents (ContentsType type, const QStyleOption* option, const QSize& contentsSize, const QWidget* widget) const {
00423   QSize sz(contentsSize);
00424   switch (type) {
00425     case CT_LineEdit:
00426       sz = QSize(sz.width() + 2, sz.height() + 2);
00427       break;
00428       
00429     case CT_ToolButton:
00430       sz = QSize(sz.width() + 4, sz.height() + 6);
00431       break;
00432       
00433     default:
00434       sz = baseStyle()->sizeFromContents(type, option, contentsSize, widget);
00435   }
00436   return sz;
00437 }
00438 
00439 
00440 int
00441 QTMStyle::pixelMetric (PixelMetric metric, const QStyleOption *opt, const QWidget *widget) const {
00442   switch (metric) {
00443     case PM_ToolBarItemSpacing:
00444       return 0;
00445     case PM_ToolBarIconSize:
00446       return 17;
00447   //  case PM_ToolBarFrameWidth:
00448   //    return 2;
00449     default:
00450       ;
00451   }
00452   return baseStyle()->pixelMetric(metric,opt,widget);
00453 }
00454 
00455 void
00456 QTMStyle::drawControl (ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const {
00457   switch (element) {
00458 #if 0
00459     case CE_MenuItem:
00460       if (const QStyleOptionMenuItem *mi =
00461           qstyleoption_cast<const QStyleOptionMenuItem *> (option)) {
00462         QStyleOptionMenuItem mi2(*mi);
00463         mi2.text= QString ("pippo");
00464         baseStyle()->drawControl (element, &mi2, painter, widget);
00465         break;
00466       }
00467 #endif
00468 
00469     case CE_ToolBar: {
00470 #ifdef UNIFIED_TOOLBAR
00471       if ((widget) &&  (widget->windowTitle() == "mode toolbar"))  {
00472 
00473           // For unified tool bars, draw nothing.
00474           if (QMainWindow * mainWindow = qobject_cast<QMainWindow *>(widget->window())) {
00475             if ((mainWindow->unifiedTitleAndToolBarOnMac()) && 
00476                 (widget->parent()->objectName() != "central widget"))
00477               break;
00478           }
00479 
00480           //QColor mainWindowGradientBeginActive (150, 150, 150);
00481           //QColor mainWindowGradientBegin (200, 200, 200);
00482           //QColor mainWindowGradientEnd (232, 232, 232);
00483 
00484           QColor mainWindowGradientBeginActive (222, 222, 222);
00485           QColor mainWindowGradientEndActive (202, 202, 202);
00486           QColor mainWindowGradientBegin (236, 236, 236);
00487           QColor mainWindowGradientEnd (226, 226, 226);
00488   
00489           if (widget->window()->isActiveWindow())
00490             mainWindowGradientBegin = mainWindowGradientBeginActive;
00491           if (widget->window()->isActiveWindow())
00492             mainWindowGradientEnd = mainWindowGradientEndActive;
00493 
00494           // draw background gradient
00495           QLinearGradient linearGrad;
00496           if (option->state & State_Horizontal)
00497             linearGrad = QLinearGradient(0, option->rect.top(), 0, option->rect.bottom());
00498           else
00499             linearGrad = QLinearGradient(option->rect.left(), 0,  option->rect.right(), 0);
00500           
00501           linearGrad.setColorAt(0, mainWindowGradientBegin);
00502           linearGrad.setColorAt(1, mainWindowGradientEnd);
00503           painter->fillRect(option->rect, linearGrad);
00504         }
00505 #endif // UNIFIED_TOOLBAR
00506     } break;
00507       
00508     default:
00509       baseStyle()->drawControl (element, option, painter, widget);
00510   }
00511 }
00512 
00513 int
00514 QTMStyle::styleHint (StyleHint hint, const QStyleOption* option, const QWidget* widget, QStyleHintReturn* returnData) const {
00515   switch (hint) {
00516     case SH_MenuBar_AltKeyNavigation:
00517       return 0;
00518       // Set SH_MenuBar_AltKeyNavigation to false. Typically this would be the job of the style that is selected.
00519       // However: That mechanism seems to be broken with some Qt versions. Furthermore, the Alt key is heavily
00520       // used within TeXmacs, so the menubar navigation gets in the way quite often.
00521     default:
00522       return baseStyle()->styleHint (hint, option, widget, returnData);
00523   }
00524 }
00525 
00526 QStyle*
00527 qtmstyle () {
00528   static QStyle* qtmstyle= NULL;
00529   if (!qtmstyle) {
00530     qtmstyle = new QTMStyle ();
00531   }
00532   if (!qtmstyle) {
00533     qtmstyle = qApp->style ();
00534   }
00535   return qtmstyle;
00536 }