2 CLASS(Image) EXTENDS(Item)
3 METHOD(Image, configureImage, void(entity, string))
4 METHOD(Image, draw, void(entity))
5 METHOD(Image, toString, string(entity))
6 METHOD(Image, resizeNotify, void(entity, vector, vector, vector, vector))
7 METHOD(Image, updateAspect, void(entity))
8 METHOD(Image, initZoom, void(entity))
9 METHOD(Image, setZoom, void(entity, float, float))
10 METHOD(Image, drag_setStartPos, float(entity, vector))
11 METHOD(Image, drag, float(entity, vector))
12 ATTRIB(Image, src, string, string_null)
13 ATTRIB(Image, color, vector, '1 1 1')
14 ATTRIB(Image, forcedAspect, float, 0) // special values: -1 keep image aspect ratio, -2 keep image size but bound to the containing box, -3 always keep image size
15 ATTRIB(Image, zoomBox, float, 0) // used by forcedAspect -2 when the image is larger than the containing box
16 ATTRIB(Image, zoomFactor, float, 1)
17 ATTRIB(Image, zoomOffset, vector, '0.5 0.5 0')
18 ATTRIB(Image, zoomTime, float, 0)
19 ATTRIB(Image, zoomLimitedByTheBox, float, 0) // forbids zoom if image would be larger than the containing box
20 ATTRIB(Image, zoomMax, float, 0)
21 ATTRIB(Image, start_zoomOffset, vector, '0 0 0')
22 ATTRIB(Image, start_coords, vector, '0 0 0')
23 ATTRIB(Image, imgOrigin, vector, '0 0 0')
24 ATTRIB(Image, imgSize, vector, '0 0 0')
29 string Image_toString(entity me)
33 void Image_configureImage(entity me, string path)
37 void Image_initZoom(entity me)
39 me.zoomOffset = '0.5 0.5 0';
41 if (me.forcedAspect == -2)
42 me.zoomBox = -1; // calculate zoomBox at the first updateAspect call
43 if (me.zoomLimitedByTheBox)
44 me.zoomMax = -1; // calculate zoomMax at the first updateAspect call
47 void Image_draw(entity me)
49 if(me.imgSize_x > 1 || me.imgSize_y > 1)
51 draw_Picture(me.imgOrigin, me.src, me.imgSize, me.color, 1);
52 if(me.imgSize_x > 1 || me.imgSize_y > 1)
54 SUPER(Image).draw(me);
56 void Image_updateAspect(entity me)
59 if(me.size_x <= 0 || me.size_y <= 0)
61 if(me.forcedAspect == 0)
63 me.imgOrigin = '0 0 0';
68 if(me.forcedAspect < 0)
71 sz = draw_PictureSize(me.src);
75 asp = me.forcedAspect;
77 if(me.forcedAspect <= -2)
79 me.imgSize_x = sz_x / me.size_x;
80 me.imgSize_y = sz_y / me.size_y;
81 if(me.zoomBox < 0 && (me.imgSize_x > 1 || me.imgSize_y > 1))
83 // image larger than the containing box, zoom it out to fit into the box
84 if(me.size_x > asp * me.size_y)
85 me.zoomBox = (me.size_y * asp / me.size_x) / me.imgSize_x;
87 me.zoomBox = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
88 me.zoomFactor = me.zoomBox;
93 if(me.size_x > asp * me.size_y)
95 // x too large, so center x-wise
96 me.imgSize = eY + eX * (me.size_y * asp / me.size_x);
100 // y too large, so center y-wise
101 me.imgSize = eX + eY * (me.size_x / (asp * me.size_y));
109 me.zoomMax = me.zoomBox;
112 if(me.size_x > asp * me.size_y)
113 me.zoomMax = (me.size_y * asp / me.size_x) / me.imgSize_x;
115 me.zoomMax = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
119 if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax)
120 me.zoomFactor = me.zoomMax;
122 me.imgSize = me.imgSize * me.zoomFactor;
124 if(me.imgSize_x > 1 || me.imgSize_y > 1)
126 me.zoomOffset_x = bound(0, me.zoomOffset_x, 1);
127 me.zoomOffset_y = bound(0, me.zoomOffset_y, 1);
130 me.zoomOffset = '0.5 0.5 0';
132 me.imgOrigin_x = 0.5 - me.zoomOffset_x * me.imgSize_x;
133 me.imgOrigin_y = 0.5 - me.zoomOffset_y * me.imgSize_y;
135 float Image_drag_setStartPos(entity me, vector coords)
137 //if(me.imgSize_x > 1 || me.imgSize_y > 1) // check disabled: mousewheel zoom may start from a non-zoomed-in image
139 me.start_zoomOffset = me.zoomOffset;
140 me.start_coords = coords;
144 float Image_drag(entity me, vector coords)
146 if(me.imgSize_x > 1 || me.imgSize_y > 1)
148 me.zoomOffset_x = me.start_zoomOffset_x + (me.start_coords_x - coords_x) / me.imgSize_x;
149 me.zoomOffset_y = me.start_zoomOffset_y + (me.start_coords_y - coords_y) / me.imgSize_y;
154 void Image_setZoom(entity me, float z, float atMousePosition)
156 float prev_zoomFactor;
157 prev_zoomFactor = me.zoomFactor;
158 if (z < 0) // multiply by the current zoomFactor (but can also snap to real dimensions or to box)
161 float realSize_in_the_middle, boxSize_in_the_middle;
162 realSize_in_the_middle = ((prev_zoomFactor - 1) * (me.zoomFactor - 1) < 0);
163 boxSize_in_the_middle = (me.zoomBox > 0 && (prev_zoomFactor - me.zoomBox) * (me.zoomFactor - me.zoomBox) < 0);
164 if (realSize_in_the_middle && boxSize_in_the_middle)
166 // snap to real dimensions or to box
167 if (prev_zoomFactor < me.zoomFactor)
168 me.zoomFactor = min(1, me.zoomBox);
170 me.zoomFactor = max(1, me.zoomBox);
172 else if (realSize_in_the_middle)
173 me.zoomFactor = 1; // snap to real dimensions
174 else if (boxSize_in_the_middle)
175 me.zoomFactor = me.zoomBox; // snap to box
177 else if (z == 0) // reset (no zoom)
180 me.zoomFactor = me.zoomBox;
186 me.zoomFactor = bound(1/16, me.zoomFactor, 16);
187 if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax)
188 me.zoomFactor = me.zoomMax;
189 if (prev_zoomFactor != me.zoomFactor)
194 me.zoomOffset_x = me.start_zoomOffset_x + (me.start_coords_x - 0.5) / me.imgSize_x;
195 me.zoomOffset_y = me.start_zoomOffset_y + (me.start_coords_y - 0.5) / me.imgSize_y;
196 // updateAspect will reset zoomOffset to '0.5 0.5 0' if
197 // with this zoomFactor the image will not be zoomed in
198 // (updateAspect will check the new values of imgSize).
203 void Image_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
205 SUPER(Image).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);