DragonFireSDK Forum

Programming Discussions => How Do I...? => Topic started by: AnswerSoft on August 06, 2012, 10:45:44 am

Title: Scrolling
Post by: AnswerSoft on August 06, 2012, 10:45:44 am
Brand new user here. I searched through the forums before posting the question. However, it seems that what I want to do isn't natively supported, though I would expect it to be an extremely common request.

I have text I need to display that exceeds the length of the screen. Are there no built in functions to scroll the text up to see it? I see that containers are a new thing for 2.0. Do these hold the key? I'm thinking that to do this manually I'll need the Touch functions. Sound reasonable? If someone has already worked this out, I'd appreciate a heads up to the standard code.

Thanks,
Mike
Title: Re: Scrolling
Post by: nednones on August 06, 2012, 12:41:57 pm
There are two ways to combat your request.

1.) Ou can either put some detection in your code so that if the amount of chars in your string exceed a set length then insert the rest of the sentence onto a new line, but make sure you account for this by leaving a blank line underneath or two in fact should you receive a lot of text.

2.) you create a scroller using say 3 images and then using the OnTouch() method you can then scroll the worldsetxy to where ever your finger has dragged the screen too. Hope that makes sense
Title: Re: Scrolling
Post by: zacho on August 06, 2012, 12:42:21 pm
A user has provided a way how to scroll, please thank him :) http://dragonfiresdk.net/forum/index.php?topic=227.0
Title: Re: Scrolling
Post by: jjsanchezramirez on August 06, 2012, 02:27:59 pm
@nednones, I think what he means is that he has a multi-line text that's too big to fit on screen.

@AnswerSoft, you will need both containers and touch components. Check out the link zacho gave you. That, however, might be a little complicated to use. I'll see if I can whip up something for you.
Title: Re: Scrolling
Post by: AnswerSoft on August 06, 2012, 06:43:16 pm
Thanks everyone. I'll check out the link. I don't mind doing the coding if I know how to approach it. The text is going to be static. Basically I'm converting a simple informational website. There's a list of names that I need to provide when the user selects "Counselors." But with all the contact info, etc, there's more text than can fit on a single screen. So I want to allow the user to scroll down to read the rest. After I posted this earlier I did see the information in the FAQ about doing the finger swipe gestures. That may provide what I'm looking for; but first I'll visit the link.
Title: Re: Scrolling
Post by: zacho on August 06, 2012, 06:48:26 pm
@nednones, I think what he means is that he has a multi-line text that's too big to fit on screen.

@AnswerSoft, you will need both containers and touch components. Check out the link zacho gave you. That, however, might be a little complicated to use. I'll see if I can whip up something for you.

If you could that would be so cool!
Title: Re: Scrolling
Post by: AnswerSoft on August 06, 2012, 07:01:15 pm
@AnswerSoft, you will need both containers and touch components. Check out the link zacho gave you. That, however, might be a little complicated to use. I'll see if I can whip up something for you.

Thanks a lot. I just downloaded the code from the link. Looks like this will work great. If you've got a simple solution that'd be great. Otherwise, I'll look through this one. Others could benefit. I'm a newbie DragonFire guy, but I've been coding for 24 years. So I should be able to follow the original solution. I'm supposed to give a demo to the customer tomorrow.

Thanks,
Mike
Title: Re: Scrolling
Post by: xabaras on August 07, 2012, 02:10:54 am
yes, jj's scroll framework seems very good... i've tested it also on the device and it works fine...

I'd like to use it in my app where i have 3 menu/pages.. in each page i should have a scrollable list of strings with a little icon on the right of each string... and when you touch one row, something happens and the little icon could change...

Is it possible to use coral framework in order to create multiple scrollable lists in different pages? i mean... can i easily show/hide them according to the page or should i wait for a proper version with containers?

Moreover... the list of elements in every page is dynamic... i could have 10 elements... 20... and so on, i don't know in advance... so, is it possible to have dynamic lists size according to the elements amount?

many thanks
Title: Re: Scrolling
Post by: jjsanchezramirez on August 07, 2012, 08:00:51 am
I made this code before DFSDK 2.0 was released, which means there were no containers. I'm hoping to write a new version that uses containers instead of moving the whole screen. It sounds so more logical. It's going to take me a while, nonetheless.
Title: Re: Scrolling
Post by: jjsanchezramirez on August 07, 2012, 01:20:24 pm
I'm done with the basics.

This is a class in a header file. It moves containers around. No friction. No elasticity. Just drag and drop. Also, I haven't tested this feature yet, but it should work for multiple containers. Finally, it doesn't have any restraints yet, but it does have the option for vertical or horizontal scrolling.

Code: [Select]
#ifndef SIMPLE_SCROLLER
#define SIMPLE_SCROLLER

int nOldX;
int nOldY;
int nNewX;
int nNewY;

int OnTouch(int id, int event, int x, int y)
{
if (event == 1)
{
nOldX = x;
nOldY = y;
nNewX = x;
nNewY = y;
}

if (event == 2)
{
nNewX = x;
nNewY = y;
}

if (event == 3)
{
nOldX = 0;
nOldY = 0;
nNewX = 0;
nNewY = 0;
}

return id;
}

class SimpleScroller
{

private:

int m_nContainer;
int m_nTouch;
int m_nX;
int m_nY;
bool m_bHorizontalScroll;
bool m_bVerticalScroll;

public:

SimpleScroller()
{

}

void Init(int& container, int x, int y, int width, int height)
{
m_nContainer = container;
m_nTouch = TouchAdd(container, x, y, width, height, OnTouch, 0);

m_nX = ContainerGetx(container);
m_nY = ContainerGety(container);

m_bHorizontalScroll = true;
m_bVerticalScroll = true;
}

void Update()
{
if (nOldX != nNewX && m_bHorizontalScroll)
ContainerSetx(m_nContainer, m_nX+nNewX-nOldX);
else if (nOldY != nNewY && m_bVerticalScroll)
ContainerSety(m_nContainer, m_nY+nNewY-nOldY);
else
{
m_nX = ContainerGetx(m_nContainer);
m_nY = ContainerGety(m_nContainer);
}
}

void SetHorizontalScroll(bool flag)
{
m_bHorizontalScroll = flag;
}

void SetVerticalScroll(bool flag)
{
m_bVerticalScroll = flag;
}
};

#endif

This is how you would use it. To initiate a scroll component, you need a container to be scrolled and some other variables for the touch component. The last two variables are width and height, which are important to establish the boundaries of your scroller.

I think the code is pretty self explanatory. You could use this as a basis for menus, sliders, etc.

Code: [Select]
//====================================================
// App.cpp
//====================================================
#include "DragonFireSDK.h"
#include "SimpleScroller.h"

int nContainer;
SimpleScroller simpleScroller;

void AppMain()
{
nContainer = ContainerAdd(0, 0, 0);
ViewAdd(nContainer, "Images/Background.png", 0, 0);
simpleScroller.Init(nContainer, 0, 0, 320, 960);
simpleScroller.SetHorizontalScroll(false);
}

void AppExit()
{

}

void OnTimer()
{
    simpleScroller.Update();
}
Title: Re: Scrolling
Post by: jjsanchezramirez on August 07, 2012, 01:33:04 pm
Just another thing.

Any elements you might want to add within the container that have touch components of their own, such as buttons and push buttons, must be initialized after the scroller. Otherwise, the scroller's touch component will be above these elements, and you won't be able to click them.

On a similar note, you won't be able to drag the scroller when you're clicking a button. If it's just one button, it's not a big deal. However, for components such as menus, you might want to write your own class of buttons.

Here's an example.

Code: [Select]
void AppMain()
{
nContainer = ContainerAdd(0, 0, 0);

ViewAdd(nContainer, "Images/Background.png", 0, 0);

simpleScroller.Init(nContainer, 0, 0, 320, 960);
simpleScroller.SetHorizontalScroll(false);

nFont = FontAdd("Arial", "Regular", 20, 0x000000);

ButtonAdd(nContainer, "Images/RoundedButton", 8, 80, OnButton, 0);
TextAdd(nContainer, 24, 91, "Button", nFont);
}
Title: Re: Scrolling
Post by: zacho on August 07, 2012, 03:08:01 pm
Thumbs up! good scroll code  8)
Title: Re: Scrolling
Post by: jjsanchezramirez on August 07, 2012, 08:23:35 pm
I finished the simple scroller. Now you don't go out of boundaries. This is also much more easier to use than my original scroller. Containers really make things a heck of a lot easier. Also, you can now use many scrollers. You can even use a scroller within a scroller!

(http://i45.tinypic.com/2hrho46.png)

Here's an example. It shows how to use more than one scroller at the same time. It's also heavily documented, so no one should have trouble figuring out how it works.

http://www.mediafire.com/?h7b31wipm8ijx11

Here's the code for the simple scroller.

Code: [Select]
/* Copyright 2012 Juan José Sánchez Ramírez

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   Author Juan José Sánchez Ramírez
   Version 1.0
*/

#ifndef SIMPLE_SCROLLER
#define SIMPLE_SCROLLER

int nOldX;
int nOldY;
int nNewX;
int nNewY;

int nTouchId;

// This function will be called when a scroller is activated
int OnTouch(int id, int event, int x, int y)
{
// Get the ID of the container
nTouchId = id;

// Record initial coordinates when pressed down
if (event == 1)
{
nOldX = x;
nOldY = y;
nNewX = x;
nNewY = y;
}

// Record new coordinates when moving
if (event == 2)
{
nNewX = x;
nNewY = y;
}

// Erase coordinates when released
if (event == 3)
{
nOldX = 0;
nOldY = 0;
nNewX = 0;
nNewY = 0;
}

return id;
}

// This class creates a simple scroller for containers
class SimpleScroller
{
/* A scroller lets a container slide upon a portion of the screen.
   It's designed to move containers that are too big for the screen,
   both vertically and horizontally, but it can be modified to move
   smaller objects too, such as sliders. This can be achieved by
   modifying minimum and maximum ranges, using the SetMinX, SetMinY,
   SetMaxX, and SetMaxY functions.

   The scroller uses the following components:

   1. A container which contains all of the elements in the scroller.
   2. A touch component which must be at least the size of the
      entire container, which records the drag and drop actions.
   3. An ID number that allows to differentiate among scrollers,
      since all scrollers use the same OnTouch function.
*/

private:

int m_nContainer;
int m_nTouch;

int m_nX;
int m_nY;

int m_nMinX;
int m_nMinY;

int m_nMaxX;
int m_nMaxY;

bool m_bHorizontalScroll;
bool m_bVerticalScroll;

public:

// Constructor
SimpleScroller()
{

}

// This function initiates the scroller and all of its components
void Init(int& container, int x, int y, int touchWidth, int touchHeight, int id)
{
m_nContainer = container;
m_nTouch = TouchAdd(container, x, y, touchWidth, touchHeight, OnTouch, id);

m_nX = ContainerGetx(container);
m_nY = ContainerGety(container);

m_nMinX = x-touchWidth+320;
m_nMinY = y-touchHeight+480;

m_nMaxX = 0;
m_nMaxY = 0;

m_bHorizontalScroll = true;
m_bVerticalScroll = true;
}

// This function updates the scroller
void Update()
{
/* To update the scroller we're going to:

   1. Check if the x coordinate has changed. If it has, and
      if horizontal scrolling is allowed, move the container.
  If the container is out of bounds, move the container
  within bounds.

   2. Repeat for the y coordinate.

   3. If nothing has changed, then make the scroller x and y
      coordinates equal to the container's coordinates. This
  is necessary to start scrolling again.
*/

if (nOldX != nNewX && m_bHorizontalScroll)
{
ContainerSetx(m_nContainer, m_nX+nNewX-nOldX);

if (ContainerGetx(m_nContainer) < m_nMinX)
ContainerSetx(m_nContainer, m_nMinX);
if (ContainerGetx(m_nContainer) > m_nMaxX)
ContainerSetx(m_nContainer, m_nMaxX);
}
else if (nOldY != nNewY && m_bVerticalScroll)
{
ContainerSety(m_nContainer, m_nY+nNewY-nOldY);

if (ContainerGety(m_nContainer) < m_nMinY)
ContainerSety(m_nContainer, m_nMinY);
if (ContainerGety(m_nContainer) > m_nMaxY)
ContainerSety(m_nContainer, m_nMaxY);
}
else
{
m_nX = ContainerGetx(m_nContainer);
m_nY = ContainerGety(m_nContainer);
}
}

// This function sets the minimum x range
void SetMinX(int x)
{
m_nMinX = x;
}

// This function sets the minimum y range
void SetMinY(int y)
{
m_nMinY = y;
}

// This function sets the maximum x range
void SetMaxX(int x)
{
m_nMaxX = x;
}

// This function sets the maximum y range
void SetMaxY(int y)
{
m_nMaxY = y;
}

// This function sets the horizontal scroll
void SetHorizontalScroll(bool flag)
{
m_bHorizontalScroll = flag;
}

// This function sets the vertical scroll
void SetVerticalScroll(bool flag)
{
m_bVerticalScroll = flag;
}
};

#endif

Here's the code for the example. You will need the images, though.

Code: [Select]
/* Copyright 2012 Juan José Sánchez Ramírez

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   Author Juan José Sánchez Ramírez
   Version 1.0
*/

#include "DragonFireSDK.h"
#include "SimpleScroller.h"

SimpleScroller simpleScroller;
SimpleScroller sliderSimpleScroller;

int nContainer;
int nSliderContainer;

int nFont;

// This function will be called when a button is pressed
int OnButton(int id)
{
return id;
}

// This function marks the beginning of program execution
void AppMain()
{
nContainer = ContainerAdd(0, 0, 0);
nSliderContainer = ContainerAdd(nContainer, 50, 165);

nFont = FontAdd("Arial", "Regular", 20, 0x000000);

ViewAdd(0, "Images/Background.png", 0, 0);

// Initiate scroller 320x720, ID 0, horizontal scroll false
simpleScroller.Init(nContainer, 0, 0, 320, 720, 0);
simpleScroller.SetHorizontalScroll(false);

// Populate container
ButtonAdd(nContainer, "Images/RoundedButton", 8, 80, OnButton, 0);
TextAdd(nContainer, 24, 91, "Button", nFont);

ButtonAdd(nContainer, "Images/RoundedButton", 8, 595, OnButton, 1);
TextAdd(nContainer, 24, 606, "Another button", nFont);

ViewAdd(nContainer, "Images/Slider.png", 50, 165);

// Initiate scroller 25x26, ID 1, vertical scroll false
sliderSimpleScroller.Init(nSliderContainer, 0, 0, 25, 26, 1);
sliderSimpleScroller.SetVerticalScroll(false);
sliderSimpleScroller.SetMinX(50);
sliderSimpleScroller.SetMaxX(246);

// Populate slider container
ViewAdd(nSliderContainer, "Images/Handle.png", 0, 0);
}

// This function is called whenever the app terminates
void AppExit()
{

}

// This function is called 30 times per second
void OnTimer()
{
if (nTouchId == 0)
simpleScroller.Update();

if (nTouchId == 1)
sliderSimpleScroller.Update();
}
Title: Re: Scrolling
Post by: xabaras on August 08, 2012, 12:47:56 am
is it already christmas??  :o

great job jj, thank you!
Title: Re: Scrolling
Post by: jjsanchezramirez on August 08, 2012, 08:58:07 pm
Hey, xabaras, I'm really sorry, I hadn't read your comment from before.

I'm planning on making a menu super class of the scroller. I'll try adding the elements you requested: dynamic size, icons, etc. It might take a while since I have to code a new class of buttons for the scroller. Otherwise, the current buttons won't allow the scroller's touch component to be activated while the button is being pressed, and buttons take up a lot of space, so this is obviously a big issue.

Other than that, your other request has been completed. You can have multiple scrollers. You can even have scrollers inside scrollers. Deactivating the scrollers is as simple as making the container invisible, which is what you would normally do to change screens. This is because when the container becomes invisible, so does the touch component, and thus it can't be scrolled.

Also, have you tested the new code on your iPhone? I don't have an iPhone, or iPad, so I can't never really test the code. I just assume it works.
Title: Re: Scrolling
Post by: xabaras on August 09, 2012, 12:53:29 am
hi jj,
thank you, containers are very very useful... i've tried on the iphone only the first version of the scroller, not the last one... i'll test it soon and i'm sure it will perfectly work.
Meanwhile i'm trying to put dynamic contents into a scroll-list... it's a "simple" loop of inner elements (not top and bottom) and dynamic calculation of sizes and scroll lengths... it should work in some way...


Otherwise, the current buttons won't allow the scroller's touch component to be activated while the button is being pressed, and buttons take up a lot of space, so this is obviously a big issue.

Yes this could be an issue... but perhaps a solution could be something like this

(http://img815.imageshack.us/img815/9751/2hrho46.png)

where you have a simple image on the main part of the button, where you can easily touch to scroll, and the real button is only on the right part... you touch it and something happens...

What about adding the fading scrollbar on the right of the scrollable content?

Anyway, thank you and really good job!
Title: Re: Scrolling
Post by: AnswerSoft on August 09, 2012, 10:24:02 am
jj,

I want to second the "thank you" here. I've been plowing through the original code trying to get my text to scroll. For some reason all the buttons would scroll while leaving the text stationary. I think this new code should work fine, as I can just add text into the container. Thanks again. I actually wound up postponing the demo last Tuesday.

Thanks again,
Mike
Title: Re: Scrolling
Post by: xabaras on August 10, 2012, 02:19:02 pm
Another question... i have a situation like this one...

(http://img221.imageshack.us/img221/7531/shot.png)

In one of the pages of my app i have a main background-image (with a transparent area inside), some buttons on it, an input field and so on... unfortunately everything not inside a container...
Now, i'm trying to put your scroller "below" the page, in order to see it only in the transparent window.... it works, obviously... but only if i put my main background in a container too... Is there a way to avoid this? or can containers stay below only other containers?
Title: Re: Scrolling
Post by: jjsanchezramirez on August 10, 2012, 03:48:47 pm
Hey, I didn't completely understood what you meant, but I think this can be solved by putting different things on different containers. Having containers on top of other containers doesn't really matter because touch components are independent of z-order.

In this example, I added another container named GUI elements. The GUI container is above the container with the scroller. Bellow the scroller container is the background image.

Code: [Select]
/* Copyright 2012 Juan José Sánchez Ramírez

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   Author Juan José Sánchez Ramírez
   Version 1.0
*/

#include "DragonFireSDK.h"
#include "SimpleScroller.h"

SimpleScroller simpleScroller;
SimpleScroller sliderSimpleScroller;

int nContainer;
int nSliderContainer;
int nGUIContainer;

int nFont;

// This function will be called when a button is pressed
int OnButton(int id)
{
return id;
}

// This function marks the beginning of program execution
void AppMain()
{
nContainer = ContainerAdd(0, 0, 0);
nSliderContainer = ContainerAdd(nContainer, 50, 165);
nGUIContainer = ContainerAdd(0, 0, 0);

nFont = FontAdd("Arial", "Regular", 20, 0x000000);

ViewAdd(0, "Images/Background.png", 0, 0);

// Initiate scroller 320x720, ID 0, horizontal scroll false
simpleScroller.Init(nContainer, 0, 0, 320, 720, 0);
simpleScroller.SetHorizontalScroll(false);

// Populate container
ButtonAdd(nContainer, "Images/RoundedButton", 8, 80, OnButton, 0);
TextAdd(nContainer, 24, 91, "Button", nFont);

ButtonAdd(nContainer, "Images/RoundedButton", 8, 595, OnButton, 1);
TextAdd(nContainer, 24, 606, "Another button", nFont);

ViewAdd(nContainer, "Images/Slider.png", 50, 165);

// Initiate scroller 25x26, ID 1, vertical scroll false
sliderSimpleScroller.Init(nSliderContainer, 0, 0, 25, 26, 1);
sliderSimpleScroller.SetVerticalScroll(false);
sliderSimpleScroller.SetMinX(50);
sliderSimpleScroller.SetMaxX(246);

// Populate slider container
ViewAdd(nSliderContainer, "Images/Handle.png", 0, 0);

// GUI elements
ViewAdd(nGUIContainer, "Images/TopBar.png", 0, 0);
ViewAdd(nGUIContainer, "Images/Navigator.png", 0, 20);
ViewAdd(nGUIContainer, "Images/Toolbar.png", 0, 436);
}

// This function is called whenever the app terminates
void AppExit()
{

}

// This function is called 30 times per second
void OnTimer()
{
if (nTouchId == 0)
simpleScroller.Update();

if (nTouchId == 1)
sliderSimpleScroller.Update();
}

By the way, I've gone over the menu in my head and wrote some ideas.

First of all, when you touch a menu item (a button), if your coordinates remain the same, it's a click. Otherwise, you're scrolling. If you did click the button, and every button will share the same OnButton function, this should call a function, OnMenu, while passing the menu item ID number. A simple switch statement in the OnMenu function will make it easy to have different commands for each item in the menu.

Also, I think the menu should be a class composed of a scroller and buttons. It will also need two string vectors, one for labels, and one for icons. Finally, it will need a variable to hold the current number of items.

If I make a scrollbar, it's going to be a very simple, rectangular scrollbar.

I imagine using the menu like this.

Code: [Select]
int nContainer;
nContainer = ContainerAdd(0, 0, 0);

Menu menu;
menu.Init(nContainer, OnMenu);
menu.AddMenuItem("Item 0");
menu.AddMenuIcon(0, "Images/Icon.png");

I've also written a pseudoscript to add elasticity (recoil) and friction (momentum) to the scroller. Unlike the initial framework, these won't be mutually exclusive, since they work very differently.

In my head, it works. The problem is I won't be having much free time this week.
Title: Re: Scrolling
Post by: jjsanchezramirez on August 11, 2012, 08:14:38 pm
It was extenuating, but I finally managed to add recoil to the scroller. This means the containers can now behave like springs. Basically, when you're scrolling out of boundaries you still move a little bit, and when you let go the container bounces back into position.

You'll probably notice I added various functions and variables, and many nested if statements. These are self-explanatory in most cases. I also added a function to set all four boundaries or ranges at once. This function is useful in the case of small components like sliders.

Code: [Select]
/* Copyright 2012 Juan José Sánchez Ramírez

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   Author Juan José Sánchez Ramírez
   Version 1.0
*/

#ifndef DYNAMIC_SCROLLER
#define DYNAMIC_SCROLLER

int nOldX;
int nOldY;
int nNewX;
int nNewY;

int nTouchId;
int nTouchEvent;

// This function will be called when a scroller is activated
int OnTouch(int id, int event, int x, int y)
{
// Get the ID of the container
nTouchId = id;

// Get the event of the container
nTouchEvent = event;

// Record initial coordinates when pressed down
if (event == 1)
{
nOldX = x;
nOldY = y;
nNewX = x;
nNewY = y;
}

// Record new coordinates when moving
if (event == 2)
{
nNewX = x;
nNewY = y;
}

// Erase coordinates when released
if (event == 3)
{
nOldX = 0;
nOldY = 0;
nNewX = 0;
nNewY = 0;
}

return id;
}

// This function approximates a container to it's target position.
void SlideContainer(int container, int targetX, int targetY, int speed=5)
{
/* To approximate the container, we're going to do the following:

   1. We get the container's x and y positions on the screen.
   2. If the value is less than the target value, we substract the
      value from the target value. If the value is more than the
  target value, we substract the target value from the value.
   3. We divide the difference by the speed.
   4. If the result equals 0, we make it equal to 1.
   5. If the value is less than the target value, we add the result
      to the value. If the value is more than the target value, we
  substract the result from the value.
   6. Finally, we set the container's position to our x and y values.
*/

int x = ContainerGetx(container);
int y = ContainerGety(container);

if (x < targetX)
{
int n = (targetX - x) / speed;
if (n == 0) n = 1;
x += n;
}
else if (x > targetX)
{
int n = (x - targetX) / speed;
if (n == 0) n = 1;
x -= n;
}

if (y < targetY)
{
int n = (targetY - y) / speed;
if (n == 0) n = 1;
y += n;
}
else if (y > targetY)
{
int n = (y - targetY) / speed;
if (n == 0) n = 1;
y -= n;
}

ContainerSetxy(container, x, y);
}

// This class creates a simple scroller for containers
class DynamicScroller
{
/* A scroller lets a container slide upon a portion of the screen.
   It's designed to move containers that are too big for the screen,
   both vertically and horizontally, but it can be modified to move
   smaller objects too, such as sliders. This can be achieved by
   modifying minimum and maximum ranges, using the SetMinX, SetMinY,
   SetMaxX, and SetMaxY functions.

   The scroller uses the following components:

   1. A container which contains all of the elements in the scroller.
   2. A touch component which must be at least the size of the
      entire container, which records the drag and drop actions.
   3. An ID number that allows to differentiate among scrollers,
      since all scrollers use the same OnTouch function.
*/

private:

int m_nContainer;
int m_nTouch;

int m_nX;
int m_nY;

int m_nMinX;
int m_nMinY;

int m_nMaxX;
int m_nMaxY;

bool m_bHorizontalScroll;
bool m_bVerticalScroll;

bool m_bRecoil;
bool m_bFriction;

public:

// Constructor
DynamicScroller()
{

}

// This function initiates the scroller and all of its components
void Init(int& container, int x, int y, int touchWidth, int touchHeight, int id)
{
m_nContainer = container;
m_nTouch = TouchAdd(container, x, y, touchWidth, touchHeight, OnTouch, id);

m_nX = ContainerGetx(container);
m_nY = ContainerGety(container);

m_nMinX = x-touchWidth+320;
m_nMinY = y-touchHeight+480;

m_nMaxX = 0;
m_nMaxY = 0;

m_bHorizontalScroll = true;
m_bVerticalScroll = true;

m_bRecoil = true;
m_bFriction = true;
}

// This function updates the scroller
void Update()
{
/* To update the scroller we're going to:

   1. Check if the x coordinate has changed. If it has, and
      if horizontal scrolling is allowed, move the container.
  If the container is out of bounds, move the container
  within bounds.

   2. Repeat for the y coordinate.

   3. If nothing has changed, then make the scroller x and y
      coordinates equal to the container's coordinates. This
  is necessary to start scrolling again.
*/

if (nOldX != nNewX && m_bHorizontalScroll)
{
ContainerSetx(m_nContainer, m_nX+nNewX-nOldX);

if (ContainerGetx(m_nContainer) < m_nMinX)
{
if (m_bRecoil)// && m_nMinX-nNewX > 0)
ContainerSetx(m_nContainer, m_nMinX-(m_nMinX-(m_nX+nNewX-nOldX))/5);
else
ContainerSetx(m_nContainer, m_nMinX);
}

if (ContainerGetx(m_nContainer) > m_nMaxX)
{
if (m_bRecoil)// && m_nMaxX-nNewX < 0)
ContainerSetx(m_nContainer, m_nMaxX-(m_nMaxX-(m_nX+nNewX-nOldX))/5);
else
ContainerSetx(m_nContainer, m_nMaxX);
}
}
else if (nOldY != nNewY && m_bVerticalScroll)
{
ContainerSety(m_nContainer, m_nY+nNewY-nOldY);

if (ContainerGety(m_nContainer) < m_nMinY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMinY-(m_nMinY-(m_nY+nNewY-nOldY))/5);
else
ContainerSety(m_nContainer, m_nMinY);
}

if (ContainerGety(m_nContainer) > m_nMaxY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMaxY-(m_nMaxY-(m_nY+nNewY-nOldY))/5);
else
ContainerSety(m_nContainer, m_nMaxY);
}
}
else
{
m_nX = ContainerGetx(m_nContainer);
m_nY = ContainerGety(m_nContainer);

if (m_nX < m_nMinX)
SlideContainer(m_nContainer, m_nMinX, m_nY);
if (m_nY < m_nMinY)
SlideContainer(m_nContainer, m_nX, m_nMinY);
if (m_nX > m_nMaxX)
SlideContainer(m_nContainer, m_nMaxX, m_nY);
if (m_nY > m_nMaxY)
SlideContainer(m_nContainer, m_nX, m_nMaxY);
}
}

// This function sets the minimum x range
void SetMinX(int x)
{
m_nMinX = x;
}

// This function sets the minimum y range
void SetMinY(int y)
{
m_nMinY = y;
}

// This function sets the maximum x range
void SetMaxX(int x)
{
m_nMaxX = x;
}

// This function sets the maximum y range
void SetMaxY(int y)
{
m_nMaxY = y;
}

// This function sets the minimum and maximum x and y ranges
void SetBoundaries(int minX, int minY, int maxX, int maxY)
{
SetMinX(minX);
SetMinY(minY);
SetMaxX(maxX);
SetMaxY(maxY);
}

// This function sets the horizontal scroll
void SetHorizontalScroll(bool flag)
{
m_bHorizontalScroll = flag;
}

// This function sets the vertical scroll
void SetVerticalScroll(bool flag)
{
m_bVerticalScroll = flag;
}
};

#endif

Now, there is a small change in how you use this scroller. Basically, when the scroller is moving, you don't want the other scrollers to be moving as well. However, when the scroller stops moving, you want all the other scrollers to move back into position at the same time. As of this moment, I can't think of a better way to do this.

Code: [Select]
if (nTouchEvent == 2)
{
if (nTouchId == 0)
dynamicScroller.Update();
else if (nTouchId == 1)
sliderDynamicScroller.Update();
}
else
{
dynamicScroller.Update();
sliderDynamicScroller.Update();
}

Seriously, if someone has a solution to this, I'd be glad to listen.
Title: Re: Scrolling
Post by: xabaras on August 13, 2012, 04:56:23 am
Recoil works very good on the device...  ;)
Title: Re: Scrolling
Post by: stuckerj on August 15, 2012, 01:11:13 am
Hi jj,

I found a bug in your DynamicScroller code.  When I put two containers side-by-size on the same screen, and give them both a DynamicScroller, the SlideContainer logic in the Update cycle immediately moves the right one on top of the left one.  Will try to track down and fix that...  I suspect it's related to the hard-coded screen size values used for m_nMinX etc.

The SimpleScroller logic works just fine with two containers side-by-side.

Thanks,

Jeff
Title: Re: Scrolling
Post by: jjsanchezramirez on August 15, 2012, 05:11:33 pm
@stuckerj

I definitely think it's related to the screen values. It's not so much a bug. The scroller is, after all, meant to be used mainly for whole screens. That's why you can change the boundaries of the scroller with the SetBoundaries function. Try changing those, and see if you can fix it. Otherwise, hand me your code in a .zip file and I'll see if I can fix it myself.

I'll probably make a newer version of the code somewhere in the near future, which has a better way to set boundaries, and which enables screen rotation.
Title: Re: Scrolling
Post by: jjsanchezramirez on August 15, 2012, 07:27:49 pm
@stuckerj

I didn't make any changes to the scroller code. I simply modified the values in the main app, and got two scrollers working side by side. To be perfect honest, the code didn't work at first. I modified the values of the touch width, and the x boundaries, and got it working.

This was a very interesting request, and something I hadn't even thought about.

(http://i47.tinypic.com/20r2ull.png)

Code: [Select]
/* Copyright 2012 Juan José Sánchez Ramírez

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   Author Juan José Sánchez Ramírez
   Version 1.0
*/

#ifndef DYNAMIC_SCROLLER
#define DYNAMIC_SCROLLER

int nOldX;
int nOldY;
int nNewX;
int nNewY;

int nTouchId;
int nTouchEvent;

// This function will be called when a scroller is activated
int OnTouch(int id, int event, int x, int y)
{
// Get the ID of the container
nTouchId = id;

// Get the event of the container
nTouchEvent = event;

// Record initial coordinates when pressed down
if (event == 1)
{
nOldX = x;
nOldY = y;
nNewX = x;
nNewY = y;
}

// Record new coordinates when moving
if (event == 2)
{
nNewX = x;
nNewY = y;
}

// Erase coordinates when released
if (event == 3)
{
nOldX = 0;
nOldY = 0;
nNewX = 0;
nNewY = 0;
}

return id;
}

// This function approximates a container to it's target position.
void SlideContainer(int container, int targetX, int targetY, int speed)
{
/* To approximate the container, we're going to do the following:

   1. We get the container's x and y positions on the screen.
   2. If the value is less than the target value, we substract the
      value from the target value. If the value is more than the
  target value, we substract the target value from the value.
   3. We divide the difference by the speed.
   4. If the result equals 0, we make it equal to 1.
   5. If the value is less than the target value, we add the result
      to the value. If the value is more than the target value, we
  substract the result from the value.
   6. Finally, we set the container's position to our x and y values.
*/

int x = ContainerGetx(container);
int y = ContainerGety(container);

if (x < targetX)
{
int n = (targetX - x) / speed;
if (n == 0) n = 1;
x += n;
}
else if (x > targetX)
{
int n = (x - targetX) / speed;
if (n == 0) n = 1;
x -= n;
}

if (y < targetY)
{
int n = (targetY - y) / speed;
if (n == 0) n = 1;
y += n;
}
else if (y > targetY)
{
int n = (y - targetY) / speed;
if (n == 0) n = 1;
y -= n;
}

ContainerSetxy(container, x, y);
}

// This class creates a simple scroller for containers
class DynamicScroller
{
/* A scroller lets a container slide upon a portion of the screen.
   It's designed to move containers that are too big for the screen,
   both vertically and horizontally, but it can be modified to move
   smaller objects too, such as sliders. This can be achieved by
   modifying minimum and maximum ranges, using the SetMinX, SetMinY,
   SetMaxX, and SetMaxY functions, or alternatively, using the
   SetBoundaries function, which modifies all of these values at once.

   The scroller uses the following components:

   1. A container which contains all of the elements in the scroller.
   2. A touch component which must be at least the size of the
      entire container, which records the drag and drop actions.
   3. An ID number that allows to differentiate among scrollers,
      since all scrollers use the same OnTouch function.
   
   The recoil component uses the following variables:

   1. Elasticity, defined here as the property of an object to return
      to its original state after a stress. In this particular context,
  elasticity can be thought of as how fast the container returns to
  its position.
 
  Note: The lower the value, the higher the elasticity!

   2. Compliance, defined here as the inverse of elasticity. In this
      particular context, compliance can be thought of as the resistance
  of a container to move out of position.

  Note: The higher the value, the higher the compliance!
*/

private:

int m_nContainer;
int m_nTouch;

int m_nX;
int m_nY;

int m_nMinX;
int m_nMinY;

int m_nMaxX;
int m_nMaxY;

int m_nCompliance;
int m_nElasticity;

bool m_bHorizontalScroll;
bool m_bVerticalScroll;

bool m_bRecoil;

public:

// Constructor
DynamicScroller()
{

}

// This function initiates the scroller and all of its components
void Init(int& container, int x, int y, int touchWidth, int touchHeight, int id)
{
m_nContainer = container;
m_nTouch = TouchAdd(container, x, y, touchWidth, touchHeight, OnTouch, id);

m_nX = ContainerGetx(container);
m_nY = ContainerGety(container);

m_nMinX = x-touchWidth+320;
m_nMinY = y-touchHeight+480;

m_nMaxX = 0;
m_nMaxY = 0;

m_nCompliance = 10;
m_nElasticity = 2;

m_bHorizontalScroll = true;
m_bVerticalScroll = true;

m_bRecoil = true;
}

// This function updates the scroller
void Update()
{
/* To update the scroller we're going to:

   1. Check if the x coordinate has changed. If it has, and
      if horizontal scrolling is allowed, move the container.
  If the container is out of bounds, and recoil is allowed,
  move the container using compliance. If the container is
  out of bounds, and recoil is not allowed, move the
  container within bounds.

   2. Repeat for the y coordinate.

   3. If nothing has changed, then make the scroller x and y
      coordinates equal to the container's coordinates. This
  is necessary to start scrolling again. If the container
  is out of bounds, slide the container within bounds using
  elasticty.
*/

if (nOldX != nNewX && m_bHorizontalScroll)
{
ContainerSetx(m_nContainer, m_nX+nNewX-nOldX);

if (ContainerGetx(m_nContainer) < m_nMinX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMinX-(m_nMinX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMinX);
}

if (ContainerGetx(m_nContainer) > m_nMaxX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMaxX-(m_nMaxX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMaxX);
}
}
else if (nOldY != nNewY && m_bVerticalScroll)
{
ContainerSety(m_nContainer, m_nY+nNewY-nOldY);

if (ContainerGety(m_nContainer) < m_nMinY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMinY-(m_nMinY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMinY);
}

if (ContainerGety(m_nContainer) > m_nMaxY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMaxY-(m_nMaxY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMaxY);
}
}
else
{
m_nX = ContainerGetx(m_nContainer);
m_nY = ContainerGety(m_nContainer);

if (m_nX < m_nMinX)
SlideContainer(m_nContainer, m_nMinX, m_nY, m_nElasticity);
if (m_nY < m_nMinY)
SlideContainer(m_nContainer, m_nX, m_nMinY, m_nElasticity);
if (m_nX > m_nMaxX)
SlideContainer(m_nContainer, m_nMaxX, m_nY, m_nElasticity);
if (m_nY > m_nMaxY)
SlideContainer(m_nContainer, m_nX, m_nMaxY, m_nElasticity);
}
}

// This function sets the minimum x range
void SetMinX(int x)
{
m_nMinX = x;
}

// This function sets the minimum y range
void SetMinY(int y)
{
m_nMinY = y;
}

// This function sets the maximum x range
void SetMaxX(int x)
{
m_nMaxX = x;
}

// This function sets the maximum y range
void SetMaxY(int y)
{
m_nMaxY = y;
}

// This function sets the minimum and maximum x and y ranges
void SetBoundaries(int minX, int minY, int maxX, int maxY)
{
SetMinX(minX);
SetMinY(minY);
SetMaxX(maxX);
SetMaxY(maxY);
}

// This function sets the horizontal scroll
void SetHorizontalScroll(bool flag)
{
m_bHorizontalScroll = flag;
}

// This function sets the vertical scroll
void SetVerticalScroll(bool flag)
{
m_bVerticalScroll = flag;
}

// This function sets the recoil
void SetRecoil(bool flag)
{
m_bRecoil = flag;
}
};

#endif

Code: [Select]
/* Copyright 2012 Juan José Sánchez Ramírez

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   Author Juan José Sánchez Ramírez
   Version 1.0
*/

#include "DragonFireSDK.h"
#include "DynamicScroller.h"

DynamicScroller leftDynamicScroller;
DynamicScroller rightDynamicScroller;

int nLeftContainer;
int nRightContainer;

// This function marks the beginning of program execution
void AppMain()
{
nLeftContainer = ContainerAdd(0, 0, 0);
nRightContainer = ContainerAdd(0, 160, 0);

// Initiate scroller 320x720, ID 0, horizontal scroll false
leftDynamicScroller.Init(nLeftContainer, 0, 0, 160, 480, 0);
leftDynamicScroller.SetHorizontalScroll(false);
leftDynamicScroller.SetMinX(0);
leftDynamicScroller.SetMaxX(160);

// Populate left container
ViewAdd(nLeftContainer, "Images/Background1.png", 0, 0);

// Initiate scroller 320x720, ID 0, horizontal scroll false
rightDynamicScroller.Init(nRightContainer, 0, 0, 160, 480, 1);
rightDynamicScroller.SetHorizontalScroll(false);
rightDynamicScroller.SetMinX(160);
rightDynamicScroller.SetMaxX(320);

// Populate right container
ViewAdd(nRightContainer, "Images/Background2.png", 0, 0);
}

// This function is called whenever the app terminates
void AppExit()
{

}

// This function is called 30 times per second
void OnTimer()
{
if (nTouchEvent == 2)
{
if (nTouchId == 0)
leftDynamicScroller.Update();
else if (nTouchId == 1)
rightDynamicScroller.Update();
}
else
{
leftDynamicScroller.Update();
rightDynamicScroller.Update();
}
}

As usual, I leave the a ZIP file for anyone that's interested.

http://www.mediafire.com/?su353d84072daj8

By the way, I'm still working on the list menu. I've got the button almost working.
Title: Re: Scrolling
Post by: stuckerj on August 15, 2012, 08:24:42 pm
Thanks, setting the min and max properly makes it work.  Good job on the scroller.
Title: Re: Scrolling
Post by: Nico91 on September 21, 2012, 10:37:44 am
the problem is that you can't include an .h file on the build center. But this recoil is perfect! im waiting the friction!! thank you very much :)
Title: Re: Scrolling
Post by: jjsanchezramirez on September 21, 2012, 12:06:25 pm
Sure you can! I'm pretty certain it says so somewhere in the help file. I've been swamped with work, but I plan to add friction soon. I'm finally getting an iPad, so I can now actually test the code.
Title: Re: Scrolling
Post by: Nico91 on September 22, 2012, 07:43:24 am
I made a code for friction, can you add on my code your code for recoil in a simple way?
The code you've shown for the recoil is very complicated to understand, there are too many features .. you can simplify it?
Title: Re: Scrolling
Post by: jjsanchezramirez on September 22, 2012, 12:58:20 pm
It's really good code. I can definitely simplify it and add it to the other one.
Title: Re: Scrolling
Post by: jjsanchezramirez on September 22, 2012, 09:03:16 pm
I just reviewed the code, and it's excellent. Sure, it's a bit confabulated, but the core idea behind it works incredibly well. You might want to consider using comments next time. :/
It was incredibly hard to read.
Title: Re: Scrolling
Post by: Nico91 on September 23, 2012, 02:30:41 am
Yes, sorry i added it quickly. Now i added the comments.  I need the recoil in this code can you Add it?
Title: Re: Scrolling
Post by: Nico91 on September 23, 2012, 09:01:31 am
I added recoil
Title: Re: Scrolling
Post by: jjsanchezramirez on September 23, 2012, 09:56:35 am
Your recoil doesn't work well. You must divide by a constant value to make it feel "smooth". If you just add a constant value, it tends to look weird.

Tell me, what exactly is the purpose of h?
Title: Re: Scrolling
Post by: Nico91 on September 23, 2012, 10:50:03 am
I know, it isn't perfect but it is a good compromise. if you can improve it I'm very grateful, however, it is semple  decrease the speed, h mesure the times that the function is called. OnTimer is called 30 times per second, so h increases by 30 every second, putting if (h% 2 == 0) means that the if statement is called 15 times per second, h%3==0 means 10 time per second.
Title: Re: Scrolling
Post by: jjsanchezramirez on September 24, 2012, 12:20:19 am
It's still not perfect, but it's working. It's definitely a WOP, so please note the code is incomplete.

Code: [Select]
/* Copyright 2012 Juan José Sánchez Ramírez

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   Author Juan José Sánchez Ramírez
   Version 1.1
*/

#ifndef DYNAMIC_SCROLLER
#define DYNAMIC_SCROLLER

int nOldX;
int nOldY;
int nNewX;
int nNewY;

int nTouchId;
int nTouchEvent;

int i;

// This function will be called when a scroller is activated
int OnTouch(int id, int event, int x, int y)
{
// Get the ID of the container
nTouchId = id;

// Get the event of the container
nTouchEvent = event;

// Record initial coordinates when pressed down
if (event == 1)
{
nOldX = x;
nOldY = y;
nNewX = x;
nNewY = y;
}

// Record new coordinates when moving
if (event == 2)
{
nNewX = x;
nNewY = y;
}

// Erase coordinates when released
if (event == 3)
{
nOldX = 0;
nOldY = 0;
nNewX = 0;
nNewY = 0;
}

return id;
}

// This function approximates a container to it's target position.
void SlideContainer(int container, int targetX, int targetY, int speed)
{
/* To approximate the container, we're going to do the following:

   1. We get the container's x and y positions on the screen.
   2. If the value is less than the target value, we substract the
      value from the target value. If the value is more than the
  target value, we substract the target value from the value.
   3. We divide the difference by the speed.
   4. If the result equals 0, we make it equal to 1.
   5. If the value is less than the target value, we add the result
      to the value. If the value is more than the target value, we
  substract the result from the value.
   6. Finally, we set the container's position to our x and y values.
*/

int x = ContainerGetx(container);
int y = ContainerGety(container);

if (x < targetX)
{
int n = (targetX - x) / speed;
if (n == 0) n = 1;
x += n;
}
else if (x > targetX)
{
int n = (x - targetX) / speed;
if (n == 0) n = 1;
x -= n;
}

if (y < targetY)
{
int n = (targetY - y) / speed;
if (n == 0) n = 1;
y += n;
}
else if (y > targetY)
{
int n = (y - targetY) / speed;
if (n == 0) n = 1;
y -= n;
}

ContainerSetxy(container, x, y);
}

// This class creates a simple scroller for containers
class DynamicScroller
{
/* A scroller lets a container slide upon a portion of the screen.
   It's designed to move containers that are too big for the screen,
   both vertically and horizontally, but it can be modified to move
   smaller objects too, such as sliders. This can be achieved by
   modifying minimum and maximum ranges, using the SetMinX, SetMinY,
   SetMaxX, and SetMaxY functions, or alternatively, using the
   SetBoundaries function, which modifies all of these values at once.

   The scroller uses the following components:

   1. A container which contains all of the elements in the scroller.
   2. A touch component which must be at least the size of the
      entire container, which records the drag and drop actions.
   3. An ID number that allows to differentiate among scrollers,
      since all scrollers use the same OnTouch function.
   
   The recoil component uses the following variables:

   1. Elasticity, defined here as the property of an object to return
      to its original state after a stress. In this particular context,
  elasticity can be thought of as how fast the container returns to
  its position.
 
  Note: The lower the value, the higher the elasticity!

   2. Compliance, defined here as the inverse of elasticity. In this
      particular context, compliance can be thought of as the resistance
  of a container to move out of position.

  Note: The higher the value, the higher the compliance!
*/

private:

int m_nContainer;
int m_nTouch;

int m_nX;
int m_nY;

int m_nMinX;
int m_nMinY;

int m_nMaxX;
int m_nMaxY;

int m_nCompliance;
int m_nElasticity;

int m_nSpeedX;
int m_nSpeedY;

int m_anTouchX[10000];
int m_anTouchY[10000];

bool m_bHorizontalScroll;
bool m_bVerticalScroll;

bool m_bRecoil;
bool m_bFriction;

public:

// Constructor
DynamicScroller()
{

}

// This function initiates the scroller and all of its components
void Init(int& container, int x, int y, int touchWidth, int touchHeight, int id)
{
m_nContainer = container;
m_nTouch = TouchAdd(container, x, y, touchWidth, touchHeight, OnTouch, id);

m_nX = ContainerGetx(container);
m_nY = ContainerGety(container);

m_nMinX = x-touchWidth+320;
m_nMinY = y-touchHeight+480;

m_nMaxX = 0;
m_nMaxY = 0;

m_nCompliance = 10;
m_nElasticity = 2;

m_nSpeedX = 0;
m_nSpeedY = 0;

m_bHorizontalScroll = true;
m_bVerticalScroll = true;

m_bRecoil = true;
m_bFriction = false;
}

// This function updates the scroller
void Update()
{
/* To update the scroller we're going to:

   1. Check if the x coordinate has changed. If it has, and
      if horizontal scrolling is allowed, move the container.
  If the container is out of bounds, and recoil is allowed,
  move the container using compliance. If the container is
  out of bounds, and recoil is not allowed, move the
  container within bounds.

   2. Repeat for the y coordinate.

   3. If nothing has changed, then make the scroller x and y
      coordinates equal to the container's coordinates. This
  is necessary to start scrolling again. If the container
  is out of bounds, slide the container within bounds using
  elasticty.
*/

if (nOldX != nNewX && m_bHorizontalScroll)
{
ContainerSetx(m_nContainer, m_nX+nNewX-nOldX);

if (ContainerGetx(m_nContainer) < m_nMinX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMinX-(m_nMinX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMinX);
}

if (ContainerGetx(m_nContainer) > m_nMaxX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMaxX-(m_nMaxX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMaxX);
}
}

if (nOldY != nNewY && m_bVerticalScroll)
{
ContainerSety(m_nContainer, m_nY+nNewY-nOldY);

if (ContainerGety(m_nContainer) < m_nMinY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMinY-(m_nMinY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMinY);
}

if (ContainerGety(m_nContainer) > m_nMaxY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMaxY-(m_nMaxY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMaxY);
}
}

if (nOldX == nNewX && nOldY == nNewY)
{
m_nX = ContainerGetx(m_nContainer);
m_nY = ContainerGety(m_nContainer);

if (m_nX < m_nMinX)
SlideContainer(m_nContainer, m_nMinX, m_nY, m_nElasticity);
if (m_nY < m_nMinY)
SlideContainer(m_nContainer, m_nX, m_nMinY, m_nElasticity);
if (m_nX > m_nMaxX)
SlideContainer(m_nContainer, m_nMaxX, m_nY, m_nElasticity);
if (m_nY > m_nMaxY)
SlideContainer(m_nContainer, m_nX, m_nMaxY, m_nElasticity);
}

if (nTouchEvent == 1)
{
i = -1;
m_bFriction = false;
}

if (nTouchEvent == 2)
{
i++;
m_anTouchY[i] = nNewY;
}

if (nTouchEvent == 3)
{
if ((m_anTouchY[i] > m_anTouchY[i-1] &&
m_anTouchY[i] - m_anTouchY[i-1] > 1) ||
(m_anTouchY[i] < m_anTouchY[i-1] &&
m_anTouchY[i-1] - m_anTouchY[i] > 1))
m_bFriction = true;

m_nSpeedY = m_anTouchY[i-1] - m_anTouchY[i];

if (m_nSpeedY >= 10)
m_nSpeedY = 10;
if (m_nSpeedY <= -10)
m_nSpeedY = -10;
}

if (m_bFriction)
{
if (m_bVerticalScroll)
{
m_nY -= m_nSpeedY;
ContainerSety(m_nContainer, m_nY);
}

if (m_nSpeedY > 0)
m_nSpeedY--;
if (m_nSpeedY < 0)
m_nSpeedY++;

if (m_nSpeedY == 0)
m_bFriction = false;
}

nTouchEvent = -1;
}

// This function sets the minimum x range
void SetMinX(int x)
{
m_nMinX = x;
}

// This function sets the minimum y range
void SetMinY(int y)
{
m_nMinY = y;
}

// This function sets the maximum x range
void SetMaxX(int x)
{
m_nMaxX = x;
}

// This function sets the maximum y range
void SetMaxY(int y)
{
m_nMaxY = y;
}

// This function sets the minimum and maximum x and y ranges
void SetBoundaries(int minX, int minY, int maxX, int maxY)
{
SetMinX(minX);
SetMinY(minY);
SetMaxX(maxX);
SetMaxY(maxY);
}

// This function sets the horizontal scroll
void SetHorizontalScroll(bool flag)
{
m_bHorizontalScroll = flag;
}

// This function sets the vertical scroll
void SetVerticalScroll(bool flag)
{
m_bVerticalScroll = flag;
}

// This function sets the recoil
void SetRecoil(bool flag)
{
m_bRecoil = flag;
}
};

#endif
Title: Re: Scrolling
Post by: jjsanchezramirez on September 24, 2012, 12:22:57 am
By the way, it's currently not supporting multiple containers. It's an issue with the nTouchId variable. I'll fix it soon.
Title: Re: Scrolling
Post by: jjsanchezramirez on September 24, 2012, 03:48:34 am
This is what you've all been waiting for. Elasticity and friction in a single container. It works with other multiple containers. It's very easy to use.

This could use better comments, but it's done and it works beautifully. Haven't encountered any errors in the programming so far. I'm still worried about the compatibility issues when using more than two containers. Please let me know if you experience any problems.

Finally, I should thank Nico91, who wrote the original friction code.

That is to say, DragonFireSDK officially has scrolling components.

DynamicScroller.h
Code: [Select]
/* Copyright 2012 Juan José Sánchez Ramírez

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   Author Juan José Sánchez Ramírez
   Co-author Nico91 at www.DragonFireSDK.net/forums
   Version 2.0
*/

#ifndef DYNAMIC_SCROLLER
#define DYNAMIC_SCROLLER

int nOldX;
int nOldY;
int nNewX;
int nNewY;

int nTouchId;
int nTouchEvent;

// This function will be called when a scroller is activated
int OnTouch(int id, int event, int x, int y)
{
// Get the ID of the container
nTouchId = id;

// Get the event of the container
nTouchEvent = event;

// Record initial coordinates when pressed down
if (event == 1)
{
nOldX = x;
nOldY = y;
nNewX = x;
nNewY = y;
}

// Record new coordinates when moving
if (event == 2)
{
nNewX = x;
nNewY = y;
}

// Erase coordinates when released
if (event == 3)
{
nOldX = 0;
nOldY = 0;
nNewX = 0;
nNewY = 0;
}

return id;
}

// This function approximates a container to it's target position.
void SlideContainer(int container, int targetX, int targetY, int speed)
{
/* To approximate the container, we're going to do the following:

   1. We get the container's x and y positions on the screen.
   2. If the value is less than the target value, we substract the
      value from the target value. If the value is more than the
  target value, we substract the target value from the value.
   3. We divide the difference by the speed.
   4. If the result equals 0, we make it equal to 1.
   5. If the value is less than the target value, we add the result
      to the value. If the value is more than the target value, we
  substract the result from the value.
   6. Finally, we set the container's position to our x and y values.
*/

int x = ContainerGetx(container);
int y = ContainerGety(container);

if (x < targetX)
{
int n = (targetX - x) / speed;
if (n == 0) n = 1;
x += n;
}
else if (x > targetX)
{
int n = (x - targetX) / speed;
if (n == 0) n = 1;
x -= n;
}

if (y < targetY)
{
int n = (targetY - y) / speed;
if (n == 0) n = 1;
y += n;
}
else if (y > targetY)
{
int n = (y - targetY) / speed;
if (n == 0) n = 1;
y -= n;
}

ContainerSetxy(container, x, y);
}

// This class creates a simple scroller for containers
class DynamicScroller
{
/* A scroller lets a container slide upon a portion of the screen.
   It's designed to move containers that are too big for the screen,
   both vertically and horizontally, but it can be modified to move
   smaller objects too, such as sliders. This can be achieved by
   modifying minimum and maximum ranges, using the SetMinX, SetMinY,
   SetMaxX, and SetMaxY functions, or alternatively, using the
   SetBoundaries function, which modifies all of these values at once.

   The scroller uses the following components:

   1. A container which contains all of the elements in the scroller.
   2. A touch component which must be at least the size of the
      entire container, which records the drag and drop actions.
   3. An ID number that allows to differentiate among scrollers,
      since all scrollers use the same OnTouch function.
   
   The recoil component uses the following variables:

   1. Elasticity, defined here as the property of an object to return
      to its original state after a stress. In this particular context,
  elasticity can be thought of as how fast the container returns to
  its position.
 
  Note: The lower the value, the higher the elasticity!

   2. Compliance, defined here as the inverse of elasticity. In this
      particular context, compliance can be thought of as the resistance
  of a container to move out of position.

  Note: The higher the value, the higher the compliance!
   
   The friction component uses the following variables:

   1. Max Speed, defined here as the maximum sliding speed between two
      bodies, independent of the acceleration.

   2. Friction Coefficient, defined here as an empirical property of the
      containers which describes the force of friction between two bodies
  and the force pressing them together. For example, ice on steel has
  a low coefficient of friction, while rubber on pavement has a high
  coefficient of friction.

  Note: The higher the value, the higher the coefficient!
*/

private:

int m_nContainer;
int m_nTouch;

int m_nX;
int m_nY;

int m_nMinX;
int m_nMinY;

int m_nMaxX;
int m_nMaxY;

int m_nCompliance;
int m_nElasticity;

int m_nSpeedX;
int m_nSpeedY;

int m_nMaxSpeed;
int m_nFrictionCoef;

int i;

int m_anTouchX[10000];
int m_anTouchY[10000];

bool m_bHorizontalScroll;
bool m_bVerticalScroll;

bool m_bRecoil;
bool m_bFriction;

bool m_bHorizontalSliding;
bool m_bVerticalSliding;

public:

// Constructor
DynamicScroller()
{

}

// This function initiates the scroller and all of its components
void Init(int& container, int x, int y, int touchWidth, int touchHeight, int id)
{
m_nContainer = container;
m_nTouch = TouchAdd(container, x, y, touchWidth, touchHeight, OnTouch, id);

m_nX = ContainerGetx(container);
m_nY = ContainerGety(container);

m_nMinX = x-touchWidth+320;
m_nMinY = y-touchHeight+480;

m_nMaxX = 0;
m_nMaxY = 0;

m_nCompliance = 10;
m_nElasticity = 2;

m_nSpeedX = 0;
m_nSpeedY = 0;

m_nMaxSpeed = 10;
m_nFrictionCoef = 2;

m_bHorizontalScroll = true;
m_bVerticalScroll = true;

m_bRecoil = true;
m_bFriction = true;

m_bHorizontalSliding = false;
m_bVerticalSliding = false;
}

// This function updates the scroller
void Update()
{
/* To update the scroller we're going to:

   1. Check if the x coordinate has changed. If it has, and
      if horizontal scrolling is allowed, move the container.
  If the container is out of bounds, and recoil is allowed,
  move the container using compliance. If the container is
  out of bounds, and recoil is not allowed, move the
  container within bounds.

   2. Repeat for the y coordinate.

   3. If nothing has changed, then make the scroller x and y
      coordinates equal to the container's coordinates. This
  is necessary to start scrolling again. If the container
  is out of bounds, slide the container within bounds using
  elasticty.

   4. If friction is allowed, depending on the Touch Id, gather
      speed and acceleration data. If there is acceleration and
  the acceleration surpasses the coefficient of friction,
  then use the last recorded speed. Activate scrolling.

   5. Substract the speed from the current coordinate, depending
      if it's vertical or horizontal scrolling. Then terminate
  scrolling. If the container is out of boundes, slide the
  container within bounds using elasticity and set the speed
  to zero.
*/

if (nOldX != nNewX && m_bHorizontalScroll)
{
ContainerSetx(m_nContainer, m_nX+nNewX-nOldX);

if (ContainerGetx(m_nContainer) < m_nMinX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMinX-(m_nMinX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMinX);
}

if (ContainerGetx(m_nContainer) > m_nMaxX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMaxX-(m_nMaxX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMaxX);
}
}

if (nOldY != nNewY && m_bVerticalScroll)
{
ContainerSety(m_nContainer, m_nY+nNewY-nOldY);

if (ContainerGety(m_nContainer) < m_nMinY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMinY-(m_nMinY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMinY);
}

if (ContainerGety(m_nContainer) > m_nMaxY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMaxY-(m_nMaxY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMaxY);
}
}

if (nOldX == nNewX && nOldY == nNewY)
{
m_nX = ContainerGetx(m_nContainer);
m_nY = ContainerGety(m_nContainer);

if (m_nX < m_nMinX)
SlideContainer(m_nContainer, m_nMinX, m_nY, m_nElasticity);
if (m_nY < m_nMinY)
SlideContainer(m_nContainer, m_nX, m_nMinY, m_nElasticity);
if (m_nX > m_nMaxX)
SlideContainer(m_nContainer, m_nMaxX, m_nY, m_nElasticity);
if (m_nY > m_nMaxY)
SlideContainer(m_nContainer, m_nX, m_nMaxY, m_nElasticity);
}

if (m_bFriction)
{
if (nTouchEvent == 1)
{
i = 0;
m_bHorizontalSliding = false;
m_bVerticalSliding = false;
}

if (nTouchEvent == 2)
{
i++;
m_anTouchX[i] = nNewX;
m_anTouchY[i] = nNewY;
}

if (nTouchEvent == 3)
{
if ((m_anTouchX[i] > m_anTouchX[i-1] && m_anTouchX[i] - m_anTouchX[i-1] > m_nFrictionCoef) ||
(m_anTouchX[i] < m_anTouchX[i-1] && m_anTouchX[i-1] - m_anTouchX[i] > m_nFrictionCoef))
m_bHorizontalSliding = true;

if ((m_anTouchY[i] > m_anTouchY[i-1] && m_anTouchY[i] - m_anTouchY[i-1] > m_nFrictionCoef) ||
(m_anTouchY[i] < m_anTouchY[i-1] && m_anTouchY[i-1] - m_anTouchY[i] > m_nFrictionCoef))
m_bVerticalSliding = true;

m_nSpeedX = m_anTouchX[i-1] - m_anTouchX[i];
m_nSpeedY = m_anTouchY[i-1] - m_anTouchY[i];

if (m_nSpeedX >= m_nMaxSpeed)
m_nSpeedX = m_nMaxSpeed;

if (m_nSpeedX <= -m_nMaxSpeed)
m_nSpeedX = -m_nMaxSpeed;

if (m_nSpeedY >= m_nMaxSpeed)
m_nSpeedY = m_nMaxSpeed;

if (m_nSpeedY <= -m_nMaxSpeed)
m_nSpeedY = -m_nMaxSpeed;

nTouchEvent = -1;
}

if (m_bHorizontalSliding && m_bHorizontalScroll)
{
m_nX -= m_nSpeedX;

if (m_nX < m_nMinX)
m_nSpeedX = 0;

if (m_nX > m_nMaxX)
m_nSpeedX = 0;

ContainerSetx(m_nContainer, m_nX);

if (m_nSpeedX > 0)
m_nSpeedX--;

if (m_nSpeedX < 0)
m_nSpeedX++;

if (m_nSpeedX == 0)
m_bHorizontalSliding = false;
}

if (m_bVerticalSliding && m_bVerticalScroll)
{
m_nY -= m_nSpeedY;

if (m_nY < m_nMinY)
m_nSpeedY = 0;

if (m_nY > m_nMaxY)
m_nSpeedY = 0;

ContainerSety(m_nContainer, m_nY);

if (m_nSpeedY > 0)
m_nSpeedY--;

if (m_nSpeedY < 0)
m_nSpeedY++;

if (m_nSpeedY == 0)
m_bVerticalSliding = false;
}
}
}

// This function sets the minimum x range
void SetMinX(int x)
{
m_nMinX = x;
}

// This function sets the minimum y range
void SetMinY(int y)
{
m_nMinY = y;
}

// This function sets the maximum x range
void SetMaxX(int x)
{
m_nMaxX = x;
}

// This function sets the maximum y range
void SetMaxY(int y)
{
m_nMaxY = y;
}

// This function sets the minimum and maximum x and y ranges
void SetBoundaries(int minX, int minY, int maxX, int maxY)
{
SetMinX(minX);
SetMinY(minY);
SetMaxX(maxX);
SetMaxY(maxY);
}

// This function sets the horizontal scroll
void SetHorizontalScroll(bool flag)
{
m_bHorizontalScroll = flag;
}

// This function sets the vertical scroll
void SetVerticalScroll(bool flag)
{
m_bVerticalScroll = flag;
}

// This function sets the recoil
void SetRecoil(bool flag)
{
m_bRecoil = flag;
}

// This function sets the friction
void SetFriction(bool flag)
{
m_bFriction = flag;
}
};

#endif

App.cpp
Code: [Select]
/* Copyright 2012 Juan José Sánchez Ramírez

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   Author Juan José Sánchez Ramírez
   Version 1.0
*/

#include "DragonFireSDK.h"
#include "DynamicScroller.h"

DynamicScroller dynamicScroller;
DynamicScroller sliderDynamicScroller;

int nContainer;
int nSliderContainer;
int nGUIContainer;

int nFont;

// This function will be called when a button is pressed
int OnButton(int id)
{
return id;
}

// This function marks the beginning of program execution
void AppMain()
{
nContainer = ContainerAdd(0, 0, 0);
nSliderContainer = ContainerAdd(nContainer, 50, 165);
nGUIContainer = ContainerAdd(0, 0, 0);

nFont = FontAdd("Arial", "Regular", 20, 0x000000);

ViewAdd(0, "Images/Background.png", 0, 0);

// Initiate scroller 320x720, ID 0, horizontal scroll false
dynamicScroller.Init(nContainer, 0, 0, 320, 720, 0);
dynamicScroller.SetHorizontalScroll(false);

// Populate container
ButtonAdd(nContainer, "Images/RoundedButton", 8, 80, OnButton, 0);
TextAdd(nContainer, 24, 91, "Button", nFont);

ButtonAdd(nContainer, "Images/RoundedButton", 8, 595, OnButton, 1);
TextAdd(nContainer, 24, 606, "Another button", nFont);

ViewAdd(nContainer, "Images/Slider.png", 50, 165);

// Initiate scroller 25x26, ID 1, vertical scroll false
sliderDynamicScroller.Init(nSliderContainer, 0, 0, 25, 26, 1);
sliderDynamicScroller.SetVerticalScroll(false);
sliderDynamicScroller.SetBoundaries(50, 165, 246, 165);

// Populate slider container
ViewAdd(nSliderContainer, "Images/Handle.png", 0, 0);

// GUI elements
ViewAdd(nGUIContainer, "Images/TopBar.png", 0, 0);
ViewAdd(nGUIContainer, "Images/Navigator.png", 0, 20);
ViewAdd(nGUIContainer, "Images/Toolbar.png", 0, 436);
}

// This function is called whenever the app terminates
void AppExit()
{

}

// This function is called 30 times per second
void OnTimer()
{
if (nTouchEvent == 2)
{
if (nTouchId == 0)
dynamicScroller.Update();
else if (nTouchId == 1)
sliderDynamicScroller.Update();
}
else
{
dynamicScroller.Update();
sliderDynamicScroller.Update();
}
}
Title: Re: Scrolling
Post by: xabaras on September 24, 2012, 05:36:35 am
Argh... i've uploaded my new app on the appstore a few days ago... i would have added friction very very willingly...   :)
Thank you  jj and nico... it works very well... and it works on the device too.
I'll sure add it in some update of the app (even if it probably will never be published...  ???)

good job!
Title: Re: Scrolling
Post by: Nico91 on September 24, 2012, 05:47:56 am
Great job jj. Can you Add friction and recoil to my code for zoom in a photo?

http://dragonfiresdk.net/forum/index.php?topic=293.0

Title: Re: Scrolling
Post by: jjsanchezramirez on September 24, 2012, 10:57:39 am
I don't have a device as of the moment, so I can't test the zoom function. Anyhow, what do you mean adding friction and recoil?
Title: Re: Scrolling
Post by: Nico91 on September 24, 2012, 11:24:33 am
You don't have to test the zoom, i need only the friction and the recoil when you move the image.
Title: Re: Scrolling
Post by: jjsanchezramirez on September 24, 2012, 12:24:26 pm
Perhaps if we modify the DynamicScroller.h code to use an image instead of a container. I'm not entirely sure this would work. I'd try it myself but I'm a bit swamped with work right now.
Title: Re: Scrolling
Post by: jjsanchezramirez on September 24, 2012, 08:45:56 pm
So this is the newest and probably final version of the dynamic scroller for containers. I added a momentum variable which increases the time it takes for a sliding container to stop. The bigger the momentum, the longer it takes to stop. Everything is explained in detail in the comments. So far, it works just fine.

Please let me know if you see any bugs.

Code: [Select]
/* Copyright 2012 Juan José Sánchez Ramírez

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   Author Juan José Sánchez Ramírez
   Co-author Nico91 at www.dragonfiresdk.net/forums
   Version 2.1
*/

#ifndef DYNAMIC_SCROLLER
#define DYNAMIC_SCROLLER

int nOldX;
int nOldY;
int nNewX;
int nNewY;

int nTouchId;
int nTouchEvent;

// This function will be called when a scroller is activated
int OnTouch(int id, int event, int x, int y)
{
// Get the ID of the container
nTouchId = id;

// Get the event of the container
nTouchEvent = event;

// Record initial coordinates when pressed down
if (event == 1)
{
nOldX = x;
nOldY = y;
nNewX = x;
nNewY = y;
}

// Record new coordinates when moving
if (event == 2)
{
nNewX = x;
nNewY = y;
}

// Erase coordinates when released
if (event == 3)
{
nOldX = 0;
nOldY = 0;
nNewX = 0;
nNewY = 0;
}

return id;
}

// This function approximates a container to it's target position.
void SlideContainer(int container, int targetX, int targetY, int speed)
{
/* To approximate the container, we're going to do the following:

   1. We get the container's x and y positions on the screen.
   2. If the value is less than the target value, we substract the
      value from the target value. If the value is more than the
  target value, we substract the target value from the value.
   3. We divide the difference by the speed.
   4. If the result equals 0, we make it equal to 1.
   5. If the value is less than the target value, we add the result
      to the value. If the value is more than the target value, we
  substract the result from the value.
   6. Finally, we set the container's position to our x and y values.
*/

int x = ContainerGetx(container);
int y = ContainerGety(container);

if (x < targetX)
{
int n = (targetX - x) / speed;
if (n == 0) n = 1;
x += n;
}
else if (x > targetX)
{
int n = (x - targetX) / speed;
if (n == 0) n = 1;
x -= n;
}

if (y < targetY)
{
int n = (targetY - y) / speed;
if (n == 0) n = 1;
y += n;
}
else if (y > targetY)
{
int n = (y - targetY) / speed;
if (n == 0) n = 1;
y -= n;
}

ContainerSetxy(container, x, y);
}

// This class creates a simple scroller for containers
class DynamicScroller
{
/* A scroller lets a container slide upon a portion of the screen.
   It's designed to move containers that are too big for the screen,
   both vertically and horizontally, but it can be modified to move
   smaller objects too, such as sliders. This can be achieved by
   modifying minimum and maximum ranges, using the SetMinX, SetMinY,
   SetMaxX, and SetMaxY functions, or alternatively, using the
   SetBoundaries function, which modifies all of these values at once.

   The scroller uses the following components:

   1. A container which contains all of the elements in the scroller.
   2. A touch component which must be at least the size of the
      entire container, which records the drag and drop actions.
   3. An ID number that allows to differentiate among scrollers,
      since all scrollers use the same OnTouch function.
   
   The recoil component uses the following variables:

   1. Elasticity, defined here as the property of an object to return
      to its original state after a stress. In this particular context,
  elasticity can be thought of as how fast the container returns to
  its position.
 
  Note: The lower the value, the higher the elasticity!

   2. Compliance, defined here as the inverse of elasticity. In this
      particular context, compliance can be thought of as the resistance
  of a container to move out of position.

  Note: The higher the value, the higher the compliance!
   
   The friction component uses the following variables:

   1. Max Speed, defined here as the maximum sliding speed between two
      bodies, independent of the acceleration.

   2. Friction Coefficient, defined here as an empirical property of the
      containers which describes the force of friction between two bodies
  and the force pressing them together. For example, ice on steel has
  a low coefficient of friction, while rubber on pavement has a high
  coefficient of friction.

   3. Momentum, defined here as the property of containers to continue
      moving until stopped by a force of friction. The greater the
  momentum of a container, the stronger the force of friction that
  is required to stop the container.
*/

private:

int m_nContainer;
int m_nTouch;

int m_nX;
int m_nY;

int m_nMinX;
int m_nMinY;

int m_nMaxX;
int m_nMaxY;

int m_nCompliance;
int m_nElasticity;

int m_nSpeedX;
int m_nSpeedY;

int m_nMaxSpeed;
int m_nFrictionCoef;
int m_nMomentum;

int i;
int j;

int m_anTouchX[10000];
int m_anTouchY[10000];

bool m_bHorizontalScroll;
bool m_bVerticalScroll;

bool m_bRecoil;
bool m_bFriction;

bool m_bHorizontalSliding;
bool m_bVerticalSliding;

public:

// Constructor
DynamicScroller()
{

}

// This function initiates the scroller and all of its components
void Init(int& container, int x, int y, int touchWidth, int touchHeight, int id)
{
m_nContainer = container;
m_nTouch = TouchAdd(container, x, y, touchWidth, touchHeight, OnTouch, id);

m_nX = ContainerGetx(container);
m_nY = ContainerGety(container);

m_nMinX = x-touchWidth+320;
m_nMinY = y-touchHeight+480;

m_nMaxX = 0;
m_nMaxY = 0;

m_nCompliance = 10;
m_nElasticity = 2;

m_nSpeedX = 0;
m_nSpeedY = 0;

m_nMaxSpeed = 40;
m_nFrictionCoef = 2;
m_nMomentum = 3;

m_bHorizontalScroll = true;
m_bVerticalScroll = true;

m_bRecoil = true;
m_bFriction = true;

m_bHorizontalSliding = false;
m_bVerticalSliding = false;
}

// This function updates the scroller
void Update()
{
/* To update the scroller we're going to:

   1. Check if the x coordinate has changed. If it has, and
      if horizontal scrolling is allowed, move the container.
  If the container is out of bounds, and recoil is allowed,
  move the container using compliance. If the container is
  out of bounds, and recoil is not allowed, move the
  container within bounds.

   2. Repeat for the y coordinate.

   3. If nothing has changed, then make the scroller x and y
      coordinates equal to the container's coordinates. This
  is necessary to start scrolling again. If the container
  is out of bounds, slide the container within bounds using
  elasticty.

   4. If friction is allowed, and if pressing down, set horizontal
      and vertical sliding off; if moving, store the x and y
  coordinates in an array; if pressing up, check if there is
  vertical or horizontal acceleration and if the acceleration
  surpasses the coefficient of friction. If there is, set
  sliding on.
   
   5. Vertical and horizontal speed is calculated as the last
      recorded x and y coordinates minus the next to last recorded
  coordinates. If speed exceeds maximum speed, set speed to
  maximum speed.

   6. If horizontal sliding is on, and  if horizontal scrolling is
      allowed, substract the horizontal speed from the x coordinate.
  If the coordinate is out of bounds, set the speed to zero.
  Move the container horizontally. If the frame count is divisble
  by the momentum, and if speed is greater than zero, substract
  one from the speed, thus creating friction. If the speed is
  equal to zero, set horizontal sliding off.

   7. Repeat for vertical sliding.
*/

if (nOldX != nNewX && m_bHorizontalScroll)
{
ContainerSetx(m_nContainer, m_nX+nNewX-nOldX);

if (ContainerGetx(m_nContainer) < m_nMinX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMinX-(m_nMinX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMinX);
}

if (ContainerGetx(m_nContainer) > m_nMaxX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMaxX-(m_nMaxX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMaxX);
}
}

if (nOldY != nNewY && m_bVerticalScroll)
{
ContainerSety(m_nContainer, m_nY+nNewY-nOldY);

if (ContainerGety(m_nContainer) < m_nMinY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMinY-(m_nMinY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMinY);
}

if (ContainerGety(m_nContainer) > m_nMaxY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMaxY-(m_nMaxY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMaxY);
}
}

if (nOldX == nNewX && nOldY == nNewY)
{
m_nX = ContainerGetx(m_nContainer);
m_nY = ContainerGety(m_nContainer);

if (m_nX < m_nMinX)
SlideContainer(m_nContainer, m_nMinX, m_nY, m_nElasticity);
if (m_nY < m_nMinY)
SlideContainer(m_nContainer, m_nX, m_nMinY, m_nElasticity);
if (m_nX > m_nMaxX)
SlideContainer(m_nContainer, m_nMaxX, m_nY, m_nElasticity);
if (m_nY > m_nMaxY)
SlideContainer(m_nContainer, m_nX, m_nMaxY, m_nElasticity);
}

if (m_bFriction)
{
j++;

if (nTouchEvent == 1)
{
i = 0;
m_bHorizontalSliding = false;
m_bVerticalSliding = false;
}

if (nTouchEvent == 2)
{
i++;
m_anTouchX[i] = nNewX;
m_anTouchY[i] = nNewY;
}

if (nTouchEvent == 3)
{
j = 0;

if ((m_anTouchX[i] > m_anTouchX[i-1] && m_anTouchX[i] - m_anTouchX[i-1] > m_nFrictionCoef) ||
(m_anTouchX[i] < m_anTouchX[i-1] && m_anTouchX[i-1] - m_anTouchX[i] > m_nFrictionCoef))
m_bHorizontalSliding = true;

if ((m_anTouchY[i] > m_anTouchY[i-1] && m_anTouchY[i] - m_anTouchY[i-1] > m_nFrictionCoef) ||
(m_anTouchY[i] < m_anTouchY[i-1] && m_anTouchY[i-1] - m_anTouchY[i] > m_nFrictionCoef))
m_bVerticalSliding = true;

m_nSpeedX = m_anTouchX[i-1] - m_anTouchX[i];
m_nSpeedY = m_anTouchY[i-1] - m_anTouchY[i];

if (m_nSpeedX >= m_nMaxSpeed)
m_nSpeedX = m_nMaxSpeed;

if (m_nSpeedX <= -m_nMaxSpeed)
m_nSpeedX = -m_nMaxSpeed;

if (m_nSpeedY >= m_nMaxSpeed)
m_nSpeedY = m_nMaxSpeed;

if (m_nSpeedY <= -m_nMaxSpeed)
m_nSpeedY = -m_nMaxSpeed;

nTouchEvent = -1;
}

if (m_bHorizontalSliding && m_bHorizontalScroll)
{
m_nX -= m_nSpeedX;

if (m_nX < m_nMinX || m_nX > m_nMaxX)
m_nSpeedX = 0;

ContainerSetx(m_nContainer, m_nX);

if (j % m_nMomentum == 0 && m_nSpeedX > 0)
m_nSpeedX--;

if (j % m_nMomentum == 0 && m_nSpeedX < 0)
m_nSpeedX++;

if (m_nSpeedX == 0)
m_bHorizontalSliding = false;
}

if (m_bVerticalSliding && m_bVerticalScroll)
{
m_nY -= m_nSpeedY;

if (m_nY < m_nMinY || m_nY > m_nMaxY)
m_nSpeedY = 0;

ContainerSety(m_nContainer, m_nY);

if (j % m_nMomentum == 0 && m_nSpeedY > 0)
m_nSpeedY--;

if (j % m_nMomentum == 0 && m_nSpeedY < 0)
m_nSpeedY++;

if (m_nSpeedY == 0)
m_bVerticalSliding = false;
}
}
}

// This function sets the minimum x range
void SetMinX(int x)
{
m_nMinX = x;
}

// This function sets the minimum y range
void SetMinY(int y)
{
m_nMinY = y;
}

// This function sets the maximum x range
void SetMaxX(int x)
{
m_nMaxX = x;
}

// This function sets the maximum y range
void SetMaxY(int y)
{
m_nMaxY = y;
}

// This function sets the minimum and maximum x and y ranges
void SetBoundaries(int minX, int minY, int maxX, int maxY)
{
SetMinX(minX);
SetMinY(minY);
SetMaxX(maxX);
SetMaxY(maxY);
}

// This function sets the horizontal scroll
void SetHorizontalScroll(bool flag)
{
m_bHorizontalScroll = flag;
}

// This function sets the vertical scroll
void SetVerticalScroll(bool flag)
{
m_bVerticalScroll = flag;
}

// This function sets the recoil
void SetRecoil(bool flag)
{
m_bRecoil = flag;
}

// This function sets the friction
void SetFriction(bool flag)
{
m_bFriction = flag;
}
};

#endif
Title: Re: Scrolling
Post by: jjsanchezramirez on September 26, 2012, 07:42:49 pm
Small update. Fixed a bug when scrolling out of bounds. It was accelerating when it shouldn't for a split frame. It works perfectly well on the simulator and device. I also tried to tweak the values to make them the most similar to native apps.

Code: [Select]
/* Copyright 2012 Juan José Sánchez Ramírez

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   Author Juan José Sánchez Ramírez
   Co-author Nico91 at www.dragonfiresdk.net/forums
   Version 2.1.1
*/

#ifndef DYNAMIC_SCROLLER
#define DYNAMIC_SCROLLER

int nOldX;
int nOldY;
int nNewX;
int nNewY;

int nTouchId;
int nTouchEvent;

// This function will be called when a scroller is activated
int OnTouch(int id, int event, int x, int y)
{
// Get the ID of the container
nTouchId = id;

// Get the event of the container
nTouchEvent = event;

// Record initial coordinates when pressed down
if (event == 1)
{
nOldX = x;
nOldY = y;
nNewX = x;
nNewY = y;
}

// Record new coordinates when moving
if (event == 2)
{
nNewX = x;
nNewY = y;
}

// Erase coordinates when released
if (event == 3)
{
nOldX = 0;
nOldY = 0;
nNewX = 0;
nNewY = 0;
}

return id;
}

// This function approximates a container to it's target position.
void SlideContainer(int container, int targetX, int targetY, int speed)
{
/* To approximate the container, we're going to do the following:

   1. We get the container's x and y positions on the screen.
   2. If the value is less than the target value, we substract the
      value from the target value. If the value is more than the
  target value, we substract the target value from the value.
   3. We divide the difference by the speed.
   4. If the result equals 0, we make it equal to 1.
   5. If the value is less than the target value, we add the result
      to the value. If the value is more than the target value, we
  substract the result from the value.
   6. Finally, we set the container's position to our x and y values.
*/

int x = ContainerGetx(container);
int y = ContainerGety(container);

if (x < targetX)
{
int n = (targetX - x) / speed;
if (n == 0) n = 1;
x += n;
}
else if (x > targetX)
{
int n = (x - targetX) / speed;
if (n == 0) n = 1;
x -= n;
}

if (y < targetY)
{
int n = (targetY - y) / speed;
if (n == 0) n = 1;
y += n;
}
else if (y > targetY)
{
int n = (y - targetY) / speed;
if (n == 0) n = 1;
y -= n;
}

ContainerSetxy(container, x, y);
}

// This class creates a simple scroller for containers
class DynamicScroller
{
/* A scroller lets a container slide upon a portion of the screen.
   It's designed to move containers that are too big for the screen,
   both vertically and horizontally, but it can be modified to move
   smaller objects too, such as sliders. This can be achieved by
   modifying minimum and maximum ranges, using the SetMinX, SetMinY,
   SetMaxX, and SetMaxY functions, or alternatively, using the
   SetBoundaries function, which modifies all of these values at once.

   The scroller uses the following components:

   1. A container which contains all of the elements in the scroller.
   2. A touch component which must be at least the size of the
      entire container, which records the drag and drop actions.
   3. An ID number that allows to differentiate among scrollers,
      since all scrollers use the same OnTouch function.
   
   The recoil component uses the following variables:

   1. Elasticity, defined here as the property of an object to return
      to its original state after a stress. In this particular context,
  elasticity can be thought of as how fast the container returns to
  its position.
 
  Note: The lower the value, the higher the elasticity!

   2. Compliance, defined here as the inverse of elasticity. In this
      particular context, compliance can be thought of as the resistance
  of a container to move out of position.

  Note: The higher the value, the higher the compliance!
   
   The friction component uses the following variables:

   1. Max Speed, defined here as the maximum sliding speed between two
      bodies, independent of the acceleration.

   2. Friction Coefficient, defined here as an empirical property of the
      containers which describes the force of friction between two bodies
  and the force pressing them together. For example, ice on steel has
  a low coefficient of friction, while rubber on pavement has a high
  coefficient of friction.

   3. Momentum, defined here as the property of containers to continue
      moving until stopped by a force of friction. The greater the
  momentum of a container, the stronger the force of friction that
  is required to stop the container.
*/

private:

int m_nContainer;
int m_nTouch;

int m_nX;
int m_nY;

int m_nMinX;
int m_nMinY;

int m_nMaxX;
int m_nMaxY;

int m_nCompliance;
int m_nElasticity;

int m_nSpeedX;
int m_nSpeedY;

int m_nMaxSpeed;
int m_nFrictionCoef;
int m_nMomentum;

int i;
int j;

int m_anTouchX[10000];
int m_anTouchY[10000];

bool m_bHorizontalScroll;
bool m_bVerticalScroll;

bool m_bRecoil;
bool m_bFriction;

bool m_bHorizontalSliding;
bool m_bVerticalSliding;

public:

// Constructor
DynamicScroller()
{

}

// This function initiates the scroller and all of its components
void Init(int& container, int x, int y, int touchWidth, int touchHeight, int id)
{
m_nContainer = container;
m_nTouch = TouchAdd(container, x, y, touchWidth, touchHeight, OnTouch, id);

m_nX = ContainerGetx(container);
m_nY = ContainerGety(container);

m_nMinX = x-touchWidth+320;
m_nMinY = y-touchHeight+480;

m_nMaxX = 0;
m_nMaxY = 0;

m_nCompliance = 1;
m_nElasticity = 2;

m_nSpeedX = 0;
m_nSpeedY = 0;

m_nMaxSpeed = 40;
m_nFrictionCoef = 2;
m_nMomentum = 3;

m_bHorizontalScroll = true;
m_bVerticalScroll = true;

m_bRecoil = true;
m_bFriction = true;

m_bHorizontalSliding = false;
m_bVerticalSliding = false;
}

// This function updates the scroller
void Update()
{
/* To update the scroller we're going to:

   1. Check if the x coordinate has changed. If it has, and
      if horizontal scrolling is allowed, move the container.
  If the container is out of bounds, and recoil is allowed,
  move the container using compliance. If the container is
  out of bounds, and recoil is not allowed, move the
  container within bounds.

   2. Repeat for the y coordinate.

   3. If nothing has changed, then make the scroller x and y
      coordinates equal to the container's coordinates. This
  is necessary to start scrolling again. If the container
  is out of bounds, slide the container within bounds using
  elasticty.

   4. If friction is allowed, and if pressing down, set horizontal
      and vertical sliding off; if moving, store the x and y
  coordinates in an array; if pressing up, check if there is
  vertical or horizontal acceleration and if the acceleration
  surpasses the coefficient of friction. If there is, set
  sliding on.
   
   5. Vertical and horizontal speed is calculated as the last
      recorded x and y coordinates minus the next to last recorded
  coordinates. If speed exceeds maximum speed, set speed to
  maximum speed.

   6. If horizontal sliding is on, if horizontal scrolling is allowed,
      and if the coordinate is out of bounds, set the speed to zero.
  Otherwise, substract the horizontal speed from the x coordinate.
  Move the container horizontally. If the frame count is divisble
  by the momentum, and if speed is greater than zero, substract
  one from the speed, thus creating friction. If the speed is
  equal to zero, set horizontal sliding off.

   7. Repeat for vertical sliding.
*/

if (nOldX != nNewX && m_bHorizontalScroll)
{
ContainerSetx(m_nContainer, m_nX+nNewX-nOldX);

if (ContainerGetx(m_nContainer) < m_nMinX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMinX-(m_nMinX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMinX);
}

if (ContainerGetx(m_nContainer) > m_nMaxX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMaxX-(m_nMaxX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMaxX);
}
}

if (nOldY != nNewY && m_bVerticalScroll)
{
ContainerSety(m_nContainer, m_nY+nNewY-nOldY);

if (ContainerGety(m_nContainer) < m_nMinY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMinY-(m_nMinY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMinY);
}

if (ContainerGety(m_nContainer) > m_nMaxY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMaxY-(m_nMaxY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMaxY);
}
}

if (nOldX == nNewX && nOldY == nNewY)
{
m_nX = ContainerGetx(m_nContainer);
m_nY = ContainerGety(m_nContainer);

if (m_nX < m_nMinX)
SlideContainer(m_nContainer, m_nMinX, m_nY, m_nElasticity);
if (m_nY < m_nMinY)
SlideContainer(m_nContainer, m_nX, m_nMinY, m_nElasticity);
if (m_nX > m_nMaxX)
SlideContainer(m_nContainer, m_nMaxX, m_nY, m_nElasticity);
if (m_nY > m_nMaxY)
SlideContainer(m_nContainer, m_nX, m_nMaxY, m_nElasticity);
}

if (m_bFriction)
{
j++;

if (nTouchEvent == 1)
{
i = 0;
m_bHorizontalSliding = false;
m_bVerticalSliding = false;
}

if (nTouchEvent == 2)
{
i++;
m_anTouchX[i] = nNewX;
m_anTouchY[i] = nNewY;
}

if (nTouchEvent == 3)
{
j = 0;

if ((m_anTouchX[i] > m_anTouchX[i-1] && m_anTouchX[i] - m_anTouchX[i-1] > m_nFrictionCoef) ||
(m_anTouchX[i] < m_anTouchX[i-1] && m_anTouchX[i-1] - m_anTouchX[i] > m_nFrictionCoef))
m_bHorizontalSliding = true;

if ((m_anTouchY[i] > m_anTouchY[i-1] && m_anTouchY[i] - m_anTouchY[i-1] > m_nFrictionCoef) ||
(m_anTouchY[i] < m_anTouchY[i-1] && m_anTouchY[i-1] - m_anTouchY[i] > m_nFrictionCoef))
m_bVerticalSliding = true;

m_nSpeedX = m_anTouchX[i-1] - m_anTouchX[i];
m_nSpeedY = m_anTouchY[i-1] - m_anTouchY[i];

if (m_nSpeedX >= m_nMaxSpeed)
m_nSpeedX = m_nMaxSpeed;

if (m_nSpeedX <= -m_nMaxSpeed)
m_nSpeedX = -m_nMaxSpeed;

if (m_nSpeedY >= m_nMaxSpeed)
m_nSpeedY = m_nMaxSpeed;

if (m_nSpeedY <= -m_nMaxSpeed)
m_nSpeedY = -m_nMaxSpeed;

nTouchEvent = -1;
}

if (m_bHorizontalSliding && m_bHorizontalScroll)
{
if (m_nX < m_nMinX || m_nX > m_nMaxX)
m_nSpeedX = 0;
else
m_nX -= m_nSpeedX;

ContainerSetx(m_nContainer, m_nX);

if (j % m_nMomentum == 0 && m_nSpeedX > 0)
m_nSpeedX--;

if (j % m_nMomentum == 0 && m_nSpeedX < 0)
m_nSpeedX++;

if (m_nSpeedX == 0)
m_bHorizontalSliding = false;
}

if (m_bVerticalSliding && m_bVerticalScroll)
{
if (m_nY < m_nMinY || m_nY > m_nMaxY)
m_nSpeedY = 0;
else
m_nY -= m_nSpeedY;

ContainerSety(m_nContainer, m_nY);

if (j % m_nMomentum == 0 && m_nSpeedY > 0)
m_nSpeedY--;

if (j % m_nMomentum == 0 && m_nSpeedY < 0)
m_nSpeedY++;

if (m_nSpeedY == 0)
m_bVerticalSliding = false;
}
}
}

// This function sets the minimum x range
void SetMinX(int x)
{
m_nMinX = x;
}

// This function sets the minimum y range
void SetMinY(int y)
{
m_nMinY = y;
}

// This function sets the maximum x range
void SetMaxX(int x)
{
m_nMaxX = x;
}

// This function sets the maximum y range
void SetMaxY(int y)
{
m_nMaxY = y;
}

// This function sets the minimum and maximum x and y ranges
void SetBoundaries(int minX, int minY, int maxX, int maxY)
{
SetMinX(minX);
SetMinY(minY);
SetMaxX(maxX);
SetMaxY(maxY);
}

// This function sets the horizontal scroll
void SetHorizontalScroll(bool flag)
{
m_bHorizontalScroll = flag;
}

// This function sets the vertical scroll
void SetVerticalScroll(bool flag)
{
m_bVerticalScroll = flag;
}

// This function sets the recoil
void SetRecoil(bool flag)
{
m_bRecoil = flag;
}

// This function sets the friction
void SetFriction(bool flag)
{
m_bFriction = flag;
}
};

#endif
Title: Re: Scrolling
Post by: zacho on October 18, 2012, 03:07:02 pm
Can you upload the image files you have used in this example, for reference of what the slider looks like?
Title: Re: Scrolling
Post by: niro on October 31, 2012, 10:29:18 am
nice scrolling. hmm how can i add "TouchAdd" than auto TouchSetxy according to the container y moving???
Title: Re: Scrolling
Post by: jjsanchezramirez on November 02, 2012, 11:25:14 pm
nice scrolling. hmm how can i add "TouchAdd" than auto TouchSetxy according to the container y moving???

I'm sorry for the late response. I did not understand this question at all.
Title: Re: Scrolling
Post by: Merkler on November 29, 2012, 12:03:13 am
Hi jjsanchezramirez, 
first big thanks for your great work!

I used youre code in my firt Iphone App and i have 2 big Problems with it.
Maybe you can help me.
First if i populate the scrolling container with Buttons i cant scroll because always button get´s klicked.

Second is that  when i cklick on a button a new container appeares with text in it.
In the Simulator it runs nearly perfect but on the phone the Textfields stay empty.
I put the code in here maybe you can help me.

Code: [Select]
/* Copyright 2012 Juan José Sánchez Ramírez

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   Author Juan José Sánchez Ramírez
   Co-author Nico91 at www.dragonfiresdk.net/forums
   Version 2.1
*/
#include "DragonFireSDK.h"
#include "DynamicScroller.h"

DynamicScroller dynamicScroller;
DynamicScroller sliderDynamicScroller;

int nContainer;
int nSliderContainer;
int nGUIContainer;
int landcontainer;
int txtcnt;
int nFont;
int backcn;
char msg1[200] = "Verbindungsaufbau:";
char msg2[100] = "An ab 61. Minute:";
char msg3[100] = "Abgehend:";
char msg4[100] = "SMS:";
int eu;
// land
int aufbau;
int an;
int ab;
int sms;
int daten;
int n2Font;

// This function will be called when a button is pressed
int OnButton(int id)
{
if (id==1) //eu
{


  TextSetText(aufbau,"Verbindungsaufbau");
TextSetText(an,"An ab 61. Minute");
TextSetText(ab,"Abgehend");
TextSetText(sms,"SMS");
ContainerSety(landcontainer, 0);
ContainerSetx(backcn, 0);
ContainerSetx(txtcnt,0);
ContainerSetVisible(nContainer,0);*/



   
   }

if (id==2) //Deutschland
{
ContainerSety(landcontainer, 0);
ContainerSetx(backcn, 0);
ContainerSetx(txtcnt,0);
ContainerSetVisible(nContainer,0);
//sprintf(msg,"Verbindungsaufbau:");
TextSetText(aufbau,msg1);
//sprintf(msg,"An ab 61. Minute:");
TextSetText(an,msg2);
//sprintf(msg,"Abgehend:");
TextSetText(ab,msg3);
TextSetText(sms,msg4);

   }
  if (id==3) //Ami

   {
   ContainerSety(landcontainer, 0);
   ContainerSetx(backcn, 0);
   ContainerSetx(txtcnt,0);
   ContainerSetVisible(nContainer,0);
   TextSetText(aufbau,"Verbindungsaufbau");
   TextSetText(an,"An ab 61. Minute");
   TextSetText(ab,"Abgehend:");
   TextSetText(sms,"SMS: ");
   
   }

  if (id==4) //rest

   {

ContainerSety(landcontainer, 0);
ContainerSetx(backcn, 0);
ContainerSetx(txtcnt,0);
ContainerSetVisible(nContainer,0);
TextSetText(aufbau,"Verbindungsaufbau:");
TextSetText(an,"An ab 61. Minute:");
TextSetText(ab,"Abgehend:");
TextSetText(sms,"SMS:");

   }




if (id==1580) //back button
{
ContainerSety(landcontainer, -10000);
ContainerSetx(backcn, -4550);
ContainerSetVisible(nContainer,1);
ContainerSetx(txtcnt,-5948);

}
return id;
}



// This function marks the beginning of program execution
void AppMain()
{
landcontainer = ContainerAdd(0,0,-1000);
nContainer = ContainerAdd(0, 0, 0);

nSliderContainer = ContainerAdd(nContainer, 50, 165);
nGUIContainer = ContainerAdd(0, 0, 0);
backcn = ContainerAdd(0,-5000,439);
txtcnt = ContainerAdd(0,-5403,0);
ContainerOrderFront(0,txtcnt);
nFont = FontAdd("Arial", "Regular", 20, 0x000000);


ViewAdd(0, "Images/Background.png", 0, 0);
ViewAdd(0,"Images/Backgroundland.ong",0,0);

ButtonAdd(backcn,"Images/BackButton",5,0, OnButton,1580);
ViewAdd(landcontainer,"Images/Backgroundland.png",0,0);

// Initiate scroller 320x720, ID 0, horizontal scroll false
dynamicScroller.Init(nContainer, 0, 0, 320, 1600, 0);
dynamicScroller.SetHorizontalScroll(false);

// Populate landcontainer
n2Font = FontAdd("Arial", "Regular", 15, 0x000000);
int q,z,p;
q = 25;
z = 122;
p = 42;
aufbau= TextAdd(txtcnt,q,z,"Verbindungsaufbau:",n2Font);
z = z+p;
an = TextAdd(txtcnt,q,z,"An ab 61 Minute:",n2Font);
z = z+p;
ab = TextAdd(txtcnt,q,z,"Abgehend:",n2Font);
z = z+p;
sms = TextAdd(txtcnt,q,z,"SMS:",n2Font);




// Populate container
int x,y;
x = 8;
y=80;

ButtonAdd(nContainer, "Images/RoundedListTop", 8, y, OnButton, 3);
TextAdd(nContainer, 24, y+11, "Amerika", nFont);
y=y+44;
ButtonAdd(nContainer, "Images/RoundedList", 8, y, OnButton, 1);
TextAdd(nContainer, 24, y+11, "Tschechien", nFont);
y=y+44;
ButtonAdd(nContainer, "Images/RoundedList", 8, y, OnButton, 1);
TextAdd(nContainer, 24, y+11, "Tuerkei", nFont);
y=y+44;
ButtonAdd(nContainer, "Images/RoundedList", 8, y, OnButton, 1);
TextAdd(nContainer, 24, y+11, "Ungarn", nFont);
y=y+44;
ButtonAdd(nContainer, "Images/RoundedListBottom", 8, y, OnButton, 4);
TextAdd(nContainer, 24, y+11, "Venezuela", nFont);


// GUI elements
ViewAdd(nGUIContainer, "Images/topbar2.png", 0, 0);
ViewAdd(nGUIContainer, "Images/Toolbar.png", 0, 436);

}


// This function is called whenever the app terminates
void AppExit()
{

}

// This function is called 30 times per second
void OnTimer()
{
if (nTouchEvent == 2)
{
if (nTouchId == 0)
dynamicScroller.Update();
else if (nTouchId == 1)
sliderDynamicScroller.Update();
}
else
{
dynamicScroller.Update();
sliderDynamicScroller.Update();
}
}
Title: Re: Scrolling
Post by: DeadSn0wMan on November 29, 2012, 06:31:38 am
Take a look at the Scrollerbutton.h and either use that or write a new class for your purpus with that class in mind.
I your text fields are empty that's probably because you use unicode characters. For example I see that you are German so if you use any German letters the Iphone wont recognize the string/char *
talk with the DRFSDK support and they can help you to fix this (it's really simple)
Title: Re: Scrolling
Post by: Merkler on November 30, 2012, 03:39:44 am
I dont know what you mean with "scrollerbutton.h" even google couldnt help me.
Please help me out.

But if this would be the problem the Text´s in the buttons (its the same letter type ("Arial") like in the Text fields") are displayed too.
And if i put in a text what didnt need to be "calculated" are there too.
Its just these texts what change the text.
Code: [Select]
if (id==4) //rest

   {

ContainerSety(landcontainer, 0);
ContainerSetx(backcn, 0);
ContainerSetx(txtcnt,0);
ContainerSetVisible(nContainer,0);
TextSetText(aufbau,"Verbindungsaufbau:");
TextSetText(an,"An ab 61. Minute:");
TextSetText(ab,"Abgehend:");
TextSetText(sms,"SMS:");

   }
But i know the programm comes into these if´s because these things
Code: [Select]
ContainerSety(landcontainer, 0);
ContainerSetx(backcn, 0);
ContainerSetx(txtcnt,0);
ContainerSetVisible(nContainer,0);

are executed
Title: Re: Scrolling
Post by: Nico91 on November 30, 2012, 04:09:00 am
Instead of using the buttons you should use ViewAdd ();

after do this:

void Openview()
{
}

int Touch(int id, int event,int x,int y)
{

   if(event==2)
  {
     scroll=1;
  }
   

  if(event==3)
 {
   if(scroll==0) // no scrolling
  {
      // if the touch is on the View
       if(y>= (ViewGety(View)+ContainerGety(Container)) && y<=(ViewGety(View)+ViewGetHeight+ContainerGety(Container)))
          OpenView(); // do something to open

 
   }
 }

   return 1;
}
Title: Re: Scrolling
Post by: DeadSn0wMan on November 30, 2012, 08:22:25 am
I dont know what you mean with "scrollerbutton.h" even google couldnt help me.
Please help me out.

But if this would be the problem the Text´s in the buttons (its the same letter type ("Arial") like in the Text fields") are displayed too.
And if i put in a text what didnt need to be "calculated" are there too.
Its just these texts what change the text.

I mean the ScrollButton.h included in the .zip you downloaded. He uses this in his example. What I mean by the text that dosen't show up is that if it works in the simulator but not on the device it's most likley because you are using foren letters that are not in the English alphabet and to fix this you need the Dragonfire SDK support team to build your app with different settings.
Title: Re: Scrolling
Post by: DeadSn0wMan on November 30, 2012, 08:27:13 am
Instead of using the buttons you should use ViewAdd ();

after do this:

void Openview()
{
}

int Touch(int id, int event,int x,int y)
{

   if(event==2)
  {
     scroll=1;
  }
   

  if(event==3)
 {
   if(scroll==0) // no scrolling
  {
      // if the touch is on the View
       if(y>= (ViewGety(View)+ContainerGety(Container)) && y<=(ViewGety(View)+ViewGetHeight+ContainerGety(Container)))
          OpenView(); // do something to open

 
   }
 }

   return 1;
}
This will not work due to the fact that you muste Update the list continiosly so you can see any Touches on the container. Use the code that jjsanchez wrote it's very effective and you can modify the ScrollButton.h file if it dosen't fit your purpus.
Title: Re: Scrolling
Post by: Merkler on December 10, 2012, 10:03:06 am
Hey Guys,

maybe you can help me.
I Create some Textboxes in the landcontainer.
These textes gets showed with no Problem.
But when i manipulate the textes with TextSetText they get empty.
But this happens just on the iPhone
In the Simulator everything works fine.
Maybe you can help me out.
Big Thanks in advance
 

Code: [Select]
#include "DragonFireSDK.h"
#include "DynamicScroller.h"


DynamicScroller dynamicScroller;
DynamicScroller sliderDynamicScroller;

int nContainer;
int nSliderContainer;
int nGUIContainer;
int landcontainer;
int nFont = FontAdd("Arial", "Regular", 20, 0x000000);
int smallFont = FontAdd("Arial", "Regular", 15, 0x000000);
int backcn;

// land
int aufbau;
int an;
int ab;
int sms;



// This function will be called when a button is pressed

int OnButton(int id)
{
switch(id)
{
case 1:
//works
ContainerSetVisible(nContainer,0);
ContainerSety(landcontainer, 0);
ContainerSetx(backcn, 0);
// dont works
TextSetText(aufbau,"Verbindungsaufbau:    x,xx€ / Verbindung");
TextSetText(an,"An ab 61. Minute:        x,xx€ / Minute");
TextSetText(ab,"Abgehend:         x,xx€ / Minute");
TextSetText(sms,"SMS:         x,xx€");
break;

case 2:
//works
ContainerSetVisible(nContainer,0);
ContainerSety(landcontainer, 0);
ContainerSetx(backcn, 0);
//dont work
TextSetText(aufbau,"Verbindungsaufbau:    x,xx€ / Verbindung");
TextSetText(an,"An ab 61. Minute:        x,xx€ / Minute");
TextSetText(ab,"Abgehend:         x,xx€ / Minute");
TextSetText(sms,"SMS:         x,xx€");
break;

case 3:
//works
ContainerSetVisible(nContainer,0);
ContainerSety(landcontainer, 0);
ContainerSetx(backcn, 0);
// dont work
TextSetText(aufbau,"Verbindungsaufbau:    x,xx€ / Verbindung");
TextSetText(an,"An ab 61. Minute:        x,xx€ / Minute");
TextSetText(ab,"Abgehend:         x,xx€ / Minute");
TextSetText(sms,"SMS:         x,xx€");
break;

case 4:
//works
ContainerSetVisible(nContainer,0);
ContainerSety(landcontainer, 0);
ContainerSetx(backcn,0);
//dont work
TextSetText(aufbau,"Verbindungsaufbau:    x,xx€ / Verbindung");
TextSetText(an,"An ab 61. Minute:        x,xx€ / Minute");
TextSetText(ab,"Abgehend:         x,xx€ / Minute");
TextSetText(sms,"SMS:         x,xx€");
break;

case 1580:
ContainerSety(landcontainer, -10000);
ContainerSetx(backcn, -4550);
ContainerSetVisible(nContainer,1);

}
return id;
}



// This function marks the beginning of program execution
void AppMain()
{
landcontainer = ContainerAdd(0,0,-1000);
nContainer = ContainerAdd(0, 0, 0);
nSliderContainer = ContainerAdd(nContainer, 50, 165);
nGUIContainer = ContainerAdd(0, 0, 0);
backcn = ContainerAdd(0,-5000,439);


ViewAdd(0, "Images/Background.png", 0, 0);
ViewAdd(landcontainer,"Images/Backgroundland.png",0,0);
ButtonAdd(backcn,"Images/BackButton",5,0, OnButton,1580);

// Initiate scroller 320x720, ID 0, horizontal scroll false
dynamicScroller.Init(nContainer, 0, 0, 320, 1600, 0);
dynamicScroller.SetHorizontalScroll(false);

// Populate landcontainer
int q,z,p;
q = 25;
z = 122;
p = 42;
aufbau= TextAdd(landcontainer,q,z,"",smallFont);
z = z+p;
an = TextAdd(landcontainer,q,z,"",smallFont);
z = z+p;
ab = TextAdd(landcontainer,q,z,"",smallFont);
z = z+p;
sms = TextAdd(landcontainer,q,z,"",smallFont);




// Populate container
int x,y;
x = 8;
y=80;

ButtonAdd(nContainer, "Images/RoundedListTop", 8, y, OnButton, 1);
TextAdd(nContainer, 24, y+11, "Amerika", nFont);
y=y+44;
ButtonAdd(nContainer, "Images/RoundedList", 8, y, OnButton, 2);
TextAdd(nContainer, 24, y+11, "Tuerkei", nFont);
y=y+44;
ButtonAdd(nContainer, "Images/RoundedList", 8, y, OnButton, 3);
TextAdd(nContainer, 24, y+11, "Ungarn", nFont);
y=y+44;
ButtonAdd(nContainer, "Images/RoundedListBottom", 8, y, OnButton, 4);
TextAdd(nContainer, 24, y+11, "Venezuela", nFont);


// GUI elements
ViewAdd(nGUIContainer, "Images/topbar2.png", 0, 0);
ViewAdd(nGUIContainer, "Images/Toolbar.png", 0, 436);

}


// This function is called whenever the app terminates
void AppExit()
{

}

// This function is called 30 times per second
void OnTimer()
{
if (nTouchEvent == 2)
{
if (nTouchId == 0)
dynamicScroller.Update();
else if (nTouchId == 1)
sliderDynamicScroller.Update();
}
else
{
dynamicScroller.Update();
sliderDynamicScroller.Update();
}
}
Title: Re: Scrolling
Post by: DeadSn0wMan on December 10, 2012, 10:09:22 am
I say again aslong as you swap change set the TExtboxes to some foren letter that is NOT in the english alphabet it will NOT show the text on the iphone or ipad to fix this read my previous posts
Title: Re: Scrolling
Post by: jjsanchezramirez on December 10, 2012, 08:51:08 pm
Hey. Sorry I haven't been active in this topic. My laptop fried and I have my USMLE Step 1 (a very difficult test) in a few weeks, so I've been studying non stop for months. Anyhow, you guys seem to get the hang of it. I'm sure DFSDK will release easier to  use GUI components on their next release. I, myself, am thinking of getting a Mac and moving to Objective C. But my priority is my test. Programming is just a hobby.

Anyhow, I don't check the forums that often, so please send me an email or personal message if you have questions.
Title: Re: Scrolling
Post by: Merkler on December 12, 2012, 08:14:08 am
Now i found out what the Problem with the text is.
If i have an "€" Sign in it they wont get showed on the iPhone.
Dont know why...

But the problem with the "Scrollbutton.h" i couldnt fix.
I really dont know where i can find this.
Could you provide me an Link or the code of this Library?

Thanks in advance
Title: Re: Scrolling
Post by: DeadSn0wMan on December 12, 2012, 09:34:01 am
told ya! Some Soybols aren't supported by default read my previous post to fix this.

Download and use this (this includes the Scrollerbutton.h):

http://www.mediafire.com/?2ipll7cb2zlxpie

Topic: http://dragonfiresdk.net/forum/index.php?topic=360.msg1936#msg1936


This is the best scroller solution out there for DFSDK for now.

Title: Re: Scrolling
Post by: jjsanchezramirez on December 16, 2012, 06:18:11 am
Now i found out what the Problem with the text is.
If i have an "€" Sign in it they wont get showed on the iPhone.
Dont know why...

But the problem with the "Scrollbutton.h" i couldnt fix.
I really dont know where i can find this.
Could you provide me an Link or the code of this Library?

Thanks in advance
You need to get your hands on the Example.
Here is the YouTube video: http://m.youtube.com/watch?v=J1UELzjk0XE
Here is the example: http://www.mediafire.com/?2ipll7cb2zlxpie

Please go through The example. No it is that it has a class called ScrollerButton.h. What you need to do list modified this class to your convenience. To learn how to use this class please go through the code and the example. It's not really a hard piece of code.
Title: Re: Scrolling
Post by: grantw1991 on December 18, 2012, 08:17:58 am
do the scroller buttons only work on page 1?
I have a long list of buttons that are used for another page but when I try to initiate them (in the example for screen 1) it doesn't work?
Anyway of making this possible? Thanks
Title: Re: Scrolling
Post by: Nico91 on December 23, 2012, 03:37:20 am
In my app you can see my scrolling features.
https://itunes.apple.com/it/app/agilescience/id587328264?mt=8
Title: Re: Scrolling
Post by: grantw1991 on December 23, 2012, 09:48:00 am
Just downloaded your app, nice work Nico!
I have a questions though, how do you add buttons to the static images at the top?
Like the back button and the refresh button, if you are using the scroller.h and keeping the top part static how can you add buttons to it?

Thanks, Grant
Title: Re: Scrolling
Post by: DeadSn0wMan on December 23, 2012, 10:55:14 am
Have them in another container anf then use ContainerOrderFront() to set that container infront of the scrolling one
Title: Re: Scrolling
Post by: grantw1991 on December 24, 2012, 03:57:52 pm
sweet, nice one mate didnt even know that function existed
Title: Re: Scrolling
Post by: Nico91 on December 27, 2012, 03:20:09 am
I didnt use scroller.h i used my originale code.