    /*\
     *  Autocad ADS library C++ link
     *  $Id: adsapp.cpp 1.1 1994/11/09 11:24:06 leon Exp leon $
    \*/

    // #define ADSDEBUG

    #include <algo.h> // stl

    #include "adsapp.hpp"

    #include <string.h>

    ADSFunction::ADSFunction(void (*pFunc)(), const char *name, short number)
       : name(name), number(number), pFunc(pFunc){}

    /**
     ** Na zahtevo sistema nalozi funkcije, ki smo jih registrirali s
     ** funkcijo Register. Funkcija je vitrualna in jo lahko uporabimo
     ** za zagon svojih funkcij, ki naj bi se izvedle ob zagonu z ukazom
     ** (xload "file.exp")
     **/
    short ADSApplication::load()
    {
      for (short i = 0; i < total; i++)
      fArray[i].load();
      return RTNORM;
    };

    /**
     ** Podobno kot funkcija load() se ta izvede, ko sistem zahteva
     ** brisanje aplikacije iz spomina. Funkcije se brisejo. Uporabnik
     ** pa lahko prepise (overloada) funkcijo s svojo, da pobrise za sabo
     ** vsa globalna polja, neshranjene podatke in podobno.
     **/
    short ADSApplication::unload()
    {
      for (short i = 0; i < total; i++)
        fArray[i].unload();
      return RTNORM;
    };

    /**
     ** Ko sistem AutoCad dobi ustrezen ukaz od Lisp-a se ugotovi, katera
     ** funkcija je to bila in jo izvrsi.
     **/
    short ADSApplication::execute()
    {
      int val;
      if ((val = ads_getfuncode ()) < 0)
        return 0;
      fArray[val].execute();
      return RTNORM;
    }

    /**
     ** Registrira funkcijo /func/ z imenom /funcName/ katerega lahko
     ** odtipkamo v ukazni vrstici.
     **/
    void ADSApplication::Register(void (*func)(), const char *funcName)
    {
      fArray.push_back(ADSFunction(func, funcName, total++));
    }

    /**
     ** Registrira aplikacijo  z imenom /appName/, da jo lahko uporabimo
     ** pri graditvi XDATA.
     **/
    void ADSApplication::Register(const char *appName)
    {
      struct resbuf *rb;
      if ((rb = ads_tblsearch("APPID", appName, 0)) == NULL)
        {
          if (ads_regapp(appName) != RTNORM)
            ads_printf("Can't register XDATA for %s.\n", appName);
        }
      else
        ads_relrb(rb);
    }
    /**
     ** Glavna funkcija za zagon aplikacije, ki vsebuje zanko za
     ** komunikacijo z AutoLispom. Argumenti /argc/ in /argv/ so
     ** isti kot pri funkciji main(int argc, char *argv[])
     **/
    void ADSApplication::Run(int argc, char *argv[])
    {
      int scode = RSRSLT;		// Normal result code (default)

      int stat;
      ads_init (argc, argv);	// Initiate communication with AutoLISP

      for (;;)
        {				/* Request/Result loop */
          if ((stat = ads_link (scode)) < 0)
    	      {
    	        cout << "Error: %d\n", stat;
              cout.flush();
    	        exit (1);
    	      }
          scode = RSRSLT;		// Reset result code

          switch (stat)
    	      {
    	      case RQXLOAD:		// Load & define functions

    	            scode = load () ? -RSRSLT : -RSERR;
                  initialize();
    	            break;

    	      case RQXUNLD:		// Unload functions

    	            scode = unload () ? -RSRSLT : -RSERR;
    	            break;

    	      case RQSUBR:		// Handle request for external function

    	            scode = execute () ? RSRSLT : RSERR;
    	            break;

    	      default:
    	            break;
    	      }
        }
    }

    static bool operator == (Control const *x, Control const &y)
    {
       return (*x).key == y.key;
    }

    void dispatch(ads_callback_packet *cbpkt)
    {
       char value[50];
       ads_get_attr_string(cbpkt->tile, "key", value, 50);

       const Control c(value);

       set <Control *, less<Control *> >::iterator i =
       find(Dialog::current->controls.begin(),
          Dialog::current->controls.end(), Control(value));

       Dialog::current->HandleMsg((*i)->cmdId, cbpkt);
    }

    Control::Control (const char *key,  int cmdId,
                         CLIENTFUNC callback)
    {
          Control::callback = callback;
          Control::key = key;
          Control::cmdId = cmdId;
    }

    //////////////////////////////////////////////////////////////////////////

    ListBox::ListBox(const ListBox& listbox)
    {
     copy(listbox.items.begin(), listbox.items.end(), items.begin() );
    }
    /**
     **Doda string /data/ na konec seznama za prikaz
     **/
    void ListBox::add(const char *data)
    {
      items.push_back(Item(data));
    }

    /**
     ** Zbrise obstoje"ci seznam in pripravi potrebno za novega
     **/
    void ListBox::newList()
    {
       items.erase(items.begin(), items.end());
    }

    /**
     ** Zahteva izris seznama v dialog oknu
     **/
    void ListBox::paint(ads_hdlg hdlg)
    {
      ads_start_list(hdlg, (char *)(const char *)key, LIST_NEW, 0);
      // items.forAll(paintItem, hdlg);

      for_each(items.begin(), items.end(), Item::paint);
      ads_printf("lb paint");
      ads_end_list();
    }

    /**
     ** Vrne /i/-ti string iz seznama
     **/
    const char * ListBox::GetString(int i)
    {
      return (const char *) items[i].item;
    }
    /**
     ** Izrise en string v dialog oknu
     **/
    void Item::paint(Item i)
    {
       ads_add_list((char *)(const char *)i.item);
    }

    //////////////////////////////////////////////////////////////////////

    /**
     ** Kreira novo polje za vnos z referenco /key/ in "stevilko sporo"cila
     ** /cmdId/. /defaultText/ je mo"zno uporabiti za prednastavljeni tekst,
     ** ki se prika"ze na Dialog oknu.
     **/
    EditBox::EditBox(const char *key, int cmdId, const char *defaultText)
      : Control(key, cmdId)
    {
      EditBox::defaultText = defaultText;
    }

    /**
     ** Izrise tekst v EditBox oknu
     **/
    void EditBox::paint(ads_hdlg hdlg)
    {
      ads_set_tile(hdlg, (char *)(const char *)key,
                    (char *)(const char *)defaultText);
    }

    /** Nastavi /defaultText/ na tekst /text/ **/
    void EditBox::Set(const char *text)
    {
      defaultText = text;
    }

    /////////////////////////////////////////////////////////

    Dialog *Dialog::current = NULL;

    #if 0

    /** {secret} **/
    void Dialog::addDialogControl(Control * data, void *hdlg)
    {
      ads_action_tile(*(ads_hdlg *)hdlg,
        (char *)(const char *)data->key, data->callback);
    }
    #endif

    /**
     ** Kreira dialog z imenom /filename/ datoteke .dcl z imenom dialoga
     ** /dialogKey/ in podrocjem pomoci /topic/.
     **/
    Dialog::Dialog(const char *filename, const char *dialogKey,
                   const char *topic)
    {
      previous = current;
      current = this;

      file = filename;
      Dialog::dialogKey = dialogKey;
      if (topic == NULL)
        helpTopic = dialogKey;
      current = this;
    }

    /** {duh} **/
    Dialog::~Dialog()
    {
      set <Control *, less<Control *> >::iterator i;

      for(i = controls.begin(); i != controls.end(); ++i)
          delete *i ;

      current = previous;
    }

    /**
     ** Podobno kot pri gumbih s to funkcijo tu prestrezamo sporo"cila
     ** za sezname (ListBox). /cmdId/ je "stevilka seznama, /cbpkt/ pa
     ** stuktura z informacijo o vrstici in na"cinu izbora, kot je to
     ** v normalnih /ADS callback/ funkcijah.
     **/
    void Dialog::HandleMsg(int cmdId, ads_callback_packet *cbpkt)
    {
    #ifdef ADSDEBUG

      ads_printf("ListBox with id: %d was selected with reason %d.\n",
                 cmdId, cbpkt->reason);
    #endif

      cmdId = 0;
      cbpkt = NULL;
    }

    /**
     ** Glavna funkcija za zagon Dialog okna, v kateri je zanka za prestrezanje
     ** in dispe"ciranje sporo"cil.
     **/
    void Dialog::Run()
    {

      ads_load_dialog((char *)(const char *)file, &dlgId);

      if (dlgId < 0)
        {
          ads_fail("Napaka pri odpiranju dialoga");
          return;
        }

      ads_new_dialog ((char *)(const char *)dialogKey, dlgId, NULLCB, &hdlg);

      if (hdlg == NULL)
        {
          ads_fail ("ads_new_dialog funkcija ni uspela");
          ads_unload_dialog (dlgId);
          return;
        }

      // add dialog controls

      set <Control *, less <Control *> >::iterator i;

      for(i = controls.begin(); i != controls.end(); ++i)
       {
          (*i)->paint(hdlg);
          (*i)->addTile(hdlg);
       }

      StartHook();

      status = DLGSTATUS;
      while (status >= DLGSTATUS)
        {
          ads_start_dialog (hdlg, &status);

          switch (status)
            {
            case DLGOK:
              Ok();
              break;
            case DLGCANCEL:
            case DLGALLDONE:
              Cancel();
              break;
            default:
              HandleMsg();
              break;
            }
         }
    //  ads_unload_dialog(dlgId);

      return;
    }

    #if 0

    /**
     ** S to funkcijo lahko registriramo funkcije kot je to normalno v ADS
     ** s /CALLB/ na"cinom. /tileFunc/ je ADSCALLBACK funkcija,
     ** ki se izvr"si ob dogodku /key/ v dialogu.
     **/
    void Dialog::Register(CLIENTFUNC tileFunc, const char *key)
    {
      Control *c = new Control(tileFunc, key);
      controls.insert(c);
    }

    /**  {duh} **/
    void Dialog::insert(ListBox listbox)
    {
      listboxes.push_back(listbox);
    }
    /** {duh} **/
    void Dialog::insert(EditBox editbox)
    {
      editboxes.insert(editbox);
    }

    #endif

    /**
     ** Dodajamo ukaze dialogu in s tem omogo"cimo izvr"sitev sporo"cila.
     **/
    void Dialog::insert(Control *control)
    {
      controls.insert(control);
    }

syntax highlighted by Code2HTML, v. 0.9.1