/** * Generate time string and store in \a str * * \param str: destination string * \param maxncpy: maximum number of characters to copy ``sizeof(str)`` * \param power: special setting for #View2D grid drawing, * used to specify how detailed we need to be * \param time_seconds: time total time in seconds * \return length of \a str * * \note in some cases this is used to print non-seconds values. */ size_t BLI_timecode_string_from_time_seconds( char *str, const size_t maxncpy, const int power, const float time_seconds) { size_t rlen; /* round to whole numbers if power is >= 1 (i.e. scale is coarse) */ if (power <= 0) { rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds); } else { rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds)); } return rlen; }
/* add the relevant text to the cache of text-strings to draw in pixelspace */ static void nla_draw_strip_text(AnimData *adt, NlaTrack *nlt, NlaStrip *strip, int index, View2D *v2d, float xminc, float xmaxc, float yminc, float ymaxc) { const bool non_solo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) && (nlt->flag & NLATRACK_SOLO) == 0); char str[256]; size_t str_len; char col[4]; /* just print the name and the range */ if (strip->flag & NLASTRIP_FLAG_TEMP_META) { str_len = BLI_snprintf_rlen(str, sizeof(str), "%d) Temp-Meta", index); } else { str_len = BLI_strncpy_rlen(str, strip->name, sizeof(str)); } /* set text color - if colors (see above) are light, draw black text, otherwise draw white */ if (strip->flag & (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_TWEAKUSER)) { col[0] = col[1] = col[2] = 0; } else { col[0] = col[1] = col[2] = 255; } /* text opacity depends on whether if there's a solo'd track, this isn't it */ if (non_solo == 0) { col[3] = 255; } else { col[3] = 128; } /* set bounding-box for text * - padding of 2 'units' on either side */ /* TODO: make this centered? */ rctf rect = { .xmin = xminc, .ymin = yminc, .xmax = xmaxc, .ymax = ymaxc, }; /* add this string to the cache of texts to draw */ UI_view2d_text_cache_add_rectf(v2d, &rect, str, str_len, col); }
/* add frame extents to cache of text-strings to draw in pixelspace * for now, only used when transforming strips */ static void nla_draw_strip_frames_text(NlaTrack *UNUSED(nlt), NlaStrip *strip, View2D *v2d, float UNUSED(yminc), float ymaxc) { const float ytol = 1.0f; /* small offset to vertical positioning of text, for legibility */ const char col[4] = {220, 220, 220, 255}; /* light gray */ char numstr[32]; size_t numstr_len; /* Always draw times above the strip, whereas sequencer drew below + above. * However, we should be fine having everything on top, since these tend to be * quite spaced out. * - 1 dp is compromise between lack of precision (ints only, as per sequencer) * while also preserving some accuracy, since we do use floats */ /* start frame */ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->start); UI_view2d_text_cache_add(v2d, strip->start - 1.0f, ymaxc + ytol, numstr, numstr_len, col); /* end frame */ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->end); UI_view2d_text_cache_add(v2d, strip->end, ymaxc + ytol, numstr, numstr_len, col); }
size_t BLI_timecode_string_from_time( char *str, const size_t maxncpy, const int power, const float time_seconds, const double fps, const short timecode_style) { int hours = 0, minutes = 0, seconds = 0, frames = 0; float time = time_seconds; char neg[2] = {'\0'}; size_t rlen; /* get cframes */ if (time < 0) { /* correction for negative cfraues */ neg[0] = '-'; time = -time; } if (time >= 3600.0f) { /* hours */ /* XXX should we only display a single digit for hours since clips are * VERY UNLIKELY to be more than 1-2 hours max? However, that would * go against conventions... */ hours = (int)time / 3600; time = fmodf(time, 3600); } if (time >= 60.0f) { /* minutes */ minutes = (int)time / 60; time = fmodf(time, 60); } if (power <= 0) { /* seconds + frames * Frames are derived from 'fraction' of second. We need to perform some additional rounding * to cope with 'half' frames, etc., which should be fine in most cases */ seconds = (int)time; frames = round_fl_to_int((float)(((double)time - (double)seconds) * fps)); } else { /* seconds (with pixel offset rounding) */ seconds = round_fl_to_int(time); } switch (timecode_style) { case USER_TIMECODE_MINIMAL: { /* - In general, minutes and seconds should be shown, as most clips will be * within this length. Hours will only be included if relevant. * - Only show frames when zoomed in enough for them to be relevant * (using separator of '+' for frames). * When showing frames, use slightly different display to avoid confusion with mm:ss format */ if (power <= 0) { /* include "frames" in display */ if (hours) { rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d+%02d", neg, hours, minutes, seconds, frames); } else if (minutes) { rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d+%02d", neg, minutes, seconds, frames); } else { rlen = BLI_snprintf_rlen(str, maxncpy, "%s%d+%02d", neg, seconds, frames); } } else { /* don't include 'frames' in display */ if (hours) { rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, hours, minutes, seconds); } else { rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d", neg, minutes, seconds); } } break; } case USER_TIMECODE_SMPTE_MSF: { /* reduced SMPTE format that always shows minutes, seconds, frames. Hours only shown as needed. */ if (hours) { rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames); } else { rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, minutes, seconds, frames); } break; } case USER_TIMECODE_MILLISECONDS: { /* reduced SMPTE. Instead of frames, milliseconds are shown */ /* precision of decimal part */ const int ms_dp = (power <= 0) ? (1 - power) : 1; /* to get 2 digit whole-number part for seconds display * (i.e. 3 is for 2 digits + radix, on top of full length) */ const int s_pad = ms_dp + 3; if (hours) { rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%0*.*f", neg, hours, minutes, s_pad, ms_dp, time); } else { rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%0*.*f", neg, minutes, s_pad, ms_dp, time); } break; } case USER_TIMECODE_SUBRIP: { /* SubRip, like SMPTE milliseconds but seconds and milliseconds are separated by a comma, not a dot... */ /* precision of decimal part */ const int ms_dp = (power <= 0) ? (1 - power) : 1; const int ms = round_fl_to_int((time - (float)seconds) * 1000.0f); rlen = BLI_snprintf_rlen( str, maxncpy, "%s%02d:%02d:%02d,%0*d", neg, hours, minutes, seconds, ms_dp, ms); break; } case USER_TIMECODE_SECONDS_ONLY: { /* only show the original seconds display */ /* round to whole numbers if power is >= 1 (i.e. scale is coarse) */ if (power <= 0) { rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds); } else { rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds)); } break; } case USER_TIMECODE_SMPTE_FULL: default: { /* full SMPTE format */ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames); break; } } return rlen; }
/* draw a handle, for each end of a sequence strip */ static void draw_seq_handle(View2D *v2d, Sequence *seq, const float handsize_clamped, const short direction) { float v1[2], v2[2], v3[2], rx1 = 0, rx2 = 0; //for triangles and rect float x1, x2, y1, y2; unsigned int whichsel = 0; x1 = seq->startdisp; x2 = seq->enddisp; y1 = seq->machine + SEQ_STRIP_OFSBOTTOM; y2 = seq->machine + SEQ_STRIP_OFSTOP; /* set up co-ordinates/dimensions for either left or right handle */ if (direction == SEQ_LEFTHANDLE) { rx1 = x1; rx2 = x1 + handsize_clamped * 0.75f; v1[0] = x1 + handsize_clamped / 4; v1[1] = y1 + ( ((y1 + y2) / 2.0f - y1) / 2); v2[0] = x1 + handsize_clamped / 4; v2[1] = y2 - ( ((y1 + y2) / 2.0f - y1) / 2); v3[0] = v2[0] + handsize_clamped / 4; v3[1] = (y1 + y2) / 2.0f; whichsel = SEQ_LEFTSEL; } else if (direction == SEQ_RIGHTHANDLE) { rx1 = x2 - handsize_clamped * 0.75f; rx2 = x2; v1[0] = x2 - handsize_clamped / 4; v1[1] = y1 + ( ((y1 + y2) / 2.0f - y1) / 2); v2[0] = x2 - handsize_clamped / 4; v2[1] = y2 - ( ((y1 + y2) / 2.0f - y1) / 2); v3[0] = v2[0] - handsize_clamped / 4; v3[1] = (y1 + y2) / 2.0f; whichsel = SEQ_RIGHTSEL; } /* draw! */ if (!(seq->type & SEQ_TYPE_EFFECT) || BKE_sequence_effect_get_num_inputs(seq->type) == 0) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if (seq->flag & whichsel) glColor4ub(0, 0, 0, 80); else if (seq->flag & SELECT) glColor4ub(255, 255, 255, 30); else glColor4ub(0, 0, 0, 22); glRectf(rx1, y1, rx2, y2); if (seq->flag & whichsel) glColor4ub(255, 255, 255, 200); else glColor4ub(0, 0, 0, 50); glEnable(GL_POLYGON_SMOOTH); glBegin(GL_TRIANGLES); glVertex2fv(v1); glVertex2fv(v2); glVertex2fv(v3); glEnd(); glDisable(GL_POLYGON_SMOOTH); glDisable(GL_BLEND); } if ((G.moving & G_TRANSFORM_SEQ) || (seq->flag & whichsel)) { const char col[4] = {255, 255, 255, 255}; char numstr[32]; size_t numstr_len; if (direction == SEQ_LEFTHANDLE) { numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", seq->startdisp); x1 = rx1; y1 -= 0.45f; } else { numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", seq->enddisp - 1); x1 = x2 - handsize_clamped * 0.75f; y1 = y2 + 0.05f; } UI_view2d_text_cache_add(v2d, x1, y1, numstr, numstr_len, col); } }
static size_t unit_as_string(char *str, int len_max, double value, int prec, bUnitCollection *usys, /* non exposed options */ const bUnitDef *unit, char pad) { double value_conv; size_t len, i; if (unit) { /* use unit without finding the best one */ } else if (value == 0.0) { /* use the default units since there is no way to convert */ unit = unit_default(usys); } else { unit = unit_best_fit(value, usys, NULL, 1); } value_conv = value / unit->scalar; /* Convert to a string */ len = BLI_snprintf_rlen(str, len_max, "%.*f", prec, value_conv); /* Add unit prefix and strip zeros */ /* replace trailing zero's with spaces * so the number is less complicated but alignment in a button wont * jump about while dragging */ i = len - 1; if (prec > 0) { while (i > 0 && str[i] == '0') { /* 4.300 -> 4.3 */ str[i--] = pad; } if (i > 0 && str[i] == '.') { /* 10. -> 10 */ str[i--] = pad; } } /* Now add the suffix */ if (i < len_max) { int j = 0; i++; while (unit->name_short[j] && (i < len_max)) { str[i++] = unit->name_short[j++]; } #if 0 if (pad) { /* this loop only runs if so many zeros were removed that * the unit name only used padded chars, * In that case add padding for the name. */ while (i <= len + j && (i < len_max)) { str[i++] = pad; } } #endif } /* terminate no matter whats done with padding above */ if (i >= len_max) i = len_max - 1; str[i] = '\0'; return i; }