src/tracks/labeltrack/ui/LabelTrackView.cpp
/// ComputeTextPosition is 'smart' about where to display
/// the label text.
///
/// The text must be displayed between its endpoints x and x1
/// We'd also like it centered between them, and we'd like it on
/// screen.  It isn't always possible to achieve all of this,
/// so we do the best we can.
///
/// This function has a number of tests and adjustments to the
/// text start position.  The tests later in the function will
/// take priority over the ones earlier, so because centering
/// is the first thing we do, it's the first thing we lose if
/// we can't do everything we want to.
ComputeTextPosition is 'smart' about where to display
the label text.

The text must be displayed between its endpoints x and x1
We'd also like it centered between them, and we'd like it on
screen.  It isn't always possible to achieve all of this,
so we do the best we can.

This function has a number of tests and adjustments to the
text start position.  The tests later in the function will
take priority over the ones earlier, so because centering
is the first thing we do, it's the first thing we lose if
we can't do everything we want to.
ComputeTextPosition is ' smart ' about where to display the label text . The text must be displayed between its endpoints x and x1 We ' d also like it centered between them and we ' d like it on screen . It isn ' t always possible to achieve all of this so we do the best we can . This function has a number of tests and adjustments to the text start position . The tests later in the function will take priority over the ones earlier so because centering is the first thing we do it ' s the first thing we lose if we can ' t do everything we want to .
void LabelTrackView::ComputeTextPosition(const wxRect & r, int index) const
{
   const auto pTrack = FindLabelTrack();
   const auto &mLabels = pTrack->GetLabels();
   const auto &labelStruct = mLabels[index];
   const int xExtra=mIconWidth;
   int x     = labelStruct.x;  
   int x1    = labelStruct.x1; 
   int width = labelStruct.width;
   int xText; 
   bool bTooWideForScreen = width > (r.width-2*xExtra);
   bool bSimpleCentering = false;
    Simple centering does its best to keep the text
    centered between the label limits.
    Complex centering positions the text proportionally
    to how far we are through the label.
    If we add preferences for this, we want to be able to
    choose separately whether:
      a) Wide text labels centered simple/complex.
      b) Other text labels centered simple/complex.
   if( bSimpleCentering )
   {
       Center text between the two end points.
      xText = (x+x1-width)/2;
   }
   else
   {
       Calculate xText position to make text line
       scroll sideways evenly as r moves right.
       xText is a linear function of r.x.
       These variables are used to compute that function.
      int rx0,rx1,xText0,xText1;
       Since we will be using a linear function,
       we should blend smoothly between left and right
       aligned text as r, the 'viewport' moves.
      if( bTooWideForScreen )
      {
         rx0=x;            when viewport at label start.
         xText0=x+xExtra;  text aligned left.
         rx1=x1-r.width;   when viewport end at label end
         xText1=x1-(width+xExtra);  text aligned right.
      }
      else
      {
          when label start + width + extra spacing at viewport end..
         rx0=x-r.width+width+2*xExtra;
          ..text aligned left.
         xText0=x+xExtra;
          when viewport start + width + extra spacing at label end..
         rx1=x1-(width+2*xExtra);
          ..text aligned right.
         xText1=x1-(width+xExtra);
      }
      if( rx1 > rx0 )  Avoid divide by zero case.
      {
          Compute the blend between left and right aligned.
          Don't use:
          xText = xText0 + ((xText1-xText0)*(r.x-rx0))/(rx1-rx0);
          The problem with the above is that it integer-oveflows at
          high zoom.
          Instead use:
         xText = xText0 + (int)((xText1-xText0)*(((float)(r.x-rx0))/(rx1-rx0)));
      }
      else
      {
          Avoid divide by zero by reverting to
          simple centering.
          We could also fall into this case if x and x1
          are swapped, in which case we'll end up
          left aligned anyway because code later on
          will catch that.
         xText = (x+x1-width)/2;
      }
   }
    Is the text now appearing partly outside r?
   bool bOffLeft = xText < r.x+xExtra;
   bool bOffRight = xText > r.x+r.width-width-xExtra;
    IF any part of the text is offscreen
    THEN we may bring it back.
   if( bOffLeft == bOffRight )
   {
      IF both sides on screen, THEN nothing to do.
      IF both sides off screen THEN don't do
      anything about it.
      (because if we did, you'd never get to read
      all the text by scrolling).
   }
   else if( bOffLeft != bTooWideForScreen)
   {
       IF we're off on the left, OR we're
       too wide for the screen and off on the right
       (only) THEN align left.
      xText = r.x+xExtra;
   }
   else
   {
       We're off on the right, OR we're
       too wide and off on the left (only)
       SO align right.
      xText =r.x+r.width-width-xExtra;
   }
    But if we've taken the text out from its endpoints
    we must move it back so that it's between the endpoints.
    We test the left end point last because the
    text might not even fit between the endpoints (at this
    zoom factor), and in that case we'd like to position
    the text at the left end point.
   if( xText > (x1-width-xExtra))
      xText=(x1-width-xExtra);
   if( xText < x+xExtra )
      xText=x+xExtra;
   labelStruct.xText = xText;
}
void LabelTrackView :: ComputeTextPosition ( const wxRect & r , int index ) const { const auto pTrack = FindLabelTrack ( ) ; const auto & mLabels = pTrack -> GetLabels ( ) ; const auto & labelStruct = mLabels [ index ] ; const int xExtra = mIconWidth ; int x = labelStruct . x ; int x1 = labelStruct . x1 ; int width = labelStruct . width ; int xText ; bool bTooWideForScreen = width > ( r . width - 2 * xExtra ) ; bool bSimpleCentering = false ; if ( bSimpleCentering ) { xText = ( x + x1 - width ) / 2 ; } else { int rx0 , rx1 , xText0 , xText1 ; if ( bTooWideForScreen ) { rx0 = x ; xText0 = x + xExtra ; rx1 = x1 - r . width ; xText1 = x1 - ( width + xExtra ) ; } else { rx0 = x - r . width + width + 2 * xExtra ; xText0 = x + xExtra ; rx1 = x1 - ( width + 2 * xExtra ) ; xText1 = x1 - ( width + xExtra ) ; } if ( rx1 > rx0 ) { xText = xText0 + ( int ) ( ( xText1 - xText0 ) * ( ( ( float ) ( r . x - rx0 ) ) / ( rx1 - rx0 ) ) ) ; } else { xText = ( x + x1 - width ) / 2 ; } } bool bOffLeft = xText < r . x + xExtra ; bool bOffRight = xText > r . x + r . width - width - xExtra ; if ( bOffLeft == bOffRight ) { } else if ( bOffLeft != bTooWideForScreen ) { xText = r . x + xExtra ; } else { xText = r . x + r . width - width - xExtra ; } if ( xText > ( x1 - width - xExtra ) ) xText = ( x1 - width - xExtra ) ; if ( xText < x + xExtra ) xText = x + xExtra ; labelStruct . xText = xText ; }
ComputeTextPosition is 'smart' about where to display
the label text.
ComputeTextPosition is ' smart ' about where to display the label text .
// xExtra is extra space // between the text and the endpoints. // left endpoint // right endpoint. // This is where the text will end up. // Will the text all fit at this zoom? // bool bSimpleCentering = !bTooWideForScreen; //TODO (possibly): // Add configurable options as to when to use simple // and when complex centering. // // Simple centering does its best to keep the text // centered between the label limits. // // Complex centering positions the text proportionally // to how far we are through the label. // // If we add preferences for this, we want to be able to // choose separately whether: //   a) Wide text labels centered simple/complex. //   b) Other text labels centered simple/complex. // // Center text between the two end points. // Calculate xText position to make text line // scroll sideways evenly as r moves right. // xText is a linear function of r.x. // These variables are used to compute that function. // Since we will be using a linear function, // we should blend smoothly between left and right // aligned text as r, the 'viewport' moves. // when viewport at label start. // text aligned left. // when viewport end at label end // text aligned right. // when label start + width + extra spacing at viewport end.. // ..text aligned left. // when viewport start + width + extra spacing at label end.. // ..text aligned right. // Avoid divide by zero case. // Compute the blend between left and right aligned. // Don't use: // // xText = xText0 + ((xText1-xText0)*(r.x-rx0))/(rx1-rx0); // // The problem with the above is that it integer-oveflows at // high zoom. // Instead use: // Avoid divide by zero by reverting to // simple centering. // // We could also fall into this case if x and x1 // are swapped, in which case we'll end up // left aligned anyway because code later on // will catch that. // Is the text now appearing partly outside r? // IF any part of the text is offscreen // THEN we may bring it back. //IF both sides on screen, THEN nothing to do. //IF both sides off screen THEN don't do //anything about it. //(because if we did, you'd never get to read //all the text by scrolling). // IF we're off on the left, OR we're // too wide for the screen and off on the right // (only) THEN align left. // We're off on the right, OR we're // too wide and off on the left (only) // SO align right. // But if we've taken the text out from its endpoints // we must move it back so that it's between the endpoints. // We test the left end point last because the // text might not even fit between the endpoints (at this // zoom factor), and in that case we'd like to position // the text at the left end point.