Initial commit
This commit is contained in:
1
src/external/qt-color-widgets.repo
vendored
Normal file
1
src/external/qt-color-widgets.repo
vendored
Normal file
@@ -0,0 +1 @@
|
||||
git@github.com:bloerwald/Qt-Color-Widgets.git
|
||||
71
src/external/qt-color-widgets/CMakeLists.txt
vendored
Normal file
71
src/external/qt-color-widgets/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
#
|
||||
# Copyright (C) 2013-2017 Mattia Basaglia
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
set(SOURCES
|
||||
src/abstract_widget_list.cpp
|
||||
src/alphaback.png
|
||||
src/bound_color_selector.cpp
|
||||
src/color_2d_slider.cpp
|
||||
src/color_delegate.cpp
|
||||
src/color_dialog.cpp
|
||||
src/color_line_edit.cpp
|
||||
src/color_list_widget.cpp
|
||||
src/color_names.cpp
|
||||
src/color_palette.cpp
|
||||
src/color_palette_model.cpp
|
||||
src/color_palette_widget.cpp
|
||||
src/color_preview.cpp
|
||||
src/color_selector.cpp
|
||||
src/color_utils.cpp
|
||||
src/color_wheel.cpp
|
||||
src/color_widgets.qrc
|
||||
src/gradient_slider.cpp
|
||||
src/hue_slider.cpp
|
||||
src/swatch.cpp
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
qt-color-widgets/abstract_widget_list.hpp
|
||||
qt-color-widgets/bound_color_selector.hpp
|
||||
qt-color-widgets/color_2d_slider.hpp
|
||||
qt-color-widgets/color_delegate.hpp
|
||||
qt-color-widgets/color_dialog.hpp
|
||||
qt-color-widgets/color_line_edit.hpp
|
||||
qt-color-widgets/color_list_widget.hpp
|
||||
qt-color-widgets/color_palette.hpp
|
||||
qt-color-widgets/color_palette_model.hpp
|
||||
qt-color-widgets/color_palette_widget.hpp
|
||||
qt-color-widgets/color_preview.hpp
|
||||
qt-color-widgets/color_selector.hpp
|
||||
qt-color-widgets/color_wheel.hpp
|
||||
qt-color-widgets/gradient_slider.hpp
|
||||
qt-color-widgets/hue_slider.hpp
|
||||
qt-color-widgets/swatch.hpp
|
||||
)
|
||||
|
||||
qt5_wrap_cpp(SOURCES ${HEADERS})
|
||||
qt5_wrap_ui(SOURCES src/color_dialog.ui src/color_palette_widget.ui)
|
||||
qt5_add_resources(SOURCES src/color_widgets.qrc)
|
||||
|
||||
# Library
|
||||
add_library(ColorWidgets-qt5 ${SOURCES})
|
||||
target_link_libraries(ColorWidgets-qt5 Qt5::Widgets)
|
||||
target_include_directories (ColorWidgets-qt5 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_include_directories (ColorWidgets-qt5 PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_compiler_flag_if_supported (ColorWidgets_CXX_FLAGS "-Wno-error=deprecated-declarations")
|
||||
target_compile_options (ColorWidgets-qt5 PRIVATE ${ColorWidgets_CXX_FLAGS})
|
||||
165
src/external/qt-color-widgets/COPYING
vendored
Normal file
165
src/external/qt-color-widgets/COPYING
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
108
src/external/qt-color-widgets/qt-color-widgets/abstract_widget_list.hpp
vendored
Normal file
108
src/external/qt-color-widgets/qt-color-widgets/abstract_widget_list.hpp
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef ABSTRACT_WIDGET_LIST_HPP
|
||||
#define ABSTRACT_WIDGET_LIST_HPP
|
||||
|
||||
#include <QSignalMapper>
|
||||
#include <QTableWidget>
|
||||
|
||||
class Q_DECL_EXPORT AbstractWidgetList : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AbstractWidgetList(QWidget *parent = 0);
|
||||
~AbstractWidgetList();
|
||||
|
||||
/**
|
||||
* \brief Get the number of items
|
||||
*/
|
||||
int count() const;
|
||||
|
||||
/**
|
||||
* \brief Swap row a and row b
|
||||
*/
|
||||
virtual void swap(int a, int b) = 0;
|
||||
|
||||
|
||||
/// Whether the given row index is valid
|
||||
bool isValidRow(int i) const { return i >= 0 && i < count(); }
|
||||
|
||||
void setRowHeight(int row, int height);
|
||||
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* \brief Remove row i
|
||||
*/
|
||||
void remove(int i);
|
||||
|
||||
/**
|
||||
* \brief append a default row
|
||||
*/
|
||||
virtual void append() = 0;
|
||||
|
||||
Q_SIGNALS:
|
||||
void removed(int i);
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* \brief Create a new row with the given widget
|
||||
*
|
||||
* Must be caled by implementations of append()
|
||||
*/
|
||||
void appendWidget(QWidget* w);
|
||||
|
||||
/**
|
||||
* \brief get the widget found at the given row
|
||||
*/
|
||||
QWidget* widget(int i);
|
||||
|
||||
|
||||
/**
|
||||
* \brief get the widget found at the given row
|
||||
*/
|
||||
template<class T>
|
||||
T* widget_cast(int i) { return qobject_cast<T*>(widget(i)); }
|
||||
|
||||
/**
|
||||
* \brief clear all rows without emitting signals
|
||||
*
|
||||
* May be useful when implementation want to set all values at once
|
||||
*/
|
||||
void clear();
|
||||
|
||||
private Q_SLOTS:
|
||||
void remove_clicked(QWidget* w);
|
||||
void up_clicked(QWidget* w);
|
||||
void down_clicked(QWidget* w);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const p;
|
||||
|
||||
QWidget* create_button(QWidget* data, QSignalMapper*mapper,
|
||||
QIcon icon, QString text,
|
||||
QString tooltip = QString()) const;
|
||||
};
|
||||
|
||||
#endif // ABSTRACT_WIDGET_LIST_HPP
|
||||
44
src/external/qt-color-widgets/qt-color-widgets/bound_color_selector.hpp
vendored
Normal file
44
src/external/qt-color-widgets/qt-color-widgets/bound_color_selector.hpp
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef BOUND_COLOR_SELECTOR_HPP
|
||||
#define BOUND_COLOR_SELECTOR_HPP
|
||||
|
||||
#include "qt-color-widgets/color_selector.hpp"
|
||||
|
||||
namespace color_widgets {
|
||||
/**
|
||||
* \brief A color selector bound to a color reference
|
||||
* \todo Maybe this can be removed
|
||||
*/
|
||||
class Q_DECL_EXPORT BoundColorSelector : public ColorSelector
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QColor* ref;
|
||||
public:
|
||||
explicit BoundColorSelector(QColor* reference, QWidget *parent = 0);
|
||||
|
||||
private Q_SLOTS:
|
||||
void update_reference(QColor);
|
||||
};
|
||||
} // namespace color_widgets
|
||||
#endif // BOUND_COLOR_SELECTOR_HPP
|
||||
127
src/external/qt-color-widgets/qt-color-widgets/color_2d_slider.hpp
vendored
Normal file
127
src/external/qt-color-widgets/qt-color-widgets/color_2d_slider.hpp
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef COLOR_WIDGETS_COLOR_2D_SLIDER_HPP
|
||||
#define COLOR_WIDGETS_COLOR_2D_SLIDER_HPP
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
/**
|
||||
* \brief A 2D slider that edits 2 color components
|
||||
*/
|
||||
class Q_DECL_EXPORT Color2DSlider : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged DESIGNABLE true STORED false )
|
||||
Q_PROPERTY(qreal hue READ hue WRITE setHue DESIGNABLE false )
|
||||
Q_PROPERTY(qreal saturation READ saturation WRITE setSaturation DESIGNABLE false )
|
||||
Q_PROPERTY(qreal value READ value WRITE setValue DESIGNABLE false )
|
||||
/**
|
||||
* \brief Which color component is used on the x axis
|
||||
*/
|
||||
Q_PROPERTY(Component componentX READ componentX WRITE setComponentX NOTIFY componentXChanged)
|
||||
/**
|
||||
* \brief Which color component is used on the y axis
|
||||
*/
|
||||
Q_PROPERTY(Component componentY READ componentY WRITE setComponentY NOTIFY componentYChanged)
|
||||
|
||||
|
||||
public:
|
||||
enum Component {
|
||||
Hue, Saturation, Value
|
||||
};
|
||||
Q_ENUMS(Component)
|
||||
|
||||
explicit Color2DSlider(QWidget *parent = nullptr);
|
||||
~Color2DSlider();
|
||||
|
||||
/// Get current color
|
||||
QColor color() const;
|
||||
|
||||
QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||
|
||||
/// Get current hue in the range [0-1]
|
||||
qreal hue() const;
|
||||
|
||||
/// Get current saturation in the range [0-1]
|
||||
qreal saturation() const;
|
||||
|
||||
/// Get current value in the range [0-1]
|
||||
qreal value() const;
|
||||
|
||||
Component componentX() const;
|
||||
Component componentY() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
/// Set current color
|
||||
void setColor(const QColor& c);
|
||||
|
||||
/**
|
||||
* @param h Hue [0-1]
|
||||
*/
|
||||
void setHue(qreal h);
|
||||
|
||||
/**
|
||||
* @param s Saturation [0-1]
|
||||
*/
|
||||
void setSaturation(qreal s);
|
||||
|
||||
/**
|
||||
* @param v Value [0-1]
|
||||
*/
|
||||
void setValue(qreal v);
|
||||
|
||||
void setComponentX(Component componentX);
|
||||
void setComponentY(Component componentY);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted when the user selects a color or setColor is called
|
||||
*/
|
||||
void colorChanged(QColor);
|
||||
|
||||
/**
|
||||
* Emitted when the user selects a color
|
||||
*/
|
||||
void colorSelected(QColor);
|
||||
|
||||
void componentXChanged(Component componentX);
|
||||
void componentYChanged(Component componentY);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event) Q_DECL_OVERRIDE;
|
||||
void mousePressEvent(QMouseEvent* event) Q_DECL_OVERRIDE;
|
||||
void mouseMoveEvent(QMouseEvent* event) Q_DECL_OVERRIDE;
|
||||
void mouseReleaseEvent(QMouseEvent* event) Q_DECL_OVERRIDE;
|
||||
void resizeEvent(QResizeEvent* event) Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const p;
|
||||
};
|
||||
|
||||
} // namespace color_widgets
|
||||
|
||||
#endif // COLOR_WIDGETS_COLOR_2D_SLIDER_HPP
|
||||
52
src/external/qt-color-widgets/qt-color-widgets/color_delegate.hpp
vendored
Normal file
52
src/external/qt-color-widgets/qt-color-widgets/color_delegate.hpp
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef COLOR_DELEGATE_HPP
|
||||
#define COLOR_DELEGATE_HPP
|
||||
|
||||
#include <QAbstractItemDelegate>
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
/**
|
||||
Delegate to use a ColorSelector in a color list
|
||||
*/
|
||||
class Q_DECL_EXPORT ColorDelegate : public QAbstractItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ColorDelegate(QWidget *parent = 0);
|
||||
|
||||
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const Q_DECL_OVERRIDE;
|
||||
|
||||
bool editorEvent(QEvent* event,
|
||||
QAbstractItemModel* model,
|
||||
const QStyleOptionViewItem & option,
|
||||
const QModelIndex & index) override;
|
||||
|
||||
virtual QSize sizeHint(const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const Q_DECL_OVERRIDE;
|
||||
};
|
||||
|
||||
} // namespace color_widgets
|
||||
|
||||
#endif // COLOR_DELEGATE_HPP
|
||||
151
src/external/qt-color-widgets/qt-color-widgets/color_dialog.hpp
vendored
Normal file
151
src/external/qt-color-widgets/qt-color-widgets/color_dialog.hpp
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef COLOR_DIALOG_HPP
|
||||
#define COLOR_DIALOG_HPP
|
||||
|
||||
#include "qt-color-widgets/color_preview.hpp"
|
||||
#include "qt-color-widgets/color_wheel.hpp"
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class QAbstractButton;
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
class Q_DECL_EXPORT ColorDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(ButtonMode)
|
||||
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged DESIGNABLE true)
|
||||
Q_PROPERTY(ColorWheel::DisplayFlags wheelFlags READ wheelFlags WRITE setWheelFlags NOTIFY wheelFlagsChanged)
|
||||
/**
|
||||
* \brief whether the color alpha channel can be edited.
|
||||
*
|
||||
* If alpha is disabled, the selected color's alpha will always be 255.
|
||||
*/
|
||||
Q_PROPERTY(bool alphaEnabled READ alphaEnabled WRITE setAlphaEnabled NOTIFY alphaEnabledChanged)
|
||||
|
||||
public:
|
||||
enum ButtonMode {
|
||||
OkCancel,
|
||||
OkApplyCancel,
|
||||
Close
|
||||
};
|
||||
|
||||
explicit ColorDialog(QWidget *parent = 0, Qt::WindowFlags f = 0);
|
||||
|
||||
/**
|
||||
* Get currently selected color
|
||||
*/
|
||||
QColor color() const;
|
||||
|
||||
/**
|
||||
* Set the display mode for the color preview
|
||||
*/
|
||||
void setPreviewDisplayMode(ColorPreview::DisplayMode mode);
|
||||
|
||||
/**
|
||||
* Get the color preview diplay mode
|
||||
*/
|
||||
ColorPreview::DisplayMode previewDisplayMode() const;
|
||||
|
||||
bool alphaEnabled() const;
|
||||
|
||||
/**
|
||||
* Select which dialog buttons to show
|
||||
*
|
||||
* There are three predefined modes:
|
||||
* OkCancel - this is useful when the dialog is modal and we just want to return a color
|
||||
* OkCancelApply - this is for non-modal dialogs
|
||||
* Close - for non-modal dialogs with direct color updates via colorChanged signal
|
||||
*/
|
||||
void setButtonMode(ButtonMode mode);
|
||||
ButtonMode buttonMode() const;
|
||||
|
||||
QSize sizeHint() const;
|
||||
|
||||
ColorWheel::DisplayFlags wheelFlags() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
/**
|
||||
* Change color
|
||||
*/
|
||||
void setColor(const QColor &c);
|
||||
|
||||
/**
|
||||
* Set the current color and show the dialog
|
||||
*/
|
||||
void showColor(const QColor &oldcolor);
|
||||
|
||||
void setWheelFlags(ColorWheel::DisplayFlags flags);
|
||||
|
||||
/**
|
||||
* Set whether the color alpha channel can be edited.
|
||||
* If alpha is disabled, the selected color's alpha will always be 255.
|
||||
*/
|
||||
void setAlphaEnabled(bool a);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The current color was changed
|
||||
*/
|
||||
void colorChanged(QColor);
|
||||
|
||||
/**
|
||||
* The user selected the new color by pressing Ok/Apply
|
||||
*/
|
||||
void colorSelected(QColor);
|
||||
|
||||
void wheelFlagsChanged(ColorWheel::DisplayFlags flags);
|
||||
void alphaEnabledChanged(bool alphaEnabled);
|
||||
|
||||
private Q_SLOTS:
|
||||
/// Update all the Ui elements to match the selected color
|
||||
void update_widgets();
|
||||
/// Update from HSV sliders
|
||||
void set_hsv();
|
||||
/// Update from RGB sliders
|
||||
void set_rgb();
|
||||
|
||||
void on_edit_hex_colorChanged(const QColor& color);
|
||||
void on_edit_hex_colorEditingFinished(const QColor& color);
|
||||
|
||||
void on_buttonBox_clicked(QAbstractButton*);
|
||||
|
||||
private:
|
||||
void setColorInternal(const QColor &color);
|
||||
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent *event);
|
||||
void dropEvent(QDropEvent * event);
|
||||
void mouseReleaseEvent(QMouseEvent *event);
|
||||
void mouseMoveEvent(QMouseEvent *event);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const p;
|
||||
};
|
||||
|
||||
} // namespace color_widgets
|
||||
|
||||
#endif // COLOR_DIALOG_HPP
|
||||
97
src/external/qt-color-widgets/qt-color-widgets/color_line_edit.hpp
vendored
Normal file
97
src/external/qt-color-widgets/qt-color-widgets/color_line_edit.hpp
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef COLOR_WIDGETS_COLOR_LINE_EDIT_HPP
|
||||
#define COLOR_WIDGETS_COLOR_LINE_EDIT_HPP
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QColor>
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
/**
|
||||
* \brief A line edit used to define a color name
|
||||
*
|
||||
* Supported string formats:
|
||||
* * Short hex strings #f00
|
||||
* * Long hex strings #ff0000
|
||||
* * Color names red
|
||||
* * Function-like rgb(255,0,0)
|
||||
*
|
||||
* Additional string formats supported when showAlpha is true:
|
||||
* * Long hex strings #ff0000ff
|
||||
* * Function like rgba(255,0,0,255)
|
||||
*/
|
||||
class Q_DECL_EXPORT ColorLineEdit : public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
|
||||
/**
|
||||
* \brief Whether the widget displays and edits the alpha channel
|
||||
*/
|
||||
Q_PROPERTY(bool showAlpha READ showAlpha WRITE setShowAlpha NOTIFY showAlphaChanged)
|
||||
/**
|
||||
* \brief If \b true, the background of the widget is changed to show the color
|
||||
*/
|
||||
Q_PROPERTY(bool previewColor READ previewColor WRITE setPreviewColor NOTIFY previewColorChanged)
|
||||
|
||||
public:
|
||||
explicit ColorLineEdit(QWidget* parent = nullptr);
|
||||
~ColorLineEdit();
|
||||
|
||||
QColor color() const;
|
||||
bool showAlpha() const;
|
||||
bool previewColor() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setColor(const QColor& color);
|
||||
void setShowAlpha(bool showAlpha);
|
||||
void setPreviewColor(bool previewColor);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* \brief Emitted when the color is changed by any means
|
||||
*/
|
||||
void colorChanged(const QColor& color);
|
||||
/**
|
||||
* \brief Emitted when the user is typing a color but has not finished yet
|
||||
*/
|
||||
void colorEdited(const QColor& color);
|
||||
/**
|
||||
* \brief Emitted when the user finished to edit a string
|
||||
*/
|
||||
void colorEditingFinished(const QColor& color);
|
||||
|
||||
void showAlphaChanged(bool showAlpha);
|
||||
void previewColorChanged(bool previewColor);
|
||||
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent *event) Q_DECL_OVERRIDE;
|
||||
void dropEvent(QDropEvent * event) Q_DECL_OVERRIDE;
|
||||
void paintEvent(QPaintEvent* event) Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private* p;
|
||||
};
|
||||
|
||||
} // namespace color_widgets
|
||||
#endif // COLOR_WIDGETS_COLOR_LINE_EDIT_HPP
|
||||
73
src/external/qt-color-widgets/qt-color-widgets/color_list_widget.hpp
vendored
Normal file
73
src/external/qt-color-widgets/qt-color-widgets/color_list_widget.hpp
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef COLOR_LIST_WIDGET_HPP
|
||||
#define COLOR_LIST_WIDGET_HPP
|
||||
|
||||
#include "qt-color-widgets/abstract_widget_list.hpp"
|
||||
#include "qt-color-widgets/color_wheel.hpp"
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
class Q_DECL_EXPORT ColorListWidget : public AbstractWidgetList
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QList<QColor> colors READ colors WRITE setColors NOTIFY colorsChanged )
|
||||
Q_PROPERTY(ColorWheel::DisplayFlags wheelFlags READ wheelFlags WRITE setWheelFlags NOTIFY wheelFlagsChanged)
|
||||
|
||||
public:
|
||||
explicit ColorListWidget(QWidget *parent = 0);
|
||||
~ColorListWidget();
|
||||
|
||||
QList<QColor> colors() const;
|
||||
void setColors(const QList<QColor>& colors);
|
||||
|
||||
void swap(int a, int b);
|
||||
|
||||
void append();
|
||||
void setColorAt(int i, QColor const& color);
|
||||
|
||||
|
||||
ColorWheel::DisplayFlags wheelFlags() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void color_added();
|
||||
void colorsChanged(const QList<QColor>&);
|
||||
void wheelFlagsChanged(ColorWheel::DisplayFlags flags);
|
||||
|
||||
public Q_SLOTS:
|
||||
void setWheelFlags(ColorWheel::DisplayFlags flags);
|
||||
|
||||
private Q_SLOTS:
|
||||
void emit_changed();
|
||||
void handle_removed(int);
|
||||
void color_changed(int row);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const p;
|
||||
void append_widget(int col);
|
||||
};
|
||||
|
||||
} // namespace color_widgets
|
||||
|
||||
#endif // COLOR_LIST_WIDGET_HPP
|
||||
55
src/external/qt-color-widgets/qt-color-widgets/color_names.hpp
vendored
Normal file
55
src/external/qt-color-widgets/qt-color-widgets/color_names.hpp
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef COLOR_WIDGETS_COLOR_NAMES_HPP
|
||||
#define COLOR_WIDGETS_COLOR_NAMES_HPP
|
||||
|
||||
#include <QColor>
|
||||
#include <QString>
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
/**
|
||||
* \brief Convert a string into a color
|
||||
*
|
||||
* Supported string formats:
|
||||
* * Short hex strings #f00
|
||||
* * Long hex strings #ff0000
|
||||
* * Color names red
|
||||
* * Function-like rgb(255,0,0)
|
||||
*
|
||||
* Additional string formats supported only when \p alpha is true:
|
||||
* * Long hex strings #ff0000ff
|
||||
* * Function like rgba(255,0,0,255)
|
||||
*/
|
||||
QColor colorFromString(const QString& string, bool alpha = true);
|
||||
|
||||
/**
|
||||
* \brief Convert a color into a string
|
||||
*
|
||||
* Format:
|
||||
* * If the color has full alpha: #ff0000
|
||||
* * If alpha is true and the color has non-full alpha: #ff000088
|
||||
*/
|
||||
QString stringFromColor(const QColor& color, bool alpha = true);
|
||||
|
||||
} // namespace color_widgets
|
||||
#endif // COLOR_WIDGETS_COLOR_NAMES_HPP
|
||||
228
src/external/qt-color-widgets/qt-color-widgets/color_palette.hpp
vendored
Normal file
228
src/external/qt-color-widgets/qt-color-widgets/color_palette.hpp
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef COLOR_WIDGETS_COLOR_PALETTE_HPP
|
||||
#define COLOR_WIDGETS_COLOR_PALETTE_HPP
|
||||
|
||||
#include <QColor>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QObject>
|
||||
#include <QPair>
|
||||
#include <QPixmap>
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
class Q_DECL_EXPORT ColorPalette : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/**
|
||||
* \brief The list of colors
|
||||
*/
|
||||
Q_PROPERTY(QVector<value_type> colors READ colors WRITE setColors NOTIFY colorsChanged)
|
||||
/**
|
||||
* \brief Name of the palette
|
||||
*/
|
||||
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
|
||||
/**
|
||||
* \brief Number of colors to display in a row, if 0 unspecified
|
||||
*/
|
||||
Q_PROPERTY(int columns READ columns WRITE setColumns NOTIFY columnsChanged)
|
||||
/**
|
||||
* \brief Number of colors
|
||||
*/
|
||||
Q_PROPERTY(int count READ count)
|
||||
/**
|
||||
* \brief Name of the file the palette has been read from
|
||||
*/
|
||||
Q_PROPERTY(QString fileName READ fileName WRITE setFileName NOTIFY fileNameChanged)
|
||||
/**
|
||||
* \brief Whether it has been modified and it might be advisable to save it
|
||||
*/
|
||||
Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged)
|
||||
|
||||
public:
|
||||
typedef QPair<QColor,QString> value_type;
|
||||
|
||||
ColorPalette(const QVector<QColor>& colors, const QString& name = QString(), int columns = 0);
|
||||
ColorPalette(const QVector<QPair<QColor,QString> >& colors, const QString& name = QString(), int columns = 0);
|
||||
explicit ColorPalette(const QString& name = QString());
|
||||
ColorPalette(const ColorPalette& other);
|
||||
ColorPalette& operator=(const ColorPalette& other);
|
||||
~ColorPalette();
|
||||
ColorPalette(ColorPalette&& other);
|
||||
ColorPalette& operator=(ColorPalette&& other);
|
||||
|
||||
/**
|
||||
* \brief Color at the given index
|
||||
*/
|
||||
Q_INVOKABLE QColor colorAt(int index) const;
|
||||
|
||||
/**
|
||||
* \brief Color name at the given index
|
||||
*/
|
||||
Q_INVOKABLE QString nameAt(int index) const;
|
||||
|
||||
QVector<QPair<QColor,QString> > colors() const;
|
||||
QVector<QColor> onlyColors() const;
|
||||
|
||||
int count() const;
|
||||
int columns();
|
||||
|
||||
QString name() const;
|
||||
|
||||
/**
|
||||
* \brief Use a color table to set the colors
|
||||
*/
|
||||
Q_INVOKABLE void loadColorTable(const QVector<QRgb>& color_table);
|
||||
|
||||
/**
|
||||
* \brief Convert to a color table
|
||||
*/
|
||||
Q_INVOKABLE QVector<QRgb> colorTable() const;
|
||||
|
||||
/**
|
||||
* \brief Creates a ColorPalette from a color table
|
||||
*/
|
||||
static ColorPalette fromColorTable(const QVector<QRgb>& table);
|
||||
|
||||
/**
|
||||
* \brief Use the pixels on an image to set the palette colors
|
||||
*/
|
||||
Q_INVOKABLE bool loadImage(const QImage& image);
|
||||
|
||||
/**
|
||||
* \brief Creates a ColorPalette from a Gimp palette (gpl) file
|
||||
*/
|
||||
static ColorPalette fromImage(const QImage& image);
|
||||
|
||||
/**
|
||||
* \brief Load contents from a Gimp palette (gpl) file
|
||||
* \returns \b true On Success
|
||||
* \note If this function returns \b false, the palette will become empty
|
||||
*/
|
||||
Q_INVOKABLE bool load(const QString& name);
|
||||
|
||||
/**
|
||||
* \brief Creates a ColorPalette from a Gimp palette (gpl) file
|
||||
*/
|
||||
static ColorPalette fromFile(const QString& name);
|
||||
|
||||
QString fileName() const;
|
||||
|
||||
bool dirty() const;
|
||||
|
||||
/**
|
||||
* \brief Returns a preview image of the colors in the palette
|
||||
*/
|
||||
QPixmap preview(const QSize& size, const QColor& background=Qt::transparent) const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setColumns(int columns);
|
||||
|
||||
void setColors(const QVector<QColor>& colors);
|
||||
void setColors(const QVector<QPair<QColor,QString> >& colors);
|
||||
|
||||
/**
|
||||
* \brief Change the color at the given index
|
||||
*/
|
||||
void setColorAt(int index, const QColor& color);
|
||||
/**
|
||||
* \brief Change the color at the given index
|
||||
*/
|
||||
void setColorAt(int index, const QColor& color, const QString& name);
|
||||
/**
|
||||
* \brief Change the name of a color
|
||||
*/
|
||||
void setNameAt(int index, const QString& name = QString());
|
||||
/**
|
||||
* \brief Append a color at the end
|
||||
*/
|
||||
void appendColor(const QColor& color, const QString& name = QString());
|
||||
/**
|
||||
* \brief Insert a color in an arbitrary location
|
||||
*/
|
||||
void insertColor(int index, const QColor& color, const QString& name = QString());
|
||||
/**
|
||||
* \brief Remove the color at the given index
|
||||
*/
|
||||
void eraseColor(int index);
|
||||
|
||||
/**
|
||||
* \brief Change file name and save
|
||||
* \returns \b true on success
|
||||
*/
|
||||
bool save(const QString& filename);
|
||||
/**
|
||||
* \brief save to file, the filename is \c fileName or determined automatically
|
||||
* \returns \b true on success
|
||||
*/
|
||||
bool save();
|
||||
|
||||
void setName(const QString& name);
|
||||
void setFileName(const QString& name);
|
||||
void setDirty(bool dirty);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* \brief Emitted when all the colors have changed
|
||||
*/
|
||||
void colorsChanged(const QVector<QPair<QColor,QString> >&);
|
||||
void columnsChanged(int);
|
||||
void nameChanged(const QString&);
|
||||
void fileNameChanged(const QString&);
|
||||
void dirtyChanged(bool);
|
||||
/**
|
||||
* \brief Emitted when the color or the name at the given index has been modified
|
||||
*/
|
||||
void colorChanged(int index);
|
||||
/**
|
||||
* \brief Emitted when the color at the given index has been removed
|
||||
*/
|
||||
void colorRemoved(int index);
|
||||
/**
|
||||
* \brief Emitted when a single color has been added
|
||||
*/
|
||||
void colorAdded(int index);
|
||||
/**
|
||||
* \brief Emitted when the colors have been modified with a simple operation (set, append etc.)
|
||||
*/
|
||||
void colorsUpdated(const QVector<QPair<QColor,QString>>&);
|
||||
|
||||
private:
|
||||
/**
|
||||
* \brief Returns \c name if it isn't null, otherwise a default value
|
||||
*/
|
||||
QString unnamed(const QString& name = QString()) const;
|
||||
|
||||
/**
|
||||
* \brief Emit all the necessary signals when the palette has been completely overwritten
|
||||
*/
|
||||
void emitUpdate();
|
||||
|
||||
class Private;
|
||||
Private *p;
|
||||
};
|
||||
|
||||
} // namespace color_widgets
|
||||
|
||||
#endif // COLOR_WIDGETS_COLOR_PALETTE_HPP
|
||||
140
src/external/qt-color-widgets/qt-color-widgets/color_palette_model.hpp
vendored
Normal file
140
src/external/qt-color-widgets/qt-color-widgets/color_palette_model.hpp
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef COLOR_WIDGETS_COLOR_PALETTE_MODEL_HPP
|
||||
#define COLOR_WIDGETS_COLOR_PALETTE_MODEL_HPP
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include "qt-color-widgets/color_palette.hpp"
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
class ColorPaletteModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
/**
|
||||
* \brief List of directories to be scanned for palette files
|
||||
*/
|
||||
Q_PROPERTY(QStringList searchPaths READ searchPaths WRITE setSearchPaths NOTIFY searchPathsChanged)
|
||||
|
||||
/**
|
||||
* \brief Default directory to be used when saving a palette
|
||||
*/
|
||||
Q_PROPERTY(QString savePath READ savePath WRITE setSavePath NOTIFY savePathChanged)
|
||||
|
||||
/**
|
||||
* \brief Size of the icon used for the palette previews
|
||||
*/
|
||||
Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize NOTIFY iconSizeChanged)
|
||||
|
||||
|
||||
public:
|
||||
ColorPaletteModel();
|
||||
~ColorPaletteModel();
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
|
||||
bool removeRows(int row, int count, const QModelIndex & parent = QModelIndex()) Q_DECL_OVERRIDE;
|
||||
|
||||
QString savePath() const;
|
||||
QStringList searchPaths() const;
|
||||
QSize iconSize() const;
|
||||
|
||||
/**
|
||||
* \brief Number of palettes
|
||||
*/
|
||||
int count() const;
|
||||
|
||||
/**
|
||||
* \brief Returns a reference to the first palette with the given name
|
||||
* \pre hasPalette(name)
|
||||
*/
|
||||
const ColorPalette& palette(const QString& name) const;
|
||||
|
||||
/**
|
||||
* \brief Whether a palette with the given name exists in the model
|
||||
*/
|
||||
bool hasPalette(const QString& name) const;
|
||||
|
||||
/**
|
||||
* \brief Get the palette at the given index (row)
|
||||
* \pre 0 <= index < count()
|
||||
*/
|
||||
const ColorPalette& palette(int index) const;
|
||||
|
||||
/**
|
||||
* \brief Updates an existing palette
|
||||
* \param index Palette index
|
||||
* \param palette New palette
|
||||
* \param save Whether to save the palette to the filesystem
|
||||
*
|
||||
* Saving will try: (in this order)
|
||||
* * To overwrite the file pointed by the old palette
|
||||
* * To write to the new palette file name
|
||||
* * To create a file in the save path
|
||||
* If all of the above fail, the palette will be replaced interally
|
||||
* but not on the filesystem
|
||||
*
|
||||
* \returns \b true if the palette has been successfully updated (and saved)
|
||||
*/
|
||||
bool updatePalette(int index, const ColorPalette& palette, bool save = true);
|
||||
|
||||
/**
|
||||
* \brief Remove a palette from the model and optionally from the filesystem
|
||||
* \returns \b true if the palette has been successfully removed
|
||||
*/
|
||||
bool removePalette(int index, bool remove_file = true);
|
||||
|
||||
/**
|
||||
* \brief Remove a palette to the model and optionally to the filesystem
|
||||
* \returns \b true if the palette has been successfully added
|
||||
*/
|
||||
bool addPalette(const ColorPalette& palette, bool save = true);
|
||||
|
||||
/**
|
||||
* \brief The index of the palette with the given file name
|
||||
* \returns -1 if none is found
|
||||
*/
|
||||
int indexFromFile(const QString& filename) const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setSavePath(const QString& savePath);
|
||||
void setSearchPaths(const QStringList& searchPaths);
|
||||
void addSearchPath(const QString& path);
|
||||
void setIconSize(const QSize& iconSize);
|
||||
|
||||
/**
|
||||
* \brief Load palettes files found in the search paths
|
||||
*/
|
||||
void load();
|
||||
|
||||
Q_SIGNALS:
|
||||
void savePathChanged(const QString& savePath);
|
||||
void searchPathsChanged(const QStringList& searchPaths);
|
||||
void iconSizeChanged(const QSize& iconSize);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private* p;
|
||||
};
|
||||
|
||||
} // namespace color_widgets
|
||||
|
||||
#endif // COLOR_WIDGETS_COLOR_PALETTE_MODEL_HPP
|
||||
181
src/external/qt-color-widgets/qt-color-widgets/color_palette_widget.hpp
vendored
Normal file
181
src/external/qt-color-widgets/qt-color-widgets/color_palette_widget.hpp
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef COLOR_WIDGETS_COLOR_PALETTE_WIDGET_HPP
|
||||
#define COLOR_WIDGETS_COLOR_PALETTE_WIDGET_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <QWidget>
|
||||
#include "qt-color-widgets/color_palette_model.hpp"
|
||||
#include "qt-color-widgets/swatch.hpp"
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
/**
|
||||
* \brief A widget to use and modify palettes
|
||||
*/
|
||||
class ColorPaletteWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/**
|
||||
* \brief Model used to store the palettes
|
||||
*/
|
||||
Q_PROPERTY(ColorPaletteModel* model READ model WRITE setModel NOTIFY modelChanged)
|
||||
|
||||
/**
|
||||
* \brief Size of a single color in the swatch widget
|
||||
*/
|
||||
Q_PROPERTY(QSize colorSize READ colorSize WRITE setColorSize NOTIFY colorSizeChanged)
|
||||
/**
|
||||
* \brief Policy for colorSize
|
||||
**/
|
||||
Q_PROPERTY(color_widgets::Swatch::ColorSizePolicy colorSizePolicy READ colorSizePolicy WRITE setColorSizePolicy NOTIFY colorSizePolicyChanged)
|
||||
|
||||
/**
|
||||
* \brief Border around the colors
|
||||
*/
|
||||
Q_PROPERTY(QPen border READ border WRITE setBorder NOTIFY borderChanged)
|
||||
|
||||
/**
|
||||
* \brief Forces the Swatch to display that many rows of colors
|
||||
*
|
||||
* If there are too few elements, the widget will display less than this
|
||||
* many rows.
|
||||
*
|
||||
* A value of0 means that the number of rows is automatic.
|
||||
*
|
||||
* \note Conflicts with forcedColumns
|
||||
*/
|
||||
Q_PROPERTY(int forcedRows READ forcedRows WRITE setForcedRows NOTIFY forcedRowsChanged)
|
||||
|
||||
/**
|
||||
* \brief Forces the Swatch to display that many columns of colors
|
||||
*
|
||||
* If there are too few elements, the widget will display less than this
|
||||
* many columns.
|
||||
*
|
||||
* A value of 0 means that the number of columns is automatic.
|
||||
*
|
||||
* \note Conflicts with forcedRows
|
||||
*/
|
||||
Q_PROPERTY(int forcedColumns READ forcedColumns WRITE setForcedColumns NOTIFY forcedColumnsChanged)
|
||||
|
||||
/**
|
||||
* \brief Whether the palettes can be modified via user interaction
|
||||
*/
|
||||
Q_PROPERTY(bool readOnly READ readOnly WRITE setReadOnly NOTIFY readOnlyChanged)
|
||||
|
||||
/**
|
||||
* \brief Currently selected color
|
||||
*/
|
||||
Q_PROPERTY(QColor currentColor READ currentColor WRITE setCurrentColor NOTIFY currentColorChanged)
|
||||
|
||||
/**
|
||||
* \brief Currently selected model row
|
||||
*/
|
||||
Q_PROPERTY(int currentRow READ currentRow WRITE setCurrentRow NOTIFY currentRowChanged)
|
||||
|
||||
public:
|
||||
ColorPaletteWidget(QWidget* parent = nullptr);
|
||||
~ColorPaletteWidget();
|
||||
|
||||
ColorPaletteModel* model() const;
|
||||
|
||||
/**
|
||||
* \brief Currently selected palette
|
||||
* \pre model() != nullptr and there is a selected palette
|
||||
*/
|
||||
const ColorPalette& currentPalette() const;
|
||||
|
||||
QSize colorSize() const;
|
||||
Swatch::ColorSizePolicy colorSizePolicy() const;
|
||||
QPen border() const;
|
||||
|
||||
int forcedRows() const;
|
||||
int forcedColumns() const;
|
||||
|
||||
bool readOnly() const;
|
||||
QColor currentColor() const;
|
||||
|
||||
int currentRow() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setModel(ColorPaletteModel* model);
|
||||
void setColorSize(const QSize& colorSize);
|
||||
void setColorSizePolicy(Swatch::ColorSizePolicy colorSizePolicy);
|
||||
void setBorder(const QPen& border);
|
||||
void setForcedRows(int forcedRows);
|
||||
void setForcedColumns(int forcedColumns);
|
||||
void setReadOnly(bool readOnly);
|
||||
/**
|
||||
* \brief Clear the selected color
|
||||
*/
|
||||
void clearCurrentColor();
|
||||
/**
|
||||
* \brief Attempt to select a color
|
||||
*
|
||||
* If the given color is available in the current palete, it will be selected
|
||||
* \return \b true on success
|
||||
*/
|
||||
bool setCurrentColor(const QColor& color);
|
||||
/**
|
||||
* \brief Attempt to select a color by name
|
||||
*
|
||||
* If the given color is available in the current palete, it will be selected
|
||||
* \return \b true on success
|
||||
*/
|
||||
bool setCurrentColor(const QString& name);
|
||||
/**
|
||||
* \brief Attempt to select a color by index
|
||||
*
|
||||
* If the given color is available in the current palete, it will be selected
|
||||
* \return \b true on success
|
||||
*/
|
||||
bool setCurrentColor(int index);
|
||||
/**
|
||||
* \brief Set the selected row in the model
|
||||
*/
|
||||
void setCurrentRow(int currentRow);
|
||||
|
||||
Q_SIGNALS:
|
||||
void modelChanged(ColorPaletteModel* model);
|
||||
void colorSizeChanged(const QSize& colorSize);
|
||||
void colorSizePolicyChanged(Swatch::ColorSizePolicy colorSizePolicy);
|
||||
void forcedRowsChanged(int forcedRows);
|
||||
void forcedColumnsChanged(int forcedColumns);
|
||||
void readOnlyChanged(bool readOnly);
|
||||
void currentColorChanged(const QColor& currentColor);
|
||||
void currentColorChanged(int index);
|
||||
void borderChanged(const QPen& border);
|
||||
void currentRowChanged(int currentRow);
|
||||
|
||||
private Q_SLOTS:
|
||||
void on_palette_list_currentIndexChanged(int index);
|
||||
void on_swatch_doubleClicked(int index);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
std::unique_ptr<Private> p;
|
||||
};
|
||||
|
||||
} // namespace color_widgets
|
||||
#endif // COLOR_WIDGETS_COLOR_PALETTE_WIDGET_HPP
|
||||
104
src/external/qt-color-widgets/qt-color-widgets/color_preview.hpp
vendored
Normal file
104
src/external/qt-color-widgets/qt-color-widgets/color_preview.hpp
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
* \copyright Copyright (C) 2014 Calle Laakkonen
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef COLOR_PREVIEW_HPP
|
||||
#define COLOR_PREVIEW_HPP
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
/**
|
||||
* Simple widget that shows a preview of a color
|
||||
*/
|
||||
class Q_DECL_EXPORT ColorPreview : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged DESIGNABLE true)
|
||||
Q_PROPERTY(QColor comparisonColor READ comparisonColor WRITE setComparisonColor DESIGNABLE true)
|
||||
Q_PROPERTY(DisplayMode display_mode READ displayMode WRITE setDisplayMode DESIGNABLE true)
|
||||
Q_PROPERTY(QBrush background READ background WRITE setBackground DESIGNABLE true)
|
||||
Q_ENUMS(DisplayMode)
|
||||
public:
|
||||
enum DisplayMode
|
||||
{
|
||||
NoAlpha, ///< Show current color with no transparency
|
||||
AllAlpha, ///< show current color with transparency
|
||||
SplitAlpha, ///< Show both solid and transparent side by side
|
||||
SplitColor ///< Show current and comparison colors side by side
|
||||
};
|
||||
Q_ENUMS(DisplayMode)
|
||||
|
||||
explicit ColorPreview(QWidget *parent = 0);
|
||||
~ColorPreview();
|
||||
|
||||
/// Get the background visible under transparent colors
|
||||
QBrush background() const;
|
||||
|
||||
/// Change the background visible under transparent colors
|
||||
void setBackground(const QBrush &bk);
|
||||
|
||||
/// Get color display mode
|
||||
DisplayMode displayMode() const;
|
||||
|
||||
/// Set how transparent colors are handled
|
||||
void setDisplayMode(DisplayMode dm);
|
||||
|
||||
/// Get current color
|
||||
QColor color() const;
|
||||
|
||||
/// Get the comparison color
|
||||
QColor comparisonColor() const;
|
||||
|
||||
QSize sizeHint () const;
|
||||
|
||||
void paint(QPainter &painter, QRect rect) const;
|
||||
|
||||
public Q_SLOTS:
|
||||
/// Set current color
|
||||
void setColor(const QColor &c);
|
||||
|
||||
/// Set the comparison color
|
||||
void setComparisonColor(const QColor &c);
|
||||
|
||||
Q_SIGNALS:
|
||||
/// Emitted when the user clicks on the widget
|
||||
void clicked();
|
||||
|
||||
/// Emitted on setColor
|
||||
void colorChanged(QColor);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *);
|
||||
void resizeEvent(QResizeEvent *);
|
||||
void mouseReleaseEvent(QMouseEvent *ev);
|
||||
void mouseMoveEvent(QMouseEvent *ev);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const p;
|
||||
};
|
||||
|
||||
} // namespace color_widgets
|
||||
Q_DECLARE_METATYPE(color_widgets::ColorPreview::DisplayMode)
|
||||
|
||||
#endif // COLOR_PREVIEW_HPP
|
||||
88
src/external/qt-color-widgets/qt-color-widgets/color_selector.hpp
vendored
Normal file
88
src/external/qt-color-widgets/qt-color-widgets/color_selector.hpp
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef COLOR_SELECTOR_HPP
|
||||
#define COLOR_SELECTOR_HPP
|
||||
|
||||
#include "qt-color-widgets/color_preview.hpp"
|
||||
#include "qt-color-widgets/color_wheel.hpp"
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
/**
|
||||
* Color preview that opens a color dialog
|
||||
*/
|
||||
class Q_DECL_EXPORT ColorSelector : public ColorPreview
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(UpdateMode)
|
||||
Q_PROPERTY(UpdateMode updateMode READ updateMode WRITE setUpdateMode )
|
||||
Q_PROPERTY(Qt::WindowModality dialogModality READ dialogModality WRITE setDialogModality )
|
||||
Q_PROPERTY(ColorWheel::DisplayFlags wheelFlags READ wheelFlags WRITE setWheelFlags NOTIFY wheelFlagsChanged)
|
||||
|
||||
public:
|
||||
enum UpdateMode {
|
||||
Confirm, ///< Update color only after the dialog has been accepted
|
||||
Continuous ///< Update color as it's being modified in the dialog
|
||||
};
|
||||
|
||||
explicit ColorSelector(QWidget *parent = 0);
|
||||
~ColorSelector();
|
||||
|
||||
void setUpdateMode(UpdateMode m);
|
||||
UpdateMode updateMode() const;
|
||||
|
||||
Qt::WindowModality dialogModality() const;
|
||||
void setDialogModality(Qt::WindowModality m);
|
||||
|
||||
ColorWheel::DisplayFlags wheelFlags() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void wheelFlagsChanged(ColorWheel::DisplayFlags flags);
|
||||
|
||||
public Q_SLOTS:
|
||||
void showDialog();
|
||||
void setWheelFlags(ColorWheel::DisplayFlags flags);
|
||||
|
||||
private Q_SLOTS:
|
||||
void accept_dialog();
|
||||
void reject_dialog();
|
||||
void update_old_color(const QColor &c);
|
||||
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent *event);
|
||||
void dropEvent(QDropEvent * event);
|
||||
|
||||
private:
|
||||
/// Connect/Disconnect colorChanged based on UpdateMode
|
||||
void connect_dialog();
|
||||
|
||||
/// Disconnect from dialog update
|
||||
void disconnect_dialog();
|
||||
|
||||
class Private;
|
||||
Private * const p;
|
||||
|
||||
};
|
||||
|
||||
} // namespace color_widgets
|
||||
|
||||
#endif // COLOR_SELECTOR_HPP
|
||||
167
src/external/qt-color-widgets/qt-color-widgets/color_wheel.hpp
vendored
Normal file
167
src/external/qt-color-widgets/qt-color-widgets/color_wheel.hpp
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef COLOR_WHEEL_HPP
|
||||
#define COLOR_WHEEL_HPP
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
/**
|
||||
* \brief Display an analog widget that allows the selection of a HSV color
|
||||
*
|
||||
* It has an outer wheel to select the Hue and an intenal square to select
|
||||
* Saturation and Lightness.
|
||||
*/
|
||||
class Q_DECL_EXPORT ColorWheel : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged DESIGNABLE true STORED false )
|
||||
Q_PROPERTY(qreal hue READ hue WRITE setHue DESIGNABLE false )
|
||||
Q_PROPERTY(qreal saturation READ saturation WRITE setSaturation DESIGNABLE false )
|
||||
Q_PROPERTY(qreal value READ value WRITE setValue DESIGNABLE false )
|
||||
Q_PROPERTY(unsigned wheelWidth READ wheelWidth WRITE setWheelWidth DESIGNABLE true )
|
||||
Q_PROPERTY(DisplayFlags displayFlags READ displayFlags WRITE setDisplayFlags NOTIFY displayFlagsChanged DESIGNABLE true )
|
||||
|
||||
public:
|
||||
enum DisplayEnum
|
||||
{
|
||||
SHAPE_DEFAULT = 0x000, ///< Use the default shape
|
||||
SHAPE_TRIANGLE = 0x001, ///< A triangle
|
||||
SHAPE_SQUARE = 0x002, ///< A square
|
||||
SHAPE_FLAGS = 0x00f, ///< Mask for the shape flags
|
||||
|
||||
ANGLE_DEFAULT = 0x000, ///< Use the default rotation style
|
||||
ANGLE_FIXED = 0x010, ///< The inner part doesn't rotate
|
||||
ANGLE_ROTATING = 0x020, ///< The inner part follows the hue selector
|
||||
ANGLE_FLAGS = 0x0f0, ///< Mask for the angle flags
|
||||
|
||||
COLOR_DEFAULT = 0x000, ///< Use the default colorspace
|
||||
COLOR_HSV = 0x100, ///< Use the HSV color space
|
||||
COLOR_HSL = 0x200, ///< Use the HSL color space
|
||||
COLOR_LCH = 0x400, ///< Use Luma Chroma Hue (Y_601')
|
||||
COLOR_FLAGS = 0xf00, ///< Mask for the color space flags
|
||||
|
||||
FLAGS_DEFAULT = 0x000, ///< Use all defaults
|
||||
FLAGS_ALL = 0xfff ///< Mask matching all flags
|
||||
};
|
||||
Q_DECLARE_FLAGS(DisplayFlags, DisplayEnum)
|
||||
Q_FLAGS(DisplayFlags)
|
||||
|
||||
explicit ColorWheel(QWidget *parent = 0);
|
||||
~ColorWheel();
|
||||
|
||||
/// Get current color
|
||||
QColor color() const;
|
||||
|
||||
virtual QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||
|
||||
/// Get current hue in the range [0-1]
|
||||
qreal hue() const;
|
||||
|
||||
/// Get current saturation in the range [0-1]
|
||||
qreal saturation() const;
|
||||
|
||||
/// Get current value in the range [0-1]
|
||||
qreal value() const;
|
||||
|
||||
/// Get the width in pixels of the outer wheel
|
||||
unsigned int wheelWidth() const;
|
||||
|
||||
/// Set the width in pixels of the outer wheel
|
||||
void setWheelWidth(unsigned int w);
|
||||
|
||||
/// Get display flags
|
||||
DisplayFlags displayFlags(DisplayFlags mask = FLAGS_ALL) const;
|
||||
|
||||
/// Set the default display flags
|
||||
static void setDefaultDisplayFlags(DisplayFlags flags);
|
||||
|
||||
/// Get default display flags
|
||||
static DisplayFlags defaultDisplayFlags(DisplayFlags mask = FLAGS_ALL);
|
||||
|
||||
/**
|
||||
* @brief Set a specific display flag
|
||||
* @param flag Flag replacing the mask
|
||||
* @param mask Mask to be cleared
|
||||
*/
|
||||
void setDisplayFlag(DisplayFlags flag, DisplayFlags mask);
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
/// Set current color
|
||||
void setColor(QColor c);
|
||||
|
||||
/**
|
||||
* @param h Hue [0-1]
|
||||
*/
|
||||
void setHue(qreal h);
|
||||
|
||||
/**
|
||||
* @param s Saturation [0-1]
|
||||
*/
|
||||
void setSaturation(qreal s);
|
||||
|
||||
/**
|
||||
* @param v Value [0-1]
|
||||
*/
|
||||
void setValue(qreal v);
|
||||
|
||||
/**
|
||||
* @brief Set the display flags
|
||||
* @param flags which will replace the current ones
|
||||
*/
|
||||
void setDisplayFlags(ColorWheel::DisplayFlags flags);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted when the user selects a color or setColor is called
|
||||
*/
|
||||
void colorChanged(QColor);
|
||||
|
||||
/**
|
||||
* Emitted when the user selects a color
|
||||
*/
|
||||
void colorSelected(QColor);
|
||||
|
||||
void displayFlagsChanged(ColorWheel::DisplayFlags flags);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE;
|
||||
void mouseMoveEvent(QMouseEvent *) Q_DECL_OVERRIDE;
|
||||
void mousePressEvent(QMouseEvent *) Q_DECL_OVERRIDE;
|
||||
void mouseReleaseEvent(QMouseEvent *) Q_DECL_OVERRIDE;
|
||||
void resizeEvent(QResizeEvent *) Q_DECL_OVERRIDE;
|
||||
void dragEnterEvent(QDragEnterEvent* event) Q_DECL_OVERRIDE;
|
||||
void dropEvent(QDropEvent* event) Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const p;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(ColorWheel::DisplayFlags)
|
||||
|
||||
} // namespace color_widgets
|
||||
|
||||
#endif // COLOR_WHEEL_HPP
|
||||
107
src/external/qt-color-widgets/qt-color-widgets/gradient_slider.hpp
vendored
Normal file
107
src/external/qt-color-widgets/qt-color-widgets/gradient_slider.hpp
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
* \copyright Copyright (C) 2014 Calle Laakkonen
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef GRADIENT_SLIDER_HPP
|
||||
#define GRADIENT_SLIDER_HPP
|
||||
|
||||
#include <QSlider>
|
||||
#include <QGradient>
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
/**
|
||||
* \brief A slider that mover on top of a gradient
|
||||
*/
|
||||
class Q_DECL_EXPORT GradientSlider : public QSlider
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QBrush background READ background WRITE setBackground)
|
||||
Q_PROPERTY(QGradientStops colors READ colors WRITE setColors DESIGNABLE false)
|
||||
Q_PROPERTY(QColor firstColor READ firstColor WRITE setFirstColor STORED false)
|
||||
Q_PROPERTY(QColor lastColor READ lastColor WRITE setLastColor STORED false)
|
||||
Q_PROPERTY(QLinearGradient gradient READ gradient WRITE setGradient)
|
||||
|
||||
public:
|
||||
explicit GradientSlider(QWidget *parent = 0);
|
||||
explicit GradientSlider(Qt::Orientation orientation, QWidget *parent = 0);
|
||||
~GradientSlider();
|
||||
|
||||
/// Get the background, it's visible for transparent gradient stops
|
||||
QBrush background() const;
|
||||
/// Set the background, it's visible for transparent gradient stops
|
||||
void setBackground(const QBrush &bg);
|
||||
|
||||
/// Get the colors that make up the gradient
|
||||
QGradientStops colors() const;
|
||||
/// Set the colors that make up the gradient
|
||||
void setColors(const QGradientStops &colors);
|
||||
|
||||
/// Get the gradient
|
||||
QLinearGradient gradient() const;
|
||||
/// Set the gradient
|
||||
void setGradient(const QLinearGradient &gradient);
|
||||
|
||||
/**
|
||||
* Overload: create an evenly distributed gradient of the given colors
|
||||
*/
|
||||
void setColors(const QVector<QColor> &colors);
|
||||
|
||||
/**
|
||||
* \brief Set the first color of the gradient
|
||||
*
|
||||
* If the gradient is currently empty it will create a stop with the given color
|
||||
*/
|
||||
void setFirstColor(const QColor &c);
|
||||
|
||||
/**
|
||||
* \brief Set the last color of the gradient
|
||||
*
|
||||
* If the gradient is has less than two colors,
|
||||
* it will create a stop with the given color
|
||||
*/
|
||||
void setLastColor(const QColor &c);
|
||||
|
||||
/**
|
||||
* \brief Get the first color
|
||||
*
|
||||
* \returns QColor() con empty gradient
|
||||
*/
|
||||
QColor firstColor() const;
|
||||
|
||||
/**
|
||||
* \brief Get the last color
|
||||
*
|
||||
* \returns QColor() con empty gradient
|
||||
*/
|
||||
QColor lastColor() const;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *ev);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const p;
|
||||
};
|
||||
|
||||
} // namespace color_widgets
|
||||
|
||||
#endif // GRADIENT_SLIDER_HPP
|
||||
95
src/external/qt-color-widgets/qt-color-widgets/hue_slider.hpp
vendored
Normal file
95
src/external/qt-color-widgets/qt-color-widgets/hue_slider.hpp
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2014 Calle Laakkonen
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef HUE_SLIDER_HPP
|
||||
#define HUE_SLIDER_HPP
|
||||
|
||||
#include "qt-color-widgets/gradient_slider.hpp"
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
/**
|
||||
* \brief A slider for selecting a hue value
|
||||
*/
|
||||
class Q_DECL_EXPORT HueSlider : public GradientSlider
|
||||
{
|
||||
Q_OBJECT
|
||||
/**
|
||||
* \brief Saturation used in the rainbow gradient, as a [0-1] float
|
||||
*/
|
||||
Q_PROPERTY(qreal colorSaturation READ colorSaturation WRITE setColorSaturation)
|
||||
/**
|
||||
* \brief Value used in the rainbow gradient, as a [0-1] float
|
||||
*/
|
||||
Q_PROPERTY(qreal colorValue READ colorValue WRITE setColorValue)
|
||||
/**
|
||||
* \brief Alpha used in the rainbow gradient, as a [0-1] float
|
||||
*/
|
||||
Q_PROPERTY(qreal colorAlpha READ colorAlpha WRITE setColorAlpha)
|
||||
|
||||
/**
|
||||
* \brief Color with corresponding color* components
|
||||
*/
|
||||
Q_PROPERTY(QColor color READ color WRITE setColor)
|
||||
|
||||
/**
|
||||
* \brief Normalized Hue, as indicated from the slider
|
||||
*/
|
||||
Q_PROPERTY(qreal colorHue READ colorHue WRITE setColorHue NOTIFY colorHueChanged)
|
||||
|
||||
|
||||
public:
|
||||
explicit HueSlider(QWidget *parent = nullptr);
|
||||
explicit HueSlider(Qt::Orientation orientation, QWidget *parent = nullptr);
|
||||
~HueSlider();
|
||||
|
||||
qreal colorSaturation() const;
|
||||
qreal colorValue() const;
|
||||
qreal colorAlpha() const;
|
||||
QColor color() const;
|
||||
qreal colorHue() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setColorValue(qreal value);
|
||||
void setColorSaturation(qreal value);
|
||||
void setColorAlpha(qreal alpha);
|
||||
void setColorHue(qreal colorHue);
|
||||
/**
|
||||
* \brief Set Hue Saturation and ColorValue, ignoring alpha
|
||||
*/
|
||||
void setColor(const QColor& color);
|
||||
/**
|
||||
* \brief Set Hue Saturation, ColorValue and Alpha
|
||||
*/
|
||||
void setFullColor(const QColor& color);
|
||||
|
||||
Q_SIGNALS:
|
||||
void colorHueChanged(qreal colorHue);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const p;
|
||||
};
|
||||
|
||||
} // namespace color_widgets
|
||||
|
||||
#endif // HUE_SLIDER_HPP
|
||||
194
src/external/qt-color-widgets/qt-color-widgets/swatch.hpp
vendored
Normal file
194
src/external/qt-color-widgets/qt-color-widgets/swatch.hpp
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef COLOR_WIDGETS_SWATCH_HPP
|
||||
#define COLOR_WIDGETS_SWATCH_HPP
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPen>
|
||||
#include "qt-color-widgets/color_palette.hpp"
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
/**
|
||||
* \brief A widget drawing a palette
|
||||
*/
|
||||
class Swatch : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/**
|
||||
* \brief Palette shown by the widget
|
||||
*/
|
||||
Q_PROPERTY(const ColorPalette& palette READ palette WRITE setPalette NOTIFY paletteChanged)
|
||||
/**
|
||||
* \brief Currently selected color (-1 if no color is selected)
|
||||
*/
|
||||
Q_PROPERTY(int selected READ selected WRITE setSelected NOTIFY selectedChanged)
|
||||
|
||||
/**
|
||||
* \brief Preferred size for a color square
|
||||
*/
|
||||
Q_PROPERTY(QSize colorSize READ colorSize WRITE setColorSize NOTIFY colorSizeChanged)
|
||||
|
||||
Q_PROPERTY(ColorSizePolicy colorSizePolicy READ colorSizePolicy WRITE setColorSizePolicy NOTIFY colorSizePolicyChanged)
|
||||
|
||||
/**
|
||||
* \brief Border around the colors
|
||||
*/
|
||||
Q_PROPERTY(QPen border READ border WRITE setBorder NOTIFY borderChanged)
|
||||
|
||||
/**
|
||||
* \brief Forces the Swatch to display that many rows of colors
|
||||
*
|
||||
* If there are too few elements, the widget will display less than this
|
||||
* many rows.
|
||||
*
|
||||
* A value of0 means that the number of rows is automatic.
|
||||
*
|
||||
* \note Conflicts with forcedColumns
|
||||
*/
|
||||
Q_PROPERTY(int forcedRows READ forcedRows WRITE setForcedRows NOTIFY forcedRowsChanged)
|
||||
|
||||
/**
|
||||
* \brief Forces the Swatch to display that many columns of colors
|
||||
*
|
||||
* If there are too few elements, the widget will display less than this
|
||||
* many columns.
|
||||
*
|
||||
* A value of 0 means that the number of columns is automatic.
|
||||
*
|
||||
* \note Conflicts with forcedRows
|
||||
*/
|
||||
Q_PROPERTY(int forcedColumns READ forcedColumns WRITE setForcedColumns NOTIFY forcedColumnsChanged)
|
||||
|
||||
/**
|
||||
* \brief Whether the palette can be modified via user interaction
|
||||
* \note Even when this is \b false, it can still be altered programmatically
|
||||
*/
|
||||
Q_PROPERTY(bool readOnly READ readOnly WRITE setReadOnly NOTIFY readOnlyChanged)
|
||||
|
||||
|
||||
public:
|
||||
enum ColorSizePolicy
|
||||
{
|
||||
Hint, ///< The size is just a hint
|
||||
Minimum, ///< Can expand but not contract
|
||||
Fixed ///< Must be exactly as specified
|
||||
};
|
||||
Q_ENUMS(ColorSizePolicy)
|
||||
|
||||
Swatch(QWidget* parent = 0);
|
||||
~Swatch();
|
||||
|
||||
QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||
QSize minimumSizeHint() const Q_DECL_OVERRIDE;
|
||||
|
||||
const ColorPalette& palette() const;
|
||||
ColorPalette& palette();
|
||||
int selected() const;
|
||||
/**
|
||||
* \brief Color at the currently selected index
|
||||
*/
|
||||
QColor selectedColor() const;
|
||||
|
||||
/**
|
||||
* \brief Color index at the given position within the widget
|
||||
* \param p Point in local coordinates
|
||||
* \returns -1 if the position doesn't represent any color
|
||||
*/
|
||||
int indexAt(const QPoint& p);
|
||||
|
||||
/**
|
||||
* \brief Color at the given position within the widget
|
||||
* \param p Point in local coordinates
|
||||
*/
|
||||
QColor colorAt(const QPoint& p);
|
||||
|
||||
QSize colorSize() const;
|
||||
ColorSizePolicy colorSizePolicy() const;
|
||||
QPen border() const;
|
||||
|
||||
int forcedRows() const;
|
||||
int forcedColumns() const;
|
||||
|
||||
bool readOnly() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setPalette(const ColorPalette& palette);
|
||||
void setSelected(int selected);
|
||||
void clearSelection();
|
||||
void setColorSize(const QSize& colorSize);
|
||||
void setColorSizePolicy(ColorSizePolicy colorSizePolicy);
|
||||
void setBorder(const QPen& border);
|
||||
void setForcedRows(int forcedRows);
|
||||
void setForcedColumns(int forcedColumns);
|
||||
void setReadOnly(bool readOnly);
|
||||
/**
|
||||
* \brief Remove the currently seleceted color
|
||||
**/
|
||||
void removeSelected();
|
||||
|
||||
Q_SIGNALS:
|
||||
void paletteChanged(const ColorPalette& palette);
|
||||
void selectedChanged(int selected);
|
||||
void colorSelected(const QColor& color);
|
||||
void colorSizeChanged(const QSize& colorSize);
|
||||
void colorSizePolicyChanged(ColorSizePolicy colorSizePolicy);
|
||||
void doubleClicked(int index);
|
||||
void rightClicked(int index);
|
||||
void forcedRowsChanged(int forcedRows);
|
||||
void forcedColumnsChanged(int forcedColumns);
|
||||
void readOnlyChanged(bool readOnly);
|
||||
void borderChanged(const QPen& border);
|
||||
|
||||
protected:
|
||||
bool event(QEvent* event) Q_DECL_OVERRIDE;
|
||||
|
||||
void paintEvent(QPaintEvent* event) Q_DECL_OVERRIDE;
|
||||
|
||||
void keyPressEvent(QKeyEvent* event) Q_DECL_OVERRIDE;
|
||||
|
||||
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
|
||||
void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
|
||||
void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
|
||||
void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
|
||||
void wheelEvent(QWheelEvent* event) Q_DECL_OVERRIDE;
|
||||
|
||||
void dragEnterEvent(QDragEnterEvent *event) Q_DECL_OVERRIDE;
|
||||
void dragMoveEvent(QDragMoveEvent* event) Q_DECL_OVERRIDE;
|
||||
void dragLeaveEvent(QDragLeaveEvent *event) Q_DECL_OVERRIDE;
|
||||
void dropEvent(QDropEvent* event) Q_DECL_OVERRIDE;
|
||||
|
||||
protected Q_SLOTS:
|
||||
/**
|
||||
* \brief Connected to the internal palette object to keep eveything consistent
|
||||
*/
|
||||
void paletteModified();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private* p;
|
||||
};
|
||||
|
||||
|
||||
} // namespace color_widgets
|
||||
#endif // COLOR_WIDGETS_SWATCH_HPP
|
||||
185
src/external/qt-color-widgets/src/abstract_widget_list.cpp
vendored
Normal file
185
src/external/qt-color-widgets/src/abstract_widget_list.cpp
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "qt-color-widgets/abstract_widget_list.hpp"
|
||||
#include <../../noggit/ui/font_awesome.hpp>
|
||||
#include <QToolButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QPushButton>
|
||||
|
||||
class AbstractWidgetList::Private
|
||||
{
|
||||
public:
|
||||
QList<QWidget*> widgets;
|
||||
QSignalMapper mapper_up;
|
||||
QSignalMapper mapper_down;
|
||||
QSignalMapper mapper_remove;
|
||||
QTableWidget *table;
|
||||
};
|
||||
|
||||
AbstractWidgetList::AbstractWidgetList(QWidget *parent) :
|
||||
QWidget(parent), p(new Private)
|
||||
{
|
||||
connect(&p->mapper_up,SIGNAL(mapped(QWidget*)),SLOT(up_clicked(QWidget*)));
|
||||
connect(&p->mapper_down,SIGNAL(mapped(QWidget*)),SLOT(down_clicked(QWidget*)));
|
||||
connect(&p->mapper_remove,SIGNAL(mapped(QWidget*)),SLOT(remove_clicked(QWidget*)));
|
||||
|
||||
|
||||
QVBoxLayout *verticalLayout = new QVBoxLayout(this);
|
||||
verticalLayout->setContentsMargins(0, 0, 0, 0);
|
||||
p->table = new QTableWidget(this);
|
||||
verticalLayout->addWidget(p->table);
|
||||
|
||||
|
||||
p->table->insertColumn(0);
|
||||
p->table->insertColumn(1);
|
||||
p->table->insertColumn(2);
|
||||
p->table->insertColumn(3);
|
||||
|
||||
p->table->setColumnWidth(0,64);
|
||||
p->table->setColumnWidth(1,24);
|
||||
p->table->setColumnWidth(2,24);
|
||||
p->table->setColumnWidth(3,24);
|
||||
|
||||
p->table->horizontalHeader()->hide();
|
||||
p->table->verticalHeader()->hide();
|
||||
p->table->setShowGrid(false);
|
||||
|
||||
QPushButton* add_button = new QPushButton(noggit::ui::font_awesome_icon(noggit::ui::font_awesome::plus),
|
||||
tr("Add New"));
|
||||
|
||||
verticalLayout->addWidget(add_button);
|
||||
connect(add_button,&QAbstractButton::clicked,this, &AbstractWidgetList::append);
|
||||
|
||||
}
|
||||
|
||||
AbstractWidgetList::~AbstractWidgetList()
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
|
||||
int AbstractWidgetList::count() const
|
||||
{
|
||||
return p->widgets.size();
|
||||
}
|
||||
|
||||
void AbstractWidgetList::setRowHeight(int row, int height)
|
||||
{
|
||||
p->table->setRowHeight(row,height);
|
||||
}
|
||||
|
||||
void AbstractWidgetList::clear()
|
||||
{
|
||||
p->widgets.clear();
|
||||
while(p->table->rowCount() > 0)
|
||||
p->table->removeRow(0);
|
||||
}
|
||||
|
||||
|
||||
void AbstractWidgetList::remove(int i)
|
||||
{
|
||||
if ( isValidRow(i) )
|
||||
{
|
||||
p->widgets.removeAt(i);
|
||||
p->table->removeRow(i);
|
||||
if ( i == 0 && !p->widgets.isEmpty() )
|
||||
p->table->cellWidget(0,1)->setEnabled(false);
|
||||
else if ( i != 0 && i == count() )
|
||||
p->table->cellWidget(count()-1,2)->setEnabled(false);
|
||||
|
||||
Q_EMIT removed(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AbstractWidgetList::appendWidget(QWidget *w)
|
||||
{
|
||||
int row = count();
|
||||
p->table->insertRow(row);
|
||||
|
||||
QString button_style =
|
||||
"QToolButton { \n "
|
||||
" border: none; \n "
|
||||
"} \n";
|
||||
|
||||
QWidget* b_up = create_button(w,&p->mapper_up, noggit::ui::font_awesome_icon(noggit::ui::font_awesome::chevronup),tr(""), tr("Move Up"));
|
||||
b_up->setStyleSheet(button_style);
|
||||
QWidget* b_down = create_button(w,&p->mapper_down, noggit::ui::font_awesome_icon(noggit::ui::font_awesome::chevrondown),tr(""), tr("Move Down"));
|
||||
b_down->setStyleSheet(button_style);
|
||||
QWidget* b_remove = create_button(w,&p->mapper_remove, noggit::ui::font_awesome_icon(noggit::ui::font_awesome::timescircle),tr(""), tr("Remove"));
|
||||
|
||||
b_remove->setStyleSheet(button_style);
|
||||
if ( row == 0 )
|
||||
b_up->setEnabled(false);
|
||||
else
|
||||
p->table->cellWidget(row-1,2)->setEnabled(true);
|
||||
b_down->setEnabled(false);
|
||||
|
||||
p->table->setCellWidget(row,0,w);
|
||||
p->table->setCellWidget(row,1,b_up);
|
||||
p->table->setCellWidget(row,2,b_down);
|
||||
p->table->setCellWidget(row,3,b_remove);
|
||||
|
||||
p->widgets.push_back(w);
|
||||
}
|
||||
|
||||
QWidget *AbstractWidgetList::widget(int i)
|
||||
{
|
||||
if ( isValidRow(i) )
|
||||
return p->widgets[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
QWidget *AbstractWidgetList::create_button(QWidget *data, QSignalMapper *mapper,
|
||||
QIcon icon,
|
||||
QString text, QString tooltip) const
|
||||
{
|
||||
|
||||
QToolButton* btn = new QToolButton;
|
||||
btn->setIcon(icon);
|
||||
btn->setText(text);
|
||||
btn->setToolTip(tooltip.isNull() ? btn->text() : tooltip );
|
||||
connect(btn,SIGNAL(clicked()),mapper,SLOT(map()));
|
||||
mapper->setMapping(btn,data);
|
||||
return btn;
|
||||
}
|
||||
|
||||
void AbstractWidgetList::remove_clicked(QWidget *w)
|
||||
{
|
||||
int row = p->widgets.indexOf(w);
|
||||
remove(row);
|
||||
}
|
||||
|
||||
void AbstractWidgetList::up_clicked(QWidget *w)
|
||||
{
|
||||
int row = p->widgets.indexOf(w);
|
||||
if ( row > 0 )
|
||||
swap(row,row-1);
|
||||
}
|
||||
|
||||
void AbstractWidgetList::down_clicked(QWidget *w)
|
||||
{
|
||||
int row = p->widgets.indexOf(w);
|
||||
if ( row+1 < count() )
|
||||
swap(row,row+1);
|
||||
}
|
||||
BIN
src/external/qt-color-widgets/src/alphaback.png
vendored
Normal file
BIN
src/external/qt-color-widgets/src/alphaback.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 208 B |
38
src/external/qt-color-widgets/src/bound_color_selector.cpp
vendored
Normal file
38
src/external/qt-color-widgets/src/bound_color_selector.cpp
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "qt-color-widgets/bound_color_selector.hpp"
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
BoundColorSelector::BoundColorSelector(QColor* reference, QWidget *parent) :
|
||||
ColorSelector(parent), ref(reference)
|
||||
{
|
||||
setColor(*reference);
|
||||
connect(this,&ColorPreview::colorChanged,this, &BoundColorSelector::update_reference);
|
||||
}
|
||||
|
||||
void BoundColorSelector::update_reference(QColor c)
|
||||
{
|
||||
*ref = c;
|
||||
}
|
||||
|
||||
} // namespace color_widgets
|
||||
267
src/external/qt-color-widgets/src/color_2d_slider.cpp
vendored
Normal file
267
src/external/qt-color-widgets/src/color_2d_slider.cpp
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "qt-color-widgets/color_2d_slider.hpp"
|
||||
#include "color_utils.hpp"
|
||||
#include <QImage>
|
||||
#include <QPainter>
|
||||
#include <QMouseEvent>
|
||||
#include <QResizeEvent>
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
static const double selector_radius = 6;
|
||||
|
||||
class Color2DSlider::Private
|
||||
{
|
||||
public:
|
||||
qreal hue = 1, sat = 1, val = 1;
|
||||
Component comp_x = Saturation;
|
||||
Component comp_y = Value;
|
||||
QImage square;
|
||||
|
||||
qreal PixHue(float x, float y)
|
||||
{
|
||||
if ( comp_x == Hue )
|
||||
return x;
|
||||
if ( comp_y == Hue )
|
||||
return y;
|
||||
return hue;
|
||||
}
|
||||
|
||||
qreal PixSat(float x, float y)
|
||||
{
|
||||
if ( comp_x == Saturation )
|
||||
return x;
|
||||
if ( comp_y == Saturation )
|
||||
return y;
|
||||
return sat;
|
||||
}
|
||||
|
||||
qreal PixVal(float x, float y)
|
||||
{
|
||||
if ( comp_x == Value )
|
||||
return x;
|
||||
if ( comp_y == Value )
|
||||
return y;
|
||||
return val;
|
||||
}
|
||||
|
||||
void renderSquare(const QSize& size)
|
||||
{
|
||||
square = QImage(size, QImage::Format_RGB32);
|
||||
|
||||
for ( int y = 0; y < size.height(); ++y )
|
||||
{
|
||||
qreal yfloat = 1 - qreal(y) / size.height();
|
||||
for ( int x = 0; x < size.width(); ++x )
|
||||
{
|
||||
qreal xfloat = qreal(x) / size.width();
|
||||
square.setPixel( x, y, QColor::fromHsvF(
|
||||
PixHue(xfloat, yfloat),
|
||||
PixSat(xfloat, yfloat),
|
||||
PixVal(xfloat, yfloat)
|
||||
).rgb());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QPointF selectorPos(const QSize& size)
|
||||
{
|
||||
QPointF pt;
|
||||
switch ( comp_x )
|
||||
{
|
||||
case Hue: pt.setX(size.width()*hue); break;
|
||||
case Saturation:pt.setX(size.width()*sat); break;
|
||||
case Value: pt.setX(size.width()*val); break;
|
||||
}
|
||||
switch ( comp_y )
|
||||
{
|
||||
case Hue: pt.setY(size.height()*(1-hue)); break;
|
||||
case Saturation:pt.setY(size.height()*(1-sat)); break;
|
||||
case Value: pt.setY(size.height()*(1-val)); break;
|
||||
}
|
||||
return pt;
|
||||
}
|
||||
|
||||
void setColorFromPos(const QPoint& pt, const QSize& size)
|
||||
{
|
||||
QPointF ptfloat(
|
||||
qBound(0.0, qreal(pt.x()) / size.width(), 1.0),
|
||||
qBound(0.0, 1 - qreal(pt.y()) / size.height(), 1.0)
|
||||
);
|
||||
switch ( comp_x )
|
||||
{
|
||||
case Hue: hue = ptfloat.x(); break;
|
||||
case Saturation:sat = ptfloat.x(); break;
|
||||
case Value: val = ptfloat.x(); break;
|
||||
}
|
||||
switch ( comp_y )
|
||||
{
|
||||
case Hue: hue = ptfloat.y(); break;
|
||||
case Saturation:sat = ptfloat.y(); break;
|
||||
case Value: val = ptfloat.y(); break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Color2DSlider::Color2DSlider(QWidget* parent)
|
||||
: QWidget(parent), p(new Private)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
}
|
||||
|
||||
Color2DSlider::~Color2DSlider()
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
|
||||
QColor Color2DSlider::color() const
|
||||
{
|
||||
return QColor::fromHsvF(p->hue, p->sat, p->val);
|
||||
}
|
||||
|
||||
QSize Color2DSlider::sizeHint() const
|
||||
{
|
||||
return {128, 128};
|
||||
}
|
||||
|
||||
qreal Color2DSlider::hue() const
|
||||
{
|
||||
return p->hue;
|
||||
}
|
||||
|
||||
qreal Color2DSlider::saturation() const
|
||||
{
|
||||
return p->sat;
|
||||
}
|
||||
|
||||
qreal Color2DSlider::value() const
|
||||
{
|
||||
return p->val;
|
||||
}
|
||||
|
||||
Color2DSlider::Component Color2DSlider::componentX() const
|
||||
{
|
||||
return p->comp_x;
|
||||
}
|
||||
|
||||
Color2DSlider::Component Color2DSlider::componentY() const
|
||||
{
|
||||
return p->comp_y;
|
||||
}
|
||||
|
||||
void Color2DSlider::setColor(const QColor& c)
|
||||
{
|
||||
p->hue = c.hsvHueF();
|
||||
p->sat = c.saturationF();
|
||||
p->val = c.valueF();
|
||||
p->renderSquare(size());
|
||||
update();
|
||||
Q_EMIT colorChanged(color());
|
||||
}
|
||||
|
||||
void Color2DSlider::setHue(qreal h)
|
||||
{
|
||||
p->hue = h;
|
||||
p->renderSquare(size());
|
||||
update();
|
||||
Q_EMIT colorChanged(color());
|
||||
}
|
||||
|
||||
void Color2DSlider::setSaturation(qreal s)
|
||||
{
|
||||
p->sat = s;
|
||||
p->renderSquare(size());
|
||||
update();
|
||||
Q_EMIT colorChanged(color());
|
||||
}
|
||||
|
||||
void Color2DSlider::setValue(qreal v)
|
||||
{
|
||||
p->val = v;
|
||||
p->renderSquare(size());
|
||||
update();
|
||||
Q_EMIT colorChanged(color());
|
||||
}
|
||||
|
||||
void Color2DSlider::setComponentX(Color2DSlider::Component componentX)
|
||||
{
|
||||
if ( componentX != p->comp_x )
|
||||
{
|
||||
p->comp_x = componentX;
|
||||
p->renderSquare(size());
|
||||
update();
|
||||
Q_EMIT componentXChanged(p->comp_x);
|
||||
}
|
||||
}
|
||||
|
||||
void Color2DSlider::setComponentY(Color2DSlider::Component componentY)
|
||||
{
|
||||
if ( componentY != p->comp_y )
|
||||
{
|
||||
p->comp_y = componentY;
|
||||
p->renderSquare(size());
|
||||
update();
|
||||
Q_EMIT componentXChanged(p->comp_y);
|
||||
}
|
||||
}
|
||||
|
||||
void Color2DSlider::paintEvent(QPaintEvent*)
|
||||
{
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.drawImage(0,0,p->square);
|
||||
|
||||
painter.setPen(QPen(p->val > 0.5 ? Qt::black : Qt::white, 3));
|
||||
painter.setBrush(Qt::NoBrush);
|
||||
painter.drawEllipse(p->selectorPos(size()), selector_radius, selector_radius);
|
||||
}
|
||||
|
||||
void Color2DSlider::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
p->setColorFromPos(event->pos(), size());
|
||||
Q_EMIT colorChanged(color());
|
||||
update();
|
||||
}
|
||||
|
||||
void Color2DSlider::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
p->setColorFromPos(event->pos(), size());
|
||||
Q_EMIT colorChanged(color());
|
||||
update();
|
||||
}
|
||||
|
||||
void Color2DSlider::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
p->setColorFromPos(event->pos(), size());
|
||||
Q_EMIT colorChanged(color());
|
||||
update();
|
||||
}
|
||||
|
||||
void Color2DSlider::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
p->renderSquare(event->size());
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
} // namespace color_widgets
|
||||
94
src/external/qt-color-widgets/src/color_delegate.cpp
vendored
Normal file
94
src/external/qt-color-widgets/src/color_delegate.cpp
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "qt-color-widgets/color_delegate.hpp"
|
||||
#include "qt-color-widgets/color_selector.hpp"
|
||||
#include "qt-color-widgets/color_dialog.hpp"
|
||||
#include <QPainter>
|
||||
#include <QMouseEvent>
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
ColorDelegate::ColorDelegate(QWidget *parent) :
|
||||
QAbstractItemDelegate(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void ColorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
if (index.data().canConvert<QColor>())
|
||||
{
|
||||
QStyleOptionFrame panel;
|
||||
panel.initFrom(option.widget);
|
||||
if (option.widget->isEnabled())
|
||||
panel.state = QStyle::State_Enabled;
|
||||
panel.rect = option.rect;
|
||||
panel.lineWidth = 2;
|
||||
panel.midLineWidth = 0;
|
||||
panel.state |= QStyle::State_Sunken;
|
||||
option.widget->style()->drawPrimitive(QStyle::PE_Frame, &panel, painter, nullptr);
|
||||
QRect r = option.widget->style()->subElementRect(QStyle::SE_FrameContents, &panel, nullptr);
|
||||
painter->setClipRect(r);
|
||||
painter->fillRect(option.rect, index.data().value<QColor>());
|
||||
}
|
||||
}
|
||||
|
||||
bool ColorDelegate::editorEvent(QEvent* event,
|
||||
QAbstractItemModel* model,
|
||||
const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index)
|
||||
{
|
||||
|
||||
if ( event->type() == QEvent::MouseButtonRelease && index.data().canConvert<QColor>())
|
||||
{
|
||||
QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
|
||||
|
||||
if ( mouse_event->button() == Qt::LeftButton &&
|
||||
( index.flags() & Qt::ItemIsEditable) )
|
||||
{
|
||||
ColorDialog *editor = new ColorDialog(const_cast<QWidget*>(option.widget));
|
||||
connect(this, &QObject::destroyed, editor, &QObject::deleteLater);
|
||||
editor->setMinimumSize(editor->sizeHint());
|
||||
auto original_color = index.data().value<QColor>();
|
||||
editor->setColor(original_color);
|
||||
auto set_color = [model, index](const QColor& color){
|
||||
model->setData(index, QVariant(color));
|
||||
};
|
||||
connect(editor, &ColorDialog::colorSelected, this, set_color);
|
||||
editor->show();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return QAbstractItemDelegate::editorEvent(event, model, option, index);
|
||||
}
|
||||
|
||||
|
||||
QSize ColorDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
Q_UNUSED(option)
|
||||
return QSize(24,16);
|
||||
}
|
||||
|
||||
} // namespace color_widgets
|
||||
340
src/external/qt-color-widgets/src/color_dialog.cpp
vendored
Normal file
340
src/external/qt-color-widgets/src/color_dialog.cpp
vendored
Normal file
@@ -0,0 +1,340 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
* \copyright Copyright (C) 2014 Calle Laakkonen
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "qt-color-widgets/color_dialog.hpp"
|
||||
#include "ui_color_dialog.h"
|
||||
|
||||
#include <QDropEvent>
|
||||
#include <QDragEnterEvent>
|
||||
#include <QDesktopWidget>
|
||||
#include <QMimeData>
|
||||
#include <QPushButton>
|
||||
#include <QScreen>
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
class ColorDialog::Private
|
||||
{
|
||||
public:
|
||||
Ui_ColorDialog ui;
|
||||
ButtonMode button_mode;
|
||||
bool pick_from_screen;
|
||||
bool alpha_enabled;
|
||||
|
||||
Private() : pick_from_screen(false), alpha_enabled(true)
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
ColorDialog::ColorDialog(QWidget *parent, Qt::WindowFlags f) :
|
||||
QDialog(parent, f), p(new Private)
|
||||
{
|
||||
p->ui.setupUi(this);
|
||||
|
||||
setAcceptDrops(true);
|
||||
|
||||
// Add "pick color" button
|
||||
QPushButton *pickButton = p->ui.buttonBox->addButton(tr("Pick"), QDialogButtonBox::ActionRole);
|
||||
pickButton->setIcon(QIcon::fromTheme(QStringLiteral("color-picker")));
|
||||
|
||||
setButtonMode(OkApplyCancel);
|
||||
|
||||
connect(p->ui.wheel,&ColorWheel::displayFlagsChanged,this, &ColorDialog::wheelFlagsChanged);
|
||||
}
|
||||
|
||||
QSize ColorDialog::sizeHint() const
|
||||
{
|
||||
return QSize(400,0);
|
||||
}
|
||||
|
||||
ColorWheel::DisplayFlags ColorDialog::wheelFlags() const
|
||||
{
|
||||
return p->ui.wheel->displayFlags();
|
||||
}
|
||||
|
||||
QColor ColorDialog::color() const
|
||||
{
|
||||
QColor col = p->ui.wheel->color();
|
||||
if(p->alpha_enabled)
|
||||
col.setAlpha(p->ui.slide_alpha->value());
|
||||
return col;
|
||||
}
|
||||
|
||||
void ColorDialog::setColor(const QColor &c)
|
||||
{
|
||||
p->ui.preview->setComparisonColor(c);
|
||||
p->ui.edit_hex->setModified(false);
|
||||
setColorInternal(c);
|
||||
}
|
||||
|
||||
void ColorDialog::setColorInternal(const QColor &c)
|
||||
{
|
||||
/**
|
||||
* \note Unlike setColor, this is used to update the current color which
|
||||
* migth differ from the final selected color
|
||||
*/
|
||||
p->ui.wheel->setColor(c);
|
||||
p->ui.slide_alpha->setValue(c.alpha());
|
||||
update_widgets();
|
||||
}
|
||||
|
||||
void ColorDialog::showColor(const QColor &c)
|
||||
{
|
||||
setColor(c);
|
||||
show();
|
||||
}
|
||||
|
||||
void ColorDialog::setWheelFlags(ColorWheel::DisplayFlags flags)
|
||||
{
|
||||
p->ui.wheel->setDisplayFlags(flags);
|
||||
}
|
||||
|
||||
void ColorDialog::setPreviewDisplayMode(ColorPreview::DisplayMode mode)
|
||||
{
|
||||
p->ui.preview->setDisplayMode(mode);
|
||||
}
|
||||
|
||||
ColorPreview::DisplayMode ColorDialog::previewDisplayMode() const
|
||||
{
|
||||
return p->ui.preview->displayMode();
|
||||
}
|
||||
|
||||
void ColorDialog::setAlphaEnabled(bool a)
|
||||
{
|
||||
if ( a != p->alpha_enabled )
|
||||
{
|
||||
p->alpha_enabled = a;
|
||||
|
||||
p->ui.edit_hex->setShowAlpha(a);
|
||||
p->ui.line_alpha->setVisible(a);
|
||||
p->ui.label_alpha->setVisible(a);
|
||||
p->ui.slide_alpha->setVisible(a);
|
||||
p->ui.spin_alpha->setVisible(a);
|
||||
|
||||
Q_EMIT alphaEnabledChanged(a);
|
||||
}
|
||||
}
|
||||
|
||||
bool ColorDialog::alphaEnabled() const
|
||||
{
|
||||
return p->alpha_enabled;
|
||||
}
|
||||
|
||||
void ColorDialog::setButtonMode(ButtonMode mode)
|
||||
{
|
||||
p->button_mode = mode;
|
||||
QDialogButtonBox::StandardButtons btns;
|
||||
switch(mode) {
|
||||
case OkCancel: btns = QDialogButtonBox::Ok | QDialogButtonBox::Cancel; break;
|
||||
case OkApplyCancel: btns = QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Apply | QDialogButtonBox::Reset; break;
|
||||
case Close: btns = QDialogButtonBox::Close;
|
||||
}
|
||||
p->ui.buttonBox->setStandardButtons(btns);
|
||||
}
|
||||
|
||||
ColorDialog::ButtonMode ColorDialog::buttonMode() const
|
||||
{
|
||||
return p->button_mode;
|
||||
}
|
||||
|
||||
void ColorDialog::update_widgets()
|
||||
{
|
||||
bool blocked = signalsBlocked();
|
||||
blockSignals(true);
|
||||
Q_FOREACH(QWidget* w, findChildren<QWidget*>())
|
||||
w->blockSignals(true);
|
||||
|
||||
QColor col = color();
|
||||
|
||||
p->ui.slide_red->setValue(col.red());
|
||||
p->ui.spin_red->setValue(p->ui.slide_red->value());
|
||||
p->ui.slide_red->setFirstColor(QColor(0,col.green(),col.blue()));
|
||||
p->ui.slide_red->setLastColor(QColor(255,col.green(),col.blue()));
|
||||
|
||||
p->ui.slide_green->setValue(col.green());
|
||||
p->ui.spin_green->setValue(p->ui.slide_green->value());
|
||||
p->ui.slide_green->setFirstColor(QColor(col.red(),0,col.blue()));
|
||||
p->ui.slide_green->setLastColor(QColor(col.red(),255,col.blue()));
|
||||
|
||||
p->ui.slide_blue->setValue(col.blue());
|
||||
p->ui.spin_blue->setValue(p->ui.slide_blue->value());
|
||||
p->ui.slide_blue->setFirstColor(QColor(col.red(),col.green(),0));
|
||||
p->ui.slide_blue->setLastColor(QColor(col.red(),col.green(),255));
|
||||
|
||||
p->ui.slide_hue->setValue(qRound(p->ui.wheel->hue()*360.0));
|
||||
p->ui.slide_hue->setColorSaturation(p->ui.wheel->saturation());
|
||||
p->ui.slide_hue->setColorValue(p->ui.wheel->value());
|
||||
p->ui.spin_hue->setValue(p->ui.slide_hue->value());
|
||||
|
||||
p->ui.slide_saturation->setValue(qRound(p->ui.wheel->saturation()*255.0));
|
||||
p->ui.spin_saturation->setValue(p->ui.slide_saturation->value());
|
||||
p->ui.slide_saturation->setFirstColor(QColor::fromHsvF(p->ui.wheel->hue(),0,p->ui.wheel->value()));
|
||||
p->ui.slide_saturation->setLastColor(QColor::fromHsvF(p->ui.wheel->hue(),1,p->ui.wheel->value()));
|
||||
|
||||
p->ui.slide_value->setValue(qRound(p->ui.wheel->value()*255.0));
|
||||
p->ui.spin_value->setValue(p->ui.slide_value->value());
|
||||
p->ui.slide_value->setFirstColor(QColor::fromHsvF(p->ui.wheel->hue(), p->ui.wheel->saturation(),0));
|
||||
p->ui.slide_value->setLastColor(QColor::fromHsvF(p->ui.wheel->hue(), p->ui.wheel->saturation(),1));
|
||||
|
||||
|
||||
QColor apha_color = col;
|
||||
apha_color.setAlpha(0);
|
||||
p->ui.slide_alpha->setFirstColor(apha_color);
|
||||
apha_color.setAlpha(255);
|
||||
p->ui.slide_alpha->setLastColor(apha_color);
|
||||
p->ui.spin_alpha->setValue(p->ui.slide_alpha->value());
|
||||
|
||||
if ( !p->ui.edit_hex->isModified() )
|
||||
p->ui.edit_hex->setColor(col);
|
||||
|
||||
p->ui.preview->setColor(col);
|
||||
|
||||
blockSignals(blocked);
|
||||
Q_FOREACH(QWidget* w, findChildren<QWidget*>())
|
||||
w->blockSignals(false);
|
||||
|
||||
Q_EMIT colorChanged(col);
|
||||
}
|
||||
|
||||
void ColorDialog::set_hsv()
|
||||
{
|
||||
if ( !signalsBlocked() )
|
||||
{
|
||||
p->ui.wheel->setColor(QColor::fromHsv(
|
||||
p->ui.slide_hue->value(),
|
||||
p->ui.slide_saturation->value(),
|
||||
p->ui.slide_value->value()
|
||||
));
|
||||
update_widgets();
|
||||
}
|
||||
}
|
||||
|
||||
void ColorDialog::set_rgb()
|
||||
{
|
||||
if ( !signalsBlocked() )
|
||||
{
|
||||
QColor col(
|
||||
p->ui.slide_red->value(),
|
||||
p->ui.slide_green->value(),
|
||||
p->ui.slide_blue->value()
|
||||
);
|
||||
if (col.saturation() == 0)
|
||||
col = QColor::fromHsv(p->ui.slide_hue->value(), 0, col.value());
|
||||
p->ui.wheel->setColor(col);
|
||||
update_widgets();
|
||||
}
|
||||
}
|
||||
|
||||
void ColorDialog::on_edit_hex_colorChanged(const QColor& color)
|
||||
{
|
||||
setColorInternal(color);
|
||||
}
|
||||
|
||||
void ColorDialog::on_edit_hex_colorEditingFinished(const QColor& color)
|
||||
{
|
||||
p->ui.edit_hex->setModified(false);
|
||||
setColorInternal(color);
|
||||
}
|
||||
|
||||
void ColorDialog::on_buttonBox_clicked(QAbstractButton *btn)
|
||||
{
|
||||
QDialogButtonBox::ButtonRole role = p->ui.buttonBox->buttonRole(btn);
|
||||
|
||||
switch(role) {
|
||||
case QDialogButtonBox::AcceptRole:
|
||||
case QDialogButtonBox::ApplyRole:
|
||||
// Explicitly select the color
|
||||
p->ui.preview->setComparisonColor(color());
|
||||
Q_EMIT colorSelected(color());
|
||||
break;
|
||||
|
||||
case QDialogButtonBox::ActionRole:
|
||||
// Currently, the only action button is the "pick color" button
|
||||
grabMouse(Qt::CrossCursor);
|
||||
p->pick_from_screen = true;
|
||||
break;
|
||||
|
||||
case QDialogButtonBox::ResetRole:
|
||||
// Restore old color
|
||||
setColorInternal(p->ui.preview->comparisonColor());
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void ColorDialog::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
if ( event->mimeData()->hasColor() ||
|
||||
( event->mimeData()->hasText() && QColor(event->mimeData()->text()).isValid() ) )
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
|
||||
|
||||
void ColorDialog::dropEvent(QDropEvent *event)
|
||||
{
|
||||
if ( event->mimeData()->hasColor() )
|
||||
{
|
||||
setColorInternal(event->mimeData()->colorData().value<QColor>());
|
||||
event->accept();
|
||||
}
|
||||
else if ( event->mimeData()->hasText() )
|
||||
{
|
||||
QColor col(event->mimeData()->text());
|
||||
if ( col.isValid() )
|
||||
{
|
||||
setColorInternal(col);
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static QColor get_screen_color(const QPoint &global_pos)
|
||||
{
|
||||
int screenNum = QApplication::desktop()->screenNumber(global_pos);
|
||||
QScreen *screen = QApplication::screens().at(screenNum);
|
||||
|
||||
WId wid = QApplication::desktop()->winId();
|
||||
QImage img = screen->grabWindow(wid, global_pos.x(), global_pos.y(), 1, 1).toImage();
|
||||
|
||||
return img.pixel(0,0);
|
||||
}
|
||||
|
||||
void ColorDialog::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
if (p->pick_from_screen)
|
||||
{
|
||||
setColorInternal(get_screen_color(event->globalPos()));
|
||||
p->pick_from_screen = false;
|
||||
releaseMouse();
|
||||
}
|
||||
}
|
||||
|
||||
void ColorDialog::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if (p->pick_from_screen)
|
||||
{
|
||||
setColorInternal(get_screen_color(event->globalPos()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace color_widgets
|
||||
699
src/external/qt-color-widgets/src/color_dialog.ui
vendored
Normal file
699
src/external/qt-color-widgets/src/color_dialog.ui
vendored
Normal file
@@ -0,0 +1,699 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ColorDialog</class>
|
||||
<widget class="QDialog" name="ColorDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>491</width>
|
||||
<height>380</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Select Color</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset theme="format-fill-color">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="color_widgets::ColorWheel" name="wheel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="color_widgets::ColorPreview" name="preview">
|
||||
<property name="display_mode" stdset="0">
|
||||
<enum>color_widgets::ColorPreview::SplitColor</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="2" column="1">
|
||||
<widget class="color_widgets::GradientSlider" name="slide_value">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Saturation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Hue</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="color_widgets::GradientSlider" name="slide_saturation">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Hex</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Blue</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="color_widgets::GradientSlider" name="slide_alpha">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="color_widgets::GradientSlider" name="slide_red">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="color_widgets::GradientSlider" name="slide_green">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Value</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Green</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_alpha">
|
||||
<property name="text">
|
||||
<string>Alpha</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Red</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="color_widgets::GradientSlider" name="slide_blue">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QSpinBox" name="spin_hue">
|
||||
<property name="wrapping">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>359</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QSpinBox" name="spin_saturation">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QSpinBox" name="spin_value">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QSpinBox" name="spin_red">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QSpinBox" name="spin_green">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="2">
|
||||
<widget class="QSpinBox" name="spin_blue">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="2">
|
||||
<widget class="QSpinBox" name="spin_alpha">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="3">
|
||||
<widget class="Line" name="line_alpha">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="3">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0" colspan="3">
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="color_widgets::HueSlider" name="slide_hue">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>359</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1" colspan="2">
|
||||
<widget class="color_widgets::ColorLineEdit" name="edit_hex">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="showAlpha">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>color_widgets::ColorPreview</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>qt-color-widgets/color_preview.hpp</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>color_widgets::ColorWheel</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>qt-color-widgets/color_wheel.hpp</header>
|
||||
<container>1</container>
|
||||
<slots>
|
||||
<signal>colorSelected(QColor)</signal>
|
||||
<slot>setColor(QColor)</slot>
|
||||
</slots>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>color_widgets::GradientSlider</class>
|
||||
<extends>QSlider</extends>
|
||||
<header>qt-color-widgets/gradient_slider.hpp</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>color_widgets::HueSlider</class>
|
||||
<extends>color_widgets::GradientSlider</extends>
|
||||
<header>qt-color-widgets/hue_slider.hpp</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>color_widgets::ColorLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>qt-color-widgets/color_line_edit.hpp</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>slide_saturation</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ColorDialog</receiver>
|
||||
<slot>set_hsv()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>416</x>
|
||||
<y>71</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>537</x>
|
||||
<y>54</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>slide_value</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ColorDialog</receiver>
|
||||
<slot>set_hsv()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>416</x>
|
||||
<y>109</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>537</x>
|
||||
<y>88</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>slide_red</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ColorDialog</receiver>
|
||||
<slot>set_rgb()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>416</x>
|
||||
<y>156</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>557</x>
|
||||
<y>142</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>slide_green</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ColorDialog</receiver>
|
||||
<slot>set_rgb()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>416</x>
|
||||
<y>194</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>538</x>
|
||||
<y>166</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>slide_blue</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ColorDialog</receiver>
|
||||
<slot>set_rgb()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>416</x>
|
||||
<y>232</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>537</x>
|
||||
<y>205</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>slide_alpha</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ColorDialog</receiver>
|
||||
<slot>update_widgets()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>416</x>
|
||||
<y>279</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>531</x>
|
||||
<y>251</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>wheel</sender>
|
||||
<signal>colorSelected(QColor)</signal>
|
||||
<receiver>ColorDialog</receiver>
|
||||
<slot>update_widgets()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>175</x>
|
||||
<y>101</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>568</x>
|
||||
<y>106</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>slide_saturation</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>spin_saturation</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>416</x>
|
||||
<y>71</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>480</x>
|
||||
<y>62</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spin_saturation</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>slide_saturation</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>461</x>
|
||||
<y>55</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>416</x>
|
||||
<y>71</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>slide_value</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>spin_value</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>416</x>
|
||||
<y>109</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>480</x>
|
||||
<y>91</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spin_value</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>slide_value</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>480</x>
|
||||
<y>91</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>416</x>
|
||||
<y>109</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>slide_red</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>spin_red</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>416</x>
|
||||
<y>156</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>482</x>
|
||||
<y>162</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spin_red</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>slide_red</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>482</x>
|
||||
<y>162</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>416</x>
|
||||
<y>156</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>slide_green</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>spin_green</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>416</x>
|
||||
<y>194</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>482</x>
|
||||
<y>200</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spin_green</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>slide_green</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>482</x>
|
||||
<y>200</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>416</x>
|
||||
<y>194</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>slide_alpha</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>spin_alpha</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>416</x>
|
||||
<y>279</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>482</x>
|
||||
<y>285</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spin_alpha</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>slide_alpha</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>482</x>
|
||||
<y>285</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>416</x>
|
||||
<y>279</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>slide_blue</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>spin_blue</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>416</x>
|
||||
<y>232</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>482</x>
|
||||
<y>238</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spin_blue</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>slide_blue</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>482</x>
|
||||
<y>238</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>416</x>
|
||||
<y>232</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>slide_hue</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>spin_hue</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>405</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>462</x>
|
||||
<y>26</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spin_hue</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>slide_hue</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>448</x>
|
||||
<y>18</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>388</x>
|
||||
<y>24</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>slide_hue</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ColorDialog</receiver>
|
||||
<slot>set_hsv()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>361</x>
|
||||
<y>17</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>363</x>
|
||||
<y>8</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ColorDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>250</x>
|
||||
<y>373</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>430</x>
|
||||
<y>267</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ColorDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>183</x>
|
||||
<y>373</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>294</x>
|
||||
<y>323</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<slots>
|
||||
<signal>colorChanged(QColor)</signal>
|
||||
<slot>set_rgb()</slot>
|
||||
<slot>set_hsv()</slot>
|
||||
<slot>setColor(QColor)</slot>
|
||||
<slot>update_widgets()</slot>
|
||||
</slots>
|
||||
</ui>
|
||||
213
src/external/qt-color-widgets/src/color_line_edit.cpp
vendored
Normal file
213
src/external/qt-color-widgets/src/color_line_edit.cpp
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "qt-color-widgets/color_line_edit.hpp"
|
||||
|
||||
#include <QDropEvent>
|
||||
#include <QDragEnterEvent>
|
||||
#include <QMimeData>
|
||||
#include <QApplication>
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionFrame>
|
||||
|
||||
#include "color_utils.hpp"
|
||||
#include "qt-color-widgets/color_names.hpp"
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
|
||||
class ColorLineEdit::Private
|
||||
{
|
||||
public:
|
||||
QColor color;
|
||||
bool show_alpha = false;
|
||||
bool preview_color = false;
|
||||
QBrush background;
|
||||
|
||||
bool customAlpha()
|
||||
{
|
||||
return preview_color && show_alpha && color.alpha() < 255;
|
||||
}
|
||||
|
||||
void setPalette(const QColor& color, ColorLineEdit* parent)
|
||||
{
|
||||
if ( preview_color )
|
||||
{
|
||||
QPalette pal = parent->palette();
|
||||
|
||||
if ( customAlpha() )
|
||||
pal.setColor(QPalette::Base, Qt::transparent);
|
||||
else
|
||||
pal.setColor(QPalette::Base, color.rgb());
|
||||
pal.setColor(QPalette::Text,
|
||||
detail::color_lumaF(color) > 0.5 || color.alphaF() < 0.2 ? Qt::black : Qt::white);
|
||||
parent->setPalette(pal);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ColorLineEdit::ColorLineEdit(QWidget* parent)
|
||||
: QLineEdit(parent), p(new Private)
|
||||
{
|
||||
p->background.setTexture(QPixmap(QStringLiteral(":/color_widgets/alphaback.png")));
|
||||
setColor(Qt::white);
|
||||
/// \todo determine if having this connection might be useful
|
||||
/*connect(this, &QLineEdit::textChanged, [this](const QString& text){
|
||||
QColor color = p->colorFromString(text);
|
||||
if ( color.isValid() )
|
||||
Q_EMIT colorChanged(color);
|
||||
});*/
|
||||
connect(this, &QLineEdit::textEdited, [this](const QString& text){
|
||||
QColor color = color_widgets::colorFromString(text, p->show_alpha);
|
||||
if ( color.isValid() )
|
||||
{
|
||||
p->color = color;
|
||||
p->setPalette(color, this);
|
||||
Q_EMIT colorEdited(color);
|
||||
Q_EMIT colorChanged(color);
|
||||
}
|
||||
});
|
||||
connect(this, &QLineEdit::editingFinished, [this](){
|
||||
QColor color = color_widgets::colorFromString(text(), p->show_alpha);
|
||||
if ( color.isValid() )
|
||||
{
|
||||
p->color = color;
|
||||
Q_EMIT colorEditingFinished(color);
|
||||
Q_EMIT colorChanged(color);
|
||||
}
|
||||
else
|
||||
{
|
||||
setText(color_widgets::stringFromColor(p->color, p->show_alpha));
|
||||
Q_EMIT colorEditingFinished(p->color);
|
||||
Q_EMIT colorChanged(color);
|
||||
}
|
||||
p->setPalette(p->color, this);
|
||||
});
|
||||
}
|
||||
|
||||
ColorLineEdit::~ColorLineEdit()
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
|
||||
QColor ColorLineEdit::color() const
|
||||
{
|
||||
return p->color;
|
||||
}
|
||||
|
||||
void ColorLineEdit::setColor(const QColor& color)
|
||||
{
|
||||
if ( color != p->color )
|
||||
{
|
||||
p->color = color;
|
||||
p->setPalette(p->color, this);
|
||||
setText(color_widgets::stringFromColor(p->color, p->show_alpha));
|
||||
Q_EMIT colorChanged(p->color);
|
||||
}
|
||||
}
|
||||
|
||||
void ColorLineEdit::setShowAlpha(bool showAlpha)
|
||||
{
|
||||
if ( p->show_alpha != showAlpha )
|
||||
{
|
||||
p->show_alpha = showAlpha;
|
||||
p->setPalette(p->color, this);
|
||||
setText(color_widgets::stringFromColor(p->color, p->show_alpha));
|
||||
Q_EMIT showAlphaChanged(p->show_alpha);
|
||||
}
|
||||
}
|
||||
|
||||
bool ColorLineEdit::showAlpha() const
|
||||
{
|
||||
return p->show_alpha;
|
||||
}
|
||||
|
||||
void ColorLineEdit::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
if ( isReadOnly() )
|
||||
return;
|
||||
|
||||
if ( event->mimeData()->hasColor() ||
|
||||
( event->mimeData()->hasText() &&
|
||||
color_widgets::colorFromString(event->mimeData()->text(), p->show_alpha).isValid() ) )
|
||||
{
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ColorLineEdit::dropEvent(QDropEvent *event)
|
||||
{
|
||||
if ( isReadOnly() )
|
||||
return;
|
||||
|
||||
if ( event->mimeData()->hasColor() )
|
||||
{
|
||||
setColor(event->mimeData()->colorData().value<QColor>());
|
||||
event->accept();
|
||||
}
|
||||
else if ( event->mimeData()->hasText() )
|
||||
{
|
||||
QColor col = color_widgets::colorFromString(event->mimeData()->text(), p->show_alpha);
|
||||
if ( col.isValid() )
|
||||
{
|
||||
setColor(col);
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ColorLineEdit::previewColor() const
|
||||
{
|
||||
return p->preview_color;
|
||||
}
|
||||
|
||||
void ColorLineEdit::setPreviewColor(bool previewColor)
|
||||
{
|
||||
if ( previewColor != p->preview_color )
|
||||
{
|
||||
p->preview_color = previewColor;
|
||||
|
||||
if ( p->preview_color )
|
||||
p->setPalette(p->color, this);
|
||||
else
|
||||
setPalette(QApplication::palette());
|
||||
|
||||
Q_EMIT previewColorChanged(p->preview_color);
|
||||
}
|
||||
}
|
||||
|
||||
void ColorLineEdit::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
if ( p->customAlpha() )
|
||||
{
|
||||
QPainter painter(this);
|
||||
QStyleOptionFrame panel;
|
||||
initStyleOption(&panel);
|
||||
QRect r = style()->subElementRect(QStyle::SE_LineEditContents, &panel, nullptr);
|
||||
painter.fillRect(r, p->background);
|
||||
painter.fillRect(r, p->color);
|
||||
}
|
||||
|
||||
QLineEdit::paintEvent(event);
|
||||
}
|
||||
|
||||
} // namespace color_widgets
|
||||
140
src/external/qt-color-widgets/src/color_list_widget.cpp
vendored
Normal file
140
src/external/qt-color-widgets/src/color_list_widget.cpp
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "qt-color-widgets/color_list_widget.hpp"
|
||||
#include "qt-color-widgets/color_selector.hpp"
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
class ColorListWidget::Private
|
||||
{
|
||||
public:
|
||||
QList<QColor> colors;
|
||||
QSignalMapper mapper;
|
||||
ColorWheel::DisplayFlags wheel_flags;
|
||||
};
|
||||
|
||||
ColorListWidget::ColorListWidget(QWidget *parent)
|
||||
: AbstractWidgetList(parent), p(new Private)
|
||||
{
|
||||
connect(this, &AbstractWidgetList::removed, this, &ColorListWidget::handle_removed);
|
||||
connect(&p->mapper, SIGNAL(mapped(int)), SLOT(color_changed(int)));
|
||||
p->wheel_flags = ColorWheel::defaultDisplayFlags();
|
||||
}
|
||||
|
||||
ColorListWidget::~ColorListWidget()
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
|
||||
QList<QColor> ColorListWidget::colors() const
|
||||
{
|
||||
return p->colors;
|
||||
}
|
||||
|
||||
void ColorListWidget::setColors(const QList<QColor> &colors)
|
||||
{
|
||||
clear();
|
||||
p->colors = colors;
|
||||
for(int i = 0;i < colors.size();i++ )
|
||||
append_widget(i);
|
||||
Q_EMIT colorsChanged(colors);
|
||||
}
|
||||
|
||||
void ColorListWidget::swap(int a, int b)
|
||||
{
|
||||
ColorSelector* sa = widget_cast<ColorSelector>(a);
|
||||
ColorSelector* sb = widget_cast<ColorSelector>(b);
|
||||
if ( sa && sb )
|
||||
{
|
||||
QColor ca = sa->color();
|
||||
sa->setColor(sb->color());
|
||||
sb->setColor(ca);
|
||||
Q_EMIT colorsChanged(p->colors);
|
||||
}
|
||||
}
|
||||
|
||||
void ColorListWidget::append()
|
||||
{
|
||||
p->colors.push_back(Qt::black);
|
||||
append_widget(p->colors.size()-1);
|
||||
Q_EMIT colorsChanged(p->colors);
|
||||
Q_EMIT color_added();
|
||||
}
|
||||
|
||||
void ColorListWidget::emit_changed()
|
||||
{
|
||||
Q_EMIT colorsChanged(p->colors);
|
||||
}
|
||||
|
||||
void ColorListWidget::handle_removed(int i)
|
||||
{
|
||||
p->colors.removeAt(i);
|
||||
Q_EMIT colorsChanged(p->colors);
|
||||
}
|
||||
|
||||
void ColorListWidget::color_changed(int row)
|
||||
{
|
||||
ColorSelector *cs = widget_cast<ColorSelector>(row);
|
||||
if ( cs )
|
||||
{
|
||||
p->colors[row] = cs->color();
|
||||
Q_EMIT colorsChanged(p->colors);
|
||||
}
|
||||
}
|
||||
|
||||
void ColorListWidget::setColorAt(int i, QColor const& color)
|
||||
{
|
||||
p->colors[i] = color;
|
||||
ColorSelector* cs = widget_cast<ColorSelector>(i);
|
||||
cs->setColor(color);
|
||||
Q_EMIT colorsChanged(p->colors);
|
||||
}
|
||||
|
||||
void ColorListWidget::append_widget(int col)
|
||||
{
|
||||
ColorSelector* cbs = new ColorSelector;
|
||||
cbs->setDisplayMode(ColorPreview::AllAlpha);
|
||||
cbs->setColor(p->colors[col]);
|
||||
//connect(cbs,SIGNAL(colorChanged(QColor)),SLOT(emit_changed()));
|
||||
p->mapper.setMapping(cbs,col);
|
||||
connect(cbs,SIGNAL(colorChanged(QColor)),&p->mapper,SLOT(map()));
|
||||
connect(this,&ColorListWidget::wheelFlagsChanged,
|
||||
cbs,&ColorSelector::setWheelFlags);
|
||||
appendWidget(cbs);
|
||||
setRowHeight(count()-1,22);
|
||||
}
|
||||
|
||||
ColorWheel::DisplayFlags ColorListWidget::wheelFlags() const
|
||||
{
|
||||
return p->wheel_flags;
|
||||
}
|
||||
|
||||
void ColorListWidget::setWheelFlags(ColorWheel::DisplayFlags flags)
|
||||
{
|
||||
if ( p->wheel_flags != flags )
|
||||
{
|
||||
p->wheel_flags = flags;
|
||||
Q_EMIT wheelFlagsChanged(flags);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace color_widgets
|
||||
89
src/external/qt-color-widgets/src/color_names.cpp
vendored
Normal file
89
src/external/qt-color-widgets/src/color_names.cpp
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "qt-color-widgets/color_names.hpp"
|
||||
#include <QRegularExpression>
|
||||
|
||||
static QRegularExpression regex_qcolor (QStringLiteral("^(?:(?:#[[:xdigit:]]{3})|(?:#[[:xdigit:]]{6})|(?:[[:alpha:]]+))$"));
|
||||
static QRegularExpression regex_func_rgb (QStringLiteral(R"(^rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)$)"));
|
||||
static QRegularExpression regex_hex_rgba (QStringLiteral("^#[[:xdigit:]]{8}$"));
|
||||
static QRegularExpression regex_func_rgba (QStringLiteral(R"(^rgba?\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)$)"));
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
|
||||
QString stringFromColor(const QColor& color, bool alpha)
|
||||
{
|
||||
if ( !alpha || color.alpha() == 255 )
|
||||
return color.name();
|
||||
return color.name()+QStringLiteral("%1").arg(color.alpha(), 2, 16, QChar('0'));
|
||||
}
|
||||
|
||||
QColor colorFromString(const QString& string, bool alpha)
|
||||
{
|
||||
QString xs = string.trimmed();
|
||||
QRegularExpressionMatch match;
|
||||
|
||||
match = regex_qcolor.match(xs);
|
||||
if ( match.hasMatch() )
|
||||
{
|
||||
return QColor(xs);
|
||||
}
|
||||
|
||||
match = regex_func_rgb.match(xs);
|
||||
if ( match.hasMatch() )
|
||||
{
|
||||
return QColor(
|
||||
match.captured(1).toInt(),
|
||||
match.captured(2).toInt(),
|
||||
match.captured(3).toInt()
|
||||
);
|
||||
}
|
||||
|
||||
if ( alpha )
|
||||
{
|
||||
match = regex_hex_rgba.match(xs);
|
||||
if ( match.hasMatch() )
|
||||
{
|
||||
return QColor(
|
||||
xs.mid(1,2).toInt(nullptr,16),
|
||||
xs.mid(3,2).toInt(nullptr,16),
|
||||
xs.mid(5,2).toInt(nullptr,16),
|
||||
xs.mid(7,2).toInt(nullptr,16)
|
||||
);
|
||||
}
|
||||
|
||||
match = regex_func_rgba.match(xs);
|
||||
if ( match.hasMatch() )
|
||||
{
|
||||
return QColor(
|
||||
match.captured(1).toInt(),
|
||||
match.captured(2).toInt(),
|
||||
match.captured(3).toInt(),
|
||||
match.captured(4).toInt()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return QColor();
|
||||
}
|
||||
|
||||
} // namespace color_widgets
|
||||
498
src/external/qt-color-widgets/src/color_palette.cpp
vendored
Normal file
498
src/external/qt-color-widgets/src/color_palette.cpp
vendored
Normal file
@@ -0,0 +1,498 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "qt-color-widgets/color_palette.hpp"
|
||||
#include <cmath>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QHash>
|
||||
#include <QPainter>
|
||||
#include <QFileInfo>
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
class ColorPalette::Private
|
||||
{
|
||||
public:
|
||||
QVector<QPair<QColor,QString> > colors;
|
||||
int columns;
|
||||
QString name;
|
||||
QString fileName;
|
||||
bool dirty;
|
||||
|
||||
bool valid_index(int index)
|
||||
{
|
||||
return index >= 0 && index < colors.size();
|
||||
}
|
||||
};
|
||||
|
||||
ColorPalette::ColorPalette(const QVector<QColor>& colors,
|
||||
const QString& name,
|
||||
int columns)
|
||||
: p ( new Private )
|
||||
{
|
||||
setName(name);
|
||||
setColumns(columns);
|
||||
setColors(colors);
|
||||
}
|
||||
|
||||
ColorPalette::ColorPalette(const QString& name)
|
||||
: p ( new Private )
|
||||
{
|
||||
setName(name);
|
||||
p->columns = 0;
|
||||
p->dirty = false;
|
||||
}
|
||||
|
||||
ColorPalette::ColorPalette(const QVector<QPair<QColor,QString> >& colors,
|
||||
const QString& name,
|
||||
int columns)
|
||||
{
|
||||
setName(name);
|
||||
setColumns(columns);
|
||||
setColors(colors);
|
||||
p->dirty = false;
|
||||
}
|
||||
|
||||
ColorPalette::ColorPalette(const ColorPalette& other)
|
||||
: QObject(), p ( new Private(*other.p) )
|
||||
{
|
||||
}
|
||||
|
||||
ColorPalette& ColorPalette::operator=(const ColorPalette& other)
|
||||
{
|
||||
*p = *other.p;
|
||||
emitUpdate();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ColorPalette::~ColorPalette()
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
|
||||
ColorPalette::ColorPalette(ColorPalette&& other)
|
||||
: QObject(), p ( other.p )
|
||||
{
|
||||
other.p = nullptr;
|
||||
}
|
||||
ColorPalette& ColorPalette::operator=(ColorPalette&& other)
|
||||
{
|
||||
std::swap(p, other.p);
|
||||
emitUpdate();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ColorPalette::emitUpdate()
|
||||
{
|
||||
Q_EMIT colorsChanged(p->colors);
|
||||
Q_EMIT columnsChanged(p->columns);
|
||||
Q_EMIT nameChanged(p->name);
|
||||
Q_EMIT fileNameChanged(p->fileName);
|
||||
Q_EMIT dirtyChanged(p->dirty);
|
||||
}
|
||||
|
||||
QColor ColorPalette::colorAt(int index) const
|
||||
{
|
||||
return p->valid_index(index) ? p->colors[index].first : QColor();
|
||||
}
|
||||
|
||||
QString ColorPalette::nameAt(int index) const
|
||||
{
|
||||
return p->valid_index(index) ? p->colors[index].second : QString();
|
||||
}
|
||||
|
||||
QVector<QPair<QColor,QString> > ColorPalette::colors() const
|
||||
{
|
||||
return p->colors;
|
||||
}
|
||||
|
||||
int ColorPalette::count() const
|
||||
{
|
||||
return p->colors.size();
|
||||
}
|
||||
|
||||
int ColorPalette::columns()
|
||||
{
|
||||
return p->columns;
|
||||
}
|
||||
|
||||
QString ColorPalette::name() const
|
||||
{
|
||||
return p->name;
|
||||
}
|
||||
|
||||
void ColorPalette::loadColorTable(const QVector<QRgb>& color_table)
|
||||
{
|
||||
p->colors.clear();
|
||||
p->colors.reserve(color_table.size());
|
||||
for ( QRgb c : color_table )
|
||||
{
|
||||
QColor color ( c );
|
||||
color.setAlpha(255);
|
||||
p->colors.push_back(qMakePair(color,QString()));
|
||||
}
|
||||
Q_EMIT colorsChanged(p->colors);
|
||||
setDirty(true);
|
||||
}
|
||||
|
||||
bool ColorPalette::loadImage(const QImage& image)
|
||||
{
|
||||
if ( image.isNull() )
|
||||
return false;
|
||||
setColumns(image.width());
|
||||
|
||||
p->colors.clear();
|
||||
p->colors.reserve(image.width()*image.height());
|
||||
for ( int y = 0; y < image.height(); y++ )
|
||||
{
|
||||
for ( int x = 0; x < image.width(); x++ )
|
||||
{
|
||||
QColor color ( image.pixel(x, y) );
|
||||
color.setAlpha(255);
|
||||
p->colors.push_back(qMakePair(color,QString()));
|
||||
}
|
||||
}
|
||||
Q_EMIT colorsChanged(p->colors);
|
||||
setDirty(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
ColorPalette ColorPalette::fromImage(const QImage& image)
|
||||
{
|
||||
ColorPalette p;
|
||||
p.loadImage(image);
|
||||
return p;
|
||||
}
|
||||
|
||||
bool ColorPalette::load(const QString& name)
|
||||
{
|
||||
p->fileName = name;
|
||||
p->colors.clear();
|
||||
p->columns = 0;
|
||||
p->dirty = false;
|
||||
p->name = QFileInfo(name).baseName();
|
||||
|
||||
QFile file(name);
|
||||
|
||||
if ( !file.open(QFile::ReadOnly|QFile::Text) )
|
||||
{
|
||||
emitUpdate();
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream stream( &file );
|
||||
|
||||
if ( stream.readLine() != QLatin1String("GIMP Palette") )
|
||||
{
|
||||
emitUpdate();
|
||||
return false;
|
||||
}
|
||||
|
||||
QString line;
|
||||
|
||||
// parse properties
|
||||
QHash<QString,QString> properties;
|
||||
while( !stream.atEnd() )
|
||||
{
|
||||
line = stream.readLine();
|
||||
if ( line.isEmpty() )
|
||||
continue;
|
||||
if ( line[0] == '#' )
|
||||
break;
|
||||
int colon = line.indexOf(':');
|
||||
if ( colon == -1 )
|
||||
break;
|
||||
properties[line.left(colon).toLower()] =
|
||||
line.right(line.size() - colon - 1).trimmed();
|
||||
}
|
||||
/// \todo Store extra properties in the palette object
|
||||
setName(properties[QStringLiteral("name")]);
|
||||
setColumns(properties[QStringLiteral("columns")].toInt());
|
||||
|
||||
// Skip comments
|
||||
if ( !stream.atEnd() && line[0] == '#' )
|
||||
while( !stream.atEnd() )
|
||||
{
|
||||
qint64 pos = stream.pos();
|
||||
line = stream.readLine();
|
||||
if ( !line.isEmpty() && line[0] != '#' )
|
||||
{
|
||||
stream.seek(pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while( !stream.atEnd() )
|
||||
{
|
||||
int r = 0, g = 0, b = 0;
|
||||
stream >> r >> g >> b;
|
||||
line = stream.readLine().trimmed();
|
||||
p->colors.push_back(qMakePair(QColor(r, g, b), line));
|
||||
}
|
||||
|
||||
Q_EMIT colorsChanged(p->colors);
|
||||
setDirty(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ColorPalette ColorPalette::fromFile(const QString& name)
|
||||
{
|
||||
ColorPalette p;
|
||||
p.load(name);
|
||||
return p;
|
||||
}
|
||||
|
||||
bool ColorPalette::save(const QString& filename)
|
||||
{
|
||||
setFileName(filename);
|
||||
return save();
|
||||
}
|
||||
|
||||
bool ColorPalette::save()
|
||||
{
|
||||
QString filename = p->fileName;
|
||||
if ( filename.isEmpty() )
|
||||
{
|
||||
filename = unnamed(p->name)+".gpl";
|
||||
}
|
||||
|
||||
QFile file(filename);
|
||||
if ( !file.open(QFile::Text|QFile::WriteOnly) )
|
||||
return false;
|
||||
|
||||
QTextStream stream(&file);
|
||||
|
||||
stream << "GIMP Palette\n";
|
||||
stream << "Name: " << unnamed(p->name) << '\n';
|
||||
if ( p->columns )
|
||||
stream << "Columns: " << p->columns << '\n';
|
||||
/// \todo Options to add comments
|
||||
stream << "#\n";
|
||||
|
||||
for ( int i = 0; i < p->colors.size(); i++ )
|
||||
{
|
||||
stream << qSetFieldWidth(3) << p->colors[i].first.red() << qSetFieldWidth(0) << ' '
|
||||
<< qSetFieldWidth(3) << p->colors[i].first.green() << qSetFieldWidth(0) << ' '
|
||||
<< qSetFieldWidth(3) << p->colors[i].first.blue() << qSetFieldWidth(0) << '\t'
|
||||
<< unnamed(p->colors[i].second) << '\n';
|
||||
}
|
||||
|
||||
if ( !file.error() )
|
||||
{
|
||||
setDirty(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
QString ColorPalette::fileName() const
|
||||
{
|
||||
return p->fileName;
|
||||
}
|
||||
|
||||
|
||||
void ColorPalette::setColumns(int columns)
|
||||
{
|
||||
if ( columns <= 0 )
|
||||
columns = 0;
|
||||
|
||||
if ( columns != p->columns )
|
||||
{
|
||||
setDirty(true);
|
||||
Q_EMIT columnsChanged( p->columns = columns );
|
||||
}
|
||||
}
|
||||
|
||||
void ColorPalette::setColors(const QVector<QColor>& colors)
|
||||
{
|
||||
p->colors.clear();
|
||||
Q_FOREACH(const QColor& col, colors)
|
||||
p->colors.push_back(qMakePair(col,QString()));
|
||||
setDirty(true);
|
||||
Q_EMIT colorsChanged(p->colors);
|
||||
}
|
||||
|
||||
void ColorPalette::setColors(const QVector<QPair<QColor,QString> >& colors)
|
||||
{
|
||||
p->colors = colors;
|
||||
setDirty(true);
|
||||
Q_EMIT colorsChanged(p->colors);
|
||||
}
|
||||
|
||||
|
||||
void ColorPalette::setColorAt(int index, const QColor& color)
|
||||
{
|
||||
if ( !p->valid_index(index) )
|
||||
return;
|
||||
|
||||
p->colors[index].first = color;
|
||||
|
||||
setDirty(true);
|
||||
Q_EMIT colorChanged(index);
|
||||
Q_EMIT colorsUpdated(p->colors);
|
||||
}
|
||||
|
||||
void ColorPalette::setColorAt(int index, const QColor& color, const QString& name)
|
||||
{
|
||||
if ( !p->valid_index(index) )
|
||||
return;
|
||||
|
||||
p->colors[index].first = color;
|
||||
p->colors[index].second = name;
|
||||
setDirty(true);
|
||||
Q_EMIT colorChanged(index);
|
||||
Q_EMIT colorsUpdated(p->colors);
|
||||
}
|
||||
|
||||
void ColorPalette::setNameAt(int index, const QString& name)
|
||||
{
|
||||
if ( !p->valid_index(index) )
|
||||
return;
|
||||
|
||||
p->colors[index].second = name;
|
||||
|
||||
setDirty(true);
|
||||
Q_EMIT colorChanged(index);
|
||||
Q_EMIT colorsUpdated(p->colors);
|
||||
}
|
||||
|
||||
|
||||
void ColorPalette::appendColor(const QColor& color, const QString& name)
|
||||
{
|
||||
p->colors.push_back(qMakePair(color,name));
|
||||
setDirty(true);
|
||||
Q_EMIT colorAdded(p->colors.size()-1);
|
||||
Q_EMIT colorsUpdated(p->colors);
|
||||
}
|
||||
|
||||
void ColorPalette::insertColor(int index, const QColor& color, const QString& name)
|
||||
{
|
||||
if ( index < 0 || index > p->colors.size() )
|
||||
return;
|
||||
|
||||
p->colors.insert(index, qMakePair(color, name));
|
||||
|
||||
setDirty(true);
|
||||
Q_EMIT colorAdded(index);
|
||||
Q_EMIT colorsUpdated(p->colors);
|
||||
}
|
||||
|
||||
void ColorPalette::eraseColor(int index)
|
||||
{
|
||||
if ( !p->valid_index(index) )
|
||||
return;
|
||||
|
||||
p->colors.remove(index);
|
||||
|
||||
setDirty(true);
|
||||
Q_EMIT colorRemoved(index);
|
||||
Q_EMIT colorsUpdated(p->colors);
|
||||
}
|
||||
|
||||
void ColorPalette::setName(const QString& name)
|
||||
{
|
||||
setDirty(true);
|
||||
p->name = name;
|
||||
}
|
||||
|
||||
void ColorPalette::setFileName(const QString& name)
|
||||
{
|
||||
setDirty(true);
|
||||
p->fileName = name;
|
||||
}
|
||||
|
||||
QString ColorPalette::unnamed(const QString& name) const
|
||||
{
|
||||
return name.isEmpty() ? tr("Unnamed") : name;
|
||||
}
|
||||
|
||||
|
||||
QPixmap ColorPalette::preview(const QSize& size, const QColor& background) const
|
||||
{
|
||||
if ( !size.isValid() || p->colors.empty() )
|
||||
return QPixmap();
|
||||
|
||||
QPixmap out( size );
|
||||
out.fill(background);
|
||||
QPainter painter(&out);
|
||||
|
||||
int count = p->colors.size();
|
||||
int columns = p->columns;
|
||||
if ( !columns )
|
||||
columns = std::ceil( std::sqrt( count * float(size.width()) / size.height() ) );
|
||||
int rows = std::ceil( float(count) / columns );
|
||||
QSizeF color_size(float(size.width()) / columns, float(size.height()) / rows);
|
||||
|
||||
for ( int y = 0, i = 0; y < rows && i < count; y++ )
|
||||
{
|
||||
for ( int x = 0; x < columns && i < count; x++, i++ )
|
||||
{
|
||||
painter.fillRect(QRectF(x*color_size.width(), y*color_size.height(),
|
||||
color_size.width(), color_size.height()),
|
||||
p->colors[i].first
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
bool ColorPalette::dirty() const
|
||||
{
|
||||
return p->dirty;
|
||||
}
|
||||
|
||||
void ColorPalette::setDirty(bool dirty)
|
||||
{
|
||||
if ( dirty != p->dirty )
|
||||
Q_EMIT dirtyChanged( p->dirty = dirty );
|
||||
}
|
||||
|
||||
QVector<QColor> ColorPalette::onlyColors() const
|
||||
{
|
||||
QVector<QColor> out;
|
||||
out.reserve(p->colors.size());
|
||||
for ( int i = 0; i < p->colors.size(); i++ )
|
||||
out.push_back(p->colors[i].first);
|
||||
return out;
|
||||
}
|
||||
|
||||
QVector<QRgb> ColorPalette::colorTable() const
|
||||
{
|
||||
QVector<QRgb> out;
|
||||
out.reserve(p->colors.size());
|
||||
for ( const auto& color_pair : p->colors )
|
||||
out.push_back(color_pair.first.rgba());
|
||||
return out;
|
||||
}
|
||||
|
||||
ColorPalette ColorPalette::fromColorTable(const QVector<QRgb>& table)
|
||||
{
|
||||
ColorPalette palette;
|
||||
palette.loadColorTable(table);
|
||||
return palette;
|
||||
}
|
||||
|
||||
} // namespace color_widgets
|
||||
329
src/external/qt-color-widgets/src/color_palette_model.cpp
vendored
Normal file
329
src/external/qt-color-widgets/src/color_palette_model.cpp
vendored
Normal file
@@ -0,0 +1,329 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "qt-color-widgets/color_palette_model.hpp"
|
||||
#include <QDir>
|
||||
#include <QList>
|
||||
#include <QRegularExpression>
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
class ColorPaletteModel::Private
|
||||
{
|
||||
public:
|
||||
/// \todo Keep sorted by name (?)
|
||||
QList<ColorPalette> palettes;
|
||||
QSize icon_size;
|
||||
QStringList search_paths;
|
||||
QString save_path;
|
||||
|
||||
Private()
|
||||
: icon_size(32, 32)
|
||||
{}
|
||||
|
||||
bool acceptable(const QModelIndex& index) const
|
||||
{
|
||||
return acceptable(index.row());
|
||||
}
|
||||
|
||||
bool acceptable(int row) const
|
||||
{
|
||||
return row >= 0 && row <= palettes.count();
|
||||
}
|
||||
|
||||
QList<ColorPalette>::iterator find(const QString& name)
|
||||
{
|
||||
return std::find_if(palettes.begin(), palettes.end(),
|
||||
[&name](const ColorPalette& palette) {
|
||||
return palette.name() == name;
|
||||
});
|
||||
}
|
||||
|
||||
bool attemptSave(ColorPalette& palette, const QString& filename)
|
||||
{
|
||||
if ( filename.isEmpty() )
|
||||
return false;
|
||||
return palette.save(filename);
|
||||
}
|
||||
|
||||
void fixUnnamed(ColorPalette& palette)
|
||||
{
|
||||
if ( palette.name().isEmpty() )
|
||||
palette.setName(ColorPaletteModel::tr("Unnamed"));
|
||||
}
|
||||
|
||||
bool save(ColorPalette& palette, const QString& suggested_filename = QString())
|
||||
{
|
||||
// Attempt to save with the existing file names
|
||||
if ( !suggested_filename.isEmpty() && attemptSave(palette, suggested_filename) )
|
||||
return true;
|
||||
if ( attemptSave(palette, palette.fileName()) )
|
||||
return true;
|
||||
|
||||
// Set up the save directory
|
||||
QDir save_dir(save_path);
|
||||
if ( !save_dir.exists() && !QDir().mkdir(save_path) )
|
||||
return false;
|
||||
|
||||
// Attempt to save as (Name).gpl
|
||||
QString filename = palette.name()+".gpl";
|
||||
if ( !save_dir.exists(filename) &&
|
||||
attemptSave(palette, save_dir.absoluteFilePath(filename)) )
|
||||
return true;
|
||||
|
||||
// Get all of the files matching the pattern *.gpl
|
||||
save_dir.setNameFilters(QStringList() << QStringLiteral("*.gpl"));
|
||||
save_dir.setFilter(QDir::Files);
|
||||
QStringList existing_files = save_dir.entryList();
|
||||
|
||||
// For all the files that match (Name)(Number).gpl, find the maximum (Number)
|
||||
QRegularExpression name_regex(QRegularExpression::escape(palette.name())+"([0-9]+)\\.gpl");
|
||||
int max = 0;
|
||||
for ( const auto& existing_file : existing_files )
|
||||
{
|
||||
QRegularExpressionMatch match = name_regex.match(existing_file);
|
||||
if ( match.hasMatch() )
|
||||
{
|
||||
int num = match.captured(1).toInt();
|
||||
if ( num > max )
|
||||
max = num;
|
||||
}
|
||||
}
|
||||
|
||||
return attemptSave(palette,
|
||||
save_dir.absoluteFilePath(QStringLiteral("%1%2.gpl").arg(palette.name()).arg(max+1))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
ColorPaletteModel::ColorPaletteModel()
|
||||
: p ( new Private )
|
||||
{}
|
||||
|
||||
ColorPaletteModel::~ColorPaletteModel()
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
|
||||
int ColorPaletteModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
return count();
|
||||
}
|
||||
|
||||
QVariant ColorPaletteModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if ( !p->acceptable(index) )
|
||||
return QVariant();
|
||||
|
||||
const ColorPalette& palette = p->palettes[index.row()];
|
||||
switch( role )
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
return palette.name();
|
||||
case Qt::DecorationRole:
|
||||
return palette.preview(p->icon_size);
|
||||
case Qt::ToolTipRole:
|
||||
return tr("%1 (%2 colors)").arg(palette.name()).arg(palette.count());
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool ColorPaletteModel::removeRows(int row, int count, const QModelIndex & parent)
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
|
||||
if ( !p->acceptable(row) || count <= 0 )
|
||||
return false;
|
||||
|
||||
auto begin = p->palettes.begin() + row;
|
||||
auto end = row + count >= p->palettes.size() ? p->palettes.end() : begin + count;
|
||||
for ( auto it = begin; it != end; ++it )
|
||||
{
|
||||
if ( !it->fileName().isEmpty() )
|
||||
{
|
||||
QFileInfo file(it->fileName());
|
||||
if ( file.isWritable() && file.isFile() )
|
||||
QFile::remove(it->fileName());
|
||||
}
|
||||
}
|
||||
|
||||
p->palettes.erase(begin, end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QSize ColorPaletteModel::iconSize() const
|
||||
{
|
||||
return p->icon_size;
|
||||
}
|
||||
|
||||
void ColorPaletteModel::setIconSize(const QSize& iconSize)
|
||||
{
|
||||
if ( p->icon_size != iconSize )
|
||||
Q_EMIT iconSizeChanged( p->icon_size = iconSize );
|
||||
}
|
||||
|
||||
QString ColorPaletteModel::savePath() const
|
||||
{
|
||||
return p->save_path;
|
||||
}
|
||||
|
||||
QStringList ColorPaletteModel::searchPaths() const
|
||||
{
|
||||
return p->search_paths;
|
||||
}
|
||||
|
||||
void ColorPaletteModel::setSavePath(const QString& savePath)
|
||||
{
|
||||
if ( p->save_path != savePath )
|
||||
Q_EMIT savePathChanged( p->save_path = savePath );
|
||||
}
|
||||
|
||||
void ColorPaletteModel::setSearchPaths(const QStringList& searchPaths)
|
||||
{
|
||||
if ( p->search_paths != searchPaths )
|
||||
Q_EMIT searchPathsChanged( p->search_paths = searchPaths );
|
||||
}
|
||||
|
||||
void ColorPaletteModel::addSearchPath(const QString& path)
|
||||
{
|
||||
/// \todo Should compare canonical paths
|
||||
/// and these checks should also be made in setSearchPaths
|
||||
if ( !p->search_paths.contains(path) )
|
||||
{
|
||||
p->search_paths.push_back(path);
|
||||
Q_EMIT searchPathsChanged( p->search_paths );
|
||||
}
|
||||
}
|
||||
|
||||
void ColorPaletteModel::load()
|
||||
{
|
||||
beginResetModel();
|
||||
p->palettes.clear();
|
||||
QStringList filters;
|
||||
filters << QStringLiteral("*.gpl");
|
||||
for ( const QString& directory_name : p->search_paths )
|
||||
{
|
||||
QDir directory(directory_name);
|
||||
directory.setNameFilters(filters);
|
||||
directory.setFilter(QDir::Files|QDir::Readable);
|
||||
directory.setSorting(QDir::Name);
|
||||
for ( const QFileInfo& file : directory.entryInfoList() )
|
||||
{
|
||||
ColorPalette palette;
|
||||
if ( palette.load(file.absoluteFilePath()) )
|
||||
{
|
||||
p->palettes.push_back(palette);
|
||||
}
|
||||
}
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
bool ColorPaletteModel::hasPalette(const QString& name) const
|
||||
{
|
||||
return p->find(name) != p->palettes.end();
|
||||
}
|
||||
|
||||
int ColorPaletteModel::count() const
|
||||
{
|
||||
return p->palettes.size();
|
||||
}
|
||||
|
||||
const ColorPalette& ColorPaletteModel::palette(const QString& name) const
|
||||
{
|
||||
return *p->find(name);
|
||||
}
|
||||
|
||||
const ColorPalette& ColorPaletteModel::palette(int index) const
|
||||
{
|
||||
return p->palettes[index];
|
||||
}
|
||||
|
||||
bool ColorPaletteModel::updatePalette(int index, const ColorPalette& palette, bool save)
|
||||
{
|
||||
if ( !p->acceptable(index) )
|
||||
return false;
|
||||
|
||||
// Store the old file name
|
||||
QString filename = p->palettes[index].fileName();
|
||||
// Update the palette
|
||||
ColorPalette& local_palette = p->palettes[index] = palette;
|
||||
p->fixUnnamed(local_palette);
|
||||
|
||||
if ( save )
|
||||
return p->save(local_palette, filename);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ColorPaletteModel::removePalette(int index, bool remove_file)
|
||||
{
|
||||
if ( !p->acceptable(index) )
|
||||
return false;
|
||||
|
||||
QString file_name = p->palettes[index].fileName();
|
||||
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
p->palettes.removeAt(index);
|
||||
endRemoveRows();
|
||||
|
||||
if ( !file_name.isEmpty() && remove_file )
|
||||
{
|
||||
QFileInfo file(file_name);
|
||||
if ( file.isWritable() && file.isFile() )
|
||||
return QFile::remove(file_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ColorPaletteModel::addPalette(const ColorPalette& palette, bool save)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), p->palettes.size(), p->palettes.size());
|
||||
p->palettes.push_back(palette);
|
||||
p->fixUnnamed(p->palettes.back());
|
||||
endInsertRows();
|
||||
|
||||
if ( save )
|
||||
return p->save(p->palettes.back());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int ColorPaletteModel::indexFromFile(const QString& filename) const
|
||||
{
|
||||
QString canonical = QFileInfo(filename).canonicalFilePath();
|
||||
int i = 0;
|
||||
for ( const auto& pal : p->palettes )
|
||||
{
|
||||
if ( !pal.fileName().isEmpty() &&
|
||||
QFileInfo(pal.fileName()).canonicalFilePath() == canonical )
|
||||
return i;
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace color_widgets
|
||||
415
src/external/qt-color-widgets/src/color_palette_widget.cpp
vendored
Normal file
415
src/external/qt-color-widgets/src/color_palette_widget.cpp
vendored
Normal file
@@ -0,0 +1,415 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "qt-color-widgets/color_palette_widget.hpp"
|
||||
#include "ui_color_palette_widget.h"
|
||||
#include "qt-color-widgets/color_dialog.hpp"
|
||||
#include <QInputDialog>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QImageReader>
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
class ColorPaletteWidget::Private : public Ui::ColorPaletteWidget
|
||||
{
|
||||
public:
|
||||
ColorPaletteModel* model = nullptr;
|
||||
bool read_only = false;
|
||||
|
||||
bool hasSelectedPalette()
|
||||
{
|
||||
return model && palette_list->currentIndex() != -1;
|
||||
}
|
||||
|
||||
const ColorPalette& selectedPalette()
|
||||
{
|
||||
return model->palette(palette_list->currentIndex());
|
||||
}
|
||||
|
||||
void addPalette(ColorPalette& palette)
|
||||
{
|
||||
bool save = false;
|
||||
// Save palettes in the savePath
|
||||
/// \todo This currently breaks opening the right directory
|
||||
/// ie: the one containing the original file.
|
||||
if ( !palette.fileName().isEmpty() )
|
||||
{
|
||||
QFileInfo file(palette.fileName());
|
||||
if ( file.dir().canonicalPath() != QDir(model->savePath()).canonicalPath() )
|
||||
{
|
||||
palette.setFileName(QString());
|
||||
save = true;
|
||||
}
|
||||
}
|
||||
model->addPalette(palette, save);
|
||||
palette_list->setCurrentIndex(model->count()-1);
|
||||
}
|
||||
|
||||
bool openImage(const QString& file)
|
||||
{
|
||||
QImage image(file);
|
||||
if ( !image.isNull() )
|
||||
{
|
||||
ColorPalette palette;
|
||||
palette.loadImage(image);
|
||||
palette.setName(QFileInfo(file).baseName());
|
||||
palette.setFileName(file+".gpl");
|
||||
addPalette(palette);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool openGpl(const QString& file)
|
||||
{
|
||||
int existing = model->indexFromFile(file);
|
||||
if ( existing != -1 )
|
||||
{
|
||||
palette_list->setCurrentIndex(existing);
|
||||
return true;
|
||||
}
|
||||
|
||||
ColorPalette palette;
|
||||
if ( palette.load(file) )
|
||||
{
|
||||
addPalette(palette);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool openPalette(const QString& file, int type)
|
||||
{
|
||||
if ( type == 1 )
|
||||
return openImage(file);
|
||||
return openGpl(file);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ColorPaletteWidget::ColorPaletteWidget(QWidget* parent)
|
||||
: QWidget(parent), p(new Private)
|
||||
{
|
||||
p->setupUi(this);
|
||||
|
||||
// Connext Swatch signals
|
||||
connect(p->swatch, &Swatch::colorSizeChanged, this, &ColorPaletteWidget::colorSizeChanged);
|
||||
connect(p->swatch, &Swatch::colorSizePolicyChanged, this, &ColorPaletteWidget::colorSizePolicyChanged);
|
||||
connect(p->swatch, &Swatch::forcedRowsChanged, this, &ColorPaletteWidget::forcedRowsChanged);
|
||||
connect(p->swatch, &Swatch::forcedColumnsChanged, this, &ColorPaletteWidget::forcedColumnsChanged);
|
||||
connect(p->swatch, &Swatch::colorSelected,
|
||||
this, (void (ColorPaletteWidget::*)(const QColor&)) &ColorPaletteWidget::currentColorChanged);
|
||||
connect(p->swatch, &Swatch::selectedChanged,
|
||||
this, (void (ColorPaletteWidget::*)(int)) &ColorPaletteWidget::currentColorChanged);
|
||||
connect(p->swatch, &Swatch::borderChanged, this, &ColorPaletteWidget::borderChanged);
|
||||
|
||||
connect(&p->swatch->palette(), &ColorPalette::dirtyChanged, p->button_palette_save, &QWidget::setEnabled);
|
||||
connect(&p->swatch->palette(), &ColorPalette::dirtyChanged, p->button_palette_revert, &QWidget::setEnabled);
|
||||
|
||||
connect(p->palette_list, (void (QComboBox::*)(int))&QComboBox::currentIndexChanged,
|
||||
this, &ColorPaletteWidget::currentRowChanged);
|
||||
|
||||
// Buttons changing the colors in the current palette
|
||||
connect(p->button_color_add, &QAbstractButton::clicked, [this](){
|
||||
if ( !p->read_only && p->hasSelectedPalette() )
|
||||
{
|
||||
ColorDialog dialog(this);
|
||||
dialog.setAlphaEnabled(false);
|
||||
if ( p->swatch->selected() != -1 )
|
||||
dialog.setColor(p->swatch->selectedColor());
|
||||
if ( dialog.exec() )
|
||||
{
|
||||
p->swatch->palette().appendColor(dialog.color());
|
||||
p->swatch->setSelected(p->swatch->palette().count()-1);
|
||||
}
|
||||
}
|
||||
});
|
||||
connect(p->button_color_remove, &QAbstractButton::clicked, p->swatch, &Swatch::removeSelected);
|
||||
|
||||
// Buttons modifying the current palette file
|
||||
connect(p->button_palette_delete, &QAbstractButton::clicked, [this]() {
|
||||
if ( !p->read_only && p->hasSelectedPalette() )
|
||||
p->model->removePalette(p->palette_list->currentIndex());
|
||||
});
|
||||
connect(p->button_palette_save, &QAbstractButton::clicked, [this](){
|
||||
if ( !p->read_only && p->hasSelectedPalette() && p->swatch->palette().dirty() )
|
||||
if ( p->model->updatePalette( p->palette_list->currentIndex(), p->swatch->palette() ) )
|
||||
{
|
||||
p->swatch->palette().setDirty(false);
|
||||
}
|
||||
/// \todo else ask for a file name (?)
|
||||
});
|
||||
connect(p->button_palette_revert, &QAbstractButton::clicked, [this](){
|
||||
if ( p->hasSelectedPalette() )
|
||||
{
|
||||
p->swatch->setPalette(p->selectedPalette());
|
||||
}
|
||||
});
|
||||
|
||||
// Buttons creating new palettes
|
||||
connect(p->button_palette_duplicate, &QAbstractButton::clicked, [this](){
|
||||
if ( p->hasSelectedPalette() )
|
||||
{
|
||||
ColorPalette new_palette = p->selectedPalette();
|
||||
new_palette.setFileName(QString());
|
||||
bool ok = false;
|
||||
QString name = QInputDialog::getText(this, tr("New Palette"),
|
||||
tr("Name"), QLineEdit::Normal, new_palette.name(), &ok);
|
||||
if ( ok )
|
||||
{
|
||||
new_palette.setName(name);
|
||||
p->model->addPalette(new_palette);
|
||||
p->palette_list->setCurrentIndex(p->model->count()-1);
|
||||
}
|
||||
}
|
||||
});
|
||||
/// \todo Show a dialog that asks for the number of columns (?)
|
||||
connect(p->button_palette_new, &QAbstractButton::clicked, [this](){
|
||||
if ( p->hasSelectedPalette() )
|
||||
{
|
||||
bool ok = false;
|
||||
QString name = QInputDialog::getText(this, tr("New Palette"),
|
||||
tr("Name"), QLineEdit::Normal, QString(), &ok);
|
||||
if ( ok )
|
||||
{
|
||||
ColorPalette new_palette(name);
|
||||
p->model->addPalette(new_palette);
|
||||
p->palette_list->setCurrentIndex(p->model->count()-1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
QString image_formats;
|
||||
Q_FOREACH(QByteArray ba, QImageReader::supportedImageFormats())
|
||||
image_formats += " *."+QString(ba);
|
||||
|
||||
connect(p->button_palette_open, &QAbstractButton::clicked, [this, image_formats](){
|
||||
if ( p->model )
|
||||
{
|
||||
QString default_dir;
|
||||
if ( p->hasSelectedPalette() )
|
||||
{
|
||||
const ColorPalette& palette = p->selectedPalette();
|
||||
if ( !palette.fileName().isEmpty() )
|
||||
default_dir = QFileInfo(palette.fileName()).dir().path();
|
||||
}
|
||||
|
||||
QStringList file_formats = QStringList()
|
||||
<< tr("GIMP Palettes (*.gpl)")
|
||||
<< tr("Palette Image (%1)").arg(image_formats)
|
||||
<< tr("All Files (*)");
|
||||
QFileDialog open_dialog(this, tr("Open Palette"), default_dir);
|
||||
open_dialog.setFileMode(QFileDialog::ExistingFile);
|
||||
open_dialog.setAcceptMode(QFileDialog::AcceptOpen);
|
||||
open_dialog.setNameFilters(file_formats);
|
||||
|
||||
if ( !open_dialog.exec() )
|
||||
return;
|
||||
|
||||
int type = file_formats.indexOf(open_dialog.selectedNameFilter());
|
||||
QString file_name = open_dialog.selectedFiles()[0];
|
||||
|
||||
if ( !p->openPalette( file_name, type ) )
|
||||
{
|
||||
QMessageBox::warning(this, tr("Open Palette"),
|
||||
tr("Failed to load the palette file\n%1").arg(file_name));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ColorPaletteWidget::~ColorPaletteWidget() = default;
|
||||
|
||||
ColorPaletteModel* ColorPaletteWidget::model() const
|
||||
{
|
||||
return p->model;
|
||||
}
|
||||
|
||||
const ColorPalette& ColorPaletteWidget::currentPalette() const
|
||||
{
|
||||
return p->swatch->palette();
|
||||
}
|
||||
|
||||
QSize ColorPaletteWidget::colorSize() const
|
||||
{
|
||||
return p->swatch->colorSize();
|
||||
}
|
||||
|
||||
Swatch::ColorSizePolicy ColorPaletteWidget::colorSizePolicy() const
|
||||
{
|
||||
return p->swatch->colorSizePolicy();
|
||||
}
|
||||
|
||||
QPen ColorPaletteWidget::border() const
|
||||
{
|
||||
return p->swatch->border();
|
||||
}
|
||||
|
||||
int ColorPaletteWidget::forcedRows() const
|
||||
{
|
||||
return p->swatch->forcedRows();
|
||||
}
|
||||
int ColorPaletteWidget::forcedColumns() const
|
||||
{
|
||||
return p->swatch->forcedColumns();
|
||||
}
|
||||
|
||||
bool ColorPaletteWidget::readOnly() const
|
||||
{
|
||||
return p->read_only;
|
||||
}
|
||||
|
||||
QColor ColorPaletteWidget::currentColor() const
|
||||
{
|
||||
return p->swatch->selectedColor();
|
||||
}
|
||||
|
||||
void ColorPaletteWidget::setModel(ColorPaletteModel* model)
|
||||
{
|
||||
if ( model == p->model )
|
||||
return;
|
||||
p->model = model;
|
||||
p->swatch->setPalette(ColorPalette());
|
||||
p->palette_list->setModel(model);
|
||||
}
|
||||
|
||||
void ColorPaletteWidget::setColorSize(const QSize& colorSize)
|
||||
{
|
||||
p->swatch->setColorSize(colorSize);
|
||||
}
|
||||
|
||||
void ColorPaletteWidget::setColorSizePolicy(Swatch::ColorSizePolicy colorSizePolicy)
|
||||
{
|
||||
p->swatch->setColorSizePolicy(colorSizePolicy);
|
||||
}
|
||||
|
||||
void ColorPaletteWidget::setBorder(const QPen& border)
|
||||
{
|
||||
p->swatch->setBorder(border);
|
||||
}
|
||||
|
||||
void ColorPaletteWidget::setForcedRows(int forcedRows)
|
||||
{
|
||||
p->swatch->setForcedRows(forcedRows);
|
||||
}
|
||||
|
||||
void ColorPaletteWidget::setForcedColumns(int forcedColumns)
|
||||
{
|
||||
p->swatch->setForcedColumns(forcedColumns);
|
||||
}
|
||||
|
||||
void ColorPaletteWidget::setReadOnly(bool readOnly)
|
||||
{
|
||||
if ( readOnly == p->read_only )
|
||||
return;
|
||||
|
||||
p->swatch->setReadOnly(readOnly);
|
||||
p->group_edit_list->setVisible(!readOnly);
|
||||
p->group_edit_palette->setVisible(!readOnly);
|
||||
Q_EMIT readOnlyChanged(p->read_only = readOnly);
|
||||
}
|
||||
|
||||
bool ColorPaletteWidget::setCurrentColor(const QColor& color)
|
||||
{
|
||||
const auto& palette = p->swatch->palette();
|
||||
for ( int i = 0; i < palette.count(); i++ )
|
||||
{
|
||||
if ( palette.colorAt(i) == color )
|
||||
{
|
||||
p->swatch->setSelected(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
p->swatch->clearSelection();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ColorPaletteWidget::setCurrentColor(const QString& name)
|
||||
{
|
||||
const auto& palette = p->swatch->palette();
|
||||
for ( int i = 0; i < palette.count(); i++ )
|
||||
{
|
||||
if ( palette.nameAt(i) == name )
|
||||
{
|
||||
p->swatch->setSelected(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
p->swatch->clearSelection();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ColorPaletteWidget::setCurrentColor(int index)
|
||||
{
|
||||
const auto& palette = p->swatch->palette();
|
||||
if ( index >= 0 && index < palette.count() )
|
||||
{
|
||||
p->swatch->setSelected(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
p->swatch->clearSelection();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void ColorPaletteWidget::on_palette_list_currentIndexChanged(int index)
|
||||
{
|
||||
if ( !p->model )
|
||||
p->swatch->setPalette(ColorPalette());
|
||||
else
|
||||
p->swatch->setPalette(p->model->palette(index));
|
||||
|
||||
p->swatch->palette().setDirty(false);
|
||||
}
|
||||
|
||||
void ColorPaletteWidget::on_swatch_doubleClicked(int index)
|
||||
{
|
||||
if ( !p->read_only )
|
||||
{
|
||||
ColorDialog dialog(this);
|
||||
dialog.setAlphaEnabled(false);
|
||||
dialog.setColor(p->swatch->palette().colorAt(index));
|
||||
if ( dialog.exec() )
|
||||
p->swatch->palette().setColorAt(index, dialog.color());
|
||||
}
|
||||
}
|
||||
|
||||
int ColorPaletteWidget::currentRow() const
|
||||
{
|
||||
return p->palette_list->currentIndex();
|
||||
}
|
||||
|
||||
void ColorPaletteWidget::setCurrentRow(int row)
|
||||
{
|
||||
p->palette_list->setCurrentIndex(row);
|
||||
}
|
||||
|
||||
void ColorPaletteWidget::clearCurrentColor()
|
||||
{
|
||||
p->swatch->clearSelection();
|
||||
}
|
||||
|
||||
} // namespace color_widgets
|
||||
205
src/external/qt-color-widgets/src/color_palette_widget.ui
vendored
Normal file
205
src/external/qt-color-widgets/src/color_palette_widget.ui
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>color_widgets::ColorPaletteWidget</class>
|
||||
<widget class="QWidget" name="color_widgets::ColorPaletteWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>227</width>
|
||||
<height>186</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QComboBox" name="palette_list">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="group_edit_list" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolButton" name="button_palette_open">
|
||||
<property name="toolTip">
|
||||
<string>Open a new palette from file</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="document-open">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="button_palette_new">
|
||||
<property name="toolTip">
|
||||
<string>Create a new palette</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="document-new">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="button_palette_duplicate">
|
||||
<property name="toolTip">
|
||||
<string>Duplicate the current palette</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="edit-copy">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="color_widgets::Swatch" name="swatch"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="group_edit_palette" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolButton" name="button_palette_delete">
|
||||
<property name="toolTip">
|
||||
<string>Delete the current palette</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="document-close">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="button_palette_revert">
|
||||
<property name="toolTip">
|
||||
<string>Revert changes to the current palette</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="document-revert">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="button_palette_save">
|
||||
<property name="toolTip">
|
||||
<string>Save changes to the current palette</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="document-save">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="button_color_add">
|
||||
<property name="toolTip">
|
||||
<string>Add a color to the palette</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="list-add">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="button_color_remove">
|
||||
<property name="toolTip">
|
||||
<string>Remove the selected color from the palette</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="list-remove">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>color_widgets::Swatch</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>qt-color-widgets/swatch.hpp</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
182
src/external/qt-color-widgets/src/color_preview.cpp
vendored
Normal file
182
src/external/qt-color-widgets/src/color_preview.cpp
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
* \copyright Copyright (C) 2014 Calle Laakkonen
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "qt-color-widgets/color_preview.hpp"
|
||||
|
||||
#include <QStylePainter>
|
||||
#include <QStyleOptionFrame>
|
||||
#include <QMouseEvent>
|
||||
#include <QDrag>
|
||||
#include <QMimeData>
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
class ColorPreview::Private
|
||||
{
|
||||
public:
|
||||
QColor col; ///< color to be viewed
|
||||
QColor comparison; ///< comparison color
|
||||
QBrush back;///< Background brush, visible on a transparent color
|
||||
DisplayMode display_mode; ///< How the color(s) are to be shown
|
||||
|
||||
Private() : col(Qt::red), back(Qt::darkGray, Qt::DiagCrossPattern), display_mode(NoAlpha)
|
||||
{}
|
||||
};
|
||||
|
||||
ColorPreview::ColorPreview(QWidget *parent) :
|
||||
QWidget(parent), p(new Private)
|
||||
{
|
||||
p->back.setTexture(QPixmap(QStringLiteral(":/color_widgets/alphaback.png")));
|
||||
}
|
||||
|
||||
ColorPreview::~ColorPreview()
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
|
||||
void ColorPreview::setBackground(const QBrush &bk)
|
||||
{
|
||||
p->back = bk;
|
||||
update();
|
||||
}
|
||||
|
||||
QBrush ColorPreview::background() const
|
||||
{
|
||||
return p->back;
|
||||
}
|
||||
|
||||
ColorPreview::DisplayMode ColorPreview::displayMode() const
|
||||
{
|
||||
return p->display_mode;
|
||||
}
|
||||
|
||||
void ColorPreview::setDisplayMode(DisplayMode m)
|
||||
{
|
||||
p->display_mode = m;
|
||||
update();
|
||||
}
|
||||
|
||||
QColor ColorPreview::color() const
|
||||
{
|
||||
return p->col;
|
||||
}
|
||||
|
||||
QColor ColorPreview::comparisonColor() const
|
||||
{
|
||||
return p->comparison;
|
||||
}
|
||||
|
||||
QSize ColorPreview::sizeHint() const
|
||||
{
|
||||
return QSize(24,24);
|
||||
}
|
||||
|
||||
void ColorPreview::paint(QPainter &painter, QRect rect) const
|
||||
{
|
||||
QColor c1, c2;
|
||||
switch(p->display_mode) {
|
||||
case DisplayMode::NoAlpha:
|
||||
c1 = c2 = p->col.rgb();
|
||||
break;
|
||||
case DisplayMode::AllAlpha:
|
||||
c1 = c2 = p->col;
|
||||
break;
|
||||
case DisplayMode::SplitAlpha:
|
||||
c1 = p->col.rgb();
|
||||
c2 = p->col;
|
||||
break;
|
||||
case DisplayMode::SplitColor:
|
||||
c1 = p->comparison;
|
||||
c2 = p->col;
|
||||
break;
|
||||
}
|
||||
|
||||
QStyleOptionFrame panel;
|
||||
panel.initFrom(this);
|
||||
panel.lineWidth = 2;
|
||||
panel.midLineWidth = 0;
|
||||
panel.state |= QStyle::State_Sunken;
|
||||
style()->drawPrimitive(QStyle::PE_Frame, &panel, &painter, this);
|
||||
QRect r = style()->subElementRect(QStyle::SE_FrameContents, &panel, this);
|
||||
painter.setClipRect(r);
|
||||
|
||||
if ( c1.alpha() < 255 || c2.alpha() < 255 )
|
||||
painter.fillRect(0, 0, rect.width(), rect.height(), p->back);
|
||||
|
||||
int w = rect.width() / 2;
|
||||
int h = rect.height();
|
||||
painter.fillRect(0, 0, w, h, c1);
|
||||
painter.fillRect(w, 0, w, h, c2);
|
||||
}
|
||||
|
||||
void ColorPreview::setColor(const QColor &c)
|
||||
{
|
||||
p->col = c;
|
||||
update();
|
||||
Q_EMIT colorChanged(c);
|
||||
}
|
||||
|
||||
void ColorPreview::setComparisonColor(const QColor &c)
|
||||
{
|
||||
p->comparison = c;
|
||||
update();
|
||||
}
|
||||
|
||||
void ColorPreview::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QStylePainter painter(this);
|
||||
|
||||
paint(painter, geometry());
|
||||
}
|
||||
|
||||
void ColorPreview::resizeEvent(QResizeEvent *)
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
void ColorPreview::mouseReleaseEvent(QMouseEvent * ev)
|
||||
{
|
||||
if ( QRect(QPoint(0,0),size()).contains(ev->pos()) )
|
||||
Q_EMIT clicked();
|
||||
}
|
||||
|
||||
void ColorPreview::mouseMoveEvent(QMouseEvent *ev)
|
||||
{
|
||||
|
||||
if ( ev->buttons() &Qt::LeftButton && !QRect(QPoint(0,0),size()).contains(ev->pos()) )
|
||||
{
|
||||
QMimeData *data = new QMimeData;
|
||||
|
||||
data->setColorData(p->col);
|
||||
|
||||
QDrag* drag = new QDrag(this);
|
||||
drag->setMimeData(data);
|
||||
|
||||
QPixmap preview(24,24);
|
||||
preview.fill(p->col);
|
||||
drag->setPixmap(preview);
|
||||
|
||||
drag->exec();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace color_widgets
|
||||
158
src/external/qt-color-widgets/src/color_selector.cpp
vendored
Normal file
158
src/external/qt-color-widgets/src/color_selector.cpp
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "qt-color-widgets/color_selector.hpp"
|
||||
#include "qt-color-widgets/color_dialog.hpp"
|
||||
#include <QDropEvent>
|
||||
#include <QDragEnterEvent>
|
||||
#include <QMimeData>
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
class ColorSelector::Private
|
||||
{
|
||||
public:
|
||||
UpdateMode update_mode;
|
||||
ColorDialog *dialog;
|
||||
QColor old_color;
|
||||
|
||||
Private(QWidget *widget) : dialog(new ColorDialog(widget))
|
||||
{
|
||||
dialog->setButtonMode(ColorDialog::OkCancel);
|
||||
}
|
||||
};
|
||||
|
||||
ColorSelector::ColorSelector(QWidget *parent) :
|
||||
ColorPreview(parent), p(new Private(this))
|
||||
{
|
||||
setUpdateMode(Continuous);
|
||||
p->old_color = color();
|
||||
|
||||
connect(this,&ColorPreview::clicked,this,&ColorSelector::showDialog);
|
||||
connect(this,SIGNAL(colorChanged(QColor)),this,SLOT(update_old_color(QColor)));
|
||||
connect(p->dialog,&QDialog::rejected,this,&ColorSelector::reject_dialog);
|
||||
connect(p->dialog,&ColorDialog::colorSelected, this, &ColorSelector::accept_dialog);
|
||||
connect(p->dialog,&ColorDialog::wheelFlagsChanged,
|
||||
this, &ColorSelector::wheelFlagsChanged);
|
||||
|
||||
setAcceptDrops(true);
|
||||
}
|
||||
|
||||
ColorSelector::~ColorSelector()
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
|
||||
ColorSelector::UpdateMode ColorSelector::updateMode() const
|
||||
{
|
||||
return p->update_mode;
|
||||
}
|
||||
|
||||
void ColorSelector::setUpdateMode(UpdateMode m)
|
||||
{
|
||||
p->update_mode = m;
|
||||
}
|
||||
|
||||
Qt::WindowModality ColorSelector::dialogModality() const
|
||||
{
|
||||
return p->dialog->windowModality();
|
||||
}
|
||||
|
||||
void ColorSelector::setDialogModality(Qt::WindowModality m)
|
||||
{
|
||||
p->dialog->setWindowModality(m);
|
||||
}
|
||||
|
||||
ColorWheel::DisplayFlags ColorSelector::wheelFlags() const
|
||||
{
|
||||
return p->dialog->wheelFlags();
|
||||
}
|
||||
|
||||
void ColorSelector::showDialog()
|
||||
{
|
||||
p->old_color = color();
|
||||
p->dialog->setColor(color());
|
||||
connect_dialog();
|
||||
p->dialog->show();
|
||||
}
|
||||
|
||||
void ColorSelector::setWheelFlags(ColorWheel::DisplayFlags flags)
|
||||
{
|
||||
p->dialog->setWheelFlags(flags);
|
||||
}
|
||||
|
||||
void ColorSelector::connect_dialog()
|
||||
{
|
||||
if (p->update_mode == Continuous)
|
||||
connect(p->dialog, SIGNAL(colorChanged(QColor)), this, SLOT(setColor(QColor)), Qt::UniqueConnection);
|
||||
else
|
||||
disconnect_dialog();
|
||||
}
|
||||
|
||||
void ColorSelector::disconnect_dialog()
|
||||
{
|
||||
disconnect(p->dialog, SIGNAL(colorChanged(QColor)), this, SLOT(setColor(QColor)));
|
||||
}
|
||||
|
||||
void ColorSelector::accept_dialog()
|
||||
{
|
||||
setColor(p->dialog->color());
|
||||
p->old_color = color();
|
||||
}
|
||||
|
||||
void ColorSelector::reject_dialog()
|
||||
{
|
||||
setColor(p->old_color);
|
||||
}
|
||||
|
||||
void ColorSelector::update_old_color(const QColor &c)
|
||||
{
|
||||
if (!p->dialog->isVisible())
|
||||
p->old_color = c;
|
||||
}
|
||||
|
||||
void ColorSelector::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
if ( event->mimeData()->hasColor() ||
|
||||
( event->mimeData()->hasText() && QColor(event->mimeData()->text()).isValid() ) )
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
|
||||
|
||||
void ColorSelector::dropEvent(QDropEvent *event)
|
||||
{
|
||||
if ( event->mimeData()->hasColor() )
|
||||
{
|
||||
setColor(event->mimeData()->colorData().value<QColor>());
|
||||
event->accept();
|
||||
}
|
||||
else if ( event->mimeData()->hasText() )
|
||||
{
|
||||
QColor col(event->mimeData()->text());
|
||||
if ( col.isValid() )
|
||||
{
|
||||
setColor(col);
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace color_widgets
|
||||
83
src/external/qt-color-widgets/src/color_utils.cpp
vendored
Normal file
83
src/external/qt-color-widgets/src/color_utils.cpp
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "color_utils.hpp"
|
||||
|
||||
namespace color_widgets {
|
||||
namespace detail {
|
||||
|
||||
QColor color_from_lch(qreal hue, qreal chroma, qreal luma, qreal alpha )
|
||||
{
|
||||
qreal h1 = hue*6;
|
||||
qreal x = chroma*(1-qAbs(std::fmod(h1,2)-1));
|
||||
QColor col;
|
||||
if ( h1 >= 0 && h1 < 1 )
|
||||
col = QColor::fromRgbF(chroma,x,0);
|
||||
else if ( h1 < 2 )
|
||||
col = QColor::fromRgbF(x,chroma,0);
|
||||
else if ( h1 < 3 )
|
||||
col = QColor::fromRgbF(0,chroma,x);
|
||||
else if ( h1 < 4 )
|
||||
col = QColor::fromRgbF(0,x,chroma);
|
||||
else if ( h1 < 5 )
|
||||
col = QColor::fromRgbF(x,0,chroma);
|
||||
else if ( h1 < 6 )
|
||||
col = QColor::fromRgbF(chroma,0,x);
|
||||
|
||||
qreal m = luma - color_lumaF(col);
|
||||
|
||||
return QColor::fromRgbF(
|
||||
qBound(0.0,col.redF()+m,1.0),
|
||||
qBound(0.0,col.greenF()+m,1.0),
|
||||
qBound(0.0,col.blueF()+m,1.0),
|
||||
alpha);
|
||||
}
|
||||
|
||||
QColor color_from_hsl(qreal hue, qreal sat, qreal lig, qreal alpha )
|
||||
{
|
||||
qreal chroma = (1 - qAbs(2*lig-1))*sat;
|
||||
qreal h1 = hue*6;
|
||||
qreal x = chroma*(1-qAbs(std::fmod(h1,2)-1));
|
||||
QColor col;
|
||||
if ( h1 >= 0 && h1 < 1 )
|
||||
col = QColor::fromRgbF(chroma,x,0);
|
||||
else if ( h1 < 2 )
|
||||
col = QColor::fromRgbF(x,chroma,0);
|
||||
else if ( h1 < 3 )
|
||||
col = QColor::fromRgbF(0,chroma,x);
|
||||
else if ( h1 < 4 )
|
||||
col = QColor::fromRgbF(0,x,chroma);
|
||||
else if ( h1 < 5 )
|
||||
col = QColor::fromRgbF(x,0,chroma);
|
||||
else if ( h1 < 6 )
|
||||
col = QColor::fromRgbF(chroma,0,x);
|
||||
|
||||
qreal m = lig-chroma/2;
|
||||
|
||||
return QColor::fromRgbF(
|
||||
qBound(0.0,col.redF()+m,1.0),
|
||||
qBound(0.0,col.greenF()+m,1.0),
|
||||
qBound(0.0,col.blueF()+m,1.0),
|
||||
alpha);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace color_widgets
|
||||
70
src/external/qt-color-widgets/src/color_utils.hpp
vendored
Normal file
70
src/external/qt-color-widgets/src/color_utils.hpp
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include <QColor>
|
||||
#include <qmath.h>
|
||||
|
||||
namespace color_widgets {
|
||||
namespace detail {
|
||||
|
||||
|
||||
inline qreal color_chromaF(const QColor& c)
|
||||
{
|
||||
qreal max = qMax(c.redF(), qMax(c.greenF(), c.blueF()));
|
||||
qreal min = qMin(c.redF(), qMin(c.greenF(), c.blueF()));
|
||||
return max - min;
|
||||
}
|
||||
|
||||
inline qreal color_lumaF(const QColor& c)
|
||||
{
|
||||
return 0.30 * c.redF() + 0.59 * c.greenF() + 0.11 * c.blueF();
|
||||
}
|
||||
QColor color_from_lch(qreal hue, qreal chroma, qreal luma, qreal alpha = 1 );
|
||||
|
||||
inline QColor rainbow_lch(qreal hue)
|
||||
{
|
||||
return color_from_lch(hue,1,1);
|
||||
}
|
||||
|
||||
inline QColor rainbow_hsv(qreal hue)
|
||||
{
|
||||
return QColor::fromHsvF(hue,1,1);
|
||||
}
|
||||
|
||||
inline qreal color_lightnessF(const QColor& c)
|
||||
{
|
||||
return ( qMax(c.redF(),qMax(c.greenF(),c.blueF())) +
|
||||
qMin(c.redF(),qMin(c.greenF(),c.blueF())) ) / 2;
|
||||
}
|
||||
|
||||
inline qreal color_HSL_saturationF(const QColor& col)
|
||||
{
|
||||
qreal c = color_chromaF(col);
|
||||
qreal l = color_lightnessF(col);
|
||||
if ( qFuzzyCompare(l+1,1) || qFuzzyCompare(l+1,2) )
|
||||
return 0;
|
||||
return c / (1-qAbs(2*l-1));
|
||||
}
|
||||
|
||||
QColor color_from_hsl(qreal hue, qreal sat, qreal lig, qreal alpha = 1 );
|
||||
|
||||
} // namespace detail
|
||||
} // namespace color_widgets
|
||||
561
src/external/qt-color-widgets/src/color_wheel.cpp
vendored
Normal file
561
src/external/qt-color-widgets/src/color_wheel.cpp
vendored
Normal file
@@ -0,0 +1,561 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "qt-color-widgets/color_wheel.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QLineF>
|
||||
#include <QDragEnterEvent>
|
||||
#include <QMimeData>
|
||||
#include "color_utils.hpp"
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
enum MouseStatus
|
||||
{
|
||||
Nothing,
|
||||
DragCircle,
|
||||
DragSquare
|
||||
};
|
||||
|
||||
static const ColorWheel::DisplayFlags hard_default_flags = ColorWheel::SHAPE_TRIANGLE|ColorWheel::ANGLE_ROTATING|ColorWheel::COLOR_HSV;
|
||||
static ColorWheel::DisplayFlags default_flags = hard_default_flags;
|
||||
static const double selector_radius = 6;
|
||||
|
||||
class ColorWheel::Private
|
||||
{
|
||||
private:
|
||||
ColorWheel * const w;
|
||||
|
||||
public:
|
||||
qreal hue, sat, val;
|
||||
unsigned int wheel_width;
|
||||
MouseStatus mouse_status;
|
||||
QPixmap hue_ring;
|
||||
QImage inner_selector;
|
||||
DisplayFlags display_flags;
|
||||
QColor (*color_from)(qreal,qreal,qreal,qreal);
|
||||
QColor (*rainbow_from_hue)(qreal);
|
||||
int max_size = 128;
|
||||
|
||||
Private(ColorWheel *widget)
|
||||
: w(widget), hue(0), sat(0), val(0),
|
||||
wheel_width(20), mouse_status(Nothing),
|
||||
display_flags(FLAGS_DEFAULT),
|
||||
color_from(&QColor::fromHsvF), rainbow_from_hue(&detail::rainbow_hsv)
|
||||
{ }
|
||||
|
||||
/// Calculate outer wheel radius from idget center
|
||||
qreal outer_radius() const
|
||||
{
|
||||
return qMin(w->geometry().width(), w->geometry().height())/2;
|
||||
}
|
||||
|
||||
/// Calculate inner wheel radius from idget center
|
||||
qreal inner_radius() const
|
||||
{
|
||||
return outer_radius()-wheel_width;
|
||||
}
|
||||
|
||||
/// Calculate the edge length of the inner square
|
||||
qreal square_size() const
|
||||
{
|
||||
return inner_radius()*qSqrt(2);
|
||||
}
|
||||
|
||||
/// Calculate the height of the inner triangle
|
||||
qreal triangle_height() const
|
||||
{
|
||||
return inner_radius()*3/2;
|
||||
}
|
||||
|
||||
/// Calculate the side of the inner triangle
|
||||
qreal triangle_side() const
|
||||
{
|
||||
return inner_radius()*qSqrt(3);
|
||||
}
|
||||
|
||||
/// return line from center to given point
|
||||
QLineF line_to_point(const QPoint &p) const
|
||||
{
|
||||
return QLineF (w->geometry().width()/2, w->geometry().height()/2, p.x(), p.y());
|
||||
}
|
||||
|
||||
void render_square()
|
||||
{
|
||||
int width = qMin<int>(square_size(), max_size);
|
||||
QSize size(width, width);
|
||||
inner_selector = QImage(size, QImage::Format_RGB32);
|
||||
|
||||
for ( int y = 0; y < width; ++y )
|
||||
{
|
||||
for ( int x = 0; x < width; ++x )
|
||||
{
|
||||
inner_selector.setPixel( x, y,
|
||||
color_from(hue,double(x)/width,double(y)/width,1).rgb());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief renders the selector as a triangle
|
||||
* \note It's the same as a square with the edge with value=0 collapsed to a single point
|
||||
*/
|
||||
void render_triangle()
|
||||
{
|
||||
QSizeF size = selector_size();
|
||||
if ( size.height() > max_size )
|
||||
size *= max_size / size.height();
|
||||
|
||||
qreal ycenter = size.height()/2;
|
||||
inner_selector = QImage(size.toSize(), QImage::Format_RGB32);
|
||||
|
||||
for (int x = 0; x < inner_selector.width(); x++ )
|
||||
{
|
||||
qreal pval = x / size.height();
|
||||
qreal slice_h = size.height() * pval;
|
||||
for (int y = 0; y < inner_selector.height(); y++ )
|
||||
{
|
||||
qreal ymin = ycenter-slice_h/2;
|
||||
qreal psat = qBound(0.0,(y-ymin)/slice_h,1.0);
|
||||
|
||||
inner_selector.setPixel(x,y,color_from(hue,psat,pval,1).rgb());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the inner image that displays the saturation-value selector
|
||||
void render_inner_selector()
|
||||
{
|
||||
if ( display_flags & ColorWheel::SHAPE_TRIANGLE )
|
||||
render_triangle();
|
||||
else
|
||||
render_square();
|
||||
}
|
||||
|
||||
/// Offset of the selector image
|
||||
QPointF selector_image_offset()
|
||||
{
|
||||
if ( display_flags & SHAPE_TRIANGLE )
|
||||
return QPointF(-inner_radius(),-triangle_side()/2);
|
||||
return QPointF(-square_size()/2,-square_size()/2);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Size of the selector when rendered to the screen
|
||||
*/
|
||||
QSizeF selector_size()
|
||||
{
|
||||
if ( display_flags & SHAPE_TRIANGLE )
|
||||
return QSizeF(triangle_height(), triangle_side());
|
||||
return QSizeF(square_size(), square_size());
|
||||
}
|
||||
|
||||
|
||||
/// Rotation of the selector image
|
||||
qreal selector_image_angle()
|
||||
{
|
||||
if ( display_flags & SHAPE_TRIANGLE )
|
||||
{
|
||||
if ( display_flags & ANGLE_ROTATING )
|
||||
return -hue*360-60;
|
||||
return -150;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( display_flags & ANGLE_ROTATING )
|
||||
return -hue*360-45;
|
||||
else
|
||||
return 180;
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the outer ring that displays the hue selector
|
||||
void render_ring()
|
||||
{
|
||||
hue_ring = QPixmap(outer_radius()*2,outer_radius()*2);
|
||||
hue_ring.fill(Qt::transparent);
|
||||
QPainter painter(&hue_ring);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
|
||||
|
||||
const int hue_stops = 24;
|
||||
QConicalGradient gradient_hue(0, 0, 0);
|
||||
if ( gradient_hue.stops().size() < hue_stops )
|
||||
{
|
||||
for ( double a = 0; a < 1.0; a+=1.0/(hue_stops-1) )
|
||||
{
|
||||
gradient_hue.setColorAt(a,rainbow_from_hue(a));
|
||||
}
|
||||
gradient_hue.setColorAt(1,rainbow_from_hue(0));
|
||||
}
|
||||
|
||||
painter.translate(outer_radius(),outer_radius());
|
||||
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.setBrush(QBrush(gradient_hue));
|
||||
painter.drawEllipse(QPointF(0,0),outer_radius(),outer_radius());
|
||||
|
||||
painter.setBrush(Qt::transparent);//palette().background());
|
||||
painter.drawEllipse(QPointF(0,0),inner_radius(),inner_radius());
|
||||
}
|
||||
|
||||
void set_color(const QColor& c)
|
||||
{
|
||||
if ( display_flags & ColorWheel::COLOR_HSV )
|
||||
{
|
||||
hue = qMax(0.0, c.hsvHueF());
|
||||
sat = c.hsvSaturationF();
|
||||
val = c.valueF();
|
||||
}
|
||||
else if ( display_flags & ColorWheel::COLOR_HSL )
|
||||
{
|
||||
hue = qMax(0.0, c.hueF());
|
||||
sat = detail::color_HSL_saturationF(c);
|
||||
val = detail::color_lightnessF(c);
|
||||
}
|
||||
else if ( display_flags & ColorWheel::COLOR_LCH )
|
||||
{
|
||||
hue = qMax(0.0, c.hsvHueF());
|
||||
sat = detail::color_chromaF(c);
|
||||
val = detail::color_lumaF(c);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ColorWheel::ColorWheel(QWidget *parent) :
|
||||
QWidget(parent), p(new Private(this))
|
||||
{
|
||||
setDisplayFlags(FLAGS_DEFAULT);
|
||||
setAcceptDrops(true);
|
||||
}
|
||||
|
||||
ColorWheel::~ColorWheel()
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
|
||||
QColor ColorWheel::color() const
|
||||
{
|
||||
return p->color_from(p->hue, p->sat, p->val, 1);
|
||||
}
|
||||
|
||||
QSize ColorWheel::sizeHint() const
|
||||
{
|
||||
return QSize(p->wheel_width*5, p->wheel_width*5);
|
||||
}
|
||||
|
||||
qreal ColorWheel::hue() const
|
||||
{
|
||||
if ( (p->display_flags & COLOR_LCH) && p->sat > 0.01 )
|
||||
return color().hueF();
|
||||
return p->hue;
|
||||
}
|
||||
|
||||
qreal ColorWheel::saturation() const
|
||||
{
|
||||
return color().hsvSaturationF();
|
||||
}
|
||||
|
||||
qreal ColorWheel::value() const
|
||||
{
|
||||
return color().valueF();
|
||||
}
|
||||
|
||||
unsigned int ColorWheel::wheelWidth() const
|
||||
{
|
||||
return p->wheel_width;
|
||||
}
|
||||
|
||||
void ColorWheel::setWheelWidth(unsigned int w)
|
||||
{
|
||||
p->wheel_width = w;
|
||||
p->render_inner_selector();
|
||||
update();
|
||||
}
|
||||
|
||||
void ColorWheel::paintEvent(QPaintEvent * )
|
||||
{
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.translate(geometry().width()/2,geometry().height()/2);
|
||||
|
||||
// hue wheel
|
||||
if(p->hue_ring.isNull())
|
||||
p->render_ring();
|
||||
|
||||
painter.drawPixmap(-p->outer_radius(), -p->outer_radius(), p->hue_ring);
|
||||
|
||||
// hue selector
|
||||
painter.setPen(QPen(Qt::black,3));
|
||||
painter.setBrush(Qt::NoBrush);
|
||||
QLineF ray(0, 0, p->outer_radius(), 0);
|
||||
ray.setAngle(p->hue*360);
|
||||
QPointF h1 = ray.p2();
|
||||
ray.setLength(p->inner_radius());
|
||||
QPointF h2 = ray.p2();
|
||||
painter.drawLine(h1,h2);
|
||||
|
||||
// lum-sat square
|
||||
if(p->inner_selector.isNull())
|
||||
p->render_inner_selector();
|
||||
|
||||
painter.rotate(p->selector_image_angle());
|
||||
painter.translate(p->selector_image_offset());
|
||||
|
||||
QPointF selector_position;
|
||||
if ( p->display_flags & SHAPE_SQUARE )
|
||||
{
|
||||
qreal side = p->square_size();
|
||||
selector_position = QPointF(p->sat*side, p->val*side);
|
||||
}
|
||||
else if ( p->display_flags & SHAPE_TRIANGLE )
|
||||
{
|
||||
qreal side = p->triangle_side();
|
||||
qreal height = p->triangle_height();
|
||||
qreal slice_h = side * p->val;
|
||||
qreal ymin = side/2-slice_h/2;
|
||||
|
||||
selector_position = QPointF(p->val*height, ymin + p->sat*slice_h);
|
||||
QPolygonF triangle;
|
||||
triangle.append(QPointF(0,side/2));
|
||||
triangle.append(QPointF(height,0));
|
||||
triangle.append(QPointF(height,side));
|
||||
QPainterPath clip;
|
||||
clip.addPolygon(triangle);
|
||||
painter.setClipPath(clip);
|
||||
}
|
||||
|
||||
painter.drawImage(QRectF(QPointF(0, 0), p->selector_size()), p->inner_selector);
|
||||
painter.setClipping(false);
|
||||
|
||||
// lum-sat selector
|
||||
painter.setPen(QPen(p->val > 0.5 ? Qt::black : Qt::white, 3));
|
||||
painter.setBrush(Qt::NoBrush);
|
||||
painter.drawEllipse(selector_position, selector_radius, selector_radius);
|
||||
|
||||
}
|
||||
|
||||
void ColorWheel::mouseMoveEvent(QMouseEvent *ev)
|
||||
{
|
||||
if (p->mouse_status == DragCircle )
|
||||
{
|
||||
p->hue = p->line_to_point(ev->pos()).angle()/360.0;
|
||||
p->render_inner_selector();
|
||||
|
||||
Q_EMIT colorSelected(color());
|
||||
Q_EMIT colorChanged(color());
|
||||
update();
|
||||
}
|
||||
else if(p->mouse_status == DragSquare)
|
||||
{
|
||||
QLineF glob_mouse_ln = p->line_to_point(ev->pos());
|
||||
QLineF center_mouse_ln ( QPointF(0,0),
|
||||
glob_mouse_ln.p2() - glob_mouse_ln.p1() );
|
||||
|
||||
center_mouse_ln.setAngle(center_mouse_ln.angle()+p->selector_image_angle());
|
||||
center_mouse_ln.setP2(center_mouse_ln.p2()-p->selector_image_offset());
|
||||
|
||||
if ( p->display_flags & SHAPE_SQUARE )
|
||||
{
|
||||
p->sat = qBound(0.0, center_mouse_ln.x2()/p->square_size(), 1.0);
|
||||
p->val = qBound(0.0, center_mouse_ln.y2()/p->square_size(), 1.0);
|
||||
}
|
||||
else if ( p->display_flags & SHAPE_TRIANGLE )
|
||||
{
|
||||
QPointF pt = center_mouse_ln.p2();
|
||||
|
||||
qreal side = p->triangle_side();
|
||||
p->val = qBound(0.0, pt.x() / p->triangle_height(), 1.0);
|
||||
qreal slice_h = side * p->val;
|
||||
|
||||
qreal ycenter = side/2;
|
||||
qreal ymin = ycenter-slice_h/2;
|
||||
|
||||
if ( slice_h > 0 )
|
||||
p->sat = qBound(0.0, (pt.y()-ymin)/slice_h, 1.0);
|
||||
}
|
||||
|
||||
Q_EMIT colorSelected(color());
|
||||
Q_EMIT colorChanged(color());
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void ColorWheel::mousePressEvent(QMouseEvent *ev)
|
||||
{
|
||||
if ( ev->buttons() & Qt::LeftButton )
|
||||
{
|
||||
setFocus();
|
||||
QLineF ray = p->line_to_point(ev->pos());
|
||||
if ( ray.length() <= p->inner_radius() )
|
||||
p->mouse_status = DragSquare;
|
||||
else if ( ray.length() <= p->outer_radius() )
|
||||
p->mouse_status = DragCircle;
|
||||
|
||||
// Update the color
|
||||
mouseMoveEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
void ColorWheel::mouseReleaseEvent(QMouseEvent *ev)
|
||||
{
|
||||
mouseMoveEvent(ev);
|
||||
p->mouse_status = Nothing;
|
||||
}
|
||||
|
||||
void ColorWheel::resizeEvent(QResizeEvent *)
|
||||
{
|
||||
p->render_ring();
|
||||
p->render_inner_selector();
|
||||
}
|
||||
|
||||
void ColorWheel::setColor(QColor c)
|
||||
{
|
||||
qreal oldh = p->hue;
|
||||
p->set_color(c);
|
||||
if (!qFuzzyCompare(oldh+1, p->hue+1))
|
||||
p->render_inner_selector();
|
||||
update();
|
||||
Q_EMIT colorChanged(c);
|
||||
}
|
||||
|
||||
void ColorWheel::setHue(qreal h)
|
||||
{
|
||||
p->hue = qBound(0.0, h, 1.0);
|
||||
p->render_inner_selector();
|
||||
update();
|
||||
}
|
||||
|
||||
void ColorWheel::setSaturation(qreal s)
|
||||
{
|
||||
p->sat = qBound(0.0, s, 1.0);
|
||||
update();
|
||||
}
|
||||
|
||||
void ColorWheel::setValue(qreal v)
|
||||
{
|
||||
p->val = qBound(0.0, v, 1.0);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
void ColorWheel::setDisplayFlags(DisplayFlags flags)
|
||||
{
|
||||
if ( ! (flags & COLOR_FLAGS) )
|
||||
flags |= default_flags & COLOR_FLAGS;
|
||||
if ( ! (flags & ANGLE_FLAGS) )
|
||||
flags |= default_flags & ANGLE_FLAGS;
|
||||
if ( ! (flags & SHAPE_FLAGS) )
|
||||
flags |= default_flags & SHAPE_FLAGS;
|
||||
|
||||
if ( (flags & COLOR_FLAGS) != (p->display_flags & COLOR_FLAGS) )
|
||||
{
|
||||
QColor old_col = color();
|
||||
if ( flags & ColorWheel::COLOR_HSL )
|
||||
{
|
||||
p->hue = old_col.hueF();
|
||||
p->sat = detail::color_HSL_saturationF(old_col);
|
||||
p->val = detail::color_lightnessF(old_col);
|
||||
p->color_from = &detail::color_from_hsl;
|
||||
p->rainbow_from_hue = &detail::rainbow_hsv;
|
||||
}
|
||||
else if ( flags & ColorWheel::COLOR_LCH )
|
||||
{
|
||||
p->hue = old_col.hueF();
|
||||
p->sat = detail::color_chromaF(old_col);
|
||||
p->val = detail::color_lumaF(old_col);
|
||||
p->color_from = &detail::color_from_lch;
|
||||
p->rainbow_from_hue = &detail::rainbow_lch;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->hue = old_col.hsvHueF();
|
||||
p->sat = old_col.hsvSaturationF();
|
||||
p->val = old_col.valueF();
|
||||
p->color_from = &QColor::fromHsvF;
|
||||
p->rainbow_from_hue = &detail::rainbow_hsv;
|
||||
}
|
||||
p->render_ring();
|
||||
}
|
||||
|
||||
p->display_flags = flags;
|
||||
p->render_inner_selector();
|
||||
update();
|
||||
Q_EMIT displayFlagsChanged(flags);
|
||||
}
|
||||
|
||||
ColorWheel::DisplayFlags ColorWheel::displayFlags(DisplayFlags mask) const
|
||||
{
|
||||
return p->display_flags & mask;
|
||||
}
|
||||
|
||||
void ColorWheel::setDefaultDisplayFlags(DisplayFlags flags)
|
||||
{
|
||||
if ( !(flags & COLOR_FLAGS) )
|
||||
flags |= hard_default_flags & COLOR_FLAGS;
|
||||
if ( !(flags & ANGLE_FLAGS) )
|
||||
flags |= hard_default_flags & ANGLE_FLAGS;
|
||||
if ( !(flags & SHAPE_FLAGS) )
|
||||
flags |= hard_default_flags & SHAPE_FLAGS;
|
||||
default_flags = flags;
|
||||
}
|
||||
|
||||
ColorWheel::DisplayFlags ColorWheel::defaultDisplayFlags(DisplayFlags mask)
|
||||
{
|
||||
return default_flags & mask;
|
||||
}
|
||||
|
||||
void ColorWheel::setDisplayFlag(DisplayFlags flag, DisplayFlags mask)
|
||||
{
|
||||
setDisplayFlags((p->display_flags&~mask)|flag);
|
||||
}
|
||||
|
||||
void ColorWheel::dragEnterEvent(QDragEnterEvent* event)
|
||||
{
|
||||
if ( event->mimeData()->hasColor() ||
|
||||
( event->mimeData()->hasText() && QColor(event->mimeData()->text()).isValid() ) )
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
|
||||
void ColorWheel::dropEvent(QDropEvent* event)
|
||||
{
|
||||
if ( event->mimeData()->hasColor() )
|
||||
{
|
||||
setColor(event->mimeData()->colorData().value<QColor>());
|
||||
event->accept();
|
||||
}
|
||||
else if ( event->mimeData()->hasText() )
|
||||
{
|
||||
QColor col(event->mimeData()->text());
|
||||
if ( col.isValid() )
|
||||
{
|
||||
setColor(col);
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace color_widgets
|
||||
5
src/external/qt-color-widgets/src/color_widgets.qrc
vendored
Normal file
5
src/external/qt-color-widgets/src/color_widgets.qrc
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/color_widgets">
|
||||
<file>alphaback.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
195
src/external/qt-color-widgets/src/gradient_slider.cpp
vendored
Normal file
195
src/external/qt-color-widgets/src/gradient_slider.cpp
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
* \copyright Copyright (C) 2014 Calle Laakkonen
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "qt-color-widgets/gradient_slider.hpp"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionSlider>
|
||||
#include <QLinearGradient>
|
||||
|
||||
static void loadResource()
|
||||
{
|
||||
static bool loaded = false;
|
||||
if ( !loaded )
|
||||
{
|
||||
Q_INIT_RESOURCE(color_widgets);
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
class GradientSlider::Private
|
||||
{
|
||||
public:
|
||||
QLinearGradient gradient;
|
||||
QBrush back;
|
||||
|
||||
Private() :
|
||||
back(Qt::darkGray, Qt::DiagCrossPattern)
|
||||
{
|
||||
loadResource();
|
||||
back.setTexture(QPixmap(QStringLiteral(":/color_widgets/alphaback.png")));
|
||||
gradient.setCoordinateMode(QGradient::StretchToDeviceMode);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
GradientSlider::GradientSlider(QWidget *parent) :
|
||||
QSlider(Qt::Horizontal, parent), p(new Private)
|
||||
{}
|
||||
|
||||
GradientSlider::GradientSlider(Qt::Orientation orientation, QWidget *parent) :
|
||||
QSlider(orientation, parent), p(new Private)
|
||||
{}
|
||||
|
||||
GradientSlider::~GradientSlider()
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
|
||||
QBrush GradientSlider::background() const
|
||||
{
|
||||
return p->back;
|
||||
}
|
||||
|
||||
void GradientSlider::setBackground(const QBrush &bg)
|
||||
{
|
||||
p->back = bg;
|
||||
update();
|
||||
}
|
||||
|
||||
QGradientStops GradientSlider::colors() const
|
||||
{
|
||||
return p->gradient.stops();
|
||||
}
|
||||
|
||||
void GradientSlider::setColors(const QGradientStops &colors)
|
||||
{
|
||||
p->gradient.setStops(colors);
|
||||
update();
|
||||
}
|
||||
|
||||
QLinearGradient GradientSlider::gradient() const
|
||||
{
|
||||
return p->gradient;
|
||||
}
|
||||
|
||||
void GradientSlider::setGradient(const QLinearGradient &gradient)
|
||||
{
|
||||
p->gradient = gradient;
|
||||
update();
|
||||
}
|
||||
|
||||
void GradientSlider::setColors(const QVector<QColor> &colors)
|
||||
{
|
||||
QGradientStops stops;
|
||||
stops.reserve(colors.size());
|
||||
|
||||
double c = colors.size() - 1;
|
||||
if(c==0) {
|
||||
stops.append(QGradientStop(0, colors.at(0)));
|
||||
|
||||
} else {
|
||||
for(int i=0;i<colors.size();++i) {
|
||||
stops.append(QGradientStop(i/c, colors.at(i)));
|
||||
}
|
||||
}
|
||||
setColors(stops);
|
||||
}
|
||||
|
||||
void GradientSlider::setFirstColor(const QColor &c)
|
||||
{
|
||||
QGradientStops stops = p->gradient.stops();
|
||||
if(stops.isEmpty())
|
||||
stops.push_back(QGradientStop(0.0, c));
|
||||
else
|
||||
stops.front().second = c;
|
||||
p->gradient.setStops(stops);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void GradientSlider::setLastColor(const QColor &c)
|
||||
{
|
||||
QGradientStops stops = p->gradient.stops();
|
||||
if(stops.size()<2)
|
||||
stops.push_back(QGradientStop(1.0, c));
|
||||
else
|
||||
stops.back().second = c;
|
||||
p->gradient.setStops(stops);
|
||||
update();
|
||||
}
|
||||
|
||||
QColor GradientSlider::firstColor() const
|
||||
{
|
||||
QGradientStops s = colors();
|
||||
return s.empty() ? QColor() : s.front().second;
|
||||
}
|
||||
|
||||
QColor GradientSlider::lastColor() const
|
||||
{
|
||||
QGradientStops s = colors();
|
||||
return s.empty() ? QColor() : s.back().second;
|
||||
}
|
||||
|
||||
void GradientSlider::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter painter(this);
|
||||
|
||||
QStyleOptionFrame panel;
|
||||
panel.initFrom(this);
|
||||
panel.lineWidth = 1;
|
||||
panel.midLineWidth = 0;
|
||||
panel.state |= QStyle::State_Sunken;
|
||||
style()->drawPrimitive(QStyle::PE_Frame, &panel, &painter, this);
|
||||
QRect r = style()->subElementRect(QStyle::SE_FrameContents, &panel, this);
|
||||
painter.setClipRect(r);
|
||||
|
||||
if(orientation() == Qt::Horizontal)
|
||||
p->gradient.setFinalStop(1, 0);
|
||||
else
|
||||
p->gradient.setFinalStop(0, 1);
|
||||
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.setBrush(p->back);
|
||||
painter.drawRect(1,1,geometry().width()-2,geometry().height()-2);
|
||||
painter.setBrush(p->gradient);
|
||||
painter.drawRect(1,1,geometry().width()-2,geometry().height()-2);
|
||||
|
||||
painter.setClipping(false);
|
||||
QStyleOptionSlider opt_slider;
|
||||
initStyleOption(&opt_slider);
|
||||
opt_slider.state &= ~QStyle::State_HasFocus;
|
||||
opt_slider.subControls = QStyle::SC_SliderHandle;
|
||||
if (isSliderDown())
|
||||
{
|
||||
opt_slider.state |= QStyle::State_Sunken;
|
||||
opt_slider.activeSubControls = QStyle::SC_SliderHandle;
|
||||
}
|
||||
opt_slider.rect = style()->subControlRect(QStyle::CC_Slider,&opt_slider,
|
||||
QStyle::SC_SliderHandle,this);
|
||||
|
||||
style()->drawComplexControl(QStyle::CC_Slider, &opt_slider, &painter, this);
|
||||
}
|
||||
|
||||
} // namespace color_widgets
|
||||
140
src/external/qt-color-widgets/src/hue_slider.cpp
vendored
Normal file
140
src/external/qt-color-widgets/src/hue_slider.cpp
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2014 Calle Laakkonen
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "qt-color-widgets/hue_slider.hpp"
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
class HueSlider::Private
|
||||
{
|
||||
private:
|
||||
HueSlider *w;
|
||||
|
||||
public:
|
||||
qreal saturation = 1;
|
||||
qreal value = 1;
|
||||
qreal alpha = 1;
|
||||
|
||||
Private(HueSlider *widget)
|
||||
: w(widget)
|
||||
{
|
||||
w->setRange(0, 359);
|
||||
connect(w, &QSlider::valueChanged, [this]{
|
||||
Q_EMIT w->colorHueChanged(percent());
|
||||
});
|
||||
updateGradient();
|
||||
}
|
||||
|
||||
void updateGradient()
|
||||
{
|
||||
static const double n_colors = 6;
|
||||
QGradientStops colors;
|
||||
colors.reserve(n_colors+1);
|
||||
for ( int i = 0; i <= n_colors; ++i )
|
||||
colors.append(QGradientStop(i/n_colors, QColor::fromHsvF(i/n_colors, saturation, value)));
|
||||
w->setColors(colors);
|
||||
}
|
||||
|
||||
qreal percent()
|
||||
{
|
||||
return qreal(w->value() - w->minimum()) / (w->maximum() - w->minimum());
|
||||
}
|
||||
};
|
||||
|
||||
HueSlider::HueSlider(QWidget *parent) :
|
||||
GradientSlider(parent), p(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
HueSlider::HueSlider(Qt::Orientation orientation, QWidget *parent) :
|
||||
GradientSlider(orientation, parent), p(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
HueSlider::~HueSlider()
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
|
||||
qreal HueSlider::colorSaturation() const
|
||||
{
|
||||
return p->saturation;
|
||||
}
|
||||
|
||||
void HueSlider::setColorSaturation(qreal s)
|
||||
{
|
||||
p->saturation = qBound(0.0, s, 1.0);
|
||||
p->updateGradient();
|
||||
}
|
||||
|
||||
qreal HueSlider::colorValue() const
|
||||
{
|
||||
return p->value;
|
||||
}
|
||||
|
||||
void HueSlider::setColorValue(qreal v)
|
||||
{
|
||||
p->value = qBound(0.0, v, 1.0);
|
||||
p->updateGradient();
|
||||
}
|
||||
|
||||
qreal HueSlider::colorAlpha() const
|
||||
{
|
||||
return p->alpha;
|
||||
}
|
||||
|
||||
void HueSlider::setColorAlpha(qreal alpha)
|
||||
{
|
||||
p->alpha = alpha;
|
||||
p->updateGradient();
|
||||
}
|
||||
|
||||
QColor HueSlider::color() const
|
||||
{
|
||||
return QColor::fromHsvF(p->percent(), p->saturation, p->value, p->alpha);
|
||||
}
|
||||
|
||||
void HueSlider::setColor(const QColor& color)
|
||||
{
|
||||
p->saturation = color.saturationF();
|
||||
p->value = color.valueF();
|
||||
p->updateGradient();
|
||||
setColorHue(color.hueF());
|
||||
}
|
||||
|
||||
void HueSlider::setFullColor(const QColor& color)
|
||||
{
|
||||
p->alpha = color.alphaF();
|
||||
setColor(color);
|
||||
}
|
||||
|
||||
qreal HueSlider::colorHue() const
|
||||
{
|
||||
return p->percent();
|
||||
}
|
||||
|
||||
void HueSlider::setColorHue(qreal colorHue)
|
||||
{
|
||||
setValue(minimum()+colorHue*(maximum()-minimum()));
|
||||
}
|
||||
|
||||
} // namespace color_widgets
|
||||
786
src/external/qt-color-widgets/src/swatch.cpp
vendored
Normal file
786
src/external/qt-color-widgets/src/swatch.cpp
vendored
Normal file
@@ -0,0 +1,786 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Mattia Basaglia
|
||||
*
|
||||
* \copyright Copyright (C) 2013-2017 Mattia Basaglia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "qt-color-widgets/swatch.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <QPainter>
|
||||
#include <QMouseEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QApplication>
|
||||
#include <QDrag>
|
||||
#include <QMimeData>
|
||||
#include <QDropEvent>
|
||||
#include <QDragEnterEvent>
|
||||
#include <QStyleOption>
|
||||
#include <QToolTip>
|
||||
|
||||
namespace color_widgets {
|
||||
|
||||
class Swatch::Private
|
||||
{
|
||||
public:
|
||||
ColorPalette palette; ///< Palette with colors and related metadata
|
||||
int selected; ///< Current selection index (-1 for no selection)
|
||||
QSize color_size; ///< Preferred size for the color squares
|
||||
ColorSizePolicy size_policy;
|
||||
QPen border;
|
||||
int forced_rows;
|
||||
int forced_columns;
|
||||
bool readonly; ///< Whether the palette can be modified via user interaction
|
||||
|
||||
QPoint drag_pos; ///< Point used to keep track of dragging
|
||||
int drag_index; ///< Index used by drags
|
||||
int drop_index; ///< Index for a requested drop
|
||||
QColor drop_color; ///< Dropped color
|
||||
bool drop_overwrite; ///< Whether the drop will overwrite an existing color
|
||||
|
||||
Swatch* owner;
|
||||
|
||||
Private(Swatch* owner)
|
||||
: selected(-1),
|
||||
color_size(16,16),
|
||||
size_policy(Hint),
|
||||
border(Qt::black, 1),
|
||||
forced_rows(0),
|
||||
forced_columns(0),
|
||||
readonly(false),
|
||||
drag_index(-1),
|
||||
drop_index(-1),
|
||||
drop_overwrite(false),
|
||||
owner(owner)
|
||||
{}
|
||||
|
||||
/**
|
||||
* \brief Number of rows/columns in the palette
|
||||
*/
|
||||
QSize rowcols()
|
||||
{
|
||||
int count = palette.count();
|
||||
if ( count == 0 )
|
||||
return QSize();
|
||||
|
||||
if ( forced_rows )
|
||||
return QSize(std::ceil( float(count) / forced_rows ), forced_rows);
|
||||
|
||||
int columns = palette.columns();
|
||||
|
||||
if ( forced_columns )
|
||||
columns = forced_columns;
|
||||
else if ( columns == 0 )
|
||||
columns = qMin(palette.count(), owner->width() / color_size.width());
|
||||
|
||||
int rows = std::ceil( float(count) / columns );
|
||||
|
||||
return QSize(columns, rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets the drop properties
|
||||
*/
|
||||
void dropEvent(QDropEvent* event)
|
||||
{
|
||||
// Find the output location
|
||||
drop_index = owner->indexAt(event->pos());
|
||||
if ( drop_index == -1 )
|
||||
drop_index = palette.count();
|
||||
|
||||
// Gather up the color
|
||||
if ( event->mimeData()->hasColor() )
|
||||
{
|
||||
drop_color = event->mimeData()->colorData().value<QColor>();
|
||||
drop_color.setAlpha(255);
|
||||
}
|
||||
else if ( event->mimeData()->hasText() )
|
||||
{
|
||||
drop_color = QColor(event->mimeData()->text());
|
||||
}
|
||||
|
||||
drop_overwrite = false;
|
||||
QRectF drop_rect = indexRect(drop_index);
|
||||
if ( drop_index < palette.count() && drop_rect.isValid() )
|
||||
{
|
||||
// 1 column => vertical style
|
||||
if ( palette.columns() == 1 || forced_columns == 1 )
|
||||
{
|
||||
// Dragged to the last quarter of the size of the square, add after
|
||||
if ( event->posF().y() >= drop_rect.top() + drop_rect.height() * 3.0 / 4 )
|
||||
drop_index++;
|
||||
// Dragged to the middle of the square, overwrite existing color
|
||||
else if ( event->posF().x() > drop_rect.top() + drop_rect.height() / 4 &&
|
||||
( event->dropAction() != Qt::MoveAction || event->source() != owner ) )
|
||||
drop_overwrite = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Dragged to the last quarter of the size of the square, add after
|
||||
if ( event->posF().x() >= drop_rect.left() + drop_rect.width() * 3.0 / 4 )
|
||||
drop_index++;
|
||||
// Dragged to the middle of the square, overwrite existing color
|
||||
else if ( event->posF().x() > drop_rect.left() + drop_rect.width() / 4 &&
|
||||
( event->dropAction() != Qt::MoveAction || event->source() != owner ) )
|
||||
drop_overwrite = true;
|
||||
}
|
||||
}
|
||||
|
||||
owner->update();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Clears drop properties
|
||||
*/
|
||||
void clearDrop()
|
||||
{
|
||||
drop_index = -1;
|
||||
drop_color = QColor();
|
||||
drop_overwrite = false;
|
||||
|
||||
owner->update();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Actual size of a color square
|
||||
*/
|
||||
QSizeF actualColorSize()
|
||||
{
|
||||
QSize rowcols = this->rowcols();
|
||||
if ( !rowcols.isValid() )
|
||||
return QSizeF();
|
||||
return actualColorSize(rowcols);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Actual size of a color square
|
||||
* \pre rowcols.isValid() and obtained via rowcols()
|
||||
*/
|
||||
QSizeF actualColorSize(const QSize& rowcols)
|
||||
{
|
||||
return QSizeF (float(owner->width()) / rowcols.width(),
|
||||
float(owner->height()) / rowcols.height());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Rectangle corresponding to the color at the given index
|
||||
* \pre rowcols.isValid() and obtained via rowcols()
|
||||
* \pre color_size obtained via rowlcols(rowcols)
|
||||
*/
|
||||
QRectF indexRect(int index, const QSize& rowcols, const QSizeF& color_size)
|
||||
{
|
||||
if ( index == -1 )
|
||||
return QRectF();
|
||||
|
||||
return QRectF(
|
||||
index % rowcols.width() * color_size.width(),
|
||||
index / rowcols.width() * color_size.height(),
|
||||
color_size.width(),
|
||||
color_size.height()
|
||||
);
|
||||
}
|
||||
/**
|
||||
* \brief Rectangle corresponding to the color at the given index
|
||||
*/
|
||||
QRectF indexRect(int index)
|
||||
{
|
||||
QSize rc = rowcols();
|
||||
if ( index == -1 || !rc.isValid() )
|
||||
return QRectF();
|
||||
return indexRect(index, rc, actualColorSize(rc));
|
||||
}
|
||||
};
|
||||
|
||||
Swatch::Swatch(QWidget* parent)
|
||||
: QWidget(parent), p(new Private(this))
|
||||
{
|
||||
connect(&p->palette, &ColorPalette::colorsChanged, this, &Swatch::paletteModified);
|
||||
connect(&p->palette, &ColorPalette::columnsChanged, this, (void(QWidget::*)())&QWidget::update);
|
||||
connect(&p->palette, &ColorPalette::colorsUpdated, this, (void(QWidget::*)())&QWidget::update);
|
||||
connect(&p->palette, &ColorPalette::colorChanged, [this](int index){
|
||||
if ( index == p->selected )
|
||||
Q_EMIT colorSelected( p->palette.colorAt(index) );
|
||||
});
|
||||
connect(&p->palette, &ColorPalette::colorRemoved, [this](int index){
|
||||
if ( index == p->selected )
|
||||
clearSelection();
|
||||
});
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
setAcceptDrops(true);
|
||||
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
||||
setAttribute(Qt::WA_Hover, true);
|
||||
}
|
||||
|
||||
Swatch::~Swatch()
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
|
||||
QSize Swatch::sizeHint() const
|
||||
{
|
||||
QSize rowcols = p->rowcols();
|
||||
|
||||
if ( !p->color_size.isValid() || !rowcols.isValid() )
|
||||
return QSize();
|
||||
|
||||
return QSize(
|
||||
p->color_size.width() * rowcols.width(),
|
||||
p->color_size.height() * rowcols.height()
|
||||
);
|
||||
}
|
||||
|
||||
QSize Swatch::minimumSizeHint() const
|
||||
{
|
||||
if ( p->size_policy != Hint )
|
||||
return sizeHint();
|
||||
return QSize();
|
||||
}
|
||||
|
||||
const ColorPalette& Swatch::palette() const
|
||||
{
|
||||
return p->palette;
|
||||
}
|
||||
|
||||
ColorPalette& Swatch::palette()
|
||||
{
|
||||
return p->palette;
|
||||
}
|
||||
|
||||
int Swatch::selected() const
|
||||
{
|
||||
return p->selected;
|
||||
}
|
||||
|
||||
QColor Swatch::selectedColor() const
|
||||
{
|
||||
return p->palette.colorAt(p->selected);
|
||||
}
|
||||
|
||||
int Swatch::indexAt(const QPoint& pt)
|
||||
{
|
||||
QSize rowcols = p->rowcols();
|
||||
if ( rowcols.isEmpty() )
|
||||
return -1;
|
||||
|
||||
QSizeF color_size = p->actualColorSize(rowcols);
|
||||
|
||||
QPoint point(
|
||||
qBound<int>(0, pt.x() / color_size.width(), rowcols.width() - 1),
|
||||
qBound<int>(0, pt.y() / color_size.height(), rowcols.height() - 1)
|
||||
);
|
||||
|
||||
int index = point.y() * rowcols.width() + point.x();
|
||||
if ( index >= p->palette.count() )
|
||||
return -1;
|
||||
return index;
|
||||
}
|
||||
|
||||
QColor Swatch::colorAt(const QPoint& pt)
|
||||
{
|
||||
return p->palette.colorAt(indexAt(pt));
|
||||
}
|
||||
|
||||
void Swatch::setPalette(const ColorPalette& palette)
|
||||
{
|
||||
clearSelection();
|
||||
p->palette = palette;
|
||||
update();
|
||||
Q_EMIT paletteChanged(p->palette);
|
||||
}
|
||||
|
||||
void Swatch::setSelected(int selected)
|
||||
{
|
||||
if ( selected < 0 || selected >= p->palette.count() )
|
||||
selected = -1;
|
||||
|
||||
if ( selected != p->selected )
|
||||
{
|
||||
Q_EMIT selectedChanged( p->selected = selected );
|
||||
if ( selected != -1 )
|
||||
Q_EMIT colorSelected( p->palette.colorAt(p->selected) );
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void Swatch::clearSelection()
|
||||
{
|
||||
setSelected(-1);
|
||||
}
|
||||
|
||||
void Swatch::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
QSize rowcols = p->rowcols();
|
||||
if ( rowcols.isEmpty() )
|
||||
return;
|
||||
|
||||
QSizeF color_size = p->actualColorSize(rowcols);
|
||||
QPainter painter(this);
|
||||
|
||||
QStyleOptionFrame panel;
|
||||
panel.initFrom(this);
|
||||
panel.lineWidth = 1;
|
||||
panel.midLineWidth = 0;
|
||||
panel.state |= QStyle::State_Sunken;
|
||||
style()->drawPrimitive(QStyle::PE_Frame, &panel, &painter, this);
|
||||
QRect r = style()->subElementRect(QStyle::SE_FrameContents, &panel, this);
|
||||
painter.setClipRect(r);
|
||||
|
||||
int count = p->palette.count();
|
||||
painter.setPen(p->border);
|
||||
for ( int y = 0, i = 0; i < count; y++ )
|
||||
{
|
||||
for ( int x = 0; x < rowcols.width() && i < count; x++, i++ )
|
||||
{
|
||||
painter.setBrush(p->palette.colorAt(i));
|
||||
painter.drawRect(p->indexRect(i, rowcols, color_size));
|
||||
}
|
||||
}
|
||||
|
||||
painter.setClipping(false);
|
||||
|
||||
if ( p->drop_index != -1 )
|
||||
{
|
||||
QRectF drop_area = p->indexRect(p->drop_index, rowcols, color_size);
|
||||
if ( p->drop_overwrite )
|
||||
{
|
||||
painter.setBrush(p->drop_color);
|
||||
painter.setPen(QPen(Qt::gray));
|
||||
painter.drawRect(drop_area);
|
||||
}
|
||||
else if ( rowcols.width() == 1 )
|
||||
{
|
||||
// 1 column => vertical style
|
||||
painter.setPen(QPen(p->drop_color, 2));
|
||||
painter.setBrush(Qt::transparent);
|
||||
painter.drawLine(drop_area.topLeft(), drop_area.topRight());
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.setPen(QPen(p->drop_color, 2));
|
||||
painter.setBrush(Qt::transparent);
|
||||
painter.drawLine(drop_area.topLeft(), drop_area.bottomLeft());
|
||||
// Draw also on the previous line when the first item of a line is selected
|
||||
if ( p->drop_index % rowcols.width() == 0 && p->drop_index != 0 )
|
||||
{
|
||||
drop_area = p->indexRect(p->drop_index-1, rowcols, color_size);
|
||||
drop_area.translate(color_size.width(), 0);
|
||||
painter.drawLine(drop_area.topLeft(), drop_area.bottomLeft());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( p->selected != -1 )
|
||||
{
|
||||
QRectF rect = p->indexRect(p->selected, rowcols, color_size);
|
||||
painter.setBrush(Qt::transparent);
|
||||
painter.setPen(QPen(Qt::darkGray, 2));
|
||||
painter.drawRect(rect);
|
||||
painter.setPen(QPen(Qt::gray, 2, Qt::DotLine));
|
||||
painter.drawRect(rect);
|
||||
}
|
||||
}
|
||||
|
||||
void Swatch::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
if ( p->palette.count() == 0 )
|
||||
QWidget::keyPressEvent(event);
|
||||
|
||||
int selected = p->selected;
|
||||
int count = p->palette.count();
|
||||
QSize rowcols = p->rowcols();
|
||||
int columns = rowcols.width();
|
||||
int rows = rowcols.height();
|
||||
switch ( event->key() )
|
||||
{
|
||||
default:
|
||||
QWidget::keyPressEvent(event);
|
||||
return;
|
||||
|
||||
case Qt::Key_Left:
|
||||
if ( selected == -1 )
|
||||
selected = count - 1;
|
||||
else if ( selected > 0 )
|
||||
selected--;
|
||||
break;
|
||||
|
||||
case Qt::Key_Right:
|
||||
if ( selected == -1 )
|
||||
selected = 0;
|
||||
else if ( selected < count - 1 )
|
||||
selected++;
|
||||
break;
|
||||
|
||||
case Qt::Key_Up:
|
||||
if ( selected == -1 )
|
||||
selected = count - 1;
|
||||
else if ( selected >= columns )
|
||||
selected -= columns;
|
||||
break;
|
||||
|
||||
case Qt::Key_Down:
|
||||
if ( selected == -1 )
|
||||
selected = 0;
|
||||
else if ( selected < count - columns )
|
||||
selected += columns;
|
||||
break;
|
||||
|
||||
case Qt::Key_Home:
|
||||
if ( event->modifiers() & Qt::ControlModifier )
|
||||
selected = 0;
|
||||
else
|
||||
selected -= selected % columns;
|
||||
break;
|
||||
|
||||
case Qt::Key_End:
|
||||
if ( event->modifiers() & Qt::ControlModifier )
|
||||
selected = count - 1;
|
||||
else
|
||||
selected += columns - (selected % columns) - 1;
|
||||
break;
|
||||
|
||||
case Qt::Key_Delete:
|
||||
removeSelected();
|
||||
return;
|
||||
|
||||
case Qt::Key_Backspace:
|
||||
if (selected != -1 && !p->readonly )
|
||||
{
|
||||
p->palette.eraseColor(selected);
|
||||
if ( p->palette.count() == 0 )
|
||||
selected = -1;
|
||||
else
|
||||
selected = qMax(selected - 1, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_PageUp:
|
||||
if ( selected == -1 )
|
||||
selected = 0;
|
||||
else
|
||||
selected = selected % columns;
|
||||
break;
|
||||
case Qt::Key_PageDown:
|
||||
if ( selected == -1 )
|
||||
{
|
||||
selected = count - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
selected = columns * (rows-1) + selected % columns;
|
||||
if ( selected >= count )
|
||||
selected -= columns;
|
||||
}
|
||||
break;
|
||||
}
|
||||
setSelected(selected);
|
||||
}
|
||||
|
||||
void Swatch::removeSelected()
|
||||
{
|
||||
if (p->selected != -1 && !p->readonly )
|
||||
{
|
||||
int selected = p->selected;
|
||||
p->palette.eraseColor(p->selected);
|
||||
setSelected(qMin(selected, p->palette.count() - 1));
|
||||
}
|
||||
}
|
||||
|
||||
void Swatch::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if ( event->button() == Qt::LeftButton )
|
||||
{
|
||||
setSelected(indexAt(event->pos()));
|
||||
p->drag_pos = event->pos();
|
||||
p->drag_index = indexAt(event->pos());
|
||||
}
|
||||
else if ( event->button() == Qt::RightButton )
|
||||
{
|
||||
int index = indexAt(event->pos());
|
||||
if ( index != -1 )
|
||||
Q_EMIT rightClicked(index);
|
||||
}
|
||||
}
|
||||
|
||||
void Swatch::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if ( p->drag_index != -1 && (event->buttons() & Qt::LeftButton) &&
|
||||
(p->drag_pos - event->pos()).manhattanLength() >= QApplication::startDragDistance() )
|
||||
{
|
||||
QColor color = p->palette.colorAt(p->drag_index);
|
||||
|
||||
QPixmap preview(24,24);
|
||||
preview.fill(color);
|
||||
|
||||
QMimeData *mimedata = new QMimeData;
|
||||
mimedata->setColorData(color);
|
||||
mimedata->setText(p->palette.nameAt(p->drag_index));
|
||||
|
||||
QDrag *drag = new QDrag(this);
|
||||
drag->setMimeData(mimedata);
|
||||
drag->setPixmap(preview);
|
||||
Qt::DropActions actions = Qt::CopyAction;
|
||||
if ( !p->readonly )
|
||||
actions |= Qt::MoveAction;
|
||||
drag->exec(actions);
|
||||
}
|
||||
}
|
||||
|
||||
void Swatch::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
if ( event->button() == Qt::LeftButton )
|
||||
{
|
||||
p->drag_index = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void Swatch::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
{
|
||||
if ( event->button() == Qt::LeftButton )
|
||||
{
|
||||
int index = indexAt(event->pos());
|
||||
if ( index != -1 )
|
||||
Q_EMIT doubleClicked(index);
|
||||
}
|
||||
}
|
||||
|
||||
void Swatch::wheelEvent(QWheelEvent* event)
|
||||
{
|
||||
if ( event->delta() > 0 )
|
||||
p->selected = qMin(p->selected + 1, p->palette.count() - 1);
|
||||
else if ( p->selected == -1 )
|
||||
p->selected = p->palette.count() - 1;
|
||||
else if ( p->selected > 0 )
|
||||
p->selected--;
|
||||
setSelected(p->selected);
|
||||
}
|
||||
|
||||
void Swatch::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
if ( p->readonly )
|
||||
return;
|
||||
|
||||
p->dropEvent(event);
|
||||
|
||||
if ( p->drop_color.isValid() && p->drop_index != -1 )
|
||||
{
|
||||
if ( event->proposedAction() == Qt::MoveAction && event->source() == this )
|
||||
event->setDropAction(Qt::MoveAction);
|
||||
else
|
||||
event->setDropAction(Qt::CopyAction);
|
||||
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
|
||||
void Swatch::dragMoveEvent(QDragMoveEvent* event)
|
||||
{
|
||||
if ( p->readonly )
|
||||
return;
|
||||
p->dropEvent(event);
|
||||
}
|
||||
|
||||
void Swatch::dragLeaveEvent(QDragLeaveEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
p->clearDrop();
|
||||
}
|
||||
|
||||
void Swatch::dropEvent(QDropEvent *event)
|
||||
{
|
||||
if ( p->readonly )
|
||||
return;
|
||||
|
||||
QString name;
|
||||
|
||||
// Gather up the color
|
||||
if ( event->mimeData()->hasColor() && event->mimeData()->hasText() )
|
||||
name = event->mimeData()->text();
|
||||
|
||||
// Not a color, discard
|
||||
if ( !p->drop_color.isValid() || p->drop_index == -1 )
|
||||
return;
|
||||
|
||||
p->dropEvent(event);
|
||||
|
||||
// Move unto self
|
||||
if ( event->dropAction() == Qt::MoveAction && event->source() == this )
|
||||
{
|
||||
// Not moved => noop
|
||||
if ( p->drop_index != p->drag_index && p->drop_index != p->drag_index + 1 )
|
||||
{
|
||||
// Erase the old color
|
||||
p->palette.eraseColor(p->drag_index);
|
||||
if ( p->drop_index > p->drag_index )
|
||||
p->drop_index--;
|
||||
p->selected = p->drop_index;
|
||||
// Insert the dropped color
|
||||
p->palette.insertColor(p->drop_index, p->drop_color, name);
|
||||
}
|
||||
}
|
||||
// Move into a color cell
|
||||
else if ( p->drop_overwrite )
|
||||
{
|
||||
p->palette.setColorAt(p->drop_index, p->drop_color, name);
|
||||
}
|
||||
// Insert the dropped color
|
||||
else
|
||||
{
|
||||
p->palette.insertColor(p->drop_index, p->drop_color, name);
|
||||
}
|
||||
|
||||
// Finalize
|
||||
event->accept();
|
||||
p->drag_index = -1;
|
||||
p->clearDrop();
|
||||
}
|
||||
|
||||
void Swatch::paletteModified()
|
||||
{
|
||||
if ( p->selected >= p->palette.count() )
|
||||
clearSelection();
|
||||
|
||||
if ( p->size_policy == Minimum )
|
||||
setMinimumSize(sizeHint());
|
||||
else if ( p->size_policy == Fixed )
|
||||
setFixedSize(sizeHint());
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
QSize Swatch::colorSize() const
|
||||
{
|
||||
return p->color_size;
|
||||
}
|
||||
|
||||
void Swatch::setColorSize(const QSize& colorSize)
|
||||
{
|
||||
if ( p->color_size != colorSize )
|
||||
Q_EMIT colorSizeChanged(p->color_size = colorSize);
|
||||
}
|
||||
|
||||
Swatch::ColorSizePolicy Swatch::colorSizePolicy() const
|
||||
{
|
||||
return p->size_policy;
|
||||
}
|
||||
|
||||
void Swatch::setColorSizePolicy(ColorSizePolicy colorSizePolicy)
|
||||
{
|
||||
if ( p->size_policy != colorSizePolicy )
|
||||
{
|
||||
setMinimumSize(0,0);
|
||||
setFixedSize(QWIDGETSIZE_MAX,QWIDGETSIZE_MAX);
|
||||
paletteModified();
|
||||
Q_EMIT colorSizePolicyChanged(p->size_policy = colorSizePolicy);
|
||||
}
|
||||
}
|
||||
|
||||
int Swatch::forcedColumns() const
|
||||
{
|
||||
return p->forced_columns;
|
||||
}
|
||||
|
||||
int Swatch::forcedRows() const
|
||||
{
|
||||
return p->forced_rows;
|
||||
}
|
||||
|
||||
void Swatch::setForcedColumns(int forcedColumns)
|
||||
{
|
||||
if ( forcedColumns <= 0 )
|
||||
forcedColumns = 0;
|
||||
|
||||
if ( forcedColumns != p->forced_columns )
|
||||
{
|
||||
Q_EMIT forcedColumnsChanged(p->forced_columns = forcedColumns);
|
||||
Q_EMIT forcedRowsChanged(p->forced_rows = 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Swatch::setForcedRows(int forcedRows)
|
||||
{
|
||||
if ( forcedRows <= 0 )
|
||||
forcedRows = 0;
|
||||
|
||||
if ( forcedRows != p->forced_rows )
|
||||
{
|
||||
Q_EMIT forcedColumnsChanged(p->forced_columns = 0);
|
||||
Q_EMIT forcedRowsChanged(p->forced_rows = forcedRows);
|
||||
}
|
||||
}
|
||||
|
||||
bool Swatch::readOnly() const
|
||||
{
|
||||
return p->readonly;
|
||||
}
|
||||
|
||||
void Swatch::setReadOnly(bool readOnly)
|
||||
{
|
||||
if ( readOnly != p->readonly )
|
||||
{
|
||||
Q_EMIT readOnlyChanged(p->readonly = readOnly);
|
||||
setAcceptDrops(!p->readonly);
|
||||
}
|
||||
}
|
||||
|
||||
bool Swatch::event(QEvent* event)
|
||||
{
|
||||
if(event->type() == QEvent::ToolTip)
|
||||
{
|
||||
QHelpEvent* help_ev = static_cast<QHelpEvent*>(event);
|
||||
int index = indexAt(help_ev->pos());
|
||||
if ( index != -1 )
|
||||
{
|
||||
QColor color = p->palette.colorAt(index);
|
||||
QString name = p->palette.nameAt(index);
|
||||
QString message = color.name();
|
||||
if ( !name.isEmpty() )
|
||||
message = tr("%1 (%2)").arg(name).arg(message);
|
||||
message = "<tt style='background-color:"+color.name()+";color:"+color.name()+";'>MM</tt> "+message.toHtmlEscaped();
|
||||
QToolTip::showText(help_ev->globalPos(), message, this,
|
||||
p->indexRect(index).toRect());
|
||||
event->accept();
|
||||
}
|
||||
else
|
||||
{
|
||||
QToolTip::hideText();
|
||||
event->ignore();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return QWidget::event(event);
|
||||
}
|
||||
|
||||
QPen Swatch::border() const
|
||||
{
|
||||
return p->border;
|
||||
}
|
||||
|
||||
void Swatch::setBorder(const QPen& border)
|
||||
{
|
||||
if ( border != p->border )
|
||||
{
|
||||
p->border = border;
|
||||
Q_EMIT borderChanged(border);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace color_widgets
|
||||
11
src/glsl/cursor_frag.glsl
Normal file
11
src/glsl/cursor_frag.glsl
Normal file
@@ -0,0 +1,11 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
uniform vec4 color;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
out_color = color;
|
||||
}
|
||||
14
src/glsl/cursor_vert.glsl
Normal file
14
src/glsl/cursor_vert.glsl
Normal file
@@ -0,0 +1,14 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
uniform mat4 model_view_projection;
|
||||
uniform vec3 cursor_pos;
|
||||
uniform float radius;
|
||||
|
||||
in vec4 position;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 p = cursor_pos + position.xyz * radius;
|
||||
gl_Position = model_view_projection * vec4(p,1.);
|
||||
}
|
||||
11
src/glsl/horizon_frag.glsl
Normal file
11
src/glsl/horizon_frag.glsl
Normal file
@@ -0,0 +1,11 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
uniform vec3 color;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
out_color = vec4(color, 1.0);
|
||||
}
|
||||
12
src/glsl/horizon_vert.glsl
Normal file
12
src/glsl/horizon_vert.glsl
Normal file
@@ -0,0 +1,12 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
in vec4 position;
|
||||
|
||||
uniform mat4 model_view;
|
||||
uniform mat4 projection;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projection * model_view * position;
|
||||
}
|
||||
44
src/glsl/liquid_frag.glsl
Normal file
44
src/glsl/liquid_frag.glsl
Normal file
@@ -0,0 +1,44 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
uniform sampler2D tex;
|
||||
uniform vec4 ocean_color_light;
|
||||
uniform vec4 ocean_color_dark;
|
||||
uniform vec4 river_color_light;
|
||||
uniform vec4 river_color_dark;
|
||||
|
||||
uniform int type;
|
||||
uniform float animtime;
|
||||
uniform vec2 param;
|
||||
|
||||
in float depth_;
|
||||
in vec2 tex_coord_;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
vec2 rot2(vec2 p, float degree)
|
||||
{
|
||||
float a = radians(degree);
|
||||
return mat2(cos(a), -sin(a), sin(a), cos(a))*p;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
// lava || slime
|
||||
if(type == 2 || type == 3)
|
||||
{
|
||||
out_color = texture(tex, tex_coord_ + vec2(param.x*animtime, param.y*animtime));
|
||||
}
|
||||
else
|
||||
{
|
||||
vec2 uv = rot2(tex_coord_ * param.x, param.y);
|
||||
vec4 texel = texture(tex, uv);
|
||||
vec4 lerp = (type == 1)
|
||||
? mix (ocean_color_light, ocean_color_dark, depth_)
|
||||
: mix (river_color_light, river_color_dark, depth_)
|
||||
;
|
||||
|
||||
//clamp shouldn't be needed
|
||||
out_color = vec4 (clamp(texel + lerp, 0.0, 1.0).rgb, lerp.a);
|
||||
}
|
||||
}
|
||||
30
src/glsl/liquid_vert.glsl
Normal file
30
src/glsl/liquid_vert.glsl
Normal file
@@ -0,0 +1,30 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
in vec4 position;
|
||||
in vec2 tex_coord;
|
||||
in float depth;
|
||||
|
||||
uniform mat4 model_view;
|
||||
uniform mat4 projection;
|
||||
uniform mat4 transform;
|
||||
|
||||
uniform int use_transform = int(0);
|
||||
|
||||
out float depth_;
|
||||
out vec2 tex_coord_;
|
||||
|
||||
void main()
|
||||
{
|
||||
depth_ = depth;
|
||||
tex_coord_ = tex_coord;
|
||||
|
||||
if(use_transform == 1)
|
||||
{
|
||||
gl_Position = projection * model_view * transform * position;
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_Position = projection * model_view * position;
|
||||
}
|
||||
}
|
||||
11
src/glsl/m2_box_frag.glsl
Normal file
11
src/glsl/m2_box_frag.glsl
Normal file
@@ -0,0 +1,11 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
uniform vec4 color;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
out_color = color;
|
||||
}
|
||||
13
src/glsl/m2_box_vert.glsl
Normal file
13
src/glsl/m2_box_vert.glsl
Normal file
@@ -0,0 +1,13 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
in mat4 transform;
|
||||
in vec4 position;
|
||||
|
||||
uniform mat4 model_view;
|
||||
uniform mat4 projection;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projection * model_view * transform * position;
|
||||
}
|
||||
194
src/glsl/m2_frag.glsl
Normal file
194
src/glsl/m2_frag.glsl
Normal file
@@ -0,0 +1,194 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
in vec2 uv1;
|
||||
in vec2 uv2;
|
||||
in float camera_dist;
|
||||
in vec3 norm;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
uniform vec4 mesh_color;
|
||||
|
||||
uniform sampler2D tex1;
|
||||
uniform sampler2D tex2;
|
||||
|
||||
uniform vec4 fog_color;
|
||||
uniform float fog_start;
|
||||
uniform float fog_end;
|
||||
uniform int draw_fog;
|
||||
uniform int fog_mode;
|
||||
uniform int unfogged;
|
||||
uniform int unlit;
|
||||
|
||||
uniform vec3 light_dir;
|
||||
uniform vec3 diffuse_color;
|
||||
uniform vec3 ambient_color;
|
||||
|
||||
uniform float alpha_test;
|
||||
uniform int pixel_shader;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 color = vec4(0.0);
|
||||
|
||||
if(mesh_color.a < alpha_test)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
vec4 texture1 = texture(tex1, uv1);
|
||||
vec4 texture2 = texture(tex2, uv2);
|
||||
|
||||
// code from Deamon87 and https://wowdev.wiki/M2/Rendering#Pixel_Shaders
|
||||
if (pixel_shader == 0) //Combiners_Opaque
|
||||
{
|
||||
color.rgb = texture1.rgb * mesh_color.rgb;
|
||||
color.a = mesh_color.a;
|
||||
}
|
||||
else if (pixel_shader == 1) // Combiners_Decal
|
||||
{
|
||||
color.rgb = mix(mesh_color.rgb, texture1.rgb, mesh_color.a);
|
||||
color.a = mesh_color.a;
|
||||
}
|
||||
else if (pixel_shader == 2) // Combiners_Add
|
||||
{
|
||||
color.rgba = texture1.rgba + mesh_color.rgba;
|
||||
}
|
||||
else if (pixel_shader == 3) // Combiners_Mod2x
|
||||
{
|
||||
color.rgb = texture1.rgb * mesh_color.rgb * vec3(2.0);
|
||||
color.a = texture1.a * mesh_color.a * 2.0;
|
||||
}
|
||||
else if (pixel_shader == 4) // Combiners_Fade
|
||||
{
|
||||
color.rgb = mix(texture1.rgb, mesh_color.rgb, mesh_color.a);
|
||||
color.a = mesh_color.a;
|
||||
}
|
||||
else if (pixel_shader == 5) // Combiners_Mod
|
||||
{
|
||||
color.rgba = texture1.rgba * mesh_color.rgba;
|
||||
}
|
||||
else if (pixel_shader == 6) // Combiners_Opaque_Opaque
|
||||
{
|
||||
color.rgb = texture1.rgb * texture2.rgb * mesh_color.rgb;
|
||||
color.a = mesh_color.a;
|
||||
}
|
||||
else if (pixel_shader == 7) // Combiners_Opaque_Add
|
||||
{
|
||||
color.rgb = texture2.rgb + texture1.rgb * mesh_color.rgb;
|
||||
color.a = mesh_color.a + texture1.a;
|
||||
}
|
||||
else if (pixel_shader == 8) // Combiners_Opaque_Mod2x
|
||||
{
|
||||
color.rgb = texture1.rgb * mesh_color.rgb * texture2.rgb * vec3(2.0);
|
||||
color.a = texture2.a * mesh_color.a * 2.0;
|
||||
}
|
||||
else if (pixel_shader == 9) // Combiners_Opaque_Mod2xNA
|
||||
{
|
||||
color.rgb = texture1.rgb * mesh_color.rgb * texture2.rgb * vec3(2.0);
|
||||
color.a = mesh_color.a;
|
||||
}
|
||||
else if (pixel_shader == 10) // Combiners_Opaque_AddNA
|
||||
{
|
||||
color.rgb = texture2.rgb + texture1.rgb * mesh_color.rgb;
|
||||
color.a = mesh_color.a;
|
||||
}
|
||||
else if (pixel_shader == 11) // Combiners_Opaque_Mod
|
||||
{
|
||||
color.rgb = texture1.rgb * texture2.rgb * mesh_color.rgb;
|
||||
color.a = texture2.a * mesh_color.a;
|
||||
}
|
||||
else if (pixel_shader == 12) // Combiners_Mod_Opaque
|
||||
{
|
||||
color.rgb = texture1.rgb * texture2.rgb * mesh_color.rgb;
|
||||
color.a = texture1.a;
|
||||
}
|
||||
else if (pixel_shader == 13) // Combiners_Mod_Add
|
||||
{
|
||||
color.rgba = texture2.rgba + texture1.rgba * mesh_color.rgba;
|
||||
}
|
||||
else if (pixel_shader == 14) // Combiners_Mod_Mod2x
|
||||
{
|
||||
color.rgba = texture1.rgba * texture2.rgba * mesh_color.rgba * vec4(2.0);
|
||||
}
|
||||
else if (pixel_shader == 15) // Combiners_Mod_Mod2xNA
|
||||
{
|
||||
color.rgb = texture1.rgb * texture2.rgb * mesh_color.rgb * vec3(2.0);
|
||||
color.a = texture1.a * mesh_color.a;
|
||||
}
|
||||
else if (pixel_shader == 16) // Combiners_Mod_AddNA
|
||||
{
|
||||
color.rgb = texture2.rgb + texture1.rgb * mesh_color.rgb;
|
||||
color.a = texture1.a * mesh_color.a;
|
||||
}
|
||||
else if (pixel_shader == 17) // Combiners_Mod_Mod
|
||||
{
|
||||
color.rgba = texture1.rgba * texture2.rgba * mesh_color.rgba;
|
||||
}
|
||||
else if (pixel_shader == 18) // Combiners_Add_Mod
|
||||
{
|
||||
color.rgb = (texture1.rgb + mesh_color.rgb) * texture2.a;
|
||||
color.a = (texture1.a + mesh_color.a) * texture2.a;
|
||||
}
|
||||
else if (pixel_shader == 19) // Combiners_Mod2x_Mod2x
|
||||
{
|
||||
color.rgba = texture1.rgba * texture2.rgba * mesh_color.rgba * vec4(4.0);
|
||||
}
|
||||
else if (pixel_shader == 20) // Combiners_Opaque_Mod2xNA_Alpha
|
||||
{
|
||||
color.rgb = (mesh_color.rgb * texture1.rgb) * mix(texture2.rgb * 2.0, vec3(1.0), texture1.a);
|
||||
color.a = mesh_color.a;
|
||||
}
|
||||
else if (pixel_shader == 21) //Combiners_Opaque_AddAlpha
|
||||
{
|
||||
color.rgb = (mesh_color.rgb * texture1.rgb) + (texture2.rgb * texture2.a);
|
||||
color.a = mesh_color.a;
|
||||
}
|
||||
else if (pixel_shader == 22) // Combiners_Opaque_AddAlpha_Alpha
|
||||
{
|
||||
color.rgb = (mesh_color.rgb * texture1.rgb) + (texture2.rgb * texture2.a * texture1.a);
|
||||
color.a = mesh_color.a;
|
||||
}
|
||||
|
||||
if(color.a < alpha_test)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
if(unlit == 0)
|
||||
{
|
||||
// diffuse + ambient lighting
|
||||
color.rgb *= vec3(clamp (diffuse_color * max(dot(norm, light_dir), 0.0), 0.0, 1.0)) + ambient_color;
|
||||
}
|
||||
|
||||
if(draw_fog == 1 && unfogged == 0 && camera_dist >= fog_end * fog_start)
|
||||
{
|
||||
float start = fog_end * fog_start;
|
||||
float alpha = (camera_dist - start) / (fog_end - start);
|
||||
|
||||
vec3 fog;
|
||||
|
||||
// see https://wowdev.wiki/M2/Rendering#Fog_Modes
|
||||
if(fog_mode == 1)
|
||||
{
|
||||
fog = fog_color.rgb;
|
||||
}
|
||||
else if(fog_mode == 2)
|
||||
{
|
||||
fog = vec3(0.);
|
||||
}
|
||||
else if(fog_mode == 3)
|
||||
{
|
||||
fog = vec3(1.);
|
||||
}
|
||||
else if(fog_mode == 4)
|
||||
{
|
||||
fog = vec3(0.5);
|
||||
}
|
||||
|
||||
color.rgb = mix(color.rgb, fog, alpha);
|
||||
}
|
||||
|
||||
out_color = color;
|
||||
}
|
||||
71
src/glsl/m2_vert.glsl
Normal file
71
src/glsl/m2_vert.glsl
Normal file
@@ -0,0 +1,71 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
in vec4 pos;
|
||||
in vec3 normal;
|
||||
in vec2 texcoord1;
|
||||
in vec2 texcoord2;
|
||||
|
||||
#ifdef instanced
|
||||
in mat4 transform;
|
||||
#else
|
||||
uniform mat4 transform;
|
||||
#endif
|
||||
|
||||
out vec2 uv1;
|
||||
out vec2 uv2;
|
||||
out float camera_dist;
|
||||
out vec3 norm;
|
||||
|
||||
uniform mat4 model_view;
|
||||
uniform mat4 projection;
|
||||
|
||||
uniform int tex_unit_lookup_1;
|
||||
uniform int tex_unit_lookup_2;
|
||||
|
||||
uniform mat4 tex_matrix_1;
|
||||
uniform mat4 tex_matrix_2;
|
||||
|
||||
// code from https://wowdev.wiki/M2/.skin#Environment_mapping
|
||||
vec2 sphere_map(vec3 vert, vec3 norm)
|
||||
{
|
||||
vec3 normPos = -(normalize(vert));
|
||||
vec3 temp = (normPos - (norm * (2.0 * dot(normPos, norm))));
|
||||
temp = vec3(temp.x, temp.y, temp.z + 1.0);
|
||||
|
||||
return ((normalize(temp).xy * 0.5) + vec2(0.5));
|
||||
}
|
||||
|
||||
vec2 get_texture_uv(int tex_unit_lookup, vec3 vert, vec3 norm)
|
||||
{
|
||||
if(tex_unit_lookup == 0)
|
||||
{
|
||||
return sphere_map(vert, norm);
|
||||
}
|
||||
else if(tex_unit_lookup == 1)
|
||||
{
|
||||
return (transpose(tex_matrix_1) * vec4(texcoord1, 0.0, 1.0)).xy;
|
||||
}
|
||||
else if(tex_unit_lookup == 2)
|
||||
{
|
||||
return (transpose(tex_matrix_2) * vec4(texcoord2, 0.0, 1.0)).xy;
|
||||
}
|
||||
else
|
||||
{
|
||||
return vec2(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 vertex = model_view * transform * pos;
|
||||
|
||||
// important to normalize because of the scaling !!
|
||||
norm = normalize(mat3(transform) * normal);
|
||||
|
||||
uv1 = get_texture_uv(tex_unit_lookup_1, vertex.xyz, norm);
|
||||
uv2 = get_texture_uv(tex_unit_lookup_2, vertex.xyz, norm);
|
||||
|
||||
camera_dist = -vertex.z;
|
||||
gl_Position = projection * vertex;
|
||||
}
|
||||
11
src/glsl/mfbo_frag.glsl
Normal file
11
src/glsl/mfbo_frag.glsl
Normal file
@@ -0,0 +1,11 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
uniform vec4 color;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
out_color = color;
|
||||
}
|
||||
11
src/glsl/mfbo_vert.glsl
Normal file
11
src/glsl/mfbo_vert.glsl
Normal file
@@ -0,0 +1,11 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
in vec4 position;
|
||||
|
||||
uniform mat4 model_view_projection;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = model_view_projection * position;
|
||||
}
|
||||
23
src/glsl/particle_frag.glsl
Normal file
23
src/glsl/particle_frag.glsl
Normal file
@@ -0,0 +1,23 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
in vec2 f_uv;
|
||||
in vec4 f_color;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
uniform sampler2D tex;
|
||||
|
||||
uniform float alpha_test;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 t = texture(tex, f_uv);
|
||||
|
||||
if(t.a < alpha_test)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
out_color = vec4(f_color.rgb * t.rgb, t.a);
|
||||
}
|
||||
30
src/glsl/particle_vert.glsl
Normal file
30
src/glsl/particle_vert.glsl
Normal file
@@ -0,0 +1,30 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
in mat4 transform;
|
||||
in vec4 position;
|
||||
in vec3 offset;
|
||||
in vec2 uv;
|
||||
in vec4 color;
|
||||
|
||||
out vec2 f_uv;
|
||||
out vec4 f_color;
|
||||
|
||||
uniform mat4 model_view_projection;
|
||||
uniform int billboard;
|
||||
|
||||
void main()
|
||||
{
|
||||
f_uv = uv;
|
||||
f_color = color;
|
||||
if(billboard == 1)
|
||||
{
|
||||
vec4 pos = transform*position;
|
||||
pos.xyz += offset;
|
||||
gl_Position = model_view_projection * pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_Position = model_view_projection * transform * position;
|
||||
}
|
||||
}
|
||||
15
src/glsl/ribbon_frag.glsl
Normal file
15
src/glsl/ribbon_frag.glsl
Normal file
@@ -0,0 +1,15 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
in vec2 f_uv;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
uniform sampler2D tex;
|
||||
uniform vec4 color;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 t = texture(tex, f_uv);
|
||||
out_color = vec4(color.rgb * t.rgb, color.a);
|
||||
}
|
||||
16
src/glsl/ribbon_vert.glsl
Normal file
16
src/glsl/ribbon_vert.glsl
Normal file
@@ -0,0 +1,16 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
in mat4 transform;
|
||||
in vec4 position;
|
||||
in vec2 uv;
|
||||
|
||||
out vec2 f_uv;
|
||||
|
||||
uniform mat4 model_view_projection;
|
||||
|
||||
void main()
|
||||
{
|
||||
f_uv = uv;
|
||||
gl_Position = model_view_projection * transform * position;
|
||||
}
|
||||
196
src/glsl/terrain_frag.glsl
Normal file
196
src/glsl/terrain_frag.glsl
Normal file
@@ -0,0 +1,196 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
uniform sampler2D shadow_map;
|
||||
uniform sampler2D tex0;
|
||||
uniform sampler2D tex1;
|
||||
uniform sampler2D tex2;
|
||||
uniform sampler2D tex3;
|
||||
uniform vec2 tex_anim_0;
|
||||
uniform vec2 tex_anim_1;
|
||||
uniform vec2 tex_anim_2;
|
||||
uniform vec2 tex_anim_3;
|
||||
uniform sampler2D alphamap;
|
||||
uniform int layer_count;
|
||||
uniform bool has_mccv;
|
||||
uniform bool cant_paint;
|
||||
uniform bool draw_areaid_overlay;
|
||||
uniform vec4 areaid_color;
|
||||
uniform bool draw_impassible_flag;
|
||||
uniform bool draw_terrain_height_contour;
|
||||
uniform bool draw_lines;
|
||||
uniform bool draw_hole_lines;
|
||||
|
||||
uniform bool draw_wireframe;
|
||||
uniform int wireframe_type;
|
||||
uniform float wireframe_radius;
|
||||
uniform float wireframe_width;
|
||||
uniform vec4 wireframe_color;
|
||||
uniform bool rainbow_wireframe;
|
||||
|
||||
uniform vec3 camera;
|
||||
uniform bool draw_fog;
|
||||
uniform vec4 fog_color;
|
||||
uniform float fog_start;
|
||||
uniform float fog_end;
|
||||
|
||||
uniform bool draw_cursor_circle;
|
||||
uniform vec3 cursor_position;
|
||||
uniform float outer_cursor_radius;
|
||||
uniform float inner_cursor_ratio;
|
||||
uniform vec4 cursor_color;
|
||||
|
||||
uniform vec3 light_dir;
|
||||
uniform vec3 diffuse_color;
|
||||
uniform vec3 ambient_color;
|
||||
|
||||
in vec3 vary_position;
|
||||
in vec2 vary_texcoord;
|
||||
in vec3 vary_normal;
|
||||
in vec3 vary_mccv;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
const float TILESIZE = 533.33333;
|
||||
const float CHUNKSIZE = TILESIZE / 16.0;
|
||||
const float HOLESIZE = CHUNKSIZE * 0.25;
|
||||
const float UNITSIZE = HOLESIZE * 0.5;
|
||||
|
||||
vec4 texture_blend()
|
||||
{
|
||||
if(layer_count == 0)
|
||||
return vec4 (1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
vec3 alpha = texture(alphamap, vary_texcoord / 8.0).rgb;
|
||||
float a0 = alpha.r;
|
||||
float a1 = alpha.g;
|
||||
float a2 = alpha.b;
|
||||
|
||||
vec3 t0 = texture(tex0, vary_texcoord + tex_anim_0).rgb;
|
||||
vec3 t1 = texture(tex1, vary_texcoord + tex_anim_1).rgb;
|
||||
vec3 t2 = texture(tex2, vary_texcoord + tex_anim_2).rgb;
|
||||
vec3 t3 = texture(tex3, vary_texcoord + tex_anim_3).rgb;
|
||||
|
||||
return vec4 (t0 * (1.0 - (a0 + a1 + a2)) + t1 * a0 + t2 * a1 + t3 * a2, 1.0);
|
||||
}
|
||||
|
||||
float contour_alpha(float unit_size, float pos, float line_width)
|
||||
{
|
||||
float f = abs(fract((pos + unit_size*0.5) / unit_size) - 0.5);
|
||||
float df = abs(line_width / unit_size);
|
||||
return smoothstep(0.0, df, f);
|
||||
}
|
||||
|
||||
float contour_alpha(float unit_size, vec2 pos, vec2 line_width)
|
||||
{
|
||||
return 1.0 - min( contour_alpha(unit_size, pos.x, line_width.x)
|
||||
, contour_alpha(unit_size, pos.y, line_width.y)
|
||||
);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
float dist_from_camera = distance(camera, vary_position);
|
||||
|
||||
if(draw_fog && dist_from_camera >= fog_end)
|
||||
{
|
||||
out_color = fog_color;
|
||||
return;
|
||||
}
|
||||
vec3 fw = fwidth(vary_position.xyz);
|
||||
|
||||
out_color = texture_blend();
|
||||
out_color.rgb *= vary_mccv;
|
||||
|
||||
// diffuse + ambient lighting
|
||||
out_color.rgb *= vec3(clamp (diffuse_color * max(dot(vary_normal, light_dir), 0.0), 0.0, 1.0)) + ambient_color;
|
||||
|
||||
if(cant_paint)
|
||||
{
|
||||
out_color *= vec4(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
if(draw_areaid_overlay)
|
||||
{
|
||||
out_color = out_color * 0.3 + areaid_color;
|
||||
}
|
||||
|
||||
if(draw_impassible_flag)
|
||||
{
|
||||
out_color.rgb = mix(vec3(1.0), out_color.rgb, 0.5);
|
||||
}
|
||||
|
||||
float shadow_alpha = texture(shadow_map, vary_texcoord / 8.0).r;
|
||||
|
||||
out_color = vec4 (out_color.rgb * (1.0 - shadow_alpha), 1.0);
|
||||
|
||||
if (draw_terrain_height_contour)
|
||||
{
|
||||
out_color = vec4(out_color.rgb * contour_alpha(4.0, vary_position.y+0.1, fw.y), 1.0);
|
||||
}
|
||||
|
||||
bool lines_drawn = false;
|
||||
if(draw_lines)
|
||||
{
|
||||
vec4 color = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
color.a = contour_alpha(TILESIZE, vary_position.xz, fw.xz * 1.5);
|
||||
color.g = color.a > 0.0 ? 0.8 : 0.0;
|
||||
|
||||
if(color.a == 0.0)
|
||||
{
|
||||
color.a = contour_alpha(CHUNKSIZE, vary_position.xz, fw.xz);
|
||||
color.r = color.a > 0.0 ? 0.8 : 0.0;
|
||||
}
|
||||
if(draw_hole_lines && color.a == 0.0)
|
||||
{
|
||||
color.a = contour_alpha(HOLESIZE, vary_position.xz, fw.xz * 0.75);
|
||||
color.b = 0.8;
|
||||
}
|
||||
|
||||
lines_drawn = color.a > 0.0;
|
||||
out_color.rgb = mix(out_color.rgb, color.rgb, color.a);
|
||||
}
|
||||
|
||||
if(draw_fog && dist_from_camera >= fog_end * fog_start)
|
||||
{
|
||||
float start = fog_end * fog_start;
|
||||
float alpha = (dist_from_camera - start) / (fog_end - start);
|
||||
out_color.rgb = mix(out_color.rgb, fog_color.rgb, alpha);
|
||||
}
|
||||
|
||||
if(draw_wireframe && !lines_drawn)
|
||||
{
|
||||
// true by default => type 0
|
||||
bool draw_wire = true;
|
||||
float real_wireframe_radius = max(outer_cursor_radius * wireframe_radius, 2.0 * UNITSIZE);
|
||||
|
||||
if(wireframe_type == 1)
|
||||
{
|
||||
draw_wire = (length(vary_position.xz - cursor_position.xz) < real_wireframe_radius);
|
||||
}
|
||||
|
||||
if(draw_wire)
|
||||
{
|
||||
float alpha = contour_alpha(UNITSIZE, vary_position.xz, fw.xz * wireframe_width);
|
||||
float xmod = mod(vary_position.x, UNITSIZE);
|
||||
float zmod = mod(vary_position.z, UNITSIZE);
|
||||
float d = length(fw.xz) * wireframe_width;
|
||||
float diff = min( min(abs(xmod - zmod), abs(xmod - UNITSIZE + zmod))
|
||||
, min(abs(zmod - xmod), abs(zmod + UNITSIZE - zmod))
|
||||
);
|
||||
|
||||
alpha = max(alpha, 1.0 - smoothstep(0.0, d, diff));
|
||||
out_color.rgb = mix(out_color.rgb, wireframe_color.rgb, wireframe_color.a*alpha);
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_cursor_circle)
|
||||
{
|
||||
float diff = length(vary_position.xz - cursor_position.xz);
|
||||
diff = min(abs(diff - outer_cursor_radius), abs(diff - outer_cursor_radius * inner_cursor_ratio));
|
||||
float alpha = smoothstep(0.0, length(fw.xz), diff);
|
||||
|
||||
out_color.rgb = mix(cursor_color.rgb, out_color.rgb, alpha);
|
||||
}
|
||||
}
|
||||
24
src/glsl/terrain_vert.glsl
Normal file
24
src/glsl/terrain_vert.glsl
Normal file
@@ -0,0 +1,24 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
in vec3 position;
|
||||
in vec3 normal;
|
||||
in vec3 mccv;
|
||||
in vec2 texcoord;
|
||||
|
||||
uniform mat4 model_view;
|
||||
uniform mat4 projection;
|
||||
|
||||
out vec3 vary_position;
|
||||
out vec2 vary_texcoord;
|
||||
out vec3 vary_normal;
|
||||
out vec3 vary_mccv;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projection * model_view * vec4(position, 1.0);
|
||||
vary_normal = normal;
|
||||
vary_position = position;
|
||||
vary_texcoord = texcoord;
|
||||
vary_mccv = mccv;
|
||||
}
|
||||
119
src/glsl/wmo_frag.glsl
Normal file
119
src/glsl/wmo_frag.glsl
Normal file
@@ -0,0 +1,119 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
uniform sampler2D tex1;
|
||||
uniform sampler2D tex2;
|
||||
|
||||
uniform bool use_vertex_color;
|
||||
|
||||
uniform bool draw_fog;
|
||||
uniform bool unfogged;
|
||||
uniform float fog_start;
|
||||
uniform float fog_end;
|
||||
uniform vec3 fog_color;
|
||||
uniform vec3 camera;
|
||||
|
||||
uniform bool unlit;
|
||||
uniform bool exterior_lit;
|
||||
uniform vec3 exterior_light_dir;
|
||||
uniform vec3 exterior_diffuse_color;
|
||||
uniform vec3 exterior_ambient_color;
|
||||
uniform vec3 ambient_color;
|
||||
|
||||
uniform float alpha_test;
|
||||
|
||||
uniform int shader_id;
|
||||
|
||||
in vec3 f_position;
|
||||
in vec3 f_normal;
|
||||
in vec2 f_texcoord;
|
||||
in vec2 f_texcoord_2;
|
||||
in vec4 f_vertex_color;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
vec3 lighting(vec3 material)
|
||||
{
|
||||
vec3 light_color = vec3(1.);
|
||||
vec3 vertex_color = use_vertex_color ? f_vertex_color.rgb : vec3(0.);
|
||||
|
||||
if(unlit)
|
||||
{
|
||||
light_color = vertex_color + (exterior_lit ? exterior_ambient_color : ambient_color);
|
||||
}
|
||||
else if(exterior_lit)
|
||||
{
|
||||
vec3 ambient = exterior_ambient_color + vertex_color.rgb;
|
||||
|
||||
light_color = vec3(clamp (exterior_diffuse_color * max(dot(f_normal, exterior_light_dir), 0.0), 0.0, 1.0)) + ambient;
|
||||
}
|
||||
else
|
||||
{
|
||||
light_color = ambient_color + vertex_color.rgb;
|
||||
}
|
||||
|
||||
return material * light_color;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
float dist_from_camera = distance(camera, f_position);
|
||||
bool fog = draw_fog && !unfogged;
|
||||
|
||||
if(fog && dist_from_camera >= fog_end)
|
||||
{
|
||||
out_color = vec4(fog_color, 1.);
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 tex = texture(tex1, f_texcoord);
|
||||
vec4 tex_2 = texture(tex2, f_texcoord_2);
|
||||
|
||||
if(tex.a < alpha_test)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
vec4 vertex_color = vec4(0., 0., 0., 1.f);
|
||||
vec3 light_color = vec3(1.);
|
||||
|
||||
if(use_vertex_color)
|
||||
{
|
||||
vertex_color = f_vertex_color;
|
||||
}
|
||||
|
||||
|
||||
// see: https://github.com/Deamon87/WebWowViewerCpp/blob/master/wowViewerLib/src/glsl/wmoShader.glsl
|
||||
if(shader_id == 3) // Env
|
||||
{
|
||||
vec3 env = tex_2.rgb * tex.rgb;
|
||||
out_color = vec4(lighting(tex.rgb) + env, 1.);
|
||||
}
|
||||
else if(shader_id == 5) // EnvMetal
|
||||
{
|
||||
vec3 env = tex_2.rgb * tex.rgb * tex.a;
|
||||
out_color = vec4(lighting(tex.rgb) + env, 1.);
|
||||
}
|
||||
else if(shader_id == 6) // TwoLayerDiffuse
|
||||
{
|
||||
vec3 layer2 = mix(tex.rgb, tex_2.rgb, tex_2.a);
|
||||
out_color = vec4(lighting(mix(layer2, tex.rgb, vertex_color.a)), 1.);
|
||||
}
|
||||
else // default shader, used for shader_id 0,1,2,4 (Diffuse, Specular, Metal, Opaque)
|
||||
{
|
||||
out_color = vec4(lighting(tex.rgb), 1.);
|
||||
}
|
||||
|
||||
if(fog && (dist_from_camera >= fog_end * fog_start))
|
||||
{
|
||||
float start = fog_end * fog_start;
|
||||
float alpha = (dist_from_camera - start) / (fog_end - start);
|
||||
|
||||
out_color.rgb = mix(out_color.rgb, fog_color, alpha);
|
||||
}
|
||||
|
||||
if(out_color.a < alpha_test)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
}
|
||||
44
src/glsl/wmo_vert.glsl
Normal file
44
src/glsl/wmo_vert.glsl
Normal file
@@ -0,0 +1,44 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
in vec4 position;
|
||||
in vec3 normal;
|
||||
in vec4 vertex_color;
|
||||
in vec2 texcoord;
|
||||
in vec2 texcoord_2;
|
||||
|
||||
out vec3 f_position;
|
||||
out vec3 f_normal;
|
||||
out vec2 f_texcoord;
|
||||
out vec2 f_texcoord_2;
|
||||
out vec4 f_vertex_color;
|
||||
|
||||
uniform mat4 model_view;
|
||||
uniform mat4 projection;
|
||||
uniform mat4 transform;
|
||||
|
||||
uniform int shader_id;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 pos = transform * position;
|
||||
vec4 view_space_pos = model_view * pos;
|
||||
gl_Position = projection * view_space_pos;
|
||||
|
||||
f_position = pos.xyz;
|
||||
f_normal = mat3(transform) * normal;
|
||||
|
||||
// Env and EnvMetal
|
||||
if(shader_id == 3 || shader_id == 5)
|
||||
{
|
||||
f_texcoord = texcoord;
|
||||
f_texcoord_2 = reflect(normalize(view_space_pos.xyz), f_normal).xy;
|
||||
}
|
||||
else
|
||||
{
|
||||
f_texcoord = texcoord;
|
||||
f_texcoord_2 = texcoord_2;
|
||||
}
|
||||
|
||||
f_vertex_color = vertex_color;
|
||||
}
|
||||
62
src/math/bounding_box.cpp
Normal file
62
src/math/bounding_box.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#include <math/bounding_box.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
math::vector_3d min_per_dimension(std::vector<math::vector_3d> const& points)
|
||||
{
|
||||
auto min(math::vector_3d::max());
|
||||
for (auto const& point : points)
|
||||
{
|
||||
min = math::min(min, point);
|
||||
}
|
||||
return min;
|
||||
}
|
||||
math::vector_3d max_per_dimension(std::vector<math::vector_3d> const& points)
|
||||
{
|
||||
auto max(math::vector_3d::min());
|
||||
for (auto const& point : points)
|
||||
{
|
||||
max = math::max(max, point);
|
||||
}
|
||||
return max;
|
||||
}
|
||||
}
|
||||
|
||||
namespace math
|
||||
{
|
||||
aabb::aabb(math::vector_3d const& min_, math::vector_3d const& max_)
|
||||
: min(min_)
|
||||
, max(max_)
|
||||
{
|
||||
}
|
||||
|
||||
aabb::aabb(std::vector<math::vector_3d> points)
|
||||
: aabb(min_per_dimension(points), max_per_dimension(points))
|
||||
{
|
||||
}
|
||||
|
||||
//! \todo Optimize: iterate lazily.
|
||||
std::vector<math::vector_3d> aabb::all_corners() const
|
||||
{
|
||||
return box_points(min, max);
|
||||
}
|
||||
|
||||
|
||||
std::vector<math::vector_3d> box_points(math::vector_3d const& box_min, math::vector_3d const& box_max)
|
||||
{
|
||||
std::vector<math::vector_3d> points;
|
||||
|
||||
points.emplace_back(box_max.x, box_max.y, box_max.z);
|
||||
points.emplace_back(box_max.x, box_max.y, box_min.z);
|
||||
points.emplace_back(box_max.x, box_min.y, box_max.z);
|
||||
points.emplace_back(box_max.x, box_min.y, box_min.z);
|
||||
points.emplace_back(box_min.x, box_max.y, box_max.z);
|
||||
points.emplace_back(box_min.x, box_max.y, box_min.z);
|
||||
points.emplace_back(box_min.x, box_min.y, box_max.z);
|
||||
points.emplace_back(box_min.x, box_min.y, box_min.z);
|
||||
|
||||
return points;
|
||||
}
|
||||
}
|
||||
23
src/math/bounding_box.hpp
Normal file
23
src/math/bounding_box.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math/vector_3d.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace math
|
||||
{
|
||||
struct aabb
|
||||
{
|
||||
aabb(math::vector_3d const& min_, math::vector_3d const& max_);
|
||||
aabb(std::vector<math::vector_3d> points);
|
||||
|
||||
std::vector<math::vector_3d> all_corners() const;
|
||||
|
||||
math::vector_3d min;
|
||||
math::vector_3d max;
|
||||
};
|
||||
|
||||
std::vector<math::vector_3d> box_points(math::vector_3d const& box_min, math::vector_3d const& box_max);
|
||||
}
|
||||
9
src/math/constants.hpp
Normal file
9
src/math/constants.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
namespace math
|
||||
{
|
||||
namespace constants
|
||||
{
|
||||
constexpr float const pi = 3.141592653f;
|
||||
}
|
||||
}
|
||||
95
src/math/frustum.cpp
Normal file
95
src/math/frustum.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#include <math/frustum.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace math
|
||||
{
|
||||
frustum::frustum (matrix_4x4 const& matrix)
|
||||
{
|
||||
const vector_4d column_0 (matrix.column<0>());
|
||||
const vector_4d column_1 (matrix.column<1>());
|
||||
const vector_4d column_2 (matrix.column<2>());
|
||||
const vector_4d column_3 (matrix.column<3>());
|
||||
|
||||
_planes[RIGHT] = column_3 - column_0;
|
||||
_planes[LEFT] = column_3 + column_0;
|
||||
_planes[TOP] = column_3 - column_1;
|
||||
_planes[BOTTOM] = column_3 + column_1;
|
||||
_planes[BACK] = column_3 - column_2;
|
||||
_planes[FRONT] = column_3 + column_2;
|
||||
}
|
||||
|
||||
bool frustum::contains (const vector_3d& point) const
|
||||
{
|
||||
for (auto const& plane : _planes)
|
||||
{
|
||||
if (plane.normal() * point <= -plane.distance())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool frustum::intersects (const std::vector<vector_3d>& intersect_points) const
|
||||
{
|
||||
for (auto const& plane : _planes)
|
||||
{
|
||||
for (auto const& point : intersect_points)
|
||||
{
|
||||
if (plane.normal() * point > -plane.distance())
|
||||
{
|
||||
//! \note C does not know how to continue out of two loops otherwise.
|
||||
goto intersects_next_side;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
intersects_next_side:;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool frustum::intersects ( const vector_3d& v1
|
||||
, const vector_3d& v2
|
||||
) const
|
||||
{
|
||||
std::vector<vector_3d> points;
|
||||
points.emplace_back (v1.x, v1.y, v1.z);
|
||||
points.emplace_back (v1.x, v1.y, v2.z);
|
||||
points.emplace_back (v1.x, v2.y, v1.z);
|
||||
points.emplace_back (v1.x, v2.y, v2.z);
|
||||
points.emplace_back (v2.x, v1.y, v1.z);
|
||||
points.emplace_back (v2.x, v1.y, v2.z);
|
||||
points.emplace_back (v2.x, v2.y, v1.z);
|
||||
points.emplace_back (v2.x, v2.y, v2.z);
|
||||
|
||||
return intersects (points);
|
||||
}
|
||||
|
||||
|
||||
bool frustum::intersectsSphere ( const vector_3d& position
|
||||
, const float& radius
|
||||
) const
|
||||
{
|
||||
for (auto const& plane : _planes)
|
||||
{
|
||||
const float distance ( plane.normal() * position
|
||||
+ plane.distance()
|
||||
);
|
||||
if (distance < -radius)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (std::abs (distance) < radius)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
73
src/math/frustum.hpp
Normal file
73
src/math/frustum.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math/vector_3d.hpp>
|
||||
#include <math/vector_4d.hpp>
|
||||
#include <math/matrix_4x4.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
namespace math
|
||||
{
|
||||
class frustum
|
||||
{
|
||||
enum SIDES
|
||||
{
|
||||
RIGHT,
|
||||
LEFT,
|
||||
BOTTOM,
|
||||
TOP,
|
||||
BACK,
|
||||
FRONT,
|
||||
SIDES_MAX,
|
||||
};
|
||||
|
||||
class plane
|
||||
{
|
||||
public:
|
||||
plane() = default;
|
||||
plane (vector_4d const& vec)
|
||||
: _normal (vec.xyz())
|
||||
, _distance (vec.w)
|
||||
{
|
||||
normalize();
|
||||
}
|
||||
|
||||
void normalize()
|
||||
{
|
||||
const float recip (1.0f / _normal.length());
|
||||
_normal *= recip;
|
||||
_distance *= recip;
|
||||
}
|
||||
|
||||
const float& distance() const
|
||||
{
|
||||
return _distance;
|
||||
}
|
||||
|
||||
const vector_3d& normal() const
|
||||
{
|
||||
return _normal;
|
||||
}
|
||||
|
||||
private:
|
||||
vector_3d _normal;
|
||||
float _distance;
|
||||
};
|
||||
std::array<plane, SIDES_MAX> _planes;
|
||||
|
||||
public:
|
||||
frustum (matrix_4x4 const& matrix);
|
||||
|
||||
bool contains (const vector_3d& point) const;
|
||||
bool intersects (const std::vector<vector_3d>& intersect_points) const;
|
||||
bool intersects ( const vector_3d& v1
|
||||
, const vector_3d& v2
|
||||
) const;
|
||||
bool intersectsSphere ( const vector_3d& position
|
||||
, const float& radius
|
||||
) const;
|
||||
};
|
||||
}
|
||||
54
src/math/interpolation.hpp
Normal file
54
src/math/interpolation.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math/trig.hpp>
|
||||
|
||||
namespace math
|
||||
{
|
||||
namespace interpolation
|
||||
{
|
||||
template<typename T>
|
||||
static T linear (const float& percentage, const T& start, const T& end)
|
||||
{
|
||||
return T (start * (1.0f - percentage) + end * percentage);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T slerp (const float& percentage, const T& start, const T& end)
|
||||
{
|
||||
const float dot (start * end);
|
||||
|
||||
if (std::abs (dot) > 0.9995f)
|
||||
{
|
||||
//! \note Don't call linear here, as this will recurse with quaternions.
|
||||
return T (start * (1.0f - percentage) + end * percentage);
|
||||
}
|
||||
|
||||
radians const a (acos (dot)._ * percentage);
|
||||
|
||||
return T (start * cos (a) + T (end - start * dot).normalize() * sin (a));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T hermite ( const float& percentage
|
||||
, const T& start
|
||||
, const T& end
|
||||
, const T& in
|
||||
, const T& out
|
||||
)
|
||||
{
|
||||
const float percentage_2 (percentage * percentage);
|
||||
const float percentage_3 (percentage_2 * percentage);
|
||||
const float _2_percentage_3 (2.0f * percentage_3);
|
||||
const float _3_percentage_2 (3.0f * percentage_2);
|
||||
|
||||
const float h1 (_2_percentage_3 - _3_percentage_2 + 1.0f);
|
||||
const float h2 (_3_percentage_2 - _2_percentage_3);
|
||||
const float h3 (percentage_3 - 2.0f * percentage_2 + percentage);
|
||||
const float h4 (percentage_3 - percentage_2);
|
||||
|
||||
return T (start * h1 + end * h2 + in * h3 + out * h4);
|
||||
}
|
||||
}
|
||||
}
|
||||
211
src/math/matrix_4x4.cpp
Normal file
211
src/math/matrix_4x4.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#include <math/matrix_4x4.hpp>
|
||||
#include <math/quaternion.hpp>
|
||||
#include <math/vector_3d.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring> // memcpy, memset
|
||||
|
||||
namespace math
|
||||
{
|
||||
matrix_4x4::uninitialized_t matrix_4x4::uninitialized;
|
||||
matrix_4x4::zero_t matrix_4x4::zero;
|
||||
matrix_4x4::unit_t matrix_4x4::unit;
|
||||
matrix_4x4::translation_t matrix_4x4::translation;
|
||||
matrix_4x4::scale_t matrix_4x4::scale;
|
||||
matrix_4x4::rotation_t matrix_4x4::rotation;
|
||||
matrix_4x4::rotation_xyz_t matrix_4x4::rotation_xyz;
|
||||
matrix_4x4::rotation_yzx_t matrix_4x4::rotation_yzx;
|
||||
|
||||
matrix_4x4::matrix_4x4 (rotation_t, quaternion const& q)
|
||||
{
|
||||
_m[0][0] = 1.0f - 2.0f * q.y * q.y - 2.0f * q.z * q.z;
|
||||
_m[0][1] = 2.0f * q.x * q.y + 2.0f * q.w * q.z;
|
||||
_m[0][2] = 2.0f * q.x * q.z - 2.0f * q.w * q.y;
|
||||
_m[0][3] = 0.0f;
|
||||
|
||||
_m[1][0] = 2.0f * q.x * q.y - 2.0f * q.w * q.z;
|
||||
_m[1][1] = 1.0f - 2.0f * q.x * q.x - 2.0f * q.z * q.z;
|
||||
_m[1][2] = 2.0f * q.y * q.z + 2.0f * q.w * q.x;
|
||||
_m[1][3] = 0.0f;
|
||||
|
||||
_m[2][0] = 2.0f * q.x * q.z + 2.0f * q.w * q.y;
|
||||
_m[2][1] = 2.0f * q.y * q.z - 2.0f * q.w * q.x;
|
||||
_m[2][2] = 1.0f - 2.0f * q.x * q.x - 2.0f * q.y * q.y;
|
||||
_m[2][3] = 0.0f;
|
||||
|
||||
_m[3][0] = 0.0f;
|
||||
_m[3][1] = 0.0f;
|
||||
_m[3][2] = 0.0f;
|
||||
_m[3][3] = 1.0f;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
enum axis
|
||||
{
|
||||
x = 0,
|
||||
y = 1,
|
||||
z = 2,
|
||||
num_axis,
|
||||
};
|
||||
|
||||
template<axis a>
|
||||
matrix_4x4 rotate_axis (radians angle)
|
||||
{
|
||||
static std::size_t const i_indices[num_axis] = {2, 2, 1};
|
||||
static std::size_t const j_indices[num_axis] = {1, 0, 0};
|
||||
std::size_t const i_index (i_indices[a]);
|
||||
std::size_t const j_index (j_indices[a]);
|
||||
|
||||
float const cosV (cos (angle));
|
||||
float const sinV (sin (angle));
|
||||
|
||||
matrix_4x4 mat (matrix_4x4::unit);
|
||||
mat (j_index, j_index, cosV);
|
||||
mat (j_index, i_index, sinV);
|
||||
mat (i_index, j_index, -sinV);
|
||||
mat (i_index, i_index, cosV);
|
||||
|
||||
return mat;
|
||||
}
|
||||
}
|
||||
|
||||
matrix_4x4::matrix_4x4 (rotation_xyz_t, degrees::vec3 const& angle)
|
||||
: matrix_4x4 (unit)
|
||||
{
|
||||
*this *= rotate_axis<x> (angle.x);
|
||||
*this *= rotate_axis<y> (angle.y);
|
||||
*this *= rotate_axis<z> (angle.z);
|
||||
}
|
||||
matrix_4x4::matrix_4x4 (rotation_yzx_t, degrees::vec3 const& angle)
|
||||
: matrix_4x4 (unit)
|
||||
{
|
||||
*this *= rotate_axis<y> (angle.y);
|
||||
*this *= rotate_axis<z> (angle.z);
|
||||
*this *= rotate_axis<x> (angle.x);
|
||||
}
|
||||
|
||||
vector_3d matrix_4x4::operator* (vector_3d const& v) const
|
||||
{
|
||||
return { _m[0][0] * v[0] + _m[0][1] * v[1] + _m[0][2] * v[2] + _m[0][3]
|
||||
, _m[1][0] * v[0] + _m[1][1] * v[1] + _m[1][2] * v[2] + _m[1][3]
|
||||
, _m[2][0] * v[0] + _m[2][1] * v[1] + _m[2][2] * v[2] + _m[2][3]
|
||||
};
|
||||
}
|
||||
vector_4d matrix_4x4::operator* (const vector_4d& v) const
|
||||
{
|
||||
return { _m[0][0] * v[0] + _m[0][1] * v[1] + _m[0][2] * v[2] + _m[0][3] * v[3]
|
||||
, _m[1][0] * v[0] + _m[1][1] * v[1] + _m[1][2] * v[2] + _m[1][3] * v[3]
|
||||
, _m[2][0] * v[0] + _m[2][1] * v[1] + _m[2][2] * v[2] + _m[2][3] * v[3]
|
||||
, _m[3][0] * v[0] + _m[3][1] * v[1] + _m[3][2] * v[2] + _m[3][3] * v[3]
|
||||
};
|
||||
}
|
||||
|
||||
matrix_4x4 matrix_4x4::operator* (matrix_4x4 const& other) const
|
||||
{
|
||||
return { _m[0][0] * other._m[0][0] + _m[0][1] * other._m[1][0] + _m[0][2] * other._m[2][0] + _m[0][3] * other._m[3][0]
|
||||
, _m[0][0] * other._m[0][1] + _m[0][1] * other._m[1][1] + _m[0][2] * other._m[2][1] + _m[0][3] * other._m[3][1]
|
||||
, _m[0][0] * other._m[0][2] + _m[0][1] * other._m[1][2] + _m[0][2] * other._m[2][2] + _m[0][3] * other._m[3][2]
|
||||
, _m[0][0] * other._m[0][3] + _m[0][1] * other._m[1][3] + _m[0][2] * other._m[2][3] + _m[0][3] * other._m[3][3]
|
||||
, _m[1][0] * other._m[0][0] + _m[1][1] * other._m[1][0] + _m[1][2] * other._m[2][0] + _m[1][3] * other._m[3][0]
|
||||
, _m[1][0] * other._m[0][1] + _m[1][1] * other._m[1][1] + _m[1][2] * other._m[2][1] + _m[1][3] * other._m[3][1]
|
||||
, _m[1][0] * other._m[0][2] + _m[1][1] * other._m[1][2] + _m[1][2] * other._m[2][2] + _m[1][3] * other._m[3][2]
|
||||
, _m[1][0] * other._m[0][3] + _m[1][1] * other._m[1][3] + _m[1][2] * other._m[2][3] + _m[1][3] * other._m[3][3]
|
||||
, _m[2][0] * other._m[0][0] + _m[2][1] * other._m[1][0] + _m[2][2] * other._m[2][0] + _m[2][3] * other._m[3][0]
|
||||
, _m[2][0] * other._m[0][1] + _m[2][1] * other._m[1][1] + _m[2][2] * other._m[2][1] + _m[2][3] * other._m[3][1]
|
||||
, _m[2][0] * other._m[0][2] + _m[2][1] * other._m[1][2] + _m[2][2] * other._m[2][2] + _m[2][3] * other._m[3][2]
|
||||
, _m[2][0] * other._m[0][3] + _m[2][1] * other._m[1][3] + _m[2][2] * other._m[2][3] + _m[2][3] * other._m[3][3]
|
||||
, _m[3][0] * other._m[0][0] + _m[3][1] * other._m[1][0] + _m[3][2] * other._m[2][0] + _m[3][3] * other._m[3][0]
|
||||
, _m[3][0] * other._m[0][1] + _m[3][1] * other._m[1][1] + _m[3][2] * other._m[2][1] + _m[3][3] * other._m[3][1]
|
||||
, _m[3][0] * other._m[0][2] + _m[3][1] * other._m[1][2] + _m[3][2] * other._m[2][2] + _m[3][3] * other._m[3][2]
|
||||
, _m[3][0] * other._m[0][3] + _m[3][1] * other._m[1][3] + _m[3][2] * other._m[2][3] + _m[3][3] * other._m[3][3]
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<math::vector_3d> matrix_4x4::operator*
|
||||
(std::vector<math::vector_3d> points) const
|
||||
{
|
||||
return apply ( [&] (math::vector_3d const& point)
|
||||
{
|
||||
return *this * point;
|
||||
}
|
||||
, points
|
||||
);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
float minor_size (matrix_4x4 const& mat, std::size_t x, std::size_t y)
|
||||
{
|
||||
float s[3][3];
|
||||
for (std::size_t j (0), v (0); j < 4; ++j)
|
||||
{
|
||||
if (j != y)
|
||||
{
|
||||
for (std::size_t i (0), u (0); i < 4; ++i)
|
||||
{
|
||||
if (i != x)
|
||||
{
|
||||
s[v][u++] = mat (j, i);
|
||||
}
|
||||
}
|
||||
++v;
|
||||
}
|
||||
}
|
||||
#define SUB(a,b) (s[1][a] * s[2][b] - s[2][a] * s[1][b])
|
||||
return s[0][0] * SUB (1,2) - s[0][1] * SUB (0,2) + s[0][2] * SUB (0,1);
|
||||
#undef SUB
|
||||
}
|
||||
}
|
||||
|
||||
matrix_4x4 matrix_4x4::adjoint() const
|
||||
{
|
||||
return { minor_size (*this, 0, 0), -minor_size (*this, 0, 1), minor_size (*this, 0, 2), -minor_size (*this, 0, 3)
|
||||
, -minor_size (*this, 1, 0), minor_size (*this, 1, 1), -minor_size (*this, 1, 2), minor_size (*this, 1, 3)
|
||||
, minor_size (*this, 2, 0), -minor_size (*this, 2, 1), minor_size (*this, 2, 2), -minor_size (*this, 2, 3)
|
||||
, -minor_size (*this, 3, 0), minor_size (*this, 3, 1), -minor_size (*this, 3, 2), minor_size (*this, 3, 3)
|
||||
};
|
||||
}
|
||||
|
||||
matrix_4x4& matrix_4x4::operator* (float f)
|
||||
{
|
||||
for (std::size_t i (0); i < 16; ++i)
|
||||
{
|
||||
_data[i] *= f;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
matrix_4x4& matrix_4x4::operator/ (float f)
|
||||
{
|
||||
return *this * (1 / f);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
float determinant (matrix_4x4 const& mat)
|
||||
{
|
||||
#define SUB(a, b) (mat (2, a) * mat (3, b) - mat (3, a) * mat (2, b))
|
||||
return mat (0, 0) * (mat (1, 1) * SUB (2, 3) - mat (1, 2) * SUB (1, 3) + mat (1, 3) * SUB (1, 2))
|
||||
- mat (0, 1) * (mat (1, 0) * SUB (2, 3) - mat (1, 2) * SUB (0, 3) + mat (1, 3) * SUB (0, 2))
|
||||
+ mat (0, 2) * (mat (1, 0) * SUB (1, 3) - mat (1, 1) * SUB (0, 3) + mat (1, 3) * SUB (0, 1))
|
||||
- mat (0, 3) * (mat (1, 0) * SUB (1, 2) - mat (1, 1) * SUB (0, 2) + mat (1, 2) * SUB (0, 1));
|
||||
#undef SUB
|
||||
}
|
||||
}
|
||||
|
||||
matrix_4x4 matrix_4x4::inverted() const
|
||||
{
|
||||
return adjoint() / determinant (*this);
|
||||
}
|
||||
|
||||
matrix_4x4 matrix_4x4::transposed() const
|
||||
{
|
||||
return { _m[0][0], _m[1][0], _m[2][0], _m[3][0]
|
||||
, _m[0][1], _m[1][1], _m[2][1], _m[3][1]
|
||||
, _m[0][2], _m[1][2], _m[2][2], _m[3][2]
|
||||
, _m[0][3], _m[1][3], _m[2][3], _m[3][3]
|
||||
};
|
||||
}
|
||||
}
|
||||
136
src/math/matrix_4x4.hpp
Normal file
136
src/math/matrix_4x4.hpp
Normal file
@@ -0,0 +1,136 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math/quaternion.hpp>
|
||||
#include <math/trig.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace math
|
||||
{
|
||||
struct vector_3d;
|
||||
|
||||
struct matrix_4x4
|
||||
{
|
||||
public:
|
||||
static struct uninitialized_t {} uninitialized;
|
||||
matrix_4x4 (uninitialized_t) {}
|
||||
|
||||
static struct zero_t {} zero;
|
||||
matrix_4x4 (zero_t)
|
||||
{
|
||||
std::fill (_data, _data + 16, 0.f);
|
||||
}
|
||||
|
||||
static struct unit_t {} unit;
|
||||
matrix_4x4 (unit_t) : matrix_4x4 (zero)
|
||||
{
|
||||
_m[0][0] = _m[1][1] = _m[2][2] = _m[3][3] = 1.0f;
|
||||
}
|
||||
|
||||
matrix_4x4 ( float m00, float m01, float m02, float m03
|
||||
, float m10, float m11, float m12, float m13
|
||||
, float m20, float m21, float m22, float m23
|
||||
, float m30, float m31, float m32, float m33
|
||||
)
|
||||
{
|
||||
_m[0][0] = m00; _m[0][1] = m01; _m[0][2] = m02; _m[0][3] = m03;
|
||||
_m[1][0] = m10; _m[1][1] = m11; _m[1][2] = m12; _m[1][3] = m13;
|
||||
_m[2][0] = m20; _m[2][1] = m21; _m[2][2] = m22; _m[2][3] = m23;
|
||||
_m[3][0] = m30; _m[3][1] = m31; _m[3][2] = m32; _m[3][3] = m33;
|
||||
}
|
||||
|
||||
static struct translation_t {} translation;
|
||||
matrix_4x4 (translation_t, vector_3d const& tr)
|
||||
: matrix_4x4 ( 1.0f, 0.0f, 0.0f, tr.x
|
||||
, 0.0f, 1.0f, 0.0f, tr.y
|
||||
, 0.0f, 0.0f, 1.0f, tr.z
|
||||
, 0.0f, 0.0f, 0.0f, 1.0f
|
||||
)
|
||||
{}
|
||||
|
||||
static struct scale_t {} scale;
|
||||
matrix_4x4 (scale_t, vector_3d const& sc)
|
||||
: matrix_4x4 ( sc.x, 0.0f, 0.0f, 0.0f
|
||||
, 0.0f, sc.y, 0.0f, 0.0f
|
||||
, 0.0f, 0.0f, sc.z, 0.0f
|
||||
, 0.0f, 0.0f, 0.0f, 1.0f
|
||||
)
|
||||
{}
|
||||
matrix_4x4 (scale_t, float sc)
|
||||
: matrix_4x4 (scale, {sc, sc, sc})
|
||||
{}
|
||||
|
||||
static struct rotation_t {} rotation;
|
||||
matrix_4x4 (rotation_t, quaternion const&);
|
||||
|
||||
static struct rotation_xyz_t {} rotation_xyz;
|
||||
matrix_4x4 (rotation_xyz_t, degrees::vec3 const&);
|
||||
static struct rotation_yzx_t {} rotation_yzx;
|
||||
matrix_4x4 (rotation_yzx_t, degrees::vec3 const&);
|
||||
|
||||
float operator() (std::size_t const& j, std::size_t const& i) const
|
||||
{
|
||||
return _m[j][i];
|
||||
}
|
||||
float operator() (std::size_t const& j, std::size_t const& i, float value)
|
||||
{
|
||||
return _m[j][i] = value;
|
||||
}
|
||||
|
||||
vector_3d operator* (vector_3d const&) const;
|
||||
vector_4d operator* (vector_4d const&) const;
|
||||
quaternion operator* (quaternion const& q) const
|
||||
{
|
||||
return quaternion {*this * static_cast<vector_4d> (q)};
|
||||
}
|
||||
matrix_4x4 operator* (matrix_4x4 const&) const;
|
||||
std::vector<math::vector_3d> operator*(std::vector<math::vector_3d> points) const;
|
||||
|
||||
matrix_4x4& operator* (float);
|
||||
matrix_4x4& operator/ (float);
|
||||
|
||||
matrix_4x4 adjoint() const;
|
||||
matrix_4x4 inverted() const;
|
||||
matrix_4x4 transposed() const;
|
||||
|
||||
inline matrix_4x4& operator*= (matrix_4x4 const& p)
|
||||
{
|
||||
return *this = operator* (p);
|
||||
}
|
||||
|
||||
inline operator float*()
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
inline operator const float*() const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
template<std::size_t i>
|
||||
vector_4d column() const
|
||||
{
|
||||
return {_m[0][i], _m[1][i], _m[2][i], _m[3][i]};
|
||||
}
|
||||
|
||||
bool operator== (matrix_4x4 const& rhs)
|
||||
{
|
||||
for (std::size_t i (0); i < 16; ++i)
|
||||
{
|
||||
if (_m[i] != rhs._m[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
union
|
||||
{
|
||||
float _m[4][4];
|
||||
float _data[16];
|
||||
};
|
||||
};
|
||||
}
|
||||
75
src/math/projection.hpp
Normal file
75
src/math/projection.hpp
Normal file
@@ -0,0 +1,75 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math/matrix_4x4.hpp>
|
||||
#include <math/trig.hpp>
|
||||
#include <math/vector_3d.hpp>
|
||||
|
||||
namespace math
|
||||
{
|
||||
inline matrix_4x4 perspective (math::degrees fovy, float aspect, float zNear, float zFar)
|
||||
{
|
||||
// assuming
|
||||
// math::vector_3d lower_left_clipping_plane (left, bottom, -nearVal);
|
||||
// math::vector_3d upper_right_clipping_plane (right, top, -nearVal);
|
||||
// math::vector_3d eye (0, 0, 0);
|
||||
// float clipping_plane_distance (zFar - zNear);
|
||||
|
||||
// with
|
||||
float const ymax (zNear * math::tan (fovy) / 2.0f);
|
||||
// float left (-ymax * aspect);
|
||||
// float right (ymax * aspect);
|
||||
// float bottom (-ymax);
|
||||
// float top (ymax);
|
||||
// float nearVal (zNear);
|
||||
// float farVal (zFar);
|
||||
|
||||
// multiply matrix by
|
||||
// math::matrix_4x4 frustum ( 2 * nearVal / (right - left), 0.0f, (right + left) / (right - left), 0.0f
|
||||
// , 0.0f, 2 * nearVal / (top - bottom), (top + bottom) / (top - bottom), 0.0f
|
||||
// , 0.0f, 0.0f, - (farVal + nearVal) / (farVal - nearVal), - 2 * farVal * nearVal / (farVal - nearVal)
|
||||
// , 0.0f, 0.0f, -1.0f, 0.0f
|
||||
// );
|
||||
|
||||
// with optimized values
|
||||
return { zNear / (ymax * aspect), 0.0f, 0.0f, 0.0f
|
||||
, 0.0f, zNear / ymax, 0.0f, 0.0f
|
||||
, 0.0f, 0.0f, -(zFar + zNear) / (zFar - zNear), -2 * zFar * zNear / (zFar - zNear)
|
||||
, 0.0f, 0.0f, -1.0f, 0.0f
|
||||
};
|
||||
}
|
||||
|
||||
inline matrix_4x4 ortho(float left, float right, float bottom, float top, float z_near, float z_far)
|
||||
{
|
||||
float v0 = 2.f / (right - left);
|
||||
float v1 = 2.f / (top - bottom);
|
||||
float v2 = -2.f / (z_far - z_near);
|
||||
|
||||
float tx = -(right + left) / (right - left);
|
||||
float ty = -(top + bottom) / (top - bottom);
|
||||
float tz = -(z_far + z_near) / (z_far - z_near);
|
||||
|
||||
return { v0, 0.f, 0.f, tx
|
||||
, 0.f, v1, 0.f, ty
|
||||
, 0.f, 0.f, v2, tz
|
||||
, 0.f, 0.f, 0.f, 1.f
|
||||
};
|
||||
}
|
||||
|
||||
inline matrix_4x4 look_at ( vector_3d const& eye
|
||||
, vector_3d const& center
|
||||
, vector_3d const& up
|
||||
)
|
||||
{
|
||||
vector_3d const z ((eye - center).normalized());
|
||||
vector_3d const x ((up % z).normalized());
|
||||
vector_3d const y ((z % x).normalized());
|
||||
|
||||
return { x.x, x.y, x.z, x * -eye
|
||||
, y.x, y.y, y.z, y * -eye
|
||||
, z.x, z.y, z.z, z * -eye
|
||||
, 0.f, 0.f, 0.f, 1.f
|
||||
};
|
||||
}
|
||||
}
|
||||
60
src/math/quaternion.hpp
Normal file
60
src/math/quaternion.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math/interpolation.hpp>
|
||||
#include <math/vector_4d.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace math
|
||||
{
|
||||
struct vector_3d;
|
||||
|
||||
//! \note Actually, a typedef would be enough.
|
||||
struct quaternion : public vector_4d
|
||||
{
|
||||
public:
|
||||
quaternion()
|
||||
: quaternion (0.f, 0.f, 0.f, 1.0f)
|
||||
{}
|
||||
|
||||
quaternion ( const float& x
|
||||
, const float& y
|
||||
, const float& z
|
||||
, const float& w
|
||||
)
|
||||
: vector_4d (x, y, z, w)
|
||||
{ }
|
||||
|
||||
explicit quaternion (const vector_4d& v)
|
||||
: vector_4d (v)
|
||||
{ }
|
||||
|
||||
quaternion (const vector_3d& v, const float w)
|
||||
: vector_4d (v, w)
|
||||
{ }
|
||||
};
|
||||
|
||||
//! \note "linear" interpolation for quaternions should be slerp by default.
|
||||
namespace interpolation
|
||||
{
|
||||
template<>
|
||||
inline quaternion linear ( const float& percentage
|
||||
, const quaternion& start
|
||||
, const quaternion& end
|
||||
)
|
||||
{
|
||||
return slerp (percentage, start, end);
|
||||
}
|
||||
}
|
||||
|
||||
//! \note In WoW 2.0+ Blizzard is now storing rotation data in 16bit values instead of 32bit. I don't really understand why as its only a very minor saving in model sizes and adds extra overhead in processing the models. Need this structure to read the data into.
|
||||
struct packed_quaternion
|
||||
{
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
int16_t z;
|
||||
int16_t w;
|
||||
};
|
||||
}
|
||||
90
src/math/ray.cpp
Normal file
90
src/math/ray.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#include <math/ray.hpp>
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace math
|
||||
{
|
||||
boost::optional<float> ray::intersect_bounds
|
||||
(vector_3d const& min, vector_3d const& max) const
|
||||
{
|
||||
float tmin (std::numeric_limits<float>::lowest());
|
||||
float tmax (std::numeric_limits<float>::max());
|
||||
|
||||
if (_direction.x != 0.0f)
|
||||
{
|
||||
float const tx1 ((min.x - _origin.x) / _direction.x);
|
||||
float const tx2 ((max.x - _origin.x) / _direction.x);
|
||||
|
||||
tmin = std::max (tmin, std::min (tx1, tx2));
|
||||
tmax = std::min (tmax, std::max (tx1, tx2));
|
||||
}
|
||||
|
||||
if (_direction.y != 0.0f)
|
||||
{
|
||||
float const ty1 ((min.y - _origin.y) / _direction.y);
|
||||
float const ty2 ((max.y - _origin.y) / _direction.y);
|
||||
|
||||
tmin = std::max (tmin, std::min (ty1, ty2));
|
||||
tmax = std::min (tmax, std::max (ty1, ty2));
|
||||
}
|
||||
|
||||
if (_direction.z != 0.0f)
|
||||
{
|
||||
float const tz1 ((min.z - _origin.z) / _direction.z);
|
||||
float const tz2 ((max.z - _origin.z) / _direction.z);
|
||||
|
||||
tmin = std::max (tmin, std::min (tz1, tz2));
|
||||
tmax = std::min (tmax, std::max (tz1, tz2));
|
||||
}
|
||||
|
||||
if (tmax >= tmin)
|
||||
{
|
||||
return tmin;
|
||||
}
|
||||
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
boost::optional<float> ray::intersect_triangle
|
||||
(vector_3d const& v0, vector_3d const& v1, vector_3d const& v2) const
|
||||
{
|
||||
vector_3d const e1 (v1 - v0);
|
||||
vector_3d const e2 (v2 - v0);
|
||||
|
||||
vector_3d const P (_direction % e2);
|
||||
|
||||
float const det (e1 * P);
|
||||
|
||||
if (det == 0.0f)
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
vector_3d const T (_origin - v0);
|
||||
float const u ((T * P) / det);
|
||||
|
||||
if (u < 0.0f || u > 1.0f)
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
vector_3d const Q (T % e1);
|
||||
float const v ((_direction * Q) / det);
|
||||
|
||||
if (v < 0.0f || u + v > 1.0f)
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
float const t ((e2 * Q) / det);
|
||||
|
||||
if (t > std::numeric_limits<float>::min())
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
39
src/math/ray.hpp
Normal file
39
src/math/ray.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math/matrix_4x4.hpp>
|
||||
#include <math/vector_3d.hpp>
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
|
||||
namespace math
|
||||
{
|
||||
struct ray
|
||||
{
|
||||
ray (vector_3d origin, vector_3d const& direction)
|
||||
: _origin (std::move (origin))
|
||||
, _direction (direction.normalized())
|
||||
{}
|
||||
|
||||
ray (matrix_4x4 const& transform, ray const& other)
|
||||
: ray ( (transform * math::vector_4d (other._origin, 1.0)).xyz()
|
||||
, (transform * math::vector_4d (other._direction, 0.0)).xyz()
|
||||
)
|
||||
{}
|
||||
|
||||
boost::optional<float> intersect_bounds
|
||||
(vector_3d const& _min, vector_3d const& _max) const;
|
||||
boost::optional<float> intersect_triangle
|
||||
(vector_3d const& _v0, vector_3d const& _v1, vector_3d const& _v2) const;
|
||||
|
||||
vector_3d position (float distance) const
|
||||
{
|
||||
return _origin + _direction * distance;
|
||||
}
|
||||
|
||||
private:
|
||||
vector_3d _origin;
|
||||
vector_3d _direction;
|
||||
};
|
||||
}
|
||||
61
src/math/trig.hpp
Normal file
61
src/math/trig.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math/constants.hpp>
|
||||
#include <math/vector_3d.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace math
|
||||
{
|
||||
struct radians;
|
||||
|
||||
struct degrees
|
||||
{
|
||||
explicit degrees (float x) : _ (x) {}
|
||||
degrees (radians);
|
||||
|
||||
float _;
|
||||
|
||||
using vec3 = vector_3d_base<degrees>;
|
||||
};
|
||||
|
||||
struct radians
|
||||
{
|
||||
explicit radians (float x) : _ (x) {}
|
||||
radians (degrees);
|
||||
|
||||
float _;
|
||||
|
||||
using vec3 = vector_3d_base<radians>;
|
||||
};
|
||||
|
||||
inline degrees::degrees (radians x) : _ (x._ * 180.0f / math::constants::pi) {}
|
||||
inline radians::radians (degrees x) : _ (x._ * math::constants::pi / 180.0f) {}
|
||||
|
||||
inline float sin (radians x)
|
||||
{
|
||||
return std::sin (x._);
|
||||
}
|
||||
inline float cos (radians x)
|
||||
{
|
||||
return std::cos (x._);
|
||||
}
|
||||
inline float tan (radians x)
|
||||
{
|
||||
return std::tan (x._);
|
||||
}
|
||||
inline radians asin (float x)
|
||||
{
|
||||
return radians {std::asin (x)};
|
||||
}
|
||||
inline radians acos (float x)
|
||||
{
|
||||
return radians {std::acos (x)};
|
||||
}
|
||||
inline radians atan2 (float y, float x)
|
||||
{
|
||||
return radians {std::atan2 (y, x)};
|
||||
}
|
||||
}
|
||||
15
src/math/vector_2d.cpp
Normal file
15
src/math/vector_2d.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#include <math/vector_2d.hpp>
|
||||
#include <math/trig.hpp>
|
||||
|
||||
namespace math
|
||||
{
|
||||
void rotate (float x0, float y0, float* x, float* y, radians angle)
|
||||
{
|
||||
const float xa (*x - x0);
|
||||
const float ya (*y - y0);
|
||||
*x = xa * cos (angle) - ya * sin (angle) + x0;
|
||||
*y = xa * sin (angle) + ya * cos (angle) + y0;
|
||||
}
|
||||
}
|
||||
64
src/math/vector_2d.hpp
Normal file
64
src/math/vector_2d.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math/trig.hpp>
|
||||
|
||||
#include <ostream>
|
||||
#include <tuple>
|
||||
|
||||
namespace math
|
||||
{
|
||||
struct vector_2d
|
||||
{
|
||||
union
|
||||
{
|
||||
float _data[2];
|
||||
struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
};
|
||||
|
||||
vector_2d() : vector_2d (0.f, 0.f) {}
|
||||
vector_2d (float x_, float y_)
|
||||
: x (x_)
|
||||
, y (y_)
|
||||
{}
|
||||
|
||||
inline operator float*()
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
inline operator float const*() const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
vector_2d operator* (float factor) const
|
||||
{
|
||||
return {x * factor, y * factor};
|
||||
}
|
||||
vector_2d operator+ (vector_2d const& other) const
|
||||
{
|
||||
return {x + other.x, y + other.y};
|
||||
}
|
||||
|
||||
bool operator== (vector_2d const& rhs) const
|
||||
{
|
||||
return std::tie (x, y) == std::tie (rhs.x, rhs.y);
|
||||
}
|
||||
friend std::ostream& operator<< (std::ostream& os, vector_2d const& x)
|
||||
{
|
||||
return os << x.x << ", " << x.y;
|
||||
}
|
||||
};
|
||||
|
||||
void rotate (float x0, float y0, float* x, float* y, radians);
|
||||
inline vector_2d rotate (vector_2d const& around, vector_2d point, radians angle)
|
||||
{
|
||||
rotate (around.x, around.y, &point.x, &point.y, angle);
|
||||
return point;
|
||||
}
|
||||
}
|
||||
218
src/math/vector_3d.hpp
Normal file
218
src/math/vector_3d.hpp
Normal file
@@ -0,0 +1,218 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace math
|
||||
{
|
||||
template<typename T>
|
||||
struct vector_3d_base
|
||||
{
|
||||
union
|
||||
{
|
||||
T _data[3];
|
||||
struct
|
||||
{
|
||||
T x;
|
||||
T y;
|
||||
T z;
|
||||
};
|
||||
};
|
||||
|
||||
vector_3d_base<T>() : vector_3d_base (0.f, 0.f, 0.f) {}
|
||||
vector_3d_base<T> (T x_, T y_, T z_)
|
||||
: x (x_)
|
||||
, y (y_)
|
||||
, z (z_)
|
||||
{}
|
||||
|
||||
inline static vector_3d_base<T> min()
|
||||
{
|
||||
return {std::numeric_limits<T>::lowest(), std::numeric_limits<T>::lowest(), std::numeric_limits<T>::lowest()};
|
||||
}
|
||||
inline static vector_3d_base<T> max()
|
||||
{
|
||||
return {std::numeric_limits<T>::max(), std::numeric_limits<T>::max(), std::numeric_limits<T>::max()};
|
||||
}
|
||||
|
||||
vector_3d_base<T> (vector_3d_base<T> const&) = default;
|
||||
vector_3d_base<T> (vector_3d_base<T>&&) = default;
|
||||
vector_3d_base<T>& operator= (vector_3d_base<T> const&) = default;
|
||||
vector_3d_base<T>& operator= (vector_3d_base<T>&&) = default;
|
||||
|
||||
inline vector_3d_base<T> operator+ (const vector_3d_base<T> &v) const
|
||||
{
|
||||
return vector_3d_base<T> (x + v.x, y + v.y, z + v.z);
|
||||
}
|
||||
|
||||
inline vector_3d_base<T> operator- (const vector_3d_base<T> &v) const
|
||||
{
|
||||
return vector_3d_base<T> (x - v.x, y - v.y, z - v.z);
|
||||
}
|
||||
|
||||
inline vector_3d_base<T> operator-() const
|
||||
{
|
||||
return vector_3d_base<T> (-x, -y, -z);
|
||||
}
|
||||
|
||||
inline T operator* (const vector_3d_base<T> &v) const
|
||||
{
|
||||
return x * v.x + y * v.y + z * v.z;
|
||||
}
|
||||
|
||||
inline T operator/ (const vector_3d_base<T>& v) const
|
||||
{
|
||||
return x / v.x + y / v.y + z / v.z;
|
||||
}
|
||||
|
||||
inline vector_3d_base<T> operator* (const T& d) const
|
||||
{
|
||||
return vector_3d_base<T> (x * d, y * d, z * d);
|
||||
}
|
||||
|
||||
inline vector_3d_base<T> operator/ (const T& d) const
|
||||
{
|
||||
return vector_3d_base<T>(x / d, y / d, z / d);
|
||||
}
|
||||
|
||||
friend vector_3d_base<T> operator* (const T& d, const vector_3d_base<T>& v)
|
||||
{
|
||||
return v * d;
|
||||
}
|
||||
|
||||
friend vector_3d_base<T> operator/ (const T& d, const vector_3d_base<T>& v)
|
||||
{
|
||||
return v / d;
|
||||
}
|
||||
|
||||
inline vector_3d_base<T> operator% (const vector_3d_base<T>& v) const
|
||||
{
|
||||
return vector_3d_base<T> ( y * v.z - z * v.y
|
||||
, z * v.x - x * v.z
|
||||
, x * v.y - y * v.x
|
||||
);
|
||||
}
|
||||
|
||||
inline vector_3d_base<T>& operator+= (const vector_3d_base<T>& v)
|
||||
{
|
||||
x += v.x;
|
||||
y += v.y;
|
||||
z += v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline vector_3d_base<T>& operator-= (const vector_3d_base<T>& v)
|
||||
{
|
||||
x -= v.x;
|
||||
y -= v.y;
|
||||
z -= v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline vector_3d_base<T>& operator*= (T d)
|
||||
{
|
||||
x *= d;
|
||||
y *= d;
|
||||
z *= d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline vector_3d_base<T>& operator/= (T d)
|
||||
{
|
||||
x /= d;
|
||||
y /= d;
|
||||
z /= d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline T length_squared() const
|
||||
{
|
||||
return x * x + y * y + z * z;
|
||||
}
|
||||
|
||||
inline T length() const
|
||||
{
|
||||
return std::sqrt (length_squared());
|
||||
}
|
||||
|
||||
inline vector_3d_base<T>& normalize()
|
||||
{
|
||||
return operator *= (1.0f / length());
|
||||
}
|
||||
|
||||
vector_3d_base<T> normalized() const
|
||||
{
|
||||
return *this * (1.0f / length());
|
||||
}
|
||||
|
||||
inline operator T*()
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
inline operator const T*() const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
inline bool is_inside_of (const vector_3d_base<T>& a, const vector_3d_base<T>& b ) const
|
||||
{
|
||||
return a.x < x && b.x > x
|
||||
&& a.y < y && b.y > y
|
||||
&& a.z < z && b.z > z;
|
||||
}
|
||||
|
||||
bool operator== (vector_3d_base<T> const& rhs) const
|
||||
{
|
||||
return std::tie (x, y, z) == std::tie (rhs.x, rhs.y, rhs.z);
|
||||
}
|
||||
friend std::ostream& operator<< (std::ostream& os, vector_3d_base<T> const& x)
|
||||
{
|
||||
return os << x.x << ", " << x.y << ", " << x.z;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline vector_3d_base<T> min (vector_3d_base<T> const& lhs, vector_3d_base<T> const& rhs)
|
||||
{
|
||||
return { std::min (lhs.x, rhs.x)
|
||||
, std::min (lhs.y, rhs.y)
|
||||
, std::min (lhs.z, rhs.z)
|
||||
};
|
||||
}
|
||||
template<typename T>
|
||||
inline vector_3d_base<T> max (vector_3d_base<T> const& lhs, vector_3d_base<T> const& rhs)
|
||||
{
|
||||
return { std::max (lhs.x, rhs.x)
|
||||
, std::max (lhs.y, rhs.y)
|
||||
, std::max (lhs.z, rhs.z)
|
||||
};
|
||||
}
|
||||
|
||||
struct vector_3d : public vector_3d_base<float>
|
||||
{
|
||||
public:
|
||||
using vector_3d_base<float>::vector_3d_base;
|
||||
vector_3d (vector_3d_base<float> x) : vector_3d_base<float> (std::move (x)) {}
|
||||
vector_3d() : vector_3d_base<float>() {}
|
||||
};
|
||||
|
||||
|
||||
template<typename Fun>
|
||||
std::vector<math::vector_3d> apply
|
||||
(Fun&& fun, std::vector<math::vector_3d> points)
|
||||
{
|
||||
for (auto& point : points)
|
||||
{
|
||||
point = fun (point);
|
||||
}
|
||||
return points;
|
||||
}
|
||||
}
|
||||
113
src/math/vector_4d.hpp
Normal file
113
src/math/vector_4d.hpp
Normal file
@@ -0,0 +1,113 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math/vector_3d.hpp>
|
||||
|
||||
namespace math
|
||||
{
|
||||
struct vector_4d
|
||||
{
|
||||
union
|
||||
{
|
||||
float _data[4];
|
||||
struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
};
|
||||
};
|
||||
|
||||
vector_4d() : vector_4d (0.f, 0.f, 0.f, 0.f) {}
|
||||
vector_4d (float x_, float y_, float z_, float w_)
|
||||
: x (x_)
|
||||
, y (y_)
|
||||
, z (z_)
|
||||
, w (w_)
|
||||
{ }
|
||||
|
||||
vector_4d (const vector_4d& v)
|
||||
: x (v.x)
|
||||
, y (v.y)
|
||||
, z (v.z)
|
||||
, w (v.w)
|
||||
{ }
|
||||
|
||||
vector_4d (const ::math::vector_3d& v, const float w)
|
||||
: x (v.x)
|
||||
, y (v.y)
|
||||
, z (v.z)
|
||||
, w (w)
|
||||
{ }
|
||||
|
||||
vector_4d& operator= (const vector_4d &v)
|
||||
{
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
w = v.w;
|
||||
return *this;
|
||||
}
|
||||
|
||||
vector_3d xyz() const
|
||||
{
|
||||
return vector_3d (x, y, z);
|
||||
}
|
||||
const vector_3d& xyz (const vector_3d& xyz_)
|
||||
{
|
||||
x = xyz_.x;
|
||||
y = xyz_.y;
|
||||
z = xyz_.z;
|
||||
return xyz_;
|
||||
}
|
||||
vector_3d xyz_normalized_by_w() const
|
||||
{
|
||||
return vector_3d (x / w, y / w, z / w);
|
||||
}
|
||||
|
||||
vector_4d operator+ (const vector_4d &v) const
|
||||
{
|
||||
return vector_4d (x + v.x, y + v.y, z + v.z, w + v.w);
|
||||
}
|
||||
|
||||
vector_4d operator- (const vector_4d &v) const
|
||||
{
|
||||
return vector_4d (x - v.x, y - v.y, z - v.z, w - v.w);
|
||||
}
|
||||
|
||||
vector_4d operator* (float d) const
|
||||
{
|
||||
return vector_4d (x * d, y * d, z * d, w * d);
|
||||
}
|
||||
|
||||
float operator* (const vector_4d& v) const
|
||||
{
|
||||
return x * v.x + y * v.y + z * v.z + w * v.w;
|
||||
}
|
||||
|
||||
vector_4d& operator*= (float d)
|
||||
{
|
||||
x *= d;
|
||||
y *= d;
|
||||
z *= d;
|
||||
w *= d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
vector_4d& normalize()
|
||||
{
|
||||
return operator *= (1.0f / std::sqrt (x * x + y * y + z * z + w * w));
|
||||
}
|
||||
|
||||
operator const float*() const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
operator float*()
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
};
|
||||
}
|
||||
77
src/mysql/mysql.cpp
Normal file
77
src/mysql/mysql.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#include <mysql/mysql.h>
|
||||
#include <noggit/world.h>
|
||||
|
||||
#include <QtCore/QSettings>
|
||||
|
||||
#include <cppconn/driver.h>
|
||||
#include <cppconn/prepared_statement.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
std::unique_ptr<sql::Connection> connect()
|
||||
{
|
||||
QSettings settings;
|
||||
std::unique_ptr<sql::Connection> Con
|
||||
(get_driver_instance()->connect
|
||||
( settings.value("project/mysql/server").toString().toStdString()
|
||||
, settings.value("project/mysql/user").toString().toStdString()
|
||||
, settings.value("project/mysql/pwd").toString().toStdString()
|
||||
)
|
||||
);
|
||||
Con->setSchema(settings.value("project/mysql/db").toString().toStdString());
|
||||
|
||||
return Con;
|
||||
}
|
||||
}
|
||||
|
||||
namespace mysql
|
||||
{
|
||||
bool hasMaxUIDStoredDB(std::size_t mapID)
|
||||
{
|
||||
auto Con(connect());
|
||||
std::unique_ptr<sql::PreparedStatement> pstmt(Con->prepareStatement("SELECT * FROM UIDs WHERE MapId=(?)"));
|
||||
pstmt->setInt(1, mapID);
|
||||
std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());
|
||||
return res->rowsCount();
|
||||
}
|
||||
|
||||
std::uint32_t getGUIDFromDB(std::size_t mapID)
|
||||
{
|
||||
auto Con(connect());
|
||||
std::unique_ptr<sql::PreparedStatement> pstmt(Con->prepareStatement("SELECT UID FROM UIDs WHERE MapId=(?)"));
|
||||
pstmt->setInt(1, mapID);
|
||||
std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());
|
||||
|
||||
std::uint32_t highGUID(0);
|
||||
if (res->rowsCount() == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
while (res->next())
|
||||
{
|
||||
highGUID = res->getInt(1);
|
||||
}
|
||||
|
||||
return highGUID;
|
||||
}
|
||||
|
||||
void insertUIDinDB(std::size_t mapID, std::uint32_t NewUID)
|
||||
{
|
||||
auto Con(connect());
|
||||
std::unique_ptr<sql::PreparedStatement> pstmt(Con->prepareStatement("INSERT INTO UIDs SET MapId=(?), UID=(?)"));
|
||||
pstmt->setInt(1, mapID);
|
||||
pstmt->setInt(2, NewUID);
|
||||
pstmt->executeUpdate();
|
||||
}
|
||||
|
||||
void updateUIDinDB (std::size_t mapID, std::uint32_t NewUID)
|
||||
{
|
||||
auto Con(connect());
|
||||
std::unique_ptr<sql::PreparedStatement> pstmt(Con->prepareStatement("UPDATE UIDs SET UID=(?) WHERE MapId=(?)"));
|
||||
pstmt->setInt(1, NewUID);
|
||||
pstmt->setInt(2, mapID);
|
||||
pstmt->executeUpdate();
|
||||
}
|
||||
}
|
||||
14
src/mysql/mysql.h
Normal file
14
src/mysql/mysql.h
Normal file
@@ -0,0 +1,14 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstddef>
|
||||
|
||||
namespace mysql
|
||||
{
|
||||
bool hasMaxUIDStoredDB(std::size_t mapID);
|
||||
std::uint32_t getGUIDFromDB(std::size_t mapID);
|
||||
void insertUIDinDB(std::size_t mapID, std::uint32_t NewUID);
|
||||
void updateUIDinDB (std::size_t mapID, std::uint32_t NewUID);
|
||||
};
|
||||
261
src/noggit/Animated.h
Normal file
261
src/noggit/Animated.h
Normal file
@@ -0,0 +1,261 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math/quaternion.hpp>
|
||||
#include <noggit/MPQ.h>
|
||||
#include <noggit/ModelHeaders.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace Animation
|
||||
{
|
||||
namespace Interpolation
|
||||
{
|
||||
//! \todo C++0x: Change namespace to "enum class Type : int16_t", remove typedef.
|
||||
namespace Type
|
||||
{
|
||||
typedef int16_t Type_t;
|
||||
enum
|
||||
{
|
||||
NONE,
|
||||
LINEAR,
|
||||
HERMITE
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
template<class FROM, class TO>
|
||||
struct Conversion
|
||||
{
|
||||
inline TO operator()(const FROM& value)
|
||||
{
|
||||
return TO(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
inline math::quaternion Conversion<math::packed_quaternion, math::quaternion>::operator()(const math::packed_quaternion& value)
|
||||
{
|
||||
//! \todo Check if this is really correct.
|
||||
return math::quaternion(
|
||||
static_cast<float>((value.x > 0 ? value.x - 32767 : value.x + 32767) / 32767.0f),
|
||||
static_cast<float>((value.y > 0 ? value.y - 32767 : value.y + 32767) / 32767.0f),
|
||||
static_cast<float>((value.z > 0 ? value.z - 32767 : value.z + 32767) / 32767.0f),
|
||||
static_cast<float>((value.w > 0 ? value.w - 32767 : value.w + 32767) / 32767.0f));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline float Conversion<int16_t, float>::operator()(const int16_t& value)
|
||||
{
|
||||
return value / 32767.0f;
|
||||
}
|
||||
|
||||
//! \note AnimatedType is the type of data getting animated.
|
||||
//! \note DataType is the type of data stored.
|
||||
//! \note The conversion from DataType to AnimatedType is done via Animation::Conversion.
|
||||
template<class AnimatedType, class DataType = AnimatedType>
|
||||
class M2Value
|
||||
{
|
||||
private:
|
||||
typedef uint32_t TimestampType;
|
||||
typedef uint32_t AnimationIdType;
|
||||
|
||||
typedef std::vector<AnimatedType> AnimatedTypeVectorType;
|
||||
typedef std::vector<TimestampType> TimestampTypeVectorType;
|
||||
|
||||
Animation::Conversion<DataType, AnimatedType> _conversion;
|
||||
|
||||
static const int32_t NO_GLOBAL_SEQUENCE = -1;
|
||||
int32_t _globalSequenceID;
|
||||
int32_t* _globalSequences;
|
||||
|
||||
Animation::Interpolation::Type::Type_t _interpolationType;
|
||||
|
||||
std::map<AnimationIdType, TimestampTypeVectorType> times;
|
||||
std::map<AnimationIdType, AnimatedTypeVectorType> data;
|
||||
|
||||
// for nonlinear interpolations:
|
||||
std::map<AnimationIdType, AnimatedTypeVectorType> in;
|
||||
std::map<AnimationIdType, AnimatedTypeVectorType> out;
|
||||
|
||||
public:
|
||||
bool uses(AnimationIdType anim)
|
||||
{
|
||||
if (_globalSequenceID != NO_GLOBAL_SEQUENCE)
|
||||
{
|
||||
anim = AnimationIdType();
|
||||
}
|
||||
|
||||
return !data[anim].empty();
|
||||
}
|
||||
|
||||
AnimatedType getValue (AnimationIdType anim, TimestampType time, int animtime)
|
||||
{
|
||||
if (_globalSequenceID != NO_GLOBAL_SEQUENCE)
|
||||
{
|
||||
if (_globalSequences[_globalSequenceID])
|
||||
{
|
||||
time = animtime % _globalSequences[_globalSequenceID];
|
||||
}
|
||||
else
|
||||
{
|
||||
time = TimestampType();
|
||||
}
|
||||
anim = AnimationIdType();
|
||||
}
|
||||
|
||||
TimestampTypeVectorType& timestampVector = times[anim];
|
||||
AnimatedTypeVectorType& dataVector = data[anim];
|
||||
AnimatedTypeVectorType& inVector = in[anim];
|
||||
AnimatedTypeVectorType& outVector = out[anim];
|
||||
|
||||
if (dataVector.empty())
|
||||
{
|
||||
return AnimatedType();
|
||||
}
|
||||
|
||||
AnimatedType result = dataVector[0];
|
||||
|
||||
if (!timestampVector.empty())
|
||||
{
|
||||
TimestampType max_time = timestampVector.back();
|
||||
if (max_time > 0)
|
||||
{
|
||||
time %= max_time;
|
||||
}
|
||||
else
|
||||
{
|
||||
time = TimestampType();
|
||||
}
|
||||
|
||||
size_t pos = 0;
|
||||
for (size_t i = 0; i < timestampVector.size() - 1; ++i)
|
||||
{
|
||||
if (time >= timestampVector[i] && time < timestampVector[i + 1])
|
||||
{
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == timestampVector.size() - 1 || _interpolationType == Animation::Interpolation::Type::NONE)
|
||||
{
|
||||
result = dataVector[pos];
|
||||
}
|
||||
else
|
||||
{
|
||||
TimestampType t1 = timestampVector[pos];
|
||||
TimestampType t2 = timestampVector[pos + 1];
|
||||
const float percentage = (time - t1) / static_cast<float>(t2 - t1);
|
||||
|
||||
switch (_interpolationType)
|
||||
{
|
||||
case Animation::Interpolation::Type::LINEAR:
|
||||
{
|
||||
result = math::interpolation::linear (percentage, dataVector[pos], dataVector[pos + 1]);
|
||||
}
|
||||
break;
|
||||
|
||||
case Animation::Interpolation::Type::HERMITE:
|
||||
{
|
||||
result = math::interpolation::hermite(percentage, dataVector[pos], dataVector[pos + 1], inVector[pos], outVector[pos]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//! \todo Use a vector of MPQFile& for the anim files instead for safety.
|
||||
M2Value (const AnimationBlock& animationBlock, const MPQFile& file, int32_t* globalSequences, const std::vector<std::unique_ptr<MPQFile>>& animation_files = std::vector<std::unique_ptr<MPQFile>>())
|
||||
{
|
||||
assert(animationBlock.nTimes == animationBlock.nKeys);
|
||||
|
||||
_interpolationType = animationBlock.type;
|
||||
|
||||
_globalSequences = globalSequences;
|
||||
_globalSequenceID = animationBlock.seq;
|
||||
if (_globalSequenceID != NO_GLOBAL_SEQUENCE)
|
||||
{
|
||||
assert(_globalSequences && "Animation said to have global sequence, but pointer to global sequence data is nullptr");
|
||||
}
|
||||
|
||||
const AnimationBlockHeader* timestampHeaders = file.get<AnimationBlockHeader>(animationBlock.ofsTimes);
|
||||
const AnimationBlockHeader* keyHeaders = file.get<AnimationBlockHeader>(animationBlock.ofsKeys);
|
||||
|
||||
for (size_t j = 0; j < animationBlock.nTimes; ++j)
|
||||
{
|
||||
const TimestampType* timestamps = j < animation_files.size() && animation_files[j] ?
|
||||
animation_files[j]->get<TimestampType>(timestampHeaders[j].ofsEntries) :
|
||||
file.get<TimestampType>(timestampHeaders[j].ofsEntries);
|
||||
|
||||
for (size_t i = 0; i < timestampHeaders[j].nEntries; ++i)
|
||||
{
|
||||
times[j].push_back(timestamps[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < animationBlock.nKeys; ++j)
|
||||
{
|
||||
const DataType* keys = j < animation_files.size() && animation_files[j] ?
|
||||
animation_files[j]->get<DataType>(keyHeaders[j].ofsEntries) :
|
||||
file.get<DataType>(keyHeaders[j].ofsEntries);
|
||||
|
||||
switch (_interpolationType)
|
||||
{
|
||||
case Animation::Interpolation::Type::NONE:
|
||||
case Animation::Interpolation::Type::LINEAR:
|
||||
for (size_t i = 0; i < keyHeaders[j].nEntries; ++i)
|
||||
{
|
||||
data[j].push_back(_conversion(keys[i]));
|
||||
}
|
||||
break;
|
||||
|
||||
case Animation::Interpolation::Type::HERMITE:
|
||||
for (size_t i = 0; i < keyHeaders[j].nEntries; ++i)
|
||||
{
|
||||
data[j].push_back(_conversion(keys[i * 3]));
|
||||
in[j].push_back(_conversion(keys[i * 3 + 1]));
|
||||
out[j].push_back(_conversion(keys[i * 3 + 2]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void apply(AnimatedType function(const AnimatedType))
|
||||
{
|
||||
switch (_interpolationType)
|
||||
{
|
||||
case Animation::Interpolation::Type::NONE:
|
||||
case Animation::Interpolation::Type::LINEAR:
|
||||
for (size_t i = 0; i < data.size(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < data[i].size(); ++j)
|
||||
{
|
||||
data[i][j] = function(data[i][j]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Animation::Interpolation::Type::HERMITE:
|
||||
for (size_t i = 0; i < data.size(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < data[i].size(); ++j)
|
||||
{
|
||||
data[i][j] = function(data[i][j]);
|
||||
in[i][j] = function(in[i][j]);
|
||||
out[i][j] = function(out[i][j]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
137
src/noggit/AsyncLoader.cpp
Normal file
137
src/noggit/AsyncLoader.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#include <noggit/AsyncLoader.h>
|
||||
#include <noggit/errorHandling.h>
|
||||
|
||||
#include <QtCore/QSettings>
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
|
||||
void AsyncLoader::process()
|
||||
{
|
||||
AsyncObject* object = nullptr;
|
||||
|
||||
QSettings settings;
|
||||
bool additional_log = settings.value("additional_file_loading_log", false).toBool();
|
||||
|
||||
while (!_stop)
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lock (_guard);
|
||||
|
||||
_state_changed.wait
|
||||
( lock
|
||||
, [&]
|
||||
{
|
||||
return !!_stop || std::any_of ( _to_load.begin(), _to_load.end()
|
||||
, [](auto const& to_load) { return !to_load.empty(); }
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
if (_stop)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& to_load : _to_load)
|
||||
{
|
||||
if (to_load.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
object = to_load.front();
|
||||
_currently_loading.emplace_back (object);
|
||||
to_load.pop_front();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (additional_log)
|
||||
{
|
||||
std::lock_guard<std::mutex> const lock(_guard);
|
||||
LogDebug << "Loading '" << object->filename << "'" << std::endl;
|
||||
}
|
||||
|
||||
object->finishLoading();
|
||||
|
||||
if (additional_log)
|
||||
{
|
||||
std::lock_guard<std::mutex> const lock(_guard);
|
||||
LogDebug << "Loaded '" << object->filename << "'" << std::endl;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> const lock (_guard);
|
||||
_currently_loading.remove (object);
|
||||
_state_changed.notify_all();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::lock_guard<std::mutex> const lock(_guard);
|
||||
object->error_on_loading();
|
||||
|
||||
if (object->is_required_when_saving())
|
||||
{
|
||||
_important_object_failed_loading = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncLoader::queue_for_load (AsyncObject* object)
|
||||
{
|
||||
std::lock_guard<std::mutex> const lock (_guard);
|
||||
_to_load[(size_t)object->loading_priority()].push_back (object);
|
||||
_state_changed.notify_one();
|
||||
}
|
||||
|
||||
void AsyncLoader::ensure_deletable (AsyncObject* object)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock (_guard);
|
||||
_state_changed.wait
|
||||
( lock
|
||||
, [&]
|
||||
{
|
||||
auto& to_load = _to_load[(size_t)object->loading_priority()];
|
||||
auto const& it = std::find (to_load.begin(), to_load.end(), object);
|
||||
|
||||
// don't load it if it's just to delete it afterward
|
||||
if (it != to_load.end())
|
||||
{
|
||||
to_load.erase(it);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::find (_currently_loading.begin(), _currently_loading.end(), object) == _currently_loading.end();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
AsyncLoader::AsyncLoader(int numThreads)
|
||||
: _stop (false)
|
||||
{
|
||||
for (int i = 0; i < numThreads; ++i)
|
||||
{
|
||||
_threads.emplace_back (&AsyncLoader::process, this);
|
||||
}
|
||||
}
|
||||
|
||||
AsyncLoader::~AsyncLoader()
|
||||
{
|
||||
_stop = true;
|
||||
_state_changed.notify_all();
|
||||
|
||||
for (auto& thread : _threads)
|
||||
{
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
45
src/noggit/AsyncLoader.h
Normal file
45
src/noggit/AsyncLoader.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <noggit/AsyncObject.h>
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
class AsyncLoader
|
||||
{
|
||||
public:
|
||||
static AsyncLoader& instance()
|
||||
{
|
||||
static AsyncLoader async_loader(2);
|
||||
return async_loader;
|
||||
}
|
||||
|
||||
//! Ownership is _not_ transferred. Call ensure_deletable to ensure
|
||||
//! that a previously enqueued object can be destroyed.
|
||||
void queue_for_load (AsyncObject*);
|
||||
|
||||
void ensure_deletable (AsyncObject*);
|
||||
|
||||
AsyncLoader(int numThreads);
|
||||
~AsyncLoader();
|
||||
|
||||
bool important_object_failed_loading() const { return _important_object_failed_loading; }
|
||||
void reset_object_fail() { _important_object_failed_loading = false; }
|
||||
|
||||
private:
|
||||
void process();
|
||||
|
||||
std::mutex _guard;
|
||||
std::condition_variable _state_changed;
|
||||
std::atomic<bool> _stop;
|
||||
std::array<std::list<AsyncObject*>, (size_t)async_priority::count> _to_load;
|
||||
std::list<AsyncObject*> _currently_loading;
|
||||
std::list<std::thread> _threads;
|
||||
bool _important_object_failed_loading = false;
|
||||
};
|
||||
84
src/noggit/AsyncObject.h
Normal file
84
src/noggit/AsyncObject.h
Normal file
@@ -0,0 +1,84 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <noggit/Log.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
enum class async_priority : int
|
||||
{
|
||||
high,
|
||||
medium,
|
||||
low,
|
||||
count
|
||||
};
|
||||
|
||||
class AsyncObject
|
||||
{
|
||||
private:
|
||||
bool _loading_failed = false;
|
||||
protected:
|
||||
std::atomic<bool> finished = {false};
|
||||
std::mutex _mutex;
|
||||
std::condition_variable _state_changed;
|
||||
|
||||
AsyncObject(std::string filename) : filename(filename) {}
|
||||
|
||||
public:
|
||||
std::string const filename;
|
||||
|
||||
AsyncObject() = delete;
|
||||
virtual ~AsyncObject() = default;
|
||||
|
||||
virtual bool finishedLoading() const
|
||||
{
|
||||
return finished.load();
|
||||
}
|
||||
|
||||
bool loading_failed() const
|
||||
{
|
||||
return _loading_failed;
|
||||
}
|
||||
|
||||
void wait_until_loaded()
|
||||
{
|
||||
if (finished.load())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock (_mutex);
|
||||
|
||||
_state_changed.wait
|
||||
( lock
|
||||
, [&]
|
||||
{
|
||||
return finished.load();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void error_on_loading()
|
||||
{
|
||||
LogError << filename << " could not be loaded" << std::endl;
|
||||
_loading_failed = true;
|
||||
finished = true;
|
||||
_state_changed.notify_all();
|
||||
}
|
||||
|
||||
virtual bool is_required_when_saving() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual async_priority loading_priority() const
|
||||
{
|
||||
return async_priority::medium;
|
||||
}
|
||||
|
||||
virtual void finishLoading() = 0;
|
||||
};
|
||||
40
src/noggit/Brush.cpp
Normal file
40
src/noggit/Brush.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#include <noggit/Brush.h>
|
||||
|
||||
void Brush::init()
|
||||
{
|
||||
radius = 15;
|
||||
hardness = 0.5f;
|
||||
iradius = hardness * radius;
|
||||
oradius = radius - iradius;
|
||||
}
|
||||
|
||||
void Brush::setHardness(float H)
|
||||
{
|
||||
hardness = H;
|
||||
iradius = hardness * radius;
|
||||
oradius = radius - iradius;
|
||||
}
|
||||
void Brush::setRadius(float R)
|
||||
{
|
||||
radius = R;
|
||||
iradius = hardness * radius;
|
||||
oradius = radius - iradius;
|
||||
}
|
||||
float Brush::getHardness() const
|
||||
{
|
||||
return hardness;
|
||||
}
|
||||
float Brush::getRadius() const
|
||||
{
|
||||
return radius;
|
||||
}
|
||||
float Brush::getValue(float dist) const
|
||||
{
|
||||
if (dist > radius)
|
||||
return 0.0f;
|
||||
if (dist < iradius)
|
||||
return 1.0f;
|
||||
return(1.0f - (dist - iradius) / oradius);
|
||||
}
|
||||
20
src/noggit/Brush.h
Normal file
20
src/noggit/Brush.h
Normal file
@@ -0,0 +1,20 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
class Brush
|
||||
{
|
||||
private:
|
||||
float hardness;
|
||||
float iradius;
|
||||
float oradius;
|
||||
float radius;
|
||||
|
||||
public:
|
||||
void setHardness(float H);
|
||||
void setRadius(float R);
|
||||
float getHardness() const;
|
||||
float getRadius() const;
|
||||
float getValue(float dist) const;
|
||||
void init();
|
||||
};
|
||||
341
src/noggit/ChunkWater.cpp
Normal file
341
src/noggit/ChunkWater.cpp
Normal file
@@ -0,0 +1,341 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#include <noggit/ChunkWater.hpp>
|
||||
#include <noggit/liquid_layer.hpp>
|
||||
#include <noggit/MPQ.h>
|
||||
#include <noggit/MapChunk.h>
|
||||
#include <noggit/Misc.h>
|
||||
|
||||
ChunkWater::ChunkWater(float x, float z, bool use_mclq_green_lava)
|
||||
: xbase(x)
|
||||
, zbase(z)
|
||||
, vmin(x, 0.f, z)
|
||||
, vmax(x + CHUNKSIZE, 0.f, z + CHUNKSIZE)
|
||||
, _use_mclq_green_lava(use_mclq_green_lava)
|
||||
{
|
||||
}
|
||||
|
||||
void ChunkWater::from_mclq(std::vector<mclq>& layers)
|
||||
{
|
||||
math::vector_3d pos(xbase, 0.0f, zbase);
|
||||
|
||||
for (mclq& liquid : layers)
|
||||
{
|
||||
std::uint8_t mclq_liquid_type = 0;
|
||||
|
||||
for (int z = 0; z < 8; ++z)
|
||||
{
|
||||
for (int x = 0; x < 8; ++x)
|
||||
{
|
||||
mclq_tile const& tile = liquid.tiles[z * 8 + x];
|
||||
|
||||
misc::bit_or(Render.fishable, x, z, tile.fishable);
|
||||
misc::bit_or(Render.fatigue, x, z, tile.fatigue);
|
||||
|
||||
if (!tile.dont_render)
|
||||
{
|
||||
mclq_liquid_type = tile.liquid_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (mclq_liquid_type)
|
||||
{
|
||||
case 1:_layers.emplace_back(pos, liquid, 2); break;
|
||||
case 3:_layers.emplace_back(pos, liquid, 4); break;
|
||||
case 4:_layers.emplace_back(pos, liquid, 1); break;
|
||||
case 6:_layers.emplace_back(pos, liquid, (_use_mclq_green_lava ? 15 : 3)); break;
|
||||
default:
|
||||
LogError << "Invalid/unhandled MCLQ liquid type" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
update_layers();
|
||||
}
|
||||
|
||||
void ChunkWater::fromFile(MPQFile &f, size_t basePos)
|
||||
{
|
||||
MH2O_Header header;
|
||||
f.read(&header, sizeof(MH2O_Header));
|
||||
|
||||
if (!header.nLayers)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//render
|
||||
if (header.ofsRenderMask)
|
||||
{
|
||||
f.seek(basePos + header.ofsRenderMask + sizeof(MH2O_Render));
|
||||
f.read(&Render, sizeof(MH2O_Render));
|
||||
}
|
||||
|
||||
for (std::size_t k = 0; k < header.nLayers; ++k)
|
||||
{
|
||||
MH2O_Information info;
|
||||
uint64_t infoMask = 0xFFFFFFFFFFFFFFFF; // default = all water
|
||||
|
||||
//info
|
||||
f.seek(basePos + header.ofsInformation + sizeof(MH2O_Information)* k);
|
||||
f.read(&info, sizeof(MH2O_Information));
|
||||
|
||||
//mask
|
||||
if (info.ofsInfoMask > 0 && info.height > 0)
|
||||
{
|
||||
size_t bitmask_size = static_cast<size_t>(std::ceil(info.height * info.width / 8.0f));
|
||||
|
||||
f.seek(info.ofsInfoMask + basePos);
|
||||
// only read the relevant data
|
||||
f.read(&infoMask, bitmask_size);
|
||||
}
|
||||
|
||||
math::vector_3d pos(xbase, 0.0f, zbase);
|
||||
_layers.emplace_back(f, basePos, pos, info, infoMask);
|
||||
}
|
||||
|
||||
update_layers();
|
||||
}
|
||||
|
||||
|
||||
void ChunkWater::save(sExtendableArray& adt, int base_pos, int& header_pos, int& current_pos)
|
||||
{
|
||||
MH2O_Header header;
|
||||
|
||||
// remove empty layers
|
||||
cleanup();
|
||||
|
||||
if (hasData(0))
|
||||
{
|
||||
header.nLayers = _layers.size();
|
||||
header.ofsRenderMask = current_pos - base_pos;
|
||||
adt.Insert(current_pos, sizeof(MH2O_Render), reinterpret_cast<char*>(&Render));
|
||||
current_pos += sizeof(MH2O_Render);
|
||||
|
||||
header.ofsInformation = current_pos - base_pos;
|
||||
int info_pos = current_pos;
|
||||
|
||||
std::size_t info_size = sizeof(MH2O_Information) * _layers.size();
|
||||
current_pos += info_size;
|
||||
|
||||
adt.Extend(info_size);
|
||||
|
||||
for (liquid_layer& layer : _layers)
|
||||
{
|
||||
layer.save(adt, base_pos, info_pos, current_pos);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(adt.GetPointer<char>(header_pos), &header, sizeof(MH2O_Header));
|
||||
header_pos += sizeof(MH2O_Header);
|
||||
}
|
||||
|
||||
|
||||
void ChunkWater::autoGen(MapChunk *chunk, float factor)
|
||||
{
|
||||
for (liquid_layer& layer : _layers)
|
||||
{
|
||||
layer.update_opacity(chunk, factor);
|
||||
}
|
||||
update_layers();
|
||||
}
|
||||
|
||||
|
||||
void ChunkWater::CropWater(MapChunk* chunkTerrain)
|
||||
{
|
||||
for (liquid_layer& layer : _layers)
|
||||
{
|
||||
layer.crop(chunkTerrain);
|
||||
}
|
||||
update_layers();
|
||||
}
|
||||
|
||||
int ChunkWater::getType(size_t layer) const
|
||||
{
|
||||
return hasData(layer) ? _layers[layer].liquidID() : 0;
|
||||
}
|
||||
|
||||
void ChunkWater::setType(int type, size_t layer)
|
||||
{
|
||||
if(hasData(layer))
|
||||
{
|
||||
_layers[layer].changeLiquidID(type);
|
||||
}
|
||||
}
|
||||
|
||||
void ChunkWater::draw ( math::frustum const& frustum
|
||||
, const float& cull_distance
|
||||
, const math::vector_3d& camera
|
||||
, bool camera_moved
|
||||
, liquid_render& render
|
||||
, opengl::scoped::use_program& water_shader
|
||||
, int animtime
|
||||
, int layer
|
||||
, display_mode display
|
||||
)
|
||||
{
|
||||
if (!is_visible (cull_distance, frustum, camera, display))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (layer == -1)
|
||||
{
|
||||
for (liquid_layer& lq_layer : _layers)
|
||||
{
|
||||
lq_layer.draw (render, water_shader, camera, camera_moved, animtime);
|
||||
}
|
||||
}
|
||||
else if (layer < _layers.size())
|
||||
{
|
||||
_layers[layer].draw (render, water_shader, camera, camera_moved, animtime);
|
||||
}
|
||||
}
|
||||
|
||||
bool ChunkWater::is_visible ( const float& cull_distance
|
||||
, const math::frustum& frustum
|
||||
, const math::vector_3d& camera
|
||||
, display_mode display
|
||||
) const
|
||||
{
|
||||
static const float chunk_radius = std::sqrt (CHUNKSIZE * CHUNKSIZE / 2.0f);
|
||||
|
||||
float dist = display == display_mode::in_3D
|
||||
? (camera - vcenter).length() - chunk_radius
|
||||
: std::abs(camera.y - vmax.y);
|
||||
|
||||
return frustum.intersects (_intersect_points)
|
||||
&& dist < cull_distance;
|
||||
}
|
||||
|
||||
void ChunkWater::update_layers()
|
||||
{
|
||||
for (liquid_layer& layer : _layers)
|
||||
{
|
||||
layer.update_indices();
|
||||
vmin.y = std::min (vmin.y, layer.min());
|
||||
vmax.y = std::max (vmax.y, layer.max());
|
||||
}
|
||||
|
||||
vcenter = (vmin + vmax) * 0.5f;
|
||||
|
||||
_intersect_points.clear();
|
||||
_intersect_points = misc::intersection_points(vmin, vmax);
|
||||
}
|
||||
|
||||
bool ChunkWater::hasData(size_t layer) const
|
||||
{
|
||||
return _layers.size() > layer;
|
||||
}
|
||||
|
||||
|
||||
void ChunkWater::paintLiquid( math::vector_3d const& pos
|
||||
, float radius
|
||||
, int liquid_id
|
||||
, bool add
|
||||
, math::radians const& angle
|
||||
, math::radians const& orientation
|
||||
, bool lock
|
||||
, math::vector_3d const& origin
|
||||
, bool override_height
|
||||
, bool override_liquid_id
|
||||
, MapChunk* chunk
|
||||
, float opacity_factor
|
||||
)
|
||||
{
|
||||
if (override_liquid_id && !override_height)
|
||||
{
|
||||
bool layer_found = false;
|
||||
for (liquid_layer& layer : _layers)
|
||||
{
|
||||
if (layer.liquidID() == liquid_id)
|
||||
{
|
||||
copy_height_to_layer(layer, pos, radius);
|
||||
layer_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!layer_found)
|
||||
{
|
||||
liquid_layer layer(math::vector_3d(xbase, 0.0f, zbase), pos.y, liquid_id);
|
||||
copy_height_to_layer(layer, pos, radius);
|
||||
_layers.push_back(layer);
|
||||
}
|
||||
}
|
||||
|
||||
bool painted = false;
|
||||
for (liquid_layer& layer : _layers)
|
||||
{
|
||||
// remove the water on all layers or paint the layer with selected id
|
||||
if (!add || layer.liquidID() == liquid_id || !override_liquid_id)
|
||||
{
|
||||
layer.paintLiquid(pos, radius, add, angle, orientation, lock, origin, override_height, chunk, opacity_factor);
|
||||
painted = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
layer.paintLiquid(pos, radius, false, angle, orientation, lock, origin, override_height, chunk, opacity_factor);
|
||||
}
|
||||
}
|
||||
|
||||
cleanup();
|
||||
|
||||
if (!add || painted)
|
||||
{
|
||||
update_layers();
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasData(0))
|
||||
{
|
||||
liquid_layer layer(_layers[0]);
|
||||
layer.clear(); // remove the liquid to not override the other layer
|
||||
layer.paintLiquid(pos, radius, true, angle, orientation, lock, origin, override_height, chunk, opacity_factor);
|
||||
layer.changeLiquidID(liquid_id);
|
||||
_layers.push_back(layer);
|
||||
}
|
||||
else
|
||||
{
|
||||
liquid_layer layer(math::vector_3d(xbase, 0.0f, zbase), pos.y, liquid_id);
|
||||
layer.paintLiquid(pos, radius, true, angle, orientation, lock, origin, override_height, chunk, opacity_factor);
|
||||
_layers.push_back(layer);
|
||||
}
|
||||
|
||||
update_layers();
|
||||
}
|
||||
|
||||
void ChunkWater::cleanup()
|
||||
{
|
||||
for (int i = _layers.size() - 1; i >= 0; --i)
|
||||
{
|
||||
if (_layers[i].empty())
|
||||
{
|
||||
_layers.erase(_layers.begin() + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChunkWater::copy_height_to_layer(liquid_layer& target, math::vector_3d const& pos, float radius)
|
||||
{
|
||||
for (liquid_layer& layer : _layers)
|
||||
{
|
||||
if (layer.liquidID() == target.liquidID())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int z = 0; z < 8; ++z)
|
||||
{
|
||||
for (int x = 0; x < 8; ++x)
|
||||
{
|
||||
if (misc::getShortestDist(pos.x, pos.z, xbase + x*UNITSIZE, zbase + z*UNITSIZE, UNITSIZE) <= radius)
|
||||
{
|
||||
if (layer.hasSubchunk(x, z))
|
||||
{
|
||||
target.copy_subchunk_height(x, z, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
91
src/noggit/ChunkWater.hpp
Normal file
91
src/noggit/ChunkWater.hpp
Normal file
@@ -0,0 +1,91 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math/frustum.hpp>
|
||||
#include <math/vector_3d.hpp>
|
||||
#include <noggit/liquid_layer.hpp>
|
||||
#include <noggit/MapHeaders.h>
|
||||
#include <noggit/tool_enums.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
class MPQFile;
|
||||
class sExtendableArray;
|
||||
class MapChunk;
|
||||
|
||||
class ChunkWater
|
||||
{
|
||||
public:
|
||||
ChunkWater() = delete;
|
||||
explicit ChunkWater(float x, float z, bool use_mclq_green_lava);
|
||||
|
||||
ChunkWater (ChunkWater const&) = delete;
|
||||
ChunkWater (ChunkWater&&) = delete;
|
||||
ChunkWater& operator= (ChunkWater const&) = delete;
|
||||
ChunkWater& operator= (ChunkWater&&) = delete;
|
||||
|
||||
void from_mclq(std::vector<mclq>& layers);
|
||||
void fromFile(MPQFile &f, size_t basePos);
|
||||
void save(sExtendableArray& adt, int base_pos, int& header_pos, int& current_pos);
|
||||
|
||||
void draw ( math::frustum const& frustum
|
||||
, const float& cull_distance
|
||||
, const math::vector_3d& camera
|
||||
, bool camera_moved
|
||||
, liquid_render& render
|
||||
, opengl::scoped::use_program& water_shader
|
||||
, int animtime
|
||||
, int layer
|
||||
, display_mode display
|
||||
);
|
||||
|
||||
bool is_visible ( const float& cull_distance
|
||||
, const math::frustum& frustum
|
||||
, const math::vector_3d& camera
|
||||
, display_mode display
|
||||
) const;
|
||||
|
||||
void autoGen(MapChunk* chunk, float factor);
|
||||
void CropWater(MapChunk* chunkTerrain);
|
||||
|
||||
void setType(int type, size_t layer);
|
||||
int getType(size_t layer) const;
|
||||
bool hasData(size_t layer) const;
|
||||
|
||||
void paintLiquid( math::vector_3d const& pos
|
||||
, float radius
|
||||
, int liquid_id
|
||||
, bool add
|
||||
, math::radians const& angle
|
||||
, math::radians const& orientation
|
||||
, bool lock
|
||||
, math::vector_3d const& origin
|
||||
, bool override_height
|
||||
, bool override_liquid_id
|
||||
, MapChunk* chunk
|
||||
, float opacity_factor
|
||||
);
|
||||
|
||||
|
||||
float xbase, zbase;
|
||||
|
||||
private:
|
||||
std::vector<math::vector_3d> _intersect_points;
|
||||
|
||||
math::vector_3d vmin, vmax, vcenter;
|
||||
bool _use_mclq_green_lava;
|
||||
|
||||
// remove empty layers
|
||||
void cleanup();
|
||||
// update every layer's render
|
||||
void update_layers();
|
||||
|
||||
void copy_height_to_layer(liquid_layer& target, math::vector_3d const& pos, float radius);
|
||||
|
||||
|
||||
MH2O_Render Render;
|
||||
|
||||
std::vector<liquid_layer> _layers;
|
||||
};
|
||||
152
src/noggit/DBC.cpp
Normal file
152
src/noggit/DBC.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#include <noggit/DBC.h>
|
||||
#include <noggit/Log.h>
|
||||
#include <noggit/Misc.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
AreaDB gAreaDB;
|
||||
MapDB gMapDB;
|
||||
LoadingScreensDB gLoadingScreensDB;
|
||||
LightDB gLightDB;
|
||||
LightParamsDB gLightParamsDB;
|
||||
LightSkyboxDB gLightSkyboxDB;
|
||||
LightIntBandDB gLightIntBandDB;
|
||||
LightFloatBandDB gLightFloatBandDB;
|
||||
GroundEffectDoodadDB gGroundEffectDoodadDB;
|
||||
GroundEffectTextureDB gGroundEffectTextureDB;
|
||||
LiquidTypeDB gLiquidTypeDB;
|
||||
|
||||
void OpenDBs()
|
||||
{
|
||||
gAreaDB.open();
|
||||
gMapDB.open();
|
||||
gLoadingScreensDB.open();
|
||||
gLightDB.open();
|
||||
gLightParamsDB.open();
|
||||
gLightSkyboxDB.open();
|
||||
gLightIntBandDB.open();
|
||||
gLightFloatBandDB.open();
|
||||
gGroundEffectDoodadDB.open();
|
||||
gGroundEffectTextureDB.open();
|
||||
gLiquidTypeDB.open();
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string AreaDB::getAreaName(int pAreaID)
|
||||
{
|
||||
if (!pAreaID || pAreaID == -1)
|
||||
{
|
||||
return "Unknown location";
|
||||
}
|
||||
|
||||
unsigned int regionID = 0;
|
||||
std::string areaName = "";
|
||||
try
|
||||
{
|
||||
AreaDB::Record rec = gAreaDB.getByID(pAreaID);
|
||||
areaName = rec.getLocalizedString(AreaDB::Name);
|
||||
regionID = rec.getUInt(AreaDB::Region);
|
||||
}
|
||||
catch (AreaDB::NotFound)
|
||||
{
|
||||
areaName = "Unknown location";
|
||||
}
|
||||
if (regionID != 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
AreaDB::Record rec = gAreaDB.getByID(regionID);
|
||||
areaName = std::string(rec.getLocalizedString(AreaDB::Name)) + std::string(": ") + areaName;
|
||||
}
|
||||
catch (AreaDB::NotFound)
|
||||
{
|
||||
areaName = "Unknown location";
|
||||
}
|
||||
}
|
||||
|
||||
return areaName;
|
||||
}
|
||||
|
||||
std::uint32_t AreaDB::get_area_parent(int area_id)
|
||||
{
|
||||
// todo: differentiate between no parent and error ?
|
||||
if (!area_id || area_id == -1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
AreaDB::Record rec = gAreaDB.getByID(area_id);
|
||||
return rec.getUInt(AreaDB::Region);
|
||||
}
|
||||
catch (AreaDB::NotFound)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::string MapDB::getMapName(int pMapID)
|
||||
{
|
||||
if (pMapID<0) return "Unknown map";
|
||||
std::string mapName = "";
|
||||
try
|
||||
{
|
||||
MapDB::Record rec = gMapDB.getByID(pMapID);
|
||||
mapName = std::string(rec.getLocalizedString(MapDB::Name));
|
||||
}
|
||||
catch (MapDB::NotFound)
|
||||
{
|
||||
mapName = "Unknown map";
|
||||
}
|
||||
|
||||
return mapName;
|
||||
}
|
||||
|
||||
const char * getGroundEffectDoodad(unsigned int effectID, int DoodadNum)
|
||||
{
|
||||
try
|
||||
{
|
||||
unsigned int doodadId = gGroundEffectTextureDB.getByID(effectID).getUInt(GroundEffectTextureDB::Doodads + DoodadNum);
|
||||
return gGroundEffectDoodadDB.getByID(doodadId).getString(GroundEffectDoodadDB::Filename);
|
||||
}
|
||||
catch (DBCFile::NotFound)
|
||||
{
|
||||
LogError << "Tried to get a not existing row in GroundEffectTextureDB or GroundEffectDoodadDB ( effectID = " << effectID << ", DoodadNum = " << DoodadNum << " )!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int LiquidTypeDB::getLiquidType(int pID)
|
||||
{
|
||||
int type = 0;
|
||||
try
|
||||
{
|
||||
LiquidTypeDB::Record rec = gLiquidTypeDB.getByID(pID);
|
||||
type = rec.getUInt(LiquidTypeDB::Type);
|
||||
}
|
||||
catch (LiquidTypeDB::NotFound)
|
||||
{
|
||||
type = 0;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
std::string LiquidTypeDB::getLiquidName(int pID)
|
||||
{
|
||||
std::string type = "";
|
||||
try
|
||||
{
|
||||
LiquidTypeDB::Record rec = gLiquidTypeDB.getByID(pID);
|
||||
type = std::string(rec.getString(LiquidTypeDB::Name));
|
||||
}
|
||||
catch (MapDB::NotFound)
|
||||
{
|
||||
type = "Unknown type";
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
196
src/noggit/DBC.h
Normal file
196
src/noggit/DBC.h
Normal file
@@ -0,0 +1,196 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <noggit/DBCFile.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
class AreaDB : public DBCFile
|
||||
{
|
||||
public:
|
||||
AreaDB() :
|
||||
DBCFile("DBFilesClient\\AreaTable.dbc")
|
||||
{ }
|
||||
|
||||
/// Fields
|
||||
static const size_t AreaID = 0; // uint
|
||||
static const size_t Continent = 1; // uint
|
||||
static const size_t Region = 2; // uint [AreaID]
|
||||
static const size_t Flags = 4; // bit field
|
||||
static const size_t Name = 11; // localisation string
|
||||
|
||||
static std::string getAreaName(int pAreaID);
|
||||
static std::uint32_t get_area_parent(int area_id);
|
||||
};
|
||||
|
||||
class MapDB : public DBCFile
|
||||
{
|
||||
public:
|
||||
MapDB() :
|
||||
DBCFile("DBFilesClient\\Map.dbc")
|
||||
{ }
|
||||
|
||||
/// Fields
|
||||
static const size_t MapID = 0; // uint
|
||||
static const size_t InternalName = 1; // string
|
||||
static const size_t AreaType = 2; // uint
|
||||
static const size_t IsBattleground = 4; // uint
|
||||
static const size_t Name = 5; // loc
|
||||
|
||||
static const size_t LoadingScreen = 57; // uint [LoadingScreen]
|
||||
static std::string getMapName(int pMapID);
|
||||
};
|
||||
|
||||
class LoadingScreensDB : public DBCFile
|
||||
{
|
||||
public:
|
||||
LoadingScreensDB() :
|
||||
DBCFile("DBFilesClient\\LoadingScreens.dbc")
|
||||
{ }
|
||||
|
||||
/// Fields
|
||||
static const size_t ID = 0; // uint
|
||||
static const size_t Name = 1; // string
|
||||
static const size_t Path = 2; // string
|
||||
};
|
||||
|
||||
class LightDB : public DBCFile
|
||||
{
|
||||
public:
|
||||
LightDB() :
|
||||
DBCFile("DBFilesClient\\Light.dbc")
|
||||
{ }
|
||||
|
||||
/// Fields
|
||||
static const size_t ID = 0; // uint
|
||||
static const size_t Map = 1; // uint
|
||||
static const size_t PositionX = 2; // float
|
||||
static const size_t PositionY = 3; // float
|
||||
static const size_t PositionZ = 4; // float
|
||||
static const size_t RadiusInner = 5; // float
|
||||
static const size_t RadiusOuter = 6; // float
|
||||
static const size_t DataIDs = 7; // uint[8]
|
||||
};
|
||||
|
||||
class LightParamsDB : public DBCFile{
|
||||
public:
|
||||
LightParamsDB() :
|
||||
DBCFile("DBFilesClient\\LightParams.dbc")
|
||||
{ }
|
||||
|
||||
/// Fields
|
||||
static const size_t ID = 0; // uint
|
||||
static const size_t skybox = 2; // uint ref to LightSkyBox
|
||||
static const size_t water_shallow_alpha = 5;
|
||||
static const size_t water_deep_alpha = 6;
|
||||
static const size_t ocean_shallow_alpha = 7;
|
||||
static const size_t ocean_deep_alpha = 8;
|
||||
};
|
||||
|
||||
class LightSkyboxDB : public DBCFile
|
||||
{
|
||||
public:
|
||||
LightSkyboxDB() :
|
||||
DBCFile("DBFilesClient\\LightSkybox.dbc")
|
||||
{ }
|
||||
|
||||
/// Fields
|
||||
static const size_t ID = 0; // uint
|
||||
static const size_t filename = 1; // string
|
||||
static const size_t flags = 2; // uint
|
||||
};
|
||||
|
||||
class LightIntBandDB : public DBCFile
|
||||
{
|
||||
public:
|
||||
LightIntBandDB() :
|
||||
DBCFile("DBFilesClient\\LightIntBand.dbc")
|
||||
{ }
|
||||
|
||||
/// Fields
|
||||
static const size_t ID = 0; // uint
|
||||
static const size_t Entries = 1; // uint
|
||||
static const size_t Times = 2; // uint
|
||||
static const size_t Values = 18; // uint
|
||||
};
|
||||
|
||||
class LightFloatBandDB : public DBCFile
|
||||
{
|
||||
public:
|
||||
LightFloatBandDB() :
|
||||
DBCFile("DBFilesClient\\LightFloatBand.dbc")
|
||||
{ }
|
||||
|
||||
/// Fields
|
||||
static const size_t ID = 0; // uint
|
||||
static const size_t Entries = 1; // uint
|
||||
static const size_t Times = 2; // uint
|
||||
static const size_t Values = 18; // float
|
||||
};
|
||||
|
||||
class GroundEffectTextureDB : public DBCFile
|
||||
{
|
||||
public:
|
||||
GroundEffectTextureDB() :
|
||||
DBCFile("DBFilesClient\\GroundEffectTexture.dbc")
|
||||
{ }
|
||||
|
||||
/// Fields
|
||||
static const size_t ID = 0; // uint
|
||||
static const size_t Doodads = 1; // uint[4]
|
||||
static const size_t Weights = 5; // uint[4]
|
||||
static const size_t Amount = 9; // uint
|
||||
static const size_t TerrainType = 10; // uint
|
||||
};
|
||||
|
||||
class GroundEffectDoodadDB : public DBCFile
|
||||
{
|
||||
public:
|
||||
GroundEffectDoodadDB() :
|
||||
DBCFile("DBFilesClient\\GroundEffectDoodad.dbc")
|
||||
{ }
|
||||
|
||||
/// Fields
|
||||
static const size_t ID = 0; // uint
|
||||
static const size_t InternalID = 1; // uint
|
||||
static const size_t Filename = 2; // string
|
||||
};
|
||||
|
||||
class LiquidTypeDB : public DBCFile
|
||||
{
|
||||
public:
|
||||
LiquidTypeDB() :
|
||||
DBCFile("DBFilesClient\\LiquidType.dbc")
|
||||
{ }
|
||||
|
||||
/// Fields
|
||||
static const size_t ID = 0; // uint
|
||||
static const size_t Name = 1; // string
|
||||
static const size_t Type = 3; // uint
|
||||
static const size_t ShaderType = 14; // uint
|
||||
static const size_t TextureFilenames = 15; // string[6]
|
||||
static const size_t TextureTilesPerBlock = 23; // uint
|
||||
static const size_t Rotation = 24; // uint
|
||||
static const size_t AnimationX = 23; // uint
|
||||
static const size_t AnimationY = 24; // uint
|
||||
|
||||
static int getLiquidType(int pID);
|
||||
static std::string getLiquidName(int pID);
|
||||
};
|
||||
|
||||
void OpenDBs();
|
||||
|
||||
const char * getGroundEffectDoodad(unsigned int effectID, int DoodadNum);
|
||||
|
||||
extern AreaDB gAreaDB;
|
||||
extern MapDB gMapDB;
|
||||
extern LoadingScreensDB gLoadingScreensDB;
|
||||
extern LightDB gLightDB;
|
||||
extern LightParamsDB gLightParamsDB;
|
||||
extern LightSkyboxDB gLightSkyboxDB;
|
||||
extern LightIntBandDB gLightIntBandDB;
|
||||
extern LightFloatBandDB gLightFloatBandDB;
|
||||
extern GroundEffectDoodadDB gGroundEffectDoodadDB;
|
||||
extern GroundEffectTextureDB gGroundEffectTextureDB;
|
||||
extern LiquidTypeDB gLiquidTypeDB;
|
||||
45
src/noggit/DBCFile.cpp
Normal file
45
src/noggit/DBCFile.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#include <noggit/DBCFile.h>
|
||||
#include <noggit/Log.h>
|
||||
#include <noggit/MPQ.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
DBCFile::DBCFile(const std::string& _filename)
|
||||
: filename(_filename)
|
||||
{}
|
||||
|
||||
void DBCFile::open()
|
||||
{
|
||||
MPQFile f (filename);
|
||||
|
||||
if (f.isEof())
|
||||
{
|
||||
LogError << "The DBC file \"" << filename << "\" could not be opened. This application may crash soon as the file is most likely needed." << std::endl;
|
||||
return;
|
||||
}
|
||||
LogDebug << "Opening DBC \"" << filename << "\"" << std::endl;
|
||||
|
||||
char header[4];
|
||||
|
||||
f.read(header, 4); // Number of records
|
||||
assert(header[0] == 'W' && header[1] == 'D' && header[2] == 'B' && header[3] == 'C');
|
||||
f.read(&recordCount, 4);
|
||||
f.read(&fieldCount, 4);
|
||||
f.read(&recordSize, 4);
|
||||
f.read(&stringSize, 4);
|
||||
|
||||
if (fieldCount * 4 != recordSize)
|
||||
{
|
||||
throw std::logic_error ("non four-byte-columns not supported");
|
||||
}
|
||||
|
||||
data.resize (recordSize * recordCount);
|
||||
f.read (data.data(), data.size());
|
||||
|
||||
stringTable.resize (stringSize);
|
||||
f.read (stringTable.data(), stringTable.size());
|
||||
|
||||
f.close();
|
||||
}
|
||||
142
src/noggit/DBCFile.h
Normal file
142
src/noggit/DBCFile.h
Normal file
@@ -0,0 +1,142 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
||||
class DBCFile
|
||||
{
|
||||
public:
|
||||
explicit DBCFile(const std::string& filename);
|
||||
|
||||
// Open database. It must be openened before it can be used.
|
||||
void open();
|
||||
|
||||
class NotFound : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
NotFound() : std::runtime_error("Key was not found")
|
||||
{ }
|
||||
};
|
||||
|
||||
class Iterator;
|
||||
class Record
|
||||
{
|
||||
public:
|
||||
const float& getFloat(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<float*>(offset + field * 4);
|
||||
}
|
||||
const unsigned int& getUInt(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<unsigned int*>(offset + field * 4);
|
||||
}
|
||||
const int& getInt(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<int*>(offset + field * 4);
|
||||
}
|
||||
const char *getString(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
size_t stringOffset = getUInt(field);
|
||||
assert(stringOffset < file.stringSize);
|
||||
return file.stringTable.data() + stringOffset;
|
||||
}
|
||||
const char *getLocalizedString(size_t field, int locale = -1) const
|
||||
{
|
||||
int loc = locale;
|
||||
if (locale == -1)
|
||||
{
|
||||
assert(field < file.fieldCount - 8);
|
||||
for (loc = 0; loc < 9; loc++)
|
||||
{
|
||||
size_t stringOffset = getUInt(field + loc);
|
||||
if (stringOffset != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(field + loc < file.fieldCount);
|
||||
size_t stringOffset = getUInt(field + loc);
|
||||
assert(stringOffset < file.stringSize);
|
||||
return file.stringTable.data() + stringOffset;
|
||||
}
|
||||
private:
|
||||
Record(const DBCFile &pfile, unsigned char *poffset) : file(pfile), offset(poffset) {}
|
||||
const DBCFile &file;
|
||||
unsigned char *offset;
|
||||
|
||||
friend class DBCFile;
|
||||
friend class DBCFile::Iterator;
|
||||
};
|
||||
/** Iterator that iterates over records
|
||||
*/
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
Iterator(const DBCFile &file, unsigned char *offset) :
|
||||
record(file, offset) {}
|
||||
/// Advance (prefix only)
|
||||
Iterator & operator++() {
|
||||
record.offset += record.file.recordSize;
|
||||
return *this;
|
||||
}
|
||||
/// Return address of current instance
|
||||
Record const & operator*() const { return record; }
|
||||
const Record* operator->() const {
|
||||
return &record;
|
||||
}
|
||||
/// Comparison
|
||||
bool operator==(const Iterator &b) const
|
||||
{
|
||||
return record.offset == b.record.offset;
|
||||
}
|
||||
bool operator!=(const Iterator &b) const
|
||||
{
|
||||
return record.offset != b.record.offset;
|
||||
}
|
||||
private:
|
||||
Record record;
|
||||
};
|
||||
|
||||
inline Record getRecord(size_t id)
|
||||
{
|
||||
return Record(*this, data.data() + id*recordSize);
|
||||
}
|
||||
|
||||
inline Iterator begin()
|
||||
{
|
||||
return Iterator(*this, data.data());
|
||||
}
|
||||
inline Iterator end()
|
||||
{
|
||||
return Iterator(*this, data.data() + data.size());
|
||||
}
|
||||
|
||||
inline size_t getRecordCount() const { return recordCount; }
|
||||
inline size_t getFieldCount() const { return fieldCount; }
|
||||
inline Record getByID(unsigned int id, size_t field = 0)
|
||||
{
|
||||
for (Iterator i = begin(); i != end(); ++i)
|
||||
{
|
||||
if (i->getUInt(field) == id)
|
||||
return (*i);
|
||||
}
|
||||
throw NotFound();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string filename;
|
||||
size_t recordSize;
|
||||
size_t recordCount;
|
||||
size_t fieldCount;
|
||||
size_t stringSize;
|
||||
std::vector<unsigned char> data;
|
||||
std::vector<char> stringTable;
|
||||
};
|
||||
43
src/noggit/Log.cpp
Normal file
43
src/noggit/Log.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#include <noggit/Log.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
|
||||
std::ostream& _LogError(const char * pFile, int pLine)
|
||||
{
|
||||
return std::cerr << clock() * 1000 / CLOCKS_PER_SEC << " - (" << ((strrchr(pFile, '/') ? strrchr(pFile, '/') : (strrchr(pFile, '\\') ? strrchr(pFile, '\\') : pFile - 1)) + 1) << ":" << pLine << "): [Error] ";
|
||||
}
|
||||
std::ostream& _LogDebug(const char * pFile, int pLine)
|
||||
{
|
||||
return std::clog << clock() * 1000 / CLOCKS_PER_SEC << " - (" << ((strrchr(pFile, '/') ? strrchr(pFile, '/') : (strrchr(pFile, '\\') ? strrchr(pFile, '\\') : pFile - 1)) + 1) << ":" << pLine << "): [Debug] ";
|
||||
}
|
||||
std::ostream& _Log(const char * pFile, int pLine)
|
||||
{
|
||||
return std::cout << clock() * 1000 / CLOCKS_PER_SEC << " - (" << ((strrchr(pFile, '/') ? strrchr(pFile, '/') : (strrchr(pFile, '\\') ? strrchr(pFile, '\\') : pFile - 1)) + 1) << ":" << pLine << "): ";
|
||||
}
|
||||
|
||||
#if DEBUG__LOGGINGTOCONSOLE
|
||||
void InitLogging()
|
||||
{
|
||||
LogDebug << "Logging to console window." << std::endl;
|
||||
}
|
||||
#else
|
||||
namespace
|
||||
{
|
||||
std::ofstream gLogStream;
|
||||
}
|
||||
void InitLogging()
|
||||
{
|
||||
// Set up log.
|
||||
gLogStream.open("log.txt", std::ios_base::out | std::ios_base::trunc);
|
||||
if (gLogStream)
|
||||
{
|
||||
std::cout.rdbuf(gLogStream.rdbuf());
|
||||
std::clog.rdbuf(gLogStream.rdbuf());
|
||||
std::cerr.rdbuf(gLogStream.rdbuf());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
15
src/noggit/Log.h
Normal file
15
src/noggit/Log.h
Normal file
@@ -0,0 +1,15 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
|
||||
std::ostream& _LogError(const char * pFile, int pLine);
|
||||
std::ostream& _LogDebug(const char * pFile, int pLine);
|
||||
std::ostream& _Log(const char * pFile, int pLine);
|
||||
|
||||
#define LogError _LogError( __FILE__, __LINE__ )
|
||||
#define LogDebug _LogDebug( __FILE__, __LINE__ )
|
||||
#define Log _Log( __FILE__, __LINE__ )
|
||||
|
||||
void InitLogging();
|
||||
354
src/noggit/MPQ.cpp
Normal file
354
src/noggit/MPQ.cpp
Normal file
@@ -0,0 +1,354 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#include <noggit/AsyncLoader.h> // AsyncLoader
|
||||
#include <noggit/Log.h>
|
||||
#include <noggit/MPQ.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <QtCore/QSettings>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace
|
||||
{
|
||||
typedef std::pair<std::string, std::unique_ptr<MPQArchive>> ArchiveEntry;
|
||||
typedef std::list<ArchiveEntry> ArchivesMap;
|
||||
ArchivesMap _openArchives;
|
||||
|
||||
boost::mutex gListfileLoadingMutex;
|
||||
boost::mutex gMPQFileMutex;
|
||||
}
|
||||
|
||||
std::unordered_set<std::string> gListfile;
|
||||
|
||||
void MPQArchive::loadMPQ (AsyncLoader* loader, std::string const& filename, bool doListfile)
|
||||
{
|
||||
_openArchives.emplace_back (filename, std::make_unique<MPQArchive> (filename, doListfile));
|
||||
loader->queue_for_load(_openArchives.back().second.get());
|
||||
}
|
||||
|
||||
MPQArchive::MPQArchive(std::string const& filename, bool doListfile)
|
||||
: AsyncObject(filename)
|
||||
,_archiveHandle(nullptr)
|
||||
{
|
||||
if (!SFileOpenArchive (filename.c_str(), 0, MPQ_OPEN_NO_LISTFILE | STREAM_FLAG_READ_ONLY, &_archiveHandle))
|
||||
{
|
||||
LogError << "Error opening archive: " << filename << std::endl;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogDebug << "Opened archive " << filename << std::endl;
|
||||
}
|
||||
|
||||
finished = !doListfile;
|
||||
}
|
||||
|
||||
void MPQArchive::finishLoading()
|
||||
{
|
||||
if (finished)
|
||||
return;
|
||||
|
||||
HANDLE fh;
|
||||
|
||||
boost::mutex::scoped_lock lock2(gMPQFileMutex);
|
||||
boost::mutex::scoped_lock lock(gListfileLoadingMutex);
|
||||
|
||||
if (SFileOpenFileEx(_archiveHandle, "(listfile)", 0, &fh))
|
||||
{
|
||||
size_t filesize = SFileGetFileSize(fh, nullptr); //last nullptr for newer version of StormLib
|
||||
|
||||
std::vector<char> readbuffer (filesize);
|
||||
SFileReadFile(fh, readbuffer.data(), filesize, nullptr, nullptr); //last nullptrs for newer version of StormLib
|
||||
SFileCloseFile(fh);
|
||||
|
||||
std::string current;
|
||||
for (char c : readbuffer)
|
||||
{
|
||||
if (c == '\r')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (c == '\n')
|
||||
{
|
||||
gListfile.emplace (noggit::mpq::normalized_filename (current));
|
||||
current.resize (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
current += c;
|
||||
}
|
||||
}
|
||||
|
||||
if (!current.empty())
|
||||
{
|
||||
gListfile.emplace (noggit::mpq::normalized_filename (current));
|
||||
}
|
||||
}
|
||||
|
||||
finished = true;
|
||||
_state_changed.notify_all();
|
||||
|
||||
if (MPQArchive::allFinishedLoading())
|
||||
{
|
||||
LogDebug << "Completed listfile loading: " << gListfile.size() << " files\n";
|
||||
}
|
||||
}
|
||||
|
||||
MPQArchive::~MPQArchive()
|
||||
{
|
||||
if (_archiveHandle)
|
||||
SFileCloseArchive(_archiveHandle);
|
||||
}
|
||||
|
||||
bool MPQArchive::allFinishedLoading()
|
||||
{
|
||||
return std::all_of ( _openArchives.begin(), _openArchives.end()
|
||||
, [] (ArchiveEntry const& archive)
|
||||
{
|
||||
return archive.second->finishedLoading();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void MPQArchive::allFinishLoading()
|
||||
{
|
||||
for (auto& archive : _openArchives)
|
||||
{
|
||||
archive.second->finishLoading();
|
||||
}
|
||||
}
|
||||
|
||||
void MPQArchive::unloadAllMPQs()
|
||||
{
|
||||
_openArchives.clear();
|
||||
}
|
||||
|
||||
bool MPQArchive::hasFile(std::string const& filename) const
|
||||
{
|
||||
return SFileHasFile(_archiveHandle, noggit::mpq::normalized_filename_insane (filename).c_str());
|
||||
}
|
||||
|
||||
void MPQArchive::unloadMPQ(std::string const& filename)
|
||||
{
|
||||
for (auto it = _openArchives.begin(); it != _openArchives.end(); ++it)
|
||||
{
|
||||
if (it->first == filename)
|
||||
{
|
||||
_openArchives.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MPQArchive::openFile(std::string const& filename, HANDLE* fileHandle) const
|
||||
{
|
||||
assert(fileHandle);
|
||||
return SFileOpenFileEx(_archiveHandle, noggit::mpq::normalized_filename_insane (filename).c_str(), 0, fileHandle);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
boost::filesystem::path getDiskPath (std::string const& pFilename)
|
||||
{
|
||||
QSettings settings;
|
||||
return boost::filesystem::path (settings.value ("project/path").toString().toStdString())
|
||||
/ noggit::mpq::normalized_filename (pFilename);
|
||||
}
|
||||
|
||||
bool existsInMPQ (std::string const& filename)
|
||||
{
|
||||
return std::any_of ( _openArchives.begin(), _openArchives.end()
|
||||
, [&] (ArchiveEntry const& archive)
|
||||
{
|
||||
return archive.second->hasFile (filename);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* basic constructor to save the file to project path
|
||||
*/
|
||||
MPQFile::MPQFile(std::string const& filename)
|
||||
: eof(true)
|
||||
, pointer(0)
|
||||
, External(false)
|
||||
, _disk_path (getDiskPath (filename))
|
||||
{
|
||||
if (filename.empty())
|
||||
throw std::runtime_error("MPQFile: filename empty");
|
||||
|
||||
boost::mutex::scoped_lock lock(gMPQFileMutex);
|
||||
|
||||
std::ifstream input(_disk_path.string(), std::ios_base::binary | std::ios_base::in);
|
||||
if (input.is_open())
|
||||
{
|
||||
External = true;
|
||||
eof = false;
|
||||
|
||||
input.seekg(0, std::ios::end);
|
||||
buffer.resize (input.tellg());
|
||||
input.seekg(0, std::ios::beg);
|
||||
|
||||
input.read(buffer.data(), buffer.size());
|
||||
|
||||
input.close();
|
||||
return;
|
||||
}
|
||||
|
||||
for (ArchivesMap::reverse_iterator i = _openArchives.rbegin(); i != _openArchives.rend(); ++i)
|
||||
{
|
||||
HANDLE fileHandle;
|
||||
|
||||
if (!i->second->openFile(filename, &fileHandle))
|
||||
continue;
|
||||
|
||||
eof = false;
|
||||
buffer.resize (SFileGetFileSize(fileHandle, nullptr));
|
||||
SFileReadFile(fileHandle, buffer.data(), buffer.size(), nullptr, nullptr); //last nullptrs for newer version of StormLib
|
||||
SFileCloseFile(fileHandle);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw std::invalid_argument ("File '" + filename + "' does not exist.");
|
||||
}
|
||||
|
||||
MPQFile::~MPQFile()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
bool MPQFile::exists (std::string const& filename)
|
||||
{
|
||||
return existsOnDisk (filename) || existsInMPQ (filename);
|
||||
}
|
||||
bool MPQFile::existsOnDisk (std::string const& filename)
|
||||
{
|
||||
return boost::filesystem::exists (getDiskPath (filename));
|
||||
}
|
||||
|
||||
size_t MPQFile::read(void* dest, size_t bytes)
|
||||
{
|
||||
if (eof || !bytes)
|
||||
return 0;
|
||||
|
||||
size_t rpos = pointer + bytes;
|
||||
if (rpos > buffer.size()) {
|
||||
bytes = buffer.size() - pointer;
|
||||
eof = true;
|
||||
}
|
||||
|
||||
memcpy(dest, &(buffer[pointer]), bytes);
|
||||
|
||||
pointer = rpos;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
bool MPQFile::isEof() const
|
||||
{
|
||||
return eof;
|
||||
}
|
||||
|
||||
void MPQFile::seek(size_t offset)
|
||||
{
|
||||
pointer = offset;
|
||||
eof = (pointer >= buffer.size());
|
||||
}
|
||||
|
||||
void MPQFile::seekRelative(size_t offset)
|
||||
{
|
||||
pointer += offset;
|
||||
eof = (pointer >= buffer.size());
|
||||
}
|
||||
|
||||
void MPQFile::close()
|
||||
{
|
||||
eof = true;
|
||||
}
|
||||
|
||||
size_t MPQFile::getSize() const
|
||||
{
|
||||
return buffer.size();
|
||||
}
|
||||
|
||||
size_t MPQFile::getPos() const
|
||||
{
|
||||
return pointer;
|
||||
}
|
||||
|
||||
char const* MPQFile::getBuffer() const
|
||||
{
|
||||
return buffer.data();
|
||||
}
|
||||
|
||||
char const* MPQFile::getPointer() const
|
||||
{
|
||||
return buffer.data() + pointer;
|
||||
}
|
||||
|
||||
void MPQFile::SaveFile()
|
||||
{
|
||||
LogDebug << "Save file to: " << _disk_path << std::endl;
|
||||
|
||||
auto const directory_name (_disk_path.parent_path());
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::create_directories (directory_name, ec);
|
||||
if (ec)
|
||||
{
|
||||
LogError << "Creating directory \"" << directory_name << "\" failed: " << ec << ". Saving is highly likely to fail." << std::endl;
|
||||
}
|
||||
|
||||
std::ofstream output(_disk_path.string(), std::ios_base::binary | std::ios_base::out);
|
||||
if (output.is_open())
|
||||
{
|
||||
Log << "Saving file \"" << _disk_path << "\"." << std::endl;
|
||||
|
||||
output.write(buffer.data(), buffer.size());
|
||||
output.close();
|
||||
|
||||
External = true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace noggit
|
||||
{
|
||||
namespace mpq
|
||||
{
|
||||
std::string normalized_filename (std::string filename)
|
||||
{
|
||||
std::transform (filename.begin(), filename.end(), filename.begin(), ::tolower);
|
||||
std::transform ( filename.begin(), filename.end(), filename.begin()
|
||||
, [] (char c)
|
||||
{
|
||||
return c == '\\' ? '/' : c;
|
||||
}
|
||||
);
|
||||
return filename;
|
||||
}
|
||||
std::string normalized_filename_insane (std::string filename)
|
||||
{
|
||||
std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
|
||||
std::transform ( filename.begin(), filename.end(), filename.begin()
|
||||
, [] (char c)
|
||||
{
|
||||
return c == '/' ? '\\' : c;
|
||||
}
|
||||
);
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
}
|
||||
108
src/noggit/MPQ.h
Normal file
108
src/noggit/MPQ.h
Normal file
@@ -0,0 +1,108 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <noggit/AsyncObject.h>
|
||||
|
||||
#include <StormLib.h>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
class AsyncLoader;
|
||||
class MPQArchive;
|
||||
class MPQFile;
|
||||
|
||||
extern std::unordered_set<std::string> gListfile;
|
||||
|
||||
class MPQArchive : public AsyncObject
|
||||
{
|
||||
HANDLE _archiveHandle;
|
||||
|
||||
public:
|
||||
MPQArchive(const std::string& filename, bool doListfile);
|
||||
|
||||
~MPQArchive();
|
||||
|
||||
bool hasFile(const std::string& filename) const;
|
||||
bool openFile(const std::string& filename, HANDLE* fileHandle) const;
|
||||
|
||||
void finishLoading();
|
||||
|
||||
static bool allFinishedLoading();
|
||||
static void allFinishLoading();
|
||||
|
||||
static void loadMPQ (AsyncLoader*, const std::string& filename, bool doListfile = false);
|
||||
static void unloadAllMPQs();
|
||||
static void unloadMPQ(const std::string& filename);
|
||||
|
||||
friend class MPQFile;
|
||||
};
|
||||
|
||||
|
||||
class MPQFile
|
||||
{
|
||||
bool eof;
|
||||
std::vector<char> buffer;
|
||||
size_t pointer;
|
||||
|
||||
|
||||
bool External;
|
||||
boost::filesystem::path _disk_path;
|
||||
std::string _mpq_path;
|
||||
|
||||
public:
|
||||
explicit MPQFile(const std::string& pFilename); // filenames are not case sensitive, the are if u dont use a filesystem which is kinda shitty...
|
||||
|
||||
MPQFile() = delete;
|
||||
~MPQFile();
|
||||
MPQFile(MPQFile const&) = delete;
|
||||
MPQFile(MPQFile&&) = delete;
|
||||
MPQFile& operator=(MPQFile const&) = delete;
|
||||
MPQFile& operator=(MPQFile&&) = delete;
|
||||
|
||||
size_t read(void* dest, size_t bytes);
|
||||
size_t getSize() const;
|
||||
size_t getPos() const;
|
||||
char const* getBuffer() const;
|
||||
char const* getPointer() const;
|
||||
bool isEof() const;
|
||||
void seek(size_t offset);
|
||||
void seekRelative(size_t offset);
|
||||
void close();
|
||||
bool isExternal() const
|
||||
{
|
||||
return External;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T* get(size_t offset) const
|
||||
{
|
||||
return reinterpret_cast<T const*>(buffer.data() + offset);
|
||||
}
|
||||
|
||||
void setBuffer (std::vector<char> const& vec)
|
||||
{
|
||||
buffer = vec;
|
||||
}
|
||||
|
||||
void SaveFile();
|
||||
|
||||
static bool exists (std::string const& filename);
|
||||
static bool existsOnDisk (std::string const& filename);
|
||||
|
||||
friend class MPQArchive;
|
||||
};
|
||||
|
||||
namespace noggit
|
||||
{
|
||||
namespace mpq
|
||||
{
|
||||
std::string normalized_filename (std::string filename);
|
||||
std::string normalized_filename_insane (std::string filename);
|
||||
}
|
||||
}
|
||||
1492
src/noggit/MapChunk.cpp
Normal file
1492
src/noggit/MapChunk.cpp
Normal file
File diff suppressed because it is too large
Load Diff
197
src/noggit/MapChunk.h
Normal file
197
src/noggit/MapChunk.h
Normal file
@@ -0,0 +1,197 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math/quaternion.hpp> // math::vector_4d
|
||||
#include <noggit/map_enums.hpp>
|
||||
#include <noggit/MapTile.h> // MapTile
|
||||
#include <noggit/ModelInstance.h>
|
||||
#include <noggit/Selection.h>
|
||||
#include <noggit/TextureManager.h>
|
||||
#include <noggit/WMOInstance.h>
|
||||
#include <noggit/texture_set.hpp>
|
||||
#include <noggit/tool_enums.hpp>
|
||||
#include <opengl/scoped.hpp>
|
||||
#include <opengl/texture.hpp>
|
||||
#include <noggit/Misc.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
class MPQFile;
|
||||
namespace math
|
||||
{
|
||||
class frustum;
|
||||
struct vector_4d;
|
||||
}
|
||||
class Brush;
|
||||
class ChunkWater;
|
||||
class sExtendableArray;
|
||||
|
||||
using StripType = uint16_t;
|
||||
static const int mapbufsize = 9 * 9 + 8 * 8; // chunk size
|
||||
|
||||
class MapChunk
|
||||
{
|
||||
private:
|
||||
tile_mode _mode;
|
||||
|
||||
bool hasMCCV;
|
||||
|
||||
int holes;
|
||||
|
||||
unsigned int areaID;
|
||||
|
||||
void update_shadows();
|
||||
|
||||
uint8_t _shadow_map[64 * 64];
|
||||
opengl::texture shadow;
|
||||
|
||||
std::vector<StripType> strip_with_holes;
|
||||
std::vector<StripType> strip_without_holes;
|
||||
std::map<int, std::vector<StripType>> strip_lods;
|
||||
|
||||
math::vector_3d mNormals[mapbufsize];
|
||||
math::vector_3d mccv[mapbufsize];
|
||||
|
||||
std::vector<uint8_t> compressed_shadow_map() const;
|
||||
bool has_shadows() const;
|
||||
|
||||
void initStrip();
|
||||
|
||||
int indexNoLoD(int x, int y);
|
||||
int indexLoD(int x, int y);
|
||||
|
||||
std::vector<math::vector_3d> _intersect_points;
|
||||
|
||||
void update_intersect_points();
|
||||
|
||||
boost::optional<int> get_lod_level( math::vector_3d const& camera_pos
|
||||
, display_mode display
|
||||
) const;
|
||||
|
||||
bool _uploaded = false;
|
||||
bool _need_indice_buffer_update = true;
|
||||
bool _need_vao_update = true;
|
||||
|
||||
void upload();
|
||||
void update_indices_buffer();
|
||||
void update_vao(opengl::scoped::use_program& mcnk_shader, GLuint const& tex_coord_vbo);
|
||||
|
||||
opengl::scoped::deferred_upload_vertex_arrays<1> _vertex_array;
|
||||
GLuint const& _vao = _vertex_array[0];
|
||||
opengl::scoped::deferred_upload_buffers<4> _buffers;
|
||||
GLuint const& _vertices_vbo = _buffers[0];
|
||||
GLuint const& _normals_vbo = _buffers[1];
|
||||
GLuint const& _indices_buffer = _buffers[2];
|
||||
GLuint const& _mccv_vbo = _buffers[3];
|
||||
opengl::scoped::deferred_upload_buffers<4> lod_indices;
|
||||
|
||||
public:
|
||||
MapChunk(MapTile* mt, MPQFile* f, bool bigAlpha, tile_mode mode);
|
||||
|
||||
MapTile *mt;
|
||||
math::vector_3d vmin, vmax, vcenter;
|
||||
int px, py;
|
||||
|
||||
MapChunkHeader header;
|
||||
|
||||
float xbase, ybase, zbase;
|
||||
|
||||
mcnk_flags header_flags;
|
||||
bool use_big_alphamap;
|
||||
|
||||
std::unique_ptr<TextureSet> texture_set;
|
||||
|
||||
math::vector_3d mVertices[mapbufsize];
|
||||
|
||||
bool is_visible ( const float& cull_distance
|
||||
, const math::frustum& frustum
|
||||
, const math::vector_3d& camera
|
||||
, display_mode display
|
||||
) const;
|
||||
private:
|
||||
// return true if the lod level changed
|
||||
bool update_visibility ( const float& cull_distance
|
||||
, const math::frustum& frustum
|
||||
, const math::vector_3d& camera
|
||||
, display_mode display
|
||||
);
|
||||
|
||||
bool _is_visible = true; // visible by default
|
||||
bool _need_visibility_update = true;
|
||||
boost::optional<int> _lod_level = boost::none; // none = no lod
|
||||
size_t _lod_level_indice_count = 0;
|
||||
public:
|
||||
|
||||
void draw ( math::frustum const& frustum
|
||||
, opengl::scoped::use_program& mcnk_shader
|
||||
, GLuint const& tex_coord_vbo
|
||||
, const float& cull_distance
|
||||
, const math::vector_3d& camera
|
||||
, bool need_visibility_update
|
||||
, bool show_unpaintable_chunks
|
||||
, bool draw_paintability_overlay
|
||||
, bool draw_chunk_flag_overlay
|
||||
, bool draw_areaid_overlay
|
||||
, std::map<int, misc::random_color>& area_id_colors
|
||||
, int animtime
|
||||
, display_mode display
|
||||
);
|
||||
//! \todo only this function should be public, all others should be called from it
|
||||
|
||||
void intersect (math::ray const&, selection_result*);
|
||||
bool ChangeMCCV(math::vector_3d const& pos, math::vector_4d const& color, float change, float radius, bool editMode);
|
||||
math::vector_3d pickMCCV(math::vector_3d const& pos);
|
||||
|
||||
ChunkWater* liquid_chunk() const;
|
||||
|
||||
void updateVerticesData();
|
||||
void recalcNorms (std::function<boost::optional<float> (float, float)> height);
|
||||
|
||||
//! \todo implement Action stack for these
|
||||
bool changeTerrain(math::vector_3d const& pos, float change, float radius, int BrushType, float inner_radius);
|
||||
bool flattenTerrain(math::vector_3d const& pos, float remain, float radius, int BrushType, flatten_mode const& mode, const math::vector_3d& origin, math::degrees angle, math::degrees orientation);
|
||||
bool blurTerrain ( math::vector_3d const& pos, float remain, float radius, int BrushType, flatten_mode const& mode
|
||||
, std::function<boost::optional<float> (float, float)> height
|
||||
);
|
||||
|
||||
void selectVertex(math::vector_3d const& pos, float radius, std::set<math::vector_3d*>& vertices);
|
||||
void fixVertices(std::set<math::vector_3d*>& selected);
|
||||
// for the vertex tool
|
||||
bool isBorderChunk(std::set<math::vector_3d*>& selected);
|
||||
|
||||
//! \todo implement Action stack for these
|
||||
bool paintTexture(math::vector_3d const& pos, Brush *brush, float strength, float pressure, scoped_blp_texture_reference texture);
|
||||
bool replaceTexture(math::vector_3d const& pos, float radius, scoped_blp_texture_reference const& old_texture, scoped_blp_texture_reference new_texture);
|
||||
bool canPaintTexture(scoped_blp_texture_reference texture);
|
||||
int addTexture(scoped_blp_texture_reference texture);
|
||||
void switchTexture(scoped_blp_texture_reference const& oldTexture, scoped_blp_texture_reference newTexture);
|
||||
void eraseTextures();
|
||||
void change_texture_flag(scoped_blp_texture_reference const& tex, std::size_t flag, bool add);
|
||||
|
||||
void clear_shadows();
|
||||
|
||||
//! \todo implement Action stack for these
|
||||
bool isHole(int i, int j);
|
||||
void setHole(math::vector_3d const& pos, bool big, bool add);
|
||||
|
||||
void setFlag(bool value, uint32_t);
|
||||
|
||||
int getAreaID();
|
||||
void setAreaID(int ID);
|
||||
|
||||
bool GetVertex(float x, float z, math::vector_3d *V);
|
||||
float getHeight(int x, int z);
|
||||
float getMinHeight();
|
||||
|
||||
void clearHeight();
|
||||
|
||||
//! \todo this is ugly create a build struct or sth
|
||||
void save(sExtendableArray &lADTFile, int &lCurrentPosition, int &lMCIN_Position, std::map<std::string, int> &lTextures, std::vector<WMOInstance> &lObjectInstances, std::vector<ModelInstance>& lModelInstances);
|
||||
|
||||
// fix the gaps with the chunk to the left
|
||||
bool fixGapLeft(const MapChunk* chunk);
|
||||
// fix the gaps with the chunk above
|
||||
bool fixGapAbove(const MapChunk* chunk);
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user