You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1590 lines
48 KiB
1590 lines
48 KiB
/*
|
|
Rosegarden
|
|
A MIDI and audio sequencer and musical notation editor.
|
|
|
|
This program is Copyright 2000-2008
|
|
Guillaume Laurent <glaurent@telegraph-road.org>,
|
|
Chris Cannam <cannam@all-day-breakfast.com>,
|
|
Richard Bown <richard.bown@ferventsoftware.com>
|
|
|
|
The moral rights of Guillaume Laurent, Chris Cannam, and Richard
|
|
Bown to claim authorship of this work have been asserted.
|
|
|
|
Other copyrights also apply to some parts of this work. Please
|
|
see the AUTHORS file and individual file headers for details.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version. See the file
|
|
COPYING included with this distribution for more information.
|
|
*/
|
|
|
|
|
|
#include "CompositionView.h"
|
|
|
|
#include "misc/Debug.h"
|
|
#include "AudioPreviewThread.h"
|
|
#include "base/RulerScale.h"
|
|
#include "base/Segment.h"
|
|
#include "base/Selection.h"
|
|
#include "base/SnapGrid.h"
|
|
#include "CompositionColourCache.h"
|
|
#include "CompositionItemHelper.h"
|
|
#include "CompositionItemImpl.h"
|
|
#include "CompositionModel.h"
|
|
#include "CompositionModelImpl.h"
|
|
#include "CompositionRect.h"
|
|
#include "AudioPreviewPainter.h"
|
|
#include "document/RosegardenGUIDoc.h"
|
|
#include "document/ConfigGroups.h"
|
|
#include "gui/general/GUIPalette.h"
|
|
#include "gui/general/RosegardenCanvasView.h"
|
|
#include "gui/general/RosegardenScrollView.h"
|
|
#include "SegmentSelector.h"
|
|
#include "SegmentToolBox.h"
|
|
#include "SegmentTool.h"
|
|
#include <tdemessagebox.h>
|
|
#include <tqbrush.h>
|
|
#include <tqcolor.h>
|
|
#include <tqevent.h>
|
|
#include <tqfont.h>
|
|
#include <tqfontmetrics.h>
|
|
#include <tqmemarray.h>
|
|
#include <tqpainter.h>
|
|
#include <tqpen.h>
|
|
#include <tqpixmap.h>
|
|
#include <tqpoint.h>
|
|
#include <tqrect.h>
|
|
#include <tqscrollbar.h>
|
|
#include <tqscrollview.h>
|
|
#include <tqsize.h>
|
|
#include <tqstring.h>
|
|
#include <tqwidget.h>
|
|
#include <tdeapplication.h>
|
|
#include <tdeconfig.h>
|
|
#include <algorithm>
|
|
|
|
|
|
namespace Rosegarden
|
|
{
|
|
|
|
class PreviewRect : public TQRect {
|
|
public:
|
|
PreviewRect(int left, int top, int width, int height) :
|
|
TQRect(left, top, width, height) {};
|
|
|
|
PreviewRect(const TQRect& r) :
|
|
TQRect(r) {};
|
|
|
|
const TQColor& getColor() const { return m_color; }
|
|
void setColor(TQColor c) { m_color = c; }
|
|
|
|
protected:
|
|
TQColor m_color;
|
|
};
|
|
|
|
CompositionView::CompositionView(RosegardenGUIDoc* doc,
|
|
CompositionModel* model,
|
|
TQWidget * parent, const char * name, WFlags f)
|
|
#if TDE_VERSION >= TDE_MAKE_VERSION(3,2,0)
|
|
: RosegardenScrollView(parent, name, f | WNoAutoErase | WStaticContents),
|
|
#else
|
|
:
|
|
RosegardenScrollView(parent, name, f | WRepaintNoErase | WResizeNoErase | WStaticContents),
|
|
#endif
|
|
m_model(model),
|
|
m_currentItem(0),
|
|
m_tool(0),
|
|
m_toolBox(0),
|
|
m_showPreviews(false),
|
|
m_showSegmentLabels(true),
|
|
m_fineGrain(false),
|
|
m_pencilOverExisting(false),
|
|
m_minWidth(m_model->getLength()),
|
|
m_stepSize(0),
|
|
m_rectFill(0xF0, 0xF0, 0xF0),
|
|
m_selectedRectFill(0x00, 0x00, 0xF0),
|
|
m_pointerPos(0),
|
|
m_pointerColor(GUIPalette::getColour(GUIPalette::Pointer)),
|
|
m_pointerWidth(4),
|
|
m_pointerPen(TQPen(m_pointerColor, m_pointerWidth)),
|
|
m_tmpRect(TQRect(TQPoint(0, 0), TQPoint( -1, -1))),
|
|
m_tmpRectFill(CompositionRect::DefaultBrushColor),
|
|
m_trackDividerColor(GUIPalette::getColour(GUIPalette::TrackDivider)),
|
|
m_drawGuides(false),
|
|
m_guideColor(GUIPalette::getColour(GUIPalette::MovementGuide)),
|
|
m_topGuidePos(0),
|
|
m_foreGuidePos(0),
|
|
m_drawSelectionRect(false),
|
|
m_drawTextFloat(false),
|
|
m_segmentsDrawBuffer(visibleWidth(), visibleHeight()),
|
|
m_artifactsDrawBuffer(visibleWidth(), visibleHeight()),
|
|
m_segmentsDrawBufferRefresh(0, 0, visibleWidth(), visibleHeight()),
|
|
m_artifactsDrawBufferRefresh(0, 0, visibleWidth(), visibleHeight()),
|
|
m_lastBufferRefreshX(0),
|
|
m_lastBufferRefreshY(0),
|
|
m_lastPointerRefreshX(0),
|
|
m_contextHelpShown(false)
|
|
{
|
|
if (doc) {
|
|
m_toolBox = new SegmentToolBox(this, doc);
|
|
|
|
connect(m_toolBox, TQT_SIGNAL(showContextHelp(const TQString &)),
|
|
this, TQT_SLOT(slotToolHelpChanged(const TQString &)));
|
|
}
|
|
|
|
setDragAutoScroll(true);
|
|
setBackgroundMode(NoBackground);
|
|
viewport()->setBackgroundMode(NoBackground);
|
|
viewport()->setPaletteBackgroundColor(GUIPalette::getColour(GUIPalette::SegmentCanvas));
|
|
|
|
slotUpdateSize();
|
|
|
|
TQScrollBar* hsb = horizontalScrollBar();
|
|
|
|
// dynamically adjust content size when scrolling past current composition's end
|
|
connect(hsb, TQT_SIGNAL(nextLine()),
|
|
this, TQT_SLOT(scrollRight()));
|
|
connect(hsb, TQT_SIGNAL(prevLine()),
|
|
this, TQT_SLOT(scrollLeft()));
|
|
|
|
// connect(this, TQT_SIGNAL(contentsMoving(int, int)),
|
|
// this, TQT_SLOT(slotAllDrawBuffersNeedRefresh()));
|
|
|
|
// connect(this, TQT_SIGNAL(contentsMoving(int, int)),
|
|
// this, TQT_SLOT(slotContentsMoving(int, int)));
|
|
|
|
connect(model, TQT_SIGNAL(needContentUpdate()),
|
|
this, TQT_SLOT(slotUpdateSegmentsDrawBuffer()));
|
|
connect(model, TQT_SIGNAL(needContentUpdate(const TQRect&)),
|
|
this, TQT_SLOT(slotUpdateSegmentsDrawBuffer(const TQRect&)));
|
|
connect(model, TQT_SIGNAL(needArtifactsUpdate()),
|
|
this, TQT_SLOT(slotArtifactsDrawBufferNeedsRefresh()));
|
|
connect(model, TQT_SIGNAL(needSizeUpdate()),
|
|
this, TQT_SLOT(slotUpdateSize()));
|
|
|
|
if (doc) {
|
|
connect(doc, TQT_SIGNAL(docColoursChanged()),
|
|
this, TQT_SLOT(slotRefreshColourCache()));
|
|
|
|
// recording-related signals
|
|
connect(doc, TQT_SIGNAL(newMIDIRecordingSegment(Segment*)),
|
|
this, TQT_SLOT(slotNewMIDIRecordingSegment(Segment*)));
|
|
connect(doc, TQT_SIGNAL(newAudioRecordingSegment(Segment*)),
|
|
this, TQT_SLOT(slotNewAudioRecordingSegment(Segment*)));
|
|
// connect(doc, TQT_SIGNAL(recordMIDISegmentUpdated(Segment*, timeT)),
|
|
// this, TQT_SLOT(slotRecordMIDISegmentUpdated(Segment*, timeT)));
|
|
connect(doc, TQT_SIGNAL(stoppedAudioRecording()),
|
|
this, TQT_SLOT(slotStoppedRecording()));
|
|
connect(doc, TQT_SIGNAL(stoppedMIDIRecording()),
|
|
this, TQT_SLOT(slotStoppedRecording()));
|
|
connect(doc, TQT_SIGNAL(audioFileFinalized(Segment*)),
|
|
getModel(), TQT_SLOT(slotAudioFileFinalized(Segment*)));
|
|
}
|
|
|
|
CompositionModelImpl* cmi = dynamic_cast<CompositionModelImpl*>(model);
|
|
if (cmi) {
|
|
cmi->setAudioPreviewThread(&doc->getAudioPreviewThread());
|
|
}
|
|
|
|
if (doc) {
|
|
doc->getAudioPreviewThread().setEmptyQueueListener(TQT_TQOBJECT(this));
|
|
}
|
|
|
|
m_segmentsDrawBuffer.setOptimization(TQPixmap::BestOptim);
|
|
m_artifactsDrawBuffer.setOptimization(TQPixmap::BestOptim);
|
|
|
|
viewport()->setMouseTracking(true);
|
|
}
|
|
|
|
void CompositionView::endAudioPreviewGeneration()
|
|
{
|
|
CompositionModelImpl* cmi = dynamic_cast<CompositionModelImpl*>(m_model);
|
|
if (cmi) {
|
|
cmi->setAudioPreviewThread(0);
|
|
}
|
|
}
|
|
|
|
void CompositionView::setBackgroundPixmap(const TQPixmap &m)
|
|
{
|
|
m_backgroundPixmap = m;
|
|
// viewport()->setErasePixmap(m_backgroundPixmap);
|
|
}
|
|
|
|
void CompositionView::initStepSize()
|
|
{
|
|
TQScrollBar* hsb = horizontalScrollBar();
|
|
m_stepSize = hsb->lineStep();
|
|
}
|
|
|
|
void CompositionView::slotUpdateSize()
|
|
{
|
|
int vStep = getModel()->grid().getYSnap();
|
|
int height = std::max(getModel()->getNbRows() * vStep, (unsigned)visibleHeight());
|
|
|
|
RulerScale *ruler = grid().getRulerScale();
|
|
|
|
int minWidth = sizeHint().width();
|
|
int computedWidth = int(nearbyint(ruler->getTotalWidth()));
|
|
|
|
int width = std::max(computedWidth, minWidth);
|
|
|
|
resizeContents(width, height);
|
|
}
|
|
|
|
void CompositionView::scrollRight()
|
|
{
|
|
RG_DEBUG << "CompositionView::scrollRight()\n";
|
|
if (m_stepSize == 0)
|
|
initStepSize();
|
|
|
|
if (horizontalScrollBar()->value() == horizontalScrollBar()->maxValue()) {
|
|
|
|
resizeContents(contentsWidth() + m_stepSize, contentsHeight());
|
|
setContentsPos(contentsX() + m_stepSize, contentsY());
|
|
getModel()->setLength(contentsWidth());
|
|
}
|
|
|
|
}
|
|
|
|
void CompositionView::scrollLeft()
|
|
{
|
|
RG_DEBUG << "CompositionView::scrollLeft()\n";
|
|
if (m_stepSize == 0)
|
|
initStepSize();
|
|
|
|
int cWidth = contentsWidth();
|
|
|
|
if (horizontalScrollBar()->value() < cWidth && cWidth > m_minWidth) {
|
|
resizeContents(cWidth - m_stepSize, contentsHeight());
|
|
getModel()->setLength(contentsWidth());
|
|
}
|
|
|
|
}
|
|
|
|
void CompositionView::setSelectionRectPos(const TQPoint& pos)
|
|
{
|
|
m_selectionRect.setRect(pos.x(), pos.y(), 0, 0);
|
|
getModel()->setSelectionRect(m_selectionRect);
|
|
}
|
|
|
|
void CompositionView::setSelectionRectSize(int w, int h)
|
|
{
|
|
m_selectionRect.setSize(TQSize(w, h));
|
|
getModel()->setSelectionRect(m_selectionRect);
|
|
}
|
|
|
|
void CompositionView::setDrawSelectionRect(bool d)
|
|
{
|
|
if (m_drawSelectionRect != d) {
|
|
m_drawSelectionRect = d;
|
|
slotArtifactsDrawBufferNeedsRefresh();
|
|
slotUpdateSegmentsDrawBuffer(m_selectionRect);
|
|
}
|
|
}
|
|
|
|
void CompositionView::clearSegmentRectsCache(bool clearPreviews)
|
|
{
|
|
dynamic_cast<CompositionModelImpl*>(getModel())->clearSegmentRectsCache(clearPreviews);
|
|
}
|
|
|
|
SegmentSelection
|
|
CompositionView::getSelectedSegments()
|
|
{
|
|
return (dynamic_cast<CompositionModelImpl*>(m_model))->getSelectedSegments();
|
|
}
|
|
|
|
void CompositionView::updateSelectionContents()
|
|
{
|
|
if (!haveSelection())
|
|
return ;
|
|
|
|
|
|
TQRect selectionRect = getModel()->getSelectionContentsRect();
|
|
updateContents(selectionRect);
|
|
}
|
|
|
|
void CompositionView::slotContentsMoving(int x, int y)
|
|
{
|
|
// tqDebug("contents moving : x=%d", x);
|
|
}
|
|
|
|
void CompositionView::slotSetTool(const TQString& toolName)
|
|
{
|
|
RG_DEBUG << "CompositionView::slotSetTool(" << toolName << ")"
|
|
<< this << "\n";
|
|
|
|
if (m_tool)
|
|
m_tool->stow();
|
|
|
|
m_toolContextHelp = "";
|
|
|
|
m_tool = m_toolBox->getTool(toolName);
|
|
|
|
if (m_tool)
|
|
m_tool->ready();
|
|
else {
|
|
KMessageBox::error(0, TQString("CompositionView::slotSetTool() : unknown tool name %1").arg(toolName));
|
|
}
|
|
}
|
|
|
|
void CompositionView::slotSelectSegments(const SegmentSelection &segments)
|
|
{
|
|
RG_DEBUG << "CompositionView::slotSelectSegments\n";
|
|
|
|
static TQRect dummy;
|
|
|
|
getModel()->clearSelected();
|
|
|
|
for (SegmentSelection::iterator i = segments.begin(); i != segments.end(); ++i) {
|
|
getModel()->setSelected(CompositionItem(new CompositionItemImpl(**i, dummy)));
|
|
}
|
|
slotUpdateSegmentsDrawBuffer();
|
|
}
|
|
|
|
SegmentSelector*
|
|
CompositionView::getSegmentSelectorTool()
|
|
{
|
|
return dynamic_cast<SegmentSelector*>(getToolBox()->getTool(SegmentSelector::ToolName));
|
|
}
|
|
|
|
void CompositionView::slotSetSelectAdd(bool value)
|
|
{
|
|
SegmentSelector* selTool = getSegmentSelectorTool();
|
|
|
|
if (!selTool)
|
|
return ;
|
|
|
|
selTool->setSegmentAdd(value);
|
|
}
|
|
|
|
void CompositionView::slotSetSelectCopy(bool value)
|
|
{
|
|
SegmentSelector* selTool = getSegmentSelectorTool();
|
|
|
|
if (!selTool)
|
|
return ;
|
|
|
|
selTool->setSegmentCopy(value);
|
|
}
|
|
|
|
void CompositionView::slotShowSplitLine(int x, int y)
|
|
{
|
|
m_splitLinePos.setX(x);
|
|
m_splitLinePos.setY(y);
|
|
}
|
|
|
|
void CompositionView::slotHideSplitLine()
|
|
{
|
|
m_splitLinePos.setX( -1);
|
|
m_splitLinePos.setY( -1);
|
|
}
|
|
|
|
void CompositionView::slotExternalWheelEvent(TQWheelEvent* e)
|
|
{
|
|
e->accept();
|
|
wheelEvent(e);
|
|
}
|
|
|
|
CompositionItem CompositionView::getFirstItemAt(TQPoint pos)
|
|
{
|
|
CompositionModel::itemcontainer items = getModel()->getItemsAt(pos);
|
|
|
|
if (items.size()) {
|
|
// find topmost item
|
|
CompositionItem res = *(items.begin());
|
|
|
|
unsigned int maxZ = res->z();
|
|
|
|
CompositionModel::itemcontainer::iterator maxZItemPos = items.begin();
|
|
|
|
for (CompositionModel::itemcontainer::iterator i = items.begin();
|
|
i != items.end(); ++i) {
|
|
CompositionItem ic = *i;
|
|
if (ic->z() > maxZ) {
|
|
RG_DEBUG << k_funcinfo << "found new topmost at z=" << ic->z() << endl;
|
|
res = ic;
|
|
maxZ = ic->z();
|
|
maxZItemPos = i;
|
|
}
|
|
}
|
|
|
|
// get rid of the rest;
|
|
items.erase(maxZItemPos);
|
|
for (CompositionModel::itemcontainer::iterator i = items.begin();
|
|
i != items.end(); ++i)
|
|
delete *i;
|
|
|
|
return res;
|
|
} else {
|
|
RG_DEBUG << k_funcinfo << "no item under cursor\n";
|
|
}
|
|
|
|
|
|
return CompositionItem();
|
|
}
|
|
|
|
void CompositionView::setSnapGrain(bool fine)
|
|
{
|
|
if (m_fineGrain) {
|
|
grid().setSnapTime(SnapGrid::NoSnap);
|
|
} else {
|
|
grid().setSnapTime(fine ? SnapGrid::SnapToBeat : SnapGrid::SnapToBar);
|
|
}
|
|
}
|
|
|
|
void CompositionView::slotUpdateSegmentsDrawBuffer()
|
|
{
|
|
// RG_DEBUG << "CompositionView::slotUpdateSegmentsDrawBuffer()\n";
|
|
slotAllDrawBuffersNeedRefresh();
|
|
updateContents();
|
|
}
|
|
|
|
void CompositionView::slotUpdateSegmentsDrawBuffer(const TQRect& rect)
|
|
{
|
|
// RG_DEBUG << "CompositionView::slotUpdateSegmentsDrawBuffer() rect "
|
|
// << rect << " - valid : " << rect.isValid() << endl;
|
|
|
|
slotAllDrawBuffersNeedRefresh(rect);
|
|
|
|
if (rect.isValid()) {
|
|
updateContents(rect);
|
|
} else {
|
|
updateContents();
|
|
}
|
|
}
|
|
|
|
void CompositionView::slotRefreshColourCache()
|
|
{
|
|
CompositionColourCache::getInstance()->init();
|
|
clearSegmentRectsCache();
|
|
slotUpdateSegmentsDrawBuffer();
|
|
}
|
|
|
|
void CompositionView::slotNewMIDIRecordingSegment(Segment* s)
|
|
{
|
|
getModel()->addRecordingItem(CompositionItemHelper::makeCompositionItem(s));
|
|
}
|
|
|
|
void CompositionView::slotNewAudioRecordingSegment(Segment* s)
|
|
{
|
|
getModel()->addRecordingItem(CompositionItemHelper::makeCompositionItem(s));
|
|
}
|
|
|
|
void CompositionView::slotStoppedRecording()
|
|
{
|
|
getModel()->clearRecordingItems();
|
|
}
|
|
|
|
void CompositionView::resizeEvent(TQResizeEvent* e)
|
|
{
|
|
TQScrollView::resizeEvent(e);
|
|
slotUpdateSize();
|
|
|
|
int w = std::max(m_segmentsDrawBuffer.width(), visibleWidth());
|
|
int h = std::max(m_segmentsDrawBuffer.height(), visibleHeight());
|
|
|
|
m_segmentsDrawBuffer.resize(w, h);
|
|
m_artifactsDrawBuffer.resize(w, h);
|
|
slotAllDrawBuffersNeedRefresh();
|
|
// RG_DEBUG << "CompositionView::resizeEvent() : drawBuffer size = " << m_segmentsDrawBuffer.size() << endl;
|
|
}
|
|
|
|
void CompositionView::viewportPaintEvent(TQPaintEvent* e)
|
|
{
|
|
TQMemArray<TQRect> rects = TQRegion(e->region()).rects();
|
|
|
|
for (unsigned int i = 0; i < rects.size(); ++i) {
|
|
viewportPaintRect(rects[i]);
|
|
}
|
|
}
|
|
|
|
void CompositionView::viewportPaintRect(TQRect r)
|
|
{
|
|
TQRect updateRect = r;
|
|
|
|
r &= viewport()->rect();
|
|
r.moveBy(contentsX(), contentsY());
|
|
|
|
// RG_DEBUG << "CompositionView::viewportPaintRect() r = " << r
|
|
// << " - moveBy " << contentsX() << "," << contentsY() << " - updateRect = " << updateRect
|
|
// << " - refresh " << m_segmentsDrawBufferRefresh << " artrefresh " << m_artifactsDrawBufferRefresh << endl;
|
|
|
|
|
|
bool scroll = false;
|
|
bool changed = checkScrollAndRefreshDrawBuffer(r, scroll);
|
|
|
|
if (changed || m_artifactsDrawBufferRefresh.isValid()) {
|
|
|
|
// r was modified by checkScrollAndRefreshDrawBuffer
|
|
TQRect copyRect(r | m_artifactsDrawBufferRefresh);
|
|
copyRect.moveBy( -contentsX(), -contentsY());
|
|
|
|
// RG_DEBUG << "copying from segment to artifacts buffer: " << copyRect << endl;
|
|
|
|
bitBlt(&m_artifactsDrawBuffer,
|
|
copyRect.x(), copyRect.y(),
|
|
&m_segmentsDrawBuffer,
|
|
copyRect.x(), copyRect.y(), copyRect.width(), copyRect.height());
|
|
m_artifactsDrawBufferRefresh |= r;
|
|
}
|
|
|
|
if (m_artifactsDrawBufferRefresh.isValid()) {
|
|
refreshArtifactsDrawBuffer(m_artifactsDrawBufferRefresh);
|
|
m_artifactsDrawBufferRefresh = TQRect();
|
|
}
|
|
|
|
if (scroll) {
|
|
bitBlt(viewport(), 0, 0,
|
|
&m_artifactsDrawBuffer, 0, 0,
|
|
m_artifactsDrawBuffer.width(), m_artifactsDrawBuffer.height());
|
|
} else {
|
|
bitBlt(viewport(), updateRect.x(), updateRect.y(),
|
|
&m_artifactsDrawBuffer, updateRect.x(), updateRect.y(),
|
|
updateRect.width(), updateRect.height());
|
|
}
|
|
|
|
// DEBUG
|
|
|
|
// TQPainter pdebug(viewport());
|
|
// static TQPen framePen(TQt::red, 1);
|
|
// pdebug.setPen(framePen);
|
|
// pdebug.drawRect(updateRect);
|
|
|
|
}
|
|
|
|
bool CompositionView::checkScrollAndRefreshDrawBuffer(TQRect &rect, bool& scroll)
|
|
{
|
|
bool all = false;
|
|
TQRect refreshRect = m_segmentsDrawBufferRefresh;
|
|
|
|
int w = visibleWidth(), h = visibleHeight();
|
|
int cx = contentsX(), cy = contentsY();
|
|
|
|
scroll = (cx != m_lastBufferRefreshX || cy != m_lastBufferRefreshY);
|
|
|
|
if (scroll) {
|
|
|
|
// RG_DEBUG << "checkScrollAndRefreshDrawBuffer: scrolling by ("
|
|
// << cx - m_lastBufferRefreshX << "," << cy - m_lastBufferRefreshY << ")" << endl;
|
|
|
|
if (refreshRect.isValid()) {
|
|
|
|
// If we've scrolled and there was an existing refresh
|
|
// rect, we can't be sure whether the refresh rect
|
|
// predated or postdated the internal update of scroll
|
|
// location. Cut our losses and refresh everything.
|
|
|
|
refreshRect.setRect(cx, cy, w, h);
|
|
|
|
} else {
|
|
|
|
// No existing refresh rect: we only need to handle the
|
|
// scroll
|
|
|
|
if (cx != m_lastBufferRefreshX) {
|
|
|
|
int dx = m_lastBufferRefreshX - cx;
|
|
|
|
if (dx > -w && dx < w) {
|
|
|
|
TQPainter cp(&m_segmentsDrawBuffer);
|
|
cp.drawPixmap(dx, 0, m_segmentsDrawBuffer);
|
|
|
|
if (dx < 0) {
|
|
refreshRect |= TQRect(cx + w + dx, cy, -dx, h);
|
|
} else {
|
|
refreshRect |= TQRect(cx, cy, dx, h);
|
|
}
|
|
|
|
} else {
|
|
|
|
refreshRect.setRect(cx, cy, w, h);
|
|
all = true;
|
|
}
|
|
}
|
|
|
|
if (cy != m_lastBufferRefreshY && !all) {
|
|
|
|
int dy = m_lastBufferRefreshY - cy;
|
|
|
|
if (dy > -h && dy < h) {
|
|
|
|
TQPainter cp(&m_segmentsDrawBuffer);
|
|
cp.drawPixmap(0, dy, m_segmentsDrawBuffer);
|
|
|
|
if (dy < 0) {
|
|
refreshRect |= TQRect(cx, cy + h + dy, w, -dy);
|
|
} else {
|
|
refreshRect |= TQRect(cx, cy, w, dy);
|
|
}
|
|
|
|
} else {
|
|
|
|
refreshRect.setRect(cx, cy, w, h);
|
|
all = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool needRefresh = false;
|
|
|
|
if (refreshRect.isValid()) {
|
|
needRefresh = true;
|
|
}
|
|
|
|
if (needRefresh)
|
|
refreshSegmentsDrawBuffer(refreshRect);
|
|
|
|
m_segmentsDrawBufferRefresh = TQRect();
|
|
m_lastBufferRefreshX = cx;
|
|
m_lastBufferRefreshY = cy;
|
|
|
|
rect |= refreshRect;
|
|
if (scroll)
|
|
rect.setRect(cx, cy, w, h);
|
|
return needRefresh;
|
|
}
|
|
|
|
void CompositionView::refreshSegmentsDrawBuffer(const TQRect& rect)
|
|
{
|
|
// Profiler profiler("CompositionView::refreshDrawBuffer", true);
|
|
// RG_DEBUG << "CompositionView::refreshSegmentsDrawBuffer() r = "
|
|
// << rect << endl;
|
|
|
|
TQPainter p(&m_segmentsDrawBuffer, viewport());
|
|
p.translate( -contentsX(), -contentsY());
|
|
|
|
if (!m_backgroundPixmap.isNull()) {
|
|
TQPoint pp(rect.x() % m_backgroundPixmap.height(), rect.y() % m_backgroundPixmap.width());
|
|
p.drawTiledPixmap(rect, m_backgroundPixmap, pp);
|
|
} else {
|
|
p.eraseRect(rect);
|
|
}
|
|
|
|
drawArea(&p, rect);
|
|
|
|
// DEBUG - show what's updated
|
|
// TQPen framePen(TQt::red, 1);
|
|
// p.setPen(framePen);
|
|
// p.drawRect(rect);
|
|
|
|
// m_segmentsDrawBufferNeedsRefresh = false;
|
|
}
|
|
|
|
void CompositionView::refreshArtifactsDrawBuffer(const TQRect& rect)
|
|
{
|
|
// RG_DEBUG << "CompositionView::refreshArtifactsDrawBuffer() r = "
|
|
// << rect << endl;
|
|
|
|
TQPainter p;
|
|
p.begin(&m_artifactsDrawBuffer, viewport());
|
|
p.translate( -contentsX(), -contentsY());
|
|
// TQRect r(contentsX(), contentsY(), m_artifactsDrawBuffer.width(), m_artifactsDrawBuffer.height());
|
|
drawAreaArtifacts(&p, rect);
|
|
p.end();
|
|
|
|
// m_artifactsDrawBufferNeedsRefresh = false;
|
|
}
|
|
|
|
void CompositionView::drawArea(TQPainter *p, const TQRect& clipRect)
|
|
{
|
|
// Profiler profiler("CompositionView::drawArea", true);
|
|
|
|
// RG_DEBUG << "CompositionView::drawArea() clipRect = " << clipRect << endl;
|
|
|
|
//
|
|
// Fetch track dividing lines
|
|
//
|
|
CompositionModel::heightlist lineHeights = getModel()->getTrackDividersIn(clipRect);
|
|
|
|
if (!lineHeights.empty()) {
|
|
|
|
p->save();
|
|
TQColor light = m_trackDividerColor.light();
|
|
p->setPen(light);
|
|
|
|
for (CompositionModel::heightlist::const_iterator hi = lineHeights.begin();
|
|
hi != lineHeights.end(); ++hi) {
|
|
int y = *hi;
|
|
if (y-1 >= clipRect.y()) {
|
|
p->drawLine(clipRect.x(), y-1,
|
|
clipRect.x() + clipRect.width() - 1, y-1);
|
|
}
|
|
if (y >= clipRect.y()) {
|
|
p->drawLine(clipRect.x(), y,
|
|
clipRect.x() + clipRect.width() - 1, y);
|
|
}
|
|
}
|
|
|
|
p->setPen(m_trackDividerColor);
|
|
|
|
for (CompositionModel::heightlist::const_iterator hi = lineHeights.begin();
|
|
hi != lineHeights.end(); ++hi) {
|
|
int y = *hi;
|
|
if (y-2 >= clipRect.y()) {
|
|
p->drawLine(clipRect.x(), y-2,
|
|
clipRect.x() + clipRect.width() - 1, y-2);
|
|
}
|
|
if (y+1 >= clipRect.y()) {
|
|
p->drawLine(clipRect.x(), y+1,
|
|
clipRect.x() + clipRect.width() - 1, y+1);
|
|
}
|
|
}
|
|
|
|
p->restore();
|
|
}
|
|
|
|
CompositionModel::AudioPreviewDrawData* audioPreviewData = 0;
|
|
CompositionModel::RectRanges* notationPreviewData = 0;
|
|
|
|
//
|
|
// Fetch previews
|
|
//
|
|
if (m_showPreviews) {
|
|
notationPreviewData = &m_notationPreviewRects;
|
|
m_notationPreviewRects.clear();
|
|
audioPreviewData = &m_audioPreviewRects;
|
|
m_audioPreviewRects.clear();
|
|
}
|
|
|
|
//
|
|
// Fetch segment rectangles to draw
|
|
//
|
|
const CompositionModel::rectcontainer& rects = getModel()->getRectanglesIn(clipRect,
|
|
notationPreviewData, audioPreviewData);
|
|
CompositionModel::rectcontainer::const_iterator i = rects.begin();
|
|
CompositionModel::rectcontainer::const_iterator end = rects.end();
|
|
|
|
//
|
|
// Draw Segment Rectangles
|
|
//
|
|
p->save();
|
|
for (; i != end; ++i) {
|
|
p->setBrush(i->getBrush());
|
|
p->setPen(i->getPen());
|
|
|
|
// RG_DEBUG << "CompositionView::drawArea : draw comp rect " << *i << endl;
|
|
drawCompRect(*i, p, clipRect);
|
|
}
|
|
|
|
p->restore();
|
|
|
|
if (rects.size() > 1) {
|
|
// RG_DEBUG << "CompositionView::drawArea : drawing intersections\n";
|
|
drawIntersections(rects, p, clipRect);
|
|
}
|
|
|
|
//
|
|
// Previews
|
|
//
|
|
if (m_showPreviews) {
|
|
p->save();
|
|
|
|
// draw audio previews
|
|
//
|
|
drawAreaAudioPreviews(p, clipRect);
|
|
|
|
// draw notation previews
|
|
//
|
|
CompositionModel::RectRanges::const_iterator npi = m_notationPreviewRects.begin();
|
|
CompositionModel::RectRanges::const_iterator npEnd = m_notationPreviewRects.end();
|
|
|
|
for (; npi != npEnd; ++npi) {
|
|
CompositionModel::RectRange interval = *npi;
|
|
p->save();
|
|
p->translate(interval.basePoint.x(), interval.basePoint.y());
|
|
// RG_DEBUG << "CompositionView::drawArea : translating to x = " << interval.basePoint.x() << endl;
|
|
for (; interval.range.first != interval.range.second; ++interval.range.first) {
|
|
|
|
const PreviewRect& pr = *(interval.range.first);
|
|
TQColor defaultCol = CompositionColourCache::getInstance()->SegmentInternalPreview;
|
|
TQColor col = interval.color.isValid() ? interval.color : defaultCol;
|
|
p->setBrush(col);
|
|
p->setPen(col);
|
|
// RG_DEBUG << "CompositionView::drawArea : drawing preview rect at x = " << pr.x() << endl;
|
|
p->drawRect(pr);
|
|
}
|
|
p->restore();
|
|
}
|
|
|
|
p->restore();
|
|
}
|
|
|
|
//
|
|
// Draw segment labels (they must be drawn over the preview rects)
|
|
//
|
|
if (m_showSegmentLabels) {
|
|
for (i = rects.begin(); i != end; ++i) {
|
|
drawCompRectLabel(*i, p, clipRect);
|
|
}
|
|
}
|
|
|
|
// drawAreaArtifacts(p, clipRect);
|
|
|
|
}
|
|
|
|
void CompositionView::drawAreaAudioPreviews(TQPainter * p, const TQRect& clipRect)
|
|
{
|
|
CompositionModel::AudioPreviewDrawData::const_iterator api = m_audioPreviewRects.begin();
|
|
CompositionModel::AudioPreviewDrawData::const_iterator apEnd = m_audioPreviewRects.end();
|
|
TQRect rectToFill, // rect to fill on canvas
|
|
localRect; // the rect of the tile to draw on the canvas
|
|
TQPoint basePoint, // origin of segment rect
|
|
drawBasePoint; // origin of rect to fill on canvas
|
|
TQRect r;
|
|
for (; api != apEnd; ++api) {
|
|
rectToFill = api->rect;
|
|
basePoint = api->basePoint;
|
|
rectToFill.moveTopLeft(basePoint);
|
|
rectToFill &= clipRect;
|
|
r = rectToFill;
|
|
drawBasePoint = rectToFill.topLeft();
|
|
rectToFill.moveBy( -basePoint.x(), -basePoint.y());
|
|
int firstPixmapIdx = (r.x() - basePoint.x()) / AudioPreviewPainter::tileWidth();
|
|
if (firstPixmapIdx >= api->pixmap.size()) {
|
|
// RG_DEBUG << "CompositionView::drawAreaAudioPreviews : WARNING - miscomputed pixmap array : r.x = "
|
|
// << r.x() << " - basePoint.x = " << basePoint.x() << " - firstPixmapIdx = " << firstPixmapIdx
|
|
// << endl;
|
|
continue;
|
|
}
|
|
int x = 0, idx = firstPixmapIdx;
|
|
// RG_DEBUG << "CompositionView::drawAreaAudioPreviews : clipRect = " << clipRect
|
|
// << " - firstPixmapIdx = " << firstPixmapIdx << endl;
|
|
while (x < clipRect.width()) {
|
|
int pixmapRectXOffset = idx * AudioPreviewPainter::tileWidth();
|
|
localRect.setRect(basePoint.x() + pixmapRectXOffset, basePoint.y(),
|
|
AudioPreviewPainter::tileWidth(), api->rect.height());
|
|
// RG_DEBUG << "CompositionView::drawAreaAudioPreviews : initial localRect = "
|
|
// << localRect << endl;
|
|
localRect &= r;
|
|
if (idx == firstPixmapIdx && api->resizeOffset != 0) {
|
|
// this segment is being resized from start, clip beginning of preview
|
|
localRect.moveBy(api->resizeOffset, 0);
|
|
}
|
|
|
|
// RG_DEBUG << "CompositionView::drawAreaAudioPreviews : localRect & clipRect = "
|
|
// << localRect << endl;
|
|
if (localRect.isEmpty()) {
|
|
// RG_DEBUG << "CompositionView::drawAreaAudioPreviews : localRect & clipRect is empty\n";
|
|
break;
|
|
}
|
|
localRect.moveBy( -(basePoint.x() + pixmapRectXOffset), -basePoint.y());
|
|
|
|
// RG_DEBUG << "CompositionView::drawAreaAudioPreviews : drawing pixmap "
|
|
// << idx << " at " << drawBasePoint << " - localRect = " << localRect
|
|
// << " - preResizeOrigin : " << api->preResizeOrigin << endl;
|
|
|
|
p->drawImage(drawBasePoint, api->pixmap[idx], localRect,
|
|
Qt::ColorOnly | Qt::ThresholdDither | Qt::AvoidDither);
|
|
|
|
++idx;
|
|
if (idx >= api->pixmap.size())
|
|
break;
|
|
drawBasePoint.setX(drawBasePoint.x() + localRect.width());
|
|
x += localRect.width();
|
|
}
|
|
}
|
|
}
|
|
|
|
void CompositionView::drawAreaArtifacts(TQPainter * p, const TQRect& clipRect)
|
|
{
|
|
//
|
|
// Playback Pointer
|
|
//
|
|
drawPointer(p, clipRect);
|
|
|
|
//
|
|
// Tmp rect (rect displayed while drawing a new segment)
|
|
//
|
|
if (m_tmpRect.isValid() && m_tmpRect.intersects(clipRect)) {
|
|
p->setBrush(m_tmpRectFill);
|
|
p->setPen(CompositionColourCache::getInstance()->SegmentBorder);
|
|
drawRect(m_tmpRect, p, clipRect);
|
|
}
|
|
|
|
//
|
|
// Tool guides (crosshairs)
|
|
//
|
|
if (m_drawGuides)
|
|
drawGuides(p, clipRect);
|
|
|
|
//
|
|
// Selection Rect
|
|
//
|
|
if (m_drawSelectionRect) {
|
|
drawRect(m_selectionRect, p, clipRect, false, 0, false);
|
|
}
|
|
|
|
//
|
|
// Floating Text
|
|
//
|
|
if (m_drawTextFloat)
|
|
drawTextFloat(p, clipRect);
|
|
|
|
//
|
|
// Split line
|
|
//
|
|
if (m_splitLinePos.x() > 0 && clipRect.contains(m_splitLinePos)) {
|
|
p->save();
|
|
p->setPen(m_guideColor);
|
|
p->drawLine(m_splitLinePos.x(), m_splitLinePos.y(),
|
|
m_splitLinePos.x(), m_splitLinePos.y() + getModel()->grid().getYSnap());
|
|
p->restore();
|
|
}
|
|
}
|
|
|
|
void CompositionView::drawGuides(TQPainter * p, const TQRect& /*clipRect*/)
|
|
{
|
|
// no need to check for clipping, these guides are meant to follow the mouse cursor
|
|
TQPoint guideOrig(m_topGuidePos, m_foreGuidePos);
|
|
|
|
p->save();
|
|
p->setPen(m_guideColor);
|
|
p->drawLine(guideOrig.x(), 0, guideOrig.x(), contentsHeight());
|
|
p->drawLine(0, guideOrig.y(), contentsWidth(), guideOrig.y());
|
|
p->restore();
|
|
}
|
|
|
|
void CompositionView::drawCompRect(const CompositionRect& r, TQPainter *p, const TQRect& clipRect,
|
|
int intersectLvl, bool fill)
|
|
{
|
|
p->save();
|
|
|
|
TQBrush brush = r.getBrush();
|
|
|
|
if (r.isRepeating()) {
|
|
TQColor brushColor = brush.color();
|
|
brush.setColor(brushColor.light(150));
|
|
}
|
|
|
|
p->setBrush(brush);
|
|
p->setPen(r.getPen());
|
|
drawRect(r, p, clipRect, r.isSelected(), intersectLvl, fill);
|
|
|
|
if (r.isRepeating()) {
|
|
|
|
CompositionRect::repeatmarks repeatMarks = r.getRepeatMarks();
|
|
|
|
// RG_DEBUG << "CompositionView::drawCompRect() : drawing repeating rect " << r
|
|
// << " nb repeat marks = " << repeatMarks.size() << endl;
|
|
|
|
// draw 'start' rectangle with original brush
|
|
//
|
|
TQRect startRect = static_cast<const TQRect&>(r);
|
|
startRect.setWidth(repeatMarks[0] - r.x());
|
|
p->setBrush(r.getBrush());
|
|
drawRect(startRect, p, clipRect, r.isSelected(), intersectLvl, fill);
|
|
|
|
|
|
// now draw the 'repeat' marks
|
|
//
|
|
p->setPen(CompositionColourCache::getInstance()->RepeatSegmentBorder);
|
|
int penWidth = std::max((uint)r.getPen().width(), 1u);
|
|
|
|
for (unsigned int i = 0; i < repeatMarks.size(); ++i) {
|
|
int pos = repeatMarks[i];
|
|
if (pos > clipRect.right())
|
|
break;
|
|
|
|
if (pos >= clipRect.left()) {
|
|
TQPoint p1(pos, r.y() + penWidth),
|
|
p2(pos, r.y() + r.height() - penWidth - 1);
|
|
|
|
// RG_DEBUG << "CompositionView::drawCompRect() : drawing repeat mark at "
|
|
// << p1 << "-" << p2 << endl;
|
|
p->drawLine(p1, p2);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p->restore();
|
|
}
|
|
|
|
void CompositionView::drawCompRectLabel(const CompositionRect& r, TQPainter *p, const TQRect& clipRect)
|
|
{
|
|
// draw segment label
|
|
//
|
|
#ifdef NOT_DEFINED
|
|
if (!r.getLabel().isEmpty() /* && !r.isSelected() */)
|
|
{
|
|
p->save();
|
|
p->setPen(GUIPalette::getColour(GUIPalette::SegmentLabel));
|
|
p->setBrush(white);
|
|
TQRect textRect(r);
|
|
textRect.setX(textRect.x() + 3);
|
|
TQString label = " " + r.getLabel() + " ";
|
|
TQRect textBoundingRect = p->boundingRect(textRect, TQt::AlignLeft | TQt::AlignVCenter, label);
|
|
p->drawRect(textBoundingRect & r);
|
|
p->drawText(textRect, TQt::AlignLeft | TQt::AlignVCenter, label);
|
|
p->restore();
|
|
}
|
|
#else
|
|
if (!r.getLabel().isEmpty()) {
|
|
|
|
p->save();
|
|
|
|
TQFont font;
|
|
font.setPixelSize(r.height() / 2.2);
|
|
font.setWeight(TQFont::Bold);
|
|
font.setItalic(false);
|
|
p->setFont(font);
|
|
|
|
TQRect labelRect = TQRect
|
|
(r.x(),
|
|
r.y() + ((r.height() - p->fontMetrics().height()) / 2) + 1,
|
|
r.width(),
|
|
p->fontMetrics().height());
|
|
|
|
int x = labelRect.x() + p->fontMetrics().width('x');
|
|
int y = labelRect.y();
|
|
|
|
TQBrush brush = r.getBrush();
|
|
TQColor surroundColour = brush.color().light(110);
|
|
|
|
int h, s, v;
|
|
surroundColour.hsv(&h, &s, &v);
|
|
if (v < 150)
|
|
surroundColour.setHsv(h, s, 225);
|
|
p->setPen(surroundColour);
|
|
|
|
for (int i = 0; i < 9; ++i) {
|
|
|
|
if (i == 4)
|
|
continue;
|
|
|
|
int wx = x, wy = y;
|
|
|
|
if (i < 3)
|
|
--wx;
|
|
if (i > 5)
|
|
++wx;
|
|
if (i % 3 == 0)
|
|
--wy;
|
|
if (i % 3 == 2)
|
|
++wy;
|
|
|
|
labelRect.setX(wx);
|
|
labelRect.setY(wy);
|
|
|
|
p->drawText(labelRect,
|
|
TQt::AlignLeft | TQt::AlignTop,
|
|
r.getLabel());
|
|
}
|
|
|
|
labelRect.setX(x);
|
|
labelRect.setY(y);
|
|
|
|
p->setPen(GUIPalette::getColour
|
|
(GUIPalette::SegmentLabel));
|
|
p->drawText(labelRect,
|
|
TQt::AlignLeft | TQt::AlignVCenter, r.getLabel());
|
|
p->restore();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void CompositionView::drawRect(const TQRect& r, TQPainter *p, const TQRect& clipRect,
|
|
bool isSelected, int intersectLvl, bool fill)
|
|
{
|
|
// RG_DEBUG << "CompositionView::drawRect : intersectLvl = " << intersectLvl
|
|
// << " - brush col = " << p->brush().color() << endl;
|
|
|
|
// RG_DEBUG << "CompositionView::drawRect " << r << " - xformed : " << p->xForm(r)
|
|
// << " - contents x = " << contentsX() << ", contents y = " << contentsY() << endl;
|
|
|
|
p->save();
|
|
|
|
TQRect rect = r;
|
|
|
|
if (fill) {
|
|
if (isSelected) {
|
|
TQColor fillColor = p->brush().color();
|
|
fillColor = fillColor.dark(200);
|
|
TQBrush b = p->brush();
|
|
b.setColor(fillColor);
|
|
p->setBrush(b);
|
|
// RG_DEBUG << "CompositionView::drawRect : selected color : " << fillColor << endl;
|
|
}
|
|
|
|
if (intersectLvl > 0) {
|
|
TQColor fillColor = p->brush().color();
|
|
fillColor = fillColor.dark((intersectLvl) * 105);
|
|
TQBrush b = p->brush();
|
|
b.setColor(fillColor);
|
|
p->setBrush(b);
|
|
// RG_DEBUG << "CompositionView::drawRect : intersected color : " << fillColor << " isSelected : " << isSelected << endl;
|
|
}
|
|
} else {
|
|
p->setBrush(TQt::NoBrush);
|
|
}
|
|
|
|
// Paint using the small coordinates...
|
|
TQRect intersection = rect.intersect(clipRect);
|
|
|
|
if (clipRect.contains(rect)) {
|
|
p->drawRect(rect);
|
|
} else {
|
|
// draw only what's necessary
|
|
if (!intersection.isEmpty() && fill)
|
|
p->fillRect(intersection, p->brush());
|
|
|
|
int rectTopY = rect.y();
|
|
|
|
if (rectTopY >= clipRect.y() &&
|
|
rectTopY <= (clipRect.y() + clipRect.height())) {
|
|
// to prevent overflow, in case the original rect is too wide
|
|
// the line would be drawn "backwards"
|
|
p->drawLine(intersection.topLeft(), intersection.topRight());
|
|
}
|
|
|
|
int rectBottomY = rect.y() + rect.height();
|
|
if (rectBottomY >= clipRect.y() &&
|
|
rectBottomY <= (clipRect.y() + clipRect.height()))
|
|
// to prevent overflow, in case the original rect is too wide
|
|
// the line would be drawn "backwards"
|
|
p->drawLine(intersection.bottomLeft(), intersection.bottomRight());
|
|
|
|
int rectLeftX = rect.x();
|
|
if (rectLeftX >= clipRect.x() &&
|
|
rectLeftX <= (clipRect.x() + clipRect.width()))
|
|
p->drawLine(rect.topLeft(), rect.bottomLeft());
|
|
|
|
unsigned int rectRightX = rect.x() + rect.width(); // make sure we don't overflow
|
|
if (rectRightX >= unsigned(clipRect.x()) &&
|
|
rectRightX <= unsigned(clipRect.x() + clipRect.width()))
|
|
p->drawLine(rect.topRight(), rect.bottomRight());
|
|
|
|
}
|
|
|
|
p->restore();
|
|
}
|
|
|
|
TQColor CompositionView::mixBrushes(TQBrush a, TQBrush b)
|
|
{
|
|
TQColor ac = a.color(), bc = b.color();
|
|
|
|
int aR = ac.red(), aG = ac.green(), aB = ac.blue(),
|
|
bR = bc.red(), bG = bc.green(), bB = ac.blue();
|
|
|
|
ac.setRgb((aR + bR) / 2, (aG + bG) / 2, (aB + bB) / 2);
|
|
|
|
return ac;
|
|
}
|
|
|
|
void CompositionView::drawIntersections(const CompositionModel::rectcontainer& rects,
|
|
TQPainter * p, const TQRect& clipRect)
|
|
{
|
|
if (! (rects.size() > 1))
|
|
return ;
|
|
|
|
CompositionModel::rectcontainer intersections;
|
|
|
|
CompositionModel::rectcontainer::const_iterator i = rects.begin(),
|
|
j = rects.begin();
|
|
|
|
for (; j != rects.end(); ++j) {
|
|
|
|
CompositionRect testRect = *j;
|
|
i = j;
|
|
++i; // set i to pos after j
|
|
|
|
if (i == rects.end())
|
|
break;
|
|
|
|
for (; i != rects.end(); ++i) {
|
|
CompositionRect ri = testRect.intersect(*i);
|
|
if (!ri.isEmpty()) {
|
|
CompositionModel::rectcontainer::iterator t = std::find(intersections.begin(),
|
|
intersections.end(), ri);
|
|
if (t == intersections.end()) {
|
|
ri.setBrush(mixBrushes(testRect.getBrush(), i->getBrush()));
|
|
ri.setSelected(testRect.isSelected() || i->isSelected());
|
|
intersections.push_back(ri);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// draw this level of intersections then compute and draw further ones
|
|
//
|
|
int intersectionLvl = 1;
|
|
|
|
while (!intersections.empty()) {
|
|
|
|
for (CompositionModel::rectcontainer::iterator intIter = intersections.begin();
|
|
intIter != intersections.end(); ++intIter) {
|
|
CompositionRect r = *intIter;
|
|
drawCompRect(r, p, clipRect, intersectionLvl);
|
|
}
|
|
|
|
if (intersections.size() > 10)
|
|
break; // put a limit on how many intersections we can compute and draw - this grows exponentially
|
|
|
|
++intersectionLvl;
|
|
|
|
CompositionModel::rectcontainer intersections2;
|
|
|
|
CompositionModel::rectcontainer::iterator i = intersections.begin(),
|
|
j = intersections.begin();
|
|
|
|
for (; j != intersections.end(); ++j) {
|
|
|
|
CompositionRect testRect = *j;
|
|
i = j;
|
|
++i; // set i to pos after j
|
|
|
|
if (i == intersections.end())
|
|
break;
|
|
|
|
for (; i != intersections.end(); ++i) {
|
|
CompositionRect ri = testRect.intersect(*i);
|
|
if (!ri.isEmpty() && ri != *i) {
|
|
CompositionModel::rectcontainer::iterator t = std::find(intersections2.begin(),
|
|
intersections2.end(), ri);
|
|
if (t == intersections2.end())
|
|
ri.setBrush(mixBrushes(testRect.getBrush(), i->getBrush()));
|
|
intersections2.push_back(ri);
|
|
}
|
|
}
|
|
}
|
|
|
|
intersections = intersections2;
|
|
}
|
|
|
|
}
|
|
|
|
void CompositionView::drawPointer(TQPainter *p, const TQRect& clipRect)
|
|
{
|
|
// RG_DEBUG << "CompositionView::drawPointer: clipRect "
|
|
// << clipRect.x() << "," << clipRect.y() << " " << clipRect.width()
|
|
// << "x" << clipRect.height() << " pointer pos is " << m_pointerPos << endl;
|
|
|
|
if (m_pointerPos >= clipRect.x() && m_pointerPos <= (clipRect.x() + clipRect.width())) {
|
|
p->save();
|
|
p->setPen(m_pointerPen);
|
|
p->drawLine(m_pointerPos, clipRect.y(), m_pointerPos, clipRect.y() + clipRect.height());
|
|
p->restore();
|
|
}
|
|
|
|
}
|
|
|
|
void CompositionView::drawTextFloat(TQPainter *p, const TQRect& clipRect)
|
|
{
|
|
TQFontMetrics metrics(p->fontMetrics());
|
|
|
|
TQRect bound = p->boundingRect(0, 0, 300, metrics.height() + 6, AlignAuto, m_textFloatText);
|
|
|
|
p->save();
|
|
|
|
bound.setLeft(bound.left() - 2);
|
|
bound.setRight(bound.right() + 2);
|
|
bound.setTop(bound.top() - 2);
|
|
bound.setBottom(bound.bottom() + 2);
|
|
|
|
TQPoint pos(m_textFloatPos);
|
|
if (pos.y() < 0 && getModel()) {
|
|
if (pos.y() + bound.height() < 0) {
|
|
pos.setY(pos.y() + getModel()->grid().getYSnap() * 3);
|
|
} else {
|
|
pos.setY(pos.y() + getModel()->grid().getYSnap() * 2);
|
|
}
|
|
}
|
|
|
|
bound.moveTopLeft(pos);
|
|
|
|
if (bound.intersects(clipRect)) {
|
|
|
|
p->setBrush(CompositionColourCache::getInstance()->RotaryFloatBackground);
|
|
|
|
drawRect(bound, p, clipRect, false, 0, true);
|
|
|
|
p->setPen(CompositionColourCache::getInstance()->RotaryFloatForeground);
|
|
|
|
p->drawText(pos.x() + 2, pos.y() + 3 + metrics.ascent(), m_textFloatText);
|
|
|
|
}
|
|
|
|
p->restore();
|
|
}
|
|
|
|
bool CompositionView::event(TQEvent* e)
|
|
{
|
|
if (e->type() == AudioPreviewThread::AudioPreviewQueueEmpty) {
|
|
RG_DEBUG << "CompositionView::event - AudioPreviewQueueEmpty\n";
|
|
slotSegmentsDrawBufferNeedsRefresh();
|
|
viewport()->update();
|
|
return true;
|
|
}
|
|
|
|
return RosegardenScrollView::event(e);
|
|
}
|
|
|
|
void CompositionView::enterEvent(TQEvent *e)
|
|
{
|
|
kapp->config()->setGroup(GeneralOptionsConfigGroup);
|
|
if (!kapp->config()->readBoolEntry("toolcontexthelp", true)) return;
|
|
|
|
emit showContextHelp(m_toolContextHelp);
|
|
m_contextHelpShown = true;
|
|
}
|
|
|
|
void CompositionView::leaveEvent(TQEvent *e)
|
|
{
|
|
emit showContextHelp("");
|
|
m_contextHelpShown = false;
|
|
}
|
|
|
|
void CompositionView::slotToolHelpChanged(const TQString &text)
|
|
{
|
|
if (m_toolContextHelp == text) return;
|
|
m_toolContextHelp = text;
|
|
|
|
kapp->config()->setGroup(GeneralOptionsConfigGroup);
|
|
if (!kapp->config()->readBoolEntry("toolcontexthelp", true)) return;
|
|
|
|
if (m_contextHelpShown) emit showContextHelp(text);
|
|
}
|
|
|
|
void CompositionView::contentsMousePressEvent(TQMouseEvent* e)
|
|
{
|
|
TQt::ButtonState bs = e->state();
|
|
slotSetSelectCopy((bs & TQt::ControlButton) != 0);
|
|
slotSetSelectAdd((bs & TQt::ShiftButton) != 0);
|
|
slotSetFineGrain((bs & TQt::ShiftButton) != 0);
|
|
slotSetPencilOverExisting((bs & TQt::AltButton + TQt::ControlButton) != 0);
|
|
|
|
switch (e->button()) {
|
|
case Qt::LeftButton:
|
|
case Qt::MidButton:
|
|
startAutoScroll();
|
|
|
|
if (m_tool)
|
|
m_tool->handleMouseButtonPress(e);
|
|
else
|
|
RG_DEBUG << "CompositionView::contentsMousePressEvent() :"
|
|
<< this << " no tool\n";
|
|
break;
|
|
case Qt::RightButton:
|
|
if (m_tool)
|
|
m_tool->handleRightButtonPress(e);
|
|
else
|
|
RG_DEBUG << "CompositionView::contentsMousePressEvent() :"
|
|
<< this << " no tool\n";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CompositionView::contentsMouseReleaseEvent(TQMouseEvent* e)
|
|
{
|
|
RG_DEBUG << "CompositionView::contentsMouseReleaseEvent()\n";
|
|
|
|
stopAutoScroll();
|
|
|
|
if (!m_tool)
|
|
return ;
|
|
|
|
if (e->button() == Qt::LeftButton ||
|
|
e->button() == Qt::MidButton )
|
|
m_tool->handleMouseButtonRelease(e);
|
|
}
|
|
|
|
void CompositionView::contentsMouseDoubleClickEvent(TQMouseEvent* e)
|
|
{
|
|
m_currentItem = getFirstItemAt(e->pos());
|
|
|
|
if (!m_currentItem) {
|
|
RG_DEBUG << "CompositionView::contentsMouseDoubleClickEvent - no currentItem\n";
|
|
RulerScale *ruler = grid().getRulerScale();
|
|
if (ruler) emit setPointerPosition(ruler->getTimeForX(e->pos().x()));
|
|
return ;
|
|
}
|
|
|
|
RG_DEBUG << "CompositionView::contentsMouseDoubleClickEvent - have currentItem\n";
|
|
|
|
CompositionItemImpl* itemImpl = dynamic_cast<CompositionItemImpl*>((_CompositionItem*)m_currentItem);
|
|
|
|
if (m_currentItem->isRepeating()) {
|
|
timeT time = getModel()->getRepeatTimeAt(e->pos(), m_currentItem);
|
|
|
|
RG_DEBUG << "editRepeat at time " << time << endl;
|
|
if (time > 0)
|
|
emit editRepeat(itemImpl->getSegment(), time);
|
|
else
|
|
emit editSegment(itemImpl->getSegment());
|
|
|
|
} else {
|
|
|
|
emit editSegment(itemImpl->getSegment());
|
|
}
|
|
}
|
|
|
|
void CompositionView::contentsMouseMoveEvent(TQMouseEvent* e)
|
|
{
|
|
if (!m_tool)
|
|
return ;
|
|
|
|
TQt::ButtonState bs = e->state();
|
|
slotSetFineGrain((bs & TQt::ShiftButton) != 0);
|
|
slotSetPencilOverExisting((bs & TQt::AltButton) != 0);
|
|
|
|
int follow = m_tool->handleMouseMove(e);
|
|
setScrollDirectionConstraint(follow);
|
|
|
|
if (follow != RosegardenCanvasView::NoFollow) {
|
|
doAutoScroll();
|
|
|
|
if (follow & RosegardenCanvasView::FollowHorizontal) {
|
|
slotScrollHorizSmallSteps(e->pos().x());
|
|
|
|
// enlarge composition if needed
|
|
if (horizontalScrollBar()->value() == horizontalScrollBar()->maxValue()) {
|
|
resizeContents(contentsWidth() + m_stepSize, contentsHeight());
|
|
setContentsPos(contentsX() + m_stepSize, contentsY());
|
|
getModel()->setLength(contentsWidth());
|
|
slotUpdateSize();
|
|
}
|
|
}
|
|
|
|
if (follow & RosegardenCanvasView::FollowVertical)
|
|
slotScrollVertSmallSteps(e->pos().y());
|
|
}
|
|
}
|
|
|
|
void CompositionView::releaseCurrentItem()
|
|
{
|
|
m_currentItem = CompositionItem();
|
|
}
|
|
|
|
void CompositionView::setPointerPos(int pos)
|
|
{
|
|
// RG_DEBUG << "CompositionView::setPointerPos(" << pos << ")\n";
|
|
int oldPos = m_pointerPos;
|
|
if (oldPos == pos)
|
|
return ;
|
|
|
|
m_pointerPos = pos;
|
|
getModel()->setPointerPos(pos);
|
|
|
|
// automagically grow contents width if pointer position goes beyond right end
|
|
//
|
|
if (pos >= (contentsWidth() - m_stepSize)) {
|
|
resizeContents(pos + m_stepSize, contentsHeight());
|
|
// grow composition too, if needed (it may not be the case if
|
|
if (getModel()->getLength() < contentsWidth())
|
|
getModel()->setLength(contentsWidth());
|
|
}
|
|
|
|
|
|
// interesting -- isAutoScrolling() never seems to return true?
|
|
// RG_DEBUG << "CompositionView::setPointerPos(" << pos << "), isAutoScrolling " << isAutoScrolling() << ", contentsX " << contentsX() << ", m_lastPointerRefreshX " << m_lastPointerRefreshX << ", contentsHeight " << contentsHeight() << endl;
|
|
|
|
if (contentsX() != m_lastPointerRefreshX) {
|
|
m_lastPointerRefreshX = contentsX();
|
|
// We'll need to shift the whole canvas anyway, so
|
|
slotArtifactsDrawBufferNeedsRefresh();
|
|
return ;
|
|
}
|
|
|
|
int deltaW = abs(m_pointerPos - oldPos);
|
|
|
|
if (deltaW <= m_pointerPen.width() * 2) { // use one rect instead of two separate ones
|
|
|
|
TQRect updateRect
|
|
(std::min(m_pointerPos, oldPos) - m_pointerPen.width(), 0,
|
|
deltaW + m_pointerPen.width() * 2, contentsHeight());
|
|
|
|
slotArtifactsDrawBufferNeedsRefresh(updateRect);
|
|
|
|
} else {
|
|
|
|
slotArtifactsDrawBufferNeedsRefresh
|
|
(TQRect(m_pointerPos - m_pointerPen.width(), 0,
|
|
m_pointerPen.width() * 2, contentsHeight()));
|
|
|
|
slotArtifactsDrawBufferNeedsRefresh
|
|
(TQRect(oldPos - m_pointerPen.width(), 0,
|
|
m_pointerPen.width() * 2, contentsHeight()));
|
|
}
|
|
}
|
|
|
|
void CompositionView::setGuidesPos(int x, int y)
|
|
{
|
|
m_topGuidePos = x;
|
|
m_foreGuidePos = y;
|
|
slotArtifactsDrawBufferNeedsRefresh();
|
|
}
|
|
|
|
void CompositionView::setGuidesPos(const TQPoint& p)
|
|
{
|
|
m_topGuidePos = p.x();
|
|
m_foreGuidePos = p.y();
|
|
slotArtifactsDrawBufferNeedsRefresh();
|
|
}
|
|
|
|
void CompositionView::setDrawGuides(bool d)
|
|
{
|
|
m_drawGuides = d;
|
|
slotArtifactsDrawBufferNeedsRefresh();
|
|
}
|
|
|
|
void CompositionView::setTmpRect(const TQRect& r)
|
|
{
|
|
setTmpRect(r, m_tmpRectFill);
|
|
}
|
|
|
|
void CompositionView::setTmpRect(const TQRect& r, const TQColor &c)
|
|
{
|
|
TQRect pRect = m_tmpRect;
|
|
m_tmpRect = r;
|
|
m_tmpRectFill = c;
|
|
slotUpdateSegmentsDrawBuffer(m_tmpRect | pRect);
|
|
}
|
|
|
|
void CompositionView::setTextFloat(int x, int y, const TQString &text)
|
|
{
|
|
m_textFloatPos.setX(x);
|
|
m_textFloatPos.setY(y);
|
|
m_textFloatText = text;
|
|
m_drawTextFloat = true;
|
|
slotArtifactsDrawBufferNeedsRefresh();
|
|
|
|
// most of the time when the floating text is drawn
|
|
// we want to update a larger part of the view
|
|
// so don't update here
|
|
// TQRect r = fontMetrics().boundingRect(x, y, 300, 40, AlignAuto, m_textFloatText);
|
|
// slotUpdateSegmentsDrawBuffer(r);
|
|
|
|
|
|
// rgapp->slotSetStatusMessage(text);
|
|
}
|
|
|
|
void CompositionView::slotSetFineGrain(bool value)
|
|
{
|
|
m_fineGrain = value;
|
|
}
|
|
|
|
void CompositionView::slotSetPencilOverExisting(bool value)
|
|
{
|
|
m_pencilOverExisting = value;
|
|
}
|
|
|
|
void
|
|
CompositionView::slotTextFloatTimeout()
|
|
{
|
|
hideTextFloat();
|
|
slotArtifactsDrawBufferNeedsRefresh();
|
|
// rgapp->slotSetStatusMessage(TQString());
|
|
}
|
|
|
|
}
|
|
#include "CompositionView.moc"
|