domingo, 17 de abril de 2011

switching images on button control (pressed and released)


...
//create two bitmaps (pressed image and released image)
__pBitmapExit = img.DecodeN(btnExitPath,
BITMAP_PIXEL_FORMAT_ARGB8888);
TryReturn(GetLastResult()==E_SUCCESS,GetLastResult(),
GetErrorMessage(GetLastResult()));
__pBitmapExitPressed = img.DecodeN(btnExitPressedPath,
BITMAP_PIXEL_FORMAT_ARGB8888);
TryReturn(GetLastResult()==E_SUCCESS,GetLastResult(),
GetErrorMessage(GetLastResult()));
...
//get button control
__pButtonExit = static_cast<Button *>(GetControl(L"IDC_BUTTON2"));
if (__pButtonExit != null)
{
//Sets a normal background bitmap to this Button.
__pButtonExit->SetNormalBackgroundBitmap(*__pBitmapExit);
//Sets a pressed background bitmap to this Button
__pButtonExit->SetPressedBackgroundBitmap(*__pBitmapExitPressed);
__pButtonExit->SetActionId(ID_BUTTON2);
__pButtonExit->AddActionEventListener(*this);

} else {
r = E_FAILURE;
}


Thanks for your visit! :)

Next post:
Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

label with background?

Need to put a bitmap in your label control?


//create an image
Image img;
r = img.Construct();
TryReturn(r==E_SUCCESS ,r, GetErrorMessage(r));

//create a bitmap (background)
__pBitmapBg = img.DecodeN(bgPopupPath,BITMAP_PIXEL_FORMAT_ARGB8888);
TryReturn(GetLastResult()==E_SUCCESS,GetLastResult(),
GetErrorMessage(GetLastResult()));

//get label control
__pLabelMainTitle = static_cast


Thanks for your visit! :)

Next post: switching images on button control (pressed and released)
Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

segunda-feira, 21 de março de 2011

popup

According to BadaDev, Samsung Apps is not accepting applications which uses MessageBox, for three reasons:

1. Message box closes when user touchs out side it.
2. The button’s captions are in device’s language and not in the application’s language.
3. The Home hard button does not works while the MessageBox has focus.

All three issues relatives to MessageBox itself, but Samsung App Review Team does not care about it.

So, let's see how to work with Popup!

The Popup is an implementation of Window. It can have controls such as Buttons, Labels, and so on. However, the Popup cannot attach some controls such as Frames, MessageBoxes, Forms and another instance of a Popup.

The Popup is displayed in the center of top screen. The Show() method is responsible for displaying the popup and its children.

Example :



Now, lets see how to create a Popup:
Insert a Resource


Select Popup resolution


Create your popup... (UI - controls)


Now, you must create a Popup .cpp and .h file, to get Popup reference, as shown below:

/*
* Popup.h
*
* Created on: 11/04/2011
* Author: eao
*/

#ifndef POPUP_H_
#define POPUP_H_

#include
#include
#include
#include

#define bgPopupPath L"/Res/Images/Popup/image1.png"
#define btnExitPath L"/Res/Images/Popup/image2.png"
#define btnExitPressedPath L"/Res/Images/Popup/image3.png"
#define btnRunAgainPath L"/Res/Images/Popup/image4.png"
#define btnRunAgainPressedPath L"/Res/Images/Popup/image5.png"

class Popup:
public Osp::Ui::IActionEventListener,
public Osp::Ui::Controls::Popup
{
public:
Popup();
virtual ~Popup();
bool Initialize(void);

protected:
static const int ID_BUTTON1 = 120;
static const int ID_BUTTON2 = 121;
int intArgs;
Osp::Graphics::Bitmap * __pBitmapBg;
Osp::Graphics::Bitmap * __pBitmapMainLabel;
Osp::Graphics::Bitmap * __pBitmapExit;
Osp::Graphics::Bitmap * __pBitmapExitPressed;
Osp::Graphics::Bitmap * __pBitmapRun;
Osp::Graphics::Bitmap * __pBitmapRunPressed;
Osp::Ui::Controls::Button * __pButtonExit;
Osp::Ui::Controls::Button * __pButtonRunAgain;
Osp::Ui::Controls::Label * __pLabelMainTitle;

//implementation
public:
virtual void OnActionPerformed(const Osp::Ui::Control& source,
int actionId);
};

#endif /* POPUP */



/*
* Popup.cpp
*
* Created on: 11/04/2011
* Author: eao
*/

#include "FormMgr.h"
#include "Popup.h"
#include "Utilities.h"

using namespace Osp::Base;
using namespace Osp::App;
using namespace Osp::Ui;
using namespace Osp::Ui::Controls;
using namespace Osp::Base::Collection;
using namespace Osp::Media;
using namespace Osp::Graphics;

Popup::Popup() {
__pBitmapBg = null;
__pBitmapMainLabel = null;
__pBitmapExit = null;
__pBitmapExitPressed = null;
__pBitmapRun = null;
__pBitmapRunPressed = null;
__pLabelMainTitle = null;

}

Popup::~Popup() {
delete __pBitmapBg;
__pBitmapBg = null;

delete __pBitmapMainLabel;
__pBitmapMainLabel = null;

delete __pBitmapExit;
__pBitmapExit = null;

delete __pBitmapExitPressed;
__pBitmapExitPressed = null;

delete __pBitmapRun;
__pBitmapRun = null;

delete __pBitmapRunPressed;
__pBitmapRunPressed = null;

}


bool
Popup::Initialize()
{
result r = E_SUCCESS;
// Construct an XML form
//THIS POPUP NAME MUST BE SET IN POPUP PROPERTIES (UI Builder)
r = Construct(L"IDP_POPUP1");
if (r != E_SUCCESS)
{
SetLastResult(r);
}

//loading bitmaps
Image img;
r = img.Construct();
TryReturn(r==E_SUCCESS ,r, GetErrorMessage(r));

__pBitmapBg = img.DecodeN(bgPopupPath,BITMAP_PIXEL_FORMAT_ARGB8888);
TryReturn(GetLastResult()==E_SUCCESS,GetLastResult(),
GetErrorMessage(GetLastResult()));

__pBitmapExit = img.DecodeN(btnExitPath, BITMAP_PIXEL_FORMAT_ARGB8888);
TryReturn(GetLastResult()==E_SUCCESS,GetLastResult(),
GetErrorMessage(GetLastResult()));
__pBitmapExitPressed = img.DecodeN(btnExitPressedPath,
BITMAP_PIXEL_FORMAT_ARGB8888);
TryReturn(GetLastResult()==E_SUCCESS,GetLastResult(),
GetErrorMessage(GetLastResult()));
__pBitmapRun = img.DecodeN(btnRunAgainPath,
BITMAP_PIXEL_FORMAT_ARGB8888);
TryReturn(GetLastResult()==E_SUCCESS,GetLastResult(),
GetErrorMessage(GetLastResult()));
__pBitmapRunPressed = img.DecodeN(btnRunAgainPressedPath,
BITMAP_PIXEL_FORMAT_ARGB8888);
TryReturn(GetLastResult()==E_SUCCESS,GetLastResult(),
GetErrorMessage(GetLastResult()));

//set a popup background
__pLabelMainTitle = static_cast<Label *>(GetControl(L"IDC_LABEL1"));
if(null!=__pLabelMainTitle){
__pBitmapMainLabel = new Bitmap();
__pBitmapMainLabel->Construct(*__pBitmapBg,
__pLabelMainTitle->GetBounds());
__pLabelMainTitle->SetBackgroundBitmap(*__pBitmapMainLabel);
}

__pButtonExit = static_cast<Button *>(GetControl(L"IDC_BUTTON2"));
if (__pButtonExit != null)
{
//set an image for button2
__pButtonExit->SetNormalBackgroundBitmap(*__pBitmapExit);
//set an image for pressed button 2
__pButtonExit->SetPressedBackgroundBitmap(*__pBitmapExitPressed);
__pButtonExit->SetActionId(ID_BUTTON2);
__pButtonExit->AddActionEventListener(*this);

} else {
r = E_FAILURE;
}

__pButtonRunAgain = static_cast<Button *>(GetControl(L"IDC_BUTTON1"));
if (__pButtonRunAgain != null)
{
//set an image for button 1
__pButtonRunAgain->SetNormalBackgroundBitmap(*__pBitmapRun);
//set an image for pressed button 1
__pButtonRunAgain->SetPressedBackgroundBitmap(*__pBitmapRunPressed);
__pButtonRunAgain ->SetActionId(ID_BUTTON1);
__pButtonRunAgain ->AddActionEventListener(*this);
} else {
r = E_FAILURE;
}

return r == E_SUCCESS;
}

//popup control (buttons)
void
Popup::OnActionPerformed(const Osp::Ui::Control& source, int actionId)
{
FormMgr *pFormMgr = null;
Frame *pFrame = null;
ArrayList * runOption = new ArrayList;
runOption->Construct(1);
String freeTimeName = __REGISTRY_SECTION_FREETIME_NAME;
String obstacleTimeName = __REGISTRY_SECTION_OBSTACLETIME_NAME;
switch(actionId)
{
case ID_BUTTON1:
{
pFrame = Application::GetInstance()->GetAppFrame()->GetFrame();
if (null != pFrame) {
pFormMgr = static_cast<FormMgr *> (pFrame->GetControl("FormMgr"));
}
if (null != pFormMgr) {
runOption->Add(*(new Integer(intArgs)));
pFormMgr->SendUserEvent(FormMgr::REQUEST_SECONDFORM, runOption);
}
break;
}
case ID_BUTTON2:
{
pFrame = Application::GetInstance()->GetAppFrame()->GetFrame();
if(null != pFrame)
{
FormRace *pFormRace = dynamic_cast<FormRace *> (pFrame->
GetCurrentForm());
if(null != pFormRace){
pFormRace->ContinueChronoTime(true,false, false);
}
}
//hide popup
this->SetShowState(false);
this->RequestRedraw(true);
break;
}

default:
break;
}
}



Note that this popup example has two buttons and one label, as presented in .cpp and .h code.


To see your popup... you must create an instance and call setshowstate and show functions, as shown below:

YourClass.cpp

result r = E_SUCCESS;
__pPopup = new Popup();
if(!__pPopup->Initialize()){
r = E_FAILURE;
}

r = __pPopup->SetShowState(true);
TryCatch(r == E_SUCCESS, , GetErrorMessage(r));
r = __pPopup->Show();
TryCatch(r == E_SUCCESS, , GetErrorMessage(r));


Thanks for your visit! :)

Next post: label with background?
Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

domingo, 20 de março de 2011

timer

Today we will see how to use Osp::Base::Runtime::Timer

This class can activate the timer and notify the listeners.
This timer class is not a periodic timer, only a one-shot timer. If you want to carry out periodic tasks, you must start it again after it has fired.

It's easy to use Timers in your app... lets see:

You must extend and construct your Timer

Extend (.h):
public Osp::Base::Runtime::ITimerEventListener


Construct(.cpp):

__pTimer = new Timer();
r = __pTimer->Construct(*this);
r = __pTimer->Start(1000);


Implement OnTimerExpired (to start again your Timer), as shown below:

void
MyApp::OnTimerExpired(Timer& timer)
{

...

timer.Start(1000);
}



Full example:

class MyApp
: public ITimerEventListener
{
...
public:
result InitTimer();
public:
void OnTimerExpired(Timer& timer);
};

void
MyApp::OnTimerExpired(Timer& timer)
{

...

timer.Start(1000);
}


result
MyApp::InitTimer()
{
result r = E_SUCCESS;

__pTimer = new Timer;

r = __pTimer->Construct(*this);
if (IsFailed(r))
{
goto CATCH;
}

__pTimer->Start(1000);
if (IsFailed(r))
{
goto CATCH;
}

return r;
CATCH:
return r;
}



A real example - implementing a bada Chronometer:
Construct:

keepRunning = true;
//get actual time and set as initial time when form is loaded.
SystemTime::GetTicks(initialTime);
__pTimer = new Timer();
r = __pTimer->Construct(*this);
r = __pTimer->Start(1000);

void
MyApp::Cronometer(){
completeTime = "00:00:00";
int diff, hour, minutes, seconds;
String hourTxt, minutesTxt, secondsTxt;
if(keepRunning){
SystemTime::GetTicks(currentTime);
//get actual time to make diff with initial time
diff = (currentTime - initialTime);

hour = Math::Floor((diff/1000)/60/60);
minutes = Math::Floor((diff/1000)/60);
seconds = Math::Floor((diff/1000)%60);
if (seconds <= 9){
secondsTxt = "0" + LongLong::ToString(seconds);
}else if(seconds == 60){
secondsTxt = "00";
minutes++;
}else{
secondsTxt = LongLong::ToString(seconds%60);
}

if (minutes <= 9){
minutesTxt = "0" + LongLong::ToString(minutes);
}else if(minutes == 60){
minutesTxt = "00";
hour++;
}else{
minutesTxt = LongLong::ToString(minutes%60);
}

if (hour <= 9){
hourTxt = "0" + LongLong::ToString(hour);
}else if(hour == 24){
hourTxt = "00";
}else{
hourTxt = LongLong::ToString(hour%24);
}

completeTime = hourTxt + ":"+ minutesTxt + ":"+ secondsTxt;

Label *lblChrono = static_cast


Thanks for your visit! :)

Next post: Popup

Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

sábado, 12 de março de 2011

bada 2.0



Samsung Bada 2.0 OS new features will include following updates:
HTML5, multitasking, FlashLite 4, Text-To-Speech, Push Notification, Near-Field Communication, Open AL and many more.

More information here.

Thanks for your visit! :)

Next post: Timer

Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

sexta-feira, 11 de março de 2011

registry

Osp::Io::Registry Class Reference

This class provides a mechanism to access the registry file. Registry consists of several sections and each section can have several entries, but only to a single depth. An entry consists of a name-value pair. The entry name must be unique inside the same section. The entry value must be one of the following data types: int, double, float, String, UuId, ByteBuffer.


Registry is an easy way to persist data.

To persist your data, you must create a section and add a value, as shown below:

//Osp::Io::Registry::Registry(void)
Osp::Io::Registry* pReg = new Osp::Io::Registry();
String regPath(L"regTest.ini");
result r = pReg->Construct(regPath, true);
TryCatch(r == E_SUCCESS, , "Failed to get a valid Registry. %s",
GetErrorMessage(r));

//create a section (data types: int, double, float, String,
//UuId, ByteBuffer)
r = pReg->AddSection(section);
TryCatch(r == E_SUCCESS, , "Failed to add the record section. %s",
GetErrorMessage(r));

//add a value to created section
//result AddValue (const Osp::Base::String §ionName,
//const Osp::Base::String &entryName,
//const Osp::Base::String &value)
//example: entryRecord = key, record = value
r = pReg->AddValue(section, entryRecord, record);
TryCatch(r == E_SUCCESS, , "Failed to add the record entry. %s",
GetErrorMessage(r));

//Writes the current contents of a registry in memory to
//the non-volatile storage.
r = pReg->Flush();
TryCatch(r == E_SUCCESS, , "Failed to save registry changes. %s",
GetErrorMessage(r));
}

return;

CATCH:
SetLastResult(r);
if(pReg != null){
delete pReg;
pReg = null;
}


If you need to recover registered data:

//result GetValue (const Osp::Base::String §ionName,
//const Osp::Base::String &entryName,
//Osp::Base::ByteBuffer &retVal) const

//result GetValue (const Osp::Base::String §ionName,
//const Osp::Base::String &entryName,
//Osp::Base::UuId &retVal) const

//result GetValue (const Osp::Base::String §ionName,
//const Osp::Base::String &entryName,
//Osp::Base::String &retVal) const

//result GetValue (const Osp::Base::String §ionName,
//const Osp::Base::String &entryName, float &retVal) const

//result GetValue (const Osp::Base::String §ionName,
//const Osp::Base::String &entryName, double &retVal) const

//result GetValue (const Osp::Base::String §ionName,
//const Osp::Base::String &entryName, int &retVal) const
r = pReg->GetValue(section, key, value);
TryCatch(r == E_SUCCESS, , "Failed to get the record from
the registry. %s", GetErrorMessage(r));

If you need to check if a section already exists:

bool
RegistryUtils::ContainsSection(Osp::Io::Registry& reg,
Osp::Base::String& section)
{
bool containsKey = false;
Osp::Base::Collection::IList* pList = reg.GetAllSectionNamesN();
Osp::Base::String* pSection = null;
for(int index = 0; index < pList->GetCount(); index++)
{
pSection = (Osp::Base::String*)pList->GetAt(index);
if(section.Equals(*(pSection), false))
{
containsKey = true;
break;
}
}


If you need more info (API, code examples, ...), try Osp::Io::Registry Class Reference.

You can see registry file in: \Model\WaveWQ_LP1\Simulator\FS\Win32FS\Osp\Applications\ or Wave_LP1 in case of 400x800 device resolution.

Thanks for your visit! :)

Next post: bada 2.0

Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

bada i18n

Today we'll learn how to internationalize our bada apps.

i18n = internationalization - means of adapting computer software to different languages, regional differences and technical requirements of a target market. Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. The terms are frequently abbreviated to the numeronyms i18n (where 18 stands for the number of letters between the first i and last n in internationalization, a usage coined at DEC in the 1970s or 80s).



8 steps to internationalize our bada apps:


Figure 1. Resource view: Double click in String table (as shown)



Figure 2. String view will be opened



Figure 3. Right click and choose Language Setting. Here you'll select the languages that your app will give support.



Figure 4. Add the languages that your app will give support



Figure 5. String table view will be updated with selected languages



Figure 6. Right click and choose "insert" to fill the table with internationalized content. I suggest you to use IDs with some pattern name. Example: IDS_CLASSNAME_VARIABLENAME



Figure 7. String table with a content example



Figure 8. You can just associate the contents, created in String tables, with any control (labels, buttons, ...)


If you need to internationalize any text that will not be constructed directly in any Form or Popup, you must insert the ID and content in String table and you can associate the created content to any control through code, as shown below:


...
//get controls
Label *lblContent = static_cast


You can change emulator language and test your bada i18n...

Thanks for your visit! :)

Next post: Registry

Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

segunda-feira, 21 de fevereiro de 2011

c.e.s.a.r internship bada apps

I am very proud to show you our available apps in SamsungApps Store (much more coming soon):

[UK]
1. Color It
2. Tangram
3. Quick Recipe
4. Dot to Dot
5. Zodiac
6. Kanjis
7. RSS Pocket
8. Appetizer bowl
9. Ballon Art
10. Trip$
11. Timetable for Children
12. My Kite
13. Chess Adventure
14. Namasté
15. My Name
16. Crazy Horn
17. Magnit


[Brazil]
1. Minha Pipa
2. Agenda dos Filhos
3. Pintando o 7
4. Receita Rapida
5. Liga Pontos
6. Kanjis
7. Zodiac
8. Petisqueira
9. Balão Arte
10. Guia Aereo
11. Viagens
12. Desafio Xadrez
13. Meu Nome
14. Namasté
15. Magnit
16. Tangram
17. RSS Pocket

Highlights
My Kite and Timetable for Children
Tangram
RSS Pocket

RSS Pocket [PT]
Agenda dos Filhos e Minha Pipa [PT]

All of these apps are FREE and available in English/Spanish/Portuguese! Enjoy! :)


Thanks for your visit! :)

Next post: bada i18n

Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

OnDraw (void);

Do you want to present images on your screen?

Lets see a simple code example:


void
FormMain::showImage(){
result r = E_SUCCESS;
// img
Image* pImg = null;
//path to your img
this->__imgPath = "/Res/Images/pista.png";

pImg = new Image();
r = pImg->Construct();
TryCatch(r == E_SUCCESS, , GetErrorMessage(r));
//Create a Bitmap == Osp::Graphics::Bitmap * __pBitmap1;
this->__pBitmap1 = pImg->DecodeN(this->__imgPath,
BITMAP_PIXEL_FORMAT_ARGB8888);
r = GetLastResult();
TryCatch(null != __pBitmap1 && r == E_SUCCESS,
,GetErrorMessage(r));

return;

CATCH:
SetLastResult(r);
AppLog("[%s] - Failed to initialize an instance of Image",
GetErrorMessage(r));

if (pImg != null) {
delete pImg;
pImg = null;
}
return;
}

If you need to present your image in other Form, you must overload OnDraw function.
OnDraw(void) is called when container needs to draw itself. Users can override this method to display user-specific drawings. This method is called after the container has drawn itself, but just before the container draws its child controls.


Thanks for your visit! :)

Next post: C.E.S.A.R Internship bada apps

Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

quinta-feira, 3 de fevereiro de 2011

form manager - how to switch forms in bada apps (part 2)

As we've learned, FormMgr is another Form in the application responsible for Forms management. The FormMgr just change screens in bada. FormMgr don't present labels, images, etc...

Steps:
1. create your Forms (Forms that app needs);



In this post I will just send an information from one Form to another (easiest way).
Note that in Forms properties you must set Form name, Labels name, Editfields names, ...

2. update application class to start with FormMgr (and not with FormMain)

bool
FormManagerSample::OnAppInitializing(AppRegistry& appRegistry)
{
result r = E_SUCCESS;
FormMgr *pFormMgr = new FormMgr();
if(pFormMgr->Initialize())
{
r = Application::GetInstance()->GetAppFrame()
->GetFrame()->AddControl(*pFormMgr);
TryCatch(r == E_SUCCESS, , GetErrorMessage(r));
pFormMgr->SetStarterForm(FormMgr::REQUEST_MAINFORM,
null);
}

return true;

CATCH:
SetLastResult(r);//we'll see this soon, in next posts
return false;
}


3. create FormMgr.cpp and FormMgr.h
Now, let's see FormMgr code...
FormMgr.h>>

#ifndef _FORMMGR_H_
#define _FORMMGR_H_

#include
#include
#include
#include
#include
#include

class FormMgr :
public Osp::Ui::Controls::Form //derived from Form;
{
public:
FormMgr(void);
virtual ~FormMgr(void);

public:
bool Initialize(void);
bool SetStarterForm(RequestId requestId,
Osp::Base::Collection::IList* pArgs);
static const RequestId REQUEST_MAINFORM = 100; //Form 1
static const RequestId REQUEST_RESULTFORM = 101; //Form 2

protected:
void SwitchToForm(RequestId requestId,
Osp::Base::Collection::IList* pArgs);
Osp::Ui::Controls::Form *__pPreviousForm;
FormMain* __pMainForm; //Main Form - will send the data
FormResult* __pResultForm; //Result Form - will receive the data

public:
virtual void OnUserEventReceivedN(RequestId requestId,
Osp::Base::Collection::IList* pArgs);
};

#endif


FormMgr.cpp>>

#include "FormMgr.h"
#include "FormMain.h"
#include
#include "FormResult.h"

using namespace Osp::App;
using namespace Osp::Base;
using namespace Osp::Ui;
using namespace Osp::Ui::Controls;

FormMgr::FormMgr(void)
{
__pPreviousForm = null;
__pMainForm = null;
__pResultForm = null;
}

FormMgr::~FormMgr(void)
{
}

bool
FormMgr::Initialize(void)
{
result r = E_SUCCESS;
//FormMgr must be constructed...
r = Form::Construct(FORM_STYLE_NORMAL);
if (r != E_SUCCESS)
{
SetLastResult(r);
}else{
//and you must set a name!
SetName(L"FormMgr");
}
return r == E_SUCCESS;
}

bool FormMgr::SetStarterForm(RequestId requestId,
Osp::Base::Collection::IList* pArgs)
{
Form *pCurrentForm = Application::GetInstance()->GetAppFrame()
->GetFrame()->GetCurrentForm();

if (pCurrentForm == this)
SwitchToForm(requestId, pArgs);
else
return false;

return true;
}

void FormMgr::OnUserEventReceivedN(RequestId requestId,
Osp::Base::Collection::IList* pArgs)
{
SwitchToForm(requestId, pArgs);
}

void FormMgr::SwitchToForm(RequestId requestId,
Osp::Base::Collection::IList* pArgs)
{
result r = E_SUCCESS;
Frame *pFrame = Application::GetInstance()
->GetAppFrame()->GetFrame();
//BaseForm is adopted to facilitate a large number of Forms...
BaseForm* pBaseForm = null;

switch (requestId)
{
//MAIN FORM
case REQUEST_MAINFORM:
{
if (null == __pMainForm)
{
__pMainForm = new FormMain();
if(!__pMainForm->Initialize())
{
TryCatch(false, , GetErrorMessage(r));
}
r = pFrame->AddControl(*__pMainForm);
TryCatch(r == E_SUCCESS, , GetErrorMessage(r));
}
r = pFrame->SetCurrentForm(*__pMainForm);
TryCatch(r == E_SUCCESS, , GetErrorMessage(r));
__pMainForm->RequestRedraw(true);
if (__pPreviousForm != null) {
if (__pPreviousForm != __pMainForm)
pFrame->RemoveControl(*__pPreviousForm);
}
__pPreviousForm = __pMainForm;
break;
}
//RESULT FORM
case REQUEST_RESULTFORM:
{
FormResult* formResult = new FormResult();
if (formResult->Initialize()) {
//Passing parameters from FORMMAIN to FORMRESULT
formResult->ShowResult(pArgs);
//BaseForm is now a FormResult
pBaseForm = formResult;
}
break;
}
default:
break;
}

if (null != pBaseForm) {
//It can be used for a large number of Forms
r = pFrame->AddControl(*pBaseForm);
TryCatch(r == E_SUCCESS, , GetErrorMessage(r));
r = pFrame->SetCurrentForm(*pBaseForm);
TryCatch(r == E_SUCCESS, , GetErrorMessage(r));
pBaseForm->RequestRedraw(true);
}

if (__pPreviousForm != null) {
if (__pPreviousForm != __pMainForm)
pFrame->RemoveControl(*__pPreviousForm);
}
__pPreviousForm = pBaseForm;


if (null != pArgs) {
pArgs->RemoveAll(true);
delete pArgs;
pArgs = null;
}

return;
CATCH:
//Avoid Memory Leak
SetLastResult(r);
if(null != __pMainForm)
{
delete __pMainForm;
__pMainForm = null;
}
if(null != pBaseForm)
{
delete pBaseForm;
pBaseForm = null;
}
return;
}


4. Link FormMgr and new Forms...
Ok, we know how to update application class to call FormMgr, understood FormMgr... Now, lets see how to call FormMgr to switch the Forms and how to receive Args.

From FormMain to FormResult: sending and presenting data texts...
FormMain.cpp>>

void
FormMain::OnActionPerformed(const Osp::Ui::Control& source,
int actionId)
{
FormMgr *pFormMgr = null;
Frame *pFrame = null;

switch(actionId)
{
//If Button OK is clicked
case ID_BUTTON_OK:
{

//Get editField control
EditField * editField = static_cast(GetControl(L"IDC_EDITFIELD1"));
//Get editField content
String* strData = new String(editField->GetText());
ArrayList * list = new ArrayList;
list->Construct(1);
list->Add(*strData);
//Get Frame Instance
pFrame = Application::GetInstance()->GetAppFrame()->GetFrame();
if(null != pFrame)
{
//Get FormMgr Control
pFormMgr = static_cast (pFrame->GetControl("FormMgr"));
}
if (null != pFormMgr)
//Send an user event to FormMgr: note that
//you must say the Form to be presented and the Args.
//In this example, FormMgr will consider
//REQUEST_RESULTFORM switch case.
pFormMgr->SendUserEvent(FormMgr::REQUEST_RESULTFORM, list);
break;
}
default:
break;
}
}


After sending... this parameters will be considered in void FormMgr::SwitchToForm(RequestId requestId, Osp::Base::Collection::IList* pArgs) function.

To receive the parameters, lets see FormResult example:
FormResult>>

void
FormResult::ShowResult(Osp::Base::Collection::IList * pArgs)
{
String * strResultFromFormMain = static_cast<String*>
(pArgs->GetAt(0));
Label * lblResultado = static_cast<Label *>
(GetControl(L"IDC_LABEL1"));
lblResultado->SetText(*strResultFromFormMain);
}


This example is available HERE!

Thanks for your visit! :)

Next post: OnDraw(void);

Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

form manager - how to switch forms in bada apps (part 1)

In general, I don't like large posts, but I'm intending to facilitate things here :)
Form Manager will be detailed in two posts :)

We've seen a lot of bada concepts, bada environment, bada tools, bada docs and we've seen a first bada app.

Now, let's see how to switch forms in bada...

What are Forms?

The Form provides the top level container with an indicator bar, soft key, and title bar. It is attached to a Frame. The Frame provides the main window for an application. There can be only 1 frame, however we can have a lot of forms in bada.

As your applications become more complex, it won't be enough to have one form only.

Let's start creating a new Form Manager Sample Code...

As we know, we must create a bada Form Based Project





And after these steps, we'll see our project in workspace.


If you ckeck the code into the header (FormMain.h) you'll see the declaration of the form's class.

class FormMain :
public Osp::Ui::Controls::Form,
public Osp::Ui::IActionEventListener
{


Every Form are derived from Osp::Ui::Controls::Form.

The Form is created in FormMain.cpp, on Initialize() function.

bool
FormMain::Initialize()
{
// Construct an XML form
Construct(L"IDF_FORMMAIN");

return true;
}

Note that the construct parameter refers to Form name, that could be updated in Form properties, as shown below.



Once you have your form’s class ready, you will need to show it somehow to the user. For such purposes we have to go to the application's class. The FormMain.cpp, in this example, is not the main class of the project so it must be explicity initialized. When we create a bada project, the class that has the exact name of the project is the main class of the project (application class). In this example, FormManagerSample is the application class.

In FormManagerSample.cpp, you can find a callback function which is called on application’s start: OnAppInitializing()

bool
FormManagerSample::OnAppInitializing(AppRegistry& appRegistry)
{

// TODO:
// Initialize UI resources and application
// specific data.
// The application's permanent data and context
//can be obtained from the appRegistry.
//
// If this method is successful, return true;
//otherwise, return false.
// If this method returns false, the application
// will be terminated.

// Uncomment the following statement to listen to
//the screen on/off events.
//PowerManager::SetScreenEventListener(*this);

// Create a form
FormMain *pFormMain = new FormMain();
pFormMain->Initialize();


// Add the form to the frame
Frame *pFrame = GetAppFrame()->GetFrame();
pFrame->AddControl(*pFormMain);

// Set the current form
pFrame->SetCurrentForm(*pFormMain);

// Draw and Show the form
pFormMain->Draw();
pFormMain->Show();

return true;
}


And... if you need a lot of Forms (screens)?
Bada suggests FormMgr (code is available in SDK_FOLDER\workspace\UiControls\src\FormMgr.cpp). You can just add UiControls project to your workspace by accessing "bada SDK Samples" view (as shown here).

What is FormMgr?
Another Form in the application responsible for Forms management. The FormMgr just change screens in bada. FormMgr don't present labels, images, etc...

Let's better understand FormMgr in next post!

Thanks for your visit! :)

Next post: Form Manager - how to switch forms in bada apps (part 2)

Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

segunda-feira, 31 de janeiro de 2011

how to enable usb debugging on your bada phone

Quick steps:

1. Install device driver (example: SDK_FOLDER\Tools\Wave-Driver-V5_02_0_0\Setup.exe for Wave or
SDK_FOLDER\Tools\WaveWQ-Driver-V4_50_7_1 for others);
2. Turn on "Mass storage" on your device (just plug your USB cable and you'll be asked);
3. Copy rootCACert into a device folder that you could find later (rootCACert location: SDK_FOLDER\Tools\sbuild\rootCACert.cer);
4. Install the certificate on mobile phone;
5. Build your Eclipse project as Target Debug (with device connected via USB);
6. Turn on "USB debugging" on your device (just plug your USB cable and you'll be asked);
7. Run your project as "bada Target Application";

That's it :)

Thanks for your visit! :)

Next post: Form Manager - How to change screens in bada apps

Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

creating our first bada app!

Let's create our first bada app...

1. Open your bada SDK and create a bada project as shown in Fig. 1

Figure 1. Creating your bada project


2.Select "bada Form Based Application" and give a project name, as shown in Fig. 2

Figure 2. Give a name to your bada project


3. Device Configurations is default... you can just click next button, as presented in Fig. 3. For manifest.xml details, click here and select Generate a New Application Profile link.

Figure 3. Device Configurations


4. Select bada SDK and language package, as shown in Fig. 4

Figure 4. bada SDK


5. As you created a bada Form Based App, now you must give a name to your Form, as shown in Fig 5.

Figure 5. Give a name to your Form


6. Select your device screen size, as presented in Fig. 6. You must select the resolution based on the device that you are intended to emulate. Samsung Wave has 480x800 resolution. The form will be created based on this size.

Figure 6. Auto-scaling Settings


7. Fill the basic settings... as shown in Fig. 7

Figure 7. Basic Settings


8. Select the configurations in which you want to deploy, as presented in Fig. 8. I suggest you to select all the options. Let's better understand each one:
Simulator-Debug: Emulate your app on windows;
Target-Debug: Allows you to debug your app in the device;
Target-Release: Compiles your code to be released in Samsung Apps (AppLog is disabled in this option).

Figure 8. Select Configurations


9. The next screen presents to you a project summary (Fig. 9)

Figure 9. Summary


10. Now, you're ready to start developing. Your project was created, as shown in Fig. 10

Figure 10. bada project


If you want to run your default app, you must select your build option, as presented ing Fig. 11. To emulate in Windows, choose Simulator-Debug option.

Figure 11. bada build


Now, you can run your app, as shown in Fig. 12

Figure 12. Running your first bada app


In this example, we've selected 240x400 resolution, so we've got a Samsung Scotia skin while emulating (Fig. 13). Note that the FORM was created in 240x400 folder.
If you need to edit the Form you must always edit the Form in Resource view. Don't try to edit the xml file (you can get serious problems).

Figure 13. Scotia emulation (240x400 screen size)


You can see some emulation options, such as Event Injector, right clicking over the device skin, as shown in Fig 14.

Figure 14. Emulation options



Now, a very important tip for you.
Interested in bada sample codes?
In the IDE, select the "bada SDK Samples" view (Fig. 15 and Fig. 16). You'll see a lot of sample codes.
Double-click and the project will be available into your workspace. Enjoy the codes :)


Figure 15. Select other views...



Figure 16. Select bada SDK Samples


Today we've configured our first bada project!
Now, we're ready to start seeing bada codes :)


Thanks for your visit! :)

Next post: How to enable USB debugging on your bada phone

Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

quarta-feira, 26 de janeiro de 2011

let's get it started (bada)...

The main idea here is to do something simple, just to help you to start developing for mobile technologies. I will present you concepts, tools, good practices, code solutions, etc...

Feel free to contact if you need any help :)

Why bada?
- I've worked with for 6 months (C.E.S.A.R / Samsung Internship)
- I got involved in the development of more than 50 Bada apps for Samsung;
- Excellent support (docs, forum, tutorials);
- Wide acceptance in the market;
- bada Ecosystem - Samsung App Store;

What is bada?

Samsung bada is a smartphone platform released in 2010. The word "bada" means "ocean" in Korean. Samsung Wave is the first bada-powered phone.
According to Samsung, for developers, bada will bring a new blue ocean of mobile applications. For customers, they will have a wider choice of smartphones with cost-effective yet powerful bada-powered phones.


How Samsung see bada

The vision of bada is "Smartphone for Everyone". bada's main goal is not to compete with other existing smartphone platforms. Instead, bada will turn Samsung’s conventional customers into smartphone users by providing cost-effective smartphones. This means that bada will open and extend a new smartphone market, which does not exist in the current mobile market.


bada will create a new smartphone market, which will turn into a new blue ocean




Samsung bada OS presentation


Ecosystem Support

To help customers and developers, bada provides well-made ecosystem support. Samsung bada provides an application store, developer support systems with useful information, and a developer-friendly certification process.


For more information: Samsung App Store.

How do you configure your development environment?

I've worked with:

- bada SDK v1.2.1.
The bada SDK installation also contains the bada IDE.
Before installing the SDK, make sure that your computer fulfills the system requirements and that the required software has been installed.
* Microsoft Windows® XP, Windows® Vista or Windows® 7 operating system.
* At least 1.4 GB of RAM memory.
* At least 1.8 GB of free disk space.
* Local administrator rights.
* The bada Simulator screen size is 480 * 800. If the screen resolution of your computer monitor is under 800, the Simulator does not show normally for applications that use OpenGL®.

NOTE: For devices with 240x400 screen size (example: Samsung Wave 525), we've worked with SDK v1.1.0 because of the skins support.

More details: here

References

- Tutorials available in SDK\Documents\Tutorial folder.
- Developer bada Site
- BadaDev

- An Introduction to Bada: A Developer's Guide

- Introduction to Bada (part 1)
- Introduction to Bada (part 2)
- Introduction to Bada (part 3)

- C++ Reference

Thanks for your visit! :)

Next post: Creating our first bada app!

Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

domingo, 23 de janeiro de 2011

data persistence

Hello! :)

In this post we will learn about the Samsung Widget Persistence Library.

When we are developing widgets, we have just two functions for saving and retrieving info:

Saving: widget.setPreferenceForKey(value, key)
Retrieving: widget.preferenceForKey(key)

The functions use a lower case "widget" object. Note that we save the information with "value", "key" (in this order).


widget.setPreferenceForKey(value, key);
Saves a value with a specified key in the mobile device. The value is retained even if a device is turned off.

Parameters
value The value to be saved.
key The key that will be used to retrieve the value.

Example
In the following function call, the value "Eduardo#Brazilian#28" is saved in a key named "user_info".

widget.setPreferenceForKey ("Eduardo#Brazilian#28", "user_info");


widget.preferenceForKey(key);
Returns the value associated with the specified key. If no value is associated with the key, this function returns NULL.
Parameters
key The key that is associated with the value to be retrieved.

Example

try
{
return widget.preferenceForKey("user_info");
}
catch(e)
{
return null;
}


Easy? You can find more about Samsung Widget API here!

NOTE: You must debug your code without any API code. If you want to debug your code, remove/comment persistence code. The browser, outside IDE, don't know about Samsung API.

Thanks for your visit! :)

Next post: Let's get it started (bada)...

Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

sexta-feira, 21 de janeiro de 2011

how to debug your code

Hello!


This post will be one of the smallest. :)
As we know, html + css + js are not compiled. These code lines are interpreted and executed by the browser. So, what can we do to debug our widgets? The answer is simple: let's try a html/css/js debugging tool :)


I suggest you to use FireBug, as shown in Figure 1.

"Firebug includes a powerful JavaScript debugger that lets you pause execution at any time and see what each variable looked like at that moment. If your code is a little sluggish, use the JavaScript profiler to measure performance and find bottlenecks fast." (FireBug Site)

Figure 1. FireBug


You can learn more here! You can also use FireBug to check your CSS and HTML files.




Figure 2. Excellent console



I've used FireBug with FireFox...

So, we need to get our widget index.html file, open in FireFox and activate the FireBug (open FireBug console). It's really easy.

Steps to see your code on FireBug:

1- Open your Browser (with FireBug installed);
2- Go to your IDE workspace;
3- Find your Widget Project folder;
4- Open the project index.html file in the browser;
5- Click on FireBug icon, as shown in Figure 3 to activate the plug-in;

Figure 3. FireBug icon


6- You'll see your code!

If you have any question, feel free to ask.



Have a nice day!

Thanks for your visit! :)

Next post: Data Persistence

Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

quinta-feira, 20 de janeiro de 2011

second widget (more complex)

Hello everybody!


Today I'll present you a widget that considers 2 depths: idle (submode) and fuel consumption screen (full mode). We'll better understand the index.html with two different screens (two div structure).
This widget is responsible for a simple fuel consumption control (considering KM and Liters). I'm not worried about images, ok? We are here today to better understand screens changes, html, css and js relationship.



Let's get it started...

html>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html;charset=UTF-8"/>
<!-- link to CSS file -->
<link rel="stylesheet" type="text/css" href="css/style.css" />
<!-- link to JS file -->
<script type=text/javascript src=js/callBack.js></script>
</head>
<!-- first js call - used to initialize some
vars, set initial screen, etc... -->
<body onload="doInit();">
<!-- first depth screen - submode -->
<div id="idle" class="idle" style="display:none">
<div id="txtFuelControl" class="txtFuelControl">Fuel
Consumption</div> </div>
<!-- second depth screen - full mode -->
<div id="fuelControlScreen" style="display:none">
<!-- label -->
<div id="km_inputTitle" class="km_inputTitle">Km</div>
<!-- label -->
<div id="l_inputTitle" class= "l_inputTitle">L</div>
<!-- inputs - created on js -->
<div id="km_inputValueJS"></div>
<!-- inputs - created on js -->
<div id="l_inputValueJS"></div>
<!-- result - will be presented by js -->
<div id="result_FuelControl"></div>
<!-- back button -->
<div id="btnBack" class="btnBack">Back</div>
<!-- result button -->
<div id="btnConfirm" class="btnConfirm">Fuel Consumption</div>
</div>
</body>
</html>

NOTE: I'm using DIV structure, that has any problem to widgets development. I think this way it's easier than modifying each HTML elements in CSS. You can try both.

css>

@CHARSET "UTF-8";

body{margin:0; padding:0;}

.idle{
position:absolute;
width: 180px;
height: 131px;
background:black;
font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;
color:white;
font-size:11pt;
font-weight:bold;
border: 1px solid white;
}

#fuelControlScreen{
position:absolute;
top:0px;
width: 239px;
height: 300px;
background:black;
}

.km_inputTitle {
position:absolute;
top:80px;
left:5px;
font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;
color:white;
font-size:11pt;
font-weight:bold;
}
.km_inputValue {
position:absolute;
top:0px;
left:0px;
}

#km_inputValueJS {
position:absolute;
top:80px;
left:135px;
}


.l_inputTitle {
position:absolute;
top:40px;
left:5px;
font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;
color:white;
font-size:11pt;
font-weight:bold;
}
.l_inputValue {
position:absolute;
top:0px;
left:0px;
}
#l_inputValueJS {
position:absolute;
top:40px;
left:135px;
}

.btnBack{
position:absolute;
top:270px;
left:180px;
width: 40px;
height: 30px;
font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;
color:white;
font-size:11pt;
font-weight:bold;
}

.btnConfirm{
position:absolute;
top:270px;
left:20px;
width: 160px;
height: 30px;
font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;
color:white;
font-size:11pt;
font-weight:bold;
}

#result_FuelControl{
position:absolute;
top:195px;
left:90px;
width: 150px;
color: white;
font-size:11pt;
font-weight:bold;
}

HR{
position:absolute;
top: 35px;
left: 30px;
color: black;
width:180px;
border: 3px solid #000;
}


.txtFuelControl {
position:absolute;
top:50px;
left:20px;
width: 160px;
height: 25px;
font-size: 11pt;
}

js>

//init
doInit=function(){
getIdleScreen();
gId("txtFuelControl").onclick=function(){
getFuelControlScreen();
};
gId("btnBack").onclick=function(){
getIdleScreen();
return;
};
gId("btnConfirm").onclick=function(){
getFuelControlResult();
return;
};
};
//shortcut
function gId(id) {
return document.getElementById(id);
};
//shows idle screen and hide fuelControlScreen
function getIdleScreen(){
gId("idle").style.display = "block";
gId("fuelControlScreen").style.display = "none";
}
//shows fuelControlScreen screen and hide idle
function getFuelControlScreen(){
try {
gId("km_inputValueJS").innerHTML = "<input type=text
id=\"km_inputValue\"
class=\"km_inputValue\" maxlength=\"5\" size=\"10\"
onclick=\"clearInputKM()\"></input>";
gId("l_inputValueJS").innerHTML = "<input type=text
id=\"l_inputValue\"
class=\"l_inputValue\" maxlength=\"5\" size=\"10\"
onclick=\"clearInputL()\"></input>";
} catch (e) {
alert(e);
}
gId("idle").style.display = "none";
gId("fuelControlScreen").style.display = "block";
}
//check comma use
function checaVirgula(valor){
return valor = valor.replace(",",".");
}

function getFuelControlResult(){
var km;
var litros;
var consumo = 0;
km = gId("km_inputValue").value;
litros = gId("l_inputValue").value;

km = checaVirgula(km);
litros = checaVirgula(litros);

if(isNaN(parseFloat(km)) || isNaN(parseFloat(litros)) ||
parseFloat(km) == 0 || parseFloat(litros) == 0 ||
parseFloat(km) < 0 || parseFloat(litros) < 0){
alert("Invalid data!");
clearFields();
return;
}

consumo = parseFloat(km);
consumo /= parseFloat(litros);

gId("result_FuelControl").innerHTML = consumo.toFixed(2)
+ " Km/L";
}

function clearInputKM(){
if(gId("result_FuelControl").innerHTML != ""){
gId("result_FuelControl").innerHTML = "";
}
}

function clearInputL(){
if(gId("result_FuelControl").innerHTML != ""){
gId("result_FuelControl").innerHTML = "";
}
}

function clearFields(){
gId("km_inputValue").value = "";
gId("l_inputValue").value = "";
gId("result_FuelControl").innerHTML = " " ;
}


The widget:



You can try this code. Remember... Package > Run as... > Widget

Have a nice day!

Thanks for your visit! :)

Next post: How to debug your code

Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

quarta-feira, 19 de janeiro de 2011

widgets: design tips and mandatory requirements!

Design Tips:
- maximum recommended size for a widget (exported - .wgt): 1MB!
- widgets can support resolutions 240 x 320 , 240 x 400 , 480 x 800;
- for multi-touch areas a minimum touch area of 35 x 35 pixels must be secured;
- The "Back" button allows the user to return to a previous stage and is an essential button for the widget.
- Network widgets require a "Refresh" button.
- A loading image(gif) is required. Displaying the widget's version is recommended. The updating process is an essential element of a network widget. A "version update" button should also be provided to enable users to update to the latest version of the widget if they so desire.
- Use bmp files as replacements on devices that don't support PNG files.

PNG
1. Although PNG files support 256 level 8-bit transparency, this significantly increases image size. Therefore, Samsung recommend using 1-bit transparency,
similar to GIF format.
2. Although PNG supports true color, its lossless compression produces overly large files as the number of colors increases. Therefore, Samsung recommend
adjusting the work palette to decrease the number of colors (under 256) within an acceptable range without sacrificing quality.
3. When saving PNG files, a preview file is also saved, resulting in a larger size. Prevent this by choosing the "save for web" option and minimize file size.
4. For images with few colors, PNG-8 is not necessarily a better option than PNG-24. Samsung recommend saving in both formats and choosing whichever is smaller.
5. Utilize optimization programs such as OptiPNG or Pngcrush to recompress images without losing any information.

Widgets Elements
Figure 1. Widget Elements



Depth 2 supports both sub and full mode, as shown in Figure 2.
Figure 2. Full Mode / Sub Mode



Mandatory Requirements
For Samsung, these requirements absolutely must be met to create widgets:

1. Depth 1 Widget Grid (widget size)
Depth 1 Widget Area Guide / 240x 320, 240 x 400
Available sizes: 58x65, 58x130, 116x65, 116x130, 174x65, 58x195, 116x195, 174x195, 174x130
Depth 1 Widget Area Guide / 480 x 800
116x129, 232x129, 348x129, 116x258, 232x258, 348x258, 116x387, 232x387, 348x387

2. Widget Icon Size (shadow included)
Widget Icon Size (shadow included)
240 x 320: 44 x 44
240 x 400: 50 x 50
480 x 800: 96 x 96

3. Rounded upper corners for widget in full mode and Content Area by Resolution

Figure 3. Rounded upper corners and content area



4. Soft Key Policy
For 240 x 320 and 240 x 400 size: 37px;
For 480 x 800 size: 74px;

Now, my tip time :)
If you really want to see your widget available in More Widgets, you MUST follow these mandatory requirements.

Thanks for your visit! :)

Next post: Second Widget (more complex)!

Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

widgets: tips and good practices!

1. Unobtrusive JavaScript

W3C recommendation! Unobtrusive JavaScript is the practice of separating out any JavaScript behavior code from your content structure and presentation. According to Adobe, with Unobtrusive JavaScript, only <script> tags that include external JavaScript files are allowed within your document. The goal is to eliminate the use of any <script> tags with inline JavaScript and the use of any HTML behavioral/event attributes, like onclick, onmouseover, etc, that make use of JavaScript from within the content markup itself, and externalize this code in a separate JavaScript file which gets included by a <script> tag with a "src" attribute. The idea here is that these externalized behaviors will get programmatically attached to the elements at some point during the document loading process, most likely after the window onload event fires, with the use of the DOM APIs which allow you to add/remove event handlers programmatically.
This practice prevent a browser that does not support the JS to crash on a particular page. Imagine you're browsing a site, your browser does not support JS and all the site links are one of the following ways:



<a href="javascript.void(0)"> Link A </ a>
<a href="#" onclick="funcao()"> Link B </ a>

This way you can not leave home because all the links use JS to set which page they should go. In this case the solution would actually put the real destination of the link and if necessary set the JS as follows:


index.html>

<script src="example.js" type="text/javascript"></script>

<a id="id_index" href="index.html">Home</a>
<a id="id_blog" href="blog.html">Blog</a>
<a id="id_contato" href="contact.html">Contact</a>


example.js>

var index = document.getElementById('id_index');

index.onclick = function(){
indexFunction();
return false;
}

function indexFunction(){
alert('here!');
}

The use of this technique may seem a little complicated and obscure at first, but from experience we find that the generated HTML code will be more readable and without the trouble of breaking if the browser that does not support JS.

You can learn more here!



2. A single HTML with multiple DIVs

It is a recommendation on developing widgets that we only use index.html file with all the screens of the widget in hidden DIVs. These screens can be grouped into different DIVs to implement the depths or "levels" (details in next post).



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<link rel="stylesheet" type="text/css" href="css/style.css" />

<script type=text/javascript src=js/callBack.js></script>
<script type=text/javascript src=js/main.js></script>
<script type=text/javascript src=js/common.js></script>
</head>
<body onload="init();">
<!-- Widget with 2 screens or 2 DIVs -->
<!-- First DIV -->
<div id="telaIcone" style="display:none">
<div id="menuLibras" class="menuLibras"></div>
</div>
<!-- Second DIV -->
<div id="telaInicialLibras" class="telaInicialLibras"
style="display:none">
<div class="topoLibras"></div>
<div class="rodape"></div>
<img id="librasImagens">
<div id="setaDireita" class="setaDireita"></div>
<div id="setaEsquerda" class="setaEsquerda"></div>
<div id="inputDados"></div>
<div id="btInterpretar" class="btInterpretar"></div>
<div id="retornaTelaIcone" class="retornaTelaIcone"></div>
</div>
</body>
</html>


3. Do not create styles depending on the ids

Another practice that i've adopted was to not set styles using the id attribute of HTML elements. I used names that could be referenced in HTML using the class attribute. Therefore the ids may be used freely by the developers without interfering with the work of designers. We may think like the developer is the owner of the functionality (use of ids and JS) while the designer is the owner of the layout (class and .css)



Thanks for your visit! :)

Next post: Widgets: Design Tips and Mandatory Requirements!

Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo

terça-feira, 18 de janeiro de 2011

better understanding your first widget!

Let's understand Hello World widget better.

As we can see, a widget has the following structure:

/ Root
– config.xml
– index.html
– icon.png – this image file is what users will see in their widget bar
– / css
- css files
– / images
- PNG (recommended)
– / js
- js files


In this post I'm assuming that everyone has HTML/CSS knowledge. So let's understand the Widget architecture.
As we can see in Figure 1 and Figure 2, a widget is a front-end app that is emulated in a browser. The widget is composed by HTML + CSS + JS.

Figure 1. Front-end architecture


Figure 2. Widget architecture



html>
a set of tags and rules for using them in developing hypertext documents

a protocol which include "tags" that are used to encode and format text, graphics, animation, sound, and other types of files on the World Wide Web

the predominant markup language for web pages. It provides a means to create structured documents by denoting structural semantics for text such as headings, paragraphs, lists etc as well as for links, quotes, and other items.

css>
is a style sheet language used to describe the presentation semantics (that is, the look and formatting) of a document written in a markup language. ...

js>
is an object-oriented scripting language used to enable programmatic access to objects within both the client application and other applications.

is a scripting language widely used for client-side web development. It was the originating dialect of the ECMAScript standard. It is a dynamic, weakly typed, prototype-based language with first-class functions.

The application that we've created can run in any browser. You can try :)

Let's check the code:

html>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><br>
<html>
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="css/style.css" />
<script type="text/javascript" src="js/main.js"></script>
</head>
<body>
<div id="hello">
<h2>Hello World</h2>
</div>
<div id="hello_again">
<h2>Another hello!</h2>
</div>
<h3 onclick="toggle()">Press to toggle</h3>
</body>
</html>


Very simple HTML with two id's: hello and hello_again (id's must be unique). And a call to toggle() js function.


js>

var state = 'hello';

//toggle function
//after any button click, this function will
//be called (based on created HTML).
function toggle()
{
//get the element id's (DOM)
var helloElem = document.getElementById("hello");
var hello_againElem = document.getElementById("hello_again");

//check the state
if(state == 'hello')
{
//change the CSS to hide the 'hello' element
helloElem.style.display = 'none';
//change the CSS to show the 'hello_again' element
hello_againElem.style.display = 'block';
//update state
state='hello_again';
}
else
{
//change the CSS to show the 'hello' element
helloElem.style.display = 'block';
//change the CSS to hide the 'hello_again' element
hello_againElem.style.display = 'none';
//update state
state='hello';
}
}

css>

body {
padding: 0;
margin: 0;
}
/* hello id: used in html and js */
div#hello {
display: block;
}
/* hello_again id: used in html and js */
div#hello_again {
display: none;
}

h2 {
color:white;
text-align: center;
background-color:rgb(80, 80, 170);
}

h3 {
text-align: center;
color:white;
margin:-15px 10px 0 10px;
padding:4px;
background-color:rgb(80, 80, 170);
border:2px solid;
border-color:#c4c4e8 black black #c4c4e8;
font-family:sans-serif;
font-size: medium;
}


So, can you see how these elements are connected? In HTML file, as presented:

<head>
<title></title>
<link rel="stylesheet" type="text/css" href="css/style.css" />
<script type="text/javascript" src="js/main.js"></script>
</head>

Easy?
:)


Thanks for your visit! :)

Next post: Widgets: Tips and Good Practices!

Feel free to ask/suggest/comment.
Twitter: @oliveiraeduardo