opdraggingmove.c

Go to the documentation of this file.
00001 
00002 /*  $Id: opdraggingmove.c 1204 2006-04-05 23:07:18Z karstenw $    */
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 #include "frontier.h"
00029 #include "standard.h"
00030 
00031 #include "memory.h"
00032 #include "kb.h"
00033 #include "mouse.h"
00034 #include "quickdraw.h"
00035 #include "ops.h"
00036 #include "smallicon.h"
00037 #include "strings.h"
00038 #include "shell.rsrc.h"
00039 #include "opdraggingmove.h"
00040 #include "opdisplay.h"
00041 #include "oplineheight.h"
00042 #include "opicons.h"
00043 #include "shellundo.h"
00044 
00045 
00046 
00047 
00048 #define draggingpix 3 /*distance to initiate drag*/
00049 
00050 #define draggingticks 30 /*time before auto-drag initiation*/
00051 
00052 #define draggingsloppix 10 /*any further outsize displayrect cancels drag*/
00053 
00054 #define dragginghotspot (iconstart + 5)
00055 
00056 #define hotspotturnedon true /*set to true and hotspot is displayed while dragging*/
00057 
00058 static hdlheadrecord hfirstmoved;
00059 
00060 static boolean opredocopy (hdlheadrecord hnode, boolean flundo); /*forward*/
00061 
00062 
00063 typedef struct tydraginfo {
00064     
00065     hdlheadrecord hnode;
00066     
00067     tydirection dir;
00068     } tydraginfo, *ptrdraginfo;
00069 
00070 
00071 #if false
00072 
00073 void opgetwindowhandle (Point pt, Handle *windowhandle) {
00074     
00075     opgetwindowhandlecallback cb = (**outlinedata).getwindowhandlecallback;
00076     
00077     if (cb == nil) {
00078         
00079         localtoglobalpoint (nil, &pt);
00080         
00081         findappwindow (pt, (hdlappwindow *) windowhandle);
00082         }
00083     else
00084         (*cb) (pt, windowhandle);
00085     } /*opgetwindowhandle*/
00086 
00087 
00088 void opsetwindowhandlecontext (Handle windowhandle) {
00089     
00090     opsetwindowhandlecontextcallback cb = (**outlinedata).setwindowhandlecontextcallback;
00091     
00092     if (cb == nil)
00093         setappwindow ((hdlappwindow) windowhandle);
00094     else
00095         (*cb) (windowhandle);
00096     } /*opsetwindowhandlecontext*/
00097 
00098 #endif
00099 
00100 static short oppointlevel (Point pt) {
00101     
00102     /*
00103     give me a point in the display rectangle, and I'll tell you what 
00104     level it refers to.
00105     
00106     to visualize the process, draw vertical lines on the screen at 
00107     (**outlinedata).lineindent increments.  each line corresponds to a
00108     level in the outline.  we match the pt up with the levels.
00109     */
00110     
00111     register hdloutlinerecord ho = outlinedata;
00112     hdlheadrecord hsummit = (**ho).hsummit;
00113     Rect r = (**ho).outlinerect;
00114     short indent;
00115     
00116     insetrect (&r, -draggingsloppix, -draggingsloppix);
00117     
00118     if (!pointinrect (pt, r)) /*too sloppy -- no move*/
00119         return (-1);
00120     
00121     indent = (pt.h - (**ho).outlinerect.left) - (opnodeindent (hsummit) + dragginghotspot);
00122     
00123     return ((**hsummit).headlevel + divround (indent, (**ho).lineindent));
00124     } /*oppointlevel*/
00125 
00126 
00127 static boolean oppointaboveline1 (Point pt) {
00128     
00129     Rect r = (**outlinedata).outlinerect;
00130     
00131     r.top += 3; /*the top 3 pixels of the outline display cause scrolling*/
00132     
00133     return (pt.v <= r.top);
00134     } /*oppointaboveline1*/
00135     
00136 
00137 void operasehotspot (tyhotspot *hotspot) {
00138     
00139     register tyhotspot *hs = hotspot;
00140     
00141     if ((*hs).fldisplayed) {
00142         
00143         opdrawarrowicon ((*hs).htarget, (*hs).lnum, nodirection);
00144         
00145         (*hotspot).fldisplayed = false;
00146         }
00147     } /*operasehotspot*/
00148     
00149 
00150 static void opdrawhotspot (tyhotspot *hotspot) {
00151     
00152     register tyhotspot *hs = hotspot;
00153     
00154     opdrawarrowicon ((*hs).htarget, (*hs).lnum, (*hs).dir);
00155     
00156     (*hs).fldisplayed = true;
00157     } /*opdrawhotspot*/
00158     
00159 
00160 static boolean isundermark (hdlheadrecord htarget, tydirection dir) {
00161 #pragma unused (dir)
00162 
00163     while (true) {
00164         
00165         if (opgetmark (htarget))
00166             return (true);
00167         
00168         if (!opnavigate (left, &htarget))
00169             return (false);
00170         } /*while*/
00171     } /*isundermark*/
00172 
00173 
00174 static void opupdatehotspot (Point ptstart, Point pt, tyhotspot *hotspot) {
00175     
00176     /*
00177     the hot spot is displayed as the user scrolls around during the first
00178     half of the dragging move operation.  it gives him a pretty good idea
00179     of where the moving headline is likely to land.
00180     
00181     we maintain a record that fully describes the hotspot, a pointer to
00182     it is passed to us.
00183     
00184     8/27/92 dmb: added multiple selection support, and fixed dragging above line1
00185     
00186     5.0.2b14 dmb: added ptstart, so we can avoid unintentional drags
00187     */
00188     
00189     register tyhotspot *hs = hotspot;
00190     register hdloutlinerecord ho = outlinedata;
00191     register hdlheadrecord htarget;
00192     register hdlheadrecord hline1 = (**ho).hline1;
00193     register hdlheadrecord hsummit = (**ho).hsummit;
00194     register hdlheadrecord hsource = (*hs).hsource;
00195     register tydirection dir;
00196     register short mouselevel;
00197     long lnum;
00198     boolean fldraw;
00199     
00200     if ((equalpoints (pt, (*hs).pt)) && (*hs).fldisplayed) /*no change*/
00201         return;
00202     
00203     mouselevel = oppointlevel (pt);
00204     
00205     if (mouselevel < 0) /*pointing outside the content region of window*/
00206         goto noway;
00207     
00208     if (pointdist (ptstart, pt) < draggingpix)
00209         goto noway;
00210     
00211     if (oppointaboveline1 (pt)) { /*try to move up from the summit*/
00212         
00213         if (hline1 == hsource) /*can't move summit up from itself*/
00214             goto noway;
00215         
00216         htarget = (**ho).hline1;
00217         
00218         if (htarget == hsummit) {
00219             
00220             dir = up;
00221             
00222             goto gottarget;
00223             }
00224         
00225         htarget = opbumpflatup (htarget, true);
00226         }
00227     else
00228         htarget = oppointnode (pt); /*find out which node he's pointing to*/
00229     
00230     if (htarget == nil) /*he's not pointing at a real line*/
00231         goto noway;
00232     
00233     if (opsubordinateto (htarget, hsource)) /*can't move under self*/
00234         goto noway;
00235         
00236     if (htarget == hsource) { /*pointing at the same guy we're moving*/
00237         
00238         register short level = (**htarget).headlevel;
00239         
00240         if (mouselevel == level) /*no move required*/
00241             goto noway;
00242             
00243         if (mouselevel > level) { /*trying to move to the right of node up from here*/
00244             
00245             while (true) { /*seek upwards*/
00246                 
00247                 if (opfirstinlist (htarget)) /*no move possible*/
00248                     goto noway;
00249                 
00250                 htarget = (**htarget).headlinkup;
00251                 
00252                 if (!(**htarget).flmarked) /*not among group being dragged*/
00253                     break;
00254                 }
00255             
00256             if (opnosubheads (htarget)) { /*becomes only subhead of up sibling*/
00257                 
00258                 dir = right;
00259                 
00260                 goto gottarget;
00261                 }
00262             
00263             htarget = oplastexpandedatlevel (htarget, mouselevel);  
00264             
00265             if ((**htarget).headlevel < mouselevel)
00266                 dir = right;
00267             else
00268                 dir = down;
00269             
00270             goto gottarget;
00271             }
00272             
00273         /*mouselevel < level*/
00274         
00275         htarget = opgetancestor (htarget, mouselevel);
00276         
00277         dir = down; 
00278         
00279         goto gottarget; 
00280         } /*htarget == hsource*/
00281     
00282     if (mouselevel > (**htarget).headlevel) {
00283         
00284         if (hsource == (**htarget).headlinkright) /*already there*/
00285             goto noway;
00286         
00287         dir = right; 
00288         
00289         goto gottarget;
00290         }
00291     
00292     dir = down; /*not pointing at moving node, not moving to right of something*/
00293     
00294     while (mouselevel < (**htarget).headlevel)
00295         htarget = (**htarget).headlinkleft;
00296     
00297     if (hsource == (**htarget).headlinkdown) /*already there*/
00298         goto noway;
00299     
00300     gottarget: /*display the hotspot, save values in the structure and return*/
00301     
00302     if (isundermark (htarget, dir))
00303         goto noway;
00304     
00305     if (!(*(**ho).validatedragcallback) (hsource, htarget, dir))
00306         goto noway;
00307     
00308     opgetscreenline (htarget, &lnum);
00309     
00310     if ((lnum < 0) && (dir == down)) {
00311         
00312         hdlheadrecord hdown = (**htarget).headlinkdown;
00313         
00314         if ((hdown != htarget) && opnodevisible (hdown)) {
00315             
00316             htarget = hdown;
00317             
00318             dir = up;
00319             
00320             opgetscreenline (hdown, &lnum);
00321             }
00322         }
00323     
00324     fldraw = true;
00325     
00326     if ((*hs).fldisplayed) {
00327         
00328         if (((*hs).htarget == htarget) && ((*hs).lnum == lnum) && ((*hs).dir == dir))
00329             fldraw = false;
00330         }
00331     
00332     if (fldraw)
00333         operasehotspot (hs);
00334     
00335     (*hs).fldisplayed = true;
00336     
00337     (*hs).lnum = lnum;
00338     
00339     (*hs).pt = pt;
00340     
00341     (*hs).dir = dir;
00342     
00343     (*hs).htarget = htarget;
00344     
00345     if (fldraw)
00346         opdrawhotspot (hs);
00347     
00348     return;
00349     
00350     noway: /*goto here if the mouse points to a place we can't move to*/
00351     
00352     operasehotspot (hs);
00353     
00354     (*hs).htarget = nil; 
00355     } /*opupdatehotspot*/
00356 
00357 
00358 static boolean opundocopy (hdlheadrecord hnode, boolean flundo) {
00359     
00360     if (flundo)
00361         oppushundo (&opredocopy, hnode);
00362     
00363     return (true);
00364     } /*opundocopy*/
00365 
00366 
00367 static boolean opredocopy (hdlheadrecord hnode, boolean flundo) {
00368     
00369     if (flundo)
00370         oppushundo (&opundocopy, hnode);
00371     else
00372         opdisposestructure (hnode, true);
00373     
00374     return (true);
00375     } /*opredocopy*/
00376 
00377 
00378 static boolean movetohotspotvisit (hdlheadrecord hnode, ptrvoid refcon) {
00379     
00380     register hdlheadrecord h = hnode;
00381     ptrdraginfo draginfo = (ptrdraginfo) refcon;
00382     register hdlheadrecord hpre = (*draginfo).hnode;
00383     tydirection dir = (*draginfo).dir;
00384     
00385     if (!(**h).tmpbit) {
00386         
00387         oppushunmarkundo (hnode);
00388         
00389         if ((*(**outlinedata).dragcopycallback) (h, hpre)) {
00390             
00391             h = opcopyoutline (h); /*caution: wipes out recursion globals*/
00392             
00393             if (h == nil)
00394                 return (false);
00395             
00396             oppushundo (&opundocopy, h);
00397             }
00398         else
00399             opunlink (h); 
00400         
00401         opdeposit (hpre, dir, h);
00402         
00403         opresetlevels (h);
00404         
00405         (*draginfo).hnode = h;
00406         
00407         (*draginfo).dir = down;
00408         
00409         (**h).tmpbit = true; /*don't visit again*/
00410         
00411         if (hfirstmoved == nil)
00412             hfirstmoved = h;
00413         }
00414     
00415     return (true);
00416     } /*movetohotspotvisit*/
00417 
00418 
00419 boolean opmovetohotspot (tyhotspot *hotspot) {
00420     
00421     /*
00422     9/3/93 DW: allow predragcallback to alert us that he's deleted the target
00423     node. we can safely redefine the move operation, and we do.
00424     
00425     9/22/93 dmb: allow postpastecallback to post-process the drag -- perhaps 
00426     to resort the level. also, turned off dropboxdrag, which conflicts with 
00427     some applets' use of the option key (Clay Basket, for one). We could 
00428     add an op preference or flag for this, but it's an obscure feature and 
00429     I don't think it's worth the mess.
00430     
00431     DW 4/10/95: I don't see what the conflict is! I'm re-enabling it, it was
00432     requested by a tester.
00433 
00434     5.0b9 dmb: improved the predrag callback so it can modify the target to be
00435     safe instead of returning -1 to say it's bad
00436     */
00437     
00438     register tyhotspot *hs = hotspot;
00439     //hdlheadrecord hsource = (*hs).hsource;
00440     hdlheadrecord htarget = (*hs).htarget;
00441     tydirection dir = (*hs).dir;
00442     hdlheadrecord horigcursor = (**outlinedata).hbarcursor;
00443     hdlscreenmap hmap;
00444     tydraginfo draginfo;
00445     
00446     boolean fldropboxdrag = false;
00447     
00448     if (htarget == nil) /*wasn't pointing at anything we could interpret*/
00449         return (false);
00450     
00451     if ((dir == right) && !opsubheadsexpanded (htarget)) {
00452         
00453         fldropboxdrag = optionkeydown (); /*deposit nodes below target w/out expanding*/
00454         
00455         if (ophassubheads (htarget)) {
00456             
00457             hdlheadrecord hlastsub;
00458             
00459             if (!fldropboxdrag) 
00460                 opexpand (htarget, 1, false);
00461             
00462             hlastsub = opgetlastsubhead (htarget);
00463             
00464             if (hlastsub != htarget) { /*DW 9/1/93: allow for clay basket*/
00465                 
00466                 htarget = hlastsub;
00467             
00468                 dir = down;
00469                 }
00470             }
00471         }
00472     
00473     #if false /*DW 4/10/95 disabled*/
00474     
00475         if (fldropboxdrag) { /*flash the icon for feedback*/
00476             
00477             register short ctflashes = 2;
00478             
00479             while (--ctflashes >= 0) {
00480                 
00481                 opdrawhotspot (hs);
00482                 
00483                 delayticks (8);
00484                 
00485                 operasehotspot (hs);
00486                 
00487                 delayticks (4);
00488                 }
00489             }
00490     #endif
00491     
00492     pushundoaction (undomovestring);
00493     
00494     opbeforestrucchange (&hmap, false);
00495     
00496     /*DW 9/3/93 -- defend against the target getting deleted in predragcallback*/ {
00497     
00498         //hdlheadrecord htargetparent = (**htarget).headlinkleft;
00499         
00500         switch ((*(**outlinedata).predragcallback) (&htarget, &dir)) {
00501             
00502             case false: /*user declined to do the move after hearing the consequences*/
00503                 goto exit;
00504             
00505         //  case (boolean) -1: /*special signal that the target has been deleted*/
00506         //      htarget = htargetparent;
00507         //      
00508         //      dir = right;
00509         //      
00510         //      break;
00511             } /*switch*/
00512         }
00513     
00514     draginfo.hnode = htarget;
00515     
00516     draginfo.dir = dir;
00517     
00518     hfirstmoved = nil;
00519     
00520     opvisitmarked (nodirection, &movetohotspotvisit, &draginfo);
00521     
00522     opcleartmpbits (); /*set by movetohotspotvisit*/
00523     
00524     (*(**outlinedata).postpastecallback) (hfirstmoved);
00525     
00526     if (fldropboxdrag) {
00527         
00528         htarget = (*hs).htarget; /*back to parent, in case it already had kids*/
00529         
00530         opfastcollapse (htarget);
00531         
00532         opclearmarks (htarget);
00533         
00534         opmoveto (htarget); /*move to "drop box" headline*/
00535         
00536         opresetscrollbars ();
00537         }
00538     else {
00539         
00540         opvisinode (draginfo.hnode, false); /*visi the last node deposited*/
00541         
00542         (**outlinedata).hbarcursor = horigcursor;
00543         
00544         opmoveto (hfirstmoved); /*move to first node deposited*/
00545         }
00546     
00547     exit:
00548     
00549     opafterstrucchange (hmap, false);
00550     
00551     opsetctexpanded (outlinedata); /*DW 4/10/95*/
00552     
00553     return (true);
00554     } /*opmovetohotspot*/
00555 
00556 
00557 void opscrollfordrag (tyhotspot *hotspot, tydirection scrolldir) {
00558     
00559     register hdloutlinerecord ho = outlinedata;
00560     register long vertcurrent = (**ho).vertscrollinfo.cur;
00561     register tydirection dir = scrolldir;
00562     
00563     if ((vertcurrent <= (**ho).vertscrollinfo.min) && (dir == down)) /*no scrolling possible*/
00564         return;
00565         
00566     if ((vertcurrent >= (**ho).vertscrollinfo.max) && (dir == up))
00567         return;
00568     
00569     operasehotspot (hotspot);
00570     
00571     opscroll (dir, false, 1);   
00572     } /*opscrollfordrag*/
00573     
00574     
00575 boolean opisdraggingmove (Point ptorig, unsigned long origticks) {
00576 
00577     Point ptnew;
00578     
00579     getmousepoint (&ptnew);
00580         
00581     return ((pointdist (ptorig, ptnew) > draggingpix) || ((gettickcount () - origticks) > draggingticks));
00582     } /*opisdraggingmove*/
00583     
00584     
00585 void opdraggingmove (Point ptstart, hdlheadrecord hsource) {
00586     
00587     /*
00588     9/22/93 dmb: need to validate a drag just like a copy. also need to 
00589     provide for client sorting, like a paste
00590     */
00591     
00592     long tc = 0;
00593     tyhotspot hotspot;
00594     Point pt;
00595     tydirection dir;
00596     
00597     if (!((**outlinedata).validatecopycallback) (STR_move))
00598         return;
00599     
00600     clearbytes ((ptrchar) &hotspot, longsizeof (hotspot));
00601     
00602     hotspot.pt = ptstart;
00603     
00604     hotspot.hsource = hsource;
00605     
00606     /*
00607     opgetwindowhandle (pt, &hotspot.sourcewindowhandle);
00608     
00609     hotspot.destwindowhandle = hotspot.sourcewindowhandle;
00610     */
00611     
00612     if (true /*claystartdrag(ptstart, hsource) != noErr*/) {
00613         
00614         while (mousestilldown ()) {
00615             
00616             getmousepoint (&pt);
00617             
00618             #if false
00619             
00620                 Handle currentwindow;
00621             
00622                 if (!pointinrect (pt, (*FrontWindow ()).portRect))
00623                     Debugger ();
00624             
00625                 opgetwindowhandle (pt, &currentwindow);
00626                 
00627                 if (currentwindow != hotspot.destwindowhandle) { /*pointing into another window*/
00628                     
00629                     opsetwindowhandlecontext (hotspot.destwindowhandle);
00630             
00631                     operasehotspot (&hotspot);
00632                     
00633                     hotspot.destwindowhandle = currentwindow;
00634                     
00635                     opsetwindowhandlecontext (hotspot.destwindowhandle);
00636             
00637                     opupdatehotspot (ptstart, pt, &hotspot);
00638                     }
00639             #endif
00640             
00641             if ((gettickcount () - tc) > draggingscrollrate) {
00642                 
00643                 if (mousecheckautoscroll (pt, (**outlinedata).outlinerect, false, &dir)) {
00644                 
00645                     opscrollfordrag (&hotspot, dir);
00646                     
00647                     tc = gettickcount ();
00648                     }
00649                 }
00650             
00651             opupdatehotspot (ptstart, pt, &hotspot);
00652             } /*while*/
00653         
00654         operasehotspot (&hotspot); /*user let up on the button*/
00655     
00656         opmovetohotspot (&hotspot);
00657         }  // if noErr
00658     } /*opdraggingmove*/
00659 
00660 
00661 
00662 

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