📄 sequence_viewer_widget.cpp
字号:
void SequenceViewerWidget_SequenceArea::DrawLine(wxDC& dc, int x1, int y1, int x2, int y2){ if (currentRubberbandType == eSolid) { dc.DrawLine(x1, y1, x2, y2); } else { // short-dashed line int i, ie; if (x1 == x2) { // vertical line min_max(y1, y2, &i, &ie); ie -= 1; for (; i<=ie; ++i) if (i%4 == 0) dc.DrawLine(x1, i, x1, i + 2); } else { // horizontal line min_max(x1, x2, &i, &ie); ie -= 1; for (; i<=ie; ++i) if (i%4 == 0) dc.DrawLine(i, y1, i + 2, y1); } }}// draw a rubberband around the cellsvoid SequenceViewerWidget_SequenceArea::DrawRubberband(wxDC& dc, int fromX, int fromY, int toX, int toY, int vsX, int vsY){ // find upper-left and lower-right corners int minX, minY, maxX, maxY; min_max(fromX, toX, &minX, &maxX); min_max(fromY, toY, &minY, &maxY); // convert to pixel coordinates of corners minX = (minX - vsX) * cellWidth; minY = (minY - vsY) * cellHeight; maxX = (maxX - vsX) * cellWidth + cellWidth - 1; maxY = (maxY - vsY) * cellHeight + cellHeight - 1; // set color dc.SetPen(*(wxThePenList->FindOrCreatePen(currentRubberbandColor, 1, wxSOLID))); // draw sides (should draw in order, due to pixel roundoff) if (mouseMode != SequenceViewerWidget::eSelectColumns) DrawLine(dc, minX, minY, maxX, minY); // top if (mouseMode != SequenceViewerWidget::eSelectRows) DrawLine(dc, maxX, minY, maxX, maxY); // right if (mouseMode != SequenceViewerWidget::eSelectColumns) DrawLine(dc, maxX, maxY, minX, maxY); // bottom if (mouseMode != SequenceViewerWidget::eSelectRows) DrawLine(dc, minX, maxY, minX, minY); // left}// move the rubber band to a new rectangle, erasing only the side(s) of the// rectangle that is changingvoid SequenceViewerWidget_SequenceArea::MoveRubberband(wxDC &dc, int fromX, int fromY, int prevToX, int prevToY, int toX, int toY, int vsX, int vsY){ int i; if ((prevToX >= fromX && toX < fromX) || (prevToX < fromX && toX >= fromX) || (prevToY >= fromY && toY < fromY) || (prevToY < fromY && toY >= fromY)) { // need to completely redraw if rectangle is "flipped" RemoveRubberband(dc, fromX, fromY, prevToX, prevToY, vsX, vsY); } else { int a, b; // erase moving bottom/top side if dragging up/down if (toY != prevToY) { min_max(fromX, prevToX, &a, &b); for (i=a; i<=b; ++i) DrawCell(dc, i, prevToY, vsX, vsY, true); } // erase partial top and bottom if dragging left by more than one a = -1; b = -2; if (fromX <= toX && toX < prevToX) { a = toX + 1; b = prevToX - 1; } else if (prevToX < toX && toX < fromX) { a = prevToX + 1; b = toX - 1; } for (i=a; i<=b; ++i) { DrawCell(dc, i, fromY, vsX, vsY, true); DrawCell(dc, i, prevToY, vsX, vsY, true); } // erase moving left/right side if (toX != prevToX) { min_max(fromY, prevToY, &a, &b); for (i=a; i<=b; ++i) DrawCell(dc, prevToX, i, vsX, vsY, true); } // erase partial left and right sides if dragging up/down by more than one a = -1; b = -2; if (fromY <= toY && toY < prevToY) { a = toY + 1; b = prevToY - 1; } else if (prevToY < toY && toY < fromY) { a = prevToY + 1; b = toY - 1; } for (i=a; i<=b; ++i) { DrawCell(dc, fromX, i, vsX, vsY, true); DrawCell(dc, prevToX, i, vsX, vsY, true); } } // redraw whole new one DrawRubberband(dc, fromX, fromY, toX, toY, vsX, vsY);}// redraw only those cells necessary to remove rubber bandvoid SequenceViewerWidget_SequenceArea::RemoveRubberband(wxDC& dc, int fromX, int fromY, int toX, int toY, int vsX, int vsY){ int i, min, max; // remove top and bottom min_max(fromX, toX, &min, &max); for (i=min; i<=max; ++i) { DrawCell(dc, i, fromY, vsX, vsY, true); DrawCell(dc, i, toY, vsX, vsY, true); } // remove left and right min_max(fromY, toY, &min, &max); for (i=min+1; i<=max-1; ++i) { DrawCell(dc, fromX, i, vsX, vsY, true); DrawCell(dc, toX, i, vsX, vsY, true); }}void SequenceViewerWidget_SequenceArea::OnScrollWin(wxScrollWinEvent& event){ // when scrolling happens via scrollbars (or movement keys), need to update status bar info. // So, fake a (non-moving) mouse wheel event, which will trigger MouseOver. wxMouseEvent fake(wxEVT_MOUSEWHEEL); fake.m_wheelRotation = 0; fake.m_wheelDelta = 120; fake.m_linesPerAction = 3; AddPendingEvent(fake); event.Skip(); // continue to process this event normally}void SequenceViewerWidget_SequenceArea::OnMouseEvent(wxMouseEvent& event){ static const ViewableAlignment *prevAlignment = NULL; static int prevMOX = -1, prevMOY = -1; static bool dragging = false; if (!alignment) { prevAlignment = NULL; prevMOX = prevMOY = -1; dragging = false; return; } if (alignment != prevAlignment) { prevMOX = prevMOY = -1; prevAlignment = alignment; dragging = false; } // get coordinates of mouse when it's over the drawing area wxCoord mX, mY; event.GetPosition(&mX, &mY); // get current view window location int vsX, vsY; GetViewStart(&vsX, &vsY); // handle wheel events static wxCoord windowMX = 0, windowMY = 0; bool wheelEvent = (event.GetEventType() == wxEVT_MOUSEWHEEL); if (wheelEvent) { if (dragging || windowMX < 0 || windowMY < 0 || windowMX >= GetClientSize().GetWidth() || windowMY >= GetClientSize().GetHeight()) return; mX = windowMX; // coords on mouse wheel event seem to be screen-relative, not window-relative mY = windowMY; static int accumulatedRotation = 0; accumulatedRotation -= event.GetWheelRotation(); // move wheel up -> scroll up int nDeltas = accumulatedRotation / event.GetWheelDelta(); if (nDeltas != 0) { accumulatedRotation -= nDeltas * event.GetWheelDelta(); int toY = vsY + nDeltas * event.GetLinesPerAction(); if (toY < 0) toY = 0; else if (toY >= areaHeight) toY = areaHeight - 1; Scroll(-1, toY); GetViewStart(&vsX, &vsY); // update vsY so that MouseOver is called on new position } } else { windowMX = mX; windowMY = mY; } // translate visible area coordinates to cell coordinates int cellX, cellY, MOX, MOY; cellX = MOX = vsX + mX / cellWidth; cellY = MOY = vsY + mY / cellHeight; // if the mouse is leaving the window, use cell coordinates of most // recent known mouse-over cell if (event.Leaving()) { cellX = prevMOX; cellY = prevMOY; MOX = MOY = -1; } // do MouseOver if not in the same cell (or outside area) as last time if (MOX >= areaWidth || MOY >= areaHeight) MOX = MOY = -1; if (MOX != prevMOX || MOY != prevMOY) alignment->MouseOver(MOX, MOY); prevMOX = MOX; prevMOY = MOY; if (wheelEvent) return; // adjust for column/row selection if (mouseMode == SequenceViewerWidget::eSelectColumns) cellY = vsY + GetClientSize().GetHeight() / cellHeight; else if (mouseMode == SequenceViewerWidget::eSelectRows) cellX = vsX + GetClientSize().GetWidth() / cellWidth; // limit coordinates of selection to virtual area if (cellX < 0) cellX = 0; else if (cellX >= areaWidth) cellX = areaWidth - 1; if (cellY < 0) cellY = 0; else if (cellY >= areaHeight) cellY = areaHeight - 1; // keep track of position of selection start, as well as last // cell dragged to during selection static int fromX, fromY, prevToX, prevToY; // limit dragging movement if necessary if (dragging) { if (mouseMode == SequenceViewerWidget::eDragHorizontal) cellY = fromY; if (mouseMode == SequenceViewerWidget::eDragVertical) cellX = fromX; } // process beginning of selection if (event.LeftDown()) { // find out which (if any) control keys are down at this time unsigned int controls = 0; if (event.ShiftDown()) controls |= ViewableAlignment::eShiftDown;#ifdef __WXMAC__ if (event.MetaDown()) // control key + mouse doesn't work on Mac?#else if (event.ControlDown())#endif controls |= ViewableAlignment::eControlDown; if (event.AltDown() || event.MetaDown()) controls |= ViewableAlignment::eAltOrMetaDown; // send MouseDown message; don't start selection if MouseDown returns false // or if not inside display area if (alignment->MouseDown(MOX, MOY, controls) && MOX != -1) { prevToX = fromX = cellX; prevToY = fromY = cellY; dragging = true; TRACEMSG("drawing initial rubberband"); wxClientDC dc(this); dc.BeginDrawing(); currentRubberbandType = (mouseMode == SequenceViewerWidget::eSelectRectangle || mouseMode == SequenceViewerWidget::eSelectColumns || mouseMode == SequenceViewerWidget::eSelectRows) ? eDot : eSolid; if (mouseMode == SequenceViewerWidget::eSelectColumns) { fromY = vsY; prevToY = cellY; DrawRubberband(dc, fromX, fromY, fromX, cellY, vsX, vsY); } else if (mouseMode == SequenceViewerWidget::eSelectRows) { fromX = vsX; prevToX = cellX; DrawRubberband(dc, fromX, fromY, cellX, fromY, vsX, vsY); } else { DrawRubberband(dc, fromX, fromY, fromX, fromY, vsX, vsY); } dc.EndDrawing(); } } // process end of selection, on mouse-up, or if the mouse leaves the window else if (dragging && (event.LeftUp() || event.Leaving() || event.Entering())) { if (!event.LeftUp()) { cellX = prevToX; cellY = prevToY; } dragging = false; wxClientDC dc(this); dc.BeginDrawing(); dc.SetFont(*currentFont); // remove rubberband if (mouseMode == SequenceViewerWidget::eSelectRectangle || mouseMode == SequenceViewerWidget::eSelectColumns || mouseMode == SequenceViewerWidget::eSelectRows) RemoveRubberband(dc, fromX, fromY, cellX, cellY, vsX, vsY); else { DrawCell(dc, fromX, fromY, vsX, vsY, true); if (cellX != fromX || cellY != fromY) DrawCell(dc, cellX, cellY, vsX, vsY, true); } dc.EndDrawing(); // adjust for column/row selection if (mouseMode == SequenceViewerWidget::eSelectColumns) { fromY = 0; cellY = areaHeight - 1; } else if (mouseMode == SequenceViewerWidget::eSelectRows) { fromX = 0; cellX = areaWidth - 1; } // do appropriate callback if (mouseMode == SequenceViewerWidget::eSelectRectangle || mouseMode == SequenceViewerWidget::eSelectColumns || mouseMode == SequenceViewerWidget::eSelectRows) alignment->SelectedRectangle( (fromX < cellX) ? fromX : cellX, (fromY < cellY) ? fromY : cellY, (cellX > fromX) ? cellX : fromX, (cellY > fromY) ? cellY : fromY); else alignment->DraggedCell(fromX, fromY, cellX, cellY); } // process continuation of selection - redraw rectangle else if (dragging && (cellX != prevToX || cellY != prevToY)) { wxClientDC dc(this); dc.BeginDrawing(); dc.SetFont(*currentFont); currentRubberbandType = eDot; if (mouseMode == SequenceViewerWidget::eSelectRectangle || mouseMode == SequenceViewerWidget::eSelectColumns || mouseMode == SequenceViewerWidget::eSelectRows) { MoveRubberband(dc, fromX, fromY, prevToX, prevToY, cellX, cellY, vsX, vsY); } else { if (prevToX != fromX || prevToY != fromY) DrawCell(dc, prevToX, prevToY, vsX, vsY, true); if (cellX != fromX || cellY != fromY) { DrawRubberband(dc, cellX, cellY, cellX, cellY, vsX, vsY); } } dc.EndDrawing(); prevToX = cellX; prevToY = cellY; }}///////////////////////////////////////////////////////////////////////////////// This is the implementation of the title drawing area /////////////////////////////////////////////////////////////////////////////////BEGIN_EVENT_TABLE(SequenceViewerWidget_TitleArea, wxWindow) EVT_PAINT (SequenceViewerWidget_TitleArea::OnPaint) EVT_MOUSE_EVENTS (SequenceViewerWidget_TitleArea::OnMouseEvent)END_EVENT_TABLE()SequenceViewerWidget_TitleArea::SequenceViewerWidget_TitleArea( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size) : wxWindow(parent, id, pos, size, wxNO_3D), titleFont(NULL), cellHeight(0), maxTitleWidth(20), alignment(NULL), sequenceArea(NULL), highlightedTitleRow(-1){ currentBackgroundColor = *wxWHITE;}SequenceViewerWidget_TitleArea::~SequenceViewerWidget_TitleArea(void){ if (titleFont) delete titleFont;}void SequenceViewerWidget_TitleArea::ShowTitles(ViewableAlignment *newAlignment){ alignment = newAlignment; highlightedTitleRow = -1; if (!alignment) return; // set font wxClientDC dc(this); dc.SetFont(*titleFont); dc.SetMapMode(wxMM_TEXT); int i; wxString title; wxColor color; wxCoord tW, tH; // get maximum width of any title alignment->GetSize(&i, &nTitles); if (nTitles <= 0) return; maxTitleWidth = 20; for (i=0; i<nTitles; ++i) { if (!alignment->GetRowTitle(i, &title, &color)) continue; // measure title size dc.GetTextExtent(title, &tW, &tH); if (tW > maxTitleWidth) maxTitleWidth = tW; }}void SequenceViewerWidget_TitleArea::SetCharacterFont(wxFont *font, int newCellHeight){ if (!font) return; if (titleFont) delete titleFont; titleFont = font; cellHeight = newCellHeight; ShowTitles(alignment);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -