/* * Copyright © 2012 Nokia Corporation. All rights reserved. * Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation. * Oracle and Java are trademarks or registered trademarks of Oracle and/or its * affiliates. Other product and company names mentioned herein may be trademarks * or trade names of their respective owners. * See LICENSE.TXT for license information. */ package com.nokia.example.drumkit.components; import com.nokia.example.drumkit.helpers.ImageLoader; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.Image; import java.util.Timer; import java.util.TimerTask; /** * Round menu component */ public class WheelMenu implements Button.Listener { private static final int BUTTON_COUNT = 12; private static final int MAX_RADIUS = 80; private static final int UPDATE_INTERVAL = 30; private static final int DELTA_RADIUS = 8; // pixels private static final float ANGLE = (float) (2 * Math.PI / BUTTON_COUNT); private int radius = 0; private int btnWidth = 49; private int btnHeight = 49; private int originX = 0; private int originY = 0; private int destinationX = 0; private int destinationY = 0; private boolean visible = false; private boolean open = false; private Button selected; private Button[] buttons = new Button[12]; private Timer animator; private final Image tapToSelect; private final Listener listener; /** * Interface for listening wheel events */ public interface Listener { void wheelOpened(); void wheelClosed(); void wheelItemSelected(Button button); } public WheelMenu(Listener listener) { this.listener = listener; createButtons(); animator = new Timer(); tapToSelect = ImageLoader.loadImage("/tap.png"); } /** * Create buttons for the wheel menu */ private void createButtons() { buttons[0] = new Button("/kick.png", "/kick_highlight.png", "/kick.png", this); buttons[1] = new Button("/snare.png", "/snare_highlight.png", "/snare.png", this); buttons[2] = new Button("/cowbell.png", "/cowbell_highlight.png", "/cowbell.png", this); buttons[3] = new Button("/hihat2.png", "/hihat2_highlight.png", "/hihat2.png", this); buttons[4] = new Button("/hihat1.png", "/hihat1_highlight.png", "/hihat1.png", this); buttons[5] = new Button("/crash.png", "/crash_highlight.png", "/crash.png", this); buttons[6] = new Button("/splash.png", "/splash_highlight.png", "/splash.png", this); buttons[7] = new Button("/ride2.png", "/ride2_highlight.png", "/ride2.png", this); buttons[8] = new Button("/ride1.png", "/ride1_highlight.png", "/ride1.png", this); buttons[9] = new Button("/tom1.png", "/tom1_highlight.png", "/tom1.png", this); buttons[10] = new Button("/tom2.png", "/tom2_highlight.png", "/tom2.png", this); buttons[11] = new Button("/tom3.png", "/tom3_highlight.png", "/tom3.png", this); // The third (disabled) image is actually not used with wheel for (int i = 0; i < buttons.length; i++) { buttons[i].setSelectable(true); } } /** * Show wheel menu */ public void show() { animator.cancel(); animator = new Timer(); TimerTask grow = new TimerTask() { public void run() { if (radius < MAX_RADIUS) { radius += DELTA_RADIUS; updateWheel(); } else { listener.wheelOpened(); open = true; this.cancel(); } } }; visible = true; animator.schedule(grow, 0, UPDATE_INTERVAL); } /** * Hide wheel menu */ public void hide() { open = false; animator.cancel(); animator = new Timer(); TimerTask shrink = new TimerTask() { public void run() { if (radius > 0) { radius -= DELTA_RADIUS; updateWheel(); } else { radius = 0; visible = false; listener.wheelClosed(); this.cancel(); } } }; animator.schedule(shrink, 0, UPDATE_INTERVAL); } /** * Calculate button positions */ public void updateWheel() { float ratio = (float) radius / MAX_RADIUS; int newX = originX + (int) ((float) (destinationX - originX) * ratio); int newY = originY + (int) ((float) (destinationY - originY) * ratio); int btnX = 0; int btnY = 0; // AngleExtra is used to get the spinning effect float angleExtra = 8 * ratio; for (int i = 0; i < BUTTON_COUNT; i++) { btnX = (int) (Math.cos(i * ANGLE + angleExtra) * radius); btnY = (int) (Math.sin(i * ANGLE + angleExtra) * radius); buttons[i].setPosition(btnX - btnWidth / 2 + newX, btnY - btnHeight / 2 + newY); } } /** * Render wheel menu * @param g Graphics */ public void paint(Graphics g) { if (visible) { for (int i = 0; i < BUTTON_COUNT; i++) { buttons[i].paint(g); } if (open) { g.drawImage(tapToSelect, destinationX - tapToSelect.getWidth() / 2, destinationY - tapToSelect.getHeight() / 2, Graphics.TOP | Graphics.LEFT); } } } /** * Handles pressed events */ public void pointerPressed(int x, int y) { if (open) { int dX = destinationX - x; int dY = destinationY - y; int distance = (int) Math.sqrt(dX * dX + dY * dY); if (distance < tapToSelect.getWidth() / 3) { hide(); } else { for (int i = 0; i < BUTTON_COUNT; i++) { if (buttons[i] != selected) { buttons[i].pointerPressed(x, y); } } } } } /** * Handles dragged events */ public void pointerDragged(int x, int y) { if (open) { for (int i = 0; i < BUTTON_COUNT; i++) { if (buttons[i] != selected) { buttons[i].pointerDragged(x, y); } } } } /** * Handles released events */ public void pointerReleased(int x, int y) { if (open) { for (int i = 0; i < BUTTON_COUNT; i++) { if (buttons[i] != selected) { buttons[i].pointerReleased(x, y); } } } } public boolean isVisible() { return visible; } /** * Center coordinate for wheel menu origin * @param x * @param y */ public void setOrigin(int x, int y) { this.originX = x; this.originY = y; } /** * Center coordinate for wheel menu destination * @param x * @param y */ public void setDestination(int x, int y) { this.destinationX = x; this.destinationY = y; } /** * Get index of the selected toggle button * @return Index */ public int getSelectedIndex() { int index = -1; for (int i = 0; i < buttons.length; i++) { if (buttons[i] == selected) { index = i; break; } } return index; } /** * Select menu item */ public void select(int index) { if (selected != null) { selected.deslect(); } selected = buttons[index]; selected.select(); } /** * Handle clicks of menu buttons * @param button Source button */ public void clicked(Button button) { if (selected != null) { selected.deslect(); } selected = button; listener.wheelItemSelected(button); } }