Sunday, January 29, 2012

Creating a Flex AIR Screenshot app: Part 8

Today we start working on adding content to the screenshot settings page of our application.

The screenshot settings page is the screenshotsettings NavigatorContent container block. Here, we need to display give the user ability to, first of all, select what screen sizes does he want to use. There will be a list of 7 items total - all with a checkbox to let the user quickly set what screen sizes he wants to use this time.

The first item of the 7 will not be the same as the other ones though. The first item will represent that "as is" function I've been talking about in earlier tutorials. This is the option that the user can select to export the whole site content as it is. So this item only consists of 1 checkbox and a text label.

The remaining 6, however, will contain of a checkbox, 2 text fields and some labels. The text fields are used to enter width and height for the screen.

Because these 6 items will be identical, it is wise to make one custom component and use that multiple times.

First, let's add the first item to the container. Create a SkinnableContainer, set some of its style properties to make it look nice, create a checkbox inside of it and a label. Set the label's styleName to settingText and id to contSize:

<s:NavigatorContent id="screenshotsettings">
<s:VGroup width="100%" horizontalAlign="center" paddingTop="20">
<s:Label styleName="descriptionText">Select screenshot screen sizes:</s:Label>
<s:SkinnableContainer backgroundColor="#999999" width="310" height="18" >
<s:CheckBox toolTip="Use this screen size" x="4" selected="true" />
<s:Label id="contSize" styleName="settingText" x="22" y="3" />
</s:SkinnableContainer>
</s:VGroup>
</s:NavigatorContent>

We can set this label's text in the changeState() function. We do it through code to include the contentWidth and contentHeight values in the label's text value:

private function changeState():void {
if (stack.selectedChild == loadpage) {
contentBox.setStyle("horizontalAlign", "center");
urlInput.text = urlString;
}
if (stack.selectedChild == crop) {
maximize();
canSelect = true;
contentBox.setStyle("horizontalAlign", "left");
cropHTML.htmlLoader.load(new URLRequest(urlString));
cropHTML.width = contentBox.width;
cropHTML.height = contentBox.height - 24;
cropStatus.text = "Loading";
cropStatus.setStyle("color", "#ffff00");
cropHTML.addEventListener(Event.COMPLETE, onCropLoad);
}
if (stack.selectedChild == screenshotsettings) {
contSize.text = "Full size (" + tempHTML.contentWidth + "x" + tempHTML.contentHeight + ")";
}
}

We used a style called settingText. Declare it in the styles:

<fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";

.descriptionText{
fontSize: 24;
color: #fff;
}

.settingText{
fontSize: 16;
color: #fff;
}

#headStep{
fontSize: 30;
fontWeight: bold;
color: #ffffbb;
}

#headDesc{
fontSize: 30;
color: #ffffff;
}
</fx:Style>

Now, let's create this list item component. Create a new file called ScreenSetting.mxml. Its root tags will be SkinnableContainer. Declare 3 values - checked (boolean), w and h (strings). Add a checkbox, a few labels and 2 text inputs. Bind the text input fields' text values to w and h properties. Make sure its double binding (include @ symbol before {}):

<?xml version="1.0" encoding="utf-8"?>
<s:SkinnableContainer xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark" 
               xmlns:mx="library://ns.adobe.com/flex/halo"
   backgroundColor="#999999" width="310" height="26">

<fx:Declarations>
<fx:Boolean id="checked">true</fx:Boolean>
<fx:String id="w"></fx:String>
<fx:String id="h"></fx:String>
</fx:Declarations>
   
<s:CheckBox toolTip="Use this screen size" x="4" selected="@{checked}" y="3" />
<s:HGroup x="22" y="2" verticalAlign="middle">
<s:Label styleName="settingText"  text="Width:" />
<s:TextInput width="50" text="@{w}" restrict="0-9" maxChars="4" />
<s:Label styleName="settingText"  text="px       Height:" />
<s:TextInput width="50" text="@{h}" restrict="0-9" maxChars="4" />
<s:Label styleName="settingText"  text="px" />
</s:HGroup>

</s:SkinnableContainer>

Then add these to the screenshotsettings container and set their values like this (this is temporary, but it is fine for now, since we are not doing any functionality right now).

<s:NavigatorContent id="screenshotsettings">
<s:VGroup width="100%" horizontalAlign="center" paddingTop="20">
<s:Label styleName="descriptionText">Select screenshot screen sizes:</s:Label>
<s:SkinnableContainer backgroundColor="#999999" width="310" height="18" >
<s:CheckBox toolTip="Use this screen size" x="4" selected="true" />
<s:Label id="contSize" styleName="settingText" x="22" y="3" />
</s:SkinnableContainer>
<custom:ScreenSetting checked="true" w="1280" h="1024" />
<custom:ScreenSetting checked="true" w="1280" h="800" />
<custom:ScreenSetting checked="true" w="1024" h="768" />
<custom:ScreenSetting checked="false" />
<custom:ScreenSetting checked="false" />
<custom:ScreenSetting checked="false" />
<s:Button label="Back" click="screenshotBack();" />
</s:VGroup>
</s:NavigatorContent>

You can see I added a Back button too, set its click event handler to screenshotBack():

private function screenshotBack():void {
stack.selectedChild = loadpage;
removeElement(tempHTML);
}

You can shorten cancelLoading() using this function too:

private function cancelLoading():void {
tempHTML.removeEventListener(Event.COMPLETE, onTempLoad);
tempHTML.cancelLoad();
screenshotBack();
}

Full code:

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                       xmlns:s="library://ns.adobe.com/flex/spark"
   xmlns:custom="*"
                       xmlns:mx="library://ns.adobe.com/flex/mx" showStatusBar="false"
   width="550" height="500" creationComplete="init();">
   
   
<fx:Declarations>
<mx:ArrayCollection id="headerTitles">
<fx:Object step="Step one:" description="load a web page." />
<fx:Object step="Loading..." description="please wait." />
<fx:Object step="Step two:" description="set your export preferences." />
<fx:Object step="Step two:" description="select the area you wish to crop." />
<fx:Object step="Step three:" description="set your export preferences for the cropped image." />
<fx:Object step="Final step:" description="please wait while your images are being expored." />
</mx:ArrayCollection>
</fx:Declarations>

<fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";

.descriptionText{
fontSize: 24;
color: #fff;
}

.settingText{
fontSize: 16;
color: #fff;
}

#headStep{
fontSize: 30;
fontWeight: bold;
color: #ffffbb;
}

#headDesc{
fontSize: 30;
color: #ffffff;
}
</fx:Style>

<fx:Script>
<![CDATA[
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filesystem.File;
import flash.geom.Rectangle;
import flash.net.URLRequest;
import mx.controls.HTML;
import mx.core.FlexHTMLLoader;
import mx.events.FlexNativeWindowBoundsEvent;
import mx.controls.Alert;
import mx.graphics.ImageSnapshot;
import spark.primitives.BitmapImage;

[Bindable]
private var urlString:String;
[Bindable]
private var canSelect:Boolean = true;
private var tempHTML:HTML = new HTML();

private function init():void {
addEventListener(FlexNativeWindowBoundsEvent.WINDOW_RESIZE, onResize);
}

private function doBrowse():void{
var file:File = new File();
file.addEventListener(Event.SELECT, browseSelect);
file.browseForOpen("Load a webpage");

function browseSelect(evt:Event):void {
urlInput.text = file.nativePath;
}
}

private function goCrop():void {
stack.selectedChild = crop;
urlString = urlInput.text;
}

private function goScreenshot():void {
stack.selectedChild = screenshotloading;
urlString = urlInput.text;

addElement(tempHTML);
tempHTML.visible = false;
tempHTML.addEventListener(Event.COMPLETE, onTempLoad);
tempHTML.htmlLoader.load(new URLRequest(urlString));
}

private function onTempLoad(evt:Event):void {
stack.selectedChild = screenshotsettings;
}

private function cancelLoading():void {
tempHTML.removeEventListener(Event.COMPLETE, onTempLoad);
tempHTML.cancelLoad();
screenshotBack();
}

private function screenshotBack():void {
stack.selectedChild = loadpage;
removeElement(tempHTML);
}

private function changeState():void {
if (stack.selectedChild == loadpage) {
contentBox.setStyle("horizontalAlign", "center");
urlInput.text = urlString;
}
if (stack.selectedChild == crop) {
maximize();
canSelect = true;
contentBox.setStyle("horizontalAlign", "left");
cropHTML.htmlLoader.load(new URLRequest(urlString));
cropHTML.width = contentBox.width;
cropHTML.height = contentBox.height - 24;
cropStatus.text = "Loading";
cropStatus.setStyle("color", "#ffff00");
cropHTML.addEventListener(Event.COMPLETE, onCropLoad);
}
if (stack.selectedChild == screenshotsettings) {
contSize.text = "Full size (" + tempHTML.contentWidth + "x" + tempHTML.contentHeight + ")";
}
}

private function onCropLoad(evt:Event):void {
cropStatus.text = "Loaded";
cropStatus.setStyle("color", "#ffffff");
}

private function onResize(evt:Event):void {
if (stack.selectedChild == crop) {
cropHTML.width = contentBox.width;
cropHTML.height = contentBox.height - 24;
}
}
]]>
</fx:Script>
   
<s:VGroup width="100%" height="100%" gap="0">
<mx:HBox backgroundColor="#333333" height="46" width="100%" paddingTop="10" paddingLeft="10">
<s:Label id="headStep" text="{headerTitles.getItemAt(stack.selectedIndex).step}" />
<s:Label id="headDesc" text="{headerTitles.getItemAt(stack.selectedIndex).description}" />
</mx:HBox>
<mx:Box backgroundColor="#666666" width="100%" height="100%" id="contentBox" horizontalAlign="center">
<mx:ViewStack id="stack" change="changeState();">
<s:NavigatorContent id="loadpage">
<s:VGroup width="100%" horizontalAlign="center" paddingTop="20">
<s:Label styleName="descriptionText">Enter the link to the page:</s:Label>
<s:HGroup>
<s:TextInput width="250" id="urlInput" text="http://" /><s:Button label="Browse local..." click="doBrowse();" />
</s:HGroup>
<s:HGroup>
<custom:ImageButton img="@Embed('../lib/b_screenshot.png')" over="@Embed('../lib/b_screenshot_over.png')" toolTip="Take screenshots" click="goScreenshot();" buttonMode="true" enabled="{urlInput.text!=''}" />
<custom:ImageButton img="@Embed('../lib/b_cut.png')" over="@Embed('../lib/b_cut_over.png')" toolTip="Crop area" click="goCrop();" buttonMode="true" enabled="{urlInput.text!=''}" />
</s:HGroup>
</s:VGroup>
</s:NavigatorContent>

<s:NavigatorContent id="screenshotloading">
<s:VGroup width="100%" horizontalAlign="center" paddingTop="20">
<s:Label styleName="descriptionText">The page is being loaded...</s:Label>
<s:Button label="Cancel" click="cancelLoading();" />
</s:VGroup>
</s:NavigatorContent>

<s:NavigatorContent id="screenshotsettings">
<s:VGroup width="100%" horizontalAlign="center" paddingTop="20">
<s:Label styleName="descriptionText">Select screenshot screen sizes:</s:Label>
<s:SkinnableContainer backgroundColor="#999999" width="310" height="18" >
<s:CheckBox toolTip="Use this screen size" x="4" selected="true" />
<s:Label id="contSize" styleName="settingText" x="22" y="3" />
</s:SkinnableContainer>
<custom:ScreenSetting checked="true" w="1280" h="1024" />
<custom:ScreenSetting checked="true" w="1280" h="800" />
<custom:ScreenSetting checked="true" w="1024" h="768" />
<custom:ScreenSetting checked="false" />
<custom:ScreenSetting checked="false" />
<custom:ScreenSetting checked="false" />
<s:Button label="Back" click="screenshotBack();" />
</s:VGroup>
</s:NavigatorContent>

<s:NavigatorContent id="crop">
<s:VGroup width="100%" height="100%" gap="0">
<mx:HBox backgroundColor="#999999" width="100%" height="24" verticalScrollPolicy="off" verticalAlign="middle" paddingLeft="2">
<s:Button label="Back" click="{cropHTML.htmlLoader.loadString(''); stack.selectedChild = loadpage;}" />
<s:Button label="Export selection" enabled="false" />
<s:Label id="cropStatus" />
<s:Label text="{urlString}" />
</mx:HBox>
<mx:HTML id="cropHTML" horizontalScrollPolicy="on" verticalScrollPolicy="on" />
</s:VGroup>
</s:NavigatorContent>

<s:NavigatorContent id="cropsettings">

</s:NavigatorContent>

<s:NavigatorContent id="export">

</s:NavigatorContent>
</mx:ViewStack>
</mx:Box>
</s:VGroup>

</s:WindowedApplication>

Thanks for reading!

No comments:

Post a Comment