home *** CD-ROM | disk | FTP | other *** search
/ Informática Multimedia: Special Games / INFESPGAMES.mdf / os2 / spl / src / bookwin.cpp next >
Encoding:
C/C++ Source or Header  |  1994-07-26  |  35.0 KB  |  1,450 lines

  1. /* bookwin.cpp:  Spellbook control program
  2.  
  3.     Copyright (C) 1993, 1994 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. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include "spl.hpp"
  24. #include "general.hpp"
  25. #include "spldlg.h"
  26. #include "bookwin.hpp"
  27. #include "splwin.hpp"
  28. #include "spldlgs.hpp"
  29. #include "ea.hpp"
  30.  
  31. // stuff defined in the main program
  32. extern HAB hab;
  33. extern HINI hini;
  34. extern int windows;
  35. extern spellbook *masterlist;
  36. extern HPOINTER dragicon;
  37. extern HEV sem_object_started;
  38. extern HWND hwndhelp;
  39. extern char quick_master_name[256];
  40. extern BYTE xfer_buffer[10240];
  41.  
  42. bookwindow *first=NULL;  /* pointer to first spell window;
  43.                  must be most recently created one */
  44.  
  45.  
  46. // some common initialization for bookwindows; called by constructors
  47. void bookwindow::init(char *bookname) {
  48.     // create object thread, while initializing other stuff
  49.     tidobject = _beginthread(threadmain, NULL, 18000, this);
  50.  
  51.     ULONG flFlags = FCF_TITLEBAR |
  52.     FCF_SIZEBORDER|
  53.     FCF_MINMAX|
  54.     FCF_SYSMENU|
  55.     FCF_MENU|
  56.     FCF_TASKLIST|
  57.     FCF_ACCELTABLE;
  58.  
  59.     // add new window as the first one
  60.     next=first;
  61.     if (first!=NULL) first->prev=this;
  62.     first=this;
  63.     prev=NULL;
  64.     saved=true;
  65.     busy=false;
  66.     readonly=false;
  67.     hwndcnr=NULL;
  68.     hwnd=NULL;
  69.     hwndobject=NULL;
  70.     sb = new spellbook;
  71.     if (bookname) sb->name = strdup(bookname);
  72.     fontname=NULL;
  73.  
  74.     // create the window -- requires first to point to this window!
  75.     hwndframe = WinCreateStdWindow(
  76.                    HWND_DESKTOP,
  77.                    WS_VISIBLE,
  78.                    &flFlags,
  79.                    (PSZ)spbclass,
  80.                    (PSZ)bookname,
  81.                    WS_VISIBLE,
  82.                    0,
  83.                    BOOKMENU,
  84.                    NULL);
  85.  
  86.     // get help for this frame
  87.     if (hwndhelp)
  88.     WinAssociateHelpInstance(hwndhelp,hwndframe);
  89. }
  90.  
  91. // default constructor for a window not doing anything
  92. bookwindow::bookwindow(char *bookname) {
  93.     filename=NULL;
  94.     master_list_win = false;
  95.     init(bookname);
  96. }
  97.  
  98. // create bookwindow from a file name, or master list
  99. bookwindow::bookwindow(char *fname, boolean is_master) {
  100.     ULONG count_sem;
  101.  
  102. /*
  103.     if (masterlist) 
  104.     sprintf((char *)xfer_buffer,"%s",masterlist->name);
  105.     else sprintf((char *)xfer_buffer,"None");
  106.  
  107.     WinMessageBox(HWND_DESKTOP,
  108.           HWND_DESKTOP,
  109.           (PSZ)xfer_buffer,
  110.           (PSZ)"master name:",
  111.           102,
  112.           MB_OK);
  113. */
  114.  
  115.     // clear the semaphore; will be posted when object ready.
  116.     DosResetEventSem(sem_object_started, &count_sem);
  117.  
  118.     if (fname) filename = strdup(fname);
  119.     else filename=NULL;
  120.  
  121.     master_list_win = is_master;
  122.     
  123.     init(NULL);
  124.  
  125.     // make the window busy.
  126.     this->disable();
  127.  
  128.     // wait for object window to be ready.
  129.     DosWaitEventSem(sem_object_started, SEM_INDEFINITE_WAIT);
  130.  
  131.     if (is_master) {
  132.     WinPostMsg(hwndobject,
  133.            WM_USER_SHOW_MASTER,
  134.            0,0);
  135.     readonly=true;
  136.     }
  137.     else {
  138.     WinPostMsg(hwndobject,
  139.            WM_USER_LOAD,
  140.            0,0);
  141.     }
  142. }
  143.  
  144. bookwindow::~bookwindow() {
  145.     // kill off object window
  146.     WinPostMsg(hwndobject,WM_QUIT,0,0);
  147.     // and wait for object thread to finish
  148.     DosWaitThread(&tidobject,DCWW_WAIT);
  149.  
  150.     // remove from display
  151.     WinDestroyWindow(hwndframe);
  152.  
  153.     // remove from linked list
  154.     if (this==first) first=next;
  155.     if (next!=NULL) next->prev=prev;
  156.     if (prev!=NULL) prev->next=next;
  157.  
  158.     delete sb; // but not the spells inside!
  159.  
  160.     // delete this last, since used during WM_DESTROY
  161.     if (filename) delete filename;
  162.     if (fontname) delete fontname;
  163. }
  164.  
  165. // make window busy
  166. void bookwindow::disable() {
  167.     busy=true;
  168.     WinEnableWindow(hwnd,FALSE);
  169.     WinEnableWindow(hwndcnr,FALSE);
  170. }
  171.  
  172. // re-enable window
  173. void bookwindow::enable() {
  174.     busy=false;
  175.     WinEnableWindow(hwnd,TRUE);
  176.     WinEnableWindow(hwndcnr,TRUE);
  177. }
  178.  
  179. // save spellbook as list of spells.
  180. boolean bookwindow::save_book(boolean just_titles) {
  181.     FILEDLG fd;
  182.  
  183.     // clear all fields to zero before proceeding
  184.     memset(&fd,0,sizeof(FILEDLG));
  185.  
  186.     // set up file dialog
  187.     fd.cbSize=sizeof(FILEDLG);
  188.     fd.fl=FDS_CENTER|FDS_SAVEAS_DIALOG;
  189.     if (just_titles)
  190.     fd.pszTitle=(PSZ)"Save spellbook to file:";
  191.     else
  192.     fd.pszTitle=(PSZ)"Save spellbook to file (with full descriptions):";
  193.     if (filename)
  194.     strcpy(fd.szFullFile,filename);
  195.     else
  196.     strcpy(fd.szFullFile,"*.sbk");
  197.  
  198.     if (!WinFileDlg(HWND_DESKTOP,
  199.             hwnd,
  200.             &fd)) return(false);
  201.  
  202.     if (fd.lReturn==DID_OK) {
  203.     if (filename) delete filename;
  204.     filename=strdup(fd.szFullFile);
  205.     // send message in order to wait for it to finish.
  206.     WinSendMsg(hwndobject,
  207.            WM_USER_SAVE,
  208.            (MPARAM)just_titles,0);
  209.     return(true);
  210.     }
  211.     else return(false);
  212. }
  213.  
  214.  
  215. // load a new spellbook from a file
  216. boolean load_book() {
  217.     FILEDLG fd;
  218.  
  219.     // clear all fields to zero before proceeding
  220.     memset(&fd,0,sizeof(FILEDLG));
  221.  
  222.     // set up file dialog
  223.     fd.cbSize=sizeof(FILEDLG);
  224.     fd.fl=FDS_CENTER|FDS_OPEN_DIALOG;
  225.     fd.pszTitle=(PSZ)"Load spellbook from file:";
  226.     strcpy(fd.szFullFile,"*.sbk");
  227.  
  228.     if (!WinFileDlg(HWND_DESKTOP,
  229.             HWND_DESKTOP,
  230.             &fd)) return(false);
  231.  
  232.     if (fd.lReturn==DID_OK) {
  233.     new bookwindow(fd.szFullFile,false);
  234.     return(true);
  235.     }
  236.     else return(false);
  237. }
  238.  
  239.  
  240. // insert fields for name and spell level
  241. boolean bookwindow::insert_fields() {
  242.     FIELDINFOINSERT fiins;
  243.     PFIELDINFO pfi;
  244.     int i;
  245.     int fields = 10;
  246.     CNRINFO cnrinfo;
  247.  
  248.     static const PSZ TitleData[] = {NULL,
  249.                     "Name of Spell",
  250.                     "Lvl",
  251.                     "Cast",
  252.                     "Range",
  253.                     "Duration",
  254.                     "Area",
  255.                     "School / Sphere",
  256.                     "Comp.",
  257.                     "Save"};
  258.  
  259.     static const ULONG flData[] = {CFA_BITMAPORICON,
  260.                    CFA_STRING|CFA_HORZSEPARATOR,
  261.                    CFA_ULONG|CFA_SEPARATOR|
  262.                        CFA_INVISIBLE|CFA_HORZSEPARATOR,
  263.                    CFA_STRING|CFA_HORZSEPARATOR|
  264.                        CFA_INVISIBLE|CFA_SEPARATOR,
  265.                    CFA_STRING|CFA_HORZSEPARATOR|
  266.                        CFA_INVISIBLE|CFA_SEPARATOR,
  267.                    CFA_STRING|CFA_HORZSEPARATOR|
  268.                        CFA_INVISIBLE|CFA_SEPARATOR,
  269.                    CFA_STRING|CFA_HORZSEPARATOR|
  270.                        CFA_INVISIBLE|CFA_SEPARATOR,
  271.                    CFA_STRING|CFA_HORZSEPARATOR|
  272.                        CFA_INVISIBLE|CFA_SEPARATOR,
  273.                    CFA_STRING|CFA_HORZSEPARATOR|
  274.                        CFA_INVISIBLE|CFA_SEPARATOR,
  275.                    CFA_STRING|CFA_HORZSEPARATOR|
  276.                        CFA_INVISIBLE};
  277.  
  278. // these are the correct macro expansions of:
  279. //FIELDOFFSET(spellrecord,level)
  280. // and so on...
  281.     static const ULONG offStruct[] = {((ULONG)&(((spellrecord *)0)->core.hptrMiniIcon)),
  282.                       ((ULONG)&(((spellrecord *)0)->core.pszText)),
  283.                       ((ULONG)&(((spellrecord *)0)->level)),
  284.                       ((ULONG)&(((spellrecord *)0)->cast)),
  285.                       ((ULONG)&(((spellrecord *)0)->range)),
  286.                       ((ULONG)&(((spellrecord *)0)->duration)),
  287.                       ((ULONG)&(((spellrecord *)0)->area)),
  288.                       ((ULONG)&(((spellrecord *)0)->sphereschool)),
  289.                       ((ULONG)&(((spellrecord *)0)->components)),
  290.                       ((ULONG)&(((spellrecord *)0)->save))};
  291.  
  292.  
  293.     // get memory for fields
  294.     pfi = pfieldinfo = (PFIELDINFO)WinSendMsg(hwndcnr,
  295.                           CM_ALLOCDETAILFIELDINFO,
  296.                           MPFROMLONG(fields),
  297.                           NULL);
  298.  
  299.     // initialize them
  300.     for (i=0; i<fields; i++) {
  301.     pfi->cb = sizeof(FIELDINFO);
  302.     pfi->flData = flData[i] | CFA_FIREADONLY;
  303.     pfi->flTitle = CFA_FITITLEREADONLY | CFA_LEFT;
  304.     pfi->pTitleData = (PVOID)TitleData[i];
  305.     pfi->offStruct = offStruct[i];
  306.     pfi = pfi->pNextFieldInfo;
  307.     }
  308.  
  309.     // initialize FIELDINFOINSERT
  310.     fiins.cb = sizeof fiins;
  311.     fiins.pFieldInfoOrder = (PFIELDINFO)CMA_FIRST;
  312.     fiins.cFieldInfoInsert = fields;
  313.     fiins.fInvalidateFieldInfo = TRUE;
  314.  
  315.     // tell cnr to insert it
  316.     WinSendMsg(hwndcnr,
  317.            CM_INSERTDETAILFIELDINFO,
  318.            MPFROMP(pfieldinfo),
  319.            MPFROMP(&fiins));
  320.  
  321.     // place vertical scroll var after "name" column
  322.     cnrinfo.xVertSplitbar = splitbarpos;
  323.     cnrinfo.pFieldInfoLast = pfieldinfo->pNextFieldInfo; // 2nd field
  324.     WinSendMsg(hwndcnr,
  325.            CM_SETCNRINFO,
  326.            MPFROMP(&cnrinfo),
  327.            MPFROMLONG(CMA_PFIELDINFOLAST | CMA_XVERTSPLITBAR));
  328.  
  329.     return(true);
  330. }
  331.  
  332. // tell container which details fields to show
  333. void bookwindow::show_fields() {
  334.     ULONG f=details_fields;
  335.     int i;
  336.     ULONG flag=1;
  337.     PFIELDINFO pfi = pfieldinfo;
  338.  
  339.     // move to 3rd field.
  340.     pfi = pfi->pNextFieldInfo;
  341.     pfi = pfi->pNextFieldInfo;
  342.  
  343.     for (i=0; i<8; i++) {
  344.     if (f & flag) {  // &= !CFA_INVISIBLE doesn't work.
  345.         pfi->flData |= CFA_INVISIBLE;
  346.         pfi->flData ^= CFA_INVISIBLE;
  347.     }
  348.     else pfi->flData |= CFA_INVISIBLE;
  349.     flag *= 2;
  350.     pfi = pfi->pNextFieldInfo;
  351.     }
  352.  
  353.     WinSendMsg(hwndcnr,
  354.            CM_INVALIDATEDETAILFIELDINFO,
  355.            0,0);
  356. }
  357.  
  358. // query split bar pos, as while saving window
  359. void bookwindow::query_splitbar() {
  360.     CNRINFO cnrinfo;
  361.  
  362.     WinSendMsg(hwndcnr,
  363.            CM_QUERYCNRINFO,
  364.            MPFROMP(&cnrinfo),
  365.            (MPARAM)sizeof(cnrinfo));
  366.     splitbarpos = cnrinfo.xVertSplitbar;
  367. }
  368.  
  369. // load and set window attributes for a bookwindow
  370. void bookwindow::load_attr() {
  371.     SWP swp;
  372.     book_attr ba;
  373.     boolean foundpos;
  374.     ULONG ultemp;
  375.     long ltemp;
  376.     SHORT w,h;
  377.  
  378.     // get default values
  379.     WinQueryTaskSizePos(hab,0,&swp);
  380.     ba.view = CV_NAME;
  381.     ba.miniicon = CV_MINI;
  382.     ba.splitbarpos = 250;
  383.     ba.x = swp.x;
  384.     ba.y = swp.y;
  385.     ba.cx = swp.cx;
  386.     ba.cy = swp.cy;
  387.     ba.foregroundcolor = 0;
  388.     ba.backgroundcolor = 0;
  389.     ba.fontnamesize[0] = (char)0;
  390.     ba.details_fields = FL_LEVEL | FL_SPHERESCHOOL;
  391.  
  392.     foundpos=false;
  393.     if (master_list_win) { 
  394.     ultemp=sizeof(book_attr);
  395.     PrfQueryProfileData(hini,
  396.                 "spellbook",
  397.                 "bookattr",
  398.                 &ba,
  399.                 &ultemp);
  400.     foundpos=true;
  401.     }
  402.     else if (filename) {
  403.     ltemp=sizeof(book_attr);
  404.     if (getEA(filename,
  405.           ".bookattr",
  406.           &ba,
  407.           <emp)==0)
  408.         foundpos=true;
  409.     }
  410.  
  411.     if (!foundpos) {
  412.     // get generic width, height; use random x,y;
  413.     ultemp=sizeof(book_attr);
  414.     PrfQueryProfileData(hini,
  415.                 "spellbook",
  416.                 "newbookattr",
  417.                 &ba,
  418.                 &ultemp);
  419.     ba.x = swp.x;
  420.     ba.y = swp.y;
  421.     }
  422.  
  423.     // make sure we aren't off screen.
  424.     w = WinQuerySysValue(HWND_DESKTOP,SV_CXSCREEN);
  425.     h = WinQuerySysValue(HWND_DESKTOP,SV_CYSCREEN);
  426.     if (ba.x+ba.cx > w) ba.x = w - ba.cx;
  427.     if (ba.y+ba.cy > h) ba.y = h - ba.cy;
  428.     
  429.     // set the position & size
  430.     hwndframe = WinQueryWindow(hwnd,QW_PARENT);
  431.     WinSetWindowPos(hwndframe,
  432.             HWND_TOP,
  433.             ba.x,ba.y,
  434.             ba.cx,ba.cy,
  435.             SWP_SIZE|SWP_SHOW|SWP_MOVE|SWP_ZORDER);
  436.  
  437.     view = ba.view;
  438.     miniicon = ba.miniicon;
  439.     splitbarpos = ba.splitbarpos;
  440.     details_fields = ba.details_fields;
  441.  
  442.     // set colors and fonts
  443.     if (ba.foregroundcolor)
  444.     WinSetPresParam(hwndcnr,
  445.             PP_FOREGROUNDCOLOR,
  446.             sizeof(ULONG),
  447.             &ba.foregroundcolor);
  448.     if (ba.backgroundcolor)
  449.     WinSetPresParam(hwndcnr,
  450.             PP_BACKGROUNDCOLOR,
  451.             sizeof(ULONG),
  452.             &ba.backgroundcolor);
  453.     if (ba.fontnamesize[0]) {
  454.     fontname = strdup(ba.fontnamesize);
  455.     WinSetPresParam(hwndcnr,
  456.             PP_FONTNAMESIZE,
  457.             (ULONG)(strlen(fontname)+1),
  458.             fontname);
  459.     }
  460. }
  461.  
  462. // save visible attributes of bookwindow
  463. void bookwindow::save_attr() {
  464.     SWP swp;
  465.     book_attr ba;
  466.     ULONG attrfound;
  467.     ULONG attrvalue[32];
  468.     ULONG rc;
  469.     
  470.     query_splitbar();
  471.     WinQueryWindowPos(hwndframe,&swp);
  472.     ba.view = view;
  473.     ba.miniicon = miniicon;
  474.     ba.splitbarpos = splitbarpos;
  475.     ba.x = swp.x;
  476.     ba.y = swp.y;
  477.     ba.cx = swp.cx;
  478.     ba.cy = swp.cy;
  479.     ba.details_fields = details_fields;
  480.  
  481.     rc=WinQueryPresParam(hwndcnr,
  482.              PP_FOREGROUNDCOLOR,
  483.              0,
  484.              &attrfound,
  485.              sizeof(attrvalue),
  486.              (PVOID)attrvalue,
  487.              0);
  488.     if (rc && (attrfound == PP_FOREGROUNDCOLOR))
  489.     memcpy(&ba.foregroundcolor,attrvalue,sizeof(ULONG));
  490.     else ba.foregroundcolor=0;
  491.  
  492.     rc=WinQueryPresParam(hwndcnr,
  493.              PP_BACKGROUNDCOLOR,
  494.              0,
  495.              &attrfound,
  496.              sizeof(attrvalue),
  497.              (PVOID)attrvalue,
  498.              0);
  499.     if (rc && (attrfound == PP_BACKGROUNDCOLOR))
  500.     memcpy(&ba.backgroundcolor,attrvalue,sizeof(ULONG));
  501.     else ba.backgroundcolor=0;
  502.  
  503.     rc=WinQueryPresParam(hwndcnr,
  504.              PP_FONTNAMESIZE,
  505.              0,
  506.              &attrfound,
  507.              sizeof(attrvalue),
  508.              (PVOID)attrvalue,
  509.              0);
  510.     if (rc && (attrfound == PP_FONTNAMESIZE)) {
  511.     if (rc>127) rc=127;
  512.     ba.fontnamesize[rc]=(char)0;
  513.     memcpy(ba.fontnamesize,attrvalue,rc);
  514.     }
  515.     else ba.fontnamesize[0]=(char)0;
  516.  
  517.  
  518.     if (master_list_win) {
  519.     PrfWriteProfileData(hini,
  520.                 "spellbook",
  521.                 "bookattr",
  522.                 &ba,
  523.                 sizeof(book_attr));
  524.     }
  525.     else if (filename) {
  526.     putEA(filename,
  527.           ".bookattr",
  528.           &ba,
  529.           sizeof(book_attr)); 
  530.     }
  531.     else {
  532.     PrfWriteProfileData(hini,
  533.                 "spellbook",
  534.                 "newbookattr",
  535.                 &ba,
  536.                 sizeof(book_attr));
  537.     }
  538. }
  539.  
  540. // add spell to a window, after spell "where" (and to book also)
  541. boolean bookwindow::add_spell(spell *s, spellrecord *where) {
  542.     spellrecord *newrecord;
  543.     LONG extrabytes;
  544.     HPOINTER myicon;
  545.     priestspell *ps = (priestspell *)s;
  546.  
  547.     extrabytes=(LONG)(sizeof(spellrecord)-sizeof(RECORDCORE));
  548.     // tell the container to allocate memory for new record 
  549.     newrecord=(spellrecord *)WinSendMsg(hwndcnr,
  550.                     CM_ALLOCRECORD,
  551.                     MPFROMLONG(extrabytes),
  552.                     (MPARAM)1);
  553.         
  554.     // set up record 
  555.     newrecord->core.flRecordAttr=0;
  556.     newrecord->s=s;
  557.     newrecord->level = (ULONG)s->level;
  558.     newrecord->cast = ps->casttime;
  559.     newrecord->range = ps->range;
  560.     newrecord->duration = ps->duration;
  561.     newrecord->area = ps->area;
  562.     if (s->type=='M')
  563.     newrecord->sphereschool = ps->school;
  564.     else 
  565.     newrecord->sphereschool = ps->sphere;
  566.     newrecord->components = ps->components;    
  567.     newrecord->save = ps->save;
  568.     newrecord->core.pszIcon=(PSZ)s->name;
  569.     newrecord->core.pszText=(PSZ)s->name;
  570.     newrecord->core.pszName=(PSZ)s->name;
  571.     myicon=lookup_icon(s);
  572.     newrecord->core.hptrIcon=myicon;
  573.     newrecord->core.hptrMiniIcon=myicon;
  574.     newrecord->core.preccNextRecord=0;
  575.         
  576.     // tell the container to add the record 
  577.     RECORDINSERT ri;
  578.     ri.cb=sizeof(RECORDINSERT);
  579.     if (where==NULL) 
  580.       ri.pRecordOrder=(PRECORDCORE)CMA_END;
  581.     else
  582.       ri.pRecordOrder=&(where->core);
  583.     ri.pRecordParent=NULL;
  584.     ri.fInvalidateRecord=FALSE;
  585.     ri.zOrder=CMA_TOP;
  586.     ri.cRecordsInsert=1;
  587.     
  588.     WinSendMsg(hwndcnr,
  589.            CM_INSERTRECORD,
  590.            MPFROMP(newrecord),
  591.            MPFROMP(&ri));
  592.  
  593.     // add to spellbook, also
  594.     if (where==NULL)  // add at end.
  595.     newrecord->spl = sb->add_spell(*s, sb->last);
  596.     else  // add after where
  597.     newrecord->spl = sb->add_spell(*s, where->spl);
  598.  
  599.     if (!readonly) saved=false;
  600.     return(true);
  601. }
  602.  
  603. // add a new spell to a window
  604. boolean bookwindow::add_new_spell() {
  605.     static int i=0;
  606.     char *buffer;
  607.     
  608.     spell *newspell;
  609.  
  610.     // edit new spell in editor
  611.  
  612.     // load new spell into window
  613.     newspell=new magespell;
  614.     buffer=new char[100];
  615.     sprintf(buffer,"New spell # %d\n",i++);
  616.     newspell->name=buffer;
  617.  
  618.     // insert spell after first emphasized record, if any
  619.     spellrecord *insafter;
  620.     insafter=(spellrecord *)
  621.     PVOIDFROMMR(WinSendMsg(hwndcnr,
  622.                    CM_QUERYRECORDEMPHASIS,
  623.                    MPFROMP(CMA_FIRST),
  624.                    MPFROMSHORT(CRA_SELECTED)));
  625.  
  626.     if (insafter==NULL)
  627.       add_spell(newspell);
  628.     else
  629.       add_spell(newspell,insafter);
  630.  
  631.     refresh();
  632.     return(true);
  633. }
  634.  
  635. // delete a spell from window and from the book.
  636. boolean bookwindow::delete_spell(spellrecord *deleteme) {
  637.   PVOID removeme=&(deleteme);
  638.  
  639.   // remove from spellbook
  640.   sb->del_spell(deleteme->spl);
  641.  
  642.   // and from window
  643.   WinSendMsg(hwndcnr,
  644.          CM_REMOVERECORD,
  645.          MPFROMP(removeme),
  646.          MPFROM2SHORT(1,CMA_FREE));
  647.  
  648.   if (!readonly) saved=false;
  649.   return(true);
  650. }
  651.  
  652. // delete all selected spells from window, then update the window.
  653. boolean bookwindow::delete_selected_spells() {
  654.     spellrecord *deleteme;
  655.  
  656.     while (deleteme=(spellrecord *)
  657.        WinSendMsg(hwndcnr,
  658.               CM_QUERYRECORDEMPHASIS,
  659.               MPFROMP(CMA_FIRST),
  660.               MPFROMSHORT(CRA_SELECTED)))
  661.     delete_spell(deleteme);
  662.  
  663.     refresh();
  664.     return(true);
  665. }
  666.  
  667. // is a given record selected? 
  668. boolean selected(spellrecord *x) {
  669.     if (x->core.flRecordAttr & CRA_SELECTED) return(true);
  670.     else return(false);
  671. }
  672.  
  673. // refresh spell window 
  674. boolean bookwindow::refresh() {
  675.     WinSendMsg(hwndcnr,
  676.            CM_INVALIDATERECORD,
  677.            (MPARAM)0,
  678.            MPFROM2SHORT(0,CMA_REPOSITION));
  679.     return(true);
  680. }
  681.  
  682. // change spell, update screen and spellbook.
  683. boolean bookwindow::change_spell(spell *oldsp, spell *newsp) {
  684.     spellrecord *found;
  685.     SEARCHSTRING oldname;
  686.  
  687.     oldname.pszSearch=(PSZ)oldsp->name;
  688.     oldname.fsPrefix=TRUE;
  689.     oldname.fsCaseSensitive=TRUE;
  690.     oldname.usView=CV_NAME;
  691.     oldname.cb=sizeof(oldname);
  692.  
  693.     found=(spellrecord *)WinSendMsg(hwndcnr,
  694.                     CM_SEARCHSTRING,
  695.                     (MPARAM)(&oldname),
  696.                     (MPARAM)CMA_FIRST);
  697.  
  698.     if (!found) return(false);
  699.  
  700.     // name match does not imply a real match.
  701.     if (found->s == oldsp) {
  702.     add_spell(newsp,found);
  703.     delete_spell(found);
  704.     refresh();
  705.     return (true);
  706.     }
  707.     return(false);
  708. }
  709.  
  710. void show_spell(bookwindow *mywin, MPARAM whichspell) {
  711.     char buffer[256];
  712.     PNOTIFYRECORDENTER pn;
  713.     spellrecord *selected;
  714.     spellwindow *child;
  715.  
  716.     pn = (PNOTIFYRECORDENTER)whichspell;
  717.     selected = (spellrecord *)(pn->pRecord);
  718.     if (selected)
  719.     child = new spellwindow(selected->spl, mywin);
  720. }
  721.  
  722. void find_and_show_spell(bookwindow *mywin, spell *s) {
  723.     spellrecord *found;
  724.     SEARCHSTRING oldname;
  725.     spellwindow *child;
  726.  
  727.     oldname.pszSearch=(PSZ)s->name;
  728.     oldname.fsPrefix=TRUE;
  729.     oldname.fsCaseSensitive=TRUE;
  730.     oldname.usView=CV_NAME;
  731.     oldname.cb=sizeof(oldname);
  732.  
  733.     found=(spellrecord *)WinSendMsg(mywin->hwndcnr,
  734.                     CM_SEARCHSTRING,
  735.                     (MPARAM)(&oldname),
  736.                     (MPARAM)CMA_FIRST);
  737.  
  738.     if (!found) return;
  739.  
  740.     // name match does not imply a real match.
  741.     if (found->s == s)
  742.     child = new spellwindow(found->spl, mywin);
  743. }
  744.  
  745. MRESULT drop_spell(bookwindow *mywin, PCNRDRAGINFO pcdi) {
  746.     char buffer[256];
  747.     int items;
  748.     PDRAGINFO pdraginfo;
  749.  
  750.     pdraginfo=pcdi->pDragInfo;
  751.  
  752.     // make sure we can access the draginfo structure
  753.     if (!DrgAccessDraginfo(pdraginfo))
  754.     return(MRFROM2SHORT(DOR_NODROPOP,0));
  755.     
  756.     // how many items?
  757.     items=DrgQueryDragitemCount(pdraginfo);
  758.  
  759.     spellrecord *dropped_on;
  760.     PDRAGITEM pditem;
  761.     spellrecord *dropping;
  762.     // add each item
  763.     if (pcdi->pRecord) {            // if dropped on another spell
  764.     for (int i=items-1; i>=0; i--) {
  765.         pditem=DrgQueryDragitemPtr(pdraginfo,i);
  766.         
  767.         // add after record it was dropped on
  768.         dropped_on=(spellrecord *)(pcdi->pRecord);
  769.         dropping=(spellrecord *)pditem->ulItemID;
  770.         mywin->add_spell(dropping->s,dropped_on);
  771.  
  772.         // dropped on same window -> delete old item
  773.         if (mywin->hwnd==pditem->hwndItem)
  774.         mywin->delete_spell(dropping);
  775.     }
  776.     }
  777.     else {                             // dropped on empty space
  778.     for (int i=0; i<items; i++) {
  779.         pditem=DrgQueryDragitemPtr(pdraginfo,i);
  780.         
  781.         // add at end
  782.         dropping=(spellrecord *)pditem->ulItemID;
  783.         mywin->add_spell(dropping->s);
  784.  
  785.         // dropped on same window -> delete old item
  786.         if (mywin->hwnd==pditem->hwndItem) 
  787.           mywin->delete_spell(dropping);
  788.     }
  789.     }
  790.  
  791.     mywin->refresh();
  792.  
  793.     DrgFreeDraginfo(pdraginfo);
  794.  
  795.     return((MRESULT)0);
  796. }
  797.  
  798.  
  799. // something is being dragged over the container
  800. MRESULT drag_over(bookwindow *mywin, PDRAGINFO pdraginfo) {
  801.     USHORT usIndicator=DOR_DROP,usOperation;
  802.     int items;
  803.  
  804.     if (mywin->readonly) return(MRFROM2SHORT(DOR_NEVERDROP,DO_COPY));
  805.  
  806.     // make sure we can access the draginfo structure
  807.     if (!DrgAccessDraginfo(pdraginfo)) 
  808.     return(MRFROM2SHORT(DOR_NODROPOP,0));
  809.     
  810.     // how many items?
  811.     items=DrgQueryDragitemCount(pdraginfo);
  812.  
  813.     // check each item
  814.     for (int i=0; i<items; i++) {
  815.     PDRAGITEM pditem;
  816.     pditem=DrgQueryDragitemPtr(pdraginfo,i);
  817.     if (!DrgVerifyRMF(pditem,(PSZ)"Spell",(PSZ)"Spell"))
  818.         usIndicator=DOR_NEVERDROP;
  819.     }
  820.  
  821.     // only operation for spells
  822.     usOperation=DO_COPY;
  823.  
  824.     DrgFreeDraginfo(pdraginfo);
  825.     return(MRFROM2SHORT(usIndicator,usOperation));
  826. }
  827.  
  828. BOOL init_drag(bookwindow *mywin,PCNRDRAGINIT pcdi) {
  829.     char buffer[256];
  830.     ULONG items;
  831.     spellrecord *selected;
  832.  
  833.     // no dragging from empty space
  834.     if (pcdi->pRecord==NULL) return(FALSE);
  835.  
  836.     // if record is selected, it may be part of a group 
  837.     if (pcdi->pRecord->flRecordAttr & CRA_SELECTED) {
  838.     // find # of items being dragged
  839.     items=0;
  840.     selected=(spellrecord *)WinSendMsg(mywin->hwndcnr,
  841.                        CM_QUERYRECORDEMPHASIS,
  842.                        MPFROMP(CMA_FIRST),
  843.                        MPFROMSHORT(CRA_SELECTED));
  844.     while (selected!=NULL) {
  845.         selected=(spellrecord *)WinSendMsg(mywin->hwndcnr,
  846.                            CM_QUERYRECORDEMPHASIS,
  847.                            MPFROMP(selected),
  848.                            MPFROMSHORT(CRA_SELECTED));
  849.         items++;
  850.     }
  851.     }
  852.     else items=1;
  853.  
  854.     // no items dragged?  shouldn't get here.
  855.     if (items==0) return (FALSE);
  856.  
  857.     // get DRAGINFO structure
  858.     PDRAGINFO pdraginfo;
  859.     pdraginfo=DrgAllocDraginfo(items);
  860.  
  861.     DRAGITEM dragitem;
  862.  
  863.     // common parts of DRAGITEM structure
  864.     dragitem.hwndItem=mywin->hwnd;
  865.     dragitem.hstrType=DrgAddStrHandle((PSZ)"Spell");
  866.     dragitem.hstrRMF=DrgAddStrHandle((PSZ)"<Spell,Spell>");
  867.     dragitem.hstrContainerName=NULL;
  868.     dragitem.fsControl=0;
  869.     dragitem.fsSupportedOps=DO_COPYABLE;
  870.  
  871.     // add each dragged item
  872.     selected=(spellrecord *)CMA_FIRST;
  873.     for (int i=0; i<items; i++) {
  874.     if (items==1) 
  875.         // if there's only 1 item, it must be the one direct
  876.         // manipulation started on.
  877.         selected=(spellrecord *)pcdi->pRecord;
  878.     else
  879.         selected=(spellrecord *)WinSendMsg(mywin->hwndcnr,
  880.                            CM_QUERYRECORDEMPHASIS,
  881.                            MPFROMP(selected),
  882.                            MPFROMSHORT(CRA_SELECTED));
  883.  
  884.     dragitem.hstrSourceName=DrgAddStrHandle(selected->core.pszText);
  885.     dragitem.hstrTargetName=dragitem.hstrSourceName;
  886.     dragitem.ulItemID=(ULONG)selected;
  887.  
  888.     // add dragitem to draginfo structure
  889.     DrgSetDragitem(pdraginfo,&dragitem,sizeof(DRAGITEM),i);
  890.     }
  891.  
  892.     DRAGIMAGE dimg;
  893.     if (items==1) 
  894.     dimg.hImage=lookup_icon(selected->s);
  895.     else dimg.hImage=dragicon;
  896.     dimg.fl=DRG_ICON;
  897.     dimg.cb=sizeof(DRAGIMAGE);
  898.     dimg.cxOffset=0;
  899.     dimg.cyOffset=0;
  900.  
  901.     pdraginfo->hwndSource=mywin->hwnd;
  902.     HWND destination;
  903.     destination = DrgDrag(mywin->hwndcnr,pdraginfo,&dimg,1,VK_ENDDRAG,NULL);
  904.  
  905.     return(TRUE);
  906. }
  907.  
  908. MRESULT savequit(bookwindow *mywin) {
  909.     // has window been saved? 
  910.     if ((!mywin->readonly) && (!mywin->saved)) {
  911.     ULONG response;
  912.     response= WinMessageBox(HWND_DESKTOP,
  913.                 HWND_DESKTOP,
  914.                 (PSZ)"Save spellbook before closing?",
  915.                 (PSZ)"Spellbook changed since last save",
  916.                 102,
  917.                 MB_YESNOCANCEL|MB_ICONQUESTION);
  918.     if (response==MBID_YES) {
  919.         if (!mywin->save_book(false)) return((MRESULT)FALSE);
  920.     }
  921.     else if (response==MBID_CANCEL) return((MRESULT)FALSE);
  922.     }
  923.     
  924.     if (first->next==NULL) { //this is the last window 
  925.     ULONG response = WinMessageBox(HWND_DESKTOP,
  926.                        HWND_DESKTOP,
  927.                        (PSZ)"Closing the last spellbook will end the program.  Are you sure?",
  928.                        (PSZ)"Warning!",
  929.                        102,
  930.                        MB_YESNO|MB_ICONEXCLAMATION);
  931.     if (response==MBID_YES)
  932.         WinPostMsg(mywin->hwnd,WM_QUIT,0,0);
  933.     }
  934.     else {
  935.     delete mywin;
  936.     return ((MRESULT)TRUE);
  937.     }
  938.     
  939.     return ((MRESULT)TRUE);
  940. }
  941.  
  942. // show spellbook in given mode
  943. void bookwindow::show() {
  944.     CNRINFO cnrInfo;
  945.     MENUITEM mi;
  946.     HWND hwndmenu;
  947.     static LONG iconcx = 0;
  948.     static LONG iconcy = 0;
  949.  
  950.     if (iconcx==0) {
  951.     // find "normal" icon size from system values
  952.     iconcx = WinQuerySysValue(HWND_DESKTOP,
  953.                   SV_CXICON);
  954.     iconcy = WinQuerySysValue(HWND_DESKTOP,
  955.                   SV_CYICON);
  956.     }
  957.  
  958.     // check items on main menu
  959.     check_menu_item(hwndframe,
  960.             VIEW_SUBMENU,
  961.             V_TEXT,
  962.             view & CV_TEXT ? TRUE : FALSE);
  963.  
  964.     check_menu_item(hwndframe,
  965.             VIEW_SUBMENU,
  966.             V_NAME,
  967.             view & CV_NAME ? TRUE : FALSE);
  968.  
  969.     check_menu_item(hwndframe,
  970.             VIEW_SUBMENU,
  971.             V_ICON,
  972.             view & CV_ICON ? TRUE : FALSE);
  973.  
  974.     check_menu_item(hwndframe,
  975.             VIEW_SUBMENU,
  976.             V_DETAIL,
  977.             view & CV_DETAIL ? TRUE : FALSE);
  978.  
  979.     check_menu_item(hwndframe,
  980.             VIEW_SUBMENU,
  981.             V_FULLICON,
  982.             miniicon ? FALSE : TRUE);
  983.  
  984.     check_menu_item(hwndframe,
  985.             VIEW_SUBMENU,
  986.             V_MINIICON,
  987.             miniicon ? TRUE : FALSE);
  988.  
  989.     // check items on popup menus
  990.     WinCheckMenuItem(hwndpopup,
  991.              V_TEXT,
  992.              view & CV_TEXT ? TRUE : FALSE);
  993.  
  994.     WinCheckMenuItem(hwndpopup,
  995.              V_NAME,
  996.              view & CV_NAME ? TRUE : FALSE);
  997.  
  998.     WinCheckMenuItem(hwndpopup,
  999.              V_ICON,
  1000.              view & CV_ICON ? TRUE : FALSE);
  1001.  
  1002.     WinCheckMenuItem(hwndpopup,
  1003.              V_DETAIL,
  1004.              view & CV_DETAIL ? TRUE : FALSE);
  1005.  
  1006.     WinCheckMenuItem(hwndpopup,
  1007.              V_FULLICON,
  1008.              miniicon ? FALSE : TRUE);
  1009.  
  1010.     WinCheckMenuItem(hwndpopup,
  1011.              V_MINIICON,
  1012.              miniicon ? TRUE : FALSE);
  1013.  
  1014.     // get "miniicon" view in details mode; not automatic
  1015.     if ((view & CV_DETAIL) && (miniicon)) {
  1016.     cnrInfo.slBitmapOrIcon.cx = iconcx / 2;
  1017.     cnrInfo.slBitmapOrIcon.cy = iconcy / 2;
  1018.     }
  1019.     else {
  1020.     cnrInfo.slBitmapOrIcon.cx = iconcx;
  1021.     cnrInfo.slBitmapOrIcon.cy = iconcy;
  1022.     }
  1023.  
  1024.     // set view
  1025.     cnrInfo.flWindowAttr = view | miniicon | 
  1026.     CA_DETAILSVIEWTITLES; 
  1027.  
  1028.     // tell the container to change view
  1029.     WinSendMsg(hwndcnr,
  1030.            CM_SETCNRINFO,
  1031.            MPFROMP(&cnrInfo),
  1032.            MPFROMLONG(CMA_FLWINDOWATTR | CMA_SLBITMAPORICON));
  1033. }
  1034.  
  1035. // change a spell in all books
  1036. void change_all(spell *old_spell, spell *mod_spell) {
  1037.     bookwindow *ptr;
  1038.  
  1039.     for (ptr=first; ptr!=NULL; ptr=ptr->next) {
  1040.     ptr->change_spell(old_spell,mod_spell);
  1041.     }
  1042. }
  1043.  
  1044. // window procedure for book windows
  1045. MRESULT EXPENTRY book_window_func(HWND hwnd, ULONG msg, 
  1046.                   MPARAM param1, MPARAM param2) {
  1047.     short cx,cy;
  1048.     char *txt,buffer[256];
  1049.     bookwindow *mywin;
  1050.     bookwindow *nsw;
  1051.     ULONG ultemp;
  1052.     SWP winpos;
  1053.     POINTL ptl;
  1054.     HWND hwndmenu;
  1055.     static spellrecord *menurecord=NULL;
  1056.     spellwindow *child;
  1057.  
  1058.     switch (msg) {
  1059.  
  1060.     case WM_ERASEBACKGROUND:
  1061.     return (MRESULT)TRUE;
  1062.  
  1063.     case WM_CREATE:
  1064.     // save book handle in first window
  1065.     first->hwnd=hwnd;
  1066.  
  1067.     // save pointer to my class in window word
  1068.     WinSetWindowPtr(hwnd,
  1069.             0,
  1070.             first);
  1071.  
  1072.     // find out my size (client window)
  1073.     WinQueryWindowPos(hwnd,&winpos);
  1074.     cx=winpos.cx;
  1075.     cy=winpos.cy;
  1076.     
  1077.     // load in popup menu 
  1078.     first->hwndpopup=WinLoadMenu(hwnd,NULLHANDLE,BOOK_POPUP_MENU);
  1079.     first->hwndsppopup=WinLoadMenu(hwnd,NULLHANDLE,SPELL_POPUP_MENU);
  1080.  
  1081.     // create container filling whole window 
  1082.     first->hwndcnr=
  1083.         WinCreateWindow(
  1084.                 hwnd,
  1085.                 WC_CONTAINER,
  1086.                 0,
  1087.                 CCS_AUTOPOSITION |  // Auto position   
  1088.                 CCS_EXTENDSEL,      // Extended selection
  1089.                 (LONG)0,
  1090.                 (LONG)0,
  1091.                 (LONG)cx,
  1092.                 (LONG)cy,
  1093.                 hwnd,
  1094.                 HWND_TOP,
  1095.                 windows++,
  1096.                 NULL,
  1097.                 NULL);
  1098.  
  1099.     // load window attributes from INI or EA's.
  1100.     first->load_attr();
  1101.  
  1102.     // add fields for details view info
  1103.     first->insert_fields();
  1104.     first->show_fields();
  1105.  
  1106.     // and activate it 
  1107.     first->show();
  1108.     WinShowWindow(first->hwndcnr,TRUE);
  1109.  
  1110.     break;
  1111.  
  1112.     case WM_SIZE:
  1113.     mywin=(bookwindow *)WinQueryWindowPtr(hwnd,0);
  1114.  
  1115.     cx=SHORT1FROMMP(param2);
  1116.     cy=SHORT2FROMMP(param2);
  1117.     // tell the container to change its size 
  1118.     WinSetWindowPos(mywin->hwndcnr,0,0,0,cx,cy,SWP_SIZE);
  1119.  
  1120.     break;
  1121.  
  1122.     // is menu valid?
  1123.     case WM_INITMENU:
  1124.     mywin=(bookwindow *)WinQueryWindowPtr(hwnd,0);
  1125.     
  1126.     switch(SHORT1FROMMP(param1)) {
  1127.     case SPELL_SUBMENU:
  1128.         BOOL ok;
  1129.  
  1130.         if (mywin->readonly) ok=FALSE;
  1131.         else ok=TRUE;
  1132.  
  1133.         enable_menu_item(HWNDFROMMP(param2), ADDSPELL, ok);
  1134.         enable_menu_item(HWNDFROMMP(param2), DELSPELL, ok);
  1135.     }
  1136.     break;
  1137.  
  1138.     // ACK from object window... done with whatever it was doing
  1139.     case WM_USER_ACK:
  1140.     mywin=(bookwindow *)WinQueryWindowPtr(hwnd,0);
  1141.     mywin->enable();
  1142.     break;
  1143.  
  1144.     case WM_USER_CREATE_SUBSET:
  1145.     mywin=(bookwindow *)WinQueryWindowPtr(hwnd,0);
  1146.     mywin->disable();
  1147.     WinPostMsg(mywin->hwndobject,
  1148.            WM_USER_CREATE_SUBSET,
  1149.            param1,param2);
  1150.     break;
  1151.  
  1152.     case WM_USER_DETAILS_FIELDS:
  1153.     mywin=(bookwindow *)WinQueryWindowPtr(hwnd,0);
  1154.     mywin->details_fields = (ULONG)param1;
  1155.     mywin->show_fields();
  1156.     break;
  1157.  
  1158.     // mouse is moving, display clock if busy
  1159.     case WM_MOUSEMOVE:
  1160.     mywin=(bookwindow *)WinQueryWindowPtr(hwnd,0);
  1161.     ultemp = mywin->busy ? SPTR_WAIT : SPTR_ARROW;
  1162.     WinSetPointer(HWND_DESKTOP,
  1163.               WinQuerySysPointer(HWND_DESKTOP,ultemp,FALSE));
  1164.     return (MRESULT)TRUE;
  1165.     break;
  1166.  
  1167.     case WM_USER_SORT:
  1168.     mywin=(bookwindow *)WinQueryWindowPtr(hwnd,0);
  1169.     mywin->disable();
  1170.     WinPostMsg(mywin->hwndobject,
  1171.            WM_USER_SORT,
  1172.            param1,param2);
  1173.     break;
  1174.  
  1175. /*
  1176.     case HM_HELPSUBITEM_NOT_FOUND:
  1177.     sprintf(buffer,"Context: %d, topic: %d, subtopic: %d",
  1178.         (ULONG)param1,
  1179.         SHORT1FROMMP(param2),
  1180.         SHORT2FROMMP(param2));
  1181.     WinMessageBox(HWND_DESKTOP,
  1182.               HWND_DESKTOP,
  1183.               (PSZ)buffer,
  1184.               "Help Subtable Not Found",
  1185.               102,
  1186.               MB_OK);
  1187.     return (MRESULT)FALSE;
  1188.     break;
  1189.  
  1190.     case HM_ERROR:
  1191.     sprintf(buffer,"%d",(ULONG)param1);
  1192.     WinMessageBox(HWND_DESKTOP,
  1193.               HWND_DESKTOP,
  1194.               (PSZ)buffer,
  1195.               "Help Error",
  1196.               102,
  1197.               MB_OK);
  1198.     return (MRESULT)FALSE;
  1199.     break;
  1200. */
  1201.  
  1202.     // command from menu or dialog
  1203.     case WM_COMMAND:
  1204.     mywin=(bookwindow *)WinQueryWindowPtr(hwnd,0);
  1205.     
  1206.     switch(SHORT1FROMMP(param1)) {
  1207.     case ADDSPELL:
  1208.         mywin->add_new_spell();
  1209.         break;
  1210.  
  1211.     case DELSPELL:
  1212.         mywin->delete_selected_spells();
  1213.         break;
  1214.  
  1215.     case MENUSHOWSPELL:
  1216.         if (menurecord) {
  1217.         child = new spellwindow(menurecord->spl, mywin);
  1218.         menurecord = NULL;
  1219.         }
  1220.         break;
  1221.  
  1222.     case MENUDELSPELL:
  1223.         if (menurecord) {
  1224.         if (selected(menurecord)) mywin->delete_selected_spells();
  1225.         else {
  1226.             mywin->delete_spell(menurecord);
  1227.             mywin->refresh();
  1228.         }
  1229.         menurecord = NULL;
  1230.         }
  1231.         else
  1232.         mywin->delete_selected_spells();
  1233.         break;
  1234.  
  1235.     case MASTER:
  1236.         // make a new master list window
  1237.         new bookwindow(NULL,true);
  1238.         break;
  1239.  
  1240.     case SUBSET:
  1241.         WinLoadDlg(HWND_DESKTOP,
  1242.                hwnd,
  1243.                select_dlg_func,
  1244.                0L,
  1245.                SELECT_DLG,
  1246.                NULL);
  1247.         break;
  1248.  
  1249.     case SORTBOOK:
  1250.         WinLoadDlg(HWND_DESKTOP,
  1251.                hwnd,
  1252.                sort_dlg_func,
  1253.                0L,
  1254.                SORT_DLG,
  1255.                mywin);
  1256.         break;
  1257.  
  1258.     case RENAME:
  1259.         WinDlgBox(HWND_DESKTOP,
  1260.               hwnd,
  1261.               rename_dlg_func,
  1262.               0L,
  1263.               RENAME_DLG,
  1264.               NULL);
  1265.         break;
  1266.  
  1267.     case ABOUT:
  1268.         WinDlgBox(HWND_DESKTOP,
  1269.               hwnd,
  1270.               about_dlg_func,
  1271.               0L,
  1272.               ABOUT_DLG,
  1273.               NULL);
  1274.         break;
  1275.  
  1276.     case HELP_INDEX:
  1277.         WinSendMsg(hwndhelp,
  1278.                HM_HELP_INDEX,
  1279.                0,0);
  1280.         break;
  1281.  
  1282.     case HELP_GENERAL:
  1283.         WinSendMsg(hwndhelp,
  1284.                HM_GENERAL_HELP,
  1285.                0,0);
  1286.         break;
  1287.  
  1288.     case HELP_HELP:
  1289.         WinSendMsg(hwndhelp,
  1290.                HM_DISPLAY_HELP,
  1291.                0,0);
  1292.         break;
  1293.  
  1294.     case V_NAME:
  1295.         mywin->view = CV_NAME;
  1296.         mywin->show();
  1297.         break;
  1298.  
  1299.     case V_ICON:
  1300.         mywin->view = CV_ICON;
  1301.         mywin->show();
  1302.         break;
  1303.  
  1304.     case V_DETAIL:
  1305.         mywin->view = CV_DETAIL;
  1306.         mywin->show();
  1307.         break;
  1308.  
  1309.     case V_DETAILSFIELDS:
  1310.         WinDlgBox(HWND_DESKTOP,
  1311.               hwnd,
  1312.               fields_dlg_func,
  1313.               0L,
  1314.               FIELD_DLG,
  1315.               mywin);
  1316.         break;
  1317.  
  1318.     case V_TEXT:
  1319.         mywin->view = CV_TEXT;
  1320.         mywin->show();
  1321.         break;
  1322.  
  1323.     case V_MINIICON:
  1324.         mywin->miniicon = CV_MINI;
  1325.         mywin->show();
  1326.         break;
  1327.         
  1328.     case V_FULLICON:
  1329.         mywin->miniicon = 0;
  1330.         mywin->show();
  1331.         break;
  1332.         
  1333.     case NEWBOOK:
  1334.         new bookwindow;
  1335.         break;
  1336.  
  1337.     case SAVETITLES:
  1338.       mywin->save_book(true);
  1339.       break;
  1340.  
  1341.     case SAVEBOOK:
  1342.       mywin->save_book(false);
  1343.       break;
  1344.  
  1345.     case LOADBOOK:
  1346.       load_book();
  1347.       break;
  1348.  
  1349.     case CLOSEBOOK:
  1350.       WinSendMsg(mywin->hwnd,
  1351.              WM_CLOSE,
  1352.              0,
  1353.              0);
  1354.       break;
  1355.  
  1356.     case QUITPROGRAM:
  1357.       boolean allsaved=true;
  1358.       bookwindow *ptr;
  1359.       for (ptr=first; ptr!=NULL; ptr=ptr->next)
  1360.           if (ptr->saved==false) allsaved=false;
  1361.       
  1362.       if (!allsaved) {
  1363.           ULONG response = WinMessageBox(HWND_DESKTOP,
  1364.                          HWND_DESKTOP,
  1365.                          (PSZ)"End the program without saving all spellbooks?",
  1366.                          (PSZ)"Warning!",
  1367.                          102,
  1368.                          MB_YESNO|MB_ICONEXCLAMATION);
  1369.           if (response==MBID_NO) break;
  1370.       }
  1371.       WinPostMsg(mywin->hwnd,WM_QUIT,0,0);
  1372.       }
  1373.     break;
  1374.  
  1375.     // message from container 
  1376.     case WM_CONTROL:
  1377.     PCNRDRAGINFO pcdi;
  1378.     mywin=(bookwindow *)WinQueryWindowPtr(hwnd,0);
  1379.     
  1380.     switch (SHORT2FROMMP(param1)) {
  1381.     case CN_ENTER:
  1382.         show_spell(mywin, param2);
  1383.         return ((MRESULT)TRUE);
  1384.         break;
  1385.  
  1386.     case CN_INITDRAG:
  1387.         if (init_drag(mywin,(PCNRDRAGINIT)param2))
  1388.         return ((MRESULT)FALSE);
  1389.         else
  1390.         return ((MRESULT)TRUE);
  1391.         break;
  1392.         
  1393.     case CN_DRAGOVER:
  1394.         pcdi=(PCNRDRAGINFO)param2;
  1395.         return drag_over(mywin,pcdi->pDragInfo);
  1396.         break;
  1397.  
  1398.     case CN_DROP:
  1399.         pcdi=(PCNRDRAGINFO)param2;
  1400.         return drop_spell(mywin,pcdi);
  1401.         break;
  1402.  
  1403.     // show container popup menu
  1404.     case CN_CONTEXTMENU:
  1405.         if (param2) {
  1406.         hwndmenu = mywin->hwndsppopup;
  1407.         menurecord = (spellrecord *)param2;
  1408.         
  1409.         enable_menu_item(hwndmenu, 
  1410.                  MENUDELSPELL, 
  1411.                  (mywin->readonly) ? FALSE : TRUE);
  1412.         }
  1413.         else
  1414.         hwndmenu = mywin->hwndpopup;
  1415.  
  1416.         // get current postion to pop up the menu
  1417.         WinQueryMsgPos(hab, &ptl);
  1418.         
  1419.         WinPopupMenu(HWND_DESKTOP,hwnd,hwndmenu,
  1420.              ptl.x,
  1421.              ptl.y,
  1422.              NULL,
  1423.              PU_HCONSTRAIN | PU_VCONSTRAIN |
  1424.              PU_KEYBOARD | PU_MOUSEBUTTON1 |
  1425.              PU_MOUSEBUTTON2 |
  1426.              PU_MOUSEBUTTON3);
  1427.         return((MRESULT)0);
  1428.     break;
  1429.  
  1430.     }
  1431.     break;
  1432.  
  1433.     // user wants to close the window 
  1434.     case WM_CLOSE:
  1435.     mywin=(bookwindow *)WinQueryWindowPtr(hwnd,0);
  1436.     return savequit(mywin);
  1437.     break;
  1438.  
  1439.     // window destroyed
  1440.     case WM_DESTROY:
  1441.     mywin=(bookwindow *)WinQueryWindowPtr(hwnd,0);
  1442.     if ((mywin->master_list_win) && (!mywin->saved))
  1443.         mywin->sb->quicksave(quick_master_name);
  1444.     mywin->save_attr();
  1445.     break;
  1446.     }
  1447.     return WinDefWindowProc(hwnd, msg, param1, param2);
  1448. }
  1449.  
  1450.