RobinSchmidt / RS-MET

Codebase for RS-MET products (Robin Schmidt's Music Engineering Tools)
Other
57 stars 6 forks source link

filmstrip for knobs/sliders? #222

Open elanhickler opened 6 years ago

elanhickler commented 6 years ago

I may need to use filmstrip for certain ui elements.

RobinSchmidt commented 6 years ago

how did you implement the custom ui in fmd? did you subclass all the relevant widget classes? or do you use the setPainter mechanism that i added to RSlider for this purpose? i could certainly add a "FilmStripSliderPainter" class or something like that to my library

elanhickler commented 6 years ago

my SVGKnob class inherits from ModulatableSlider. I override paint method.

RobinSchmidt commented 6 years ago

hmm..ok. so how do you want that to work? i could imagine to do something like:

FilmStripSliderPainter : public RSliderPainter
{
public:
  setFilmStrip(juce::Image* filmStripToUse, int numSnapshots, bool isVertical);
}

and then you could instantiate an object of that class and pass it to the sliders. a similar mechanism could be implemented for buttons. the outlying class (your editor class) would then be responsible to take care of the filmstrip image object (and ensure that its lifetime is longer than the lifetime of the widgets and painter)

elanhickler commented 6 years ago

yes, that will work. please auto-calculate num snapshots and isVertical.

numsnapshots and isVertical is x/y or y/x depending on which axis is longer.

RobinSchmidt commented 6 years ago

that would assume that one frame is exactly square. but maybe the library should not necessarily assume that - for generality. ...but perhaps the best would be to allow both and make these arguments optional....but yeah...the "isVertical" is probably indeed not needed.....hmm...or maybe for horizontal/vertical faders with very low "snapshot-resolution" (think of a wide horizontal fader with a low number of snapshots or something)....but yeah...normally, your heuristic should work

elanhickler commented 6 years ago

then allow for the input of the resolution of a single frame. In my experience that would be less annoying than trying to remember isVertical and number of frames, because no software helps you figure out number of frames. But it is much easier to get the resolution of a single frame.

RobinSchmidt commented 6 years ago

ok - i see. then maybe just the width or height should be passed (because the other one would then be redundant)...we'll see..but yeah

setFilmStrip(juce::Image* filmStripToUse, int frameWidth, int frameHeight);

seems reasonable. maybe with default arguments zero - and if they are zero indeed in a call, the functions applies heuristics

elanhickler commented 6 years ago

done. If you implement this into your library I could delete mine and reference yours.

edit: I think I should start a library of convenience classes for doing synth UI

class FilmstripPainter
{
public:
  FilmstripPainter() = default;

  void setImageAndFrameSize(Image * v, int singleFrameWidth, int singleFrameHeight)
  {
    image = v;
    imageIsVertical = image->getBounds().getWidth() < image->getBounds().getHeight();

    frameSizeWidth = singleFrameWidth;
    frameSizeHeight = singleFrameHeight;

    numFrames = imageIsVertical ?
      image->getBounds().getHeight() / frameSizeHeight      
      :
      image->getBounds().getWidth() / frameSizeWidth
      ;

    numFrames -= 1;
  }

  ~FilmstripPainter() = default;

  void draw(Graphics & g, juce::Rectangle<int> area, float normalizedValue)
  {
    if (imageIsVertical)
    {
      frameX = 0;
      frameY = (int)round(normalizedValue * numFrames) * frameSizeHeight;
    }
    else
    {
      frameX = (int)round(normalizedValue * numFrames) * frameSizeWidth;
      frameY = 0;
    }

    g.drawImage(*image, area.getX(), area.getY(), area.getWidth(), area.getHeight(), frameX, frameY, frameSizeWidth, frameSizeHeight);
  }

protected:

  Image * image;

  int frameSizeWidth = 0;
  int frameSizeHeight = 0;

  //coefficients
  bool imageIsVertical;
  int numFrames;
  int frameX;
  int frameY;
};
RobinSchmidt commented 6 years ago

If you implement this into your library I could delete mine and reference yours.

you mean, i could just take this code as is and add it to my library?

elanhickler commented 6 years ago

yes you can use this code if you want

elanhickler commented 6 years ago

you'll want to add stuff like getFrameWidth / getFrameHeight.

I'm going to need to add more features to this class in the future, for example, to scale correctly for eventual resizable interfaces, and for retina display. Will keep my own version.