02-09-2011 09:19 AM
I've searched for half an hour but can't find it.
Did someone (John or Joynal probably) post a snippet or draft version of code that implemented an "overlay" (popup, alert, whatever you call it) that looked basically like the standard ones you get by clicking on the hammer or music icons in the system status bar?
I'm interested mainly in learning how one might cleanly generated the non-rectangular shape (presumably applying a mask?) and especially the white outline which is not just a rounded-rectangle shape but doesn't look like it was done with a mere drawPath().
As a Flash newbie, some of these things get me stumped while I reprogram my brain.
If there was no previous post on that, can anyone offer guidance? Thanks!
Solved! Go to Solution.
02-09-2011 09:36 AM
I did not post code, but I do remember that some may have. I do this a lot in one of my apps. I am not near that code set just now but basically:
Pseudo code for draw:
override protected function draw() : void
{
this.graphics.clear();
this.graphics.lineStyle( 3, 0xFFFFFF ); // white thick border
this.graphics.beginFill( 0xFFFFFF, 0.50 ); // translucent white fill
this.graphics.moveTo( 0, 10 );
this.graphics.lineTo( (this.width/2) - 5, 10 ); // start of mid-arrow
this.graphics.lineTo( this.width/2, 0 ); // arrow point
this.graphics.lineTo( (this.width/2) + 5, 10 );
this.graphics.lineTo( this.width, 10 );
this.graphics.lineTo( this.width, this.height );
this.graphics.lineTo( 0, this.height );
this.graphics.lineTo( 0, 10 ); // close end point
this.graphics.endFill();
// add drop shadow in constructor
// IN CONSTRUCTOR: this.filters[] = ...
}
Adjust geometry as needed.
In my classes, I even override the x and y attributes to be used where I want the arrow head to be placed once I convert local to global coordinates.
02-09-2011 10:06 AM
Hmm... I can see that using a transparent fill and drawing the outline would be sufficient to avoid the need for a mask, but wouldn't your code produce sharp corners? The one on the PlayBook has perfect quarter-round corners.
Or... would curveTo() be able to produce those corners too? Searching suggests it can, with some tweaking to get the corners just right since where to place the control point may not be obvious (i.e. the corners may not look like they have a constant radius if you just put the control point where a regular corner would be).
02-09-2011 10:15 AM - edited 02-09-2011 10:16 AM
curveTo are bezier curves, so a "good" arc would have the controls points as the end points of the arc and the corner of the rectangle for the tangent ends of the 2 control lines. If the curve still looks a little oblong, try 0.667 arc radius.
Alternatively, an arc can be a series of short line segments. The number of points in the arc is proprotional to the radius to reduce a facetted look. Bezier curve might be good since the corners are not too large.
02-09-2011 10:22 AM
I think the post you are looking for is here. The term 'popover' was used instead of popup or overlay, so thats probably why you didnt find it.
02-09-2011 10:41 AM
Thanks Bill (and John). Oddly the word "popup" was used in the content of that thread so I don't know why I missed it either, but in any case that's the one.
I note he doesn't (if I understand the code) use a lineStyle(), so he's just doing the background, and used a rounded-rect for the main portion. I'd still be quite interested if there's some way to use that for the outline as well, mainly out of curiosity. I think I can combine curveTo() and John's point about using a background fill to do it in one shot (using drawPath(), no doubt, after setting up a matrix of coords).
02-09-2011 01:10 PM
I started with @zezke's code and adapted it to more closely match the system "popover" as a learning exercise.
package {
import flash.display.*; // don't use wildcards imports in real code
import flash.geom.*;
[SWF(width="1024", height="600", backgroundColor="#777777", frameRate="20")]
public class PopOverTest extends Sprite {
public static const WIDTH:int = 316;
public static const HEIGHT:int = 207;
public static const ARROW_WIDTH:int = 22;
public static const ARROW_HEIGHT:int = 10;
public static const CORNER_SIZE:int = 3;
public function PopOverTest()
{
// where the arrow will point
var p:Point = new Point(610, 150);
graphics.beginFill(0x0099ee);
graphics.drawRect(0, 0, 1024, 600);
graphics.beginFill(0x994400);
graphics.drawCircle(p.x, p.y, 100);
// set up line and fill
var popover:Shape = new Shape();
popover.graphics.lineStyle(3, 0xffffff, 1, true);
var mat:Matrix = new Matrix();
mat.createGradientBox(WIDTH, HEIGHT, Math.PI / 2, 0, HEIGHT/2);
popover.graphics.beginGradientFill(GradientType.LI NEAR,
[0x444444, 0x000000], [0.75, 0.75], [30, 220], mat);
var cmds:Vector.<int> = new Vector.<int>();
cmds.push(GraphicsPathCommand.MOVE_TO, // point of triangle
GraphicsPathCommand.LINE_TO,
GraphicsPathCommand.LINE_TO,
GraphicsPathCommand.CURVE_TO, // top-right corner
GraphicsPathCommand.LINE_TO,
GraphicsPathCommand.CURVE_TO, // bottom-right
GraphicsPathCommand.LINE_TO,
GraphicsPathCommand.CURVE_TO, // bottom-left
GraphicsPathCommand.LINE_TO,
GraphicsPathCommand.CURVE_TO, // top-right
GraphicsPathCommand.LINE_TO,
GraphicsPathCommand.LINE_TO // pack to point of triangle
);
trace(cmds.length, cmds);
// form two rectangles defining all eight corner points
var rt:Rectangle = new Rectangle(p.x - WIDTH / 2, p.y + ARROW_HEIGHT, WIDTH, HEIGHT);
var rw:Rectangle = rt.clone();
rw.inflate(0, -CORNER_SIZE * 2);
rt.inflate(-CORNER_SIZE * 2, 0);
var base_offset:Number = (rt.width - ARROW_WIDTH) / 2;
// build coordinate list from defined points
var coords:Vector.<Number> = new Vector.<Number>();
coords.push.apply(coords, [p.x, p.y,
rt.right - base_offset, rt.top,
rt.right + 2, rt.top,
rw.right, rt.top, // TR control
rw.right, rw.top + 2,
rw.right, rw.bottom,
rw.right, rt.bottom, // BR control
rt.right, rt.bottom,
rt.left, rt.bottom,
rw.left, rt.bottom, // BL control
rw.left, rw.bottom,
rw.left, rw.top + 2,
rw.left, rt.top, // TL control
rt.left - 2, rt.top,
rt.left + base_offset, rt.top,
p.x, p.y
]);
popover.graphics.drawPath(cmds, coords);
popover.graphics.endFill();
addChild(popover);
}
}
}
The bezier-curve corners work out fairly well, though as you can see I had to tweak the top two corners. When I didn't, they came out a bit squashed to one side. I think it's probably a bug in the curve calculations (not mine) but don't have the expertise to be sure. I would have expected that drawCurve() curves drawn between three points with a particular relationship should look the same regardless of which of the four orientations they're rotated too.
I'm still curious if there's a drawRoundRect() technique that could do this... some way of overwriting the top line easily where the arrow goes? Seems like it could be possible, but perhaps messy.
Anyway, here's how it looks, with the system media player "popover" thing showing on top for comparison.
02-09-2011 01:20 PM
You can do a round rect and then draw 2 triangles after the round rect call so that the bottom of the triangle will mask the border thinkness. The first triangle has no border line (thinkness=0) with the same background fill color (assumes opaque). This will give you the same background and mask that section of the round rect border. The last call would be to create 2 lines (moveTo, LineTo) to draw the border of the triangle. Be certain to use the rounded miter on the line creation so that the flatness of the line caps do no stickout if the border thinkness is significant.
02-09-2011 01:24 PM
jtegen wrote:
The first triangle has no border line (thinkness=0) with the same background fill color (assumes opaque). This will give you the same background and mask that section of the round rect border.
"Assumes opaque"? So this wouldn't work for this particular style, would it? It has a semi-transparent background, and I couldn't think whether there was a way to "erase" the border under those conditions. My gut says if you use alpha levels that can't be done, and it only looks like you're erasing the line even when it's opaque (with the end result you want, but by overwriting with the solid background colour).
02-09-2011 01:43 PM
If I am doing it, then I will use the draw Arc method.
In such case, I can either simply draw the outline without fill,
or I can fill to make it opaque.
The graphic has drawRect, drawRoundRect, and moveTo, lineTo etc methods, but there is no such drawArc;
but, I found and used this cool draw Arc code at :
http://www.pixelwit.com/blog/2007/07/draw-an-arc-w
---------------------
a) If you like my response/post, please provide a Kudo (white star to the left).
b) If my post solved your problem please click on the Accept as Solution button.