Ticket #5606: mhegupdate.patch
File mhegupdate.patch, 55.7 KB (added by , 17 years ago) |
---|
-
libs/libmythtv/mhi.h
182 182 183 183 uint m_lastNbiVersion; 184 184 Q3MemArray<unsigned char> m_nbiData; 185 186 QRect m_videoRect; 185 187 }; 186 188 187 189 // Object for drawing text. -
libs/libmythtv/mhi.cpp
37 37 m_face_loaded(false), m_currentChannel(-1), 38 38 m_isLive(false), m_currentCard(0), 39 39 m_audioTag(-1), m_videoTag(-1), 40 m_tuningTo(-1), m_lastNbiVersion(NBI_VERSION_UNSET) 40 m_tuningTo(-1), m_lastNbiVersion(NBI_VERSION_UNSET), 41 m_videoRect(0, 0, StdDisplayWidth, StdDisplayHeight) 41 42 { 42 43 m_display.setAutoDelete(true); 43 44 m_dsmccQueue.setAutoDelete(true); … … 418 419 { 419 420 m_displayWidth = display.width(); 420 421 m_displayHeight = display.height(); 422 m_videoRect = display; // Assume full screen at this stage. 421 423 } 422 424 423 425 void MHIContext::SetInputRegister(int num) … … 468 470 void MHIContext::AddToDisplay(const QImage &image, int x, int y) 469 471 { 470 472 MHIImageData *data = new MHIImageData; 471 data->m_image = image; 473 // It seems that OSDTypeImage::Load doesn't deal well with images 474 // located on odd pixel boundaries and the resulting display contains 475 // transparent lines. To avoid this we create a new image if either 476 // the x or y offset would be odd and set the extra pixels to transparent. 477 QImage img = image; 478 int xboundary = x & 1; 479 int yboundary = y & 1; 480 481 if (xboundary || yboundary) 482 { 483 int width = img.width(), height = img.height(); 484 if (xboundary) 485 { 486 width++; 487 x--; 488 } 489 if (yboundary) 490 { 491 height++; 492 y--; 493 } 494 img = QImage(width, height, QImage::Format_ARGB32); 495 QRgb qTransparent = qRgba(0,0,0,0); 496 if (xboundary) 497 { 498 for (int i = 0; i < height; i++) 499 img.setPixel(0, i, qTransparent); 500 } 501 502 if (yboundary) 503 { 504 for (int j = 0; j < width; j++) 505 img.setPixel(j, 0, qTransparent); 506 } 507 508 for (int i = 0; i < height-yboundary; i++) 509 { 510 for (int j = 0; j < width-xboundary; j++) 511 { 512 img.setPixel(j+xboundary, i+yboundary, image.pixel(j,i)); 513 } 514 } 515 } 516 data->m_image = img; 472 517 data->m_x = x; 473 518 data->m_y = y; 474 519 QMutexLocker locker(&m_display_lock); … … 486 531 { 487 532 // tell the video player to resize the video stream 488 533 if (m_parent->GetNVP()) 489 m_parent->GetNVP()->SetVideoResize(videoRect); 534 { 535 QRect vidRect(videoRect.x() * m_displayWidth/StdDisplayWidth, 536 videoRect.y() * m_displayHeight/StdDisplayHeight, 537 videoRect.width() * m_displayWidth/StdDisplayWidth, 538 videoRect.height() * m_displayHeight/StdDisplayHeight); 539 if (m_videoRect != vidRect) 540 { 541 m_parent->GetNVP()->SetVideoResize(vidRect); 542 m_videoRect = vidRect; 543 } 544 } 490 545 491 546 QMutexLocker locker(&m_display_lock); 492 547 QRect displayRect(dispRect.x() * m_displayWidth/StdDisplayWidth, … … 729 784 QRgb qColour = qRgba(colour.red(), colour.green(), 730 785 colour.blue(), colour.alpha()); 731 786 732 // This is a bit of a mess: we should be able to create a rectangle object.733 // Scale the image to the current display size734 787 int scaledWidth = width * GetWidth() / MHIContext::StdDisplayWidth; 735 788 int scaledHeight = height * GetHeight() / MHIContext::StdDisplayHeight; 736 QImage qImage(scaledWidth, scaledHeight, 32); 737 qImage.setAlphaBuffer(true); 789 QImage qImage(scaledWidth, scaledHeight, QImage::Format_ARGB32); 738 790 739 // As far as I can tell this is the only way to draw with an740 // intermediate transparency.741 791 for (int i = 0; i < scaledHeight; i++) 742 792 { 743 793 for (int j = 0; j < scaledWidth; j++) … … 921 971 // different layers. The background is drawn separately as a rectangle. 922 972 void MHIText::Clear(void) 923 973 { 924 m_image = QImage(m_width, m_height, 32); 925 // 926 m_image.setAlphaBuffer(true); 974 m_image = QImage(m_width, m_height, QImage::Format_ARGB32); 927 975 // QImage::fill doesn't set the alpha buffer. 928 976 for (int i = 0; i < m_height; i++) 929 977 { … … 1062 1110 m_image = QImage(); 1063 1111 return; 1064 1112 } 1065 m_image = QImage(m_width, m_height, 32);1113 m_image = QImage(m_width, m_height, QImage::Format_ARGB32); 1066 1114 // Fill the image with "transparent colour". 1067 1115 DrawRect(0, 0, m_width, m_height, MHRgba(0, 0, 0, 0)); 1068 1116 } … … 1274 1322 // The UK profile says that MHEG should not contain concave or 1275 1323 // self-crossing polygons but we can get the former at least as 1276 1324 // a result of rounding when drawing ellipses. 1325 typedef struct { int yBottom, yTop, xBottom; float slope; } lineSeg; 1326 1277 1327 void MHIDLA::DrawPoly(bool isFilled, const Q3PointArray &points) 1278 1328 { 1279 1329 int nPoints = points.size(); … … 1282 1332 1283 1333 if (isFilled) 1284 1334 { 1285 // Polygon filling is done by sketching the outline of 1286 // the polygon in a separate bitmap and then raster scanning 1287 // across this to generate the fill. There are some special 1288 // cases that have to be considered when doing this. Maximum 1289 // and minimum points have to be removed otherwise they will 1290 // turn the scan on but not off again. Horizontal lines are 1291 // suppressed and their ends handled specially. 1292 QRect bounds = points.boundingRect(); 1293 int width = bounds.width()+1, height = bounds.height()+1; 1294 QBitArray boundsMap(width*height); 1295 boundsMap.fill(0); 1296 // Draw the boundaries in the bounds map. This is 1297 // the Bresenham algorithm if the absolute gradient is 1298 // greater than 1 but puts only the centre of each line 1299 // (so there is only one point for each y value) if less. 1300 QPoint last = points[nPoints-1]; // Last point 1301 for (int i = 0; i < nPoints; i++) 1335 Q3MemArray <lineSeg> lineArray(nPoints); 1336 int nLines = 0; 1337 // Initialise the line segment array. Include all lines 1338 // apart from horizontal. Close the polygon by starting 1339 // with the last point in the array. 1340 int lastX = points[nPoints-1].x(); // Last point 1341 int lastY = points[nPoints-1].y(); 1342 int yMin = lastY, yMax = lastY; 1343 for (int k = 0; k < nPoints; k++) 1302 1344 { 1303 QPoint thisPoint = points[i]; 1304 int x1 = last.x() - bounds.x(); 1305 int y1 = last.y() - bounds.y(); 1306 int x2 = thisPoint.x() - bounds.x(); 1307 int y2 = thisPoint.y() - bounds.y(); 1308 int x, xEnd, y, yEnd; 1309 if (y2 > y1) 1345 int thisX = points[k].x(); 1346 int thisY = points[k].y(); 1347 if (lastY != thisY) 1310 1348 { 1311 x = x1; 1312 y = y1; 1313 xEnd = x2; 1314 yEnd = y2; 1315 } 1316 else 1317 { 1318 x = x2; 1319 y = y2; 1320 xEnd = x1; 1321 yEnd = y1; 1322 } 1323 int dx = abs(xEnd-x), dy = yEnd-y; 1324 int xStep = xEnd >= x ? 1 : -1; 1325 if (abs(y2-y1) > abs(x2-x1)) 1326 { 1327 int error = dy/2; 1328 y++; 1329 for (; y < yEnd; y++) // Exclude endpoints 1349 if (lastY > thisY) 1330 1350 { 1331 boundsMap.toggleBit(x+y*width); 1332 error += dx; 1333 if (error*2 > dy) 1334 { 1335 error -= dy; 1336 x += xStep; 1337 } 1351 lineArray[nLines].yBottom = thisY; 1352 lineArray[nLines].yTop = lastY; 1353 lineArray[nLines].xBottom = thisX; 1338 1354 } 1339 } 1340 else 1341 { 1342 int error = 0; 1343 y++; 1344 for (; y < yEnd; y++) 1355 else 1345 1356 { 1346 boundsMap.toggleBit(x+y*width); 1347 error += dx; 1348 while (error > dy) 1349 { 1350 x += xStep; 1351 error -= dy; 1352 } 1357 lineArray[nLines].yBottom = lastY; 1358 lineArray[nLines].yTop = thisY; 1359 lineArray[nLines].xBottom = lastX; 1353 1360 } 1361 lineArray[nLines++].slope = 1362 (float)(thisX-lastX) / (float)(thisY-lastY); 1354 1363 } 1355 QPoint nextPoint = points[(i+1) % nPoints]; 1356 int nextY = nextPoint.y() - bounds.y(); 1357 int turn = (y2 - y1) * (nextY - y2); 1358 if (turn > 0) // Not a max or min 1359 boundsMap.toggleBit(x2+y2*width); 1360 else if (turn == 0) // Previous or next line is horizontal 1361 { 1362 // We only draw a point at the beginning or end of a horizontal 1363 // line if it turns clockwise. This means that the fill 1364 // will be different depending on the direction the polygon was 1365 // drawn but that will be tidied up when we draw the lines round. 1366 if (y1 == y2) 1367 { 1368 if ((x2-x1) * (nextY - y2) > 0) 1369 boundsMap.toggleBit(x2+y2*width); 1370 } 1371 else if ((nextPoint.x() - bounds.x() - x2) * (y2 - y1) < 0) 1372 // Next line is horizontal - draw point if turn is clockwise. 1373 boundsMap.toggleBit(x2+y2*width); 1374 } 1375 last = thisPoint; 1364 if (thisY < yMin) 1365 yMin = thisY; 1366 if (thisY > yMax) 1367 yMax = thisY; 1368 lastX = thisX; 1369 lastY = thisY; 1376 1370 } 1371 1372 // Find the intersections of each line in the line segment array 1373 // with the scan line. Because UK MHEG says that figures should be 1374 // convex we only need to consider two intersections. 1377 1375 QRgb fillColour = qRgba(m_fillColour.red(), m_fillColour.green(), 1378 1376 m_fillColour.blue(), m_fillColour.alpha()); 1379 // Now scan the bounds map and use this to fill the polygon. 1380 for (int j = 0; j < bounds.height(); j++) 1377 for (int y = yMin; y < yMax; y++) 1381 1378 { 1382 bool penDown = false;1383 for (int k = 0; k < bounds.width(); k++)1379 int crossings = 0, xMin = 0, xMax = 0; 1380 for (int l = 0; l < nLines; l++) 1384 1381 { 1385 if (boundsMap.testBit(k+j*width)) 1386 penDown = ! penDown; 1387 else if (penDown && k+bounds.x() >= 0 && j+bounds.y() >= 0 && 1388 k+bounds.x() < m_width && j+bounds.y() < m_height) 1389 m_image.setPixel(k+bounds.x(), j+bounds.y(), fillColour); 1382 if (y >= lineArray[l].yBottom && y < lineArray[l].yTop) 1383 { 1384 int x = (int)round((float)(y - lineArray[l].yBottom) * 1385 lineArray[l].slope) + lineArray[l].xBottom; 1386 if (crossings == 0 || x < xMin) 1387 xMin = x; 1388 if (crossings == 0 || x > xMax) 1389 xMax = x; 1390 crossings++; 1391 } 1390 1392 } 1393 if (crossings == 2) 1394 { 1395 for (int x = xMin; x <= xMax; x++) 1396 m_image.setPixel(x, y, fillColour); 1397 } 1391 1398 } 1392 1399 1393 1400 // Draw the boundary 1394 last = points[nPoints-1]; // Last point1401 QPoint last = points[nPoints-1]; // Last point 1395 1402 for (int i = 0; i < nPoints; i++) 1396 1403 { 1397 1404 DrawLine(points[i].x(), points[i].y(), last.x(), last.y()); … … 1502 1509 { 1503 1510 int nContentWidth = c->width; 1504 1511 int nContentHeight = c->height; 1505 m_image = QImage(nContentWidth, nContentHeight, 32);1512 m_image = QImage(nContentWidth, nContentHeight, QImage::Format_ARGB32); 1506 1513 m_opaque = true; // MPEG images are always opaque. 1507 1514 1508 1515 AVPicture retbuf; … … 1559 1566 m_image = m_image.scaled(newWidth, newHeight, 1560 1567 Qt::IgnoreAspectRatio, Qt::SmoothTransformation); 1561 1568 } 1569 1570 -
libs/libmythfreemheg/Actions.cpp
1 1 /* Actions.cpp 2 2 3 Copyright (C) David C. J. Matthews 2004 dm at prolingua.co.uk3 Copyright (C) David C. J. Matthews 2004, 2008 dm at prolingua.co.uk 4 4 5 5 This program is free software; you can redistribute it and/or 6 6 modify it under the terms of the GNU General Public License … … 93 93 case C_GET_ENTRY_POINT: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // EntryField 94 94 case C_GET_FILL_COLOUR: pAction = new MHGetFillColour; break; 95 95 case C_GET_FIRST_ITEM: pAction = new MHGetFirstItem; break; 96 case C_GET_HIGHLIGHT_STATUS: pAction = new MH UnimplementedAction(pElemAction->GetTagNo()); break;// ?97 case C_GET_INTERACTION_STATUS: pAction = new MH UnimplementedAction(pElemAction->GetTagNo()); break;// ?96 case C_GET_HIGHLIGHT_STATUS: pAction = new MHGetHighlightStatus; break; 97 case C_GET_INTERACTION_STATUS: pAction = new MHGetInteractionStatus; break; 98 98 case C_GET_ITEM_STATUS: pAction = new MHGetItemStatus; break; 99 99 case C_GET_LABEL: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break;// PushButton 100 100 case C_GET_LAST_ANCHOR_FIRED: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break;// HyperText … … 104 104 case C_GET_LIST_ITEM: pAction = new MHGetListItem; break; 105 105 case C_GET_LIST_SIZE: pAction = new MHGetListSize; break; 106 106 case C_GET_OVERWRITE_MODE: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break;// ? 107 case C_GET_PORTION: pAction = new MH UnimplementedAction(pElemAction->GetTagNo()); break;// Slider107 case C_GET_PORTION: pAction = new MHGetPortion; break; 108 108 case C_GET_POSITION: pAction = new MHGetPosition; break; 109 109 case C_GET_RUNNING_STATUS: pAction = new MHGetRunningStatus; break; 110 110 case C_GET_SELECTION_STATUS: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break;// ? 111 case C_GET_SLIDER_VALUE: pAction = new MH UnimplementedAction(pElemAction->GetTagNo()); break;// Slider111 case C_GET_SLIDER_VALUE: pAction = new MHGetSliderValue; break; 112 112 case C_GET_TEXT_CONTENT: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break;// Text 113 113 case C_GET_TEXT_DATA: pAction = new MHGetTextData; break; 114 114 case C_GET_TOKEN_POSITION: pAction = new MHGetTokenPosition; break; … … 145 145 case C_SET_FILL_COLOUR: pAction = new MHSetFillColour; break; 146 146 case C_SET_FIRST_ITEM: pAction = new MHSetFirstItem; break; 147 147 case C_SET_FONT_REF: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // Text 148 case C_SET_HIGHLIGHT_STATUS: pAction = new MH UnimplementedAction(pElemAction->GetTagNo()); break; // ?149 case C_SET_INTERACTION_STATUS: pAction = new MH UnimplementedAction(pElemAction->GetTagNo()); break; // ?148 case C_SET_HIGHLIGHT_STATUS: pAction = new MHSetHighlightStatus; break; 149 case C_SET_INTERACTION_STATUS: pAction = new MHSetInteractionStatus; break; 150 150 case C_SET_LABEL: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // PushButton 151 151 case C_SET_LINE_COLOUR: pAction = new MHSetLineColour; break; 152 152 case C_SET_LINE_STYLE: pAction = new MHSetLineStyle; break; 153 153 case C_SET_LINE_WIDTH: pAction = new MHSetLineWidth; break; 154 154 case C_SET_OVERWRITE_MODE: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // EntryField 155 155 case C_SET_PALETTE_REF: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // Visible 156 case C_SET_PORTION: pAction = new MH UnimplementedAction(pElemAction->GetTagNo()); break; // Slider156 case C_SET_PORTION: pAction = new MHSetPortion; break; 157 157 case C_SET_POSITION: pAction = new MHSetPosition; break; 158 case C_SET_SLIDER_VALUE: pAction = new MH UnimplementedAction(pElemAction->GetTagNo()); break; // Slider158 case C_SET_SLIDER_VALUE: pAction = new MHSetSliderValue; break; 159 159 case C_SET_SPEED: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // ? 160 160 case C_SET_TIMER: pAction = new MHSetTimer; break; 161 161 case C_SET_TRANSPARENCY: pAction = new MHSetTransparency; break; 162 162 case C_SET_VARIABLE: pAction = new MHSetVariable; break; 163 163 case C_SET_VOLUME: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // ? 164 164 case C_SPAWN: pAction = new MHSpawn; break; 165 case C_STEP: pAction = new MH UnimplementedAction(pElemAction->GetTagNo()); break; // Slider165 case C_STEP: pAction = new MHStep; break; 166 166 case C_STOP: pAction = new MHStop; break; 167 167 case C_STORE_PERSISTENT: pAction = new MHPersistent(":StorePersistent", false); break; 168 168 case C_SUBTRACT: pAction = new MHSubtract; break; … … 184 184 case C_SET_FOCUS_POSITION: pAction = new MHUnimplementedAction(pElemAction->GetTagNo()); break; // HyperText 185 185 case C_SET_BITMAP_DECODE_OFFSET: pAction = new MHSetBitmapDecodeOffset; break; 186 186 case C_GET_BITMAP_DECODE_OFFSET: pAction = new MHGetBitmapDecodeOffset; break; 187 case C_SET_SLIDER_PARAMETERS: pAction = new MH UnimplementedAction(pElemAction->GetTagNo()); break; // ?187 case C_SET_SLIDER_PARAMETERS: pAction = new MHSetSliderParameters; break; 188 188 189 189 default: 190 190 MHLOG(MHLogWarning, QString("Unknown action %1").arg(pElemAction->GetTagNo())); -
libs/libmythfreemheg/Engine.cpp
1 1 /* Engine.cpp 2 2 3 Copyright (C) David C. J. Matthews 2004 dm at prolingua.co.uk3 Copyright (C) David C. J. Matthews 2004, 2008 dm at prolingua.co.uk 4 4 5 5 This program is free software; you can redistribute it and/or 6 6 modify it under the terms of the GNU General Public License … … 31 31 #include "ASN1Codes.h" 32 32 #include "Logging.h" 33 33 #include "freemheg.h" 34 #include "Visible.h" // For MHInteractible 34 35 35 36 #include <stdio.h> 36 37 #include <stdlib.h> … … 46 47 { 47 48 m_fInTransition = false; 48 49 m_fBooting = true; 50 m_Interacting = 0; 49 51 } 50 52 51 53 MHEngine::~MHEngine() … … 323 325 pApp->m_pCurrentScene = NULL; 324 326 } 325 327 328 m_Interacting = 0; 326 329 327 330 // Switch to the new scene. 328 331 CurrentApp()->m_pCurrentScene = (MHScene*) pProgram; … … 620 623 { 621 624 MHScene *pScene = CurrentScene(); 622 625 if (! pScene) return; 623 EventTriggered(pScene, EventUserInput, nCode); 626 // Various keys generate engine events as well as user events. 627 // These are generated before the user events and even if there 628 // is an interactible. 629 switch (nCode) 630 { 631 case 104: 632 case 105: // Text key 633 EventTriggered(pScene, EventEngineEvent, 4); 634 break; 635 case 16: // Text Exit/Cancel key 636 case 100: // Red 637 case 101: // Green 638 case 102: // Yellow 639 case 103: // Blue 640 EventTriggered(pScene, EventEngineEvent, nCode); 641 break; 642 } 643 644 // If we are interacting with an interactible send the key 645 // there otherwise generate a user event. 646 if (m_Interacting) 647 m_Interacting->KeyEvent(this, nCode); 648 else EventTriggered(pScene, EventUserInput, nCode); 624 649 } 625 650 626 651 // Called by an ingredient wanting external content. -
libs/libmythfreemheg/ParseText.cpp
1 1 /* ParseText.cpp 2 2 3 Copyright (C) David C. J. Matthews 2004 dm at prolingua.co.uk3 Copyright (C) David C. J. Matthews 2004, 2008 dm at prolingua.co.uk 4 4 5 5 This program is free software; you can redistribute it and/or 6 6 modify it under the terms of the GNU General Public License … … 536 536 if (m_nInt > 0) return; 537 537 m_nInt = MHText::GetStartCorner(buff); 538 538 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; 539 543 540 544 // Check the colour table. If it's there generate a string containing the colour info. 541 545 for (int i = 0; i < (int)(sizeof(colourTable)/sizeof(colourTable[0])); i++) { -
libs/libmythfreemheg/Text.cpp
1 1 /* Text.cpp 2 2 3 Copyright (C) David C. J. Matthews 2004 dm at prolingua.co.uk3 Copyright (C) David C. J. Matthews 2004, 2008 dm at prolingua.co.uk 4 4 5 5 This program is free software; you can redistribute it and/or 6 6 modify it under the terms of the GNU General Public License … … 465 465 pNewLine->m_Items.Append(pNewItem); 466 466 pNewItem->m_Unicode = pItem->m_Unicode.mid(nNewStart, nNewWidth); 467 467 pNewItem->m_nUnicode = nNewWidth; 468 // Move any remaining items, e.g. in a different colour, from this line onto the new line. 469 while (pLine->m_Items.Size() > j+1) { 470 pNewLine->m_Items.Append(pLine->m_Items.GetAt(j+1)); 471 pLine->m_Items.RemoveAt(j+1); 472 } 468 473 } 469 474 // Remove any spaces at the end of the old section. If we don't do that and 470 475 // we are centering or right aligning the text we'll get it wrong. … … 536 541 } 537 542 538 543 539 MHHyperText::MHHyperText() 544 MHHyperText::MHHyperText(): MHInteractible(this) 540 545 { 541 546 542 547 } -
libs/libmythfreemheg/Root.h
176 176 virtual void SetVideoDecodeOffset(int /*newXOffset*/, int /*newYOffset*/, MHEngine *) { InvalidAction("SetVideoDecodeOffset"); } 177 177 virtual void GetVideoDecodeOffset(MHRoot * /*pXOffset*/, MHRoot */*pYOffset*/, MHEngine *) { InvalidAction("GetVideoDecodeOffset"); } 178 178 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 179 195 protected: 180 196 181 197 void InvalidAction(const char *actionName); -
libs/libmythfreemheg/BaseActions.h
1 1 /* BaseActions.h 2 2 3 Copyright (C) David C. J. Matthews 2004 dm at prolingua.co.uk3 Copyright (C) David C. J. Matthews 2004, 2008 dm at prolingua.co.uk 4 4 5 5 This program is free software; you can redistribute it and/or 6 6 modify it under the terms of the GNU General Public License … … 73 73 MHGenericInteger m_Argument1, m_Argument2; 74 74 }; 75 75 76 // Base class for actions with three integers. Used for SetSliderParameters 77 class MHActionInt3: public MHElemAction 78 { 79 public: 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; 85 protected: 86 MHGenericInteger m_Argument1, m_Argument2, m_Argument3; 87 }; 88 76 89 // Base class for actions with four integers. Used in the DynamicLineArt class 77 90 class MHActionInt4: public MHElemAction 78 91 { … … 139 152 }; 140 153 141 154 155 // Base class for actions with a single boolean argument. 156 class MHActionBool: public MHElemAction 157 { 158 public: 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; 164 protected: 165 MHGenericBoolean m_Argument; 166 }; 167 142 168 #endif -
libs/libmythfreemheg/Visible.h
1 1 /* Visible.h 2 2 3 Copyright (C) David C. J. Matthews 2004 dm at prolingua.co.uk3 Copyright (C) David C. J. Matthews 2004, 2008 dm at prolingua.co.uk 4 4 5 5 This program is free software; you can redistribute it and/or 6 6 modify it under the terms of the GNU General Public License … … 124 124 virtual MHIngredient *Clone(MHEngine *) { return new MHRectangle(*this); } // Create a clone of this ingredient. 125 125 }; 126 126 127 // The Interactible class is described as a "mix-in" class. It is used 128 // in various classes which complicates inheritance. 127 129 class MHInteractible 128 130 { 129 131 public: 130 MHInteractible( );132 MHInteractible(MHVisible *parent); 131 133 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 152 protected: 153 // Exchanged attributes 154 bool m_fEngineResp; 155 MHColour m_highlightRefColour; 156 // Internal attributes 157 bool m_fHighlightStatus; 158 bool m_fInteractionStatus; 159 160 private: 161 MHVisible *m_parent; 134 162 }; 135 163 136 164 class MHSlider : public MHVisible, public MHInteractible … … 141 169 virtual const char *ClassName() { return "Slider"; } 142 170 virtual void Initialise(MHParseNode *p, MHEngine *engine); 143 171 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); 200 protected: 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; 145 220 }; 146 221 147 222 class MHEntryField : public MHVisible, public MHInteractible … … 153 228 virtual void Initialise(MHParseNode *p, MHEngine *engine); 154 229 virtual void PrintMe(FILE *fd, int nTabs) const; 155 230 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(); } 156 240 }; 157 241 158 242 // Button - not needed for UK MHEG. … … 311 395 virtual void CallAction(MHEngine *engine, MHRoot *pTarget, int nArg) { pTarget->SetLineStyle(nArg, engine); }; 312 396 }; 313 397 398 class MHSetInteractionStatus: public MHActionBool 399 { 400 public: 401 MHSetInteractionStatus(): MHActionBool("SetInteractionStatus") {} 402 virtual void CallAction(MHEngine *engine, MHRoot *pTarget, bool newStatus) 403 { Target(engine)->SetInteractionStatus(newStatus, engine); } 404 }; 405 406 class MHGetInteractionStatus: public MHActionObjectRef 407 { 408 public: 409 MHGetInteractionStatus(): MHActionObjectRef(":GetInteractionStatus") {} 410 virtual void CallAction(MHEngine *, MHRoot *pTarget, MHRoot *pResult) 411 { pResult->SetVariableValue(pTarget->GetInteractionStatus());} 412 }; 413 414 class MHSetHighlightStatus: public MHActionBool 415 { 416 public: 417 MHSetHighlightStatus(): MHActionBool("SetHighlightStatus") {} 418 virtual void CallAction(MHEngine *engine, MHRoot *pTarget, bool newStatus) 419 { Target(engine)->SetHighlightStatus(newStatus, engine); } 420 }; 421 422 class MHGetHighlightStatus: public MHActionObjectRef 423 { 424 public: 425 MHGetHighlightStatus(): MHActionObjectRef(":GetHighlightStatus") {} 426 virtual void CallAction(MHEngine *, MHRoot *pTarget, MHRoot *pResult) 427 { pResult->SetVariableValue(pTarget->GetHighlightStatus());} 428 }; 429 430 class MHStep: public MHActionInt 431 { 432 public: 433 MHStep(): MHActionInt(":Step") {} 434 virtual void CallAction(MHEngine *engine, MHRoot *pTarget, int nArg) { pTarget->Step(nArg, engine); }; 435 }; 436 437 class MHSetSliderValue: public MHActionInt 438 { 439 public: 440 MHSetSliderValue(): MHActionInt(":SetSliderValue") {} 441 virtual void CallAction(MHEngine *engine, MHRoot *pTarget, int nArg) { pTarget->SetSliderValue(nArg, engine); }; 442 }; 443 444 class MHGetSliderValue: public MHActionObjectRef 445 { 446 public: 447 MHGetSliderValue(): MHActionObjectRef(":GetSliderValue") {} 448 virtual void CallAction(MHEngine *, MHRoot *pTarget, MHRoot *pResult) 449 { pResult->SetVariableValue(pTarget->GetSliderValue());} 450 }; 451 452 class MHSetPortion: public MHActionInt 453 { 454 public: 455 MHSetPortion(): MHActionInt(":SetPortion") {} 456 virtual void CallAction(MHEngine *engine, MHRoot *pTarget, int nArg) { pTarget->SetPortion(nArg, engine); }; 457 }; 458 459 class MHGetPortion: public MHActionObjectRef 460 { 461 public: 462 MHGetPortion(): MHActionObjectRef(":GetPortion") {} 463 virtual void CallAction(MHEngine *, MHRoot *pTarget, MHRoot *pResult) 464 { pResult->SetVariableValue(pTarget->GetPortion());} 465 }; 466 467 class MHSetSliderParameters: public MHActionInt3 468 { 469 public: 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 314 475 #endif -
libs/libmythfreemheg/Engine.h
1 1 /* Engine.h 2 2 3 Copyright (C) David C. J. Matthews 2004 dm at prolingua.co.uk3 Copyright (C) David C. J. Matthews 2004, 2008 dm at prolingua.co.uk 4 4 5 5 This program is free software; you can redistribute it and/or 6 6 modify it under the terms of the GNU General Public License … … 64 64 MHIngredient *m_pRequester; 65 65 }; 66 66 67 class MHInteractible; 68 67 69 class MHEngine: public MHEG { 68 70 public: 69 71 MHEngine(MHContext *context); … … 149 151 150 152 static const char *MHEGEngineProviderIdString; 151 153 154 // Interaction: Set if an Interactible has the focus and is receiving key presses. 155 MHInteractible *GetInteraction(void) { return m_Interacting; } 156 void SetInteraction(MHInteractible *p) { m_Interacting = p; } 157 152 158 protected: 153 159 void CheckLinks(const MHObjectRef &sourceRef, enum EventType ev, const MHUnion &un); 154 160 MHGroup *ParseProgram(QByteArray &text); … … 193 199 194 200 MHContext *m_Context; // Pointer to the context providing drawing and other operations 195 201 bool m_fBooting; 202 203 MHInteractible *m_Interacting; // Set to current interactive object if any. 196 204 }; 197 205 198 206 #endif -
libs/libmythfreemheg/Bitmap.cpp
1 1 /* Bitmap.cpp 2 2 3 Copyright (C) David C. J. Matthews 2004 dm at prolingua.co.uk3 Copyright (C) David C. J. Matthews 2004, 2008 dm at prolingua.co.uk 4 4 5 5 This program is free software; you can redistribute it and/or 6 6 modify it under the terms of the GNU General Public License … … 113 113 if (nCHook == 4) { // PNG. 114 114 m_pContent->CreateFromPNG(data, length); 115 115 } 116 else if (nCHook == 2) { // MPEG I-frame. 116 // CHook 5 seems to be used by the BBC on Freesat for an MPEG I-frame for the 117 // background but enabling it here results in it overlaying the video. 118 // Presumably it is not simply the same as CHook 2. 119 else if (nCHook == 2 /* ||nCHook == 5 */) { // MPEG I-frame. 117 120 m_pContent->CreateFromMPEG(data, length); 118 121 } 119 122 -
libs/libmythfreemheg/freemheg.h
69 69 { 70 70 public: 71 71 MHRgba(int red, int green, int blue, int alpha): 72 m_red( Qt::red), m_green(Qt::green), m_blue(Qt::blue), m_alpha(alpha) {};72 m_red(red), m_green(green), m_blue(blue), m_alpha(alpha) {}; 73 73 MHRgba(): m_red(0), m_green(0), m_blue(0), m_alpha(0) {}; 74 74 int red() const { return m_red; } 75 75 int green() const { return m_green; } -
libs/libmythfreemheg/Text.h
90 90 void CreateContent(const unsigned char *p, int s, MHEngine *engine); 91 91 }; 92 92 93 class MHHyperText : public MHText, public 93 class MHHyperText : public MHText, public MHInteractible 94 94 { 95 95 public: 96 96 MHHyperText(); … … 98 98 virtual ~MHHyperText(); 99 99 virtual void Initialise(MHParseNode *p, MHEngine *engine); 100 100 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(); } 101 110 }; 102 111 103 112 // Get Text Data - get the data out of a text object. -
libs/libmythfreemheg/Programs.cpp
492 492 } 493 493 494 494 else if (m_Name.Equal("DBG")) { // Debug - optional 495 MHERROR("Debug ResidentProgram is not implemented"); 495 QString message = "DEBUG: "; 496 for (int i = 0; i < args.Size(); i++) { 497 MHUnion un; 498 un.GetValueFrom(*(args.GetAt(i)), engine); 499 switch (un.m_Type) { 500 case MHUnion::U_Int: 501 message.append(QString("%1").arg(un.m_nIntVal)); 502 break; 503 case MHParameter::P_Bool: 504 message.append(un.m_fBoolVal ? "True" : "False"); 505 break; 506 case MHParameter::P_String: 507 message.append(QString::fromUtf8((const char *)un.m_StrVal.Bytes(), un.m_StrVal.Size())); 508 break; 509 case MHParameter::P_ObjRef: 510 message.append(un.m_ObjRefVal.Printable()); 511 break; 512 case MHParameter::P_ContentRef: 513 message.append(un.m_ContentRefVal.Printable()); 514 break; 515 case MHParameter::P_Null: 516 break; 517 } 518 } 519 MHLOG(MHLogNotifications, message); 496 520 } 497 521 498 522 else { -
libs/libmythfreemheg/BaseActions.cpp
1 1 /* BaseActions.cpp 2 2 3 Copyright (C) David C. J. Matthews 2004 dm at prolingua.co.uk3 Copyright (C) David C. J. Matthews 2004, 2008 dm at prolingua.co.uk 4 4 5 5 This program is free software; you can redistribute it and/or 6 6 modify it under the terms of the GNU General Public License … … 87 87 m_ResultVar2.Initialise(p->GetArgN(2), engine); 88 88 } 89 89 90 void 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 98 void 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 105 void MHActionInt3::Perform(MHEngine *engine) 106 { 107 CallAction(engine, Target(engine), m_Argument1.GetValue(engine), m_Argument2.GetValue(engine), m_Argument3.GetValue(engine)); 108 } 109 90 110 void MHActionInt4::Initialise(MHParseNode *p, MHEngine *engine) 91 111 { 92 112 MHElemAction::Initialise(p, engine); … … 160 180 { 161 181 CallAction(engine, Target(engine), engine->FindObject(m_ResultVar1), engine->FindObject(m_ResultVar2)); 162 182 } 183 184 void MHActionBool::Initialise(MHParseNode *p, MHEngine *engine) 185 { 186 MHElemAction::Initialise(p, engine); 187 m_Argument.Initialise(p->GetArgN(1), engine); 188 } 189 190 191 void MHActionBool::Perform(MHEngine *engine) 192 { 193 CallAction(engine, Target(engine), m_Argument.GetValue(engine)); 194 } -
libs/libmythfreemheg/Link.cpp
1 1 /* Link.cpp 2 2 3 Copyright (C) David C. J. Matthews 2004 dm at prolingua.co.uk3 Copyright (C) David C. J. Matthews 2004, 2008 dm at prolingua.co.uk 4 4 5 5 This program is free software; you can redistribute it and/or 6 6 modify it under the terms of the GNU General Public License -
libs/libmythfreemheg/TokenGroup.cpp
54 54 for (int i = 0; i < m_ActionSlots.Size(); i++) { 55 55 PrintTabs(fd, nTabs+2); fprintf(fd, "(\n"); 56 56 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"); } 58 59 else pActions->PrintMe(fd, nTabs+2); 59 60 PrintTabs(fd, nTabs+2); fprintf(fd, ")\n"); 60 61 } -
libs/libmythfreemheg/Visible.cpp
355 355 } 356 356 357 357 358 MHInteractible::MHInteractible( )358 MHInteractible::MHInteractible(MHVisible *parent): m_parent(parent) 359 359 { 360 360 m_fEngineResp = true; 361 m_fHighlightStatus = false; 362 m_fInteractionStatus = false; 361 363 } 362 364 363 365 MHInteractible::~MHInteractible() … … 365 367 366 368 } 367 369 368 void MHInteractible::Initialise(MHParseNode * /*p*/, MHEngine */*engine*/)370 void MHInteractible::Initialise(MHParseNode *p, MHEngine *engine) 369 371 { 372 // Engine Resp - optional 373 MHParseNode *pEngineResp = p->GetNamedArg(C_ENGINE_RESP); 374 if (pEngineResp) m_fEngineResp = pEngineResp->GetArgN(0)->GetBoolValue(); 375 // Highlight colour. 376 MHParseNode *phlCol = p->GetNamedArg(C_HIGHLIGHT_REF_COLOUR); 377 if (phlCol) m_highlightRefColour.Initialise(phlCol->GetArgN(0), engine); 378 else engine->GetDefaultHighlightRefColour(m_highlightRefColour); 379 m_fHighlightStatus = false; 380 m_fInteractionStatus = false; 370 381 } 371 382 372 void MHInteractible::PrintMe(FILE * /*fd*/, int /*nTabs*/) const383 void MHInteractible::PrintMe(FILE *fd, int nTabs) const 373 384 { 385 if (! m_fEngineResp) { PrintTabs(fd, nTabs); fprintf(fd, ":EngineResp false\n"); } 386 387 if (m_highlightRefColour.IsSet()) { 388 PrintTabs(fd, nTabs); 389 fprintf(fd, ":HighlightRefColour "); 390 m_highlightRefColour.PrintMe(fd, nTabs+1); 391 fprintf(fd, "\n"); 392 } 374 393 } 375 394 376 MHSlider::MHSlider()395 void MHInteractible::Interaction(MHEngine *engine) 377 396 { 397 m_fInteractionStatus = true; 398 engine->SetInteraction(this); 399 // The MHEG standard says: "generate visual feedback" here 400 // but it appears that any visual feedback is controlled only 401 // by the highlight status combined with engine-resp. 402 } 378 403 404 void MHInteractible::InteractSetInteractionStatus(bool newStatus, MHEngine *engine) 405 { 406 if (newStatus) { // Turning interaction on. 407 if (engine->GetInteraction() == 0) // No current interactible 408 Interaction(engine); // virtual function 409 } 410 else { // Turning interaction off. 411 if (m_fInteractionStatus) { 412 m_fInteractionStatus = false; 413 engine->SetInteraction(0); 414 InteractionCompleted(engine); // Interaction is interrupted. 415 engine->EventTriggered(m_parent, EventInteractionCompleted); 416 } 417 } 379 418 } 380 419 381 MHSlider::~MHSlider()420 void MHInteractible::InteractSetHighlightStatus(bool newStatus, MHEngine *engine) 382 421 { 422 if (newStatus == m_fHighlightStatus) return; 423 m_fHighlightStatus = newStatus; 424 // If active redraw to show change of status. 425 if (m_parent->GetRunningStatus() && m_fEngineResp) 426 engine->Redraw(m_parent->GetVisibleArea()); 427 // Generate the event for the change of highlight status. 428 engine->EventTriggered(m_parent, m_fHighlightStatus ? EventHighlightOn: EventHighlightOff); 429 } 383 430 431 MHSlider::MHSlider(): MHInteractible(this) 432 { 433 m_orientation = SliderLeft; 434 orig_max_value = -1; 435 orig_min_value = initial_value = orig_step_size = 1; 436 initial_portion = 0; 437 m_style = SliderNormal; 384 438 } 385 439 440 MHSlider::~MHSlider() 441 { 442 } 443 386 444 void MHSlider::Initialise(MHParseNode *p, MHEngine *engine) 387 445 { 388 446 MHVisible::Initialise(p, engine); 389 447 MHInteractible::Initialise(p, engine); 390 // 448 // 449 MHParseNode *pOrientation = p->GetNamedArg(C_ORIENTATION); 450 if (pOrientation) 451 m_orientation = (enum SliderOrientation)pOrientation->GetArgN(0)->GetEnumValue(); 452 // This is not optional. 453 454 MHParseNode *pMin = p->GetNamedArg(C_MIN_VALUE); 455 if (pMin) orig_min_value = pMin->GetArgN(0)->GetIntValue(); 456 else orig_min_value = 1; 457 458 MHParseNode *pMax = p->GetNamedArg(C_MAX_VALUE); 459 if (pMax) orig_max_value = pMax->GetArgN(0)->GetIntValue(); 460 else orig_max_value = orig_min_value-1; // Unset 461 462 MHParseNode *pInit = p->GetNamedArg(C_INITIAL_VALUE); 463 if (pInit) initial_value = pInit->GetArgN(0)->GetIntValue(); 464 else initial_value = orig_min_value; // Default is min_value 465 466 MHParseNode *pPortion = p->GetNamedArg(C_INITIAL_PORTION); 467 if (pPortion) initial_portion = pPortion->GetArgN(0)->GetIntValue(); 468 else initial_portion = orig_min_value-1; // Unset 469 470 MHParseNode *pStep = p->GetNamedArg(C_STEP_SIZE); 471 if (pStep) orig_step_size = pStep->GetArgN(0)->GetIntValue(); 472 else orig_step_size = 1; // Unset 473 474 MHParseNode *pStyle = p->GetNamedArg(C_SLIDER_STYLE); 475 if (pStyle) m_style = (enum SliderStyle)pStyle->GetArgN(0)->GetEnumValue(); 476 else m_style = SliderNormal; 477 478 MHParseNode *pslCol = p->GetNamedArg(C_SLIDER_REF_COLOUR); 479 if (pslCol) m_sliderRefColour.Initialise(pslCol->GetArgN(0), engine); 480 else engine->GetDefaultSliderRefColour(m_sliderRefColour); 391 481 } 392 482 483 static const char *rchOrientation[] = 484 { 485 "left", // 1 486 "right", 487 "up", 488 "down" // 4 489 }; 490 491 // Look up the Orientation. Returns zero if it doesn't match. Used in the text parser only. 492 int MHSlider::GetOrientation(const char *str) 493 { 494 for (int i = 0; i < (int)(sizeof(rchOrientation)/sizeof(rchOrientation[0])); i++) { 495 if (strcasecmp(str, rchOrientation[i]) == 0) return (i+1); // Numbered from 1 496 } 497 return 0; 498 } 499 500 static const char *rchStyle[] = 501 { 502 "normal", // 1 503 "thermometer", 504 "proportional" // 3 505 }; 506 507 int MHSlider::GetStyle(const char *str) 508 { 509 for (int i = 0; i < (int)(sizeof(rchStyle)/sizeof(rchStyle[0])); i++) { 510 if (strcasecmp(str, rchStyle[i]) == 0) return (i+1); // Numbered from 1 511 } 512 return 0; 513 } 514 393 515 void MHSlider::PrintMe(FILE *fd, int nTabs) const 394 516 { 395 517 PrintTabs(fd, nTabs); fprintf(fd, "{:Slider "); 396 MHVisible::PrintMe(fd, nTabs );518 MHVisible::PrintMe(fd, nTabs+1); 397 519 MHInteractible::PrintMe(fd, nTabs+1); 398 fprintf(fd, "****TODO\n"); 520 521 PrintTabs(fd, nTabs); fprintf(fd, ":Orientation %s\n", rchOrientation[m_orientation-1]); 522 523 if (initial_value >= orig_min_value) { 524 PrintTabs(fd, nTabs+1); fprintf(fd, ":InitialValue %d\n", initial_value); 525 } 526 527 if (orig_min_value != 1) { 528 PrintTabs(fd, nTabs+1); fprintf(fd, ":MinValue %d\n", orig_min_value); 529 } 530 531 if (orig_max_value > orig_min_value) { 532 PrintTabs(fd, nTabs+1); fprintf(fd, ":MaxValue %d\n", orig_max_value); 533 } 534 535 if (initial_portion >= orig_min_value) { 536 PrintTabs(fd, nTabs+1); fprintf(fd, ":InitialPortion %d\n", initial_portion); 537 } 538 539 if (orig_step_size != 1) { 540 PrintTabs(fd, nTabs+1); fprintf(fd, ":StepSize %d\n", orig_step_size); 541 } 542 543 if (m_style != SliderNormal) 544 { 545 PrintTabs(fd, nTabs+1); 546 fprintf(fd, ":SliderStyle %s\n", rchStyle[m_style-1]); 547 } 548 549 if (m_sliderRefColour.IsSet()) { 550 PrintTabs(fd, nTabs+1); 551 fprintf(fd, ":SliderRefColour "); 552 m_sliderRefColour.PrintMe(fd, nTabs+2); 553 fprintf(fd, "\n"); 554 } 555 399 556 PrintTabs(fd, nTabs); fprintf(fd, "}\n"); 400 557 } 401 558 402 MHEntryField::MHEntryField() 559 // The MHEG standard doesn't define where the internal values are 560 // initialised. Assume it's during preparation. 561 void MHSlider::Preparation(MHEngine *engine) 403 562 { 563 MHVisible::Preparation(engine); 564 max_value = orig_max_value; 565 min_value = orig_min_value; 566 step_size = orig_step_size; 567 slider_value = initial_value; 568 portion = initial_portion; 569 } 404 570 571 void MHSlider::Display(MHEngine *engine) 572 { 573 MHContext *d = engine->GetContext(); 574 MHRgba colour; 575 if (m_fHighlightStatus && m_fEngineResp) 576 colour = GetColour(m_highlightRefColour); 577 else colour = GetColour(m_sliderRefColour); 578 579 int major; // Direction of change. 580 if (m_orientation == SliderLeft || m_orientation == SliderRight) 581 major = m_nBoxWidth; 582 else major = m_nBoxHeight; 583 584 if (max_value <= min_value) return; // Avoid divide by zero if error. 585 586 if (m_style == SliderNormal) 587 { 588 // This is drawn as a 9 pixel wide "thumb" at the position. 589 major -= 9; // Width of "thumb" 590 int posn = major * (slider_value-min_value) / (max_value-min_value); 591 switch (m_orientation) 592 { 593 case SliderLeft: 594 d->DrawRect(m_nPosX + posn, m_nPosY, 9, m_nBoxHeight, colour); 595 break; 596 case SliderRight: 597 d->DrawRect(m_nPosX + m_nBoxWidth - posn - 9, m_nPosY, 9, m_nBoxHeight, colour); 598 break; 599 case SliderUp: 600 d->DrawRect(m_nPosX, m_nPosY + m_nBoxHeight - posn - 9, m_nBoxWidth, 9, colour); 601 break; 602 case SliderDown: 603 d->DrawRect(m_nPosX, m_nPosY + posn, m_nBoxWidth, 9, colour); 604 break; 605 } 606 } 607 else { 608 // Thermometer and proportional sliders are drawn as bars. Thermometers 609 // run from the start to the position, proportional sliders from the 610 // position for the "portion". 611 int start = 0; 612 int end = major * (slider_value-min_value) / (max_value-min_value); 613 if (m_style == SliderProp) 614 { 615 start = end; 616 end = major * (slider_value+portion -min_value) / (max_value-min_value); 617 } 618 switch (m_orientation) 619 { 620 case SliderLeft: 621 d->DrawRect(m_nPosX + start, m_nPosY, end-start, m_nBoxHeight, colour); 622 break; 623 case SliderRight: 624 d->DrawRect(m_nPosX + m_nBoxWidth - end, m_nPosY, end-start, m_nBoxHeight, colour); 625 break; 626 case SliderUp: 627 d->DrawRect(m_nPosX, m_nPosY + m_nBoxHeight - end, m_nBoxWidth, end-start, colour); 628 break; 629 case SliderDown: 630 d->DrawRect(m_nPosX, m_nPosY + start, m_nBoxWidth, end-start, colour); 631 break; 632 } 633 634 } 405 635 } 406 636 637 void MHSlider::Interaction(MHEngine *engine) 638 { 639 MHInteractible::Interaction(engine); 640 // All the interaction is handled by KeyEvent. 641 } 642 643 // Called when the interaction has been terminated and we need 644 // to restore the state to non-interacting. 645 void MHSlider::InteractionCompleted(MHEngine *engine) 646 { 647 MHInteractible::InteractionCompleted(engine); 648 // Redraw with the interaction highlighting turned off 649 engine->Redraw(GetVisibleArea()); 650 } 651 652 // Called when a key is pressed. The only keys that have an effect are 653 // the Select and Cancel keys which both terminate the action and the 654 // arrow keys. The effect of the arrow keys depends on the orientation of 655 // the slider. 656 void MHSlider::KeyEvent(MHEngine *engine, int nCode) 657 { 658 switch (nCode) 659 { 660 case 15: // Select key 661 case 16: // Cancel key 662 m_fInteractionStatus = false; 663 engine->SetInteraction(0); 664 InteractionCompleted(engine); // Interaction is interrupted. 665 engine->EventTriggered(this, EventInteractionCompleted); 666 break; 667 668 case 1: // Up 669 if (m_orientation == SliderUp) 670 Increment(engine); 671 else if (m_orientation == SliderDown) 672 Decrement(engine); 673 break; 674 675 case 2: // Down 676 if (m_orientation == SliderUp) 677 Decrement(engine); 678 else if (m_orientation == SliderDown) 679 Increment(engine); 680 break; 681 682 case 3: // Left 683 if (m_orientation == SliderLeft) 684 Increment(engine); 685 else if (m_orientation == SliderRight) 686 Decrement(engine); 687 break; 688 689 case 4: // Right 690 if (m_orientation == SliderLeft) 691 Decrement(engine); 692 else if (m_orientation == SliderRight) 693 Increment(engine); 694 break; 695 696 } 697 } 698 699 void MHSlider::Increment(MHEngine *engine) 700 { 701 if (slider_value+step_size <= max_value) 702 { 703 slider_value += step_size; 704 engine->Redraw(GetVisibleArea()); 705 engine->EventTriggered(this, EventSliderValueChanged); 706 } 707 } 708 709 void MHSlider::Decrement(MHEngine *engine) 710 { 711 if (slider_value-step_size >= min_value) 712 { 713 slider_value -= step_size; 714 engine->Redraw(GetVisibleArea()); 715 engine->EventTriggered(this, EventSliderValueChanged); 716 } 717 } 718 719 void MHSlider::Step(int nbSteps, MHEngine *engine) 720 { 721 step_size = nbSteps; 722 if (m_fRunning) engine->Redraw(GetVisibleArea()); 723 engine->EventTriggered(this, EventSliderValueChanged); 724 } 725 726 void MHSlider::SetSliderValue(int newValue, MHEngine *engine) 727 { 728 slider_value = newValue; 729 if (m_fRunning) engine->Redraw(GetVisibleArea()); 730 engine->EventTriggered(this, EventSliderValueChanged); 731 } 732 733 void MHSlider::SetPortion(int newPortion, MHEngine *engine) 734 { 735 portion = newPortion; 736 if (m_fRunning) engine->Redraw(GetVisibleArea()); 737 engine->EventTriggered(this, EventSliderValueChanged); 738 } 739 740 // Additional action defined in UK MHEG. 741 void MHSlider::SetSliderParameters(int newMin, int newMax, int newStep, MHEngine *engine) 742 { 743 min_value = newMin; 744 max_value = newMax; 745 step_size = newStep; 746 slider_value = newMin; 747 if (m_fRunning) engine->Redraw(GetVisibleArea()); 748 engine->EventTriggered(this, EventSliderValueChanged); 749 } 750 751 752 MHEntryField::MHEntryField(): MHInteractible(this) 753 { 754 755 } 756 407 757 MHEntryField::~MHEntryField() 408 758 { 409 759