Package com.scriptographer.adm.ui

Source Code of com.scriptographer.adm.ui.AdmComponentProxy

/*
* Scriptographer
*
* This file is part of Scriptographer, a Scripting Plugin for Adobe Illustrator
* http://scriptographer.org/
*
* Copyright (c) 2002-2010, Juerg Lehni
* http://scratchdisk.com/
*
* All rights reserved. See LICENSE file for details.
*
* File created on Jun 2, 2010.
*/

package com.scriptographer.adm.ui;

import java.util.LinkedHashMap;

import com.scratchdisk.script.ScriptEngine;
import com.scratchdisk.util.ConversionUtils;
import com.scriptographer.adm.Border;
import com.scriptographer.adm.Button;
import com.scriptographer.adm.CheckBox;
import com.scriptographer.adm.ColorButton;
import com.scriptographer.adm.Dialog;
import com.scriptographer.adm.FontPopupList;
import com.scriptographer.adm.FontPopupListOption;
import com.scriptographer.adm.Frame;
import com.scriptographer.adm.FrameStyle;
import com.scriptographer.adm.Item;
import com.scriptographer.adm.ItemGroup;
import com.scriptographer.adm.ListEntry;
import com.scriptographer.adm.PopupList;
import com.scriptographer.adm.PopupMenu;
import com.scriptographer.adm.Size;
import com.scriptographer.adm.Slider;
import com.scriptographer.adm.SpinEdit;
import com.scriptographer.adm.TextEdit;
import com.scriptographer.adm.TextEditItem;
import com.scriptographer.adm.TextOption;
import com.scriptographer.adm.TextPane;
import com.scriptographer.adm.TextValueItem;
import com.scriptographer.adm.ToggleItem;
import com.scriptographer.adm.ValueItem;
import com.scriptographer.adm.layout.TableLayout;
import com.scriptographer.ai.Color;
import com.scriptographer.ai.FontWeight;
import com.scriptographer.ai.RGBColor;
import com.scriptographer.ui.Component;
import com.scriptographer.ui.ComponentProxy;
import com.scriptographer.ui.ComponentType;
import com.scriptographer.ui.TextUnits;

/**
* @author lehni
*
*/
public class AdmComponentProxy extends ComponentProxy {
  // Used for scaling slider values
  private double factor = 1;

  private Integer selectedIndex;

  // Native items / entries
  private Item item;
  private ListEntry entry;

  public AdmComponentProxy(Component component) {
    super(component);
    // Set scaling factor for Slider to allow fractional digits
    if (component.getType() == ComponentType.SLIDER)
      factor = 1000;
  }

  protected Item createItem(Dialog dialog) {
    // Item:
    item = null;
    ComponentType type = component.getType();
    switch (type) {
    case NUMBER: {
      Boolean steppers = component.getSteppers();
      if (steppers != null && steppers) {
        item = new SpinEdit(dialog) {
          protected void onChange() {
            AdmComponentProxy.this.onChange(true);
          }
        };
      } else {
        TextEditItem textItem = new TextEdit(dialog) {
          protected void onChange() {
            AdmComponentProxy.this.onChange(true);
          }
        };
        textItem.setAllowMath(true);
        textItem.setAllowUnits(true);
        item = textItem;
      }
    }
    break;
    case STRING: {
      Boolean multiline = component.getMultiline();
      TextOption[] options = multiline != null && multiline
          ? new TextOption[] { TextOption.MULTILINE }
          : null;
      item = new TextEdit(dialog, options) {
        protected void onChange() {
          AdmComponentProxy.this.onChange(true);
        }
      };
    }
    break;
    case TEXT: {
      item = new TextPane(dialog);
      // Space a bit more to the top, to compensate the descender space.
      item.setMargin(new Border(1, 0, 0, 0));
    }
    break;
    case RULER: {
      // If the ruler has a label, add it to the left of it, using an
      // ItemGroup and a TableLayout. The ItemGroup needs to be created
      // before the frame, otherwise layouting issues arise...
      // Ideally this should be resolved, but as ADM is on its way out,
      // just work around it for now.
      ItemGroup group;
      String label = component.getLabel();
      if (label != null && !label.equals("")) {
        group = new ItemGroup(dialog);
        TextPane labelItem = new TextPane(dialog);
        labelItem.setText(label);
        // Use 3 rows, so the center one with the ruler gets centered,
        // then span the label across all three.
        double[][] sizes = {
          new double[] { TableLayout.PREFERRED, TableLayout.FILL },
          new double[] { TableLayout.FILL, TableLayout.PREFERRED,
              TableLayout.FILL }
        };
        group.setLayout(new TableLayout(sizes));
        group.add(labelItem, "0, 0, 0, 2");
        group.setMarginTop(2);
      } else {
        group = null;
      }
      Frame frame = new Frame(dialog);
      frame.setStyle(FrameStyle.SUNKEN);
      // Margin needs to be set before changing size...
      // TODO: Fix this in UI package?
      int top = label != null ? 2 : 4, bottom = 4;
      frame.setMargin(top, 0, bottom, 0);
      // Margin is included inside size, not added. This is different
      // to how things works with CSS...
      // TODO: Fix this in UI package?
      frame.setHeight(2 + top + bottom);
      // Now finish setting up the layout group and label
      if (group != null) {
        group.add(frame, "1, 1, full, center");
        item = group;
      } else {
        item = frame;
      }
    }
    break;
    case SLIDER: {
      item = new Slider(dialog) {
        protected void onChange() {
          AdmComponentProxy.this.onChange(true);
        }
      };
    }
    break;
    case BOOLEAN: {
      item = new CheckBox(dialog) {
        protected void onClick() {
          AdmComponentProxy.this.onChange(true);
        }
      };
    }
    break;
    case LIST: {
      item = new PopupList(dialog, true) {
        protected void onChange() {
          selectedIndex = this.getSelectedEntry().getIndex();
          AdmComponentProxy.this.onChange(true);
        }
      };
    }
    break;
    case BUTTON: {
      item = new Button(dialog) {
        protected void onClick() {
          AdmComponentProxy.this.onClick();
        }
      };
    }
    break;
    case COLOR: {
      item = new ColorButton(dialog) {
        protected void onClick() {
          AdmComponentProxy.this.onChange(true);
        }
      };
    }
    break;
    case FONT: {
      item = new FontPopupList(dialog, new FontPopupListOption[] {
          FontPopupListOption.EDITABLE,
          FontPopupListOption.VERTICAL
      }) {
        protected void onChange() {
          AdmComponentProxy.this.onChange(true);
        }
      };
    }
    break;
    case MENU_ENTRY:
    case MENU_SEPARATOR: {
      PopupMenu menu = dialog.getPopupMenu();
      if (menu != null) {
        entry = new ListEntry(menu) {
          protected void onSelect() {
            AdmComponentProxy.this.onSelect();
          }
        };
        if (type == ComponentType.MENU_SEPARATOR)
          entry.setSeparator(true);
      }
    }
    break;
    }
    initialize();
    return item;
  }

  protected int addToContent(Dialog dialog,
      LinkedHashMap<String, com.scriptographer.adm.Component> content,
      int column, int row) {
    Item valueItem = createItem(dialog);
    String label = component.getLabel();
    boolean isRuler = component.getType() == ComponentType.RULER;
    boolean hasLabel = !isRuler && label != null && !"".equals(label);
    if (hasLabel) {
      TextPane labelItem = new TextPane(dialog);
      labelItem.setText(label + ":");
      // Adjust top margin of label to reflect the native margin
      // in the value item.
      Item marginItem = valueItem;
      // If this is an item group, use the first item in it instead
      // This is only needed for FontPopupList so far.
      if (marginItem instanceof ItemGroup)
        marginItem = (Item) ((ItemGroup) marginItem).getContent().get(0);
      Border margin = marginItem.getVisualMargin();
      // Also take into account any margins the component might have set
      if (valueItem != marginItem)
        margin = margin.add(valueItem.getMargin());
      labelItem.setMargin(margin.top + 3, 4, 0, 0);
      content.put(column + ", " + row + ", right, top", labelItem);
    }
    boolean fullSize = component.getFullSize();
    String justification = isRuler || component.getFullSize()
        ? "full, center" : "left, center";
    content.put(isRuler || !hasLabel && fullSize
        ? column + ", " + row  + ", " + (column + 1) + ", " + row + ", "
            + justification
        : (column + 1) + ", " + row + ", " + justification,
        valueItem);
    return row + 1;
  }

  protected Size getSize() {
    if (item != null) {
      Size size;
      Boolean multiline = component.getMultiline();
      Integer columns = component.getColumns();
      Integer rows = component.getRows();
      if (multiline != null && multiline && columns != null
          && rows != null) {
        // Base width on an average wide character, such as H
        size = item.getTextSize("H");
        size = new Size(
            size.width * columns + 8,
            size.height * rows + 8
        );
      } else {
        // Use preferred size instead of best size for ruler, as we want
        // to take into account items of which the size was already set.
        size = component.getType() == ComponentType.RULER
            ? item.getPreferredSize()
            : item.getBestSize();
        Integer length = component.getLength();
        if (length != null)
          size.width = item.getTextSize("H").width * length;
      }
      Integer width = component.getWidth();
      if (width != null)
        size.width = width;
      Integer height = component.getHeight();
      if (height != null)
        size.height = height;
      return size;
    }
    return null;
  }

  public void updateSize() {
    if (item != null) {
      Size size = getSize();
      if (size != null && !size.equals(item.getSize())) {
        item.setSize(size);
        onSizeChanged();
      }
    }
  }

  public Object getValue() {
    if (item == null)
      return component.getDefaultValue();
    switch (component.getType()) {
    case STRING:
    case TEXT:
      return ((TextValueItem) item).getText();
    case BUTTON:
      return ((Button) item).getText();
    case NUMBER:
      return ((ValueItem) item).getValue();
    case SLIDER:
      double value = ((ValueItem) item).getValue() / factor;
      Double inc = component.getIncrement();
      if (inc != null) {
        double pre = value;
        value = Math.round(value / inc) * inc;
        if (pre != value)
          ((ValueItem) item).setValue((float) (value * factor));
      }
      return value;
    case BOOLEAN:
      return ((ToggleItem) item).isChecked();
    case LIST:
      ListEntry selected = ((PopupList) item).getSelectedEntry();
      if (selected != null)
        return component.getOption(selected.getIndex());
      break;
    case COLOR:
      return ((ColorButton) item).getColor();
    case FONT:
      return ((FontPopupList) item).getFontWeight();
    }
    return null;
  }

  public boolean setValue(Object value) {
    if (item == null && entry == null)
      return false;
    boolean callOnChange = true;
    switch (component.getType()) {
    case STRING:
    case TEXT: {
      String text = ConversionUtils.toString(value);
      Integer maxLength = component.getMaxLength();
      if (maxLength != null && text != null
          && text.length() > maxLength)
        text = text.substring(0, maxLength);
      ((TextValueItem) item).setText(text);
      updateSize();
    }
    break;
    case BUTTON: {
      ((Button) item).setText(ConversionUtils.toString(value));
      updateSize();
    }
    break;
    case NUMBER:
    case SLIDER: {
      ((ValueItem) item).setValue(
          (float) (ConversionUtils.toDouble(value) * factor));
    }
    break;
    case BOOLEAN: {
      ((CheckBox) item).setChecked(ConversionUtils.toBoolean(value));
    }
    break;
    case LIST: {
      PopupList list = (PopupList) item;
      int index = selectedIndex != null ? selectedIndex : 0;
      for (int i = 0, l = list.size(); i < l; i++) {
        Object option = component.getOption(i);
        if (ConversionUtils.equals(value, option)) {
          index = i;
          break;
        }
      }
      setSelectedIndex(index, false);
      // No need to call onChange, as setSelectionIndex already does:
      callOnChange = false;
    }
    break;
    case COLOR: {
      Color color = ScriptEngine.convertToJava(value, Color.class);
      if (color == null)
        color = new RGBColor(0, 0, 0);
      ((ColorButton) item).setColor(color);
    }
    break;
    case FONT: {
      FontWeight weight = ScriptEngine.convertToJava(value,
          FontWeight.class);
      if (weight != null)
        ((FontPopupList) item).setFontWeight(weight);
    }
    break;
    case MENU_ENTRY: {
      entry.setText(ConversionUtils.toString(value));
    }
    break;
    }
    // Update palette's value object too
    if (callOnChange)
      onChange(false);
    return true;
  }

  public Integer getSelectedIndex() {
    return selectedIndex;
  }

  public boolean setSelectedIndex(Integer index, boolean callback) {
    selectedIndex = index;
    if (item == null)
      return false;
    // TODO: Handle index == null ?
    PopupList list = (PopupList) item;
    list.setSelectedEntry(list.get(index));
    return true;
  }

  public boolean setRange(Double min, Double max) {
    if (item == null)
      return false;
    ((ValueItem) item).setRange(
        (float) (min != null ? min * factor : Integer.MIN_VALUE),
        (float) (max != null ? max * factor : Integer.MAX_VALUE));
    return true;
  }

  public void setIncrement(double increment) {
    if (item != null)
      ((ValueItem) item).setIncrements((float) (increment * factor));
  }

  public void setFractionDigits(Integer fractionDigits) {
    if (item != null)
      ((TextEditItem) item).setFractionDigits(fractionDigits);
  }

  public void setUnits(TextUnits units) {
    if (item != null) {
      TextEditItem textItem = (TextEditItem) item;
      textItem.setUnits(units);
      textItem.setShowUnits(units != TextUnits.NONE);
    }
  }

  public void setSteppers(Boolean steppers) {
    // No support to change this at runtime for now
  }

  public void setVisible(boolean visible) {
    if (item != null)
      item.setVisible(visible);
  }

  public void setEnabled(boolean enabled) {
    if (item != null)
      item.setEnabled(enabled);
  }

  public void setMaxLength(Integer maxLength) {
    if (item != null)
      ((TextEditItem) item).setMaxLength(maxLength != null
          ? maxLength : -1);
  }

  public void setOptions(Object[] options, Object current) {
    if (item == null)
      return;
    PopupList list = (PopupList) item;
    list.removeAll();
    if (options != null && options.length > 0) {
      int index = selectedIndex != null ? selectedIndex : 0;
      for (int i = 0; i < options.length; i++) {
        Object option = options[i];
        if (option.equals(current))
          index = i;
        ListEntry entry = null;
        if (option instanceof ListEntry) {
          entry = (ListEntry) option;
          entry = list.add(entry);
        } else {
          entry = new ListEntry(list);
          // Simplify names for art items
          String name = option instanceof com.scriptographer.ai.Item
              ? ((com.scriptographer.ai.Item) option).getName()
              : null;
          entry.setText(name != null ? name : option.toString());
        }
      }
      if (index < 0)
        index = 0;
      else if (index >= options.length)
        index = options.length - 1;
      // We're changing options, not value, so cause onChange
      // callback for value
      setSelectedIndex(index, true);
      updateSize();
    }
  }
}
TOP

Related Classes of com.scriptographer.adm.ui.AdmComponentProxy

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.