/* * Copyright (c) 2012 Felix Mo. All rights reserved. * * CitySim is published under the terms of the MIT License. See the LICENSE file for more information. * */ import greenfoot.*; import java.util.ArrayList; import java.awt.Color; import java.awt.FontMetrics; import java.awt.Point; import java.awt.Rectangle; /** * Menu view and view controller; extends MenuElement. * * @author Felix Mo * @version v1.0 * @since 2012-04-19 */ public class Menu extends MenuElement { // --------------------------------------------------------------------------------------------------------------------- /* * INSTANCE VARIABLES */ private MenuBarItem menuBarItem; // The menu bar item the menu belongs to private ArrayList<MenuItem> menuItems; // The MenuItem actors that belong to the Menu private int activeIndex = -1; // The index of the current active menu item (-1 = none) private MouseInfo mouseInfo; // A reference to the MouseInfo object provided by the Greenfoot framework // --------------------------------------------------------------------------------------------------------------------- /* * CONSTRUCTORS * */ /** * Constructs a Menu. * * @param menuBarItem The menu bar item that the menu belongs to. * @param items The items in the menu (as {@link Strings}) */ public Menu(MenuBarItem menuBarItem, ArrayList<String> items) { super("", 0); this.menuBarItem = menuBarItem; setItems(items); } // --------------------------------------------------------------------------------------------------------------------- /* * GREENFOOT METHODS */ /** * Draws, and activates, the menu when it is added to the world. * * @param World The {@link World} the object was added to. */ protected void addedToWorld(World world) { // Activate this menu this.active = true; // Draw the menu if it has not already been drawn if (this.image != null) draw(); } /** * The procedure to draw the menu and its menu items. */ private void draw() { Point origin = this.frame.getLocation(); this.image.clear(); // Draw menu this.image.setColor(Color.WHITE); this.image.fillRect(0, 0, this.frame.width, this.frame.height); // Draw menu outline this.image.setColor(Color.BLACK); this.image.drawRect(0, 0, this.frame.width, this.frame.height); // Add menu items to menu for (MenuItem menuItem : menuItems) { City.getInstance().addObject(menuItem, menuItem.frame().x+(int)menuItem.frame().width/2, menuItem.frame().y); } } /** * The procedure containing the menu's behaviour. The menu will highlight menu items as the cursor hovers over them. */ public void act() { // Get mouse position Point mouse = null; if (Greenfoot.getMouseInfo() != null) { mouseInfo = Greenfoot.getMouseInfo(); } // Get the menu item the cursor is currently hovering over if (active) { if (mouseInfo != null) { mouse = new Point(mouseInfo.getX(), mouseInfo.getY()); // Check horizontal bounds if (mouse.x <= this.frame.width + this.frame.x && mouse.x >= menuBarItem.frame().x) { // Check vertical bounds if (mouse.y <= this.frame.height + this.frame.y && mouse.y >= menuBarItem.frame().height) { // Iterate through all the menu items to check if cursor is within the bounds of their frames for (MenuItem item : menuItems) { Rectangle frame = item.frame(); Point origin = item.frame().getLocation(); if (mouse.y >= origin.y && mouse.y <= origin.y + frame.height) { // Activate menu item IF it is not the current active item (prevents redundancy) if (menuItems.indexOf(item) != this.activeIndex) { didHoverOverMenuItem(item); } } } } } } } } // --------------------------------------------------------------------------------------------------------------------- /* * MENU * */ /** * Menu behaviour for hovering over a menu item. * * @param menuItem The menu item that the cursor is currently hovering over. */ public void didHoverOverMenuItem(MenuItem menuItem) { // Activate the menu item for (MenuItem item : menuItems) { item.setActive(item == menuItem ? (active ? true : false) : false); } // Update index this.activeIndex = menuItem.index(); } // --------------------------------------------------------------------------------------------------------------------- /* * ACCESSORS * */ /** * Returns the {@link MenuItems} that belongs to the menu. * * @return The {@link MenuItems} belonging to the menu. */ public ArrayList<MenuItem> menuItems() { return this.menuItems; } /** * Sets the items of the menu. * * @param items The titles (as {@link Strings}) of the menu's items. */ public void setItems(ArrayList<String> items) { // Create frame based on dimensions derived from font metrics FontMetrics fontMetrics = new GreenfootImage(1024, 768).getAwtImage().getGraphics().getFontMetrics(FONT); int width = 0; int index = 0; // Find the widest menu item and use it's width + padding as the menu width for (String item : items) { if (fontMetrics.stringWidth(item) > width) { width = fontMetrics.stringWidth(item)+36; } } // Create the 'MenuItem' actors this.menuItems = new ArrayList<MenuItem>(items.size()); for (String item : items) { MenuItem menuItem = new MenuItem(item, this, index); Rectangle miFrame = new Rectangle(menuBarItem.frame().x, menuBarItem.frame().y+14+10+index*24, width, 22); menuItem.setFrame(miFrame); this.menuItems.add(menuItem); index++; } int height = items.size() * 24; // 14px + 4px padding this.frame = new Rectangle(menuBarItem.frame().x, menuBarItem.frame().y+14, width, height); // Recreate the menu's view with the new dimensions this.image = new GreenfootImage(width, height); setImage(this.image); } /** * Sets the state of the menu. * * @param The new state of the menu. */ public void setActive(boolean state) { this.active = state; // If the menu is now inactive if (!active) { // Reset the active index to -1 (no selection); this.activeIndex = -1; // Deactivate the menu bar item that this menu belogns to this.menuBarItem.menuBar().changeItemStateTo(this.menuBarItem, false); } } }