chiark / gitweb /
Initial revision
[ssr] / StraySrc / Glass / !Glass / c / wRedraw
1 /*
2  * wRedraw.c
3  *
4  * Redrawing template windows
5  *
6  * © 1994-1998 Straylight
7  */
8
9 /*----- Licensing note ----------------------------------------------------*
10  *
11  * This file is part of Straylight's Glass.
12  *
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)
16  * any later version.
17  *
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.
22  *
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.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 /*
31  * ANSI standard headers
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 /*
39  * Steel headers
40  */
41
42 #define _STDAPP
43 #define _LOWLVL
44 #include "steel/Steel.h"
45
46 #include "steel/interface.h"
47 #include "steel/sculptrix.h"
48 #include "steel/bbc.h"
49 #include "steel/coords.h"
50
51 /*
52  * Glass headers
53  */
54
55 #include "gStruct.h"
56 #include "gMenus.h"
57 #include "gIcons.h"
58
59 #include "glass.h"
60 #include "gPrefs.h"
61 #include "window.h"
62 #include "_window.h"
63 #include "tearEdit.h"
64
65 /*----- Main code ---------------------------------------------------------*/
66
67 /*
68  * void window__drawSelectBox(glass_windPointer *w,
69  *                            int icon,
70  *                            BOOL makesi,
71  *                            wimp_redrawstr *r)
72  *
73  * Use
74  *  Draws the selection box around an icon
75  *
76  * Parameters
77  *  glass_windPointer *w == the window
78  *  int icon == the icon
79  *  BOOL makesi == whether we're going between a selected and main selected
80  *    icon.
81  *  wimp_redrawstr *r == the redraw structure
82  */
83
84 #define HW window__HANDLEWIDTH
85
86 void window__drawSelectBox(glass_windPointer *w,
87                            int icon,
88                            BOOL makesi,
89                            wimp_redrawstr *r)
90 {
91   wimp_box box;
92   int ox=r->box.x0-r->scx;
93   int oy=r->box.y1-r->scy;
94
95   window_boundingBox(w,icon,&box);
96
97   /* --- If we're in test mode, do nothing --- */
98
99 #ifndef glass_DEMO
100   if (w->testMode)
101     /* Blank */;
102   else
103 #endif
104
105   /* --- If we're not renumbering, draw in all the fancy bits --- */
106
107   if (!w->renumber)
108   {
109
110     /* --- Make sure the user wants a border, and draw the right one --- */
111
112     if (gPrefs_current()->sBorder && !makesi)
113     {
114       window__setXORColour(w,window__SELBOXCOL);
115       if (gPrefs_current()->sDotted)
116       {
117         window__makeDashPattern(0xf0);
118         window__rectangle(ox+box.x0-wimpt_dx(),
119                           oy+box.y0-wimpt_dy(),
120                           box.x1-box.x0+wimpt_dx(),
121                           box.y1-box.y0+wimpt_dy());
122       }
123       else
124       {
125         bbc_rectangle(ox+box.x0-wimpt_dx(),
126                       oy+box.y0-wimpt_dy(),
127                       box.x1-box.x0+wimpt_dx(),
128                       box.y1-box.y0+wimpt_dy());
129       }
130     }
131
132     /* --- Draw in all the drag handles --- */
133
134     if (makesi)
135       window__colourChange(window__MSELBOXCOL,window__HANDCOL);
136     else if (icon==window__selectedIcon())
137       window__setXORColour(w,window__MSELBOXCOL);
138     else
139       window__setXORColour(w,window__HANDCOL);
140
141     /* If edges are wanted, fill them in */
142
143     if (gPrefs_current()->sEdgeHandles)
144     {
145       bbc_rectanglefill(ox+box.x0-wimpt_dx()-HW,
146                         oy+box.y0+(box.y1-box.y0-HW*2)/2,
147                         HW*2,
148                         HW*2);
149       bbc_rectanglefill(ox+box.x1-HW,
150                         oy+box.y0+(box.y1-box.y0-HW*2)/2,
151                         HW*2,
152                         HW*2);
153       bbc_rectanglefill(ox+box.x0+(box.x1-box.x0-HW*2)/2,
154                         oy+box.y0-wimpt_dy()-HW,
155                         HW*2,
156                         HW*2);
157       bbc_rectanglefill(ox+box.x0+(box.x1-box.x0-HW*2)/2,
158                         oy+box.y1-HW,
159                         HW*2,
160                         HW*2);
161     }
162
163     /* Corners are always drawn */
164
165     bbc_rectanglefill(ox+box.x0-wimpt_dx()-HW,
166                       oy+box.y0-wimpt_dy()-HW,
167                       HW*2,
168                       HW*2);
169     bbc_rectanglefill(ox+box.x1-HW,
170                       oy+box.y0-wimpt_dy()-HW,
171                       HW*2,
172                       HW*2);
173     bbc_rectanglefill(ox+box.x0-wimpt_dx()-HW,
174                       oy+box.y1-HW,
175                       HW*2,
176                       HW*2);
177     bbc_rectanglefill(ox+box.x1-HW,
178                       oy+box.y1-HW,
179                       HW*2,
180                       HW*2);
181   }
182   else
183
184   /* --- Otherwise, we do the funny renumbering corner bits --- */
185
186   {
187     window__setXORColour(w,window__HANDCOL);
188     bbc_move(ox+box.x0-8,oy+box.y1-wimpt_dy()-12);
189     bbc_drawby(0,20);
190     bbc_drawby(20,0);
191     bbc_move(ox+box.x1-wimpt_dx()+8,oy+box.y1-wimpt_dy()-12);
192     bbc_drawby(0,20);
193     bbc_drawby(-20,0);
194     bbc_move(ox+box.x0-8,oy+box.y0+12);
195     bbc_drawby(0,-20);
196     bbc_drawby(20,0);
197     bbc_move(ox+box.x1-wimpt_dx()+8,oy+box.y0+12);
198     bbc_drawby(0,-20);
199     bbc_drawby(-20,0);
200   }
201 }
202
203 #undef HW
204
205 /*
206  * void window__redrawDragBox(glass_windPointer *w,
207  *                            wimp_redrawstr *r,
208  *                            int x,
209  *                            int y)
210  *
211  * Use
212  *  Redraws the screen during a drag operation, either to update the window
213  *  during the drag, or to redraw the window should something silly happen
214  *  to it.
215  *
216  * Parameters
217  *  glass_windPointer *w == pointer to the window owning drag
218  *  wimp_redrawstr *r == pointer to current redraw
219  *  int x,int y == coordinates to draw drag relative to...
220  */
221
222 void window__redrawDragBox(glass_windPointer *w,wimp_redrawstr *r,
223                            int x,int y)
224 {
225   int ox=r->box.x0-r->scx;
226   int oy=r->box.y1-r->scy;
227   int i;
228   wimp_box box;
229   int bw;
230   int bh;
231   int type=window__qDragType();
232   int sx,sy;
233
234   /* --- If we don't know which window to draw in, don't --- */
235
236   if (!window__dragWind())
237     return;
238
239   /* --- Work out what we have to draw --- */
240
241   window__dragStart(&sx,&sy);
242   switch (type)
243   {
244
245     /* --- A selection box -- draw a rubber rectangle --- */
246
247     case window__SELECT:         /* Drag out a box to select icons         */
248       window__rectangle(sx+ox,sy+oy,x-sx,y-sy);
249       break;
250
251     /* --- We're grabbing an icon, so this is like a move --- *
252      *
253      * We can't actually use the main move code, because it works on all
254      * selected icons, and the one we're drawing doesn't actually exist as
255      * such.
256      */
257
258     case window__GRABICON:
259       box=window__qDragBox();
260       box.y1+=y-sy;
261       box.y0+=y-sy;
262       box.x0+=x-sx;
263       box.x1+=x-sx;
264       window__rectangle(ox+box.x0,
265                         oy+box.y0,
266                         box.x1-box.x0-wimpt_dx(),
267                         box.y1-box.y0-wimpt_dy());
268       break;
269
270     /* --- Guidelines moving -- draw all the guides which are moving --- */
271
272     case window__HORGUIDE:
273       for (i=0;i<glass_GUIDELIMIT;i++)
274       {
275         if (w->guide[i].active && w->guide[i].selected && w->guide[i].horiz)
276         {
277           bbc_plot(bbc_DottedBoth+bbc_MoveCursorAbs,
278                    ox+w->def->desc.w.ex.x0,
279                    oy+w->guide[i].coord+y-sy);
280           bbc_plot(bbc_DottedBoth+bbc_DrawAbsFore,
281                    ox+w->def->desc.w.ex.x1,
282                    oy+w->guide[i].coord+y-sy);
283         }
284       }
285       break;
286     case window__VERGUIDE:
287       for (i=0;i<glass_GUIDELIMIT;i++)
288       {
289         if (w->guide[i].active && w->guide[i].selected && !w->guide[i].horiz)
290         {
291           bbc_plot(bbc_DottedBoth+bbc_MoveCursorAbs,
292                    ox+w->guide[i].coord+x-sx,
293                    oy+w->def->desc.w.ex.y0);
294           bbc_plot(bbc_DottedBoth+bbc_DrawAbsFore,
295                    ox+w->guide[i].coord+x-sx,
296                    oy+w->def->desc.w.ex.y1);
297         }
298       }
299       break;
300
301     /* --- Normal icon moves/resizes --- *
302      *
303      * We find out where the box is according to the drag-type bitfield,
304      * and draw that for each selected icon.
305      */
306
307     default:
308       for (i=0;i<w->def->desc.w.nicons;i++)
309       {
310         if (w->def->i[i].selected)
311         {
312           window_boundingBox(w,i,&box);
313           bw=(w->def->i[i].i.box.x0-box.x0) + (box.x1-w->def->i[i].i.box.x1);
314           bh=(w->def->i[i].i.box.y0-box.y0) + (box.y1-w->def->i[i].i.box.y1);
315
316           /* --- Adjust coordinates according to drag type --- */
317
318           if (type & window__TOP)
319             box.y1+=y-sy;
320           if (type & window__BOTTOM)
321             box.y0+=y-sy;
322           if (type & window__LEFT)
323             box.x0+=x-sx;
324           if (type & window__RIGHT)
325             box.x1+=x-sx;
326
327           /* --- Ensure that the box is not inside-out --- */
328
329           if (type & window__TOP)
330           {
331             if (box.y1-box.y0<bh)
332               box.y1=box.y0+bh;
333           }
334           if (type & window__BOTTOM)
335           {
336             if (box.y1-box.y0<bh)
337               box.y0=box.y1-bh;
338           }
339           if (type & window__LEFT)
340           {
341             if (box.x1-box.x0<bw)
342               box.x0=box.x1-bw;
343           }
344           if (type & window__RIGHT)
345           {
346             if (box.x1-box.x0<bw)
347               box.x1=box.x0+bw;
348           }
349
350           window__rectangle(ox+box.x0,
351                             oy+box.y0,
352                             box.x1-box.x0-wimpt_dx(),
353                             box.y1-box.y0-wimpt_dy());
354         }
355       }
356       break;
357   }
358 }
359
360 /*
361  * void window__redraw(glass_windPointer *w,wimp_redrawstr *r,BOOL *more)
362  *
363  * Use
364  *  Redraws a window following a call to Wimp_UpdateWindow or
365  *  Wimp_RedrawWindow.
366  *
367  * Parameters
368  *  glass_windPointer *w == the window to draw
369  *  wimp_redrawstr *r == stuff about the redraw
370  *  BOOL *more == whether there is more to do
371  */
372
373 void window__redraw(glass_windPointer *w,wimp_redrawstr *r,BOOL *more)
374 {
375   int i;
376   os_regset reg;
377   int xx;
378   int yy;
379   int XX;
380   int YY;
381   int xd;
382   int x;
383   int y;
384   int ox=r->box.x0-r->scx;
385   int oy=r->box.y1-r->scy;
386
387   /* --- Make Sculptrix use the right sprite area --- */
388
389   sculptrix_setSpriteArea(w->t->s);
390
391   /* --- Do the redraw for each rectangle the WIMP gives us --- */
392
393   while (*more)
394   {
395
396     /* --- Draw the grid --- */
397
398     if (w->gridShow
399   #ifndef glass_DEMO
400     && !w->testMode
401   #endif
402     )
403     {
404       xx=((r->g.x0-ox)/w->gridx)*w->gridx-w->gridx;
405       yy=((r->g.y0-oy)/w->gridy)*w->gridy-w->gridy;
406       XX=((r->g.x1-ox)/w->gridx)*w->gridx+w->gridx;
407       YY=((r->g.y1-oy)/w->gridy)*w->gridy+w->gridy;
408       wimp_setcolour(gPrefs_current()->gGridCol);
409       if (gPrefs_current()->gLines)
410       {
411         for (x=xx;x<=XX;x+=w->gridx)
412         {
413           bbc_move(x+ox,yy+oy);
414           bbc_draw(x+ox,YY+oy);
415         }
416         for (y=yy;y<=YY;y+=w->gridy)
417         {
418           bbc_move(xx+ox,y+oy);
419           bbc_draw(XX+ox,y+oy);
420         }
421       }
422       else
423       {
424         for (x=xx;x<=XX;x+=w->gridx)
425         {
426           for (y=yy;y<=YY;y+=w->gridy)
427             bbc_plot(bbc_Point+bbc_DrawAbsFore,x+ox,y+oy);
428         }
429       }
430     }
431
432     /* --- Draw guidelines --- */
433
434   #ifndef glass_DEMO
435     if (!w->testMode)
436   #endif
437     {
438       for (i=0;i<glass_GUIDELIMIT;i++)
439       {
440         if (w->guide[i].active)
441         {
442           if (w->guide[i].selected)
443           {
444             wimp_setcolour(window__GDESELCOL);
445             window__makeDashPattern(0xff);
446           }
447           else
448           {
449             wimp_setcolour(window__GUIDECOL);
450             window__makeDashPattern(0x33);
451           }
452           if (w->guide[i].horiz)
453           {
454             bbc_plot(bbc_DottedBoth+bbc_MoveCursorAbs,
455                      ox+w->def->desc.w.ex.x0,
456                      oy+w->guide[i].coord);
457             bbc_plot(bbc_DottedBoth+bbc_DrawAbsFore,
458                      ox+w->def->desc.w.ex.x1,
459                      oy+w->guide[i].coord);
460           }
461           else
462           {
463             bbc_plot(bbc_DottedBoth+bbc_MoveCursorAbs,
464                      ox+w->guide[i].coord,
465                      oy+w->def->desc.w.ex.y0);
466             bbc_plot(bbc_DottedBoth+bbc_DrawAbsFore,
467                      ox+w->guide[i].coord,
468                      oy+w->def->desc.w.ex.y1);
469           }
470         }
471       }
472     }
473
474     /* --- Draw the hatch pattern, if applicable --- */
475
476     if (gPrefs_current()->mDrawHatch &&
477         !(w->def->desc.w.flags & wimp_REDRAW_OK))
478     {
479       wimpt_noerr(wimp_setcolour(w->def->desc.w.colours[2]));
480       xx=((r->g.x0-ox)/48)*48-48;
481       yy=((r->g.y0-oy)/48)*48-48;
482       XX=((r->g.x1-ox)/48)*48+48;
483       YY=((r->g.y1-oy)/48)*48+48;
484       xd=YY-yy;
485       for (x=xx-xd;x<=XX;x+=48)
486       {
487         bbc_move(x+ox,yy+oy);
488         bbc_draw(x+ox+xd,YY+oy);
489         bbc_move(x+ox+xd,yy+oy);
490         bbc_draw(x+ox,YY+oy);
491       }
492     }
493
494     /* --- If in test mode, draw 3D bits, and skip icon rendering --- */
495
496   #ifndef glass_DEMO
497     if (w->testMode)
498     {
499       if (gPrefs_current()->sDispBorders)
500         sculptrix_redrawWindow(r);
501       if (gPrefs_current()->iDispBorders)
502         interface_render3dWindow(r);
503       if (gPrefs_current()->wDispBorders)
504       {
505         reg.r[1]=(int)r;
506         os_swix(XWimpExt_Redraw,&reg);
507       }
508       wimpt_noerr(wimp_get_rectangle(r,more));
509       continue;
510     }
511   #endif
512
513     /* --- Otherwise, translate coordinates for optimisation --- *
514      *
515      * We also bodge the rectangle a bit to include 3D borders.  This is
516      * to avoid really very slow redrawing in big windows, where we have to
517      * pass each validation string to each of 3 modules to be parsed before
518      * rendering...
519      *
520      * If this goes seriously wrong, blame someone else.  The worst that is
521      * likely to happen is that some *seriously* large borders don't get
522      * drawn all the time.
523      */
524
525     coords_box_toworkarea(&r->g,(coords_cvtstr *)&(r->box));
526     r->g.x0-=16;
527     r->g.y0-=32;
528     r->g.x1+=16;
529     r->g.y1+=16;
530
531     /* --- Plot 3D borders --- */
532
533     if (gPrefs_current()->iDispBorders ||
534         gPrefs_current()->wDispBorders ||
535         gPrefs_current()->sDispBorders)
536     {
537       for (i=0;i<w->def->desc.w.nicons;i++) /* Plot 3D borders first     */
538       {
539         if (!(w->def->i[i].i.flags & wimp_IDELETED) &&
540             coords_boxesoverlap(&w->def->i[i].i.box,&r->g))
541         {
542           if (gPrefs_current()->sDispBorders)
543             sculptrix_plotIcon(&w->def->i[i].i,r);
544           if (gPrefs_current()->iDispBorders)
545           {
546             reg.r[1]=(int)&(w->def->i[i].i);
547             reg.r[0]=(int)r;
548             os_swix(XInterface_Plot3dIcon,&reg);
549           }
550           if (gPrefs_current()->wDispBorders)
551           {
552             reg.r[1]=(int)&(w->def->i[i].i);
553             reg.r[0]=0;
554             reg.r[2]=w->h;
555             os_swix(XWimpExt_PlotBorder,&reg);
556           }
557         }
558       }
559     }
560
561     /* --- Plot the actual icons on top of everything --- */
562
563     for (i=0;i<w->def->desc.w.nicons;i++) /* And then the icons            */
564     {
565       if (!(w->def->i[i].i.flags & wimp_IDELETED) &&
566           coords_boxesoverlap(&w->def->i[i].i.box,&r->g))
567         wimp_ploticon(&(w->def->i[i].i));
568     }
569
570     /* --- Now temporary things (drawn in XOR mode) --- *
571      *
572      * The actual order of these is not important, seeing as the XOR nicely
573      * over each other, and XOR as we all know is commutative.
574      */
575
576     /* --- Bodge the graphics box to fit in the selection boxen --- */
577
578     r->g.x0-=window__HANDLEWIDTH+8;
579     r->g.y0-=window__HANDLEWIDTH+8;
580     r->g.x1+=window__HANDLEWIDTH+8;
581     r->g.y1+=window__HANDLEWIDTH+8;
582
583     /* --- Draw select boxes --- */
584
585     for (i=0;i<w->def->desc.w.nicons;i++) /* Select boxes...               */
586     {
587       if (w->def->i[i].selected)
588       {
589         if (coords_boxesoverlap(&w->def->i[i].i.box,&r->g))
590           window__drawSelectBox(w,i,FALSE,r);
591       }
592     }
593
594     /* --- Any drag boxen --- */
595
596     if (window__qDragType()!=-1 && w==window__dragWind())
597     {
598       window__rotate(0);
599       window__dragCoords(&x,&y);
600       window__redrawDragBox(w,r,x,y);
601     }
602
603     /* --- Get more rectangles from the WIMP --- */
604
605     wimpt_noerr(wimp_get_rectangle(r,more)); /* Get next bit to draw       */
606   }
607 }
608
609 /*
610  * void window_redrawIcon(glass_windPointer *w,int icon)
611  *
612  * Use
613  *  Sets the WIMP up to call for a redraw of the spcified icon (i.e. it
614  *  uses Wimp_ForceRedraw).
615  *
616  * Parameters
617  *  glass_windPointer *w == pointer to the window owning the icon
618  *  int icon == the icon to redraw
619  */
620
621 void window_redrawIcon(glass_windPointer *w,int icon)
622 {
623   wimp_redrawstr r;
624   if (!w->h)
625     return;
626   r.w=w->h;
627   window__bound(&w->def->i[icon].i,&r.box,TRUE);
628   r.box.x0-=window__HANDLEWIDTH+4;
629   r.box.x1+=window__HANDLEWIDTH+4;
630   r.box.y0-=window__HANDLEWIDTH+4;
631   r.box.y1+=window__HANDLEWIDTH+4;
632   wimpt_noerr(wimp_force_redraw(&r));
633   if (w==window_selectionOwner() && icon==window__selectedIcon())
634     tearEdit_update(w,icon);
635   window__updateMenu(w);
636 }
637
638 /*
639  * void window__redrawGuide(glass_windPointer *w,int guide)
640  *
641  * Use
642  *  Forces a redraw of the specified guideline.
643  *
644  * Parameters
645  *  glass_windPointer *w == the window containing the guideline
646  *  int guide == the number of the guideline.
647  */
648
649 void window__redrawGuide(glass_windPointer *w,int guide)
650 {
651   wimp_wstate s;
652   wimp_redrawstr r;
653
654   /* --- Force a redraw of the guideline --- *
655    *
656    * We can't realistically use Wimp_UpdateWindow because the guidelines are
657    * drawn over by everything else.  So all we do is leave a bit of the
658    * window marked as invalid, and wait for the redraw event a bit later.
659    */
660
661   wimpt_noerr(wimp_get_wind_state(w->h,&s));
662   r.w=w->h;
663   if (w->guide[guide].horiz)
664   {
665     r.box.x0=s.o.x;
666     r.box.y0=w->guide[guide].coord;
667     r.box.x1=s.o.x+s.o.box.x1-s.o.box.x0;
668     r.box.y1=w->guide[guide].coord+wimpt_dy();
669   }
670   else
671   {
672     r.box.y1=s.o.y;
673     r.box.x0=w->guide[guide].coord;
674     r.box.y0=s.o.y-s.o.box.y1+s.o.box.y0;
675     r.box.x1=w->guide[guide].coord+wimpt_dx();
676   }
677   wimpt_noerr(wimp_force_redraw(&r));
678 }