Package limelight.ui.model

Source Code of limelight.ui.model.PropPanel$MouseWheelAction

//- Copyright © 2008-2011 8th Light, Inc. All Rights Reserved.
//- Limelight and all included source files are distributed under terms of the MIT License.

package limelight.ui.model;

import limelight.Context;
import limelight.LimelightException;
import limelight.Log;
import limelight.events.Event;
import limelight.events.EventAction;
import limelight.model.CastingDirector;
import limelight.model.api.Player;
import limelight.model.api.PlayerRecruiter;
import limelight.model.api.PropProxy;
import limelight.styles.*;
import limelight.styles.abstrstyling.StyleValue;
import limelight.ui.PaintablePanel;
import limelight.ui.Painter;
import limelight.ui.Panel;
import limelight.ui.events.panel.MouseEnteredEvent;
import limelight.ui.events.panel.MouseExitedEvent;
import limelight.ui.events.panel.MouseWheelEvent;
import limelight.ui.events.panel.PanelEvent;
import limelight.ui.model.inputs.ScrollBarPanel;
import limelight.ui.painting.Border;
import limelight.ui.painting.DefaultPainter;
import limelight.ui.painting.PaintAction;
import limelight.util.*;

import java.awt.*;
import java.util.*;
import java.util.List;

public class PropPanel extends ParentPanelBase implements Prop, PaintablePanel, ChangeablePanel, StyleObserver
{
  protected static final Map<String, Object> EMPTY_OPTIONS = new EmptyMap<String, Object>();
  protected static final List<Player> EMPTY_PLAYERS = Collections.unmodifiableList(new LinkedList<Player>());

  private final PropProxy proxy;
  private String id;
  private String name;
  private final ScreenableStyle style;
  private final RichStyle hoverStyle;
  private Border borderShaper;
  private TextAccessor textAccessor;
  private Box marginedBounds;
  private Box borderedBounds;
  private Box paddedBounds;
  private Box childConsumableBounds;
  private PaintAction afterPaintAction;
  private ScrollBarPanel verticalScrollbar;
  private ScrollBarPanel horizontalScrollbar;
  private boolean sizeChangePending = true;
  public boolean borderChanged = true;
  private Painter painter = DefaultPainter.instance;
  private Cursor preHoverCursor;
  protected Map<String, Object> options;
  private List<Player> players;
  public Dimension greediness = new Dimension(0, 0);

  public PropPanel(PropProxy proxy)
  {
    this.proxy = proxy;
    textAccessor = TempTextAccessor.instance();
    style = new ScreenableStyle();
    hoverStyle = new RichStyle();
    style.addObserver(this);
    getEventHandler().add(MouseWheelEvent.class, MouseWheelAction.instance);
    getEventHandler().add(MouseEnteredEvent.class, HoverOnAction.instance);
    getEventHandler().add(MouseExitedEvent.class, HoverOffAction.instance);
  }

  public PropPanel(PropProxy proxy, Map<String, Object> options)
  {
    this(proxy);
    addOptions(options);
  }

  public String getText()
  {
    return textAccessor.getText();
  }

  public void setText(String text) throws LimelightException
  {
    textAccessor.setText(text, this);
  }

  public TextAccessor getTextAccessor()
  {
    return textAccessor;
  }

  public void setTextAccessor(TextAccessor textAccessor)
  {
    this.textAccessor = textAccessor;
  }

  public PropProxy getProxy()
  {
    return proxy;
  }

  @Override
  public Panel getOwnerOfPoint(Point point)
  {
    if(verticalScrollbar != null && verticalScrollbar.getAbsoluteBounds().contains(point))
      return verticalScrollbar;
    else if(horizontalScrollbar != null && horizontalScrollbar.getAbsoluteBounds().contains(point))
      return horizontalScrollbar;

    return super.getOwnerOfPoint(point);
  }

  public synchronized Box getMarginedBounds()
  {
    if(marginedBounds == null)
    {
      Box bounds = new Box(0, 0, getWidth(), getHeight());
      marginedBounds = bounds;
      Style style = getStyle();
      marginedBounds.shave(style.getCompiledTopMargin().pixelsFor(bounds.height),
        style.getCompiledRightMargin().pixelsFor(bounds.width),
        style.getCompiledBottomMargin().pixelsFor(bounds.height),
        style.getCompiledLeftMargin().pixelsFor(bounds.width));
    }
    return marginedBounds;
  }

  public synchronized Box getBorderedBounds()
  {
    if(borderedBounds == null)
    {
      Box bounds = getMarginedBounds();
      borderedBounds = (Box) bounds.clone();
      Style style = getStyle();
      borderedBounds.shave(style.getCompiledTopBorderWidth().pixelsFor(bounds.height),
        style.getCompiledRightBorderWidth().pixelsFor(bounds.width),
        style.getCompiledBottomBorderWidth().pixelsFor(bounds.height),
        style.getCompiledLeftBorderWidth().pixelsFor(bounds.width));
    }
    return borderedBounds;
  }

  public synchronized Box getPaddedBounds()
  {
    if(paddedBounds == null)
    {
      Box bounds = getBorderedBounds();
      paddedBounds = (Box) bounds.clone();
      Style style = getStyle();
      paddedBounds.shave(style.getCompiledTopPadding().pixelsFor(bounds.height),
        style.getCompiledRightPadding().pixelsFor(bounds.width),
        style.getCompiledBottomPadding().pixelsFor(bounds.height),
        style.getCompiledLeftPadding().pixelsFor(bounds.width));
    }
    return paddedBounds;
  }

  public Box getChildConsumableBounds()
  {
    if(childConsumableBounds == null)
    {
      Box boxInsidePadding = getPaddedBounds();
      int width = verticalScrollbar == null ? boxInsidePadding.width : boxInsidePadding.width - verticalScrollbar.getWidth();
      int height = horizontalScrollbar == null ? boxInsidePadding.height : boxInsidePadding.height - horizontalScrollbar.getHeight();
      childConsumableBounds = new Box(boxInsidePadding.x, boxInsidePadding.y, width, height);
    }
    return childConsumableBounds;
  }

  public void consumableAreaChanged()
  {
    Style style = getStyle();
    if(!needsLayout() && style != null && style.hasDynamicDimension())
      super.consumableAreaChanged();
  }

  @Override
  public Layout getDefaultLayout()
  {
    return PropPanelLayout.instance;
  }

  public void updateBorder()
  {
    if(borderShaper != null)
    {
      borderShaper.setBounds(getMarginedBounds());
      if(borderChanged)
      {
        borderShaper.updateDimentions();
        borderChanged = false;
      }
    }
  }

  public void paintOn(Graphics2D graphics)
  {
    painter.paint(graphics, this);

    if(afterPaintAction != null)
    {
      afterPaintAction.invoke(graphics);
    }
  }

  public ScreenableStyle getStyle()
  {
    return style;
  }

  public RichStyle getHoverStyle()
  {
    return hoverStyle;
  }

  public Border getBorderShaper()
  {
    if(borderShaper == null)
      borderShaper = new Border(getStyle(), getMarginedBounds());
    return borderShaper;
  }

  public void setCursor(Cursor cursor)
  {
    getRoot().setCursor(cursor);
  }

  @Override
  public String toString()
  {
    return getClass().getSimpleName() + "-[name: " + getName() + ", id: " + getId() + "]";
  }

  public void setAfterPaintAction(PaintAction action)
  {
    afterPaintAction = action;
  }

  public PaintAction getAfterPaintAction()
  {
    return afterPaintAction;
  }

  @Override
  public boolean isFloater()
  {
    return getStyle().getCompiledFloat().isOn();
  }

  //TODO super.clearCache() deals with absolute positioning.  Here the boxes are all relative.  They're uneccessarily being cleared.
  @Override
  public synchronized void clearCache()
  {
    super.clearCache();
    marginedBounds = null;
    borderedBounds = null;
    paddedBounds = null;
    childConsumableBounds = null;
  }

  public void styleChanged(StyleAttribute attribute, StyleValue value)
  {
    if(isIlluminated() && getParent() != null && getRoot() != null)
      attribute.applyChange(this, value);
  }

  public ScrollBarPanel getVerticalScrollbar()
  {
    return verticalScrollbar;
  }

  public ScrollBarPanel getHorizontalScrollbar()
  {
    return horizontalScrollbar;
  }

  public void addVerticalScrollBar()
  {
    verticalScrollbar = new ScrollBarPanel(ScrollBarPanel.VERTICAL);
    add(verticalScrollbar);
    childConsumableBounds = null;
  }

  public void addHorizontalScrollBar()
  {
    horizontalScrollbar = new ScrollBarPanel(ScrollBarPanel.HORIZONTAL);
    add(horizontalScrollbar);
    childConsumableBounds = null;
  }

  public void removeVerticalScrollBar()
  {
    remove(verticalScrollbar);
    verticalScrollbar = null;
    childConsumableBounds = null;
  }

  public void removeHorizontalScrollBar()
  {
    remove(horizontalScrollbar);
    horizontalScrollbar = null;
    childConsumableBounds = null;
  }

  public void playSound(String filename)
  {
    Context.instance().audioPlayer.playAuFile(filename);
  }

  public boolean isSizeChangePending()
  {
    return sizeChangePending;
  }

  public void setSizeChangePending(boolean value)
  {
    sizeChangePending = value;
  }

  public void propagateSizeChangeUp()
  {
    doPropagateSizeChangeUp(getParent());
  }

  public void propagateSizeChangeDown()
  {
    doPropagateSizeChangeDown();
  }

  public void resetPendingSizeChange()
  {
    sizeChangePending = false;
  }

  public boolean isBorderChanged()
  {
    return borderChanged;
  }

  public void setBorderChanged(boolean value)
  {
    borderChanged = value;
  }

  @Override
  protected boolean canRemove(Panel child)
  {
    return child != verticalScrollbar && child != horizontalScrollbar;
  }

  public void setPainter(Painter instance)
  {
    painter = instance;
  }

  public Painter getPainter()
  {
    return painter;
  }

  @Override
  public boolean hasFocus()
  {
    return textAccessor.hasFocus();
  }

  @Override
  public void illuminate()
  {
    if(isIlluminated())
      return;

    Map<String, Object> illuminateOptions = options == null ? EMPTY_OPTIONS : options;
    illuminateId(illuminateOptions.remove("id"));
    illuminateName(illuminateOptions.remove("name"));
    illuminatePlayers(illuminateOptions.remove("players"));
    illuminateStyles(illuminateOptions.remove("styles"));
    illuminateBackstage(illuminateOptions.remove("backstage"));

    Options.apply(this, illuminateOptions);
    illuminateOptions = applyPlayerOptions(illuminateOptions);
    Options.apply(getStyle(), illuminateOptions);

    proxy.applyOptions(illuminateOptions);

    logUnusedOptions(illuminateOptions);

    options = null;

    super.illuminate();
  }

  @Override
  public void delluminate()
  {
    getRoot().removeFromCaches(this);
    style.tearDown();
    hoverStyle.tearDown();
    super.delluminate();
  }

  public void addOptions(Map<String, Object> newOptions)
  {
    if(isIlluminated())
      throw new LimelightException("Cannot add options to an illuminated Prop");

    if(options == null)
      options = new HashMap<String, Object>(newOptions);
    else
    {
      for(Map.Entry<String, Object> entry : newOptions.entrySet())
        options.put(entry.getKey(), entry.getValue());
    }
  }

  public String getId()
  {
    return id;
  }

  public String getName()
  {
    return name;
  }

  public List<PropPanel> getChildPropPanels()
  {
    List<PropPanel> childProps = new LinkedList<PropPanel>();
    for(Panel child : getChildren())
    {
      if(child instanceof PropPanel)
        childProps.add((PropPanel) child);
    }
    return childProps;
  }

  public List<PropPanel> findByName(String name)
  {
    List<PropPanel> results = new LinkedList<PropPanel>();
    if(name == null)
      return results;
    findByName(name, results);
    return results;
  }

  private void findByName(String name, List<PropPanel> results)
  {
    if(name.equals(getName()))
      results.add(this);
    for(Panel panel : getChildren())
    {
      if(panel instanceof PropPanel)
        ((PropPanel) panel).findByName(name, results);
    }
  }

  // PRIVATE ///////////////////////////////////////////////////////////////////////////////////////////////////////////


  protected void illuminateName(Object nameObject)
  {
    if(nameObject != null)
      name = nameObject.toString();
  }

  protected void illuminateId(Object idObject)
  {
    if(idObject != null && !idObject.toString().isEmpty())
      id = idObject.toString();
    if(id != null)
      getRoot().addToIndex(this);
  }

  protected void illuminateStyles(Object stylesObject)
  {
    String allStyles = stylesObject == null ? "" : stylesObject.toString();

    if(name != null)
      allStyles = name + "," + allStyles;

    Map<String, RichStyle> store = getRoot().getStyles();
    String[] styleNames = allStyles.split("[ ,]+");
    for(String styleName : styleNames)
      addStyleNamed(styleName, store);
  }

  private void addStyleNamed(String styleName, Map<String, RichStyle> store)
  {
    if(styleName != null && !styleName.isEmpty())
    {
      RichStyle style = store.get(styleName);
      if(style != null)
        getStyle().addExtension(style);
      else if(!styleName.equals(name))
        Log.warn("Prop named '" + name + "' attempting to use missing style '" + styleName + "'");

      RichStyle hoverStyle = store.get(styleName + ".hover");
      if(hoverStyle != null)
      {
        getHoverStyle().addExtension(hoverStyle);
        getStyle().setDefault(Style.CURSOR, "hand");
      }
    }
  }

  protected boolean hasPlayerWithName(String name)
  {
    for(Player player : getPlayers())
    {
      if(StringUtil.snakeCase(player.getName()).equals(StringUtil.snakeCase(name)))
        return true;
    }
    return false;
  }

  protected void illuminatePlayers(Object playersObject)
  {
    ArrayList<String> playerNames = new ArrayList<String>();
    String allPlayers = playersObject == null ? "" : playersObject.toString();
    if(name != null)
      playerNames.add(name);

    for(String playerName : allPlayers.split("[ ,]+"))
    {
      if(!playerNames.contains(playerName))
        playerNames.add(playerName);
    }

    final Scene scene = getRoot();
    final PlayerRecruiter director = scene.getPlayerRecruiter();
    final CastingDirector castingDirector = Context.instance().castingDirector;
    for(String playerName : playerNames)
    {
      if(!playerName.isEmpty() && !hasPlayerWithName(playerName))
      {
        castingDirector.castRole(this, playerName, director);
      }
    }
  }

  private void illuminateBackstage(Object backstageObject)
  {
    if(backstageObject == null)
      return;
    if(!(backstageObject instanceof Map))
      throw new LimelightException("backstage must be a map, but is: " + backstageObject.getClass());
    Map backstage = (Map) backstageObject;
    getBackstage().inject(backstage);
  }

  private Map<String, Object> applyPlayerOptions(Map<String, Object> options)
  {
    Map<String, Object> result = options;
    for(Player player : getPlayers())
      result = player.applyOptions(this, result);
    return result;
  }

  private void logUnusedOptions(Map<String, Object> illuminateOptions)
  {
    for(Map.Entry<String, Object> entry : illuminateOptions.entrySet())
      Log.warn("Prop named '" + name + "' has unused option: " + entry.getKey() + " => " + entry.getValue());
  }

  public void addPlayer(Player player)
  {
    if(players == null)
      players = new LinkedList<Player>();
    players.add(player);
  }

  public List<Player> getPlayers()
  {
    if(players == null)
      return EMPTY_PLAYERS;
    return players;
  }

  public Opts getBackstage()
  {
    final Scene root = getRoot();
    if(root != null)
      return root.getBackstage(this);
    else
      throw new LimelightException("Backstage requires the prop to be part of a scene.");
  }

  private static class MouseWheelAction implements EventAction
  {
    public static MouseWheelAction instance = new MouseWheelAction();

    public void invoke(Event e)
    {
      PanelEvent event = (PanelEvent) e;
      if(!(event.getRecipient() instanceof PropPanel))
        return;

      MouseWheelEvent wheelEvent = (MouseWheelEvent) event;
      PropPanel panel = (PropPanel) event.getRecipient();
      ScrollBarPanel scrollBar = wheelEvent.isVertical() ? panel.getVerticalScrollbar() : panel.getHorizontalScrollbar();
      if(scrollBar != null)
        scrollBar.setValue(scrollBar.getValue() + wheelEvent.getUnitsToScroll());
      else if(panel.getParent() != null)
        event.dispatch(panel.getParent());
    }
  }

  private static class HoverOnAction implements EventAction
  {
    public static HoverOnAction instance = new HoverOnAction();

    public void invoke(Event e)
    {
      PanelEvent event = (PanelEvent) e;
      final PropPanel panel = (PropPanel) event.getRecipient();
      if(panel.getRoot() == null)
        return;
      //TODO MDM - If the prop has no surface area (perhasps it's a floater that floated out of bounds), does it still get the mouseExited event?
      if(!panel.getStyle().hasScreen())
        panel.getStyle().applyScreen(panel.getHoverStyle()); // TODO - MDM - This seems inefficient considering most of the time, there's no change in styles.

      Cursor currentCursor = panel.getRoot().getCursor();
      Cursor hoverCursor = panel.getStyle().getCompiledCursor().getCursor();
      if(hoverCursor != currentCursor)
      {
        panel.preHoverCursor = currentCursor;
        panel.getRoot().setCursor(hoverCursor);
      }
    }
  }

  private static class HoverOffAction implements EventAction
  {
    public static HoverOffAction instance = new HoverOffAction();

    public void invoke(Event e)
    {
      PanelEvent event = (PanelEvent) e;
      final PropPanel panel = (PropPanel) event.getRecipient();
      if(panel.getStyle().hasScreen())
        panel.getStyle().removeScreen();

      if(panel.preHoverCursor != null)
      {
        final Scene root = panel.getRoot();
        // TODO MDM - If the panel is removed from the scene, the cursor is never changed.  Perhaps the right way to do this is in the MouseListener... when ever entering a panel, get the cursor and change it.... when exiting a panel, pop the cursor
        if(root != null)
          root.setCursor(panel.preHoverCursor);
        panel.preHoverCursor = null;
      }
    }
  }
}
TOP

Related Classes of limelight.ui.model.PropPanel$MouseWheelAction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.