📜 ⬆️ ⬇️

Tai'Dzen: the first steps (part 2)

Dear habrasoobschestvo, welcome!
Let's continue the consideration of a simple native shopping list application. In the first part , the preparatory work was carried out: the structure of the typical Tizen project, some approaches to the design of the application architecture, and also the peculiarities of working with the WYSIWYG GUI editor were investigated. Today, the reader is waiting for scenes and scene editor, managing lists of graphical controls (controls), their customization and event handling. The third part will be a little later, it is devoted to working with the database, but the text contains a link to the git-repository. All commits are provided with comments, so work with the data can be investigated right now, without waiting for the third part. For each stage, the labels on the corresponding commits are indicated, so welcome under cat.

Part one

PART TWO

Let's start with the problem statement. Before going to the supermarket often need to make a list of purchases, so as not to forget anything. The mobile application is more convenient than a regular notebook with a pen according to the following parameters:


Fig. by Leka
')
The git repository contains a learning project that describes the steps involved in creating such an application. All significant stages are marked by tags (see further in the text). READMe.txt describes the changes that occurred between the two tags.

For the application will need at least two forms or panels. At the first we work directly with the names of purchases (add, delete, rename, cross out). The shopping list, which cannot be saved, does not make sense, so on the second form we work with the names of the lists: create a new one, delete it, rename it, duplicate it, copy it to the clipboard (then send it to the artist).

At the moment, three tabs are connected to ShoppingListMainForm (see the first part of the article). Reduce the livestock to two, i.e. delete the third tab. Removal is carried out first in the UI Builder, and then we clean up the code.
Uninstalling in UI Builder:
  1. in IDL_FORM, delete the button for the third panel (HEADERITEM3) from the Header;
  2. we delete directly the IDL_PANEL3 panel itself - an xml-file with its description;
  3. delete TabScene3 in Workflow;
  4. save changes :)

In general, the marked points are obvious, but the third will take a closer look.

Together with TabScene3, its transitions are also deleted, including the transition from TabScene1 - IDSCNT_3. Therefore it is necessary to add a transition from TabScene1 to TabScene, let's call it IDSCNT_2.



By default, a new transition saves history in the transition stack. About the properties of the transitions can be read in detail here . It makes no sense to memorize transitions between tabs, so we set the History property to no :



The Destroy property determines whether the current panel will be deleted from memory when switching to a new one. If the keep value is set, the panel will be created once, and on subsequent transitions it will simply be displayed on the screen. If the value is set to destroy , then each time you switch to the panel, it will be created anew (since it was deleted when it left it). In this case, regardless of the value of this property, the form will be created only once, since all transitions are carried out within its limits.

The code generation system will add a transition command to the ShoppingListMainForm::OnActionPerformed() event handler, all that remains is to move it to the corresponding case:

 void ShoppingListMainForm::OnActionPerformed(const Tizen::Ui::Control& source, int actionId) { SceneManager* pSceneManager = SceneManager::GetInstance(); AppAssert(pSceneManager); switch(actionId) { case ID_HEADER_ITEM1: pSceneManager->GoForward(SceneTransitionId(IDSCNT_1)); break; case ID_HEADER_ITEM2: pSceneManager->GoForward(SceneTransitionId(IDSCNT_2)); break; default: break; } } 


Restore order in the code:
  1. delete the source code of the panel - the files ShoppingListTab3.h and ShoppingListTab3.cpp;
  2. automatic deletion of identifiers from AppResourceId.h and AppResourceId.cpp does not occur when working with UI Builder, so you need to delete unnecessary lines manually: IDL_PANEL3 (panel ID) and IDSCNT_3 (ID of switching to this panel);
  3. remove references to the third panel from the ShoppingListPanelFactory.


Attention! Perhaps some neophytes now want to decompose all the source files into daddies: panels and forms separately, control code and other controllers with models separately ... So, adherents of Tai'Dzen consider perfectionism to be a big mistake. Therefore, any change in the source structure of the GUI, to which the UI Builder is relevant, leads to the unpredictable behavior of the latter. Files can not be renamed, moved to a directory other than the root, etc. Otherwise, the code generation system begins to go crazy, then the workflow builder, which negates all the benefits of using this utility.

We proceed directly to the development of the application.

The application is designed to manage lists - and we will deal with them. Open the IDL_PANEL1.xml panel using the UI Builder, then drag the ListView component from the Listbox & TableView tab to the workspace from the Toolbox window. The differences between the six types of lists presented on the tab are described in detail in the documentation, and now another “joy” awaits us - managing the overlay order does not work (this is how I translated the z-order term):



Buttons for moving GUI components by “layers” are inactive. Currently IDC_LISTVIEW1 closes IDC_LABEL1 - no problem, as the ListView is transparent. However, if, for example, the button (the Button component) is closed, then we simply cannot press it! In general, it is not yet possible to subordinate Z-order using the UI Builder; therefore, we open IDL_PANEL1.xml using a standard text editor and swap lines responsible for adding components:

 <ScenePanel Bversion="2.0.0.201311071821" Dversion="20120315"> <LogicalCoordinate>720</LogicalCoordinate> <Panel id="IDL_PANEL1"> … /*   */ </Panel> <Label id="IDC_LABEL1" parent="IDL_PANEL1"> … /*   */ </Label> <ListView id="IDC_LISTVIEW1" parent="IDL_PANEL1"> … /*   */ </ListView> </ScenePanel> 

replace with

 <ScenePanel Bversion="2.0.0.201311071821" Dversion="20120315"> <LogicalCoordinate>720</LogicalCoordinate> <Panel id="IDL_PANEL1"> … /*   */ </Panel> <ListView id="IDC_LISTVIEW1" parent="IDL_PANEL1"> … /*   */ </ListView> <Label id="IDC_LABEL1" parent="IDL_PANEL1"> … /*   */ </Label> </ScenePanel> 


Then we save the changes and reopen them using the UI Builder. Components are swapped. If you have not changed - you need to go to drink coffee, then relax, take the position most convenient for comprehending Tai'Den and start anew. You can also restart Tizen IDE.

Next, we set the required dimensions for the ListView in a way that depends on the selected coordinate system (the default is logical relative). In this case, I tied the sizes of the ListView to the sizes of the parent panel IDL_PANEL1.

Now fill the ListView with life: call the context menu in the workspace and select Add Event Handler.



The minimum required set in this case are the IListViewItemEventListener and IListViewItemProvider items. Selecting these items means that an object that implements these interfaces will be assigned to the ListView. The first interface is responsible for the reaction to the events of the elements of the list, and the second provides the data to create these elements. In this case, such an object is an instance of the ShoppingListTab1 class, i.e. parent panel (described in the file IDL_PANEL1.xml).

After clicking the Finish button, the code generation system will automatically register the implementation of the interfaces and the subscription to the ListView events in the files ShoppingListTab1.h and ShoppingListTab1.cpp. The results of her work are best not to change - she likes to modify the manually modified code without warning. In this regard, aesthetic adherents better to abandon her services at all and prescribe all pens. What the project looks like at this stage - see the v0.1 label.

Regarding IListViewItemProvider, everything is pretty obvious: create / delete a list item by index, return the number of these items. As an element of the list, we will use CustomItem (after all, I promised customization?). Add EnrichedText to it, which will be used as a container for TextElements, so our element will display the text.

I deliberately do not describe in detail the purpose of these elements - everything is set out in the documentation in great detail. My goal is to reveal some pitfalls.

EnrichedText allows you to format text very flexibly, but its possibilities are not limitless. First of all, long texts cannot be added to it. This means that the display area of ​​the text should not exceed 2048 pixels (found experimentally). I suspect that this limitation is due to the maximum size of textures with which the text rendering library can work. The question arises, why such difficulties when you can use a ready-made TextBox component? The truth is that TextBox starts to slow down, even when the size of scrollable text is twice the size of the screen. Currently, using ListView + CustomItem + EnrichedText allows you to create the smoothest scrolling. Yes, we break the text into parts and form an adapter that will slowly feed it to the ListView when scrolling. Tai'Dzen teaches patience.



Another trap is the empty string in TextElement. When you try to draw a text element, initiated by an empty line, the application will crash. To hedge, I usually add a newline character \ n at the end of the text:

 pTextElement->Construct(strSomeText + "\n"); 


IDC_LABEL1 is no longer needed and can be deleted. What the project looks like at this stage - see the v0.2 label.

Now consider the events that are handled in the IListViewItemEventListener. The OnListViewItemLongPressed and OnListViewItemStateChanged events are fairly obvious — they occur when an item is clicked. But the OnListViewItemSwept event remains a mystery to me: I have never been able to call it.

The OnListViewContextItemStateChanged event deserves a special mention - it is a kind of analogue of the context menu within the list item. It is realized through a rather elegant, though very simple effect - the element is shifted to the side, while the substrate is dynamically “lightened”. In order for OnListViewContextItemStateChanged events to occur, customItem s should generate them, so you need to connect the so-called ItemContext to them:

 pItemContext = new (std::nothrow) ListContextItem();//   pItemContext->Construct(); pItemContext->AddElement(ID_CNTX_BTN_DELETE, "Delete"); … AppAssert(pItemContext); pItem->SetContextItem(pItemContext); //    CustomItem 




Here we have added a delete button to the context that will delete the corresponding element. We’ll go back to work with list items, and now we’ll move on to data management.

Part three

Source: https://habr.com/ru/post/213605/


All Articles