配方库管理
GuiSearch 是玩家自己的配方库浏览器:按组浏览全部配方、重命名组、
导入导出、删除。配方本身的存在形式就是「一个标签」,所以这个界面看起来像
一个物品/配方清单。
基本信息
| 属性 | 值 |
|---|---|
| 实现类 | me.towdium.jecalculation.gui.guis.GuiSearch extends Gui |
| 核心映射 | IdentityHashMap<ILabel, Trio<Recipe, String, Integer>> recipes(按对象同一性索引) |
| 列表控件 | WLabelScroll labels = new WLabelScroll(7, 51, 8, 6, false) |
| 搜索控件 | WSearch search = new WSearch(26, 25, 61, labels) |
| 打开方式 | 合成计算器界面的按钮 → JecaGui.displayGui(new GuiSearch()) |
| 视图 | 6 列 × 8 行的标签网格 |
视图模型:下标 0 是「全部」
refreshGroups() 构造一个组切换器,第 0 项是本地化的「全部」:
ArrayList<String> groups = new ArrayList<>();
groups.add(Utilities.I18n.get("gui.search.all")); // ← 下标 0 = "All"
groups.addAll(Controller.getGroups());
group = new WSwitcher(7, 7, 162, groups).setListener(i -> refreshDisplay());
下标越界会被夹到最后一档(if (index >= groups.size()) index = groups.size() - 1;)。
generate() 按当前下标决定数据源:
| 下标 | 数据源 |
|---|---|
0(全部) |
Controller.recipeIterator() |
≥ 1 |
Controller.recipeIterator(group.getText()) |
列表条目是 Recipe.getRep()——即该配方的代表产物标签(取 output.get(0)):
ILabel id = i.one.getRep();
recipes.put(id, i);
identifiers.add(id);
⚠️
recipes用的是IdentityHashMap,即按引用相等而非equals索引。 由于getRep()返回的是output列表里的同一个对象引用,指向同一ILabel实例的条目会被覆盖——这在两条不同配方共享同一个output.get(0)引用时 会导致列表里出现重复标签但浮层只指得到最后一条。
「全部」视图与单组视图的按钮差异
refreshDisplay() 按下标切换按钮:
| 按钮 | 下标 0(全部) |
下标 ≥ 1(单组) |
|---|---|---|
| 导出 | exportN(BTN_EXPORT_N,search.export_all)→ Controller.export() |
export1(BTN_EXPORT_1,search.export_group)→ Controller.export(group.getText()) |
| 删除 | deleteN(BTN_DELETE_N,search.delete_all)→ 逐组遍历删除全部 |
delete1(BTN_DELETE_1,search.delete_group)→ 只删当前组 |
| 重命名 | 禁用(rename.setDisabled(group.getIndex() == 0)) |
可用 |
「全部」视图下的删除是不可撤销的批量操作,且没有二次确认:
deleteN = new WButtonIcon(130, 25, 20, 20, BTN_DELETE_N, "search.delete_all").setListener(i -> {
Controller.getGroups().forEach(Controller::removeGroup);
refreshGroups();
refreshDisplay();
});
两个导出按钮在没有配方时禁用:exportN.setDisabled(identifiers.size() == 0)。
重命名流程
点重命名进入 setRename(true):禁用组切换器,换成「输入框 + 确认 + 取消」三件套,
并移除图标/搜索/导入/导出/重命名按钮。setRename(false) 反向恢复并清空输入框。
输入框监听器控制确认按钮可用性:
yes.setDisabled(s.isEmpty() || Controller.getGroups().contains(s));
即空名或与已有组重名都不能确认。
确认后执行 Controller.renameGroup(group.getText(), text.getText()),
然后刷新组列表并把切换器文本设为新名。
onKeyPressed 里 KEY_ESCAPE 且焦点在输入框内时取消重命名并 return true
(阻止 ESC 关闭整个界面)。
单条配方的浮层操作
左键点击某个标签(非 ILabel.EMPTY)弹出 Overlay:
| 按钮 | 提示键 | 行为 |
|---|---|---|
| 编辑 | search.edit |
JecaGui.displayGui(true, true, new GuiRecipe(recipe.two, recipe.three)) —— 带着组名与下标打开编辑页 |
| 删除 | search.delete |
Controller.removeRecipe(recipe.two, recipe.three),关浮层并刷新 |
recipe.two 是组名、recipe.three 是组内下标——这是 GuiRecipe(String group, int index)
构造器的两个参数。
标签点击的忽略条件
labels.setLsnrLeftClick((i, v) -> {
ILabel l = i.get(v).getLabel();
if (l != ILabel.EMPTY) setOverlay(new Overlay(i.get(v)));
});
空标签(ILabel.EMPTY)点击不弹浮层。