mirror of https://github.com/axmolengine/axmol.git
1085 lines
34 KiB
C++
1085 lines
34 KiB
C++
|
|
#pragma comment(lib, "comctl32.lib")
|
|
#pragma comment(linker, "\"/manifestdependency:type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
|
|
|
#include "stdafx.h"
|
|
#include <io.h>
|
|
#include <stdlib.h>
|
|
#include <malloc.h>
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <Commdlg.h>
|
|
#include <Shlobj.h>
|
|
#include <winnls.h>
|
|
#include <shobjidl.h>
|
|
#include <objbase.h>
|
|
#include <objidl.h>
|
|
#include <shlguid.h>
|
|
#include <shellapi.h>
|
|
#include <Winuser.h>
|
|
|
|
#include "SimulatorWin.h"
|
|
|
|
#include "glfw3.h"
|
|
#include "glfw3native.h"
|
|
|
|
#include "AppEvent.h"
|
|
#include "AppLang.h"
|
|
#include "runtime/ConfigParser.h"
|
|
#include "runtime/Runtime.h"
|
|
|
|
#include "platform/win32/PlayerWin.h"
|
|
#include "platform/win32/PlayerMenuServiceWin.h"
|
|
|
|
#include "resource.h"
|
|
|
|
USING_NS_CC;
|
|
|
|
static WNDPROC g_oldWindowProc = NULL;
|
|
INT_PTR CALLBACK AboutDialogCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LOGFONT lf;
|
|
HFONT hFont;
|
|
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
ZeroMemory(&lf, sizeof(LOGFONT));
|
|
lf.lfHeight = 24;
|
|
lf.lfWeight = 200;
|
|
_tcscpy(lf.lfFaceName, _T("Arial"));
|
|
|
|
hFont = CreateFontIndirect(&lf);
|
|
if ((HFONT)0 != hFont)
|
|
{
|
|
SendMessage(GetDlgItem(hDlg, IDC_ABOUT_TITLE), WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE);
|
|
}
|
|
return (INT_PTR)TRUE;
|
|
|
|
case WM_COMMAND:
|
|
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
|
|
{
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
return (INT_PTR)TRUE;
|
|
}
|
|
break;
|
|
}
|
|
return (INT_PTR)FALSE;
|
|
}
|
|
void onHelpAbout()
|
|
{
|
|
DialogBox(GetModuleHandle(NULL),
|
|
MAKEINTRESOURCE(IDD_DIALOG_ABOUT),
|
|
Director::getInstance()->getOpenGLView()->getWin32Window(),
|
|
AboutDialogCallback);
|
|
}
|
|
|
|
void shutDownApp()
|
|
{
|
|
auto glview = dynamic_cast<GLViewImpl*> (Director::getInstance()->getOpenGLView());
|
|
HWND hWnd = glview->getWin32Window();
|
|
::SendMessage(hWnd, WM_CLOSE, NULL, NULL);
|
|
}
|
|
|
|
std::string getCurAppPath(void)
|
|
{
|
|
TCHAR szAppDir[MAX_PATH] = {0};
|
|
if (!GetModuleFileName(NULL, szAppDir, MAX_PATH))
|
|
return "";
|
|
int nEnd = 0;
|
|
for (int i = 0; szAppDir[i]; i++)
|
|
{
|
|
if (szAppDir[i] == '\\')
|
|
nEnd = i;
|
|
}
|
|
szAppDir[nEnd] = 0;
|
|
int iLen = 2 * wcslen(szAppDir);
|
|
char* chRtn = new char[iLen + 1];
|
|
wcstombs(chRtn, szAppDir, iLen + 1);
|
|
std::string strPath = chRtn;
|
|
delete[] chRtn;
|
|
chRtn = NULL;
|
|
char fuldir[MAX_PATH] = {0};
|
|
_fullpath(fuldir, strPath.c_str(), MAX_PATH);
|
|
return fuldir;
|
|
}
|
|
|
|
static bool stringEndWith(const std::string str, const std::string needle)
|
|
{
|
|
if (str.length() >= needle.length())
|
|
{
|
|
return (0 == str.compare(str.length() - needle.length(), needle.length(), needle));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void initGLContextAttrs()
|
|
{
|
|
//set OpenGL context attributions,now can only set six attributions:
|
|
//red,green,blue,alpha,depth,stencil
|
|
GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8};
|
|
|
|
GLView::setGLContextAttrs(glContextAttrs);
|
|
}
|
|
|
|
SimulatorWin *SimulatorWin::_instance = nullptr;
|
|
|
|
SimulatorWin *SimulatorWin::getInstance()
|
|
{
|
|
if (!_instance)
|
|
{
|
|
_instance = new SimulatorWin();
|
|
}
|
|
return _instance;
|
|
}
|
|
|
|
SimulatorWin::SimulatorWin()
|
|
: _app(nullptr)
|
|
, _hwnd(NULL)
|
|
, _hwndConsole(NULL)
|
|
, _writeDebugLogFile(nullptr)
|
|
{
|
|
}
|
|
|
|
SimulatorWin::~SimulatorWin()
|
|
{
|
|
CC_SAFE_DELETE(_app);
|
|
if (_writeDebugLogFile)
|
|
{
|
|
fclose(_writeDebugLogFile);
|
|
}
|
|
}
|
|
|
|
void SimulatorWin::quit()
|
|
{
|
|
Director::getInstance()->end();
|
|
}
|
|
|
|
void SimulatorWin::relaunch()
|
|
{
|
|
_project.setWindowOffset(Vec2(getPositionX(), getPositionY()));
|
|
openNewPlayerWithProjectConfig(_project);
|
|
|
|
quit();
|
|
}
|
|
|
|
void SimulatorWin::openNewPlayer()
|
|
{
|
|
openNewPlayerWithProjectConfig(_project);
|
|
}
|
|
|
|
void SimulatorWin::openNewPlayerWithProjectConfig(const ProjectConfig &config)
|
|
{
|
|
static long taskid = 100;
|
|
stringstream buf;
|
|
buf << taskid++;
|
|
|
|
string commandLine;
|
|
commandLine.append(getApplicationExePath());
|
|
commandLine.append(" ");
|
|
commandLine.append(config.makeCommandLine());
|
|
|
|
CCLOG("SimulatorWin::openNewPlayerWithProjectConfig(): %s", commandLine.c_str());
|
|
|
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx
|
|
SECURITY_ATTRIBUTES sa = {0};
|
|
sa.nLength = sizeof(sa);
|
|
|
|
PROCESS_INFORMATION pi = {0};
|
|
STARTUPINFO si = {0};
|
|
si.cb = sizeof(STARTUPINFO);
|
|
|
|
#define MAX_COMMAND 1024 // lenth of commandLine is always beyond MAX_PATH
|
|
|
|
WCHAR command[MAX_COMMAND];
|
|
memset(command, 0, sizeof(command));
|
|
MultiByteToWideChar(CP_UTF8, 0, commandLine.c_str(), -1, command, MAX_COMMAND);
|
|
|
|
BOOL success = CreateProcess(NULL,
|
|
command, // command line
|
|
NULL, // process security attributes
|
|
NULL, // primary thread security attributes
|
|
FALSE, // handles are inherited
|
|
0, // creation flags
|
|
NULL, // use parent's environment
|
|
NULL, // use parent's current directory
|
|
&si, // STARTUPINFO pointer
|
|
&pi); // receives PROCESS_INFORMATION
|
|
|
|
if (!success)
|
|
{
|
|
CCLOG("PlayerTaskWin::run() - create process failed, for execute %s", commandLine.c_str());
|
|
}
|
|
}
|
|
|
|
void SimulatorWin::openProjectWithProjectConfig(const ProjectConfig &config)
|
|
{
|
|
openNewPlayerWithProjectConfig(config);
|
|
quit();
|
|
}
|
|
|
|
int SimulatorWin::getPositionX()
|
|
{
|
|
RECT rect;
|
|
GetWindowRect(_hwnd, &rect);
|
|
return rect.left;
|
|
}
|
|
|
|
int SimulatorWin::getPositionY()
|
|
{
|
|
RECT rect;
|
|
GetWindowRect(_hwnd, &rect);
|
|
return rect.top;
|
|
}
|
|
|
|
int SimulatorWin::run()
|
|
{
|
|
INITCOMMONCONTROLSEX InitCtrls;
|
|
InitCtrls.dwSize = sizeof(InitCtrls);
|
|
InitCtrls.dwICC = ICC_WIN95_CLASSES;
|
|
InitCommonControlsEx(&InitCtrls);
|
|
|
|
parseCocosProjectConfig(_project);
|
|
|
|
// load project config from command line args
|
|
vector<string> args;
|
|
for (int i = 0; i < __argc; ++i)
|
|
{
|
|
wstring ws(__wargv[i]);
|
|
string s;
|
|
s.assign(ws.begin(), ws.end());
|
|
args.push_back(s);
|
|
}
|
|
_project.parseCommandLine(args);
|
|
|
|
if (_project.getProjectDir().empty())
|
|
{
|
|
if (args.size() == 2)
|
|
{
|
|
// for Code IDE before RC2
|
|
_project.setProjectDir(args.at(1));
|
|
_project.setDebuggerType(kCCRuntimeDebuggerCodeIDE);
|
|
}
|
|
}
|
|
|
|
// create the application instance
|
|
_app = new AppDelegate();
|
|
RuntimeEngine::getInstance()->setProjectConfig(_project);
|
|
|
|
// create console window
|
|
if (_project.isShowConsole())
|
|
{
|
|
AllocConsole();
|
|
_hwndConsole = GetConsoleWindow();
|
|
if (_hwndConsole != NULL)
|
|
{
|
|
ShowWindow(_hwndConsole, SW_SHOW);
|
|
BringWindowToTop(_hwndConsole);
|
|
freopen("CONOUT$", "wt", stdout);
|
|
freopen("CONOUT$", "wt", stderr);
|
|
|
|
HMENU hmenu = GetSystemMenu(_hwndConsole, FALSE);
|
|
if (hmenu != NULL)
|
|
{
|
|
DeleteMenu(hmenu, SC_CLOSE, MF_BYCOMMAND);
|
|
}
|
|
}
|
|
}
|
|
|
|
// log file
|
|
if (_project.isWriteDebugLogToFile())
|
|
{
|
|
const string debugLogFilePath = _project.getDebugLogFilePath();
|
|
_writeDebugLogFile = fopen(debugLogFilePath.c_str(), "w");
|
|
if (!_writeDebugLogFile)
|
|
{
|
|
CCLOG("Cannot create debug log file %s", debugLogFilePath.c_str());
|
|
}
|
|
}
|
|
|
|
// set environments
|
|
SetCurrentDirectoryA(_project.getProjectDir().c_str());
|
|
FileUtils::getInstance()->setDefaultResourceRootPath(_project.getProjectDir());
|
|
FileUtils::getInstance()->setWritablePath(_project.getWritableRealPath().c_str());
|
|
|
|
// check screen DPI
|
|
HDC screen = GetDC(0);
|
|
int dpi = GetDeviceCaps(screen, LOGPIXELSX);
|
|
ReleaseDC(0, screen);
|
|
|
|
// set scale with DPI
|
|
// 96 DPI = 100 % scaling
|
|
// 120 DPI = 125 % scaling
|
|
// 144 DPI = 150 % scaling
|
|
// 192 DPI = 200 % scaling
|
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/dn469266%28v=vs.85%29.aspx#dpi_and_the_desktop_scaling_factor
|
|
//
|
|
// enable DPI-Aware with DeclareDPIAware.manifest
|
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/dn469266%28v=vs.85%29.aspx#declaring_dpi_awareness
|
|
float screenScale = 1.0f;
|
|
if (dpi >= 120 && dpi < 144)
|
|
{
|
|
screenScale = 1.25f;
|
|
}
|
|
else if (dpi >= 144 && dpi < 192)
|
|
{
|
|
screenScale = 1.5f;
|
|
}
|
|
else if (dpi >= 192)
|
|
{
|
|
screenScale = 2.0f;
|
|
}
|
|
CCLOG("SCREEN DPI = %d, SCREEN SCALE = %0.2f", dpi, screenScale);
|
|
|
|
// check scale
|
|
Size frameSize = _project.getFrameSize();
|
|
float frameScale = 1.0f;
|
|
if (_project.isRetinaDisplay())
|
|
{
|
|
frameSize.width *= screenScale;
|
|
frameSize.height *= screenScale;
|
|
}
|
|
else
|
|
{
|
|
frameScale = screenScale;
|
|
}
|
|
|
|
// check screen workarea
|
|
RECT workareaSize;
|
|
if (SystemParametersInfo(SPI_GETWORKAREA, NULL, &workareaSize, NULL))
|
|
{
|
|
float workareaWidth = fabsf(workareaSize.right - workareaSize.left);
|
|
float workareaHeight = fabsf(workareaSize.bottom - workareaSize.top);
|
|
float frameBorderCX = GetSystemMetrics(SM_CXSIZEFRAME);
|
|
float frameBorderCY = GetSystemMetrics(SM_CYSIZEFRAME);
|
|
workareaWidth -= frameBorderCX * 2;
|
|
workareaHeight -= (frameBorderCY * 2 + GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYMENU));
|
|
CCLOG("WORKAREA WIDTH %0.2f, HEIGHT %0.2f", workareaWidth, workareaHeight);
|
|
while (true && frameScale > 0.25f)
|
|
{
|
|
if (frameSize.width * frameScale > workareaWidth || frameSize.height * frameScale > workareaHeight)
|
|
{
|
|
frameScale = frameScale - 0.25f;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (frameScale < 0.25f) frameScale = 0.25f;
|
|
}
|
|
_project.setFrameScale(frameScale);
|
|
CCLOG("FRAME SCALE = %0.2f", frameScale);
|
|
|
|
// create opengl view
|
|
const Rect frameRect = Rect(0, 0, frameSize.width, frameSize.height);
|
|
ConfigParser::getInstance()->setInitViewSize(frameSize);
|
|
const bool isResize = _project.isResizeWindow();
|
|
std::stringstream title;
|
|
title << "Cocos Simulator (" << _project.getFrameScale() * 100 << "%)";
|
|
initGLContextAttrs();
|
|
auto glview = GLViewImpl::createWithRect(title.str(), frameRect, frameScale);
|
|
_hwnd = glview->getWin32Window();
|
|
player::PlayerWin::createWithHwnd(_hwnd);
|
|
DragAcceptFiles(_hwnd, TRUE);
|
|
//SendMessage(_hwnd, WM_SETICON, ICON_BIG, (LPARAM)icon);
|
|
//SendMessage(_hwnd, WM_SETICON, ICON_SMALL, (LPARAM)icon);
|
|
//FreeResource(icon);
|
|
|
|
// path for looking Lang file, Studio Default images
|
|
FileUtils::getInstance()->addSearchPath(getApplicationPath().c_str());
|
|
|
|
auto director = Director::getInstance();
|
|
director->setOpenGLView(glview);
|
|
|
|
director->setAnimationInterval(1.0 / 60.0);
|
|
|
|
// set window position
|
|
if (_project.getProjectDir().length())
|
|
{
|
|
setZoom(_project.getFrameScale());
|
|
}
|
|
Vec2 pos = _project.getWindowOffset();
|
|
if (pos.x != 0 && pos.y != 0)
|
|
{
|
|
RECT rect;
|
|
GetWindowRect(_hwnd, &rect);
|
|
if (pos.x < 0)
|
|
pos.x = 0;
|
|
if (pos.y < 0)
|
|
pos.y = 0;
|
|
MoveWindow(_hwnd, pos.x, pos.y, rect.right - rect.left, rect.bottom - rect.top, FALSE);
|
|
}
|
|
|
|
// init player services
|
|
setupUI();
|
|
DrawMenuBar(_hwnd);
|
|
|
|
// prepare
|
|
FileUtils::getInstance()->setPopupNotify(false);
|
|
_project.dump();
|
|
auto app = Application::getInstance();
|
|
|
|
g_oldWindowProc = (WNDPROC)SetWindowLong(_hwnd, GWL_WNDPROC, (LONG)SimulatorWin::windowProc);
|
|
|
|
// update window title
|
|
updateWindowTitle();
|
|
|
|
// startup message loop
|
|
return app->run();
|
|
}
|
|
|
|
// services
|
|
|
|
void SimulatorWin::setupUI()
|
|
{
|
|
auto menuBar = player::PlayerProtocol::getInstance()->getMenuService();
|
|
|
|
// FILE
|
|
menuBar->addItem("FILE_MENU", tr("File"));
|
|
menuBar->addItem("OPEN_FILE_MENU", tr("Open File") + "...", "FILE_MENU");
|
|
menuBar->addItem("OPEN_PROJECT_MENU", tr("Open Project") + "...", "FILE_MENU");
|
|
menuBar->addItem("FILE_MENU_SEP1", "-", "FILE_MENU");
|
|
menuBar->addItem("EXIT_MENU", tr("Exit"), "FILE_MENU");
|
|
|
|
// VIEW
|
|
menuBar->addItem("VIEW_MENU", tr("View"));
|
|
SimulatorConfig *config = SimulatorConfig::getInstance();
|
|
int current = config->checkScreenSize(_project.getFrameSize());
|
|
for (int i = 0; i < config->getScreenSizeCount(); i++)
|
|
{
|
|
SimulatorScreenSize size = config->getScreenSize(i);
|
|
std::stringstream menuId;
|
|
menuId << "VIEWSIZE_ITEM_MENU_" << i;
|
|
auto menuItem = menuBar->addItem(menuId.str(), size.title.c_str(), "VIEW_MENU");
|
|
|
|
if (i == current)
|
|
{
|
|
menuItem->setChecked(true);
|
|
}
|
|
}
|
|
|
|
// About
|
|
menuBar->addItem("HELP_MENU", tr("Help"));
|
|
menuBar->addItem("ABOUT_MENUITEM", tr("About"), "HELP_MENU");
|
|
|
|
menuBar->addItem("DIRECTION_MENU_SEP", "-", "VIEW_MENU");
|
|
menuBar->addItem("DIRECTION_PORTRAIT_MENU", tr("Portrait"), "VIEW_MENU")
|
|
->setChecked(_project.isPortraitFrame());
|
|
menuBar->addItem("DIRECTION_LANDSCAPE_MENU", tr("Landscape"), "VIEW_MENU")
|
|
->setChecked(_project.isLandscapeFrame());
|
|
|
|
menuBar->addItem("VIEW_SCALE_MENU_SEP", "-", "VIEW_MENU");
|
|
std::vector<player::PlayerMenuItem*> scaleMenuVector;
|
|
auto scale200Menu = menuBar->addItem("VIEW_SCALE_MENU_200", tr("Zoom Out").append(" (200%)"), "VIEW_MENU");
|
|
auto scale175Menu = menuBar->addItem("VIEW_SCALE_MENU_175", tr("Zoom Out").append(" (175%)"), "VIEW_MENU");
|
|
auto scale150Menu = menuBar->addItem("VIEW_SCALE_MENU_150", tr("Zoom Out").append(" (150%)"), "VIEW_MENU");
|
|
auto scale125Menu = menuBar->addItem("VIEW_SCALE_MENU_125", tr("Zoom Out").append(" (125%)"), "VIEW_MENU");
|
|
auto scale100Menu = menuBar->addItem("VIEW_SCALE_MENU_100", tr("Zoom Out").append(" (100%)"), "VIEW_MENU");
|
|
auto scale75Menu = menuBar->addItem("VIEW_SCALE_MENU_75", tr("Zoom Out").append(" (75%)"), "VIEW_MENU");
|
|
auto scale50Menu = menuBar->addItem("VIEW_SCALE_MENU_50", tr("Zoom Out").append(" (50%)"), "VIEW_MENU");
|
|
auto scale25Menu = menuBar->addItem("VIEW_SCALE_MENU_25", tr("Zoom Out").append(" (25%)"), "VIEW_MENU");
|
|
int frameScale = int(_project.getFrameScale() * 100);
|
|
|
|
if (frameScale == 200)
|
|
{
|
|
scale200Menu->setChecked(true);
|
|
}
|
|
else if (frameScale == 175)
|
|
{
|
|
scale175Menu->setChecked(true);
|
|
}
|
|
else if (frameScale == 150)
|
|
{
|
|
scale150Menu->setChecked(true);
|
|
}
|
|
else if (frameScale == 125)
|
|
{
|
|
scale125Menu->setChecked(true);
|
|
}
|
|
else if (frameScale == 100)
|
|
{
|
|
scale100Menu->setChecked(true);
|
|
}
|
|
else if (frameScale == 75)
|
|
{
|
|
scale75Menu->setChecked(true);
|
|
}
|
|
else if (frameScale == 50)
|
|
{
|
|
scale50Menu->setChecked(true);
|
|
}
|
|
else if (frameScale == 25)
|
|
{
|
|
scale25Menu->setChecked(true);
|
|
}
|
|
else
|
|
{
|
|
scale100Menu->setChecked(true);
|
|
}
|
|
|
|
scaleMenuVector.push_back(scale200Menu);
|
|
scaleMenuVector.push_back(scale175Menu);
|
|
scaleMenuVector.push_back(scale150Menu);
|
|
scaleMenuVector.push_back(scale125Menu);
|
|
scaleMenuVector.push_back(scale100Menu);
|
|
scaleMenuVector.push_back(scale75Menu);
|
|
scaleMenuVector.push_back(scale50Menu);
|
|
scaleMenuVector.push_back(scale25Menu);
|
|
|
|
menuBar->addItem("REFRESH_MENU_SEP", "-", "VIEW_MENU");
|
|
menuBar->addItem("REFRESH_MENU", tr("Refresh"), "VIEW_MENU");
|
|
|
|
HWND &hwnd = _hwnd;
|
|
ProjectConfig &project = _project;
|
|
auto dispatcher = Director::getInstance()->getEventDispatcher();
|
|
dispatcher->addEventListenerWithFixedPriority(EventListenerCustom::create("APP.EVENT", [&project, &hwnd, scaleMenuVector](EventCustom* event){
|
|
auto menuEvent = dynamic_cast<AppEvent*>(event);
|
|
if (menuEvent)
|
|
{
|
|
rapidjson::Document dArgParse;
|
|
dArgParse.Parse<0>(menuEvent->getDataString().c_str());
|
|
if (dArgParse.HasMember("name"))
|
|
{
|
|
string strcmd = dArgParse["name"].GetString();
|
|
|
|
if (strcmd == "menuClicked")
|
|
{
|
|
player::PlayerMenuItem *menuItem = static_cast<player::PlayerMenuItem*>(menuEvent->getUserData());
|
|
if (menuItem)
|
|
{
|
|
if (menuItem->isChecked())
|
|
{
|
|
return;
|
|
}
|
|
|
|
string data = dArgParse["data"].GetString();
|
|
|
|
if ((data == "CLOSE_MENU") || (data == "EXIT_MENU"))
|
|
{
|
|
_instance->quit();
|
|
}
|
|
else if (data == "REFRESH_MENU")
|
|
{
|
|
_instance->relaunch();
|
|
}
|
|
else if (data.find("VIEW_SCALE_MENU_") == 0) // begin with VIEW_SCALE_MENU_
|
|
{
|
|
string tmp = data.erase(0, strlen("VIEW_SCALE_MENU_"));
|
|
float scale = atof(tmp.c_str()) / 100.0f;
|
|
project.setFrameScale(scale);
|
|
|
|
_instance->setZoom(scale);
|
|
|
|
// update scale menu state
|
|
for (auto &it : scaleMenuVector)
|
|
{
|
|
it->setChecked(false);
|
|
}
|
|
menuItem->setChecked(true);
|
|
|
|
// update window title
|
|
_instance->updateWindowTitle();
|
|
|
|
// update window size
|
|
RECT rect;
|
|
GetWindowRect(hwnd, &rect);
|
|
MoveWindow(hwnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top + GetSystemMetrics(SM_CYMENU), FALSE);
|
|
|
|
// fix: can not update window on some windows system
|
|
::SendMessage(hwnd, WM_MOVE, NULL, NULL);
|
|
}
|
|
else if (data.find("VIEWSIZE_ITEM_MENU_") == 0) // begin with VIEWSIZE_ITEM_MENU_
|
|
{
|
|
string tmp = data.erase(0, strlen("VIEWSIZE_ITEM_MENU_"));
|
|
int index = atoi(tmp.c_str());
|
|
SimulatorScreenSize size = SimulatorConfig::getInstance()->getScreenSize(index);
|
|
|
|
if (project.isLandscapeFrame())
|
|
{
|
|
std::swap(size.width, size.height);
|
|
}
|
|
|
|
project.setFrameSize(cocos2d::Size(size.width, size.height));
|
|
project.setWindowOffset(cocos2d::Vec2(_instance->getPositionX(), _instance->getPositionY()));
|
|
_instance->openProjectWithProjectConfig(project);
|
|
}
|
|
else if (data == "DIRECTION_PORTRAIT_MENU")
|
|
{
|
|
project.changeFrameOrientationToPortait();
|
|
_instance->openProjectWithProjectConfig(project);
|
|
}
|
|
else if (data == "DIRECTION_LANDSCAPE_MENU")
|
|
{
|
|
project.changeFrameOrientationToLandscape();
|
|
_instance->openProjectWithProjectConfig(project);
|
|
}
|
|
else if (data == "OPEN_FILE_MENU")
|
|
{
|
|
auto fileDialog = player::PlayerProtocol::getInstance()->getFileDialogService();
|
|
stringstream extensions;
|
|
extensions << "All Support File|config.json,*.csd,*csd;"
|
|
<< "Project Config File|config.json;"
|
|
<< "Cocos Studio File|*.csd;"
|
|
<< "Cocos Studio Binary File|*.csb";
|
|
auto entry = fileDialog->openFile(tr("Choose File"), "", extensions.str());
|
|
|
|
_instance->onOpenFile(entry);
|
|
}
|
|
else if (data == "OPEN_PROJECT_MENU")
|
|
{
|
|
auto fileDialog = player::PlayerProtocol::getInstance()->getFileDialogService();
|
|
auto path = fileDialog->openDirectory(tr("Choose Folder"), "");
|
|
|
|
_instance->onOpenProjectFolder(path);
|
|
}
|
|
else if (data == "ABOUT_MENUITEM")
|
|
{
|
|
onHelpAbout();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}), 1);
|
|
|
|
AppDelegate *app = _app;
|
|
auto listener = EventListenerCustom::create(kAppEventDropName, [&project, app](EventCustom* event)
|
|
{
|
|
AppEvent *dropEvent = dynamic_cast<AppEvent*>(event);
|
|
if (dropEvent)
|
|
{
|
|
string dirPath = dropEvent->getDataString() + "/";
|
|
string configFilePath = dirPath + CONFIG_FILE;
|
|
|
|
if (FileUtils::getInstance()->isDirectoryExist(dirPath) &&
|
|
FileUtils::getInstance()->isFileExist(configFilePath))
|
|
{
|
|
// parse config.json
|
|
ConfigParser::getInstance()->readConfig(configFilePath);
|
|
|
|
project.setProjectDir(dirPath);
|
|
project.setScriptFile(ConfigParser::getInstance()->getEntryFile());
|
|
project.setWritablePath(dirPath);
|
|
|
|
RuntimeEngine::getInstance()->setProjectConfig(project);
|
|
}
|
|
}
|
|
});
|
|
dispatcher->addEventListenerWithFixedPriority(listener, 1);
|
|
}
|
|
|
|
void SimulatorWin::setZoom(float frameScale)
|
|
{
|
|
_project.setFrameScale(frameScale);
|
|
cocos2d::Director::getInstance()->getOpenGLView()->setFrameZoomFactor(frameScale);
|
|
}
|
|
|
|
void SimulatorWin::updateWindowTitle()
|
|
{
|
|
std::stringstream title;
|
|
title << "Cocos " << tr("Simulator") << " (" << _project.getFrameScale() * 100 << "%)";
|
|
std::u16string u16title;
|
|
cocos2d::StringUtils::UTF8ToUTF16(title.str(), u16title);
|
|
SetWindowText(_hwnd, (LPCTSTR)u16title.c_str());
|
|
}
|
|
|
|
// debug log
|
|
void SimulatorWin::writeDebugLog(const char *log)
|
|
{
|
|
if (!_writeDebugLogFile) return;
|
|
|
|
fputs(log, _writeDebugLogFile);
|
|
fputc('\n', _writeDebugLogFile);
|
|
fflush(_writeDebugLogFile);
|
|
}
|
|
|
|
void SimulatorWin::parseCocosProjectConfig(ProjectConfig &config)
|
|
{
|
|
// get project directory
|
|
ProjectConfig tmpConfig;
|
|
// load project config from command line args
|
|
vector<string> args;
|
|
for (int i = 0; i < __argc; ++i)
|
|
{
|
|
wstring ws(__wargv[i]);
|
|
string s;
|
|
s.assign(ws.begin(), ws.end());
|
|
args.push_back(s);
|
|
}
|
|
|
|
if (args.size() >= 2)
|
|
{
|
|
if (args.size() && args.at(1).at(0) == '/')
|
|
{
|
|
// FIXME:
|
|
// for Code IDE before RC2
|
|
tmpConfig.setProjectDir(args.at(1));
|
|
}
|
|
|
|
tmpConfig.parseCommandLine(args);
|
|
}
|
|
|
|
// set project directory as search root path
|
|
string solutionDir = tmpConfig.getProjectDir();
|
|
if (!solutionDir.empty())
|
|
{
|
|
for (int i = 0; i < solutionDir.size(); ++i)
|
|
{
|
|
if (solutionDir[i] == '\\')
|
|
{
|
|
solutionDir[i] = '/';
|
|
}
|
|
}
|
|
int nPos = -1;
|
|
if (solutionDir[solutionDir.length() - 1] == '/')
|
|
nPos = solutionDir.rfind('/', solutionDir.length() - 2);
|
|
else
|
|
nPos = solutionDir.rfind('/');
|
|
if (nPos > 0)
|
|
solutionDir = solutionDir.substr(0, nPos + 1);
|
|
FileUtils::getInstance()->setDefaultResourceRootPath(solutionDir);
|
|
FileUtils::getInstance()->addSearchPath(solutionDir);
|
|
FileUtils::getInstance()->addSearchPath(tmpConfig.getProjectDir().c_str());
|
|
}
|
|
else
|
|
{
|
|
FileUtils::getInstance()->setDefaultResourceRootPath(tmpConfig.getProjectDir().c_str());
|
|
}
|
|
|
|
// parse config.json
|
|
auto parser = ConfigParser::getInstance();
|
|
auto configPath = solutionDir.append(CONFIG_FILE);
|
|
parser->readConfig(configPath);
|
|
|
|
// set information
|
|
config.setConsolePort(parser->getConsolePort());
|
|
config.setFileUploadPort(parser->getUploadPort());
|
|
config.setFrameSize(parser->getInitViewSize());
|
|
if (parser->isLanscape())
|
|
{
|
|
config.changeFrameOrientationToLandscape();
|
|
}
|
|
else
|
|
{
|
|
config.changeFrameOrientationToPortait();
|
|
}
|
|
config.setScriptFile(parser->getEntryFile());
|
|
}
|
|
|
|
//
|
|
// D:\aaa\bbb\ccc\ddd\abc.txt --> D:/aaa/bbb/ccc/ddd/abc.txt
|
|
//
|
|
std::string SimulatorWin::convertPathFormatToUnixStyle(const std::string& path)
|
|
{
|
|
std::string ret = path;
|
|
int len = ret.length();
|
|
for (int i = 0; i < len; ++i)
|
|
{
|
|
if (ret[i] == '\\')
|
|
{
|
|
ret[i] = '/';
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
//
|
|
// @return: C:/Users/win8/Documents/
|
|
//
|
|
std::string SimulatorWin::getUserDocumentPath()
|
|
{
|
|
TCHAR filePath[MAX_PATH];
|
|
SHGetSpecialFolderPath(NULL, filePath, CSIDL_PERSONAL, FALSE);
|
|
int length = 2 * wcslen(filePath);
|
|
char* tempstring = new char[length + 1];
|
|
wcstombs(tempstring, filePath, length + 1);
|
|
string userDocumentPath(tempstring);
|
|
free(tempstring);
|
|
|
|
userDocumentPath = convertPathFormatToUnixStyle(userDocumentPath);
|
|
userDocumentPath.append("/");
|
|
|
|
return userDocumentPath;
|
|
}
|
|
|
|
//
|
|
// convert Unicode/LocalCode TCHAR to Utf8 char
|
|
//
|
|
char* SimulatorWin::convertTCharToUtf8(const TCHAR* src)
|
|
{
|
|
#ifdef UNICODE
|
|
WCHAR* tmp = (WCHAR*)src;
|
|
size_t size = wcslen(src) * 3 + 1;
|
|
char* dest = new char[size];
|
|
memset(dest, 0, size);
|
|
WideCharToMultiByte(CP_UTF8, 0, tmp, -1, dest, size, NULL, NULL);
|
|
return dest;
|
|
#else
|
|
char* tmp = (char*)src;
|
|
uint32 size = strlen(tmp) + 1;
|
|
WCHAR* dest = new WCHAR[size];
|
|
memset(dest, 0, sizeof(WCHAR)*size);
|
|
MultiByteToWideChar(CP_ACP, 0, src, -1, dest, (int)size); // convert local code to unicode.
|
|
|
|
size = wcslen(dest) * 3 + 1;
|
|
char* dest2 = new char[size];
|
|
memset(dest2, 0, size);
|
|
WideCharToMultiByte(CP_UTF8, 0, dest, -1, dest2, size, NULL, NULL); // convert unicode to utf8.
|
|
delete[] dest;
|
|
return dest2;
|
|
#endif
|
|
}
|
|
|
|
//
|
|
std::string SimulatorWin::getApplicationExePath()
|
|
{
|
|
TCHAR szFileName[MAX_PATH];
|
|
GetModuleFileName(NULL, szFileName, MAX_PATH);
|
|
std::u16string u16ApplicationName;
|
|
char *applicationExePath = convertTCharToUtf8(szFileName);
|
|
std::string path(applicationExePath);
|
|
CC_SAFE_FREE(applicationExePath);
|
|
|
|
return path;
|
|
}
|
|
|
|
std::string SimulatorWin::getApplicationPath()
|
|
{
|
|
std::string path = getApplicationExePath();
|
|
size_t pos;
|
|
while ((pos = path.find_first_of("\\")) != std::string::npos)
|
|
{
|
|
path.replace(pos, 1, "/");
|
|
}
|
|
size_t p = path.find_last_of("/");
|
|
string workdir;
|
|
if (p != path.npos)
|
|
{
|
|
workdir = path.substr(0, p);
|
|
}
|
|
|
|
return workdir;
|
|
}
|
|
|
|
LRESULT CALLBACK SimulatorWin::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (!_instance) return 0;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_SYSCOMMAND:
|
|
case WM_COMMAND:
|
|
{
|
|
if (HIWORD(wParam) == 0)
|
|
{
|
|
// menu
|
|
WORD menuId = LOWORD(wParam);
|
|
auto menuService = dynamic_cast<player::PlayerMenuServiceWin*> (player::PlayerProtocol::getInstance()->getMenuService());
|
|
auto menuItem = menuService->getItemByCommandId(menuId);
|
|
if (menuItem)
|
|
{
|
|
AppEvent event("APP.EVENT", APP_EVENT_MENU);
|
|
|
|
std::stringstream buf;
|
|
buf << "{\"data\":\"" << menuItem->getMenuId().c_str() << "\"";
|
|
buf << ",\"name\":" << "\"menuClicked\"" << "}";
|
|
event.setDataString(buf.str());
|
|
event.setUserData(menuItem);
|
|
Director::getInstance()->getEventDispatcher()->dispatchEvent(&event);
|
|
}
|
|
|
|
if (menuId == ID_HELP_ABOUT)
|
|
{
|
|
onHelpAbout();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case WM_KEYDOWN:
|
|
{
|
|
if (wParam == VK_F5)
|
|
{
|
|
_instance->relaunch();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_COPYDATA:
|
|
{
|
|
PCOPYDATASTRUCT pMyCDS = (PCOPYDATASTRUCT)lParam;
|
|
if (pMyCDS->dwData == 1)
|
|
{
|
|
const char *szBuf = (const char*)(pMyCDS->lpData);
|
|
SimulatorWin::getInstance()->writeDebugLog(szBuf);
|
|
break;
|
|
}
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
DragAcceptFiles(hWnd, FALSE);
|
|
break;
|
|
}
|
|
|
|
case WM_DROPFILES:
|
|
{
|
|
HDROP hDrop = (HDROP)wParam;
|
|
|
|
const int count = DragQueryFileW(hDrop, 0xffffffff, NULL, 0);
|
|
|
|
if (count > 0)
|
|
{
|
|
int fileIndex = 0;
|
|
|
|
const UINT length = DragQueryFileW(hDrop, fileIndex, NULL, 0);
|
|
WCHAR* buffer = (WCHAR*)calloc(length + 1, sizeof(WCHAR));
|
|
|
|
DragQueryFileW(hDrop, fileIndex, buffer, length + 1);
|
|
char *utf8 = SimulatorWin::convertTCharToUtf8(buffer);
|
|
std::string firstFile(utf8);
|
|
CC_SAFE_FREE(utf8);
|
|
DragFinish(hDrop);
|
|
|
|
_instance->onDrop(firstFile);
|
|
}
|
|
} // WM_DROPFILES
|
|
|
|
}
|
|
return g_oldWindowProc(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
void SimulatorWin::onOpenFile(const std::string &filePath)
|
|
{
|
|
string entry = filePath;
|
|
if (entry.empty()) return;
|
|
|
|
if (stringEndWith(entry, "config.json") || stringEndWith(entry, ".csb") || stringEndWith(entry, ".csd"))
|
|
{
|
|
replaceAll(entry, "\\", "/");
|
|
size_t p = entry.find_last_of("/");
|
|
if (p != entry.npos)
|
|
{
|
|
string workdir = entry.substr(0, p);
|
|
_project.setProjectDir(workdir);
|
|
}
|
|
|
|
_project.setScriptFile(entry);
|
|
if (stringEndWith(entry, CONFIG_FILE))
|
|
{
|
|
ConfigParser::getInstance()->readConfig(entry);
|
|
_project.setScriptFile(ConfigParser::getInstance()->getEntryFile());
|
|
}
|
|
openProjectWithProjectConfig(_project);
|
|
}
|
|
else
|
|
{
|
|
auto title = tr("Open File") + tr("Error");
|
|
auto msg = tr("Only support") + " config.json;*.csb;*.csd";
|
|
auto msgBox = player::PlayerProtocol::getInstance()->getMessageBoxService();
|
|
msgBox->showMessageBox(title, msg);
|
|
}
|
|
}
|
|
|
|
/*
|
|
1. find @folderPath/config.json
|
|
2. get project name from file: @folderPath/folderName.ccs
|
|
3. find @folderPath/cocosstudio/MainScene.csd
|
|
4. find @folderPath/cocosstudio/MainScene.csb
|
|
*/
|
|
void SimulatorWin::onOpenProjectFolder(const std::string &folderPath)
|
|
{
|
|
string path = folderPath;
|
|
if (!path.empty())
|
|
{
|
|
replaceAll(path, "\\", "/");
|
|
|
|
auto fileUtils = FileUtils::getInstance();
|
|
bool foundProjectFile = false;
|
|
// 1. check config.json
|
|
auto configPath = path + "/" + CONFIG_FILE;
|
|
if (fileUtils->isFileExist(configPath))
|
|
{
|
|
ConfigParser::getInstance()->readConfig(configPath);
|
|
_project.setProjectDir(path);
|
|
_project.setScriptFile(ConfigParser::getInstance()->getEntryFile());
|
|
foundProjectFile = true;
|
|
}
|
|
// check ccs project
|
|
else
|
|
{
|
|
// 2.
|
|
if (path.at(path.size() - 1) == '/') path.erase(path.size() - 1);
|
|
ssize_t pos = path.find_last_of('/');
|
|
if (pos != std::string::npos)
|
|
{
|
|
auto folderName = path.substr(path.find_last_of('/'), path.size());
|
|
auto ccsFilePath = path + folderName + ".ccs";
|
|
if (fileUtils->isFileExist(ccsFilePath))
|
|
{
|
|
auto fileContent = fileUtils->getStringFromFile(ccsFilePath);
|
|
|
|
string matchString("<Project Name=\"");
|
|
pos = fileContent.find(matchString);
|
|
// get project file name
|
|
if (pos != std::string::npos)
|
|
{
|
|
fileContent = fileContent.substr(pos + matchString.size(), fileContent.size());
|
|
ssize_t posEnd = fileContent.find_first_of('"');
|
|
auto projectFileName = path + "/cocosstudio/" + fileContent.substr(0, posEnd);
|
|
_project.setProjectDir(path);
|
|
_project.setScriptFile(projectFileName);
|
|
foundProjectFile = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!foundProjectFile)
|
|
{
|
|
auto csdFilePath = path + "/cocosstudio/MainScene.csd";
|
|
auto csbFilePath = path + "/cocosstudio/MainScene.csb";
|
|
// 3.
|
|
if (fileUtils->isFileExist(csdFilePath))
|
|
{
|
|
_project.setProjectDir(path);
|
|
_project.setScriptFile(csdFilePath);
|
|
foundProjectFile = true;
|
|
}
|
|
// 4.
|
|
else if (fileUtils->isFileExist(csbFilePath))
|
|
{
|
|
_project.setProjectDir(path);
|
|
_project.setScriptFile(csbFilePath);
|
|
foundProjectFile = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (foundProjectFile)
|
|
{
|
|
openProjectWithProjectConfig(_project);
|
|
}
|
|
else
|
|
{
|
|
auto title = tr("Open Project") + tr("Error");
|
|
auto msgBox = player::PlayerProtocol::getInstance()->getMessageBoxService();
|
|
msgBox->showMessageBox(title, tr("Can not find project"));
|
|
}
|
|
}
|
|
}
|
|
|
|
void SimulatorWin::onDrop(const std::string &path)
|
|
{
|
|
auto fileUtils = FileUtils::getInstance();
|
|
if (fileUtils->isDirectoryExist(path))
|
|
{
|
|
onOpenProjectFolder(path);
|
|
}
|
|
else if (fileUtils->isFileExist(path))
|
|
{
|
|
onOpenFile(path);
|
|
}
|
|
}
|