<commit_before>
/*!
	\file

	\author Igor Mironchik (igor.mironchik at gmail dot com).

	Copyright (c) 2014 Igor Mironchik

	Permission is hereby granted, free of charge, to any person
	obtaining a copy of this software and associated documentation
	files (the "Software"), to deal in the Software without
	restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the
	Software is furnished to do so, subject to the following
	conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
	OTHER DEALINGS IN THE SOFTWARE.
*/

// QtMWidgets include.
#include "navigationbar.hpp"
#include "navigationbutton.hpp"
#include "textlabel.hpp"
#include "fingergeometry.hpp"

// Qt include.
#include <QStackedWidget>
#include <QVector>
#include <QMap>
#include <QSharedPointer>
#include <QGridLayout>
#include <QVBoxLayout>
#include <QResizeEvent>
#include <QStack>
#include <QHideEvent>

namespace QtMWidgets {

//
// NavigationItem
//

class NavigationItem {
public:

	NavigationItem()
		:	index( -1 )
		,	parent( 0 )
	{
	}

	NavigationItem( const NavigationItem & other )
		:	title( other.title )
		,	index( other.index )
		,	children( other.children )
		,	parent( other.parent )
	{
	}

	NavigationItem & operator = ( const NavigationItem & other )
	{
		if( this != &other )
		{
			title = other.title;
			index = other.index;
			children = other.children;
			parent = other.parent;
		}

		return *this;
	}

	QString title;
	int index;
	QVector< QSharedPointer< NavigationItem > > children;
	QVector< int > childrenIndexes;
	NavigationItem * parent;
}; // class NavigationItem

//
// NavigationBarPrivate
//

class NavigationBarPrivate {
public:
	NavigationBarPrivate( NavigationBar * parent )
		:	q( parent )
		,	stack( 0 )
		,	left( 0 )
		,	right( 0 )
		,	title( 0 )
		,	grid( 0 )
	{
	}

	void init();
	void removeWidget( int index );

	NavigationBar * q;
	QStackedWidget * stack;
	QList< QSharedPointer< NavigationItem > > rootItems;
	QMap< int, QSharedPointer< NavigationItem > > itemsMap;
	NavigationButton * left;
	NavigationButton * right;
	TextLabel * title;
	QGridLayout * grid;
	QStack< int > backStack;
	QStack< int > forwardStack;
}; // class NavigationBarPrivate

void
NavigationBarPrivate::init()
{
	q->setBackgroundRole( QPalette::Base );
	q->setAutoFillBackground( true );

	stack = new QStackedWidget( q );
	stack->setFrameStyle( QFrame::NoFrame | QFrame::Plain );

	left = new NavigationButton( NavigationButton::Left, q );
	right = new NavigationButton( NavigationButton::Right, q );
	title = new TextLabel( q );
	title->setColor( q->palette().color( QPalette::Highlight ) );

	QObject::connect( left, &NavigationButton::clicked,
		q, &NavigationBar::showPreviousScreen );
	QObject::connect( right, &NavigationButton::clicked,
		q, &NavigationBar::showNextScreen );

	QTextOption opt = title->textOption();
	opt.setAlignment( Qt::AlignCenter );
	opt.setWrapMode( QTextOption::NoWrap );

	title->setTextOption( opt );

	QFont f = title->font();
	f.setBold( true );
	f.setPointSize( f.pointSize() + 1 );

	title->setFont( f );

	QVBoxLayout * layout = new QVBoxLayout( q );
	layout->setSpacing( 0 );
	layout->setContentsMargins( 3, 3, 3, 3 );

	grid = new QGridLayout;
	grid->addWidget( left, 0, 0 );
	grid->addWidget( title, 0, 1 );
	grid->addWidget( right, 0, 2 );
	grid->setRowMinimumHeight( 0, FingerGeometry::height() );

	left->hide();
	right->hide();

	layout->addLayout( grid );
	layout->addWidget( stack );
}

void
NavigationBarPrivate::removeWidget( int index )
{
	QSharedPointer< NavigationItem > item = itemsMap[ index ];

	itemsMap.remove( index );
	stack->removeWidget( stack->widget( index ) );

	foreach( int childIndex, item->childrenIndexes )
		removeWidget( childIndex );

	if( item->parent )
	{
		item->parent->children.removeAt(
			item->parent->children.indexOf( item ) );
		item->parent->childrenIndexes.removeAt(
			item->parent->childrenIndexes.indexOf( index ) );
	}
}

//
// NavigationBar
//

NavigationBar::NavigationBar( QWidget * parent )
	:	QWidget( parent )
	,	d( new NavigationBarPrivate( this ) )
{
	d->init();
}

NavigationBar::~NavigationBar()
{
}

int
NavigationBar::setMainWidget( const QString & title,
	QWidget * widget )
{
	const int index = d->stack->addWidget( widget );

	d->rootItems.append(
		QSharedPointer< NavigationItem > ( new NavigationItem ) );
	d->itemsMap[ index ] = d->rootItems.back();

	d->rootItems.back()->index = index;
	d->rootItems.back()->title = title;

	d->stack->setCurrentIndex( index );
	d->title->setText( title );

	return index;
}

int
NavigationBar::addWidget( int parentIndex, const QString & title,
	QWidget * widget )
{
	const int index = d->stack->addWidget( widget );

	if( d->itemsMap.contains( parentIndex ) )
	{
		QSharedPointer< NavigationItem > parent = d->itemsMap[ parentIndex ];

		QSharedPointer< NavigationItem > item( new NavigationItem );
		item->index = index;
		item->title = title;
		item->parent = parent.data();

		parent->children.append( item );
		parent->childrenIndexes.append( index );
		d->itemsMap[ index ] = item;
	}

	return index;
}

void
NavigationBar::removeWidget( QWidget * widget )
{
	const int index = d->stack->indexOf( widget );

	if( index != -1 )
	{
		d->removeWidget( index );

		d->backStack.clear();
		d->forwardStack.clear();

		d->left->hide();
		d->right->hide();
	}
}

int
NavigationBar::currentIndex() const
{
	return d->stack->currentIndex();
}

QWidget *
NavigationBar::currentWidget() const
{
	return d->stack->currentWidget();
}

int
NavigationBar::indexOf( QWidget * widget ) const
{
	return d->stack->indexOf( widget );
}

QWidget *
NavigationBar::widget( int index ) const
{
	return d->stack->widget( index );
}

QSize
NavigationBar::minimumSizeHint() const
{
	return QSize( FingerGeometry::width(), FingerGeometry::height() );
}

QSize
NavigationBar::sizeHint() const
{
	return minimumSizeHint();
}

void
NavigationBar::showScreen( int index )
{
	if( d->itemsMap.contains( index ) && currentIndex() != -1 )
	{
		QSharedPointer< NavigationItem > nextItem = d->itemsMap[ index ];
		QSharedPointer< NavigationItem > currentItem = d->itemsMap[ currentIndex() ];

		if( d->backStack.isEmpty() || d->backStack.back() != currentIndex() )
		{
			d->backStack.push( currentIndex() );

			d->left->setText( currentItem->title );
			d->left->show();
		}

		d->title->setText( nextItem->title );

		d->stack->setCurrentIndex( index );
	}
}

void
NavigationBar::showPreviousScreen()
{
	if( !d->backStack.isEmpty() )
	{
		const int prevIndex = d->backStack.pop();
		QSharedPointer< NavigationItem > prevItem = d->itemsMap[ prevIndex ];
		QSharedPointer< NavigationItem > currentItem = d->itemsMap[ currentIndex() ];

		if( d->forwardStack.isEmpty() || d->forwardStack.back() != currentIndex() )
		{
			d->forwardStack.push( currentIndex() );

			d->right->setText( currentItem->title );
			d->right->show();
		}

		d->title->setText( prevItem->title );

		d->stack->setCurrentIndex( prevIndex );

		if( !d->backStack.isEmpty() )
		{
			QSharedPointer< NavigationItem > backItem = d->itemsMap[ d->backStack.top() ];

			d->left->setText( backItem->title );
		}
		else
			d->left->hide();
	}
}

void
NavigationBar::showNextScreen()
{
	if( !d->forwardStack.isEmpty() )
	{
		const int nextIndex = d->forwardStack.pop();
		QSharedPointer< NavigationItem > nextItem = d->itemsMap[ nextIndex ];
		QSharedPointer< NavigationItem > currentItem = d->itemsMap[ currentIndex() ];

		d->backStack.push( currentIndex() );

		d->title->setText( nextItem->title );

		d->left->setText( currentItem->title );
		d->left->show();

		d->stack->setCurrentIndex( nextIndex );

		if( !d->forwardStack.isEmpty() )
		{
			QSharedPointer< NavigationItem > item = d->itemsMap[ d->forwardStack.top() ];

			d->right->setText( item->title );
		}
		else
			d->right->hide();
	}
}

void
NavigationBar::resizeEvent( QResizeEvent * e )
{
	const int width = e->size().width() / 3;

	d->grid->setColumnMinimumWidth( 0, width );
	d->grid->setColumnMinimumWidth( 1, width );
	d->grid->setColumnMinimumWidth( 2, width );

	e->accept();
}

void
NavigationBar::hideEvent( QHideEvent * e )
{
	if( !isVisible() )
	{
		d->backStack.clear();
		d->forwardStack.clear();

		d->left->hide();
		d->right->hide();
	}

	e->accept();
}

} /* namespace QtMWidgets */
<commit_msg>Disable forward stack on show screen in navigation bar.<commit_after>
/*!
	\file

	\author Igor Mironchik (igor.mironchik at gmail dot com).

	Copyright (c) 2014 Igor Mironchik

	Permission is hereby granted, free of charge, to any person
	obtaining a copy of this software and associated documentation
	files (the "Software"), to deal in the Software without
	restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the
	Software is furnished to do so, subject to the following
	conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
	OTHER DEALINGS IN THE SOFTWARE.
*/

// QtMWidgets include.
#include "navigationbar.hpp"
#include "navigationbutton.hpp"
#include "textlabel.hpp"
#include "fingergeometry.hpp"

// Qt include.
#include <QStackedWidget>
#include <QVector>
#include <QMap>
#include <QSharedPointer>
#include <QGridLayout>
#include <QVBoxLayout>
#include <QResizeEvent>
#include <QStack>
#include <QHideEvent>

namespace QtMWidgets {

//
// NavigationItem
//

class NavigationItem {
public:

	NavigationItem()
		:	index( -1 )
		,	parent( 0 )
	{
	}

	NavigationItem( const NavigationItem & other )
		:	title( other.title )
		,	index( other.index )
		,	children( other.children )
		,	parent( other.parent )
	{
	}

	NavigationItem & operator = ( const NavigationItem & other )
	{
		if( this != &other )
		{
			title = other.title;
			index = other.index;
			children = other.children;
			parent = other.parent;
		}

		return *this;
	}

	QString title;
	int index;
	QVector< QSharedPointer< NavigationItem > > children;
	QVector< int > childrenIndexes;
	NavigationItem * parent;
}; // class NavigationItem

//
// NavigationBarPrivate
//

class NavigationBarPrivate {
public:
	NavigationBarPrivate( NavigationBar * parent )
		:	q( parent )
		,	stack( 0 )
		,	left( 0 )
		,	right( 0 )
		,	title( 0 )
		,	grid( 0 )
	{
	}

	void init();
	void removeWidget( int index );

	NavigationBar * q;
	QStackedWidget * stack;
	QList< QSharedPointer< NavigationItem > > rootItems;
	QMap< int, QSharedPointer< NavigationItem > > itemsMap;
	NavigationButton * left;
	NavigationButton * right;
	TextLabel * title;
	QGridLayout * grid;
	QStack< int > backStack;
	QStack< int > forwardStack;
}; // class NavigationBarPrivate

void
NavigationBarPrivate::init()
{
	q->setBackgroundRole( QPalette::Base );
	q->setAutoFillBackground( true );

	stack = new QStackedWidget( q );
	stack->setFrameStyle( QFrame::NoFrame | QFrame::Plain );

	left = new NavigationButton( NavigationButton::Left, q );
	right = new NavigationButton( NavigationButton::Right, q );
	title = new TextLabel( q );
	title->setColor( q->palette().color( QPalette::Highlight ) );

	QObject::connect( left, &NavigationButton::clicked,
		q, &NavigationBar::showPreviousScreen );
	QObject::connect( right, &NavigationButton::clicked,
		q, &NavigationBar::showNextScreen );

	QTextOption opt = title->textOption();
	opt.setAlignment( Qt::AlignCenter );
	opt.setWrapMode( QTextOption::NoWrap );

	title->setTextOption( opt );

	QFont f = title->font();
	f.setBold( true );
	f.setPointSize( f.pointSize() + 1 );

	title->setFont( f );

	QVBoxLayout * layout = new QVBoxLayout( q );
	layout->setSpacing( 0 );
	layout->setContentsMargins( 3, 3, 3, 3 );

	grid = new QGridLayout;
	grid->addWidget( left, 0, 0 );
	grid->addWidget( title, 0, 1 );
	grid->addWidget( right, 0, 2 );
	grid->setRowMinimumHeight( 0, FingerGeometry::height() );

	left->hide();
	right->hide();

	layout->addLayout( grid );
	layout->addWidget( stack );
}

void
NavigationBarPrivate::removeWidget( int index )
{
	QSharedPointer< NavigationItem > item = itemsMap[ index ];

	itemsMap.remove( index );
	stack->removeWidget( stack->widget( index ) );

	foreach( int childIndex, item->childrenIndexes )
		removeWidget( childIndex );

	if( item->parent )
	{
		item->parent->children.removeAt(
			item->parent->children.indexOf( item ) );
		item->parent->childrenIndexes.removeAt(
			item->parent->childrenIndexes.indexOf( index ) );
	}
}

//
// NavigationBar
//

NavigationBar::NavigationBar( QWidget * parent )
	:	QWidget( parent )
	,	d( new NavigationBarPrivate( this ) )
{
	d->init();
}

NavigationBar::~NavigationBar()
{
}

int
NavigationBar::setMainWidget( const QString & title,
	QWidget * widget )
{
	const int index = d->stack->addWidget( widget );

	d->rootItems.append(
		QSharedPointer< NavigationItem > ( new NavigationItem ) );
	d->itemsMap[ index ] = d->rootItems.back();

	d->rootItems.back()->index = index;
	d->rootItems.back()->title = title;

	d->stack->setCurrentIndex( index );
	d->title->setText( title );

	return index;
}

int
NavigationBar::addWidget( int parentIndex, const QString & title,
	QWidget * widget )
{
	const int index = d->stack->addWidget( widget );

	if( d->itemsMap.contains( parentIndex ) )
	{
		QSharedPointer< NavigationItem > parent = d->itemsMap[ parentIndex ];

		QSharedPointer< NavigationItem > item( new NavigationItem );
		item->index = index;
		item->title = title;
		item->parent = parent.data();

		parent->children.append( item );
		parent->childrenIndexes.append( index );
		d->itemsMap[ index ] = item;
	}

	return index;
}

void
NavigationBar::removeWidget( QWidget * widget )
{
	const int index = d->stack->indexOf( widget );

	if( index != -1 )
	{
		d->removeWidget( index );

		d->backStack.clear();
		d->forwardStack.clear();

		d->left->hide();
		d->right->hide();
	}
}

int
NavigationBar::currentIndex() const
{
	return d->stack->currentIndex();
}

QWidget *
NavigationBar::currentWidget() const
{
	return d->stack->currentWidget();
}

int
NavigationBar::indexOf( QWidget * widget ) const
{
	return d->stack->indexOf( widget );
}

QWidget *
NavigationBar::widget( int index ) const
{
	return d->stack->widget( index );
}

QSize
NavigationBar::minimumSizeHint() const
{
	return QSize( FingerGeometry::width(), FingerGeometry::height() );
}

QSize
NavigationBar::sizeHint() const
{
	return minimumSizeHint();
}

void
NavigationBar::showScreen( int index )
{
	if( d->itemsMap.contains( index ) && currentIndex() != -1 )
	{
		QSharedPointer< NavigationItem > nextItem = d->itemsMap[ index ];
		QSharedPointer< NavigationItem > currentItem = d->itemsMap[ currentIndex() ];

		if( d->backStack.isEmpty() || d->backStack.top() != currentIndex() )
		{
			d->backStack.push( currentIndex() );

			d->left->setText( currentItem->title );
			d->left->show();
		}

		d->forwardStack.clear();
		d->right->hide();

		d->title->setText( nextItem->title );

		d->stack->setCurrentIndex( index );
	}
}

void
NavigationBar::showPreviousScreen()
{
	if( !d->backStack.isEmpty() )
	{
		const int prevIndex = d->backStack.pop();
		QSharedPointer< NavigationItem > prevItem = d->itemsMap[ prevIndex ];
		QSharedPointer< NavigationItem > currentItem = d->itemsMap[ currentIndex() ];

		if( d->forwardStack.isEmpty() || d->forwardStack.top() != currentIndex() )
		{
			d->forwardStack.push( currentIndex() );

			d->right->setText( currentItem->title );
			d->right->show();
		}

		d->title->setText( prevItem->title );

		d->stack->setCurrentIndex( prevIndex );

		if( !d->backStack.isEmpty() )
		{
			QSharedPointer< NavigationItem > backItem = d->itemsMap[ d->backStack.top() ];

			d->left->setText( backItem->title );
		}
		else
			d->left->hide();
	}
}

void
NavigationBar::showNextScreen()
{
	if( !d->forwardStack.isEmpty() )
	{
		const int nextIndex = d->forwardStack.pop();
		QSharedPointer< NavigationItem > nextItem = d->itemsMap[ nextIndex ];
		QSharedPointer< NavigationItem > currentItem = d->itemsMap[ currentIndex() ];

		d->backStack.push( currentIndex() );

		d->title->setText( nextItem->title );

		d->left->setText( currentItem->title );
		d->left->show();

		d->stack->setCurrentIndex( nextIndex );

		if( !d->forwardStack.isEmpty() )
		{
			QSharedPointer< NavigationItem > item = d->itemsMap[ d->forwardStack.top() ];

			d->right->setText( item->title );
		}
		else
			d->right->hide();
	}
}

void
NavigationBar::resizeEvent( QResizeEvent * e )
{
	const int width = e->size().width() / 3;

	d->grid->setColumnMinimumWidth( 0, width );
	d->grid->setColumnMinimumWidth( 1, width );
	d->grid->setColumnMinimumWidth( 2, width );

	e->accept();
}

void
NavigationBar::hideEvent( QHideEvent * e )
{
	if( !isVisible() )
	{
		d->backStack.clear();
		d->forwardStack.clear();

		d->left->hide();
		d->right->hide();
	}

	e->accept();
}

} /* namespace QtMWidgets */
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: PaneDockingWindow.hxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 05:11:45 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SD_PANE_DOCKING_WINDOW_HXX
#define SD_PANE_DOCKING_WINDOW_HXX

#ifndef _SFXDOCKWIN_HXX
#include <sfx2/dockwin.hxx>
#endif
#include <sfx2/viewfrm.hxx>
#include "PaneManager.hxx"

class ToolBox;

namespace sd {

class PaneDockingWindow
    : public SfxDockingWindow
{
public:
    /** Create a new docking window that will be displayed in the specified
        pane.
        The constructor will determine the ViewShellBase via the given
        bindings and tell its PaneManager about the new window.  It will ask
        the PaneManager for a window title.
        @param pBindings
            Used, among others, to determine the ViewShellBase and
            PaneManager that manage the new docking window.
        @param pChildWindow
            This child window is the logical container for the new docking
            window.
        @param pParent
            The parent window of the new docking window.
        @param rResId
            The resource is used to determine initial size and attributes.
        @param ePane
            The pane in which to show the docking window.
    */
    PaneDockingWindow (
        SfxBindings *pBindings,
        SfxChildWindow *pChildWindow,
        ::Window* pParent,
        const ResId& rResId,
        PaneManager::PaneType ePane);

    virtual ~PaneDockingWindow (void);

    virtual void Paint (const Rectangle& rRectangle);
    virtual void Resize (void);

    virtual long Notify( NotifyEvent& rNEvt );
    virtual void StateChanged( StateChangedType nType );
    virtual void DataChanged( const DataChangedEvent& rDCEvt );

    /** Initializing the title tool box either creates a new title tool box
        or clears all items from an existing one.  A closer is added as only
        item.
    */
    void InitializeTitleToolBox (void);

    /** Add a top down menu to the title bar or rather the top-level menu
        entry.  The given callback is called when the menu is clicked and it
        is the task of the callback to show the menu.
        @return
            The id of the new menu is returned.  It can be compared by the
            callback to the value of GetCurItemId() when called at the given
            tool box.
    */
    USHORT AddMenu (const String& rsMenuName, ULONG nHelpId, const Link& rCallback);

    /** Set the title of the docking window to the given string.  Use this
        method when the title is not yet known at the time of construction
        or can not be passed to the constructor.
    */
    void SetTitle (const String& rsTitle);

private:
    /** The pane which is represented by the docking window.
    */
    PaneManager::PaneType mePane;

    /** Title that is shown at the top of the docking window.
    */
    String msTitle;

    /** The tool box that is displayed in the window title area contains
        menus and the closer button.
    */
    ::std::auto_ptr<ToolBox> mpTitleToolBox;

    /** The border that is painted arround the inner window.  The bevel
        shadow lines are part of the border, so where the border is 0 no
        such line is painted.
    */
    SvBorder maBorder;

    sal_uInt16 mnChildWindowId;

    DECL_LINK(ToolboxSelectHandler, ToolBox*);
    DECL_LINK(WindowEventListener, VclSimpleEvent*);
};

} // end of namespace ::sd

#endif
<commit_msg>INTEGRATION: CWS impress66 (1.7.80); FILE MERGED 2005/10/10 14:36:24 af 1.7.80.2: RESYNC: (1.7-1.8); FILE MERGED 2005/08/08 11:38:19 af 1.7.80.1: #i48402# Added argument for docking window title to constructor.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: PaneDockingWindow.hxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: hr $ $Date: 2005-10-24 16:17:35 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SD_PANE_DOCKING_WINDOW_HXX
#define SD_PANE_DOCKING_WINDOW_HXX

#ifndef _SFXDOCKWIN_HXX
#include <sfx2/dockwin.hxx>
#endif
#include <sfx2/viewfrm.hxx>
#include "PaneManager.hxx"

class ToolBox;

namespace sd {

class PaneDockingWindow
    : public SfxDockingWindow
{
public:
    /** Create a new docking window that will be displayed in the specified
        pane.
        The constructor will determine the ViewShellBase via the given
        bindings and tell its PaneManager about the new window.  It will ask
        the PaneManager for a window title.
        @param pBindings
            Used, among others, to determine the ViewShellBase and
            PaneManager that manage the new docking window.
        @param pChildWindow
            This child window is the logical container for the new docking
            window.
        @param pParent
            The parent window of the new docking window.
        @param rResId
            The resource is used to determine initial size and attributes.
        @param ePane
            The pane in which to show the docking window.
    */
    PaneDockingWindow (
        SfxBindings *pBindings,
        SfxChildWindow *pChildWindow,
        ::Window* pParent,
        const ResId& rResId,
        PaneManager::PaneType ePane,
        const String& rsTitle);

    virtual ~PaneDockingWindow (void);

    virtual void Paint (const Rectangle& rRectangle);
    virtual void Resize (void);

    virtual long Notify( NotifyEvent& rNEvt );
    virtual void StateChanged( StateChangedType nType );
    virtual void DataChanged( const DataChangedEvent& rDCEvt );

    /** Initializing the title tool box either creates a new title tool box
        or clears all items from an existing one.  A closer is added as only
        item.
    */
    void InitializeTitleToolBox (void);

    /** Add a top down menu to the title bar or rather the top-level menu
        entry.  The given callback is called when the menu is clicked and it
        is the task of the callback to show the menu.
        @return
            The id of the new menu is returned.  It can be compared by the
            callback to the value of GetCurItemId() when called at the given
            tool box.
    */
    USHORT AddMenu (const String& rsMenuName, ULONG nHelpId, const Link& rCallback);

    /** Set the title of the docking window to the given string.  Use this
        method when the title is not yet known at the time of construction
        or can not be passed to the constructor.
    */
    void SetTitle (const String& rsTitle);

private:
    /** The pane which is represented by the docking window.
    */
    PaneManager::PaneType mePane;

    /** Title that is shown at the top of the docking window.
    */
    String msTitle;

    /** The tool box that is displayed in the window title area contains
        menus and the closer button.
    */
    ::std::auto_ptr<ToolBox> mpTitleToolBox;

    /** The border that is painted arround the inner window.  The bevel
        shadow lines are part of the border, so where the border is 0 no
        such line is painted.
    */
    SvBorder maBorder;

    sal_uInt16 mnChildWindowId;

    DECL_LINK(ToolboxSelectHandler, ToolBox*);
    DECL_LINK(WindowEventListener, VclSimpleEvent*);
};

} // end of namespace ::sd

#endif
<|endoftext|>


<commit_before>/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */

/*
    Memcached protocol extensions for testapp.

    Provides extended protocol commands to enable interesting testcases.

    1. Currently supports shifting the Memcached's timeofday.
      * protocol command can be overridden in config.
*/

#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <inttypes.h>

#include "extensions/protocol_extension.h"
#include <memcached/util.h>
#include <platform/platform.h>

static uint8_t adjust_timeofday_command = PROTOCOL_BINARY_CMD_ADJUST_TIMEOFDAY;

GET_SERVER_API server_api;

static const char *get_name(void);
static void setup(void (*add)(EXTENSION_BINARY_PROTOCOL_DESCRIPTOR *descriptor,
                              uint8_t cmd,
                              BINARY_COMMAND_CALLBACK new_handler));

static ENGINE_ERROR_CODE handle_adjust_time(EXTENSION_BINARY_PROTOCOL_DESCRIPTOR *descriptor,
                                            ENGINE_HANDLE* handle,
                                            const void* cookie,
                                            protocol_binary_request_header *request,
                                            ADD_RESPONSE response);

static EXTENSION_BINARY_PROTOCOL_DESCRIPTOR descriptor;

static const char *get_name(void) {
    return "testapp protocol extension";
}

static void setup(void (*add)(EXTENSION_BINARY_PROTOCOL_DESCRIPTOR *descriptor,
                              uint8_t cmd,
                              BINARY_COMMAND_CALLBACK new_handler))
{
    add(&descriptor, adjust_timeofday_command, handle_adjust_time);
}

static ENGINE_ERROR_CODE handle_adjust_time(EXTENSION_BINARY_PROTOCOL_DESCRIPTOR *descriptor,
                                            ENGINE_HANDLE* handle,
                                            const void* cookie,
                                            protocol_binary_request_header *request,
                                            ADD_RESPONSE response)
{
    protocol_binary_adjust_time *req = (protocol_binary_adjust_time*)request;
    ENGINE_ERROR_CODE r = ENGINE_SUCCESS;
    uint64_t offset = 0;

    offset = ntohll(req->message.body.offset);

    if (r == ENGINE_SUCCESS) {

        if (r == ENGINE_SUCCESS) {
            if (request->request.opcode == adjust_timeofday_command) {
                cb_set_timeofday_offset(offset);

                if (!response(NULL, 0, NULL, 0, NULL, 0,
                                PROTOCOL_BINARY_RAW_BYTES,
                                PROTOCOL_BINARY_RESPONSE_SUCCESS,
                                0, cookie)) {
                    return ENGINE_DISCONNECT;
                }
            } else {
                if (!response(NULL, 0, NULL, 0, NULL, 0,
                                PROTOCOL_BINARY_RAW_BYTES,
                                PROTOCOL_BINARY_RESPONSE_SUCCESS,
                                0, cookie)) {
                    return ENGINE_DISCONNECT;
                }
            }

        }
    }
    return r;
}

MEMCACHED_PUBLIC_API
EXTENSION_ERROR_CODE memcached_extensions_initialize(const char *config,
                                                     GET_SERVER_API get_server_api) {
    SERVER_HANDLE_V1 *server = get_server_api();
    server_api = get_server_api;
    descriptor.get_name = get_name;
    descriptor.setup = setup;

    if (server == NULL) {
        return EXTENSION_FATAL;
    }

    if (config != NULL) {
        size_t time_op = 0;
        struct config_item items[2];
        memset(&items, 0, sizeof(items));

        items[0].key = "t";
        items[0].datatype = DT_SIZE;
        items[0].value.dt_size = &time_op;

        if (server->core->parse_config(config, items, stderr) != 0) {
            return EXTENSION_FATAL;
        }

        if (items[0].found) {
            adjust_timeofday_command = (uint8_t)(time_op & 0xff);
        }
    }

    if (!server->extension->register_extension(EXTENSION_BINARY_PROTOCOL,
                                               &descriptor)) {
        return EXTENSION_FATAL;
    }

    return EXTENSION_SUCCESS;
}
<commit_msg>Refactor: Drop dead code<commit_after>/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */

/*
    Memcached protocol extensions for testapp.

    Provides extended protocol commands to enable interesting testcases.

    1. Currently supports shifting the Memcached's timeofday.
*/

#include "config.h"
#include "extensions/protocol_extension.h"

static EXTENSION_BINARY_PROTOCOL_DESCRIPTOR descriptor;

static const char *get_name(void) {
    return "testapp protocol extension";
}

static ENGINE_ERROR_CODE handle_adjust_time(EXTENSION_BINARY_PROTOCOL_DESCRIPTOR*,
                                            ENGINE_HANDLE*,
                                            const void* cookie,
                                            protocol_binary_request_header *request,
                                            ADD_RESPONSE response) {
    auto *req = reinterpret_cast<protocol_binary_adjust_time*>(request);
    uint64_t offset = ntohll(req->message.body.offset);

    if (request->request.opcode == PROTOCOL_BINARY_CMD_ADJUST_TIMEOFDAY) {
        cb_set_timeofday_offset(offset);
    }

    if (!response(nullptr, 0, nullptr, 0, nullptr, 0,
                  PROTOCOL_BINARY_RAW_BYTES,
                  PROTOCOL_BINARY_RESPONSE_SUCCESS,
                  0, cookie)) {
        return ENGINE_DISCONNECT;
    }

    return ENGINE_SUCCESS;
}

static void setup(void (*add)(EXTENSION_BINARY_PROTOCOL_DESCRIPTOR *descriptor,
                              uint8_t cmd,
                              BINARY_COMMAND_CALLBACK new_handler)) {
    add(&descriptor, PROTOCOL_BINARY_CMD_ADJUST_TIMEOFDAY, handle_adjust_time);
}

MEMCACHED_PUBLIC_API
EXTENSION_ERROR_CODE memcached_extensions_initialize(const char *config,
                                                     GET_SERVER_API get_server_api) {
    SERVER_HANDLE_V1 *server = get_server_api();
    descriptor.get_name = get_name;
    descriptor.setup = setup;

    if (server == nullptr) {
        return EXTENSION_FATAL;
    }

    if (config != nullptr && strlen(config) > 0) {
        return EXTENSION_FATAL;
    }

    if (!server->extension->register_extension(EXTENSION_BINARY_PROTOCOL,
                                               &descriptor)) {
        return EXTENSION_FATAL;
    }

    return EXTENSION_SUCCESS;
}
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2018-2019 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <inviwo/core/interaction/pickingcontrollermousestate.h>

#include <inviwo/core/interaction/pickingmanager.h>
#include <inviwo/core/interaction/events/eventpropagator.h>
#include <inviwo/core/interaction/events/mouseevent.h>
#include <inviwo/core/interaction/events/pickingevent.h>
#include <inviwo/core/interaction/pickingaction.h>
#include <inviwo/core/interaction/pickingcontroller.h>

#include <sml/sml.hpp>
namespace sml = boost::sml;

namespace inviwo {

namespace fsm {

// State
struct FsmState {
    size_t active_globalId = 0;
};

struct PreviousFsmState {
    size_t globalId = 0;
    dvec3 ndc{0};
};

struct PressFsmState {
    size_t globalId = 0;
    dvec3 ndc{0};
};

// States
struct Idle {};
struct HasId {};
struct Pressing {};

// events;
struct BaseEvent {
    BaseEvent(const size_t globalId, MouseEvent* event, EventPropagator* propagator)
        : globalId{globalId}, event{event}, propagator{propagator} {}
    const size_t globalId;
    MouseEvent* event;
    EventPropagator* propagator;
};
struct Move : BaseEvent {
    using BaseEvent::BaseEvent;
};
struct Press : BaseEvent {
    using BaseEvent::BaseEvent;
};
struct Release : BaseEvent {
    using BaseEvent::BaseEvent;
};
struct DblClk : BaseEvent {
    using BaseEvent::BaseEvent;
};

PickingPressItem mouseButtonToPressItem(MouseButton mb) {
    switch (mb) {
        case MouseButton::None:
            return PickingPressItem::None;
        case MouseButton::Left:
            return PickingPressItem::Primary;
        case MouseButton::Middle:
            return PickingPressItem::Tertiary;
        case MouseButton::Right:
            return PickingPressItem::Secondary;
        default:
            return PickingPressItem::None;
    }
}
PickingPressItems mouseButtonsToPressItems(MouseButtons mb) {
    PickingPressItems res = PickingPressItem::None;
    if (mb.count(MouseButton::Left)) res |= PickingPressItem::Primary;
    if (mb.count(MouseButton::Middle)) res |= PickingPressItem::Tertiary;
    if (mb.count(MouseButton::Right)) res |= PickingPressItem::Secondary;
    return res;
}

template <typename E>
auto send(PickingState state, PickingPressState pressState, PickingHoverState hoverState,
          bool updatePrev = true, bool markAsUsed = true) {
    return [state, pressState, hoverState, updatePrev, markAsUsed](
               const E& fsmEvent, FsmState& fsmState, PreviousFsmState& prev, PressFsmState& press,
               PickingManager* pickingManager) {
        auto res = pickingManager->getPickingActionFromIndex(fsmState.active_globalId);
        if (res.index == 0 || !res.action) return;

        auto me = fsmEvent.event;
        const PickingPressItem pressItem = mouseButtonToPressItem(me->button());
        const PickingPressItems pressedState = mouseButtonsToPressItems(me->buttonState());

        PickingEvent pe(res.action, me, state, pressState, pressItem, hoverState, pressedState,
                        fsmState.active_globalId, fsmEvent.globalId, press.globalId, prev.globalId,
                        press.ndc, prev.ndc);
        fsmEvent.propagator->propagateEvent(&pe, nullptr);

        if (markAsUsed && pe.hasBeenUsed()) me->markAsUsed();
        if (updatePrev) {
            prev.globalId = fsmState.active_globalId;
            prev.ndc = me->ndc();
        }
    };
}

template <typename E>
auto uid() {
    return [](const E& e, FsmState& fsmstate) { fsmstate.active_globalId = e.globalId; };
}

struct Fsm {
    auto operator()() const noexcept {
        using namespace sml;
        const auto idle = sml::state<Idle>;
        const auto hasId = sml::state<HasId>;
        const auto pressing = sml::state<Pressing>;

        const auto uidm = uid<Move>();
        const auto uidp = uid<Press>();
        const auto uidr = uid<Release>();

        using S = PickingState;
        using P = PickingPressState;
        using H = PickingHoverState;

        const auto ups = [](const Press& e, PressFsmState& pressState) {
            pressState.globalId = e.globalId;
            pressState.ndc = e.event->ndc();
        };
        const auto rps = [](PressFsmState& pressState) {
            pressState.globalId = 0;
            pressState.ndc = dvec3{0};
        };

        // guards
        const auto sameId = [](const FsmState& state, const auto& e) -> bool {
            return e.globalId == state.active_globalId;
        };
        const auto diffId = [](const FsmState& state, const auto& e) -> bool {
            return e.globalId != state.active_globalId && e.globalId != 0;
        };
        const auto zeroId = [](const auto& e) -> bool { return e.globalId == 0; };
        const auto zeroMB = [](const FsmState&, const auto& e) -> bool {
            return e.event->buttonState().empty();
        };

        // clang-format off
        return sml::make_transition_table(
           *idle + event<Move>  [!zeroId && zeroMB] / (uidm, send<Move>(S::Started, P::None, H::Enter)) = hasId,
            idle + event<Press> [!zeroId] / (uidp, send<Press>(S::Updated, P::Press, H::Enter)) = pressing,
            idle + event<Release> [!zeroId] / (uidr,  send<Release>(S::Started, P::None, H::Enter)) = hasId,
            idle + sml::on_entry<_> / rps,

            hasId + event<Move>  [sameId] / (send<Move>(S::Updated,  P::None, H::Move)),
            hasId + event<Move>  [zeroId] / (send<Move>(S::Finished, P::None, H::Exit), uidm) = idle,
            hasId + event<Move>  [diffId] / (send<Move>(S::Finished, P::None, H::Exit, false, false), uidm, send<Move>(S::Started, P::None, H::Enter)),
            hasId + event<Press> [sameId] / (ups, send<Press>(S::Updated, P::Press, H::None)) = pressing,
            hasId + sml::on_entry<_> / rps,

            pressing + event<Move>    [sameId]           / (send<Move>(S::Updated, P::Move, H::Move)),
            pressing + event<Move>    [diffId]           / (send<Move>(S::Updated, P::Move, H::Move)),
            pressing + event<Move>    [zeroId]           / (send<Move>(S::Updated, P::Move, H::Move)),

            pressing + event<Release> [sameId && zeroMB] / (send<Release>(S::Updated,  P::Release, H::None)) = hasId,
            pressing + event<Release> [zeroId && zeroMB] / (send<Release>(S::Finished, P::Release, H::Exit), uidr) = idle,
            pressing + event<Release> [diffId && zeroMB] / (send<Release>(S::Finished, P::Release, H::Exit, true, false), uidr, send<Release>(S::Started, P::None, H::Enter)) = hasId,
            pressing + event<Release> [!zeroMB]          / (send<Release>(S::Updated,  P::Release, H::None)),
            pressing + event<Press>                      / (send<Press>  (S::Updated,  P::Press,   H::None)),

            hasId + event<DblClk> [sameId] / (send<DblClk>(S::Updated, P::DoubleClick, H::None)),
            pressing + event<DblClk>       / (send<DblClk>(S::Updated, P::DoubleClick, H::None))
        );
        // clang-format on
    }
};

}  // namespace fsm

struct PickingControllerMouseStateSM {
    PickingControllerMouseStateSM(PickingManager* pickingManager)
        : pickingManager{pickingManager} {}
    PickingManager* pickingManager;
    fsm::FsmState state;
    fsm::PreviousFsmState previousState;
    fsm::PressFsmState pressState;
    sml::sm<fsm::Fsm> sm{state, previousState, pressState, pickingManager};
};

PickingControllerMouseState::PickingControllerMouseState(PickingManager* pickingManager)
    : msm{std::make_unique<PickingControllerMouseStateSM>(pickingManager)} {}

PickingControllerMouseState::~PickingControllerMouseState() = default;

void PickingControllerMouseState::propagateEvent(MouseEvent* e, EventPropagator* propagator,
                                                 size_t globalId) {
    switch (e->state()) {
        case MouseState::Press: {
            msm->sm.process_event(fsm::Press{globalId, e, propagator});
            break;
        }
        case MouseState::Move: {
            msm->sm.process_event(fsm::Move{globalId, e, propagator});
            break;
        }
        case MouseState::Release: {
            msm->sm.process_event(fsm::Release{globalId, e, propagator});
            break;
        }
        case MouseState::DoubleClick: {
            msm->sm.process_event(fsm::DblClk{globalId, e, propagator});
            break;
        }
    }
}

}  // namespace inviwo
<commit_msg>Core: picking controller fix for mouse * handle case when the picking ID under the mouse changes without moving the mouse<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2018-2019 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <inviwo/core/interaction/pickingcontrollermousestate.h>

#include <inviwo/core/interaction/pickingmanager.h>
#include <inviwo/core/interaction/events/eventpropagator.h>
#include <inviwo/core/interaction/events/mouseevent.h>
#include <inviwo/core/interaction/events/pickingevent.h>
#include <inviwo/core/interaction/pickingaction.h>
#include <inviwo/core/interaction/pickingcontroller.h>

#include <sml/sml.hpp>
namespace sml = boost::sml;

namespace inviwo {

namespace fsm {

// State
struct FsmState {
    size_t active_globalId = 0;
};

struct PreviousFsmState {
    size_t globalId = 0;
    dvec3 ndc{0};
};

struct PressFsmState {
    size_t globalId = 0;
    dvec3 ndc{0};
};

// States
struct Idle {};
struct HasId {};
struct Pressing {};

// events;
struct BaseEvent {
    BaseEvent(const size_t globalId, MouseEvent* event, EventPropagator* propagator)
        : globalId{globalId}, event{event}, propagator{propagator} {}
    const size_t globalId;
    MouseEvent* event;
    EventPropagator* propagator;
};
struct Move : BaseEvent {
    using BaseEvent::BaseEvent;
};
struct Press : BaseEvent {
    using BaseEvent::BaseEvent;
};
struct Release : BaseEvent {
    using BaseEvent::BaseEvent;
};
struct DblClk : BaseEvent {
    using BaseEvent::BaseEvent;
};

PickingPressItem mouseButtonToPressItem(MouseButton mb) {
    switch (mb) {
        case MouseButton::None:
            return PickingPressItem::None;
        case MouseButton::Left:
            return PickingPressItem::Primary;
        case MouseButton::Middle:
            return PickingPressItem::Tertiary;
        case MouseButton::Right:
            return PickingPressItem::Secondary;
        default:
            return PickingPressItem::None;
    }
}
PickingPressItems mouseButtonsToPressItems(MouseButtons mb) {
    PickingPressItems res = PickingPressItem::None;
    if (mb.count(MouseButton::Left)) res |= PickingPressItem::Primary;
    if (mb.count(MouseButton::Middle)) res |= PickingPressItem::Tertiary;
    if (mb.count(MouseButton::Right)) res |= PickingPressItem::Secondary;
    return res;
}

template <typename E>
auto send(PickingState state, PickingPressState pressState, PickingHoverState hoverState,
          bool updatePrev = true, bool markAsUsed = true) {
    return [state, pressState, hoverState, updatePrev, markAsUsed](
               const E& fsmEvent, FsmState& fsmState, PreviousFsmState& prev, PressFsmState& press,
               PickingManager* pickingManager) {
        auto res = pickingManager->getPickingActionFromIndex(fsmState.active_globalId);
        if (res.index == 0 || !res.action) return;

        auto me = fsmEvent.event;
        const PickingPressItem pressItem = mouseButtonToPressItem(me->button());
        const PickingPressItems pressedState = mouseButtonsToPressItems(me->buttonState());

        PickingEvent pe(res.action, me, state, pressState, pressItem, hoverState, pressedState,
                        fsmState.active_globalId, fsmEvent.globalId, press.globalId, prev.globalId,
                        press.ndc, prev.ndc);
        fsmEvent.propagator->propagateEvent(&pe, nullptr);

        if (markAsUsed && pe.hasBeenUsed()) me->markAsUsed();
        if (updatePrev) {
            prev.globalId = fsmState.active_globalId;
            prev.ndc = me->ndc();
        }
    };
}

template <typename E>
auto uid() {
    return [](const E& e, FsmState& fsmstate) { fsmstate.active_globalId = e.globalId; };
}

struct Fsm {
    auto operator()() const noexcept {
        using namespace sml;
        const auto idle = sml::state<Idle>;
        const auto hasId = sml::state<HasId>;
        const auto pressing = sml::state<Pressing>;

        const auto uidm = uid<Move>();
        const auto uidp = uid<Press>();
        const auto uidr = uid<Release>();

        using S = PickingState;
        using P = PickingPressState;
        using H = PickingHoverState;

        const auto ups = [](const Press& e, PressFsmState& pressState) {
            pressState.globalId = e.globalId;
            pressState.ndc = e.event->ndc();
        };
        const auto rps = [](PressFsmState& pressState) {
            pressState.globalId = 0;
            pressState.ndc = dvec3{0};
        };

        // guards
        const auto sameId = [](const FsmState& state, const auto& e) -> bool {
            return e.globalId == state.active_globalId;
        };
        const auto diffId = [](const FsmState& state, const auto& e) -> bool {
            return e.globalId != state.active_globalId && e.globalId != 0;
        };
        const auto zeroId = [](const auto& e) -> bool { return e.globalId == 0; };
        const auto zeroMB = [](const FsmState&, const auto& e) -> bool {
            return e.event->buttonState().empty();
        };

        // clang-format off
        return sml::make_transition_table(
           *idle + event<Move>  [!zeroId && zeroMB] / (uidm, send<Move>(S::Started, P::None, H::Enter)) = hasId,
            idle + event<Press> [!zeroId] / (uidp, send<Press>(S::Updated, P::Press, H::Enter)) = pressing,
            idle + event<Release> [!zeroId] / (uidr,  send<Release>(S::Started, P::None, H::Enter)) = hasId,
            idle + sml::on_entry<_> / rps,

            hasId + event<Move>  [sameId] / (send<Move>(S::Updated,  P::None, H::Move)),
            hasId + event<Move>  [zeroId] / (send<Move>(S::Finished, P::None, H::Exit), uidm) = idle,
            hasId + event<Move>  [diffId] / (send<Move>(S::Finished, P::None, H::Exit, false, false), uidm, send<Move>(S::Started, P::None, H::Enter)),
            hasId + event<Press> [sameId] / (ups, send<Press>(S::Updated, P::Press, H::None)) = pressing,
            hasId + event<Press> [diffId] / (send<Press>(S::Finished, P::None, H::Exit, false, false), ups, uidp, send<Press>(S::Updated, P::Press, H::Enter)) = pressing,
            hasId + sml::on_entry<_> / rps,

            pressing + event<Move>    [sameId]           / (send<Move>(S::Updated, P::Move, H::Move)),
            pressing + event<Move>    [diffId]           / (send<Move>(S::Updated, P::Move, H::Move)),
            pressing + event<Move>    [zeroId]           / (send<Move>(S::Updated, P::Move, H::Move)),

            pressing + event<Release> [sameId && zeroMB] / (send<Release>(S::Updated,  P::Release, H::None)) = hasId,
            pressing + event<Release> [zeroId && zeroMB] / (send<Release>(S::Finished, P::Release, H::Exit), uidr) = idle,
            pressing + event<Release> [diffId && zeroMB] / (send<Release>(S::Finished, P::Release, H::Exit, true, false), uidr, send<Release>(S::Started, P::None, H::Enter)) = hasId,
            pressing + event<Release> [!zeroMB]          / (send<Release>(S::Updated,  P::Release, H::None)),
            pressing + event<Press>                      / (send<Press>  (S::Updated,  P::Press,   H::None)),

            hasId + event<DblClk> [sameId] / (send<DblClk>(S::Updated, P::DoubleClick, H::None)),
            pressing + event<DblClk>       / (send<DblClk>(S::Updated, P::DoubleClick, H::None))
        );
        // clang-format on
    }
};

}  // namespace fsm

struct PickingControllerMouseStateSM {
    PickingControllerMouseStateSM(PickingManager* pickingManager)
        : pickingManager{pickingManager} {}
    PickingManager* pickingManager;
    fsm::FsmState state;
    fsm::PreviousFsmState previousState;
    fsm::PressFsmState pressState;
    sml::sm<fsm::Fsm> sm{state, previousState, pressState, pickingManager};
};

PickingControllerMouseState::PickingControllerMouseState(PickingManager* pickingManager)
    : msm{std::make_unique<PickingControllerMouseStateSM>(pickingManager)} {}

PickingControllerMouseState::~PickingControllerMouseState() = default;

void PickingControllerMouseState::propagateEvent(MouseEvent* e, EventPropagator* propagator,
                                                 size_t globalId) {
    switch (e->state()) {
        case MouseState::Press: {
            msm->sm.process_event(fsm::Press{globalId, e, propagator});
            break;
        }
        case MouseState::Move: {
            msm->sm.process_event(fsm::Move{globalId, e, propagator});
            break;
        }
        case MouseState::Release: {
            msm->sm.process_event(fsm::Release{globalId, e, propagator});
            break;
        }
        case MouseState::DoubleClick: {
            msm->sm.process_event(fsm::DblClk{globalId, e, propagator});
            break;
        }
    }
}

}  // namespace inviwo
<|endoftext|>


<commit_before>/****************************************************************************
*
* NAME: smbPitchShift.cpp
* VERSION: 1.2
* HOME URL: http://blogs.zynaptiq.com/bernsee
* KNOWN BUGS: none
*
* SYNOPSIS: Routine for doing pitch shifting while maintaining
* duration using the Short Time Fourier Transform.
*
* DESCRIPTION: The routine takes a pitchShift factor value which is between 0.5
* (one octave down) and 2. (one octave up). A value of exactly 1 does not change
* the pitch. numSampsToProcess tells the routine how many samples in indata[0...
* numSampsToProcess-1] should be pitch shifted and moved to outdata[0 ...
* numSampsToProcess-1]. The two buffers can be identical (ie. it can process the
* data in-place). fftFrameSize defines the FFT frame size used for the
* processing. Typical values are 1024, 2048 and 4096. It MUST be a power of 2.
* oversamp is the STFT oversampling factor which also determines the overlap
* between adjacent STFT frames. It should at least be 4 for moderate scaling
* ratios. A value of 32 is recommended for best quality. sampleRate takes the
* sample rate for the signal in unit Hz, ie. 44100 for 44.1 kHz audio. The data
* passed to the routine in indata[] should be in the range [-1.0, 1.0), which is
* also the output range for the data, make sure you scale the data accordingly
* (for 16bit signed integers you would have to divide (and multiply) by 32768).
*
* COPYRIGHT 1999-2015 Stephan M. Bernsee <s.bernsee [AT] zynaptiq [DOT] com>
*
* 						The Wide Open License (WOL)
*
* Permission to use, copy, modify, distribute and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice and this license appear in all source copies.
* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF
* ANY KIND. See http://www.dspguru.com/wol.htm for more information.
*
*****************************************************************************/

#ifndef SMBPITCHSHIFT_HPP
#define SMBPITCHSHIFT_HPP

#include <algorithm>
#include <cmath>
#include <cstdint>

namespace smb
{
    namespace
    {
        constexpr float pi = 3.14159265358979323846F;

        // Use own implementation because std::complex has a poor performance
        template <class T>
        struct Complex final
        {
            constexpr Complex<T> operator+(const Complex& other) const noexcept
            {
                return Complex{real + other.real, imag + other.imag};
            }

            constexpr Complex<T>& operator+=(const Complex& other)
            {
                real += other.real;
                imag += other.imag;
                return *this;
            }

            constexpr Complex<T> operator-(const Complex& other) const noexcept
            {
                return Complex{real - other.real, imag - other.imag};
            }

            constexpr Complex<T> operator-() const noexcept
            {
                return Complex{-real, -imag};
            }

            constexpr Complex<T>& operator-=(const Complex& other) noexcept
            {
                real -= other.real;
                imag -= other.imag;
                return *this;
            }

            constexpr Complex<T> operator*(const Complex& other) const noexcept
            {
                return Complex{real * other.real - imag * other.imag, real * other.imag + imag * other.real};
            }

            constexpr Complex<T>& operator*=(const Complex& other) noexcept
            {
                float tempReal = real;
                real = tempReal * other.real - imag * other.imag;
                imag = tempReal * other.imag + imag * other.real;
                return *this;
            }

            inline T magnitude() const noexcept
            {
                return sqrt(real * real + imag * imag);
            }

            T real;
            T imag;
        };

        template <int32_t sign, uint32_t fftFrameSize>
        void fft(Complex<float>* fftBuffer) noexcept
        {
            // Bit-reversal permutation applied to a sequence of fftFrameSize items
            for (uint32_t i = 1; i < fftFrameSize - 1; ++i)
            {
                uint32_t j = 0;

                for (uint32_t bitm = 1; bitm < fftFrameSize; bitm <<= 1)
                {
                    if (i & bitm) ++j;
                    j <<= 1;
                }
                j >>= 1;

                if (i < j)
                    std::swap(fftBuffer[i], fftBuffer[j]);
            }

            // Iterative form of Danielson-Lanczos lemma
            uint32_t step = 2;
            for (uint32_t i = 1; i < fftFrameSize; i <<= 1, step <<= 1)
            {
                const uint32_t step2 = step >> 1;
                const float arg = pi / step2;

                const Complex<float> w{std::cos(arg), std::sin(arg) * sign};
                Complex<float> u{1.0F, 0.0F};
                for (uint32_t j = 0; j < step2; ++j)
                {
                    for (uint32_t k = j; k < fftFrameSize; k += step)
                    {
                        const Complex<float> temp = fftBuffer[k + step2] * u;
                        fftBuffer[k + step2] = fftBuffer[k] - temp;
                        fftBuffer[k] += temp;
                    }

                    u *= w;
                }
            }
        }
    }

    template <uint32_t fftFrameSize, uint32_t oversamp>
    class PitchShift final
    {
    public:
        PitchShift()
        {
            // Hann window
            for (uint32_t k = 0; k < fftFrameSize; ++k)
                window[k] = 0.5F * (1.0F + std::cos(2.0F * pi * static_cast<float>(k) / static_cast<float>(fftFrameSize)));
        }

        /*
            Routine process(). See top of file for explanation
            Purpose: doing pitch shifting while maintaining duration using the Short
            Time Fourier Transform.
            Author: (c)1999-2015 Stephan M. Bernsee <s.bernsee [AT] zynaptiq [DOT] com>
        */
        void process(const float pitchShift, const uint32_t numSampsToProcess,
                     const uint32_t sampleRate, const float* indata, float* outdata) noexcept
        {
            // set up some handy variables
            constexpr uint32_t fftFrameSizeHalf = fftFrameSize / 2;
            constexpr uint32_t stepSize = fftFrameSize / oversamp;
            constexpr uint32_t inFifoLatency = fftFrameSize - stepSize;
            const float freqPerBin = static_cast<float>(sampleRate) / static_cast<float>(fftFrameSize);
            const float expected = 2.0F * pi * static_cast<float>(stepSize) / static_cast<float>(fftFrameSize);
            if (rover == 0) rover = inFifoLatency;

            // main processing loop
            for (uint32_t i = 0; i < numSampsToProcess; ++i)
            {
                // As long as we have not yet collected enough data just read in
                inFifo[rover] = indata[i];
                outdata[i] = outFifo[rover - inFifoLatency];
                ++rover;

                // now we have enough data for processing
                if (rover >= fftFrameSize)
                {
                    rover = inFifoLatency;

                    // do windowing
                    for (uint32_t k = 0; k < fftFrameSize; ++k)
                        fftWorksp[k] = { inFifo[k] * window[k], 0.0F };

                    // ***************** ANALYSIS *******************
                    // do transform
                    fft<-1, fftFrameSize>(fftWorksp);

                    // this is the analysis step
                    for (uint32_t k = 0; k < fftFrameSizeHalf + 1; ++k)
                    {
                        const Complex<float>& current = fftWorksp[k];

                        // compute magnitude and phase
                        const float magn = 2.0F * current.magnitude();
                        const float signx = (current.imag > 0.0F) ? 1.0F : -1.0F;
                        const float phase = (current.imag == 0.0F) ? 0.0F :
                            (current.real == 0.0F) ? signx * pi / 2.0F :
                            std::atan2(current.imag, current.real);

                        // compute phase difference
                        float tmp = phase - lastPhase[k];
                        lastPhase[k] = phase;

                        // subtract expected phase difference
                        tmp -= static_cast<float>(k) * expected;

                        // map delta phase into +/- Pi interval
                        int32_t qpd = static_cast<int32_t>(tmp / pi);
                        if (qpd >= 0) qpd += qpd & 1;
                        else qpd -= qpd & 1;
                        tmp -= pi * static_cast<float>(qpd);

                        // get deviation from bin frequency from the +/- Pi interval
                        tmp = oversamp * tmp / (2.0F * pi);

                        // compute the k-th partials' true frequency
                        tmp = static_cast<float>(k) * freqPerBin + tmp * freqPerBin;

                        // store magnitude and true frequency in analysis arrays
                        anaMagn[k] = magn;
                        anaFreq[k] = tmp;
                    }

                    // ***************** PROCESSING *******************
                    // this does the actual pitch shifting
                    std::fill(std::begin(synMagn), std::begin(synMagn) + fftFrameSize, 0.0F);
                    std::fill(std::begin(synFreq), std::begin(synFreq) + fftFrameSize, 0.0F);
                    for (uint32_t k = 0; k < fftFrameSizeHalf + 1; ++k)
                    {
                        const uint32_t index = static_cast<uint32_t>(k * pitchShift);
                        if (index > fftFrameSizeHalf) break;
                        synMagn[index] += anaMagn[k];
                        synFreq[index] = anaFreq[k] * pitchShift;
                    }

                    // ***************** SYNTHESIS *******************
                    // this is the synthesis step
                    for (uint32_t k = 0; k < fftFrameSizeHalf + 1; ++k)
                    {
                        // get magnitude and true frequency from synthesis arrays
                        const float magn = synMagn[k];
                        float tmp = synFreq[k];

                        // subtract bin mid frequency
                        tmp -= static_cast<float>(k) * freqPerBin;

                        // get bin deviation from freq deviation
                        tmp /= freqPerBin;

                        // take oversampling factor into account
                        tmp = 2.0F * pi * tmp / oversamp;

                        // add the overlap phase advance back in
                        tmp += static_cast<float>(k) * expected;

                        // accumulate delta phase to get bin phase
                        sumPhase[k] += tmp;
                        const float phase = sumPhase[k];

                        // get real and imag part and re-interleave
                        fftWorksp[k] = { magn * std::cos(phase), magn * std::sin(phase) };
                    }

                    // zero negative frequencies
                    for (uint32_t k = fftFrameSize + 1; k < fftFrameSize; ++k)
                        fftWorksp[k] = {0.0F, 0.0F};

                    // do inverse transform
                    fft<1, fftFrameSize>(fftWorksp);

                    // do windowing and add to output accumulator
                    for (uint32_t k = 0; k < fftFrameSize; ++k)
                        outputAccum[k] += 2.0F * window[k] * fftWorksp[k].real / (fftFrameSizeHalf * oversamp);

                    uint32_t k;
                    for (k = 0 ; k < stepSize; ++k)
                        outFifo[k] = outputAccum[k];
                    // shift accumulator
                    uint32_t j;
                    for (j = 0; k < fftFrameSize; ++k, ++j)
                        outputAccum[j] = outputAccum[k];
                    for (; j < fftFrameSize; ++j)
                        outputAccum[j] = 0.0;

                    // move input FIFO
                    for (k = 0; k < inFifoLatency; ++k)
                        inFifo[k] = inFifo[k + stepSize];
                }
            }
        }

    private:
        float window[fftFrameSize]; // the windowing function
        float inFifo[fftFrameSize]{0.0F};
        float outFifo[fftFrameSize]{0.0F};
        Complex<float> fftWorksp[fftFrameSize]{{0.0F, 0.0F}};
        float lastPhase[fftFrameSize / 2 + 1]{0.0F};
        float sumPhase[fftFrameSize / 2 + 1]{0.0F};
        float outputAccum[2 * fftFrameSize]{0.0F};
        float anaFreq[fftFrameSize]{0.0F};
        float anaMagn[fftFrameSize]{0.0F};
        float synFreq[fftFrameSize]{0.0F};
        float synMagn[fftFrameSize]{0.0F};
        uint32_t rover = 0;
    };
}

#endif
<commit_msg>Make the constructor of PitchShift noexcept<commit_after>/****************************************************************************
*
* NAME: smbPitchShift.cpp
* VERSION: 1.2
* HOME URL: http://blogs.zynaptiq.com/bernsee
* KNOWN BUGS: none
*
* SYNOPSIS: Routine for doing pitch shifting while maintaining
* duration using the Short Time Fourier Transform.
*
* DESCRIPTION: The routine takes a pitchShift factor value which is between 0.5
* (one octave down) and 2. (one octave up). A value of exactly 1 does not change
* the pitch. numSampsToProcess tells the routine how many samples in indata[0...
* numSampsToProcess-1] should be pitch shifted and moved to outdata[0 ...
* numSampsToProcess-1]. The two buffers can be identical (ie. it can process the
* data in-place). fftFrameSize defines the FFT frame size used for the
* processing. Typical values are 1024, 2048 and 4096. It MUST be a power of 2.
* oversamp is the STFT oversampling factor which also determines the overlap
* between adjacent STFT frames. It should at least be 4 for moderate scaling
* ratios. A value of 32 is recommended for best quality. sampleRate takes the
* sample rate for the signal in unit Hz, ie. 44100 for 44.1 kHz audio. The data
* passed to the routine in indata[] should be in the range [-1.0, 1.0), which is
* also the output range for the data, make sure you scale the data accordingly
* (for 16bit signed integers you would have to divide (and multiply) by 32768).
*
* COPYRIGHT 1999-2015 Stephan M. Bernsee <s.bernsee [AT] zynaptiq [DOT] com>
*
* 						The Wide Open License (WOL)
*
* Permission to use, copy, modify, distribute and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice and this license appear in all source copies.
* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF
* ANY KIND. See http://www.dspguru.com/wol.htm for more information.
*
*****************************************************************************/

#ifndef SMBPITCHSHIFT_HPP
#define SMBPITCHSHIFT_HPP

#include <algorithm>
#include <cmath>
#include <cstdint>

namespace smb
{
    namespace
    {
        constexpr float pi = 3.14159265358979323846F;

        // Use own implementation because std::complex has a poor performance
        template <class T>
        struct Complex final
        {
            constexpr Complex<T> operator+(const Complex& other) const noexcept
            {
                return Complex{real + other.real, imag + other.imag};
            }

            constexpr Complex<T>& operator+=(const Complex& other)
            {
                real += other.real;
                imag += other.imag;
                return *this;
            }

            constexpr Complex<T> operator-(const Complex& other) const noexcept
            {
                return Complex{real - other.real, imag - other.imag};
            }

            constexpr Complex<T> operator-() const noexcept
            {
                return Complex{-real, -imag};
            }

            constexpr Complex<T>& operator-=(const Complex& other) noexcept
            {
                real -= other.real;
                imag -= other.imag;
                return *this;
            }

            constexpr Complex<T> operator*(const Complex& other) const noexcept
            {
                return Complex{real * other.real - imag * other.imag, real * other.imag + imag * other.real};
            }

            constexpr Complex<T>& operator*=(const Complex& other) noexcept
            {
                float tempReal = real;
                real = tempReal * other.real - imag * other.imag;
                imag = tempReal * other.imag + imag * other.real;
                return *this;
            }

            inline T magnitude() const noexcept
            {
                return sqrt(real * real + imag * imag);
            }

            T real;
            T imag;
        };

        template <int32_t sign, uint32_t fftFrameSize>
        void fft(Complex<float>* fftBuffer) noexcept
        {
            // Bit-reversal permutation applied to a sequence of fftFrameSize items
            for (uint32_t i = 1; i < fftFrameSize - 1; ++i)
            {
                uint32_t j = 0;

                for (uint32_t bitm = 1; bitm < fftFrameSize; bitm <<= 1)
                {
                    if (i & bitm) ++j;
                    j <<= 1;
                }
                j >>= 1;

                if (i < j)
                    std::swap(fftBuffer[i], fftBuffer[j]);
            }

            // Iterative form of Danielson-Lanczos lemma
            uint32_t step = 2;
            for (uint32_t i = 1; i < fftFrameSize; i <<= 1, step <<= 1)
            {
                const uint32_t step2 = step >> 1;
                const float arg = pi / step2;

                const Complex<float> w{std::cos(arg), std::sin(arg) * sign};
                Complex<float> u{1.0F, 0.0F};
                for (uint32_t j = 0; j < step2; ++j)
                {
                    for (uint32_t k = j; k < fftFrameSize; k += step)
                    {
                        const Complex<float> temp = fftBuffer[k + step2] * u;
                        fftBuffer[k + step2] = fftBuffer[k] - temp;
                        fftBuffer[k] += temp;
                    }

                    u *= w;
                }
            }
        }
    }

    template <uint32_t fftFrameSize, uint32_t oversamp>
    class PitchShift final
    {
    public:
        PitchShift() noexcept
        {
            // Hann window
            for (uint32_t k = 0; k < fftFrameSize; ++k)
                window[k] = 0.5F * (1.0F + std::cos(2.0F * pi * static_cast<float>(k) / static_cast<float>(fftFrameSize)));
        }

        /*
            Routine process(). See top of file for explanation
            Purpose: doing pitch shifting while maintaining duration using the Short
            Time Fourier Transform.
            Author: (c)1999-2015 Stephan M. Bernsee <s.bernsee [AT] zynaptiq [DOT] com>
        */
        void process(const float pitchShift, const uint32_t numSampsToProcess,
                     const uint32_t sampleRate, const float* indata, float* outdata) noexcept
        {
            // set up some handy variables
            constexpr uint32_t fftFrameSizeHalf = fftFrameSize / 2;
            constexpr uint32_t stepSize = fftFrameSize / oversamp;
            constexpr uint32_t inFifoLatency = fftFrameSize - stepSize;
            const float freqPerBin = static_cast<float>(sampleRate) / static_cast<float>(fftFrameSize);
            const float expected = 2.0F * pi * static_cast<float>(stepSize) / static_cast<float>(fftFrameSize);
            if (rover == 0) rover = inFifoLatency;

            // main processing loop
            for (uint32_t i = 0; i < numSampsToProcess; ++i)
            {
                // As long as we have not yet collected enough data just read in
                inFifo[rover] = indata[i];
                outdata[i] = outFifo[rover - inFifoLatency];
                ++rover;

                // now we have enough data for processing
                if (rover >= fftFrameSize)
                {
                    rover = inFifoLatency;

                    // do windowing
                    for (uint32_t k = 0; k < fftFrameSize; ++k)
                        fftWorksp[k] = { inFifo[k] * window[k], 0.0F };

                    // ***************** ANALYSIS *******************
                    // do transform
                    fft<-1, fftFrameSize>(fftWorksp);

                    // this is the analysis step
                    for (uint32_t k = 0; k < fftFrameSizeHalf + 1; ++k)
                    {
                        const Complex<float>& current = fftWorksp[k];

                        // compute magnitude and phase
                        const float magn = 2.0F * current.magnitude();
                        const float signx = (current.imag > 0.0F) ? 1.0F : -1.0F;
                        const float phase = (current.imag == 0.0F) ? 0.0F :
                            (current.real == 0.0F) ? signx * pi / 2.0F :
                            std::atan2(current.imag, current.real);

                        // compute phase difference
                        float tmp = phase - lastPhase[k];
                        lastPhase[k] = phase;

                        // subtract expected phase difference
                        tmp -= static_cast<float>(k) * expected;

                        // map delta phase into +/- Pi interval
                        int32_t qpd = static_cast<int32_t>(tmp / pi);
                        if (qpd >= 0) qpd += qpd & 1;
                        else qpd -= qpd & 1;
                        tmp -= pi * static_cast<float>(qpd);

                        // get deviation from bin frequency from the +/- Pi interval
                        tmp = oversamp * tmp / (2.0F * pi);

                        // compute the k-th partials' true frequency
                        tmp = static_cast<float>(k) * freqPerBin + tmp * freqPerBin;

                        // store magnitude and true frequency in analysis arrays
                        anaMagn[k] = magn;
                        anaFreq[k] = tmp;
                    }

                    // ***************** PROCESSING *******************
                    // this does the actual pitch shifting
                    std::fill(std::begin(synMagn), std::begin(synMagn) + fftFrameSize, 0.0F);
                    std::fill(std::begin(synFreq), std::begin(synFreq) + fftFrameSize, 0.0F);
                    for (uint32_t k = 0; k < fftFrameSizeHalf + 1; ++k)
                    {
                        const uint32_t index = static_cast<uint32_t>(k * pitchShift);
                        if (index > fftFrameSizeHalf) break;
                        synMagn[index] += anaMagn[k];
                        synFreq[index] = anaFreq[k] * pitchShift;
                    }

                    // ***************** SYNTHESIS *******************
                    // this is the synthesis step
                    for (uint32_t k = 0; k < fftFrameSizeHalf + 1; ++k)
                    {
                        // get magnitude and true frequency from synthesis arrays
                        const float magn = synMagn[k];
                        float tmp = synFreq[k];

                        // subtract bin mid frequency
                        tmp -= static_cast<float>(k) * freqPerBin;

                        // get bin deviation from freq deviation
                        tmp /= freqPerBin;

                        // take oversampling factor into account
                        tmp = 2.0F * pi * tmp / oversamp;

                        // add the overlap phase advance back in
                        tmp += static_cast<float>(k) * expected;

                        // accumulate delta phase to get bin phase
                        sumPhase[k] += tmp;
                        const float phase = sumPhase[k];

                        // get real and imag part and re-interleave
                        fftWorksp[k] = { magn * std::cos(phase), magn * std::sin(phase) };
                    }

                    // zero negative frequencies
                    for (uint32_t k = fftFrameSize + 1; k < fftFrameSize; ++k)
                        fftWorksp[k] = {0.0F, 0.0F};

                    // do inverse transform
                    fft<1, fftFrameSize>(fftWorksp);

                    // do windowing and add to output accumulator
                    for (uint32_t k = 0; k < fftFrameSize; ++k)
                        outputAccum[k] += 2.0F * window[k] * fftWorksp[k].real / (fftFrameSizeHalf * oversamp);

                    uint32_t k;
                    for (k = 0 ; k < stepSize; ++k)
                        outFifo[k] = outputAccum[k];
                    // shift accumulator
                    uint32_t j;
                    for (j = 0; k < fftFrameSize; ++k, ++j)
                        outputAccum[j] = outputAccum[k];
                    for (; j < fftFrameSize; ++j)
                        outputAccum[j] = 0.0;

                    // move input FIFO
                    for (k = 0; k < inFifoLatency; ++k)
                        inFifo[k] = inFifo[k + stepSize];
                }
            }
        }

    private:
        float window[fftFrameSize]; // the windowing function
        float inFifo[fftFrameSize]{0.0F};
        float outFifo[fftFrameSize]{0.0F};
        Complex<float> fftWorksp[fftFrameSize]{{0.0F, 0.0F}};
        float lastPhase[fftFrameSize / 2 + 1]{0.0F};
        float sumPhase[fftFrameSize / 2 + 1]{0.0F};
        float outputAccum[2 * fftFrameSize]{0.0F};
        float anaFreq[fftFrameSize]{0.0F};
        float anaMagn[fftFrameSize]{0.0F};
        float synFreq[fftFrameSize]{0.0F};
        float synMagn[fftFrameSize]{0.0F};
        uint32_t rover = 0;
    };
}

#endif
<|endoftext|>


<commit_before>#include <mbed.h>
#include "ReceiverIR.h"

Serial pc(USBTX, USBRX); // tx, rx
ReceiverIR ir_rx(p3);
Ticker ledTicker;

int receive(RemoteIR::Format *format, uint8_t *buf, int bufsiz, int timeout = 100) {
    int cnt = 0;
    while (ir_rx.getState() != ReceiverIR::Received) {
        cnt++;
        if (timeout < cnt) {
            return -1;
        }
    }

    return ir_rx.getData(format, buf, bufsiz * 8);
}

int main(void) {

    while (1) {
        uint8_t buf1[32];
        int bitlength1;
        RemoteIR::Format format;

        memset(buf1, 0x00, sizeof(buf1));

        {
            bitlength1 = receive(&format, buf1, sizeof(buf1));
            if (bitlength1 < 0) {
                continue;
            }

			const int n = bitlength1 / 8 + (((bitlength1 % 8) != 0) ? 1 : 0);
		    for (int i = 0; i < n; i++) {
		        pc.printf("%02X", buf1[i]);
		    }
        }
    }
}<commit_msg>Display button pressed<commit_after>#include <mbed.h>
#include "ReceiverIR.h"
#include "MicroBit.h"

Serial pc(USBTX, USBRX); // tx, rx
ReceiverIR ir_rx(p3);
Ticker ledTicker;

int receive(RemoteIR::Format *format, uint8_t *buf, int bufsiz, int timeout = 100) {
    int cnt = 0;
    while (ir_rx.getState() != ReceiverIR::Received) {
        cnt++;
        if (timeout < cnt) {
            return -1;
        }
    }

    return ir_rx.getData(format, buf, bufsiz * 8);
}

int main(void) {

    MicroBitDisplay display;
	display.scroll("Press a button on the remote :)");

    while (1) {
        uint8_t buf1[32];
        int bitlength1;
        RemoteIR::Format format;

        memset(buf1, 0x00, sizeof(buf1));
        {
            bitlength1 = receive(&format, buf1, sizeof(buf1));
            if (bitlength1 < 0) {
                continue;
            }

			const int n = bitlength1 / 8 + (((bitlength1 % 8) != 0) ? 1 : 0);

			if (buf1[0] == 0x00 && buf1[1] == 0xBF) {
				if (buf1[2] == 0x00 && buf1[3] == 0xFF) {
					display.printChar('1');
				}
				if (buf1[2] == 0x01 && buf1[3] == 0xFE) {
					display.printChar('2');
				}
				if (buf1[2] == 0x02 && buf1[3] == 0xFD) {
					display.printChar('3');
				}
				if (buf1[2] == 0x04 && buf1[3] == 0xFB) {
					display.printChar('4');
				}
				if (buf1[2] == 0x05 && buf1[3] == 0xFA) {
					display.printChar('5');
				}
				if (buf1[2] == 0x06 && buf1[3] == 0xF9) {
					display.printChar('6');
				}
				if (buf1[2] == 0x08 && buf1[3] == 0xF7) {
					display.printChar('7');
				}
				if (buf1[2] == 0x09 && buf1[3] == 0xF6) {
					display.printChar('8');
				}
				if (buf1[2] == 0x0A && buf1[3] == 0xF5) {
					display.printChar('9');
				}
				if (buf1[2] == 0x0D && buf1[3] == 0xF2) {
					display.printChar('0');
				}
				if (buf1[2] == 0x0C && buf1[3] == 0xF3) {
					display.printChar('*');
				}
				if (buf1[2] == 0x0E && buf1[3] == 0xF1) {
					display.printChar('#');
				}
				if (buf1[2] == 0x14 && buf1[3] == 0xEB) {
					display.printChar('L');
				}
				if (buf1[2] == 0x16 && buf1[3] == 0xE9) {
					display.printChar('R');
				}
				if (buf1[2] == 0x11 && buf1[3] == 0xEE) {
					display.printChar('U');
				}
				if (buf1[2] == 0x19 && buf1[3] == 0xE6) {
					display.printChar('D');
				}
				if (buf1[2] == 0x15 && buf1[3] == 0xEA) {
					display.scroll("OK!");
				}
			}

			// echo to serial port
		    for (int i = 0; i < n; i++) {
		        pc.printf("%02X", buf1[i]);
		    }

			pc.printf("\n\r");
        }
    }
}
<|endoftext|>


<commit_before>#include "ErrorEstimator.h"

// from STL
#include <algorithm>

// from RooFit
#include "RooMultiVarGaussian.h"
#include "TMatrixDSym.h"
#include "RooArgList.h"
#include "RooArgSet.h"
#include "RooAbsArg.h"
#include "RooRealVar.h"
#include "RooDataSet.h"

// from DooCore
#include "doocore/io/MsgStream.h"
#include "doocore/statistics/general.h"

doocore::statistics::montecarlo::MultiVarGaussianSampleGenerator::MultiVarGaussianSampleGenerator(const RooArgList& values_expected, const TMatrixDSym& covariance)
: mvg_(NULL),
values_expected_(new RooArgSet(values_expected)),
values_mu_(new RooArgList()),
num_generated_(0),
pos_dataset_(0),
dataset_(NULL) {
  using namespace doocore::io;

  TIterator* it = values_expected.createIterator();
  RooAbsArg* arg = NULL;

  while ((arg = dynamic_cast<RooAbsArg*>(it->Next()))) {
    RooRealVar* var = dynamic_cast<RooRealVar*>(arg);
    if (var != NULL) {
      std::string name_copy(std::string(var->GetName())+"_mu");
      RooRealVar* var_copy = new RooRealVar(*var, name_copy.c_str());
      values_mu_->addOwned(*var_copy);
    }
  }
  delete it;

  mvg_ = new RooMultiVarGaussian("mvg", "mvg", *values_expected_, *values_mu_, covariance);
}

doocore::statistics::montecarlo::MultiVarGaussianSampleGenerator::~MultiVarGaussianSampleGenerator() {
  delete mvg_;
  delete values_expected_;
  delete values_mu_;
  if (dataset_ != NULL) {
    delete dataset_;
  }
}

const RooArgSet* doocore::statistics::montecarlo::MultiVarGaussianSampleGenerator::Generate() {
  using namespace doocore::io;

  const RooArgSet* values;
  pos_dataset_++;
  if (dataset_ == NULL || pos_dataset_ >= dataset_->numEntries()) {
    pos_dataset_ = 0;
    int num_generate = std::max(100, 2*static_cast<int>(num_generated_));
    num_generated_ += num_generate;
    if (dataset_ != NULL) {
      delete dataset_;
    }

    dataset_ = mvg_->generate(*values_expected_, num_generate);
  }

  values = dataset_->get(pos_dataset_);
  return values;
}<commit_msg>Statistics: bugfix in MultiVarGaussianSampleGenerator<commit_after>#include "ErrorEstimator.h"

// from STL
#include <algorithm>

// from RooFit
#include "RooMultiVarGaussian.h"
#include "TMatrixDSym.h"
#include "RooArgList.h"
#include "RooArgSet.h"
#include "RooAbsArg.h"
#include "RooRealVar.h"
#include "RooDataSet.h"

// from DooCore
#include "doocore/io/MsgStream.h"
#include "doocore/statistics/general.h"

doocore::statistics::montecarlo::MultiVarGaussianSampleGenerator::MultiVarGaussianSampleGenerator(const RooArgList& values_expected, const TMatrixDSym& covariance)
: mvg_(NULL),
values_expected_(new RooArgSet()),
values_mu_(new RooArgList()),
num_generated_(0),
pos_dataset_(0),
dataset_(NULL) {
  using namespace doocore::io;

  TIterator* it = values_expected.createIterator();
  RooAbsArg* arg = NULL;

  while ((arg = dynamic_cast<RooAbsArg*>(it->Next()))) {
    RooRealVar* var = dynamic_cast<RooRealVar*>(arg);
    if (var != NULL) {
      RooRealVar* var_copy = new RooRealVar(*var, var->GetName());
      values_expected_->addOwned(*var_copy);

      std::string name_copy(std::string(var->GetName())+"_mu");
      RooRealVar* var_copy_mu = new RooRealVar(*var, name_copy.c_str());
      values_mu_->addOwned(*var_copy_mu);
    }
  }
  delete it;

  mvg_ = new RooMultiVarGaussian("mvg", "mvg", *values_expected_, *values_mu_, covariance);
}

doocore::statistics::montecarlo::MultiVarGaussianSampleGenerator::~MultiVarGaussianSampleGenerator() {
  delete mvg_;
  delete values_expected_;
  delete values_mu_;
  if (dataset_ != NULL) {
    delete dataset_;
  }
}

const RooArgSet* doocore::statistics::montecarlo::MultiVarGaussianSampleGenerator::Generate() {
  using namespace doocore::io;

  const RooArgSet* values;
  pos_dataset_++;
  if (dataset_ == NULL || pos_dataset_ >= dataset_->numEntries()) {
    pos_dataset_ = 0;
    int num_generate = std::max(100, 2*static_cast<int>(num_generated_));
    num_generated_ += num_generate;
    if (dataset_ != NULL) {
      delete dataset_;
    }

//    values_expected_->Print();
//    values_mu_->Print();
    dataset_ = mvg_->generate(*values_expected_, num_generate);
  }

  values = dataset_->get(pos_dataset_);
  return values;
}<|endoftext|>