From 4531b9957810a08d91078c8d17cac7534229bbca Mon Sep 17 00:00:00 2001 From: elliot woods Date: Sun, 30 Nov 2014 13:23:46 +0900 Subject: [PATCH 01/10] minor refactoring. took out clipboard defines for time being --- src/ofxTextInputField.cpp | 104 ++++++++++++++------------------------ src/ofxTextInputField.h | 27 +++++----- 2 files changed, 52 insertions(+), 79 deletions(-) diff --git a/src/ofxTextInputField.cpp b/src/ofxTextInputField.cpp index 732e398..9ece40d 100755 --- a/src/ofxTextInputField.cpp +++ b/src/ofxTextInputField.cpp @@ -1,22 +1,14 @@ // // textInput.cpp // -// Created by Elliot Woods on 09/12/2011. -// Copyright 2011 Kimchi and Chips. -// -// modified by James George 12/2/2011 -// modified by Momo the Monster 7/10/2012 -// swappable fonts added by James George 9/11/2012 -// // MIT license // http://www.opensource.org/licenses/mit-license.php // #include "ofxTextInputField.h" - +//---------- ofxTextInputField::ofxTextInputField() { - shiftMap[44] = '<'; shiftMap[45] = '_'; shiftMap[46] = '>'; @@ -45,7 +37,6 @@ ofxTextInputField::ofxTextInputField() { selectionEnd = 0; selecting = false; - fontRef = NULL; isEnabled = false; isEditing = false; @@ -56,13 +47,13 @@ ofxTextInputField::ofxTextInputField() { mouseDownInRect = false; fontRef = new ofxTextInput::BitmapFontRenderer(); - //isSetup = false; - VERTICAL_PADDING = 3; - HORIZONTAL_PADDING = 3; + verticalPadding = 3; + horizontalPadding = 3; lastTimeCursorMoved = ofGetElapsedTimef(); } +//---------- ofxTextInputField::~ofxTextInputField(){ if(isEnabled){ disable(); @@ -70,11 +61,20 @@ ofxTextInputField::~ofxTextInputField(){ } +//---------- void ofxTextInputField::setup(){ enable(); } +//---------- +void ofxTextInputField::setFont(OFX_TEXTFIELD_FONT_RENDERER& font){ + if (fontRef->isBitmapFont()) { + delete fontRef; + } + fontRef = new ofxTextInput::TypedFontRenderer(&font); +} +//---------- void ofxTextInputField::enable(){ if(!isEnabled){ ofAddListener(ofEvents().mousePressed, this, &ofxTextInputField::mousePressed); @@ -84,6 +84,7 @@ void ofxTextInputField::enable(){ } } +//---------- void ofxTextInputField::disable(){ if(isEditing){ endEditing(); @@ -96,6 +97,8 @@ void ofxTextInputField::disable(){ } } + +//---------- void ofxTextInputField::beginEditing() { if(!isEditing){ ofAddListener(ofEvents().keyPressed, this, &ofxTextInputField::keyPressed); @@ -113,6 +116,7 @@ void ofxTextInputField::beginEditing() { } } +//---------- void ofxTextInputField::endEditing() { if(isEditing){ ofRemoveListener(ofEvents().keyPressed, this, &ofxTextInputField::keyPressed); @@ -123,21 +127,17 @@ void ofxTextInputField::endEditing() { } } -void ofxTextInputField::setFont(OFX_TEXTFIELD_FONT_RENDERER& font){ - if(fontRef->isBitmapFont()) { - delete fontRef; - } - fontRef = new ofxTextInput::TypedFontRenderer(&font); -} - +//---------- bool ofxTextInputField::getIsEditing(){ return isEditing; } +//---------- bool ofxTextInputField::getIsEnabled(){ return isEnabled; } +//---------- void ofxTextInputField::draw() { ofPushMatrix(); @@ -213,10 +213,10 @@ void ofxTextInputField::draw() { int cursorX, cursorY; getCursorCoords(cursorPosition, cursorX, cursorY); // printf("Pos: %d X: %d Y: %d\n", cursorPosition, cursorX, cursorY); - int cursorPos = HORIZONTAL_PADDING + fontRef->stringWidth(lines[cursorY].substr(0,cursorX)); + int cursorPos = horizontalPadding + fontRef->stringWidth(lines[cursorY].substr(0, cursorX)); - int cursorTop = VERTICAL_PADDING + fontRef->getLineHeight()*cursorY; + int cursorTop = verticalPadding + fontRef->getLineHeight()*cursorY; int cursorBottom = cursorTop + fontRef->getLineHeight(); @@ -229,13 +229,14 @@ void ofxTextInputField::draw() { ofPopStyle(); } - fontRef->drawString(text, HORIZONTAL_PADDING, fontRef->getLineHeight()+VERTICAL_PADDING); + fontRef->drawString(text, horizontalPadding, fontRef->getLineHeight() + verticalPadding); ofPopMatrix(); } +//---------- void ofxTextInputField::getCursorCoords(int pos, int &cursorX, int &cursorY) { vector lines = ofSplitString(text, "\n"); @@ -254,20 +255,11 @@ void ofxTextInputField::getCursorCoords(int pos, int &cursorX, int &cursorY) { } -/* -void ofxTextInputField::setCursorPositionFromXY() { - cursorPosition = cursorx; - vector parts = ofSplitString(text, "\n"); - for(int i = 0 ; i < cursory; i++) { - cursorPosition += parts[i].size() + i; // for carriage returns - } -} - -*/ +//---------- int ofxTextInputField::getCursorPositionFromMouse(int x, int y) { int cursorX = 0; int cursorY = 0; - float pos = y - bounds.y - VERTICAL_PADDING; + float pos = y - bounds.y - verticalPadding; pos /= fontRef->getLineHeight(); int line = pos; cursorY = line; @@ -275,7 +267,7 @@ int ofxTextInputField::getCursorPositionFromMouse(int x, int y) { vector lines = ofSplitString(text, "\n"); if(cursorY>=lines.size()-1) cursorY = lines.size()-1; if(lines.size()>0) { - cursorX = fontRef->getPosition(lines[cursorY], x - HORIZONTAL_PADDING - bounds.x); + cursorX = fontRef->getPosition(lines[cursorY], x - horizontalPadding - bounds.x); } int c = 0; for(int i = 0; i < cursorY; i++) { @@ -285,7 +277,7 @@ int ofxTextInputField::getCursorPositionFromMouse(int x, int y) { return c; } - +//---------- void ofxTextInputField::mousePressed(ofMouseEventArgs& args){ mouseDownInRect = bounds.inside(args.x, args.y); if(mouseDownInRect) { @@ -296,6 +288,7 @@ void ofxTextInputField::mousePressed(ofMouseEventArgs& args){ } +//---------- void ofxTextInputField::mouseDragged(ofMouseEventArgs& args) { if(bounds.inside(args.x, args.y)) { int pos = getCursorPositionFromMouse(args.x, args.y); @@ -310,8 +303,8 @@ void ofxTextInputField::mouseDragged(ofMouseEventArgs& args) { } } +//---------- void ofxTextInputField::mouseReleased(ofMouseEventArgs& args){ - if(bounds.inside(args.x, args.y)) { if(!isEditing && mouseDownInRect){ beginEditing(); @@ -322,32 +315,21 @@ void ofxTextInputField::mouseReleased(ofMouseEventArgs& args){ } } - -#ifdef OF_VERSION_MINOR -#if OF_VERSION_MINOR>=8 || OF_VERSION_MAJOR>0 -#define USE_GLFW_CLIPBOARD - -#endif -#endif - - #ifdef USE_GLFW_CLIPBOARD - #if (_MSC_VER) #include #else #include "GLFW/glfw3.h" #endif - -void ofxTextInputField::setClipboard(string clippy) -{ +//---------- +void ofxTextInputField::setClipboard(string clippy){ glfwSetClipboardString( (GLFWwindow*) ofGetWindowPtr()->getCocoaWindow(), clippy.c_str()); } -string ofxTextInputField::getClipboard() -{ +//---------- +string ofxTextInputField::getClipboard(){ const char *clip = glfwGetClipboardString((GLFWwindow*) ofGetWindowPtr()->getCocoaWindow()); if(clip!=NULL) { return string(clip); @@ -359,13 +341,13 @@ string ofxTextInputField::getClipboard() #endif +//---------- void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { //ew: add charachter (non unicode sorry!) //jg: made a step closer to this with swappable renderers and ofxFTGL -- but need unicode text input... lastTimeCursorMoved = ofGetElapsedTimef(); int key = args.key; - if(key == OF_KEY_SHIFT) { isShifted = true; } @@ -396,7 +378,6 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { } } - if (key == OF_KEY_RETURN) { if(!multiline) { endEditing(); @@ -404,7 +385,6 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { } text.insert(text.begin()+cursorPosition, '\n'); cursorPosition++; - if(autoTab) { // how much whitespace is there on the previous line? @@ -459,7 +439,6 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { cursorPosition++; } - if (key==OF_KEY_BACKSPACE) { if(selecting) { text.erase(text.begin() + selectionBegin, @@ -501,8 +480,6 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { } } - - if (key==OF_KEY_RIGHT){ if(selecting) { cursorPosition = selectionEnd; @@ -514,7 +491,6 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { } } - if (key==OF_KEY_UP){ if(selecting) { cursorPosition = selectionBegin; @@ -538,8 +514,6 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { } } - - if (key==OF_KEY_DOWN){ if(selecting) { cursorPosition = selectionEnd; @@ -560,12 +534,9 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { } } } - - - - } +//---------- void ofxTextInputField::keyReleased(ofKeyEventArgs &a) { @@ -578,7 +549,8 @@ void ofxTextInputField::keyReleased(ofKeyEventArgs &a) } } +//---------- void ofxTextInputField::clear() { text.clear(); cursorPosition = 0; -} +} \ No newline at end of file diff --git a/src/ofxTextInputField.h b/src/ofxTextInputField.h index e697542..25cdae3 100755 --- a/src/ofxTextInputField.h +++ b/src/ofxTextInputField.h @@ -3,16 +3,17 @@ // textInput // // Created by Elliot Woods on 09/12/2011. -// Copyright 2011 Kimchi and Chips. -// // modified by James George 12/2/2011 // modified by Momo the Monster 7/10/2012 // swappable fonts added by James George 9/11/2012 +// refactoring and modifications by Elliot Woods on 30/11/2014 // // MIT license // http://www.opensource.org/licenses/mit-license.php // +// jg : TODO: text wrapping + #pragma once #include "ofMain.h" @@ -21,7 +22,7 @@ //(like ofxFTGL or ofxFont) //to use ofxFTGL use somethinglike this: //#define OFX_TEXTFIELD_FONT_RENDERER ofxFTGLFont -//#define OFX_TEXTFIELD_FONT_RENDERER "ofxFTGLFont.h" +//#define OFX_TEXTFIELD_FONT_INCLUDE "ofxFTGLFont.h" #ifndef OFX_TEXTFIELD_FONT_RENDERER #define OFX_TEXTFIELD_FONT_RENDERER ofTrueTypeFont @@ -34,19 +35,19 @@ #define TEXTFIELD_IS_ACTIVE "textfieldIsActive" #define TEXTFIELD_IS_INACTIVE "textfieldIsInactive" - -// TODO: wrapping #include "ofxTextInputFieldFontRenderer.h" class ofxTextInputField { public: ofxTextInputField(); virtual ~ofxTextInputField(); - //swap in a font! + + /// Always call this first + void setup(bool useEvents = trie); + + /// Change the font used to draw the text void setFont(OFX_TEXTFIELD_FONT_RENDERER& font); - - void setup(); - + void enable(); void disable(); bool getIsEnabled(); @@ -73,7 +74,10 @@ class ofxTextInputField { ofEvent textChanged; void keyPressed(ofKeyEventArgs &a); void keyReleased(ofKeyEventArgs &a); - + void mousePressed(ofMouseEventArgs& args); + void mouseDragged(ofMouseEventArgs& args); + void mouseReleased(ofMouseEventArgs& args); + bool autoClear; bool autoTab; @@ -93,9 +97,6 @@ class ofxTextInputField { bool isEnabled; bool isEditing; bool mouseDownInRect; - void mousePressed(ofMouseEventArgs& args); - void mouseDragged(ofMouseEventArgs& args); - void mouseReleased(ofMouseEventArgs& args); //int getLineForPosition(int pos); From 5c66e5025275b405036246eb5661bee038ac7be8 Mon Sep 17 00:00:00 2001 From: elliot woods Date: Sun, 30 Nov 2014 13:31:42 +0900 Subject: [PATCH 02/10] refactoring --- src/ofxTextInputField.cpp | 104 ++++++++++++++------------------------ src/ofxTextInputField.h | 28 +++++----- 2 files changed, 50 insertions(+), 82 deletions(-) diff --git a/src/ofxTextInputField.cpp b/src/ofxTextInputField.cpp index 9ece40d..a63d7cc 100755 --- a/src/ofxTextInputField.cpp +++ b/src/ofxTextInputField.cpp @@ -38,8 +38,8 @@ ofxTextInputField::ofxTextInputField() { selecting = false; fontRef = NULL; - isEnabled = false; - isEditing = false; + this->enabled = false; + this->editing = false; bounds = ofRectangle(0,0,100,22); drawCursor = false; @@ -55,7 +55,7 @@ ofxTextInputField::ofxTextInputField() { //---------- ofxTextInputField::~ofxTextInputField(){ - if(isEnabled){ + if(this->enabled){ disable(); } @@ -76,82 +76,69 @@ void ofxTextInputField::setFont(OFX_TEXTFIELD_FONT_RENDERER& font){ //---------- void ofxTextInputField::enable(){ - if(!isEnabled){ + if(!this->enabled){ ofAddListener(ofEvents().mousePressed, this, &ofxTextInputField::mousePressed); ofAddListener(ofEvents().mouseDragged, this, &ofxTextInputField::mouseDragged); ofAddListener(ofEvents().mouseReleased, this, &ofxTextInputField::mouseReleased); - isEnabled = true; + this->enabled = true; } } //---------- void ofxTextInputField::disable(){ - if(isEditing){ + if(this->editing){ endEditing(); } - if(isEnabled){ + if(this->enabled){ ofRemoveListener(ofEvents().mousePressed, this, &ofxTextInputField::mousePressed); ofRemoveListener(ofEvents().mouseDragged, this, &ofxTextInputField::mouseDragged); ofRemoveListener(ofEvents().mouseReleased, this, &ofxTextInputField::mouseReleased); - isEnabled = false; + this->enabled = false; } } +//---------- +bool ofxTextInputField::isEnabled() const { + return this->enabled; +} + //---------- void ofxTextInputField::beginEditing() { - if(!isEditing){ + if(!this->editing){ ofAddListener(ofEvents().keyPressed, this, &ofxTextInputField::keyPressed); ofAddListener(ofEvents().keyReleased, this, &ofxTextInputField::keyReleased); ofSendMessage(TEXTFIELD_IS_ACTIVE); - isEditing = true; + this->enabled = true; drawCursor = true; - if(autoClear){ + if(autoClear) { clear(); } - else{ - - - } } } //---------- void ofxTextInputField::endEditing() { - if(isEditing){ + if(this->editing){ ofRemoveListener(ofEvents().keyPressed, this, &ofxTextInputField::keyPressed); ofSendMessage(TEXTFIELD_IS_INACTIVE); ofNotifyEvent(textChanged, text, this); - isEditing = false; - drawCursor = false; + this->editing = false; + this->drawCursor = false; } } //---------- -bool ofxTextInputField::getIsEditing(){ - return isEditing; -} - -//---------- -bool ofxTextInputField::getIsEnabled(){ - return isEnabled; +bool ofxTextInputField::isEditing() const { + return this->editing; } //---------- void ofxTextInputField::draw() { - ofPushMatrix(); ofTranslate(bounds.x, bounds.y); - - - - - - if(selecting) { - - ofPushStyle(); // argh, splitting all the time. vector lines = ofSplitString(text, "\n"); @@ -168,26 +155,26 @@ void ofxTextInputField::draw() { if(beginCursorY==endCursorY) { // single line selection - ofRect(HORIZONTAL_PADDING + startX, VERTICAL_PADDING + fontRef->getLineHeight()*beginCursorY, + ofRect(horizontalPadding + startX, verticalPadding + fontRef->getLineHeight()*beginCursorY, endX - startX, fontRef->getLineHeight()); } else { // multiline selection. // do first line to the end - ofRect(HORIZONTAL_PADDING + startX, VERTICAL_PADDING + fontRef->getLineHeight()*beginCursorY, + ofRect(horizontalPadding + startX, verticalPadding + fontRef->getLineHeight()*beginCursorY, fontRef->stringWidth(lines[beginCursorY]) - startX, fontRef->getLineHeight() ); // loop through entirely selected lines for(int i = beginCursorY + 1; i < endCursorY; i++) { - ofRect(HORIZONTAL_PADDING, VERTICAL_PADDING + fontRef->getLineHeight()*i, + ofRect(horizontalPadding, verticalPadding + fontRef->getLineHeight()*i, fontRef->stringWidth(lines[i]), fontRef->getLineHeight() ); } // do last line up to endX - ofRect(HORIZONTAL_PADDING, VERTICAL_PADDING + fontRef->getLineHeight()*endCursorY, + ofRect(horizontalPadding, verticalPadding + fontRef->getLineHeight()*endCursorY, endX, fontRef->getLineHeight() ); } @@ -215,13 +202,9 @@ void ofxTextInputField::draw() { // printf("Pos: %d X: %d Y: %d\n", cursorPosition, cursorX, cursorY); int cursorPos = horizontalPadding + fontRef->stringWidth(lines[cursorY].substr(0, cursorX)); - int cursorTop = verticalPadding + fontRef->getLineHeight()*cursorY; int cursorBottom = cursorTop + fontRef->getLineHeight(); - - - ofSetLineWidth(1.0f); //TODO: multiline with fontRef ofLine(cursorPos, cursorTop, @@ -230,9 +213,6 @@ void ofxTextInputField::draw() { } fontRef->drawString(text, horizontalPadding, fontRef->getLineHeight() + verticalPadding); - - - ofPopMatrix(); } @@ -240,10 +220,7 @@ void ofxTextInputField::draw() { void ofxTextInputField::getCursorCoords(int pos, int &cursorX, int &cursorY) { vector lines = ofSplitString(text, "\n"); - int c = 0; - - for(int i = 0; i < lines.size(); i++) { if(pos<=c+lines[i].size()) { cursorY = i; @@ -252,7 +229,6 @@ void ofxTextInputField::getCursorCoords(int pos, int &cursorX, int &cursorY) { } c += lines[i].size() + 1; } - } //---------- @@ -278,7 +254,7 @@ int ofxTextInputField::getCursorPositionFromMouse(int x, int y) { } //---------- -void ofxTextInputField::mousePressed(ofMouseEventArgs& args){ +void ofxTextInputField::mousePressed(ofMouseEventArgs& args) { mouseDownInRect = bounds.inside(args.x, args.y); if(mouseDownInRect) { cursorPosition = getCursorPositionFromMouse(args.x, args.y); @@ -304,13 +280,12 @@ void ofxTextInputField::mouseDragged(ofMouseEventArgs& args) { } //---------- -void ofxTextInputField::mouseReleased(ofMouseEventArgs& args){ +void ofxTextInputField::mouseReleased(ofMouseEventArgs& args) { if(bounds.inside(args.x, args.y)) { - if(!isEditing && mouseDownInRect){ + if(!this->editing && mouseDownInRect) { beginEditing(); } - } - else if(isEditing){ + } else if(this->editing){ endEditing(); } } @@ -349,20 +324,20 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { int key = args.key; if(key == OF_KEY_SHIFT) { - isShifted = true; + this->shiftHeld = true; } if(key == 4352) { - isCommand = true; + this->commandHeld = true; } #ifdef USE_GLFW_CLIPBOARD - if(key == 'c' && isCommand ) { + if(key == 'c' && this->commandHeld) { setClipboard(text.substr(selectionBegin, selectionEnd - selectionBegin)); return; } - if(key == 'v' && isCommand ) { + if(key == 'v' && this->commandHeld) { text.insert(cursorPosition, getClipboard()); return; } @@ -422,8 +397,7 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { } if ((key >=32 && key <=126) || key=='\t') { - - if(isShifted) { + if(this->shiftHeld) { char toInsert; if( !(key > 96 && key < 123) && !(key > 65 && key < 90) && shiftMap.find(key) != shiftMap.end() ) { @@ -537,20 +511,18 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { } //---------- -void ofxTextInputField::keyReleased(ofKeyEventArgs &a) -{ - +void ofxTextInputField::keyReleased(ofKeyEventArgs &a){ if(a.key == 4352) { - isCommand = false; + this->commandHeld = false; } if(a.key == OF_KEY_SHIFT) { - isShifted = false; + this->shiftHeld = false; } } //---------- -void ofxTextInputField::clear() { +void ofxTextInputField::clear(){ text.clear(); cursorPosition = 0; } \ No newline at end of file diff --git a/src/ofxTextInputField.h b/src/ofxTextInputField.h index 25cdae3..8d7ab1a 100755 --- a/src/ofxTextInputField.h +++ b/src/ofxTextInputField.h @@ -43,19 +43,19 @@ class ofxTextInputField { virtual ~ofxTextInputField(); /// Always call this first - void setup(bool useEvents = trie); + void setup(); /// Change the font used to draw the text void setFont(OFX_TEXTFIELD_FONT_RENDERER& font); void enable(); void disable(); - bool getIsEnabled(); + bool isEnabled() const; - bool getIsEditing(); void beginEditing(); void endEditing(); - + bool isEditing() const; + //can be set manually or otherwise is controlled by enable/disable bool drawCursor; @@ -90,23 +90,19 @@ class ofxTextInputField { protected: float lastTimeCursorMoved; - int VERTICAL_PADDING; - int HORIZONTAL_PADDING; - ofxTextInput::FontRenderer* fontRef; - bool isEnabled; - bool isEditing; - bool mouseDownInRect; + float verticalPadding; + float horizontalPadding; + + ofxTextInput::FontRenderer* fontRef; + bool enabled; + bool editing; + bool mouseDownInRect; - //int getLineForPosition(int pos); - - //void setCursorPositionFromXY(); - //void setCursorFromMouse(int x, int y); - //void setCursorXYFromPosition(); void getCursorCoords(int pos, int &cursorX, int &cursorY); int getCursorPositionFromMouse(int x, int y); - bool isShifted, isCommand; + bool shiftHeld, commandHeld; map shiftMap; }; From bbe4914bfc9107e0e3f570652e85477616a19c53 Mon Sep 17 00:00:00 2001 From: elliot woods Date: Sun, 30 Nov 2014 14:13:21 +0900 Subject: [PATCH 03/10] debug --- src/ofxTextInputField.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/ofxTextInputField.cpp b/src/ofxTextInputField.cpp index a63d7cc..b13caf0 100755 --- a/src/ofxTextInputField.cpp +++ b/src/ofxTextInputField.cpp @@ -109,7 +109,7 @@ void ofxTextInputField::beginEditing() { ofAddListener(ofEvents().keyPressed, this, &ofxTextInputField::keyPressed); ofAddListener(ofEvents().keyReleased, this, &ofxTextInputField::keyReleased); ofSendMessage(TEXTFIELD_IS_ACTIVE); - this->enabled = true; + this->editing = true; drawCursor = true; if(autoClear) { clear(); @@ -138,6 +138,16 @@ void ofxTextInputField::draw() { ofPushMatrix(); ofTranslate(bounds.x, bounds.y); + //debug graphics + ofPushStyle(); + ofSetColor(255, 0, 0); + this->isEnabled() ? ofFill() : ofNoFill(); + ofCircle(10, 10, 5); + ofSetColor(0, 255, 0); + this->isEditing() ? ofFill() : ofNoFill(); + ofCircle(20, 10, 5); + ofPopStyle(); + if(selecting) { ofPushStyle(); // argh, splitting all the time. @@ -272,7 +282,6 @@ void ofxTextInputField::mouseDragged(ofMouseEventArgs& args) { selecting = true; selectionBegin = MIN(pos, cursorPosition); selectionEnd = MAX(pos, cursorPosition); - } else { selecting = false; } @@ -285,7 +294,7 @@ void ofxTextInputField::mouseReleased(ofMouseEventArgs& args) { if(!this->editing && mouseDownInRect) { beginEditing(); } - } else if(this->editing){ + } else { endEditing(); } } @@ -367,7 +376,6 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { getCursorCoords(cursorPosition, xx, yy); vector lines = ofSplitString(text, "\n"); if(yy>0) { - // collect all the whitespace on the previous line. string previousWhitespace = ""; string previousLine = lines[yy-1]; From 973ba220fdb358bf96f2e52c8beb85f6c11fdf56 Mon Sep 17 00:00:00 2001 From: Elliot Woods Date: Sun, 30 Nov 2014 09:15:08 +0100 Subject: [PATCH 04/10] listeners are seperated. tested with example and works --- src/ofxTextInputField.cpp | 1126 +++++++++++++++++++------------------ src/ofxTextInputField.h | 228 ++++---- 2 files changed, 711 insertions(+), 643 deletions(-) diff --git a/src/ofxTextInputField.cpp b/src/ofxTextInputField.cpp index b13caf0..e37f3c4 100755 --- a/src/ofxTextInputField.cpp +++ b/src/ofxTextInputField.cpp @@ -1,536 +1,592 @@ -// -// textInput.cpp -// -// MIT license -// http://www.opensource.org/licenses/mit-license.php -// - -#include "ofxTextInputField.h" - -//---------- -ofxTextInputField::ofxTextInputField() { - shiftMap[44] = '<'; - shiftMap[45] = '_'; - shiftMap[46] = '>'; - shiftMap[48] = ')'; - shiftMap[49] = '!'; - shiftMap[50] = '@'; - shiftMap[51] = '#'; - shiftMap[52] = '$'; - shiftMap[53] = '%'; - shiftMap[54] = '^'; - shiftMap[55] = '&'; - shiftMap[56] = '*'; - shiftMap[57] = '('; - shiftMap[61] = '+'; - shiftMap[63] = '/'; - shiftMap[91] = '{'; - shiftMap[92] = '|'; - shiftMap[93] = '}'; - shiftMap[96] = '~'; - - text = ""; - multiline = false; - autoTab = true; - cursorPosition = 0; - selectionBegin = 0; - selectionEnd = 0; - selecting = false; - - fontRef = NULL; - this->enabled = false; - this->editing = false; - bounds = ofRectangle(0,0,100,22); - - drawCursor = false; - autoClear = false; - mouseDownInRect = false; - - fontRef = new ofxTextInput::BitmapFontRenderer(); - - verticalPadding = 3; - horizontalPadding = 3; - lastTimeCursorMoved = ofGetElapsedTimef(); -} - -//---------- -ofxTextInputField::~ofxTextInputField(){ - if(this->enabled){ - disable(); - } - -} - -//---------- -void ofxTextInputField::setup(){ - enable(); -} - -//---------- -void ofxTextInputField::setFont(OFX_TEXTFIELD_FONT_RENDERER& font){ - if (fontRef->isBitmapFont()) { - delete fontRef; - } - fontRef = new ofxTextInput::TypedFontRenderer(&font); -} - -//---------- -void ofxTextInputField::enable(){ - if(!this->enabled){ - ofAddListener(ofEvents().mousePressed, this, &ofxTextInputField::mousePressed); - ofAddListener(ofEvents().mouseDragged, this, &ofxTextInputField::mouseDragged); - ofAddListener(ofEvents().mouseReleased, this, &ofxTextInputField::mouseReleased); - this->enabled = true; - } -} - -//---------- -void ofxTextInputField::disable(){ - if(this->editing){ - endEditing(); - } - if(this->enabled){ - ofRemoveListener(ofEvents().mousePressed, this, &ofxTextInputField::mousePressed); - ofRemoveListener(ofEvents().mouseDragged, this, &ofxTextInputField::mouseDragged); - ofRemoveListener(ofEvents().mouseReleased, this, &ofxTextInputField::mouseReleased); - this->enabled = false; - } - -} - -//---------- -bool ofxTextInputField::isEnabled() const { - return this->enabled; -} - -//---------- -void ofxTextInputField::beginEditing() { - if(!this->editing){ - ofAddListener(ofEvents().keyPressed, this, &ofxTextInputField::keyPressed); - ofAddListener(ofEvents().keyReleased, this, &ofxTextInputField::keyReleased); - ofSendMessage(TEXTFIELD_IS_ACTIVE); - this->editing = true; - drawCursor = true; - if(autoClear) { - clear(); - } - } -} - -//---------- -void ofxTextInputField::endEditing() { - if(this->editing){ - ofRemoveListener(ofEvents().keyPressed, this, &ofxTextInputField::keyPressed); - ofSendMessage(TEXTFIELD_IS_INACTIVE); - ofNotifyEvent(textChanged, text, this); - this->editing = false; - this->drawCursor = false; - } -} - -//---------- -bool ofxTextInputField::isEditing() const { - return this->editing; -} - -//---------- -void ofxTextInputField::draw() { - ofPushMatrix(); - ofTranslate(bounds.x, bounds.y); - - //debug graphics - ofPushStyle(); - ofSetColor(255, 0, 0); - this->isEnabled() ? ofFill() : ofNoFill(); - ofCircle(10, 10, 5); - ofSetColor(0, 255, 0); - this->isEditing() ? ofFill() : ofNoFill(); - ofCircle(20, 10, 5); - ofPopStyle(); - - if(selecting) { - ofPushStyle(); - // argh, splitting all the time. - vector lines = ofSplitString(text, "\n"); - int beginCursorX, beginCursorY; - int endCursorX, endCursorY; - getCursorCoords(selectionBegin, beginCursorX, beginCursorY); - getCursorCoords(selectionEnd, endCursorX, endCursorY); - - float startX = fontRef->stringWidth(lines[beginCursorY].substr(0,beginCursorX)); - float endX = fontRef->stringWidth(lines[endCursorY].substr(0, endCursorX)); - - ofSetHexColor(0x6988db); - ofFill(); - - if(beginCursorY==endCursorY) { - // single line selection - ofRect(horizontalPadding + startX, verticalPadding + fontRef->getLineHeight()*beginCursorY, - endX - startX, fontRef->getLineHeight()); - } else { - - // multiline selection. - // do first line to the end - ofRect(horizontalPadding + startX, verticalPadding + fontRef->getLineHeight()*beginCursorY, - fontRef->stringWidth(lines[beginCursorY]) - startX, - fontRef->getLineHeight() - ); - - // loop through entirely selected lines - for(int i = beginCursorY + 1; i < endCursorY; i++) { - ofRect(horizontalPadding, verticalPadding + fontRef->getLineHeight()*i, - fontRef->stringWidth(lines[i]), - fontRef->getLineHeight() - ); - } - // do last line up to endX - ofRect(horizontalPadding, verticalPadding + fontRef->getLineHeight()*endCursorY, - endX, fontRef->getLineHeight() - ); - } - ofPopStyle(); - - - //draw cursor line - } else if(drawCursor) { - ofPushStyle(); - // cursor should only blink when its been idle, and animation - // should be a clipped sine wave - float timeFrac = 0.5 * ofClamp(cos(6.0f * (ofGetElapsedTimef()-lastTimeCursorMoved))*4, -1, 1) + 0.5; - - ofColor col = ofGetStyle().color; - ofSetColor(col.r * timeFrac, col.g * timeFrac, col.b * timeFrac); - - - // argh, splitting all the time. - vector lines = ofSplitString(text, "\n"); - - - // calculate this every loop. - int cursorX, cursorY; - getCursorCoords(cursorPosition, cursorX, cursorY); - // printf("Pos: %d X: %d Y: %d\n", cursorPosition, cursorX, cursorY); - int cursorPos = horizontalPadding + fontRef->stringWidth(lines[cursorY].substr(0, cursorX)); - - int cursorTop = verticalPadding + fontRef->getLineHeight()*cursorY; - int cursorBottom = cursorTop + fontRef->getLineHeight(); - - ofSetLineWidth(1.0f); - //TODO: multiline with fontRef - ofLine(cursorPos, cursorTop, - cursorPos, cursorBottom); - ofPopStyle(); - } - - fontRef->drawString(text, horizontalPadding, fontRef->getLineHeight() + verticalPadding); - ofPopMatrix(); -} - -//---------- -void ofxTextInputField::getCursorCoords(int pos, int &cursorX, int &cursorY) { - vector lines = ofSplitString(text, "\n"); - - int c = 0; - for(int i = 0; i < lines.size(); i++) { - if(pos<=c+lines[i].size()) { - cursorY = i; - cursorX = pos - c; - return; - } - c += lines[i].size() + 1; - } -} - -//---------- -int ofxTextInputField::getCursorPositionFromMouse(int x, int y) { - int cursorX = 0; - int cursorY = 0; - float pos = y - bounds.y - verticalPadding; - pos /= fontRef->getLineHeight(); - int line = pos; - cursorY = line; - - vector lines = ofSplitString(text, "\n"); - if(cursorY>=lines.size()-1) cursorY = lines.size()-1; - if(lines.size()>0) { - cursorX = fontRef->getPosition(lines[cursorY], x - horizontalPadding - bounds.x); - } - int c = 0; - for(int i = 0; i < cursorY; i++) { - c += lines[i].size() + 1; - } - c += cursorX; - return c; -} - -//---------- -void ofxTextInputField::mousePressed(ofMouseEventArgs& args) { - mouseDownInRect = bounds.inside(args.x, args.y); - if(mouseDownInRect) { - cursorPosition = getCursorPositionFromMouse(args.x, args.y); - lastTimeCursorMoved = ofGetElapsedTimef(); - selecting = false; - } -} - - -//---------- -void ofxTextInputField::mouseDragged(ofMouseEventArgs& args) { - if(bounds.inside(args.x, args.y)) { - int pos = getCursorPositionFromMouse(args.x, args.y); - if(pos!=cursorPosition) { - selecting = true; - selectionBegin = MIN(pos, cursorPosition); - selectionEnd = MAX(pos, cursorPosition); - } else { - selecting = false; - } - } -} - -//---------- -void ofxTextInputField::mouseReleased(ofMouseEventArgs& args) { - if(bounds.inside(args.x, args.y)) { - if(!this->editing && mouseDownInRect) { - beginEditing(); - } - } else { - endEditing(); - } -} - -#ifdef USE_GLFW_CLIPBOARD - -#if (_MSC_VER) -#include -#else -#include "GLFW/glfw3.h" -#endif - -//---------- -void ofxTextInputField::setClipboard(string clippy){ - glfwSetClipboardString( (GLFWwindow*) ofGetWindowPtr()->getCocoaWindow(), clippy.c_str()); -} - -//---------- -string ofxTextInputField::getClipboard(){ - const char *clip = glfwGetClipboardString((GLFWwindow*) ofGetWindowPtr()->getCocoaWindow()); - if(clip!=NULL) { - return string(clip); - } else { - return ""; - } - -} - -#endif - -//---------- -void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { - //ew: add charachter (non unicode sorry!) - //jg: made a step closer to this with swappable renderers and ofxFTGL -- but need unicode text input... - lastTimeCursorMoved = ofGetElapsedTimef(); - int key = args.key; - - if(key == OF_KEY_SHIFT) { - this->shiftHeld = true; - } - - if(key == 4352) { - this->commandHeld = true; - } - - #ifdef USE_GLFW_CLIPBOARD - if(key == 'c' && this->commandHeld) { - setClipboard(text.substr(selectionBegin, selectionEnd - selectionBegin)); - return; - } - - if(key == 'v' && this->commandHeld) { - text.insert(cursorPosition, getClipboard()); - return; - } - #endif - - if ((key >=32 && key <=126) || key=='\t' || key==OF_KEY_RETURN) { - if(selecting) { - text.erase(text.begin() + selectionBegin, - text.begin() + selectionEnd - ); - cursorPosition = selectionBegin; - selecting = false; - } - } - - if (key == OF_KEY_RETURN) { - if(!multiline) { - endEditing(); - return; - } - text.insert(text.begin()+cursorPosition, '\n'); - cursorPosition++; - - if(autoTab) { - // how much whitespace is there on the previous line? - int xx, yy; - getCursorCoords(cursorPosition, xx, yy); - vector lines = ofSplitString(text, "\n"); - if(yy>0) { - // collect all the whitespace on the previous line. - string previousWhitespace = ""; - string previousLine = lines[yy-1]; - int pos = 0; - for(int i = 0; i < previousLine.size(); i++) { - if(previousLine[i]==' ' || previousLine[i]=='\t') { - previousWhitespace += previousLine[i]; - } else { - break; - } - } - // if we have a curly brace as the last char on the previous line - // increase the indentation - if(previousLine[previousLine.size()-1]=='{') { - if(previousWhitespace=="") { - previousWhitespace = "\t"; - } else { - previousWhitespace += previousWhitespace[previousWhitespace.size()-1]; - } - } - text = text.insert(cursorPosition, previousWhitespace); - cursorPosition += previousWhitespace.size(); - } - } - - return; - } - - if ((key >=32 && key <=126) || key=='\t') { - if(this->shiftHeld) { - - char toInsert; - if( !(key > 96 && key < 123) && !(key > 65 && key < 90) && shiftMap.find(key) != shiftMap.end() ) { - toInsert = shiftMap[key];//toInsert = key - 32; - } else { - toInsert = key; - } - - text.insert(text.begin()+cursorPosition, toInsert); - } else { - text.insert(text.begin()+cursorPosition, key); - } - cursorPosition++; - } - - if (key==OF_KEY_BACKSPACE) { - if(selecting) { - text.erase(text.begin() + selectionBegin, - text.begin() + selectionEnd - ); - cursorPosition = selectionBegin; - selecting = false; - } else { - if (cursorPosition>0) { - text.erase(text.begin()+cursorPosition-1); - --cursorPosition; - } - } - } - - if (key==OF_KEY_DEL) { - if(selecting) { - text.erase(text.begin() + selectionBegin, - text.begin() + selectionEnd - ); - cursorPosition = selectionBegin; - selecting = false; - } else { - if (text.size() > cursorPosition) { - text.erase(text.begin()+cursorPosition); - } - } - } - - if (key==OF_KEY_LEFT){ - if(selecting) { - cursorPosition = selectionBegin; - selecting = false; - - } else { - if (cursorPosition>0){ - --cursorPosition; - } - } - } - - if (key==OF_KEY_RIGHT){ - if(selecting) { - cursorPosition = selectionEnd; - selecting = false; - } else { - if (cursorPosition0) { - int xx, yy; - getCursorCoords(cursorPosition, xx, yy); - if(yy>0) { - yy--; - vector lines = ofSplitString(text, "\n"); - xx = MIN(lines[yy].size()-1, xx); - cursorPosition = xx; - for(int i = 0; i < yy; i++) cursorPosition += lines[i].size()+1; - printf("Cursor position: %d\n", cursorPosition); - } else { - cursorPosition = 0; - } - } - } - } - - if (key==OF_KEY_DOWN){ - if(selecting) { - cursorPosition = selectionEnd; - selecting = false; - } else { - int xx, yy; - getCursorCoords(cursorPosition, xx, yy); - vector lines = ofSplitString(text, "\n"); - yy++; - if(yycommandHeld = false; - } - - if(a.key == OF_KEY_SHIFT) { - this->shiftHeld = false; - } -} - -//---------- -void ofxTextInputField::clear(){ - text.clear(); - cursorPosition = 0; +// +// textInput.cpp +// +// MIT license +// http://www.opensource.org/licenses/mit-license.php +// + +#include "ofxTextInputField.h" + +//---------- +ofxTextInputField::ofxTextInputField() { + shiftMap[44] = '<'; + shiftMap[45] = '_'; + shiftMap[46] = '>'; + shiftMap[48] = ')'; + shiftMap[49] = '!'; + shiftMap[50] = '@'; + shiftMap[51] = '#'; + shiftMap[52] = '$'; + shiftMap[53] = '%'; + shiftMap[54] = '^'; + shiftMap[55] = '&'; + shiftMap[56] = '*'; + shiftMap[57] = '('; + shiftMap[61] = '+'; + shiftMap[63] = '/'; + shiftMap[91] = '{'; + shiftMap[92] = '|'; + shiftMap[93] = '}'; + shiftMap[96] = '~'; + + text = ""; + multiline = false; + autoTab = true; + cursorPosition = 0; + selectionBegin = 0; + selectionEnd = 0; + selecting = false; + + fontRef = NULL; + this->enabled = false; + this->editing = false; + this->useListeners = false; + this->hasListeners = false; + bounds = ofRectangle(0,0,100,22); + + drawCursor = false; + autoClear = false; + mouseDownInRect = false; + + fontRef = new ofxTextInput::BitmapFontRenderer(); + + verticalPadding = 3; + horizontalPadding = 3; + lastTimeCursorMoved = ofGetElapsedTimef(); +} + +//---------- +ofxTextInputField::~ofxTextInputField(){ + this->removeListeners(); +} + +//---------- +void ofxTextInputField::setup(bool enableListeners){ + enable(); + this->setUseListeners(enableListeners); +} + +//---------- +void ofxTextInputField::setFont(OFX_TEXTFIELD_FONT_RENDERER& font){ + if (fontRef->isBitmapFont()) { + delete fontRef; + } + fontRef = new ofxTextInput::TypedFontRenderer(&font); +} + +//---------- +void ofxTextInputField::enable(){ + if(!this->enabled){ + this->enabled = true; + } +} + +//---------- +void ofxTextInputField::disable(){ + if(this->editing){ + endEditing(); + } + if(this->enabled){ + this->enabled = false; + } + +} + +//---------- +bool ofxTextInputField::isEnabled() const { + return this->enabled; +} + +//---------- +void ofxTextInputField::beginEditing() { + if(!this->editing){ + ofSendMessage(TEXTFIELD_IS_ACTIVE); + this->editing = true; + drawCursor = true; + if(autoClear) { + clear(); + } + } +} + +//---------- +void ofxTextInputField::endEditing() { + if(this->editing){ + ofSendMessage(TEXTFIELD_IS_INACTIVE); + ofNotifyEvent(textChanged, text, this); + this->editing = false; + this->drawCursor = false; + this->shiftHeld = false; + this->commandHeld = false; + } +} + +//---------- +bool ofxTextInputField::isEditing() const { + return this->editing; +} + +//---------- +void ofxTextInputField::setUseListeners(bool useListeners) { + if (useListeners) { + this->addListeners(); + } else { + this->removeListeners(); + } +} + +//---------- +bool ofxTextInputField::getUseListeners() const { + return this->useListeners; +} + +//---------- +void ofxTextInputField::draw() { + ofPushMatrix(); + ofTranslate(bounds.x, bounds.y); + + //debug graphics + ofPushStyle(); + ofSetColor(255, 0, 0); + this->isEnabled() ? ofFill() : ofNoFill(); + ofCircle(10, 10, 5); + ofSetColor(0, 255, 0); + this->isEditing() ? ofFill() : ofNoFill(); + ofCircle(20, 10, 5); + ofPopStyle(); + + if(selecting) { + ofPushStyle(); + // argh, splitting all the time. + vector lines = ofSplitString(text, "\n"); + int beginCursorX, beginCursorY; + int endCursorX, endCursorY; + getCursorCoords(selectionBegin, beginCursorX, beginCursorY); + getCursorCoords(selectionEnd, endCursorX, endCursorY); + + float startX = fontRef->stringWidth(lines[beginCursorY].substr(0,beginCursorX)); + float endX = fontRef->stringWidth(lines[endCursorY].substr(0, endCursorX)); + + ofSetHexColor(0x6988db); + ofFill(); + + if(beginCursorY==endCursorY) { + // single line selection + ofRect(horizontalPadding + startX, verticalPadding + fontRef->getLineHeight()*beginCursorY, + endX - startX, fontRef->getLineHeight()); + } else { + + // multiline selection. + // do first line to the end + ofRect(horizontalPadding + startX, verticalPadding + fontRef->getLineHeight()*beginCursorY, + fontRef->stringWidth(lines[beginCursorY]) - startX, + fontRef->getLineHeight() + ); + + // loop through entirely selected lines + for(int i = beginCursorY + 1; i < endCursorY; i++) { + ofRect(horizontalPadding, verticalPadding + fontRef->getLineHeight()*i, + fontRef->stringWidth(lines[i]), + fontRef->getLineHeight() + ); + } + // do last line up to endX + ofRect(horizontalPadding, verticalPadding + fontRef->getLineHeight()*endCursorY, + endX, fontRef->getLineHeight() + ); + } + ofPopStyle(); + + + //draw cursor line + } else if(drawCursor) { + ofPushStyle(); + // cursor should only blink when its been idle, and animation + // should be a clipped sine wave + float timeFrac = 0.5 * ofClamp(cos(6.0f * (ofGetElapsedTimef()-lastTimeCursorMoved))*4, -1, 1) + 0.5; + + ofColor col = ofGetStyle().color; + ofSetColor(col.r * timeFrac, col.g * timeFrac, col.b * timeFrac); + + + // argh, splitting all the time. + vector lines = ofSplitString(text, "\n"); + + + // calculate this every loop. + int cursorX, cursorY; + getCursorCoords(cursorPosition, cursorX, cursorY); + // printf("Pos: %d X: %d Y: %d\n", cursorPosition, cursorX, cursorY); + int cursorPos = horizontalPadding + fontRef->stringWidth(lines[cursorY].substr(0, cursorX)); + + int cursorTop = verticalPadding + fontRef->getLineHeight()*cursorY; + int cursorBottom = cursorTop + fontRef->getLineHeight(); + + ofSetLineWidth(1.0f); + //TODO: multiline with fontRef + ofLine(cursorPos, cursorTop, + cursorPos, cursorBottom); + ofPopStyle(); + } + + fontRef->drawString(text, horizontalPadding, fontRef->getLineHeight() + verticalPadding); + ofPopMatrix(); +} + +//---------- +void ofxTextInputField::clear(){ + text.clear(); + cursorPosition = 0; +} + +//---------- +void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { + //ew: add charachter (non unicode sorry!) + //jg: made a step closer to this with swappable renderers and ofxFTGL -- but need unicode text input... + + //if we're not focused, then ignore the keypress + if (!this->editing) { + return; + } + + lastTimeCursorMoved = ofGetElapsedTimef(); + int key = args.key; + + if(key == OF_KEY_SHIFT) { + this->shiftHeld = true; + } + + if(key == 4352) { + this->commandHeld = true; + } + + #ifdef USE_GLFW_CLIPBOARD + if(key == 'c' && this->commandHeld) { + setClipboard(text.substr(selectionBegin, selectionEnd - selectionBegin)); + return; + } + + if(key == 'v' && this->commandHeld) { + text.insert(cursorPosition, getClipboard()); + return; + } + #endif + + if ((key >=32 && key <=126) || key=='\t' || key==OF_KEY_RETURN) { + if(selecting) { + text.erase(text.begin() + selectionBegin, + text.begin() + selectionEnd + ); + cursorPosition = selectionBegin; + selecting = false; + } + } + + if (key == OF_KEY_RETURN) { + if(!multiline) { + endEditing(); + return; + } + text.insert(text.begin()+cursorPosition, '\n'); + cursorPosition++; + + if(autoTab) { + // how much whitespace is there on the previous line? + int xx, yy; + getCursorCoords(cursorPosition, xx, yy); + vector lines = ofSplitString(text, "\n"); + if(yy>0) { + // collect all the whitespace on the previous line. + string previousWhitespace = ""; + string previousLine = lines[yy-1]; + int pos = 0; + for(int i = 0; i < previousLine.size(); i++) { + if(previousLine[i]==' ' || previousLine[i]=='\t') { + previousWhitespace += previousLine[i]; + } else { + break; + } + } + // if we have a curly brace as the last char on the previous line + // increase the indentation + if(previousLine[previousLine.size()-1]=='{') { + if(previousWhitespace=="") { + previousWhitespace = "\t"; + } else { + previousWhitespace += previousWhitespace[previousWhitespace.size()-1]; + } + } + text = text.insert(cursorPosition, previousWhitespace); + cursorPosition += previousWhitespace.size(); + } + } + return; + } + + if ((key >=32 && key <=126) || key=='\t') { + if(this->shiftHeld) { + + char toInsert; + if( !(key > 96 && key < 123) && !(key > 65 && key < 90) && shiftMap.find(key) != shiftMap.end() ) { + toInsert = shiftMap[key];//toInsert = key - 32; + } else { + toInsert = key; + } + + text.insert(text.begin()+cursorPosition, toInsert); + } else { + text.insert(text.begin()+cursorPosition, key); + } + cursorPosition++; + } + + if (key==OF_KEY_BACKSPACE) { + if(selecting) { + text.erase(text.begin() + selectionBegin, + text.begin() + selectionEnd + ); + cursorPosition = selectionBegin; + selecting = false; + } else { + if (cursorPosition>0) { + text.erase(text.begin()+cursorPosition-1); + --cursorPosition; + } + } + } + + if (key==OF_KEY_DEL) { + if(selecting) { + text.erase(text.begin() + selectionBegin, + text.begin() + selectionEnd + ); + cursorPosition = selectionBegin; + selecting = false; + } else { + if (text.size() > cursorPosition) { + text.erase(text.begin()+cursorPosition); + } + } + } + + if (key==OF_KEY_LEFT){ + if(selecting) { + cursorPosition = selectionBegin; + selecting = false; + + } else { + if (cursorPosition>0){ + --cursorPosition; + } + } + } + + if (key==OF_KEY_RIGHT){ + if(selecting) { + cursorPosition = selectionEnd; + selecting = false; + } else { + if (cursorPosition0) { + int xx, yy; + getCursorCoords(cursorPosition, xx, yy); + if(yy>0) { + yy--; + vector lines = ofSplitString(text, "\n"); + xx = MIN(lines[yy].size()-1, xx); + cursorPosition = xx; + for(int i = 0; i < yy; i++) cursorPosition += lines[i].size()+1; + printf("Cursor position: %d\n", cursorPosition); + } else { + cursorPosition = 0; + } + } + } + } + + if (key==OF_KEY_DOWN){ + if(selecting) { + cursorPosition = selectionEnd; + selecting = false; + } else { + int xx, yy; + getCursorCoords(cursorPosition, xx, yy); + vector lines = ofSplitString(text, "\n"); + yy++; + if(yyediting) { + return; + } + + if(a.key == 4352) { + this->commandHeld = false; + } + + if(a.key == OF_KEY_SHIFT) { + this->shiftHeld = false; + } +} + +//---------- +void ofxTextInputField::mousePressed(ofMouseEventArgs& args) { + if (!this->enabled) { + return; + } + + mouseDownInRect = bounds.inside(args.x, args.y); + if (mouseDownInRect) { + cursorPosition = getCursorPositionFromMouse(args.x, args.y); + lastTimeCursorMoved = ofGetElapsedTimef(); + selecting = false; + } +} + +//---------- +void ofxTextInputField::mouseDragged(ofMouseEventArgs& args) { + if (!this->enabled) { + return; + } + + if (bounds.inside(args.x, args.y)) { + int pos = getCursorPositionFromMouse(args.x, args.y); + if (pos != cursorPosition) { + selecting = true; + selectionBegin = MIN(pos, cursorPosition); + selectionEnd = MAX(pos, cursorPosition); + } + else { + selecting = false; + } + } +} + +//---------- +void ofxTextInputField::mouseReleased(ofMouseEventArgs& args) { + if (!this->enabled) { + return; + } + + if (bounds.inside(args.x, args.y)) { + if (!this->editing && mouseDownInRect) { + beginEditing(); + } + } + else { + endEditing(); + } +} + +#ifdef USE_GLFW_CLIPBOARD + +#if (_MSC_VER) +#include +#else +#include "GLFW/glfw3.h" +#endif + +//---------- +void ofxTextInputField::setClipboard(string clippy){ + glfwSetClipboardString((GLFWwindow*)ofGetWindowPtr()->getCocoaWindow(), clippy.c_str()); +} + +//---------- +string ofxTextInputField::getClipboard(){ + const char *clip = glfwGetClipboardString((GLFWwindow*)ofGetWindowPtr()->getCocoaWindow()); + if (clip != NULL) { + return string(clip); + } + else { + return ""; + } + +} + +#endif + + +//---------- +void ofxTextInputField::getCursorCoords(int pos, int &cursorX, int &cursorY) { + vector lines = ofSplitString(text, "\n"); + + int c = 0; + for (int i = 0; i < lines.size(); i++) { + if (pos <= c + lines[i].size()) { + cursorY = i; + cursorX = pos - c; + return; + } + c += lines[i].size() + 1; + } +} + +//---------- +int ofxTextInputField::getCursorPositionFromMouse(int x, int y) { + int cursorX = 0; + int cursorY = 0; + float pos = y - bounds.y - verticalPadding; + pos /= fontRef->getLineHeight(); + int line = pos; + cursorY = line; + + vector lines = ofSplitString(text, "\n"); + if (cursorY >= lines.size() - 1) cursorY = lines.size() - 1; + if (lines.size()>0) { + cursorX = fontRef->getPosition(lines[cursorY], x - horizontalPadding - bounds.x); + } + int c = 0; + for (int i = 0; i < cursorY; i++) { + c += lines[i].size() + 1; + } + c += cursorX; + return c; +} + +//---------- +void ofxTextInputField::addListeners() { + if (this->hasListeners) { + return; + } + ofAddListener(ofEvents().keyPressed, this, &ofxTextInputField::keyPressed); + ofAddListener(ofEvents().keyReleased, this, &ofxTextInputField::keyReleased); + ofAddListener(ofEvents().mousePressed, this, &ofxTextInputField::mousePressed); + ofAddListener(ofEvents().mouseDragged, this, &ofxTextInputField::mouseDragged); + ofAddListener(ofEvents().mouseReleased, this, &ofxTextInputField::mouseReleased); +} + +//---------- +void ofxTextInputField::removeListeners() { + if (!this->hasListeners) { + return; + } + ofRemoveListener(ofEvents().keyPressed, this, &ofxTextInputField::keyPressed); + ofAddListener(ofEvents().keyReleased, this, &ofxTextInputField::keyReleased); + ofRemoveListener(ofEvents().mousePressed, this, &ofxTextInputField::mousePressed); + ofRemoveListener(ofEvents().mouseDragged, this, &ofxTextInputField::mouseDragged); + ofRemoveListener(ofEvents().mouseReleased, this, &ofxTextInputField::mouseReleased); } \ No newline at end of file diff --git a/src/ofxTextInputField.h b/src/ofxTextInputField.h index 8d7ab1a..0a2444b 100755 --- a/src/ofxTextInputField.h +++ b/src/ofxTextInputField.h @@ -1,108 +1,120 @@ -// -// textInput.h -// textInput -// -// Created by Elliot Woods on 09/12/2011. -// modified by James George 12/2/2011 -// modified by Momo the Monster 7/10/2012 -// swappable fonts added by James George 9/11/2012 -// refactoring and modifications by Elliot Woods on 30/11/2014 -// -// MIT license -// http://www.opensource.org/licenses/mit-license.php -// - -// jg : TODO: text wrapping - -#pragma once - -#include "ofMain.h" - -//For lack of a type abstraction, this lets you #define a font renderer so -//(like ofxFTGL or ofxFont) -//to use ofxFTGL use somethinglike this: -//#define OFX_TEXTFIELD_FONT_RENDERER ofxFTGLFont -//#define OFX_TEXTFIELD_FONT_INCLUDE "ofxFTGLFont.h" - -#ifndef OFX_TEXTFIELD_FONT_RENDERER -#define OFX_TEXTFIELD_FONT_RENDERER ofTrueTypeFont -#endif - -#ifdef OFX_TEXTFIELD_FONT_INCLUDE -#include OFX_TEXTFIELD_FONT_INCLUDE -#endif - -#define TEXTFIELD_IS_ACTIVE "textfieldIsActive" -#define TEXTFIELD_IS_INACTIVE "textfieldIsInactive" - -#include "ofxTextInputFieldFontRenderer.h" - -class ofxTextInputField { - public: - ofxTextInputField(); - virtual ~ofxTextInputField(); - - /// Always call this first - void setup(); - - /// Change the font used to draw the text - void setFont(OFX_TEXTFIELD_FONT_RENDERER& font); - - void enable(); - void disable(); - bool isEnabled() const; - - void beginEditing(); - void endEditing(); - bool isEditing() const; - - //can be set manually or otherwise is controlled by enable/disable - bool drawCursor; - - ofRectangle bounds; - - void draw(); - void clear(); - - string text; - int cursorPosition; - - int selectionBegin; - int selectionEnd; - bool selecting; - - ofEvent textChanged; - void keyPressed(ofKeyEventArgs &a); - void keyReleased(ofKeyEventArgs &a); - void mousePressed(ofMouseEventArgs& args); - void mouseDragged(ofMouseEventArgs& args); - void mouseReleased(ofMouseEventArgs& args); - - bool autoClear; - bool autoTab; - - bool multiline; - - #ifdef USE_GLFW_CLIPBOARD - void setClipboard(string clippy); - string getClipboard(); - #endif - - protected: - float lastTimeCursorMoved; - - float verticalPadding; - float horizontalPadding; - - ofxTextInput::FontRenderer* fontRef; - - bool enabled; - bool editing; - bool mouseDownInRect; - - void getCursorCoords(int pos, int &cursorX, int &cursorY); - int getCursorPositionFromMouse(int x, int y); - - bool shiftHeld, commandHeld; - map shiftMap; -}; +// +// textInput.h +// textInput +// +// Created by Elliot Woods on 09/12/2011. +// modified by James George 12/2/2011 +// modified by Momo the Monster 7/10/2012 +// swappable fonts added by James George 9/11/2012 +// refactoring and modifications by Elliot Woods on 30/11/2014 +// +// MIT license +// http://www.opensource.org/licenses/mit-license.php +// + +// jg : TODO: text wrapping + +#pragma once + +#include "ofMain.h" + +//For lack of a type abstraction, this lets you #define a font renderer so +//(like ofxFTGL or ofxFont) +//to use ofxFTGL use somethinglike this: +//#define OFX_TEXTFIELD_FONT_RENDERER ofxFTGLFont +//#define OFX_TEXTFIELD_FONT_INCLUDE "ofxFTGLFont.h" + +#ifndef OFX_TEXTFIELD_FONT_RENDERER +#define OFX_TEXTFIELD_FONT_RENDERER ofTrueTypeFont +#endif + +#ifdef OFX_TEXTFIELD_FONT_INCLUDE +#include OFX_TEXTFIELD_FONT_INCLUDE +#endif + +#define TEXTFIELD_IS_ACTIVE "textfieldIsActive" +#define TEXTFIELD_IS_INACTIVE "textfieldIsInactive" + +#include "ofxTextInputFieldFontRenderer.h" + +class ofxTextInputField { + public: + ofxTextInputField(); + virtual ~ofxTextInputField(); + + /// Always call this first + void setup(bool enableListeners = true); + + /// Change the font used to draw the text + void setFont(OFX_TEXTFIELD_FONT_RENDERER& font); + + void enable(); + void disable(); + bool isEnabled() const; + + /// Whether the text box is focused and capturing keys + void beginEditing(); + void endEditing(); + bool isEditing() const; + + void setUseListeners(bool); + bool getUseListeners() const; + + /// Draw inside this->bounds + void draw(); + + /// Clear text + void clear(); + + //can be set manually or otherwise is controlled by enable/disable + bool drawCursor; + + string text; + + ofRectangle bounds; + int cursorPosition; + int selectionBegin; + int selectionEnd; + bool selecting; + + ofEvent textChanged; + void keyPressed(ofKeyEventArgs &a); + void keyReleased(ofKeyEventArgs &a); + void mousePressed(ofMouseEventArgs& args); + void mouseDragged(ofMouseEventArgs& args); + void mouseReleased(ofMouseEventArgs& args); + + bool autoClear; + bool autoTab; + + bool multiline; + + #ifdef USE_GLFW_CLIPBOARD + void setClipboard(string clippy); + string getClipboard(); + #endif + + protected: + float lastTimeCursorMoved; + + float verticalPadding; + float horizontalPadding; + + ofxTextInput::FontRenderer* fontRef; + + bool enabled; + bool editing; + bool useListeners; + + bool mouseDownInRect; + + void getCursorCoords(int pos, int &cursorX, int &cursorY); + int getCursorPositionFromMouse(int x, int y); + + void addListeners(); + void removeListeners(); + bool hasListeners; + + bool shiftHeld, commandHeld; + map shiftMap; +}; From f81b622f7b608531fe90bfb5e8b6640660aa40fb Mon Sep 17 00:00:00 2001 From: Elliot Woods Date: Sun, 30 Nov 2014 10:04:48 +0100 Subject: [PATCH 05/10] remove debug graphics --- src/ofxTextInputField.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/ofxTextInputField.cpp b/src/ofxTextInputField.cpp index e37f3c4..4022a5f 100755 --- a/src/ofxTextInputField.cpp +++ b/src/ofxTextInputField.cpp @@ -144,16 +144,6 @@ bool ofxTextInputField::getUseListeners() const { void ofxTextInputField::draw() { ofPushMatrix(); ofTranslate(bounds.x, bounds.y); - - //debug graphics - ofPushStyle(); - ofSetColor(255, 0, 0); - this->isEnabled() ? ofFill() : ofNoFill(); - ofCircle(10, 10, 5); - ofSetColor(0, 255, 0); - this->isEditing() ? ofFill() : ofNoFill(); - ofCircle(20, 10, 5); - ofPopStyle(); if(selecting) { ofPushStyle(); From 13d2ac624a9bbdd3ba6d496092a0c89e4295690c Mon Sep 17 00:00:00 2001 From: Elliot Woods Date: Sun, 30 Nov 2014 10:39:04 +0100 Subject: [PATCH 06/10] Fixes to events. textChange had been changed to only fire when editing ended. perhaps also need an event onEditingEnd for whoever made that change? --- src/ofxTextInputField.cpp | 28 ++++++++++++++++++++++++---- src/ofxTextInputField.h | 6 +++++- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/ofxTextInputField.cpp b/src/ofxTextInputField.cpp index 4022a5f..cf051f6 100755 --- a/src/ofxTextInputField.cpp +++ b/src/ofxTextInputField.cpp @@ -113,7 +113,6 @@ void ofxTextInputField::beginEditing() { void ofxTextInputField::endEditing() { if(this->editing){ ofSendMessage(TEXTFIELD_IS_INACTIVE); - ofNotifyEvent(textChanged, text, this); this->editing = false; this->drawCursor = false; this->shiftHeld = false; @@ -227,6 +226,7 @@ void ofxTextInputField::draw() { void ofxTextInputField::clear(){ text.clear(); cursorPosition = 0; + this->notifyTextChange(); } //---------- @@ -269,12 +269,14 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { ); cursorPosition = selectionBegin; selecting = false; + this->notifyTextChange(); } } if (key == OF_KEY_RETURN) { if(!multiline) { endEditing(); + this->notifyHitReturn(); return; } text.insert(text.begin()+cursorPosition, '\n'); @@ -310,7 +312,8 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { cursorPosition += previousWhitespace.size(); } } - return; + this->notifyTextChange(); + return; } if ((key >=32 && key <=126) || key=='\t') { @@ -328,6 +331,7 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { text.insert(text.begin()+cursorPosition, key); } cursorPosition++; + this->notifyTextChange(); } if (key==OF_KEY_BACKSPACE) { @@ -337,10 +341,13 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { ); cursorPosition = selectionBegin; selecting = false; - } else { + this->notifyTextChange(); + } + else { if (cursorPosition>0) { text.erase(text.begin()+cursorPosition-1); --cursorPosition; + this->notifyTextChange(); } } } @@ -352,9 +359,12 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { ); cursorPosition = selectionBegin; selecting = false; - } else { + this->notifyTextChange(); + } + else { if (text.size() > cursorPosition) { text.erase(text.begin()+cursorPosition); + this->notifyTextChange(); } } } @@ -520,6 +530,16 @@ string ofxTextInputField::getClipboard(){ #endif +//---------- +void ofxTextInputField::notifyTextChange() { + ofNotifyEvent(this->onTextChange, this->text, this); +} + +//---------- +void ofxTextInputField::notifyHitReturn() { + ofNotifyEvent(this->onHitReturn, this->text, this); +} + //---------- void ofxTextInputField::getCursorCoords(int pos, int &cursorX, int &cursorY) { vector lines = ofSplitString(text, "\n"); diff --git a/src/ofxTextInputField.h b/src/ofxTextInputField.h index 0a2444b..0ed09df 100755 --- a/src/ofxTextInputField.h +++ b/src/ofxTextInputField.h @@ -77,7 +77,9 @@ class ofxTextInputField { int selectionEnd; bool selecting; - ofEvent textChanged; + ofEvent onTextChange; + ofEvent onHitReturn; + void keyPressed(ofKeyEventArgs &a); void keyReleased(ofKeyEventArgs &a); void mousePressed(ofMouseEventArgs& args); @@ -108,6 +110,8 @@ class ofxTextInputField { bool mouseDownInRect; + void notifyTextChange(); + void notifyHitReturn(); void getCursorCoords(int pos, int &cursorX, int &cursorY); int getCursorPositionFromMouse(int x, int y); From 81afa4a3a66c5a4862d8d4871fa8b474b68ad954 Mon Sep 17 00:00:00 2001 From: elliot woods Date: Sun, 30 Nov 2014 20:36:21 +0900 Subject: [PATCH 07/10] temporary bug fix on pressing up/down (this causes out of range exceptions for single line). i think a more considerable bug fix would also handle multiline also --- src/ofxTextInputField.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ofxTextInputField.cpp b/src/ofxTextInputField.cpp index cf051f6..90cf6ad 100755 --- a/src/ofxTextInputField.cpp +++ b/src/ofxTextInputField.cpp @@ -397,7 +397,7 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { cursorPosition = selectionBegin; selecting = false; - } else { + } else if (this->multiline) { if (cursorPosition>0) { int xx, yy; getCursorCoords(cursorPosition, xx, yy); @@ -419,7 +419,7 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { if(selecting) { cursorPosition = selectionEnd; selecting = false; - } else { + } else if (this->multiline) { int xx, yy; getCursorCoords(cursorPosition, xx, yy); vector lines = ofSplitString(text, "\n"); From d9e9557b5b67c6beba5ab5965076ae5801147c75 Mon Sep 17 00:00:00 2001 From: elliot woods Date: Sun, 30 Nov 2014 23:42:45 +0900 Subject: [PATCH 08/10] add some getters --- src/ofxTextInputField.cpp | 17 ++++++++++++++++- src/ofxTextInputField.h | 6 +++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/ofxTextInputField.cpp b/src/ofxTextInputField.cpp index 90cf6ad..cebff79 100755 --- a/src/ofxTextInputField.cpp +++ b/src/ofxTextInputField.cpp @@ -67,13 +67,18 @@ void ofxTextInputField::setup(bool enableListeners){ } //---------- -void ofxTextInputField::setFont(OFX_TEXTFIELD_FONT_RENDERER& font){ +void ofxTextInputField::setFont(OFX_TEXTFIELD_FONT_RENDERER & font){ if (fontRef->isBitmapFont()) { delete fontRef; } fontRef = new ofxTextInput::TypedFontRenderer(&font); } +//---------- +ofxTextInput::FontRenderer * ofxTextInputField::getFontRenderer() { + return this->fontRef; +} + //---------- void ofxTextInputField::enable(){ if(!this->enabled){ @@ -502,6 +507,16 @@ void ofxTextInputField::mouseReleased(ofMouseEventArgs& args) { } } +//---------- +float ofxTextInputField::getVerticalPadding() const { + return this->verticalPadding; +} + +//---------- +float ofxTextInputField::getHorizontalPadding() const { + return this->horizontalPadding; +} + #ifdef USE_GLFW_CLIPBOARD #if (_MSC_VER) diff --git a/src/ofxTextInputField.h b/src/ofxTextInputField.h index 0ed09df..fd23965 100755 --- a/src/ofxTextInputField.h +++ b/src/ofxTextInputField.h @@ -46,7 +46,8 @@ class ofxTextInputField { void setup(bool enableListeners = true); /// Change the font used to draw the text - void setFont(OFX_TEXTFIELD_FONT_RENDERER& font); + void setFont(OFX_TEXTFIELD_FONT_RENDERER & font); + ofxTextInput::FontRenderer * getFontRenderer(); void enable(); void disable(); @@ -91,6 +92,9 @@ class ofxTextInputField { bool multiline; + float getVerticalPadding() const; + float getHorizontalPadding() const; + #ifdef USE_GLFW_CLIPBOARD void setClipboard(string clippy); string getClipboard(); From 0727b14406cdc6e537f50a7395b24ec25c3f4b58 Mon Sep 17 00:00:00 2001 From: Roy Macdonald Date: Tue, 11 Aug 2015 17:34:26 -0400 Subject: [PATCH 09/10] Added getters and setters for vertical and horizontal padding --- src/ofxTextInputField.cpp | 14 +++++++++++++- src/ofxTextInputField.h | 7 +++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/ofxTextInputField.cpp b/src/ofxTextInputField.cpp index cebff79..704cdc9 100755 --- a/src/ofxTextInputField.cpp +++ b/src/ofxTextInputField.cpp @@ -517,6 +517,18 @@ float ofxTextInputField::getHorizontalPadding() const { return this->horizontalPadding; } +//---------- +void ofxTextInputField::setVerticalPadding(float vp){ + verticalPadding = vp; +} +//---------- +void ofxTextInputField::setHorizontalPadding(float hp){ + horizontalPadding = hp; +} + + + + #ifdef USE_GLFW_CLIPBOARD #if (_MSC_VER) @@ -614,4 +626,4 @@ void ofxTextInputField::removeListeners() { ofRemoveListener(ofEvents().mousePressed, this, &ofxTextInputField::mousePressed); ofRemoveListener(ofEvents().mouseDragged, this, &ofxTextInputField::mouseDragged); ofRemoveListener(ofEvents().mouseReleased, this, &ofxTextInputField::mouseReleased); -} \ No newline at end of file +} diff --git a/src/ofxTextInputField.h b/src/ofxTextInputField.h index fd23965..ea1af87 100755 --- a/src/ofxTextInputField.h +++ b/src/ofxTextInputField.h @@ -94,7 +94,10 @@ class ofxTextInputField { float getVerticalPadding() const; float getHorizontalPadding() const; - + + void setVerticalPadding(float vp); + void setHorizontalPadding(float hp); + #ifdef USE_GLFW_CLIPBOARD void setClipboard(string clippy); string getClipboard(); @@ -125,4 +128,4 @@ class ofxTextInputField { bool shiftHeld, commandHeld; map shiftMap; -}; +}; \ No newline at end of file From c8f186b8f69ff59b1429105fc99c3d8ecce37dfe Mon Sep 17 00:00:00 2001 From: Roy Macdonald Date: Tue, 11 Aug 2015 17:45:06 -0400 Subject: [PATCH 10/10] Added preprocessor define for OSX --- src/ofxTextInputField.cpp | 2 +- src/ofxTextInputField.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ofxTextInputField.cpp b/src/ofxTextInputField.cpp index 704cdc9..5ae5241 100755 --- a/src/ofxTextInputField.cpp +++ b/src/ofxTextInputField.cpp @@ -255,7 +255,7 @@ void ofxTextInputField::keyPressed(ofKeyEventArgs& args) { this->commandHeld = true; } - #ifdef USE_GLFW_CLIPBOARD +#if defined(USE_GLFW_CLIPBOARD) && defined(TARGET_OSX) if(key == 'c' && this->commandHeld) { setClipboard(text.substr(selectionBegin, selectionEnd - selectionBegin)); return; diff --git a/src/ofxTextInputField.h b/src/ofxTextInputField.h index ea1af87..5434803 100755 --- a/src/ofxTextInputField.h +++ b/src/ofxTextInputField.h @@ -98,7 +98,7 @@ class ofxTextInputField { void setVerticalPadding(float vp); void setHorizontalPadding(float hp); - #ifdef USE_GLFW_CLIPBOARD + #if defined(USE_GLFW_CLIPBOARD) && defined(TARGET_OSX) void setClipboard(string clippy); string getClipboard(); #endif