Exemple #1
0
  @Override
  public TerminalSize getPreferredSize(List<Component> components) {
    TerminalSize preferredSize = TerminalSize.ZERO;
    if (components.isEmpty()) {
      return preferredSize.withRelative(
          leftMarginSize + rightMarginSize, topMarginSize + bottomMarginSize);
    }

    Component[][] table = buildTable(components);
    table = eliminateUnusedRowsAndColumns(table);

    // Figure out each column first, this can be done independently of the row heights
    int preferredWidth = 0;
    int preferredHeight = 0;
    for (int width : getPreferredColumnWidths(table)) {
      preferredWidth += width;
    }
    for (int height : getPreferredRowHeights(table)) {
      preferredHeight += height;
    }
    preferredSize = preferredSize.withRelative(preferredWidth, preferredHeight);
    preferredSize =
        preferredSize.withRelativeColumns(
            leftMarginSize + rightMarginSize + (table[0].length - 1) * horizontalSpacing);
    preferredSize =
        preferredSize.withRelativeRows(
            topMarginSize + bottomMarginSize + (table.length - 1) * verticalSpacing);
    return preferredSize;
  }
  @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;
  }
Exemple #3
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;
  }