Wednesday sync orange with bf-blender
[blender.git] / source / blender / src / drawoops.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <math.h>
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #include "BMF_Api.h"
42
43 #include "BLI_blenlib.h"
44 #include "BLI_arithb.h"
45
46 #include "DNA_ID.h"
47 #include "DNA_object_types.h"
48 #include "DNA_oops_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_screen_types.h"
51 #include "DNA_space_types.h"
52 #include "DNA_view2d_types.h"
53
54 #include "BKE_utildefines.h"
55 #include "BKE_global.h"
56
57 #include "BIF_interface.h"
58 #include "BIF_interface_icons.h"
59 #include "BIF_gl.h"
60 #include "BIF_glutil.h"
61 #include "BIF_mywindow.h"
62 #include "BIF_outliner.h"
63 #include "BIF_resources.h"
64 #include "BIF_screen.h"
65
66 /*  #include "BIF_drawoops.h" bad name :(*/
67 #include "BIF_oops.h"
68
69 #include "BSE_drawipo.h"
70 #include "BSE_drawoops.h"
71
72 float oopscalex;
73 struct BMF_Font *font; /* for using different sized fonts */
74
75 void boundbox_oops(short sel)
76 {
77         Oops *oops;
78         float min[2], max[2];
79         int ok= 0;
80         
81         if(G.soops==0) return;
82         
83         min[0]= 1000.0;
84         max[0]= -1000.0;
85         min[1]= 1000.0;
86         max[1]= -1000.0;
87         
88         oops= G.soops->oops.first;
89         while(oops) {
90                 if ((oops->hide==0 && !sel) || (sel && oops->flag & SELECT )) {
91                         ok= 1;
92                         
93                         min[0]= MIN2(min[0], oops->x);
94                         max[0]= MAX2(max[0], oops->x+OOPSX);
95                         min[1]= MIN2(min[1], oops->y);
96                         max[1]= MAX2(max[1], oops->y+OOPSY);
97                 }
98                 oops= oops->next;
99         }
100         
101         if(ok==0) return;
102         
103         G.v2d->tot.xmin= min[0];
104         G.v2d->tot.xmax= max[0];
105         G.v2d->tot.ymin= min[1];
106         G.v2d->tot.ymax= max[1];
107         
108 }
109
110 void give_oopslink_line(Oops *oops, OopsLink *ol, float *v1, float *v2)
111 {
112
113         if(ol->to && ol->to->hide==0) {
114                 v1[0]= oops->x+ol->xof;
115                 v1[1]= oops->y+ol->yof;
116                 v2[0]= ol->to->x+OOPSX/2;
117                 v2[1]= ol->to->y;
118         }
119         else if(ol->from && ol->from->hide==0) {
120                 v1[0]= ol->from->x + ol->xof;
121                 v1[1]= ol->from->y + ol->xof;
122                 v2[0]= oops->x+OOPSX/2;
123                 v2[1]= oops->y;
124         }
125 }
126
127 void draw_oopslink(Oops *oops)
128 {
129         OopsLink *ol;
130         float vec[4][3], dist, spline_step;
131         short curve_res;
132         
133         if(oops->type==ID_SCE) {
134                 if(oops->flag & SELECT) {
135                         /* when using python Mesh to make meshes a file was saved
136                         that had an oops with no ID, stops a segfault when looking for lib */
137                         if(oops->id && oops->id->lib) cpack(0x4080A0);
138                         else cpack(0x808080);
139                 }
140                 else cpack(0x606060);
141         }
142         else {
143                 if(oops->flag & SELECT) {
144                         if(oops->id && oops->id->lib) cpack(0x11AAFF);
145                         else cpack(0xFFFFFF);
146                 }
147                 else cpack(0x0);
148         }
149         
150         glEnable(GL_MAP1_VERTEX_3);
151         vec[0][2]= vec[1][2]= vec[2][2]= vec[3][2]= 0.0; /* only 2d spline, set the Z to 0*/
152         
153         ol= oops->link.first;
154         while(ol) {
155                 if(ol->to && ol->to->hide==0) {
156                         
157                         give_oopslink_line(oops, ol, vec[0], vec[3]);
158                         
159                         dist= 0.5*VecLenf(vec[0], vec[3]);
160
161                         /* check ol->xof and yof for direction */
162                         if(ol->xof == 0.0) {
163                                 vec[1][0]= vec[0][0]-dist;
164                                 vec[1][1]= vec[0][1];
165                         }
166                         else if(ol->xof==OOPSX) {
167                                 vec[1][0]= vec[0][0]+dist;
168                                 vec[1][1]= vec[0][1];
169                         }
170                         else {
171                                 vec[1][0]= vec[0][0];
172                                 vec[1][1]= vec[0][1]+dist;
173                         }
174                         
175                         /* v3 is always pointing down */
176                         vec[2][0]= vec[3][0];
177                         vec[2][1]= vec[3][1] - dist;
178                         
179                         if( MIN4(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) > G.v2d->cur.xmax); /* clipped */  
180                                 else if ( MAX4(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) < G.v2d->cur.xmin); /* clipped */
181                                         else {
182                                                 /* calculate a curve resolution to use based on the length of the curve.*/
183                                                 curve_res = MIN2(40, MAX2(2, (short)((dist*2) * (oopscalex))));
184                                                 
185                                                 /* we can reuse the dist variable here to increment the GL curve eval amount*/
186                                                 dist = (float)1/curve_res;
187                                                 spline_step = 0.0;
188                                                 
189                                                 glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]);
190                                                 glBegin(GL_LINE_STRIP);
191                                                 while (spline_step < 1.000001) {
192                                                         glEvalCoord1f(spline_step);
193                                                         spline_step += dist;
194                                                 }
195                                                 glEnd();
196                                         }
197                         
198                 }
199                 ol= ol->next;
200         }
201 }
202
203 void draw_icon_oops(float *co, short type)
204 {
205         BIFIconID icon;
206         
207         switch(type) {
208         default: return;
209
210         case ID_OB:     icon= ICON_OBJECT_HLT; break;
211         case ID_ME:     icon= ICON_MESH_HLT; break;
212         case ID_CU:     icon= ICON_CURVE_HLT; break;
213         case ID_MB:     icon= ICON_MBALL_HLT; break;
214         case ID_LT:     icon= ICON_LATTICE_HLT; break;
215         case ID_LA:     icon= ICON_LAMP_HLT; break;
216         case ID_MA:     icon= ICON_MATERIAL_HLT; break;
217         case ID_TE:     icon= ICON_TEXTURE_HLT; break;
218         case ID_IP:     icon= ICON_IPO_HLT; break;
219         case ID_LI:     icon= ICON_LIBRARY_HLT; break;
220         case ID_IM:     icon= ICON_IMAGE_HLT; break;
221         }
222
223         glEnable(GL_BLEND);
224         glBlendFunc(GL_SRC_ALPHA,  GL_ONE_MINUS_SRC_ALPHA); 
225
226         BIF_icon_draw(co[0], co[1]-0.2, icon);
227
228         glBlendFunc(GL_ONE,  GL_ZERO); 
229         glDisable(GL_BLEND);
230 }
231
232 void mysbox(float x1, float y1, float x2, float y2)
233 {
234         float vec[2];
235         
236         glBegin(GL_LINE_LOOP);
237         vec[0]= x1; vec[1]= y1;
238         glVertex2fv(vec);
239         vec[0]= x2;
240         glVertex2fv(vec);
241         vec[1]= y2;
242         glVertex2fv(vec);
243         vec[0]= x1;
244         glVertex2fv(vec);
245         glEnd();
246 }
247
248 unsigned int give_oops_color(short type, short sel, unsigned int *border)
249 {
250         unsigned int body;
251         /* also finds out if a dashed line should be drawn */
252
253         switch(type) {
254         case ID_OB:
255                 body= 0x707070; break;
256         case ID_SCE:
257                 body= 0x608060; break;
258         case ID_MA:
259                 body= 0x808060; break;
260         case ID_TE:
261                 body= 0x7080a0; break;
262         case ID_IP:
263                 body= 0x906050; break;
264         case ID_LA:
265                 body= 0x608080; break;
266         case ID_LI:
267                 body= 0x2198DC; break;
268         case ID_IM:
269                 body= 0x35659F; break;
270         default:
271                 body= 0x606070; break;
272         }
273
274         if(sel) {
275                 if(G.moving) *border= 0xf0f0f0;
276                 else *border= 0xc0c0c0; 
277         }
278         else *border= 0x0;
279
280         
281         return body;
282 }
283
284 void calc_oopstext(char *str, float *v1)
285 {
286         float f1, f2, size; /* f1 is the lhs of the oops block, f2 is the rhs */
287         short mval[2], len, flen;
288         
289         ipoco_to_areaco_noclip(G.v2d, v1, mval);
290         f1= mval[0];
291         v1[0]+= OOPSX;
292         ipoco_to_areaco_noclip(G.v2d, v1, mval);
293         f2= mval[0];
294         
295         if (oopscalex>1.1) { /* Make text area wider if we have no icon.*/
296                 size= f2-f1;
297         } else {
298                 size= (f2-f1)*1.7; 
299         }
300
301         len= strlen(str);
302         
303         while( (flen= BMF_GetStringWidth(G.fonts, str)) > size) {
304                 if(flen < 10 || len<2) break;
305                 len--;
306                 str[len]= 0;
307         }
308         
309         flen= BMF_GetStringWidth(font, str);
310         
311         /* calc centred location for icon and text,
312         else if were zoomed too far out, just push text to the left of the oops block. */
313         if (oopscalex>1.1) { 
314                 mval[0]= (f1+f2-flen+1)/2;
315         } else {
316                 mval[0]=  f1; 
317         }
318         
319         mval[1]= 1;
320         areamouseco_to_ipoco(G.v2d, mval, &f1, &f2);
321         
322         v1[0]= f1;
323         
324 }
325
326 void draw_oops(Oops *oops)
327 {
328         OopsLink *ol;
329         float v1[2], x1, y1, x2, y2, f1, f2;
330         unsigned int body, border;
331         short line= 0;
332         char str[32];
333
334         x1= oops->x; 
335         x2= oops->x+OOPSX;
336         y1= oops->y; 
337         y2= oops->y+OOPSY;
338
339         if(x2 < G.v2d->cur.xmin || x1 > G.v2d->cur.xmax) return;
340         if(y2 < G.v2d->cur.ymin || y1 > G.v2d->cur.ymax) return;
341
342         body= give_oops_color(oops->type, oops->flag & SELECT, &border);
343         if(oops->id== (ID *)((G.scene->basact) ? (G.scene->basact->object) : 0)) line= 1;
344         else if(oops->id== (ID *)G.scene) line= 1;
345
346         if(oops->id->us) {
347                 cpack(body);
348
349                 glRectf(x1,  y1,  x2,  y2);
350         }
351         
352         /* it has never happened that an oops was missing an ID at
353         this point but has occured elseware so lets be safe */
354         if(oops->id && oops->id->lib) { 
355                 if(oops->id->flag & LIB_INDIRECT) cpack(0x1144FF);
356                 else cpack(0x11AAFF);
357
358                 glRectf(x2-0.2*OOPSX,  y2-0.2*OOPSX,  x2-0.1*OOPSX,  y2-0.1*OOPSX);
359         }
360
361         v1[0]= x1; 
362         v1[1]= (y1+y2)/2 -0.3;
363         if(oops->type==ID_LI) {
364                 sprintf(str, "     %s", ((Library *)oops->id)->name);
365         }
366         else {
367                 sprintf(str, "     %s", oops->id->name+2);
368         }
369         calc_oopstext(str, v1);
370
371         /* ICON */
372         if(str[1] && oopscalex>1.1) { /* HAS ICON */
373                 draw_icon_oops(v1, oops->type);
374         } else { /* NO ICON, UNINDENT*/
375                 v1[0] -= 1.3 / oopscalex;
376         }
377         if(oops->flag & SELECT) BIF_ThemeColor(TH_TEXT_HI);
378         else BIF_ThemeColor(TH_TEXT);
379         glRasterPos3f(v1[0],  v1[1], 0.0);
380         BMF_DrawString(font, str);
381
382         if(line) setlinestyle(2);
383         cpack(border);
384
385         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
386         glRectf(x1,  y1,  x2,  y2);
387         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
388         if(line) setlinestyle(0);
389
390         /* connection blocks */
391         ol= oops->link.first;
392         while(ol) {
393
394                 f1= x1+ol->xof; 
395                 f2= y1+ol->yof;
396
397                 body= give_oops_color(ol->type, oops->flag & SELECT, &border);
398                 cpack(body);
399
400                 glRectf(f1-.2,  f2-.2,  f1+.2,  f2+.2);
401                 cpack(border);
402
403                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
404
405                 glRectf(f1-.2,  f2-.2,  f1+.2,  f2+.2);
406
407                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
408
409                 ol= ol->next;
410         }
411
412         if(oops->flag & OOPS_REFER) {
413                         /* Draw the little rounded connection point */
414                 glColor3ub(0, 0, 0);
415                 glPushMatrix();
416
417                 glTranslatef(oops->x + 0.5*OOPSX, oops->y, 0.0);
418                 glutil_draw_filled_arc(0.0, M_PI, 0.05*OOPSX, 7);
419
420                 glPopMatrix();
421         }
422 }
423
424 void drawoopsspace(ScrArea *sa, void *spacedata)
425 {
426         SpaceOops *soops= spacedata;
427         Oops *oops;
428         float col[3];
429         
430         BIF_GetThemeColor3fv(TH_BACK, col);
431         
432         /* darker background for oops */
433         if(soops->type!=SO_OUTLINER) {
434                 col[0] = col[0] * 0.75; col[1] = col[1] * 0.75; col[2] = col[2] * 0.75;
435         }
436         
437         glClearColor(col[0], col[1], col[2], 0.0);
438         glClear(GL_COLOR_BUFFER_BIT);
439         if(soops==0) return;    
440         
441         if(soops->type==SO_OUTLINER) draw_outliner(sa, soops);
442         else {
443                 build_oops();   /* changed to become first call... */
444                 
445                 boundbox_oops(0);
446                 calc_scrollrcts(sa, G.v2d, curarea->winx, curarea->winy);
447
448                 myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
449
450                 oopscalex= .14*((float)curarea->winx)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
451                 calc_ipogrid(); /* for scrollvariables */
452                 
453                 
454                 /* Draw a page about the oops */
455                 BIF_GetThemeColor3fv(TH_BACK, col);
456                 glColor3fv(col);
457                 glRectf(G.v2d->tot.xmin-2, G.v2d->tot.ymin-2,  G.v2d->tot.xmax+2, G.v2d->tot.ymax+2); /* light square in the centre */
458                 BIF_ThemeColorShade(TH_BACK, -96); /* drop shadow color */
459                 glRectf(G.v2d->tot.xmin-1, G.v2d->tot.ymin-2,  G.v2d->tot.xmax+3, G.v2d->tot.ymin-3); /* bottom dropshadow */
460                 glRectf(G.v2d->tot.xmax+2, G.v2d->tot.ymin-2,  G.v2d->tot.xmax+3, G.v2d->tot.ymax+1); /* right hand dropshadow */
461                 /* box around the oops. */
462                 cpack(0x0);
463                 mysbox(G.v2d->tot.xmin-2, G.v2d->tot.ymin-2,  G.v2d->tot.xmax+2, G.v2d->tot.ymax+2);
464                 
465                 
466                 /* Set the font size for the oops based on the zoom level */
467                 if (oopscalex > 6.0) font = BMF_GetFont(BMF_kScreen15);
468                 else if (oopscalex > 3.5) font = G.font;
469                 else if (oopscalex > 2.5) font = G.fonts;
470                 else font = G.fontss;           
471                 
472                 /* Draw unselected oops links */
473                 oops= soops->oops.first;
474                 while(oops) {
475                         if(oops->hide==0 && (oops->flag & SELECT)); else {
476                                 draw_oopslink(oops);
477                         }
478                         oops= oops->next;
479                 }
480                 
481                 /* Draw selected oops links */
482                 oops= soops->oops.first;
483                 while(oops) {
484                         if(oops->hide==0 && (oops->flag & SELECT)) {
485                                 draw_oopslink(oops);
486                         }
487                         oops= oops->next;
488                 }                       
489                 
490                 oops= soops->oops.first;
491                 while(oops) {
492                         if(oops->hide==0) {
493                                 if(oops->flag & SELECT); else draw_oops(oops);
494                         }
495                         oops= oops->next;
496                 }
497                 
498                 oops= soops->oops.first;
499                 while(oops) {
500                         if(oops->hide==0) {
501                                 if(oops->flag & SELECT) draw_oops(oops);
502                         }
503                         oops= oops->next;
504                 }
505         }
506         
507         /* restore viewport */
508         mywinset(curarea->win);
509         
510         /* ortho at pixel level curarea */
511         myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
512
513         if(soops->type==SO_OUTLINER) {
514                 if(sa->winx>SCROLLB+10 && sa->winy>SCROLLH+10) {
515                         if(G.v2d->scroll) drawscroll(0);                
516                 }
517         }
518         draw_area_emboss(sa);   
519         
520         curarea->win_swap= WIN_BACK_OK;
521 }
522
523
524