Port of part of the Interface code to 2.50.
[blender.git] / source / blender / editors / interface / view2d.c
1
2 #include <math.h>
3
4 #include "MEM_guardedalloc.h"
5
6 #include "DNA_scene_types.h"
7 #include "DNA_screen_types.h"
8 #include "DNA_space_types.h"
9 #include "DNA_view2d_types.h"
10
11 #include "BKE_global.h"
12
13 #include "WM_api.h"
14
15 #include "BIF_gl.h"
16
17 #include "UI_resources.h"
18 #include "UI_view2d.h"
19
20 /* minimum pixels per gridstep */
21 #define IPOSTEP 35
22
23 struct View2DGrid {
24         float dx, dy, startx, starty;
25         int machtx, machty;
26 };
27
28 /* Setup */
29
30 void UI_view2d_ortho(const bContext *C, View2D *v2d)
31 {
32         wmOrtho2(C->window, v2d->cur.xmin, v2d->cur.xmax, v2d->cur.ymin, v2d->cur.ymax);
33 }
34
35 void UI_view2d_update_size(View2D *v2d, int winx, int winy)
36 {
37         v2d->mask.xmin= v2d->mask.ymin= 0;
38         v2d->mask.xmax= winx;
39         v2d->mask.ymax= winy;
40         
41 #if 0
42         if(sa->spacetype==SPACE_ACTION) {
43                 if(sa->winx > ACTWIDTH+50) { 
44                         v2d->mask.xmin+= ACTWIDTH;
45                         v2d->hor.xmin+=ACTWIDTH;
46                 }
47         }
48         else if(sa->spacetype==SPACE_NLA){
49                 if(sa->winx > NLAWIDTH+50) { 
50                         v2d->mask.xmin+= NLAWIDTH;
51                         v2d->hor.xmin+=NLAWIDTH;
52                 }
53         }
54         else if(sa->spacetype==SPACE_IPO) {
55                 int ipobutx = calc_ipobuttonswidth(sa);
56                 
57                 v2d->mask.xmax-= ipobutx;
58                 
59                 if(v2d->mask.xmax<ipobutx)
60                         v2d->mask.xmax= winx;
61         }
62 #endif
63         
64         if(v2d->scroll) {
65                 if(v2d->scroll & L_SCROLL) {
66                         v2d->vert= v2d->mask;
67                         v2d->vert.xmax= SCROLLB;
68                         v2d->mask.xmin= SCROLLB;
69                 }
70                 else if(v2d->scroll & R_SCROLL) {
71                         v2d->vert= v2d->mask;
72                         v2d->vert.xmin= v2d->vert.xmax-SCROLLB;
73                         v2d->mask.xmax= v2d->vert.xmin;
74                 }
75                 
76                 if((v2d->scroll & B_SCROLL) || (v2d->scroll & B_SCROLLO)) {
77                         v2d->hor= v2d->mask;
78                         v2d->hor.ymax= SCROLLH;
79                         v2d->mask.ymin= SCROLLH;
80                 }
81                 else if(v2d->scroll & T_SCROLL) {
82                         v2d->hor= v2d->mask;
83                         v2d->hor.ymin= v2d->hor.ymax-SCROLLH;
84                         v2d->mask.ymax= v2d->hor.ymin;
85                 }
86         }
87 }
88
89 /* Grid */
90
91 static void step_to_grid(float *step, int *macht, int unit)
92 {
93         float loga, rem;
94         
95         /* try to write step as a power of 10 */
96         
97         loga= log10(*step);
98         *macht= (int)(loga);
99
100         rem= loga- *macht;
101         rem= pow(10.0, rem);
102         
103         if(loga<0.0) {
104                 if(rem < 0.2) rem= 0.2;
105                 else if(rem < 0.5) rem= 0.5;
106                 else rem= 1.0;
107
108                 *step= rem*pow(10.0, (float)*macht);
109
110                 if(unit == V2D_UNIT_FRAMES) {
111                         rem = 1.0;
112                         *step = 1.0;
113                 }
114
115                 if(rem==1.0) (*macht)++;        // prevents printing 1.0 2.0 3.0 etc
116         }
117         else {
118                 if(rem < 2.0) rem= 2.0;
119                 else if(rem < 5.0) rem= 5.0;
120                 else rem= 10.0;
121                 
122                 *step= rem*pow(10.0, (float)*macht);
123                 
124                 (*macht)++;
125                 if(rem==10.0) (*macht)++;       // prevents printing 1.0 2.0 3.0 etc
126         }
127 }
128
129 View2DGrid *UI_view2d_calc_grid(const bContext *C, View2D *v2d, int unit, int clamp, int winx, int winy)
130 {
131         View2DGrid *grid;
132         float space, pixels, seconddiv;
133         int secondgrid;
134
135         grid= MEM_callocN(sizeof(View2DGrid), "View2DGrid");
136
137         /* rule: gridstep is minimal IPOSTEP pixels */
138         /* how large is IPOSTEP pixels? */
139         
140         if(unit == V2D_UNIT_FRAMES) {
141                 secondgrid= 0;
142                 seconddiv= 0.01f * FPS;
143         }
144         else {
145                 secondgrid= 1;
146                 seconddiv= 1.0f;
147         }
148
149         space= v2d->cur.xmax - v2d->cur.xmin;
150         pixels= v2d->mask.xmax - v2d->mask.xmin;
151         
152         grid->dx= IPOSTEP*space/(seconddiv*pixels);
153         step_to_grid(&grid->dx, &grid->machtx, unit);
154         grid->dx*= seconddiv;
155         
156         if(clamp == V2D_GRID_CLAMP) {
157                 if(grid->dx < 0.1) grid->dx= 0.1;
158                 grid->machtx-= 2;
159                 if(grid->machtx<-2) grid->machtx= -2;
160         }
161         
162         space= (v2d->cur.ymax - v2d->cur.ymin);
163         pixels= winy;
164         grid->dy= IPOSTEP*space/pixels;
165         step_to_grid(&grid->dy, &grid->machty, unit);
166         
167         if(clamp == V2D_GRID_CLAMP) {
168                 if(grid->dy < 1.0) grid->dy= 1.0;
169                 if(grid->machty<1) grid->machty= 1;
170         }
171         
172         grid->startx= seconddiv*(v2d->cur.xmin/seconddiv - fmod(v2d->cur.xmin/seconddiv, grid->dx/seconddiv));
173         if(v2d->cur.xmin<0.0) grid->startx-= grid->dx;
174         
175         grid->starty= (v2d->cur.ymin-fmod(v2d->cur.ymin, grid->dy));
176         if(v2d->cur.ymin<0.0) grid->starty-= grid->dy;
177
178         return grid;
179 }
180
181 void UI_view2d_draw_grid(const bContext *C, View2D *v2d, View2DGrid *grid, int flag)
182 {
183         float vec1[2], vec2[2];
184         int a, step;
185         
186         if(flag & V2D_VERTICAL_LINES) {
187                 /* vertical lines */
188                 vec1[0]= vec2[0]= grid->startx;
189                 vec1[1]= grid->starty;
190                 vec2[1]= v2d->cur.ymax;
191                 
192                 step= (v2d->mask.xmax - v2d->mask.xmin+1)/IPOSTEP;
193                 
194                 UI_ThemeColor(TH_GRID);
195                 
196                 for(a=0; a<step; a++) {
197                         glBegin(GL_LINE_STRIP);
198                         glVertex2fv(vec1); glVertex2fv(vec2);
199                         glEnd();
200                         vec2[0]= vec1[0]+= grid->dx;
201                 }
202                 
203                 vec2[0]= vec1[0]-= 0.5*grid->dx;
204                 
205                 UI_ThemeColorShade(TH_GRID, 16);
206                 
207                 step++;
208                 for(a=0; a<=step; a++) {
209                         glBegin(GL_LINE_STRIP);
210                         glVertex2fv(vec1); glVertex2fv(vec2);
211                         glEnd();
212                         vec2[0]= vec1[0]-= grid->dx;
213                 }
214         }
215         
216         if(flag & V2D_HORIZONTAL_LINES) {
217                 /* horizontal lines */
218                 vec1[0]= grid->startx;
219                 vec1[1]= vec2[1]= grid->starty;
220                 vec2[0]= v2d->cur.xmax;
221                 
222                 step= (C->area->winy+1)/IPOSTEP;
223                 
224                 UI_ThemeColor(TH_GRID);
225                 for(a=0; a<=step; a++) {
226                         glBegin(GL_LINE_STRIP);
227                         glVertex2fv(vec1); glVertex2fv(vec2);
228                         glEnd();
229                         vec2[1]= vec1[1]+= grid->dy;
230                 }
231                 vec2[1]= vec1[1]-= 0.5*grid->dy;
232                 step++;
233         }
234         
235         UI_ThemeColorShade(TH_GRID, -50);
236         
237         if(flag & V2D_HORIZONTAL_AXIS) {
238                 /* horizontal axis */
239                 vec1[0]= v2d->cur.xmin;
240                 vec2[0]= v2d->cur.xmax;
241                 vec1[1]= vec2[1]= 0.0;
242                 glBegin(GL_LINE_STRIP);
243                 
244                 glVertex2fv(vec1);
245                 glVertex2fv(vec2);
246                 
247                 glEnd();
248         }
249         
250         if(flag & V2D_VERTICAL_AXIS) {
251                 /* vertical axis */
252                 vec1[1]= v2d->cur.ymin;
253                 vec2[1]= v2d->cur.ymax;
254                 vec1[0]= vec2[0]= 0.0;
255                 glBegin(GL_LINE_STRIP);
256                 glVertex2fv(vec1); glVertex2fv(vec2);
257                 glEnd();
258         }
259 }
260
261 void UI_view2d_free_grid(View2DGrid *grid)
262 {
263         MEM_freeN(grid);
264 }
265
266 /* Coordinate conversion */
267
268 void UI_view2d_region_to_view(View2D *v2d, short x, short y, float *viewx, float *viewy)
269 {
270         float div, ofs;
271
272         if(viewx) {
273                 div= v2d->mask.xmax-v2d->mask.xmin;
274                 ofs= v2d->mask.xmin;
275
276                 *viewx= v2d->cur.xmin+ (v2d->cur.xmax-v2d->cur.xmin)*(x-ofs)/div;
277         }
278
279         if(viewy) {
280                 div= v2d->mask.ymax-v2d->mask.ymin;
281                 ofs= v2d->mask.ymin;
282
283                 *viewy= v2d->cur.ymin+ (v2d->cur.ymax-v2d->cur.ymin)*(y-ofs)/div;
284         }
285 }
286
287 void UI_view2d_view_to_region(View2D *v2d, float x, float y, short *regionx, short *regiony)
288 {
289         *regionx= V2D_IS_CLIPPED;
290         *regiony= V2D_IS_CLIPPED;
291
292         x= (x - v2d->cur.xmin)/(v2d->cur.xmax-v2d->cur.xmin);
293         y= (x - v2d->cur.ymin)/(v2d->cur.ymax-v2d->cur.ymin);
294
295         if(x>=0.0 && x<=1.0) {
296                 if(y>=0.0 && y<=1.0) {
297                         if(regionx)
298                                 *regionx= v2d->mask.xmin + x*(v2d->mask.xmax-v2d->mask.xmin);
299                         if(regiony)
300                                 *regiony= v2d->mask.ymin + y*(v2d->mask.ymax-v2d->mask.ymin);
301                 }
302         }
303 }
304
305 void UI_view2d_to_region_no_clip(View2D *v2d, float x, float y, short *regionx, short *regiony)
306 {
307         x= (x - v2d->cur.xmin)/(v2d->cur.xmax-v2d->cur.xmin);
308         y= (x - v2d->cur.ymin)/(v2d->cur.ymax-v2d->cur.ymin);
309
310         x= v2d->mask.xmin + x*(v2d->mask.xmax-v2d->mask.xmin);
311         y= v2d->mask.ymin + y*(v2d->mask.ymax-v2d->mask.ymin);
312
313         if(regionx) {
314                 if(x<-32760) *regionx= -32760;
315                 else if(x>32760) *regionx= 32760;
316                 else *regionx= x;
317         }
318
319         if(regiony) {
320                 if(y<-32760) *regiony= -32760;
321                 else if(y>32760) *regiony= 32760;
322                 else *regiony= y;
323         }
324 }
325
326