2013-06-26 4 views
2

Я работаю над кросс-платформенным игровым движком, который отлично работает (я использую SDL). Однако я хочу простой способ отображения окна сообщения пользователю без необходимости полагаться на SDL или OpenGL (для рендеринга на экран), например. что, если окно уничтожено или еще не создано, поэтому я не могу отобразить сообщение на экране?SDL перекрестная платформа для Linux

Я реализовал функцию окна сообщений с несколькими реализациями для каждой платформы: в реализации Windows используется MessageBox, реализация Mac OS X использует NSAlert из Cocoa, и я не знаю, что я могу использовать для реализации Linux. Я думал о X11, потому что это то, что SDL использует для оконной обработки на linux.

Я пробовал другие ответы, но они либо слишком расплывчаты, либо требуют, чтобы я перестроил весь игровой движок с X11 или что-то в этом роде. Я пытаюсь найти решение, которое не зависит от приложения (например, функция MessageBox Windows, которая может использоваться в консольных приложениях).

ПРИМЕЧАНИЕ: Весь код для реализации Mac и Windows отлично работает, это просто реализация Linux, в которой мне нужна помощь.

О, и когда я компилирую в Mac OS X, я использую Objective-C++, поэтому я могу комбинировать Cocoa (Objective-C) с моей функцией C++ msgbox().

Вот код, который я до сих пор для реализации Windows, Mac &:

msgbox.h

#ifndef MSGBOX_H 
#define MSGBOX_H 

//Cross-platform message box method. 
#include "platform.h" 
#include "string.h" 

//This is my own cross platform enum for message boxes. 
//This enumeration 'overlaps' with some declarations in windows.h but that is fine. 
enum //Message box values. 
{ 
    MB_OK, //For OK message box and return value. 
    MB_OKCANCEL, 
    MB_YESNO, 
    MB_RETRYCANCEL, 
    MB_YESNOCANCEL, 
    MB_ABORTRETRYIGNORE, 
    MB_CANCELTRYCONTINUE, 
    MB_CANCEL, 
    MB_YES, 
    MB_NO, 
    MB_RETRY, 
    MB_IGNORE, 
    MB_TRYAGAIN, 
    MB_CONTINUE, 
    MB_ABORT, 
}; 

//The message box function (multiple implementations for each platform). 
int msgbox(string msg, string title, int buttons); 

#endif // MSGBOX_H 

msgbox.cpp

#include "msgbox.h" 

#if CURRENT_PLATFORM == PLATFORM_WINDOWS //We can use the windows API for our messagebox. 

#include <windows.h> //For the message box function. 
#define IDTRYAGAIN 10 //Some fixes to help this application compile. 
#define IDCONTINUE 11 

int msgbox(string msg, string title, int buttons) 
{ 
    //Display the mesagebox. 
    int retval = MessageBox(NULL, msg.c_str(), title.c_str(), buttons | MB_ICONEXCLAMATION | MB_SYSTEMMODAL); 

    //Map the windows return value to ours. 
    switch(retval) 
    { 
    case IDOK:  return MB_OK; 
    case IDCANCEL: return MB_CANCEL; 
    case IDYES:  return MB_YES; 
    case IDNO:  return MB_NO; 
    case IDRETRY: return MB_RETRY; 
    case IDIGNORE: return MB_IGNORE; 
    case IDTRYAGAIN:return MB_TRYAGAIN; 
    case IDCONTINUE:return MB_CONTINUE; 
    } 
} 

#elif CURRENT_PLATFORM == PLATFORM_MACOSX //Use Cocoa to display the message box. 

int msgbox(string msg, string title, int buttons) 
{ 
    NSString* defbutton = nil; 
    NSString* altbutton = nil; 
    NSString* otherbutton = nil; 

    switch(buttons) 
    { 
    default: 
    case MB_OK: 
     defbutton = @"Ok"; 
     break; 

    case MB_OKCANCEL: 
     defbutton = @"Ok"; 
     altbutton = @"Cancel"; 
     break; 

    case MB_RETRYCANCEL: 
     defbutton = @"Retry"; 
     altbutton = @"Cancel"; 
     break; 

    case MB_YESNO: 
     defbutton = @"Yes"; 
     altbutton = @"No"; 
     break; 

    case MB_YESNOCANCEL: 
     defbutton = @"Yes"; 
     altbutton = @"No"; 
     otherbutton = @"Cancel"; 
     break; 

    case MB_ABORTRETRYIGNORE: 
     defbutton = @"Abort"; 
     altbutton = @"Retry"; 
     otherbutton = @"Ignore"; 
     break; 

    case MB_CANCELTRYCONTINUE: 
     defbutton = @"Cancel"; 
     altbutton = @"Try Again"; 
     otherbutton = @"Continue"; 
     break; 
    } 

    NSAlert* alert = [NSAlert alertWithMessageText:[NSString  stringWithCString:title.c_str() encoding:[NSString defaultCStringEncoding]] 
           defaultButton:defbutton 
           alternateButton:altbutton 
            otherButton:otherbutton 
        informativeTextWithFormat:@"%s", msg.c_str()]; 

    //brings this 'application' to the front. 
    [[NSRunningApplication currentApplication]  activateWithOptions:NSApplicationActivateIgnoringOtherApps]; 
    NSInteger retval = [alert runModal]; 

    //Convert the NSAlert return values into my MB_* return values. 
    if(retval == NSAlertDefaultReturn) 
    { 
     switch(buttons) 
     { 
     case MB_OK: 
     case MB_OKCANCEL: 
      return MB_OK; 

     case MB_YESNO: 
     case MB_YESNOCANCEL: 
      return MB_YES; 

     case MB_ABORTRETRYIGNORE: 
      return MB_ABORT; 

     case MB_CANCELTRYCONTINUE: 
      return MB_CANCEL; 

     case MB_RETRYCANCEL: 
      return MB_RETRY; 
     } 
    } else if(retval == NSAlertAlternateReturn) 
    { 
     switch(buttons) 
     { 
     case MB_OKCANCEL: 
     case MB_RETRYCANCEL: 
      return MB_CANCEL; 

     case MB_YESNO: 
     case MB_YESNOCANCEL: 
      return MB_NO; 

     case MB_ABORTRETRYIGNORE: 
      return MB_RETRY; 

     case MB_CANCELTRYCONTINUE: 
      return MB_TRYAGAIN; 
     } 
    } else if(retval == NSAlertOtherReturn) 
    { 
     switch(buttons) 
     { 
     case MB_YESNOCANCEL: 
      return MB_CANCEL; 

     case MB_ABORTRETRYIGNORE: 
      return MB_IGNORE; 

     case MB_CANCELTRYCONTINUE: 
      return MB_CONTINUE; 
     } 
    } 

    return NULL; 
} 

#else 

int msgbox(string msg, string title, int buttons) 
{ 
    //WHAT DO I DO?????? 
    return 0; 
} 

//#error No implementation of message boxes on current platform! 
#endif // CURRENT_PLATFORM 

EDIT: Я предпочитаю не использовать Qt по нескольким причинам: он слишком тяжелый, он не работает на моем основном компьютере & i t не дает мне достаточного контроля над программой. Во всяком случае, я пытаюсь превратить этот игровой движок с нуля в качестве хобби проекта, не полагаясь на другие библиотеки (я собираюсь заменить SDL в конечном итоге своим собственным кодом).

+0

Почему бы не использовать кросс-платформенный набор инструментов GUI, например Qt? Тогда вам не нужно беспокоиться о таких вещах. –

+0

Я собираюсь настроить больше платформ за пределами поддержки Qt. Кроме того, Qt слишком тяжел для моей симпатии и не дает мне достаточного контроля над такими вещами, как цикл сообщений и т. Д. - я уже пробовал Qt, и он не работает на моем основном компьютере разработки. – hddh

+0

В чем вопрос? Существует несколько возможностей для отображения окна сообщений в Linux без раздутой библиотеки, например, с помощью Xlib или OpenMotif. – scai

ответ

2

Я создал простую функцию обертки, которая использует SDL_ShowMessageBox из SDL 2.0 и заменяет предыдущий код, который я отправил, и он работает на Linux, Mac & Windows.

SDL 2.0 можно найти по адресу (http://www.libsdl.org/tmp/download-2.0.php).

Вы должны сами создать SDL 2 самостоятельно - просто загрузите исходный код на представленной странице, затем извлеките архив и следуйте инструкциям по установке в INSTALL.txt (после сборки SDL 2 библиотеки помещаются в/usr/local/lib - вам может потребоваться переместить их или сообщить своему компоновщику, где они есть (включенные файлы находятся в каталоге include).

Вот код:

Пример (с помощью моей функции):

int i = showMessageBox(mySDLWindow, "Message", "Title", 3, MB_BUTTONS("BUTTON 1", "BUTTON 2", "BUTTON 3"), 0); 
printf("Button %i was pressed", i + 1); 

messagebox.h:

//Cross-platform message box method. 
#include <string> 
#include <SDL/SDL.h> //SDL 2.0 header file 

//Helper macro 
#define MB_BUTTONS(...) ((char*[]) {__VA_ARGS__}) 

//Flexible message box function. 
//Returns the index of button pressed on success or a negative value on a failure. 
//The parent argument can be set to NULL if not available. 
int showMessageBox(SDL_Window *parent, std::string msg, std::string title, 
        int count, char* buttons[], int defbutton = 0); 

messagebox.cpp:

//Complex function 
int showMessageBox(SDL_Window *parent, string msg, string title, 
        int count, char* buttons[], int defbutton) 
{ 
    //Variables. 
    int resultButton = 0; 
    SDL_MessageBoxData mbdata; 

    //Set the message box information. 
    mbdata.flags = SDL_MESSAGEBOX_INFORMATION; 
    mbdata.message = msg.c_str(); 
    mbdata.title = title.c_str(); 
    mbdata.colorScheme = NULL; 
    mbdata.window = parent; 
    mbdata.numbuttons = count; 

    //Allocate buttons. 
    SDL_MessageBoxButtonData *butarray = new SDL_MessageBoxButtonData[mbdata.numbuttons]; 

    //Set the button values. 
    for(unsigned char i = 0; i < mbdata.numbuttons; i++) 
    { 
     //Is this button the default button? 
     if(i == defbutton) 
     { 
      butarray[i].flags = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT; 
     } else 
     { 
      butarray[i].flags = 0; 
     } 

     //Set button text. 
     if(buttons[i] != NULL) 
     { 
      butarray[i].text = buttons[i]; 
     } 

     //Set button ID. 
     butarray[i].buttonid = i; 
    } 

    //Set the message box data's button array. 
    mbdata.buttons = butarray; 

    //Display the message box. 
    int retval = SDL_ShowMessageBox(&mbdata, &resultButton); 

    //Deallocate the buttons array to prevent memory leaks. 
    delete[] butarray;   

    //Return the result (-1 on failure or if the dialog was closed). 
    return retval < 0 ? -1 : resultButton; 
} 
+0

"вам может потребоваться переместить их или сообщить своему компоновщику, где они находятся" ... если вы используете дистрибутив Debian '/ usr/local', должны находиться в различных' PATH ', необходимых для' pkg-config 'для сбора информационных файлов SDL2. Обычно 'sudo ldconfig' тоже не болит. – genpfault

+0

Да, я использовал ldconfig, чтобы добавить usr/local/lib в путь – hddh

1

Я использую gdialog/kdialog и передаю сообщение в командной строке. Вот код:

#include <cstdlib> 
#include <string> 

const char * getDialogCommand() { 
    if (::system(NULL)) { 
    if (::system("which gdialog") == 0) 
     return "gdialog"; 
    else if (::system("which kdialog") == 0) 
     return "kdialog"; 
    } 
    return NULL; 
} 

void showWarning(const std::string & warning) { 
    const char * dialogCommand = getDialogCommand(); 
    if (dialogCommand) { 
    std::string command = dialogCommand; 
    command += " --title \"Message Box Title\" --msgbox \"" + warning + "\""; 
    int result = ::system(command.c_str()); 
    if (result == 0) 
     return; // success 
    } 

    // fail-safe method here, using stdio perhaps, depends on your application 
} 

Это не самый надежный код в мире, но, по крайней мере, в наших играх, я никогда не видел, что это провал. По коду это зависит от зависимости, однако вам нужно убедиться, что вы не используете символы в строке, которые завинчивают командную строку, то есть escape-символы, такие как <,>, &,! \ И все, кроме ASCII.

Также обратите внимание, что SDL 2.0 имеет SDL_ShowMessageBox.

+0

Это зависит от установки 'gdialog' или' kdialog'. Существует также «xmessage», который, вероятно, доступен для большего количества систем, но менее интересен. – scai

+0

Я еще не знал, что SDL 2.0 вышел. Где я могу получить файлы .lib и header? (Я использую GCC/MinGW). – hddh

+0

Ничего, я нашел библиотеки SDL 2.0. – hddh