mainframe.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. #include "stdafx.h"
  2. #include "resource.h"
  3. #include "mainframe.h"
  4. #include "about.h"
  5. #include "blitzide.h"
  6. #include "libs.h"
  7. #include <mmsystem.h>
  8. #include <fstream>
  9. #include <sstream>
  10. IMPLEMENT_DYNAMIC( MainFrame,CFrameWnd )
  11. BEGIN_MESSAGE_MAP( MainFrame,CFrameWnd )
  12. ON_WM_CREATE()
  13. ON_WM_CLOSE()
  14. ON_WM_DESTROY()
  15. ON_WM_ERASEBKGND()
  16. ON_WM_SIZE()
  17. ON_WM_ACTIVATE()
  18. ON_COMMAND( ID_NEW,fileNew )
  19. ON_COMMAND( ID_OPEN,fileOpen )
  20. ON_COMMAND( ID_SAVE,fileSave )
  21. ON_COMMAND( ID_SAVEAS,fileSaveAs )
  22. ON_COMMAND( ID_SAVEALL,fileSaveAll )
  23. ON_COMMAND( ID_PRINT,filePrint )
  24. ON_COMMAND( ID_CLOSE,fileClose )
  25. ON_COMMAND( ID_CLOSEALL,fileCloseAll )
  26. ON_COMMAND( ID_EXIT,fileExit )
  27. ON_COMMAND_RANGE( 333,343,fileRecent )
  28. ON_COMMAND( ID_CUT,editCut )
  29. ON_COMMAND( ID_COPY,editCopy )
  30. ON_COMMAND( ID_PASTE,editPaste )
  31. ON_COMMAND( ID_SELECTALL,editSelectAll )
  32. ON_COMMAND( ID_FIND,editFind )
  33. ON_COMMAND( ID_FINDNEXT,editFindNext )
  34. ON_COMMAND( ID_REPLACE,editReplace )
  35. ON_COMMAND( ID_CTRLTAB,ctrlTab )
  36. ON_COMMAND( ID_CTRLSHIFTTAB,ctrlShiftTab )
  37. ON_COMMAND( ID_ESCAPE,escape )
  38. ON_COMMAND( ID_QUICKHELP,quick_Help )
  39. ON_COMMAND( ID_EXECUTE,programExecute )
  40. ON_COMMAND( ID_REEXECUTE,programReExecute )
  41. ON_COMMAND( ID_COMPILE,programCompile )
  42. ON_COMMAND( ID_PUBLISH,programPublish )
  43. ON_COMMAND( ID_COMMANDLINE,programCommandLine )
  44. ON_COMMAND( ID_DEBUG,programDebug )
  45. ON_COMMAND( ID_HOME,helpHome )
  46. ON_COMMAND( ID_BACK,helpBack )
  47. ON_COMMAND( ID_FORWARD,helpForward )
  48. ON_COMMAND( ID_ABOUT,helpAbout )
  49. ON_UPDATE_COMMAND_UI( ID_NEW,updateCmdUI )
  50. ON_UPDATE_COMMAND_UI( ID_OPEN,updateCmdUI )
  51. ON_UPDATE_COMMAND_UI( ID_SAVE,updateCmdUI )
  52. ON_UPDATE_COMMAND_UI( ID_SAVEAS,updateCmdUI )
  53. ON_UPDATE_COMMAND_UI( ID_SAVEALL,updateCmdUI )
  54. ON_UPDATE_COMMAND_UI( ID_PRINT,updateCmdUI )
  55. ON_UPDATE_COMMAND_UI( ID_CLOSE,updateCmdUI )
  56. ON_UPDATE_COMMAND_UI( ID_CLOSEALL,updateCmdUI )
  57. ON_UPDATE_COMMAND_UI( ID_CUT,updateCmdUI )
  58. ON_UPDATE_COMMAND_UI( ID_COPY,updateCmdUI )
  59. ON_UPDATE_COMMAND_UI( ID_PASTE,updateCmdUI )
  60. ON_UPDATE_COMMAND_UI( ID_SELECTALL,updateCmdUI )
  61. ON_UPDATE_COMMAND_UI( ID_FIND,updateCmdUI )
  62. ON_UPDATE_COMMAND_UI( ID_FINDNEXT,updateCmdUI )
  63. ON_UPDATE_COMMAND_UI( ID_REPLACE,updateCmdUI )
  64. ON_UPDATE_COMMAND_UI( ID_EXECUTE,updateCmdUI )
  65. ON_UPDATE_COMMAND_UI( ID_REEXECUTE,updateCmdUI )
  66. ON_UPDATE_COMMAND_UI( ID_COMPILE,updateCmdUI )
  67. ON_UPDATE_COMMAND_UI( ID_PUBLISH,updateCmdUI )
  68. ON_UPDATE_COMMAND_UI( ID_COMMANDLINE,updateCmdUI )
  69. ON_UPDATE_COMMAND_UI( ID_DEBUG,updateCmdUI )
  70. ON_UPDATE_COMMAND_UI( ID_HOME,updateCmdUI )
  71. ON_UPDATE_COMMAND_UI( ID_BACK,updateCmdUI )
  72. ON_UPDATE_COMMAND_UI( ID_FORWARD,updateCmdUI )
  73. ON_UPDATE_COMMAND_UI( ID_ESCAPE,updateCmdUI )
  74. ON_UPDATE_COMMAND_UI( ID_QUICKHELP,updateCmdUI )
  75. ON_UPDATE_COMMAND_UI_RANGE( 333,343,updateCmdUIRange )
  76. END_MESSAGE_MAP()
  77. enum{
  78. TAB_INVALID,TAB_EDITOR,TAB_HTMLHELP,TAB_DEBUGLOG
  79. };
  80. static string getFile( const string &f ){
  81. int n;
  82. string t=f;
  83. n=t.rfind( '/' );if( n!=string::npos ) t=t.substr(n+1);
  84. n=t.rfind( '\\' );if( n!=string::npos ) t=t.substr(n+1);
  85. return t;
  86. }
  87. static string getPath( const string &f ){
  88. int n;
  89. string t=f;
  90. n=t.rfind( '/' );if( n!=string::npos ) t=t.substr(0,n );
  91. n=t.rfind( '\\' );if( n!=string::npos ) t=t.substr(0,n);
  92. return t;
  93. }
  94. MainFrame::MainFrame():exit_flag(false){
  95. }
  96. int MainFrame::OnCreate( LPCREATESTRUCT lpCreateStruct ){
  97. CFrameWnd::OnCreate( lpCreateStruct );
  98. static HBITMAP toolbmp;
  99. static SIZE imgsz,butsz;
  100. static UINT toolbuts[]={
  101. ID_NEW,ID_OPEN,ID_SAVE,ID_CLOSE,ID_SEPARATOR,
  102. ID_CUT,ID_COPY,ID_PASTE,ID_SEPARATOR,
  103. ID_FIND,ID_SEPARATOR,
  104. ID_EXECUTE,ID_SEPARATOR,
  105. ID_HOME,ID_BACK,ID_FORWARD };
  106. static int toolcnt=sizeof(toolbuts)/sizeof(UINT);
  107. if( !toolbmp ){
  108. BITMAP bm;
  109. string t=prefs.homeDir+"/cfg/ide_toolbar.bmp";
  110. toolbmp=(HBITMAP)LoadImage( 0,t.c_str(),IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_LOADMAP3DCOLORS );
  111. if( !toolbmp ){
  112. AfxMessageBox( "toolbar bitmap failed to load!" );
  113. ExitProcess(0);
  114. }
  115. GetObject( toolbmp,sizeof(bm),&bm );
  116. int n=0;
  117. for( int k=0;k<toolcnt;++k ) if( toolbuts[k]!=ID_SEPARATOR ) ++n;
  118. imgsz.cx=bm.bmWidth/n;imgsz.cy=bm.bmHeight;
  119. butsz.cx=imgsz.cx+7;butsz.cy=imgsz.cy+6;
  120. }
  121. toolBar.CreateEx( this,TBSTYLE_FLAT,WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_TOOLTIPS );
  122. toolBar.SetBitmap( toolbmp );
  123. toolBar.SetSizes( butsz,imgsz );
  124. toolBar.SetButtons( toolbuts,toolcnt );
  125. int style;
  126. style=WS_CHILD|WS_VISIBLE|CBRS_ALIGN_BOTTOM;
  127. statusBar.CreateEx( this,0,style );
  128. UINT IDS[]={ ID_STATUSTEXT,ID_COLROWTEXT };
  129. statusBar.SetIndicators( IDS,2 );
  130. statusBar.SetPaneInfo( 0,ID_STATUSTEXT,SBPS_NOBORDERS|SBPS_STRETCH,0 );
  131. statusBar.SetPaneInfo( 1,ID_COLROWTEXT,0,128 );
  132. statusBar.SetPaneText( 0,"" );statusBar.SetPaneText( 1,"" );
  133. tabber.Create( WS_VISIBLE|WS_CHILD|TCS_HOTTRACK,CRect( 0,0,0,0 ),this,1 );
  134. tabber.SetFont( &prefs.tabsFont );
  135. tabber.setListener( this );
  136. prefs.win_notoolbar=!prefs.win_notoolbar;
  137. escape();
  138. //create recent file list
  139. CMenu menu;
  140. menu.CreatePopupMenu();
  141. for( int k=0;k<prefs.recentFiles.size();++k ){
  142. menu.InsertMenu( k,MF_BYPOSITION|MF_ENABLED,333+k,prefs.recentFiles[k].c_str() );
  143. }
  144. CMenu *file=GetMenu()->GetSubMenu( 0 );
  145. file->InsertMenu( 12,MF_BYPOSITION|MF_ENABLED|MF_POPUP,(UINT)menu.m_hMenu,"&Recent Files" );
  146. menu.Detach();
  147. helpHome();
  148. trackmem( true );
  149. if( blitzIDE.m_lpCmdLine[0] ){
  150. string t=string( blitzIDE.m_lpCmdLine );
  151. if( t[0]=='\"' ) t=t.substr( 1,t.size()-2 );
  152. open( t );
  153. }else{
  154. SetCurrentDirectory( (prefs.homeDir+"/samples").c_str() );
  155. }
  156. return 0;
  157. }
  158. void MainFrame::OnDestroy(){
  159. trackmem( false );
  160. WINDOWPLACEMENT wp={sizeof(wp)};
  161. if( GetWindowPlacement( &wp ) ){
  162. prefs.win_rect=wp.rcNormalPosition;
  163. if( wp.showCmd==SW_SHOWMAXIMIZED ){
  164. prefs.win_maximized=true;
  165. }else{
  166. prefs.win_maximized=false;
  167. }
  168. }
  169. }
  170. void MainFrame::setTitle( const string &s ){
  171. #ifdef PRO
  172. SetWindowText( ("Blitz3D - "+s ).c_str() );
  173. return;
  174. #else
  175. SetWindowText( ("Blitz2D - "+s ).c_str() );
  176. return;
  177. #endif
  178. }
  179. void MainFrame::OnClose(){
  180. bool exit_flag=true;
  181. for( int k=tabber.size()-1;k>=0;--k ){
  182. exit_flag=close( k );
  183. if( !exit_flag ) break;
  184. }
  185. if( exit_flag ) DestroyWindow();
  186. }
  187. BOOL MainFrame::OnEraseBkgnd( CDC *dc ){
  188. return true;
  189. }
  190. void MainFrame::OnSize( UINT type,int sw,int sh ){
  191. CFrameWnd::OnSize( type,sw,sh );
  192. CRect r,t;GetClientRect( &r );
  193. int x=r.left,y=r.top,w=r.Width(),h=r.Height();
  194. if( !prefs.win_notoolbar ){
  195. statusBar.GetWindowRect( &t );h-=t.Height();
  196. toolBar.GetWindowRect( &t );y+=t.Height();h-=t.Height();
  197. }
  198. tabber.MoveWindow( x,y,w,h );
  199. }
  200. static char *bbFilter=
  201. "Blitz Basic files (.bb)|*.bb|"
  202. #ifdef PRO
  203. "Image files (.bmp,.jpg,.png,.tga,.iff,.pcx)|*.bmp;*.jpg;*.png;*.tga;*.iff;*.pcx|"
  204. "Audio files (.wav,.mid,.mod,.mp3,.s3m,.xm,.it,.rmi,.sgt)|*.wav;*.mid;*.mod;*.mp3;*.s3m;*.xm;*.it;*.rmi;*.sgt|"
  205. "3D Mesh files (.x,.3ds,.md2)|*.x;*.3ds;*.md2|"
  206. #endif
  207. "All files|*.*||";
  208. Editor *MainFrame::getEditor(){
  209. return getEditor( tabber.getCurrent() );
  210. }
  211. Editor *MainFrame::getEditor( int n ){
  212. map<CWnd*,Editor*>::iterator it=editors.find( tabber.getTabWnd( n ) );
  213. return it==editors.end() ? 0 : it->second;
  214. }
  215. HtmlHelp *MainFrame::getHelp( int n ){
  216. map<CWnd*,HtmlHelp*>::iterator it=helps.find( tabber.getTabWnd( n ) );
  217. return it==helps.end() ? 0 : it->second;
  218. }
  219. HtmlHelp *MainFrame::getHelp(){
  220. return getHelp( tabber.getCurrent() );
  221. }
  222. HtmlHelp *MainFrame::findHelp(){
  223. int n;
  224. HtmlHelp *h;
  225. for( n=0;n<tabber.size();++n ){
  226. if( h=getHelp( n ) ) break;
  227. }
  228. if( n==tabber.size() ){
  229. h=new HtmlHelp( this );
  230. h->Create( 0,"Help",WS_CHILD|WS_BORDER,CRect( 0,0,0,0 ),&tabber,1 );
  231. helps[h]=h;
  232. tabber.insert( n,h,"Help" );
  233. }
  234. tabber.setCurrent( n );
  235. return h;
  236. }
  237. void MainFrame::cursorMoved( Editor *editor ){
  238. if( editor!=getEditor() ) return;
  239. int row,col;
  240. editor->getCursor( &row,&col );
  241. char mod=editor->getModified() ? '*' : ' ';
  242. char str[64];sprintf( str,"Row:%i Col:%i %c",row,col,mod );
  243. statusBar.SetPaneText( 1,str );
  244. }
  245. void MainFrame::currentSet( Tabber *tabber,int index ){
  246. if( Editor *e=getEditor() ){
  247. string t=e->getName();
  248. if( !t.size() ) t="<untitled>";
  249. setTitle( t );
  250. cursorMoved( e );
  251. }else if( HtmlHelp *h=getHelp() ){
  252. setTitle( h->getTitle() );
  253. statusBar.SetPaneText( 1,"" );
  254. }else{
  255. setTitle( "no file" );
  256. statusBar.SetPaneText( 1,"" );
  257. }
  258. }
  259. void MainFrame::helpOpen( HtmlHelp *help,const string &file ){
  260. open( file );
  261. }
  262. void MainFrame::helpTitleChange( HtmlHelp *help,const string &title ){
  263. if( HtmlHelp *h=getHelp() ) setTitle( h->getTitle() );
  264. }
  265. void MainFrame::insertRecent( const string &file ){
  266. //check recent files
  267. if( CMenu *list=GetMenu()->GetSubMenu( 0 )->GetSubMenu( 12 ) ){
  268. vector<string>::iterator it;
  269. vector<string> &f=prefs.recentFiles;
  270. for( it=f.begin();it!=f.end();++it ){
  271. if( tolower( *it )==tolower( file ) ) break;
  272. }
  273. if( it!=f.end() ){
  274. //move to top
  275. string t=*it;
  276. f.erase( it );
  277. f.insert( f.begin(),t );
  278. }else{
  279. //insert
  280. if( f.size()==10 ){
  281. f.pop_back();
  282. list->RemoveMenu( 9,MF_BYPOSITION );
  283. }
  284. f.insert( f.begin(),file );
  285. list->InsertMenu( 0,MF_BYPOSITION|MF_ENABLED,333,file.c_str() );
  286. }
  287. //renumber menu items
  288. for( int k=0;k<f.size();++k ){
  289. list->ModifyMenu( k,MF_BYPOSITION|MF_ENABLED,333+k,f[k].c_str() );
  290. }
  291. }
  292. }
  293. void MainFrame::newed( const string &t ){
  294. CRect r( 0,0,0,0 );
  295. Editor *e=new Editor( this );
  296. e->Create( 0,"Editor",WS_CHILD,r,&tabber,1 );
  297. e->setName( t );
  298. editors[e]=e;
  299. int n=tabber.size();
  300. string s=t.size() ? getFile( t ) : "<untitled>";
  301. tabber.insert( n,e,s.c_str() );
  302. tabber.setCurrent( n );
  303. }
  304. bool MainFrame::open( const string &f ){
  305. string file=f,filter="*.bb";
  306. int n=f.find( "*." );
  307. if( n!=string::npos ){
  308. file=f.substr( 0,n );
  309. filter=f.substr( n );
  310. }
  311. int attr=GetFileAttributes( file.c_str() );if( attr==-1 ) attr=0;
  312. if( !file.size() || (attr & FILE_ATTRIBUTE_DIRECTORY) ){
  313. int n=OFN_NOCHANGEDIR|OFN_FILEMUSTEXIST;
  314. CFileDialog fd( true,"bb",filter.c_str(),n,bbFilter );
  315. char *i_dir=strdup( file.c_str() );
  316. fd.m_ofn.lpstrInitialDir=i_dir;
  317. fd.m_ofn.lpstrTitle="Open Blitz Basic File...";
  318. int nn=fd.DoModal();free( i_dir );
  319. if( nn==IDCANCEL ) return false;
  320. file=fd.GetPathName();
  321. }else{
  322. char buff[MAX_PATH],*p;
  323. if( GetFullPathName( file.c_str(),MAX_PATH,buff,&p ) ) file=buff;
  324. else file=f;
  325. }
  326. if( isMediaFile( tolower( file ) ) ){
  327. string t=prefs.homeDir+"/bin/mediaview.exe";
  328. if( (int)ShellExecute( ::GetDesktopWindow(),0,t.c_str(),file.c_str(),0,SW_SHOW )>32 ){
  329. }
  330. return false;
  331. }
  332. //is file already open?
  333. int k;
  334. for( k=0;k<tabber.size();++k ){
  335. if( Editor *e=getEditor( k ) ){
  336. if( tolower( e->getName() )==tolower( file ) ){
  337. tabber.setCurrent( k );
  338. return true;
  339. }
  340. }
  341. }
  342. //open new file
  343. ifstream in( file.c_str() );
  344. if( !in.good() ){
  345. string e="Error reading file \""+f+"\"";
  346. AfxMessageBox( e.c_str(),MB_ICONWARNING );
  347. return false;
  348. }
  349. newed( file );
  350. tabber.UpdateWindow();
  351. Editor *e=getEditor();
  352. e->setText( in );
  353. e->setName( file );
  354. e->setModified( false );
  355. insertRecent( file );
  356. cursorMoved( e );
  357. return true;
  358. }
  359. bool MainFrame::close( int n ){
  360. if( Editor *e=getEditor( n ) ){
  361. if( e->getModified() ){
  362. tabber.setCurrent( n );
  363. string t="File "+e->getName()+" has been modified!\nSave changes before closing?";
  364. int rt=AfxMessageBox( t.c_str(),MB_YESNOCANCEL|MB_ICONWARNING );
  365. if( rt==IDYES ) return save( n );
  366. if( rt==IDCANCEL ) return false;
  367. }
  368. tabber.remove( n );
  369. e->DestroyWindow();
  370. editors.erase( e );
  371. delete e;
  372. }else if( HtmlHelp *h=getHelp( n ) ){
  373. }
  374. return true;
  375. }
  376. bool MainFrame::save( int n ){
  377. Editor *e=getEditor( n );
  378. if( !e ) return true;
  379. string t=e->getName();
  380. if( !t.size() ){
  381. tabber.setCurrent( n );
  382. int df=OFN_NOCHANGEDIR|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY|OFN_EXPLORER|OFN_OVERWRITEPROMPT;
  383. CFileDialog fd( false,"bb","*.bb",df,bbFilter );
  384. fd.m_ofn.lpstrTitle="Save Blitz Basic program as...";
  385. if( fd.DoModal()==IDCANCEL ) return false;
  386. t=fd.GetPathName();
  387. tabber.setTabText( n,getFile( t ) );
  388. e->setName( t );
  389. insertRecent( t );
  390. }
  391. //Do backups!
  392. if( prefs.edit_backup ){
  393. for( int k=prefs.edit_backup;k>1;--k ){
  394. CopyFile( (t+"_bak"+itoa(k-1)).c_str(),(t+"_bak"+itoa(k)).c_str(),false );
  395. }
  396. CopyFile( t.c_str(),(t+"_bak1").c_str(),false );
  397. }
  398. int om=ios_base::binary|ios_base::out|ios_base::trunc;
  399. ofstream out( t.c_str(),om );
  400. if( !out.good() ){
  401. string e="Error writing file \""+t+"\"";
  402. AfxMessageBox( e.c_str(),MB_ICONWARNING );
  403. return false;
  404. }
  405. e->getText( out );
  406. out.close();
  407. e->setModified( false );
  408. cursorMoved( e );
  409. return true;
  410. }
  411. void MainFrame::fileNew(){
  412. newed( "" );
  413. }
  414. void MainFrame::fileOpen(){
  415. open( "" );
  416. }
  417. void MainFrame::fileSave(){
  418. save( tabber.getCurrent() );
  419. }
  420. void MainFrame::fileSaveAs(){
  421. if( Editor *e=getEditor() ){
  422. string t=e->getName();
  423. e->setName( "" );
  424. if( !save( tabber.getCurrent() ) ) e->setName( t );
  425. currentSet( &tabber,tabber.getCurrent() );
  426. }
  427. }
  428. void MainFrame::fileSaveAll(){
  429. for( int k=tabber.size()-1;k>=0;--k ){
  430. if( !save( k ) ) return;
  431. }
  432. }
  433. void MainFrame::filePrint(){
  434. if( Editor *e=getEditor() ) e->print();
  435. }
  436. void MainFrame::fileClose(){
  437. close( tabber.getCurrent() );
  438. }
  439. void MainFrame::fileCloseAll(){
  440. for( int k=tabber.size()-1;k>=0;--k ){
  441. if( !close( k ) ) return;
  442. }
  443. }
  444. void MainFrame::fileExit(){
  445. PostMessage( WM_CLOSE );
  446. }
  447. void MainFrame::fileRecent( UINT id ){
  448. id-=333;
  449. if( id<0 || id>=prefs.recentFiles.size() ) return;
  450. open( prefs.recentFiles[id] );
  451. }
  452. void MainFrame::editCut(){
  453. if( Editor *e=getEditor() ) e->cut();
  454. }
  455. void MainFrame::editCopy(){
  456. if( Editor *e=getEditor() ) e->copy();
  457. }
  458. void MainFrame::editPaste(){
  459. if( Editor *e=getEditor() ) e->paste();
  460. }
  461. void MainFrame::editSelectAll(){
  462. if( Editor *e=getEditor() ) e->selectAll();
  463. }
  464. void MainFrame::editFind(){
  465. if( Editor *e=getEditor() ) e->find();
  466. }
  467. void MainFrame::editFindNext(){
  468. if( Editor *e=getEditor() ) e->findNext( true );
  469. }
  470. void MainFrame::editReplace(){
  471. if( Editor *e=getEditor() ) e->replace();
  472. }
  473. static HANDLE startProc( const string &proc ){
  474. HANDLE rd,wr;
  475. SECURITY_ATTRIBUTES sa={sizeof(sa),0,true};
  476. if( CreatePipe( &rd,&wr,&sa,0 ) ){
  477. STARTUPINFO si={sizeof(si)};
  478. si.dwFlags=STARTF_USESTDHANDLES;
  479. si.hStdOutput=si.hStdError=wr;
  480. PROCESS_INFORMATION pi={0};
  481. if( CreateProcess( 0,(char*)proc.c_str(),0,0,true,DETACHED_PROCESS,0,0,&si,&pi ) ){
  482. CloseHandle( pi.hProcess );
  483. CloseHandle( pi.hThread );
  484. CloseHandle( wr );
  485. return rd;
  486. }
  487. CloseHandle( rd );
  488. CloseHandle( wr );
  489. }
  490. return 0;
  491. }
  492. class PDialog : public CDialog{
  493. public:
  494. void OnOk(){}
  495. void OnCancel(){}
  496. };
  497. void MainFrame::compile( const string &cmd ){
  498. CDialog compiling;
  499. compiling.Create( IDD_COMPILING );
  500. CProgressCtrl *cp=(CProgressCtrl*)compiling.GetDlgItem( IDC_COMPILEPROGRESS );
  501. cp->SetStep(20);
  502. putenv( "blitzide=1" );
  503. HANDLE rd=startProc( cmd );
  504. if( !rd ){
  505. putenv( "blitzide" );
  506. compiling.DestroyWindow();
  507. AfxMessageBox( "Error launching compiler",MB_ICONWARNING|MB_OK );
  508. return;
  509. }
  510. string line,err;
  511. //OK....here we go!
  512. for(;;){
  513. char buff;
  514. unsigned long sz;
  515. int n=ReadFile( rd,&buff,1,&sz,0 );
  516. if( n && !sz ) break; //EOF!
  517. if( !n && GetLastError()==ERROR_BROKEN_PIPE ) break; //PROC END!
  518. if( !n ){ err="Internal Error";break; }
  519. if( buff=='\r' ) continue;
  520. if( buff!='\n' ){ line+=buff;continue; }
  521. if( !line.size() ) continue;
  522. if( line[0]=='\"' ){
  523. err=line;
  524. int n=line.find( "\"",1 );
  525. if( n==string::npos ) break;
  526. if( ++n==line.size() || line[n]!=':' ) break;
  527. string file=line.substr( 1,n-2 );line=line.substr(n+1);
  528. n=line.find( ':' );if( !n || n==string::npos ) break;
  529. int row1=atoi(line.substr(0,n));line=line.substr(n+1);
  530. n=line.find( ':' );if( !n || n==string::npos ) break;
  531. int col1=atoi(line.substr(0,n));line=line.substr(n+1);
  532. n=line.find( ':' );if( !n || n==string::npos ) break;
  533. int row2=atoi(line.substr(0,n));line=line.substr(n+1);
  534. n=line.find( ':' );if( !n || n==string::npos ) break;
  535. int col2=atoi(line.substr(0,n));line=line.substr(n+1);
  536. int pos=((row1-1)<<16)|(col1-1);
  537. if( !open( file ) ) return;
  538. if( Editor *e=getEditor() ) e->setCursor( pos );
  539. err=line;
  540. break;
  541. }else if( line.find( "..." )!=line.size()-3 ){
  542. err=line;break;
  543. }
  544. if( line.find( "Executing" )==0 ){
  545. //OK, we're running!
  546. break;
  547. }
  548. cp->StepIt();
  549. line="";
  550. }
  551. compiling.DestroyWindow();
  552. CloseHandle( rd );
  553. putenv( "blitzide" );
  554. if( !err.size() ) return;
  555. AfxMessageBox( err.c_str(),MB_ICONWARNING|MB_OK );
  556. }
  557. void MainFrame::build( bool exec,bool publish ){
  558. Editor *e=getEditor();
  559. if( !e ) return;
  560. string src_file=e->getName();
  561. for( int k=tabber.size()-1;k>=0;--k ){
  562. if( Editor *e=getEditor( k ) ){
  563. if( e->getModified() && e->getName().size() ){
  564. if( !save(k) ) return;
  565. }
  566. }
  567. }
  568. string opts=" ";
  569. if( prefs.prg_debug ) opts+="-d ";
  570. if( publish ){
  571. string exe=src_file;
  572. if( exe.size() ){
  573. int n=exe.find( '.' );
  574. if( n!=string::npos ) exe=exe.substr( 0,n );
  575. }else{
  576. exe="untitled";
  577. }
  578. static char *exeFilter="Executable files (*.exe)|*.exe||";
  579. int t=OFN_NOCHANGEDIR|OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT;
  580. CFileDialog fd( false,"exe",exe.c_str(),t,exeFilter );
  581. fd.m_ofn.lpstrTitle="Select executable filename";
  582. fd.m_ofn.lpstrInitialDir="./";
  583. if( fd.DoModal()==IDCANCEL ) return;
  584. opts+="-o \""+string( fd.GetPathName() )+"\" ";
  585. }else if( !exec ){
  586. opts+="-c ";
  587. }
  588. string src=src_file;
  589. if( !src.size() ){
  590. src=prefs.homeDir+"\\tmp\\tmp.bb";
  591. int om=ios_base::binary|ios_base::out|ios_base::trunc;
  592. ofstream out( src.c_str(),om );
  593. if( !out.good() ){
  594. string e="Error writing file \""+src+"\"";
  595. AfxMessageBox( e.c_str(),MB_ICONWARNING );
  596. return;
  597. }
  598. e->getText( out );
  599. out.close();
  600. e->setName( src );
  601. }else{
  602. prefs.prg_lastbuild=e->getName();
  603. }
  604. compile( prefs.homeDir+"/bin/blitzcc -q "+opts+" \""+src+"\" "+prefs.cmd_line );
  605. if( !src_file.size() ) e->setName( "" );
  606. }
  607. void MainFrame::programExecute(){
  608. build( true,false );
  609. }
  610. void MainFrame::programReExecute(){
  611. if( prefs.prg_lastbuild.size() && open( prefs.prg_lastbuild ) ){
  612. build( true,false );
  613. }
  614. }
  615. void MainFrame::programCompile(){
  616. build( false,false );
  617. }
  618. void MainFrame::programPublish(){
  619. #ifdef DEMO
  620. MessageBox( "Create Executable unavailable in demo version","Sorry!",MB_TOPMOST|MB_SETFOREGROUND|MB_ICONINFORMATION );
  621. return;
  622. #endif
  623. Editor *e=getEditor();if( !e ) return;
  624. if( prefs.prg_debug ){
  625. string t=
  626. "You currently have the debugging feature enabled!\n\n"
  627. "This will result in slower executables - continue anyway?";
  628. if( MessageBox( t.c_str(),0,MB_OKCANCEL )==IDCANCEL ) return;
  629. }
  630. build( false,true );
  631. }
  632. struct CmdLineDialog : public CDialog{
  633. CmdLineDialog():CDialog( IDD_COMMANDLINE ){
  634. }
  635. BOOL OnInitDialog(){
  636. CDialog::OnInitDialog();
  637. SetDlgItemText( IDC_CMDLINE,prefs.cmd_line.c_str() );
  638. return TRUE;
  639. }
  640. void OnOK(){
  641. CString c_str;
  642. GetDlgItemText( IDC_CMDLINE,c_str );
  643. prefs.cmd_line=c_str;
  644. CDialog::OnOK();
  645. }
  646. };
  647. void MainFrame::programCommandLine(){
  648. CmdLineDialog d;
  649. d.DoModal();
  650. }
  651. void MainFrame::programDebug(){
  652. prefs.prg_debug=!prefs.prg_debug;
  653. }
  654. void MainFrame::helpHome(){
  655. HtmlHelp *h=findHelp();
  656. string t;
  657. t="index.html";
  658. h->Navigate( (prefs.homeDir+"/help/"+t).c_str() );
  659. }
  660. void MainFrame::helpAutodoc(){
  661. HtmlHelp *h=findHelp();
  662. h->Navigate( (prefs.homeDir+"/help/autodoc.html").c_str() );
  663. }
  664. void MainFrame::helpBack(){
  665. if( HtmlHelp *h=findHelp() ) h->GoBack();
  666. }
  667. void MainFrame::helpForward(){
  668. if( HtmlHelp *h=findHelp() ) h->GoForward();
  669. }
  670. void MainFrame::helpAbout(){
  671. aboutBlitz( false );
  672. }
  673. void MainFrame::ctrlTab(){
  674. int n=tabber.getCurrent()+1;
  675. if( n>=tabber.size() ) n-=tabber.size();
  676. tabber.setCurrent( n );
  677. }
  678. void MainFrame::ctrlShiftTab(){
  679. int n=tabber.getCurrent()-1;
  680. if( n<0 ) n+=tabber.size();
  681. tabber.setCurrent( n );
  682. }
  683. void MainFrame::escape(){
  684. if( !prefs.win_notoolbar ){
  685. toolBar.ShowWindow( SW_HIDE );
  686. statusBar.ShowWindow( SW_HIDE );
  687. prefs.win_notoolbar=true;
  688. }else{
  689. toolBar.ShowWindow( SW_SHOW );
  690. statusBar.ShowWindow( SW_SHOW );
  691. prefs.win_notoolbar=false;
  692. }
  693. RECT r;GetClientRect( &r );
  694. int w=r.right-r.left,h=r.bottom-r.top;
  695. int n=prefs.win_maximized ? SIZE_MAXIMIZED : SIZE_RESTORED;
  696. PostMessage( WM_SIZE,n,(h<<16)|w );
  697. }
  698. void MainFrame::updateCmdUIRange( CCmdUI *ui ){
  699. int n=ui->m_nID-333;
  700. if( n>=0 && n<prefs.recentFiles.size() ){
  701. ui->Enable( true );
  702. }else{
  703. ui->Enable( false );
  704. }
  705. }
  706. void MainFrame::updateCmdUI( CCmdUI *ui ){
  707. int k;
  708. Editor *e=getEditor();
  709. switch( ui->m_nID ){
  710. case ID_NEW:case ID_OPEN:case ID_HOME:
  711. ui->Enable( true );
  712. break;
  713. case ID_DEBUG:
  714. ui->SetCheck( prefs.prg_debug );ui->Enable( true );
  715. break;
  716. case ID_CLOSE:case ID_PRINT:
  717. ui->Enable( !!e );
  718. break;
  719. case ID_CLOSEALL:
  720. for( k=0;k<tabber.size() && !getEditor(k);++k ){}
  721. ui->Enable( k<tabber.size() );
  722. break;
  723. case ID_CUT:case ID_COPY:
  724. if( !!e ){
  725. ui->Enable( e->canCutCopy() );
  726. }else ui->Enable( false );
  727. break;
  728. case ID_PASTE:
  729. if( !!e ){
  730. ui->Enable( e->canPaste() );
  731. }else ui->Enable( false );
  732. break;
  733. case ID_SELECTALL:case ID_QUICKHELP:
  734. case ID_FIND:case ID_FINDNEXT:case ID_REPLACE:
  735. case ID_EXECUTE:case ID_COMPILE:case ID_PUBLISH:
  736. ui->Enable( !!e );
  737. break;
  738. case ID_REEXECUTE:
  739. ui->Enable( prefs.prg_lastbuild.size() );
  740. break;
  741. case ID_COMMANDLINE:
  742. ui->Enable( true );
  743. break;
  744. case ID_SAVE:case ID_SAVEAS:
  745. ui->Enable( !!e );
  746. break;
  747. case ID_SAVEALL:
  748. for( k=0;k<tabber.size() && !getEditor(k);++k ){}
  749. ui->Enable( k<tabber.size() );
  750. break;
  751. case ID_BACK:case ID_FORWARD:
  752. ui->Enable( getHelp()!=0 );
  753. break;
  754. case ID_ESCAPE:
  755. ui->SetCheck( !prefs.win_notoolbar );
  756. break;
  757. default:
  758. ui->Enable( false );
  759. }
  760. }
  761. static string commandURL( const string &t ){
  762. static char *dirs[]={
  763. "help\\commands\\2d_commands\\",
  764. #ifdef PRO
  765. "help\\commands\\3d_commands\\",
  766. #endif
  767. 0
  768. };
  769. char **dir_p=dirs;
  770. while( char *dir=*dir_p++ ){
  771. WIN32_FIND_DATA fd;
  772. string path=prefs.homeDir+"/"+dir+t+".htm";
  773. HANDLE h=FindFirstFile( path.c_str(),&fd );
  774. if( h==INVALID_HANDLE_VALUE ) continue;
  775. FindClose( h );
  776. return path;
  777. }
  778. return "";
  779. }
  780. void MainFrame::quick_Help(){
  781. if( Editor *e=getEditor() ){
  782. //look for keyword at cursor...
  783. string t=e->getKeyword();if( !t.size() ) return;
  784. statusBar.SetPaneText( 0,quickHelp( t ).c_str() );
  785. if( t!=last_quick_help ){
  786. last_quick_help=t;
  787. return;
  788. }
  789. string url=commandURL( t );
  790. if( !url.size() ){
  791. string ex="Unable to open help file for \""+t+"\"";
  792. AfxMessageBox( ex.c_str(),MB_ICONWARNING );
  793. return;
  794. }
  795. if( HtmlHelp *h=findHelp() ){
  796. h->Navigate( url.c_str(),0,0 );
  797. }
  798. }
  799. }
  800. void MainFrame::OnActivate( UINT state,CWnd *other,BOOL min ){
  801. CFrameWnd::OnActivate( state,other,min );
  802. if( Editor *e=getEditor() ){
  803. if( state!=WA_ACTIVE && state!=WA_CLICKACTIVE ) return;
  804. e->SetFocus();
  805. }
  806. }