@@ -1927,6 +1927,91 @@ void MeasureLayout::setCourtesyClef(Measure* m, const Fraction& refClefTick, con
19271927 }
19281928}
19291929
1930+ void MeasureLayout::placeParentheses (const Segment* segment, track_idx_t trackIdx, LayoutContext& ctx)
1931+ {
1932+ const EngravingItem* segItem = segment->elementAt (trackIdx);
1933+ const std::vector<EngravingItem*> parens = segment->findAnnotations (ElementType::PARENTHESIS, trackIdx, trackIdx);
1934+ assert (parens.size () <= 2 );
1935+ if (parens.empty () || !segItem) {
1936+ return ;
1937+ }
1938+
1939+ Shape dummySegShape = segment->staffShape (track2staff (trackIdx));
1940+ dummySegShape.remove_if ([](ShapeElement& shapeEl) {
1941+ return shapeEl.item () && shapeEl.item ()->isParenthesis ();
1942+ });
1943+
1944+ if (parens.size () == 1 ) {
1945+ // 1 parenthesis
1946+ Parenthesis* paren = toParenthesis (parens.front ());
1947+ const bool leftBracket = paren->direction () == DirectionH::LEFT;
1948+ TLayout::layoutParenthesis (paren, ctx);
1949+ if (!leftBracket) {
1950+ // Space against existing segment shape
1951+ const double minDist = HorizontalSpacing::minHorizontalDistance (dummySegShape, paren->shape ().translated (
1952+ paren->pos ()), paren->spatium ());
1953+ paren->mutldata ()->moveX (minDist);
1954+ } else {
1955+ // Space following segment shape against this
1956+ const double minDist = HorizontalSpacing::minHorizontalDistance (paren->shape ().translated (
1957+ paren->pos ()), dummySegShape, paren->spatium ());
1958+ paren->mutldata ()->moveX (-minDist);
1959+ }
1960+ return ;
1961+ }
1962+
1963+ // 2 parentheses
1964+ Parenthesis* leftParen = nullptr ;
1965+ Parenthesis* rightParen = nullptr ;
1966+ for (EngravingItem* paren : parens) {
1967+ if (toParenthesis (paren)->direction () == DirectionH::LEFT) {
1968+ leftParen = toParenthesis (paren);
1969+ continue ;
1970+ }
1971+
1972+ rightParen = toParenthesis (paren);
1973+ }
1974+
1975+ assert (leftParen && rightParen);
1976+
1977+ TLayout::layoutParenthesis (toParenthesis (leftParen), ctx);
1978+ TLayout::layoutParenthesis (toParenthesis (rightParen), ctx);
1979+
1980+ const double itemLeftX = segItem->pos ().x ();
1981+ const double itemRightX = itemLeftX + segItem->width ();
1982+
1983+ const double leftParenPadding = HorizontalSpacing::minHorizontalDistance (leftParen->shape ().translated (leftParen->pos ()),
1984+ dummySegShape, leftParen->spatium ());
1985+ leftParen->mutldata ()->moveX (-leftParenPadding);
1986+ dummySegShape.add (leftParen->shape ().translate (leftParen->pos () + leftParen->staffOffset ()));
1987+
1988+ const double rightParenPadding = HorizontalSpacing::minHorizontalDistance (dummySegShape, rightParen->shape ().translated (
1989+ rightParen->pos ()), rightParen->spatium ());
1990+ rightParen->mutldata ()->moveX (rightParenPadding);
1991+
1992+ // If the right parenthesis has been padded against the left parenthesis, this means the parenthesis -> parenthesis padding distance
1993+ // is larger than the width of the item the parentheses surrounds. In this case, the result is visually unbalanced. Move both parens
1994+ // to the left (relative to the segment) in order to centre the item: (b ) -> ( b )
1995+ const double itemWidth = segItem->width ();
1996+ const double parenPadding = segment->score ()->paddingTable ().at (ElementType::PARENTHESIS).at (ElementType::PARENTHESIS);
1997+
1998+ if (itemWidth >= parenPadding) {
1999+ return ;
2000+ }
2001+
2002+ // Move parentheses to place item in the middle
2003+ const double leftParenX = leftParen->pos ().x () + leftParen->ldata ()->bbox ().x () + leftParen->ldata ()->thickness ;
2004+ const double rightParenX = rightParen->pos ().x () + rightParen->ldata ()->bbox ().x () + rightParen->width ()
2005+ - rightParen->ldata ()->thickness ;
2006+
2007+ const double leftParenToItem = itemLeftX - leftParenX;
2008+ const double itemToRightParen = rightParenX - itemRightX;
2009+ const double parenToItemDist = (leftParenToItem + itemToRightParen) / 2 ;
2010+
2011+ leftParen->mutldata ()->moveX (-std::abs (parenToItemDist - leftParenToItem));
2012+ rightParen->mutldata ()->moveX (-std::abs (itemToRightParen - parenToItemDist));
2013+ }
2014+
19302015Parenthesis* MeasureLayout::findOrCreateParenthesis (Segment* segment, const DirectionH direction, const track_idx_t track)
19312016{
19322017 if (!segment || !segment->element (track)) {
@@ -2037,6 +2122,14 @@ void MeasureLayout::addRepeatCourtesyParentheses(Measure* m, const bool continua
20372122 leftParen->mutldata ()->startY .set_value (top);
20382123 leftParen->mutldata ()->height .set_value (height);
20392124 }
2125+
2126+ if (leftParen) {
2127+ placeParentheses (leftMostSeg, track2staff (track), ctx);
2128+ }
2129+
2130+ if (rightParen && rightMostSeg != leftMostSeg) {
2131+ placeParentheses (rightMostSeg, track2staff (track), ctx);
2132+ }
20402133 }
20412134}
20422135
0 commit comments