27 November 2009

Focus Loops within Focus Loops

Some time back I created my Sliding Panel component and did a demo of it here.

The problem with this component as it stands is that the focus goes around all the focusable components, including those on the sliding panel.  In other words, you can tab around the TextInput controls on the main forms, and then focus will disappear off onto the TextInput controls on the sliding panel, even if it’s closed.  What is really required is a separate focus loop around the components in the sliding panel.

I started off just by creating a new instance of FocusManager and pointing it at the SlidingPanel instance.  That solution suffered from two problems:

  • Firstly whilst focus would correctly move around all the components within the sliding panel, focus in the parent form would also include the components in the panel.   This wasn’t really a surprise as the FocusManager in the parent form will just go right ahead and include all the focusable component that it finds in its children, which will include those in the sliding panel.
  • Secondly, I hit a big bug in SystemManager.  I just clicked on a TextInput in the sliding panel and the app crashed in SystemManager::mouseDownHandler(), on the line:
index = childList.getChildIndex(p);

The code in SystemManager assumes that all the members of the forms collection are either pop-ups or direct children of the SystemManager instance.  My new FocusManager automatically added itself to the forms collection, but it was somewhere in the middle of the display list, not a pop-up of child of the SystemManager.  So I had to fix this issue, and for now I’ve just put that whole section of code in a try/catch block so that it survives the call to childList.getChildIndex(p).

The next problem to solve was that focus in the main form continued around all the controls in the sliding panel.  This was relatively easy to fix just by setting the tabChildren property of the SlidingPanel class to false.  This meant that the FocusManager handling the main form stopped adding any focusable components within the sliding panel.

However, this had a major side-effect – the FocusManager handling the components contained in the sliding panel didn’t work at all.  The reason was that in addFocusables() there was a call to isTabVisible() which searches up the display list to see if any parent objects have tabChildren set to false.  Of course, this spotted that SlidingPanel had its tabChildren property set to false and concluded that all its children should be ignored for tabbing.  So I had to create my own SlidingPanelFocusManager which didn’t perform that test.

The end result is here.  You can tab around the 6 TextInput controls and focus won’t enter any of the sliding panels.  If you open a panel, however, focus will move around the controls within the panel, including the button to open or close the panel.  It all works, but the number of changes to the mx framework mean that it won’t see production for a while until I make sure that there aren’t any more side effects.

20 November 2009

Custom Overlays and getting the scale

Custom Overlay and map scale

I needed to create a map with a movable circle on it, and then be able to hit a button and get a list of locations within that circle.

This presented a couple of problems – firstly how to draw a circle over the top of the map, and secondly, how big to make it.   Looking at the map API, there’s not an easy way to figure out what the scale of the map is.  In other words, you have to find out how many pixels wide the circle needs to be to represent a given radius in kilometres on the map, taking into account the current zoom level.

Here’s how I did it….

private function calculateMapScale():Number { var topLeft:LatLng; var bottomLeft:LatLng; var scale:Number; var distance:Number; topLeft = _mapPane.fromPaneCoordsToLatLng(new Point(0,0)); bottomLeft = _mapPane.fromPaneCoordsToLatLng(new Point(0, _map.height)); distance = topLeft.distanceFrom(bottomLeft) / 1000 ; scale = _map.height / distance; return scale; }

All the code above does is get the top and bottom of the map as lat/longs and then find the distance between the two points. Then I have the number of pixels and the distance they represent.

And the caveats are:

  • This relies on the use of one of the later versions of the API library – you need to set applyProjection to true on the GroundOverlayOptions otherwise you’ll get an oval instead of a circle.
  • I just get the vertical scale, and assume that the horizontal scale is the same.

Click on the image to get to my prototype app. The app includes a slider with a range of 0 to 10000 to set the radius in kilometres of the circle. The circle itself just moves automatically to the centre of the map.

26 September 2009

Scaling an mx:Text – The Bottom Line…

Have a look at my little test app here.

On the numeric stepper, keep increasing the scaling.

You’ll find at about 1.26, a strange thing happens – you lose the bottom line.

As usual in my adventures with the Flex SDK, it’s a bug.  But this time I don’t think it’s a bug in the Flex SDK.   I believe it is in the text control in Flash Player.

Anyway, there is a bug report, and it’s here: SDK-16876.

If you encounter this issue with showing controls on the screen, you can probably get around it by setting an explicit height on the Text control.  However, what happens if you want the Text control to grow it’s height?  Setting an explicit height simply isn’t going to work if you don’t know at runtime if the Text control will hold 2 lines or 20.

But there is another sting in the tail of this particular bug.  You may be able to work around this issue on the screen by either sizing components or not scaling them.  But there is one time where you will have to use scaling…..

Printing.

And that’s where I hit this problem.  I can’t use any of the existing solutions in my app because I need the Text control to grow to show all it’s text, and I need to print that Text component, so it needs to scale properly.

My test app uses a copy of the Text component, and I have updated it a bit.   I have added a new function:

private function getCalculatedTextHeight():Number { var textHeight:Number = 0; for(var i:int=0; i < textField.numLines; i++) { textHeight += textField.getLineMetrics(i).height; } // SDK-16876 // Comment in this line instead of the following one // to fix the issue. // return Math.ceil(textHeight) + 4; return Math.ceil(textHeight); }

It seems that there is a rounding error somewhere, because if you add 4 to the height returned by getCalculatedTextHeight(), the problem goes away. The downside is that Text controls appear a bit larger in height, but the major plus side is that all the lines in my Text controls now get printed.

I thank you.

25 August 2009

MAXwidget

18 August 2009

Loading assets on demand, and blowing up Flex Builder…

We’re using the Flash API for Google Maps.  You can specify your own image for a location marker, and because we don’t do anything by halves here, we wanted an image for each location.

So we generated 99 icons for 20 routes, with each route being a different colour, and the number embedded in the icon.  In fact, the background colours from the icons were generated using the colours from my Colour Scheme tool that I mentioned in my previous post.

So thats about 180 small images that we wanted to download to the client.  Rather than making each client download these images every time, we wanted the client to only download the images when they were required.  So the images are in their own swf which is simply a compiled stylesheet.  The stylesheet looks like this:


route1
{
drop1: Embed(source='../assets/drop_icons/1/drop_icons_1_1.png');
drop2: Embed(source='../assets/drop_icons/1/drop_icons_1_2.png');
drop3: Embed(source='../assets/drop_icons/1/drop_icons_1_3.png');
drop4: Embed(source='../assets/drop_icons/1/drop_icons_1_4.png');
drop5: Embed(source='../assets/drop_icons/1/drop_icons_1_5.png');
...etc...

I’ve named the styles according to how they are used, so that one style has all the icons for a single route.

Then I wrote a simple little app to make sure that I could get the images out and pass them to the map API.  You can click on the image at the top of this post to go to the test app – View Source is enabled, but you won’t get the images cos we had to pay for those…:-D

And then there was the problem of Flex Builder just exiting without warning. I found that after I had built the swf containing these 180 images, I would continue normally for a couple of minutes and then I performed some action like opening a project, and Flex Builder would just vanish. It exited. It was no more. A few very strange messages were produce, and reading between the lines it seems that Flex Builder just ran out of memory.

Flex Builder is working ok up to a point in that it managed to compile the swf.  However, there’s obviously something not being tidied up after the compilation, so I have raised a bug with Adobe and it’s here.  I’m pleased that it seems to be getting quite a bit of attention from the Adobe guys….

18 August 2009

Overlay colours in Google Maps

ColourScheme Test App

When you have more than one route overlay shown on a map, it gets a bit difficult to separate them out.  We needed to show several routes on a map all at once, and generating the colours using some fancy colour-wheel stuff just didn’t make the route overlays show up.

So we went for Plan B.  We needed to generate a fixed set of colours that we knew would show up on the map.  I needed a way of showing about 20 colours up against each other so that as routes were added, the colours would be so different that we would be able to see each route.  In addition, we wanted to make sure that the route colours were different to the default colours used to show roads etc on the maps themselves.

So I wrote a simple little app to show colours in a list.  You can drag the colours around, and as you select each colour, the colour picker at the top gets set, and you can then edit that individual colour with the picker.  You can click on the add button to add a new bar to the list.   As you make changes, the code window on the right gets updates, and you can copy that and paste it into your actionscript to create a colour array.

21 June 2009

Flash Builder 4 and netmon.swc

I downloaded the latest build of the new Flash Builder 4.0 standalone, hoping for a bit of a fiddle to see what it did.  Unfortunately I didn’t get very far.  I created about the simplest test app you’re like to to find, but when I came to build it, I got this error:

unable to open ‘C:\Program Files\Adobe\Flash Builder4 Beta\sdks\4.0.0\frameworks/libs/netmon.swc’

I’m not sure whether the forward slashes at the end of the path are the problem, and even if they were, I couldn’t find any configuration file to correct it. In any case, I really don’t think Flash Builder should throw an error like this just after a vanilla installation.

You can get around the issue by simply unchecking “enable network monitor” in the compiler settings for the project, but to me that’s not acceptable as I wanted to play around with the network monitor.

I’ve had a look at the Adobe bugs and there is an issue that mentions this error message here, but the issue report isn’t actually about the error itself. I’ve commented on this issue asking if there should be a separate issue for this.  After thinking about it for a bit, I added a new bug report anyway, and it’s here.

25 May 2009

Sliding Panel

Sliding Panel Test App

Sliding Panel Test App

I’ve been working on a screen that shows a diary something like the calendar in Outlook.  We’re targeting fairly low-spec machines with screen resolutions not more than 1024 x 768.

On one side I have a list of items that I can drag onto the schedule to create entries.  As development continues, the width of this list is getting wider as the implementors want more columns in the list, and the visible area of the schedule is getting smaller.

Once again, the old saying is never more true – Necessity is the Mother of Invention. I need to show a list and a schedule almost at the same time.

So here’s my solution to the problem.  My list of things to drag onto the schedule will go in a SlidingPanel on the right.  The user can click on the arrow button to show or hide the panel.  Once they have selected an item from the list on the right they can drag it onto the schedule, close the panel, and then move the item around on the schedule.

Click on the image above to go to my test app.  The SlidingPanel component can be set to anchor to the left or right, and start up open or closed.  The tab (the vertical bar with the button on it) is a separate component, SlidingPanelTabSkin, and you can change that to alter how the tab is displayed.   The only requirement is that it implements ISlidingPanelTabSkin and dispatches a SlidingPanelEvent when the user clicks somewhere on the tab to get the panel to open or close.

23 April 2009

Expanding TextArea Component

I’ve been working with printing with Flex for a while now, and hit a problem where my TextArea controls weren’t showing all their text when they were printed.

The problem arises because it’s difficult to figure out how many lines of text the TextArea will show, and hence how high to make the TextArea control.  My first attempt involved searching through the text for \r\n etc and adding the height of one text line for each of them.  That won’t work if the text has automatically wrapped within the control.

Why not use the textHeight property of TextArea, you’re asking?  Well, that’s what I tried, and I would have finished a lot quicker if it was that easy.  But unfortunately there are some bugs with the calculations that produce the textHeight.  One of them is described here.

I found some helpful stuff on the web, and the most promising page was from a bunch of guys called idletogether.com, here.  So I used that and created a test app that demonstrates a control based on TextArea, which will automaticlly expand or shrink as you edit the text.  It will also print properly by sizing itself according the length of text in it.  My app is here.

14 April 2009

Google Maps: Security Sandbox Error when using Flex Effects

For a while we have been wondering why we get a Security Sandbox Violation when we run an effect over a container that has a map in it. Just to make sure we all know what we’re talking about, here’s the error that we currently get:


SecurityError: Error #2122: Security sandbox violation: BitmapData.draw: http://10.44.181.34:8080/tls-hs/HomeServices.swf/[[DYNAMIC]]/1 cannot access http://mt0.google.com/mt/v=ap.92&hl=en&x=253&y=167&zoom=8&s=Galile. A policy file is required, but the checkPolicyFile flag was not set when this media was loaded.
at flash.display::BitmapData/draw()
at mx.effects.effectClasses::MaskEffectInstance/getVisibleBounds()[E:\dev\3.1.0\frameworks\projects\framework\src\mx\effects\effectClasses\MaskEffectInstance.as:771]
at mx.effects.effectClasses::MaskEffectInstance/initMask()[E:\dev\3.1.0\frameworks\projects\framework\src\mx\effects\effectClasses\MaskEffectInstance.as:650]
at mx.effects.effectClasses::MaskEffectInstance/startEffect()[E:\dev\3.1.0\frameworks\projects\framework\src\mx\effects\effectClasses\MaskEffectInstance.as:463]
at mx.effects::Effect/play()[E:\dev\3.1.0\frameworks\projects\framework\src\mx\effects\Effect.as:930]
..etc...

I think we have finally found the answer here.  And the answer is…

You can’t.   So don’t try.

When you run an effect, it attempts to render the entire container and everything in it to a bitmap, which it then processes to produce the effect.  But as Pamela Fox explains in the Google Groups post, they don’t really want to allow people to render parts of their maps to bitmaps which people can then mess about with.

I’ve had a moan about this on three points:

  1. I can’t find any documentation anywhere that explicitly says that you can’t do effects over a map. At least if you type in “Google maps flash effects” there’s nothing that I could see to tell me that effects aren’t supported.
  2. I think effects should be able to run over a map.  After all, the whole point of Flex it provide a “Rich” application, and effects are a sizeable part of that.
  3. The error message we get relates to a Sandbox Violation.  How are we supposed to figure out from that that drawing to a bitmap (and hence effects) is disabled?

In the meantime, it seems we have to remove the map from the display list whilst an effect is playing, and that’s the solution described in the Google Groups post.

Update – I had a reply from Pamela Fox on the Google Maps team and there’s a issue for this here.  Please star this issue and add to the growing band of developers who want to do effects stuff….