Author: Created: Saturday, April 23, 2011 RssIcon
A blog about user interfaces, workflow, developing in LiveCode and whatever comes to mind!
By Steve on Saturday, April 21, 2012

Before we do anything in code, we should experiment with LiveCode's inspector palette to work out the properties that need to be applied to the button to give it the desired appearances in both normal and pressed states. These will then be applied in code and we'll set things up so all instances of the button behave and draw the same way.

So to start, create a new stack and then a new rounded rectangle graphic. You'll notice that the corners are way too rounded, so let's set them to 4. As we're going to be applying filled effects to the control, it's best to change its transparency to opaque.

At this stage, you should be looking at something like this:

The normal state has a fairly soft gray gradient applied to it, with the change from one shade to the next occurring mostly about two thirds of the way down.

Open up the Property Inspector and switch to the Gradient property set. We'll be editing the Fill gradient (Stroke is for the outline of the graphic) and applying a Linear gradient type.

The block of colour in the middle of the inspector is known as a gradient ramp. You can click on it to add colour points to it and their spacing helps to determine how quickly the gradient switches from one colour to the next. In building our ramp up, I reckon that a gray of 75% to the left looks good and 100% to the right is perfect (use the gray scale colour slider to choose these values, rather than RGB values).

You'll notice that the angle of the gradient goes from left to right but a button needs to go from top to bottom. We therefore need to rotate the gradient by 90°. Unfortunately, the gradient inspector doesn't allow for a rotation value to be entered, so you'll need to use the handles to drag the gradient control points into position.

If the handles prove fiddly to use, you can enlarge the graphic or zoom using the control key and the mousewheel (assuming you have zooming in this way turned on).

You should end up with this:

The next step is to add the slight halo and drop shadow that can be seen on the button. You won't be able to see these on a white background, so change the stack's background colour to something darker or more vibrant like bright magenta.

In the Property Inspector, select the Outer Glow set. As the halo is very subtle indeed, we don't want to go overboard on the settings. Therefore, change the colour to a dark gray (about 38%) and bring its opacity down to about 64. The Size needs to be just one pixel.

Note that the Blend Mode is set to Colour Dodge, so it blends in well with the background.

It's a similar affair with the drop shadow. Be sure to change the angle to 90°, so it sits directly beneath the rectangle. The colour is changed to a lighter gray and the opacity reduced, so the background can come through.

Note again that the Blend Mode is set to Colour Dodge.

Now we're ready to see what we've created. In this image, I've changed the height of the rectangle to 23 pixels, which is the actual height that the control will be. We can really get a good idea of how we're doing.

Super. I think we're finished with this button state. Tune in next week for the pressed version! 

By Steve on Sunday, April 15, 2012

Being a multi-platform development environment, the main focus of LiveCode has always been to provide the developer with controls and styles that are common to all operating systems that you can deploy to. If Apple and Microsoft could agree on doing everything exactly the same way, this would be great. But they don't and each OS has its own style variations, layout rules and various other quirks.

As a developer, I like to make my work look like it's always been coded for the intended platforms. Take Data Tree, which is now being looked after by NativeSoft. This multi-platform control looks great on Mac OS X and Windows by adapting itself to match the styles and behaviours of the host operating system. It takes work to do this but the results pay dividends.

In this series of blog posts, we're going to look at how to create a custom gradient button for Mac OS X. We'll seem how I overcome my aversion to gradients and use behaviours to make the control work.

Before we start…

In my old site, I used to have a gradient button library that composed the button out of a couple of bitmaps. This was before the days of gradients, graphic effects and behaviours. It's very much due a revist.

The key advantage of using graphic objects, rather than bitmaps, is that they resize very nicely indeed. The trick that I used with bitmaps was to split the body of the control into three. The two ends remained fixed but the bit in the middle was stretched to fit the width of the button. In taking this approach, I needed six images: two ends and a middle for both normal and pressed versions.

Apple also likes to apply some very nice text effects to their controls, giving them a very subtle drop shadow. Some controls have further graphical emphasis on them, which is not possible to recreate with just one field alone. The technique that I used in Data Tree, especially in the highlight, is to layer a couple of fields over the top of each other, each with a different text colour and the anti-aliasing blended them together for me. However, in this library, I've used the graphic effects alone to accomplish this for me and so therefore just need the one field for the label.

Dissection class

To understand what we're trying to recreate, I've snapped and blown up a textured button from Apple's Pages application. Most graphic manipulation packages will smooth and blur an image that's been enlarged, making the pixels fuzzy and harder for us to work out which subtle effects have been applied. I've therefore applied an aggressive sharpen filter to it, so we can better see the pixels.


We can see that the key features of the button includes:

  • rounded rectangle
  • gradients
  • an inner shadow on the pressed version of the button
  • a drop shadow or some other halo effect beneath and around the button
  • same again on the label of the button

Whenever you create a custom control, the chances are it will be composed of a number of other controls and objects that make it up. Just as my bitmap version consisted of six images and two fields, this control needs at least one graphic for the body of the button and at least one field for its label. They'll be fused together and with a little bit of coding, will work just like any other native control.

The button has two states: normal and pressed. In creating a custom button, I have two options in achieving this:

  1. Use just one rounded rectangle graphic and change its graphical properties in code to display each button state.
  2. Use two rounded rectangle graphics and show or hide them to display each button state.

Although the second option is easier to do, one of the goals of this exercise is to reduce the number of objects inside the controls. I'm therefore going to go for the first option.

End of part one

That's quite a lot of words for now and so I'll leave things there for today. Tune in next week for more!

By Steve on Sunday, November 13, 2011

It's been some time since I last posted (in fact back in June) and now I'm back with some important news.

I'm very pleased to announce that Data Tree has been sold to NativeSoft, developer of the excellent NativeGeometry and NativeDoc add-ons for RunRev's LiveCode.

As many of you know, I have had a major update to Data Tree in progress for some time but due to work commitments, has sadly stalled. This work will now be completed by NativeSoft.

NativeSoft will also be taking over support queries for the versions currently in circulation. Downloads and information about the product can still be obtained from my site but will be transferring to NativeSoft's site in due course. Licences can still be purchased from RunRev's Marketplace site.

I'd like to thank the many, many customers of Data Tree who have bought the product over the last two years. I'm proud to say that many more licences were sold than I ever thought would be.

By Steve on Monday, June 27, 2011

I guess that the post title says it all! The iOS update second beta is available for download on the Data Tree page.

By Steve on Sunday, May 08, 2011

These last few months, I've been working on an update to Data Tree for iOS users. Today, I finally wrote the last line of code that makes it all work.

This has been one hell of an experience. Hopefully, you can tell from the original release that when it comes to recreating the look, feel and experience of a native control, I aim for perfection and nothing short of perfection here would do. Well, you don't want Apple to reject your applications because there was a scrollbar, do you?

Originally when I started to work on adding iOS functionality, I was hopeful that I could simply build upon the existing engines, routines and managers and it wouldn't take too long to complete. Unfortunately, it didn't work out to be that simple and I ended up having to write many, many lines of code to get things to look and work just right.

The real kicker is the relationship between touch events and scrolling events and I thought it would be really helpful to other developers out there if I wrote about my experience.

When does a tapping interaction become a scrolling interaction?

Oh, how much fun was this? in a desktop UI, these are very much separate: you can click on nodes or interact with the scrollbar. In iOS, there is no scrollbar. One touch has to do it all.

When, like me, you want to recreate a control as if it were a native one, you have to dissect what the OS does and then work out how to apply it to a control that Apple doesn't actually give Cocoa developers.

For example, say the user taps a node in the tree, highlights it and then begins to scroll. What happens? In iOS, the node unhighlights and after the scrolling has been done, the node that was previously highlighted is re-highlighted.

But, if the user taps and scrolls immediately, the highlight stays put and the list scrolls.

A quick tap on its own has to activate the node but not if the user taps on a toggle triangle. Also, it would be very un-Applelike if tapping a triangle immediately activated it.

The touch handlers have to cater for all of this, whilst the scroller control has a mind of its own.

Speaking of scrolling controls

In implementing the iOS scrolling controls, I was slightly surprised to find that RunRev requires you, the developer, to create and place them yourself at runtime. That does go a bit against the idea behind LiveCode and actually introduces a code-build-test cycle should you want to evaluate how the fruits of your labours are working.

I can see why, though. Although deploying a scroll control is quite easy, fine tuning it to work the way you would expect it to has some complication and with all of the uniqueness of iOS, you can't really do that within the desktop environment. It does, however, make things a little bit more complicated for the new user that wants to write software for iPads like we used to back in the 80s and 90s with HyperCard. But I digress.

Quirks in LiveCode

Now for the hair pulling moments. Although the language and syntax in the iOS implementation of LiveCode is pretty robust, I have come across a few oddities.

The first came up when working with the iOS scroller controls. As these controls sit on top of a group, naturally, you'd want to scroll the underlying group in realtime. What I found here is that to make anything happen, it wasn't enough to refer in code to a group by its id. I also had to refer to the stack that owns it.

What makes it all the more bizarre is that none of the example stacks that come with LiveCode have to do this. Also, when I tried to recreate the situation in a test stack, it all worked. I debugged, debugged again, pulled my hair out and went on to evaluate every line of code in the scrollerBeginScroll and scrollerDidScroll events as they executed. And then again with everything they called, but I just simply couldn't get to the bottom of why I had to be so specific.

Another quirk seems to be related. I couldn't get some aspects of the tree to draw when these routines were called inside of a handler. Once the handler finished, changes would be made, so they were being executed. Obviously, I needed them to happen at that precise moment and in the end, the solution was to call the routine by sending the message in time (tricks such as waiting for 0 seconds or locking and unlocking the screen didn't help one jot).

Ho hum. So, if you find that you can't get or set properties or modify the appearance of controls during a scrollerDidScroll event, try addressing it by its id and the stack that owns it (or just the topStack, if you don't know the stack's name or id). If you really can't get the appearance to change, try making those changes in a handler that's called using the send in time command.

Finally, the most frustrating issue I came across that I couldn't rely upon the name of the control that was placed in both the mouseControl or in the target, when scroller events were being executed. When a scroll group sits on top of another control, there's a really fine line between an event being sent to the underlying control, and thus filling the mouseControl with the name of an object, and immediately activating the scroller control, which returns the name or id of the card. If your scrollerDidScroll message looks to evaluate the mouseControl or the target to see what's underneath, it won't work all of the time.

Thankfully, each time a scroll event happens, it's possible to test the id of the control that's been interacted with. So, to overcome the mouseControl/target problem, the ids of all of the scroll controls that sat on top of Data Trees were cached upon their creation and by looking up the ID of the scroller being interacted with in the cache, the correct tree could be chosen and scrolled.

Last piece of advice

Having gotten to the end of the coding effort, my final piece of advice is to abandon mouse events altogether and go for touch events. But that story I shall save for another day.

Next steps

So the code is all done and I've tested it best I can with the simulator. All that's left to do is to update the manual, create a demo stack or two and I can put it all out for public testing on real life iOS devices.

So, in summary of all of that: almost there!

By Steve on Saturday, April 23, 2011

The last few weeks have not been great from a website/LiveCode perspective. As you're looking at the start of a brand new site here, you might very well be able to draw the conclusion that something un-brilliant has happened at .

It's true. The old site has gone.

But life moves on and every problem represents an opportunity. What's great is that I've been able to install the new version of DotNetNuke (DNN), which is my CMS of choice. Quite a few things have changed since 2008 and even though its very unlikely that the search engines will pick up on the content, I'll post about the issues (and solutions) that have had my head scratching.

And as for LiveCode, seems that the approach I took to getting Data Tree running on iOS hasn't worked out, so I'm back to the drawing board.

At least it's the Easter bank holiday and I have some time to sort this little lot out.




Login Copyright ©2011-2013