// .sgui 打开
@Command(name="sgui", description="open script clickgui")
void openExec(args) { me.openScreen("script_clickgui"); }
@OnLoad void onLoad() { me.registerScreen("script_clickgui"); }
// ─── 布局参数 ────────────────────────────────────────────
String[] CATS = new String[]{ "COMBAT", "EXPLOIT", "MOVE", "PLAYER", "VISUAL", "WORLD" };
int PANEL_W = 110;
int HEADER_H = 18;
int ROW_H = 14;
int MAX_BODY = 240;
int CORNER_R = 3;
// ─── 颜色 ────────────────────────────────────────────────
long C_HEADER = 0xFF1E2430L;
long C_BG = 0xE0101418L;
long C_ROW = 0xFF1A1F28L;
long C_HOVER = 0xFF2A3340L;
long C_ROW_ON = 0xFF3F8DFFL;
long C_TEXT = 0xFFFFFFFFL;
long C_DIM = 0xFFAAAAAAL;
// ─── 状态 ────────────────────────────────────────────────
Map panelX = null; // category -> Integer
Map panelY = null;
Map panelScroll = null;
Map panelModules = null; // category -> List<Module>
int screenW = 854;
int screenH = 480;
String draggingCat = null;
double dragOffX = 0;
double dragOffY = 0;
// ───────────────────────────────────────────────────────────
// init:屏幕打开时,每次重新读模块列表 + 默认布局
// ───────────────────────────────────────────────────────────
@EventTarget(events="init")
void onInit(event) {
screenW = event.getInt("width");
screenH = event.getInt("height");
panelX = new LinkedHashMap();
panelY = new LinkedHashMap();
panelScroll = new LinkedHashMap();
panelModules = new LinkedHashMap();
int x = 16;
int y = 30;
for (cat : CATS) {
panelX.put(cat, x);
panelY.put(cat, y);
panelScroll.put(cat, 0);
panelModules.put(cat, moduleManager.byCategory(cat));
x += PANEL_W + 6;
}
draggingCat = null;
}
// ───────────────────────────────────────────────────────────
// 渲染
// ───────────────────────────────────────────────────────────
@EventTarget(events="render_screen")
void onRender(event) {
if (!render.isActive()) return;
if (panelModules == null) return;
mx = event.getNumber("mouse_x");
my = event.getNumber("mouse_y");
for (cat : CATS) drawPanel(cat, mx, my);
}
void drawPanel(cat, mx, my) {
px = panelX.get(cat);
py = panelY.get(cat);
scroll = panelScroll.get(cat);
list = panelModules.get(cat);
if (list == null) return;
bodyTotalH = list.size() * ROW_H;
bodyVisibleH = bodyTotalH > MAX_BODY ? MAX_BODY : bodyTotalH;
// header(圆顶)
render.round(px, py, PANEL_W, HEADER_H, CORNER_R, C_HEADER, true, true, false, false);
titleY = py + (HEADER_H - render.fontHeight()) / 2.0;
render.text(cat, px + 8, titleY, C_TEXT);
if (bodyVisibleH <= 0) return;
// body 背景
render.round(px, py + HEADER_H, PANEL_W, bodyVisibleH, CORNER_R, C_BG, false, false, true, true);
// 用 scissor 把超出可视区的行剪掉
render.pushScissor(px, py + HEADER_H, PANEL_W, bodyVisibleH);
rowY = py + HEADER_H - scroll;
for (h : list) {
if (rowY + ROW_H < py + HEADER_H || rowY > py + HEADER_H + bodyVisibleH) {
rowY += ROW_H;
continue;
}
hover = mx >= px && mx < px + PANEL_W && my >= rowY && my < rowY + ROW_H;
bg = h.isEnabled() ? C_ROW_ON : (hover ? C_HOVER : C_ROW);
render.rect(px, rowY, PANEL_W, ROW_H, bg);
render.text(h.getName(), px + 8, rowY + (ROW_H - render.fontHeight()) / 2.0, C_TEXT);
rowY += ROW_H;
}
render.popScissor();
// 滚动条提示(只在能滚的时候画)
if (bodyTotalH > bodyVisibleH) {
// 比例条
ratio = (double) bodyVisibleH / bodyTotalH;
scrollH = (int) (bodyVisibleH * ratio);
scrollOffsetY = (int) ((double) scroll / bodyTotalH * bodyVisibleH);
render.rect(px + PANEL_W - 2, py + HEADER_H + scrollOffsetY, 2, scrollH, C_DIM);
}
}
int panelTotalH(cat) {
list = panelModules.get(cat);
if (list == null) return HEADER_H;
bodyH = list.size() * ROW_H;
if (bodyH > MAX_BODY) bodyH = MAX_BODY;
return HEADER_H + bodyH;
}
// ───────────────────────────────────────────────────────────
// 点击:header 起拖 / row 切模块
// ───────────────────────────────────────────────────────────
@EventTarget(events="mouse_clicked")
void onClick(event) {
if (event.getInt("button") != 0) return;
if (panelModules == null) return;
mx = event.getNumber("mouse_x");
my = event.getNumber("mouse_y");
for (cat : CATS) {
px = panelX.get(cat);
py = panelY.get(cat);
if (mx < px || mx >= px + PANEL_W) continue;
// header → 拖拽
if (my >= py && my < py + HEADER_H) {
draggingCat = cat;
dragOffX = mx - px;
dragOffY = my - py;
return;
}
// body → 切模块
totalH = panelTotalH(cat);
if (my < py + HEADER_H || my >= py + totalH) continue;
scroll = panelScroll.get(cat);
list = panelModules.get(cat);
rowY = py + HEADER_H - scroll;
for (h : list) {
if (my >= rowY && my < rowY + ROW_H) {
// 行可能在 scroll 之外,hit 一下用 visible 范围二次校验
if (rowY + ROW_H >= py + HEADER_H && rowY < py + totalH) {
h.toggle();
}
return;
}
rowY += ROW_H;
}
return;
}
}
@EventTarget(events="mouse_released")
void onRelease(event) {
if (event.getInt("button") == 0) draggingCat = null;
}
// ───────────────────────────────────────────────────────────
// 拖拽
// ───────────────────────────────────────────────────────────
@EventTarget(events="mouse_dragged")
void onDrag(event) {
if (draggingCat == null) return;
if (event.getInt("button") != 0) return;
mx = event.getNumber("mouse_x");
my = event.getNumber("mouse_y");
newX = (int) (mx - dragOffX);
newY = (int) (my - dragOffY);
if (newX < 0) newX = 0;
if (newY < 0) newY = 0;
if (newX + PANEL_W > screenW) newX = screenW - PANEL_W;
totalH = panelTotalH(draggingCat);
if (newY + totalH > screenH) newY = screenH - totalH;
panelX.put(draggingCat, newX);
panelY.put(draggingCat, newY);
}
// ───────────────────────────────────────────────────────────
// 滚轮:在哪个面板上方就滚那个的模块列表
// ───────────────────────────────────────────────────────────
@EventTarget(events="mouse_scrolled")
void onScroll(event) {
if (panelModules == null) return;
mx = event.getNumber("mouse_x");
my = event.getNumber("mouse_y");
delta = event.getNumber("delta");
for (cat : CATS) {
px = panelX.get(cat);
py = panelY.get(cat);
totalH = panelTotalH(cat);
if (mx < px || mx >= px + PANEL_W) continue;
if (my < py || my >= py + totalH) continue;
list = panelModules.get(cat);
bodyTotalH = list.size() * ROW_H;
bodyVisibleH = bodyTotalH > MAX_BODY ? MAX_BODY : bodyTotalH;
maxScroll = bodyTotalH - bodyVisibleH;
if (maxScroll < 0) maxScroll = 0;
cur = panelScroll.get(cat);
newScroll = ((int) cur) - (int) (delta * 20);
if (newScroll < 0) newScroll = 0;
if (newScroll > maxScroll) newScroll = maxScroll;
panelScroll.put(cat, newScroll);
return;
}
}
@EventTarget(events="close")
void onClose(event) {
draggingCat = null;
}