Thursday, April 19, 2012

KirSizer - Flex AIR Image Sizer app: Part 3

Today we'll add some "Add files" button functionality.

Go to the first NavigatorContent container and ste the first label's id to labelSelected. Set the TileList's widht to 282, columnWidth and columnHeight to 60, columnCount to 4 and itemRenderer to a custom class called TileRenderer.

Set the "Add files" button's click event handler to addFiles() function:

<s:NavigatorContent width="100%" height="100%" hideEffect="fadeOut" showEffect="fadeIn">
<s:VGroup width="100%" height="100%" paddingLeft="10" paddingTop="10" paddingRight="10" paddingBottom="10">
<s:Label id="labelSelected">0 files selected</s:Label>
<mx:TileList id="tileList" width="282" height="100%" dataProvider="{selectedFiles}" itemRenderer="TileRenderer" columnWidth="60" rowHeight="60" columnCount="4" />
<s:Button label="Add folder" width="100%" />
<s:Button label="Add files" width="100%" click="addFiles();" />
<s:Button label="Continue" width="100%" click="contentStack.selectedIndex = 1;" />
</s:VGroup>
</s:NavigatorContent>

In the script tags declare a new ArrayCollection called slectedFiles, make it bindable:

[Bindable]
private var selectedFiles:ArrayCollection = new ArrayCollection([]);

Now create this addFiles() function and inside of it create a new File object. Call its browseForOpenMultiple() method and add a filter for jpg, jpeg and png pictures. Add a SELECT_MULTIPLE event listener for the File.

private function addFiles():void {
var file:File = new File();
file.browseForOpenMultiple("Select JPG or PNG files", [new FileFilter("Pictures", "*.jpg;*.jpeg;*.png")]);
file.addEventListener(FileListEvent.SELECT_MULTIPLE, filesSelected);
}

The fileSelected function, which is a handler to the SELECT_MULTIPLE event, loops through the receives files and adds their native paths to the selectedFiles array. However, we must keep in mind that the user might accidently import the same file twice, so we need to check if the file already exists in the array before adding it. We use another loop for that. After the loop, we set labelSelected's text to display how many files are selected:

private function filesSelected(evt:FileListEvent):void {
for (var i:int = 0; i < evt.files.length; i++) {
var alreadySelected:Boolean = false;
for (var u:int = 0; u < selectedFiles.length; u++) {
if (selectedFiles[u] == evt.files[i].nativePath) {
alreadySelected = true;
}
}
if (!alreadySelected) selectedFiles.addItem(evt.files[i].nativePath);
}
labelSelected.text = selectedFiles.length + " files selected";
}

Now create a new mxml file called TileRenderer.mxml. This is our custom item renderer for the TileList. Set the root tags to a VBox, and inside of it create an Image object with source bound to {data}, which is the received image url. Set maxWidth to 60, maxHeight to 60 and scaleContent to true:

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
horizontalAlign="center"
verticalAlign="middle" horizontalScrollPolicy="off"
verticalScrollPolicy="off">
<mx:Image source="{data}" maxWidth="60" maxHeight="60" scaleContent="true"/>
</mx:VBox>

And full Main.mxml code looks like this:

<?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:mx="library://ns.adobe.com/flex/mx"
width="300" height="460" 
showStatusBar="false" title="KirSizer">
   
<fx:Declarations>
<mx:ArrayCollection id="measures">
<fx:String>%</fx:String>
<fx:String>px</fx:String>
</mx:ArrayCollection>
<mx:ArrayCollection id="actions">
<fx:String>Fixed width, fixed height</fx:String>
<fx:String>Fixed width, proportional height</fx:String>
<fx:String>Proportional width, fixed height</fx:String>
<fx:String>Proportional sizes to fit specified sizes</fx:String>
</mx:ArrayCollection>
<mx:ArrayCollection id="formats">
<fx:String>Same format as initial file</fx:String>
<fx:String>Convert all to JPG</fx:String>
<fx:String>Convert all to PNG</fx:String>
</mx:ArrayCollection>
<mx:Fade id="fadeIn" alphaFrom="0" alphaTo="1" duration="300"/>
<mx:Fade id="fadeOut" alphaFrom="1" alphaTo="0" duration="300"/>
</fx:Declarations>

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

#contentStack{
backgroundColor: #313131;
}

s|Label{
color: #fcfcfc;
}

s|Button{
chromeColor: #636363;
}

mx|ComboBox{
chromeColor: #636363;
color: #fcfcfc;
contentBackgroundColor: #000000;
rollOverColor: #aaaaaa;
selectionColor: #ffffff;
}
</fx:Style>

<fx:Script>
<![CDATA[
import flash.events.FileListEvent;
import flash.filesystem.File;
import flash.net.FileFilter;
import mx.collections.ArrayCollection;
import mx.effects.easing.Linear;
import mx.controls.Alert;

[Bindable]
private var selectedFiles:ArrayCollection = new ArrayCollection([]);

private function actionChange():void{
switch (actionCombo.selectedIndex) {
case 0: case 3:
newWidth.enabled = true;
widthMeasure.enabled = true;
newHeight.enabled = true;
heightMeasure.enabled = true;
break;
case 1:
newWidth.enabled = true;
widthMeasure.enabled = true;
newHeight.enabled = false;
heightMeasure.enabled = false;
break;
case 2:
newWidth.enabled = false;
widthMeasure.enabled = false;
newHeight.enabled = true;
heightMeasure.enabled = true;
break;
}
}

private function addFiles():void {
var file:File = new File();
file.browseForOpenMultiple("Select JPG or PNG files", [new FileFilter("Pictures", "*.jpg;*.jpeg;*.png")]);
file.addEventListener(FileListEvent.SELECT_MULTIPLE, filesSelected);
}

private function filesSelected(evt:FileListEvent):void {
for (var i:int = 0; i < evt.files.length; i++) {
var alreadySelected:Boolean = false;
for (var u:int = 0; u < selectedFiles.length; u++) {
if (selectedFiles[u] == evt.files[i].nativePath) {
alreadySelected = true;
}
}
if (!alreadySelected) selectedFiles.addItem(evt.files[i].nativePath);
}
labelSelected.text = selectedFiles.length + " files selected";
}
]]>
</fx:Script>
   
<mx:ViewStack id="contentStack" width="100%" height="100%">
<s:NavigatorContent width="100%" height="100%" hideEffect="fadeOut" showEffect="fadeIn">
<s:VGroup width="100%" height="100%" paddingLeft="10" paddingTop="10" paddingRight="10" paddingBottom="10">
<s:Label id="labelSelected">0 files selected</s:Label>
<mx:TileList id="tileList" width="282" height="100%" dataProvider="{selectedFiles}" itemRenderer="TileRenderer" columnWidth="60" rowHeight="60" columnCount="4" />
<s:Button label="Add folder" width="100%" />
<s:Button label="Add files" width="100%" click="addFiles();" />
<s:Button label="Continue" width="100%" click="contentStack.selectedIndex = 1;" />
</s:VGroup>
</s:NavigatorContent>
<s:NavigatorContent width="100%" height="100%" hideEffect="fadeOut" showEffect="fadeIn">
<s:VGroup width="100%" height="100%" paddingLeft="10" paddingTop="10" paddingRight="10" paddingBottom="10">
<s:Button label="Return to file selection" width="100%" click="contentStack.selectedIndex = 0;" />

<s:Label>Resize options:</s:Label>

<mx:ComboBox width="100%" id="actionCombo" height="22" dataProvider="{actions}" selectedIndex="0" editable="false" change="actionChange();"
openEasingFunction="Linear.easeOut" closeEasingFunction="Linear.easeIn" openDuration="300" closeDuration="300"/>
<s:HGroup verticalAlign="middle">
<s:Label width="50">Width:</s:Label>
<s:NumericStepper id="newWidth" height="22" width="150" minimum="1" value="100" maximum="{(widthMeasure.selectedIndex==0)?(100):(4000)}" />
<mx:ComboBox id="widthMeasure" height="22" width="50" dataProvider="{measures}" selectedIndex="0" editable="false" 
openEasingFunction="Linear.easeOut" closeEasingFunction="Linear.easeIn" openDuration="300" closeDuration="300"/>
</s:HGroup>

<s:HGroup verticalAlign="middle">
<s:Label width="50">Height:</s:Label>
<s:NumericStepper id="newHeight" height="22" width="150" minimum="1" value="100" maximum="{(heightMeasure.selectedIndex==0)?(100):(4000)}"/>
<mx:ComboBox id="heightMeasure" height="22" width="50" dataProvider="{measures}" selectedIndex="0" editable="false" 
openEasingFunction="Linear.easeOut" closeEasingFunction="Linear.easeIn" openDuration="300" closeDuration="300"/>
</s:HGroup>

<s:Label/>

<s:Label>Output file names:</s:Label>
<s:HGroup verticalAlign="middle">
<s:TextInput width="240" text="%initialName%" />
<s:Button width="35" label="?"/>
</s:HGroup>

<s:Label/>

<s:Label>Output destination:</s:Label>
<s:HGroup verticalAlign="middle">
<s:RadioButton id="oldDestination" label="Same directory" groupName="destinationGroup" selected="true" />
<s:RadioButton id="newDestination" label="Specified directory" groupName="destinationGroup" />
</s:HGroup>
<s:HGroup verticalAlign="middle" width="100%">
<s:TextInput width="100%" enabled="{newDestination.selected}" text="Select destination..." editable="false" />
<s:Button width="80" label="Browse" enabled="{newDestination.selected}"/>
</s:HGroup>

<s:Label/>

<s:Label>Output format:</s:Label>
<mx:ComboBox width="100%" height="22" id="formatCombo" dataProvider="{formats}" selectedIndex="0" editable="false" 
openEasingFunction="Linear.easeOut" closeEasingFunction="Linear.easeIn" openDuration="300" closeDuration="300"/>

<s:Label/>

<s:Label>Output JPG quality:</s:Label>
<s:HSlider width="100%" minimum="1" maximum="100" value="100" />

<s:Label/>

<s:Button label="Resize" width="100%" />
</s:VGroup>
</s:NavigatorContent>
</mx:ViewStack>
</s:WindowedApplication>

Thanks for reading!

No comments:

Post a Comment