ewol/sources/ewol/renderer/os/eSystemInput.cpp

437 lines
17 KiB
C++

/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license BSD v3 (see license file)
*/
#include <etk/types.h>
#include <etk/UString.h>
#include <ewol/debug.h>
#include <ewol/ewol.h>
#include <ewol/eObject/EObject.h>
#include <ewol/eObject/EObjectManager.h>
#include <ewol/renderer/os/gui.h>
#include <ewol/renderer/os/eSystem.h>
#include <ewol/renderer/os/eSystemInput.h>
#include <ewol/renderer/resources/Texture.h>
#include <ewol/widget/Widget.h>
#include <ewol/widget/Windows.h>
#include <ewol/widget/WidgetManager.h>
#define EVENT_DEBUG EWOL_VERBOSE
//#define EVENT_DEBUG EWOL_DEBUG
void ewol::eSystemInput::CalculateLimit(void)
{
m_eventInputLimit.sepatateTime = 300000; // µs
m_eventInputLimit.DpiOffset = m_dpi*100;
m_eventMouseLimit.sepatateTime = 300000; // µs
m_eventMouseLimit.DpiOffset = (float)m_dpi*(float)0.1;
}
void ewol::eSystemInput::SetDpi(int32_t newDPI)
{
m_dpi = newDPI;
// recalculate the DPI system ...
CalculateLimit();
}
bool ewol::eSystemInput::localEventInput(ewol::keyEvent::type_te _type,
ewol::Widget* _destWidget,
int32_t _IdInput,
ewol::keyEvent::status_te _status,
vec2 _pos)
{
if (NULL != _destWidget) {
if (_type == ewol::keyEvent::typeMouse || _type == ewol::keyEvent::typeFinger) {
// create the system Event :
ewol::EventInputSystem tmpEventSystem(_type, _status, _IdInput, _pos, _destWidget, 0); // TODO : set the real ID ...
// generate the event :
return _destWidget->SystemEventInput(tmpEventSystem);
} else {
return false;
}
}
return false;
}
void ewol::eSystemInput::AbortElement(InputPoperty_ts *_eventTable, int32_t _idInput, ewol::keyEvent::type_te _type)
{
if (NULL==_eventTable) {
return;
}
if (_eventTable[_idInput].isUsed==true) {
localEventInput(_type,
_eventTable[_idInput].curentWidgetEvent,
_eventTable[_idInput].destinationInputId,
ewol::keyEvent::statusAbort,
_eventTable[_idInput].posEvent);
}
}
void ewol::eSystemInput::CleanElement(InputPoperty_ts *_eventTable, int32_t _idInput)
{
if (NULL==_eventTable) {
return;
}
//EWOL_INFO("CleanElement[" << idInput << "] = @" << (int64_t)eventTable);
_eventTable[_idInput].isUsed = false;
_eventTable[_idInput].destinationInputId = 0;
_eventTable[_idInput].lastTimeEvent = 0;
_eventTable[_idInput].curentWidgetEvent = NULL;
_eventTable[_idInput].origin.setValue(0,0);
_eventTable[_idInput].size.setValue(99999999,99999999);
_eventTable[_idInput].downStart.setValue(0,0);
_eventTable[_idInput].isDown = false;
_eventTable[_idInput].isInside = false;
_eventTable[_idInput].nbClickEvent = 0;
_eventTable[_idInput].posEvent.setValue(0,0);
}
void ewol::eSystemInput::TransfertEvent(ewol::Widget* source, ewol::Widget* destination)
{
if( NULL == source
|| NULL == destination) {
// prevent errors ...
return;
}
for(int32_t iii=0; iii<MAX_MANAGE_INPUT; iii++) {
if (m_eventInputSaved[iii].curentWidgetEvent == source) {
// inform the widget that it does not receive the event now
EVENT_DEBUG("GUI : Input ID=" << iii << "==>" << m_eventInputSaved[iii].destinationInputId << " [EVENT_INPUT_TYPE_ABORT] " << m_eventInputSaved[iii].posEvent);
localEventInput(ewol::keyEvent::typeFinger, m_eventInputSaved[iii].curentWidgetEvent, m_eventInputSaved[iii].destinationInputId, ewol::keyEvent::statusAbort, m_eventInputSaved[iii].posEvent);
// set the new widget ...
m_eventInputSaved[iii].curentWidgetEvent = destination;
// inform the widget that he receive the event property now...
EVENT_DEBUG("GUI : Input ID=" << iii << "==>" << m_eventInputSaved[iii].destinationInputId << " [EVENT_INPUT_TYPE_TRANSFERT] " << m_eventInputSaved[iii].posEvent);
localEventInput(ewol::keyEvent::typeFinger, m_eventInputSaved[iii].curentWidgetEvent, m_eventInputSaved[iii].destinationInputId, ewol::keyEvent::statusTransfert, m_eventInputSaved[iii].posEvent);
}
if (m_eventMouseSaved[iii].curentWidgetEvent == source) {
// inform the widget that it does not receive the event now
EVENT_DEBUG("GUI : Input ID=" << iii << "==>" << m_eventMouseSaved[iii].destinationInputId << " [EVENT_INPUT_TYPE_ABORT] " << m_eventMouseSaved[iii].posEvent);
localEventInput(ewol::keyEvent::typeMouse, m_eventMouseSaved[iii].curentWidgetEvent, m_eventMouseSaved[iii].destinationInputId, ewol::keyEvent::statusAbort, m_eventMouseSaved[iii].posEvent);
// set the new widget ...
m_eventMouseSaved[iii].curentWidgetEvent = destination;
// inform the widget that he receive the event property now...
EVENT_DEBUG("GUI : Input ID=" << iii << "==>" << m_eventMouseSaved[iii].destinationInputId << " [EVENT_INPUT_TYPE_TRANSFERT] " << m_eventMouseSaved[iii].posEvent);
localEventInput(ewol::keyEvent::typeMouse, m_eventMouseSaved[iii].curentWidgetEvent, m_eventMouseSaved[iii].destinationInputId, ewol::keyEvent::statusTransfert, m_eventMouseSaved[iii].posEvent);
}
}
}
void ewol::eSystemInput::GrabPointer(ewol::Widget* widget)
{
if(NULL==widget) {
return;
}
m_grabWidget = widget;
guiInterface::GrabPointerEvents(true, widget->GetOrigin() + ivec2(widget->GetSize().x()/2.0f, widget->GetSize().y()/2.0f) );
}
void ewol::eSystemInput::UnGrabPointer(void)
{
m_grabWidget = NULL;
guiInterface::GrabPointerEvents(false, vec2(0,0));
}
void ewol::eSystemInput::OnObjectRemove(ewol::EObject * removeObject)
{
for(int32_t iii=0; iii<MAX_MANAGE_INPUT; iii++) {
if (m_eventInputSaved[iii].curentWidgetEvent == removeObject) {
// remove the property of this input ...
CleanElement(m_eventInputSaved, iii);
}
if (m_eventMouseSaved[iii].curentWidgetEvent == removeObject) {
// remove the property of this input ...
CleanElement(m_eventMouseSaved, iii);
}
}
}
void ewol::eSystemInput::NewLayerSet(void)
{
for(int32_t iii=0; iii<MAX_MANAGE_INPUT; iii++) {
// remove the property of this input ...
AbortElement(m_eventInputSaved, iii, ewol::keyEvent::typeFinger);
CleanElement(m_eventInputSaved, iii);
AbortElement(m_eventMouseSaved, iii, ewol::keyEvent::typeMouse);
CleanElement(m_eventMouseSaved, iii);
}
}
void ewol::eSystemInput::Reset(void)
{
for(int32_t iii=0; iii<MAX_MANAGE_INPUT; iii++) {
// remove the property of this input ...
CleanElement(m_eventInputSaved, iii);
CleanElement(m_eventMouseSaved, iii);
}
}
ewol::eSystemInput::eSystemInput(void) :
m_grabWidget(NULL)
{
SetDpi(200);
EWOL_INFO("Init (start)");
Reset();
EWOL_INFO("Init (end)");
}
ewol::eSystemInput::~eSystemInput(void)
{
EWOL_INFO("Un-Init (start)");
Reset();
EWOL_INFO("Un-Init (end)");
}
int32_t ewol::eSystemInput::localGetDestinationId(ewol::keyEvent::type_te type, ewol::Widget* destWidget, int32_t realInputId)
{
if (type == ewol::keyEvent::typeFinger) {
int32_t lastMinimum = 0;
for(int32_t iii=0; iii<MAX_MANAGE_INPUT; iii++) {
if (true==m_eventInputSaved[iii].isUsed) {
if (m_eventInputSaved[iii].curentWidgetEvent == destWidget) {
if (iii != realInputId) {
lastMinimum = etk_max(lastMinimum, m_eventInputSaved[iii].destinationInputId);
}
}
}
}
return lastMinimum+1;
}
return realInputId;
}
// note if id<0 ==> the it was finger event ...
void ewol::eSystemInput::Motion(ewol::keyEvent::type_te type, int pointerID, vec2 pos)
{
InputPoperty_ts *eventTable = NULL;
if (type == ewol::keyEvent::typeMouse) {
eventTable = m_eventMouseSaved;
} else if (type == ewol::keyEvent::typeFinger) {
eventTable = m_eventInputSaved;
} else {
EWOL_ERROR("Unknown type of event");
return;
}
if( pointerID > MAX_MANAGE_INPUT
|| pointerID < 0) {
// not manage input
return;
}
ewol::Windows* tmpWindows = eSystem::GetCurrentWindows();
// special case for the mouse event 0 that represent the hover event of the system :
if (type == ewol::keyEvent::typeMouse && pointerID == 0) {
// this event is all time on the good widget ... and manage the enter and leave ...
// NOTE : the "layer widget" force us to get the widget at the specific position all the time :
ewol::Widget* tmpWidget = NULL;
if (m_grabWidget != NULL) {
// grab all events ...
tmpWidget = m_grabWidget;
} else {
if (NULL != tmpWindows) {
tmpWidget = tmpWindows->GetWidgetAtPos(pos);
}
}
if( tmpWidget != eventTable[pointerID].curentWidgetEvent
|| ( true == eventTable[pointerID].isInside
&& ( eventTable[pointerID].origin.x() > pos.x()
|| eventTable[pointerID].origin.y() > pos.y()
|| (eventTable[pointerID].origin.x() + eventTable[pointerID].size.x()) < pos.x()
|| (eventTable[pointerID].origin.y() + eventTable[pointerID].size.y()) < pos.y()) ) ) {
eventTable[pointerID].isInside = false;
EVENT_DEBUG("GUI : Input ID=" << pointerID << "==>" << eventTable[pointerID].destinationInputId << " [LEAVE] " << pos);
eventTable[pointerID].posEvent = pos;
localEventInput(type, eventTable[pointerID].curentWidgetEvent, eventTable[pointerID].destinationInputId, ewol::keyEvent::statusLeave, pos);
}
if (false == eventTable[pointerID].isInside) {
// Set the element inside ...
eventTable[pointerID].isInside = true;
// get destination widget :
eventTable[pointerID].curentWidgetEvent = tmpWidget;
if (NULL == eventTable[pointerID].curentWidgetEvent) {
eventTable[pointerID].isInside = false;
}
if (NULL != eventTable[pointerID].curentWidgetEvent) {
eventTable[pointerID].origin = eventTable[pointerID].curentWidgetEvent->GetOrigin();
eventTable[pointerID].size = eventTable[pointerID].curentWidgetEvent->GetSize();
}
eventTable[pointerID].destinationInputId = 0;
EVENT_DEBUG("GUI : Input ID=" << pointerID << "==>" << eventTable[pointerID].destinationInputId << " [ENTER] " << pos);
eventTable[pointerID].posEvent = pos;
localEventInput(type, eventTable[pointerID].curentWidgetEvent, eventTable[pointerID].destinationInputId, ewol::keyEvent::statusEnter, pos);
}
EVENT_DEBUG("GUI : Input ID=" << pointerID << "==>" << eventTable[pointerID].destinationInputId << " [MOVE] " << pos);
eventTable[pointerID].posEvent = pos;
localEventInput(type, eventTable[pointerID].curentWidgetEvent, eventTable[pointerID].destinationInputId, ewol::keyEvent::statusMove, pos);
} else if (true == eventTable[pointerID].isUsed) {
if (true == eventTable[pointerID].isInside) {
if( eventTable[pointerID].origin.x() > pos.x()
|| eventTable[pointerID].origin.y() > pos.y()
|| (eventTable[pointerID].origin.x() + eventTable[pointerID].size.x()) < pos.x()
|| (eventTable[pointerID].origin.y() + eventTable[pointerID].size.y()) < pos.y()) {
eventTable[pointerID].isInside = false;
EVENT_DEBUG("GUI : Input ID=" << pointerID << "==>" << eventTable[pointerID].destinationInputId << " [LEAVE] " << pos);
eventTable[pointerID].posEvent = pos;
localEventInput(type, eventTable[pointerID].curentWidgetEvent, eventTable[pointerID].destinationInputId, ewol::keyEvent::statusLeave, pos);
}
} else {
if( ( eventTable[pointerID].origin.x() <= pos.x()
&& (eventTable[pointerID].origin.x() + eventTable[pointerID].size.x()) >= pos.x() )
&& ( eventTable[pointerID].origin.y() <= pos.y()
&& (eventTable[pointerID].origin.y() + eventTable[pointerID].size.y()) >= pos.y() ) ) {
eventTable[pointerID].isInside = true;
EVENT_DEBUG("GUI : Input ID=" << pointerID << "==>" << eventTable[pointerID].destinationInputId << " [ENTER] " << pos);
eventTable[pointerID].posEvent = pos;
localEventInput(type, eventTable[pointerID].curentWidgetEvent, eventTable[pointerID].destinationInputId, ewol::keyEvent::statusEnter, pos);
}
}
EVENT_DEBUG("GUI : Input ID=" << pointerID << "==>" << eventTable[pointerID].destinationInputId << " [MOVE] " << pos);
eventTable[pointerID].posEvent = pos;
localEventInput(type, eventTable[pointerID].curentWidgetEvent, eventTable[pointerID].destinationInputId, ewol::keyEvent::statusMove, pos);
}
}
void ewol::eSystemInput::State(ewol::keyEvent::type_te type, int pointerID, bool isDown, vec2 pos)
{
// convert position in Open-GL coordonates ...
InputPoperty_ts *eventTable = NULL;
inputLimit_ts localLimit;
if (type == ewol::keyEvent::typeMouse) {
eventTable = m_eventMouseSaved;
localLimit = m_eventMouseLimit;
} else if (type == ewol::keyEvent::typeFinger) {
eventTable = m_eventInputSaved;
localLimit = m_eventInputLimit;
} else {
EWOL_ERROR("Unknown type of event");
return;
}
if( pointerID > MAX_MANAGE_INPUT
|| pointerID <= 0) {
// not manage input
return;
}
// get the curent time ...
int64_t currentTime = ewol::GetTime();
ewol::Windows* tmpWindows = eSystem::GetCurrentWindows();
if (true == isDown) {
EWOL_VERBOSE("GUI : Input ID=" << pointerID << "==>" << eventTable[pointerID].destinationInputId << " [DOWN] " << pos);
if(true == eventTable[pointerID].isUsed) {
// we have an event previously ... check delay between click and offset position
if (currentTime - eventTable[pointerID].lastTimeEvent > localLimit.sepatateTime) {
CleanElement(eventTable, pointerID);
} else if( abs(eventTable[pointerID].downStart.x() - pos.x()) >= localLimit.DpiOffset
|| abs(eventTable[pointerID].downStart.y() - pos.y()) >= localLimit.DpiOffset ){
CleanElement(eventTable, pointerID);
}
}
if(true == eventTable[pointerID].isUsed) {
// save start time
eventTable[pointerID].lastTimeEvent = currentTime;
// generate DOWN Event
EVENT_DEBUG("GUI : Input ID=" << pointerID << "==>" << eventTable[pointerID].destinationInputId << " [DOWN] " << pos);
eventTable[pointerID].posEvent = pos;
localEventInput(type, eventTable[pointerID].curentWidgetEvent, eventTable[pointerID].destinationInputId, ewol::keyEvent::statusDown, pos);
} else {
// Mark it used :
eventTable[pointerID].isUsed = true;
// Save current position :
eventTable[pointerID].downStart = pos;
// save start time
eventTable[pointerID].lastTimeEvent = currentTime;
// Set the element inside ...
eventTable[pointerID].isInside = true;
// get destination widget :
if(NULL != tmpWindows) {
if (m_grabWidget != NULL && type == ewol::keyEvent::typeMouse) {
eventTable[pointerID].curentWidgetEvent = m_grabWidget;
} else {
eventTable[pointerID].curentWidgetEvent = tmpWindows->GetWidgetAtPos(pos);
}
} else {
eventTable[pointerID].curentWidgetEvent = NULL;
}
if (NULL != eventTable[pointerID].curentWidgetEvent) {
eventTable[pointerID].origin = eventTable[pointerID].curentWidgetEvent->GetOrigin();
eventTable[pointerID].size = eventTable[pointerID].curentWidgetEvent->GetSize();
eventTable[pointerID].destinationInputId = localGetDestinationId(type, eventTable[pointerID].curentWidgetEvent, pointerID);
} else {
eventTable[pointerID].destinationInputId = -1;
}
// generate DOWN Event
EVENT_DEBUG("GUI : Input ID=" << pointerID << "==>" << eventTable[pointerID].destinationInputId << " [DOWN] " << pos);
eventTable[pointerID].posEvent = pos;
localEventInput(type, eventTable[pointerID].curentWidgetEvent, eventTable[pointerID].destinationInputId, ewol::keyEvent::statusDown, pos);
}
} else {
EWOL_VERBOSE("GUI : Input ID=" << pointerID << "==>" << eventTable[pointerID].destinationInputId << " [UP] " << pos);
if(false == eventTable[pointerID].isUsed) {
// bad case ... ???
EWOL_DEBUG("Up event without previous down ... ");
// Mark it un-used :
eventTable[pointerID].isUsed = false;
// revove the widget ...
eventTable[pointerID].curentWidgetEvent = NULL;
} else {
// generate UP Event
EVENT_DEBUG("GUI : Input ID=" << pointerID << "==>" << eventTable[pointerID].destinationInputId << " [UP] " << pos);
eventTable[pointerID].posEvent = pos;
localEventInput(type, eventTable[pointerID].curentWidgetEvent, pointerID, ewol::keyEvent::statusUp, pos);
// generate event (single)
if( abs(eventTable[pointerID].downStart.x() - pos.x()) < localLimit.DpiOffset
&& abs(eventTable[pointerID].downStart.y() - pos.y()) < localLimit.DpiOffset ){
// Save current position :
eventTable[pointerID].downStart = pos;
// save start time
eventTable[pointerID].lastTimeEvent = currentTime;
int32_t nbClickMax = 0;
if(eventTable[pointerID].curentWidgetEvent != NULL) {
nbClickMax = eventTable[pointerID].curentWidgetEvent->GetMouseLimit();
if (nbClickMax>5) {
nbClickMax = 5;
}
}
// in grab mode the single to quinte event are not generated ....
if( ( m_grabWidget == NULL
|| type != ewol::keyEvent::typeMouse )
&& eventTable[pointerID].nbClickEvent < nbClickMax) {
// generate event SINGLE :
eventTable[pointerID].nbClickEvent++;
EVENT_DEBUG("GUI : Input ID=" << pointerID << "==>" << eventTable[pointerID].destinationInputId << " [" << eventTable[pointerID].nbClickEvent << "] " << pos);
eventTable[pointerID].posEvent = pos;
localEventInput(type,
eventTable[pointerID].curentWidgetEvent,
eventTable[pointerID].destinationInputId,
(ewol::keyEvent::status_te)(ewol::keyEvent::statusSingle + eventTable[pointerID].nbClickEvent-1),
pos);
if( eventTable[pointerID].nbClickEvent >= nbClickMax) {
eventTable[pointerID].nbClickEvent = 0;
}
} else {
eventTable[pointerID].nbClickEvent = 0;
}
}
// specific for tuch event
if (type == ewol::keyEvent::typeFinger) {
CleanElement(eventTable, pointerID);
}
}
}
}