!7 sclass Tab { S name, moduleID; } compact module Tabs { transient NotifyingList tabs; transient JTabbedPane jtabs; S libID = "#1016118/SFEditor"; start { tabs = notifyingList(r change + r updateTabs); dm_vmBus_onMessage_q('moduleStarted, voidfunc(S moduleID) { addTabForModule(moduleID) }); dm_vmBus_onMessage_q('deletingModule, voidfunc(O module) { removeTabForModule(dm_moduleID(module)) }); dm_vmBus_onMessage_q('moduleNameChange, voidfunc(O module, S oldName, S newName) { updateTabForModule(dm_moduleID(module)) }); dm_q(r { for (S moduleID : dm_listModuleIDs()) addTabForModule(moduleID) }); dm_vmBus_onMessage_q('newActiveModule, vf selectModule); } visualize { jtabs = jtabs(); updateTabs(); onTabSelected(jtabs, r { Tab tab = get(tabs, selectedTabIndex(jtabs)); if (tab != null) showModule(tab.moduleID); }); ret withButtonsAbove(jtabs, "+", rThread dm_newEditor); } void updateTabs q { if (jtabs == null) ret; fillJTabs(jtabs, syncCollect name(tabs)); for (Component c : tabComponents(jtabs)) jminwidth(100, c/JComponent); selectModule(dm_activeModule()); } void addTabForModule(S moduleID) { if (eq(dm_moduleLibID(moduleID), libID) && !containsWhere(tabs, +moduleID)) tabs.add(nu(Tab, name := moduleName(moduleID), +moduleID)); } void removeTabForModule(S moduleID) { removeWhere(tabs, +moduleID); } void updateTabForModule(S moduleID) { Tab tab = firstWhere(tabs, +moduleID); if (tab == null) ret; tab.name = moduleName(moduleID); tabs.change(); } S moduleName(O module) { ret dropPrefix("Editing: ", dm_moduleName(module)); } void selectModule(O module) { if (jtabs == null || module == null || dm_isMe(module)) ret; selectTab(jtabs, indexOfWhere(tabs, moduleID := dm_moduleID(module))); } void showModule(O module) { dm_showModule(module); Rect r = dm_bounds(module), me = dm_bounds(); dm_setBounds(module, me.x, me.y2(), me.w, r.h); } }