oppopup.c

Go to the documentation of this file.
00001 
00002 /*  $Id: oppopup.c 1260 2006-04-13 06:13:10Z sethdill $    */
00003 
00004 /******************************************************************************
00005 
00006     UserLand Frontier(tm) -- High performance Web content management,
00007     object database, system-level and Internet scripting environment,
00008     including source code editing and debugging.
00009 
00010     Copyright (C) 1992-2004 UserLand Software, Inc.
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 
00026 ******************************************************************************/
00027 
00028 /*
00029 oppopup.c -- handle right-click popup menus in outlines.
00030 
00031 7.0b10 PBS
00032 */
00033 
00034 #include "frontier.h"
00035 #include "standard.h"
00036 
00037 #include "quickdraw.h"
00038 #include "op.h"
00039 #include "opdisplay.h"
00040 #include "opinternal.h"
00041 #include "opicons.h"
00042 #include "oplineheight.h"
00043 #include "frontierwindows.h"
00044 #include "popup.h"
00045 #include "lang.h"
00046 #include "menueditor.h"
00047 #include "meprograms.h"
00048 #include "tablestructure.h"
00049 #include "threads.h"
00050 #include "strings.h"
00051 #include "mouse.h"
00052 #include "dockmenu.h"
00053 #include "menu.h"
00054 #include "menuverbs.h"
00055 
00056 #define idgetmenuaddresscallback 39
00057 
00058 #define maxsubmenus 40
00059 
00060 static hdlmenurecord oppopupmenubar; /*current popup menu*/
00061 
00062 static boolean opbuildpopupmenu (hdlheadrecord hnode, hdlmenu hmenu);
00063 
00064 static boolean oppopupinsertmenuitem (hdlmenu hmenu, short itemnumber, hdlheadrecord hnode);
00065 
00066 static boolean oppopupruncallbackscript (tyvaluerecord *val);
00067 
00068 short currmenuid;
00069 
00070 #ifdef WIN95VERSION
00071 
00072     static unsigned long popupstartticks = 0; /*7.0b27 PBS: when menu was started. Used to make sure menu appeared minimum amount of ticks.*/
00073 
00074     static unsigned long popupticksminimum = 20; /*7.0b27 PBS*/
00075 
00076 #endif
00077 
00078 #if MACVERSION
00079 
00080     typedef struct typopupinfo {
00081 
00082         hdlmenu hmenu;
00083         
00084         short id;
00085             
00086         } typopupinfo, *ptrpopupinfo, **hdlpopupinfo;
00087 
00088     typedef struct typopupmenustack {
00089         
00090         typopupinfo popupmenus [maxsubmenus];
00091         
00092         short currstackitem;
00093         } typopupmenustack, *ptrpopupmenustack, **hdlpopupmenustack;
00094 
00095 
00096     typopupmenustack popupmenustack;
00097 
00098 #endif
00099 
00100 
00101 static void oppopupresetmenustack (void) {
00102     
00103     #if MACVERSION
00104 
00105         popupmenustack.currstackitem = -1;
00106         
00107         popupmenustack.popupmenus [0].hmenu = nil;
00108         
00109         popupmenustack.popupmenus [0].id = 0;
00110     
00111     #endif
00112     } /*oppopupresetmenustack*/
00113 
00114 
00115 static void oppopupdisposemenusinstack (void) {
00116     
00117     /*
00118     Dispose and delete all menus in popup menu stack.
00119     */
00120     
00121     #if MACVERSION
00122     
00123         short ix = popupmenustack.currstackitem;
00124         short i, id;
00125         hdlmenu hmenu;
00126         
00127         if (ix < 0)
00128             return;
00129         
00130         for (i = ix; i > -1; i--) {
00131             
00132             id = popupmenustack.popupmenus [i].id;
00133             
00134             if (id > -1)
00135             
00136                 DeleteMenu (id);
00137             
00138             hmenu = popupmenustack.popupmenus [i].hmenu;
00139             
00140             if (hmenu != nil)
00141             
00142                 disposemenu (hmenu);
00143             } /*for*/
00144             
00145     #endif
00146     } /*oppopupdisposemenusinstack*/
00147 
00148 
00149 static boolean oppopupaddtomenustack (hdlmenu hmenu, short idsubmenu) {
00150 
00151     #if MACVERSION
00152 
00153         short ix = popupmenustack.currstackitem + 1;
00154         
00155         if (ix > maxsubmenus)   
00156             return (false);
00157         
00158         popupmenustack.currstackitem = ix;
00159         
00160         popupmenustack.popupmenus [ix].hmenu = hmenu;
00161         
00162         popupmenustack.popupmenus [ix].id = idsubmenu;
00163     
00164     #endif
00165 
00166     return (true);  
00167     } /*oppopupaddtomenustack*/
00168 
00169 
00170 static void oppopupinsertsubmenu (hdlmenu hmenu, short itemnumber, hdlheadrecord hnode) {
00171 
00172     /*
00173     7.1b23 PBS: build a sub-menu and attach it.
00174     */
00175 
00176     hdlmenu hsubmenu;
00177     short idsubmenu = currmenuid;
00178 
00179     hsubmenu = Newmenu (idsubmenu, BIGSTRING (""));
00180     
00181 #if MACVERSION
00182     InsertMenu (hsubmenu, -1);
00183 #endif
00184     
00185     opbuildpopupmenu (hnode, hsubmenu);
00186     
00187     oppopupaddtomenustack (hsubmenu, idsubmenu);
00188     
00189     sethierarchicalmenuitem (hmenu, itemnumber, hsubmenu, idsubmenu);
00190     } /*oppopupinsertsubmenu*/
00191 
00192 
00193 static boolean oppopupinsertmenuitem (hdlmenu hmenu, short itemnumber, hdlheadrecord hnode) {
00194     
00195     /*
00196     7.0b23 PBS: allow right-click menu items to be disabled.
00197     */
00198 
00199     bigstring bsheadstring;
00200     boolean flenabled = true;
00201     boolean flchecked = false; /*it's ignored anyway*/
00202 
00203     getheadstring (hnode, bsheadstring);
00204 
00205     mereduceformula (bsheadstring);
00206     
00207     mereducemenucodes (bsheadstring, &flenabled, &flchecked); /*7.0b23 PBS: items can be disabled.*/
00208 
00209     pushpopupitem (hmenu, bsheadstring, flenabled, currmenuid);
00210 
00211     if (ophassubheads (hnode))
00212         oppopupinsertsubmenu (hmenu, itemnumber, hnode);
00213 
00214     return (true);
00215     } /*oppopupinsertmenuitem*/
00216 
00217 
00218 static boolean opbuildpopupmenu (hdlheadrecord hnode, hdlmenu hmenu) {
00219     
00220     /*
00221     7.0b10 PBS: Build a popup menu from the outline pointed to by hnode.
00222     Recurse to handle a menu that has a submenu.
00223 
00224     Based on mebuildmenu, but different enough to need its own routine. 
00225     */
00226     
00227     short itemnumber;
00228     bigstring bs;
00229     
00230     getheadstring (hnode, bs); /*get the menu title*/
00231     
00232     if (opnosubheads (hnode))
00233         return (true);
00234     
00235     hnode = (**hnode).headlinkright; /*move to first subhead*/
00236     
00237     for (itemnumber = 1; ; itemnumber++) {
00238 
00239         currmenuid++;
00240 
00241         if (!oppopupinsertmenuitem (hmenu, itemnumber, hnode))
00242             return (false);
00243 
00244         if (opislastsubhead (hnode)) /*done with this menu*/
00245             return (true);
00246         
00247         hnode = (**hnode).headlinkdown; /*advance to next item*/
00248         } /*while*/
00249     } /*opbuildpopupmenu*/
00250 
00251 
00252 static boolean oppopupruncallbackscript (tyvaluerecord *val) {
00253 
00254     /*
00255     7.0b11 PBS: run the callback script that returns the address
00256     of a menubar object to use.
00257     */
00258 
00259     Handle htext;
00260     boolean fl = false; /*assume it didn't work*/
00261     bigstring bsscript;
00262     short idscript = idgetmenuaddresscallback;
00263 
00264     if (getsystemtablescript (idscript, bsscript)) {
00265     
00266         if (!newtexthandle (bsscript, &htext))
00267         
00268                 return (false);
00269 
00270         grabthreadglobals ();
00271 
00272         oppushoutline (outlinedata); /*7.0b10 PBS: make sure the current outline gets saved.*/
00273         
00274         fl = langrun (htext, val);
00275 
00276         oppopoutline (); /*7.0b10 PBS: restore the current outline*/
00277 
00278         releasethreadglobals ();
00279         }
00280 
00281     return (fl);
00282     } /*oppopupruncallbackscript*/
00283 
00284 
00285 static boolean oppopupgetaddresscallback (tyvaluerecord *val) {
00286 
00287     /*
00288     7.0b11 PBS: get the address of a menubar object to use
00289     in creating the popup menu. Call a callback script.
00290     */
00291 
00292     if (!oppopupruncallbackscript (val))
00293         return (false);
00294 
00295     return (true);
00296     } /*oppopupgetaddresscallback*/
00297 
00298 
00299 static boolean opfillpopup (hdlmenu hmenu, short *checkeditem) {
00300 
00301     /*
00302     7.1b43 PBS: make sure the menu object is in memory, so the
00303     app doesn't crash.
00304     */
00305 
00306     hdlhashtable htable;
00307     hdlhashnode hnode;
00308     tyvaluerecord valaddress;
00309     tyvaluerecord val;
00310     hdlmenurecord hm;
00311     hdlexternalhandle h;
00312     hdlheadrecord hsummit;
00313     bigstring bsaddress;
00314     boolean fl = false;
00315     long menusize = 0;
00316 
00317     if (!oppopupgetaddresscallback (&valaddress))
00318         return (false);
00319 
00320     if (valaddress.valuetype != addressvaluetype)
00321         goto exit;
00322 
00323     if (!getaddressvalue (valaddress, &htable, bsaddress))
00324         goto exit;
00325 
00326     if (!langsymbolreference (htable, bsaddress, &val, &hnode))
00327         goto exit;
00328 
00329     if ((val.valuetype) != externalvaluetype)
00330         goto exit;
00331 
00332     h = (hdlexternalhandle) val.data.externalvalue;
00333 
00334     if (!menuverbgetsize (h, &menusize)) /*7.1b43 PBS: We don't care about the size. We just want to read it into memory.*/
00335         goto exit;
00336 
00337     if ((**h).id != idmenuprocessor) /*it must be a menu*/
00338         goto exit;
00339 
00340     hm = (hdlmenurecord) (**h).variabledata;
00341 
00342     oppopupmenubar = hm;
00343 
00344     hsummit = (**(**hm).menuoutline).hsummit;
00345 
00346     opbuildpopupmenu (hsummit, hmenu);
00347 
00348     fl = true;
00349     
00350     exit:
00351 
00352     disposevaluerecord (valaddress, false);
00353 
00354     *checkeditem = -1; /*Get rid of random checked item bug*/
00355 
00356     return (fl);
00357     } /*opfillpopup*/
00358 
00359 
00360 static boolean oppopupselect (hdlmenu hmenu, short itemselected) {
00361     
00362     /*
00363     Run a popup menu command.
00364 
00365     7.0b26 PBS: on Windows, don't run the menu item in a new thread. When two right-click
00366     menu items run at the same time as the result of rapid right-clicking, something gets
00367     stepped on and the app crashes. So, instead, allow only one command to run at a time.
00368 
00369     7.0b27 PBS: make sure menu appears for a minimum amount of ticks on Windows, so you
00370     don't get the case where you choose a menu item without even seeing the menu.
00371     */
00372     
00373     #pragma unused(hmenu)
00374     
00375     hdlmenurecord hm = oppopupmenubar;
00376     hdlheadrecord hsummit;
00377     hdlheadrecord hmenuitem;
00378 
00379     if (oppopupmenubar == nil)
00380         return (false);
00381 
00382     #ifdef WIN95VERSION /*7.0b27 PBS: enforce minimum menu display time.*/
00383 
00384         if ((gettickcount () - popupticksminimum) < popupstartticks)
00385             return (false);
00386 
00387     #endif
00388 
00389     oppopupmenubar = nil;
00390 
00391     hsummit = (**(**hm).menuoutline).hsummit; /*Top level of the menu*/
00392     
00393     //hmenuitem = opnthsubhead (hsummit, itemselected);
00394 
00395     hmenuitem = oprepeatedbump (flatdown, itemselected, hsummit, false);
00396 
00397     oppushoutline ((**hm).menuoutline);
00398 
00399     meuserselected (hmenuitem);
00400 
00401     oppopoutline ();
00402 
00403     return (true);
00404     } /*oppopupselect*/
00405 
00406 
00407 boolean oprmousedown (Point pt, tyclickflags flags) {
00408     
00409     /*
00410     7.0b10 PBS: handle right-clicks in an outline.
00411     Possibly display and track a menu.
00412     */
00413     
00414     #pragma unused(flags)
00415     
00416     register hdloutlinerecord ho = outlinedata;
00417     Rect linerect;
00418     hdlheadrecord hcursor;
00419     long i;
00420     
00421     if (!pointinrect (pt, (**ho).outlinerect))
00422         return (false);
00423     
00424     currmenuid = 0;
00425     
00426     oppopupresetmenustack (); /*7.1b23 PBS: maintain a stack of submenus*/
00427 
00428     /*determine the line number and rectangle for the mouse click*/ {
00429     
00430     long screenlines = opgetcurrentscreenlines (false) + 1;
00431         
00432     for (i = 0; i < screenlines; i++) {
00433             
00434         opgetlinerect (i, &linerect);
00435             
00436         if (pt.v <= linerect.bottom) /*we've reached the right line*/
00437             goto L2;
00438         } /*for*/
00439                     
00440     return (true);;
00441     }
00442     
00443     L2:
00444     
00445     hcursor = oprepeatedbump (flatdown, i, (**ho).hline1, true);
00446 
00447     opmoveto (hcursor); /*potentially re-position the bar cursor*/ 
00448         
00449     opupdatenow (); /*be sure any changes are visible now*/
00450 
00451     if (!pointinrect (pt, linerect)) /*Must be right-click on a line*/
00452         return (false);
00453 
00454     linerect.left = pt.h - 5; /*relative to cursor*/
00455 
00456     #ifdef WIN95VERSION /*7.0b26 PBS: wait for the mouse to come back up -- Windows UI standard*/
00457 
00458         while (rightmousestilldown ()) {
00459 
00460             true;
00461             } /*while*/
00462 
00463         popupstartticks = gettickcount ();
00464     #endif
00465     
00466     popupmenuhit (linerect, false, &opfillpopup, &oppopupselect);
00467     
00468     oppopupdisposemenusinstack (); /*7.1b23 PBS: delete and dispose submenus*/
00469     
00470     return (true);
00471     } /*oprmousedown*/

Generated on Wed May 31 18:19:57 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6