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, setZoom, void(entity, float, float))
9 METHOD(Image, drag_setStartPos, float(entity, vector))
10 METHOD(Image, drag, float(entity, vector))
11 ATTRIB(Image, src, string, string_null)
12 ATTRIB(Image, color, vector, '1 1 1')
13 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
14 ATTRIB(Image, initialForcedZoom, float, 0) // used by forcedAspect -2 when the image is larger than the containing box
15 ATTRIB(Image, zoomFactor, float, 1)
16 ATTRIB(Image, zoomOffset, vector, '0.5 0.5 0')
17 ATTRIB(Image, zoomTime, float, 0)
18 ATTRIB(Image, zoomLimitedByTheBox, float, 0) // forbids zoom if image would be larger than the containing box
19 ATTRIB(Image, zoomMax, float, 0)
20 ATTRIB(Image, start_zoomOffset, vector, '0 0 0')
21 ATTRIB(Image, start_coords, vector, '0 0 0')
22 ATTRIB(Image, imgOrigin, vector, '0 0 0')
23 ATTRIB(Image, imgSize, vector, '0 0 0')
28 string Image_toString(entity me)
32 void Image_configureImage(entity me, string path)
35 me.zoomOffset = '0.5 0.5 0';
37 if (me.forcedAspect == -2)
38 me.initialForcedZoom = -1; // calculate initialForcedZoom at the first updateAspect call
39 if (me.zoomLimitedByTheBox)
40 me.zoomMax = -1; // calculate zoomMax at the first updateAspect call
42 void Image_draw(entity me)
44 if(me.imgSize_x > 1 || me.imgSize_y > 1)
46 draw_Picture(me.imgOrigin, me.src, me.imgSize, me.color, 1);
47 if(me.imgSize_x > 1 || me.imgSize_y > 1)
49 SUPER(Image).draw(me);
51 void Image_updateAspect(entity me)
54 if(me.size_x <= 0 || me.size_y <= 0)
56 if(me.forcedAspect == 0)
58 me.imgOrigin = '0 0 0';
63 if(me.forcedAspect < 0)
66 sz = draw_PictureSize(me.src);
70 asp = me.forcedAspect;
72 if(me.forcedAspect <= -2)
74 me.imgSize_x = sz_x / me.size_x;
75 me.imgSize_y = sz_y / me.size_y;
76 if(me.initialForcedZoom < 0 && (me.imgSize_x > 1 || me.imgSize_y > 1))
78 // image larger than the containing box, zoom it out to fit into the box
79 if(me.size_x > asp * me.size_y)
80 me.initialForcedZoom = (me.size_y * asp / me.size_x) / me.imgSize_x;
82 me.initialForcedZoom = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
83 me.zoomFactor = me.initialForcedZoom;
88 if(me.size_x > asp * me.size_y)
90 // x too large, so center x-wise
91 me.imgSize = eY + eX * (me.size_y * asp / me.size_x);
95 // y too large, so center y-wise
96 me.imgSize = eX + eY * (me.size_x / (asp * me.size_y));
103 if(me.initialForcedZoom > 0)
104 me.zoomMax = me.initialForcedZoom;
107 if(me.size_x > asp * me.size_y)
108 me.zoomMax = (me.size_y * asp / me.size_x) / me.imgSize_x;
110 me.zoomMax = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
114 if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax)
115 me.zoomFactor = me.zoomMax;
117 me.imgSize = me.imgSize * me.zoomFactor;
119 if(me.imgSize_x > 1 || me.imgSize_y > 1)
121 me.zoomOffset_x = bound(0, me.zoomOffset_x, 1);
122 me.zoomOffset_y = bound(0, me.zoomOffset_y, 1);
125 me.zoomOffset = '0.5 0.5 0';
127 me.imgOrigin_x = 0.5 - me.zoomOffset_x * me.imgSize_x;
128 me.imgOrigin_y = 0.5 - me.zoomOffset_y * me.imgSize_y;
130 float Image_drag_setStartPos(entity me, vector coords)
132 //if(me.imgSize_x > 1 || me.imgSize_y > 1) // check disabled: mousewheel zoom may start from a non-zoomed-in image
134 me.start_zoomOffset = me.zoomOffset;
135 me.start_coords = coords;
139 float Image_drag(entity me, vector coords)
141 if(me.imgSize_x > 1 || me.imgSize_y > 1)
143 me.zoomOffset_x = me.start_zoomOffset_x + (me.start_coords_x - coords_x) / me.imgSize_x;
144 me.zoomOffset_y = me.start_zoomOffset_y + (me.start_coords_y - coords_y) / me.imgSize_y;
149 void Image_setZoom(entity me, float z, float atMousePosition)
151 float prev_zoomFactor;
152 prev_zoomFactor = me.zoomFactor;
153 if (z < 0) // multiply by the current zoomFactor
156 float one_in_the_middle, initialZoom_in_the_middle;
157 one_in_the_middle = ((prev_zoomFactor - 1) * (me.zoomFactor - 1) < 0);
158 initialZoom_in_the_middle = (me.initialForcedZoom > 0 && (prev_zoomFactor - me.initialForcedZoom) * (me.zoomFactor - me.initialForcedZoom) < 0);
159 if (one_in_the_middle && initialZoom_in_the_middle)
161 // snap to real dimensions or to box
162 if (prev_zoomFactor < me.zoomFactor)
163 me.zoomFactor = min(1, me.initialForcedZoom);
165 me.zoomFactor = max(1, me.initialForcedZoom);
167 else if (one_in_the_middle)
168 me.zoomFactor = 1; // snap to real dimensions
169 else if (initialZoom_in_the_middle)
170 me.zoomFactor = me.initialForcedZoom; // snap to box
172 else if (z == 0) // reset (no zoom)
174 if (me.initialForcedZoom > 0)
175 me.zoomFactor = me.initialForcedZoom;
181 me.zoomFactor = bound(1/16, me.zoomFactor, 16);
182 if (me.zoomFactor > me.zoomMax)
183 me.zoomFactor = me.zoomMax;
184 if (prev_zoomFactor != me.zoomFactor)
189 me.zoomOffset_x = me.start_zoomOffset_x + (me.start_coords_x - 0.5) / me.imgSize_x;
190 me.zoomOffset_y = me.start_zoomOffset_y + (me.start_coords_y - 0.5) / me.imgSize_y;
191 // updateAspect will reset however zoomOffset to '0.5 0.5 0' if with
192 // this zoomFactor the image will not be zoomed (updateAspect will check
193 // the new values of imgSize).
198 void Image_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
200 SUPER(Image).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);