Ejemplo n.º 1
0
static struct CEntry *FindOrNak(RPC2_PacketBuffer *pb)
{
    struct CEntry *ce;
    int invalid_sa, init2;

    ce = rpc2_GetConn(ntohl(pb->Header.RemoteHandle));

    /* The received packet must be using the exact same security context as
     * the connection on which the packet was received. */
    invalid_sa = ce && ce->sa.decrypt && &ce->sa != pb->Prefix.sa;

    /* The only situation where this can differ is when we received an
     * non-encrypted response to the INIT1 request from a server that
     * doesn't know the new 'secret handshake'.
     * This test can be removed if we don't need or want to be compatible
     * with non-encrypted rpc2 connections anymore. */
    init2 = ce && TestState(ce, CLIENT, C_AWAITINIT2);

    if (invalid_sa && !init2) {
        /* should we log this? Responding is useless because the client
         * that sent this packet must not have had good intentions. */
        RPC2_FreeBuffer(&pb);
        return NULL;
    }

    if (!ce || TestState(ce, CLIENT, C_HARDERROR) ||
        TestState(ce, SERVER, S_HARDERROR)) {
        rpc2_ntohp(pb);
        NAKIT(pb);
        return NULL;
    }

    return (ce);
}
Ejemplo n.º 2
0
void CEditValue::Draw()
{
    if ( (m_state & STATE_VISIBLE) == 0 )  return;

    if ( m_state & STATE_SHADOW )
    {
        DrawShadow(m_pos, m_dim);
    }

    if (m_edit != nullptr)
    {
        m_edit->SetState(STATE_ENABLE, TestState(STATE_ENABLE));
        m_edit->Draw();
    }
    if (m_buttonUp != nullptr)
    {
        m_buttonUp->SetState(STATE_DEAD, TestState(STATE_DEAD));
        m_buttonUp->Draw();
    }
    if (m_buttonDown != nullptr)
    {
        m_buttonDown->SetState(STATE_DEAD, TestState(STATE_DEAD));
        m_buttonDown->Draw();
    }
}
Ejemplo n.º 3
0
void rpc2_HandlePacket(RPC2_PacketBuffer *pb)
{
    struct CEntry *ce = NULL;
    assert(pb->Prefix.LE.Queue == &rpc2_PBList);

    rpc2_Recvd.Total++;
    rpc2_Recvd.Bytes += pb->Prefix.LengthOfPacket;

    /* no handle, this must be an INIT1 packet */
    if (!pb->Header.RemoteHandle) {
        HandleInit1(pb);
        return;
    }

    ce = FindOrNak(pb);
    if (!ce)
        return;

    if ((ntohl(pb->Header.LocalHandle) == -1) ||
        (ntohl(pb->Header.Opcode) == RPC2_NAKED)) {
        HandleSLPacket(pb, ce);
        return;
    }

    if (!TestState(ce, CLIENT, C_AWAITINIT2) &&
        !TestState(ce, SERVER, S_AWAITINIT3) &&
        !TestState(ce, CLIENT, C_AWAITINIT4))
        rpc2_ApplyD(pb, ce);

#ifdef RPC2DEBUG
    /* debugging */
    if (RPC2_DebugLevel >= 10)
        rpc2_PrintCEntry(ce, rpc2_tracefile);
#endif
    /* update the host entry if there is one */
    if (ce->HostInfo)
        ce->HostInfo->LastWord = pb->Prefix.RecvStamp;

    /* convert to host-byte order */
    rpc2_ntohp(pb);

    /* maintain causality */
    if (pb->Header.Lamport >= rpc2_LamportClock)
        rpc2_LamportClock = pb->Header.Lamport + 1;

    say(9, RPC2_DebugLevel, "Decoding opcode %d\n", pb->Header.Opcode);

    DecodePacket(pb, ce);

    say(9, RPC2_DebugLevel, "Decoding complete\n");
}
Ejemplo n.º 4
0
/* Special packet from socketlistener: never encrypted */
static void HandleSLPacket(RPC2_PacketBuffer *pb, struct CEntry *ce)
{
    rpc2_ntohp(pb);

    if (pb->Header.Opcode != RPC2_NAKED) {
        BOGUS(pb, "HandleSLPacket: bogus opcode\n");
        return;
    }

    if (!TestState(ce, CLIENT, (C_AWAITREPLY | C_AWAITINIT2))) {
        BOGUS(pb, "HandleSLPacket: state != AWAIT\n");
        return;
    }

    say(1, RPC2_DebugLevel, "HandleNak()\n");

    rpc2_Recvd.Naks++;

    if (BogusSl(ce, pb))
        return;

    rpc2_SetConnError(ce);
    rpc2_DeactivateSle(ce->MySl, NAKED);
    LWP_NoYieldSignal((char *)ce->MySl);
    RPC2_FreeBuffer(&pb);
}
  //
  // Notify this task of an event
  //
  Bool SquadMoveTogether::ProcessEvent(const Event &event)
  {
    switch (event.message)
    {
      case GameObjNotify::Interrupted:
        LOG_DIAG(("SquadMoveTogether: Interrupted"))
        inst.Set(0xABAA7B48); // "Init"
        return (TRUE);

      case 0x6B0DB5AA: // "Move::Incapable"
      {
        // One of the units in the squad is telling us
        // it can't make it to the destination
//        LOG_DIAG(("Unit %d in the squad could not make it to its destination", event.param2))

        for (SquadObj::UnitList::Iterator i(&subject->GetList()); *i; i++)
        {
          if (
            (*i)->Alive() && 
            (*i)->task == event.param1 &&
            (*i)->Id() == event.param2)
          {
            (*i)->completed = TRUE;
            GoToNextPoint(*i);
          }
        }
        return (TRUE);
      }

      case 0xFCBF8881: // "Move::Completed"
      {
        // One of the units in the squad is telling us 
        // it made it to the destination
//        LOG_DIAG(("Unit %d in the squad made it to its destination", event.param2))

        // Mark the completed flag for this squad member
        for (SquadObj::UnitList::Iterator i(&subject->GetList()); *i; i++)
        {
          if (
            (*i)->Alive() && 
            (*i)->task == event.param1 &&
            (*i)->Id() == event.param2)
          {
            (*i)->completed = TRUE;
            if ((*i)->data < point || TestState(0x9E947215)) // "Moving"
            {
//              LOG_DIAG(("We're in the move state so proceeding immediately"))
              GoToNextPoint(*i);
            }
            break;
          }

        }
        return (TRUE);
      }

      default:
        return (GameTask<SquadObjType, SquadObj>::ProcessEvent(event));
    }
  }
Ejemplo n.º 6
0
bool OOPLyric::Resume() {
    // 不能在停止状态下调用本函数
    wxASSERT(!TestState(OLST_STOPPED));

    // 必须先进入 StartLyric()
    if (!TestState(OLST_STARTED) || m_timer.IsRunning()) {
        return false;
    }

    RemoveState(OLST_PAUSED);

    //--------------------------------------------------------

    m_timer.Start(REFRESH_INTERVAL_MS);
    return true;
}
Ejemplo n.º 7
0
DWORD fsSitePingMgr::Ping(LPCSTR pszSite)
{
  
    IPINFO ipInfo;
   

	WORD w = MAKEWORD (1,1);
	WSADATA data;
	::WSAStartup (w, &data);

	if (TestState () == FALSE)
		return SPM_PINGERR;

    HANDLE hFile = m_pfnIcmpCreateFile();

    if (hFile == NULL || hFile == INVALID_HANDLE_VALUE)
		return SPM_PINGERR;

    ipInfo.Ttl = 238;
    ipInfo.Tos = 0;
    ipInfo.IPFlags = 0;
    ipInfo.OptSize = 0;
    ipInfo.Options = NULL;

	ULONG dwIp = fsGetSiteIp (pszSite);
	
	if (dwIp == 0)
	{
		m_pfnIcmpCloseHandle (hFile);
		return SPM_PINGERR;
	}

	char reply [sizeof (ICMPECHO)+50];
	ICMPECHO* iep = (ICMPECHO*) reply;
	iep->RTTime = 0xffffffff;

	char buftosend [32];
	memset (buftosend, 0, sizeof (buftosend));
   
     m_pfnIcmpSendEcho(
        hFile,       
        dwIp,       
        buftosend,           
        sizeof (buftosend),               
        NULL,       
        iep,      
        sizeof (reply),
        5000);           

    m_pfnIcmpCloseHandle (hFile);

	if (!iep->Status)
		return iep->RTTime;
	else
		return SPM_PINGERR;
}
Ejemplo n.º 8
0
static void HandleRetriedBind(RPC2_PacketBuffer *pb, struct CEntry *ce)
{
    say(1, RPC2_DebugLevel, "HandleRetriedBind()\n");

    if (!TestRole(ce, SERVER)) {
        BOGUS(pb, "HandleRetriedBind: not server\n");
        return;
    }

    /* The original bind request could be:
         (1) in the hold queue,
         (2) in RPC2_GetRequest() on some LWP,
         (3) already completed.
    */
    ce->TimeStampEcho = pb->Header.TimeStamp;
    /* if we're modifying the TimeStampEcho, we also have
     * to reset the RequestTime */
    TVTOTS(&pb->Prefix.RecvStamp, ce->RequestTime);

    say(15, RPC2_DebugLevel, "handleinit1 TS %u RQ %u\n", ce->TimeStampEcho,
        ce->RequestTime);

    if (TestState(ce, SERVER, S_STARTBIND)) {
        /* Cases (1) and (2) */
        say(1, RPC2_DebugLevel, "Busying Init1 on %#x\n", ce->UniqueCID);

        SendBusy(ce, FALSE);
        RPC2_FreeBuffer(&pb);
        return;
    }
    if (ce->SecurityLevel == RPC2_OPENKIMONO && ce->HeldPacket) {
        /* Case (3): The Init2 must have been dropped; resend it */
        say(1, RPC2_DebugLevel, "Resending Init2 %#x\n", ce->UniqueCID);
        ce->HeldPacket->Header.TimeStamp = htonl(ce->TimeStampEcho);
        rpc2_XmitPacket(ce->HeldPacket, ce->HostInfo->Addr, 1);
        RPC2_FreeBuffer(&pb);
        return;
    }
    /* This retry is totally bogus */
    BOGUS(pb, "HandleRetriedBind: anything else\n");
    return;
}
Ejemplo n.º 9
0
void OOPLyric::Start() {
    if (!IsOk()) {
        wxLogError(L"歌词控件尚未正确初始化。");
        return;
    }

    // 不能两次进入本函数
    if (TestState(OLST_STARTED)) {
        if (m_stopWatch->IsRunning()) {
            Resume();
        }

        return;
    }

    SetAddinState(OLST_STARTED);
    RemoveState(OLST_STOPPED | OLST_PAUSED);

    //======================================================

    UpdateProgress(NULL);
}
Ejemplo n.º 10
0
static void HandleInit3(RPC2_PacketBuffer *pb, struct CEntry *ce)
{
    struct SL_Entry *sl;

    say(1, RPC2_DebugLevel, "HandleInit3()\n");

    rpc2_Recvd.Requests++;

    /* Am I expecting this packet? */
    if (!TestState(ce, SERVER, S_AWAITINIT3)) {
        if (ce->HeldPacket) {
            /* My Init4 must have got lost; resend it */
            ce->HeldPacket->Header.TimeStamp = htonl(pb->Header.TimeStamp);
            rpc2_XmitPacket(ce->HeldPacket, ce->HostInfo->Addr, 1);
        } else
            say(1, RPC2_DebugLevel, "Bogus Init3\n");
        /* Throw packet away anyway */
        RPC2_FreeBuffer(&pb);
        return;
    }

    /* Expected Init3 */
    if (BogusSl(ce, pb))
        return;
    pb = ShrinkPacket(pb);

    ce->TimeStampEcho = pb->Header.TimeStamp;
    TVTOTS(&pb->Prefix.RecvStamp, ce->RequestTime);

    say(15, RPC2_DebugLevel, "handleinit3 TS %u RQ %u\n", ce->TimeStampEcho,
        ce->RequestTime);

    sl       = ce->MySl;
    sl->data = pb;
    SetState(ce, S_FINISHBIND);
    rpc2_DeactivateSle(sl, ARRIVED);
    LWP_NoYieldSignal((char *)sl);
}
Ejemplo n.º 11
0
// ...
void GLWidget::mousePressEvent(QMouseEvent* e)
{
	// Check mouse button pressed: right and middle button not active.
	switch (e->button()) {
	case Qt::RightButton: { return; }
	case Qt::MiddleButton: { return; }
	default: { break; }
	}
	// Store window mouse position and convert it into OpenGL screen coordinates.
	mouWinPos = e->pos();
	mouGLPos.setX(e->pos().x());
	mouGLPos.setY(height() - e->pos().y());
	// Safety check: mouse OpenGL coordinates inside OpenGL context!
	printf("%d %d\n", mouGLPos.x(), mouGLPos.y());
	if (!checkInsideWidget(mouGLPos)) return;
	// Update click info.
	clickGLPos = mouGLPos;
	clickFlag = true;
	// Setup for the selection implementation using the back-buffer!
	// Blending disabled to ensure color consistency.
	glDisable(GL_BLEND);
	// Clearing the color and depth buffers.
	// NOTE: We don't need to call glDrawBuffer( GL_BACK ) since the back buffer is the default writing buffer in doublebuffering mode!
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	// Draw 2D Fitts' task circles: in selection mode each circle is rendered with a specific color to aid its identification.
	drawFittsTask2D(fittsNum, fittsSize, fittsRadius, true, false);
	// Set the back buffer for reading the color of the pixel located at mouse coordinates (OpenGL screen coordinate).
	GLfloat pixelRGBA[4];
	glReadBuffer(GL_BACK);
	glReadPixels(mouGLPos.x(), mouGLPos.y(), 1, 1, GL_RGBA, GL_FLOAT, pixelRGBA);
	// Convert the color into an pos (the 2D Fitts' task circle pos).
	unsigned int p = (unsigned int)(pixelRGBA[0] * 255.0f);
	// If the pos is different than 0: a circle has been selected, and we store selection info.
	if (p != 0) {
		slcIdx = fittsPos2Idx(p);
		// Store selection data.
		slcClick = mouGLPos;
		slcColor[0] = pixelRGBA[0];
		slcColor[1] = pixelRGBA[1];
		slcColor[2] = pixelRGBA[2];
		slcColor[3] = pixelRGBA[3];
		// Compute selected circle center.
		float const t = 2.0f * float(M_PI) * float(slcIdx) / float(fittsNum);
		float cx = std::sin(t) * fittsRadius;
		float cy = std::cos(t) * fittsRadius;
		unsigned int px = (cx);
		unsigned int py = (cy);
		slcCenter.setX(px);
		slcCenter.setY(py);
	}
	// If the index equals 0: no circle has been selected, and we reset the previous selection info.
	else { resetSelection(); }
	// Fitts' task 2D game logic.
	switch (fittsStatus) {
		// Start.
	case TestState::READY: {
							   if (slcIdx == fittsMarkedIdx) {
								   fittsStatus = TestState((unsigned int)fittsStatus + 1);
								   fittsMarkedIdx = (unsigned int)fittsStatus;
							   }
							   break; }
		// End.as
	case TestState::END: {
							 fittsStatus = TestState::READY;
							 fittsMarkedIdx = (fittsNum % 2 == 0) ? (fittsNum - 1) : fittsNum;
							 break; }
		// Game states during task completion.
	default: {
				 if (slcIdx == fittsMarkedIdx) {
					 fittsStatus = TestState((unsigned int)fittsStatus + 1);
					 if ((unsigned int)fittsStatus > fittsNum) { fittsStatus = TestState::END; }
					 else { fittsMarkedIdx = (unsigned int)fittsStatus; }
					 break;
				 }
	}
	}
	// Repaints the widget immediately.
	repaint();
}
Ejemplo n.º 12
0
static void DecodePacket(RPC2_PacketBuffer *pb, struct CEntry *ce)
{
    /* either this was an INIT1 and was handled, or we found a valid connection
     * entry before calling DecodePacket */
    assert(ce != NULL);

    switch (pb->Header.Opcode) {
    case RPC2_BUSY: {
        if (!TestState(ce, CLIENT, (C_AWAITINIT2 | C_AWAITREPLY))) {
            BOGUS(pb, "DecodePacket(RPC2_BUSY): state != AWAIT\n");
            return;
        }
        /*
         * If the state is C_AWAITINIT2, the server is processing
         * a bind request. Sequence numbers are 0 during the bind,
         * but a busy during bind will have a sequence number of -1.
         */
        if (TestState(ce, CLIENT, C_AWAITREPLY) &&
            ce->NextSeqNumber != pb->Header.SeqNumber - 1) {
            BOGUS(pb, "DecodePacket(RPC2_BUSY): bad seqno\n");
            return;
        }
        if (TestState(ce, CLIENT, C_AWAITINIT2) && pb->Header.SeqNumber != -1) {
            BOGUS(pb, "DecodePacket(RPC2_BUSY): bad bind seqno\n");
            return;
        }

        HandleBusy(pb, ce);
        return;
    }

    case RPC2_REPLY: {
        if (!TestState(ce, CLIENT, C_AWAITREPLY)) {
            BOGUS(pb, "DecodePacket(RPC2_REPLY): state != AWAIT\n");
            return;
        }
        if (ce->NextSeqNumber != pb->Header.SeqNumber - 1) {
            BOGUS(pb, "DecodePacket(RPC2_REPLY): bad seqno\n");
            return;
        }

        HandleCurrentReply(pb, ce);
        return;
    }

    case RPC2_INIT1OPENKIMONO:
    case RPC2_INIT1AUTHONLY:
    case RPC2_INIT1HEADERSONLY:
    case RPC2_INIT1SECURE: {
        /* INIT1 on an established connection is invalid */
        NAKIT(pb);
        return;
    }

    case RPC2_INIT2: {
        if (TestState(ce, CLIENT, C_AWAITINIT2)) {
            HandleInit2(pb, ce);
            return;
        }
        /* anything else */
        BOGUS(pb, "DecodePacket(RPC2_INIT2): state != AWAIT\n");
        return;
    }

    case RPC2_INIT3: {
        if (!TestRole(ce, SERVER)) {
            NAKIT(pb);
            return;
        }
        HandleInit3(pb, ce); /* This could be a retry */
        return;
    }

    case RPC2_INIT4: {
        if (TestState(ce, CLIENT, C_AWAITINIT4)) {
            HandleInit4(pb, ce);
            return;
        }
        BOGUS(pb, "DecodePacket(RPC2_INIT4): state != AWAIT\n");
        return;
    }

    case RPC2_INITMULTICAST: {
        if (TestState(ce, SERVER, S_AWAITENABLE)) {
            say(1, RPC2_DebugLevel, "Connection not enabled\n");
            // BOGUS(pb, "DecodePacket(INITMC): connection not enabled\n");
            SendBusy(ce, TRUE);
            return;
        }

        if (TestState(ce, SERVER, S_AWAITREQUEST) &&
            ce->NextSeqNumber == pb->Header.SeqNumber) {
            HandleInitMulticast(pb, ce);
            return;
        }

        if (TestState(ce, SERVER, S_AWAITREQUEST) &&
            ce->NextSeqNumber == pb->Header.SeqNumber + 2) {
            HandleOldRequest(pb, ce);
            return;
        }

        /* We can't have the "HandleCurrentRequest()" case because we don't
           yield control while processing an InitMulticast request.  Retries
           are thus always seen as "old requests."
           We don't special case the MultiRPC "packets ahead of sequence"
           situation because InitMulticast requests cannot be multicasted.
        */
        /* Anything else */
        BOGUS(pb, "DecodePacket(INITMC): anything else\n");
        return;
    }
    /* cannot be any negative opcode XXXXXXXXXXXXXXXX */
    default: {
        if (TestState(ce, SERVER, S_AWAITENABLE)) {
            say(1, RPC2_DebugLevel, "Connection not enabled\n");
            // BOGUS(pb, "DecodePacket: connection not enabled\n");
            SendBusy(ce, TRUE);
            return;
        }

        if (TestState(ce, SERVER, S_AWAITREQUEST) &&
            ce->NextSeqNumber == pb->Header.SeqNumber) {
            HandleNewRequest(pb, ce);
            return;
        }

        if (TestState(ce, SERVER, S_AWAITREQUEST) &&
            ce->NextSeqNumber == pb->Header.SeqNumber + 2) {
            HandleOldRequest(pb, ce);
            return;
        }

        if (TestState(ce, SERVER, (S_PROCESS | S_INSE | S_REQINQUEUE)) &&
            ce->NextSeqNumber == pb->Header.SeqNumber + 2) {
            HandleCurrentRequest(pb, ce);
            return;
        }

        /* fix for MultiRPC; nak request packets ahead of sequence */
        if ((pb->Header.SeqNumber > ce->NextSeqNumber + 2) &&
            (pb->Header.SeqNumber & 1) == 0) {
            NAKIT(pb);
            return;
        }
        /* Anything else */
        BOGUS(pb, "DecodePacket: anything else\n");
        return;
    }
    }
}
Ejemplo n.º 13
0
void OOPLyric::OnMouseEvent(VdkMouseEvent &e) {
    switch (e.evtCode) {
    case RIGHT_UP: {
        // 拖动歌词时不要响应右键事件
        if (TestState(OLST_DRAGGING)) {
            return;
        }

        wxPoint menuPos(AbsoluteRect().GetPosition());
        menuPos.x += e.mousePos.x;
        menuPos.y += e.mousePos.y;

        m_Window->ShowContextMenu(this, menuPos);

        break;
    }

    case LEFT_DOWN: {
        m_draggDistance = e.mousePos.y;
        SetAddinState(OLST_DRAGGING_STARTED);

        break;
    }

    case DRAGGING: {
        // 不接受先在一首歌的会话中拖动歌词,然后在未释放鼠标的情况下
        // 另一首歌开始播放,继续前面的拖动事件
        if (!TestState(OLST_DRAGGING_STARTED)) {
            break;
        }

        if (!IsOk()) {
            break;
        }

        if (m_timer.IsRunning()) {
            Pause();
            SetAddinState(OLST_RUNNING_BEFORE_DRAGGING);
        }

        SetAddinState(OLST_DRAGGING);

        //======================================================

        int ystart;
        GetViewStartCoord(NULL, &ystart);

        int dY = e.mousePos.y - m_draggDistance;
        m_draggDistance = e.mousePos.y;

        // 这是一行我们手工加上去的空行
        int rowHeight = GetRowHeight();
        int upperBound =
            (*(m_parser->begin()))->GetLyric().empty() ? rowHeight : 0;

        // 无法继续将帘布向上卷(再拖下去就到下一首了)
        // 我们将拖到尽头的事件视为无效
        bool lastLine = false;

        // 情景:将虚拟画布像窗帘一样向下拖
        // 拖动尽头了,不能再把窗帘哪怕拖下一寸
        if (ystart - dY < upperBound) {
            dY = ystart - upperBound; // 加加减减的原因参照(*)
        } else {
            int maxy;
            GetMaxViewStartCoord(NULL, &maxy);

            // 将帘布向上卷,卷到尽头了,再卷下去就会导致
            // 无法完整遮住窗口
            if (ystart - dY > maxy) {
                dY = ystart - maxy; // 加加减减的原因参照(*)
                // 无效拖动事件
                lastLine = true;
            }
        }

        if (dY) {
            SetViewStart(0, ystart - dY, &e.dc);   //………………(*)
        }

        // 无效拖动事件
        if (lastLine) {
            m_draggHit = m_parser->end();
        }

        //===================================================
        // 绘制中间线段

        wxRect rc(GetAbsoluteRect());
        int y = rc.y + m_blankLinesTop * GetRowHeight();

        m_Window->ResetDcOrigin(e.dc);
        e.dc.SetPen(wxPen(m_TextColor));
        e.dc.DrawLine(rc.x, y, rc.GetRight(), y);

        break;
    }

    case NORMAL:
    case LEFT_UP: {
        if (!TestState(OLST_DRAGGING) ||
            !TestState(OLST_DRAGGING_STARTED)) {
            break;
        }

        wxASSERT(IsOk());

        //-----------------------------------------------------

        RemoveState(OLST_DRAGGING | OLST_DRAGGING_STARTED);

        // 拖到最下面了,尽头
        if (m_draggHit == m_parser->end()) {
            RefreshState(&e.dc);
        } else {
            int ystart; // 起始绘图坐标
            GetViewStartCoord(NULL, &ystart);

            LineInfo *lineDraggHit = *m_draggHit;
            size_t timeToGo = lineDraggHit->GetStartTime();

            int rowHeight = GetRowHeight();
            double linePercentage = double(ystart % rowHeight) / rowHeight ;
            timeToGo += lineDraggHit->GetMilSeconds() * linePercentage;

            // 歌词可能并不匹配正在播放的歌曲
            if (timeToGo < m_parser->GetTimeSum()) {
                m_currLine = m_draggHit;

                if (IsReadyForEvent()) {
                    FireEvent(&e.dc, (void *) timeToGo);
                }
            }
        }

        bool resume = TestState(OLST_RUNNING_BEFORE_DRAGGING);
        if (resume) {
            RemoveState(OLST_RUNNING_BEFORE_DRAGGING);
            Resume();
        }

        break;
    }

    default:

        break;
    }
}
Ejemplo n.º 14
0
VdkCusdrawReturnFlag OOPLyric::DoDrawCellText
        (const VdkLcCell *cell,
         int col_index,
         int index0,
         wxDC &dc,
         VdkLcHilightState state) {
    wxASSERT(m_parser);

    // 注意:index 是不计算加入的空行的
    int index = (int) (cell->GetClientData()) - 1;
    if (index == -1) { // 此时 ClientData == NULL,是我们添加的空行
        return VCCDRF_DODEFAULT;
    }

    dc.SetTextForeground(m_TextColor);

    // 暂停时高亮当前行,情景见于用户正在拖动歌词。
    // 另外先暂停,然后拖动歌词完毕,此时假如歌词秀是以卡拉OK
    // 方式进行显示时,那么不会保持半高亮的状态,而是全高亮。
    if (TestState(OLST_PAUSED)) {
        int yStart;
        GetViewStartCoord(NULL, &yStart);

        int rowHeight = GetRowHeight();
        int dragRegion = yStart + rowHeight * m_blankLinesTop;
        int index2 = index + m_blankLinesTop;

        // 检测拖动歌词时中间线下面的一行
        if (rowHeight * index2 <= dragRegion &&
            rowHeight * (index2 + 1) > dragRegion) {
            m_draggHit = m_parser->GetLine(index);

            dc.SetTextForeground(m_HilightColor);
        }

        return VCCDRF_DODEFAULT;
    }

    LineInfo *currLine = *m_currLine;
    // TODO: 是否考虑优化?
    size_t currLineIndex = m_parser->IndexOf(m_currLine);
    int lineHasGone = m_stopWatch->Time() - currLine->GetStartTime();

    if ((index == currLineIndex - 1) && !cell->GetLabel().empty()) {
        // 使用渐变色还原上一句歌词
        if (lineHasGone < ALPHA_SHOW_LAST_LINE_MS) {
            unsigned char r, g, b;
            double alpha2 = double(lineHasGone) / ALPHA_SHOW_LAST_LINE_MS;
            double alpha1 = 1 - alpha2;

            r = m_HilightColor.Red() * alpha1 + m_TextColor.Red() * alpha2;
            g = m_HilightColor.Green() * alpha1 + m_TextColor.Green() * alpha2;
            b = m_HilightColor.Blue() * alpha1 + m_TextColor.Blue() * alpha2;

            dc.SetTextForeground(wxColour(r, g, b));
        }
    } else if (index == currLineIndex) { // 高亮当前文本行
        // 尽管这是一种很罕见的情况,但一旦出现了就会导致下面 (*) 表达式
        // 的除数为 0
        if (currLine->GetMilSeconds() == 0) {
            return VCCDRF_DODEFAULT;
        }

        if (!cell->IsEmpty()) {
            /* 经验教训:
            1. SetClippingRegiion 有叠加效应,因此在执行新的
               SetClippingRegiion 前别忘了销毁原来的 ClippingRegiion 。
            2. 关于表达式中整数与浮点数混用:注意中间运算结果会
               被强制转换成 int 然后参加下一步的运算,并不是对
               最终结果进行转换,使之成为一个浮点数。
            */

            const int rowHeight = GetRowHeight();
            int y = (currLineIndex + m_blankLinesTop) * rowHeight;
            cell->DrawLabel(dc, 0, y);

            // (*)
            double lineProgress = double(lineHasGone) / currLine->GetMilSeconds();

            // 要实现 KALA-OK 效果的文本宽度
            int w = (m_Rect.width - cell->GetX_Padding() * 2) * lineProgress;

            wxRect rc(GetAbsoluteRect());
            const int bottom = rc.y + rc.height;

            int yStart;
            VdkScrolledWindow::GetViewStartCoord(NULL, &yStart);
            rc.y += y - yStart;

            rc.width = cell->GetX_Padding() + w;
            rc.height = rowHeight;
            // 不能使 KALA-OK 效果的 ClippingRegion 超出列表窗口
            if ((rc.y + rc.height) > bottom) {
                rc.height = bottom - rc.y;
            }

            VdkDcDeviceOriginSaver saver(dc);
            dc.SetDeviceOrigin(0, 0);
            VdkDcClippingRegionDestroyer destroyer(dc, rc);

#       ifdef __WXGTK__
            dc.SetBrush(m_crossBrush1);
            dc.DrawRectangle(rc);
#       endif
            dc.SetTextForeground(m_HilightColor);

            cell->DrawLabel(dc, rc.x, rc.y);
        }

        return VCCDRF_SKIPDEFAULT;
    }

    return VCCDRF_DODEFAULT;
}