Lua-Plugins erstellen

Plugins basierend auf Lua und andere Erweiterungen
mohousch
Einsteiger
Einsteiger
Beiträge: 362
Registriert: Mittwoch 14. Dezember 2005, 03:25

Lua-Plugins erstellen

Beitrag von mohousch »

@seife

kannst du einen lua demo plugins bitte zu Verfügung stellen?
thx
seife
Developer
Beiträge: 4189
Registriert: Sonntag 2. November 2003, 12:36

Re: NeutrinoHD(2) für sh4 und mips Platformen

Beitrag von seife »

luatest.lua

Code: Alles auswählen

-- print goes to stdout
print("hallo lua")
print(RC['RC_home'])
SX = SCREEN['OFF_X']
SY = SCREEN['OFF_Y']
EX = SCREEN['END_X']
EY = SCREEN['END_Y']
print("SX:" .. SX .. " SY:" .. SY .. " EX:" .. EX .. " EY:" .. EY)

local n = neutrino() -- max size
sx = SCREEN['OFF_X'] + 20
sy = SCREEN['OFF_Y'] + 20
w = SCREEN['END_X'] - 20 - sx
h = SCREEN['END_Y'] - 20 - sy
f = FONT['CHANNELLIST']
n:PaintBox(sx, sy, w, h, COL['MENUCONTENT'] + 0)
n:RenderString(f, "Hallo Lua!", 100, 100, COL['MENUCONTENT_TEXT'])
msg, data = n:GetInput(1000) -- sleep(1)
-- n = nil -- funktioniert nicht, ein "destruktor" fehlt noch

sx = SCREEN['OFF_X'] + 100
sy = SCREEN['OFF_Y'] + 100
w = SCREEN['END_X'] - 100 - sx
h = SCREEN['END_Y'] - 100 - sy

local m = neutrino(sx, sy, w, h);
m:PaintBox(-1, -1, -1, -1, COL['MENUCONTENT'] + 1) -- max size
m:RenderString(f, "Hallo Lua2!", 100, 100, COL['MENUCONTENT_TEXT'])

repeat
	msg, data = m:GetInput(1000)
	print("msg: " .. msg .. " data: " .. data)
until msg == RC['home']

neutrino():RenderString(f, "1 to exit", 200, 400, COL['MENUCONTENT_TEXT'])

repeat
	msg, data = m:GetInput(1000)
	print("msg: " .. msg .. " data: " .. data)
until msg == RC['1']

print("ciao!")
--end
luatest.cfg

Code: Alles auswählen

name=Lua Test
desc=tests lua
type=4
needfb=1
needrc=1
needoffsets=1
seife
Developer
Beiträge: 4189
Registriert: Sonntag 2. November 2003, 12:36

Re: NeutrinoHD(2) für sh4 und mips Platformen

Beitrag von seife »

window.lua

Code: Alles auswählen

listbox = {}

listbox.header = "Header Text"
listbox.entries = {
	"First entry",
	"second entry",
	"third!",
	"four",
	"fünf",
	"six",
	"seven",
	"888888888888"
}

-- global setting for rounded corners
radius = CORNER.RADIUS_MID
round_top    = bit32.bor(CORNER.TOP_LEFT, CORNER.TOP_RIGHT)
round_bottom = bit32.bor(CORNER.BOTTOM_LEFT, CORNER.BOTTOM_RIGHT)
round_all    = bit32.bor(round_top, round_bottom)
--
-- first call without position to initialize values
--
listbox.paint = function(self, sel)
	if sel == nil then -- initialize
		self.xs = self.x+10 -- string start
		self.ws = self.w-20 -- string end
		self.h_font = FONT.MENU_TITLE
		self.b_font = FONT.MENU
		self.b_height = n:FontHeight(self.b_font)
		if self.header then
			self.h_height = n:FontHeight(self.h_font)
			n:PaintBox(self.x, self.y, self.w, self.h_height, COL.MENUHEAD, radius, round_top)
			n:RenderString(self.h_font, self.header, self.xs, self.y + self.h_height, COL.MENUHEAD_TEXT, self.ws)
		else
			self.h_height = 0
		end
		self.offset = 1 -- start with first item
		local avail = self.h - self.h_height
		self.cap = math.floor(avail / self.b_height)
	else
		while sel - self.offset >= self.cap do
			self.offset = self.offset + self.cap
			self.old = nil -- "page change"
		end
		while sel < self.offset do
			self.offset = self.offset - self.cap
			self.old = nil
		end
	end
	if self.old == nil then -- initial call or changed page
		local round = self.h_height == 0 and round_all or round_bottom
		n:PaintBox(self.x, self.y + self.h_height, self.w, self.h - self.h_height, COL.MENUCONTENT, radius, round)
	end
	local yy = self.y + self.h_height + self.b_height
	for idx,entry in pairs(self.entries) do
		if idx >= self.offset and yy <= self.y + self.h then
			if self.old == nil then
				n:RenderString(self.b_font, entry, self.xs, yy, COL.MENUCONTENT_TEXT, self.ws)
			end
			if self.old ~= sel then -- selection changed
				local col, colt
				if idx == self.old then
					col  = COL.MENUCONTENT
					colt = COL.MENUCONTENT_TEXT
				elseif idx == sel then
					col  = COL.MENUCONTENTSELECTED
					colt = COL.MENUCONTENTSELECTED_TEXT
				end
				if col then
					n:PaintBox(self.x, yy - self.b_height, self.w, self.b_height, col, radius)
					n:RenderString(self.b_font, entry, self.xs, yy, colt, self.ws)
				end
			end
			yy = yy+self.b_height
		end
	end
	self.old = sel
end

--
-- main()
--
SX = SCREEN.OFF_X
SY = SCREEN.OFF_Y
EX = SCREEN.END_X
EY = SCREEN.END_Y
print("SX:"..SX.." SY:"..SY.." EX:"..EX.." EY:"..EY)
n = neutrino() -- max size
-- set dimensions of the listbox
listbox.x = SX+50
listbox.y = SY+50
listbox.w = EX-100
listbox.h = 5 * n:FontHeight(FONT.MENU) -- small, to force scrolling
listbox.paint(listbox)
i = 1
repeat
	listbox.paint(listbox, i)
	msg, data = n:GetInput(1000) -- sleep(1)
	if msg == RC.up then
		i = i - 1
		if i < 1 then i = #listbox.entries end
	elseif msg == RC.down then
		i = i + 1
		if i > #listbox.entries then i = 1 end
	end
	print("msg: "..msg.." data: "..data.." i: "..i)
until msg == RC.home
print("bye")
window.cfg

Code: Alles auswählen

name=Lua Window
desc=window
type=4
needfb=1
needrc=1
needoffsets=1
seife
Developer
Beiträge: 4189
Registriert: Sonntag 2. November 2003, 12:36

Re: NeutrinoHD(2) für sh4 und mips Platformen

Beitrag von seife »

window.lua ist ein Beispiel, wie man menüs etc. machen kann, ganz ohne C-Code und ohne daß die internen Menüklassen ans lua-Interface exportiert werden müssen (und man muß das plugin nicht updaten, wenn sich im neutrino interface was ändert, von Stabiler API hält da ja keiner was :-))
svenhoefer
Interessierter
Interessierter
Beiträge: 42
Registriert: Donnerstag 25. Oktober 2012, 14:22

Lua-Plugin: Shellexec-Ersatz

Beitrag von svenhoefer »

ich habe window.lua mal genommen, um einen shellexec-ersatz zu beginnen. funktioniert auch soweit, nur bin ich nicht in der lage, alles in eine tabelle zu verfrachten. ich hätte gern eine tabelle für die einträge angelegt, die so in etwas tickt:

Code: Alles auswählen

listbox.entries = {
	{ name = "Börse", exec = "boerse.sh"},
	{ name = "Handball", exec= "'handhall.sh options'"}
}
ich scheitere daran, auf "name" und "exec" zugreifen zu können. kann mir da mal bitte jemand auf die sprünge helfen?

mein bisheriger stand:

Code: Alles auswählen

listbox = {}

listbox.header = "Flex Nachbau"
listbox.entries = {
	"Börse",
	"Handball",
}
listbox.executes = {
	"/share/tuxbox/neutrino/plugins/boerse.sh",
	"/share/tuxbox/neutrino/plugins/handball.sh",
}

-- global setting for rounded corners
radius = CORNER.RADIUS_MID
round_top    = bit32.bor(CORNER.TOP_LEFT, CORNER.TOP_RIGHT)
round_bottom = bit32.bor(CORNER.BOTTOM_LEFT, CORNER.BOTTOM_RIGHT)
round_all    = bit32.bor(round_top, round_bottom)
--
-- first call without position to initialize values
--
listbox.paint = function(self, sel)
   if sel == nil then -- initialize
      self.xs = self.x+10 -- string start
      self.ws = self.w-20 -- string end
      self.h_font = FONT.MENU_TITLE
      self.h_height = n:FontHeight(self.h_font)
      self.b_font = FONT.MENU
      self.b_height = n:FontHeight(self.b_font)

	-- calc window h and y -- FIXME
	self.h = self.h_height + (#listbox.entries * self.b_height)
	self.y = ((EY - SY) /2) - (self.h / 2) 

      if self.header then
         n:PaintBox(self.x, self.y, self.w, self.h_height, COL.MENUHEAD, radius, round_top)
         n:RenderString(self.h_font, self.header, self.xs, self.y + self.h_height, COL.MENUHEAD_TEXT, self.ws)
      else
         self.h_height = 0
      end
      self.offset = 1 -- start with first item
      local avail = self.h - self.h_height
      self.cap = math.floor(avail / self.b_height)
   else
      while sel - self.offset >= self.cap do
         self.offset = self.offset + self.cap
         self.old = nil -- "page change"
      end
      while sel < self.offset do
         self.offset = self.offset - self.cap
         self.old = nil
      end
   end
   if self.old == nil then -- initial call or changed page
      local round = self.h_height == 0 and round_all or round_bottom
      n:PaintBox(self.x, self.y + self.h_height, self.w, self.h - self.h_height, COL.MENUCONTENT, radius, round)
   end
   local yy = self.y + self.h_height + self.b_height
   for idx, entry in pairs(self.entries) do
      if idx >= self.offset and yy <= self.y + self.h then
         if self.old == nil then
            n:RenderString(self.b_font, entry, self.xs, yy, COL.MENUCONTENT_TEXT, self.ws)
         end
         if self.old ~= sel then -- selection changed
            local col, colt
            if idx == self.old then
               col  = COL.MENUCONTENT
               colt = COL.MENUCONTENT_TEXT
            elseif idx == sel then
               col  = COL.MENUCONTENTSELECTED
               colt = COL.MENUCONTENTSELECTED_TEXT
            end
            if col then
               n:PaintBox(self.x, yy - self.b_height, self.w, self.b_height, col, radius)
               n:RenderString(self.b_font, entry, self.xs, yy, colt, self.ws)
            end
         end
         yy = yy+self.b_height
      end
   end
   self.old = sel
end

--
-- main()
--
SX = SCREEN.OFF_X
SY = SCREEN.OFF_Y
EX = SCREEN.END_X
EY = SCREEN.END_Y
print("SX:"..SX.." SY:"..SY.." EX:"..EX.." EY:"..EY)
n = neutrino() -- max size
-- set dimensions of the listbox
listbox.w = (EX-SX) / 2
listbox.h = nil -- (EY-SY) / 2
listbox.x = SX + (listbox.w / 2)
listbox.y = nil -- SY + (listbox.h / 2)
listbox.paint(listbox)
i = 1
repeat
   listbox.paint(listbox, i)
   msg, data = n:GetInput(1000) -- sleep(1)
   if msg == RC.up then
      i = i - 1
      if i < 1 then i = #listbox.entries end
   elseif msg == RC.down then
      i = i + 1
      if i > #listbox.entries then i = 1 end
   end
   if msg == RC.ok then
	print("key OK, i: " ..i.. " execute: " ..listbox.executes[i])
	os.execute(listbox.executes[i])
   end
   print("msg: "..msg.." data: "..data.." i: "..i)
until msg == RC.home
print("bye")
svenhoefer
Interessierter
Interessierter
Beiträge: 42
Registriert: Donnerstag 25. Oktober 2012, 14:22

Re: Lua-Plugins erstellen

Beitrag von svenhoefer »

ich habe es eben selbst herausgefunden. man muss die tabelle nochmal in arrays zerlegen:

Code: Alles auswählen

listbox.entries = {
	{ name = "Börse",		exec = "/share/tuxbox/neutrino/plugins/boerse.sh"},
	{ name = "Handball",	exec = "/share/tuxbox/neutrino/plugins/handhall.sh"}
}

names = {}
execs = {}
for v, w in ipairs(listbox.entries) do
	names[v] = w.name
	execs[v] = w.exec
end
seife
Developer
Beiträge: 4189
Registriert: Sonntag 2. November 2003, 12:36

Re: Lua-Plugins erstellen

Beitrag von seife »

Ja, genau. Tabellen (ähnlich "assoziative arrays" oder in perl "Hashes") sind die first-class datatype in lua. Und natürlich kann man alles in eine Tabelle reinpacken, auch andere Tabellen :-)

Nun musst du nur noch deine listbox.entries aus einem extra configfile lesen (mit "do filename" IIRC), und schon ist das plugin nützlich.
Janus
Einsteiger
Einsteiger
Beiträge: 232
Registriert: Sonntag 29. Juli 2001, 23:00

Re: Lua-Plugins erstellen

Beitrag von Janus »

Und natürlich kann man alles in eine Tabelle reinpacken, auch andere Tabellen
... und sogar Funktionen und Methoden.

Wenn Du Jemand zum Testen brauchst... :wink:
svenhoefer
Interessierter
Interessierter
Beiträge: 42
Registriert: Donnerstag 25. Oktober 2012, 14:22

Re: Lua-Plugins erstellen

Beitrag von svenhoefer »

kann man ein luascript auch von der konsole aus starten und dann auf neutrino-funktionen zugreifen? also zum beispiel eine hintbox erscheinen lassen? das kleine beispiel unten funktioniert prima als plugin via neutrino. an der konsole läuft es aber in einen fehler.

Code: Alles auswählen

#!/bin/lua

n = neutrino()

h = hintbox.new{caption="Header", text="Content"}
h:paint()
repeat
	msg, data = n:GetInput(500)
until msg == RC.ok or msg == RC.home
h:hide()
seife
Developer
Beiträge: 4189
Registriert: Sonntag 2. November 2003, 12:36

Re: Lua-Plugins erstellen

Beitrag von seife »

nein.
svenhoefer
Interessierter
Interessierter
Beiträge: 42
Registriert: Donnerstag 25. Oktober 2012, 14:22

Re: Lua-Plugins erstellen

Beitrag von svenhoefer »

schade. wäre cool, wenn man auch /bin/msgbox, /bin/input und so ersetzen könnte.
martii
Einsteiger
Einsteiger
Beiträge: 217
Registriert: Donnerstag 14. Juni 2012, 08:39

Re: Lua-Plugins erstellen

Beitrag von martii »

Lua-Plugins lassen sich via

http://.../control/startplugin?name=...

zur Not auch extern aufrufen.

Die Herausforderung wäre an dieser Stelle aber, sowohl Argumente übergeben zu können als auch einen Rückgabewert zu bekommen.
martii
Einsteiger
Einsteiger
Beiträge: 217
Registriert: Donnerstag 14. Juni 2012, 08:39

Re: Lua-Plugins erstellen

Beitrag von martii »

Mit

https://gitorious.org/neutrino-mp/marti ... 416d8ab8d0

sollte der Aufruf von Lua-Plugins via CLI im Neutrino-Kontext möglich sein. Bisher nur minimalst mit

Code: Alles auswählen

# cat /lib/tuxbox/luaplugins/test.lua 
for i,v in ipairs(arg) do
        print(tostring(i) .. "\t" .. tostring(v))
end
return "ok"
# luaclient test a b c
getestet. Funktioniert vermutlich, zumindest einigermaßen, ich hab heute keine Lust mehr zum Testen. Die "print"-Ausgaben erscheinen im Neutrino-stdout, das "ok" als Output von luaclient.
micha-bbg
Interessierter
Interessierter
Beiträge: 31
Registriert: Dienstag 14. Juli 2009, 08:59

Re: Lua-Plugins erstellen

Beitrag von micha-bbg »

Hallo,
hab mir das grad mal angeschaut.
Eigentlich ist doch fast alles schon im yweb enthalten. Wäre es nicht einfacher, yweb dahin etwas aufzubohren, dass mit nem entsprechenden Parameter in der Url ein Luascript ausgeführt wird? Ist dann genauso von der Kommandozeile aufrufbar, aber erheblich einfacher zu realisieren. Wie gesagt, die ganzen Client/Server Sachen sind ja schon im yweb enthalten, so wär es auch weit ressourcenschonender.
martii
Einsteiger
Einsteiger
Beiträge: 217
Registriert: Donnerstag 14. Juni 2012, 08:39

Re: Lua-Plugins erstellen

Beitrag von martii »

Ich halte die Integration in yweb nicht für einfacher, aber falls unsere Ansichten da divergieren, freue ich mich auf eine passende Implementierung. Gegen yweb spricht (freilich nur IMHO), dass
  • Aufrufe überlappend möglich sein müssen (aus der Erinnerung heraus meine ich, dass nhttpd in HD nicht multi-threaded ist, ich hab das aber nicht verifiziert)
  • Exit-Status, Fehlermeldungen und ein Rückgabewert (schöner wäre stdout, hab' ich aber ad hoc nicht herausgefunden, wie das zu bewerkstelligen wäre) propagiert werden
  • die Integration transparent zu vorhandenen Mechanismen/Plugins sein sollte
  • der Plugin-Aufruf nur möglich sein darf, wenn Neutrino nicht zeitgleich versucht, die RC-Events abzugreifen
Prinzipiell erlaubt mein Commit beispielsweise den transparenten Ersatz von shellexec, getrc, ..., sofern passende Lua-Implementierungen existieren. Dazu muss nichtmal "luaclient" explizit aufgerufen werden, es reicht dann schon, wenn z.B. "shellexec" darauf verlinkt.

Was ich überhaupt nicht nachvollziehen kann, ist Dein "weit ressourcenschonender". Zum einen achte ich schon aus Gewohnheit darauf, dass mein Code nicht ineffizient ist, und zum anderen sind selbst Deine CST-Kisten nicht so schwach dimensioniert, als dass sie durch einen weiteren Thread, der im Idle-Zustand keine nennenswerten Ressourcen braucht, ausgebremst würden.
mohousch
Einsteiger
Einsteiger
Beiträge: 362
Registriert: Mittwoch 14. Dezember 2005, 03:25

Re: Lua-Plugins erstellen

Beitrag von mohousch »

Hm
Plugins aus dem Yweb ausführen entschliesst mir wirklich den Sinn :roll: wofür?
Hingegen aus der Console wie damals für die Dbox2 der Pluginx ist ein alternative für den Plugin Entwickler nicht jedes mal auf die FB zu zugreifen.
martii hat geschrieben:# der Plugin-Aufruf nur möglich sein darf, wenn Neutrino nicht zeitgleich versucht, die RC-Events abzugreifen
da war seife wo anders (libtuxtxt) schneller, da nhttpd nicht als standalone Deamon läuft eigene RC -Event Code im nhttpd hat kein Sinn mir man koennte das wie im seifes tuxtxt machen (im Neutrino-HD2 ist langher shamelos aus siefes tuxtxt geklaut ;)) der neutrino RCInput pointer nutzen und somit solange man den Plugin ausführt gehen die event nicht an nhttpd oder auch immer was ;)
schufti
Einsteiger
Einsteiger
Beiträge: 352
Registriert: Freitag 20. August 2004, 22:33

Re: Lua-Plugins erstellen

Beitrag von schufti »

Hmmm, habe ich da was falsch verstanden, oder hat der Initiator der Lua-Integration (versehentlich) da selbst ein falsches Beispiel gegeben:

Code: Alles auswählen

name=Lua Test
desc=tests lua
type=4
needfb=1
needrc=1
needoffsets=1
seife selbst hat ja für Lua den typ 0x10 eingeführt. 0x4 wäre ja ein "Tool"

so beißt sich das jetzt natürlich mit

Code: Alles auswählen

new_plugin.pluginfile = fname;
if (new_plugin.type == CPlugins::P_TYPE_SCRIPT)
new_plugin.pluginfile.append(".sh");
else if (new_plugin.type == CPlugins::P_TYPE_LUA)
new_plugin.pluginfile.append(".lua");
else // CPlugins::P_TYPE_GAME or CPlugins::P_TYPE_TOOL
new_plugin.pluginfile.append(".so");
aus plugins.cpp

und in den div. Neutrino Ausprägungen finden sich dann die abenteuerlichsten Lösungen um das gerade zu biegen und (Lua)Plugins gestartet zu bekommen. Auch "Listenzugehörigkeit" ist damit natürlich etwas durcheinender, vermutlich wurde die daher überall "neu gewürfelt".

P.S.: ich hoffe, das kommt jetzt nicht als Kritik an Seife rüber. Soll eigentlich eine an den Image und Plugin Authoren sein.

P.P.S.: da war ich am Holzweg, sorry. Die abenteuerliche Lösung war ein einfacher Codeteil, den ich übersehen habe :oops:
Zuletzt geändert von schufti am Montag 1. Dezember 2014, 16:53, insgesamt 1-mal geändert.
svenhoefer
Interessierter
Interessierter
Beiträge: 42
Registriert: Donnerstag 25. Oktober 2012, 14:22

Re: Lua-Plugins erstellen

Beitrag von svenhoefer »

Schau mal in src/plugin.h:

Code: Alles auswählen

typedef enum plugin_type
{
	PLUGIN_TYPE_DISABLED = 0,
	PLUGIN_TYPE_GAME     = 1,
	PLUGIN_TYPE_TOOL     = 2,
	PLUGIN_TYPE_SCRIPT   = 3,
	PLUGIN_TYPE_LUA      = 4
}
plugin_type_t;
Alles gut also. Intern wird dann mit dem von dir angesprochenen Hex-Wert gearbeitet.
svenhoefer
Interessierter
Interessierter
Beiträge: 42
Registriert: Donnerstag 25. Oktober 2012, 14:22

Re: Lua-Plugins erstellen

Beitrag von svenhoefer »

In src/gui/plugins.cpp wird in der Funktion CPlugins::p_type_t CPlugins::getPluginType(int type) quasi von dem cfg-Wert (4) auf den internen Wert (0x10) "umgeschalten". Das geht schon alles so in Ordnung.

Was ist denn eigentlich der Grund deiner Frage? Was funktioniert nicht?

//Huch. Ich hätte wetten können, hier oben drüber stand eben noch eine Nachricht von schufti. Nu isse weg.
schufti
Einsteiger
Einsteiger
Beiträge: 352
Registriert: Freitag 20. August 2004, 22:33

Re: Lua-Plugins erstellen

Beitrag von schufti »

oh, super, eine doppelte Übersetzung sozusagen.... damit das noch einfacher zu behirnen ist.

Also in plugin_xxx.cfg gilt src/plugin.h und wird für "Intern" entsprechend auf src/gui/plugins.h übersetzt.

Naja, ich hatte damit zu kämpfen, dass Hinticons nicht angezeigt werden, wenn das Plugin auf "disabled" gesetzt ist (also nicht per "Liste" eingebunden werden soll) aber direkt im Usermenü plaziert ist.

Nachtrag: (martii Neutrino-MP) wäre vermutlich besser, das über das bool Attribut hidden zu machen und den Typ original zu lassen?
svenhoefer
Interessierter
Interessierter
Beiträge: 42
Registriert: Donnerstag 25. Oktober 2012, 14:22

Re: Lua-Plugins erstellen

Beitrag von svenhoefer »

schufti hat geschrieben:Naja, ich hatte damit zu kämpfen, dass Hinticons nicht angezeigt werden, wenn das Plugin auf "disabled" gesetzt ist (also nicht per "Liste" eingebunden werden soll) aber direkt im Usermenü plaziert ist.
OK. Das lässt sich sicher reparieren. Ebenso sicher hat das aber nichts mit der internen Handhabung der Plugin-Typen zu tun.

//Sollte man denn ein disabled Plugins überhaupt noch irgendwo einbinden können?
schufti
Einsteiger
Einsteiger
Beiträge: 352
Registriert: Freitag 20. August 2004, 22:33

Re: Lua-Plugins erstellen

Beitrag von schufti »

Also erstmal Danke für die Erklärung, wobei der erste Hinweis mich ja schon auf die richtige Fährte brachte um mir sozusagen selbst zu helfen. Daher haben sich die Beiträge(Änderungen/Löschung überschnitten.

Schöner wäre es allerdings, wenn die "Maintainer" jeweils etwas Kommentar zu den gerade bearbeiteten Codestellen spenden würden. Ich weiß, Speicherplatz ist auch heute noch heilig, aber es würde sicher einigen "Neueinsteigern" das Verständniss ungemein erleichtern. Besonders wenn man so wie ich mit PL/I, Cobol und Fortran auf Mainframe und Vax aufgewachsen ist.

Und da Seife und martii sich ja dzt./bis auf weiteres/endgültig anderen Hobbies widmen, muß Mann selbst Hand anlegen (lernen).

naja, disabled verstehe ich entsprechend martiis code ja so, dass es nur nicht in einem der User-sub-menüs auftauichen soll (wobei da auch ein Bruch bei Plugins und Tools drinnen ist, die wieder direkt im Usermenü eigebunden werden). Als Plugin direkt in einem Usermenü (also 1. Ebene) durchaus, ausser es ist hidden (aus Plugin.cfg).