# Formatted / paragraph text

**URL:** <https://iplug2.discourse.group/t/formatted-paragraph-text/544>\
**Category:** Uncategorized\
**Created:** [13 January 2022 15:49 UTC](https://iplug2.discourse.group/t/formatted-paragraph-text/544 "2022-01-13T15:49:32Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![snfk](https://yyz2.discourse-cdn.com/free1/user_avatar/iplug2.discourse.group/snfk/32/140_2.png) [@snfk](https://iplug2.discourse.group/u/snfk)\
**Post date:** [13 January 2022 15:49 UTC](https://iplug2.discourse.group/t/formatted-paragraph-text/544/1 "2022-01-13T15:49:32Z")

</div>

I’m implementing some alert functions and attempted to implement a word wrapped function.

```auto

static void DrawWordWrappedText(IGraphics& g, IText& style, std::string text, IRECT mRECT) {
    std::vector<std::string> words;
    std::string temp = "";
    for (int i = 0; i < text.length(); i++) {
      if (text[i] == ' ') {
        words.push_back(temp);
        temp = "";
      }
      else {
        temp.push_back(text[i]);
      }
    }

    int i = 0;
    float length = 0;
    temp = "";
    float y = mRECT.T+10;
    float y_inc = 25;
    while (i < words.size()) {
      length = 0;
      temp = "";
      while (length < mRECT.W()) {
        if (i == words.size()) {
          break;
        }
        temp.append(words[i]);
        temp.push_back(' ');
        length = g.MeasureText(style, temp.c_str(), mRECT); //Always returns mRect.W()…
        i++;
      }
      g.DrawText(style, temp.c_str(), mRECT.L+3, y);
      y += y_inc;
    }

  }

```

Ignore any inconsistency in the code- it’s very ugly right now because of debugging 🙂

The issue is that the text measured is always the width of the IRECT passed through. (Because I’m not passing mRECT as a reference….? I’ve started to run out of ideas)

I’m using Skia, thanks for any help!

---

<div class="post-metadata">

**Author:** ![olilarkin](https://yyz2.discourse-cdn.com/free1/user_avatar/iplug2.discourse.group/olilarkin/32/2_2.png) [@olilarkin](https://iplug2.discourse.group/u/olilarkin)\
**Post date:** [13 January 2022 16:50 UTC](https://iplug2.discourse.group/t/formatted-paragraph-text/544/2 "2022-01-13T16:50:03Z")

</div>

Since you are using Skia, you could use SkParagraph, which is the most advanced way of drawing formatted text in iPlug2. Unfortunately the pre-built skia libs zips are missing some headers that got moved in the latest skia. With a bit of manually copying the missing headers, you can do this:

 ![Screenshot 2022-01-13 at 17.42.48](https://global.discourse-cdn.com/free1/uploads/iplug2/original/1X/e58c5cf3964155388f607ab88f59e37de8b74634.jpeg)  
 ![Screenshot 2022-01-13 at 17.48.19](https://global.discourse-cdn.com/free1/uploads/iplug2/original/1X/2be22d7a8417b1cd50733ebe2837986d9fccf511.jpeg)

```auto
/*
 ==============================================================================
 
 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
 
 See LICENSE.txt for more info.
 
 ==============================================================================
 */

#pragma once

#ifndef IGRAPHICS_SKIA
#error This IControl only works with the Skia graphics backend
#endif

#include "IControl.h"
#include "IGraphicsSkia.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColorFilter.h"
#include "include/core/SkColorPriv.h"
#include "include/core/SkFontMgr.h"
#include "include/core/SkGraphics.h"
#include "include/core/SkPath.h"
#include "include/core/SkRegion.h"
#include "include/core/SkShader.h"
#include "include/core/SkStream.h"
#include "include/core/SkTextBlob.h"
#include "include/core/SkTime.h"
#include "include/core/SkTypeface.h"
#include "include/effects/SkGradientShader.h"
#include "include/utils/SkRandom.h"
#include "modules/skparagraph/include/Paragraph.h"
#include "modules/skparagraph/include/TypefaceFontProvider.h"
#include "modules/skparagraph/src/ParagraphBuilderImpl.h"
#include "modules/skparagraph/src/ParagraphImpl.h"
#include "modules/skparagraph/src/TextLine.h"
#include "modules/skparagraph/utils/TestFontCollection.h"

#ifdef OS_WIN
#pragma comment(lib, "skparagraph.lib")
#pragma comment(lib, "skshaper.lib")
#endif

BEGIN_IPLUG_NAMESPACE
BEGIN_IGRAPHICS_NAMESPACE

using namespace skia::textlayout;

class ISkParagraphControl : public IControl
{
public:
  ISkParagraphControl(const IRECT& bounds)
  : IControl(bounds)
  {
  }
  
  void Draw(IGraphics& g) override
  {
    g.FillRect(COLOR_GREEN, mRECT);
    SkCanvas* canvas = (SkCanvas*) g.GetDrawContext();
    DoDrawContent(canvas);
  }
  
// void DoDrawContent(SkCanvas* canvas)
// {
// float w = mRECT.W();
// // float h = mRECT.H();
//
// const std::vector<
// std::tuple<std::string, bool, bool, int, SkColor, SkColor, bool, TextDecorationStyle>>
// gParagraph = { {"monospace", true, false, 14, SK_ColorWHITE, SK_ColorRED, true,
// TextDecorationStyle::kDashed},
// {"Assyrian", false, false, 20, SK_ColorWHITE, SK_ColorBLUE, false,
// TextDecorationStyle::kDotted},
// {"serif", true, true, 10, SK_ColorWHITE, SK_ColorRED, true,
// TextDecorationStyle::kDouble},
// {"Arial", false, true, 16, SK_ColorGRAY, SK_ColorGREEN, true,
// TextDecorationStyle::kSolid},
// {"sans-serif", false, false, 8, SK_ColorWHITE, SK_ColorRED, false,
// TextDecorationStyle::kWavy} };
// SkAutoCanvasRestore acr(canvas, true);
//
// // canvas->clipRect(SkRect::MakeWH(w, h));
// canvas->drawColor(SK_ColorWHITE);
//
// SkScalar margin = 20;
//
// SkPaint paint;
// paint.setAntiAlias(true);
// paint.setColor(SK_ColorWHITE);
//
// SkPaint blue;
// blue.setColor(SK_ColorBLUE);
//
// TextStyle defaultStyle;
// defaultStyle.setBackgroundColor(blue);
// defaultStyle.setForegroundColor(paint);
// ParagraphStyle paraStyle;
//
// auto fontCollection = sk_make_sp<FontCollection>();
// fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
// for (auto i = 1; i < 5; ++i) {
// defaultStyle.setFontSize(24 * i);
// paraStyle.setTextStyle(defaultStyle);
// ParagraphBuilderImpl builder(paraStyle, fontCollection);
// std::string name = "Paragraph: " + std::to_string(24 * i);
// builder.addText(name.c_str(), name.length());
// for (auto para : gParagraph) {
// TextStyle style;
// style.setFontFamilies({ SkString(std::get<0>(para).c_str()) });
// SkFontStyle fontStyle(std::get<1>(para) ? SkFontStyle::Weight::kBold_Weight
// : SkFontStyle::Weight::kNormal_Weight,
// SkFontStyle::Width::kNormal_Width,
// std::get<2>(para) ? SkFontStyle::Slant::kItalic_Slant
// : SkFontStyle::Slant::kUpright_Slant);
// style.setFontStyle(fontStyle);
// style.setFontSize(std::get<3>(para) * i);
// SkPaint background;
// background.setColor(std::get<4>(para));
// style.setBackgroundColor(background);
// SkPaint foreground;
// foreground.setColor(std::get<5>(para));
// foreground.setAntiAlias(true);
// style.setForegroundColor(foreground);
// if (std::get<6>(para)) {
// style.addShadow(TextShadow(SK_ColorBLACK, SkPoint::Make(5, 5), 2));
// }
//
// auto decoration = (i % 4);
// if (decoration == 3) {
// decoration = 4;
// }
//
// bool test = (TextDecoration)decoration != TextDecoration::kNoDecoration;
// std::string deco = std::to_string((int)decoration);
// if (test) {
// style.setDecoration((TextDecoration)decoration);
// style.setDecorationStyle(std::get<7>(para));
// style.setDecorationColor(std::get<5>(para));
// }
// builder.pushStyle(style);
// std::string name = " " + std::get<0>(para) + " " +
// (std::get<1>(para) ? ", bold" : "") +
// (std::get<2>(para) ? ", italic" : "") + " " +
// std::to_string(std::get<3>(para) * i) +
// (std::get<4>(para) != SK_ColorRED ? ", background" : "") +
// (std::get<5>(para) != SK_ColorWHITE ? ", foreground" : "") +
// (std::get<6>(para) ? ", shadow" : "") +
// (test ? ", decorations " + deco : "") + ";";
// builder.addText(name.c_str(), name.length());
// builder.pop();
// }
//
// auto paragraph = builder.Build();
// paragraph->layout(w - margin * 2);
// paragraph->paint(canvas, mRECT.L + margin, mRECT.T + margin);
//
// canvas->translate(0, paragraph->getHeight());
// }
// }
  
    void DoDrawContent(SkCanvas* canvas)
    {
      const std::u16string text = u"The quick brown fox \U0001f98a ate a zesty ham burger fons \U0001f354."
        "The \U0001f469\u200D\U0001f469\u200D\U0001f467\u200D\U0001f467 laughed.";
      canvas->drawColor(SK_ColorWHITE);

      auto fontCollection = sk_make_sp<FontCollection>();
      fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
      
      ParagraphStyle paragraph_style;
      paragraph_style.setMaxLines(7);
      paragraph_style.setEllipsis(u"\u2026");
      ParagraphBuilderImpl builder(paragraph_style, fontCollection);
      TextStyle text_style;
      text_style.setColor(SK_ColorBLACK);
      text_style.setFontFamilies({ SkString("Roboto"), SkString("Noto Color Emoji") });
      text_style.setFontSize(60);
      builder.pushStyle(text_style);
      builder.addText(text);
      auto paragraph = builder.Build();
      assert(paragraph);
      paragraph->layout(mRECT.W());
      paragraph->paint(canvas, mRECT.L, mRECT.T);
    }
};

END_IGRAPHICS_NAMESPACE
END_IPLUG_NAMESPACE

```

---

<div class="post-metadata">

**Author:** ![olilarkin](https://yyz2.discourse-cdn.com/free1/user_avatar/iplug2.discourse.group/olilarkin/32/2_2.png) [@olilarkin](https://iplug2.discourse.group/u/olilarkin)\
**Post date:** [14 January 2022 20:37 UTC](https://iplug2.discourse.group/t/formatted-paragraph-text/544/3 "2022-01-14T20:37:47Z")

</div>

Latest prebuilt libraries now include everything necessary to use SKParagraph as above

---

<div class="post-metadata">

**Author:** ![snfk](https://yyz2.discourse-cdn.com/free1/user_avatar/iplug2.discourse.group/snfk/32/140_2.png) [@snfk](https://iplug2.discourse.group/u/snfk)\
**Post date:** [17 January 2022 14:13 UTC](https://iplug2.discourse.group/t/formatted-paragraph-text/544/4 "2022-01-17T14:13:27Z")

</div>

Instead of creating a new thread again, I’ll just ask this here because it’s quite similar.

Is there a control to enter paragraph text? I’m working on a preset saving window that should provide name, description, (etc) inputs. Is there anything in iPlug to create a multi-line textbox, or would it be better for me to just create a new control from scratch for that purpose?  
Thanks!

---

<div class="post-metadata">

**Author:** ![stw](https://avatars.discourse-cdn.com/v4/letter/s/8e8cbc/32.png) [@stw](https://iplug2.discourse.group/u/stw)\
**Post date:** [17 January 2022 14:33 UTC](https://iplug2.discourse.group/t/formatted-paragraph-text/544/5 "2022-01-17T14:33:05Z")

</div>

AFAIK you have to do it on your own (at least i did)…  
@Youlean did also one and provided a gist which maybe fit your needs, or at least gives some ideas:

> <https://gist.github.com/Youlean/f3885098d95826e83d04bfb19c738265>

---

<div class="post-metadata">

**Author:** ![snfk](https://yyz2.discourse-cdn.com/free1/user_avatar/iplug2.discourse.group/snfk/32/140_2.png) [@snfk](https://iplug2.discourse.group/u/snfk)\
**Post date:** [17 January 2022 14:34 UTC](https://iplug2.discourse.group/t/formatted-paragraph-text/544/6 "2022-01-17T14:34:31Z")

</div>

Looks promising, thanks!
