Fix [#21516] UI artifacts in array modifier
[blender.git] / source / blender / editors / space_action / space_action.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL 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. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31
32 #include "DNA_action_types.h"
33 #include "DNA_scene_types.h"
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_blenlib.h"
38 #include "BLI_math.h"
39 #include "BLI_rand.h"
40
41 #include "BKE_colortools.h"
42 #include "BKE_context.h"
43 #include "BKE_screen.h"
44 #include "BKE_utildefines.h"
45
46 #include "ED_screen.h"
47
48 #include "BIF_gl.h"
49
50 #include "WM_api.h"
51 #include "WM_types.h"
52
53 #include "UI_resources.h"
54 #include "UI_view2d.h"
55
56 #include "ED_anim_api.h"
57 #include "ED_markers.h"
58
59 #include "action_intern.h"      // own include
60
61 /* ******************** default callbacks for action space ***************** */
62
63 static SpaceLink *action_new(const bContext *C)
64 {
65         ScrArea *sa= CTX_wm_area(C);
66         SpaceAction *saction;
67         ARegion *ar;
68         
69         saction= MEM_callocN(sizeof(SpaceAction), "initaction");
70         saction->spacetype= SPACE_ACTION;
71         
72         saction->autosnap = SACTSNAP_FRAME;
73         saction->mode= SACTCONT_DOPESHEET;
74         
75         /* header */
76         ar= MEM_callocN(sizeof(ARegion), "header for action");
77         
78         BLI_addtail(&saction->regionbase, ar);
79         ar->regiontype= RGN_TYPE_HEADER;
80         ar->alignment= RGN_ALIGN_BOTTOM;
81         
82         /* channel list region */
83         ar= MEM_callocN(sizeof(ARegion), "channel area for action");
84         BLI_addtail(&saction->regionbase, ar);
85         ar->regiontype= RGN_TYPE_CHANNELS;
86         ar->alignment= RGN_ALIGN_LEFT;
87         
88                 /* only need to set scroll settings, as this will use 'listview' v2d configuration */
89         ar->v2d.scroll = V2D_SCROLL_BOTTOM;
90         ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL;
91         
92         /* main area */
93         ar= MEM_callocN(sizeof(ARegion), "main area for action");
94         
95         BLI_addtail(&saction->regionbase, ar);
96         ar->regiontype= RGN_TYPE_WINDOW;
97         
98         ar->v2d.tot.xmin= -10.0f;
99         ar->v2d.tot.ymin= (float)(-sa->winy)/3.0f;
100         ar->v2d.tot.xmax= (float)(sa->winx);
101         ar->v2d.tot.ymax= 0.0f;
102         
103         ar->v2d.cur = ar->v2d.tot;
104         
105         ar->v2d.min[0]= 0.0f;
106          ar->v2d.min[1]= 0.0f;
107         
108         ar->v2d.max[0]= MAXFRAMEF;
109          ar->v2d.max[1]= FLT_MAX;
110         
111         ar->v2d.minzoom= 0.01f;
112         ar->v2d.maxzoom= 50;
113         ar->v2d.scroll = (V2D_SCROLL_BOTTOM|V2D_SCROLL_SCALE_HORIZONTAL);
114         ar->v2d.scroll |= (V2D_SCROLL_RIGHT);
115         ar->v2d.keepzoom= V2D_LOCKZOOM_Y;
116         ar->v2d.align= V2D_ALIGN_NO_POS_Y;
117         ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL;
118         
119         return (SpaceLink *)saction;
120 }
121
122 /* not spacelink itself */
123 static void action_free(SpaceLink *sl)
124 {       
125 //      SpaceAction *saction= (SpaceAction*) sl;
126         
127 }
128
129
130 /* spacetype; init callback */
131 static void action_init(struct wmWindowManager *wm, ScrArea *sa)
132 {
133         SpaceAction *saction = sa->spacedata.first;
134         saction->flag |= SACTION_TEMP_NEEDCHANSYNC;
135 }
136
137 static SpaceLink *action_duplicate(SpaceLink *sl)
138 {
139         SpaceAction *sactionn= MEM_dupallocN(sl);
140         
141         /* clear or remove stuff from old */
142         
143         return (SpaceLink *)sactionn;
144 }
145
146
147
148 /* add handlers, stuff you only do once or on area/region changes */
149 static void action_main_area_init(wmWindowManager *wm, ARegion *ar)
150 {
151         wmKeyMap *keymap;
152         
153         UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
154         
155         /* own keymap */
156         keymap= WM_keymap_find(wm->defaultconf, "Dopesheet", SPACE_ACTION, 0);
157         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
158 }
159
160 static void action_main_area_draw(const bContext *C, ARegion *ar)
161 {
162         /* draw entirely, view changes should be handled here */
163         SpaceAction *saction= CTX_wm_space_action(C);
164         bAnimContext ac;
165         View2D *v2d= &ar->v2d;
166         View2DGrid *grid;
167         View2DScrollers *scrollers;
168         short unit=0, flag=0;
169         
170         /* clear and setup matrix */
171         UI_ThemeClearColor(TH_BACK);
172         glClear(GL_COLOR_BUFFER_BIT);
173         
174         UI_view2d_view_ortho(C, v2d);
175         
176         /* time grid */
177         unit= (saction->flag & SACTION_DRAWTIME)? V2D_UNIT_SECONDS : V2D_UNIT_FRAMES;
178         grid= UI_view2d_grid_calc(C, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY, ar->winx, ar->winy);
179         UI_view2d_grid_draw(C, v2d, grid, V2D_GRIDLINES_ALL);
180         UI_view2d_grid_free(grid);
181         
182         /* data */
183         if (ANIM_animdata_get_context(C, &ac)) {
184                 draw_channel_strips(&ac, saction, ar);
185         }
186         
187         /* current frame */
188         if (saction->flag & SACTION_DRAWTIME)   flag |= DRAWCFRA_UNIT_SECONDS;
189         if ((saction->flag & SACTION_NODRAWCFRANUM)==0)  flag |= DRAWCFRA_SHOW_NUMBOX;
190         ANIM_draw_cfra(C, v2d, flag);
191         
192         /* markers */
193         UI_view2d_view_orthoSpecial(C, v2d, 1);
194         draw_markers_time(C, 0);
195         
196         /* preview range */
197         UI_view2d_view_ortho(C, v2d);
198         ANIM_draw_previewrange(C, v2d);
199         
200         /* reset view matrix */
201         UI_view2d_view_restore(C);
202         
203         /* scrollers */
204         scrollers= UI_view2d_scrollers_calc(C, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
205         UI_view2d_scrollers_draw(C, v2d, scrollers);
206         UI_view2d_scrollers_free(scrollers);
207 }
208
209 /* add handlers, stuff you only do once or on area/region changes */
210 static void action_channel_area_init(wmWindowManager *wm, ARegion *ar)
211 {
212         wmKeyMap *keymap;
213         
214         UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy);
215         
216         /* own keymap */
217         keymap= WM_keymap_find(wm->defaultconf, "Animation Channels", 0, 0);
218         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
219 }
220
221 static void action_channel_area_draw(const bContext *C, ARegion *ar)
222 {
223         /* draw entirely, view changes should be handled here */
224         SpaceAction *saction= CTX_wm_space_action(C);
225         bAnimContext ac;
226         View2D *v2d= &ar->v2d;
227         View2DScrollers *scrollers;
228         
229         /* clear and setup matrix */
230         UI_ThemeClearColor(TH_BACK);
231         glClear(GL_COLOR_BUFFER_BIT);
232         
233         UI_view2d_view_ortho(C, v2d);
234         
235         /* data */
236         if (ANIM_animdata_get_context(C, &ac)) {
237                 draw_channel_names((bContext *)C, &ac, saction, ar);
238         }
239         
240         /* reset view matrix */
241         UI_view2d_view_restore(C);
242         
243         /* scrollers */
244         scrollers= UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
245         UI_view2d_scrollers_draw(C, v2d, scrollers);
246         UI_view2d_scrollers_free(scrollers);
247 }
248
249
250 /* add handlers, stuff you only do once or on area/region changes */
251 static void action_header_area_init(wmWindowManager *wm, ARegion *ar)
252 {
253         ED_region_header_init(ar);
254 }
255
256 static void action_header_area_draw(const bContext *C, ARegion *ar)
257 {
258         ED_region_header(C, ar);
259 }
260
261 static void action_channel_area_listener(ARegion *ar, wmNotifier *wmn)
262 {
263         /* context changes */
264         switch(wmn->category) {
265                 case NC_ANIMATION:
266                         ED_region_tag_redraw(ar);
267                         break;
268                 case NC_SCENE:
269                         switch(wmn->data) {
270                                 case ND_OB_ACTIVE:
271                                 case ND_FRAME:
272                                         ED_region_tag_redraw(ar);
273                                         break;
274                         }
275                         break;
276                 case NC_OBJECT:
277                         switch(wmn->data) {
278                                 case ND_BONE_ACTIVE:
279                                 case ND_BONE_SELECT:
280                                 case ND_KEYS:
281                                         ED_region_tag_redraw(ar);
282                                         break;
283                                 case ND_MODIFIER:
284                                         if(wmn->action == NA_RENAME)
285                                                 ED_region_tag_redraw(ar);
286                                         break;
287                         }
288                         break;
289                 case NC_ID:
290                         if(wmn->action == NA_RENAME)
291                                 ED_region_tag_redraw(ar);
292                         break;
293                 default:
294                         if(wmn->data==ND_KEYS)
295                                 ED_region_tag_redraw(ar);
296         }
297 }
298
299 static void action_main_area_listener(ARegion *ar, wmNotifier *wmn)
300 {
301         /* context changes */
302         switch(wmn->category) {
303                 case NC_ANIMATION:
304                         ED_region_tag_redraw(ar);
305                         break;
306                 case NC_SCENE:
307                         switch(wmn->data) {
308                                 case ND_RENDER_OPTIONS:
309                                 case ND_OB_ACTIVE:
310                                 case ND_FRAME:
311                                 case ND_MARKERS:
312                                         ED_region_tag_redraw(ar);
313                                         break;
314                         }
315                         break;
316                 case NC_OBJECT:
317                         switch(wmn->data) {
318                                 case ND_TRANSFORM:
319                                         /* moving object shouldn't need to redraw action */
320                                         break;
321                                 case ND_BONE_ACTIVE:
322                                 case ND_BONE_SELECT:
323                                 case ND_KEYS:
324                                         ED_region_tag_redraw(ar);
325                                         break;
326                         }
327                         break;
328                 case NC_NODE:
329                         switch(wmn->action) {
330                                 case NA_EDITED:
331                                         ED_region_tag_redraw(ar);
332                                         break;
333                         }
334                         break;
335                 case NC_ID:
336                         if(wmn->action == NA_RENAME)
337                                 ED_region_tag_redraw(ar);
338                         break;
339                                 
340                 default:
341                         if(wmn->data==ND_KEYS)
342                                 ED_region_tag_redraw(ar);
343         }
344 }
345
346 /* editor level listener */
347 static void action_listener(ScrArea *sa, wmNotifier *wmn)
348 {
349         SpaceAction *saction= (SpaceAction *)sa->spacedata.first;
350         
351         /* context changes */
352         switch (wmn->category) {
353                 case NC_ANIMATION:
354                         /* for selection changes of animation data, we can just redraw... otherwise autocolor might need to be done again */
355                         if (ELEM(wmn->data, ND_KEYFRAME_SELECT, ND_ANIMCHAN_SELECT))
356                                 ED_area_tag_redraw(sa);
357                         else
358                                 ED_area_tag_refresh(sa);
359                         break;
360                 case NC_SCENE:
361                         switch (wmn->data) {    
362                                 case ND_OB_ACTIVE:      /* selection changed, so force refresh to flush (needs flag set to do syncing) */
363                                 case ND_OB_SELECT:
364                                         saction->flag |= SACTION_TEMP_NEEDCHANSYNC;
365                                         ED_area_tag_refresh(sa);
366                                         break;
367                                         
368                                 default: /* just redrawing the view will do */
369                                         ED_area_tag_redraw(sa);
370                                         break;
371                         }
372                         break;
373                 case NC_OBJECT:
374                         switch (wmn->data) {
375                                 case ND_BONE_SELECT:    /* selection changed, so force refresh to flush (needs flag set to do syncing) */
376                                 case ND_BONE_ACTIVE:
377                                         saction->flag |= SACTION_TEMP_NEEDCHANSYNC;
378                                         ED_area_tag_refresh(sa);
379                                         break;
380                                 case ND_TRANSFORM:
381                                         /* moving object shouldn't need to redraw action */
382                                         break;
383                                 default: /* just redrawing the view will do */
384                                         ED_area_tag_redraw(sa);
385                                         break;
386                         }
387                         break;
388                 case NC_SPACE:
389                         switch (wmn->data) {
390                                 case ND_SPACE_DOPESHEET:
391                                         ED_area_tag_redraw(sa);
392                                         break;
393                                 case ND_SPACE_CHANGED:
394                                         saction->flag |= SACTION_TEMP_NEEDCHANSYNC;
395                                         ED_area_tag_refresh(sa);
396                                         break;
397                         }                       
398                         break;
399         }
400 }
401
402 static void action_header_area_listener(ARegion *ar, wmNotifier *wmn)
403 {
404         /* context changes */
405         switch(wmn->category) {
406                 case NC_SCENE:
407                         switch(wmn->data) {
408                                 case ND_OB_ACTIVE:
409                                         ED_region_tag_redraw(ar);
410                                         break;
411                         }
412                         break;
413                 case NC_ID:
414                         if(wmn->action == NA_RENAME)
415                                 ED_region_tag_redraw(ar);
416                         break;
417         }
418 }
419
420 static void action_refresh(const bContext *C, ScrArea *sa)
421 {
422         SpaceAction *saction= CTX_wm_space_action(C);
423         
424         /* update the state of the animchannels in response to changes from the data they represent 
425          * NOTE: the temp flag is used to indicate when this needs to be done, and will be cleared once handled
426          */
427         if (saction->flag & SACTION_TEMP_NEEDCHANSYNC) {
428                 ANIM_sync_animchannels_to_data(C);
429                 saction->flag &= ~SACTION_TEMP_NEEDCHANSYNC;
430         }
431         
432         /* region updates? */
433         // XXX resizing y-extents of tot should go here?
434 }
435
436 /* only called once, from space/spacetypes.c */
437 void ED_spacetype_action(void)
438 {
439         SpaceType *st= MEM_callocN(sizeof(SpaceType), "spacetype action");
440         ARegionType *art;
441         
442         st->spaceid= SPACE_ACTION;
443         strncpy(st->name, "Action", BKE_ST_MAXNAME);
444         
445         st->new= action_new;
446         st->free= action_free;
447         st->init= action_init;
448         st->duplicate= action_duplicate;
449         st->operatortypes= action_operatortypes;
450         st->keymap= action_keymap;
451         st->listener= action_listener;
452         st->refresh= action_refresh;
453         
454         /* regions: main window */
455         art= MEM_callocN(sizeof(ARegionType), "spacetype action region");
456         art->regionid = RGN_TYPE_WINDOW;
457         art->init= action_main_area_init;
458         art->draw= action_main_area_draw;
459         art->listener= action_main_area_listener;
460         art->keymapflag= ED_KEYMAP_VIEW2D/*|ED_KEYMAP_MARKERS*/|ED_KEYMAP_ANIMATION|ED_KEYMAP_FRAMES;
461
462         BLI_addhead(&st->regiontypes, art);
463         
464         /* regions: header */
465         art= MEM_callocN(sizeof(ARegionType), "spacetype action region");
466         art->regionid = RGN_TYPE_HEADER;
467         art->prefsizey= HEADERY;
468         art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_VIEW2D|ED_KEYMAP_FRAMES|ED_KEYMAP_HEADER;
469         
470         art->init= action_header_area_init;
471         art->draw= action_header_area_draw;
472         art->listener= action_header_area_listener;
473         
474         BLI_addhead(&st->regiontypes, art);
475         
476         /* regions: channels */
477         art= MEM_callocN(sizeof(ARegionType), "spacetype action region");
478         art->regionid = RGN_TYPE_CHANNELS;
479         art->prefsizex= 200;
480         art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_VIEW2D;
481         
482         art->init= action_channel_area_init;
483         art->draw= action_channel_area_draw;
484         art->listener= action_channel_area_listener;
485         
486         BLI_addhead(&st->regiontypes, art);
487         
488         
489         BKE_spacetype_register(st);
490 }
491