示例#1
0
void RenderMessagePicture(CDrawPort *pdp)
{
  CCompMessage &cm = _acmMessages[_iActiveMessage];
  // try to
  try {
    // load image
    _toPicture.SetData_t(cm.cm_fnmPicture);
    ((CTextureData*)_toPicture.GetData())->Force(TEX_CONSTANT);
  // if failed
  } catch(char *strError) {
    // report error
    CPrintF("Cannot load '%s':\n%s\n", (CTString&)cm.cm_fnmPicture, strError);
    // do nothing
    return;
  }

  // get image and box sizes
  PIX pixImgSizeI = _toPicture.GetWidth();
  PIX pixImgSizeJ = _toPicture.GetHeight();
  PIXaabbox2D boxPic(PIX2D(_pixMarginI, _pixMarginJ),
      PIX2D(_boxMsgImage.Size()(1)-_pixMarginI, _boxMsgImage.Size()(2)-_pixMarginJ));
  PIX pixBoxSizeI = boxPic.Size()(1);
  PIX pixBoxSizeJ = boxPic.Size()(2);
  PIX pixCenterI = _boxMsgImage.Size()(1)/2;
  PIX pixCenterJ = _boxMsgImage.Size()(2)/2;
  // find image stretch to fit in box
  FLOAT fStretch = Min(FLOAT(pixBoxSizeI)/pixImgSizeI, FLOAT(pixBoxSizeJ)/pixImgSizeJ);
  // draw the image
  pdp->PutTexture(&_toPicture,
    PIXaabbox2D(
      PIX2D(pixCenterI-pixImgSizeI*fStretch/2, pixCenterJ-pixImgSizeJ*fStretch/2),
      PIX2D(pixCenterI+pixImgSizeI*fStretch/2, pixCenterJ+pixImgSizeJ*fStretch/2)));
}
示例#2
0
static PIXaabbox2D GetMsgListBox(INDEX i)
{
  PIX pixI0 = _boxMsgList.Min()(1)+_pixMarginI;
  PIX pixI1 = _boxMsgList.Max()(1)-_pixMarginI*3;
  PIX pixJ0 = _boxMsgList.Min()(2)+_pixMarginJ;
  PIX pixDJ = _pixCharSizeJ;
  return PIXaabbox2D(
    PIX2D(pixI0, pixJ0+pixDJ*i),
    PIX2D(pixI1, pixJ0+pixDJ*(i+1)-1));
}
示例#3
0
void CMGTitle::Render(CDrawPort *pdp)
{
  SetFontTitle(pdp);

  PIXaabbox2D box = FloatBoxToPixBox(pdp, mg_boxOnScreen);
  PIX pixI = box.Center()(1);
  PIX pixJ = box.Min()(2);

  pdp->PutTextC(mg_strText, pixI, pixJ, _pGame->LCDGetColor(C_WHITE | CT_OPAQUE, "title"));
}
示例#4
0
static INDEX SliderPixToIndex(PIX pixOffset, INDEX iVisible, INDEX iTotal, PIXaabbox2D boxFull)
{
  FLOAT fSize = ClampUp(FLOAT(iVisible)/iTotal, 1.0f);
  PIX pixFull = boxFull.Size()(2);
  PIX pixSize = PIX(pixFull*fSize);
  if (pixSize>=boxFull.Size()(2)) {
    return 0;
  }
  return (iTotal*pixOffset)/pixFull;
}
示例#5
0
static PIXaabbox2D GetSliderBox(INDEX iFirst, INDEX iVisible, INDEX iTotal,
  PIXaabbox2D boxFull)
{
  FLOAT fSize = ClampUp(FLOAT(iVisible)/iTotal, 1.0f);
  PIX pixFull = boxFull.Size()(2);
  PIX pixSize = PIX(pixFull*fSize);
  pixSize = ClampDn(pixSize, boxFull.Size()(1));
  PIX pixTop = pixFull*(FLOAT(iFirst)/iTotal)+boxFull.Min()(2);
  PIX pixI0 = boxFull.Min()(1);
  PIX pixI1 = boxFull.Max()(1);
  return PIXaabbox2D(PIX2D(pixI0, pixTop), PIX2D(pixI1, pixTop+pixSize));
}
示例#6
0
void TiledTexture( PIXaabbox2D &_boxScreen, FLOAT fStretch, MEX2D &vScreen, MEXaabbox2D &boxTexture)
{
  PIX pixW = _boxScreen.Size()(1);
  PIX pixH = _boxScreen.Size()(2);
  boxTexture = MEXaabbox2D(MEX2D(0, 0), MEX2D(pixW/fStretch, pixH/fStretch));
  boxTexture+=vScreen;
}
示例#7
0
static PIXaabbox2D GetMsgSliderBox(void)
{
  INDEX ctLines = _acmMessages.Count();
  PIX pixSizeI = _boxMsgList.Size()(1);
  PIX pixSizeJ = _boxMsgList.Size()(2);
  return GetSliderBox(
    _iFirstMessageOnScreen, _ctMessagesOnScreen, ctLines, GetMsgSliderSpace());
}
示例#8
0
extern void LCDScreenBoxOpenRight(COLOR col)
{
  // up
  _pdp->DrawLine(
    _boxScreen.Min()(1)-1, _boxScreen.Min()(2), 
    _boxScreen.Max()(1)-1, _boxScreen.Min()(2), col);
  // down
  _pdp->DrawLine(
    _boxScreen.Min()(1)-1, _boxScreen.Max()(2)-1, 
    _boxScreen.Max()(1)-1, _boxScreen.Max()(2)-1, col);
  // left
  _pdp->DrawLine(
    _boxScreen.Min()(1), _boxScreen.Min()(2), 
    _boxScreen.Min()(1), _boxScreen.Max()(2)-1+1, col);
}
示例#9
0
void CMGTrigger::Render(CDrawPort *pdp)
{
  SetFontMedium(pdp);

  PIXaabbox2D box = FloatBoxToPixBox(pdp, mg_boxOnScreen);
  PIX pixIL = box.Min()(1) + box.Size()(1)*0.45f;
  PIX pixIR = box.Min()(1) + box.Size()(1)*0.55f;
  PIX pixJ = box.Min()(2);

  COLOR col = GetCurrentColor();
  if (!mg_bVisual || mg_strValue == "") {
    CTString strValue = mg_strValue;
    if (mg_bVisual) {
      strValue = TRANS("none");
    }

    if (mg_iCenterI == -1) {
      pdp->PutText(mg_strLabel, box.Min()(1), pixJ, col);
      pdp->PutTextR(strValue, box.Max()(1), pixJ, col);
    } else {
      pdp->PutTextR(mg_strLabel, pixIL, pixJ, col);
      pdp->PutText(strValue, pixIR, pixJ, col);
    }
  } else {
    CTString strLabel = mg_strLabel + ": ";
    pdp->PutText(strLabel, box.Min()(1), pixJ, col);
    CTextureObject to;
    try {
      to.SetData_t(mg_strValue);
      CTextureData *ptd = (CTextureData *)to.GetData();
      PIX pixSize = box.Size()(2);
      PIX pixCX = box.Max()(1) - pixSize / 2;
      PIX pixCY = box.Center()(2);
      pdp->PutTexture(&to, PIXaabbox2D(
        PIX2D(pixCX - pixSize / 2, pixCY - pixSize / 2),
        PIX2D(pixCX - pixSize / 2 + pixSize, pixCY - pixSize / 2 + pixSize)), C_WHITE | 255);
    } catch (char *strError) {
      CPrintF("%s\n", strError);
    }
    to.SetData(NULL);
  }
}
示例#10
0
static PIXaabbox2D GetTextSliderBox(void)
{
  if (_iActiveMessage>=_acmMessages.Count()) {
    return PIXaabbox2D();
  }
  INDEX ctTextLines = _acmMessages[_iActiveMessage].cm_ctFormattedLines;
  PIX pixSizeI = _boxMsgText.Size()(1);
  PIX pixSizeJ = _boxMsgText.Size()(2);
  return GetSliderBox(
    _iTextLineOnScreen, _ctTextLinesOnScreen, ctTextLines, GetTextSliderSpace());
}
示例#11
0
static PIXaabbox2D GetMsgSliderSpace(void)
{
  PIX pixSizeI = _boxMsgList.Size()(1);
  PIX pixSizeJ = _boxMsgList.Size()(2);

  PIX pixSliderSizeI = _pixMarginI*2;
  if (pixSliderSizeI<5) {
    pixSliderSizeI=5;
  }
  return PIXaabbox2D(
    PIX2D(pixSizeI-pixSliderSizeI, 0),
    PIX2D(pixSizeI, pixSizeJ));
}
示例#12
0
// print list of messages
void PrintMessageList(CDrawPort *pdp)
{
  PIX pixTextX = _pixMarginI;
  PIX pixYLine = _pixMarginJ;
  SetFont1(pdp);

  INDEX iFirst = _iFirstMessageOnScreen;
  INDEX iLast = Min(INDEX(_iFirstMessageOnScreen+_ctMessagesOnScreen), _acmMessages.Count())-1;
  if (iFirst>iLast) {
    pdp->PutText( TRANS("no messages"), pixTextX, pixYLine, _colDark);
  }
  for(INDEX i=iFirst; i<=iLast; i++) {
    COLOR col = _colMedium;
    if (_acmMessages[i].cm_bRead) {
      col = _colDark;
    }
    if (i==_iActiveMessage) {
      col = _colLight;
    }
    if (GetMsgListBox(i-_iFirstMessageOnScreen)>=_vpixMouse) {
      col = LCDBlinkingColor(_colLight, _colMedium);
    }
    pdp->PutText( _acmMessages[i].cm_strSubject, pixTextX, pixYLine, col);
    pixYLine+=_pixCharSizeJ;
  }

  PIXaabbox2D boxSliderSpace = GetMsgSliderSpace();
  LCDDrawBox(0,0,boxSliderSpace, _colBoxes);
  PIXaabbox2D boxSlider = GetMsgSliderBox();
  COLOR col = _colBoxes;
  PIXaabbox2D boxSliderTrans = boxSlider;
  boxSliderTrans+=_boxMsgList.Min();
  if (boxSliderTrans>=_vpixMouse) {
    col = LCDBlinkingColor(_colLight, _colDark);
  }
  pdp->Fill( boxSlider.Min()(1)+2,  boxSlider.Min()(2)+2,
             boxSlider.Size()(1)-4, boxSlider.Size()(2)-4, col);
}
示例#13
0
void CBrushPaletteWnd::OnPaint() 
{
  {
  CPaintDC dc(this); // device context for painting
  }
  // skip if already drawing
  extern BOOL _bInTestGame; 
	if( _bInTestGame) return;

  if( m_iTimerID == -1)
  {
    m_iTimerID = (int) SetTimer( 1, 10, NULL);
  }

  POINT ptMouse;
  GetCursorPos( &ptMouse); 
  ScreenToClient( &ptMouse);

  // if there is a valid drawport, and the drawport can be locked
  if( m_pDrawPort != NULL ) {
    m_pDrawPort->SetAsCurrent();

    CWorldEditorView *pWorldEditorView = theApp.GetActiveView();
    ASSERT( pWorldEditorView != NULL);
    // clear background
    m_pDrawPort->Fill( C_lGRAY|CT_OPAQUE);
    // erase z-buffer
    m_pDrawPort->FillZBuffer(ZBUF_BACK);
    // for all brushes
    for( INDEX iBrush=0; iBrush<CT_BRUSHES; iBrush++)
    {
      // get current brush's box in pixels inside window
      PIXaabbox2D boxBrush = GetBrushBBox( iBrush);
      RenderBrushShape( iBrush, boxBrush, m_pDrawPort);

      TIME tm=_pTimer->GetRealTimeTick();
      // if we are drawing selected brush
      if(iBrush==theApp.m_fCurrentTerrainBrush)
      {
        m_pDrawPort->SetAsCurrent();
        FLOAT fFactor=sin(tm*8)/2.0f+0.5f;
        COLOR colSelected=LerpColor(C_lGRAY,C_RED,fFactor);
        m_pDrawPort->DrawBorder(boxBrush.Min()(1)-1, boxBrush.Min()(2)-1, 
                                boxBrush.Max()(1)-boxBrush.Min()(1)+2, boxBrush.Max()(2)-boxBrush.Min()(2)+2,
                                colSelected|CT_OPAQUE);
      }
      PIXaabbox2D boxPoint( PIX2D( ptMouse.x, ptMouse.y), PIX2D(ptMouse.x, ptMouse.y) );
      if( (boxBrush & boxPoint) == boxPoint)
      {
        m_pDrawPort->SetAsCurrent();
        INDEX iRot=((ULONG)(tm*25.0f))&7;
        ULONG ulLineType=0x0f0f0f0f<<iRot;
        m_pDrawPort->DrawBorder(boxBrush.Min()(1)-1, boxBrush.Min()(2)-1, 
                                boxBrush.Max()(1)-boxBrush.Min()(1)+2, boxBrush.Max()(2)-boxBrush.Min()(2)+2,
                                C_BLUE|CT_OPAQUE, ulLineType);
      }
    }

    // if there is a valid viewport
    if (m_pViewPort!=NULL)
    {
      m_pViewPort->SwapBuffers();
    }
  }
}
示例#14
0
extern void LCDDrawBox(PIX pixUL, PIX pixDR, PIXaabbox2D &box, COLOR col)
{
  // up
  _pdp->DrawLine(
    box.Min()(1)-pixUL, box.Min()(2)-pixUL, 
    box.Max()(1)+pixDR, box.Min()(2)-pixUL, col);
  // down
  _pdp->DrawLine(
    box.Min()(1)-pixUL, box.Max()(2)+pixDR, 
    box.Max()(1)+pixDR, box.Max()(2)+pixDR, col);
  // left
  _pdp->DrawLine(
    box.Min()(1)-pixUL, box.Min()(2)-pixUL, 
    box.Min()(1)-pixUL, box.Max()(2)+pixDR, col);
  // right
  _pdp->DrawLine(
    box.Max()(1)+pixDR, box.Min()(2)-pixUL, 
    box.Max()(1)+pixDR, box.Max()(2)+pixDR+1, col);
}
示例#15
0
// update screen geometry
static void UpdateSize(CDrawPort *pdp)
{
  // get screen size
  PIX pixSizeI = pdp->GetWidth();
  PIX pixSizeJ = pdp->GetHeight();

  // remember new size
  _pixSizeI = pixSizeI;
  _pixSizeJ = pixSizeJ;

  // determine scaling
  _fScaling = 1.0f;
  _fScaling2 = 1.0f;
  if (pixSizeJ<384) {
    _fScaling = 1.0f;
    _fScaling2 = pixSizeJ/480.0f;
  }

  // remember font size
  CFontData *pfd = _pfdConsoleFont;
  _pixCharSizeI = pfd->fd_pixCharWidth  + pfd->fd_pixCharSpacing;
  _pixCharSizeJ = pfd->fd_pixCharHeight + pfd->fd_pixLineSpacing;
  _pixCharSize2I = _pixCharSizeI*_fScaling2;
  _pixCharSize2J = _pixCharSizeJ*_fScaling2;
  _pixCharSizeI = _pixCharSizeI*_fScaling;
  _pixCharSizeJ = _pixCharSizeJ*_fScaling;

  _pixMarginI = 5*_fScaling2;
  _pixMarginJ = 5*_fScaling2;
  PIX pixBoxMarginI = 10*_fScaling2;
  PIX pixBoxMarginJ = 10*_fScaling2;

  PIX pixJ0Dn = pixBoxMarginJ;
  PIX pixJ1Up = pixJ0Dn+_pixCharSize2J+_pixMarginI*2;
  PIX pixJ1Dn = pixJ1Up+pixBoxMarginJ;
  PIX pixJ2Up = pixJ1Dn+_pixCharSize2J*6*2+pixBoxMarginJ;
  PIX pixJ2Dn = pixJ2Up+pixBoxMarginJ;
  PIX pixJ3Up = _pixSizeJ-pixBoxMarginJ;

  PIX pixI0Rt = pixBoxMarginI;
  PIX pixI1Lt = pixI0Rt+_pixCharSize2I*20+pixBoxMarginI;
  PIX pixI1Rt = pixI1Lt+pixBoxMarginI;
  PIX pixI2Lt = _pixSizeI/2-pixBoxMarginI/2;
  PIX pixI2Rt = _pixSizeI/2+pixBoxMarginI/2;
  PIX pixI4Lt = _pixSizeI-pixBoxMarginI;
  PIX pixI3Rt = pixI4Lt-pixBoxMarginI*2-_pixCharSize2I*10;
  PIX pixI3Lt = pixI3Rt-pixBoxMarginI;

  // calculate box sizes
  _boxTitle = PIXaabbox2D( PIX2D(0, pixJ0Dn-1), PIX2D(pixI3Lt, pixJ1Up));
  _boxExit  = PIXaabbox2D( PIX2D( pixI3Rt, pixJ0Dn-1), PIX2D(_pixSizeI, pixJ1Up));
  PIX pixD = 5;
  PIX pixH = (pixJ2Up-pixJ1Dn-pixD*(CMT_COUNT-1))/CMT_COUNT;
  INDEX i;
  for( i=0; i<CMT_COUNT; i++) {
    _boxButton[i] = PIXaabbox2D( 
      PIX2D(0,       pixJ1Dn+(pixH+pixD)*i),
      PIX2D(pixI1Lt, pixJ1Dn+(pixH+pixD)*i+pixH));
  }
  _boxMsgList = PIXaabbox2D( PIX2D(pixI1Rt, pixJ1Dn), PIX2D(pixI4Lt, pixJ2Up));

  if (GetSP()->sp_bCooperative) {
    _boxMsgText = PIXaabbox2D( PIX2D(pixI2Rt, pixJ2Dn), PIX2D(pixI4Lt, pixJ3Up));
    _boxMsgImage= PIXaabbox2D( PIX2D(pixI0Rt, pixJ2Dn), PIX2D(pixI2Lt, pixJ3Up));
  } else {
    _boxMsgText = PIXaabbox2D( PIX2D(pixI0Rt, pixJ2Dn), PIX2D(pixI4Lt, pixJ3Up));
    _boxMsgImage= PIXaabbox2D();
  }

  FLOAT fSlideSpeed = Max(_pixSizeI, _pixSizeJ*2L);
  FLOAT fGroup0 = ClampDn((1-fComputerFadeValue)*fSlideSpeed-_pixSizeJ, 0.0f);
  FLOAT fGroup1 = (1-fComputerFadeValue)*fSlideSpeed;
  // animate box positions
  _boxTitle -= PIX2D( fGroup1, 0);
  _boxExit  += PIX2D( fGroup1, 0);
  for( i=0; i<CMT_COUNT; i++) {
    FLOAT fOffs = ClampDn(fGroup1-(CMT_COUNT-i)*_pixMarginJ*10, 0.0f);
    _boxButton[i] -= PIX2D(fOffs, 0);
  }
  _boxMsgList -= PIX2D(0, fGroup0);
  _boxMsgText += PIX2D(fGroup0, 0);
  _boxMsgImage+= PIX2D(0, fGroup0);
  _ctMessagesOnScreen  = (_boxMsgList.Size()(2) - _pixMarginJ*2)                 / _pixCharSizeJ;
  _ctTextCharsPerRow   = (_boxMsgText.Size()(1) - _pixMarginI*4)                 / _pixCharSizeI;
  _ctTextLinesOnScreen = (_boxMsgText.Size()(2) - _pixMarginJ*2 - _pixMarginJ*4) / _pixCharSizeJ;
}
示例#16
0
// print exit button
void PrintExit(CDrawPort *pdp)
{
  SetFont2(pdp);
  pdp->PutTextR( TRANS("Exit"), _boxExit.Size()(1)-_pixMarginI*3, _pixMarginJ-2*_fScaling2+1, 
    MouseOverColor(_boxExit, _colMedium, _colDark, _colLight));
}
示例#17
0
// print text of current message
void PrintMessageText(CDrawPort *pdp)
{
  if (_acmMessages.Count()==0 ||
      _iActiveMessage>=_acmMessages.Count()||
      fComputerFadeValue<0.99f) {
    return;
  }

  SetFont2(pdp);

  // print subject
  CTString strSubject0;
  CTString strSubject1;
  CTString strSubject2;
  //strSubject.PrintF("%g", _fMsgAppearFade);
  const char *strSubject = _acmMessages[_iActiveMessage].cm_strSubject;
  INDEX ctSubjectLen = strlen(strSubject);
  INDEX ctToPrint = int(_fMsgAppearDelta*20.0f);
  for (INDEX iChar=0; iChar<ctSubjectLen; iChar++) {
    char strChar[2];
    strChar[0] = strSubject[iChar];
    strChar[1] = 0;
    if (iChar>ctToPrint) {
      NOTHING;
    } else if (iChar==ctToPrint) {
      strSubject2+=strChar;
    } else if (iChar==ctToPrint-1) {
      strSubject1+=strChar;
    } else {
      strSubject0+=strChar;
    }
  }
  PIX pixWidth0 = pdp->GetTextWidth(strSubject0);
  PIX pixWidth1 = pdp->GetTextWidth(strSubject1);
  pdp->PutText(strSubject0, _pixMarginI, _pixMarginJ-1, _colMedium);
  pdp->PutText(strSubject1, _pixMarginI+pixWidth0, _pixMarginJ-1, LerpColor( _colLight, _colMedium, 0.5f));
  pdp->PutText(strSubject2, _pixMarginI+pixWidth0+pixWidth1, _pixMarginJ-1, _colLight);

  pdp->DrawLine(0, PIX(_pixMarginJ*4), _boxMsgText.Size()(1), PIX(_pixMarginJ*4), _colBoxes);

  // fill in fresh player statistics
  if (strncmp(_acmMessages[_iActiveMessage].cm_strText, "$STAT", 5)==0) {
    _ppenPlayer->GetStats(_strStatsDetails, CST_DETAIL, _ctTextCharsPerRow);
    _acmMessages[_iActiveMessage].cm_ctFormattedWidth = 0;
  }
  // format text
  _acmMessages[_iActiveMessage].PrepareMessage(_ctTextCharsPerRow);

  SetFont1(pdp);
  INDEX ctLineToPrint = int(_fMsgAppearDelta*20.0f);
  // print it
  PIX pixJ = _pixMarginJ*4;
  for (INDEX iLine = _iTextLineOnScreen; 
    iLine<_iTextLineOnScreen+_ctTextLinesOnScreen;
    iLine++) {
    INDEX iPrintLine = iLine-_iTextLineOnScreen;
    if (iPrintLine>ctLineToPrint) {
      continue;
    }
    COLOR col = LerpColor( _colLight, _colMedium, Clamp( FLOAT(ctLineToPrint-iPrintLine)/3, 0.0f, 1.0f));
    pdp->PutText(_acmMessages[_iActiveMessage].GetLine(iLine),
      _pixMarginI, pixJ, col);
    pixJ+=_pixCharSizeJ;
  }

  PIXaabbox2D boxSliderSpace = GetTextSliderSpace();
  LCDDrawBox(0,0,boxSliderSpace, _colBoxes);
  PIXaabbox2D boxSlider = GetTextSliderBox();
  COLOR col = _colBoxes;
  PIXaabbox2D boxSliderTrans = boxSlider;
  boxSliderTrans+=_boxMsgText.Min();
  if (boxSliderTrans>=_vpixMouse) {
    col = LCDBlinkingColor(_colLight, _colDark);
  }
  pdp->Fill( boxSlider.Min()(1)+2,  boxSlider.Min()(2)+2,
             boxSlider.Size()(1)-4, boxSlider.Size()(2)-4, col);
}
示例#18
0
void CGame::ComputerKeyDown(MSG msg)
{
  static BOOL bRDown = FALSE;
  // if computer is not active
  if (_pGame->gm_csComputerState!=CS_ON && _pGame->gm_csComputerState!=CS_TURNINGON) {
    // do nothing
    return;
  }

  // if escape pressed
  if (msg.message==WM_KEYDOWN && msg.wParam==VK_ESCAPE) {
    ExitRequested();
  }

  // if right mouse pressed
  if (msg.message==WM_RBUTTONDOWN || msg.message==WM_RBUTTONDBLCLK) {
    bRDown = TRUE;
  }
  // if right mouse released
  if (bRDown && msg.message==WM_RBUTTONUP) {
    bRDown = FALSE;
    // mark current message as read
    MarkCurrentRead();
    // find a group with first unread message
    BOOL bHasUnread = FindGroupWithUnread();
    // if some
    if (bHasUnread) {
      // select first unread message in it
      NextUnreadMessage();
    } else {
      ExitRequested();
    }
  }
  
  if (msg.message==WM_KEYDOWN) {
    switch (msg.wParam) {
    // change message types on number keys
    case '1': _cmtWantedType = CMT_INFORMATION ; return;
    case '2': _cmtWantedType = CMT_WEAPONS     ; return;
    case '3': _cmtWantedType = CMT_ENEMIES     ; return;
    case '4': _cmtWantedType = CMT_BACKGROUND  ; return;
    case '5': _cmtWantedType = CMT_STATISTICS  ; return;
    // go to next unread
    case 'U':
    case VK_SPACE:
      NextUnreadMessage(); return;
    // scroll message list
    case 219: PrevMessage(); return;
    case 221: NextMessage(); return;
    // mark current message as read and go to next
    case VK_RETURN: MarkCurrentRead(); NextUnreadMessage(); return;
    // scroll message text
    case VK_UP:   MessageTextUp(1); return;
    case VK_DOWN: MessageTextDn(1); return;
    case VK_PRIOR:MessageTextUp(_ctTextLinesOnScreen-1); return;
    case VK_NEXT: MessageTextDn(_ctTextLinesOnScreen-1); return;
    };
  }

  // if left mouse pressed
  if (msg.message==WM_LBUTTONDOWN || msg.message==WM_LBUTTONDBLCLK) {
    BOOL bOverMsgSlider = FALSE;
    // if over slider
    {PIXaabbox2D boxSlider = GetTextSliderBox();
    PIXaabbox2D boxSliderTrans = boxSlider;
    boxSliderTrans+=_boxMsgText.Min();
    if (boxSliderTrans>=_vpixMouse) {
      bOverMsgSlider = TRUE;
      // start dragging
      _bSliderDragText = TRUE;
      _pixSliderDragJ=_vpixMouse(2);
      _iSliderDragLine = _iTextLineOnScreen;
    }}

    // if over slider
    {PIXaabbox2D boxSlider = GetMsgSliderBox();
    PIXaabbox2D boxSliderTrans = boxSlider;
    boxSliderTrans+=_boxMsgList.Min();
    if (boxSliderTrans>=_vpixMouse) {
      // start dragging
      _bSliderDragText = FALSE;
      _pixSliderDragJ=_vpixMouse(2);
      _iSliderDragLine = _iFirstMessageOnScreen;
    }}
    // if over some button
    {for(INDEX i=0; i<CMT_COUNT; i++) {
      if (_boxButton[i]>=_vpixMouse) {
        // switch to that message type
        _cmtWantedType = (CompMsgType)i;
      }
    }}
    // if over some message
    {for(INDEX i=0; i<_ctMessagesOnScreen; i++) {
      if (GetMsgListBox(i)>=_vpixMouse && !bOverMsgSlider) {
        // switch to that message
        SelectMessage(_iFirstMessageOnScreen+i);
      }
    }}
  }

  // if left mouse released
  if (msg.message==WM_LBUTTONUP) {
    // stop dragging
    _pixSliderDragJ=-1;
    // if over exit
    if (_boxExit>=_vpixMouse) {
      // exit
      ExitRequested();
    }
  }
}