package org.leumasjaffe.charsheet.view.magic; import javax.swing.JPanel; import javax.swing.JScrollPane; import java.awt.GridBagLayout; import java.util.function.BiConsumer; import javax.swing.JTabbedPane; import org.jdesktop.swingx.VerticalLayout; import org.leumasjaffe.charsheet.model.Ability; import org.leumasjaffe.charsheet.model.DDCharacter; import org.leumasjaffe.charsheet.model.DDCharacterClass; import org.leumasjaffe.charsheet.util.AbilityHelper; import org.leumasjaffe.function.QuadFunction; import org.leumasjaffe.observer.IndirectObservableListener; import org.leumasjaffe.observer.ObserverDispatch; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; import lombok.experimental.NonFinal; import java.awt.GridBagConstraints; @FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true) public class SpellPanel extends JPanel { /** * */ private static final long serialVersionUID = 1L; IndirectObservableListener listenerPerDay, listenerKnown; public SpellPanel(DDCharacter chara, final DDCharacterClass dclass) { GridBagLayout gridBagLayout = new GridBagLayout(); gridBagLayout.columnWidths = new int[]{0, 0}; gridBagLayout.rowHeights = new int[]{0, 0}; gridBagLayout.columnWeights = new double[]{1.0, Double.MIN_VALUE}; gridBagLayout.rowWeights = new double[]{1.0, Double.MIN_VALUE}; setLayout(gridBagLayout); JTabbedPane spellsPane = new JTabbedPane(JTabbedPane.TOP); GridBagConstraints gbc_spells = new GridBagConstraints(); gbc_spells.fill = GridBagConstraints.BOTH; gbc_spells.gridx = 0; gbc_spells.gridy = 0; add(spellsPane, gbc_spells); JScrollPane preparedPane = new JScrollPane(); spellsPane.addTab("Prepared", null, preparedPane, "Spells the character can use today"); JScrollPane knownPane = new JScrollPane(); spellsPane.addTab("Known", null, knownPane, "Spells the player knows for this class"); final Ability.Scores ability = AbilityHelper.get(chara, dclass); final JPanel prepared = new JPanel(new VerticalLayout()); preparedPane.setViewportView(prepared); final JPanel known = new JPanel(new VerticalLayout()); knownPane.setViewportView(known); listenerPerDay = new IndirectObservableListener<>(prepared, new AppendSpellLevelOperation(chara, ability, SpellLevelPerDayPanel::new)); listenerPerDay.setObserved(dclass, ability, dclass.getLevel(), dclass.getSpellBook().get()); listenerKnown = new IndirectObservableListener<>(known, new AppendSpellLevelOperation(chara, ability, SpellLevelPanel::new)); listenerKnown.setObserved(dclass, ability, dclass.getLevel(), dclass.getSpellBook().get()); } @RequiredArgsConstructor @FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true) private static final class AppendSpellLevelOperation implements BiConsumer { @NonFinal int previousHighestSpellLevel = 0; DDCharacter chara; Ability.Scores ability; QuadFunction function; @Override public void accept(final JPanel root, final DDCharacterClass dclass) { for (int i = previousHighestSpellLevel; i < dclass.getHighestSpellLevel(); ++i) { if (dclass.getSpellBook().get().numSpellsKnownAtLevel(i) == 0) break; root.add(function.apply(chara, dclass, i, ability)); } previousHighestSpellLevel = dclass.getHighestSpellLevel(); } } @Override public void removeNotify() { super.removeNotify(); ObserverDispatch.unsubscribeAll(listenerKnown); ObserverDispatch.unsubscribeAll(listenerPerDay); } }