package org.leumasjaffe.charsheet.view.skills; import javax.swing.JPanel; import org.leumasjaffe.charsheet.model.Ability; import org.leumasjaffe.charsheet.model.DDCharacter; import org.leumasjaffe.charsheet.model.DDCharacterClass; import org.leumasjaffe.charsheet.model.observable.IntValue; import org.leumasjaffe.charsheet.model.skill.DDSkill; import org.leumasjaffe.charsheet.util.AbilityHelper; import org.leumasjaffe.format.StringHelper; import org.leumasjaffe.observer.IndirectObservableListener; import org.leumasjaffe.observer.ObserverDispatch; import lombok.AccessLevel; import lombok.Value; import lombok.experimental.FieldDefaults; import java.awt.GridBagLayout; import javax.swing.JCheckBox; import java.awt.GridBagConstraints; import javax.swing.JLabel; import java.awt.Insets; import java.util.Optional; import java.util.function.IntFunction; import java.awt.Dimension; import javax.swing.JTextField; import java.awt.Color; import javax.swing.border.MatteBorder; import javax.swing.SwingConstants; import java.awt.Component; import javax.swing.Box; import javax.swing.JButton; import java.awt.Font; @FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true) class SkillLevelUpLine extends JPanel { /** * */ private static final long serialVersionUID = 1L; boolean isClassSkill; DDSkill skill; IntValue current; IndirectObservableListener totalListener; @Value private static final class TotalPacket { Optional ability; DDSkill skill; IntValue points; } public SkillLevelUpLine(final DDCharacter chara, final DDCharacterClass cclass, final DDSkill skill, IntValue pointsAvaliable) { isClassSkill = cclass.isClassSkill(skill.getName()); this.skill = skill; current = new IntValue(0); final int pointsPerRank = isClassSkill ? 1 : 2; final int maxPoints = (chara.getLevel() + 3) / pointsPerRank - skill.getRanks().value(); setBorder(new MatteBorder(0, 0, 1, 0, (Color) new Color(0, 0, 0))); setPreferredSize(new Dimension(475, 22)); GridBagLayout gridBagLayout = new GridBagLayout(); gridBagLayout.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; gridBagLayout.rowHeights = new int[]{0, 0}; gridBagLayout.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; gridBagLayout.rowWeights = new double[]{0.0, Double.MIN_VALUE}; setLayout(gridBagLayout); JCheckBox checkBoxIsClassSkill = new JCheckBox(""); checkBoxIsClassSkill.setToolTipText("Class Skill?"); checkBoxIsClassSkill.setSelected(cclass.isClassSkill(skill.getName())); checkBoxIsClassSkill.setEnabled(false); GridBagConstraints gbc_checkBoxIsClassSkill = new GridBagConstraints(); gbc_checkBoxIsClassSkill.insets = new Insets(1, 0, 0, 5); gbc_checkBoxIsClassSkill.gridx = 0; gbc_checkBoxIsClassSkill.gridy = 0; add(checkBoxIsClassSkill, gbc_checkBoxIsClassSkill); JLabel lblName = new JLabel(skill.getName()); lblName.setMaximumSize(new Dimension(150, 14)); lblName.setMinimumSize(new Dimension(150, 14)); lblName.setPreferredSize(new Dimension(150, 14)); GridBagConstraints gbc_lblName = new GridBagConstraints(); gbc_lblName.fill = GridBagConstraints.HORIZONTAL; gbc_lblName.insets = new Insets(1, 0, 0, 5); gbc_lblName.gridx = 1; gbc_lblName.gridy = 0; add(lblName, gbc_lblName); JLabel lblAbil = new JLabel(skill.getAbility()); lblAbil.setMaximumSize(new Dimension(30, 14)); lblAbil.setMinimumSize(new Dimension(30, 14)); lblAbil.setPreferredSize(new Dimension(30, 14)); GridBagConstraints gbc_lblAbil = new GridBagConstraints(); gbc_lblAbil.insets = new Insets(1, 0, 0, 5); gbc_lblAbil.anchor = GridBagConstraints.EAST; gbc_lblAbil.gridx = 2; gbc_lblAbil.gridy = 0; add(lblAbil, gbc_lblAbil); JTextField total = new JTextField(); total.setToolTipText("Skill Modifier"); total.setHorizontalAlignment(SwingConstants.CENTER); total.setEditable(false); total.setMinimumSize(new Dimension(30, 20)); total.setMaximumSize(new Dimension(30, 20)); total.setPreferredSize(new Dimension(30, 20)); GridBagConstraints gbc_total = new GridBagConstraints(); gbc_total.insets = new Insets(1, 0, 0, 5); gbc_total.fill = GridBagConstraints.HORIZONTAL; gbc_total.gridx = 3; gbc_total.gridy = 0; add(total, gbc_total); total.setColumns(10); JLabel label = new JLabel("="); GridBagConstraints gbc_label = new GridBagConstraints(); gbc_label.anchor = GridBagConstraints.EAST; gbc_label.insets = new Insets(1, 0, 0, 5); gbc_label.gridx = 4; gbc_label.gridy = 0; add(label, gbc_label); JTextField modifier = new JTextField(); modifier.setToolTipText("Ability Modifier"); modifier.setHorizontalAlignment(SwingConstants.CENTER); modifier.setEditable(false); modifier.setMinimumSize(new Dimension(30, 20)); modifier.setMaximumSize(new Dimension(30, 20)); modifier.setPreferredSize(new Dimension(30, 20)); GridBagConstraints gbc_modifier = new GridBagConstraints(); gbc_modifier.insets = new Insets(1, 0, 0, 5); gbc_modifier.fill = GridBagConstraints.HORIZONTAL; gbc_modifier.gridx = 5; gbc_modifier.gridy = 0; add(modifier, gbc_modifier); modifier.setColumns(10); JLabel label_1 = new JLabel("+"); GridBagConstraints gbc_label_1 = new GridBagConstraints(); gbc_label_1.anchor = GridBagConstraints.EAST; gbc_label_1.insets = new Insets(1, 0, 0, 5); gbc_label_1.gridx = 6; gbc_label_1.gridy = 0; add(label_1, gbc_label_1); JTextField ranks = new JTextField(StringHelper.toString(skill.getRanks())); ranks.setToolTipText("Ranks"); ranks.setHorizontalAlignment(SwingConstants.CENTER); ranks.setEditable(false); ranks.setMinimumSize(new Dimension(30, 20)); ranks.setMaximumSize(new Dimension(30, 20)); ranks.setPreferredSize(new Dimension(30, 20)); GridBagConstraints gbc_ranks = new GridBagConstraints(); gbc_ranks.insets = new Insets(1, 0, 0, 5); gbc_ranks.fill = GridBagConstraints.HORIZONTAL; gbc_ranks.gridx = 7; gbc_ranks.gridy = 0; add(ranks, gbc_ranks); ranks.setColumns(10); Component horizontalStrut = Box.createHorizontalStrut(20); GridBagConstraints gbc_horizontalStrut = new GridBagConstraints(); gbc_horizontalStrut.insets = new Insets(0, 0, 0, 5); gbc_horizontalStrut.gridx = 8; gbc_horizontalStrut.gridy = 0; add(horizontalStrut, gbc_horizontalStrut); JButton plus = new JButton("+"); plus.setMargin(new Insets(2, 2, 2, 2)); plus.setFont(new Font("Tahoma", Font.PLAIN, 8)); plus.setPreferredSize(new Dimension(30, 19)); plus.setMinimumSize(new Dimension(30, 19)); GridBagConstraints gbc_plus = new GridBagConstraints(); gbc_plus.insets = new Insets(0, 0, 1, 5); gbc_plus.gridx = 9; gbc_plus.gridy = 0; add(plus, gbc_plus); JButton minus = new JButton("-"); minus.setMargin(new Insets(2, 2, 2, 2)); minus.setFont(new Font("Tahoma", Font.PLAIN, 8)); minus.setMinimumSize(new Dimension(30, 19)); minus.setPreferredSize(new Dimension(30, 19)); GridBagConstraints gbc_minus = new GridBagConstraints(); gbc_minus.insets = new Insets(0, 0, 1, 5); gbc_minus.gridx = 10; gbc_minus.gridy = 0; add(minus, gbc_minus); JTextField points = new JTextField(); points.setMinimumSize(new Dimension(30, 20)); points.setText("0"); points.setEditable(false); GridBagConstraints gbc_points = new GridBagConstraints(); gbc_points.gridx = 11; gbc_points.gridy = 0; add(points, gbc_points); points.setColumns(10); IntFunction lambda = (value) -> { pointsAvaliable.value(pointsAvaliable.value() - (value * pointsPerRank)); current.value(current.value() + value); points.setText(Integer.toString(current.value())); ObserverDispatch.notifySubscribers(pointsAvaliable, this); ObserverDispatch.notifySubscribers(current, this); return null; }; plus.addActionListener((e) -> { if (pointsAvaliable.value() >= pointsPerRank && current.value() < maxPoints) { lambda.apply(1); } }); minus.addActionListener((e) -> { if (current.value() > 0) { lambda.apply(-1); } }); totalListener = new IndirectObservableListener<>(total, (c, p) -> { final int skillRanks = p.skill.getRanks().value(); final int mod = p.ability.map(v -> v.baseModifier()).orElse(0); c.setText(StringHelper.toString(skillRanks + mod + p.points.value())); }); final Optional ability = getAbility(chara, skill); ability.ifPresent(v -> modifier.setText(StringHelper.toString(v.baseModifier()))); totalListener.setObserved(new TotalPacket(ability, skill, current), current); } private Optional getAbility(final DDCharacter chara, final DDSkill skill) { if (skill.getAbility().isEmpty()) { return Optional.empty(); } else { return Optional.of(AbilityHelper.get(chara, skill)); } } void applyChange() { skill.spendPoints(current.value(), !isClassSkill); ObserverDispatch.notifySubscribers(skill.getRanks(), this); } @Override public void removeNotify() { super.removeNotify(); ObserverDispatch.unsubscribeAll(totalListener); } }