]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/menu/item/image.qc
Header police
[xonotic/xonotic-data.pk3dir.git] / qcsrc / menu / item / image.qc
1 #include "image.qh"
2 #ifndef ITEM_IMAGE_H
3         #define ITEM_IMAGE_H
4         #include "../item.qc"
5         CLASS(Image, Item)
6                 METHOD(Image, configureImage, void(entity, string));
7                 METHOD(Image, draw, void(entity));
8                 METHOD(Image, toString, string(entity));
9                 METHOD(Image, resizeNotify, void(entity, vector, vector, vector, vector));
10                 METHOD(Image, updateAspect, void(entity));
11                 METHOD(Image, initZoom, void(entity));
12                 METHOD(Image, setZoom, void(entity, float, float));
13                 METHOD(Image, drag_setStartPos, float(entity, vector));
14                 METHOD(Image, drag, float(entity, vector));
15                 ATTRIB(Image, src, string, string_null)
16                 ATTRIB(Image, color, vector, '1 1 1')
17                 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
18                 ATTRIB(Image, zoomBox, float, 0)             // used by forcedAspect -2 when the image is larger than the containing box
19                 ATTRIB(Image, zoomFactor, float, 1)
20                 ATTRIB(Image, zoomOffset, vector, '0.5 0.5 0')
21                 ATTRIB(Image, zoomSnapToTheBox, float, 1)    // snap the zoomed in image to the box borders when zooming/dragging it
22                 ATTRIB(Image, zoomTime, float, 0)
23                 ATTRIB(Image, zoomLimitedByTheBox, float, 0) // forbids zoom if image would be larger than the containing box
24                 ATTRIB(Image, zoomMax, float, 0)
25                 ATTRIB(Image, start_zoomOffset, vector, '0 0 0')
26                 ATTRIB(Image, start_coords, vector, '0 0 0')
27                 ATTRIB(Image, imgOrigin, vector, '0 0 0')
28                 ATTRIB(Image, imgSize, vector, '0 0 0')
29         ENDCLASS(Image)
30 #endif
31
32 #ifdef IMPLEMENTATION
33         string Image_toString(entity me)
34         {
35                 return me.src;
36         }
37         void Image_configureImage(entity me, string path)
38         {
39                 me.src = path;
40         }
41         void Image_initZoom(entity me)
42         {
43                 me.zoomOffset = '0.5 0.5 0';
44                 me.zoomFactor = 1;
45                 if (me.forcedAspect == -2) me.zoomBox = -1;  // calculate zoomBox at the first updateAspect call
46                 if (me.zoomLimitedByTheBox) me.zoomMax = -1; // calculate zoomMax at the first updateAspect call
47         }
48
49         void Image_draw(entity me)
50         {
51                 if (me.imgSize.x > 1 || me.imgSize.y > 1) draw_SetClip();
52                 draw_Picture(me.imgOrigin, me.src, me.imgSize, me.color, 1);
53                 if (me.imgSize.x > 1 || me.imgSize.y > 1) draw_ClearClip();
54                 SUPER(Image).draw(me);
55         }
56         void Image_updateAspect(entity me)
57         {
58                 float asp = 0;
59                 if (me.size.x <= 0 || me.size.y <= 0) return;
60                 if (me.forcedAspect == 0)
61                 {
62                         me.imgOrigin = '0 0 0';
63                         me.imgSize = '1 1 0';
64                 }
65                 else
66                 {
67                         vector sz = '0 0 0';
68                         if (me.forcedAspect < 0)
69                         {
70                                 if (me.src != "") sz = draw_PictureSize(me.src);
71                                 if (sz.x <= 0 || sz.y <= 0)
72                                 {
73                                         // image is broken or doesn't exist, set the size for the placeholder image
74                                         sz.x = me.size.x;
75                                         sz.y = me.size.y;
76                                 }
77                                 asp = sz.x / sz.y;
78                         }
79                         else
80                         {
81                                 asp = me.forcedAspect;
82                         }
83
84                         if (me.forcedAspect <= -2)
85                         {
86                                 me.imgSize_x = sz.x / me.size.x;
87                                 me.imgSize_y = sz.y / me.size.y;
88                                 if (me.zoomBox < 0 && (me.imgSize.x > 1 || me.imgSize.y > 1))
89                                 {
90                                         // image larger than the containing box, zoom it out to fit into the box
91                                         if (me.size.x > asp * me.size.y) me.zoomBox = (me.size.y * asp / me.size.x) / me.imgSize.x;
92                                         else me.zoomBox = (me.size.x / (asp * me.size.y)) / me.imgSize.y;
93                                         me.zoomFactor = me.zoomBox;
94                                 }
95                         }
96                         else
97                         {
98                                 if (me.size.x > asp * me.size.y)
99                                 {
100                                         // x too large, so center x-wise
101                                         me.imgSize = eY + eX * (me.size.y * asp / me.size.x);
102                                 }
103                                 else
104                                 {
105                                         // y too large, so center y-wise
106                                         me.imgSize = eX + eY * (me.size.x / (asp * me.size.y));
107                                 }
108                         }
109                 }
110
111                 if (me.zoomMax < 0)
112                 {
113                         if (me.zoomBox > 0)
114                         {
115                                 me.zoomMax = me.zoomBox;
116                         }
117                         else
118                         {
119                                 if (me.size.x > asp * me.size.y) me.zoomMax = (me.size.y * asp / me.size.x) / me.imgSize.x;
120                                 else me.zoomMax = (me.size.x / (asp * me.size.y)) / me.imgSize.y;
121                         }
122                 }
123
124                 if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax) me.zoomFactor = me.zoomMax;
125                 if (me.zoomFactor) me.imgSize = me.imgSize * me.zoomFactor;
126
127                 if (me.imgSize.x > 1 || me.imgSize.y > 1)
128                 {
129                         if (me.zoomSnapToTheBox)
130                         {
131                                 if (me.imgSize.x > 1) me.zoomOffset_x = bound(0.5 / me.imgSize.x, me.zoomOffset.x, 1 - 0.5 / me.imgSize.x);
132                                 else me.zoomOffset_x = bound(1 - 0.5 / me.imgSize.x, me.zoomOffset.x, 0.5 / me.imgSize.x);
133
134                                 if (me.imgSize.y > 1) me.zoomOffset_y = bound(0.5 / me.imgSize.y, me.zoomOffset.y, 1 - 0.5 / me.imgSize.y);
135                                 else me.zoomOffset_y = bound(1 - 0.5 / me.imgSize.y, me.zoomOffset.y, 0.5 / me.imgSize.y);
136                         }
137                         else
138                         {
139                                 me.zoomOffset_x = bound(0, me.zoomOffset.x, 1);
140                                 me.zoomOffset_y = bound(0, me.zoomOffset.y, 1);
141                         }
142                 }
143                 else
144                 {
145                         me.zoomOffset = '0.5 0.5 0';
146                 }
147
148                 me.imgOrigin_x = 0.5 - me.zoomOffset.x * me.imgSize.x;
149                 me.imgOrigin_y = 0.5 - me.zoomOffset.y * me.imgSize.y;
150         }
151         float Image_drag_setStartPos(entity me, vector coords)
152         {
153                 // if(me.imgSize_x > 1 || me.imgSize_y > 1) // check disabled: mousewheel zoom may start from a non-zoomed-in image
154                 {
155                         me.start_zoomOffset = me.zoomOffset;
156                         me.start_coords = coords;
157                 }
158                 return 1;
159         }
160         float Image_drag(entity me, vector coords)
161         {
162                 if (me.imgSize.x > 1 || me.imgSize.y > 1)
163                 {
164                         me.zoomOffset_x = me.start_zoomOffset.x + (me.start_coords.x - coords.x) / me.imgSize.x;
165                         me.zoomOffset_y = me.start_zoomOffset.y + (me.start_coords.y - coords.y) / me.imgSize.y;
166                         me.updateAspect(me);
167                 }
168                 return 1;
169         }
170         void Image_setZoom(entity me, float z, float atMousePosition)
171         {
172                 float prev_zoomFactor;
173                 prev_zoomFactor = me.zoomFactor;
174                 if (z < 0)  // multiply by the current zoomFactor (but can also snap to real dimensions or to box)
175                 {
176                         me.zoomFactor *= -z;
177                         float realSize_in_the_middle, boxSize_in_the_middle;
178                         realSize_in_the_middle = ((prev_zoomFactor - 1) * (me.zoomFactor - 1) < 0);
179                         boxSize_in_the_middle = (me.zoomBox > 0 && (prev_zoomFactor - me.zoomBox) * (me.zoomFactor - me.zoomBox) < 0);
180                         if (realSize_in_the_middle && boxSize_in_the_middle)
181                         {
182                                 // snap to real dimensions or to box
183                                 if (prev_zoomFactor < me.zoomFactor) me.zoomFactor = min(1, me.zoomBox);
184                                 else me.zoomFactor = max(1, me.zoomBox);
185                         }
186                         else if (realSize_in_the_middle)
187                         {
188                                 me.zoomFactor = 1;  // snap to real dimensions
189                         }
190                         else if (boxSize_in_the_middle)
191                         {
192                                 me.zoomFactor = me.zoomBox; // snap to box
193                         }
194                 }
195                 else if (z == 0)                    // reset (no zoom)
196                 {
197                         if (me.zoomBox > 0) me.zoomFactor = me.zoomBox;
198                         else me.zoomFactor = 1;
199                 }
200                 else  // directly set
201                 {
202                         me.zoomFactor = z;
203                 }
204                 me.zoomFactor = bound(1 / 16, me.zoomFactor, 16);
205                 if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax) me.zoomFactor = me.zoomMax;
206                 if (prev_zoomFactor != me.zoomFactor)
207                 {
208                         me.zoomTime = time;
209                         if (atMousePosition)
210                         {
211                                 me.zoomOffset_x = me.start_zoomOffset.x + (me.start_coords.x - 0.5) / me.imgSize.x;
212                                 me.zoomOffset_y = me.start_zoomOffset.y + (me.start_coords.y - 0.5) / me.imgSize.y;
213                                 // updateAspect will reset zoomOffset to '0.5 0.5 0' if
214                                 // with this zoomFactor the image will not be zoomed in
215                                 // (updateAspect will check the new values of imgSize).
216                         }
217                 }
218                 me.updateAspect(me);
219         }
220         void Image_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
221         {
222                 SUPER(Image).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
223                 me.updateAspect(me);
224         }
225 #endif