Hello! I'm trying to design a very simple GUI which has the following hierarchy:
View
Frame
Control
Widgets Timers
Label
TextBox
Button
Frame has a map which stores pointers to the controls that belong to it. (You can think of frame as a window). It also has a redraw method, that redraws all the widgets that belong to the frame. As you can see in the method implementation below, I am using a switch, that first asks for the kind of widget and then casts a pointer to the correct type, then finally calls the redraw method implementation for that particular object type. The things is that in my very limited knowledge, this seems (to me) to void the concept of polymorphism, because for each new widget that I add to my class, I need to expand the WidgetType enum and create a new case: . Is there another way to do this, so that the type of the object to be redrawn can be determined at run-time ? Thank you very much in advance. Please excuse my poor english.
METHOD:
Code:
void Frame::redraw( SDL_Surface* screen )
{
SDL_BlitSurface(backgroundImage, NULL, screen, NULL );
for( map<string, Control*>::iterator iter = frameControls.begin(); iter != frameControls.end(); iter++ )
if( CONTROL_WIDGET == ((*iter).second)->getControlType() )
{
// (*iter).second is a pointer to a Control object, which is being casted to a Widget*.
switch( (reinterpret_cast<Widgets*>((*iter).second))->getWidgetType() )
{
case WIDGET_LABEL:
(reinterpret_cast<Label*>((*iter).second))->getWidgetType();
break;
case WIDGET_TEXTBOX:
(reinterpret_cast<Textbox*>((*iter).second))->getWidgetType();
break;
case WIDGET_BUTTON:
(reinterpret_cast<Button*>((*iter).second))->getWidgetType();
break;
}
}
return;
}
HEADER:
Code:
/******************** INCLUDES *******************/
#include <SDL/SDL.h>
#include <string>
#include <vector>
#include <map>
/************** ENUMS *******************/
typedef enum { CONTROL_WIDGET, CONTROL_TIMER } ControlType;
typedef enum { WIDGET_LABEL, WIDGET_TEXTBOX, WIDGET_BUTTON} WidgetType;
typedef enum { TIMER_TEXTBOX_POINTER, TIMER_CURRENT_TIME, TIMER_WAIT_FOR_INTERVAL } TimerType;
/***************** CONSTANTS ***********************/
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;
using namespace std;
/*************************************************************
*
* Control Class
*
**************************************************************/
class Control
{
public:
Control() {}
~Control() {}
inline ControlType getControlType() { return controlType; }
protected:
ControlType controlType;
};
/**************************************************************/
/*************************************************************
*
* Timers Class
*
**************************************************************/
class Timers: public Control
{
public:
// Depending on the TimerType, the action performed when the time ends varies.
Timers( Uint32 interval = 0, TimerType action = TIMER_CURRENT_TIME );
~Timers() {}
protected:
TimerType timerType;
SDL_TimerID timerID; //Used to store the info returned by SDL_AddTimer.
inline Uint32 getTicks() { return SDL_GetTicks();}
};
/**************************************************************/
/*************************************************************
*
* Widgets Class
*
**************************************************************/
class Widgets: public Control
{
public:
virtual inline int redraw( SDL_Surface* screen) = 0;
inline void setText( string text ) { this->text = text; }
inline void setImage( string imagePathName ) { }
inline SDL_Rect getUpLeftCoordinate() { return upLeftCoordinate; }
inline SDL_Rect getDownRightCoordinate() { return downRightCoordinate; }
inline WidgetType getWidgetType() { return widgetType; }
void setBackgroundColor( SDL_Color newColor );
bool wasClicked( SDL_Rect upLeftCoordinate );
protected:
//Coords to describe the Widget rectangle.
SDL_Rect upLeftCoordinate;
SDL_Rect downRightCoordinate;
//Contains the image (which was in a file BMP, JPG, etc) that represents the widget.
SDL_Surface* image;
// String of text that is shown by the widget.
string text;
// Optional, in case there is no image.
Uint32 backgroundColor;
// Used to identify the widget.
WidgetType widgetType;
};
/**************************************************************/
/*************************************************************
*
* Label Class
*
**************************************************************/
class Label: public Widgets
{
public:
Label( SDL_Rect upLeft, SDL_Surface* image = NULL, Uint32 backgroundColor = 0, string text = "");
~Label();
virtual inline int redraw( SDL_Surface* screen);
protected:
};
/**************************************************************/
/*************************************************************
*
* Textbox Class
*
**************************************************************/
class Textbox: public Widgets
{
public:
Textbox( SDL_Rect upLeft, SDL_Surface* image = NULL, Uint32 backgroundColor = 0, string text = "", string textboxMessage = "" );
~Textbox();
virtual inline int redraw( SDL_Surface* screen );
inline void setActiveTextbox() {activeTextbox = true;}
inline void unsetActiveTextbox() {activeTextbox = false;}
inline bool isActiveTextbox() { return activeTextbox; }
protected:
bool activeTextbox;
bool drawPointer;
// Message that tells the user what is a particular textbox for.
string textboxMessage;
};
/**************************************************************/
/*************************************************************
*
* Button Class
*
**************************************************************/
class Button: public Widgets
{
public:
Button( SDL_Rect upLeft, SDL_Surface* pressedImage = NULL, SDL_Surface* unPressedImage = NULL, Uint32 backgroundColor = 0, string text = "" );
~Button();
inline void setPressed() { pressed = true; }
inline void unsetPressed() { pressed = false; }
virtual int redraw( SDL_Surface* screen );
protected:
bool pressed; // Tells wether the button is being pressed or not.
SDL_Surface* pressedImage;
SDL_Surface* unPressedImage;
};
/**************************************************************/
/*************************************************************
*
* Frame Class
*
**************************************************************/
class Frame
{
public:
Frame( SDL_Surface* backgroundImage = NULL, Uint32 backgroundColor = 0 );
~Frame();
bool addControl( string identifier, Control* newControl );
//Redraw the whole window, with all it's elements.
void redraw( SDL_Surface* screen );
//Given a Coordinate, return the string key of the widget that resides in that coordinate.
Control* getWidget( SDL_Rect clickCoordinate );
protected:
SDL_Surface* backgroundImage; //Window background image.
Uint32 backgroundColor; // Optional, in case there is no image.
//Contains pointers to all the elements belonging to the frame.
map< string, Control* > frameControls;
};
/**************************************************************/
/*************************************************************
*
* View Class
*
**************************************************************/
class View
{
public:
View(string windowMarkerName = "");
~View();
inline void setRefresh() { refreshScreen = true; }
bool addFrame( Frame* newFrame);
void redrawScreen();
protected:
SDL_Surface* screen;
vector<Frame *> frameStack;
bool refreshScreen;
};
/**************************************************************/