Intervals on timeline are now graphically proportional to time:

- intervals are only valid when using key shortcuts
 - using the mouse to select/scroll does not show proper proportions yet
This commit is contained in:
Stephen Anthony 2018-01-28 20:11:21 -03:30
parent 63acb76911
commit b11643881a
5 changed files with 51 additions and 18 deletions

View File

@ -129,6 +129,12 @@ class LinkedObjectPool
*/ */
const_iter next(const_iter i) const { return std::next(i, 1); } const_iter next(const_iter i) const { return std::next(i, 1); }
/**
Canonical iterators from C++ STL.
*/
const_iter cbegin() const { return myList.cbegin(); }
const_iter cend() const { return myList.cend(); }
/** /**
Answer whether 'current' is at the specified iterator. Answer whether 'current' is at the specified iterator.
*/ */

View File

@ -344,7 +344,7 @@ IntArray RewindManager::cyclesList() const
IntArray arr; IntArray arr;
uInt64 firstCycle = getFirstCycles(); uInt64 firstCycle = getFirstCycles();
for(auto it = myStateList.first(); it != myStateList.last(); ++it) for(auto it = myStateList.cbegin(); it != myStateList.cend(); ++it)
arr.push_back(uInt32(it->cycles - firstCycle)); arr.push_back(uInt32(it->cycles - firstCycle));
return arr; return arr;

View File

@ -25,13 +25,16 @@
#include "TimeLineWidget.hxx" #include "TimeLineWidget.hxx"
// TODO - remove all references to _stepValue__
// - fix posToValue to use _stepValue
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TimeLineWidget::TimeLineWidget(GuiObject* boss, const GUI::Font& font, TimeLineWidget::TimeLineWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h, int x, int y, int w, int h,
const string& label, int labelWidth, int cmd) const string& label, int labelWidth, int cmd)
: ButtonWidget(boss, font, x, y, w, h, label, cmd), : ButtonWidget(boss, font, x, y, w, h, label, cmd),
_value(0), _value(0),
_stepValue(1), _stepValue__(1),
_valueMin(0), _valueMin(0),
_valueMax(100), _valueMax(100),
_isDragging(false), _isDragging(false),
@ -45,6 +48,8 @@ TimeLineWidget::TimeLineWidget(GuiObject* boss, const GUI::Font& font,
_labelWidth = _font.getStringWidth(_label); _labelWidth = _font.getStringWidth(_label);
_w = w + _labelWidth; _w = w + _labelWidth;
_stepValue.reserve(100);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -73,13 +78,24 @@ void TimeLineWidget::setMaxValue(int value)
_valueMax = value; _valueMax = value;
} }
#if 0
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeLineWidget::setStepValue(int value) void TimeLineWidget::setStepValues(const IntArray& steps)
{ {
_stepValue = value; // Try to allocate as infrequently as possible
if(steps.size() > _stepValue.capacity())
_stepValue.reserve(2 * steps.size());
_stepValue.clear();
double scale = (_w - _labelWidth - 4) / double(steps.back());
// Skip the very last value; we take care of it outside the end of the loop
for(uInt32 i = 0; i < steps.size() - 1; ++i)
_stepValue.push_back(int(steps[i] * scale));
// Due to integer <-> double conversion, the last value is sometimes
// slightly less than the maximum value; we assign it manually to fix this
_stepValue.push_back(_w - _labelWidth - 4);
} }
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeLineWidget::handleMouseMoved(int x, int y) void TimeLineWidget::handleMouseMoved(int x, int y)
@ -132,13 +148,13 @@ bool TimeLineWidget::handleEvent(Event::Type e)
case Event::UIDown: case Event::UIDown:
case Event::UILeft: case Event::UILeft:
case Event::UIPgDown: case Event::UIPgDown:
setValue(_value - _stepValue); setValue(_value - _stepValue__);
break; break;
case Event::UIUp: case Event::UIUp:
case Event::UIRight: case Event::UIRight:
case Event::UIPgUp: case Event::UIPgUp:
setValue(_value + _stepValue); setValue(_value + _stepValue__);
break; break;
case Event::UIHome: case Event::UIHome:
@ -196,9 +212,14 @@ int TimeLineWidget::valueToPos(int value)
{ {
if(value < _valueMin) value = _valueMin; if(value < _valueMin) value = _valueMin;
else if(value > _valueMax) value = _valueMax; else if(value > _valueMax) value = _valueMax;
int range = std::max(_valueMax - _valueMin, 1); // don't divide by zero
return ((_w - _labelWidth - 4) * (value - _valueMin) / range); int real = _stepValue[BSPF::clamp(value, _valueMin, _valueMax)];
#if 0
int range = std::max(_valueMax - _valueMin, 1); // don't divide by zero
int actual = ((_w - _labelWidth - 4) * (value - _valueMin) / range);
cerr << "i=" << value << " real=" << real << endl << "actual=" << actual << endl << endl;
#endif
return real;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -207,5 +228,5 @@ int TimeLineWidget::posToValue(int pos)
int value = (pos) * (_valueMax - _valueMin) / (_w - _labelWidth - 4) + _valueMin; int value = (pos) * (_valueMax - _valueMin) / (_w - _labelWidth - 4) + _valueMin;
// Scale the position to the correct interval (according to step value) // Scale the position to the correct interval (according to step value)
return value - (value % _stepValue); return value - (value % _stepValue__);
} }

View File

@ -34,10 +34,12 @@ class TimeLineWidget : public ButtonWidget
int getMinValue() const { return _valueMin; } int getMinValue() const { return _valueMin; }
void setMaxValue(int value); void setMaxValue(int value);
int getMaxValue() const { return _valueMax; } int getMaxValue() const { return _valueMax; }
#if 0
void setStepValue(int value); /**
int getStepValue() const { return _stepValue; } Steps are not necessarily linear in a timeline, so we need info
#endif on each interval instead.
*/
void setStepValues(const IntArray& steps);
protected: protected:
void handleMouseMoved(int x, int y) override; void handleMouseMoved(int x, int y) override;
@ -52,11 +54,13 @@ class TimeLineWidget : public ButtonWidget
int posToValue(int pos); int posToValue(int pos);
protected: protected:
int _value, _stepValue; int _value, _stepValue__;
int _valueMin, _valueMax; int _valueMin, _valueMax;
bool _isDragging; bool _isDragging;
int _labelWidth; int _labelWidth;
IntArray _stepValue;
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported
TimeLineWidget() = delete; TimeLineWidget() = delete;

View File

@ -192,6 +192,7 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
tl_y = ypos + (myCurrentIdxWidget->getHeight() - tl_h) / 2, tl_y = ypos + (myCurrentIdxWidget->getHeight() - tl_h) / 2,
tl_w = myLastIdxWidget->getAbsX() - tl_x - 8; tl_w = myLastIdxWidget->getAbsX() - tl_x - 8;
myTimeline = new TimeLineWidget(this, font, tl_x, tl_y, tl_w, tl_h, "", 0, kTimeline); myTimeline = new TimeLineWidget(this, font, tl_x, tl_y, tl_w, tl_h, "", 0, kTimeline);
myTimeline->setMinValue(0);
ypos += rowHeight; ypos += rowHeight;
// Add time info // Add time info
@ -252,8 +253,9 @@ void TimeMachineDialog::loadConfig()
RewindManager& r = instance().state().rewindManager(); RewindManager& r = instance().state().rewindManager();
IntArray cycles = r.cyclesList(); IntArray cycles = r.cyclesList();
// Set range for timeline // Set range and intervals for timeline
myTimeline->setMaxValue(std::max(Int32(cycles.size()), 1)); myTimeline->setMaxValue(cycles.size() - 1);
myTimeline->setStepValues(cycles);
// Enable blending (only once is necessary) // Enable blending (only once is necessary)
if(!surface().attributes().blending) if(!surface().attributes().blending)