Javafx Pie Menu (with Fish Eye Effect)

Here’s a simple pie menu (context menu) using javafx. 

 

use right click to show (context) menu and left click to hide it. 

try this here:   

fyi, i also post it at javafxstudio.

here it is the source code 

/*
 * Main.fx
 *
 * Created on 16 Mei 09, 18:36:11
 */

package piemenu;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.animation.Interpolator;
import javafx.util.Sequences;
import javafx.scene.CustomNode;
import javafx.scene.Node;
import javafx.scene.shape.Circle;
import javafx.scene.paint.Color;
import javafx.scene.Group;
import javafx.scene.image.*;
import java.lang.Math;
import javafx.scene.input.MouseEvent;
import javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import javafx.scene.shape.Rectangle;
import javafx.scene.input.MouseButton;
/**
 * @author Muhammad Hakim A
 */

class PieMenu extends CustomNode{
    public var radius = 150;
    var angle = 0.0;
    def deg2rad = Math.PI/180.0;

    def imgsurl:String[] = ["{__DIR__}images/blender.png", "{__DIR__}images/editor.png",
    "{__DIR__}images/feh.png","{__DIR__}images/firefox.png","{__DIR__}images/gimp.png",
    "{__DIR__}images/inkscape.png","{__DIR__}images/openoffice.png","{__DIR__}images/terminal.png",
    "{__DIR__}images/thunderbird.png"];

    var border = Circle {
        centerX: translateX/2, centerY: translateY/2
        radius: radius
        fill: Color.WHITE
    }

    function zoomAnimation(s:Number, n:Node):Void{
        def t = Timeline {
            keyFrames : [
                KeyFrame {
                    time: 0s
                    values:[n.scaleX => n.scaleX,
                           n.scaleY => n.scaleY]
                },
                KeyFrame {
                    time: 50ms
                    values:[n.scaleX => s tween Interpolator.LINEAR,
                           n.scaleY => s tween Interpolator.LINEAR]
                }
            ]
        };
        t.play();
    }

    def groupMenu:Group = Group{
        content:[border]
        onMouseMoved: function( e: MouseEvent ):Void {

            if (sizeof groupMenu.content > 0){
                // distances
                var seqdist:Float[];
                for(i in [1..9]){
                    def imgv = groupMenu.content[i];
                    def d = distance(e.x,e.y, imgv.translateX, imgv.translateY);
                    insert d into seqdist;
                }

                // sort
                def sortedseqdist = Sequences.sort(seqdist);

                // zoom in/out range[1.7..0.35]
                var zoom = 1.7;
                var zoomseq:Number[];
                for (j in [0..8]){
                    // search the index
                    def idx = Sequences.indexOf(seqdist, sortedseqdist[j]);
                    zoomAnimation(zoom, groupMenu.content[idx+1]);
                    zoomseq[idx] = zoom;
                    zoom -= 0.15;
                }
            }
        }

        // back to normal
        onMouseExited: function( e: MouseEvent ):Void {
             for (j in [1..8]){
                 zoomAnimation(1, groupMenu.content[j]);
            }
        }
    }

    function distance(x1:Float, y1:Float, x2:Float, y2:Float):Integer{
        return (Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)) as Integer);
    }

    function PieMenu(){
        var anglestep = 360/9;
        var images:Image[] = for (idx in [0..8]){
            Image{url: imgsurl[idx]}
        };

        for (img in images){
            var a = (angle + anglestep / 2.0) * deg2rad;

            var imgv = ImageView{
                translateX: (translateX/2 + Math.cos(a)*radius);
                translateY: (translateY/2 + Math.sin(a)*radius);
                image: img
                }
            // insert ke group
            insert imgv into groupMenu.content;
            // step
            angle += anglestep;
        };
    }

    override function create():Node{
        PieMenu();
        return groupMenu;
    }
}

def p = PieMenu{
    translateX: 100,
    translateY: 100,
    radius: 150
    scaleX: 0.001
    scaleY: 0.001
};

def background:Rectangle = Rectangle {
                width: bind scene.width, height: bind scene.height
                fill: Color.WHITE
            };

def anim = Timeline {
    keyFrames : [
        at(0s){
            p.scaleX => 0.001;
            p.scaleY => 0.001;
            p.rotate => 0;
        },
        at(150ms){
            p.scaleX => 1.1 tween Interpolator.EASEOUT;
            p.scaleY => 1.1 tween Interpolator.EASEOUT;
            p.rotate => -20 tween Interpolator.LINEAR;
        },
        at(500ms){
            p.scaleX => 1 tween Interpolator.EASEOUT;
            p.scaleY => 1 tween Interpolator.EASEOUT;
            p.rotate => 0 tween Interpolator.LINEAR;
        }
    ]
}

function animate(r:Integer){

    anim.rate = r;
    anim.play();
}

def scene:Scene = Scene{
    content: Group{
        content:[background, p]

            onMouseClicked: function( e: MouseEvent ):Void {
                if (e.button == MouseButton.SECONDARY ){
                    p.translateX = e.x;
                    p.translateY = e.y;
                    anim.stop();
                    animate(1);
                }
                if (e.button == MouseButton.PRIMARY and p.scaleX > 0.1){
                    animate(-1);
                }
            }
        }
}

Stage {
    title: "Pie Menu"
    width: 500
    height: 500
    scene: scene
}

Tinggalkan Balasan

Isikan data di bawah atau klik salah satu ikon untuk log in:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s