popcap sexyframework - Demo5 键盘输入 对话框 滑动条 设置音量

//board.h

#ifndef __BOARD_H__
#define __BOARD_H__
 

#include "SexyAppFramework/Widget.h"
#include "SexyAppFramework/ButtonListener.h"
 
#include "SexyAppFramework/EditListener.h"
#include "SexyAppFramework/CheckboxListener.h"
#include "SexyAppFramework/ListListener.h"
 


class Graphics;
class GameApp;
class ButtonWidget;
class WidgetManager;
class Image;

//定义视差层结构体
struct ParallaxLayer
{
 float  mX;
 float  mY;
 Image*  mImage;
};


class Board : public Widget, public ButtonListener
{
  GameApp*   mApp;
  ButtonWidget*  mButton;

  // 使用3层图片 (即一些背景靠前一些背景靠后. 移动的时候前边的背景移动较快)
  struct ParallaxLayer mLayer[3];  

 public: 
  enum { OPTIONS_BUTTON_ID };

  Board(GameApp* theApp);
  virtual ~Board();  

  //
  // 当有键盘键按下时调用. 
  virtual void KeyDown(KeyCode theKey);
  //
  // 它和KeyDown()不同. 它只能处理 ascii 输入 
  //virtual void KeyChar(char theChar);
 
  virtual void Draw(Graphics* g); 
  virtual void Update();  
  virtual void ButtonDepress(int theId);  
  virtual void AddedToManager(WidgetManager* theWidgetManager); 
  virtual void RemovedFromManager(WidgetManager* theWidgetManager);
   
};

 

#endif // __BOARD_H__

//gameapp.h

#ifndef __GAMEAPP_H__
#define __GAMEAPP_H__

#include "SexyAppFramework/SexyAppBase.h"


 class Board; 
 class TitleScreen; 
 class Dialog;

class GameApp : public SexyAppBase
{
  Board*   mBoard;
  TitleScreen* mTitleScreen;

 public:

  GameApp();
  virtual ~GameApp();
  virtual void Init(); 
  virtual void LoadingThreadProc();
  virtual void LoadingThreadCompleted(); 
  void TitleScreenIsFinished();


  //  
  //我们经常需要调用基类的 SexyAppBase::DoDialog() 来创建对话框. 
  //而后者会调用虚函数 NewDialog(). 我们在此重写 NewDialog() 使其调用我们重写版的. 
  //这样我们可以在其中指定对话框的通用的皮肤等.
  //该参数的意义参照 Dialog()构造函数的后几个参数.
  virtual Dialog* NewDialog(int theDialogId, bool isModal, const std::string& theDialogHeader, 
        const std::string& theDialogLines, const std::string& theDialogFooter, int theButtonMode);
 
  //  
  // 基类的函数. 用来设置是否3D 以及 是否全屏.
  // 本例中我们在对话框中用一个单选框来设置/记录是否全屏. 
  // 但有这样一种可能: 该对话框显示的时候用户按 ALT+ENTER 来使程序全屏模式运行. 
  // 而这时对话框中的单选按钮的状态还没有被改变. 这就是要改写该函数的原因.
  virtual void SwitchScreenMode(bool wantWindowed, bool is3d);
 
  virtual void ButtonPress(int theId);

  //
  // 自定义的函数. 用来使 Board 部件获得焦点.
  void SetFocusToBoard();
};
 

#endif // __GAMEAPP_H__

//demoDialog.h

//
//    DemoDialog.h
// 这里示范如何自定义一个对话框. 
// (如果是简单的 Yes/No/OK 消息框. 
//  则只要重写app类的 NewDialog()并在需要的时候调用app的DoDialog()就可以了.
//  不必这么麻烦. )
//

#ifndef __DEMO_DIALOG_H__
#define __DEMO_DIALOG_H__

#include "SexyAppFramework/Dialog.h"
#include "SexyAppFramework/SliderListener.h"
#include "SexyAppFramework/CheckboxListener.h"
 
class Graphics; 
// 滑动条部件. (这里用来控制音量).
class Slider;

// 使用DialogButton类而不是 ButtonWidget. 因为DialogButton可以自动使皮肤图片覆盖到按钮大小.
class DialogButton;
class Checkbox;

// 对话框从 Dialog 类派生.
class DemoDialog : public Dialog, public SliderListener, public CheckboxListener
{
  //对话框中包含的部件们
  Slider*   mMusicVolumeSlider;
  Slider*   mSfxVolumeSlider;
  DialogButton* mRandomBtn;    // 生成随机数按钮
  DialogButton* mClipBtn;    

 public:

  // 部件ID使用的常数
  enum{MUSIC_SLIDER_ID, SFX_SLIDER_ID, RANDOM_BTN_ID, CLIP_BTN_ID, FS_CHECKBOX_ID, HARDWARE_CHECKBOX_ID, MESSAGE_BOX_ID, DIALOG_ID};

  Checkbox*  m3DCheckbox;   // 3D效果
  Checkbox*  mFSCheckbox;   // 全屏效果

 
 public:
  // 构造 
  // 参数为 对话框的标题字符串. 对话框中的文字(文字可以换行).
  DemoDialog(std::string theHeader, std::string theBody);
  virtual ~DemoDialog();
 
  // 重写基类的函数
  virtual void Draw(Graphics* g); 
  virtual void Update();
  
  virtual void ButtonDepress(int theId); 
  virtual void AddedToManager(WidgetManager* theWidgetManager); 
  virtual void RemovedFromManager(WidgetManager* theWidgetManager);

  // 改变对话框大小时. 会调用该函数. 我们需要在此布局自定义对话框包含的部件们.
  virtual void Resize(int theX, int theY, int theWidth, int theHeight);

  //
  // 滑动条部件有操作时. 会调用它来处理.
  // 参数为 滑动条的ID, 当前值(从0到最大值).
  virtual void SliderVal(int theId, double theVal);

  //
  // 单选框事件处理函数
  void CheckboxChecked(int theId, bool checked);
};

 

#endif

// board.cpp

#include "Board.h"
#include "GameApp.h"

// Contains all the resources from the resources.xml file in our
// properties directory. See that file for more information.
#include "Res.h"
 
#include "SexyAppFramework/Graphics.h"
#include "SexyAppFramework/Color.h"
#include "SexyAppFramework/Rect.h"
#include "SexyAppFramework/ButtonWidget.h"
#include "SexyAppFramework/WidgetManager.h"
#include "SexyAppFramework/ImageFont.h"
#include "SexyAppFramework/Image.h"

// 本例子我们使用自定义的对话框类
#include "DemoDialog.h" 
 
// 下边演示如何检测内存泄漏.  在每个要检测的文件中加上下边2句. 
// 要注意的是这两句必须放在包含其他的头文件之后. 否则会产生编译/连接错误.
// 如果使用内存泄漏检测. 在程序结束时检测的结果会写入"mem_leaks.txt"文件.
#define SEXY_MEMTRACE
#include "SexyAppFramework/memmgr.h"

using namespace Sexy;
 
//
Board::Board(GameApp* theApp)
{
 mApp = theApp;  
 mButton = NULL;

 // 初始化3个视差层. 
 for (int i = 0; i < 3; i++)
 {
  mLayer[i].mX = 0;

  // 设置 mLayer[i] 的图片. 例如第一层的图片ID是 IMAGE_BG1, 第二层是IMAGE_BG2...

  std::string imageStringID = StrFormat("IMAGE_BG%d", i);
  // 把上边构造的字符串ID映射到对应的整数ID. 函数 GetIdByStringId() 我们定义在res.cpp中
  int id = GetIdByStringId(imageStringID.c_str()); 
  // 通过该ID取得对应的图片对象的指针. 函数GetImageById() 我们也定义在res.cpp中.
  mLayer[i].mImage = GetImageById(id);
 
  mLayer[i].mY = (float)(mApp->mHeight - mLayer[i].mImage->GetHeight());
 }

 // 故意泄漏一块内存. 做为测试用.
 int* aLeakedInteger = new int;
 
}
 
Board::~Board()
{
 delete mButton;
}
 
void Board::Update()
{   
 Widget::Update(); 
 MarkDirty(); 
}
 
void Board::KeyDown(KeyCode theKey)
{
 // 当按下左右箭头时. 水平移动这3个层. 但每个层移动的速度不同.
 if (theKey == KEYCODE_RIGHT)
 {
  for (int i = 0; i < 3; i++)
  { 
   mLayer[i].mX -= 1.0f * (i + 1);
   if (mLayer[i].mX <= -mLayer[i].mImage->GetWidth())
    mLayer[i].mX = 0;
  }
 }
 else if (theKey == KEYCODE_LEFT)
 {
  for (int i = 0; i < 3; i++)
  { 
   mLayer[i].mX += 1.0f * (i + 1);
   if (mLayer[i].mX >= mLayer[i].mImage->GetWidth())
    mLayer[i].mX = 0;
  }
 }
}
 
void Board::Draw(Graphics* g)
{  
 g->SetColor(Color(0, 0, 0));
 g->FillRect(0, 0, mWidth, mHeight);


 for (int i = 0; i < 3; i++)
 {
  int imgWidth = mLayer[i].mImage->GetWidth();

  
  // 设置新的绘制原点. 则绘制函数使用的(x,y)都是对这个点的偏移值.
  g->TranslateF(mLayer[i].mX, mLayer[i].mY);
 
  // 根据是否有3D加速. 使用不同的绘制函数.
  if (mApp->Is3DAccelerated())
  {  
   g->DrawImageF(mLayer[i].mImage, (float)-imgWidth, 0.0f);
   g->DrawImageF(mLayer[i].mImage, 0.0f, 0.0f);
   g->DrawImageF(mLayer[i].mImage, (float)imgWidth, 0.0f);
  }
  else
  { 
   g->DrawImage(mLayer[i].mImage, -imgWidth, 0);
   g->DrawImage(mLayer[i].mImage, 0, 0);
   g->DrawImage(mLayer[i].mImage, imgWidth, 0);
  }

  // 将绘制原点移动回来..
  g->TranslateF(-mLayer[i].mX, -mLayer[i].mY);
 } 
} 
 
void Board::AddedToManager(WidgetManager* theWidgetManager)
{ 
 Widget::AddedToManager(theWidgetManager);
 
 mButton = new ButtonWidget(Board::OPTIONS_BUTTON_ID, this); 
 mButton->SetFont(FONT_DEFAULT);
 mButton->mLabel = _S("Click Me!");
 
 // 这次我们为按钮带点皮肤.
 mButton->mOverImage = IMAGE_BUTTON_OVER;      // 鼠标经过图片
 mButton->mDownImage = IMAGE_BUTTON_DOWN;      // 按钮按下图片
 mButton->mButtonImage = IMAGE_BUTTON_NORMAL;  // 正常按钮图片
 mButton->mDoFinger = true;  //允许鼠标移上时鼠标变为手形.
 mButton->Resize(56, 5, IMAGE_BUTTON_NORMAL->GetWidth(), IMAGE_BUTTON_NORMAL->GetHeight());

 theWidgetManager->AddWidget(mButton);
}
 
//
void Board::RemovedFromManager(WidgetManager* theWidgetManager)
{ 
 Widget::RemovedFromManager(theWidgetManager); 
 theWidgetManager->RemoveWidget(mButton);
}
 
//
void Board::ButtonDepress(int theId)
{  
 if (theId == Board::OPTIONS_BUTTON_ID)
 { 
  // 创建自定义的对话框.
  DemoDialog* dlg = new DemoDialog("Header", "Hello! I am a dialog box.");
  dlg->Resize(50, 50, 300, 400);
  // 对于对话框. 我们不把它加入 WidgetManager. 而是调用如下函数:
  mApp->AddDialog(DemoDialog::DIALOG_ID, dlg);
 }
}

//gameapp.cpp


#include "GameApp.h"
#include "TitleScreen.h"
#include "Board.h"
#include "DemoDialog.h"
#include "SexyAppFramework/WidgetManager.h"

#include "SexyAppFramework/Checkbox.h"

// We will be accessing the resource manager in this demo, so include it's header
#include "SexyAppFramework/ResourceManager.h"

// Required for playing music
#include "SexyAppFramework/BassMusicInterface.h"

// Contains all the resources from the resources.xml file in our
// properties directory. See that file for more information.
#include "Res.h"

#include "SexyAppFramework/Dialog.h" 
using namespace Sexy;


//
//
GameApp::GameApp()
{ 
 mProdName = "Demo 5"; 
 mProductVersion = "1.0"; 
 mTitle = StringToSexyStringFast("SexyAppFramework: " + mProdName + " - " + mProductVersion); 
 mRegKey = "PopCap\SexyAppFramework\Demo5";

 mWidth = 640;
 mHeight = 480;
 
 mAutoEnable3D = true;

 mBoard = NULL;
 mTitleScreen = NULL; 
}
 
//
GameApp::~GameApp()
{ 
 if (mBoard != NULL)
  mWidgetManager->RemoveWidget(mBoard); 
 delete mBoard;

 if (mTitleScreen != NULL)
  mWidgetManager->RemoveWidget(mTitleScreen);
 delete mTitleScreen;
 
 mResourceManager->DeleteResources("Init");
 mResourceManager->DeleteResources("TitleScreen");
 mResourceManager->DeleteResources("Game"); 
}
 
//
void GameApp::Init()
{ 
 SexyAppBase::Init();

 //加载资源.


 LoadResourceManifest();
 
 if (!mResourceManager->LoadResources("Init"))
 {
  mLoadingFailed = true;
  // 显示资源加载失败信息
  ShowResourceError(true);
  return;
 }
 
 if (!ExtractInitResources(mResourceManager))
 {
  mLoadingFailed = true;
  ShowResourceError(true);
  return;
 }
 
 if (!mResourceManager->LoadResources("TitleScreen"))
 {
  mLoadingFailed = true;
  ShowResourceError(true);
  return;
 }

 if (!ExtractTitleScreenResources(mResourceManager))
 {
  mLoadingFailed = true;
  ShowResourceError(true);
  return;
 }

 // 开始前导屏幕
 mTitleScreen = new TitleScreen(this);
 mTitleScreen->Resize(0, 0, mWidth, mHeight); 
 mTitleScreen->Init(); 
 mWidgetManager->AddWidget(mTitleScreen);

 mMusicInterface->LoadMusic(0, "music/music.mo3");
 mMusicInterface->LoadMusic(1, "music/music.mo3");
 mMusicInterface->FadeIn(0, 0, 0.002, false);


 mNumLoadingThreadTasks = mResourceManager->GetNumResources("Game");
}

// 
void GameApp::LoadingThreadProc()
{ 
 // 加载资源
 mResourceManager->StartLoadResources("Game");

 while (mResourceManager->LoadNextResource())
 { 
  mCompletedLoadingThreadTasks++; 
  if (mShutdown)
   return;

  mTitleScreen->MarkDirty();
 }
 
 if (mResourceManager->HadError() || !ExtractGameResources(mResourceManager))
 {  
  ShowResourceError(false);
  mLoadingFailed = true;
  return;
 }
 
}

// 
void GameApp::LoadingThreadCompleted()
{ 
 SexyAppBase::LoadingThreadCompleted();
 
 if (mLoadingFailed)
  return;
 
 mTitleScreen->LoadingComplete(); 
 mTitleScreen->MarkDirty();
}
 
//
void GameApp::TitleScreenIsFinished()
{
 // 结束前导屏幕. 开始 board部件.
 mTitleScreen = NULL;
 mBoard = new Board(this);

 // 释放前导屏幕使用的资源
 mResourceManager->DeleteResources("TitleScreen");

 mBoard->Resize(0, 0, mWidth, mHeight);
 mWidgetManager->AddWidget(mBoard);

 // 使输入焦点放在 mBoard 上. 
 mWidgetManager->SetFocus(mBoard);

 // 淡出声音0.淡入声音1.
 mMusicInterface->FadeOut(0, true, 0.004); 
 mMusicInterface->FadeIn(1, 9, 0.002, false); 
}
 
//
// 改写基类的NewDialog()函数
// 这个函数会被基类的 DoDialog() 调用. 在这里我们可以设置对话框通用一些特征. 例如皮肤. 字体. 大小等.
Dialog* GameApp::NewDialog(int theDialogId, bool isModal, const std::string& theDialogHeader, 
         const std::string& theDialogLines, const std::string& theDialogFooter, int theButtonMode)
{
 // 下边的 Dialog() 构造函数指定了对话框皮肤和按钮皮肤. 这样我们以后使用 YES/NO 对话框时就自动拥有这些皮肤了.
 Dialog* d = new Dialog(IMAGE_DIALOG_BOX, IMAGE_DIALOG_BUTTON, theDialogId, isModal,
       StringToSexyStringFast(theDialogHeader), StringToSexyStringFast(theDialogLines), StringToSexyStringFast(theDialogFooter), theButtonMode);

 d->SetButtonFont(FONT_DEFAULT);
 d->SetLinesFont(FONT_DEFAULT);
 d->SetHeaderFont(FONT_DEFAULT);

 d->SetColor(Dialog::COLOR_HEADER, Color::Black);
 d->SetColor(Dialog::COLOR_LINES, Color::Black);

 d->mSpaceAfterHeader = 30;
 d->Resize(100, 100, 300, 250);

 return d;
}
 
//
// 在设置3D模式  全屏模式 时. 我们想干点其他事...
void GameApp::SwitchScreenMode(bool wantWindowed, bool is3d)
{ 
 SexyAppBase::SwitchScreenMode(wantWindowed, is3d);

 // 根据对话框ID得到对话框的指针. 这需要调用 SexyAppBase::GetDialog().
 DemoDialog* d = (DemoDialog*) GetDialog(DemoDialog::DIALOG_ID);

 // 即使用户通过Alt+Enter的办法切换全屏/窗口模式. 也应该使单选框 mFSCheckbox 的状态和它保持一致.
 if ((d != NULL) && (d->mFSCheckbox != NULL))
  d->mFSCheckbox->SetChecked(!wantWindowed);

}
 
//
void GameApp::ButtonPress(int theId)
{
 // 点对话框底部的按钮时. 关掉该对话框.
 if (theId == DemoDialog::MESSAGE_BOX_ID + 2000)
  KillDialog(theId - 2000);  //关闭对话框.
}
 
//
void GameApp::SetFocusToBoard()
{
 if (mBoard != NULL)
  mWidgetManager->SetFocus(mBoard);
}

//demoDialog.cpp

#include "DemoDialog.h"
#include "Res.h"
#include "GameApp.h"
#include "SexyAppFramework/SexyAppBase.h"
#include "SexyAppFramework/WidgetManager.h"
#include "SexyAppFramework/Font.h"
#include "SexyAppFramework/DialogButton.h"
#include "SexyAppFramework/Checkbox.h"
 
#include "SexyAppFramework/Slider.h"

using namespace Sexy;

// 
// 对话框的基类 Dialog 的构造函数参数:
//  对话框的外观图片 (本例中的图片在 images/dialog.gif)
//  对话框中按钮的图片(本例中的图片在 images/dialog_btn.gif)
//  对话框ID
//  是否模式对话框
//  对话框顶部文字
//  对话框中间文字(可以用 \n 分行)
//  如果允许最下部按钮( 即下一个参数是 Dialog::BUTTONS_FOOTER ). 这个参数是按钮上的文字. 
//  最后一个参数是对话框带的默认按钮的风格: 可以是 
//   // BUTTONS_YES_NO    //YES按钮的ID为: ID_YES    //NO按钮的ID为: ID_NO
//   // BUTTONS_OK_CANCEL //OK按钮的ID为: ID_OK    //CANCEL按钮的ID为: ID_CANCEL
//   // BUTTONS_NONE(没有默认按钮)
//   // BUTTONS_FOOTER(对话框底部有一个按钮).    //该按钮的ID为 ID_FOOTER 
//
DemoDialog::DemoDialog(std::string theHeader, std::string theBody) :
Dialog(IMAGE_DIALOG_BOX, IMAGE_DIALOG_BUTTON, DemoDialog::DIALOG_ID, true, StringToSexyStringFast(theHeader), StringToSexyStringFast(theBody), _S("CLOSE"), Dialog::BUTTONS_FOOTER)
{
 // 为对话框设置一个区域. 其中所有的文本/按钮等等都会被调整到该区域内.
 mContentInsets = Insets(23, 20, 23, 20);  // Insets()的参数表示区域到四边的距离

 // 设置对话框中间的文字(参数theBody) 显示时距离标题栏的距离 
 mSpaceAfterHeader = 30;

 // 设置对话框的 标题字体.  中间文字的字体.  按钮的字体.
 SetHeaderFont(FONT_DEFAULT);
 SetLinesFont(FONT_DEFAULT);
 SetButtonFont(FONT_DEFAULT);

 // 设置对话框使用的一些颜色.
 SetColor(COLOR_HEADER, Color::Black);
 SetColor(COLOR_LINES, Color::Black);
 
 // 创建滑动条部件. Slider的构造函数参数分别是:
 //  滑动路径图片.  滑块图片.  本部件ID,   监听者
 mMusicVolumeSlider = new Slider(IMAGE_SLIDER_TRACK, IMAGE_SLIDER_THUMB, DemoDialog::MUSIC_SLIDER_ID, this);
 
 // 设置滑块的当前位置值(范围在0.0 - 1.0 之间). 这里我们设置为当前的音量. 
 // 获取当前音量用 SexyAppBase::GetMusicVolume() 函数. 
 mMusicVolumeSlider->SetValue(gSexyAppBase->GetMusicVolume()); //对话框部件没有保存App的指针. 但可以使用声明在SexyAppBase.h文件的 gSexyAppBase

 // 另一个滑动条部件
 mSfxVolumeSlider = new Slider(IMAGE_SLIDER_TRACK, IMAGE_SLIDER_THUMB, DemoDialog::SFX_SLIDER_ID, this); 
 mSfxVolumeSlider->SetValue(gSexyAppBase->GetSfxVolume());

 // 创建按钮.  使用 DialogButton 类 而不是它的父类 ButtonWidget.
 // 构造函数参数为:   按钮图片.  按钮ID.  监听器
 mRandomBtn = new DialogButton(IMAGE_DIALOG_BUTTON, DemoDialog::RANDOM_BTN_ID, this);
 mRandomBtn->mLabel = _S("Random #");
 mRandomBtn->SetFont(FONT_DEFAULT);
 
 mClipBtn = new DialogButton(IMAGE_DIALOG_BUTTON, DemoDialog::CLIP_BTN_ID, this);
 mClipBtn->mLabel = _S("Clipping");
 mClipBtn->SetFont(FONT_DEFAULT);

 m3DCheckbox = new Checkbox(IMAGE_CHECKBOX, IMAGE_CHECKBOX, DemoDialog::HARDWARE_CHECKBOX_ID, this);
 mFSCheckbox = new Checkbox(IMAGE_CHECKBOX, IMAGE_CHECKBOX, DemoDialog::FS_CHECKBOX_ID, this);
}

//
//
DemoDialog::~DemoDialog()
{
 delete mMusicVolumeSlider;
 delete mSfxVolumeSlider;
 delete mRandomBtn;
 delete mClipBtn;
 delete m3DCheckbox;
 delete mFSCheckbox;
}

// 
void DemoDialog::Draw(Graphics* g)
{
 Dialog::Draw(g);
 
 // 绘制几个文字.
 g->SetFont(FONT_DEFAULT);
 g->SetColor(Color::Black); 
 g->DrawString(_S("Music volume:"), mMusicVolumeSlider->mX - mX, 
   mMusicVolumeSlider->mY - mY - mMusicVolumeSlider->mHeight);
 g->DrawString(_S("Sound volume:"), mSfxVolumeSlider->mX - mX, 
   mSfxVolumeSlider->mY - mY - mSfxVolumeSlider->mHeight);
 g->DrawString(_S("3D Mode:"), m3DCheckbox->mX - mX, m3DCheckbox->mY - mY - m3DCheckbox->mHeight + 20);
 g->DrawString(_S("Full Screen:"), mFSCheckbox->mX - mX, mFSCheckbox->mY - mY - mFSCheckbox->mHeight + 20);

 // 在对话框的矩形区域之外绘制一点东西.
 // 但只有当基类的 mClip 成员被设置时这些东西才能真正绘制到屏幕上. 
 g->SetColor(Color(255, 0, 0, 128));  
 g->FillRect(mWidth, mHeight, 100, 100); 
 g->FillRect(-100, -100, 100, 100);
 g->SetColor(Color::Black);
 g->DrawString(_S("Top left"), -90, -20);
 g->DrawString(_S("Bottom right"), mWidth + 10, mHeight + 20);
}

// 
void DemoDialog::Update()
{
 Dialog::Update();
}

 
//
void DemoDialog::AddedToManager(WidgetManager* theWidgetManager)
{
 Dialog::AddedToManager(theWidgetManager);
 theWidgetManager->AddWidget(mMusicVolumeSlider);
 theWidgetManager->AddWidget(mSfxVolumeSlider);
 theWidgetManager->AddWidget(mRandomBtn);
 theWidgetManager->AddWidget(mClipBtn);

 int checkWidth = IMAGE_CHECKBOX->GetWidth() / 2;
 m3DCheckbox->mUncheckedRect = Rect(0, 0, checkWidth, IMAGE_CHECKBOX->GetHeight());
 m3DCheckbox->mCheckedRect = Rect(checkWidth, 0, checkWidth, IMAGE_CHECKBOX->GetHeight());

 mFSCheckbox->mUncheckedRect = Rect(0, 0, checkWidth, IMAGE_CHECKBOX->GetHeight());
 mFSCheckbox->mCheckedRect = Rect(checkWidth, 0, checkWidth, IMAGE_CHECKBOX->GetHeight());
  
 m3DCheckbox->mChecked = gSexyAppBase->Is3DAccelerated();
  
 mFSCheckbox->mChecked = !gSexyAppBase->mIsWindowed;

 theWidgetManager->AddWidget(m3DCheckbox);
 theWidgetManager->AddWidget(mFSCheckbox);
}

//
//
void DemoDialog::RemovedFromManager(WidgetManager* theWidgetManager)
{
 Dialog::RemovedFromManager(theWidgetManager);
 theWidgetManager->RemoveWidget(mMusicVolumeSlider);
 theWidgetManager->RemoveWidget(mSfxVolumeSlider);
 theWidgetManager->RemoveWidget(mRandomBtn);
 theWidgetManager->RemoveWidget(mClipBtn);
 theWidgetManager->RemoveWidget(m3DCheckbox);
 theWidgetManager->RemoveWidget(mFSCheckbox);
}

//
//设置对话框大小时改变它的部件的布局.
void DemoDialog::Resize(int theX, int theY, int theWidth, int theHeight)
{
 Dialog::Resize(theX, theY, theWidth, theHeight);  //先调用基类的Resize()
 
 // 调整每个部件的位置/大小. 使其适应对话框的 mContentInsets 区域.
 mMusicVolumeSlider->Resize(theX + mContentInsets.mLeft, 
        theY + 140,
        mWidth - mContentInsets.mLeft - mContentInsets.mRight,
        IMAGE_SLIDER_THUMB->GetHeight());
 
 // 用另一种方法布局部件.
 // 这里设置第二个滑动条部件. 它和 mMusicVolumeSlider 的x坐标.宽度.高度一样. 只是Y坐标低一些. 
 // 所以这里根据 mMusicVolumeSlider 的位置来布局它.
 mSfxVolumeSlider->Layout(LAY_SameLeft | LAY_Below | LAY_SameWidth | LAY_SameHeight, 
        mMusicVolumeSlider, 0, 40, 0, 0);

 // 同样. 根据 mSfxVolumeSlider 的位置布局 mRandomBtn.
 mRandomBtn->Layout(LAY_SameLeft | LAY_SameTop, mSfxVolumeSlider, 0, 40, 0, 0);
 mRandomBtn->Resize(mRandomBtn->mX, mRandomBtn->mY, 
      mSfxVolumeSlider->mWidth / 2, IMAGE_DIALOG_BUTTON->mHeight);

 // 再根据 mRandomBtn 的位置和 对话框mContentInsets的区域边界来调整 mClipBtn 部件的位置.
 mClipBtn->Layout(LAY_Right | LAY_SameTop | LAY_SameWidth | LAY_SameHeight,
      mRandomBtn, 0, 0, 0, 0);

 //布局两个单选框
 m3DCheckbox->Layout(LAY_SameLeft | LAY_Below, mRandomBtn, 0, 40, 0, 0);
 m3DCheckbox->Resize(m3DCheckbox->mX, m3DCheckbox->mY,
      IMAGE_CHECKBOX->mWidth / 2, IMAGE_CHECKBOX->mHeight); 
 mFSCheckbox->Layout(LAY_SameTop | LAY_SameWidth | LAY_SameHeight, m3DCheckbox);
 mFSCheckbox->Layout(LAY_SameLeft, mClipBtn);

}

//
//处理滑动条事件
void DemoDialog::SliderVal(int theId, double theVal)
{
 if (theId == DemoDialog::MUSIC_SLIDER_ID)
 {
  gSexyAppBase->SetMusicVolume(theVal);
 }
 else if (theId == DemoDialog::SFX_SLIDER_ID)
 {
  gSexyAppBase->SetSfxVolume(theVal);

  // 当用户鼠标释放滑块时播放提示音.
  if (!mSfxVolumeSlider->mDragging)
   gSexyAppBase->PlaySample(SOUND_TIMER);
 }
}
 
//
void DemoDialog::ButtonDepress(int theId)
{
 Dialog::ButtonDepress(theId);

 if (theId == mRandomBtn->mId)   //按钮的ID记录在 ButtonWidget::mID .
 {
  // 点击 Random 按钮时. 生成一个随机整数. 
  int r = Rand();

  // 并设置 该整数串做为对话框的 中间文字.
  // 可以看出. 修改对话框的中的文字很容易. 只要修改 mDialogLines 成员即可.
  mDialogLines = StrFormat(_S("Random number: %d"), r); 
 }
 else if (theId == mClipBtn->mId)
 { 
  // 点击这个按钮时我们设置基类的 mClip 成员(该成员声明在WidgetContainer类中). 
  // 当 mClip 关闭时我们可以在该部件的矩形区域之外绘制. 
  mClip = !mClip;
  if (mClip)
   mClipBtn->mLabel = _S("Clipping");
  else
   mClipBtn->mLabel = _S("No clipping");
 }

 else if (theId == ID_YES)
 { 
  // 点击这个按钮将要关闭对话框. 在这里我们使用户的设置生效.
  // 调用 app 的 SwitchScreenMode() 可以设置全屏/窗口模式. 以及是否3D.
  gSexyAppBase->SwitchScreenMode(!mFSCheckbox->mChecked, m3DCheckbox->mChecked);
  
  // 关掉对话框.
  gSexyAppBase->KillDialog(this);
 
  ((GameApp*)gSexyAppBase)->SetFocusToBoard();  //设置焦点
 }
 
}

//
// 处理单选框事件
void DemoDialog::CheckboxChecked(int theId, bool checked)
{ 
 if (theId == m3DCheckbox->mId)
 {
  if (checked)
  { 
   if (!gSexyAppBase->Is3DAccelerationSupported())
   {
    //如果3D不被支持. 则不设置该单选框. 并弹出一个对话框通知用户.
    m3DCheckbox->SetChecked(false);

    //调用 SexyAppBase::DoDialog() 来创建对话框. 
    //这个函数将调用 NewDialog() 来创建对话框. 而NewDialog()调用的是我们重写版的. 我们在其中指定了对话框的通用的皮肤等.
    //参数的意义参照 Dialog()构造函数的后几个参数.
    gSexyAppBase->DoDialog(DemoDialog::MESSAGE_BOX_ID, true, _S("Not Supported"), 
       _S("Hardware acceleration can not be enabled on this computer. \nYour\
       video card does not meet the minimum requirements for this game."),
       _S("OK"), Dialog::BUTTONS_FOOTER);
   }
   else if(!gSexyAppBase->Is3DAccelerationRecommended())
   { 
    gSexyAppBase->DoDialog(DemoDialog::MESSAGE_BOX_ID, true, _S("Warning"), 
     _S("Your video card may not fully support this feature.\n\
     If you experience slower performance, please disable Hardware Acceleration."),
     _S("OK"), Dialog::BUTTONS_FOOTER);
   }
   
  }
 }
 else if (theId == mFSCheckbox->mId)
 { 
  if (gSexyAppBase->mForceFullscreen && !checked)
  {
   gSexyAppBase->DoDialog(DemoDialog::MESSAGE_BOX_ID, true, _S("No Windowed Mode"),
   _S("Windowed mode is only available if your desktop is running in\n\
   either 16 bit or 32 bit color mode, which it is not."), _S("OK"), Dialog::BUTTONS_FOOTER);
 
   mFSCheckbox->SetChecked(true);
  }
 }
}

//main.cpp

//
// 本例子学习:
//
// * Drawing differently if 3D or 2D
// * Using Translate instead of using XYs
// * 键盘输入. 设置输入焦点.
// * 学习新的部件: 对话框. 滑动条. 
// * Advanced widget topics: mClip, using Layout_ flags, using images
// * 设置3D模式. 全屏模式. 设置音量.
// * Parallax scrolling
// * 随机数
// * 检测内存泄漏
// * Profiling
//

#include "GameApp.h"
 
using namespace Sexy;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{  
 gHInstance = hInstance; 
 GameApp* anApp = new GameApp();
 anApp->Init(); 
 anApp->Start();

 delete anApp;

 return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值