OPT PREPROCESS,LARGE,OSVERSION=39
#define PlaneFuncObject NewObjectA(cl_planefunc.mcc_class,NIL,[TAG_IGNORE,0
#define ProjectListObject NewObjectA(cl_projectlist.mcc_class,NIL,[TAG_IGNORE,0
#define uSliderObject NewObjectA(cl_uslider.mcc_class,NIL,[TAG_IGNORE,0
#define SizeTextObject NewObjectA(cl_sizetxt.mcc_class,NIL,[TAG_IGNORE,0
#define MyApplicationObject NewObjectA(cl_myapp.mcc_class,NIL,[TAG_IGNORE,0

#define label(t) TextObject,MUIA_Text_Contents,t,MUIA_Text_SetMax,MUI_TRUE,End

#define modt(val) val AND $FF

#define PICVERSION 'PicFX alpha 0.87'
#define FULLVERSION '$VER: PicFX alpha 0.87 (27/04/99)'

MODULE 'afc/super_picture','afc/trueBitmap'
MODULE       'amigalib/boopsi','amigalib/lists',
       'asl',
       'datatypes','datatypes/datatypes','datatypes/pictureclass','datatypes/pictureclassext','datatypes/datatypesclass',
       'devices/timer',
       'dos/dos','dos/dosextens','dos/dostags',
       'exec/io','exec/lists','exec/memory','exec/nodes','exec/ports','exec/semaphores','exec/tasks',
       'graphics/gfx','graphics/rastport','graphics/view',
           'cybergraphics','picasso96api',
       'intuition/classes','intuition/classusr','intuition/intuition','intuition/screens',
       'libraries/asl','libraries/cybergraphics','libraries/gadtools','libraries/mui',
           'libraries/muip','libraries/picasso96',
       'mui/muicustomclass',
       'muimaster',
       'utility','utility/tagitem',
       '*parser','tools/longreal',
       'mui/lamp_mcc','mui/SettingsWindow_mcc',
       '*picFXlocale'

MODULE 'tools/debug' ->kputfmt(formatstring,[values])

CONST TICKS_PER_MINUTE = TICKS_PER_SECOND*60

DEF app,
    messages_win,messages_lst,
    prefs_win,mainpri_sld,renderpri_sld,renderupdate_sld,mui_btn,
        currpri_sld,close_cyc,
    settings_win,colour_txt,
    opened_lsv,opened_lst,
    new_btn,prefs_btn,
    sgroup, /*settings gadgets*/
    name_str,type_reg,
        path_str,size_rad,size_txt, -> for the DTPic type
        r_lbl,g_lbl,b_lbl,
        red_str,green_str,blue_str,outr_cyc,outg_cyc,outb_cyc, -> for the Function type
        red_fail,green_fail,blue_fail,comr_cyc,comg_cyc,comb_cyc,
    width_str,height_str,
            /*action buttons*/
    draw_btn,savepic_btn,savefunc_btn,abort_btn,showme_cyc,close_btn,
    loadfunc_btn,clear_btn,
            /*state area*/
    lamp_lmp,state_txt,state_gau,

    ftype_registertitles,size_radiolabels,showme_cyclelabels,
    sigs=0,
    lastid=0,/* lastid is a global variable incremented everytime a project is opened.
                absolutely no risk to have several projects with same ID*/
    screentitle,
    title[15]:STRING,counter=1, -> number of messages
    messages[15]:ARRAY OF LONG,

    cat:PTR TO catalog_picFX,

    rp=-2,cp=-1,        -> Priorities
    rupd=10,wclose,     -> Render update and Pwindow-close settings
    psema:ss,           -> Semaphore for preferences  (!!)

    currid=-1,quiet=FALSE     -> currid contains the id of the currently selected project. Quiet controls attributes refreshing.

DEF nodraw,friend=NIL

ENUM SETID_MainP=1,
     SETID_RenderP,
     SETID_CurrP,
     SETID_RUpd,
     SETID_Close

DEF cl_planefunc:PTR TO mui_customclass
DEF cl_projectlist:PTR TO mui_customclass
DEF cl_uslider:PTR TO mui_customclass
DEF cl_sizetxt:PTR TO mui_customclass
DEF cl_myapp:PTR TO mui_customclass

/*Registation Number:FCB96172; I take FCB9 as base... :(*/
ENUM MUIA_PlaneFunc_Bstr=$FCB90000, -> String of the B function
     /*MUIA_PlaneFunc_CompileR,       -> Is the red function compiled?
     MUIA_PlaneFunc_CompileG,       -> Is the green function compiled?
     MUIA_PlaneFunc_CompileB,       -> Is the blue function compiled?
*/     MUIA_PlaneFunc_Fail,           -> $RGB:How decoding went..
     MUIA_PlaneFunc_Gstr,           -> ..Its string
     MUIA_PlaneFunc_Height,         -> Height of the object
     MUIA_PlaneFunc_ImageFile,      -> FileName of the image to load
     MUIA_PlaneFunc_Left,
     MUIA_PlaneFunc_Loading,        -> TRUE/FALSE
     MUIA_PlaneFunc_LoadM,          -> Way of loading an image, concerning the size
     MUIA_PlaneFunc_Lock,           -> Allows to read/write lock the instance of the class
     MUIA_PlaneFunc_Name,           -> Name of the graph
     MUIA_PlaneFunc_Percent,        -> Percentage of current work done.
     MUIA_PlaneFunc_OutputR,        -> values: OUT_Integer,OUT_Float32 or OUT_Float64,...
     MUIA_PlaneFunc_OutputG,        -> ... or OUT_OldR,OUT_OldG,OUT_OldB,...
     MUIA_PlaneFunc_OutputB,        -> ... or Out_CopyR,OUT_CopyG (!)
     MUIA_PlaneFunc_ProjectID,      -> Used by ProjectList class, it is the ID of the object
     MUIA_PlaneFunc_ProjectNode,    -> Address of the node in the exec_list of opened_lst
     MUIA_PlaneFunc_Quiet,          -> Width/Height changes won't resize the window if non-zero
     MUIA_PlaneFunc_Rstr,           -> Its string
     MUIA_PlaneFunc_State,
     MUIA_PlaneFunc_Top,
     MUIA_PlaneFunc_Type,           -> Type of graph
     MUIA_PlaneFunc_Width           -> Width of the object

ENUM MUIM_PlaneFunc_Abort=$FCB90800,-> Aborts Rendering SubTask
     MUIM_PlaneFunc_Clear,          -> Clears bitmap
     MUIM_PlaneFunc_Close,          -> React after a click on the close button.
     MUIM_PlaneFunc_Lamps,          -> This updates the failure lamps of the functions.
     MUIM_PlaneFunc_LoadFunc,       -> Loads a function from disk
     MUIM_PlaneFunc_Render,         -> Launches/pauses the rendering subtask
     MUIM_PlaneFunc_SaveFunc,       -> Saves the function to disk
     MUIM_PlaneFunc_SavePic,        -> Saves the picture to disk, as an ILBM image
     MUIM_PlaneFunc_SetTaskPri,     -> Sets the priority of the subtask
     MUIM_PlaneFunc_Update          -> sent by the subtask, to update the picture display

CONST MUIV_PlaneFunc_Type_DTPic=1,
      MUIV_PlaneFunc_Type_Graph=2,

      MUIV_PlaneFunc_LoadM_Scale=1,
      MUIV_PlaneFunc_LoadM_CutTile=2,
      MUIV_PlaneFunc_LoadM_ChangeSize=3,

      MUIV_PlaneFunc_State_Idle=0,   ->free
      MUIV_PlaneFunc_State_Drawing=1,->busy
      MUIV_PlaneFunc_State_Paused=2, ->busy but paused
      MUIV_PlaneFunc_State_Frozen=3, ->free but being read
      MUIV_PlaneFunc_State_Loading=4,->loading picture

      MUIV_PlaneFunc_Lock_Write=-1, -> Want to lock it in write mode, so nobody else may touch the object
      MUIV_PlaneFunc_Lock_NoWrite=0,-> remove writelock
      MUIV_PlaneFunc_Lock_Read=1,   -> Want to lock it in read mode, only reading is now allowed. Nesting counter!
      MUIV_PlaneFunc_Lock_NoRead=0, -> remove one readlock

      MUIV_PlaneFunc_Abort_Finish=1,-> Aborted because rendering finished
      MUIV_PlaneFunc_Abort_Abort=2, -> Aborted because user asked
      MUIV_PlaneFunc_Abort_NoLoad=3 -> Aborted because picture could not be loaded

ENUM MUIM_ProjectList_DelItem=$FCB91800,-> Closes the current project if possible (i.e. if it isn't read-locked)
     MUIM_ProjectList_Exit,             -> This aborts all currently running projects and quits the application
     MUIM_ProjectList_Forward,          -> Forwards the method (no args!) to the current project
     MUIM_ProjectList_Memory,           -> Shows available memory in title bar.
     MUIM_ProjectList_NewItem,          -> Adds an item in the list
     MUIM_ProjectList_Notify,           -> Sends a notification information to the current project
     MUIM_ProjectList_Prefs,            -> writes a new value in a preference variable
     MUIM_ProjectList_Refresh,          -> Refreshes the user interface according to the select item
     MUIM_ProjectList_SetPri,           -> Set the priority of a task (see MUIV_~)
     MUIM_ProjectList_ShowMe            -> Sets the MUIA_Window_Open of the current project

ENUM MUIV_ProjectList_Notify_Name=1,    /*gadget that has been changed*/
     MUIV_ProjectList_Notify_Type,
     MUIV_ProjectList_Notify_ImageFile,
     MUIV_ProjectList_Notify_LoadM,
     MUIV_ProjectList_Notify_Red,
     MUIV_ProjectList_Notify_Green,
     MUIV_ProjectList_Notify_Blue,
/*     MUIV_ProjectList_Notify_CompileR,
     MUIV_ProjectList_Notify_CompileG,
     MUIV_ProjectList_Notify_CompileB,
*/     MUIV_ProjectList_Notify_OutputR,
     MUIV_ProjectList_Notify_OutputG,
     MUIV_ProjectList_Notify_OutputB,
     MUIV_ProjectList_Notify_Width,
     MUIV_ProjectList_Notify_Height

ENUM MUIV_ProjectList_SetPri_Main=0,
     MUIV_ProjectList_SetPri_Render,
     MUIV_ProjectList_SetPri_Curr

CONST MUIA_uSlider_Stringify=$FCB92000

ENUM MUIM_uSlider_Bigger=$FCB92800,
     MUIM_uSlider_Smaller

ENUM STC_STARTUP=-2,
    STC_SHUTDOWN,      /*messages to the subtask*/
    STC_START,
    STC_PAUSE,
    STC_RESTART,
    STC_CHANGEDONE
/***************************************************************
**            Custom PlaneFunc private Class                  **
****************************************************************
This class is responsible for rendering the functions. It uses a
subtask to avoid the main program to be freezed during rendering
***************************************************************/

OBJECT empty_data -> class(es) that doesn't use any data
    nothing
ENDOBJECT

OBJECT projectList_data
    exec_list:PTR TO lh -> list of the opened projects
/* Stuff for timer (title bar) */
/* Everything is copied from mui demo "inputhandler" Thanks for its authors ;-) */
    port:PTR TO mp
    req:PTR TO timerequest
    ihnode:mui_inputhandlernode_timer
ENDOBJECT

OBJECT uslider_data
    buffer:PTR TO CHAR
    stringify
ENDOBJECT

OBJECT args_compare -> MUIM_uSlider_Bigger/Smaller
    id
    than
ENDOBJECT

OBJECT args_abort -> Used by MUIM_PlaneFunc_Abort
    id
    reason
ENDOBJECT

OBJECT args_ctp -> MUIM_PlaneFunc_SetTaskPri
    id
    value
ENDOBJECT

OBJECT args_notify -> Used by MUIM_ProjectList_Notify
    id
    gadget -> MUIV_ProjectList_Notify_<something>
    value
ENDOBJECT

OBJECT args_showme -> Used by MUIM_ProjectList_ShowMe
    id
    value
ENDOBJECT

OBJECT args_forward -> Used by MUIM_ProjectList_Forward
    id
    method
ENDOBJECT

OBJECT args_prefs -> MUIM_ProjectList_Prefs
    id
    var:PTR TO LONG
    value
ENDOBJECT

OBJECT args_refresh -> Used by MUIM_ProjectList_Refresh
    id
    ostate -> TRUE if only the 'state' field must be refreshed.
ENDOBJECT

OBJECT args_setpri -> MUIM_ProjectList_SetPri
    id
    task -> MUIV_ProjectList_SetPri_*
    value
ENDOBJECT

PROC planeFunc_dispatcher(cl:PTR TO iclass,obj,msg:PTR TO msg)
DEF methodid
    methodid:=msg.methodid
    SELECT methodid
    CASE OM_NEW;        RETURN planeFunc_new(cl,obj,msg)
    CASE OM_DISPOSE;    RETURN planeFunc_dispose(cl,obj,msg)
    CASE OM_GET;        RETURN planeFunc_get(cl,obj,msg)   /*gets an attribute*/
    CASE OM_SET;        RETURN planeFunc_set(cl,obj,msg)   /*sets an attribute*/
    CASE MUIM_AskMinMax;RETURN planeFunc_askminmax(cl,obj,msg)
    CASE MUIM_Cleanup;  RETURN planeFunc_cleanup(cl,obj,msg)
    CASE MUIM_Draw;     RETURN planeFunc_draw(cl,obj,msg)  /*mui (or the subtask) asked to redraw*/
    CASE MUIM_HandleInput;RETURN planeFunc_handleinput(cl,obj,msg)
    CASE MUIM_Setup;    RETURN planeFunc_setup(cl,obj,msg)

    CASE MUIM_PlaneFunc_Abort;      RETURN planeFunc_abort(cl,obj,msg)      /*public methods...*/
    CASE MUIM_PlaneFunc_Clear;      RETURN planeFunc_clear(cl,obj/*,msg*/)
    CASE MUIM_PlaneFunc_Close;      RETURN planeFunc_close(cl,obj/*,msg*/)
    CASE MUIM_PlaneFunc_Lamps;      RETURN planeFunc_lamps(cl,obj/*,msg*/)
    CASE MUIM_PlaneFunc_LoadFunc;   RETURN planeFunc_loadfunc(cl,obj/*,msg*/)
    CASE MUIM_PlaneFunc_Render;     RETURN planeFunc_render(cl,obj/*,msg*/)
    CASE MUIM_PlaneFunc_SaveFunc;   RETURN planeFunc_savefunc(cl,obj/*,msg*/)
    CASE MUIM_PlaneFunc_SavePic;    RETURN planeFunc_savepic(/*cl,obj,msg*/)
    CASE MUIM_PlaneFunc_SetTaskPri; RETURN planeFunc_settaskpri(cl,obj,msg)
    CASE MUIM_PlaneFunc_Update;     RETURN planeFunc_update(cl,obj/*,msg*/)
    ENDSELECT
ENDPROC doSuperMethodA(cl,obj,msg)

PROC planeFunc_new(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO msg)
DEF data:PTR TO planeFunc_data
    IF (obj:=doSuperMethodA(cl,obj,msg))=NIL THEN RETURN 0
    data:=INST_DATA(cl,obj)

    data.self:=obj
    data.app:=app
    InitSemaphore(data.sema)
    NEW data.rp
    InitRastPort(data.rp)

    data.projectid:=lastid++
    data.failure:=$000
    data.rstr:=String(256)
    data.gstr:=String(256)
    data.bstr:=String(256)
    StrCopy(data.rstr,'x')
    StrCopy(data.gstr,'y')
    StrCopy(data.bstr,'(x+y)/2')
    data.outputr:=OUT_Integer
    data.outputg:=OUT_Integer
    data.outputb:=OUT_Integer
    NEW data.rfunc.create(data.outputr,data.rstr)
    NEW data.gfunc.create(data.outputg,data.gstr)
    NEW data.bfunc.create(data.outputb,data.bstr)
    data.imagefile:=String(256)

    idecode(data.rfunc,data.rstr,$100,data) -> Is this necessary?
    idecode(data.gfunc,data.gstr,$10,data)
    idecode(data.bfunc,data.bstr,$1,data)
    data.height:=256
    StrCopy(data.imagefile,cat.msg_Unnamed.getstr())
    data.loadm:=MUIV_PlaneFunc_LoadM_CutTile
    data.lock:=0
    data.name:=String(32)
    StrCopy(data.name,cat.msg_Unnamed.getstr())
    data.paused:=FALSE
    data.type:=MUIV_PlaneFunc_Type_Graph
    data.width:=256

    data.xmin:=10
    data.xmax:=240
    data.ymin:=30
    data.ymax:=80

    IF cybergfxbase
        data.rp.bitmap:= AllocBitMap(data.width,data.height,24,BMF_MINPLANES OR BMF_CLEAR,NIL)
    ELSE
        data.rp.bitmap:= Pi96AllocBitMap(data.width,data.height,24,BMF_MINPLANES OR BMF_CLEAR,NIL,RGBFB_A8R8G8B8)
    ENDIF
    IF (data.rp.bitmap)
        RETURN obj -> If everything got ok
    ENDIF
    coerceMethodA(cl,obj,OM_DISPOSE) -> In case of failure
ENDPROC
PROC planeFunc_askminmax(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO muip_askminmax)
DEF minmax:PTR TO mui_minmax,data:PTR TO planeFunc_data
    data:=INST_DATA(cl,obj)
    doSuperMethodA(cl,obj,msg)
    minmax:=msg.minmaxinfo
    minmax.maxwidth:=minmax.maxwidth+data.width
    minmax.maxheight:=minmax.maxheight+data.height
    minmax.defwidth:=minmax.defwidth+(data.width)
    minmax.defheight:=minmax.defheight+(data.height)
ENDPROC 0

PROC planeFunc_setup(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO msg)
    IF doSuperMethodA(cl,obj,msg)=NIL THEN RETURN FALSE
    Mui_RequestIDCMP(obj,IDCMP_MOUSEBUTTONS)
    ->Mui_RequestIDCMP(obj,IDCMP_RAWKEY)
ENDPROC MUI_TRUE

PROC planeFunc_cleanup(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO msg)
    Mui_RejectIDCMP(obj,IDCMP_MOUSEBUTTONS)
    ->Mui_RejectIDCMP(obj,IDCMP_RAWKEY)
ENDPROC doSuperMethodA(cl,obj,msg)

PROC planeFunc_handleinput(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO muip_handleinput)
#define _between(a,x,b) (((x)>=(a)) AND ((x)<=(b)))
DEF data:PTR TO planeFunc_data,col,colourstr[30]:STRING,x,y

    data:=INST_DATA(cl,obj)
    IF msg.imsg
        IF (msg.imsg.class=IDCMP_MOUSEBUTTONS) AND (msg.imsg.code=SELECTDOWN)
            IF (_between(_mleft(obj),msg.imsg.mousex,_mright(obj)) AND _between(_mtop(obj),msg.imsg.mousey,_bottom(obj)))
                x:=msg.imsg.mousex-_mleft(obj)+data.left
                y:=msg.imsg.mousey-_mtop(obj)+data.top
                /*get colour*/
                ObtainSemaphore(data.sema)
                IF cybergfxbase
                    e_mod(x,data.width)
                    col:=ReadRGBPixel(data.rp,e_mod(x,data.width),e_mod(y,data.height))
                ELSE
                    col:=Pi96ReadPixel(data.rp,e_mod(x,data.width),e_mod(y,data.height))
                ENDIF
                ReleaseSemaphore(data.sema)
                StringF(colourstr,'c(\d,\d,\d)=[\d,\d,\d]',data.projectid,x,y,Shr(col,16),Shr(col AND $FF00,8),col AND $FF)
                set(colour_txt,MUIA_Text_Contents,colourstr)
            ENDIF
/*        ELSEIF (msg.imsg.class=IDCMP_RAWKEY)
            IF (msg.imsg.code=96) OR (msg.imsg.code=97)
                data.shift:=TRUE
            ELSEIF (msg.imsg.code=224) OR (msg.imsg.code=225)
                data.shift:=FALSE
            ENDIF*/
        ENDIF
    ENDIF
ENDPROC doSuperMethodA(cl,obj,msg)

PROC planeFunc_clear(cl:PTR TO iclass,obj:PTR TO object/*,msg:PTR TO msg*/)
DEF data:PTR TO planeFunc_data
    data:=INST_DATA(cl,obj)
    ObtainSemaphore(data.sema)
    IF data.lock=0
        SetRast(data.rp,1)
        ReleaseSemaphore(data.sema)
        Mui_Redraw(obj,MADF_DRAWOBJECT)
    ELSE
        ReleaseSemaphore(data.sema)
        message(data.projectid,cat.msgm_WriteVsLock.getstr())
    ENDIF
ENDPROC

PROC planeFunc_close(cl:PTR TO iclass,obj:PTR TO object/*,msg:PTR TO msg*/)
DEF data:PTR TO planeFunc_data,kdata:PTR TO projectList_data
DEF state,node:PTR TO project_Node,count=0,exec_list:PTR TO lh
    data:=INST_DATA(cl,obj)
    IF wclose=0
        IF data.projectid=currid
            nnset(showme_cyc,MUIA_Cycle_Active,0) -> update cycle display.
        ENDIF
        set(data.projectnode.window,MUIA_Window_Open,FALSE)
    ELSEIF wclose=1
quiet:=TRUE
IF currid=data.projectid THEN currid:=-1
        kdata:=INST_DATA(cl_projectlist.mcc_class,opened_lst)
        doMethodA(obj,[MUIM_PlaneFunc_Abort,MUIV_PlaneFunc_Abort_Abort])
        get(obj,MUIA_PlaneFunc_State,{state})
        IF state = MUIV_PlaneFunc_State_Frozen
            message(data.projectid,cat.msgm_RemVsFreeze.getstr())
            quiet:=FALSE
            RETURN
        ENDIF

        exec_list:=kdata.exec_list
        node:=exec_list.head
        WHILE node.pid <> data.projectid
            count++
            node:=node.ln.succ
        ENDWHILE
        get(obj,MUIA_PlaneFunc_ProjectNode,{state})
        doMethodA(opened_lst,[MUIM_List_Remove,count])
        DisposeLink(node.item)
        set(node.window,MUIA_Window_Open,FALSE)
        doMethodA(app,[OM_REMMEMBER,node.window])
        Mui_DisposeObject(node.window)
        Remove(node)
        END node
quiet:=FALSE
        doMethodA(opened_lst,[MUIM_ProjectList_Refresh,0])
    ENDIF
ENDPROC

PROC planeFunc_dispose(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO msg)
DEF data:PTR TO planeFunc_data
    data:=INST_DATA(cl,obj)
    ObtainSemaphore(data.sema)
    data.app:=NIL
    ReleaseSemaphore(data.sema)
    IF data.subtask
        killsubtask(data.subtask)
        IF data.type = MUIV_PlaneFunc_Type_Graph
            free(data.rfunc)
            free(data.gfunc)
            free(data.bfunc)
        ENDIF
    ENDIF
    IF cybergfxbase
        IF (data.rp.bitmap) THEN FreeBitMap(data.rp.bitmap)
    ELSE
        IF (data.rp.bitmap) THEN Pi96FreeBitMap(data.rp.bitmap)
    ENDIF
    END data.rp
    DisposeLink(data.name)
    DisposeLink(data.rstr)
    DisposeLink(data.gstr)
    DisposeLink(data.bstr)
    END data.rfunc
    END data.gfunc
    END data.bfunc
    DisposeLink(data.imagefile)
ENDPROC doSuperMethodA(cl,obj,msg)
PROC planeFunc_lamps(cl:PTR TO iclass,obj:PTR TO object/*,msg:PTR TO msg*/)
DEF data:PTR TO planeFunc_data
    data:=INST_DATA(cl,obj)
    IF data.failure AND $1
        set(blue_fail,MUIA_Lamp_Color,MUIV_Lamp_Color_Error)
    ELSE
        set(blue_fail,MUIA_Lamp_Color,MUIV_Lamp_Color_Ok)
    ENDIF
    data:=INST_DATA(cl,obj)
    IF data.failure AND $10
        set(green_fail,MUIA_Lamp_Color,MUIV_Lamp_Color_Error)
    ELSE
        set(green_fail,MUIA_Lamp_Color,MUIV_Lamp_Color_Ok)
    ENDIF
    IF data.failure AND $100
        set(red_fail,MUIA_Lamp_Color,MUIV_Lamp_Color_Error)
    ELSE
        set(red_fail,MUIA_Lamp_Color,MUIV_Lamp_Color_Ok)
    ENDIF
ENDPROC

PROC planeFunc_draw(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO muip_draw)
DEF data:PTR TO planeFunc_data,utop,delta
/*
MovePixelArray(srcx,srcy,rp,dstx,dsty,wid,hei) -> (wid×hei) is the size of the rectangle to be moved!
ScrollRaster(rp,dltx,dlty,xmin,ymin,xmax,ymax) -> (rectangle) is the rectangle where scroll will occur!
*/
    doSuperMethodA(cl,obj,msg)
    IF nodraw THEN RETURN
    data:=INST_DATA(cl,obj)
    IF (msg.flags AND MADF_DRAWUPDATE)
        IF data.newtop <> 0/*scroll vertically*/
            ObtainSemaphore(data.sema)
            IF data.newtop < data.top  /*1)scroll upwards*/
                delta:=data.top-data.newtop
                IF delta < _mheight(obj)
                    IF pi96base
                        ScrollRaster(_rp(obj),0,-delta,_mleft(obj),_mtop(obj),_mleft(obj)+_mwidth(obj),_mtop(obj)+_mheight(obj))
                    ELSE
                        MovePixelArray(_mleft(obj),_mtop(obj),_rp(obj),_mleft(obj),_mtop(obj)+delta,_mwidth(obj),_mheight(obj)-delta)
                    ENDIF
                ELSE
                    delta:=_mheight(obj)
                ENDIF
                BltBitMapRastPort(data.rp.bitmap,data.left,data.newtop,_rp(obj),_mleft(obj),_mtop(obj),_mwidth(obj),delta,$c0)
            ELSE        /*2)data.newtop > data.top => scroll downwards*/
                delta:=data.newtop-data.top
                IF delta < _mheight(obj)
                    IF pi96base
                        ScrollRaster(_rp(obj),0,delta,_mleft(obj),_mtop(obj),_mleft(obj)+_mwidth(obj),_mtop(obj)+_mheight(obj))
                    ELSE
                        MovePixelArray(_mleft(obj),_mtop(obj)+delta,_rp(obj),_mleft(obj),_mtop(obj),_mwidth(obj),_mheight(obj)-delta)
                    ENDIF
                ELSE
                    delta:=_mheight(obj)
                ENDIF
                BltBitMapRastPort(data.rp.bitmap,data.left,data.top+_mheight(obj),_rp(obj),_mleft(obj),_mbottom(obj)-delta+1,_mwidth(obj),delta,$c0)
            ENDIF
            ReleaseSemaphore(data.sema)
            data.top:=data.newtop
            data.newtop:=0
        ENDIF
        IF data.newleft <> 0/*scroll horizontally*/
            ObtainSemaphore(data.sema)
            IF data.newleft < data.left  /*3)scroll leftwards*/
                delta:=data.left-data.newleft
                IF delta < _mwidth(obj)
                    IF pi96base
                        ScrollRaster(_rp(obj),-delta,0,_mleft(obj),_mtop(obj),_mleft(obj)+_mwidth(obj),_mtop(obj)+_mheight(obj))
                    ELSE
                        MovePixelArray(_mleft(obj),_mtop(obj),_rp(obj),_mleft(obj)+delta,_mtop(obj),_mwidth(obj)-delta,_mheight(obj))
                    ENDIF
                ELSE
                    delta:=_mwidth(obj)
                ENDIF
                BltBitMapRastPort(data.rp.bitmap,data.newleft,data.top,_rp(obj),_mleft(obj),_mtop(obj),delta,_mheight(obj),$c0)
            ELSE        /*4)data.newleft > data.left => scroll rightwards*/
                delta:=data.newleft-data.left
                IF delta < _mwidth(obj)
                    IF pi96base
                        ScrollRaster(_rp(obj),delta,0,_mleft(obj),_mtop(obj),_mleft(obj)+_mwidth(obj),_mtop(obj)+_mheight(obj))
                    ELSE
                        MovePixelArray(_mleft(obj)+delta,_mtop(obj),_rp(obj),_mleft(obj),_mtop(obj),_mwidth(obj)-delta,_mheight(obj))
                    ENDIF
                ELSE
                    delta :=_mwidth(obj)
                ENDIF
                BltBitMapRastPort(data.rp.bitmap,data.left+_mwidth(obj),data.top,_rp(obj),_mright(obj)-delta+1,_mtop(obj),delta,_mheight(obj),$c0)
            ENDIF
            ReleaseSemaphore(data.sema)
            data.left:=data.newleft
            data.newleft:=0
        ENDIF
        IF data.drawn < data.calculated
            utop:=data.drawn+1  /*5) Update display*/
            delta:=data.calculated-data.drawn            /*I don't think that the semaphore is required here, only the lines that are already been*/
            IF delta > 0                                /*calculated will be drawn and data.calculated is accessed only once.*/
                IF (utop < (data.top+_mheight(obj))) AND (utop+delta > data.top)
                    IF utop < data.top
                        delta:=delta-data.top+utop
                        utop:=data.top
                    ELSEIF (utop+delta) > (data.top+_mheight(obj))
                        delta:=data.top+_mheight(obj)-utop
                    ENDIF
                    BltBitMapRastPort(data.rp.bitmap,data.left,utop,_rp(obj),_mleft(obj),_mtop(obj)+utop-data.top,_mwidth(obj),delta,$c0)
                ENDIF
            ENDIF
            data.drawn:=data.calculated
        ENDIF
    ELSEIF (msg.flags AND MADF_DRAWOBJECT)
        /*the window may have been resized..*/
        ObtainSemaphore(data.sema)
        set(data.hscroll,MUIA_Prop_Visible,_mwidth(obj))
        set(data.vscroll,MUIA_Prop_Visible,_mheight(obj))
        get(data.vscroll,MUIA_Prop_First,{delta})
        data.top:=delta
        get(data.hscroll,MUIA_Prop_First,{delta})
        data.left:=delta
        BltBitMapRastPort(data.rp.bitmap,data.left,data.top,_rp(obj),_mleft(obj),_mtop(obj),_mwidth(obj),_mheight(obj),$c0)
        data.drawn:=data.calculated
        ReleaseSemaphore(data.sema)

        /*SetAPen(_rp(obj),_dri(obj).pens[TEXTPEN])
        data.xmin:=data.xmin-1
        data.xmax:=data.xmax+2
        data.ymin:=data.ymin-1
        data.ymax:=data.ymax+2
        IF data.ymin > data.top              /*top border*/
            Move(_rp(obj),_mleft(obj)+Max(0,data.xmin-data.left),         _mtop(obj)+data.ymin-data.top)
            Draw(_rp(obj),_mleft(obj)+Min(_mwidth(obj),data.xmax-data.left),_mtop(obj)+data.ymin-data.top)
        ENDIF
        IF data.xmax < data.left+_mwidth(obj)/*right border*/
            Move(_rp(obj),_mleft(obj)+data.xmax-data.left,                _mtop(obj)+Max(0,data.ymin-data.top))
            Draw(_rp(obj),_mleft(obj)+data.xmax-data.left,                _mtop(obj)+Min(_mheight(obj),data.ymax-data.top))
        ENDIF
        IF data.ymax < data.top+_mheight(obj)/*bottom border*/
            Move(_rp(obj),_mleft(obj)+Min(_mwidth(obj),data.xmax-data.left),_mtop(obj)+data.ymax-data.top)
            Draw(_rp(obj),_mleft(obj)+Max(0,data.xmin-data.left),         _mtop(obj)+data.ymax-data.top)
        ENDIF
        IF data.xmin > data.left             /*left border*/
            Move(_rp(obj),_mleft(obj)+data.xmin-data.left,                _mtop(obj)+Min(_mheight(obj),data.ymax-data.top))
            Draw(_rp(obj),_mleft(obj)+data.xmin-data.left,                _mtop(obj)+Max(0,data.ymin-data.top))
        ENDIF

        SetAPen(_rp(obj),_dri(obj).pens[SHINEPEN])
        data.xmin:=data.xmin-1
        data.xmax:=data.xmax-1
        data.ymin:=data.ymin-1
        data.ymax:=data.ymax-1
        IF data.ymin > data.top              /*top border*/
            Move(_rp(obj),_mleft(obj)+Max(0,data.xmin-data.left),         _mtop(obj)+data.ymin-data.top)
            Draw(_rp(obj),_mleft(obj)+Min(_mwidth(obj),data.xmax-data.left),_mtop(obj)+data.ymin-data.top)
        ENDIF
        IF data.xmax < data.left+_mwidth(obj)/*right border*/
            Move(_rp(obj),_mleft(obj)+data.xmax-data.left,                _mtop(obj)+Max(0,data.ymin-data.top))
            Draw(_rp(obj),_mleft(obj)+data.xmax-data.left,                _mtop(obj)+Min(_mheight(obj),data.ymax-data.top))
        ENDIF
        IF data.ymax < data.top+_mheight(obj)/*bottom border*/
            Move(_rp(obj),_mleft(obj)+Min(_mwidth(obj),data.xmax-data.left),_mtop(obj)+data.ymax-data.top)
            Draw(_rp(obj),_mleft(obj)+Max(0,data.xmin-data.left),         _mtop(obj)+data.ymax-data.top)
        ENDIF
        IF data.xmin > data.left            /*left border*/
            Move(_rp(obj),_mleft(obj)+data.xmin-data.left,                _mtop(obj)+Min(_mheight(obj),data.ymax-data.top))
            Draw(_rp(obj),_mleft(obj)+data.xmin-data.left,                _mtop(obj)+Max(0,data.ymin-data.top))
        ENDIF
        data.xmin:=data.xmin+2
        data.xmax:=data.xmax-1
        data.ymin:=data.ymin+2
        data.ymax:=data.ymax-1  */
    ENDIF
ENDPROC

/*not yet finished: ability to select a destination area*/

/*PROC drawhoriz(x,y,xx,obj:PTR TO object,data:PTR TO planeFunc_data)
    IF data.ymin > data.top              /*top border*/
        Move(_rp(obj),_mleft(obj)+Max(0,data.xmin-data.left),         _mtop(obj)+data.ymin-data.top)
        Draw(_rp(obj),_mleft(obj)+Min(_mwidth(obj),data.xmax-data.left),_mtop(obj)+data.ymin-data.top)
    ENDIF

    Move(_rp(obj),x,y)
    Draw(_rp(obj),xx,y)
ENDPROC*/

PROC planeFunc_get(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO opget)
DEF data:PTR TO planeFunc_data,storage,attrid

    data:=INST_DATA(cl,obj)
    attrid:=msg.attrid
    storage:=msg.storage
    ObtainSemaphore(data.sema)
    SELECT attrid
    CASE MUIA_PlaneFunc_Bstr
        ^storage:=data.bstr
/*    CASE MUIA_CompileR
        ^storage:=data.compiler
    CASE MUIA_CompileG
        ^storage:=data.compileg
    CASE MUIA_CompileB
        ^storage:=data.compileb
*/    CASE MUIA_PlaneFunc_Gstr
        ^storage:=data.gstr
    CASE MUIA_PlaneFunc_Height
        ^storage:=data.height
    CASE MUIA_PlaneFunc_ImageFile
        ^storage:=data.imagefile
    CASE MUIA_PlaneFunc_Loading
        ^storage:=data.loading
    CASE MUIA_PlaneFunc_LoadM
        ^storage:=data.loadm
    CASE MUIA_PlaneFunc_Lock
        ^storage:=data.lock
    CASE MUIA_PlaneFunc_Name
        ^storage:=data.name
    CASE MUIA_PlaneFunc_Percent
        IF data.lock=MUIV_PlaneFunc_Lock_Write
            ^storage:=data.calculated*100/data.height
        ELSE
            ^storage:=0
        ENDIF
    CASE MUIA_PlaneFunc_OutputR
        ^storage:=data.outputr
    CASE MUIA_PlaneFunc_OutputG
        ^storage:=data.outputg
    CASE MUIA_PlaneFunc_OutputB
        ^storage:=data.outputb
    CASE MUIA_PlaneFunc_ProjectID
        ^storage:=data.projectid
    CASE MUIA_PlaneFunc_ProjectNode
        ^storage:=data.projectnode
    CASE MUIA_PlaneFunc_Quiet
        ^storage:=data.quiet
    CASE MUIA_PlaneFunc_Rstr
        ^storage:=data.rstr
    CASE MUIA_PlaneFunc_State
        IF data.lock = MUIV_PlaneFunc_Lock_Write
            IF data.paused
                ^storage:=MUIV_PlaneFunc_State_Paused
            ELSEIF data.loading
                ^storage:=MUIV_PlaneFunc_State_Loading
            ELSE
                ^storage:=MUIV_PlaneFunc_State_Drawing
            ENDIF
        ELSE
            IF data.lock = 0
                ^storage:=MUIV_PlaneFunc_State_Idle
            ELSE
                ^storage:=MUIV_PlaneFunc_State_Frozen
            ENDIF
        ENDIF
    CASE MUIA_PlaneFunc_Type
        ^storage:=data.type
    CASE MUIA_PlaneFunc_Width
        ^storage:=data.width
    DEFAULT
        ReleaseSemaphore(data.sema)
        RETURN doSuperMethodA(cl,obj,msg)
    ENDSELECT
    ReleaseSemaphore(data.sema)
ENDPROC MUI_TRUE

PROC planeFunc_set(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO opset)
DEF data:PTR TO planeFunc_data,
    tags:PTR TO tagitem,
    tag:PTR TO tagitem,
    attrid
DEF window,group

    data:=INST_DATA(cl,obj)
    tags:=msg.attrlist
    ObtainSemaphore(data.sema)
    WHILE tag:=NextTagItem({tags})
        attrid:=tag.tag
        SELECT attrid
        CASE MUIA_PlaneFunc_ImageFile
            StrCopy(data.imagefile,tag.data)
        CASE MUIA_PlaneFunc_Loading
            data.loading:=tag.data
            IF data.projectid=currid THEN
                setlamp(obj)
        CASE MUIA_PlaneFunc_Left
            data.newleft:=tag.data
            Mui_Redraw(obj,MADF_DRAWUPDATE)
        CASE MUIA_PlaneFunc_ProjectNode
            data.projectnode:=tag.data
        CASE MUIA_PlaneFunc_Top
            data.newtop:=tag.data
            Mui_Redraw(obj,MADF_DRAWUPDATE)
        CASE MUIA_PlaneFunc_Lock
            IF data.lock=MUIV_PlaneFunc_Lock_Write-> If the object is being written, the only tag allowed is NoWrite
                IF tag.data=MUIV_PlaneFunc_Lock_NoWrite
                    data.lock:=0
                ENDIF
            ELSEIF data.lock=0            -> If the object is free, it can either be read or write - locked
                data.lock:=tag.data
            ELSE                         -> If the object is read locked, it can be read unlocked or read locked again.
                IF tag.data=MUIV_PlaneFunc_Lock_NoRead
                    data.lock:=data.lock-1
                ELSEIF tag.data=MUIV_PlaneFunc_Lock_Read
                    data.lock:=data.lock+1
                ENDIF
            ENDIF
            doMethodA(opened_lst,[MUIM_ProjectList_Refresh,data.projectid+2]) -> Refresh the "state" lamp.
        CASE MUIA_PlaneFunc_Name
            StrCopy(data.name,tag.data)
            get(obj,MUIA_WindowObject,{window})
            set(window,MUIA_Window_Title,data.name)
        CASE MUIA_PlaneFunc_Quiet
            data.quiet:=tag.data
            IF data.quiet=FALSE
                get(obj,MUIA_Parent,{group})
                doMethodA(group,[MUIM_Group_InitChange])
                doMethodA(group,[MUIM_Group_ExitChange])
                IF cybergfxbase
                    IF (data.rp.bitmap) THEN FreeBitMap(data.rp.bitmap)
                    data.rp.bitmap:= AllocBitMap(data.width,data.height,24,BMF_MINPLANES OR BMF_CLEAR,friend)
                ELSE
                    IF (data.rp.bitmap) THEN Pi96FreeBitMap(data.rp.bitmap)
                    data.rp.bitmap:= Pi96AllocBitMap(data.width,data.height,24,BMF_MINPLANES OR BMF_CLEAR,NIL,RGBFB_A8R8G8B8)
                ENDIF
                IF data.projectid=currid
                    nnset(width_str,MUIA_String_Integer,data.width)
                    nnset(height_str,MUIA_String_Integer,data.height)
                ENDIF
                IF data.subtask THEN
                    sendsubtaskmsg(data.subtask,STC_CHANGEDONE,NIL)
            ENDIF
        DEFAULT
            IF (data.lock <> MUIV_PlaneFunc_Lock_Write) OR (data.quiet=-2)
                SELECT attrid
                CASE MUIA_PlaneFunc_Bstr
                    StrCopy(data.bstr,tag.data)
                    LowerStr(data.bstr)
                    idecode(data.bfunc,tag.data,$1,data)
/*                CASE MUIA_PlaneFunc_CompileR -> No need to react, as both the code and the description of function are saved.
                    data.compiler:=tag.data
                CASE MUIA_PlaneFunc_CompileG
                    data.compiler:=tag.data
                CASE MUIA_PlaneFunc_CompileB
                    data.compiler:=tag.data
*/                CASE MUIA_PlaneFunc_Gstr
                    StrCopy(data.gstr,tag.data)
                    idecode(data.gfunc,tag.data,$10,data)
                CASE MUIA_PlaneFunc_LoadM
                    data.loadm:=tag.data
                CASE MUIA_PlaneFunc_OutputR
                    data.outputr:=tag.data
                    IF tag.data <= OUT_Float64
                        idecode(data.rfunc,data.rstr,$100,data,data.outputr)
                    ENDIF
                CASE MUIA_PlaneFunc_OutputG
                    data.outputg:=tag.data
                    IF tag.data <= OUT_Float64
                        idecode(data.gfunc,data.gstr,$10,data,data.outputg)
                    ENDIF
                CASE MUIA_PlaneFunc_OutputB
                    data.outputb:=tag.data
                    IF tag.data <= OUT_Float64
                        idecode(data.bfunc,data.bstr,$1,data,data.outputb)
                    ENDIF
                CASE MUIA_PlaneFunc_Rstr
                    StrCopy(data.rstr,tag.data)
                    LowerStr(data.rstr)
                    idecode(data.rfunc,tag.data,$100,data)
                CASE MUIA_PlaneFunc_Type
                    data.type:=tag.data
                DEFAULT
                    IF (data.lock <> MUIV_PlaneFunc_Lock_NoRead) AND (data.quiet<>-2)
                        message(data.projectid,cat.msgm_AttrVsLock.getstr())
                    ELSEIF attrid = MUIA_PlaneFunc_Width
                        data.width:=tag.data
                        set(data.hscroll,MUIA_Prop_Entries,tag.data)
                        IF data.quiet=FALSE
                            get(obj,MUIA_Parent,{group})
                            doMethodA(group,[MUIM_Group_InitChange])
                            doMethodA(group,[MUIM_Group_ExitChange])
                            IF cybergfxbase
                                IF (data.rp.bitmap) THEN FreeBitMap(data.rp.bitmap)
                                data.rp.bitmap:= AllocBitMap(data.width,data.height,24,BMF_MINPLANES OR BMF_CLEAR,friend)
                            ELSE
                                IF (data.rp.bitmap) THEN Pi96FreeBitMap(data.rp.bitmap)
                                data.rp.bitmap:= Pi96AllocBitMap(data.width,data.height,24,BMF_MINPLANES OR BMF_CLEAR,NIL,RGBFB_A8R8G8B8)
                            ENDIF
                        ENDIF
                    ELSEIF attrid = MUIA_PlaneFunc_Height
                        data.height:=tag.data
                        set(data.vscroll,MUIA_Prop_Entries,tag.data)
                        IF data.quiet=FALSE
                            get(obj,MUIA_Parent,{group})
                            doMethodA(group,[MUIM_Group_InitChange])
                            doMethodA(group,[MUIM_Group_ExitChange])
                            IF cybergfxbase
                            IF (data.rp.bitmap) THEN FreeBitMap(data.rp.bitmap)
                                data.rp.bitmap:= AllocBitMap(data.width,data.height,24,BMF_MINPLANES OR BMF_CLEAR,friend)
                            ELSE
                                IF (data.rp.bitmap) THEN Pi96FreeBitMap(data.rp.bitmap)
                                data.rp.bitmap:= Pi96AllocBitMap(data.width,data.height,24,BMF_MINPLANES OR BMF_CLEAR,NIL,RGBFB_A8R8G8B8)
                            ENDIF
                        ENDIF
                    ENDIF
                ENDSELECT
            ELSE
                message(data.projectid,cat.msgm_AttrVsLock.getstr())
            ENDIF
        ENDSELECT
    ENDWHILE
    ReleaseSemaphore(data.sema)
ENDPROC doSuperMethodA(cl,obj,msg)

/*idecode, extends f.create(). Ok, I know I should maybe have written a method, but it's easier like this :-¦*/
PROC idecode(f:PTR TO expression,s:PTR TO CHAR,l,data:PTR TO planeFunc_data,in=-1)
DEF out/*:PTR TO outinfo,err*/,i:PTR TO CHAR

    i:=String(StrLen(s)) -> New string so that lowerstr doesn't change text in field.
    StrCopy(i,s)
    LowerStr(i)

    IF in = -1 THEN
        in:=f.precision

    IF in = OUT_Float64
        message(data.projectid,cat.msgm_Nof64.getstr())
        DisposeLink(i)
        RETURN
    ENDIF

    END f

    NEW f.create(in,i)
    out:=f.message
    IF out AND FAILURE
        data.failure:=data.failure OR l
        /*err:=out.error
        SELECT err
        CASE ERR_NoParse
            messagefmt(data.projectid,cat.msgm_NoParse.getstr(),out.quote)
        CASE ERR_NoFunc
            messagefmt(data.projectid,cat.msgm_NoFunc.getstr(),out.quote)
        CASE ERR_NoChar
            messagefmt(data.projectid,cat.msgm_NoChar.getstr(),out.quote)
        DEFAULT
            message(data.projectid,cat.msgm_Failure.getstr())
        ENDSELECT
        END out*/
    ELSE -> Can't currently have both failure and warning. It will come :-)
        data.failure:=data.failure AND Not(l)
        IF out AND WARN_NoSupport THEN
            message(data.projectid,cat.msgm_WarnNoSupport.getstr())
        IF out AND WARN_EPi THEN
            message(data.projectid,cat.msgm_WarnEPi.getstr())
    ENDIF
    doMethodA(data.self,[MUIM_PlaneFunc_Lamps])
    DisposeLink(i)
ENDPROC

PROC planeFunc_abort(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO args_abort)
DEF data:PTR TO planeFunc_data,ds1:PTR TO datestamp,ds2:datestamp,qe[30]:STRING,u
    data:=INST_DATA(cl,obj)
    IF data.subtask
        killsubtask(data.subtask)
        data.subtask:=NIL
        set(obj,MUIA_PlaneFunc_Lock,MUIV_PlaneFunc_Lock_NoWrite)
        IF data.type = MUIV_PlaneFunc_Type_Graph
            free(data.rfunc)
            free(data.gfunc)
            free(data.bfunc)
        ENDIF
        u:=msg.reason
        SELECT u
        CASE MUIV_PlaneFunc_Abort_Finish
            ds1:=data.ds
            DateStamp(ds2)
            u:=(ds2.minute-ds1.minute)*TICKS_PER_MINUTE+ds2.tick-ds1.tick -> number of ticks
            StringF(qe,'\s  \z\d[2]:\z\d[2].\z\d[2].',cat.msgm_Done.getstr(),u/TICKS_PER_MINUTE,Mod(u,TICKS_PER_MINUTE)/TICKS_PER_SECOND,Mod(u,TICKS_PER_SECOND)*100/TICKS_PER_SECOND)
            message(data.projectid,qe)
        CASE MUIV_PlaneFunc_Abort_Abort
            message(data.projectid,cat.msgm_Abort.getstr())
        CASE MUIV_PlaneFunc_Abort_NoLoad
            message(data.projectid,cat.msgm_NoLoad.getstr())
        ENDSELECT

        data.drawn:=0
        data.calculated:=0
        data.paused:=FALSE
    ENDIF
ENDPROC

PROC planeFunc_loadfunc(cl:PTR TO iclass,obj:PTR TO object/*,msg:PTR TO msg*/)
DEF u,filereq:PTR TO filerequester,s[200]:STRING,handler,data:PTR TO planeFunc_data,
    eq,var[10]:STRING,value:PTR TO CHAR

    data:=INST_DATA(cl,obj)
    get(settings_win,MUIA_Window_Window,{u})
    filereq:=AllocAslRequest(ASL_FILEREQUEST,
                            [ASL_HAIL,      cat.msgr_Loadf_T.getstr(),
                             ASL_OKTEXT,    cat.msgr_Loadf_Ok.getstr(),
                             ASL_DIR,       'progdir:Functions/',
                             ASL_WINDOW,    u,
                             NIL])
    IF filereq=NIL
        Mui_RequestA(app,settings_win,0,cat.msgr_Loadf_T.getstr(),NIL,cat.msgr_NoAslReq.getstr(),NIL)
    ELSE
        IF AslRequest(filereq,NIL)
            StrCopy(s,filereq.drawer)
            AddPart(s,filereq.file,StrMax(s))
            SetStr(s,StrLen(s))
        ENDIF
        FreeAslRequest(filereq)
    ENDIF
    IF s[] = NIL THEN RETURN
    handler:=Open(s,OLDFILE)
    Fgets(handler,s,StrMax(s)-1)
    IF s[]=NIL
        Close(handler)
        message(data.projectid,cat.msgm_EmptyFile.getstr())
        RETURN
    ENDIF
    SetStr(s,StrLen(s)-1)
    IF Not(StrCmp(s,'picFX function-file; type1'))
        Close(handler)
        message(data.projectid,cat.msgm_BadFile.getstr())
        RETURN
    ENDIF
    set(obj,MUIA_PlaneFunc_Quiet,MUI_TRUE)
    WHILE Fgets(handler,s,StrMax(s)-1)/* semaphore will be obtained in the SET method */
        SetStr(s,StrLen(s)-1)
        eq:=InStr(s,'=')
        StrCopy(var,s,eq)
        value:=s+eq+1
        IF StrCmp(var,'bstr')
            set(obj,MUIA_PlaneFunc_Bstr,value)
        ELSEIF StrCmp(var,'gstr')
            set(obj,MUIA_PlaneFunc_Gstr,value)
        ELSEIF StrCmp(var,'height')
            set(obj,MUIA_PlaneFunc_Height,Val(value))
        ELSEIF StrCmp(var,'rstr')
            set(obj,MUIA_PlaneFunc_Rstr,value)
        ELSEIF StrCmp(var,'width')
            set(obj,MUIA_PlaneFunc_Width,Val(value))
        ELSEIF StrCmp(var,'precision') -> Obsolete tag!
            set(obj,MUIA_PlaneFunc_OutputR,Val(value))
            set(obj,MUIA_PlaneFunc_OutputG,Val(value))
            set(obj,MUIA_PlaneFunc_OutputB,Val(value))
            message(data.projectid,'Warning, obsolete tag "precision" used!')
        ELSEIF StrCmp(var,'outputr')
            set(obj,MUIA_PlaneFunc_OutputR,Val(value))
        ELSEIF StrCmp(var,'outputg')
            set(obj,MUIA_PlaneFunc_OutputG,Val(value))
        ELSEIF StrCmp(var,'outputb')
            set(obj,MUIA_PlaneFunc_OutputB,Val(value))
        ELSE
            StringF(s,cat.msgm_UnknownVar.getstr(),var)
            message(data.projectid,s)
        ENDIF
    ENDWHILE
    Close(handler)
    set(obj,MUIA_PlaneFunc_Quiet,FALSE)
    doMethodA(opened_lst,[MUIM_ProjectList_Refresh,0])
ENDPROC

PROC planeFunc_render(cl:PTR TO iclass,obj:PTR TO object/*,msg*/)
DEF data:PTR TO planeFunc_data,state
    data:=INST_DATA(cl,obj)
    get(obj,MUIA_PlaneFunc_State,{state})
    SELECT state
    CASE MUIV_PlaneFunc_State_Idle
        IF data.type = MUIV_PlaneFunc_Type_DTPic
            set(obj,MUIA_PlaneFunc_Loading,TRUE)
            set(obj,MUIA_PlaneFunc_Lock,MUIV_PlaneFunc_Lock_Write)

            data.rupd:=rupd

            /* the following call starts the sub task */
            data.subtask:= spawnsubtask('PicFX-Render-Task',{loadpicture},data)
            IF (data.subtask)
                SetTaskPri(data.subtask.st_Task,cp)
                sendsubtaskmsg(data.subtask,STC_START,NIL)
            ENDIF
        ELSE
            set(obj,MUIA_PlaneFunc_Lock,MUIV_PlaneFunc_Lock_Write)
            IF freeze(data.rfunc) = 0 -> This will freeze used projects; if zero, it failed.
                message(data.projectid,cat.msgm_NoAlloc.getstr())
                set(obj,MUIA_PlaneFunc_Lock,MUIV_PlaneFunc_Lock_NoWrite)
                RETURN
            ENDIF
            IF freeze(data.gfunc) = 0
                message(data.projectid,cat.msgm_NoAlloc.getstr())
                set(obj,MUIA_PlaneFunc_Lock,MUIV_PlaneFunc_Lock_NoWrite)
                RETURN
            ENDIF
            IF freeze(data.bfunc) = 0
                message(data.projectid,cat.msgm_NoAlloc.getstr())
                set(obj,MUIA_PlaneFunc_Lock,MUIV_PlaneFunc_Lock_NoWrite)
                RETURN
            ENDIF
            /*will we have to save previous pixel information?*/
            data.savepixel:=(data.outputr>=OUT_OldR) AND (data.outputr<=OUT_OldB)
            data.savepixel:=data.savepixel OR ((data.outputg>=OUT_OldR) AND (data.outputg<=OUT_OldB))
            data.savepixel:=data.savepixel OR ((data.outputb>=OUT_OldR) AND (data.outputb<=OUT_OldB))

            data.rupd:=rupd

            data.subtask:= spawnsubtask('PicFX-Render-Task',{renderfunc},data)
            IF (data.subtask)
                SetTaskPri(data.subtask.st_Task,cp)
                sendsubtaskmsg(data.subtask,STC_START,NIL)
            ENDIF
        ENDIF
    CASE MUIV_PlaneFunc_State_Drawing
        sendsubtaskmsg(data.subtask,STC_PAUSE,NIL)
        data.paused:=TRUE
        doMethodA(opened_lst,[MUIM_ProjectList_Refresh,data.projectid+2])
    CASE MUIV_PlaneFunc_State_Paused
        data.paused:=FALSE
        sendsubtaskmsg(data.subtask,STC_RESTART,NIL)
        doMethodA(opened_lst,[MUIM_ProjectList_Refresh,data.projectid+2])
    CASE MUIV_PlaneFunc_State_Frozen
        message(data.projectid,cat.msgm_WriteVsFreeze.getstr())
    ENDSELECT
ENDPROC

PROC planeFunc_savefunc(cl:PTR TO iclass,obj:PTR TO object/*,msg:PTR TO msg*/)
DEF u,filereq:PTR TO filerequester,s[200]:STRING,newhandler,oldhandler,data:PTR TO planeFunc_data
    data:=INST_DATA(cl,obj)
    get(settings_win,MUIA_Window_Window,{u})
    filereq:=AllocAslRequest(ASL_FILEREQUEST,
                            [ASL_HAIL,      cat.msgr_Savef_T.getstr(),
                             ASL_OKTEXT,    cat.msgr_Savef_Ok.getstr(),
                             ASL_DIR,       'progdir:Functions/',
                             ASL_WINDOW,    u,
                             ASL_FUNCFLAGS, FILF_SAVE,
                             NIL])
    IF filereq=NIL
        Mui_RequestA(app,settings_win,0,cat.msgr_Savef_T.getstr(),NIL,cat.msgr_NoAslReq.getstr(),NIL)
    ELSE
        IF AslRequest(filereq,NIL)
            StrCopy(s,filereq.drawer)
            AddPart(s,filereq.file,StrMax(s))
            SetStr(s,StrLen(s))
        ENDIF
        FreeAslRequest(filereq)
    ENDIF
    IF s[] = NIL THEN RETURN
    newhandler:=Open(s,NEWFILE)
    oldhandler:=SetStdOut(newhandler)
    WriteF('picFX function-file; type1\n')
    ObtainSemaphore(data.sema)
    WriteF('bstr=\s\n',data.bstr)
    WriteF('gstr=\s\n',data.gstr)
    WriteF('height=\d\n',data.height)
    WriteF('rstr=\s\n',data.rstr)
    WriteF('outputr=\d\n',data.outputr)
    WriteF('outputg=\d\n',data.outputg)
    WriteF('outputb=\d\n',data.outputb)
    WriteF('width=\d\n',data.width)
    ReleaseSemaphore(data.sema)
    Close(newhandler)
    SetStdOut(oldhandler)
ENDPROC

PROC planeFunc_savepic(/*cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO args_file*/)
ENDPROC

PROC planeFunc_settaskpri(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO args_ctp)
DEF data:PTR TO planeFunc_data
    data:=INST_DATA(cl,obj)
    ObtainSemaphore(data.sema)
    IF data.subtask THEN
        SetTaskPri(data.subtask.st_Task,msg.value)
    ReleaseSemaphore(data.sema)
ENDPROC
PROC planeFunc_update(cl:PTR TO iclass,obj:PTR TO object/*,msg:PTR TO msg*/)
DEF data:PTR TO planeFunc_data
    data:=INST_DATA(cl,obj)
    ObtainSemaphore(data.sema)
    data.app:=NIL
    ReleaseSemaphore(data.sema)
    Mui_Redraw(obj,MADF_DRAWUPDATE)
    IF data.projectid = currid
->        ObtainSemaphore(data.sema)
        set(state_gau,MUIA_Gauge_Current,data.calculated*100/data.height)
->        ReleaseSemaphore(data.sema)
    ENDIF
    ObtainSemaphore(data.sema)
    data.app:=app
    ReleaseSemaphore(data.sema)
ENDPROC

/***************************************************************
** custom ProjectList private subclass of List class          **
****************************************************************
**                                                            **
** Interaction between the application and the opened projects**
***************************************************************/

CONST PROJECTNODE_ID=100

PROC projectList_dispatcher(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO msg)
DEF methodid
    methodid:=msg.methodid
    SELECT methodid
    CASE OM_NEW                   ; RETURN projectList_new(cl,obj,msg)
    CASE OM_DISPOSE               ; RETURN projectList_dispose(cl,obj,msg)
    CASE MUIM_Setup               ; RETURN projectList_setup(cl,obj,msg)
    CASE MUIM_Cleanup             ; RETURN projectList_cleanup(cl,obj,msg)
    CASE MUIM_ProjectList_DelItem ; RETURN projectList_delitem(cl,obj/*,msg*/)
    CASE MUIM_ProjectList_Exit    ; RETURN projectList_exit(cl,obj/*,msg*/)
    CASE MUIM_ProjectList_Forward ; RETURN projectList_forward(cl,obj,msg)
    CASE MUIM_ProjectList_Memory  ; RETURN projectList_memory(cl,obj/*,msg*/)
    CASE MUIM_ProjectList_NewItem ; RETURN projectList_newitem(cl,obj/*,msg*/)
    CASE MUIM_ProjectList_Notify  ; RETURN projectList_notify(cl,obj,msg)
    CASE MUIM_ProjectList_Prefs   ; RETURN projectList_prefs(/*cl,obj,*/msg)
    CASE MUIM_ProjectList_Refresh ; RETURN projectList_refresh(cl,obj,msg)
    CASE MUIM_ProjectList_SetPri  ; RETURN projectList_setpri(cl,obj,msg)
    CASE MUIM_ProjectList_ShowMe  ; RETURN projectList_showme(cl,obj,msg)
    ENDSELECT
ENDPROC doSuperMethodA(cl,obj,msg)

PROC getcurrent(data:PTR TO projectList_data,obj:PTR TO object)
DEF active
DEF exec_list:PTR TO lh,worknode:PTR TO project_Node,z,list:PTR TO mlh,cs:PTR TO object
    get(obj,MUIA_List_Active,{active})
    IF active=MUIV_List_Active_Off THEN RETURN 0
    exec_list:=data.exec_list
    worknode:=exec_list.head
              /* I should add here a check that the bound of the list is never reached!*/
    IF active > 0
        FOR z:=1 TO active
            worknode:=worknode.ln.succ
        ENDFOR
    ENDIF
    get(worknode.window,MUIA_Window_RootObject,{z})

    get(z,MUIA_Group_ChildList,{list})
    cs:=list.head
ENDPROC NextObject({cs}),worknode.window

/*Care! getp() asks the ProjectID and not line number!!!*/

PROC getp(data:PTR TO projectList_data,pid)
DEF exec_list:PTR TO lh,worknode:PTR TO project_Node,z,list:PTR TO mlh,cs:PTR TO object

    exec_list:=data.exec_list
    worknode:=exec_list.head
              /* I should add here a check that the bound of the list is never reached!*/
    WHILE mcomp(worknode,pid)
        worknode:=worknode.ln.succ
    ENDWHILE
    IF worknode.ln.succ = 0
        z:=String(80)
        StringF(z,cat.msgm_NoID.getstr(),pid)
        message(-1,z)
        DisposeLink(z)
        RETURN 0,0
    ENDIF
    get(worknode.window,MUIA_Window_RootObject,{z})

    get(z,MUIA_Group_ChildList,{list})
    cs:=list.head
ENDPROC NextObject({cs}),worknode.window

PROC mcomp(node:PTR TO project_Node,id)
    IF node.ln.succ=0 THEN RETURN FALSE -> This silly proc to avoid a atupid enforcer hit :-s
ENDPROC (node.pid <> id)

PROC getdata(data:PTR TO projectList_data,pid)
DEF gad
    gad:=getp(data,pid)
    IF gad = 0 THEN RETURN 0
ENDPROC INST_DATA(cl_planefunc.mcc_class,gad)

PROC projectList_new(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO msg)
DEF exec_list:PTR TO lh,data:PTR TO projectList_data
DEF port,req
    IF (obj:=doSuperMethodA(cl,obj,msg)) = FALSE THEN RETURN FALSE
    data:=INST_DATA(cl,obj)
    NEW exec_list
    newList(exec_list) -> Create an Exec list for the opened projects
    data.exec_list:=exec_list -> save the list in the instance data

    screentitle:=String(150)

    port := CreateMsgPort() -> Check here that port exists
    data.port:=port
    req := CreateIORequest(data.port,SIZEOF timerequest) -> Check here that req exists
    data.req:=req
    OpenDevice(TIMERNAME,UNIT_VBLANK,data.req,0) -> NIL if it went all right, check it
    data.ihnode.ihn_millis  := 5000 -> Update memory display every five seconds
    data.ihnode.ihn_object  := obj
    data.ihnode.ihn_method  := MUIM_ProjectList_Memory
    data.ihnode.ihn_flags   := MUIIHNF_TIMER
ENDPROC obj

PROC projectList_setup(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO muip_setup)
DEF id,data:PTR TO projectList_data
    IF doSuperMethodA(cl,obj,msg) = FALSE THEN RETURN FALSE
    data:=INST_DATA(cl,obj)
    IF (msg.renderinfo.mri_flags AND MUIMRI_TRUECOLOR) = 0
        message(-1,cat.msgm_NoCgx.getstr())
        message(-1,cat.msgm_NoDraw.getstr())
        nodraw:=MUI_TRUE
    ELSEIF nodraw=MUI_TRUE
        nodraw:=FALSE
        message(-1,cat.msgm_CgxOk.getstr())
        message(-1,cat.msgm_DrawOk.getstr())
    ENDIF
    id:=GetVPModeID(msg.renderinfo.mri_screen.viewport) AND $FFF00000
        /*This is only due to my observation, that first three
         quartets "seem" to be constant for a given monitor*/

    SELECT id
    CASE $40d00000 /*cgx*/  /* what about IsCyberModeID() ? */
        IF pi96base
            CloseLibrary(pi96base)
            pi96base:=0
        ENDIF
        IF Not(cybergfxbase) THEN cybergfxbase:=OpenLibrary('cybergraphics.library',0)
        IF cybergfxbase=0
            messagefmt(-1,cat.msg_Nolib.getstr(), 'cybergraphics.library')
        ELSE
            messagefmt(-1,cat.msgm_useDriver.getstr(),'Cybergraph''x')
        ENDIF
    CASE $50000000 /*p96*/
        IF cybergfxbase
            CloseLibrary(cybergfxbase)
            cybergfxbase:=0
        ENDIF
        IF Not(pi96base) THEN pi96base:=OpenLibrary('Picasso96API.library',0)
        IF pi96base=0
            messagefmt(-1,cat.msg_Nolib.getstr(),'Picasso96API.library')
        ELSE
            messagefmt(-1,cat.msgm_useDriver.getstr(),'Picasso96')
        ENDIF
    CASE $00000000 /*aga*/
        IF cybergfxbase
            CloseLibrary(cybergfxbase)
            cybergfxbase:=0
        ENDIF
        IF pi96base
            CloseLibrary(pi96base)
            pi96base:=0
        ENDIF
        message(-1,cat.msgm_AgaSorry1.getstr())
        message(-1,cat.msgm_AgaSorry2.getstr())
    DEFAULT
        message(-1,cat.msgm_UnknownMode.getstr())
        IF cybergfxbase
            CloseLibrary(cybergfxbase)
            cybergfxbase:=0
        ENDIF
        IF pi96base
            CloseLibrary(pi96base)
            pi96base:=0
        ENDIF
    ENDSELECT

    data.req.io.command := TR_ADDREQUEST
    data.req.time.secs    := 5 -> Update every five seconds
    data.req.time.micro   := 0
    SendIO(data.req)
    doMethodA(_app(obj),[MUIM_Application_AddInputHandler,data.ihnode])

    initfuncs({getdata},data,pi96base) -> initialization of parser.m

ENDPROC MUI_TRUE

PROC projectList_cleanup(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO msg)
DEF data:PTR TO projectList_data
    data := INST_DATA(cl,obj)
    doMethodA(_app(obj),[MUIM_Application_RemInputHandler,data.ihnode])
    IF (CheckIO(data.req)=NIL) THEN AbortIO(data.req)
    WaitIO(data.req)
ENDPROC (doSuperMethodA(cl,obj,msg))

PROC projectList_dispose(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO msg)
DEF worknode:PTR TO project_Node, nextnode,exec_list:PTR TO lh,data:PTR TO projectList_data
    data:=INST_DATA(cl,obj)
    exec_list:=data.exec_list
    worknode:=exec_list.head  -> First node
    IF worknode
        WHILE nextnode:=worknode.ln.succ
            END worknode;worknode:=nextnode
        ENDWHILE
    ENDIF

    DisposeLink(screentitle)

    IF (data.req)
        IF (data.req.io.device) THEN CloseDevice(data.req)
        DeleteIORequest(data.req)
    ENDIF
    IF (data.port) THEN DeleteMsgPort(data.port)
ENDPROC doSuperMethodA(cl,obj,msg)

PROC projectList_delitem(cl:PTR TO iclass,obj:PTR TO object/*,msg:PTR TO msg*/)
DEF data:PTR TO projectList_data,gad,window,state,
  node:PTR TO project_Node

quiet:=TRUE /*prevents the opened projects list from refreshing the display*/
    data:=INST_DATA(cl,obj)
    gad,window:=getcurrent(data,obj)
    doMethodA(gad,[MUIM_PlaneFunc_Abort,MUIV_PlaneFunc_Abort_Abort])/*aborts the task, if necessary*/
    get(gad,MUIA_PlaneFunc_ProjectNode,{node})
    get(gad,MUIA_PlaneFunc_State,{state})
    IF state = MUIV_PlaneFunc_State_Frozen
        message(node.pid,cat.msgm_RemVsFreeze.getstr())
        RETURN
    ENDIF
    doMethodA(obj,[MUIM_List_Remove,MUIV_List_Remove_Active])/*removes the name from the list*/
    DisposeLink(node.item)
    set(window,MUIA_Window_Open,FALSE)/*Closes the window*/
    doMethodA(app,[OM_REMMEMBER,window])
    Mui_DisposeObject(window) /*Removes the window and the PlaneFuncObject*/
    Remove(node)
    END node
    currid:=-1 -> This is to prevent projectList to change that unexistant project's priority
quiet:=FALSE
    doMethodA(obj,[MUIM_ProjectList_Refresh,0])
ENDPROC

PROC projectList_exit(cl:PTR TO iclass,obj:PTR TO object/*,msg:PTR TO msg*/)
DEF gad,data:PTR TO projectList_data,str[40]:STRING,pid
DEF exec_list:PTR TO lh,worknode:PTR TO project_Node,z,list:PTR TO mlh,cs:PTR TO object
    ->WriteF('Executing exit method...\n')
    data:=INST_DATA(cl,obj)
    exec_list:=data.exec_list
    worknode:=exec_list.head
    WHILE worknode.ln.succ
        get(worknode.window,MUIA_Window_RootObject,{z})
        get(z,MUIA_Group_ChildList,{list})
        cs:=list.head
        gad:=NextObject({cs})
        get(gad,MUIA_PlaneFunc_ProjectID,{pid})
        StringF(str,cat.msgm_Removing.getstr(),pid)
        message(-1,str)
        doMethodA(gad,[MUIM_PlaneFunc_Abort,MUIV_PlaneFunc_Abort_Abort])
        worknode:=worknode.ln.succ
    ENDWHILE
ENDPROC

PROC projectList_forward(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO args_forward)
DEF gad,data:PTR TO projectList_data
    data:=INST_DATA(cl,obj)
    gad:=getcurrent(data,obj)
    IF msg.method=MUIM_PlaneFunc_Abort
        doMethodA(gad,[MUIM_PlaneFunc_Abort,MUIV_PlaneFunc_Abort_Abort])
    ELSE
        doMethodA(gad,[msg.method])
    ENDIF
ENDPROC

PROC projectList_memory(cl:PTR TO iclass,obj:PTR TO object)
DEF win:PTR TO object,data:PTR TO projectList_data
    data:=INST_DATA(cl,obj)

    StringF(screentitle,'\s - \d Chip - \d Fast - \d Total',PICVERSION,AvailMem(MEMF_CHIP),AvailMem(MEMF_FAST),AvailMem(MEMF_ANY))
    get(obj,MUIA_WindowObject,{win})
    set(win,MUIA_Window_ScreenTitle,screentitle)
    set(messages_win,MUIA_Window_ScreenTitle,screentitle)
ENDPROC

PROC projectList_newitem(cl:PTR TO iclass,obj:PTR TO object/*,msg:PTR TO msg*/)
DEF window, pfunc,vscroll,hscroll,pid,
name:PTR TO CHAR,node:PTR TO project_Node,inlist:PTR TO CHAR,
exec_list:PTR TO lh,data:PTR TO projectList_data,
pdata:PTR TO planeFunc_data

    data:=INST_DATA(cl,obj);exec_list:=data.exec_list
    NEW node
    window:=WindowObject,
        MUIA_Window_ScreenTitle, PICVERSION,
        ->MUIA_Window_UseRightBorderScroller,MUI_TRUE,
        MUIA_Window_UseBottomBorderScroller,MUI_TRUE,
        WindowContents,
            HGroup,
                MUIA_Group_Spacing,0,
                Child, pfunc:=PlaneFuncObject,End,
                Child, vscroll:=ScrollbarObject,
                    MUIA_FixWidth,20,
                    ->MUIA_Prop_UseWinBorder,MUIV_Prop_UseWinBorder_Right, /*This is an MUI bug, the refreshing is not done correctely when having a scroller in the right border..*/
                    MUIA_Prop_Entries,255,MUIA_Prop_Visible,255,
                End,
                Child, hscroll:=PropObject,
                    MUIA_Prop_UseWinBorder,MUIV_Prop_UseWinBorder_Bottom,
                    MUIA_Prop_Entries,255,MUIA_Prop_Visible,255,
                End,
            End,
        End

    set(vscroll,MUIA_Prop_Entries,255) -> entries not set correctely..

    doMethodA(app,[OM_ADDMEMBER,window])  /* now the project window is ready;*/
    get(pfunc,MUIA_PlaneFunc_Name,{name}) /* the PlaneFunc class has also initialised.*/
    set(window,MUIA_Window_Title,name) -> Read the default PlaneFunc name
    pdata:=INST_DATA(cl_planefunc.mcc_class,pfunc)
    pdata.hscroll:=hscroll
    pdata.vscroll:=vscroll
    doMethodA(hscroll,[MUIM_Notify,MUIA_Prop_First,MUIV_EveryTime,pfunc,3,MUIM_Set,MUIA_PlaneFunc_Left,MUIV_TriggerValue])
    doMethodA(vscroll,[MUIM_Notify,MUIA_Prop_First,MUIV_EveryTime,pfunc,3,MUIM_Set,MUIA_PlaneFunc_Top,MUIV_TriggerValue])
    doMethodA(window,[MUIM_Notify,MUIA_Window_CloseRequest,MUI_TRUE,pfunc,1,MUIM_PlaneFunc_Close])
    node.window:=window
    node.ln.name:=name
    node.ln.type:=PROJECTNODE_ID
    node.ln.pri:=0
    inlist:=String(40)
    node.item:=inlist
    get(pfunc,MUIA_PlaneFunc_ProjectID,{pid})
    node.pid:=pid
    AddTail(exec_list,node)

    set(pfunc,MUIA_PlaneFunc_ProjectNode,node)

    StringF(inlist,'\d :\s',lastid-1,name)
    doMethodA(obj,[MUIM_List_InsertSingle,inlist,MUIV_List_Insert_Bottom])
    set(window,MUIA_Window_Open,MUI_TRUE) -> Open the window when everything is finished
    set(obj,MUIA_List_Active,MUIV_List_Active_Bottom)
    doMethodA(obj,[MUIM_ProjectList_Memory]) -> Update memory display when opening a project
ENDPROC

PROC projectList_notify(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO args_notify)
DEF data:PTR TO projectList_data,gadid,z,gad,value,pid,node:PTR TO project_Node
    data:=INST_DATA(cl,obj)
    gad:=getcurrent(data,obj)
    value:=msg.value
    gadid:=msg.gadget
    SELECT gadid
    CASE MUIV_ProjectList_Notify_Name
        set(gad,MUIA_PlaneFunc_Name,value)
        get(gad,MUIA_PlaneFunc_State,{z})
        IF (z=MUIV_PlaneFunc_State_Drawing) OR (value=MUIV_PlaneFunc_State_Loading)
            z:=33
        ELSE
            z:=32
        ENDIF
        get(gad,MUIA_PlaneFunc_ProjectID,{pid})
        get(gad,MUIA_PlaneFunc_ProjectNode,{node})
        StringF(node.item,'\d\c:\s',pid,z,value)
        doMethodA(obj,[MUIM_List_Redraw,MUIV_List_Redraw_Active])
    CASE MUIV_ProjectList_Notify_Type
        SELECT value
        CASE 0
            set(gad,MUIA_PlaneFunc_Type,MUIV_PlaneFunc_Type_DTPic)
        CASE 1
            set(gad,MUIA_PlaneFunc_Type,MUIV_PlaneFunc_Type_Graph)
        ENDSELECT
    CASE MUIV_ProjectList_Notify_ImageFile
        set(gad,MUIA_PlaneFunc_ImageFile,value)
    CASE MUIV_ProjectList_Notify_LoadM
        SELECT value
        CASE 0
            set(gad,MUIA_PlaneFunc_LoadM,MUIV_PlaneFunc_LoadM_Scale)
        CASE 1
            set(gad,MUIA_PlaneFunc_LoadM,MUIV_PlaneFunc_LoadM_CutTile)
        CASE 2
            set(gad,MUIA_PlaneFunc_LoadM,MUIV_PlaneFunc_LoadM_ChangeSize)
        ENDSELECT
    CASE MUIV_ProjectList_Notify_Red
        set(gad,MUIA_PlaneFunc_Rstr,value)
    CASE MUIV_ProjectList_Notify_Green
        set(gad,MUIA_PlaneFunc_Gstr,value)
    CASE MUIV_ProjectList_Notify_Blue
        set(gad,MUIA_PlaneFunc_Bstr,value)
/*    CASE MUIV_ProjectList_Notify_CompileR
        set(gad,MUIA_PlaneFunc_CompileR,value)
    CASE MUIV_ProjectList_Notify_CompileG
        set(gad,MUIA_PlaneFunc_CompileG,value)
    CASE MUIV_ProjectList_Notify_CompileB
        set(gad,MUIA_PlaneFunc_CompileB,value)
*/    CASE MUIV_ProjectList_Notify_OutputR
        set(gad,MUIA_PlaneFunc_OutputR,value)
    CASE MUIV_ProjectList_Notify_OutputG
        set(gad,MUIA_PlaneFunc_OutputG,value)
    CASE MUIV_ProjectList_Notify_OutputB
        set(gad,MUIA_PlaneFunc_OutputB,value)
    CASE MUIV_ProjectList_Notify_Width
        set(gad,MUIA_PlaneFunc_Width,Val(value))
    CASE MUIV_ProjectList_Notify_Height
        set(gad,MUIA_PlaneFunc_Height,Val(value))
    ENDSELECT
ENDPROC

PROC projectList_prefs(msg:PTR TO args_prefs) -> a future version may require semaphore, but not for now.
    msg.var[]:=msg.value
ENDPROC

/*This method reads all attributes of the current class and writes the state of the gadgets
in the settings window*/
PROC projectList_refresh(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO args_refresh)
DEF data:PTR TO projectList_data,nm:PTR TO CHAR,gad,value,q[11]:STRING,pid,win
DEF exec_list:PTR TO lh,worknode:PTR TO project_Node, count=0,ogad

    IF quiet=TRUE THEN RETURN
    data:=INST_DATA(cl,obj)
    gad,win:=getcurrent(data,obj)
    IF gad=NIL
        set(sgroup,MUIA_Disabled,MUI_TRUE)
        currid:=-1
        RETURN
    ENDIF
    set(sgroup,MUIA_Disabled,FALSE)
    get(gad,MUIA_PlaneFunc_ProjectID,{pid})
    IF pid <> currid /*was currid and will be pid*/
        IF currid > -1
            ogad:=getp(data,currid)
            doMethodA(ogad,[MUIM_PlaneFunc_SetTaskPri,rp])
        ENDIF
        doMethodA(gad,[MUIM_PlaneFunc_SetTaskPri,cp])
    ENDIF

    currid:=pid
    IF msg.ostate=FALSE
        doMethodA(gad,[MUIM_PlaneFunc_Lamps])
        StringF(q,'r(\d,x,y)=',pid)
        set(r_lbl,MUIA_Text_Contents,q)
        StringF(q,'g(\d,x,y)=',pid)
        set(g_lbl,MUIA_Text_Contents,q)
        StringF(q,'b(\d,x,y)=',pid)
        set(b_lbl,MUIA_Text_Contents,q)
        get(gad,MUIA_PlaneFunc_Name,{value})
        nnset(name_str,MUIA_String_Contents,value)   /*nnset to avoid triggering useless notification*/
        get(gad,MUIA_PlaneFunc_Type,{value})
        SELECT value
        CASE MUIV_PlaneFunc_Type_DTPic
            nnset(type_reg,MUIA_Group_ActivePage,0)
        CASE MUIV_PlaneFunc_Type_Graph
            nnset(type_reg,MUIA_Group_ActivePage,1)
        ENDSELECT

        get(gad,MUIA_PlaneFunc_LoadM,{value})  /* these are for image-projects*/
        SELECT value                           
        CASE MUIV_PlaneFunc_LoadM_Scale        /* but all settings are updated, so that */   
            nnset(size_rad,MUIA_Radio_Active,0)/* the user may change the selected page and*/
        CASE MUIV_PlaneFunc_LoadM_CutTile      /*see the current settings..*/                
            nnset(size_rad,MUIA_Radio_Active,1)
        CASE MUIV_PlaneFunc_LoadM_ChangeSize
            nnset(size_rad,MUIA_Radio_Active,2)
        ENDSELECT
        get(gad,MUIA_PlaneFunc_ImageFile,{value})
        nnset(path_str,MUIA_String_Contents,value)

        get(gad,MUIA_PlaneFunc_Rstr,{value})   /*these are for function-projects*/
        nnset(red_str,MUIA_String_Contents,value)
        get(gad,MUIA_PlaneFunc_Gstr,{value})
        nnset(green_str,MUIA_String_Contents,value)
        get(gad,MUIA_PlaneFunc_Bstr,{value})
        nnset(blue_str,MUIA_String_Contents,value)
        get(gad,MUIA_PlaneFunc_OutputR,{value})
        nnset(outr_cyc,MUIA_Cycle_Active,value)
        get(gad,MUIA_PlaneFunc_OutputG,{value})
        nnset(outg_cyc,MUIA_Cycle_Active,value)
        get(gad,MUIA_PlaneFunc_OutputB,{value})
        nnset(outb_cyc,MUIA_Cycle_Active,value)
/*        get(gad,MUIA_PlaneFunc_CompileR,{value})
        nnset(comr_cyc,MUIA_Cycle_Active,value)
        get(gad,MUIA_PlaneFunc_CompileG,{value})
        nnset(comg_cyc,MUIA_Cycle_Active,value)
        get(gad,MUIA_PlaneFunc_CompileB,{value})
        nnset(comb_cyc,MUIA_Cycle_Active,value)
*/

        get(gad,MUIA_PlaneFunc_Width,{value})
        nnset(width_str,MUIA_String_Integer,value)
        get(gad,MUIA_PlaneFunc_Height,{value})
        nnset(height_str,MUIA_String_Integer,value)
        get(win,MUIA_Window_Open,{value})
        nnset(showme_cyc,MUIA_Cycle_Active,value)
    ENDIF
    IF (msg.ostate = FALSE) OR (msg.ostate-2=pid)
        setlamp(gad)
    ENDIF
    IF msg.ostate > 0
        pid:=msg.ostate-2
        gad:=getp(data,pid)
        get(gad,MUIA_PlaneFunc_Name,{nm})
        get(gad,MUIA_PlaneFunc_State,{value})
        IF (value=MUIV_PlaneFunc_State_Drawing) OR (value=MUIV_PlaneFunc_State_Loading)
            value:=33
        ELSE
            value:=32
        ENDIF

        exec_list:=data.exec_list
        worknode:=exec_list.head
        WHILE worknode.pid <> pid
            count++
            worknode:=worknode.ln.succ
        ENDWHILE

        StringF(worknode.item,'\d\c:\s',pid,value,nm)
        doMethodA(obj,[MUIM_List_Redraw,count])
    ENDIF
ENDPROC

PROC setlamp(gad:PTR TO object)
DEF value
    get(gad,MUIA_PlaneFunc_State,{value})
    SELECT value
    CASE MUIV_PlaneFunc_State_Idle
        set(state_txt,MUIA_Text_Contents,cat.msgs_Idle.getstr())
        set(lamp_lmp,MUIA_Lamp_Color,MUIV_Lamp_Color_Off)
        set(state_gau,MUIA_Gauge_Current,0)
        set(draw_btn,MUIA_Text_Contents,cat.msgl_Render.getstr())
    CASE MUIV_PlaneFunc_State_Drawing
        set(state_txt,MUIA_Text_Contents,cat.msgs_Drawing.getstr())
        set(lamp_lmp,MUIA_Lamp_Color,MUIV_Lamp_Color_Processing)
        get(gad,MUIA_PlaneFunc_Percent,{value})
        set(state_gau,MUIA_Gauge_Current,value)
        set(draw_btn,MUIA_Text_Contents,cat.msgl_Pause.getstr())
    CASE MUIV_PlaneFunc_State_Loading
        set(state_txt,MUIA_Text_Contents,cat.msgs_Loading.getstr())
        set(lamp_lmp,MUIA_Lamp_Color,MUIV_Lamp_Color_LoadingData)
        get(gad,MUIA_PlaneFunc_Percent,{value})
        set(state_gau,MUIA_Gauge_Current,value)
        set(draw_btn,MUIA_Text_Contents,cat.msgl_Pause.getstr())
    CASE MUIV_PlaneFunc_State_Paused
        set(state_txt,MUIA_Text_Contents,cat.msgs_Paused.getstr())
        set(lamp_lmp,MUIA_Lamp_Color,MUIV_Lamp_Color_Ok)
        get(gad,MUIA_PlaneFunc_Percent,{value})
        set(state_gau,MUIA_Gauge_Current,value)
        set(draw_btn,MUIA_Text_Contents,cat.msgl_Restart.getstr())
    CASE MUIV_PlaneFunc_State_Frozen
        set(state_txt,MUIA_Text_Contents,cat.msgs_Frozen.getstr())
        set(lamp_lmp,MUIA_Lamp_Color,MUIV_Lamp_Color_SendingData)
        set(state_gau,MUIA_Gauge_Current,0)
        set(draw_btn,MUIA_Text_Contents,cat.msgl_Render.getstr())
    ENDSELECT
ENDPROC

PROC projectList_setpri(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO args_setpri)
DEF data:PTR TO projectList_data,task,
gad
DEF worknode:PTR TO project_Node, nextnode,exec_list:PTR TO lh,list:PTR TO mlh,cs:PTR TO object,z
    data:=INST_DATA(cl,obj)
    task:=msg.task
    SELECT task
    CASE MUIV_ProjectList_SetPri_Main
        SetTaskPri(FindTask(0),msg.value)
    CASE MUIV_ProjectList_SetPri_Render
        rp:=msg.value

        exec_list:=data.exec_list
        worknode:=exec_list.head  -> First node
        IF worknode
            WHILE nextnode:=worknode.ln.succ
                IF worknode.pid <> currid
                    get(worknode.window,MUIA_Window_RootObject,{z})
                    get(z,MUIA_Group_ChildList,{list})
                    cs:=list.head
                    gad:=NextObject({cs})
                    doMethodA(gad,[MUIM_PlaneFunc_SetTaskPri,rp])
                ENDIF
                worknode:=nextnode
            ENDWHILE
        ENDIF

    CASE MUIV_ProjectList_SetPri_Curr
        cp:=msg.value
        gad:=getcurrent(data,obj)
        IF gad
            doMethodA(gad,[MUIM_PlaneFunc_SetTaskPri,cp])
        ENDIF
    ENDSELECT
ENDPROC

PROC projectList_showme(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO args_showme)
DEF win,data:PTR TO projectList_data
DEF exec_list:PTR TO lh,active,worknode:PTR TO project_Node,z->,qe[30]:STRING

    data:=INST_DATA(cl,obj)

    exec_list:=data.exec_list
    get(obj,MUIA_List_Active,{active})
    /*get item number "active" of the exec_list (isn't any faster way to do it?)*/
    worknode:=exec_list.head
              /* I should add here a check that the bound of the list is never reached!*/
    IF active > 0
        FOR z:=1 TO active DO worknode:=worknode.ln.succ
    ENDIF -> now worknode is the node of the wanted project
    win:=worknode.window
    set(win,MUIA_Window_Open,msg.value)
    /*StringF(qe,'set(\d,MUIA_Window_Open,\d)',win,msg.value)
    message(active,qe)*/
ENDPROC

/***************************************************************
** custom uSlider private subclass of Slider class            **
****************************************************************
*                                                              *
*Simple sub-class of Slider, overriding MUIM_Numeric_Stringify *
*                                                              *
***************************************************************/
PROC uslider_dispatcher(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO muip_numeric_stringify)
DEF data:PTR TO uslider_data,methodid
    methodid:=msg.methodid
    SELECT methodid
    CASE OM_NEW;RETURN uslider_new(cl,obj,msg)
    CASE MUIM_Numeric_Stringify
        data:=INST_DATA(cl,obj)
        IF data.stringify=MUI_TRUE
            IF msg.value = 0
                StrCopy(data.buffer,cat.msgp_guNone.getstr())
            ELSEIF msg.value=1
                StringF(data.buffer,'\d \s',msg.value,cat.msgp_Pixel.getstr())
            ELSE
                StringF(data.buffer,'\d \s',msg.value,cat.msgp_Pixels.getstr())
            ENDIF
            RETURN data.buffer
        ENDIF
    CASE MUIM_uSlider_Bigger;RETURN uslider_bigger(obj,msg)
    CASE MUIM_uSlider_Smaller;RETURN uslider_smaller(obj,msg)
    CASE MUIM_Cleanup
        data:=INST_DATA(cl,obj)
        IF data.stringify THEN
            DisposeLink(data.buffer)
    ENDSELECT
ENDPROC doSuperMethodA(cl,obj,msg)

PROC uslider_new(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO opset)
DEF data:PTR TO uslider_data,
    tags:PTR TO tagitem,
    tag:PTR TO tagitem

    IF (obj:=doSuperMethodA(cl,obj,msg))=NIL THEN RETURN 0

    data:=INST_DATA(cl,obj)
    tags:=msg.attrlist
    WHILE tag:=NextTagItem({tags})
        IF tag.tag=MUIA_uSlider_Stringify
            data.stringify:=tag.data
            data.buffer:=String(10)
        ENDIF
    ENDWHILE
ENDPROC obj

PROC uslider_bigger(obj:PTR TO object,msg:PTR TO args_compare)
DEF level
    get(obj,MUIA_Slider_Level,{level})
    IF level < msg.than THEN
        nnset(obj,MUIA_Slider_Level,msg.than)
ENDPROC

PROC uslider_smaller(obj:PTR TO object,msg:PTR TO args_compare)
DEF level
    get(obj,MUIA_Slider_Level,{level})
    IF level > msg.than THEN
        nnset(obj,MUIA_Slider_Level,msg.than)
ENDPROC

/***************************************************************
** sizetxt class                                              **
****************************************************************
*  textobject containing the size of the last loaded picture.  *
***************************************************************/

OBJECT sizetxt_data
    buffer:PTR TO CHAR
ENDOBJECT

CONST MUIM_SizeTxt_Update=$FCB93800

OBJECT muip_stupd
    methodid
    width,height,depth
    projectid
ENDOBJECT

PROC sizetxt_dispatcher(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO msg)
DEF methodid
    methodid:=msg.methodid
    SELECT methodid
    CASE OM_NEW;RETURN sizetxt_new(cl,obj,msg)
    CASE OM_DISPOSE;RETURN sizetxt_dispose(cl,obj,msg)
    CASE MUIM_SizeTxt_Update;RETURN sizetxt_update(cl,obj,msg)
    ENDSELECT
ENDPROC doSuperMethodA(cl,obj,msg)

PROC sizetxt_new(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO msg)
DEF data:PTR TO sizetxt_data
    obj:=doSuperMethodA(cl,obj,msg)
    data:=INST_DATA(cl,obj)
    data.buffer:=String(50)
ENDPROC obj

PROC sizetxt_dispose(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO msg)
DEF data:PTR TO sizetxt_data
    data:=INST_DATA(cl,obj)
    DisposeLink(data.buffer)
ENDPROC doSuperMethodA(cl,obj,msg)

PROC sizetxt_update(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO muip_stupd)
DEF data:PTR TO sizetxt_data
    data:=INST_DATA(cl,obj)
    IF msg.projectid = currid
        StringF(data.buffer,'\s\d×\d×\d',cat.msgl_PicSize.getstr(),msg.width,msg.height,msg.depth)
        set(obj,MUIA_Text_Contents,data.buffer)
    ENDIF
ENDPROC

PROC myapp_dispatcher(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO muip_application_returnid)
    ->WriteF('$\h\n',msg.methodid)
    IF msg.methodid=MUIM_Application_ReturnID
        IF msg.retid=MUIV_Application_ReturnID_Quit THEN /*separate IFs to avoid illegal memory access, if the message hasn't any argument*/
            doMethodA(opened_lst,[MUIM_ProjectList_Exit]) -> This will cause the Exit method to be executed right before
    ENDIF                                           -> ReturnId (when called with Exit returnid)
ENDPROC doSuperMethodA(cl,obj,msg)

/***************************************************************
** Functions for easy and secure spawning/killing of subtasks **
***************************************************************/

PROC sendsubtaskmsg(st:PTR TO subtask,command,params)
    st.st_Message.stm_Message.replyport:= st.st_Reply
    st.st_Message.stm_Message.length   := SIZEOF subtaskmsg
    st.st_Message.stm_Command          := command
    st.st_Message.stm_Parameter        := params
    st.st_Message.stm_Result           := 0

    PutMsg(IF command=STC_STARTUP THEN st.st_Task::process.msgport ELSE st.st_Port,st.st_Message)
    WaitPort(st.st_Reply)          /*gets the reply*/
    GetMsg(st.st_Reply)
ENDPROC (st.st_Message.stm_Result)

PROC spawnsubtask(name,func,data:PTR TO planeFunc_data)
    DEF st=NIL:PTR TO subtask

    IF (st:=AllocVec(SIZEOF subtask,MEMF_PUBLIC OR MEMF_CLEAR))
        st.st_Reply:=CreateMsgPort()
        IF (st.st_Reply)
            st.st_Data:=data
            st.st_Task:= CreateNewProc([NP_ENTRY,func,
                                        NP_NAME,name,
                                        TAG_DONE])
            IF (st.st_Task)
                IF (sendsubtaskmsg(st,STC_STARTUP,st)) THEN RETURN (st)
            ENDIF
            DeleteMsgPort(st.st_Reply)
        ENDIF
        FreeVec(st)
    ENDIF
ENDPROC

PROC killsubtask(st:PTR TO subtask)
    sendsubtaskmsg(st,STC_SHUTDOWN,st)
    DeleteMsgPort(st.st_Reply)
    FreeVec(st)
ENDPROC

/*exitsubtask and initsubtask are called from the subtask*/
PROC exitsubtask(st:PTR TO subtask,stm:PTR TO subtaskmsg)
  /*
  ** We reply after a Forbid() to make sure we're really gone
  ** when the main task continues.
  */
  IF (st.st_Port) THEN DeleteMsgPort(st.st_Port)
  Forbid()
  stm.stm_Result:= FALSE
  ReplyMsg(stm)
ENDPROC

PROC initsubtask()
  DEF me=NIL:PTR TO tc,
      st=NIL:PTR TO subtask,
      stm=NIL:PTR TO subtaskmsg

  me:= FindTask(NIL)

  /*
  ** Wait for our startup message from the SpawnSubTask() function.
  */

  WaitPort(me::process.msgport)
  stm:= GetMsg(me::process.msgport)
  st:= stm.stm_Parameter
  st.st_Port:=CreateMsgPort()
  IF (st.st_Port)
    /*
    ** Reply startup message, everything ok.
    ** Note that if the initialization fails, the code falls
    ** through and replies the startup message with a stm_Result
    ** of 0 after a Forbid(). This tells SpawnSubTask() that the
    ** sub task failed to run.
    */
    stm.stm_Result:= TRUE
    ReplyMsg(stm)
    RETURN (st)
  ELSE
    exitsubtask(st,stm)
    RETURN (NIL)
  ENDIF
ENDPROC

/***************************************************************
**    Subtask which does all the time-consuming rendering     **
***************************************************************/

PROC renderfunc()
DEF st=NIL:PTR TO subtask,
    data=NIL:PTR TO planeFunc_data,
    running=TRUE,worktodo=FALSE,x,y,
    stm=NIL:PTR TO subtaskmsg,
    command,i,
    red,green,blue,lr:PTR TO longreal,cnt,oldpixel,
    rf,gf,bf

    geta4() -> !!!

    IF (st:= initsubtask())
        data:= st.st_Data
        LOOP
            /*
            ** after the sub task is up and running, we go into
            ** a loop and process the messages from the main task.
            */
            WHILE (stm:= GetMsg(st.st_Port))
                command:=stm.stm_Command
                SELECT command
                CASE STC_SHUTDOWN
                    /*
                    ** This is the shutdown message from KillSubTask().
                    */
                    running:= FALSE
                    IF data.line
                        END data.line[data.width*(data.rupd+1)]
                        data.line:=0
                    ENDIF
                CASE STC_START
                    ObtainSemaphore(data.sema)
                    data.drawn:=-1
                    data.calculated:=-1
                    DateStamp(data.ds)
                    ReleaseSemaphore(data.sema)

                    y:=0;cnt:=data.rupd
                    i:=0
                    NEW lr
                    worktodo:= TRUE
                    rf:=data.rfunc.calculate
                    gf:=data.gfunc.calculate
                    bf:=data.bfunc.calculate
                    /*allocate memory for a block, if necessary (cgx optimisation)*/
                    IF cybergfxbase THEN
                        NEW data.line[data.width*(data.rupd+2)]

                CASE STC_PAUSE
                    worktodo:= FALSE
                CASE STC_RESTART -> Deactivate pause
                    worktodo:=TRUE
                ENDSELECT
                /*
                ** If we received a shutdown message, we do not reply it
                ** immediately. First, we need to free our resources.
                */
                IF (running=FALSE) THEN JUMP exit
                ReplyMsg(stm.stm_Message)
            ENDWHILE
            IF (worktodo)
                /* if there is work to do, i.e. if the rendering is not
                   finished yet, we calculate the next line and draw
                   it to the offscreen rastport.*/
                ObtainSemaphore(data.sema)

                ->rproc(-1,y,lr,data.rfunc) /*precalculation*/
                ->gproc(-1,y,lr,data.gfunc) /*... later :-)*/
                ->bproc(-1,y,lr,data.bfunc)

                IF data.savepixel 
                    IF cybergfxbase -> calculate here just to avoid testing twice for gfx system (...)
                        oldpixel:=ReadRGBPixel(data.rp,0,y)
                    ELSE
                        oldpixel:=Pi96ReadPixel(data.rp,0,y)
                    ENDIF
                ENDIF

                FOR x:=0 TO data.width-1
                    IF data.outputr=OUT_Integer      /*red*/

                        red:=rf(x,y)
                        ->red:=data.rfunc.evaluate(x,y)
                        red:=modt(red)
                        red:=Shl(red,16)
                    ELSEIF data.outputr=OUT_Float32
                        red:=!rf(x!,y!)!
                        ->red:=!data.rfunc.evaluate(x,y)!
                        red:=modt(red)
                        red:=Shl(red,16)
                    /*ELSEIF data.outputr=OUT_Float64
                        rproc(x,y,lr,data.rfunc)
                        red:=dFix(lr)
                        red:=modt(red)
                        red:=Shl(red,16)*/
                    ELSEIF data.outputr=OUT_OldR
                        red:=oldpixel AND $FF0000
                    ELSEIF data.outputr=OUT_OldG
                        red:=Shl(oldpixel AND $FF00,8)
                    ELSE /*IF data.outputr=OUT_OldB*/
                        red:=Shl(oldpixel AND $FF,16)
                    ENDIF
                    IF data.outputg=OUT_Integer      /*green*/
                        green:=gf(x,y)
                        ->green:=data.gfunc.evaluate(x,y)
                        green:=modt(green)
                        green:=Shl(green,8)
                    ELSEIF data.outputg=OUT_Float32
                        green:=!gf(x!,y!)!
                        ->green:=!data.gfunc.evaluate(x,y)!
                        green:=modt(green)
                        green:=Shl(green,8)
                    /*ELSEIF data.outputg=OUT_Float64
                        gproc(x,y,lr,data.gfunc)
                        green:=dFix(lr)
                        green:=modt(green)
                        green:=Shl(green,8)*/
                    ELSEIF data.outputg=OUT_OldR
                        green:=oldpixel AND $FF0000
                        green:=Shr(green,8)
                    ELSEIF data.outputg=OUT_OldG
                        green:=oldpixel AND $FF00
                    ELSEIF data.outputg=OUT_OldB
                        green:=oldpixel AND $FF
                        green:=Shl(green,8)
                    ELSE /*IF data.outputr=OUT_CopyR*/
                        green:=Shr(red,8)
                    ENDIF
                    IF data.outputb=OUT_Integer      /*blue*/
                        blue:=bf(x,y)
                        ->blue:=data.bfunc.evaluate(x,y)
                        blue:=modt(blue)
                    ELSEIF data.outputb=OUT_Float32
                        blue:=!bf(x!,y!)!
                        ->blue:=!data.bfunc.evaluate(x,y)!
                        blue:=modt(blue)
                    /*ELSEIF data.outputb=OUT_Float64
                        bproc(x,y,lr,data.bfunc)
                        blue:=dFix(lr)
                        blue:=modt(blue)*/
                    ELSEIF data.outputb=OUT_OldR
                        blue:=Shr(oldpixel,16)
                    ELSEIF data.outputb=OUT_OldG
                        blue:=Shr(oldpixel,8) AND $FF
                        blue:=blue AND $FF
                    ELSEIF data.outputb=OUT_OldB
                        blue:=oldpixel AND $FF
                    ELSEIF data.outputb=OUT_CopyR
                        blue:=Shr(red,16)
                    ELSE /*IF data.outputb=OUT_CopyG*/
                        blue:=Shr(green,8)
                    ENDIF

                    IF cybergfxbase
                        ->WriteRGBPixel(data.rp,x,y,red+green+blue)
                        data.line[i]:=red+green+blue
                        i++
                        IF data.savepixel THEN                    -> mmh, what if x is on the right border?
                            oldpixel:=ReadRGBPixel(data.rp,x+1,y)
                    ELSE
                        Pi96WritePixel(data.rp,x,y,red+green+blue)
                        IF data.savepixel THEN
                            oldpixel:=Pi96ReadPixel(data.rp,x+1,y)

                    ENDIF
                ENDFOR
                IF pi96base THEN data.calculated:=y -> that block optimisation isn't available for p96 yet...
                ReleaseSemaphore(data.sema)
                ObtainSemaphore(data.sema)
                IF data.rupd
                    IF cnt=0
                        IF (data.app)
                            IF cybergfxbase
                                WritePixelArray(data.line,0,0,data.width*4,data.rp,0,data.calculated+1,data.width,data.rupd+1,RECTFMT_ARGB)
                                data.calculated:=y
                                i:=0
                            ENDIF
                            doMethodA(data.app,[MUIM_Application_PushMethod,data.self,1,MUIM_PlaneFunc_Update])
                        ENDIF
                        cnt:=data.rupd
                    ELSE ; cnt--
                    ENDIF
                ENDIF
                ReleaseSemaphore(data.sema)
                y++
                IF (y=data.height)
                    /* check if we are finished to draw our picture */
                     worktodo:= FALSE
                    /*if we're finished, we ask the main task to exit ourselves..*/
                    IF (data.app)
                        IF cybergfxbase
                            WritePixelArray(data.line,0,0,data.width*4,data.rp,0,data.calculated+1,data.width,data.rupd-cnt+1,RECTFMT_ARGB)
                            data.calculated:=y
                        ENDIF

                        doMethodA(data.app,[MUIM_Application_PushMethod,data.self,1,MUIM_PlaneFunc_Update])
                        doMethodA(data.app,[MUIM_Application_PushMethod,data.self,2,MUIM_PlaneFunc_Abort,MUIV_PlaneFunc_Abort_Finish])
                    ENDIF
                ENDIF
                /* Since we are very busy working, we do not Wait() for signals. */
            ELSE
                /* We have nothing to do, just sit quietly and wait for something to happen */
                WaitPort(st.st_Port)
            ENDIF
        ENDLOOP
        END lr
exit:
        exitsubtask(st,stm)
    ENDIF
ENDPROC

PROC loadpicture()
DEF pic:PTR TO super_picture,file:PTR TO CHAR,tbmp:PTR TO trueBitmap
DEF st=NIL:PTR TO subtask,
    data=NIL:PTR TO planeFunc_data,
    running=TRUE,worktodo=FALSE,changedone=TRUE,
    x,y,
    stm=NIL:PTR TO subtaskmsg,
    command,i,
    cnt=0,init=2

    geta4()
    IF (st:= initsubtask())
        data:=st.st_Data
        LOOP
            WHILE (stm:= GetMsg(st.st_Port))
                command:=stm.stm_Command
                SELECT command
                CASE STC_SHUTDOWN
                    running:= FALSE
                    IF data.line
                        END data.line[data.width*(data.rupd+1)]
                        data.line:=0
                    ENDIF
                CASE STC_START
                    ObtainSemaphore(data.sema)
                    data.drawn:=-1
                    data.calculated:=-1
                    DateStamp(data.ds)
                    ReleaseSemaphore(data.sema)
                    worktodo:=TRUE
                    y:=0;i:=0
                    /*allocate memory for a block, if necessary (cgx optimisation)*/
                    IF cybergfxbase THEN
                        NEW data.line[data.width*(data.rupd+2)]
                CASE STC_PAUSE
                    worktodo:= FALSE
                CASE STC_RESTART
                    worktodo:=TRUE
                CASE STC_CHANGEDONE
                    changedone:=TRUE
                ENDSELECT
                IF (running=FALSE) THEN JUMP finish
                ReplyMsg(stm.stm_Message)
            ENDWHILE
            ->IF (running=FALSE) THEN JUMP finish
            IF worktodo AND changedone
                IF init = 2
                    NEW pic.super_picture(TRUE)
                    file:=data.imagefile
                    IF pic.load(file) <> 0  /*And if data.app=NIL ? :-)*/
                        doMethodA(data.app,[MUIM_Application_PushMethod,data.self,2,MUIM_PlaneFunc_Abort,MUIV_PlaneFunc_Abort_NoLoad])
                        worktodo:=FALSE
                    ELSE
                        ObtainSemaphore(data.sema) /*same as above :-)*/
                        IF data.loadm=MUIV_PlaneFunc_LoadM_ChangeSize
                            doMethodA(data.app,[MUIM_Application_PushMethod,data.self,3,
                                MUIM_Set,MUIA_PlaneFunc_Quiet,-2])
                            doMethodA(data.app,[MUIM_Application_PushMethod,data.self,3,
                                MUIM_Set,MUIA_PlaneFunc_Width,pic.width()])
                            doMethodA(data.app,[MUIM_Application_PushMethod,data.self,3,
                                MUIM_Set,MUIA_PlaneFunc_Height,pic.height()])
                            doMethodA(data.app,[MUIM_Application_PushMethod,data.self,3,
                                MUIM_Set,MUIA_PlaneFunc_Quiet,FALSE])
                            changedone:=FALSE
                        ENDIF
                        doMethodA(data.app,[MUIM_Application_PushMethod,size_txt,5,MUIM_SizeTxt_Update,
                            pic.width(),pic.height(),pic.depth(),data.projectid])
                        ReleaseSemaphore(data.sema)
                    ENDIF
                    init:=1
                ELSEIF init = 1
                    IF (tbmp:=pic.trueconv()) = NIL
                        doMethodA(data.app,[MUIM_Application_PushMethod,data.self,2,MUIM_PlaneFunc_Abort,MUIV_PlaneFunc_Abort_NoLoad])
                        worktodo:=FALSE
                    ENDIF
                    doMethodA(data.app,[MUIM_Application_PushMethod,data.self,3,MUIM_Set,MUIA_PlaneFunc_Loading,FALSE])
                    init:=0
                ELSE
                    ObtainSemaphore(data.sema)
                    IF data.loadm=MUIV_PlaneFunc_LoadM_Scale
                        IF cybergfxbase /*cgx*/
                            FOR x:=0 TO data.width-1
                                ->WriteRGBPixel(data.rp,x,y,tbmp.readPixel(x*pic.width()/data.width,y*pic.height()/data.height))
                                data.line[i]:=tbmp.readPixel(x*pic.width()/data.width,y*pic.height()/data.height)
                                i++
                            ENDFOR
                        ELSE    /*picasso*/
                            FOR x:=0 TO data.width-1
                                Pi96WritePixel(data.rp,x,y,tbmp.readPixel(x*pic.width()/data.width,y*pic.height()/data.height))
                            ENDFOR
                            data.calculated:=y
                        ENDIF
                    ELSE
                        IF cybergfxbase /*cgx*/
                            FOR x:=0 TO data.width-1
                                ->WriteRGBPixel(data.rp,x,y,tbmp.readPixel(Mod(x,pic.width()),Mod(y,pic.height())))
                                data.line[i]:=tbmp.readPixel(Mod(x,pic.width()),Mod(y,pic.height()))
                                i++
                            ENDFOR
                        ELSE    /*picasso*/
                            FOR x:=0 TO data.width-1
                                Pi96WritePixel(data.rp,x,y,tbmp.readPixel(Mod(x,pic.width()),Mod(y,pic.height())))
                            ENDFOR
                            data.calculated:=y
                        ENDIF
                    ENDIF
                    IF data.rupd
                        IF cnt=0
                            IF (data.app)
                                IF cybergfxbase
                                    WritePixelArray(data.line,0,0,data.width*4,data.rp,0,data.calculated+1,data.width,data.rupd+1,RECTFMT_ARGB)
                                    data.calculated:=y
                                    i:=0
                                ENDIF
                                doMethodA(data.app,[MUIM_Application_PushMethod,data.self,1,MUIM_PlaneFunc_Update])
                            ENDIF
                            cnt:=data.rupd
                        ELSE ; cnt--
                        ENDIF
                    ENDIF

                    ReleaseSemaphore(data.sema)
                    y++
                    IF (y=data.height)
                         worktodo:= FALSE
                        IF (data.app)
                            IF cybergfxbase
                                WritePixelArray(data.line,0,0,data.width*4,data.rp,0,data.calculated+1,data.width,data.rupd-cnt+1,RECTFMT_ARGB)
                                data.calculated:=y
                            ENDIF
                            doMethodA(data.app,[MUIM_Application_PushMethod,data.self,1,MUIM_PlaneFunc_Update])
                            doMethodA(data.app,[MUIM_Application_PushMethod,data.self,2,MUIM_PlaneFunc_Abort,MUIV_PlaneFunc_Abort_Finish])
                        ENDIF
                    ENDIF
                ENDIF
            ELSE
                WaitPort(st.st_Port)
            ENDIF
        ENDLOOP
finish:
        END pic
        exitsubtask(st,stm)
    ENDIF
ENDPROC
/********************************
*   Inter-referencing...        *
********************************/

/*freeze(expression): this will read-lock all used functions.
returns true if success, or false if failure*/

PROC freeze(f:PTR TO expression)
DEF a:PTR TO planeFunc_data,b,c,data:PTR TO projectList_data,obj,lock
DEF exec_list:PTR TO lh,worknode:PTR TO project_Node
    IF f.precision > OUT_Float64 THEN RETURN TRUE
    data:=INST_DATA(cl_projectlist.mcc_class,opened_lst)

    a,b,c:=f.reference()

    IF a > 3 -> direct reference to project "a" (a is the data of the object)
            /* + sub-functions "b" and "c"*/
        /*checks that a exists, searching it in the projects list*/
        data:=INST_DATA(cl_projectlist.mcc_class,opened_lst)
        exec_list:=data.exec_list
        worknode:=exec_list.head
        WHILE wcomp(worknode,a)
            worknode:=worknode.ln.succ
        ENDWHILE
        IF worknode.ln.succ = 0 -> a doesn't exist
            RETURN FALSE
        ENDIF
        obj:=a.self
        get(obj,MUIA_PlaneFunc_Lock,{lock})
        IF lock = MUIV_PlaneFunc_Lock_Write THEN RETURN FALSE
        set(obj,MUIA_PlaneFunc_Lock,MUIV_PlaneFunc_Lock_Read)
        IF freeze(b) = 0
            set(obj,MUIA_PlaneFunc_Lock,MUIV_PlaneFunc_Lock_NoRead)
            RETURN FALSE
        ENDIF
        IF freeze(c) = 0
            free(b) -> IF "c" can't be frozen, let's free "b" before returning
            set(obj,MUIA_PlaneFunc_Lock,MUIV_PlaneFunc_Lock_NoRead)
            RETURN FALSE
        ENDIF
        RETURN TRUE
    ENDIF

    SELECT a
    CASE 2 -> One sub-function : "b"
        IF freeze(b) = 0 THEN RETURN FALSE
    CASE 3 -> Two sub functions : "b" and "c"
        IF freeze(b) = 0 THEN RETURN FALSE
        IF freeze(c) = 0
            free(b) -> IF "c" can't be frozen, let's free "b" before returning
            RETURN FALSE
        ENDIF
    ENDSELECT
ENDPROC TRUE

PROC wcomp(node:PTR TO project_Node,data)
    IF node.ln.succ = 0 THEN RETURN FALSE
ENDPROC (wdata(node.window) <> data)

PROC wdata(window)
DEF gad,list:PTR TO mlh,cs:PTR TO object
    get(window,MUIA_Window_RootObject,{gad})
    get(gad,MUIA_Group_ChildList,{list})
    cs:=list.head
ENDPROC INST_DATA(cl_planefunc.mcc_class,NextObject({cs}))

/*free(expression): This un read-locks all used functions.
It assumes that freeze(function) has been executed before and that
function did not change since*/

PROC free(f:PTR TO expression)
DEF a:PTR TO planeFunc_data,b,c,data:PTR TO projectList_data,obj

    data:=INST_DATA(cl_projectlist.mcc_class,opened_lst)

    a,b,c:=f.reference()
    IF a > 3
        obj:=a.self
        set(obj,MUIA_PlaneFunc_Lock,MUIV_PlaneFunc_Lock_NoRead)
        a:=3
    ENDIF
    SELECT a
    CASE 2 -> One sub-expression : "b"
        free(b)
    CASE 3 -> Two sub-expressions : "b" and "c"
        free(b)
        free(c)
    ENDSELECT
ENDPROC

/***************************************************************
**                       main program                         **
****************************************************************
 Opens the libraries, creates the user interface structure and
notifications. The input loop just waits for MUI to say to quit.
***************************************************************/

PROC main() HANDLE
DEF l
    storea4()
    IF (localebase:=OpenLibrary('locale.library',0)) = NIL THEN
        Raise('locale.library')
    NEW cat.create()
    cat.open()
    IF (utilitybase:=OpenLibrary('utility.library',36))=NIL THEN
        Raise('utility.library') /*for tag-list parsing*/
    IF (datatypesbase:=OpenLibrary('datatypes.library',0))=NIL THEN
        Raise('datatypes.library')
    muimasterbase:=OpenLibrary(MUIMASTER_NAME,MUIMASTER_VMIN)
    IF muimasterbase = NIL THEN
        Raise('muimaster.library')
    IF (aslbase:=OpenLibrary('asl.library',37))=NIL THEN
        Raise('asl.library')

    dInit(TRUE)
    cl_planefunc:=eMui_CreateCustomClass(NIL,MUIC_Area ,NIL,SIZEOF planeFunc_data,{planeFunc_dispatcher})
    cl_projectlist:=eMui_CreateCustomClass(NIL,MUIC_List,NIL,SIZEOF projectList_data,{projectList_dispatcher})
    cl_uslider:=eMui_CreateCustomClass(NIL,MUIC_Slider,NIL,SIZEOF uslider_data,{uslider_dispatcher})
    cl_sizetxt:=eMui_CreateCustomClass(NIL,MUIC_Text,NIL,SIZEOF sizetxt_data,{sizetxt_dispatcher})
    cl_myapp:=eMui_CreateCustomClass(NIL,MUIC_Application,NIL,SIZEOF empty_data,{myapp_dispatcher})
    ftype_registertitles:=[cat.msgl_type_Image.getstr(),cat.msgl_type_Function.getstr(),NIL]
    size_radiolabels:=[cat.msgl_lm_Scale.getstr(),cat.msgl_lm_CutTile.getstr(),cat.msgl_lm_Change.getstr(),NIL]
    showme_cyclelabels:=[cat.msgl_Hidden.getstr(),cat.msgl_Shown.getstr(),NIL]

    FOR app:=0 TO 14 -> app: I did not want to create a var just for that loop :-)
        messages[app]:=String(100)
    ENDFOR

    app:=MyApplicationObject,
        MUIA_Application_Title, 'picFX',
        MUIA_Application_Version,FULLVERSION,
        MUIA_Application_Author, 'Maxime Gamboni',
        MUIA_Application_Description, cat.msg_Description.getstr(),
        MUIA_Application_Base,'picFX',

        SubWindow, settings_win:=WindowObject,
            MUIA_Window_Title, cat.msgl_Title.getstr(),
            MUIA_Window_ScreenTitle, PICVERSION,
            MUIA_Window_ID,"SETT",
            WindowContents,HGroup,
                Child, VGroup,
                    MUIA_Weight,30,
                    Child, TextObject,
                        NoFrame,
                        MUIA_Text_PreParse,'\ec',
                        MUIA_Text_Contents,cat.msgl_OpenedProjects.getstr(),
                    End,
                    Child, opened_lsv:=ListviewObject,
                        InputListFrame,
                        MUIA_Listview_List,opened_lst:=ProjectListObject,End,
                    End,
                    Child, new_btn:=SimpleButton(cat.msgl_New.getstr()),
                    Child, RectangleObject,MUIA_Rectangle_HBar,MUI_TRUE,MUIA_Weight,0,End,
                    Child, prefs_btn:=TextObject,
                        ButtonFrame,
                        MUIA_Background,MUII_ButtonBack,
                        MUIA_Text_PreParse,'\ec',
                        MUIA_Text_Contents,cat.msgl_Prefs.getstr(),
                        MUIA_InputMode,MUIV_InputMode_RelVerify,
                    End,
                End,
                Child, RectangleObject,MUIA_Rectangle_VBar,MUI_TRUE,MUIA_Weight,0,End,
                Child, sgroup:=VGroup,
                    MUIA_Disabled,MUI_TRUE, -> No projects are opened at beginning
                    Child,name_str:= StringObject,MUIA_String_Contents,cat.msg_Unnamed.getstr(),StringFrame,End,
                    Child, type_reg:=RegisterGroup(ftype_registertitles),
                        Child, VGroup,
                            Child, HGroup,
                                Child, FreeLabel(cat.msgl_Path.getstr()),
                                Child, PopaslObject,
                                    MUIA_Popstring_Button,PopButton(MUII_PopFile),
                                    MUIA_Popasl_Type,ASL_FILEREQUEST,
                                    MUIA_Popstring_String,path_str:=StringObject,
                                        StringFrame,
                                        MUIA_String_Contents,cat.msg_Unnamed.getstr(),
                                    End,
                                End,
                            End,
                            Child, HGroup,
                                Child, size_rad:=RadioObject,
                                    GroupFrameT(cat.msgl_Size.getstr()),
                                    MUIA_Radio_Entries,size_radiolabels,
                                    MUIA_Radio_Active,1,
                                End,
                                Child, VGroup,
                                    Child, RectangleObject,End,
                                    Child, size_txt:=SizeTextObject,
                                        TextFrame,
                                        MUIA_Text_PreParse,'\ec',
                                        MUIA_Text_Contents,cat.msgl_PicSize.getstr(),
                                    End,
                                    Child, RectangleObject,End,
                                End,
                            End,
                        End,
                        Child, VGroup,
                            Child, HGroup,
                                Child,red_fail:=LampObject,
                                    MUIA_Lamp_Type,MUIV_Lamp_Type_Big,
                                    MUIA_Lamp_ColorType,MUIV_Lamp_ColorType_UserDefined,
                                    MUIA_Lamp_Color,MUIV_Lamp_Color_Ok,
                                End,
                                Child, r_lbl:=label('r(#,x,y)='),
                                Child, red_str:=StringObject,
                                    StringFrame,
                                End,
                            End,
                            Child, HGroup,
                                Child, Label(cat.msgl_Output.getstr()),
                                Child, outr_cyc:=CycleObject,
                                    MUIA_Cycle_Entries,[cat.msgl_Int32.getstr(),cat.msgl_Float32.getstr(),cat.msgl_Float64.getstr(),
                                                        cat.msgl_OldR.getstr(),cat.msgl_OldG.getstr(),cat.msgl_OldB.getstr(),NIL],
                                    MUIA_Cycle_Active,3,
                                End,
                                Child, RectangleObject,End,
                                /*Child, comr_cyc:=CycleObject,
                                    MUIA_Cycle_Entries,['Not compiled','Always compile',NIL],
                                End,*/
                            End,

                            Child, HGroup,
                                Child,green_fail:=LampObject,
                                    MUIA_Lamp_Type,MUIV_Lamp_Type_Big,
                                    MUIA_Lamp_ColorType,MUIV_Lamp_ColorType_UserDefined,
                                    MUIA_Lamp_Color,MUIV_Lamp_Color_Ok,
                                End,
                                Child, g_lbl:=label('g(#,x,y)='),
                                Child, green_str:=StringObject,
                                    StringFrame,
                                End,
                            End,
                            Child, HGroup,
                                Child, Label(cat.msgl_Output.getstr()),
                                Child, outg_cyc:=CycleObject,
                                    MUIA_Cycle_Entries,[cat.msgl_Int32.getstr(),cat.msgl_Float32.getstr(),cat.msgl_Float64.getstr(),
                                                        cat.msgl_OldR.getstr(),cat.msgl_OldG.getstr(),cat.msgl_OldB.getstr(),
                                                        cat.msgl_CopyR.getstr(),NIL],
                                    MUIA_Cycle_Active,3,
                                End,
                                Child, RectangleObject,End,
                                /*Child,comg_cyc:=CycleObject,
                                    MUIA_Cycle_Entries,['Not compiled','Always compile',NIL],
                                End,*/
                            End,

                            Child, HGroup,
                                Child,blue_fail:=LampObject,
                                    MUIA_Lamp_Type,MUIV_Lamp_Type_Big,
                                    MUIA_Lamp_ColorType,MUIV_Lamp_ColorType_UserDefined,
                                    MUIA_Lamp_Color,MUIV_Lamp_Color_Ok,
                                End,
                                Child, b_lbl:=label('b(#,x,y)='),
                                Child, blue_str:=StringObject,
                                    StringFrame,
                                End,
                            End,
                            Child, HGroup,
                                Child, Label(cat.msgl_Output.getstr()),
                                Child, outb_cyc:=CycleObject,
                                    MUIA_Cycle_Entries,[cat.msgl_Int32.getstr(),cat.msgl_Float32.getstr(),cat.msgl_Float64.getstr(),
                                                        cat.msgl_OldR.getstr(),cat.msgl_OldG.getstr(),cat.msgl_OldB.getstr(),
                                                        cat.msgl_CopyR.getstr(),cat.msgl_CopyG.getstr(),NIL],
                                    MUIA_Cycle_Active,3,
                                End,
                                Child, RectangleObject,End,
                                /*Child, cmb_cyc:=CycleObject,
                                    MUIA_Cycle_Entries,['Not compiled','Always compile',NIL],
                                End,*/
                            End,
                        End,
                    End,
                    Child, HGroup,
                        Child, TextObject,
                            MUIA_Text_PreParse,'\ec',
                            MUIA_Text_Contents,cat.msgl_Width.getstr(),
                        End,
                        Child, TextObject,
                            MUIA_Text_PreParse,'\ec',
                            MUIA_Text_Contents,cat.msgl_Height.getstr(),
                        End,
                    End,
                    Child, HGroup,
                        Child, width_str:=StringObject,
                            StringFrame,
                            MUIA_String_Accept,'0123456789',
                        End,
                        Child, height_str:=StringObject,
                            StringFrame,
                            MUIA_String_Accept,'0123456789',
                        End,
                    End,
                    Child, GroupObject,MUIA_Group_Rows,2,
                        Child, draw_btn:=TextObject,
                            ButtonFrame,
                            MUIA_Background,MUII_ButtonBack,
                            MUIA_Text_PreParse,'\ec',
                            MUIA_Text_Contents,cat.msgl_Render.getstr(),
                            MUIA_InputMode,MUIV_InputMode_RelVerify,
                        End,
                        Child, savepic_btn:=SimpleButton(cat.msgl_SavePic.getstr()),
                        Child, savefunc_btn:=SimpleButton(cat.msgl_SaveFunc.getstr()),
                        Child, abort_btn:=SimpleButton(cat.msgl_Abort.getstr()),
                        Child, showme_cyc:=CycleObject,
                            ButtonFrame,
                            MUIA_Cycle_Entries,showme_cyclelabels,
                            MUIA_Cycle_Active,1,
                        End,
                        Child, close_btn:=SimpleButton(cat.msgl_Close.getstr()),
                        Child, loadfunc_btn:=SimpleButton(cat.msgl_LoadFunc.getstr()),
                        Child, clear_btn:=SimpleButton(cat.msgl_Clear.getstr()),
                    End,
                    Child, HGroup,
                        Child,lamp_lmp:=LampObject,
                            MUIA_Lamp_Type,MUIV_Lamp_Type_Big,
                            MUIA_Lamp_ColorType,MUIV_Lamp_ColorType_UserDefined,
                            MUIA_Lamp_Color,MUIV_Lamp_Color_Off,
                        End,
                        Child,state_txt:=TextObject,
                            MUIA_Text_Contents,cat.msgs_Idle.getstr(),
                            MUIA_Weight,50,
                        End,
                        Child,state_gau:=GaugeObject,
                            TextFrame,
                            MUIA_Gauge_Horiz , MUI_TRUE,
                        End,
                    End,
                End,
            End,
        End,
        SubWindow,prefs_win:=SettingsWindowObject,
            MUIA_Window_Title,cat.msgl_Prefs.getstr(),
            MUIA_Window_ID,"PREF",
            WindowContents,HGroup,
                Child, VGroup,
                    GroupFrameT(cat.msgp_Priority.getstr()),
                    Child, mainpri_sld:=uSliderObject,
                        GroupFrameT(cat.msgp_MainTask.getstr()),
                        MUIA_Slider_Min,-10,
                        MUIA_Slider_Max,10,
                        MUIA_Slider_Level,0,
                    End,
                    Child, currpri_sld:=uSliderObject,
                        GroupFrameT(cat.msgp_CurrentTask.getstr()),
                        MUIA_Slider_Min,-10,
                        MUIA_Slider_Max,10,
                        MUIA_Slider_Level,-1,
                    End,
                    Child, renderpri_sld:=uSliderObject,
                        GroupFrameT(cat.msgp_RenderTask.getstr()),
                        MUIA_Slider_Min,-10,
                        MUIA_Slider_Max,10,
                        MUIA_Slider_Level,-2,
                    End,
                End,
                Child, VGroup,
                    Child, renderupdate_sld:=uSliderObject,
                        GroupFrameT(cat.msgp_RenderUpd.getstr()),
                        MUIA_uSlider_Stringify,MUI_TRUE,
                        MUIA_Slider_Min,0,
                        MUIA_Slider_Max,40,
                        MUIA_Slider_Level,10,
                    End,
                    Child, HGroup,
                        Child, FreeLabel(cat.msgp_Close.getstr()),
                        Child, close_cyc:=CycleObject,
                            MUIA_Cycle_Entries,[cat.msgl_Iconify.getstr(),cat.msgl_Close.getstr(),NIL],
                            MUIA_Cycle_Active,0,
                        End,
                    End,
                    Child, mui_btn:=SimpleButton(cat.msgp_MuiPrefs.getstr()),
                End,
            End,
        End,
        SubWindow,messages_win:=WindowObject,
            MUIA_Window_Title,cat.msgm_NoMsg.getstr(),
            MUIA_Window_ID,"MESS",
            WindowContents,VGroup,
                Child,ListviewObject,
                    MUIA_Listview_Input,FALSE,
                    ReadListFrame,
                    MUIA_Listview_List,messages_lst:=ListObject,
                        MUIA_List_SourceArray,messages,
                    End,
                End,
                Child, colour_txt:=TextObject,
                    TextFrame,
                    MUIA_Background,MUII_TextBack,
                    MUIA_Text_Contents,'c(p,x,y)=[r,g,b]',
                End,
            End,
        End,
    End
    IF app <> NIL
        set(settings_win,MUIA_Window_DefaultObject,opened_lsv) -> This doesn't really work.

        doMethodA(settings_win,[MUIM_Notify,MUIA_Window_CloseRequest,MUI_TRUE,app,2,MUIM_Application_ReturnID,MUIV_Application_ReturnID_Quit])
        doMethodA(new_btn,     [MUIM_Notify,MUIA_Pressed,FALSE,opened_lst,1,MUIM_ProjectList_NewItem])
/*preferences*/

/*The settingswindow mcc-startup init is really unstable on my system, on some occasions it crashes, else not. So I have put a switch for
[de-]activating the preferences in picFX. When the noprefs file is present, the preferences will be deactivated and button disabled.
If noprefs is not present (rename the file), prefs are here as normally.*/

        IF (l:=Lock('PROGDIR:noprefs',ACCESS_READ)) -> Let's just hope that nobody is writing it right now ;-)
            set(prefs_btn,MUIA_Disabled,MUI_TRUE)
            UnLock(l)
        ELSE
            doMethodA(prefs_btn,   [MUIM_Notify,MUIA_Pressed,FALSE,prefs_win,3,MUIM_Set,MUIA_Window_Open,MUI_TRUE])
            doMethodA(mui_btn,     [MUIM_Notify,MUIA_Pressed,FALSE,app,1,MUIM_Application_OpenConfigWindow])

            doMethodA(prefs_win,   [MUIM_SettingsWindow_Notify,SETID_MainP,  MUIV_EveryTime,opened_lst,3,MUIM_ProjectList_SetPri,MUIV_ProjectList_SetPri_Main,MUIV_TriggerValue])
            doMethodA(prefs_win,   [MUIM_SettingsWindow_Notify,SETID_RenderP,MUIV_EveryTime,opened_lst,3,MUIM_ProjectList_SetPri,MUIV_ProjectList_SetPri_Render,MUIV_TriggerValue])
            doMethodA(prefs_win,   [MUIM_SettingsWindow_Notify,SETID_CurrP,  MUIV_EveryTime,opened_lst,3,MUIM_ProjectList_SetPri,MUIV_ProjectList_SetPri_Curr,MUIV_TriggerValue])
            doMethodA(prefs_win,   [MUIM_SettingsWindow_Notify,SETID_RUpd,   MUIV_EveryTime,opened_lst,3,MUIM_ProjectList_Prefs,{rupd},MUIV_TriggerValue])
            doMethodA(prefs_win,   [MUIM_SettingsWindow_Notify,SETID_Close,  MUIV_EveryTime,app,3,MUIM_WriteLong,MUIV_TriggerValue,{wclose}])
            doMethodA(prefs_win,[MUIM_SettingsWindow_Init,
                mainpri_sld,     MUIA_Slider_Level,SWIT_STANDARD,0,SETID_MainP,
                renderpri_sld,   MUIA_Slider_Level,SWIT_STANDARD,0,SETID_RenderP,
                currpri_sld,     MUIA_Slider_Level,SWIT_STANDARD,0,SETID_CurrP,
                renderupdate_sld,MUIA_Slider_Level,SWIT_STANDARD,0,SETID_RUpd,
                close_cyc,       MUIA_Cycle_Active,SWIT_STANDARD,0,SETID_Close,
                NIL])
        ENDIF
/*mainpri >= currpri >= renderpri*/
        doMethodA(mainpri_sld,[MUIM_Notify,MUIA_Slider_Level,MUIV_EveryTime,currpri_sld,2,MUIM_uSlider_Smaller,MUIV_TriggerValue])
        doMethodA(mainpri_sld,[MUIM_Notify,MUIA_Slider_Level,MUIV_EveryTime,renderpri_sld,2,MUIM_uSlider_Smaller,MUIV_TriggerValue])

        doMethodA(currpri_sld,[MUIM_Notify,MUIA_Slider_Level,MUIV_EveryTime,renderpri_sld,2,MUIM_uSlider_Smaller,MUIV_TriggerValue])
        doMethodA(currpri_sld,[MUIM_Notify,MUIA_Slider_Level,MUIV_EveryTime,mainpri_sld,2,MUIM_uSlider_Bigger,MUIV_TriggerValue])

        doMethodA(renderpri_sld,[MUIM_Notify,MUIA_Slider_Level,MUIV_EveryTime,mainpri_sld,2,MUIM_uSlider_Bigger,MUIV_TriggerValue])
        doMethodA(renderpri_sld,[MUIM_Notify,MUIA_Slider_Level,MUIV_EveryTime,currpri_sld,2,MUIM_uSlider_Bigger,MUIV_TriggerValue])

/*Every change to a gadget is sent to the ProjectList class*/
        doMethodA(name_str,    [MUIM_Notify,MUIA_String_Contents,MUIV_EveryTime,opened_lst,3,MUIM_ProjectList_Notify,MUIV_ProjectList_Notify_Name,MUIV_TriggerValue])
        doMethodA(type_reg,    [MUIM_Notify,MUIA_Group_ActivePage,MUIV_EveryTime,opened_lst,3,MUIM_ProjectList_Notify,MUIV_ProjectList_Notify_Type,MUIV_TriggerValue])
        doMethodA(path_str,    [MUIM_Notify,MUIA_String_Contents,MUIV_EveryTime,opened_lst,3,MUIM_ProjectList_Notify,MUIV_ProjectList_Notify_ImageFile,MUIV_TriggerValue])
        doMethodA(size_rad,    [MUIM_Notify,MUIA_Radio_Active,MUIV_EveryTime,opened_lst,3,MUIM_ProjectList_Notify,MUIV_ProjectList_Notify_LoadM,MUIV_TriggerValue])
        doMethodA(red_str,     [MUIM_Notify,MUIA_String_Acknowledge,MUIV_EveryTime,opened_lst,3,MUIM_ProjectList_Notify,MUIV_ProjectList_Notify_Red,MUIV_TriggerValue])
        doMethodA(green_str,   [MUIM_Notify,MUIA_String_Acknowledge,MUIV_EveryTime,opened_lst,3,MUIM_ProjectList_Notify,MUIV_ProjectList_Notify_Green,MUIV_TriggerValue])
        doMethodA(blue_str,    [MUIM_Notify,MUIA_String_Acknowledge,MUIV_EveryTime,opened_lst,3,MUIM_ProjectList_Notify,MUIV_ProjectList_Notify_Blue,MUIV_TriggerValue])
        doMethodA(outr_cyc,    [MUIM_Notify,MUIA_Cycle_Active,MUIV_EveryTime,opened_lst,3,MUIM_ProjectList_Notify,MUIV_ProjectList_Notify_OutputR,MUIV_TriggerValue])
        doMethodA(outg_cyc,    [MUIM_Notify,MUIA_Cycle_Active,MUIV_EveryTime,opened_lst,3,MUIM_ProjectList_Notify,MUIV_ProjectList_Notify_OutputG,MUIV_TriggerValue])
        doMethodA(outb_cyc,    [MUIM_Notify,MUIA_Cycle_Active,MUIV_EveryTime,opened_lst,3,MUIM_ProjectList_Notify,MUIV_ProjectList_Notify_OutputB,MUIV_TriggerValue])
        doMethodA(width_str,   [MUIM_Notify,MUIA_String_Acknowledge,MUIV_EveryTime,opened_lst,3,MUIM_ProjectList_Notify,MUIV_ProjectList_Notify_Width,MUIV_TriggerValue])
        doMethodA(height_str,  [MUIM_Notify,MUIA_String_Acknowledge,MUIV_EveryTime,opened_lst,3,MUIM_ProjectList_Notify,MUIV_ProjectList_Notify_Height,MUIV_TriggerValue])
/*If the active element of the Opened Projects List has changed, the gadgets must be refreshed*/
        doMethodA(opened_lst,  [MUIM_Notify,MUIA_List_Active,MUIV_EveryTime,opened_lst,1,MUIM_ProjectList_Refresh,0])
/*Action buttons:ProjectList class will forward those messages to the selected project*/
        doMethodA(draw_btn,    [MUIM_Notify,MUIA_Pressed,FALSE,opened_lst,2,MUIM_ProjectList_Forward,MUIM_PlaneFunc_Render])
        doMethodA(savepic_btn, [MUIM_Notify,MUIA_Pressed,FALSE,opened_lst,2,MUIM_ProjectList_Forward,MUIM_PlaneFunc_SavePic])
        doMethodA(savefunc_btn,[MUIM_Notify,MUIA_Pressed,FALSE,opened_lst,2,MUIM_ProjectList_Forward,MUIM_PlaneFunc_SaveFunc])
        doMethodA(loadfunc_btn,[MUIM_Notify,MUIA_Pressed,FALSE,opened_lst,2,MUIM_ProjectList_Forward,MUIM_PlaneFunc_LoadFunc])
        doMethodA(abort_btn,   [MUIM_Notify,MUIA_Pressed,FALSE,opened_lst,2,MUIM_ProjectList_Forward,MUIM_PlaneFunc_Abort])
        doMethodA(clear_btn,   [MUIM_Notify,MUIA_Pressed,FALSE,opened_lst,2,MUIM_ProjectList_Forward,MUIM_PlaneFunc_Clear])
/*since the address of the current project is variable I can't do direct notification. Instead, there are two methods for ProjectList.*/
        doMethodA(opened_lsv,  [MUIM_Notify,MUIA_Listview_DoubleClick,MUI_TRUE,showme_cyc,3,MUIM_Set,MUIA_Cycle_Active,1])
        doMethodA(showme_cyc,  [MUIM_Notify,MUIA_Cycle_Active,MUIV_EveryTime,opened_lst,2,MUIM_ProjectList_ShowMe,MUIV_TriggerValue])
        doMethodA(close_btn,   [MUIM_Notify,MUIA_Pressed,FALSE,opened_lst,1,MUIM_ProjectList_DelItem])

        set(settings_win,MUIA_Window_Open,MUI_TRUE)
        set(messages_win,MUIA_Window_Open,MUI_TRUE)

        doMethodA(opened_lst,MUIM_ProjectList_Memory)

        message(-1,cat.msgm_Welcome.getstr())

        WHILE Not(doMethodA(app,[MUIM_Application_NewInput,{sigs}]) = MUIV_Application_ReturnID_Quit)
            IF sigs THEN sigs := Wait(sigs)
        ENDWHILE

    ELSE
        WriteF(cat.msg_NoApp.getstr())
    ENDIF
EXCEPT DO
    IF app THEN Mui_DisposeObject(app)
    IF cl_planefunc THEN Mui_DeleteCustomClass(cl_planefunc)
    IF cl_projectlist THEN Mui_DeleteCustomClass(cl_projectlist)
    IF cl_uslider THEN Mui_DeleteCustomClass(cl_uslider)
    IF cl_sizetxt THEN Mui_DeleteCustomClass(cl_sizetxt)
    IF cl_myapp THEN Mui_DeleteCustomClass(cl_myapp)
    dCleanup()
    cleanfuncs()
    IF exception
        IF localebase
            WriteF(cat.msg_Nolib.getstr(),exception)
        ELSE
            WriteF('Failed to open \s.\n',exception)
        ENDIF
    ENDIF
    IF cybergfxbase  THEN CloseLibrary(cybergfxbase)
    IF datatypesbase THEN CloseLibrary(datatypesbase)
    IF muimasterbase THEN CloseLibrary(muimasterbase)
    IF pi96base      THEN CloseLibrary(pi96base)
    IF utilitybase   THEN CloseLibrary(utilitybase)
    cat.close()
    IF localebase THEN CloseLibrary(localebase)
ENDPROC                     

PROC message(id,info:PTR TO CHAR) -> Writes a message in the message-list
DEF t
    FOR t:=0 TO 13
        StrCopy(messages[t],messages[t+1]) -> Warning, the addresses mustn't change!
    ENDFOR
    StringF(messages[14],'[\d] \s',id,info)
    doMethodA(messages_lst,[MUIM_List_Redraw,MUIV_List_Redraw_All])
    StringF(title,'\d Message\c',counter++,-(counter<>2)*"s")     /*I will have to localize this, too!*/
ENDPROC

PROC messagefmt(id,info:PTR TO CHAR,arg1=0,arg2=0,arg3=0)
DEF s[100]:STRING
    StringF(s,info,arg1,arg2,arg3)
    message(id,s)
ENDPROC

/* geta4.e © Leon Woestenberg */

PROC storea4()
  LEA a4storage(PC),A0
  MOVE.L A4,(A0)
ENDPROC

PROC geta4()
  LEA a4storage(PC),A0
  MOVE.L (A0),A4
ENDPROC

a4storage:
  LONG NIL
