home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / wps / games / spl / src / spl.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-10  |  48.9 KB  |  1,985 lines

  1. /* spl.cpp:  Spellbook control program
  2.  
  3.     Copyright (C) 1993 John-Marc Chandonia
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 2 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19.  
  20. #define VERSION "1.0, 8/10/93"
  21.  
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #define INCL_WIN
  26. #define INCL_GPI
  27. #define INCL_WINSTDFILE
  28. #define INCL_DOSPROCESS
  29. #include <os2.h>
  30. #include "general.hpp"
  31. #include "splbook.hpp"
  32. #include "spl.h"
  33. #include "spldlg.h"
  34.  
  35. MRESULT EXPENTRY window_func(HWND, ULONG, MPARAM, MPARAM);
  36.  
  37. ULONG flFlags;  // window frame declaration 
  38. unsigned char spbclass[] = "Spellbookwindow";  // class name 
  39. unsigned char splclass[] = "Spellwindow";  // class name 
  40. HAB hand_ab;  // anchor block 
  41. BYTE xfer_buffer[10240];
  42. CNRINFO cnrInfo;
  43.  
  44. // table of icons for various schools and spheres.
  45. int icons;
  46. HPOINTER *icontable;
  47. char **icontext;
  48.  
  49. // icon for dragging
  50. HPOINTER dragicon;
  51.  
  52. int windows=1000;
  53. spellbook *masterlist;
  54.  
  55. // spell record 
  56. typedef struct spellrecord {
  57.     RECORDCORE core;
  58.     spell *s;  // the spell
  59.     spelllist *spl;  // where the spell is in the spellbook
  60. } spellrecord;
  61.  
  62. // set up the icon table and the drag icon.
  63. void setupicons() {
  64.     FILE *infile;
  65.     char buffer[256];
  66.     int i,j,k;
  67.  
  68.     dragicon=WinLoadFileIcon((PSZ)"spl.ico",FALSE);
  69.  
  70.     // get spell icons out of file.
  71.     icons=0;
  72.     if ((infile=fopen(ICONFILE,"r"))==NULL) return;
  73.  
  74.     // count lines
  75.     while (!feof(infile)) {
  76.     fgets(buffer,256,infile);
  77.     if ((buffer[0]!=';') && (strlen(buffer)>2)) {
  78.         icons++;
  79.     }
  80.     }
  81.     rewind(infile);
  82.  
  83.     icontable=new HPOINTER[icons];
  84.     icontext=new PCHAR[icons];
  85.  
  86.     for (i=0; i<icons; i++) {
  87.     do {
  88.         fgets(buffer,256,infile);
  89.     } while ((buffer[0]==';') || (strlen(buffer)<=2));
  90.  
  91.     // get rid of \n
  92.     buffer[strlen(buffer)-1]=(char)0;
  93.  
  94.     // find first space in line
  95.     if (strchr(buffer,' ')==NULL) {
  96.         icons=0;
  97.         return;
  98.     }
  99.     // with no error handling whatsoever!
  100.     j=strlen(buffer)-strlen(strchr(buffer,' '));
  101.     icontext[i]=new char[j+1];
  102.     icontext[i][j]=(char)0;
  103.     strncpy(icontext[i],buffer,j);
  104.     icontable[i]=WinLoadFileIcon((PSZ)(buffer+j+1),FALSE);
  105.     }
  106. }
  107.  
  108. // return the appropriate icon for a spell, from the icon table
  109. HPOINTER lookup_icon(spell *s) {
  110.     magespell *ms;
  111.     priestspell *ps;
  112.     int i;
  113.  
  114.     // if a priest spell, try to look it up by sphere
  115.     if (s->type=='P') {
  116.     ps=(priestspell *)s;
  117.     if (ps->sphere) {
  118.         for (i=0; i<icons; i++) 
  119.         if (strstr(ps->sphere,icontext[i])!=0)
  120.             return(icontable[i]);
  121.     }
  122.     }
  123.  
  124.     // try looking it up by school.
  125.     if ((s->type=='M') || (s->type=='P')) {
  126.     ms=(magespell *)s;
  127.     if (ms->school) {
  128.         for (i=0; i<icons; i++) 
  129.         if (strstr(ms->school,icontext[i])!=0)
  130.             return(icontable[i]);
  131.     }
  132.     }
  133.  
  134.     // return generic icon if nothing else works.
  135.     return(dragicon);
  136. }
  137.  
  138. // print copyleft notice
  139. void copyleft() {
  140.     int i;
  141.  
  142.     sprintf((char *)xfer_buffer,"spl version %s\n",VERSION);
  143.     i=strlen((char *)xfer_buffer);
  144.     sprintf((char *)xfer_buffer+i,"Copyright (C) 1993 John-Marc Chandonia\n");
  145.     i=strlen((char *)xfer_buffer);
  146.     sprintf((char *)xfer_buffer+i,"spl comes with ABSOLUTELY NO WARRANTY; ");
  147.     i=strlen((char *)xfer_buffer);
  148.     sprintf((char *)xfer_buffer+i,"for details see license.txt.\n");
  149.     i=strlen((char *)xfer_buffer);
  150.     sprintf((char *)xfer_buffer+i,"This is free software, and you are welcome to redistribute ");
  151.     i=strlen((char *)xfer_buffer);
  152.     sprintf((char *)xfer_buffer+i,"it under certain conditions; see license.txt for details.\n");
  153.  
  154.     i=strlen((char *)xfer_buffer);
  155.     WinMessageBox(HWND_DESKTOP,
  156.           HWND_DESKTOP,
  157.           (PSZ)xfer_buffer,
  158.           (PSZ)"Copyright Notice",
  159.           102,
  160.           MB_OK);
  161. }
  162.  
  163. // a spellbook window class 
  164. class spellwindow {
  165. public:
  166.     // handles for all relevant windows 
  167.     HWND hwndbook;  // main window
  168.     HWND hwndframe;  // frame window
  169.     HWND hwndcnr;  // container window
  170.     
  171.     // one spellbook per window.
  172.     spellbook *sb;
  173.  
  174.     // has it been saved?
  175.     boolean saved;
  176.  
  177.     // is is changeable?
  178.     boolean readonly;
  179.  
  180.     // maintain double linked list 
  181.     spellwindow *next;
  182.     spellwindow *prev;
  183.  
  184.     spellwindow(char *bookname="New Spellbook");
  185.     ~spellwindow();
  186.  
  187.     boolean save_titles();
  188.     boolean save_book();
  189.     boolean load_book();
  190.     boolean load_titles();
  191.     boolean set_spellbook(spellbook *);
  192.     boolean sort_book();
  193.  
  194.     boolean add_spell(spell *s, spellrecord *where=NULL);
  195.     boolean add_new_spell();
  196.     boolean delete_spell(spellrecord *s);
  197.     boolean delete_selected_spells();
  198.     boolean change_spell(spell *oldsp, spell *newsp);
  199.     boolean refresh();  // redraw the window after adding or deleting spells.
  200. };
  201.  
  202. spellwindow *first=NULL;  /* pointer to first spell window;
  203.                  must be most recently created one */
  204.  
  205. spellwindow::spellwindow(char *bookname) {    
  206.     // add new window as the first one
  207.     next=first;
  208.     if (first!=NULL) first->prev=this;
  209.     first=this;
  210.     prev=NULL;
  211.     saved=true;
  212.     readonly=false;
  213.     hwndcnr=NULL;
  214.     hwndbook=NULL;
  215.     sb = new spellbook;
  216.     sb->name = strdup(bookname);
  217.  
  218.     // create the window -- requires first to point to this window!
  219.     hwndframe = WinCreateStdWindow(
  220.                    HWND_DESKTOP,
  221.                    WS_VISIBLE,
  222.                    &flFlags,
  223.                    (PSZ)spbclass,
  224.                    (PSZ)bookname,
  225.                    WS_VISIBLE,
  226.                    0,
  227.                    BOOKMENU,
  228.                    NULL);
  229. }
  230.  
  231. spellwindow::~spellwindow() {
  232.     // remove from linked list
  233.     if (this==first) first=next;
  234.     if (next!=NULL) next->prev=prev;
  235.     if (prev!=NULL) prev->next=next;
  236.  
  237.     delete sb; // but not the spells inside!
  238.  
  239.     // remove from display
  240.     WinDestroyWindow(hwndframe);
  241. }
  242.  
  243.  
  244. // look up the spell window associated with a given book handle 
  245. spellwindow *windowof(HWND b) {
  246.     spellwindow *x;
  247.     for (x=first; x!=NULL; x=x->next) 
  248.     if (x->hwndbook==b) return(x);
  249.  
  250.     return(NULL);
  251. }
  252.  
  253. // save spellbook as list of spells.
  254. boolean spellwindow::save_titles() {
  255.     FILEDLG fd;
  256.     char filename[CCHMAXPATH]="*.lst";
  257.  
  258.     // clear all fields to zero before proceeding
  259.     memset(&fd,0,sizeof(FILEDLG));
  260.  
  261.     // set up file dialog
  262.     fd.cbSize=sizeof(FILEDLG);
  263.     fd.fl=FDS_CENTER|FDS_SAVEAS_DIALOG;
  264.     fd.pszTitle=(PSZ)"Save spellbook to file:";
  265.     strcpy(fd.szFullFile,filename);
  266.  
  267.     if (!WinFileDlg(HWND_DESKTOP,
  268.             hwndbook,
  269.             &fd)) return(false);
  270.  
  271.     if (fd.lReturn==DID_OK) {
  272.       sb->print_titles(fd.szFullFile);
  273.       saved=true;
  274.       return(true);
  275.     }
  276.     else return(false);
  277. }
  278.  
  279. // print entire spellbook to file.
  280. boolean spellwindow::save_book() {
  281.     FILEDLG fd;
  282.     char filename[CCHMAXPATH]="*.sbk";
  283.  
  284.     // clear all fields to zero before proceeding
  285.     memset(&fd,0,sizeof(FILEDLG));
  286.  
  287.     // set up file dialog
  288.     fd.cbSize=sizeof(FILEDLG);
  289.     fd.fl=FDS_CENTER|FDS_SAVEAS_DIALOG;
  290.     fd.pszTitle=(PSZ)"Print spellbook to file:";
  291.     strcpy(fd.szFullFile,filename);
  292.  
  293.     if (!WinFileDlg(HWND_DESKTOP,
  294.             hwndbook,
  295.             &fd)) return(false);
  296.  
  297.     if (fd.lReturn==DID_OK) {
  298.       sb->print_book(fd.szFullFile);
  299.       return(true);
  300.     }
  301.     else return(false);
  302. }
  303.  
  304. // load a spellbook from a file, add to spellbook in window.
  305. boolean spellwindow::load_book() {
  306.     FILEDLG fd;
  307.     char filename[CCHMAXPATH]="*.sbk";
  308.     spellbook *newsb;
  309.     spelllist *i;
  310.  
  311.     // clear all fields to zero before proceeding
  312.     memset(&fd,0,sizeof(FILEDLG));
  313.  
  314.     // set up file dialog
  315.     fd.cbSize=sizeof(FILEDLG);
  316.     fd.fl=FDS_CENTER|FDS_OPEN_DIALOG;
  317.     fd.pszTitle=(PSZ)"Load spellbook from file:";
  318.     strcpy(fd.szFullFile,filename);
  319.  
  320.     if (!WinFileDlg(HWND_DESKTOP,
  321.             hwndbook,
  322.             &fd)) return(false);
  323.  
  324.     if (fd.lReturn==DID_OK) {
  325.     newsb=new spellbook;
  326.     newsb->read_book(fd.szFullFile);
  327.  
  328.     // add new spells to my window, at end.
  329.     for (i=newsb->first; i!=NULL; i=i->next)
  330.         add_spell(i->s);
  331.     delete newsb;
  332.     
  333.     refresh();
  334.  
  335.     // change name of book to book just read.
  336.     if (newsb->name) {
  337.         delete (sb->name);
  338.         sb->name=strdup(newsb->name);
  339.         WinSetWindowText(hwndframe,(PSZ)sb->name);
  340.     }
  341.     saved=true;
  342.  
  343.     return(true);
  344.     }
  345.     else return(false);
  346. }
  347.  
  348. // load a spellbook from a file of titles, add to spellbook in window.
  349. boolean spellwindow::load_titles() {
  350.     FILEDLG fd;
  351.     char filename[CCHMAXPATH]="*.lst";
  352.     spellbook *newsb;
  353.     spelllist *i;
  354.  
  355.     // clear all fields to zero before proceeding
  356.     memset(&fd,0,sizeof(FILEDLG));
  357.  
  358.     // set up file dialog
  359.     fd.cbSize=sizeof(FILEDLG);
  360.     fd.fl=FDS_CENTER|FDS_OPEN_DIALOG;
  361.     fd.pszTitle=(PSZ)"Load spellbook from file:";
  362.     strcpy(fd.szFullFile,filename);
  363.  
  364.     if (!WinFileDlg(HWND_DESKTOP,
  365.             hwndbook,
  366.             &fd)) return(false);
  367.  
  368.     if (fd.lReturn==DID_OK) {
  369.     newsb=new spellbook;
  370.     newsb->read_titles(fd.szFullFile,masterlist);
  371.  
  372.     // add new spells to my window, at end.
  373.     for (i=newsb->first; i!=NULL; i=i->next)
  374.         add_spell(i->s);
  375.     delete newsb;
  376.  
  377.     refresh();
  378.     
  379.     // change name of book to book just read.
  380.     if (newsb->name) {
  381.         delete (sb->name);
  382.         sb->name=strdup(newsb->name);
  383.         WinSetWindowText(hwndframe,(PSZ)sb->name);
  384.     }
  385.  
  386.     saved=true;
  387.     return(true);
  388.     }
  389.     else return(false);
  390. }
  391.  
  392. // set window to a given spellbook
  393. boolean spellwindow::set_spellbook(spellbook *x) {
  394.     spellrecord *deleteme;
  395.     spelllist *i;
  396.  
  397.     // clear old spellbook, and window
  398.     while (deleteme=(spellrecord *)
  399.        WinSendMsg(hwndcnr,
  400.               CM_QUERYRECORD,
  401.               0,
  402.               MPFROM2SHORT(CMA_FIRST,CMA_ITEMORDER)))
  403.        delete_spell(deleteme);
  404.        
  405.     // add new spells to my window, at end.
  406.     for (i=x->first; i!=NULL; i=i->next)
  407.        add_spell(i->s);
  408.     
  409.     // change name of book to book just read.
  410.     if (x->name) {
  411.     delete (sb->name);
  412.     sb->name=strdup(x->name);
  413.     WinSetWindowText(hwndframe,(PSZ)sb->name);
  414.     }
  415.     
  416.     refresh();
  417.  
  418.     saved=true;
  419.     return(true);
  420. }
  421.  
  422. // sort function:  mage, then priest in alphabetical order.
  423. SHORT APIENTRY spell_order(PRECORDCORE prc1, PRECORDCORE prc2, PVOID foo) {
  424.     spellrecord *psr1, *psr2;
  425.     FILE *outfile;
  426.  
  427.     psr1=(spellrecord *)prc1;
  428.     psr2=(spellrecord *)prc2;
  429.  
  430.     if ((psr1->s->type=='P') && (psr2->s->type=='M'))
  431.     return(-1);
  432.     if ((psr1->s->type=='M') && (psr2->s->type=='P'))
  433.     return(1);
  434.  
  435.     return(strcmpi(psr1->s->name,psr2->s->name));
  436. }
  437.  
  438. // sort spellbook
  439. boolean spellwindow::sort_book() {
  440.     spelllist *sl1, *sl2;
  441.  
  442.     WinSendMsg(hwndcnr,
  443.            CM_SORTRECORD,
  444.            (MPARAM)(spell_order),
  445.            (MPARAM)NULL);
  446.  
  447.     // sort sb also, according to result of container sort
  448.     spellrecord *i;
  449.     i=(spellrecord *)
  450.     WinSendMsg(hwndcnr,
  451.            CM_QUERYRECORD,
  452.            0,
  453.            MPFROM2SHORT(CMA_FIRST,CMA_ITEMORDER));
  454.     sl1=i->spl;
  455.     sb->first=sl1;
  456.     sl1->prev=NULL;  
  457.     while (i!=NULL) {
  458.     i=(spellrecord *)
  459.         WinSendMsg(hwndcnr,
  460.                CM_QUERYRECORD,
  461.                (MPARAM)i,
  462.                MPFROM2SHORT(CMA_NEXT,CMA_ITEMORDER));
  463.     if (i!=NULL) {
  464.         sl2=i->spl;
  465.         sl2->prev=sl1;
  466.         sl1->next=sl2;
  467.         sl1=sl2;
  468.     }
  469.     }
  470.     sl1->next=NULL;
  471.     sb->last=sl1;
  472.  
  473.     return(true);    
  474. }
  475.  
  476. // add spell to a window, after spell "where" (and to book also)
  477. boolean spellwindow::add_spell(spell *s, spellrecord *where) {
  478.     char buffer[256];
  479.     spellrecord *newrecord;
  480.     LONG extrabytes;
  481.     HPOINTER myicon;
  482.  
  483.     extrabytes=(LONG)(sizeof(spellrecord)-sizeof(RECORDCORE));
  484.     // tell the container to allocate memory for new record 
  485.     newrecord=(spellrecord *)WinSendMsg(hwndcnr,
  486.                     CM_ALLOCRECORD,
  487.                     MPFROMLONG(extrabytes),
  488.                     (MPARAM)1);
  489.         
  490.     // set up record 
  491.     newrecord->core.flRecordAttr=0;
  492.     newrecord->s=s;
  493.     newrecord->core.pszIcon=(PSZ)s->name;
  494.     newrecord->core.pszText=(PSZ)s->name;
  495.     newrecord->core.pszName=(PSZ)s->name;
  496.     myicon=lookup_icon(s);
  497.     newrecord->core.hptrIcon=myicon;
  498.     newrecord->core.hptrMiniIcon=myicon;
  499.     newrecord->core.preccNextRecord=0;
  500.         
  501.     // tell the container to add the record 
  502.     RECORDINSERT ri;
  503.     ri.cb=sizeof(RECORDINSERT);
  504.     if (where==NULL) 
  505.       ri.pRecordOrder=(PRECORDCORE)CMA_END;
  506.     else
  507.       ri.pRecordOrder=&(where->core);
  508.     ri.pRecordParent=NULL;
  509. //    ri.fInvalidateRecord=TRUE;
  510.     ri.fInvalidateRecord=FALSE;
  511.     ri.zOrder=CMA_TOP;
  512.     ri.cRecordsInsert=1;
  513.     
  514.     WinSendMsg(hwndcnr,
  515.            CM_INSERTRECORD,
  516.            MPFROMP(newrecord),
  517.            MPFROMP(&ri));
  518.  
  519.     // add to spellbook, also
  520.     if (where==NULL)  // add at end.
  521.     newrecord->spl = sb->add_spell(*s, sb->last);
  522.     else  // add after where
  523.     newrecord->spl = sb->add_spell(*s, where->spl);
  524.  
  525.     if (!readonly) saved=false;
  526.     return(true);
  527. }
  528.  
  529. // add a new spell to a window
  530. boolean spellwindow::add_new_spell() {
  531.     static int i=0;
  532.     char *buffer;
  533.     
  534.     spell *newspell;
  535.  
  536.     // edit new spell in editor
  537.  
  538.     // load new spell into window
  539.     newspell=new magespell;
  540.     buffer=new char[100];
  541.     sprintf(buffer,"New spell # %d\n",i++);
  542.     newspell->name=buffer;
  543.  
  544.     // insert spell after first emphasized record, if any
  545.     spellrecord *insafter;
  546.     insafter=(spellrecord *)
  547.     PVOIDFROMMR(WinSendMsg(hwndcnr,
  548.                    CM_QUERYRECORDEMPHASIS,
  549.                    MPFROMP(CMA_FIRST),
  550.                    MPFROMSHORT(CRA_SELECTED)));
  551.  
  552.     if (insafter==NULL)
  553.       add_spell(newspell);
  554.     else
  555.       add_spell(newspell,insafter);
  556.  
  557.     refresh();
  558.     return(true);
  559. }
  560.  
  561. // delete a spell from window and from the book.
  562. boolean spellwindow::delete_spell(spellrecord *deleteme) {
  563.   PVOID removeme=&(deleteme);
  564.  
  565.   // remove from spellbook
  566.   sb->del_spell(deleteme->spl);
  567.  
  568.   // and from window
  569.   WinSendMsg(hwndcnr,
  570.          CM_REMOVERECORD,
  571.          MPFROMP(removeme),
  572.          MPFROM2SHORT(1,CMA_FREE)); // |CMA_INVALIDATE));
  573.  
  574.   if (!readonly) saved=false;
  575.   return(true);
  576. }
  577.  
  578. // delete all selected spells from window, then update the window.
  579. boolean spellwindow::delete_selected_spells() {
  580.     spellrecord *deleteme;
  581.  
  582.     while (deleteme=(spellrecord *)
  583.        WinSendMsg(hwndcnr,
  584.               CM_QUERYRECORDEMPHASIS,
  585.               MPFROMP(CMA_FIRST),
  586.               MPFROMSHORT(CRA_SELECTED)))
  587.     delete_spell(deleteme);
  588.  
  589.     refresh();
  590.     return(true);
  591. }
  592.  
  593. // refresh spell window 
  594. boolean spellwindow::refresh() {
  595.     WinSendMsg(hwndcnr,
  596.            CM_INVALIDATERECORD,
  597.            (MPARAM)0,
  598.            MPFROM2SHORT(0,CMA_REPOSITION));
  599.     return(true);
  600. }
  601.  
  602.  
  603. // change spell, update screen and spellbook.
  604. boolean spellwindow::change_spell(spell *oldsp, spell *newsp) {
  605.     spellrecord *found;
  606.     SEARCHSTRING oldname;
  607.  
  608.     oldname.pszSearch=(PSZ)oldsp->name;
  609.     oldname.fsPrefix=TRUE;
  610.     oldname.fsCaseSensitive=TRUE;
  611.     oldname.usView=CV_NAME;
  612.     oldname.cb=sizeof(oldname);
  613.  
  614.     found=(spellrecord *)WinSendMsg(hwndcnr,
  615.                     CM_SEARCHSTRING,
  616.                     (MPARAM)(&oldname),
  617.                     (MPARAM)CMA_FIRST);
  618.  
  619.     if (!found) return(false);
  620.  
  621.     // name match does not imply a real match.
  622.     if (found->s == oldsp) {
  623.     add_spell(newsp,found);
  624.     delete_spell(found);
  625.     refresh();
  626.     return (true);
  627.     }
  628.     return(false);
  629. }
  630.  
  631. // a class for displaying individual spells
  632. class slwindow {
  633. public:
  634.     // handles for all relevant windows 
  635.     HWND hwndmain;  // main window
  636.     HWND hwndmle;   // entry field
  637.     HWND hwndframe;  // frame window
  638.  
  639.     // double linked list
  640.     slwindow *next;
  641.     slwindow *prev;
  642.  
  643.     // default is readonly; can be edited.
  644.     boolean readonly;
  645.  
  646.     // one spelllist associated with the window:
  647.     spelllist *sl;
  648.  
  649.     // the window that the spelllist is in, if any.
  650.     spellwindow *parent;
  651.     
  652.     slwindow(spelllist *spll=NULL);
  653.     ~slwindow();
  654. };
  655.  
  656. slwindow *firstspell=NULL;
  657.  
  658. slwindow::slwindow(spelllist *spll) {    
  659.     char *windowname;
  660.  
  661.     // add new window as the first one
  662.     next=firstspell;
  663.     if (firstspell!=NULL) firstspell->prev=this;
  664.     firstspell=this;
  665.     prev=NULL;
  666.  
  667.     readonly=true;
  668.     sl=spll;
  669.  
  670.     if (sl) windowname=sl->s->name;
  671.     else windowname="Spell";
  672.  
  673.     // create the window 
  674.     hwndframe = WinCreateStdWindow(
  675.                   HWND_DESKTOP,
  676.                   WS_VISIBLE,
  677.                   &flFlags,
  678.                   (PSZ)splclass,
  679.                   (PSZ)windowname,
  680.                   WS_VISIBLE,
  681.                   0,
  682.                   SPELLMENU,
  683.                   NULL);
  684. }
  685.  
  686. slwindow::~slwindow() {
  687.     // remove from linked list
  688.     if (this==firstspell) firstspell=next;
  689.     if (next!=NULL) next->prev=prev;
  690.     if (prev!=NULL) prev->next=next;
  691.  
  692.     // remove from display
  693.     WinDestroyWindow(hwndframe);
  694. }
  695.  
  696. slwindow *spellwindowof(HWND b) {
  697.     slwindow *x;
  698.     for (x=firstspell; x!=NULL; x=x->next) 
  699.     if (x->hwndmain==b) return(x);
  700.  
  701.     return(NULL);
  702. }
  703.  
  704. void show_spell(spellwindow *mywin, MPARAM whichspell) {
  705.     char buffer[256];
  706.     PNOTIFYRECORDENTER pn;
  707.     spellrecord *selected;
  708.     slwindow *child;
  709.  
  710.     pn = (PNOTIFYRECORDENTER)whichspell;
  711.     selected = (spellrecord *)(pn->pRecord);
  712.     if (selected) {
  713.     child = new slwindow(selected->spl);
  714.     child->parent=mywin;
  715.     }
  716. }
  717.  
  718. void find_and_show_spell(spellwindow *mywin, spell *s) {
  719.     spellrecord *found;
  720.     SEARCHSTRING oldname;
  721.     slwindow *child;
  722.  
  723.     oldname.pszSearch=(PSZ)s->name;
  724.     oldname.fsPrefix=TRUE;
  725.     oldname.fsCaseSensitive=TRUE;
  726.     oldname.usView=CV_NAME;
  727.     oldname.cb=sizeof(oldname);
  728.  
  729.     found=(spellrecord *)WinSendMsg(mywin->hwndcnr,
  730.                     CM_SEARCHSTRING,
  731.                     (MPARAM)(&oldname),
  732.                     (MPARAM)CMA_FIRST);
  733.  
  734.     if (!found) return;
  735.  
  736.     // name match does not imply a real match.
  737.     if (found->s == s) {
  738.     child = new slwindow(found->spl);
  739.     child->parent=mywin;
  740.     }
  741. }
  742.  
  743. MRESULT drop_spell(spellwindow *mywin, PCNRDRAGINFO pcdi) {
  744.     char buffer[256];
  745.     int items;
  746.     PDRAGINFO pdraginfo;
  747.  
  748.     pdraginfo=pcdi->pDragInfo;
  749.  
  750.     // make sure we can access the draginfo structure
  751.     if (!DrgAccessDraginfo(pdraginfo))
  752.     return(MRFROM2SHORT(DOR_NODROPOP,0));
  753.     
  754.     // how many items?
  755.     items=DrgQueryDragitemCount(pdraginfo);
  756.  
  757.     spellrecord *dropped_on;
  758.     PDRAGITEM pditem;
  759.     spellrecord *dropping;
  760.     // add each item
  761.     if (pcdi->pRecord) {            // if dropped on another spell
  762.     for (int i=items-1; i>=0; i--) {
  763.         pditem=DrgQueryDragitemPtr(pdraginfo,i);
  764.         
  765.         // add after record it was dropped on
  766.         dropped_on=(spellrecord *)(pcdi->pRecord);
  767.         dropping=(spellrecord *)pditem->ulItemID;
  768.         mywin->add_spell(dropping->s,dropped_on);
  769.  
  770.         // dropped on same window -> delete old item
  771.         if (mywin->hwndbook==pditem->hwndItem)
  772.         mywin->delete_spell(dropping);
  773.     }
  774.     }
  775.     else {                             // dropped on empty space
  776.     for (int i=0; i<items; i++) {
  777.         pditem=DrgQueryDragitemPtr(pdraginfo,i);
  778.         
  779.         // add at end
  780.         dropping=(spellrecord *)pditem->ulItemID;
  781.         mywin->add_spell(dropping->s);
  782.  
  783.         // dropped on same window -> delete old item
  784.         if (mywin->hwndbook==pditem->hwndItem) 
  785.           mywin->delete_spell(dropping);
  786.     }
  787.     }
  788.  
  789.     mywin->refresh();
  790.  
  791.     DrgFreeDraginfo(pdraginfo);
  792.     
  793. }
  794.  
  795.  
  796. // something is being dragged over the container
  797. MRESULT drag_over(spellwindow *mywin, PDRAGINFO pdraginfo) {
  798.     USHORT usIndicator=DOR_DROP,usOperation;
  799.     int items;
  800.  
  801.     if (mywin->readonly) return(MRFROM2SHORT(DOR_NEVERDROP,DO_COPY));
  802.  
  803.     // make sure we can access the draginfo structure
  804.     if (!DrgAccessDraginfo(pdraginfo)) 
  805.     return(MRFROM2SHORT(DOR_NODROPOP,0));
  806.     
  807.     // how many items?
  808.     items=DrgQueryDragitemCount(pdraginfo);
  809.  
  810.     // check each item
  811.     for (int i=0; i<items; i++) {
  812.     PDRAGITEM pditem;
  813.     pditem=DrgQueryDragitemPtr(pdraginfo,i);
  814.     if (!DrgVerifyRMF(pditem,(PSZ)"Spell",(PSZ)"Spell"))
  815.         usIndicator=DOR_NEVERDROP;
  816.     }
  817.  
  818.     // only operation for spells
  819.     usOperation=DO_COPY;
  820.  
  821.     DrgFreeDraginfo(pdraginfo);
  822.     return(MRFROM2SHORT(usIndicator,usOperation));
  823. }
  824.  
  825. BOOL init_drag(spellwindow *mywin,PCNRDRAGINIT pcdi) {
  826.     char buffer[256];
  827.     ULONG items;
  828.     spellrecord *selected;
  829.  
  830.     // no dragging from empty space
  831.     if (pcdi->pRecord==NULL) return(FALSE);
  832.  
  833.     // if record is selected, it may be part of a group 
  834.     if (pcdi->pRecord->flRecordAttr & CRA_SELECTED) {
  835.     // find # of items being dragged
  836.     items=0;
  837.     selected=(spellrecord *)WinSendMsg(mywin->hwndcnr,
  838.                        CM_QUERYRECORDEMPHASIS,
  839.                        MPFROMP(CMA_FIRST),
  840.                        MPFROMSHORT(CRA_SELECTED));
  841.     while (selected!=NULL) {
  842.         selected=(spellrecord *)WinSendMsg(mywin->hwndcnr,
  843.                            CM_QUERYRECORDEMPHASIS,
  844.                            MPFROMP(selected),
  845.                            MPFROMSHORT(CRA_SELECTED));
  846.         items++;
  847.     }
  848.     }
  849.     else items=1;
  850.  
  851.     // no items dragged?  shouldn't get here.
  852.     if (items==0) return (FALSE);
  853.  
  854.     // get DRAGINFO structure
  855.     PDRAGINFO pdraginfo;
  856.     pdraginfo=DrgAllocDraginfo(items);
  857.  
  858.     DRAGITEM dragitem;
  859.  
  860.     // common parts of DRAGITEM structure
  861.     dragitem.hwndItem=mywin->hwndbook;
  862.     dragitem.hstrType=DrgAddStrHandle((PSZ)"Spell");
  863.     dragitem.hstrRMF=DrgAddStrHandle((PSZ)"<Spell,Spell>");
  864.     dragitem.hstrContainerName=NULL;
  865.     dragitem.fsControl=0;
  866.     dragitem.fsSupportedOps=DO_COPYABLE;
  867.  
  868.     // add each dragged item
  869.     selected=(spellrecord *)CMA_FIRST;
  870.     for (int i=0; i<items; i++) {
  871.     if (items==1) 
  872.         // if there's only 1 item, it must be the one direct
  873.         // manipulation started on.
  874.         selected=(spellrecord *)pcdi->pRecord;
  875.     else
  876.         selected=(spellrecord *)WinSendMsg(mywin->hwndcnr,
  877.                            CM_QUERYRECORDEMPHASIS,
  878.                            MPFROMP(selected),
  879.                            MPFROMSHORT(CRA_SELECTED));
  880.  
  881.     dragitem.hstrSourceName=DrgAddStrHandle(selected->core.pszText);
  882.     dragitem.hstrTargetName=dragitem.hstrSourceName;
  883.     dragitem.ulItemID=(ULONG)selected;
  884.  
  885.     // add dragitem to draginfo structure
  886.     DrgSetDragitem(pdraginfo,&dragitem,sizeof(DRAGITEM),i);
  887.     }
  888.  
  889.     DRAGIMAGE dimg;
  890.     if (items==1) 
  891.     dimg.hImage=lookup_icon(selected->s);
  892.     else dimg.hImage=dragicon;
  893.     dimg.fl=DRG_ICON;
  894.     dimg.cb=sizeof(DRAGIMAGE);
  895.     dimg.cxOffset=0;
  896.     dimg.cyOffset=0;
  897.  
  898.     pdraginfo->hwndSource=mywin->hwndbook;
  899.     HWND destination;
  900.     destination = DrgDrag(mywin->hwndcnr,pdraginfo,&dimg,1,VK_ENDDRAG,NULL);
  901.  
  902. /*
  903.     sprintf(buffer,"Item Dropped on handle %d\n",(int)destination);
  904.     WinMessageBox(HWND_DESKTOP,
  905.           HWND_DESKTOP,
  906.           (PSZ)buffer,
  907.           (PSZ)"WM_INITDRAG",
  908.           102,
  909.           MB_OK);
  910. */        
  911.         
  912.     return(TRUE);
  913. }
  914.  
  915. MRESULT savequit(spellwindow *mywin) {
  916.  
  917.     // has window been saved? 
  918.     if (!mywin->saved) {
  919.     ULONG response;
  920.     response= WinMessageBox(HWND_DESKTOP,
  921.                 HWND_DESKTOP,
  922.                 (PSZ)"Save spellbook before closing?",
  923.                 (PSZ)"Spellbook changed since last save",
  924.                 102,
  925.                 MB_YESNOCANCEL|MB_ICONQUESTION);
  926.     if (response==MBID_YES) {
  927.         if (!mywin->save_book()) return((MRESULT)FALSE);
  928.     }
  929.     else if (response==MBID_CANCEL) return((MRESULT)FALSE);
  930.     }
  931.     
  932.     if (first->next==NULL) { //this is the last window 
  933.     ULONG response = WinMessageBox(HWND_DESKTOP,
  934.                        HWND_DESKTOP,
  935.                        (PSZ)"Closing the last spellbook will end the program.  Are you sure?",
  936.                        (PSZ)"Warning!",
  937.                        102,
  938.                        MB_YESNO|MB_ICONEXCLAMATION);
  939.     if (response==MBID_YES)
  940.         WinPostMsg(mywin->hwndbook,WM_QUIT,0,0);
  941.     }
  942.     else {
  943.     delete mywin;
  944.     return ((MRESULT)TRUE);
  945.     }
  946.     
  947.     return ((MRESULT)TRUE);
  948. }
  949.  
  950. // quick enabling of menu items
  951. VOID EnableMenuItem( HWND hwndMenu, SHORT sIditem, BOOL bEnable)
  952. {
  953.   SHORT sFlag;
  954.  
  955.   if(bEnable)
  956.     sFlag = 0;
  957.   else
  958.     sFlag = MIA_DISABLED;
  959.  
  960.   WinSendMsg(hwndMenu, MM_SETITEMATTR, MPFROM2SHORT(sIditem, TRUE),
  961.                MPFROM2SHORT(MIA_DISABLED, sFlag));
  962.  
  963. }
  964.  
  965. // create a subset, given a window to choose from and a selection dialog.
  966. // returns true if a subset was found, else false.
  967. boolean create_subset(spellwindow *mywin,HWND dlg) {
  968.     spellwindow *nsw=NULL;
  969.     spellrecord *sr;
  970.     spell *s;
  971.     char *tmpstr;
  972.     magespell *ms;
  973.     priestspell *ps;
  974.     boolean matches,itemmatch;
  975.     int i,j;
  976.  
  977.     // see if we're doing "and" or "or"
  978.     boolean s_and;
  979.     if (WinQueryButtonCheckstate(dlg,DLG_AND)==1) s_and=true;
  980.     else s_and=false;
  981.  
  982.     // see if things are case sensitive
  983.     boolean s_nocase=false;
  984.     if (WinQueryButtonCheckstate(dlg,DLG_CASE)==0) s_nocase=true;
  985.  
  986.     // see if there's a restriction on the name.
  987.     boolean s_name;
  988.     char *str_name;
  989.     if ((i=WinQueryDlgItemTextLength(dlg,DLG_NAME))==0) 
  990.     s_name=false;
  991.     else {
  992.     s_name=true;
  993.     str_name=new char[i+1];
  994.     WinQueryDlgItemText(dlg,DLG_NAME,i+1,(PSZ)str_name);
  995.     if (s_nocase) upstr(str_name);
  996.     }
  997.  
  998.     // check school
  999.     boolean s_school;
  1000.     char *str_school;
  1001.     if ((i=WinQueryDlgItemTextLength(dlg,DLG_SCHOOL))==0) 
  1002.     s_school=false;
  1003.     else {
  1004.     s_school=true;
  1005.     str_school=new char[i+1];
  1006.     WinQueryDlgItemText(dlg,DLG_SCHOOL,i+1,(PSZ)str_school);
  1007.     if (s_nocase) upstr(str_school);
  1008.     }
  1009.  
  1010.     // check sphere
  1011.     boolean s_sphere;
  1012.     char *str_sphere;
  1013.     if ((i=WinQueryDlgItemTextLength(dlg,DLG_SPHERE))==0) 
  1014.     s_sphere=false;
  1015.     else {
  1016.     s_sphere=true;
  1017.     str_sphere=new char[i+1];
  1018.     WinQueryDlgItemText(dlg,DLG_SPHERE,i+1,(PSZ)str_sphere);
  1019.     if (s_nocase) upstr(str_sphere);
  1020.     }
  1021.  
  1022.     // check mage,priest,reversible
  1023.     boolean s_mage;
  1024.     boolean s_priest;
  1025.     boolean s_reversible;
  1026.     if (WinQueryButtonCheckstate(dlg,DLG_MAGE)==1) s_mage=true;
  1027.     else s_mage=false;
  1028.     if (WinQueryButtonCheckstate(dlg,DLG_PRIEST)==1) s_priest=true;
  1029.     else s_priest=false;
  1030.     if (WinQueryButtonCheckstate(dlg,DLG_REVERSIBLE)==1) s_reversible=true;
  1031.     else s_reversible=false;
  1032.  
  1033.     
  1034.     // check save
  1035.     boolean s_save;
  1036.     char *str_save;
  1037.     if ((i=WinQueryDlgItemTextLength(dlg,DLG_SAVE))==0) 
  1038.     s_save=false;
  1039.     else {
  1040.     s_save=true;
  1041.     str_save=new char[i+1];
  1042.     WinQueryDlgItemText(dlg,DLG_SAVE,i+1,(PSZ)str_save);
  1043.     if (s_nocase) upstr(str_save);
  1044.     }
  1045.  
  1046.     // check components
  1047.     boolean s_components;
  1048.     boolean s_c_v=false;
  1049.     boolean s_c_s=false;
  1050.     boolean s_c_m=false;
  1051.     if ((i=WinQueryDlgItemTextLength(dlg,DLG_COMPONENTS))==0) 
  1052.     s_components=false;
  1053.     else {
  1054.     s_components=true;
  1055.     tmpstr=new char[i+1];
  1056.     WinQueryDlgItemText(dlg,DLG_COMPONENTS,i+1,(PSZ)tmpstr);
  1057.     upstr(tmpstr);
  1058.     if (strchr(tmpstr,'V')!=0) s_c_v=true;
  1059.     if (strchr(tmpstr,'S')!=0) s_c_s=true;
  1060.     if (strchr(tmpstr,'M')!=0) s_c_m=true;
  1061.     delete tmpstr;
  1062.     }
  1063.  
  1064.     // see if there's a restriction on the level.
  1065.     boolean s_level;
  1066.     boolean s_level_gt=false;
  1067.     boolean s_level_lt=false;
  1068.     int int_level=0;
  1069.     if ((i=WinQueryDlgItemTextLength(dlg,DLG_LEVEL))==0) 
  1070.     s_level=false;
  1071.     else {
  1072.     s_level=true;
  1073.     tmpstr=new char[i+1];
  1074.     WinQueryDlgItemText(dlg,DLG_LEVEL,i+1,(PSZ)tmpstr);
  1075.     if (tmpstr[0]=='>') {
  1076.         s_level_gt=true;
  1077.         sscanf(tmpstr,">%d",&int_level);
  1078.     }
  1079.     else if (tmpstr[0]=='<') {
  1080.         s_level_lt=true;
  1081.         sscanf(tmpstr,"<%d",&int_level);
  1082.     }
  1083.     else sscanf(tmpstr,"%d",&int_level);
  1084.     delete tmpstr;
  1085.     }
  1086.  
  1087.     // see if there's a description search going
  1088.     boolean s_desc;
  1089.     int int_desc;
  1090.     int str_desc_len;
  1091.     boolean s_desc_and=false;
  1092.     PCHAR *str_desc;
  1093.     HWND dh=WinWindowFromID(dlg,DLG_DESCRIPTION);
  1094.     if (WinSendMsg(dh,
  1095.            MLM_QUERYTEXTLENGTH,
  1096.            0,0)==0)
  1097.     s_desc=false;
  1098.     else {
  1099.     int_desc=(int)WinSendMsg(dh,
  1100.                  MLM_QUERYLINECOUNT,
  1101.                  0,0);
  1102.     str_desc=new PCHAR[int_desc];
  1103.     IPT pos= 0;
  1104.  
  1105.     // see if we're and'ing or or'ing the description search.
  1106.     if (WinQueryButtonCheckstate(dlg,DLG_DES_AND)==1) s_desc_and=true;
  1107.  
  1108.     // set up xfer buffer
  1109.     WinSendMsg(dh,
  1110.            MLM_SETIMPORTEXPORT,
  1111.            (MPARAM)(&xfer_buffer),
  1112.            (MPARAM)10240);
  1113.     WinSendMsg(dh,
  1114.            MLM_FORMAT,
  1115.            (MPARAM)MLFIE_NOTRANS,
  1116.            0);
  1117.     for (i=0; i<int_desc; i++) {
  1118.         WinSendMsg(dh,MLM_SETSEL,(MPARAM)pos,(MPARAM)pos);
  1119.         j=(int)WinSendMsg(dh,
  1120.                   MLM_QUERYLINELENGTH,
  1121.                   (MPARAM)pos,
  1122.                   0);
  1123.         str_desc[i]=new char[j+1];
  1124.         str_desc_len=j;
  1125.         WinSendMsg(dh,
  1126.                MLM_EXPORT,
  1127.                (MPARAM)&pos,
  1128.                (MPARAM)&j);
  1129.         strncpy(str_desc[i],(char *)xfer_buffer,str_desc_len);
  1130.         str_desc[i][str_desc_len]=(char)0;
  1131.  
  1132.         // get rid of \n at end of string.
  1133.         if ((str_desc_len>1) && (i<int_desc-1))
  1134.         str_desc[i][str_desc_len-1]=(char)0;
  1135.  
  1136.         if (s_nocase) upstr(str_desc[i]);
  1137.     }
  1138.     }
  1139.     
  1140.     // get first spell
  1141.     sr=(spellrecord *)
  1142.     WinSendMsg(mywin->hwndcnr,
  1143.            CM_QUERYRECORD,
  1144.            0,
  1145.            MPFROM2SHORT(CMA_FIRST,CMA_ITEMORDER));
  1146.     while (sr!=NULL) {
  1147.     s=sr->s;
  1148.     ms=(magespell *)s;
  1149.     ps=(priestspell *)s;
  1150.     if (s_and) matches=true;
  1151.     else matches=false;
  1152.  
  1153.     // see if this spell matches selection.
  1154.     if (s_name) {
  1155.         if (s_nocase) {
  1156.         tmpstr=strdup(s->name);
  1157.         upstr(tmpstr);
  1158.         itemmatch=(boolean)(strstr(tmpstr,str_name)!=0);
  1159.         delete tmpstr;
  1160.         }
  1161.         else itemmatch = (boolean)(strstr(s->name,str_name)!=0);
  1162.  
  1163.         if (s_and) matches = (boolean)(matches && itemmatch);
  1164.         else matches = (boolean)(matches || itemmatch);
  1165.     }
  1166.     if (s_school) {
  1167.         if ((s->type=='M') || (s->type=='P')) {
  1168.         if (s_nocase) {
  1169.             tmpstr=strdup(ms->school);
  1170.             upstr(tmpstr);
  1171.             itemmatch=(boolean)(strstr(tmpstr,str_school)!=0);
  1172.             delete tmpstr;
  1173.         }
  1174.         else itemmatch = (boolean)(strstr(ms->school,str_school)!=0);
  1175.         }
  1176.         else itemmatch=false;
  1177.  
  1178.         if (s_and) matches = (boolean)(matches && itemmatch);
  1179.         else matches = (boolean)(matches || itemmatch);
  1180.     }
  1181.     if (s_sphere) {
  1182.         if (s->type=='P') {
  1183.         if (s_nocase) {
  1184.             tmpstr=strdup(ps->sphere);
  1185.             upstr(tmpstr);
  1186.             itemmatch=(boolean)(strstr(tmpstr,str_sphere)!=0);
  1187.             delete tmpstr;
  1188.         }
  1189.         else itemmatch = (boolean)(strstr(ps->sphere,str_sphere)!=0);
  1190.         }
  1191.         else itemmatch=false;
  1192.  
  1193.         if (s_and) matches = (boolean)(matches && itemmatch);
  1194.         else matches = (boolean)(matches || itemmatch);
  1195.     }
  1196.     if (s_level) {
  1197.         if (s_level_gt) itemmatch = (boolean)(s->level > int_level);
  1198.         else if (s_level_lt) itemmatch = (boolean)(s->level < int_level);
  1199.         else itemmatch = (boolean)(s->level == int_level);
  1200.  
  1201.         if (s_and) matches = (boolean)(matches && itemmatch);
  1202.         else matches = (boolean)(matches || itemmatch);
  1203.     }
  1204.     if (s_save) {
  1205.         if ((s->type=='M') || (s->type=='P')) {
  1206.         if (s_nocase) {
  1207.             tmpstr=strdup(ms->save);
  1208.             upstr(tmpstr);
  1209.             itemmatch=(boolean)(strstr(tmpstr,str_save)!=0);
  1210.             delete tmpstr;
  1211.         }
  1212.         else itemmatch = (boolean)(strstr(ms->save,str_save)!=0);
  1213.         }
  1214.         else itemmatch=false;
  1215.  
  1216.         if (s_and) matches = (boolean)(matches && itemmatch);
  1217.         else matches = (boolean)(matches || itemmatch);
  1218.     }
  1219.     if (s_mage) {
  1220.         itemmatch=(boolean)(s->type=='M');
  1221.  
  1222.         if (s_and) matches = (boolean)(matches && itemmatch);
  1223.         else matches = (boolean)(matches || itemmatch);
  1224.     }
  1225.     if (s_priest) {
  1226.         itemmatch=(boolean)(s->type=='P');
  1227.  
  1228.         if (s_and) matches = (boolean)(matches && itemmatch);
  1229.         else matches = (boolean)(matches || itemmatch);
  1230.     }
  1231.     if (s_reversible) {
  1232.         if ((s->type=='M') || (s->type=='P')) 
  1233.         itemmatch=ms->reversible;
  1234.         else itemmatch=false;
  1235.  
  1236.         if (s_and) matches = (boolean)(matches && itemmatch);
  1237.         else matches = (boolean)(matches || itemmatch);
  1238.     }
  1239.     if (s_components) {
  1240.         if ((s->type=='M') || (s->type=='P')) {
  1241.         itemmatch=(boolean)(s_c_v || s_c_m || s_c_s);
  1242.         if (s_c_v) itemmatch = 
  1243.             (boolean)(itemmatch && strchr(ms->components,'V'));
  1244.         if (s_c_s) itemmatch = 
  1245.             (boolean)(itemmatch && strchr(ms->components,'S'));
  1246.         if (s_c_m) itemmatch = 
  1247.             (boolean)(itemmatch && strchr(ms->components,'M'));
  1248.         }
  1249.         else itemmatch=false;
  1250.  
  1251.         if (s_and) matches = (boolean)(matches && itemmatch);
  1252.         else matches = (boolean)(matches || itemmatch);
  1253.     }
  1254.     // only search thru the descs if it matters... slow!
  1255.     if ((s_desc) &&
  1256.         (((s_and) && (matches==true)) ||
  1257.          ((s_and==false) && (matches==false)))) {
  1258.         if (s_desc_and) itemmatch=true;
  1259.         else itemmatch=false;
  1260.  
  1261.         for (i=0; i<int_desc; i++) {
  1262.         if (strlen(str_desc[i])!=0) {
  1263.             if (s_desc_and) itemmatch = 
  1264.             (boolean)(itemmatch && 
  1265.                   s->desc_search(str_desc[i],s_nocase));
  1266.             else itemmatch = 
  1267.             (boolean)(itemmatch || 
  1268.                   s->desc_search(str_desc[i],s_nocase));
  1269.         }
  1270.         }
  1271.  
  1272.         if (s_and) matches = (boolean)(matches && itemmatch);
  1273.         else matches = (boolean)(matches || itemmatch);
  1274.     }
  1275.  
  1276.     // if it still matches, add it in.
  1277.     if (matches) {
  1278.         if (!nsw) nsw=new spellwindow("Selection Matches:");
  1279.         nsw->add_spell(s);
  1280.     }
  1281.  
  1282.     // get next spell
  1283.     sr=(spellrecord *)
  1284.         WinSendMsg(mywin->hwndcnr,
  1285.                CM_QUERYRECORD,
  1286.                (MPARAM)sr,
  1287.                MPFROM2SHORT(CMA_NEXT,CMA_ITEMORDER));
  1288.     }
  1289.  
  1290.     // see if any spells were actually selected
  1291.     if (nsw==NULL) {
  1292.     WinMessageBox(HWND_DESKTOP,
  1293.               HWND_DESKTOP,
  1294.               (PSZ)"No spells in this book matched these selection criteria",
  1295.               (PSZ)"Sorry!",
  1296.               102,
  1297.               MB_OK|MB_ICONEXCLAMATION);
  1298.     return(false);
  1299.     }
  1300.     
  1301.     // don't bug the user about closing the window
  1302.     nsw->saved=true;
  1303.     nsw->refresh();
  1304.     return(true);
  1305. }
  1306.  
  1307. // dialog procedure for select boxes:
  1308. MRESULT EXPENTRY select_dlg_func(HWND handle, ULONG msg,
  1309.                  MPARAM param1, MPARAM param2) {
  1310.     switch (msg) {
  1311.     case WM_INITDLG:
  1312.     // turn on default buttons.
  1313.     WinSendMsg(WinWindowFromID(handle,DLG_AND),
  1314.            BM_SETCHECK,
  1315.            (MPARAM)1,
  1316.            0);
  1317.     WinSendMsg(WinWindowFromID(handle,DLG_DES_OR),
  1318.            BM_SETCHECK,
  1319.            (MPARAM)1,
  1320.            0);
  1321.     WinSendMsg(WinWindowFromID(handle,DLG_CASE),
  1322.            BM_SETCHECK,
  1323.            (MPARAM)1,
  1324.            0);
  1325.     break;
  1326.  
  1327.     case WM_COMMAND: 
  1328.     switch (SHORT1FROMMP(param1)) {
  1329.     case DLG_OK:
  1330.         HWND hwndparent;
  1331.         hwndparent=WinQueryWindow(handle,QW_OWNER);    
  1332.         // search list of spellwindows for frame who owns this dlg.
  1333.         // if found, create subset window.
  1334.         boolean subset_found;
  1335.         spellwindow *x;    
  1336.         subset_found=false;
  1337.         for (x=first; x!=NULL; x=x->next) 
  1338.         if (x->hwndframe==hwndparent) 
  1339.             subset_found=create_subset(x,handle);
  1340.         if (subset_found) WinDismissDlg(handle,TRUE);
  1341.         return (MRESULT)TRUE;
  1342.         break;
  1343.  
  1344.     case DLG_CANCEL:
  1345.         WinDismissDlg(handle,TRUE);
  1346.         return (MRESULT)FALSE;
  1347.         break;
  1348.  
  1349.     case DLG_HELP:
  1350.         WinMessageBox(HWND_DESKTOP,
  1351.               HWND_DESKTOP,
  1352.               (PSZ)"I haven't figured out how to do this yet... see the INF file instead.",
  1353.               (PSZ)"Sorry!",
  1354.               102,
  1355.               MB_OK|MB_ICONQUESTION);
  1356.         return (MRESULT)TRUE;
  1357.     }
  1358.     break;
  1359.     }
  1360.     return (WinDefDlgProc(handle,msg,param1,param2));
  1361. }
  1362.  
  1363. // dialog procedure for renaming spellbook
  1364. MRESULT EXPENTRY rename_dlg_func(HWND handle, ULONG msg,
  1365.                  MPARAM param1, MPARAM param2) {
  1366.     int i;
  1367.  
  1368.     switch (msg) {
  1369.     case WM_COMMAND: 
  1370.     switch (SHORT1FROMMP(param1)) {
  1371.     case DLG_OK:
  1372.         HWND hwndparent;
  1373.         hwndparent=WinQueryWindow(handle,QW_OWNER);    
  1374.         // search list of spellwindows for frame who owns this dlg.
  1375.         // if found, create subset window.
  1376.         spellwindow *x;    
  1377.         for (x=first; x!=NULL; x=x->next) 
  1378.         if (x->hwndframe==hwndparent) {
  1379.             i=WinQueryDlgItemTextLength(handle,DLG_NEWNAME);
  1380.             if (i>0) {
  1381.             delete (x->sb->name);
  1382.             x->sb->name=new char[i+1];
  1383.             WinQueryDlgItemText(handle,DLG_NEWNAME,i+1,(PSZ)(x->sb->name));
  1384.             WinSetWindowText(x->hwndframe,(PSZ)(x->sb->name));
  1385.             }
  1386.         }
  1387.         WinDismissDlg(handle,TRUE);
  1388.         return (MRESULT)TRUE;
  1389.         break;
  1390.  
  1391.     case DLG_CANCEL:
  1392.         WinDismissDlg(handle,TRUE);
  1393.         return (MRESULT)FALSE;
  1394.         break;
  1395.     }
  1396.     break;
  1397.     }
  1398.     return (WinDefDlgProc(handle,msg,param1,param2));
  1399. }
  1400.  
  1401. // custom window procedure
  1402. MRESULT EXPENTRY book_window_func(HWND handle, ULONG msg, 
  1403.                   MPARAM param1, MPARAM param2) {
  1404.     SWP windowpos;
  1405.     short cx,cy;
  1406.     char *txt,buffer[256];
  1407.     spellwindow *mywin;
  1408.     spellwindow *nsw;
  1409.  
  1410.     switch (msg) {
  1411.  
  1412.     case WM_ERASEBACKGROUND:
  1413.     return (MRESULT)TRUE;
  1414.  
  1415.     case WM_CREATE:
  1416.     // save book handle in first window
  1417.     first->hwndbook=handle;
  1418.  
  1419.     // find out my size 
  1420.     WinQueryWindowPos(handle,&windowpos);
  1421.     cx=windowpos.cx;
  1422.     cy=windowpos.cy;
  1423.     
  1424.     // create container filling whole window 
  1425.     first->hwndcnr=
  1426.         WinCreateWindow(
  1427.                 handle,
  1428.                 WC_CONTAINER,
  1429.                 0,
  1430.                 CCS_AUTOPOSITION |            // Auto position   
  1431.                 CCS_EXTENDSEL,           // Extended selection     
  1432.                 (LONG)0,
  1433.                 (LONG)0,
  1434.                 (LONG)cx,
  1435.                 (LONG)cy,
  1436.                 handle,
  1437.                 HWND_TOP,
  1438.                 windows++,
  1439.                 NULL,
  1440.                 NULL);
  1441.  
  1442.     // put container in name/icon mode 
  1443.     cnrInfo.flWindowAttr = CV_NAME|CV_MINI;
  1444.     WinSendMsg(first->hwndcnr,
  1445.            CM_SETCNRINFO,
  1446.            MPFROMP(&cnrInfo),
  1447.            MPFROMLONG(CMA_FLWINDOWATTR));
  1448.     
  1449.     // and activate it 
  1450.     WinShowWindow(first->hwndcnr,TRUE);
  1451.     break;
  1452.  
  1453.     case WM_SIZE:
  1454.     mywin=windowof(handle);
  1455.  
  1456.     cx=SHORT1FROMMP(param2);
  1457.     cy=SHORT2FROMMP(param2);
  1458.     // tell the container to change its size 
  1459.     WinSetWindowPos(mywin->hwndcnr,0,0,0,cx,cy,SWP_SIZE);
  1460.  
  1461.     break;
  1462.  
  1463.     // is menu valid?
  1464.     case WM_INITMENU:
  1465.     mywin=windowof(handle);
  1466.     
  1467.     switch(SHORT1FROMMP(param1)) {
  1468.     case SPELL_SUBMENU:
  1469.         BOOL enable;
  1470.  
  1471.         if (mywin->readonly) enable=FALSE;
  1472.         else enable=TRUE;
  1473.  
  1474.         EnableMenuItem(HWNDFROMMP(param2), ADDSPELL, enable);
  1475.         EnableMenuItem(HWNDFROMMP(param2), DELSPELL, enable);
  1476.     }
  1477.     break;
  1478.  
  1479.     // command from menu or dialog
  1480.     case WM_COMMAND:
  1481.     mywin=windowof(handle);
  1482.     
  1483.     switch(SHORT1FROMMP(param1)) {
  1484.     case ADDSPELL:
  1485.         mywin->add_new_spell();
  1486.         break;
  1487.  
  1488.     case DELSPELL:
  1489.       mywin->delete_selected_spells();
  1490.       break;
  1491.  
  1492.     case SUBSET:
  1493.         WinLoadDlg(HWND_DESKTOP,
  1494.                handle,
  1495.                select_dlg_func,
  1496.                0L,
  1497.                SELECT_DLG,
  1498.                NULL);
  1499.         break;
  1500.  
  1501.     case SORTBOOK:
  1502.         mywin->sort_book();
  1503.         break;
  1504.  
  1505.     case RENAME:
  1506.         WinDlgBox(HWND_DESKTOP,
  1507.               handle,
  1508.               rename_dlg_func,
  1509.               0L,
  1510.               RENAME_DLG,
  1511.               NULL);
  1512.         break;
  1513.  
  1514.     case ABOUT:
  1515.         copyleft();
  1516.         break;
  1517.  
  1518.     case NEWBOOK:
  1519.       new spellwindow;
  1520.       break;
  1521.  
  1522.     case SAVETITLES:
  1523.       mywin->save_titles();
  1524.       break;
  1525.  
  1526.     case SAVEBOOK:
  1527.       mywin->save_book();
  1528.       break;
  1529.  
  1530.     case LOADBOOK:
  1531.       nsw=new spellwindow;
  1532.       nsw->load_book();
  1533.       break;
  1534.  
  1535.     case LOADTITLES:
  1536.       nsw=new spellwindow;
  1537.       nsw->load_titles();
  1538.       break;
  1539.  
  1540.  
  1541.     case CLOSEBOOK:
  1542.       WinSendMsg(mywin->hwndbook,
  1543.              WM_CLOSE,
  1544.              0,
  1545.              0);
  1546.       break;
  1547.  
  1548.     case QUITPROGRAM:
  1549.       boolean allsaved=true;
  1550.       spellwindow *ptr;
  1551.       for (ptr=first; ptr!=NULL; ptr=ptr->next)
  1552.           if (ptr->saved==false) allsaved=false;
  1553.       
  1554.       if (!allsaved) {
  1555.           ULONG response = WinMessageBox(HWND_DESKTOP,
  1556.                          HWND_DESKTOP,
  1557.                          (PSZ)"End the program without saving all spellbooks?",
  1558.                          (PSZ)"Warning!",
  1559.                          102,
  1560.                          MB_YESNO|MB_ICONEXCLAMATION);
  1561.           if (response==MBID_NO) break;
  1562.       }
  1563.       WinPostMsg(mywin->hwndbook,WM_QUIT,0,0);
  1564.       }
  1565.     break;
  1566.  
  1567.     // message from container 
  1568.     case WM_CONTROL:
  1569.     PCNRDRAGINFO pcdi;
  1570.     mywin=windowof(handle);
  1571.     
  1572.     switch (SHORT2FROMMP(param1)) {
  1573.     case CN_ENTER:
  1574.         show_spell(mywin, param2);
  1575.         return ((MRESULT)TRUE);
  1576.         break;
  1577.  
  1578.     case CN_INITDRAG:
  1579.         if (init_drag(mywin,(PCNRDRAGINIT)param2))
  1580.         return ((MRESULT)FALSE);
  1581.         else
  1582.         return ((MRESULT)TRUE);
  1583.         break;
  1584.         
  1585.     case CN_DRAGOVER:
  1586.         pcdi=(PCNRDRAGINFO)param2;
  1587.         return drag_over(mywin,pcdi->pDragInfo);
  1588.         break;
  1589.  
  1590.     case CN_DROP:
  1591.         pcdi=(PCNRDRAGINFO)param2;
  1592.         return drop_spell(mywin,pcdi);
  1593.         break;
  1594.  
  1595.     }
  1596.     break;
  1597.  
  1598.     // user wants to close the window 
  1599.     case WM_CLOSE:
  1600.     mywin=windowof(handle);
  1601.     return savequit(mywin);
  1602.     break;
  1603.     }
  1604.     return WinDefWindowProc(handle, msg, param1, param2);
  1605. }
  1606.  
  1607. // empty out mle and show a spell in it
  1608. void mle_show_spell(HWND hwndmle, spell *s) {
  1609.     IPT insertion_point=0;
  1610.  
  1611.     // remove old spell
  1612.     IPT text_length;
  1613.     text_length=(IPT)WinSendMsg(hwndmle,
  1614.                 MLM_QUERYTEXTLENGTH,
  1615.                 0,0);
  1616.  
  1617.     // hide window for speed:
  1618.     WinShowWindow(hwndmle,FALSE);
  1619.  
  1620.     WinSendMsg(hwndmle,
  1621.            MLM_DELETE,
  1622.            0,
  1623.            (MPARAM)text_length);
  1624.  
  1625.     // set up transfer buffer
  1626.     WinSendMsg(hwndmle,
  1627.            MLM_SETIMPORTEXPORT,
  1628.            (MPARAM)(&xfer_buffer),
  1629.            (MPARAM)10240);
  1630.     WinSendMsg(hwndmle,
  1631.            MLM_FORMAT,
  1632.            (MPARAM)MLFIE_CFTEXT,
  1633.            0);
  1634.  
  1635.     s->s_print((char *)xfer_buffer);
  1636.  
  1637.     WinSendMsg(hwndmle,
  1638.            MLM_IMPORT,
  1639.            (MPARAM)(&insertion_point),
  1640.            (MPARAM)strlen((char *)xfer_buffer));
  1641.  
  1642.     // show window again
  1643.     WinShowWindow(hwndmle,TRUE);
  1644. }
  1645.  
  1646. void edit_save_changes(slwindow *mywin) {
  1647.     IPT insertion_point;
  1648.     ULONG text_length;
  1649.     char *tmpfilename;
  1650.     FILE *tmpfile;
  1651.     spell *mod_spell, *old_spell;
  1652.     spellwindow *ptr;
  1653.     char *bptr;
  1654.     int i;
  1655.  
  1656.     WinSendMsg(mywin->hwndmle,MLM_SETREADONLY,(MPARAM)TRUE,0);
  1657.     mywin->readonly=true;
  1658.  
  1659.         
  1660.     // set up transfer buffer
  1661.     text_length=(ULONG)WinSendMsg(mywin->hwndmle,
  1662.                   MLM_QUERYTEXTLENGTH,
  1663.                   0,0);
  1664.     WinSendMsg(mywin->hwndmle,
  1665.            MLM_SETIMPORTEXPORT,
  1666.            (MPARAM)(&xfer_buffer),
  1667.            (MPARAM)10240);
  1668.     WinSendMsg(mywin->hwndmle,
  1669.            MLM_FORMAT,
  1670.            (MPARAM)MLFIE_CFTEXT,
  1671.            0);
  1672.     
  1673.     // get spell into transfer buffer
  1674.     insertion_point=0;
  1675.  
  1676.     WinSendMsg(mywin->hwndmle,
  1677.            MLM_EXPORT,
  1678.            (MPARAM)(&insertion_point),
  1679.            (MPARAM)(&text_length));
  1680.     
  1681.     // write spell to file
  1682.     tmpfilename=tmpnam(NULL);
  1683.     tmpfile=fopen(tmpfilename,"w");
  1684.     bptr=(char *)xfer_buffer;
  1685.     i=0;
  1686.     while (*bptr!=(char)0) {
  1687.     if (*bptr==(char)13) {
  1688.         fprintf(tmpfile,"\n");
  1689.         bptr++;
  1690.         i=0;
  1691.     }
  1692.     else if ((i>65) && (*bptr==' ')) {
  1693.         fprintf(tmpfile,"\n");
  1694.         i=0;
  1695.     }
  1696.     else fprintf(tmpfile,"%c",*bptr);
  1697.     bptr++;
  1698.     i++;
  1699.     }
  1700.     fprintf(tmpfile,"\n");
  1701.     fclose(tmpfile);
  1702.     
  1703.     // read it back in, deleting tmp file
  1704.     tmpfile=fopen(tmpfilename,"r");
  1705.     if (mywin->sl->s->type=='M') mod_spell=new magespell;
  1706.     else mod_spell=new priestspell;
  1707.     mod_spell->f_read(tmpfile);
  1708.     fclose(tmpfile);
  1709.     //unlink(tmpfilename);
  1710.  
  1711.     old_spell=mywin->sl->s;
  1712.     // get all spellbooks updated with the new spell, including parent of this window!
  1713.     for (ptr=first; ptr!=NULL; ptr=ptr->next) {
  1714.     ptr->change_spell(old_spell,mod_spell);
  1715.     }
  1716.  
  1717.     // write the spell to the end of "changed"
  1718.     tmpfile=fopen(CHANGEFILE,"a");
  1719.     fprintf(tmpfile,"-----\n");
  1720.     mod_spell->f_print(tmpfile);
  1721.     fclose(tmpfile);
  1722.  
  1723.     // show the new spell window
  1724.     find_and_show_spell(mywin->parent, mod_spell);
  1725.  
  1726.     // remove old spell, and my window
  1727.     delete old_spell;
  1728.     WinSendMsg(mywin->hwndmain,
  1729.            WM_CLOSE,
  1730.            0,
  1731.            0); 
  1732. }
  1733.  
  1734. // change mle to given spellist, if everything's OK.
  1735. void mle_set_spell(slwindow *mywin, spelllist *sl) {
  1736.     if (sl!=NULL) {
  1737.     if (!mywin->readonly) {
  1738.         ULONG response = WinMessageBox(HWND_DESKTOP,
  1739.                        HWND_DESKTOP,
  1740.                        (PSZ)"You are in the middle of editing.  Any changes will be lost.  Are you sure?",
  1741.                        (PSZ)"Warning!",
  1742.                        102,
  1743.                        MB_YESNO|MB_ICONEXCLAMATION);
  1744.         if (response==MBID_NO) return;
  1745.         mywin->readonly=true;
  1746.     }
  1747.     mywin->sl=sl;
  1748.     WinSetWindowText(mywin->hwndframe,(PSZ)mywin->sl->s->name);
  1749.     mle_show_spell(mywin->hwndmle,mywin->sl->s);
  1750.     }
  1751. }
  1752.  
  1753. // window function for spell window:
  1754. MRESULT EXPENTRY spell_window_func(HWND handle, ULONG msg, 
  1755.                    MPARAM param1, MPARAM param2) {
  1756.     slwindow *mywin;
  1757.     RECTL rcl;
  1758.     int cx,cy;
  1759.  
  1760.     switch (msg) {
  1761.     case WM_ERASEBACKGROUND:
  1762.     return (MRESULT)TRUE;
  1763.  
  1764.     case WM_CREATE:
  1765.     SWP windowpos;
  1766.  
  1767.     // save handle 
  1768.     firstspell->hwndmain=handle;
  1769.  
  1770.     // find out my size 
  1771.     WinQueryWindowRect(handle, (PRECTL)&rcl);
  1772.     
  1773.     // create multi line entry filling whole window 
  1774.     firstspell->hwndmle=
  1775.         WinCreateWindow(
  1776.                 handle,
  1777.                 WC_MLE,
  1778.                 (PSZ)0,
  1779.                 MLS_READONLY | MLS_WORDWRAP | MLS_VSCROLL,
  1780.                 rcl.xLeft,
  1781.                 rcl.yBottom,
  1782.                 rcl.xRight,
  1783.                 rcl.yTop,
  1784.                 handle,
  1785.                 HWND_TOP,
  1786.                 windows++,
  1787.                 NULL,
  1788.                 NULL);
  1789.  
  1790.     // fill mle with spell 
  1791.     mle_show_spell(firstspell->hwndmle, firstspell->sl->s);
  1792.  
  1793.     // and activate it 
  1794.     WinShowWindow(firstspell->hwndmle,TRUE);
  1795.  
  1796.     break;
  1797.  
  1798.     case WM_SIZE:
  1799.     mywin=spellwindowof(handle);
  1800.  
  1801.     cx=SHORT1FROMMP(param2);
  1802.     cy=SHORT2FROMMP(param2);
  1803.     // tell the MLE to change its size 
  1804.     WinSetWindowPos(mywin->hwndmle,0,0,0,cx,cy,SWP_SIZE);
  1805.  
  1806.     break;
  1807.  
  1808.  
  1809.     // menu is activated
  1810.     case WM_INITMENU:
  1811.     mywin=spellwindowof(handle);
  1812.     
  1813.     switch(SHORT1FROMMP(param1)) {
  1814.     case EDIT_SUBMENU:
  1815.         MRESULT mr1, mr2;
  1816.         BOOL enable;
  1817.  
  1818.         // see if text is selected in MLE
  1819.         mr1 = WinSendMsg(mywin->hwndmle, MLM_QUERYSEL,MPFROMSHORT(MLFQS_MINSEL), NULL);
  1820.         mr2 = WinSendMsg(mywin->hwndmle, MLM_QUERYSEL,MPFROMSHORT(MLFQS_MAXSEL), NULL);
  1821.         if (mr1 != mr2) enable = TRUE;
  1822.         else enable = FALSE;
  1823.  
  1824.         EnableMenuItem(HWNDFROMMP(param2), EDIT_COPY, enable);
  1825.  
  1826.         if (mywin->readonly) enable=FALSE;
  1827.         EnableMenuItem(HWNDFROMMP(param2), EDIT_CUT, enable);
  1828.         EnableMenuItem(HWNDFROMMP(param2), EDIT_CLEAR, enable);
  1829.  
  1830.         // if undoable, and !readonly, enable undo.
  1831.         if (!mywin->readonly) {
  1832.         mr1 =  WinSendMsg(mywin->hwndmle, MLM_QUERYUNDO, NULL, NULL);
  1833.         if (mr1 != 0) enable = TRUE;
  1834.         else enable = FALSE;
  1835.         }
  1836.         EnableMenuItem(HWNDFROMMP(param2), EDIT_UNDO, enable);
  1837.  
  1838.         // if clipboard has text, and !readonly, enable paste.
  1839.         if (!mywin->readonly) {
  1840.         if(WinOpenClipbrd(hand_ab))
  1841.         {
  1842.             ULONG ulFmtInfo;
  1843.             if (WinQueryClipbrdFmtInfo(hand_ab, CF_TEXT, &ulFmtInfo))
  1844.             enable = TRUE;
  1845.             else
  1846.             enable = FALSE;
  1847.             WinCloseClipbrd(hand_ab);
  1848.         }
  1849.         else
  1850.             enable = TRUE;
  1851.         }
  1852.         EnableMenuItem(HWNDFROMMP(param2), EDIT_PASTE, enable);
  1853.  
  1854.         // enable other menus depending on readonly status
  1855.         if (mywin->readonly) enable=TRUE;
  1856.         else enable=FALSE;
  1857.         EnableMenuItem(HWNDFROMMP(param2),EDIT_START,enable);
  1858.         EnableMenuItem(HWNDFROMMP(param2),EDIT_SAVECHANGES,!enable);
  1859.         EnableMenuItem(HWNDFROMMP(param2),EDIT_DISCARDCHANGES,!enable);
  1860.  
  1861.         break;
  1862.     }
  1863.     break;
  1864.     
  1865.     // command from menu 
  1866.     case WM_COMMAND:
  1867.     mywin=spellwindowof(handle);
  1868.     
  1869.     switch(SHORT1FROMMP(param1)) {
  1870.     case NEXTSPELL:
  1871.         mle_set_spell(mywin,mywin->sl->next);
  1872.         break;
  1873.  
  1874.     case PREVSPELL:
  1875.         mle_set_spell(mywin,mywin->sl->prev);
  1876.         break;
  1877.  
  1878.     case EDIT_UNDO:
  1879.         WinSendMsg(mywin->hwndmle,MLM_UNDO,0,0);
  1880.         break;
  1881.  
  1882.     case EDIT_CUT:
  1883.         WinSendMsg(mywin->hwndmle,MLM_CUT,0,0);
  1884.         break;
  1885.  
  1886.     case EDIT_CLEAR:
  1887.         WinSendMsg(mywin->hwndmle,MLM_CLEAR,0,0);
  1888.         break;
  1889.  
  1890.     case EDIT_COPY:
  1891.         WinSendMsg(mywin->hwndmle,MLM_COPY,0,0);
  1892.         break;
  1893.  
  1894.     case EDIT_PASTE:
  1895.         WinSendMsg(mywin->hwndmle,MLM_PASTE,0,0);
  1896.         break;
  1897.  
  1898.     case EDIT_START:
  1899.         WinSendMsg(mywin->hwndmle,MLM_SETREADONLY,(MPARAM)FALSE,0);
  1900.         mywin->readonly=false;
  1901.         break;
  1902.  
  1903.     case EDIT_SAVECHANGES:
  1904.         edit_save_changes(mywin);
  1905.         break;
  1906.  
  1907.     case EDIT_DISCARDCHANGES:
  1908.         WinSendMsg(mywin->hwndmle,MLM_SETREADONLY,(MPARAM)TRUE,0);
  1909.         mywin->readonly=true;
  1910.         mle_show_spell(mywin->hwndmle,mywin->sl->s);
  1911.         break;
  1912.  
  1913.     }
  1914.     break;
  1915.  
  1916.     case WM_CLOSE:
  1917.     mywin=spellwindowof(handle);
  1918.     delete mywin;
  1919.     return (MRESULT)TRUE;
  1920.     }
  1921.     return WinDefWindowProc(handle, msg, param1, param2);
  1922. }
  1923.  
  1924. main() {
  1925.     int i;
  1926.     HMQ hand_mq;  // message queue 
  1927.     QMSG q_mess;  // message queue 
  1928.     spellwindow *masterwindow;
  1929.  
  1930.     // define the frame contents 
  1931.     flFlags = FCF_TITLEBAR |
  1932.       FCF_SIZEBORDER|
  1933.       FCF_MINMAX|
  1934.       FCF_SYSMENU|
  1935.       FCF_MENU|
  1936.       FCF_ACCELTABLE|
  1937.       FCF_SHELLPOSITION;
  1938.  
  1939.     hand_ab=WinInitialize(0);  // get anchor block 
  1940.     hand_mq = WinCreateMsgQueue(hand_ab, 0); // start queue 
  1941.  
  1942.     // register the classes 
  1943.     if (!WinRegisterClass(
  1944.               hand_ab,
  1945.               (PSZ) spbclass,
  1946.               (PFNWP) book_window_func,
  1947.               CS_SIZEREDRAW,
  1948.               0))
  1949.     exit(1);
  1950.     if (!WinRegisterClass(
  1951.               hand_ab,
  1952.               (PSZ) splclass,
  1953.               (PFNWP) spell_window_func,
  1954.               CS_SIZEREDRAW,
  1955.               0))
  1956.     exit(1);
  1957.  
  1958.  
  1959.     // load in icons
  1960.     setupicons();
  1961.  
  1962.     // create first spell book with master list
  1963.     masterlist=get_master_list();
  1964.     masterwindow=new spellwindow;
  1965.     masterwindow->set_spellbook(masterlist);
  1966.     masterwindow->readonly=true;
  1967.     masterwindow->sort_book();
  1968.  
  1969.     // show copyright notice
  1970.     copyleft();
  1971.  
  1972.     // message loop 
  1973.     while(WinGetMsg(hand_ab, &q_mess, 0L,0,0))
  1974.     WinDispatchMsg(hand_ab, &q_mess);
  1975.  
  1976.     // shut down all remaining windows and quit 
  1977.     while (first!=NULL) delete first;
  1978.     while (firstspell!=NULL) delete firstspell;
  1979.     WinDestroyMsgQueue(hand_mq);
  1980.     WinTerminate(hand_ab);
  1981. }
  1982.  
  1983.  
  1984.  
  1985.