LUA meets MUI, C and Abox
  • Moderator
    Kronos
    Posts: 2267 from 2003/2/24
    This is a a continuation of this and my 2nd attempt (after PastePass last year) to bring old unfinished projects to a usable state instead of starting something new...

    Download here :http://www.steamdraw.homepage.t-online.de/LUA_MUI.lha

    I have now settled on most of API/formats and there aren't any super obvious bugs around (but still plenty of hidden ones for sure).



    [ Edited by Kronos 01.04.2023 - 19:16 ]
  • »01.04.23 - 18:12
    Profile
  • Moderator
    Kronos
    Posts: 2267 from 2003/2/24
    This is Class1.lua (similar to what existed in the old release).

    "include" all needed modules and define OM_SET (since it is not in mui.h and won't be generated by current scripts)
    Code:

    require 'abox'
    require 'cdata'
    require "muidefs"
    require "muifuncs"
    require "muistructs"
    require "io"



    mui.OM_SET = 0x103


    Modes if and when DoSuperMethod() should be called, save unnecessary back and forth between the script and the mui.module but should be defined inside the module.
    Code:


    mui.NoSuper = 0
    mui.PreSuper = 1
    mui.PostSuper = 2



    Define some structs not covered by the scripts.

    Code:


    TagItem = {
    name = "TagItem",
    {types.ULONG, "ti_Tag"},
    {types.ULONG, "ti_Data"}
    };

    opSet = {
    name = "opSet",
    {types.ULONG, " MethodID"},
    {"struct TagItem", "ops_AttrList"},
    {"struct GadgetInfo *", "ops_GInfo"}
    };

    mydata = {
    name = "mydata",
    {types.ULONG,"dummy1"},
    {types.ULONG,"dummy2"},
    }


    Implementation of MUIM_AskMinMax, note that cdata.module now will now set amm to MinMaxInfo by default

    Code:

    function areaamm(cl,obj,msg)
    amm = msg.MinMaxInfo
    amm.MinWidth = amm.MinWidth + 200
    amm.DefWidth = amm.DefWidth + 220
    amm.MaxWidth = amm.MaxWidth + 500
    amm.MinHeight = amm.MinHeight + 220
    amm.DefHeight = amm.DefHeight + 190
    amm.MaxHeight = amm.MaxHeight + 300
    end



    MUIM_Draw using some special function found in abox.module.

    Code:


    function areadraw(cl,obj,msg)
    rp = obj:rp()
    data = obj:inst_data(cl)
    data.dummy1 = data.dummy1+1
    -- cache the dimesions to enhance performace
    -- as these accesses aren't as straightforward as they would be with C
    top = obj:mtop()
    left = obj:mleft()
    bottom = obj:mbottom()
    right = obj:mright()
    for i = left,right,5 do
    rp:Move(left,bottom+data.dummy1)
    rp:Draw(i,top)
    rp:Move(right,bottom)
    rp:Draw(i,top)
    end
    end


    MUIM_Set with some pointless test code. Parsing a full TagList is possible, just not in an elegant way.

    Code:

    function areaset(cl,obj,msg)
    io.write(msg.ops_AttrList.ti_Tag.." "..mui.MUIA_Window_Open.."n")
    io.write(msg.ops_AttrList[1].ti_Tag.." "..mui.MUIA_Window_Open.."n")
    msg.ops_AttrList[1].ti_Tag = 111111112
    io.write(msg.ops_AttrList[1].ti_Tag.." "..mui.MUIA_Window_Open.."n")
    end


    Definition of the dispatcher.
    Code:

    myclass_dis = {{mui.MUIM_AskMinMax,areaamm,mui.PreSuper,mui.MUIP_AskMinMax},
    {mui.MUIM_Draw,areadraw,mui.PreSuper,mui.MUIP_Draw},
    {mui.OM_SET,areaset,mui.PreSuper,"opSet"}
    }


    "Registering" structs is still needed in some cases but will disappear later on.
    Create class and object.

    Code:

    function main()
    struct.register(mui.MUI_MinMax)
    struct.register(opSet)
    struct.register(TagItem)
    mcc = mui.createcostumclass(mui.MUIC_Area,myclass_dis,mydata)
    myobj = mui.new(mcc)--, mui.TextFrame,mui.UIA_Background,mui.MUII_BACKGROUND )


    Boilerplate MUI code.
    Code:

    window = mui.WindowObject(
    mui.MUIA_Window_Title, "A Simple Custom Class",
    mui.MUIA_Window_ID , mui.makeid("CLS1"),
    mui.WindowContents, mui.HGroup (mui.Child,mui.HSpace(202),mui.Child, myobj)
    )

    app = mui.ApplicationObject(
    mui.MUIA_Application_Title , "Class1",
    mui.MUIA_Application_Version , "$VER: Class1.lua 0.2 (28.1.2023)",
    mui.MUIA_Application_Author , "Stefan Stuntz, Stefan Kleinheinrich",
    mui.MUIA_Application_Description, "LUA port of the Class1 demo",
    mui.MUIA_Application_Base , "CLASS1",
    mui.SubWindow, window )

    window:doint(mui.MUIM_Notify, mui.MUIA_Window_CloseRequest, true,
    app, 2, mui.MUIM_Application_ReturnID, mui.MUIV_Application_ReturnID_Quit)

    window:set(mui.MUIA_Window_Open, true)
    -- myobj:set(mui.MUIA_Window_Open, true,mui.MUIA_Window_Open+1, true)
    app:doint(mui.MUIM_Application_Execute)
    -- window:set(mui.MUIA_Window_Open, false)
    if app then app:dispose() end

    end

    main()



    [ Edited by Kronos 01.04.2023 - 19:17 ]
  • »01.04.23 - 18:12
    Profile
  • Moderator
    Kronos
    Posts: 2267 from 2003/2/24
    This is aboxtest.lua

    "Includes" and a reminder on what ID number goes for what type of data.

    Code:
    require 'mui'
    require "muidefs"
    require "muifuncs"

    require "cdata"
    require 'abox'
    require 'io'



    -- TYPE_VOID 0x00
    -- TYPE_BYTE 0x01
    -- TYPE_UBYTE 0x02
    -- TYPE_WORD 0x03
    -- TYPE_UWORD 0x04
    -- TYPE_LONG 0x05
    -- TYPE_ULONG 0x06
    -- TYPE_STRPTR 0x07
    -- TYPE_C_STRUCT 0x08 obsolete
    -- TYPE_BOOL 0x09
    -- TYPE_APTR 0x10
    -- TYPE_PTR 0x10000




    Bunch of structs we are gonna use, note the "Window" is just a placeholder as I plan to support a "typed" pointer later on for when you never need to look inside a structure but just a handle for it.

    Code:

    Node =
    {
    name = "Node",
    {"struct Node*", "ln_Succ"},
    {"struct Node*", "ln_Pred"},
    {types.UBYTE, "ln_Type"},
    {types.BYTE, "ln_Pri"},
    {types.STRPTR, "ln_Name"}
    }



    List =
    {
    name = "List",
    {"struct Node*", "lh_Head"},
    {"struct Node*", "lh_Tail"},
    {"struct Node*", "lh_TailPred"},
    {types.UBYTE, "lh_Type"},
    {types.UBYTE, "lh_pad"}
    }



    Task =
    {
    name = "Task",
    {"struct Node", "tc_Node"},
    {types.UBYTE, "tc_Flags"},
    {types.UBYTE, "tc_State"},
    {types.BYTE, "tc_IDNestCnt"},
    {types.BYTE, "tc_TDNestCnt"},
    {types.ULONG, "tc_SigAlloc"},
    {types.ULONG, "tc_SigWait"},
    {types.ULONG, "tc_SigRecvd"},
    {types.ULONG, "tc_SigExcept"},
    {types.APTR, "tc_ETask"},
    {types.APTR, "tc_ExceptData"},
    {types.APTR, "tc_ExceptCode"},
    {types.APTR, "tc_TrapData"},
    {types.APTR, "tc_TrapCode"},
    {types.APTR, "tc_SPReg"},
    {types.APTR, "tc_SPLower"},
    {types.APTR, "tc_SPUpper"},
    {types.ULONG, "void1"}, --(*tc_Switch)(VOID); /*** OBSOLETE ***/
    {types.ULONG, "void2"}, --(*tc_Launch)(VOID); /*** OBSOLETE ***/
    {"struct List", "tc_MemEntry"},
    {types.APTR, "tc_UserData"}
    }



    NewWindow =
    {
    name = "NewWindow",
    {types.WORD, "LeftEdge"},
    {types.WORD, "TopEdge"},
    {types.WORD, "Width"},
    {types.WORD, "Height"},
    {types.UBYTE, "DetailPen"},
    {types.UBYTE, "lockPen"},
    {types.ULONG, "IDCMPFlags"},
    {types.ULONG, "Flags"},
    {"struct Gadget *", "FirstGadget"},
    {"struct Image *", "CheckMark"},
    -- {types.UBYTE+types.PTR, "Title"},
    {types.STRPTR, "Title"},
    {"struct Screen *", "Screen"},
    {"struct BitMap *", "BitMap"},
    {types.WORD, "MinWidth"},
    {types.WORD, "MinHeight"},
    {types.UWORD, "MaxWidth"},
    {types.WORD, "MaxHeight"},
    {types.UWORD, "Type"}
    }

    Window =
    {
    name = "Window",
    {types.ULONG, "VOID"}
    }

    struct.register(Node)
    struct.register(List)
    struct.register(Task)
    struct.register(NewWindow)
    struct.register(Window)



    Definition of the LibCalls we want to use.
    Format is base,offset,return type, arg1 type, arg1 register (1- for D0-7, 8-13 for A0-A5),arg2 type..... LUA-Varargs

    Code:


    function abox.OpenLibrary(...) return abox.LibCall(abox.SysBase,-552,"Library",0x07,0x09,0x05,0x00,arg) end
    function abox.CloseLibrary(...) return abox.LibCall(abox.SysBase,-414,0x00,"Library",0x08,arg) end


    function abox.NewGetSystemAttrsA(...) return abox.LibCall(abox.SysBase,-906,0x05,0x10,0x08,0x05,0,0x05,0x01,"TagItem",0x09,arg) end
    function abox.FindTask(...) return abox.LibCall(abox.SysBase,-294,"Task",arg) end



    function abox.OpenWindowTagList(...) return abox.LibCall(abox.IntuitionBase,-606,"Window","NewWindow",0x08,"TagItem",0x09,arg) end
    function abox.DisplayBeep(...) return abox.LibCall(abox.IntuitionBase,-96,0x00,0x05,0x08,arg) end
    function abox.CloseWindow(...) return abox.LibCall(abox.IntuitionBase,-72,0x00,"Window",0x08,arg) end

    function abox.Delay(...) return abox.LibCall(abox.DosBase,-198,0,5,1,arg) end



    Some constants and an array to use as a string result (should have been UBYTE)

    Code:

    abox.SYSTEMINFOTYPE_REGUSER = 0x23c

    abox.SYSTEMINFOTYPE_VENDOR = 0x236

    abox.SYSTEMINFOTYPE_CPUCOUNT = 0x101


    res_str = array.new(130,types.ULONG)

    res_str[1] = 190
    io.write(res_str[1].."n")


    res_str.LUA_String and res_str.LUA_Int converts the raw data into a string or number.
    Code:

    res = abox.NewGetSystemAttrsA(res_str,130,abox.SYSTEMINFOTYPE_REGUSER,0)
    xx = res_str.LUA_String
    io.write(res_str.LUA_String.."n")
    res = abox.NewGetSystemAttrsA(res_str,130,abox.SYSTEMINFOTYPE_VENDOR,0)
    xx = res_str.LUA_String
    io.write(res_str.LUA_String.."n")
    res = abox.NewGetSystemAttrsA(res_str,130,abox.SYSTEMINFOTYPE_CPUCOUNT,0)
    xx = res_str.LUA_String
    io.write(res_str.LUA_Int.."n")



    Setting a tasks priority actually works this way but is bad style for obvious reasons. Was only done to test if write access to an "embeeded" struct actually works (a struct inside a struct that is not just a pointer).

    Code:


    task =abox.FindTask(0)
    node = task.tc_Node
    --task.tc_Node.ln_Pri = -41
    io.write(task.tc_Node.ln_Name.."n")
    io.write(task.tc_Node.ln_Type.." typen")
    io.write(task.tc_Node.ln_Pri.." prin")
    io.write(task.tc_SigAlloc.."n")


    Opening, using and closing some Libraries. Note that there are no checks for failure as those aren't implemented yet in abox.module.
    At the moment on a failed OpenLibrary() it will just return struct_Library object pointing to 0.
    Doing non MUI windows is not recommended off course and just done as a poof of concept.
    Code:

    abox.IntuitionBase = abox.OpenLibrary("intuition.library",0)
    abox.DosBase = abox.OpenLibrary("dos.library",0)

    nw = struct.new(NewWindow)
    nw.LeftEdge = 300
    nw.TopEdge = 400
    nw.Width = 300
    nw.Height = 200
    nw.Title = "Test_Window"
    nw.Type = 1 --WBENCHSCREEN
    win = abox.OpenWindowTagList(nw,0)
    abox.Delay(100)
    abox.CloseWindow(win)
    abox.DisplayBeep(0)
    abox.CloseLibrary(abox.IntuitionBase)
    abox.CloseLibrary(abox.DosBase)



    [ Edited by Kronos 01.04.2023 - 19:15 ]
  • »01.04.23 - 18:13
    Profile
  • MorphOS Developer
    jacadcaps
    Posts: 3029 from 2003/3/5
    From: Canada
    Quite interesting. How about using lua classes for MUI? Anyway, good stuff. Looks fairly complete from the examples.
  • »02.04.23 - 12:12
    Profile Visit Website
  • Moderator
    Kronos
    Posts: 2267 from 2003/2/24
    Quote:

    jacadcaps wrote:
    How about using lua classes for MUI?


    Most of the MUI stuff is still a straight port from the AROS version and I don't intend to rewrite all of that.

    I also assume that going that route would require some sort of stub function for each MUI class and each Method (maybe even for every Attribute) which would not only blow up the module quite a bit but would also make it harder to support 3rd party MCCs.
  • »02.04.23 - 12:33
    Profile
  • Moderator
    Kronos
    Posts: 2267 from 2003/2/24
    New version to be found in the old place.


    - LibCall() will now fail if the called function failed (the result is a NIL value)
    - LibCall() can return Integer values
    - "virtual structs" aka just pointers without a closer definition did already

    Updated the example to reflect that.

    I have also changed muistructs.lua to register all structs at launch. This will lead to a noticeable delay and eats quite some memory (the whole thing also still leaks some).

    I do have some idea to reduce the bloat (and will for sure fix the leaks) but that requires some testing.

    Todo:
    - clean up code
    - debug versions that provide info useful for developing scripts

    I will now switch focus on 1 or 2 other projects where I plan to use LUA_MUI which should help finding and fixing remaining issues.
  • »13.04.23 - 14:22
    Profile
  • Moderator
    Kronos
    Posts: 2267 from 2003/2/24
    New version to be found in the old place.

    This is a kinda stop gap release as I have run into a small (mental) roadblock with this project while I got plenty ideas for another.

    I did finally settle on how to define/include structures.

    - you can "require" a header which will initialize all structures at that point
    - you can use "add_header" which will only initialize a structure when it is used the 1st time (some caveats still apply)
    - you can dump the structures used (based on those added with "add_header") to include them directly in a release version

    In the definition you can now add a 3rd value that will determine wether it is a pointer (0), a single value (1 or NIL) or an embedded array (2 or higher).

    I also added a "DATA" ID so one can copy a whole struct instead of just a reference (pointer) to it. This whole "treat as a pointer or not" issue is what is stopping me atm as LUA just does not have such concepts.

    [ Edited by Kronos 27.08.2023 - 11:47 ]
  • »27.08.23 - 10:41
    Profile