chiark / gitweb /
Initial revision
[ssr] / StraySrc / Libraries / Steel / c / template
1 /*
2  * template.c
3  *
4  * Loading and manipulation of window templates
5  *
6  * © 1994-1998 Straylight
7  */
8
9 /*----- Licensing note ----------------------------------------------------*
10  *
11  * This file is part of Straylight's Steel library.
12  *
13  * Steel 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  * Steel 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 Steel.  If not, write to the Free Software Foundation,
25  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26  */
27
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31
32 #include "os.h"
33 #include "wimp.h"
34 #include "utils.h"
35 #include "template.h"
36 #include "dll.h"
37 #include "mem.h"
38 #include "font.h"
39 #include "msgs.h"
40 #include "werr.h"
41 #include "res.h"
42 #include "resspr.h"
43
44 /*----- Note to the reader ------------------------------------------------*
45  *
46  * This code makes no use of Wimp_LoadTemplate at all.  It's modified from
47  * the Glass template loading code, which as we all know is no slouch.
48  */
49
50 /*----- Variables ---------------------------------------------------------*/
51
52 static template *template__all;
53 static char template__fonts[256];
54 static BOOL template__usingFonts;
55
56 /*----- Main code ---------------------------------------------------------*/
57
58 #ifndef _dll_NODLL
59   extern void _dllEntry(template__exit)(void);
60 #endif
61
62 /*
63  * int template__cmp(char *a,char *b)
64  *
65  * Use
66  *  Compares two strings of length 12 or less.
67  */
68
69 static int template__cmp(char *a,char *b)
70 {
71   int i;
72   for (i=0;i<12;i++)
73   {
74     if (*a<32 && *b<32)
75       return (0);
76     if (*a!=*b)
77       return (*a-*b);
78     a++;
79     b++;
80   }
81   return (0);
82 }
83
84 /*
85  * template *template_copy(template *from)
86  *
87  * Use
88  *  Copies a template field-for-field and fixes up new indirected data for
89  *  it.
90  */
91
92 template *template_copy(template *from)
93 {
94   template *t;
95   wimp_icon *ic;
96   int i;
97   int size=sizeof(template)+from->window.nicons*sizeof(wimp_icon);
98
99   /* --- Allocate a new template block and copy --- */
100
101   t=mem_alloc(size);
102   if (!t)
103     return (0);
104   memcpy(t,from,size);
105
106   /* --- Allocate a new indirected space block and copy that too --- */
107
108   if (!from->workspace)
109     return(t);
110
111   t->workspace=mem_alloc(t->workspacesize);
112   if (!t->workspace)
113   {
114     mem_free(t);
115     return (0);
116   }
117   memcpy(t->workspace,from->workspace,t->workspacesize);
118
119   /* --- Fix up all the indirected pointers --- */
120
121   if (t->window.titleflags & wimp_INDIRECT)
122   {
123     t->window.title.indirecttext.buffer+=t->workspace-from->workspace;
124     if (t->window.titleflags & wimp_ITEXT &&
125         t->window.title.indirecttext.validstring!=(char *)-1)
126       t->window.title.indirecttext.validstring+=t->workspace-from->workspace;
127   }
128
129   /* --- And for the icons --- */
130
131   ic=(wimp_icon *)(t+1);
132   for (i=0;i<t->window.nicons;i++)
133   {
134     if (ic->flags & wimp_INDIRECT)
135     {
136       ic->data.indirecttext.buffer+=t->workspace-from->workspace;
137       if (ic->flags & wimp_ITEXT &&
138           ic->data.indirecttext.validstring!=(char *)-1)
139         ic->data.indirecttext.validstring+=t->workspace-from->workspace;
140     }
141     ic++;
142   }
143
144   return (t);
145 }
146
147 /*
148  * void template__exit(void)
149  *
150  * Use
151  *  Closes down all the fonts loaded with templates
152  */
153
154 _dll_static void template__exit(void)
155 {
156   int i,j;
157   for (i=0;i<256;i++)
158   {
159     for (j=0;j<template__fonts[i];j++)
160       font_lose(i);
161   }
162 }
163
164 /*
165  * BOOL template_readfile(char *name)
166  *
167  * Use
168  *  Loads the template file named into memory, and sorts out all its
169  *  indirected data.
170  *
171  *  Template entries with strange identifiers are ignored.  Other entry
172  *  types may be supported later.
173  *
174  * Parameters
175  *  char *name == the name of the template file to load (a resource file)
176  *
177  * Returns
178  *  FALSE if the file contained no sprite icons.  No, I don't understand
179  *  the use of this either.  It's not my problem though.  I just write the
180  *  code.
181  */
182
183 /* --- Macros from Glass's gStruct.h to help read the structure --- */
184
185 #define intptr(flex,offset) \
186   ((int *)(((char *)(flex))+(offset)))
187 #define charptr(flex,offset) \
188   (((char *)(flex))+(offset))
189 #define _ptr(type,flex,offset) \
190   ((type *)(((char *)(flex))+(offset)))
191
192 BOOL template_readfile(char *file)
193 {
194   /* --- Variables for loading the file --- */
195
196   char *filebuf;
197   os_filestr f;
198
199   /* --- Variables for mangling the file in memory --- */
200
201   int fontData;                  /* Offset of font ata from start of file  */
202   template *w;                   /* For each window we come across         */
203   int datasize;                  /* Size of indirected data for the window */
204   char *p=0;                     /* Offset in indirected data for next item*/
205   char *q;                       /* Pointer to an indirected string        */
206   int index;                     /* Current index entry we're looking at   */
207   char name[13];                 /* For the name of the template           */
208   int objoff;                    /* Offset of window we're looking at      */
209   wimp_icon *iconptr;            /* Offset of icon we're looking at        */
210   wimp_iconflags icf;            /* Icon flags for something or other      */
211   int objtype;                   /* Type of current template entry         */
212   int numicons;                  /* Number of icons in a window            */
213   int i;                         /* A loop counter                         */
214   int pass;                      /* We take two passes at each window      */
215
216   /* --- Font handling --- */
217
218   int fheight;                   /* Height of a font required              */
219   int fwidth;                    /* Width of a font required               */
220   int fhandle;                   /* Font handle                            */
221   int fptr;                      /* Offset of font name                    */
222   BOOL fquiet=FALSE;             /* Shut up about font failures.           */
223
224   /* --- Load the file into memory --- */
225
226   f.action=17;
227   f.name=file;
228   if (utils_complain(os_file(&f),
229       msgs_lookup("templateELF:Error loading template file: '%s'")))
230   {
231     exit(1);
232   }
233
234   filebuf=mem_alloc(f.start);
235   if (!f.start)
236   {
237     werr(FALSE,msgs_lookup("templateNEM:Not enough memory "
238                            "to load template file."));
239     exit(1);
240   }
241
242   f.action=16;
243   f.loadaddr=(int)filebuf;
244   f.execaddr=0;
245   if (utils_complain(os_file(&f),
246       msgs_lookup("templateELF:Error loading template file: '%s'")))
247   {
248     exit(1);
249   }
250
251   /* --- Now start parsing up the file structure --- */
252
253   fontData=*intptr(filebuf,0);
254
255   /* --- Loop through each index entry in turn --- */
256
257   for (index=16;*intptr(filebuf,index);index+=24)
258   {
259     /* --- Find this entry's location in the file --- */
260
261     objoff=*intptr(filebuf,index);
262     objtype=*intptr(filebuf,index+8);
263
264     /* --- Mangle it according to its type --- */
265
266     switch (objtype)
267     {
268       case 1:
269
270         /* --- Find the name of the window and its number of icons --- */
271
272         memcpy(name,charptr(filebuf,index+12),12);
273         name[12]=0;
274         utils_ctermToNterm(name);
275         memcpy(&numicons,intptr(filebuf,objoff+84),sizeof(int));
276
277         /* --- Allocate a template block for it --- */
278
279         datasize=sizeof(template)+numicons*sizeof(wimp_icon);
280         w=mem_alloc(datasize);
281         if (!w)
282         {
283           werr(FALSE,msgs_lookup("templateNEM:Not enough memory "
284                                  "to load template file."));
285           exit(1);
286         }
287
288         /* --- Copy the template data into this block --- */
289
290         memcpy(&w->window,
291                _ptr(void,filebuf,objoff),
292                sizeof(wimp_wind)+numicons*sizeof(wimp_icon));
293
294         /* --- Set up the window's sprite area --- */
295
296         w->window.spritearea=resspr_area();
297
298         /* --- Now perform the two passes on the window data --- */
299
300         datasize=0;
301         for (pass=1;pass<=2;pass++)
302         {
303           icf=w->window.titleflags;
304
305           /* --- Handle title indirected data --- */
306
307           if (icf & wimp_INDIRECT)
308           {
309             if (pass==1)
310             {
311               /* --- Pass 1 just counts the size we need --- */
312
313               q=(int)w->window.title.indirecttext.buffer+filebuf+objoff;
314               utils_ctermToNterm(q);
315               datasize+=w->window.title.indirecttext.bufflen;
316               if (icf & wimp_ITEXT &&
317                   w->window.title.indirecttext.validstring!=(char *)-1)
318               {
319                 q=(int)w->window.title.indirecttext.validstring+
320                   filebuf+
321                   objoff;
322                 utils_ctermToNterm(q);
323                 datasize+=strlen(q)+1;
324               }
325             }
326             else
327             {
328               q=(int)w->window.title.indirecttext.buffer+filebuf+objoff;
329               memcpy(p,q,w->window.title.indirecttext.bufflen);
330               w->window.title.indirecttext.buffer=p;
331               p+=w->window.title.indirecttext.bufflen;
332               if (icf & wimp_ITEXT &&
333                   w->window.title.indirecttext.validstring!=(char *)-1)
334               {
335                 q=(int)w->window.title.indirecttext.validstring+
336                   filebuf+
337                   objoff;
338                 strcpy(p,q);
339                 w->window.title.indirecttext.validstring=p;
340                 p+=strlen(q)+1;
341               }
342             }
343           }
344
345           /* --- Cope with antialiasing on the second pass --- */
346
347           if ((icf & wimp_IFONT) && pass==2)
348           {
349             /* --- Get the font handle --- */
350
351             fhandle=(icf & 0xff000000) >> 24;
352
353             /* --- Find information about the font --- */
354
355             fptr=fontData+(fhandle-1)*48;
356             memcpy(&fwidth,intptr(filebuf,fptr)+0,sizeof(int));
357             memcpy(&fheight,intptr(filebuf,fptr)+1,sizeof(int));
358             utils_ctermToNterm(charptr(filebuf,fptr+8));
359
360             /* --- Get a real font like this --- */
361
362             if (font_find(charptr(filebuf,fptr+8),
363                           fwidth,
364                           fheight,
365                           0,0,
366                           &fhandle))
367             {
368               if (!fquiet)
369               {
370                 werr(FALSE,msgs_lookup("templateCFF:Some fonts used in this "
371                                        "template file could not be found.  "
372                                        "Icons with such fonts will not be "
373                                        "anti-aliased."));
374                 fquiet=TRUE;
375               }
376               icf&=~wimp_IFONT;
377             }
378             else
379             {
380               icf=(icf & 0x00ffffff) | (fhandle << 24);
381               template__fonts[fhandle]++;
382               if (!template__usingFonts)
383               {
384                 atexit(_dllEntry(template__exit));
385                 template__usingFonts=TRUE;
386               }
387             }
388             w->window.titleflags=icf;
389           }
390
391           /* --- Now handle each icon in turn like this --- */
392
393           iconptr=(wimp_icon *)(w+1);
394           for (i=0;i<numicons;i++)
395           {
396             icf=iconptr->flags;
397
398             /* --- Handle title indirected data --- */
399
400             if (icf & wimp_INDIRECT)
401             {
402               if (pass==1)
403               {
404                 /* --- Pass 1 just counts the size we need --- */
405
406                 q=(int)iconptr->data.indirecttext.buffer+filebuf+objoff;
407                 utils_ctermToNterm(q);
408                 datasize+=iconptr->data.indirecttext.bufflen;
409                 if (icf & wimp_ITEXT &&
410                     iconptr->data.indirecttext.validstring!=(char *)-1)
411                 {
412                   q=(int)iconptr->data.indirecttext.validstring+
413                     filebuf+
414                     objoff;
415                   utils_ctermToNterm(q);
416                   datasize+=strlen(q)+1;
417                 }
418               }
419               else
420               {
421                 q=(int)iconptr->data.indirecttext.buffer+filebuf+objoff;
422                 memcpy(p,q,iconptr->data.indirecttext.bufflen);
423                 iconptr->data.indirecttext.buffer=p;
424                 p+=iconptr->data.indirecttext.bufflen;
425                 if (icf & wimp_ITEXT &&
426                     iconptr->data.indirecttext.validstring!=(char *)-1)
427                 {
428                   q=(int)iconptr->data.indirecttext.validstring+
429                     filebuf+
430                     objoff;
431                   strcpy(p,q);
432                   iconptr->data.indirecttext.validstring=p;
433                   p+=strlen(q)+1;
434                 }
435               }
436             }
437
438             /* --- Cope with antialiasing on the second pass --- */
439
440             if ((icf & wimp_IFONT) && pass==2)
441             {
442               /* --- Get the font handle --- */
443
444               fhandle=(icf & 0xff000000) >> 24;
445
446               /* --- Find information about the font --- */
447
448               fptr=fontData+(fhandle-1)*48;
449               memcpy(&fwidth,intptr(filebuf,fptr)+0,sizeof(int));
450               memcpy(&fheight,intptr(filebuf,fptr)+1,sizeof(int));
451               utils_ctermToNterm(charptr(filebuf,fptr+8));
452
453               /* --- Get a real font like this --- */
454
455               if (font_find(charptr(filebuf,fptr+8),
456                             fwidth,
457                             fheight,
458                             0,0,
459                             &fhandle))
460               {
461                 if (!fquiet)
462                 {
463                   werr(FALSE,msgs_lookup("templateCFF:Some fonts used in "
464                                          "this template file could not be "
465                                          "found.  Icons with such fonts "
466                                          "will not be anti-aliased."));
467                   fquiet=TRUE;
468                 }
469                 icf&=~wimp_IFONT;
470               }
471               else
472               {
473                 icf=(icf & 0x00ffffff) | (fhandle << 24);
474                 template__fonts[fhandle]++;
475                 if (!template__usingFonts)
476                 {
477                   atexit(_dllEntry(template__exit));
478                   template__usingFonts=TRUE;
479                 }
480               }
481               iconptr->flags=icf;
482             }
483             iconptr++;
484           }
485
486           /* --- Finish off the pass properly now --- */
487
488           if (pass==1)
489           {
490             /* --- Allocate the right amount of indirected space --- */
491
492             w->workspacesize=datasize;
493             if (datasize)
494             {
495               w->workspace=mem_alloc(datasize);
496               if (!w->workspace)
497               {
498                 werr(FALSE,msgs_lookup("templateNEM:Not enough memory "
499                                        "to load template file."));
500                 exit(1);
501               }
502             }
503             else
504               w->workspace=0;
505             p=w->workspace;
506           }
507           else
508           {
509             /* --- Link the filled in structure into the list --- */
510
511             w->next=template__all;
512             template__all=w;
513
514             /* --- Fill in the name of the template --- */
515
516             memcpy(w->name,name,12);
517           }
518         }
519         break;
520     }
521   }
522
523   /* --- Finished -- return to the user --- */
524
525   mem_free(filebuf);
526   return (TRUE);                     /* It can't do any harm, now, can it? */
527 }
528
529 /*
530  * void template_init(void)
531  *
532  * Use
533  *  Loads the application's `Templates' file.
534  */
535
536 void template_init(void)
537 {
538   template_readfile(res_name("Templates"));
539 }
540
541 /*
542  * void template_use_fancyfonts(void)
543  *
544  * Use
545  *  Does absolutely nothing at all.  Fancy font support happens anyway.
546  */
547
548 void template_use_fancyfonts(void)
549 {
550   /* Do absolutely nothing at all :-) */
551 }
552
553 /*
554  * BOOL template_exists(char *name)
555  *
556  * Use
557  *  Returns TRUE if the named template is known at the moment, or FALSE
558  *  otherwise
559  */
560
561 BOOL template_exists(char *name)
562 {
563   template *t=template__all;
564   while (t)
565   {
566     if (!template__cmp(name,t->name))
567       return (TRUE);
568     t=t->next;
569   }
570   return (FALSE);
571 }
572
573 /*
574  * template *template_find(char *name)
575  *
576  * Use
577  *  Locates a named template and returns a pointer to it
578  */
579
580 template *template_find(char *name)
581 {
582   template *t=template__all;
583   while (t)
584   {
585     if (!template__cmp(name,t->name))
586       return (t);
587     t=t->next;
588   }
589   werr(TRUE,msgs_lookup("templateNF:Template '%s' not found"),name);
590   return (0); /* FWIW */
591 }
592
593 /*
594  * wimp_wind *template_syshandle(char *name)
595  *
596  * Use
597  *  Not very much, if the truth be known.  It returns a pointer to a named
598  *  window definition.
599  */
600
601 wimp_wind *template_syshandle(char *name)
602 {
603   return (&template_find(name)->window);
604 }
605
606 /*
607  * BOOL template_loaded(void)
608  *
609  * Use
610  *  Returns TRUE if we have templates on board.
611  */
612
613 BOOL template_loaded(void)
614 {
615   return (template__all ? TRUE : FALSE);
616 }