Monday, December 28, 2020

Microsoft Office 365-like Ribbon Control

Merry Christmas! Every year between Christmas and New Year's, I like to work on a fun project, such as learning a new technique or writing some cool utility. Last year, I worked on the open source version of Hacker's Guide to Visual FoxPro. This year, I created an open source Microsoft Office 365-like ribbon control for VFP forms.

Here's a sample form containing the ribbon control that resembles Microsoft Outlook. It has two tabs: Home and Send / Receive. Clicking a tab displays the toolbar for that tab.


Here's the Send / Receive tab:

So far, I've included two themes: Colorful (above) and Dark Grey (below):


Themes are defined as RGB colors in an XML file so it's a simple matter to add another theme.

The ribbon control is 100% VFP code. Please try it out and let me know of any enhancements you'd like by creating issues in the GitHub repository for the project.

9 comments:

Anonymous said...

Fantastic!!!
I loved the layout and the user interface. It's definitely time to make some cosmetic changes to our Apps.
I performed some basic tests, added some tabs and buttons, and everything is working as expected. Congratulations.
Seems very easy to implement.

I hope to go deep into it in the next weeks.

Thanks for sharing!
Cesar

Phil91 said...

Hello,
Great control...However, I'm more in the Winforms world so I have a beginner's simple and stupid question: is there a chance that I can migrae this superb control to informs?

Thanks

Philippe

Doug Hennig said...

Google "winforms ribbon control" and you'll find lots of hits.

Doug

Nigel Gomm said...

Doug,
great stuff - i've just started adding this to a project.

I added a new property sfribbontoolbarbutton.disabledpicture to my copy

and this code in sfribbontolbarbutton.enabled_assign

LPARAMETERS tlEnabled
DO CASE
CASE tlEnabled = .F. AND !EMPTY(THIS.DISABLEDPICTURE) AND LEFT(THIS.DISABLEDPICTURE,4) = "‰PNG"
THIS.imgButton.PICTUREVAL= THIS.DISABLEDPICTURE
CASE tlEnabled = .F. AND !EMPTY(THIS.DISABLEDPICTURE) AND FILE(THIS.DISABLEDPICTURE)
THIS.imgButton.PICTUREVAL= FILETOSTR(THIS.DISABLEDPICTURE)
CASE tlEnabled = .F. AND !EMPTY(THIS.IMAGE) AND FILE(THIS.IMAGE)
TRY
WITH _SCREEN.SYSTEM.Drawing
LOCAL loBitmap AS xfcBitmap
LOCAL loNewBitmap AS xfcBitmap

loBitmap = .BITMAP.fromfile(THIS.IMAGE)
LOCAL lnWidth, lnHeight, X, Y, lnLuma
LOCAL loColor AS xfcColor

FOR Y = 0 TO loBitmap.HEIGHT - 1
FOR X = 0 TO loBitmap.WIDTH - 1
loColor = loBitmap.GetPixel(m.X,m.Y)
IF loColor.isknowncolor AND loColor.r != 255 AND loColor.g !=255 AND loColor.b !=255
loBitmap.SetPixel(m.X, m.Y, .COLOR.FromRgb(RGB(200,200,200)))
ENDIF
NEXT
NEXT


THIS.DISABLEDPICTURE = loNewBitmap.GetPictureVal(.Imaging.ImageFormat.png)
THIS.imgButton.PICTUREVAL = THIS.DISABLEDPICTURE
ENDWITH
CATCH TO loerr
THIS.imgButton.PICTUREVAL= FILETOSTR(THIS.IMAGE)
ENDTRY
CASE FILE(THIS.IMAGE)
THIS.imgButton.PICTUREVAL= FILETOSTR(THIS.IMAGE)
ENDCASE
DODEFAULT(tlEnabled)


the .getpixel approach is too slow where there's no filename but i'll try and get a colormatrix to speed things up. Unless you already have some code for that?

Nigel Gomm said...

sorry there's a typo in my previous post....

THIS.DISABLEDPICTURE = loBitmap.GetPictureVal

n

Doug Hennig said...

Thanks, Nigel. I've added a DisabledImage property for consistency with the Image property, and didn't add the GDI+ code.

Nigel Gomm said...

Doug,
i also removed (in my copy) the "if enabled" in sfribbontoolbar.mouseleave()
because if a button disables itself it remains highlighted otherwise.

n

Doug Hennig said...

Thanks. As an aside, these things are best posted as Issues on the GitHub page rather than as comments here.

Nigel Gomm said...

will do (and have done)