@Override
  public void onAdded(WindowBasedTextGUI textGUI, Window window, List<Window> allWindows) {
    WindowDecorationRenderer decorationRenderer = getWindowDecorationRenderer(window);
    TerminalSize expectedDecoratedSize =
        decorationRenderer.getDecoratedSize(window, window.getPreferredSize());
    window.setDecoratedSize(expectedDecoratedSize);

    if (window.getHints().contains(Window.Hint.FIXED_POSITION)) {
      // Don't place the window, assume the position is already set
    } else if (allWindows.isEmpty()) {
      window.setPosition(TerminalPosition.OFFSET_1x1);
    } else if (window.getHints().contains(Window.Hint.CENTERED)) {
      int left = (lastKnownScreenSize.getColumns() - expectedDecoratedSize.getColumns()) / 2;
      int top = (lastKnownScreenSize.getRows() - expectedDecoratedSize.getRows()) / 2;
      window.setPosition(new TerminalPosition(left, top));
    } else {
      TerminalPosition nextPosition =
          allWindows.get(allWindows.size() - 1).getPosition().withRelative(2, 1);
      if (nextPosition.getColumn() + expectedDecoratedSize.getColumns()
              > lastKnownScreenSize.getColumns()
          || nextPosition.getRow() + expectedDecoratedSize.getRows()
              > lastKnownScreenSize.getRows()) {
        nextPosition = TerminalPosition.OFFSET_1x1;
      }
      window.setPosition(nextPosition);
    }

    // Finally, run through the usual calculations so the window manager's usual prepare method can
    // have it's say
    prepareWindow(lastKnownScreenSize, window);
  }
예제 #2
0
 @Override
 public void drawComponent(TextGUIGraphics graphics) {
   TerminalSize area = graphics.getSize();
   String absolutePath = directory.getAbsolutePath();
   if (area.getColumns() < absolutePath.length()) {
     absolutePath = absolutePath.substring(absolutePath.length() - area.getColumns());
     absolutePath = "..." + absolutePath.substring(Math.min(absolutePath.length(), 3));
   }
   setText(absolutePath);
   super.drawComponent(graphics);
 }
예제 #3
0
 @Override
 public TextGraphics newTextGraphics(TerminalPosition topLeftCorner, TerminalSize size)
     throws IllegalArgumentException {
   TerminalSize writableArea = getSize();
   if (topLeftCorner.getColumn() + size.getColumns() <= 0
       || topLeftCorner.getColumn() >= writableArea.getColumns()
       || topLeftCorner.getRow() + size.getRows() <= 0
       || topLeftCorner.getRow() >= writableArea.getRows()) {
     // The area selected is completely outside of this TextGraphics, so we can return a "null"
     // object that doesn't
     // do anything because it is impossible to change anything anyway
     return new NullTextGraphics(size);
   }
   return new SubTextGraphics(this, topLeftCorner, size);
 }
 private void buttonMoveCursorActionPerformed(
     java.awt.event.ActionEvent evt) { // GEN-FIRST:event_buttonMoveCursorActionPerformed
   TerminalSize terminalSize = scrollingSwingTerminal.getTerminalSize();
   Random random = new Random();
   scrollingSwingTerminal.setCursorPosition(
       random.nextInt(terminalSize.getColumns()), random.nextInt(terminalSize.getRows()));
   scrollingSwingTerminal.flush();
 } // GEN-LAST:event_buttonMoveCursorActionPerformed
예제 #5
0
 @Override
 public String toString() {
   StringBuilder sb = new StringBuilder(size.getRows() * (size.getColumns() + 1) + 50);
   sb.append('{')
       .append(size.getColumns())
       .append('x')
       .append(size.getRows())
       .append('}')
       .append('\n');
   for (TextCharacter[] line : buffer) {
     for (TextCharacter tc : line) {
       sb.append(tc.getCharacter());
     }
     sb.append('\n');
   }
   return sb.toString();
 }
예제 #6
0
 private int shrinkWidthToFitArea(TerminalSize area, int[] columnWidths) {
   int totalWidth = 0;
   for (int width : columnWidths) {
     totalWidth += width;
   }
   if (totalWidth > area.getColumns()) {
     int columnOffset = 0;
     do {
       if (columnWidths[columnOffset] > 0) {
         columnWidths[columnOffset]--;
         totalWidth--;
       }
       if (++columnOffset == numberOfColumns) {
         columnOffset = 0;
       }
     } while (totalWidth > area.getColumns());
   }
   return totalWidth;
 }
예제 #7
0
  @Override
  public TextGraphics drawImage(
      TerminalPosition topLeft,
      TextImage image,
      TerminalPosition sourceImageTopLeft,
      TerminalSize sourceImageSize) {

    // If the source image position is negative, offset the whole image
    if (sourceImageTopLeft.getColumn() < 0) {
      topLeft = topLeft.withRelativeColumn(-sourceImageTopLeft.getColumn());
      sourceImageSize = sourceImageSize.withRelativeColumns(sourceImageTopLeft.getColumn());
      sourceImageTopLeft = sourceImageTopLeft.withColumn(0);
    }
    if (sourceImageTopLeft.getRow() < 0) {
      topLeft = topLeft.withRelativeRow(-sourceImageTopLeft.getRow());
      sourceImageSize = sourceImageSize.withRelativeRows(sourceImageTopLeft.getRow());
      sourceImageTopLeft = sourceImageTopLeft.withRow(0);
    }

    // cropping specified image-subrectangle to the image itself:
    int fromRow = Math.max(sourceImageTopLeft.getRow(), 0);
    int untilRow =
        Math.min(
            sourceImageTopLeft.getRow() + sourceImageSize.getRows(), image.getSize().getRows());
    int fromColumn = Math.max(sourceImageTopLeft.getColumn(), 0);
    int untilColumn =
        Math.min(
            sourceImageTopLeft.getColumn() + sourceImageSize.getColumns(),
            image.getSize().getColumns());

    // difference between position in image and position on target:
    int diffRow = topLeft.getRow() - sourceImageTopLeft.getRow();
    int diffColumn = topLeft.getColumn() - sourceImageTopLeft.getColumn();

    // top/left-crop at target(TextGraphics) rectangle: (only matters, if topLeft has a negative
    // coordinate)
    fromRow = Math.max(fromRow, -diffRow);
    fromColumn = Math.max(fromColumn, -diffColumn);

    // bot/right-crop at target(TextGraphics) rectangle: (only matters, if topLeft has a negative
    // coordinate)
    untilRow = Math.min(untilRow, getSize().getRows() - diffRow);
    untilColumn = Math.min(untilColumn, getSize().getColumns() - diffColumn);

    if (fromRow >= untilRow || fromColumn >= untilColumn) {
      return this;
    }
    for (int row = fromRow; row < untilRow; row++) {
      for (int column = fromColumn; column < untilColumn; column++) {
        setCharacter(column + diffColumn, row + diffRow, image.getCharacterAt(column, row));
      }
    }
    return this;
  }
예제 #8
0
 private int grabExtraVerticalSpace(
     TerminalSize area, int[] rowHeights, Set<Integer> expandableRows, int totalHeight) {
   for (int rowIndex : expandableRows) {
     rowHeights[rowIndex]++;
     totalHeight++;
     if (area.getColumns() == totalHeight) {
       break;
     }
   }
   return totalHeight;
 }
예제 #9
0
 private int grabExtraHorizontalSpace(
     TerminalSize area, int[] columnWidths, Set<Integer> expandableColumns, int totalWidth) {
   for (int columnIndex : expandableColumns) {
     columnWidths[columnIndex]++;
     totalWidth++;
     if (area.getColumns() == totalWidth) {
       break;
     }
   }
   return totalWidth;
 }
예제 #10
0
 @Override
 public BasicTextImage resize(TerminalSize newSize, TextCharacter filler) {
   if (newSize == null || filler == null) {
     throw new IllegalArgumentException(
         "Cannot resize BasicTextImage with null " + (newSize == null ? "newSize" : "filler"));
   }
   if (newSize.getRows() == buffer.length
       && (buffer.length == 0 || newSize.getColumns() == buffer[0].length)) {
     return this;
   }
   return new BasicTextImage(newSize, buffer, filler);
 }
  /**
   * Called by {@link DefaultWindowManager} when iterating through all windows to decide their size
   * and position. If you override {@link DefaultWindowManager} to add your own logic to how windows
   * are placed on the screen, you can override this method and selectively choose which window to
   * interfere with. Note that the two key properties that are read by the GUI system after
   * preparing all windows are the position and decorated size. Your custom implementation should
   * set these two fields directly on the window. You can infer the decorated size from the content
   * size by using the window decoration renderer that is attached to the window manager.
   *
   * @param screenSize Size of the terminal that is available to draw on
   * @param window Window to prepare decorated size and position for
   */
  protected void prepareWindow(TerminalSize screenSize, Window window) {
    WindowDecorationRenderer decorationRenderer = getWindowDecorationRenderer(window);
    TerminalSize contentAreaSize;
    if (window.getHints().contains(Window.Hint.FIXED_SIZE)) {
      contentAreaSize = window.getSize();
    } else {
      contentAreaSize = window.getPreferredSize();
    }
    TerminalSize size = decorationRenderer.getDecoratedSize(window, contentAreaSize);
    TerminalPosition position = window.getPosition();

    if (window.getHints().contains(Window.Hint.FULL_SCREEN)) {
      position = TerminalPosition.TOP_LEFT_CORNER;
      size = screenSize;
    } else if (window.getHints().contains(Window.Hint.EXPANDED)) {
      position = TerminalPosition.OFFSET_1x1;
      size =
          screenSize.withRelative(
              -Math.min(4, screenSize.getColumns()), -Math.min(3, screenSize.getRows()));
      if (!size.equals(window.getDecoratedSize())) {
        window.invalidate();
      }
    } else if (window.getHints().contains(Window.Hint.FIT_TERMINAL_WINDOW)
        || window.getHints().contains(Window.Hint.CENTERED)) {
      // If the window is too big for the terminal, move it up towards 0x0 and if that's not enough
      // then shrink
      // it instead
      while (position.getRow() > 0 && position.getRow() + size.getRows() > screenSize.getRows()) {
        position = position.withRelativeRow(-1);
      }
      while (position.getColumn() > 0
          && position.getColumn() + size.getColumns() > screenSize.getColumns()) {
        position = position.withRelativeColumn(-1);
      }
      if (position.getRow() + size.getRows() > screenSize.getRows()) {
        size = size.withRows(screenSize.getRows() - position.getRow());
      }
      if (position.getColumn() + size.getColumns() > screenSize.getColumns()) {
        size = size.withColumns(screenSize.getColumns() - position.getColumn());
      }
      if (window.getHints().contains(Window.Hint.CENTERED)) {
        int left = (lastKnownScreenSize.getColumns() - size.getColumns()) / 2;
        int top = (lastKnownScreenSize.getRows() - size.getRows()) / 2;
        position = new TerminalPosition(left, top);
      }
    }

    window.setPosition(position);
    window.setDecoratedSize(size);
  }
예제 #12
0
  /**
   * Creates a new BasicTextImage by copying a region of a two-dimensional array of TextCharacter:s.
   * If the area to be copied to larger than the source array, a filler character is used.
   *
   * @param size Size to create the new BasicTextImage as (and size to copy from the array)
   * @param toCopy Array to copy initial data from
   * @param initialContent Filler character to use if the source array is smaller than the requested
   *     size
   */
  private BasicTextImage(
      TerminalSize size, TextCharacter[][] toCopy, TextCharacter initialContent) {
    if (size == null || toCopy == null || initialContent == null) {
      throw new IllegalArgumentException(
          "Cannot create BasicTextImage with null "
              + (size == null ? "size" : (toCopy == null ? "toCopy" : "filler")));
    }
    this.size = size;

    int rows = size.getRows();
    int columns = size.getColumns();
    buffer = new TextCharacter[rows][];
    for (int y = 0; y < rows; y++) {
      buffer[y] = new TextCharacter[columns];
      for (int x = 0; x < columns; x++) {
        if (y < toCopy.length && x < toCopy[y].length) {
          buffer[y][x] = toCopy[y][x];
        } else {
          buffer[y][x] = initialContent;
        }
      }
    }
  }
예제 #13
0
  @Override
  public void doLayout(TerminalSize area, List<Component> components) {
    // Sanity check, if the area is way too small, just return
    Component[][] table = buildTable(components);
    table = eliminateUnusedRowsAndColumns(table);

    if (area.equals(TerminalSize.ZERO)
        || table.length == 0
        || area.getColumns()
            <= leftMarginSize + rightMarginSize + ((table[0].length - 1) * horizontalSpacing)
        || area.getRows()
            <= bottomMarginSize + topMarginSize + ((table.length - 1) * verticalSpacing)) {
      return;
    }

    // Adjust area to the margins
    area = area.withRelative(-leftMarginSize - rightMarginSize, -topMarginSize - bottomMarginSize);

    Map<Component, TerminalSize> sizeMap = new IdentityHashMap<Component, TerminalSize>();
    Map<Component, TerminalPosition> positionMap =
        new IdentityHashMap<Component, TerminalPosition>();

    // Figure out each column first, this can be done independently of the row heights
    int[] columnWidths = getPreferredColumnWidths(table);

    // Take notes of which columns we can expand if the usable area is larger than what the
    // components want
    Set<Integer> expandableColumns = getExpandableColumns(table);

    // Next, start shrinking to make sure it fits the size of the area we are trying to lay out on.
    // Notice we subtract the horizontalSpacing to take the space between components into account
    TerminalSize areaWithoutHorizontalSpacing =
        area.withRelativeColumns(-horizontalSpacing * (table[0].length - 1));
    int totalWidth = shrinkWidthToFitArea(areaWithoutHorizontalSpacing, columnWidths);

    // Finally, if there is extra space, make the expandable columns larger
    while (areaWithoutHorizontalSpacing.getColumns() > totalWidth && !expandableColumns.isEmpty()) {
      totalWidth =
          grabExtraHorizontalSpace(
              areaWithoutHorizontalSpacing, columnWidths, expandableColumns, totalWidth);
    }

    // Now repeat for rows
    int[] rowHeights = getPreferredRowHeights(table);
    Set<Integer> expandableRows = getExpandableRows(table);
    TerminalSize areaWithoutVerticalSpacing =
        area.withRelativeRows(-verticalSpacing * (table.length - 1));
    int totalHeight = shrinkHeightToFitArea(areaWithoutVerticalSpacing, rowHeights);
    while (areaWithoutVerticalSpacing.getRows() > totalHeight && !expandableRows.isEmpty()) {
      totalHeight =
          grabExtraVerticalSpace(
              areaWithoutVerticalSpacing, rowHeights, expandableRows, totalHeight);
    }

    // Ok, all constraints are in place, we can start placing out components. To simplify, do it
    // horizontally first
    // and vertically after
    TerminalPosition tableCellTopLeft = TerminalPosition.TOP_LEFT_CORNER;
    for (int y = 0; y < table.length; y++) {
      tableCellTopLeft = tableCellTopLeft.withColumn(0);
      for (int x = 0; x < table[y].length; x++) {
        Component component = table[y][x];
        if (component != null && !positionMap.containsKey(component)) {
          GridLayoutData layoutData = getLayoutData(component);
          TerminalSize size = component.getPreferredSize();
          TerminalPosition position = tableCellTopLeft;

          int availableHorizontalSpace = 0;
          int availableVerticalSpace = 0;
          for (int i = 0; i < layoutData.horizontalSpan; i++) {
            availableHorizontalSpace += columnWidths[x + i] + (i > 0 ? horizontalSpacing : 0);
          }
          for (int i = 0; i < layoutData.verticalSpan; i++) {
            availableVerticalSpace += rowHeights[y + i] + (i > 0 ? verticalSpacing : 0);
          }

          // Make sure to obey the size restrictions
          size = size.withColumns(Math.min(size.getColumns(), availableHorizontalSpace));
          size = size.withRows(Math.min(size.getRows(), availableVerticalSpace));

          switch (layoutData.horizontalAlignment) {
            case CENTER:
              position =
                  position.withRelativeColumn((availableHorizontalSpace - size.getColumns()) / 2);
              break;
            case END:
              position = position.withRelativeColumn(availableHorizontalSpace - size.getColumns());
              break;
            case FILL:
              size = size.withColumns(availableHorizontalSpace);
              break;
            default:
              break;
          }
          switch (layoutData.verticalAlignment) {
            case CENTER:
              position = position.withRelativeRow((availableVerticalSpace - size.getRows()) / 2);
              break;
            case END:
              position = position.withRelativeRow(availableVerticalSpace - size.getRows());
              break;
            case FILL:
              size = size.withRows(availableVerticalSpace);
              break;
            default:
              break;
          }

          sizeMap.put(component, size);
          positionMap.put(component, position);
        }
        tableCellTopLeft = tableCellTopLeft.withRelativeColumn(columnWidths[x] + horizontalSpacing);
      }
      tableCellTopLeft = tableCellTopLeft.withRelativeRow(rowHeights[y] + verticalSpacing);
    }

    // Apply the margins here
    for (Component component : components) {
      component.setPosition(positionMap.get(component).withRelative(leftMarginSize, topMarginSize));
      component.setSize(sizeMap.get(component));
    }
    this.changed = false;
  }
예제 #14
0
 private TextCharacter[] newBlankLine() {
   TextCharacter[] line = new TextCharacter[size.getColumns()];
   Arrays.fill(line, TextCharacter.DEFAULT_CHARACTER);
   return line;
 }
예제 #15
0
  @Override
  public void doLayout(TerminalSize area, List<Component> components) {
    EnumMap<Location, Component> layout = makeLookupMap(components);
    int availableHorizontalSpace = area.getColumns();
    int availableVerticalSpace = area.getRows();

    // We'll need this later on
    int topComponentHeight = 0;
    int leftComponentWidth = 0;

    // First allocate the top
    if (layout.containsKey(Location.TOP)) {
      Component topComponent = layout.get(Location.TOP);
      topComponentHeight =
          Math.min(topComponent.getPreferredSize().getRows(), availableVerticalSpace);
      topComponent.setPosition(TerminalPosition.TOP_LEFT_CORNER);
      topComponent.setSize(new TerminalSize(availableHorizontalSpace, topComponentHeight));
      availableVerticalSpace -= topComponentHeight;
    }

    // Next allocate the bottom
    if (layout.containsKey(Location.BOTTOM)) {
      Component bottomComponent = layout.get(Location.BOTTOM);
      int bottomComponentHeight =
          Math.min(bottomComponent.getPreferredSize().getRows(), availableVerticalSpace);
      bottomComponent.setPosition(new TerminalPosition(0, area.getRows() - bottomComponentHeight));
      bottomComponent.setSize(new TerminalSize(availableHorizontalSpace, bottomComponentHeight));
      availableVerticalSpace -= bottomComponentHeight;
    }

    // Now divide the remaining space between LEFT, CENTER and RIGHT
    if (layout.containsKey(Location.LEFT)) {
      Component leftComponent = layout.get(Location.LEFT);
      leftComponentWidth =
          Math.min(leftComponent.getPreferredSize().getColumns(), availableHorizontalSpace);
      leftComponent.setPosition(new TerminalPosition(0, topComponentHeight));
      leftComponent.setSize(new TerminalSize(leftComponentWidth, availableVerticalSpace));
      availableHorizontalSpace -= leftComponentWidth;
    }
    if (layout.containsKey(Location.RIGHT)) {
      Component rightComponent = layout.get(Location.RIGHT);
      int rightComponentWidth =
          Math.min(rightComponent.getPreferredSize().getColumns(), availableHorizontalSpace);
      rightComponent.setPosition(
          new TerminalPosition(area.getColumns() - rightComponentWidth, topComponentHeight));
      rightComponent.setSize(new TerminalSize(rightComponentWidth, availableVerticalSpace));
      availableHorizontalSpace -= rightComponentWidth;
    }
    if (layout.containsKey(Location.CENTER)) {
      Component centerComponent = layout.get(Location.CENTER);
      centerComponent.setPosition(new TerminalPosition(leftComponentWidth, topComponentHeight));
      centerComponent.setSize(new TerminalSize(availableHorizontalSpace, availableVerticalSpace));
    }

    // Set the remaining components to 0x0
    for (Component component : components) {
      if (!layout.values().contains(component)) {
        component.setPosition(TerminalPosition.TOP_LEFT_CORNER);
        component.setSize(TerminalSize.ZERO);
      }
    }
  }
예제 #16
0
  public FileDialog(
      String title,
      String description,
      String actionLabel,
      TerminalSize dialogSize,
      boolean showHiddenFilesAndDirs,
      File selectedObject) {
    super(title);
    this.selectedFile = null;
    this.showHiddenFilesAndDirs = showHiddenFilesAndDirs;

    if (selectedObject == null || !selectedObject.exists()) {
      selectedObject = new File("").getAbsoluteFile();
    }
    selectedObject = selectedObject.getAbsoluteFile();

    Panel contentPane = new Panel();
    contentPane.setLayoutManager(new GridLayout(2));

    if (description != null) {
      new Label(description)
          .setLayoutData(
              GridLayout.createLayoutData(
                  GridLayout.Alignment.BEGINNING, GridLayout.Alignment.CENTER, false, false, 2, 1))
          .addTo(contentPane);
    }

    int unitWidth = dialogSize.getColumns() / 3;
    int unitHeight = dialogSize.getRows();

    new FileSystemLocationLabel()
        .setLayoutData(
            GridLayout.createLayoutData(
                GridLayout.Alignment.FILL, GridLayout.Alignment.CENTER, true, false, 2, 1))
        .addTo(contentPane);

    fileListBox = new ActionListBox(new TerminalSize(unitWidth * 2, unitHeight));
    fileListBox
        .withBorder(Borders.singleLine())
        .setLayoutData(
            GridLayout.createLayoutData(
                GridLayout.Alignment.BEGINNING, GridLayout.Alignment.CENTER, false, false))
        .addTo(contentPane);
    directoryListBox = new ActionListBox(new TerminalSize(unitWidth, unitHeight));
    directoryListBox.withBorder(Borders.singleLine()).addTo(contentPane);

    fileBox =
        new TextBox()
            .setLayoutData(
                GridLayout.createLayoutData(
                    GridLayout.Alignment.FILL, GridLayout.Alignment.CENTER, true, false, 2, 1))
            .addTo(contentPane);

    new Separator(Direction.HORIZONTAL)
        .setLayoutData(
            GridLayout.createLayoutData(
                GridLayout.Alignment.FILL, GridLayout.Alignment.CENTER, true, false, 2, 1))
        .addTo(contentPane);

    okButton = new Button(actionLabel, new OkHandler());
    Panels.grid(2, okButton, new Button("Cancel", new CancelHandler()))
        .setLayoutData(
            GridLayout.createLayoutData(
                GridLayout.Alignment.END, GridLayout.Alignment.CENTER, false, false, 2, 1))
        .addTo(contentPane);

    if (selectedObject.isFile()) {
      directory = selectedObject.getParentFile();
      fileBox.setText(selectedObject.getName());
    } else if (selectedObject.isDirectory()) {
      directory = selectedObject;
    }

    reloadViews(directory);
    setComponent(contentPane);
  }