How do I change the scroll bar colors

SyntaxEditor for Windows Forms Forum

Posted 6 years ago by Mike Dempsey - Sr. Developer, Teradata Corp
Version: 12.1.0303
Avatar

I am trying to set the Office2007Blue colors using:

    UIRendererManager.ColorScheme = ActiproSoftware.Drawing.WindowsColorScheme.Office2007Blue

but this appears to have no effect.

By using the RendererResolved (as a VisualStudio2005SyntaxEditorRenderer) I can control the background color for the ScrollBarBlock and the Splitter bar (only when not collapsed) but I can't control the scroll bars themselves.

Also I can set the back color for the QuickInfo tips, but not for the Description tip that appears when using the dropdown Intelliprompt list.

How do I force the ColorScheme to be applied to the SyntaxEditor coltrol?

Thanks
Mike

Comments (8)

Answer - Posted 6 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Mike,

The scrollbars have methods that you can override on the renderer instance (like DrawScrollBarBackground) to render them yourself.  But by default they just use system colors and aren't theme-dependent.

[Modified 6 years ago]


Actipro Software Support

Posted 6 years ago by Mike Dempsey - Sr. Developer, Teradata Corp
Avatar

So if the theme does not control either the scroll bars or the ToolTip background ... what does it effect?
(The text area is controlled by the language and the margins are controled by the renderer colors ... so what's left?)

By creating my own renderer and overriding the scrollbar methods it is simple to change the background color but rather more complex to change the thumb. (I allow the user to select from a bunch of different appearance settings including the 3 Office2007 color sets so I need to draw different borders and/or the 4 lines in the middle etc.)

I also found some example code on the forum to show how to determine what to draw for the buttons ... but the ControlPaint.DrawScrollButton() method does not allow me to specify any colors. It just uses the system colors which brings me back to the original problem.

How do I change the color of the scroll buttons (and also their borders since Office does not use 3D borders)?
Do I just have to manually draw everything myself - as in the thumb?

 

There also seems to be a problem with the UIElementDrawState.Hot property.
My thumb colors change correctly when the button is pressed (based on UIElementDrawState.Pressed) but not when I hover over the scroll bar thumb. My code should change the color if either of these is set.

Posted 6 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Mike,

The renderer in SyntaxEditor is used to render most of the margin and view backgrounds, along with the scrollbars.  It also renders the foreground of some margins.  But the one we provide uses system colors by default only.  You can customize some properties on the render to change certain things though.

Sorry but you do have to render all the pieces of the ScrollBar if you are trying to customize it.  ControlPaint is a system-defined class too, it's nothing we make.  You'd have to use normal drawing methods on e.Graphics to render things with custom colors.

I'm not sure what's wrong with your hot state on the thumb though.  It's working fine in our default implementation.


Actipro Software Support

Posted 6 years ago by Mike Dempsey - Sr. Developer, Teradata Corp
Avatar

The Hot state problem was a logic error that was created when I converted your C# example tho VB so that is fixed.

I have created a ScrollRenderer class that allows me to create an instance by simply passing in 6 colors.
It is working almost like Office apps but not quite.

The problem I have is identifying when the mouse is over ANY part of the scroll bar.
I can use the GetDrawState() method to check if it is over the current button that I am drawing but Office apps change the border/backcolor of all 3 parts (buttons and thumb) when the mouse moves over any part of the scroll bar.

Is there a way to determine that the mouse is over some part of the scroll bar when the Draw methods file? 

(I'll post the full class once I get everything working)

Posted 6 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Mike,

You can get to the scrollbar from the thumb via thumb.ScrollBar.  Then you'd have to see if the mouse is over the ScrollBar somehow (maybe checking Cursor.Position) and render accordingly.


Actipro Software Support

Posted 6 years ago by Mike Dempsey - Sr. Developer, Teradata Corp
Avatar

I can use the following to determine whether the cursor is over the scroll bar:

     sb.ClipBounds.IntersectsWith(New Rectangle(sb.PointToClient(Cursor.Position), New Size(1, 1)))

but the problem is that your Draw events only fire for the button that the mouse is over - so it still only redraws the one button.

I can force it to fire for all the buttons by calling sb.Invalidate() in each of your draw functions but that will generate a lot of messages and still only works when the mouse is over a button/thumb. It also causes the scroll buttons to fire only one time even when I hold the button down ... so that's no good.

I need the events to fire whenever the mouse is over ANY part of the scroll bar so that all the buttons get drawn even if the mouse is not over a button. (I experimented with HitTest() in MouseMove but it doesnt seem to fire for the scroll bars, and I really only want to Invalidate the scrollbar, not the entire control, anyway. Plus the 'one-time problem.)

Is there any way to force all the buttons to redraw when the mouse is over any part of the scrollbar - without causing secondary problems?

Posted 6 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Mike,

I was looking around in the code and unfortunately it doesn't look like there's anything easy that you can do to enable this.  The only thing I can really think of is if you recursively look down the SyntaxEditor's Controls for the ScrollBar instances, then attach to their mouse events and call Invalidate when appropriate on it.  You may have to do the same on the child elements like the buttons and thumb.  I would only call Invalidate from the mouse events and not from within Draw method overrides.


Actipro Software Support

Posted 6 years ago by Mike Dempsey - Sr. Developer, Teradata Corp
Avatar

Thanks. I was not planning to call Invalidate from within Draw - that seemed like a recipe for an infinite loop.

I have attached a handler to the scroll bars and simply call invalidate in the event handler.
Then in my DrawButton function I change the state from 'Normal' to 'Hot' if the cursor position overlaps the scrollbar.

The code for the class follows.

To use this simply add the following to your initialization code: 
     AddHandler Me.Controls(0).MouseMove, AddressOf Scrollbar_MouseOver
     AddHandler Me.Controls(1).MouseMove, AddressOf Scrollbar_MouseOver
     Me.Renderer = New ScrollRenderer(Color.FromArgb(240, 247, 255), Color.FromArgb(110, 140, 170), _
                                                                         Color.FromArgb(80, 90, 110), Color.FromArgb(225, 238, 255), _
                                                                         Color.FromArgb(191, 219, 255), Color.FromArgb(175, 210, 255)) 
(Use your syntaxEditor instance instead of 'Me' if not using a derived control)
This sets the renderer to use Blue colors similar to Office, but you can use any color set.

Then add :
    Protected Sub Scrollbar_MouseOver(ByVal sender As Object, ByVal e As MouseEventArgs)
        sender.Invalidate()
    End Sub

The class itself is:

Public Class ScrollRenderer
    Inherits VisualStudio2005SyntaxEditorRenderer

    Dim backColor As Color          'The background color of the scroll track
    Dim borderColor As Color        'The border color around buttons
    Dim iconColor As Color          'The color of the triangles or bars on buttons 
    Dim normalBtnColor As Color     'The default background color of buttons
    Dim hotBtnColor As Color        'The background color of buttons when mouse over
    Dim pressedBtnColor As Color    'The background color of buttons when pressed

    Enum scrollState
        Normal = 0
        Hot = 1
        Pressed = 3    'Really Hot + Pressed
        Disabled = 16
    End Enum

    Public Sub New(ByVal back As Color, ByVal border As Color, ByVal icon As Color, ByVal normal As Color, ByVal hot As Color, ByVal pressed As Color)
        'Store the colors for use in the override functions and set the background
        backColor = back
        borderColor = border
        iconColor = icon
        normalBtnColor = normal
        hotBtnColor = hot
        pressedBtnColor = pressed
        SplitterBackgroundFill = New SolidColorBackgroundFill(hotBtnColor)
        ScrollBarBlockBackgroundFill = New SolidColorBackgroundFill(backColor)
    End Sub

    Public Overrides Sub DrawScrollBarBackground(ByVal e As PaintEventArgs, ByVal bounds As Rectangle, ByVal scrollBar As ScrollBar)
        'Draw the background using the appropriate appearance
        SolidColorBackgroundFill.Draw(e.Graphics, bounds, backColor)
    End Sub

    Public Overrides Sub DrawEditorViewSplitButton(ByVal e As PaintEventArgs, ByVal bounds As Rectangle, ByVal view As EditorView, ByVal orientation As Orientation)
        'Draw the small splitter bar button
        DrawButton(e, bounds, scrollState.Normal, Nothing, True)
    End Sub

    Public Overrides Sub DrawScrollBarButton(ByVal e As PaintEventArgs, ByVal bounds As Rectangle, ByVal button As ScrollBarButton)
        'Use the appropriate colors and style to draw the scroll button
        DrawButton(e, bounds, button.GetDrawState(), button.ScrollBar, False)
        'Draw the triangle on the button
        Dim point1 As Point
        Dim point2 As Point
        Dim point3 As Point
        If button.CommandLink.Command Is button.ScrollBar.DecreaseSmallCommand Then
            If button.ScrollBar.Orientation = Orientation.Horizontal Then
                point1 = New Point(bounds.Width / 3, bounds.Height / 2)
                point2 = New Point(bounds.Width * 3 / 5, bounds.Height / 4)
                point3 = New Point(bounds.Width * 3 / 5, bounds.Height * 3 / 4)
            Else
                point1 = New Point(bounds.Width / 2, bounds.Height / 3)
                point2 = New Point(bounds.Width / 4, bounds.Height * 3 / 5)
                point3 = New Point(bounds.Width * 3 / 4, bounds.Height * 3 / 5)
            End If
        ElseIf button.CommandLink.Command Is button.ScrollBar.IncreaseSmallCommand Then
            If button.ScrollBar.Orientation = Orientation.Horizontal Then
                Dim off As Integer = bounds.X + 1
                point1 = New Point(off + bounds.Width / 3, bounds.Height / 4)
                point2 = New Point(off + bounds.Width / 3, bounds.Height * 3 / 4)
                point3 = New Point(off + bounds.Width * 3 / 5, bounds.Height / 2)
            Else
                Dim off As Integer = bounds.Y + 1
                point1 = New Point(bounds.Width / 4, off + bounds.Height / 3)
                point2 = New Point(bounds.Width * 3 / 4, off + bounds.Height / 3)
                point3 = New Point(bounds.Width / 2, off + bounds.Height * 3 / 5)
            End If
        End If
        Dim points As Point() = {point1, point2, point3}
        e.Graphics.FillPolygon(New SolidBrush(iconColor), points)
    End Sub

    Public Overrides Sub DrawScrollBarThumb(ByVal e As PaintEventArgs, ByVal bounds As Rectangle, ByVal thumb As ScrollBarThumb)
        'Use the appropriate colors and style to draw the thumb
        If thumb.ScrollBar.Enabled Then
            DrawButton(e, bounds, thumb.GetDrawState(), thumb.ScrollBar, True)
            'Draw the 4 dashes in the center using an Office appearance
            Dim p As Pen = New Pen(iconColor)
            If thumb.ScrollBar.Orientation = Orientation.Horizontal Then
                Dim mid As Integer = (bounds.Right + bounds.Left) / 2
                e.Graphics.DrawLine(p, mid - 3, 5, mid - 3, bounds.Height - 6)
                e.Graphics.DrawLine(p, mid - 1, 5, mid - 1, bounds.Height - 6)
                e.Graphics.DrawLine(p, mid + 1, 5, mid + 1, bounds.Height - 6)
                e.Graphics.DrawLine(p, mid + 3, 5, mid + 3, bounds.Height - 6)
            Else
                Dim mid As Integer = (bounds.Bottom + bounds.Top) / 2
                e.Graphics.DrawLine(p, 5, mid - 3, bounds.Width - 6, mid - 3)
                e.Graphics.DrawLine(p, 5, mid - 1, bounds.Width - 6, mid - 1)
                e.Graphics.DrawLine(p, 5, mid + 1, bounds.Width - 6, mid + 1)
                e.Graphics.DrawLine(p, 5, mid + 3, bounds.Width - 6, mid + 3)
            End If
        End If
    End Sub

    Private Sub DrawButton(ByVal e As PaintEventArgs, ByVal bounds As Rectangle, _
                           ByVal state As scrollState, ByVal sb As ScrollBar, ByVal drawBorder As Boolean)
        'Paint the background of the button and maybe draw borders around it
        'Change Normal state to Hot if the cursor is over the scrollbar
        If sb IsNot Nothing AndAlso state = scrollState.Normal Then
            Dim csr As Rectangle = New Rectangle(sb.PointToClient(Cursor.Position), New Size(1, 1))
            If sb.ClipBounds.IntersectsWith(csr) Then _
                state = scrollState.Hot
        End If

        If state = scrollState.Hot Then
            e.Graphics.FillRectangle(New SolidBrush(hotBtnColor), bounds)
            ControlPaint.DrawBorder(e.Graphics, bounds, borderColor, ButtonBorderStyle.Solid)
        ElseIf state = scrollState.Pressed Then
            e.Graphics.FillRectangle(New SolidBrush(pressedBtnColor), bounds)
            ControlPaint.DrawBorder(e.Graphics, bounds, borderColor, ButtonBorderStyle.Solid)
        Else
            e.Graphics.FillRectangle(New SolidBrush(normalBtnColor), bounds)
            If drawBorder Then _
                ControlPaint.DrawBorder(e.Graphics, bounds, borderColor, ButtonBorderStyle.Solid)
        End If
    End Sub

End Class

Note that this draws 'flat' scroll bars, not 3D.
If you want 3D you can use the default renderer if the system colors are OK. If you want 3D in different colors you will need to change the DrawBorder function to manually draw the 8 (inner and outer) border lines manually. That may require you to pass in additional colors. (or use the Light/Dark methods of ControlPaint to modify existing colors)

Also note that the automatic highlighting of all buttons when the mouse moves over any part of the scrollbar works only with the original 2 scrollbars. If you split the view into 2 or more parts the new scroll bars in the new views will highlight only the button that the mouse is over. (You could fix that by handling the creation/deletion of views and adding/removing handlers ... but that may be overkill.)

The latest build of this product (v2018.1 build 0341) was released 3 months ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.