Ejemplo n.º 1
0
void View::DrawTupletPostponed(DeviceContext *dc, Tuplet *tuplet, Layer *layer, Staff *staff)
{
    assert(dc);
    assert(tuplet);
    assert(layer);
    assert(staff);

    if ((tuplet->GetBracketVisible() == BOOLEAN_false) && (tuplet->GetNumVisible() == BOOLEAN_false)) {
        tuplet->SetEmptyBB();
        return;
    }

    tuplet->ResetList(tuplet);

    TextExtend extend;
    std::wstring notes;

    Point start, end, center;
    data_STEMDIRECTION direction = GetTupletCoordinates(tuplet, layer, &start, &end, &center);
    int x1 = center.x, x2 = center.x;

    // draw tuplet numerator
    if ((tuplet->GetNum() > 0) && (tuplet->GetNumVisible() != BOOLEAN_false)) {
        bool drawingCueSize = tuplet->GetDrawingCueSize();
        dc->SetFont(m_doc->GetDrawingSmuflFont(staff->m_drawingStaffSize, drawingCueSize));
        notes = IntToTupletFigures((short int)tuplet->GetNum());
        if (tuplet->GetNumFormat() == tupletVis_NUMFORMAT_ratio) {
            notes.push_back(SMUFL_E88A_tupletColon);
            notes = notes + IntToTupletFigures((short int)tuplet->GetNumbase());
        }
        dc->GetSmuflTextExtent(notes, &extend);

        // Calculate position for number 0x82
        // since the number is slanted, move the center left
        int txtX = x1 - (extend.m_width / 2);
        // and move it further, when it is under the stave
        if (direction == STEMDIRECTION_down) {
            txtX -= staff->m_drawingStaffSize;
        }
        // we need to move down the figure of half of it height, which is about an accid width;
        // also, cue size is not supported. Does it has to?
        int txt_y
            = center.y - m_doc->GetGlyphWidth(SMUFL_E262_accidentalSharp, staff->m_drawingStaffSize, drawingCueSize);

        DrawSmuflString(dc, txtX, txt_y, notes, false, staff->m_drawingStaffSize);

        // x1 = 10 pixels before the number
        x1 = ((txtX - 40) > start.x) ? txtX - 40 : start.x;
        // x2 = just after, the number is abundant so I do not add anything
        x2 = txtX + extend.m_width + 20;

        dc->ResetFont();
    }

    // Nothing to do if the bracket is not visible
    if (tuplet->GetBracketVisible() == BOOLEAN_false) {
        return;
    }
    // If all tuplets beamed draw no bracket by default
    if (OneBeamInTuplet(tuplet) && !(tuplet->GetBracketVisible() == BOOLEAN_true)) {
        return;
    }

    int verticalLine = m_doc->GetDrawingUnit(100);

    dc->SetPen(m_currentColour, m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize), AxSOLID);

    // Draw the bracket, interrupt where the number is

    // get the slope
    double m = (double)(start.y - end.y) / (double)(start.x - end.x);

    // calculate the y coords in the slope
    double y1 = (double)start.y + m * (x1 - (double)start.x);
    double y2 = (double)start.y + m * (x2 - (double)start.x);

    if (tuplet->GetNumVisible() == BOOLEAN_false) {
        // one single line
        dc->DrawLine(start.x, ToDeviceContextY(start.y), end.x, ToDeviceContextY(end.y));
    }
    else {
        // first line
        dc->DrawLine(start.x, ToDeviceContextY(start.y), (int)x1, ToDeviceContextY((int)y1));
        // second line after gap
        dc->DrawLine((int)x2, ToDeviceContextY((int)y2), end.x, ToDeviceContextY(end.y));
    }

    // vertical bracket lines
    if (direction == STEMDIRECTION_up) {
        dc->DrawLine(start.x + m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize) / 2, ToDeviceContextY(start.y),
            start.x + m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize) / 2,
            ToDeviceContextY(start.y - verticalLine));
        dc->DrawLine(end.x - m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize) / 2, ToDeviceContextY(end.y),
            end.x - m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize) / 2, ToDeviceContextY(end.y - verticalLine));
    }
    else {
        dc->DrawLine(start.x + m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize) / 2, ToDeviceContextY(start.y),
            start.x + m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize) / 2,
            ToDeviceContextY(start.y + verticalLine));
        dc->DrawLine(end.x - m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize) / 2, ToDeviceContextY(end.y),
            end.x - m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize) / 2, ToDeviceContextY(end.y + verticalLine));
    }

    dc->ResetPen();
}
Ejemplo n.º 2
0
data_STEMDIRECTION View::GetTupletCoordinates(Tuplet *tuplet, Layer *layer, Point *start, Point *end, Point *center)
{
    assert(tuplet);
    assert(layer);
    assert(start);
    assert(end);
    assert(center);

    Point first, last;
    int x, y;
    data_STEMDIRECTION direction = STEMDIRECTION_up;

    ListOfObjects *tupletChildren = tuplet->GetList(tuplet);
    LayerElement *firstElement = dynamic_cast<LayerElement *>(tupletChildren->front());
    LayerElement *lastElement = dynamic_cast<LayerElement *>(tupletChildren->back());

    // AllNotesBeamed tries to figure out if all the notes are in the same beam
    if (OneBeamInTuplet(tuplet)) {

        // yes they are in a beam
        x = firstElement->GetDrawingX()
            + (lastElement->GetDrawingX() - firstElement->GetDrawingX() + lastElement->m_selfBB_x2) / 2;

        // align the center point at the exact center of the first an last stem
        // TUPLET_OFFSET is summed so it does not collide with the stem
        Note *firstNote = dynamic_cast<Note *>(tuplet->FindChildByType(NOTE));
        Note *lastNote = dynamic_cast<Note *>(tuplet->FindChildByType(NOTE, UNLIMITED_DEPTH, BACKWARD));

        y = firstElement->GetDrawingY();
        if (firstNote && lastNote) {
            if (firstNote->GetDrawingStemDir() == STEMDIRECTION_up)
                y = lastNote->GetDrawingStemEnd().y
                    + (firstNote->GetDrawingStemEnd().y - lastNote->GetDrawingStemEnd().y) / 2 + TUPLET_OFFSET;
            else
                y = lastNote->GetDrawingStemEnd().y
                    + (firstNote->GetDrawingStemEnd().y - lastNote->GetDrawingStemEnd().y) / 2 - TUPLET_OFFSET;
        }

        // Copy the generated coordinates
        center->x = x;
        center->y = y;
        direction = firstNote->GetDrawingStemDir(); // stem direction is the same for all notes
    }
    else {
        // There are unbeamed notes of two different beams
        // treat all the notes as unbeamed
        int ups = 0, downs = 0; // quantity of up- and down-stems

        // In this case use the center of the notehead to calculate the exact center
        // as it looks better
        x = firstElement->GetDrawingX()
            + (lastElement->GetDrawingX() - firstElement->GetDrawingX() + lastElement->m_selfBB_x2) / 2;

        // Return the start and end position for the brackes
        // starting from the first edge and last of the BBoxes
        start->x = firstElement->m_selfBB_x1 + firstElement->GetDrawingX();
        end->x = lastElement->m_selfBB_x2 + lastElement->GetDrawingX();

        // The first step is to calculate all the stem directions
        // cycle into the elements and count the up and down dirs
        ListOfObjects::iterator iter = tupletChildren->begin();
        while (iter != tupletChildren->end()) {
            if ((*iter)->Is() == NOTE) {
                Note *currentNote = dynamic_cast<Note *>(*iter);
                assert(currentNote);
                if (currentNote->GetDrawingStemDir() == STEMDIRECTION_up)
                    ups++;
                else
                    downs++;
            }
            ++iter;
        }
        // true means up
        direction = ups > downs ? STEMDIRECTION_up : STEMDIRECTION_down;

        // if ups or downs are 0, it means all the stems go in the same direction
        if (ups == 0 || downs == 0) {

            Note *firstNote = dynamic_cast<Note *>(tuplet->FindChildByType(NOTE));
            Note *lastNote = dynamic_cast<Note *>(tuplet->FindChildByType(NOTE, UNLIMITED_DEPTH, BACKWARD));

            // Calculate the average between the first and last stem
            // set center, start and end too.
            y = firstElement->GetDrawingY();
            if (firstNote && lastNote) {
                if (direction == STEMDIRECTION_up) { // up
                    y = lastNote->GetDrawingStemEnd().y
                        + (firstNote->GetDrawingStemEnd().y - lastNote->GetDrawingStemEnd().y) / 2 + TUPLET_OFFSET;
                    start->y = firstNote->GetDrawingStemEnd().y + TUPLET_OFFSET;
                    end->y = lastNote->GetDrawingStemEnd().y + TUPLET_OFFSET;
                }
                else {
                    y = lastNote->GetDrawingStemEnd().y
                        + (firstNote->GetDrawingStemEnd().y - lastNote->GetDrawingStemEnd().y) / 2 - TUPLET_OFFSET;
                    start->y = firstNote->GetDrawingStemEnd().y - TUPLET_OFFSET;
                    end->y = lastNote->GetDrawingStemEnd().y - TUPLET_OFFSET;
                }
            }

            // Now we cycle again in all the intermediate notes (i.e. we start from the second note
            // and stop at last -1)
            // We will see if the position of the note is more (or less for down stems) of the calculated
            // average. In this case we offset down or up all the points
            iter = tupletChildren->begin();
            while (iter != tupletChildren->end()) {
                if ((*iter)->Is() == NOTE) {
                    Note *currentNote = dynamic_cast<Note *>(*iter);
                    assert(currentNote);

                    if (direction == STEMDIRECTION_up) {
                        // The note is more than the avg, adjust to y the difference
                        // from this note to the avg
                        if (currentNote->GetDrawingStemEnd().y + TUPLET_OFFSET > y) {
                            int offset = y - (currentNote->GetDrawingStemEnd().y + TUPLET_OFFSET);
                            y -= offset;
                            end->y -= offset;
                            start->y -= offset;
                        }
                    }
                    else {
                        if (currentNote->GetDrawingStemEnd().y - TUPLET_OFFSET < y) {
                            int offset = y - (currentNote->GetDrawingStemEnd().y - TUPLET_OFFSET);
                            y -= offset;
                            end->y -= offset;
                            start->y -= offset;
                        }
                    }
                }
                ++iter;
            }
        }
        else {
            // two-directional beams
            // this case is similar to the above, but the bracket is only horizontal
            // y is 0 because the final y pos is above the tallest stem
            y = 0;

            // Find the tallest stem and set y to it (with the offset distance)
            iter = tupletChildren->begin();
            while (iter != tupletChildren->end()) {
                if ((*iter)->Is() == NOTE) {
                    Note *currentNote = dynamic_cast<Note *>(*iter);
                    assert(currentNote);

                    if (currentNote->GetDrawingStemDir() == direction) {
                        if (direction == STEMDIRECTION_up) {
                            if (y == 0 || currentNote->GetDrawingStemEnd().y + TUPLET_OFFSET >= y)
                                y = currentNote->GetDrawingStemEnd().y + TUPLET_OFFSET;
                        }
                        else {
                            if (y == 0 || currentNote->GetDrawingStemEnd().y - TUPLET_OFFSET <= y)
                                y = currentNote->GetDrawingStemEnd().y - TUPLET_OFFSET;
                        }
                    }
                    else {
                        // do none for now
                        // but if a notehead with a reversed stem is taller that the last
                        // calculated y, we need to offset
                    }
                }
                ++iter;
            }

            // end and start are on the same line (and so il center when set later)
            end->y = start->y = y;
        }
    }

    center->x = x;
    center->y = y;
    return direction;
}
Ejemplo n.º 3
0
bool View::GetTupletCoordinates(Tuplet* tuplet, Layer *layer, MusPoint* start, MusPoint* end, MusPoint *center) {
    MusPoint first, last;
    int x, y;
    bool direction = true; //true = up, false = down
    
    LayerElement *firstNote, *lastNote;
    
    // AllNotesBeamed tries to figure out if all the notes are in the same beam
    if (OneBeamInTuplet(tuplet)) {
        
        firstNote = dynamic_cast<LayerElement*>(tuplet->m_list.front());
        lastNote = dynamic_cast<LayerElement*>(tuplet->m_list.back());

        // yes they are in a beam
        // get the x position centered from the STEM so it looks better
        // NOTE start and end are left to 0, this is the signal that no bracket has to be drawn
        x = firstNote->m_drawingStemStart.x + (lastNote->m_drawingStemStart.x - firstNote->m_drawingStemStart.x) / 2;
        
        // align the center point at the exact center of the first an last stem
        // TUPLET_OFFSET is summed so it does not collide with the stem
        if (firstNote->m_drawingStemDir)
            y = lastNote->m_drawingStemEnd.y + (firstNote->m_drawingStemEnd.y - lastNote->m_drawingStemEnd.y) / 2 + TUPLET_OFFSET;
        else 
            y = lastNote->m_drawingStemEnd.y + (firstNote->m_drawingStemEnd.y - lastNote->m_drawingStemEnd.y) / 2 - TUPLET_OFFSET;
        
        // Copy the generated coordinates
        center->x = x;
        center->y = y;
        direction =  firstNote->m_drawingStemDir; // stem direction is same for all notes
    } else {
            
        //ArrayOfObjects all_notes;
        
        // We can have a mixed group of Beams and notes. Flatten it
        /*
        for (unsigned int i = 0; i < tuplet->m_children.size(); i++) {
            if (dynamic_cast<Note*>(tuplet->m_children[i]))
                all_notes.push_back(tuplet->m_children[i]);
            
            if (dynamic_cast<Beam*>(tuplet->m_children[i])) {
                Beam* beam = dynamic_cast<Beam*>(tuplet->m_children[i]);
                std::copy( beam->m_list.begin(), beam->m_list.end(), std::back_inserter( all_notes ) );
            }
        }*/
        
        firstNote = dynamic_cast<LayerElement*>(tuplet->m_list.front());
        lastNote = dynamic_cast<LayerElement*>(tuplet->m_list.back());
        
        // There are unbeamed notes of two different beams
        // treat all the notes as unbeames
        int ups = 0, downs = 0; // quantity of up- and down-stems
        
        // In this case use the center of the notehead to calculate the exact center
        // as it looks better
        x = firstNote->GetDrawingX() + (lastNote->GetDrawingX() - firstNote->GetDrawingX() + lastNote->m_selfBB_x2) / 2;
        
        // Return the start and end position for the brackes
        // starting from the first edge and last of the BBoxes
        start->x = firstNote->m_selfBB_x1 + firstNote->GetDrawingX();
        end->x = lastNote->m_selfBB_x2 + lastNote->GetDrawingX();
        
        // THe first step is to calculate all the stem directions
        // cycle into the elements and count the up and down dirs
        ListOfObjects::iterator iter = tuplet->m_list.begin();
        while (iter != tuplet->m_list.end()) {
            LayerElement *currentNote = dynamic_cast<LayerElement*>(*iter);
            
            if (currentNote->m_drawingStemDir == true)
                ups++;
            else
                downs++;
            
            ++iter;
        }
        // true means up
        direction = ups > downs ? true : false;
        
        // if ups or downs is 0, it means all the stems go in the same direction
        if (ups == 0 || downs == 0) {
            
            // Calculate the average between the first and last stem
            // set center, start and end too.
            if (direction) { // up
                y = lastNote->m_drawingStemEnd.y + (firstNote->m_drawingStemEnd.y - lastNote->m_drawingStemEnd.y) / 2 + TUPLET_OFFSET;
                start->y = firstNote->m_drawingStemEnd.y + TUPLET_OFFSET;
                end->y = lastNote->m_drawingStemEnd.y + TUPLET_OFFSET;
            } else {
                y = lastNote->m_drawingStemEnd.y + (firstNote->m_drawingStemEnd.y - lastNote->m_drawingStemEnd.y) / 2 - TUPLET_OFFSET;
                start->y = firstNote->m_drawingStemEnd.y - TUPLET_OFFSET;
                end->y = lastNote->m_drawingStemEnd.y - TUPLET_OFFSET;
            }
            
            // Now we cycle again in all the intermediate notes (i.e. we start from the second note
            // and stop at last -1)
            // We will see if the position of the note is more (or less for down stems) of the calculated
            // average. In this case we offset down or up all the points
            iter = tuplet->m_list.begin();
            while (iter != tuplet->m_list.end()) {
                 LayerElement *currentNote = dynamic_cast<LayerElement*>(*iter);
                
                if (direction) {
                    // The note is more than the avg, adjust to y the difference
                    // from this note to the avg
                    if (currentNote->m_drawingStemEnd.y + TUPLET_OFFSET > y) {
                        int offset = y - (currentNote->m_drawingStemEnd.y + TUPLET_OFFSET);
                        y -= offset;
                        end->y -= offset;
                        start->y -= offset;
                    }
                } else {
                    if (currentNote->m_drawingStemEnd.y - TUPLET_OFFSET < y) {
                        int offset = y - (currentNote->m_drawingStemEnd.y - TUPLET_OFFSET);
                        y -= offset;
                        end->y -= offset;
                        start->y -= offset;
                    }
                }
                
                ++iter;
            }
            
            
        } else { // two directional beams
            // this case is similar to the above, but the bracket is only orizontal
            // y is 0 because the final y pos is above the tallest stem
            y = 0;
            
            // Find the tallest stem and set y to it (with the offset distance)
            iter = tuplet->m_list.begin();
            while (iter != tuplet->m_list.end()) {
                LayerElement *currentNote = dynamic_cast<LayerElement*>(*iter);
                
                if (currentNote->m_drawingStemDir == direction) {
                                        
                    if (direction) {
                        if (y == 0 || currentNote->m_drawingStemEnd.y + TUPLET_OFFSET >= y)
                            y = currentNote->m_drawingStemEnd.y + TUPLET_OFFSET;
                    } else {
                        if (y == 0 || currentNote->m_drawingStemEnd.y - TUPLET_OFFSET <= y)
                            y = currentNote->m_drawingStemEnd.y - TUPLET_OFFSET;
                    }
                        
                } else {
                    // do none for now
                    // but if a notehead with a reversed stem is taller that the last
                    // calculated y, we need to offset
                }
                
                ++iter;
            }
            
            // end and start are on the same line (and so il center when set later)
            end->y = start->y = y;
        }
    }
        
    
    center->x = x;
    center->y = y;
    return direction;
}