/* * wIcons.c * * Manipulation of icons within 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/flex.h" #include "steel/bbc.h" #include "steel/font.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 "editIcon.h" #include "indir.h" #include "iconData.h" #include "tearEdit.h" /*----- Main code ---------------------------------------------------------*/ /* * void window__bound(wimp_icon *i,wimp_box *box,BOOL force) * * Use * Works out the bounding box (including 3D border) of the given pseudoicon. * * Parameters * wimp_icon *i == pointer to an icon definition * wimp_box *box == where to put the result * BOOL force == force reading of the border, even if disabled in prefs */ void window__bound(wimp_icon *i,wimp_box *box,BOOL force) { os_regset r; wimp_icon j; /* --- Get the answer from Sculptrix --- */ j=*i; if (gPrefs_current()->sDispBorders && (force || gPrefs_current()->sIncBorder) && sculptrix_boundingBox(&j)) { *box=j.box; return; } /* --- Ask Interface if there's a bounding box at all --- */ if (gPrefs_current()->iDispBorders && (force || gPrefs_current()->iIncBorder)) { r.r[1]=(int)&j; wimpt_noerr(os_swix(XInterface_BoundingBox,&r)); *box=j.box; } else *box=i->box; /* --- Now ask WimpExtension --- */ if (gPrefs_current()->wDispBorders && (force || gPrefs_current()->wIncBorder)) { r.r[0]=2; r.r[1]=(int)i; wimpt_noerr(os_swix(XWimpExt_BorderOp,&r)); box->x0=min2(box->x0,r.r[2]); box->y0=min2(box->y0,r.r[3]); box->x1=max2(box->x1,r.r[4]); box->y1=max2(box->y1,r.r[5]); } } /* * void window__removeTrailingDeleted(glass_windPointer *w) * * Use * Removes trailing deleted icons from a window (i.e. ones that can be * safely deleted properly without messing up icon numbers). * * Parameters * glass_windPointer *w == the window to blitz */ void window__removeTrailingDeleted(glass_windPointer *w) { int i=w->def->desc.w.nicons-1; int dead=0; while (w->def->i[i].i.flags & wimp_IDELETED) { i--; /* Now points to top undeleted icon */ dead++; } flex_extend((flex_ptr)&w->def, sizeof(glass_window)+ i*sizeof(glass_iconDescription)); w->size-=dead*sizeof(glass_iconDescription); w->def->desc.w.nicons-=dead; } /* * int window__createIcon(glass_windPointer *w) * * Use * Creates a slot for an icon in the window specified, according to current * preferences. The contents of the icon array are unspecified (and * probably not too useful). * * Parameters * glass_windPointer *w == the window to create the icon in * * Returns * Icon number that can be used, or -1 if the operation failed. */ int window__createIcon(glass_windPointer *w) { int i; /* --- Find a space to create the icon --- * * * If we're using up deleted spaces, then loop through to find the lowest * free one. */ if (!gPrefs_current()->mCreateTop) { for (i=0;idef->desc.w.nicons;i++) { if (w->def->i[i].i.flags & wimp_IDELETED) { w->def->i[i].selected=FALSE; w->def->i[i].edit=0; return (i); } } } else i=w->def->desc.w.nicons; /* --- We need to add a new icon on the end --- */ if (!flex_extend((flex_ptr)&w->def, sizeof(glass_window)+ i*sizeof(glass_iconDescription))) { werr(FALSE,msgs_lookup("wdNEMCI")); return (-1); } w->def->desc.w.nicons++; w->size+=sizeof(glass_iconDescription); w->def->i[i].selected=FALSE; w->def->i[i].copied=FALSE; w->def->i[i].edit=0; return (i); } /* * void window__renumber(glass_windPointer *w,BOOL renum) * * Use * Sets the renumber flag of the given window to the given state. * Everything is set up properly according to the new state. * * Parameters * glass_windPointer *w == the window to renumber * BOOL renum == the new state of the flag */ void window__renumber(glass_windPointer *w,BOOL renum) { int i; /* --- Make sure we've got something to do --- */ if (renum==w->renumber) return; /* --- Unselect all the guidelines --- */ for (i=0;iguide[i].selected) { w->guide[i].selected=FALSE; window__redrawGuide(w,i); } } /* --- Now change the selection boxes for all the icons --- * * * For each one, we undraw the old box, change the renumber state, and * draw the new one. Klugey, but it works. */ for (i=0;idef->desc.w.nicons;i++) { if (w->def->i[i].selected) { window__select(w,i,FALSE); w->renumber=!w->renumber; window__select(w,i,TRUE); w->renumber=!w->renumber; } } /* --- Update the window state information, and the info bar --- */ w->renumber=!w->renumber; window__toggleRenumber(w); } /* * void window__copyIcons(glass_windPointer *w) * * Use * Copies the selected icons into the given window. If the icons are * already in the given window, they are duplicated and offset by a small * quantity. If the icons are in a different window, then they are * centred over the current visible area. * * Parameters * glass_windPointer *w == the window to put the icons */ void window__copyIcons(glass_windPointer *w) { int xoff; int yoff; wimp_box bound; BOOL started; int i; wimp_wstate s; int ni; BOOL fonterr=FALSE; glass_windPointer *wso=window_selectionOwner(); /* --- Work out where to put the selected icons --- * * * If we're copying to the same window, we just displace them a bit. If * we're copying between windows, we need to centre them in the new * window. */ if (w==wso) { xoff=w->gridx; yoff=-w->gridy; } else { started=FALSE; /* --- Calculate the bounding box of the selection --- */ for (i=0;idef->desc.w.nicons;i++) { if (wso->def->i[i].selected) { if (started) { if (wso->def->i[i].i.box.x0def->i[i].i.box.x0; if (wso->def->i[i].i.box.x1>bound.x1) bound.x1=wso->def->i[i].i.box.x1; if (wso->def->i[i].i.box.y0def->i[i].i.box.y0; if (wso->def->i[i].i.box.y1>bound.y1) bound.y1=wso->def->i[i].i.box.y1; } else { bound=wso->def->i[i].i.box; started=TRUE; } } } /* --- Work out how to centre the icons --- */ wimpt_noerr(wimp_get_wind_state(w->h,&s)); xoff=(s.o.x+(s.o.box.x1-s.o.box.x0)/2-(bound.x1-bound.x0)/2); yoff=(s.o.y-(s.o.box.y1-s.o.box.y0)/2-(bound.y1-bound.y0)/2); xoff-=bound.x0; yoff-=bound.y0; /* --- If there's a grid lock, keep the same grid alignment --- */ if (w->gridLock) window__align(w,&xoff,&yoff); /* --- Also retain the pixel alignment --- */ xoff&=~(wimpt_dx()-1); yoff&=~(wimpt_dy()-1); } /* --- We've altered the template file --- */ tfile_markAsAltered(w->t); /* --- Now actually do the copy --- */ for (i=0;idef->desc.w.nicons;i++) { if (wso->def->i[i].selected) { /* --- Find out there to put the copy --- */ ni=window__createIcon(w); if (ni==-1) return; /* --- Reposition the copied icon nicely --- */ w->def->i[ni].i=wso->def->i[i].i; w->def->i[ni].i.box.x0+=xoff; w->def->i[ni].i.box.x1+=xoff; w->def->i[ni].i.box.y0+=yoff; w->def->i[ni].i.box.y1+=yoff; /* --- Set up the copied icon's font information --- */ if (!iconData_handleFont(w,&w->def->i[ni].i.flags) && !fonterr) { werr(FALSE,msgs_lookup("wdFERCPY")); fonterr=TRUE; } /* --- Set up the copied icon's indirected data nicely --- */ if (!iconData_processIcon(w,ni,0,TRUE,0)) { werr(FALSE,msgs_lookup("wdNEMCP")); w->def->i[ni].i.flags&=~wimp_INDIRECT; window_deleteIcon(w,ni); return; } window_redrawIcon(w,ni); w->def->i[ni].copied=TRUE; } } /* --- Now move the selection across, and select the copies --- */ for (i=0;idef->desc.w.nicons;i++) window__select(wso,i,FALSE); for (i=0;idef->desc.w.nicons;i++) { if (w->def->i[i].copied) window__select(w,i,TRUE); w->def->i[i].copied=FALSE; } window__gainSelection(w); } /* * void window__nudgeIcons(glass_windPointer *w,wimp_box *nudge) * * Use * Nudges the selected icons in the specified window, by adding the box * given to each icon's bounding box. The nudge box is multiplied either by * the current grid size (if grid lock is enabled) or by the pixel size (if * it isn't) before addition. A nudge is considered to be a single * alteration for the purposes of autosave-counting. If no icons are moved * then the selected guidelines are moved instead. * * Parameters * glass_windPointer *w == the window containing the icons to nudge * wimp_box *nudge == the box to add to the coordinates of the icons */ void window__nudgeIcons(glass_windPointer *w,wimp_box *nudge) { int i; wimp_box b; wimp_box *bp; BOOL doneOne=FALSE; /* --- Make sure we're not dragging something --- */ if (window__qDragType()!=-1) return; /* --- Multiply up the nudge rectangle --- */ if (w->gridLock) { nudge->x0*=w->gridx; nudge->y0*=w->gridy; nudge->x1*=w->gridx; nudge->y1*=w->gridy; } else { nudge->x0*=wimpt_dx(); nudge->y0*=wimpt_dy(); nudge->x1*=wimpt_dx(); nudge->y1*=wimpt_dy(); } /* --- Nudge the selected icons --- * * * Remember to make sure that we don't turn the icon inside-out. */ for (i=0;idef->desc.w.nicons;i++) { if (w->def->i[i].selected) { doneOne=TRUE; window_boundingBox(w,i,&b); bp=&w->def->i[i].i.box; if (bp->x0+nudge->x0<=bp->x1+nudge->x1) b.x0+=nudge->x0; if (bp->x1+nudge->x1>=bp->x0+nudge->x0) b.x1+=nudge->x1; if (bp->y0+nudge->y0<=bp->y1+nudge->y1) b.y0+=nudge->y0; if (bp->y1+nudge->y1>=bp->y0+nudge->y0) b.y1+=nudge->y1; window_setBox(w,i,&b); } } /* --- If no icons moved, nudge the guidelines --- * * * Only move guidelines if the box is sensible -- i.e. we're not just * moving an edge, we're moving the whole box either horizontally or * vertically */ if (!doneOne && nudge->x0==nudge->x1 && nudge->y0==nudge->y1) { for (i=0;iguide[i].selected) { doneOne=TRUE; window__redrawGuide(w,i); if (w->guide[i].horiz) w->guide[i].coord+=nudge->y0; else w->guide[i].coord+=nudge->x0; window__redrawGuide(w,i); } } } /* --- If we did something, bump the alteration count --- */ if (!doneOne) bbc_vdu(7); else tfile_markAsAltered(w->t); } /* * void window_boundingBox(glass_windPointer *w,int icon,wimp_box *box) * * Use * Gets the bounding box of the icon given and returns it in the block * pointed to by box * * Parameters * glass_windPointer *w == the window containing the icon * int icon == the icon to 'boxise' * wimp_box *box == where to put the result */ void window_boundingBox(glass_windPointer *w,int icon,wimp_box *box) { window__bound(&w->def->i[icon].i,box,FALSE); } /* * void window_setBox(glass_windPointer *w,int icon,wimp_box *box) * * Use * Sets the icon bounding box to the box given, taking into account * Interface borders and so on. * * Parameters * glass_windPointer *w == the window containing the icon * int icon == the icon number * wimp_box *box == the new box for the icon */ void window_setBox(glass_windPointer *w,int icon,wimp_box *box) { wimp_box bound; window_boundingBox(w,icon,&bound); window_redrawIcon(w,icon); w->def->i[icon].i.box.x0+=box->x0-bound.x0; w->def->i[icon].i.box.x1+=box->x1-bound.x1; w->def->i[icon].i.box.y0+=box->y0-bound.y0; w->def->i[icon].i.box.y1+=box->y1-bound.y1; window_redrawIcon(w,icon); editIcon_iconMoved(w,icon); } /* * void window_deleteIcon(glass_windPointer *w,int icon) * * Use * Deletes the icon specified, good an' proper. * * Parameters * glass_windPointer *w == the scene of the crime * int icon == the victim... */ void window_deleteIcon(glass_windPointer *w,int icon) { int fhand; editIcon_close(w,icon); if (w->def->i[icon].selected) w->selno--; if (w==window_selectionOwner() && icon==window__selectedIcon()) window__setSelectedIcon(-1); window_redrawIcon(w,icon); if (w->def->i[icon].i.flags & wimp_IFONT) { fhand=(w->def->i[icon].i.flags>>24) & 0xff; wimpt_noerr(font_lose(fhand)); w->fonts[fhand]--; } if (w->def->i[icon].i.flags & wimp_INDIRECT) { w->size-=w->def->i[icon].i.data.indirecttext.bufflen; indir_free(w->def->i[icon].i.data.indirecttext.buffer); if (w->def->i[icon].i.flags & wimp_ITEXT && w->def->i[icon].i.data.indirecttext.validstring!=(char *)-1) { utils_ctermToNterm(w->def->i[icon].i.data.indirecttext.validstring); w->size-=strlen(w->def->i[icon].i.data.indirecttext.validstring)+1; indir_free(w->def->i[icon].i.data.indirecttext.validstring); } } w->def->i[icon].i.flags=wimp_IDELETED; /* This is a late icon */ w->def->i[icon].selected=FALSE; if (gPrefs_current()->mDeleteRenum) window_renumber(w,icon,w->def->desc.w.nicons-1); tfile_markAsAltered(w->t); window__removeTrailingDeleted(w); } /* * void window_renumber(glass_windPointer *w,int icon,int new) * * Use * Renumbers an icon, by removing it from the array, shuffling others out * the way, and the putting it in its new position (i.e. it's an insert * renumber, not a swap renumber like the old version - which wasn't * terribly useful...) * * Parameters * glass_windPointer *w == the window containing the icon * int icon == the icon to renumber * int new == the new number to give it * * Returns * TRUE if successful */ BOOL window_renumber(glass_windPointer *w,int icon,int new) { glass_iconDescription idef=w->def->i[icon]; int i; int si=window__selectedIcon(); if (new<0 || new>=w->def->desc.w.nicons) { note(msgs_lookup("wdIIRN")); return (FALSE); } if (new==icon) return (TRUE); editIcon_renumber(w,icon,new); if (new=new && sinew;i--) { editIcon_renumber(w,i-1,i); w->def->i[i]=w->def->i[i-1]; } } else { if (w==window_selectionOwner() && si!=-1) { if (si==icon) window__renumberSelectedIcon(new); else if (si<=new && si>icon) window__renumberSelectedIcon(si-1); } for (i=icon;idef->i[i]=w->def->i[i+1]; } } w->def->i[new]=idef; window_redrawIcon(w,new); return (TRUE); }