]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/menu/item/image.c
Merge branch 'master' into terencehill/screenshot_viewer
[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, 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')
24 ENDCLASS(Image)
25 #endif
26
27 #ifdef IMPLEMENTATION
28 string Image_toString(entity me)
29 {
30         return me.src;
31 }
32 void Image_configureImage(entity me, string path)
33 {
34         me.src = path;
35         me.zoomOffset = '0.5 0.5 0';
36         me.zoomFactor = 1;
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
41 }
42 void Image_draw(entity me)
43 {
44         if(me.imgSize_x > 1 || me.imgSize_y > 1)
45                 draw_SetClip();
46         draw_Picture(me.imgOrigin, me.src, me.imgSize, me.color, 1);
47         if(me.imgSize_x > 1 || me.imgSize_y > 1)
48                 draw_ClearClip();
49 }
50 void Image_updateAspect(entity me)
51 {
52         float asp;
53         if(me.size_x <= 0 || me.size_y <= 0)
54                 return;
55         if(me.forcedAspect == 0)
56         {
57                 me.imgOrigin = '0 0 0';
58                 me.imgSize = '1 1 0';
59         }
60         else
61         {
62                 if(me.forcedAspect < 0)
63                 {
64                         vector sz;
65                         sz = draw_PictureSize(me.src);
66                         asp = sz_x / sz_y;
67                 }
68                 else
69                         asp = me.forcedAspect;
70
71                 if(me.forcedAspect <= -2)
72                 {
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))
76                         {
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;
80                                 else
81                                         me.initialForcedZoom = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
82                                 me.zoomFactor = me.initialForcedZoom;
83                         }
84                 }
85                 else
86                 {
87                         if(me.size_x > asp * me.size_y)
88                         {
89                                 // x too large, so center x-wise
90                                 me.imgSize = eY + eX * (me.size_y * asp / me.size_x);
91                         }
92                         else
93                         {
94                                 // y too large, so center y-wise
95                                 me.imgSize = eX + eY * (me.size_x / (asp * me.size_y));
96                         }
97                 }
98         }
99
100         if (me.zoomMax < 0)
101         {
102                 if(me.initialForcedZoom > 0)
103                         me.zoomMax = me.initialForcedZoom;
104                 else
105                 {
106                         if(me.size_x > asp * me.size_y)
107                                 me.zoomMax = (me.size_y * asp / me.size_x) / me.imgSize_x;
108                         else
109                                 me.zoomMax = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
110                 }
111         }
112
113         if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax)
114                 me.zoomFactor = me.zoomMax;
115         if (me.zoomFactor)
116                 me.imgSize = me.imgSize * me.zoomFactor;
117
118         if(me.imgSize_x > 1 || me.imgSize_y > 1)
119         {
120                 me.zoomOffset_x = bound(0, me.zoomOffset_x, 1);
121                 me.zoomOffset_y = bound(0, me.zoomOffset_y, 1);
122         }
123         else
124                 me.zoomOffset = '0.5 0.5 0';
125
126         me.imgOrigin_x = 0.5 - me.zoomOffset_x * me.imgSize_x;
127         me.imgOrigin_y = 0.5 - me.zoomOffset_y * me.imgSize_y;
128 }
129 float Image_drag_setStartPos(entity me, vector coords)
130 {
131         //if(me.imgSize_x > 1 || me.imgSize_y > 1) // check disabled: mousewheel zoom may start from a non-zoomed-in image
132         {
133                 me.start_zoomOffset = me.zoomOffset;
134                 me.start_coords = coords;
135         }
136         return 1;
137 }
138 float Image_drag(entity me, vector coords)
139 {
140         if(me.imgSize_x > 1 || me.imgSize_y > 1)
141         {
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;
144                 me.updateAspect(me);
145         }
146         return 1;
147 }
148 void Image_setZoom(entity me, float z, float atMousePosition)
149 {
150         float prev_zoomFactor;
151         prev_zoomFactor = me.zoomFactor;
152         if (z < 0) // multiply by the current zoomFactor
153         {
154                 me.zoomFactor *= -z;
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)
159                 {
160                         // snap to real dimensions or to box
161                         if (prev_zoomFactor < me.zoomFactor)
162                                 me.zoomFactor = min(1, me.initialForcedZoom);
163                         else
164                                 me.zoomFactor = max(1, me.initialForcedZoom);
165                 }
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
170         }
171         else if (z == 0) // reset (no zoom)
172         {
173                 if (me.initialForcedZoom > 0)
174                         me.zoomFactor = me.initialForcedZoom;
175                 else
176                         me.zoomFactor = 1;
177         }
178         else // directly set
179                 me.zoomFactor = z;
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)
184         {
185                 me.zoomTime = time;
186                 if (atMousePosition)
187                 {
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).
193                 }
194         }
195         me.updateAspect(me);
196 }
197 void Image_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
198 {
199         SUPER(Image).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
200         me.updateAspect(me);
201 }
202 #endif