面板恢复成上/中/下三段:上=按钮块(两列紧邻+名字输入框)、中=列表(expand+fill)、下=日志(独立 Label,自然高度贴底);去掉列表里内嵌的日志行与之前未验证的尺寸调用
This commit is contained in:
1 parent
4b05804479
commit
55c0794ed4
1 file changed
+75
-49
@@ -50,6 +50,7 @@ public final class ObjectPanel {
|
||||
List<Object> objects = new ArrayList<Object>();
|
||||
Object target;
|
||||
boolean scrollFocusLogged;
|
||||
boolean geometryDumped;
|
||||
Class<?> tableClass;
|
||||
Class<?> scrollClass;
|
||||
Class<?> actorClass;
|
||||
@@ -116,58 +117,29 @@ public final class ObjectPanel {
|
||||
|
||||
// 按钮直接放进根表格:两行按钮 + 一行滚动列表(与阶段四验证过的结构一致)
|
||||
Object[] top = {refresh, newBone, newSlot, newBBox, newPath, delete, rename, inspect, setValue};
|
||||
Object buttons = tableClass.getConstructor().newInstance();
|
||||
call(buttons, Obf.TABLE_TOP, new Class<?>[0], tableClass);
|
||||
for (int i = 0; i < top.length; i++) {
|
||||
Object cell = call(root, Obf.TABLE_ADD, new Class<?>[] {actorClass}, cellClass, top[i]);
|
||||
layoutCell(cell, Obf.CELL_LEFT);
|
||||
if (i % 2 == 1 || i == top.length - 1) {
|
||||
call(root, Obf.TABLE_ROW, new Class<?>[0], cellClass);
|
||||
}
|
||||
Object buttonCell = call(buttons, Obf.TABLE_ADD, new Class<?>[] {actorClass}, cellClass, top[i]);
|
||||
layoutCell(buttonCell, Obf.CELL_LEFT);
|
||||
if (i % 2 == 1) call(buttons, Obf.TABLE_ROW, new Class<?>[0], cellClass);
|
||||
}
|
||||
Object cell = call(root, Obf.TABLE_ADD, new Class<?>[] {actorClass}, cellClass, state.nameField);
|
||||
call(buttons, Obf.TABLE_ROW, new Class<?>[0], cellClass);
|
||||
Object nameCell = call(buttons, Obf.TABLE_ADD, new Class<?>[] {actorClass}, cellClass, state.nameField);
|
||||
layoutCell(nameCell, Obf.CELL_LEFT);
|
||||
// 上段:按钮块(自适应高度,紧贴顶部)
|
||||
Object cell = call(root, Obf.TABLE_ADD, new Class<?>[] {actorClass}, cellClass, buttons);
|
||||
layoutCell(cell, Obf.CELL_LEFT);
|
||||
call(root, Obf.TABLE_ROW, new Class<?>[0], cellClass);
|
||||
// 唯一 expand+fill 的单元格:内容区(上面是列表/Inspector,最下面是日志块,同一个滚动区)
|
||||
// 中段:列表(唯一 expand+fill 的行,吃掉剩余高度)
|
||||
cell = call(root, Obf.TABLE_ADD, new Class<?>[] {actorClass}, cellClass, scroll);
|
||||
layoutCell(cell, Obf.CELL_TOP, Obf.CELL_EXPAND, Obf.CELL_FILL);
|
||||
state.listCell = cell;
|
||||
try {
|
||||
// 给列表一个**固定高度**:这样 ScrollPane 必定比内容矮,可滚范围(maxY)一定 > 0。
|
||||
// Cell.height(float) 的载荷名是 `I`(描述符 (F)LdR;,MapMethods 指纹确认)。
|
||||
call(cell, "I", new Class<?>[] {float.class}, cellClass, Float.valueOf(360f));
|
||||
} catch (Throwable error) {
|
||||
System.err.println("[panel] 列表固定高度设置失败: " + error);
|
||||
}
|
||||
// 下段:日志(独立一行,自然高度贴底;不用任何未验证的尺寸方法)
|
||||
call(root, Obf.TABLE_ROW, new Class<?>[0], cellClass);
|
||||
cell = call(root, Obf.TABLE_ADD, new Class<?>[] {actorClass}, cellClass, state.status);
|
||||
layoutCell(cell, Obf.CELL_LEFT);
|
||||
|
||||
wire(loader, refresh, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
refreshList(state);
|
||||
}
|
||||
});
|
||||
wire(loader, newBone, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
create(state, "Bone");
|
||||
}
|
||||
});
|
||||
wire(loader, newSlot, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
create(state, "Slot");
|
||||
}
|
||||
});
|
||||
wire(loader, newBBox, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
create(state, "Bounding Box");
|
||||
}
|
||||
});
|
||||
wire(loader, newPath, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
create(state, "Path");
|
||||
}
|
||||
});
|
||||
wire(loader, setValue, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -215,6 +187,29 @@ public final class ObjectPanel {
|
||||
return root;
|
||||
}
|
||||
|
||||
/** 把日志缓冲写进底部 Label(多行)。 */
|
||||
private static void writeLogLabel(final State state) {
|
||||
if (state.status == null) return;
|
||||
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] 日志 Label 更新失败: " + error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 只往内容表格末尾追加**一行**日志(必要时先补一行分隔标记)。 */
|
||||
private static void appendLogRow(State state, String text) {
|
||||
try {
|
||||
@@ -319,8 +314,21 @@ public final class ObjectPanel {
|
||||
+ (state.target == null ? "" : "; target = " + SceneObjects.kind(state.target)
|
||||
+ " " + SceneObjects.nameOf(state.target)));
|
||||
state.rendering = false;
|
||||
appendLogRows(state);
|
||||
invalidateList(state);
|
||||
if (!state.geometryDumped) {
|
||||
state.geometryDumped = true;
|
||||
dumpFloats("pane(before)", state.listScroll);
|
||||
for (String candidate : new String[] {"I", "L", "B", "Z", "V", "C", "S"}) {
|
||||
try {
|
||||
call(state.listCell, candidate, new Class<?>[] {float.class}, state.cellClass,
|
||||
Float.valueOf(400f));
|
||||
System.err.println("[panel] tried Cell." + candidate + "(400)");
|
||||
dumpFloats("pane(after " + candidate + ")", state.listScroll);
|
||||
} catch (Throwable ignored) {
|
||||
// 该名字上没有 (F)Cell 方法
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -621,6 +629,26 @@ public final class ObjectPanel {
|
||||
}
|
||||
}
|
||||
|
||||
/** 只读诊断:打印对象上所有**无参返回 float**的方法名和值(用来看 ScrollPane 的真实宽高)。 */
|
||||
static void dumpFloats(String tag, Object target) {
|
||||
StringBuilder out = new StringBuilder("[panel] " + tag + ": ");
|
||||
try {
|
||||
for (Method method : target.getClass().getMethods()) {
|
||||
if (method.getParameterTypes().length != 0) continue;
|
||||
if (method.getReturnType() != float.class) continue;
|
||||
try {
|
||||
method.setAccessible(true);
|
||||
out.append(method.getName()).append('=').append(method.invoke(target)).append(" ");
|
||||
} catch (Throwable ignored) {
|
||||
// 跳过
|
||||
}
|
||||
}
|
||||
System.err.println(out.toString());
|
||||
} catch (Throwable error) {
|
||||
System.err.println("[panel] dumpFloats 失败: " + error);
|
||||
}
|
||||
}
|
||||
|
||||
static void attachEventProbe(final Object actor, final String tag) {
|
||||
try {
|
||||
Class<?> listenerClass = Class.forName("dn", true, actor.getClass().getClassLoader());
|
||||
@@ -791,7 +819,6 @@ public final class ObjectPanel {
|
||||
}
|
||||
}
|
||||
state.rendering = false;
|
||||
appendLogRows(state);
|
||||
invalidateList(state);
|
||||
} catch (Throwable error) {
|
||||
System.err.println("[panel] 字段列表填充失败: " + error);
|
||||
@@ -834,7 +861,6 @@ public final class ObjectPanel {
|
||||
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);
|
||||
@@ -858,8 +884,8 @@ public final class ObjectPanel {
|
||||
state.log.addLast(text);
|
||||
while (state.log.size() > LOG_LINES) state.log.removeFirst();
|
||||
}
|
||||
// 只追加一行日志:千万不要在这里重跑列表渲染,否则 Inspect 写好的字段清单会被覆盖
|
||||
if (!state.rendering) appendLogRow(state, text);
|
||||
// 写进底部日志 Label(多行、只保留最近几条)——不再动列表内容
|
||||
writeLogLabel(state);
|
||||
}
|
||||
|
||||
/** TextField 里的文字(名字被混淆了,按"无参 + 返回 String"取)。 */
|
||||
|
||||
Reference in new issue
Block a user