2b4a3e869f8548c5a0ca510047cc8d1df06ee1a3
[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 LEFTMOUSE:
339                                 case SPACEKEY:
340                                 case RETKEY:
341                                         afbreek= 1;
342                                         break;
343                                 case MIDDLEMOUSE:
344                                         
345                                         midtog= ~midtog;
346                                         if(midtog) {
347                                                 if( abs(mval[0]-xn) > abs(mval[1]-yn)) proj= 1;
348                                                 else proj= 0;
349                                                 firsttime= 1;
350                                         }
351                                 
352                                         break;
353                                 default:
354                                         arrows_move_cursor(event);
355                                 }
356                         }
357                         if(afbreek) break;
358                 }
359         }
360         
361         if(event==ESCKEY) {
362                 tv= transmain;
363                 for(a=0; a<tot; a++, tv++) {
364                         tv->loc[0]= tv->oldloc[0];
365                         tv->loc[1]= tv->oldloc[1];
366                 }
367         }
368         MEM_freeN(transmain);
369                         
370         G.moving= 0;
371
372         scrarea_queue_redraw(curarea);
373 }
374
375 static Oops *find_nearest_oops(void)
376 {
377         Oops *oops;
378         float x, y;
379         short mval[2];
380         
381         getmouseco_areawin(mval);
382         areamouseco_to_ipoco(G.v2d, mval, &x, &y);
383         
384         oops= G.soops->oops.first;
385         while(oops) {
386                 if(oops->hide == 0) {
387                         if(oops->x <=x && oops->x+OOPSX >= x) {
388                                 if(oops->y <=y && oops->y+OOPSY >= y) {         
389                                         return oops;
390                                 }
391                         }
392                 }
393                 oops= oops->next;
394         }
395         return 0;
396 }
397
398 static void do_activate_oops(Oops *oops)
399 {
400         Base *base;
401         Object *ob;
402         
403         switch(oops->type) {
404         case ID_SCE:
405                 if(oops->id) set_scene((Scene *)oops->id);
406                 break;
407         case ID_OB:
408                 base= FIRSTBASE;
409                 while(base) {
410                         if(base->object == (Object *)oops->id) break;
411                         base= base->next;
412                 }
413                 if(base) {
414                         if(G.obedit==NULL) set_active_base(base);       /* editview.c */
415                         allqueue(REDRAWVIEW3D, 0);
416                         allqueue(REDRAWOOPS, 0);
417                         allqueue(REDRAWINFO, 1);
418                 }
419                 break;
420         case ID_MA:
421                 ob= OBACT;
422                 if(ob && oops->id) {
423                         assign_material(ob, (Material *)oops->id, ob->actcol);
424                         allqueue(REDRAWBUTSSHADING, 0);
425                         scrarea_queue_winredraw(curarea);
426                 }
427                 break;
428                 
429         case ID_IM:
430                 if(oops->id && G.sima) {
431                         /* only set if the new image isnt alredy active */
432                         if ((ID *)G.sima->image != oops->id) {
433                                 G.sima->image = (Image *)oops->id;
434                                 allqueue(REDRAWIMAGE, 0);
435                                 scrarea_queue_winredraw(curarea);
436                         }
437                 }
438                 break;
439         /*
440         case ID_IP:
441                 if(oops->id && G.sipo) {
442                         *//* only set if the new ipo isnt alredy active *//*
443                         if ((ID *)G.sipo->ipo != oops->id) {
444                                 G.sipo->ipo = (Ipo *)oops->id;
445                                 allqueue(REDRAWIPO, 0);
446                                 scrarea_queue_winredraw(curarea);
447                         }
448                 }
449                 break;
450         */
451         }
452 }
453
454 void mouse_select_oops(void)
455 {
456         Oops *oops;
457         extern float oopslastx, oopslasty;      /* oops.c */
458         
459         if(G.soops==0) return;  
460                 
461         /* which oopses... */
462         oops= G.soops->oops.first;
463
464         oops= find_nearest_oops();
465         if(oops==0) return;
466         
467         if((G.qual & LR_SHIFTKEY)==0) deselect_all_oops();
468         
469         if(oops) {
470                 /* last_seq= seq; */
471                 
472                 if(G.qual==0) {
473                         oops->flag |= SELECT;
474                 }
475                 else {
476                         if(oops->flag & SELECT) {
477                                 oops->flag &= ~SELECT;
478                         }
479                         else {
480                                 oops->flag |= SELECT;
481                         }
482                 }
483                 
484                 oopslastx= oops->x;
485                 oopslasty= oops->y;
486                 
487                 if(G.qual & LR_CTRLKEY) do_activate_oops(oops);
488                 G.soops->lockpoin= oops;
489         }
490         
491         oops_to_select_objects();       /* also redraw */
492         scrarea_queue_headredraw(curarea);
493         
494         force_draw(1);
495         
496         std_rmouse_transform(transform_oops);
497 }
498
499 void borderselect_oops(void)
500 {
501         Oops *oops;
502         rcti rect;
503         rctf rectf, rq;
504         int val;
505         short mval[2];
506
507         if(G.soops==0) return;  
508         
509         val= get_border(&rect, 3);
510
511         if(val) {
512                 mval[0]= rect.xmin;
513                 mval[1]= rect.ymin;
514                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
515                 mval[0]= rect.xmax;
516                 mval[1]= rect.ymax;
517                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
518
519                 oops= G.soops->oops.first;
520                 while(oops) {
521                         if(oops->hide == 0) {
522                         
523                                 rq.xmin= oops->x;
524                                 rq.xmax= oops->x+OOPSX;
525                                 rq.ymin= oops->y;
526                                 rq.ymax= oops->y+OOPSY;
527                 
528                                 if(BLI_isect_rctf(&rq, &rectf, 0)) {
529                                         if(val==LEFTMOUSE) {
530                                                 oops->flag |= SELECT;
531                                         }
532                                         else {
533                                                 oops->flag &= ~SELECT;
534                                         }
535                                 }
536                         }
537                         oops= oops->next;
538                 }
539
540                 oops_to_select_objects();       /* also redraw */
541         }
542 }
543
544 static void select_oops_lib(ID *id)
545 {
546         Oops *oops;
547         
548         oops= G.soops->oops.first;
549         while(oops) {
550                 if(oops->hide==0) {     
551                         if(oops->id->lib== (Library *)id) oops->flag |= OOPS_DOSELECT;
552                 }
553                 oops= oops->next;
554         }
555 }
556
557 void select_linked_oops(void)
558 {
559         Oops *oops;
560         OopsLink *ol;
561         
562         if(G.soops==0) return;  
563
564         oops= G.soops->oops.first;
565         while(oops) {
566                 if(oops->hide==0) {     
567                         if(oops->flag & SELECT) {
568                                 if(oops->type==ID_LI) select_oops_lib(oops->id);
569                                 ol= oops->link.first;
570                                 while(ol) {
571                                         if(ol->to && ol->to->hide==0) ol->to->flag |= OOPS_DOSELECT;
572                                         ol= ol->next;
573                                 }
574                         }
575                 }
576                 oops= oops->next;
577         }
578         
579         oops= G.soops->oops.first;
580         while(oops) {
581                 if(oops->hide==0) {     
582                         if(oops->flag & OOPS_DOSELECT) {
583                                 oops->flag |= SELECT;
584                                 oops->flag &= ~OOPS_DOSELECT;
585                         }
586                 }
587                 oops= oops->next;
588         }
589         
590         oops_to_select_objects();       /* also redraw */
591         
592 }
593
594 void select_backlinked_oops(void)
595 {
596         Oops *oops;
597         OopsLink *ol;
598         
599         if(G.soops==0) return;  
600
601         oops= G.soops->oops.first;
602         while(oops) {
603                 if(oops->hide==0) {     
604                         if( (oops->flag & SELECT)==0) {
605                                 ol= oops->link.first;
606                                 while(ol) {
607                                         if(ol->to && ol->to->hide==0) {
608                                                 if(ol->to->flag & SELECT) oops->flag |= OOPS_DOSELECT;
609                                         }
610                                         ol= ol->next;
611                                 }
612                         }
613                 }
614                 oops= oops->next;
615         }
616         
617         oops= G.soops->oops.first;
618         while(oops) {
619                 if(oops->hide==0) {     
620                         if(oops->flag & OOPS_DOSELECT) {
621                                 oops->flag |= SELECT;
622                                 oops->flag &= ~OOPS_DOSELECT;
623                         }
624                 }
625                 oops= oops->next;
626         }
627         
628         oops_to_select_objects();       /* also redraw */
629         
630 }
631
632
633 void clever_numbuts_oops()
634 {
635         Oops *oops;
636         Object *ob;
637         char str1[10];
638         static char naam[256];
639         static char naam2[256];
640         static short doit;
641         int len;
642
643         if(G.soops->lockpoin) {
644                 oops= G.soops->lockpoin;
645                 ob = (Object *)oops->id;
646                 if(oops->type==ID_LI) strcpy(naam, ((Library *)oops->id)->name);
647                 else strcpy(naam, oops->id->name);
648
649                 strcpy(naam2, naam+2);
650                 str1[0]= oops->id->name[0];
651                 str1[1]= oops->id->name[1];
652                 str1[2]= ':';
653                 str1[3]= 0;
654                 if(strcmp(str1, "SC:")==0) strcpy(str1, "SCE:");
655                 else if(strcmp(str1, "SR:")==0) strcpy(str1, "SCR:");
656                 
657 //              if( GS(id->name)==ID_IP) len= 110;
658 //              else len= 120;
659                 len = 110;
660
661                 add_numbut(0, TEX, str1, 0, len, naam2, "Rename Object");
662                 if((oops->type==ID_OB || oops->type==ID_ME) && ob->type != OB_EMPTY) {
663         //              add_numbut(1, TEX, str1, 0, len, naam2, "Name Object");
664                         add_numbut(1, TOG|SHO, "Rename Linked Data", 0, 0, &doit, "Rename corresponding Datablock as well");
665                         do_clever_numbuts("Rename Datablock", 2, REDRAW); 
666                 } else {
667                         do_clever_numbuts("Rename Datablock", 1, REDRAW); 
668                 }
669
670                 rename_id((ID *)oops->id, naam2);
671         }
672 }