]> 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         SUPER(Image).draw(me);
50 }
51 void Image_updateAspect(entity me)
52 {
53         float asp;
54         if(me.size_x <= 0 || me.size_y <= 0)
55                 return;
56         if(me.forcedAspect == 0)
57         {
58                 me.imgOrigin = '0 0 0';
59                 me.imgSize = '1 1 0';
60         }
61         else
62         {
63                 if(me.forcedAspect < 0)
64                 {
65                         vector sz;
66                         sz = draw_PictureSize(me.src);
67                         asp = sz_x / sz_y;
68                 }
69                 else
70                         asp = me.forcedAspect;
71
72                 if(me.forcedAspect <= -2)
73                 {
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))
77                         {
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;
81                                 else
82                                         me.initialForcedZoom = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
83                                 me.zoomFactor = me.initialForcedZoom;
84                         }
85                 }
86                 else
87                 {
88                         if(me.size_x > asp * me.size_y)
89                         {
90                                 // x too large, so center x-wise
91                                 me.imgSize = eY + eX * (me.size_y * asp / me.size_x);
92                         }
93                         else
94                         {
95                                 // y too large, so center y-wise
96                                 me.imgSize = eX + eY * (me.size_x / (asp * me.size_y));
97                         }
98                 }
99         }
100
101         if (me.zoomMax < 0)
102         {
103                 if(me.initialForcedZoom > 0)
104                         me.zoomMax = me.initialForcedZoom;
105                 else
106                 {
107                         if(me.size_x > asp * me.size_y)
108                                 me.zoomMax = (me.size_y * asp / me.size_x) / me.imgSize_x;
109                         else
110                                 me.zoomMax = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
111                 }
112         }
113
114         if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax)
115                 me.zoomFactor = me.zoomMax;
116         if (me.zoomFactor)
117                 me.imgSize = me.imgSize * me.zoomFactor;
118
119         if(me.imgSize_x > 1 || me.imgSize_y > 1)
120         {
121                 me.zoomOffset_x = bound(0, me.zoomOffset_x, 1);
122                 me.zoomOffset_y = bound(0, me.zoomOffset_y, 1);
123         }
124         else
125                 me.zoomOffset = '0.5 0.5 0';
126
127         me.imgOrigin_x = 0.5 - me.zoomOffset_x * me.imgSize_x;
128         me.imgOrigin_y = 0.5 - me.zoomOffset_y * me.imgSize_y;
129 }
130 float Image_drag_setStartPos(entity me, vector coords)
131 {
132         //if(me.imgSize_x > 1 || me.imgSize_y > 1) // check disabled: mousewheel zoom may start from a non-zoomed-in image
133         {
134                 me.start_zoomOffset = me.zoomOffset;
135                 me.start_coords = coords;
136         }
137         return 1;
138 }
139 float Image_drag(entity me, vector coords)
140 {
141         if(me.imgSize_x > 1 || me.imgSize_y > 1)
142         {
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;
145                 me.updateAspect(me);
146         }
147         return 1;
148 }
149 void Image_setZoom(entity me, float z, float atMousePosition)
150 {
151         float prev_zoomFactor;
152         prev_zoomFactor = me.zoomFactor;
153         if (z < 0) // multiply by the current zoomFactor
154         {
155                 me.zoomFactor *= -z;
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)
160                 {
161                         // snap to real dimensions or to box
162                         if (prev_zoomFactor < me.zoomFactor)
163                                 me.zoomFactor = min(1, me.initialForcedZoom);
164                         else
165                                 me.zoomFactor = max(1, me.initialForcedZoom);
166                 }
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
171         }
172         else if (z == 0) // reset (no zoom)
173         {
174                 if (me.initialForcedZoom > 0)
175                         me.zoomFactor = me.initialForcedZoom;
176                 else
177                         me.zoomFactor = 1;
178         }
179         else // directly set
180                 me.zoomFactor = z;
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)
185         {
186                 me.zoomTime = time;
187                 if (atMousePosition)
188                 {
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).
194                 }
195         }
196         me.updateAspect(me);
197 }
198 void Image_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
199 {
200         SUPER(Image).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
201         me.updateAspect(me);
202 }
203 #endif