// Copyright 2013-03-03 PlanBase Inc. & Glen Peterson
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.planbase.pdf.layoutmanager;
import java.awt.Color;
/**
The style of a cell including: horizontal alignment, padding, background color, and border style.
Immutable.
*/
public class CellStyle {
// /** Horizontal allignment options for cell contents */
// public enum HorizAlign { LEFT, CENTER, RIGHT; }
// public enum VertAlign { TOP, MIDDLE, BOTTOM; }
/** Horizontal and vertical alignment options for cell contents */
public enum Align {
TOP_LEFT {
@Override public Padding calcPadding(XyDim outer, XyDim inner) {
if (outer.lte(inner)) { return null; }
return Padding.of(0, outer.x() - inner.x(), outer.y() - inner.y(), 0);
}
@Override public float leftOffset(float outerWidth, float innerWidth) { return 0f; }
},
TOP_CENTER {
@Override public Padding calcPadding(XyDim outer, XyDim inner) {
if (outer.lte(inner)) { return null; }
float dx = (outer.x() - inner.x()) / 2;
return Padding.of(0, dx, outer.y() - inner.y(), dx);
}
@Override public float leftOffset(float outerWidth, float innerWidth) {
return (innerWidth >= outerWidth) ? 0f : (outerWidth - innerWidth) / 2;
}
},
TOP_RIGHT {
@Override public Padding calcPadding(XyDim outer, XyDim inner) {
if (outer.lte(inner)) { return null; }
return Padding.of(0, 0, outer.y() - inner.y(), outer.x() - inner.x());
}
@Override public float leftOffset(float outerWidth, float innerWidth) {
return (innerWidth >= outerWidth) ? 0f : (outerWidth - innerWidth);
}
},
MIDDLE_LEFT {
@Override public Padding calcPadding(XyDim outer, XyDim inner) {
if (outer.lte(inner)) { return null; }
float dy = (outer.y() - inner.y()) / 2;
return Padding.of(dy, outer.x() - inner.x(), dy, 0);
}
@Override public float leftOffset(float outerWidth, float innerWidth) { return 0f; }
},
MIDDLE_CENTER {
@Override public Padding calcPadding(XyDim outer, XyDim inner) {
if (outer.lte(inner)) { return null; }
float dx = (outer.x() - inner.x()) / 2;
float dy = (outer.y() - inner.y()) / 2;
return Padding.of(dy, dx, dy, dx);
}
@Override public float leftOffset(float outerWidth, float innerWidth) {
return (innerWidth >= outerWidth) ? 0f : (outerWidth - innerWidth) / 2;
}
},
MIDDLE_RIGHT {
@Override public Padding calcPadding(XyDim outer, XyDim inner) {
if (outer.lte(inner)) { return null; }
float dy = (outer.y() - inner.y()) / 2;
return Padding.of(dy, 0, dy, outer.x() - inner.x());
}
@Override public float leftOffset(float outerWidth, float innerWidth) {
return (innerWidth >= outerWidth) ? 0f : (outerWidth - innerWidth);
}
},
BOTTOM_LEFT {
@Override public Padding calcPadding(XyDim outer, XyDim inner) {
if (outer.lte(inner)) { return null; }
return Padding.of(outer.y() - inner.y(), outer.x() - inner.x(), 0, 0);
}
@Override public float leftOffset(float outerWidth, float innerWidth) { return 0f; }
},
BOTTOM_CENTER {
@Override public Padding calcPadding(XyDim outer, XyDim inner) {
// System.out.println("\t\t\tcalcPadding(o=" + outer + " i=" + inner + ")");
if (outer.lte(inner)) { return null; }
float dx = (outer.x() - inner.x()) / 2;
// System.out.println("\t\t\tcalcPadding() dx=" + dx);
// Like HTML it's top, right, bottom, left
// System.out.println("\t\t\tcalcPadding() outer.y() - inner.y()=" + (outer.y() - inner.y()));
return Padding.of(outer.y() - inner.y(), dx, 0, dx);
}
@Override public float leftOffset(float outerWidth, float innerWidth) {
return (innerWidth >= outerWidth) ? 0f : (outerWidth - innerWidth) / 2;
}
},
BOTTOM_RIGHT {
@Override public Padding calcPadding(XyDim outer, XyDim inner) {
if (outer.lte(inner)) { return null; }
return Padding.of(outer.y() - inner.y(), 0, 0, outer.x() - inner.x());
}
@Override public float leftOffset(float outerWidth, float innerWidth) {
return (innerWidth >= outerWidth) ? 0f : (outerWidth - innerWidth);
}
};
/*
Given outer dimensions (make sure to add padding as necessary), and inner dimensions,
calculates additional padding to apply.
*/
public abstract Padding calcPadding(XyDim outer, XyDim inner);
public abstract float leftOffset(float outerWidth, float innerWidth);
}
public static final Align DEFAULT_ALIGN = Align.TOP_LEFT;
public static final CellStyle DEFAULT = new CellStyle(DEFAULT_ALIGN, null, null, null);
private final Align align;
private final Padding padding;
private final Color bgColor;
private final BorderStyle borderStyle; // Only for cell-style
private CellStyle(Align a, Padding p, Color bg, BorderStyle b) {
align = a; padding = p; bgColor = bg; // I think it's OK if this is null.
borderStyle = b;
}
public static CellStyle of(Align a, Padding p, Color bg, BorderStyle b) {
return builder().align(a).padding(p).bgColor(bg).borderStyle(b).build();
}
public Align align() { return align; }
public Padding padding() { return padding; }
public Color bgColor() { return bgColor; }
public BorderStyle borderStyle() { return borderStyle; }
// NOTE: This lincluded the padding!
// public float calcLeftX(float x, float spareRoom) {
// return HorizAlign.LEFT == align ? x + padding.left() :
// HorizAlign.CENTER == align ? x + (spareRoom / 2) :
// HorizAlign.RIGHT == align ? x + spareRoom - padding.right() :
// x;
// }
public CellStyle align(Align a) { return new Builder(this).align(a).build(); }
public CellStyle padding(Padding p) { return new Builder(this).padding(p).build(); }
public CellStyle bgColor(Color c) { return new Builder(this).bgColor(c).build(); }
public CellStyle borderStyle(BorderStyle bs) {
return new Builder(this).borderStyle(bs).build();
}
public static Builder builder() { return new Builder(); }
/**
* A mutable Builder for immutable CellStyles.
*/
public static class Builder {
private Align align;
private Padding padding;
private Color bgColor;
private BorderStyle borderStyle; // Only for cell-style
private Builder() {}
private Builder(CellStyle cs) {
align = cs.align; padding = cs.padding; bgColor = cs.bgColor;
borderStyle = cs.borderStyle;
}
public CellStyle build() {
if (align == null) { align = DEFAULT_ALIGN; }
if (padding == null) { padding = Padding.DEFAULT_TEXT_PADDING; }
// if (borderStyle == null) { borderStyle = BorderStyle.NO_BORDERS; }
if ( (align == DEFAULT_ALIGN) &&
(padding == Padding.DEFAULT_TEXT_PADDING) &&
((bgColor == null) || bgColor.equals(Color.WHITE)) &&
((borderStyle == null) || (borderStyle == BorderStyle.NO_BORDERS)) ) {
return DEFAULT;
}
return new CellStyle(align, padding, bgColor, borderStyle);
}
public Builder align(Align a) { align = a; return this; }
// public Builder alignLeft() { align = HorizAlign.LEFT; return this; }
// public Builder alignCenter() { align = HorizAlign.CENTER; return this; }
// public Builder alignRight() { align = HorizAlign.RIGHT; return this; }
public Builder padding(Padding p) { padding = p; return this; }
public Builder bgColor(Color c) { bgColor = c; return this; }
public Builder borderStyle(BorderStyle bs) { borderStyle = bs; return this; }
}
@Override public String toString() {
StringBuilder sB = new StringBuilder("CellStyle(").append(align);
if (padding != null) { sB.append(" ").append(padding); }
if (bgColor != null) { sB.append(" ").append(Utils.toString(bgColor)); }
if (borderStyle != null) { sB.append(" ").append(borderStyle); }
return sB.append(")").toString();
}
}