10-14-2012 06:25 PM
I am currently working on my app kind of like a custom time watch that keeps time, so I though the circular slider example would do, and so I got o everything right. The only thing where the tutorial is incomplete is at the Touch Interaction with the handle.
So they just give us, incomplete code, I tired so much to complete it it just doesn't work any help is appreciated.
PROBLEM: The mRootContainer is to be linked to the touch() event, when the event happens the slider to move.
Which they give us in the Touch Handling Section
as:
10-14-2012 10:44 PM
Any one have a working code for this it will be of a great help,
thanks
10-14-2012 11:31 PM
I was also unable to get the code to work. BUMP.
Can RIM dev consultant or Open-Source dude post a complete source of this on GitHub or make a zip of the Circular Slider?
Thank you!
10-15-2012 05:17 PM
I really dont want to halt my devlopment process, anyone knows how to get in touch with the cascades devlopment team,
Thanks
11-03-2012 05:57 PM
for me the example works just fine. I did not do any modification. Just copy-paste of all the code. Compiled and launched it. I agree that it would be great to have it on GitHub .. it is a great example!
Here the code:
CircularSlider.cpp:
#include "CircularSlider.h"
#include <bb/cascades/AbsoluteLayout>
#include <bb/cascades/AbsoluteLayoutProperties>
#include <bb/cascades/DockLayout>
#include <iostream>
#include <math.h>
#define PI 3.141592653589793
CircularSlider::CircularSlider()
{
// Create a root container with an AbsoluteLayout.
mRootContainer = new Container();
mRootContainer->setLayout(new AbsoluteLayout());
connect(mRootContainer, SIGNAL(touch(bb::cascades::TouchEvent *)),
this, SLOT(onSliderHandleTouched(bb::cascades::TouchEven t *)));
// Create the slider track image.
mTrackImage = ImageView::create().image(
QUrl("asset:///images/slider_track.png"));
// Create the handle container and two images, one for
// active state and one for inactive.
mHandleContainer = Container::create()
.layout(new DockLayout());
// Disable implicit animations for the handle container so that
// the handle doesn't jump when it's being dragged.
mHandleImplicitAnimationController =
ImplicitAnimationController::create(mHandleContain er)
.enabled(false);
// Load the handle images
mHandleOn = Image(QUrl("asset:///images/handle_pressed.png"));
mHandleOff = Image(QUrl("asset:///images/handle_inactive.png")) ;
// Create the image view for the handle using the image for
// the inactive handle
mHandle = ImageView::create().image(mHandleOff)
.horizontal(HorizontalAlignment::Right)
.vertical(VerticalAlignment::Center);
// Add the handle image to the to handle container
// and add everything to the root container
mHandleContainer->add(mHandle);
mRootContainer->add(mTrackImage);
mRootContainer->add(mHandleContainer);
// Set the root of the custom control.
setRoot(mRootContainer);
// Connect the signals to your custom slots and check the return value
// for errors.
bool res = connect(this, SIGNAL(preferredHeightChanged(float)), this,
SLOT(onHeightChanged(float)));
Q_ASSERT(res);
Q_UNUSED(res);
bool res2 = connect(this, SIGNAL(preferredWidthChanged(float)), this,
SLOT(onWidthChanged(float)));
Q_ASSERT(res2);
Q_UNUSED(res2);
// Set the initial size.
mWidth = 600;
mHeight = 600;
setPreferredSize(mWidth, mHeight);
}
// Set the new width of the custom control and
// initiate the resizing
void CircularSlider::onWidthChanged(float width)
{
mWidth = width;
onSizeChanged();
}
// Set the new height of the custom control and
// initiate the resizing
void CircularSlider::onHeightChanged(float height)
{
mHeight = height;
onSizeChanged();
}
void CircularSlider::onSizeChanged()
{
// Define the center of the circle.
mCenterX = mWidth / 2;
mCenterY = mHeight / 2;
mRadiusCircle = mWidth - mCenterX;
// Set the root container to the new size.
mRootContainer->setPreferredSize(mWidth, mHeight);
// Set the track image to be slightly smaller than the root.
mTrackImage->setPreferredSize(mWidth * 0.85, mHeight * 0.85);
// Set the handle image and container to be much smaller.
mHandle->setPreferredSize(0.2 * mWidth, 0.2 * mHeight);
mHandleContainer->setPreferredSize(mWidth, 0.2 * mHeight);
// Transform the handle container along its y axis to move it
// into the correct position.
mHandleContainer->setTranslationY((mHeight - 0.2 * mHeight) / 2);
// Transform the position of the track image to the correct
// position.
mTrackImage->setTranslation((mWidth - 0.85 * mWidth) / 2,
(mHeight - 0.85 * mHeight) / 2);
// Clear the circumference points for the circle
// and reinitialize them to reflect the new size.
pointsOnCircumference.clear();
for (int angle = 0; angle < 360; angle++) {
float x = mCenterX + (mRadiusCircle) * cos(angle * PI / 180);
float y = mCenterY + (mRadiusCircle) * sin(angle * PI / 180);
pointsOnCircumference.push_back(make_pair(x, y));
}
}
void CircularSlider::onSliderHandleTouched(TouchEvent* pTouchEvent)
{
// Change to the active handle image if isDown()
if (pTouchEvent->isDown()) {
mHandle->setImage(mHandleOn);
// Change to the inactive handle image if isUp()
} else if (pTouchEvent->isUp()) {
mHandle->setImage(mHandleOff);
// Change the position of the slider handle if isMove()
} else if (pTouchEvent->isMove()) {
processRawCoordinates(pTouchEvent->localX(),
pTouchEvent->localY());
}
}
void CircularSlider::processRawCoordinates(float touchX, float touchY) {
// Determine the distance from the center to the touch point.
float distanceFromCenterToTouchPoint = sqrt(
(touchX - mCenterX) * (touchX - mCenterX)
+ (touchY - mCenterY) * (touchY - mCenterY));
// Determine whether the touch point is outside the center of
// the circle and in the valid touch area.
if (distanceFromCenterToTouchPoint >= 0.3 * mRadiusCircle
&& distanceFromCenterToTouchPoint <= mRadiusCircle) {
// The minimum distance from the touch.
float minDistanceFromTouch = INT_MAX;
// Measure the distance from the touch to the circumference
// for each point on the circle and store the X and Y
// coordinates for the shortest distance.
for (float i = 0; i < pointsOnCircumference.size(); i++) {
float x = pointsOnCircumference[i].first;
float y = pointsOnCircumference[i].second;
float distanceFromTouch = sqrt(
(x - touchX) * (x - touchX)
+ (y - touchY) * (y - touchY));
if (distanceFromTouch < minDistanceFromTouch) {
minDistanceFromTouch = distanceFromTouch;
// The angle to rotate the handle container once moved
mAngle = i;
}
}
// Rotate the handle container along its Z-axis.
if (mAngle != mrevAngle) {
mHandleContainer->setRotationZ(mAngle);
// Our slider has a new value, and we want our QML to know
emit valueChanged(mAngle);
mrevAngle = mAngle;
}
}
}
// Get the value of the slider.
float CircularSlider::value() const
{
return mValue;
}
// Set the value of the slider.
void CircularSlider::setValue(float value)
{
if (mValue != value)
{
mValue = value;
emit valueChanged(mValue);
}
}
CircularSlider::~CircularSlider() {
// TODO Auto-generated destructor stub
}CircularSlider.h
#ifndef CIRCULARSLIDER_H_
#define CIRCULARSLIDER_H_
#include <bb/cascades/CustomControl>
#include <bb/cascades/Container>
#include <bb/cascades/TouchEvent>
#include <bb/cascades/ImageView>
#include <bb/cascades/Image>
#include <bb/cascades/ImplicitAnimationController>
#include <bb/cascades/Label>
#include <QObject>
#include <vector>
using namespace std;
using namespace bb::cascades;
class CircularSlider: public CustomControl {
Q_OBJECT
Q_PROPERTY(float value READ value WRITE setValue
NOTIFY valueChanged FINAL)
public:
CircularSlider();
virtual ~CircularSlider();
float value() const;
void setValue(float value);
void innerCircle(QVariant innerCircle);
Q_SIGNALS:
void valueChanged(float value);
private slots:
void onSliderHandleTouched(bb::cascades::TouchEvent *pTouchEvent);
private slots:
void onWidthChanged(float width);
void onHeightChanged(float height);
private:
float convertAngleToValue(float angle);
void onSizeChanged();
void processRawCoordinates(float inX, float inY);
Container *mRootContainer;
ImageView *mTrackImage;
float mWidth;
float mHeight;
float mrevAngle;
float mCenterX;
float mCenterY;
float mRadiusCircle;
Image mHandleOn;
Image mHandleOff;
ImageView *mHandle;
Container *mHandleContainer;
vector<pair<int, int> > pointsOnCircumference;
float mAngle;
float mValue;
ImplicitAnimationController mHandleImplicitAnimationController;
};
#endif /* CIRCULARSLIDER_H_ */CircularSliderDemo.cpp (the application file that was generated automatically):
// Default empty project template #include "CircularSliderDemo.hpp" #include "CircularSlider.h" #include <bb/cascades/Application> #include <bb/cascades/QmlDocument> #include <bb/cascades/AbstractPane> using namespace bb::cascades; CircularSliderDemo::CircularSliderDemo(bb::cascades::Application *app) : QObject(app) { // Register our custom control qmlRegisterType<CircularSlider>("custom.lib", 1, 0, "CircularSlider"); QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(th is); AbstractPane *root = qml->createRootObject<AbstractPane>(); app->setScene(root); }
main.qml
import bb.cascades 1.0
import custom.lib 1.0
Page {
// The root container
content: Container {
topMargin: 130
layout: DockLayout {}
background: Color.create ("#404040")
// Display the current rotation of the slider handle.
Label {
id: myLabel
text: "0"
horizontalAlignment: HorizontalAlignment.Center
textStyle {
base: SystemDefaults.TextStyles.BigText
fontWeight: FontWeight.Bold
}
}
// Create the CircularSlider and lay it out
// just like any other control.
CircularSlider {
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
// Capture the valueChanged signal and update
// the label.
onValueChanged: {
console.debug (value);
myLabel.text = value;
}
} // Ends the circular slider
} // Ends the root container
} // Ends the page
15 hours ago