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 }