/* * wWinEvent.c * * Handling events for template windows * * © 1994-1998 Straylight */ /*----- Licensing note ----------------------------------------------------* * * This file is part of Straylight's Glass. * * Glass is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * Glass is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Glass. If not, write to the Free Software Foundation, * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*----- Header files ------------------------------------------------------*/ /* * ANSI standard headers */ #include #include #include /* * Steel headers */ #define _STDAPP #define _LOWLVL #include "steel/Steel.h" #include "steel/interface.h" #include "steel/sculptrix.h" #include "steel/caretPtr.h" #include "steel/akbd.h" #include "steel/bbc.h" /* * Glass headers */ #include "gStruct.h" #include "gMenus.h" #include "gIcons.h" #include "glass.h" #include "gPrefs.h" #include "tfile.h" #include "window.h" #include "_window.h" #include "intMsgs.h" #include "toolbox.h" #include "editIcon.h" #include "editWin.h" #include "tearEdit.h" /*----- Main code ---------------------------------------------------------*/ /* * void window__winIdles(void *handle) * * Use * Changes the pointer shape to something appropriate for what its over. * * Parameters * void *handle == pointer to window containing pointer */ void window__winIdles(void *handle) { glass_windPointer *w=handle; int i=window__pointerInfo(w,-1,TRUE); #ifndef glass_DEMO if (w->testMode) i=window__SELECT; #endif window__setPtrShape(i); window__updateInfoBar(FALSE); } /* * int window__keyAhead(int k,int *nk) * * Use * Counts how many times the given key k is pressed, and returns the next * key in *nk (or -1 if no next key). * * Parameters * int k == the key to check for * int *nk == where to store next key value * * Returns * Number of times key was buffered. */ static int window__keyAhead(int k,int *nk) { int count=0; *nk=k; while (*nk==k) { count++; if (!akbd_pollkey(nk)) *nk=-1; else *nk=akbd_translate(*nk); } return (count); } /* * void window__testEvents(wimp_eventstr *e,void *handle) * * Use * Handles all events for windows running in Test mode. Events handled * are: * * Redraw Redraws the window using Interface/hatch pattern as requested. * Open Moves the window around. * Close Closes the window(!) * Leave Ignored * Enter Turn off STEEL pointer changing * Click Handled by WIMP or Interface, except for menu, which opens * the menu(!) * Key Handled by WIMP, WimpExtension, or ignored * * Parameters * wimp_eventstr *e == the event * void *handle == pointer to window info */ #ifndef glass_DEMO void window__testEvents(wimp_eventstr *e,void *handle) { glass_windPointer *w=handle; /* Extract my data from the handle */ wimp_wstate s; int ox,oy; wimp_redrawstr r; /* For the redraw event */ BOOL more; /* To tell me when I've finished */ wimp_w wnd; os_regset reg; wimp_icon icon; sculptrix_slabDescriptor d; switch (e->e) { case wimp_EREDRAW: r.w=w->h; wimpt_noerr(wimp_redraw_wind(&r,&more)); /* Start the redraw */ window__redraw(w,&r,&more); break; case wimp_EOPEN: if (e->data.o.x<=w->def->desc.w.scx && e->data.o.y>=w->def->desc.w.scy) { r.w=e->data.o.w; r.box=w->tex; if (tst(w->def->desc.w.flags,14)) { r.box.x0=w->def->desc.w.ex.x0; r.box.x1=max2(w->def->desc.w.ex.x1,e->data.o.x+e->data.o.box.x1- e->data.o.box.x0); } if (tst(w->def->desc.w.flags,15)) { r.box.y1=w->def->desc.w.ex.y1; r.box.y0=min2(w->def->desc.w.ex.y0,e->data.o.y-e->data.o.box.y1+ e->data.o.box.y0); } if (memcmp(&r.box,&w->tex,sizeof(wimp_box))) { wimpt_noerr(wimp_set_extent(&r)); w->tex=r.box; } } if (window_selectionOwner()==w) window__setToolBarPositions(&e->data.o); else wimpt_noerr(wimp_open_wind(&e->data.o)); w->def->desc.w.box=e->data.o.box; /* Copy the information down */ w->def->desc.w.scx=e->data.o.x; w->def->desc.w.scy=e->data.o.y; w->def->desc.w.behind=e->data.o.behind; if (!w->t->alts) /* Moving the window alters the template */ tfile_markAsAltered(w->t); /* But only if not already altered */ if (wimpt_justChangedMode() && w->antiAliased) { if (wnd=window__recreate(w),!wnd) return; win_register_event_handler(wnd,window__testEvents,w); wimpt_noerr(wimp_get_wind_state(w->h,&s)); wimpt_noerr(wimp_delete_wind(w->h)); win_register_event_handler(w->h,0,0); win_activedec(); w->h=wnd; s.o.w=w->h; wimpt_noerr(wimp_open_wind(&s.o)); } break; case wimp_ECLOSE: window_close(w); break; case wimp_EBUT: e=wimpt_last_event(); /* Get the real event */ switch (e->data.but.m.bbits) { case wimp_BMID: if (gPrefs_current()->sSlabMenu && e->data.but.m.i!=-1) sculptrix_slabIcon(e->data.but.m.w,e->data.but.m.i,&d); if (gPrefs_current()->iSlabMenu && e->data.but.m.i!=-1) { wimpt_noerr(wimp_get_icon_info(w->h,e->data.but.m.i,&icon)); interface_slabButton(&e->data.but.m); } wimpt_noerr(wimp_get_wind_state(w->h,&s)); ox=s.o.box.x0-s.o.x; oy=s.o.box.y1-s.o.y; window__showMenu(e->data.but.m.x-ox,e->data.but.m.y-oy,w); e->data.but.m.bbits=0; if (gPrefs_current()->iSlabMenu && e->data.but.m.i!=-1) { interface_slabButton(&e->data.but.m); if (icon.flags & wimp_IFONT) { wimpt_noerr(wimp_set_icon_state(w->h, e->data.but.m.i, icon.flags & 0xff000000, 0xff000000)); } } if (gPrefs_current()->sSlabMenu && e->data.but.m.i!=-1) sculptrix_unslabIcon(&d); break; case wimp_BDRAGLEFT: case wimp_BDRAGRIGHT: break; default: if (gPrefs_current()->sSlabIcons && e->data.but.m.i!=-1) sculptrix_slabIcon(e->data.but.m.w,e->data.but.m.i,&d); if (gPrefs_current()->iSlabIcons && e->data.but.m.i!=-1) { wimpt_noerr(wimp_get_icon_info(w->h,e->data.but.m.i,&icon)); interface_slabButton(&e->data.but.m); e->data.but.m.bbits=0; interface_slabButton(&e->data.but.m); if (icon.flags & wimp_IFONT) { wimpt_noerr(wimp_set_icon_state(w->h, e->data.but.m.i, icon.flags & 0xff000000, 0xff000000)); } } if (gPrefs_current()->sSlabIcons && e->data.but.m.i!=-1) sculptrix_unslabIcon(&d); break; } break; case wimp_EPTRLEAVE: w->ownPointer=FALSE; win_removeIdleClaimer(window__winIdles,w); window__updateInfoBar(FALSE); window__setPtrShape(window__SELECT); interface_spritearea((sprite_area *)1); break; case wimp_EPTRENTER: w->ownPointer=TRUE; win_addIdleClaimer(window__winIdles,win_DONTCARE,w); caretPtr__pointer(FALSE); /* Don't change pointer in this window */ interface_spritearea(w->t->s); break; case wimp_EKEY: if (gPrefs_current()->wKeyPress) { reg.r[0]=e->data.key.chcode; reg.r[2]=w->h; reg.r[3]=e->data.key.c.i; os_swix(XWimpExt_MoveCaret,®); if (reg.r[0]) wimpt_noerr(wimp_processkey(e->data.key.chcode)); else { reg.r[0]=2; reg.r[2]=-1; os_swix(XWimpExt_ViewIcon,®); /* --- That may have moved the window, so... --- */ wimpt_noerr(wimp_get_wind_state(w->h,&s)); if (s.o.x!=w->def->desc.w.scx || s.o.y!=w->def->desc.w.scy) { w->def->desc.w.scx=s.o.x; w->def->desc.w.scy=s.o.y; if (!w->t->alts) tfile_markAsAltered(w->t); } } } else wimpt_noerr(wimp_processkey(e->data.key.chcode)); break; case wimp_ESEND: case wimp_ESENDWANTACK: window__events(e,w); break; } } #endif /* * void window__events(wimp_eventstr *e,void *handle) * * Use * Handles all events for template windows (this is the first chance I've * had to get my fingers *REALLY* mucky on this whole project!) * * Parameters * wimp_eventstr *e == the event that I am meant to be inerested in * void *handle == a pointer to the structural information for this window */ void window__events(wimp_eventstr *e,void *handle) { glass_windPointer *w=handle; /* Extract my data from the handle */ wimp_redrawstr r; /* For the redraw event */ BOOL more; /* To tell me when I've finished */ int i; int zone; glass_intMsgstr *m; wimp_wstate s; wimp_w wnd; wimp_caretstr c; int ox=0,oy=0; int set=FALSE; wimp_box b; BOOL started=FALSE; static BOOL dontDrag; /* Disable/ignore next drag event */ glass_iconDescription icd; wimp_box bound; int dragType; int key,okey; switch (e->e) { case wimp_EREDRAW: r.w=w->h; wimpt_noerr(wimp_redraw_wind(&r,&more)); /* Start the redraw */ window__redraw(w,&r,&more); break; case wimp_EOPEN: /* --- Handle rubbery extents --- * * * We've got to make sure the window's not scrolling here, otherwise * very strange things start happening. */ if (e->data.o.x<=w->def->desc.w.scx && e->data.o.y>=w->def->desc.w.scy) { r.w=e->data.o.w; r.box=w->tex; if (tst(w->def->desc.w.flags,14)) { r.box.x0=w->def->desc.w.ex.x0; r.box.x1=max2(w->def->desc.w.ex.x1,e->data.o.x+e->data.o.box.x1- e->data.o.box.x0); } if (tst(w->def->desc.w.flags,15)) { r.box.y1=w->def->desc.w.ex.y1; r.box.y0=min2(w->def->desc.w.ex.y0,e->data.o.y-e->data.o.box.y1+ e->data.o.box.y0); } if (memcmp(&r.box,&w->tex,sizeof(wimp_box))) { wimpt_noerr(wimp_set_extent(&r)); w->tex=r.box; } } if (window_selectionOwner()==w) window__setToolBarPositions(&e->data.o); else wimpt_noerr(wimp_open_wind(&e->data.o)); w->def->desc.w.box=e->data.o.box; /* Copy the information down */ w->def->desc.w.scx=e->data.o.x; w->def->desc.w.scy=e->data.o.y; w->def->desc.w.behind=e->data.o.behind; if (!w->t->alts) /* Moving the window alters the template */ tfile_markAsAltered(w->t); /* But only if not already altered */ editWindow_windowMoved(w); if (wimpt_justChangedMode() && w->antiAliased) { if (wnd=window__recreate(w),!wnd) return; win_register_event_handler(wnd,window__events,w); wimpt_noerr(wimp_get_wind_state(w->h,&s)); wimpt_noerr(wimp_delete_wind(w->h)); win_register_event_handler(w->h,0,0); win_activedec(); w->h=wnd; s.o.w=w->h; wimpt_noerr(wimp_open_wind(&s.o)); } break; case wimp_ECLOSE: window_close(w); break; case wimp_EBUT: if (window__qDragType()!=-1) break; switch (e->data.but.m.bbits) { case wimp_BMID: wimpt_noerr(wimp_get_wind_state(w->h,&s)); ox=s.o.box.x0-s.o.x; oy=s.o.box.y1-s.o.y; window__showMenu(e->data.but.m.x-ox,e->data.but.m.y-oy,w); break; case wimp_BLEFT: if (!(akbd_pollsh() && (w->lastClicked!=-1)) && !w->renumber && (!gPrefs_current()->mCtrlEdit || akbd_pollctl())) { i=window__pointerInfo(w,-1,TRUE); if ((i & window__ZONEMASK)==window__HORGUIDE || (i & window__ZONEMASK)==window__VERGUIDE) break; if (i!=-1) editIcon(w,i&window__ICONMASK); else { i=window__pointerInfo(w,-1,FALSE); if (i!=-1) editIcon(w,i); else editWindow(w); } break; } /* Otherwise drop through to select... */ case wimp_BRIGHT: /* Treat this as a normal click - drop to select */ case wimp_BCLICKLEFT: case wimp_BCLICKRIGHT: /* --- if we're in the toolbox, or grab mode, ignore click --- */ if (toolbox_toolSelected() || window_grabbing()) { dontDrag=TRUE; /* The WIMP gives a drag on grab sprites! */ break; } /* --- give this window the selection, tool bars, and caret --- */ window__gainSelection(w); /* --- special case for renumbering --- */ if (w->renumber) { i=window__pointerInfo(w,-1,FALSE); if (!(i & window__ZONEMASK) && w->def->i[i].selected) { set=window__lowestSelected(w); window__select(w,i,FALSE); icd=w->def->i[i]; w->def->i[i]=w->def->i[set]; w->def->i[set]=icd; window_redrawIcon(w,i); window_redrawIcon(w,set); tfile_markAsAltered(w->t); if (w->selno) window__nextRenumber(w); else window__renumber(w,FALSE); } window__updateMenu(w); /* May have changed focus */ break; } /* --- handle depthwise selection - no problem with guides --- */ /* --- because we know the pointer is over an icon --- */ if (akbd_pollsh() && w->lastClicked!=-1 && window__pointerOverIcon(w,w->lastClicked)) { i=w->lastClicked; w->lastClicked=window__pointerInfo(w,w->lastClicked,FALSE); if (i!=w->lastClicked) { if (i==window__selectedIcon()) window__setSelectedIconDeselecting(w->lastClicked); else { window__select(w,i,FALSE); window__select(w,w->lastClicked,TRUE); } } dontDrag=TRUE; window__updateMenu(w); break; } /* --- this is the complicated bit. ADJUST should just --- */ /* --- toggle the object. So do this, but remember, it --- */ /* --- could have been a double-click --- */ if (e->data.but.m.bbits==wimp_BCLICKRIGHT || e->data.but.m.bbits==wimp_BRIGHT) { i=window__pointerInfo(w,-1,FALSE); if (i != -1 && (i & window__ZONEMASK)) { i &= window__ICONMASK; w->guide[i].selected=!w->guide[i].selected; window__redrawGuide(w,i); dontDrag=TRUE; } else { if (i!=-1) { window__select(w,i,!w->def->i[i].selected); w->lastClicked=i; dontDrag=TRUE; } else dontDrag=FALSE; } window__updateMenu(w); break; } /* --- now we're left with a SELECT click. If this is the --- */ /* --- start of a drag, then ignore it, otherwise do normal --- */ /* --- SELECT-type things (deselecting other icons etc.) --- */ i=window__pointerInfo(w,-1,TRUE); if (i==-1) { i=window__pointerInfo(w,-1,FALSE); zone=-1; } else { zone=i & window__ZONEMASK; i&=window__ICONMASK; } w->lastClicked=i; switch (zone) { case -1: /* Not previously selected */ if (w->lastClicked!=-1) window__setSelectedIconDeselecting(w->lastClicked); for (i=0;idef->desc.w.nicons;i++) { if (i!=w->lastClicked) window__select(w,i,FALSE); } dontDrag=FALSE; break; case window__HORGUIDE: case window__VERGUIDE: if (!w->guide[i].selected) { for (i=0;iguide[i].selected) { w->guide[i].selected=FALSE; window__redrawGuide(w,i); } } w->guide[w->lastClicked].selected=TRUE; window__redrawGuide(w,w->lastClicked); } dontDrag=FALSE; break; default: /* --- Any other zones we ignore - these are for drag --- */ /* --- operations --- */ window__setSelectedIcon(w->lastClicked); dontDrag=FALSE; break; } window__updateMenu(w); break; case wimp_BDRAGLEFT: case wimp_BDRAGRIGHT: if (dontDrag || toolbox_toolSelected() || window_grabbing() || w->renumber) break; /* --- YARB -- Yet Another RISC OS Bug --- * * * In a terribly cunning way, the WIMP gives me drag events even * when the mouse button is up and the user didn't drag at all. * This is phenomenally irritating, and so, hi-ho, a bodging we * will go... */ bbc_mouse(0,0,&i,0); if (!i) return; if (e->data.but.m.bbits==wimp_BDRAGLEFT) { i=window__pointerInfo(w,-1,TRUE); if (i == -1) dragType = window__SELECT; else dragType=i & window__ZONEMASK; } else dragType=window__SELECT; switch (dragType) { case window__SELECT: case window__HORGUIDE: case window__VERGUIDE: break; default: for (i=0;idef->desc.w.nicons;i++) { if (w->def->i[i].selected) { window_boundingBox(w,i,&b); if (!started) { bound=b; started=TRUE; } else { if (bound.x0>b.x0) bound.x0=b.x0; if (bound.x1b.y0) bound.y0=b.y0; if (bound.y1h,&s)); ox=s.o.box.x0-s.o.x; oy=s.o.box.y1-s.o.y; window__startDrag(dragType, &bound, w, e->data.but.m.x-ox, e->data.but.m.y-oy); break; } break; case wimp_EPTRLEAVE: w->ownPointer=FALSE; win_removeIdleClaimer(window__winIdles,w); window__updateInfoBar(FALSE); window__setPtrShape(window__SELECT); break; case wimp_EPTRENTER: w->ownPointer=TRUE; win_addIdleClaimer(window__winIdles,win_DONTCARE,w); if (window__qDragType()==window__GRABICON && !window__dragWind()) window__setDragWind(w); break; case wimp_EKEY: key=akbd_translate(e->data.key.chcode); while (key!=-1) { okey=key; key=-1; switch (okey) { /* --- Normal short-cuts, simulate menu entries --- */ case key_cF1: window__simMenu(w,glass_TWMISC,glass_TWMINFO); break; case key_cW: window__simMenu(w,glass_TWMISC,glass_TWMEDITWIN); break; case key_cT: window__simMenu(w,glass_TWMISC,glass_TWMTEST); break; case key_cF2: window__simMenu(w,glass_TWMISC,glass_TWMCLOSE); break; case key_F3: window__simMenu(w,glass_TWSAVE,0); break; case key_cA: window__simMenu(w,glass_TWSELECT,glass_TWSALL); break; case key_cZ: window__simMenu(w,glass_TWSELECT,glass_TWSCLR); break; case key_cC: window__simMenu(w,glass_TWSELECT,glass_TWSCOPY); break; case key_cX: window__simMenu(w,glass_TWSELECT,glass_TWSDEL); break; case key_cR: window__simMenu(w,glass_TWSELECT,glass_TWSORDER); break; case key_scF: window__simMenu(w,glass_TWSELECT,glass_TWSFRONT); break; case key_cF: window__simMenu(w,glass_TWSELECT,glass_TWSRAISE); break; case key_cB: window__simMenu(w,glass_TWSELECT,glass_TWSLOWER); break; case key_scB: window__simMenu(w,glass_TWSELECT,glass_TWSBACK); break; case key_cP: window__simMenu(w,glass_TWSELECT,glass_TWSPULL); break; case key_cL: window__simMenu(w,glass_TWSELECT,glass_TWSALIGN); break; case key_scE: tearEdit_open(); break; case key_cE: window__simMenu(w,glass_TWSELECT,glass_TWSEDIT); break; #ifdef glass_NOTLAZY case key_cD: window__simMenu(w,glass_TWSELECT,glass_TWSDATA); break; #endif case key_cN: window__simMenu(w,glass_TWICON,glass_TWINEW); break; case key_cG: window__simMenu(w,glass_TWICON,glass_TWIGRAB); break; /* --- Cursor keys -- move icons around --- */ /* No modifiers -- move the whole icon */ case key_Up: b.y0=b.y1=window__keyAhead(okey,&key); b.x0=b.x1=0; window__nudgeIcons(w,&b); break; case key_Down: b.y0=b.y1=-window__keyAhead(okey,&key); b.x0=b.x1=0; window__nudgeIcons(w,&b); break; case key_Left: b.y0=b.y1=0; b.x0=b.x1=-window__keyAhead(okey,&key); window__nudgeIcons(w,&b); break; case key_Right: b.y0=b.y1=0; b.x0=b.x1=window__keyAhead(okey,&key); window__nudgeIcons(w,&b); break; /* Control pressed -- move the most significant edge */ case key_cUp: b.y1=window__keyAhead(okey,&key); b.x0=b.x1=b.y0=0; window__nudgeIcons(w,&b); break; case key_cDown: b.y1=-window__keyAhead(okey,&key); b.x0=b.x1=b.y0=0; window__nudgeIcons(w,&b); break; case key_cLeft: b.x1=-window__keyAhead(okey,&key); b.y0=b.y1=b.x0=0; window__nudgeIcons(w,&b); break; case key_cRight: b.x1=window__keyAhead(okey,&key); b.y0=b.y1=b.x0=0; window__nudgeIcons(w,&b); break; /* Shift pressed -- move the least significant edge */ case key_sUp: b.y0=window__keyAhead(okey,&key); b.x0=b.x1=b.y1=0; window__nudgeIcons(w,&b); break; case key_sDown: b.y0=-window__keyAhead(okey,&key); b.x0=b.x1=b.y1=0; window__nudgeIcons(w,&b); break; case key_sLeft: b.x0=-window__keyAhead(okey,&key); b.y0=b.y1=b.x1=0; window__nudgeIcons(w,&b); break; case key_sRight: b.x0=window__keyAhead(okey,&key); b.y0=b.y1=b.x1=0; window__nudgeIcons(w,&b); break; /* Shift and control pressed -- scroll the window --- */ case key_scUp: window__nudgeScroll(w,0,window__keyAhead(okey,&key)); break; case key_scDown: window__nudgeScroll(w,0,-window__keyAhead(okey,&key)); break; case key_scLeft: window__nudgeScroll(w,-window__keyAhead(okey,&key),0); break; case key_scRight: window__nudgeScroll(w,window__keyAhead(okey,&key),0); break; /* --- No match -- pass on keypress --- */ default: wimp_processkey(e->data.key.chcode); break; } } break; case wimp_ESEND: case wimp_ESENDWANTACK: switch (e->data.msg.hdr.action) { case wimp_MHELPREQUEST: help_startHelp(); help_addLine(msgs_lookup("wdhWIN"),w->id); if (i=window__pointerInfo(w,-1,FALSE),i!=-1) help_addLine(msgs_lookup("wdhICN"),i); else help_addLine(msgs_lookup("wdhBKG")); help_endHelp(); break; case wimp_MINTERNAL: m=intMsgs_receive(e); switch (e->data.msg.data.words[0]) { case glass_REDRAW: if (m->rdr.t==w->t || m->rdr.t==0) { wimpt_noerr(wimp_get_wind_state(w->h,&s)); r.w=w->h; r.box.x0=s.o.x; r.box.x1=r.box.x0+s.o.box.x1-s.o.box.x0; r.box.y1=s.o.y; r.box.y0=r.box.y1+s.o.box.y0-s.o.box.y1; wimpt_noerr(wimp_force_redraw(&r)); } break; case glass_RENAME: if (m->rn.w==w && w==window_selectionOwner()) window__updateInfoName(w->id); break; case glass_SPRITECHANGE: if (m->sc.t==w->t) { wimpt_noerr(wimp_get_caret_pos(&c)); if (wnd=window__recreate(w),!wnd) return; if (c.w==w->h) c.w=wnd; #ifndef glass_DEMO win_register_event_handler(wnd, w->testMode ? window__testEvents : window__events,w); #else win_register_event_handler(wnd,window__events,w); #endif wimpt_noerr(wimp_get_wind_state(w->h,&s)); wimpt_noerr(wimp_delete_wind(w->h)); win_register_event_handler(w->h,0,0); win_activedec(); w->h=wnd; s.o.w=w->h; wimpt_noerr(wimp_open_wind(&s.o)); if (c.w==wnd) wimp_set_caret_pos(&c); } break; } break; } break; } }