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
[] = {
69 const static MPattern patternPens
[] = {
70 {MPEN_SHADOW
, MPEN_BACKGROUND
, gridpattern1
}, /* MUII_SHADOWBACK */
71 {MPEN_SHADOW
, MPEN_FILL
, gridpattern1
}, /* MUII_SHADOWFILL */
72 {MPEN_SHADOW
, MPEN_SHINE
, gridpattern1
}, /* MUII_SHADOWSHINE */
73 {MPEN_FILL
, MPEN_BACKGROUND
, gridpattern1
}, /* MUII_FILLBACK */
74 {MPEN_FILL
, MPEN_SHINE
, gridpattern1
}, /* MUII_FILLSHINE */
75 {MPEN_SHINE
, MPEN_BACKGROUND
, gridpattern1
}, /* MUII_SHINEBACK */
76 {MPEN_FILL
, MPEN_BACKGROUND
, gridpattern2
}, /* MUII_FILLBACK2 */
77 {MPEN_HALFSHINE
, MPEN_BACKGROUND
, gridpattern1
}, /* MUII_HSHINEBACK */
78 {MPEN_HALFSHADOW
, MPEN_BACKGROUND
, gridpattern1
}, /* MUII_HSHADOWBACK */
79 {MPEN_HALFSHINE
, MPEN_SHINE
, gridpattern1
}, /* MUII_HSHINESHINE */
80 {MPEN_HALFSHADOW
, MPEN_SHADOW
, gridpattern1
}, /* MUII_HSHADOWSHADOW */
81 {MPEN_MARK
, MPEN_SHINE
, gridpattern1
}, /* MUII_MARKSHINE */
82 {MPEN_MARK
, MPEN_HALFSHINE
, gridpattern1
}, /* MUII_MARKHALFSHINE */
83 {MPEN_MARK
, MPEN_BACKGROUND
, gridpattern1
}, /* MUII_MARKBACKGROUND */
86 #define PATTERN_COUNT (MUII_LASTPAT - MUII_BACKGROUND + 1)
88 static struct MUI_ImageSpec_intern
*get_pattern_imspec(LONG in
)
90 struct MUI_ImageSpec_intern
*spec
= NULL
;
92 if (in
>= MUII_BACKGROUND
&& in
<= MUII_FILL
)
94 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
97 if (in
== MUII_BACKGROUND
)
98 color
= MPEN_BACKGROUND
;
99 else if (in
== MUII_SHADOW
)
101 else if (in
== MUII_SHINE
)
106 spec
->type
= IST_COLOR
;
107 zune_penspec_fill_muipen(&spec
->u
.penspec
, color
);
111 else if (in
>= MUII_SHADOWBACK
&& in
<= MUII_MARKBACKGROUND
)
113 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
115 spec
->type
= IST_PATTERN
;
116 spec
->u
.pattern
= in
- MUII_SHADOWBACK
;
124 static struct MUI_ImageSpec_intern
*get_pen_imspec(CONST_STRPTR str
)
126 struct MUI_ImageSpec_intern
*spec
;
128 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
130 if (!zune_pen_string_to_intern(str
, &spec
->u
.penspec
))
132 D(bug("*** zune_pen_string_to_intern failed\n"));
136 spec
->type
= IST_COLOR
;
142 static struct MUI_ImageSpec_intern
*get_scaled_gradient_imspec(CONST_STRPTR
145 struct MUI_ImageSpec_intern
*spec
;
147 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
149 if (!zune_gradient_string_to_intern(str
, spec
))
151 D(bug("*** zune_gradient_string_to_intern failed\n"));
155 spec
->type
= IST_SCALED_GRADIENT
;
161 static struct MUI_ImageSpec_intern
*get_tiled_gradient_imspec(CONST_STRPTR
164 struct MUI_ImageSpec_intern
*spec
;
166 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
168 if (!zune_gradient_string_to_intern(str
, spec
))
170 D(bug("*** zune_gradient_string_to_intern failed\n"));
174 spec
->type
= IST_TILED_GRADIENT
;
180 static struct MUI_ImageSpec_intern
*get_boopsi_imspec(CONST_STRPTR filename
)
182 struct MUI_ImageSpec_intern
*spec
;
186 if (!strstr(filename
, ".image"))
187 return get_brush_imspec(filename
);
189 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
191 spec
->u
.boopsi
.filename
= StrDup(filename
);
192 if (!spec
->u
.boopsi
.filename
)
194 spec
->u
.boopsi
.obj
= NULL
;
195 spec
->type
= IST_BOOPSI
;
202 static struct MUI_ImageSpec_intern
*get_brush_imspec(CONST_STRPTR filename
)
204 struct MUI_ImageSpec_intern
*spec
;
205 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
208 spec
->u
.brush
.filename
[0] = StrDup(filename
);
209 if (!spec
->u
.brush
.filename
[0])
211 last_idx
= strlen(spec
->u
.brush
.filename
[0]) - 1;
212 if (spec
->u
.brush
.filename
[0][last_idx
] == '0')
215 tmpstr
= StrDup(filename
);
218 FreeVec((APTR
) spec
->u
.brush
.filename
[0]);
221 tmpstr
[last_idx
] = '1';
222 spec
->u
.brush
.filename
[1] = tmpstr
;
224 spec
->u
.brush
.dt
[0] = NULL
;
225 spec
->u
.brush
.dt
[1] = NULL
;
226 spec
->type
= IST_BRUSH
;
233 static struct MUI_ImageSpec_intern
*get_bitmap_imspec(CONST_STRPTR filename
)
235 struct MUI_ImageSpec_intern
*spec
;
236 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
238 spec
->u
.bitmap
.filename
= StrDup(filename
);
239 if (!spec
->u
.bitmap
.filename
)
241 spec
->u
.bitmap
.dt
= NULL
;
242 spec
->type
= IST_BITMAP
;
249 static struct MUI_ImageSpec_intern
*get_config_imspec(LONG img
)
251 if ((img
>= MUII_WindowBack
) && (img
<= MUII_ReadListBack
))
253 struct MUI_ImageSpec_intern
*spec
;
254 if ((spec
= mui_alloc_struct(struct MUI_ImageSpec_intern
)))
256 spec
->u
.cfg
.muiimg
= img
;
257 spec
->type
= IST_CONFIG
;
266 static const char *zune_imspec_to_string(struct MUI_ImageSpec_intern
*spec
)
278 sprintf(buf
, "0:%ld", spec
->u
.pattern
);
282 sprintf(buf
, "1:%ld", spec
->u
.vect
.type
);
286 zune_pen_intern_to_spec(&spec
->u
.penspec
,
287 (struct MUI_PenSpec
*)buf
);
291 sprintf(buf
, "3:%s", spec
->u
.boopsi
.filename
);
294 case IST_BRUSH
: /* this is really 3: too */
295 sprintf(buf
, "3:%s", spec
->u
.brush
.filename
[0]);
299 sprintf(buf
, "5:%s", spec
->u
.bitmap
.filename
);
303 sprintf(buf
, "6:%ld", spec
->u
.cfg
.muiimg
);
306 case IST_SCALED_GRADIENT
:
307 zune_scaled_gradient_intern_to_string(spec
, buf
);
310 case IST_TILED_GRADIENT
:
311 zune_tiled_gradient_intern_to_string(spec
, buf
);
318 /**************************************************************************
319 Create a image spec from a string or a magic value.
320 in : contains magic or string
321 obj: is a AreaObject. It is used to access the config data.
323 TODO: merge this with zune_imspec_setup() because this function should
324 be called in MUIM_Setup (configdata)
325 **************************************************************************/
326 static struct MUI_ImageSpec_intern
*zune_image_spec_to_structure(IPTR in
)
328 struct MUI_ImageSpec_intern
*spec
= NULL
;
331 if (in
>= MUII_WindowBack
&& in
<= MUII_ReadListBack
)
333 D(bug("zune_image_spec_to_structure [config] : in=%ld\n", in
));
334 spec
= get_config_imspec(in
);
336 else if (in
>= MUII_BACKGROUND
&& in
<= MUII_MARKBACKGROUND
)
338 D(bug("zune_image_spec_to_structure [pattern] : in=%ld\n", in
));
339 spec
= get_pattern_imspec(in
);
343 s
= (CONST_STRPTR
) in
;
344 D(bug("zune_image_spec_to_structure [string] : in=%s\n", s
));
348 case '0': /* builtin pattern */
351 StrToLong(s
+ 2, &pat
);
352 spec
= get_pattern_imspec(pat
);
356 case '1': /* builtin standard image, obsoleted by 6: */
359 StrToLong(s
+ 2, &vect
);
360 spec
= zune_imspec_create_vector(vect
);
364 case '2': /* a penspec */
365 spec
= get_pen_imspec(s
+ 2);
366 D(bug("zune_image_spec_to_structure : penspec %lx\n",
370 case '3': /* BOOPSI image class name */
371 spec
= get_boopsi_imspec(s
+ 2);
374 case '4': /* external MUI brush name */
375 spec
= get_brush_imspec(s
+ 2);
378 case '5': /* external bitmap loaded with datatypes */
379 spec
= get_bitmap_imspec(s
+ 2);
382 case '6': /* preconfigured image or background */
385 StrToLong(s
+ 2, &img
);
387 if (img
>= MUII_WindowBack
&& img
<= MUII_ReadListBack
)
388 spec
= get_config_imspec(img
);
392 case '7': /* scaled gradient */
393 spec
= get_scaled_gradient_imspec(s
+ 2);
396 case '8': /* tiled gradient */
397 spec
= get_tiled_gradient_imspec(s
+ 2);
402 D(bug("zune_image_spec_to_structure : out=0x%lx [%s]\n",
403 spec
, zune_imspec_to_string(spec
)));
408 static struct MUI_ImageSpec_intern
*zune_imspec_copy(struct
409 MUI_ImageSpec_intern
*spec
)
411 struct MUI_ImageSpec_intern
*nspec
;
416 nspec
= mui_alloc_struct(struct MUI_ImageSpec_intern
);
418 memcpy(nspec
, spec
, sizeof(struct MUI_ImageSpec_intern
));
425 static void zune_imspec_free(struct MUI_ImageSpec_intern
*spec
)
429 D(bug("zune_imspec_free(0x%lx) [%s]\n",
430 spec
, zune_imspec_to_string(spec
)));
435 if (spec
->u
.boopsi
.filename
)
436 FreeVec((APTR
) spec
->u
.boopsi
.filename
);
440 if (spec
->u
.brush
.filename
[0])
441 FreeVec((APTR
) spec
->u
.brush
.filename
[0]);
442 if (spec
->u
.brush
.filename
[1])
443 FreeVec((APTR
) spec
->u
.brush
.filename
[1]);
447 if (spec
->u
.bitmap
.filename
)
448 FreeVec((APTR
) spec
->u
.bitmap
.filename
);
458 struct MUI_ImageSpec_intern
*zune_imspec_setup(IPTR s
,
459 struct MUI_RenderInfo
*mri
)
461 struct MUI_ImageSpec_intern
*spec
;
465 D(bug("zune_imspec_setup: param error: mri=%p\n", mri
));
469 spec
= zune_image_spec_to_structure(s
);
471 D(bug("zune_imspec_setup(%lx) [%s]\n",
472 spec
, zune_imspec_to_string(spec
)));
485 zune_penspec_setup(&spec
->u
.penspec
, mri
);
495 for (i
= 0; i
< 2; i
++)
497 if (spec
->u
.brush
.filename
[i
])
499 spec
->u
.brush
.dt
[i
] = dt_load_picture
500 (spec
->u
.brush
.filename
[i
], mri
->mri_Screen
);
502 if (!spec
->u
.brush
.dt
[i
]
503 && !strchr(spec
->u
.brush
.filename
[i
], ':'))
508 size
= strlen(IMSPEC_EXTERNAL_PREFIX
)
509 + strlen(spec
->u
.brush
.filename
[i
]) + 1;
510 fullpath
= (STRPTR
) AllocVec(size
, MEMF_ANY
);
512 if (fullpath
!= NULL
)
514 strcpy(fullpath
, IMSPEC_EXTERNAL_PREFIX
);
515 strcat(fullpath
, spec
->u
.brush
.filename
[i
]);
516 fullpath
[size
- 1] = 0;
517 spec
->u
.brush
.dt
[i
] = dt_load_picture
518 (fullpath
, mri
->mri_Screen
);
525 spec
->u
.brush
.dt
[i
] = spec
->u
.brush
.dt
[0];
532 if (spec
->u
.bitmap
.filename
)
534 spec
->u
.bitmap
.dt
= dt_load_picture
535 (spec
->u
.bitmap
.filename
, mri
->mri_Screen
);
541 Object
*win
= mri
->mri_WindowObject
;
542 struct ZunePrefsNew
*prefs
= muiGlobalInfo(win
)->mgi_Prefs
;
543 /* potential for deadloop if Zune prefs images contain a 6: */
544 CONST_STRPTR spec_desc
= prefs
->imagespecs
[spec
->u
.cfg
.muiimg
];
545 zune_imspec_free(spec
);
548 if (spec_desc
&& (spec_desc
[0] == '6'))
550 D(bug("*** zune_imspec_setup (%s recursive config)\n",
551 zune_imspec_to_string(spec
)));
555 spec
= zune_imspec_setup((IPTR
) spec_desc
, mri
);
560 case IST_SCALED_GRADIENT
:
561 case IST_TILED_GRADIENT
:
562 zune_gradientspec_setup(spec
, mri
);
568 /* bug : never called in textengine, fix this */
569 void zune_imspec_cleanup(struct MUI_ImageSpec_intern
*spec
)
574 D(bug("zune_imspec_cleanup(0x%lx) [%s]\n",
575 spec
, zune_imspec_to_string(spec
)));
586 zune_penspec_cleanup(&spec
->u
.penspec
);
596 for (i
= 0; i
< 2; i
++)
598 if (spec
->u
.brush
.filename
[i
])
600 dt_dispose_picture(spec
->u
.brush
.dt
[i
]);
602 spec
->u
.brush
.dt
[i
] = NULL
;
607 if (spec
->u
.bitmap
.dt
)
609 dt_dispose_picture(spec
->u
.bitmap
.dt
);
610 spec
->u
.bitmap
.dt
= NULL
;
615 D(bug("*** zune_imspec_cleanup : IST_CONFIG\n"));
618 case IST_SCALED_GRADIENT
:
619 case IST_TILED_GRADIENT
:
620 zune_gradientspec_cleanup(spec
);
625 zune_imspec_free(spec
);
629 BOOL
zune_imspec_askminmax(struct MUI_ImageSpec_intern
*spec
,
630 struct MUI_MinMax
*minmax
)
632 if ((!spec
) || (!minmax
))
638 case IST_SCALED_GRADIENT
:
639 case IST_TILED_GRADIENT
:
641 minmax
->MinWidth
= 3;
642 minmax
->MinHeight
= 3;
643 minmax
->DefWidth
= 8;
644 minmax
->DefHeight
= 8;
645 minmax
->MaxWidth
= MUI_MAXMAX
;
646 minmax
->MaxHeight
= MUI_MAXMAX
;
650 return zune_imspec_vector_get_minmax(spec
, minmax
);
658 if (spec
->u
.brush
.dt
[0])
662 straddr
= *(spec
->u
.brush
.filename
);
663 len
= strlen(straddr
);
666 if (strcmp(&straddr
[len
- 4], ".mim") == 0)
668 minmax
->MinWidth
= dt_width(spec
->u
.brush
.dt
[0]) >> 1;
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
= dt_width(spec
->u
.brush
.dt
[0]);
678 minmax
->MinHeight
= dt_height(spec
->u
.brush
.dt
[0]);
679 minmax
->DefWidth
= minmax
->MinWidth
;
680 minmax
->DefHeight
= minmax
->MinHeight
;
681 minmax
->MaxWidth
= minmax
->MinWidth
;
682 minmax
->MaxHeight
= minmax
->MinHeight
;
686 minmax
->MinWidth
= 3;
687 minmax
->MinHeight
= 3;
688 minmax
->DefWidth
= 8;
689 minmax
->DefHeight
= 8;
690 minmax
->MaxWidth
= MUI_MAXMAX
;
691 minmax
->MaxHeight
= MUI_MAXMAX
;
697 minmax
->MinWidth
= 3;
698 minmax
->MinHeight
= 3;
699 minmax
->DefWidth
= dt_width(spec
->u
.bitmap
.dt
);
700 minmax
->DefHeight
= dt_height(spec
->u
.bitmap
.dt
);
701 minmax
->MaxWidth
= MUI_MAXMAX
;
702 minmax
->MaxHeight
= MUI_MAXMAX
;
703 if (!spec
->u
.bitmap
.dt
)
708 D(bug("*** zune_imspec_askminmax : IST_CONFIG\n"));
715 void zune_imspec_show(struct MUI_ImageSpec_intern
*spec
, Object
*obj
)
717 if ((!spec
) || (!obj
))
720 D(bug("zune_imspec_show(0x%lx) [%s]\n", spec
,
721 zune_imspec_to_string(spec
)));
723 /* scaled gradient generation made here */
727 D(bug("*** zune_imspec_show : IST_CONFIG\n"));
730 case IST_SCALED_GRADIENT
:
731 case IST_TILED_GRADIENT
:
732 spec
->u
.gradient
.obj
= obj
;
741 void zune_imspec_hide(struct MUI_ImageSpec_intern
*spec
)
746 D(bug("zune_imspec_hide(0x%lx) [%s]\n", spec
,
747 zune_imspec_to_string(spec
)));
752 D(bug("*** zune_imspec_hide : IST_CONFIG\n"));
760 void zune_imspec_drawbuffered(struct MUI_ImageSpec_intern
*spec
,
761 struct RastPort
*rp
, struct MUI_RenderInfo
*mri
, LONG left
, LONG top
,
762 LONG width
, LONG height
, LONG xoffset
, LONG yoffset
, LONG state
,
763 LONG dx
, LONG dy
, WORD mode
, LONG abs_l
, LONG abs_t
, LONG abs_r
,
766 LONG right
= left
+ width
- 1;
767 LONG bottom
= top
+ height
- 1;
768 struct MUI_ImageSpec_intern def
;
772 D(bug("*** zune_imspec_draw called on null imspec\n"));
776 if ((spec
->type
== IST_BITMAP
&& !spec
->u
.bitmap
.dt
)
777 || (spec
->type
== IST_BRUSH
&& !spec
->u
.brush
.dt
[0]))
779 def
.type
= IST_COLOR
;
780 zune_penspec_fill_muipen(&def
.u
.penspec
, MPEN_BACKGROUND
);
788 LONG fg
= mri
->mri_Pens
[patternPens
[spec
->u
.pattern
].fg
];
789 LONG bg
= mri
->mri_Pens
[patternPens
[spec
->u
.pattern
].bg
];
793 SetAfPt(rp
, patternPens
[spec
->u
.pattern
].pattern
, 1);
794 RectFill(rp
, left
- dx
, top
- dy
, right
- dx
, bottom
- dy
);
795 SetAfPt(rp
, NULL
, 0);
800 if (spec
->u
.vect
.draw
)
802 spec
->u
.vect
.draw(mri
, left
- dx
, top
- dy
, width
, height
,
808 zune_penspec_drawdirect(&spec
->u
.penspec
, rp
, mri
, left
- dx
,
809 top
- dy
, right
- dx
, bottom
- dy
);
816 if (state
< 0 || state
> 1)
818 if (spec
->u
.brush
.dt
[state
])
822 straddr
= *(spec
->u
.brush
.filename
);
823 len
= strlen(straddr
);
826 if (strcmp(&straddr
[len
- 4], ".mim") == 0)
828 dt_put_mim_on_rastport(spec
->u
.brush
.dt
[0],
829 mri
->mri_RastPort
, left
- dx
, top
- dy
, state
);
833 dt_put_on_rastport(spec
->u
.brush
.dt
[state
], mri
->mri_RastPort
,
834 left
- dx
, top
- dy
);
835 /* dt_put_on_rastport_tiled(spec->u.brush.dt[state], mri->mri_RastPort, */
836 /* left, top, right, bottom, */
837 /* xoffset - left, yoffset - top); */
842 if (spec
->u
.bitmap
.dt
)
844 dt_put_on_rastport_tiled(spec
->u
.bitmap
.dt
, rp
,
845 left
- dx
, top
- dy
, right
- dx
, bottom
- dy
,
846 xoffset
- left
, yoffset
- top
);
851 D(bug("*** zune_imspec_draw : IST_CONFIG\n"));
854 case IST_SCALED_GRADIENT
:
856 zune_gradient_draw(spec
, mri
, left
, top
, right
, bottom
, 0, 0);
858 zune_gradient_drawfast(spec
, rp
, mri
, 1, abs_l
, abs_t
, abs_r
,
859 abs_b
, left
, top
, right
, bottom
, xoffset
, yoffset
);
862 case IST_TILED_GRADIENT
:
864 zune_gradient_draw(spec
, mri
, left
, top
, right
, bottom
, xoffset
,
867 zune_gradient_drawfast(spec
, rp
, mri
, 1, abs_l
, abs_t
, abs_r
,
868 abs_b
, left
, top
, right
, bottom
, xoffset
, yoffset
);
873 void zune_imspec_draw(struct MUI_ImageSpec_intern
*spec
,
874 struct MUI_RenderInfo
*mri
, LONG left
, LONG top
, LONG width
,
875 LONG height
, LONG xoffset
, LONG yoffset
, LONG state
)
877 zune_imspec_drawbuffered(spec
, mri
->mri_RastPort
, mri
, left
, top
, width
,
878 height
, xoffset
, yoffset
, state
, 0, 0, 0, left
, top
, left
+ width
,
882 /**************************************************************************
883 Duplicates an image spec. In 'in' may be one of the MUII_#? identifiers
884 (but it will always return a string).
885 The returned string must be freed with zune_image_spec_free() because
886 in the future it might be that the MUII_#? stuff is not converted to
888 **************************************************************************/
889 STRPTR
zune_image_spec_duplicate(IPTR in
)
894 if (in
>= MUII_WindowBack
&& in
< MUII_BACKGROUND
)
896 sprintf(spec_buf
, "6:%ld", in
);
901 if (in
>= MUII_BACKGROUND
&& in
< MUII_LASTPAT
)
903 sprintf(spec_buf
, "0:%ld", in
);
913 /**************************************************************************
914 Use this function to free the zune_image_spec_duplicate() result
915 **************************************************************************/
916 void zune_image_spec_free(CONST_STRPTR spec
)
919 FreeVec((APTR
) spec
);