Commit c3a41aa75b3340d1b670e1b276dd92232677224a

Authored by Richard Huang
1 parent 24c8baf6

Flexbox Demo to demonstrates a proof of concept for FlexContainer UI control

Change-Id: I20f7a13ebc19b54ab91194b9c6b87d787f23501d
com.samsung.dali-demo.xml
@@ -148,4 +148,7 @@ @@ -148,4 +148,7 @@
148 <ui-application appid="native-image-source.example" exec="/usr/apps/com.samsung.dali-demo/bin/native-image-source.example" nodisplay="true" multiple="false" type="c++app" taskmanage="true"> 148 <ui-application appid="native-image-source.example" exec="/usr/apps/com.samsung.dali-demo/bin/native-image-source.example" nodisplay="true" multiple="false" type="c++app" taskmanage="true">
149 <label>Native Image Source</label> 149 <label>Native Image Source</label>
150 </ui-application> 150 </ui-application>
  151 + <ui-application appid="flex-container.example" exec="/usr/apps/com.samsung.dali-demo/bin/flex-container.example" nodisplay="true" multiple="false" type="c++app" taskmanage="true">
  152 + <label>Flex Container</label>
  153 + </ui-application>
151 </manifest> 154 </manifest>
examples/flex-container/flex-container-example.cpp 0 → 100644
  1 +/*
  2 + * Copyright (c) 2016 Samsung Electronics Co., Ltd.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + *
  16 + */
  17 +
  18 +#include <sstream>
  19 +#include "shared/view.h"
  20 +
  21 +#include <dali/dali.h>
  22 +#include <dali-toolkit/dali-toolkit.h>
  23 +#include <dali-toolkit/devel-api/controls/flex-container/flex-container.h>
  24 +
  25 +using namespace Dali;
  26 +using namespace Dali::Toolkit;
  27 +
  28 +namespace
  29 +{
  30 +
  31 +const int NUM_FLEX_ITEMS = 8;
  32 +
  33 +const char* BACKGROUND_IMAGE( DEMO_IMAGE_DIR "background-default.png" );
  34 +const char* TOOLBAR_IMAGE( DEMO_IMAGE_DIR "top-bar.png" );
  35 +
  36 +const DemoHelper::ViewStyle VIEW_STYLE( 0.08f, 0.45f, 80.f, 4.f );
  37 +
  38 +const std::string FLEX_DIRECTION[] = {
  39 + "column",
  40 + "columnReverse",
  41 + "row",
  42 + "rowReverse"
  43 +};
  44 +
  45 +const unsigned int NUM_FLEX_DIRECTION = sizeof(FLEX_DIRECTION) / sizeof(std::string);
  46 +
  47 +const std::string FLEX_WRAP[] = {
  48 + "noWrap",
  49 + "Wrap"
  50 +};
  51 +
  52 +const unsigned int NUM_FLEX_WRAP = sizeof(FLEX_WRAP) / sizeof(std::string);
  53 +
  54 +const std::string CONTENT_DIRECTION[] = {
  55 + "inherit",
  56 + "LTR",
  57 + "RTL"
  58 +};
  59 +
  60 +const unsigned int NUM_CONTENT_DIRECTION = sizeof(CONTENT_DIRECTION) / sizeof(std::string);
  61 +
  62 +const std::string JUSTIFY_CONTENT[] = {
  63 + "flexStart",
  64 + "center",
  65 + "flexEnd",
  66 + "spaceBetween",
  67 + "spaceAround"
  68 +};
  69 +
  70 +const unsigned int NUM_JUSTIFY_CONTENT = sizeof(JUSTIFY_CONTENT) / sizeof(std::string);
  71 +
  72 +const std::string ALIGN_ITEMS[] = {
  73 + "flexStart",
  74 + "center",
  75 + "flexEnd",
  76 + "stretch"
  77 +};
  78 +
  79 +const unsigned int NUM_ALIGN_ITEMS = sizeof(ALIGN_ITEMS) / sizeof(std::string);
  80 +
  81 +const std::string ALIGN_CONTENT[] = {
  82 + "flexStart",
  83 + "center",
  84 + "flexEnd",
  85 + "stretch"
  86 +};
  87 +
  88 +const unsigned int NUM_ALIGN_CONTENT = sizeof(ALIGN_CONTENT) / sizeof(std::string);
  89 +
  90 +} // unnamed namespace
  91 +
  92 +/**
  93 + * This example demonstrates a proof of concept for FlexContainer UI control.
  94 + * The flexbox properties can be changed by pressing different buttons in the
  95 + * toolbar.
  96 + */
  97 +class FlexContainerExample : public ConnectionTracker
  98 +{
  99 +public:
  100 +
  101 + /**
  102 + * Constructor
  103 + * @param application class, stored as reference
  104 + */
  105 + FlexContainerExample( Application& application )
  106 + : mApplication( application ),
  107 + mCurrentFlexDirection( FlexContainer::ROW ),
  108 + mCurrentFlexWrap( FlexContainer::WRAP ),
  109 + mCurrentContentDirection( FlexContainer::INHERIT),
  110 + mCurrentJustifyContent( FlexContainer::JUSTIFY_FLEX_START ),
  111 + mCurrentAlignItems( FlexContainer::ALIGN_FLEX_START ),
  112 + mCurrentAlignContent( FlexContainer::ALIGN_FLEX_START )
  113 + {
  114 + // Connect to the Application's Init signal
  115 + mApplication.InitSignal().Connect(this, &FlexContainerExample::OnInit);
  116 + }
  117 +
  118 + /**
  119 + * This method gets called once the main loop of application is up and running
  120 + */
  121 + void OnInit(Application& app)
  122 + {
  123 + Stage stage = Dali::Stage::GetCurrent();
  124 + stage.KeyEventSignal().Connect(this, &FlexContainerExample::OnKeyEvent);
  125 + stage.GetRootLayer().SetBehavior(Layer::LAYER_3D);
  126 +
  127 + Vector2 stageSize = Stage::GetCurrent().GetSize();
  128 +
  129 + // Creates a default view with a default tool bar.
  130 + // The view is added to the stage.
  131 + Layer contents = DemoHelper::CreateView( mApplication,
  132 + mView,
  133 + mToolBar,
  134 + BACKGROUND_IMAGE,
  135 + TOOLBAR_IMAGE,
  136 + "" );
  137 +
  138 + // Create a flex direction toggle button. (left of toolbar)
  139 + mFlexDirectionButton = Toolkit::PushButton::New();
  140 + mFlexDirectionButton.SetName("mFlexDirectionButton");
  141 + mFlexDirectionButton.SetUnselectedImage( DEMO_IMAGE_DIR "icon-change.png" );
  142 + mFlexDirectionButton.SetSelectedImage( DEMO_IMAGE_DIR "icon-change-selected.png" );
  143 + mFlexDirectionButton.ClickedSignal().Connect( this, &FlexContainerExample::OnFlexDirectionButtonClicked);
  144 + mFlexDirectionButton.SetLeaveRequired( true );
  145 + mToolBar.AddControl( mFlexDirectionButton, VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalLeft, DemoHelper::DEFAULT_MODE_SWITCH_PADDING );
  146 +
  147 + // Create a flex wrap toggle button. (left of toolbar)
  148 + mFlexWrapButton = Toolkit::PushButton::New();
  149 + mFlexWrapButton.SetName("mFlexWrapButton");
  150 + mFlexWrapButton.SetUnselectedImage( DEMO_IMAGE_DIR "icon-edit.png" );
  151 + mFlexWrapButton.SetSelectedImage( DEMO_IMAGE_DIR "icon-edit-selected.png" );
  152 + mFlexWrapButton.ClickedSignal().Connect( this, &FlexContainerExample::OnFlexWrapButtonClicked);
  153 + mFlexWrapButton.SetLeaveRequired( true );
  154 + mToolBar.AddControl( mFlexWrapButton, VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalLeft, DemoHelper::DEFAULT_MODE_SWITCH_PADDING );
  155 +
  156 + // Create a content direction toggle button. (left of toolbar)
  157 + mContentDirectionButton = Toolkit::PushButton::New();
  158 + mContentDirectionButton.SetName("mContentDirectionButton");
  159 + mContentDirectionButton.SetUnselectedImage( DEMO_IMAGE_DIR "icon-replace.png" );
  160 + mContentDirectionButton.SetSelectedImage( DEMO_IMAGE_DIR "icon-replace-selected.png" );
  161 + mContentDirectionButton.ClickedSignal().Connect( this, &FlexContainerExample::OnContentDirectionButtonClicked);
  162 + mContentDirectionButton.SetLeaveRequired( true );
  163 + mToolBar.AddControl( mContentDirectionButton, VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalLeft, DemoHelper::DEFAULT_MODE_SWITCH_PADDING );
  164 +
  165 + // Create a justify content toggle button. (right of toolbar)
  166 + mJustifyContentButton = Toolkit::PushButton::New();
  167 + mJustifyContentButton.SetName("mJustifyContentButton");
  168 + mJustifyContentButton.SetUnselectedImage( DEMO_IMAGE_DIR "icon-reset.png" );
  169 + mJustifyContentButton.SetSelectedImage( DEMO_IMAGE_DIR "icon-reset-selected.png" );
  170 + mJustifyContentButton.ClickedSignal().Connect( this, &FlexContainerExample::OnJustifyContentButtonClicked);
  171 + mJustifyContentButton.SetLeaveRequired( true );
  172 + mToolBar.AddControl( mJustifyContentButton, VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalRight, DemoHelper::DEFAULT_MODE_SWITCH_PADDING );
  173 +
  174 + // Create a align items toggle button. (right of toolbar)
  175 + mAlignItemsButton = Toolkit::PushButton::New();
  176 + mAlignItemsButton.SetName("mAlignItemsButton");
  177 + mAlignItemsButton.SetUnselectedImage( DEMO_IMAGE_DIR "icon-highp.png" );
  178 + mAlignItemsButton.SetSelectedImage( DEMO_IMAGE_DIR "icon-highp-selected.png" );
  179 + mAlignItemsButton.ClickedSignal().Connect( this, &FlexContainerExample::OnAlignItemsButtonClicked);
  180 + mAlignItemsButton.SetLeaveRequired( true );
  181 + mToolBar.AddControl( mAlignItemsButton, VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalRight, DemoHelper::DEFAULT_MODE_SWITCH_PADDING );
  182 +
  183 + // Create a align content toggle button. (right of toolbar)
  184 + mAlignContentButton = Toolkit::PushButton::New();
  185 + mAlignContentButton.SetName("mAlignContentButton");
  186 + mAlignContentButton.SetUnselectedImage( DEMO_IMAGE_DIR "icon-effect-cross.png" );
  187 + mAlignContentButton.SetSelectedImage( DEMO_IMAGE_DIR "icon-effect-cross-selected.png" );
  188 + mAlignContentButton.ClickedSignal().Connect( this, &FlexContainerExample::OnAlignContentButtonClicked);
  189 + mAlignContentButton.SetLeaveRequired( true );
  190 + mToolBar.AddControl( mAlignContentButton, VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalRight, DemoHelper::DEFAULT_MODE_SWITCH_PADDING );
  191 +
  192 + // Create the base flex container
  193 + mFlexContainer = FlexContainer::New();
  194 + mFlexContainer.SetParentOrigin(ParentOrigin::TOP_LEFT);
  195 + mFlexContainer.SetAnchorPoint(AnchorPoint::TOP_LEFT);
  196 + mFlexContainer.SetSize( stageSize.width, stageSize.height - VIEW_STYLE.mToolBarHeight );
  197 + mFlexContainer.SetY(VIEW_STYLE.mToolBarHeight);
  198 + mFlexContainer.SetProperty(FlexContainer::Property::FLEX_DIRECTION, FlexContainer::COLUMN); // column as main axis
  199 + contents.Add(mFlexContainer);
  200 +
  201 + // Add a text label to the container for showing the recently updated flexbox property value
  202 + mFlexPropertyLabel = TextLabel::New( FLEX_DIRECTION[mCurrentFlexDirection] );
  203 + mFlexPropertyLabel.RegisterProperty("flexMargin", Vector4(10.0f, 10.0f, 10.0f, 10.0f), Property::READ_WRITE);
  204 + mFlexPropertyLabel.RegisterProperty("flex", 0.05f, Property::READ_WRITE); // 5 pecent of the container size in the main axis
  205 + mFlexPropertyLabel.SetProperty(TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER");
  206 + mFlexPropertyLabel.SetProperty(TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER");
  207 + mFlexContainer.Add( mFlexPropertyLabel );
  208 +
  209 + // Create the flex container for the flex items and add it to the base flex container
  210 + mFlexItemContainer = FlexContainer::New();
  211 + mFlexItemContainer.SetParentOrigin(ParentOrigin::TOP_LEFT);
  212 + mFlexItemContainer.SetAnchorPoint(AnchorPoint::TOP_LEFT);
  213 + mFlexItemContainer.SetBackgroundColor( Color::YELLOW );
  214 + mFlexItemContainer.RegisterProperty("flex", 0.95f, Property::READ_WRITE); // 95 pecent of the container size in the main axis
  215 + mFlexItemContainer.SetProperty(FlexContainer::Property::FLEX_DIRECTION, mCurrentFlexDirection);
  216 + mFlexItemContainer.SetProperty(FlexContainer::Property::FLEX_WRAP, mCurrentFlexWrap);
  217 + mFlexContainer.Add(mFlexItemContainer);
  218 +
  219 + // Create flex items and add them to the container
  220 + for (int i = 0; i < NUM_FLEX_ITEMS; i++)
  221 + {
  222 + PushButton flexItem = PushButton::New();
  223 + flexItem.SetAnchorPoint( AnchorPoint::TOP_LEFT );
  224 + flexItem.SetParentOrigin( ParentOrigin::TOP_LEFT );
  225 +
  226 + // Set different background colour to help to identify different items
  227 + flexItem.SetBackgroundColor(Vector4(static_cast<float>(i) / NUM_FLEX_ITEMS, static_cast<float>(NUM_FLEX_ITEMS - i) / NUM_FLEX_ITEMS, 1.0f, 1.0f));
  228 + flexItem.SetUnselectedImage("");
  229 + flexItem.SetSelectedImage("");
  230 +
  231 + // Add a label to the button so that we can identify each item more easily
  232 + std::ostringstream index;
  233 + index << i + 1;
  234 + flexItem.SetLabelText(index.str());
  235 + flexItem.SetName("FlexItem " + index.str());
  236 +
  237 + // Set a fixed size to the items so that we can wrap the line and test these
  238 + // flex properties that only work when there are multiple lines in the layout
  239 + flexItem.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS);
  240 + // Make sure there are still extra space in the line after wrapping
  241 + flexItem.SetSize(stageSize.width / NUM_FLEX_ITEMS * 1.25f, (stageSize.height - VIEW_STYLE.mToolBarHeight) * 0.95f / NUM_FLEX_ITEMS * 1.25f);
  242 +
  243 + mFlexItemContainer.Add( flexItem );
  244 + }
  245 +
  246 + // Update the title
  247 + SetTitle( "Flex direction", FLEX_DIRECTION[mCurrentFlexDirection] );
  248 + }
  249 +
  250 + bool OnFlexDirectionButtonClicked( Toolkit::Button button )
  251 + {
  252 + mCurrentFlexDirection = static_cast<FlexContainer::FlexDirection>( ( mCurrentFlexDirection + 1 ) % NUM_FLEX_DIRECTION );
  253 + mFlexItemContainer.SetProperty(FlexContainer::Property::FLEX_DIRECTION, mCurrentFlexDirection);
  254 + SetTitle( "Flex direction", FLEX_DIRECTION[mCurrentFlexDirection] );
  255 +
  256 + return true;
  257 + }
  258 +
  259 + bool OnFlexWrapButtonClicked( Toolkit::Button button )
  260 + {
  261 + mCurrentFlexWrap = static_cast<FlexContainer::WrapType>( ( mCurrentFlexWrap + 1 ) % NUM_FLEX_WRAP );
  262 + mFlexItemContainer.SetProperty(FlexContainer::Property::FLEX_WRAP, mCurrentFlexWrap);
  263 + SetTitle( "Flex wrap", FLEX_WRAP[mCurrentFlexWrap] );
  264 +
  265 + return true;
  266 + }
  267 +
  268 + bool OnContentDirectionButtonClicked( Toolkit::Button button )
  269 + {
  270 + mCurrentContentDirection = static_cast<FlexContainer::ContentDirection>( ( mCurrentContentDirection + 1 ) % NUM_CONTENT_DIRECTION );
  271 + mFlexItemContainer.SetProperty(FlexContainer::Property::CONTENT_DIRECTION, mCurrentContentDirection);
  272 + SetTitle( "Content direction", CONTENT_DIRECTION[mCurrentContentDirection] );
  273 +
  274 + return true;
  275 + }
  276 +
  277 + bool OnJustifyContentButtonClicked( Toolkit::Button button )
  278 + {
  279 + mCurrentJustifyContent = static_cast<FlexContainer::Justification>( ( mCurrentJustifyContent + 1 ) % NUM_JUSTIFY_CONTENT );
  280 + mFlexItemContainer.SetProperty(FlexContainer::Property::JUSTIFY_CONTENT, mCurrentJustifyContent);
  281 + SetTitle( "Justify content", JUSTIFY_CONTENT[mCurrentJustifyContent] );
  282 +
  283 + return true;
  284 + }
  285 +
  286 + bool OnAlignItemsButtonClicked( Toolkit::Button button )
  287 + {
  288 + mCurrentAlignItems = static_cast<FlexContainer::Alignment>( ( mCurrentAlignItems + 1 ) % ( NUM_ALIGN_ITEMS + 1 ) );
  289 + mCurrentAlignItems = mCurrentAlignItems < FlexContainer::ALIGN_FLEX_START ? FlexContainer::ALIGN_FLEX_START : mCurrentAlignItems; // skip auto as it is invalid for alignItems property
  290 + mFlexItemContainer.SetProperty(FlexContainer::Property::ALIGN_ITEMS, mCurrentAlignItems );
  291 + SetTitle( "Align Items", ALIGN_ITEMS[mCurrentAlignItems - 1] );
  292 +
  293 + return true;
  294 + }
  295 +
  296 + bool OnAlignContentButtonClicked( Toolkit::Button button )
  297 + {
  298 + mCurrentAlignContent = static_cast<FlexContainer::Alignment>( ( mCurrentAlignContent + 1 ) % (NUM_ALIGN_CONTENT + 1 ) );
  299 + mCurrentAlignContent = mCurrentAlignContent < FlexContainer::ALIGN_FLEX_START ? FlexContainer::ALIGN_FLEX_START : mCurrentAlignContent; // skip auto as it is invalid for alignContent property
  300 + mFlexItemContainer.SetProperty(FlexContainer::Property::ALIGN_CONTENT, mCurrentAlignContent);
  301 + SetTitle( "Align content", ALIGN_CONTENT[mCurrentAlignContent - 1] );
  302 +
  303 + return true;
  304 + }
  305 +
  306 +private:
  307 +
  308 + /**
  309 + * Sets/Updates the title of the View and the value of the recently updated
  310 + * flexbox property.
  311 + *
  312 + * @param[in] title The new title for the view.
  313 + * @param[in] propertyValue The value of the flexbox property.
  314 + */
  315 + void SetTitle(const std::string& title, const std::string& propertyValue)
  316 + {
  317 + if(!mTitleActor)
  318 + {
  319 + mTitleActor = DemoHelper::CreateToolBarLabel( "" );
  320 + // Add title to the tool bar.
  321 + mToolBar.AddControl( mTitleActor, VIEW_STYLE.mToolBarTitlePercentage, Alignment::HorizontalCenter );
  322 + }
  323 +
  324 + // Update the title and property value
  325 + mTitleActor.SetProperty( TextLabel::Property::TEXT, title );
  326 + mFlexPropertyLabel.SetProperty( TextLabel::Property::TEXT, propertyValue );
  327 + }
  328 +
  329 + /**
  330 + * Main key event handler
  331 + */
  332 + void OnKeyEvent(const KeyEvent& event)
  333 + {
  334 + if(event.state == KeyEvent::Down)
  335 + {
  336 + if( IsKey( event, DALI_KEY_ESCAPE) || IsKey( event, DALI_KEY_BACK ) )
  337 + {
  338 + mApplication.Quit();
  339 + }
  340 + }
  341 + }
  342 +
  343 +private:
  344 +
  345 + Application& mApplication;
  346 +
  347 + Toolkit::Control mView;
  348 + Toolkit::ToolBar mToolBar;
  349 + TextLabel mTitleActor; ///< The Toolbar's Title.
  350 +
  351 + FlexContainer mFlexContainer;
  352 + FlexContainer mFlexItemContainer;
  353 + TextLabel mFlexPropertyLabel;
  354 +
  355 + FlexContainer::FlexDirection mCurrentFlexDirection;
  356 + FlexContainer::WrapType mCurrentFlexWrap;
  357 + FlexContainer::ContentDirection mCurrentContentDirection;
  358 + FlexContainer::Justification mCurrentJustifyContent;
  359 + FlexContainer::Alignment mCurrentAlignItems;
  360 + FlexContainer::Alignment mCurrentAlignContent;
  361 +
  362 + Toolkit::PushButton mFlexDirectionButton;
  363 + Toolkit::PushButton mFlexWrapButton;
  364 + Toolkit::PushButton mContentDirectionButton;
  365 + Toolkit::PushButton mJustifyContentButton;
  366 + Toolkit::PushButton mAlignItemsButton;
  367 + Toolkit::PushButton mAlignContentButton;
  368 +};
  369 +
  370 +void RunTest(Application& app)
  371 +{
  372 + FlexContainerExample test(app);
  373 +
  374 + app.MainLoop();
  375 +}
  376 +
  377 +int DALI_EXPORT_API main(int argc, char **argv)
  378 +{
  379 + Application app = Application::New(&argc, &argv, DEMO_THEME_PATH);
  380 +
  381 + RunTest(app);
  382 +
  383 + return 0;
  384 +}