1 
2 
3 #include "toonzqt/spreadsheetviewer.h"
4 #include "toonzqt/gutil.h"
5 #include "toonz/preferences.h"
6 #include "toonz/toonzfolders.h"
7 #include "toonz/tframehandle.h"
8 #include "orientation.h"
9 
10 #include <QKeyEvent>
11 #include <QWheelEvent>
12 #include <QLabel>
13 #include <QScrollBar>
14 #include <QPainter>
15 #include <QGridLayout>
16 #include <QPaintEvent>
17 #include <QToolTip>
18 #include <assert.h>
19 
20 #include <QMainWindow>
21 #include <QDockWidget>
22 #include <QSettings>
23 
24 namespace Spreadsheet {
25 
26 //=============================================================================
FrameScroller()27 FrameScroller::FrameScroller()
28     : m_orientation(Orientations::topToBottom())
29     , m_scrollArea(nullptr)
30     , m_lastX(0)
31     , m_lastY(0)
32     , m_syncing(false) {}
33 
~FrameScroller()34 FrameScroller::~FrameScroller() {}
35 
setFrameScrollArea(QScrollArea * scrollArea)36 void FrameScroller::setFrameScrollArea(QScrollArea *scrollArea) {
37   disconnectScrollbars();
38   m_scrollArea = scrollArea;
39   connectScrollbars();
40 }
41 
disconnectScrollbars()42 void FrameScroller::disconnectScrollbars() {
43   if (!m_scrollArea) return;
44   disconnect(m_scrollArea->verticalScrollBar(), &QScrollBar::valueChanged, this,
45              &FrameScroller::onVScroll);
46   disconnect(m_scrollArea->horizontalScrollBar(), &QScrollBar::valueChanged,
47              this, &FrameScroller::onHScroll);
48 }
49 
connectScrollbars()50 void FrameScroller::connectScrollbars() {
51   if (!m_scrollArea) return;
52   m_lastX = m_scrollArea->horizontalScrollBar()->value();
53   m_lastY = m_scrollArea->verticalScrollBar()->value();
54   connect(m_scrollArea->verticalScrollBar(), &QScrollBar::valueChanged, this,
55           &FrameScroller::onVScroll);
56   connect(m_scrollArea->horizontalScrollBar(), &QScrollBar::valueChanged, this,
57           &FrameScroller::onHScroll);
58 }
59 
onVScroll(int y)60 void FrameScroller::onVScroll(int y) {
61   QPoint offset(0, y - m_lastY);
62   if (isSyncing()) return;
63   m_lastY = y;
64   setSyncing(true);
65   handleScroll(offset);
66   setSyncing(false);
67 }
onHScroll(int x)68 void FrameScroller::onHScroll(int x) {
69   QPoint offset(x - m_lastX, 0);
70   if (isSyncing()) return;
71   m_lastX = x;
72   setSyncing(true);
73   handleScroll(offset);
74   setSyncing(false);
75 }
76 
77 static QList<FrameScroller *> frameScrollers;
78 
handleScroll(QPoint & offset)79 void FrameScroller::handleScroll(QPoint &offset) {
80   if ((m_orientation->isVerticalTimeline() && offset.x()) ||
81       (!m_orientation->isVerticalTimeline() &&
82        offset.y()))  // only synchronize changes by frames axis
83     return;
84 
85   // In case of a zoomed viewer is sending this out, adjust the
86   // zoomed offset back to a standardized offset
87   emit zoomScrollAdjust(offset, false);
88 
89   CellPositionRatio ratio = orientation()->xyToPositionRatio(offset);
90 
91   for (int i = 0; i < frameScrollers.size(); i++)
92     if (frameScrollers[i] != this) {
93       if (!frameScrollers[i]->isSyncing()) {
94         frameScrollers[i]->onScroll(ratio);
95         break;
96       }
97     }
98 }
99 
100 void adjustScrollbar(QScrollBar *scrollBar, int add);
101 
onScroll(const CellPositionRatio & ratio)102 void FrameScroller::onScroll(const CellPositionRatio &ratio) {
103   QPoint offset = orientation()->positionRatioToXY(ratio);
104 
105   // In case of a zoomed viewer is receiving this, adjust the
106   // standardized offset to zoomed offset
107   emit zoomScrollAdjust(offset, true);
108 
109   // scroll area should be resized before moving down the scroll bar.
110   // SpreadsheetViewer::onPrepareToScrollOffset() will be invoked immediately
111   // since the receiver is in the same thread.
112   // when moving up the scroll bar, resizing will be done in
113   // SpreadsheetViewer::onVSliderChanged().
114   if (offset.x() > 0 || offset.y() > 0) emit prepareToScrollOffset(offset);
115   if (offset.x())
116     adjustScrollbar(m_scrollArea->horizontalScrollBar(), offset.x());
117   if (offset.y())
118     adjustScrollbar(m_scrollArea->verticalScrollBar(), offset.y());
119 }
120 
adjustScrollbar(QScrollBar * scrollBar,int add)121 void adjustScrollbar(QScrollBar *scrollBar, int add) {
122   scrollBar->setValue(scrollBar->value() + add);
123 }
124 
registerFrameScroller()125 void FrameScroller::registerFrameScroller() {
126   if (!frameScrollers.contains(this)) frameScrollers.append(this);
127 }
128 
unregisterFrameScroller()129 void FrameScroller::unregisterFrameScroller() {
130   if (frameScrollers.contains(this)) frameScrollers.removeAll(this);
131 }
132 
prepareToScrollOthers(const QPoint & offset)133 void FrameScroller::prepareToScrollOthers(const QPoint &offset) {
134   CellPositionRatio ratio = orientation()->xyToPositionRatio(offset);
135   for (int i = 0; i < frameScrollers.size(); i++)
136     if (frameScrollers[i] != this)
137       frameScrollers[i]->prepareToScrollRatio(ratio);
138 }
prepareToScrollRatio(const CellPositionRatio & ratio)139 void FrameScroller::prepareToScrollRatio(const CellPositionRatio &ratio) {
140   QPoint offset = orientation()->positionRatioToXY(ratio);
141   emit prepareToScrollOffset(offset);
142 }
143 
144 //=============================================================================
145 
click(int row,int col,QMouseEvent * e)146 void SetFrameDragTool::click(int row, int col, QMouseEvent *e) {
147   m_frameHandle->setFrame(row);
148 }
149 
drag(int row,int col,QMouseEvent * e)150 void SetFrameDragTool::drag(int row, int col, QMouseEvent *e) {
151   if (row < 0) row = 0;
152   m_frameHandle->setFrame(row);
153 }
154 
release(int row,int col,QMouseEvent * e)155 void SetFrameDragTool::release(int row, int col, QMouseEvent *e) {}
156 
157 //=============================================================================
158 //
159 // SelectionDragTool
160 //
161 //-----------------------------------------------------------------------------
162 
SelectionDragTool(SpreadsheetViewer * viewer)163 SelectionDragTool::SelectionDragTool(SpreadsheetViewer *viewer)
164     : m_viewer(viewer), m_firstRow(-1), m_firstCol(-1) {}
165 
click(int row,int col,QMouseEvent * e)166 void SelectionDragTool::click(int row, int col, QMouseEvent *e) {
167   m_firstCol = col;
168   m_firstRow = row;
169   QRect selectedCells(col, row, 1, 1);
170   m_viewer->selectCells(selectedCells);
171 }
172 
drag(int row,int col,QMouseEvent * e)173 void SelectionDragTool::drag(int row, int col, QMouseEvent *e) {
174   int r0 = std::min(row, m_firstRow);
175   int r1 = std::max(row, m_firstRow);
176   int c0 = std::min(col, m_firstCol);
177   int c1 = std::max(col, m_firstCol);
178   QRect selectedCells(c0, r0, c1 - c0 + 1, r1 - r0 + 1);
179   m_viewer->selectCells(selectedCells);
180 }
181 
release(int row,int col,QMouseEvent * e)182 void SelectionDragTool::release(int row, int col, QMouseEvent *e) {}
183 
184 //=============================================================================
185 
PanTool(Spreadsheet::GenericPanel * panel)186 PanTool::PanTool(Spreadsheet::GenericPanel *panel)
187     : m_panel(panel), m_viewer(panel->getViewer()), m_lastPos() {}
188 
click(int row,int col,QMouseEvent * e)189 void PanTool::click(int row, int col, QMouseEvent *e) {
190   m_lastPos = e->pos();  // m_panel->mapToGlobal(e->pos());
191 }
drag(int row,int col,QMouseEvent * e)192 void PanTool::drag(int row, int col, QMouseEvent *e) {
193   QPoint pos = e->pos();  // m_panel->mapToGlobal(e->pos());
194   // QPoint delta = p - m_lastPos;
195   // m_lastPos = p;
196   // QToolTip::showText(p,"delta="+QString::number(delta.x())+","+QString::number(delta.y()));
197   m_viewer->scroll(m_lastPos - pos);
198 }
release(int row,int col,QMouseEvent * e)199 void PanTool::release(int row, int col, QMouseEvent *e) {
200   // QToolTip::hideText();
201 }
202 
203 //=============================================================================
204 
205 #if QT_VERSION >= 0x050500
ScrollArea(QWidget * parent,Qt::WindowFlags flags)206 ScrollArea::ScrollArea(QWidget *parent, Qt::WindowFlags flags)
207 #else
208 ScrollArea::ScrollArea(QWidget *parent, Qt::WFlags flags)
209 #endif
210     : QScrollArea(parent) {
211   setFrameStyle(QFrame::Panel | QFrame::Raised);
212   setLineWidth(6);
213   setContentsMargins(10, 10, 10, 10);
214 }
215 
~ScrollArea()216 ScrollArea::~ScrollArea() {}
217 
keyPressEvent(QKeyEvent * e)218 void ScrollArea::keyPressEvent(QKeyEvent *e) { e->ignore(); }
219 
wheelEvent(QWheelEvent * e)220 void ScrollArea::wheelEvent(QWheelEvent *e) { e->ignore(); }
221 
222 //=============================================================================
223 
GenericPanel(SpreadsheetViewer * viewer)224 GenericPanel::GenericPanel(SpreadsheetViewer *viewer)
225     : QWidget(viewer), m_viewer(viewer), m_dragTool(0) {
226   setFocusPolicy(Qt::NoFocus);
227 }
228 
~GenericPanel()229 GenericPanel::~GenericPanel() {}
230 
paintEvent(QPaintEvent * e)231 void GenericPanel::paintEvent(QPaintEvent *e) {
232   QPainter p(this);
233   p.setPen(m_viewer->getLightLineColor());
234   for (int c = 0;; c++) {
235     int x = getViewer()->columnToX(c);
236     if (x > width()) break;
237     p.drawLine(x, 0, x, height());
238   }
239   for (int r = 0;; r++) {
240     int y = getViewer()->rowToY(r);
241     if (y > height()) break;
242     p.drawLine(0, y, width(), y);
243   }
244   p.setPen(Qt::magenta);
245   p.drawLine(e->rect().topLeft(), e->rect().bottomRight());
246 }
247 
mousePressEvent(QMouseEvent * e)248 void GenericPanel::mousePressEvent(QMouseEvent *e) {
249   assert(!m_dragTool);
250   if (e->button() == Qt::MidButton)
251     m_dragTool = new PanTool(this);
252   else
253     m_dragTool = createDragTool(e);
254 
255   CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
256   int row                   = cellPosition.frame();
257   int col                   = cellPosition.layer();
258   if (m_dragTool) m_dragTool->click(row, col, e);
259 }
260 
mouseReleaseEvent(QMouseEvent * e)261 void GenericPanel::mouseReleaseEvent(QMouseEvent *e) {
262   CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
263   int row                   = cellPosition.frame();
264   int col                   = cellPosition.layer();
265   m_viewer->stopAutoPan();
266   if (m_dragTool) {
267     m_dragTool->release(row, col, e);
268     delete m_dragTool;
269     m_dragTool = 0;
270   }
271 }
272 
mouseMoveEvent(QMouseEvent * e)273 void GenericPanel::mouseMoveEvent(QMouseEvent *e) {
274   CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
275   int row                   = cellPosition.frame();
276   int col                   = cellPosition.layer();
277   if (e->buttons() != 0 && m_dragTool != 0) {
278     if ((e->buttons() & Qt::LeftButton) != 0 &&
279         !visibleRegion().contains(e->pos())) {
280       QRect bounds = visibleRegion().boundingRect();
281       m_viewer->setAutoPanSpeed(bounds, e->pos());
282     } else
283       m_viewer->stopAutoPan();
284     m_dragTool->drag(row, col, e);
285   }
286 }
287 
288 //=============================================================================
289 
RowPanel(SpreadsheetViewer * viewer)290 RowPanel::RowPanel(SpreadsheetViewer *viewer)
291     : GenericPanel(viewer), m_xa(12) {}
292 
293 //-----------------------------------------------------------------------------
294 
createDragTool(QMouseEvent *)295 DragTool *RowPanel::createDragTool(QMouseEvent *) {
296   TFrameHandle *frameHandle = getViewer()->getFrameHandle();
297   if (frameHandle)
298     return new SetFrameDragTool(frameHandle);
299   else
300     return 0;
301 }
302 
303 //-----------------------------------------------------------------------------
304 
drawRows(QPainter & p,int r0,int r1)305 void RowPanel::drawRows(QPainter &p, int r0, int r1) {
306   QString fontName = Preferences::instance()->getInterfaceFont();
307   if (fontName == "") {
308 #ifdef _WIN32
309     fontName = "Arial";
310 #else
311     fontName = "Helvetica";
312 #endif
313   }
314   static QFont font(fontName, -1, QFont::Bold);
315   font.setPixelSize(12);
316   p.setFont(font);
317 
318   QRect visibleRect = visibleRegion().boundingRect();
319   int x0            = visibleRect.left();
320   int x1            = visibleRect.right();
321   int y0            = visibleRect.top();
322   int y1            = visibleRect.bottom();
323 
324   int r;
325   for (r = r0; r <= r1; r++) {
326     int y = getViewer()->rowToY(r);
327     // draw horizontal line
328     QColor color = (getViewer()->isMarkRow(r))
329                        ? getViewer()->getMarkerLineColor()
330                        : getViewer()->getLightLineColor();
331     p.setPen(color);
332     p.drawLine(x0, y, x1, y);
333 
334     // draw numbers
335     p.setPen(getViewer()->getTextColor());
336 
337     QString number = QString::number(r + 1);
338     p.drawText(QRect(x0, y + 1, width(), 18),
339                Qt::AlignHCenter | Qt::AlignBottom, number);
340   }
341   // erase the marker interval at upper-end
342   if (r0 == 0) {
343     p.setPen(getViewer()->getLightLineColor());
344     p.drawLine(x0, getViewer()->rowToY(0), x1, getViewer()->rowToY(0));
345   }
346 }
347 
348 //-----------------------------------------------------------------------------
349 
drawCurrentRowGadget(QPainter & p,int r0,int r1)350 void RowPanel::drawCurrentRowGadget(QPainter &p, int r0, int r1) {
351   int currentRow = getViewer()->getCurrentRow();
352   int y          = getViewer()->rowToY(currentRow);
353   if (currentRow < r0 || r1 < currentRow) return;
354   p.fillRect(1, y + 1, width() - 1, 19, getViewer()->getCurrentRowBgColor());
355 }
356 
357 //-----------------------------------------------------------------------------
358 
paintEvent(QPaintEvent * e)359 void RowPanel::paintEvent(QPaintEvent *e) {
360   QRect toBeUpdated = e->rect();
361   QPainter p(this);
362 
363   CellRange visible = getViewer()->xyRectToRange(toBeUpdated);
364   // range of visible rows
365   int r0 = visible.from().frame();
366   int r1 = visible.to().frame();
367 
368   p.setClipRect(toBeUpdated);
369   p.fillRect(toBeUpdated, QBrush(getViewer()->getLightLightBGColor()));
370 
371   drawCurrentRowGadget(p, r0, r1);
372   drawRows(p, r0, r1);
373 }
374 
375 //=============================================================================
376 
ColumnPanel(SpreadsheetViewer * viewer)377 ColumnPanel::ColumnPanel(SpreadsheetViewer *viewer) : GenericPanel(viewer) {}
378 
379 //=============================================================================
380 
CellPanel(SpreadsheetViewer * viewer)381 CellPanel::CellPanel(SpreadsheetViewer *viewer) : GenericPanel(viewer) {}
382 
createDragTool(QMouseEvent *)383 DragTool *CellPanel::createDragTool(QMouseEvent *) {
384   // FunctionSheetCellViewer::createDragTool is called instead
385   // when clicking on the CellPanel in NumericalColumns
386   return new SelectionDragTool(getViewer());
387 }
388 
paintEvent(QPaintEvent * e)389 void CellPanel::paintEvent(QPaintEvent *e) {
390   QPainter painter(this);
391 
392   QRect toBeUpdated = e->rect();
393   painter.setClipRect(toBeUpdated);
394 
395   int x0 = toBeUpdated.left() - 1;
396   int y0 = toBeUpdated.top();
397   int x1 = toBeUpdated.right(), y1 = toBeUpdated.bottom();
398 
399   QRect alteredRect(QPoint(x0, y0), QPoint(x1, y1));
400   CellRange cellRange = getViewer()->xyRectToRange(alteredRect);
401   // visible rows range
402   int r0 = cellRange.from().frame();
403   int r1 = cellRange.to().frame();
404 
405   // visible columns range
406   int c0 = cellRange.from().layer();
407   int c1 = cellRange.to().layer();
408 
409   // cambia colore alle celle prima di rowCount()
410   int rowCount = getViewer()->getRowCount();
411 
412   // fill with bg color
413   painter.fillRect(toBeUpdated, getViewer()->getLightLightBGColor());
414 
415   // scene range bg
416   int yLast = getViewer()->rowToY(rowCount);
417   if (yLast < y1)
418     painter.fillRect(x0, y0, x1 - x0, yLast - y0, getViewer()->getBGColor());
419   else
420     painter.fillRect(toBeUpdated, getViewer()->getBGColor());
421 
422   // draw cells
423   drawCells(painter, r0, c0, r1, c1);
424 
425   // draw columns
426   painter.setPen(getViewer()->getVerticalLineColor());
427   for (int col = c0; col <= c1; col++) {
428     int x = getViewer()->columnToX(col);
429     painter.drawLine(x, y0, x, y1);
430   }
431 
432   // draw rows
433   int currentRow = getViewer()->getCurrentRow();
434   for (int r = r0; r <= r1; r++) {
435     int y        = getViewer()->rowToY(r);
436     QColor color = getViewer()->isMarkRow(r) ? getViewer()->getMarkerLineColor()
437                                              : getViewer()->getLightLineColor();
438     painter.setPen(color);
439     painter.drawLine(x0, y, x1, y);
440   }
441   // erase the marker interval at upper-end
442   painter.setPen(getViewer()->getLightLineColor());
443   painter.drawLine(x0, 0, x1, 0);
444 }
445 
446 }  // namespace Spreadsheet
447 
448 //=============================================================================
449 
SpreadsheetViewer(QWidget * parent)450 SpreadsheetViewer::SpreadsheetViewer(QWidget *parent)
451     : QDialog(parent)
452     , m_columnScrollArea(0)
453     , m_rowScrollArea(0)
454     , m_cellScrollArea(0)
455     , m_frameHandle(0)
456     , m_columnWidth(50)
457     , m_rowHeight(20)
458     , m_timerId(0)
459     , m_autoPanSpeed(0, 0)
460     , m_lastAutoPanPos(0, 0)
461     , m_rowCount(0)
462     , m_columnCount(0)
463     , m_currentRow(0)
464     , m_markRowDistance(6)
465     , m_markRowOffset(0)
466     , m_isComputingSize(false)
467     , m_frameScroller() {
468   // m_orientation = Orientations::topToBottom ();
469 
470   setFocusPolicy(Qt::NoFocus);
471 
472   // setFrameStyle(QFrame::StyledPanel);
473   setObjectName("Viewer");
474 
475   // column header
476   m_columnScrollArea = new Spreadsheet::ScrollArea;
477   m_columnScrollArea->setObjectName("ScrollColumnArea");
478   m_columnScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
479   m_columnScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
480   m_columnScrollArea->setFocusPolicy(Qt::NoFocus);
481 
482   // row area
483   m_rowScrollArea = new Spreadsheet::ScrollArea;
484   m_rowScrollArea->setObjectName("ScrollRowArea");
485   m_rowScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
486   m_rowScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
487   m_rowScrollArea->setFocusPolicy(Qt::NoFocus);
488 
489   // cell area
490   m_cellScrollArea = new Spreadsheet::ScrollArea;
491   m_cellScrollArea->setObjectName("ScrollCellArea");
492   m_cellScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
493   m_cellScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
494   // m_cellScrollArea->horizontalScrollBar()->setObjectName("XsheetScrollBar");
495   // m_cellScrollArea->verticalScrollBar()->setObjectName("XsheetScrollBar");
496   m_cellScrollArea->setFocusPolicy(Qt::NoFocus);
497 
498   m_columnScrollArea->setSizePolicy(
499       QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed));
500   m_rowScrollArea->setSizePolicy(
501       QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored));
502 
503   m_rowScrollArea->setFixedWidth(30);
504   m_columnScrollArea->setFixedHeight(m_rowHeight * 3 - 3);
505   // m_columnScrollArea->setFixedHeight(m_rowHeight * 3 + 60 - 63);
506 
507   m_frameScroller.setFrameScrollArea(m_cellScrollArea);
508   connect(&m_frameScroller, &Spreadsheet::FrameScroller::prepareToScrollOffset,
509           this, &SpreadsheetViewer::onPrepareToScrollOffset);
510 
511   //---- layout
512   QGridLayout *layout = new QGridLayout();
513   layout->setMargin(0);
514   layout->setSpacing(0);
515   {
516     layout->addWidget(m_columnScrollArea, 0, 1);
517     layout->addWidget(m_rowScrollArea, 1, 0);
518     layout->addWidget(m_cellScrollArea, 1, 1, 2, 2);
519 
520     int scrollBarWidth = 16;
521     // upper-right
522     QWidget *w = new QWidget(this);
523     w->setFixedSize(QSize(scrollBarWidth, m_rowHeight * 3 + 60 - 63));
524     layout->addWidget(w, 0, 2);
525 
526     // lower-left
527     w = new QWidget(this);
528     w->setFixedSize(QSize(30, scrollBarWidth));
529     layout->addWidget(w, 2, 0);
530 
531     layout->setColumnStretch(0, 0);
532     layout->setColumnStretch(1, 1);
533     layout->setColumnStretch(2, 0);
534     layout->setRowStretch(0, 0);
535     layout->setRowStretch(1, 1);
536     layout->setRowStretch(2, 0);
537   }
538   setLayout(layout);
539 
540   //---signal-slot connections
541 
542   // vertical slider: cell <=> row
543   connect(m_rowScrollArea->verticalScrollBar(), SIGNAL(valueChanged(int)),
544           m_cellScrollArea->verticalScrollBar(), SLOT(setValue(int)));
545   connect(m_cellScrollArea->verticalScrollBar(), SIGNAL(valueChanged(int)),
546           m_rowScrollArea->verticalScrollBar(), SLOT(setValue(int)));
547 
548   // horizontal slider: cell <=> column
549   connect(m_columnScrollArea->horizontalScrollBar(), SIGNAL(valueChanged(int)),
550           m_cellScrollArea->horizontalScrollBar(), SLOT(setValue(int)));
551   connect(m_cellScrollArea->horizontalScrollBar(), SIGNAL(valueChanged(int)),
552           m_columnScrollArea->horizontalScrollBar(), SLOT(setValue(int)));
553 
554   connect(m_cellScrollArea->verticalScrollBar(), SIGNAL(valueChanged(int)),
555           SLOT(onVSliderChanged(int)));
556   connect(m_cellScrollArea->horizontalScrollBar(), SIGNAL(valueChanged(int)),
557           SLOT(onHSliderChanged(int)));
558 }
559 
~SpreadsheetViewer()560 SpreadsheetViewer::~SpreadsheetViewer() {}
561 
setFrameHandle(TFrameHandle * frameHandle)562 void SpreadsheetViewer::setFrameHandle(TFrameHandle *frameHandle) {
563   if (m_frameHandle == frameHandle) return;
564   if (m_frameHandle) m_frameHandle->disconnect(this);
565   m_frameHandle = frameHandle;
566 
567   if (isVisible() && m_frameHandle) {
568     connect(m_frameHandle, SIGNAL(frameSwitched()), this,
569             SLOT(onFrameSwitched()));
570     update();
571   }
572 }
573 
setRowsPanel(Spreadsheet::RowPanel * rows)574 void SpreadsheetViewer::setRowsPanel(Spreadsheet::RowPanel *rows) {
575   m_rowScrollArea->setWidget(rows);
576 }
577 
setColumnsPanel(Spreadsheet::ColumnPanel * columns)578 void SpreadsheetViewer::setColumnsPanel(Spreadsheet::ColumnPanel *columns) {
579   m_columnScrollArea->setWidget(columns);
580   // columns->setFixedHeight(200);
581 }
582 
setCellsPanel(Spreadsheet::CellPanel * cells)583 void SpreadsheetViewer::setCellsPanel(Spreadsheet::CellPanel *cells) {
584   m_cellScrollArea->setWidget(cells);
585 }
586 
setRowCount(int rowCount)587 void SpreadsheetViewer::setRowCount(int rowCount) {
588   if (m_rowCount != rowCount) {
589     m_rowCount = rowCount;
590     refreshContentSize(0, 0);
591   }
592 }
593 
setColumnCount(int columnCount)594 void SpreadsheetViewer::setColumnCount(int columnCount) {
595   if (m_columnCount != columnCount) {
596     m_columnCount = columnCount;
597     refreshContentSize(0, 0);
598   }
599 }
600 
scroll(QPoint delta)601 void SpreadsheetViewer::scroll(QPoint delta) {
602   int x = delta.x();
603   int y = delta.y();
604 
605   QScrollBar *hSc = m_cellScrollArea->horizontalScrollBar();
606   QScrollBar *vSc = m_cellScrollArea->verticalScrollBar();
607 
608   int valueH    = hSc->value() + x;
609   int valueV    = vSc->value() + y;
610   int maxValueH = hSc->maximum();
611   int maxValueV = vSc->maximum();
612 
613   bool notUpdateSizeH = maxValueH > valueH && x >= 0;
614   bool notUpdateSizeV = maxValueV > valueV && y >= 0;
615   if ((!notUpdateSizeH) && (!notUpdateSizeV))
616     refreshContentSize(x, y);
617   else if (notUpdateSizeH && !notUpdateSizeV)
618     refreshContentSize(0, y);
619   else if (!notUpdateSizeH && notUpdateSizeV)
620     refreshContentSize(x, 0);
621 
622   if (valueH > maxValueH && x > 0) valueH = hSc->maximum();
623 
624   if (valueV > maxValueV && y > 0) valueV = vSc->maximum();
625 
626   hSc->setValue(valueH);
627   vSc->setValue(valueV);
628 }
629 
onPrepareToScrollOffset(const QPoint & offset)630 void SpreadsheetViewer::onPrepareToScrollOffset(const QPoint &offset) {
631   refreshContentSize(offset.x(), offset.y());
632 }
633 
setAutoPanSpeed(const QPoint & speed)634 void SpreadsheetViewer::setAutoPanSpeed(const QPoint &speed) {
635   bool wasAutoPanning = isAutoPanning();
636   m_autoPanSpeed      = speed;
637   if (isAutoPanning() && !wasAutoPanning && m_timerId == 0)
638     m_timerId = startTimer(40);
639   else if (!isAutoPanning() && wasAutoPanning && m_timerId != 0) {
640     killTimer(m_timerId);
641     m_timerId = 0;
642   }
643 }
644 
645 //-----------------------------------------------------------------------------
646 
getAutoPanSpeed(int pixels)647 static int getAutoPanSpeed(int pixels) {
648   int f = 40;
649   return std::min(100, (f - 1 + pixels * f) / 100);
650 }
651 
652 //-----------------------------------------------------------------------------
653 
setAutoPanSpeed(const QRect & widgetBounds,const QPoint & mousePos)654 void SpreadsheetViewer::setAutoPanSpeed(const QRect &widgetBounds,
655                                         const QPoint &mousePos) {
656   QPoint speed;
657   int limit = 100, factor = 30;
658   if (mousePos.x() < widgetBounds.left())
659     speed.setX(-getAutoPanSpeed(widgetBounds.left() - mousePos.x()));
660   else if (mousePos.x() > widgetBounds.right())
661     speed.setX(getAutoPanSpeed(mousePos.x() - widgetBounds.right()));
662   if (mousePos.y() < widgetBounds.top())
663     speed.setY(-getAutoPanSpeed(widgetBounds.top() - mousePos.y()));
664   else if (mousePos.y() > widgetBounds.bottom())
665     speed.setY(getAutoPanSpeed(mousePos.y() - widgetBounds.bottom()));
666   setAutoPanSpeed(speed);
667   m_lastAutoPanPos = mousePos;
668 }
669 
xToColumn(int x) const670 int SpreadsheetViewer::xToColumn(int x) const {
671   CellPosition pos = xyToPosition(QPoint(x, 0));
672   return pos.layer();
673 }
yToRow(int y) const674 int SpreadsheetViewer::yToRow(int y) const {
675   CellPosition pos = xyToPosition(QPoint(0, y));
676   return pos.frame();
677 }
columnToX(int col) const678 int SpreadsheetViewer::columnToX(int col) const {
679   QPoint xy = positionToXY(CellPosition(0, col));
680   return xy.x();
681 }
rowToY(int row) const682 int SpreadsheetViewer::rowToY(int row) const {
683   QPoint xy = positionToXY(CellPosition(row, 0));
684   return xy.y();
685 }
686 
687 /*!Shift is a consequence of style sheet border.*/
xyToPosition(const QPoint & point) const688 CellPosition SpreadsheetViewer::xyToPosition(const QPoint &point) const {
689   int row = (point.y() + 1) / m_rowHeight;
690   int col = (point.x()) / m_columnWidth;
691   return CellPosition(row, col);
692 }
693 
694 /*!Shift is a consequence of style sheet border.*/
positionToXY(const CellPosition & pos) const695 QPoint SpreadsheetViewer::positionToXY(const CellPosition &pos) const {
696   int x = (pos.layer() * m_columnWidth);
697   int y = (pos.frame() * m_rowHeight) - 1;
698   return QPoint(x, y);
699 }
700 
xyRectToRange(const QRect & rect) const701 CellRange SpreadsheetViewer::xyRectToRange(const QRect &rect) const {
702   CellPosition topLeft     = xyToPosition(rect.topLeft());
703   CellPosition bottomRight = xyToPosition(rect.bottomRight());
704   return CellRange(topLeft, bottomRight);
705 }
706 
refreshContentSize(int scrollDx,int scrollDy)707 bool SpreadsheetViewer::refreshContentSize(int scrollDx, int scrollDy) {
708   QSize viewportSize = m_cellScrollArea->viewport()->size();
709   QPoint offset      = m_cellScrollArea->widget()->pos();
710   offset             = QPoint(std::min(0, offset.x() - scrollDx),
711                   std::min(0, offset.y() - scrollDy));
712 
713   QSize contentSize(columnToX(m_columnCount + 1), rowToY(m_rowCount + 1));
714 
715   QSize actualSize(contentSize);
716   int x = viewportSize.width() - offset.x();
717   int y = viewportSize.height() - offset.y();
718   if (x > actualSize.width()) actualSize.setWidth(x);
719   if (y > actualSize.height()) actualSize.setHeight(y);
720 
721   if (actualSize == m_cellScrollArea->widget()->size())
722     return false;
723   else {
724     m_isComputingSize = true;
725     m_cellScrollArea->widget()->setFixedSize(actualSize);
726     m_rowScrollArea->widget()->setFixedSize(
727         m_rowScrollArea->viewport()->width(), actualSize.height());
728     m_columnScrollArea->widget()->setFixedSize(
729         actualSize.width(), m_columnScrollArea->viewport()->height());
730     m_isComputingSize = false;
731     return true;
732   }
733 }
734 
showEvent(QShowEvent *)735 void SpreadsheetViewer::showEvent(QShowEvent *) {
736   int viewportHeight = m_cellScrollArea->height();
737   int contentHeight  = rowToY(m_rowCount * 0 + 50);
738   QScrollBar *vSc    = m_cellScrollArea->verticalScrollBar();
739   int actualContentHeight =
740       std::max(contentHeight, vSc->value() + viewportHeight);
741   m_rowScrollArea->widget()->setFixedHeight(actualContentHeight);
742   m_cellScrollArea->widget()->setFixedHeight(actualContentHeight);
743   if (m_frameHandle)
744     connect(m_frameHandle, SIGNAL(frameSwitched()), this,
745             SLOT(onFrameSwitched()));
746 
747   // updateAreasSize();
748 }
749 
hideEvent(QHideEvent *)750 void SpreadsheetViewer::hideEvent(QHideEvent *) {
751   if (m_frameHandle) m_frameHandle->disconnect(this);
752 }
753 
resizeEvent(QResizeEvent * e)754 void SpreadsheetViewer::resizeEvent(QResizeEvent *e) {
755   QDialog::resizeEvent(e);
756   refreshContentSize(0, 0);
757   /*
758   int w = width();
759   int h = height();
760 
761 int hSpacing = 4;
762 int vSpacing = 4;
763 
764 int x = m_rowScrollAreaWidth + hSpacing;
765 int y = m_columnScrollAreaHeight + vSpacing;
766 
767   m_cellScrollArea->setGeometry(x,y, w-x, h-y);
768 
769 int sh = m_cellScrollArea->horizontalScrollBar()->height();
770 int sw = m_cellScrollArea->verticalScrollBar()->width();
771 
772   m_columnScrollArea->setGeometry(x, 0, w-x-sw, m_columnScrollAreaHeight);
773 m_rowScrollArea->setGeometry(0, y, m_rowScrollAreaWidth, h-y-sh);
774 
775 updateSizeToScroll(0,0); //Non updateAreeSize() perche' si deve tener conto
776 degli scrollbar.
777 */
778 }
779 
wheelEvent(QWheelEvent * event)780 void SpreadsheetViewer::wheelEvent(QWheelEvent *event) {
781   switch (event->source()) {
782   case Qt::MouseEventNotSynthesized: {
783     if (event->angleDelta().x() == 0) {  // vertical scroll
784       int scrollPixels = (event->angleDelta().y() > 0 ? 1 : -1) *
785                          m_markRowDistance * m_rowHeight;
786       scroll(QPoint(0, -scrollPixels));
787     } else {  // horizontal scroll
788       int scrollPixels = (event->angleDelta().x() > 0 ? 1 : -1) * m_columnWidth;
789       scroll(QPoint(-scrollPixels, 0));
790     }
791     break;
792   }
793 
794   case Qt::MouseEventSynthesizedBySystem:  // macbook touch-pad
795   {
796     QPoint numPixels  = event->pixelDelta();
797     QPoint numDegrees = event->angleDelta() / 8;
798     if (!numPixels.isNull()) {
799       scroll(-numPixels);
800     } else if (!numDegrees.isNull()) {
801       QPoint numSteps = numDegrees / 15;
802       scroll(-numSteps);
803     }
804     break;
805   }
806 
807   default:  // Qt::MouseEventSynthesizedByQt,
808             // Qt::MouseEventSynthesizedByApplication
809   {
810     std::cout << "not supported wheelEvent.source(): "
811                  "Qt::MouseEventSynthesizedByQt, "
812                  "Qt::MouseEventSynthesizedByApplication"
813               << std::endl;
814     break;
815   }
816 
817   }  // end switch
818 }
819 
timerEvent(QTimerEvent * e)820 void SpreadsheetViewer::timerEvent(QTimerEvent *e) {
821   if (!isAutoPanning()) return;
822   scroll(m_autoPanSpeed);
823   m_lastAutoPanPos += m_autoPanSpeed;
824   /*
825 if(m_dragTool)
826 {
827 QMouseEvent mouseEvent(QEvent::MouseMove, m_lastAutoPanPos, Qt::NoButton, 0, 0);
828 m_dragTool->onDrag(&mouseEvent);
829 }
830 */
831 }
832 
keyPressEvent(QKeyEvent * e)833 void SpreadsheetViewer::keyPressEvent(QKeyEvent *e) {
834   int frameCount = m_rowCount;
835   int row        = m_frameHandle->getFrame();
836 
837   if (e->key() == Qt::Key_Up &&
838       row > 0) {  // Row = frame precedente a quello settato
839     m_frameHandle->setFrame(row - 1);
840     return;
841   } else if (e->key() ==
842              Qt::Key_Down) {  // Row = frame successivo a quello settato
843     m_frameHandle->setFrame(row + 1);
844     return;
845   } else if (e->key() == '0') {
846     QWidget *panel       = parentWidget();
847     QWidget *panelParent = panel->parentWidget();
848     while (panelParent != 0 && dynamic_cast<QMainWindow *>(panelParent) == 0) {
849       panel       = panelParent;
850       panelParent = panel->parentWidget();
851     }
852     if (panelParent) {
853       QList<QDockWidget *> panels = panelParent->findChildren<QDockWidget *>();
854       for (int i = 0; i < panels.size(); i++) {
855         QWidget *w = panels[i];
856       }
857     }
858     return;
859   }
860 
861   int y = 0;
862   QRect visibleRect =
863       m_cellScrollArea->widget()->visibleRegion().boundingRect();
864   int visibleRowCount = visibleRect.height() / m_rowHeight;
865   if (e->key() ==
866       Qt::Key_PageUp)  // Setto la visualizzazione della pagina precedente
867     y = visibleRect.top() - (visibleRowCount + 1) * m_rowHeight;
868   else if (e->key() == Qt::Key_PageDown)  // Setto la visualizzazione della
869                                           // pagina successiva
870     y = visibleRect.bottom() + (visibleRowCount + 1) * m_rowHeight;
871   else if (e->key() == Qt::Key_Home)
872     y = 0;
873   else if (e->key() == Qt::Key_End)
874     y = (frameCount + 1) * m_rowHeight;
875   else
876     return;
877 
878   int deltaY = 0;
879   if (y < visibleRect.top())
880     deltaY = y - visibleRect.top();
881   else
882     deltaY = y - visibleRect.bottom();
883   scroll(QPoint(0, deltaY));
884 }
885 
frameSwitched()886 void SpreadsheetViewer::frameSwitched() {}
887 
888 /*
889 void SpreadsheetViewer::updateAllAree()
890 {
891 }
892 
893 void SpreadsheetViewer::updateCellColumnAree()
894 {
895 }
896 
897 void SpreadsheetViewer::updateCellRowAree()
898 {
899 }
900 
901 */
902 
updateAreas()903 void SpreadsheetViewer::updateAreas() {}
904 
onVSliderChanged(int)905 void SpreadsheetViewer::onVSliderChanged(int) {
906   if (!m_isComputingSize) refreshContentSize(0, 0);
907   /*
908 QScrollBar *vSc = m_cellScrollArea->verticalScrollBar();
909 int h = qMax(vSc->value() + m_cellScrollArea->height(), rowToY(getRowCount()));
910 if(m_cellScrollArea->widget())
911 m_cellScrollArea->widget()->setFixedHeight(h);
912 if(m_rowScrollArea->widget())
913 m_rowScrollArea->widget()->setFixedHeight(h);
914 */
915 
916   /*
917 int viewportHeight = m_cellScrollArea->height();
918 int contentHeight = rowToY(m_rowCount*0 + 50);
919 QScrollBar *vSc = m_cellScrollArea->verticalScrollBar();
920 int actualContentHeight = qMax(contentHeight, vSc->value() + viewportHeight);
921 m_rowScrollArea->widget()->setFixedHeight(actualContentHeight);
922 m_cellScrollArea->widget()->setFixedHeight(actualContentHeight);
923 */
924 }
925 
onHSliderChanged(int)926 void SpreadsheetViewer::onHSliderChanged(int) {
927   if (!m_isComputingSize) refreshContentSize(0, 0);
928 }
929 
ensureVisibleCol(int col)930 void SpreadsheetViewer::ensureVisibleCol(int col) {
931   int x = columnToX(col) + m_columnWidth / 2;
932 
933   int vertValue = m_cellScrollArea->verticalScrollBar()->value();
934   m_cellScrollArea->ensureVisible(x, vertValue, m_columnWidth / 2, 0);
935 }
936