/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */

/*
    Rosegarden
    A MIDI and audio sequencer and musical notation editor.
    Copyright 2000-2026 the Rosegarden development team.
    Modifications and additions Copyright (c) 2023 Mark R. Rubin aka "thanks4opensource" aka "thanks4opensrc"

    This file is Copyright 2003-2006
        D. Michael McIntyre <dmmcintyr@users.sourceforge.net>

    Other copyrights also apply to some parts of this work.  Please
    see the AUTHORS file and individual file headers for details.

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.  See the file
    COPYING included with this distribution for more information.
*/

#ifndef RG_EVENTFILTERDIALOG_H
#define RG_EVENTFILTERDIALOG_H

#include "base/TimeT.h"

#include <QDialog>
#include <QComboBox>

class QCheckBox;
class QWidget;
class QSpinBox;
class QPushButton;
class QGridLayout;

#include <utility>
#include <vector>


namespace Rosegarden
{


class Event;


/// The "Event Filter" dialog.
/**
 * Creates a dialog box to allow the user to dial up various selection
 * criteria used for removing events from a selection.
 *
 * To use: Select some notes in either notation or the matrix.  In the
 * menu, select Edit > Filter Selection.  Dial up whatever filtering criteria
 * you want and press OK.  The selection will be modified accordingly.
 *
 * ??? It would be nice to be able to see the effect of the filtering
 *     in real-time on the selection.
 */
class EventFilterDialog : public QDialog
{
    Q_OBJECT

public:

    explicit EventFilterDialog(QWidget* parent);
    ~EventFilterDialog() override;

    //-------[ accessor functions ]------------------------

    // NOTE: the filterRange type is used to return an A B pair with A and B set
    // according to the state of the related include/exclude combo.  If A > B
    // then this is an inclusive range.  If A < B then it's an exclusive
    // range.  This saves passing around a third variable.
    typedef std::pair<long, long> filterRange;

    filterRange getPitch();
    filterRange getVelocity();
    filterRange getDuration();

    // returns TRUE if the property value falls with in the filterRange
    bool eventInRange(filterRange foo, long property) {
        if (foo.first > foo.second)
            return (property <= foo.second || property >= foo.first);
        else
            return (property >= foo.first && property <= foo.second); }

    /**
     * Used to do the work of deciding whether to keep or reject an event
     * based on the state of the dialog's widgets.  Returns TRUE if an event
     * should continue to be selected.
     *
     * After the dialog has been accepted, keepEvent() can be used to decide
     * whether a particular event should continue to be selected.  See
     * MatrixView::slotFilterSelection() and NotationView::slotFilterSelection()
     * for examples of how to use this routine.
     */
    bool keepEvent(const Event *event);

private:

    // initialize the dialog
    void initDialog();

    void populateDurationCombo(QComboBox *durationCombo);

    // convert duration from combobox index into actual RG duration
    // between 0 and LONG_MAX
    long getDurationFromIndex(unsigned index);

    // simple A B swap used to flip inclusive/exclusive values
    void invert (filterRange &);

    // return inclusive/exclusive toggle states concisely for tidy code
    bool pitchIsInclusive()    { return (m_notePitchIncludeComboBox->currentIndex()    == 0); }
    bool velocityIsInclusive() { return (m_noteVelocityIncludeComboBox->currentIndex() == 0); }
    bool durationIsInclusive() { return (m_noteDurationIncludeComboBox->currentIndex() == 0); }

protected slots:

    // set widget values to include everything
    void slotToggleAll();

    // set widget values to include nothing
    void slotToggleNone();

    // write out settings to QSettings data for next time
    void accept() override;

    // update note name text display and ensure From <= To
    void slotPitchFromChanged(int pitch);
    void slotPitchToChanged(int pitch);

    // ensure From <= To to guarantee a logical range for these sets
    void slotVelocityFromChanged(int velocity);
    void slotVelocityToChanged(int velocity);
    void slotDurationFromChanged(int index);
    void slotDurationToChanged(int index);

    // create a pitch chooser widget sub-dialog to show pitch on staff
    void slotPitchFromChooser();
    void slotPitchToChooser();


private:
    void resetValuesToAll();

    //---------[ data members ]-----------------------------

    QGridLayout* m_layout;

    QComboBox*   m_noteDurationFromComboBox;
    QComboBox*   m_noteDurationIncludeComboBox;
    QComboBox*   m_noteDurationToComboBox;
    QComboBox*   m_notePitchIncludeComboBox;
    QComboBox*   m_noteVelocityIncludeComboBox;

    QPushButton* m_pitchFromChooserButton;
    QPushButton* m_pitchToChooserButton;
    QPushButton* m_buttonAll;
    QPushButton* m_buttonNone;

    QSpinBox*    m_pitchFromSpinBox;
    QSpinBox*    m_pitchToSpinBox;
    QSpinBox*    m_velocityFromSpinBox;
    QSpinBox*    m_velocityToSpinBox;

    QCheckBox*   m_useNotationDuration;
    QCheckBox*   m_selectRests;

    std::vector<timeT> m_comboDurations;

};


}

#endif
