├── .gitignore ├── screenshot.png ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── qequalizerview.h ├── LICENSE ├── QEqualizerView.pro ├── mainwindow.ui ├── README.md └── qequalizerview.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.pro.user -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timschneeb/QEqualizerView/HEAD/screenshot.png -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainWindow w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | 4 | MainWindow::MainWindow(QWidget *parent) : 5 | QMainWindow(parent), 6 | ui(new Ui::MainWindow) 7 | { 8 | ui->setupUi(this); 9 | } 10 | 11 | MainWindow::~MainWindow() 12 | { 13 | delete ui; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class MainWindow; 8 | } 9 | 10 | class MainWindow : public QMainWindow 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit MainWindow(QWidget *parent = nullptr); 16 | ~MainWindow(); 17 | 18 | private: 19 | Ui::MainWindow *ui; 20 | }; 21 | 22 | #endif // MAINWINDOW_H 23 | -------------------------------------------------------------------------------- /qequalizerview.h: -------------------------------------------------------------------------------- 1 | #ifndef EQWIDGET_H 2 | #define EQWIDGET_H 3 | 4 | #include "qcustomplot.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define NUM_BANDS 15 11 | const double bands[NUM_BANDS] = { 25.0, 40.0, 63.0, 100.0, 160.0, 250.0, 400.0, 630.0, 1000.0, 1600.0, 2500.0, 4000.0, 6300.0, 10000.0, 16000.0 }; 12 | const QStringList bands_str = QStringList() << "25" << "40" << "63" << "100" << "160" << "250" << "400" << "630" << "1k" << "1.6k" << "2.5k" << "4k" << "6.3k" << "10k" << "16k"; 13 | 14 | class QEqualizerView : public QCustomPlot 15 | { 16 | Q_OBJECT 17 | public: 18 | QEqualizerView(QWidget* parent); 19 | void mousePressEvent(QMouseEvent *event); 20 | void mouseReleaseEvent(QMouseEvent *event); 21 | void mouseMoveEvent(QMouseEvent *event); 22 | void setDragInfo( int graph = -1, int distance = -1); 23 | signals: 24 | void DataChanged(void); 25 | void EditingFinished(void); 26 | private: 27 | int drag_number = -1; 28 | int dragable_graph_number = -1; 29 | int max_distance_to_add_point = -1; 30 | }; 31 | 32 | #endif // EQWIDGET_H 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 ThePBone 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /QEqualizerView.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2019-10-19T20:20:30 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = QEqualizerView 12 | TEMPLATE = app 13 | 14 | # The following define makes your compiler emit warnings if you use 15 | # any feature of Qt which has been marked as deprecated (the exact warnings 16 | # depend on your compiler). Please consult the documentation of the 17 | # deprecated API in order to know how to port your code away from it. 18 | DEFINES += QT_DEPRECATED_WARNINGS 19 | 20 | # You can also make your code fail to compile if you use deprecated APIs. 21 | # In order to do so, uncomment the following line. 22 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 24 | 25 | CONFIG += c++11 26 | 27 | SOURCES += \ 28 | main.cpp \ 29 | mainwindow.cpp \ 30 | qcustomplot.cpp \ 31 | qequalizerview.cpp 32 | 33 | HEADERS += \ 34 | mainwindow.h \ 35 | qcustomplot.h \ 36 | qequalizerview.h 37 | 38 | FORMS += \ 39 | mainwindow.ui 40 | 41 | # Default rules for deployment. 42 | qnx: target.path = /tmp/$${TARGET}/bin 43 | else: unix:!android: target.path = /opt/$${TARGET}/bin 44 | !isEmpty(target.path): INSTALLS += target 45 | -------------------------------------------------------------------------------- /mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 482 10 | 300 11 | 12 | 13 | 14 | EQ View 15 | 16 | 17 | 18 | 19 | 20 | 21 | background-color: rgb(255, 255, 255); 22 | 23 | 24 | QFrame::StyledPanel 25 | 26 | 27 | QFrame::Raised 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | QEqualizerView 44 | QWidget 45 |
qequalizerview.h
46 | 1 47 |
48 |
49 | 50 | 51 |
52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QEqualizerView 2 | Simple equalizer widget for Qt 3 | 4 | ## Usage 5 | 6 | This is a equalizer widget based on QCustomPlot for Qt. 7 | 8 | _**Use [LiquidEqualizerWidget](https://github.com/ThePBone/LiquidEqualizerWidget) instead!**_ 9 | 10 | Since the `QEqualizerView` class inherits QCustomPlot, you can use its functions to read/write the eq graph. 11 | (Refer to the [docs](https://www.qcustomplot.com/documentation/) if you don't know how) 12 | 13 | ### Customization 14 | The widget is a 15-band equalizer by default. However, you can customize the amount and the interval of these bands. 15 | To do that, go to the file `qequalizerview.h` and modify the following variables/statements: 16 | 17 | | Variable | Description | 18 | |------------------------- |----------------------------------------------------------- | 19 | | `NUM_BANDS` | amount of bands | 20 | | `double bands[]` | numeric values (used as x-coordinates) | 21 | | `QStringList bands_str[]` | string representation of these values (displayed as labels) | 22 | 23 | ### Public signals 24 | Because this class implements its own editing logic, it contains with two signals which can be used to check if a slider has been dragged. 25 | 26 | Of course QCustomPlot provides a lot more signals, check their docs for more information. 27 | 28 | | Signal | Description | 29 | |--------------------- |---------------------------------------------------- | 30 | | `EditingFinished()` | mouse has been released | 31 | | `DataChanged()` | mousebutton is held down and data is being changed | 32 | 33 | ### Access values 34 | You can use the interface of QCustomPlot to access the values of the graph like this: 35 | 36 | ui->eqplot->graph(0)->data()->... 37 | 38 | Now you could iterate though the keys (hz/x-values) to find a value or update an eq-band manually. 39 | Check the QCustomPlot [docs](https://www.qcustomplot.com/documentation/classQCPDataContainer.html) for more information... 40 | ## Screenshot 41 | ![](https://raw.githubusercontent.com/ThePBone/QEqualizerView/master/screenshot.png) 42 | -------------------------------------------------------------------------------- /qequalizerview.cpp: -------------------------------------------------------------------------------- 1 | #include "qequalizerview.h" 2 | 3 | QEqualizerView::QEqualizerView(QWidget* parent) : QCustomPlot(parent) 4 | { 5 | xAxis->setScaleType(QCPAxis::stLogarithmic); 6 | setInteraction(QCP::Interaction::iRangeDrag,true); 7 | setInteraction(QCP::Interaction::iRangeZoom,true); 8 | yAxis->setRange(QCPRange(-12, 12)); 9 | xAxis->setRange(QCPRange(25, 16000)); 10 | addGraph(); 11 | addGraph(); 12 | setDragInfo(0, 20); // data of graph(0) is dragable, 20px margin 13 | 14 | graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, QPen(Qt::black, 1.5), QBrush(Qt::white), 9)); 15 | graph(0)->setPen(QPen(QColor(120, 120, 120), 2)); 16 | 17 | for(int i = 0; i < NUM_BANDS; i++) 18 | graph(0)->addData(bands[i],0); 19 | 20 | QSharedPointer fixedTicker(new QCPAxisTickerText); 21 | xAxis->setTicker(fixedTicker); 22 | fixedTicker->setTickCount(NUM_BANDS); 23 | for(int i = 0; i < NUM_BANDS; i++) 24 | fixedTicker->addTick(bands[i],bands_str.at(i)); 25 | 26 | xAxis->setBasePen(QPen(Qt::white, 1)); 27 | yAxis->setBasePen(QPen(Qt::white, 1)); 28 | xAxis->setTickPen(QPen(Qt::white, 1)); 29 | yAxis->setTickPen(QPen(Qt::white, 1)); 30 | xAxis->setSubTickPen(QPen(Qt::white, 1)); 31 | yAxis->setSubTickPen(QPen(Qt::white, 1)); 32 | xAxis->setTickLabelColor(Qt::white); 33 | yAxis->setTickLabelColor(Qt::white); 34 | xAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine)); 35 | yAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine)); 36 | xAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine)); 37 | yAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine)); 38 | xAxis->grid()->setSubGridVisible(true); 39 | yAxis->grid()->setSubGridVisible(true); 40 | xAxis->grid()->setZeroLinePen(Qt::NoPen); 41 | yAxis->grid()->setZeroLinePen(Qt::NoPen); 42 | QLinearGradient plotGradient; 43 | plotGradient.setStart(0, 0); 44 | plotGradient.setFinalStop(0, 350); 45 | plotGradient.setColorAt(0, QColor(80, 80, 80)); 46 | plotGradient.setColorAt(1, QColor(50, 50, 50)); 47 | setBackground(plotGradient); 48 | QLinearGradient axisRectGradient; 49 | axisRectGradient.setStart(0, 0); 50 | axisRectGradient.setFinalStop(0, 350); 51 | axisRectGradient.setColorAt(0, QColor(80, 80, 80)); 52 | axisRectGradient.setColorAt(1, QColor(30, 30, 30)); 53 | axisRect()->setBackground(axisRectGradient); 54 | } 55 | 56 | void QEqualizerView::setDragInfo(int graph, int distance) 57 | { 58 | dragable_graph_number = graph; 59 | max_distance_to_add_point = distance; 60 | } 61 | 62 | void QEqualizerView::mousePressEvent(QMouseEvent *event) 63 | { 64 | double x,y; 65 | 66 | double best_dist = 1E+300; 67 | int best_index = 0; 68 | if( (dragable_graph_number >= 0) && ( dragable_graph_number < this->graphCount()) ) 69 | { 70 | QCPGraph* pq_graph = this->graph(dragable_graph_number); 71 | pq_graph->pixelsToCoords(event->localPos(),x,y); 72 | 73 | //get nearest band and control it 74 | double nearest = -1; 75 | double nearest_diff = DBL_MAX; 76 | for(int i=0;idata()->size() >= 1 ) 86 | { 87 | for( int n=0; n<(pq_graph->data()->size()); n++ ) 88 | { 89 | double dist = fabs( (pq_graph->data()->begin()+n)->value - y ); 90 | dist += fabs( (pq_graph->data()->begin()+n)->key - x ); 91 | if( dist < best_dist ) 92 | { 93 | best_dist = dist; 94 | best_index = n; 95 | } 96 | } 97 | /*if( max_distance_to_add_point > 0 ) 98 | { 99 | QPointF q_pos_gui = pq_graph->coordsToPixels( (pq_graph->data()->begin()+best_index)->key, (pq_graph->data()->begin()+best_index)->value ); 100 | int dist_px = fabs( event->localPos().x() - q_pos_gui.x()) + fabs( event->localPos().y() - q_pos_gui.y()); 101 | if( dist_px/2 > max_distance_to_add_point ) 102 | { 103 | pq_graph->addData(x,y); 104 | pq_graph->data().data()->sort(); 105 | for( int n=0; n<(pq_graph->data()->size()); n++ ) 106 | { 107 | if( (pq_graph->data()->begin()+n)->value == y && (pq_graph->data()->begin()+n)->key == x ) best_index = n; 108 | } 109 | } 110 | }*/ 111 | drag_number = best_index; 112 | } 113 | } 114 | QCustomPlot::mousePressEvent(event); 115 | } 116 | 117 | void QEqualizerView::mouseReleaseEvent(QMouseEvent *event) 118 | { 119 | drag_number = -1; 120 | if( (dragable_graph_number >= 0) && ( dragable_graph_number < this->graphCount()) ) 121 | { 122 | this->graph(dragable_graph_number)->data().data()->sort(); 123 | } 124 | this->replot(); 125 | emit( EditingFinished() ); 126 | QCustomPlot::mouseReleaseEvent(event); 127 | } 128 | void QEqualizerView::mouseMoveEvent(QMouseEvent *event) 129 | { 130 | double x,y; 131 | 132 | if( (dragable_graph_number >= 0) && ( dragable_graph_number < this->graphCount()) ) 133 | { 134 | QCPGraph* pq_graph = this->graph(dragable_graph_number); 135 | pq_graph->pixelsToCoords(event->localPos(),x,y); 136 | 137 | //get nearest band and control it 138 | double nearest = -1; 139 | double nearest_diff = DBL_MAX; 140 | for(int i=0;i12.0)y=12.0; 151 | else if(y<-12.0)y=-12.0; 152 | //x = round( x*4 ) / 4; //snap to grid 153 | 154 | if( drag_number >= 0 ) 155 | { 156 | (pq_graph->data()->begin()+drag_number)->value = y; 157 | //(pq_graph->data()->begin()+drag_number)->key = x; 158 | emit( DataChanged() ); 159 | 160 | this->replot(); 161 | } 162 | } 163 | 164 | } 165 | --------------------------------------------------------------------------------