On Fri, Dec 31, 2010 at 4:03 AM, Stephen Chin <st
...@widgetfx.org> wrote:
> Well, probably not what you were wishing for when you thought about what
> you wanted for 2011, but I implemented it anyway.
> What is a length literal? Here are a few examples:
> 12px
> 5mm
> 2cm
> 1.5em
> They are similar to the Duration type, but applicable to a lot more places
> (think of how many different places you specify length or pixel values in
> most APIs).
> So what other interesting things can you do with them? You can:
> add lengths: 5cm + 5mm
> subtract lengths: 5cm - 5mm
> divide lengths: 5mm / 2
> divide lengths by lengths: 5cm / 5mm
> compare lengths: 5mm < 5cm
> This is all pretty basic, but the complexity comes in with different types
> of length. How do you convert from pixels to inches? What length is an
> em? I looked at all the different length systems in common use today, and
> came up with what I think is a reasonable system. Feel free to weigh in...
> The Visage Length class supports 4 different classes of lengths:
> - pixel - Exact screen pixels. This should not be used for layouts
> that need to be resizable or device portable.
> - dp - Density-independent pixels - Reference pixel for the target
> device. Will scale to a whole or even fractional pixel value based on the
> device viewing distance and density. This is approximately one pixel on a
> device with a density of 96dpi at arm's length. For example:
> - Desktop - 28 inches away, .26mm pixel (96 dpi), 1dp = 1px
> - Medium Density Mobile - 17 inches away, .16mm pixel (160 dpi), 1dp
> = 1px
> - High Density Mobile - 17 inches away, .16mm pixel (240 dpi), 1dp =
> 1.5px
> - 55" HD TV - 10 feet away, .73mm pixel (35 dpi), 1dp = 1.5px
> - sp - Scale-independent pixels - Similar to dp, but also relative to
> the user font scale. For the default font scale will be 1 to 1 with dp.
> - em - Typographic measure relative to the enclosing element's font
> height.
> - percentage - Percentage of the enclosing element's length or size.
> The DP and SP units are inspired from the Android APIs. DP is actually
> equivalent to the reference pixel concept in CSS, so it is really nothing
> new. However, defining it as 160dpi makes a lot of sense (for mobile), just
> not for desktop.
> SP units also have a CSS equivalent. They are semantically similar to the
> new rem (root em) unit defined in CSS3. It solves a fundamental problem
> with the em unit, which is the context sensitivity. It is often difficult
> to figure out what size an em will show up as. Also, simply reparenting an
> element specified in ems may change its size.
> Inches, centimeters, millimeters, points, and picas are losslessly
> converted into density-independent pixels at a scale of 96dpi (preserving
> compatibility with CSS). This is a pretty good approximation of
> print-format needs, so it should prevent gross resizing of pixels when
> inches become fixed to a physical unit.
> Percentage is a special case... it is entirely context dependent (on the
> container and field usage), so there is really no point converting it.
> To make it possible to include these concepts in the language where there
> is no knowledge of the device metrics or scenegraph context, I introduced a
> concept of ComplexLengths. Addition and subtraction of simple lengths may
> result in a new length object that cannot be simplified, such as:
> println("complex = {5px + 5dp}");
> This will literally print the following:
> complex = 5px + 5dp
> However, if an expression can be simplified, it will be:
> println("simple = {%#s 1cm + 1mm}
> simple = 11mm
> Notice that I used a funky formatting symbol on that expression. The
> Length type also implements Formattable with full support for width,
> precision, capitalization, justification, and alternate formats. The
> alternate format for lengths is to choose an equivalent unit that has the
> shortest form (in this case mm). The normal format method will simply use
> the base type (in this case dp) and print a decimal value to 6 significant
> digits.
> When lengths are complex or simply incompatible, certain operations may not
> work. For example, you can't compare px and dp, so this will throw an
> IncompatibleLengthException:
> 5px < 5dp
> You could fix this by first converting them to compatible units like the
> following:
> def dps = 5px.toDensityIndependentLength(1.5);
> 5px < dps
> Notice that I passed in a density factor of 1.5. This means 1px = 1.5dp,
> which would be appropriate for a very high resolution display (like a 240dpi
> WVGA phone display).
> There are similar conversion methods for every combination that I thought
> makes sense... although in practice, the one that will prove the most
> useful is the toPixels method.
> So with all this unit madness, what do I expect people to really do?
> - API Designers: Use the Visage Length type anywhere a length or font
> size would normally be used. When you get back a length, simply convert it
> to pixels (passing in the appropriate conversion factors) and let the Visage
> implementation do all the complex math.
> - Application Developers: Use lengths that make sense for the context
> you are working in... DPs (or a compatible measure) most of the time. EMs
> if you want to line up to the enclosing text. SPs when you want something
> to scale with the user font preference. Pixels when you really need to make
> sure it lines up with the device pixel grid (thin lines, etc.) Mixing and
> matching lengths is fine too.
> And why should this be a feature of Visage, and not the APIs built on top
> (maybe I should have started with this):
> 1. Succinctness - It is really nice to simply be able to write 1mm
> rather than Length {value: 1, unit: LengthUnit.MM}
> 2. Uniformity - CSS does lengths one way, Android another, JavaFX
> another... and even in the best case you have platform differences
> (Mac/Windows, IE/Webkit) that further complicate things. As long as you let
> Visage do the conversion of lengths, you can (mostly) ignore the underlying
> funky toolkits.
> The code for all this Length literal goodness is checked in if you want to
> take a look. Here is a link to the change list (which also includes a first
> pass at an Angle literal... more on this soon):
> http://code.google.com/p/visage/source/detail?r=00179720e5af01bd021ff...
> Cheers,
> --
> --Steve
> blog: http://steveonjava.com/