Dopesheet: Keyframe size can be adjusted as part of theme settings
[blender.git] / source / blender / editors / space_action / action_draw.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Joshua Leung
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_action/action_draw.c
29  *  \ingroup spaction
30  */
31
32
33 /* System includes ----------------------------------------------------- */
34
35 #include <math.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <float.h>
39
40 #include "BLI_blenlib.h"
41 #include "BLI_utildefines.h"
42
43 /* Types --------------------------------------------------------------- */
44
45 #include "DNA_anim_types.h"
46 #include "DNA_screen_types.h"
47
48 #include "BKE_action.h"
49 #include "BKE_context.h"
50
51
52 /* Everything from source (BIF, BDR, BSE) ------------------------------ */ 
53
54 #include "BIF_gl.h"
55
56 #include "UI_interface.h"
57 #include "UI_resources.h"
58 #include "UI_view2d.h"
59
60 #include "ED_anim_api.h"
61 #include "ED_keyframes_draw.h"
62
63 #include "action_intern.h"
64
65 /* ************************************************************************* */
66 /* Channel List */
67
68 /* left hand part */
69 void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) 
70 {
71         ListBase anim_data = {NULL, NULL};
72         bAnimListElem *ale;
73         int filter;
74         
75         View2D *v2d = &ar->v2d;
76         float y = 0.0f;
77         size_t items;
78         int height;
79         
80         /* build list of channels to draw */
81         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
82         items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
83         
84         height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac)));
85         if (height > BLI_rcti_size_y(&v2d->mask)) {
86                 /* don't use totrect set, as the width stays the same 
87                  * (NOTE: this is ok here, the configuration is pretty straightforward) 
88                  */
89                 v2d->tot.ymin = (float)(-height);
90         }
91         /* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */
92         UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY);
93         
94         /* loop through channels, and set up drawing depending on their type  */
95         {   /* first pass: just the standard GL-drawing for backdrop + text */
96                 size_t channel_index = 0;
97                 
98                 y = (float)ACHANNEL_FIRST(ac);
99                 
100                 for (ale = anim_data.first; ale; ale = ale->next) {
101                         float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
102                         float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
103                         
104                         /* check if visible */
105                         if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
106                             IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
107                         {
108                                 /* draw all channels using standard channel-drawing API */
109                                 ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index);
110                         }
111                         
112                         /* adjust y-position for next one */
113                         y -= ACHANNEL_STEP(ac);
114                         channel_index++;
115                 }
116         }
117         {   /* second pass: widgets */
118                 uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
119                 size_t channel_index = 0;
120                 
121                 y = (float)ACHANNEL_FIRST(ac);
122                 
123                 for (ale = anim_data.first; ale; ale = ale->next) {
124                         float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
125                         float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
126                         
127                         /* check if visible */
128                         if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
129                             IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
130                         {
131                                 /* draw all channels using standard channel-drawing API */
132                                 ANIM_channel_draw_widgets(C, ac, ale, block, yminc, ymaxc, channel_index);
133                         }
134                         
135                         /* adjust y-position for next one */
136                         y -= ACHANNEL_STEP(ac);
137                         channel_index++;
138                 }
139                 
140                 UI_block_end(C, block);
141                 UI_block_draw(C, block);
142         }
143         
144         /* free tempolary channels */
145         ANIM_animdata_freelist(&anim_data);
146 }
147
148 /* ************************************************************************* */
149 /* Keyframes */
150
151 /* extra padding for lengths (to go under scrollers) */
152 #define EXTRA_SCROLL_PAD    100.0f
153
154 /* draw keyframes in each channel */
155 void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
156 {
157         ListBase anim_data = {NULL, NULL};
158         bAnimListElem *ale;
159         int filter;
160         
161         View2D *v2d = &ar->v2d;
162         bDopeSheet *ads = &saction->ads;
163         AnimData *adt = NULL;
164         
165         float act_start, act_end, y;
166         size_t items;
167         int height;
168         
169         unsigned char col1[3], col2[3];
170         unsigned char col1a[3], col2a[3];
171         unsigned char col1b[3], col2b[3];
172         
173         
174         /* get theme colors */
175         UI_GetThemeColor3ubv(TH_BACK, col2);
176         UI_GetThemeColor3ubv(TH_HILITE, col1);
177         
178         UI_GetThemeColor3ubv(TH_GROUP, col2a);
179         UI_GetThemeColor3ubv(TH_GROUP_ACTIVE, col1a);
180         
181         UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELOB, col1b);
182         UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELSUBOB, col2b);
183         
184         /* set view-mapping rect (only used for x-axis), for NLA-scaling mapping with less calculation */
185
186         /* if in NLA there's a strip active, map the view */
187         if (ac->datatype == ANIMCONT_ACTION) {
188                 /* adt = ANIM_nla_mapping_get(ac, NULL); */ /* UNUSED */
189                 
190                 /* start and end of action itself */
191                 calc_action_range(ac->data, &act_start, &act_end, 0);
192         }
193         
194         /* build list of channels to draw */
195         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
196         items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
197         
198         height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac)));
199         /* don't use totrect set, as the width stays the same 
200          * (NOTE: this is ok here, the configuration is pretty straightforward) 
201          */
202         v2d->tot.ymin = (float)(-height);
203         
204         /* first backdrop strips */
205         y = (float)(-ACHANNEL_HEIGHT(ac));
206         glEnable(GL_BLEND);
207         
208         for (ale = anim_data.first; ale; ale = ale->next) {
209                 const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
210                 const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
211                 
212                 /* check if visible */
213                 if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
214                     IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
215                 {
216                         const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
217                         int sel = 0;
218                         
219                         /* determine if any need to draw channel */
220                         if (ale->datatype != ALE_NONE) {
221                                 /* determine if channel is selected */
222                                 if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT))
223                                         sel = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT);
224                                 
225                                 if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) {
226                                         switch (ale->type) {
227                                                 case ANIMTYPE_SUMMARY:
228                                                 {
229                                                         /* reddish color from NLA */
230                                                         UI_ThemeColor4(TH_ANIM_ACTIVE);
231                                                         break;
232                                                 }
233                                                 case ANIMTYPE_SCENE:
234                                                 case ANIMTYPE_OBJECT:
235                                                 {
236                                                         if (sel) glColor4ub(col1b[0], col1b[1], col1b[2], 0x45); 
237                                                         else glColor4ub(col1b[0], col1b[1], col1b[2], 0x22); 
238                                                         break;
239                                                 }
240                                                 case ANIMTYPE_FILLACTD:
241                                                 case ANIMTYPE_DSSKEY:
242                                                 case ANIMTYPE_DSWOR:
243                                                 {
244                                                         if (sel) glColor4ub(col2b[0], col2b[1], col2b[2], 0x45); 
245                                                         else glColor4ub(col2b[0], col2b[1], col2b[2], 0x22); 
246                                                         break;
247                                                 }
248                                                 case ANIMTYPE_GROUP:
249                                                 {
250                                                         if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22);
251                                                         else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22);
252                                                         break;
253                                                 }
254                                                 default:
255                                                 {
256                                                         if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
257                                                         else glColor4ub(col2[0], col2[1], col2[2], 0x22);
258                                                         break;
259                                                 }
260                                         }
261                                         
262                                         /* draw region twice: firstly backdrop, then the current range */
263                                         glRectf(v2d->cur.xmin,  (float)y - ACHANNEL_HEIGHT_HALF(ac),  v2d->cur.xmax + EXTRA_SCROLL_PAD,  (float)y + ACHANNEL_HEIGHT_HALF(ac));
264                                         
265                                         if (ac->datatype == ANIMCONT_ACTION)
266                                                 glRectf(act_start,  (float)y - ACHANNEL_HEIGHT_HALF(ac),  act_end,  (float)y + ACHANNEL_HEIGHT_HALF(ac));
267                                 }
268                                 else if (ac->datatype == ANIMCONT_GPENCIL) {
269                                         /* frames less than one get less saturated background */
270                                         if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
271                                         else glColor4ub(col2[0], col2[1], col2[2], 0x22);
272                                         glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac));
273                                         
274                                         /* frames one and higher get a saturated background */
275                                         if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44);
276                                         else glColor4ub(col2[0], col2[1], col2[2], 0x44);
277                                         glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD,  (float)y + ACHANNEL_HEIGHT_HALF(ac));
278                                 }
279                                 else if (ac->datatype == ANIMCONT_MASK) {
280                                         /* TODO --- this is a copy of gpencil */
281                                         /* frames less than one get less saturated background */
282                                         if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
283                                         else glColor4ub(col2[0], col2[1], col2[2], 0x22);
284                                         glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac));
285
286                                         /* frames one and higher get a saturated background */
287                                         if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44);
288                                         else glColor4ub(col2[0], col2[1], col2[2], 0x44);
289                                         glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD,  (float)y + ACHANNEL_HEIGHT_HALF(ac));
290                                 }
291                         }
292                 }
293                 
294                 /*      Increment the step */
295                 y -= ACHANNEL_STEP(ac);
296         }
297         glDisable(GL_BLEND);
298         
299         /* Draw keyframes 
300          *      1) Only channels that are visible in the Action Editor get drawn/evaluated.
301          *         This is to try to optimize this for heavier data sets
302          *      2) Keyframes which are out of view horizontally are disregarded 
303          */
304         y = (float)(-ACHANNEL_HEIGHT(ac));
305         
306         for (ale = anim_data.first; ale; ale = ale->next) {
307                 const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
308                 const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
309                 
310                 /* check if visible */
311                 if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
312                     IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
313                 {
314                         /* check if anything to show for this channel */
315                         if (ale->datatype != ALE_NONE) {
316                                 adt = ANIM_nla_mapping_get(ac, ale);
317                                 
318                                 /* draw 'keyframes' for each specific datatype */
319                                 switch (ale->datatype) {
320                                         case ALE_ALL:
321                                                 draw_summary_channel(v2d, ale->data, y, ac->yscale_fac);
322                                                 break;
323                                         case ALE_SCE:
324                                                 draw_scene_channel(v2d, ads, ale->key_data, y, ac->yscale_fac);
325                                                 break;
326                                         case ALE_OB:
327                                                 draw_object_channel(v2d, ads, ale->key_data, y, ac->yscale_fac);
328                                                 break;
329                                         case ALE_ACT:
330                                                 draw_action_channel(v2d, adt, ale->key_data, y, ac->yscale_fac);
331                                                 break;
332                                         case ALE_GROUP:
333                                                 draw_agroup_channel(v2d, adt, ale->data, y, ac->yscale_fac);
334                                                 break;
335                                         case ALE_FCURVE:
336                                                 draw_fcurve_channel(v2d, adt, ale->key_data, y, ac->yscale_fac);
337                                                 break;
338                                         case ALE_GPFRAME:
339                                                 draw_gpl_channel(v2d, ads, ale->data, y, ac->yscale_fac);
340                                                 break;
341                                         case ALE_MASKLAY:
342                                                 draw_masklay_channel(v2d, ads, ale->data, y, ac->yscale_fac);
343                                                 break;
344                                 }
345                         }
346                 }
347                 
348                 y -= ACHANNEL_STEP(ac);
349         }
350         
351         /* free tempolary channels used for drawing */
352         ANIM_animdata_freelist(&anim_data);
353
354         /* black line marking 'current frame' for Time-Slide transform mode */
355         if (saction->flag & SACTION_MOVING) {
356                 glColor3f(0.0f, 0.0f, 0.0f);
357                 
358                 glBegin(GL_LINES);
359                 glVertex2f(saction->timeslide, v2d->cur.ymin - EXTRA_SCROLL_PAD);
360                 glVertex2f(saction->timeslide, v2d->cur.ymax);
361                 glEnd();
362         }
363 }