Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

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

Generated on Tue Jun 24 01:27:45 2008 for Advanced Strategic Command by  doxygen 1.4.2