]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/menu/item/image.c
initialForcedZoom -> zoomBox
[xonotic/xonotic-data.pk3dir.git] / qcsrc / menu / item / image.c
1 #ifdef INTERFACE
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')
25 ENDCLASS(Image)
26 #endif
27
28 #ifdef IMPLEMENTATION
29 string Image_toString(entity me)
30 {
31         return me.src;
32 }
33 void Image_configureImage(entity me, string path)
34 {
35         me.src = path;
36 }
37 void Image_initZoom(entity me)
38 {
39         me.zoomOffset = '0.5 0.5 0';
40         me.zoomFactor = 1;
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
45 }
46
47 void Image_draw(entity me)
48 {
49         if(me.imgSize_x > 1 || me.imgSize_y > 1)
50                 draw_SetClip();
51         draw_Picture(me.imgOrigin, me.src, me.imgSize, me.color, 1);
52         if(me.imgSize_x > 1 || me.imgSize_y > 1)
53                 draw_ClearClip();
54         SUPER(Image).draw(me);
55 }
56 void Image_updateAspect(entity me)
57 {
58         float asp;
59         if(me.size_x <= 0 || me.size_y <= 0)
60                 return;
61         if(me.forcedAspect == 0)
62         {
63                 me.imgOrigin = '0 0 0';
64                 me.imgSize = '1 1 0';
65         }
66         else
67         {
68                 if(me.forcedAspect < 0)
69                 {
70                         vector sz;
71                         sz = draw_PictureSize(me.src);
72                         asp = sz_x / sz_y;
73                 }
74                 else
75                         asp = me.forcedAspect;
76
77                 if(me.forcedAspect <= -2)
78                 {
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))
82                         {
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;
86                                 else
87                                         me.zoomBox = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
88                                 me.zoomFactor = me.zoomBox;
89                         }
90                 }
91                 else
92                 {
93                         if(me.size_x > asp * me.size_y)
94                         {
95                                 // x too large, so center x-wise
96                                 me.imgSize = eY + eX * (me.size_y * asp / me.size_x);
97                         }
98                         else
99                         {
100                                 // y too large, so center y-wise
101                                 me.imgSize = eX + eY * (me.size_x / (asp * me.size_y));
102                         }
103                 }
104         }
105
106         if (me.zoomMax < 0)
107         {
108                 if(me.zoomBox > 0)
109                         me.zoomMax = me.zoomBox;
110                 else
111                 {
112                         if(me.size_x > asp * me.size_y)
113                                 me.zoomMax = (me.size_y * asp / me.size_x) / me.imgSize_x;
114                         else
115                                 me.zoomMax = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
116                 }
117         }
118
119         if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax)
120                 me.zoomFactor = me.zoomMax;
121         if (me.zoomFactor)
122                 me.imgSize = me.imgSize * me.zoomFactor;
123
124         if(me.imgSize_x > 1 || me.imgSize_y > 1)
125         {
126                 me.zoomOffset_x = bound(0, me.zoomOffset_x, 1);
127                 me.zoomOffset_y = bound(0, me.zoomOffset_y, 1);
128         }
129         else
130                 me.zoomOffset = '0.5 0.5 0';
131
132         me.imgOrigin_x = 0.5 - me.zoomOffset_x * me.imgSize_x;
133         me.imgOrigin_y = 0.5 - me.zoomOffset_y * me.imgSize_y;
134 }
135 float Image_drag_setStartPos(entity me, vector coords)
136 {
137         //if(me.imgSize_x > 1 || me.imgSize_y > 1) // check disabled: mousewheel zoom may start from a non-zoomed-in image
138         {
139                 me.start_zoomOffset = me.zoomOffset;
140                 me.start_coords = coords;
141         }
142         return 1;
143 }
144 float Image_drag(entity me, vector coords)
145 {
146         if(me.imgSize_x > 1 || me.imgSize_y > 1)
147         {
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;
150                 me.updateAspect(me);
151         }
152         return 1;
153 }
154 void Image_setZoom(entity me, float z, float atMousePosition)
155 {
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)
159         {
160                 me.zoomFactor *= -z;
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)
165                 {
166                         // snap to real dimensions or to box
167                         if (prev_zoomFactor < me.zoomFactor)
168                                 me.zoomFactor = min(1, me.zoomBox);
169                         else
170                                 me.zoomFactor = max(1, me.zoomBox);
171                 }
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
176         }
177         else if (z == 0) // reset (no zoom)
178         {
179                 if (me.zoomBox > 0)
180                         me.zoomFactor = me.zoomBox;
181                 else
182                         me.zoomFactor = 1;
183         }
184         else // directly set
185                 me.zoomFactor = z;
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)
190         {
191                 me.zoomTime = time;
192                 if (atMousePosition)
193                 {
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).
199                 }
200         }
201         me.updateAspect(me);
202 }
203 void Image_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
204 {
205         SUPER(Image).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
206         me.updateAspect(me);
207 }
208 #endif