MODULE RawCx;
(*$ StackChk:=FALSE LargeVars:=FALSE StackParms:=FALSE Volatile:=FALSE *)

(* 18.5.91 Bernd Preusing, AMSoft *)

(*
   CX_PRIORITY=0
   CX_POPUP=YES
   CX_POPKEY=alt f5
 *)

(* Please only change parts between vvv^^^ rows! *)

(* vvvvvvvvvvvvvvvvvvvvv *)

(*$ DEFINE Window:=TRUE *) (* You need a Window? *)
(*$ DEFINE WSizing:=FALSE *) (* Window sizable? *)
(*$ DEFINE CSIGNAL:=FALSE *) (* You need a custom Signal? *)

(* ^^^^^^^^^^^^^^^^^^^^^ *)

FROM SYSTEM	IMPORT	ADR,ADDRESS,CAST,BITSET,LONGSET,TAG;
(*$ IF Window *)
FROM Cio	IMPORT	sprintf;
FROM String	IMPORT	Compare;
(*$ ENDIF *)
FROM ExecSupport IMPORT	CreatePort, DeletePort;
IMPORT
   A:  Arts,
   DD:DosD,
   ED:ExecD,
   EL:ExecL,
(*$ IF Window *)
   ID: IntuitionD,
   IL: IntuitionL,
   GD: GraphicsD,
   GrD: GraphicsD,
   GrL: GraphicsL,
   GtD:GadToolsD,
   GtL:GadToolsL,
(*$ ENDIF *)
   IE:InputEvent,
   CD:CommoditiesD,
   CL:CommoditiesL,
   CS:CommoditiesSupport;

CONST
  priorityToolType="CX_PRIORITY";
  (*$ IF Window *)
  popOnStartToolType="CX_POPUP";
  popKeyToolType="CX_POPKEY";
  (*$ ENDIF *)

  (* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv *)
  comName="Commodity";
  comTitle="Commodities Demo";
  comDescr="Does nothing";
  cxDefaultPriority=0;
  (*$ IF Window *)
    cxDefaultPopKey="alt f5";
    cxDefaultPopOnStart="YES";
    windowLeft=134;
    windowTop=64;
    windowWidth=450;
    windowHeight=68;
    windowInnerHeight=70;
    (*$ IF WSizing *)
      windowMinWidth=100;
      windowMaxWidth=-1;
      windowMinHeight=50;
      windowMaxHeight=-1;
      wFlags=ID.WindowFlagSet{ID.windowSizing,ID.activate,ID.windowClose,
			ID.windowDrag,ID.windowDepth,ID.simpleRefresh};
    (*$ ELSE *)
      windowMinWidth=windowWidth;
      windowMaxWidth=windowWidth;
      windowMinHeight=windowHeight;
      windowMaxHeight=windowHeight;
      wFlags=ID.WindowFlagSet{ID.activate,ID.windowClose,
			ID.windowDrag,ID.windowDepth,ID.simpleRefresh};
    (*$ ENDIF *)

    iFlags=ID.IDCMPFlagSet{ID.menuPick,ID.mouseButtons,ID.gadgetUp,ID.gadgetDown,
		ID.mouseMove,ID.closeWindow,ID.refreshWindow};

    popKeyID=86; (* warum? *)

    gadHide=1;
    gadDie=2;

    menuHide=1;
    menuDie=2;


  (*$ ENDIF *)
  (* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ *)

TYPE
  Str255=ARRAY [0..255] OF CHAR;
  Str255Ptr=POINTER TO Str255;

VAR
  (*$ LongAlign:=TRUE *)
  tBuff:ARRAY[1..10] OF LONGINT;
  cxport:ED.MsgPortPtr;
  broker:CD.CxObjPtr; (* Our broker *)
  hotkeybuff:Str255; (* for showing the user the hotkey *)
  mynb:CD.NewBroker;
  cxsignal:SHORTINT;
  (*$ IF CSIGNAL *)
  csignal:SHORTINT;
  (*$ ENDIF *)
(*$ IF Window *)
  (* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv *)
  mydesiredfont:=GrD.TextAttr{name:ADR("topaz.font"),ySize:8};
  (* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ *)

  (*$ LongAlign:=TRUE *)
  window:ID.WindowPtr;
  vi: ADDRESS;
  myscreen:ID.ScreenPtr;
  topborder:INTEGER;
  font:GD.TextFontPtr;
  glist:ID.GadgetPtr;
  menu:ID.MenuPtr;
  mydi:ID.DrawInfoPtr;
  iport:ED.MsgPortPtr;
  (*$ LongAlign:=FALSE *)
  menuattached:BOOLEAN;
  IDCMPRefresh:BOOLEAN;
  isignal:SHORTINT;
  savewindow:RECORD left,top,width,height:INTEGER END;
  windowTitle:ARRAY[0..127] OF CHAR;
(*$ ENDIF *)

(*$ IF Window *)

PROCEDURE shutdownWindow(); FORWARD;

(* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv *)

PROCEDURE setupCustomGadgets(VAR gad:ID.GadgetPtr);
VAR
  ng:GtD.NewGadget;
BEGIN
  ng.topEdge:=topborder;
  ng.leftEdge:=10;
  ng.width:=40;
  ng.height:=12;
  ng.gadgetText:=ADR("Hide");
  ng.textAttr:=ADR(mydesiredfont);
  ng.gadgetID:=gadHide;
  ng.flags:=GtD.NewGadgetFlagSet{};
  ng.visualInfo:=vi;
  gad:=GtL.CreateGadgetA(GtD.buttonKind,gad^,ng,TAG(tBuff,0));

  ng.topEdge:=topborder+15;
  ng.gadgetText:=ADR("Die");
  ng.gadgetID:=gadDie;
  gad:=GtL.CreateGadgetA(GtD.buttonKind,gad^,ng,TAG(tBuff,0));
END setupCustomGadgets;

PROCEDURE HandleGadget(id:INTEGER; code:CARDINAL);
BEGIN
  CASE id OF
  | gadHide:
	shutdownWindow;
  | gadDie:
	A.Terminate;
  |ELSE
	A.BreakPoint(ADR("wrong gad id!"));
  END;
END HandleGadget;

TYPE
  NmArr=ARRAY[1..4] OF GtD.NewMenu;
VAR
  mynewmenu:=NmArr{
    GtD.NewMenu{type:GtD.nmTitle,label:ADR("Project")},
    GtD.NewMenu{type:GtD.nmItem, label:ADR("Hide"), commKey:ADR("H"),userData:menuHide},
    GtD.NewMenu{type:GtD.nmItem, label:ADR("Die"),  commKey:ADR("Q"),userData:menuDie},
    GtD.NewMenu{type:GtD.nmEnd}
  };

PROCEDURE setupCustomMenu();
BEGIN
  menu:=GtL.CreateMenusA(ADR(mynewmenu),TAG(tBuff,0));
END setupCustomMenu;

PROCEDURE handleCustomMenu(code:CARDINAL);
TYPE
  ExtMenuItemPtr=POINTER TO RECORD
    i:ID.MenuItem;
    userData:LONGINT;
  END;
VAR
  item:ExtMenuItemPtr;
  terminated:BOOLEAN;
BEGIN
  terminated:=FALSE;
  WHILE (code#ID.menuNull) & ~terminated DO
    item:=CAST(ExtMenuItemPtr,IL.ItemAddress(menu,code));
    CASE item^.userData OF
    | menuHide:
	shutdownWindow;
	terminated:=TRUE;
    | menuDie:
	A.Terminate;
    | ELSE
	A.BreakPoint(ADR("illegal menucode"));
    END;
    code:=item^.i.nextSelect;
  END;
END handleCustomMenu;

PROCEDURE refreshWindow();
VAR
BEGIN
  IF window#NIL THEN
    IF IDCMPRefresh THEN
      GtL.GTBeginRefresh(window)
    END;
    (* Own refresh here *)
    IF IDCMPRefresh THEN
      GtL.GTEndRefresh(window,TRUE);
    END;
    IF topborder+windowInnerHeight>window^.height THEN
      IL.RefreshWindowFrame(window)
    END;
  END;
END refreshWindow;

(*$ ENDIF *) (* Window *)


PROCEDURE setupCustomCx():BOOLEAN;
BEGIN
  (* beliebige Filter, Customs etc erzeugen *)
  RETURN TRUE; (* Error wird gleich gecheckt! *)
END setupCustomCx;

PROCEDURE shutdownCustomCx;
BEGIN
  (* setup wieder löschen, soweit nicht durch DelAll getan *)
END shutdownCustomCx;

PROCEDURE handleCustomCxMsg(id:LONGCARD);
BEGIN
  (* eigene auswerten
  CASE id OF
  | 0:
  | 1:
  |ELSE
  END;
  *)
END handleCustomCxMsg;

PROCEDURE handleCustomCxCommand(id:LONGINT);
BEGIN

END handleCustomCxCommand;

(*$ IF CSIGNAL *)
PROCEDURE handleCustomSignal();
BEGIN
END handleCustomSignal;
(*$ ENDIF *)

(* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ *)
(*$ IF Window *)

PROCEDURE getNewWindow():ID.WindowPtr;
VAR
  nw:ID.NewWindow;
  tBuff:ARRAY[0..6] OF LONGINT;
BEGIN
  sprintf(windowTitle,"%s: HotKey=%s",TAG(tBuff,ADR(comTitle),ADR(hotkeybuff)));
  nw.leftEdge:=savewindow.left;
  nw.topEdge:=savewindow.top;
  nw.width:=savewindow.width;
  nw.height:=savewindow.height;
  nw.detailPen:=-1;
  nw.blockPen:=-1;
  nw.idcmpFlags:=iFlags;
  nw.flags:=wFlags;
  nw.firstGadget:=NIL;
  nw.checkMark:=NIL;
  nw.title:=ADR(windowTitle);
  nw.screen:=NIL;
  nw.bitMap:=NIL;
  nw.minWidth:=windowMinWidth;
  nw.minHeight:=windowMinHeight;
  nw.maxWidth:=windowMaxWidth;
  nw.maxHeight:=windowMaxHeight;
  nw.type:=ID.ScreenFlagSet{ID.wbenchScreen};
  RETURN IL.OpenWindowTagList(ADR(nw),TAG(tBuff,
	ID.waInnerHeight, windowInnerHeight,
	ID.waAutoAdjust,  TRUE,
	ID.waPubScreen,   myscreen,
	0));
END getNewWindow;

PROCEDURE removeGadgets;
VAR
BEGIN
  IF glist#NIL THEN
    GtL.FreeGadgets(glist);
    glist:=NIL;
  END;
  IF font#NIL THEN
    GrL.CloseFont(font);
    font:=NIL
  END;
END removeGadgets;

PROCEDURE addGadgets(w:ID.WindowPtr):BOOLEAN;
VAR
  gad:ID.GadgetPtr;
BEGIN
  IF font=NIL THEN
    font:=GrL.OpenFont(ADR(mydesiredfont));
    IF font=NIL THEN RETURN FALSE END;
  END;
  gad:=GtL.CreateContext(glist);
  setupCustomGadgets(gad);
  IF gad=NIL THEN
    IF glist#NIL THEN
      GtL.FreeGadgets(glist);
      glist:=NIL;
    END;
    IF font#NIL THEN
      GrL.CloseFont(font);
      font:=NIL;
    END;
    RETURN FALSE
  END;
  IF IL.AddGList(window,glist,-1,-1,NIL)=0 THEN END;
  IL.RefreshGList(window^.firstGadget,window,NIL,-1);
  GtL.GTRefreshWindow(window,NIL);
  RETURN TRUE;
END addGadgets;

PROCEDURE setupWindow;
VAR
  tagBuff:LONGINT;
BEGIN
  IF window#NIL THEN
    IL.WindowToFront(window);
    RETURN
  END;
  tagBuff:=0;
  IF myscreen=NIL THEN
    myscreen:=IL.LockPubScreen(NIL);
    IF myscreen=NIL THEN RETURN END;
  END;
  IF mydi=NIL THEN
    mydi:=IL.GetScreenDrawInfo(myscreen);
    IF mydi=NIL THEN RETURN END;
  END;
  topborder:=myscreen^.wBorTop+INTEGER(myscreen^.font^.ySize)+1;
  IF vi=NIL THEN
    vi:=GtL.GetVisualInfoA(myscreen,ADR(tagBuff));
    IF vi=NIL THEN RETURN END;
  END;
  window:=getNewWindow();
  IF window=NIL THEN RETURN END;
  iport:=window^.userPort;
  isignal:=iport^.sigBit;
  IF ~addGadgets(window) THEN
    shutdownWindow;
    RETURN;
  END;
  setupCustomMenu;
  IF menu#NIL THEN
    IF ~GtL.LayoutMenusA(menu,vi,ADR(tagBuff)) THEN END;
  END;
  menuattached:=IL.SetMenuStrip(window,menu);
  refreshWindow;
END setupWindow;

PROCEDURE shutdownWindow();
VAR
BEGIN
  IF window=NIL THEN
    RETURN
  END;
  savewindow.left:=window^.leftEdge;
  savewindow.top:=window^.topEdge;
  savewindow.width:=window^.width;
  savewindow.height:=window^.height;
  IF menuattached THEN
    IL.ClearMenuStrip(window);
    menuattached:=FALSE;
  END;
  IF menu#NIL THEN
    GtL.FreeMenus(menu);
    menu:=NIL
  END;
  IL.CloseWindow(window);
  window:=NIL;
  iport:=NIL;
  isignal:=cxsignal; (* Achtung bei Wait() sonst Trap #14 ! *)

  removeGadgets;

  IF vi#NIL THEN
    GtL.FreeVisualInfo(vi);
    vi:=NIL;
  END;
  IF mydi#NIL THEN
    IL.FreeScreenDrawInfo(myscreen,mydi);
    mydi:=NIL
  END;
  IF myscreen#NIL THEN
    IL.UnlockPubScreen(NIL,myscreen);
    myscreen:=NIL
  END;
END shutdownWindow;

PROCEDURE handleIMsg(i:ID.IntuiMessagePtr);
VAR
  class:ID.IDCMPFlagSet;
  code:CARDINAL;
  gaddress:ID.GadgetPtr;
BEGIN
  class:=i^.class;
  code:=i^.code;
  gaddress:=CAST(ID.GadgetPtr,i^.iAddress);
  GtL.GTReplyIMsg(i);

  IF class=ID.IDCMPFlagSet{ID.closeWindow} THEN
    shutdownWindow;
  ELSIF class=ID.IDCMPFlagSet{ID.refreshWindow} THEN
    IDCMPRefresh:=TRUE;
    refreshWindow;
    IDCMPRefresh:=FALSE;
  ELSIF class=ID.IDCMPFlagSet{ID.menuPick} THEN
    handleCustomMenu(code);
  ELSIF class=ID.IDCMPFlagSet{ID.gadgetUp} THEN
    HandleGadget(gaddress^.gadgetID,code);
  END;
END handleIMsg;

(*$ ENDIF *) (* Window *)

PROCEDURE handleCxMsg(msg:ED.MessagePtr);
VAR
  msgid:LONGINT;
  msgtype:LONGCARD;
BEGIN
  msgid:=CL.CxMsgID(CAST(CD.CxMsgPtr,msg));
  msgtype:=CL.CxMsgType(CAST(CD.CxMsgPtr,msg));
  EL.ReplyMsg(msg);
  IF msgtype=CD.cxmIevent THEN
    (*$ IF Window *)
      IF msgid=popKeyID THEN
        setupWindow;
      ELSE
        handleCustomCxMsg(msgid);
      END;
    (*$ ELSE *)
      handleCustomCxMsg(msgid);
    (*$ ENDIF *)
  ELSIF msgtype=CD.cxmCommand THEN
    IF msgid=CD.cxcmdDisable THEN
      IF CL.ActivateCxObj(broker,FALSE) THEN END;
    ELSIF msgid=CD.cxcmdEnable THEN
      IF CL.ActivateCxObj(broker,TRUE) THEN END;
    ELSIF (msgid=CD.cxcmdAppear) OR (msgid=CD.cxcmdUnique) THEN
      (*$ IF Window *)
        setupWindow;
      (*$ ELSE *)
        A.Terminate;
      (*$ ENDIF *)
    ELSIF msgid=CD.cxcmdDisappear THEN
      (*$ IF Window *)
        shutdownWindow;
      (*$ ENDIF *)
    ELSIF msgid=CD.cxcmdKill THEN
      A.Terminate
    ELSE
      handleCustomCxCommand(msgid);
    END;
  END; (* else nix? *)
END handleCxMsg;

PROCEDURE shutdownCx();
VAR
  msg:ED.MessagePtr;
BEGIN
  shutdownCustomCx;
  IF cxport#NIL THEN
    CL.DeleteCxObjAll(broker);
    LOOP
      msg:=EL.GetMsg(cxport);
      IF msg=NIL THEN EXIT END;
      EL.ReplyMsg(cxport);
    END;
    DeletePort(cxport);

    cxport:=NIL;
    cxsignal:=-1;
    CAST(ADDRESS,broker):=NIL;
  END;
END shutdownCx;


PROCEDURE setupCx():BOOLEAN;
VAR
  error:LONGCARD;
  (*$ IF Window *)
  str:Str255Ptr;
  (*$ ENDIF *)
  coerr:CD.CoErrorSet;
BEGIN
  shutdownCx;
  cxport:=CreatePort(mynb.name,0);
  IF cxport=NIL THEN
    RETURN FALSE
  END;
  cxsignal:=cxport^.sigBit;
  mynb.pri:=CS.ArgInt(ADR(priorityToolType),cxDefaultPriority);
  mynb.port:=cxport;

  (*$ IF Window *)
    (*INCL(mynb.flags,CD.cofShowHide);*)
    mynb.flags:=CD.NewBrokerFlagSet{CD.cofShowHide};
  (*$ ENDIF *)

  broker:=CL.CxBroker(mynb,error);
  IF broker=NIL THEN
    shutdownCx;
    RETURN FALSE
  END;

  (*$ IF Window *)
    str:=CS.ArgString(ADR(popKeyToolType),ADR(cxDefaultPopKey));
    CL.AttachCxObj(broker,CS.HotKey(str,cxport,popKeyID));
    hotkeybuff:=str^;
  (*$ ENDIF *)

  IF ~setupCustomCx() THEN
    shutdownCx;
    RETURN FALSE
  END;

  coerr:=CL.CxObjError(broker);
  IF coerr#CD.CoErrorSet{} THEN
    shutdownCx;
    RETURN FALSE
  END;

  IF CL.ActivateCxObj(broker,TRUE) THEN END;
  RETURN TRUE;
END setupCx;

PROCEDURE main();
VAR
  sigrcvd:LONGSET;
  msg:ADDRESS;
  (*$ IF Window *)
  str:Str255Ptr;
  (*$ ENDIF *)
BEGIN
  (*$ IF CSIGNAL *)
  csignal:=EL.AllocSignal(-1);
  IF csignal=-1 THEN
    A.Terminate
  END;
  (*$ ENDIF *)
  IF ~setupCx() THEN
    A.Terminate;
  END;
  (*$ IF Window *)
  str:=CS.ArgString(ADR(popOnStartToolType),ADR(cxDefaultPopOnStart));
  IF Compare(str^,"YES")=0 THEN
    setupWindow;
  END;
  (*$ ENDIF *)
  LOOP (* exit by terminate *)
    sigrcvd:=EL.Wait(LONGSET{DD.ctrlE (*$ IF Window *),isignal (*$ ENDIF *),cxsignal
				(*$ IF CSIGNAL *),csignal (*$ ENDIF *)});
    IF DD.ctrlE IN sigrcvd THEN
      A.Terminate
    (*$ IF CSIGNAL *)
    ELSIF csignal IN sigrcvd THEN
      handleCustomSignal
    (*$ ENDIF *)
    END;
    LOOP
      IF cxport=NIL THEN EXIT END;
      msg:=EL.GetMsg(cxport);
      IF msg=NIL THEN EXIT END;
      handleCxMsg(msg);
    END;
    (*$ IF Window *)
    LOOP
      IF iport=NIL THEN EXIT END;
      msg:=GtL.GTGetIMsg(iport);
      IF msg=NIL THEN EXIT END;
      handleIMsg(msg);
    END;
    (*$ ENDIF *)
  END; (* LOOP *)

END main;

PROCEDURE terminate();
BEGIN
  shutdownCx;
  (*$ IF Window *)
  shutdownWindow;
  (*$ ENDIF *)
  (*$ IF CSIGNAL *)
  IF csignal#-1 THEN
    EL.FreeSignal(csignal);
    csignal:=-1
  END;
  (*$ ENDIF *)
END terminate;


BEGIN
  (*$ IF Window *)
  savewindow.left:=windowLeft;
  savewindow.top:=windowTop;
  savewindow.width:=windowWidth;
  savewindow.height:=windowHeight;
  (*$ ENDIF *)
  (*$ IF CSIGNAL *)
  csignal:=1;
  (*$ ENDIF *)
  mynb.version:=CD.nbVersion;
  mynb.name:=ADR(comName);
  mynb.title:=ADR(comTitle);
  mynb.descr:=ADR(comDescr);
  mynb.unique:=CD.nbuUnique+CD.nbuNotify;
  (* Rest bleibt NIL oder 0 *)
  main;
CLOSE
  terminate;
END RawCx.
