Beispiel #1
1
void TFTPar8::writeData8(uint8_t data) {
    digitalWrite(_dc, HIGH);
    digitalWrite(_cs, HIGH);
    setBus(data);
    clock();
    digitalWrite(_cs, LOW);
}
Beispiel #2
1
EFX::EFX(Doc* doc) : Function(doc)
{
    m_width = 127;
    m_height = 127;
    m_xOffset = 127;
    m_yOffset = 127;
    m_rotation = 0;

    m_xFrequency = 2;
    m_yFrequency = 3;
    m_xPhase = M_PI / 2.0;
    m_yPhase = 0;

    m_propagationMode = Parallel;

    m_algorithm = EFX::Circle;

    setName(tr("New EFX"));

    m_fader = NULL;

    /* Set default speed buses */
    setBus(Bus::defaultHold());
    setFadeBus(Bus::defaultFade());
}
Beispiel #3
0
bool VCSlider::copyFrom(VCWidget* widget)
{
    VCSlider* slider = qobject_cast<VCSlider*> (widget);
    if (slider == NULL)
        return false;

    /* Copy level stuff */
    setLevelLowLimit(slider->levelLowLimit());
    setLevelHighLimit(slider->levelHighLimit());
    m_levelChannels = slider->m_levelChannels;

    /* Copy bus stuff */
    setBusLowLimit(slider->busLowLimit());
    setBusHighLimit(slider->busHighLimit());
    setBus(slider->bus());

    /* Copy slider appearance */
    setValueDisplayStyle(slider->valueDisplayStyle());
    setInvertedAppearance(slider->invertedAppearance());

    /* Copy mode & current value */
    setSliderMode(slider->sliderMode());
    m_slider->setValue(slider->sliderValue());

    /* Copy common stuff */
    return VCWidget::copyFrom(widget);
}
Beispiel #4
0
void TFTPar8::streamData16(uint16_t data) {
    digitalWrite(_dc, HIGH);
    setBus(data >> 8);
    clock();
    setBus(data & 0xFF);
    clock();
}
Beispiel #5
0
void TFTPar8::streamCommand16(uint16_t data) {
    digitalWrite(_dc, LOW);
    setBus(data >> 8);
    clock();
    setBus(data & 0xFF);
    clock();
}
Beispiel #6
0
Shuffle::Shuffle(QObject* parent) : Function(parent)
{
	m_masterTimer = NULL;

	setName(tr("New Shuffle"));
	setBus(Bus::defaultHold());

	/* initialize random seed: */
	srand ( time(NULL) );


	Doc* doc = qobject_cast <Doc*> (parent);
	if (doc != NULL)
	{
		/* Listen to function removals so that they can be removed from
		   this chaser as well. Parent might not always be Doc, but an
		   editor dialog, for example. Such chasers cannot be run,
		   though. */
		connect(doc, SIGNAL(functionRemoved(t_function_id)),
			this, SLOT(slotFunctionRemoved(t_function_id)));
	}

	//always add a blackout state to the start!
	BlackoutState *b = new BlackoutState();
	m_steps.append(b);

	//setup m_filter
	QList<StateFilter *> *foo;
	foo = new QList<StateFilter *>();
	m_filters = *foo;
	m_filters.append(new GoboFilter());
}
Beispiel #7
0
void TFTPar8::writeCommand8(uint8_t command) {
    digitalWrite(_dc, LOW);
    digitalWrite(_cs, HIGH);
    setBus(command);
    clock();
    digitalWrite(_cs, LOW);
}
Beispiel #8
0
void TFTPar8::writeCommand16(uint16_t command) {
    digitalWrite(_dc, LOW);
    digitalWrite(_cs, HIGH);
    setBus((command >> 8) & 0xFF);
    clock();
    setBus(command & 0xFF);
    clock();
    digitalWrite(_cs, LOW);
}
Beispiel #9
0
void TFTPar8::writeData16(uint16_t data) {
    digitalWrite(_dc, HIGH);
    digitalWrite(_cs, HIGH);
    setBus(data >> 8);
    clock();
    setBus(data & 0xFF);
    clock();
    digitalWrite(_cs, LOW);
}
Beispiel #10
0
void VCSlider::init()
{
	setCaption("");

	/* Main VBox */
	m_vbox = new QVBoxLayout(this);
	m_vbox->setMargin(10);
	m_vbox->setSpacing(10);
	
	/* Top label */
	m_topLabel = new QLabel(this);
	m_vbox->addWidget(m_topLabel);
	m_topLabel->setAlignment(AlignCenter);

	/* Slider & its HBox */
	m_hbox = new QHBoxLayout(m_vbox);
	m_hbox->insertSpacing(-1, 10);

	m_slider = new QSlider(this);
	m_hbox->addWidget(m_slider);
	m_slider->setRange(KDefaultBusLowLimit * KFrequency, 
			   KDefaultBusHighLimit * KFrequency);
	m_slider->setPageStep(1);
	connect(m_slider, SIGNAL(sliderPressed()),
		this, SLOT(slotSliderPressed()));
	connect(m_slider, SIGNAL(valueChanged(int)),
		this, SLOT(slotSliderValueChanged(int)));
	connect(m_slider, SIGNAL(sliderReleased()),
		this, SLOT(slotSliderReleased()));
	
	m_hbox->insertSpacing(-1, 10);

	/* Tap button */
	m_tapButton = new QPushButton(this);
	m_vbox->addWidget(m_tapButton);
	connect(m_tapButton, SIGNAL(clicked()),
		this, SLOT(slotTapButtonClicked()));
	m_time = new QTime();

	/* Bottom label */
	m_bottomLabel = new QLabel(this);
	m_vbox->addWidget(m_bottomLabel);
	m_bottomLabel->setAlignment(AlignCenter);
	m_bottomLabel->hide();

	resize(QPoint(60, 220));

	/* Initialize to bus mode by default */
	setBus(KBusIDDefaultFade);
	setSliderMode(Bus);
	setSliderValue(0);
	slotSliderValueChanged(0);

	/* Update the slider according to current mode */
	slotModeChanged(_app->mode());
}
Beispiel #11
0
void TFTPar8::streamData32(uint32_t data) {
    digitalWrite(_dc, HIGH);
    setBus((data >> 24) & 0xFF);
    clock();
    setBus((data >> 16) & 0xFF);
    clock();
    setBus((data >> 8) & 0xFF);
    clock();
    setBus(data & 0xFF);
    clock();
}
Beispiel #12
0
void TFTPar8::streamCommand32(uint32_t data) {
    digitalWrite(_dc, LOW);
    setBus((data >> 24) & 0xFF);
    clock();
    setBus((data >> 16) & 0xFF);
    clock();
    setBus((data >> 8) & 0xFF);
    clock();
    setBus(data & 0xFF);
    clock();
}
// Update current bus in view.
void qtractorBusForm::updateBus (void)
{
	// That's it...
	if (updateBus(m_pBus)) {
		++m_iDirtyTotal;
		refreshBuses();
	}

	// Reselect current bus...
	setBus(m_pBus);
}
Beispiel #14
0
Scene::Scene() : 
	Function      ( Function::Scene ),
	m_values      (            NULL ),
	m_timeSpan    (             255 ),
	m_elapsedTime (               0 ),
	m_runTimeData (            NULL ),
	m_channelData (            NULL ),
	m_dataMutex   (           false ),
	m_address     ( KChannelInvalid )
{
	setBus(KBusIDDefaultFade);
}
Beispiel #15
0
bool Scene::loadXML(QDomDocument* doc, QDomElement* root)
{
	t_value value = 0;
	t_channel ch = 0;
	Scene::ValueType value_type;
	QString str;
	
	QDomNode node;
	QDomElement tag;
	
	Q_ASSERT(doc != NULL);
	Q_ASSERT(root != NULL);

	if (root->tagName() != KXMLQLCFunction)
	{
		qWarning("Function node not found!");
		return false;
	}

	/* Load scene contents */
	node = root->firstChild();
	while (node.isNull() == false)
	{
		tag = node.toElement();
		
		if (tag.tagName() == KXMLQLCBus)
		{
			/* Bus */
			str = tag.attribute(KXMLQLCBusRole);
			Q_ASSERT(str == KXMLQLCBusFade);

			Q_ASSERT(setBus(tag.text().toInt()) == true);
		}
		else if (tag.tagName() == KXMLQLCFunctionValue)
		{
			/* Channel value */
			str = tag.attribute(KXMLQLCFunctionValueType);
			value_type = stringToValueType(str);
			ch = tag.attribute(KXMLQLCFunctionChannel).toInt();
			value = tag.text().toInt();

			Q_ASSERT(set(ch, value, value_type) == true);
		}
		else
			qWarning("Unknown scene tag: %s",
				 (const char*) tag.tagName());
		
		node = node.nextSibling();
	}

	return true;
}
Beispiel #16
0
void TFTPar8::writeData32(uint32_t data) {
    digitalWrite(_dc, HIGH);
    digitalWrite(_cs, HIGH);
    setBus((data >> 24) & 0xFF);
    clock();
    setBus((data >> 16) & 0xFF);
    clock();
    setBus((data >> 8) & 0xFF);
    clock();
    setBus(data & 0xFF);
    clock();
    digitalWrite(_cs, LOW);
}
// Bus selection slot.
void qtractorBusForm::selectBus (void)
{
	if (m_iDirtySetup > 0)
		return;

	// Get current selected item, must not be a root one...
	QTreeWidgetItem *pItem = m_ui.BusListView->currentItem();
	if (pItem == NULL)
		return;
	if (pItem->parent() == NULL)
		return;

	// Just make it in current view...
	qtractorBusListItem *pBusItem
		= static_cast<qtractorBusListItem *> (pItem);
	if (pBusItem == NULL)
		return;

	// Check if we need an update?...
	bool bUpdate = false;
	qtractorBus *pBus = pBusItem->bus();
	if (m_pBus && m_pBus != pBus && m_iDirtyCount > 0) {
		QMessageBox::StandardButtons buttons
			= QMessageBox::Discard | QMessageBox::Cancel;
		if (m_ui.UpdatePushButton->isEnabled())
			buttons |= QMessageBox::Apply;
		switch (QMessageBox::warning(this,
			tr("Warning") + " - " QTRACTOR_TITLE,
			tr("Some settings have been changed.\n\n"
			"Do you want to apply the changes?"),
			buttons)) {
		case QMessageBox::Apply:
			bUpdate = updateBus(m_pBus);
			// Fall thru...
		case QMessageBox::Discard:
			break;
		default: // Cancel.
			return;
		}
	}

	// Get new one into view...
	showBus(pBus);

	// Reselect as current (only on apply/update)
	if (bUpdate) {
		++m_iDirtyTotal;
		refreshBuses();
		setBus(m_pBus);
	}
}
Beispiel #18
0
bool Function::copyFrom(const Function* function)
{
    /* Don't copy the function's parent */

    if (function == NULL)
        return false;

    setName(function->name());
    setRunOrder(function->runOrder());
    setDirection(function->direction());
    setBus(function->busID());

    return true;
}
Beispiel #19
0
//
// Standard constructor
//
Chaser::Chaser() : 
	Function(Function::Chaser),
  
	m_runOrder     (   Loop ),
	m_direction    ( Forward ),
	m_childRunning (  false ),

	m_holdTime     (       0 ),
	m_holdStart    (       0 ),
	m_timeCode     (       0 ),

	m_runTimeDirection ( Forward ),
	m_runTimePosition  (      0 )
{
	setBus(KBusIDDefaultHold);
}
Beispiel #20
0
Chaser::Chaser(Doc* doc) : Function(doc)
{
    m_runTimeDirection = Forward;
    m_runTimePosition = 0;
    m_runner = NULL;

    setName(tr("New Chaser"));
    setBus(Bus::defaultHold());

    connect(Bus::instance(), SIGNAL(tapped(quint32)),
            this, SLOT(slotBusTapped(quint32)));

    // Listen to member Function removals
    connect(doc, SIGNAL(functionRemoved(t_function_id)),
            this, SLOT(slotFunctionRemoved(t_function_id)));
}
Beispiel #21
0
bool Scene::loadXML(const QDomElement* root)
{
	QString str;

	QDomNode node;
	QDomElement tag;

	Q_ASSERT(root != NULL);

	if (root->tagName() != KXMLQLCFunction)
	{
		qWarning("Function node not found!");
		return false;
	}

	/* Load scene contents */
	node = root->firstChild();
	while (node.isNull() == false)
	{
		tag = node.toElement();

		if (tag.tagName() == KXMLQLCBus)
		{
			/* Bus */
			str = tag.attribute(KXMLQLCBusRole);
			Q_ASSERT(str == KXMLQLCBusFade);

			setBus(tag.text().toUInt());
		}
		else if (tag.tagName() == KXMLQLCFunctionValue)
		{
			/* Channel value */
			SceneValue scv(&tag);
			if (scv.isValid() == true)
				setValue(scv);
		}
		else
		{
			qWarning() << "Unknown scene tag:" << tag.tagName();
		}

		node = node.nextSibling();
	}

	return true;
}
// Move current bus up towards the list top.
void qtractorBusForm::moveUpBus (void)
{
	if (m_pBus == NULL)
		return;

	qtractorBus *pNextBus = m_pBus->prev();
	if (pNextBus == NULL)
		return;

	qtractorSession *pSession = qtractorSession::getInstance();
	if (pSession == NULL)
		return;

	// Make it an undoable command...
	if (pSession->execute(new qtractorMoveBusCommand(m_pBus, pNextBus))) {
		++m_iDirtyTotal;
		refreshBuses();
	}

	// Reselect current bus...
	setBus(m_pBus);
}
Beispiel #23
0
EFX::EFX(QObject* parent) : Function(parent, Function::EFX)
{
	pointFunc = NULL;

	m_width = 127;
	m_height = 127;
	m_xOffset = 127;
	m_yOffset = 127;
	m_rotation = 0;

	m_xFrequency = 2;
	m_yFrequency = 3;
	m_xPhase = 1.5707963267;
	m_yPhase = 0;

	m_propagationMode = Parallel;

	m_runOrder = EFX::Loop;
	m_direction = EFX::Forward;

	m_startSceneID = KNoID;
	m_startSceneEnabled = false;

	m_stopSceneID = KNoID;
	m_stopSceneEnabled = false;

	m_previewPointArray = NULL;

	m_algorithm = KCircleAlgorithmName;

	m_stepSize = 0;

	setName(tr("New EFX"));

	/* Set Default Fade as the speed bus */
	setBus(KBusIDDefaultFade);
	connect(Bus::emitter(), SIGNAL(valueChanged(t_bus_id,t_bus_value)),
		this, SLOT(slotBusValueChanged(t_bus_id,t_bus_value)));
}
Beispiel #24
0
EFX::EFX(Doc* doc) : Function(doc)
{
	pointFunc = NULL;

	m_width = 127;
	m_height = 127;
	m_xOffset = 127;
	m_yOffset = 127;
	m_rotation = 0;

	m_xFrequency = 2;
	m_yFrequency = 3;
	m_xPhase = M_PI / 2.0;
	m_yPhase = 0;

	m_propagationMode = Parallel;

	m_startSceneID = Function::invalidId();
	m_startSceneEnabled = false;

	m_stopSceneID = Function::invalidId();
	m_stopSceneEnabled = false;

	m_algorithm = KCircleAlgorithmName;

	m_stepSize = 0;

	setName(tr("New EFX"));

	/* Set Default Fade as the speed bus */
	setBus(Bus::defaultFade());
	connect(Bus::instance(), SIGNAL(valueChanged(quint32,quint32)),
		this, SLOT(slotBusValueChanged(quint32,quint32)));

	// Listen to start/stop scene removals
	connect(doc, SIGNAL(functionRemoved(t_function_id)),
		this, SLOT(slotFunctionRemoved(t_function_id)));
}
Beispiel #25
0
Chaser::Chaser(QObject* parent) : Function(parent)
{
	m_runTimeDirection = Forward;
	m_runTimePosition = 0;
	m_masterTimer = NULL;

	setName(tr("New Chaser"));
	setBus(Bus::defaultHold());

	connect(Bus::instance(), SIGNAL(tapped(quint32)),
		this, SLOT(slotBusTapped(quint32)));

	Doc* doc = qobject_cast <Doc*> (parent);
	if (doc != NULL)
	{
		/* Listen to function removals so that they can be removed from
		   this chaser as well. Parent might not always be Doc, but an
		   editor dialog, for example. Such chasers cannot be run,
		   though. */
		connect(doc, SIGNAL(functionRemoved(t_function_id)),
			this, SLOT(slotFunctionRemoved(t_function_id)));
	}
}
Beispiel #26
0
bool Chaser::loadXML(QDomDocument* doc, QDomElement* root)
{
	t_fixture_id step_fxi = KNoID;
	int step_number = 0;
	QString str;
	
	QDomNode node;
	QDomElement tag;
	
	Q_ASSERT(doc != NULL);
	Q_ASSERT(root != NULL);

	if (root->tagName() != KXMLQLCFunction)
	{
		qWarning("Function node not found!");
		return false;
	}

	/* Load chaser contents */
	node = root->firstChild();
	while (node.isNull() == false)
	{
		tag = node.toElement();
		
		if (tag.tagName() == KXMLQLCBus)
		{
			/* Bus */
			str = tag.attribute(KXMLQLCBusRole);
			Q_ASSERT(str == KXMLQLCBusHold);

			Q_ASSERT(setBus(tag.text().toInt()) == true);
		}
		else if (tag.tagName() == KXMLQLCFunctionDirection)
		{
			/* Direction */
			setDirection(Function::stringToDirection(tag.text()));
		}
		else if (tag.tagName() == KXMLQLCFunctionRunOrder)
		{
			/* Run Order */
			setRunOrder(Function::stringToRunOrder(tag.text()));
		}
		else if (tag.tagName() == KXMLQLCFunctionStep)
		{
			step_number = 
				tag.attribute(KXMLQLCFunctionNumber).toInt();
			step_fxi = tag.text().toInt();

			if (step_number > m_steps.size())
				m_steps.append(step_fxi);
			else
				m_steps.insert(m_steps.at(step_number),
					       step_fxi);
			
		}
		else
		{
			qWarning("Unknown chaser tag: %s",
				 (const char*) tag.tagName());
		}
		
		node = node.nextSibling();
	}

	return true;
}
// Create a new bus from current view.
void qtractorBusForm::createBus (void)
{
	if (m_pBus == NULL)
		return;

	qtractorSession *pSession = qtractorSession::getInstance();
	if (pSession == NULL)
		return;
	
	const QString sBusName = m_ui.BusNameLineEdit->text().simplified();
	if (sBusName.isEmpty())
		return;

	qtractorBus::BusMode busMode = qtractorBus::None;
	switch (m_ui.BusModeComboBox->currentIndex()) {
	case 0:
		busMode = qtractorBus::Input;
		break;
	case 1:
		busMode = qtractorBus::Output;
		break;
	case 2:
		busMode = qtractorBus::Duplex;
		break;
	}

	// Make it as an unduable command...
	qtractorCreateBusCommand *pCreateBusCommand
		= new qtractorCreateBusCommand();

	// Set all creational properties...
	qtractorTrack::TrackType busType = m_pBus->busType();
	pCreateBusCommand->setBusType(busType);
	pCreateBusCommand->setBusName(sBusName);
	pCreateBusCommand->setBusMode(busMode);	
	pCreateBusCommand->setMonitor(
		(busMode & qtractorBus::Duplex) == qtractorBus::Duplex
		&& m_ui.MonitorCheckBox->isChecked());

	// Specialties for bus types...
	switch (busType) {
	case qtractorTrack::Audio:
		pCreateBusCommand->setChannels(
			m_ui.AudioChannelsSpinBox->value());
		pCreateBusCommand->setAutoConnect(
			m_ui.AudioAutoConnectCheckBox->isChecked());
		break;
	case qtractorTrack::Midi:
		pCreateBusCommand->setInstrumentName(
			m_ui.MidiInstrumentComboBox->currentIndex() > 0
			? m_ui.MidiInstrumentComboBox->currentText()
			: QString::null);
		// Fall thru...
	case qtractorTrack::None:
	default:
		break;
	}

	// Execute and refresh form...
	if (pSession->execute(pCreateBusCommand)) {
		++m_iDirtyTotal;
		refreshBuses();
	}

	// Get new one into view,
	// usually created as last one...
	qtractorBus *pBus = m_pBus;
	while (pBus->next())
		pBus = pBus->next();
	showBus(pBus);

	// Select the new bus...
	setBus(m_pBus);
}
Beispiel #28
0
bool EFX::loadXML(const QDomElement* root)
{
	QString str;
	QDomNode node;
	QDomElement tag;

	Q_ASSERT(root != NULL);

	if (root->tagName() != KXMLQLCFunction)
	{
		qWarning() << "Function node not found!";
		return false;
	}

	/* Load EFX contents */
	node = root->firstChild();
	while (node.isNull() == false)
	{
		tag = node.toElement();

		if (tag.tagName() == KXMLQLCBus)
		{
			/* Bus */
			str = tag.attribute(KXMLQLCBusRole);
			setBus(tag.text().toInt());
		}
		else if (tag.tagName() == KXMLQLCEFXFixture)
		{
			EFXFixture* ef = new EFXFixture(this);
			ef->loadXML(&tag);
			if (ef->fixture() != KNoID)
			{
				if (addFixture(ef) == false)
					delete ef;
			}
		}
		else if (tag.tagName() == KXMLQLCEFXPropagationMode)
		{
			/* Propagation mode */
			setPropagationMode(stringToPropagationMode(tag.text()));
		}
		else if (tag.tagName() == KXMLQLCEFXAlgorithm)
		{
			/* Algorithm */
			setAlgorithm(tag.text());
		}
		else if (tag.tagName() == KXMLQLCFunctionDirection)
		{
			/* Direction */
			setDirection(Function::stringToDirection(tag.text()));
		}
		else if (tag.tagName() == KXMLQLCFunctionRunOrder)
		{
			/* Run Order */
			setRunOrder(Function::stringToRunOrder(tag.text()));
		}
		else if (tag.tagName() == KXMLQLCEFXWidth)
		{
			/* Width */
			setWidth(tag.text().toInt());
		}
		else if (tag.tagName() == KXMLQLCEFXHeight)
		{
			/* Height */
			setHeight(tag.text().toInt());
		}
		else if (tag.tagName() == KXMLQLCEFXRotation)
		{
			/* Rotation */
			setRotation(tag.text().toInt());
		}
		else if (tag.tagName() == KXMLQLCEFXStartScene)
		{
			/* Start scene */
			setStartScene(tag.text().toInt());

			if (tag.attribute(KXMLQLCFunctionEnabled) ==
			    KXMLQLCTrue)
				setStartSceneEnabled(true);
			else
				setStartSceneEnabled(false);
		}
		else if (tag.tagName() == KXMLQLCEFXStopScene)
		{
			/* Stop scene */
			setStopScene(tag.text().toInt());

			if (tag.attribute(KXMLQLCFunctionEnabled) ==
			    KXMLQLCTrue)
				setStopSceneEnabled(true);
			else
				setStopSceneEnabled(false);
		}
		else if (tag.tagName() == KXMLQLCEFXAxis)
		{
			/* Axes */
			loadXMLAxis(&tag);
		}
		else
		{
			qWarning() << "Unknown EFX tag:" << tag.tagName();
		}
		
		node = node.nextSibling();
	}

	return true;
}
Beispiel #29
0
Scene::Scene(QObject* parent) : Function(parent)
{
	setName(tr("New Scene"));
	setBus(Bus::defaultFade());
}
Beispiel #30
0
VCSlider::VCSlider(QWidget* parent, Doc* doc, OutputMap* outputMap, InputMap* inputMap, MasterTimer* masterTimer)
    : VCWidget(parent, doc, outputMap, inputMap, masterTimer)
{
    /* Set the class name "VCSlider" as the object name as well */
    setObjectName(VCSlider::staticMetaObject.className());

    m_hbox = NULL;
    m_topLabel = NULL;
    m_slider = NULL;
    m_bottomLabel = NULL;
    m_tapButton = NULL;

    m_sliderMode = Bus;
    m_valueDisplayStyle = ExactValue;

    m_levelLowLimit = 0;
    m_levelHighLimit = UCHAR_MAX;

    m_bus = Bus::defaultFade();
    m_busLowLimit = KDefaultBusLowLimit;
    m_busHighLimit = KDefaultBusHighLimit;

    m_levelValue = 0;
    m_levelValueChanged = false;

    m_playbackFunction = Function::invalidId();
    m_playbackValue = 0;
    m_playbackValueChanged = false;

    m_time = NULL;

    setCaption(QString());
    setFrameStyle(KVCFrameStyleSunken);

    /* Main VBox */
    new QVBoxLayout(this);

    /* Top label */
    m_topLabel = new QLabel(this);
    layout()->addWidget(m_topLabel);
    m_topLabel->setAlignment(Qt::AlignHCenter);

    /* Slider's HBox |stretch|slider|stretch| */
    m_hbox = new QHBoxLayout();
    layout()->addItem(m_hbox);

    /* Put stretchable space before the slider (to its left side) */
    m_hbox->addStretch();

    /* The slider */
    m_slider = new QSlider(this);
    m_slider->setStyle(App::saneStyle());
    m_hbox->addWidget(m_slider);
    m_slider->setRange(KDefaultBusLowLimit * MasterTimer::frequency(),
                       KDefaultBusHighLimit * MasterTimer::frequency());
    m_slider->setPageStep(1);
    m_slider->setInvertedAppearance(false);
    connect(m_slider, SIGNAL(valueChanged(int)),
            this, SLOT(slotSliderMoved(int)));
    m_externalMovement = false;

    /* Put stretchable space after the slider (to its right side) */
    m_hbox->addStretch();

    /* Tap button */
    m_tapButton = new QPushButton(this);
    layout()->addWidget(m_tapButton);
    connect(m_tapButton, SIGNAL(clicked()),
            this, SLOT(slotTapButtonClicked()));
    m_time = new QTime();

    /* Bottom label */
    m_bottomLabel = new QLabel(this);
    layout()->addWidget(m_bottomLabel);
    m_bottomLabel->setAlignment(Qt::AlignCenter);
    m_bottomLabel->hide();

    setMinimumSize(VCSlider::defaultSize);
    resize(VCSlider::defaultSize);

    /* Initialize to bus mode by default */
    setInvertedAppearance(true);
    setBus(Bus::defaultFade());
    setSliderMode(Bus);

    /* Update the slider according to current mode */
    slotModeChanged(mode());

    /* Listen to fixture removals so that LevelChannels can be removed when
       they no longer point to an existing fixture->channel */
    connect(m_doc, SIGNAL(fixtureRemoved(quint32)),
            this, SLOT(slotFixtureRemoved(quint32)));
}