Package jcurses.widgets

Source Code of jcurses.widgets.WindowWidgetComparator

package jcurses.widgets;


import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jcurses.event.WindowEvent;
import jcurses.event.WindowListener;
import jcurses.event.WindowListenerManager;
import jcurses.system.CharColor;
import jcurses.system.InputChar;
import jcurses.system.Toolkit;
import jcurses.util.Rectangle;

/**
* This class is a jcurses implementation of an text based window. An window
*  under jcurses is, differnt from other GUI libraries, not a widget, this
*  contains a panel ( a the called root panel ), that contains all widgets.
*  A window can, but doesn't must, have a border and a title.
*  All windows under jcurses are managed in a stack, the topmost visible window
*  window on the stack gets all input chars for handling, this is so called focus
*  window. If an window are created, it gets automatically to the top of the stack
*  and leaves the until an other window is created or explicitly brought to the top.
*/

public class Window {

  private Panel _root = null;
 
  private List<Widget> _focusableChilds = null;
  private int _currentIndex = -1;
 
  private boolean _visible = false;
 
  private Rectangle _rect = null;
 
  private boolean _border = false;
  private String _title = null;
 
  private boolean _hasShadow = true;
 
  private List<InputChar> _shortCutsList = new ArrayList<InputChar>();
  private Map<InputChar, Widget> _shortCutsTable = new HashMap<InputChar, Widget>();
 
  boolean _closed = false;
 

 
   /**
   *  The constructor
   *
   * @param x the the top left corner's x coordinate
   * @param y the top left corner's y coordinate
   * @param width window's width
   * @param height window's height
   * @param border true, if the window has a border, false in other case
   */
  public Window (int x, int y, int width, int height, boolean border, String title) {
    _border = border;
    _title = title;
    _rect = new Rectangle(width, height);
    _rect.setLocation(x, y);
   
    int x1 = border?x+1:x;
    int y1 = border?y+1:y;
    int w = border?width-2:width;
    int h = border?height-2:height;
   
    _root = new Panel(w, h);
    _root.setSize(new Rectangle(w, h));
    _root.setX(x1);
    _root.setY(y1);
    _root.setWindow(this);
    WindowManager.createWindow(this);
  }
 
 
   /**
   *  The constructor. A window created with this constructor is centered on the screen.
   *
   * @param width window's width
   * @param height window's height
   * @param border true, if the window has a border, false in other case
   */
  public Window (int width, int height, boolean border, String title) {
    this((Toolkit.getScreenWidth()-width)/2,(Toolkit.getScreenHeight()-height)/2, width, height, border, title);
  }
 
 
  private void configureRootPanel() {
    if (_root == null) {
      _root = new Panel();
    }
   
    int x = _rect.getX();
    int y = _rect.getY();
    int width = _rect.getWidth();
    int height = _rect.getHeight();
   
    int x1 = _border?x+1:x;
    int y1 = _border?y+1:y;
    int w =  _border?width-2:width;
    int h =  _border?height-2:height;
   
    _root.setSize(new Rectangle(w, h));
    _root.setX(x1);
    _root.setY(y1);
   
  }
 
 
  /**
  *  The method shows the window
  */
  public void show() {
    setVisible(true);
  }
 
  /**
  *  The method hides the window
  */
 
  public void hide() {
    setVisible(false);
  }
 
 
  /**
  * The method changes the window's visibility status
    *
    * @param value true, if the window becomes visible, false in other case
  */
 
  public void setVisible(boolean value){
    Window oldTop = WindowManager.getTopWindow();
    if (value) {
      pack();
      _visible = value;
      WindowManager.makeWindowVisible(this, oldTop);
    } else {
      _visible = value;
      WindowManager.makeWindowInvisible(this, oldTop);
    }
  }
 
 
    /**
    *  The method returns the window's visibility status
    * @return true, if the window becomes visible, false in other case
    */
  public boolean isVisible() {
    return _visible;
  }
 
    /**
    *  The method paint's the window
    */
 
  protected void paint() {
    drawThingsIfNeeded();
    _root.paint();
  }
 
   
    /**
    *  Currently the method makes the same as repaint, in next versions the method
    * will repaint only the part of the window, that was hided.
    */
 
  protected void repaint() {
    drawThingsIfNeeded();
    _root.repaint();
  }
 
  /**
  *  @return the rectangle occupied by the window
  */
 
  protected Rectangle getRectangle() {
    return _rect;
  }
 
  /**
  *  The method closed the window, that is removes it from window stack an
    *  evantually from screen, if it was visible.
  */
 
  public void close() {
    WindowManager.removeWindow(this);
  }
   
 
  /**
  * The method moves the window to the top of the stack
  */
 
  public void moveToTheTop() {
    WindowManager.moveToTop(this);
  }
 
  /**
  *  Folgende Methoden bestimmen das zeichen das benutzt wird, um das Fenster zu schlie�en
  */
 
  private static InputChar __defaultClosingChar = new InputChar(27);//escape character
  private InputChar  _closingChar = getDefaultClosingChar();
 
 
  private InputChar getDefaultClosingChar() {
    return __defaultClosingChar;
  }
 
 
    /**
    *  The method returns the character to close window.
    * As default is escape characted defined
    *
    * @return window's closing character
    */
  public InputChar getClosingChar() {
    return _closingChar;
  }
 
 
 
    /**
    *  The method defines a new window's closing character. Default is escape.
    * @param character new  window's closing character
    */
  public void setClosingChar(InputChar character) {
     _closingChar = character;
  }
 
 
 
  private static InputChar __defaultFocusChangeChar = new InputChar('\t');//tab character
  private InputChar  _focusChangeChar = getDefaultFocusChangeChar();
 
 
  private InputChar getDefaultFocusChangeChar() {
    return __defaultFocusChangeChar;
  }
 
  /**
  *  The method returns the charater used to navigate (change the focus) between widgets
    * within the window. Default is 'tab'
    *
    * @return window's focus changing charater
  */
  public InputChar getFocusChangeChar() {
    return _focusChangeChar;
  }
 
 
  /**
  *  The method defined the charater used to navigate (change the focus) between widgets
    * within the window. Default is 'tab'
    *
    * @param character new window's focus changing charater
  */
  public void setFocusChangeChar(InputChar character) {
     _focusChangeChar = character;
  }
 
  /**
  *  Behandlung der Eingabe.
  *  Vier m�gliche F�lle:
  *  1. Fenster schliessen.
  *  2. Zum n�chsten Widget springen.
  *  3. Shortcut bearbeiten.
  *  3. Eingabe vom aktuell Fokus habenden Kind bearbeiten lassen.
  */
 
 
  private boolean isShortCut(InputChar inp) {
    return (_shortCutsList.indexOf(inp)!=-1);
  }
 
 
  private Widget getWidgetByShortCut(InputChar inp) {
    return (Widget)_shortCutsTable.get(inp);
  }
 
 
  private static InputChar __upChar = new InputChar(InputChar.KEY_UP);
  private static InputChar __downChar = new InputChar(InputChar.KEY_DOWN);
  private static InputChar __leftChar = new InputChar(InputChar.KEY_LEFT);
  private static InputChar __rightChar = new InputChar(InputChar.KEY_RIGHT);
 
  /**
  *  The method tries to close the window, after the user has typed 'escape'
    * or an other closing character. The procedure is as following:
    * If the window has listeners, than an event is sent to the listeners. The window
    * can be closed bei listeners. Did'nt listeners close the window, in leaves open.
    * Has the window no listeners, than the method closes it.
    *
  */
 
  public boolean tryToClose() {
    if (_listenerManager.countListeners() > 0) {
      _listenerManager.handleEvent(new WindowEvent(this, WindowEvent.CLOSING));
      return isClosed();
    } else {
      close();
      return true;
    }
  }
 
   
    /**
    *  @return true, if the window is already closed, false in othe case.
    */
 
  public boolean isClosed() {
    return _closed;
  }
 
 
    /**
    *  The method is called by the libray to handle an input character, if the window has the focus.
    */
  protected void handleInput(InputChar inp) {
    if (inp.equals(getClosingChar())) {
      tryToClose();
    else if (inp.equals(getFocusChangeChar())) {
       changeFocus();
    else if (inp.equals(__upChar)) {
       Widget cur = getCurrentWidget();
       if (cur != null) {
           boolean result = cur.handleInput(inp);
        if (!result) {
         changeFocus(2)
       
       }
    }  else if (inp.equals(__downChar)) {
       Widget cur = getCurrentWidget();
       if (cur != null) {
           boolean result = cur.handleInput(inp);
        if (!result) {
         changeFocus(3)
       
       }
    }  else if (inp.equals(__leftChar)) {
       Widget cur = getCurrentWidget();
       if (cur != null) {
           boolean result = cur.handleInput(inp);
        if (!result) {
         changeFocus(0)
       
       }
    }  else if (inp.equals(__rightChar)) {
       Widget cur = getCurrentWidget();
       if (cur != null) {
           boolean result = cur.handleInput(inp);
        if (!result) {
         changeFocus(1)
       
       }
    } else if (isShortCut(inp)) {
      Widget cur = getCurrentWidget();
      if  (cur!=null) {
        boolean result = cur.handleInput(inp);
        if (!result) {
          getWidgetByShortCut(inp).handleInput(inp)
        }
      }
    }  else {
      if (!handleInputByCurrentChild(inp)) {
        onChar(inp);
      }
    }
  }
 
 
  /**
  * The method is called by <code>handleInput</code>, if no widget has handled
    * the input. Derived classes can override the method to define additional shortcuts.
  */
 
  protected void onChar(InputChar inp) {
    //default nothing
  }
 
 
  private void changeFocus() {
    if (_currentIndex != -1) {
      int newIndex = (_currentIndex == (_focusableChilds.size()-1))?0:(_currentIndex+1);
      if (newIndex!=_currentIndex) {
        (_focusableChilds.get(_currentIndex)).setFocus(false);
        (_focusableChilds.get(newIndex)).setFocus(true);
        _currentIndex = newIndex;
      }
    }
  }
 
 
  private void changeFocus(int direction) {
    if (_currentIndex != -1) {
      changeFocus(getNextWidget(direction));
    }
  }
 
 
 
  private Widget getNextWidget(int direction) {
    Widget result = getCurrentWidget();
    Widget current = getCurrentWidget();
//    int x = result.getAbsoluteX();
//    int y = result.getAbsoluteY();
    int searchDirection = ((direction == 0) || (direction == 2))?-1:1;
   
    List<Widget> widgets = _focusableChilds;
    int index = widgets.indexOf(result);
    if (index < 0) {
      throw new RuntimeException("widget in the sorted queue not found!!");
    }
   
    int distance = Integer.MAX_VALUE;
    while (index < widgets.size() && index > -1)  {
      index+=searchDirection;
      if (index < widgets.size() && index > -1) {
        Widget candidate = (Widget)widgets.get(index);
        if (((direction == 0) && WindowWidgetComparator.toTheLeftOf(candidate, current)) ||
          ((direction == 1) && WindowWidgetComparator.toTheRightOf(candidate, current)) ||
          ((direction == 2) && WindowWidgetComparator.atTheTopOf(candidate, current)) ||
          ((direction == 3) && WindowWidgetComparator.atTheBottomOf(candidate, current))) {
          int newDistance = WindowWidgetComparator.getDistance(candidate, current);
          if (newDistance < distance) {
            distance = newDistance;
            result = candidate;
          }
        }
      }
       
    }
   
    return result;
   
  }
 
 
 
 
  void changeFocus(Widget widget) {
    int newIndex = _focusableChilds.indexOf(widget);
    if (newIndex!=-1) {
      if (_currentIndex == -1) {
        widget.setFocus(true);
        _currentIndex = newIndex;
      } else if (_currentIndex == newIndex) {
      } else {
        widget.setFocus(true);
        _focusableChilds.get(_currentIndex).setFocus(false);
         _currentIndex = newIndex;
      }
       
    }
  }
 
 
  private Widget getCurrentWidget() {
    if (_currentIndex != -1) {
      return  _focusableChilds.get(_currentIndex);
    } else {
      return null;
    }
  }
 
  private boolean handleInputByCurrentChild(InputChar inp) {
    if (_currentIndex != -1) {
      return _focusableChilds.get(_currentIndex).handleInput(inp);
    }
   
    return false;
  }
 
 
 
  private void loadShortcuts() {
    _shortCutsList.clear();
    _shortCutsTable.clear();
   
    List<Widget> list = _root.getListOfWidgetsWithShortCuts();
    for (int i=0; i<list.size(); i++) {
      Widget widget = (Widget)list.get(i);
      List<InputChar> shortCuts = widget.getShortCutsList();
      _shortCutsList.addAll(shortCuts);
      for (int j=0; j< shortCuts.size(); j++) {
        _shortCutsTable.put(shortCuts.get(j), widget);
      }
    }
   
  }
 
  private void loadFocusableChilds() {
    _focusableChilds = _root.getListOfFocusables();
    if (_focusableChilds.size() == 0) {
      _currentIndex = -1;
    } else {
      Collections.sort(_focusableChilds, new WindowWidgetComparator());
      _currentIndex = 0;
      _focusableChilds.get(0).setFocus(true);
    }
  }
 
 
    /**
    *  The method computes new window's layout.
  *  The method must already be called, if anything on the window building
  *  is changed, for example, an widget is removed or isn't more focusable
  * ( because not visible or other ).
    */
  public void pack() {
    cutIfNeeded();
    configureRootPanel();
    _root.pack();
    loadFocusableChilds();
    loadShortcuts();
   
  }
 
 
  private void cutIfNeeded() {
    int maxWidth = Toolkit.getScreenWidth()-_rect.getX()-(_hasShadow?1:0);
    int maxHeight = Toolkit.getScreenHeight()-_rect.getY()-(_hasShadow?1:0);
   
     
    if (_rect.getWidth() > maxWidth) {
      _rect.setWidth(maxWidth);
    }
   
    if (_rect.getHeight() > maxHeight) {
      _rect.setHeight(maxHeight);
    }
   
 
   
  }
 
 
 
    /**
    *  @return the root panel of the window
    */
  public Panel getRootPanel() {
    //Ein kommentar
    return _root;
  }
 
   
    /**
    *  Sets the root panel of the window. This is the top most widget container in the
    *  window's widget hierarchy. It occupies the entire window out of the border (if exists ).
    */
 
  public void setRootPanel(Panel root) {
    _root = root; 
    _root.setWindow(this);
  }
 
 
  private void drawThingsIfNeeded() {
    if (_border) {
      Toolkit.drawBorder(_rect, getBorderColors());
    }
   
    paintTitle();
   
    if (hasShadow()) {
      Toolkit.drawRectangle(_rect.getX()+_rect.getWidth(),
                  _rect.getY()+1,
                  1,
                  _rect.getHeight(), getShadowColors());
      Toolkit.drawRectangle(_rect.getX()+1,
                  _rect.getY()+_rect.getHeight(),
                  _rect.getWidth(),
                  1, getShadowColors());
                   
    }
  }
 
 
  private void paintTitle() {
    if (_title!=null) {
      CharColor color = getTitleColors();
      Toolkit.printString( _title, _rect.getX()+(_rect.getWidth()-_title.length())/2,_rect.getY(), color);
    }
  }
 
 
 
  private static CharColor __defaultBorderColors = new CharColor(CharColor.WHITE, CharColor.BLACK);
  private CharColor _borderColors = getDefaultBorderColors();
 
  public CharColor getDefaultBorderColors() {
    return __defaultBorderColors;
  }
 
 
  public CharColor getBorderColors() {
    return _borderColors;
  }
 
 
  public void setBorderColors(CharColor colors) {
    _borderColors = colors;
  }
 
  /**
  *  Normaler title
  */
 
 
  private static CharColor __defaultTitleColors = new CharColor(CharColor.WHITE, CharColor.RED);
  private CharColor _titleColors = getDefaultTitleColors();
 
  public CharColor getDefaultTitleColors() {
    return __defaultTitleColors;
  }
 
 
  public CharColor getTitleColors() {
    return _titleColors;
  }
 
 
  public void setTitleColors(CharColor colors) {
    _titleColors = colors;
  }
 
  /**
  * The method defines, whether the window is to paint with a shadow
    *
    * @param value true if a shadow is to paint, false in othe case
  */
  public void setShadow(boolean value) {
    _hasShadow=value;
  }
 
 
  boolean hasShadow() {
    return _hasShadow;
  }
 
 
  private static CharColor __shadowColors = new CharColor(CharColor.BLACK, CharColor.BLACK);
 
  private CharColor getShadowColors() {
    return __shadowColors;
  }
 
 
  //Listener-Zeugs
 
  private WindowListenerManager _listenerManager = new WindowListenerManager();
 
  /**
  *  The method adds a listener to the window
    *
    * @param listener the listener to add
  */
  public void addListener(WindowListener listener) {
    _listenerManager.addListener(listener);
  }
 
 
    /**
  *  The method remove a listener from the window
    *
    * @param listener the listener to remove
  */
  public void removeListener(WindowListener listener) {
    _listenerManager.removeListener(listener);
  }
 
 
    /**
    *  The method is called, if the window gets focus.
    */
  protected void activate() {
    _listenerManager.handleEvent(new WindowEvent(this, WindowEvent.ACTIVATED));
  }
 
 
    /**
    *  The method is called, if the window loses focus.
    */
  protected void deactivate() {
    _listenerManager.handleEvent(new WindowEvent(this, WindowEvent.DEACTIVATED));
  }
 
  /**
    *  The method is called, if the window is closed.
    */
  protected void closed() {
    _closed = true;
    _listenerManager.handleEvent(new WindowEvent(this, WindowEvent.CLOSED));
  }
 
 
  
  protected void resize(int width, int height) {
    _rect.setWidth(width);
    _rect.setHeight(height);
  }
 
 
 
 
 
 
 
 
 
 
 

}


class WindowWidgetComparator implements Comparator<Widget> {
 
 
 
  // methods to compare widget positions
  static boolean toTheLeftOf(Widget widget1, Widget widget2) {
    Rectangle rect1 = widget1.getRectangle();
    Rectangle rect2 = widget2.getRectangle();
    boolean result = ((rect1.getX()+rect1.getWidth()-1) < rect2.getX());
    return result;
  }
 

  static boolean toTheRightOf(Widget widget1, Widget widget2) {
    Rectangle rect1 = widget1.getRectangle();
    Rectangle rect2 = widget2.getRectangle();
    boolean result = ((rect1.getX()) > (rect2.getX()+rect2.getWidth()-1));
    return  result;
  }
 
  static boolean atTheTopOf(Widget widget1, Widget widget2) {
    Rectangle rect1 = widget1.getRectangle();
    Rectangle rect2 = widget2.getRectangle();
    boolean result = ((rect1.getY()+rect1.getHeight()-1) < rect2.getY());
    return result;
  }
 
  static boolean atTheBottomOf(Widget widget1, Widget widget2) {
    Rectangle rect1 = widget1.getRectangle();
    Rectangle rect2 = widget2.getRectangle();
    boolean result = ((rect1.getY()) > (rect2.getY()+rect2.getHeight()-1));
    return  result;
  }
 
  static int getDistance(Widget widget1, Widget widget2) {
    Rectangle rect1 = widget1.getRectangle();
    Rectangle rect2 = widget2.getRectangle();
    int x1 = rect1.getX()+(rect1.getWidth()/2);
    int y1 = rect1.getY()+(rect1.getHeight()/2);
    int x2 = rect2.getX()+(rect2.getWidth()/2);
    int y2 = rect2.getY()+(rect2.getHeight()/2);
   
    return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1);
   
  }
 
 
  public int compare(Widget widget1, Widget widget2) {   
    int result = 0;
   
    if (atTheTopOf(widget1, widget2)) {
      result = -1;
    } else if  (atTheBottomOf(widget1, widget2)) {
      result = 1;
    } else {
      if (toTheLeftOf(widget1, widget2)) {
        result = -1;
      } else if (toTheRightOf(widget1, widget2)) {
        result = 1;
      } else {
        result = 0;
      }
    }
   
   
    return result;
   
  }
 
}
TOP

Related Classes of jcurses.widgets.WindowWidgetComparator

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.