// Activation - starts running the object. Sets m_fRunning and generates IsRunning event. void MHGroup::Activation(MHEngine *engine) { if (m_fRunning) { return; } MHRoot::Activation(engine); // Run any start-up actions. engine->AddActions(m_StartUp); engine->RunActions(); // Activate the ingredients in order. for (int i = 0; i < m_Items.Size(); i++) { MHIngredient *pIngredient = m_Items.GetAt(i); if (pIngredient->InitiallyActive()) { pIngredient->Activation(engine); } } m_fRunning = true; // Record the time here. This is the basis for absolute times. m_StartTime.start(); // Don't generate IsRunning here - that's done by the sub-classes. }
// Create a clone of the target and add it to the ingredients. void MHGroup::MakeClone(MHRoot *pTarget, MHRoot *pRef, MHEngine *engine) { MHIngredient *pClone = pTarget->Clone(engine); // Clone it. pClone->m_ObjectReference.m_GroupId.Copy(m_ObjectReference.m_GroupId); // Group id is the same as this. pClone->m_ObjectReference.m_nObjectNo = ++m_nLastId; // Create a new object id. m_Items.Append(pClone); // Set the object reference result to the newly constructed ref. pRef->SetVariableValue(pClone->m_ObjectReference); pClone->Preparation(engine); // Prepare the clone. }
// Preparation - sets up the run-time representation. Sets m_fAvailable and generates IsAvailable event. void MHGroup::Preparation(MHEngine *engine) { // Prepare the ingredients first if they are initially active or are initially available programs. for (int i = 0; i < m_Items.Size(); i++) { MHIngredient *pIngredient = m_Items.GetAt(i); if (pIngredient->InitiallyActive() || pIngredient->InitiallyAvailable()) { pIngredient->Preparation(engine); } } MHRoot::Preparation(engine); // Prepare the root object and send the IsAvailable event. }
void MHEngine::TransitionToScene(const MHObjectRef &target) { int i; if (m_fInTransition) { // TransitionTo is not allowed in OnStartUp or OnCloseDown actions. MHLOG(MHLogWarning, "WARN TransitionTo during transition - ignoring"); return; } if (target.m_GroupId.Size() == 0) { return; // No file name. } QString csPath = GetPathName(target.m_GroupId); // Check that the file exists before we commit to the transition. // This may block if we cannot be sure whether the object is present. QByteArray text; if (! m_Context->GetCarouselData(csPath, text)) { EngineEvent(2); // GroupIDRefError return; } // Parse and run the file. MHGroup *pProgram = ParseProgram(text); if (!pProgram ) MHERROR("Empty scene"); if (pProgram->m_fIsApp) { delete pProgram; MHERROR("Expected a scene"); } // Clear the action queue of anything pending. m_ActionStack.clear(); // At this point we have managed to load the scene. // Deactivate any non-shared ingredients in the application. MHApplication *pApp = CurrentApp(); for (i = pApp->m_Items.Size(); i > 0; i--) { MHIngredient *pItem = pApp->m_Items.GetAt(i - 1); if (! pItem->IsShared()) { pItem->Deactivation(this); // This does not remove them from the display stack. } } m_fInTransition = true; // TransitionTo etc are not allowed. if (pApp->m_pCurrentScene) { pApp->m_pCurrentScene->Deactivation(this); // This may involve a call to RunActions pApp->m_pCurrentScene->Destruction(this); } // Everything that belongs to the previous scene should have been removed from the display stack. // At this point we may have added actions to the queue as a result of synchronous // events during the deactivation. // Remove any events from the asynch event queue unless they derive from // the application itself or a shared ingredient. MHAsynchEvent *pEvent; QQueue<MHAsynchEvent *>::iterator it = m_EventQueue.begin(); while (it != m_EventQueue.end()) { pEvent = *it; if (!pEvent->pEventSource->IsShared()) { delete pEvent; it = m_EventQueue.erase(it); } else { ++it; } } // Can now actually delete the old scene. if (pApp->m_pCurrentScene) { delete(pApp->m_pCurrentScene); pApp->m_pCurrentScene = NULL; } m_Interacting = 0; // Switch to the new scene. CurrentApp()->m_pCurrentScene = static_cast< MHScene* >(pProgram); SetInputRegister(CurrentScene()->m_nEventReg); m_redrawRegion = QRegion(0, 0, CurrentScene()->m_nSceneCoordX, CurrentScene()->m_nSceneCoordY); // Redraw the whole screen if ((__mhlogoptions & MHLogScenes) && __mhlogStream != 0) // Print it so we know what's going on. { pProgram->PrintMe(__mhlogStream, 0); } pProgram->Preparation(this); pProgram->Activation(this); m_fInTransition = false; // The transition is complete }
void MHGroup::Initialise(MHParseNode *p, MHEngine *engine) { engine->GetGroupId().Copy(""); // Set to empty before we start (just in case). MHRoot::Initialise(p, engine); // Must be an external reference with an object number of zero. if (m_ObjectReference.m_nObjectNo != 0 || m_ObjectReference.m_GroupId.Size() == 0) { MHERROR("Object reference for a group object must be zero and external"); } // Set the group id for the rest of the group to this. engine->GetGroupId().Copy(m_ObjectReference.m_GroupId); // Some of the information is irrelevant. // MHParseNode *pStdId = p->GetNamedArg(C_STANDARD_IDENTIFIER); // MHParseNode *pStdVersion = p->GetNamedArg(C_STANDARD_VERSION); // MHParseNode *pObjectInfo = p->GetNamedArg(C_OBJECT_INFORMATION); MHParseNode *pOnStartUp = p->GetNamedArg(C_ON_START_UP); if (pOnStartUp) { m_StartUp.Initialise(pOnStartUp, engine); } MHParseNode *pOnCloseDown = p->GetNamedArg(C_ON_CLOSE_DOWN); if (pOnCloseDown) { m_CloseDown.Initialise(pOnCloseDown, engine); } MHParseNode *pOriginalGCPrio = p->GetNamedArg(C_ORIGINAL_GC_PRIORITY); if (pOriginalGCPrio) { m_nOrigGCPriority = pOriginalGCPrio->GetArgN(0)->GetIntValue(); } // Ignore the other stuff at the moment. MHParseNode *pItems = p->GetNamedArg(C_ITEMS); if (pItems == NULL) { p->Failure("Missing :Items block"); return; } for (int i = 0; i < pItems->GetArgCount(); i++) { MHParseNode *pItem = pItems->GetArgN(i); MHIngredient *pIngredient = NULL; try { // Generate the particular kind of ingredient. switch (pItem->GetTagNo()) { case C_RESIDENT_PROGRAM: pIngredient = new MHResidentProgram; break; case C_REMOTE_PROGRAM: pIngredient = new MHRemoteProgram; break; case C_INTERCHANGED_PROGRAM: pIngredient = new MHInterChgProgram; break; case C_PALETTE: pIngredient = new MHPalette; break; case C_FONT: pIngredient = new MHFont; break; case C_CURSOR_SHAPE: pIngredient = new MHCursorShape; break; case C_BOOLEAN_VARIABLE: pIngredient = new MHBooleanVar; break; case C_INTEGER_VARIABLE: pIngredient = new MHIntegerVar; break; case C_OCTET_STRING_VARIABLE: pIngredient = new MHOctetStrVar; break; case C_OBJECT_REF_VARIABLE: pIngredient = new MHObjectRefVar; break; case C_CONTENT_REF_VARIABLE: pIngredient = new MHContentRefVar; break; case C_LINK: pIngredient = new MHLink; break; case C_STREAM: pIngredient = new MHStream; break; case C_BITMAP: pIngredient = new MHBitmap; break; case C_LINE_ART: pIngredient = new MHLineArt; break; case C_DYNAMIC_LINE_ART: pIngredient = new MHDynamicLineArt; break; case C_RECTANGLE: pIngredient = new MHRectangle; break; case C_HOTSPOT: pIngredient = new MHHotSpot; break; case C_SWITCH_BUTTON: pIngredient = new MHSwitchButton; break; case C_PUSH_BUTTON: pIngredient = new MHPushButton; break; case C_TEXT: pIngredient = new MHText; break; case C_ENTRY_FIELD: pIngredient = new MHEntryField; break; case C_HYPER_TEXT: pIngredient = new MHHyperText; break; case C_SLIDER: pIngredient = new MHSlider; break; case C_TOKEN_GROUP: pIngredient = new MHTokenGroup; break; case C_LIST_GROUP: pIngredient = new MHListGroup; break; default: MHLOG(MHLogWarning, QString("Unknown ingredient %1").arg(pItem->GetTagNo())); // Future proofing: ignore any ingredients that we don't know about. // Obviously these can only arise in the binary coding. } if (pIngredient) { // Initialise it from its argments. pIngredient->Initialise(pItem, engine); // Remember the highest numbered ingredient if (pIngredient->m_ObjectReference.m_nObjectNo > m_nLastId) { m_nLastId = pIngredient->m_ObjectReference.m_nObjectNo; } // Add it to the ingedients of this group. m_Items.Append(pIngredient); } } catch (...) { delete(pIngredient); throw; } } }