Wednesday, September 7, 2011

Dome Land Wilderness - Trip Report

It was Labor Day weekend and we wanted to go somewhere off the beaten path to avoid the crowds of unwashed masses. Greg suggested we check out the Dome Land Wilderness, with a name like that how could we argue?

Greg and Carly came from the south, and I was coming from the north. We met at the Kernville Ranger Station. The rangers and people of Kernville were über friendly. One of the rangers even invited Greg back to go climbing :)

Big Meadow

We car camped at Big Meadow the first night. Big Meadow can be accessed via the myriad of dirt roads that run through the park. Our approach was from the Kern River Highway (Mountain Highway 99, M99). We took Sherman Pass Road until it met with a dirt road (Forest Route 22S12 -- the dirt roads all have fancy names like this). These roads are mostly sufficient for any type of vehicle (in good weather conditions).

Big Meadow is at 8,000 feet and it's spectacular. We left the crowds camping by the river on M99, and saw only one other party camping that night. This is a great place to take your family, there's lots of sites to camp around the meadow.

Manter Meadow

The next day, we drove around to the other side of Big Meadow to the Manter Meadow trail head. The rangers had warned us about snakes, and we arrived to a rude awakening at the trail head. Just as we arrived, 3 hikers were coming off the trail. They told us that someone in their party got bit by a rattle snake. The young lad was doing OK, but was 2.5 miles up the trail at the meadow.

We offered to assist, but there wasn't much we could do. We headed out, a little weary. When we arrived at Manter Meadow, we found the rest of their party and got filled in on the details of the snake bite incident: the lad literally did not look before he leaped over a log, and there was a lot of log-leaping to do. The area had burned several years ago, and there were lots of downed trees and logs to cross. After you get to Manter Meadow, the trails can be difficult to see. Suffice it to say, we were very careful crossing the log fields and often opted to walk through the meadow.

There are some really nice camp spots at the east end of the meadow. We rounded the corner and headed east towards the South Fork of the Kern river, following the trail to Little Manter Meadow and beyond. It was easy to loose the trail here. The fire, resulting flash floods, over-growth, and general under-use of the trail meant that if you weren't paying attention, you might end up doing some bush whacking (and we did!)

There are signs and trail markers along the way. A good map/compass/GPS is advised.

Our Own Private Idaho, in California

Our original goal was to reach the South Fork of the Kern River. We decided not to descend all that way, knowing the trails might lead to more bush whacking. We stayed in this really cool canyon/valley with interesting rock formations outlining the valley. It was a good decision, because we got to relax and just enjoyed being there. On the way back, we found the trail and stayed on it mostly. We scrambled through some rough spots, but the uphill hike out was much faster.

Dome Land, come again?!

We can't wait to get back to Dome Land Wilderness. It's beautiful and remote. The myriad of dirt roads means it's accessible for those willing to take the time and effort to get out there. Some of the trails may not be well maintained or used, but with this knowledge our next trip should be even more fun!

Sunday, October 17, 2010

Flash player level focus vs. component level focus

From the FocusManager docs:

The FocusManager manages focus from the "component level". In Flex, a UITextField in a component is the only way to allow keyboard entry of text. To the Flash Player or AIR, that UITextField has focus. However, from the FocusManager's perspective the component that parents the UITextField has focus. Thus there is a distinction between component-level focus and player-level focus. Application developers generally only have to deal with component-level focus while component developers must understand player-level focus.

The Flash player doesn't see a Flex component as something that can receive focus. Flex's FocusManager remedies this, and does all the heavy lifting for you. However, if you're working with a FocusEvent, you soon realize that the event's target and relatedObject properties are not what you might be expecting.

FocusEvent is dispatched natively by the Flash player (it's not a Flex event). So the objects retrieved by the target and relatedObject properties of the FocusEvent are with respect to Flash player level focus (they will be some lower level objects, not Flex components).

Use the FocusManager in conjunction with FocusEvent

The FocusManager has two useful methods that you should be using in conjunction with FocusEvent:

  • findFocusManagerComponent(o:InteractiveObject):IFocusManagerComponent
  • getNextFocusManagerComponent(backward:Boolean = false):IFocusManagerComponent

Use findFocusManagerComponent() to translate the low level object in the event's target property into the Flex component that contains the low level object.

Use getNextFocusManagerComponent() to determine where the focus is going next. Don't use FocusEvent's relatedObject property for this. This method accepts a Boolean argument to specify whether the focus is moving forwards/backwards. BTW, there is a bug in Flex 3.3 where this argument is ignored, fixed in Flex 4 and 3.5.

Thursday, August 26, 2010

Create a focusable component

In a Flex application a focusable component implements the IFocusManagerComponent interface. UIComponent implements the methods of this interface, so your work is mostly done! However, since not all UIComponent's are intended to be focusable (containers, labels, etc.) UIComponent's class declaration does not state that it implements the interface.

Step 1: implement this interface by adding "implements IFocusManagerComponent" to your class definition

Note: in an MXML component you could do this w/the 'implements' attribute.

Step 2: set the appropriate values on the tab & focus related properties

This all depends on what your component does. The interesting properties are tabEnabled and tabChildren. Here some examples of how you might use them:

  • Your component gets focus, but not it's child objects: use tabEnabled=true, tabChildren=false
  • Your component does not get focused, some of it's child objects do: use tabEnabled=false, tabChildren=true
  • Your component gets focus, and so do some of it's children: tabEnabled=true, tabChildren=true
PropertyClassNotes
tabEnabledInteractiveObject Whether the user can tab navigate to this component. UIComponent sets this to 'true' if the component implements IFocusManagerComponent
tabIndexInterativeObject Optional, specifies the index of this component in the tab order. After all I've learned, I say avoid using this. More on this later!
tabChildrenDisplayObjectContainer Whether or not child objects of your component are able to be tabbed to. The default is true.
focusEnabledUIComponent Whether the component can receive focus when tabbed to. The default is 'true'.
hasFocusableChildrenUIComponent Flex 4 only! Similar to the tabChildren property, docs say that Flex apps should not use tabChildren.
mouseFocusEnabledUIComponent Whether or not the component can be focused with the mouse. This is a strange property b/c somewhere else some other class seems to decide whether or not to honor it. Default is 'true'.
tabFocusEnabledUIComponent Flex 4 only! Similar to tabEnabled property. Default is 'true'.

Step 3: Implement keyboard support

Making something focusable means that keystrokes will be sent to your component when it has focus. So go the distance and add sensible keyboard support to your component.

When your component has focus, it's keyDownHandler() and keyUpHandler() methods will be called as the user is typing. Override the keyDownHandler() method and you're off to the races.


override protected function keyDownHandler(event:KeyboardEvent):void
{
    switch(event.keyCode)
    {
        case Keyboard.ENTER:
            dispatchEvent( new MouseEvent(MouseEvent.CLICK) );
            break;
  // and so on
    }
}

Wednesday, August 25, 2010

30 Days of Accessibility

For the last month or so, I've been delving into the topic of accessibility in Flex. I've learned a lot, and know there is still plenty more to learn (there always is). But it's already changed how I approach building an app or component.

I've decided to post something (hopefully) useful about accessibility once a day for a month. 30 days seemed like a good challenge, and it's about how long I been a learnin'. So here I go.

Event listeners and keyboard navigation

Why am I starting here? I think there's plenty of info already available, it's how I got here. This is actually something I would never have thought twice about. But maybe you should.

Watch what you listen for!

Pun intended. Here's an example with ComboBox. It dispatches ListEvent.CHANGE when the selection changes, and DropDownEvent.CLOSE when the drop down list closes. When the user is navigating with the keyboard, there is a big difference between these two events!

The CHANGE event will be dispatched each time the user uses the arrow keys to move the selection in the drop down list. This would fire your listener many times, when the user pressed down arrow to choose something from the drop down list. It's not a problem when using the mouse.

Instead, listen for the CLOSE event (DropDownList.CLOSE) and know that your listener will fire when the user finishes interacting w/the ComboBox.

Be careful about where you add your event listeners

Let's say your itemRenderer is a Canvas with some labels and pretty pictures. Now you add a CLICK listener to the canvas (or even the image). However, there's no way to trigger a CLICK event on this itemRenderer with using only the keyboard :(

Note, I've been working on a Flex 3 project lately, but I don't think this is any different in Flex 4. My solution was to extend List and override keyDownHandler(). When the ENTER key is pressed, I dispatch ListEvent.ITEM_CLICK. ITEM_CLICK is already dispatched when you use the mouse, problem solved!


override protected function keyDownHandler(event:KeyboardEvent):void
{  
   super.keyDownHandler(event);
   // the super classes return on these conditions, this should too
   if (!selectable || !iteratorValid || !collection || itemEditorInstance )
      return;
   // our own reason to do nothing
   if (selectedIndex == -1)
      return;
   
   switch (event.keyCode)
   {
      case Keyboard.ENTER:
         dispatchEvent( new ListEvent(
            ListEvent.ITEM_CLICK, false, false, -1,
            selectedIndex, null,
            indexToItemRenderer(selectedIndex) ) );
         break;
   }
}
// now listen for ITEM_CLICK being dispatched by the list
// in your listener, use the event's itemRender property
// to get at the selected item: event.itemRenderer.data

The lessons I learned

Know what events a component dispatches with respect to mouse and keyboard interaction. Then make sure your event listeners can be triggered using keyboard navigation.

Bonus points
  • Look at the keyDownHandler() method of any UIComponent to see how it processes keystrokes. keyUpHandler is available too, but not necessarily as useful (Button uses it for auto-repeating keystroke support)
  • If you don't want to read code, you can read some Adobe docs to see how keyboard navigation works for each component.

Thursday, April 1, 2010

Conditional breakpoints in Flash Builder 4 can result in slooooow execution

Flash Builder 4 has some nifty new features, and I'm glad it's finally released. One of the new features that I forgot to try out (until today), was using a conditional breakpoint.

To make a breakpoint conditional, just right click it and choose "Properties". Doing this, however, can dramatically slow down the execution of your code, if your breakpoint is in a method that gets called frequently.

This is somewhat understandable, as the condition needs to be evaluated each time your breakpoint is reached. In my case the breakpoint was in the updateDisplayList() method of a Spark Layout class ... and it made scrolling in my List control unbearable. Fortunately, I didn't waste too much time before I realized that my conditional breakpoint was the cause!