2 Copyright 1999, David Le Corfec.
3 Copyright 2002-2007, The AROS Development Team.
9 /* This is the implementation of a MUI-like image engine
10 * (see MUIA_Image_Spec for more information about MUI image specs)
11 * Their external form is a string "<type>:<parameters>"
12 * with type being a single char. See zune_image_spec_to_structure().
14 * Basically an ImageSpec can be anything which can be displayed:
15 * gfx datas, drawing code, ...
16 * See ImageSpecType for the known types.
23 #include <exec/types.h>
24 #include <exec/memory.h>
26 #include <graphics/gfxmacros.h>
28 #include <proto/exec.h>
29 #include <proto/graphics.h>
30 #include <proto/intuition.h>
31 #include <proto/dos.h>
32 #include <clib/alib_protos.h>
39 #include "datatypescache.h"
43 #include "muimaster_intern.h"
46 #include "imspec_intern.h"
48 extern struct Library
*MUIMasterBase
;
50 static struct MUI_ImageSpec_intern
*get_brush_imspec(CONST_STRPTR filename
);
52 const static UWORD gridpattern1
[] = {
57 const static UWORD gridpattern2
[] = {
68 const static MPattern patternPens
[] = {
69 { MPEN_SHADOW
, MPEN_BACKGROUND
, gridpattern1
}, /* MUII_SHADOWBACK */
70 { MPEN_SHADOW
, MPEN_FILL
, gridpattern1
}, /* MUII_SHADOWFILL */
71 { MPEN_SHADOW
, MPEN_SHINE
, gridpattern1
}, /* MUII_SHADOWSHINE */
72 { MPEN_FILL
, MPEN_BACKGROUND
, gridpattern1
}, /* MUII_FILLBACK */
73 { MPEN_FILL
, MPEN_SHINE
, gridpattern1
}, /* MUII_FILLSHINE */
74 { MPEN_SHINE
, MPEN_BACKGROUND
, gridpattern1
}, /* MUII_SHINEBACK */
75 { MPEN_FILL
, MPEN_BACKGROUND
, gridpattern2
}, /* MUII_FILLBACK2 */
76 { MPEN_HALFSHINE
, MPEN_BACKGROUND
, gridpattern1
}, /* MUII_HSHINEBACK */
77 { MPEN_HALFSHADOW
, MPEN_BACKGROUND
, gridpattern1
}, /* MUII_HSHADOWBACK */
78 { MPEN_HALFSHINE
, MPEN_SHINE
, gridpattern1
}, /* MUII_HSHINESHINE */
79 { MPEN_HALFSHADOW
, MPEN_SHADOW
, gridpattern1
}, /* MUII_HSHADOWSHADOW */
80 { MPEN_MARK
, MPEN_SHINE
, gridpattern1
}, /* MUII_MARKSHINE */
81 { MPEN_MARK
, MPEN_HALFSHINE
, gridpattern1
}, /* MUII_MARKHALFSHINE */
82 { MPEN_MARK
, MPEN_BACKGROUND
, gridpattern1
}, /* MUII_MARKBACKGROUND */
85 #define PATTERN_COUNT (MUII_LASTPAT - MUII_BACKGROUND + 1)
87 static struct MUI_ImageSpec_intern
*get_pattern_imspec(LONG in
)
89 struct MUI_ImageSpec_intern
*spec
= NULL
;
91 if (in
>= MUII_BACKGROUND
&& in
<= MUII_FILL
)
93 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
96 if (in
== MUII_BACKGROUND
) color
= MPEN_BACKGROUND
;
97 else if (in
== MUII_SHADOW
) color
= MPEN_SHADOW
;
98 else if (in
== MUII_SHINE
) color
= MPEN_SHINE
;
99 else color
= MPEN_FILL
;
101 spec
->type
= IST_COLOR
;
102 zune_penspec_fill_muipen(&spec
->u
.penspec
, color
);
106 else if (in
>= MUII_SHADOWBACK
&& in
<= MUII_MARKBACKGROUND
)
108 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
110 spec
->type
= IST_PATTERN
;
111 spec
->u
.pattern
= in
- MUII_SHADOWBACK
;
119 static struct MUI_ImageSpec_intern
*get_pen_imspec(CONST_STRPTR str
)
121 struct MUI_ImageSpec_intern
*spec
;
123 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
125 if (!zune_pen_string_to_intern(str
, &spec
->u
.penspec
))
127 D(bug("*** zune_pen_string_to_intern failed\n"));
131 spec
->type
= IST_COLOR
;
137 static struct MUI_ImageSpec_intern
*get_scaled_gradient_imspec(CONST_STRPTR str
)
139 struct MUI_ImageSpec_intern
*spec
;
141 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
143 if (!zune_gradient_string_to_intern(str
, spec
))
145 D(bug("*** zune_gradient_string_to_intern failed\n"));
149 spec
->type
= IST_SCALED_GRADIENT
;
155 static struct MUI_ImageSpec_intern
*get_tiled_gradient_imspec(CONST_STRPTR str
)
157 struct MUI_ImageSpec_intern
*spec
;
159 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
161 if (!zune_gradient_string_to_intern(str
, spec
))
163 D(bug("*** zune_gradient_string_to_intern failed\n"));
167 spec
->type
= IST_TILED_GRADIENT
;
173 static struct MUI_ImageSpec_intern
*get_boopsi_imspec(CONST_STRPTR filename
)
175 struct MUI_ImageSpec_intern
*spec
;
179 if (!strstr(filename
, ".image"))
180 return get_brush_imspec(filename
);
182 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
184 spec
->u
.boopsi
.filename
= StrDup(filename
);
185 if (!spec
->u
.boopsi
.filename
)
187 spec
->u
.boopsi
.obj
= NULL
;
188 spec
->type
= IST_BOOPSI
;
195 static struct MUI_ImageSpec_intern
*get_brush_imspec(CONST_STRPTR filename
)
197 struct MUI_ImageSpec_intern
*spec
;
198 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
201 spec
->u
.brush
.filename
[0] = StrDup(filename
);
202 if (!spec
->u
.brush
.filename
[0])
204 last_idx
= strlen(spec
->u
.brush
.filename
[0]) - 1;
205 if (spec
->u
.brush
.filename
[0][last_idx
] == '0')
208 tmpstr
= StrDup(filename
);
211 FreeVec((APTR
)spec
->u
.brush
.filename
[0]);
214 tmpstr
[last_idx
] = '1';
215 spec
->u
.brush
.filename
[1] = tmpstr
;
217 spec
->u
.brush
.dt
[0] = NULL
;
218 spec
->u
.brush
.dt
[1] = NULL
;
219 spec
->type
= IST_BRUSH
;
226 static struct MUI_ImageSpec_intern
*get_bitmap_imspec(CONST_STRPTR filename
)
228 struct MUI_ImageSpec_intern
*spec
;
229 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
231 spec
->u
.bitmap
.filename
= StrDup(filename
);
232 if (!spec
->u
.bitmap
.filename
)
234 spec
->u
.bitmap
.dt
= NULL
;
235 spec
->type
= IST_BITMAP
;
242 static struct MUI_ImageSpec_intern
*get_config_imspec(LONG img
)
244 if ((img
>= MUII_WindowBack
) && (img
<= MUII_ReadListBack
))
246 struct MUI_ImageSpec_intern
*spec
;
247 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
249 spec
->u
.cfg
.muiimg
= img
;
250 spec
->type
= IST_CONFIG
;
259 static const char *zune_imspec_to_string(struct MUI_ImageSpec_intern
*spec
)
271 sprintf(buf
, "0:%ld", spec
->u
.pattern
);
275 sprintf(buf
, "1:%ld", spec
->u
.vect
.type
);
279 zune_pen_intern_to_spec(&spec
->u
.penspec
, (struct MUI_PenSpec
*)buf
);
283 sprintf(buf
, "3:%s", spec
->u
.boopsi
.filename
);
286 case IST_BRUSH
: /* this is really 3: too */
287 sprintf(buf
, "3:%s", spec
->u
.brush
.filename
[0]);
291 sprintf(buf
, "5:%s", spec
->u
.bitmap
.filename
);
295 sprintf(buf
, "6:%ld", spec
->u
.cfg
.muiimg
);
298 case IST_SCALED_GRADIENT
:
299 zune_scaled_gradient_intern_to_string(spec
, buf
);
302 case IST_TILED_GRADIENT
:
303 zune_tiled_gradient_intern_to_string(spec
, buf
);
310 /**************************************************************************
311 Create a image spec from a string or a magic value.
312 in : contains magic or string
313 obj: is a AreaObject. It is used to access the config data.
315 TODO: merge this with zune_imspec_setup() because this function should
316 be called in MUIM_Setup (configdata)
317 **************************************************************************/
318 static struct MUI_ImageSpec_intern
*zune_image_spec_to_structure(IPTR in
)
320 struct MUI_ImageSpec_intern
*spec
= NULL
;
323 if (in
>= MUII_WindowBack
&& in
<= MUII_ReadListBack
)
325 D(bug("zune_image_spec_to_structure [config] : in=%ld\n", in
));
326 spec
= get_config_imspec(in
);
328 else if (in
>= MUII_BACKGROUND
&& in
<= MUII_MARKBACKGROUND
)
330 D(bug("zune_image_spec_to_structure [pattern] : in=%ld\n", in
));
331 spec
= get_pattern_imspec(in
);
335 s
= (CONST_STRPTR
)in
;
336 D(bug("zune_image_spec_to_structure [string] : in=%s\n", s
));
340 case '0': /* builtin pattern */
343 StrToLong(s
+2, &pat
);
344 spec
= get_pattern_imspec(pat
);
348 case '1': /* builtin standard image, obsoleted by 6: */
351 StrToLong(s
+2, &vect
);
352 spec
= zune_imspec_create_vector(vect
);
356 case '2': /* a penspec */
357 spec
= get_pen_imspec(s
+2);
358 D(bug("zune_image_spec_to_structure : penspec %lx\n", &spec
->u
.penspec
));
361 case '3': /* BOOPSI image class name */
362 spec
= get_boopsi_imspec(s
+2);
365 case '4': /* external MUI brush name */
366 spec
= get_brush_imspec(s
+2);
369 case '5': /* external bitmap loaded with datatypes */
370 spec
= get_bitmap_imspec(s
+2);
373 case '6': /* preconfigured image or background */
376 StrToLong(s
+2, &img
);
378 if (img
>= MUII_WindowBack
&& img
<= MUII_ReadListBack
)
379 spec
= get_config_imspec(img
);
383 case '7': /* scaled gradient */
384 spec
= get_scaled_gradient_imspec(s
+2);
387 case '8': /* tiled gradient */
388 spec
= get_tiled_gradient_imspec(s
+2);
393 D(bug("zune_image_spec_to_structure : out=0x%lx [%s]\n",
394 spec
, zune_imspec_to_string(spec
)));
399 static struct MUI_ImageSpec_intern
*zune_imspec_copy(struct MUI_ImageSpec_intern
*spec
)
401 struct MUI_ImageSpec_intern
*nspec
;
403 if (!spec
) return NULL
;
405 nspec
= mui_alloc_struct(struct MUI_ImageSpec_intern
);
406 if (nspec
) memcpy(nspec
,spec
,sizeof(struct MUI_ImageSpec_intern
));
413 static void zune_imspec_free(struct MUI_ImageSpec_intern
*spec
)
417 D(bug("zune_imspec_free(0x%lx) [%s]\n",
418 spec
, zune_imspec_to_string(spec
)));
423 if (spec
->u
.boopsi
.filename
)
424 FreeVec((APTR
)spec
->u
.boopsi
.filename
);
428 if (spec
->u
.brush
.filename
[0])
429 FreeVec((APTR
)spec
->u
.brush
.filename
[0]);
430 if (spec
->u
.brush
.filename
[1])
431 FreeVec((APTR
)spec
->u
.brush
.filename
[1]);
435 if (spec
->u
.bitmap
.filename
)
436 FreeVec((APTR
)spec
->u
.bitmap
.filename
);
446 struct MUI_ImageSpec_intern
*zune_imspec_setup(IPTR s
, struct MUI_RenderInfo
*mri
)
448 struct MUI_ImageSpec_intern
*spec
;
452 D(bug("zune_imspec_setup: param error: mri=%p\n", mri
));
456 spec
= zune_image_spec_to_structure(s
);
458 D(bug("zune_imspec_setup(%lx) [%s]\n",
459 spec
, zune_imspec_to_string(spec
)));
472 zune_penspec_setup(&spec
->u
.penspec
, mri
);
482 for (i
= 0; i
< 2; i
++)
484 if (spec
->u
.brush
.filename
[i
])
486 spec
->u
.brush
.dt
[i
] = dt_load_picture
488 spec
->u
.brush
.filename
[i
], mri
->mri_Screen
491 if (!spec
->u
.brush
.dt
[i
] && !strchr(spec
->u
.brush
.filename
[i
], ':'))
496 size
= strlen(IMSPEC_EXTERNAL_PREFIX
)
497 + strlen(spec
->u
.brush
.filename
[i
]) + 1;
498 fullpath
= (STRPTR
)AllocVec(size
, MEMF_ANY
);
500 if (fullpath
!= NULL
)
502 strcpy(fullpath
, IMSPEC_EXTERNAL_PREFIX
);
503 strcat(fullpath
, spec
->u
.brush
.filename
[i
]);
504 fullpath
[size
- 1] = 0;
505 spec
->u
.brush
.dt
[i
] = dt_load_picture
507 fullpath
, mri
->mri_Screen
515 spec
->u
.brush
.dt
[i
] = spec
->u
.brush
.dt
[0];
522 if (spec
->u
.bitmap
.filename
)
524 spec
->u
.bitmap
.dt
= dt_load_picture
526 spec
->u
.bitmap
.filename
, mri
->mri_Screen
533 Object
*win
= mri
->mri_WindowObject
;
534 struct ZunePrefsNew
*prefs
= muiGlobalInfo(win
)->mgi_Prefs
;
535 /* potential for deadloop if Zune prefs images contain a 6: */
536 CONST_STRPTR spec_desc
= prefs
->imagespecs
[spec
->u
.cfg
.muiimg
];
537 zune_imspec_free(spec
);
540 if (spec_desc
&& (spec_desc
[0] == '6'))
542 D(bug("*** zune_imspec_setup (%s recursive config)\n",
543 zune_imspec_to_string(spec
)));
547 spec
= zune_imspec_setup((IPTR
)spec_desc
, mri
);
552 case IST_SCALED_GRADIENT
:
553 case IST_TILED_GRADIENT
:
554 zune_gradientspec_setup(spec
, mri
);
560 /* bug : never called in textengine, fix this */
561 void zune_imspec_cleanup(struct MUI_ImageSpec_intern
*spec
)
566 D(bug("zune_imspec_cleanup(0x%lx) [%s]\n",
567 spec
, zune_imspec_to_string(spec
)));
578 zune_penspec_cleanup(&spec
->u
.penspec
);
588 for (i
= 0; i
< 2; i
++)
590 if (spec
->u
.brush
.filename
[i
])
592 dt_dispose_picture(spec
->u
.brush
.dt
[i
]);
594 spec
->u
.brush
.dt
[i
] = NULL
;
599 if (spec
->u
.bitmap
.dt
)
601 dt_dispose_picture(spec
->u
.bitmap
.dt
);
602 spec
->u
.bitmap
.dt
= NULL
;
607 D(bug("*** zune_imspec_cleanup : IST_CONFIG\n"));
610 case IST_SCALED_GRADIENT
:
611 case IST_TILED_GRADIENT
:
612 zune_gradientspec_cleanup(spec
);
617 zune_imspec_free(spec
);
621 BOOL
zune_imspec_askminmax(struct MUI_ImageSpec_intern
*spec
, struct MUI_MinMax
*minmax
)
623 if ((!spec
) || (!minmax
))
629 case IST_SCALED_GRADIENT
:
630 case IST_TILED_GRADIENT
:
632 minmax
->MinWidth
= 3;
633 minmax
->MinHeight
= 3;
634 minmax
->DefWidth
= 8;
635 minmax
->DefHeight
= 8;
636 minmax
->MaxWidth
= MUI_MAXMAX
;
637 minmax
->MaxHeight
= MUI_MAXMAX
;
641 return zune_imspec_vector_get_minmax(spec
, minmax
);
649 if (spec
->u
.brush
.dt
[0])
653 straddr
= *(spec
->u
.brush
.filename
);
654 len
= strlen(straddr
);
657 if (strcmp(&straddr
[len
-4],".mim")==0)
659 minmax
->MinWidth
= dt_width(spec
->u
.brush
.dt
[0]) >> 1;
660 minmax
->MinHeight
= dt_height(spec
->u
.brush
.dt
[0]);
661 minmax
->DefWidth
= minmax
->MinWidth
;
662 minmax
->DefHeight
= minmax
->MinHeight
;
663 minmax
->MaxWidth
= minmax
->MinWidth
;
664 minmax
->MaxHeight
= minmax
->MinHeight
;
668 minmax
->MinWidth
= dt_width(spec
->u
.brush
.dt
[0]);
669 minmax
->MinHeight
= dt_height(spec
->u
.brush
.dt
[0]);
670 minmax
->DefWidth
= minmax
->MinWidth
;
671 minmax
->DefHeight
= minmax
->MinHeight
;
672 minmax
->MaxWidth
= minmax
->MinWidth
;
673 minmax
->MaxHeight
= minmax
->MinHeight
;
677 minmax
->MinWidth
= 3;
678 minmax
->MinHeight
= 3;
679 minmax
->DefWidth
= 8;
680 minmax
->DefHeight
= 8;
681 minmax
->MaxWidth
= MUI_MAXMAX
;
682 minmax
->MaxHeight
= MUI_MAXMAX
;
688 minmax
->MinWidth
= 3;
689 minmax
->MinHeight
= 3;
690 minmax
->DefWidth
= dt_width(spec
->u
.bitmap
.dt
);
691 minmax
->DefHeight
= dt_height(spec
->u
.bitmap
.dt
);
692 minmax
->MaxWidth
= MUI_MAXMAX
;
693 minmax
->MaxHeight
= MUI_MAXMAX
;
694 if (!spec
->u
.bitmap
.dt
)
699 D(bug("*** zune_imspec_askminmax : IST_CONFIG\n"));
706 void zune_imspec_show(struct MUI_ImageSpec_intern
*spec
, Object
*obj
)
708 if ((!spec
) || (!obj
))
711 D(bug("zune_imspec_show(0x%lx) [%s]\n", spec
,
712 zune_imspec_to_string(spec
)));
714 /* scaled gradient generation made here */
718 D(bug("*** zune_imspec_show : IST_CONFIG\n"));
721 case IST_SCALED_GRADIENT
:
722 case IST_TILED_GRADIENT
:
723 spec
->u
.gradient
.obj
= obj
;
732 void zune_imspec_hide(struct MUI_ImageSpec_intern
*spec
)
737 D(bug("zune_imspec_hide(0x%lx) [%s]\n", spec
,
738 zune_imspec_to_string(spec
)));
743 D(bug("*** zune_imspec_hide : IST_CONFIG\n"));
751 void zune_imspec_drawbuffered (struct MUI_ImageSpec_intern
*spec
, struct RastPort
*rp
, struct MUI_RenderInfo
*mri
,
752 LONG left
, LONG top
, LONG width
, LONG height
,
753 LONG xoffset
, LONG yoffset
, LONG state
, LONG dx
, LONG dy
, WORD mode
, LONG abs_l
, LONG abs_t
, LONG abs_r
, LONG abs_b
)
755 LONG right
= left
+ width
- 1;
756 LONG bottom
= top
+ height
- 1;
757 struct MUI_ImageSpec_intern def
;
761 D(bug("*** zune_imspec_draw called on null imspec\n"));
765 if ((spec
->type
== IST_BITMAP
&& !spec
->u
.bitmap
.dt
)
766 || (spec
->type
== IST_BRUSH
&& !spec
->u
.brush
.dt
[0]))
768 def
.type
= IST_COLOR
;
769 zune_penspec_fill_muipen(&def
.u
.penspec
, MPEN_BACKGROUND
);
777 LONG fg
= mri
->mri_Pens
[patternPens
[spec
->u
.pattern
].fg
];
778 LONG bg
= mri
->mri_Pens
[patternPens
[spec
->u
.pattern
].bg
];
782 SetAfPt(rp
, patternPens
[spec
->u
.pattern
].pattern
, 1);
783 RectFill(rp
, left
-dx
, top
-dy
, right
-dx
, bottom
-dy
);
784 SetAfPt(rp
, NULL
, 0);
789 if (spec
->u
.vect
.draw
)
791 spec
->u
.vect
.draw(mri
, left
-dx
, top
-dy
, width
, height
, state
);
796 zune_penspec_drawdirect(&spec
->u
.penspec
, rp
, mri
, left
-dx
, top
-dy
, right
-dx
, bottom
-dy
);
803 if (state
< 0 || state
> 1)
805 if (spec
->u
.brush
.dt
[state
])
809 straddr
= *(spec
->u
.brush
.filename
);
810 len
= strlen(straddr
);
813 if (strcmp(&straddr
[len
-4],".mim")==0)
815 dt_put_mim_on_rastport(spec
->u
.brush
.dt
[0], mri
->mri_RastPort
,
816 left
-dx
, top
-dy
, state
);
820 dt_put_on_rastport(spec
->u
.brush
.dt
[state
], mri
->mri_RastPort
,
822 /* dt_put_on_rastport_tiled(spec->u.brush.dt[state], mri->mri_RastPort, */
823 /* left, top, right, bottom, */
824 /* xoffset - left, yoffset - top); */
829 if (spec
->u
.bitmap
.dt
)
831 dt_put_on_rastport_tiled(spec
->u
.bitmap
.dt
, rp
,
832 left
-dx
, top
-dy
, right
-dx
, bottom
-dy
,
833 xoffset
- left
, yoffset
- top
);
838 D(bug("*** zune_imspec_draw : IST_CONFIG\n"));
841 case IST_SCALED_GRADIENT
:
842 if (mode
== 0) zune_gradient_draw(spec
, mri
, left
, top
, right
, bottom
, 0, 0);
843 else zune_gradient_drawfast(spec
, rp
, mri
, 1, abs_l
, abs_t
, abs_r
, abs_b
, left
, top
, right
, bottom
, xoffset
, yoffset
);
846 case IST_TILED_GRADIENT
:
847 if (mode
== 0) zune_gradient_draw(spec
, mri
, left
, top
, right
, bottom
, xoffset
, yoffset
);
848 else zune_gradient_drawfast(spec
, rp
, mri
, 1, abs_l
, abs_t
, abs_r
, abs_b
, left
, top
, right
, bottom
, xoffset
, yoffset
);
853 void zune_imspec_draw (struct MUI_ImageSpec_intern
*spec
, struct MUI_RenderInfo
*mri
,
854 LONG left
, LONG top
, LONG width
, LONG height
,
855 LONG xoffset
, LONG yoffset
, LONG state
)
857 zune_imspec_drawbuffered(spec
, mri
->mri_RastPort
, mri
, left
, top
, width
, height
, xoffset
, yoffset
, state
, 0, 0, 0, left
, top
, left
+width
, top
+height
);
860 /**************************************************************************
861 Duplicates a image spec. In in may be one of the MUII_#? identifiers
862 (but it will always return a string).
863 The returned string must be freed with zune_image_spec_free() because
864 in the future it might be that the MUII_#? stuff is not converted to
866 **************************************************************************/
867 STRPTR
zune_image_spec_duplicate(IPTR in
)
872 if (in
>= MUII_WindowBack
&& in
< MUII_BACKGROUND
)
874 sprintf(spec_buf
,"6:%ld",in
);
878 if (in
>= MUII_BACKGROUND
&& in
< MUII_LASTPAT
)
880 sprintf(spec_buf
,"0:%ld",in
);
882 } else spec
= (char*)in
;
888 /**************************************************************************
889 Use this function to free the zune_image_spec_duplicate() result
890 **************************************************************************/
891 void zune_image_spec_free(CONST_STRPTR spec
)
893 if (spec
) FreeVec((APTR
)spec
);