messagedlg.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           messagedlg.cpp  -  description
00003                              -------------------
00004     begin                : Mon M� 24 2003
00005     copyright            : (C) 2003 by Martin Bickel
00006     email                : bickel@asc-hq.org
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include "messagedlg.h"
00019 #include "gamemap.h"
00020 
00021 
00022 
00023 #include "paradialog.h"
00024 #include "gameeventsystem.h"
00025 
00026 
00027 #include "dialog.h"
00028 #include "dlg_box.h"
00029 #include "spfst.h"
00030 
00031 #include "widgets/textrenderer.h"
00032 
00033 #include "messages.h"
00034 #include "pgwidget.h"
00035 #include "widgets/playerselector.h"
00036 #include "pgrichedit.h"
00037 #include "pgmultilineedit.h"
00038 #include "pgtooltiphelp.h"
00039 
00040 #include "dialogs/fieldmarker.h"
00041 #include "dialogs/selectionwindow.h"
00042 
00043 #include "spfst-legacy.h"
00044 
00045 class  NewMessage : public ASC_PG_Dialog {
00046       GameMap* gamemap;
00047       Message* message;
00048       PG_MultiLineEdit* editor;
00049       PlayerSelector* to;
00050       PlayerSelector* cc;
00051       bool reminder;
00052       
00053       bool ok()
00054       {
00055          if ( !message ) {
00056             message = new Message ( editor->GetText(), gamemap, 0, 1 << actmap->actplayer );
00057             gamemap->unsentmessage.push_back ( message );
00058          } else {
00059             message->text = editor->GetText();
00060          }
00061 
00062          if ( reminder ) {
00063             message->cc = 0;
00064             message->to = 1 << actmap->actplayer;
00065          } else {
00066             message->cc = cc->getSelectedPlayers();
00067             message->to = to->getSelectedPlayers();
00068          }
00069          message->reminder = reminder;
00070          
00071          QuitModal();
00072          return true;
00073       }
00074       
00075       bool cancel()
00076       {
00077          QuitModal();
00078          return true;
00079       }
00080 
00081       bool insertCursorCoordinates()
00082       {
00083          MapCoordinate pos = gamemap->getCursor();
00084          if ( pos.valid() ) {
00085             editor->InsertText( pos.toString() );
00086             return true;
00087          } else
00088             return false;
00089       }
00090 
00091       bool insertCoordinates()
00092       {
00093          SelectFromMap::CoordinateList coordinates;
00094          
00095          SelectFromMap sfm( coordinates, gamemap );
00096          sfm.Show();
00097          sfm.RunModal();
00098          
00099          ASCString text = "#coord("; 
00100          for ( SelectFromMap::CoordinateList::iterator i = coordinates.begin(); i != coordinates.end(); ++i ) {
00101             if ( i != coordinates.begin() )
00102                text += ";";
00103             text += ASCString::toString( i->x ) + "/" + ASCString::toString( i->y );
00104          }
00105          text += ")#";
00106          editor->InsertText( text );
00107          return true;
00108       }
00109 
00110       bool eventKeyDown(const SDL_KeyboardEvent* key)
00111       {
00112          int mod = SDL_GetModState() & ~(KMOD_NUM | KMOD_CAPS | KMOD_MODE);
00113          if ( (mod & KMOD_CTRL) &&( key->keysym.sym == SDLK_r )) 
00114             return insertCursorCoordinates();
00115 
00116          return ASC_PG_Dialog::eventKeyDown(key);
00117       }
00118 
00119    public:
00120       NewMessage ( GameMap* gamemap, Message* msg = NULL, bool reminder = false ); 
00121       
00122       void Show(bool fade = false ) {
00123          editor->EditBegin();
00124          ASC_PG_Dialog::Show(fade);
00125       }
00126       
00127 };
00128 
00129 
00130 NewMessage :: NewMessage ( GameMap* gamemap, Message* msg, bool reminder ) : ASC_PG_Dialog( NULL, PG_Rect( -1, -1, 600, 500 ), "new message" )
00131 {
00132    this->gamemap = gamemap;
00133    message = msg;
00134    if ( message )
00135       reminder = message->reminder;
00136    this->reminder = reminder;
00137     
00138    int startY = 30;
00139    
00140    if ( !reminder )  {
00141       new PG_Label ( this, PG_Rect( 20, 30, 30, 20 ), "TO:");
00142       to = new PlayerSelector ( this, PG_Rect( 50, 30, 150, 150 ), gamemap, true, 1 << gamemap->actplayer );
00143       if ( msg )
00144          to->setSelection( msg->to );
00145       
00146       new PG_Label ( this, PG_Rect( 210, 30, 30, 20 ), "CC:" );
00147       cc = new PlayerSelector ( this, PG_Rect( 240, 30, 150, 150 ), gamemap, true, 1 << gamemap->actplayer );
00148       if ( msg )
00149          cc->setSelection( msg->cc );
00150       
00151       startY += 170;
00152    }
00153    
00154    editor = new PG_MultiLineEdit( this, PG_Rect(20, startY, Width() - 140, Height() - startY - 10 ));
00155    if ( message )
00156       editor->SetText( message->text );
00157    editor->SetInputFocus();
00158     
00159    AddStandardButton("OK")->sigClick.connect( SigC::slot( *this, &NewMessage::ok ));
00160    AddStandardButton("Cancel")->sigClick.connect( SigC::slot( *this, &NewMessage::cancel ));
00161    AddStandardButton("");
00162    AddStandardButton("Coordinates")->sigClick.connect( SigC::slot( *this, &NewMessage::insertCoordinates ));
00163    PG_Button* coord = AddStandardButton("Cursor Coord");
00164    coord->sigClick.connect( SigC::slot( *this, &NewMessage::insertCursorCoordinates ));
00165    new PG_ToolTipHelp ( coord, "ctrl-r");
00166   
00167 }
00168       
00169 
00170 class IngameMessageViewer : public ASC_PG_Dialog {
00171       TextRenderer* textViewer;
00172       const Message* message;
00173       PG_Label* from;
00174       PG_Label* to;
00175       PG_Label* cc;
00176       bool keepMessage;
00177 
00178       bool ok()
00179       {
00180          keepMessage = false;
00181          Hide();
00182          QuitModal();
00183          return true;
00184       };
00185 
00186       bool keep()
00187       {
00188          keepMessage = true;
00189          Hide();
00190          QuitModal();
00191          return true;
00192       };
00193       
00194 
00195       PG_Label* addHeaderLine( int y, const ASCString& name )
00196       {
00197          PG_Rect f( 10, y, Width() - 20, 25 );
00198 
00199          new PG_Label( this, PG_Rect( f.x, f.y, 50, f.h ), name );
00200          Emboss* emb = new Emboss( this, PG_Rect( f.x + 50, f.y, f.w - 50, f.h ), true );
00201          return new PG_Label( emb, PG_Rect( 2, 2, emb->w - 4, emb->h - 4) );
00202       }
00203 
00204    public:
00205       IngameMessageViewer ( const ASCString& title, const Message& msg, PG_Rect rect = PG_Rect( 50, 50, 500, 400 ), bool autoHeader = true ) : ASC_PG_Dialog ( NULL, rect, title ), message(NULL), from(NULL), to(NULL), cc(NULL)
00206       {
00207 
00208          keepMessage = false;
00209          int footerHeight;
00210          /* if ( !buttonText.empty() ) { */
00211          if ( msg.reminder ) {
00212             PG_Button* b = new PG_Button( this, PG_Rect( Width() - 70, Height() - 40, 60, 30), "Done" );
00213             b->sigClick.connect( SigC::slot( *this, &IngameMessageViewer::ok) );
00214             
00215             PG_Button* b2 = new PG_Button( this, PG_Rect( Width() - 140, Height() - 40, 60, 30), "Keep" );
00216             b2->sigClick.connect( SigC::slot( *this, &IngameMessageViewer::keep) );
00217          } else {
00218             PG_Button* b = new PG_Button( this, PG_Rect( Width() - 110, Height() - 40, 100, 30), "OK" );
00219             b->sigClick.connect( SigC::slot( *this, &IngameMessageViewer::ok) );
00220          }
00221             footerHeight = 50;
00222          /* } else
00223             footerHeight = 10; */
00224 
00225          int y = 40;
00226          if ( !msg.getFromText( actmap ).empty()  ) {
00227 
00228 
00229             from = addHeaderLine( y, "From:");
00230             y += 30;
00231 
00232             if ( !autoHeader || (msg.to && !(msg.from & 512))  ) {
00233                to = addHeaderLine( y, "To:");
00234                y += 30;
00235             }
00236 
00237             if ( !autoHeader || msg.cc ) {
00238                cc = addHeaderLine( y, "CC:");
00239                y += 30;
00240             }
00241 
00242 
00243          }
00244 
00245          PG_Rect r ( 10, y, Width() - 20, Height() - (y + footerHeight ));
00246          new Emboss( this, r, true );
00247 
00248 #ifdef RICHEDIT
00249          PG_RichEdit* re = new PG_RichEdit( this, PG_Rect(r.x + 2, r.y+2, r.w-4, r.h-4));
00250 
00251          ASCString text  = msg.text;
00252          while ( text.find ( "#crt#" ) != ASCString::npos )
00253             text.replace ( text.find  ("#crt#"), 5, " \n");
00254 
00255          re->SetText( text );
00256          re->SetTransparency(255);
00257          textViewer = re;
00258 #else
00259          TextRenderer* tr = new TextRenderer( this, PG_Rect(r.x + 2, r.y+2, r.w-4, r.h-4));
00260          tr->SetText( msg.text );
00261          textViewer = tr;
00262 #endif
00263          SetMessage( msg );
00264       };
00265 
00266       void SetMessage( const Message& msg )
00267       {
00268          if ( &msg != message) {
00269             PG_Application::BulkModeActivator bulk;
00270             textViewer->SetText( msg.text );
00271 
00272             if ( from )
00273                from->SetText( msg.getFromText( actmap ));
00274 
00275             if ( cc )
00276                cc->SetText( msg.getCcText( actmap ));
00277 
00278             if ( to )
00279                to->SetText( msg.getToText( actmap ));
00280 
00281 
00282             bulk.disable();
00283             Show();
00284             message = &msg;
00285          } else
00286             Show();
00287       };
00288 
00289 
00290       void      Hide (bool fade=false)
00291       {
00292          ASC_PG_Dialog::Hide(fade);
00293          getPGApplication().queueWidgetForDeletion( this );
00294       }
00295 
00296       bool eventKeyDown (const SDL_KeyboardEvent *key)
00297       {
00298          if (  key->keysym.sym == SDLK_ESCAPE ) {
00299             quitModalLoop(10);
00300             return true;
00301          }
00302          if (  key->keysym.sym == SDLK_RETURN || key->keysym.sym == SDLK_KP_ENTER ) {
00303             quitModalLoop(11);
00304             return true;
00305          }
00306          if (  key->keysym.sym == SDLK_SPACE ) {
00307             quitModalLoop(12);
00308             return true;
00309          }
00310          
00311          int mod = SDL_GetModState() & ~(KMOD_NUM | KMOD_CAPS | KMOD_MODE);
00312          if ( mod & KMOD_CTRL ) 
00313             if ( key->keysym.sym == 's' )
00314                textViewer->saveText( mod & KMOD_SHIFT );
00315          
00316          
00317          return ASC_PG_Dialog::eventKeyDown( key );
00318       };
00319 
00320       bool getKeepMessage() 
00321       {
00322          return keepMessage;
00323       }
00324       
00325       ~IngameMessageViewer()
00326       {
00327          displayLogMessage ( 9, "~IngameMessageViewer\n" );
00328       }
00329       
00330 };
00331 
00332 
00333 
00334 
00335 void newmessage()
00336 {
00337    if ( Player::getHumanPlayerNum( actmap ) < 2 ) {
00338       infoMessage( "nobody is listening to our transmissions");
00339       return;
00340    }
00341    
00342    // PG_LineEdit::SetBlinkingTime(-1);
00343         
00344    NewMessage  nm ( actmap );
00345    nm.Show();
00346    nm.RunModal();
00347 }
00348 
00349 void newreminder()
00350 {
00351    NewMessage  nm ( actmap, NULL, true );
00352    nm.Show();
00353    nm.RunModal();
00354 }
00355 
00356 
00357 
00358 
00359 class MessageLineWidget: public SelectionWidget
00360 {
00361        Message* message;
00362       ASCString msgtime;
00363       GameMap* map;
00364    public:
00365       MessageLineWidget( PG_Widget* parent, const PG_Point& pos, int width, Message* msg, GameMap* gamemap );
00366 
00367       ASCString getName() const
00368       {
00369          if ( message->from > 0 && message->from <= 255 )
00370             return map->getPlayer(getFirstBit(message->from)).getName();
00371          else
00372             if ( message->from & ( 1 << 9 ))
00373                return "system";
00374          return "";
00375       };
00376 
00377       Message* getMessage() const { return message; };
00378 
00379    protected:
00380 
00381       void display( SDL_Surface * surface, const PG_Rect & src, const PG_Rect & dst )
00382       {
00383       }
00384       ;
00385 };
00386 
00387 
00388 
00389 MessageLineWidget::MessageLineWidget( PG_Widget* parent, const PG_Point& pos, int width,  Message* msg, GameMap* gamemap ) : SelectionWidget( parent, PG_Rect( pos.x, pos.y, width, 20 )), message( msg ), map(gamemap)
00390 {
00391 #ifndef ctime_r
00392    msgtime = ctime( &msg->time);
00393 #else
00394 
00395    char c[100];
00396    ctime_r( &msg->time, c );
00397    msgtime  = c;
00398 #endif
00399 
00400    int col1 =        width * 3 / 10;
00401    int col2 = col1 + width * 4 / 10;
00402 
00403 
00404    PG_Label* lbl1 = new PG_Label( this, PG_Rect( 0, 0, col1 - 10, Height() ), getName() );
00405    lbl1->SetFontSize( lbl1->GetFontSize() -2 );
00406 
00407    PG_Label* lbl2 = new PG_Label( this, PG_Rect( col1, 0, col2-col1-10, Height() ), msgtime );
00408    lbl2->SetFontSize( lbl2->GetFontSize() -2 );
00409 
00410    int x = 0;
00411    for ( int i = 0; i< gamemap->getPlayerCount(); ++i )
00412       if ( msg->to & (1 << i)) {
00413          new ColoredBar( gamemap->getPlayer(i).getColor(), this, PG_Rect( col2 + x, 0, 15 , 15 ));
00414          x += 18;
00415       }
00416 
00417    SetTransparency( 255 );
00418 };
00419 
00420 
00421 class MessageListItemFactory: public SelectionItemFactory  {
00422    protected:
00423       const MessagePntrContainer& messageContainer;
00424       MessagePntrContainer::const_iterator it;
00425       GameMap* gamemap;
00426 
00427    public:
00428       MessageListItemFactory( const MessagePntrContainer& messages, GameMap* g );
00429       
00430       void restart();
00431       
00432       SelectionWidget* spawnNextItem( PG_Widget* parent, const PG_Point& pos );
00433       
00434       void itemMarked( const SelectionWidget* widget );
00435       void itemSelected( const SelectionWidget* widget, bool mouse );
00436 
00437       SigC::Signal1<void, Message* > messageSelected;
00438 };
00439 
00440 
00441 MessageListItemFactory::MessageListItemFactory( const MessagePntrContainer& messages, GameMap* map ) : messageContainer ( messages ), gamemap(map)
00442 {
00443    restart();
00444 };
00445 
00446 
00447 void MessageListItemFactory::restart()
00448 {
00449    it = messageContainer.begin();
00450 };
00451 
00452 SelectionWidget* MessageListItemFactory::spawnNextItem( PG_Widget* parent, const PG_Point& pos )
00453 {
00454    if ( it != messageContainer.end() )
00455       return new MessageLineWidget( parent, pos, parent->Width() - 15, *(it++), gamemap );
00456    else
00457       return NULL;
00458 };
00459 
00460 
00461 void MessageListItemFactory::itemMarked( const SelectionWidget* widget )
00462 {
00463    if ( !widget )
00464       return;
00465 
00466    const MessageLineWidget* mlw = dynamic_cast< const MessageLineWidget*>(widget);
00467    assert( mlw );
00468    messageSelected( mlw->getMessage() );
00469 }
00470 
00471 void MessageListItemFactory::itemSelected( const SelectionWidget* widget, bool mouse )
00472 {
00473    if ( !widget )
00474       return;
00475 
00476    const MessageLineWidget* fw = dynamic_cast<const MessageLineWidget*>(widget);
00477    assert( fw );
00478    messageSelected( fw->getMessage() );
00479 }
00480 
00481 
00482 
00483 
00484 class MessageSelectionWindow : public ASC_PG_Dialog {
00485    private:
00486       bool edit;
00487 
00488       bool viewerDeleted( const PG_MessageObject* obj )
00489       {
00490          if ( viewer == obj )
00491             viewer = NULL;
00492          return true;
00493       };
00494 
00495       bool ProcessEvent ( const SDL_Event *   event, bool bModal = false  )
00496       {
00497          if ( ASC_PG_Dialog::ProcessEvent( event, bModal ) )
00498             return true;
00499 
00500          if ( viewer ) 
00501             if ( viewer->ProcessEvent( event, bModal ))
00502                return true;
00503          
00504          return false;
00505       };
00506 
00507       bool eventKeyDown(const SDL_KeyboardEvent* key)
00508       {
00509          
00510          int mod = SDL_GetModState() & ~(KMOD_NUM | KMOD_CAPS | KMOD_MODE);
00511          if ( mod & KMOD_CTRL ) 
00512             if ( key->keysym.sym == 's' )
00513                if ( viewer )
00514                   return viewer->eventKeyDown( key );
00515          
00516          return ASC_PG_Dialog::eventKeyDown(key);
00517       }
00518 
00519       
00520 
00521    protected:
00522       void messageSelected( Message* msg );
00523       IngameMessageViewer* viewer;
00524 
00525    public:
00526       MessageSelectionWindow( PG_Widget *parent, const PG_Rect &r, const MessagePntrContainer& messages, GameMap* g, bool editable );
00527 };
00528 
00529 void MessageSelectionWindow::messageSelected(  Message* msg )
00530 {
00531    if ( edit ) {
00532       NewMessage  nm ( actmap, msg );
00533       nm.Show();
00534       nm.RunModal();
00535    } else {
00536       if ( !viewer ) {
00537          PG_Rect r ( my_xpos + Width(), my_ypos, min( PG_Application::GetScreenWidth()/2, 500), Height() );
00538          viewer = new IngameMessageViewer( "Message", *msg, r );
00539          viewer->Show();
00540          viewer->sigDelete.connect( SigC::slot( *this, &MessageSelectionWindow::viewerDeleted ));
00541       } else 
00542          viewer->SetMessage( *msg );
00543    }
00544 };
00545 
00546 
00547 MessageSelectionWindow::MessageSelectionWindow( PG_Widget *parent, const PG_Rect &r, const MessagePntrContainer& messages, GameMap* gamemap, bool editable ) 
00548    : ASC_PG_Dialog( parent, r, "Messages" ), edit( editable), viewer(NULL)
00549 {
00550   
00551    MessageListItemFactory* factory = new MessageListItemFactory( messages, gamemap );
00552    factory->messageSelected.connect ( SigC::slot( *this, &MessageSelectionWindow::messageSelected ));
00553 
00554    ItemSelectorWidget* isw = new ItemSelectorWidget( this, PG_Rect(10, GetTitlebarHeight(), r.Width() - 10, r.Height() - GetTitlebarHeight()), factory );
00555    isw->sigQuitModal.connect( SigC::slot( *this, &ItemSelectorWindow::QuitModal));
00556 };
00557 
00558 
00559 
00560 
00561 void viewmessages ( const char* title, const MessagePntrContainer& msg, bool editable  )    // mode : 0 verschickte ; 1 empfangene
00562 {
00563    int ww = min( PG_Application::GetScreenWidth()/2, 500 );
00564    PG_Rect r ( max(PG_Application::GetScreenWidth()/2,0) - ww, -1, ww, 500 );
00565    MessageSelectionWindow msw ( NULL, r, msg, actmap, editable );
00566    msw.Show();
00567    msw.RunModal();
00568 }
00569 
00570 
00571 
00572 bool viewmessage ( const Message& message )
00573 {
00575    if ( PG_Application::GetScreen()==NULL )
00576       return false;
00577    
00578    assert( !legacyEventSystemActive() );
00579    IngameMessageViewer igm( "incoming message...", message );
00580    igm.Show();
00581    igm.RunModal();
00582    return igm.getKeepMessage();
00583 }
00584 
00585 
00586 
00587 void checkJournal( Player& player )
00588 {
00589    GameMap* actmap = player.getParentMap();
00590    
00591    if ( actmap->lastjournalchange.abstime )
00592       if ( (actmap->lastjournalchange.turn() == actmap->time.turn() ) ||
00593             (actmap->lastjournalchange.turn() == actmap->time.turn()-1  &&  actmap->lastjournalchange.move() > actmap->actplayer ) )
00594                viewjournal( false );
00595 }
00596 
00597 void viewjournal ( bool showEmptyDlg )
00598 {
00599    if ( !actmap->gameJournal.empty() ) {
00600       tviewanytext vat;
00601       vat.init ( "journal", actmap->gameJournal.c_str() );
00602       vat.run();
00603       vat.done();
00604    } else
00605       if ( showEmptyDlg )
00606          infoMessage("no entries to journal yet");
00607 
00608 }
00609 
00610 void editjournal ( void )
00611 {
00612    MultilineEdit ej ( actmap->newJournal, "Journal" );
00613    ej.init ();
00614    ej.run ();
00615    if ( ej.changed() )
00616       actmap->lastjournalchange.set ( actmap->time.turn(), actmap->actplayer );
00617    ej.done ();
00618 }
00619 
00620 
00621 void viewunreadmessages ( Player& player )
00622 {
00623 
00629    static bool isRunning = false;
00630    if ( isRunning )
00631       return;
00632 
00633    VariableLocker l( isRunning );
00634    
00635    if( (player.stat == Player::human || player.stat == Player::supervisor) && player.getParentMap()->getPlayerView() == player.getPosition() ) {
00636       MessagePntrContainer::iterator mi = player.unreadmessage.begin();
00637       while ( mi != player.unreadmessage.end()  ) {
00638          Message* msg = *mi;
00639          bool keep = viewmessage ( *msg );
00640          
00641          if ( keep )
00642             ++mi;
00643          else {
00644             player.oldmessage.push_back ( *mi );
00645             mi = player.unreadmessage.erase ( mi );
00646          }
00647       }
00648    }
00649 }

Generated on Mon May 21 01:26:35 2012 for Advanced Strategic Command by  doxygen 1.5.1