Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Native Development

Reply
Contributor
Posts: 33
Registered: ‎01-02-2012
My Device: 9900
My Carrier: bell

Circular Slider Tutorial Help

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.

https://developer.blackberry.com/cascades/documentation/dev/integrating_cpp_qml/custom_control_tutor...

 

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: 

connect(mRootContainer, SIGNAL(touch(bb::cascades::TouchEvent *)),
    this, SLOT(onSliderHandleTouched(bb::cascades::TouchEvent *)));
 
when i put this in the constructor it dosent work. I know this code is incomplete please make it work
Thanks
 

 

Contributor
Posts: 33
Registered: ‎01-02-2012
My Device: 9900
My Carrier: bell

Re: Circular Slider Tutorial Help

Any one have a working code for this it will be of a great help,

thanks

Developer
Posts: 613
Registered: ‎10-17-2010
My Device: (BlackBerry Z10)-> Q10/Passport Dual Use

Re: Circular Slider Tutorial Help

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!

Contributor
Posts: 33
Registered: ‎01-02-2012
My Device: 9900
My Carrier: bell

Re: Circular Slider Tutorial Help

I really dont want to halt my devlopment process, anyone knows how to get in touch with the cascades devlopment team,

Thanks

Highlighted
Developer
Posts: 40
Registered: ‎07-06-2012
My Device: DevAlpha, PlayBook
My Carrier: BaseDE, BouyguesFR

Re: Circular Slider Tutorial Help

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::TouchEvent *)));

	// 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(mHandleContainer)
	.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(this);

	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

 

Developer
Posts: 24
Registered: ‎05-16-2013
My Device: Developer
My Carrier: Developer

Re: Circular Slider Tutorial Help