Old methods die hard

 

A little over a year ago, I wrote a workaround for displaying multiple spaces in HTML TextField instances. The trick is to add   to each space. In non-Flash HTML, this would create two spaces for each space, but since the Flash TextField class is unfortunate in so many ways, it ignores the entity, but not completely. Instead of inserting a space,   creates an invisible divider, allowing multiple consecutive spaces in an HTML TextField instance.

In that same article, I shared my HTMLFormat.space(n) method that returns n spaces using a for loop. I’ve been using this method for the past few years, not thinking twice about it. Then, last week, I was showing it to a co-worker, saying it was faster than the String.replace() method. I have no idea why I said that, considering I never tested it—I just assumed. Of course, I was embarrassed when it turned out to be five times slower.

I headed to my Test app to find the best approach. Here’s the code I used:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package app.test {
	import flash.display.Sprite;
	import flash.utils.getTimer;
 
	import format.HTMLFormat;
 
	public class Test extends Sprite {
		public function Test () {
			__init ();
		}
 
		private function __init ():void {
			var $a:uint, $A:uint;
			var $before:int, $after:int;
			var $string:String;
 
			$A = 10000;
 
			$string = "Hey there  , what is    going on    ?";
 
			$before = getTimer ();
			for ($a = 0; $a < $A; $a++) {
			 	$string.replace (" ", "&nbsp; ");
			}
			$after = getTimer () - $before
			trace ("String.replace (\" \", \"&nbsp; \");", $after);
 
			$before = getTimer ();
			for ($a = 0; $a < $A; $a++) {
			 	$string.replace (/[ ]/ig, "&nbsp; ");
			}
			$after = getTimer () - $before
			trace ("String.replace (/[ ]/ig, \"&nbsp; \");", $after);
 
			$before = getTimer ();
			for ($a = 0; $a < $A; $a++) {
				"Hey there" + HTMLFormat.space (2) + ", what is" + HTMLFormat.space (4) + "going on" + HTMLFormat.space (4) + "?";
			}
			$after = getTimer () - $before
			trace ("HTMLFormat.space (n);", $after);
 
			$before = getTimer ();
			for ($a = 0; $a < $A; $a++) {
				String ("Hey there" + HTMLFormat.space (2) + ", what is" + HTMLFormat.space (4) + "going on" + HTMLFormat.space (4) + "?")
			}
			$after = getTimer () - $before
			trace ("String (HTMLFormat.space (n));", $after);
 
			$before = getTimer ();
			for ($a = 0; $a < $A; $a++) {
				("Hey there" + HTMLFormat.space (2) + ", what is" + HTMLFormat.space (4) + "going on" + HTMLFormat.space (4) + "?") as String
			}
			$after = getTimer () - $before
			trace ("HTMLFormat.space (n) as String;", $after);
 
			$before = getTimer ();
			for ($a = 0; $a < $A; $a++) {
				"Hey there" + "&nbsp; &nbsp; " + ", what is" + "&nbsp; &nbsp; &nbsp; &nbsp; " + "going on" + "&nbsp; &nbsp; &nbsp; &nbsp; " + "?";
			}
			$after = getTimer () - $before
			trace ("\"&nbsp; \"", $after);
 
			$before = getTimer ();
			for ($a = 0; $a < $A; $a++) {
				String ("Hey there" + "&nbsp; &nbsp; " + ", what is" + "&nbsp; &nbsp; &nbsp; &nbsp; " + "going on" + "&nbsp; &nbsp; &nbsp; &nbsp; " + "?");
			}
			$after = getTimer () - $before
			trace ("String (\"&nbsp; \");", $after);
 
			$before = getTimer ();
			for ($a = 0; $a < $A; $a++) {
				("Hey there" + "&nbsp; &nbsp; " + ", what is" + "&nbsp; &nbsp; &nbsp; &nbsp; " + "going on" + "&nbsp; &nbsp; &nbsp; &nbsp; " + "?") as String;
			}
			$after = getTimer () - $before
			trace ("(\"&nbsp; \") as String;", $after);
 
			$before = getTimer ();
			for ($a = 0; $a < $A; $a++) {
				$string.split (" ").join ("&nbsp; ");
			}
			$after = getTimer () - $before
			trace ("String.split (\" \").join (\"&nbsp; \");", $after);
		}
	}
}

And, the startling results:

String.replace (" ", "&nbsp; "); // 15
String.replace (/[ ]/ig, "&nbsp; "); // 142
HTMLFormat.space (n); // 72
String (HTMLFormat.space (n)); // 73
HTMLFormat.space (n) as String; // 75
"&nbsp; " // 15
String ("&nbsp; "); // 15
("&nbsp; ") as String; // 19
String.split (" ").join ("&nbsp; "); // 178

It looks like your best bet is to use the String.replace () method with a String pattern. Though typing out “&nbsp; “ is just as fast, it’s an inconvenience for the developer to type out and dirties up the code. As you might have guessed, I will retire the HTMLFormat.space (n) method and spend a solid hour refactoring some code.

At Adobe MAX

 

Adobe MAX

I arrived at the LA Convention Center this afternoon to get my MAX badge and everything looks amazing. I spent the day hanging in the community plaza, where all the booths are set up. This place is massive and everyone is so very busy. I’m getting tons of swag and my badge even says MAX Staff—unreal. The action starts tomorrow, so expect a ton of #adobemax tagged tweets.

Note: If you use DestroyTwitter and can’t stand people who tweet from events, add this regex to your exclude keywords: #adobemax[A-Za-z0-9]*

Tutorial: Context menus are our friends if we use them correctly

 

In my quest to blur the line between native apps and AIR apps, I decided to fully incorporate context menus (right-click) in the next release of DestroyTwitter. In my initial tests, I came to realize that the ContextMenu class is the roommate who is really nice and optimistic before you move in, then a nightmare to get along with once you’re finally settled. It screams to be extended, but ironically it’s a final class (not extendable). After a few hours, I found a solution. But first, the problem.

Let’s say I have 100 icons. I want each icon to have five actions accessible from its context menu. This results in 100 ContextMenu instances and 500 NativeMenuItem instances, as seen below:

ContextMenu memory

This is not pretty. The solution: share. In programming, sharing is one big step towards drastically reducing memory usage. If I share a single context menu, I will have one instance instead of 100 and five item instances instead of 500.

Context Menu memory

As expected, memory usage is divided by 100. The problem with sharing the ContextMenu class using a display object’s contextMenu property is that it can’t be done. On paper it can be, but not the way you want. To share a context menu, you’d have to listen on Event.DISPLAYING and use the hitTest() method to check which object the user is right-clicking. From a developer’s standpoint, this is simply unethical. Also, Flash content doesn’t update the mouse position between sequential right-clicks, so you could have a major issue with power users.

The solution is to forget the ContextMenu class altogether. While you’re at it, forget the contextMenu property as well. If you want something done right, you have to do it yourself. Add a listener to the MouseEvent.RIGHT_CLICK event, share a single NativeMenu instance, and call the NativeMenu.display() method in the right-click handler. For the purpose of this demonstration, I construct the NativeMenu in the Icon class. Since we’d ideally share the menu, you’d construct it outside of the class that’s using it, then reference it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package {
	// import classes
 
	public class Icon extends Sprite {
		public var _menu:NativeMenu;
 
		public function Icon () {
			__construct ();
			__init ();
		}
		private function __construct ():void {
			_menu = new NativeMenu ();
 
			// construct NativeMenu items
		}
		private function __init ():void {
			addEventListener (MouseEvent.RIGHT_CLICK, __rightClick__, false, 0, true);
		}
		private function __rightClick__ ($event:MouseEvent):void {
			// change NativeMenu items' attributes
 
			_menu.display (stage, stage.mouseX, stage.mouseY);
		}
	}
}

There is a second chapter to the context menu nightmare, which is the API for managing items. It’s clumsy, excessive, and requires the developers to write some pretty gross-looking code. I’ll save the solution to that for another time.

Adobe MAX Companion launched

 

MAX Companion

The Adobe MAX Companion has been my life over the past two months. It was my first project as an Adobe employee and I’m thrilled that it’s finally live. The app sports the ability to tweet about the conference with the proper hashtags automatically included as well as streams from each session. There’s a section for sessions, including a view of your own schedule along with a filter to quickly find what you’re looking for.  It also provides maps of the venue. Check it out and if you’re attending MAX, use it for a chance to win some sweet prizes.

Video chat at 34,000 feet

 

Video chat at 34,000 feet

Technology continues to amaze me. Can you remember a time before cell phones, when you had ALL of your friends’ phone numbers memorized. Back then, it was a bit easier without area codes. Now, I can video chat with Jen from an airplane. Here’s to the future.

Off to Adobe MAX

 

Off to Adobe MAX

I leave for Adobe MAX within the hour, making a pit stop in San Francisco to join up with the Adobe XD crew, then to Los Angeles for MAX. The past two months have been spent on an Adobe AIR app for the conference. I’ll be sure to post about it when it goes live—a day I’ve been longing for. Since this year’s MAX is Star Wars/Trek themed with Mark Hammil, aka Luke Skywalker, co-hosting with LeVar Burton, I decided to bring my Diesel stormtrooper shoes. To all Destroy Today readers attending MAX, I’ll see you there!

Today is my 23rd birthday

 

23rd_birthday

Another day, another baby photo sent in an email from mom. It seems I forget my birthday more and more each year, but luckily I’ve had Jen around for the past two years to remind me. Recently, I’ve ended up in moment of five minutes or so where I just sit. I don’t necessarily think of anything specific—memories fly by, but I can’t seem to grasp one. It’s the sort of feeling you think a brain dead person might have. I don’t know what it is, but it sure does remind me how fast the years have passed.

Linvilla Orchards and the 50mm 1.2L

 

Linvilla Orchards

Linvilla Orchards

Jen and I recently went home to PA for a weekend visit with my newly acquired Canon 50mm 1.2L. When I had the Canon 30D, my 35mm 1.4L had the perfect focal length, but after upgrading to full frame with the Canon 5D MKII, it became too wide. Since the 35mm on the 30D’s 1.6x crop body is the equivalent to 55mm on full frame, I decided to take the plunge and pick up the Canon 50mm 1.2L. I couldn’t be happier with the lens—its bokeh makes butter feel like concrete. While in PA, Jen, her sister, and I stopped at the Linvilla Orchards for some test shots and fresh apples. Check out the photos on Flickr.

DestroyTwitter + Twitter = @destroytwitter

 

DestroyTwitter twitter account

DestroyTwitter is finally on Twitter. For the past nine months, I’ve used my personal Twitter account (@destroytoday) to post news and respond to feedback. That’s all fine by me, but I figured an account of its own would make things more official. Lots of people asked how I was able to get an account with the word “Twitter” in the name. In all honesty, I simply asked. Since DestroyTwitter has been around for a while (for a Twitter app), they were able to make an exception. If you haven’t done so already, go ahead and follow the @destroytwitter account—and keep an eye out over the next few weeks.

Tutorial: Coloring Eclipse

 

If you follow me on Twitter, you probably already know that I wear sunglasses in front of the computer at night. Cool, right? I do this because my eyes get warn out and the brighter the screen, the more my eyes hurt. Unfortunately, turning down the brightness of the screen doesn’t help as much as you’d think it would, so I resort to shades.

The brightest color on the screen, white, does the most damage. And oddly enough, Eclipse, the application I use the most, is as white as it gets. I previously developed a theme for TextMate, which helped tremendously, but I don’t use TextMate as often as I’d like. For whatever reason, I never thought of coloring Eclipse until last night. Here’s how you do it.

(Click the images to view at 100%)

Coloring Eclipse / General

Eclipse is a bit more involved when it comes to customization than TextMate. Because it utilizes a variety of plugins, the preferences are not all standardized and they are not all in the same place. Let’s start with the general colors—for items such as background/foreground colors, highlights, selections, etc. These are all located under General/Editors/Text Editors. Under “Appearance color options” there are nine items to color using the button to the right of the menu. The problem I have with this color picker, if you’re using OS X, is that you can’t enter Hex values by hand—the color has to be either chosen with a slider or sampled with the eye dropper.

Coloring Eclipse / Actionscript

Now, with syntax coloring, located under Flash(Flex) Builder/Editors/Syntax Coloring, Eclipse doesn’t apply the previously chosen background color to the preview seen above. It’s easy enough to imagine how things will look if you already have your Hex values picked out. Above the preview, you have three expandable menus to configure: Actionscript, CSS, MXML. Here you get to specify text colors and decorations, with the choices of bold, italic, and underline—I keep my syntax decoration free. The color picker in Syntax Coloring is beautiful. It has a field for the Hex value and that’s all I need. Once you’ve handled the syntax, there’s one last step.

Coloring Eclipse / Annotations

Annotations are located at General/Editors/Text Editors/Annotations. They are the little things that only occasionally make an appearance—for instance, “Debug Call Stack”. This one, in particular, is the style for when your application has a runtime error, reverts to the workspace, and highlights the problematic line. The fanciness about these sets of annotations is that you get to choose between outlined boxes, filled highlights, squiggly underlines, etc. I only needed to color the breakpoint, debug, and error annotations, but there are a dozen others for those that use them.

Coloring Eclipse

When you’re all set, you’ll have a brand new look, based on your styles. My eyes feel tremendous now that the bright white has been replaced with my Destroy Today darkest gray. Please note, I have yet to find a way to export the styles, but if anyone comes across how, please let me know.