Bugfix for http://projects.blender.org/tracker/?func=detail&atid=125&aid=3767&group_id=9
[blender.git] / source / blender / src / editoops.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 <stdlib.h>
34 #include <math.h>
35 #include <string.h>
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifndef WIN32
42 #include <unistd.h>
43 #else
44 #include <io.h>
45 #endif   
46
47 #include "MEM_guardedalloc.h"
48
49 #include "BLI_blenlib.h"
50 #include "BLI_arithb.h"
51
52 #include "DNA_material_types.h"
53 #include "DNA_object_types.h"
54 #include "DNA_oops_types.h"
55 #include "DNA_screen_types.h"
56 #include "DNA_space_types.h"
57 #include "DNA_scene_types.h"
58 #include "DNA_image_types.h"
59 #include "DNA_ipo_types.h"
60
61 #include "BKE_global.h"
62 #include "BKE_scene.h"
63 #include "BKE_library.h"
64 #include "BKE_material.h"
65 #include "BKE_utildefines.h"
66
67 #include "BIF_space.h"
68 #include "BIF_screen.h"
69 #include "BIF_editoops.h"
70 #include "BIF_editview.h"
71 #include "BIF_drawscene.h"
72 #include "BIF_mywindow.h"
73 #include "BIF_toolbox.h"
74 #include "BIF_interface.h"
75
76 #include "BDR_editobject.h"
77
78 #include "BSE_edit.h"
79 #include "BSE_drawipo.h"
80
81 #include "blendef.h"
82 #include "mydevice.h"
83
84
85 typedef struct TransOops {
86         float *loc;
87         float oldloc[2];
88 } TransOops;
89
90 struct ID *idt;
91
92
93 static void oops_to_select_objects(void)
94 {
95         Oops *oops;
96         Base *base;
97         Object *ob;
98
99         if(G.soops==0) return;  
100
101         oops= G.soops->oops.first;
102         while(oops) {
103                 if(oops->hide==0) {     
104                         if(oops->type==ID_OB) {
105                                 ob= (Object *)oops->id;
106                                 if(oops->flag & SELECT) ob->flag |= SELECT;
107                                 else ob->flag &= ~SELECT;
108                         }
109                 }
110                 oops= oops->next;
111         }
112         base= FIRSTBASE;
113         while(base) {
114                 if(base->flag != base->object->flag) {
115                         base->flag= base->object->flag;
116                 }
117                 base= base->next;
118         }
119
120         allqueue(REDRAWVIEW3D, 0);
121         allqueue(REDRAWOOPS, 0);
122 }
123
124 void swap_select_all_oops(void)
125 {
126         Oops *oops;
127         int sel= 0;
128         
129         if(G.soops==0) return;  
130
131         oops= G.soops->oops.first;
132         while(oops) {
133                 if(oops->hide==0) {     
134                         if(oops->flag & SELECT) {
135                                 sel= 1;
136                                 break;
137                         }
138                 }
139                 oops= oops->next;
140         }
141
142         oops= G.soops->oops.first;
143         while(oops) {
144                 if(oops->hide==0) {     
145                         if(sel) oops->flag &= ~SELECT;
146                         else oops->flag |= SELECT;
147                 }
148                 oops= oops->next;
149         }
150         
151         oops_to_select_objects();       /* also redraw */
152         
153         G.soops->lockpoin= NULL;
154 }
155
156 /* never used... check CVS 1.12 for the code */
157 /*  static void select_swap_oops(void) */
158
159 static void deselect_all_oops(void)
160 {
161         Oops *oops;
162         
163         if(G.soops==0) return;  
164
165         oops= G.soops->oops.first;
166         while(oops) {
167                 if(oops->hide==0) {     
168                         oops->flag &= ~SELECT;
169                 }
170                 oops= oops->next;
171         }
172         G.soops->lockpoin= NULL;
173 }
174
175 void set_select_flag_oops(void) /* all areas */
176 {
177         SpaceOops *so;
178         ScrArea *sa;
179         
180         sa= G.curscreen->areabase.first;
181         while(sa) {
182                 if(sa->spacetype==SPACE_OOPS) {
183                         so= sa->spacedata.first;
184                         so->flag |= SO_NEWSELECTED;
185                 }
186                 sa= sa->next;
187         }
188         if(G.soops) G.soops->lockpoin= NULL;
189 }
190
191 void deselect_all_area_oops(void)       /* all areas */
192 {
193         SpaceOops *so;
194         Oops *oops;
195         ScrArea *sa;
196         
197         sa= G.curscreen->areabase.first;
198         while(sa) {
199                 if(sa->spacetype==SPACE_OOPS) {
200                         so= sa->spacedata.first;
201                         
202                         oops= so->oops.first;
203                         while(oops) {
204                                 oops->flag &= ~SELECT;
205                                 oops= oops->next;
206                         }
207                 }
208                 sa= sa->next;
209         }
210         
211         if(G.soops) G.soops->lockpoin= NULL;
212 }
213
214 void transform_oops(int mode, int context)
215 {
216         TransOops *transmain, *tv;
217         Oops *oops;
218         float dx, dy, div, dvec[3], cent[3], min[3], max[3];
219         float sizefac, size[2], xref=1.0, yref=1.0;
220         int a, tot= 0, midtog= 0;
221         unsigned short event = 0;
222         short firsttime= 1, proj = 0, afbreek=0, xc, yc, xo, yo, xn, yn, mval[2];
223         short val;
224         char str[32];
225         
226         if(G.soops==0) return;  
227                 
228         /* which oopses... */
229         oops= G.soops->oops.first;
230         while(oops) {
231                 if(oops->hide==0) {     
232                         if(oops->flag & SELECT) {
233                                 tot++;
234                         }
235                 }
236                 oops= oops->next;
237         }
238         
239         if(tot==0) return;
240         
241         G.moving= 1;
242         
243         INIT_MINMAX(min, max);
244         
245         tv=transmain= MEM_callocN(tot*sizeof(TransOops), "transmain");
246         oops= G.soops->oops.first;
247         while(oops) {
248                 if(oops->hide==0) {     
249                         if(oops->flag & SELECT) {
250                                 tv->loc= &oops->x;
251                                 tv->oldloc[0]= tv->loc[0];
252                                 tv->oldloc[1]= tv->loc[1];
253                                 DO_MINMAX2(tv->loc, min, max);
254                                 tv++;
255                         }
256                 }
257                 oops= oops->next;
258         }
259
260         cent[0]= (min[0]+max[0])/2.0;
261         cent[1]= (min[1]+max[1])/2.0;
262
263         ipoco_to_areaco_noclip(G.v2d, cent, mval);
264         xc= mval[0];
265         yc= mval[1];
266         
267         getmouseco_areawin(mval);
268         xo= xn= mval[0];
269         yo= yn= mval[1];
270         dvec[0]= dvec[1]= 0.0;
271
272         sizefac= sqrt( (float)((yc-yn)*(yc-yn)+(xn-xc)*(xn-xc)) );
273         if(sizefac<2.0) sizefac= 2.0;
274
275         while(afbreek==0) {
276                 getmouseco_areawin(mval);
277                 if(mval[0]!=xo || mval[1]!=yo || firsttime) {
278                         
279                         if(mode=='g') {
280                         
281                                 dx= mval[0]- xo;
282                                 dy= mval[1]- yo;
283         
284                                 div= G.v2d->mask.xmax-G.v2d->mask.xmin;
285                                 dvec[0]+= (G.v2d->cur.xmax-G.v2d->cur.xmin)*(dx)/div;
286         
287                                 div= G.v2d->mask.ymax-G.v2d->mask.ymin;
288                                 dvec[1]+= (G.v2d->cur.ymax-G.v2d->cur.ymin)*(dy)/div;
289                                 
290                                 if(midtog) dvec[proj]= 0.0;
291                                 
292                                 tv= transmain;
293                                 for(a=0; a<tot; a++, tv++) {
294                                         
295                                         tv->loc[0]= tv->oldloc[0]+dvec[0];
296                                         tv->loc[1]= tv->oldloc[1]+dvec[1];
297                                                 
298                                 }
299                         
300                                 sprintf(str, "X: %.2f   Y: %.2f  ", dvec[0], dvec[1]);
301                                 headerprint(str);
302                         }
303                         else if(mode=='s') {
304                                 size[0]=size[1]= (sqrt( (float)((yc-mval[1])*(yc-mval[1])+(mval[0]-xc)*(mval[0]-xc)) ))/sizefac;
305                                 
306                                 if(midtog) size[proj]= 1.0;
307                                 size[0]*= xref;
308                                 size[1]*= yref;
309
310                                 tv= transmain;
311                                 for(a=0; a<tot; a++, tv++) {
312                                 
313                                         tv->loc[0]= size[0]*(tv->oldloc[0]-cent[0])+ cent[0];
314                                         tv->loc[1]= size[1]*(tv->oldloc[1]-cent[1])+ cent[1];
315                                         
316                                 }
317                                 
318                                 sprintf(str, "sizeX: %.3f   sizeY: %.3f  ", size[0], size[1]);
319                                 headerprint(str);
320                         }
321                         
322
323                         xo= mval[0];
324                         yo= mval[1];
325                         
326                         force_draw(0);
327                         
328                         firsttime= 0;
329                         
330                 }
331                 else BIF_wait_for_statechange();
332                 
333                 while(qtest()) {
334                         event= extern_qread(&val);
335                         if(val) {
336                                 switch(event) {
337                                 case ESCKEY:
338                                 case RIGHTMOUSE:
339                                 case LEFTMOUSE:
340                                 case SPACEKEY:
341                                 case RETKEY:
342                                         afbreek= 1;
343                                         break;
344                                 case MIDDLEMOUSE:
345                                         
346                                         midtog= ~midtog;
347                                         if(midtog) {
348                                                 if( abs(mval[0]-xn) > abs(mval[1]-yn)) proj= 1;
349                                                 else proj= 0;
350                                                 firsttime= 1;
351                                         }
352                                 
353                                         break;
354                                 default:
355                                         arrows_move_cursor(event);
356                                 }
357                         }
358                         if(afbreek) break;
359                 }
360         }
361         
362         if(event==ESCKEY || event==RIGHTMOUSE) {
363                 tv= transmain;
364                 for(a=0; a<tot; a++, tv++) {
365                         tv->loc[0]= tv->oldloc[0];
366                         tv->loc[1]= tv->oldloc[1];
367                 }
368         }
369         MEM_freeN(transmain);
370                         
371         G.moving= 0;
372
373         scrarea_queue_redraw(curarea);
374 }
375
376 static Oops *find_nearest_oops(void)
377 {
378         Oops *oops;
379         float x, y;
380         short mval[2];
381         
382         getmouseco_areawin(mval);
383         areamouseco_to_ipoco(G.v2d, mval, &x, &y);
384         
385         oops= G.soops->oops.first;
386         while(oops) {
387                 if(oops->hide == 0) {
388                         if(oops->x <=x && oops->x+OOPSX >= x) {
389                                 if(oops->y <=y && oops->y+OOPSY >= y) {         
390                                         return oops;
391                                 }
392                         }
393                 }
394                 oops= oops->next;
395         }
396         return 0;
397 }
398
399 static void do_activate_oops(Oops *oops)
400 {
401         Base *base;
402         Object *ob;
403         
404         switch(oops->type) {
405         case ID_SCE:
406                 if(oops->id) set_scene((Scene *)oops->id);
407                 break;
408         case ID_OB:
409                 base= FIRSTBASE;
410                 while(base) {
411                         if(base->object == (Object *)oops->id) break;
412                         base= base->next;
413                 }
414                 if(base) {
415                         if(G.obedit==NULL) set_active_base(base);       /* editview.c */
416                         allqueue(REDRAWVIEW3D, 0);
417                         allqueue(REDRAWOOPS, 0);
418                         allqueue(REDRAWINFO, 1);
419                 }
420                 break;
421         case ID_MA:
422                 ob= OBACT;
423                 if(ob && oops->id) {
424                         assign_material(ob, (Material *)oops->id, ob->actcol);
425                         allqueue(REDRAWBUTSSHADING, 0);
426                         scrarea_queue_winredraw(curarea);
427                 }
428                 break;
429                 
430         case ID_IM:
431                 if(oops->id && G.sima) {
432                         /* only set if the new image isnt alredy active */
433                         if ((ID *)G.sima->image != oops->id) {
434                                 G.sima->image = (Image *)oops->id;
435                                 allqueue(REDRAWIMAGE, 0);
436                                 scrarea_queue_winredraw(curarea);
437                         }
438                 }
439                 break;
440         /*
441         case ID_IP:
442                 if(oops->id && G.sipo) {
443                         *//* only set if the new ipo isnt alredy active *//*
444                         if ((ID *)G.sipo->ipo != oops->id) {
445                                 G.sipo->ipo = (Ipo *)oops->id;
446                                 allqueue(REDRAWIPO, 0);
447                                 scrarea_queue_winredraw(curarea);
448                         }
449                 }
450                 break;
451         */
452         }
453 }
454
455 void mouse_select_oops(void)
456 {
457         Oops *oops;
458         extern float oopslastx, oopslasty;      /* oops.c */
459         
460         if(G.soops==0) return;  
461                 
462         /* which oopses... */
463         oops= G.soops->oops.first;
464
465         oops= find_nearest_oops();
466         if(oops==0) return;
467         
468         if((G.qual & LR_SHIFTKEY)==0) deselect_all_oops();
469         
470         if(oops) {
471                 /* last_seq= seq; */
472                 
473                 if(G.qual==0) {
474                         oops->flag |= SELECT;
475                 }
476                 else {
477                         if(oops->flag & SELECT) {
478                                 oops->flag &= ~SELECT;
479                         }
480                         else {
481                                 oops->flag |= SELECT;
482                         }
483                 }
484                 
485                 oopslastx= oops->x;
486                 oopslasty= oops->y;
487                 
488                 if(G.qual & LR_CTRLKEY) do_activate_oops(oops);
489                 G.soops->lockpoin= oops;
490         }
491         
492         oops_to_select_objects();       /* also redraw */
493         scrarea_queue_headredraw(curarea);
494         
495         force_draw(1);
496         
497         std_rmouse_transform(transform_oops);
498 }
499
500 void borderselect_oops(void)
501 {
502         Oops *oops;
503         rcti rect;
504         rctf rectf, rq;
505         int val;
506         short mval[2];
507
508         if(G.soops==0) return;  
509         
510         val= get_border(&rect, 3);
511
512         if(val) {
513                 mval[0]= rect.xmin;
514                 mval[1]= rect.ymin;
515                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
516                 mval[0]= rect.xmax;
517                 mval[1]= rect.ymax;
518                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
519
520                 oops= G.soops->oops.first;
521                 while(oops) {
522                         if(oops->hide == 0) {
523                         
524                                 rq.xmin= oops->x;
525                                 rq.xmax= oops->x+OOPSX;
526                                 rq.ymin= oops->y;
527                                 rq.ymax= oops->y+OOPSY;
528                 
529                                 if(BLI_isect_rctf(&rq, &rectf, 0)) {
530                                         if(val==LEFTMOUSE) {
531                                                 oops->flag |= SELECT;
532                                         }
533                                         else {
534                                                 oops->flag &= ~SELECT;
535                                         }
536                                 }
537                         }
538                         oops= oops->next;
539                 }
540
541                 oops_to_select_objects();       /* also redraw */
542         }
543 }
544
545 static void select_oops_lib(ID *id)
546 {
547         Oops *oops;
548         
549         oops= G.soops->oops.first;
550         while(oops) {
551                 if(oops->hide==0) {     
552                         if(oops->id->lib== (Library *)id) oops->flag |= OOPS_DOSELECT;
553                 }
554                 oops= oops->next;
555         }
556 }
557
558 void select_linked_oops(void)
559 {
560         Oops *oops;
561         OopsLink *ol;
562         
563         if(G.soops==0) return;  
564
565         oops= G.soops->oops.first;
566         while(oops) {
567                 if(oops->hide==0) {     
568                         if(oops->flag & SELECT) {
569                                 if(oops->type==ID_LI) select_oops_lib(oops->id);
570                                 ol= oops->link.first;
571                                 while(ol) {
572                                         if(ol->to && ol->to->hide==0) ol->to->flag |= OOPS_DOSELECT;
573                                         ol= ol->next;
574                                 }
575                         }
576                 }
577                 oops= oops->next;
578         }
579         
580         oops= G.soops->oops.first;
581         while(oops) {
582                 if(oops->hide==0) {     
583                         if(oops->flag & OOPS_DOSELECT) {
584                                 oops->flag |= SELECT;
585                                 oops->flag &= ~OOPS_DOSELECT;
586                         }
587                 }
588                 oops= oops->next;
589         }
590         
591         oops_to_select_objects();       /* also redraw */
592         
593 }
594
595 void select_backlinked_oops(void)
596 {
597         Oops *oops;
598         OopsLink *ol;
599         
600         if(G.soops==0) return;  
601
602         oops= G.soops->oops.first;
603         while(oops) {
604                 if(oops->hide==0) {     
605                         if( (oops->flag & SELECT)==0) {
606                                 ol= oops->link.first;
607                                 while(ol) {
608                                         if(ol->to && ol->to->hide==0) {
609                                                 if(ol->to->flag & SELECT) oops->flag |= OOPS_DOSELECT;
610                                         }
611                                         ol= ol->next;
612                                 }
613                         }
614                 }
615                 oops= oops->next;
616         }
617         
618         oops= G.soops->oops.first;
619         while(oops) {
620                 if(oops->hide==0) {     
621                         if(oops->flag & OOPS_DOSELECT) {
622                                 oops->flag |= SELECT;
623                                 oops->flag &= ~OOPS_DOSELECT;
624                         }
625                 }
626                 oops= oops->next;
627         }
628         
629         oops_to_select_objects();       /* also redraw */
630         
631 }
632
633
634 void clever_numbuts_oops()
635 {
636         Oops *oops;
637         Object *ob;
638         char str1[10];
639         static char naam[256];
640         static char naam2[256];
641         static short doit;
642         int len;
643
644         if(G.soops->lockpoin) {
645                 oops= G.soops->lockpoin;
646                 ob = (Object *)oops->id;
647                 if(oops->type==ID_LI) strcpy(naam, ((Library *)oops->id)->name);
648                 else strcpy(naam, oops->id->name);
649
650                 strcpy(naam2, naam+2);
651                 str1[0]= oops->id->name[0];
652                 str1[1]= oops->id->name[1];
653                 str1[2]= ':';
654                 str1[3]= 0;
655                 if(strcmp(str1, "SC:")==0) strcpy(str1, "SCE:");
656                 else if(strcmp(str1, "SR:")==0) strcpy(str1, "SCR:");
657                 
658 //              if( GS(id->name)==ID_IP) len= 110;
659 //              else len= 120;
660                 len = 110;
661
662                 add_numbut(0, TEX, str1, 0, len, naam2, "Rename Object");
663                 if((oops->type==ID_OB || oops->type==ID_ME) && ob->type != OB_EMPTY) {
664         //              add_numbut(1, TEX, str1, 0, len, naam2, "Name Object");
665                         add_numbut(1, TOG|SHO, "Rename Linked Data", 0, 0, &doit, "Rename corresponding Datablock as well");
666                         do_clever_numbuts("Rename Datablock", 2, REDRAW); 
667                 } else {
668                         do_clever_numbuts("Rename Datablock", 1, REDRAW); 
669                 }
670
671                 rename_id((ID *)oops->id, naam2);
672         }
673 }