#304 Regions 4.x-dev

Sun, 11 Apr 2021 12:04:29 +0300

author
cemkalyoncu
date
Sun, 11 Apr 2021 12:04:29 +0300
branch
4.x-dev
changeset 1648
528446910569
parent 1647
98c554aac82d
child 1649
f2b7cf3a11bc

#304 Regions
* CGI Marking DrawBounds

Source/Gorgon/CGI/Line.h file | annotate | diff | comparison | revisions
Source/Gorgon/CGI/Marking.h file | annotate | diff | comparison | revisions
Source/Gorgon/Graphics/AdvancedPrinter.h file | annotate | diff | comparison | revisions
Testing/Source/Manual/AdvancedText.cpp file | annotate | diff | comparison | revisions
Testing/Source/Manual/CGI.cpp file | annotate | diff | comparison | revisions
--- a/Source/Gorgon/CGI/Line.h	Sat Apr 10 13:12:04 2021 +0300
+++ b/Source/Gorgon/CGI/Line.h	Sun Apr 11 12:04:29 2021 +0300
@@ -38,6 +38,10 @@
                 s++;
             } while(s < p.GetSize() && l.Start == l.End);
             
+            //nothing to draw here
+            if(l.Start == l.End)
+                return {};
+            
 			auto off = (Geometry::Pointf(l.End) - Geometry::Pointf(l.Start)).Perpendicular().Normalize() * w;
 
 			//if closed the first two points will be added last
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Source/Gorgon/CGI/Marking.h	Sun Apr 11 12:04:29 2021 +0300
@@ -0,0 +1,48 @@
+#pragma once
+
+#include "Line.h"
+
+namespace Gorgon { namespace CGI {
+    
+    template<int S_ = GORGON_DEFAULT_SUBDIVISIONS, class I_, class T_= float, class F1_ = SolidFill<>>
+    void DrawBounds(I_ &target, const Geometry::basic_Bounds<T_> &bnds, 
+                    float strokewidth = 1, 
+                    F1_ stroke = SolidFill<>{Graphics::Color::Black}
+    ) {
+        Geometry::Pointf tl = bnds.TopLeft(), br = bnds.BottomRight();
+        tl.X -= strokewidth/2;
+        tl.Y -= strokewidth/2;
+        br.X += strokewidth/2;
+        br.Y += strokewidth/2;
+        
+        DrawLines(target, {tl, {br.X, tl.Y}, br, {tl.X, br.Y}, tl}, strokewidth, stroke);
+    }
+    
+    template<int S_ = GORGON_DEFAULT_SUBDIVISIONS, class I_, class T_= float, class F1_ = SolidFill<>, class F2_ = SolidFill<>>
+    void DrawBounds(I_ &target, const Geometry::basic_Bounds<T_> &bnds, 
+                    F2_ fill,
+                    float strokewidth, 
+                    F1_ stroke = SolidFill<>{Graphics::Color::Black}
+    ) {
+        Geometry::Pointf tl = bnds.TopLeft(), br = bnds.BottomRight();
+        
+        Polyfill(target, {tl, {br.X, tl.Y}, br, {tl.X, br.Y}, tl}, fill);
+        
+        tl.X -= strokewidth/2;
+        tl.Y -= strokewidth/2;
+        br.X += strokewidth/2;
+        br.Y += strokewidth/2;
+        
+        DrawLines(target, {tl, {br.X, tl.Y}, br, {tl.X, br.Y}, tl}, strokewidth, stroke);
+    }
+    
+    template<int S_ = GORGON_DEFAULT_SUBDIVISIONS, class I_, class T_= float, class F2_ = SolidFill<>>
+    void DrawBounds(I_ &target, const Geometry::basic_Bounds<T_> &bnds, 
+                    F2_ fill
+    ) {
+        Geometry::Pointf tl = bnds.TopLeft(), br = bnds.BottomRight();
+        
+        Polyfill(target, {tl, {br.X, tl.Y}, br, {tl.X, br.Y}, tl}, fill);
+    }
+    
+} }
--- a/Source/Gorgon/Graphics/AdvancedPrinter.h	Sat Apr 10 13:12:04 2021 +0300
+++ b/Source/Gorgon/Graphics/AdvancedPrinter.h	Sun Apr 11 12:04:29 2021 +0300
@@ -786,8 +786,14 @@
         
         class Region {
         public:
-            Byte id;
-            Geometry::Bounds bounds;
+            Region() = default;
+            
+            Region(Byte id, const Geometry::Bounds &bounds) : 
+                ID(id), Bounds(bounds) 
+            { }
+            
+            Byte ID;
+            Geometry::Bounds Bounds;
         };
         
         
@@ -855,6 +861,17 @@
             
             Glyph prev = 0;
             int ind = 0;
+            
+            struct openregioninfo : public Region {
+                openregioninfo() = default;
+                
+                openregioninfo(Byte id, const Geometry::Bounds &bounds, int startat) :
+                    Region(id, bounds), startat(startat) 
+                { }
+                    
+                int    startat =  0;
+                int    doneat  = -1;
+            };
 
             
             std::vector<Glyph> breaking = breakingchars;
@@ -883,6 +900,7 @@
             int height = 0; //current font height, line gap is used
             int baseline = 0; //current font baseline
             int em = 0; //current font size em size
+            float baselineoffsetatlastspace = 0;
             
             //for sub/superscript
             float baselineoffset = 0;
@@ -893,6 +911,7 @@
             
             //for placing letters
             Geometry::Point cur = location;
+            int  starty = cur.Y;
             int  lastbreak = 0;
             bool beginparag = true;
             bool newline    = true;
@@ -908,10 +927,45 @@
             
             changeprinter(printer);
             
+            //bool is for regions that end at the middle of a line
+            std::vector<openregioninfo> openregions; 
+            std::vector<Region> regions;
             
             //used in the parsers too
             auto end = text.end();
             
+            std::vector<glyphmark> acc;
+            int maxh = 0; //maximum height of a line
+            int maxb = 0; //maximum baseline of a line
+            
+            auto switchtoscript = [&] {
+                if(
+                    fontid == NamedFont::Info || fontid == NamedFont::Small ||  fontid == NamedFont::Script || 
+                    fontid == NamedFont::BoldScript || fontid == NamedFont::SmallScript) 
+                {
+                    changeprinter(findfont(NamedFont::SmallScript));
+                }
+                else if(
+                    fontid == NamedFont::Bold || fontid == NamedFont::BoldItalic || fontid == NamedFont::H3 || 
+                    fontid == NamedFont::H4
+                ) {
+                    changeprinter(findfont(NamedFont::BoldScript));
+                }
+                else if(
+                    fontid == NamedFont::Larger
+                ) {
+                    changeprinter(&fonts.at(0));
+                }
+                else if(
+                    fontid == NamedFont::H1 || fontid == NamedFont::H2
+                ) {
+                    changeprinter(findfont(NamedFont::Bold));
+                }
+                else {
+                    changeprinter(findfont(NamedFont::Script));
+                }
+            };
+            
             //parse multi character command
             auto CSI = [&](auto &it, auto end) {
                 MOVEIT();
@@ -963,6 +1017,13 @@
                     xoffset = readvalrel(it, end, p, true);
                     yoffset = readvalrel(it, end, p, true);
                     break;
+                case 0x15:
+                    fontid = readindex(it, end, p);
+                    if(baselineoffset != 0)
+                        switchtoscript();
+                    else
+                        changeprinter(findfont(fontid));
+                    break;
                 case 0x17: { //set tab width
                     auto val = readvalrelper(it, end, p, false);
                     tabwidth = setval<int>{val.set, val(em, wrapwidth, printer->GetTabWidth())};
@@ -995,6 +1056,22 @@
                     }), breaking.end());
                     break;
                 }
+                case 0x30:
+                    openregions.push_back({readindex(it, end, p), {cur, 0, 0}, (int)acc.size()});
+                    break;
+                case 0x31: {
+                    auto ind = readindex(it, end, p);
+                    
+                    for(int i=openregions.size()-1; i>=0; i--) {
+                        if(openregions[i].ID == ind && openregions[i].doneat == -1) {
+                            openregions[i].Bounds.Right = cur.X;
+                            openregions[i].Bounds.Bottom = cur.Y + height;
+                            openregions[i].doneat = (int)acc.size();
+                            break;
+                        }
+                    }
+                    break;
+                }
                 case 0x40: //horizontal spacing
                     cur.X += readvalrelper(it, end, p, false)(em, wrapwidth, 0);
                     prev = 0; //no kerning after a spacing like this
@@ -1030,34 +1107,11 @@
                     xoffset.set             = false;
                     yoffset.set             = false;
                     changeprinter(&fonts.at(0));
+                    fontid = 0;
                     baselineoffset = 0.0f;
                 case 0x5:
                 case 0x6:
-                    if(
-                        fontid == NamedFont::Info || fontid == NamedFont::Small ||  fontid == NamedFont::Script || 
-                        fontid == NamedFont::BoldScript || fontid == NamedFont::SmallScript) 
-                    {
-                        changeprinter(findfont(NamedFont::SmallScript));
-                    }
-                    else if(
-                        fontid == NamedFont::Bold || fontid == NamedFont::BoldItalic || fontid == NamedFont::H3 || 
-                        fontid == NamedFont::H4
-                    ) {
-                        changeprinter(findfont(NamedFont::BoldScript));
-                    }
-                    else if(
-                        fontid == NamedFont::Larger
-                    ) {
-                        changeprinter(&fonts.at(0));
-                    }
-                    else if(
-                        fontid == NamedFont::H1 || fontid == NamedFont::H2
-                    ) {
-                        changeprinter(findfont(NamedFont::Bold));
-                    }
-                    else {
-                        changeprinter(findfont(NamedFont::Script));
-                    }
+                    switchtoscript();
                     break;
                 case 0x7:
                     changeprinter(findfont(fontid));
@@ -1118,43 +1172,48 @@
                 switch(g) {
                 case 0x0e:
                     changeprinter(findfont(NamedFont::Bold));
+                    fontid = (int)NamedFont::Bold;
                     return true;
                 case 0x0f:
                     changeprinter(findfont(NamedFont::Regular));
+                    fontid = (int)NamedFont::Regular;
                     return true;
                 case 0x91:
                     changeprinter(findfont(NamedFont::Italic));
+                    fontid = (int)NamedFont::Italic;
                     return true;
                 case 0x92:
                     changeprinter(findfont(NamedFont::Small));
+                    fontid = (int)NamedFont::Small;
                     return true;
                 case 0x11:
                     changeprinter(findfont(NamedFont::H1));
+                    fontid = (int)NamedFont::H1;
                     return true;
                 case 0x12:
                     changeprinter(findfont(NamedFont::H2));
+                    fontid = (int)NamedFont::H2;
                     return true;
                 case 0x13:
                     changeprinter(findfont(NamedFont::H3));
+                    fontid = (int)NamedFont::H3;
                     return true;
                 case 0x14:
                     changeprinter(findfont(NamedFont::H4));
+                    fontid = (int)NamedFont::H4;
                     return true;
                 }
                 
                 return false;
             };
             
-            std::vector<glyphmark> acc;
-            int maxh = 0; //maximum height of a line
-            int maxb = 0; //maximum baseline of a line
-            
             auto doline = [&](Glyph nl) {
                 
-                auto end = nl == 0 ? lastbreak : acc.size();
+                int end = nl == 0 ? lastbreak : (int)acc.size();
                 
                 int totalw = acc[end-1].location.X + acc[end-1].width - location.X;
                 int xoff = 0;
+                int lineend = 0;
                 
                 if(nl == 0 && justify(printer->GetJustify()) && wrapwidth) {
                     //count spaces and letters
@@ -1253,14 +1312,17 @@
                     switch(align(printer->GetDefaultAlign())) {
                     case TextAlignment::Right:
                         xoff = wrapwidth - totalw;
+                        lineend = wrapwidth + location.X;
                         
                         break;
                     case TextAlignment::Center:
                         xoff = (wrapwidth - totalw) / 2;
+                        lineend = wrapwidth - xoff + location.X;
                         
                         break;
                     default:
-                        //nothing
+                        lineend = totalw + location.X;
+                        
                         break;
                     }
                 }
@@ -1311,27 +1373,84 @@
                 ind = acc.size();
                 newline = ind == 0;
 
-
                 cur.Y += lineh;
                 
+                //finalize regions before paragraph spacing
+                int rstart = location.X + indent(em, 0) + hangingindent(em, 0) * beginparag;
+                for(auto &r : openregions) {
+                    
+                    if(r.startat >= end) {
+                        r.startat -= end;
+                        
+                        ASSERT(r.startat < acc.size(), "FIX ME");
+                        
+                        r.Bounds.Move(acc[r.startat].location);
+                        continue;
+                    }
+                    else {
+                        r.startat = -1;
+                    }
+                    
+                    r.Bounds.Bottom = cur.Y;
+                    r.Bounds.Top = starty;
+                    
+                    if(r.doneat != -1 && r.doneat <= end) {
+                        regions.push_back(r);
+                        r.doneat = -2;
+                    }
+                    else {
+                        r.Bounds.Right = lineend;
+                        
+                        regions.push_back(r);
+                        
+                        r.Bounds.Left = rstart;
+                        r.Bounds.Top  = cur.Y;
+                        
+                        if(r.doneat != -1) {
+                            r.doneat -= end;
+                            r.Bounds.Right = acc[r.doneat].location.X;
+                        }
+                    }
+                }
+                
+                openregions.erase(
+                    std::remove_if(
+                        openregions.begin(), openregions.end(), 
+                        [](auto r) { return r.doneat == -2; }
+                    ), openregions.end()
+                );
+                
+                //if requested do paragraph
                 if(beginparag)
                     cur.Y += paragraphspacing(maxh, printer->GetParagraphSpacing());
                 
+                //reset
                 maxh = 0;
                 maxb = 0;
+                lastbreak = 0;
                 extralineoffset = 0;
                 extralineheight = 0;
-                lastbreak = 0;
+                starty = cur.Y;
+                baselineoffsetatlastspace = 0;
+                
+                auto backup = printer;
+                changeprinter(findfont(fontid));
+                
+                //if still doing scripts, readjust exta line height and offset
                 if(baselineoffset < 0) {
                     auto height = renderer->GetBaseLine() * -baselineoffset;
                     if(height > extralineheight)
                         extralineheight = height;
+                    
+                    changeprinter(backup);
                 }
                 else if(baselineoffset > 0) {
                     auto offset = renderer->GetBaseLine() * baselineoffset;
                     
                     if(offset > extralineoffset)
                         extralineoffset = offset;
+                    
+                    changeprinter(backup);
                 }
             }; //do line
             
@@ -1369,6 +1488,7 @@
                 // **** Breaking character check
                 if(internal::isbreaking(g)) {
                     lastbreak = (int)acc.size();
+                    baselineoffsetatlastspace = baselineoffset;
                 }
                 
                 // **** Determine spacing
@@ -1470,7 +1590,15 @@
                             break;
                     }
                     
+                    auto blosave = baselineoffset;
+                    baselineoffset = baselineoffsetatlastspace;
+                    
                     doline(0);
+                    
+                    baselineoffset = blosave;
+                    if(baselineoffset == 0 && blosave != 0) {
+                        changeprinter(findfont(fontid));
+                    }
                 }
                 
                 auto br = std::lower_bound(breaking.begin(), breaking.end(), g);
@@ -1483,7 +1611,7 @@
             if(!acc.empty())
                 doline(-1);
             
-            return {};
+            return regions;
         }
         
         std::vector<Region> AdvancedPrint(
--- a/Testing/Source/Manual/AdvancedText.cpp	Sat Apr 10 13:12:04 2021 +0300
+++ b/Testing/Source/Manual/AdvancedText.cpp	Sun Apr 11 12:04:29 2021 +0300
@@ -8,6 +8,7 @@
 #include <Gorgon/ImageProcessing/Filters.h>
 #include <Gorgon/UI/Window.h>
 #include <Gorgon/Widgets/Generator.h>
+#include <Gorgon/CGI/Marking.h>
 
 
 
@@ -29,17 +30,25 @@
     Graphics::AdvancedTextBuilder builder;
     builder.UseHeader(Gorgon::Graphics::HeaderLevel::H1)
            .WordWrap(false)
+           .StartRegion(4)
            .Append("Hello world. ")
+           .EndRegion(4)
            .UseDefaultFont()
-           .Append("Not header\n")
+           .StartRegion(5)
+           .Append("Not header")
+           .EndRegion(5)
+           .Append("\n")
            .WordWrap(true)
            .SetHangingIndent(10, 0)
-           .Append("This is ")
+           .Append("This ")
+           .StartRegion(0)
+           .Append("is")
            .UseBoldFont()
-           .SetLetterSpacing(5, 0)
+           .SetLetterSpacing(3, 0)
            .HorizontalSpace(-5)
            .VerticalSpace(15)
-           .Append("a bold ")
+           .Append(" a bold ")
+           .EndRegion(0)
            .UseDefaultFont()
            .DefaultLetterSpacing()
            .SetColor(2, 171)
@@ -48,18 +57,26 @@
            .Append("e = mc")
            .UseSubscript()
            .SetColor(Gorgon::Graphics::Color::DarkAqua)
+           .StartRegion(6)
            .Append("Hello there")
+           .EndRegion(6)
            .UseDefaultColor()
            .ScriptOff()
+           .StartRegion(1)
            .Append("And")
-           .UseSubscript()
+           .EndRegion(1)
+           .UseSuperscript()
+           .StartRegion(3)
            .Append("back")
-           .SetParagraphSpacing(0, 0)
+           .EndRegion(3)
+           .SetParagraphSpacing(0, 50)
            .ScriptOff()
            .LineBreak()
            .SetWrapWidth(200)
            .SetTabWidth(0, 0, 2500)
+           .StartRegion(2)
            .Append("Not a\tnew\tparagraph. Just a line break\n")
+           .EndRegion(2)
            .UseItalicFont()
            .Append("New\tparagraph ")
            .Append("D")
@@ -95,8 +112,34 @@
     printer.RegisterColor(2, Gorgon::Graphics::Color::Red, Gorgon::Graphics::Color::LightYellow);
     
     l.Draw(reg.Background.Regular);
-    printer.AdvancedPrint(l, builder, {25, 25}, 150);
+
+    Graphics::Bitmap markings(500, 500, Gorgon::Graphics::ColorMode::RGBA);
+    markings.Clear();
+    markings.Prepare();
+    markings.Draw(l, 0, 0);
+    
+    auto regions = printer.AdvancedPrint(l, builder, {25, 25}, 150);
     
+    std::vector<Graphics::RGBA> regioncolor = {
+        Graphics::Color::Red,
+        Graphics::Color::Brown,
+        Graphics::Color::DarkGreen,
+        Graphics::Color::Charcoal,
+        Graphics::Color::Navy,
+        Graphics::Color::Purple,
+        Graphics::Color::Orange,
+    };
+    
+    for(auto r : regions) {
+        Gorgon::CGI::DrawBounds(
+            markings, 
+            r.Bounds,
+            0.5, Gorgon::CGI::SolidFill<>(regioncolor[r.ID])
+        );
+    }
+    
+    markings.Prepare();
+
     while(true) {
         Gorgon::NextFrame();
     }
--- a/Testing/Source/Manual/CGI.cpp	Sat Apr 10 13:12:04 2021 +0300
+++ b/Testing/Source/Manual/CGI.cpp	Sun Apr 11 12:04:29 2021 +0300
@@ -50,7 +50,8 @@
         Circle(bmp2, b.P2*zoom, 3, SolidFill<>(Blue));
         Circle(bmp2, b.P3*zoom, 3, SolidFill<>(Green));
         
-        DrawLines(bmp2, {b.P0*zoom, b.P1*zoom, b.P2*zoom, b.P3*zoom}, 0.75, SolidFill<>(LightBlue));
+        DrawLines(bmp2, {b.P0*zoom, b.P1*zoom}, 0.75, SolidFill<>(LightBlue));
+        DrawLines(bmp2, {b.P2*zoom, b.P3*zoom}, 0.75, SolidFill<>(LightBlue));
     };
     
     

mercurial