Showing posts with label part. Show all posts
Showing posts with label part. Show all posts
Saturday, February 28, 2015
I Have Bragging Rights Because I Am Part 2
- Part 1 - Teaching Habits That Inspire You Out of Learning?
- Link to ZaidLearns Del.icio.us Teaching Links
"If you done it, it aint bragging." - Walt Whitman"Its not bragging if you can back it up." - Muhammad Ali
“He who is humble is confident and wise. He who brags is insecure and lacking.” - Lisa Edmondson
In the last episode, we got a taste of a lecturer that only had time to engage the whiteboard, so that he could complete his syllabus. This time around, I will have to put on my student experience goggles and transport myself back to an undergraduate psychology course (Deviant Behavior) I took in the previous millennium. For the identity protection sake, we will name this lecturer Dr. Brag.
DEVIANT BEHAVIOR
Dr. Brag was not an ordinary lecturer. No, he was an extraordinary lecturer! I used to enjoy coming to his classes, and occasionally he practiced what he preached, too. So, why are you writing about Dr. Brag? Lets begin!
Although, I admired his expertise, experience and knowledge, it got kind of frustrating listening to him brag (boastful statements/arrogant talk) about all his amazing achievements every class. By the end of the course, we probably knew more about him and his familys achievements than the subject matter itself. Every class, we would hear one self-glory ego-boosting story after another, covering his greatness in sports, politics, work, family and education. Yes, he was also writing more than 10 books concurrently at that time. My best friend was assisting him in editing these books, and that must have been reasonably challenging. I wonder if Dr. Brag ever finished writing any of those amazing books.
I have to feel sorry for the guy, too. He had high blood pressure and was a diabetic in a country like Malaysia. Now, that is a bad combination, especially when the classroom is hot and humid with many students who are mentally on holiday. Or sleeping with their eyes open!
Anyway, I was there! Since I had already developed the habit of sitting in the front row and asking questions, the classes got quite lively at times. Although, he bragged a lot, I loved the fact that he would always challenge us. The one bragging challenge that really got to me, was that he was happy to claim that, "No student in my class has ever gotten an A!" I am not sure if that is something a lecturer should be proud of, but strangely some are.
That was a challenge too good to resist. I didnt get that many As during my undergraduate days, but somehow this particular challenge inspired me to get one. And I am really proud to share with you all that I was the first student at the University to achieve an A with him (Am I bragging or what! I hope he was actually telling the truth!). The glory was short lived though, as I heard that others got As with him in the following semesters. Well, I am proud to be the first one at least (Bragging again!).
I suppose Deviant Behavior was a course that came naturally to me, so I should not think so highly of my success. It is also no surprise that I also scored an A in Abnormal Psychology (Oh man, can you stop bragging!). Some students scores As all the way, some score As in only subjects they like, and some dont get a single one. Nothing to worry about, if you believe in yourself and work hard, I am pretty sure you can succeed anyway. Also, scoring As is probably not the best indicator to predict future success in life. Though, it does help to get a few As on your scroll, because it could at least help you to get an interview with a top company. Why didnt I think of that earlier!
REFLECTION
Some argue that Teachers or lecturers join the academic world (of theory), because they are failures in the real (practical) world. Such statements often drive academic staff nuts (even if it is sometimes true!), and brings laughter to students. Anyway, we dont need to go into this discussion here, because it will probably lead to no constructive alignment.
Instead, we could ask ourselves, "why do we like to brag about our achievements?" Do you brag? I certainly do, but I usually feel kind of stupid when I realize it. But then again, we forget fast, because it is always nice to feel appreciated and important. The best thing is when someone else praises us about our work. But if none do, we could always do it ourselves.
The best thing about teaching and bragging, is that we are guaranteed an audience, which will probably just look in shock and awe (some will already be sleeping!). I mean, no sane student is going to stand up, and tell the lecturer, "Give us a break from your pathetic achievements, and please get on with the class!" And unless one or a few students make it clear sooner or later, the lecturer will probably continue semester after semester, year after year. Interestingly, the stories will become more amazing and exciting every time they are told. There might even be 2-3 new versions every semester, especially if the lecturer is teaching more than one section.
Certainly, lecturers that have a lot of experiences relevant to the topic discussed should share them with the class. However, we should also ask ourselves whether we are doing it to assist our students to understand the learning content better, or emphasize an important point, or are we doing it to boost our ego. Perhaps we do it for both reasons.
If you think that your achievements are so great, perhaps you should watch a few TED Talks to put your achievements in a global perspective (do a bit of benchmarking, please!).
In my opinion, the greatness of a lecturer does not lie in what he (or she) has personally achieved. Instead, a great lecturer is a person who is able to consistently facilitate AHA-moments in students (Oh, now I understand!) and inspire (or trigger) them to explore and discover their true potential.
To sum up, Dr. Brag was actually a very knowledgeable and experienced lecturer, but his habit of bragging was something that was in my opinion more destructive than constructive in motivating students and facilitating learning.
Do you brag in class (or at work)? Has it become a habit beyond control? Think about it! It doesnt take much effort to change. I am trying, but I want to be appreciated and feel important! Unless I tell them, they will never respect me, recognize my amazing talent, and look up to me. What was the agenda again?
"Develop success from failures. Discouragement and failure are two of the surest stepping stones to success." - Dale Carnegie
5-PART SERIES
- Part 1 - Whiteboard And I Are One!
- Part 2 - I Have Bragging Rights, Because I Am …
- Part 3 - Is PowerPoint Evil?
- Part 4 - No Stupid Questions! I am Serious!
- Part 5 - Show Up to Throw Up! 21st Century Thinking?
Thursday, February 5, 2015
Android beginner tutorial Part 37 GridView widget
In this tutorial well learn how to display text data using GridView widget.
The GridView component displays data in a table structure.
There are a few properties that we can use to customize the appearance of the widget.
The first one is android:numColumns - it determines how many columns the grid has. It can be set to "auto_fit" to fit as many columns as possible.
The android:verticalSpacing and android:horizontalSpacing variables determine the horizontal and vertical spacing between the cells.
The android:columnWidth property sets the width of each column.
The android:stretchMode property determines how the grid is stretched. You can set it to columnWidth to increase the cell width if there is any extra space left, or to spacingWidth to increase the spacing between the cells. Set to none to disable stretching.
Go to activity_main.xml layout file and create a simple layout with a TextView and a GridView:
We need to have an array declared in our strings.xml file. Its the one from the previous tutorials:
Go to MainActivity.java class. Implement OnItemClickListener class:
Declare text and grid variables to later reference the TextView and GridView objects:
Set their value sin onCreate() function. Then retreive the array from the strings.xml and apply it to an array adapter. Apply this adapter to this activity using setAdapter() method, then call setOnItemClickListener() method to add a click listener:
Add a onItemClick() function, which handles the item click event. Display the selected item in the text field:
Full code:
The results look like this:

Thanks for reading!
Read more »
The GridView component displays data in a table structure.
There are a few properties that we can use to customize the appearance of the widget.
The first one is android:numColumns - it determines how many columns the grid has. It can be set to "auto_fit" to fit as many columns as possible.
The android:verticalSpacing and android:horizontalSpacing variables determine the horizontal and vertical spacing between the cells.
The android:columnWidth property sets the width of each column.
The android:stretchMode property determines how the grid is stretched. You can set it to columnWidth to increase the cell width if there is any extra space left, or to spacingWidth to increase the spacing between the cells. Set to none to disable stretching.
Go to activity_main.xml layout file and create a simple layout with a TextView and a GridView:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView
android:id="@+id/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<GridView
android:id="@+id/grid"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:verticalSpacing="35dp"
android:horizontalSpacing="5dp"
android:numColumns="auto_fit"
android:columnWidth="100dp"
android:stretchMode="columnWidth"
android:gravity="center"
/>
</LinearLayout>
We need to have an array declared in our strings.xml file. Its the one from the previous tutorials:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Code For Food Test</string>
<string name="menu_settings">Settings</string>
<string-array name="choices_array">
<item>One</item>
<item>Two</item>
<item>Three</item>
<item>Four</item>
<item>Five</item>
<item>Seven</item>
<item>Eight</item>
<item>Nine</item>
<item>Ten</item>
</string-array>
</resources>
Go to MainActivity.java class. Implement OnItemClickListener class:
public class MainActivity extends Activity implements OnItemClickListener{
Declare text and grid variables to later reference the TextView and GridView objects:
private TextView text;
private GridView grid;
Set their value sin onCreate() function. Then retreive the array from the strings.xml and apply it to an array adapter. Apply this adapter to this activity using setAdapter() method, then call setOnItemClickListener() method to add a click listener:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
grid = (GridView)findViewById(R.id.grid);
text = (TextView)findViewById(R.id.text);
String[] choices = getResources().getStringArray(R.array.choices_array);
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, choices);
grid.setAdapter(arrayAdapter);
grid.setOnItemClickListener(this);
}
Add a onItemClick() function, which handles the item click event. Display the selected item in the text field:
public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
text.setText("The selected item is " + parent.getItemAtPosition(pos).toString());
}
Full code:
package com.kircode.codeforfood_test;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.GridView;
import android.widget.TextView;
public class MainActivity extends Activity implements OnItemClickListener{
private TextView text;
private GridView grid;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
grid = (GridView)findViewById(R.id.grid);
text = (TextView)findViewById(R.id.text);
String[] choices = getResources().getStringArray(R.array.choices_array);
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, choices);
grid.setAdapter(arrayAdapter);
grid.setOnItemClickListener(this);
}
public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
text.setText("The selected item is " + parent.getItemAtPosition(pos).toString());
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
The results look like this:

Thanks for reading!
Creating a Flex AIR text editor Part 50
In this tutorial we will start turning our snippet structure plan to life.
The first thing well need to do is get rid of everything that, according to the previous tutorials plan, is not needed.
Firstly go to the SnippetWindow.mxml file, remove all things related to XML and the code that is responsible for applying changes. In the setValues() function, add 2 parameters - conn1 and conn2. Those will be the connection objects for category and snippet databases. Declare snippetConnection and categoryConnection variables that will receive these parameters values and store them.
Now go to the main mxml file. Here, remove the rewriteSQL() and snippetChange() functions completely.
Add a connection2 variable next to connection, as well as snippetData and categoryData objects:
In the init() function, remove the line which listens to the Event.CHANGE event for the snippetWindow object.
In the part where we declare database object and set up connections, add and open connection2 as well:
Now update the doSnippet() function to pass connection and connection2 values as parameters with the setValues() function. In the snippetTreeChange event, remove the line which inserts the text:
Now, be careful and pay attention on the next part. After both connections are open, the onOpen() function is called. Here we create the snippets table:
NOTE: IF YOU FOLLOWED THE STEPS OF THE PREVIOUS TUTORIALS, YOU WILL NEED TO DELETE THE SNIPPETS TABLE TO RESET THE SETTINGS.
To do that, change the code aboves statements text to "DROP TABLE snippets" and run the code once. Then change it back to what it is shown here.
When the snippets table is created, we proceed to create the category table:
When this is created, we select the items from the snippets table.
When we receive those, we set the snippetData variables value to the data received. Then we also select all categories:
When we receive that, we set categoryData property value to the received data. Then we call a function called createSnippetXML:
Here, we will first create a temporary piece of code which changes categoryData and snippetData to pre-defined array of objects (because our databases are empty and this is necessary for debugging).
Then we check if there are any objects in any database at all. If there is at least one item in any of the databases, then create root tags for the snippetXML object.
After that we loop through the categories to add them and their content.
Later we loop through the snippets one more time to add items that do not belong to any category:
It displays everything correctly now.
Thats all for today.
Full code of the main file:
Thanks for reading!
Read more »
The first thing well need to do is get rid of everything that, according to the previous tutorials plan, is not needed.
Firstly go to the SnippetWindow.mxml file, remove all things related to XML and the code that is responsible for applying changes. In the setValues() function, add 2 parameters - conn1 and conn2. Those will be the connection objects for category and snippet databases. Declare snippetConnection and categoryConnection variables that will receive these parameters values and store them.
<?xml version="1.0" encoding="utf-8"?>
<mx:Window xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
title="Snippet management" type="utility" width="500" height="730"
creationComplete="init();" showStatusBar="false" alwaysInFront="true" resizable="false" backgroundColor="#dddddd">
<fx:Script>
<![CDATA[
import flash.data.SQLConnection;
import flash.events.Event;
[Bindable]
public var treeData:XMLList;
private var snippetConnection:SQLConnection;
private var categoryConnection:SQLConnection;
private function init():void{
this.addEventListener(Event.CLOSING, onClose);
}
private function onClose(evt:Event):void {
this.visible = false;
evt.preventDefault();
}
public function setValues(xmlData:XMLList, conn1:SQLConnection, conn2:SQLConnection, createNewOnStart:Boolean = false, newText:String = ""):void {
snippetConnection = conn1;
categoryConnection = conn2;
treeData = xmlData.copy();
newTextInput.text = newText;
newNameInput.text = "New snippet name here";
if (newText=="") {
newTextInput.text = "New snippet text here";
}
}
private function addSnippet(name:String, text:String):void{
}
private function addCategory(name:String):void{
}
]]>
</fx:Script>
<s:VGroup paddingLeft="5" paddingRight="5" paddingTop="5" paddingBottom="5">
<s:Label text="Snippet creation and management: " />
<s:TextInput id="newNameInput" text="New snippet name" width="490" />
<s:TextArea id="newTextInput" width="490" height="200" text="Snippet text" />
<s:HGroup>
<s:Button label="Add snippet" click="addSnippet(newNameInput.text, newTextInput.text);" />
<s:Button label="Save changes" enabled="false" />
<s:Button label="Delete snippet" enabled="false" />
</s:HGroup>
<s:Label text="" />
<s:Label text="Category creation and management: " />
<s:TextInput id="newCategoryInput" text="New category name" width="490" />
<s:HGroup>
<s:Button label="Add category" click="addCategory(newCategoryInput.text);"/>
<s:Button label="Save changes" enabled="false"/>
<s:Button label="Delete category with its contents" enabled="false"/>
</s:HGroup>
<s:Label text="" />
<mx:Tree id="snippetManageTree" dataProvider="{treeData}" width="490" height="300" showRoot="false" labelField="@label"/>
</s:VGroup>
</mx:Window>
Now go to the main mxml file. Here, remove the rewriteSQL() and snippetChange() functions completely.
Add a connection2 variable next to connection, as well as snippetData and categoryData objects:
public var connection:SQLConnection;
public var connection2:SQLConnection;
private var snippetData:Array;
private var categoryData:Array;
In the init() function, remove the line which listens to the Event.CHANGE event for the snippetWindow object.
In the part where we declare database object and set up connections, add and open connection2 as well:
// Database management
var dbFile:File = File.applicationStorageDirectory.resolvePath("database.db");
connection = new SQLConnection();
connection2 = new SQLConnection();
connection2.open(dbFile, SQLMode.CREATE);
connection.addEventListener(SQLEvent.OPEN, onOpen);
connection.openAsync(dbFile, SQLMode.CREATE);
Now update the doSnippet() function to pass connection and connection2 values as parameters with the setValues() function. In the snippetTreeChange event, remove the line which inserts the text:
private function snippetTreeChange(evt:Event):void {
if (evt.currentTarget.selectedItem.@isBranch == false) {
// TODO: get data from database and insert it
evt.currentTarget.selectedIndex = -1;
}
}
private function doSnippet(createNew:Boolean = false, newText:String = ""):void{
snippetWindow.open();
snippetWindow.activate();
snippetWindow.visible = true;
snippetWindow.setValues(snippetXML, connection, connection2, createNew, newText);
}
Now, be careful and pay attention on the next part. After both connections are open, the onOpen() function is called. Here we create the snippets table:
private function onOpen(evt:SQLEvent):void {
// create snippets table
var stat:SQLStatement = new SQLStatement();
stat.sqlConnection = connection;
stat.text = "CREATE TABLE IF NOT EXISTS snippets (id INTEGER PRIMARY KEY AUTOINCREMENT, snippetName TEXT, snippetText TEXT, categoryID INTEGER, snippetPosition INTEGER)";
stat.execute( -1, new Responder(onCreateSnippets));
}
NOTE: IF YOU FOLLOWED THE STEPS OF THE PREVIOUS TUTORIALS, YOU WILL NEED TO DELETE THE SNIPPETS TABLE TO RESET THE SETTINGS.
To do that, change the code aboves statements text to "DROP TABLE snippets" and run the code once. Then change it back to what it is shown here.
When the snippets table is created, we proceed to create the category table:
private function onCreateSnippets(evt:SQLResult):void {
// create category table
var stat:SQLStatement = new SQLStatement();
stat.sqlConnection = connection2;
stat.text = "CREATE TABLE IF NOT EXISTS categories (id INTEGER PRIMARY KEY AUTOINCREMENT, categoryName TEXT, categoryPosition INTEGER)";
stat.execute( -1, new Responder(onCreateCategory));
}
When this is created, we select the items from the snippets table.
private function onCreateCategory(evt:SQLResult):void {
// select snippets
var stat:SQLStatement = new SQLStatement();
stat.sqlConnection = connection;
stat.text = "SELECT id, snippetName, categoryID, snippetPosition FROM snippets ORDER BY id";
stat.execute( -1, new Responder(onSelectedSnippets));
}
When we receive those, we set the snippetData variables value to the data received. Then we also select all categories:
private function onSelectedSnippets(evt:SQLResult):void {
// save selected snippets to a variable
snippetData = evt.data;
// select categories
var stat:SQLStatement = new SQLStatement();
stat.sqlConnection = connection2;
stat.text = "SELECT id, categoryName, categoryPosition FROM categories ORDER BY id";
stat.execute( -1, new Responder(onSelectedCategories));
}
When we receive that, we set categoryData property value to the received data. Then we call a function called createSnippetXML:
private function onSelectedCategories(evt:SQLResult):void {
// save selected categories to a variable
categoryData = evt.data;
// call function to start creating the XML
createSnippetXML();
}
Here, we will first create a temporary piece of code which changes categoryData and snippetData to pre-defined array of objects (because our databases are empty and this is necessary for debugging).
Then we check if there are any objects in any database at all. If there is at least one item in any of the databases, then create root tags for the snippetXML object.
After that we loop through the categories to add them and their content.
Later we loop through the snippets one more time to add items that do not belong to any category:
private function createSnippetXML():void {
// temporary:
categoryData = [
{ id:0, categoryName:"Cat1", categoryPosition:1 },
{ id:1, categoryName:"Cat2", categoryPosition:0 },
]
snippetData = [
{ id:0, snippetName: "Snip1", snippetPosition: 0, categoryID: 0 },
{ id:1, snippetName: "Snip2", snippetPosition: 1, categoryID: 0 },
{ id:2, snippetName: "Snip3", snippetPosition: 1, categoryID: 1 },
{ id:3, snippetName: "Snip4", snippetPosition: 0, categoryID: 1 },
{ id:4, snippetName: "Snip5", snippetPosition: 0, categoryID: -1 },
{ id:5, snippetName: "Snip6", snippetPosition: 1, categoryID: -1 },
]
snippetXML = new XMLList();
// add root tags if there are any items in any database
if (snippetData || categoryData) {
snippetXML = new XMLList(<root></root>);
}
// loop through categories to add them and their content
if (categoryData) {
for (var i:int = 0; i < categoryData.length; i++) {
var aCategory:XML = <category/>
aCategory.@id = categoryData[i].id;
aCategory.@label = categoryData[i].categoryName;
aCategory.@isBranch = true;
snippetXML[0].appendChild(aCategory);
for (var u:int = 0; u < snippetData.length; u++) {
if (snippetData[u].categoryID == categoryData[i].id) {
var aSnippet:XML = <snippet/>;
aSnippet.@id = snippetData[u].id;
aSnippet.@label = snippetData[u].snippetName;
aSnippet.@categoryID = snippetData[u].categoryID;
aCategory.appendChild(aSnippet);
}
}
}
// look for snippets located in root tags (not in a category)
for (var t:int = 0; t < snippetData.length; t++) {
if (snippetData[t].categoryID == -1) {
var aRootSnippet:XML = <snippet/>;
aRootSnippet.@id = snippetData[t].id;
aRootSnippet.@label = snippetData[t].snippetName;
aRootSnippet.@categoryID = snippetData[t].categoryID;
snippetXML[0].appendChild(aRootSnippet);
}
}
}
}
It displays everything correctly now.
Thats all for today.
Full code of the main file:
<?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"
xmlns:custom="*"
creationComplete="init();" title="Kirpad" showStatusBar="{pref_status}"
minWidth="400" minHeight="200" height="700" width="900">
<s:menu>
<mx:FlexNativeMenu dataProvider="{windowMenu}" showRoot="false" labelField="@label" keyEquivalentField="@key" itemClick="menuSelect(event);" />
</s:menu>
<fx:Script>
<![CDATA[
import flash.data.SQLConnection;
import flash.events.KeyboardEvent;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.NativeWindowBoundsEvent;
import flash.filesystem.File;
import flash.filesystem.FileStream;
import flash.net.SharedObject;
import flashx.textLayout.accessibility.TextAccImpl;
import flashx.textLayout.edit.EditManager;
import flashx.textLayout.edit.TextScrap;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.controls.TextArea;
import mx.events.FlexNativeMenuEvent;
import flashx.textLayout.elements.TextFlow;
import flashx.textLayout.elements.Configuration;
import flash.system.System;
import flash.desktop.Clipboard;
import flash.desktop.ClipboardFormats;
import flash.ui.Mouse;
import mx.events.CloseEvent;
import flash.ui.ContextMenu;
import flash.ui.ContextMenuItem;
import flash.events.ContextMenuEvent;
import mx.events.ResizeEvent;
import mx.core.FlexGlobals;
import mx.printing.FlexPrintJob;
import mx.printing.FlexPrintJobScaleType;
import flashx.undo.UndoManager;
import flashx.textLayout.operations.UndoOperation;
import flash.data.SQLConnection;
import flash.events.SQLEvent;
import flash.data.SQLStatement;
import flash.data.SQLResult;
import flash.data.SQLMode;
import flash.net.Responder;
import XML;
import XMLList;
private var preferences:SharedObject = SharedObject.getLocal("kirpadPreferences");
[Bindable]
private var pref_wrap:Boolean = true;
[Bindable]
private var pref_status:Boolean = true;
[Bindable]
private var pref_toolbar:Boolean = true;
[Bindable]
private var pref_sidepane:Boolean = true;
[Bindable]
private var pref_linecount:Boolean = true;
[Bindable]
public var pref_fontsettings:Object = new Object();
private var initHeight:Number;
private var heightFixed:Boolean = false;
private var statusMessage:String;
[Bindable]
private var textHeight:Number;
[Bindable]
private var textWidth:Number;
[Bindable]
private var textY:Number;
[Bindable]
private var textX:Number;
[Bindable]
private var tabY:Number;
[Bindable]
private var sidePaneY:Number;
[Bindable]
private var sidePaneX:Number;
[Bindable]
private var sidePaneHeight:Number;
[Bindable]
private var sidePaneWidth:Number = 180;
[Bindable]
private var sideContentWidth:Number = 170;
[Bindable]
private var tabWidth:Number;
[Bindable]
private var lineCountWidth:Number = 40;
[Bindable]
private var lineNumbers:String = "1";
[Bindable]
private var lineDisplayedNum:int = 1;
[Bindable]
private var tabSelectedIndex:int = 0;
[Bindable]
private var canUndo:Boolean = false;
[Bindable]
private var canRedo:Boolean = false;
private var previousTextInOperation:String = "";
private var currentTextInOperation:String = "";
private var previousIndex:int = 0;
private var rightclickTabIndex:int = 0;
private var untitledNum:int = 0;
private var tabsToClose:int = 0;
private var closeAfterConfirm:Boolean = false;
public var fontWindow:FontWindow = new FontWindow();
public var snippetWindow:SnippetWindow = new SnippetWindow();
private var undoManager:UndoManager;
private var editManager:EditManager;
private var saveWait:Boolean = false;
private var saveAsQueue:Array = [];
public var connection:SQLConnection;
public var connection2:SQLConnection;
private var snippetData:Array;
private var categoryData:Array;
[Bindable]
private var snippetXML:XMLList;
private function init():void {
// Create a listener for every frame
addEventListener(Event.ENTER_FRAME, everyFrame);
// Set initHeight to the initial height value on start
initHeight = height;
// Set preferences if loaded for the first time
if (preferences.data.firsttime == null) {
preferences.data.firsttime = true;
preferences.data.wrap = false;
preferences.data.status = true;
preferences.data.toolbar = true;
preferences.data.sidepane = true;
preferences.data.linecount = true;
preferences.data.fontsettings = {fontfamily:"Lucida Console", fontsize:14, fontstyle:"normal", fontweight:"normal", fontcolor:0x000000, bgcolor:0xffffff};
preferences.flush();
}
// Set preferences loaded from local storage
pref_wrap = preferences.data.wrap;
pref_status = preferences.data.status;
pref_toolbar = preferences.data.toolbar;
pref_sidepane = preferences.data.sidepane;
pref_fontsettings = preferences.data.fontsettings;
pref_linecount = preferences.data.linecount;
// Allow insertion of tabs
var textFlow:TextFlow = textArea.textFlow;
var config:Configuration = Configuration(textFlow.configuration);
config.manageTabKey = true;
// Set status message
statusMessage = "[ " + new Date().toLocaleTimeString() + " ] Kirpad initialized";
updateStatus();
// Close all sub-windows if main window is closed
addEventListener(Event.CLOSING, onClose);
// Add listener for the event that is dispatched when new font settings are applied
fontWindow.addEventListener(Event.CHANGE, fontChange);
// Update real fonts with the data from the settings values
updateFonts();
// Create a listener for resizing
addEventListener(NativeWindowBoundsEvent.RESIZE, onResize);
// Context menu declaration for the tabbar control
var cm_close:ContextMenuItem = new ContextMenuItem("Close tab");
cm_close.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, tabContextClose);
var cm_closeother:ContextMenuItem = new ContextMenuItem("Close other tabs");
cm_closeother.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, tabContextCloseOther);
var cm_save:ContextMenuItem = new ContextMenuItem("Save");
cm_save.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, tabContextSave);
var cm_duplicate:ContextMenuItem = new ContextMenuItem("Duplicate");
cm_duplicate.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, tabContextDuplicate);
var cm:ContextMenu = new ContextMenu();
cm.items = [cm_close, cm_closeother, cm_save, cm_duplicate];
cm.hideBuiltInItems();
tabBar.contextMenu = cm;
tabBar.addEventListener(MouseEvent.RIGHT_MOUSE_DOWN, tabRightClick);
// Context menu declaration for the tab management list control
sideList.contextMenu = cm;
sideList.addEventListener(MouseEvent.RIGHT_MOUSE_DOWN, listRightClick);
// Listen to keyboard
addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
// Undo management
undoManager = new UndoManager();
editManager = new EditManager(undoManager);
textArea.textFlow.interactionManager = editManager;
// Select first tab
tabChange();
// Database management
var dbFile:File = File.applicationStorageDirectory.resolvePath("database.db");
connection = new SQLConnection();
connection2 = new SQLConnection();
connection2.open(dbFile, SQLMode.CREATE);
connection.addEventListener(SQLEvent.OPEN, onOpen);
connection.openAsync(dbFile, SQLMode.CREATE);
}
private function menuSelect(evt:FlexNativeMenuEvent):void {
(evt.item.@label == "New")?(doNew()):(void);
(evt.item.@label == "Open")?(doOpen()):(void);
(evt.item.@label == "Save")?(doSave(tabSelectedIndex)):(void);
(evt.item.@label == "Save As")?(doSaveAs(textArea.text, tabSelectedIndex)):(void);
(evt.item.@label == "Save All")?(doSaveAll()):(void);
(evt.item.@label == "Word wrap")?(pref_wrap = !pref_wrap):(void);
(evt.item.@label == "Cut")?(doCut()):(void);
(evt.item.@label == "Copy")?(doCopy()):(void);
(evt.item.@label == "Paste")?(doPaste()):(void);
(evt.item.@label == "Select all")?(doSelectall()):(void);
(evt.item.@label == "Status bar")?(pref_status = !pref_status):(void);
(evt.item.@label == "Tool bar")?(pref_toolbar = !pref_toolbar):(void);
(evt.item.@label == "Side pane")?(pref_sidepane = !pref_sidepane):(void);
(evt.item.@label == "Line count")?(pref_linecount = !pref_linecount):(void);
(evt.item.@label == "Font...")?(doFont()):(void);
(evt.item.@label == "Print")?(doPrint()):(void);
(evt.item.@label == "Undo")?(doUndo()):(void);
(evt.item.@label == "Redo")?(doRedo()):(void);
savePreferences();
updateStatus();
if (pref_wrap) {
pref_linecount = false;
}
updateTextSize();
countLines();
}
private function savePreferences():void {
preferences.data.wrap = pref_wrap;
preferences.data.status = pref_status;
preferences.data.toolbar = pref_toolbar;
preferences.data.fontsettings = pref_fontsettings;
preferences.data.sidepane = pref_sidepane;
preferences.data.linecount = pref_linecount;
preferences.flush();
}
private function doCut():void {
var selectedText:String = textArea.text.substring(textArea.selectionActivePosition, textArea.selectionAnchorPosition);
System.setClipboard(selectedText);
insertText("");
}
private function doCopy():void {
var selectedText:String = textArea.text.substring(textArea.selectionActivePosition, textArea.selectionAnchorPosition);
System.setClipboard(selectedText);
}
private function doPaste():void{
var myClip:Clipboard = Clipboard.generalClipboard;
var pastedText:String = myClip.getData(ClipboardFormats.TEXT_FORMAT) as String;
insertText(pastedText);
}
private function doSelectall():void {
textArea.selectAll();
}
private function insertText(str:String):void {
editManager.insertText(str);
}
private function cursorFix():void{
Mouse.cursor = "ibeam";
}
private function everyFrame(evt:Event):void {
if (!heightFixed && height==initHeight) {
height = initHeight - 20;
if (height != initHeight) {
heightFixed = true;
updateTextSize();
}
}
updateLineScroll();
if (sideList.selectedIndices.length==0) {
sideList.selectedIndex = tabSelectedIndex;
}
}
private function onResize(evt:ResizeEvent):void {
updateTextSize();
}
private function updateTextSize():void {
tabY = (toolBar.visible)?(toolBar.height):(0);
textX = (pref_linecount)?(lineCountWidth):(0);
var statusHeight:Number = (pref_status)?(statusBar.height):(0);
textWidth = (pref_sidepane)?(width - sidePaneWidth - textX):(width - textX);
tabWidth = textWidth + textX;
var tabbarScrollHeight:Number = (tabData.length * 170 > tabWidth)?(15):(0);
textY = tabBar.height + tabY + tabbarScrollHeight;
textHeight = height - textY - statusHeight;
focusManager.setFocus(textArea);
sidePaneHeight = textHeight + tabBar.height + tabbarScrollHeight;
sidePaneY = textY - tabBar.height - tabbarScrollHeight;
sidePaneX = width - sidePaneWidth;
}
private function updateStatus():void {
var str:String = new String();
str = (pref_wrap)?("Word wrapping on"):(caretPosition());
status = str + " " + statusMessage;
}
private function caretPosition():String {
var pos:int = textArea.selectionActivePosition;
var str:String = textArea.text.substring(0, pos);
var lines:Array = str.split("
");
var line:int = lines.length;
var col:int = lines[lines.length - 1].length + 1;
return "Ln " + line + ", Col " + col;
}
private function doFont():void{
fontWindow.open();
fontWindow.activate();
fontWindow.visible = true;
fontWindow.setValues(pref_fontsettings.fontsize, pref_fontsettings.fontfamily, pref_fontsettings.fontstyle, pref_fontsettings.fontweight, pref_fontsettings.fontcolor, pref_fontsettings.bgcolor);
}
private function onClose(evt:Event):void {
if(!closeAfterConfirm){
evt.preventDefault();
var allWindows:Array = NativeApplication.nativeApplication.openedWindows;
for (var i:int = 1; i < allWindows.length; i++)
{
allWindows[i].close();
}
// Check if there are any unsaved tabs
var needSaving:Boolean = false;
tabsToClose = 0;
for (var u:int = 0; u < tabData.length; u++) {
if (tabData[u].saved == false) {
needSaving = true;
tabsToClose++;
}
}
// If there are unsaved tabs, dont close window yet, set closeAfterConfirm to true and close all tabs
if (needSaving) {
closeAfterConfirm = true;
for (var t:int = 0; t < tabData.length; t++) {
closeTab(t);
}
}
if (!needSaving) {
FlexGlobals.topLevelApplication.close();
}
}
}
private function fontChange(evt:Event):void{
pref_fontsettings.fontfamily = fontWindow.fontCombo.selectedItem.fontName;
pref_fontsettings.fontsize = fontWindow.sizeStepper.value;
if (fontWindow.styleCombo.selectedIndex == 0) {
pref_fontsettings.fontstyle = "normal";
pref_fontsettings.fontweight = "normal";
}
if (fontWindow.styleCombo.selectedIndex == 1) {
pref_fontsettings.fontstyle = "italic";
pref_fontsettings.fontweight = "normal";
}
if (fontWindow.styleCombo.selectedIndex == 2) {
pref_fontsettings.fontstyle = "normal";
pref_fontsettings.fontweight = "bold";
}
if (fontWindow.styleCombo.selectedIndex == 3) {
pref_fontsettings.fontstyle = "italic";
pref_fontsettings.fontweight = "bold";
}
pref_fontsettings.fontcolor = fontWindow.colorPicker.selectedColor;
pref_fontsettings.bgcolor = fontWindow.bgColorPicker.selectedColor;
savePreferences();
updateFonts();
}
private function updateFonts():void{
textArea.setStyle("fontFamily", pref_fontsettings.fontfamily);
textArea.setStyle("fontSize", pref_fontsettings.fontsize);
textArea.setStyle("fontStyle", pref_fontsettings.fontstyle);
textArea.setStyle("fontWeight", pref_fontsettings.fontweight);
textArea.setStyle("color", pref_fontsettings.fontcolor);
textArea.setStyle("contentBackgroundColor", pref_fontsettings.bgcolor);
lineCount.setStyle("fontFamily", pref_fontsettings.fontfamily);
lineCount.setStyle("fontSize", pref_fontsettings.fontsize);
lineCount.setStyle("fontStyle", pref_fontsettings.fontstyle);
lineCount.setStyle("fontWeight", pref_fontsettings.fontweight);
lineCount.setStyle("color", pref_fontsettings.fontcolor);
lineCount.setStyle("contentBackgroundColor", pref_fontsettings.bgcolor);
}
private function onTabClose(evt:Event):void {
var tabWidth:Number = tabBar.width / tabData.length;
var cIndex:int = Math.floor(tabBar.mouseX / tabWidth);
tabSelectedIndex = cIndex;
tabChange();
closeTab(tabSelectedIndex);
}
private function onListClose(evt:Event):void {
tabSelectedIndex = sideList.selectedIndex;
tabChange();
closeTab(tabSelectedIndex);
}
private function closeTab(index:int):void {
if (tabData[index].saved) {
removeTab(index);
} else
if (!tabData[index].saved) {
Alert.show("Save " + tabData[index].title + " before closing?", "Confirmation", Alert.YES | Alert.NO, null, confirmClose);
}
function confirmClose(evt:CloseEvent):void {
tabsToClose--;
if (evt.detail == Alert.YES) {
tabSelectedIndex = index;
tabChange();
removeTab(index, true);
doSave(index, false);
}else {
removeTab(index);
}
}
}
private function removeTab(index:int, waitForSave:Boolean = false):void {
if(!closeAfterConfirm){
// if this is the last tab, create a new empty tab
if (tabData.length == 1) {
tabData.addItem( { title:"Untitled", textData:"", saved:false, location:""} );
}
statusMessage = "[ " + new Date().toLocaleTimeString() + " ] Tab closed: " + tabData[index].title;
updateStatus();
tabData.removeItemAt(index);
tabSelectedIndex = tabBar.selectedIndex;
previousIndex = tabSelectedIndex;
textArea.text = tabData[tabSelectedIndex].textData;
textArea.selectRange(tabData[tabSelectedIndex].selectedAnchor, tabData[tabSelectedIndex].selectedActive);
}
if (closeAfterConfirm && tabsToClose == 0 && waitForSave == false) {
FlexGlobals.topLevelApplication.close();
}
if (waitForSave) {
saveWait = true;
}
countLines();
updateTextSize();
undoManager.clearAll();
textChange();
}
private function doNew():void {
statusMessage = "[ " + new Date().toLocaleTimeString() + " ] New tab created";
updateStatus();
untitledNum++;
tabData.addItem( { title:"Untitled("+untitledNum+")", textData:"", saved:false, location:""} );
tabSelectedIndex = tabData.length - 1;
tabChange();
updateTextSize();
}
public function tabChange(from:String = "none", ind:int = 0, createOperation:Boolean = true):void {
if (from == "tabbar") {
tabSelectedIndex = tabBar.selectedIndex;
}
if (from == "sidelist") {
tabSelectedIndex = sideList.selectedIndex;
}
if (from == "operation") {
tabSelectedIndex = ind;
}
tabData[previousIndex].textData = textArea.text;
tabData[previousIndex].selectedActive = textArea.selectionActivePosition;
tabData[previousIndex].selectedAnchor = textArea.selectionAnchorPosition;
if (createOperation) {
var operation:TabOperation = new TabOperation(previousIndex, tabSelectedIndex, undoManager);
undoManager.pushUndo(operation);
}
previousIndex = tabSelectedIndex;
textArea.text = tabData[tabSelectedIndex].textData;
textArea.selectRange(tabData[tabSelectedIndex].selectedAnchor, tabData[tabSelectedIndex].selectedActive);
updateStatus();
countLines();
textChange();
var savedSymbol:String = (tabData[tabSelectedIndex].saved)?(""):("*");
title = "Kirpad - " + tabData[tabSelectedIndex].title + savedSymbol;
}
private function tabContextClose(evt:ContextMenuEvent):void{
closeTab(rightclickTabIndex);
}
private function tabContextCloseOther(evt:ContextMenuEvent):void {
var len:int = tabData.length;
for (var i:int = 0; i < len; i++) {
if (i != rightclickTabIndex && tabData[i].saved) {
closeTab(i);
}
}
len = tabData.length;
for (var u:int = 0; u < len; u++) {
if (u != rightclickTabIndex) {
closeTab(u);
}
}
}
private function tabContextSave(evt:ContextMenuEvent):void {
tabSelectedIndex = rightclickTabIndex;
tabChange();
doSave(rightclickTabIndex);
}
private function tabContextDuplicate(evt:ContextMenuEvent):void {
tabSelectedIndex = rightclickTabIndex;
tabChange();
statusMessage = "[ " + new Date().toLocaleTimeString() + " ] " + tabData[rightclickTabIndex].title + " duplicated";
updateStatus();
tabData.addItem( { title:"Copy of " + tabData[rightclickTabIndex].title, textData: tabData[rightclickTabIndex].textData, saved:false, location:""} );
tabSelectedIndex = tabData.length - 1;
tabChange();
updateTextSize();
}
private function tabRightClick(evt:MouseEvent):void {
var tabWidth:Number = tabBar.width / tabData.length;
var rcIndex:int = Math.floor(tabBar.mouseX / tabWidth);
rightclickTabIndex = rcIndex;
}
private function listRightClick(evt:MouseEvent):void {
var tabHeight:Number = 20;
var rcIndex:int = Math.floor((sideList.mouseY + sideList.scroller.verticalScrollBar.value) / tabHeight);
rightclickTabIndex = rcIndex;
}
private function onKeyDown(evt:KeyboardEvent):void{
if (evt.ctrlKey) {
// Ctrl+TAB - next tab
if (evt.keyCode == 9 && !evt.shiftKey) {
if (tabData.length - tabSelectedIndex > 1) {
tabSelectedIndex++;
tabChange();
}
}
// Ctrl+Shift+TAB - previous tab
if (evt.keyCode == 9 && evt.shiftKey) {
if (tabSelectedIndex > 0) {
tabSelectedIndex--;
tabChange();
}
}
// Ctrl+number (1-8) - go to numbered tab
if (evt.keyCode >= 49 && evt.keyCode <= 56) {
var num:int = evt.keyCode - 48;
if (tabData.length > num - 1) {
tabSelectedIndex = num - 1;
tabChange();
}
}
// Ctrl+9 - go to last tab
if (evt.keyCode == 57) {
tabSelectedIndex = tabData.length - 1;
tabChange();
}
}
}
private function closeSidePane():void{
pref_sidepane = !pref_sidepane
savePreferences();
updateTextSize();
}
private function countLines():void {
if (pref_linecount && !pref_wrap) {
var totalLines:int = textArea.text.split("
").length;
if (totalLines != lineDisplayedNum) {
updateTextSize();
updateLineCount(totalLines, totalLines-lineDisplayedNum, lineDisplayedNum);
lineDisplayedNum = totalLines;
}
}
}
private function updateLineCount(total:int, difference:int, current:int):void {
if (difference > 0) {
for (var i:int = current + 1; i < (total+1); i++) {
lineNumbers += "
" + (i);
}
}
if (difference < 0) {
var charsInTheEnd:int = 0;
for (var u:int = 0; u < -difference; u++) {
charsInTheEnd += ((current - u).toString().length + 1);
}
lineNumbers = lineCount.text.substring(0, lineCount.text.length - charsInTheEnd);
}
}
private function updateLineScroll():void{
lineCount.scroller.verticalScrollBar.value = textArea.scroller.verticalScrollBar.value;
}
private function doPrint():void {
var printJob:FlexPrintJob = new FlexPrintJob();
if (!printJob.start()) return;
tempText.visible = true;
tempText.setStyle("lineBreak", "toFit");
tempText.text = textArea.text;
tempText.width = printJob.pageWidth;
tempText.heightInLines = NaN;
tempText.setStyle("horizontalScrollPolicy", "off");
tempText.setStyle("verticalScrollPolicy", "off");
printJob.printAsBitmap = false;
printJob.addObject(tempText, "matchWidth");
printJob.send();
tempText.visible = false;
}
private function textChange():void{
canUndo = undoManager.canUndo();
canRedo = undoManager.canRedo();
focusManager.setFocus(textArea);
}
private function doUndo():void {
undoManager.undo();
textChange();
}
private function doRedo():void {
undoManager.redo();
textChange();
}
private function doOpen():void {
var file:File = new File();
file.browseForOpen("Open document", [new FileFilter("Text documents", "*.txt"), new FileFilter("All files", "*")]);
file.addEventListener(Event.SELECT, fileLoad);
function fileLoad(evt:Event):void {
loadFile(file);
}
}
private function loadFile(file:File):void {
if(fileDuplicateCheck(file.nativePath)){
var stream:FileStream = new FileStream();
stream.open(file, FileMode.READ);
var str:String = stream.readUTFBytes(stream.bytesAvailable);
stream.close();
str = str.replace(File.lineEnding, "
");
statusMessage = "[ " + new Date().toLocaleTimeString() + " ] " + file.name + " opened";
updateStatus();
tabData.addItem( { title:file.name, textData: str, saved:true, location:file.nativePath } );
tabSelectedIndex = tabData.length - 1;
tabChange();
updateTextSize();
}else {
Alert.show("File " + file.name + " is already open","Error");
}
}
private function fileDuplicateCheck(loc:String):Boolean {
var toReturn:Boolean = true;
for (var i:int = 0; i < tabData.length; i++) {
if (tabData[i].location == loc) {
toReturn = false;
tabSelectedIndex = i;
tabChange();
break;
}
}
return toReturn;
}
private function saveUpdate():void {
if (tabData[tabSelectedIndex].saved) {
tabData[tabSelectedIndex].saved = false;
tabBar.dataProvider = new ArrayCollection([]);
tabBar.dataProvider = tabData;
tabBar.selectedIndex = tabSelectedIndex;
sideList.dataProvider = tabData;
var savedSymbol:String = (tabData[tabSelectedIndex].saved)?(""):("*");
title = "Kirpad - " + tabData[tabSelectedIndex].title + savedSymbol;
}
}
private function doSave(ind:int, updateIndexNeeded:Boolean = true):void {
if(!tabData[ind].saved){
if (tabData[ind].location != "") {
saveFile(textArea.text, tabData[ind].location, updateIndexNeeded);
statusMessage = "[ " + new Date().toLocaleTimeString() + " ] " + tabData[ind].title + " saved";
updateStatus();
tabData[ind].saved = true;
}else{
doSaveAs(textArea.text, ind, updateIndexNeeded);
}
}
}
private function doSaveAll():void {
saveAsQueue = [];
for (var i:int = 0; i < tabData.length; i++) {
saveAsQueue.push(i);
}
doSaveQueue();
}
private function doSaveQueue():void {
if (saveAsQueue.length > 0) {
var ind:int = saveAsQueue[0];
saveAsQueue.splice(0, 1);
tabSelectedIndex = ind;
tabChange();
doSave(ind);
}
}
private function refreshData():void {
tabBar.dataProvider = new ArrayCollection([]);
tabBar.dataProvider = tabData;
tabBar.selectedIndex = tabSelectedIndex;
sideList.dataProvider = tabData;
}
private function doSaveAs(text:String, ind:int, updateIndexNeeded:Boolean = true):void {
var file:File = new File();
file.browseForSave("Save " + tabData[ind].title);
file.addEventListener(Event.SELECT, fileSave);
file.addEventListener(Event.CANCEL, fileCancel);
function fileSave(evt:Event):void {
if (file.name.length > 0) {
// See if user entered extension for the file (for example .txt)
// If not, add .txt by default
var extReg:RegExp = /.([a-z0-9]{2,})/i;
if (extReg.test(file.name)) {
saveFile(text, file.nativePath, updateIndexNeeded);
tabData[ind].location = file.nativePath;
tabData[ind].title = file.name;
tabData[ind].saved = true;
}else{
saveFile(text, file.nativePath + ".txt", updateIndexNeeded);
tabData[ind].location = file.nativePath + ".txt";
tabData[ind].title = file.name + ".txt";
tabData[ind].saved = true;
}
}else{
Alert.show("You need to enter a name for your file.", "Error");
}
}
function fileCancel(evt:Event):void {
doSaveQueue();
}
}
private function saveFile(text:String, location:String, updateIndexNeeded:Boolean = true):void {
var file:File = new File(location);
var stream:FileStream = new FileStream();
stream.open(file, FileMode.WRITE);
var str:String = text;
str = str.replace(/
/g, File.lineEnding);
stream.writeUTFBytes(str);
stream.close();
if (closeAfterConfirm && tabsToClose == 0 && saveWait) {
FlexGlobals.topLevelApplication.close();
}
saveWait = false;
if (updateIndexNeeded) {
refreshData();
}
doSaveQueue();
}
private function updateDirectoryPath():void{
directoryLabel.text = fileList.directory.nativePath;
}
private function fileListLoad():void{
var file:File = new File(fileList.selectedPath);
loadFile(file);
}
private function onOpen(evt:SQLEvent):void {
// create snippets table
var stat:SQLStatement = new SQLStatement();
stat.sqlConnection = connection;
stat.text = "CREATE TABLE IF NOT EXISTS snippets (id INTEGER PRIMARY KEY AUTOINCREMENT, snippetName TEXT, snippetText TEXT, categoryID INTEGER, snippetPosition INTEGER)";
stat.execute( -1, new Responder(onCreateSnippets));
}
private function onCreateSnippets(evt:SQLResult):void {
// create category table
var stat:SQLStatement = new SQLStatement();
stat.sqlConnection = connection2;
stat.text = "CREATE TABLE IF NOT EXISTS categories (id INTEGER PRIMARY KEY AUTOINCREMENT, categoryName TEXT, categoryPosition INTEGER)";
stat.execute( -1, new Responder(onCreateCategory));
}
private function onCreateCategory(evt:SQLResult):void {
// select snippets
var stat:SQLStatement = new SQLStatement();
stat.sqlConnection = connection;
stat.text = "SELECT id, snippetName, categoryID, snippetPosition FROM snippets ORDER BY id";
stat.execute( -1, new Responder(onSelectedSnippets));
}
private function onSelectedSnippets(evt:SQLResult):void {
// save selected snippets to a variable
snippetData = evt.data;
// select categories
var stat:SQLStatement = new SQLStatement();
stat.sqlConnection = connection2;
stat.text = "SELECT id, categoryName, categoryPosition FROM categories ORDER BY id";
stat.execute( -1, new Responder(onSelectedCategories));
}
private function onSelectedCategories(evt:SQLResult):void {
// save selected categories to a variable
categoryData = evt.data;
// call function to start creating the XML
createSnippetXML();
}
private function createSnippetXML():void {
// temporary:
categoryData = [
{ id:0, categoryName:"Cat1", categoryPosition:1 },
{ id:1, categoryName:"Cat2", categoryPosition:0 },
]
snippetData = [
{ id:0, snippetName: "Snip1", snippetPosition: 0, categoryID: 0 },
{ id:1, snippetName: "Snip2", snippetPosition: 1, categoryID: 0 },
{ id:2, snippetName: "Snip3", snippetPosition: 1, categoryID: 1 },
{ id:3, snippetName: "Snip4", snippetPosition: 0, categoryID: 1 },
{ id:4, snippetName: "Snip5", snippetPosition: 0, categoryID: -1 },
{ id:5, snippetName: "Snip6", snippetPosition: 1, categoryID: -1 },
]
snippetXML = new XMLList();
// add root tags if there are any items in any database
if (snippetData || categoryData) {
snippetXML = new XMLList(<root></root>);
}
// loop through categories to add them and their content
if (categoryData) {
for (var i:int = 0; i < categoryData.length; i++) {
var aCategory:XML = <category/>
aCategory.@id = categoryData[i].id;
aCategory.@label = categoryData[i].categoryName;
aCategory.@isBranch = true;
snippetXML[0].appendChild(aCategory);
for (var u:int = 0; u < snippetData.length; u++) {
if (snippetData[u].categoryID == categoryData[i].id) {
var aSnippet:XML = <snippet/>;
aSnippet.@id = snippetData[u].id;
aSnippet.@label = snippetData[u].snippetName;
aSnippet.@categoryID = snippetData[u].categoryID;
aCategory.appendChild(aSnippet);
}
}
}
// look for snippets located in root tags (not in a category)
for (var t:int = 0; t < snippetData.length; t++) {
if (snippetData[t].categoryID == -1) {
var aRootSnippet:XML = <snippet/>;
aRootSnippet.@id = snippetData[t].id;
aRootSnippet.@label = snippetData[t].snippetName;
aRootSnippet.@categoryID = snippetData[t].categoryID;
snippetXML[0].appendChild(aRootSnippet);
}
}
}
}
private function snippetTreeChange(evt:Event):void {
if (evt.currentTarget.selectedItem.@isBranch == false) {
// TODO: get data from database and insert it
evt.currentTarget.selectedIndex = -1;
}
}
private function doSnippet(createNew:Boolean = false, newText:String = ""):void{
snippetWindow.open();
snippetWindow.activate();
snippetWindow.visible = true;
snippetWindow.setValues(snippetXML, connection, connection2, createNew, newText);
}
]]>
</fx:Script>
<fx:Declarations>
<fx:XML id="windowMenu">
<root>
<menuitem label="File">
<menuitem label="New" key="n" controlKey="true" />
<menuitem label="Open" key="o" controlKey="true" />
<menuitem label="Save" key="s" controlKey="true" />
<menuitem label="Save As" key="s" controlKey="true" shiftKey="true" />
<menuitem label="Save All" key="s" controlKey="true" altKey="true" />
<menuitem type="separator"/>
<menuitem label="Print" key="p" controlKey="true" />
</menuitem>
<menuitem label="Edit">
<menuitem label="Undo" key="z" controlKey="true" enabled="{canUndo}" />
<menuitem label="Redo" key="y" controlKey="true" enabled="{canRedo}" />
<menuitem type="separator"/>
<menuitem label="Cut" key="x" controlKey="true" />
<menuitem label="Copy" key="c" controlKey="true" />
<menuitem label="Paste" key="v" controlKey="true" />
<menuitem type="separator"/>
<menuitem label="Select all" key="a" controlKey="true" />
</menuitem>
<menuitem label="Settings">
<menuitem label="Word wrap" type="check" toggled="{pref_wrap}" />
<menuitem label="Font..."/>
</menuitem>
<menuitem label="View">
<menuitem label="Tool bar" type="check" toggled="{pref_toolbar}" />
<menuitem label="Status bar" type="check" toggled="{pref_status}" />
<menuitem label="Line count" type="check" toggled="{pref_linecount}" />
<menuitem label="Side pane" type="check" toggled="{pref_sidepane}" />
</menuitem>
</root>
</fx:XML>
<mx:ArrayCollection id="tabData">
<fx:Object title="Untitled" textData="" saved="false" seletedActive="0" selectedAnchor="0" location="" />
</mx:ArrayCollection>
<mx:ArrayCollection id="sidePaneData">
<fx:Object icon="@Embed(../lib/page.png)" tip="Tab management" />
<fx:Object icon="@Embed(../lib/folder_magnify.png)" tip="File browsing" />
<fx:Object icon="@Embed(../lib/book.png)" tip="Snippets" />
</mx:ArrayCollection>
<mx:ArrayCollection id="sidePaneTabHeadings">
<fx:String>Tab management</fx:String>
<fx:String>File browsing</fx:String>
<fx:String>Snippets</fx:String>
</mx:ArrayCollection>
</fx:Declarations>
<s:Group width="100%" height="100%">
<s:TextArea id="textArea" width="{textWidth}" height="{textHeight}" y="{textY}" x="{textX}" lineBreak="{(pref_wrap)?(toFit):(explicit)}" click="cursorFix(); updateStatus();" change="updateStatus(); countLines(); textChange(); saveUpdate();" keyDown="updateStatus();" borderVisible="false" focusThickness="0" />
<s:Scroller horizontalScrollPolicy="auto" verticalScrollPolicy="off" width="{tabWidth}" y="{tabY}">
<s:Group>
<custom:CustomTabBar id="tabBar" dataProvider="{tabData}" itemRenderer="CustomTab" height="22" tabClose="onTabClose(event);" change="tabChange(tabbar);" selectedIndex="{tabSelectedIndex}" labelField="saved">
<custom:layout>
<s:HorizontalLayout gap="-1" columnWidth="170" variableColumnWidth="false"/>
</custom:layout>
</custom:CustomTabBar>
</s:Group>
</s:Scroller>
<s:TextArea id="lineCount" width="{lineCountWidth}" text="{lineNumbers}" visible="{pref_linecount}" height="{textHeight}" y="{textY}" editable="false" selectable="false" mouseEnabled="false" textAlign="right" verticalScrollPolicy="off" horizontalScrollPolicy="off" />
<mx:HBox id="toolBar" width="100%" backgroundColor="#dddddd" height="30" visible="{pref_toolbar}" paddingTop="2" paddingLeft="3">
<custom:IconButton icon="@Embed(../lib/page.png)" toolTip="New document" click="doNew();" />
<custom:IconButton icon="@Embed(../lib/folder_page.png)" toolTip="Open" click="doOpen();" />
<custom:IconButton icon="@Embed(../lib/disk.png)" toolTip="Save" click="doSave(tabSelectedIndex);" />
<custom:IconButton icon="@Embed(../lib/disk_multiple.png)" toolTip="Save all" click="doSaveAll();" />
<custom:IconButton icon="@Embed(../lib/printer.png)" toolTip="Print" click="doPrint();" />
<s:Label text="|" fontSize="18" color="#bbbbbb" paddingTop="4" />
<custom:IconButton icon="@Embed(../lib/arrow_undo.png)" toolTip="Undo" enabled="{canUndo}" click="doUndo();" />
<custom:IconButton icon="@Embed(../lib/arrow_redo.png)" toolTip="Redo" enabled="{canRedo}" click="doRedo();" />
<s:Label text="|" fontSize="18" color="#bbbbbb" paddingTop="4" />
<custom:IconButton icon="@Embed(../lib/cut.png)" toolTip="Cut" click="doCut();" />
<custom:IconButton icon="@Embed(../lib/page_white_copy.png)" toolTip="Copy" click="doCopy();" />
<custom:IconButton icon="@Embed(../lib/paste_plain.png)" toolTip="Paste" click="doPaste();" />
</mx:HBox>
<mx:Box id="sidePane" width="{sidePaneWidth}" y="{sidePaneY}" x="{sidePaneX}" height="{sidePaneHeight}" backgroundColor="#dddddd" visible="{pref_sidepane}" paddingTop="5" paddingLeft="5" horizontalScrollPolicy="off">
<s:Group>
<s:Label text="{sidePaneTabHeadings.getItemAt(sidePaneButtons.selectedIndex)}" width="{sidePaneWidth}" top="1" />
<custom:IconButton icon="@Embed(../lib/bullet_go.png)" toolTip="Hide side pane" click="closeSidePane();" top="-4" right="12"/>
</s:Group>
<mx:ToggleButtonBar id="sidePaneButtons" dataProvider="{sidePaneData}" iconField="icon" width="{sidePaneWidth-10}" toolTipField="tip" />
<mx:ViewStack id="sidePaneStack" height="100%" selectedIndex="{sidePaneButtons.selectedIndex}">
<s:NavigatorContent id="tabs">
<custom:CustomList id="sideList" dataProvider="{tabData}" width="{sideContentWidth}" height="100%" itemRenderer="CustomListItem" selectedIndex="{tabSelectedIndex}" change="tabChange(sidelist);" tabClose="onListClose(event);" />
</s:NavigatorContent>
<s:NavigatorContent id="files">
<s:VGroup height="100%">
<s:HGroup width="100%">
<custom:IconButton icon="@Embed(../lib/arrow_up.png)" toolTip="Up" click="fileList.navigateUp();" enabled="{fileList.canNavigateUp}"/>
<s:Label width="140" id="directoryLabel" paddingTop="6" />
</s:HGroup>
<mx:FileSystemList width="{sidePaneWidth-10}" height="100%" id="fileList" directory="{File.desktopDirectory}" directoryChange="updateDirectoryPath();" creationComplete="updateDirectoryPath();" fileChoose="fileListLoad();" />
</s:VGroup>
</s:NavigatorContent>
<s:NavigatorContent id="snippets">
<s:VGroup height="100%" width="100%">
<mx:Tree height="100%" width="100%" id="snippetTree" showRoot="false" labelField="@label" dataProvider="{snippetXML}" change="snippetTreeChange(event);" />
<s:Button width="100%" label="New snippet" click="doSnippet(true, textArea.text.substring(textArea.selectionActivePosition, textArea.selectionAnchorPosition));" />
<s:Button width="100%" label="Manage snippets" click="doSnippet();" />
</s:VGroup>
</s:NavigatorContent>
</mx:ViewStack>
</mx:Box>
</s:Group>
<s:TextArea id="tempText" borderVisible="false" visible="false"/>
</s:WindowedApplication>
Thanks for reading!
Android beginner tutorial Part 58 Send and receive data between Activities
In this tutorial well learn how to transfer data between two Activities.
We are going to have two activities - MainActivity and SecondActivity. Ive already covered how to create secondary Activities in the tutorial about Intents. I explained how to do that in detail in that tutorial, so if you followed my tutorials you should be able to do that. A reminder: add an Activity in the Manifest XML file and add a SecondActivity.java class and an activity_second.xml layout.
The main activity is going to have a button that opens a new Activity. However, it launches it with an intention to receive a result. This is done using a startActivityForResult() method. By doing it that way we tell our main activity to expect a result from the Activity were launching. In the second activity well have an EditText input and a button. When the button is pressed, the data in the text field is sent back to the main activity and the second activity is closed.
When the main activity receives the message, it displays it in a toast.
Lets see how we are going to do this. Firstly, go to activity_main.xml layout and add a button:
In MainActivity.java declare an ID for the request:
Use it when you call startActivityForResult() in the click event handler of the button:
The request is sent, but what about receiving the results?
Create a function onActivityResult(). Call its superclass and then check if resultCode parameter equals RESULT_OK. That means weve received a result as expected.
Inside the if...statement declare an "extras" variable, which is a Bundle type object and gets its values from data.getExtras().
Then we check if requestCode parameters value equals IDM_TEST (the id we passed when requesting the result), and if so, toast the results using the extras object:
Full MainActivity.java code:
The activity_second.xml layout has an EditText object and a Button:
In SecondActivity.java class, we only need to handle the button. When it is clicked, we create an intent and use a method called setResult(). To pass the values to the parent activity we can use the putExtra() method of the intent. It has 2 parameters - name and value.
Thats all! Now you can go to the second activity from your main one, enter some text, return to the main activity using the button and see the main activity display the data received from the second one.
Thanks for reading!
Read more »
We are going to have two activities - MainActivity and SecondActivity. Ive already covered how to create secondary Activities in the tutorial about Intents. I explained how to do that in detail in that tutorial, so if you followed my tutorials you should be able to do that. A reminder: add an Activity in the Manifest XML file and add a SecondActivity.java class and an activity_second.xml layout.
The main activity is going to have a button that opens a new Activity. However, it launches it with an intention to receive a result. This is done using a startActivityForResult() method. By doing it that way we tell our main activity to expect a result from the Activity were launching. In the second activity well have an EditText input and a button. When the button is pressed, the data in the text field is sent back to the main activity and the second activity is closed.
When the main activity receives the message, it displays it in a toast.
Lets see how we are going to do this. Firstly, go to activity_main.xml layout and add a button:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="32sp"
android:text="First Activity"
/>
<Button android:id="@+id/goButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Launch Second Activity"
/>
</LinearLayout>
In MainActivity.java declare an ID for the request:
private static final int IDM_TEST = 101;
Use it when you call startActivityForResult() in the click event handler of the button:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button btn = (Button)findViewById(R.id.goButton);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(getApplicationContext(), SecondActivity.class);
startActivityForResult(intent, IDM_TEST);
}
});
}
The request is sent, but what about receiving the results?
Create a function onActivityResult(). Call its superclass and then check if resultCode parameter equals RESULT_OK. That means weve received a result as expected.
Inside the if...statement declare an "extras" variable, which is a Bundle type object and gets its values from data.getExtras().
Then we check if requestCode parameters value equals IDM_TEST (the id we passed when requesting the result), and if so, toast the results using the extras object:
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
Bundle extras = data.getExtras();
// handle results
if(requestCode == IDM_TEST){
Toast toast = Toast.makeText(MainActivity.this, extras.getString("UserText"), Toast.LENGTH_SHORT);
toast.show();
}
}
}
Full MainActivity.java code:
package com.kircode.codeforfood_test;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends Activity{
private static final int IDM_TEST = 101;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button btn = (Button)findViewById(R.id.goButton);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(getApplicationContext(), SecondActivity.class);
startActivityForResult(intent, IDM_TEST);
}
});
}
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
Bundle extras = data.getExtras();
// handle results
if(requestCode == IDM_TEST){
Toast toast = Toast.makeText(MainActivity.this, extras.getString("UserText"), Toast.LENGTH_SHORT);
toast.show();
}
}
}
}
The activity_second.xml layout has an EditText object and a Button:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="32sp"
android:text="Second Activity"
/>
<EditText android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Write something here..."
android:id="@+id/editText"
/>
<Button android:id="@+id/backButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="OK"
/>
</LinearLayout>
In SecondActivity.java class, we only need to handle the button. When it is clicked, we create an intent and use a method called setResult(). To pass the values to the parent activity we can use the putExtra() method of the intent. It has 2 parameters - name and value.
package com.kircode.codeforfood_test;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class SecondActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
final Button btn = (Button)findViewById(R.id.backButton);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EditText text = (EditText)findViewById(R.id.editText);
Intent intent = new Intent();
intent.putExtra("UserText", text.getText().toString());
setResult(RESULT_OK, intent);
finish();
}
});
}
}
Thats all! Now you can go to the second activity from your main one, enter some text, return to the main activity using the button and see the main activity display the data received from the second one.
Thanks for reading!
Creating EasyTooltip class Part 16
Today well add the ability to create bitmap fills and strokes for our tooltips.
First, create 2 new class files - BitmapRect.as and BitmapStroke.as. These are similar to the classes of the same name in the AdvAlert library.
BitmapRect.as code:
BitmapStroke.as code:
Go to TooltipCursor.as, find the updateDisplay() function. Create 2 new if..statements here.
The first one checks if style.backgroundStroke is an object of class BitmapStroke. Base this if..statement off the one that checks if the object is an instance of GradientColorStroke, just change lineGradientStyle() to lineBitmapStyle() and use the approporiate values:
The second if...statement checks if backgroundRect is an instance of BitmapRect class. Base this one on the if...statement that checks if backgroundRect is an object of GradientColorRect class. Change beginGradientFill() to beginBitmapFill() and use the new values:
Full class code:
Using bitmap strokes and fills is now as easy as it is to use gradients. In this example, I create 2 perlin noise BitmapDatas and set them as stroke and fill of the tooltip:
Thanks for reading!
The results:
Read more »
First, create 2 new class files - BitmapRect.as and BitmapStroke.as. These are similar to the classes of the same name in the AdvAlert library.
BitmapRect.as code:
package com.kircode.EasyTooltip
{
import flash.display.BitmapData;
import flash.geom.Matrix;
/**
* ...
* @author Kirill Poletaev
*/
public class BitmapRect
{
public var _bitmap:BitmapData;
public var _matrix:Matrix;
public var _repeat:Boolean;
public var _smooth:Boolean;
public var _radius:Array;
/**
* Create a rectangle filled with bitmap. Has the same parameters as beginBitmapFill(), plus lineThickness, lineColor, lineAlpha and cornerRadius.
* @parambitmap BitmapData to be used to fill the rectangle.
* @parammatrix Matrix object for transformation.
* @paramrepeat Repeat the bitmap when filling.
* @paramsmooth Smoothen the bitmap.
* @paramcornerRadius Radius of the corners of the box - top left, top right, bottom left, bottom right.
*/
public function BitmapRect(bitmap:BitmapData, matrix:Matrix = null, repeat:Boolean = true, smooth:Boolean = false, cornerRadius:Array = null)
{
if (cornerRadius == null) cornerRadius = [10, 10, 0, 0];
_bitmap = bitmap;
_matrix = matrix;
_repeat = repeat;
_smooth = smooth;
_radius = cornerRadius;
}
}
}
BitmapStroke.as code:
package com.kircode.EasyTooltip
{
import flash.display.BitmapData;
import flash.geom.Matrix;
/**
* ...
* @author Kirill Poletaev
*/
public class BitmapStroke
{
public var _lineThickness:Number;
public var _bitmap:BitmapData;
public var _matrix:Matrix;
public var _repeat:Boolean;
public var _smooth:Boolean;
/**
* Create a bitmap filled line stroke. Uses same parameters as lineBitmapStyle() + lineThickness.
* @paramlineThickness Thickness of the line stroke.
* @parambitmap BitmapData to be used to fill the rectangle.
* @parammatrix Matrix object for transformation.
* @paramrepeat Repeat the bitmap when filling.
* @paramsmooth Smoothen the bitmap.
*/
public function BitmapStroke(lineThickness:Number, bitmap:BitmapData, matrix:Matrix = null, repeat:Boolean = true, smooth:Boolean = false)
{
_lineThickness = lineThickness;
_bitmap = bitmap;
_matrix = matrix;
_repeat = repeat;
_smooth = smooth;
}
}
}
Go to TooltipCursor.as, find the updateDisplay() function. Create 2 new if..statements here.
The first one checks if style.backgroundStroke is an object of class BitmapStroke. Base this if..statement off the one that checks if the object is an instance of GradientColorStroke, just change lineGradientStyle() to lineBitmapStyle() and use the approporiate values:
if (style.backgroundStroke is BitmapStroke) {
if(style.backgroundStroke._matrix){
style.backgroundStroke._matrix.tx = actual_x;
style.backgroundStroke._matrix.ty = actual_y;
}
background.graphics.lineStyle(style.backgroundStroke._lineThickness);
background.graphics.lineBitmapStyle(style.backgroundStroke._bitmap, style.backgroundStroke._matrix, style.backgroundStroke._repeat, style.backgroundStroke._smooth);
}
The second if...statement checks if backgroundRect is an instance of BitmapRect class. Base this one on the if...statement that checks if backgroundRect is an object of GradientColorRect class. Change beginGradientFill() to beginBitmapFill() and use the new values:
if (style.backgroundRect is BitmapRect) {
if(style.backgroundRect._matrix){
style.backgroundRect._matrix.tx = actual_x;
style.backgroundRect._matrix.ty = actual_y;
}
background.graphics.beginBitmapFill(style.backgroundRect._bitmap, style.backgroundRect._matrix, style.backgroundRect._repeat, style.backgroundRect._smooth);
background.graphics.drawRoundRectComplex(actual_x, actual_y, w, h, style.backgroundRect._radius[0], style.backgroundRect._radius[1], style.backgroundRect._radius[2], style.backgroundRect._radius[3]);
background.graphics.endFill();
}
Full class code:
package com.kircode.EasyTooltip
{
import flash.display.MovieClip;
import flash.display.Shape;
import flash.text.TextField;
import flash.text.TextFormat;
/**
* The cursor that follows the mouse (if not set otherwise) and displays each tooltip.
* @author Kirill Poletaev
*/
public class TooltipCursor extends MovieClip
{
public var txt:TextField;
private var style:TooltipStyle;
private var background:Shape;
private var w:int;
private var h:int;
private var actual_x:int;
private var actual_y:int;
private var parentW:int;
private var parentH:int;
private var direction:String = "";
public function TooltipCursor(pW:int, pH:int)
{
parentW = pW;
parentH = pH;
txt = new TextField();
txt.multiline = true;
background = new Shape();
addChild(background);
addChild(txt);
txt.width = 1;
txt.height = 1;
}
/**
* Set style of the tooltips.
* @paramst TooltipStyle object to apply.
*/
public function setStyle(st:TooltipStyle):void {
style = st;
}
/**
* Change the text value of the tooltip.
* @parammessage The new text value.
*/
public function setText(message:String):void {
txt.text = message;
txt.setTextFormat(style.textFormat);
updateSize();
updateDisplay();
}
private function updateDisplay():void {
background.graphics.clear();
if (style.backgroundStroke is SolidColorStroke) {
background.graphics.lineStyle(style.backgroundStroke._lineThickness, style.backgroundStroke._lineColor, style.backgroundStroke._lineAlpha);
}
if (style.backgroundStroke is GradientColorStroke) {
if(style.backgroundStroke._matrix){
style.backgroundStroke._matrix.tx = actual_x;
style.backgroundStroke._matrix.ty = actual_y;
}
background.graphics.lineStyle(style.backgroundStroke._lineThickness);
background.graphics.lineGradientStyle(style.backgroundStroke._gradientType, style.backgroundStroke._colors, style.backgroundStroke._alphas, style.backgroundStroke._ratios, style.backgroundStroke._matrix, style.backgroundStroke._spreadMethod, style.backgroundStroke._interpolationMethod, style.backgroundStroke._focalPointRatio);
}
if (style.backgroundStroke is BitmapStroke) {
if(style.backgroundStroke._matrix){
style.backgroundStroke._matrix.tx = actual_x;
style.backgroundStroke._matrix.ty = actual_y;
}
background.graphics.lineStyle(style.backgroundStroke._lineThickness);
background.graphics.lineBitmapStyle(style.backgroundStroke._bitmap, style.backgroundStroke._matrix, style.backgroundStroke._repeat, style.backgroundStroke._smooth);
}
if (style.backgroundRect is SolidColorRect) {
background.graphics.beginFill(style.backgroundRect._backgroundColor, style.backgroundRect._alpha);
background.graphics.drawRoundRectComplex(actual_x, actual_y, w, h, style.backgroundRect._radius[0], style.backgroundRect._radius[1], style.backgroundRect._radius[2], style.backgroundRect._radius[3]);
background.graphics.endFill();
}
if (style.backgroundRect is GradientColorRect) {
if(style.backgroundRect._matrix){
style.backgroundRect._matrix.tx = actual_x;
style.backgroundRect._matrix.ty = actual_y;
}
background.graphics.beginGradientFill(style.backgroundRect._gradientType, style.backgroundRect._colors, style.backgroundRect._alphas, style.backgroundRect._ratios, style.backgroundRect._matrix, style.backgroundRect._spreadMethod, style.backgroundRect._interpolationMethod, style.backgroundRect._focalPointRatio);
background.graphics.drawRoundRectComplex(actual_x, actual_y, w, h, style.backgroundRect._radius[0], style.backgroundRect._radius[1], style.backgroundRect._radius[2], style.backgroundRect._radius[3]);
background.graphics.endFill();
}
if (style.backgroundRect is BitmapRect) {
if(style.backgroundRect._matrix){
style.backgroundRect._matrix.tx = actual_x;
style.backgroundRect._matrix.ty = actual_y;
}
background.graphics.beginBitmapFill(style.backgroundRect._bitmap, style.backgroundRect._matrix, style.backgroundRect._repeat, style.backgroundRect._smooth);
background.graphics.drawRoundRectComplex(actual_x, actual_y, w, h, style.backgroundRect._radius[0], style.backgroundRect._radius[1], style.backgroundRect._radius[2], style.backgroundRect._radius[3]);
background.graphics.endFill();
}
txt.width = w - style.textPadding.left - style.textPadding.right;
txt.height = h - style.textPadding.top - style.textPadding.bottom;
txt.x = actual_x + style.textPadding.left;
txt.y = actual_y + style.textPadding.top;
}
private function updateSize():void {
if (style.maxWidth == 0) style.maxWidth = parentW;
if (style.maxHeight == 0) style.maxHeight = parentH;
txt.wordWrap = true;
w = txt.textWidth + 4 + style.textPadding.left + style.textPadding.right;
h = txt.textHeight + 4 + style.textPadding.top + style.textPadding.bottom;
if (w > style.maxWidth) w = style.maxWidth;
if (h > style.maxHeight) h = style.maxHeight;
if (w < style.minWidth) w = style.minWidth;
if (h < style.minHeight) h = style.minHeight;
// calculate best direction
if (this.y <= h-style.offsetY) {
direction = "bottom";
actual_y = -style.offsetY;
} else
if (this.y > h-style.offsetY) {
direction = "top";
actual_y = -h + style.offsetY;
}
if (this.x <= parentW * 0.5) {
direction += "right";
actual_x = - style.offsetX;
} else
if (this.x > parentW * 0.5) {
direction += "left";
actual_x = -w + style.offsetX;
}
// If sticks out on the right:
if(direction == "topright" || direction == "bottomright"){
// if tooltip sticks out of border - calculate shortened width to fit the content
if (this.x + actual_x + w > parentW) {
txt.wordWrap = true;
w = parentW - this.x - actual_x;
h = txt.textHeight + 4 + style.textPadding.top + style.textPadding.bottom;
if (w > style.maxWidth) w = style.maxWidth;
if (h > style.maxHeight) h = style.maxHeight;
if (w < style.minWidth) {
w = style.minWidth;
this.x = parentW - w + style.offsetX;
}
if (h < style.minHeight) h = style.minHeight;
} else {
// if doesnt stick out, keep adding 1 pixel to the width until as much text is seen as possible
while (this.x + actual_x + w < parentW && w < style.maxWidth && w >= style.minWidth) {
w += 1;
// try turning off wordwrap and see if it still fits (as one line)
txt.wordWrap = false;
if (w > txt.textWidth + 4 + style.textPadding.left + style.textPadding.right && w >= style.minWidth && w < style.maxWidth) {
w = txt.textWidth + 4 + style.textPadding.left + style.textPadding.right;
if (w < style.minWidth) {
w = style.minWidth;
}
break;
}
txt.wordWrap = true;
}
}
}
// If sticks out on the left:
if(direction == "topleft" || direction == "bottomleft"){
if (this.x + actual_x <= 0) {
txt.wordWrap = true;
actual_x = -this.x;
w = this.x + style.offsetX;
h = txt.textHeight + 4 + style.textPadding.top + style.textPadding.bottom;
if (w > style.maxWidth) w = style.maxWidth;
if (h > style.maxHeight) h = style.maxHeight;
if (w < style.minWidth) w = style.minWidth;
if (h < style.minHeight) h = style.minHeight;
} else {
// if doesnt stick out, keep adding 1 pixel to the width (and substracting it from actual_x) until as much text is seen as possible
while (this.x + actual_x > 0 && w < style.maxWidth && w >= style.minWidth) {
actual_x -= 1;
w += 1;
// try turning off wordwrap and see if it still fits (as one line)
txt.wordWrap = false;
if (w > txt.textWidth + 4 + style.textPadding.left + style.textPadding.right && w >= style.minWidth && w <= style.maxWidth) {
w = txt.textWidth + 4 + style.textPadding.left + style.textPadding.right;
if (w < style.minWidth) {
w = style.minWidth;
}
break;
}
txt.wordWrap = true;
}
}
}
}
}
}
Using bitmap strokes and fills is now as easy as it is to use gradients. In this example, I create 2 perlin noise BitmapDatas and set them as stroke and fill of the tooltip:
var myStyle:TooltipStyle = new TooltipStyle();
myStyle.minWidth = 240;
myStyle.maxWidth = 0;
myStyle.offsetX = -10;
myStyle.offsetY = -10;
var myBitmap:BitmapData = new BitmapData(200, 100, false, 0x000000);
myBitmap.perlinNoise(200, 100, 3, 7, true, true);
var myBitmap2:BitmapData = new BitmapData(200, 100, false, 0x000000);
myBitmap2.perlinNoise(100, 100, 3, 11, true, true);
myStyle.backgroundRect = new BitmapRect(myBitmap, new Matrix(), true, true, [10, 10, 10, 10]);
myStyle.backgroundStroke = new BitmapStroke(2, myBitmap2, new Matrix(), true, true);
tooltip = new EasyTooltip(stage, stage.stageWidth, stage.stageHeight, 0);
tooltip.setStyle(myStyle);
tooltip.addListener(object1, "Test test test test test test test test test test test test test test test");
Thanks for reading!
The results:
Wednesday, February 4, 2015
Android beginner tutorial Part 69 Queries and Cursors
In this tutorial we will add our Content Provider to the Manifest xml and learn a bit about queries and cursors.
To make a Content Provider visible and usable by the system and your own application, we need to add it to the AndroidManifest.xml file of our project.
Add a new node provider to the application node, set values for two of its attributes - android:name and android:authorities. The name attribute points to the custom ContentProvider class, and the authorities value is the URI address of the provider:
To send SQL queries to the content provider from your application, use the ContentResolver object that is obtainable using getContentResolver() method.
For example, this way we can send a query that selects all names and phones of the people in our database.
The query() method, for instance, has 5 parameters. Those are the URI address of the provider, the projection (list of columns to return, if null - everything is returned), selection (what would normally be written after "WHERE" in an SQL command), selectionArgs (extra functionality for selection parameter) and sortOrder (what would normally be written after "ORDER BY").
The Cursor object thats returned to us is a helpful tool for navigating through the results of the query. It has a set of useful methods like moveToFirst(), moveToLast(), moveToNext(), moveToPrevious(), moveToPosition(), getToPosition() and more.
Since the Cursor lines up all the results in some sort of a row and moves back and forth displaying one at a time, there are a few methods that let us know where exactly the cursor is currently located. These methods are isFirst(), isLast(), isBeforeFirst() and isAfterLast().
The insert(), update() and delete() methods are also all called from the ContentResolver object, but they dont result any Cusors. They are even simpler commands that basically insert, update and delete rows in a table.
Thats all for today.
Thanks for reading!
Read more »
To make a Content Provider visible and usable by the system and your own application, we need to add it to the AndroidManifest.xml file of our project.
Add a new node provider to the application node, set values for two of its attributes - android:name and android:authorities. The name attribute points to the custom ContentProvider class, and the authorities value is the URI address of the provider:
<provider
android:name="com.kircode.codeforfood_test.myContentProvider"
android:authorities="com.kircode.codeforfood_test.contactprovider">
</provider>
To send SQL queries to the content provider from your application, use the ContentResolver object that is obtainable using getContentResolver() method.
For example, this way we can send a query that selects all names and phones of the people in our database.
String[] columns = new String[] {myDbHelper.NAME, myDbHelper.PHONE};
ContentResolver resolver = getContentResolver();
Cursor cursor = resolver.query(CONTENT_URI, columns, null, null, null);
The query() method, for instance, has 5 parameters. Those are the URI address of the provider, the projection (list of columns to return, if null - everything is returned), selection (what would normally be written after "WHERE" in an SQL command), selectionArgs (extra functionality for selection parameter) and sortOrder (what would normally be written after "ORDER BY").
The Cursor object thats returned to us is a helpful tool for navigating through the results of the query. It has a set of useful methods like moveToFirst(), moveToLast(), moveToNext(), moveToPrevious(), moveToPosition(), getToPosition() and more.
Since the Cursor lines up all the results in some sort of a row and moves back and forth displaying one at a time, there are a few methods that let us know where exactly the cursor is currently located. These methods are isFirst(), isLast(), isBeforeFirst() and isAfterLast().
The insert(), update() and delete() methods are also all called from the ContentResolver object, but they dont result any Cusors. They are even simpler commands that basically insert, update and delete rows in a table.
Thats all for today.
Thanks for reading!
Creating a Pentomino game using AS3 Part 38
Today we will add the ability to browse through the solutions.
Firstly declare a new variable - currentSol. Set its value to 0 by default. This variable represents the id of the solution that is currently displayed.
Open the project in Flash and go to fifth frame (the solutions screen). Add two buttons shaped like arrows with ids btn_prev and btn_next. Add a dynamic text field with id tSol, it will display which solutions is currently is shown.
Go to level_solver.as again and in the solve() function add CLICK event listeners for btn_prev and btn_next. Set handlers to goPrev and goNext functions:
The functions decrease/increase currentSol values and call updateCurrentInfo() function.
The same function is called in nextCycle():
The function updates what is displayed in the tSol text field, disables/enables arrow buttons when needed, draws the preview image:
Update the drawPreview() function so that cells are colored depending on the shape type:
Now we can browse through the solutions!
Full level_solver.as code:
Thanks for reading!
Read more »
Firstly declare a new variable - currentSol. Set its value to 0 by default. This variable represents the id of the solution that is currently displayed.
private var currentSol:int = 0;
Open the project in Flash and go to fifth frame (the solutions screen). Add two buttons shaped like arrows with ids btn_prev and btn_next. Add a dynamic text field with id tSol, it will display which solutions is currently is shown.
Go to level_solver.as again and in the solve() function add CLICK event listeners for btn_prev and btn_next. Set handlers to goPrev and goNext functions:
btn_prev.addEventListener(MouseEvent.CLICK, goPrev);
btn_next.addEventListener(MouseEvent.CLICK, goNext);
The functions decrease/increase currentSol values and call updateCurrentInfo() function.
private function goPrev(evt:MouseEvent):void {
currentSol--;
updateCurrentInfo();
}
private function goNext(evt:MouseEvent):void {
currentSol++;
updateCurrentInfo();
}
The same function is called in nextCycle():
private function nextCycle():void {
cycleNum++;
updateCurrentInfo();
if (cycleNum == givenShapes.length) {
removeEventListener(Event.ENTER_FRAME, onFrame);
// display info
tInfo.text = Finished solving " + levelName + "
Attempts: + attempts + "
Solutions: " + solutions.length;
}
}
The function updates what is displayed in the tSol text field, disables/enables arrow buttons when needed, draws the preview image:
private function updateCurrentInfo():void {
var sol:int = (solutions.length > 0)?(currentSol + 1):(0);
tSol.text = sol + "/" + solutions.length;
if (sol <= 1) {
btn_prev.alpha = 0.5;
btn_prev.mouseEnabled = false;
}else {
btn_prev.alpha = 1;
btn_prev.mouseEnabled = true;
}
if (sol == solutions.length) {
btn_next.alpha = 0.5;
btn_next.mouseEnabled = false;
}else {
btn_next.alpha = 1;
btn_next.mouseEnabled = true;
}
if (solutions.length > 0) drawPreview(levelPreview, solutions[currentSol]);
}
Update the drawPreview() function so that cells are colored depending on the shape type:
private function drawPreview(levelPreview:MovieClip, mapGrid:Array):void {
var columns:int = mapGrid[0].length;
var rows:int = mapGrid.length;
var frameWidth:int = levelPreview.width;
var frameHeight:int = levelPreview.height;
var padding:int = 5;
var fitWidth:int = levelPreview.width - (padding * 2);
var fitHeight:int = levelPreview.height - (padding * 2);
var gridStartX:int;
var gridStartY:int;
// calculate width of a cell:
var gridCellWidth:int = Math.round(fitWidth / columns);
var width:int = columns * gridCellWidth;
var height:int = rows * gridCellWidth;
// calculate side margin
gridStartX = (frameWidth - width) / 2;
if (height < fitHeight) {
gridStartY = (fitHeight - height) / 2;
}
if (height >= fitHeight) {
gridCellWidth = Math.round(fitHeight / rows);
height = rows * gridCellWidth;
width = columns * gridCellWidth;
gridStartY = (frameHeight - height) / 2;
gridStartX = (frameWidth - width) / 2;
}
// draw map
levelPreview.shape.x = gridStartX;
levelPreview.shape.y = gridStartY;
levelPreview.shape.graphics.clear();
var i:int;
var u:int;
for (i = 0; i < rows; i++) {
for (u = 0; u < columns; u++) {
if (mapGrid[i][u] == 1) drawCell(u, i, 0xffffff, 1, 0x999999, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 2) drawCell(u, i, 0xff66cc, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 3) drawCell(u, i, 0x00FF66, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 4) drawCell(u, i, 0x99ff00, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 5) drawCell(u, i, 0x00ccff, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 6) drawCell(u, i, 0xffcc66, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 7) drawCell(u, i, 0x66cc33, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 8) drawCell(u, i, 0x9900ff, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 9) drawCell(u, i, 0xff5858, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 10) drawCell(u, i, 0xff6600, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 11) drawCell(u, i, 0x00ffff, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 12) drawCell(u, i, 0xff6b20, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 13) drawCell(u, i, 0xffff66, 1, 0x000000, gridCellWidth, levelPreview.shape);
}
}
}
Now we can browse through the solutions!
Full level_solver.as code:
package
{
import fl.controls.TextInput;
import flash.display.MovieClip;
import flash.display.Shape;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.net.SharedObject;
import flash.text.TextField;
import flash.utils.ByteArray;
/**
* Open-source pentomino game engine
* @author Kirill Poletaev
*/
public class level_solver extends MovieClip
{
private var allCells:Array;
private var tempGrid:Array;
private var tempShapes:Array;
private var givenGrid:Array;
private var givenShapes:Array;
private var cycleNum:int;
private var attempts:int;
private var solutions:Array;
private var levelName:String;
private var shapeValues:Array;
private var currentSol:int = 0;
public function level_solver()
{
}
public function solve(levelItem:Object):void {
drawPreview(levelPreview, levelItem.grid);
tInfo.text = Solving level " + levelItem.name + ";
var shapes:Array = levelItem.shapes;
var i:int
var u:int;
givenShapes = [];
for (i = 1; i <= 12; i++) {
this["tShape" + i].text = shapes[i - 1];
for (u = 0; u < shapes[i - 1]; u++) {
givenShapes.push(i - 1);
}
}
allCells = [];
for (i = 0; i < levelItem.grid.length; i++) {
for (u = 0; u < levelItem.grid.length; u++) {
if (levelItem.grid[i][u] == 1) {
allCells.push(new Point(u, i));
}
}
}
givenGrid = levelItem.grid;
tempGrid = [];
tempShapes = [];
solutions = [];
levelName = levelItem.name;
attempts = 0;
cycleNum = 0;
shapeValues = [
[[0, 0], [0, 1], [0, 2], [0, -1], [0, -2]],
[[0, 0], [0, -1], [0, 1], [1, 0], [1, -1]],
[[0, 0], [0, 1], [0, 2], [0, -1], [ -1, -1]],
[[0, 0], [0, 1], [0, -1], [ -1, 0], [1, -1]],
[[0, 0], [ -1, 0], [ -2, 0], [0, -1], [1, -1]],
[[0, 0], [0, 1], [0, -1], [1, -1], [ -1, -1]],
[[0, 0], [1, 0], [ -1, 0], [1, -1], [ -1, -1]],
[[0, 0], [ -1, 0], [ -2, 0], [0, -1], [0, -2]],
[[0, 0], [0, 1], [ -1, 1], [1, 0], [1, -1]],
[[0, 0], [0, 1], [0, -1], [1, 0], [ -1, 0]],
[[0, 0], [ -1, 0], [ -2, 0], [1, 0], [0, -1]],
[[0, 0], [0, 1], [1, 1], [0, -1], [-1, -1]]
];
addEventListener(Event.ENTER_FRAME, onFrame);
btn_prev.addEventListener(MouseEvent.CLICK, goPrev);
btn_next.addEventListener(MouseEvent.CLICK, goNext);
}
private function onFrame(evt:Event):void {
// set temporary values
tempGrid = clone(givenGrid);
tempShapes = clone(givenShapes);
// perform a new cycle
var i:int;
var u:int;
var currentShapeValues:Array;
// Take the first shape in this cycle...
currentShapeValues = clone(shapeValues[tempShapes[cycleNum]]);
// ...try putting it in each available cell...
for (i = 0; i < allCells.length; i++) {
// ...try putting the shape in all 8 possible positions...
for (u = 0; u < 8; u++) {
// ...if successful, continue placing other cells...
if (canPut(currentShapeValues, allCells[i].x, allCells[i].y, tempGrid, u)) {
// ...first put the first shape on the grid...
putHere(currentShapeValues, allCells[i].x, allCells[i].y, tempGrid, u, tempShapes[cycleNum] + 2);
// ...try all remaining shapes...
tryRemainingShapes(tempShapes, tempGrid);
removeHere(currentShapeValues, allCells[i].x, allCells[i].y, tempGrid, u);
}
}
}
// ...remove it from shapes array (so that it isnt used twice)...
tempShapes.splice(cycleNum, 1);
// display info
tInfo.text = Solving level " + levelName + "
Attempts: + attempts + "
Solutions: " + solutions.length;
// next cycle
nextCycle();
}
private function tryRemainingShapes(tShapes:Array, tGrid:Array):void {
var innerTempShapes:Array = clone(tShapes);
var innerTempGrid:Array = clone(tGrid);
var e:int;
var t:int;
// ...take each remaining shape...
while (innerTempShapes.length > 0) {
var currentShapeValues:Array = clone(shapeValues[innerTempShapes[0]]);
// ...try putting it in each cell...
for (e = 0; e < allCells.length; e++) {
// ...rotate the shape...
if(hasSpace(innerTempGrid, allCells[e].x, allCells[e].y)){
for (t = 0; t < 8; t++) {
// ...check if it can be put...
if (canPut(currentShapeValues, allCells[e].x, allCells[e].y, innerTempGrid, t)) {
// ...on success, put this shape and try all remaining shapes...
putHere(currentShapeValues, allCells[e].x, allCells[e].y, innerTempGrid, t, innerTempShapes[0] + 2);
tryRemainingShapes(clone(innerTempShapes).splice(0, 1), innerTempGrid);
// ...if no empty cells remaining, then the puzzle is solved.
if (checkWin(innerTempGrid)) doWin(clone(innerTempGrid));
// ...step backwards...
removeHere(currentShapeValues, allCells[e].x, allCells[e].y, innerTempGrid, t);
}
}
}
}
// ...get rid of the shape and continue...
innerTempShapes.shift();
}
}
private function hasSpace(mapGrid:Array, cX:int, cY:int):Boolean {
if (mapGrid[cY][cX] != 1) return false;
return true;
}
private function checkWin(mapGrid:Array):Boolean {
var i:int;
var u:int;
var didWin:Boolean = true;
var width:int = mapGrid[0].length;
var height:int = mapGrid.length;
for (i = 0; i < height; i++) {
for (u = 0; u < width; u++) {
if (mapGrid[i][u] == 1) {didWin = false;}
}
}
return didWin;
}
private function doWin(grid:Array):void {
var exists:Boolean = false;
for (var i:int = 0; i < solutions.length; i++) {
if (compare(solutions[i], grid)) {
exists = true;
break;
}
}
if (!exists) solutions.push(grid);
}
private function compare(arr1:Array, arr2:Array):Boolean {
for (var i:int = 0; i < arr1.length; i++) {
for (var u:int = 0; u < arr1[i].length; u++){
if (arr1[i][u] != arr2[i][u]) {
return false;
break;
}
}
}
return true;
}
private function goPrev(evt:MouseEvent):void {
currentSol--;
updateCurrentInfo();
}
private function goNext(evt:MouseEvent):void {
currentSol++;
updateCurrentInfo();
}
private function updateCurrentInfo():void {
var sol:int = (solutions.length > 0)?(currentSol + 1):(0);
tSol.text = sol + "/" + solutions.length;
if (sol <= 1) {
btn_prev.alpha = 0.5;
btn_prev.mouseEnabled = false;
}else {
btn_prev.alpha = 1;
btn_prev.mouseEnabled = true;
}
if (sol == solutions.length) {
btn_next.alpha = 0.5;
btn_next.mouseEnabled = false;
}else {
btn_next.alpha = 1;
btn_next.mouseEnabled = true;
}
if (solutions.length > 0) drawPreview(levelPreview, solutions[currentSol]);
}
private function nextCycle():void {
cycleNum++;
updateCurrentInfo();
if (cycleNum == givenShapes.length) {
removeEventListener(Event.ENTER_FRAME, onFrame);
// display info
tInfo.text = Finished solving " + levelName + "
Attempts: + attempts + "
Solutions: " + solutions.length;
}
}
private function canPut(cValues:Array, cellX:int, cellY:int, mapGrid:Array, rotation:int):Boolean {
attempts++;
var canPutHere:Boolean = true;
var currentValues:Array = clone(cValues);
updateCurrentValues(currentValues, rotation);
for (var i:int = 0; i < currentValues.length; i++) {
var cX:int = currentValues[i][0] + cellX;
var cY:int = currentValues[i][1] + cellY;
if (cX < 0 || cY < 0 || cX >= mapGrid[0].length || cY >= mapGrid.length || mapGrid[cY][cX]!=1) {
canPutHere = false;
}
}
return canPutHere;
}
private function putHere(currentValues:Array, cellX:int, cellY:int, mapGrid:Array, rotation:int, shape:int):void {
currentValues = clone(currentValues);
updateCurrentValues(currentValues, rotation);
for (var i:int = 0; i < currentValues.length; i++) {
var cX:int = currentValues[i][0] + cellX;
var cY:int = currentValues[i][1] + cellY;
mapGrid[cY][cX] = shape;
}
}
private function removeHere(currentValues:Array, cellX:int, cellY:int, mapGrid:Array, rotation:int):void {
currentValues = clone(currentValues);
updateCurrentValues(currentValues, rotation);
for (var i:int = 0; i < currentValues.length; i++) {
var cX:int = currentValues[i][0] + cellX;
var cY:int = currentValues[i][1] + cellY;
mapGrid[cY][cX] = 1;
}
}
private function updateCurrentValues(currentValues:Array, rot:int):void{
for (var i:int = 0; i < 5; i++) {
// do nothing if rot == 0
if (rot == 1) {
currentValues[i].reverse();
currentValues[i][0] *= -1;
}
if (rot == 2) {
currentValues[i][0] *= -1;
currentValues[i][1] *= -1;
}
if (rot == 3) {
currentValues[i].reverse();
currentValues[i][1] *= -1;
}
if (rot == 4) {
currentValues[i][0] *= -1;
}
if (rot == 5) {
currentValues[i].reverse();
}
if (rot == 6) {
currentValues[i][1] *= -1;
}
if (rot == 7) {
currentValues[i].reverse();
currentValues[i][1] *= -1;
currentValues[i][0] *= -1;
}
}
}
private function clone(source:Object):*{
var myBA:ByteArray = new ByteArray();
myBA.writeObject(source);
myBA.position = 0;
return(myBA.readObject());
}
private function drawPreview(levelPreview:MovieClip, mapGrid:Array):void {
var columns:int = mapGrid[0].length;
var rows:int = mapGrid.length;
var frameWidth:int = levelPreview.width;
var frameHeight:int = levelPreview.height;
var padding:int = 5;
var fitWidth:int = levelPreview.width - (padding * 2);
var fitHeight:int = levelPreview.height - (padding * 2);
var gridStartX:int;
var gridStartY:int;
// calculate width of a cell:
var gridCellWidth:int = Math.round(fitWidth / columns);
var width:int = columns * gridCellWidth;
var height:int = rows * gridCellWidth;
// calculate side margin
gridStartX = (frameWidth - width) / 2;
if (height < fitHeight) {
gridStartY = (fitHeight - height) / 2;
}
if (height >= fitHeight) {
gridCellWidth = Math.round(fitHeight / rows);
height = rows * gridCellWidth;
width = columns * gridCellWidth;
gridStartY = (frameHeight - height) / 2;
gridStartX = (frameWidth - width) / 2;
}
// draw map
levelPreview.shape.x = gridStartX;
levelPreview.shape.y = gridStartY;
levelPreview.shape.graphics.clear();
var i:int;
var u:int;
for (i = 0; i < rows; i++) {
for (u = 0; u < columns; u++) {
if (mapGrid[i][u] == 1) drawCell(u, i, 0xffffff, 1, 0x999999, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 2) drawCell(u, i, 0xff66cc, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 3) drawCell(u, i, 0x00FF66, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 4) drawCell(u, i, 0x99ff00, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 5) drawCell(u, i, 0x00ccff, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 6) drawCell(u, i, 0xffcc66, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 7) drawCell(u, i, 0x66cc33, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 8) drawCell(u, i, 0x9900ff, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 9) drawCell(u, i, 0xff5858, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 10) drawCell(u, i, 0xff6600, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 11) drawCell(u, i, 0x00ffff, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 12) drawCell(u, i, 0xff6b20, 1, 0x000000, gridCellWidth, levelPreview.shape);
if (mapGrid[i][u] == 13) drawCell(u, i, 0xffff66, 1, 0x000000, gridCellWidth, levelPreview.shape);
}
}
}
private function drawCell(width:int, height:int, fill:uint, thick:Number, line:uint, gridCellWidth:int, gridShape:MovieClip):void {
gridShape.graphics.beginFill(fill);
gridShape.graphics.lineStyle(thick, line);
gridShape.graphics.drawRect(width * gridCellWidth, height * gridCellWidth, gridCellWidth, gridCellWidth);
}
}
}
Thanks for reading!
Subscribe to:
Posts (Atom)