Ticket #5606: fixes-mhegupdate.patch

File fixes-mhegupdate.patch, 54.6 KB (added by David Matthews <dm@…>, 17 years ago)
  • libs/libmythfreemheg/Actions.cpp

     
    11/* Actions.cpp
    22
    3    Copyright (C)  David C. J. Matthews 2004  dm at prolingua.co.uk
     3   Copyright (C)  David C. J. Matthews 2004, 2008  dm at prolingua.co.uk
    44
    55   This program is free software; you can redistribute it and/or
    66   modify it under the terms of the GNU General Public License
     
    9393        case C_GET_ENTRY_POINT: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // EntryField
    9494        case C_GET_FILL_COLOUR: pAction = new MHGetFillColour; break;
    9595        case C_GET_FIRST_ITEM: pAction = new MHGetFirstItem; break;
    96         case C_GET_HIGHLIGHT_STATUS: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break;// ?
    97         case C_GET_INTERACTION_STATUS: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break;// ?
     96        case C_GET_HIGHLIGHT_STATUS: pAction = new MHGetHighlightStatus; break;
     97        case C_GET_INTERACTION_STATUS: pAction = new MHGetInteractionStatus; break;
    9898        case C_GET_ITEM_STATUS: pAction = new MHGetItemStatus; break;
    9999        case C_GET_LABEL: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break;// PushButton
    100100        case C_GET_LAST_ANCHOR_FIRED: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break;// HyperText
     
    104104        case C_GET_LIST_ITEM: pAction = new MHGetListItem; break;
    105105        case C_GET_LIST_SIZE: pAction = new MHGetListSize; break;
    106106        case C_GET_OVERWRITE_MODE: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break;// ?
    107         case C_GET_PORTION: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break;// Slider
     107        case C_GET_PORTION: pAction = new MHGetPortion; break;
    108108        case C_GET_POSITION: pAction = new MHGetPosition; break;
    109109        case C_GET_RUNNING_STATUS: pAction = new MHGetRunningStatus; break;
    110110        case C_GET_SELECTION_STATUS: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break;// ?
    111         case C_GET_SLIDER_VALUE: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break;// Slider
     111        case C_GET_SLIDER_VALUE: pAction = new MHGetSliderValue; break;
    112112        case C_GET_TEXT_CONTENT: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break;// Text
    113113        case C_GET_TEXT_DATA: pAction = new MHGetTextData; break;
    114114        case C_GET_TOKEN_POSITION: pAction = new MHGetTokenPosition; break;
     
    145145        case C_SET_FILL_COLOUR: pAction = new MHSetFillColour; break;
    146146        case C_SET_FIRST_ITEM: pAction = new MHSetFirstItem; break;
    147147        case C_SET_FONT_REF: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // Text
    148         case C_SET_HIGHLIGHT_STATUS: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // ?
    149         case C_SET_INTERACTION_STATUS: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // ?
     148        case C_SET_HIGHLIGHT_STATUS: pAction = new MHSetHighlightStatus; break;
     149        case C_SET_INTERACTION_STATUS: pAction = new MHSetInteractionStatus; break;
    150150        case C_SET_LABEL: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // PushButton
    151151        case C_SET_LINE_COLOUR: pAction = new MHSetLineColour; break;
    152152        case C_SET_LINE_STYLE: pAction = new MHSetLineStyle; break;
    153153        case C_SET_LINE_WIDTH: pAction = new MHSetLineWidth; break;
    154154        case C_SET_OVERWRITE_MODE: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // EntryField
    155155        case C_SET_PALETTE_REF: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // Visible
    156         case C_SET_PORTION: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // Slider
     156        case C_SET_PORTION: pAction = new MHSetPortion; break;
    157157        case C_SET_POSITION: pAction = new MHSetPosition; break;
    158         case C_SET_SLIDER_VALUE: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // Slider
     158        case C_SET_SLIDER_VALUE: pAction = new MHSetSliderValue; break;
    159159        case C_SET_SPEED: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // ?
    160160        case C_SET_TIMER: pAction = new MHSetTimer; break;
    161161        case C_SET_TRANSPARENCY: pAction = new MHSetTransparency; break;
    162162        case C_SET_VARIABLE: pAction = new MHSetVariable; break;
    163163        case C_SET_VOLUME: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // ?
    164164        case C_SPAWN: pAction = new MHSpawn; break;
    165         case C_STEP: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // Slider
     165        case C_STEP: pAction = new MHStep; break;
    166166        case C_STOP: pAction = new MHStop; break;
    167167        case C_STORE_PERSISTENT: pAction = new MHPersistent(":StorePersistent", false); break;
    168168        case C_SUBTRACT: pAction = new MHSubtract; break;
     
    184184        case C_SET_FOCUS_POSITION: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // HyperText
    185185        case C_SET_BITMAP_DECODE_OFFSET: pAction = new MHSetBitmapDecodeOffset; break;
    186186        case C_GET_BITMAP_DECODE_OFFSET: pAction = new MHGetBitmapDecodeOffset; break;
    187         case C_SET_SLIDER_PARAMETERS: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // ?
     187        case C_SET_SLIDER_PARAMETERS: pAction = new MHSetSliderParameters; break;
    188188
    189189        default:
    190190            MHLOG(MHLogWarning, QString("Unknown action %1").arg(pElemAction->GetTagNo()));
  • libs/libmythfreemheg/Engine.cpp

     
    11/* Engine.cpp
    22
    3    Copyright (C)  David C. J. Matthews 2004  dm at prolingua.co.uk
     3   Copyright (C)  David C. J. Matthews 2004, 2008  dm at prolingua.co.uk
    44
    55   This program is free software; you can redistribute it and/or
    66   modify it under the terms of the GNU General Public License
     
    3131#include "ASN1Codes.h"
    3232#include "Logging.h"
    3333#include "freemheg.h"
     34#include "Visible.h"  // For MHInteractible
    3435
    3536#include <stdio.h>
    3637#include <stdlib.h>
     
    5051    m_ExternContentTable.setAutoDelete(true);
    5152
    5253    m_fBooting = true;
     54    m_Interacting = 0;
    5355}
    5456
    5557MHEngine::~MHEngine()
     
    307309        pApp->m_pCurrentScene = NULL;
    308310    }
    309311
     312    m_Interacting = 0;
    310313
    311314    // Switch to the new scene.
    312315    CurrentApp()->m_pCurrentScene = (MHScene*) pProgram;
     
    604607{
    605608    MHScene *pScene = CurrentScene();
    606609    if (! pScene) return;
    607     EventTriggered(pScene, EventUserInput, nCode);
     610    // Various keys generate engine events as well as user events.
     611    // These are generated before the user events and even if there
     612    // is an interactible.
     613    switch (nCode)
     614    {
     615    case 104:
     616    case 105: // Text key
     617        EventTriggered(pScene, EventEngineEvent, 4);
     618        break;
     619    case 16: // Text Exit/Cancel key
     620    case 100: // Red
     621    case 101: // Green
     622    case 102: // Yellow
     623    case 103: // Blue
     624        EventTriggered(pScene, EventEngineEvent, nCode);
     625        break;
     626    }
     627
     628    // If we are interacting with an interactible send the key
     629    // there otherwise generate a user event.
     630    if (m_Interacting)
     631        m_Interacting->KeyEvent(this, nCode);
     632    else EventTriggered(pScene, EventUserInput, nCode);
    608633}
    609634
    610635// Called by an ingredient wanting external content.
  • libs/libmythfreemheg/ParseText.cpp

     
    11/* ParseText.cpp
    22
    3    Copyright (C)  David C. J. Matthews 2004  dm at prolingua.co.uk
     3   Copyright (C)  David C. J. Matthews 2004, 2008  dm at prolingua.co.uk
    44
    55   This program is free software; you can redistribute it and/or
    66   modify it under the terms of the GNU General Public License
     
    536536                if (m_nInt > 0) return;
    537537                m_nInt = MHText::GetStartCorner(buff);
    538538                if (m_nInt > 0) return;
     539                m_nInt = MHSlider::GetOrientation(buff);
     540                if (m_nInt > 0) return;
     541                m_nInt = MHSlider::GetStyle(buff);
     542                if (m_nInt > 0) return;
    539543
    540544                // Check the colour table.  If it's there generate a string containing the colour info.
    541545                for (int i = 0; i < (int)(sizeof(colourTable)/sizeof(colourTable[0])); i++) {
  • libs/libmythfreemheg/Text.cpp

     
    11/* Text.cpp
    22
    3    Copyright (C)  David C. J. Matthews 2004  dm at prolingua.co.uk
     3   Copyright (C)  David C. J. Matthews 2004, 2008  dm at prolingua.co.uk
    44
    55   This program is free software; you can redistribute it and/or
    66   modify it under the terms of the GNU General Public License
     
    463463                    pNewLine->m_Items.Append(pNewItem);
    464464                    pNewItem->m_Unicode = pItem->m_Unicode.mid(nNewStart, nNewWidth);
    465465                    pNewItem->m_nUnicode = nNewWidth;
     466                    // Move any remaining items, e.g. in a different colour, from this line onto the new line.
     467                    while (pLine->m_Items.Size() > j+1) {
     468                        pNewLine->m_Items.Append(pLine->m_Items.GetAt(j+1));
     469                        pLine->m_Items.RemoveAt(j+1);
     470                    }
    466471                }
    467472                // Remove any spaces at the end of the old section.  If we don't do that and
    468473                // we are centering or right aligning the text we'll get it wrong.
     
    534539}
    535540
    536541
    537 MHHyperText::MHHyperText()
     542MHHyperText::MHHyperText(): MHInteractible(this)
    538543{
    539544
    540545}
  • libs/libmythfreemheg/Root.h

     
    176176    virtual void SetVideoDecodeOffset(int /*newXOffset*/, int /*newYOffset*/, MHEngine *) { InvalidAction("SetVideoDecodeOffset"); }
    177177    virtual void GetVideoDecodeOffset(MHRoot * /*pXOffset*/, MHRoot */*pYOffset*/, MHEngine *) { InvalidAction("GetVideoDecodeOffset"); }
    178178
     179    // Actions on Interactibles.
     180    virtual void SetInteractionStatus(bool /*newStatus*/, MHEngine *) { InvalidAction("SetInteractionStatus"); }
     181    virtual bool GetInteractionStatus(void) { InvalidAction("GetInteractionStatus"); return false; }
     182    virtual void SetHighlightStatus(bool /*newStatus*/, MHEngine *engine) { InvalidAction("SetHighlightStatus"); }
     183    virtual bool GetHighlightStatus(void) { InvalidAction("GetHighlightStatus"); return false; }
     184
     185    // Actions on Sliders.
     186    virtual void Step(int /*nbSteps*/, MHEngine */*engine*/) { InvalidAction("Step"); }
     187    virtual void SetSliderValue(int /*nbSteps*/, MHEngine */*engine*/) { InvalidAction("SetSliderValue"); }
     188    virtual int GetSliderValue(void) { InvalidAction("GetSliderValue"); return 0; }
     189    virtual void SetPortion(int /*newPortion*/, MHEngine */*engine*/) { InvalidAction("SetPortion"); }
     190    virtual int GetPortion(void) { InvalidAction("GetPortion"); return 0; }
     191    // Additional action defined in UK MHEG.
     192    virtual void SetSliderParameters(int /*newMin*/, int /*newMax*/, int /*newStep*/, MHEngine */*engine*/)
     193         { InvalidAction("SetSliderParameters"); }
     194
    179195protected:
    180196
    181197    void InvalidAction(const char *actionName);
  • libs/libmythfreemheg/BaseActions.h

     
    11/* BaseActions.h
    22
    3    Copyright (C)  David C. J. Matthews 2004  dm at prolingua.co.uk
     3   Copyright (C)  David C. J. Matthews 2004, 2008  dm at prolingua.co.uk
    44
    55   This program is free software; you can redistribute it and/or
    66   modify it under the terms of the GNU General Public License
     
    7373    MHGenericInteger m_Argument1, m_Argument2;
    7474};
    7575
     76// Base class for actions with three integers.  Used for SetSliderParameters
     77class MHActionInt3: public MHElemAction
     78{
     79public:
     80    MHActionInt3(const char *name): MHElemAction(name) {}
     81    virtual void Initialise(MHParseNode *p, MHEngine *engine);
     82    virtual void PrintArgs(FILE *fd, int nTabs) const;
     83    virtual void Perform(MHEngine *engine);
     84    virtual void CallAction(MHEngine *engine, MHRoot *pTarget, int nArg1, int nArg2, int nArg3) = 0;
     85protected:
     86    MHGenericInteger m_Argument1, m_Argument2, m_Argument3;
     87};
     88
    7689// Base class for actions with four integers.  Used in the DynamicLineArt class
    7790class MHActionInt4: public MHElemAction
    7891{
     
    139152};
    140153
    141154
     155// Base class for actions with a single boolean argument.
     156class MHActionBool: public MHElemAction
     157{
     158public:
     159    MHActionBool(const char *name): MHElemAction(name) {}
     160    virtual void Initialise(MHParseNode *p, MHEngine *engine);
     161    virtual void PrintArgs(FILE *fd, int) const { m_Argument.PrintMe(fd, 0); }
     162    virtual void Perform(MHEngine *engine);
     163    virtual void CallAction(MHEngine *engine, MHRoot *pTarget, bool fArg) = 0;
     164protected:
     165    MHGenericBoolean m_Argument;
     166};
     167
    142168#endif
  • libs/libmythfreemheg/Visible.h

     
    11/* Visible.h
    22
    3    Copyright (C)  David C. J. Matthews 2004  dm at prolingua.co.uk
     3   Copyright (C)  David C. J. Matthews 2004, 2008  dm at prolingua.co.uk
    44
    55   This program is free software; you can redistribute it and/or
    66   modify it under the terms of the GNU General Public License
     
    124124    virtual MHIngredient *Clone(MHEngine *) { return new MHRectangle(*this); } // Create a clone of this ingredient.
    125125};
    126126
     127// The Interactible class is described as a "mix-in" class.  It is used
     128// in various classes which complicates inheritance.
    127129class MHInteractible
    128130{
    129131public:
    130     MHInteractible();
     132    MHInteractible(MHVisible *parent);
    131133    virtual ~MHInteractible();
    132     virtual void Initialise(MHParseNode *p, MHEngine *engine);
    133     virtual void PrintMe(FILE *fd, int nTabs) const;
     134    void Initialise(MHParseNode *p, MHEngine *engine);
     135    void PrintMe(FILE *fd, int nTabs) const;
     136
     137    virtual void Interaction(MHEngine *engine);
     138
     139    // This is called whenever a key is pressed while this
     140    // interactible is set to interactive.
     141    virtual void KeyEvent(MHEngine */*engine*/, int /*nCode*/) {}
     142    virtual void InteractionCompleted(MHEngine */*engine*/) {}
     143
     144    void InteractSetInteractionStatus(bool newStatus, MHEngine *engine);
     145    bool InteractGetInteractionStatus(void) { return m_fInteractionStatus; }
     146    void InteractSetHighlightStatus(bool newStatus, MHEngine *engine);
     147    bool InteractGetHighlightStatus(void) { return m_fHighlightStatus; }
     148    // InteractDeactivation should be applied in every Deactivation action
     149    // of derived classes.
     150    void InteractDeactivation(void) { m_fInteractionStatus = false; }
     151
     152protected:
     153    // Exchanged attributes
     154    bool     m_fEngineResp;
     155    MHColour m_highlightRefColour;
     156    // Internal attributes
     157    bool     m_fHighlightStatus;
     158    bool     m_fInteractionStatus;
     159
     160private:
     161    MHVisible *m_parent;
    134162};
    135163
    136164class MHSlider : public MHVisible, public MHInteractible
     
    141169    virtual const char *ClassName() { return "Slider"; }
    142170    virtual void Initialise(MHParseNode *p, MHEngine *engine);
    143171    virtual void PrintMe(FILE *fd, int nTabs) const;
    144     virtual void Display(MHEngine *) {} // Not (yet?) supported
     172    virtual void Display(MHEngine *);
     173    virtual void Preparation(MHEngine *engine);
     174
     175    virtual void Interaction(MHEngine *engine);
     176    virtual void InteractionCompleted(MHEngine *engine);
     177    virtual void KeyEvent(MHEngine *engine, int nCode);
     178
     179    // Implement the actions in the main inheritance line.
     180    virtual void SetInteractionStatus(bool newStatus, MHEngine *engine)
     181    { InteractSetInteractionStatus(newStatus, engine); }
     182    virtual bool GetInteractionStatus(void) { return InteractGetInteractionStatus(); }
     183    virtual void SetHighlightStatus(bool newStatus, MHEngine *engine)
     184    { InteractSetHighlightStatus(newStatus, engine); }
     185    virtual bool GetHighlightStatus(void) { return InteractGetHighlightStatus(); }
     186    virtual void Deactivation(MHEngine *engine) { InteractDeactivation(); }
     187
     188    // Actions
     189    virtual void Step(int nbSteps, MHEngine *engine);
     190    virtual void SetSliderValue(int newValue, MHEngine *engine);
     191    virtual int GetSliderValue(void) { return slider_value; }
     192    virtual void SetPortion(int newPortion, MHEngine *engine);
     193    virtual int GetPortion(void) { return portion; }
     194    // Additional action defined in UK MHEG.
     195    virtual void SetSliderParameters(int newMin, int newMax, int newStep, MHEngine *engine);
     196
     197    // Enumerated type lookup functions for the text parser.
     198    static int GetOrientation(const char *str);
     199    static int GetStyle(const char *str);
     200protected:
     201    void Increment(MHEngine *engine);
     202    void Decrement(MHEngine *engine);
     203
     204    // Exchanged attributes
     205    // Orientation and direction of increasing value.
     206    enum SliderOrientation { SliderLeft = 1, SliderRight, SliderUp, SliderDown }
     207        m_orientation;
     208    int initial_value, initial_portion;
     209    int orig_max_value, orig_min_value, orig_step_size;
     210    // Style of slider.  Normal represents a mark on a scale,
     211    // Thermometer a range from the start up to the mark and Proportional
     212    // a range from the slider to the portion.
     213    enum SliderStyle { SliderNormal = 1, SliderThermo, SliderProp }
     214        m_style;
     215    MHColour m_sliderRefColour;
     216    // Internal attributes
     217    // In UK MHEG min_value, max_value and step_size can be changed.
     218    int max_value, min_value, step_size;
     219    int slider_value, portion;
    145220};
    146221
    147222class MHEntryField : public MHVisible, public MHInteractible
     
    153228    virtual void Initialise(MHParseNode *p, MHEngine *engine);
    154229    virtual void PrintMe(FILE *fd, int nTabs) const;
    155230    virtual void Display(MHEngine *) {} // Not (yet?) supported
     231
     232    // Implement the actions in the main inheritance line.
     233    virtual void SetInteractionStatus(bool newStatus, MHEngine *engine)
     234    { InteractSetInteractionStatus(newStatus, engine); }
     235    virtual bool GetInteractionStatus(void) { return InteractGetInteractionStatus(); }
     236    virtual void SetHighlightStatus(bool newStatus, MHEngine *engine)
     237    { InteractSetHighlightStatus(newStatus, engine); }
     238    virtual bool GetHighlightStatus(void) { return InteractGetHighlightStatus(); }
     239    virtual void Deactivation(MHEngine *engine) { InteractDeactivation(); }
    156240};
    157241
    158242// Button - not needed for UK MHEG.
     
    311395    virtual void CallAction(MHEngine *engine, MHRoot *pTarget, int nArg) { pTarget->SetLineStyle(nArg, engine); };
    312396};
    313397
     398class MHSetInteractionStatus: public MHActionBool
     399{
     400public:
     401    MHSetInteractionStatus(): MHActionBool("SetInteractionStatus") {}
     402    virtual void CallAction(MHEngine *engine, MHRoot *pTarget, bool newStatus)
     403    { Target(engine)->SetInteractionStatus(newStatus, engine); }
     404};
     405
     406class MHGetInteractionStatus: public MHActionObjectRef
     407{
     408public:
     409    MHGetInteractionStatus(): MHActionObjectRef(":GetInteractionStatus")  {}
     410    virtual void CallAction(MHEngine *, MHRoot *pTarget, MHRoot *pResult)
     411        { pResult->SetVariableValue(pTarget->GetInteractionStatus());}
     412};
     413
     414class MHSetHighlightStatus: public MHActionBool
     415{
     416public:
     417    MHSetHighlightStatus(): MHActionBool("SetHighlightStatus") {}
     418    virtual void CallAction(MHEngine *engine, MHRoot *pTarget, bool newStatus)
     419    { Target(engine)->SetHighlightStatus(newStatus, engine); }
     420};
     421
     422class MHGetHighlightStatus: public MHActionObjectRef
     423{
     424public:
     425    MHGetHighlightStatus(): MHActionObjectRef(":GetHighlightStatus")  {}
     426    virtual void CallAction(MHEngine *, MHRoot *pTarget, MHRoot *pResult)
     427        { pResult->SetVariableValue(pTarget->GetHighlightStatus());}
     428};
     429
     430class MHStep: public MHActionInt
     431{
     432public:
     433    MHStep(): MHActionInt(":Step") {}
     434    virtual void CallAction(MHEngine *engine, MHRoot *pTarget, int nArg) { pTarget->Step(nArg, engine); };
     435};
     436
     437class MHSetSliderValue: public MHActionInt
     438{
     439public:
     440    MHSetSliderValue(): MHActionInt(":SetSliderValue") {}
     441    virtual void CallAction(MHEngine *engine, MHRoot *pTarget, int nArg) { pTarget->SetSliderValue(nArg, engine); };
     442};
     443
     444class MHGetSliderValue: public MHActionObjectRef
     445{
     446public:
     447    MHGetSliderValue(): MHActionObjectRef(":GetSliderValue")  {}
     448    virtual void CallAction(MHEngine *, MHRoot *pTarget, MHRoot *pResult)
     449        { pResult->SetVariableValue(pTarget->GetSliderValue());}
     450};
     451
     452class MHSetPortion: public MHActionInt
     453{
     454public:
     455    MHSetPortion(): MHActionInt(":SetPortion") {}
     456    virtual void CallAction(MHEngine *engine, MHRoot *pTarget, int nArg) { pTarget->SetPortion(nArg, engine); };
     457};
     458
     459class MHGetPortion: public MHActionObjectRef
     460{
     461public:
     462    MHGetPortion(): MHActionObjectRef(":GetPortion")  {}
     463    virtual void CallAction(MHEngine *, MHRoot *pTarget, MHRoot *pResult)
     464        { pResult->SetVariableValue(pTarget->GetPortion());}
     465};
     466
     467class MHSetSliderParameters: public MHActionInt3
     468{
     469public:
     470    MHSetSliderParameters(): MHActionInt3(":SetSliderParameters") {}
     471    virtual void CallAction(MHEngine *engine, MHRoot *pTarget, int newMin, int newMax, int newStep)
     472        { pTarget->SetSliderParameters(newMin, newMax, newStep, engine); };
     473};
     474
    314475#endif
  • libs/libmythfreemheg/Engine.h

     
    11/* Engine.h
    22
    3    Copyright (C)  David C. J. Matthews 2004  dm at prolingua.co.uk
     3   Copyright (C)  David C. J. Matthews 2004, 2008  dm at prolingua.co.uk
    44
    55   This program is free software; you can redistribute it and/or
    66   modify it under the terms of the GNU General Public License
     
    6363    MHIngredient *m_pRequester;
    6464};
    6565
     66class MHInteractible;
     67
    6668class MHEngine: public MHEG {
    6769public:
    6870    MHEngine(MHContext *context);
     
    148150
    149151    static const char *MHEGEngineProviderIdString;
    150152
     153    // Interaction: Set if an Interactible has the focus and is receiving key presses.
     154    MHInteractible *GetInteraction(void) { return m_Interacting; }
     155    void SetInteraction(MHInteractible *p) { m_Interacting = p; }
     156
    151157protected:
    152158    void CheckLinks(const MHObjectRef &sourceRef, enum EventType ev, const MHUnion &un);
    153159    MHGroup *ParseProgram(QByteArray &text);
     
    187193
    188194    MHContext       *m_Context; // Pointer to the context providing drawing and other operations
    189195    bool            m_fBooting;
     196
     197    MHInteractible  *m_Interacting; // Set to current interactive object if any.
    190198};
    191199
    192200#endif
  • libs/libmythfreemheg/Bitmap.cpp

     
    11/* Bitmap.cpp
    22
    3    Copyright (C)  David C. J. Matthews 2004  dm at prolingua.co.uk
     3   Copyright (C)  David C. J. Matthews 2004, 2008  dm at prolingua.co.uk
    44
    55   This program is free software; you can redistribute it and/or
    66   modify it under the terms of the GNU General Public License
     
    111111    if (nCHook == 4) { // PNG.
    112112        m_pContent->CreateFromPNG(data, length);
    113113    }
    114     else if (nCHook == 2) { // MPEG I-frame.
     114    // CHook 5 seems to be used by the BBC on Freesat for an MPEG I-frame for the
     115    // background but enabling it here results in it overlaying the video.
     116    // Presumably it is not simply the same as CHook 2.
     117    else if (nCHook == 2 /* ||nCHook == 5 */) { // MPEG I-frame.
    115118        m_pContent->CreateFromMPEG(data, length);
    116119    }
    117120
  • libs/libmythfreemheg/Text.h

     
    9090    void CreateContent(const unsigned char *p, int s, MHEngine *engine);
    9191};
    9292
    93 class MHHyperText : public MHText, public  MHInteractible
     93class MHHyperText : public MHText, public MHInteractible
    9494{
    9595public:
    9696    MHHyperText();
     
    9898    virtual ~MHHyperText();
    9999    virtual void Initialise(MHParseNode *p, MHEngine *engine);
    100100    virtual void PrintMe(FILE *fd, int nTabs) const;
     101
     102    // Implement the actions in the main inheritance line.
     103    virtual void SetInteractionStatus(bool newStatus, MHEngine *engine)
     104    { InteractSetInteractionStatus(newStatus, engine); }
     105    virtual bool GetInteractionStatus(void) { return InteractGetInteractionStatus(); }
     106    virtual void SetHighlightStatus(bool newStatus, MHEngine *engine)
     107    { InteractSetHighlightStatus(newStatus, engine); }
     108    virtual bool GetHighlightStatus(void) { return InteractGetHighlightStatus(); }
     109    virtual void Deactivation(MHEngine *engine) { InteractDeactivation(); }
    101110};
    102111
    103112// Get Text Data - get the data out of a text object.
  • libs/libmythfreemheg/Programs.cpp

     
    490490        }
    491491
    492492        else if (m_Name.Equal("DBG")) { // Debug - optional
    493             MHERROR("Debug ResidentProgram is not implemented");
     493            QString message = "DEBUG: ";
     494            for (int i = 0; i < args.Size(); i++) {
     495                MHUnion un;
     496                un.GetValueFrom(*(args.GetAt(i)), engine);
     497                switch (un.m_Type) {
     498                case MHUnion::U_Int:
     499                    message.append(QString("%1").arg(un.m_nIntVal));
     500                    break;
     501                case MHParameter::P_Bool:
     502                    message.append(un.m_fBoolVal ? "True" : "False");
     503                    break;
     504                case MHParameter::P_String:
     505                    message.append(QString::fromUtf8((const char *)un.m_StrVal.Bytes(), un.m_StrVal.Size()));
     506                    break;
     507                case MHParameter::P_ObjRef:
     508                    message.append(un.m_ObjRefVal.Printable());
     509                    break;
     510                case MHParameter::P_ContentRef:
     511                    message.append(un.m_ContentRefVal.Printable());
     512                    break;
     513                case MHParameter::P_Null:
     514                    break;
     515                }
     516            }
     517            MHLOG(MHLogNotifications, message);
    494518        }
    495519
    496520        else {
  • libs/libmythfreemheg/BaseActions.cpp

     
    11/* BaseActions.cpp
    22
    3    Copyright (C)  David C. J. Matthews 2004  dm at prolingua.co.uk
     3   Copyright (C)  David C. J. Matthews 2004, 2008  dm at prolingua.co.uk
    44
    55   This program is free software; you can redistribute it and/or
    66   modify it under the terms of the GNU General Public License
     
    8787    m_ResultVar2.Initialise(p->GetArgN(2), engine);
    8888}
    8989
     90void MHActionInt3::Initialise(MHParseNode *p, MHEngine *engine)
     91{
     92    MHElemAction::Initialise(p, engine);
     93    m_Argument1.Initialise(p->GetArgN(1), engine);
     94    m_Argument2.Initialise(p->GetArgN(2), engine);
     95    m_Argument3.Initialise(p->GetArgN(3), engine);
     96}
     97
     98void MHActionInt3::PrintArgs(FILE *fd, int /*nTabs*/) const
     99{
     100    m_Argument1.PrintMe(fd, 0);
     101    m_Argument2.PrintMe(fd, 0);
     102    m_Argument3.PrintMe(fd, 0);
     103}
     104
     105void MHActionInt3::Perform(MHEngine *engine)
     106{
     107    CallAction(engine, Target(engine), m_Argument1.GetValue(engine), m_Argument2.GetValue(engine), m_Argument3.GetValue(engine));
     108}
     109
    90110void MHActionInt4::Initialise(MHParseNode *p, MHEngine *engine)
    91111{
    92112    MHElemAction::Initialise(p, engine);
     
    160180{
    161181    CallAction(engine, Target(engine), engine->FindObject(m_ResultVar1), engine->FindObject(m_ResultVar2));
    162182}
     183
     184void MHActionBool::Initialise(MHParseNode *p, MHEngine *engine)
     185{
     186    MHElemAction::Initialise(p, engine);
     187    m_Argument.Initialise(p->GetArgN(1), engine);
     188}
     189
     190
     191void MHActionBool::Perform(MHEngine *engine)
     192{
     193    CallAction(engine, Target(engine), m_Argument.GetValue(engine));
     194}
  • libs/libmythfreemheg/Link.cpp

     
    11/* Link.cpp
    22
    3    Copyright (C)  David C. J. Matthews 2004  dm at prolingua.co.uk
     3   Copyright (C)  David C. J. Matthews 2004, 2008  dm at prolingua.co.uk
    44
    55   This program is free software; you can redistribute it and/or
    66   modify it under the terms of the GNU General Public License
     
    7676    m_LinkEffect.Initialise(pLinkEffect, engine);
    7777}
    7878
    79 static char *rchEventType[] =
     79static const char *rchEventType[] =
    8080{
    8181    "IsAvailable",
    8282    "ContentAvailable",
  • libs/libmythfreemheg/TokenGroup.cpp

     
    5454        for (int i = 0; i < m_ActionSlots.Size(); i++) {
    5555            PrintTabs(fd, nTabs+2); fprintf(fd, "(\n");
    5656            MHActionSequence *pActions = m_ActionSlots.GetAt(i);
    57             if (pActions->Size() == 0) fprintf(fd, "NULL\n");
     57            if (pActions->Size() == 0)
     58                { PrintTabs(fd, nTabs+2); fprintf(fd, "NULL\n"); }
    5859            else pActions->PrintMe(fd, nTabs+2);
    5960            PrintTabs(fd, nTabs+2); fprintf(fd, ")\n");
    6061        }
  • libs/libmythfreemheg/Visible.cpp

     
    345345}
    346346
    347347
    348 MHInteractible::MHInteractible()
     348MHInteractible::MHInteractible(MHVisible *parent): m_parent(parent)
    349349{
    350 
     350    m_fEngineResp = true;
     351    m_fHighlightStatus = false;
     352    m_fInteractionStatus = false;
    351353}
    352354
    353355MHInteractible::~MHInteractible()
     
    355357
    356358}
    357359
    358 void MHInteractible::Initialise(MHParseNode */*p*/, MHEngine */*engine*/)
     360void MHInteractible::Initialise(MHParseNode *p, MHEngine *engine)
    359361{
     362    // Engine Resp - optional
     363    MHParseNode *pEngineResp = p->GetNamedArg(C_ENGINE_RESP);
     364    if (pEngineResp) m_fEngineResp = pEngineResp->GetArgN(0)->GetBoolValue();
     365    // Highlight colour.
     366    MHParseNode *phlCol = p->GetNamedArg(C_HIGHLIGHT_REF_COLOUR);
     367    if (phlCol) m_highlightRefColour.Initialise(phlCol->GetArgN(0), engine);
     368    else engine->GetDefaultHighlightRefColour(m_highlightRefColour);
     369    m_fHighlightStatus = false;
     370    m_fInteractionStatus = false;
    360371}
    361372
    362 void MHInteractible::PrintMe(FILE */*fd*/, int /*nTabs*/) const
     373void MHInteractible::PrintMe(FILE *fd, int nTabs) const
    363374{
     375    if (! m_fEngineResp)  { PrintTabs(fd, nTabs); fprintf(fd, ":EngineResp false\n"); }
     376
     377    if (m_highlightRefColour.IsSet()) {
     378        PrintTabs(fd, nTabs);
     379        fprintf(fd, ":HighlightRefColour ");
     380        m_highlightRefColour.PrintMe(fd, nTabs+1);
     381        fprintf(fd, "\n");
     382    }
    364383}
    365384
    366 MHSlider::MHSlider()
     385void MHInteractible::Interaction(MHEngine *engine)
    367386{
     387    m_fInteractionStatus = true;
     388    engine->SetInteraction(this);
     389    // The MHEG standard says: "generate visual feedback" here
     390    // but it appears that any visual feedback is controlled only
     391    // by the highlight status combined with engine-resp.
     392}
    368393
     394void MHInteractible::InteractSetInteractionStatus(bool newStatus, MHEngine *engine)
     395{
     396    if (newStatus) { // Turning interaction on.
     397        if (engine->GetInteraction() == 0) // No current interactible
     398            Interaction(engine); // virtual function
     399    }
     400    else { // Turning interaction off.
     401        if (m_fInteractionStatus) {
     402            m_fInteractionStatus = false;
     403            engine->SetInteraction(0);
     404            InteractionCompleted(engine); // Interaction is interrupted.
     405            engine->EventTriggered(m_parent, EventInteractionCompleted);
     406        }
     407    }
    369408}
    370409
    371 MHSlider::~MHSlider()
     410void MHInteractible::InteractSetHighlightStatus(bool newStatus, MHEngine *engine)
    372411{
     412    if (newStatus == m_fHighlightStatus) return;
     413    m_fHighlightStatus = newStatus;
     414    // If active redraw to show change of status.
     415    if (m_parent->GetRunningStatus() && m_fEngineResp)
     416        engine->Redraw(m_parent->GetVisibleArea());
     417    // Generate the event for the change of highlight status.
     418    engine->EventTriggered(m_parent, m_fHighlightStatus ? EventHighlightOn: EventHighlightOff);
     419}
    373420
     421MHSlider::MHSlider(): MHInteractible(this)
     422{
     423    m_orientation = SliderLeft;
     424    orig_max_value = -1;
     425    orig_min_value = initial_value = orig_step_size = 1;
     426    initial_portion = 0;
     427    m_style = SliderNormal;
    374428}
    375429
     430MHSlider::~MHSlider()
     431{
     432}
     433
    376434void MHSlider::Initialise(MHParseNode *p, MHEngine *engine)
    377435{
    378436    MHVisible::Initialise(p, engine);
    379437    MHInteractible::Initialise(p, engine);
    380     //
     438    //
     439    MHParseNode *pOrientation = p->GetNamedArg(C_ORIENTATION);
     440    if (pOrientation)
     441        m_orientation = (enum SliderOrientation)pOrientation->GetArgN(0)->GetEnumValue();
     442    // This is not optional.
     443
     444    MHParseNode *pMin = p->GetNamedArg(C_MIN_VALUE);
     445    if (pMin) orig_min_value = pMin->GetArgN(0)->GetIntValue();
     446    else orig_min_value = 1;
     447
     448    MHParseNode *pMax = p->GetNamedArg(C_MAX_VALUE);
     449    if (pMax) orig_max_value = pMax->GetArgN(0)->GetIntValue();
     450    else orig_max_value = orig_min_value-1; // Unset
     451
     452    MHParseNode *pInit = p->GetNamedArg(C_INITIAL_VALUE);
     453    if (pInit) initial_value = pInit->GetArgN(0)->GetIntValue();
     454    else initial_value = orig_min_value; // Default is min_value
     455
     456    MHParseNode *pPortion = p->GetNamedArg(C_INITIAL_PORTION);
     457    if (pPortion) initial_portion = pPortion->GetArgN(0)->GetIntValue();
     458    else initial_portion = orig_min_value-1; // Unset
     459
     460    MHParseNode *pStep = p->GetNamedArg(C_STEP_SIZE);
     461    if (pStep) orig_step_size = pStep->GetArgN(0)->GetIntValue();
     462    else orig_step_size = 1; // Unset
     463
     464    MHParseNode *pStyle = p->GetNamedArg(C_SLIDER_STYLE);
     465    if (pStyle) m_style = (enum SliderStyle)pStyle->GetArgN(0)->GetEnumValue();
     466    else m_style = SliderNormal;
     467
     468    MHParseNode *pslCol = p->GetNamedArg(C_SLIDER_REF_COLOUR);
     469    if (pslCol) m_sliderRefColour.Initialise(pslCol->GetArgN(0), engine);
     470    else engine->GetDefaultSliderRefColour(m_sliderRefColour);
    381471}
    382472
     473static const char *rchOrientation[] =
     474{
     475    "left", // 1
     476    "right",
     477    "up",
     478    "down" // 4
     479};
     480
     481// Look up the Orientation. Returns zero if it doesn't match.  Used in the text parser only.
     482int MHSlider::GetOrientation(const char *str)
     483{
     484    for (int i = 0; i < (int)(sizeof(rchOrientation)/sizeof(rchOrientation[0])); i++) {
     485        if (strcasecmp(str, rchOrientation[i]) == 0) return (i+1); // Numbered from 1
     486    }
     487    return 0;
     488}
     489
     490static const char *rchStyle[] =
     491{
     492    "normal", // 1
     493    "thermometer",
     494    "proportional" // 3
     495};
     496
     497int MHSlider::GetStyle(const char *str)
     498{
     499    for (int i = 0; i < (int)(sizeof(rchStyle)/sizeof(rchStyle[0])); i++) {
     500        if (strcasecmp(str, rchStyle[i]) == 0) return (i+1); // Numbered from 1
     501    }
     502    return 0;
     503}
     504
    383505void MHSlider::PrintMe(FILE *fd, int nTabs) const
    384506{
    385507    PrintTabs(fd, nTabs); fprintf(fd, "{:Slider ");
    386     MHVisible::PrintMe(fd, nTabs);
     508    MHVisible::PrintMe(fd, nTabs+1);
    387509    MHInteractible::PrintMe(fd, nTabs+1);
    388     fprintf(fd, "****TODO\n");
     510
     511    PrintTabs(fd, nTabs); fprintf(fd, ":Orientation %s\n", rchOrientation[m_orientation-1]);
     512
     513    if (initial_value >= orig_min_value) {
     514        PrintTabs(fd, nTabs+1); fprintf(fd, ":InitialValue %d\n", initial_value);
     515    }
     516
     517    if (orig_min_value != 1) {
     518        PrintTabs(fd, nTabs+1); fprintf(fd, ":MinValue %d\n", orig_min_value);
     519    }
     520
     521    if (orig_max_value > orig_min_value) {
     522        PrintTabs(fd, nTabs+1); fprintf(fd, ":MaxValue %d\n", orig_max_value);
     523    }
     524
     525    if (initial_portion >= orig_min_value) {
     526        PrintTabs(fd, nTabs+1); fprintf(fd, ":InitialPortion %d\n", initial_portion);
     527    }
     528
     529    if (orig_step_size != 1) {
     530        PrintTabs(fd, nTabs+1); fprintf(fd, ":StepSize %d\n", orig_step_size);
     531    }
     532
     533    if (m_style != SliderNormal)
     534    {
     535        PrintTabs(fd, nTabs+1);
     536        fprintf(fd, ":SliderStyle %s\n", rchStyle[m_style-1]);
     537    }
     538
     539    if (m_sliderRefColour.IsSet()) {
     540        PrintTabs(fd, nTabs+1);
     541        fprintf(fd, ":SliderRefColour ");
     542        m_sliderRefColour.PrintMe(fd, nTabs+2);
     543        fprintf(fd, "\n");
     544    }
     545
    389546    PrintTabs(fd, nTabs); fprintf(fd, "}\n");
    390547}
    391548
    392 MHEntryField::MHEntryField()
     549// The MHEG standard doesn't define where the internal values are
     550// initialised.  Assume it's during preparation.
     551void MHSlider::Preparation(MHEngine *engine)
    393552{
     553    MHVisible::Preparation(engine);
     554    max_value = orig_max_value;
     555    min_value = orig_min_value;
     556    step_size = orig_step_size;
     557    slider_value = initial_value;
     558    portion = initial_portion;
     559}
    394560
     561void MHSlider::Display(MHEngine *engine)
     562{
     563    MHContext *d = engine->GetContext();
     564    MHRgba colour;
     565    if (m_fHighlightStatus && m_fEngineResp)
     566        colour = GetColour(m_highlightRefColour);
     567    else colour = GetColour(m_sliderRefColour);
     568
     569    int major; // Direction of change.
     570    if (m_orientation == SliderLeft || m_orientation == SliderRight)
     571        major = m_nBoxWidth;
     572    else major = m_nBoxHeight;
     573
     574    if (max_value <= min_value) return; // Avoid divide by zero if error.
     575
     576    if (m_style == SliderNormal)
     577    {
     578        // This is drawn as a 9 pixel wide "thumb" at the position.
     579        major -= 9; // Width of "thumb"
     580        int posn = major * (slider_value-min_value) / (max_value-min_value);
     581        switch (m_orientation)
     582        {
     583        case SliderLeft:
     584            d->DrawRect(m_nPosX + posn, m_nPosY, 9, m_nBoxHeight, colour);
     585            break;
     586        case SliderRight:
     587            d->DrawRect(m_nPosX + m_nBoxWidth - posn - 9, m_nPosY, 9, m_nBoxHeight, colour);
     588            break;
     589        case SliderUp:
     590            d->DrawRect(m_nPosX, m_nPosY + m_nBoxHeight - posn - 9, m_nBoxWidth, 9, colour);
     591            break;
     592        case SliderDown:
     593            d->DrawRect(m_nPosX, m_nPosY + posn, m_nBoxWidth, 9, colour);
     594            break;
     595        }
     596    }
     597    else {
     598        // Thermometer and proportional sliders are drawn as bars.  Thermometers
     599        // run from the start to the position, proportional sliders from the
     600        // position for the "portion".
     601        int start = 0;
     602        int end = major * (slider_value-min_value) / (max_value-min_value);
     603        if (m_style == SliderProp)
     604        {
     605            start = end;
     606            end = major * (slider_value+portion -min_value) / (max_value-min_value);
     607        }
     608        switch (m_orientation)
     609        {
     610        case SliderLeft:
     611            d->DrawRect(m_nPosX + start, m_nPosY, end-start, m_nBoxHeight, colour);
     612            break;
     613        case SliderRight:
     614            d->DrawRect(m_nPosX + m_nBoxWidth - end, m_nPosY, end-start, m_nBoxHeight, colour);
     615            break;
     616        case SliderUp:
     617            d->DrawRect(m_nPosX, m_nPosY + m_nBoxHeight - end, m_nBoxWidth, end-start, colour);
     618            break;
     619        case SliderDown:
     620            d->DrawRect(m_nPosX, m_nPosY + start, m_nBoxWidth, end-start, colour);
     621            break;
     622        }
     623
     624    }
    395625}
    396626
     627void MHSlider::Interaction(MHEngine *engine)
     628{
     629    MHInteractible::Interaction(engine);
     630    // All the interaction is handled by KeyEvent.
     631}
     632
     633// Called when the interaction has been terminated and we need
     634// to restore the state to non-interacting.
     635void MHSlider::InteractionCompleted(MHEngine *engine)
     636{
     637    MHInteractible::InteractionCompleted(engine);
     638    // Redraw with the interaction highlighting turned off
     639    engine->Redraw(GetVisibleArea());
     640}
     641
     642// Called when a key is pressed.  The only keys that have an effect are
     643// the Select and Cancel keys which both terminate the action and the
     644// arrow keys.  The effect of the arrow keys depends on the orientation of
     645// the slider.
     646void MHSlider::KeyEvent(MHEngine *engine, int nCode)
     647{
     648    switch (nCode)
     649    {
     650    case 15: // Select key
     651    case 16: // Cancel key
     652        m_fInteractionStatus = false;
     653        engine->SetInteraction(0);
     654        InteractionCompleted(engine); // Interaction is interrupted.
     655        engine->EventTriggered(this, EventInteractionCompleted);
     656        break;
     657
     658    case 1: // Up
     659        if (m_orientation == SliderUp)
     660            Increment(engine);
     661        else if (m_orientation == SliderDown)
     662            Decrement(engine);
     663        break;
     664
     665    case 2: // Down
     666        if (m_orientation == SliderUp)
     667            Decrement(engine);
     668        else if (m_orientation == SliderDown)
     669            Increment(engine);
     670        break;
     671
     672    case 3: // Left
     673        if (m_orientation == SliderLeft)
     674            Increment(engine);
     675        else if (m_orientation == SliderRight)
     676            Decrement(engine);
     677        break;
     678
     679    case 4: // Right
     680        if (m_orientation == SliderLeft)
     681            Decrement(engine);
     682        else if (m_orientation == SliderRight)
     683            Increment(engine);
     684        break;
     685
     686    }
     687}
     688
     689void MHSlider::Increment(MHEngine *engine)
     690{
     691    if (slider_value+step_size <= max_value)
     692    {
     693        slider_value += step_size;
     694        engine->Redraw(GetVisibleArea());
     695        engine->EventTriggered(this, EventSliderValueChanged);
     696    }
     697}
     698
     699void MHSlider::Decrement(MHEngine *engine)
     700{
     701    if (slider_value-step_size >= min_value)
     702    {
     703        slider_value -= step_size;
     704        engine->Redraw(GetVisibleArea());
     705        engine->EventTriggered(this, EventSliderValueChanged);
     706    }
     707}
     708
     709void MHSlider::Step(int nbSteps, MHEngine *engine)
     710{
     711    step_size = nbSteps;
     712    if (m_fRunning) engine->Redraw(GetVisibleArea());
     713    engine->EventTriggered(this, EventSliderValueChanged);
     714}
     715
     716void MHSlider::SetSliderValue(int newValue, MHEngine *engine)
     717{
     718    slider_value = newValue;
     719    if (m_fRunning) engine->Redraw(GetVisibleArea());
     720    engine->EventTriggered(this, EventSliderValueChanged);
     721}
     722
     723void MHSlider::SetPortion(int newPortion, MHEngine *engine)
     724{
     725    portion = newPortion;
     726    if (m_fRunning) engine->Redraw(GetVisibleArea());
     727    engine->EventTriggered(this, EventSliderValueChanged);
     728}
     729
     730// Additional action defined in UK MHEG.
     731void MHSlider::SetSliderParameters(int newMin, int newMax, int newStep, MHEngine *engine)
     732{
     733    min_value = newMin;
     734    max_value = newMax;
     735    step_size = newStep;
     736    slider_value = newMin;
     737    if (m_fRunning) engine->Redraw(GetVisibleArea());
     738    engine->EventTriggered(this, EventSliderValueChanged);
     739}
     740
     741
     742MHEntryField::MHEntryField(): MHInteractible(this)
     743{
     744
     745}
     746
    397747MHEntryField::~MHEntryField()
    398748{
    399749
  • libs/libmythtv/mhi.h

     
    180180
    181181    uint             m_lastNbiVersion;
    182182    QMemArray<unsigned char> m_nbiData;
     183   
     184    QRect            m_videoRect;
    183185};
    184186
    185187// Object for drawing text.
  • libs/libmythtv/mhi.cpp

     
    3636      m_face_loaded(false), m_currentChannel(-1),
    3737      m_isLive(false),      m_currentCard(0),
    3838      m_audioTag(-1),       m_videoTag(-1),
    39       m_tuningTo(-1),       m_lastNbiVersion(NBI_VERSION_UNSET)
     39      m_tuningTo(-1),       m_lastNbiVersion(NBI_VERSION_UNSET),
     40      m_videoRect(0, 0, StdDisplayWidth, StdDisplayHeight)
    4041{
    4142    m_display.setAutoDelete(true);
    4243    m_dsmccQueue.setAutoDelete(true);
     
    402403{
    403404    m_displayWidth = display.width();
    404405    m_displayHeight = display.height();
     406    m_videoRect = display; // Assume full screen at this stage.
    405407}
    406408
    407409void MHIContext::SetInputRegister(int num)
     
    452454void MHIContext::AddToDisplay(const QImage &image, int x, int y)
    453455{
    454456    MHIImageData *data = new MHIImageData;
    455     data->m_image = image;
     457    // It seems that OSDTypeImage::Load doesn't deal well with images
     458    // located on odd pixel boundaries and the resulting display contains
     459    // transparent lines.  To avoid this we create a new image if either
     460    // the x or y offset would be odd and set the extra pixels to transparent.
     461    QImage img = image;
     462    int xboundary = x & 1;
     463    int yboundary = y & 1;
     464   
     465    if (xboundary || yboundary)
     466    {
     467        int width = img.width(), height = img.height();
     468        if (xboundary)
     469        {
     470            width++;
     471            x--;
     472        }
     473        if (yboundary)
     474        {
     475            height++;
     476            y--;
     477        }
     478        img = QImage(width, height, 32);
     479        img.setAlphaBuffer(true);
     480        QRgb qTransparent = qRgba(0,0,0,0);
     481        if (xboundary)
     482        {
     483            for (int i = 0; i < height; i++)
     484                img.setPixel(0, i, qTransparent);
     485        }
     486
     487        if (yboundary)
     488        {
     489            for (int j = 0; j < width; j++)
     490                img.setPixel(j, 0, qTransparent);
     491        }
     492
     493        for (int i = 0; i < height-yboundary; i++)
     494        {
     495            for (int j = 0; j < width-xboundary; j++)
     496            {
     497                img.setPixel(j+xboundary, i+yboundary, image.pixel(j,i));
     498            }
     499        }
     500    }
     501    data->m_image = img;
    456502    data->m_x = x;
    457503    data->m_y = y;
    458504    QMutexLocker locker(&m_display_lock);
     
    470516{
    471517    // tell the video player to resize the video stream
    472518    if (m_parent->GetNVP())
    473         m_parent->GetNVP()->SetVideoResize(videoRect);
     519    {
     520        QRect vidRect(videoRect.x() * m_displayWidth/StdDisplayWidth,
     521                      videoRect.y() * m_displayHeight/StdDisplayHeight,
     522                      videoRect.width() * m_displayWidth/StdDisplayWidth,
     523                      videoRect.height() * m_displayHeight/StdDisplayHeight);
     524        if (m_videoRect != vidRect)
     525        {
     526            m_parent->GetNVP()->SetVideoResize(vidRect);
     527            m_videoRect = vidRect;
     528        }
     529    }
    474530
    475531    QMutexLocker locker(&m_display_lock);
    476532    QRect displayRect(dispRect.x() * m_displayWidth/StdDisplayWidth,
     
    713769    QRgb qColour = qRgba(colour.red(), colour.green(),
    714770                         colour.blue(), colour.alpha());
    715771
    716     // This is a bit of a mess: we should be able to create a rectangle object.
    717     // Scale the image to the current display size
    718772    int scaledWidth = width * GetWidth() / MHIContext::StdDisplayWidth;
    719773    int scaledHeight = height * GetHeight() / MHIContext::StdDisplayHeight;
    720774    QImage qImage(scaledWidth, scaledHeight, 32);
    721775    qImage.setAlphaBuffer(true);
    722776
    723     // As far as I can tell this is the only way to draw with an
    724     // intermediate transparency.
    725777    for (int i = 0; i < scaledHeight; i++)
    726778    {
    727779        for (int j = 0; j < scaledWidth; j++)
     
    12521304// The UK profile says that MHEG should not contain concave or
    12531305// self-crossing polygons but we can get the former at least as
    12541306// a result of rounding when drawing ellipses.
     1307typedef struct { int yBottom, yTop, xBottom; float slope; } lineSeg;
     1308
    12551309void MHIDLA::DrawPoly(bool isFilled, const QPointArray &points)
    12561310{
    12571311    int nPoints = points.size();
     
    12601314
    12611315    if (isFilled)
    12621316    {
    1263         // Polygon filling is done by sketching the outline of
    1264         // the polygon in a separate bitmap and then raster scanning
    1265         // across this to generate the fill.  There are some special
    1266         // cases that have to be considered when doing this.  Maximum
    1267         // and minimum points have to be removed otherwise they will
    1268         // turn the scan on but not off again.  Horizontal lines are
    1269         // suppressed and their ends handled specially.
    1270         QRect bounds = points.boundingRect();
    1271         int width = bounds.width()+1, height = bounds.height()+1;
    1272         QBitArray boundsMap(width*height);
    1273         boundsMap.fill(0);
    1274         // Draw the boundaries in the bounds map.  This is
    1275         // the Bresenham algorithm if the absolute gradient is
    1276         // greater than 1 but puts only the centre of each line
    1277         // (so there is only one point for each y value) if less.
    1278         QPoint last = points[nPoints-1]; // Last point
    1279         for (int i = 0; i < nPoints; i++)
     1317        QMemArray <lineSeg> lineArray(nPoints);
     1318        int nLines = 0;
     1319        // Initialise the line segment array.  Include all lines
     1320        // apart from horizontal.  Close the polygon by starting
     1321        // with the last point in the array.
     1322        int lastX = points[nPoints-1].x(); // Last point
     1323        int lastY = points[nPoints-1].y();
     1324        int yMin = lastY, yMax = lastY;
     1325        for (int k = 0; k < nPoints; k++)
    12801326        {
    1281             QPoint thisPoint = points[i];
    1282             int x1 = last.x() - bounds.x();
    1283             int y1 = last.y() - bounds.y();
    1284             int x2 = thisPoint.x() - bounds.x();
    1285             int y2 = thisPoint.y() - bounds.y();
    1286             int x, xEnd, y, yEnd;
    1287             if (y2 > y1)
     1327            int thisX = points[k].x();
     1328            int thisY = points[k].y();
     1329            if (lastY != thisY)
    12881330            {
    1289                 x = x1;
    1290                 y = y1;
    1291                 xEnd = x2;
    1292                 yEnd = y2;
    1293             }
    1294             else
    1295             {
    1296                 x = x2;
    1297                 y = y2;
    1298                 xEnd = x1;
    1299                 yEnd = y1;
    1300             }
    1301             int dx = abs(xEnd-x), dy = yEnd-y;
    1302             int xStep = xEnd >= x ? 1 : -1;
    1303             if (abs(y2-y1) > abs(x2-x1))
    1304             {
    1305                 int error = dy/2;
    1306                 y++;
    1307                 for (; y < yEnd; y++) // Exclude endpoints
     1331                if (lastY > thisY)
    13081332                {
    1309                     boundsMap.toggleBit(x+y*width);
    1310                     error += dx;
    1311                     if (error*2 > dy)
    1312                     {
    1313                         error -= dy;
    1314                         x += xStep;
    1315                     }
     1333                    lineArray[nLines].yBottom = thisY;
     1334                    lineArray[nLines].yTop = lastY;
     1335                    lineArray[nLines].xBottom = thisX;
    13161336                }
    1317             }
    1318             else
    1319             {
    1320                 int error = 0;
    1321                 y++;
    1322                 for (; y < yEnd; y++)
     1337                else
    13231338                {
    1324                     boundsMap.toggleBit(x+y*width);
    1325                     error += dx;
    1326                     while (error > dy)
    1327                     {
    1328                         x += xStep;
    1329                         error -= dy;
    1330                     }
     1339                    lineArray[nLines].yBottom = lastY;
     1340                    lineArray[nLines].yTop = thisY;
     1341                    lineArray[nLines].xBottom = lastX;
    13311342                }
     1343                lineArray[nLines++].slope =
     1344                    (float)(thisX-lastX) / (float)(thisY-lastY);
    13321345            }
    1333             QPoint nextPoint = points[(i+1) % nPoints];
    1334             int nextY = nextPoint.y() - bounds.y();
    1335             int turn = (y2 - y1) * (nextY - y2);
    1336             if (turn > 0) // Not a max or min
    1337                 boundsMap.toggleBit(x2+y2*width);
    1338             else if (turn == 0) // Previous or next line is horizontal
    1339             {
    1340                 // We only draw a point at the beginning or end of a horizontal
    1341                 // line if it turns clockwise.  This means that the fill
    1342                 // will be different depending on the direction the polygon was
    1343                 // drawn but that will be tidied up when we draw the lines round.
    1344                 if (y1 == y2)
    1345                 {
    1346                     if ((x2-x1) * (nextY - y2) > 0)
    1347                        boundsMap.toggleBit(x2+y2*width);
    1348                 }
    1349                 else if ((nextPoint.x() - bounds.x() - x2) * (y2 - y1) < 0)
    1350                     // Next line is horizontal -  draw point if turn is clockwise.
    1351                     boundsMap.toggleBit(x2+y2*width);
    1352             }
    1353             last = thisPoint;
     1346            if (thisY < yMin)
     1347                yMin = thisY;
     1348            if (thisY > yMax)
     1349                yMax = thisY;
     1350            lastX = thisX;
     1351            lastY = thisY;
    13541352        }
     1353       
     1354        // Find the intersections of each line in the line segment array
     1355        // with the scan line.  Because UK MHEG says that figures should be
     1356        // convex we only need to consider two intersections.
    13551357        QRgb fillColour = qRgba(m_fillColour.red(), m_fillColour.green(),
    13561358                                m_fillColour.blue(), m_fillColour.alpha());
    1357         // Now scan the bounds map and use this to fill the polygon.
    1358         for (int j = 0; j < bounds.height(); j++)
     1359        for (int y = yMin; y < yMax; y++)
    13591360        {
    1360             bool penDown = false;
    1361             for (int k = 0; k < bounds.width(); k++)
     1361            int crossings = 0, xMin = 0, xMax = 0;
     1362            for (int l = 0; l < nLines; l++)
    13621363            {
    1363                 if (boundsMap.testBit(k+j*width))
    1364                     penDown = ! penDown;
    1365                 else if (penDown && k+bounds.x() >= 0 && j+bounds.y() >= 0 &&
    1366                          k+bounds.x() < m_width && j+bounds.y() < m_height)
    1367                     m_image.setPixel(k+bounds.x(), j+bounds.y(), fillColour);
     1364                if (y >= lineArray[l].yBottom && y < lineArray[l].yTop)
     1365                {
     1366                    int x = (int)round((float)(y - lineArray[l].yBottom) *
     1367                        lineArray[l].slope) + lineArray[l].xBottom;
     1368                    if (crossings == 0 || x < xMin)
     1369                        xMin = x;
     1370                    if (crossings == 0 || x > xMax)
     1371                        xMax = x;
     1372                    crossings++;
     1373                }
    13681374            }
     1375            if (crossings == 2)
     1376            {
     1377                for (int x = xMin; x <= xMax; x++)
     1378                    m_image.setPixel(x, y, fillColour);
     1379            }
    13691380        }
    13701381
    13711382        // Draw the boundary
    1372         last = points[nPoints-1]; // Last point
     1383        QPoint last = points[nPoints-1]; // Last point
    13731384        for (int i = 0; i < nPoints; i++)
    13741385        {
    13751386            DrawLine(points[i].x(), points[i].y(), last.x(), last.y());
     
    13941405            return;
    13951406        // Construct an image the size of the bounding box and tile the
    13961407        // bitmap over this.
    1397         QImage tiledImage = QImage(rect.width(), rect.height(),
    1398                                    m_image.depth());
     1408        QImage tiledImage = QImage(rect.width(), rect.height(), 32);
    13991409
    14001410        for (int i = 0; i < rect.width(); i += m_image.width())
    14011411        {
     
    15361546
    15371547    m_image = m_image.smoothScale(newWidth, newHeight);
    15381548}
     1549
     1550