[PATCH] Enable native sumbenu arrow drawing and implement it in GTK+

Michael Natterer mitch at gimp.org
Thu May 5 00:13:37 PDT 2011


---
 vcl/inc/vcl/menu.hxx                     |    4 +
 vcl/inc/vcl/salnativewidgets.hxx         |    1 +
 vcl/source/window/menu.cxx               |   93 +++++++++++++++++++++++++----
 vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx |   64 ++++++++++++++++++++
 4 files changed, 149 insertions(+), 13 deletions(-)

diff --git a/vcl/inc/vcl/menu.hxx b/vcl/inc/vcl/menu.hxx
index c052c14..6109491 100644
--- a/vcl/inc/vcl/menu.hxx
+++ b/vcl/inc/vcl/menu.hxx
@@ -199,6 +199,10 @@ protected:
     // return value is Max( rCheckHeight, rRadioHeight ) 
     SAL_DLLPRIVATE long             ImplGetNativeCheckAndRadioSize( Window*, long& rCheckHeight, long& rRadioHeight, long &rMaxWidth ) const;
 
+    // returns native submenu arrow size and spacing from right border
+    // return value is whether it's supported natively
+    SAL_DLLPRIVATE sal_Bool         ImplGetNativeSubmenuArrowSize( Window* pWin, Size& rArrowSize, long& rArrowSpacing ) const;
+
     SAL_DLLPRIVATE void                ImplAddDel( ImplMenuDelData &rDel );
     SAL_DLLPRIVATE void                ImplRemoveDel( ImplMenuDelData &rDel );
 public:
diff --git a/vcl/inc/vcl/salnativewidgets.hxx b/vcl/inc/vcl/salnativewidgets.hxx
index 39e6c18..94fa162 100644
--- a/vcl/inc/vcl/salnativewidgets.hxx
+++ b/vcl/inc/vcl/salnativewidgets.hxx
@@ -178,6 +178,7 @@ typedef sal_uInt32		ControlPart;
 #define PART_MENU_ITEM_CHECK_MARK   251
 #define PART_MENU_ITEM_RADIO_MARK   252
 #define PART_MENU_SEPARATOR         253
+#define PART_MENU_SUBMENU_ARROW     254
 
 /*  #i77549#
     HACK: for scrollbars in case of thumb rect, page up and page down rect we
diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx
index 9984ee7..2afd2ea 100644
--- a/vcl/source/window/menu.cxx
+++ b/vcl/source/window/menu.cxx
@@ -2305,6 +2305,37 @@ long Menu::ImplGetNativeCheckAndRadioSize( Window* pWin, long& rCheckHeight, lon
     return (rCheckHeight > rRadioHeight) ? rCheckHeight : rRadioHeight;
 }
 
+sal_Bool Menu::ImplGetNativeSubmenuArrowSize( Window* pWin, Size& rArrowSize, long& rArrowSpacing ) const
+{
+    ImplControlValue aVal;
+    Rectangle aNativeBounds;
+    Rectangle aNativeContent;
+    Point tmp( 0, 0 );
+    Rectangle aCtrlRegion( Rectangle( tmp, Size( 100, 15 ) ) );
+    if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP,
+                                        PART_MENU_SUBMENU_ARROW ) )
+        {
+            if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
+                                              ControlPart(PART_MENU_SUBMENU_ARROW),
+                                              aCtrlRegion,
+                                              ControlState(CTRL_STATE_ENABLED),
+                                              aVal,
+                                              OUString(),
+                                              aNativeBounds,
+                                              aNativeContent )
+            )
+            {
+                Size aSize( Size ( aNativeContent.GetWidth(),
+                                   aNativeContent.GetHeight() ) );
+                rArrowSize = aSize;
+                rArrowSpacing = aNativeBounds.GetWidth() - aNativeContent.GetWidth();
+
+                return sal_True;
+            }
+        }
+    return sal_False;
+}
+
 // -----------------------------------------------------------------------
 
 void Menu::ImplAddDel( ImplMenuDelData& rDel )
@@ -2853,21 +2884,57 @@ void Menu::ImplPaint( Window* pWin, sal_uInt16 nBorder, long nStartY, MenuItemDa
                 // SubMenu?
                 if ( !bLayout && !bIsMenuBar && pData->pSubMenu )
                 {
-                    aTmpPos.X() = aOutSz.Width() - nFontHeight + nExtra - nOuterSpace;
-                    aTmpPos.Y() = aPos.Y();
-                    aTmpPos.Y() += nExtra/2;
-                    aTmpPos.Y() += ( pData->aSz.Height() / 2 ) - ( nFontHeight/4 );
-                    if ( pData->nBits & MIB_POPUPSELECT )
+                    bool bNativeOk = false;
+                    if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP,
+                                                        PART_MENU_SUBMENU_ARROW ) )
                     {
-                        pWin->SetTextColor( rSettings.GetMenuTextColor() );
-                        Point aTmpPos2( aPos );
-                        aTmpPos2.X() = aOutSz.Width() - nFontHeight - nFontHeight/4;
-                        aDecoView.DrawFrame(
-                            Rectangle( aTmpPos2, Size( nFontHeight+nFontHeight/4, pData->aSz.Height() ) ), FRAME_DRAW_GROUP );
+                        ControlState nState = 0;
+                        Size aTmpSz( 0, 0 );
+                        long aSpacing = 0;
+
+                        if( !ImplGetNativeSubmenuArrowSize( pWin,
+                                                            aTmpSz, aSpacing ) )
+                        {
+                            aTmpSz = Size( nFontHeight, nFontHeight );
+                            aSpacing = nOuterSpace;
+                        }
+
+                        if ( pData->bEnabled )
+                            nState |= CTRL_STATE_ENABLED;
+                        if ( bHighlighted )
+                            nState |= CTRL_STATE_SELECTED;
+
+                        aTmpPos.X() = aOutSz.Width() - aTmpSz.Width() - aSpacing - nOuterSpace;
+                        aTmpPos.Y() = aPos.Y() + ( pData->aSz.Height() - aTmpSz.Height() ) / 2;
+                        aTmpPos.Y() += nExtra/2;
+
+                        Rectangle aItemRect( aTmpPos, aTmpSz );
+                        MenupopupValue aVal( nTextPos-GUTTERBORDER, aItemRect );
+                        bNativeOk = pWin->DrawNativeControl( CTRL_MENU_POPUP,
+                                                             PART_MENU_SUBMENU_ARROW,
+                                                             aItemRect,
+                                                             nState,
+                                                             aVal,
+                                                             OUString() );
+                    }
+                    if( ! bNativeOk )
+                    {
+                        aTmpPos.X() = aOutSz.Width() - nFontHeight + nExtra - nOuterSpace;
+                        aTmpPos.Y() = aPos.Y();
+                        aTmpPos.Y() += nExtra/2;
+                        aTmpPos.Y() += ( pData->aSz.Height() / 2 ) - ( nFontHeight/4 );
+                        if ( pData->nBits & MIB_POPUPSELECT )
+                        {
+                            pWin->SetTextColor( rSettings.GetMenuTextColor() );
+                            Point aTmpPos2( aPos );
+                            aTmpPos2.X() = aOutSz.Width() - nFontHeight - nFontHeight/4;
+                            aDecoView.DrawFrame(
+                                Rectangle( aTmpPos2, Size( nFontHeight+nFontHeight/4, pData->aSz.Height() ) ), FRAME_DRAW_GROUP );
+                        }
+                        aDecoView.DrawSymbol(
+                            Rectangle( aTmpPos, Size( nFontHeight/2, nFontHeight/2 ) ),
+                            SYMBOL_SPIN_RIGHT, pWin->GetTextColor(), nSymbolStyle );
                     }
-                    aDecoView.DrawSymbol(
-                        Rectangle( aTmpPos, Size( nFontHeight/2, nFontHeight/2 ) ),
-                        SYMBOL_SPIN_RIGHT, pWin->GetTextColor(), nSymbolStyle );
                 }
 
                 if ( pThisItemOnly && bHighlighted )
diff --git a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx
index c37b366..8da8035 100644
--- a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx
+++ b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx
@@ -586,6 +586,7 @@ sal_Bool GtkSalGraphics::IsNativeControlSupported( ControlType nType, ControlPar
                 ||  (nPart==PART_MENU_ITEM_CHECK_MARK)
                 ||  (nPart==PART_MENU_ITEM_RADIO_MARK)
                 ||  (nPart==PART_MENU_SEPARATOR)
+                ||  (nPart==PART_MENU_SUBMENU_ARROW)
                 )
                                                                 )   ||
         ((nType == CTRL_PROGRESS) &&
@@ -853,6 +854,7 @@ sal_Bool GtkSalGraphics::drawNativeControl(	ControlType nType,
     || (nPart == PART_MENU_ITEM_CHECK_MARK)
     || (nPart == PART_MENU_ITEM_RADIO_MARK)
     || (nPart == PART_MENU_SEPARATOR)
+    || (nPart == PART_MENU_SUBMENU_ARROW)
     )
     )
     {
@@ -1026,6 +1028,42 @@ sal_Bool GtkSalGraphics::getNativeControlRegion(  ControlType nType,
             rNativeContentRegion = aIndicatorRect;
             returnVal = sal_True;
         }
+        else if( nPart == PART_MENU_SUBMENU_ARROW )
+        {
+            GtkWidget* widget = gWidgetData[m_nScreen].gMenuItemMenuWidget;
+            GtkWidget* child;
+            PangoContext *context;
+            PangoFontMetrics *metrics;
+            gint arrow_size;
+            gint arrow_extent;
+            guint horizontal_padding;
+            gfloat arrow_scaling;
+
+            gtk_widget_style_get( widget,
+                                  "horizontal-padding", &horizontal_padding,
+                                  "arrow-scaling", &arrow_scaling,
+                                  NULL );
+
+            child = GTK_BIN( widget )->child;
+
+            context = gtk_widget_get_pango_context( child );
+            metrics = pango_context_get_metrics( context,
+                                                 child->style->font_desc,
+                                                 pango_context_get_language( context ) );
+
+            arrow_size = ( PANGO_PIXELS( pango_font_metrics_get_ascent( metrics ) +
+                                         pango_font_metrics_get_descent( metrics ) ));
+
+            pango_font_metrics_unref( metrics );
+
+            arrow_extent = arrow_size * arrow_scaling;
+
+            rNativeContentRegion = Rectangle( Point( 0, 0 ),
+                                              Size( arrow_extent, arrow_extent ));
+            rNativeBoundingRegion = Rectangle( Point( 0, 0 ),
+                                               Size( arrow_extent + horizontal_padding, arrow_extent ));
+            returnVal = sal_True;
+        }
     }
     if( (nType == CTRL_RADIOBUTTON || nType == CTRL_CHECKBOX) )
     {
@@ -2819,6 +2857,32 @@ sal_Bool GtkSalGraphics::NWPaintGTKPopupMenu(
                              "menuitem",
                              x, x + w, y + h / 2);
         }
+        else if( nPart == PART_MENU_SUBMENU_ARROW )
+        {
+            GtkStateType nStateType = GTK_STATE_NORMAL;
+            GtkShadowType nShadowType;
+
+            if ( nState & CTRL_STATE_SELECTED )
+                nStateType = GTK_STATE_PRELIGHT;
+
+            NWSetWidgetState( gWidgetData[m_nScreen].gMenuItemMenuWidget,
+                              nState, nStateType );
+
+            if ( nState & CTRL_STATE_PRESSED )
+                nShadowType = GTK_SHADOW_IN;
+            else
+                nShadowType = GTK_SHADOW_OUT;
+
+            gtk_paint_arrow( gWidgetData[m_nScreen].gMenuItemMenuWidget->style,
+                             gdkDrawable,
+                             nStateType,
+                             nShadowType,
+                             &clipRect,
+                             gWidgetData[m_nScreen].gMenuItemMenuWidget,
+                             "menuitem",
+                             GTK_ARROW_RIGHT, TRUE,
+                             x, y, w, h);
+        }
     }
 
     return( sal_True );
-- 
1.7.4.4


--------------000702030506040302070409--


More information about the LibreOffice mailing list