Tuesday, August 2, 2011

Experimenting with ribbons in LiveCode (part 3)

Three weeks ago, we kicked off an experiment to create a ribbon control for LiveCode. By now, we have a good plan, and we have an initial XML structure for our 'ribbonText' property. So let's go ahead and start putting together some code! Let's start with the ribbon background and header area, shall we?

I really wanted to do it all with only graphics, gradients and effects, but I couldn't quite get the details right. So eventually I went for the oldest trick in the book: I took a screenshot and then extracted three slices from the image: 2 pixels wide for the left and right edge, and then 1 pixel wide for the center. You can't use this slice as a pattern for another control, but you can just stretch that image as far as you need: because the original is only 1 pixel wide, the engine can stretch the image at a low cost, because there is no interpolation required.



Let's get a head start on the ApplicationMenu button: take some more screenshots while hovering and after clicking on it; then extract the images for each state of the ApplicationMenu; drop in a button and assign the appropriate image ids for the button's regular, hilited and hover icons. This is not the time for the menu itself, though, so let's move on to the ribbon tabs.



But before that, let's drop in a field "RibbonText" and a button to apply it to our ribbon group. It will make testing a whole lot easier as we go and add features.



Pop quiz: what is the fastest way to create a custom tab header in LiveCode?
Answer: why, a radio button group, of course!

I know what you're thinking: "Hold on, have you lost your marbles? Doesn't a group of radio buttons look like this?"



Well, sure - but by setting a few properties, you can turn that into this:



And that's accomplished without any scripting; once you start handling mouse event messages, you can dynamically apply graphic effects to even greater effect. But that won't suffice for our ribbon, I'm afraid, altough the principle stands: a group of 'radio buttons' can adequately implement our ribbon tabs, as long as they don't have to do it on their own...

There are several factors that determine a ribbon tab's appearance: whether or not the tab is hilited, whether or not the mouse is hovering over the tab, and whether the mouse is pressed or not. So we will enlist the help of some image controls to achieve each of these appearances.

Once again, we use an image editor to take three slices from a screenshot: one for the left edge, one for the right edge, and another to serve as a background, stretched accross the gap. Rinse and repeat for each appearance. The width of the tab can be calculated by taking the formattedWidth of the button, and adding another eighteen pixels, nine on each side, for good measure.

With our approach clearly outlined, we can code the creation of all the controls needed for the ribbon tabs, one tab at a time: first we create the three images for the tab, and then a heavily modified radio button; next, we determine the correct rectangle of our tab button, and adapt the rectangles of our three backing images to match; finally, we inject copies of the appropriate original images; and all the layers are as we would expect.



As soon as we have the tab creation working correctly, we can code the necessary engine event message handlers, property getters and setters, as well as a splash of private commands to make the ribbon tabs act like the real deal. I'd rather not paste the code into this blog post - just download the current revision here and take a good look at the scripts in the qrtRexBehaviors substack.

Next time, we'll tackle the creation of groups - and the weather is still a bit of a mess, so check back soon!

No comments: