Added classes for MindLink and CompuMate controllers. Note that

these aren't fully activated yet, but they're the next thing I plan
to work on.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2322 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2012-01-02 16:37:17 +00:00
parent d8b59f7083
commit b7125a26ee
13 changed files with 467 additions and 122 deletions

53
src/emucore/CompuMate.cxx Normal file
View File

@ -0,0 +1,53 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2012 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#include "Event.hxx"
#include "CompuMate.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CompuMate::CompuMate(Jack jack, const Event& event, const System& system)
: Controller(jack, event, system, Controller::CompuMate),
myIOPort(0xff)
{
if(myJack == Left)
{
myAnalogPinValue[Five] = minimumResistance;
myAnalogPinValue[Nine] = maximumResistance;
}
else
{
myAnalogPinValue[Five] = maximumResistance;
myAnalogPinValue[Nine] = minimumResistance;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CompuMate::~CompuMate()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CompuMate::controlWrite()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CompuMate::update()
{
}

82
src/emucore/CompuMate.hxx Normal file
View File

@ -0,0 +1,82 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2012 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#ifndef COMPUMATE_HXX
#define COMPUMATE_HXX
#include "bspf.hxx"
#include "Control.hxx"
#include "Event.hxx"
/**
The Spectravideo CompuMate SV010 was a home computer expansion for the
Atari VCS / 2600 video game system.
It consists of a membrane keyboard unit with interface connectors. These
connectors were placed in the module slot and both controller ports of the
Atari console. As the user could place the keyboard on the old style VCS
consoles, the two devices resulted in one compact unit. When using with the
2600jr console, resulted in a desktop computer look with separated keyboard.
The CompuMate was equipped with an audio jack for use with a standard tape
connector as a possibility of permanent data storage.
This code was heavily borrowed from z26, and uses conventions defined
there. Specifically, IOPortA is treated as a complete uInt8, whereas
the Stella core actually stores this information in boolean arrays
addressable by DigitalPin number.
@author Stephen Anthony & z26 team
@version $Id$
*/
class CompuMate : public Controller
{
public:
/**
Create a new MindLink controller plugged into the specified jack
@param jack The jack the controller is plugged into
@param event The event object to use for events
@param system The system using this controller
*/
CompuMate(Jack jack, const Event& event, const System& system);
/**
Destructor
*/
virtual ~CompuMate();
public:
/**
Called after *all* digital pins have been written on Port A.
*/
void controlWrite();
/**
Update the entire digital and analog pin state according to the
events currently set.
*/
void update();
private:
// Internal state of the port pins
uInt8 myIOPort;
};
#endif

View File

@ -34,6 +34,8 @@
#include "Keyboard.hxx"
#include "KidVid.hxx"
#include "Genesis.hxx"
#include "MindLink.hxx"
#include "CompuMate.hxx"
#include "M6502.hxx"
#include "M6532.hxx"
#include "Paddles.hxx"
@ -664,6 +666,14 @@ void Console::setControllers(const string& rommd5)
{
myControllers[leftPort] = new Genesis(Controller::Left, *myEvent, *mySystem);
}
else if(left == "COMPUMATE")
{
myControllers[leftPort] = new CompuMate(Controller::Left, *myEvent, *mySystem);
}
else if(left == "MINDLINK")
{
myControllers[leftPort] = new MindLink(Controller::Left, *myEvent, *mySystem);
}
else
{
myControllers[leftPort] = new Joystick(Controller::Left, *myEvent, *mySystem);
@ -723,13 +733,21 @@ void Console::setControllers(const string& rommd5)
myControllers[rightPort] = new SaveKey(Controller::Right, *myEvent, *mySystem,
eepromfile);
}
else if(right == "GENESIS")
{
myControllers[rightPort] = new Genesis(Controller::Right, *myEvent, *mySystem);
}
else if(right == "COMPUMATE")
{
myControllers[rightPort] = new CompuMate(Controller::Right, *myEvent, *mySystem);
}
else if(right == "KIDVID")
{
myControllers[rightPort] = new KidVid(Controller::Right, *myEvent, *mySystem, rommd5);
}
else if(right == "GENESIS")
else if(right == "MINDLINK")
{
myControllers[rightPort] = new Genesis(Controller::Right, *myEvent, *mySystem);
myControllers[rightPort] = new MindLink(Controller::Right, *myEvent, *mySystem);
}
else
{

View File

@ -77,6 +77,12 @@ Controller::Controller(Jack jack, const Event& event, const System& system,
case Genesis:
myName = "Genesis";
break;
case MindLink:
myName = "MindLink";
break;
case CompuMate:
myName = "CompuMate";
break;
}
}
@ -91,6 +97,18 @@ const Controller::Type Controller::type() const
return myType;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 Controller::read()
{
uInt8 ioport = 0x00;
if(myDigitalPinState[One]) ioport |= 0x01;
if(myDigitalPinState[Two]) ioport |= 0x02;
if(myDigitalPinState[Three]) ioport |= 0x04;
if(myDigitalPinState[Four]) ioport |= 0x08;
return myJack == Left ? (ioport << 4) : ioport;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Controller::read(DigitalPin pin)
{

View File

@ -90,7 +90,7 @@ class Controller : public Serializable
{
BoosterGrip, Driving, Keyboard, Paddles, Joystick,
TrackBall22, TrackBall80, AmigaMouse, AtariVox, SaveKey,
KidVid, Genesis
KidVid, Genesis, MindLink, CompuMate
};
/**
@ -124,6 +124,19 @@ class Controller : public Serializable
*/
const Type type() const;
/**
Read the entire state of all digital pins for this controller.
Note that this method must take into account the location of the
pin data in the bitfield, and zero the remaining data:
Left port : upper 4 bits valid, lower 4 bits zero'ed
Right port: lower 4 bits valid, upper 4 bits zero'ed
@return The state of all digital pins
*/
virtual uInt8 read();
/**
Read the value of the specified digital pin for this controller.
@ -151,12 +164,19 @@ class Controller : public Serializable
*/
virtual void write(DigitalPin pin, bool value) { };
/**
Called after *all* digital pins have been written on Port A.
Most controllers don't do anything in this case.
*/
virtual void controlWrite() { };
/**
Update the entire digital and analog pin state according to the
events currently set.
*/
virtual void update() = 0;
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary

View File

@ -119,19 +119,8 @@ uInt8 M6532::peek(uInt16 addr)
{
case 0x00: // SWCHA - Port A I/O Register (Joystick)
{
uInt8 value = 0x00;
Controller& port0 = myConsole.controller(Controller::Left);
if(port0.read(Controller::One)) value |= 0x10;
if(port0.read(Controller::Two)) value |= 0x20;
if(port0.read(Controller::Three)) value |= 0x40;
if(port0.read(Controller::Four)) value |= 0x80;
Controller& port1 = myConsole.controller(Controller::Right);
if(port1.read(Controller::One)) value |= 0x01;
if(port1.read(Controller::Two)) value |= 0x02;
if(port1.read(Controller::Three)) value |= 0x04;
if(port1.read(Controller::Four)) value |= 0x08;
uInt8 value = myConsole.controller(Controller::Left).read() |
myConsole.controller(Controller::Right).read();
// Each pin is high (1) by default and will only go low (0) if either
// (a) External device drives the pin low
@ -231,14 +220,14 @@ bool M6532::poke(uInt16 addr, uInt8 value)
case 0: // SWCHA - Port A I/O Register (Joystick)
{
myOutA = value;
setPinState();
setPinState(true);
break;
}
case 1: // SWACNT - Port A Data Direction Register
{
myDDRA = value;
setPinState();
setPinState(false);
break;
}
@ -271,7 +260,7 @@ void M6532::setTimerRegister(uInt8 value, uInt8 interval)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6532::setPinState()
void M6532::setPinState(bool swcha)
{
/*
When a bit in the DDR is set as input, +5V is placed on its output
@ -290,12 +279,14 @@ void M6532::setPinState()
port0.write(Controller::Two, a & 0x20);
port0.write(Controller::Three, a & 0x40);
port0.write(Controller::Four, a & 0x80);
if(swcha) port0.controlWrite();
Controller& port1 = myConsole.controller(Controller::Right);
port1.write(Controller::One, a & 0x01);
port1.write(Controller::Two, a & 0x02);
port1.write(Controller::Three, a & 0x04);
port1.write(Controller::Four, a & 0x08);
if(swcha) port1.controlWrite();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -134,7 +134,7 @@ class M6532 : public Device
{ return myTimer - (mySystem->cycles() - myCyclesWhenTimerSet); }
void setTimerRegister(uInt8 data, uInt8 interval);
void setPinState();
void setPinState(bool shcha);
private:
// Reference to the console

100
src/emucore/MindLink.cxx Normal file
View File

@ -0,0 +1,100 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2012 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#include "Event.hxx"
#include "MindLink.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MindLink::MindLink(Jack jack, const Event& event, const System& system)
: Controller(jack, event, system, Controller::MindLink),
myIOPort(0xff),
myMindlinkPos(0x2800),
myMindlinkPos1(0x2800),
myMindlinkPos2(0x1000),
myMindlinkShift(1)
{
// Analog pins are never used by the MindLink
myAnalogPinValue[Five] = myAnalogPinValue[Nine] = maximumResistance;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MindLink::~MindLink()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MindLink::update()
{
myIOPort |= 0xf0;
if(0)//MPdirection & 0x01)
myMindlinkPos = myMindlinkPos2 + 0x1800;
else
myMindlinkPos = myMindlinkPos1;
myMindlinkPos = (myMindlinkPos & 0x3fffffff) +
(myEvent.get(Event::MouseAxisXValue) << 3);
if(myMindlinkPos < 0x2800)
myMindlinkPos = 0x2800;
if(myMindlinkPos >= 0x3800)
myMindlinkPos = 0x3800;
if(0)//MPdirection & 0x01)
{
myMindlinkPos2 = myMindlinkPos - 0x1800;
myMindlinkPos = myMindlinkPos2;
}
else
myMindlinkPos1 = myMindlinkPos;
myMindlinkShift = 1;
nextMindlinkBit();
if(myEvent.get(Event::MouseButtonValue))
myMindlinkPos |= 0x4000; /* this bit starts a game */
//cerr << HEX4 << (int)myMindlinkPos << " : " << HEX2 << (int)myIOPort << endl;
// Convert IOPort values back to booleans
myDigitalPinState[One] = myIOPort & 0x10;
myDigitalPinState[Two] = myIOPort & 0x20;
myDigitalPinState[Three] = myIOPort & 0x40;
myDigitalPinState[Four] = myIOPort & 0x80;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MindLink::nextMindlinkBit()
{
if(myIOPort & 0x10)
{
myIOPort &= 0x3f;
if(myMindlinkPos & myMindlinkShift)
myIOPort |= 0x80;
myMindlinkShift <<= 1;
myDigitalPinState[One] = myIOPort & 0x10;
myDigitalPinState[Two] = myIOPort & 0x20;
myDigitalPinState[Three] = myIOPort & 0x40;
myDigitalPinState[Four] = myIOPort & 0x80;
cerr << dec << (int)myMindlinkShift << " : " << HEX2 << (int)myIOPort << endl;
}
}

95
src/emucore/MindLink.hxx Normal file
View File

@ -0,0 +1,95 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2012 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#ifndef MINDLINK_HXX
#define MINDLINK_HXX
#include "bspf.hxx"
#include "Control.hxx"
/**
The Atari Mindlink was an unreleased video game controller intended for
release in 1984. The Mindlink was unique in that one had to move the
muscles in one's head to control the game. These movements would be read by
infrared sensors and transferred as movement in the game. For more
information, see the following link:
http://www.atarimuseum.com/videogames/consoles/2600/mindlink.html
This code was heavily borrowed from z26, and uses conventions defined
there. Specifically, IOPortA is treated as a complete uInt8, whereas
the Stella core actually stores this information in boolean arrays
addressable by DigitalPin number.
@author Stephen Anthony & z26 team
@version $Id$
*/
class MindLink : public Controller
{
public:
/**
Create a new MindLink controller plugged into the specified jack
@param jack The jack the controller is plugged into
@param event The event object to use for events
@param system The system using this controller
*/
MindLink(Jack jack, const Event& event, const System& system);
/**
Destructor
*/
virtual ~MindLink();
public:
/**
Called after *all* digital pins have been written on Port A.
*/
void controlWrite() { nextMindlinkBit(); }
/**
Update the entire digital and analog pin state according to the
events currently set.
*/
void update();
private:
void nextMindlinkBit();
private:
uInt8 myMask1, myMask2, myMask3;
// Internal state of the port pins
uInt8 myIOPort;
// Position value in Mindlink controller
// Gets transferred bitwise (16 bits)
int myMindlinkPos;
// Position for player 1 (0x2800-0x3800)
int myMindlinkPos1;
// Position for player 2 (0x1000-0x2000)
int myMindlinkPos2;
// Which bit to transfer next
int myMindlinkShift;
};
#endif

View File

@ -29,23 +29,11 @@ TrackBall::TrackBall(Jack jack, const Event& event, const System& system,
Type type)
: Controller(jack, event, system, type),
myHCounter(0),
myVCounter(0),
myCyclesWhenSWCHARead(0)
myVCounter(0)
{
if(myJack == Left)
{
myPin1Mask = 0x10;
myPin2Mask = 0x20;
myPin3Mask = 0x40;
myPin4Mask = 0x80;
}
else
{
myPin1Mask = 0x01;
myPin2Mask = 0x02;
myPin3Mask = 0x04;
myPin4Mask = 0x08;
}
// This code in ::read() is set up to always return IOPortA values in
// the lower 4 bits data value
// As such, the jack type (left or right) isn't necessary here
myTrakBallCountH = myTrakBallCountV = 0;
myTrakBallLinesH = myTrakBallLinesV = 1;
@ -63,76 +51,65 @@ TrackBall::~TrackBall()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool TrackBall::read(DigitalPin pin)
uInt8 TrackBall::read()
{
// Only update the controller pins when an SWCHA read is actually
// different from a previous one
// This is done since Stella tends to read several pins consecutively
// in the same processor 'cycle', and it would be incorrect to do this
// work multiple times per processor cycle
if(myCyclesWhenSWCHARead != mySystem.cycles())
int scanline = ((System&)mySystem).tia().scanlines();
if(myScanCountV > scanline) myScanCountV = 0;
if(myScanCountH > scanline) myScanCountH = 0;
while((myScanCountV + myTrakBallLinesV) < scanline)
{
int scanline = ((System&)mySystem).tia().scanlines();
if(myScanCountV > scanline) myScanCountV = 0;
if(myScanCountH > scanline) myScanCountH = 0;
while((myScanCountV + myTrakBallLinesV) < scanline)
if(myTrakBallCountV)
{
if(myTrakBallCountV)
{
if(myTrakBallDown) myCountV--;
else myCountV++;
myTrakBallCountV--;
}
myScanCountV += myTrakBallLinesV;
if(myTrakBallDown) myCountV--;
else myCountV++;
myTrakBallCountV--;
}
myScanCountV += myTrakBallLinesV;
}
while((myScanCountH + myTrakBallLinesH) < scanline)
while((myScanCountH + myTrakBallLinesH) < scanline)
{
if(myTrakBallCountH)
{
if(myTrakBallCountH)
{
if(myTrakBallLeft) myCountH--;
else myCountH++;
myTrakBallCountH--;
}
myScanCountH += myTrakBallLinesH;
if(myTrakBallLeft) myCountH--;
else myCountH++;
myTrakBallCountH--;
}
myCountV &= 0x03;
myCountH &= 0x03;
uInt8 IOPortA = 0x00;
switch(myType)
{
case Controller::TrackBall80:
IOPortA = IOPortA
| ourTrakBallTableST_V[myCountV]
| ourTrakBallTableST_H[myCountH];
break;
case Controller::TrackBall22:
IOPortA = IOPortA
| ourTrakBallTableTB_V[myCountV & 0x01][myTrakBallDown]
| ourTrakBallTableTB_H[myCountH & 0x01][myTrakBallLeft];
break;
case Controller::AmigaMouse:
IOPortA = IOPortA
| ourTrakBallTableAM_V[myCountV]
| ourTrakBallTableAM_H[myCountH];
break;
default:
break;
}
myDigitalPinState[One] = IOPortA & myPin1Mask;
myDigitalPinState[Two] = IOPortA & myPin2Mask;
myDigitalPinState[Three] = IOPortA & myPin3Mask;
myDigitalPinState[Four] = IOPortA & myPin4Mask;
myScanCountH += myTrakBallLinesH;
}
// Remember when the SWCHA read was issued
myCyclesWhenSWCHARead = mySystem.cycles();
myCountV &= 0x03;
myCountH &= 0x03;
return Controller::read(pin);
uInt8 IOPortA = 0x00;
switch(myType)
{
case Controller::TrackBall80:
IOPortA = IOPortA
| ourTrakBallTableST_V[myCountV]
| ourTrakBallTableST_H[myCountH];
break;
case Controller::TrackBall22:
IOPortA = IOPortA
| ourTrakBallTableTB_V[myCountV & 0x01][myTrakBallDown]
| ourTrakBallTableTB_H[myCountH & 0x01][myTrakBallLeft];
break;
case Controller::AmigaMouse:
IOPortA = IOPortA
| ourTrakBallTableAM_V[myCountV]
| ourTrakBallTableAM_H[myCountH];
break;
default:
break;
}
myDigitalPinState[One] = IOPortA & 0x10;
myDigitalPinState[Two] = IOPortA & 0x20;
myDigitalPinState[Three] = IOPortA & 0x40;
myDigitalPinState[Four] = IOPortA & 0x80;
return myJack == Left ? IOPortA : (IOPortA >> 4);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -157,13 +134,6 @@ void TrackBall::update()
myDigitalPinState[Six] = (myEvent.get(Event::MouseButtonValue) == 0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TrackBall::systemCyclesReset()
{
myCyclesWhenSWCHARead -= mySystem.cycles();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt32 TrackBall::ourTrakBallTableTB_H[2][2] = {
{ 0x40, 0x00 }, { 0xc0, 0x80 }

View File

@ -58,12 +58,20 @@ class TrackBall : public Controller
public:
/**
Read the value of the specified digital pin for this controller.
Read the entire state of all digital pins for this controller.
@param pin The pin of the controller jack to read
@return The state of the pin
Note that this method must take into account the location of the
pin data in the bitfield, and zero the remaining data:
Left port : upper 4 bits valid, lower 4 bits zero'ed
Right port: lower 4 bits valid, upper 4 bits zero'ed
This method completely takes over reading of the port;
it doesn't call Controller::read() at all.
@return The state of all digital pins
*/
bool read(DigitalPin pin);
uInt8 read();
/**
Update the entire digital and analog pin state according to the
@ -71,24 +79,10 @@ class TrackBall : public Controller
*/
void update();
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for devices that remember cycle counts.
*/
void systemCyclesReset();
private:
// Counter to iterate through the gray codes
int myHCounter, myVCounter;
// Indicates the processor cycle when SWCHA was last read
uInt32 myCyclesWhenSWCHARead;
// Masks to indicate how to access the pins (differentiate between
// left and right ports)
uInt8 myPin1Mask, myPin2Mask, myPin3Mask, myPin4Mask;
// How many new horizontal and vertical values this frame
int myTrakBallCountH, myTrakBallCountV;

View File

@ -31,6 +31,7 @@ MODULE_OBJS := \
src/emucore/CartUA.o \
src/emucore/Cart0840.o \
src/emucore/CartX07.o \
src/emucore/CompuMate.o \
src/emucore/Console.o \
src/emucore/Control.o \
src/emucore/Driving.o \
@ -41,6 +42,7 @@ MODULE_OBJS := \
src/emucore/Joystick.o \
src/emucore/Keyboard.o \
src/emucore/KidVid.o \
src/emucore/MindLink.o \
src/emucore/M6502.o \
src/emucore/M6532.o \
src/emucore/MT24LC256.o \

View File

@ -238,7 +238,9 @@ GameInfoDialog::GameInfoDialog(
ctrls.push_back("AtariVox", "ATARIVOX" );
ctrls.push_back("SaveKey", "SAVEKEY" );
ctrls.push_back("Sega Genesis", "GENESIS" );
// TODO ctrls.push_back("KidVid", "KIDVID" );
// ctrls.push_back("CompuMate", "COMPUMATE" );
// ctrls.push_back("KidVid", "KIDVID" );
// ctrls.push_back("MindLink", "MINDLINK" );
myP0Controller = new PopUpWidget(myTab, font, xpos+lwidth, ypos,
pwidth, lineHeight, ctrls, "", 0, 0);
wid.push_back(myP0Controller);