diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0628afa4..6b67bd83 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -32,7 +32,8 @@ src/glmesh.cpp
src/loader.cpp
src/main.cpp
src/mesh.cpp
-src/window.cpp)
+src/window.cpp
+src/shaderlightprefs.cpp)
#set project headers.
set(Project_Headers src/app.h
@@ -42,7 +43,8 @@ src/canvas.h
src/glmesh.h
src/loader.h
src/mesh.h
-src/window.h)
+src/window.h
+src/shaderlightprefs.h)
#set project resources and icon resource
set(Project_Resources qt/qt.qrc gl/gl.qrc)
@@ -52,7 +54,7 @@ set(Icon_Resource exe/fstl.rc)
set(OpenGL_GL_PREFERENCE GLVND)
#find required packages.
-find_package(Qt5 5.14 REQUIRED COMPONENTS Core Gui Widgets OpenGL)
+find_package(Qt5 5.12 REQUIRED COMPONENTS Core Gui Widgets OpenGL)
find_package(OpenGL REQUIRED)
find_package(Threads REQUIRED)
diff --git a/gl/calc_altitudes.glsl b/gl/calc_altitudes.glsl
new file mode 100644
index 00000000..721bed1f
--- /dev/null
+++ b/gl/calc_altitudes.glsl
@@ -0,0 +1,64 @@
+#version 330
+
+layout (triangles) in;
+layout (triangle_strip, max_vertices = 3) out;
+
+out vec3 ec_pos;
+noperspective out vec3 altitude;
+
+uniform vec2 portSize;
+
+void main() {
+ vec4 p0 = gl_in[0].gl_Position;
+ vec4 p1 = gl_in[1].gl_Position;
+ vec4 p2 = gl_in[2].gl_Position;
+
+ vec2 p0_f = p0.xy/p0.w;
+ vec2 p1_f = p1.xy/p1.w;
+ vec2 p2_f = p2.xy/p2.w;
+
+ // Altitude calculation :
+ // vp0p1 is the p0p1 vector
+ // vp0p2 is the p0p2 vector
+ // det(vp0p1,vp0p2) is the area of the parallelogram defined by the two vectors vp0p1 and vp0p2
+ // h0 is the altitude from p0 in the triangle (p0 p1 p2)
+ // h0 multiplied by p1p2 which is the length of vp0p1-vp0p2 is also the area of the parallelogram defined by the two vectors vp0p1 and vp0p2
+ // this leads to h0
+ //
+ // portSize is used to have an altitude in pixel
+ //
+
+ // Calculate h0 altitude from p0
+ vec2 vp0p1 = portSize*(p1_f-p0_f);
+ vec2 vp0p2 = portSize*(p2_f-p0_f);
+ float h0 = abs(determinant(mat2(vp0p1,vp0p2))) / length(vp0p1-vp0p2);
+ // release values
+ gl_Position = p0;
+ ec_pos = gl_Position.xyz;
+ altitude = vec3(h0*p0.w, 0.0, 0.0);
+ EmitVertex();
+
+ // calculate h1 altitude from p1
+ vec2 vp1p0 = portSize*(p0_f-p1_f);
+ vec2 vp1p2 = portSize*(p2_f-p1_f);
+ float h1 = abs(determinant(mat2(vp1p0,vp1p2))) / length(vp1p0-vp1p2);
+ // release values
+ gl_Position = p1;
+ ec_pos = gl_Position.xyz;
+ altitude = vec3(0.0, h1*p1.w, 0.0);
+ EmitVertex();
+
+ // calculate h2 altitude from p2
+ vec2 vp2p0 = portSize*(p0_f-p2_f);
+ vec2 vp2p1 = portSize*(p1_f-p2_f);
+ float h2 = abs(determinant(mat2(vp2p0,vp2p1))) / length(vp2p0-vp2p1);
+ // release values
+ gl_Position = p2;
+ ec_pos = gl_Position.xyz;
+ altitude = vec3(0.0, 0.0, h2*p2.w);
+ EmitVertex();
+
+ EndPrimitive();
+
+}
+
diff --git a/gl/gl.qrc b/gl/gl.qrc
index 6e8baa90..6d919e69 100644
--- a/gl/gl.qrc
+++ b/gl/gl.qrc
@@ -1,13 +1,16 @@
-
+
mesh.frag
mesh.vert
mesh_wireframe.frag
mesh_surfaceangle.frag
+ mesh_light.frag
quad.frag
quad.vert
colored_lines.frag
colored_lines.vert
sphere.stl
+ calc_altitudes.glsl
+ mesh_light_120.frag
diff --git a/gl/mesh_light.frag b/gl/mesh_light.frag
new file mode 100644
index 00000000..d2ceaa2b
--- /dev/null
+++ b/gl/mesh_light.frag
@@ -0,0 +1,33 @@
+#version 330
+
+uniform float zoom;
+uniform vec4 ambient_light_color;
+uniform vec4 directive_light_color;
+uniform vec3 directive_light_direction;
+uniform bool useWire;
+uniform vec3 wireColor;
+uniform float wireWidth;
+
+in vec3 ec_pos;
+noperspective in vec3 altitude;
+
+void main() {
+ // Normalize light direction
+ vec3 dir = normalize(directive_light_direction);
+
+ // normal vector
+ vec3 ec_normal = normalize(cross(dFdx(ec_pos), dFdy(ec_pos)));
+ ec_normal.z *= zoom;
+ ec_normal = normalize(ec_normal);
+
+
+ vec3 color = ambient_light_color.w * ambient_light_color.xyz + directive_light_color.w * dot(ec_normal,dir) * directive_light_color.xyz;
+
+ if (useWire) {
+ float d = min(min(altitude.x, altitude.y),altitude.z);
+ float mixVal = smoothstep(wireWidth-1.0, wireWidth+1.0,d);
+ color = mix(wireColor,color,mixVal);
+ }
+
+ gl_FragColor = vec4(color, 1.0);
+}
diff --git a/gl/mesh_light_120.frag b/gl/mesh_light_120.frag
new file mode 100644
index 00000000..4c671470
--- /dev/null
+++ b/gl/mesh_light_120.frag
@@ -0,0 +1,23 @@
+#version 120
+
+uniform float zoom;
+uniform vec4 ambient_light_color;
+uniform vec4 directive_light_color;
+uniform vec3 directive_light_direction;
+
+varying vec3 ec_pos;
+
+void main() {
+ // Normalize light direction
+ vec3 dir = normalize(directive_light_direction);
+
+ // normal vector
+ vec3 ec_normal = normalize(cross(dFdx(ec_pos), dFdy(ec_pos)));
+ ec_normal.z *= zoom;
+ ec_normal = normalize(ec_normal);
+
+
+ vec3 color = ambient_light_color.w * ambient_light_color.xyz + directive_light_color.w * dot(ec_normal,dir) * directive_light_color.xyz;
+
+ gl_FragColor = vec4(color, 1.0);
+}
diff --git a/qt/icons/auto_refresh.png b/qt/icons/auto_refresh.png
new file mode 100644
index 00000000..34826986
Binary files /dev/null and b/qt/icons/auto_refresh.png differ
diff --git a/qt/icons/axes.png b/qt/icons/axes.png
new file mode 100644
index 00000000..e4400735
Binary files /dev/null and b/qt/icons/axes.png differ
diff --git a/qt/icons/document-open.png b/qt/icons/document-open.png
new file mode 100644
index 00000000..c94a7edf
Binary files /dev/null and b/qt/icons/document-open.png differ
diff --git a/qt/icons/exit.png b/qt/icons/exit.png
new file mode 100644
index 00000000..fb0a1a6b
Binary files /dev/null and b/qt/icons/exit.png differ
diff --git a/qt/icons/invert_zoom.png b/qt/icons/invert_zoom.png
new file mode 100644
index 00000000..7136b95c
Binary files /dev/null and b/qt/icons/invert_zoom.png differ
diff --git a/qt/icons/orthographic.png b/qt/icons/orthographic.png
new file mode 100644
index 00000000..64cbb7d7
Binary files /dev/null and b/qt/icons/orthographic.png differ
diff --git a/qt/icons/perspective.png b/qt/icons/perspective.png
new file mode 100644
index 00000000..442f9bf0
Binary files /dev/null and b/qt/icons/perspective.png differ
diff --git a/qt/icons/preferences-system.png b/qt/icons/preferences-system.png
new file mode 100644
index 00000000..97c48025
Binary files /dev/null and b/qt/icons/preferences-system.png differ
diff --git a/qt/icons/reset_rotation_on_load.png b/qt/icons/reset_rotation_on_load.png
new file mode 100644
index 00000000..1f17a007
Binary files /dev/null and b/qt/icons/reset_rotation_on_load.png differ
diff --git a/qt/icons/resolution_1_32.png b/qt/icons/resolution_1_32.png
new file mode 100644
index 00000000..7d655cc9
Binary files /dev/null and b/qt/icons/resolution_1_32.png differ
diff --git a/qt/icons/screenshot.png b/qt/icons/screenshot.png
new file mode 100644
index 00000000..97f380e3
Binary files /dev/null and b/qt/icons/screenshot.png differ
diff --git a/qt/icons/sphere_shader1.png b/qt/icons/sphere_shader1.png
new file mode 100644
index 00000000..84931c37
Binary files /dev/null and b/qt/icons/sphere_shader1.png differ
diff --git a/qt/icons/sphere_shader2.png b/qt/icons/sphere_shader2.png
new file mode 100644
index 00000000..258b3598
Binary files /dev/null and b/qt/icons/sphere_shader2.png differ
diff --git a/qt/icons/sphere_shader3.png b/qt/icons/sphere_shader3.png
new file mode 100644
index 00000000..ca05cd45
Binary files /dev/null and b/qt/icons/sphere_shader3.png differ
diff --git a/qt/icons/sphere_shader4.png b/qt/icons/sphere_shader4.png
new file mode 100644
index 00000000..31b3e787
Binary files /dev/null and b/qt/icons/sphere_shader4.png differ
diff --git a/qt/icons/view-fullscreen.png b/qt/icons/view-fullscreen.png
new file mode 100644
index 00000000..bc059924
Binary files /dev/null and b/qt/icons/view-fullscreen.png differ
diff --git a/qt/icons/view-refresh.png b/qt/icons/view-refresh.png
new file mode 100644
index 00000000..72f6df20
Binary files /dev/null and b/qt/icons/view-refresh.png differ
diff --git a/qt/qt.qrc b/qt/qt.qrc
index f2b1266f..2c9179de 100644
--- a/qt/qt.qrc
+++ b/qt/qt.qrc
@@ -2,5 +2,22 @@
style.qss
icons/fstl_64x64.png
+ icons/sphere_shader1.png
+ icons/sphere_shader2.png
+ icons/sphere_shader3.png
+ icons/sphere_shader4.png
+ icons/document-open.png
+ icons/exit.png
+ icons/screenshot.png
+ icons/view-fullscreen.png
+ icons/view-refresh.png
+ icons/preferences-system.png
+ icons/axes.png
+ icons/orthographic.png
+ icons/perspective.png
+ icons/reset_rotation_on_load.png
+ icons/invert_zoom.png
+ icons/auto_refresh.png
+ icons/resolution_1_32.png
diff --git a/src/canvas.cpp b/src/canvas.cpp
index 0f6037fb..0349660d 100644
--- a/src/canvas.cpp
+++ b/src/canvas.cpp
@@ -11,6 +11,24 @@
const float Canvas::P_PERSPECTIVE = 0.25f;
const float Canvas::P_ORTHOGRAPHIC = 0.0f;
+const QString Canvas::AMBIENT_COLOR = "ambientColor";
+const QString Canvas::AMBIENT_FACTOR = "ambientFactor";
+const QString Canvas::DIRECTIVE_COLOR = "directiveColor";
+const QString Canvas::DIRECTIVE_FACTOR = "directiveFactor";
+const QString Canvas::CURRENT_LIGHT_DIRECTION = "currentLightDirection";
+const QString Canvas::USE_WIRE = "useWire";
+const QString Canvas::WIRE_WIDTH = "wireWidth";
+const QString Canvas::WIRE_COLOR = "wireColor";
+
+const QColor Canvas::defaultAmbientColor = QColor::fromRgbF(0.22,0.8,1.0);
+const QColor Canvas::defaultDirectiveColor = QColor(255,255,255);
+const double Canvas::defaultAmbientFactor = 0.67;
+const double Canvas::defaultDirectiveFactor = 0.5;
+const int Canvas::defaultCurrentLightDirection = 1;
+const bool Canvas::defaultUseWire = false;
+const double Canvas::defaultWireWidth = 1.0;
+const QColor Canvas::defaultWireColor = QColor(255,128,0);
+
Canvas::Canvas(const QSurfaceFormat& format, QWidget *parent)
: QOpenGLWidget(parent), mesh(nullptr),
scale(1), zoom(1),
@@ -24,7 +42,42 @@ Canvas::Canvas(const QSurfaceFormat& format, QWidget *parent)
currentTransform = QMatrix4x4();
resetTransform();
+ fallbackGlsl = false;
+ QSettings settings;
+ ambientColor = settings.value(AMBIENT_COLOR,defaultAmbientColor).value();
+ directiveColor = settings.value(DIRECTIVE_COLOR,defaultDirectiveColor).value();
+ ambientFactor = settings.value(AMBIENT_FACTOR,defaultAmbientFactor).value();
+ directiveFactor = settings.value(DIRECTIVE_FACTOR,defaultDirectiveFactor).value();
+ useWire = settings.value(USE_WIRE,defaultUseWire).value();
+ wireWidth = settings.value(WIRE_WIDTH,defaultWireWidth).value();
+ wireColor = settings.value(WIRE_COLOR,defaultWireColor).value();
+
+ // Fill direction list
+ // Fill in directions
+ nameDir.clear();
+ listDir.clear();
+ QList xname, yname, zname;
+ xname << "right " << " " << "left ";
+ yname << "top " << " " << "bottom ";
+ zname << "rear " << " " << "front ";
+ for (int i=-1; i<2 ; i++) {
+ for (int j=-1; j<2; j++) {
+ for (int k=-1; k<2; k++) {
+ QString current = xname.at(i+1) + yname.at(j+1) + zname.at(k+1);
+ if (!(i==0 && j==0 && k==0)) {
+ nameDir << current.simplified();
+ listDir << QVector3D((double)i,(double)j,(double)k);
+ }
+ }
+ }
+ }
+ currentLightDirection = settings.value(CURRENT_LIGHT_DIRECTION,defaultCurrentLightDirection).value();
+ if (currentLightDirection < 0 || currentLightDirection >= nameDir.length()) {
+ currentLightDirection = defaultCurrentLightDirection;
+ }
+
anim.setDuration(100);
+
}
Canvas::~Canvas()
@@ -134,6 +187,8 @@ void Canvas::initializeGL()
{
initializeOpenGLFunctions();
+ fallbackGlsl = false;
+
mesh_vertshader = new QOpenGLShader(QOpenGLShader::Vertex);
mesh_vertshader->compileSourceFile(":/gl/mesh.vert");
mesh_shader.addShader(mesh_vertshader);
@@ -145,6 +200,18 @@ void Canvas::initializeGL()
mesh_surfaceangle_shader.addShader(mesh_vertshader);
mesh_surfaceangle_shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/gl/mesh_surfaceangle.frag");
mesh_surfaceangle_shader.link();
+ mesh_meshlight_shader.addShader(mesh_vertshader);
+ bool loadSuccess330 = mesh_meshlight_shader.addShaderFromSourceFile(QOpenGLShader::Geometry, ":/gl/calc_altitudes.glsl") &&
+ mesh_meshlight_shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/gl/mesh_light.frag");
+ if (!loadSuccess330) {
+ // fallback to 120
+ fallbackGlsl = true;
+ mesh_meshlight_shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/gl/mesh_light_120.frag");
+ qDebug() << "Cannot load a shader using glsl version 330, fall back to another using version 120";
+ qDebug() << "Adding wireframe on top of meshlight shader will be disabled.";
+ }
+ emit fallbackGlslUpdated(fallbackGlsl);
+ mesh_meshlight_shader.link();
backdrop = new Backdrop();
axis = new Axis();
@@ -166,6 +233,17 @@ void Canvas::paintGL()
float textHeight = painter.fontInfo().pointSize();
if (drawAxes) painter.drawText(QRect(10, textHeight, width(), height()), meshInfo);
painter.drawText(10, height() - textHeight, status);
+
+ if (drawAxes) {
+ QString sWidth = QString("GL Width = %1").arg(width());
+ QString sHeight = QString("GL Height = %1").arg(height());
+ int sWidthLength = painter.fontMetrics().horizontalAdvance(sWidth);
+ int sHeightLength = painter.fontMetrics().horizontalAdvance(sHeight);
+ int origin = std::min(sWidthLength,sHeightLength);
+ painter.drawText(width() - origin - 10, textHeight + 10, sWidth);
+ painter.drawText(width() - origin - 10, 2* textHeight + 10, sHeight);
+ }
+
}
void Canvas::draw_mesh()
@@ -182,10 +260,14 @@ void Canvas::draw_mesh()
{
selected_mesh_shader = &mesh_shader;
}
- else
+ else if (drawMode == surfaceangle)
{
selected_mesh_shader = &mesh_surfaceangle_shader;
}
+ else if (drawMode == meshlight)
+ {
+ selected_mesh_shader = &mesh_meshlight_shader;
+ }
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
@@ -202,6 +284,34 @@ void Canvas::draw_mesh()
// Compensate for z-flattening when zooming
glUniform1f(selected_mesh_shader->uniformLocation("zoom"), 1/zoom);
+ // specific meshlight arguments
+ if (drawMode == meshlight) {
+ // Ambient Light Color, followed by the ambient light coefficient to use
+ //glUniform4f(selected_mesh_shader->uniformLocation("ambient_light_color"),0.22f, 0.8f, 1.0f, 0.67f);
+ glUniform4f(selected_mesh_shader->uniformLocation("ambient_light_color"),ambientColor.redF(), ambientColor.greenF(), ambientColor.blueF(), ambientFactor);
+ // Directive Light Color, followed by the directive light coefficient to use
+ //glUniform4f(selected_mesh_shader->uniformLocation("directive_light_color"),1.0f,1.0f,1.0f,0.5f);
+ glUniform4f(selected_mesh_shader->uniformLocation("directive_light_color"),directiveColor.redF(),directiveColor.greenF(),directiveColor.blueF(),directiveFactor);
+
+ // Directive Light Direction
+ // dir 1,0,0 Light from the left
+ // dir -1,0,0 Light from the right
+ // dir 0,1,0 Light from bottom
+ // dir 0,-1,0 Light from top
+ // dir 0,0,1 Light from viewer (front)
+ // dir 0,0,-1 Light from behind
+ //
+ // -1,-1,0 Light from top right
+ //glUniform3f(selected_mesh_shader->uniformLocation("directive_light_direction"),-1.0f,-1.0f,0.0f);
+ glUniform3f(selected_mesh_shader->uniformLocation("directive_light_direction"),listDir.at(currentLightDirection).x(), listDir.at(currentLightDirection).y(), listDir.at(currentLightDirection).z());
+ if (!fallbackGlsl) {
+ glUniform1i(selected_mesh_shader->uniformLocation("useWire"),useWire);
+ glUniform1f(selected_mesh_shader->uniformLocation("wireWidth"),wireWidth);
+ glUniform2f(selected_mesh_shader->uniformLocation("portSize"),(float)this->width(),(float)this->height());
+ glUniform3f(selected_mesh_shader->uniformLocation("wireColor"),wireColor.redF(),wireColor.greenF(),wireColor.blueF());
+ }
+ }
+
// Find and enable the attribute location for vertex position
const GLuint vp = selected_mesh_shader->attributeLocation("vertex_position");
glEnableVertexAttribArray(vp);
@@ -351,7 +461,13 @@ void Canvas::wheelEvent(QWheelEvent *event)
{
// Find GL position before the zoom operation
// (to zoom about mouse cursor)
+// event->pos() obsolete since introduction of event->position() in 5.14
+// but we still want to be able compile with 5.12 which is the minimum requirement in CmakeLists.txt
+#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
+ auto p = event->pos();
+#else
auto p = event->position();
+#endif
QVector3D v(1 - p.x() / (0.5*width()),
p.y() / (0.5*height()) - 1, 0);
QVector3D a = transform_matrix().inverted() *
@@ -385,3 +501,117 @@ void Canvas::resizeGL(int width, int height)
{
glViewport(0, 0, width, height);
}
+
+QColor Canvas::getAmbientColor() {
+ return ambientColor;
+}
+
+void Canvas::setAmbientColor(QColor c) {
+ ambientColor = c;
+ QSettings settings;
+ settings.setValue(AMBIENT_COLOR,c);
+}
+
+double Canvas::getAmbientFactor() {
+ return (float) ambientFactor;
+}
+
+void Canvas::setAmbientFactor(double f) {
+ ambientFactor = (float) f;
+ QSettings settings;
+ settings.setValue(AMBIENT_FACTOR,f);
+}
+
+void Canvas::resetAmbientColor() {
+ setAmbientColor(defaultAmbientColor);
+ setAmbientFactor(defaultAmbientFactor);
+}
+
+QColor Canvas::getDirectiveColor() {
+ return directiveColor;
+}
+
+void Canvas::setDirectiveColor(QColor c) {
+ directiveColor = c;
+ QSettings settings;
+ settings.setValue(DIRECTIVE_COLOR,c);
+}
+
+double Canvas::getDirectiveFactor() {
+ return (float) directiveFactor;
+}
+
+void Canvas::setDirectiveFactor(double f) {
+ directiveFactor = (float) f;
+ QSettings settings;
+ settings.setValue(DIRECTIVE_FACTOR,f);
+}
+
+void Canvas::resetDirectiveColor() {
+ setDirectiveColor(defaultDirectiveColor);
+ setDirectiveFactor(defaultDirectiveFactor);
+}
+
+QList Canvas::getNameDir() {
+ return nameDir;
+}
+
+int Canvas::getCurrentLightDirection() {
+ return currentLightDirection;
+}
+
+void Canvas::setCurrentLightDirection(int ind) {
+ currentLightDirection = ind;
+ QSettings settings;
+ settings.setValue(CURRENT_LIGHT_DIRECTION,currentLightDirection);
+}
+
+void Canvas::resetCurrentLightDirection() {
+ setCurrentLightDirection(defaultCurrentLightDirection);
+}
+
+bool Canvas::getUseWire() {
+ return useWire;
+}
+
+void Canvas::setUseWire(bool b) {
+ useWire = b;
+ QSettings settings;
+ settings.setValue(USE_WIRE,useWire);
+}
+
+void Canvas::resetUseWire() {
+ setUseWire(defaultUseWire);
+}
+
+double Canvas::getWireWidth() {
+ return (double) wireWidth;
+}
+
+void Canvas::setWireWidth(double w) {
+ wireWidth = (float) w;
+ QSettings settings;
+ settings.setValue(WIRE_WIDTH,w);
+}
+
+void Canvas::resetWireWidth() {
+ setWireWidth(defaultWireWidth);
+}
+
+QColor Canvas::getWireColor() {
+ return wireColor;
+}
+
+void Canvas::setWireColor(QColor c) {
+ wireColor = c;
+ QSettings settings;
+ settings.setValue(WIRE_COLOR,wireColor);
+}
+
+void Canvas::resetWireColor() {
+ setWireColor(defaultWireColor);
+}
+
+bool Canvas::isFallbackGlsl() {
+ return fallbackGlsl;
+}
diff --git a/src/canvas.h b/src/canvas.h
index e065db65..a5994363 100644
--- a/src/canvas.h
+++ b/src/canvas.h
@@ -10,7 +10,7 @@ class Mesh;
class Backdrop;
class Axis;
-enum DrawMode {shaded, wireframe, surfaceangle, DRAWMODECOUNT};
+enum DrawMode {shaded, wireframe, surfaceangle, meshlight, DRAWMODECOUNT};
class Canvas : public QOpenGLWidget, protected QOpenGLFunctions
{
@@ -29,6 +29,37 @@ class Canvas : public QOpenGLWidget, protected QOpenGLFunctions
void set_drawMode(enum DrawMode mode);
void setResetTransformOnLoad(bool d);
+ QColor getAmbientColor();
+ void setAmbientColor(QColor c);
+ double getAmbientFactor();
+ void setAmbientFactor(double f);
+ void resetAmbientColor();
+
+ QColor getDirectiveColor();
+ void setDirectiveColor(QColor c);
+ double getDirectiveFactor();
+ void setDirectiveFactor(double f);
+ void resetDirectiveColor();
+
+ QList getNameDir();
+ int getCurrentLightDirection();
+ void setCurrentLightDirection(int ind);
+ void resetCurrentLightDirection();
+
+ bool getUseWire();
+ void setUseWire(bool b);
+ void resetUseWire();
+
+ double getWireWidth();
+ void setWireWidth(double w);
+ void resetWireWidth();
+
+ QColor getWireColor();
+ void setWireColor(QColor c);
+ void resetWireColor();
+
+ bool isFallbackGlsl();
+
public slots:
void set_status(const QString& s);
void clear_status();
@@ -47,6 +78,9 @@ public slots:
void set_perspective(float p);
void view_anim(float v);
+signals:
+ void fallbackGlslUpdated(bool b);
+
private:
void draw_mesh();
@@ -62,6 +96,38 @@ public slots:
QOpenGLShaderProgram mesh_shader;
QOpenGLShaderProgram mesh_wireframe_shader;
QOpenGLShaderProgram mesh_surfaceangle_shader;
+ QOpenGLShaderProgram mesh_meshlight_shader;
+
+ QColor ambientColor;
+ QColor directiveColor;
+ float ambientFactor;
+ float directiveFactor;
+ QList nameDir;
+ QList listDir;
+ int currentLightDirection;
+ bool useWire;
+ float wireWidth;
+ QColor wireColor;
+ bool fallbackGlsl;
+
+ const static QColor defaultAmbientColor;
+ const static QColor defaultDirectiveColor;
+ const static double defaultAmbientFactor;
+ const static double defaultDirectiveFactor;
+ const static int defaultCurrentLightDirection;
+ const static bool defaultUseWire;
+ const static double defaultWireWidth;
+ const static QColor defaultWireColor;
+
+ const static QString AMBIENT_COLOR;
+ const static QString AMBIENT_FACTOR;
+ const static QString DIRECTIVE_COLOR;
+ const static QString DIRECTIVE_FACTOR;
+ const static QString CURRENT_LIGHT_DIRECTION;
+ const static QString USE_WIRE;
+ const static QString WIRE_WIDTH;
+ const static QString WIRE_COLOR;
+
GLMesh* mesh;
Backdrop* backdrop;
diff --git a/src/main.cpp b/src/main.cpp
index 4ec87227..14561ebc 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -4,10 +4,14 @@
int main(int argc, char *argv[])
{
+ // Force C locale to force decimal point
+ QLocale::setDefault(QLocale::c());
+
QCoreApplication::setOrganizationName("fstl-app");
QCoreApplication::setOrganizationDomain("https://github.com/fstl-app/fstl");
QCoreApplication::setApplicationName("fstl");
QCoreApplication::setApplicationVersion(FSTL_VERSION);
App a(argc, argv);
+
return a.exec();
}
diff --git a/src/shaderlightprefs.cpp b/src/shaderlightprefs.cpp
new file mode 100644
index 00000000..bb4cc38d
--- /dev/null
+++ b/src/shaderlightprefs.cpp
@@ -0,0 +1,272 @@
+#include "shaderlightprefs.h"
+#include "canvas.h"
+#include
+
+const QString ShaderLightPrefs::PREFS_GEOM = "shaderPrefsGeometry";
+
+ShaderLightPrefs::ShaderLightPrefs(QWidget *parent, Canvas *_canvas) : QDialog(parent)
+{
+ canvas = _canvas;
+
+ QVBoxLayout* prefsLayout = new QVBoxLayout;
+ this->setLayout(prefsLayout);
+
+ QLabel* title = new QLabel("Shader preferences");
+ QFont boldFont = QApplication::font();
+ boldFont.setWeight(QFont::Bold);
+ title->setFont(boldFont);
+ title->setAlignment(Qt::AlignCenter);
+ prefsLayout->addWidget(title);
+
+ QWidget* middleWidget = new QWidget;
+ QGridLayout* middleLayout = new QGridLayout;
+ middleWidget->setLayout(middleLayout);
+ this->layout()->addWidget(middleWidget);
+
+ // labels
+ middleLayout->addWidget(new QLabel("Ambient Color"),0,0);
+ middleLayout->addWidget(new QLabel("Directive Color"),1,0);
+ middleLayout->addWidget(new QLabel("Direction"),2,0);
+
+ QPixmap dummy(20, 20);
+
+ dummy.fill(canvas->getAmbientColor());
+ buttonAmbientColor = new QPushButton;
+ buttonAmbientColor->setIcon(QIcon(dummy));
+ middleLayout->addWidget(buttonAmbientColor,0,1);
+ buttonAmbientColor->setFocusPolicy(Qt::NoFocus);
+ connect(buttonAmbientColor,SIGNAL(clicked(bool)),this,SLOT(buttonAmbientColorClicked()));
+
+ editAmbientFactor = new QLineEdit;
+ editAmbientFactor->setValidator(new QDoubleValidator);
+ editAmbientFactor->setText(QString("%1").arg(canvas->getAmbientFactor()));
+ middleLayout->addWidget(editAmbientFactor,0,2);
+ connect(editAmbientFactor,SIGNAL(editingFinished()),this,SLOT(editAmbientFactorFinished()));
+
+ QPushButton* buttonResetAmbientColor = new QPushButton("Reset");
+ middleLayout->addWidget(buttonResetAmbientColor,0,3);
+ buttonResetAmbientColor->setFocusPolicy(Qt::NoFocus);
+ connect(buttonResetAmbientColor,SIGNAL(clicked(bool)),this,SLOT(resetAmbientColorClicked()));
+
+
+ dummy.fill(canvas->getDirectiveColor());
+ buttonDirectiveColor = new QPushButton;
+ buttonDirectiveColor->setIcon(QIcon(dummy));
+ middleLayout->addWidget(buttonDirectiveColor,1,1);
+ buttonDirectiveColor->setFocusPolicy(Qt::NoFocus);
+ connect(buttonDirectiveColor,SIGNAL(clicked(bool)),this,SLOT(buttonDirectiveColorClicked()));
+
+ editDirectiveFactor = new QLineEdit;
+ editDirectiveFactor->setValidator(new QDoubleValidator);
+ editDirectiveFactor->setText(QString("%1").arg(canvas->getDirectiveFactor()));
+ middleLayout->addWidget(editDirectiveFactor,1,2);
+ connect(editDirectiveFactor,SIGNAL(editingFinished()),this,SLOT(editDirectiveFactorFinished()));
+
+ QPushButton* buttonResetDirectiveColor = new QPushButton("Reset");
+ middleLayout->addWidget(buttonResetDirectiveColor,1,3);
+ buttonResetDirectiveColor->setFocusPolicy(Qt::NoFocus);
+ connect(buttonResetDirectiveColor,SIGNAL(clicked(bool)),this,SLOT(resetDirectiveColorClicked()));
+
+ // Fill in directions
+
+ comboDirections = new QComboBox;
+ comboDirections->setFocusPolicy(Qt::NoFocus);
+ middleLayout->addWidget(comboDirections,2,1,1,2);
+ comboDirections->addItems(canvas->getNameDir());
+ comboDirections->setCurrentIndex(canvas->getCurrentLightDirection());
+ connect(comboDirections,SIGNAL(currentIndexChanged(int)),this,SLOT(comboDirectionsChanged(int)));
+
+ QPushButton* buttonResetDirection = new QPushButton("Reset");
+ middleLayout->addWidget(buttonResetDirection,2,3);
+ buttonResetDirection->setFocusPolicy(Qt::NoFocus);
+ connect(buttonResetDirection,SIGNAL(clicked(bool)),this,SLOT(resetDirection()));
+
+
+ groupWireFrame = new QFrame;
+ QGridLayout* groupWireFrameLayout = new QGridLayout;
+ groupWireFrame->setLayout(groupWireFrameLayout);
+
+ checkboxUseWireFrame = new QCheckBox("Add wireframe");
+ checkboxUseWireFrame->setChecked(canvas->getUseWire());
+ groupWireFrameLayout->addWidget(checkboxUseWireFrame,0,0);
+ checkboxUseWireFrame->setFocusPolicy(Qt::NoFocus);
+ connect(checkboxUseWireFrame,SIGNAL(stateChanged(int)),this,SLOT(checkboxUseWireFrameChanged()));
+
+ QLabel* labelWireColor = new QLabel("Wire Color");
+ groupWireFrameLayout->addWidget(labelWireColor,1,0);
+ dummy.fill(canvas->getWireColor());
+ buttonWireColor = new QPushButton;
+ buttonWireColor->setIcon(QIcon(dummy));
+ groupWireFrameLayout->addWidget(buttonWireColor,1,1);
+ buttonWireColor->setFocusPolicy(Qt::NoFocus);
+ QPushButton* buttonResetWireColor = new QPushButton("Reset");
+ buttonResetWireColor->setFocusPolicy(Qt::NoFocus);
+ groupWireFrameLayout->addWidget(buttonResetWireColor,1,3);
+ connect(buttonWireColor,SIGNAL(clicked(bool)),this,SLOT(buttonWireColorClicked()));
+ connect(buttonResetWireColor,SIGNAL(clicked(bool)),this,SLOT(resetWireColorClicked()));
+
+ labelWireWidth = new QLabel(QString("Wire Width : %1").arg((int)canvas->getWireWidth()));
+ groupWireFrameLayout->addWidget(labelWireWidth,2,0);
+ sliderWireWidth = new QSlider(Qt::Horizontal);
+ sliderWireWidth->setFocusPolicy(Qt::NoFocus);
+ sliderWireWidth->setRange(1,10);
+ sliderWireWidth->setTickPosition(QSlider::TicksBelow);
+ sliderWireWidth->setSingleStep(1);
+ sliderWireWidth->setPageStep(1);
+ sliderWireWidth->setValue((int)canvas->getWireWidth());
+ groupWireFrameLayout->addWidget(sliderWireWidth,2,1,1,2);
+ connect(sliderWireWidth,SIGNAL(valueChanged(int)),this,SLOT(sliderWireWidthChanged()));
+ QPushButton* buttonResetLineWidth = new QPushButton("Reset");
+ buttonResetLineWidth->setFocusPolicy(Qt::NoFocus);
+ groupWireFrameLayout->addWidget(buttonResetLineWidth,2,3);
+ connect(buttonResetLineWidth,SIGNAL(clicked(bool)),this,SLOT(resetWireWidthClicked()));
+
+ middleLayout->addWidget(groupWireFrame,3,0,3,4);
+
+ // Ok button
+ QWidget* boxButton = new QWidget;
+ QHBoxLayout* boxButtonLayout = new QHBoxLayout;
+ boxButton->setLayout(boxButtonLayout);
+ QFrame *spacerL = new QFrame;
+ spacerL->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding));
+ QPushButton* okButton = new QPushButton("Ok");
+ boxButtonLayout->addWidget(spacerL);
+ boxButtonLayout->addWidget(okButton);
+ this->layout()->addWidget(boxButton);
+ okButton->setFocusPolicy(Qt::NoFocus);
+ connect(okButton,SIGNAL(clicked(bool)),this,SLOT(okButtonClicked()));
+
+ QSettings settings;
+ if (!settings.value(PREFS_GEOM).isNull()) {
+ restoreGeometry(settings.value(PREFS_GEOM).toByteArray());
+ }
+
+ connect(canvas,SIGNAL(fallbackGlslUpdated(bool)),this,SLOT(onFallbackGlslUpdated(bool)));
+}
+
+void ShaderLightPrefs::buttonAmbientColorClicked() {
+ QColor newColor = QColorDialog::getColor(canvas->getAmbientColor(), this, QString("Choose color"),QColorDialog::DontUseNativeDialog);
+ if (newColor.isValid() == true)
+ {
+ canvas->setAmbientColor(newColor);
+ QPixmap dummy(20, 20);
+ dummy.fill(canvas->getAmbientColor());
+ buttonAmbientColor->setIcon(QIcon(dummy));
+ canvas->update();
+ }
+}
+
+void ShaderLightPrefs::editAmbientFactorFinished() {
+ canvas->setAmbientFactor(editAmbientFactor->text().toDouble());
+ canvas->update();
+}
+
+void ShaderLightPrefs::resetAmbientColorClicked() {
+ canvas->resetAmbientColor();
+ QPixmap dummy(20, 20);
+ dummy.fill(canvas->getAmbientColor());
+ buttonAmbientColor->setIcon(QIcon(dummy));
+ editAmbientFactor->setText(QString("%1").arg(canvas->getAmbientFactor()));
+ canvas->update();
+}
+
+void ShaderLightPrefs::buttonDirectiveColorClicked() {
+ QColor newColor = QColorDialog::getColor(canvas->getDirectiveColor(), this, QString("Choose color"),QColorDialog::DontUseNativeDialog);
+ if (newColor.isValid() == true)
+ {
+ canvas->setDirectiveColor(newColor);
+ QPixmap dummy(20, 20);
+ dummy.fill(canvas->getDirectiveColor());
+ buttonDirectiveColor->setIcon(QIcon(dummy));
+ canvas->update();
+ }
+}
+
+void ShaderLightPrefs::editDirectiveFactorFinished() {
+ canvas->setDirectiveFactor(editDirectiveFactor->text().toDouble());
+ canvas->update();
+}
+
+void ShaderLightPrefs::resetDirectiveColorClicked() {
+ canvas->resetDirectiveColor();
+ QPixmap dummy(20, 20);
+ dummy.fill(canvas->getDirectiveColor());
+ buttonDirectiveColor->setIcon(QIcon(dummy));
+ editDirectiveFactor->setText(QString("%1").arg(canvas->getDirectiveFactor()));
+ canvas->update();
+}
+
+void ShaderLightPrefs::okButtonClicked() {
+ this->close();
+}
+
+void ShaderLightPrefs::comboDirectionsChanged(int ind) {
+ canvas->setCurrentLightDirection(ind);
+ canvas->update();
+}
+
+void ShaderLightPrefs::resetDirection() {
+ canvas->resetCurrentLightDirection();
+ comboDirections->setCurrentIndex(canvas->getCurrentLightDirection());
+ canvas->update();
+}
+
+void ShaderLightPrefs::resizeEvent(QResizeEvent *event)
+{
+ QSettings().setValue(PREFS_GEOM, saveGeometry());
+ QWidget::resizeEvent(event);
+}
+
+void ShaderLightPrefs::moveEvent(QMoveEvent *event)
+{
+ QSettings().setValue(PREFS_GEOM, saveGeometry());
+ QWidget::moveEvent(event);
+}
+
+void ShaderLightPrefs::checkboxUseWireFrameChanged() {
+ bool state = checkboxUseWireFrame->isChecked();
+ canvas->setUseWire(state);
+ canvas->update();
+}
+
+void ShaderLightPrefs::buttonWireColorClicked() {
+ QColor newColor = QColorDialog::getColor(canvas->getWireColor(), this, QString("Choose color"),QColorDialog::DontUseNativeDialog);
+ if (newColor.isValid() == true)
+ {
+ canvas->setWireColor(newColor);
+ QPixmap dummy(20, 20);
+ dummy.fill(canvas->getWireColor());
+ buttonWireColor->setIcon(QIcon(dummy));
+ canvas->update();
+ }
+}
+
+void ShaderLightPrefs::resetWireColorClicked() {
+ canvas->resetWireColor();
+ QPixmap dummy(20, 20);
+ dummy.fill(canvas->getWireColor());
+ buttonWireColor->setIcon(QIcon(dummy));
+ canvas->update();
+}
+
+void ShaderLightPrefs::sliderWireWidthChanged() {
+ int lw = sliderWireWidth->value();
+ canvas->setWireWidth((double) lw);
+ labelWireWidth->setText(QString("Wire Width : %1").arg(lw));
+ canvas->update();
+}
+
+void ShaderLightPrefs::resetWireWidthClicked() {
+ canvas->resetWireWidth();
+ sliderWireWidth->setValue((int)canvas->getWireWidth());
+}
+
+void ShaderLightPrefs::onFallbackGlslUpdated(bool b) {
+ groupWireFrame->setDisabled(b);
+}
+
+void ShaderLightPrefs::toggleUseWire() {
+ // toggle if enable, no sense to do so otherwise
+ if (checkboxUseWireFrame->isEnabled())
+ checkboxUseWireFrame->toggle();
+}
diff --git a/src/shaderlightprefs.h b/src/shaderlightprefs.h
new file mode 100644
index 00000000..0e6b79ee
--- /dev/null
+++ b/src/shaderlightprefs.h
@@ -0,0 +1,63 @@
+#ifndef SHADERLIGHTPREFS_H
+#define SHADERLIGHTPREFS_H
+
+#include
+
+class Canvas;
+class QLabel;
+class QLineEdit;
+class QComboBox;
+class QCheckBox;
+class QSlider;
+class QFrame;
+
+class ShaderLightPrefs : public QDialog
+{
+ Q_OBJECT
+public:
+ ShaderLightPrefs(QWidget* parent, Canvas* _canvas);
+ void toggleUseWire();
+
+protected:
+ void resizeEvent(QResizeEvent *event) override;
+ void moveEvent(QMoveEvent *event) override;
+
+private slots:
+ void buttonAmbientColorClicked();
+ void editAmbientFactorFinished();
+ void resetAmbientColorClicked();
+
+ void buttonDirectiveColorClicked();
+ void editDirectiveFactorFinished();
+ void resetDirectiveColorClicked();
+
+ void comboDirectionsChanged(int ind);
+ void resetDirection();
+
+ void checkboxUseWireFrameChanged();
+ void buttonWireColorClicked();
+ void resetWireColorClicked();
+ void sliderWireWidthChanged();
+ void resetWireWidthClicked();
+
+ void okButtonClicked();
+ void onFallbackGlslUpdated(bool b);
+
+private:
+ Canvas* canvas;
+ QPushButton* buttonAmbientColor;
+ QLineEdit* editAmbientFactor;
+ QPushButton* buttonDirectiveColor;
+ QLineEdit* editDirectiveFactor;
+ QComboBox* comboDirections;
+
+ QFrame* groupWireFrame;
+ QCheckBox* checkboxUseWireFrame;
+ QPushButton* buttonWireColor;
+ QLabel* labelWireWidth;
+ QSlider* sliderWireWidth;
+
+ const static QString PREFS_GEOM;
+};
+
+#endif // SHADERLIGHTPREFS_H
diff --git a/src/window.cpp b/src/window.cpp
index db9e99a0..40e0d8cd 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -3,6 +3,7 @@
#include "window.h"
#include "canvas.h"
#include "loader.h"
+#include "shaderlightprefs.h"
#include
#include
@@ -15,6 +16,16 @@ const QString Window::PROJECTION_KEY = "projection";
const QString Window::DRAW_MODE_KEY = "drawMode";
const QString Window::WINDOW_GEOM_KEY = "windowGeometry";
const QString Window::RESET_TRANSFORM_ON_LOAD_KEY = "resetTransformOnLoad";
+const QString Window::HIDE_MENU_BAR = "hideMenuBar";
+
+const QKeySequence Window::shortcutOpen = Qt::Key_O;
+const QKeySequence Window::shortcutReload = Qt::Key_R;
+const QKeySequence Window::shortcutScreenshot = Qt::Key_S;
+const QKeySequence Window::shortcutQuit = Qt::Key_Q;
+const QKeySequence Window::shortcutDrawModeSettings = Qt::Key_P;
+const QKeySequence Window::shortcutDrawAxes = Qt::Key_A;
+const QKeySequence Window::shortcutHideMenuBar = Qt::Key_M;
+const QKeySequence Window::shortcutFullscreen = Qt::Key_F;
Window::Window(QWidget *parent) :
QMainWindow(parent),
@@ -26,6 +37,8 @@ Window::Window(QWidget *parent) :
shaded_action(new QAction("Shaded", this)),
wireframe_action(new QAction("Wireframe", this)),
surfaceangle_action(new QAction("Surface Angle", this)),
+ meshlight_action(new QAction("Shaded ambient and directive light source", this)),
+ drawModePrefs_action(new QAction("Draw Mode Settings")),
axes_action(new QAction("Draw Axes", this)),
invert_zoom_action(new QAction("Invert Zoom", this)),
reload_action(new QAction("Reload", this)),
@@ -34,6 +47,7 @@ Window::Window(QWidget *parent) :
hide_menuBar_action(new QAction("Hide Menu Bar", this)),
fullscreen_action(new QAction("Toggle Fullscreen",this)),
resetTransformOnLoadAction(new QAction("Reset rotation on load",this)),
+ setGLSizeAction(new QAction("Set Viewport Size",this)),
recent_files(new QMenu("Open recent", this)),
recent_files_group(new QActionGroup(this)),
recent_files_clear_action(new QAction("Clear recent files", this)),
@@ -54,25 +68,38 @@ Window::Window(QWidget *parent) :
canvas = new Canvas(format, this);
setCentralWidget(canvas);
+ canvas->update();
+
+ meshlightprefs = new ShaderLightPrefs(this, canvas);
+
+ QObject::connect(drawModePrefs_action, &QAction::triggered,this,&Window::on_drawModePrefs);
QObject::connect(watcher, &QFileSystemWatcher::fileChanged,
this, &Window::on_watched_change);
- open_action->setShortcut(QKeySequence::Open);
+ //open_action->setShortcut(QKeySequence::Open);
+ open_action->setShortcut(shortcutOpen);
+ open_action->setIcon(QIcon(":/qt/icons/document-open.png"));
QObject::connect(open_action, &QAction::triggered,
this, &Window::on_open);
this->addAction(open_action);
- quit_action->setShortcut(QKeySequence::Quit);
+ //quit_action->setShortcut(QKeySequence::Quit);
+ quit_action->setShortcut(shortcutQuit);
+ quit_action->setIcon(QIcon(":/qt/icons/exit.png"));
QObject::connect(quit_action, &QAction::triggered,
this, &Window::close);
this->addAction(quit_action);
autoreload_action->setCheckable(true);
+ autoreload_action->setIcon(QIcon(":/qt/icons/auto_refresh.png"));
QObject::connect(autoreload_action, &QAction::triggered,
this, &Window::on_autoreload_triggered);
- reload_action->setShortcut(QKeySequence::Refresh);
+ //reload_action->setShortcut(QKeySequence::Refresh);
+ reload_action->setShortcut(shortcutReload);
+ reload_action->setIcon(QIcon(":/qt/icons/view-refresh.png"));
+ this->addAction(reload_action);
reload_action->setEnabled(false);
QObject::connect(reload_action, &QAction::triggered,
this, &Window::on_reload);
@@ -86,6 +113,9 @@ Window::Window(QWidget *parent) :
this, &Window::on_load_recent);
save_screenshot_action->setCheckable(false);
+ save_screenshot_action->setShortcut(shortcutScreenshot);
+ save_screenshot_action->setIcon(QIcon(":/qt/icons/screenshot.png"));
+ this->addAction(save_screenshot_action);
QObject::connect(save_screenshot_action, &QAction::triggered,
this, &Window::on_save_screenshot);
@@ -101,9 +131,11 @@ Window::Window(QWidget *parent) :
file_menu->addAction(quit_action);
auto view_menu = menuBar()->addMenu("View");
- auto projection_menu = view_menu->addMenu("Projection");
+ projection_menu = view_menu->addMenu("Projection");
projection_menu->addAction(perspective_action);
+ perspective_action->setIcon(QIcon(":/qt/icons/perspective.png"));
projection_menu->addAction(orthographic_action);
+ orthographic_action->setIcon(QIcon(":/qt/icons/orthographic.png"));
auto projections = new QActionGroup(projection_menu);
for (auto p : {perspective_action, orthographic_action})
{
@@ -114,12 +146,17 @@ Window::Window(QWidget *parent) :
QObject::connect(projections, &QActionGroup::triggered,
this, &Window::on_projection);
- auto draw_menu = view_menu->addMenu("Draw Mode");
+ draw_menu = view_menu->addMenu("Draw Mode");
draw_menu->addAction(shaded_action);
draw_menu->addAction(wireframe_action);
draw_menu->addAction(surfaceangle_action);
+ draw_menu->addAction(meshlight_action);
+ shaded_action->setIcon(QIcon(":/qt/icons/sphere_shader1.png"));
+ wireframe_action->setIcon(QIcon(":/qt/icons/sphere_shader2.png"));
+ surfaceangle_action->setIcon(QIcon(":/qt/icons/sphere_shader3.png"));
+ meshlight_action->setIcon(QIcon(":/qt/icons/sphere_shader4.png"));
auto drawModes = new QActionGroup(draw_menu);
- for (auto p : {shaded_action, wireframe_action, surfaceangle_action})
+ for (auto p : {shaded_action, wireframe_action, surfaceangle_action, meshlight_action})
{
drawModes->addAction(p);
p->setCheckable(true);
@@ -127,39 +164,155 @@ Window::Window(QWidget *parent) :
drawModes->setExclusive(true);
QObject::connect(drawModes, &QActionGroup::triggered,
this, &Window::on_drawMode);
+ view_menu->addAction(drawModePrefs_action);
+ drawModePrefs_action->setShortcut(shortcutDrawModeSettings);
+ drawModePrefs_action->setIcon(QIcon(":/qt/icons/preferences-system.png"));
+ this->addAction(drawModePrefs_action);
+ drawModePrefs_action->setDisabled(true);
view_menu->addAction(axes_action);
axes_action->setCheckable(true);
- QObject::connect(axes_action, &QAction::triggered,
+ axes_action->setShortcut(shortcutDrawAxes);
+ axes_action->setIcon(QIcon(":/qt/icons/axes.png"));
+ this->addAction(axes_action);
+ QObject::connect(axes_action, &QAction::toggled,
this, &Window::on_drawAxes);
view_menu->addAction(invert_zoom_action);
invert_zoom_action->setCheckable(true);
+ invert_zoom_action->setIcon(QIcon(":/qt/icons/invert_zoom.png"));
QObject::connect(invert_zoom_action, &QAction::triggered,
this, &Window::on_invertZoom);
view_menu->addAction(resetTransformOnLoadAction);
resetTransformOnLoadAction->setCheckable(true);
+ resetTransformOnLoadAction->setIcon(QIcon(":/qt/icons/reset_rotation_on_load.png"));
QObject::connect(resetTransformOnLoadAction, &QAction::triggered,
this, &Window::on_resetTransformOnLoad);
view_menu->addAction(hide_menuBar_action);
- hide_menuBar_action->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_C);
+ hide_menuBar_action->setShortcut(shortcutHideMenuBar);
hide_menuBar_action->setCheckable(true);
QObject::connect(hide_menuBar_action, &QAction::toggled,
this, &Window::on_hide_menuBar);
+ // To have the shortcut work without the menu
this->addAction(hide_menuBar_action);
view_menu->addAction(fullscreen_action);
- fullscreen_action->setShortcut(Qt::Key_F11);
+ fullscreen_action->setShortcut(shortcutFullscreen);
+ fullscreen_action->setIcon(QIcon(":/qt/icons/view-fullscreen.png"));
fullscreen_action->setCheckable(true);
QObject::connect(fullscreen_action, &QAction::toggled,
this, &Window::on_fullscreen);
this->addAction(fullscreen_action);
+ QMenu *resolutionMenu = view_menu->addMenu("Set Viewport Size");
+ resolutionMenu->setIcon(QIcon(":/qt/icons/resolution_1_32.png"));
+ resolutionMenu->menuAction()->setIconVisibleInMenu(true);
+ QActionGroup* groupResolution = new QActionGroup(resolutionMenu);
+
+ QAction *quatreTiers = new QAction("-- 4:3",this);
+ quatreTiers->setDisabled(true);
+ resolutionMenu->addAction(quatreTiers);
+ QAction *setResolution0Action = new QAction("640 x 480 (VGA)",this);
+ resolutionMenu->addAction(setResolution0Action);
+ groupResolution->addAction(setResolution0Action);
+
+ QAction *setResolution1Action = new QAction("768 x 576 (PAL)",this);
+ resolutionMenu->addAction(setResolution1Action);
+ groupResolution->addAction(setResolution1Action);
+
+ QAction *setResolution2Action = new QAction("800 x 600 (SVGA)",this);
+ resolutionMenu->addAction(setResolution2Action);
+ groupResolution->addAction(setResolution2Action);
+
+ QAction *setResolution3Action = new QAction("1024 x 768 (XGA)",this);
+ resolutionMenu->addAction(setResolution3Action);
+ groupResolution->addAction(setResolution3Action);
+
+ QAction *seizeNeuf = new QAction("-- 16:9",this);
+ seizeNeuf->setDisabled(true);
+ resolutionMenu->addAction(seizeNeuf);
+
+ QAction *setResolution4Action = new QAction("800 x 480 (WVGA)",this);
+ resolutionMenu->addAction(setResolution4Action);
+ groupResolution->addAction(setResolution4Action);
+
+ QAction *setResolution5Action = new QAction("1024 x 576 (16:9 PAL)",this);
+ resolutionMenu->addAction(setResolution5Action);
+ groupResolution->addAction(setResolution5Action);
+
+ QAction *setResolution6Action = new QAction("1280 x 720 (HD720)",this);
+ resolutionMenu->addAction(setResolution6Action);
+ groupResolution->addAction(setResolution6Action);
+
+ resolutionMenu->addSeparator();
+
+// QAction *setCustomResolutionAction = new QAction("Custom Resolution",this);
+// //connect(setCustomResolutionAction,SIGNAL(triggered(bool)),this,SLOT(setCustomResolution()));
+// resolutionMenu->addAction(setCustomResolutionAction);
+
+ connect(groupResolution,SIGNAL(triggered(QAction*)),this,SLOT(setViewportSize(QAction*)));
auto help_menu = menuBar()->addMenu("Help");
help_menu->addAction(about_action);
+ // Toolbar
+ // First group
+ windowToolBar = new QToolBar;
+ windowToolBar->addAction(quit_action);
+ windowToolBar->addAction(open_action);
+ windowToolBar->addAction(reload_action);
+ windowToolBar->addAction(autoreload_action);
+
+ // preferences button here
+ windowToolBar->addSeparator();
+
+ // Second group
+ projectionButton = new QToolButton;
+ projectionButton->setPopupMode(QToolButton::InstantPopup);
+ projectionButton->setMenu(projection_menu);
+ projectionButton->setFocusPolicy(Qt::NoFocus); // we do not want the button to have keyboard focus
+ windowToolBar->addWidget(projectionButton);
+
+ shaderButton = new QToolButton;
+ shaderButton->setPopupMode(QToolButton::InstantPopup);
+ shaderButton->setMenu(draw_menu);
+ shaderButton->setFocusPolicy(Qt::NoFocus); // we do not want the button to have keyboard focus
+ windowToolBar->addWidget(shaderButton);
+ windowToolBar->addAction(drawModePrefs_action);
+
+ windowToolBar->addAction(axes_action);
+ windowToolBar->addAction(invert_zoom_action);
+ windowToolBar->addAction(resetTransformOnLoadAction);
+
+ windowToolBar->addSeparator();
+ // Third group
+
+ QToolButton* viewportSizeButton = new QToolButton;
+ viewportSizeButton->setPopupMode(QToolButton::InstantPopup);
+ viewportSizeButton->setMenu(resolutionMenu);
+ viewportSizeButton->setIcon(resolutionMenu->icon());
+ viewportSizeButton->setToolTip(resolutionMenu->title());
+ viewportSizeButton->setFocusPolicy(Qt::NoFocus); // we do not want the button to have keyboard focus
+ windowToolBar->addWidget(viewportSizeButton);
+
+ windowToolBar->addAction(save_screenshot_action);
+ windowToolBar->addAction(fullscreen_action);
+
+
+
+
+ // reset view here
+ // select views here
+ // slect shader here
+ // select gl size here
+
+
+
+
+
+
+ this->addToolBar(windowToolBar);
load_persist_settings();
}
@@ -180,13 +333,16 @@ void Window::load_persist_settings(){
axes_action->setChecked(draw_axes);
QString projection = settings.value(PROJECTION_KEY, "perspective").toString();
+ QAction* currentProjection;
if(projection == "perspective"){
canvas->view_perspective(Canvas::P_PERSPECTIVE, false);
- perspective_action->setChecked(true);
+ currentProjection = perspective_action;
}else{
canvas->view_perspective(Canvas::P_ORTHOGRAPHIC, false);
- orthographic_action->setChecked(true);
+ currentProjection = orthographic_action;
}
+ currentProjection->setChecked(true);
+ on_projection(currentProjection);
DrawMode draw_mode = (DrawMode)settings.value(DRAW_MODE_KEY, DRAWMODECOUNT).toInt();
@@ -194,12 +350,35 @@ void Window::load_persist_settings(){
{
draw_mode = shaded;
}
- canvas->set_drawMode(draw_mode);
- QAction* (dm_acts[]) = {shaded_action, wireframe_action, surfaceangle_action};
+ dm_acts = {shaded_action, wireframe_action, surfaceangle_action, meshlight_action};
dm_acts[draw_mode]->setChecked(true);
+ on_drawMode(dm_acts[draw_mode]);
+
+ // menu bar
+ bool hideMenu = settings.value(HIDE_MENU_BAR, false).toBool();
+ hide_menuBar_action->blockSignals(true);
+ hide_menuBar_action->setChecked(hideMenu);
+ on_hide_menuBar();
+ hide_menuBar_action->blockSignals(false);
resize(600, 400);
restoreGeometry(settings.value(WINDOW_GEOM_KEY).toByteArray());
+ if (this->isFullScreen()) {
+ fullscreen_action->blockSignals(true);
+ fullscreen_action->setChecked(true);
+ fullscreen_action->blockSignals(false);
+ }
+ }
+
+void Window::on_drawModePrefs() {
+ // For now only one draw mode has settings
+ // when settings for other draw mode will be available
+ // we will need to check the current mode
+ if (meshlightprefs->isVisible()) {
+ meshlightprefs->hide();
+ } else {
+ meshlightprefs->show();
+ }
}
void Window::on_open()
@@ -290,25 +469,42 @@ void Window::on_projection(QAction* proj)
canvas->view_perspective(Canvas::P_ORTHOGRAPHIC, true);
QSettings().setValue(PROJECTION_KEY, "orthographic");
}
+ projection_menu->setIcon(proj->icon());
+ projectionButton->setIcon(proj->icon());
+ projectionButton->setToolTip(QString("%1 : %2").arg(projection_menu->title()).arg(proj->toolTip()));
}
void Window::on_drawMode(QAction* act)
{
+ // On mode change hide prefs first
+ meshlightprefs->hide();
+
DrawMode mode;
if (act == shaded_action)
{
+ drawModePrefs_action->setEnabled(false);
mode = shaded;
}
else if (act == wireframe_action)
{
+ drawModePrefs_action->setEnabled(false);
mode = wireframe;
}
- else
+ else if (act == surfaceangle_action)
{
+ drawModePrefs_action->setEnabled(false);
mode = surfaceangle;
}
+ else if (act == meshlight_action)
+ {
+ drawModePrefs_action->setEnabled(true);
+ mode = meshlight;
+ }
canvas->set_drawMode(mode);
QSettings().setValue(DRAW_MODE_KEY, mode);
+ draw_menu->setIcon(act->icon());
+ shaderButton->setIcon(act->icon());
+ shaderButton->setToolTip(QString("%1 : %2").arg(draw_menu->title()).arg(act->toolTip()));
}
void Window::on_drawAxes(bool d)
@@ -399,6 +595,9 @@ void Window::on_save_screenshot()
void Window::on_hide_menuBar()
{
menuBar()->setVisible(!hide_menuBar_action->isChecked());
+ windowToolBar->setVisible(!hide_menuBar_action->isChecked());
+ QSettings settings;
+ settings.setValue(HIDE_MENU_BAR,hide_menuBar_action->isChecked());
}
void Window::rebuild_recent_files()
@@ -642,11 +841,19 @@ void Window::keyPressEvent(QKeyEvent* event)
{
load_next();
return;
- }
- else if (event->key() == Qt::Key_Escape)
- {
- hide_menuBar_action->setChecked(false);
+ } else if (event->key() == Qt::Key_Up) {
+ cycleShader(true);
+ return;
+ } else if (event->key() == Qt::Key_Down) {
+ cycleShader(false);
+ return;
+ } else if (event->key() == Qt::Key_Escape && !menuBar()->isVisible()) { // this is if user did not noticed the hide menu key
+ hide_menuBar_action->toggle();
return;
+ } else if (event->key() == Qt::Key_W) {
+ if (dm_acts.at(getCurrentShader()) == meshlight_action) {
+ meshlightprefs->toggleUseWire();
+ }
}
QMainWindow::keyPressEvent(event);
@@ -659,3 +866,46 @@ void Window::on_fullscreen() {
this->showNormal();
}
}
+
+int Window::getCurrentShader() {
+ int shadeNumber = dm_acts.size();
+ int current = 0;
+ for (int i=0; iisChecked()) {
+ current = i;
+ break;
+ }
+ }
+ return current;
+}
+
+void Window::cycleShader(bool up) {
+ int current = getCurrentShader();
+ int updown = up ? 1 : -1;
+ int nextS = (current + updown) % dm_acts.size();
+ nextS = nextS < 0 ? dm_acts.size() - 1 : nextS;
+ dm_acts.at(nextS)->setChecked(true);
+ on_drawMode(dm_acts.at(nextS));
+}
+
+
+// Resize the widget giving the canvas dimension
+// Useful for screenshot of given size.
+void Window::setCanvasSize(int w, int h) {
+ if (this->isFullScreen()) {
+ fullscreen_action->toggle();
+ }
+ int dw = this->size().width() - canvas->size().width();
+ int dh = this->size().height() - canvas->size().height();
+ this->resize(w + dw, h + dh);
+}
+
+void Window::setViewportSize(QAction* act) {
+ QString t = act->text();
+ QRegExp rx = QRegExp("^\\s*(\\d+).+(\\d+).*");
+ rx.indexIn(t);
+ QStringList desc = rx.capturedTexts();
+ int w = desc.at(1).toInt();
+ int h = desc.at(2).toInt();
+ setCanvasSize(w, h);
+}
diff --git a/src/window.h b/src/window.h
index 3efbeadd..31e5c130 100644
--- a/src/window.h
+++ b/src/window.h
@@ -5,8 +5,10 @@
#include
#include
#include
+#include
class Canvas;
+class ShaderLightPrefs;
class Window : public QMainWindow
{
@@ -16,6 +18,9 @@ class Window : public QMainWindow
bool load_stl(const QString& filename, bool is_reload=false);
bool load_prev(void);
bool load_next(void);
+ int getCurrentShader();
+ void cycleShader(bool);
+ void setCanvasSize(int w, int h);
protected:
void dragEnterEvent(QDragEnterEvent* event) override;
@@ -51,6 +56,8 @@ private slots:
void on_save_screenshot();
void on_fullscreen();
void on_hide_menuBar();
+ void on_drawModePrefs();
+ void setViewportSize(QAction* act);
private:
void rebuild_recent_files();
@@ -67,6 +74,8 @@ private slots:
QAction* const shaded_action;
QAction* const wireframe_action;
QAction* const surfaceangle_action;
+ QAction* const meshlight_action;
+ QAction* const drawModePrefs_action;
QAction* const axes_action;
QAction* const invert_zoom_action;
QAction* const reload_action;
@@ -75,8 +84,15 @@ private slots:
QAction* const hide_menuBar_action;
QAction* const fullscreen_action;
QAction* const resetTransformOnLoadAction;
+ QAction* const setGLSizeAction;
QMenu* const recent_files;
+ QMenu* draw_menu;
+ QToolButton* shaderButton;
+ QToolBar* windowToolBar;
+ QMenu* projection_menu;
+ QToolButton* projectionButton;
+
QActionGroup* const recent_files_group;
QAction* const recent_files_clear_action;
const static int MAX_RECENT_FILES=8;
@@ -88,6 +104,17 @@ private slots:
const static QString DRAW_MODE_KEY;
const static QString WINDOW_GEOM_KEY;
const static QString RESET_TRANSFORM_ON_LOAD_KEY;
+ const static QString HIDE_MENU_BAR;
+
+
+ const static QKeySequence shortcutOpen;
+ const static QKeySequence shortcutReload;
+ const static QKeySequence shortcutScreenshot;
+ const static QKeySequence shortcutQuit;
+ const static QKeySequence shortcutDrawModeSettings;
+ const static QKeySequence shortcutDrawAxes;
+ const static QKeySequence shortcutHideMenuBar;
+ const static QKeySequence shortcutFullscreen;
QString current_file;
QString lookup_folder;
@@ -96,6 +123,9 @@ private slots:
QFileSystemWatcher* watcher;
Canvas* canvas;
+
+ ShaderLightPrefs* meshlightprefs;
+ QList dm_acts;
};
#endif // WINDOW_H
diff --git a/xdg/README.txt b/xdg/README.txt
new file mode 100644
index 00000000..7aad2b0f
--- /dev/null
+++ b/xdg/README.txt
@@ -0,0 +1,23 @@
+Linux :
+-----------
+desktop file and application icons installation.
+This tells the system that fstl knows to open stl files and allow stl to
+be launched using windows key.
+
+Install :
+./xdg_install.sh fstl
+
+Uninstall :
+./xdg_uninstall.sh fstl
+
+if runned as regular user this will install locally in :
+ $HOME/.local/share/mime/
+ $HOME/.local/share/applications/
+ $HOME/.local/share/icons/
+
+if runned as root this will install system-wide in :
+ /usr/share/mime
+ /usr/share/applications
+ /usr/share/icons
+
+Third script xdg_package_install.sh is to be used when building deb or rpm package.
diff --git a/xdg/fstlapp-fstl.desktop b/xdg/fstlapp-fstl.desktop
new file mode 100644
index 00000000..b4e93c5b
--- /dev/null
+++ b/xdg/fstlapp-fstl.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Name=fstl
+GenericName=Fast STL Viewer
+Exec=fstl %U
+Terminal=false
+Icon=fstlapp-fstl
+Type=Application
+MimeType=model/stl;
+Categories=Utility;
diff --git a/xdg/icons/fstlapp-fstl_128x128.png b/xdg/icons/fstlapp-fstl_128x128.png
new file mode 100644
index 00000000..0c312003
Binary files /dev/null and b/xdg/icons/fstlapp-fstl_128x128.png differ
diff --git a/xdg/icons/fstlapp-fstl_16x16.png b/xdg/icons/fstlapp-fstl_16x16.png
new file mode 100644
index 00000000..d53992e2
Binary files /dev/null and b/xdg/icons/fstlapp-fstl_16x16.png differ
diff --git a/xdg/icons/fstlapp-fstl_22x22.png b/xdg/icons/fstlapp-fstl_22x22.png
new file mode 100644
index 00000000..40e760eb
Binary files /dev/null and b/xdg/icons/fstlapp-fstl_22x22.png differ
diff --git a/xdg/icons/fstlapp-fstl_256x256.png b/xdg/icons/fstlapp-fstl_256x256.png
new file mode 100644
index 00000000..4235dc58
Binary files /dev/null and b/xdg/icons/fstlapp-fstl_256x256.png differ
diff --git a/xdg/icons/fstlapp-fstl_32x32.png b/xdg/icons/fstlapp-fstl_32x32.png
new file mode 100644
index 00000000..8bab67ea
Binary files /dev/null and b/xdg/icons/fstlapp-fstl_32x32.png differ
diff --git a/xdg/icons/fstlapp-fstl_48x48.png b/xdg/icons/fstlapp-fstl_48x48.png
new file mode 100644
index 00000000..851d8bd4
Binary files /dev/null and b/xdg/icons/fstlapp-fstl_48x48.png differ
diff --git a/xdg/icons/fstlapp-fstl_64x64.png b/xdg/icons/fstlapp-fstl_64x64.png
new file mode 100644
index 00000000..0f83e6bf
Binary files /dev/null and b/xdg/icons/fstlapp-fstl_64x64.png differ
diff --git a/xdg/xdg_install.sh b/xdg/xdg_install.sh
new file mode 100755
index 00000000..b9d59b20
--- /dev/null
+++ b/xdg/xdg_install.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+# This script will install mimetypes, icons and desktop file,
+# it takes a name in argument
+#
+# if runned as regular user this will install locally in :
+# $HOME/.local/share/mime/
+# $HOME/.local/share/applications/
+# $HOME/.local/share/icons/
+#
+# if runned as root this will install system-wide in :
+# /usr/share/mime
+# /usr/share/applications
+# /usr/share/icons
+
+if [ $# != 1 ]; then
+ echo "You must provide an application name"
+ exit 1
+fi
+
+name=$1
+
+# echo "Installing mimetypes"
+# xdg-mime install fstlapp-$name-mimetypes.xml
+
+echo "Installing desktop file"
+xdg-desktop-menu install fstlapp-$name.desktop
+
+echo "Installing apps icons"
+iclist="fstlapp-$name"
+for im in $iclist
+do
+ xdg-icon-resource install --theme hicolor --context apps --size 16 icons/${im}_16x16.png $im
+ xdg-icon-resource install --theme hicolor --context apps --size 22 icons/${im}_22x22.png $im
+ xdg-icon-resource install --theme hicolor --context apps --size 32 icons/${im}_32x32.png $im
+ xdg-icon-resource install --theme hicolor --context apps --size 48 icons/${im}_48x48.png $im
+ xdg-icon-resource install --theme hicolor --context apps --size 64 icons/${im}_64x64.png $im
+ xdg-icon-resource install --theme hicolor --context apps --size 128 icons/${im}_128x128.png $im
+ xdg-icon-resource install --theme hicolor --context apps --size 256 icons/${im}_256x256.png $im
+done
+
+# echo "Installing mimetypes icons"
+# iclist="`cat fstlapp-$name-mimetypes.xml | grep "icon name" | sed 's/^.*"\(.*\)".*$/\1/'`"
+# for im in $iclist
+# do
+# xdg-icon-resource install --theme hicolor --context mimetypes --size 16 icons/${im}_16x16.png $im
+# xdg-icon-resource install --theme hicolor --context mimetypes --size 22 icons/${im}_22x22.png $im
+# xdg-icon-resource install --theme hicolor --context mimetypes --size 32 icons/${im}_32x32.png $im
+# xdg-icon-resource install --theme hicolor --context mimetypes --size 48 icons/${im}_48x48.png $im
+# xdg-icon-resource install --theme hicolor --context mimetypes --size 64 icons/${im}_64x64.png $im
+# done
+
diff --git a/xdg/xdg_package_install.sh b/xdg/xdg_package_install.sh
new file mode 100755
index 00000000..7e19a420
--- /dev/null
+++ b/xdg/xdg_package_install.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+# For a package installation (rpm or deb), we must proceed a different way
+# This script takes two arguments, the first one is the installation
+# prefix and the second is the name
+
+if [ $# != 2 ]; then
+ echo "You must provide two arguments"
+ exit 1
+fi
+
+base=$1
+name=$2
+
+# echo "Drop mimetypes file in /usr/share/mime/packages/"
+# mkdir -p $base/usr/share/mime/packages/
+# cp fstlapp-$name-mimetypes.xml $base/usr/share/mime/packages/
+
+echo "Drop desktop file in /usr/share/applications/"
+mkdir -p $base/usr/share/applications/
+cp fstlapp-$name.desktop $base/usr/share/applications/
+
+slist="16 22 32 48 64 128 256"
+echo "Installing apps icons"
+iclist="fstlapp-$name"
+for im in $iclist
+do
+ for s in $slist
+ do
+ mkdir -p $base/usr/share/icons/hicolor/${s}x${s}/apps
+ cp icons/${im}_${s}x${s}.png $base/usr/share/icons/hicolor/${s}x${s}/apps/$im.png
+ done
+done
+
+# echo "Installing mimetypes icons"
+# iclist="`cat fstlapp-$name-mimetypes.xml | grep "icon name" | sed 's/^.*"\(.*\)".*$/\1/'`"
+# for im in $iclist
+# do
+# for s in $slist
+# do
+# mkdir -p $base/usr/share/icons/hicolor/${s}x${s}/mimetypes
+# cp icons/${im}_${s}x${s}.png $base/usr/share/icons/hicolor/${s}x${s}/mimetypes/$im.png
+# done
+# done
+
+#
+# Put this in the post installation and post uninstallation scripts
+#
+#echo "Updating mime database"
+#update-mime-database /usr/share/mim
+#
+#echo "Updating desktop database"
+#update-desktop-database
diff --git a/xdg/xdg_uninstall.sh b/xdg/xdg_uninstall.sh
new file mode 100755
index 00000000..1dd7ef4f
--- /dev/null
+++ b/xdg/xdg_uninstall.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+# This script will uninstall mimetypes, icons and desktop file
+#
+# if runned as regular user this will uninstall locally from :
+# $HOME/.local/share/mime/
+# $HOME/.local/share/applications/
+# $HOME/.local/share/icons/
+#
+# if runned as root this will uninstall system-wide from :
+# /usr/share/mime
+# /usr/share/applications
+# /usr/share/icons
+
+if [ $# != 1 ]; then
+ echo "You must provide a name"
+ exit 1
+fi
+
+name=$1
+
+# echo "Uninstalling mimetypes"
+# xdg-mime uninstall fstlapp-$name-mimetypes.xml
+
+echo "Uninstalling desktop file"
+xdg-desktop-menu uninstall fstlapp-$name.desktop
+
+echo "Uninstalling apps icons"
+iclist="fstlapp-$name"
+for im in $iclist
+do
+ xdg-icon-resource uninstall --theme hicolor --context apps --size 16 $im
+ xdg-icon-resource uninstall --theme hicolor --context apps --size 22 $im
+ xdg-icon-resource uninstall --theme hicolor --context apps --size 32 $im
+ xdg-icon-resource uninstall --theme hicolor --context apps --size 48 $im
+ xdg-icon-resource uninstall --theme hicolor --context apps --size 64 $im
+ xdg-icon-resource uninstall --theme hicolor --context apps --size 128 $im
+ xdg-icon-resource uninstall --theme hicolor --context apps --size 256 $im
+done
+
+# echo "Uninstalling mimetypes icons"
+# iclist="`cat fstlapp-$name-mimetypes.xml | grep "icon name" | sed 's/^.*"\(.*\)".*$/\1/'`"
+# for im in $iclist
+# do
+# xdg-icon-resource uninstall --theme hicolor --context mimetypes --size 16 $im
+# xdg-icon-resource uninstall --theme hicolor --context mimetypes --size 22 $im
+# xdg-icon-resource uninstall --theme hicolor --context mimetypes --size 32 $im
+# xdg-icon-resource uninstall --theme hicolor --context mimetypes --size 48 $im
+# xdg-icon-resource uninstall --theme hicolor --context mimetypes --size 64 $im
+# done