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)
50 void Image_updateAspect(entity me)
53 if(me.size_x <= 0 || me.size_y <= 0)
55 if(me.forcedAspect == 0)
57 me.imgOrigin = '0 0 0';
62 if(me.forcedAspect < 0)
65 sz = draw_PictureSize(me.src);
69 asp = me.forcedAspect;
71 if(me.forcedAspect <= -2)
73 me.imgSize_x = sz_x / me.size_x;
74 me.imgSize_y = sz_y / me.size_y;
75 if(me.initialForcedZoom < 0 && (me.imgSize_x > 1 || me.imgSize_y > 1))
77 // image larger than the containing box, zoom it out to fit into the box
78 if(me.size_x > asp * me.size_y)
79 me.initialForcedZoom = (me.size_y * asp / me.size_x) / me.imgSize_x;
81 me.initialForcedZoom = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
82 me.zoomFactor = me.initialForcedZoom;
87 if(me.size_x > asp * me.size_y)
89 // x too large, so center x-wise
90 me.imgSize = eY + eX * (me.size_y * asp / me.size_x);
94 // y too large, so center y-wise
95 me.imgSize = eX + eY * (me.size_x / (asp * me.size_y));
102 if(me.initialForcedZoom > 0)
103 me.zoomMax = me.initialForcedZoom;
106 if(me.size_x > asp * me.size_y)
107 me.zoomMax = (me.size_y * asp / me.size_x) / me.imgSize_x;
109 me.zoomMax = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
113 if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax)
114 me.zoomFactor = me.zoomMax;
116 me.imgSize = me.imgSize * me.zoomFactor;
118 if(me.imgSize_x > 1 || me.imgSize_y > 1)
120 me.zoomOffset_x = bound(0, me.zoomOffset_x, 1);
121 me.zoomOffset_y = bound(0, me.zoomOffset_y, 1);
124 me.zoomOffset = '0.5 0.5 0';
126 me.imgOrigin_x = 0.5 - me.zoomOffset_x * me.imgSize_x;
127 me.imgOrigin_y = 0.5 - me.zoomOffset_y * me.imgSize_y;
129 float Image_drag_setStartPos(entity me, vector coords)
131 //if(me.imgSize_x > 1 || me.imgSize_y > 1) // check disabled: mousewheel zoom may start from a non-zoomed-in image
133 me.start_zoomOffset = me.zoomOffset;
134 me.start_coords = coords;
138 float Image_drag(entity me, vector coords)
140 if(me.imgSize_x > 1 || me.imgSize_y > 1)
142 me.zoomOffset_x = me.start_zoomOffset_x + (me.start_coords_x - coords_x) / me.imgSize_x;
143 me.zoomOffset_y = me.start_zoomOffset_y + (me.start_coords_y - coords_y) / me.imgSize_y;
148 void Image_setZoom(entity me, float z, float atMousePosition)
150 float prev_zoomFactor;
151 prev_zoomFactor = me.zoomFactor;
152 if (z < 0) // multiply by the current zoomFactor
155 float one_in_the_middle, initialZoom_in_the_middle;
156 one_in_the_middle = ((prev_zoomFactor - 1) * (me.zoomFactor - 1) < 0);
157 initialZoom_in_the_middle = (me.initialForcedZoom > 0 && (prev_zoomFactor - me.initialForcedZoom) * (me.zoomFactor - me.initialForcedZoom) < 0);
158 if (one_in_the_middle && initialZoom_in_the_middle)
160 // snap to real dimensions or to box
161 if (prev_zoomFactor < me.zoomFactor)
162 me.zoomFactor = min(1, me.initialForcedZoom);
164 me.zoomFactor = max(1, me.initialForcedZoom);
166 else if (one_in_the_middle)
167 me.zoomFactor = 1; // snap to real dimensions
168 else if (initialZoom_in_the_middle)
169 me.zoomFactor = me.initialForcedZoom; // snap to box
171 else if (z == 0) // reset (no zoom)
173 if (me.initialForcedZoom > 0)
174 me.zoomFactor = me.initialForcedZoom;
180 me.zoomFactor = bound(1/16, me.zoomFactor, 16);
181 if (me.zoomFactor > me.zoomMax)
182 me.zoomFactor = me.zoomMax;
183 if (prev_zoomFactor != me.zoomFactor)
188 me.zoomOffset_x = me.start_zoomOffset_x + (me.start_coords_x - 0.5) / me.imgSize_x;
189 me.zoomOffset_y = me.start_zoomOffset_y + (me.start_coords_y - 0.5) / me.imgSize_y;
190 // updateAspect will reset however zoomOffset to '0.5 0.5 0' if with
191 // this zoomFactor the image will not be zoomed (updateAspect will check
192 // the new values of imgSize).
197 void Image_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
199 SUPER(Image).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);