mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-24 15:18:07 +00:00
feat(app): add camera component used by Calls views
This commit is contained in:
parent
8de2b05b53
commit
5d3cefccc3
5 changed files with 262 additions and 41 deletions
|
|
@ -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);
|
||||
|
|
|
|||
140
tests/src/components/camera/Camera.cpp
Normal file
140
tests/src/components/camera/Camera.cpp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
#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 *) {}
|
||||
53
tests/src/components/camera/Camera.hpp
Normal file
53
tests/src/components/camera/Camera.hpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#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
|
||||
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
|
||||
|
||||
height: _computeAvatarSize()
|
||||
width: height
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: camera
|
||||
|
||||
Camera {
|
||||
height: container.height
|
||||
width: container.width
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
backgroundColor: StartingCallStyle.avatar.backgroundColor
|
||||
image: _contact.avatar
|
||||
username: contactDescription.username
|
||||
|
||||
height: _computeAvatarSize()
|
||||
width: height
|
||||
sourceComponent: isVideoCall ? camera : avatar
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue