Commit 5d3cefcc authored by Ronan's avatar Ronan
Browse files

feat(app): add camera component used by Calls views

parent 8de2b05b
......@@ -55,6 +55,7 @@ set(SOURCES
src/app/Database.cpp
src/app/DefaultTranslator.cpp
src/app/Logger.cpp
src/components/camera/Camera.cpp
src/components/chat/ChatModel.cpp
src/components/chat/ChatProxyModel.cpp
src/components/contacts/ContactModel.cpp
......@@ -76,6 +77,7 @@ set(HEADERS
src/app/Database.hpp
src/app/DefaultTranslator.hpp
src/app/Logger.hpp
src/components/camera/Camera.hpp
src/components/chat/ChatModel.hpp
src/components/chat/ChatProxyModel.hpp
src/components/contacts/ContactModel.hpp
......
......@@ -4,6 +4,7 @@
#include <QQuickView>
#include <QtDebug>
#include "../components/camera/Camera.hpp"
#include "../components/chat/ChatProxyModel.hpp"
#include "../components/contacts/ContactsListModel.hpp"
#include "../components/contacts/ContactsListProxyModel.hpp"
......@@ -21,7 +22,7 @@
#define QML_VIEW_MAIN_WINDOW "qrc:/ui/views/App/MainWindow/MainWindow.qml"
#define QML_VIEW_CALL_WINDOW "qrc:/ui/views/App/Calls/Calls.qml"
// ===================================================================
// =============================================================================
App *App::m_instance = nullptr;
......@@ -102,6 +103,8 @@ void App::registerTypes () {
);
// Register models.
qmlRegisterType<Camera>("Linphone", 1, 0, "Camera");
qmlRegisterUncreatableType<ContactModel>(
"Linphone", 1, 0, "ContactModel", "ContactModel is uncreatable"
);
......@@ -163,14 +166,17 @@ void App::setTrayIcon () {
root->connect(restore_action, &QAction::triggered, root, &QQuickWindow::showNormal);
// trayIcon: Left click actions.
root->connect(m_system_tray_icon, &QSystemTrayIcon::activated, [root](QSystemTrayIcon::ActivationReason reason) {
if (reason == QSystemTrayIcon::Trigger) {
if (root->visibility() == QWindow::Hidden)
root->showNormal();
else
root->hide();
root->connect(
m_system_tray_icon, &QSystemTrayIcon::activated, [root](
QSystemTrayIcon::ActivationReason reason) {
if (reason == QSystemTrayIcon::Trigger) {
if (root->visibility() == QWindow::Hidden)
root->showNormal();
else
root->hide();
}
}
});
);
// Build trayIcon menu.
menu->addAction(restore_action);
......
#include <QOpenGLFunctions>
#include "Camera.hpp"
#define ATTRIBUTE_VERTEX 0
// =============================================================================
static const char *_vertex_shader = "attribute vec2 vertex;"
"uniform mat4 projection;"
"void main() {"
" gl_Position = projection * vec4(vertex.xy, 0, 1);"
"}";
static const char *_fragment_shader = "void main() {"
" gl_FragColor = vec4(vec3(1.0, 0.0, 0.0), 1.0);"
"}";
static const GLfloat _camera_vertices[] = {
0.0f, 0.0f,
50.0f, 0.0f,
0.0f, 50.0f,
50.0f, 50.0f
};
// -----------------------------------------------------------------------------
struct CameraStateBinder {
CameraStateBinder (CameraRenderer *renderer) : m_renderer(renderer) {
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
f->glEnable(GL_DEPTH_TEST);
f->glEnable(GL_CULL_FACE);
f->glDepthMask(GL_TRUE);
f->glDepthFunc(GL_LESS);
f->glFrontFace(GL_CCW);
f->glCullFace(GL_BACK);
m_renderer->m_program->bind();
}
~CameraStateBinder () {
m_renderer->m_program->release();
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
f->glDisable(GL_CULL_FACE);
f->glDisable(GL_DEPTH_TEST);
}
CameraRenderer *m_renderer;
};
// -----------------------------------------------------------------------------
QOpenGLFramebufferObject *CameraRenderer::createFramebufferObject (const QSize &size) {
m_projection.setToIdentity();
m_projection.ortho(
0, size.width(),
0, size.height(),
-1, 1
);
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
format.setSamples(4);
return new QOpenGLFramebufferObject(size, format);
}
void CameraRenderer::render () {
init();
m_vao.bind();
CameraStateBinder state(this);
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
f->glClearColor(0.f, 0.f, 0.f, 1.f);
f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_program->setUniformValue(m_projection_loc, m_projection);
// Draw.
f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
m_vao.release();
}
void CameraRenderer::init () {
if (m_inited)
return;
m_inited = true;
initProgram();
initBuffer();
}
void CameraRenderer::initBuffer () {
QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
m_vbo.create();
m_vbo.bind();
m_vbo.allocate(&_camera_vertices, sizeof _camera_vertices);
m_vbo.bind();
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
f->glEnableVertexAttribArray(ATTRIBUTE_VERTEX);
f->glVertexAttribPointer(ATTRIBUTE_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, 0);
m_vbo.release();
}
void CameraRenderer::initProgram () {
m_program.reset(new QOpenGLShaderProgram());
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, _vertex_shader);
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, _fragment_shader);
m_program->bindAttributeLocation("vertex", ATTRIBUTE_VERTEX);
m_program->link();
m_projection_loc = m_program->uniformLocation("projection");
}
// -----------------------------------------------------------------------------
Camera::Camera (QQuickItem *parent) : QQuickFramebufferObject(parent) {
setAcceptHoverEvents(true);
setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton);
}
QQuickFramebufferObject::Renderer *Camera::createRenderer () const {
return new CameraRenderer();
}
void Camera::hoverMoveEvent (QHoverEvent *) {}
void Camera::mousePressEvent (QMouseEvent *) {
setFocus(true);
}
void Camera::keyPressEvent (QKeyEvent *) {}
#ifndef CAMERA_H_
#define CAMERA_H_
#include <QOpenGLBuffer>
#include <QOpenGLFramebufferObject>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QQuickFramebufferObject>
// =============================================================================
class CameraRenderer : public QQuickFramebufferObject::Renderer {
friend struct CameraStateBinder;
public:
QOpenGLFramebufferObject *createFramebufferObject (const QSize &size) override;
void render () override;
private:
void init ();
void initBuffer ();
void initProgram ();
bool m_inited = false;
QMatrix4x4 m_projection;
int m_projection_loc;
QOpenGLVertexArrayObject m_vao;
QOpenGLBuffer m_vbo;
QScopedPointer<QOpenGLShaderProgram> m_program;
};
// -----------------------------------------------------------------------------
class Camera : public QQuickFramebufferObject {
Q_OBJECT;
public:
Camera (QQuickItem *parent = Q_NULLPTR);
~Camera () = default;
QQuickFramebufferObject::Renderer *createRenderer () const override;
protected:
void hoverMoveEvent (QHoverEvent *event) override;
void mousePressEvent (QMouseEvent *event) override;
void keyPressEvent (QKeyEvent *event) override;
};
#endif // CAMERA_H_
......@@ -8,7 +8,7 @@ import LinphoneUtils 1.0
import App.Styles 1.0
// ===================================================================
// =============================================================================
Rectangle {
id: call
......@@ -20,7 +20,7 @@ Rectangle {
sipAddress
) || sipAddress
// -----------------------------------------------------------------
// ---------------------------------------------------------------------------
color: StartingCallStyle.backgroundColor
......@@ -32,11 +32,11 @@ Rectangle {
spacing: 0
// ---------------------------------------------------------------
// -------------------------------------------------------------------------
// Call info.
// ---------------------------------------------------------------
// -------------------------------------------------------------------------
RowLayout {
Item {
id: info
Layout.fillWidth: true
......@@ -45,15 +45,29 @@ Rectangle {
Layout.preferredHeight: StartingCallStyle.contactDescriptionHeight
Icon {
iconSize: 40
id: callQuality
anchors.left: parent.left
icon: 'call_quality_' + 2
iconSize: 40
}
Item {
Layout.fillWidth: true
ContactDescription {
id: contactDescription
anchors.centerIn: parent
horizontalTextAlignment: Text.AlignHCenter
sipAddress: call.sipAddress
username: LinphoneUtils.getContactUsername(_contact)
height: parent.height
width: parent.width - cameraActions.width - callQuality.width - 150
}
ActionBar {
id: cameraActions
anchors.right: parent.right
iconSize: 40
ActionButton {
......@@ -70,18 +84,9 @@ Rectangle {
}
}
ContactDescription {
id: contactDescription
anchors.fill: info
username: LinphoneUtils.getContactUsername(_contact)
sipAddress: call.sipAddress
horizontalTextAlignment: Text.AlignHCenter
}
// ---------------------------------------------------------------
// -------------------------------------------------------------------------
// Contact visual.
// ---------------------------------------------------------------
// -------------------------------------------------------------------------
Item {
id: container
......@@ -90,26 +95,41 @@ Rectangle {
Layout.fillHeight: true
Layout.margins: StartingCallStyle.containerMargins
Avatar {
Component {
id: avatar
function _computeAvatarSize () {
var height = container.height
var width = container.width
Avatar {
function _computeAvatarSize () {
var height = container.height
var width = container.width
var size = height < StartingCallStyle.avatar.maxSize && height > 0
? height
: StartingCallStyle.avatar.maxSize
return size < width ? size : width
}
backgroundColor: StartingCallStyle.avatar.backgroundColor
image: _contact.avatar
username: contactDescription.username
var size = height < StartingCallStyle.avatar.maxSize && height > 0
? height
: StartingCallStyle.avatar.maxSize
return size < width ? size : width
height: _computeAvatarSize()
width: height
}
}
anchors.centerIn: parent
backgroundColor: StartingCallStyle.avatar.backgroundColor
image: _contact.avatar
username: contactDescription.username
Component {
id: camera
Camera {
height: container.height
width: container.width
}
}
height: _computeAvatarSize()
width: height
Loader {
anchors.centerIn: parent
sourceComponent: isVideoCall ? camera : avatar
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment