#11: mouse selection 4.x-dev

Fri, 07 Feb 2020 14:29:25 +0200

author
cemkalyoncu
date
Fri, 07 Feb 2020 14:29:25 +0200
branch
4.x-dev
changeset 1336
45675ee6f581
parent 1335
d5c2fef48059
child 1337
dc599f9d279d

#11: mouse selection

Source/Gorgon/UI/ComponentStack.h file | annotate | diff | comparison | revisions
Source/Gorgon/UI/ComponentStackWidget.h file | annotate | diff | comparison | revisions
Source/Gorgon/Widgets/Inputbox.cpp file | annotate | diff | comparison | revisions
Source/Gorgon/Widgets/Inputbox.h file | annotate | diff | comparison | revisions
--- a/Source/Gorgon/UI/ComponentStack.h	Thu Feb 06 12:50:18 2020 +0200
+++ b/Source/Gorgon/UI/ComponentStack.h	Fri Feb 07 14:29:25 2020 +0200
@@ -279,7 +279,7 @@
         int IndexOfTag(ComponentTemplate::Tag tag);
 
         /// Returns the boundaries of the component marked with the given tag. This function may cause
-        /// update thus may take time to execute.
+        /// update thus may take time to execute. The bounds are within the parent.
         Geometry::Bounds TagBounds(ComponentTemplate::Tag tag);
 
         /// Returns if the component at the given index has a layer.
@@ -290,7 +290,7 @@
         /// a layer. Layer is probably a graphics layer, you may use RTTI to query layer type.
         Layer &GetLayerOf(int ind);
         
-        /// Returns the boundaries of the component with the given index.
+        /// Returns the boundaries of the component with the given index. The bounds are from the top level.
         Geometry::Bounds BoundsOf(int ind);
 
         /// Returns the index of the component at the given location.
--- a/Source/Gorgon/UI/ComponentStackWidget.h	Thu Feb 06 12:50:18 2020 +0200
+++ b/Source/Gorgon/UI/ComponentStackWidget.h	Fri Feb 07 14:29:25 2020 +0200
@@ -48,11 +48,13 @@
         mutable ComponentStack stack;
 
 		virtual void focused() override {
+            WidgetBase::focused();
 			stack.AddCondition(ComponentCondition::Focused);
 			FocusEvent();
 		}
 
 		virtual void focuslost() override {
+            WidgetBase::focuslost();
 			stack.RemoveCondition(ComponentCondition::Focused);
 			FocusEvent();
 		}
--- a/Source/Gorgon/Widgets/Inputbox.cpp	Thu Feb 06 12:50:18 2020 +0200
+++ b/Source/Gorgon/Widgets/Inputbox.cpp	Fri Feb 07 14:29:25 2020 +0200
@@ -5,6 +5,100 @@
 
 namespace Gorgon { namespace Widgets { namespace internal {
     
+    Inputbox_base::Inputbox_base(const UI::Template& temp) : UI::ComponentStackWidget(temp) {
+            
+        stack.HandleMouse(Input::Mouse::Button::Left);
+            
+        stack.SetMouseUpEvent([this](auto tag, auto location, auto button) { mouseup(tag, location, button); });
+        stack.SetMouseMoveEvent([this](auto tag, auto location) { mousemove(tag, location); });
+        stack.SetMouseDownEvent([this](auto tag, auto location, auto button) { 
+            if(IsFocused())
+                mousedown(tag, location, button); 
+
+            if(allowfocus() && button == Input::Mouse::Button::Left)
+                Focus();
+        });
+        
+        repeater.Register(Input::Keyboard::Keycodes::Left);
+        repeater.Register(Input::Keyboard::Keycodes::Right);
+
+        repeater.SetRepeatOnPress(true);
+
+        repeater.Repeat.Register([this](Input::Key key) {
+            if(Input::Keyboard::CurrentModifier == Input::Keyboard::Modifier::Shift) {
+                if(sellen.byte == allselected) {
+                    sellen.byte  = (int)display.size() - selstart.byte;
+                    sellen.glyph = glyphcount - selstart.glyph;
+                }
+
+                if(key == Input::Keyboard::Keycodes::Left) {
+                    if(sellen.glyph + selstart.glyph > 0) {
+                        sellen.glyph--;
+                        sellen.byte--;
+
+                        //if previous byte is unicode continuation point, go further before
+                        while((sellen.byte + selstart.byte) && (display[sellen.byte + selstart.byte] & 0b11000000) == 0b10000000)
+                            sellen.byte--;
+                    }
+
+                    updateselection();
+                }
+                else if(key == Input::Keyboard::Keycodes::Right) {
+                    if(sellen.glyph + selstart.glyph < glyphcount) {
+                        sellen.glyph++;
+                        sellen.byte += String::UTF8Bytes(display[selstart.byte + sellen.byte]);
+                    }
+
+                    updateselection();
+                }
+            }
+            else if(Input::Keyboard::CurrentModifier == Input::Keyboard::Modifier::None) {
+                if(sellen.byte == allselected) {
+                    sellen = {0, 0};
+
+                    if(key == Input::Keyboard::Keycodes::Left) {
+                        selstart = {0, 0};
+                    }
+                    else if(key == Input::Keyboard::Keycodes::Right) {
+                        selstart = {Length(), (int)display.size()};
+                    }
+
+                    updateselection();
+                }
+                else if(sellen.byte != 0) {
+                    if(key == Input::Keyboard::Keycodes::Left) {
+                        if(sellen.byte < 0) {
+                            selstart += sellen;
+
+                            moveselleft();
+                        }
+                    }
+                    else if(key == Input::Keyboard::Keycodes::Right) {
+                        if(sellen.byte > 0) {
+                            selstart += sellen;
+
+                            moveselright();
+                        }
+                    }
+
+                    sellen = {0, 0};
+
+                    updateselection();
+                }
+                else {
+                    if(key == Input::Keyboard::Keycodes::Left) {
+                        moveselleft();
+                        updateselection();
+                    }
+                    else if(key == Input::Keyboard::Keycodes::Right) {
+                        moveselright();
+                        updateselection();
+                    }
+                }
+            }
+        });
+    }
+
     bool Inputbox_base::KeyEvent(Input::Key key, float state) {
         namespace Keycodes = Input::Keyboard::Keycodes;
 
@@ -182,7 +276,7 @@
         else
             pos += sellen.glyph;
 
-        std::cout<<selstart.glyph<<"\t"<<selstart.byte<<"\t|\t"<<sellen.glyph<<"\t"<<sellen.byte<<"\t|\t"<<glyphcount<<std::endl;
+        //std::cout<<selstart.glyph<<"\t"<<selstart.byte<<"\t|\t"<<sellen.glyph<<"\t"<<sellen.byte<<"\t|\t"<<glyphcount<<std::endl;
 
         Geometry::Point location;
         
@@ -221,4 +315,107 @@
         updateselection();
     }
 
+
+    
+    void Inputbox_base::mousedown(UI::ComponentTemplate::Tag, Geometry::Point location, Input::Mouse::Button button) { 
+        if(button != Input::Mouse::Button::Left) {
+            return;
+        }
+        
+        ismousedown = true;
+        
+        //for font
+        int idx = stack.IndexOfTag(UI::ComponentTemplate::ContentsTag);
+
+        //no contents??!!
+        if(idx == -1)
+            return;
+
+        //contents is not a textholder
+        auto &temp = stack.GetTemplate(idx);
+        if(temp.GetType() != UI::ComponentType::Textholder)
+            return;
+
+        auto &textt = dynamic_cast<const UI::TextholderTemplate&>(temp);
+
+        //no renderer is set or renderer is not in valid state
+        if(!textt.IsReady())
+            return;
+
+        auto &renderer = textt.GetRenderer();
+        
+        auto bounds = stack.BoundsOf(idx);
+        
+        location -= bounds.TopLeft();
+        
+        selstart.glyph = renderer.GetCharacterIndex(display, bounds.Width(), location);
+        selstart.byte  = 0;
+        int g = selstart.glyph;
+        pglyph = g;
+        
+        while(g) {
+            selstart.byte += String::UTF8Bytes(display[selstart.byte]);
+            g--;
+        }
+        
+        sellen = {0,0};
+        
+        updateselection();
+    }
+    
+    void Inputbox_base::mousemove(UI::ComponentTemplate::Tag, Geometry::Point location) { 
+        if(!ismousedown) {
+            return;
+        }
+        
+        //for font
+        int idx = stack.IndexOfTag(UI::ComponentTemplate::ContentsTag);
+
+        //no contents??!!
+        if(idx == -1)
+            return;
+
+        //contents is not a textholder
+        auto &temp = stack.GetTemplate(idx);
+        if(temp.GetType() != UI::ComponentType::Textholder)
+            return;
+
+        auto &textt = dynamic_cast<const UI::TextholderTemplate&>(temp);
+
+        //no renderer is set or renderer is not in valid state
+        if(!textt.IsReady())
+            return;
+
+        auto &renderer = textt.GetRenderer();
+        
+        auto bounds = stack.BoundsOf(idx);
+        
+        location -= bounds.TopLeft();
+        
+        int glyph = renderer.GetCharacterIndex(display, bounds.Width(), location);
+        
+        if(glyph == pglyph)
+            return;
+        
+        pglyph = glyph;
+        
+        int byte  = 0;
+        int g = glyph;
+        while(g) {
+            byte += String::UTF8Bytes(display[byte]);
+            g--;
+        }
+        
+        sellen.glyph = glyph - selstart.glyph;
+        sellen.byte  = byte  - selstart.byte;
+        
+        updateselection();
+    }
+    
+    void Inputbox_base::mouseup(UI::ComponentTemplate::Tag, Geometry::Point, Input::Mouse::Button button) { 
+        if(button == Input::Mouse::Button::Left) {
+            ismousedown = false;
+        }
+    }
+    
 } } }
--- a/Source/Gorgon/Widgets/Inputbox.h	Thu Feb 06 12:50:18 2020 +0200
+++ b/Source/Gorgon/Widgets/Inputbox.h	Fri Feb 07 14:29:25 2020 +0200
@@ -33,7 +33,7 @@
         
         class Inputbox_base : public UI::ComponentStackWidget {
         protected:
-            Inputbox_base(const UI::Template &temp) : UI::ComponentStackWidget(temp) { }
+            Inputbox_base(const UI::Template &temp);
             
             //for keeping selection both in bytes and glyphs
             struct glyphbyte {
@@ -175,6 +175,12 @@
             }
             
             void focused() override;
+            
+            void mousedown(UI::ComponentTemplate::Tag tag, Geometry::Point location, Input::Mouse::Button button);
+            
+            void mouseup(UI::ComponentTemplate::Tag tag, Geometry::Point location, Input::Mouse::Button button);
+            
+            void mousemove(UI::ComponentTemplate::Tag tag, Geometry::Point location);
 
             
             std::string display;
@@ -182,6 +188,9 @@
             glyphbyte selstart = {0, 0};
             glyphbyte sellen   = {0, 0};
             int glyphcount = 0;
+            int pglyph;
+            
+            bool ismousedown = false;
         
             Input::KeyRepeater repeater;
             
@@ -217,94 +226,9 @@
         {
             display = validator.ToString(value);
             
-            stack.HandleMouse(Input::Mouse::Button::Left);
-            
-            stack.SetMouseDownEvent([this](auto, auto, auto btn) {
-                if(allowfocus() && btn == Input::Mouse::Button::Left)
-                    Focus();
-            });
-            
             updatevaluedisplay();
             updateselection();
 
-            repeater.Register(Input::Keyboard::Keycodes::Left);
-            repeater.Register(Input::Keyboard::Keycodes::Right);
-
-            repeater.SetRepeatOnPress(true);
-
-            repeater.Repeat.Register([this](Input::Key key) {
-                if(Input::Keyboard::CurrentModifier == Input::Keyboard::Modifier::Shift) {
-                    if(sellen.byte == allselected) {
-                        sellen.byte  = (int)display.size() - selstart.byte;
-                        sellen.glyph = glyphcount - selstart.glyph;
-                    }
-
-                    if(key == Input::Keyboard::Keycodes::Left) {
-                        if(sellen.glyph + selstart.glyph > 0) {
-                            sellen.glyph--;
-                            sellen.byte--;
-
-                            //if previous byte is unicode continuation point, go further before
-                            while((sellen.byte + selstart.byte) && (display[sellen.byte + selstart.byte] & 0b11000000) == 0b10000000)
-                                sellen.byte--;
-                        }
-
-                        updateselection();
-                    }
-                    else if(key == Input::Keyboard::Keycodes::Right) {
-                        if(sellen.glyph + selstart.glyph < glyphcount) {
-                            sellen.glyph++;
-                            sellen.byte += String::UTF8Bytes(display[selstart.byte + sellen.byte]);
-                        }
-
-                        updateselection();
-                    }
-                }
-                else if(Input::Keyboard::CurrentModifier == Input::Keyboard::Modifier::None) {
-                    if(sellen.byte == allselected) {
-                        sellen = {0, 0};
-
-                        if(key == Input::Keyboard::Keycodes::Left) {
-                            selstart = {0, 0};
-                        }
-                        else if(key == Input::Keyboard::Keycodes::Right) {
-                            selstart = {Length(), (int)display.size()};
-                        }
-
-                        updateselection();
-                    }
-                    else if(sellen.byte != 0) {
-                        if(key == Input::Keyboard::Keycodes::Left) {
-                            if(sellen.byte < 0) {
-                                selstart += sellen;
-
-                                moveselleft();
-                            }
-                        }
-                        else if(key == Input::Keyboard::Keycodes::Right) {
-                            if(sellen.byte > 0) {
-                                selstart += sellen;
-
-                                moveselright();
-                            }
-                        }
-
-                        sellen = {0, 0};
-
-                        updateselection();
-                    }
-                    else {
-                        if(key == Input::Keyboard::Keycodes::Left) {
-                            moveselleft();
-                            updateselection();
-                        }
-                        else if(key == Input::Keyboard::Keycodes::Right) {
-                            moveselright();
-                            updateselection();
-                        }
-                    }
-                }
-            });
         }
         
         /// Initializes the inputbox

mercurial