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

Java Development

Reply
Developer
WesleyT
Posts: 206
Registered: ‎07-02-2010
My Device: 8320 Curve
My Carrier: Vodacom

Spiral / Rotation Menu Control ?

Hello everyone,

 

I was just wondering weather there is a possibility to create or use a spiral/ Rotating menu. For argument sake. You have a main Background, On this background you have 5 images, which you want to spiral through till you reach the image (Option) that you want to select.

 

If there are any links that might help me please give them or articles etc.

 

Thanks in advance.

Please use plain text.
Developer
rcmaniac25
Posts: 1,804
Registered: ‎04-28-2009
My Device: Z10 (STL100-4)-10.2.1.2174, Z10 (STL100-3)-10.3.0.700 Dev OS, Z30 (STA100-5)-10.3.0.700 Dev OS, PlayBook (16GB)-2.1.0.1917
My Carrier: Verizon

Re: Spiral / Rotation Menu Control ?

Do you mean something like the "Featured View" (the initial page) of App World? But with a different format?

---Spends time in #blackberrydev on freenode (IRC)----
Three simple rules:
1. Please use the search bar before making new posts.
2. "Like" posts that you find helpful.
3. If a solution has been found for your post, mark it as solved.
--I code too much. Well, too bad.
Please use plain text.
Developer
Developer
CMY
Posts: 1,123
Registered: ‎02-10-2009
My Device: 8130 / 8350 / 9530 / 9550 / 9850 / PlayBook
My Carrier: Verizon

Re: Spiral / Rotation Menu Control ?

I think he is referring to the rotating carousel like in Poynt.

Please use plain text.
Developer
rcmaniac25
Posts: 1,804
Registered: ‎04-28-2009
My Device: Z10 (STL100-4)-10.2.1.2174, Z10 (STL100-3)-10.3.0.700 Dev OS, Z30 (STA100-5)-10.3.0.700 Dev OS, PlayBook (16GB)-2.1.0.1917
My Carrier: Verizon

Re: Spiral / Rotation Menu Control ?

Ok, that's what I was thinking but couldn't think of an app that had anything like that except App World (it's the same thing except it doesn't have a Spiral / Rotation-like control. It is linear instead.

---Spends time in #blackberrydev on freenode (IRC)----
Three simple rules:
1. Please use the search bar before making new posts.
2. "Like" posts that you find helpful.
3. If a solution has been found for your post, mark it as solved.
--I code too much. Well, too bad.
Please use plain text.
Developer
peter_strange
Posts: 19,601
Registered: ‎07-14-2008
My Device: Not Specified

Re: Spiral / Rotation Menu Control ?

One the presentations at DevCon 2009 was a presentation by some RIM chaps who had done something like this.  Do you know if the presentation material is available?  It will prbably be on the DVD.

Please use plain text.
Developer
Developer
CMY
Posts: 1,123
Registered: ‎02-10-2009
My Device: 8130 / 8350 / 9530 / 9550 / 9850 / PlayBook
My Carrier: Verizon

Re: Spiral / Rotation Menu Control ?

I have some code that simulates the rotation used in Poynt. It doesn't do the auto scroll detection though (where the icon you touch automatically comes to the front). Mine also fades out all the images except the one that has focus and shows the name below instead of as a tooltip over the images.

Please use plain text.
Developer
WesleyT
Posts: 206
Registered: ‎07-02-2010
My Device: 8320 Curve
My Carrier: Vodacom

Re: Spiral / Rotation Menu Control ?

Thank you for the input guys.

 

I just saw the windows phone simulator and it had an "application toolbar" which looked really nice.

Please use plain text.
Developer
kylefowler
Posts: 526
Registered: ‎05-17-2009
My Device: 9900
My Carrier: ATT

Re: Spiral / Rotation Menu Control ?

CMY - is this code you developed or  is it code you found that you could share?

Like all of my posts
Please use plain text.
Developer
Developer
CMY
Posts: 1,123
Registered: ‎02-10-2009
My Device: 8130 / 8350 / 9530 / 9550 / 9850 / PlayBook
My Carrier: Verizon

Re: Spiral / Rotation Menu Control ?

[ Edited ]

It is code I developed. Here is my paint routine which should be enough as I calculate everything there. It runs pretty fast and smooth for me on every device/OS I have tested on (Pearl,Curve 83XX,S1,S2,Tour - 4.3,4.5,4.7,5.0).

 

 

public void paint(Graphics g){
      // Need to start drawing from middle of vector and move out to each end
      int itemAngle = 360 / choices.size();
      int startItem = choices.size()>>>1;
      int wRadius = (myWidth()-itemSize)>>>1;
      int hRadius = (myHeight()-(itemSize+fontSize+4))>>>1;
      int xstart = myWidth()>>>1;
      int ystart = hRadius;
      int xoff;
      int yoff;
      int xleft = (int)(wRadius * Math.cos( Math.toRadians(90+(itemAngle>>>1)) ));
      int xright = (int)(wRadius * Math.cos( Math.toRadians(90-(itemAngle>>>1)) ));
      int xs;
      int iw;
      int yadj = 0;
      CarouselItem item = null;

      //Figure out selectedItem before drawing instead of while drawing
      for( int i=0; i<choices.size(); ++i ){
         xoff = (int)(wRadius * Math.cos( Math.toRadians((itemAngle * i) + 90 + offset) ));
         yoff = (int)(hRadius * Math.sin( Math.toRadians((itemAngle * i) + 90 + offset) ));
         xs = (xstart+xoff);
         iw = itemSize>>>1;

         if( ((xs) > (xstart+xleft)) && ((xs) < (xstart+xright)) && ((ystart+yoff) > ystart) ){
            selectedChoice = i;
         }
      }

      Vector temp = new Vector();
      
      for( int i=selectedChoice; i<choices.size(); ++i ){
         temp.addElement( choices.elementAt(i) );
      }
      for( int i=0; i<selectedChoice; ++i ){
         temp.addElement( choices.elementAt(i) );
      }      
      
      //Draw startItem
      item = (CarouselItem)temp.elementAt(startItem);
      xoff = (int)(wRadius * Math.cos( Math.toRadians((itemAngle * item.element) + 90 + offset) ));
      yoff = (int)(hRadius * Math.sin( Math.toRadians((itemAngle * item.element) + 90 + offset) ));

      xs = (xstart+xoff);
      iw = itemSize>>>1;

      int [] xpt = { xs-iw, xs-iw, xs-iw+8, xs+iw-8, xs+iw, xs+iw,
                     xs+iw, xs+iw, xs+iw-8, xs-iw+8, xs-iw, xs-iw };
      int [] ypt = { ystart+yoff+8, ystart+yoff, ystart+yoff, ystart+yoff, ystart+yoff, ystart+yoff+8,
                     ystart+yoff+itemSize-8, ystart+yoff+itemSize, ystart+yoff+itemSize,
                     ystart+yoff+itemSize, ystart+yoff+itemSize, ystart+yoff+itemSize-8 };
      byte [] typ = { Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT, Graphics.CURVEDPATH_END_POINT,
                      Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT, Graphics.CURVEDPATH_END_POINT,
                      Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT, Graphics.CURVEDPATH_END_POINT,
                      Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT, Graphics.CURVEDPATH_END_POINT };
      
      double pcnt = 160 / (hRadius*2);
      double alpha = 255 - (((hRadius*2)-(ystart+yoff)) * pcnt);
      g.setGlobalAlpha( (int)alpha - 64 );

      if( useGradient ){
         int [] col = { backgroundColor, backgroundColor, backgroundColor, backgroundColor, backgroundColor, backgroundColor,
                        backgroundGradient, backgroundGradient, backgroundGradient, backgroundGradient, backgroundGradient, backgroundGradient };
         g.drawShadedFilledPath(xpt, ypt, typ, col, null);
      } else {
         g.setColor( backgroundColor );
         g.drawFilledPath(xpt, ypt, typ, null);
      }

      g.setColor(fontColor);
      g.drawPathOutline(xpt, ypt, typ, null, true);

      if( item.image.getHeight() < itemSize ) yadj = (itemSize-item.image.getHeight())>>>1;
      else yadj = 0;
      g.drawBitmap((xstart+xoff)-(item.image.getWidth()>>>1), (ystart+yoff+yadj),
                   item.image.getWidth(), item.image.getHeight(), item.image, 0, 0);

      for( int i=(startItem-1); i>=0; --i ){

         if( i != 0 ){

            item = (CarouselItem)temp.elementAt(i);

            //Left (i)
            xoff = (int)(wRadius * Math.cos( Math.toRadians((itemAngle * item.element) + 90 + offset) ));
            yoff = (int)(hRadius * Math.sin( Math.toRadians((itemAngle * item.element) + 90 + offset) ));

            xs = (xstart+xoff);
            
            int [] xpt2 = { xs-iw, xs-iw, xs-iw+8, xs+iw-8, xs+iw, xs+iw,
                            xs+iw, xs+iw, xs+iw-8, xs-iw+8, xs-iw, xs-iw };
            int [] ypt2 = { ystart+yoff+8, ystart+yoff, ystart+yoff, ystart+yoff, ystart+yoff, ystart+yoff+8,
                            ystart+yoff+itemSize-8, ystart+yoff+itemSize, ystart+yoff+itemSize,
                            ystart+yoff+itemSize, ystart+yoff+itemSize, ystart+yoff+itemSize-8 };
            byte [] typ2 = { Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT, Graphics.CURVEDPATH_END_POINT,
                             Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT, Graphics.CURVEDPATH_END_POINT,
                             Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT, Graphics.CURVEDPATH_END_POINT,
                             Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT, Graphics.CURVEDPATH_END_POINT };

            alpha = 255 - (((hRadius*2)-(ystart+yoff)) * pcnt);
            g.setGlobalAlpha( (int)alpha - 64 );

            if( useGradient ){
               int [] col2 = { backgroundColor, backgroundColor, backgroundColor, backgroundColor, backgroundColor, backgroundColor,
                               backgroundGradient, backgroundGradient, backgroundGradient, backgroundGradient, backgroundGradient, backgroundGradient };
               g.drawShadedFilledPath(xpt2, ypt2, typ2, col2, null);
            } else {
               g.setColor( backgroundColor );
               g.drawFilledPath(xpt2, ypt2, typ2, null);
            }

            g.setColor(fontColor);
            g.drawPathOutline(xpt2, ypt2, typ2, null, true);

            if( item.image.getHeight() < itemSize ) yadj = (itemSize-item.image.getHeight())>>>1;
            else yadj = 0;
            g.drawBitmap((xstart+xoff)-(item.image.getWidth()>>>1), (ystart+yoff+yadj),
                         item.image.getWidth(), item.image.getHeight(), item.image, 0, 0);

         }

         //Right (startItem+(startItem-i))
         if( (startItem+(startItem-i)) < temp.size() ){

            int n = (startItem+(startItem-i));

            if( n != 0 ){

               item = (CarouselItem)temp.elementAt(n);

               xoff = (int)(wRadius * Math.cos( Math.toRadians((itemAngle * item.element) + 90 + offset) ));
               yoff = (int)(hRadius * Math.sin( Math.toRadians((itemAngle * item.element) + 90 + offset) ));

               xs = (xstart+xoff);
               
               int [] xpt3 = { xs-iw, xs-iw, xs-iw+8, xs+iw-8, xs+iw, xs+iw,
                               xs+iw, xs+iw, xs+iw-8, xs-iw+8, xs-iw, xs-iw };
               int [] ypt3 = { ystart+yoff+8, ystart+yoff, ystart+yoff, ystart+yoff, ystart+yoff, ystart+yoff+8,
                               ystart+yoff+itemSize-8, ystart+yoff+itemSize, ystart+yoff+itemSize,
                               ystart+yoff+itemSize, ystart+yoff+itemSize, ystart+yoff+itemSize-8 };
               byte [] typ3 = { Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT, Graphics.CURVEDPATH_END_POINT,
                                Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT, Graphics.CURVEDPATH_END_POINT,
                                Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT, Graphics.CURVEDPATH_END_POINT,
                                Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT, Graphics.CURVEDPATH_END_POINT };

               alpha = 255 - (((hRadius*2)-(ystart+yoff)) * pcnt);
               g.setGlobalAlpha( (int)alpha - 64 );

               if( useGradient ){
                  int [] col3 = { backgroundColor, backgroundColor, backgroundColor, backgroundColor, backgroundColor, backgroundColor,
                                  backgroundGradient, backgroundGradient, backgroundGradient, backgroundGradient, backgroundGradient, backgroundGradient };
                  g.drawShadedFilledPath(xpt3, ypt3, typ3, col3, null);
               } else {
                  g.setColor( backgroundColor );
                  g.drawFilledPath(xpt3, ypt3, typ3, null);
               }

               g.setColor(fontColor);
               g.drawPathOutline(xpt3, ypt3, typ3, null, true);

               if( item.image.getHeight() < itemSize ) yadj = (itemSize-item.image.getHeight())>>>1;
               else yadj = 0;
               g.drawBitmap((xstart+xoff)-(item.image.getWidth()>>>1), (ystart+yoff+yadj),
                            item.image.getWidth(), item.image.getHeight(), item.image, 0, 0);

            }
         }
      }

      g.setGlobalAlpha(255);

      //Draw startItem
      item = (CarouselItem)temp.elementAt(0);
      xoff = (int)(wRadius * Math.cos( Math.toRadians((itemAngle * item.element) + 90 + offset) ));
      yoff = (int)(hRadius * Math.sin( Math.toRadians((itemAngle * item.element) + 90 + offset) ));

      xs = (xstart+xoff);
      
      int [] xpt2 = { xs-iw, xs-iw, xs-iw+8, xs+iw-8, xs+iw, xs+iw,
                      xs+iw, xs+iw, xs+iw-8, xs-iw+8, xs-iw, xs-iw };
      int [] ypt2 = { ystart+yoff+8, ystart+yoff, ystart+yoff, ystart+yoff, ystart+yoff, ystart+yoff+8,
                      ystart+yoff+itemSize-8, ystart+yoff+itemSize, ystart+yoff+itemSize,
                      ystart+yoff+itemSize, ystart+yoff+itemSize, ystart+yoff+itemSize-8 };
      byte [] typ2 = { Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT, Graphics.CURVEDPATH_END_POINT,
                       Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT, Graphics.CURVEDPATH_END_POINT,
                       Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT, Graphics.CURVEDPATH_END_POINT,
                       Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT, Graphics.CURVEDPATH_END_POINT };
      if( useGradient ){
         int [] col2 = { backgroundColor, backgroundColor, backgroundColor, backgroundColor, backgroundColor, backgroundColor,
                         backgroundGradient, backgroundGradient, backgroundGradient, backgroundGradient, backgroundGradient, backgroundGradient };
         g.drawShadedFilledPath(xpt2, ypt2, typ2, col2, null);
      } else {
         g.setColor( backgroundColor );
         g.drawFilledPath(xpt2, ypt2, typ2, null);
      }

      g.setColor(fontColor);
      g.drawPathOutline(xpt2, ypt2, typ2, null, true);

      if( item.image.getHeight() < itemSize ) yadj = (itemSize-item.image.getHeight())>>>1;
      else yadj = 0;
      g.drawBitmap((xstart+xoff)-(item.image.getWidth()>>>1), (ystart+yoff+yadj),
                   item.image.getWidth(), item.image.getHeight(), item.image, 0, 0);

   }

 

 

Here is the code for the CarouselItem internal class:

 

 

   private class CarouselItem {
      String name,description;
      Bitmap image;
      Runnable action;
      int element;

      CarouselItem(String n,String b,int pos,Runnable r){
         name = n;
         element = pos;
         action = r;

         EncodedImage enc = EncodedImage.getEncodedImageResource(b);

         int ratio2 = Fixed32.div(enc.getWidth(), itemSize);
         int ratio3 = Fixed32.div(enc.getHeight(), itemSize);
         int ratio = ratio2;
         if( ratio3 > ratio2 ) ratio = ratio3;

         image = enc.scaleImage32( ratio, ratio ).getBitmap();
      }

      CarouselItem(String n,String desc,String b,int pos,Runnable r){
         description = desc;
         name = n;
         element = pos;
         action = r;

         EncodedImage enc = EncodedImage.getEncodedImageResource(n,b);

         int ratio2 = Fixed32.div(enc.getWidth(), itemSize);
         int ratio3 = Fixed32.div(enc.getHeight(), itemSize);
         int ratio = ratio2;
         if( ratio3 > ratio2 ) ratio = ratio3;

         image = enc.scaleImage32( ratio, ratio ).getBitmap();
      }
   }

 

ItemSize is passed in to the CarouselField (what I called it) to tell how big the image tiles are. To do the rotation, I use the TouchEvent.MOVE and update the offset by the moved amount, and for trackball devices I make it rotate half the distance to the next image (so it is not exactly smooth, which you can adjust yourself).

 

A basic overview of what I do is:

 

1) I figure out which Item is in the center of the wheel and put it into position 0 in a vector

2) Next, I load the rest of the vector with the first half being the images to the left of center and the second half being the images to right of center

3) Then I start from the middle and end of the vector and draw the images moving down towards 0 (the middle) so that the item preceding it is drawn over top of the item behind it in the vector

4) Then i draw the item in the front

 

Since it is a rotation around Y i use cos to get the x-value angle of the images. The xstart and ystart values are the center of the rotation circle. xstart is half the width of the field, while ystart is half the difference between the height of the filed and the image height plus font height. If anyone wants to see it in action just PM me and I will give you a coupon code to download the app where it is used from a mobihand site.

 

Please use plain text.
Trusted Contributor
coilfyzx
Posts: 204
Registered: ‎07-03-2011
My Device: Torch
My Carrier: Digicel

Re: Spiral / Rotation Menu Control ?

Has this code worked for you before?
_______________________________________________________
Never be close-fisted with the knowledge you've received. For if others were the same to you, you would not be painted as the person you are; the flowing definition of you, would be non existent.

You would be meaningless.
Please use plain text.