Merge branch 'master' into konero_svg_icons

This commit is contained in:
Jeremy Bullock 2017-07-23 14:38:57 -06:00 committed by GitHub
commit e8422eb87f
44 changed files with 4295 additions and 1806 deletions

View file

@ -125,9 +125,12 @@ bool isDouble(std::wstring s) { return isDouble(::to_string(s)); }
std::string toUpper(std::string a) {
#ifdef _WIN32
return _strupr(const_cast<char *>(a.c_str()));
size_t size = a.size();
const char* cstr = a.c_str();
std::vector<char> buf(cstr, cstr + size + 1);
return _strupr(&buf[0]);
#else
std::string ret = a;
std::string ret(a);
for (int i = 0; i < (int)ret.length(); i++) ret[i] = toupper(ret[i]);
return ret;
#endif
@ -135,9 +138,12 @@ std::string toUpper(std::string a) {
std::string toLower(std::string a) {
#ifdef _WIN32
return _strlwr(const_cast<char *>(a.c_str()));
size_t size = a.size();
const char* cstr = a.c_str();
std::vector<char> buf(cstr, cstr + size + 1);
return _strlwr(&buf[0]);
#else
std::string ret = a;
std::string ret(a);
for (int i = 0; i < (int)ret.length(); i++) ret[i] = tolower(ret[i]);
return ret;
#endif
@ -145,27 +151,26 @@ std::string toLower(std::string a) {
std::wstring toUpper(std::wstring a) {
#ifdef _WIN32
return _wcsupr(const_cast<wchar_t *>(a.c_str()));
size_t size = a.size();
const wchar_t* cstr = a.c_str();
std::vector<wchar_t> buf(cstr, cstr + size + 1);
return _wcsupr(&buf[0]);
#else
std::wstring ret;
for (int i = 0; i < (int)a.length(); i++) {
wchar_t c = towupper(a[i]);
ret += c;
}
std::wstring ret(a);
for (int i = 0; i < (int)ret.length(); i++) ret[i] = towupper(ret[i]);
return ret;
#endif
}
std::wstring toLower(std::wstring a) {
#ifdef _WIN32
return _wcslwr(const_cast<wchar_t *>(a.c_str()));
size_t size = a.size();
const wchar_t* cstr = a.c_str();
std::vector<wchar_t> buf(cstr, cstr + size + 1);
return _wcslwr(&buf[0]);
#else
const int length = (int)a.length();
std::wstring ret;
ret.resize(length);
for (int i = 0; i < length; i++) {
ret[i] = towlower(a[i]);
}
std::wstring ret(a);
for (int i = 0; i < (int)ret.length(); i++) ret[i] = towlower(ret[i]);
return ret;
#endif
}

View file

@ -0,0 +1,58 @@
#pragma once
#ifndef CELL_POSITION_INCLUDED
#define CELL_POSITION_INCLUDED
#include <algorithm>
using std::min;
using std::max;
// Identifies cells by frame and layer rather than row and column
class CellPosition {
int _frame; // a frame number. corresponds to row in vertical xsheet
int _layer; // a layer number. corresponds to col in vertical xsheet
public:
CellPosition() : _frame(0), _layer(0) {}
CellPosition(int frame, int layer) : _frame(frame), _layer(layer) {}
int frame() const { return _frame; }
int layer() const { return _layer; }
void setFrame(int frame) { _frame = frame; }
void setLayer(int layer) { _layer = layer; }
CellPosition &operator=(const CellPosition &that) = default;
operator bool() const { return _frame || _layer; }
CellPosition operator+(const CellPosition &add) {
return CellPosition(_frame + add._frame, _layer + add._layer);
}
CellPosition operator*(const CellPosition &mult) {
return CellPosition(_frame * mult._frame, _layer * mult._layer);
}
void ensureValid() {
if (_frame < 0) _frame = 0;
if (_layer < 0) _layer = 0;
}
};
// A square range identified by two corners
class CellRange {
CellPosition _from, _to; // from.frame <= to.frame && from.layer <= to.layer
public:
CellRange() {}
CellRange(const CellPosition &from, const CellPosition &to)
: _from(min(from.frame(), to.frame()), min(from.layer(), to.layer()))
, _to(max(from.frame(), to.frame()), max(from.layer(), to.layer())) {}
const CellPosition &from() const { return _from; }
const CellPosition &to() const { return _to; }
CellRange &operator=(const CellRange &that) = default;
};
#endif

View file

@ -0,0 +1,243 @@
#pragma once
#ifndef ORIENTATION_INCLUDED
#define ORIENTATION_INCLUDED
#undef DVAPI
#undef DVVAR
#ifdef TOONZLIB_EXPORTS
#define DVAPI DV_EXPORT_API
#define DVVAR DV_EXPORT_VAR
#else
#define DVAPI DV_IMPORT_API
#define DVVAR DV_IMPORT_VAR
#endif
#include "tcommon.h"
#include "cellposition.h"
#include "toonz/cellpositionratio.h"
#include <QPoint>
#include <QLine>
#include <QRect>
#include <QPainterPath>
#include <map>
#include <vector>
using std::vector;
using std::map;
// Defines timeline direction: top to bottom; left to right.
// old (vertical timeline) = new (universal) = old (kept)
// x = layer axis = column
// y = frame axis = row
// A pair of numbers
class DVAPI NumberRange {
int _from, _to; // _from <= _to
NumberRange() : _from(0), _to(0) {}
public:
NumberRange(int from, int to) : _from(min(from, to)), _to(max(from, to)) {}
int from() const { return _from; }
int to() const { return _to; }
int length() const { return _to - _from; }
int middle() const { return (_to + _from) / 2; }
int weight(double toWeight) const;
double ratio(int at) const;
NumberRange adjusted(int addFrom, int addTo) const;
};
class ColumnFan;
class QPixmap;
class QPainterPath;
//! lists predefined rectangle sizes and positions (relative to top left corner
//! of a cell)
enum class PredefinedRect {
CELL, //! size of a cell
DRAG_HANDLE_CORNER, //! area for dragging a cell
KEY_ICON, //! position of key icon
CELL_NAME, //! cell name box
CELL_NAME_WITH_KEYFRAME, //! cell name box when keyframe is displayed
END_EXTENDER, //! bottom / right extender
BEGIN_EXTENDER, //! top / left extender
KEYFRAME_AREA, //! part of cell dedicated to key frames
DRAG_AREA, //! draggable side bar
SOUND_TRACK, //! area dedicated to waveform display
PREVIEW_TRACK, //! sound preview area
BEGIN_SOUND_EDIT, //! top sound resize
END_SOUND_EDIT, //! bottom sound resize
NOTE_AREA, //! size of top left note controls
NOTE_ICON, //! size of note icons that appear in cells area
FRAME_LABEL, //! area for writing frame number
FRAME_HEADER,
LAYER_HEADER,
FOLDED_LAYER_HEADER, //! size of layer header when it is folded
PLAY_RANGE, //! area for play range marker within frame header
ONION, //! onion handle placement
ONION_DOT, //! moveable dot placement
ONION_DOT_FIXED, //! fixed dot placement
ONION_AREA, //! area where mouse events will alter onion
ONION_FIXED_DOT_AREA,
ONION_DOT_AREA,
PINNED_CENTER_KEY, //! displays a small blue number
RENAME_COLUMN, //! where column rename control appears after clicking
EYE_AREA, //! clickable area larger than the eye, containing it
EYE, //! the eye itself
PREVIEW_LAYER_AREA, //! clickable area larger than preview icon, containing
//! it
PREVIEW_LAYER,
LOCK_AREA, //! clickable area larger than lock icon, containing it
LOCK, //! the lock icon itself
DRAG_LAYER, //! draggable area in layer header
LAYER_NAME, //! where to display column name. clicking will rename
LAYER_NUMBER, //! where to display column number.
SOUND_ICON,
VOLUME_TRACK, //! area where track is displayed
VOLUME_AREA, //! active area for volume control
LOOP_ICON, //! area for repeat animation icon
LAYER_HEADER_PANEL, //! panel displaying headers for the layer rows in
//! timeline mode
THUMBNAIL_AREA, //! area for header thumbnails and other icons
THUMBNAIL, //! the actual thumbnail, if there is one
PEGBAR_NAME, //! where to display pegbar name
PARENT_HANDLE_NAME, //! where to display parent handle number
FILTER_COLOR //! where to show layer's filter color
};
enum class PredefinedLine {
LOCKED, //! dotted vertical line when cell is locked
SEE_MARKER_THROUGH, //! horizontal marker visible through drag handle
CONTINUE_LEVEL, //! level with the same name represented by vertical line
CONTINUE_LEVEL_WITH_NAME, //! adjusted when level name is on each marker
EXTENDER_LINE //! see grid through extender handle
};
enum class PredefinedDimension {
LAYER, //! width of a layer column / height of layer row
FRAME, //! height of frame row / width of frame column
INDEX, //! index of this orientation in the array of all
SOUND_AMPLITUDE, //! amplitude of sound track, in pixels
FRAME_LABEL_ALIGN, //! alignment flag for frame number
ONION_TURN, //! onion handle turn in degrees
QBOXLAYOUT_DIRECTION, //! direction of QBoxLayout
CENTER_ALIGN, //! horizontal / vertical align
};
enum class PredefinedPath {
DRAG_HANDLE_CORNER, //! triangle corner at drag sidebar
BEGIN_EASE_TRIANGLE, //! triangle marking beginning of ease range
END_EASE_TRIANGLE, //! triangle marking end of ease range
BEGIN_PLAY_RANGE, //! play range markers
END_PLAY_RANGE,
VOLUME_SLIDER_TRACK, //! slider track
VOLUME_SLIDER_HEAD //! slider head
};
enum class PredefinedPoint {
KEY_HIDDEN, //! move extender handle that much if key icons are disabled
EXTENDER_XY_RADIUS, //! x and y radius for rounded rectangle
VOLUME_DIVISIONS_TOP_LEFT //! where to draw volume slider
};
enum class PredefinedRange {
HEADER_FRAME, //! size of of column header height(v) / row header width(h)
HEADER_LAYER, //! size of row header width(v) / column header height(h)
};
// Knows everything about geometry of a particular orientation.
class DVAPI Orientation {
protected:
map<PredefinedRect, QRect> _rects;
map<PredefinedLine, QLine> _lines;
map<PredefinedDimension, int> _dimensions;
map<PredefinedPath, QPainterPath> _paths;
map<PredefinedPoint, QPoint> _points;
map<PredefinedRange, NumberRange> _ranges;
public:
virtual CellPosition xyToPosition(const QPoint &xy,
const ColumnFan *fan) const = 0;
virtual QPoint positionToXY(const CellPosition &position,
const ColumnFan *fan) const = 0;
virtual CellPositionRatio xyToPositionRatio(const QPoint &xy) const = 0;
virtual QPoint positionRatioToXY(const CellPositionRatio &ratio) const = 0;
virtual int colToLayerAxis(int layer, const ColumnFan *fan) const = 0;
virtual int rowToFrameAxis(int frame) const = 0;
virtual QPoint frameLayerToXY(int frameAxis, int layerAxis) const = 0;
QRect frameLayerRect(const NumberRange &frameAxis,
const NumberRange &layerAxis) const;
virtual NumberRange layerSide(const QRect &area) const = 0;
virtual NumberRange frameSide(const QRect &area) const = 0;
virtual int layerAxis(const QPoint &xy) const = 0;
virtual int frameAxis(const QPoint &xy) const = 0;
//! top right corner in vertical layout. bottom left in horizontal
virtual QPoint topRightCorner(const QRect &area) const = 0;
QRect foldedRectangle(int layerAxis, const NumberRange &frameAxis,
int i) const;
QLine foldedRectangleLine(int layerAxis, const NumberRange &frameAxis,
int i) const;
virtual CellPosition arrowShift(int direction) const = 0;
//! line was vertical in vertical timeline. adjust accordingly
QLine verticalLine(int layerAxis, const NumberRange &frameAxis) const;
QLine horizontalLine(int frameAxis, const NumberRange &layerAxis) const;
virtual bool isVerticalTimeline() const = 0;
virtual bool flipVolume() const = 0;
virtual QString name() const = 0;
virtual QString caption() const = 0;
virtual const Orientation *next() const = 0;
const QRect &rect(PredefinedRect which) const { return _rects.at(which); }
const QLine &line(PredefinedLine which) const { return _lines.at(which); }
int dimension(PredefinedDimension which) const {
return _dimensions.at(which);
}
const QPainterPath &path(PredefinedPath which) const {
return _paths.at(which);
}
const QPoint &point(PredefinedPoint which) const { return _points.at(which); }
const NumberRange &range(PredefinedRange which) const {
return _ranges.at(which);
}
virtual int cellWidth() const = 0;
virtual int cellHeight() const = 0;
protected:
void addRect(PredefinedRect which, const QRect &rect);
void addLine(PredefinedLine which, const QLine &line);
void addDimension(PredefinedDimension which, int dimension);
void addPath(PredefinedPath which, const QPainterPath &path);
void addPoint(PredefinedPoint which, const QPoint &point);
void addRange(PredefinedRange which, const NumberRange &range);
};
// Enumerates all orientations available in the system as global const objects.
class DVAPI Orientations {
const Orientation *_topToBottom, *_leftToRight;
vector<const Orientation *> _all;
Orientations();
public:
~Orientations();
static const Orientations &instance();
static const int COUNT = 2;
static const Orientation *topToBottom();
static const Orientation *leftToRight();
static const vector<const Orientation *> &all();
static const Orientation *byName(const QString &name);
};
#endif

View file

@ -0,0 +1,18 @@
#pragma once
#ifndef SAVE_LOAD_QSETTINGS_INCLUDED
#define SAVE_LOAD_QSETTINGS_INCLUDED
#include <QSettings>
class QSettings;
//! An interface that claims: this object wants to save / load something
//! into / from provided qsettings
class SaveLoadQSettings {
public:
virtual void save(QSettings &settings) const = 0;
virtual void load(QSettings &settings) = 0;
};
#endif

View file

@ -0,0 +1,48 @@
#pragma once
#ifndef CELL_POSITION_RATIO_INCLUDED
#define CELL_POSITION_RATIO_INCLUDED
#undef DVAPI
#undef DVVAR
#ifdef TOONZLIB_EXPORTS
#define DVAPI DV_EXPORT_API
#define DVVAR DV_EXPORT_VAR
#else
#define DVAPI DV_IMPORT_API
#define DVVAR DV_IMPORT_VAR
#endif
#include "tcommon.h"
class DVAPI Ratio {
int m_num, m_denom;
void normalize();
Ratio normalized() const;
public:
Ratio(int num, int denom);
friend Ratio operator+(const Ratio &a, const Ratio &b);
friend Ratio operator-(const Ratio &a, const Ratio &b);
friend Ratio operator*(const Ratio &a, const Ratio &b);
friend Ratio operator/(const Ratio &a, const Ratio &b);
friend int operator*(const Ratio &a, int b);
bool operator!() const { return m_num == 0; }
};
class DVAPI CellPositionRatio {
Ratio m_frame, m_layer;
public:
CellPositionRatio(const Ratio &frame, const Ratio &layer)
: m_frame(frame), m_layer(layer) {}
Ratio frame() const { return m_frame; }
Ratio layer() const { return m_layer; }
};
#endif

View file

@ -24,9 +24,10 @@ class TIStream;
open folded columns, activate() and to know if column is folded or not,
isActive().
Class provides column x-axis coordinate too.
It's possible to know column index by column x-axis coordinate, colToX()
and vice versa, xToCol().
Class provides column layer-axis coordinate too.
It's possible to know column index by column layer-axis coordinate,
colToLayerAxis()
and vice versa, layerAxisToCol().
*/
//=============================================================================
@ -40,6 +41,7 @@ class DVAPI ColumnFan {
std::vector<Column> m_columns;
std::map<int, int> m_table;
int m_firstFreePos;
int m_unfolded, m_folded;
/*!
Called by activate() and deactivate() to update columns coordinates.
@ -52,6 +54,9 @@ Constructs a ColumnFan with default value.
*/
ColumnFan();
//! Adjust column sizes when switching orientation
void setDimension(int unfolded);
/*!
Set column \b col not folded.
\sa deactivate() and isActive()
@ -69,15 +74,19 @@ Return true if column \b col is active, column is not folded, else return false.
bool isActive(int col) const;
/*!
Return column index of column in x-axis coordinate \b x.
\sa colToX()
Return column index of column in layer axis (x for vertical timeline, y for
horizontal).
\sa colToLayerAxis()
*/
int xToCol(int x) const;
int layerAxisToCol(int layerAxis) const;
/*!
Return column x-axis coordinate of column identify with \b col.
\sa xToCol()
Return layer coordinate (x for vertical timeline, y for horizontal)
of column identified by \b col.
\sa layerAxisToCol()
*/
int colToX(int col) const;
int colToLayerAxis(int col) const;
void copyFoldedStateFrom(const ColumnFan &from);
bool isEmpty() const;

View file

@ -362,6 +362,9 @@ public:
void enableExpandFunctionHeader(bool on);
bool isExpandFunctionHeaderEnabled() const { return m_expandFunctionHeader; }
void enableShowColumnNumbers(bool on);
bool isShowColumnNumbersEnabled() const { return m_showColumnNumbers; }
// Animation tab
void setKeyframeType(int s);
@ -503,7 +506,7 @@ private:
m_rewindAfterPlaybackEnabled, m_fitToFlipbookEnabled, m_autosaveEnabled,
m_autosaveSceneEnabled, m_autosaveOtherFilesEnabled,
m_defaultViewerEnabled, m_pixelsOnly, m_showXSheetToolbar,
m_expandFunctionHeader;
m_expandFunctionHeader, m_showColumnNumbers;
bool m_rasterOptimizedMemory, m_saveUnpaintedInCleanup,
m_askForOverrideRender, m_automaticSVNFolderRefreshEnabled, m_SVNEnabled,
m_levelsBackupEnabled, m_minimizeSaveboxAfterEditing,

View file

@ -13,6 +13,8 @@
// TnzLib includes
#include "toonz/txshcolumn.h"
#include "cellposition.h"
// STD includes
#include <set>
@ -46,6 +48,7 @@ class ToonzScene;
class TXshSoundColumn;
class TXshNoteSet;
class TFrameId;
class Orientation;
//=============================================================================
@ -58,62 +61,68 @@ class TFrameId;
/*!
Inherits \b TSmartObject and \b TPersist.
The class provides a collection of functions that returns xsheet
The class provides a collection of functions that returns xsheet
elements, defined in
struct \b TXsheetImp, and enables manipulation of these. Most
important xsheet elements
are: a \b column \b set \b TColumnSetT, a \b pegbar \b tree \b
struct \b TXsheetImp, and enables manipulation of these. Most important
xsheet elements
are: a \b column \b set \b TColumnSetT, a \b pegbar \b tree \b
TStageObjectTree, a \b fx
\b dag \b FxDag, a \b sound \b track \b TSoundTrack and a \b
scene \b ToonzScene.
\b dag \b FxDag, a \b sound \b track \b TSoundTrack and a \b scene \b
ToonzScene.
A \b column \b set contains all xsheet column. A collection of
function, concern column
set, allows to manage xsheet column. It's possible to know
xsheet column number,
getColumnCount(), know first not empty column index,
For purposes of this class, a Column is a graphics layer, and a
row is a frame number.
(Whether horizontal or vertial is a matter of displaying).
A \b column \b set contains all xsheet columns. A collection of
functions, concerning column
set, allows to manage xsheet column. It's possible to know xsheet column
count,
getColumnCount(), know first non empty column index,
getFirstFreeColumnIndex(),
or know if column in datum index is empty, isColumnEmpty(). You
can work on single xsheet
column, getColumn(), using its indexes: insert and remove a
column with insertColumn()
and removeColumn() or move column from an index to another using
or know if column in datum index is empty, isColumnEmpty(). You can work
on single xsheet
column, getColumn(), using its indexes: insert and remove a column with
insertColumn()
and removeColumn() or move column from an index to another using
moveColumn().
You can manage also column visualization in xsheet, using the
xsheet object \b ColumnFan
getColumnFan(), and find column icon getColumnIcon().
You can manage also column visualization in xsheet, using the xsheet
object \b ColumnFan
getColumnFan(), and find column icon getColumnIcon().
It's possible work on xsheet cells directly, getCell() and
setCell() or getCells() and
setCells(); cells are identified in xsheet by two index one for
row and one for column.
You can insert, remove or clear cells using insertCells(),
removeCells() or clearCells();
the difference between the remove and the clear function is the
shift of remains cells.
Also there are functions to manipulate cells reverseCells(),
cell positions will be identified by a pair of row+column index,
which is a separate class.
It's possible work on xsheet cells directly, getCell() and setCell() or
getCells() and
setCells(); cells are identified in xsheet by two index one for row and
one for column.
You can insert, remove or clear cells using insertCells(), removeCells()
or clearCells();
the difference between the remove and the clear function is the shift of
remains cells.
Also there are functions to manipulate cells reverseCells(),
swingCells(),
incrementCells(), duplicateCells(), int upTo, stepCells(),
eachCells().
incrementCells(), duplicateCells(), int upTo, stepCells(), eachCells().
About \b pegbar \b tree \b TStageObjectTree, it's possible to
manage it through the stage object's
related functions.
About \b pegbar \b tree \b TStageObjectTree, it's possible to manage it
through the stage object's
related functions.
The \b fx \b dag \b FxDag getFxDag() is not managed with direct
The \b fx \b dag \b FxDag getFxDag() is not managed with direct
functions but is always
up to date; in fact same functions update it. For example
up to date; in fact same functions update it. For example
insertColumn(), if necessary,
insert column index in fx dag, the same happen in setCells().
insert column index in fx dag, the same happen in setCells().
The \b sound \b track \b TSoundTrack contain a mixed sound,
computed using makeSound(),
of all \b TXshSoundColumn present in xsheet.
The \b sound \b track \b TSoundTrack contain a mixed sound, computed
using makeSound(),
of all \b TXshSoundColumn present in xsheet.
It's possible take and know the \b scene \b ToonzScene to which
the xsheet refers using
getScene() and setScene().
It's possible take and know the \b scene \b ToonzScene to which the
xsheet refers using
getScene() and setScene().
*/
class DVAPI TXsheet final : public TSmartObject, public TPersist {
@ -159,64 +168,66 @@ public:
\sa getMaxFrame()
*/
int getFrameCount() const;
/*! Returns true if cells contained in rect delimited by first row \b \e r0,
last row \b \e r1
and first column \b \e c0, last column \b \e c1 are empty; otherwise,
returns false.
/*! Returns true if all cells in rect delimited by first frame \b \e
pos0.frame,
last frame \b \e pos1.frame and first layer \b \e pos0.layer, last layer \b
\e pos1.layer
are empty; otherwise, false.
*/
bool isRectEmpty(int r0, int c0, int r1, int c1) const;
bool isRectEmpty(const CellPosition &pos0, const CellPosition &pos1) const;
/*! Returns the \b TXshCell cell in row identified by index \b \e row and
column identified by
index \b \e col. If column \b TXshColumnP in \b \e col is empty return
column identified by index \b \e col. If column \b TXshColumnP in \b \e col
is empty return
an empty cell.
\sa setCell(), getCells(), setCells()
*/
const TXshCell &getCell(int row, int col) const;
const TXshCell &getCell(const CellPosition &pos) const;
bool setCell(int row, int col, const TXshCell &cell);
/*! Set \b \e cells[] to \b \e rowCount cells of column identified by index \b
\e col starting from
row identified by index \b \e row. If column is empty or is not a \b
TXshCellColumn
set \b \e cells[] to \b \e rowCount empty cells.
\e col starting from row identified by index \b \e row. If column is empty
or is not a \b
TXshCellColumn set \b \e cells[] to \b \e rowCount empty cells.
\sa getCells(), setCells(), getCell()
*/
void getCells(int row, int col, int rowCount, TXshCell cells[]) const;
/*! If column identified by index \b \e col is a \b TXshCellColumn or is empty
and is not
locked, this method sets to \b \e cells[] the given \b \e rowCount
cells of column \b \e col starting from
row \b \e row. If column in \b \e col is empty it creates a new column
recalling
\b TColumnSetT::touchColumn() and sets the new cells to \b \e cells[],
and on creating a new
column it adds it to fx dag \b FxDag.
If cells in \b \e row and \b \e col are not empty recalls \b
TXshCellColumn::setCells(),
insert the new cells \b \e cells[] in \b \e row \b \e col and shift
old cells.
If xsheet change it updates xsheet's frame count.
Return false if cannot set cells.
\sa getCells(), setCell(), getCell()
and is not
locked, this method sets to \b \e cells[] the given \b \e rowCount cells of
column \b \e col starting from
row \b \e row. If column in \b \e col is empty it creates a new column
recalling
\b TColumnSetT::touchColumn() and sets the new cells to \b \e cells[], and
on creating a new
column it adds it to fx dag \b FxDag.
If cells in \b \e row and \b \e col are not empty recalls \b
TXshCellColumn::setCells(),
insert the new cells \b \e cells[] in \b \e row \b \e col and shift old
cells.
If xsheet change it updates xsheet's frame count. Return false if cannot set
cells.
\sa getCells(), setCell(), getCell()
*/
bool setCells(int row, int col, int rowCount, const TXshCell cells[]);
/*! If column identified by index \b \e col is not empty, is a \b \e
TXshCellColumn and is not
locked this method inserts in row identified by index \b \e row \b \e
rowCount empty cells, it calls
TXshCellColumn::insertEmptyCells(). An update of xsheet's frame count
TXshCellColumn and is not locked this method inserts in row identified by
index \b \e row \b \e
rowCount empty cells, it calls TXshCellColumn::insertEmptyCells(). An
update of xsheet's frame count
is performed.
\sa setCells(), removeCells()
*/
void insertCells(int row, int col, int rowCount = 1);
/*! If column identified by index \b \e col is not empty, is a \b
TXshCellColumn and is not
locked, this method removes \b \e rowCount cells starting from \b \e
row, it calls
TXshCellColumn::removeCells(). It removes cells without shift
remaining cells.
An update of xsheet's frame count is performed.
TXshCellColumn and is not locked, this method removes \b \e rowCount cells
starting from \b \e
row, it calls TXshCellColumn::removeCells(). It removes cells without shift
remaining cells. An update of xsheet's frame count is performed.
\sa clearCells(), insertCells()
*/
void removeCells(int row, int col, int rowCount = 1);
@ -232,10 +243,10 @@ Return false if cannot set cells.
*/
void clearAll();
/*! Returns cell range of column identified by index \b \e col and set \b \e
r0 and \b \e r1
respectively to first and last not empty cell, it then recalls \b
TXshCellColumn::getRange().
If column is empty or is not a \b TXshCellColumn this method returns
r0 and \b \e r1 respectively to first and last not empty cell, it then
recalls \b
TXshCellColumn::getRange(). If column is empty or is not a \b
TXshCellColumn this method returns
zero and sets
\b \e r0 to 0 and \b \e r1 to -1.
*/
@ -504,8 +515,9 @@ in TXsheetImp.
FxDag *getFxDag() const;
/*! Returns a pointer to object \b ColumnFan contained in \b TXsheetImp, this
object allows the user to manage columns visualization in xsheet.
TXsheet maintains one column fan per each orientation.
*/
ColumnFan *getColumnFan() const;
ColumnFan *getColumnFan(const Orientation *o) const;
/*! Returns a pointer to \b ToonzScene contained in \b TXsheetImp, that is the
scene to
which the xsheet refers.

View file

@ -9,6 +9,7 @@
#include <QList>
#include "tpersist.h"
#include "orientation.h"
#undef DVAPI
#undef DVVAR
@ -30,10 +31,11 @@ class DVAPI TXshSoundLevel final : public TXshLevel {
int m_frameSoundCount;
double m_fps;
//! Values is a map of \b Integer and \b DoublePair.
/*!Integer is horizontal value of row pixel.
/*! Two maps, one for vertical layout and one for horizontal.
Integer is pixel number since start of sound.
DoublePair is computed according to frameRate, frameCount
and soundtrack pressure.*/
std::map<int, DoublePair> m_values;
and soundtrack pressure. Means sound min and max.*/
std::map<int, DoublePair> m_values[Orientations::COUNT];
TFilePath m_path;
@ -60,9 +62,11 @@ public:
void save() override;
void save(const TFilePath &path);
void computeValues(int frameHeight = 20);
void computeValuesFor(const Orientation *o);
void computeValues();
void getValueAtPixel(int pixel, DoublePair &values) const;
void getValueAtPixel(const Orientation *o, int pixel,
DoublePair &values) const;
/*! Set frame rate to \b fps. \sa getSamplePerFrame() */
void setFrameRate(double fps);

View file

@ -4,6 +4,9 @@
#define SPREADSHEETVIEWER_H
#include "tcommon.h"
#include "cellposition.h"
#include "toonz/cellpositionratio.h"
// #include "orientation.h"
#include <QFrame>
#include <QScrollArea>
@ -20,6 +23,7 @@
// forward declaration
class TFrameHandle;
class SpreadsheetViewer;
class Orientation;
//-------------------------------------------------------------------
@ -30,23 +34,51 @@ class GenericPanel;
//-------------------------------------------------------------------
class DVAPI FrameScroller {
QList<FrameScroller *> m_connectedScrollers;
// Use composition rather than inheritance.
// How this works:
// * scroll area scrollbars sends event to this;
// * it notifies every other FrameScroller with difference;
// * they handle it by adjusting their scrollbars
class DVAPI FrameScroller final : public QObject {
Q_OBJECT
const Orientation *m_orientation;
QScrollArea *m_scrollArea;
int m_lastX, m_lastY;
bool m_syncing;
public:
FrameScroller();
virtual ~FrameScroller();
void connectScroller(FrameScroller *scroller);
void disconnectScroller(FrameScroller *scroller);
bool isScrollerConnected(FrameScroller *scroller);
virtual QScrollArea *getFrameScrollArea() const = 0;
void setFrameScrollArea(QScrollArea *scrollArea);
QScrollArea *getFrameScrollArea() const { return m_scrollArea; }
void setOrientation(const Orientation *o) { m_orientation = o; }
const Orientation *orientation() const { return m_orientation; }
void registerFrameScroller();
void unregisterFrameScroller();
void prepareToScroll(int dy);
virtual void onPrepareToScroll(int dy) {}
void prepareToScrollOthers(const QPoint &offset);
void setSyncing(bool s) { m_syncing = s; }
bool isSyncing() { return m_syncing; }
private:
void connectScrollbars();
void disconnectScrollbars();
void handleScroll(const QPoint &offset) const;
void onScroll(const CellPositionRatio &offset);
void prepareToScrollRatio(const CellPositionRatio &offset);
private slots:
void onVScroll(int value);
void onHScroll(int value);
signals:
void prepareToScrollOffset(const QPoint &offset);
};
//-------------------------------------------------------------------
@ -190,8 +222,7 @@ protected:
//-------------------------------------------------------------------
class DVAPI SpreadsheetViewer : public QFrame,
public Spreadsheet::FrameScroller {
class DVAPI SpreadsheetViewer : public QFrame {
Q_OBJECT
QColor m_lightLightBgColor; // RowPanel background (124,124,124)
@ -269,6 +300,10 @@ class DVAPI SpreadsheetViewer : public QFrame,
int m_markRowDistance, m_markRowOffset;
// QRect m_selectedCells; // x=col, y=row
bool m_isComputingSize;
// const Orientation *m_orientation;
protected:
Spreadsheet::FrameScroller m_frameScroller;
public:
SpreadsheetViewer(QWidget *parent);
@ -286,9 +321,6 @@ public:
int getRowCount() const { return m_rowCount; }
// provvisorio
QScrollArea *getFrameScrollArea() const override { return m_cellScrollArea; }
// QProperty
void setLightLightBGColor(const QColor &color) {
m_lightLightBgColor = color;
@ -354,7 +386,6 @@ public:
}
void scroll(QPoint delta);
void onPrepareToScroll(int dy) override { refreshContentSize(0, dy); }
void setAutoPanSpeed(const QPoint &speed);
void setAutoPanSpeed(const QRect &widgetBounds, const QPoint &mousePos);
@ -368,6 +399,13 @@ public:
int columnToX(int col) const;
int rowToY(int row) const;
CellPosition xyToPosition(const QPoint &point) const;
QPoint positionToXY(const CellPosition &pos) const;
CellRange xyRectToRange(const QRect &rect) const;
// const Orientation *orientation () const { return m_orientation; }
bool refreshContentSize(int scrollDx, int scrollDy);
int getCurrentRow() const { return m_currentRow; }
@ -413,6 +451,8 @@ public slots:
void updateAreas();
void onVSliderChanged(int);
void onHSliderChanged(int);
void onPrepareToScrollOffset(const QPoint &offset);
/*
void updateAllAree();
void updateCellColumnAree();

View file

@ -19,6 +19,7 @@ set(MOC_HEADERS
cellkeyframedata.h
cellkeyframeselection.h
cellselection.h
../include/cellposition.h
cleanuppaletteviewer.h
cleanuppopup.h
cleanuppreview.h
@ -61,6 +62,7 @@ set(MOC_HEADERS
keyframedata.h
keyframeselection.h
keyframemover.h
layerheaderpanel.h
levelcreatepopup.h
levelsettingspopup.h
linesfadepopup.h
@ -77,6 +79,7 @@ set(MOC_HEADERS
meshifypopup.h
messagepanel.h
moviegenerator.h
../include/orientation.h
onionskinmaskgui.h
outputsettingspopup.h
overwritepopup.h
@ -90,6 +93,7 @@ set(MOC_HEADERS
renumberpopup.h
reslist.h
ruler.h
../include/saveloadqsettings.h
savepresetpopup.h
scanlist.h
scanpopup.h
@ -217,6 +221,7 @@ set(SOURCES
fxparameditorpopup.cpp
histogrampopup.cpp
insertfxpopup.cpp
layerheaderpanel.cpp
levelcreatepopup.cpp
levelsettingspopup.cpp
linetestcapturepane.cpp

View file

@ -1586,7 +1586,7 @@ void TCellSelection::deleteCells() {
getSelectedCells(r0, c0, r1, c1);
TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
// if all the selected cells are already empty, then do nothing
if (xsh->isRectEmpty(r0, c0, r1, c1)) return;
if (xsh->isRectEmpty(CellPosition(r0, c0), CellPosition(r1, c1))) return;
TCellData *data = new TCellData();
data->setCells(xsh, r0, c0, r1, c1);
DeleteCellsUndo *undo =

View file

@ -16,6 +16,7 @@
#include "toonz/txshleveltypes.h"
#include "toonz/txshsimplelevel.h"
#include "toonz/txshcell.h"
#include "orientation.h"
// TnzCore includes
#include "tvectorimage.h"
@ -201,10 +202,13 @@ void TColumnSelection::cloneChild() {
//-----------------------------------------------------------------------------
void TColumnSelection::hideColumns() {
TApp *app = TApp::instance();
ColumnFan *columnFan = app->getCurrentXsheet()->getXsheet()->getColumnFan();
std::set<int>::iterator it = m_indices.begin();
for (; it != m_indices.end(); ++it) columnFan->deactivate(*it);
TApp *app = TApp::instance();
for (auto o : Orientations::all()) {
ColumnFan *columnFan =
app->getCurrentXsheet()->getXsheet()->getColumnFan(o);
std::set<int>::iterator it = m_indices.begin();
for (; it != m_indices.end(); ++it) columnFan->deactivate(*it);
}
m_indices.clear();
app->getCurrentXsheet()->notifyXsheetChanged();
// DA FARE (non c'e una notica per il solo cambiamento della testa delle

View file

@ -334,7 +334,7 @@ bool KeyframeMoverTool::canMove(const TPoint &pos) {
if (pos.x < 0) return false;
int col = pos.x;
int startCol = getViewer()->xToColumn(m_startPos.x);
int startCol = getViewer()->xyToPosition(m_startPos).layer();
if (col != startCol) return false;
return true;
@ -358,14 +358,15 @@ void KeyframeMoverTool::onCellChange(int row, int col) {
//-----------------------------------------------------------------------------
void KeyframeMoverTool::onClick(const QMouseEvent *event) {
m_firstKeyframeMovement = true;
m_selecting = false;
TXsheet *xsheet = getViewer()->getXsheet();
int row = getViewer()->yToRow(event->pos().y());
int col = getViewer()->xToColumn(event->pos().x());
m_firstRow = row;
m_firstCol = col;
bool isSelected = getSelection()->isSelected(row, col);
m_firstKeyframeMovement = true;
m_selecting = false;
TXsheet *xsheet = getViewer()->getXsheet();
CellPosition cellPosition = getViewer()->xyToPosition(event->pos());
int row = cellPosition.frame();
int col = cellPosition.layer();
m_firstRow = row;
m_firstCol = col;
bool isSelected = getSelection()->isSelected(row, col);
if (!m_justMovement) {
if (event->modifiers() & Qt::ControlModifier)
ctrlSelect(row, col);
@ -389,11 +390,12 @@ void KeyframeMoverTool::onClick(const QMouseEvent *event) {
//-----------------------------------------------------------------------------
void KeyframeMoverTool::onDrag(const QMouseEvent *e) {
int x = e->pos().x();
int y = e->pos().y();
m_curPos = TPointD(x, y);
int row = getViewer()->yToRow(y);
int col = getViewer()->xToColumn(x);
int x = e->pos().x();
int y = e->pos().y();
m_curPos = TPointD(x, y);
CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
int row = cellPosition.frame();
int col = cellPosition.layer();
if (m_selecting)
rectSelect(row, col);
else {
@ -417,7 +419,7 @@ void KeyframeMoverTool::onDrag(const QMouseEvent *e) {
//-----------------------------------------------------------------------------
void KeyframeMoverTool::onRelease(int row, int col) {
void KeyframeMoverTool::onRelease(const CellPosition &pos) {
if (m_selecting) {
m_selecting = false;
getViewer()->updateCells();

View file

@ -92,7 +92,7 @@ public:
void onClick(const QMouseEvent *event) override;
void onDrag(const QMouseEvent *event) override;
void onRelease(int row, int col) override;
void onRelease(const CellPosition &pos) override;
void drawCellsArea(QPainter &p) override;
};

View file

@ -0,0 +1,240 @@
#include "layerheaderpanel.h"
#include <QPainter>
#include <QToolTip>
#include "xsheetviewer.h"
#include "xshcolumnviewer.h"
#include "tapp.h"
#include "toonz/tscenehandle.h"
#include "toonz/txsheethandle.h"
#include "toonz/tobjecthandle.h"
#include "toonz/preferences.h"
using XsheetGUI::ColumnArea;
#if QT_VERSION >= 0x050500
LayerHeaderPanel::LayerHeaderPanel(XsheetViewer *viewer, QWidget *parent,
Qt::WindowFlags flags)
#else
LayerHeaderPanel::LayerHeaderPanel(XsheetViewer *viewer, QWidget *parent,
Qt::WFlags flags)
#endif
: QWidget(parent, flags), m_viewer(viewer) {
const Orientation *o = Orientations::leftToRight();
QRect rect = o->rect(PredefinedRect::LAYER_HEADER_PANEL);
setObjectName("layerHeaderPanel");
setFixedSize(rect.size());
setMouseTracking(true);
}
LayerHeaderPanel::~LayerHeaderPanel() {}
namespace {
QColor mix(const QColor &a, const QColor &b, double w) {
return QColor(a.red() * w + b.red() * (1 - w),
a.green() * w + b.green() * (1 - w),
a.blue() * w + b.blue() * (1 - w));
}
QColor withAlpha(const QColor &color, double alpha) {
QColor result(color);
result.setAlpha(alpha * 255);
return result;
}
QRect shorter(const QRect original) { return original.adjusted(0, 2, 0, -2); }
QLine leftSide(const QRect &r) { return QLine(r.topLeft(), r.bottomLeft()); }
QLine rightSide(const QRect &r) { return QLine(r.topRight(), r.bottomRight()); }
}
void LayerHeaderPanel::paintEvent(QPaintEvent *event) {
QPainter p(this);
p.setRenderHint(QPainter::SmoothPixmapTransform, true);
const Orientation *o = Orientations::leftToRight();
QColor background = m_viewer->getBGColor();
QColor slightlyLighter = {mix(background, Qt::white, 0.95)};
QRect rect = QRect(QPoint(0, 0), size());
p.fillRect(rect.adjusted(0, 0, -3, 0), slightlyLighter);
drawIcon(p, PredefinedRect::EYE, XsheetGUI::PreviewVisibleColor,
ColumnArea::Pixmaps::eye());
drawIcon(p, PredefinedRect::PREVIEW_LAYER, boost::none,
ColumnArea::Pixmaps::cameraStand());
drawIcon(p, PredefinedRect::LOCK, QColor(255, 255, 255, 128),
ColumnArea::Pixmaps::lock());
QRect numberRect = o->rect(PredefinedRect::LAYER_NUMBER);
int leftadj = 2;
if (Preferences::instance()->isShowColumnNumbersEnabled())
{
p.drawText(numberRect, Qt::AlignCenter | Qt::TextSingleLine, "#");
leftadj += 20;
}
QRect nameRect = o->rect(PredefinedRect::LAYER_NAME).adjusted(leftadj, 0, -1, 0);
p.drawText(nameRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine,
QObject::tr("Layer name"));
drawLines(p, numberRect, nameRect);
}
void LayerHeaderPanel::drawIcon(QPainter &p, PredefinedRect rect,
optional<QColor> fill,
const QPixmap &pixmap) const {
QRect iconRect = Orientations::leftToRight()->rect(rect).adjusted(-2, 0,-2, 0);
if (rect == PredefinedRect::LOCK)
{
p.setPen(Qt::gray);
p.setBrush(QColor(255, 255, 255, 128));
p.drawRect(iconRect);
iconRect.adjust(1, 1, -1, -1);
}
else
if (fill) p.fillRect(iconRect, *fill);
p.drawPixmap(iconRect, pixmap);
}
void LayerHeaderPanel::drawLines(QPainter &p, const QRect &numberRect,
const QRect &nameRect) const {
p.setPen(withAlpha(m_viewer->getTextColor(), 0.5));
QLine line = {leftSide(shorter(numberRect)).translated(-2, 0)};
p.drawLine(line);
if (Preferences::instance()->isShowColumnNumbersEnabled())
{
line = rightSide(shorter(numberRect)).translated(-2, 0);
p.drawLine(line);
}
line = rightSide(shorter(nameRect));
p.drawLine(line);
}
void LayerHeaderPanel::showOrHide(const Orientation *o) {
QRect rect = o->rect(PredefinedRect::LAYER_HEADER_PANEL);
if (rect.isEmpty())
hide();
else
show();
}
//-----------------------------------------------------------------------------
void LayerHeaderPanel::mousePressEvent(QMouseEvent *event) {
const Orientation *o = Orientations::leftToRight();
m_doOnRelease = 0;
if (event->button() == Qt::LeftButton) {
// get mouse position
QPoint pos = event->pos();
// preview button
if (o->rect(PredefinedRect::EYE_AREA).contains(pos)) {
m_doOnRelease = ToggleAllPreviewVisible;
}
// camstand button
else if (o->rect(PredefinedRect::PREVIEW_LAYER_AREA).contains(pos)) {
m_doOnRelease = ToggleAllTransparency;
}
// lock button
else if (o->rect(PredefinedRect::LOCK_AREA).contains(pos)) {
m_doOnRelease = ToggleAllLock;
}
}
update();
}
void LayerHeaderPanel::mouseMoveEvent(QMouseEvent *event) {
const Orientation *o = Orientations::leftToRight();
QPoint pos = event->pos();
// preview button
if (o->rect(PredefinedRect::EYE_AREA).contains(pos)) {
m_tooltip = tr("Preview Visbility Toggle All");
}
// camstand button
else if (o->rect(PredefinedRect::PREVIEW_LAYER_AREA).contains(pos)) {
m_tooltip = tr("Camera Stand Visibility Toggle All");
}
// lock button
else if (o->rect(PredefinedRect::LOCK).contains(pos)) {
m_tooltip = tr("Lock Toggle All");
}
else {
m_tooltip = tr("");
}
m_pos = pos;
update();
}
//-----------------------------------------------------------------------------
bool LayerHeaderPanel::event(QEvent *event) {
if (event->type() == QEvent::ToolTip) {
if (!m_tooltip.isEmpty())
QToolTip::showText(mapToGlobal(m_pos), m_tooltip);
else
QToolTip::hideText();
}
return QWidget::event(event);
}
//-----------------------------------------------------------------------------
void LayerHeaderPanel::mouseReleaseEvent(QMouseEvent *event) {
TApp *app = TApp::instance();
TXsheet *xsh = m_viewer->getXsheet();
int col, totcols = xsh->getColumnCount();
bool sound_changed = false;
if (m_doOnRelease != 0 && totcols > 0)
{
for (col = 0; col < totcols; col++)
{
if (!xsh->isColumnEmpty(col)) {
TXshColumn *column = xsh->getColumn(col);
if (m_doOnRelease == ToggleAllPreviewVisible) {
column->setPreviewVisible(!column->isPreviewVisible());
}
else if (m_doOnRelease == ToggleAllTransparency) {
column->setCamstandVisible(!column->isCamstandVisible());
if (column->getSoundColumn()) sound_changed = true;
}
else if (m_doOnRelease == ToggleAllLock) {
column->lock(!column->isLocked());
}
}
}
if (sound_changed) {
app->getCurrentXsheet()->notifyXsheetSoundChanged();
}
app->getCurrentScene()->notifySceneChanged();
app->getCurrentXsheet()->notifyXsheetChanged();
}
m_viewer->updateColumnArea();
update();
m_doOnRelease = 0;
}

View file

@ -0,0 +1,55 @@
#pragma once
#ifndef LAYER_HEADER_PANEL_INCLUDED
#define LAYER_HEADER_PANEL_INCLUDED
#include <QWidget>
#include <boost/optional.hpp>
#include "orientation.h"
using boost::optional;
class XsheetViewer;
// Panel showing column headers for layers in timeline mode
class LayerHeaderPanel final : public QWidget {
Q_OBJECT
enum { ToggleAllTransparency = 1, ToggleAllPreviewVisible, ToggleAllLock };
int m_doOnRelease;
QString m_tooltip;
QPoint m_pos;
private:
XsheetViewer *m_viewer;
public:
#if QT_VERSION >= 0x050500
LayerHeaderPanel(XsheetViewer *viewer, QWidget *parent = 0,
Qt::WindowFlags flags = 0);
#else
LayerHeaderPanel(XsheetViewer *viewer, QWidget *parent = 0,
Qt::WFlags flags = 0);
#endif
~LayerHeaderPanel();
void showOrHide(const Orientation *o);
protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
bool event(QEvent *event) override;
private:
void drawIcon(QPainter &p, PredefinedRect rect, optional<QColor> fill,
const QPixmap &pixmap) const;
void drawLines(QPainter &p, const QRect &numberRect,
const QRect &nameRect) const;
};
#endif

View file

@ -89,7 +89,8 @@ TEnv::IntVar NoShiftToggleAction("NoShiftToggleAction", 0);
namespace {
//=============================================================================
const std::string layoutsFileName = "layouts.txt";
// layout file name may be overwritten by the argument
std::string layoutsFileName = "layouts.txt";
const std::string currentRoomFileName = "currentRoom.txt";
bool scrambledRooms = false;
@ -108,8 +109,10 @@ bool readRoomList(std::vector<TFilePath> &roomPaths,
" not found!");
fp = ToonzFolder::getRoomsFile(layoutsFileName);
if (!TFileStatus(fp).doesExist()) return false;
} else
} else {
argumentLayoutFileLoaded = true;
layoutsFileName = argumentLayoutFileName.toStdString();
}
} else {
fp = ToonzFolder::getRoomsFile(layoutsFileName);
if (!TFileStatus(fp).doesExist()) return false;
@ -255,6 +258,9 @@ void Room::save() {
TPanel *pane = static_cast<TPanel *>(layout->itemAt(i)->widget());
settings.setValue("name", pane->objectName());
settings.setValue("geometry", geometries[i]); // Use passed geometry
if (SaveLoadQSettings *persistent =
dynamic_cast<SaveLoadQSettings *>(pane->widget()))
persistent->save(settings);
if (pane->getViewType() != -1)
// If panel has different viewtypes, store current one
settings.setValue("viewtype", pane->getViewType());
@ -303,6 +309,9 @@ void Room::load(const TFilePath &fp) {
// Allocate panel
paneObjectName = name.toString();
pane = TPanelFactory::createPanel(this, paneObjectName);
if (SaveLoadQSettings *persistent =
dynamic_cast<SaveLoadQSettings *>(pane->widget()))
persistent->load(settings);
}
if (!pane) {

View file

@ -671,7 +671,7 @@ void PreferencesPopup::setChessboardColor2(const TPixel32 &color,
//-----------------------------------------------------------------------------
void PreferencesPopup::onColumnIconChange(const QString &value) {
m_pref->setColumnIconLoadingPolicy(value == QString("At Once")
m_pref->setColumnIconLoadingPolicy(value == tr("At Once")
? Preferences::LoadAtOnce
: Preferences::LoadOnDemand);
}
@ -1002,6 +1002,10 @@ void PreferencesPopup::onExpandFunctionHeaderClicked(bool checked) {
m_pref->enableExpandFunctionHeader(checked);
}
void PreferencesPopup::onShowColumnNumbersChanged(int index) {
m_pref->enableShowColumnNumbers(index == Qt::Checked);
}
//-----------------------------------------------------------------------------
void PreferencesPopup::onUseArrowKeyToShiftCellSelectionClicked(int on) {
@ -1224,6 +1228,7 @@ PreferencesPopup::PreferencesPopup()
tr("Expand Function Editor Header to Match XSheet Toolbar Height "
"(Requires Restart)"),
this);
CheckBox *showColumnNumbersCB = new CheckBox(tr("Show Column Numbers in Column Headers"), this);
//--- Animation ------------------------------
categoryList->addItem(tr("Animation"));
@ -1492,6 +1497,7 @@ PreferencesPopup::PreferencesPopup()
m_pref->isInputCellsWithoutDoubleClickingEnabled());
m_showXSheetToolbar->setChecked(m_pref->isShowXSheetToolbarEnabled());
m_expandFunctionHeader->setChecked(m_pref->isExpandFunctionHeaderEnabled());
showColumnNumbersCB->setChecked(m_pref->isShowColumnNumbersEnabled());
//--- Animation ------------------------------
QStringList list;
@ -1929,7 +1935,7 @@ PreferencesPopup::PreferencesPopup()
QGridLayout *xsheetFrameLay = new QGridLayout();
xsheetFrameLay->setMargin(15);
xsheetFrameLay->setHorizontalSpacing(15);
xsheetFrameLay->setVerticalSpacing(10);
xsheetFrameLay->setVerticalSpacing(11);
{
xsheetFrameLay->addWidget(new QLabel(tr("Next/Previous Step Frames:")), 0,
0, Qt::AlignRight | Qt::AlignVCenter);
@ -1955,7 +1961,8 @@ PreferencesPopup::PreferencesPopup()
m_showXSheetToolbar->setLayout(xSheetToolbarLay);
xsheetFrameLay->addWidget(m_showXSheetToolbar, 7, 0, 3, 3);
}
xsheetFrameLay->addWidget(showColumnNumbersCB, 10, 0, 1, 2);
}
xsheetFrameLay->setColumnStretch(0, 0);
xsheetFrameLay->setColumnStretch(1, 0);
xsheetFrameLay->setColumnStretch(2, 1);
@ -2305,6 +2312,9 @@ PreferencesPopup::PreferencesPopup()
ret = ret && connect(m_expandFunctionHeader, SIGNAL(clicked(bool)),
SLOT(onExpandFunctionHeaderClicked(bool)));
ret = ret && connect(showColumnNumbersCB, SIGNAL(stateChanged(int)),
this, SLOT(onShowColumnNumbersChanged(int)));
//--- Animation ----------------------
ret = ret && connect(m_keyframeType, SIGNAL(currentIndexChanged(int)),
SLOT(onKeyframeTypeChanged(int)));

View file

@ -174,6 +174,7 @@ private slots:
void onUseNumpadForSwitchingStylesClicked(bool);
void onShowXSheetToolbarClicked(bool);
void onExpandFunctionHeaderClicked(bool);
void onShowColumnNumbersChanged(int);
void onUseArrowKeyToShiftCellSelectionClicked(int);
void onInputCellsWithoutDoubleClickingClicked(int);
void onWatchFileSystemClicked(int);

View file

@ -935,9 +935,9 @@ void SceneViewer::keyPressEvent(QKeyEvent *event) {
if (!ret) {
TFrameHandle *fh = TApp::instance()->getCurrentFrame();
if (key == TwConsts::TK_UpArrow)
if (key == TwConsts::TK_UpArrow || key == TwConsts::TK_LeftArrow)
fh->prevFrame();
else if (key == TwConsts::TK_DownArrow)
else if (key == TwConsts::TK_DownArrow || key == TwConsts::TK_RightArrow)
fh->nextFrame();
else if (key == TwConsts::TK_Home)
fh->firstFrame();

View file

@ -371,9 +371,10 @@ qDebug() << "check: " << srcIndex << ":" <<
}
void LevelMoverTool::onClick(const QMouseEvent *e) {
QPoint pos = e->pos();
int row = getViewer()->yToRow(pos.y());
int col = getViewer()->xToColumn(pos.x());
QPoint pos = e->pos();
CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
int row = cellPosition.frame();
int col = cellPosition.layer();
m_qualifiers = 0;
if (Preferences::instance()->getDragCellsBehaviour() == 1)
@ -509,13 +510,13 @@ void LevelMoverTool::onCellChange(int row, int col) {
}
void LevelMoverTool::onDrag(const QMouseEvent *e) {
QPoint pos = e->pos();
onCellChange(getViewer()->yToRow(pos.y()), getViewer()->xToColumn(pos.x()));
CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
onCellChange(cellPosition.frame(), cellPosition.layer());
refreshCellsArea();
refreshColumnsArea();
}
void LevelMoverTool::onRelease(int row, int col) {
void LevelMoverTool::onRelease(const CellPosition &pos) {
m_validPos = false;
m_range.lx = 0;
m_range.ly = 0;
@ -534,15 +535,13 @@ void LevelMoverTool::drawCellsArea(QPainter &p) {
if (rect.x1 < 0 || rect.y1 < 0) return;
if (rect.x0 < 0) rect.x0 = 0;
if (rect.y0 < 0) rect.y0 = 0;
int x0, y0, x1, y1;
x0 = getViewer()->columnToX(rect.x0);
x1 = getViewer()->columnToX(rect.x1 + 1);
y0 = getViewer()->rowToY(rect.y0);
y1 = getViewer()->rowToY(rect.y1 + 1);
int x = x1 - x0;
int y = y1 - y0;
QRect screen = getViewer()->rangeToXYRect(CellRange(
CellPosition(rect.y0, rect.x0), CellPosition(rect.y1 + 1, rect.x1 + 1)));
p.setPen((m_aimedPos == m_lastPos && m_validPos) ? QColor(190, 220, 255)
: QColor(255, 0, 0));
int i;
for (i = 0; i < 3; i++) p.drawRect(x0 + i, y0 + i, x - 2 * i, y - 2 * i);
for (i = 0; i < 3; i++) // thick border inside cell
p.drawRect(QRect(screen.topLeft() + QPoint(i, i),
screen.size() - QSize(2 * i, 2 * i)));
}

View file

@ -89,7 +89,7 @@ private:
class LevelMoverTool : public XsheetGUI::DragTool {
protected:
TPoint m_grabOffset;
TPoint m_startPos, m_lastPos, m_aimedPos;
TPoint m_startPos, m_lastPos, m_aimedPos; // x=col, y=row coordinates
TDimension m_range;
int m_qualifiers;
@ -109,7 +109,7 @@ public:
void onClick(const QMouseEvent *e) override;
void onCellChange(int row, int col);
void onDrag(const QMouseEvent *e) override;
void onRelease(int row, int col) override;
void onRelease(const CellPosition &pos) override;
void drawCellsArea(QPainter &p) override;
};

File diff suppressed because it is too large Load diff

View file

@ -5,6 +5,7 @@
#include <QWidget>
#include <QLineEdit>
#include "orientation.h"
// forward declaration
class XsheetViewer;
@ -70,11 +71,27 @@ class CellArea final : public QWidget {
RenameCellField *m_renameCell;
void drawCells(QPainter &p, const QRect toBeUpdated);
void drawNonEmptyBackground(QPainter &p) const;
void drawFoldedColumns(QPainter &p, int layerAxis,
const NumberRange &frameAxis) const;
void drawSelectionBackground(QPainter &p) const;
void drawExtenderHandles(QPainter &p);
void drawDragHandle(QPainter &p, const QPoint &xy,
const QColor &sideColor) const;
void drawEndOfDragHandle(QPainter &p, bool isEnd, const QPoint &xy,
const QColor &cellColor) const;
void drawLockedDottedLine(QPainter &p, bool isLocked, const QPoint &xy,
const QColor &cellColor) const;
void drawLevelCell(QPainter &p, int row, int col, bool isReference = false);
void drawSoundTextCell(QPainter &p, int row, int col);
void drawSoundCell(QPainter &p, int row, int col);
void drawPaletteCell(QPainter &p, int row, int col, bool isReference = false);
void drawKeyframe(QPainter &p, const QRect toBeUpdated);
void drawKeyframeLine(QPainter &p, int col, const NumberRange &rows) const;
void drawNotes(QPainter &p, const QRect toBeUpdated);
// Restistusce true

File diff suppressed because it is too large Load diff

View file

@ -6,6 +6,8 @@
#include <QWidget>
#include <QListWidget>
#include <QLineEdit>
#include <QPoint>
#include <QColor>
// forward declaration
class XsheetViewer;
@ -14,6 +16,9 @@ class TXsheetHandle;
class TStageObjectId;
class TXshColumn;
class QComboBox;
class Orientation;
class TApp;
class TXsheet;
//=============================================================================
namespace XsheetGUI {
@ -134,7 +139,7 @@ public:
m_xsheetHandle = xsheetHandle;
}
void show(QPoint pos, int col);
void show(const QRect &rect, int col);
protected:
void focusOutEvent(QFocusEvent *) override;
@ -173,11 +178,11 @@ protected slots:
void onFilterColorChanged(int id);
};
//! La classe si occupa della visualizzazione dell'area che gestisce le colonne.
//! The class in charge of the region showing layer headers
class ColumnArea final : public QWidget {
Q_OBJECT
enum { ToggleTransparency = 1, TogglePreviewVisible, ToggleLock };
enum { ToggleTransparency = 1, ToggleAllTransparency, TogglePreviewVisible, ToggleAllPreviewVisible, ToggleLock, ToggleAllLock };
ColumnTransparencyPopup *m_columnTransparencyPopup;
QTimer *m_transparencyPopupTimer;
@ -188,9 +193,6 @@ class ColumnArea final : public QWidget {
QRect m_tabBox;
QRect m_nameBox;
QRect m_linkBox;
QRect m_prevViewBox;
QRect m_tableViewBox;
QRect m_lockBox;
bool m_isPanning;
@ -214,6 +216,43 @@ class ColumnArea final : public QWidget {
void setDragTool(DragTool *dragTool);
void startTransparencyPopupTimer(QMouseEvent *e);
// extracted all variables of drawSomething methods
class DrawHeader {
ColumnArea *area;
QPainter &p;
int col;
XsheetViewer *m_viewer;
const Orientation *o;
TApp *app;
TXsheet *xsh;
bool isEmpty, isCurrent;
TXshColumn *column;
QPoint orig;
public:
DrawHeader(ColumnArea *area, QPainter &p, int col);
void prepare() const;
void levelColors(QColor &columnColor, QColor &dragColor) const;
void soundColors(QColor &columnColor, QColor &dragColor) const;
void paletteColors(QColor &columnColor, QColor &dragColor) const;
void drawBaseFill(const QColor &columnColor, const QColor &dragColor) const;
void drawEye() const;
void drawPreviewToggle(int opacity) const;
void drawLock() const;
void drawColumnNumber() const;
void drawColumnName() const;
void drawThumbnail(QPixmap &iconPixmap) const;
void drawPegbarName() const;
void drawParentHandleName() const;
void drawFilterColor() const;
void drawSoundIcon(bool isPlaying) const;
void drawVolumeControl(double volume) const;
};
public:
#if QT_VERSION >= 0x050500
ColumnArea(XsheetViewer *parent, Qt::WindowFlags flags = 0);
@ -222,6 +261,10 @@ public:
#endif
~ColumnArea();
void onControlPressed(bool pressed);
const bool isControlPressed();
void drawFoldedColumnHead(QPainter &p, int col);
void drawLevelColumnHead(QPainter &p, int col);
void drawSoundColumnHead(QPainter &p, int col);
void drawPaletteColumnHead(QPainter &p, int col);
@ -229,6 +272,16 @@ public:
QPixmap getColumnIcon(int columnIndex);
class Pixmaps {
public:
static const QPixmap &eye();
static const QPixmap &cameraStand();
static const QPixmap &cameraStandTransparent();
static const QPixmap &lock();
static const QPixmap &sound();
static const QPixmap &soundPlaying();
};
protected:
void select(int columnIndex, QMouseEvent *event);

View file

@ -86,22 +86,25 @@ void XsheetGUI::DragTool::refreshRowsArea() { getViewer()->updateRows(); }
//-----------------------------------------------------------------------------
void XsheetGUI::DragTool::onClick(const QMouseEvent *event) {
QPoint pos = event->pos();
onClick(getViewer()->yToRow(pos.y()), getViewer()->xToColumn(pos.x()));
QPoint xy = event->pos();
CellPosition pos = getViewer()->xyToPosition(xy);
onClick(pos);
}
//-----------------------------------------------------------------------------
void XsheetGUI::DragTool::onDrag(const QMouseEvent *event) {
QPoint pos = event->pos();
onDrag(getViewer()->yToRow(pos.y()), getViewer()->xToColumn(pos.x()));
QPoint xy = event->pos();
CellPosition pos = getViewer()->xyToPosition(xy);
onDrag(pos);
}
//-----------------------------------------------------------------------------
void XsheetGUI::DragTool::onRelease(const QMouseEvent *event) {
QPoint pos = event->pos();
onRelease(getViewer()->yToRow(pos.y()), getViewer()->xToColumn(pos.x()));
QPoint xy = event->pos();
CellPosition pos = getViewer()->xyToPosition(xy);
onRelease(pos);
}
//=============================================================================
@ -117,11 +120,12 @@ public:
: DragTool(viewer), m_firstRow(0), m_firstCol(0), m_modifier() {}
// activate when clicked the cell
void onClick(const QMouseEvent *event) override {
m_modifier = event->modifiers();
int row = getViewer()->yToRow(event->pos().y());
int col = getViewer()->xToColumn(event->pos().x());
m_firstCol = col;
m_firstRow = row;
m_modifier = event->modifiers();
CellPosition pos = getViewer()->xyToPosition(event->pos());
int row = pos.frame();
int col = pos.layer();
m_firstCol = col;
m_firstRow = row;
if (m_modifier & Qt::ShiftModifier) {
int r0, c0, r1, c1;
getViewer()->getCellSelection()->getSelectedCells(r0, c0, r1, c1);
@ -171,7 +175,8 @@ public:
refreshCellsArea();
refreshRowsArea();
}
void onDrag(int row, int col) override {
void onDrag(const CellPosition &pos) override {
int row = pos.frame(), col = pos.layer();
if (col < 0) return;
if (row < 0) row = 0;
if (m_modifier & Qt::ControlModifier)
@ -626,7 +631,8 @@ public:
, m_invert(invert) {}
// called when the smart tab is clicked
void onClick(int row, int col) override {
void onClick(const CellPosition &pos) override {
int row = pos.frame(), col = pos.layer();
int r0, c0, r1, c1;
getViewer()->getCellSelection()->getSelectedCells(r0, c0, r1, c1);
if (m_invert)
@ -647,7 +653,8 @@ public:
m_undo->setCells(xsh, r0, c0, m_rowCount, m_colCount);
}
void onDrag(int row, int col) override {
void onDrag(const CellPosition &pos) override {
int row = pos.frame(), col = pos.layer();
if (!m_invert)
onCellChange(row, col);
else
@ -704,7 +711,7 @@ public:
bool found = false;
for (int c = 0; c < m_colCount; c++) {
TXshColumn *column = xsh->getColumn(m_c0 + c);
if (column && column->getSoundColumn()) continue;
if (!column || column->getSoundColumn()) continue;
if (!column->isCellEmpty(emptyRow)) {
emptyRow += 1;
found = true;
@ -725,7 +732,7 @@ public:
// clear cells
for (int c = 0; c < m_colCount; c++) {
TXshColumn *column = xsh->getColumn(m_c0 + c);
if (column && column->getSoundColumn()) continue;
if (!column || column->getSoundColumn()) continue;
xsh->clearCells(m_r0, m_c0 + c, dr);
}
}
@ -733,7 +740,7 @@ public:
else {
for (int c = 0; c < m_colCount; c++) {
TXshColumn *column = xsh->getColumn(m_c0 + c);
if (column && column->getSoundColumn()) continue;
if (!column || column->getSoundColumn()) continue;
for (int r = r0; r <= m_r0 - 1; r++) {
xsh->setCell(r, m_c0 + c, m_columns[c].generate(r));
}
@ -744,7 +751,8 @@ public:
m_c0 + m_colCount - 1);
}
void onRelease(int row, int col) override {
void onRelease(const CellPosition &pos) override {
int row = pos.frame(), col = pos.layer();
int delta = m_r1 - (m_r0 + m_rowCount - 1);
if (delta == 0)
delete m_undo;
@ -883,9 +891,9 @@ public:
return soundColumn;
}
void onClick(int row, int col) override {
m_firstRow = row;
m_col = col;
void onClick(const CellPosition &pos) override {
m_firstRow = pos.frame();
m_col = pos.layer();
TXshSoundColumn *soundColumn = getColumn();
if (!soundColumn) return;
m_oldColumn = dynamic_cast<TXshSoundColumn *>(soundColumn->clone());
@ -893,8 +901,8 @@ public:
getViewer()->update();
}
void onDrag(int row, int col) override {
onChange(row);
void onDrag(const CellPosition &pos) override {
onChange(pos.frame());
refreshCellsArea();
}
@ -922,7 +930,8 @@ public:
TApp::instance()->getCurrentXsheet()->notifyXsheetSoundChanged();
}
void onRelease(int row, int col) override {
void onRelease(const CellPosition &pos) override {
int row = pos.frame();
if (row - m_firstRow == 0) {
m_undo = 0;
return;
@ -985,10 +994,11 @@ public:
LevelMoverTool::onDrag(e);
if (m_validPos) m_keyframeMoverTool->onDrag(e);
}
void onRelease(int row, int col) override {
void onRelease(const CellPosition &pos) override {
int row = pos.frame(), col = pos.layer();
TUndoManager::manager()->beginBlock();
LevelMoverTool::onRelease(row, col);
m_keyframeMoverTool->onRelease(row, col);
LevelMoverTool::onRelease(pos);
m_keyframeMoverTool->onRelease(pos);
TUndoManager::manager()->endBlock();
}
@ -1089,7 +1099,8 @@ public:
, m_r1(0)
, m_enable(true) {}
void onClick(int row, int col) override {
void onClick(const CellPosition &pos) override {
int row = pos.frame(), col = pos.layer();
m_r0 = m_r1 = row;
TXsheet *xsh = getViewer()->getXsheet();
TStageObjectId cameraId = xsh->getStageObjectTree()->getCurrentCameraId();
@ -1105,7 +1116,8 @@ public:
m_undo = new KeyFrameHandleUndo(objId, m_startRow);
}
void onDrag(int row, int col) override {
void onDrag(const CellPosition &pos) override {
int row = pos.frame(), col = pos.layer();
if (!m_enable) return;
m_r1 = row;
onCellChange(row, col);
@ -1127,7 +1139,8 @@ public:
m_stageObject->setKeyframeWithoutUndo(m_startRow, m_k);
}
void onRelease(int row, int col) override {
void onRelease(const CellPosition &pos) override {
int row = pos.frame(), col = pos.layer();
if (!m_enable) return;
if (m_r0 == m_r1)
delete m_undo;
@ -1175,21 +1188,22 @@ public:
m_startCol = notes->getNoteCol(currentIndex);
QPoint p = e->pos();
TPointD mousePos(p.x(), p.y());
TPointD cellTopLeft(getViewer()->columnToX(m_startCol),
getViewer()->rowToY(m_startRow));
QPoint xy = getViewer()->positionToXY(CellPosition(m_startRow, m_startCol));
TPointD cellTopLeft(xy.x(), xy.y());
m_delta = mousePos - (cellTopLeft + m_startPos);
}
void onChange(TPointD pos) {
pos = pos - m_delta;
int row = getViewer()->yToRow(pos.y);
int col = getViewer()->xToColumn(pos.x);
pos = pos - m_delta;
CellPosition cellPosition = getViewer()->xyToPosition(pos);
int row = cellPosition.frame();
int col = cellPosition.layer();
if (row < 0) row = 0;
if (col < 0) col = 0;
TPointD newPos =
pos - TPointD(getViewer()->columnToX(col), getViewer()->rowToY(row));
QPoint xy = getViewer()->positionToXY(CellPosition(row, col));
TPointD newPos = pos - TPointD(xy.x(), xy.y());
if (newPos.x < 0) newPos.x = 0;
if (newPos.y < 0) newPos.y = 0;
@ -1252,14 +1266,16 @@ public:
TApp::instance()->getCurrentFrame()->getFrame())
, m_isFos(isFos) {}
void onClick(int row, int col) override {
void onClick(const CellPosition &pos) override {
int row = pos.frame();
OnionSkinMask mask = m_modifier.getMask();
TApp::instance()->getCurrentOnionSkin()->setOnionSkinMask(mask);
m_modifier.click(row, m_isFos);
TApp::instance()->getCurrentOnionSkin()->notifyOnionSkinMaskChanged();
}
void onDrag(int row, int col) override {
void onDrag(const CellPosition &pos) override {
int row = pos.frame();
if (row < 0) row = 0;
onRowChange(row);
TApp::instance()->getCurrentOnionSkin()->notifyOnionSkinMaskChanged();
@ -1271,7 +1287,8 @@ public:
TApp::instance()->getCurrentOnionSkin()->setOnionSkinMask(mask);
}
void onRelease(int row, int col) override {
void onRelease(const CellPosition &pos) override {
int row = pos.frame();
m_modifier.release(row);
OnionSkinMask mask = m_modifier.getMask();
TApp::instance()->getCurrentOnionSkin()->setOnionSkinMask(mask);
@ -1302,12 +1319,14 @@ class CurrentFrameModifier final : public XsheetGUI::DragTool {
public:
CurrentFrameModifier(XsheetViewer *viewer) : DragTool(viewer) {}
void onClick(int row, int col) override {
void onClick(const CellPosition &pos) override {
int row = pos.frame();
TApp::instance()->getCurrentFrame()->setFrame(row);
refreshRowsArea();
}
void onDrag(int row, int col) override {
void onDrag(const CellPosition &pos) override {
int row = pos.frame();
if (row < 0) row = 0;
int lastRow = TApp::instance()->getCurrentFrame()->getFrameIndex();
if (lastRow == row) return;
@ -1322,7 +1341,7 @@ public:
app->getCurrentFrame()->scrubXsheet(row, row, getViewer()->getXsheet());
}
void onRelease(int row, int col) override {
void onRelease(const CellPosition &pos) override {
getViewer()->getXsheet()->stopScrub();
}
};
@ -1354,14 +1373,16 @@ public:
PlayRangeModifier(XsheetViewer *viewer)
: DragTool(viewer), m_movingFirst(false) {}
void onClick(int row, int col) override {
void onClick(const CellPosition &pos) override {
int row = pos.frame();
XsheetGUI::getPlayRange(m_oldR0, m_oldR1, m_oldStep);
assert(m_oldR0 == row || m_oldR1 == row);
m_movingFirst = m_oldR0 == row;
refreshRowsArea();
}
void onDrag(int row, int col) override {
void onDrag(const CellPosition &pos) override {
int row = pos.frame();
if (row < 0) row = 0;
onRowChange(row);
refreshRowsArea();
@ -1391,7 +1412,8 @@ public:
XsheetGUI::setPlayRange(r0, r1, step, false);
}
void onRelease(int row, int col) override {
void onRelease(const CellPosition &pos) override {
int row = pos.frame();
int newR0, newR1, newStep;
XsheetGUI::getPlayRange(newR0, newR1, newStep);
if (m_oldR0 != newR0 || m_oldR1 != newR1) {
@ -1428,7 +1450,8 @@ public:
void onClick(const QMouseEvent *event) override {
TColumnSelection *selection = getViewer()->getColumnSelection();
int col = getViewer()->xToColumn(event->pos().x());
CellPosition cellPosition = getViewer()->xyToPosition(event->pos());
int col = cellPosition.layer();
m_firstColumn = col;
bool isSelected = selection->isColumnSelected(col);
if (event->modifiers() & Qt::ControlModifier) {
@ -1453,7 +1476,8 @@ public:
getViewer()->update();
}
void onDrag(int row, int col) override {
void onDrag(const CellPosition &pos) override {
int col = pos.layer();
if (!m_enabled) return;
if (col < 0) return;
TColumnSelection *selection = getViewer()->getColumnSelection();
@ -1465,7 +1489,7 @@ public:
refreshCellsArea();
return;
}
void onRelease(int row, int col) override {
void onRelease(const CellPosition &pos) override {
TSelectionHandle::getCurrent()->notifySelectionChanged();
}
};
@ -1559,7 +1583,8 @@ public:
, m_lastCol(-1)
, m_offset(0) {}
void onClick(int row, int col) override {
void onClick(const CellPosition &pos) override {
int col = pos.layer();
TColumnSelection *selection = getViewer()->getColumnSelection();
if (!selection->isColumnSelected(col)) {
selection->selectNone();
@ -1574,7 +1599,8 @@ public:
assert(m_lastCol == *indices.begin());
getViewer()->update();
}
void onDrag(int row, int col) override {
void onDrag(const CellPosition &pos) override {
int col = pos.layer();
TColumnSelection *selection = getViewer()->getColumnSelection();
std::set<int> indices = selection->getIndices();
if (indices.empty()) return;
@ -1595,7 +1621,7 @@ public:
++it)
selection->selectColumn(*it + dCol, true);
}
void onRelease(int row, int col) override {
void onRelease(const CellPosition &pos) override {
int delta = m_lastCol - m_firstCol;
if (delta == 0) return;
TColumnSelection *selection = getViewer()->getColumnSelection();
@ -1657,9 +1683,11 @@ public:
ChangePegbarParentDragTool(XsheetViewer *viewer)
: XsheetGUI::DragTool(viewer), m_firstCol(-1), m_lastCol(-1) {}
void onClick(int row, int col) override { m_firstCol = m_lastCol = col; }
void onDrag(int row, int col) override { m_lastCol = col; }
void onRelease(int row, int col) override {
void onClick(const CellPosition &pos) override {
m_firstCol = m_lastCol = pos.layer();
}
void onDrag(const CellPosition &pos) override { m_lastCol = pos.layer(); }
void onRelease(const CellPosition &pos) override {
// TUndoManager::manager()->add(new ColumnMoveUndo(indices, delta));
TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
TStageObjectId columnId(getViewer()->getObjectId(m_firstCol));
@ -1732,9 +1760,14 @@ public:
void onDrag(const QMouseEvent *event) override {
if (!m_enabled) return;
double v =
(double)(60 - (event->pos().y() - (XsheetGUI::RowHeight * 2 + 4))) /
60.0;
const Orientation *o = getViewer()->orientation();
QRect track = o->rect(PredefinedRect::VOLUME_TRACK);
NumberRange range = o->frameSide(track);
int frameAxis = o->frameAxis(event->pos());
double v = range.ratio(frameAxis);
if (o->flipVolume()) v = 1 - v;
TXsheet *xsh = getViewer()->getXsheet();
TXshColumn *column = xsh->getColumn(m_index);
if (!column) return;
@ -1782,7 +1815,8 @@ public:
, m_oldRow(0)
, m_timerId(0) {}
void onClick(int row, int col) override {
void onClick(const CellPosition &pos) override {
int row = pos.frame(), col = pos.layer();
TColumnSelection *selection = getViewer()->getColumnSelection();
selection->selectNone();
m_startRow = row;
@ -1790,7 +1824,10 @@ public:
getViewer()->updateCells();
}
void onDrag(int row, int col) override { onCellChange(row, col); }
void onDrag(const CellPosition &pos) override {
int row = pos.frame(), col = pos.layer();
onCellChange(row, col);
}
void onCellChange(int row, int col) {
assert(m_startRow >= 0);
@ -1798,9 +1835,9 @@ public:
getViewer()->updateCells();
}
void onRelease(int row, int col) override {
int r0 = std::min(row, m_startRow);
int r1 = std::max(row, m_startRow);
void onRelease(const CellPosition &pos) override {
int r0 = std::min(pos.frame(), m_startRow);
int r1 = std::max(pos.frame(), m_startRow);
assert(m_soundColumn);
TApp *app = TApp::instance();
ToonzScene *scene = app->getCurrentScene()->getScene();
@ -1870,7 +1907,7 @@ enum CellMovementType { NO_MOVEMENT, INSERT_CELLS, OVERWRITE_CELLS };
class DataDragTool final : public XsheetGUI::DragTool {
DragAndDropData *m_data;
bool m_valid;
TPoint m_curPos;
TPoint m_curPos; // screen xy of drag begin
CellMovementType m_type;
protected:
@ -1928,8 +1965,9 @@ public:
}
void onDrag(const QDropEvent *e) override {
TPoint pos(e->pos().x(), e->pos().y());
int row = getViewer()->yToRow(pos.y);
int col = getViewer()->xToColumn(pos.x);
CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
int row = cellPosition.frame();
int col = cellPosition.layer();
m_valid = true;
if (e->keyboardModifiers() & Qt::ShiftModifier)
@ -1943,8 +1981,9 @@ public:
}
void onRelease(const QDropEvent *e) override {
TPoint pos(e->pos().x(), e->pos().y());
int row = getViewer()->yToRow(pos.y);
int col = getViewer()->xToColumn(pos.x);
CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
int row = cellPosition.frame();
int col = cellPosition.layer();
if (m_type != NO_MOVEMENT && !m_valid) return;
bool insert = m_type == INSERT_CELLS;
@ -1973,24 +2012,23 @@ public:
refreshCellsArea();
}
void drawCellsArea(QPainter &p) override {
TPoint pos(getViewer()->xToColumn(m_curPos.x),
getViewer()->yToRow(m_curPos.y));
TRect rect = m_data->getLevelFrameRect();
CellPosition beginDragPosition = getViewer()->xyToPosition(m_curPos);
TPoint pos(beginDragPosition.layer(),
beginDragPosition.frame()); // row and cell coordinates
TRect rect = m_data->getLevelFrameRect(); // row and cell coordinates
if (rect.isEmpty()) return;
rect += pos;
if (rect.x1 < 0 || rect.y1 < 0) return;
if (rect.x0 < 0) rect.x0 = 0;
if (rect.y0 < 0) rect.y0 = 0;
int x0, y0, x1, y1;
x0 = getViewer()->columnToX(rect.x0);
x1 = getViewer()->columnToX(rect.x1 + 1);
y0 = getViewer()->rowToY(rect.y0);
y1 = getViewer()->rowToY(rect.y1 + 1);
int x = x1 - x0;
int y = y1 - y0;
QRect screenCell = getViewer()->rangeToXYRect(
CellRange(CellPosition(rect.y0, rect.x0),
CellPosition(rect.y1 + 1, rect.x1 + 1)));
p.setPen(m_valid ? QColor(190, 220, 255) : QColor(255, 0, 0));
int i;
for (i = 0; i < 3; i++) p.drawRect(x0 + i, y0 + i, x - 2 * i, y - 2 * i);
for (i = 0; i < 3; i++) // thick border within cell
p.drawRect(QRect(screenCell.topLeft() + QPoint(i, i),
screenCell.size() - QSize(2 * i, 2 * i)));
}
};

View file

@ -4,6 +4,7 @@
#define XSHEET_DRAG_TOOL_H
#include "tgeometry.h"
#include "cellposition.h"
// forward declaration
class QPainter;
@ -28,9 +29,9 @@ public:
void refreshRowsArea();
void refreshColumnsArea();
virtual void onClick(int row, int col) {}
virtual void onDrag(int row, int col) {}
virtual void onRelease(int row, int col) {}
virtual void onClick(const CellPosition &pos) {}
virtual void onDrag(const CellPosition &pos) {}
virtual void onRelease(const CellPosition &pos) {}
virtual void onClick(const QMouseEvent *event);
virtual void onDrag(const QMouseEvent *event);

View file

@ -48,8 +48,10 @@ TEnv::IntVar FrameDisplayStyleInXsheetRowArea(
namespace XsheetGUI {
//-----------------------------------------------------------------------------
const int ColumnWidth = 74;
const int RowHeight = 20;
const int ColumnWidth = 74;
const int RowHeight = 20;
const int SCROLLBAR_WIDTH = 16;
const int TOOLBAR_HEIGHT = 30;
} // namespace XsheetGUI
@ -139,14 +141,6 @@ XsheetViewer::XsheetViewer(QWidget *parent, Qt::WindowFlags flags)
XsheetViewer::XsheetViewer(QWidget *parent, Qt::WFlags flags)
#endif
: QFrame(parent)
, m_x0(XsheetGUI::ColumnWidth + 1)
#ifndef LINETEST
, m_y0(XsheetGUI::RowHeight * 3 +
60) // Per tab il numero delle righe era 8 perche c'e' il linkBox
#else
, m_y0(XsheetGUI::RowHeight * 8 +
5) // Per tab il numero delle righe era 8 perche c'e' il linkBox
#endif
, m_timerId(0)
, m_autoPanSpeed(0, 0)
, m_dragTool(0)
@ -161,28 +155,31 @@ XsheetViewer::XsheetViewer(QWidget *parent, Qt::WFlags flags)
, m_isComputingSize(false)
, m_currentNoteIndex(0)
, m_qtModifiers(0)
, m_toolbarHeight(30)
, m_frameDisplayStyle(to_enum(FrameDisplayStyleInXsheetRowArea)) {
, m_frameDisplayStyle(to_enum(FrameDisplayStyleInXsheetRowArea))
, m_orientation(nullptr) {
setFocusPolicy(Qt::StrongFocus);
setFrameStyle(QFrame::StyledPanel);
setObjectName("XsheetViewer");
m_orientation = Orientations::topToBottom();
m_cellKeyframeSelection->setXsheetHandle(
TApp::instance()->getCurrentXsheet());
m_toolbarScrollArea = new XsheetScrollArea(this);
m_toolbarScrollArea->setFixedSize(m_x0 * 12, m_toolbarHeight);
m_toolbarScrollArea->setFixedSize(m_orientation->cellWidth() * 12, XsheetGUI::TOOLBAR_HEIGHT);
m_toolbarScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_toolbarScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_toolbar = new XsheetGUI::Toolbar(this);
m_toolbar->setFixedSize(m_x0 * 12, m_toolbarHeight);
m_toolbar->setFixedSize(m_orientation->cellWidth() * 12, XsheetGUI::TOOLBAR_HEIGHT);
m_toolbarScrollArea->setWidget(m_toolbar);
m_noteArea = new XsheetGUI::NoteArea(this);
m_noteArea->setFixedSize(m_x0 + 1, m_y0 - 3);
QRect noteArea(0, 0, 75, 120);
m_noteArea = new XsheetGUI::NoteArea(this);
m_noteScrollArea = new XsheetScrollArea(this);
m_noteScrollArea->setFixedSize(m_x0 + 1, m_y0 - 3);
m_noteScrollArea->setObjectName("xsheetArea");
m_noteScrollArea->setWidget(m_noteArea);
m_noteScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_noteScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
@ -193,8 +190,6 @@ XsheetViewer::XsheetViewer(QWidget *parent, Qt::WFlags flags)
m_cellScrollArea->setWidget(m_cellArea);
m_cellScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
m_cellScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
// m_cellScrollArea->horizontalScrollBar()->setObjectName("XsheetScrollBar");
// m_cellScrollArea->verticalScrollBar()->setObjectName("XsheetScrollBar");
m_columnArea = new XsheetGUI::ColumnArea(this);
m_columnScrollArea = new XsheetScrollArea(this);
@ -210,19 +205,16 @@ XsheetViewer::XsheetViewer(QWidget *parent, Qt::WFlags flags)
m_rowScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_rowScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
connect(m_rowScrollArea->verticalScrollBar(), SIGNAL(valueChanged(int)),
m_cellScrollArea->verticalScrollBar(), SLOT(setValue(int)));
connect(m_cellScrollArea->verticalScrollBar(), SIGNAL(valueChanged(int)),
m_rowScrollArea->verticalScrollBar(), SLOT(setValue(int)));
connect(m_columnScrollArea->horizontalScrollBar(), SIGNAL(valueChanged(int)),
m_cellScrollArea->horizontalScrollBar(), SLOT(setValue(int)));
connect(m_cellScrollArea->horizontalScrollBar(), SIGNAL(valueChanged(int)),
m_columnScrollArea->horizontalScrollBar(), SLOT(setValue(int)));
m_frameScroller.setFrameScrollArea(m_cellScrollArea);
connect(&m_frameScroller, &Spreadsheet::FrameScroller::prepareToScrollOffset,
this, &XsheetViewer::onPrepareToScrollOffset);
connect(m_cellScrollArea->verticalScrollBar(), SIGNAL(valueChanged(int)),
SLOT(updateCellRowAree()));
connect(m_cellScrollArea->horizontalScrollBar(), SIGNAL(valueChanged(int)),
SLOT(updateCellColumnAree()));
connectScrollBars();
connect(this, &XsheetViewer::orientationChanged, this,
&XsheetViewer::onOrientationChanged);
emit orientationChanged(orientation());
}
//-----------------------------------------------------------------------------
@ -284,6 +276,115 @@ void XsheetViewer::dragToolLeave(QEvent *e) {
//-----------------------------------------------------------------------------
const Orientation *XsheetViewer::orientation() const {
if (!m_orientation) throw std::runtime_error("!m_orientation");
return m_orientation;
}
void XsheetViewer::flipOrientation() {
m_orientation = orientation()->next();
emit orientationChanged(orientation());
}
void XsheetViewer::onOrientationChanged(const Orientation *newOrientation) {
disconnectScrollBars();
positionSections();
m_frameScroller.setOrientation(newOrientation);
refreshContentSize(0, 0);
connectScrollBars();
update();
}
void XsheetViewer::positionSections() {
const Orientation *o = orientation();
QRect size = QRect(QPoint(0, 0), geometry().size());
NumberRange allLayer = o->layerSide(size);
NumberRange allFrame = o->frameSide(size);
NumberRange headerLayer = o->range(PredefinedRange::HEADER_LAYER);
NumberRange headerFrame = o->range(PredefinedRange::HEADER_FRAME);
NumberRange bodyLayer(headerLayer.to(), allLayer.to());
NumberRange bodyFrame(headerFrame.to(), allFrame.to());
if (Preferences::instance()->isShowXSheetToolbarEnabled()) {
m_toolbar->showToolbar(true);
int w = geometry().size().width();
m_toolbarScrollArea->setGeometry(0, 0, w, XsheetGUI::TOOLBAR_HEIGHT);
if (o->isVerticalTimeline()) {
headerFrame = headerFrame.adjusted(XsheetGUI::TOOLBAR_HEIGHT, XsheetGUI::TOOLBAR_HEIGHT);
bodyFrame = bodyFrame.adjusted(XsheetGUI::TOOLBAR_HEIGHT, 0);
}
else {
headerLayer = headerLayer.adjusted(XsheetGUI::TOOLBAR_HEIGHT, XsheetGUI::TOOLBAR_HEIGHT);
bodyLayer = bodyLayer.adjusted(XsheetGUI::TOOLBAR_HEIGHT, 0);
}
}
else {
m_toolbar->showToolbar(false);
}
m_noteScrollArea->setGeometry(o->frameLayerRect(headerFrame, headerLayer));
m_cellScrollArea->setGeometry(o->frameLayerRect(bodyFrame, bodyLayer));
m_columnScrollArea->setGeometry(o->frameLayerRect(
headerFrame.adjusted(-1,-1), bodyLayer.adjusted(0, -XsheetGUI::SCROLLBAR_WIDTH)));
m_rowScrollArea->setGeometry(o->frameLayerRect(
bodyFrame.adjusted(0, -XsheetGUI::SCROLLBAR_WIDTH), headerLayer));
}
void XsheetViewer::disconnectScrollBars() {
connectOrDisconnectScrollBars(false);
}
void XsheetViewer::connectScrollBars() { connectOrDisconnectScrollBars(true); }
void XsheetViewer::connectOrDisconnectScrollBars(bool toConnect) {
const Orientation *o = orientation();
bool isVertical = o->isVerticalTimeline();
QWidget *scrolledVertically =
(isVertical ? m_rowScrollArea : m_columnScrollArea)->verticalScrollBar();
QWidget *scrolledHorizontally =
(isVertical ? m_columnScrollArea : m_rowScrollArea)
->horizontalScrollBar();
connectOrDisconnect(toConnect, scrolledVertically, SIGNAL(valueChanged(int)),
m_cellScrollArea->verticalScrollBar(),
SLOT(setValue(int)));
connectOrDisconnect(toConnect, m_cellScrollArea->verticalScrollBar(),
SIGNAL(valueChanged(int)), scrolledVertically,
SLOT(setValue(int)));
connectOrDisconnect(
toConnect, scrolledHorizontally, SIGNAL(valueChanged(int)),
m_cellScrollArea->horizontalScrollBar(), SLOT(setValue(int)));
connectOrDisconnect(toConnect, m_cellScrollArea->horizontalScrollBar(),
SIGNAL(valueChanged(int)), scrolledHorizontally,
SLOT(setValue(int)));
connectOrDisconnect(
toConnect, m_cellScrollArea->verticalScrollBar(),
SIGNAL(valueChanged(int)), this,
isVertical ? SLOT(updateCellRowAree()) : SLOT(updateCellColumnAree()));
connectOrDisconnect(
toConnect, m_cellScrollArea->horizontalScrollBar(),
SIGNAL(valueChanged(int)), this,
isVertical ? SLOT(updateCellColumnAree()) : SLOT(updateCellRowAree()));
}
void XsheetViewer::connectOrDisconnect(bool toConnect, QWidget *sender,
const char *signal, QWidget *receiver,
const char *slot) {
if (toConnect)
connect(sender, signal, receiver, slot);
else
disconnect(sender, signal, receiver, slot);
}
//-----------------------------------------------------------------------------
TXsheet *XsheetViewer::getXsheet() const {
return TApp::instance()->getCurrentXsheet()->getXsheet();
}
@ -361,8 +462,7 @@ frameHandle->setFrame(row);*/
void XsheetViewer::scroll(QPoint delta) {
int x = delta.x();
int y = delta.y();
prepareToScroll(y);
int valueH = m_cellScrollArea->horizontalScrollBar()->value() + x;
int valueV = m_cellScrollArea->verticalScrollBar()->value() + y;
int maxValueH = m_cellScrollArea->horizontalScrollBar()->maximum();
@ -391,7 +491,9 @@ void XsheetViewer::scroll(QPoint delta) {
//-----------------------------------------------------------------------------
void XsheetViewer::onPrepareToScroll(int dy) { refreshContentSize(0, dy); }
void XsheetViewer::onPrepareToScrollOffset(const QPoint &offset) {
refreshContentSize(offset.x(), offset.y());
}
//-----------------------------------------------------------------------------
@ -445,18 +547,20 @@ void XsheetViewer::timerEvent(QTimerEvent *) {
//-----------------------------------------------------------------------------
// adjust sizes after scrolling event
bool XsheetViewer::refreshContentSize(int dx, int dy) {
QSize viewportSize = m_cellScrollArea->viewport()->size();
QPoint offset = m_cellArea->pos();
offset = QPoint(qMin(0, offset.x() - dx), qMin(0, offset.y() - dy));
offset = QPoint(qMin(0, offset.x() - dx), qMin(0, offset.y() - dy)); // what?
TXsheet *xsh = getXsheet();
int frameCount = xsh ? xsh->getFrameCount() : 0;
int columnCount = xsh ? xsh->getColumnCount() : 0;
QSize contentSize(columnToX(columnCount + 1), rowToY(frameCount + 1));
QPoint contentSize =
positionToXY(CellPosition(frameCount + 1, columnCount + 1));
QSize actualSize(contentSize);
int x = viewportSize.width() - offset.x();
QSize actualSize(contentSize.x(), contentSize.y());
int x = viewportSize.width() - offset.x(); // wtf is going on
int y = viewportSize.height() - offset.y();
if (x > actualSize.width()) actualSize.setWidth(x);
if (y > actualSize.height()) actualSize.setHeight(y);
@ -464,10 +568,17 @@ bool XsheetViewer::refreshContentSize(int dx, int dy) {
if (actualSize == m_cellArea->size())
return false;
else {
const Orientation *o = orientation();
NumberRange allLayer = o->layerSide(QRect(QPoint(0, 0), actualSize));
NumberRange allFrame = o->frameSide(QRect(QPoint(0, 0), actualSize));
NumberRange headerLayer = o->range(PredefinedRange::HEADER_LAYER);
NumberRange headerFrame = o->range(PredefinedRange::HEADER_FRAME);
m_isComputingSize = true;
m_noteArea->setFixedSize(o->rect(PredefinedRect::NOTE_AREA).size());
m_cellArea->setFixedSize(actualSize);
m_rowArea->setFixedSize(m_x0, actualSize.height());
m_columnArea->setFixedSize(actualSize.width(), m_y0);
m_rowArea->setFixedSize(o->frameLayerRect(allFrame, headerLayer).size());
m_columnArea->setFixedSize(o->frameLayerRect(headerFrame, allLayer).size());
m_isComputingSize = false;
return true;
}
@ -475,43 +586,92 @@ bool XsheetViewer::refreshContentSize(int dx, int dy) {
//-----------------------------------------------------------------------------
// call when in doubt
void XsheetViewer::updateAreeSize() {
int w = m_cellScrollArea->width() - 15;
int h = m_cellScrollArea->height() - 15;
const Orientation *o = orientation();
QRect viewArea(QPoint(0, 0), m_cellScrollArea->geometry()
.adjusted(0, 0, -XsheetGUI::SCROLLBAR_WIDTH,
-XsheetGUI::SCROLLBAR_WIDTH)
.size());
TXsheet *xsh = getXsheet();
int frameCount = xsh ? xsh->getFrameCount() : 0;
int hCounted = (XsheetGUI::RowHeight) * (frameCount + 1);
if (h < hCounted) h = hCounted;
QPoint areaFilled(0, 0);
TXsheet *xsh = getXsheet();
if (xsh)
areaFilled = positionToXY(
CellPosition(xsh->getFrameCount() + 1, xsh->getColumnCount() + 1));
if (viewArea.right() < areaFilled.x()) viewArea.setRight(areaFilled.x());
if (viewArea.bottom() < areaFilled.y()) viewArea.setBottom(areaFilled.y());
int columnCount = xsh ? xsh->getColumnCount() : 0;
int wCounted = (XsheetGUI::ColumnWidth) * (columnCount + 1);
if (w < wCounted) w = wCounted;
NumberRange allLayer = o->layerSide(viewArea);
NumberRange allFrame = o->frameSide(viewArea);
NumberRange headerLayer = o->range(PredefinedRange::HEADER_LAYER);
NumberRange headerFrame = o->range(PredefinedRange::HEADER_FRAME);
m_cellArea->setFixedSize(w, h);
m_rowArea->setFixedSize(m_x0, h);
m_columnArea->setFixedSize(w, m_y0);
m_cellArea->setFixedSize(viewArea.size());
m_rowArea->setFixedSize(o->frameLayerRect(allFrame, headerLayer).size());
m_columnArea->setFixedSize(o->frameLayerRect(headerFrame, allLayer).size());
}
//-----------------------------------------------------------------------------
int XsheetViewer::xToColumn(int x) const {
return getXsheet()->getColumnFan()->xToCol(x);
CellPosition XsheetViewer::xyToPosition(const QPoint &point) const {
const Orientation *o = orientation();
return o->xyToPosition(point, getXsheet()->getColumnFan(o));
}
CellPosition XsheetViewer::xyToPosition(const TPoint &point) const {
return xyToPosition(QPoint(point.x, point.y));
}
CellPosition XsheetViewer::xyToPosition(const TPointD &point) const {
return xyToPosition(QPoint((int)point.x, (int)point.y));
}
//-----------------------------------------------------------------------------
int XsheetViewer::yToRow(int y) const { return y / XsheetGUI::RowHeight; }
QPoint XsheetViewer::positionToXY(const CellPosition &pos) const {
const Orientation *o = orientation();
return o->positionToXY(pos, getXsheet()->getColumnFan(o));
}
//-----------------------------------------------------------------------------
int XsheetViewer::columnToX(int col) const {
return getXsheet()->getColumnFan()->colToX(col);
int XsheetViewer::columnToLayerAxis(int layer) const {
const Orientation *o = orientation();
return o->colToLayerAxis(layer, getXsheet()->getColumnFan(o));
}
int XsheetViewer::rowToFrameAxis(int frame) const {
return orientation()->rowToFrameAxis(frame);
}
//-----------------------------------------------------------------------------
int XsheetViewer::rowToY(int row) const { return row * XsheetGUI::RowHeight; }
CellRange XsheetViewer::xyRectToRange(const QRect &rect) const {
CellPosition topLeft = xyToPosition(rect.topLeft());
CellPosition bottomRight = xyToPosition(rect.bottomRight());
return CellRange(topLeft, bottomRight);
}
//-----------------------------------------------------------------------------
QRect XsheetViewer::rangeToXYRect(const CellRange &range) const {
QPoint from = positionToXY(range.from());
QPoint to = positionToXY(range.to());
QPoint topLeft = QPoint(min(from.x(), to.x()), min(from.y(), to.y()));
QPoint bottomRight = QPoint(max(from.x(), to.x()), max(from.y(), to.y()));
return QRect(topLeft, bottomRight);
}
//-----------------------------------------------------------------------------
void XsheetViewer::drawPredefinedPath(QPainter &p, PredefinedPath which,
const CellPosition &pos,
optional<QColor> fill,
optional<QColor> outline) const {
QPoint xy = positionToXY(pos);
QPainterPath path = orientation()->path(which).translated(xy);
if (fill) p.fillPath(path, QBrush(*fill));
if (outline) {
p.setPen(*outline);
p.drawPath(path);
}
}
//-----------------------------------------------------------------------------
@ -590,7 +750,7 @@ bool XsheetViewer::isScrubHighlighted(int row, int col) {
//-----------------------------------------------------------------------------
void XsheetViewer::showEvent(QShowEvent *) {
registerFrameScroller();
m_frameScroller.registerFrameScroller();
if (m_isCurrentFrameSwitched) onCurrentFrameSwitched();
if (m_isCurrentColumnSwitched) onCurrentColumnSwitched();
m_isCurrentFrameSwitched = false;
@ -651,7 +811,7 @@ void XsheetViewer::showEvent(QShowEvent *) {
//-----------------------------------------------------------------------------
void XsheetViewer::hideEvent(QHideEvent *) {
unregisterFrameScroller();
m_frameScroller.unregisterFrameScroller();
TApp *app = TApp::instance();
@ -704,39 +864,13 @@ void XsheetViewer::paintEvent(QPaintEvent*)
//-----------------------------------------------------------------------------
void XsheetViewer::updatePanelsSizes() {
int w = width();
int h = height();
int scrollBarWidth = 16;
if (Preferences::instance()->isShowXSheetToolbarEnabled()) {
m_toolbar->showToolbar(true);
m_toolbarScrollArea->setGeometry(1, 1, m_x0 * 12, m_y0 - 3);
m_noteScrollArea->setGeometry(3, m_toolbarHeight + 1, m_x0 - 4, m_y0 - 3);
m_cellScrollArea->setGeometry(m_x0, m_y0 + m_toolbarHeight, w - m_x0,
h - m_y0 - m_toolbarHeight);
m_columnScrollArea->setGeometry(m_x0, m_toolbarHeight + 1,
w - m_x0 - scrollBarWidth, m_y0 - 3);
m_rowScrollArea->setGeometry(1, m_y0 + m_toolbarHeight, m_x0 - 1,
h - m_y0 - scrollBarWidth - m_toolbarHeight);
} else {
m_toolbar->showToolbar(false);
m_toolbarScrollArea->setGeometry(3, 1, m_x0 - 4, m_y0 - 3);
m_noteScrollArea->setGeometry(3, 1, m_x0 - 4, m_y0 - 3);
m_cellScrollArea->setGeometry(m_x0, m_y0, w - m_x0, h - m_y0);
m_columnScrollArea->setGeometry(m_x0, 1, w - m_x0 - scrollBarWidth,
m_y0 - 3);
m_rowScrollArea->setGeometry(1, m_y0, m_x0 - 1, h - m_y0 - scrollBarWidth);
}
}
//-----------------------------------------------------------------------------
void XsheetViewer::resizeEvent(QResizeEvent *event) {
updatePanelsSizes();
//(Nuovo Layout Manager) Reintrodotto per il refresh automatico
positionSections();
//(New Layout Manager) introduced automatic refresh
refreshContentSize(
0,
0); // Non updateAreeSize() perche' si deve tener conto degli scrollbar.
0); // Don't updateAreeSize because you have to account scrollbars
updateAllAree();
}
@ -751,13 +885,19 @@ void XsheetViewer::wheelEvent(QWheelEvent *event) {
->getScene()
->getProperties()
->getMarkers(markerDistance, markerOffset);
if (event->angleDelta().x() == 0) { // vertical scroll
if (!orientation()->isVerticalTimeline())
markerDistance = 1;
int scrollPixels = (event->angleDelta().y() > 0 ? 1 : -1) *
markerDistance * XsheetGUI::RowHeight;
markerDistance * orientation()->cellHeight();
scroll(QPoint(0, -scrollPixels));
} else { // horizontal scroll
if (orientation()->isVerticalTimeline())
markerDistance = 1;
int scrollPixels =
(event->angleDelta().x() > 0 ? 1 : -1) * XsheetGUI::ColumnWidth;
(event->angleDelta().x() > 0 ? 1 : -1) *
markerDistance * orientation()->cellWidth();
scroll(QPoint(-scrollPixels, 0));
}
break;
@ -806,9 +946,10 @@ void XsheetViewer::keyPressEvent(QKeyEvent *event) {
if (changeFrameSkippingHolds(event)) return;
int frameCount = getXsheet()->getFrameCount();
int row = getCurrentRow(), col = getCurrentColumn();
CellPosition now(getCurrentRow(), getCurrentColumn());
CellPosition shift = orientation()->arrowShift(event->key());
CellPosition stride(1, 1); // stride in row and column axes
int rowStride = 1;
TCellSelection *cellSel =
dynamic_cast<TCellSelection *>(TSelection::getCurrent());
// Use arrow keys to shift the cell selection. Ctrl + arrow keys to resize the
@ -817,77 +958,62 @@ void XsheetViewer::keyPressEvent(QKeyEvent *event) {
cellSel && !cellSel->isEmpty()) {
int r0, c0, r1, c1;
cellSel->getSelectedCells(r0, c0, r1, c1);
rowStride = cellSel->getSelectedCells().getRowCount();
QPoint offset(0, 0);
switch (int key = event->key()) {
case Qt::Key_Up:
offset.setY(-1);
break;
case Qt::Key_Down:
offset.setY(1);
break;
case Qt::Key_Left:
offset.setX(-1);
break;
case Qt::Key_Right:
offset.setX(1);
break;
}
if (m_cellArea->isControlPressed()) {
if (r0 == r1 && offset.y() == -1) return;
if (c0 == c1 && offset.x() == -1) return;
cellSel->selectCells(r0, c0, r1 + offset.y(), c1 + offset.x());
stride.setFrame(cellSel->getSelectedCells().getRowCount());
if (m_cellArea->isControlPressed()) { // resize
if (r0 == r1 && shift.frame() < 0) return;
if (c0 == c1 && shift.layer() < 0) return;
cellSel->selectCells(r0, c0, r1 + shift.frame(), c1 + shift.layer());
updateCells();
TApp::instance()->getCurrentSelection()->notifySelectionChanged();
return;
} else {
offset.setY(offset.y() * rowStride);
if (r0 + offset.y() < 0) offset.setY(-r0);
if (c0 + offset.x() < 0) return;
cellSel->selectCells(r0 + offset.y(), c0 + offset.x(), r1 + offset.y(),
c1 + offset.x());
} else { // shift
CellPosition offset(shift * stride);
int movedR0 = std::max(0, r0 + offset.frame());
int movedC0 = std::max(0, c0 + offset.layer());
int diffFrame = movedR0 - r0;
int diffLayer = movedC0 - c0;
cellSel->selectCells(r0 + diffFrame, c0 + diffLayer, r1 + diffFrame,
c1 + diffLayer);
TApp::instance()->getCurrentSelection()->notifySelectionChanged();
}
}
if (shift) {
now = now + shift * stride;
now.ensureValid();
setCurrentRow(now.frame());
setCurrentColumn(now.layer());
return;
}
switch (int key = event->key()) {
case Qt::Key_Up:
setCurrentRow(std::max(row - rowStride, 0));
break;
case Qt::Key_Down:
setCurrentRow(row + rowStride);
break;
case Qt::Key_Left:
setCurrentColumn(std::max(col - 1, 0));
break;
case Qt::Key_Right:
setCurrentColumn(col + 1);
break;
case Qt::Key_Control:
// display the upper-directional smart tab only when the ctrl key is pressed
m_cellArea->onControlPressed(true);
break;
m_columnArea->onControlPressed(true);
break;
default: {
QRect visibleRect = m_cellArea->visibleRegion().boundingRect();
int visibleRowCount = visibleRect.height() / XsheetGUI::RowHeight;
int visibleRowCount = visibleRect.height() / orientation()->cellHeight();
switch (key) {
case Qt::Key_PageUp:
locals.scrollTo(
visibleRect.top() - visibleRowCount * XsheetGUI::RowHeight,
visibleRect.top() - visibleRowCount * orientation()->cellHeight(),
visibleRect);
break;
case Qt::Key_PageDown:
locals.scrollTo(
visibleRect.bottom() + visibleRowCount * XsheetGUI::RowHeight,
visibleRect.bottom() + visibleRowCount * orientation()->cellHeight(),
visibleRect);
break;
case Qt::Key_Home:
locals.scrollTo(0, visibleRect);
break;
case Qt::Key_End:
locals.scrollTo((frameCount + 1) * XsheetGUI::RowHeight, visibleRect);
locals.scrollTo((frameCount + 1) * orientation()->cellHeight(), visibleRect);
break;
}
break;
@ -898,18 +1024,24 @@ void XsheetViewer::keyPressEvent(QKeyEvent *event) {
//-----------------------------------------------------------------------------
// display the upper-directional smart tab only when the ctrl key is pressed
void XsheetViewer::keyReleaseEvent(QKeyEvent *event) {
if (event->key() == Qt::Key_Control) m_cellArea->onControlPressed(false);
if (event->key() == Qt::Key_Control) {
m_cellArea->onControlPressed(false);
m_columnArea->onControlPressed(false);
}
}
void XsheetViewer::enterEvent(QEvent *) { m_cellArea->onControlPressed(false); }
void XsheetViewer::enterEvent(QEvent *) {
m_cellArea->onControlPressed(false);
m_columnArea->onControlPressed(false);
}
//-----------------------------------------------------------------------------
/*! scroll the cell area to make a cell at (row,col) visible
*/
void XsheetViewer::scrollTo(int row, int col) {
QRect visibleRect = m_cellArea->visibleRegion().boundingRect();
QRect cellRect(columnToX(col), rowToY(row), XsheetGUI::ColumnWidth,
XsheetGUI::RowHeight);
QPoint topLeft = positionToXY(CellPosition(row, col));
QRect cellRect(topLeft, QSize(orientation()->cellWidth(), orientation()->cellHeight()));
int deltaX = 0;
int deltaY = 0;
@ -949,7 +1081,10 @@ void XsheetViewer::onXsheetChanged() {
//-----------------------------------------------------------------------------
void XsheetViewer::onPreferenceChanged(const QString &prefName) {
if (prefName == "XSheetToolbar") updatePanelsSizes();
if (prefName == "XSheetToolbar") {
positionSections();
refreshContentSize(0, 0);
}
}
//-----------------------------------------------------------------------------
@ -988,50 +1123,63 @@ void XsheetViewer::onCurrentColumnSwitched() {
//-----------------------------------------------------------------------------
void XsheetViewer::scrollToColumn(int col) {
int x0 = columnToX(col);
int x1 = columnToX(col + 1);
int x0 = columnToLayerAxis(col);
int x1 = columnToLayerAxis(col + 1);
scrollToHorizontalRange(x0, x1);
if (orientation()->isVerticalTimeline())
scrollToHorizontalRange(x0, x1);
else
scrollToVerticalRange(x0, x1);
}
//-----------------------------------------------------------------------------
void XsheetViewer::scrollToHorizontalRange(int x0, int x1) {
QRect visibleRect = m_cellArea->visibleRegion().boundingRect();
int visibleLeft = visibleRect.left();
int visibleRight = visibleRect.right();
if (visibleRect.isEmpty()) return;
int visibleLeft = visibleRect.left();
int visibleRight = visibleRect.right();
if (visibleLeft > x1) { // Se sono fuori dalla regione visibile in alto
if (visibleLeft > x0) { // If they are out of left visible region
int deltaX = x0 - visibleLeft;
scroll(QPoint(deltaX, 0));
return;
}
if (visibleRight < x1) { // Se sono fuori dalla regione visibile in basso
if (visibleRight < x1) { // If they are out of right visible region
int deltaX = x1 + 2 - visibleRight;
scroll(QPoint(deltaX, 0));
return;
}
updateCellColumnAree();
if (orientation()->isVerticalTimeline())
updateCellColumnAree();
else
updateCellRowAree();
}
//-----------------------------------------------------------------------------
void XsheetViewer::scrollToRow(int row) {
int y0 = rowToY(row);
int y1 = rowToY(row + 1);
int y0 = rowToFrameAxis(row);
int y1 = rowToFrameAxis(row + 1);
scrollToVerticalRange(y0, y1);
if (orientation()->isVerticalTimeline())
scrollToVerticalRange(y0, y1);
else
scrollToHorizontalRange(y0, y1);
}
//-----------------------------------------------------------------------------
void XsheetViewer::scrollToVerticalRange(int y0, int y1) {
int yMin = min(y0, y1);
int yMax = max(y0, y1);
QRect visibleRect = m_cellArea->visibleRegion().boundingRect();
if (visibleRect.isEmpty()) return;
int visibleTop = visibleRect.top();
int visibleBottom = visibleRect.bottom();
if (visibleTop > y0) { // Se sono fuori dalla regione visibile in alto
int deltaY = y0 - visibleTop;
if (visibleTop > yMin) { // If they are out of top visible region
int deltaY = yMin - visibleTop;
if (!TApp::instance()->getCurrentFrame()->isPlaying() ||
Preferences::instance()->isXsheetAutopanEnabled()) {
scroll(QPoint(0, deltaY));
@ -1039,16 +1187,18 @@ void XsheetViewer::scrollToVerticalRange(int y0, int y1) {
}
}
if (visibleBottom < y1) { // Se sono fuori dalla regione visibile in basso
int deltaY = y1 + 2 - visibleBottom;
if (visibleBottom < yMax) { // If they are out of bottom visible region
int deltaY = yMax + 2 - visibleBottom;
if (!TApp::instance()->getCurrentFrame()->isPlaying() ||
Preferences::instance()->isXsheetAutopanEnabled()) {
scroll(QPoint(0, deltaY));
return;
}
}
m_rowArea->update(m_rowArea->visibleRegion());
m_cellArea->update(m_cellArea->visibleRegion());
if (orientation()->isVerticalTimeline())
updateCellRowAree();
else
updateCellColumnAree();
}
//-----------------------------------------------------------------------------
@ -1089,6 +1239,7 @@ void XsheetViewer::updateAllAree(bool isDragging) {
m_rowArea->update(m_rowArea->visibleRegion());
m_columnArea->update(m_columnArea->visibleRegion());
}
m_toolbar->update(m_toolbar->visibleRegion());
}
//-----------------------------------------------------------------------------
@ -1166,12 +1317,12 @@ void XsheetViewer::setCurrentNoteIndex(int currentNoteIndex) {
int col = notes->getNoteCol(currentNoteIndex);
TPointD pos = notes->getNotePos(currentNoteIndex);
int x0 = columnToX(col) + pos.x;
int x1 = x0 + XsheetGUI::NoteWidth;
scrollToHorizontalRange(x0, x1);
int y0 = rowToY(row) + pos.y;
int y1 = y0 + XsheetGUI::NoteHeight;
scrollToVerticalRange(y0, y1);
QPoint topLeft = positionToXY(CellPosition(row, col)) +
QPoint(pos.x, pos.y); // actually xy
QSize size(XsheetGUI::NoteWidth, XsheetGUI::NoteHeight);
QRect noteRect(topLeft, size);
scrollToHorizontalRange(noteRect.left(), noteRect.right());
scrollToVerticalRange(noteRect.top(), noteRect.bottom());
}
//-----------------------------------------------------------------------------
@ -1295,6 +1446,19 @@ void XsheetViewer::setFrameDisplayStyle(FrameDisplayStyle style) {
FrameDisplayStyleInXsheetRowArea = (int)style;
}
//-----------------------------------------------------------------------------
void XsheetViewer::save(QSettings &settings) const {
settings.setValue("orientation", orientation()->name());
}
void XsheetViewer::load(QSettings &settings) {
QVariant name = settings.value("orientation");
if (!name.canConvert(QVariant::String)) return;
m_orientation = Orientations::byName(name.toString());
emit orientationChanged(orientation());
}
//-----------------------------------------------------------------------------
/*
TPanel *createXsheetViewer(QWidget *parent)

View file

@ -12,7 +12,12 @@
#include "xshnoteviewer.h"
#include "xshtoolbar.h"
#include "cellkeyframeselection.h"
#include "saveloadqsettings.h"
#include "toonzqt/spreadsheetviewer.h"
#include "orientation.h"
#include <boost/optional.hpp>
using boost::optional;
#define XSHEET_FONT_PX_SIZE 12
#define H_ADJUST 2
@ -150,7 +155,7 @@ protected:
//! Note: some refactoring is needed. XsheetViewer is going to derive from
//! SpreadsheetViewer.
class XsheetViewer final : public QFrame, public Spreadsheet::FrameScroller {
class XsheetViewer final : public QFrame, public SaveLoadQSettings {
Q_OBJECT
QColor m_lightLightBgColor;
@ -322,7 +327,8 @@ class XsheetViewer final : public QFrame, public Spreadsheet::FrameScroller {
XsheetGUI::NoteArea *m_noteArea;
XsheetGUI::Toolbar *m_toolbar;
int m_x0, m_y0, m_toolbarHeight;
Spreadsheet::FrameScroller m_frameScroller;
int m_timerId;
QPoint m_autoPanSpeed;
QPoint m_lastAutoPanPos;
@ -344,6 +350,8 @@ class XsheetViewer final : public QFrame, public Spreadsheet::FrameScroller {
Qt::KeyboardModifiers m_qtModifiers;
const Orientation *m_orientation;
public:
enum FrameDisplayStyle { Frame = 0, SecAndFrame, SixSecSheet, ThreeSecSheet };
@ -417,7 +425,6 @@ public:
void setCurrentRow(int row);
void scroll(QPoint delta);
void onPrepareToScroll(int dy) override;
void setAutoPanSpeed(const QPoint &speed);
void setAutoPanSpeed(const QRect &widgetBounds, const QPoint &mousePos);
@ -426,22 +433,33 @@ public:
return m_autoPanSpeed.x() != 0 || m_autoPanSpeed.y() != 0;
}
int xToColumn(int x) const;
int yToRow(int y) const;
int columnToX(int col) const;
int rowToY(int row) const;
//-------
const Orientation *orientation() const;
void flipOrientation();
CellPosition xyToPosition(const QPoint &point) const;
CellPosition xyToPosition(const TPoint &point) const;
CellPosition xyToPosition(const TPointD &point) const;
QPoint positionToXY(const CellPosition &pos) const;
int columnToLayerAxis(int layer) const;
int rowToFrameAxis(int frame) const;
CellRange xyRectToRange(const QRect &rect) const;
QRect rangeToXYRect(const CellRange &range) const;
void drawPredefinedPath(QPainter &p, PredefinedPath which,
const CellPosition &pos, optional<QColor> fill,
optional<QColor> outline) const;
//---------
void updateCells() { m_cellArea->update(m_cellArea->visibleRegion()); }
void updateRows() { m_rowArea->update(m_rowArea->visibleRegion()); }
void updateColumns() { m_columnArea->update(m_columnArea->visibleRegion()); }
void updatePanelsSizes();
bool refreshContentSize(int scrollDx, int scrollDy);
void updateAreeSize();
// provvisorio
QScrollArea *getFrameScrollArea() const override { return m_cellScrollArea; }
QList<XsheetGUI::NoteWidget *> getNotesWidget() const;
void addNoteWidget(XsheetGUI::NoteWidget *w);
int getCurrentNoteIndex() const;
@ -660,6 +678,10 @@ public:
void setFrameDisplayStyle(FrameDisplayStyle style);
FrameDisplayStyle getFrameDisplayStyle() { return m_frameDisplayStyle; }
// SaveLoadQSettings
virtual void save(QSettings &settings) const override;
virtual void load(QSettings &settings) override;
protected:
void scrollToColumn(int col);
void scrollToHorizontalRange(int x0, int x1);
@ -676,6 +698,15 @@ protected:
void wheelEvent(QWheelEvent *event) override;
void timerEvent(QTimerEvent *) override;
void positionSections();
void disconnectScrollBars();
void connectScrollBars();
void connectOrDisconnectScrollBars(bool toConnect);
void connectOrDisconnect(bool toConnect, QWidget *sender, const char *signal,
QWidget *receiver, const char *slot);
signals:
void orientationChanged(const Orientation *newOrientation);
public slots:
void onSceneSwitched();
void onXsheetChanged();
@ -697,6 +728,9 @@ public slots:
void changeWindowTitle();
void resetXsheetNotes();
void onOrientationChanged(const Orientation *newOrientation);
void onPrepareToScrollOffset(const QPoint &offset);
};
#endif // XSHEETVIEWER_H

View file

@ -14,6 +14,7 @@
#include "toonz/txshnoteset.h"
#include "toonz/sceneproperties.h"
#include "toonz/txsheethandle.h"
#include "orientation.h"
// Qt includes
#include <QVariant>
@ -372,7 +373,7 @@ NoteWidget::NoteWidget(XsheetViewer *parent, int noteIndex)
void NoteWidget::paint(QPainter *painter, QPoint pos, bool isCurrent) {
painter->translate(pos);
QRect rect(0, 0, width(), height());
QRect rect = m_viewer->orientation()->rect(PredefinedRect::NOTE_ICON);
TXshNoteSet *notes = m_viewer->getXsheet()->getNotes();
TSceneProperties *sp = m_viewer->getXsheet()->getScene()->getProperties();
@ -450,23 +451,38 @@ NoteArea::NoteArea(XsheetViewer *parent, Qt::WindowFlags flags)
#else
NoteArea::NoteArea(XsheetViewer *parent, Qt::WFlags flags)
#endif
: QFrame(parent), m_viewer(parent) {
: QFrame(parent)
, m_viewer(parent)
, m_flipOrientationButton(nullptr)
, m_noteButton(nullptr)
, m_precNoteButton(nullptr)
, m_nextNoteButton(nullptr)
, m_frameDisplayStyleCombo(nullptr)
, m_layerHeaderPanel(nullptr) {
setFrameStyle(QFrame::StyledPanel);
setObjectName("cornerWidget");
QToolButton *toolButton = new QToolButton(this);
m_flipOrientationButton =
new QPushButton(m_viewer->orientation()->name(), this);
m_noteButton = new QToolButton(this);
m_precNoteButton = new QToolButton(this);
m_nextNoteButton = new QToolButton(this);
m_frameDisplayStyleCombo = new QComboBox(this);
m_layerHeaderPanel = new LayerHeaderPanel(m_viewer, this);
//-----
toolButton->setObjectName("ToolbarToolButton");
toolButton->setFixedSize(44, 26);
toolButton->setIconSize(QSize(38, 20));
QIcon addNoteIcon = createQIcon("newmemo");
m_flipOrientationButton->setObjectName("flipOrientationButton");
m_flipOrientationButton->setFocusPolicy(Qt::FocusPolicy::NoFocus);
m_noteButton->setObjectName("ToolbarToolButton");
m_noteButton->setFixedSize(44, 26);
m_noteButton->setIconSize(QSize(38, 20));
QIcon addNoteIcon = createQIconPNG("newmemo");
addNoteIcon.addFile(QString(":Resources/newmemo_disabled.svg"), QSize(),
QIcon::Disabled);
toolButton->setIcon(addNoteIcon);
m_noteButton->setIcon(addNoteIcon);
m_precNoteButton->setObjectName("ToolbarToolButton");
m_precNoteButton->setFixedSize(22, 22);
@ -492,35 +508,14 @@ NoteArea::NoteArea(XsheetViewer *parent, Qt::WFlags flags)
(int)m_viewer->getFrameDisplayStyle());
// layout
QVBoxLayout *mainLay = new QVBoxLayout();
mainLay->setMargin(0);
mainLay->setSpacing(5);
{
mainLay->addStretch(1);
mainLay->addWidget(toolButton, 0, Qt::AlignHCenter);
QHBoxLayout *noteLay = new QHBoxLayout();
noteLay->setMargin(0);
noteLay->setSpacing(0);
{
noteLay->addStretch(1);
noteLay->addWidget(m_precNoteButton, 0);
noteLay->addWidget(m_nextNoteButton, 0);
noteLay->addStretch(1);
}
mainLay->addLayout(noteLay, 0);
mainLay->addStretch(1);
mainLay->addWidget(m_frameDisplayStyleCombo, 0);
}
setLayout(mainLay);
createLayout();
// signal-slot connections
bool ret = true;
ret = ret && connect(m_flipOrientationButton, SIGNAL(clicked()),
SLOT(flipOrientation()));
ret = ret && connect(toolButton, SIGNAL(clicked()), SLOT(toggleNewNote()));
ret = ret && connect(m_noteButton, SIGNAL(clicked()), SLOT(toggleNewNote()));
ret = ret &&
connect(m_precNoteButton, SIGNAL(clicked()), this, SLOT(precNote()));
ret = ret &&
@ -530,6 +525,9 @@ NoteArea::NoteArea(XsheetViewer *parent, Qt::WFlags flags)
ret && connect(m_frameDisplayStyleCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(onFrameDisplayStyleChanged(int)));
ret = ret && connect(m_viewer, &XsheetViewer::orientationChanged, this,
&NoteArea::onXsheetOrientationChanged);
updateButtons();
assert(ret);
@ -537,6 +535,69 @@ NoteArea::NoteArea(XsheetViewer *parent, Qt::WFlags flags)
//-----------------------------------------------------------------------------
void NoteArea::removeLayout() {
QLayout *currentLayout = layout();
if (!currentLayout) return;
currentLayout->removeWidget(m_flipOrientationButton);
currentLayout->removeWidget(m_noteButton);
currentLayout->removeWidget(m_precNoteButton);
currentLayout->removeWidget(m_nextNoteButton);
currentLayout->removeWidget(m_frameDisplayStyleCombo);
currentLayout->removeWidget(m_layerHeaderPanel);
delete currentLayout;
}
void NoteArea::createLayout() {
const Orientation *o = m_viewer->orientation();
QRect rect = o->rect(PredefinedRect::NOTE_AREA);
setFixedSize(rect.size());
// has two elements: main layout and header panel
QVBoxLayout *panelLayout = new QVBoxLayout();
panelLayout->setMargin(1);
panelLayout->setSpacing(0);
{
QBoxLayout *mainLayout = new QBoxLayout(QBoxLayout::Direction(
o->dimension(PredefinedDimension::QBOXLAYOUT_DIRECTION)));
Qt::AlignmentFlag centerAlign =
Qt::AlignmentFlag(o->dimension(PredefinedDimension::CENTER_ALIGN));
mainLayout->setMargin(1);
mainLayout->setSpacing(0);
{
mainLayout->addWidget(m_flipOrientationButton, 0, centerAlign);
mainLayout->addStretch(1);
mainLayout->addWidget(m_noteButton, 0, centerAlign);
QHBoxLayout *buttonsLayout = new QHBoxLayout();
buttonsLayout->setMargin(0);
buttonsLayout->setSpacing(0);
{
buttonsLayout->addStretch(1);
buttonsLayout->addWidget(m_precNoteButton, 0);
buttonsLayout->addWidget(m_nextNoteButton, 0);
buttonsLayout->addStretch(1);
}
mainLayout->addLayout(buttonsLayout, 0);
mainLayout->addStretch(1);
mainLayout->addWidget(m_frameDisplayStyleCombo, 0);
}
panelLayout->addLayout(mainLayout);
panelLayout->addWidget(m_layerHeaderPanel);
}
setLayout(panelLayout);
m_layerHeaderPanel->showOrHide(o);
}
//-----------------------------------------------------------------------------
void NoteArea::updateButtons() {
TXshNoteSet *notes = m_viewer->getXsheet()->getNotes();
@ -555,6 +616,16 @@ void NoteArea::updateButtons() {
//-----------------------------------------------------------------------------
void NoteArea::flipOrientation() { m_viewer->flipOrientation(); }
void NoteArea::onXsheetOrientationChanged(const Orientation *newOrientation) {
m_flipOrientationButton->setText(newOrientation->caption());
removeLayout();
createLayout();
}
//-----------------------------------------------------------------------------
void NoteArea::toggleNewNote() {
if (!m_newNotePopup)
m_newNotePopup.reset(new XsheetGUI::NotePopup(m_viewer, -1));

View file

@ -13,6 +13,8 @@
#include <QFrame>
#include <QScrollArea>
#include "layerheaderpanel.h"
//-----------------------------------------------------------------------------
// forward declaration
@ -22,6 +24,7 @@ class TColorStyle;
class QToolButton;
class QPushButton;
class QComboBox;
class Orientation;
//-----------------------------------------------------------------------------
@ -117,11 +120,16 @@ class NoteArea final : public QFrame {
std::unique_ptr<NotePopup> m_newNotePopup; // Popup used to create new note
XsheetViewer *m_viewer;
QPushButton *m_flipOrientationButton;
QToolButton *m_noteButton;
QToolButton *m_nextNoteButton;
QToolButton *m_precNoteButton;
QComboBox *m_frameDisplayStyleCombo;
LayerHeaderPanel *m_layerHeaderPanel;
public:
#if QT_VERSION >= 0x050500
NoteArea(XsheetViewer *parent = 0, Qt::WindowFlags flags = 0);
@ -133,11 +141,17 @@ public:
void updateButtons();
protected slots:
void flipOrientation();
void toggleNewNote();
void nextNote();
void precNote();
void onFrameDisplayStyleChanged(int id);
void onXsheetOrientationChanged(const Orientation *orientation);
protected:
void removeLayout();
void createLayout();
};
} // namespace XsheetGUI;

View file

@ -46,7 +46,6 @@ RowArea::RowArea(XsheetViewer *parent, Qt::WFlags flags)
#endif
: QWidget(parent, flags)
, m_viewer(parent)
, m_xa(ColumnWidth / 2 - 12)
, m_row(-1)
, m_showOnionToSet(None)
, m_pos(-1, -1)
@ -108,20 +107,23 @@ void RowArea::drawRows(QPainter &p, int r0, int r1) {
QRect visibleRect = visibleRegion().boundingRect();
int x0 = visibleRect.left();
int x1 = visibleRect.right();
int y0 = visibleRect.top();
int y1 = visibleRect.bottom();
int x0 = visibleRect.left();
int x1 = visibleRect.right();
int y0 = visibleRect.top();
int y1 = visibleRect.bottom();
NumberRange layerSide = m_viewer->orientation()->layerSide(visibleRect);
for (int r = r0; r <= r1; r++) {
int y = m_viewer->rowToY(r);
int frameAxis = m_viewer->rowToFrameAxis(r);
//--- draw horizontal line
QColor color = ((r - offset) % distance != 0)
? m_viewer->getLightLineColor()
: m_viewer->getMarkerLineColor();
QColor color = ((r - offset) % distance == 0 && r != 0)
? m_viewer->getMarkerLineColor()
: m_viewer->getLightLineColor();
p.setPen(color);
p.drawLine(x0, y, x1, y);
QLine horizontalLine =
m_viewer->orientation()->horizontalLine(frameAxis, layerSide);
p.drawLine(horizontalLine);
// draw frame text
if (playR0 <= r && r <= playR1) {
@ -132,6 +134,13 @@ void RowArea::drawRows(QPainter &p, int r0, int r1) {
else
p.setPen(m_viewer->getTextColor());
QPoint basePoint = m_viewer->positionToXY(CellPosition(r, 0));
QRect labelRect = m_viewer->orientation()
->rect(PredefinedRect::FRAME_LABEL)
.translated(basePoint);
int align = m_viewer->orientation()->dimension(
PredefinedDimension::FRAME_LABEL_ALIGN);
// display time and/or frame number
switch (m_viewer->getFrameDisplayStyle()) {
case XsheetViewer::SecAndFrame: {
int frameRate = TApp::instance()
@ -152,16 +161,14 @@ void RowArea::drawRows(QPainter &p, int r0, int r1) {
str = QString("%1\"").arg(QString::number(koma).rightJustified(2, '0'));
}
p.drawText(QRect(width() / 2 - 15, y + 1, width() / 2 + 7, RowHeight - 2),
Qt::AlignRight | Qt::AlignBottom, str);
p.drawText(labelRect, align, str);
break;
}
case XsheetViewer::Frame: {
QString number = QString::number(r + 1);
p.drawText(QRect(width() / 2 - 2, y + 1, width() / 2, RowHeight - 2),
Qt::AlignHCenter | Qt::AlignBottom, number);
p.drawText(labelRect, align, number);
break;
}
@ -177,15 +184,14 @@ void RowArea::drawRows(QPainter &p, int r0, int r1) {
int koma = (r + 1) % (frameRate * 6);
if ((r + 1) % frameRate == 1) {
int page = (r + 1) / (frameRate * 6) + 1;
str = QString("p%1 %2")
str = QString("p%1 %2")
.arg(QString::number(page))
.arg(QString::number(koma).rightJustified(3, '0'));
} else {
if (koma == 0) koma = frameRate * 6;
str = QString("%1").arg(QString::number(koma).rightJustified(3, '0'));
}
p.drawText(QRect(width() / 2 - 21, y + 1, width() / 2 + 7, RowHeight - 2),
Qt::AlignRight | Qt::AlignBottom, str);
p.drawText(labelRect, align, str);
break;
}
// 3 second sheet (72frames per page)
@ -200,25 +206,18 @@ void RowArea::drawRows(QPainter &p, int r0, int r1) {
int koma = (r + 1) % (frameRate * 3);
if ((r + 1) % frameRate == 1) {
int page = (r + 1) / (frameRate * 3) + 1;
str = QString("p%1 %2")
str = QString("p%1 %2")
.arg(QString::number(page))
.arg(QString::number(koma).rightJustified(2, '0'));
} else {
if (koma == 0) koma = frameRate * 3;
str = QString("%1").arg(QString::number(koma).rightJustified(2, '0'));
}
p.drawText(QRect(width() / 2 - 21, y + 1, width() / 2 + 7, RowHeight - 2),
Qt::AlignRight | Qt::AlignBottom, str);
p.drawText(labelRect, align, str);
break;
}
}
}
// hide the top-most horizontal line
if (r0 == 0) {
p.setPen(m_viewer->getLightLineColor());
p.drawLine(x0, m_viewer->rowToY(0), x1, m_viewer->rowToY(0));
}
}
//-----------------------------------------------------------------------------
@ -243,28 +242,29 @@ void RowArea::drawPlayRange(QPainter &p, int r0, int r1) {
QColor ArrowColor = (playRangeEnabled) ? QColor(255, 255, 255) : grey150;
p.setBrush(QBrush(ArrowColor));
if (m_r0 > r0 - 1 && r1 + 1 > m_r0) {
int y0 = m_viewer->rowToY(m_r0);
drawArrow(p, QPointF(m_xa, y0 + 1), QPointF(m_xa + 10, y0 + 1),
QPointF(m_xa, y0 + 11), true, ArrowColor);
}
if (m_r0 > r0 - 1 && r1 + 1 > m_r0)
m_viewer->drawPredefinedPath(p, PredefinedPath::BEGIN_PLAY_RANGE,
CellPosition(m_r0, 0), ArrowColor,
QColor(Qt::black));
if (m_r1 > r0 - 1 && r1 + 1 > m_r1) {
int y1 = m_viewer->rowToY(m_r1 + 1) - 12;
drawArrow(p, QPointF(m_xa, y1 + 1), QPointF(m_xa + 10, y1 + 11),
QPointF(m_xa, y1 + 11), true, ArrowColor);
}
if (m_r1 > r0 - 1 && r1 + 1 > m_r1)
m_viewer->drawPredefinedPath(p, PredefinedPath::END_PLAY_RANGE,
CellPosition(m_r1, 0), ArrowColor,
QColor(Qt::black));
}
//-----------------------------------------------------------------------------
void RowArea::drawCurrentRowGadget(QPainter &p, int r0, int r1) {
int currentRow = m_viewer->getCurrentRow();
int y = m_viewer->rowToY(currentRow);
if (currentRow < r0 || r1 < currentRow) return;
p.fillRect(1, y + 1, width() - 4, RowHeight - 1,
m_viewer->getCurrentRowBgColor());
QPoint topLeft = m_viewer->positionToXY(CellPosition(currentRow, 0));
QRect header = m_viewer->orientation()
->rect(PredefinedRect::FRAME_HEADER)
.translated(topLeft)
.adjusted(1, 1, 0, 0);
p.fillRect(header, m_viewer->getCurrentRowBgColor());
}
//-----------------------------------------------------------------------------
@ -282,12 +282,9 @@ void RowArea::drawOnionSkinSelection(QPainter &p) {
bool inksOnly;
Preferences::instance()->getOnionData(frontPixel, backPixel, inksOnly);
QColor frontColor((int)frontPixel.r, (int)frontPixel.g, (int)frontPixel.b,
128);
QColor backColor((int)backPixel.r, (int)backPixel.g, (int)backPixel.b, 128);
int onionDotDiam = 8;
int onionHandleDiam = RowHeight - 1;
int onionDotYPos = (RowHeight - onionDotDiam) / 2;
128);
QColor backColor((int)backPixel.r, (int)backPixel.g, (int)backPixel.b,
128);
// If the onion skin is disabled, draw dash line instead.
if (osMask.isEnabled())
@ -299,14 +296,11 @@ void RowArea::drawOnionSkinSelection(QPainter &p) {
p.setPen(currentPen);
}
// Draw onion skin extender handles.
QRectF handleRect(3, m_viewer->rowToY(currentRow) + 1, onionHandleDiam,
onionHandleDiam);
int angle180 = 16 * 180;
p.setBrush(QBrush(backColor));
p.drawChord(handleRect, 0, angle180);
p.setBrush(QBrush(frontColor));
p.drawChord(handleRect, angle180, angle180);
QRect onionRect = m_viewer->orientation()->rect(PredefinedRect::ONION);
int onionCenter_frame =
m_viewer->orientation()->frameSide(onionRect).middle();
int onionCenter_layer =
m_viewer->orientation()->layerSide(onionRect).middle();
//-- draw movable onions
@ -322,18 +316,43 @@ void RowArea::drawOnionSkinSelection(QPainter &p) {
p.setBrush(Qt::NoBrush);
if (minMos < 0) // previous frames
{
int y0 =
m_viewer->rowToY(currentRow + minMos) + onionDotYPos + onionDotDiam;
int y1 = m_viewer->rowToY(currentRow);
p.drawLine(onionDotDiam * 1.5, y0, onionDotDiam * 1.5, y1);
int layerAxis = onionCenter_layer;
int fromFrameAxis =
m_viewer->rowToFrameAxis(currentRow + minMos) + onionCenter_frame;
int toFrameAxis = m_viewer->rowToFrameAxis(currentRow) + onionCenter_frame;
QLine verticalLine = m_viewer->orientation()->verticalLine(
layerAxis, NumberRange(fromFrameAxis, toFrameAxis));
if (m_viewer->orientation()->isVerticalTimeline())
p.drawLine(verticalLine.x1() + 1, verticalLine.y1() + 4, verticalLine.x2() + 1, verticalLine.y2() - 10);
else
p.drawLine(verticalLine.x1() + 4, verticalLine.y1() + 1, verticalLine.x2() - 10, verticalLine.y2() + 1);
}
if (maxMos > 0) // foward frames
if (maxMos > 0) // forward frames
{
int y0 = m_viewer->rowToY(currentRow + 1);
int y1 = m_viewer->rowToY(currentRow + maxMos) + onionDotYPos;
p.drawLine(onionDotDiam * 1.5, y0, onionDotDiam * 1.5, y1);
int layerAxis = onionCenter_layer;
int fromFrameAxis =
m_viewer->rowToFrameAxis(currentRow) + onionCenter_frame;
int toFrameAxis =
m_viewer->rowToFrameAxis(currentRow + maxMos) + onionCenter_frame;
QLine verticalLine = m_viewer->orientation()->verticalLine(
layerAxis, NumberRange(fromFrameAxis, toFrameAxis));
if (m_viewer->orientation()->isVerticalTimeline())
p.drawLine(verticalLine.x1() + 1, verticalLine.y1() + 10, verticalLine.x2() + 1, verticalLine.y2() - 4);
else
p.drawLine(verticalLine.x1() + 10, verticalLine.y1() + 1, verticalLine.x2() - 4, verticalLine.y2() + 1);
}
// Draw onion skin main handle
QPoint handleTopLeft = m_viewer->positionToXY(CellPosition(currentRow, 0));
QRect handleRect = onionRect.translated(handleTopLeft);
int angle180 = 16 * 180;
int turn =
m_viewer->orientation()->dimension(PredefinedDimension::ONION_TURN) * 16;
p.setBrush(QBrush(backColor));
p.drawChord(handleRect, turn, angle180);
p.setBrush(QBrush(frontColor));
p.drawChord(handleRect, turn + angle180, angle180);
// draw onion skin dots
p.setPen(Qt::red);
for (int i = 0; i < mosCount; i++) {
@ -341,13 +360,16 @@ void RowArea::drawOnionSkinSelection(QPainter &p) {
int mos = osMask.getMos(i);
// skip drawing if the frame is under the mouse cursor
if (m_showOnionToSet == Mos && currentRow + mos == m_row) continue;
int y = m_viewer->rowToY(currentRow + mos) + onionDotYPos;
if (osMask.isEnabled())
p.setBrush(mos < 0 ? backColor : frontColor);
else
p.setBrush(Qt::NoBrush);
p.drawEllipse(onionDotDiam, y, onionDotDiam, onionDotDiam);
QPoint topLeft = m_viewer->positionToXY(CellPosition(currentRow + mos, 0));
QRect dotRect = m_viewer->orientation()
->rect(PredefinedRect::ONION_DOT)
.translated(topLeft);
p.drawEllipse(dotRect);
}
//-- draw fixed onions
@ -356,22 +378,29 @@ void RowArea::drawOnionSkinSelection(QPainter &p) {
if (fos == currentRow) continue;
// skip drawing if the frame is under the mouse cursor
if (m_showOnionToSet == Fos && fos == m_row) continue;
int y = m_viewer->rowToY(fos) + onionDotYPos;
if (osMask.isEnabled())
p.setBrush(QBrush(QColor(0, 255, 255, 128)));
else
p.setBrush(Qt::NoBrush);
p.drawEllipse(0, y, onionDotDiam, onionDotDiam);
QPoint topLeft = m_viewer->positionToXY(CellPosition(fos, 0));
QRect dotRect = m_viewer->orientation()
->rect(PredefinedRect::ONION_DOT_FIXED)
.translated(topLeft);
p.drawEllipse(dotRect);
}
//-- draw highlighted onion
//-- onion placement hint under mouse
if (m_showOnionToSet != None) {
int y = m_viewer->rowToY(m_row) + onionDotYPos;
int xPos = (m_showOnionToSet == Fos) ? 0 : onionDotDiam;
p.setPen(QColor(255, 128, 0));
p.setBrush(QBrush(QColor(255, 255, 0, 200)));
p.drawEllipse(xPos, y, onionDotDiam, onionDotDiam);
p.setBrush(QBrush(QColor(255, 255, 0)));
QPoint topLeft = m_viewer->positionToXY(CellPosition(m_row, 0));
QRect dotRect =
m_viewer->orientation()
->rect(m_showOnionToSet == Fos ? PredefinedRect::ONION_DOT_FIXED
: PredefinedRect::ONION_DOT)
.translated(topLeft);
p.drawEllipse(dotRect);
}
}
@ -416,7 +445,8 @@ void RowArea::drawPinnedCenterKeys(QPainter &p, int r0, int r1) {
int columnCount = xsh->getColumnCount();
int prev_pinnedCol = -2;
QRect keyRect(30, 5, 10, 10);
QRect keyRect =
m_viewer->orientation()->rect(PredefinedRect::PINNED_CENTER_KEY);
p.setPen(Qt::black);
r1 = (r1 < xsh->getFrameCount() - 1) ? xsh->getFrameCount() - 1 : r1;
@ -430,21 +460,22 @@ void RowArea::drawPinnedCenterKeys(QPainter &p, int r0, int r1) {
if (tmp_pinnedCol != prev_pinnedCol) {
prev_pinnedCol = tmp_pinnedCol;
if (r != r0 - 1) {
if (m_pos.x() >= 30 && m_pos.x() <= 40 && m_row == r)
QPoint mouseInCell = m_pos - m_viewer->positionToXY(CellPosition(r, 0));
if (keyRect.contains(mouseInCell))
p.setBrush(QColor(30, 210, 255));
else
p.setBrush(QColor(0, 175, 255));
int y = m_viewer->rowToY(r);
QRect tmpKeyRect = keyRect.translated(0, y);
p.drawRect(tmpKeyRect);
QPoint topLeft = m_viewer->positionToXY(CellPosition(r, 0));
QRect adjusted = keyRect.translated(topLeft);
p.drawRect(adjusted);
QFont font = p.font();
font.setPixelSize(8);
font.setBold(false);
p.setFont(font);
p.drawText(
tmpKeyRect, Qt::AlignCenter,
adjusted, Qt::AlignCenter,
QString::number((tmp_pinnedCol == -1) ? ancestorId.getIndex() + 1
: tmp_pinnedCol + 1));
}
@ -459,9 +490,10 @@ void RowArea::paintEvent(QPaintEvent *event) {
QPainter p(this);
int r0, r1; // range di righe visibili
r0 = m_viewer->yToRow(toBeUpdated.top());
r1 = m_viewer->yToRow(toBeUpdated.bottom());
CellRange cellRange = m_viewer->xyRectToRange(toBeUpdated);
int r0, r1; // range of visible rows
r0 = cellRange.from().frame();
r1 = cellRange.to().frame();
p.setClipRect(toBeUpdated);
@ -487,6 +519,8 @@ void RowArea::paintEvent(QPaintEvent *event) {
//-----------------------------------------------------------------------------
void RowArea::mousePressEvent(QMouseEvent *event) {
const Orientation *o = m_viewer->orientation();
m_viewer->setQtModifiers(event->modifiers());
if (event->button() == Qt::LeftButton) {
bool frameAreaIsClicked = false;
@ -496,22 +530,28 @@ void RowArea::mousePressEvent(QMouseEvent *event) {
TPoint pos(event->pos().x(), event->pos().y());
int currentFrame = TApp::instance()->getCurrentFrame()->getFrame();
int row = m_viewer->yToRow(pos.y);
int row = m_viewer->xyToPosition(pos).frame();
QPoint topLeft = m_viewer->positionToXY(CellPosition(row, 0));
QPoint mouseInCell = event->pos() - topLeft;
int onionDotDiam = 8;
if (Preferences::instance()->isOnionSkinEnabled() &&
((row == currentFrame && pos.x < RowHeight + 2) ||
(pos.x < onionDotDiam * 2))) {
o->rect(PredefinedRect::ONION_AREA).contains(mouseInCell)) {
if (row == currentFrame) {
setDragTool(
XsheetGUI::DragTool::makeCurrentFrameModifierTool(m_viewer));
frameAreaIsClicked = true;
} else if (pos.x <= onionDotDiam)
} else if (o->rect(PredefinedRect::ONION_FIXED_DOT_AREA)
.contains(mouseInCell))
setDragTool(XsheetGUI::DragTool::makeKeyOnionSkinMaskModifierTool(
m_viewer, true));
else
else if (o->rect(PredefinedRect::ONION_DOT_AREA).contains(mouseInCell))
setDragTool(XsheetGUI::DragTool::makeKeyOnionSkinMaskModifierTool(
m_viewer, false));
else {
setDragTool(
XsheetGUI::DragTool::makeCurrentFrameModifierTool(m_viewer));
frameAreaIsClicked = true;
}
} else {
int playR0, playR1, step;
XsheetGUI::getPlayRange(playR0, playR1, step);
@ -527,7 +567,7 @@ void RowArea::mousePressEvent(QMouseEvent *event) {
setDragTool(
XsheetGUI::DragTool::makeCurrentFrameModifierTool(m_viewer));
frameAreaIsClicked = true;
} else if (m_xa <= pos.x && pos.x <= m_xa + 10 &&
} else if (o->rect(PredefinedRect::PLAY_RANGE).contains(mouseInCell) &&
(row == playR0 || row == playR1)) {
if (!playRangeEnabled) XsheetGUI::setPlayRange(playR0, playR1, step);
setDragTool(XsheetGUI::DragTool::makePlayRangeModifierTool(m_viewer));
@ -566,24 +606,31 @@ void RowArea::mousePressEvent(QMouseEvent *event) {
//-----------------------------------------------------------------------------
void RowArea::mouseMoveEvent(QMouseEvent *event) {
const Orientation *o = m_viewer->orientation();
m_viewer->setQtModifiers(event->modifiers());
QPoint pos = event->pos();
// pan by middle-drag
if (m_isPanning) {
QPoint delta = m_pos - pos;
delta.setX(0);
m_viewer->scroll(delta);
if (o->isVerticalTimeline())
delta.setX(0);
else
delta.setY(0);
m_viewer->scroll(delta);
return;
}
m_row = m_viewer->yToRow(pos.y());
m_row = m_viewer->xyToPosition(pos).frame();
int x = pos.x();
if ((event->buttons() & Qt::LeftButton) != 0 &&
!visibleRegion().contains(pos)) {
QRect bounds = visibleRegion().boundingRect();
m_viewer->setAutoPanSpeed(bounds, QPoint(bounds.left(), pos.y()));
if(o->isVerticalTimeline())
m_viewer->setAutoPanSpeed(bounds, QPoint(bounds.left(), pos.y()));
else
m_viewer->setAutoPanSpeed(bounds, QPoint(pos.x(), bounds.top()));
} else
m_viewer->stopAutoPan();
@ -596,14 +643,15 @@ void RowArea::mouseMoveEvent(QMouseEvent *event) {
if (getDragTool()) return;
int currentRow = TApp::instance()->getCurrentFrame()->getFrame();
int row = m_viewer->yToRow(m_pos.y());
int row = m_viewer->xyToPosition(m_pos).frame();
QPoint mouseInCell =
event->pos() - m_viewer->positionToXY(CellPosition(row, 0));
if (row < 0) return;
// "decide" se mostrare la possibilita' di settare l'onion skin
if (Preferences::instance()->isOnionSkinEnabled()) {
int onionDotDiam = 8;
if (x <= onionDotDiam && row != currentRow)
// whether to show ability to set onion marks
if (Preferences::instance()->isOnionSkinEnabled() && row != currentRow) {
if (o->rect(PredefinedRect::ONION_FIXED_DOT_AREA).contains(mouseInCell))
m_showOnionToSet = Fos;
else if (x <= onionDotDiam * 2 && row != currentRow)
else if (o->rect(PredefinedRect::ONION_DOT_AREA).contains(mouseInCell))
m_showOnionToSet = Mos;
}
@ -612,7 +660,7 @@ void RowArea::mouseMoveEvent(QMouseEvent *event) {
bool isRootBonePinned;
int pinnedCenterColumnId = -1;
if (TApp::instance()->getCurrentTool()->getTool()->getName() == T_Skeleton &&
x >= 30 && x <= 40) {
o->rect(PredefinedRect::PINNED_CENTER_KEY).contains(mouseInCell)) {
int col = m_viewer->getCurrentColumn();
TXsheet *xsh = m_viewer->getXsheet();
if (col >= 0 && xsh && !xsh->isColumnEmpty(col)) {
@ -635,27 +683,27 @@ void RowArea::mouseMoveEvent(QMouseEvent *event) {
update();
int y0 = m_viewer->rowToY(m_r0);
int y1 = m_viewer->rowToY(m_r1 + 1) - 12;
QPolygon startArrow, endArrow;
startArrow << QPoint(m_xa, y0 + 1) << QPoint(m_xa + 10, y0 + 1)
<< QPoint(m_xa, y0 + 11);
endArrow << QPoint(m_xa, y1 + 1) << QPoint(m_xa + 10, y1 + 11)
<< QPoint(m_xa, y1 + 11);
QPoint base0 = m_viewer->positionToXY(CellPosition(m_r0, 0));
QPoint base1 = m_viewer->positionToXY(CellPosition(m_r1, 0));
QPainterPath startArrow =
o->path(PredefinedPath::BEGIN_PLAY_RANGE).translated(base0);
QPainterPath endArrow =
o->path(PredefinedPath::END_PLAY_RANGE).translated(base1);
if (startArrow.containsPoint(m_pos, Qt::OddEvenFill))
if (startArrow.contains(m_pos))
m_tooltip = tr("Playback Start Marker");
else if (endArrow.containsPoint(m_pos, Qt::OddEvenFill))
else if (endArrow.contains(m_pos))
m_tooltip = tr("Playback End Marker");
else if (isOnPinnedCenterKey)
m_tooltip = tr("Pinned Center : Col%1%2")
.arg(pinnedCenterColumnId + 1)
.arg((isRootBonePinned) ? " (Root)" : "");
else if (row == currentRow) {
if (Preferences::instance()->isOnionSkinEnabled() && x < RowHeight + 2)
if (Preferences::instance()->isOnionSkinEnabled() &&
o->rect(PredefinedRect::ONION).contains(mouseInCell))
m_tooltip = tr("Double Click to Toggle Onion Skin");
else
m_tooltip = tr("Curren Frame");
m_tooltip = tr("Current Frame");
} else if (m_showOnionToSet == Fos)
m_tooltip = tr("Fixed Onion Skin Toggle");
else if (m_showOnionToSet == Mos)
@ -674,7 +722,7 @@ void RowArea::mouseReleaseEvent(QMouseEvent *event) {
TPoint pos(event->pos().x(), event->pos().y());
int row = m_viewer->yToRow(pos.y);
int row = m_viewer->xyToPosition(pos).frame();
if (m_playRangeActiveInMousePress && row == m_mousePressRow &&
(13 <= pos.x && pos.x <= 26 && (row == m_r0 || row == m_r1)))
onRemoveMarkers();
@ -756,11 +804,15 @@ int RowArea::getNonEmptyCell(int row, int column, Direction direction) {
void RowArea::mouseDoubleClickEvent(QMouseEvent *event) {
int currentFrame = TApp::instance()->getCurrentFrame()->getFrame();
int row = m_viewer->yToRow(event->pos().y());
int row = m_viewer->xyToPosition(event->pos()).frame();
QPoint mouseInCell =
event->pos() - m_viewer->positionToXY(CellPosition(row, 0));
if (TApp::instance()->getCurrentFrame()->isEditingScene() &&
event->buttons() & Qt::LeftButton &&
Preferences::instance()->isOnionSkinEnabled() && row == currentFrame &&
event->pos().x() < RowHeight + 2) {
m_viewer->orientation()
->rect(PredefinedRect::ONION)
.contains(mouseInCell)) {
TOnionSkinMaskHandle *osmh = TApp::instance()->getCurrentOnionSkin();
OnionSkinMask osm = osmh->getOnionSkinMask();
osm.enable(!osm.isEnabled());

View file

@ -21,7 +21,6 @@ class DragTool;
class RowArea final : public QWidget {
Q_OBJECT
XsheetViewer *m_viewer;
int m_xa;
int m_row;
enum ShowOnionToSetFlag {

View file

@ -152,6 +152,7 @@ set(MOC_HEADERS
sandor_fxs/YOMBParam.h
texturemanager.h
imagebuilders.h
../include/orientation.h
)
set(HEADERS ${MOC_HEADERS})
@ -161,6 +162,7 @@ set(SOURCES
autoclose.cpp
autopos.cpp
captureparameters.cpp
cellpositionratio.cpp
childstack.cpp
cleanupcolorstyles.cpp
cleanuppalette.cpp
@ -193,6 +195,7 @@ set(SOURCES
Naa2TlvConverter.cpp
observer.cpp
onionskinmask.cpp
orientation.cpp
outputproperties.cpp
preferences.cpp
rasterbrush.cpp

View file

@ -0,0 +1,66 @@
#include "toonz/cellpositionratio.h"
#include <stdexcept>
#include <algorithm>
// Euclid's algorithm
int greatestCommonDivisor(int a, int b) {
a = std::abs(a);
b = std::abs(b);
int c = std::max(a, b);
int d = std::min(a, b);
while (d) {
int q = c / d;
int r = c % d;
c = d;
d = r;
}
return c;
}
int leastCommonMultiple(int a, int b) {
return a * b / greatestCommonDivisor(a, b);
}
void Ratio::normalize() {
int gcd = greatestCommonDivisor(m_num, m_denom);
if (m_denom < 0) gcd = -gcd;
m_num /= gcd;
m_denom /= gcd;
}
Ratio Ratio::normalized() const {
Ratio copy(*this);
copy.normalize();
return copy;
}
Ratio::Ratio(int num, int denom) : m_num(num), m_denom(denom) {
if (!denom) throw std::runtime_error("ratio with denominator == 0");
normalize();
}
Ratio operator*(const Ratio &a, const Ratio &b) {
return Ratio(a.m_num * b.m_num, a.m_denom * b.m_denom);
}
Ratio operator/(const Ratio &a, const Ratio &b) {
return Ratio(a.m_num * b.m_denom, a.m_denom * b.m_num);
}
Ratio operator+(const Ratio &a, const Ratio &b) {
int gcd = greatestCommonDivisor(a.m_denom, b.m_denom);
int denom = a.m_denom * b.m_denom / gcd;
int aMult = b.m_denom * gcd;
int bMult = a.m_denom * gcd;
return Ratio(a.m_num * aMult + b.m_num * bMult, denom);
}
Ratio operator-(const Ratio &a, const Ratio &b) {
int gcd = greatestCommonDivisor(a.m_denom, b.m_denom);
int denom = a.m_denom * b.m_denom / gcd;
int aMult = b.m_denom * gcd;
int bMult = a.m_denom * gcd;
return Ratio(a.m_num * aMult - b.m_num * bMult, denom);
}
int operator*(const Ratio &a, int b) { return a.m_num * b / a.m_denom; }

View file

@ -8,37 +8,40 @@
// STD includss
#include <assert.h>
//=============================================================================
const int colWidth = 74;
const int colSkip = 9;
//=============================================================================
// ColumnFan
ColumnFan::ColumnFan() : m_firstFreePos(0) {}
ColumnFan::ColumnFan() : m_firstFreePos(0), m_unfolded(74), m_folded(9) {}
//-----------------------------------------------------------------------------
void ColumnFan::setDimension(int unfolded) {
m_unfolded = unfolded;
// folded always 9
update();
}
//-----------------------------------------------------------------------------
void ColumnFan::update() {
int lastPos = -colWidth;
int lastPos = -m_unfolded;
bool lastActive = true;
int m = m_columns.size();
int i;
for (i = 0; i < m; i++) {
bool active = m_columns[i].m_active;
if (lastActive)
lastPos += colWidth;
lastPos += m_unfolded;
else if (active)
lastPos += colSkip;
lastPos += m_folded;
m_columns[i].m_pos = lastPos;
lastActive = active;
}
m_firstFreePos = lastPos + (lastActive ? colWidth : colSkip);
m_firstFreePos = lastPos + (lastActive ? m_unfolded : m_folded);
m_table.clear();
for (i = 0; i < m; i++)
if (m_columns[i].m_active)
m_table[m_columns[i].m_pos + colWidth - 1] = i;
m_table[m_columns[i].m_pos + m_unfolded - 1] = i;
else if (i + 1 < m && m_columns[i + 1].m_active)
m_table[m_columns[i + 1].m_pos - 1] = i;
else if (i + 1 == m)
@ -47,24 +50,24 @@ void ColumnFan::update() {
//-----------------------------------------------------------------------------
int ColumnFan::xToCol(int x) const {
if (x < m_firstFreePos) {
std::map<int, int>::const_iterator it = m_table.lower_bound(x);
int ColumnFan::layerAxisToCol(int coord) const {
if (coord < m_firstFreePos) {
std::map<int, int>::const_iterator it = m_table.lower_bound(coord);
if (it == m_table.end()) return -3;
assert(it != m_table.end());
return it->second;
} else
return m_columns.size() + (x - m_firstFreePos) / colWidth;
return m_columns.size() + (coord - m_firstFreePos) / m_unfolded;
}
//-----------------------------------------------------------------------------
int ColumnFan::colToX(int col) const {
int ColumnFan::colToLayerAxis(int col) const {
int m = m_columns.size();
if (col >= 0 && col < m)
return m_columns[col].m_pos;
else
return m_firstFreePos + (col - m) * colWidth;
return m_firstFreePos + (col - m) * m_unfolded;
}
//-----------------------------------------------------------------------------
@ -106,7 +109,15 @@ bool ColumnFan::isEmpty() const { return m_columns.empty(); }
//-----------------------------------------------------------------------------
void ColumnFan::saveData(TOStream &os) {
void ColumnFan::copyFoldedStateFrom(const ColumnFan &from) {
for (int i = 0, n = (int)from.m_columns.size(); i < n; i++)
if (!from.isActive(i)) deactivate(i);
}
//-----------------------------------------------------------------------------
void ColumnFan::saveData(
TOStream &os) { // only saves indices of folded columns
int index, n = (int)m_columns.size();
for (index = 0; index < n;) {
while (index < n && m_columns[index].m_active) index++;

View file

@ -0,0 +1,706 @@
#include "orientation.h"
#include "toonz/columnfan.h"
#include <QPainterPath>
#include <QBoxLayout>
#include <math.h>
using std::pair;
namespace {
const int KEY_ICON_WIDTH = 11;
const int KEY_ICON_HEIGHT = 13;
const int EASE_TRIANGLE_SIZE = 4;
const int PLAY_MARKER_SIZE = 10;
const int ONION_SIZE = 19;
const int ONION_DOT_SIZE = 8;
const int PINNED_SIZE = 10;
}
class TopToBottomOrientation : public Orientation {
const int CELL_WIDTH = 74;
const int CELL_HEIGHT = 20;
const int CELL_DRAG_WIDTH = 7;
const int EXTENDER_WIDTH = 18;
const int EXTENDER_HEIGHT = 8;
const int SOUND_PREVIEW_WIDTH = 7;
const int LAYER_HEADER_HEIGHT = CELL_HEIGHT * 3 + 60;
const int FOLDED_LAYER_HEADER_HEIGHT = LAYER_HEADER_HEIGHT;
const int FOLDED_LAYER_HEADER_WIDTH = 8;
const int FRAME_HEADER_WIDTH = CELL_WIDTH;
const int PLAY_RANGE_X = FRAME_HEADER_WIDTH / 2 - PLAY_MARKER_SIZE;
const int ONION_X = 0, ONION_Y = 0;
const int ICON_WIDTH = CELL_HEIGHT;
public:
TopToBottomOrientation();
virtual CellPosition xyToPosition(const QPoint &xy,
const ColumnFan *fan) const override;
virtual QPoint positionToXY(const CellPosition &position,
const ColumnFan *fan) const override;
virtual CellPositionRatio xyToPositionRatio(const QPoint &xy) const override;
virtual QPoint positionRatioToXY(
const CellPositionRatio &ratio) const override;
virtual int colToLayerAxis(int layer, const ColumnFan *fan) const override;
virtual int rowToFrameAxis(int frame) const override;
virtual QPoint frameLayerToXY(int frameAxis, int layerAxis) const override;
virtual int layerAxis(const QPoint &xy) const override;
virtual int frameAxis(const QPoint &xy) const override;
virtual NumberRange layerSide(const QRect &area) const override;
virtual NumberRange frameSide(const QRect &area) const override;
virtual QPoint topRightCorner(const QRect &area) const override;
virtual CellPosition arrowShift(int direction) const override;
virtual QString name() const override { return "TopToBottom"; }
virtual QString caption() const override { return "Xsheet"; }
virtual const Orientation *next() const override {
return Orientations::leftToRight();
}
virtual bool isVerticalTimeline() const override { return true; }
virtual bool flipVolume() const override { return true; }
virtual int cellWidth() const override { return CELL_WIDTH; }
virtual int cellHeight() const override { return CELL_HEIGHT; }
};
class LeftToRightOrientation : public Orientation {
const int CELL_WIDTH = 50;
const int CELL_HEIGHT = 20;
const int CELL_DRAG_HEIGHT = 5;
const int EXTENDER_WIDTH = 8;
const int EXTENDER_HEIGHT = 12;
const int SOUND_PREVIEW_HEIGHT = 6;
const int FRAME_HEADER_HEIGHT = 50;
const int ONION_X = (CELL_WIDTH - ONION_SIZE) / 2, ONION_Y = 0;
const int PLAY_RANGE_Y = ONION_SIZE;
const int ICON_WIDTH = CELL_HEIGHT;
const int ICON_OFFSET = ICON_WIDTH;
const int ICONS_WIDTH = ICON_OFFSET * 3; // 88
const int LAYER_NUMBER_WIDTH = 20;
const int LAYER_NAME_WIDTH = 170;
const int LAYER_HEADER_WIDTH =
ICONS_WIDTH + LAYER_NUMBER_WIDTH + LAYER_NAME_WIDTH;
const int FOLDED_LAYER_HEADER_HEIGHT = 8;
const int FOLDED_LAYER_HEADER_WIDTH = LAYER_HEADER_WIDTH;
public:
LeftToRightOrientation();
virtual CellPosition xyToPosition(const QPoint &xy,
const ColumnFan *fan) const override;
virtual QPoint positionToXY(const CellPosition &position,
const ColumnFan *fan) const override;
virtual CellPositionRatio xyToPositionRatio(const QPoint &xy) const override;
virtual QPoint positionRatioToXY(
const CellPositionRatio &ratio) const override;
virtual int colToLayerAxis(int layer, const ColumnFan *fan) const override;
virtual int rowToFrameAxis(int frame) const override;
virtual QPoint frameLayerToXY(int frameAxis, int layerAxis) const override;
virtual int layerAxis(const QPoint &xy) const override;
virtual int frameAxis(const QPoint &xy) const override;
virtual NumberRange layerSide(const QRect &area) const override;
virtual NumberRange frameSide(const QRect &area) const override;
virtual QPoint topRightCorner(const QRect &area) const override;
virtual CellPosition arrowShift(int direction) const override;
virtual QString name() const override { return "LeftToRight"; }
virtual QString caption() const override { return "Timeline"; }
virtual const Orientation *next() const override {
return Orientations::topToBottom();
}
virtual bool isVerticalTimeline() const override { return false; }
virtual bool flipVolume() const override { return false; }
virtual int cellWidth() const override { return CELL_WIDTH; }
virtual int cellHeight() const override { return CELL_HEIGHT; }
};
/// -------------------------------------------------------------------------------
int NumberRange::weight(double toWeight) const { // weight ranging 0..1
return _from + (_to - _from) * toWeight;
}
NumberRange NumberRange::adjusted(int addFrom, int addTo) const {
return NumberRange(_from + addFrom, _to + addTo);
}
double NumberRange::ratio(int at) const {
double result = ((double)at - _from) / (_to - _from);
if (result < 0) result = 0;
if (result > 1) result = 1;
return result;
}
/// -------------------------------------------------------------------------------
// const int Orientations::COUNT = 2;
Orientations::Orientations() : _topToBottom(nullptr), _leftToRight(nullptr) {
_topToBottom = new TopToBottomOrientation();
_leftToRight = new LeftToRightOrientation();
_all.push_back(_topToBottom);
_all.push_back(_leftToRight);
}
Orientations::~Orientations() {
delete _topToBottom;
_topToBottom = nullptr;
delete _leftToRight;
_leftToRight = nullptr;
}
const Orientations &Orientations::instance() {
static Orientations singleton;
return singleton;
}
const Orientation *Orientations::topToBottom() {
return instance()._topToBottom;
}
const Orientation *Orientations::leftToRight() {
return instance()._leftToRight;
}
const vector<const Orientation *> &Orientations::all() {
return instance()._all;
}
const Orientation *Orientations::byName(const QString &name) {
vector<const Orientation *> m_all = all();
for (auto it = m_all.begin(); it != m_all.end(); it++)
if ((*it)->name() == name) return *it;
throw std::runtime_error(
(QString("no such orientation: ") + name).toStdString().c_str());
}
/// -------------------------------------------------------------------------------
QLine Orientation::verticalLine(int layerAxis,
const NumberRange &frameAxis) const {
QPoint first = frameLayerToXY(frameAxis.from(), layerAxis);
QPoint second = frameLayerToXY(frameAxis.to(), layerAxis);
return QLine(first, second);
}
QLine Orientation::horizontalLine(int frameAxis,
const NumberRange &layerAxis) const {
QPoint first = frameLayerToXY(frameAxis, layerAxis.from());
QPoint second = frameLayerToXY(frameAxis, layerAxis.to());
return QLine(first, second);
}
QRect Orientation::frameLayerRect(const NumberRange &frameAxis,
const NumberRange &layerAxis) const {
QPoint topLeft = frameLayerToXY(frameAxis.from(), layerAxis.from());
QPoint bottomRight = frameLayerToXY(frameAxis.to(), layerAxis.to());
return QRect(topLeft, bottomRight);
}
QRect Orientation::foldedRectangle(int layerAxis, const NumberRange &frameAxis,
int i) const {
QPoint topLeft = frameLayerToXY(frameAxis.from(), layerAxis + 1 + i * 3);
QPoint size = frameLayerToXY(frameAxis.length(), 2);
return QRect(topLeft, QSize(size.x(), size.y()));
}
QLine Orientation::foldedRectangleLine(int layerAxis,
const NumberRange &frameAxis,
int i) const {
return verticalLine(layerAxis + i * 3, frameAxis);
}
void Orientation::addRect(PredefinedRect which, const QRect &rect) {
_rects.insert(pair<PredefinedRect, QRect>(which, rect));
}
void Orientation::addLine(PredefinedLine which, const QLine &line) {
_lines.insert(pair<PredefinedLine, QLine>(which, line));
}
void Orientation::addDimension(PredefinedDimension which, int dimension) {
_dimensions.insert(pair<PredefinedDimension, int>(which, dimension));
}
void Orientation::addPath(PredefinedPath which, const QPainterPath &path) {
_paths.insert(pair<PredefinedPath, QPainterPath>(which, path));
}
void Orientation::addPoint(PredefinedPoint which, const QPoint &point) {
_points.insert(pair<PredefinedPoint, QPoint>(which, point));
}
void Orientation::addRange(PredefinedRange which, const NumberRange &range) {
_ranges.insert(pair<PredefinedRange, NumberRange>(which, range));
}
/// -------------------------------------------------------------------------------
TopToBottomOrientation::TopToBottomOrientation() {
//
// Area rectangles
//
// Cell viewer
QRect cellRect(0, 0, CELL_WIDTH, CELL_HEIGHT);
addRect(PredefinedRect::CELL, cellRect);
addRect(PredefinedRect::DRAG_HANDLE_CORNER, QRect(0, 0, CELL_DRAG_WIDTH, CELL_HEIGHT));
QRect keyRect(CELL_WIDTH - KEY_ICON_WIDTH, (CELL_HEIGHT - KEY_ICON_HEIGHT) / 2, KEY_ICON_WIDTH, KEY_ICON_HEIGHT);
addRect(PredefinedRect::KEY_ICON, keyRect);
QRect nameRect = cellRect.adjusted(8, 0, -6, 0);
addRect(PredefinedRect::CELL_NAME, nameRect);
addRect(PredefinedRect::CELL_NAME_WITH_KEYFRAME, nameRect.adjusted(0, 0, -KEY_ICON_WIDTH, 0));
addRect(PredefinedRect::END_EXTENDER, QRect(-EXTENDER_WIDTH - KEY_ICON_WIDTH, 0, EXTENDER_WIDTH, EXTENDER_HEIGHT));
addRect(PredefinedRect::BEGIN_EXTENDER, QRect(-EXTENDER_WIDTH - KEY_ICON_WIDTH, -EXTENDER_HEIGHT, EXTENDER_WIDTH, EXTENDER_HEIGHT));
addRect(PredefinedRect::KEYFRAME_AREA, QRect(CELL_WIDTH - KEY_ICON_WIDTH, 0, KEY_ICON_WIDTH, CELL_HEIGHT));
addRect(PredefinedRect::DRAG_AREA, QRect(0, 0, CELL_DRAG_WIDTH, CELL_HEIGHT));
QRect soundRect(CELL_DRAG_WIDTH, 0, CELL_WIDTH - CELL_DRAG_WIDTH - SOUND_PREVIEW_WIDTH, CELL_HEIGHT);
addRect(PredefinedRect::SOUND_TRACK, soundRect);
addRect(PredefinedRect::PREVIEW_TRACK, QRect(CELL_WIDTH - SOUND_PREVIEW_WIDTH + 1, 0, SOUND_PREVIEW_WIDTH, CELL_HEIGHT));
addRect(PredefinedRect::BEGIN_SOUND_EDIT, QRect(CELL_DRAG_WIDTH, 0, CELL_WIDTH - CELL_DRAG_WIDTH, 2));
addRect(PredefinedRect::END_SOUND_EDIT, QRect(CELL_DRAG_WIDTH, CELL_HEIGHT - 2, CELL_WIDTH - CELL_DRAG_WIDTH, 2));
addRect(PredefinedRect::LOOP_ICON, QRect(keyRect.left(), 0, 10, 11));
// Note viewer
addRect(PredefinedRect::NOTE_AREA, QRect(QPoint(0, 0), QSize(FRAME_HEADER_WIDTH, LAYER_HEADER_HEIGHT - 1)));
addRect(PredefinedRect::NOTE_ICON, QRect(QPoint(0, 0), QSize(CELL_WIDTH - 2, CELL_HEIGHT - 2)));
addRect(PredefinedRect::LAYER_HEADER_PANEL, QRect(0, 0, -1, -1)); // hide
// Row viewer
addRect(PredefinedRect::FRAME_LABEL, QRect(CELL_WIDTH / 2, 1, CELL_WIDTH / 2, CELL_HEIGHT - 2));
addRect(PredefinedRect::FRAME_HEADER, QRect(0, 0, FRAME_HEADER_WIDTH - 1, CELL_HEIGHT));
addRect(PredefinedRect::PLAY_RANGE, QRect(PLAY_RANGE_X, 0, PLAY_MARKER_SIZE, CELL_HEIGHT));
addRect(PredefinedRect::ONION, QRect(ONION_X + (3 * ONION_DOT_SIZE - ONION_SIZE) / 2, ONION_Y, ONION_SIZE, ONION_SIZE));
int adjustOnion = (ONION_SIZE - ONION_DOT_SIZE) / 2;
addRect(PredefinedRect::ONION_DOT, QRect(ONION_X + ONION_DOT_SIZE, ONION_Y + adjustOnion, ONION_DOT_SIZE, ONION_DOT_SIZE));
addRect(PredefinedRect::ONION_DOT_FIXED, QRect(ONION_X, ONION_Y + adjustOnion, ONION_DOT_SIZE, ONION_DOT_SIZE));
addRect(PredefinedRect::ONION_AREA, QRect(ONION_X, ONION_Y, PLAY_RANGE_X, CELL_HEIGHT));
addRect(PredefinedRect::ONION_FIXED_DOT_AREA, QRect(ONION_X, ONION_Y, ONION_DOT_SIZE, CELL_HEIGHT));
addRect(PredefinedRect::ONION_DOT_AREA, QRect(ONION_X + ONION_DOT_SIZE, ONION_Y, ONION_DOT_SIZE, CELL_HEIGHT));
addRect(PredefinedRect::PINNED_CENTER_KEY, QRect((FRAME_HEADER_WIDTH - PINNED_SIZE) / 2, (CELL_HEIGHT - PINNED_SIZE) / 2, PINNED_SIZE, PINNED_SIZE));
// Column viewer
static int INDENT = 9;
static int HDRROW1 = 6; // Name/eye
static int HDRROW2 = HDRROW1 + CELL_HEIGHT; // lock, preview
static int HDRROW3 = HDRROW2 + CELL_HEIGHT + 1; // thumbnail
static int HDRROW4 = HDRROW3 + 48; // pegbar, parenthandle
addRect(PredefinedRect::LAYER_HEADER, QRect(0, 1, CELL_WIDTH, LAYER_HEADER_HEIGHT - 3));
addRect(PredefinedRect::DRAG_LAYER, QRect(0, 0, CELL_DRAG_WIDTH, LAYER_HEADER_HEIGHT - 3));
addRect(PredefinedRect::FOLDED_LAYER_HEADER, QRect(0, 1, FOLDED_LAYER_HEADER_WIDTH, FOLDED_LAYER_HEADER_HEIGHT - 3));
addRect(PredefinedRect::RENAME_COLUMN, QRect(0, 6, CELL_WIDTH, CELL_HEIGHT - 3));
QRect layername(INDENT, HDRROW1, CELL_WIDTH - 11, CELL_HEIGHT - 3);
addRect(PredefinedRect::LAYER_NAME, layername);
addRect(PredefinedRect::LAYER_NUMBER, QRect(0, 0, -1, -1)); // hide
QRect eyeArea(INDENT, HDRROW1, CELL_WIDTH - 11, CELL_HEIGHT - 3);
addRect(PredefinedRect::EYE_AREA, eyeArea);
QRect eye(eyeArea.right() - 18, HDRROW1, 18, 15);
addRect(PredefinedRect::EYE, eye);
QRect previewArea(INDENT, HDRROW2, CELL_WIDTH - 11, CELL_HEIGHT - 3);
addRect(PredefinedRect::PREVIEW_LAYER_AREA, previewArea);
QRect preview(previewArea.right() - 18, HDRROW2, 18, 15);
addRect(PredefinedRect::PREVIEW_LAYER, preview);
QRect lockArea(INDENT, HDRROW2, 16, 16);
addRect(PredefinedRect::LOCK_AREA, lockArea);
QRect lock(INDENT, HDRROW2, 16, 16);
addRect(PredefinedRect::LOCK, lock);
QRect thumbnailArea(INDENT, HDRROW3, CELL_WIDTH - 11, 42);
addRect(PredefinedRect::THUMBNAIL_AREA, thumbnailArea);
QRect thumbnail(INDENT, HDRROW3, CELL_WIDTH - 11, 42);
addRect(PredefinedRect::THUMBNAIL, thumbnail);
addRect(PredefinedRect::FILTER_COLOR, QRect(thumbnailArea.right() - 14, thumbnailArea.top() + 3, 12, 12));
addRect(PredefinedRect::SOUND_ICON, QRect(thumbnailArea.right() - 40, 3 * CELL_HEIGHT + 4, 40, 30));
int trackLen = 60;
QRect volumeArea(thumbnailArea.left(), thumbnailArea.top() + 1, 29 - CELL_DRAG_WIDTH, trackLen + 7);
addRect(PredefinedRect::VOLUME_AREA, volumeArea);
QPoint soundTopLeft(volumeArea.left() + 12, volumeArea.top() + 4);
addRect(PredefinedRect::VOLUME_TRACK, QRect(soundTopLeft, QSize(3, trackLen)));
QRect pegbarname(INDENT, HDRROW4, CELL_WIDTH - 11, CELL_HEIGHT - 3);
addRect(PredefinedRect::PEGBAR_NAME, pegbarname);
addRect(PredefinedRect::PARENT_HANDLE_NAME, QRect(INDENT + pegbarname.width() - 20, HDRROW4, 20, CELL_HEIGHT - 3));
//
// Lines
//
addLine(PredefinedLine::LOCKED, verticalLine((CELL_DRAG_WIDTH + 1) / 2, NumberRange(0, CELL_HEIGHT)));
addLine(PredefinedLine::SEE_MARKER_THROUGH, horizontalLine(0, NumberRange(0, CELL_DRAG_WIDTH)));
addLine(PredefinedLine::CONTINUE_LEVEL, verticalLine(CELL_WIDTH / 2, NumberRange(0, CELL_HEIGHT)));
addLine(PredefinedLine::CONTINUE_LEVEL_WITH_NAME, verticalLine(CELL_WIDTH - 11, NumberRange(0, CELL_HEIGHT)));
addLine(PredefinedLine::EXTENDER_LINE, horizontalLine(0, NumberRange(-EXTENDER_WIDTH - KEY_ICON_WIDTH, 0)));
//
// Dimensions
//
addDimension(PredefinedDimension::LAYER, CELL_WIDTH);
addDimension(PredefinedDimension::FRAME, CELL_HEIGHT);
addDimension(PredefinedDimension::INDEX, 0);
addDimension(PredefinedDimension::SOUND_AMPLITUDE, int(sqrt(CELL_HEIGHT * soundRect.width()) / 2));
addDimension(PredefinedDimension::FRAME_LABEL_ALIGN, Qt::AlignCenter);
addDimension(PredefinedDimension::ONION_TURN, 0);
addDimension(PredefinedDimension::QBOXLAYOUT_DIRECTION, QBoxLayout::Direction::TopToBottom);
addDimension(PredefinedDimension::CENTER_ALIGN, Qt::AlignHCenter);
//
// Paths
//
QPainterPath corner(QPointF(0, CELL_HEIGHT));
corner.lineTo(QPointF(CELL_DRAG_WIDTH, CELL_HEIGHT));
corner.lineTo(QPointF(CELL_DRAG_WIDTH, CELL_HEIGHT - CELL_DRAG_WIDTH));
corner.lineTo(QPointF(0, CELL_HEIGHT));
addPath(PredefinedPath::DRAG_HANDLE_CORNER, corner);
QPainterPath fromTriangle(QPointF(0, EASE_TRIANGLE_SIZE / 2));
fromTriangle.lineTo(QPointF(EASE_TRIANGLE_SIZE, -EASE_TRIANGLE_SIZE / 2));
fromTriangle.lineTo(QPointF(-EASE_TRIANGLE_SIZE, -EASE_TRIANGLE_SIZE / 2));
fromTriangle.lineTo(QPointF(0, EASE_TRIANGLE_SIZE / 2));
fromTriangle.translate(keyRect.center());
addPath(PredefinedPath::BEGIN_EASE_TRIANGLE, fromTriangle);
QPainterPath toTriangle(QPointF(0, -EASE_TRIANGLE_SIZE / 2));
toTriangle.lineTo(QPointF(EASE_TRIANGLE_SIZE, EASE_TRIANGLE_SIZE / 2));
toTriangle.lineTo(QPointF(-EASE_TRIANGLE_SIZE, EASE_TRIANGLE_SIZE / 2));
toTriangle.lineTo(QPointF(0, -EASE_TRIANGLE_SIZE / 2));
toTriangle.translate(keyRect.center());
addPath(PredefinedPath::END_EASE_TRIANGLE, toTriangle);
QPainterPath playFrom(QPointF(0, 0));
playFrom.lineTo(QPointF(PLAY_MARKER_SIZE, 0));
playFrom.lineTo(QPointF(0, PLAY_MARKER_SIZE));
playFrom.lineTo(QPointF(0, 0));
playFrom.translate(PLAY_RANGE_X, 1);
addPath(PredefinedPath::BEGIN_PLAY_RANGE, playFrom);
QPainterPath playTo(QPointF(0, 0));
playTo.lineTo(QPointF(PLAY_MARKER_SIZE, 0));
playTo.lineTo(QPointF(0, -PLAY_MARKER_SIZE));
playTo.lineTo(QPointF(0, 0));
playTo.translate(PLAY_RANGE_X, CELL_HEIGHT - 1);
addPath(PredefinedPath::END_PLAY_RANGE, playTo);
QPainterPath track(QPointF(0, 0));
track.lineTo(QPointF(1, 1));
track.lineTo(QPointF(1, trackLen - 1));
track.lineTo(QPointF(0, trackLen));
track.lineTo(QPointF(-1, trackLen - 1));
track.lineTo(QPointF(-1, 1));
track.lineTo(QPointF(0, 0));
track.translate(soundTopLeft);
addPath(PredefinedPath::VOLUME_SLIDER_TRACK, track);
QPainterPath head(QPointF(0, 0));
head.lineTo(QPointF(4, 4));
head.lineTo(QPointF(8, 4));
head.lineTo(QPointF(8, -4));
head.lineTo(QPointF(4, -4));
head.lineTo(QPointF(0, 0));
addPath(PredefinedPath::VOLUME_SLIDER_HEAD, head);
//
// Points
//
addPoint(PredefinedPoint::KEY_HIDDEN, QPoint(KEY_ICON_WIDTH, 0));
addPoint(PredefinedPoint::EXTENDER_XY_RADIUS, QPoint(30, 75));
addPoint(PredefinedPoint::VOLUME_DIVISIONS_TOP_LEFT, soundTopLeft - QPoint(5, 0));
//
// Ranges
//
addRange(PredefinedRange::HEADER_LAYER, NumberRange(0, FRAME_HEADER_WIDTH));
addRange(PredefinedRange::HEADER_FRAME, NumberRange(0, LAYER_HEADER_HEIGHT));
}
CellPosition TopToBottomOrientation::xyToPosition(const QPoint &xy,
const ColumnFan *fan) const {
int layer = fan->layerAxisToCol(xy.x());
int frame = xy.y() / CELL_HEIGHT;
return CellPosition(frame, layer);
}
QPoint TopToBottomOrientation::positionToXY(const CellPosition &position,
const ColumnFan *fan) const {
int x = colToLayerAxis(position.layer(), fan);
int y = rowToFrameAxis(position.frame());
return QPoint(x, y);
}
CellPositionRatio TopToBottomOrientation::xyToPositionRatio(
const QPoint &xy) const {
Ratio frame{xy.y(), CELL_HEIGHT};
Ratio layer{xy.x(), CELL_WIDTH};
return CellPositionRatio{frame, layer};
}
QPoint TopToBottomOrientation::positionRatioToXY(
const CellPositionRatio &ratio) const {
int x = ratio.layer() * CELL_WIDTH;
int y = ratio.frame() * CELL_HEIGHT;
return QPoint(x, y);
}
int TopToBottomOrientation::colToLayerAxis(int layer,
const ColumnFan *fan) const {
return fan->colToLayerAxis(layer);
}
int TopToBottomOrientation::rowToFrameAxis(int frame) const {
return frame * CELL_HEIGHT;
}
QPoint TopToBottomOrientation::frameLayerToXY(int frameAxis,
int layerAxis) const {
return QPoint(layerAxis, frameAxis);
}
int TopToBottomOrientation::layerAxis(const QPoint &xy) const { return xy.x(); }
int TopToBottomOrientation::frameAxis(const QPoint &xy) const { return xy.y(); }
NumberRange TopToBottomOrientation::layerSide(const QRect &area) const {
return NumberRange(area.left(), area.right());
}
NumberRange TopToBottomOrientation::frameSide(const QRect &area) const {
return NumberRange(area.top(), area.bottom());
}
QPoint TopToBottomOrientation::topRightCorner(const QRect &area) const {
return area.topRight();
}
CellPosition TopToBottomOrientation::arrowShift(int direction) const {
switch (direction) {
case Qt::Key_Up:
return CellPosition(-1, 0);
case Qt::Key_Down:
return CellPosition(1, 0);
case Qt::Key_Left:
return CellPosition(0, -1);
case Qt::Key_Right:
return CellPosition(0, 1);
default:
return CellPosition(0, 0);
}
}
/// --------------------------------------------------------------------------------
LeftToRightOrientation::LeftToRightOrientation() {
//
// Ranges
//
// Cell viewer
QRect cellRect(0, 0, CELL_WIDTH, CELL_HEIGHT);
addRect(PredefinedRect::CELL, cellRect);
addRect(PredefinedRect::DRAG_HANDLE_CORNER, QRect(0, 0, CELL_WIDTH, CELL_DRAG_HEIGHT));
QRect keyRect((CELL_WIDTH - KEY_ICON_WIDTH) / 2, CELL_HEIGHT - KEY_ICON_HEIGHT, KEY_ICON_WIDTH, KEY_ICON_HEIGHT);
addRect(PredefinedRect::KEY_ICON, keyRect);
QRect nameRect = cellRect.adjusted(4, 4, -6, 0);
addRect(PredefinedRect::CELL_NAME, nameRect);
addRect(PredefinedRect::CELL_NAME_WITH_KEYFRAME, nameRect);
addRect(PredefinedRect::END_EXTENDER, QRect(0, -EXTENDER_HEIGHT - 10, EXTENDER_WIDTH, EXTENDER_HEIGHT));
addRect(PredefinedRect::BEGIN_EXTENDER, QRect(-EXTENDER_WIDTH, -EXTENDER_HEIGHT - 10, EXTENDER_WIDTH, EXTENDER_HEIGHT));
addRect(PredefinedRect::KEYFRAME_AREA, keyRect);
addRect(PredefinedRect::DRAG_AREA, QRect(0, 0, CELL_WIDTH, CELL_DRAG_HEIGHT));
QRect soundRect(0, CELL_DRAG_HEIGHT, CELL_WIDTH, CELL_HEIGHT - CELL_DRAG_HEIGHT - SOUND_PREVIEW_HEIGHT);
addRect(PredefinedRect::SOUND_TRACK, soundRect);
addRect(PredefinedRect::PREVIEW_TRACK, QRect(0, CELL_HEIGHT - SOUND_PREVIEW_HEIGHT + 1, CELL_WIDTH, SOUND_PREVIEW_HEIGHT));
addRect(PredefinedRect::BEGIN_SOUND_EDIT, QRect(0, CELL_DRAG_HEIGHT, 2, CELL_HEIGHT - CELL_DRAG_HEIGHT));
addRect(PredefinedRect::END_SOUND_EDIT, QRect(CELL_WIDTH - 2, CELL_DRAG_HEIGHT, 2, CELL_HEIGHT - CELL_DRAG_HEIGHT));
addRect(PredefinedRect::LOOP_ICON, QRect(0, keyRect.top(), 10, 11));
// Notes viewer
addRect(PredefinedRect::NOTE_AREA, QRect(QPoint(0, 0), QSize(LAYER_HEADER_WIDTH - 1, FRAME_HEADER_HEIGHT)));
addRect(PredefinedRect::NOTE_ICON, QRect(QPoint(0, 0), QSize(CELL_WIDTH - 2, CELL_HEIGHT - 2)));
addRect(PredefinedRect::LAYER_HEADER_PANEL, QRect(0, FRAME_HEADER_HEIGHT - CELL_HEIGHT, LAYER_HEADER_WIDTH, CELL_HEIGHT));
// Row viewer
addRect(PredefinedRect::FRAME_LABEL, QRect(CELL_WIDTH / 4, 1, CELL_WIDTH / 2, FRAME_HEADER_HEIGHT - 2));
addRect(PredefinedRect::FRAME_HEADER, QRect(0, 0, CELL_WIDTH, FRAME_HEADER_HEIGHT - 1));
addRect(PredefinedRect::PLAY_RANGE, QRect(0, PLAY_RANGE_Y, CELL_WIDTH, PLAY_MARKER_SIZE));
addRect(PredefinedRect::ONION, QRect(ONION_X, ONION_Y + (3 * ONION_DOT_SIZE - ONION_SIZE) / 2, ONION_SIZE, ONION_SIZE));
int adjustOnion = (ONION_SIZE - ONION_DOT_SIZE) / 2;
addRect(PredefinedRect::ONION_DOT, QRect(ONION_X + adjustOnion, ONION_Y + ONION_DOT_SIZE, ONION_DOT_SIZE, ONION_DOT_SIZE));
addRect(PredefinedRect::ONION_DOT_FIXED, QRect(ONION_X + adjustOnion, ONION_Y, ONION_DOT_SIZE, ONION_DOT_SIZE));
addRect(PredefinedRect::ONION_AREA, QRect(ONION_X, ONION_Y, CELL_WIDTH, ONION_SIZE));
addRect(PredefinedRect::ONION_FIXED_DOT_AREA, QRect(ONION_X, ONION_Y, CELL_WIDTH, ONION_DOT_SIZE));
addRect(PredefinedRect::ONION_DOT_AREA, QRect(ONION_X, ONION_Y + ONION_DOT_SIZE, CELL_WIDTH, ONION_DOT_SIZE));
addRect(PredefinedRect::PINNED_CENTER_KEY, QRect((CELL_WIDTH - PINNED_SIZE) / 2, (FRAME_HEADER_HEIGHT - PINNED_SIZE) / 2, PINNED_SIZE, PINNED_SIZE));
// Column viewer
addRect(PredefinedRect::LAYER_HEADER, QRect(1, 0, LAYER_HEADER_WIDTH - 3, CELL_HEIGHT));
addRect(PredefinedRect::FOLDED_LAYER_HEADER, QRect(1, 0, FOLDED_LAYER_HEADER_WIDTH - 3, FOLDED_LAYER_HEADER_HEIGHT));
QRect columnName(ICONS_WIDTH + 1, 0, LAYER_NAME_WIDTH + LAYER_NUMBER_WIDTH - 3, CELL_HEIGHT);
addRect(PredefinedRect::RENAME_COLUMN, columnName);
QRect eye(1, 0, ICON_WIDTH, CELL_HEIGHT);
addRect(PredefinedRect::EYE_AREA, eye);
addRect(PredefinedRect::EYE, eye.adjusted(1, 1, 0, 0));
addRect(PredefinedRect::PREVIEW_LAYER_AREA, eye.translated(ICON_OFFSET, 0));
addRect(PredefinedRect::PREVIEW_LAYER, eye.translated(ICON_OFFSET + 1, 0).adjusted(-1, 1, -1, 0));
addRect(PredefinedRect::LOCK_AREA, eye.translated(2 * ICON_OFFSET, 0));
addRect(PredefinedRect::LOCK, eye.translated(2 * ICON_OFFSET + 1, 0).adjusted(-1, 1, -1, 0));
addRect(PredefinedRect::DRAG_LAYER, QRect(ICONS_WIDTH + 1, 0, LAYER_HEADER_WIDTH - ICONS_WIDTH - 3, CELL_DRAG_HEIGHT));
addRect(PredefinedRect::LAYER_NAME, columnName);
addRect(PredefinedRect::LAYER_NUMBER, QRect(ICONS_WIDTH + 1, 0, LAYER_NUMBER_WIDTH, CELL_HEIGHT));
addRect(PredefinedRect::THUMBNAIL_AREA, QRect(0, 0, -1, -1)); // hide
addRect(PredefinedRect::FILTER_COLOR, QRect(LAYER_HEADER_WIDTH - 17, 6, 12, 12));
addRect(PredefinedRect::PEGBAR_NAME, QRect(0, 0, -1, -1)); // hide
addRect(PredefinedRect::PARENT_HANDLE_NAME, QRect(0, 0, -1, -1)); // hide
int trackLen = 60;
QRect volumeArea(QRect(columnName.topRight(), QSize(trackLen + 8, columnName.height())).adjusted(-97, 0, -97, 0));
addRect(PredefinedRect::VOLUME_AREA, volumeArea);
QPoint soundTopLeft(volumeArea.left() + 4, volumeArea.top() + 12);
addRect(PredefinedRect::VOLUME_TRACK, QRect(soundTopLeft, QSize(trackLen, 3)));
addRect(PredefinedRect::SOUND_ICON, QRect(columnName.topRight(), QSize(27, columnName.height())).adjusted(-28, 0, -28, 0));
//
// Lines
//
addLine(PredefinedLine::LOCKED, verticalLine(CELL_DRAG_HEIGHT / 2, NumberRange(0, CELL_WIDTH)));
addLine(PredefinedLine::SEE_MARKER_THROUGH, horizontalLine(0, NumberRange(0, CELL_DRAG_HEIGHT)));
addLine(PredefinedLine::CONTINUE_LEVEL, verticalLine(CELL_HEIGHT / 2, NumberRange(0, CELL_WIDTH)));
addLine(PredefinedLine::CONTINUE_LEVEL_WITH_NAME, verticalLine(CELL_HEIGHT / 2, NumberRange(0, CELL_WIDTH)));
addLine(PredefinedLine::EXTENDER_LINE, horizontalLine(0, NumberRange(-EXTENDER_WIDTH - KEY_ICON_WIDTH, 0)));
//
// Dimensions
//
addDimension(PredefinedDimension::LAYER, CELL_HEIGHT);
addDimension(PredefinedDimension::FRAME, CELL_WIDTH);
addDimension(PredefinedDimension::INDEX, 1);
addDimension(PredefinedDimension::SOUND_AMPLITUDE, soundRect.height() / 2);
addDimension(PredefinedDimension::FRAME_LABEL_ALIGN, Qt::AlignHCenter | Qt::AlignBottom | Qt::TextWordWrap);
addDimension(PredefinedDimension::ONION_TURN, 90);
addDimension(PredefinedDimension::QBOXLAYOUT_DIRECTION, QBoxLayout::Direction::LeftToRight);
addDimension(PredefinedDimension::CENTER_ALIGN, Qt::AlignVCenter);
//
// Paths
//
QPainterPath corner(QPointF(CELL_WIDTH, 0));
corner.lineTo(QPointF(CELL_WIDTH, CELL_DRAG_HEIGHT));
corner.lineTo(QPointF(CELL_WIDTH - CELL_DRAG_HEIGHT, CELL_DRAG_HEIGHT));
corner.lineTo(QPointF(CELL_WIDTH, 0));
addPath(PredefinedPath::DRAG_HANDLE_CORNER, corner);
QPainterPath fromTriangle(QPointF(EASE_TRIANGLE_SIZE / 2, 0));
fromTriangle.lineTo(QPointF(-EASE_TRIANGLE_SIZE / 2, EASE_TRIANGLE_SIZE));
fromTriangle.lineTo(QPointF(-EASE_TRIANGLE_SIZE / 2, -EASE_TRIANGLE_SIZE));
fromTriangle.lineTo(QPointF(EASE_TRIANGLE_SIZE / 2, 0));
fromTriangle.translate(keyRect.center());
addPath(PredefinedPath::BEGIN_EASE_TRIANGLE, fromTriangle);
QPainterPath toTriangle(QPointF(-EASE_TRIANGLE_SIZE / 2, 0));
toTriangle.lineTo(QPointF(EASE_TRIANGLE_SIZE / 2, EASE_TRIANGLE_SIZE));
toTriangle.lineTo(QPointF(EASE_TRIANGLE_SIZE / 2, -EASE_TRIANGLE_SIZE));
toTriangle.lineTo(QPointF(-EASE_TRIANGLE_SIZE / 2, 0));
toTriangle.translate(keyRect.center());
addPath(PredefinedPath::END_EASE_TRIANGLE, toTriangle);
QPainterPath playFrom(QPointF(0, 0));
playFrom.lineTo(QPointF(PLAY_MARKER_SIZE, 0));
playFrom.lineTo(QPointF(0, PLAY_MARKER_SIZE));
playFrom.lineTo(QPointF(0, 0));
playFrom.translate(1, PLAY_RANGE_Y);
addPath(PredefinedPath::BEGIN_PLAY_RANGE, playFrom);
QPainterPath playTo(QPointF(0, 0));
playTo.lineTo(QPointF(-PLAY_MARKER_SIZE, 0));
playTo.lineTo(QPointF(0, PLAY_MARKER_SIZE));
playTo.lineTo(QPointF(0, 0));
playTo.translate(CELL_WIDTH - 1, PLAY_RANGE_Y);
addPath(PredefinedPath::END_PLAY_RANGE, playTo);
QPainterPath track(QPointF(0, 0));
track.lineTo(QPointF(1, 1));
track.lineTo(QPointF(trackLen - 1, 1));
track.lineTo(QPointF(trackLen, 0));
track.lineTo(QPointF(trackLen - 1, -1));
track.lineTo(QPointF(1, -1));
track.lineTo(QPointF(0, 0));
track.translate(soundTopLeft);
addPath(PredefinedPath::VOLUME_SLIDER_TRACK, track);
QPainterPath head(QPointF(0, 0));
head.lineTo(QPointF(4, -4));
head.lineTo(QPointF(4, -8));
head.lineTo(QPointF(-4, -8));
head.lineTo(QPointF(-4, -4));
head.lineTo(QPointF(0, 0));
addPath(PredefinedPath::VOLUME_SLIDER_HEAD, head);
//
// Points
//
addPoint(PredefinedPoint::KEY_HIDDEN, QPoint(0, 10));
addPoint(PredefinedPoint::EXTENDER_XY_RADIUS, QPoint(75, 30));
addPoint(PredefinedPoint::VOLUME_DIVISIONS_TOP_LEFT, soundTopLeft + QPoint(0, 3));
//
// Ranges
//
addRange(PredefinedRange::HEADER_LAYER, NumberRange(0, FRAME_HEADER_HEIGHT));
addRange(PredefinedRange::HEADER_FRAME, NumberRange(0, LAYER_HEADER_WIDTH));
}
CellPosition LeftToRightOrientation::xyToPosition(const QPoint &xy,
const ColumnFan *fan) const {
int layer = fan->layerAxisToCol(xy.y());
int frame = xy.x() / CELL_WIDTH;
return CellPosition(frame, layer);
}
QPoint LeftToRightOrientation::positionToXY(const CellPosition &position,
const ColumnFan *fan) const {
int y = colToLayerAxis(position.layer(), fan);
int x = rowToFrameAxis(position.frame());
return QPoint(x, y);
}
CellPositionRatio LeftToRightOrientation::xyToPositionRatio(
const QPoint &xy) const {
Ratio frame{xy.x(), CELL_WIDTH};
Ratio layer{xy.y(), CELL_HEIGHT};
return CellPositionRatio{frame, layer};
}
QPoint LeftToRightOrientation::positionRatioToXY(
const CellPositionRatio &ratio) const {
int x = ratio.frame() * CELL_WIDTH;
int y = ratio.layer() * CELL_HEIGHT;
return QPoint(x, y);
}
int LeftToRightOrientation::colToLayerAxis(int layer,
const ColumnFan *fan) const {
return fan->colToLayerAxis(layer);
}
int LeftToRightOrientation::rowToFrameAxis(int frame) const {
return frame * CELL_WIDTH;
}
QPoint LeftToRightOrientation::frameLayerToXY(int frameAxis,
int layerAxis) const {
return QPoint(frameAxis, layerAxis);
}
int LeftToRightOrientation::layerAxis(const QPoint &xy) const { return xy.y(); }
int LeftToRightOrientation::frameAxis(const QPoint &xy) const { return xy.x(); }
NumberRange LeftToRightOrientation::layerSide(const QRect &area) const {
return NumberRange(area.top(), area.bottom());
}
NumberRange LeftToRightOrientation::frameSide(const QRect &area) const {
return NumberRange(area.left(), area.right());
}
QPoint LeftToRightOrientation::topRightCorner(const QRect &area) const {
return area.bottomLeft();
}
CellPosition LeftToRightOrientation::arrowShift(int direction) const {
switch (direction) {
case Qt::Key_Up:
return CellPosition(0, -1);
case Qt::Key_Down:
return CellPosition(0, 1);
case Qt::Key_Left:
return CellPosition(-1, 0);
case Qt::Key_Right:
return CellPosition(1, 0);
default:
return CellPosition(0, 0);
}
}

View file

@ -310,7 +310,8 @@ Preferences::Preferences()
, m_useNumpadForSwitchingStyles(true)
, m_showXSheetToolbar(false)
, m_expandFunctionHeader(false)
, m_useArrowKeyToShiftCellSelection(false)
, m_showColumnNumbers(false)
, m_useArrowKeyToShiftCellSelection(false)
, m_inputCellsWithoutDoubleClickingEnabled(false)
, m_importPolicy(0)
, m_watchFileSystem(true) {
@ -589,6 +590,7 @@ Preferences::Preferences()
m_useNumpadForSwitchingStyles);
getValue(*m_settings, "showXSheetToolbar", m_showXSheetToolbar);
getValue(*m_settings, "expandFunctionHeader", m_expandFunctionHeader);
getValue(*m_settings, "showColumnNumbers", m_showColumnNumbers);
getValue(*m_settings, "useArrowKeyToShiftCellSelection",
m_useArrowKeyToShiftCellSelection);
getValue(*m_settings, "inputCellsWithoutDoubleClickingEnabled",
@ -1389,6 +1391,11 @@ void Preferences::enableExpandFunctionHeader(bool on) {
m_settings->setValue("expandFunctionHeader", on ? "1" : "0");
}
void Preferences::enableShowColumnNumbers(bool on) {
m_showColumnNumbers = on;
m_settings->setValue("showColumnNumbers", on ? "1" : "0");
}
//-----------------------------------------------------------------
void Preferences::enableUseArrowKeyToShiftCellSelection(bool on) {

View file

@ -31,6 +31,7 @@
#include "toonz/stage.h"
#include "toonz/textureutils.h"
#include "xshhandlemanager.h"
#include "orientation.h"
#include "toonz/txsheet.h"
@ -92,7 +93,7 @@ struct TXsheet::TXsheetImp {
int m_viewColumn;
TSoundTrackP m_mixedSound;
ColumnFan m_columnFan;
ColumnFan m_columnFans[Orientations::COUNT];
XshHandleManager *m_handleManager;
ToonzScene *m_scene;
@ -105,7 +106,11 @@ public:
return ++currentId;
}
void copyFoldedState();
private:
void initColumnFans();
// not implemented
TXsheetImp(const TXsheetImp &);
TXsheetImp &operator=(const TXsheetImp &);
@ -144,7 +149,9 @@ TXsheet::TXsheetImp::TXsheetImp()
, m_soloColumn(-1)
, m_viewColumn(-1)
, m_mixedSound(0)
, m_scene(0) {}
, m_scene(0) {
initColumnFans();
}
//-----------------------------------------------------------------------------
@ -157,6 +164,20 @@ TXsheet::TXsheetImp::~TXsheetImp() {
delete m_handleManager;
}
//-----------------------------------------------------------------------------
void TXsheet::TXsheetImp::initColumnFans() {
for (auto o : Orientations::all()) {
int index = o->dimension(PredefinedDimension::INDEX);
m_columnFans[index].setDimension(o->dimension(PredefinedDimension::LAYER));
}
}
void TXsheet::TXsheetImp::copyFoldedState() {
for (int i = 1; i < Orientations::COUNT; i++)
m_columnFans[i].copyFoldedStateFrom(m_columnFans[0]);
}
//=============================================================================
// TXsheet
@ -193,12 +214,17 @@ int TXsheet::getFrameCount() const { return m_imp->m_frameCount; }
//-----------------------------------------------------------------------------
const TXshCell &TXsheet::getCell(int row, int col) const {
return getCell(CellPosition(row, col));
}
const TXshCell &TXsheet::getCell(const CellPosition &pos) const {
static const TXshCell emptyCell;
TXshColumnP column = m_imp->m_columnSet.getColumn(col);
TXshColumnP column = m_imp->m_columnSet.getColumn(pos.layer());
if (!column) return emptyCell;
TXshCellColumn *xshColumn = column->getCellColumn();
if (!xshColumn) return emptyCell;
return xshColumn->getCell(row);
return xshColumn->getCell(pos.frame());
}
//-----------------------------------------------------------------------------
@ -590,8 +616,8 @@ void TXsheet::reverseCells(int r0, int c0, int r1, int c1) {
for (int j = c0; j <= c1; j++) {
int i1, i2;
for (i1 = r0, i2 = r1; i1 < i2; i1++, i2--) {
TXshCell app1 = getCell(i1, j);
TXshCell app2 = getCell(i2, j);
TXshCell app1 = getCell(CellPosition(i1, j));
TXshCell app2 = getCell(CellPosition(i2, j));
setCell(i1, j, app2);
setCell(i2, j, app1);
}
@ -608,7 +634,7 @@ void TXsheet::swingCells(int r0, int c0, int r1, int c1) {
for (int j = c0; j <= c1; j++) {
for (int i1 = r0Mod, i2 = r1 - 1; i2 >= r0; i1++, i2--) {
TXshCell cell = getCell(i2, j);
TXshCell cell = getCell(CellPosition(i2, j));
setCell(i1, j, cell);
}
}
@ -620,49 +646,52 @@ bool TXsheet::incrementCells(int r0, int c0, int r1, int c1,
vector<std::pair<TRect, TXshCell>> &forUndo) {
for (int j = c0; j <= c1; j++) {
int i = r0;
while (getCell(i, j).isEmpty() && i <= r1 - 1) i++;
while (getCell(CellPosition(i, j)).isEmpty() && i <= r1 - 1) i++;
for (; i <= r1 - 1; i++) {
if (getCell(i + 1, j).isEmpty()) break;
const TXshCell &ce1 = getCell(i, j), &ce2 = getCell(i + 1, j);
if (getCell(CellPosition(i + 1, j)).isEmpty()) break;
const TXshCell &ce1 = getCell(CellPosition(i, j)),
&ce2 = getCell(CellPosition(i + 1, j));
if (ce2.getSimpleLevel() != ce1.getSimpleLevel() ||
ce2.getFrameId().getNumber() < ce1.getFrameId().getNumber())
return false;
}
i = r0;
while (getCell(i, j).isEmpty() && i <= r1 - 1) i++;
while (getCell(CellPosition(i, j)).isEmpty() && i <= r1 - 1) i++;
int count;
for (; i <= r1 - 1; i++) {
count = 1;
if (getCell(i + 1, j).isEmpty()) continue;
if (getCell(CellPosition(i + 1, j)).isEmpty()) continue;
int frame1 = getCell(i, j).getFrameId().getNumber();
int frame1 = getCell(CellPosition(i, j)).getFrameId().getNumber();
if (frame1 == -1) break;
while (!getCell(i + 1, j).isEmpty() &&
getCell(i + 1, j).getFrameId().getNumber() ==
getCell(i, j).getFrameId().getNumber())
while (!getCell(CellPosition(i + 1, j)).isEmpty() &&
getCell(CellPosition(i + 1, j)).getFrameId().getNumber() ==
getCell(CellPosition(i, j)).getFrameId().getNumber())
i++, count++;
int frame2 = getCell(i + 1, j).getFrameId().getNumber();
int frame2 = getCell(CellPosition(i + 1, j)).getFrameId().getNumber();
if (frame2 == -1) break;
if (frame1 + count == frame2)
continue;
else if (frame1 + count < frame2) // aggiungo
else if (frame1 + count < frame2) // add
{
int numCells = frame2 - frame1 - count;
insertCells(i + 1, j, numCells);
forUndo.push_back(std::pair<TRect, TXshCell>(
TRect(i + 1, j, i + 1 + numCells - 1, j), TXshCell()));
for (int k = 1; k <= numCells; k++) setCell(i + k, j, getCell(i, j));
for (int k = 1; k <= numCells; k++)
setCell(i + k, j, getCell(CellPosition(i, j)));
i += numCells;
r1 += numCells;
} else // tolgo
} else // remove
{
int numCells = count - frame2 + frame1;
i = i - numCells;
forUndo.push_back(std::pair<TRect, TXshCell>(
TRect(i + 1, j, i + 1 + numCells - 1, j), getCell(i + 1, j)));
forUndo.push_back(
std::pair<TRect, TXshCell>(TRect(i + 1, j, i + 1 + numCells - 1, j),
getCell(CellPosition(i + 1, j))));
removeCells(i + 1, j, numCells);
r1 -= numCells;
}
@ -680,7 +709,7 @@ void TXsheet::duplicateCells(int r0, int c0, int r1, int c1, int upTo) {
for (int j = c0; j <= c1; j++) {
insertCells(r1 + 1, j, upTo - (r1 + 1) + 1);
for (int i = r1 + 1; i <= upTo; i++)
setCell(i, j, getCell(r0 + ((i - (r1 + 1)) % chunk), j));
setCell(i, j, getCell(CellPosition(r0 + ((i - (r1 + 1)) % chunk), j)));
}
}
@ -697,7 +726,7 @@ void TXsheet::stepCells(int r0, int c0, int r1, int c1, int type) {
int k = 0;
for (int r = r0; r <= r1; r++)
for (int c = c0; c <= c1; c++) {
cells[k++] = getCell(r, c);
cells[k++] = getCell(CellPosition(r, c));
}
int nrows = nr * (type - 1);
@ -726,13 +755,13 @@ void TXsheet::increaseStepCells(int r0, int c0, int &r1, int c1) {
for (c = c0; c <= c1; c++) {
int r = r0, i = 0, rEnd = r1;
while (r <= rEnd) {
TXshCell cell = getCell(r, c);
TXshCell cell = getCell(CellPosition(r, c));
if (!cell.isEmpty()) {
insertCells(r, c);
setCell(r, c, cell);
rEnd++;
r++;
while (cell == getCell(r, c) && r <= rEnd) r++;
while (cell == getCell(CellPosition(r, c)) && r <= rEnd) r++;
} else
r++;
i++;
@ -755,11 +784,11 @@ void TXsheet::decreaseStepCells(int r0, int c0, int &r1, int c1) {
for (c = c0; c <= c1; c++) {
int r = r0, i = 0, rEnd = r1;
while (r <= rEnd) {
TXshCell cell = getCell(r, c);
TXshCell cell = getCell(CellPosition(r, c));
if (!cell.isEmpty()) {
r++;
bool removed = false;
while (cell == getCell(r, c) && r <= rEnd) {
while (cell == getCell(CellPosition(r, c)) && r <= rEnd) {
if (!removed) {
removed = true;
removeCells(r, c);
@ -799,7 +828,7 @@ void TXsheet::eachCells(int r0, int c0, int r1, int c1, int type) {
for (j = r0, i = 0; i < size;
j += type) // in cells copio il contenuto delle celle che mi interessano
{
for (k = c0; k <= c1; k++, i++) cells[i] = getCell(j, k);
for (k = c0; k <= c1; k++, i++) cells[i] = getCell(CellPosition(j, k));
}
int c;
@ -831,8 +860,8 @@ int TXsheet::reframeCells(int r0, int r1, int col, int type) {
cells.clear();
for (int r = r0; r <= r1; r++) {
if (cells.size() == 0 || cells.last() != getCell(r, col))
cells.push_back(getCell(r, col));
if (cells.size() == 0 || cells.last() != getCell(CellPosition(r, col)))
cells.push_back(getCell(CellPosition(r, col)));
}
if (cells.empty()) return 0;
@ -871,9 +900,9 @@ void TXsheet::resetStepCells(int r0, int c0, int r1, int c1) {
TXshCell *cells = new TXshCell[size];
while (r <= r1) {
// mi prendo le celle che mi servono
cells[i] = getCell(r, c);
cells[i] = getCell(CellPosition(r, c));
r++;
while (cells[i] == getCell(r, c) && r <= r1) r++;
while (cells[i] == getCell(CellPosition(r, c)) && r <= r1) r++;
i++;
}
@ -899,7 +928,7 @@ void TXsheet::rollupCells(int r0, int c0, int r1, int c1) {
// in cells copio il contenuto delle celle che mi interessano
int k;
for (k = c0; k <= c1; k++) cells[k - c0] = getCell(r0, k);
for (k = c0; k <= c1; k++) cells[k - c0] = getCell(CellPosition(r0, k));
for (k = c0; k <= c1; k++) removeCells(r0, k, 1);
@ -922,7 +951,7 @@ void TXsheet::rolldownCells(int r0, int c0, int r1, int c1) {
// in cells copio il contenuto delle celle che mi interessano
int k;
for (k = c0; k <= c1; k++) cells[k - c0] = getCell(r1, k);
for (k = c0; k <= c1; k++) cells[k - c0] = getCell(CellPosition(r1, k));
for (k = c0; k <= c1; k++) removeCells(r1, k, 1);
@ -1188,7 +1217,8 @@ void TXsheet::loadData(TIStream &is) {
TFxSet fxSet;
fxSet.loadData(is);
} else if (tagName == "columnFan") {
m_imp->m_columnFan.loadData(is);
m_imp->m_columnFans[0].loadData(is);
m_imp->copyFoldedState();
} else if (tagName == "noteSet") {
m_notes->loadData(is);
} else {
@ -1218,7 +1248,8 @@ void TXsheet::saveData(TOStream &os) {
fxDag->saveData(os, getFirstFreeColumnIndex());
os.closeChild();
ColumnFan *columnFan = getColumnFan();
// does not matter which Orientation to take, as all fans share folded data
ColumnFan *columnFan = getColumnFan(Orientations::topToBottom());
if (!columnFan->isEmpty()) {
os.openChild("columnFan");
columnFan->saveData(os);
@ -1439,7 +1470,10 @@ FxDag *TXsheet::getFxDag() const { return m_imp->m_fxDag; }
//-----------------------------------------------------------------------------
ColumnFan *TXsheet::getColumnFan() const { return &m_imp->m_columnFan; }
ColumnFan *TXsheet::getColumnFan(const Orientation *o) const {
int index = o->dimension(PredefinedDimension::INDEX);
return &m_imp->m_columnFans[index];
}
//-----------------------------------------------------------------------------
@ -1504,7 +1538,7 @@ TRectD TXsheet::getBBox(int r) const {
struct locals {
static TRectD getBBox(const TXsheet *xsh, int r, int c) {
// Discriminate cell content
const TXshCell &cell = xsh->getCell(r, c);
const TXshCell &cell = xsh->getCell(CellPosition(r, c));
if (cell.isEmpty()) return voidRect;
if (TXshChildLevel *cl = cell.getChildLevel())
@ -1570,11 +1604,10 @@ TRectD TXsheet::getBBox(int r) const {
//-----------------------------------------------------------------------
bool TXsheet::isRectEmpty(int r0, int c0, int r1, int c1) const {
for (int r = r0; r <= r1; r++) {
for (int c = c0; c <= c1; c++) {
if (!getCell(r, c).isEmpty()) return false;
}
}
bool TXsheet::isRectEmpty(const CellPosition &pos0,
const CellPosition &pos1) const {
for (int frame = pos0.frame(); frame <= pos1.frame(); frame++)
for (int layer = pos0.layer(); layer <= pos1.layer(); layer++)
if (!getCell(CellPosition(frame, layer)).isEmpty()) return false;
return true;
}

View file

@ -145,9 +145,13 @@ void TXshSoundLevel::saveData(TOStream &os) {
//-----------------------------------------------------------------------------
void TXshSoundLevel::computeValues(int frameHeight) {
void TXshSoundLevel::computeValuesFor(const Orientation *o) {
int frameHeight = o->dimension(PredefinedDimension::FRAME); // time axis
int index = o->dimension(PredefinedDimension::INDEX);
map<int, DoublePair> &values = m_values[index];
if (frameHeight == 0) frameHeight = 1;
m_values.clear();
values.clear();
if (!m_soundTrack) {
m_frameSoundCount = 0;
m_samplePerFrame = 0;
@ -174,7 +178,9 @@ void TXshSoundLevel::computeValues(int frameHeight) {
if (absMaxPressure <= 0) return;
// Adjusting using a fixed scaleFactor
double weightA = 20.0 / absMaxPressure;
int desiredAmplitude = o->dimension(PredefinedDimension::SOUND_AMPLITUDE);
// results will be in range -desiredAmplitude .. +desiredAmplitude
double weightA = desiredAmplitude / absMaxPressure;
long i = 0, j;
long p = 0; // se p parte da zero notazione per pixel,
@ -187,7 +193,7 @@ void TXshSoundLevel::computeValues(int frameHeight) {
(TINT32)(i * m_samplePerFrame + j * samplePerPixel),
(TINT32)(i * m_samplePerFrame + (j + 1) * samplePerPixel - 1),
TSound::MONO, min, max);
m_values.insert(std::pair<int, std::pair<double, double>>(
values.insert(std::pair<int, std::pair<double, double>>(
p + j, std::pair<double, double>(min * weightA, max * weightA)));
}
@ -196,7 +202,7 @@ void TXshSoundLevel::computeValues(int frameHeight) {
m_soundTrack->getMinMaxPressure(
(TINT32)(i * m_samplePerFrame + j * samplePerPixel),
(TINT32)((i + 1) * m_samplePerFrame - 1), TSound::MONO, min, max);
m_values.insert(std::pair<int, std::pair<double, double>>(
values.insert(std::pair<int, std::pair<double, double>>(
p + j, std::pair<double, double>(min * weightA, max * weightA)));
++i;
@ -206,9 +212,17 @@ void TXshSoundLevel::computeValues(int frameHeight) {
//-----------------------------------------------------------------------------
void TXshSoundLevel::getValueAtPixel(int pixel, DoublePair &values) const {
std::map<int, DoublePair>::const_iterator it = m_values.find(pixel);
if (it != m_values.end()) values = it->second;
void TXshSoundLevel::computeValues() {
for (auto o : Orientations::all()) computeValuesFor(o);
}
//-----------------------------------------------------------------------------
void TXshSoundLevel::getValueAtPixel(const Orientation *o, int pixel,
DoublePair &values) const {
int index = o->dimension(PredefinedDimension::INDEX);
std::map<int, DoublePair>::const_iterator it = m_values[index].find(pixel);
if (it != m_values[index].end()) values = it->second;
}
//-----------------------------------------------------------------------------

View file

@ -251,12 +251,10 @@ void FunctionSheetColumnHeadViewer::paintEvent(QPaintEvent *e) {
QRect toBeUpdated = e->rect();
painter.setClipRect(toBeUpdated);
int x0 = toBeUpdated.left();
int x1 = toBeUpdated.right();
// visible columns range
int c0 = getViewer()->xToColumn(x0);
int c1 = getViewer()->xToColumn(x1);
CellRange visible = getViewer()->xyRectToRange(toBeUpdated);
int c0 = visible.from().layer();
int c1 = visible.to().layer();
if (c0 > c1) return;
@ -264,7 +262,8 @@ void FunctionSheetColumnHeadViewer::paintEvent(QPaintEvent *e) {
FunctionTreeModel::ChannelGroup *currentGroup = 0;
/*--- 表示範囲左右1カラムの範囲で、ChannelGroupを格納。無ければ0を入れる
/*--- Display range + right and left 1 column range ChannelGroup. If there is
* none, put 0
* ---*/
std::vector<FunctionTreeModel::ChannelGroup *> channelGroups(n);
for (int i = 0; i < n; ++i) {
@ -281,11 +280,11 @@ void FunctionSheetColumnHeadViewer::paintEvent(QPaintEvent *e) {
}
int y0 = 0;
int y1 = 17;
int y1 = 17; // needs work
int y2 = 34;
int y3 = 53;
/*--- Channelの有る範囲内を明るめのグレーで塗る ---*/
/*--- Fill header with background color ---*/
for (int c = c0; c <= c1; c++) {
FunctionTreeModel::Channel *channel = m_sheet->getChannel(c);
if (!channel) continue;
@ -301,16 +300,18 @@ void FunctionSheetColumnHeadViewer::paintEvent(QPaintEvent *e) {
FunctionTreeModel::Channel *channel = m_sheet->getChannel(c);
if (!channel) continue;
int i = c - c0 + 1;
/*---- 現在のColumnと前後のColumnのChannelGroup ---*/
/*---- Channel Column of the current Column and the preceding and following
* Columns ---*/
FunctionTreeModel::ChannelGroup *prevGroup = channelGroups[c - c0],
*group = channelGroups[c - c0 + 1],
*nextGroup = channelGroups[c - c0 + 2];
/*---- 前後とグループが違ってた場合、それぞれフラグを立てる ---*/
/*---- If the group is different from the before and after, flags are set
* respectively ---*/
bool firstGroupColumn = prevGroup != group;
bool lastGroupColumn = nextGroup != group;
/*--- 現在のカラムの左右座標 ---*/
/*--- The left and right coordinates of the current column ---*/
int x0 = getViewer()->columnToX(c);
int x1 = getViewer()->columnToX(c + 1) - 1;
// Column width
@ -380,7 +381,7 @@ void FunctionSheetColumnHeadViewer::mouseMoveEvent(QMouseEvent *e) {
}
// get the column under the cursor
int col = getViewer()->xToColumn(e->pos().x());
int col = getViewer()->xyToPosition(e->pos()).layer();
FunctionTreeModel::Channel *channel = m_sheet->getChannel(col);
if (!channel) {
setToolTip(QString(""));
@ -392,7 +393,7 @@ void FunctionSheetColumnHeadViewer::mouseMoveEvent(QMouseEvent *e) {
void FunctionSheetColumnHeadViewer::mousePressEvent(QMouseEvent *e) {
QPoint pos = e->pos();
int currentC = getViewer()->xToColumn(pos.x());
int currentC = getViewer()->xyToPosition(pos).layer();
FunctionTreeModel::Channel *channel;
for (int c = 0; c <= m_sheet->getChannelCount(); c++) {
channel = m_sheet->getChannel(c);
@ -428,7 +429,7 @@ void FunctionSheetColumnHeadViewer::mousePressEvent(QMouseEvent *e) {
void FunctionSheetColumnHeadViewer::contextMenuEvent(QContextMenuEvent *ce) {
// First, select column under cursor
const QPoint &pos = ce->pos();
int cursorCol = getViewer()->xToColumn(pos.x());
int cursorCol = getViewer()->xyToPosition(pos).layer();
if (cursorCol < 0 || cursorCol >= m_sheet->getChannelCount()) return;
@ -510,10 +511,11 @@ FunctionSheetCellViewer::FunctionSheetCellViewer(FunctionSheet *parent)
/*! Called when the cell panel is left/right-clicked
*/
Spreadsheet::DragTool *FunctionSheetCellViewer::createDragTool(QMouseEvent *e) {
int row = getViewer()->yToRow(e->pos().y());
int col = getViewer()->xToColumn(e->pos().x());
bool isEmpty = true;
TDoubleParam *curve = m_sheet->getCurve(col);
CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
int row = cellPosition.frame();
int col = cellPosition.layer();
bool isEmpty = true;
TDoubleParam *curve = m_sheet->getCurve(col);
if (curve) {
int kCount = curve->getKeyframeCount();
if (kCount > 0) {
@ -665,8 +667,9 @@ void FunctionSheetCellViewer::drawCells(QPainter &painter, int r0, int c0,
//-----------------------------------------------------------------------------
void FunctionSheetCellViewer::mouseDoubleClickEvent(QMouseEvent *e) {
int row = getViewer()->yToRow(e->pos().y());
int col = getViewer()->xToColumn(e->pos().x());
CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
int row = cellPosition.frame();
int col = cellPosition.layer();
int x0, y0, x1, y1;
x0 = getViewer()->columnToX(col);
x1 = getViewer()->columnToX(col + 1) - 1;
@ -737,8 +740,6 @@ void FunctionSheetCellViewer::mousePressEvent(QMouseEvent *e) {
if (e->button() == Qt::LeftButton || e->button() == Qt::MidButton)
Spreadsheet::CellPanel::mousePressEvent(e);
else if (e->button() == Qt::RightButton) {
int row = getViewer()->yToRow(e->pos().y());
int col = getViewer()->xToColumn(e->pos().x());
update();
openContextMenu(e);
}
@ -749,8 +750,9 @@ void FunctionSheetCellViewer::mousePressEvent(QMouseEvent *e) {
void FunctionSheetCellViewer::mouseReleaseEvent(QMouseEvent *e) {
Spreadsheet::CellPanel::mouseReleaseEvent(e);
/*
int row = getViewer()->yToRow(e->pos().y());
int col = getViewer()->xToColumn(e->pos().x());
CellPosition cellPosition = getViewer ()->xyToPosition (e->pos ());
int row = cellPosition.frame ();
int col = cellPosition.layer ();
FunctionSheet::DragTool *dragTool = m_sheet->getDragTool();
if(dragTool) dragTool->release(row,col);
m_sheet->setDragTool(0);
@ -792,9 +794,10 @@ void FunctionSheetCellViewer::openContextMenu(QMouseEvent *e) {
QAction setStep3Action(tr("Step 3"), 0);
QAction setStep4Action(tr("Step 4"), 0);
int row = getViewer()->yToRow(e->pos().y());
int col = getViewer()->xToColumn(e->pos().x());
TDoubleParam *curve = m_sheet->getCurve(col);
CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
int row = cellPosition.frame();
int col = cellPosition.layer();
TDoubleParam *curve = m_sheet->getCurve(col);
if (!curve) return;
bool isEmpty = true;
@ -947,14 +950,14 @@ void FunctionSheet::setSelection(FunctionSelection *selection) {
//-----------------------------------------------------------------------------
void FunctionSheet::showEvent(QShowEvent *e) {
registerFrameScroller();
m_frameScroller.registerFrameScroller();
SpreadsheetViewer::showEvent(e);
}
//-----------------------------------------------------------------------------
void FunctionSheet::hideEvent(QHideEvent *e) {
unregisterFrameScroller();
m_frameScroller.unregisterFrameScroller();
SpreadsheetViewer::hideEvent(e);
}

View file

@ -4,6 +4,7 @@
#include "toonzqt/gutil.h"
#include "toonz/tframehandle.h"
#include "orientation.h"
#include <QKeyEvent>
#include <QWheelEvent>
@ -21,60 +22,109 @@
namespace Spreadsheet {
//=============================================================================
FrameScroller::FrameScroller() {}
FrameScroller::FrameScroller()
: m_orientation(Orientations::topToBottom())
, m_scrollArea(nullptr)
, m_lastX(0)
, m_lastY(0)
,m_syncing(false){}
FrameScroller::~FrameScroller() {}
void FrameScroller::connectScroller(FrameScroller *scroller) {
if (scroller != this && !m_connectedScrollers.contains(scroller)) {
m_connectedScrollers.append(scroller);
scroller->connectScroller(this);
QScrollBar *sb0 = getFrameScrollArea()->verticalScrollBar();
QScrollBar *sb1 = scroller->getFrameScrollArea()->verticalScrollBar();
QObject::connect(sb0, SIGNAL(valueChanged(int)), sb1, SLOT(setValue(int)));
QObject::connect(sb1, SIGNAL(valueChanged(int)), sb0, SLOT(setValue(int)));
}
void FrameScroller::setFrameScrollArea(QScrollArea *scrollArea) {
disconnectScrollbars();
m_scrollArea = scrollArea;
connectScrollbars();
}
void FrameScroller::disconnectScroller(FrameScroller *scroller) {
if (m_connectedScrollers.contains(scroller)) {
m_connectedScrollers.removeAll(scroller);
scroller->disconnectScroller(this);
QScrollBar *sb0 = getFrameScrollArea()->verticalScrollBar();
QScrollBar *sb1 = scroller->getFrameScrollArea()->verticalScrollBar();
QObject::disconnect(sb0, SIGNAL(valueChanged(int)), sb1,
SLOT(setValue(int)));
QObject::disconnect(sb1, SIGNAL(valueChanged(int)), sb0,
SLOT(setValue(int)));
}
void FrameScroller::disconnectScrollbars() {
if (!m_scrollArea) return;
disconnect(m_scrollArea->verticalScrollBar(), &QScrollBar::valueChanged, this,
&FrameScroller::onVScroll);
disconnect(m_scrollArea->horizontalScrollBar(), &QScrollBar::valueChanged,
this, &FrameScroller::onHScroll);
}
bool FrameScroller::isScrollerConnected(FrameScroller *scroller) {
return m_connectedScrollers.contains(scroller);
void FrameScroller::connectScrollbars() {
if (!m_scrollArea) return;
m_lastX = m_scrollArea->horizontalScrollBar()->value();
m_lastY = m_scrollArea->verticalScrollBar()->value();
connect(m_scrollArea->verticalScrollBar(), &QScrollBar::valueChanged, this,
&FrameScroller::onVScroll);
connect(m_scrollArea->horizontalScrollBar(), &QScrollBar::valueChanged, this,
&FrameScroller::onHScroll);
}
void FrameScroller::onVScroll(int y) {
QPoint offset(0, y - m_lastY);
if (isSyncing()) return;
m_lastY = y;
setSyncing(true);
handleScroll(offset);
setSyncing(false);
}
void FrameScroller::onHScroll(int x) {
QPoint offset(x - m_lastX, 0);
if (isSyncing()) return;
m_lastX = x;
setSyncing(true);
handleScroll(offset);
setSyncing(false);
}
static QList<FrameScroller *> frameScrollers;
void FrameScroller::handleScroll(const QPoint &offset) const {
CellPositionRatio ratio = orientation()->xyToPositionRatio(offset);
if( (m_orientation->isVerticalTimeline() && offset.x())
|| (!m_orientation->isVerticalTimeline() && offset.y())) // only synchronize changes by frames axis
return;
for (int i = 0; i < frameScrollers.size(); i++)
if (frameScrollers[i] != this)
{
if (!frameScrollers[i]->isSyncing())
{
frameScrollers[i]->onScroll(ratio);
break;
}
}
}
void adjustScrollbar(QScrollBar *scrollBar, int add);
void FrameScroller::onScroll(const CellPositionRatio &ratio) {
QPoint offset = orientation()->positionRatioToXY(ratio);
if (offset.x())
adjustScrollbar(m_scrollArea->horizontalScrollBar(),
offset.x());
if (offset.y())
adjustScrollbar(m_scrollArea->verticalScrollBar(),
offset.y());
emit prepareToScrollOffset(offset);
}
void adjustScrollbar(QScrollBar *scrollBar, int add) {
scrollBar->setValue(scrollBar->value() + add);
}
void FrameScroller::registerFrameScroller() {
if (!frameScrollers.contains(this)) {
for (int i = 0; i < frameScrollers.size(); i++)
connectScroller(frameScrollers[i]);
frameScrollers.append(this);
}
if (!frameScrollers.contains(this)) frameScrollers.append(this);
}
void FrameScroller::unregisterFrameScroller() {
if (frameScrollers.contains(this)) {
frameScrollers.removeAll(this);
for (int i = 0; i < frameScrollers.size(); i++)
disconnectScroller(frameScrollers[i]);
}
if (frameScrollers.contains(this)) frameScrollers.removeAll(this);
}
void FrameScroller::prepareToScroll(int dy) {
if (dy == 0) return;
void FrameScroller::prepareToScrollOthers(const QPoint &offset) {
CellPositionRatio ratio = orientation()->xyToPositionRatio(offset);
for (int i = 0; i < frameScrollers.size(); i++)
if (frameScrollers[i] != this) frameScrollers[i]->onPrepareToScroll(dy);
if (frameScrollers[i] != this)
frameScrollers[i]->prepareToScrollRatio(ratio);
}
void FrameScroller::prepareToScrollRatio(const CellPositionRatio &ratio) {
QPoint offset = orientation()->positionRatioToXY(ratio);
emit prepareToScrollOffset(offset);
}
//=============================================================================
@ -188,14 +238,16 @@ void GenericPanel::mousePressEvent(QMouseEvent *e) {
else
m_dragTool = createDragTool(e);
int row = getViewer()->yToRow(e->pos().y());
int col = getViewer()->xToColumn(e->pos().x());
CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
int row = cellPosition.frame();
int col = cellPosition.layer();
if (m_dragTool) m_dragTool->click(row, col, e);
}
void GenericPanel::mouseReleaseEvent(QMouseEvent *e) {
int row = getViewer()->yToRow(e->pos().y());
int col = getViewer()->xToColumn(e->pos().x());
CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
int row = cellPosition.frame();
int col = cellPosition.layer();
m_viewer->stopAutoPan();
if (m_dragTool) {
m_dragTool->release(row, col, e);
@ -205,8 +257,9 @@ void GenericPanel::mouseReleaseEvent(QMouseEvent *e) {
}
void GenericPanel::mouseMoveEvent(QMouseEvent *e) {
int row = getViewer()->yToRow(e->pos().y());
int col = getViewer()->xToColumn(e->pos().x());
CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
int row = cellPosition.frame();
int col = cellPosition.layer();
if (e->buttons() != 0 && m_dragTool != 0) {
if ((e->buttons() & Qt::LeftButton) != 0 &&
!visibleRegion().contains(e->pos())) {
@ -289,9 +342,10 @@ void RowPanel::paintEvent(QPaintEvent *e) {
QRect toBeUpdated = e->rect();
QPainter p(this);
// range di righe visibili
int r0 = getViewer()->yToRow(toBeUpdated.top());
int r1 = getViewer()->yToRow(toBeUpdated.bottom());
CellRange visible = getViewer()->xyRectToRange(toBeUpdated);
// range of visible rows
int r0 = visible.from().frame();
int r1 = visible.to().frame();
p.setClipRect(toBeUpdated);
p.fillRect(toBeUpdated, QBrush(getViewer()->getLightLightBGColor()));
@ -324,13 +378,15 @@ void CellPanel::paintEvent(QPaintEvent *e) {
int y0 = toBeUpdated.top();
int x1 = toBeUpdated.right(), y1 = toBeUpdated.bottom();
QRect alteredRect(QPoint(x0, y0), QPoint(x1, y1));
CellRange cellRange = getViewer()->xyRectToRange(alteredRect);
// visible rows range
int r0 = getViewer()->yToRow(y0);
int r1 = getViewer()->yToRow(y1);
int r0 = cellRange.from().frame();
int r1 = cellRange.to().frame();
// visible columns range
int c0 = getViewer()->xToColumn(x0);
int c1 = getViewer()->xToColumn(x1);
int c0 = cellRange.from().layer();
int c1 = cellRange.to().layer();
// cambia colore alle celle prima di rowCount()
int rowCount = getViewer()->getRowCount();
@ -389,7 +445,10 @@ SpreadsheetViewer::SpreadsheetViewer(QWidget *parent)
, m_currentRow(0)
, m_markRowDistance(6)
, m_markRowOffset(0)
, m_isComputingSize(false) {
, m_isComputingSize(false)
, m_frameScroller() {
// m_orientation = Orientations::topToBottom ();
setFocusPolicy(Qt::NoFocus);
setFrameStyle(QFrame::StyledPanel);
@ -427,6 +486,10 @@ SpreadsheetViewer::SpreadsheetViewer(QWidget *parent)
m_columnScrollArea->setFixedHeight(m_rowHeight * 3 - 3);
// m_columnScrollArea->setFixedHeight(m_rowHeight * 3 + 60 - 63);
m_frameScroller.setFrameScrollArea(m_cellScrollArea);
connect(&m_frameScroller, &Spreadsheet::FrameScroller::prepareToScrollOffset,
this, &SpreadsheetViewer::onPrepareToScrollOffset);
//---- layout
QGridLayout *layout = new QGridLayout();
layout->setMargin(0);
@ -520,7 +583,6 @@ void SpreadsheetViewer::setColumnCount(int columnCount) {
void SpreadsheetViewer::scroll(QPoint delta) {
int x = delta.x();
int y = delta.y();
prepareToScroll(y);
QScrollBar *hSc = m_cellScrollArea->horizontalScrollBar();
QScrollBar *vSc = m_cellScrollArea->verticalScrollBar();
@ -547,6 +609,10 @@ void SpreadsheetViewer::scroll(QPoint delta) {
vSc->setValue(valueV);
}
void SpreadsheetViewer::onPrepareToScrollOffset(const QPoint &offset) {
refreshContentSize(offset.x(), offset.y());
}
void SpreadsheetViewer::setAutoPanSpeed(const QPoint &speed) {
bool wasAutoPanning = isAutoPanning();
m_autoPanSpeed = speed;
@ -583,21 +649,42 @@ void SpreadsheetViewer::setAutoPanSpeed(const QRect &widgetBounds,
m_lastAutoPanPos = mousePos;
}
/*!Shift is a consequence of style sheet border.*/
int SpreadsheetViewer::xToColumn(int x) const {
return (x + 1) / m_columnWidth;
CellPosition pos = xyToPosition(QPoint(x, 0));
return pos.layer();
}
int SpreadsheetViewer::yToRow(int y) const {
CellPosition pos = xyToPosition(QPoint(0, y));
return pos.frame();
}
/*!Shift is a consequence of style sheet border.*/
int SpreadsheetViewer::columnToX(int col) const {
return (col * m_columnWidth) - 1;
QPoint xy = positionToXY(CellPosition(0, col));
return xy.x();
}
int SpreadsheetViewer::rowToY(int row) const {
QPoint xy = positionToXY(CellPosition(row, 0));
return xy.y();
}
/*!Shift is a consequence of style sheet border.*/
int SpreadsheetViewer::yToRow(int y) const { return (y + 1) / m_rowHeight; }
CellPosition SpreadsheetViewer::xyToPosition(const QPoint &point) const {
int row = (point.y() + 1) / m_rowHeight;
int col = (point.x() + 1) / m_columnWidth;
return CellPosition(row, col);
}
/*!Shift is a consequence of style sheet border.*/
int SpreadsheetViewer::rowToY(int row) const { return (row * m_rowHeight) - 1; }
QPoint SpreadsheetViewer::positionToXY(const CellPosition &pos) const {
int x = (pos.layer() * m_columnWidth) - 1;
int y = (pos.frame() * m_rowHeight) - 1;
return QPoint(x, y);
}
CellRange SpreadsheetViewer::xyRectToRange(const QRect &rect) const {
CellPosition topLeft = xyToPosition(rect.topLeft());
CellPosition bottomRight = xyToPosition(rect.bottomRight());
return CellRange(topLeft, bottomRight);
}
bool SpreadsheetViewer::refreshContentSize(int scrollDx, int scrollDy) {
QSize viewportSize = m_cellScrollArea->viewport()->size();