webengine/webkitutils/stmgesturefw/src/stateengine.cpp
branchRCL_3
changeset 49 919f36ff910f
equal deleted inserted replaced
48:79859ed3eea9 49:919f36ff910f
       
     1 /*
       
     2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include "stateengine.h"
       
    20 #include "utils.h"
       
    21 #include "uievent.h"
       
    22 #include "uieventsender.h"
       
    23 #include "filelogger.h"
       
    24 //#include "flogger.h"
       
    25 
       
    26 using namespace stmUiEventEngine ;
       
    27 
       
    28 /*!
       
    29   State definitions glue together the methods of the stateengine.cpp
       
    30   so that it will behave as defined in the state machine specification.
       
    31   First define the separate elements for each possible event and then tie them together
       
    32   to create one state entry.  The state entries then are put to array
       
    33   where the index is at the same time also the state ID.
       
    34 
       
    35   STATE_ELEMENT arrays define the methods called when handling a message.
       
    36   \sa STATE_ELEMENT.
       
    37   Note that the last row of STATE_ELEMENT array must NOT have a ConditionFunction entry
       
    38   and it must have a NextState entry != Eignore.  Otherwise the state machine will
       
    39   not behave correctly.
       
    40 
       
    41  */
       
    42 /*! Add macro with token pasting to make creation of the state machine tables easier
       
    43    and removing the necessity to write the classname twice.
       
    44    Maybe there would be some better way to do this using templates and typedefs?
       
    45  */
       
    46 #define CND(x) isF<CStateEngine,&CStateEngine::##x>
       
    47 #define ACT(x) aF<CStateEngine,&CStateEngine::##x>
       
    48 
       
    49 /*********************************************************************************
       
    50  * empty statedef as a dummy entry
       
    51  *  */
       
    52 const STATE_ELEMENT __ErrorEvent[1] = {
       
    53         0,
       
    54         ACT(ErrorEvent),
       
    55         EInit
       
    56 };
       
    57 
       
    58 const STATE Ignore__[1] = {
       
    59         EDown,          __ErrorEvent
       
    60 } ;
       
    61 
       
    62 /*!
       
    63   :INIT state and its event specific elements
       
    64   See the spec in http://wikis.in.nokia.com/Runtimes/NewGestureLibrary
       
    65   Down is only valid event in :INIT state
       
    66   The event is consumed immediately, so that the state machine will process only these
       
    67   methods when processing the message.
       
    68   If touch timer has been set, the next state is InTouchTime.
       
    69   If no touch timer, but if hold timer has been defined, the next state is InHoldTime_U
       
    70   If no touch or hold timer have been defined, but touch area has been defined, next state is InTouchArea.
       
    71   11-May-2009: addition: add another touch area: one for touch time and one for touch area after touch time
       
    72   has elapsed.  This allows "sloppy" touch to be handled properly without extra move if touchtimearea is larger,
       
    73   but after touch has been detected a smaller movement is allowed.
       
    74  */
       
    75 const STATE_ELEMENT Init__Down[12] = {
       
    76         0,                  ACT(ConsumeEvent),    Eignore,
       
    77         0,                  ACT(SetGestureStart), Eignore,
       
    78         0,                  ACT(SetCurrentPos),   Eignore,
       
    79         CND(IsTouchTimer),  ACT(InitTouchTimer),  Eignore,
       
    80         CND(IsHoldTimer),   ACT(InitHoldTimer),   Eignore,
       
    81         CND(IsTouchTimeArea),   ACT(PrepareTouchTimeArea),Eignore,
       
    82         CND(IsHoldArea),    ACT(PrepareHoldArea) ,Eignore,
       
    83         CND(IsTouchTimer),  0,                    EInTouchTime,
       
    84         0,                  ACT(ProduceTouch),    Eignore,
       
    85         CND(IsHoldTimer),   0,                    EInHoldTime_U,
       
    86         CND(IsTouchArea),   ACT(PrepareTouchArea),EInTouchArea,
       
    87         0,                  0,                    EDispatch             // If nothing else happens, goto to Dispatch state
       
    88 };
       
    89 /**
       
    90  * All the rest of the events are errors so produce error entry to log and
       
    91  * stay in the Init state
       
    92  */
       
    93 const STATE_ELEMENT Init__ErrorEvent[2] = {
       
    94         0,              ACT(ConsumeEvent),    Eignore,  // remember to consume event, otherwise state machine will loop...
       
    95         0,              ACT(ErrorEvent),      EInit
       
    96 };
       
    97 
       
    98 /*!
       
    99  * :INIT
       
   100  * note that only valid event is DOWN, all the rest can be handled as errors
       
   101  */
       
   102 const STATE Init__[7] = {
       
   103         EDown,          Init__Down,
       
   104         EDrag,          Init__ErrorEvent,
       
   105         ECapacitiveUP,  Init__ErrorEvent,
       
   106         EResistiveUP,   Init__ErrorEvent,
       
   107         ETouchTimer,    Init__ErrorEvent,
       
   108         EHoldTimer,     Init__ErrorEvent,
       
   109         ESuppressTimer, Init__ErrorEvent
       
   110 };
       
   111 
       
   112 /*!
       
   113  *  :Dispatch state end its elements
       
   114  *  Here the valid events are DRAG and the UP events.
       
   115  */
       
   116 const STATE_ELEMENT Dispatch__Drag[7] = {
       
   117         0,                  ACT(StoreMovePos),    Eignore,
       
   118         0,                  ACT(ConsumeEvent),    Eignore,
       
   119         0,                  ACT(SetCurrentPos),   Eignore,
       
   120         0,                  ACT(AddDraggingPos),  Eignore,
       
   121         0,                  ACT(ProduceMove),     Eignore,
       
   122         CND(LooksLikeHold), ACT(InitHoldTimer),EInHoldTime_U,
       
   123         0,                  0,                    EDispatch
       
   124 } ;
       
   125 
       
   126 const STATE_ELEMENT Dispatch__CapacitiveUp[3] = {
       
   127         0,                  ACT(ConsumeEvent),    Eignore,
       
   128         0,                  ACT(SetCurrentPos),   Eignore,
       
   129         0,                  ACT(ProduceRelease),  EInit
       
   130 } ;
       
   131 
       
   132 const STATE_ELEMENT Dispatch__ResistiveUp[4] = {
       
   133         0,                   ACT(ConsumeEvent),       Eignore,
       
   134         0,                   ACT(SetCurrentPos),   Eignore,
       
   135         CND(IsSuppressTimer),ACT(InitMoveSuppressTimer),  ESuppress_D,
       
   136         0,                   ACT(ProduceRelease),     EInit
       
   137 } ;
       
   138 
       
   139 /*!
       
   140  * All the rest of the events are errors so produce error entry to log and
       
   141  * stay in the Dispatch state
       
   142  * (TODO: note that in the future we may further
       
   143  * define the error cases so that they may change state; )
       
   144  */
       
   145 const STATE_ELEMENT DispatchErrorEvent[2] = {
       
   146         0,              ACT(ConsumeEvent),    Eignore,  // remember to consume event, otherwise state machine will loop...
       
   147         0,              ACT(ErrorEvent),      EDispatch
       
   148 };
       
   149 
       
   150 const STATE Dispatch__[7] = {
       
   151         EDown,          DispatchErrorEvent,
       
   152         EDrag,          Dispatch__Drag,
       
   153         ECapacitiveUP,  Dispatch__CapacitiveUp,
       
   154         EResistiveUP,   Dispatch__ResistiveUp,
       
   155         ETouchTimer,    DispatchErrorEvent,
       
   156         EHoldTimer,     DispatchErrorEvent,
       
   157         ESuppressTimer, DispatchErrorEvent
       
   158 };
       
   159 
       
   160 /*!
       
   161  *  :InTouchTime state end its elements
       
   162  *  Here the valid events are DRAG and the UP events and the TouchTimer
       
   163  */
       
   164 const STATE_ELEMENT InTouchTime__Drag[6] = {
       
   165         0,                  ACT(StoreMovePos),    Eignore,
       
   166         CND(InsideTouchTimeArea), ACT(ConsumeEvent),      Eignore,
       
   167         CND(InsideTouchTimeArea), ACT(AddToTouch),        EInTouchTime,     // Calculate touch XY as average of the touches
       
   168         0,                    ACT(ClearTouchTimer),   Eignore,          // These lines are done only if InsideTouchArea returns false
       
   169         0,                    ACT(ClearHoldTimer),    Eignore,
       
   170         0,                    ACT(ProduceTouch),      EDispatch
       
   171 
       
   172 } ;
       
   173 /**
       
   174  * Note that ConsumeEvent is missing so after doing this the state engine will do EDispatch
       
   175  */
       
   176 const STATE_ELEMENT InTouchTime__CapacitiveUp[4] = {
       
   177         0,                  ACT(SetCurrentPos),       Eignore,
       
   178         0,                  ACT(ClearTouchTimer),     Eignore,
       
   179         0,                  ACT(ClearHoldTimer),      Eignore,
       
   180         0,                  ACT(ProduceTouch),        EDispatch
       
   181 } ;
       
   182 /**
       
   183  * Note that ConsumeEvent is not called if IsHoldTimer returns false, so the Dispatch will be done
       
   184  * by the state machine.
       
   185  */
       
   186 const STATE_ELEMENT InTouchTime__ResistiveUp[5] = {
       
   187         0,                   ACT(SetCurrentPos),   Eignore,
       
   188         0,                   ACT(ClearTouchTimer),    Eignore,
       
   189         0,                   ACT(ProduceTouch),       Eignore,
       
   190         CND(IsHoldTimer),    0, /*ACT(ConsumeEvent),*/EInHoldTime_U,    // Note that otherwise immediate UP is handled improperly
       
   191         0,                   0,                       EDispatch
       
   192 } ;
       
   193 
       
   194 const STATE_ELEMENT InTouchTime__TouchTimer[6] = {
       
   195         0,                   ACT(ConsumeEvent),       Eignore,
       
   196         0,                   ACT(ClearTouchTimer),    Eignore,
       
   197         0,                   ACT(ProduceTouch),       Eignore,
       
   198         CND(IsTouchArea),    ACT(PrepareTouchArea),Eignore,         // prepare the other touch area
       
   199         CND(IsHoldTimer),    0,                       EInHoldTime_U,
       
   200         0,                   0,                     EInTouchArea
       
   201 } ;
       
   202 
       
   203 
       
   204 /**
       
   205  * All the rest of the events are errors so produce error entry to log and
       
   206  * stay in the InTouchTime state
       
   207  */
       
   208 const STATE_ELEMENT InTouchTimeErrorEvent[2] = {
       
   209         0,              ACT(ConsumeEvent),    Eignore,  // remember to consume event, otherwise state machine will loop...
       
   210         0,              ACT(ErrorEvent),      EInTouchTime
       
   211 };
       
   212 
       
   213 const STATE InTouchTime__[7] = {
       
   214         EDown,          InTouchTimeErrorEvent,
       
   215         EDrag,          InTouchTime__Drag,
       
   216         ECapacitiveUP,  InTouchTime__CapacitiveUp,
       
   217         EResistiveUP,   InTouchTime__ResistiveUp,
       
   218         ETouchTimer,    InTouchTime__TouchTimer,
       
   219         EHoldTimer,     InTouchTimeErrorEvent,
       
   220         ESuppressTimer, InTouchTimeErrorEvent
       
   221 };
       
   222 
       
   223 /*!
       
   224  *  :InHoldTime_U state end its elements
       
   225  *  Here only touch timer event is invalid
       
   226  */
       
   227 
       
   228 const STATE_ELEMENT InHoldTime_U__Down[1] = {
       
   229         0,                    0,      EInHoldTime_D  // Note that ConsumeEvent is not called
       
   230 } ;
       
   231 
       
   232 const STATE_ELEMENT InHoldTime_U__Drag[3] = {
       
   233         0,                  ACT(StoreMovePos),    Eignore,
       
   234         CND(InsideHoldArea), ACT(ConsumeEvent),       EInHoldTime_U,
       
   235         0,                    ACT(ClearHoldTimer),    EDispatch     // Note that in this case ConsumeEvent is not called
       
   236 } ;
       
   237 /**
       
   238  * Note that ConsumeEvent is missing so after doing this the state engine will do EDispatch
       
   239  */
       
   240 const STATE_ELEMENT InHoldTime_U__CapacitiveUp[1] = {
       
   241         0,                  ACT(ClearHoldTimer),      EDispatch     // Note that ConsumeEvent not called
       
   242 } ;
       
   243 /**
       
   244  *
       
   245  */
       
   246 const STATE_ELEMENT InHoldTime_U__ResistiveUp[5] = {
       
   247         0,                   ACT(ConsumeEvent),  Eignore,
       
   248         0,                   ACT(SetCurrentPos),   Eignore,
       
   249         CND(IsSuppressTimer),ACT(InitTouchSuppressTimer),  EInHoldTime_D,   // If suppression, start timer and wait for down or timer
       
   250         0,                   ACT(ClearHoldTimer), Eignore,  // remember to do this
       
   251         0,                   ACT(ProduceRelease), EInit     // No suppression, then this is immediate release
       
   252 } ;
       
   253 
       
   254 const STATE_ELEMENT InHoldTime_U__HoldTimer[3] = {
       
   255         0,                   ACT(ConsumeEvent),       Eignore,
       
   256         0,                   ACT(ProduceHold),        Eignore,
       
   257         0,                   ACT(RestartHoldTimer),   EInHoldTime_U,
       
   258 } ;
       
   259 
       
   260 const STATE_ELEMENT InHoldTime_U__SuppressTimer[2] = {
       
   261         0,              ACT(ConsumeEvent),    Eignore,  // remember to consume event, otherwise state machine will loop...
       
   262         0,              ACT(ErrorEvent),      EInHoldTime_U
       
   263 } ;
       
   264 
       
   265 
       
   266 /**
       
   267  * All the rest of the events are errors so produce error entry to log and
       
   268  * stay in the InHoldTime_U state
       
   269  */
       
   270 const STATE_ELEMENT InHoldTime_UErrorEvent[2] = {
       
   271         0,              ACT(ConsumeEvent),    Eignore,  // remember to consume event, otherwise state machine will loop...
       
   272         0,              ACT(ErrorEvent),      EInHoldTime_U
       
   273 };
       
   274 
       
   275 const STATE InHoldTime_U__[7] = {
       
   276         EDown,          InHoldTime_U__Down,
       
   277         EDrag,          InHoldTime_U__Drag,
       
   278         ECapacitiveUP,  InHoldTime_U__CapacitiveUp,
       
   279         EResistiveUP,   InHoldTime_U__ResistiveUp,
       
   280         ETouchTimer,    InHoldTime_UErrorEvent,
       
   281         EHoldTimer,     InHoldTime_U__HoldTimer,
       
   282         ESuppressTimer, InHoldTime_U__SuppressTimer
       
   283 };
       
   284 
       
   285 
       
   286 /*!
       
   287  *  :InHoldTime_D state end its elements
       
   288  *  Here drag, touch timer and suppress timer events are invalid
       
   289  */
       
   290 
       
   291 const STATE_ELEMENT InHoldTime_D__Down[5] = {
       
   292         0,                    ACT(ClearSuppressTimer),    Eignore,
       
   293         0,                    ACT(ConsumeEvent),      Eignore,
       
   294         CND(InsideHoldArea),  0,                      EInHoldTime_U,
       
   295         0,                    ACT(ClearHoldTimer),    Eignore,
       
   296         0,                    ACT(ProduceMove),       EDispatch
       
   297 } ;
       
   298 
       
   299 /**
       
   300  * Note that ConsumeEvent is missing so after doing this the state engine will do InHoldTime_U
       
   301  */
       
   302 const STATE_ELEMENT InHoldTime_D__CapacitiveUp[1] = {
       
   303         0,                  0,    EInHoldTime_U
       
   304 } ;
       
   305 /**
       
   306  * Note that ConsumeEvent is missing so after doing this the state engine will do InHoldTime_U
       
   307  */
       
   308 const STATE_ELEMENT InHoldTime_D__ResistiveUp[1] = {
       
   309         0,                  0,    EInHoldTime_U     // InHoldTime_U initialises timers etc. if needed
       
   310 } ;
       
   311 /*!
       
   312  * In case of hold timer has been elapsed stop the timers, generate Release UI event.
       
   313  */
       
   314 const STATE_ELEMENT InHoldTime_D__HoldTimer[4] = {
       
   315         0,                   ACT(ConsumeEvent),       Eignore,
       
   316         0,                   ACT(ClearSuppressTimer), Eignore,
       
   317         0,                   ACT(ClearHoldTimer),     Eignore,
       
   318         0,                   ACT(ProduceRelease),     EInit,
       
   319 } ;
       
   320 /*!
       
   321  * If suppress timer hits, stop the timers and generate Release UI event.
       
   322  */
       
   323 const STATE_ELEMENT InHoldTime_D__SuppressTimer[4] = {
       
   324         0,                   ACT(ConsumeEvent),       Eignore,
       
   325         0,                   ACT(ClearSuppressTimer), Eignore,
       
   326         0,                   ACT(ClearHoldTimer),     Eignore,
       
   327         0,                   ACT(ProduceRelease),     EInit,
       
   328 } ;
       
   329 
       
   330 /**
       
   331  * All the rest of the events are errors so produce error entry to log and
       
   332  * stay in the InHoldTime_D state
       
   333  */
       
   334 const STATE_ELEMENT InHoldTime_DErrorEvent[2] = {
       
   335         0,              ACT(ConsumeEvent),    Eignore,  // remember to consume event, otherwise state machine will loop...
       
   336         0,              ACT(ErrorEvent),      EInHoldTime_D
       
   337 };
       
   338 
       
   339 const STATE InHoldTime_D__[7] = {
       
   340         EDown,          InHoldTime_D__Down,
       
   341         EDrag,          InHoldTime_DErrorEvent,
       
   342         ECapacitiveUP,  InHoldTime_D__CapacitiveUp,
       
   343         EResistiveUP,   InHoldTime_D__ResistiveUp,
       
   344         ETouchTimer,    InHoldTime_DErrorEvent,
       
   345         EHoldTimer,     InHoldTime_D__HoldTimer,
       
   346         ESuppressTimer, InHoldTime_D__SuppressTimer
       
   347 };
       
   348 
       
   349 
       
   350 /*!
       
   351  *  :InTouchArea state end its elements
       
   352  *  Here Drag and Up events are valid.
       
   353  *  If drag is inside touch are it is ignored, otherwise
       
   354  *  the Dispatch state will handle the event.
       
   355  */
       
   356 
       
   357 const STATE_ELEMENT InTouchArea__Drag[3] = {
       
   358         0,                  ACT(StoreMovePos),    Eignore,
       
   359         CND(InsideTouchArea), ACT(ConsumeEvent),     EInTouchArea,
       
   360         0,                    0,                     EDispatch  // Note that in this case ConsumeEvent has not been called so Dispatch state processes the message
       
   361 } ;
       
   362 
       
   363 /**
       
   364  * Note that ConsumeEvent is missing so after doing this the state engine will do Dispatch
       
   365  */
       
   366 const STATE_ELEMENT InTouchArea__CapacitiveUp[1] = {
       
   367         0,                  0,    EDispatch
       
   368 } ;
       
   369 /**
       
   370  * Note that ConsumeEvent is missing so after doing this the state engine will do Dispatch
       
   371  */
       
   372 const STATE_ELEMENT InTouchArea__ResistiveUp[1] = {
       
   373         0,                  0,    EDispatch
       
   374 } ;
       
   375 
       
   376 /**
       
   377  * All the rest of the events are errors so produce error entry to log and
       
   378  * stay in the InTouchArea state
       
   379  */
       
   380 const STATE_ELEMENT InTouchAreaErrorEvent[2] = {
       
   381         0,              ACT(ConsumeEvent),    Eignore,  // remember to consume event, otherwise state machine will loop...
       
   382         0,              ACT(ErrorEvent),      EInTouchArea
       
   383 };
       
   384 
       
   385 const STATE InTouchArea__[7] = {
       
   386         EDown,          InTouchAreaErrorEvent,
       
   387         EDrag,          InTouchArea__Drag,
       
   388         ECapacitiveUP,  InTouchArea__CapacitiveUp,
       
   389         EResistiveUP,   InTouchArea__ResistiveUp,
       
   390         ETouchTimer,    InTouchAreaErrorEvent,
       
   391         EHoldTimer,     InTouchAreaErrorEvent,
       
   392         ESuppressTimer, InTouchAreaErrorEvent
       
   393 };
       
   394 
       
   395 
       
   396 /*!
       
   397  *  :Suppress_D state end its elements
       
   398  *  Here Down and suppress timers are OK.
       
   399  */
       
   400 
       
   401 /*!
       
   402  * Down will be handled as a Drag event in the Dispatch state.
       
   403  */
       
   404 const STATE_ELEMENT Suppress_D__Down[4] = {
       
   405         0,           ACT(ClearSuppressTimer),    Eignore,
       
   406         0,           ACT(RenameToDrag),          EDispatch
       
   407 } ;
       
   408 /*!
       
   409  * Suppress timer will generate Release UI event.
       
   410  */
       
   411 const STATE_ELEMENT Suppress_D__SuppressTimer[3] = {
       
   412         0,                   ACT(ConsumeEvent),       Eignore,
       
   413         0,                   ACT(ClearSuppressTimer), Eignore,
       
   414         0,                   ACT(ProduceRelease),     EInit,
       
   415 } ;
       
   416 
       
   417 /**
       
   418  * All the rest of the events are errors so produce error entry to log and
       
   419  * stay in the Suppress_D state
       
   420  */
       
   421 const STATE_ELEMENT Suppress_DErrorEvent[2] = {
       
   422         0,              ACT(ConsumeEvent),    Eignore,  // remember to consume event, otherwise state machine will loop...
       
   423         0,              ACT(ErrorEvent),      ESuppress_D
       
   424 };
       
   425 
       
   426 const STATE Suppress_D__[7] = {
       
   427         EDown,          Suppress_D__Down,
       
   428         EDrag,          Suppress_DErrorEvent,
       
   429         ECapacitiveUP,  Suppress_DErrorEvent,
       
   430         EResistiveUP,   Suppress_DErrorEvent,
       
   431         ETouchTimer,    Suppress_DErrorEvent,
       
   432         EHoldTimer,     Suppress_DErrorEvent,
       
   433         ESuppressTimer, Suppress_D__SuppressTimer
       
   434 };
       
   435 /*!
       
   436  * The allStates array contains all the possible states of the state machine.
       
   437  */
       
   438 const STATE* const allStates[8] =
       
   439 {
       
   440         Ignore__,
       
   441         Init__,
       
   442         Dispatch__,
       
   443         InTouchTime__,
       
   444         InHoldTime_U__,
       
   445         InHoldTime_D__,
       
   446         InTouchArea__,
       
   447         Suppress_D__
       
   448 };
       
   449 /*!
       
   450  * stateNames are used in the logging
       
   451  */
       
   452 #ifdef GESTURE_LOGGING
       
   453 const char* const stateNames[8] =
       
   454 {
       
   455         "Ignore",
       
   456         "Init",
       
   457         "Dispatch",
       
   458         "InTouchTime",
       
   459         "InHoldTime_U",
       
   460         "InHoldTime_D",
       
   461         "InTouchArea",
       
   462         "Suppress"
       
   463 };
       
   464 
       
   465 // event names are also used in logging
       
   466 const char* const hweventNames[] = {
       
   467         "EDown",
       
   468         "EDrag",
       
   469         "ECapacitiveUP",
       
   470         "EResistiveUP",
       
   471         "ETouchTimer",
       
   472         "EHoldTimer",
       
   473         "ESuppressTimer"
       
   474 } ;
       
   475 #endif
       
   476 
       
   477 /*! CStateEngine contains the methods used in the state machine implementation.
       
   478  *
       
   479  *  The methods in CStateEngine used in the state machine definition are
       
   480  *  either condition methods or action methods.
       
   481  *
       
   482  *  Constructor
       
   483  *  \param[in]: MTimerInterface atimerif.  An attempt to make this more OS agnostic the actual
       
   484  *  timers are accessed using a separate interface.
       
   485  */
       
   486 CStateEngine::CStateEngine(CStateEngineConfiguration* aConfig, MTimerInterface* atimerif, int aIndex)
       
   487 {
       
   488     m_config = aConfig ;
       
   489     m_timerif = atimerif ;
       
   490     m_currentState = EInit ;
       
   491     m_index = aIndex ;
       
   492     isStatemachineBlocked = false;
       
   493 }
       
   494 
       
   495 CStateEngine::~CStateEngine()
       
   496 {
       
   497     // Just to be sure...
       
   498     iTouchPoints.Reset() ;
       
   499     iDragPoints.ResetAndDestroy() ;
       
   500 }
       
   501 /*!
       
   502  * ConsumeEvent: the method defines that the turnStateMachine will stop the processing
       
   503  * of the state methods after it has reached the next state.
       
   504  *
       
   505  */
       
   506 void CStateEngine::ConsumeEvent()
       
   507 {
       
   508     m_eventConsumed = true ;
       
   509 }
       
   510 /*!
       
   511  * Condition method
       
   512  * \return true, if the touch timer limit > 0
       
   513  */
       
   514 bool CStateEngine::IsTouchTimer()
       
   515 {
       
   516     bool isit =  (m_config->m_touchTimerLimit > 0) ;
       
   517 
       
   518     return isit ;
       
   519 }
       
   520 /*!
       
   521  * Condition method
       
   522  * \return true, if the hold timer limit > 0
       
   523  */
       
   524 bool CStateEngine::IsHoldTimer()
       
   525 {
       
   526     bool isit =  (m_config->m_holdTimerLimit > 0) ;
       
   527 
       
   528     return isit ;
       
   529 }
       
   530 /*!
       
   531  * Condition method
       
   532  * \return true, if the suppress timer limit > 0
       
   533  */
       
   534 bool CStateEngine::IsSuppressTimer()
       
   535 {
       
   536     bool isit =  (m_config->m_suppressTimerLimit > 0) ;
       
   537 
       
   538     return isit ;
       
   539 }
       
   540 /*!
       
   541  * Condition method
       
   542  * \return true, if the touch area has been defined (the touch tolerancelength > 0)
       
   543  */
       
   544 bool CStateEngine::IsTouchTimeArea()
       
   545 {
       
   546     bool isit = (m_config->m_touchTimeTolerance.iX > 0) ;
       
   547     return isit  ;
       
   548 }
       
   549 /*!
       
   550  * Condition method
       
   551  * \return true, if the touch area has been defined (the touch tolerancelength > 0)
       
   552  */
       
   553 bool CStateEngine::IsTouchArea()
       
   554 {
       
   555     bool isit = (m_config->m_touchTolerance.iX > 0) ;
       
   556     return isit  ;
       
   557 }
       
   558 /*!
       
   559  * Condition method
       
   560  * \return true, if the hold area has been defined (the hold tolerancelength > 0)
       
   561  */
       
   562 bool CStateEngine::IsHoldArea()
       
   563 {
       
   564     bool isit = (m_config->m_holdTolerance.iX > 0) ;
       
   565     return isit  ;
       
   566 }
       
   567 
       
   568 bool CStateEngine::InsideArea(const TPoint& point,
       
   569                               const TRect& rect,
       
   570                               TAreaShape shape,
       
   571                               const TPoint& tolerance)
       
   572 {
       
   573     bool isit;
       
   574     switch(shape)
       
   575     {
       
   576     default:    // pass trough
       
   577     case ERectangle:
       
   578     {
       
   579         isit = rect.Contains(m_hwe.iPosition) ;
       
   580         break ;
       
   581     }
       
   582     case ECircle:
       
   583     {
       
   584         TPoint delta = m_hwe.iPosition - point;
       
   585         long circlepoint = delta.iX * delta.iX + delta.iY * delta.iY;
       
   586         isit = (circlepoint < tolerance.iX * tolerance.iX);
       
   587         break ;
       
   588     }
       
   589     case EEllipse:
       
   590     {
       
   591         int asquare = tolerance.iX * tolerance.iX ;
       
   592         int bsquare = tolerance.iY * tolerance.iY ;
       
   593         TPoint delta = m_hwe.iPosition - point;
       
   594         int result = (delta.iX * delta.iX) * bsquare + (delta.iY * delta.iY) * asquare;
       
   595 
       
   596         isit = (result < asquare * bsquare);
       
   597         break ;
       
   598     }
       
   599     }
       
   600     return isit ;
       
   601 }
       
   602 
       
   603 /*!
       
   604  * Condition method
       
   605  * Check if the current event is positioned inside the touch area.
       
   606  * Touch area can be a rectangle, a circle or an ellipse, so different
       
   607  * calculation needs to be done based on the shape of the area.
       
   608  */
       
   609 bool CStateEngine::InsideTouchTimeArea()
       
   610 {
       
   611     return InsideArea(m_touchCentre, m_touchRect,
       
   612                       m_config->m_touchAreaShape, m_config->m_touchTimeTolerance);
       
   613 }
       
   614 /*!
       
   615  * Condition method
       
   616  * Check if the current event is positioned inside the touch area.
       
   617  * Touch area can be a rectangle, a circle or an ellipse, so different
       
   618  * calculation needs to be done based on the shape of the area.
       
   619  */
       
   620 bool CStateEngine::InsideTouchArea()
       
   621 {
       
   622     return InsideArea(m_touchCentre, m_touchRect,
       
   623                       m_config->m_touchAreaShape, m_config->m_touchTolerance);
       
   624 }
       
   625 /*!
       
   626  * Condition method
       
   627  * Check if the current event is positioned inside the hold area.
       
   628  * Hold area can be a rectangle, a circle or an ellipse, so different
       
   629  * calculation needs to be done based on the shape of the area.
       
   630  */
       
   631 bool CStateEngine::InsideHoldArea()
       
   632 {
       
   633     return InsideArea(m_holdCentre, m_holdRect,
       
   634                       m_config->m_holdAreaShape, m_config->m_holdTolerance);
       
   635 }
       
   636 /*!
       
   637  * Condition method
       
   638  * Check if the gesture looks like a hold, i.e. the movement has stopped.
       
   639  * \sa isNewHoldingPoint
       
   640  */
       
   641 bool CStateEngine::LooksLikeHold()
       
   642 {
       
   643     bool isit = isNewHoldingPoint() ;
       
   644     return isit ;
       
   645 }
       
   646 /*!
       
   647  * Action method
       
   648  * Error logging.
       
   649  */
       
   650 void CStateEngine::ErrorEvent()
       
   651 {
       
   652     // Log the error
       
   653     if (m_config->m_enableLogging)
       
   654     {
       
   655         LOGARG("ErrorEvent: %s %s", stateNames[m_currentState], hweventNames[m_hwe.iType]) ;
       
   656     }
       
   657 }
       
   658 /*!
       
   659  * Action method
       
   660  * Initialize touch timer.  At the same time calculate also the touch rectangle.
       
   661  */
       
   662 void CStateEngine::InitTouchTimer()
       
   663 {
       
   664     m_touchRect = ToleranceRect(m_hwe.iPosition, m_config->m_touchTolerance) ;
       
   665     m_touchCentre = m_hwe.iPosition ;
       
   666     m_timerif->startTouchTimer(m_config->m_touchTimerLimit, m_index) ;
       
   667 }
       
   668 /*!
       
   669  * Action method.
       
   670  * Initialize hold timer.  At the same time calculate also the hold rectangle.
       
   671  */
       
   672 void CStateEngine::InitHoldTimer()
       
   673 {
       
   674     m_holdRect = ToleranceRect(m_hwe.iPosition, m_config->m_holdTolerance) ;
       
   675     m_holdCentre = m_hwe.iPosition ;
       
   676     m_timerif->startHoldTimer(m_config->m_holdTimerLimit, m_index) ;
       
   677 }
       
   678 /*!
       
   679  * Action method
       
   680  * Restart the hold timer using the hold timer limit.
       
   681  */
       
   682 void CStateEngine::RestartHoldTimer()
       
   683 {
       
   684     m_timerif->startHoldTimer(m_config->m_holdTimerLimit, m_index) ;
       
   685 }
       
   686 /*!
       
   687  * Action method
       
   688  * Initialize suppression timer.  This timer is used during touch detection when
       
   689  * resistive UP has been detected.  If new DOWN comes while timer is running, it is ignored.
       
   690  */
       
   691 void CStateEngine::InitTouchSuppressTimer()
       
   692 {
       
   693     m_timerif->startSuppressTimer(m_config->m_suppressTimerLimit, m_index) ;
       
   694 }
       
   695 /*!
       
   696  * Action method.
       
   697  * Initialize suppression timer after move.  Tests show that when user is using light touch and
       
   698  * moving finger to opposite directions there may be accidental ups and downs where the time between
       
   699  * up and down may be well over 120 ms.
       
   700  */
       
   701 void CStateEngine::InitMoveSuppressTimer()
       
   702 {
       
   703     m_timerif->startSuppressTimer(m_config->m_moveSuppressTimerLimit, m_index) ;
       
   704 }
       
   705 /*!
       
   706  * Action method
       
   707  * Stop the touch timer.
       
   708  */
       
   709 void CStateEngine::ClearTouchTimer()
       
   710 {
       
   711     m_timerif->cancelTouchTimer(m_index) ;
       
   712 }
       
   713 /*!
       
   714  * Action method
       
   715  * Stop the hold timer.
       
   716  */
       
   717 void CStateEngine::ClearHoldTimer()
       
   718 {
       
   719     m_timerif->cancelHoldTimer(m_index) ;
       
   720 }
       
   721 /*!
       
   722  * Action method
       
   723  * Stop the suppress timer.
       
   724  */
       
   725 void CStateEngine::ClearSuppressTimer()
       
   726 {
       
   727     m_timerif->cancelSuppressTimer(m_index) ;
       
   728 }
       
   729 /*!Helper method.
       
   730  * Create UI event
       
   731  * \param code The new UI event type (Touch, Release, Move, Hold)
       
   732  */
       
   733 CUiEvent* CStateEngine::createUIEventL(TUiEventCode code, const TPoint& aPos)
       
   734 {
       
   735 
       
   736     m_previousUiGenerated = code ;
       
   737     return CUiEvent::NewL(code, m_gestureStartXY, aPos, getPreviousXY(aPos),
       
   738         isTimerMessage(), m_hwe.iTarget, getInterval(), m_index, m_hwe.iTime.Int64()) ;
       
   739 }
       
   740 /*!
       
   741  * Return the previous XY position and store the current for next round
       
   742  */
       
   743 TPoint CStateEngine::getPreviousXY(const TPoint& aCurrentXY)
       
   744 {
       
   745     TPoint p = m_previousXY ;
       
   746     m_previousXY = aCurrentXY ;
       
   747     return p ;
       
   748 }
       
   749 /*!
       
   750  * \return true, if the current event was timer triggered
       
   751  */
       
   752 bool CStateEngine::isTimerMessage()
       
   753 {
       
   754     return (m_hwe.iType >= ETouchTimer); // NOTE: if new events are added at the end of the list this needs to be changed
       
   755 }
       
   756 /*!
       
   757  * Action method.
       
   758  * Generate the Touch UI event.
       
   759  * If there are a set of touch points collected, calculate the position to the
       
   760  * Touch UI event to be the average of the collected points.
       
   761  */
       
   762 void CStateEngine::ProduceTouch()
       
   763 {
       
   764     m_wasFiltered = false ;
       
   765     CUiEvent* cue = NULL;
       
   766     getInterval() ; // dummy call to initialize the variable....
       
   767     TInt err(KErrNone);
       
   768     if (iTouchPoints.Count()>0)
       
   769     {
       
   770         // calculate average of the touch points
       
   771         m_currentTouchXY = calculateTouchAverageFromPoints() ;
       
   772         TRAP(err, cue = createUIEventL(stmUiEventEngine::ETouch, m_currentTouchXY)) ;
       
   773     }
       
   774     else
       
   775     {
       
   776         TRAP(err, cue = createUIEventL(stmUiEventEngine::ETouch, m_uiEventXY)) ;
       
   777     }
       
   778     if(!err)
       
   779         m_config->m_uiEventSender->AddEvent(cue) ;
       
   780 }
       
   781 /*!
       
   782  * Action method
       
   783  * Generate the Move UI event.  The position of the event has been set in the SetCurrentPos
       
   784  * The previous position needs some special handling, if filtering has been used.
       
   785  * \sa SetCurrentPos
       
   786  */
       
   787 void CStateEngine::ProduceMove()
       
   788 {
       
   789     m_wasFiltered = false ;
       
   790     if (m_uiEventXY == m_previousXY) {
       
   791     return;
       
   792     }
       
   793     CUiEvent* cue = NULL;
       
   794     TRAPD(err, cue = createUIEventL(stmUiEventEngine::EMove, m_uiEventXY)) ;
       
   795 
       
   796     if(!err)
       
   797     	m_config->m_uiEventSender->AddEvent(cue) ;
       
   798 }
       
   799 /*!
       
   800  * Action method
       
   801  * Generate the Release UI event.
       
   802  */
       
   803 void CStateEngine::ProduceRelease()
       
   804 {
       
   805     m_wasFiltered = false ;
       
   806     CUiEvent* cue = NULL;
       
   807     TRAPD(err, cue = createUIEventL(stmUiEventEngine::ERelease, m_uiEventXY)) ;
       
   808     if(!err)
       
   809     	m_config->m_uiEventSender->AddEvent(cue) ;
       
   810 
       
   811     if (m_config->m_enableLogging)
       
   812     {
       
   813         LOGFLUSH ;
       
   814     }
       
   815 }
       
   816 /*!
       
   817  * Action method
       
   818  * Generate the Hold UI event.
       
   819  */
       
   820 void CStateEngine::ProduceHold()
       
   821 {
       
   822     m_wasFiltered = false ;
       
   823     CUiEvent* cue = NULL;
       
   824     TRAPD(err, cue = createUIEventL(stmUiEventEngine::EHold, m_holdCentre)) ;
       
   825     if(!err)
       
   826  	   m_config->m_uiEventSender->AddEvent(cue) ;
       
   827 
       
   828 }
       
   829 /*!
       
   830  * Action method
       
   831  * Rename the current event to drag.  This is used when the accidental up/down message pair
       
   832  * has been detected, the DOWN event is handled as it were a move event.
       
   833  */
       
   834 void CStateEngine::RenameToDrag()
       
   835 {
       
   836     m_hwe.iType = stmUiEventEngine::EDrag ;
       
   837 }
       
   838 /*!
       
   839  * Action method
       
   840  * Initialize the touch time area.  Clear the array for collected touch points and
       
   841  * calculate the touch rectangle.
       
   842  */
       
   843 void CStateEngine::PrepareTouchTimeArea()
       
   844 {
       
   845     if (iTouchPoints.Count()>0) iTouchPoints.Reset() ;
       
   846     m_touchRect = ToleranceRect(m_hwe.iPosition, m_config->m_touchTimeTolerance) ;
       
   847 }
       
   848 
       
   849 /*!
       
   850  * Action method
       
   851  * Initialize the touch area.  Clear the array for collected touch points and
       
   852  * calculate the touch rectangle.
       
   853  */
       
   854 void CStateEngine::PrepareTouchArea()
       
   855 {
       
   856     if (iTouchPoints.Count()>0) iTouchPoints.Reset() ;
       
   857     m_touchRect = ToleranceRect(m_hwe.iPosition, m_config->m_touchTolerance) ;
       
   858 }
       
   859 /*!
       
   860  * Action method
       
   861  * Initialize the hold area rectangle.
       
   862  */
       
   863 void CStateEngine::PrepareHoldArea()
       
   864 {
       
   865     m_holdRect = ToleranceRect(m_hwe.iPosition, m_config->m_holdTolerance) ;
       
   866 }
       
   867 /*!
       
   868  * Action method
       
   869  * Store the current position and time always when we see EDrag.  The stored value is used
       
   870  * to calculate correct speed after filtered messages.
       
   871  */
       
   872 void CStateEngine::StoreMovePos()
       
   873 {
       
   874     if (m_config->m_enableLogging)
       
   875     {
       
   876         LOGARG("store move pos from (%d, %d) to (%d, %d)",
       
   877                 m_lastFilteredPosition.iX, m_lastFilteredPosition.iY,m_hwe.iPosition.iX,
       
   878                 m_hwe.iPosition.iY  ) ;
       
   879     }
       
   880     m_lastFilteredPosition = m_hwe.iPosition ;
       
   881     m_lastFilteredMessageTime = m_hwe.iTime ;
       
   882 
       
   883 }
       
   884 /*!
       
   885  * Action method
       
   886  * Store the current position and time.
       
   887  */
       
   888 void CStateEngine::SetCurrentPos()
       
   889 {
       
   890     m_uiEventXY = m_hwe.iPosition ;
       
   891 }
       
   892 /*!
       
   893  * Action method
       
   894  * Initialize the gesture starting.
       
   895  */
       
   896 void CStateEngine::SetGestureStart()
       
   897 {
       
   898     m_gestureStartXY = m_hwe.iPosition ;
       
   899     m_previousXY = m_hwe.iPosition ;
       
   900     m_gestureTarget = m_hwe.iTarget ;
       
   901     iDragPoints.ResetAndDestroy() ;
       
   902     iTouchPoints.Reset() ;
       
   903 }
       
   904 /*!
       
   905  * Action method
       
   906  * Add current point to the set of touch points.
       
   907  */
       
   908 void CStateEngine::AddToTouch()
       
   909 {
       
   910     iTouchPoints.Append(THwEvent(m_hwe.iType,
       
   911                                  m_hwe.iPosition,
       
   912                                  m_hwe.iTime,
       
   913                                  m_hwe.iTarget,
       
   914                                  m_index)
       
   915                         ) ;
       
   916     // calculate the average of touch points and move the touch area accordingly
       
   917     // this allows slight movement of the figertip while inside touch time
       
   918     if (iTouchPoints.Count()>2)
       
   919     {
       
   920         TPoint newtp = calculateTouchAverageFromPoints() ;
       
   921         m_touchRect = ToleranceRect(newtp, m_config->m_touchTolerance) ;
       
   922         m_holdRect = ToleranceRect(newtp, m_config->m_holdTolerance) ;
       
   923     }
       
   924 }
       
   925 /*!
       
   926  * Action method
       
   927  * Add the current point to the set of dragging points.
       
   928  * The set of dragging points is examined to determine if a enw hold has been started.
       
   929  */
       
   930 void CStateEngine::AddDraggingPos()
       
   931 {
       
   932     iDragPoints.Append(new THwEvent(m_hwe.iType,
       
   933                                     m_hwe.iPosition,
       
   934                                     m_hwe.iTime,
       
   935                                     m_hwe.iTarget,
       
   936                                     m_index)
       
   937                        ) ;
       
   938 }
       
   939 /*!
       
   940  * HandleStateEvent processes one event, which can be either pointer event or timer event.
       
   941  * The event is handled by calling the turnStateMachine method.
       
   942  */
       
   943 bool CStateEngine::handleStateEvent()
       
   944 {
       
   945     // We get an event into m_hwe by this moment, lets kick the state machine
       
   946     m_wasFiltered = ETrue ;
       
   947     if (isStatemachineBlocked)
       
   948         return m_wasFiltered;
       
   949 
       
   950     CalculateDelta() ;
       
   951     turnStateMachine();
       
   952 
       
   953     m_previousPointerEventPosition = m_hwe.iPosition ;
       
   954     return m_wasFiltered ;
       
   955 }
       
   956 
       
   957 /*!
       
   958  *  Get the current touch rectangle.  If touch state not currently on, returns TRect(TPoint(0,0),TPoint(0,0))
       
   959  * (touch state meaning that the touch timer is still running and the points have been kept inside the area)
       
   960  */
       
   961 TRect CStateEngine::getTouchArea()
       
   962 {
       
   963     return m_touchRect ;
       
   964 }
       
   965 /*!
       
   966  * get the hold area rectangle
       
   967  */
       
   968 TRect CStateEngine::getHoldArea()
       
   969 {
       
   970     return m_holdRect ;
       
   971 }
       
   972 /*!
       
   973  * MStateMachine method.
       
   974  */
       
   975 bool CStateEngine::wasLastMessageFiltered()
       
   976 {
       
   977     return m_wasFiltered ;
       
   978 }
       
   979 
       
   980 /*!
       
   981  * Check if the last X points in the stored points look like the movement has stopped
       
   982  */
       
   983 bool CStateEngine::isNewHoldingPoint()
       
   984 {
       
   985     int x = iDragPoints.Count();
       
   986     if (x > 2)    // are there any points to be checked?
       
   987     {
       
   988         THwEvent* phwe = iDragPoints[x-1] ;
       
   989         THwEvent* phweinsidehold = phwe ;
       
   990         TRect recth = ToleranceRect(phwe->iPosition, m_config->m_holdTolerance) ;
       
   991         // Look backwards from the last point to see if there are enought points (enough in time) to look like a hold
       
   992         x -= 2 ;
       
   993         while (x > 0 && recth.Contains(iDragPoints[x]->iPosition))
       
   994         {
       
   995             phweinsidehold = iDragPoints[x];
       
   996             --x;
       
   997         }
       
   998         TTimeIntervalMicroSeconds tival = phwe->iTime.MicroSecondsFrom(phweinsidehold->iTime) ;
       
   999 
       
  1000         /**
       
  1001          * remove the extra points from the list if they are outside of holding area
       
  1002          */
       
  1003         while (x > 0)
       
  1004         {
       
  1005             THwEvent* p = iDragPoints[x] ;
       
  1006             delete p ;
       
  1007             iDragPoints.Remove(x) ;
       
  1008             --x ;
       
  1009         }
       
  1010 
       
  1011         // See the time difference of the two points which still are inside the hold area
       
  1012         TTimeIntervalMicroSeconds limit = m_config->m_holdTimerLimit/2 ;
       
  1013         if (tival > limit)
       
  1014         {
       
  1015             if (m_config->m_enableLogging)
       
  1016             {
       
  1017                 LOGARG("isNewHoldingPoint: %s, dragpoints count %d",
       
  1018                         stateNames[m_currentState], iDragPoints.Count()) ;
       
  1019             }
       
  1020             return true ;
       
  1021         }
       
  1022     }
       
  1023     else
       
  1024     {
       
  1025         // one or 0 points does not look like hold
       
  1026 
       
  1027     }
       
  1028     return false ;
       
  1029 }
       
  1030 /*!
       
  1031  * calculate simple average of the touch points, i.e. calculate the average of the previous and current
       
  1032  * position.  Note that the touch point remains the same, this just calculates new value for the UI position
       
  1033  */
       
  1034 void CStateEngine::CalculateTouchAverage()
       
  1035 {
       
  1036     m_uiEventXY.iX =  (m_uiEventXY.iX+m_hwe.iPosition.iX)/2 ;
       
  1037     m_uiEventXY.iY =  (m_uiEventXY.iY+m_hwe.iPosition.iY)/2 ;
       
  1038 }
       
  1039 /*!
       
  1040  * Calculate the movement vector.
       
  1041  */
       
  1042 void CStateEngine::CalculateDelta()
       
  1043 {
       
  1044     m_deltaVector.iX = m_hwe.iPosition.iX-m_previousPointerEventPosition.iX ;
       
  1045     m_deltaVector.iY = m_hwe.iPosition.iY-m_previousPointerEventPosition.iY ;
       
  1046 }
       
  1047 /*!internal
       
  1048  * Debug logging method
       
  1049  */
       
  1050 void CStateEngine::DebugPrintState(TStateMachineState anextstate)
       
  1051 {
       
  1052     if (m_config->m_enableLogging)
       
  1053     {
       
  1054     LOGARG("%s: cuiev(%d,%d) cTxy ((%d,%d)(%d,%d)) cHxy ((%d,%d)(%d,%d)) gsXY(%d,%d) dV(%d,%d) EVNT(%d,%d (%s)) going to %s",
       
  1055             stateNames[m_currentState],
       
  1056             m_uiEventXY.iX, m_uiEventXY.iY,
       
  1057             m_touchRect.iTl.iX, m_touchRect.iTl.iY,m_touchRect.iBr.iX, m_touchRect.iBr.iY,
       
  1058             m_holdRect.iTl.iX, m_holdRect.iTl.iY,m_holdRect.iBr.iX, m_holdRect.iBr.iY,
       
  1059             m_gestureStartXY.iX, m_gestureStartXY.iY,
       
  1060             m_deltaVector.iX, m_deltaVector.iY,
       
  1061             m_hwe.iPosition.iX, m_hwe.iPosition.iY, hweventNames[m_hwe.iType],
       
  1062             stateNames[anextstate]
       
  1063             );
       
  1064     }
       
  1065 }
       
  1066 
       
  1067 /*!
       
  1068  * calculate the rectangle for touch or hold
       
  1069  */
       
  1070 TRect CStateEngine::ToleranceRect(const TPoint& aCenterPoint, const TPoint& tolerance)
       
  1071 {
       
  1072     // grow by the tolerance length, while keeping the center point
       
  1073     TRect toleranceRect(
       
  1074         aCenterPoint - tolerance,
       
  1075         aCenterPoint + tolerance);
       
  1076     return toleranceRect;
       
  1077 }
       
  1078 /*!
       
  1079  * turnStateMachine.  Go trough the state elements found for the current event
       
  1080  * until the event has been consumed.
       
  1081  *
       
  1082  * \pre m_currentState defines the current state and the index to the allStates array.
       
  1083  * \pre m_hwe is the message being handled.  The corresponding STATE_ELEMENT array must be found and processed.
       
  1084  *
       
  1085  */
       
  1086 void CStateEngine::turnStateMachine()
       
  1087 {
       
  1088 
       
  1089     const STATE_ELEMENT* pelement ;
       
  1090     m_eventConsumed = false ;   // run the loop until the event has been consumed
       
  1091     // Now run trough the motions of the state elements, and prepare to change to next state while doing so.
       
  1092     // If the state elements set the m_eventConsumed then all is done
       
  1093     isStatemachineBlocked = true;
       
  1094     while (!m_eventConsumed)
       
  1095     {
       
  1096         int i = 0 ;
       
  1097         const STATE* const pcurrentstate = allStates[m_currentState] ;
       
  1098         // Since each state definition must contain entries for all possible events the following loop cannot fail ;-)
       
  1099         while (pcurrentstate[i].theEvent != m_hwe.iType ) ++i ;
       
  1100         pelement = pcurrentstate[i].stateElements ;
       
  1101         TStateMachineState      nextState = Eignore ;
       
  1102         /*
       
  1103          * Handle the individual state elements.  If there is a condition function,
       
  1104          * call the function and if it returns true, handle the action function and possible next state
       
  1105          * if the condition returns false, continue to next element
       
  1106          * if there is no condition, run the action function if it exists.
       
  1107          * if the next state is defined (i.e it is != Eignore), go to that state
       
  1108          */
       
  1109         while (nextState == Eignore)
       
  1110         {
       
  1111             condition_t cndfunc = pelement->conditionFunction ;
       
  1112             action_t    actfunc = pelement->actionFunction ;
       
  1113             if (cndfunc != 0)
       
  1114             {
       
  1115                 /*
       
  1116                  * There was a condition function, call it to see whether the action needs to performed and/or the next satte defined
       
  1117                  */
       
  1118                 if (cndfunc(this))
       
  1119                 {
       
  1120                     // Condition was true, handle it
       
  1121                     // call the action if it exists
       
  1122                     if (actfunc != 0) actfunc(this) ;
       
  1123                     // and now get to the next state
       
  1124                     nextState   = pelement->nextState ; // Note that while this remains Eignore there are elements to be run
       
  1125                 }
       
  1126             }
       
  1127             else
       
  1128             {
       
  1129                 /**
       
  1130                  * No condition function, call the possible action function and get the next state
       
  1131                  */
       
  1132                 if (actfunc != 0) actfunc(this) ;
       
  1133                 nextState   = pelement->nextState ;     // Note that while this remains Eignore there are elements to be run
       
  1134             }
       
  1135             ++pelement ;    // next entry in the elements
       
  1136         }
       
  1137         if (m_config->m_enableLogging) DebugPrintState(nextState) ;
       
  1138         m_currentState = nextState ;    // Change to the next state
       
  1139     }
       
  1140     isStatemachineBlocked = false;
       
  1141 }
       
  1142 TTimeIntervalMicroSeconds CStateEngine::getInterval()
       
  1143 {
       
  1144     TTime now ;
       
  1145     now.HomeTime() ;
       
  1146     TTimeIntervalMicroSeconds interval = now.MicroSecondsFrom(m_lastMessageTime) ;
       
  1147     m_lastMessageTime = now ;
       
  1148     return interval ;
       
  1149 }
       
  1150 
       
  1151 TPoint CStateEngine::calculateTouchAverageFromPoints()
       
  1152 {
       
  1153     TPoint tp ;
       
  1154     int count = iTouchPoints.Count() ;
       
  1155     for (int i = 0; i < count; i++)
       
  1156     {
       
  1157         tp += iTouchPoints[i].iPosition;
       
  1158     }
       
  1159     if(count)
       
  1160         {
       
  1161         tp.iX /= count ;
       
  1162         tp.iY /= count ;
       
  1163         }
       
  1164     return tp ;
       
  1165 }
       
  1166