/* * Copyright (c) 1998-2017 by Richard A. Wilkes. All rights reserved. * * This Source Code Form is subject to the terms of the Mozilla Public * License, version 2.0. If a copy of the MPL was not distributed with * this file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This Source Code Form is "Incompatible With Secondary Licenses", as * defined by the Mozilla Public License, version 2.0. */ package com.trollworks.gcs.page; import com.trollworks.gcs.app.GCSFonts; import com.trollworks.gcs.character.CharacterSheet; import com.trollworks.toolkit.ui.GraphicsUtilities; import com.trollworks.toolkit.ui.UIUtilities; import com.trollworks.toolkit.ui.border.EmptyBorder; import com.trollworks.toolkit.ui.border.TitledBorder; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.Rectangle; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import javax.swing.JPanel; import javax.swing.UIManager; import javax.swing.border.CompoundBorder; /** A standard panel with a drop shadow. */ public class DropPanel extends JPanel { private Map<Component, Color> mHorizontalBackgrounds = new HashMap<>(); private Map<Component, Color> mVerticalBackgrounds = new HashMap<>(); private boolean mPaintVerticalFirst; private TitledBorder mTitledBorder; private boolean mOnlyReportPreferredSize; /** * Creates a standard panel with a drop shadow. * * @param layout The layout to use. */ public DropPanel(LayoutManager layout) { this(layout, false); } /** * Creates a standard panel with a drop shadow. * * @param layout The layout to use. * @param onlyReportPreferredSize Whether or not minimum and maximum size is reported as * preferred size or not. */ public DropPanel(LayoutManager layout, boolean onlyReportPreferredSize) { this(layout, null, null, onlyReportPreferredSize); } /** * Creates a standard panel with a drop shadow. * * @param layout The layout to use. * @param title The title to use. */ public DropPanel(LayoutManager layout, String title) { this(layout, title, UIManager.getFont(GCSFonts.KEY_LABEL), false); } /** * Creates a standard panel with a drop shadow. * * @param layout The layout to use. * @param title The title to use. * @param onlyReportPreferredSize Whether or not minimum and maximum size is reported as * preferred size or not. */ public DropPanel(LayoutManager layout, String title, boolean onlyReportPreferredSize) { this(layout, title, UIManager.getFont(GCSFonts.KEY_LABEL), onlyReportPreferredSize); } /** * Creates a standard panel with a drop shadow. * * @param layout The layout to use. * @param title The title to use. * @param font The font to use for the title. * @param onlyReportPreferredSize Whether or not minimum and maximum size is reported as * preferred size or not. */ public DropPanel(LayoutManager layout, String title, Font font, boolean onlyReportPreferredSize) { super(layout); setOpaque(true); setBackground(Color.WHITE); mTitledBorder = new TitledBorder(font, title); setBorder(new CompoundBorder(mTitledBorder, new EmptyBorder(0, 2, 1, 2))); setAlignmentY(TOP_ALIGNMENT); mOnlyReportPreferredSize = onlyReportPreferredSize; } @Override public Dimension getMinimumSize() { return mOnlyReportPreferredSize ? getPreferredSize() : super.getMinimumSize(); } @Override public Dimension getMaximumSize() { return mOnlyReportPreferredSize ? getPreferredSize() : super.getMaximumSize(); } /** * Marks an area with a specific background color. The panel specified will be used to calculate * the area's top and bottom, and the background color will span the width of the drop panel. * * @param panel The panel to attach the color to. * @param background The color to attach. */ public void addHorizontalBackground(Component panel, Color background) { mHorizontalBackgrounds.put(panel, background); } /** * Removes a horizontal background added with {@link #addHorizontalBackground(Component,Color)}. * * @param panel The panel to remove. */ public void removeHorizontalBackground(Component panel) { mHorizontalBackgrounds.remove(panel); } /** * Marks an area with a specific background color. The panel specified will be used to calculate * the area's left and right, and the background color will span the height of the drop panel. * * @param panel The panel to attach the color to. * @param background The color to attach. */ public void addVerticalBackground(Component panel, Color background) { mVerticalBackgrounds.put(panel, background); } /** * Removes a vertical background added with {@link #addVerticalBackground(Component,Color)}. * * @param panel The panel to remove. */ public void removeVerticalBackground(Component panel) { mVerticalBackgrounds.remove(panel); } @Override protected void paintComponent(Graphics gc) { super.paintComponent(GraphicsUtilities.prepare(gc)); Insets insets = mTitledBorder.getBorderInsets(this); Rectangle localBounds = getBounds(); localBounds.x = insets.left; localBounds.y = insets.top; localBounds.width -= insets.left + insets.right; localBounds.height -= insets.top + insets.bottom; if (mPaintVerticalFirst) { paintVerticalBackgrounds(gc, localBounds); paintHorizontalBackgrounds(gc, localBounds); } else { paintHorizontalBackgrounds(gc, localBounds); paintVerticalBackgrounds(gc, localBounds); } } private void paintHorizontalBackgrounds(Graphics gc, Rectangle localBounds) { for (Entry<Component, Color> entry : mHorizontalBackgrounds.entrySet()) { Component panel = entry.getKey(); Rectangle bounds = panel.getBounds(); Container parent = panel.getParent(); if (parent != null) { if (parent != this) { UIUtilities.convertRectangle(bounds, parent, this); } gc.setColor(entry.getValue()); gc.fillRect(localBounds.x, bounds.y, localBounds.width, bounds.height); } } } private void paintVerticalBackgrounds(Graphics gc, Rectangle localBounds) { for (Entry<Component, Color> entry : mVerticalBackgrounds.entrySet()) { Component panel = entry.getKey(); Rectangle bounds = panel.getBounds(); Container parent = panel.getParent(); if (parent != null) { if (parent != this) { UIUtilities.convertRectangle(bounds, parent, this); } gc.setColor(entry.getValue()); gc.fillRect(bounds.x, localBounds.y, bounds.width, localBounds.height); } } } /** @return Whether or not to paint the vertical backgrounds first. */ public final boolean isPaintVerticalFirst() { return mPaintVerticalFirst; } /** @param first Whether or not to paint the vertical backgrounds first. */ public final void setPaintVerticalFirst(boolean first) { mPaintVerticalFirst = first; } /** @return The {@link TitledBorder}. */ public TitledBorder getTitledBorder() { return mTitledBorder; } /** * @param parent The parent to use. * @param sheet The {@link CharacterSheet} to use. * @param key The notification ID to use. * @param title The title to use. * @param tooltip The tooltip to use. * @param alignment The horizontal field alignment to use. * @return The newly created field. */ @SuppressWarnings("static-method") protected PageField createLabelAndField(Container parent, CharacterSheet sheet, String key, String title, String tooltip, int alignment) { PageField field = new PageField(sheet, key, alignment, true, tooltip); parent.add(new PageLabel(title, field)); parent.add(field); return field; } /** * @param parent The parent to use. * @param sheet The {@link CharacterSheet} to use. * @param key The notification ID to use. * @param title The title to use. * @param tooltip The tooltip to use. * @param alignment The horizontal field alignment to use. * @return The newly created field. */ @SuppressWarnings("static-method") protected PageField createLabelAndDisabledField(Container parent, CharacterSheet sheet, String key, String title, String tooltip, int alignment) { PageField field = new PageField(sheet, key, alignment, false, tooltip); parent.add(new PageLabel(title, field)); parent.add(field); return field; } /** * @param parent The parent to use. * @param sheet The {@link CharacterSheet} to use. * @param key The notification ID to use. * @param tooltip The tooltip to use. * @param alignment The horizontal field alignment to use. * @return The newly created field. */ @SuppressWarnings("static-method") protected PageField createField(Container parent, CharacterSheet sheet, String key, String tooltip, int alignment) { PageField field = new PageField(sheet, key, alignment, true, tooltip); parent.add(field); return field; } /** * @param parent The parent to use. * @param sheet The {@link CharacterSheet} to use. * @param key The notification ID to use. * @param tooltip The tooltip to use. * @param alignment The horizontal field alignment to use. * @return The newly created field. */ @SuppressWarnings("static-method") protected PageField createDisabledField(Container parent, CharacterSheet sheet, String key, String tooltip, int alignment) { PageField field = new PageField(sheet, key, alignment, false, tooltip); parent.add(field); return field; } /** * @param parent The parent to use. * @param title The title to use. * @param tooltip The tooltip to use. * @return The newly created header. */ @SuppressWarnings("static-method") protected PageHeader createHeader(Container parent, String title, String tooltip) { PageHeader header = new PageHeader(title, tooltip); parent.add(header); return header; } }