23 package com.realtime.crossfire.jxclient.skin.io;
154 import java.awt.Color;
155 import java.awt.Component;
156 import java.awt.Container;
157 import java.awt.Font;
158 import java.awt.Image;
159 import java.awt.image.BufferedImage;
160 import java.io.IOException;
161 import java.io.InputStream;
162 import java.io.InputStreamReader;
163 import java.io.LineNumberReader;
164 import java.nio.charset.StandardCharsets;
165 import java.util.ArrayList;
166 import java.util.Collection;
167 import java.util.Comparator;
168 import java.util.List;
169 import java.util.TreeSet;
170 import javax.swing.GroupLayout;
171 import javax.swing.GroupLayout.Group;
172 import javax.swing.GroupLayout.SequentialGroup;
173 import javax.swing.SwingConstants;
174 import org.jetbrains.annotations.NotNull;
175 import org.jetbrains.annotations.Nullable;
424 private final List<ActivatableGUIElement>
focusOrder =
new ArrayList<>();
445 final Comparable<String> n1 = o1.getName();
446 final String n2 = o2.getName();
447 return n1.compareTo(n2);
481 public JXCSkinLoader(@NotNull
final Model model, @NotNull
final InventoryView inventoryView, @NotNull
final FloorView floorView, @NotNull
final SpellsView spellView, @NotNull
final SpellSkillView spellSkillsView, @NotNull
final FacesManager facesManager, @NotNull
final MapUpdaterState mapUpdaterState, @NotNull
final KeyBindings defaultKeyBindings, @NotNull
final OptionManager optionManager,
final int defaultTileSize, @NotNull
final KeybindingsManager keybindingsManager, @NotNull
final QuestsView questView, @NotNull
final CommandHistoryFactory commandHistoryFactory, @NotNull
final KnowledgeView knowledgeView, @NotNull
final KnowledgeTypeView knowledgeTypeView,
final boolean avoidCopyArea, @NotNull
final GuiManager guiManager, @NotNull
final GuiFactory guiFactory, @NotNull
final PendingDirections pendingDirections, @NotNull
final String
soundsCredits,
final float fontScaleFactor) {
527 public JXCSkin load(@NotNull
final JXCSkinSource skinSource, @NotNull
final CrossfireServerConnection crossfireServerConnection, @NotNull
final GuiStateManager guiStateManager, @NotNull
final TooltipManager tooltipManager, @NotNull
final JXCWindowRenderer windowRenderer, @NotNull
final GUIElementListener elementListener, @NotNull
final MetaserverModel metaserverModel, @NotNull
final CharacterModel characterModel, @NotNull
final CommandQueue commandQueue, @NotNull
final Shortcuts shortcuts, @NotNull
final CommandExecutor commandExecutor, @NotNull
final CommandCallback commandCallback, @NotNull
final Macros macros, @NotNull
final SmoothFaces smoothFaces)
throws JXCSkinException {
531 final Image nextGroupFace;
534 }
catch (
final IOException ex) {
537 final Image prevGroupFace;
540 }
catch (
final IOException ex) {
568 load(skinSource,
"global", crossfireServerConnection, guiStateManager, tooltipManager, windowRenderer, elementListener, metaserverModel, characterModel, commandQueue,
null, shortcuts, commandExecutor, commandCallback, macros, nextGroupFace, prevGroupFace, smoothFaces);
575 load(skinSource, name, crossfireServerConnection, guiStateManager, tooltipManager, windowRenderer, elementListener, metaserverModel, characterModel, commandQueue, gui, shortcuts, commandExecutor, commandCallback, macros, nextGroupFace, prevGroupFace, smoothFaces);
587 if (skinToDetach !=
null) {
588 skinToDetach.detach();
589 windowRenderer.setTooltip(
null);
619 private void load(@NotNull
final JXCSkinSource skinSource, @NotNull
final String dialogName, @NotNull
final CrossfireServerConnection server, @NotNull
final GuiStateManager guiStateManager, @NotNull
final TooltipManager tooltipManager, @NotNull
final JXCWindowRenderer windowRenderer, @NotNull
final GUIElementListener elementListener, @NotNull
final MetaserverModel metaserverModel, @NotNull
final CharacterModel characterModel, @NotNull
final CommandQueue commandQueue, @Nullable
final Gui gui, @NotNull
final Shortcuts shortcuts, @NotNull
final CommandExecutor commandExecutor, @NotNull
final CommandCallback commandCallback, @NotNull
final Macros macros, @NotNull
final Image nextGroupFace, @NotNull
final Image prevGroupFace, @NotNull
final SmoothFaces smoothFaces)
throws JXCSkinException {
620 String resourceName = dialogName+
".skin";
625 InputStream inputStream;
627 inputStream = skinSource.getInputStream(resourceName);
628 }
catch (
final IOException ignored) {
629 resourceName = dialogName+
".skin";
630 inputStream = skinSource.getInputStream(resourceName);
633 load(skinSource, dialogName, resourceName, inputStream, server, guiStateManager, tooltipManager, windowRenderer, elementListener, metaserverModel, characterModel, commandQueue, gui, shortcuts, commandExecutor, commandCallback, macros, nextGroupFace, prevGroupFace, smoothFaces);
638 throw new JXCSkinException(skinSource.getURI(resourceName)+
": "+ex.getMessage(), ex);
671 private void load(@NotNull
final JXCSkinSource skinSource, @NotNull
final String dialogName, @NotNull
final String resourceName, @NotNull
final InputStream inputStream, @NotNull
final CrossfireServerConnection server, @NotNull
final GuiStateManager guiStateManager, @NotNull
final TooltipManager tooltipManager, @NotNull
final JXCWindowRenderer windowRenderer, @NotNull
final GUIElementListener elementListener, @NotNull
final MetaserverModel metaserverModel, @NotNull
final CharacterModel characterModel, @NotNull
final CommandQueue commandQueue, @Nullable
final Gui gui, @NotNull
final Shortcuts shortcuts, @NotNull
final CommandExecutor commandExecutor, @NotNull
final CommandCallback commandCallback, @NotNull
final Macros macros, @NotNull
final Image nextGroupFace, @NotNull
final Image prevGroupFace, @NotNull
final SmoothFaces smoothFaces)
throws JXCSkinException {
673 try (InputStreamReader isr =
new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
674 try (LineNumberReader lnr =
new LineNumberReader(isr)) {
676 boolean isDialog =
false;
678 final String line = lnr.readLine();
683 if (line.startsWith(
"#") || line.isEmpty()) {
687 final String[] argsTmp;
693 final Args args =
new Args(argsTmp);
694 final String cmd = args.
get();
695 if (gui !=
null && cmd.equals(
"button")) {
696 parseButton(args, tooltipManager, elementListener, lnr);
697 }
else if (gui !=
null && cmd.equals(
"selectable_button")) {
699 }
else if (gui !=
null && cmd.equals(
"checkbox")) {
701 }
else if (gui !=
null && cmd.equals(
"combobox")) {
703 }
else if (gui !=
null && cmd.equals(
"spinner")) {
705 }
else if (cmd.equals(
"commandlist")) {
706 parseCommandList(args, guiStateManager, lnr, commandExecutor, commandQueue, server, commandCallback, macros);
707 }
else if (cmd.equals(
"commandlist_add")) {
708 parseCommandListAdd(args, guiStateManager, lnr, commandExecutor, commandQueue, server, commandCallback, macros);
709 }
else if (gui !=
null && cmd.equals(
"command_text")) {
710 parseCommandText(args, commandCallback, tooltipManager, elementListener, commandExecutor, server);
711 }
else if (cmd.equals(
"def")) {
713 }
else if (gui !=
null && cmd.equals(
"dialog")) {
715 throw new JXCSkinException(
"'dialog' must not be used more than once per dialog");
717 parseDialog(args, tooltipManager, windowRenderer, elementListener, lnr, gui, dialogName);
719 }
else if (gui !=
null && cmd.equals(
"dialog_hide")) {
721 }
else if (gui !=
null && cmd.equals(
"dupgauge")) {
723 }
else if (cmd.equals(
"event")) {
725 }
else if (gui !=
null && cmd.equals(
"fill")) {
726 parseFill(args, tooltipManager, elementListener);
727 }
else if (cmd.equals(
"font")) {
729 }
else if (gui !=
null && cmd.equals(
"gauge")) {
730 parseGauge(args, tooltipManager, elementListener, lnr);
731 }
else if (gui !=
null && cmd.equals(
"ignore")) {
733 }
else if (gui !=
null && cmd.equals(
"inventory_list")) {
735 }
else if (gui !=
null && cmd.equals(
"floor_list")) {
736 parseList(args,
ListType.
GROUND, tooltipManager, elementListener, commandQueue, server, nextGroupFace, prevGroupFace);
737 }
else if (gui !=
null && cmd.equals(
"spells_list")) {
738 parseList(args,
ListType.
SPELL, tooltipManager, elementListener, commandQueue, server, nextGroupFace, prevGroupFace);
739 }
else if (gui !=
null && cmd.equals(
"spell_skills")) {
741 }
else if (gui !=
null && cmd.equals(
"quests_list")) {
742 parseList(args,
ListType.
QUEST, tooltipManager, elementListener, commandQueue, server, nextGroupFace, prevGroupFace);
743 }
else if (gui !=
null && cmd.equals(
"knowledge_types")) {
745 }
else if (gui !=
null && cmd.equals(
"knowledge_list")) {
747 }
else if (gui !=
null && cmd.equals(
"horizontal")) {
749 }
else if (gui !=
null && cmd.equals(
"item")) {
750 parseItem(args, tooltipManager, elementListener, commandQueue, commandExecutor, server, shortcuts, nextGroupFace, prevGroupFace);
751 }
else if (cmd.equals(
"key")) {
753 }
else if (gui !=
null && cmd.equals(
"label_html")) {
755 }
else if (gui !=
null && cmd.equals(
"label_multi")) {
757 }
else if (gui !=
null && cmd.equals(
"label_query")) {
759 }
else if (gui !=
null && cmd.equals(
"label_failure")) {
761 }
else if (gui !=
null && cmd.equals(
"label_message")) {
762 parseLabelMessage(args, tooltipManager, elementListener, server, windowRenderer);
763 }
else if (gui !=
null && cmd.equals(
"label_text")) {
765 }
else if (gui !=
null && cmd.equals(
"label_stat")) {
767 }
else if (gui !=
null && cmd.equals(
"label_stat2")) {
769 }
else if (gui !=
null && cmd.equals(
"label_newchar")) {
771 }
else if (gui !=
null && cmd.equals(
"label_sounds_credits")) {
773 }
else if (gui !=
null && cmd.equals(
"link_size")) {
775 }
else if (gui !=
null && cmd.equals(
"log_label")) {
777 }
else if (gui !=
null && cmd.equals(
"log_message")) {
779 }
else if (gui !=
null && cmd.equals(
"log_color")) {
781 }
else if (gui !=
null && cmd.equals(
"log_filter")) {
783 }
else if (gui !=
null && cmd.equals(
"minimap")) {
785 }
else if (gui !=
null && cmd.equals(
"map")) {
786 parseMap(args, tooltipManager, elementListener, server, smoothFaces);
787 }
else if (gui !=
null && cmd.equals(
"map_directions")) {
789 }
else if (gui !=
null && cmd.equals(
"meta_list")) {
790 parseMetaList(args, tooltipManager, elementListener, metaserverModel);
791 }
else if (gui !=
null && cmd.equals(
"picture")) {
792 parsePicture(args, tooltipManager, elementListener, lnr, gui,
false);
793 }
else if (gui !=
null && cmd.equals(
"picture_scaled")) {
794 parsePicture(args, tooltipManager, elementListener, lnr, gui,
true);
795 }
else if (gui !=
null && cmd.equals(
"picture_stat")) {
797 }
else if (gui !=
null && cmd.equals(
"query_text")) {
798 parseQueryText(args, server, commandCallback, tooltipManager, elementListener);
799 }
else if (gui !=
null && cmd.equals(
"set_forced_active")) {
801 }
else if (gui !=
null && cmd.equals(
"set_auto_size")) {
803 }
else if (gui !=
null && cmd.equals(
"set_default")) {
805 }
else if (gui !=
null && cmd.equals(
"set_invisible")) {
807 }
else if (gui !=
null && cmd.equals(
"set_modal")) {
809 }
else if (gui !=
null && cmd.equals(
"set_user_resizable")) {
811 }
else if (gui !=
null && cmd.equals(
"scrollbar")) {
813 }
else if (gui ==
null && cmd.equals(
"skin_name")) {
815 }
else if (gui !=
null && cmd.equals(
"text")) {
816 parseText(args, commandCallback, tooltipManager, elementListener);
817 }
else if (gui !=
null && cmd.equals(
"textbutton")) {
819 }
else if (gui !=
null && cmd.equals(
"textgauge")) {
821 }
else if (cmd.equals(
"tooltip")) {
823 }
else if (gui !=
null && cmd.equals(
"vertical")) {
825 }
else if (cmd.equals(
"character_list")) {
827 }
else if (cmd.equals(
"hide_input")) {
829 }
else if (gui !=
null && cmd.equals(
"focus")) {
832 throw new IOException(
"unknown keyword '"+cmd+
"'");
836 throw new IOException(
"excess arguments");
840 throw new IOException(ex.getMessage()+
" in line "+lnr.getLineNumber(), ex);
841 }
catch (
final IllegalArgumentException ex) {
842 final Object msg = ex.getMessage();
843 throw new IOException(
"invalid parameter"+(msg ==
null ?
"" :
" ("+msg+
")")+
" in line "+lnr.getLineNumber(), ex);
858 final Collection<GUIElement> unreferencedElements =
new TreeSet<>(
ELEMENT_COMPARATOR);
861 unreferencedElements.add(element);
865 if (!unreferencedElements.isEmpty()) {
866 throw new IOException(
"missing elements in focus block: "+unreferencedElements);
876 }
catch (
final IOException ex) {
877 throw new JXCSkinException(skinSource.getURI(resourceName)+
": "+ex.getMessage(), ex);
893 final String name = args.get();
898 @Nullable
final String label;
899 @Nullable
final Font font;
900 @Nullable
final Color color;
903 if (args.hasMore()) {
916 insertGuiElement(
new GUIButton(tooltipManager, elementListener, name, upImage, downImage, label, font, color, textX, textY, autoRepeat, commandList,
guiFactory,
newCharModel));
929 final String name = args.get();
949 throw new IOException(
"missing 'def checkbox' command");
952 final String name = args.get();
968 final String name = args.get();
969 final String type = args.get();
981 case "starting_maps":
990 throw new IOException(
"undefined 'combobox' type '"+type+
"'");
1004 final String name = args.get();
1023 final String commandListName = args.get();
1026 if (args.hasMore()) {
1028 addCommand(commandListName, args, element, args.get(), guiStateManager, commandExecutor, lnr, commandQueue, server, commandCallback, macros);
1046 final String name = args.get();
1048 addCommand(name, args, element, args.get(), guiStateManager, commandExecutor, lnr, commandQueue, server, commandCallback, macros);
1063 final String name = args.get();
1072 insertGuiElement(
new GUICommandText(commandCallback, commandHistory, tooltipManager, elementListener, name,
newCharModel, activeImage, inactiveImage, font, inactiveColor, activeColor, margin,
"", commandExecutor,
guiFactory, crossfireServerConnection));
1083 final String type = args.get();
1094 case "checkbox_option":
1095 final String optionName = args.get();
1104 final String frame = args.get();
1118 if (alpha < 0 || alpha > 1.0F) {
1119 throw new IOException(
"invalid alpha value: "+alpha);
1121 dialogFactory =
new DialogFactory(frameNW, frameN, frameNE, frameW, frameC, frameE, frameSW, frameS, frameSE, titleFont, titleColor, titleBackgroundColor, alpha,
guiFactory);
1147 defaultItemPainter =
new ItemPainter(cursedImage, damnedImage, magicImage, blessedImage, appliedImage, unidentifiedImage, selectorImage, lockedImage, unpaidImage, markedImage, cursedColor, damnedColor, magicColor, blessedColor, appliedColor, unidentifiedColor, selectorColor, lockedColor, unpaidColor, markedColor, font, nrofColor);
1152 final String up = args.get();
1153 final String down = args.get();
1170 throw new IOException(
"unknown type '"+type+
"'");
1188 throw new IOException(
"missing 'def dialog' command");
1196 final Iterable<AbstractGUIElement> elements =
dialogFactory.
newDialog(tooltipManager, windowRenderer, elementListener, title);
1200 gui.getComponent().setName(dialogName);
1201 gui.setDefaultPosition(defaultX, defaultY);
1203 gui.setSaveDialog();
1216 }
while (args.hasMore());
1229 final String name = args.get();
1240 final GUIDupGauge element =
new GUIDupGauge(tooltipManager, elementListener, name, positiveDivImage, positiveModImage, emptyImage, orientationDiv, orientationMod, tooltipPrefix.isEmpty() ?
null : tooltipPrefix, color, font, commandList,
guiFactory);
1254 final String type = args.get();
1291 final String subtype = args.get();
1304 throw new IOException(
"undefined event sub-type: "+subtype);
1309 throw new IOException(
"undefined event type: "+type);
1322 final String name = args.get();
1325 if (alpha < 0 || alpha > 1.0F) {
1326 throw new IOException(
"invalid alpha value: "+alpha);
1338 final String name = args.get();
1355 throw new IOException(
"missing 'def dialog' command");
1358 final String name = args.get();
1359 final Image positiveImage = args.get().equals(
"null") ? null :
imageParser.
getImage(args.getPrev());
1360 final Image positiveLowImage = args.get().equals(
"null") ? null :
imageParser.
getImage(args.getPrev());
1361 final Image negativeImage = args.get().equals(
"null") ? null :
imageParser.
getImage(args.getPrev());
1362 final Image emptyImage = args.get().equals(
"null") ? null :
imageParser.
getImage(args.getPrev());
1369 final GUIGauge element =
new GUIGauge(tooltipManager, elementListener, name, positiveImage, positiveLowImage, negativeImage, emptyImage, orientation, tooltipFormat.isEmpty() ?
null : tooltipFormat, alpha, commandList,
guiFactory,
model.
getStats());
1381 final String name = args.get();
1401 throw new IOException(
"cannot use '"+type+
"_list"+
"' without 'def item' command");
1404 final String name = args.get();
1414 element =
new GUIInventoryList(tooltipManager, elementListener, name, cellWidth, cellHeight,
inventoryView, selectedItem, commandQueue, itemPainter, server,
facesManager,
floorView,
guiFactory);
1418 element =
new GUIFloorList(tooltipManager, elementListener, name, cellWidth, cellHeight,
floorView, selectedItem, commandQueue, itemPainter, server,
facesManager,
model.
getItemSet(), nextGroupFace, prevGroupFace,
guiFactory);
1422 element =
new GUISpellList(tooltipManager, elementListener, name, cellWidth, cellHeight,
spellView, selectedItem,
model.
getSpellsManager(),
keybindingsManager, commandQueue, itemPainter,
facesManager,
guiFactory);
1426 element =
new GUIQuestList(tooltipManager, elementListener, name, cellWidth, cellHeight,
questView, selectedItem,
model.
getQuestsManager(), commandQueue, itemPainter,
facesManager,
guiFactory);
1431 element =
new GUISpellSkillList(tooltipManager, elementListener, name, cellWidth, cellHeight,
spellSkillsView, selectedItem,
model.
getSpellsManager(), itemPainter,
facesManager, defaultSkillIcon,
guiFactory);
1434 case KNOWLEDGE_TYPES:
1435 element =
new GUIKnowledgeTypeList(tooltipManager, elementListener, name, cellWidth, cellHeight,
knowledgeTypeView, selectedItem,
model.
getKnowledgeManager(), itemPainter,
facesManager,
guiFactory);
1438 case KNOWLEDGE_LIST:
1439 element =
new GUIKnowledgeList(tooltipManager, elementListener, name, cellWidth, cellHeight,
knowledgeView, selectedItem, itemPainter,
facesManager,
model.
getKnowledgeManager(), commandQueue,
guiFactory);
1443 throw new AssertionError(
"unhandled type "+type);
1458 final GroupLayout layout = (GroupLayout)gui.getLayout();
1459 final String begin = args.get();
1460 if (!begin.equals(
"begin")) {
1461 throw new IOException(
"syntax error: expecting 'begin'");
1463 final Collection<GUIElement> unreferencedElements =
new TreeSet<>(
ELEMENT_COMPARATOR);
1465 unreferencedElements.add(element);
1468 final Group content =
parseBegin(args, layout, lnr, unreferencedElements,
true);
1469 if (!unreferencedElements.isEmpty()) {
1470 throw new IOException(
"layout doesn't define elements "+unreferencedElements);
1472 layout.setHorizontalGroup(content);
1476 if (background ==
null) {
1477 throw new AssertionError(
"element 'dialog_background' is missing");
1479 final Group content =
parseBegin(args, layout, lnr, unreferencedElements,
true);
1483 final Group group2 = layout.createSequentialGroup();
1485 if (title ==
null) {
1487 if (close ==
null) {
1489 group2.addGroup(content);
1492 final Group group3 = layout.createSequentialGroup();
1493 group3.addGap(0, 10, Short.MAX_VALUE);
1494 group3.addComponent(close);
1495 final Group group4 = layout.createParallelGroup();
1496 group4.addGroup(group3);
1497 group4.addGroup(content);
1498 group2.addGroup(group4);
1501 if (close ==
null) {
1503 final Group group3 = layout.createSequentialGroup();
1504 group3.addGap(0, 10, Short.MAX_VALUE);
1505 group3.addComponent(help);
1506 final Group group4 = layout.createParallelGroup();
1507 group4.addGroup(group3);
1508 group4.addGroup(content);
1509 group2.addGroup(group4);
1512 final Group group3 = layout.createSequentialGroup();
1513 group3.addGap(0, 10, Short.MAX_VALUE);
1514 group3.addComponent(help);
1515 group3.addComponent(close);
1516 final Group group4 = layout.createParallelGroup();
1517 group4.addGroup(group3);
1518 group4.addGroup(content);
1519 group2.addGroup(group4);
1524 if (close ==
null) {
1526 final Group group3 = layout.createParallelGroup();
1527 group3.addComponent(title);
1528 group3.addGroup(content);
1529 group2.addGroup(group3);
1532 final Group group3 = layout.createSequentialGroup();
1533 group3.addComponent(title);
1534 group3.addComponent(close);
1535 final Group group4 = layout.createParallelGroup();
1536 group4.addGroup(group3);
1537 group4.addGroup(content);
1538 group2.addGroup(group4);
1541 if (close ==
null) {
1543 final Group group3 = layout.createSequentialGroup();
1544 group3.addComponent(title);
1545 group3.addComponent(help);
1546 final Group group4 = layout.createParallelGroup();
1547 group4.addGroup(group3);
1548 group4.addGroup(content);
1549 group2.addGroup(group4);
1552 final Group group3 = layout.createSequentialGroup();
1553 group3.addComponent(title);
1554 group3.addComponent(help);
1555 group3.addComponent(close);
1556 final Group group4 = layout.createParallelGroup();
1557 group4.addGroup(group3);
1558 group4.addGroup(content);
1559 group2.addGroup(group4);
1564 if (!unreferencedElements.isEmpty()) {
1565 throw new IOException(
"layout doesn't define elements "+unreferencedElements);
1568 final Group group1 = layout.createParallelGroup();
1569 group1.addGroup(group2);
1570 group1.addComponent(background);
1572 layout.setHorizontalGroup(group1);
1584 if (component ==
null) {
1588 return unreferencedElements.remove(component) ? component :
null;
1606 final String type = args.get();
1607 final String name = args.get();
1613 throw new IOException(
"cannot use 'item floor' without 'def item' command");
1617 element =
new GUIItemFloor(tooltipManager, elementListener, commandQueue, name, itemPainter, index, server,
floorView,
model.
getItemSet(),
facesManager, nextGroupFace, prevGroupFace, 0,
guiFactory);
1624 throw new IOException(
"cannot use 'item inventory' without 'def item' command");
1628 element =
new GUIItemInventory(tooltipManager, elementListener, commandQueue, name, itemPainter, index, server,
facesManager,
floorView,
inventoryView, 0,
guiFactory);
1639 element =
new GUIItemShortcut(tooltipManager, elementListener, name, activateColor, activateImage, immediateColor, immediateImage, shortcutSlot,
facesManager, commandExecutor, shortcuts, font,
guiFactory);
1645 throw new IOException(
"cannot use 'item spelllist' without 'def item' command");
1649 element =
new GUIItemSpell(tooltipManager, elementListener, commandQueue, name, itemPainter, index,
facesManager,
model.
getSpellsManager(),
spellView, 0,
guiFactory);
1653 throw new IOException(
"undefined item type: "+type);
1665 private void parseKey(@NotNull
final Args args, @Nullable
final Gui gui, @NotNull
final String line)
throws IOException {
1670 throw new IOException(
"invalid key binding: "+ex.getMessage(), ex);
1674 while (args.hasMore()) {
1689 final String name = args.get();
1706 final String name = args.get();
1723 final String name = args.get();
1740 final String name = args.get();
1756 final String name = args.get();
1772 final String name = args.get();
1776 insertGuiElement(
new GUIOneLineLabel(tooltipManager, elementListener, name,
null, font, color, color,
null,
Alignment.
LEFT, text,
guiFactory));
1788 final String name = args.get();
1795 insertGuiElement(
new GUILabelStats(tooltipManager, elementListener, name, textFont, textColor, textHighlightColor, backgroundColor, stat, alignment,
model.
getStats(),
guiFactory));
1807 final String name = args.get();
1819 insertGuiElement(
new GUILabelStats2(tooltipManager, elementListener, name, font, colorNormal, colorUpgradable, colorDepleted, colorBoosted, colorBoostedUpgradable,
null, statCurrent, statBase, statRace, statApplied, alignment,
model.
getStats(),
guiFactory));
1832 final String name = args.get();
1839 insertGuiElement(
new GUINewcharLabel(tooltipManager, elementListener, name, server, font, fontError, stat, type,
newCharModel, color, colorError,
guiFactory));
1851 final String name = args.get();
1865 final String type = args.get();
1866 final List<Component> elements =
new ArrayList<>();
1867 while (args.hasMore()) {
1870 if (elements.size() < 2) {
1871 throw new IOException(
"'link_size' needs at least two gui elements");
1873 final Component[] array = elements.toArray(
new Component[elements.size()]);
1874 final GroupLayout layout = (GroupLayout)gui.getLayout();
1877 layout.linkSize(SwingConstants.HORIZONTAL, array);
1881 layout.linkSize(SwingConstants.VERTICAL, array);
1885 layout.linkSize(SwingConstants.HORIZONTAL, array);
1886 layout.linkSize(SwingConstants.VERTICAL, array);
1890 throw new IOException(
"undefined type '"+type+
"'");
1903 final String name = args.get();
1904 final Image backgroundImage = args.get().equals(
"null") ? null :
imageParser.
getImage(args.getPrev());
1911 final Fonts fonts =
new Fonts(fontPrint, fontFixed, fontFixedBold, fontArcane);
1925 final String name = args.get();
1926 final Image backgroundImage = args.get().equals(
"null") ? null :
imageParser.
getImage(args.getPrev());
1933 final Fonts fonts =
new Fonts(fontPrint, fontFixed, fontFixedBold, fontArcane);
1944 final String name = args.get();
1949 throw new IOException(
"element '"+name+
"' is not of type 'log'");
1952 throw new IOException(
"invalid color index "+index);
1964 final String name = args.get();
1965 final String type = args.get();
1977 throw new IOException(
"type '"+type+
"' is invalid");
1984 throw new IOException(ex);
1986 }
while (args.hasMore());
1989 throw new IOException(
"element '"+name+
"' is not of type 'log'");
2003 final String name = args.get();
2007 if (facesProvider ==
null) {
2008 throw new IOException(
"cannot create faces with size 4");
2024 final String name = args.get();
2026 if (facesProvider ==
null) {
2027 throw new IOException(
"cannot create faces with size "+
defaultTileSize);
2042 final String name = args.get();
2044 if (facesProvider ==
null) {
2045 throw new IOException(
"cannot create faces with size "+
defaultTileSize);
2060 final String name = args.get();
2063 final Image image = args.get().equals(
"null") ? null :
imageParser.
getImage(args.getPrev());
2068 final String format = args.get();
2069 final String tooltip = args.get();
2070 insertGuiElement(
new GUIMetaElementList(tooltipManager, elementListener, name, cellWidth, cellHeight, metaserverModel, image, font, format, tooltip, text, label, connectCommandList,
guiFactory));
2085 final String name = args.get();
2088 if (alpha < 0 || alpha > 1.0F) {
2089 throw new IOException(
"invalid alpha value: "+alpha);
2092 final GUIPicture picture =
new GUIPicture(tooltipManager, elementListener, name, image, alpha, image.getWidth(), image.getHeight(),
guiFactory, text);
2094 if (name.equals(
"dialog_help")) {
2095 gui.setHelp(picture);
2109 final String name = args.get();
2111 final BufferedImage imageInactive = args.get().equals(
"null") ? null :
imageParser.
getImage(args.getPrev());
2112 final BufferedImage imageActive = args.get().equals(
"null") ? null :
imageParser.
getImage(args.getPrev());
2113 if (imageInactive ==
null && imageActive ==
null) {
2114 throw new IOException(
"picture is never visible");
2117 final int preferredWidth;
2118 final int preferredHeight;
2119 if (imageInactive ==
null) {
2120 preferredWidth = imageActive.getWidth();
2121 preferredHeight = imageActive.getHeight();
2122 }
else if (imageActive ==
null) {
2123 preferredWidth = imageInactive.getWidth();
2124 preferredHeight = imageInactive.getHeight();
2126 preferredWidth = imageInactive.getWidth();
2127 preferredHeight = imageInactive.getHeight();
2128 if (preferredWidth != imageActive.getWidth() || preferredHeight != imageActive.getHeight()) {
2129 throw new IOException(
"pictures do not have the same size");
2132 insertGuiElement(
new GUIPictureStat(tooltipManager, elementListener, name, stat, imageInactive, imageActive, preferredWidth, preferredHeight,
model.
getStats(),
guiFactory, text));
2146 final String name = args.get();
2155 insertGuiElement(
new GUIQueryText(server, commandHistory, commandCallback, tooltipManager, elementListener, name,
newCharModel, activeImage, inactiveImage, font, inactiveColor, activeColor, margin,
"",
guiFactory));
2168 throw new IOException(
"argument to set_forced_active must be an activatable gui element");
2184 gui.setAutoSize(
new Extent(x, y, w, h));
2218 throw new JXCSkinException(
"can't use hide_input on a non text field "+args.getPrev());
2232 throw new IOException(
"focus must not be used more than once");
2235 final String begin = args.get();
2236 if (!begin.equals(
"begin")) {
2237 throw new IOException(
"syntax error: expecting 'begin'");
2242 final String line = lnr.readLine();
2244 throw new IOException(
"unterminated 'begin' block");
2247 if (line.startsWith(
"#") || line.isEmpty()) {
2251 final String[] argsTmp;
2257 final Args args2 =
new Args(argsTmp);
2258 final String cmd = args2.
get();
2259 if (cmd.equals(
"end")) {
2261 throw new IOException(
"excess arguments");
2270 throw new JXCSkinException(
"can't use hide_input on a non text field "+cmd);
2274 throw new IOException(
"excess arguments");
2278 throw new IOException(
"not an activatable element: "+element);
2281 throw new IOException(
"duplicate element: "+element);
2285 if (tmp.isEmpty()) {
2286 throw new IOException(
"focus block must not be empty");
2303 gui.setUserResizable(
true);
2315 final String name = args.get();
2321 throw new IOException(
"'"+element+
"' is not a scrollable element");
2332 final String newSkinName = args.get();
2335 if (!newSkinName.matches(
"[-a-z_0-9]+")) {
2336 throw new IOException(
"invalid skin_name: "+newSkinName);
2339 throw new IOException(
"minimum resolution ("+minResolution+
") must not exceed maximum resolution ("+maxResolution+
")");
2355 final String name = args.get();
2365 insertGuiElement(
new GUITextField(commandCallback, commandHistory, tooltipManager, elementListener, name,
newCharModel, activeImage, inactiveImage, font, inactiveColor, activeColor, margin,
"", commandList,
guiFactory));
2379 throw new IOException(
"missing 'def textbutton' command");
2382 final String name = args.get();
2401 throw new IOException(
"missing 'def dialog' command");
2404 final String name = args.get();
2417 final GUITextGauge element =
new GUITextGauge(tooltipManager, elementListener, name, positiveImage, positiveLowImage, negativeImage, emptyImage, orientation, tooltipFormat.isEmpty() ?
null : tooltipFormat, color, font, alpha, commandList,
guiFactory,
model.
getStats());
2446 private void parseVertical(@NotNull
final Args args, @NotNull
final Container gui, @NotNull
final LineNumberReader lnr,
final boolean isDialog)
throws IOException,
JXCSkinException {
2447 final GroupLayout layout = (GroupLayout)gui.getLayout();
2448 final String begin = args.get();
2449 if (!begin.equals(
"begin")) {
2450 throw new IOException(
"syntax error: expecting 'begin'");
2452 final Collection<GUIElement> unreferencedElements =
new TreeSet<>(
ELEMENT_COMPARATOR);
2454 unreferencedElements.add(element);
2457 final Group content =
parseBegin(args, layout, lnr, unreferencedElements,
true);
2458 if (!unreferencedElements.isEmpty()) {
2459 throw new IOException(
"layout doesn't define elements "+unreferencedElements);
2461 layout.setVerticalGroup(content);
2465 if (background ==
null) {
2466 throw new AssertionError(
"element 'dialog_background' is missing");
2468 final Group content =
parseBegin(args, layout, lnr, unreferencedElements,
true);
2472 final Group group2 = layout.createSequentialGroup();
2474 if (title ==
null) {
2476 if (close ==
null) {
2478 group2.addGroup(content);
2481 final Group group3 = layout.createParallelGroup();
2482 group3.addComponent(close);
2483 group3.addGroup(content);
2484 group2.addGroup(group3);
2487 if (close ==
null) {
2489 final Group group3 = layout.createParallelGroup();
2490 group3.addComponent(help);
2491 group3.addGroup(content);
2492 group2.addGroup(group3);
2495 final Group group3 = layout.createParallelGroup();
2496 group3.addComponent(help);
2497 group3.addComponent(close);
2498 group3.addGroup(content);
2499 group2.addGroup(group3);
2505 if (close ==
null) {
2507 group2.addComponent(title);
2508 group2.addGroup(content);
2511 final Group group3 = layout.createParallelGroup();
2512 group3.addComponent(title);
2513 group3.addComponent(close);
2514 group2.addGroup(group3);
2515 group2.addGroup(content);
2519 if (close ==
null) {
2521 final Group group3 = layout.createParallelGroup();
2522 group3.addComponent(title);
2523 group3.addComponent(help);
2524 group2.addGroup(group3);
2525 group2.addGroup(content);
2528 final Group group3 = layout.createParallelGroup();
2529 group3.addComponent(title);
2530 group3.addComponent(help);
2531 group3.addComponent(close);
2532 group2.addGroup(group3);
2533 group2.addGroup(content);
2538 if (!unreferencedElements.isEmpty()) {
2539 throw new IOException(
"layout doesn't define elements "+unreferencedElements);
2542 final Group group1 = layout.createParallelGroup();
2543 group1.addGroup(group2);
2544 group1.addComponent(background);
2546 layout.setVerticalGroup(group1);
2558 if (resolution ==
null) {
2559 throw new IOException(
"invalid resolution: "+text);
2574 final String name = args.get();
2607 private void addCommand(@NotNull
final String listName, @NotNull
final Args args, @Nullable
final AbstractGUIElement element, @NotNull
final String command, @NotNull
final GuiStateManager guiStateManager, @NotNull
final CommandExecutor commandExecutor, @NotNull
final LineNumberReader lnr, @NotNull
final CommandQueue commandQueue, @NotNull
final CrossfireServerConnection crossfireServerConnection, @NotNull
final CommandCallback commandCallback, @NotNull
final Macros macros)
throws IOException,
JXCSkinException {
2609 commandList.
add(
commandParser.
parseCommandArgs(args, element, command, guiStateManager, commandExecutor, lnr, commandQueue, crossfireServerConnection, commandCallback, macros));
2637 private Group
parseBegin(@NotNull
final Args beginArgs, @NotNull
final GroupLayout layout, @NotNull
final LineNumberReader lnr, @NotNull
final Collection<GUIElement> unreferencedElements,
final boolean topLevel)
throws IOException,
JXCSkinException {
2638 final String type = beginArgs.get();
2642 group = layout.createSequentialGroup();
2646 group = layout.createParallelGroup();
2650 throw new IOException(
"undefined type '"+type+
"'");
2655 final String line = lnr.readLine();
2657 throw new IOException(
"unterminated 'begin' block");
2660 if (line.startsWith(
"#") || line.isEmpty()) {
2664 final String[] argsTmp;
2670 final Args args =
new Args(argsTmp);
2671 final String cmd = args.
get();
2672 if (cmd.equals(
"end")) {
2674 throw new IOException(
"excess arguments");
2681 group.addGroup(
parseBegin(args, layout, lnr, unreferencedElements,
false));
2685 if (!(group instanceof SequentialGroup)) {
2686 throw new IOException(
"'border_gap' cannot be used outside 'seq' groups");
2688 ((SequentialGroup)group).addContainerGap();
2697 group.addGap(tmp, size, max);
2702 group.addGap(0, 1, Short.MAX_VALUE);
2708 if (!unreferencedElements.remove(element)) {
2709 throw new IOException(
"layout defines element '"+element+
"' more than once");
2725 group.addComponent(element, min, pref, max);
2727 group.addComponent(element);
2732 throw new IOException(
"excess arguments");
2737 throw new IOException(
"begin...end block must have at least one element");
2741 throw new IOException(
"begin...end block must have at least two elements");
2753 private BufferedImage
scaleImage(@NotNull
final BufferedImage sourceImage) {
2754 final int height = (int)(sourceImage.getHeight()*
fontScaleFactor+0.5F);
2755 final Image scaled = sourceImage.getScaledInstance(-1, height, Image.SCALE_SMOOTH);
2756 final BufferedImage bufferedScaled =
new BufferedImage(scaled.getWidth(
null), scaled.getHeight(
null), BufferedImage.TYPE_INT_ARGB);
2757 bufferedScaled.getGraphics().drawImage(scaled, 0, 0,
null);
2758 return bufferedScaled;
2771 }
catch (
final IllegalArgumentException ex) {