Torque3D Documentation / _generateds / x86UNIXMessageBox.client.cpp

x86UNIXMessageBox.client.cpp

Engine/source/platformX86UNIX/x86UNIXMessageBox.client.cpp

More...

Public Functions

max(Type v1, Type v2)
min(Type v1, Type v2)

Detailed Description

Public Defines

MessageBox_ButtonBoxHeight() 22
MessageBox_ButtonBoxWidth() 60
MessageBox_ButtonHMargin() 10
MessageBox_ButtonSpacer() 20
MessageBox_ButtonVMargin() 10
MessageBox_LineHMargin() 10
MessageBox_LineSpacer() 2
MessageBox_LineVMargin() 10
MessageBox_MaxWinHeight() 600
MessageBox_MaxWinWidth() 800
MessageBox_MinWinWidth() 450

Public Functions

max(Type v1, Type v2)

min(Type v1, Type v2)

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include <stdio.h>
 25#include <stdlib.h>
 26#include <string.h>
 27
 28#include <X11/Xlib.h>
 29#include <X11/Xutil.h>
 30#include <X11/Xatom.h>
 31
 32#include "platformX86UNIX/x86UNIXMessageBox.h"
 33
 34#define MessageBox_MaxWinWidth 800
 35#define MessageBox_MaxWinHeight 600
 36#define MessageBox_MinWinWidth 450
 37
 38#define MessageBox_ButtonBoxWidth 60
 39#define MessageBox_ButtonBoxHeight 22
 40#define MessageBox_ButtonSpacer 20
 41#define MessageBox_ButtonVMargin 10
 42#define MessageBox_ButtonHMargin 10
 43
 44#define MessageBox_LineSpacer 2
 45#define MessageBox_LineVMargin 10
 46#define MessageBox_LineHMargin 10
 47
 48XMessageBoxButton::XMessageBoxButton()
 49{
 50   strcpy(mLabel, "");
 51   mClickVal = -1;
 52   mLabelWidth = mX = mY = mWidth = mHeight = mMouseX = mMouseX = -1;
 53   mMouseDown = false;
 54}
 55
 56XMessageBoxButton::XMessageBoxButton(const char* label, int clickVal)
 57{
 58   strncpy(mLabel, label, LabelSize);
 59   mClickVal = clickVal;
 60   mLabelWidth = mX = mY = mWidth = mHeight = mMouseX = mMouseX = -1;
 61   mMouseDown = false;
 62}
 63
 64XMessageBox::XMessageBox(Display* display)
 65{
 66   mMessage = "";
 67   mFS = NULL;
 68   mDisplay = display;
 69}
 70
 71XMessageBox::~XMessageBox()
 72{
 73   clearMessageLines();
 74   if (mDisplay != NULL)
 75   {
 76      mDisplay = NULL;
 77   }
 78}
 79
 80int XMessageBox::alertOK(const char *windowTitle, const char *message)
 81{
 82   mMessage = message;
 83   mTitle = windowTitle;
 84   mButtons.clear();
 85   mButtons.push_back(XMessageBoxButton("OK", OK));
 86   return show();
 87}
 88
 89int XMessageBox::alertOKCancel(const char *windowTitle, const char *message)
 90{
 91   mMessage = message;
 92   mTitle = windowTitle;
 93   mButtons.clear();
 94   mButtons.push_back(XMessageBoxButton("OK", OK));
 95   mButtons.push_back(XMessageBoxButton("Cancel", Cancel));
 96   return show();
 97}
 98
 99int XMessageBox::alertRetryCancel(const char *windowTitle, const char *message)
100{
101   mMessage = message;
102   mTitle = windowTitle;
103   mButtons.clear();
104   mButtons.push_back(XMessageBoxButton("Retry", Retry));
105   mButtons.push_back(XMessageBoxButton("Cancel", Cancel));
106   return show();
107}
108
109int XMessageBox::alertAssert(const char *windowTitle, const char *message)
110{
111    mMessage = message;
112    mTitle = windowTitle;
113    mButtons.clear();
114    mButtons.push_back(XMessageBoxButton("Exit", OK));
115    mButtons.push_back(XMessageBoxButton("Ignore", Cancel));
116    mButtons.push_back(XMessageBoxButton("Ignore All", IgnoreAll));
117    mButtons.push_back(XMessageBoxButton("Debug", Retry));
118    return show();
119}
120
121void XMessageBox::repaint()
122{
123   int white = WhitePixel(mDisplay, DefaultScreen(mDisplay));
124   int black = BlackPixel(mDisplay, DefaultScreen(mDisplay));
125
126   int x = 0;
127   int y = 0;
128
129   // line V margin
130   y = y + MessageBox_LineVMargin * 2;
131
132   // line H margin 
133   x = MessageBox_LineHMargin;
134
135   XSetForeground(mDisplay, mGC, black);
136   for (unsigned int i = 0; i < mMessageLines.size(); ++i)
137   {
138      XDrawString(mDisplay, mWin, mGC, x, y, mMessageLines[i], 
139         strlen(mMessageLines[i]));
140      if (i < (mMessageLines.size() - 1))
141         y = y + MessageBox_LineSpacer + mFontHeight;
142   }
143   XFlush(mDisplay);
144
145   // line V margin
146   y = y + MessageBox_LineVMargin;
147
148   int maxButWidth = MessageBox_ButtonBoxWidth;
149   int maxButHeight = MessageBox_ButtonBoxHeight;
150
151   // compute size of text labels on buttons
152   int fgColor, bgColor;
153
154   int fontDirection, fontAscent, fontDescent;
155   Vector<XMessageBoxButton>::iterator iter;
156   for (iter = mButtons.begin(); iter != mButtons.end(); ++iter)
157   {
158      XCharStruct strInfo;
159      XTextExtents(mFS, iter->getLabel(), strlen(iter->getLabel()), 
160         &fontDirection, &fontAscent, &fontDescent,
161         &strInfo);
162//       if (maxButWidth < strInfo.width)
163//          maxButWidth = strInfo.width;
164//       if (maxButHeight < (strInfo.ascent + strInfo.descent))
165//          maxButHeight = (strInfo.ascent + strInfo.descent);
166      iter->setLabelWidth(strInfo.width);
167   }
168   int buttonBoxWidth = maxButWidth;
169   int buttonBoxHeight = maxButHeight;
170
171   // draw buttons
172   // button V margin
173   y = y + MessageBox_ButtonVMargin;
174
175   // center the buttons 
176   x = MessageBox_ButtonHMargin + (mMBWidth - getButtonLineWidth()) / 2;
177
178   for (iter = mButtons.begin(); iter != mButtons.end(); ++iter)
179   {
180      if (iter->drawReverse())
181      {
182         fgColor = white;
183         bgColor = black;
184      }
185      else
186      {
187         fgColor = black;
188         bgColor = white;
189      }
190
191      XSetForeground(mDisplay, mGC, bgColor);
192      XFillRectangle(mDisplay, mWin, mGC, x, y, 
193         buttonBoxWidth, buttonBoxHeight);
194      XSetForeground(mDisplay, mGC, fgColor);
195      XDrawRectangle(mDisplay, mWin, mGC, x, y, 
196         buttonBoxWidth, buttonBoxHeight);
197      XDrawString(mDisplay, mWin, mGC, 
198         x + ((buttonBoxWidth - iter->getLabelWidth()) / 2),
199         y + mFontAscent + ((buttonBoxHeight - mFontAscent) / 2),
200         iter->getLabel(),
201         strlen(iter->getLabel()));
202      iter->setButtonRect(x, y, buttonBoxWidth, buttonBoxHeight);
203      x = x + buttonBoxWidth + MessageBox_ButtonSpacer;
204   }   
205}
206
207template <class Type>
208static inline Type max(Type v1, Type v2)
209{
210   if (v1 <= v2)
211      return v2;
212   else
213      return v1;
214}
215
216template <class Type>
217static inline Type min(Type v1, Type v2)
218{
219   if (v1 > v2)
220      return v2;
221   else
222      return v1;
223}
224
225void XMessageBox::clearMessageLines()
226{
227   Vector<char*>::iterator iter;
228   for (iter = mMessageLines.begin(); iter != mMessageLines.end(); ++iter)
229      delete [] *iter;
230   mMessageLines.clear();
231}
232
233void XMessageBox::splitMessage()
234{
235   clearMessageLines();
236   if (mMessage == NULL || strlen(mMessage)==0)
237      // JMQTODO: what to do with empty strings?
238      return;
239
240   // need to break message up in to lines, and store lines in 
241   // mMessageLines
242
243   int numChars = strlen(mMessage);
244   const int ScratchBufSize = 2048;
245   char scratchBuf[ScratchBufSize];
246   memset(scratchBuf, 0, ScratchBufSize);
247
248   int fontDirection, fontAscent, fontDescent;
249   XCharStruct strInfo;
250
251   char *curChar = const_cast<char*>(mMessage);
252   char *endChar;
253   char *curWrapped = scratchBuf;
254   int curWidth = 0;
255   int maxWidth = mMaxWindowWidth - (MessageBox_LineHMargin);
256
257   while ( // while pointers are in range...
258      (curChar - mMessage) < numChars &&
259      (curWrapped - scratchBuf) < ScratchBufSize)
260   {
261      // look for next space in remaining string
262      endChar = index(curChar, ' ');
263      if (endChar == NULL)
264         endChar = index(curChar, '\0');
265
266      if (endChar != NULL)
267         // increment one char past the space to include it
268         endChar++;
269      else
270         // otherwise, set the endchar to one char ahead
271         endChar = curChar + 1;
272
273      // compute length of substr
274      int len = endChar - curChar;
275      XTextExtents(mFS, curChar, len, 
276         &fontDirection, &fontAscent, &fontDescent,
277         &strInfo);
278      // if its too big, time to add a new line...
279      if ((curWidth + strInfo.width) > maxWidth)
280      {
281         // create a new block for the line and add it
282         *curWrapped = '\0';
283         int len = strlen(scratchBuf);
284         char* line = new char[len+1];
285         strncpy(line, scratchBuf, len+1); // +1 gets the null char
286         mMessageLines.push_back(line);
287         
288         // reset curWrapped to the beginning of the scratch buffer
289         curWrapped = scratchBuf;
290         curWidth = 0;
291      }
292      // copy the current string into curWrapped if we have enough room
293      int bytesRemaining = 
294         ScratchBufSize - (curWrapped - scratchBuf);
295      if (bytesRemaining >= len)
296         strncpy(curWrapped, curChar, len);
297
298      curWrapped += len;
299      curWidth += strInfo.width;
300      curChar = endChar;
301   }
302
303   // make a final line out of any leftover stuff in the scratch buffer
304   if (curWrapped != scratchBuf)
305   {
306      *curWrapped = '\0';
307      int len = strlen(scratchBuf);
308      char* line = new char[len+1];
309      strncpy(line, scratchBuf, len+1); // +1 gets the null char
310      mMessageLines.push_back(line);
311   }
312}
313
314int XMessageBox::loadFont()
315{
316  // load the font
317   mFS = XLoadQueryFont(mDisplay, 
318      "-*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*");
319   
320   if (mFS == NULL)
321      mFS = XLoadQueryFont(mDisplay, "fixed");
322
323   if (mFS == NULL)
324      return -1;
325
326   // dummy call to XTextExtents to get the font specs
327   XCharStruct strInfo;
328   
329   XTextExtents(mFS, "foo", 1, 
330      &mFontDirection, &mFontAscent, &mFontDescent,
331      &strInfo);
332
333   mFontHeight = mFontAscent + mFontDescent;
334   return 0;
335}
336
337int XMessageBox::getButtonLineWidth()
338{
339   return mButtons.size() * MessageBox_ButtonBoxWidth +
340      (mButtons.size() - 1) * MessageBox_ButtonSpacer +
341      MessageBox_ButtonHMargin * 2;
342}
343
344void XMessageBox::setDimensions()
345{
346   mMBWidth = MessageBox_MaxWinWidth;
347   mMBHeight = MessageBox_MaxWinHeight;
348
349   // determine width of button line
350   int buttonWidth = getButtonLineWidth();
351
352   // if there is only one line, the desired width is the greater of the 
353   // line width and the buttonWidth, otherwise the lineWidth is the 
354   // max possible width which we already set.
355   if (mMessageLines.size() == 1)
356   {
357      XCharStruct strInfo;
358      int fontDirection, fontAscent, fontDescent;
359
360      XTextExtents(mFS, mMessageLines[0], strlen(mMessageLines[0]), 
361         &fontDirection, &fontAscent, &fontDescent,
362         &strInfo);
363
364      mMBWidth = max(MessageBox_LineHMargin * 2 + strInfo.width,
365         buttonWidth);
366      mMBWidth = max(mMBWidth, MessageBox_MinWinWidth);
367   }
368
369   // determine the height of the button line
370   int buttonHeight = MessageBox_ButtonBoxHeight + 
371      MessageBox_ButtonVMargin * 2;
372
373   int lineHeight = mFontHeight * mMessageLines.size() +
374      (mMessageLines.size() - 1) * MessageBox_LineSpacer +
375      MessageBox_LineVMargin * 2;
376
377   mMBHeight = buttonHeight + lineHeight;
378}
379
380int XMessageBox::show()
381{
382   if (mDisplay == NULL)
383      return -1;
384
385   int retVal = 0;
386   retVal = loadFont();
387   if (retVal < 0)
388      return retVal;
389
390   // set the maximum window dimensions
391   mScreenWidth = DisplayWidth(mDisplay, DefaultScreen(mDisplay));
392   mScreenHeight = DisplayHeight(mDisplay, DefaultScreen(mDisplay));
393   mMaxWindowWidth = min(mScreenWidth, MessageBox_MaxWinWidth);
394   mMaxWindowHeight = min(mScreenHeight, MessageBox_MaxWinHeight);
395
396   // split the message into a vector of lines
397   splitMessage();
398
399   // set the dialog dimensions
400   setDimensions();
401
402   mWin = XCreateSimpleWindow(
403      mDisplay,
404      DefaultRootWindow(mDisplay),
405      (mScreenWidth - mMBWidth) / 2,  (mScreenHeight - mMBHeight) / 2,
406      mMBWidth, mMBHeight,
407      1, 
408      BlackPixel(mDisplay, DefaultScreen(mDisplay)),
409      WhitePixel(mDisplay, DefaultScreen(mDisplay)));
410
411   mGC = XCreateGC(mDisplay, mWin, 0, 0);
412
413   XSetFont(mDisplay, mGC, mFS->fid);
414
415   // set input mask
416   XSelectInput(mDisplay, mWin, 
417      ExposureMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
418
419   // set wm protocols in case they hit X
420   Atom wm_delete_window = 
421      XInternAtom(mDisplay, "WM_DELETE_WINDOW", False);
422   Atom wm_protocols = 
423      XInternAtom(mDisplay, "WM_PROTOCOLS", False);
424   XSetWMProtocols (mDisplay, mWin, &wm_delete_window, 1);
425   // set pop up dialog hint
426   XSetTransientForHint(mDisplay, mWin, mWin);
427   
428   // set title
429   XTextProperty wtitle;
430   wtitle.value = (unsigned char *)mTitle;
431   wtitle.encoding = XA_STRING;
432   wtitle.format = 8;
433   wtitle.nitems = strlen(mTitle);
434   XSetWMName(mDisplay, mWin, &wtitle);
435
436   // show window
437   XMapRaised(mDisplay, mWin);
438   // move it in case some bozo window manager repositioned it
439   XMoveWindow(mDisplay, mWin, 
440      (mScreenWidth - mMBWidth) / 2,  (mScreenHeight - mMBHeight) / 2);
441   // raise it to top
442   XRaiseWindow(mDisplay, mWin);
443
444   XMessageBoxButton* clickedButton = NULL;
445   XEvent event;
446   Vector<XMessageBoxButton>::iterator iter;
447   bool done = false;
448   while (!done)
449   {
450      XNextEvent(mDisplay, &event);
451      switch (event.type)
452      {
453         case Expose:
454            repaint();
455            break;
456         case MotionNotify:
457            for (iter = mButtons.begin(); iter != mButtons.end(); ++iter)
458               iter->setMouseCoordinates(event.xmotion.x, event.xmotion.y);
459            break;
460         case ButtonPress:
461            for (iter = mButtons.begin(); iter != mButtons.end(); ++iter)
462            {
463               if (iter->pointInRect(event.xbutton.x, event.xbutton.y))
464               {
465                  iter->setMouseDown(true);
466                  iter->setMouseCoordinates(event.xbutton.x, event.xbutton.y);
467                  break;
468               }
469            }
470            break;
471         case ButtonRelease:
472            for (iter = mButtons.begin(); iter != mButtons.end(); ++iter)
473            {
474               if (iter->pointInRect(event.xbutton.x, event.xbutton.y) &&
475                  iter->isMouseDown())
476               {
477                  // we got a winner!
478                  clickedButton = iter;
479                  done = true;
480                  break;
481               }
482            }
483            if (clickedButton == NULL)
484            {
485               // user released outside a button.  clear the button states
486               for (iter = mButtons.begin(); iter != mButtons.end(); ++iter)
487                  iter->setMouseDown(false);
488            }
489            break;
490         case ClientMessage:
491            if (event.xclient.message_type == wm_protocols &&
492               event.xclient.data.l[0] == static_cast<long>(wm_delete_window))
493               done = true;
494            break;
495      }
496      repaint();
497   }
498
499   XUnmapWindow(mDisplay, mWin);
500   XDestroyWindow(mDisplay, mWin);
501   XFreeGC(mDisplay, mGC);
502   XFreeFont(mDisplay, mFS);
503
504   if (clickedButton != NULL)
505      return clickedButton->getClickVal();
506   else
507      return -1;
508}
509