4 * Manipulation of icons within template windows
6 * © 1994-1998 Straylight
9 /*----- Licensing note ----------------------------------------------------*
11 * This file is part of Straylight's Glass.
13 * Glass is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2, or (at your option)
18 * Glass is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with Glass. If not, write to the Free Software Foundation,
25 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 /*----- Header files ------------------------------------------------------*/
31 * ANSI standard headers
44 #include "steel/Steel.h"
46 #include "steel/interface.h"
47 #include "steel/sculptrix.h"
48 #include "steel/flex.h"
49 #include "steel/bbc.h"
50 #include "steel/font.h"
70 /*----- Main code ---------------------------------------------------------*/
73 * void window__bound(wimp_icon *i,wimp_box *box,BOOL force)
76 * Works out the bounding box (including 3D border) of the given pseudoicon.
79 * wimp_icon *i == pointer to an icon definition
80 * wimp_box *box == where to put the result
81 * BOOL force == force reading of the border, even if disabled in prefs
84 void window__bound(wimp_icon *i,wimp_box *box,BOOL force)
89 /* --- Get the answer from Sculptrix --- */
92 if (gPrefs_current()->sDispBorders &&
93 (force || gPrefs_current()->sIncBorder) &&
94 sculptrix_boundingBox(&j))
100 /* --- Ask Interface if there's a bounding box at all --- */
102 if (gPrefs_current()->iDispBorders &&
103 (force || gPrefs_current()->iIncBorder))
106 wimpt_noerr(os_swix(XInterface_BoundingBox,&r));
112 /* --- Now ask WimpExtension --- */
114 if (gPrefs_current()->wDispBorders &&
115 (force || gPrefs_current()->wIncBorder))
119 wimpt_noerr(os_swix(XWimpExt_BorderOp,&r));
120 box->x0=min2(box->x0,r.r[2]);
121 box->y0=min2(box->y0,r.r[3]);
122 box->x1=max2(box->x1,r.r[4]);
123 box->y1=max2(box->y1,r.r[5]);
128 * void window__removeTrailingDeleted(glass_windPointer *w)
131 * Removes trailing deleted icons from a window (i.e. ones that can be
132 * safely deleted properly without messing up icon numbers).
135 * glass_windPointer *w == the window to blitz
138 void window__removeTrailingDeleted(glass_windPointer *w)
140 int i=w->def->desc.w.nicons-1;
142 while (w->def->i[i].i.flags & wimp_IDELETED)
144 i--; /* Now points to top undeleted icon */
147 flex_extend((flex_ptr)&w->def,
148 sizeof(glass_window)+
149 i*sizeof(glass_iconDescription));
150 w->size-=dead*sizeof(glass_iconDescription);
151 w->def->desc.w.nicons-=dead;
155 * int window__createIcon(glass_windPointer *w)
158 * Creates a slot for an icon in the window specified, according to current
159 * preferences. The contents of the icon array are unspecified (and
160 * probably not too useful).
163 * glass_windPointer *w == the window to create the icon in
166 * Icon number that can be used, or -1 if the operation failed.
169 int window__createIcon(glass_windPointer *w)
173 /* --- Find a space to create the icon --- *
175 * If we're using up deleted spaces, then loop through to find the lowest
179 if (!gPrefs_current()->mCreateTop)
181 for (i=0;i<w->def->desc.w.nicons;i++)
183 if (w->def->i[i].i.flags & wimp_IDELETED)
185 w->def->i[i].selected=FALSE;
192 i=w->def->desc.w.nicons;
194 /* --- We need to add a new icon on the end --- */
196 if (!flex_extend((flex_ptr)&w->def,
197 sizeof(glass_window)+
198 i*sizeof(glass_iconDescription)))
200 werr(FALSE,msgs_lookup("wdNEMCI"));
203 w->def->desc.w.nicons++;
204 w->size+=sizeof(glass_iconDescription);
205 w->def->i[i].selected=FALSE;
206 w->def->i[i].copied=FALSE;
212 * void window__renumber(glass_windPointer *w,BOOL renum)
215 * Sets the renumber flag of the given window to the given state.
216 * Everything is set up properly according to the new state.
219 * glass_windPointer *w == the window to renumber
220 * BOOL renum == the new state of the flag
223 void window__renumber(glass_windPointer *w,BOOL renum)
227 /* --- Make sure we've got something to do --- */
229 if (renum==w->renumber)
232 /* --- Unselect all the guidelines --- */
234 for (i=0;i<glass_GUIDELIMIT;i++)
236 if (w->guide[i].selected)
238 w->guide[i].selected=FALSE;
239 window__redrawGuide(w,i);
243 /* --- Now change the selection boxes for all the icons --- *
245 * For each one, we undraw the old box, change the renumber state, and
246 * draw the new one. Klugey, but it works.
249 for (i=0;i<w->def->desc.w.nicons;i++)
251 if (w->def->i[i].selected)
253 window__select(w,i,FALSE);
254 w->renumber=!w->renumber;
255 window__select(w,i,TRUE);
256 w->renumber=!w->renumber;
260 /* --- Update the window state information, and the info bar --- */
262 w->renumber=!w->renumber;
263 window__toggleRenumber(w);
267 * void window__copyIcons(glass_windPointer *w)
270 * Copies the selected icons into the given window. If the icons are
271 * already in the given window, they are duplicated and offset by a small
272 * quantity. If the icons are in a different window, then they are
273 * centred over the current visible area.
276 * glass_windPointer *w == the window to put the icons
279 void window__copyIcons(glass_windPointer *w)
289 glass_windPointer *wso=window_selectionOwner();
291 /* --- Work out where to put the selected icons --- *
293 * If we're copying to the same window, we just displace them a bit. If
294 * we're copying between windows, we need to centre them in the new
307 /* --- Calculate the bounding box of the selection --- */
309 for (i=0;i<wso->def->desc.w.nicons;i++)
311 if (wso->def->i[i].selected)
315 if (wso->def->i[i].i.box.x0<bound.x0)
316 bound.x0=wso->def->i[i].i.box.x0;
317 if (wso->def->i[i].i.box.x1>bound.x1)
318 bound.x1=wso->def->i[i].i.box.x1;
319 if (wso->def->i[i].i.box.y0<bound.y0)
320 bound.y0=wso->def->i[i].i.box.y0;
321 if (wso->def->i[i].i.box.y1>bound.y1)
322 bound.y1=wso->def->i[i].i.box.y1;
326 bound=wso->def->i[i].i.box;
332 /* --- Work out how to centre the icons --- */
334 wimpt_noerr(wimp_get_wind_state(w->h,&s));
335 xoff=(s.o.x+(s.o.box.x1-s.o.box.x0)/2-(bound.x1-bound.x0)/2);
336 yoff=(s.o.y-(s.o.box.y1-s.o.box.y0)/2-(bound.y1-bound.y0)/2);
340 /* --- If there's a grid lock, keep the same grid alignment --- */
343 window__align(w,&xoff,&yoff);
345 /* --- Also retain the pixel alignment --- */
347 xoff&=~(wimpt_dx()-1);
348 yoff&=~(wimpt_dy()-1);
351 /* --- We've altered the template file --- */
353 tfile_markAsAltered(w->t);
355 /* --- Now actually do the copy --- */
357 for (i=0;i<wso->def->desc.w.nicons;i++)
359 if (wso->def->i[i].selected)
362 /* --- Find out there to put the copy --- */
364 ni=window__createIcon(w);
368 /* --- Reposition the copied icon nicely --- */
370 w->def->i[ni].i=wso->def->i[i].i;
371 w->def->i[ni].i.box.x0+=xoff;
372 w->def->i[ni].i.box.x1+=xoff;
373 w->def->i[ni].i.box.y0+=yoff;
374 w->def->i[ni].i.box.y1+=yoff;
376 /* --- Set up the copied icon's font information --- */
378 if (!iconData_handleFont(w,&w->def->i[ni].i.flags) && !fonterr)
380 werr(FALSE,msgs_lookup("wdFERCPY"));
384 /* --- Set up the copied icon's indirected data nicely --- */
386 if (!iconData_processIcon(w,ni,0,TRUE,0))
388 werr(FALSE,msgs_lookup("wdNEMCP"));
389 w->def->i[ni].i.flags&=~wimp_INDIRECT;
390 window_deleteIcon(w,ni);
393 window_redrawIcon(w,ni);
394 w->def->i[ni].copied=TRUE;
398 /* --- Now move the selection across, and select the copies --- */
400 for (i=0;i<wso->def->desc.w.nicons;i++)
401 window__select(wso,i,FALSE);
402 for (i=0;i<w->def->desc.w.nicons;i++)
404 if (w->def->i[i].copied)
405 window__select(w,i,TRUE);
406 w->def->i[i].copied=FALSE;
408 window__gainSelection(w);
412 * void window__nudgeIcons(glass_windPointer *w,wimp_box *nudge)
415 * Nudges the selected icons in the specified window, by adding the box
416 * given to each icon's bounding box. The nudge box is multiplied either by
417 * the current grid size (if grid lock is enabled) or by the pixel size (if
418 * it isn't) before addition. A nudge is considered to be a single
419 * alteration for the purposes of autosave-counting. If no icons are moved
420 * then the selected guidelines are moved instead.
423 * glass_windPointer *w == the window containing the icons to nudge
424 * wimp_box *nudge == the box to add to the coordinates of the icons
427 void window__nudgeIcons(glass_windPointer *w,wimp_box *nudge)
434 /* --- Make sure we're not dragging something --- */
436 if (window__qDragType()!=-1)
439 /* --- Multiply up the nudge rectangle --- */
450 nudge->x0*=wimpt_dx();
451 nudge->y0*=wimpt_dy();
452 nudge->x1*=wimpt_dx();
453 nudge->y1*=wimpt_dy();
456 /* --- Nudge the selected icons --- *
458 * Remember to make sure that we don't turn the icon inside-out.
461 for (i=0;i<w->def->desc.w.nicons;i++)
463 if (w->def->i[i].selected)
466 window_boundingBox(w,i,&b);
467 bp=&w->def->i[i].i.box;
468 if (bp->x0+nudge->x0<=bp->x1+nudge->x1)
470 if (bp->x1+nudge->x1>=bp->x0+nudge->x0)
472 if (bp->y0+nudge->y0<=bp->y1+nudge->y1)
474 if (bp->y1+nudge->y1>=bp->y0+nudge->y0)
476 window_setBox(w,i,&b);
480 /* --- If no icons moved, nudge the guidelines --- *
482 * Only move guidelines if the box is sensible -- i.e. we're not just
483 * moving an edge, we're moving the whole box either horizontally or
487 if (!doneOne && nudge->x0==nudge->x1 && nudge->y0==nudge->y1)
489 for (i=0;i<glass_GUIDELIMIT;i++)
491 if (w->guide[i].selected)
494 window__redrawGuide(w,i);
495 if (w->guide[i].horiz)
496 w->guide[i].coord+=nudge->y0;
498 w->guide[i].coord+=nudge->x0;
499 window__redrawGuide(w,i);
504 /* --- If we did something, bump the alteration count --- */
509 tfile_markAsAltered(w->t);
513 * void window_boundingBox(glass_windPointer *w,int icon,wimp_box *box)
516 * Gets the bounding box of the icon given and returns it in the block
520 * glass_windPointer *w == the window containing the icon
521 * int icon == the icon to 'boxise'
522 * wimp_box *box == where to put the result
525 void window_boundingBox(glass_windPointer *w,int icon,wimp_box *box)
527 window__bound(&w->def->i[icon].i,box,FALSE);
531 * void window_setBox(glass_windPointer *w,int icon,wimp_box *box)
534 * Sets the icon bounding box to the box given, taking into account
535 * Interface borders and so on.
538 * glass_windPointer *w == the window containing the icon
539 * int icon == the icon number
540 * wimp_box *box == the new box for the icon
543 void window_setBox(glass_windPointer *w,int icon,wimp_box *box)
546 window_boundingBox(w,icon,&bound);
547 window_redrawIcon(w,icon);
548 w->def->i[icon].i.box.x0+=box->x0-bound.x0;
549 w->def->i[icon].i.box.x1+=box->x1-bound.x1;
550 w->def->i[icon].i.box.y0+=box->y0-bound.y0;
551 w->def->i[icon].i.box.y1+=box->y1-bound.y1;
552 window_redrawIcon(w,icon);
553 editIcon_iconMoved(w,icon);
557 * void window_deleteIcon(glass_windPointer *w,int icon)
560 * Deletes the icon specified, good an' proper.
563 * glass_windPointer *w == the scene of the crime
564 * int icon == the victim...
567 void window_deleteIcon(glass_windPointer *w,int icon)
570 editIcon_close(w,icon);
572 if (w->def->i[icon].selected)
574 if (w==window_selectionOwner() && icon==window__selectedIcon())
575 window__setSelectedIcon(-1);
577 window_redrawIcon(w,icon);
578 if (w->def->i[icon].i.flags & wimp_IFONT)
580 fhand=(w->def->i[icon].i.flags>>24) & 0xff;
581 wimpt_noerr(font_lose(fhand));
584 if (w->def->i[icon].i.flags & wimp_INDIRECT)
586 w->size-=w->def->i[icon].i.data.indirecttext.bufflen;
587 indir_free(w->def->i[icon].i.data.indirecttext.buffer);
588 if (w->def->i[icon].i.flags & wimp_ITEXT &&
589 w->def->i[icon].i.data.indirecttext.validstring!=(char *)-1)
591 utils_ctermToNterm(w->def->i[icon].i.data.indirecttext.validstring);
592 w->size-=strlen(w->def->i[icon].i.data.indirecttext.validstring)+1;
593 indir_free(w->def->i[icon].i.data.indirecttext.validstring);
597 w->def->i[icon].i.flags=wimp_IDELETED; /* This is a late icon */
598 w->def->i[icon].selected=FALSE;
600 if (gPrefs_current()->mDeleteRenum)
601 window_renumber(w,icon,w->def->desc.w.nicons-1);
602 tfile_markAsAltered(w->t);
603 window__removeTrailingDeleted(w);
607 * void window_renumber(glass_windPointer *w,int icon,int new)
610 * Renumbers an icon, by removing it from the array, shuffling others out
611 * the way, and the putting it in its new position (i.e. it's an insert
612 * renumber, not a swap renumber like the old version - which wasn't
613 * terribly useful...)
616 * glass_windPointer *w == the window containing the icon
617 * int icon == the icon to renumber
618 * int new == the new number to give it
624 BOOL window_renumber(glass_windPointer *w,int icon,int new)
626 glass_iconDescription idef=w->def->i[icon];
628 int si=window__selectedIcon();
630 if (new<0 || new>=w->def->desc.w.nicons)
632 note(msgs_lookup("wdIIRN"));
637 editIcon_renumber(w,icon,new);
641 if (w==window_selectionOwner() && si!=-1)
644 window__renumberSelectedIcon(new);
645 else if (si>=new && si<icon)
646 window__renumberSelectedIcon(si+1);
648 for (i=icon;i>new;i--)
650 editIcon_renumber(w,i-1,i);
651 w->def->i[i]=w->def->i[i-1];
656 if (w==window_selectionOwner() && si!=-1)
659 window__renumberSelectedIcon(new);
660 else if (si<=new && si>icon)
661 window__renumberSelectedIcon(si-1);
663 for (i=icon;i<new;i++)
665 editIcon_renumber(w,i+1,i);
666 w->def->i[i]=w->def->i[i+1];
670 window_redrawIcon(w,new);