面板内容区合并为一个滚动区:列表/Inspector 在上、日志块在下(不再用两个单元格,顺序不会再反)

This commit is contained in:
tianmo committed 2026-10-16 16:00:46 +08:00
1 parent 9e318f3361
commit 1333e3d89c
1 file changed
+41 -34
+41 -34
View File
@@ -41,6 +41,8 @@ public final class ObjectPanel {
String statusText;
Object nameField;
final java.util.Deque<String> log = new java.util.ArrayDeque<String>();
boolean rendering;
Runnable logPanelRefresh;
List<Object> objects = new ArrayList<Object>();
Object target;
}
@@ -106,21 +108,16 @@ public final class ObjectPanel {
Object cell = call(root, Obf.TABLE_ADD, new Class<?>[] {actorClass}, cellClass, state.nameField);
layoutCell(cell, Obf.CELL_LEFT);
call(root, Obf.TABLE_ROW, new Class<?>[0], cellClass);
// 中段:列表区 —— 唯一 expand+fill 的单元格,吃掉剩余的高度
// 唯一 expand+fill 的单元格:内容区(上面是列表/Inspector,最下面是日志块,同一个滚动区)
cell = call(root, Obf.TABLE_ADD, new Class<?>[] {actorClass}, cellClass, scroll);
layoutCell(cell, Obf.CELL_TOP, Obf.CELL_EXPAND, Obf.CELL_FILL);
// 下段:实时提示(多行、只靠左,不加 fill,保持自然高度贴在底部)
call(root, Obf.TABLE_ROW, new Class<?>[0], cellClass);
cell = call(root, Obf.TABLE_ADD, new Class<?>[] {actorClass}, cellClass,
logScroll == null ? state.status : logScroll);
layoutCell(cell, Obf.CELL_LEFT, Obf.CELL_FILL_X);
try {
// 固定高度 90px:下段永远占一块,消息多了在它自己里滚
call(cell, "L", new Class<?>[] {float.class}, cellClass, Float.valueOf(90f));
} catch (Throwable error) {
System.err.println("[panel] 提示区高度设置失败: " + error);
}
state.logPanelRefresh = new Runnable() {
@Override
public void run() {
refreshList(state);
}
};
wire(loader, refresh, new Runnable() {
@Override
public void run() {
@@ -191,6 +188,28 @@ public final class ObjectPanel {
return root;
}
/** 在内容表格末尾追加"日志块"(分隔行 + 最近几条消息)。 */
private static void appendLogRows(State state) {
try {
Class<?> cellClass = Class.forName(Obf.CELL, true, state.loader);
Class<?> actorClass = Class.forName(Obf.ACTOR, true, state.loader);
Object cell = call(state.listTable, Obf.TABLE_ADD, new Class<?>[] {actorClass},
cellClass, label(state.loader, state.skin, "---------- log ----------"));
layoutCell(cell, Obf.CELL_LEFT);
call(state.listTable, Obf.TABLE_ROW, new Class<?>[0], cellClass);
synchronized (state.log) {
for (String line : state.log) {
cell = call(state.listTable, Obf.TABLE_ADD, new Class<?>[] {actorClass},
cellClass, label(state.loader, state.skin, line));
layoutCell(cell, Obf.CELL_LEFT);
call(state.listTable, Obf.TABLE_ROW, new Class<?>[0], cellClass);
}
}
} catch (Throwable error) {
System.err.println("[panel] 日志块追加失败: " + error);
}
}
/** 状态文字:作为列表区的第一行显示(这样不再单独占根表格的一行,布局更稳)。 */
private static void statusRow(final State state, final String text) {
try {
@@ -212,6 +231,7 @@ public final class ObjectPanel {
@Override
public void run() {
List<Object> objects;
state.rendering = true;
try {
objects = SceneObjects.listAllNodes(state.loader);
} catch (Throwable error) {
@@ -222,9 +242,6 @@ public final class ObjectPanel {
try {
// Table.clearChildren()(载荷名 `SourceFile()V`):把列表里的行全清掉重建。
call(state.listTable, Obf.TABLE_CLEAR_CHILDREN, new Class<?>[0], void.class);
setStatus(state, objects.size() + " scene objects"
+ (state.target == null ? "" : "; target = " + SceneObjects.kind(state.target)
+ " " + SceneObjects.nameOf(state.target)));
Class<?> cellClass = Class.forName(Obf.CELL, true, state.loader);
Class<?> actorClass = Class.forName(Obf.ACTOR, true, state.loader);
for (int i = 0; i < objects.size() && i < 300; i++) {
@@ -246,6 +263,11 @@ public final class ObjectPanel {
setStatus(state, "List build failed: " + error);
return;
}
setStatus(state, objects.size() + " scene objects"
+ (state.target == null ? "" : "; target = " + SceneObjects.kind(state.target)
+ " " + SceneObjects.nameOf(state.target)));
state.rendering = false;
appendLogRows(state);
invalidateList(state);
}
});
@@ -389,6 +411,8 @@ public final class ObjectPanel {
layoutCell(cell, Obf.CELL_LEFT);
call(state.listTable, Obf.TABLE_ROW, new Class<?>[0], cellClass);
}
state.rendering = false;
appendLogRows(state);
invalidateList(state);
} catch (Throwable error) {
System.err.println("[panel] inspector 填充失败: " + error);
@@ -408,29 +432,12 @@ public final class ObjectPanel {
private static void setStatus(final State state, final String text) {
state.statusText = text;
System.err.println("[panel] " + text);
if (state.status == null) return;
synchronized (state.log) {
state.log.addLast(text);
while (state.log.size() > LOG_LINES) state.log.removeFirst();
}
final StringBuilder joined = new StringBuilder();
synchronized (state.log) {
for (String line : state.log) {
if (joined.length() > 0) joined.append('\n');
joined.append(line);
}
}
SceneActions.onEditorThread(state.loader, new Runnable() {
@Override
public void run() {
try {
call(state.status, Obf.LABEL_SET_TEXT, new Class<?>[] {CharSequence.class},
void.class, joined.toString());
} catch (Throwable error) {
System.err.println("[panel] 提示区更新失败: " + error);
}
}
});
// 没在渲染中就立刻把日志块刷出来(渲染中则由那次渲染带上,避免递归重排)
if (!state.rendering && state.logPanelRefresh != null) state.logPanelRefresh.run();
}
/** TextField 里的文字(名字被混淆了,按"无参 + 返回 String"取)。 */