Browse Source

Support auto line break style in TextFeld

Kolja Strohm 1 year ago
parent
commit
1c5afde7ac
2 changed files with 138 additions and 24 deletions
  1. 108 10
      TextFeld.cpp
  2. 30 14
      TextFeld.h

+ 108 - 10
TextFeld.cpp

@@ -246,7 +246,8 @@ TextFeld::TextFeld()
       showChar(0),
       cpos(0),
       tickVal(0),
-      mausKlick(0)
+      mausKlick(0),
+      autoLineBreakSpacing(0)
 {
     charEvent = 0;
     horizontalScrollBar = new HScrollBar();
@@ -259,6 +260,7 @@ TextFeld::TextFeld()
 TextFeld::~TextFeld()
 {
     tm->release();
+    if (autoLineBreakSpacing) autoLineBreakSpacing->release();
 }
 
 void TextFeld::doMausEreignis(MausEreignis& me, bool userRet) // Maus Ereignis
@@ -427,6 +429,14 @@ int TextFeld::getTextHeight() const
     int th = 0;
     int len = tm->text->getLength();
     const char* text = tm->text->getText();
+    Text txtWithLineBreaks;
+    if (hatStyle(Style::AutoLineBreak))
+    {
+        txtWithLineBreaks = addLineBreaksToText(tm->text->getText(),
+            autoLineBreakSpacing ? autoLineBreakSpacing->getText() : "");
+        text = txtWithLineBreaks;
+        len = txtWithLineBreaks.getLength();
+    }
     int max = 0;
     int abstand = 0;
     for (int i = 0; i < len; i++)
@@ -459,6 +469,14 @@ int TextFeld::getTextWidth() const
     int maxBr = 0;
     int len = tm->text->getLength();
     const char* text = tm->text->getText();
+    Text txtWithLineBreaks;
+    if (hatStyle(Style::AutoLineBreak))
+    {
+        txtWithLineBreaks = addLineBreaksToText(tm->text->getText(),
+            autoLineBreakSpacing ? autoLineBreakSpacing->getText() : "");
+        text = txtWithLineBreaks;
+        len = txtWithLineBreaks.getLength();
+    }
     int lineBr = 0;
     char buff[] = {0, 0};
     for (int i = 0; i < len; i++)
@@ -623,13 +641,16 @@ void TextFeld::setFormattedText(const char* txt)
 void TextFeld::addLineBreaks(const char* spacing)
 {
     if (!tm->text) return;
+    setFormattedText(addLineBreaksToText(tm->text->getText(), spacing));
+}
+
+Text TextFeld::addLineBreaksToText(const char* txt, const char* spacing) const
+{
     int lastPos = -1;
     int lastPos2 = -1;
     int x = 0;
-    const char* txt = tm->text->getText();
     Text result = "";
-    int len = tm->text->getLength();
-    lockZeichnung();
+    int len = (int)strlen(txt);
     int maxBr = getBreite();
     if (hatStyle(Style::VScroll) && vertikalScrollBar) maxBr -= 15;
     tm->resetIteration();
@@ -751,8 +772,14 @@ void TextFeld::addLineBreaks(const char* spacing)
         }
         tm->nextStyle();
     }
-    unlockZeichnung();
-    setFormattedText(result);
+    return result;
+}
+
+
+void TextFeld::setAutoLineBreakSpacing(const char* spacing)
+{
+    if (!autoLineBreakSpacing) autoLineBreakSpacing = new Text();
+    autoLineBreakSpacing->setText(spacing);
 }
 
 // Setzt den Style eines Textabschnittes
@@ -1028,6 +1055,14 @@ void TextFeld::setVScrollZuZeile(int zeile) // scrollt zur Zeile
         int y = 0;
         int lnum = 0;
         const char* text = tm->text->getText();
+        Text txtWithLineBreaks;
+        if (hatStyle(Style::AutoLineBreak))
+        {
+            txtWithLineBreaks = addLineBreaksToText(tm->text->getText(),
+                autoLineBreakSpacing ? autoLineBreakSpacing->getText() : "");
+            text = txtWithLineBreaks;
+            len = txtWithLineBreaks.getLength();
+        }
         int max = 0;
         for (int i = 0; i < len && lnum < zeile; i++)
         {
@@ -1073,6 +1108,15 @@ void TextFeld::updateVScroll(int pos) // scrollt nach unten
             tm->resetIteration();
             int len = tm->text->getLength();
             const char* text = tm->text->getText();
+            Text txtWithLineBreaks;
+            if (hatStyle(Style::AutoLineBreak))
+            {
+                txtWithLineBreaks = addLineBreaksToText(tm->text->getText(),
+                    autoLineBreakSpacing ? autoLineBreakSpacing->getText()
+                                         : "");
+                text = txtWithLineBreaks;
+                len = txtWithLineBreaks.getLength();
+            }
             int max = 0;
             int lastMax = 0;
             for (int i = 0; i < len; i++)
@@ -1450,12 +1494,26 @@ void TextFeld::render(Bild& zRObj) // zeichenet nach zRObj
     int y = yyy;
     int len = tm->text->getLength();
     const char* text = tm->text->getText();
+    Text txtWithLineBreaks;
+    if (hatStyle(Style::AutoLineBreak))
+    {
+        txtWithLineBreaks = addLineBreaksToText(tm->text->getText(),
+            autoLineBreakSpacing ? autoLineBreakSpacing->getText() : "");
+        text = txtWithLineBreaks;
+        len = txtWithLineBreaks.getLength();
+    }
     lockZeichnung();
     tm->resetIteration();
     TextStyle& style = tm->currentStyle();
     int maxLH = 0;
+    int corrector = 0;
+    int realLen = tm->text->getLength();
     for (int i = 0; i <= len; i++)
     {
+        if (i >= realLen || text[i] != tm->text->getText()[i])
+        {
+            corrector++;
+        }
         int oldX = x;
         if (i < len && tm->zCurrentRenderer())
             tm->zCurrentRenderer()->renderChar(x,
@@ -1466,7 +1524,7 @@ void TextFeld::render(Bild& zRObj) // zeichenet nach zRObj
                 style.underlined,
                 style.selected,
                 style.selectedBackcroundColor);
-        if (i == cpos && tickVal <= 0.5 && hatStyle(Style::Fokus)
+        if (i - corrector == cpos && tickVal <= 0.5 && hatStyle(Style::Fokus)
             && hatStyle(Style::Editierbar) && tm->zCurrentRenderer())
             zRObj.drawLinieV(
                 oldX, y, tm->zCurrentRenderer()->getZeilenHeight(), 0xFFFF5555);
@@ -1629,14 +1687,29 @@ int TextFeld::getTextIndexAt(int mx, int my) const
     int y = yyy;
     int len = tm->text->getLength();
     const char* text = tm->text->getText();
+    Text txtWithLineBreaks;
+    if (hatStyle(Style::AutoLineBreak))
+    {
+        txtWithLineBreaks = addLineBreaksToText(tm->text->getText(),
+            autoLineBreakSpacing ? autoLineBreakSpacing->getText() : "");
+        text = txtWithLineBreaks;
+        len = txtWithLineBreaks.getLength();
+    }
     tm->resetIteration();
+    int corrector = 0;
     int maxLH = 0;
+    int realLen = tm->text->getLength();
     for (int i = 0; i < len; i++)
     {
+        if (i >= realLen || text[i] != tm->text->getText()[i])
+        {
+            corrector++;
+        }
         char buff[2] = {istSchreibbar(showChar) ? (char)showChar : text[i], 0};
         int tmpx = tm->zCurrentRenderer()->getTextBreite(buff);
         int tmpy = tm->zCurrentRenderer()->getZeilenHeight();
-        if (mx >= x && mx < x + tmpx && my >= y && my < y + tmpy) return i;
+        if (mx >= x && mx < x + tmpx && my >= y && my < y + tmpy)
+            return i - corrector;
         if (mx < x + tmpx && my < y + tmpy) return -1;
         x += tmpx;
         tmpy += tm->zCurrentRenderer()->getZeilenAbstand();
@@ -1675,17 +1748,31 @@ int TextFeld::getCurserPosAt(int mx, int my) const
     int y = yyy;
     int len = tm->text->getLength();
     const char* text = tm->text->getText();
+    Text txtWithLineBreaks;
+    if (hatStyle(Style::AutoLineBreak))
+    {
+        txtWithLineBreaks = addLineBreaksToText(tm->text->getText(),
+            autoLineBreakSpacing ? autoLineBreakSpacing->getText() : "");
+        text = txtWithLineBreaks;
+        len = txtWithLineBreaks.getLength();
+    }
     tm->resetIteration();
     int maxLH = 0;
+    int realLen = tm->text->getLength();
+    int corrector = 0;
     for (int i = 0; i < len; i++)
     {
+        if (i >= realLen || text[i] != tm->text->getText()[i])
+        {
+            corrector++;
+        }
         int tmpx = tm->zCurrentRenderer()->getCharWidth(
             istSchreibbar(showChar) ? showChar : text[i]);
         int tmpy = tm->zCurrentRenderer()->getZeilenHeight()
                  + tm->zCurrentRenderer()->getZeilenAbstand();
         if (mx < x + tmpx / 2
             && my < y + tmpy - tm->zCurrentRenderer()->getZeilenAbstand() / 2)
-            return i;
+            return i - corrector;
         x += tmpx + tm->zCurrentRenderer()->getZeichenAbstand();
         maxLH = tmpy > maxLH ? tmpy : maxLH;
         if (text[i] == '\n')
@@ -1693,7 +1780,7 @@ int TextFeld::getCurserPosAt(int mx, int my) const
             if (my >= y - tm->zCurrentRenderer()->getZeilenAbstand() / 2
                 && my < y + maxLH
                             - tm->zCurrentRenderer()->getZeilenAbstand() / 2)
-                return i;
+                return i - corrector;
             x = xxx;
             y += maxLH;
         }
@@ -1709,6 +1796,13 @@ TextFeld::TextStyle TextFeld::getTextStyle(int index) const
     return tm->getTextStyle(index);
 }
 
+// gibt die Zeichenkette zurück, die bei Verwendung des Styles
+// AutoLineBreak nach jedem Zeilenumbruch eingefügt wird
+Text TextFeld::getAutoLineBreakSpacing() const
+{
+    return autoLineBreakSpacing ? *autoLineBreakSpacing : "";
+}
+
 Zeichnung* TextFeld::dublizieren() const // Erzeugt eine Kopie des Zeichnungs
 {
     TextFeld* obj = new TextFeld();
@@ -1751,6 +1845,10 @@ Zeichnung* TextFeld::dublizieren() const // Erzeugt eine Kopie des Zeichnungs
         obj->setHorizontalScrollFarbe(
             horizontalScrollBar->getFarbe(), horizontalScrollBar->getBgFarbe());
     }
+    if (autoLineBreakSpacing)
+    {
+        obj->setAutoLineBreakSpacing(*autoLineBreakSpacing);
+    }
     obj->setSchowChar(showChar);
     return obj;
 }

+ 30 - 14
TextFeld.h

@@ -85,20 +85,22 @@ namespace Framework
         class Style : public ZeichnungHintergrund::Style
         {
         public:
-            static const __int64 Mehrzeilig
-                = 0x001000; //! Wenn dieser Flag nicht gesetzt wird, werden alle
-                            //! Zeilenumbrüche automatisch aus dem Text entfernt
-            static const __int64 HCenter
-                = 0x002000; //! Wenn dieser Flag gesetzt wird, wird der Text
-                            //! genau in der horizontaen Mitte des Feldes
-                            //! plaziert
-            static const __int64 VCenter
-                = 0x004000; //! Wenn dieser Flag gesetzt wird, wird der Text
-                            //! genau in der vertikalen Mitte des Feldes
-                            //! plaziert
-            static const __int64 Editierbar
-                = 0x2000000; //! Wenn dieser Flag gesetzt wird, kann der Text
-                             //! durch den Nutzer bearbeitet werden
+            // Wenn dieser Flag nicht gesetzt wird, werden alle Zeilenumbrüche
+            // automatisch aus dem Text entfernt
+            static const __int64 Mehrzeilig = 0x001000;
+            // Wenn dieser Flag gesetzt wird, wird der Text genau in der
+            // horizontaen Mitte des Feldes plaziert
+            static const __int64 HCenter = 0x002000;
+            // Wenn dieser Flag gesetzt wird, wird der Text genau in der
+            // vertikalen Mitte des Feldes plaziert
+            static const __int64 VCenter = 0x004000;
+            // Wenn dieser Flag gesetzt wird, kann der Text durch den Nutzer
+            // bearbeitet werden
+            static const __int64 Editierbar = 0x2000000;
+            // Fügt beim rendern automatisch zeilenumbrüche in den Text ein, so
+            // dass die Breite des Textfeldes nicht überschritten wird. Der Text
+            // wird dabei nicht verändert. Benötigt Style Mehrzeilig
+            static const __int64 AutoLineBreak = 0x4000000;
 
             static const __int64 Center
                 = HCenter | VCenter; //! Vereint die Flags HCenter und VCenter
@@ -120,6 +122,7 @@ namespace Framework
 
     private:
         TextStyleManager* tm;
+        Text* autoLineBreakSpacing;
         unsigned char showChar;
         int cpos;
         double tickVal;
@@ -173,6 +176,16 @@ namespace Framework
         //! textfeldes überschreitet \param spacing ein text, der direkt nach
         //! jedem eingefügten Zeilenumbruch eingefügt wird
         DLLEXPORT void addLineBreaks(const char* spacing = "");
+        //! fügt zeilenumbrüche in den Text txt so ein, dass der text nicht die
+        //! breite des textfeldes überschreitet \param txt der Text in den
+        //! Zeilenumbrüche eingefügt werden sollen \param spacing ein text, der
+        //! direkt nach jedem eingefügten Zeilenumbruch eingefügt wird \return
+        //! der Text mit zeilenumbrüchen
+        DLLEXPORT Text addLineBreaksToText(
+            const char* txt, const char* spacing = "") const;
+        // setzt eine Zeichenfolge die mit dem style AutoLineBreak nach jedem
+        // eingefügten Zeilenumbruch eingefügt wird
+        DLLEXPORT void setAutoLineBreakSpacing(const char* spacing);
         //! Setzt den Style eines Textabschnittes
         //! \param begin die startposition des Abschnittes
         //! \param end die endposition des Abschnittes (nicht enthalten)
@@ -351,6 +364,9 @@ namespace Framework
         //! Gibt den Style eines bestimmten zeichens zurück
         //! \param index Der index des Zeichensf
         DLLEXPORT TextStyle getTextStyle(int index) const;
+        // gibt die Zeichenkette zurück, die bei Verwendung des Styles
+        // AutoLineBreak nach jedem Zeilenumbruch eingefügt wird
+        DLLEXPORT Text getAutoLineBreakSpacing() const;
         //! Erzeugt eine Komplette Kopie des Textfeldes, welches ohne
         //! auswirkungen verändert werden kann
         DLLEXPORT Zeichnung* dublizieren() const override;